@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.
Files changed (102) hide show
  1. package/_testable/index.js +1 -3
  2. package/client/componentRegistry.js +44 -0
  3. package/client/componentRegistry.test.js +16 -0
  4. package/client/moduleBootstrap.js +54 -97
  5. package/client/moduleBootstrap.test.js +47 -32
  6. package/client/vite/clientBootstrapPlugin.test.js +2 -2
  7. package/internal/node/installedPackages.js +2 -7
  8. package/internal/node/installedPackages.test.js +26 -5
  9. package/package.json +3 -5
  10. package/server/actions/actionCatalogue.js +162 -0
  11. package/server/actions/actionEvents.js +66 -0
  12. package/server/actions/actionProvider.js +23 -0
  13. package/server/actions/index.js +3 -6
  14. package/server/features/defineFeature.js +131 -0
  15. package/server/features/defineFeature.test.js +238 -0
  16. package/server/features/index.js +1 -0
  17. package/server/http/HttpProvider.js +23 -0
  18. package/server/http/_testable/index.js +0 -1
  19. package/server/http/capabilityHttpRuntime.js +123 -0
  20. package/server/http/capabilityHttpRuntime.test.js +161 -0
  21. package/server/http/directRequestActionExecutor.js +78 -0
  22. package/server/http/index.js +2 -1
  23. package/server/http/lib/index.js +1 -13
  24. package/server/http/lib/routeRegistration.js +9 -25
  25. package/server/platform/index.js +2 -2
  26. package/server/platform/installedRuntime.js +122 -0
  27. package/server/platform/installedRuntime.test.js +103 -0
  28. package/server/platform/providerRuntime/capabilityProviderLoader.js +100 -0
  29. package/server/platform/providerRuntime/capabilityProviderLoader.test.js +80 -0
  30. package/server/platform/providerRuntime/packageCatalog.js +4 -1
  31. package/server/platform/surfaceRuntime.js +1 -15
  32. package/server/runtime/BootstrapProvider.js +69 -0
  33. package/server/runtime/EventProvider.js +74 -0
  34. package/server/runtime/EventProvider.test.js +32 -0
  35. package/server/runtime/entityChangeEvents.js +7 -7
  36. package/server/runtime/entityChangeEvents.test.js +2 -2
  37. package/server/runtime/fastifyBootstrap.js +0 -40
  38. package/server/runtime/index.js +2 -3
  39. package/server/surface/index.js +0 -1
  40. package/shared/actions/actionDefinitions.js +20 -0
  41. package/shared/actions/pipeline.js +22 -0
  42. package/shared/actions/policies.js +1 -1
  43. package/shared/actions/registry.js +3 -0
  44. package/shared/capabilities/defineProvider.js +99 -0
  45. package/shared/capabilities/index.js +2 -0
  46. package/shared/capabilities/runtime.js +243 -0
  47. package/shared/capabilities/runtime.test.js +170 -0
  48. package/test/barrelExposure.test.js +36 -13
  49. package/test/exportsContract.test.js +8 -3
  50. package/server/actions/ActionRuntimeServiceProvider.js +0 -304
  51. package/server/actions/ActionRuntimeServiceProvider.test.js +0 -558
  52. package/server/container/ContainerCoreServiceProvider.js +0 -27
  53. package/server/container/index.js +0 -10
  54. package/server/http/HttpFastifyServiceProvider.js +0 -25
  55. package/server/http/lib/httpRuntime.js +0 -83
  56. package/server/http/lib/kernel.js +0 -15
  57. package/server/http/lib/kernel.test.js +0 -1565
  58. package/server/http/lib/requestActionExecutor.js +0 -265
  59. package/server/http/lib/requestScope.js +0 -57
  60. package/server/kernel/KernelCoreServiceProvider.js +0 -27
  61. package/server/kernel/index.js +0 -10
  62. package/server/platform/PlatformServerRuntimeServiceProvider.js +0 -30
  63. package/server/platform/providerRuntime/providerLoader.js +0 -283
  64. package/server/platform/providerRuntime.js +0 -146
  65. package/server/platform/providerRuntime.test.js +0 -214
  66. package/server/platform/runtime.js +0 -40
  67. package/server/registries/actionSurfaceSourceRegistry.js +0 -148
  68. package/server/registries/bootstrapPayloadContributorRegistry.js +0 -51
  69. package/server/registries/domainEventListenerRegistry.js +0 -58
  70. package/server/registries/index.js +0 -32
  71. package/server/registries/primitives.js +0 -63
  72. package/server/registries/routeVisibilityResolverRegistry.js +0 -84
  73. package/server/registries/serviceRegistrationRegistry.js +0 -488
  74. package/server/runtime/ServerRuntimeCoreServiceProvider.js +0 -64
  75. package/server/runtime/ServerRuntimeCoreServiceProvider.test.js +0 -53
  76. package/server/runtime/apiRoutePolicyParity.test.js +0 -109
  77. package/server/runtime/apiRouteRegistration.js +0 -65
  78. package/server/runtime/bootBootstrapRoutes.js +0 -29
  79. package/server/runtime/bootBootstrapRoutes.test.js +0 -69
  80. package/server/runtime/bootstrapContributors.test.js +0 -166
  81. package/server/runtime/composition.js +0 -142
  82. package/server/runtime/domainEvents.test.js +0 -114
  83. package/server/runtime/domainRules.js +0 -50
  84. package/server/runtime/domainRules.test.js +0 -87
  85. package/server/runtime/runtimeAssembly.js +0 -113
  86. package/server/runtime/runtimeKernel.js +0 -55
  87. package/server/runtime/serviceRegistration.test.js +0 -251
  88. package/server/support/SupportCoreServiceProvider.js +0 -27
  89. package/server/surface/SurfaceRoutingServiceProvider.js +0 -27
  90. package/shared/actions/index.js +0 -2
  91. package/shared/runtime/application.js +0 -324
  92. package/shared/runtime/container.js +0 -261
  93. package/shared/runtime/containerErrors.js +0 -22
  94. package/shared/runtime/index.js +0 -18
  95. package/shared/runtime/kernelErrors.js +0 -25
  96. package/shared/runtime/kernelErrors.test.js +0 -120
  97. package/shared/runtime/serviceProvider.js +0 -13
  98. package/shared/support/containerToken.js +0 -8
  99. package/shared/support/generatedUiContract.js +0 -542
  100. package/shared/support/generatedUiContract.test.js +0 -218
  101. package/shared/support/tokens.js +0 -1
  102. package/shared/support/tokens.test.js +0 -17
@@ -1,53 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createContainer } from "../container/index.js";
4
- import { registerDomainEventListener } from "../registries/domainEventListenerRegistry.js";
5
- import { ServerRuntimeCoreServiceProvider } from "./ServerRuntimeCoreServiceProvider.js";
6
-
7
- test("ServerRuntimeCoreServiceProvider registers runtime.server and default domainEvents", () => {
8
- const app = createContainer();
9
- const provider = new ServerRuntimeCoreServiceProvider();
10
- provider.register(app);
11
-
12
- assert.equal(typeof app.service, "function");
13
-
14
- const runtimeServer = app.make("runtime.server");
15
- assert.equal(typeof runtimeServer, "object");
16
-
17
- const domainEvents = app.make("domainEvents");
18
- assert.equal(typeof domainEvents.publish, "function");
19
- });
20
-
21
- test("ServerRuntimeCoreServiceProvider default domainEvents dispatches registered listeners", async () => {
22
- const app = createContainer();
23
- const provider = new ServerRuntimeCoreServiceProvider();
24
- provider.register(app);
25
-
26
- const received = [];
27
- registerDomainEventListener(app, "test.domainEvents.alpha", () => ({
28
- listenerId: "alpha",
29
- async handle(payload) {
30
- received.push(payload);
31
- }
32
- }));
33
-
34
- const domainEvents = app.make("domainEvents");
35
- const eventPayload = {
36
- source: "test"
37
- };
38
- const result = await domainEvents.publish(eventPayload);
39
-
40
- assert.equal(result, null);
41
- assert.deepEqual(received, [eventPayload]);
42
- });
43
-
44
- test("ServerRuntimeCoreServiceProvider owns domainEvents binding", async () => {
45
- const app = createContainer();
46
- app.singleton("domainEvents", () => ({ publish: async () => "existing" }));
47
-
48
- const provider = new ServerRuntimeCoreServiceProvider();
49
- assert.throws(
50
- () => provider.register(app),
51
- /Token "domainEvents" is already bound\./
52
- );
53
- });
@@ -1,109 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import {
4
- defaultApplyRoutePolicy as applyHttpRoutePolicy,
5
- normalizeRoutePolicyConfig as normalizeHttpRoutePolicyConfig
6
- } from "../http/lib/kernel.js";
7
- import { __testables as runtimeRouteRegistrationTestables } from "./apiRouteRegistration.js";
8
- import {
9
- defaultApplyRoutePolicy as applyCanonicalRoutePolicy,
10
- normalizeRoutePolicyConfig as normalizeCanonicalRoutePolicyConfig
11
- } from "../support/routePolicyConfig.js";
12
-
13
- test("route policy mapping is sourced from one canonical mapper in both registration paths", () => {
14
- assert.equal(applyHttpRoutePolicy, applyCanonicalRoutePolicy);
15
- assert.equal(runtimeRouteRegistrationTestables.defaultApplyRoutePolicy, applyCanonicalRoutePolicy);
16
- assert.equal(normalizeHttpRoutePolicyConfig, normalizeCanonicalRoutePolicyConfig);
17
- assert.equal(runtimeRouteRegistrationTestables.normalizeRoutePolicyConfig, normalizeCanonicalRoutePolicyConfig);
18
- });
19
-
20
- test("route policy parity matrix stays aligned across http/runtime registration", () => {
21
- const ownerResolver = () => 42;
22
-
23
- const matrix = [
24
- {
25
- label: "auth maps to authPolicy",
26
- route: { auth: "required" },
27
- expectedConfig: { seed: "x", authPolicy: "required" }
28
- },
29
- {
30
- label: "contextPolicy maps through",
31
- route: { contextPolicy: "required" },
32
- expectedConfig: { seed: "x", contextPolicy: "required" }
33
- },
34
- {
35
- label: "surface maps through",
36
- route: { surface: "admin" },
37
- expectedConfig: { seed: "x", surface: "admin" }
38
- },
39
- {
40
- label: "visibility is normalized",
41
- route: { visibility: "USER" },
42
- expectedConfig: { seed: "x", visibility: "user" }
43
- },
44
- {
45
- label: "permission maps through",
46
- route: { permission: "workspace.settings.read" },
47
- expectedConfig: { seed: "x", permission: "workspace.settings.read" }
48
- },
49
- {
50
- label: "ownerParam maps through",
51
- route: { ownerParam: "userId" },
52
- expectedConfig: { seed: "x", ownerParam: "userId" }
53
- },
54
- {
55
- label: "userField maps through",
56
- route: { userField: "accountId" },
57
- expectedConfig: { seed: "x", userField: "accountId" }
58
- },
59
- {
60
- label: "ownerResolver maps through",
61
- route: { ownerResolver },
62
- expectedConfig: { seed: "x", ownerResolver }
63
- },
64
- {
65
- label: "csrfProtection maps through",
66
- route: { csrfProtection: false },
67
- expectedConfig: { seed: "x", csrfProtection: false }
68
- },
69
- {
70
- label: "route fields override existing config values",
71
- routeOptionsConfig: { authPolicy: "public", visibility: "public", seed: "x" },
72
- route: { auth: "own", visibility: "WORKSPACE" },
73
- expectedConfig: { seed: "x", authPolicy: "own", visibility: "workspace" }
74
- },
75
- {
76
- label: "unmapped route fields do not alter config",
77
- route: { rateLimit: { max: 1, timeWindow: "1 second" } },
78
- expectedConfig: { seed: "x" }
79
- }
80
- ];
81
-
82
- for (const testCase of matrix) {
83
- const routeOptions = {
84
- method: "GET",
85
- url: "/demo",
86
- config: {
87
- seed: "x",
88
- ...(testCase.routeOptionsConfig || {})
89
- }
90
- };
91
- const route = {
92
- method: "GET",
93
- path: "/demo",
94
- ...(testCase.route || {})
95
- };
96
-
97
- const canonical = applyCanonicalRoutePolicy(routeOptions, route);
98
- const fromHttp = applyHttpRoutePolicy(routeOptions, route);
99
- const fromRuntime = runtimeRouteRegistrationTestables.defaultApplyRoutePolicy(routeOptions, route);
100
-
101
- assert.deepEqual(
102
- canonical.config,
103
- testCase.expectedConfig,
104
- `canonical mapping failed for case: ${testCase.label}`
105
- );
106
- assert.deepEqual(fromHttp, canonical, `http mapping drifted for case: ${testCase.label}`);
107
- assert.deepEqual(fromRuntime, canonical, `runtime mapping drifted for case: ${testCase.label}`);
108
- }
109
- });
@@ -1,65 +0,0 @@
1
- import { defaultMissingHandler } from "./routeUtils.js";
2
- import { defaultApplyRoutePolicy, normalizeRoutePolicyConfig } from "../support/routePolicyConfig.js";
3
- import { isRecord } from "../../shared/support/normalize.js";
4
-
5
- function buildBaseRouteOptions(route) {
6
- if (!isRecord(route)) {
7
- throw new TypeError("Route definition must be an object.");
8
- }
9
-
10
- const sourceRoute = route;
11
- const routeOptions = {
12
- method: sourceRoute.method,
13
- url: sourceRoute.path,
14
- config: {}
15
- };
16
-
17
- if (sourceRoute.schema) {
18
- routeOptions.schema = sourceRoute.schema;
19
- }
20
- if (sourceRoute.bodyLimit) {
21
- routeOptions.bodyLimit = sourceRoute.bodyLimit;
22
- }
23
- if (sourceRoute.rateLimit) {
24
- routeOptions.config.rateLimit = sourceRoute.rateLimit;
25
- }
26
-
27
- return routeOptions;
28
- }
29
-
30
- function registerApiRouteDefinitions(
31
- fastify,
32
- { routes = [], applyRoutePolicy = defaultApplyRoutePolicy, resolveRequestUrl = null, missingHandler } = {}
33
- ) {
34
- if (!fastify || typeof fastify.route !== "function") {
35
- throw new TypeError("registerApiRouteDefinitions requires a Fastify instance.");
36
- }
37
-
38
- const routeList = Array.isArray(routes) ? routes : [];
39
- const toRequestUrl = typeof resolveRequestUrl === "function" ? resolveRequestUrl : () => null;
40
- const routePolicyApplier = typeof applyRoutePolicy === "function" ? applyRoutePolicy : defaultApplyRoutePolicy;
41
- const fallbackHandler = typeof missingHandler === "function" ? missingHandler : defaultMissingHandler;
42
-
43
- for (const route of routeList) {
44
- const routeOptions = routePolicyApplier(buildBaseRouteOptions(route), route);
45
- let routeHandler = fallbackHandler;
46
- if (isRecord(route) && typeof route.handler === "function") {
47
- routeHandler = route.handler;
48
- }
49
- fastify.route({
50
- ...routeOptions,
51
- handler: async (request, reply) => {
52
- await routeHandler(request, reply, toRequestUrl(request));
53
- }
54
- });
55
- }
56
- }
57
-
58
- const __testables = {
59
- buildBaseRouteOptions,
60
- defaultApplyRoutePolicy,
61
- normalizeRoutePolicyConfig,
62
- defaultMissingHandler
63
- };
64
-
65
- export { registerApiRouteDefinitions, __testables };
@@ -1,29 +0,0 @@
1
- import { AUTH_POLICY_PUBLIC } from "../../shared/support/policies.js";
2
- import { resolveBootstrapPayload } from "../registries/bootstrapPayloadContributorRegistry.js";
3
-
4
- function bootBootstrapRoutes(app) {
5
- const router = app.make("jskit.http.router");
6
-
7
- router.register(
8
- "GET",
9
- "/api/bootstrap",
10
- {
11
- auth: AUTH_POLICY_PUBLIC,
12
- meta: {
13
- tags: ["bootstrap"],
14
- summary: "Resolve app bootstrap payload from registered contributors"
15
- }
16
- },
17
- async function (request, reply) {
18
- const payload = await resolveBootstrapPayload(app, {
19
- request,
20
- reply,
21
- query: request.query || {}
22
- });
23
-
24
- reply.code(200).send(payload);
25
- }
26
- );
27
- }
28
-
29
- export { bootBootstrapRoutes };
@@ -1,69 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createContainer } from "../container/index.js";
4
- import { registerBootstrapPayloadContributor } from "../registries/bootstrapPayloadContributorRegistry.js";
5
- import { bootBootstrapRoutes } from "./bootBootstrapRoutes.js";
6
-
7
- function createReplyDouble() {
8
- return {
9
- statusCode: 200,
10
- payload: null,
11
- code(value) {
12
- this.statusCode = value;
13
- return this;
14
- },
15
- send(value) {
16
- this.payload = value;
17
- return this;
18
- }
19
- };
20
- }
21
-
22
- test("bootBootstrapRoutes registers GET /api/bootstrap and resolves contributors", async () => {
23
- const app = createContainer();
24
- const routes = [];
25
- const router = {
26
- register(method, path, route, handler) {
27
- routes.push({
28
- method,
29
- path,
30
- route,
31
- handler
32
- });
33
- }
34
- };
35
-
36
- app.instance("jskit.http.router", router);
37
- registerBootstrapPayloadContributor(app, "test.bootstrap.payload", () => ({
38
- contributorId: "test.bootstrap.payload",
39
- contribute({ query }) {
40
- return {
41
- source: "test",
42
- workspaceSlug: query.workspaceSlug
43
- };
44
- }
45
- }));
46
-
47
- bootBootstrapRoutes(app);
48
-
49
- const bootstrapRoute = routes.find((entry) => entry.method === "GET" && entry.path === "/api/bootstrap");
50
- assert.ok(bootstrapRoute);
51
- assert.equal(Object.prototype.hasOwnProperty.call(bootstrapRoute.route, "query"), false);
52
- assert.equal(Object.prototype.hasOwnProperty.call(bootstrapRoute.route, "responses"), false);
53
-
54
- const reply = createReplyDouble();
55
- await bootstrapRoute.handler(
56
- {
57
- query: {
58
- workspaceSlug: "acme"
59
- }
60
- },
61
- reply
62
- );
63
-
64
- assert.equal(reply.statusCode, 200);
65
- assert.deepEqual(reply.payload, {
66
- source: "test",
67
- workspaceSlug: "acme"
68
- });
69
- });
@@ -1,166 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createContainer } from "../container/index.js";
4
- import {
5
- registerBootstrapPayloadContributor,
6
- resolveBootstrapPayloadContributors,
7
- resolveBootstrapPayload
8
- } from "../registries/bootstrapPayloadContributorRegistry.js";
9
-
10
- test("registerBootstrapPayloadContributor + resolveBootstrapPayloadContributors register canonical contributors", () => {
11
- const app = createContainer();
12
-
13
- registerBootstrapPayloadContributor(app, "test.bootstrap.alpha", () => ({
14
- contributorId: "alpha",
15
- contribute() {
16
- return {
17
- alpha: true
18
- };
19
- }
20
- }));
21
-
22
- const contributors = resolveBootstrapPayloadContributors(app);
23
- assert.equal(contributors.length, 1);
24
- assert.equal(contributors[0].contributorId, "alpha");
25
- assert.equal(typeof contributors[0].contribute, "function");
26
- });
27
-
28
- test("resolveBootstrapPayload applies contributors in deterministic token order", async () => {
29
- const app = createContainer();
30
- const calls = [];
31
-
32
- registerBootstrapPayloadContributor(app, "test.bootstrap.zeta", () => ({
33
- contributorId: "zeta",
34
- contribute({ payload, query }) {
35
- calls.push({
36
- contributorId: "zeta",
37
- payload,
38
- query
39
- });
40
- return {
41
- last: true
42
- };
43
- }
44
- }));
45
-
46
- registerBootstrapPayloadContributor(app, "test.bootstrap.alpha", () => ({
47
- contributorId: "alpha",
48
- contribute({ payload, query }) {
49
- calls.push({
50
- contributorId: "alpha",
51
- payload,
52
- query
53
- });
54
- return {
55
- first: true
56
- };
57
- }
58
- }));
59
-
60
- const payload = await resolveBootstrapPayload(app, {
61
- query: {
62
- workspaceSlug: "acme"
63
- }
64
- });
65
-
66
- assert.deepEqual(calls, [
67
- {
68
- contributorId: "alpha",
69
- payload: {},
70
- query: {
71
- workspaceSlug: "acme"
72
- }
73
- },
74
- {
75
- contributorId: "zeta",
76
- payload: {
77
- first: true
78
- },
79
- query: {
80
- workspaceSlug: "acme"
81
- }
82
- }
83
- ]);
84
- assert.deepEqual(payload, {
85
- first: true,
86
- last: true
87
- });
88
- });
89
-
90
- test("resolveBootstrapPayload honors explicit contributor order before token order", async () => {
91
- const app = createContainer();
92
- const calls = [];
93
-
94
- registerBootstrapPayloadContributor(app, "test.bootstrap.alpha", () => ({
95
- contributorId: "alpha",
96
- order: 200,
97
- contribute({ payload }) {
98
- calls.push({
99
- contributorId: "alpha",
100
- payload
101
- });
102
- return {
103
- alpha: true
104
- };
105
- }
106
- }));
107
-
108
- registerBootstrapPayloadContributor(app, "test.bootstrap.zeta", () => ({
109
- contributorId: "zeta",
110
- order: 100,
111
- contribute({ payload }) {
112
- calls.push({
113
- contributorId: "zeta",
114
- payload
115
- });
116
- return {
117
- zeta: true
118
- };
119
- }
120
- }));
121
-
122
- const payload = await resolveBootstrapPayload(app);
123
-
124
- assert.deepEqual(calls, [
125
- {
126
- contributorId: "zeta",
127
- payload: {}
128
- },
129
- {
130
- contributorId: "alpha",
131
- payload: {
132
- zeta: true
133
- }
134
- }
135
- ]);
136
- assert.deepEqual(payload, {
137
- zeta: true,
138
- alpha: true
139
- });
140
- });
141
-
142
- test("resolveBootstrapPayload ignores non-object contributions", async () => {
143
- const app = createContainer();
144
-
145
- registerBootstrapPayloadContributor(app, "test.bootstrap.noop", () => ({
146
- contributorId: "noop",
147
- contribute() {
148
- return null;
149
- }
150
- }));
151
- registerBootstrapPayloadContributor(app, "test.bootstrap.ok", () => ({
152
- contributorId: "ok",
153
- contribute() {
154
- return {
155
- ok: true
156
- };
157
- }
158
- }));
159
-
160
- const payload = await resolveBootstrapPayload(app, {
161
- ignored: true
162
- });
163
- assert.deepEqual(payload, {
164
- ok: true
165
- });
166
- });
@@ -1,142 +0,0 @@
1
- function normalizeRegistryDefinitions(definitions, { registryKind = "registry" } = {}) {
2
- const source = Array.isArray(definitions) ? definitions : [];
3
- const normalized = [];
4
- const seenIds = new Set();
5
-
6
- for (const entry of source) {
7
- const id = String(entry?.id || "").trim();
8
- const create = entry?.create;
9
-
10
- if (!id) {
11
- throw new TypeError(`${registryKind} definition id is required.`);
12
- }
13
- if (seenIds.has(id)) {
14
- throw new TypeError(`${registryKind} definition "${id}" is duplicated.`);
15
- }
16
- if (typeof create !== "function") {
17
- throw new TypeError(`${registryKind} definition "${id}" create must be a function.`);
18
- }
19
-
20
- seenIds.add(id);
21
- normalized.push({
22
- id,
23
- create
24
- });
25
- }
26
-
27
- return normalized;
28
- }
29
-
30
- function createRegistryFromDefinitions(definitions, createArgsFactory, options = {}) {
31
- const normalizedDefinitions = normalizeRegistryDefinitions(definitions, options);
32
- const registry = {};
33
-
34
- for (const definition of normalizedDefinitions) {
35
- const createArgs =
36
- typeof createArgsFactory === "function" ? createArgsFactory({ definition, registry }) : Object.freeze({});
37
- registry[definition.id] = definition.create(createArgs || {});
38
- }
39
-
40
- return registry;
41
- }
42
-
43
- function createRepositoryRegistry(definitions) {
44
- return createRegistryFromDefinitions(definitions, () => ({}), {
45
- registryKind: "repository"
46
- });
47
- }
48
-
49
- function createServiceRegistry({ definitions, dependencies = {} } = {}) {
50
- return createRegistryFromDefinitions(
51
- definitions,
52
- ({ registry }) => ({
53
- ...(dependencies || {}),
54
- services: registry
55
- }),
56
- {
57
- registryKind: "service"
58
- }
59
- );
60
- }
61
-
62
- function createControllerRegistry({ definitions, services = {}, dependencies = {} } = {}) {
63
- return createRegistryFromDefinitions(
64
- definitions,
65
- ({ registry }) => ({
66
- ...(dependencies || {}),
67
- services,
68
- controllers: registry
69
- }),
70
- {
71
- registryKind: "controller"
72
- }
73
- );
74
- }
75
-
76
- function selectRuntimeServices(services, selectedIds = []) {
77
- const source = services && typeof services === "object" ? services : {};
78
- const ids = Array.isArray(selectedIds) ? selectedIds : [];
79
- const runtimeServices = {};
80
-
81
- for (const rawId of ids) {
82
- const id = String(rawId || "").trim();
83
- if (!id) {
84
- continue;
85
- }
86
- if (!Object.hasOwn(source, id)) {
87
- throw new Error(`Runtime service "${id}" is not defined.`);
88
- }
89
- runtimeServices[id] = source[id];
90
- }
91
-
92
- return runtimeServices;
93
- }
94
-
95
- function createRuntimeComposition({
96
- repositoryDefinitions = [],
97
- serviceDefinitions = [],
98
- controllerDefinitions = [],
99
- runtimeServiceIds = [],
100
- repositoryDependencies = {},
101
- serviceDependencies = {},
102
- controllerDependencies = {}
103
- } = {}) {
104
- const repositories = createRepositoryRegistry(repositoryDefinitions);
105
- const services = createServiceRegistry({
106
- definitions: serviceDefinitions,
107
- dependencies: {
108
- ...(repositoryDependencies || {}),
109
- ...(serviceDependencies || {}),
110
- repositories
111
- }
112
- });
113
- const controllers = createControllerRegistry({
114
- definitions: controllerDefinitions,
115
- services,
116
- dependencies: {
117
- ...(controllerDependencies || {})
118
- }
119
- });
120
- const runtimeServices = selectRuntimeServices(services, runtimeServiceIds);
121
-
122
- return {
123
- repositories,
124
- services,
125
- controllers,
126
- runtimeServices
127
- };
128
- }
129
-
130
- const __testables = {
131
- normalizeRegistryDefinitions,
132
- createRegistryFromDefinitions
133
- };
134
-
135
- export {
136
- createRepositoryRegistry,
137
- createServiceRegistry,
138
- createControllerRegistry,
139
- selectRuntimeServices,
140
- createRuntimeComposition,
141
- __testables
142
- };