Scoped dependencies

Scoped dependencies cache one value for each context key. Compdi provides an accessor form and a contextual proxy form.

FormContext selectionBest fit
defineScopedPassed explicitly to the accessorRequest handlers and code where ownership should be visible.
createScopedRead from a context() callbackFramework integrations with an existing ambient context.

Keyed accessor

defineScoped returns a callable accessor. Supply the context key when resolving a value:

const useRequestService = defineScoped<RequestService, Request>({
  target: RequestService,
  deps: [database],
  onRelease: service => service.close(),
});

const service = useRequestService(request);

useRequestService.has(request);     // true
useRequestService.peek(request);    // existing value, without creating one
await useRequestService.release(request);

The lifecycle methods never create a value:

  • has(context) reports whether an entry exists.
  • peek(context) returns an existing entry or undefined.
  • release(context) removes the entry and runs onRelease, when configured.

Contextual proxy

createScoped returns a stable proxy and a controller. The proxy asks context() for the active key when one of its properties is used:

const [database, databaseScope] = createScoped({
  factory: request => createRequestDatabase(request),
  context: useRequest,
  onRelease: instance => instance.close(),
});

database.query("SELECT 1");
await databaseScope.release(request);

Use the proxy form when an ambient context is already available. Use the accessor form when passing the context explicitly makes ownership clearer.

createScoped proxies objects. For primitive scoped values, use defineScoped.
Release each finished context. Otherwise its cached value remains reachable for the lifetime of the module.