di-bag 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -0
  3. package/dist/acquisition-context.d.ts +42 -0
  4. package/dist/acquisition-context.js +19 -0
  5. package/dist/acquisition-family.d.ts +32 -0
  6. package/dist/acquisition-family.js +135 -0
  7. package/dist/acquisition-mode.d.ts +34 -0
  8. package/dist/acquisition-mode.js +35 -0
  9. package/dist/acquisition.d.ts +44 -0
  10. package/dist/acquisition.js +395 -0
  11. package/dist/alias-types.d.ts +22 -0
  12. package/dist/alias-types.js +2 -0
  13. package/dist/aliases.d.ts +4 -0
  14. package/dist/aliases.js +24 -0
  15. package/dist/composition.d.ts +41 -0
  16. package/dist/composition.js +45 -0
  17. package/dist/contribution-types.d.ts +57 -0
  18. package/dist/contribution-types.js +2 -0
  19. package/dist/contributions.d.ts +3 -0
  20. package/dist/contributions.js +11 -0
  21. package/dist/dependency-references.d.ts +52 -0
  22. package/dist/dependency-references.js +53 -0
  23. package/dist/di-bag.d.ts +247 -0
  24. package/dist/di-bag.js +211 -0
  25. package/dist/errors.d.ts +66 -0
  26. package/dist/errors.js +89 -0
  27. package/dist/index.d.ts +25 -0
  28. package/dist/index.js +10 -0
  29. package/dist/inspection.d.ts +36 -0
  30. package/dist/inspection.js +2 -0
  31. package/dist/lifetime-types.d.ts +214 -0
  32. package/dist/lifetime-types.js +2 -0
  33. package/dist/lifetime.d.ts +42 -0
  34. package/dist/lifetime.js +31 -0
  35. package/dist/module-types.d.ts +182 -0
  36. package/dist/module-types.js +2 -0
  37. package/dist/module.d.ts +45 -0
  38. package/dist/module.js +118 -0
  39. package/dist/node.d.ts +4 -0
  40. package/dist/node.js +22 -0
  41. package/dist/observers.d.ts +71 -0
  42. package/dist/observers.js +58 -0
  43. package/dist/persistent-map.d.ts +29 -0
  44. package/dist/persistent-map.js +146 -0
  45. package/dist/persistent-sequence.d.ts +9 -0
  46. package/dist/persistent-sequence.js +20 -0
  47. package/dist/plugins.d.ts +32 -0
  48. package/dist/plugins.js +82 -0
  49. package/dist/provider-execution.d.ts +59 -0
  50. package/dist/provider-execution.js +271 -0
  51. package/dist/provider-operations.d.ts +59 -0
  52. package/dist/provider-operations.js +38 -0
  53. package/dist/provider.d.ts +199 -0
  54. package/dist/provider.js +158 -0
  55. package/dist/registration.d.ts +32 -0
  56. package/dist/registration.js +45 -0
  57. package/dist/replacement-types.d.ts +30 -0
  58. package/dist/replacement-types.js +2 -0
  59. package/dist/runtime.d.ts +90 -0
  60. package/dist/runtime.js +428 -0
  61. package/dist/scope-selection.d.ts +6 -0
  62. package/dist/scope-selection.js +62 -0
  63. package/dist/scope-types.d.ts +58 -0
  64. package/dist/scope-types.js +2 -0
  65. package/dist/startup.d.ts +14 -0
  66. package/dist/startup.js +141 -0
  67. package/dist/token-types.d.ts +67 -0
  68. package/dist/token-types.js +2 -0
  69. package/dist/tokens.d.ts +47 -0
  70. package/dist/tokens.js +69 -0
  71. package/dist/types.d.ts +174 -0
  72. package/dist/types.js +2 -0
  73. package/package.json +64 -0
package/dist/errors.js ADDED
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DiBagStartupCancelledError = exports.DiBagStartupError = exports.DiBagCleanupError = exports.DiBagPluginValidationError = void 0;
4
+ exports.diagnostic = diagnostic;
5
+ exports.libraryError = libraryError;
6
+ exports.libraryTypeError = libraryTypeError;
7
+ /** Attach only at library-owned error creation sites; never modify application errors. */
8
+ function diagnostic(error, code, details = {}) {
9
+ Object.defineProperties(error, {
10
+ code: { value: code, enumerable: true },
11
+ details: { value: Object.freeze({ ...details }), enumerable: true },
12
+ });
13
+ return error;
14
+ }
15
+ function libraryError(code, message, details = {}) {
16
+ return diagnostic(new Error(message), code, details);
17
+ }
18
+ function libraryTypeError(code, message, details = {}) {
19
+ return diagnostic(new TypeError(message), code, details);
20
+ }
21
+ /** A plugin descriptor or produced value crossed the checked plugin boundary. */
22
+ class DiBagPluginValidationError extends Error {
23
+ phase;
24
+ reason;
25
+ /**
26
+ * @param phase - Whether descriptor authentication or output validation failed.
27
+ * @param reason - A stable description of the rejected boundary condition.
28
+ */
29
+ constructor(phase, reason) {
30
+ super(`Invalid plugin ${phase}: ${reason}`);
31
+ this.phase = phase;
32
+ this.reason = reason;
33
+ this.name = 'DiBagPluginValidationError';
34
+ diagnostic(this, 'DI_BAG_PLUGIN_VALIDATION', { operation: 'fromPlugin', phase, reason });
35
+ }
36
+ }
37
+ exports.DiBagPluginValidationError = DiBagPluginValidationError;
38
+ /** Original cleanup causes and detached acquisition diagnostics, in attempt order. */
39
+ class DiBagCleanupError extends AggregateError {
40
+ /** Frozen cleanup failures in finalizer invocation order. */
41
+ failures;
42
+ /** @param failures - Structured failures whose original errors also populate `AggregateError.errors`. */
43
+ constructor(failures) {
44
+ const snapshot = Object.freeze(failures.map(item => Object.freeze({ ...item })));
45
+ super(snapshot.map(item => item.error), `Failed to run ${snapshot.length} disposal callback(s)`);
46
+ this.name = 'DiBagCleanupError';
47
+ diagnostic(this, 'DI_BAG_CLEANUP_FAILED', { operation: 'close', failedCallbacks: snapshot.length, failures: snapshot });
48
+ this.failures = snapshot;
49
+ }
50
+ }
51
+ exports.DiBagCleanupError = DiBagCleanupError;
52
+ /** Acquisition failure after the new bag has finished releasing its resources. */
53
+ class DiBagStartupError extends Error {
54
+ cleanupError;
55
+ /** Frozen rollback disposal failures in invocation order. */
56
+ cleanupFailures;
57
+ /**
58
+ * @param cause - The original selected-service acquisition failure.
59
+ * @param cleanupFailures - Structured failures collected while rolling back the new bag.
60
+ * @param cleanupError - The complete shutdown error, when rollback itself rejected.
61
+ */
62
+ constructor(cause, cleanupFailures, cleanupError) {
63
+ super('Failed to start bag', { cause });
64
+ this.cleanupError = cleanupError;
65
+ this.name = 'DiBagStartupError';
66
+ this.cleanupFailures = Object.freeze(cleanupFailures.map(item => Object.freeze({ ...item })));
67
+ diagnostic(this, 'DI_BAG_STARTUP_FAILED', { operation: 'buildAndStart', cleanupFailures: this.cleanupFailures });
68
+ }
69
+ }
70
+ exports.DiBagStartupError = DiBagStartupError;
71
+ /** Prompt cancellation; cleanup remains awaitable for uncooperative factories. */
72
+ class DiBagStartupCancelledError extends Error {
73
+ reason;
74
+ cleanupPromise;
75
+ /**
76
+ * @param reason - Whether an external abort or startup timeout cancelled the wait.
77
+ * @param cause - The abort reason or generated timeout error.
78
+ * @param cleanupPromise - Eventual shutdown of the partially started bag; cancellation does not await it.
79
+ */
80
+ constructor(reason, cause, cleanupPromise) {
81
+ super(`Bag startup ${reason}`, { cause });
82
+ this.reason = reason;
83
+ this.cleanupPromise = cleanupPromise;
84
+ this.name = 'DiBagStartupCancelledError';
85
+ diagnostic(this, 'DI_BAG_STARTUP_CANCELLED', { operation: 'buildAndStart', reason });
86
+ void cleanupPromise.catch(() => { });
87
+ }
88
+ }
89
+ exports.DiBagStartupCancelledError = DiBagStartupCancelledError;
@@ -0,0 +1,25 @@
1
+ export { DiBag } from './di-bag';
2
+ export { DiBagCleanupError, DiBagPluginValidationError, DiBagStartupError, DiBagStartupCancelledError } from './errors';
3
+ export type { CleanupFailure, DiBagErrorCode, DiBagDiagnostic } from './errors';
4
+ export type { Bag, Builder, DiBagApi, ConfigurationOptions } from './di-bag';
5
+ export type { Module } from './module';
6
+ export type { ModuleExportedServices, ModuleRequiredServices, ModuleConstraints, ModuleSealedConstraints, SealedConstraints, PublicProviders, ModulePublicProviders, Renamed } from './module-types';
7
+ export type { FactoryWithDisposal, Registration } from './registration';
8
+ export type { Provider, ProviderFactory, ProviderGraphContract, ProviderOutput, ProviderAcquiredValue, ProviderNamedDependencies, ProviderRegistrationMetadata, ProviderAcquisitionMetadata, ProviderRequiredTokens, ProviderOptionalTokens, ProviderCollectionTokens } from './provider';
9
+ export type { AcquisitionMode, RuntimeOptions } from './acquisition-mode';
10
+ export type { Lifetime } from './lifetime';
11
+ export type { AcquisitionContext, ContextualFactory } from './acquisition-context';
12
+ export type { StartupOptions } from './startup';
13
+ export type { ScopeOptions, DisjointScopeSelection, UnsharedAliases, ScopedAliases, SharedAliasProviders } from './scope-types';
14
+ export type { Token, TokenBase, TokenKey, TokenService } from './tokens';
15
+ export type { TokenBinding, TokenMember, TokenDependencyContract, ReboundProviders, ReboundSelection, SelectionKey } from './token-types';
16
+ export type { CheckedLifetimes, CheckedScopeLifetimes, LexicalContext, ModuleScope, Enclosed, RenamedContext, RenamedLifetimeObligation, EnclosedLifetimeObligation, RenamedLifetimeProviders } from './lifetime-types';
17
+ export type { CheckDependencyCompatibility, CheckDependencyCompleteness, RegistrationEntries, OverrideFactoryContext, RegistrationsFromEntries, OverrideRegistrations, Overrides, ServicesOf, SelectedRegistrations, Selection } from './types';
18
+ export type { Presence, AcquisitionMetadataPresence, AcquisitionSnapshot, RegistrationSnapshot } from './inspection';
19
+ export type { CompositionArguments, CompositionFunction } from './composition';
20
+ export type { OptionalDependency, LazyDependency, CollectionDependency, DependencyReference } from './dependency-references';
21
+ export type { PluginProviderFactory, PluginAcquisitionMode, PluginOptions, PluginOutputValidator, PluginProvider } from './plugins';
22
+ export type { AliasRegistration, AliasEntries, AliasOutput } from './alias-types';
23
+ export type { Contribution, ContributionConstraint, ModuleContributions, ModuleContributionConstraints } from './contribution-types';
24
+ export type { BuilderContribute } from './contribution-types';
25
+ export type { LifecycleEvent, ObserverFailure, ObserverCallback, ObserverErrorCallback, ObserverOptions, ScopeEventFields, AcquisitionEventFields } from './observers';
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DiBagStartupCancelledError = exports.DiBagStartupError = exports.DiBagPluginValidationError = exports.DiBagCleanupError = exports.DiBag = void 0;
4
+ var di_bag_1 = require("./di-bag");
5
+ Object.defineProperty(exports, "DiBag", { enumerable: true, get: function () { return di_bag_1.DiBag; } });
6
+ var errors_1 = require("./errors");
7
+ Object.defineProperty(exports, "DiBagCleanupError", { enumerable: true, get: function () { return errors_1.DiBagCleanupError; } });
8
+ Object.defineProperty(exports, "DiBagPluginValidationError", { enumerable: true, get: function () { return errors_1.DiBagPluginValidationError; } });
9
+ Object.defineProperty(exports, "DiBagStartupError", { enumerable: true, get: function () { return errors_1.DiBagStartupError; } });
10
+ Object.defineProperty(exports, "DiBagStartupCancelledError", { enumerable: true, get: function () { return errors_1.DiBagStartupCancelledError; } });
@@ -0,0 +1,36 @@
1
+ /** Structural optional presence; payloads are application-owned and not frozen. */
2
+ export type Presence<T> = {
3
+ readonly present: false;
4
+ } | {
5
+ readonly present: true;
6
+ readonly value: T;
7
+ };
8
+ /** A readonly tuple indicating whether each acquisition-stage frame is available. */
9
+ export type AcquisitionMetadataPresence<A extends readonly unknown[]> = {
10
+ readonly [I in keyof A]: Presence<A[I]>;
11
+ };
12
+ /** A frozen point-in-time view of one acquisition attempt. */
13
+ export interface AcquisitionSnapshot<A extends readonly unknown[] = readonly []> {
14
+ /** Stable identity for this attempt; retries receive a new symbol. */
15
+ readonly acquisitionId: symbol;
16
+ /** State at the instant the snapshot was copied. */
17
+ readonly state: 'creating' | 'pending' | 'ready' | 'failed' | 'disposing' | 'disposed';
18
+ /** Ordered presence records for metadata captured during acquisition. */
19
+ readonly acquisitionMetadata: AcquisitionMetadataPresence<A>;
20
+ }
21
+ /** A frozen registration description and copied acquisition state returned by bag inspection. */
22
+ export interface RegistrationSnapshot<M = Readonly<{}>, A extends readonly unknown[] = readonly []> {
23
+ /** Stable identity for the canonical graph binding. */
24
+ readonly bindingId: symbol;
25
+ /** Human-readable binding label. */
26
+ readonly label: string;
27
+ /** Direct lexical target; acquisition snapshots follow the canonical target. */
28
+ readonly aliasTarget?: {
29
+ readonly bindingId: symbol;
30
+ readonly label: string;
31
+ };
32
+ /** Static registration metadata; application-owned payload values retain their identity. */
33
+ readonly registrationMetadata: Readonly<M>;
34
+ /** Point-in-time attempts; inspection does not retain failed-attempt history. */
35
+ readonly acquisitions: readonly AcquisitionSnapshot<A>[];
36
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,214 @@
1
+ import type { ContributionConstraint } from './contribution-types';
2
+ import type { Registration, Registrations } from './registration';
3
+ import type { Provider, ProviderFactory, ProviderGraphContract, ProviderNamedDependencies, ProviderRequiredTokens, ProviderOptionalTokens, ProviderCollectionTokens, ProviderRegistrationMetadata, ProviderAcquisitionMetadata, ProviderAcquiredValue } from './provider';
4
+ import type { GraphContract } from './token-types';
5
+ import type { TokenKey } from './tokens';
6
+ import type { CheckDependencyCompatibility, CheckDependencyCompleteness, Unsatisfied } from './types';
7
+ import type { CheckedConstraints, CompleteConstraints, NeedConstraint, Renamed } from './module-types';
8
+ /**
9
+ * A module provider's retained local registrations and public-to-local export mapping.
10
+ * Contexts chain through `parent` when a module was sealed inside another module:
11
+ * a name absent from `registrations` resolves in the parent, and the chain end
12
+ * resolves in the installing host, matching runtime lexical lookup.
13
+ */
14
+ export type LexicalContext<R extends Registrations = Registrations, E extends object = object> = {
15
+ readonly registrations: R;
16
+ /** Current public name -> original local name. */
17
+ readonly exports: E;
18
+ readonly parent?: LexicalContext;
19
+ };
20
+ /** The lexical scope a sealing builder gives its retained constraints and providers. */
21
+ export type ModuleScope<R extends Registrations, P extends PropertyKey> = LexicalContext<R, ExportMap<P>>;
22
+ type Extras<C> = Pick<C, Exclude<keyof C, keyof LexicalContext>>;
23
+ type WithExtras<C, X> = [Exclude<keyof C, keyof LexicalContext>] extends [never] ? X : X & Extras<C>;
24
+ /** Attach an enclosing scope at the end of a lexical chain; `undefined` leaves the chain unchanged. */
25
+ export type Enclosed<C, Parent> = [Parent] extends [undefined] ? C : C extends LexicalContext<infer R, infer E> ? C extends {
26
+ readonly parent: infer P extends LexicalContext;
27
+ } ? WithExtras<C, LexicalContext<R, E> & {
28
+ readonly parent: Enclosed<P, Parent>;
29
+ }> : WithExtras<C, LexicalContext<R, E> & {
30
+ readonly parent: Parent;
31
+ }> : C;
32
+ /** Rename one public export at the chain end, where names meet the installing host. */
33
+ export type RenamedContext<C, Old extends string, New extends string> = C extends LexicalContext<infer R, infer E> ? C extends {
34
+ readonly parent: infer P extends LexicalContext;
35
+ } ? WithExtras<C, LexicalContext<R, E> & {
36
+ readonly parent: RenamedContext<P, Old, New>;
37
+ }> : WithExtras<C, LexicalContext<R, Renamed<E, Old, New>>> : C;
38
+ /** The plain scope of a sealed contribution, without its retained original registration. */
39
+ type Scope<C> = C extends LexicalContext<infer R, infer E> ? C extends {
40
+ readonly parent: infer P extends LexicalContext;
41
+ } ? LexicalContext<R, E> & {
42
+ readonly parent: P;
43
+ } : LexicalContext<R, E> : undefined;
44
+ type WithoutLexical<G> = G extends {
45
+ readonly lexical: unknown;
46
+ } ? Omit<G, 'lexical'> : G;
47
+ export type LifetimeObligation = {
48
+ readonly kind: 'lifetime';
49
+ readonly source: PropertyKey;
50
+ readonly context: LexicalContext;
51
+ };
52
+ type ExportMap<P extends PropertyKey> = {
53
+ readonly [K in P]: K;
54
+ };
55
+ type Strict<R> = ProviderGraphContract<R> extends infer G ? G extends {
56
+ readonly lifetime: {
57
+ readonly kind: 'root';
58
+ readonly allowScopedDependencies: infer C;
59
+ };
60
+ } ? [C] extends [true] ? false : true : false : false;
61
+ export type PrivateLifetimes<R extends Registrations, P extends keyof R> = {
62
+ [K in Exclude<keyof R, P>]: true extends Strict<R[K]> ? {
63
+ readonly kind: 'lifetime';
64
+ readonly source: K;
65
+ readonly context: LexicalContext<R, ExportMap<P>>;
66
+ } : never;
67
+ }[Exclude<keyof R, P>];
68
+ export type LexicalProvider<V extends Registration, R extends Registrations, P extends keyof R, K extends keyof R> = V extends infer T & {} ? T extends Registration ? [Extract<ProviderGraphContract<T>, {
69
+ readonly lifetime: {
70
+ readonly kind: 'root' | 'transient';
71
+ };
72
+ } | {
73
+ readonly alias: PropertyKey;
74
+ }>] extends [never] ? T : Provider<ProviderFactory<T>, ProviderRegistrationMetadata<T> & object, ProviderAcquisitionMetadata<T>, WithoutLexical<ProviderGraphContract<T>> & {
75
+ readonly lexical: {
76
+ readonly source: K;
77
+ readonly context: ModuleScope<R, P>;
78
+ };
79
+ }, ProviderAcquiredValue<T>> : never : never;
80
+ type RenamedGraph<G extends GraphContract, Old extends string, New extends string> = G extends {
81
+ readonly lexical: {
82
+ readonly source: infer K;
83
+ readonly context: infer L extends LexicalContext;
84
+ };
85
+ } ? Omit<G, 'lexical'> & {
86
+ readonly lexical: {
87
+ readonly source: K;
88
+ readonly context: RenamedContext<L, Old, New>;
89
+ };
90
+ } : G;
91
+ export type RenamedLifetimeProvider<V extends Registration, Old extends string, New extends string> = V extends infer T & {} ? T extends Registration ? ProviderGraphContract<T> extends {
92
+ readonly lexical: unknown;
93
+ } ? Provider<ProviderFactory<T>, ProviderRegistrationMetadata<T> & object, ProviderAcquisitionMetadata<T>, RenamedGraph<ProviderGraphContract<T>, Old, New>, ProviderAcquiredValue<T>> : T : never : never;
94
+ /** Rename public lifetime-carrier registrations while preserving their lexical sources. */
95
+ export type RenamedLifetimeProviders<D extends Registrations, Old extends string, New extends string> = {
96
+ [K in keyof D as K extends Old ? New : K]: RenamedLifetimeProvider<D[K], Old, New>;
97
+ };
98
+ /** Rename a retained lifetime obligation's public export view. */
99
+ export type RenamedLifetimeObligation<C extends LifetimeObligation, Old extends string, New extends string> = {
100
+ readonly kind: 'lifetime';
101
+ readonly source: C['source'];
102
+ readonly context: RenamedContext<C['context'], Old, New>;
103
+ };
104
+ /** Re-scope a retained obligation when the builder holding it seals into a module. */
105
+ export type EnclosedLifetimeObligation<C extends LifetimeObligation, R extends Registrations, P extends PropertyKey> = {
106
+ readonly kind: 'lifetime';
107
+ readonly source: C['source'];
108
+ readonly context: Enclosed<C['context'], ModuleScope<R, P>>;
109
+ };
110
+ type PublicSite<K> = {
111
+ readonly kind: 'public';
112
+ readonly key: K;
113
+ };
114
+ type PrivateSite<C, K> = {
115
+ readonly kind: 'private';
116
+ readonly context: C;
117
+ readonly key: K;
118
+ };
119
+ type Captive<Root, Site> = {
120
+ readonly root: Root;
121
+ readonly dependency: Site;
122
+ };
123
+ type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;
124
+ type Seen<S, V> = true extends (V extends unknown ? Equal<S, V> : never) ? true : false;
125
+ type PublicKey<E, K> = {
126
+ [P in keyof E]: Equal<E[P], K> extends true ? P : never;
127
+ }[keyof E];
128
+ type Dependencies<V extends Registration> = keyof ProviderNamedDependencies<V> | TokenKey<ProviderRequiredTokens<V> | ProviderOptionalTokens<V>>;
129
+ type WalkEnclosing<H extends Registrations, C, K, Root, Visited, G> = C extends {
130
+ readonly parent: infer P extends LexicalContext;
131
+ } ? WalkDependency<H, P, K, Root, Visited, G> : WalkPublic<H, K, Root, Visited, G>;
132
+ type WalkDependency<H extends Registrations, C, K, Root, Visited, G> = K extends PropertyKey ? C extends LexicalContext<infer R, infer E> ? K extends keyof R ? [PublicKey<E, K>] extends [never] ? WalkTarget<H, R[K], C, Root, PrivateSite<C, K>, Visited, G> : WalkEnclosing<H, C, PublicKey<E, K>, Root, Visited, G> : WalkEnclosing<H, C, K, Root, Visited, G> : WalkPublic<H, K, Root, Visited, G> : never;
133
+ type WalkPublic<H extends Registrations, K, Root, Visited, G> = K extends keyof H ? WalkTarget<H, H[K], undefined, Root, PublicSite<K>, Visited, G> : never;
134
+ type WalkTarget<H extends Registrations, V extends Registration, C, Root, Site, Visited, G> = V extends infer T & {} ? T extends Registration ? ProviderGraphContract<T> extends infer PG ? PG extends {
135
+ readonly sharedAlias: {
136
+ readonly registrations: infer P extends Registrations;
137
+ readonly source: infer K;
138
+ };
139
+ } ? WalkPublic<P, K, Root, never, G> : PG extends {
140
+ readonly kind: 'opaque';
141
+ } ? never : PG extends {
142
+ readonly alias: PropertyKey;
143
+ } ? Seen<Site, Visited> extends true ? never : WalkSource<H, T, C, Root, Visited | Site, G> : PG extends {
144
+ readonly lifetime: {
145
+ readonly kind: 'root';
146
+ };
147
+ } ? never : PG extends {
148
+ readonly lifetime: {
149
+ readonly kind: 'transient';
150
+ };
151
+ } ? Seen<Site, Visited> extends true ? never : WalkSource<H, T, C, Root, Visited | Site, G> : Captive<Root, Site> : never : never : never;
152
+ type WalkSource<H extends Registrations, V extends Registration, C, Root, Visited, G> = ProviderGraphContract<V> extends {
153
+ readonly lexical: {
154
+ readonly source: infer K;
155
+ readonly context: infer L extends LexicalContext;
156
+ };
157
+ } ? K extends keyof L['registrations'] ? WalkSource<H, L['registrations'][K], Enclosed<L, C>, Root, Visited, G> : never : WalkDeclared<H, V, C, Root, Visited, G>;
158
+ type WalkDeclared<H extends Registrations, V extends Registration, C, Root, Visited, G> = unknown extends (C extends LexicalContext ? CheckDependencyCompatibility<C['registrations']> : unknown) ? WalkDependency<H, C, Dependencies<V>, Root, Visited, G> | WalkCollection<H, ProviderCollectionTokens<V>, Root, Visited, G> : never;
159
+ type CheckRoot<H extends Registrations, V extends Registration, C, Site, G> = V extends infer T & {} ? T extends Registration ? true extends Strict<T> ? WalkSource<H, T, C, Site, Site, G> : never : never : never;
160
+ type PublicCaptives<H extends Registrations, G> = {
161
+ [K in keyof H]: CheckRoot<H, H[K], undefined, PublicSite<K>, G>;
162
+ }[keyof H];
163
+ type PrivateCaptives<H extends Registrations, C, G> = C extends LifetimeObligation ? C['source'] extends keyof C['context']['registrations'] ? CheckRoot<H, C['context']['registrations'][C['source']], C['context'], PrivateSite<C['context'], C['source']>, G> : never : never;
164
+ type ContributionSite<C> = {
165
+ readonly kind: 'contribution';
166
+ readonly contribution: C;
167
+ };
168
+ type ContributionRegistration<I extends ContributionConstraint> = I['context'] extends {
169
+ readonly registration: infer O extends Registration;
170
+ } ? O : I['registration'];
171
+ type ContributionScope<I extends ContributionConstraint> = Scope<I['context']>;
172
+ type WalkCollection<H extends Registrations, T, Root, Visited, G, Items = Extract<G, ContributionConstraint>> = Items extends ContributionConstraint ? TokenKey<Items['token']> extends TokenKey<T> ? WalkTarget<H, ContributionRegistration<Items>, ContributionScope<Items>, Root, ContributionSite<Items>, Visited, G> : never : never;
173
+ type ContributionCaptives<H extends Registrations, G, Items = Extract<G, ContributionConstraint>> = Items extends ContributionConstraint ? CheckRoot<H, ContributionRegistration<Items>, ContributionScope<Items>, ContributionSite<Items>, G> : never;
174
+ type Captives<R extends Registrations, C> = PublicCaptives<R, C> | PrivateCaptives<R, C, C> | ContributionCaptives<R, C>;
175
+ type OverrideCaptives<R extends Registrations, O extends Registrations, G> = {
176
+ [K in keyof O & keyof R]: CheckRoot<R, R[K], undefined, PublicSite<K>, G>;
177
+ }[keyof O & keyof R];
178
+ /** Reject root providers introduced by a scope override when they capture scoped dependencies. */
179
+ export type CheckedScopeLifetimes<R extends Registrations, O extends Registrations, G = never> = [
180
+ OverrideCaptives<R, O, G>
181
+ ] extends [never] ? unknown : Unsatisfied<'root lifetime cannot capture scoped dependency', {
182
+ readonly captives: OverrideCaptives<R, O, G>;
183
+ }>;
184
+ /** Reject strict root providers that transitively capture scoped dependencies. */
185
+ export type CheckedLifetimes<R extends Registrations, C extends NeedConstraint> = [
186
+ Captives<R, C>
187
+ ] extends [never] ? unknown : unknown extends CheckDependencyCompatibility<R> & CheckDependencyCompleteness<R> & CheckedConstraints<C, R> & CompleteConstraints<C, R> ? Unsatisfied<'root lifetime cannot capture scoped dependency', {
188
+ readonly captives: Captives<R, C>;
189
+ }> : unknown;
190
+ type PolicyEnclosing<H extends Registrations, C, K, Visited> = C extends {
191
+ readonly parent: infer P extends LexicalContext;
192
+ } ? PolicyDependency<H, P, K, Visited> : PolicyPublic<H, K, Visited>;
193
+ type PolicyDependency<H extends Registrations, C, K, Visited> = K extends PropertyKey ? C extends LexicalContext<infer R, infer E> ? K extends keyof R ? [PublicKey<E, K>] extends [never] ? PolicyTarget<H, R[K], C, PrivateSite<C, K>, Visited> : PolicyEnclosing<H, C, PublicKey<E, K>, Visited> : PolicyEnclosing<H, C, K, Visited> : PolicyPublic<H, K, Visited> : never;
194
+ type PolicyPublic<H extends Registrations, K, Visited> = K extends keyof H ? PolicyTarget<H, H[K], undefined, PublicSite<K>, Visited> : never;
195
+ type PolicyTarget<H extends Registrations, V extends Registration, C, Site, Visited> = Seen<Site, Visited> extends true ? never : PolicyGraph<H, V, C, Visited | Site>;
196
+ type PolicyGraph<H extends Registrations, V extends Registration, C, Visited> = ProviderGraphContract<V> extends infer G ? G extends {
197
+ readonly sharedAlias: {
198
+ readonly registrations: infer P extends Registrations;
199
+ readonly source: infer K;
200
+ };
201
+ } ? PolicyPublic<P, K, never> : G extends {
202
+ readonly lexical: {
203
+ readonly source: infer S;
204
+ readonly context: infer L extends LexicalContext;
205
+ };
206
+ } ? S extends keyof L['registrations'] ? PolicyGraph<H, L['registrations'][S], Enclosed<L, C>, Visited> : never : G extends {
207
+ readonly alias: infer K;
208
+ } ? PolicyDependency<H, C, K, Visited> : G extends {
209
+ readonly lifetime: {
210
+ readonly kind: infer K;
211
+ };
212
+ } ? K : 'scoped' : never;
213
+ export type CanonicalLifetime<R extends Registrations, K extends keyof R> = PolicyPublic<R, K, never>;
214
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,42 @@
1
+ import type { Registration } from './registration';
2
+ import type { Provider, ProviderFactory, RetainedMetadata, ProviderAcquisitionMetadata, ProviderGraphContract, ProviderAcquiredValue } from './provider';
3
+ import type { GraphContract } from './token-types';
4
+ import type { Singleton, Unsatisfied } from './types';
5
+ /** Cache at the ownership-family root, once per scope, or once per resolution. */
6
+ export type Lifetime = 'root' | 'scoped' | 'transient';
7
+ export interface LifetimePolicy {
8
+ readonly kind: Lifetime;
9
+ readonly allowScopedDependencies: boolean;
10
+ }
11
+ type Admission<L> = Singleton<L> extends true ? unknown : Unsatisfied<'lifetime requires an individually known policy literal', {}>;
12
+ type InvalidOption<L, O> = O extends infer T & {} ? T extends unknown ? Exclude<keyof T, 'allowScopedDependencies'> extends never ? L extends 'root' ? T extends {
13
+ readonly allowScopedDependencies?: boolean;
14
+ } ? never : true : 'allowScopedDependencies' extends keyof T ? true : never : true : never : never;
15
+ type Options<L, O> = [InvalidOption<L, O>] extends [never] ? unknown : InvalidOptions;
16
+ type InvalidOptions = Unsatisfied<'withLifetime allowScopedDependencies requires root lifetime and a boolean value', {}>;
17
+ export type LifetimeGraph<G extends GraphContract, L extends Lifetime, O> = G extends infer T & {} ? T extends GraphContract ? L extends 'scoped' ? 'lifetime' extends keyof T ? Omit<T, 'lifetime'> : T : Omit<T, 'lifetime'> & {
18
+ readonly lifetime: {
19
+ readonly kind: L;
20
+ readonly allowScopedDependencies: [O] extends [{
21
+ readonly allowScopedDependencies: true;
22
+ }] ? true : false;
23
+ };
24
+ } : never : never;
25
+ /**
26
+ * Select family-root caching, per-scope caching, or a fresh owned attempt per read.
27
+ * Strict roots cannot capture scoped dependencies. Wrapping preserves the factory,
28
+ * acquired value, metadata, frames, and ownership stages.
29
+ * @param registration - The registration whose caching policy to replace.
30
+ * @param lifetime - An individually known `root`, `scoped`, or `transient` literal.
31
+ * @returns A provider with the selected lifetime policy.
32
+ */
33
+ export declare function withLifetime<R extends Registration, const L extends Lifetime>(registration: R & Registration, lifetime: L & Admission<L>): Provider<ProviderFactory<R>, RetainedMetadata<R>, ProviderAcquisitionMetadata<R>, LifetimeGraph<ProviderGraphContract<R>, L, undefined>, ProviderAcquiredValue<R>>;
34
+ /**
35
+ * Select a lifetime and optionally permit a root provider to capture scoped dependencies.
36
+ * @param registration - The registration whose caching policy to replace.
37
+ * @param lifetime - An individually known `root`, `scoped`, or `transient` literal.
38
+ * @param options - Root-only `{ allowScopedDependencies: boolean }` admission.
39
+ * @returns A provider preserving factory, output, metadata, frames, and ownership stages.
40
+ */
41
+ export declare function withLifetime<R extends Registration, const L extends Lifetime, const O extends object | undefined>(registration: R & Registration, lifetime: L & Admission<L>, options: O & Options<NoInfer<L>, NoInfer<O>>): Provider<ProviderFactory<R>, RetainedMetadata<R>, ProviderAcquisitionMetadata<R>, LifetimeGraph<ProviderGraphContract<R>, L, O>, ProviderAcquiredValue<R>>;
42
+ export {};
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withLifetime = withLifetime;
4
+ const errors_1 = require("./errors");
5
+ const provider_1 = require("./provider");
6
+ const provider_operations_1 = require("./provider-operations");
7
+ function withLifetime(registration, lifetime, options) {
8
+ if (lifetime !== 'root' && lifetime !== 'scoped' && lifetime !== 'transient')
9
+ throw (0, errors_1.libraryError)('DI_BAG_INVALID_LIFETIME', 'invalid lifetime policy', { operation: 'withLifetime', lifetime });
10
+ let allowScopedDependencies = false;
11
+ if (options !== undefined) {
12
+ if (typeof options !== 'object' || options === null || Array.isArray(options))
13
+ throw (0, errors_1.libraryError)('DI_BAG_INVALID_LIFETIME', 'invalid lifetime options', { operation: 'withLifetime', lifetime });
14
+ const keys = Reflect.ownKeys(options);
15
+ if (keys.some(key => key !== 'allowScopedDependencies') || ('allowScopedDependencies' in options && !Object.hasOwn(options, 'allowScopedDependencies')))
16
+ throw (0, errors_1.libraryError)('DI_BAG_INVALID_LIFETIME', 'invalid lifetime options', { operation: 'withLifetime', lifetime });
17
+ if (keys.length) {
18
+ if (lifetime !== 'root')
19
+ throw (0, errors_1.libraryError)('DI_BAG_INVALID_LIFETIME', 'withLifetime allowScopedDependencies requires root lifetime', { operation: 'withLifetime', lifetime });
20
+ const selected = Reflect.get(options, 'allowScopedDependencies');
21
+ if (typeof selected !== 'boolean')
22
+ throw (0, errors_1.libraryError)('DI_BAG_INVALID_LIFETIME', 'withLifetime allowScopedDependencies must be boolean', { operation: 'withLifetime', lifetime });
23
+ allowScopedDependencies = selected;
24
+ }
25
+ }
26
+ const policy = Object.freeze({ kind: lifetime, allowScopedDependencies });
27
+ const description = (0, provider_operations_1.describe)(registration);
28
+ const handle = (0, provider_1.createProvider)();
29
+ (0, provider_operations_1.retainDescription)(handle, Object.freeze({ ...description, lifetime: policy }));
30
+ return handle;
31
+ }