npm.io
0.0.1 • Published 1 month ago

resource-tracker

Licence
EPL-1.0
Version
0.0.1
Deps
1
Size
29 kB
Vulns
0
Weekly
0
Stars
2

resource-tracker

This is a squint port of tech.resource, to provide parallel functionality in an ES module.

Cross-platform RAII (stack-scoped) and GC-based cleanup for opaque JavaScript resources. Distributed as a single squint-compiled ES module for managing resources that have no implicit JS garbage-collection story of their own (native pointers held by WASM modules, worker-scoped handles, etc.).

Installation

npm install resource-tracker

Requires Node 18.18+, the floor for Symbol.dispose / Symbol.asyncDispose.

Usage from JavaScript

Deterministic cleanup at scope exit:

import * as resource from 'resource-tracker';

resource.releasing_fn(() => {
  const ptr = allocateNativePointer();
  resource.track(ptr, { tracktype: 'stack', disposefn: () => freePointer(ptr) });
  // ...use ptr...
});  // dispose fires LIFO here

GC-backed cleanup for resources that escape their creating scope:

resource.track(ptr, { tracktype: 'gc', disposefn: () => freePointer(ptr) });
// dispose fires after the runtime collects ptr

Combined first-wins (release no later than scope exit, GC-cleanup as a safety net):

resource.track(ptr, {
  tracktype: ['gc', 'stack'],
  disposefn: () => freePointer(ptr),
});

auto (the default) picks stack if a context is bound and gc otherwise.

ES2023 Explicit Resource Management integration. The native using keyword needs Node 24+ or a transpiler; the make_closeable_context, .close(), and [Symbol.dispose] APIs it builds on work on any supported Node:

using ctx = resource.make_closeable_context(() => {
  resource.stack_track(someFileHandle);  // anything with .close() works
  return computeValue();
});
console.log(ctx.value);
// ctx[Symbol.dispose]() fires at scope exit; releases entries LIFO
using ctx = resource.make_closeable_context(() => {
  resource.stack_track({ [Symbol.dispose]() { shutdownNetworkSync(); } });
});
// closes synchronously; async-dispose flushing is a consumer concern
// (see clj-native's pool/flush-pending-disposes! for that path).

Usage from Squint or ClojureScript

Require it by package name. Squint and ClojureScript both munge hyphenated names to the compiled exports, so you write idiomatic Clojure (releasing-fn, in-stack-resource-context?) rather than the releasing_fn / in_stack_resource_context_QMARK_ JS spellings:

(ns my.app
  (:require ["resource-tracker" :as resource]))

(resource/releasing-fn
  (fn []
    (resource/track ptr #js {:tracktype "stack"
                             :disposefn #(free-pointer! ptr)})))
;; dispose fires LIFO when releasing-fn returns

Options are JS objects with string values, the same shape as the JavaScript API above, not tech.resource's {:track-type :stack} keyword maps:

(resource/track ptr #js {:tracktype "gc" :disposefn f})
(resource/track ptr #js {:tracktype #js ["gc" "stack"] :disposefn f})

The interop form with the literal export name, (.releasing_fn resource (fn [] ...)), works identically and is what the test suite uses.

License

Distributed under the Eclipse Public License 1.0 (EPL-1.0), the same license as tech.resource. See LICENSE.

Keywords