@jskit-ai/kernel 0.1.158 → 0.1.160

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 (103) 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.js +12 -3
  7. package/client/vite/clientBootstrapPlugin.test.js +21 -6
  8. package/internal/node/installedPackages.js +2 -7
  9. package/internal/node/installedPackages.test.js +26 -5
  10. package/package.json +3 -5
  11. package/server/actions/actionCatalogue.js +162 -0
  12. package/server/actions/actionEvents.js +66 -0
  13. package/server/actions/actionProvider.js +23 -0
  14. package/server/actions/index.js +3 -6
  15. package/server/features/defineFeature.js +131 -0
  16. package/server/features/defineFeature.test.js +238 -0
  17. package/server/features/index.js +1 -0
  18. package/server/http/HttpProvider.js +23 -0
  19. package/server/http/_testable/index.js +0 -1
  20. package/server/http/capabilityHttpRuntime.js +123 -0
  21. package/server/http/capabilityHttpRuntime.test.js +161 -0
  22. package/server/http/directRequestActionExecutor.js +78 -0
  23. package/server/http/index.js +2 -1
  24. package/server/http/lib/index.js +1 -13
  25. package/server/http/lib/routeRegistration.js +9 -25
  26. package/server/platform/index.js +2 -2
  27. package/server/platform/installedRuntime.js +122 -0
  28. package/server/platform/installedRuntime.test.js +103 -0
  29. package/server/platform/providerRuntime/capabilityProviderLoader.js +100 -0
  30. package/server/platform/providerRuntime/capabilityProviderLoader.test.js +80 -0
  31. package/server/platform/providerRuntime/packageCatalog.js +4 -1
  32. package/server/platform/surfaceRuntime.js +1 -15
  33. package/server/runtime/BootstrapProvider.js +69 -0
  34. package/server/runtime/EventProvider.js +74 -0
  35. package/server/runtime/EventProvider.test.js +32 -0
  36. package/server/runtime/entityChangeEvents.js +7 -7
  37. package/server/runtime/entityChangeEvents.test.js +2 -2
  38. package/server/runtime/fastifyBootstrap.js +0 -40
  39. package/server/runtime/index.js +2 -3
  40. package/server/surface/index.js +0 -1
  41. package/shared/actions/actionDefinitions.js +20 -0
  42. package/shared/actions/pipeline.js +22 -0
  43. package/shared/actions/policies.js +1 -1
  44. package/shared/actions/registry.js +3 -0
  45. package/shared/capabilities/defineProvider.js +99 -0
  46. package/shared/capabilities/index.js +2 -0
  47. package/shared/capabilities/runtime.js +243 -0
  48. package/shared/capabilities/runtime.test.js +170 -0
  49. package/test/barrelExposure.test.js +36 -13
  50. package/test/exportsContract.test.js +8 -3
  51. package/server/actions/ActionRuntimeServiceProvider.js +0 -304
  52. package/server/actions/ActionRuntimeServiceProvider.test.js +0 -558
  53. package/server/container/ContainerCoreServiceProvider.js +0 -27
  54. package/server/container/index.js +0 -10
  55. package/server/http/HttpFastifyServiceProvider.js +0 -25
  56. package/server/http/lib/httpRuntime.js +0 -83
  57. package/server/http/lib/kernel.js +0 -15
  58. package/server/http/lib/kernel.test.js +0 -1565
  59. package/server/http/lib/requestActionExecutor.js +0 -265
  60. package/server/http/lib/requestScope.js +0 -57
  61. package/server/kernel/KernelCoreServiceProvider.js +0 -27
  62. package/server/kernel/index.js +0 -10
  63. package/server/platform/PlatformServerRuntimeServiceProvider.js +0 -30
  64. package/server/platform/providerRuntime/providerLoader.js +0 -283
  65. package/server/platform/providerRuntime.js +0 -146
  66. package/server/platform/providerRuntime.test.js +0 -214
  67. package/server/platform/runtime.js +0 -40
  68. package/server/registries/actionSurfaceSourceRegistry.js +0 -148
  69. package/server/registries/bootstrapPayloadContributorRegistry.js +0 -51
  70. package/server/registries/domainEventListenerRegistry.js +0 -58
  71. package/server/registries/index.js +0 -32
  72. package/server/registries/primitives.js +0 -63
  73. package/server/registries/routeVisibilityResolverRegistry.js +0 -84
  74. package/server/registries/serviceRegistrationRegistry.js +0 -488
  75. package/server/runtime/ServerRuntimeCoreServiceProvider.js +0 -64
  76. package/server/runtime/ServerRuntimeCoreServiceProvider.test.js +0 -53
  77. package/server/runtime/apiRoutePolicyParity.test.js +0 -109
  78. package/server/runtime/apiRouteRegistration.js +0 -65
  79. package/server/runtime/bootBootstrapRoutes.js +0 -29
  80. package/server/runtime/bootBootstrapRoutes.test.js +0 -69
  81. package/server/runtime/bootstrapContributors.test.js +0 -166
  82. package/server/runtime/composition.js +0 -142
  83. package/server/runtime/domainEvents.test.js +0 -114
  84. package/server/runtime/domainRules.js +0 -50
  85. package/server/runtime/domainRules.test.js +0 -87
  86. package/server/runtime/runtimeAssembly.js +0 -113
  87. package/server/runtime/runtimeKernel.js +0 -55
  88. package/server/runtime/serviceRegistration.test.js +0 -251
  89. package/server/support/SupportCoreServiceProvider.js +0 -27
  90. package/server/surface/SurfaceRoutingServiceProvider.js +0 -27
  91. package/shared/actions/index.js +0 -2
  92. package/shared/runtime/application.js +0 -324
  93. package/shared/runtime/container.js +0 -261
  94. package/shared/runtime/containerErrors.js +0 -22
  95. package/shared/runtime/index.js +0 -18
  96. package/shared/runtime/kernelErrors.js +0 -25
  97. package/shared/runtime/kernelErrors.test.js +0 -120
  98. package/shared/runtime/serviceProvider.js +0 -13
  99. package/shared/support/containerToken.js +0 -8
  100. package/shared/support/generatedUiContract.js +0 -542
  101. package/shared/support/generatedUiContract.test.js +0 -218
  102. package/shared/support/tokens.js +0 -1
  103. package/shared/support/tokens.test.js +0 -17
@@ -0,0 +1,23 @@
1
+ import { defineProvider } from "../../shared/capabilities/defineProvider.js";
2
+ import { createCapabilityHttpRuntime } from "./capabilityHttpRuntime.js";
3
+
4
+ const HttpProvider = defineProvider({
5
+ id: "runtime.http",
6
+ requires: {
7
+ actions: "runtime.actions",
8
+ fastify: "runtime.fastify"
9
+ },
10
+ provides: {
11
+ http: "runtime.http"
12
+ },
13
+ setup({ actions, fastify }) {
14
+ return {
15
+ http: createCapabilityHttpRuntime({ actions, fastify })
16
+ };
17
+ },
18
+ boot(_dependencies, { outputs }) {
19
+ outputs.http.start();
20
+ }
21
+ });
22
+
23
+ export { HttpProvider };
@@ -1,2 +1 @@
1
- export { createHttpRuntime } from "../lib/httpRuntime.js";
2
1
  export { compileRouteValidator } from "../lib/routeValidator.js";
@@ -0,0 +1,123 @@
1
+ import {
2
+ normalizeRouteVisibility,
3
+ normalizeRouteVisibilityToken,
4
+ normalizeVisibilityContext
5
+ } from "../../shared/support/visibility.js";
6
+ import { normalizeText } from "../../shared/support/normalize.js";
7
+ import { createRouter } from "./lib/router.js";
8
+ import { registerRoutes } from "./lib/routeRegistration.js";
9
+ import {
10
+ registerApiErrorHandler,
11
+ registerBodylessContentTypeNormalizer
12
+ } from "../runtime/fastifyBootstrap.js";
13
+ import { isAppError } from "../runtime/errors.js";
14
+
15
+ function normalizeResolver({ id, resolve } = {}) {
16
+ const resolverId = normalizeText(id);
17
+ if (!resolverId) {
18
+ throw new TypeError("HTTP visibility resolver id is required.");
19
+ }
20
+ if (typeof resolve !== "function") {
21
+ throw new TypeError(`HTTP visibility resolver "${resolverId}" requires resolve().`);
22
+ }
23
+ return Object.freeze({ id: resolverId, resolve });
24
+ }
25
+
26
+ function createCapabilityHttpRuntime({ fastify, actions }) {
27
+ if (!fastify || typeof fastify.route !== "function") {
28
+ throw new TypeError("HTTP runtime requires a Fastify instance.");
29
+ }
30
+ if (!actions || typeof actions.registerContextContributor !== "function") {
31
+ throw new TypeError("HTTP runtime requires the runtime.actions capability.");
32
+ }
33
+
34
+ const router = createRouter();
35
+ const visibilityResolvers = [];
36
+ const visibilityResolverIds = new Set();
37
+ let started = false;
38
+ let registration = null;
39
+
40
+ function assertOpen() {
41
+ if (started) {
42
+ throw new Error("HTTP runtime registration is closed after startup.");
43
+ }
44
+ }
45
+
46
+ function registerVisibilityResolver(value) {
47
+ assertOpen();
48
+ const resolver = normalizeResolver(value);
49
+ if (visibilityResolverIds.has(resolver.id)) {
50
+ throw new Error(`HTTP visibility resolver "${resolver.id}" is duplicated.`);
51
+ }
52
+ visibilityResolverIds.add(resolver.id);
53
+ visibilityResolvers.push(resolver);
54
+ return api;
55
+ }
56
+
57
+ actions.registerContextContributor({
58
+ id: "runtime.http.visibility",
59
+ async contribute({ actionId, version, definition, input, context }) {
60
+ const visibility = normalizeRouteVisibilityToken(context.routeVisibility);
61
+ const patch = {};
62
+ for (const resolver of visibilityResolvers) {
63
+ const contribution = await resolver.resolve(Object.freeze({
64
+ request: context.requestMeta?.request || null,
65
+ visibility,
66
+ context,
67
+ input,
68
+ actionId,
69
+ version,
70
+ definition,
71
+ channel: normalizeText(context.channel).toLowerCase() || "api"
72
+ }));
73
+ if (contribution && typeof contribution === "object" && !Array.isArray(contribution)) {
74
+ Object.assign(patch, contribution);
75
+ }
76
+ }
77
+ const coreVisibility = normalizeRouteVisibility(visibility);
78
+ const visibilityContext = normalizeVisibilityContext({
79
+ ...patch,
80
+ visibility,
81
+ requiresActorScope: patch.requiresActorScope === true || coreVisibility === "user"
82
+ });
83
+ return {
84
+ visibilityContext,
85
+ requestMeta: {
86
+ visibilityContext,
87
+ routeVisibility: visibilityContext.visibility
88
+ }
89
+ };
90
+ }
91
+ });
92
+
93
+ function start(options = {}) {
94
+ assertOpen();
95
+ started = true;
96
+ registerBodylessContentTypeNormalizer(fastify);
97
+ registerApiErrorHandler(fastify, { isAppError });
98
+ registration = Object.freeze(registerRoutes(fastify, {
99
+ ...options,
100
+ actions,
101
+ routes: router.list()
102
+ }));
103
+ return registration;
104
+ }
105
+
106
+ function diagnostics() {
107
+ return Object.freeze({
108
+ started,
109
+ routeCount: registration?.routeCount || router.list().filter((route) => route.internal !== true).length,
110
+ visibilityResolverIds: Object.freeze([...visibilityResolverIds].sort())
111
+ });
112
+ }
113
+
114
+ const api = Object.freeze({
115
+ router,
116
+ registerVisibilityResolver,
117
+ start,
118
+ diagnostics
119
+ });
120
+ return api;
121
+ }
122
+
123
+ export { createCapabilityHttpRuntime };
@@ -0,0 +1,161 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { createSchema } from "json-rest-schema";
4
+
5
+ import { createActionProvider } from "../actions/actionProvider.js";
6
+ import { createCapabilityRuntime } from "../../shared/capabilities/runtime.js";
7
+ import { defineFeature } from "../features/defineFeature.js";
8
+ import { HttpProvider } from "./HttpProvider.js";
9
+
10
+ function createFastifyStub() {
11
+ return {
12
+ routes: [],
13
+ hooks: {},
14
+ contentTypeParsers: new Map(),
15
+ log: { error() {} },
16
+ route(value) {
17
+ this.routes.push(value);
18
+ },
19
+ addHook(name, handler) {
20
+ this.hooks[name] = handler;
21
+ },
22
+ setErrorHandler(handler) {
23
+ this.errorHandler = handler;
24
+ },
25
+ hasContentTypeParser(type) {
26
+ return this.contentTypeParsers.has(type);
27
+ },
28
+ getDefaultJsonParser() {
29
+ return (_request, body, done) => done(null, body);
30
+ },
31
+ addContentTypeParser(type, options, parser) {
32
+ this.contentTypeParsers.set(type, { options, parser });
33
+ }
34
+ };
35
+ }
36
+
37
+ function createReply() {
38
+ return {
39
+ statusCode: 200,
40
+ headers: {},
41
+ code(value) {
42
+ this.statusCode = value;
43
+ return this;
44
+ },
45
+ header(name, value) {
46
+ this.headers[name.toLowerCase()] = value;
47
+ return this;
48
+ },
49
+ hasHeader(name) {
50
+ return Object.hasOwn(this.headers, name.toLowerCase());
51
+ },
52
+ send(value) {
53
+ this.payload = value;
54
+ return this;
55
+ }
56
+ };
57
+ }
58
+
59
+ test("HttpProvider registers routes that invoke actions directly", async () => {
60
+ const fastify = createFastifyStub();
61
+ const feature = defineFeature({
62
+ id: "feature.http-proof",
63
+ domain: "http-proof",
64
+ requires: { http: "runtime.http" },
65
+ setup({ http }) {
66
+ http.router.get("/proof", {
67
+ surface: "app",
68
+ visibility: "public"
69
+ }, async (request, reply) => {
70
+ const result = await request.executeAction({ actionId: "http-proof.read" });
71
+ reply.code(200).send(result);
72
+ });
73
+ return {};
74
+ },
75
+ actions: [{
76
+ id: "http-proof.read",
77
+ kind: "query",
78
+ channels: ["api"],
79
+ surfaces: ["app"],
80
+ input: { schema: createSchema({}) },
81
+ idempotency: "none",
82
+ async execute(_input, context) {
83
+ return {
84
+ channel: context.channel,
85
+ surface: context.surface,
86
+ visibility: context.visibilityContext.visibility,
87
+ hasRequest: Boolean(context.requestMeta.request)
88
+ };
89
+ }
90
+ }]
91
+ });
92
+ const runtime = createCapabilityRuntime({
93
+ inputs: { "runtime.fastify": fastify },
94
+ providers: [createActionProvider(), HttpProvider, feature]
95
+ });
96
+
97
+ await runtime.start();
98
+ assert.equal(fastify.routes.length, 1);
99
+ assert.equal(fastify.routes[0].url, "/proof");
100
+
101
+ const request = { id: "req-1", routeOptions: { config: fastify.routes[0].config } };
102
+ const reply = createReply();
103
+ await fastify.routes[0].handler(request, reply);
104
+
105
+ assert.equal(reply.statusCode, 200);
106
+ assert.deepEqual(reply.payload, {
107
+ channel: "api",
108
+ surface: "app",
109
+ visibility: "public",
110
+ hasRequest: true
111
+ });
112
+ assert.equal(Object.hasOwn(request, "scope"), false);
113
+ await runtime.shutdown();
114
+ });
115
+
116
+ test("direct HTTP action execution preserves request-scoped stream dependencies", async () => {
117
+ const fastify = createFastifyStub();
118
+ const streamWriter = Object.freeze({ id: "writer-1" });
119
+ const abortSignal = Object.freeze({ aborted: false });
120
+ const feature = defineFeature({
121
+ id: "feature.stream-proof",
122
+ domain: "stream-proof",
123
+ requires: { http: "runtime.http" },
124
+ setup({ http }) {
125
+ http.router.post("/stream-proof", { surface: "app", visibility: "public" }, async (request, reply) => {
126
+ const result = await request.executeAction({
127
+ actionId: "stream-proof.run",
128
+ deps: { streamWriter, abortSignal }
129
+ });
130
+ reply.code(200).send(result);
131
+ });
132
+ return {};
133
+ },
134
+ actions: [{
135
+ id: "stream-proof.run",
136
+ kind: "stream",
137
+ channels: ["api"],
138
+ surfaces: ["app"],
139
+ input: { schema: createSchema({}) },
140
+ idempotency: "none",
141
+ async execute(_input, _context, deps) {
142
+ return {
143
+ writerId: deps.streamWriter.id,
144
+ aborted: deps.abortSignal.aborted
145
+ };
146
+ }
147
+ }]
148
+ });
149
+ const runtime = createCapabilityRuntime({
150
+ inputs: { "runtime.fastify": fastify },
151
+ providers: [createActionProvider(), HttpProvider, feature]
152
+ });
153
+
154
+ await runtime.start();
155
+ const request = { routeOptions: { config: fastify.routes[0].config } };
156
+ const reply = createReply();
157
+ await fastify.routes[0].handler(request, reply);
158
+
159
+ assert.deepEqual(reply.payload, { writerId: "writer-1", aborted: false });
160
+ await runtime.shutdown();
161
+ });
@@ -0,0 +1,78 @@
1
+ import { normalizeObject, normalizeText } from "../../shared/support/normalize.js";
2
+ import { normalizeRouteVisibilityToken } from "../../shared/support/visibility.js";
3
+ import { resolveDefaultSurfaceId } from "../support/appConfig.js";
4
+ import { RouteRegistrationError } from "./lib/errors.js";
5
+
6
+ function resolveSurface(request, explicitSurface = "", defaultSurfaceId = "") {
7
+ return (
8
+ normalizeText(explicitSurface).toLowerCase() ||
9
+ normalizeText(request?.routeOptions?.config?.surface).toLowerCase() ||
10
+ normalizeText(request?.surface).toLowerCase() ||
11
+ resolveDefaultSurfaceId(null, { defaultSurfaceId })
12
+ );
13
+ }
14
+
15
+ function routeVisibility(request, payload = {}) {
16
+ const routeConfig = normalizeObject(request?.routeOptions?.config);
17
+ return normalizeRouteVisibilityToken(
18
+ Object.hasOwn(routeConfig, "visibility")
19
+ ? routeConfig.visibility
20
+ : payload.visibility
21
+ );
22
+ }
23
+
24
+ function attachDirectRequestActionExecutor({
25
+ actions,
26
+ request,
27
+ property = "executeAction",
28
+ defaultChannel = "api",
29
+ defaultSurfaceId = ""
30
+ } = {}) {
31
+ if (!actions || typeof actions.execute !== "function") {
32
+ throw new RouteRegistrationError("Direct request action execution requires the runtime.actions capability.");
33
+ }
34
+ if (!request || typeof request !== "object") {
35
+ return null;
36
+ }
37
+ const propertyName = normalizeText(property) || "executeAction";
38
+ if (typeof request[propertyName] === "function") {
39
+ return request[propertyName];
40
+ }
41
+
42
+ const executeAction = async (payload = {}) => {
43
+ const source = normalizeObject(payload);
44
+ const channel = normalizeText(source.channel || defaultChannel).toLowerCase() || "api";
45
+ const context = Object.freeze({
46
+ ...normalizeObject(source.context),
47
+ channel,
48
+ surface: resolveSurface(request, source.surface, defaultSurfaceId),
49
+ routeVisibility: routeVisibility(request, source),
50
+ requestMeta: Object.freeze({
51
+ ...normalizeObject(source.context?.requestMeta),
52
+ request
53
+ })
54
+ });
55
+
56
+ const actionId = source.actionId;
57
+ const version = source.version == null ? null : source.version;
58
+ const definition = actions.getDefinition(actionId, version);
59
+ const execute = definition.kind === "stream" ? actions.executeStream : actions.execute;
60
+ return execute({
61
+ actionId,
62
+ version,
63
+ input: normalizeObject(source.input),
64
+ context,
65
+ deps: normalizeObject(source.deps)
66
+ });
67
+ };
68
+
69
+ Object.defineProperty(request, propertyName, {
70
+ configurable: true,
71
+ enumerable: false,
72
+ writable: true,
73
+ value: executeAction
74
+ });
75
+ return executeAction;
76
+ }
77
+
78
+ export { attachDirectRequestActionExecutor };
@@ -1 +1,2 @@
1
- export { registerRouteVisibilityResolver } from "../registries/routeVisibilityResolverRegistry.js";
1
+ export { createCapabilityHttpRuntime } from "./capabilityHttpRuntime.js";
2
+ export { HttpProvider } from "./HttpProvider.js";
@@ -2,16 +2,4 @@ export { HttpKernelError, RouteDefinitionError, RouteRegistrationError } from ".
2
2
  export { HttpRouter, createRouter, joinPath } from "./router.js";
3
3
  export { defineRouteValidator, compileRouteValidator, resolveRouteValidatorOptions } from "./routeValidator.js";
4
4
  export { BaseController, DEFAULT_DOMAIN_ERROR_STATUS_BY_CODE, resolveDomainErrorStatus } from "./controller.js";
5
- export {
6
- defaultMissingHandler,
7
- defaultApplyRoutePolicy,
8
- normalizeRoutePolicyConfig,
9
- registerRoutes,
10
- registerHttpRuntime,
11
- createHttpRuntime
12
- } from "./kernel.js";
13
- export {
14
- resolveRouteVisibilityResolvers,
15
- registerRouteVisibilityResolver,
16
- resolveRouteVisibilityContext
17
- } from "../../registries/routeVisibilityResolverRegistry.js";
5
+ export { defaultMissingHandler, registerRoutes } from "./routeRegistration.js";
@@ -6,8 +6,7 @@ import { defaultMissingHandler } from "../../support/defaultMissingHandler.js";
6
6
  import { registerJsonApiContentTypeParser } from "../../runtime/fastifyBootstrap.js";
7
7
  import { RouteRegistrationError } from "./errors.js";
8
8
  import { executeMiddlewareStack, normalizeRuntimeMiddlewareConfig, resolveRouteMiddlewareHandlers } from "./middlewareRuntime.js";
9
- import { attachRequestScope } from "./requestScope.js";
10
- import { attachRequestActionExecutor } from "./requestActionExecutor.js";
9
+ import { attachDirectRequestActionExecutor } from "../directRequestActionExecutor.js";
11
10
  import { normalizeRouteOutputTransform, normalizeRouteTransport } from "./routeTransport.js";
12
11
 
13
12
  const { structuredClone: cloneRouteSchema } = globalThis;
@@ -291,23 +290,21 @@ function registerRoutes(
291
290
  fastify,
292
291
  {
293
292
  routes = [],
294
- app = null,
295
293
  applyRoutePolicy = defaultApplyRoutePolicy,
296
294
  missingHandler = defaultMissingHandler,
297
- enableRequestScope = true,
298
- requestScopeProperty = "scope",
299
295
  requestActionExecutorProperty = "executeAction",
300
- actionExecutorToken = "actionExecutor",
301
296
  requestActionDefaultChannel = "api",
302
297
  requestActionDefaultSurface = "",
303
- requestScopeIdPrefix = "http",
304
- requestIdResolver = null,
305
- middleware = {}
298
+ middleware = {},
299
+ actions = null
306
300
  } = {}
307
301
  ) {
308
302
  if (!fastify || typeof fastify.route !== "function") {
309
303
  throw new RouteRegistrationError("registerRoutes requires a Fastify instance.");
310
304
  }
305
+ if (!actions || typeof actions.execute !== "function") {
306
+ throw new RouteRegistrationError("registerRoutes requires the runtime.actions capability.");
307
+ }
311
308
 
312
309
  const normalizedRoutes = normalizeArray(routes);
313
310
  const publicRoutes = normalizedRoutes.filter((route) => route?.internal !== true);
@@ -353,23 +350,10 @@ function registerRoutes(
353
350
  request.routeOptions.config = normalizeObject(routeOptions?.config);
354
351
  }
355
352
 
356
- if (enableRequestScope) {
357
- attachRequestScope({
358
- app,
359
- request,
360
- reply,
361
- requestScopeProperty,
362
- requestScopeIdPrefix,
363
- requestIdResolver
364
- });
365
- }
366
-
367
- attachRequestActionExecutor({
368
- app,
353
+ attachDirectRequestActionExecutor({
354
+ actions,
369
355
  request,
370
- requestScopeProperty,
371
- requestActionExecutorProperty,
372
- actionExecutorToken,
356
+ property: requestActionExecutorProperty,
373
357
  defaultChannel: requestActionDefaultChannel,
374
358
  defaultSurfaceId: routeActionDefaultSurface
375
359
  });
@@ -1,5 +1,5 @@
1
1
  export {
2
2
  registerSurfaceRequestConstraint,
3
- resolveRuntimeProfileFromSurface,
4
- tryCreateProviderRuntimeFromApp
3
+ resolveRuntimeProfileFromSurface
5
4
  } from "./surfaceRuntime.js";
5
+ export { createInstalledRuntime } from "./installedRuntime.js";
@@ -0,0 +1,122 @@
1
+ import { createActionProvider } from "../actions/actionProvider.js";
2
+ import { createCapabilityRuntime } from "../../shared/capabilities/runtime.js";
3
+ import { HttpProvider } from "../http/HttpProvider.js";
4
+ import { BootstrapProvider } from "../runtime/BootstrapProvider.js";
5
+ import { EventProvider } from "../runtime/EventProvider.js";
6
+ import {
7
+ collectGlobalUiPaths,
8
+ resolveInstalledJskitPackages,
9
+ resolvePackageLoadOrder,
10
+ validatePackageCapabilities
11
+ } from "./providerRuntime/packageCatalog.js";
12
+ import {
13
+ appendCapabilityProviders,
14
+ loadCapabilityProviders
15
+ } from "./providerRuntime/capabilityProviderLoader.js";
16
+
17
+ function normalizeInputCapabilities({ inputs, config, env, logger, fastify, appRoot }) {
18
+ const source = inputs && typeof inputs === "object" && !Array.isArray(inputs) ? inputs : {};
19
+ const normalized = {
20
+ ...source,
21
+ "runtime.app-root": appRoot,
22
+ "runtime.config": Object.freeze({ ...(config && typeof config === "object" ? config : {}) }),
23
+ "runtime.env": Object.freeze({ ...(env && typeof env === "object" ? env : {}) }),
24
+ "runtime.logger": logger || console,
25
+ ...(fastify && typeof fastify.route === "function" ? { "runtime.fastify": fastify } : {})
26
+ };
27
+ return Object.freeze(normalized);
28
+ }
29
+
30
+ function builtinCapabilityProviders(inputCapabilities) {
31
+ return Object.fromEntries([
32
+ ["runtime.actions", ["@jskit-ai/kernel"]],
33
+ ["runtime.events", ["@jskit-ai/kernel"]],
34
+ ...(Object.hasOwn(inputCapabilities, "runtime.fastify")
35
+ ? [
36
+ ["runtime.bootstrap", ["@jskit-ai/kernel"]],
37
+ ["runtime.http", ["@jskit-ai/kernel"]]
38
+ ]
39
+ : []),
40
+ ...Object.keys(inputCapabilities).map((capabilityId) => [capabilityId, ["application"]])
41
+ ]);
42
+ }
43
+
44
+ async function createInstalledRuntime({
45
+ appRoot,
46
+ profile = "",
47
+ providers = [],
48
+ inputs = {},
49
+ config = {},
50
+ env = {},
51
+ logger = console,
52
+ fastify = null
53
+ } = {}) {
54
+ if (!appRoot || typeof appRoot !== "string") {
55
+ throw new TypeError("createInstalledRuntime requires appRoot.");
56
+ }
57
+
58
+ const inputCapabilities = normalizeInputCapabilities({ inputs, config, env, logger, fastify, appRoot });
59
+ const installedPackages = await resolveInstalledJskitPackages({ appRoot });
60
+ validatePackageCapabilities(installedPackages, {
61
+ builtinProvidersByCapability: builtinCapabilityProviders(inputCapabilities)
62
+ });
63
+ const orderedPackages = resolvePackageLoadOrder(installedPackages);
64
+ const orderedProviders = [];
65
+ const seenProviderIds = new Map();
66
+ const providerPackageOrder = [];
67
+
68
+ appendCapabilityProviders({
69
+ providers: [
70
+ EventProvider,
71
+ createActionProvider({ logger }),
72
+ ...(fastify && typeof fastify.route === "function" ? [HttpProvider, BootstrapProvider] : [])
73
+ ],
74
+ sourceId: "@jskit-ai/kernel",
75
+ seenProviderIds,
76
+ orderedProviders
77
+ });
78
+
79
+ for (const packageEntry of orderedPackages) {
80
+ const packageProviders = await loadCapabilityProviders({ packageEntry });
81
+ if (packageProviders.length === 0) {
82
+ continue;
83
+ }
84
+ providerPackageOrder.push(packageEntry.packageId);
85
+ appendCapabilityProviders({
86
+ providers: packageProviders,
87
+ sourceId: packageEntry.packageId,
88
+ seenProviderIds,
89
+ orderedProviders
90
+ });
91
+ }
92
+
93
+ appendCapabilityProviders({
94
+ providers: Array.isArray(providers) ? providers : [],
95
+ sourceId: "application",
96
+ seenProviderIds,
97
+ orderedProviders
98
+ });
99
+
100
+ const runtime = createCapabilityRuntime({
101
+ providers: orderedProviders,
102
+ inputs: inputCapabilities,
103
+ profile
104
+ });
105
+ await runtime.start();
106
+
107
+ if (fastify && typeof fastify.addHook === "function") {
108
+ fastify.addHook("onClose", async () => {
109
+ await runtime.shutdown();
110
+ });
111
+ }
112
+
113
+ return Object.freeze({
114
+ runtime,
115
+ packageOrder: Object.freeze(orderedPackages.map((entry) => entry.packageId)),
116
+ providerPackageOrder: Object.freeze(providerPackageOrder),
117
+ globalUiPaths: collectGlobalUiPaths(orderedPackages),
118
+ diagnostics: runtime.diagnostics()
119
+ });
120
+ }
121
+
122
+ export { createInstalledRuntime };