@telorun/kernel 0.2.5 → 0.2.7

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 (138) hide show
  1. package/dist/base-definition.d.ts +14 -0
  2. package/dist/base-definition.d.ts.map +1 -0
  3. package/dist/base-definition.js +17 -0
  4. package/dist/base-definition.js.map +1 -0
  5. package/dist/capabilities/component.d.ts +3 -0
  6. package/dist/capabilities/component.d.ts.map +1 -0
  7. package/dist/capabilities/component.js +4 -0
  8. package/dist/capabilities/component.js.map +1 -0
  9. package/dist/capabilities/executable.d.ts +3 -0
  10. package/dist/capabilities/executable.d.ts.map +1 -0
  11. package/dist/capabilities/executable.js +5 -0
  12. package/dist/capabilities/executable.js.map +1 -0
  13. package/dist/capabilities/handler.d.ts +3 -0
  14. package/dist/capabilities/handler.d.ts.map +1 -0
  15. package/dist/capabilities/handler.js +4 -0
  16. package/dist/capabilities/handler.js.map +1 -0
  17. package/dist/capabilities/invokable.d.ts +3 -0
  18. package/dist/capabilities/invokable.d.ts.map +1 -0
  19. package/dist/capabilities/invokable.js +5 -0
  20. package/dist/capabilities/invokable.js.map +1 -0
  21. package/dist/capabilities/listener.d.ts +3 -0
  22. package/dist/capabilities/listener.d.ts.map +1 -0
  23. package/dist/capabilities/listener.js +5 -0
  24. package/dist/capabilities/listener.js.map +1 -0
  25. package/dist/capabilities/mount.d.ts +3 -0
  26. package/dist/capabilities/mount.d.ts.map +1 -0
  27. package/dist/capabilities/mount.js +5 -0
  28. package/dist/capabilities/mount.js.map +1 -0
  29. package/dist/capabilities/provider.d.ts +3 -0
  30. package/dist/capabilities/provider.d.ts.map +1 -0
  31. package/dist/capabilities/provider.js +8 -0
  32. package/dist/capabilities/provider.js.map +1 -0
  33. package/dist/capabilities/runnable.d.ts +3 -0
  34. package/dist/capabilities/runnable.d.ts.map +1 -0
  35. package/dist/capabilities/runnable.js +5 -0
  36. package/dist/capabilities/runnable.js.map +1 -0
  37. package/dist/capabilities/service.d.ts +3 -0
  38. package/dist/capabilities/service.d.ts.map +1 -0
  39. package/dist/capabilities/service.js +5 -0
  40. package/dist/capabilities/service.js.map +1 -0
  41. package/dist/capabilities/template.d.ts +3 -0
  42. package/dist/capabilities/template.d.ts.map +1 -0
  43. package/dist/capabilities/template.js +5 -0
  44. package/dist/capabilities/template.js.map +1 -0
  45. package/dist/capabilities/type.d.ts +3 -0
  46. package/dist/capabilities/type.d.ts.map +1 -0
  47. package/dist/capabilities/type.js +5 -0
  48. package/dist/capabilities/type.js.map +1 -0
  49. package/dist/controller-loader.d.ts.map +1 -1
  50. package/dist/controller-loader.js +2 -1
  51. package/dist/controller-loader.js.map +1 -1
  52. package/dist/controller-registry.d.ts +0 -4
  53. package/dist/controller-registry.d.ts.map +1 -1
  54. package/dist/controller-registry.js +11 -22
  55. package/dist/controller-registry.js.map +1 -1
  56. package/dist/controllers/capability/capability-controller.d.ts +0 -5
  57. package/dist/controllers/capability/capability-controller.d.ts.map +1 -1
  58. package/dist/controllers/capability/capability-controller.js +1 -5
  59. package/dist/controllers/capability/capability-controller.js.map +1 -1
  60. package/dist/controllers/module/import-controller.d.ts +0 -3
  61. package/dist/controllers/module/import-controller.d.ts.map +1 -1
  62. package/dist/controllers/module/import-controller.js +21 -27
  63. package/dist/controllers/module/import-controller.js.map +1 -1
  64. package/dist/controllers/module/module-controller.d.ts +0 -59
  65. package/dist/controllers/module/module-controller.d.ts.map +1 -1
  66. package/dist/controllers/module/module-controller.js +0 -45
  67. package/dist/controllers/module/module-controller.js.map +1 -1
  68. package/dist/controllers/resource-definition/resource-definition-controller.d.ts +3 -4
  69. package/dist/controllers/resource-definition/resource-definition-controller.d.ts.map +1 -1
  70. package/dist/controllers/resource-definition/resource-definition-controller.js +6 -8
  71. package/dist/controllers/resource-definition/resource-definition-controller.js.map +1 -1
  72. package/dist/controllers/resource-definition/resource-template-controller.d.ts +12 -0
  73. package/dist/controllers/resource-definition/resource-template-controller.d.ts.map +1 -0
  74. package/dist/controllers/resource-definition/resource-template-controller.js +112 -0
  75. package/dist/controllers/resource-definition/resource-template-controller.js.map +1 -0
  76. package/dist/index.d.ts +2 -2
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +0 -1
  79. package/dist/index.js.map +1 -1
  80. package/dist/kernel.d.ts +38 -24
  81. package/dist/kernel.d.ts.map +1 -1
  82. package/dist/kernel.js +296 -201
  83. package/dist/kernel.js.map +1 -1
  84. package/dist/loader.d.ts +9 -8
  85. package/dist/loader.d.ts.map +1 -1
  86. package/dist/loader.js +50 -132
  87. package/dist/loader.js.map +1 -1
  88. package/dist/manifest-adapters/http-adapter.d.ts.map +1 -1
  89. package/dist/manifest-adapters/http-adapter.js +3 -1
  90. package/dist/manifest-adapters/http-adapter.js.map +1 -1
  91. package/dist/manifest-adapters/local-file-adapter.d.ts +7 -5
  92. package/dist/manifest-adapters/local-file-adapter.d.ts.map +1 -1
  93. package/dist/manifest-adapters/local-file-adapter.js +21 -26
  94. package/dist/manifest-adapters/local-file-adapter.js.map +1 -1
  95. package/dist/manifest-adapters/manifest-adapter.d.ts +2 -0
  96. package/dist/manifest-adapters/manifest-adapter.d.ts.map +1 -1
  97. package/dist/manifest-adapters/registry-adapter.d.ts.map +1 -1
  98. package/dist/manifest-adapters/registry-adapter.js +3 -1
  99. package/dist/manifest-adapters/registry-adapter.js.map +1 -1
  100. package/dist/manifest-schemas.d.ts +61 -25
  101. package/dist/manifest-schemas.d.ts.map +1 -1
  102. package/dist/manifest-schemas.js +56 -16
  103. package/dist/manifest-schemas.js.map +1 -1
  104. package/dist/resource-context.d.ts +11 -10
  105. package/dist/resource-context.d.ts.map +1 -1
  106. package/dist/resource-context.js +70 -25
  107. package/dist/resource-context.js.map +1 -1
  108. package/dist/schema-valiator.d.ts +6 -1
  109. package/dist/schema-valiator.d.ts.map +1 -1
  110. package/dist/schema-valiator.js +76 -4
  111. package/dist/schema-valiator.js.map +1 -1
  112. package/package.json +6 -7
  113. package/src/controller-loader.ts +2 -1
  114. package/src/controller-registry.ts +11 -26
  115. package/src/controllers/module/import-controller.ts +30 -30
  116. package/src/controllers/module/module-controller.ts +0 -51
  117. package/src/controllers/resource-definition/resource-definition-controller.ts +14 -15
  118. package/src/controllers/resource-definition/resource-template-controller.ts +138 -0
  119. package/src/index.ts +2 -2
  120. package/src/kernel.ts +364 -226
  121. package/src/manifest-adapters/local-file-adapter.ts +24 -31
  122. package/src/manifest-adapters/manifest-adapter.ts +2 -0
  123. package/src/manifest-schemas.ts +60 -24
  124. package/src/resource-context.ts +90 -35
  125. package/src/schema-valiator.ts +90 -13
  126. package/src/capabilities/component.yaml +0 -4
  127. package/src/capabilities/executable.yaml +0 -8
  128. package/src/capabilities/handler.yaml +0 -4
  129. package/src/capabilities/listener.yaml +0 -4
  130. package/src/capabilities/provider.yaml +0 -4
  131. package/src/capabilities/template.yaml +0 -4
  132. package/src/capabilities/type.yaml +0 -4
  133. package/src/controllers/capability/capability-controller.ts +0 -41
  134. package/src/controllers/module/module.json +0 -48
  135. package/src/controllers/module/module.yaml +0 -32
  136. package/src/loader.ts +0 -245
  137. package/src/manifest-adapters/http-adapter.ts +0 -35
  138. package/src/manifest-adapters/registry-adapter.ts +0 -56
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/kernel",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Telo Runtime - A lightweight, polyglot execution host.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -27,19 +27,18 @@
27
27
  "@sinclair/typebox": "^0.34.48",
28
28
  "ajv": "^8.17.1",
29
29
  "ajv-formats": "^3.0.1",
30
- "cel-js": "^0.8.2",
31
- "js-yaml": "^4.1.0",
30
+ "@marcbachmann/cel-js": "^7.5.3",
32
31
  "packageurl-js": "^2.0.1",
33
- "@telorun/sdk": "0.2.5",
34
- "@telorun/yaml-cel-templating": "1.0.2"
32
+ "@telorun/analyzer": "0.1.2",
33
+ "@telorun/sdk": "0.2.7",
34
+ "@telorun/yaml-cel-templating": "1.0.3"
35
35
  },
36
36
  "devDependencies": {
37
- "@types/js-yaml": "^4.0.5",
38
37
  "@types/node": "^20.0.0",
39
38
  "typescript": "^5.0.0"
40
39
  },
41
40
  "scripts": {
42
- "build": "tsc && cp -r src/capabilities dist/capabilities",
41
+ "build": "tsc",
43
42
  "dev": "tsc --watch"
44
43
  }
45
44
  }
@@ -39,7 +39,8 @@ export class ControllerLoader {
39
39
  const isLocalManifest =
40
40
  baseUri && !baseUri.startsWith("http://") && !baseUri.startsWith("https://");
41
41
  if (localPath && isLocalManifest) {
42
- const manifestDir = path.dirname(baseUri);
42
+ const baseUriPath = baseUri.startsWith("file://") ? baseUri.slice("file://".length) : baseUri;
43
+ const manifestDir = path.dirname(baseUriPath);
43
44
  const resolvedLocalPath = path.resolve(manifestDir, localPath);
44
45
  if (await this.pathExists(resolvedLocalPath)) {
45
46
  packageRoot = resolvedLocalPath;
@@ -9,20 +9,6 @@ export class ControllerRegistry {
9
9
  private controllersByKind: Map<string, ControllerInstance> = new Map();
10
10
  private definitionsByKind: Map<string, ResourceDefinition> = new Map();
11
11
  private controllerLoaders: Map<string, () => Promise<ControllerInstance>> = new Map();
12
- private capabilitySchemas: Map<string, Record<string, any> | null> = new Map();
13
-
14
- registerCapability(name: string, schema?: Record<string, any>): void {
15
- this.capabilitySchemas.set(name, schema ?? null);
16
- }
17
-
18
- isCapabilityRegistered(name: string): boolean {
19
- return this.capabilitySchemas.has(name);
20
- }
21
-
22
- getCapabilitySchema(name: string): Record<string, any> | null | undefined {
23
- return this.capabilitySchemas.get(name);
24
- }
25
-
26
12
  /**
27
13
  * Register a controller definition
28
14
  */
@@ -64,8 +50,10 @@ export class ControllerRegistry {
64
50
  // this.controllersByKind.set(kind, controller);
65
51
  // return controller;
66
52
  // }
67
-
68
- throw new Error(`No controller registered for kind: ${kind}`);
53
+ return {
54
+ schema: { type: "object", additionalProperties: false },
55
+ };
56
+ // throw new Error(`No controller registered for kind: ${kind}`);
69
57
  }
70
58
 
71
59
  /**
@@ -124,16 +112,13 @@ export class ControllerRegistry {
124
112
  }
125
113
  // Ensure controller has schema from definition
126
114
  const definition = this.definitionsByKind.get(kind);
127
- if (definition?.schema && !controller.schema) {
128
- // Wrap controller to add schema without mutating the original
129
- const wrappedController: ControllerInstance = {
130
- ...controller,
131
- schema: definition.schema,
132
- };
133
- this.controllersByKind.set(kind, wrappedController);
134
- } else {
135
- this.controllersByKind.set(kind, controller);
136
- }
115
+ const wrappedController: ControllerInstance = {
116
+ ...controller,
117
+ schema: controller.schema ?? definition?.schema,
118
+ inputType: controller.inputType,
119
+ outputType: controller.outputType,
120
+ };
121
+ this.controllersByKind.set(kind, wrappedController);
137
122
  }
138
123
 
139
124
  /**
@@ -1,20 +1,37 @@
1
+ import { DiagnosticSeverity, Loader, StaticAnalyzer } from "@telorun/analyzer";
1
2
  import type { ResourceContext, ResourceInstance } from "@telorun/sdk";
2
- import { EvaluationContext } from "@telorun/sdk";
3
- import { Loader } from "../../loader.js";
3
+ import { EvaluationContext, RuntimeError } from "@telorun/sdk";
4
+ import { LocalFileAdapter } from "../../manifest-adapters/local-file-adapter.js";
4
5
 
5
6
  export async function create(resource: any, ctx: ResourceContext): Promise<ResourceInstance> {
6
7
  const alias = resource.metadata.name as string;
7
- const declaringModule: string = resource.metadata.module ?? "default";
8
- const loader = new Loader();
8
+ const loader = new Loader([new LocalFileAdapter()]);
9
9
 
10
- // Load target module manifests. Inject variables/secrets as compile context so that
11
- // ${{ variables.x }} / ${{ secrets.y }} templates in the child module resolve correctly.
10
+ const moduleSource: string = resource.module ?? resource.source;
11
+
12
+ // Validate the imported module and all its transitive imports before loading for runtime.
13
+ // loadManifests() follows Kernel.Import chains so definitions from sub-imports are present,
14
+ // preventing false UNDEFINED_KIND errors for kinds that come from the module's own imports.
15
+ const resolvedUrl = new URL(moduleSource, ctx.moduleContext.source).toString();
16
+ const analysisManifests = await loader.loadManifests(resolvedUrl);
17
+ const diagnostics = new StaticAnalyzer().analyze(analysisManifests);
18
+ const errors = diagnostics.filter((d) => d.severity === DiagnosticSeverity.Error);
19
+ if (errors.length > 0) {
20
+ throw new RuntimeError(
21
+ "ERR_MANIFEST_VALIDATION_FAILED",
22
+ errors.map((d) => d.message).join("\n"),
23
+ );
24
+ }
25
+
26
+ // Load target module manifests for runtime. Inject variables/secrets as compile context so
27
+ // that ${{ variables.x }} / ${{ secrets.y }} templates in the child module resolve correctly.
12
28
  // No env — child modules are isolated from host environment.
13
- const manifests = await loader.loadManifest(resource.source as string, ctx.moduleContext.source, {
14
- // Potentially not needed
15
- variables: (resource.variables as Record<string, unknown>) ?? {},
16
- secrets: (resource.secrets as Record<string, unknown>) ?? {},
17
- });
29
+ const manifests = await loader.loadModule(
30
+ new URL(moduleSource, ctx.moduleContext.source).toString(),
31
+ {
32
+ compile: true,
33
+ },
34
+ );
18
35
  // Find the kind: Module manifest to learn the target module name and contract.
19
36
  const moduleManifest = manifests.find((m: any) => m.kind === "Kernel.Module");
20
37
  if (!moduleManifest) {
@@ -22,22 +39,6 @@ export async function create(resource: any, ctx: ResourceContext): Promise<Resou
22
39
  }
23
40
  const targetModule: string = moduleManifest.metadata.name;
24
41
 
25
- // Validate that every non-module manifest's metadata.module (when explicitly set)
26
- // matches the target module name. A mismatch means the author put the wrong module
27
- // name in a resource's metadata, which would silently give it an empty context and
28
- // produce a confusing CEL "Identifier not found" error at runtime.
29
- for (const manifest of manifests) {
30
- if (manifest.kind === "Kernel.Module") continue;
31
- const declaredModule: string | undefined = manifest.metadata?.module;
32
- if (declaredModule && declaredModule !== targetModule) {
33
- throw new Error(
34
- `Resource '${manifest.metadata?.name ?? "(unnamed)"}' (kind: ${manifest.kind}) inside module '${targetModule}' ` +
35
- `has metadata.module: '${declaredModule}', but the module is named '${targetModule}'. ` +
36
- `Update metadata.module to '${targetModule}'.`,
37
- );
38
- }
39
- }
40
-
41
42
  // Validate required inputs before injecting.
42
43
  validateRequiredInputs(moduleManifest.variables ?? {}, resource.variables ?? {}, "variables");
43
44
  validateRequiredInputs(moduleManifest.secrets ?? {}, resource.secrets ?? {}, "secrets");
@@ -82,8 +83,8 @@ export async function create(resource: any, ctx: ResourceContext): Promise<Resou
82
83
  // in the declaring module's evaluation context — no separate imports namespace needed.
83
84
  return {
84
85
  snapshot: () => ({
85
- variables: (resource.variables as Record<string, unknown>) ?? {},
86
- secrets: (resource.secrets as Record<string, unknown>) ?? {},
86
+ variables: ctx.expandValue(resource.variables, {}) ?? {},
87
+ secrets: ctx.expandValue(resource.secrets, {}) ?? {},
87
88
  }),
88
89
  run: async () => {
89
90
  // Proxy run to target module
@@ -128,7 +129,6 @@ export const schema = {
128
129
  type: "object",
129
130
  properties: {
130
131
  name: { type: "string" },
131
- source: { type: "string" },
132
132
  module: { type: "string" },
133
133
  },
134
134
  required: ["name"],
@@ -1,27 +1,6 @@
1
1
  import type { ResourceContext, ResourceInstance } from "@telorun/sdk";
2
- import { Loader } from "../../loader.js";
3
2
 
4
3
  export async function create(resource: any, ctx: ResourceContext): Promise<ResourceInstance> {
5
- const moduleName = resource.metadata.name as string;
6
- const loader = new Loader();
7
-
8
- for (const includePath of (resource.include as string[]) ?? []) {
9
- const manifests = await loader.loadManifest(
10
- includePath,
11
- resource.metadata.source as string,
12
- {},
13
- );
14
- for (const manifest of manifests) {
15
- if (manifest.kind === "Kernel.Module") {
16
- throw new Error(`Included file "${includePath}" must not declare kind: Module`);
17
- }
18
- if (!manifest.metadata.module) {
19
- manifest.metadata.module = moduleName;
20
- }
21
- ctx.registerManifest(manifest);
22
- }
23
- }
24
-
25
4
  return {
26
5
  run: async () => {
27
6
  for (const target of (resource.targets as string[]) ?? []) {
@@ -35,33 +14,3 @@ export async function create(resource: any, ctx: ResourceContext): Promise<Resou
35
14
  };
36
15
  }
37
16
 
38
- export const schema = {
39
- type: "object",
40
- properties: {
41
- kind: { type: "string" },
42
- metadata: {
43
- type: "object",
44
- properties: {
45
- name: { type: "string" },
46
- version: { type: "string" },
47
- source: { type: "string" },
48
- module: { type: "string" },
49
- },
50
- required: ["name"],
51
- additionalProperties: true,
52
- },
53
- include: { type: "array", items: { type: "string" } },
54
- variables: { type: "object" },
55
- secrets: { type: "object" },
56
- targets: { type: "array", items: { type: "string" } },
57
- exports: {
58
- type: "object",
59
- properties: {
60
- kinds: { type: "array", items: { type: "string" } },
61
- },
62
- additionalProperties: true,
63
- },
64
- },
65
- required: ["metadata"],
66
- additionalProperties: false,
67
- };
@@ -6,18 +6,18 @@ import type {
6
6
  } from "@telorun/sdk";
7
7
  import { ControllerLoader } from "../../controller-loader.js";
8
8
  import { formatAjvErrors, validateResourceDefinition } from "../../manifest-schemas.js";
9
+ import { createTemplateController } from "./resource-template-controller.js";
9
10
 
10
11
  type ResourceDefinitionResource = RuntimeResource & {
11
- kind: "Definition";
12
+ kind: "Kernel.Definition";
12
13
  metadata: {
13
14
  [key: string]: any;
14
15
  name: string;
15
16
  module?: string;
16
17
  };
17
18
  schema: Record<string, any>;
18
- capabilities: string[];
19
- events?: string[];
20
- controllers: Array<string>;
19
+ capability?: string;
20
+ controllers?: Array<string>;
21
21
  };
22
22
 
23
23
  /**
@@ -33,16 +33,15 @@ class ResourceDefinition implements ResourceInstance {
33
33
  ) {}
34
34
 
35
35
  async init(ctx: ResourceContext) {
36
- for (const cap of this.resource.capabilities) {
37
- if (!ctx.isCapabilityRegistered(cap)) {
38
- throw new Error(
39
- `Capability "${cap}" is not registered. Declare it as a Kernel.Capability resource.`,
40
- );
41
- }
42
- const capSchema = ctx.getCapabilitySchema(cap);
43
- if (capSchema) {
44
- ctx.validateSchema(this.resource, capSchema);
45
- }
36
+ if (!this.resource.controllers?.length) {
37
+ const controllerInstance = createTemplateController(this.resource as any);
38
+ ctx.registerDefinition(this.resource);
39
+ await ctx.registerController(
40
+ this.resource.metadata.module,
41
+ this.resource.metadata.name,
42
+ controllerInstance,
43
+ );
44
+ return;
46
45
  }
47
46
  ctx.emit("ControllerLoading", { controllers: this.resource.controllers });
48
47
  try {
@@ -77,7 +76,7 @@ export async function create(resource: any, ctx: ResourceContext): Promise<Resou
77
76
  }
78
77
 
79
78
  // Return a fully-formed ResourceDefinition instance
80
- const definition = resource as ResourceDefinitionResource;
79
+ const definition = resource as unknown as ResourceDefinitionResource;
81
80
  return new ResourceDefinition(definition, new ControllerLoader());
82
81
  }
83
82
 
@@ -0,0 +1,138 @@
1
+ import type { ControllerInstance, ResourceContext, ResourceInstance } from "@telorun/sdk";
2
+ import { isCompiledValue } from "@telorun/sdk";
3
+
4
+ export function createTemplateController(definition: {
5
+ schema: Record<string, any>;
6
+ resources?: any[];
7
+ invoke?: string | { kind?: string; name: string; inputs?: Record<string, any> };
8
+ run?: string;
9
+ }): ControllerInstance {
10
+ return {
11
+ schema: definition.schema ?? { type: "object", additionalProperties: true },
12
+
13
+ create: async (resource: any, ctx: ResourceContext): Promise<ResourceInstance> => {
14
+ const self = { ...resource, name: resource.metadata.name };
15
+
16
+ // Old string form: invoke is a plain string or a CompiledValue (after precompile).
17
+ // New object form: invoke is a plain object (non-CompiledValue) with at least `name`.
18
+ const objectInvoke =
19
+ definition.invoke !== null &&
20
+ typeof definition.invoke === "object" &&
21
+ !isCompiledValue(definition.invoke)
22
+ ? (definition.invoke as { kind?: string; name: string; inputs?: Record<string, any> })
23
+ : null;
24
+ const invokeNameTemplate = objectInvoke ? objectInvoke.name : (definition.invoke ?? null);
25
+ const invokeTarget = invokeNameTemplate
26
+ ? (ctx.moduleContext.expandWith(invokeNameTemplate, { self }) as string)
27
+ : null;
28
+ const runTarget = definition.run
29
+ ? (ctx.moduleContext.expandWith(definition.run, { self }) as string)
30
+ : null;
31
+
32
+ const persistentManifests: any[] = [];
33
+ let ephemeralTemplate: any = null;
34
+
35
+ for (const template of definition.resources ?? []) {
36
+ const expandedName = ctx.moduleContext.expandWith(template.metadata?.name ?? "", {
37
+ self,
38
+ }) as string;
39
+ const isTarget = expandedName === invokeTarget || expandedName === runTarget;
40
+ if (isTarget) {
41
+ ephemeralTemplate = template;
42
+ } else {
43
+ persistentManifests.push(ctx.moduleContext.expandWith(template, { self }));
44
+ }
45
+ }
46
+
47
+ const childContext = ctx.spawnChildContext();
48
+
49
+ // Registers an ephemeral manifest on ctx.moduleContext so it shares the same
50
+ // resource scope (and can access connections, etc. via getInstance).
51
+ // Tears down and removes the resource after fn() completes.
52
+ const withEphemeral = async (expandedManifest: any, fn: (name: string) => Promise<any>) => {
53
+ const uniqueName = `${expandedManifest.metadata?.name ?? "eph"}__${Math.random().toString(16).slice(2, 8)}`;
54
+ const manifest = {
55
+ ...expandedManifest,
56
+ metadata: {
57
+ ...expandedManifest.metadata,
58
+ name: uniqueName,
59
+ module: resource.metadata.module,
60
+ },
61
+ };
62
+ ctx.moduleContext.registerManifest(manifest);
63
+ await ctx.moduleContext.initializeResources();
64
+ const entry = ctx.moduleContext.resourceInstances.get(uniqueName);
65
+ try {
66
+ return await fn(uniqueName);
67
+ } finally {
68
+ if (entry?.instance?.teardown) await entry.instance.teardown();
69
+ ctx.moduleContext.resourceInstances.delete(uniqueName);
70
+ }
71
+ };
72
+
73
+ return {
74
+ init: async () => {
75
+ for (const m of persistentManifests) childContext.registerManifest(m);
76
+ await childContext.initializeResources();
77
+ },
78
+
79
+ ...(invokeTarget && {
80
+ invoke: async (inputs: any) => {
81
+ if (!ephemeralTemplate) {
82
+ throw new Error(
83
+ `Template '${resource.metadata.name}': no ephemeral resource for invoke target '${invokeTarget}'`,
84
+ );
85
+ }
86
+ const extraContext = { self, inputs };
87
+ const expanded = ctx.moduleContext.expandWith(
88
+ ctx.moduleContext.expandWith(ephemeralTemplate, extraContext),
89
+ extraContext,
90
+ ) as any;
91
+ return withEphemeral(expanded, async (name) => {
92
+ const entry = ctx.moduleContext.resourceInstances.get(name);
93
+ if (!entry?.instance?.invoke) {
94
+ throw new Error(`Ephemeral resource '${name}' is not invocable`);
95
+ }
96
+ // New object form: expand objectInvoke.inputs with invoke context and pass as arg.
97
+ // Old string form: the manifest inputs were computed during template expansion;
98
+ // pass expanded.inputs so Sql.Exec/Query controllers receive { sql, bindings }.
99
+ const invokeInputs = objectInvoke?.inputs != null
100
+ ? ctx.moduleContext.expandWith(
101
+ ctx.moduleContext.expandWith(objectInvoke.inputs, extraContext),
102
+ extraContext,
103
+ )
104
+ : expanded.inputs ?? inputs;
105
+ return entry.instance.invoke(invokeInputs);
106
+ });
107
+ },
108
+ }),
109
+
110
+ ...(runTarget && {
111
+ run: async () => {
112
+ if (!ephemeralTemplate) {
113
+ throw new Error(
114
+ `Template '${resource.metadata.name}': no ephemeral resource for run target '${runTarget}'`,
115
+ );
116
+ }
117
+ const extraContext = { self };
118
+ const expanded = ctx.moduleContext.expandWith(
119
+ ctx.moduleContext.expandWith(ephemeralTemplate, extraContext),
120
+ extraContext,
121
+ );
122
+ return withEphemeral(expanded, async (name) => {
123
+ const entry = ctx.moduleContext.resourceInstances.get(name);
124
+ if (!entry?.instance?.run) {
125
+ throw new Error(`Ephemeral resource '${name}' is not runnable`);
126
+ }
127
+ return entry.instance.run();
128
+ });
129
+ },
130
+ }),
131
+
132
+ teardown: async () => {
133
+ await childContext.teardownResources();
134
+ },
135
+ };
136
+ },
137
+ };
138
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { ControllerRegistry } from "./controller-registry.js";
2
2
  export { EventStream } from "./event-stream.js";
3
- export { Kernel } from "./kernel.js";
4
- export { Loader } from "./loader.js";
3
+ export { Kernel, type KernelOptions } from "./kernel.js";
5
4
  export { ManifestRegistry as Registry } from "./registry.js";
6
5
  export { ResourceURI } from "./resource-uri.js";
6
+ export type { RuntimeDiagnostic } from "@telorun/sdk";
7
7