Skip to content

@btravstack/di


@btravstack/di ​

Interfaces ​

ProviderBase ​

Defined in: provider.ts:275

The instance side of a Provider.class base: a port instance whose service is the subclass itself, through the polymorphic this. Declared, never defined — the runtime class is minted per id — so it cannot be extended directly.

deps is protected, not #private: this is a named class, so a subclass a consumer exports emits without TS4094, and a caller of the service cannot reach past it to the services it was built from.

Type Parameters ​

Type Parameter
Id extends string
D extends Deps

Properties ​

PropertyModifierTypeDefined in
[ID]readonlyIdprovider.ts:276
[SERVICE]readonlyProviderBase<Id, D>provider.ts:277

Scope ​

Defined in: port.ts:139

A phantom requirement, not a real service: nothing constructs one or reads it out of a Context. A resourceful provider adds Scope to its Needs, so Module.build refuses a graph that still owns an un-discharged resource and only Module.scoped — which opens one — strips it back out.

Whether Scope can be PROVIDED is a separate hazard, checked at run time by build.ts's plan rather than in the types. A type-level guard keyed on the id was tried and was both bypassable (a widening to AnyPort before the call slips past it) and a false positive on any port-generic helper, since the conditional cannot reduce for an unresolved P.

Extends ​

Properties ​

PropertyModifierTypeInherited fromDefined in
[ID]readonly"@di/Scope"PortDeclaration("@di/Scope").[ID]port.ts:12
[SERVICE]readonlyneverPortDeclaration("@di/Scope").[SERVICE]port.ts:13

Type Aliases ​

AnyModule ​

ts
type AnyModule = object;

Defined in: module.ts:16

Properties ​

PropertyModifierTypeDefined in
exportsreadonlyreadonly (AnyPort | AnyModule)[]module.ts:20
importsreadonlyreadonly AnyModule[]module.ts:18
namereadonlystringmodule.ts:17
providesreadonlyreadonly AnyProvider[]module.ts:19

AnyPort ​

ts
type AnyPort = object & (abstract new (...args) => AnyPortInstance);

Defined in: port.ts:54

Type Declaration ​

NameTypeDefined in
many?trueport.ts:56
portIdstringport.ts:55

AnyProvider ​

ts
type AnyProvider = object;

Defined in: module.ts:14

Structural, listing only the concrete fields: a bound that compared the phantom channels would trip on their mixed variance. Do not replace with Provider<any, any, any>.

Properties ​

PropertyModifierTypeDefined in
depsreadonlyreadonly AnyPort[]module.ts:14
portreadonlyAnyPortmodule.ts:14

Context ​

ts
type Context<R> = object;

Defined in: context.ts:36

_R is LOAD-BEARING. in R only asserts contravariance, and get cannot carry the check on its own — R appears there solely as the bound of get's own type parameter, which is not independently contravariant. Remove the phantom field, or make it optional, and Context measures as bivariant: Context<Database> flows where Context<Database | Logger> is required, with no signal at the use site.

Type Parameters ​

Type Parameter
R

Properties ​

PropertyModifierTypeDefined in
_Rreadonly(r) => voidcontext.ts:37
getreadonly<S>(port) => ServiceOf<Held<R, S>>context.ts:41

DependencyGate ​

ts
type DependencyGate<N> = [N] extends [never] ? unknown : object;

Defined in: module.ts:166

The entry points' gate for unmet dependencies, on NeedsGate's mechanism: unknown when nothing is unmet, the one-property object otherwise, so the diagnostic ends on the missing port.

Type Parameters ​

Type Parameter
N

Exportable ​

ts
type Exportable<I, P> = 
  | AnyPort & (new (...args) => Available<I, P>)
  | AnyProvider & object
  | I[number];

Defined in: module.ts:76

An export entry is legal only if it is an available port, a provider for one (normalised to provider.port by ModuleDeclaration below), or an imported module (whole-module re-export).

The provider arm is for the helpers that mint their own port and hand back no class to name.

Each arm must stay a plain union member, never a generic helper taking AnyPort: instantiating the per-element conditional with the whole union asks whether EVERY port is available, and rejects legal exports.

Type Parameters ​

Type Parameter
I extends readonly AnyModule[]
P extends readonly AnyProvider[]

ManyPortClass() ​

ts
type ManyPortClass<Id> = PortInstance<Id, readonly Member[]> & object;

Defined in: port.ts:31

A set port: several providers may target it, and Context.get yields every contribution rather than one service. Port.many("Id")<Member> fixes the MEMBER shape, but the port's own service — what lands in a Context — is readonly Member[].

many: true is the runtime discriminant build.ts reads off the class; the [MANY] brand is its type-level twin, which is what lets MemberOf recover a member's shape from a concrete set-port class.

Type Parameters ​

Type Parameter
Id extends string
ts
type new ManyPortClass<Member>(): PortInstance<Id, readonly Member[]> & object;

A set port: several providers may target it, and Context.get yields every contribution rather than one service. Port.many("Id")<Member> fixes the MEMBER shape, but the port's own service — what lands in a Context — is readonly Member[].

many: true is the runtime discriminant build.ts reads off the class; the [MANY] brand is its type-level twin, which is what lets MemberOf recover a member's shape from a concrete set-port class.

Returns ​

PortInstance<Id, readonly Member[]> & object

Properties ​

PropertyModifierTypeDefined in
manyreadonlytrueport.ts:34
portIdreadonlyIdport.ts:33

MemberOf ​

ts
type MemberOf<T> = T extends object & PortInstance<string, infer S> ? S extends readonly infer M[] ? M : never : T extends abstract new () => object & PortInstance<string, infer S> ? S extends readonly infer M[] ? M : never : never;

Defined in: port.ts:95

Recovers a set port's member shape — the type a Provider.member factory actually produces — from [MANY], not from ServiceOf<T>'s shape. An earlier version keyed this off "does the service look like an array" (ServiceOf<T> extends readonly (infer M)[] ? M : never), which is unsound: an ordinary port whose declared service happens to be an array — class Tags extends Port("Tags")<readonly string[]> {} — has manyundefined at runtime (build.ts's plan/context.ts's unsafeAddAll both discriminate on that static field, never on shape), so Provider.member(Tags)({ inject: {}, value: "a" }) type-checked under the old definition while landing as a single service at runtime — ctx.get(Tags) would return "a", contradicting its own readonly string[] type. [MANY] is the same brand ManyPortClass's instance type carries and is module-private (declared, not exported, above), so nothing outside this file can forge it onto an ordinary port's instance type; keying MemberOf off its presence makes the type-level check agree with the runtime one.

Type Parameters ​

Type Parameter
T

Module ​

ts
type Module<Exports, E, Needs> = object;

Defined in: module.ts:49

The variance rule, shared with Provider: capability channels (_exports) are contravariant, so you may forget what you have; obligation channels (_error, _needs) are covariant, so you may not forget what you owe.

Both directions are load-bearing and were measured. Turning _error or _needs contravariant lets an error channel narrow to one arm and lets Module<X, E, Database> launder past the build gate as Module<X, E, never>.

Type Parameters ​

Type Parameter
Exports
E
Needs

Properties ​

PropertyModifierTypeDefined in
_errorreadonly() => Emodule.ts:51
_exportsreadonly(x) => voidmodule.ts:50
_needsreadonly() => Needsmodule.ts:52
exportsreadonlyreadonly (AnyPort | AnyModule)[]module.ts:56
importsreadonlyreadonly AnyModule[]module.ts:54
namereadonlystringmodule.ts:53
providesreadonlyreadonly AnyProvider[]module.ts:55

NeedsGate ​

ts
type NeedsGate<I, P, N> = [N] extends [readonly AnyPort[]] ? [Exclude<NeedOf<P[number]>, Available<I, P>>] extends [
  | InstanceType<NonNullable<N>[number]>
  | Scope] ? unknown : object : unknown;

Defined in: module.ts:107

The optional declaration gate. Without needs, a module's external requirements are inferred from its providers' inject records and its imports, and travel in its Needs channel to whoever composes it. With needs, the module states its boundary: a port this module's own providers read, and that nothing here satisfies, is an error unless it is named there. Naming a port does not make it Available here, so a declared need is still not exportable.

An import's own unmet needs are not this module's to re-declare; Scope is exempt, since nothing can provide it.

The gate is an object with one required property, not StartGate's bare string: only the property makes the diagnostic name the port. Do not "simplify" it back.

Type Parameters ​

Type Parameter
I extends readonly AnyModule[]
P extends readonly AnyProvider[]
N extends readonly AnyPort[] | undefined

PortClass() ​

ts
type PortClass<Id> = PortInstance<Id, Service>;

Defined in: port.ts:16

Type Parameters ​

Type Parameter
Id extends string
ts
type new PortClass<Service>(): PortInstance<Id, Service>;

Returns ​

PortInstance<Id, Service>

Properties ​

PropertyModifierTypeDefined in
portIdreadonlyIdport.ts:18

PortClassOf() ​

ts
type PortClassOf<Id, Service> = PortInstance<Id, Service>;

Defined in: port.ts:65

A concrete port class with Id and Service fixed — the type of provider.port for a helper that mints or targets a port the caller never spells. A class expression's type is anonymous and declaration emit cannot name it across packages; this is the nameable spelling.

Type Parameters ​

Type Parameter
Id extends string
Service
ts
type new PortClassOf(): PortInstance<Id, Service>;

A concrete port class with Id and Service fixed — the type of provider.port for a helper that mints or targets a port the caller never spells. A class expression's type is anonymous and declaration emit cannot name it across packages; this is the nameable spelling.

Returns ​

PortInstance<Id, Service>

Properties ​

PropertyModifierTypeDefined in
portIdreadonlyIdport.ts:66

PortInstance ​

ts
type PortInstance<Id, Service> = object;

Defined in: port.ts:11

The type that appears in a Needs / Exports union. Identity is the literal Id: two ports declared with different ids have different instance types even when their service shapes are identical.

Extended by ​

Type Parameters ​

Type Parameter
Id extends string
Service

Properties ​

PropertyModifierTypeDefined in
[ID]readonlyIdport.ts:12
[SERVICE]readonlyServiceport.ts:13

Provider ​

ts
type Provider<P, E, N> = object;

Defined in: provider.ts:146

The package's variance rule, stated here and on Module: capability channels (_port) are contravariant, obligation channels (_error, _needs) covariant.

With the obligation channels contravariant an ordinary return-type annotation laundered both — and with them the Scope ScopeOf puts in Needs, routing a resourceful provider to Module.build, which never closes the scope it opens, and silently dropping its release.

Type Parameters ​

Type Parameter
P
E
N

Properties ​

PropertyModifierTypeDefined in
_errorreadonly() => Eprovider.ts:148
_needsreadonly() => Nprovider.ts:149
_portreadonly(p) => voidprovider.ts:147
constructreadonly(services) => AsyncResult<unknown, unknown>provider.ts:155
depsreadonlyreadonly AnyPort[]provider.ts:151
onStartreadonly((service) => void | Promise<void>) | undefinedprovider.ts:157
onStopreadonly((service) => void | Promise<void>) | undefinedprovider.ts:158
portreadonlyAnyPortprovider.ts:150
releasereadonly((service) => void | Promise<void>) | undefinedprovider.ts:156

ProviderClass ​

ts
type ProviderClass<Id, D> = Provider<ProviderBase<Id, D>, never, NeedsOf<D>> & object & (abstract new (deps) => ProviderBase<Id, D>);

Defined in: provider.ts:283

What Provider.class(id, { inject }) returns: a port, a provider, and the base of both.

Type Parameters ​

Type Parameter
Id extends string
D extends Deps

Type Declaration ​

NameTypeDefined in
portIdIdprovider.ts:287

ScopedOptions ​

ts
type ScopedOptions = object;

Defined in: build.ts:237

Properties ​

PropertyModifierTypeDescriptionDefined in
onConstructionFailure?readonly(failure) => voidCalled after construction fails and before acquired resources are released.build.ts:240
onTeardownError?readonlyTeardownReporter-build.ts:238
seed?readonlyreadonly SeedEntry<AnyPort>[]Values supplied to the scope from OUTSIDE its module tree, keyed by port. The planner treats a seeded port as provided, exactly as it treats the parent's services — a seed is more keys on the same context.build.ts:246

SeedEntry ​

ts
type SeedEntry<P> = readonly [port: P, value: ServiceOf<InstanceType<P>>];

Defined in: build.ts:235

Type Parameters ​

Type Parameter
P extends AnyPort

ServiceOf ​

ts
type ServiceOf<T> = T extends PortInstance<string, infer S> ? S : T extends abstract new (...args) => PortInstance<string, infer S> ? S : never;

Defined in: port.ts:71

Recovers a service shape from either the instance type or the class.

Type Parameters ​

Type Parameter
T

SetPortGate ​

ts
type SetPortGate<P> = [Extract<P, {
  many: true;
}>] extends [never] ? unknown : object;

Defined in: provider.ts:237

unknown unless P is, or includes, a set port, and a marker naming Provider.member otherwise. A wrapper forwarding a caller's port to Provider intersects it onto its own parameter, since a widened port passes.

Type Parameters ​

Type Parameter
P

Variables ​

Context ​

ts
Context: object;

Defined in: context.ts:36

Type Declaration ​

NameTypeDefined in
empty()() => Context<never>context.ts:77

Module ​

ts
Module: (<Name>(name) => <I, P, X, N>(options) => Module<ResolvedExports<X>, ErrOf<P[number]> | ErrOfModule<I[number]>, 
  | Exclude<NeedOf<P[number]>, Available<I, P>>
  | Exclude<NeedsOfModule<I[number]>, Available<I, P>>>) & object;

Defined in: module.ts:49

Module.build sorts the tree into dependency-ordered levels, checks for wiring bugs before any factory runs, then constructs level by level.

Type Declaration ​

NameTypeDescriptionDefined in
build()<X, E, N>(module) => AsyncResult<Context<X>, E>-module.ts:175
forkScope()<PParent, X, E, N, A, E2, Seeded>(parent, module, use, options?) => AsyncResult<A, E | E2>A short-lived scope layered over an already-built parent Context, for per-request services that must not outlive the request but do read what the parent constructed. The fork gets a fresh scope, so closing it releases only what the fork acquired and the parent stays up for a sibling. The gate subtracts PParent as well as Scope: a request module may depend on anything the parent already provides. It also subtracts InstanceType<Seeded>, for the same reason: a seed entry supplies a port from outside the tree exactly as the parent does.module.ts:204
scoped()<X, E, N, A, E2>(module, use, options?) => AsyncResult<A, E | E2>Module.build's resourceful counterpart: opens a scope, runs the module, hands the built Context to use, and closes the scope — releasing every acquired resource, LIFO — on every path out. The gate excludes Scope alone, since this is the entry point that discharges it; every other unmet requirement still surfaces.module.ts:186

Port ​

ts
const Port: (<Id>(id) => PortClass<Id>) & object;

Defined in: port.ts:169

Port.many is PortDeclaration plus a many: true static field — the runtime discriminant build.ts's plan/constructLevel read to decide a port accumulates contributions instead of colliding on the second provider. See ManyPortClass's own doc comment above for why this is a static field (readable at runtime off the class) rather than the [MANY] brand (a type-level-only marker on the never-instantiated instance type).

Type Declaration ​

NameTypeDefined in
many()<Id>(id) => ManyPortClass<Id>port.ts:170

Provider ​

ts
Provider: (<P>(port) => <D, O>(options) => Provider<InstanceType<P>, ErrorOf<O>, InstanceType<D[keyof D]> | ScopeOf<O>> & object) & object;

Defined in: provider.ts:146

Provider.member's port is bound by the structural AnyPort, not ManyPortClass<string>: a concrete set-port class has a concrete constructor once Member is fixed, so — exactly as with PortClass — it is not assignable to the generic form, and binding it that way would reject every real call site.

Instantiating S as MemberOf<P> is the whole difference: it qualifies an arm against ONE member's shape. The runtime body is the ordinary factory's; context.ts's unsafeAddAll is what turns a member into an array entry.

Type Declaration ​

NameTypeDefault valueDefined in
class()<Id, D>(id, __namedParameters) => ProviderClass<Id, D>providerClassprovider.ts:351
member()<P>(port) => <D, O>(options) => Provider<InstanceType<P>, ErrorOf<O>, InstanceType<D[keyof D]> | ScopeOf<O>> & object-provider.ts:350

Functions ​

overrideProvider() ​

ts
function overrideProvider<P, E, N, Q>(provider): Provider<P, E, N> & object;

Defined in: provider.ts:216

Type Parameters ​

Type Parameter
P
E
N
Q extends AnyPort

Parameters ​

ParameterType
providerProvider<P, E, N> & object

Returns ​

Provider<P, E, N> & object

Released under the MIT License.