@codefast/di 0.3.13-canary.4

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 (50) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/LICENSE +21 -0
  3. package/README.md +572 -0
  4. package/dist/binding-select.d.mts +22 -0
  5. package/dist/binding-select.mjs +50 -0
  6. package/dist/binding.d.mts +219 -0
  7. package/dist/binding.mjs +240 -0
  8. package/dist/constraints.d.mts +18 -0
  9. package/dist/constraints.mjs +24 -0
  10. package/dist/container.d.mts +82 -0
  11. package/dist/container.mjs +406 -0
  12. package/dist/decorators/inject.d.mts +24 -0
  13. package/dist/decorators/inject.mjs +69 -0
  14. package/dist/decorators/injectable.d.mts +40 -0
  15. package/dist/decorators/injectable.mjs +62 -0
  16. package/dist/decorators/lifecycle-decorators.d.mts +13 -0
  17. package/dist/decorators/lifecycle-decorators.mjs +34 -0
  18. package/dist/dependency-graph.d.mts +35 -0
  19. package/dist/dependency-graph.mjs +126 -0
  20. package/dist/environment.d.mts +14 -0
  21. package/dist/environment.mjs +20 -0
  22. package/dist/errors.d.mts +100 -0
  23. package/dist/errors.mjs +152 -0
  24. package/dist/index.d.mts +10 -0
  25. package/dist/index.mjs +8 -0
  26. package/dist/inspector.d.mts +76 -0
  27. package/dist/inspector.mjs +247 -0
  28. package/dist/lifecycle.d.mts +34 -0
  29. package/dist/lifecycle.mjs +83 -0
  30. package/dist/metadata/metadata-keys.d.mts +17 -0
  31. package/dist/metadata/metadata-keys.mjs +19 -0
  32. package/dist/metadata/metadata-types.d.mts +55 -0
  33. package/dist/metadata/metadata-types.mjs +1 -0
  34. package/dist/metadata/param-registry.d.mts +16 -0
  35. package/dist/metadata/param-registry.mjs +25 -0
  36. package/dist/metadata/symbol-metadata-reader.d.mts +15 -0
  37. package/dist/metadata/symbol-metadata-reader.mjs +32 -0
  38. package/dist/module.d.mts +60 -0
  39. package/dist/module.mjs +57 -0
  40. package/dist/registry.d.mts +38 -0
  41. package/dist/registry.mjs +65 -0
  42. package/dist/resolver.d.mts +102 -0
  43. package/dist/resolver.mjs +361 -0
  44. package/dist/scope-validation.d.mts +20 -0
  45. package/dist/scope-validation.mjs +34 -0
  46. package/dist/scope.d.mts +80 -0
  47. package/dist/scope.mjs +185 -0
  48. package/dist/token.d.mts +20 -0
  49. package/dist/token.mjs +9 -0
  50. package/package.json +157 -0
@@ -0,0 +1,126 @@
1
+ import { InternalError } from "./errors.mjs";
2
+ import { registryKeyLabel, selectBindingForRegistry } from "./binding-select.mjs";
3
+ //#region src/dependency-graph.ts
4
+ /** Converts a tag value to a printable string for graph edge labels. */
5
+ function formatTagValueForGraph(value) {
6
+ if (typeof value === "string") return value;
7
+ try {
8
+ return JSON.stringify(value);
9
+ } catch {
10
+ return String(value);
11
+ }
12
+ }
13
+ /** Converts a {@link ResolveHint} to a human-readable edge label for graph output (`name: x` / `tag: k=v`). */
14
+ function injectHintLabelFromResolveHint(hint) {
15
+ if (hint === void 0) return;
16
+ if (hint.name !== void 0) return `name: ${hint.name}`;
17
+ if (hint.tag !== void 0) {
18
+ const [tagKey, tagValue] = hint.tag;
19
+ return `tag: ${tagKey}=${formatTagValueForGraph(tagValue)}`;
20
+ }
21
+ }
22
+ /** Returns `"async"` when either the consumer or dependency binding is an `async-dynamic` factory. */
23
+ function edgeKindFor(consumer, dependency) {
24
+ if (consumer.kind === "async-dynamic" || dependency.kind === "async-dynamic") return "async";
25
+ return "sync";
26
+ }
27
+ /**
28
+ * Resolves the default (first matching, no hint) binding for `depKey`.
29
+ * Returns `undefined` when the key has no registered bindings.
30
+ */
31
+ function resolveDefaultBinding(lookup, depKey, pathPrefix) {
32
+ const label = registryKeyLabel(depKey);
33
+ const nextPath = [...pathPrefix, label];
34
+ const list = lookup(depKey);
35
+ if (list === void 0 || list.length === 0) return;
36
+ return selectBindingForRegistry(list, void 0, label, nextPath, void 0);
37
+ }
38
+ /**
39
+ * Follows alias bindings until a non-alias binding is reached.
40
+ * Returns the last reachable binding; stops if an alias target is unregistered.
41
+ */
42
+ function expandAliasChain(lookup, start, pathPrefix) {
43
+ let current = start;
44
+ let path = pathPrefix;
45
+ while (current.kind === "alias") {
46
+ const next = resolveDefaultBinding(lookup, current.targetToken, path);
47
+ if (next === void 0) return current;
48
+ const label = registryKeyLabel(current.targetToken);
49
+ path = [...path, label];
50
+ current = next;
51
+ }
52
+ return current;
53
+ }
54
+ /**
55
+ * Lists direct static dependencies (constructor metadata, `toResolved` tokens, alias targets).
56
+ * Factories (`toDynamic` / `toAsyncDynamic`) have no enumerable dependency keys.
57
+ */
58
+ function listResolvedDependencies(consumer, lookup, reader, pathPrefix) {
59
+ switch (consumer.kind) {
60
+ case "constant":
61
+ case "dynamic":
62
+ case "async-dynamic": return [];
63
+ case "alias": {
64
+ const binding = resolveDefaultBinding(lookup, consumer.targetToken, pathPrefix);
65
+ if (binding === void 0) return [];
66
+ const label = registryKeyLabel(consumer.targetToken);
67
+ const nextPath = [...pathPrefix, label];
68
+ return [{
69
+ binding: expandAliasChain(lookup, binding, nextPath),
70
+ path: nextPath,
71
+ injectHintLabel: void 0
72
+ }];
73
+ }
74
+ case "resolved": return consumer.dependencyTokens.map((tok) => {
75
+ const label = registryKeyLabel(tok);
76
+ const nextPath = [...pathPrefix, label];
77
+ const binding = resolveDefaultBinding(lookup, tok, pathPrefix);
78
+ if (binding === void 0) throw new InternalError(`Missing binding for dependency "${label}" while building dependency graph (resolution path: ${nextPath.join(" -> ")})`);
79
+ return {
80
+ binding: expandAliasChain(lookup, binding, nextPath),
81
+ path: nextPath,
82
+ injectHintLabel: void 0
83
+ };
84
+ });
85
+ case "class": {
86
+ if (reader === void 0) return [];
87
+ const meta = reader.getConstructorMetadata(consumer.implementationClass);
88
+ if (meta === void 0 || meta.params.length === 0) return [];
89
+ return meta.params.flatMap((param) => {
90
+ const tok = param.token;
91
+ const label = registryKeyLabel(tok);
92
+ const nextPath = [...pathPrefix, label];
93
+ const binding = resolveDefaultBinding(lookup, tok, pathPrefix);
94
+ if (binding === void 0) {
95
+ if (param.optional) return [];
96
+ throw new InternalError(`Missing binding for constructor parameter "${label}" while building dependency graph (resolution path: ${nextPath.join(" -> ")})`);
97
+ }
98
+ return [{
99
+ binding: expandAliasChain(lookup, binding, nextPath),
100
+ path: nextPath,
101
+ injectHintLabel: injectHintLabelFromResolveHint(param.name !== void 0 ? { name: param.name } : param.tag !== void 0 ? { tag: param.tag } : void 0)
102
+ }];
103
+ });
104
+ }
105
+ default: return consumer;
106
+ }
107
+ }
108
+ /**
109
+ * Flattens the direct dependencies of `consumer` into typed graph edges.
110
+ * Used by {@link ContainerInspector} to build DOT and JSON outputs.
111
+ */
112
+ function collectStaticDependencyEdges(consumer, lookup, reader, pathPrefix) {
113
+ const deps = listResolvedDependencies(consumer, lookup, reader, pathPrefix);
114
+ const isAliasEdge = consumer.kind === "alias";
115
+ return deps.map((dep) => ({
116
+ fromBindingId: consumer.id,
117
+ toBindingId: dep.binding.id,
118
+ resolutionPath: dep.path,
119
+ edgeKind: edgeKindFor(consumer, dep.binding),
120
+ toBindingConditional: dep.binding.constraint !== void 0,
121
+ injectHintLabel: dep.injectHintLabel,
122
+ isAliasEdge
123
+ }));
124
+ }
125
+ //#endregion
126
+ export { collectStaticDependencyEdges, injectHintLabelFromResolveHint, listResolvedDependencies };
@@ -0,0 +1,14 @@
1
+ //#region src/environment.d.ts
2
+ /**
3
+ * Node-style production gate using `process.env.NODE_ENV`.
4
+ * When `process` is unavailable, this returns false (not treated as production).
5
+ */
6
+ declare function isProductionEnvironment(): boolean;
7
+ /**
8
+ * True when not in production: `development`, `test`, unset `NODE_ENV`, or any value other than `"production"`.
9
+ * The container uses this to run one-time static scope validation after load/resolve so graph issues surface
10
+ * during local work and CI tests (e.g. Vitest).
11
+ */
12
+ declare function isDevelopmentOrTestEnvironment(): boolean;
13
+ //#endregion
14
+ export { isDevelopmentOrTestEnvironment, isProductionEnvironment };
@@ -0,0 +1,20 @@
1
+ //#region src/environment.ts
2
+ /**
3
+ * Node-style production gate using `process.env.NODE_ENV`.
4
+ * When `process` is unavailable, this returns false (not treated as production).
5
+ */
6
+ function isProductionEnvironment() {
7
+ const processRef = globalThis.process;
8
+ if (processRef === void 0 || processRef === null) return false;
9
+ return processRef.env.NODE_ENV === "production";
10
+ }
11
+ /**
12
+ * True when not in production: `development`, `test`, unset `NODE_ENV`, or any value other than `"production"`.
13
+ * The container uses this to run one-time static scope validation after load/resolve so graph issues surface
14
+ * during local work and CI tests (e.g. Vitest).
15
+ */
16
+ function isDevelopmentOrTestEnvironment() {
17
+ return !isProductionEnvironment();
18
+ }
19
+ //#endregion
20
+ export { isDevelopmentOrTestEnvironment, isProductionEnvironment };
@@ -0,0 +1,100 @@
1
+ import { Binding, BindingIdentifier, BindingScope, ResolveHint } from "./binding.mjs";
2
+
3
+ //#region src/errors.d.ts
4
+ /**
5
+ * Base error for all `@codefast/di` failures. Subclasses expose a stable, machine-readable `code`.
6
+ */
7
+ declare abstract class DiError extends Error {
8
+ abstract readonly code: string;
9
+ constructor(message: string, options?: ErrorOptions);
10
+ }
11
+ /**
12
+ * Raised for internal programming errors — invalid library usage or unexpected state that
13
+ * indicates a bug in the caller (e.g. accessing an uninitialized container, misconfigured binding).
14
+ */
15
+ declare class InternalError extends DiError {
16
+ readonly code = "INTERNAL_ERROR";
17
+ }
18
+ /**
19
+ * Raised when a name/tag filter matches no binding although other bindings exist for the token.
20
+ */
21
+ declare class NoMatchingBindingError extends DiError {
22
+ readonly code = "NO_MATCHING_BINDING";
23
+ readonly tokenName: string;
24
+ readonly hint: ResolveHint;
25
+ readonly resolutionPath: readonly string[];
26
+ constructor(tokenName: string, hint: ResolveHint, resolutionPath: readonly string[], options?: ErrorOptions);
27
+ }
28
+ /**
29
+ * Raised when resolving a value for a token that has no binding.
30
+ */
31
+ declare class TokenNotBoundError extends DiError {
32
+ readonly code = "TOKEN_NOT_BOUND";
33
+ readonly tokenName: string;
34
+ readonly resolutionPath: readonly string[];
35
+ constructor(tokenName: string, resolutionPath: readonly string[], options?: ErrorOptions);
36
+ }
37
+ /**
38
+ * Raised when the dependency graph contains a cycle during resolution.
39
+ */
40
+ declare class CircularDependencyError extends DiError {
41
+ readonly code = "CIRCULAR_DEPENDENCY";
42
+ readonly resolutionPath: readonly string[];
43
+ readonly cycle: string[];
44
+ constructor(resolutionPath: readonly string[], options?: ErrorOptions);
45
+ }
46
+ /**
47
+ * Raised when a class binding requires `@injectable()` / `Symbol.metadata` constructor metadata but none is present.
48
+ */
49
+ declare class MissingMetadataError extends DiError {
50
+ readonly code = "MISSING_METADATA";
51
+ readonly className: string;
52
+ readonly resolutionPath: readonly string[];
53
+ constructor(className: string, resolutionPath: readonly string[], options?: ErrorOptions);
54
+ }
55
+ /** Raised when `load()` is used with an async module. */
56
+ declare class AsyncModuleLoadError extends DiError {
57
+ readonly code = "ASYNC_MODULE_LOAD";
58
+ readonly moduleName: string;
59
+ constructor(moduleName: string, options?: ErrorOptions);
60
+ }
61
+ /**
62
+ * Raised when `resolve()` is called on a binding chain that contains an async factory or
63
+ * an async `onActivation` handler. Use `resolveAsync()` / `resolveAllAsync()` instead.
64
+ */
65
+ declare class AsyncResolutionError extends DiError {
66
+ readonly code = "ASYNC_RESOLUTION";
67
+ readonly tokenName: string;
68
+ readonly resolutionPath: readonly string[];
69
+ readonly reason: string;
70
+ constructor(tokenName: string, resolutionPath: readonly string[], reason: string, options?: ErrorOptions);
71
+ }
72
+ /** Structured payload attached to {@link ScopeViolationError}. */
73
+ type ScopeViolationDetails = {
74
+ readonly consumerBindingId: BindingIdentifier;
75
+ readonly consumerKind: Binding<unknown>["kind"];
76
+ readonly consumerScope: BindingScope;
77
+ readonly consumerLabel?: string;
78
+ readonly dependencyBindingId: BindingIdentifier;
79
+ readonly dependencyKind: Binding<unknown>["kind"];
80
+ readonly dependencyScope: BindingScope;
81
+ readonly dependencyLabel?: string;
82
+ readonly resolutionPath: readonly string[];
83
+ };
84
+ /**
85
+ * Raised when a long-lived binding would capture a shorter-lived (scoped or transient) dependency
86
+ * (captive dependency). Constant value dependencies are excluded.
87
+ */
88
+ declare class ScopeViolationError extends DiError {
89
+ readonly code = "SCOPE_VIOLATION";
90
+ readonly consumerBindingId: BindingIdentifier;
91
+ readonly consumerKind: Binding<unknown>["kind"];
92
+ readonly consumerScope: BindingScope;
93
+ readonly dependencyBindingId: BindingIdentifier;
94
+ readonly dependencyKind: Binding<unknown>["kind"];
95
+ readonly dependencyScope: BindingScope;
96
+ readonly resolutionPath: readonly string[];
97
+ constructor(details: ScopeViolationDetails, options?: ErrorOptions);
98
+ }
99
+ //#endregion
100
+ export { AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, InternalError, MissingMetadataError, NoMatchingBindingError, ScopeViolationDetails, ScopeViolationError, TokenNotBoundError };
@@ -0,0 +1,152 @@
1
+ //#region src/errors.ts
2
+ /** Formats a resolution path array into a human-readable `"A -> B -> C"` string. */
3
+ function formatResolutionPath(resolutionPath) {
4
+ return resolutionPath.length > 0 ? resolutionPath.join(" -> ") : "(empty)";
5
+ }
6
+ /** Serializes a {@link ResolveHint} to a debug string; never throws even for exotic values. */
7
+ function safeSerializeHint(hint) {
8
+ if (hint === void 0) return "(none)";
9
+ try {
10
+ const parts = [];
11
+ if (hint.name !== void 0) parts.push(`name: ${String(hint.name)}`);
12
+ if (hint.tag !== void 0) {
13
+ const [tagKey, tagValue] = hint.tag;
14
+ parts.push(`tag: [${tagKey}, <${typeof tagValue}>]`);
15
+ }
16
+ return `{ ${parts.join(", ")} }`;
17
+ } catch {
18
+ return "(unserializable hint)";
19
+ }
20
+ }
21
+ /**
22
+ * Base error for all `@codefast/di` failures. Subclasses expose a stable, machine-readable `code`.
23
+ */
24
+ var DiError = class extends Error {
25
+ constructor(message, options) {
26
+ super(message, options);
27
+ this.name = new.target.name;
28
+ }
29
+ };
30
+ /**
31
+ * Raised for internal programming errors — invalid library usage or unexpected state that
32
+ * indicates a bug in the caller (e.g. accessing an uninitialized container, misconfigured binding).
33
+ */
34
+ var InternalError = class extends DiError {
35
+ code = "INTERNAL_ERROR";
36
+ };
37
+ /**
38
+ * Raised when a name/tag filter matches no binding although other bindings exist for the token.
39
+ */
40
+ var NoMatchingBindingError = class extends DiError {
41
+ code = "NO_MATCHING_BINDING";
42
+ tokenName;
43
+ hint;
44
+ resolutionPath;
45
+ constructor(tokenName, hint, resolutionPath, options) {
46
+ const pathText = resolutionPath.length > 0 ? resolutionPath.join(" -> ") : "(empty)";
47
+ const hintText = safeSerializeHint(hint);
48
+ super(`No binding matched resolve options ${hintText} for token "${tokenName}" (resolution path: ${pathText})`, options);
49
+ this.tokenName = tokenName;
50
+ this.hint = hint;
51
+ this.resolutionPath = resolutionPath;
52
+ }
53
+ };
54
+ /**
55
+ * Raised when resolving a value for a token that has no binding.
56
+ */
57
+ var TokenNotBoundError = class extends DiError {
58
+ code = "TOKEN_NOT_BOUND";
59
+ tokenName;
60
+ resolutionPath;
61
+ constructor(tokenName, resolutionPath, options) {
62
+ const pathText = formatResolutionPath(resolutionPath);
63
+ super(`Token not bound: ${tokenName} (resolution path: ${pathText})`, options);
64
+ this.tokenName = tokenName;
65
+ this.resolutionPath = resolutionPath;
66
+ }
67
+ };
68
+ /**
69
+ * Raised when the dependency graph contains a cycle during resolution.
70
+ */
71
+ var CircularDependencyError = class extends DiError {
72
+ code = "CIRCULAR_DEPENDENCY";
73
+ resolutionPath;
74
+ cycle;
75
+ constructor(resolutionPath, options) {
76
+ const pathText = formatResolutionPath(resolutionPath);
77
+ super(`Circular dependency detected: ${pathText}`, options);
78
+ this.resolutionPath = resolutionPath;
79
+ this.cycle = [...resolutionPath];
80
+ }
81
+ };
82
+ /**
83
+ * Raised when a class binding requires `@injectable()` / `Symbol.metadata` constructor metadata but none is present.
84
+ */
85
+ var MissingMetadataError = class extends DiError {
86
+ code = "MISSING_METADATA";
87
+ className;
88
+ resolutionPath;
89
+ constructor(className, resolutionPath, options) {
90
+ const pathText = formatResolutionPath(resolutionPath);
91
+ super(`Missing injectable constructor metadata for class "${className}" (resolution path: ${pathText})`, options);
92
+ this.className = className;
93
+ this.resolutionPath = resolutionPath;
94
+ }
95
+ };
96
+ /** Raised when `load()` is used with an async module. */
97
+ var AsyncModuleLoadError = class extends DiError {
98
+ code = "ASYNC_MODULE_LOAD";
99
+ moduleName;
100
+ constructor(moduleName, options) {
101
+ super(`Cannot load async module "${moduleName}" synchronously; use loadAsync() or Container.fromModulesAsync().`, options);
102
+ this.moduleName = moduleName;
103
+ }
104
+ };
105
+ /**
106
+ * Raised when `resolve()` is called on a binding chain that contains an async factory or
107
+ * an async `onActivation` handler. Use `resolveAsync()` / `resolveAllAsync()` instead.
108
+ */
109
+ var AsyncResolutionError = class extends DiError {
110
+ code = "ASYNC_RESOLUTION";
111
+ tokenName;
112
+ resolutionPath;
113
+ reason;
114
+ constructor(tokenName, resolutionPath, reason, options) {
115
+ const pathText = formatResolutionPath(resolutionPath);
116
+ super(`Cannot resolve "${tokenName}" synchronously: ${reason} (resolution path: ${pathText})`, options);
117
+ this.tokenName = tokenName;
118
+ this.resolutionPath = resolutionPath;
119
+ this.reason = reason;
120
+ }
121
+ };
122
+ /**
123
+ * Raised when a long-lived binding would capture a shorter-lived (scoped or transient) dependency
124
+ * (captive dependency). Constant value dependencies are excluded.
125
+ */
126
+ var ScopeViolationError = class extends DiError {
127
+ code = "SCOPE_VIOLATION";
128
+ consumerBindingId;
129
+ consumerKind;
130
+ consumerScope;
131
+ dependencyBindingId;
132
+ dependencyKind;
133
+ dependencyScope;
134
+ resolutionPath;
135
+ constructor(details, options) {
136
+ const pathText = formatResolutionPath(details.resolutionPath);
137
+ const consumerLabel = details.consumerLabel ?? String(details.consumerBindingId);
138
+ const dependencyLabel = details.dependencyLabel ?? String(details.dependencyBindingId);
139
+ const consumerScopeLabel = details.consumerScope.charAt(0).toUpperCase() + details.consumerScope.slice(1);
140
+ const dependencyScopeLabel = details.dependencyScope.charAt(0).toUpperCase() + details.dependencyScope.slice(1);
141
+ super(`Scope Violation: ${consumerScopeLabel} "${consumerLabel}" cannot depend on ${dependencyScopeLabel} "${dependencyLabel}" (resolution path: ${pathText})`, options);
142
+ this.consumerBindingId = details.consumerBindingId;
143
+ this.consumerKind = details.consumerKind;
144
+ this.consumerScope = details.consumerScope;
145
+ this.dependencyBindingId = details.dependencyBindingId;
146
+ this.dependencyKind = details.dependencyKind;
147
+ this.dependencyScope = details.dependencyScope;
148
+ this.resolutionPath = details.resolutionPath;
149
+ }
150
+ };
151
+ //#endregion
152
+ export { AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, InternalError, MissingMetadataError, NoMatchingBindingError, ScopeViolationError, TokenNotBoundError };
@@ -0,0 +1,10 @@
1
+ import { Token, TokenValue, token } from "./token.mjs";
2
+ import { ActivationHandler, BindingBuilder, BindingIdentifier, BindingScope, ConstraintContext, Constructor, DeactivationHandler, ResolveOptions } from "./binding.mjs";
3
+ import { ContainerGraphJson, ContainerSnapshot } from "./inspector.mjs";
4
+ import { AsyncModule, AsyncModuleBuilder, Module, ModuleBuilder } from "./module.mjs";
5
+ import { Container } from "./container.mjs";
6
+ import { InjectOptions, inject, isInjectionDescriptor, optional } from "./decorators/inject.mjs";
7
+ import { InjectableDependency, getAutoRegistered, injectable } from "./decorators/injectable.mjs";
8
+ import { postConstruct, preDestroy } from "./decorators/lifecycle-decorators.mjs";
9
+ import { AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, InternalError, MissingMetadataError, NoMatchingBindingError, ScopeViolationDetails, ScopeViolationError, TokenNotBoundError } from "./errors.mjs";
10
+ export { type ActivationHandler, AsyncModule, type AsyncModuleBuilder, AsyncModuleLoadError, AsyncResolutionError, type BindingBuilder, type BindingIdentifier, type BindingScope, CircularDependencyError, type ConstraintContext, type Constructor, Container, type ContainerGraphJson, type ContainerSnapshot, type DeactivationHandler, DiError, type InjectOptions, type InjectableDependency, InternalError, MissingMetadataError, Module, type ModuleBuilder, NoMatchingBindingError, type ResolveOptions, type ScopeViolationDetails, ScopeViolationError, type Token, TokenNotBoundError, type TokenValue, getAutoRegistered, inject, injectable, isInjectionDescriptor, optional, postConstruct, preDestroy, token };
package/dist/index.mjs ADDED
@@ -0,0 +1,8 @@
1
+ import { AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, DiError, InternalError, MissingMetadataError, NoMatchingBindingError, ScopeViolationError, TokenNotBoundError } from "./errors.mjs";
2
+ import { inject, isInjectionDescriptor, optional } from "./decorators/inject.mjs";
3
+ import { getAutoRegistered, injectable } from "./decorators/injectable.mjs";
4
+ import { AsyncModule, Module } from "./module.mjs";
5
+ import { Container } from "./container.mjs";
6
+ import { token } from "./token.mjs";
7
+ import { postConstruct, preDestroy } from "./decorators/lifecycle-decorators.mjs";
8
+ export { AsyncModule, AsyncModuleLoadError, AsyncResolutionError, CircularDependencyError, Container, DiError, InternalError, MissingMetadataError, Module, NoMatchingBindingError, ScopeViolationError, TokenNotBoundError, getAutoRegistered, inject, injectable, isInjectionDescriptor, optional, postConstruct, preDestroy, token };
@@ -0,0 +1,76 @@
1
+ import { RegistryKey } from "./registry.mjs";
2
+ import { Binding, BindingIdentifier, BindingScope } from "./binding.mjs";
3
+ import { MetadataReader } from "./metadata/metadata-types.mjs";
4
+ import { collectStaticDependencyEdges } from "./dependency-graph.mjs";
5
+
6
+ //#region src/inspector.d.ts
7
+ /** Whether a singleton/scoped binding's instance is currently held in the scope cache. */
8
+ type BindingActivationStatus = "cached" | "not-cached" | "transient";
9
+ /** Per-binding row inside a {@link ContainerSnapshot}. */
10
+ type ContainerBindingSnapshot = {
11
+ readonly registryKeyLabel: string;
12
+ readonly bindingId: BindingIdentifier;
13
+ readonly kind: Binding<unknown>["kind"];
14
+ readonly scope: BindingScope;
15
+ readonly activationStatus: BindingActivationStatus; /** True when {@link BindingBuilder.when} was used (runtime predicate; static graph may still show edges). */
16
+ readonly hasConditionalConstraint: boolean;
17
+ readonly moduleId?: string;
18
+ };
19
+ /** Full debug snapshot returned by {@link Container.inspect}. */
20
+ type ContainerSnapshot = {
21
+ readonly bindings: readonly ContainerBindingSnapshot[];
22
+ };
23
+ /** Structured dependency graph returned by {@link Container.generateDependencyGraph} with `format: "json"`. */
24
+ type ContainerGraphJson = {
25
+ nodes: ContainerBindingSnapshot[];
26
+ edges: ReturnType<typeof collectStaticDependencyEdges>[number][];
27
+ };
28
+ /** Read-only view of the container internals exposed to {@link ContainerInspector}. */
29
+ type ContainerInspectorContext = {
30
+ collectAllRegistryKeys(): readonly RegistryKey[];
31
+ lookupBindings(key: RegistryKey): readonly Binding<unknown>[] | undefined;
32
+ isBindingCached(binding: Binding<unknown>): boolean;
33
+ metadataReader: MetadataReader | undefined;
34
+ };
35
+ /** Options for {@link Container.generateDependencyGraph}. */
36
+ type DotGraphOptions = {
37
+ /**
38
+ * When true, omit registry keys whose label starts with `CODEFAST_DI_` (framework-style tokens)
39
+ * and any edges that would only connect hidden nodes.
40
+ */
41
+ readonly hideInternals?: boolean;
42
+ };
43
+ /**
44
+ * Read-only introspection and Graphviz DOT export for a container graph.
45
+ */
46
+ /**
47
+ * Reads the registry and scope-cache state to produce debug snapshots and dependency graphs.
48
+ * Instantiated internally by the container; advanced consumers can construct it directly via
49
+ * the `@codefast/di/inspector` subpath export.
50
+ */
51
+ declare class ContainerInspector {
52
+ private readonly ctx;
53
+ constructor(ctx: ContainerInspectorContext);
54
+ /** Collects all registered bindings into a flat, serialisable snapshot. */
55
+ getSnapshot(): ContainerSnapshot;
56
+ /**
57
+ * Produces a Graphviz `digraph` string with HTML-label nodes and styled edges.
58
+ * Cycles are represented as ordinary edges (Graphviz renders them correctly).
59
+ * Pass `hideInternals: true` to suppress `CODEFAST_DI_`-prefixed tokens.
60
+ */
61
+ generateDotGraph(options?: DotGraphOptions): string;
62
+ generateDependencyGraph(options?: DotGraphOptions & {
63
+ format?: "dot";
64
+ }): string;
65
+ generateDependencyGraph(options: DotGraphOptions & {
66
+ format: "json";
67
+ }): ContainerGraphJson;
68
+ generateDependencyGraphJsonTyped(options?: DotGraphOptions): ContainerGraphJson;
69
+ /**
70
+ * Produces a JSON graph representation with `nodes` and `edges`.
71
+ * @internal Use `generateDependencyGraph({ format: "json" })` for typed output.
72
+ */
73
+ generateDependencyGraphJson(options?: DotGraphOptions): string;
74
+ }
75
+ //#endregion
76
+ export { BindingActivationStatus, ContainerBindingSnapshot, ContainerGraphJson, ContainerInspector, ContainerInspectorContext, ContainerSnapshot, DotGraphOptions };