@jskit-ai/kernel 0.1.159 → 0.1.161
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.
- package/_testable/index.js +1 -3
- package/client/componentRegistry.js +44 -0
- package/client/componentRegistry.test.js +16 -0
- package/client/moduleBootstrap.js +54 -97
- package/client/moduleBootstrap.test.js +47 -32
- package/client/vite/clientBootstrapPlugin.test.js +2 -2
- package/internal/node/installedPackages.js +2 -7
- package/internal/node/installedPackages.test.js +26 -5
- package/package.json +3 -5
- package/server/actions/actionCatalogue.js +162 -0
- package/server/actions/actionEvents.js +66 -0
- package/server/actions/actionProvider.js +23 -0
- package/server/actions/index.js +3 -6
- package/server/features/defineFeature.js +131 -0
- package/server/features/defineFeature.test.js +238 -0
- package/server/features/index.js +1 -0
- package/server/http/HttpProvider.js +23 -0
- package/server/http/_testable/index.js +0 -1
- package/server/http/capabilityHttpRuntime.js +123 -0
- package/server/http/capabilityHttpRuntime.test.js +161 -0
- package/server/http/directRequestActionExecutor.js +78 -0
- package/server/http/index.js +2 -1
- package/server/http/lib/index.js +1 -13
- package/server/http/lib/routeRegistration.js +9 -25
- package/server/platform/index.js +2 -2
- package/server/platform/installedRuntime.js +122 -0
- package/server/platform/installedRuntime.test.js +103 -0
- package/server/platform/providerRuntime/capabilityProviderLoader.js +100 -0
- package/server/platform/providerRuntime/capabilityProviderLoader.test.js +80 -0
- package/server/platform/providerRuntime/packageCatalog.js +4 -1
- package/server/platform/surfaceRuntime.js +1 -15
- package/server/runtime/BootstrapProvider.js +69 -0
- package/server/runtime/EventProvider.js +74 -0
- package/server/runtime/EventProvider.test.js +32 -0
- package/server/runtime/entityChangeEvents.js +7 -7
- package/server/runtime/entityChangeEvents.test.js +2 -2
- package/server/runtime/fastifyBootstrap.js +0 -40
- package/server/runtime/index.js +2 -3
- package/server/surface/index.js +0 -1
- package/shared/actions/actionDefinitions.js +20 -0
- package/shared/actions/pipeline.js +22 -0
- package/shared/actions/policies.js +1 -1
- package/shared/actions/registry.js +3 -0
- package/shared/capabilities/defineProvider.js +99 -0
- package/shared/capabilities/index.js +2 -0
- package/shared/capabilities/runtime.js +243 -0
- package/shared/capabilities/runtime.test.js +170 -0
- package/test/barrelExposure.test.js +36 -13
- package/test/exportsContract.test.js +8 -3
- package/server/actions/ActionRuntimeServiceProvider.js +0 -304
- package/server/actions/ActionRuntimeServiceProvider.test.js +0 -558
- package/server/container/ContainerCoreServiceProvider.js +0 -27
- package/server/container/index.js +0 -10
- package/server/http/HttpFastifyServiceProvider.js +0 -25
- package/server/http/lib/httpRuntime.js +0 -83
- package/server/http/lib/kernel.js +0 -15
- package/server/http/lib/kernel.test.js +0 -1565
- package/server/http/lib/requestActionExecutor.js +0 -265
- package/server/http/lib/requestScope.js +0 -57
- package/server/kernel/KernelCoreServiceProvider.js +0 -27
- package/server/kernel/index.js +0 -10
- package/server/platform/PlatformServerRuntimeServiceProvider.js +0 -30
- package/server/platform/providerRuntime/providerLoader.js +0 -283
- package/server/platform/providerRuntime.js +0 -146
- package/server/platform/providerRuntime.test.js +0 -214
- package/server/platform/runtime.js +0 -40
- package/server/registries/actionSurfaceSourceRegistry.js +0 -148
- package/server/registries/bootstrapPayloadContributorRegistry.js +0 -51
- package/server/registries/domainEventListenerRegistry.js +0 -58
- package/server/registries/index.js +0 -32
- package/server/registries/primitives.js +0 -63
- package/server/registries/routeVisibilityResolverRegistry.js +0 -84
- package/server/registries/serviceRegistrationRegistry.js +0 -488
- package/server/runtime/ServerRuntimeCoreServiceProvider.js +0 -64
- package/server/runtime/ServerRuntimeCoreServiceProvider.test.js +0 -53
- package/server/runtime/apiRoutePolicyParity.test.js +0 -109
- package/server/runtime/apiRouteRegistration.js +0 -65
- package/server/runtime/bootBootstrapRoutes.js +0 -29
- package/server/runtime/bootBootstrapRoutes.test.js +0 -69
- package/server/runtime/bootstrapContributors.test.js +0 -166
- package/server/runtime/composition.js +0 -142
- package/server/runtime/domainEvents.test.js +0 -114
- package/server/runtime/domainRules.js +0 -50
- package/server/runtime/domainRules.test.js +0 -87
- package/server/runtime/runtimeAssembly.js +0 -113
- package/server/runtime/runtimeKernel.js +0 -55
- package/server/runtime/serviceRegistration.test.js +0 -251
- package/server/support/SupportCoreServiceProvider.js +0 -27
- package/server/surface/SurfaceRoutingServiceProvider.js +0 -27
- package/shared/actions/index.js +0 -2
- package/shared/runtime/application.js +0 -324
- package/shared/runtime/container.js +0 -261
- package/shared/runtime/containerErrors.js +0 -22
- package/shared/runtime/index.js +0 -18
- package/shared/runtime/kernelErrors.js +0 -25
- package/shared/runtime/kernelErrors.test.js +0 -120
- package/shared/runtime/serviceProvider.js +0 -13
- package/shared/support/containerToken.js +0 -8
- package/shared/support/generatedUiContract.js +0 -542
- package/shared/support/generatedUiContract.test.js +0 -218
- package/shared/support/tokens.js +0 -1
- package/shared/support/tokens.test.js +0 -17
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import * as apiPaths from "../../shared/surface/apiPaths.js";
|
|
2
|
-
import * as paths from "../../shared/surface/paths.js";
|
|
3
|
-
import * as registry from "../../shared/surface/registry.js";
|
|
4
|
-
import { escapeRegExp } from "../../shared/surface/escapeRegExp.js";
|
|
5
|
-
|
|
6
|
-
const SURFACE_ROUTING_API = Object.freeze({
|
|
7
|
-
apiPaths: Object.freeze({ ...apiPaths }),
|
|
8
|
-
paths: Object.freeze({ ...paths }),
|
|
9
|
-
registry: Object.freeze({ ...registry }),
|
|
10
|
-
escapeRegExp
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
class SurfaceRoutingServiceProvider {
|
|
14
|
-
static id = "runtime.surface-routing";
|
|
15
|
-
|
|
16
|
-
register(app) {
|
|
17
|
-
if (!app || typeof app.singleton !== "function") {
|
|
18
|
-
throw new Error("SurfaceRoutingServiceProvider requires application singleton().");
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
app.singleton("runtime.surface-routing", () => SURFACE_ROUTING_API);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
boot() {}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { SurfaceRoutingServiceProvider };
|
package/shared/actions/index.js
DELETED
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
import { createContainer } from "./container.js";
|
|
2
|
-
import {
|
|
3
|
-
DuplicateProviderError,
|
|
4
|
-
ProviderStartOrderError,
|
|
5
|
-
ProviderLifecycleError,
|
|
6
|
-
ProviderNormalizationError
|
|
7
|
-
} from "./kernelErrors.js";
|
|
8
|
-
import { ServiceProvider } from "./serviceProvider.js";
|
|
9
|
-
import { normalizeText } from "../support/normalize.js";
|
|
10
|
-
|
|
11
|
-
function normalizeStringArray(value) {
|
|
12
|
-
if (!Array.isArray(value)) {
|
|
13
|
-
return [];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return [...new Set(value.map((entry) => String(entry || "").trim()).filter(Boolean))].sort((left, right) =>
|
|
17
|
-
left.localeCompare(right)
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function nowMilliseconds() {
|
|
22
|
-
return Date.now();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function createProviderLifecycleError(providerId, phase, cause) {
|
|
26
|
-
const message = `Provider \"${providerId}\" failed during ${phase}().`;
|
|
27
|
-
const causeMessage = String(cause?.message || cause || "").trim();
|
|
28
|
-
return new ProviderLifecycleError(
|
|
29
|
-
causeMessage ? `${message} ${causeMessage}` : message,
|
|
30
|
-
{
|
|
31
|
-
providerId,
|
|
32
|
-
phase,
|
|
33
|
-
cause
|
|
34
|
-
}
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
class Application {
|
|
39
|
-
constructor({ profile = "", strict = true, container = null } = {}) {
|
|
40
|
-
this.profile = normalizeText(profile);
|
|
41
|
-
this.strict = strict !== false;
|
|
42
|
-
this.container = container || createContainer({ scopeId: "root" });
|
|
43
|
-
|
|
44
|
-
this.providerEntries = [];
|
|
45
|
-
this.registeredProviders = [];
|
|
46
|
-
this.bootedProviders = [];
|
|
47
|
-
|
|
48
|
-
this.diagnostics = {
|
|
49
|
-
profile: this.profile,
|
|
50
|
-
providerOrder: [],
|
|
51
|
-
registeredOrder: [],
|
|
52
|
-
bootedOrder: [],
|
|
53
|
-
timings: {
|
|
54
|
-
register: {},
|
|
55
|
-
boot: {},
|
|
56
|
-
shutdown: {}
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
bind(token, factory) {
|
|
62
|
-
this.container.bind(token, factory);
|
|
63
|
-
return this;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
singleton(token, factory) {
|
|
67
|
-
this.container.singleton(token, factory);
|
|
68
|
-
return this;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
scoped(token, factory) {
|
|
72
|
-
this.container.scoped(token, factory);
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
instance(token, value) {
|
|
77
|
-
this.container.instance(token, value);
|
|
78
|
-
return this;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
make(token) {
|
|
82
|
-
return this.container.make(token);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
has(token) {
|
|
86
|
-
return this.container.has(token);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
createScope(scopeId) {
|
|
90
|
-
return this.container.createScope(scopeId);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
tag(token, tagName) {
|
|
94
|
-
this.container.tag(token, tagName);
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
resolveTag(tagName) {
|
|
99
|
-
return this.container.resolveTag(tagName);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
normalizeProviderEntries(providers = []) {
|
|
103
|
-
if (!Array.isArray(providers)) {
|
|
104
|
-
throw new ProviderNormalizationError("Providers must be an array.");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const entries = [];
|
|
108
|
-
const seenIds = new Set();
|
|
109
|
-
|
|
110
|
-
for (const rawProvider of providers) {
|
|
111
|
-
const entry = this.normalizeProviderEntry(rawProvider);
|
|
112
|
-
if (seenIds.has(entry.id)) {
|
|
113
|
-
throw new DuplicateProviderError(`Provider \"${entry.id}\" is duplicated.`);
|
|
114
|
-
}
|
|
115
|
-
seenIds.add(entry.id);
|
|
116
|
-
entries.push(entry);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return entries.sort((left, right) => left.id.localeCompare(right.id));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
normalizeProviderEntry(rawProvider) {
|
|
123
|
-
if (!rawProvider) {
|
|
124
|
-
throw new ProviderNormalizationError("Provider entry is required.");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (typeof rawProvider === "function") {
|
|
128
|
-
const providerInstance = new rawProvider(this);
|
|
129
|
-
const providerId = normalizeText(rawProvider.id || providerInstance.id || rawProvider.name);
|
|
130
|
-
if (!providerId) {
|
|
131
|
-
throw new ProviderNormalizationError("Provider class must define a stable id.");
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
id: providerId,
|
|
136
|
-
startsAfter: normalizeStringArray(rawProvider.startsAfter ?? providerInstance.startsAfter),
|
|
137
|
-
provider: providerInstance
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (typeof rawProvider === "object") {
|
|
142
|
-
const provider = rawProvider;
|
|
143
|
-
const providerId = normalizeText(provider.id || provider.constructor?.id || provider.constructor?.name);
|
|
144
|
-
if (!providerId) {
|
|
145
|
-
throw new ProviderNormalizationError("Provider object must define id.");
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
id: providerId,
|
|
150
|
-
startsAfter: normalizeStringArray(provider.startsAfter ?? provider.constructor?.startsAfter),
|
|
151
|
-
provider
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
throw new ProviderNormalizationError("Provider entry must be a class or object instance.");
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
sortProviderStartOrder(entries = []) {
|
|
159
|
-
const byId = new Map(entries.map((entry) => [entry.id, entry]));
|
|
160
|
-
const visited = new Set();
|
|
161
|
-
const visiting = new Set();
|
|
162
|
-
const ordered = [];
|
|
163
|
-
|
|
164
|
-
const visit = (providerId, lineage = []) => {
|
|
165
|
-
if (visited.has(providerId)) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (visiting.has(providerId)) {
|
|
169
|
-
throw new ProviderStartOrderError(`Provider start-order cycle detected: ${[...lineage, providerId].join(" -> ")}`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const entry = byId.get(providerId);
|
|
173
|
-
if (!entry) {
|
|
174
|
-
throw new ProviderStartOrderError(`Provider \"${lineage[lineage.length - 1] || "<unknown>"}\" starts after missing provider \"${providerId}\".`);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
visiting.add(providerId);
|
|
178
|
-
for (const earlierProviderId of entry.startsAfter) {
|
|
179
|
-
visit(earlierProviderId, [...lineage, providerId]);
|
|
180
|
-
}
|
|
181
|
-
visiting.delete(providerId);
|
|
182
|
-
visited.add(providerId);
|
|
183
|
-
ordered.push(entry);
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
for (const entry of [...entries].sort((left, right) => left.id.localeCompare(right.id))) {
|
|
187
|
-
visit(entry.id, []);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return ordered;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
configureProviders(providers = []) {
|
|
194
|
-
const normalized = this.normalizeProviderEntries(providers);
|
|
195
|
-
const ordered = this.sortProviderStartOrder(normalized);
|
|
196
|
-
|
|
197
|
-
this.providerEntries = ordered;
|
|
198
|
-
this.diagnostics.providerOrder = ordered.map((entry) => entry.id);
|
|
199
|
-
return this;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async registerProviders() {
|
|
203
|
-
this.registeredProviders = [];
|
|
204
|
-
|
|
205
|
-
for (const entry of this.providerEntries) {
|
|
206
|
-
const startedAt = nowMilliseconds();
|
|
207
|
-
try {
|
|
208
|
-
if (typeof entry.provider.register === "function") {
|
|
209
|
-
await entry.provider.register(this);
|
|
210
|
-
}
|
|
211
|
-
} catch (error) {
|
|
212
|
-
throw createProviderLifecycleError(entry.id, "register", error);
|
|
213
|
-
} finally {
|
|
214
|
-
this.diagnostics.timings.register[entry.id] = nowMilliseconds() - startedAt;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
this.registeredProviders.push(entry);
|
|
218
|
-
this.diagnostics.registeredOrder.push(entry.id);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return this;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async bootProviders() {
|
|
225
|
-
this.bootedProviders = [];
|
|
226
|
-
|
|
227
|
-
for (const entry of this.providerEntries) {
|
|
228
|
-
const startedAt = nowMilliseconds();
|
|
229
|
-
try {
|
|
230
|
-
if (typeof entry.provider.boot === "function") {
|
|
231
|
-
await entry.provider.boot(this);
|
|
232
|
-
}
|
|
233
|
-
} catch (error) {
|
|
234
|
-
throw createProviderLifecycleError(entry.id, "boot", error);
|
|
235
|
-
} finally {
|
|
236
|
-
this.diagnostics.timings.boot[entry.id] = nowMilliseconds() - startedAt;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
this.bootedProviders.push(entry);
|
|
240
|
-
this.diagnostics.bootedOrder.push(entry.id);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return this;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async start({ providers = [] } = {}) {
|
|
247
|
-
this.configureProviders(providers);
|
|
248
|
-
await this.registerProviders();
|
|
249
|
-
await this.bootProviders();
|
|
250
|
-
return this;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
async shutdown() {
|
|
254
|
-
const shutdownOrder = [...this.bootedProviders].reverse();
|
|
255
|
-
|
|
256
|
-
for (const entry of shutdownOrder) {
|
|
257
|
-
const startedAt = nowMilliseconds();
|
|
258
|
-
try {
|
|
259
|
-
if (typeof entry.provider.shutdown === "function") {
|
|
260
|
-
await entry.provider.shutdown(this);
|
|
261
|
-
}
|
|
262
|
-
} catch (error) {
|
|
263
|
-
throw createProviderLifecycleError(entry.id, "shutdown", error);
|
|
264
|
-
} finally {
|
|
265
|
-
this.diagnostics.timings.shutdown[entry.id] = nowMilliseconds() - startedAt;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return shutdownOrder.map((entry) => entry.id);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
getDiagnostics() {
|
|
273
|
-
return Object.freeze({
|
|
274
|
-
profile: this.diagnostics.profile,
|
|
275
|
-
providerOrder: Object.freeze([...this.diagnostics.providerOrder]),
|
|
276
|
-
registeredOrder: Object.freeze([...this.diagnostics.registeredOrder]),
|
|
277
|
-
bootedOrder: Object.freeze([...this.diagnostics.bootedOrder]),
|
|
278
|
-
timings: Object.freeze({
|
|
279
|
-
register: Object.freeze({ ...this.diagnostics.timings.register }),
|
|
280
|
-
boot: Object.freeze({ ...this.diagnostics.timings.boot }),
|
|
281
|
-
shutdown: Object.freeze({ ...this.diagnostics.timings.shutdown })
|
|
282
|
-
})
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function createApplication(options = {}) {
|
|
288
|
-
return new Application(options);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function createProviderClass({ id, startsAfter = [], register = null, boot = null, shutdown = null } = {}) {
|
|
292
|
-
const providerId = normalizeText(id);
|
|
293
|
-
if (!providerId) {
|
|
294
|
-
throw new ProviderNormalizationError("createProviderClass requires id.");
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
class DynamicProvider extends ServiceProvider {
|
|
298
|
-
static id = providerId;
|
|
299
|
-
|
|
300
|
-
static startsAfter = normalizeStringArray(startsAfter);
|
|
301
|
-
|
|
302
|
-
async register(app) {
|
|
303
|
-
if (typeof register === "function") {
|
|
304
|
-
await register(app);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
async boot(app) {
|
|
309
|
-
if (typeof boot === "function") {
|
|
310
|
-
await boot(app);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
async shutdown(app) {
|
|
315
|
-
if (typeof shutdown === "function") {
|
|
316
|
-
await shutdown(app);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return DynamicProvider;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export { Application, createApplication, createProviderClass };
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CircularDependencyError,
|
|
3
|
-
DuplicateBindingError,
|
|
4
|
-
InvalidFactoryError,
|
|
5
|
-
InvalidTokenError,
|
|
6
|
-
UnresolvedTokenError
|
|
7
|
-
} from "./containerErrors.js";
|
|
8
|
-
|
|
9
|
-
const LIFETIME_TRANSIENT = "transient";
|
|
10
|
-
const LIFETIME_SINGLETON = "singleton";
|
|
11
|
-
const LIFETIME_SCOPED = "scoped";
|
|
12
|
-
|
|
13
|
-
function normalizeToken(token) {
|
|
14
|
-
const kind = typeof token;
|
|
15
|
-
if (kind === "string") {
|
|
16
|
-
const normalized = token.trim();
|
|
17
|
-
if (!normalized) {
|
|
18
|
-
throw new InvalidTokenError("Container token string cannot be empty.");
|
|
19
|
-
}
|
|
20
|
-
return normalized;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (kind === "symbol" || kind === "function") {
|
|
24
|
-
return token;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
throw new InvalidTokenError("Container token must be a non-empty string, symbol, or function.", {
|
|
28
|
-
receivedType: kind
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function tokenLabel(token) {
|
|
33
|
-
if (typeof token === "string") {
|
|
34
|
-
return token;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (typeof token === "symbol") {
|
|
38
|
-
return token.description ? `Symbol(${token.description})` : String(token);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (typeof token === "function") {
|
|
42
|
-
return token.name ? `Function(${token.name})` : "Function(<anonymous>)";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return String(token);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function ensureFactory(factory, token) {
|
|
49
|
-
if (typeof factory !== "function") {
|
|
50
|
-
throw new InvalidFactoryError(`Factory for token \"${tokenLabel(token)}\" must be a function.`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function normalizeTagName(tagName) {
|
|
55
|
-
const normalized = String(tagName || "").trim();
|
|
56
|
-
if (!normalized) {
|
|
57
|
-
throw new TypeError("Tag name is required.");
|
|
58
|
-
}
|
|
59
|
-
return normalized;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function normalizeScopeId(scopeId) {
|
|
63
|
-
const normalized = String(scopeId || "").trim();
|
|
64
|
-
return normalized || "scope";
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
class Container {
|
|
68
|
-
constructor({ parent = null, scopeId = "root" } = {}) {
|
|
69
|
-
this.parent = parent instanceof Container ? parent : null;
|
|
70
|
-
this.scopeId = normalizeScopeId(scopeId);
|
|
71
|
-
this.bindings = new Map();
|
|
72
|
-
this.instances = new Map();
|
|
73
|
-
this.scopedInstances = new Map();
|
|
74
|
-
|
|
75
|
-
if (!this.parent) {
|
|
76
|
-
this.tags = new Map();
|
|
77
|
-
this.resolutionStack = [];
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
root() {
|
|
82
|
-
let node = this;
|
|
83
|
-
while (node.parent) {
|
|
84
|
-
node = node.parent;
|
|
85
|
-
}
|
|
86
|
-
return node;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
has(token) {
|
|
90
|
-
const normalizedToken = normalizeToken(token);
|
|
91
|
-
return this.findBindingRecord(normalizedToken) !== null || this.findInstanceRecord(normalizedToken) !== null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
bind(token, factory) {
|
|
95
|
-
return this.setBinding(token, factory, LIFETIME_TRANSIENT);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
singleton(token, factory) {
|
|
99
|
-
return this.setBinding(token, factory, LIFETIME_SINGLETON);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
scoped(token, factory) {
|
|
103
|
-
return this.setBinding(token, factory, LIFETIME_SCOPED);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
instance(token, value) {
|
|
107
|
-
const normalizedToken = normalizeToken(token);
|
|
108
|
-
if (this.bindings.has(normalizedToken) || this.instances.has(normalizedToken)) {
|
|
109
|
-
throw new DuplicateBindingError(`Token \"${tokenLabel(normalizedToken)}\" is already bound.`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
this.instances.set(normalizedToken, value);
|
|
113
|
-
return this;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
tag(token, tagName) {
|
|
117
|
-
const normalizedToken = normalizeToken(token);
|
|
118
|
-
const normalizedTagName = normalizeTagName(tagName);
|
|
119
|
-
|
|
120
|
-
if (!this.has(normalizedToken)) {
|
|
121
|
-
throw new UnresolvedTokenError(`Cannot tag unresolved token \"${tokenLabel(normalizedToken)}\".`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const rootContainer = this.root();
|
|
125
|
-
if (!rootContainer.tags.has(normalizedTagName)) {
|
|
126
|
-
rootContainer.tags.set(normalizedTagName, new Set());
|
|
127
|
-
}
|
|
128
|
-
rootContainer.tags.get(normalizedTagName).add(normalizedToken);
|
|
129
|
-
return this;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
resolveTag(tagName) {
|
|
133
|
-
const normalizedTagName = normalizeTagName(tagName);
|
|
134
|
-
const rootContainer = this.root();
|
|
135
|
-
const tokens = rootContainer.tags.get(normalizedTagName);
|
|
136
|
-
if (!tokens || tokens.size < 1) {
|
|
137
|
-
return [];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return [...tokens]
|
|
141
|
-
.sort((left, right) => tokenLabel(left).localeCompare(tokenLabel(right)))
|
|
142
|
-
.map((token) => this.make(token));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
createScope(scopeId = "scope") {
|
|
146
|
-
return new Container({
|
|
147
|
-
parent: this,
|
|
148
|
-
scopeId: normalizeScopeId(scopeId)
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
make(token) {
|
|
153
|
-
const normalizedToken = normalizeToken(token);
|
|
154
|
-
const instanceRecord = this.findInstanceRecord(normalizedToken);
|
|
155
|
-
if (instanceRecord) {
|
|
156
|
-
return instanceRecord.value;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const bindingRecord = this.findBindingRecord(normalizedToken);
|
|
160
|
-
if (!bindingRecord) {
|
|
161
|
-
throw new UnresolvedTokenError(`Token \"${tokenLabel(normalizedToken)}\" is not registered.`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const rootContainer = this.root();
|
|
165
|
-
const stack = rootContainer.resolutionStack;
|
|
166
|
-
const stackIndex = stack.indexOf(normalizedToken);
|
|
167
|
-
if (stackIndex >= 0) {
|
|
168
|
-
const cycle = stack
|
|
169
|
-
.slice(stackIndex)
|
|
170
|
-
.concat([normalizedToken])
|
|
171
|
-
.map((entry) => tokenLabel(entry));
|
|
172
|
-
throw new CircularDependencyError(`Circular dependency detected: ${cycle.join(" -> ")}.`, {
|
|
173
|
-
cycle
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
stack.push(normalizedToken);
|
|
178
|
-
try {
|
|
179
|
-
return this.resolveFromBindingRecord(bindingRecord);
|
|
180
|
-
} finally {
|
|
181
|
-
stack.pop();
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
setBinding(token, factory, lifetime) {
|
|
186
|
-
const normalizedToken = normalizeToken(token);
|
|
187
|
-
ensureFactory(factory, normalizedToken);
|
|
188
|
-
|
|
189
|
-
if (this.bindings.has(normalizedToken) || this.instances.has(normalizedToken)) {
|
|
190
|
-
throw new DuplicateBindingError(`Token \"${tokenLabel(normalizedToken)}\" is already bound.`);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
this.bindings.set(normalizedToken, {
|
|
194
|
-
token: normalizedToken,
|
|
195
|
-
factory,
|
|
196
|
-
lifetime
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
return this;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
findBindingRecord(token) {
|
|
203
|
-
let node = this;
|
|
204
|
-
while (node) {
|
|
205
|
-
if (node.bindings.has(token)) {
|
|
206
|
-
return {
|
|
207
|
-
container: node,
|
|
208
|
-
binding: node.bindings.get(token)
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
node = node.parent;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return null;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
findInstanceRecord(token) {
|
|
218
|
-
let node = this;
|
|
219
|
-
while (node) {
|
|
220
|
-
if (node.instances.has(token)) {
|
|
221
|
-
return {
|
|
222
|
-
container: node,
|
|
223
|
-
value: node.instances.get(token)
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
node = node.parent;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return null;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
resolveFromBindingRecord(record) {
|
|
233
|
-
const { container, binding } = record;
|
|
234
|
-
|
|
235
|
-
if (binding.lifetime === LIFETIME_SINGLETON) {
|
|
236
|
-
if (container.instances.has(binding.token)) {
|
|
237
|
-
return container.instances.get(binding.token);
|
|
238
|
-
}
|
|
239
|
-
const created = binding.factory(this);
|
|
240
|
-
container.instances.set(binding.token, created);
|
|
241
|
-
return created;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (binding.lifetime === LIFETIME_SCOPED) {
|
|
245
|
-
if (this.scopedInstances.has(binding.token)) {
|
|
246
|
-
return this.scopedInstances.get(binding.token);
|
|
247
|
-
}
|
|
248
|
-
const created = binding.factory(this);
|
|
249
|
-
this.scopedInstances.set(binding.token, created);
|
|
250
|
-
return created;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return binding.factory(this);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function createContainer(options = {}) {
|
|
258
|
-
return new Container(options);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export { Container, createContainer, tokenLabel };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
class ContainerError extends Error {
|
|
2
|
-
constructor(message, details = {}) {
|
|
3
|
-
super(String(message || "Container error."));
|
|
4
|
-
this.name = this.constructor.name;
|
|
5
|
-
this.details = details && typeof details === "object" ? { ...details } : {};
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
class InvalidTokenError extends ContainerError {}
|
|
10
|
-
class InvalidFactoryError extends ContainerError {}
|
|
11
|
-
class DuplicateBindingError extends ContainerError {}
|
|
12
|
-
class UnresolvedTokenError extends ContainerError {}
|
|
13
|
-
class CircularDependencyError extends ContainerError {}
|
|
14
|
-
|
|
15
|
-
export {
|
|
16
|
-
ContainerError,
|
|
17
|
-
InvalidTokenError,
|
|
18
|
-
InvalidFactoryError,
|
|
19
|
-
DuplicateBindingError,
|
|
20
|
-
UnresolvedTokenError,
|
|
21
|
-
CircularDependencyError
|
|
22
|
-
};
|
package/shared/runtime/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export { Container, createContainer, tokenLabel } from "./container.js";
|
|
2
|
-
export {
|
|
3
|
-
ContainerError,
|
|
4
|
-
InvalidTokenError,
|
|
5
|
-
InvalidFactoryError,
|
|
6
|
-
DuplicateBindingError,
|
|
7
|
-
UnresolvedTokenError,
|
|
8
|
-
CircularDependencyError
|
|
9
|
-
} from "./containerErrors.js";
|
|
10
|
-
export { Application, createApplication, createProviderClass } from "./application.js";
|
|
11
|
-
export { ServiceProvider } from "./serviceProvider.js";
|
|
12
|
-
export {
|
|
13
|
-
KernelError,
|
|
14
|
-
ProviderNormalizationError,
|
|
15
|
-
DuplicateProviderError,
|
|
16
|
-
ProviderStartOrderError,
|
|
17
|
-
ProviderLifecycleError
|
|
18
|
-
} from "./kernelErrors.js";
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
class KernelError extends Error {
|
|
2
|
-
constructor(message, details = {}) {
|
|
3
|
-
const normalizedDetails = details && typeof details === "object" ? { ...details } : {};
|
|
4
|
-
const hasCause = Object.prototype.hasOwnProperty.call(normalizedDetails, "cause");
|
|
5
|
-
super(
|
|
6
|
-
String(message || "Kernel error."),
|
|
7
|
-
hasCause ? { cause: normalizedDetails.cause } : undefined
|
|
8
|
-
);
|
|
9
|
-
this.name = this.constructor.name;
|
|
10
|
-
this.details = normalizedDetails;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
class ProviderNormalizationError extends KernelError {}
|
|
15
|
-
class DuplicateProviderError extends KernelError {}
|
|
16
|
-
class ProviderStartOrderError extends KernelError {}
|
|
17
|
-
class ProviderLifecycleError extends KernelError {}
|
|
18
|
-
|
|
19
|
-
export {
|
|
20
|
-
KernelError,
|
|
21
|
-
ProviderNormalizationError,
|
|
22
|
-
DuplicateProviderError,
|
|
23
|
-
ProviderStartOrderError,
|
|
24
|
-
ProviderLifecycleError
|
|
25
|
-
};
|