@telorun/kernel 0.13.2 → 0.15.0

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 (122) hide show
  1. package/dist/application-env.d.ts +1 -0
  2. package/dist/application-env.d.ts.map +1 -1
  3. package/dist/application-env.js +59 -1
  4. package/dist/application-env.js.map +1 -1
  5. package/dist/base-definition.d.ts +14 -0
  6. package/dist/base-definition.d.ts.map +1 -0
  7. package/dist/base-definition.js +17 -0
  8. package/dist/base-definition.js.map +1 -0
  9. package/dist/capabilities/capabilities/component.yaml +4 -0
  10. package/dist/capabilities/capabilities/executable.yaml +8 -0
  11. package/dist/capabilities/capabilities/handler.yaml +4 -0
  12. package/dist/capabilities/capabilities/listener.yaml +4 -0
  13. package/dist/capabilities/capabilities/provider.yaml +4 -0
  14. package/dist/capabilities/capabilities/template.yaml +4 -0
  15. package/dist/capabilities/capabilities/type.yaml +4 -0
  16. package/dist/capabilities/component.d.ts +3 -0
  17. package/dist/capabilities/component.d.ts.map +1 -0
  18. package/dist/capabilities/component.js +4 -0
  19. package/dist/capabilities/component.js.map +1 -0
  20. package/dist/capabilities/component.yaml +3 -0
  21. package/dist/capabilities/executable.d.ts +3 -0
  22. package/dist/capabilities/executable.d.ts.map +1 -0
  23. package/dist/capabilities/executable.js +5 -0
  24. package/dist/capabilities/executable.js.map +1 -0
  25. package/dist/capabilities/executable.yaml +7 -0
  26. package/dist/capabilities/handler.d.ts +3 -0
  27. package/dist/capabilities/handler.d.ts.map +1 -0
  28. package/dist/capabilities/handler.js +4 -0
  29. package/dist/capabilities/handler.js.map +1 -0
  30. package/dist/capabilities/handler.yaml +3 -0
  31. package/dist/capabilities/invokable.d.ts +3 -0
  32. package/dist/capabilities/invokable.d.ts.map +1 -0
  33. package/dist/capabilities/invokable.js +5 -0
  34. package/dist/capabilities/invokable.js.map +1 -0
  35. package/dist/capabilities/listener.d.ts +3 -0
  36. package/dist/capabilities/listener.d.ts.map +1 -0
  37. package/dist/capabilities/listener.js +5 -0
  38. package/dist/capabilities/listener.js.map +1 -0
  39. package/dist/capabilities/listener.yaml +3 -0
  40. package/dist/capabilities/mount.d.ts +3 -0
  41. package/dist/capabilities/mount.d.ts.map +1 -0
  42. package/dist/capabilities/mount.js +5 -0
  43. package/dist/capabilities/mount.js.map +1 -0
  44. package/dist/capabilities/provider.d.ts +3 -0
  45. package/dist/capabilities/provider.d.ts.map +1 -0
  46. package/dist/capabilities/provider.js +8 -0
  47. package/dist/capabilities/provider.js.map +1 -0
  48. package/dist/capabilities/provider.yaml +3 -0
  49. package/dist/capabilities/runnable.d.ts +3 -0
  50. package/dist/capabilities/runnable.d.ts.map +1 -0
  51. package/dist/capabilities/runnable.js +5 -0
  52. package/dist/capabilities/runnable.js.map +1 -0
  53. package/dist/capabilities/service.d.ts +3 -0
  54. package/dist/capabilities/service.d.ts.map +1 -0
  55. package/dist/capabilities/service.js +5 -0
  56. package/dist/capabilities/service.js.map +1 -0
  57. package/dist/capabilities/template.d.ts +3 -0
  58. package/dist/capabilities/template.d.ts.map +1 -0
  59. package/dist/capabilities/template.js +5 -0
  60. package/dist/capabilities/template.js.map +1 -0
  61. package/dist/capabilities/template.yaml +3 -0
  62. package/dist/capabilities/type.d.ts +3 -0
  63. package/dist/capabilities/type.d.ts.map +1 -0
  64. package/dist/capabilities/type.js +5 -0
  65. package/dist/capabilities/type.js.map +1 -0
  66. package/dist/capabilities/type.yaml +3 -0
  67. package/dist/controllers/capability/capability-controller.d.ts +32 -0
  68. package/dist/controllers/capability/capability-controller.d.ts.map +1 -0
  69. package/dist/controllers/capability/capability-controller.js +26 -0
  70. package/dist/controllers/capability/capability-controller.js.map +1 -0
  71. package/dist/controllers/module/module.json +48 -0
  72. package/dist/kernel.d.ts.map +1 -1
  73. package/dist/kernel.js +23 -15
  74. package/dist/kernel.js.map +1 -1
  75. package/dist/loader.d.ts +18 -0
  76. package/dist/loader.d.ts.map +1 -0
  77. package/dist/loader.js +127 -0
  78. package/dist/loader.js.map +1 -0
  79. package/dist/manifest-adapters/http-adapter.d.ts +8 -0
  80. package/dist/manifest-adapters/http-adapter.d.ts.map +1 -0
  81. package/dist/manifest-adapters/http-adapter.js +31 -0
  82. package/dist/manifest-adapters/http-adapter.js.map +1 -0
  83. package/dist/manifest-adapters/local-file-adapter.d.ts +15 -0
  84. package/dist/manifest-adapters/local-file-adapter.d.ts.map +1 -0
  85. package/dist/manifest-adapters/local-file-adapter.js +95 -0
  86. package/dist/manifest-adapters/local-file-adapter.js.map +1 -0
  87. package/dist/manifest-adapters/manifest-adapter.d.ts +35 -0
  88. package/dist/manifest-adapters/manifest-adapter.d.ts.map +1 -0
  89. package/dist/manifest-adapters/manifest-adapter.js +2 -0
  90. package/dist/manifest-adapters/manifest-adapter.js.map +1 -0
  91. package/dist/manifest-adapters/registry-adapter.d.ts +9 -0
  92. package/dist/manifest-adapters/registry-adapter.d.ts.map +1 -0
  93. package/dist/manifest-adapters/registry-adapter.js +48 -0
  94. package/dist/manifest-adapters/registry-adapter.js.map +1 -0
  95. package/dist/module-context-registry.d.ts +48 -0
  96. package/dist/module-context-registry.d.ts.map +1 -0
  97. package/dist/module-context-registry.js +91 -0
  98. package/dist/module-context-registry.js.map +1 -0
  99. package/dist/module-context.d.ts +11 -5
  100. package/dist/module-context.d.ts.map +1 -1
  101. package/dist/module-context.js +49 -4
  102. package/dist/module-context.js.map +1 -1
  103. package/dist/schema-valiator.d.ts +15 -0
  104. package/dist/schema-valiator.d.ts.map +1 -0
  105. package/dist/schema-valiator.js +127 -0
  106. package/dist/schema-valiator.js.map +1 -0
  107. package/dist/schema-validator.d.ts.map +1 -1
  108. package/dist/schema-validator.js +1 -0
  109. package/dist/schema-validator.js.map +1 -1
  110. package/dist/snapshot-serializer.d.ts +62 -0
  111. package/dist/snapshot-serializer.d.ts.map +1 -0
  112. package/dist/snapshot-serializer.js +164 -0
  113. package/dist/snapshot-serializer.js.map +1 -0
  114. package/dist/types.d.ts +65 -0
  115. package/dist/types.d.ts.map +1 -0
  116. package/dist/types.js +8 -0
  117. package/dist/types.js.map +1 -0
  118. package/package.json +4 -4
  119. package/src/application-env.ts +74 -1
  120. package/src/kernel.ts +28 -17
  121. package/src/module-context.ts +57 -6
  122. package/src/schema-validator.ts +1 -0
@@ -0,0 +1,62 @@
1
+ import { ResourceInstance, RuntimeResource } from "@telorun/sdk";
2
+ export interface SnapshotData {
3
+ timestamp: string;
4
+ resources: Array<{
5
+ kind: string;
6
+ name: string;
7
+ metadata: Record<string, any>;
8
+ data: Record<string, any>;
9
+ snapshot?: Record<string, any>;
10
+ }>;
11
+ }
12
+ /**
13
+ * Serializes runtime state into YAML snapshots
14
+ * Captures resource definitions, instances, and custom state
15
+ * Recursively includes nested resources based on generationDepth
16
+ */
17
+ export declare class SnapshotSerializer {
18
+ /**
19
+ * Take a snapshot of runtime state
20
+ * @param resources Map of resources organized by kind
21
+ * @param resourceInstances Map of resource instances to include custom snapshots
22
+ * @param filePath Optional file path to write snapshot to
23
+ * @returns Snapshot data object
24
+ */
25
+ takeSnapshot(resources: Map<string, Map<string, RuntimeResource>>, resourceInstances?: Map<string, {
26
+ resource: RuntimeResource;
27
+ instance: ResourceInstance;
28
+ }>, filePath?: string): Promise<SnapshotData>;
29
+ /**
30
+ * Serialize a single resource
31
+ */
32
+ private serializeResource;
33
+ /**
34
+ * Get snapshot from resource instance if it implements snapshot() method
35
+ */
36
+ private getInstanceSnapshot;
37
+ /**
38
+ * Serialize metadata, filtering out circular references and functions
39
+ */
40
+ private serializeMetadata;
41
+ /**
42
+ * Serialize resource data, filtering out circular references and functions
43
+ */
44
+ private serializeData;
45
+ /**
46
+ * Group resources by generation depth for hierarchical ordering
47
+ */
48
+ private groupByGenerationDepth;
49
+ /**
50
+ * Write snapshot to YAML file
51
+ */
52
+ private writeSnapshotToFile;
53
+ /**
54
+ * Generate resource key for instance lookup
55
+ */
56
+ private getResourceKey;
57
+ /**
58
+ * Load snapshot from YAML file
59
+ */
60
+ loadSnapshotFromFile(filePath: string): Promise<SnapshotData>;
61
+ }
62
+ //# sourceMappingURL=snapshot-serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-serializer.d.ts","sourceRoot":"","sources":["../src/snapshot-serializer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAKjE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAChC,CAAC,CAAC;CACJ;AAED;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B;;;;;;OAMG;IACG,YAAY,CAChB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,EACpD,iBAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAC;QAAC,QAAQ,EAAE,gBAAgB,CAAA;KAAE,CAAC,EAC1F,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC;IA4BxB;;OAEG;YACW,iBAAiB;IAoC/B;;OAEG;YACW,mBAAmB;IAmBjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAiBrB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAoB9B;;OAEG;YACW,mBAAmB;IAgBjC;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAIpE"}
@@ -0,0 +1,164 @@
1
+ import * as fs from "fs/promises";
2
+ import * as YAML from "js-yaml";
3
+ import * as path from "path";
4
+ /**
5
+ * Serializes runtime state into YAML snapshots
6
+ * Captures resource definitions, instances, and custom state
7
+ * Recursively includes nested resources based on generationDepth
8
+ */
9
+ export class SnapshotSerializer {
10
+ /**
11
+ * Take a snapshot of runtime state
12
+ * @param resources Map of resources organized by kind
13
+ * @param resourceInstances Map of resource instances to include custom snapshots
14
+ * @param filePath Optional file path to write snapshot to
15
+ * @returns Snapshot data object
16
+ */
17
+ async takeSnapshot(resources, resourceInstances, filePath) {
18
+ const snapshot = {
19
+ timestamp: new Date().toISOString(),
20
+ resources: [],
21
+ };
22
+ // Get all resources organized by generation depth (0 = first level)
23
+ // Start with depth 0 (directly loaded resources) and recursively include nested ones
24
+ const resourcesByDepth = this.groupByGenerationDepth(resources);
25
+ // Process resources starting from depth 0
26
+ for (const depth of Array.from(resourcesByDepth.keys()).sort((a, b) => a - b)) {
27
+ const resourcesAtDepth = resourcesByDepth.get(depth) || [];
28
+ for (const resource of resourcesAtDepth) {
29
+ const resourceEntry = await this.serializeResource(resource, resourceInstances);
30
+ snapshot.resources.push(resourceEntry);
31
+ }
32
+ }
33
+ // Write to file if path provided
34
+ if (filePath) {
35
+ await this.writeSnapshotToFile(snapshot, filePath);
36
+ }
37
+ return snapshot;
38
+ }
39
+ /**
40
+ * Serialize a single resource
41
+ */
42
+ async serializeResource(resource, resourceInstances) {
43
+ const { kind, metadata, ...data } = resource;
44
+ const { name } = metadata;
45
+ const resourceEntry = {
46
+ kind,
47
+ name,
48
+ metadata: this.serializeMetadata(metadata),
49
+ data: this.serializeData(data),
50
+ };
51
+ // Include custom snapshot if resource instance has snapshot() method
52
+ if (resourceInstances) {
53
+ const key = this.getResourceKey(kind, name);
54
+ const instanceData = resourceInstances.get(key);
55
+ if (instanceData && instanceData.instance) {
56
+ const snapshotData = await this.getInstanceSnapshot(instanceData.instance);
57
+ if (snapshotData) {
58
+ resourceEntry.snapshot = snapshotData;
59
+ }
60
+ }
61
+ }
62
+ return resourceEntry;
63
+ }
64
+ /**
65
+ * Get snapshot from resource instance if it implements snapshot() method
66
+ */
67
+ async getInstanceSnapshot(instance) {
68
+ const instanceAny = instance;
69
+ // Check if snapshot method exists
70
+ if (typeof instanceAny.snapshot === "function") {
71
+ try {
72
+ const result = await Promise.resolve(instanceAny.snapshot(instance));
73
+ return result;
74
+ }
75
+ catch (error) {
76
+ console.error("Error calling snapshot() on resource instance:", error);
77
+ return null;
78
+ }
79
+ }
80
+ return null;
81
+ }
82
+ /**
83
+ * Serialize metadata, filtering out circular references and functions
84
+ */
85
+ serializeMetadata(metadata) {
86
+ const serialized = {};
87
+ for (const [key, value] of Object.entries(metadata)) {
88
+ if (typeof value === "function") {
89
+ continue;
90
+ }
91
+ try {
92
+ serialized[key] = JSON.parse(JSON.stringify(value));
93
+ }
94
+ catch {
95
+ // Skip non-serializable values
96
+ }
97
+ }
98
+ return serialized;
99
+ }
100
+ /**
101
+ * Serialize resource data, filtering out circular references and functions
102
+ */
103
+ serializeData(data) {
104
+ const serialized = {};
105
+ for (const [key, value] of Object.entries(data)) {
106
+ if (typeof value === "function") {
107
+ continue;
108
+ }
109
+ try {
110
+ serialized[key] = JSON.parse(JSON.stringify(value));
111
+ }
112
+ catch {
113
+ // Skip non-serializable values
114
+ }
115
+ }
116
+ return serialized;
117
+ }
118
+ /**
119
+ * Group resources by generation depth for hierarchical ordering
120
+ */
121
+ groupByGenerationDepth(resources) {
122
+ const grouped = new Map();
123
+ for (const kindMap of resources.values()) {
124
+ for (const resource of kindMap.values()) {
125
+ const depth = resource.metadata.generationDepth ?? 0;
126
+ if (!grouped.has(depth)) {
127
+ grouped.set(depth, []);
128
+ }
129
+ grouped.get(depth).push(resource);
130
+ }
131
+ }
132
+ return grouped;
133
+ }
134
+ /**
135
+ * Write snapshot to YAML file
136
+ */
137
+ async writeSnapshotToFile(snapshot, filePath) {
138
+ // Ensure directory exists
139
+ const dir = path.dirname(filePath);
140
+ if (dir !== "." && dir !== "") {
141
+ await fs.mkdir(dir, { recursive: true });
142
+ }
143
+ // Convert to YAML
144
+ const yaml = YAML.dump(snapshot, {
145
+ indent: 2,
146
+ lineWidth: 0,
147
+ });
148
+ await fs.writeFile(filePath, yaml, "utf-8");
149
+ }
150
+ /**
151
+ * Generate resource key for instance lookup
152
+ */
153
+ getResourceKey(kind, name) {
154
+ return `${kind}:${name}`;
155
+ }
156
+ /**
157
+ * Load snapshot from YAML file
158
+ */
159
+ async loadSnapshotFromFile(filePath) {
160
+ const content = await fs.readFile(filePath, "utf-8");
161
+ return YAML.load(content);
162
+ }
163
+ }
164
+ //# sourceMappingURL=snapshot-serializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-serializer.js","sourceRoot":"","sources":["../src/snapshot-serializer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import type { ControllerContext, ResourceContext, ResourceInstance, ResourceManifest, RuntimeErrorCode, RuntimeResource } from "@telorun/sdk";
2
+ import type { ModuleContext } from "./module-context.js";
3
+ export type { ControllerContext, ResourceContext, ResourceInstance, ResourceManifest } from "@telorun/sdk";
4
+ export interface KernelContext {
5
+ kernel: Kernel;
6
+ }
7
+ export interface ExecContext {
8
+ execute(urn: string, input: any): Promise<any>;
9
+ [key: string]: any;
10
+ }
11
+ export type ResourceCapability = string;
12
+ export interface ResourceDefinition {
13
+ kind: string;
14
+ metadata: {
15
+ name: string;
16
+ module: string;
17
+ };
18
+ schema: Record<string, any>;
19
+ capabilities: ResourceCapability[];
20
+ events?: string[];
21
+ controllers?: Array<{
22
+ runtime: string;
23
+ entry: string;
24
+ }>;
25
+ }
26
+ /**
27
+ * Controller definition for a resource kind.
28
+ * Maps a fully-qualified resource kind to its controller implementation for a specific runtime.
29
+ */
30
+ export interface ControllerDefinition {
31
+ kind: string;
32
+ runtime: string;
33
+ entry: string;
34
+ controller?: any;
35
+ }
36
+ /**
37
+ * Controller instance - runtime representation of a controller that handles resource instances.
38
+ */
39
+ export interface ControllerInstance {
40
+ execute?(name: string, inputs: any, ctx: ExecContext): Promise<any>;
41
+ compile?(resource: ResourceManifest, ctx: ResourceContext): RuntimeResource | Promise<RuntimeResource>;
42
+ register?(ctx: ControllerContext): void | Promise<void>;
43
+ create?(resource: ResourceManifest, ctx: ResourceContext): ResourceInstance | null | Promise<ResourceInstance | null>;
44
+ schema: any;
45
+ }
46
+ export interface Kernel {
47
+ loadFromConfig(runtimeYamlPath: string): Promise<void>;
48
+ start(): Promise<void>;
49
+ acquireHold(reason?: string): () => void;
50
+ waitForIdle(): Promise<void>;
51
+ requestExit(code: number): void;
52
+ readonly exitCode: number;
53
+ teardownResource(module: string, kind: string, name: string): Promise<void>;
54
+ registerChildManifest(parentKey: string, resource: ResourceManifest): void;
55
+ getSourceFiles(): string[];
56
+ reloadSource(sourcePath: string): Promise<void>;
57
+ shutdown(): void;
58
+ registerModuleContext(moduleName: string, variables: Record<string, unknown>, secrets: Record<string, unknown>): void;
59
+ getModuleContext(moduleName: string): ModuleContext;
60
+ }
61
+ export declare class RuntimeError extends Error {
62
+ code: RuntimeErrorCode;
63
+ constructor(code: RuntimeErrorCode, message: string);
64
+ }
65
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ export class RuntimeError extends Error {
2
+ constructor(code, message) {
3
+ super(message);
4
+ this.code = code;
5
+ this.name = "RuntimeError";
6
+ }
7
+ }
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA0FA,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YACS,IAAsB,EAC7B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,SAAI,GAAJ,IAAI,CAAkB;QAI7B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/kernel",
3
- "version": "0.13.2",
3
+ "version": "0.15.0",
4
4
  "description": "Telo Runtime - A lightweight, polyglot execution host.",
5
5
  "keywords": [
6
6
  "telo",
@@ -47,8 +47,8 @@
47
47
  "dependencies": {
48
48
  "@marcbachmann/cel-js": "^7.5.3",
49
49
  "@sinclair/typebox": "^0.34.48",
50
- "@telorun/analyzer": "0.12.1",
51
- "@telorun/templating": "0.3.0",
50
+ "@telorun/analyzer": "0.14.0",
51
+ "@telorun/templating": "0.4.0",
52
52
  "ajv": "^8.17.1",
53
53
  "ajv-formats": "^3.0.1",
54
54
  "minimatch": "^10.2.5",
@@ -61,7 +61,7 @@
61
61
  "vitest": "^2.1.8"
62
62
  },
63
63
  "peerDependencies": {
64
- "@telorun/sdk": "0.12.0"
64
+ "@telorun/sdk": "0.13.0"
65
65
  },
66
66
  "overrides": {
67
67
  "@marcbachmann/cel-js": "$@marcbachmann/cel-js",
@@ -11,11 +11,27 @@ interface EnvEntry {
11
11
  [key: string]: unknown;
12
12
  }
13
13
 
14
+ interface PortEntry {
15
+ env: string;
16
+ protocol?: "tcp" | "udp";
17
+ default?: number;
18
+ }
19
+
14
20
  export interface EnvResolutionResult {
15
21
  variables: Record<string, unknown>;
16
22
  secrets: Record<string, unknown>;
23
+ ports: Record<string, number>;
17
24
  }
18
25
 
26
+ /** Residual schema every resolved port value is validated against. Ports are
27
+ * implicitly integers in the IANA range; `protocol` selects transport and
28
+ * carries no validation. */
29
+ const PORT_RESIDUAL_SCHEMA: Record<string, unknown> = {
30
+ type: "integer",
31
+ minimum: 1,
32
+ maximum: 65535,
33
+ };
34
+
19
35
  /**
20
36
  * Populate the root Application's `variables` / `secrets` namespaces from
21
37
  * host environment variables, per the per-field `env:` mapping declared on
@@ -53,6 +69,7 @@ export function resolveApplicationEnv(
53
69
  errors,
54
70
  true,
55
71
  );
72
+ const ports = resolvePorts(manifest.ports ?? {}, env, validator, errors);
56
73
  if (errors.length > 0) {
57
74
  throw new RuntimeError(
58
75
  "ERR_MANIFEST_VALIDATION_FAILED",
@@ -60,7 +77,63 @@ export function resolveApplicationEnv(
60
77
  errors.map((e) => ` - ${e}`).join("\n"),
61
78
  );
62
79
  }
63
- return { variables, secrets };
80
+ return { variables, secrets, ports };
81
+ }
82
+
83
+ /**
84
+ * Populate the root Application's `ports` namespace from host environment
85
+ * variables. Mirrors `resolveBlock` but fixes the value type to a port integer
86
+ * (1–65535): read `entry.env`, coerce the raw value as an integer, validate it
87
+ * against `PORT_RESIDUAL_SCHEMA`, and fall back to `entry.default` when the env
88
+ * var is unset. Failures aggregate into the shared `errors` list so they
89
+ * surface alongside variable/secret problems.
90
+ */
91
+ function resolvePorts(
92
+ block: Record<string, PortEntry> | unknown,
93
+ env: Record<string, string | undefined>,
94
+ validator: SchemaValidator,
95
+ errors: string[],
96
+ ): Record<string, number> {
97
+ const out: Record<string, number> = {};
98
+ if (!block || typeof block !== "object" || Array.isArray(block)) {
99
+ return out;
100
+ }
101
+ for (const [name, entry] of Object.entries(block as Record<string, PortEntry>)) {
102
+ if (!entry || typeof entry !== "object") continue;
103
+ const envKey = entry.env;
104
+ const raw = env[envKey];
105
+
106
+ if (raw === undefined || raw === null) {
107
+ if (entry.default !== undefined) {
108
+ const validation = validateResidual(entry.default, PORT_RESIDUAL_SCHEMA, validator);
109
+ if (validation) {
110
+ errors.push(`${name}: ${validation}`);
111
+ } else {
112
+ out[name] = entry.default;
113
+ }
114
+ continue;
115
+ }
116
+ errors.push(`${name}: environment variable ${envKey} is not set (no default)`);
117
+ continue;
118
+ }
119
+
120
+ let coerced: unknown;
121
+ try {
122
+ coerced = coerce(raw, "integer", envKey, false);
123
+ } catch (e) {
124
+ errors.push(`${name}: ${(e as Error).message}`);
125
+ continue;
126
+ }
127
+
128
+ const validation = validateResidual(coerced, PORT_RESIDUAL_SCHEMA, validator);
129
+ if (validation) {
130
+ errors.push(`${name}: ${validation}`);
131
+ continue;
132
+ }
133
+
134
+ out[name] = coerced as number;
135
+ }
136
+ return out;
64
137
  }
65
138
 
66
139
  function resolveBlock(
package/src/kernel.ts CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  ResourceManifest,
20
20
  RuntimeError,
21
21
  RuntimeEvent,
22
+ type BootTarget,
22
23
  type EvaluationContext as IEvaluationContext,
23
24
  type ModuleContext as IModuleContext,
24
25
  type LoadOptions,
@@ -392,25 +393,32 @@ export class Kernel implements IKernel {
392
393
  // `process.env` after the manifest loop so imports can read
393
394
  // `${{ variables.X }}` during their own init.
394
395
  //
395
- // Targets normalize down to bare names regardless of source surface.
396
- // The analyzer's `resolveRefSentinels` pass already substituted any
397
- // `!ref <name>` to `{kind, name}`; bare-string forms pass through.
398
- // Anything else (e.g. an unresolved sentinel because the analyzer
399
- // couldn't see it, or a malformed manifest) is a hard error —
400
- // silently dropping the entry would leave the user staring at a
401
- // "no targets ran" outcome with no signal where it went wrong.
396
+ // Targets are preserved as their full shape so the boot runner can
397
+ // evaluate `when` guards and inline invoke steps. The analyzer's
398
+ // `resolveRefSentinels` pass already substituted any `!ref <name>` to
399
+ // `{kind, name}` (including inside an inline target's `invoke`).
400
+ // Recognized shapes: bare string ref, resolved `{kind, name}`, gated
401
+ // `{ ref, when? }`, and inline `{ name?, invoke, inputs?, when?, retry? }`.
402
+ // Anything else (e.g. an unresolved sentinel, or a malformed manifest)
403
+ // is a hard error — silently dropping the entry would leave the user
404
+ // staring at a "no targets ran" outcome with no signal.
402
405
  const rawTargets = (manifest.targets ?? []) as unknown[];
403
- const targetNames = rawTargets.map((t, index) => {
404
- if (typeof t === "string") return t;
405
- if (t && typeof t === "object" && typeof (t as { name?: unknown }).name === "string") {
406
- return (t as { name: string }).name;
406
+ rawTargets.forEach((t, index) => {
407
+ const ok =
408
+ typeof t === "string" ||
409
+ (!!t &&
410
+ typeof t === "object" &&
411
+ (typeof (t as { name?: unknown }).name === "string" ||
412
+ (t as { ref?: unknown }).ref != null ||
413
+ (t as { invoke?: unknown }).invoke !== undefined));
414
+ if (!ok) {
415
+ throw new RuntimeError(
416
+ "ERR_INVALID_VALUE",
417
+ `Telo.Application '${(manifest.metadata as { name?: string } | undefined)?.name ?? "(unnamed)"}' targets[${index}] is not a recognized target shape. Got: ${JSON.stringify(t)}`,
418
+ );
407
419
  }
408
- throw new RuntimeError(
409
- "ERR_INVALID_VALUE",
410
- `Telo.Application '${(manifest.metadata as { name?: string } | undefined)?.name ?? "(unnamed)"}' targets[${index}] could not be normalized to a resource name. Got: ${JSON.stringify(t)}`,
411
- );
412
420
  });
413
- this.rootContext.setTargets(targetNames);
421
+ this.rootContext.setTargets(rawTargets as BootTarget[]);
414
422
  if (manifest.kind === "Telo.Application") {
415
423
  rootApplicationManifest = manifest;
416
424
  }
@@ -419,7 +427,7 @@ export class Kernel implements IKernel {
419
427
  }
420
428
 
421
429
  if (rootApplicationManifest) {
422
- const { variables, secrets } = resolveApplicationEnv(
430
+ const { variables, secrets, ports } = resolveApplicationEnv(
423
431
  rootApplicationManifest as Record<string, any>,
424
432
  this.env,
425
433
  this.sharedSchemaValidator,
@@ -430,6 +438,9 @@ export class Kernel implements IKernel {
430
438
  if (Object.keys(secrets).length > 0) {
431
439
  this.rootContext.setSecrets(secrets);
432
440
  }
441
+ if (Object.keys(ports).length > 0) {
442
+ this.rootContext.setPorts(ports);
443
+ }
433
444
  }
434
445
  }
435
446
 
@@ -1,6 +1,10 @@
1
+ import { executeInvokeStep } from "@telorun/sdk";
1
2
  import type {
3
+ BootTarget,
2
4
  ControllerPolicy,
3
5
  Invocable,
6
+ InvokeStep,
7
+ InvokeStepContext,
4
8
  ModuleContext as IModuleContext,
5
9
  } from "@telorun/sdk";
6
10
  import type { EmitEvent, InstanceFactory } from "@telorun/sdk";
@@ -42,8 +46,8 @@ function collectSecretValues(secrets: Record<string, unknown>): Set<string> {
42
46
  }
43
47
 
44
48
  /**
45
- * Persistent, module-scoped context. Three reserved CEL namespaces:
46
- * variables, secrets, resources.
49
+ * Persistent, module-scoped context. Reserved CEL namespaces:
50
+ * variables, secrets, resources, ports (Application-only).
47
51
  *
48
52
  * Unlike the base EvaluationContext, ModuleContext is stateful and mutable:
49
53
  * variables/secrets/resources accumulate during multi-pass initialization and
@@ -57,6 +61,10 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
57
61
  private _variables: Record<string, unknown>;
58
62
  private _secrets: Record<string, unknown>;
59
63
  private _resources: Record<string, unknown>;
64
+ /** Resolved inbound ports (`ports.<name>` → integer). Application-only:
65
+ * populated on the root context from the Application's `ports` block;
66
+ * imported child modules keep this empty. */
67
+ private _ports: Record<string, unknown> = {};
60
68
 
61
69
  /** Maps import alias → real module name for kind resolution. */
62
70
  private readonly importAliases = new Map<string, string>();
@@ -78,7 +86,7 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
78
86
  variables: Record<string, unknown> = {},
79
87
  secrets: Record<string, unknown> = {},
80
88
  resources: Record<string, unknown> = {},
81
- private targets: string[] = [],
89
+ private targets: BootTarget[] = [],
82
90
  createInstance: InstanceFactory = async () => null,
83
91
  emit: EmitEvent,
84
92
  private readonly _hostEnv?: Record<string, string | undefined>,
@@ -102,12 +110,21 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
102
110
  return this._resources;
103
111
  }
104
112
 
113
+ get ports(): Record<string, unknown> {
114
+ return this._ports;
115
+ }
116
+
105
117
  setVariables(vars: Record<string, unknown>): void {
106
118
  this._variables = vars;
107
119
  this._rebuildContext();
108
120
  }
109
121
 
110
- setTargets(vars: string[]): void {
122
+ setPorts(ports: Record<string, unknown>): void {
123
+ this._ports = ports;
124
+ this._rebuildContext();
125
+ }
126
+
127
+ setTargets(vars: BootTarget[]): void {
111
128
  this.targets = vars;
112
129
  }
113
130
 
@@ -212,6 +229,7 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
212
229
  variables: this._variables,
213
230
  secrets: this._secrets,
214
231
  resources: this._resources,
232
+ ports: this._ports,
215
233
  ...(this._hostEnv ? { env: lenientEnv(this._hostEnv) } : {}),
216
234
  };
217
235
  this._secretValues = collectSecretValues(this._secrets);
@@ -242,8 +260,41 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
242
260
  }
243
261
 
244
262
  async runTargets() {
245
- for (const target of this.targets) {
246
- await this.run(target);
263
+ const steps: Record<string, unknown> = {};
264
+ const stepCtx: InvokeStepContext = {
265
+ expandValue: (value, context) => this.expandWith(value, context),
266
+ invoke: (kind, name, inputs) => this.invoke(kind, name, inputs),
267
+ invokeResolved: (kind, name, instance, inputs) =>
268
+ this.invokeResolved(kind, name, instance, inputs),
269
+ };
270
+ for (let i = 0; i < this.targets.length; i++) {
271
+ const target = this.targets[i]!;
272
+ if (typeof target === "string") {
273
+ await this.run(target);
274
+ continue;
275
+ }
276
+ if ("invoke" in target && target.invoke !== undefined) {
277
+ const step: InvokeStep = {
278
+ name: target.name ?? `Target${i}`,
279
+ when: target.when,
280
+ invoke: target.invoke,
281
+ inputs: target.inputs,
282
+ };
283
+ await executeInvokeStep(step, stepCtx, { steps });
284
+ continue;
285
+ }
286
+ if ("ref" in target && target.ref != null) {
287
+ const refName = typeof target.ref === "string" ? target.ref : target.ref.name;
288
+ if (target.when === undefined || this.expandWith(target.when, { steps })) {
289
+ await this.run(refName);
290
+ }
291
+ continue;
292
+ }
293
+ if ("name" in target && typeof target.name === "string") {
294
+ await this.run(target.name);
295
+ continue;
296
+ }
297
+ throw new Error(`Unrecognized target shape at index ${i}: ${JSON.stringify(target)}`);
247
298
  }
248
299
  }
249
300
  }
@@ -112,6 +112,7 @@ export class SchemaValidator {
112
112
  "x-telo-topology-role",
113
113
  "x-telo-step-context",
114
114
  "x-telo-widget",
115
+ "x-telo-type",
115
116
  ]) {
116
117
  this.ajv.addKeyword(kw);
117
118
  }