@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.
- package/dist/application-env.d.ts +1 -0
- package/dist/application-env.d.ts.map +1 -1
- package/dist/application-env.js +59 -1
- package/dist/application-env.js.map +1 -1
- package/dist/base-definition.d.ts +14 -0
- package/dist/base-definition.d.ts.map +1 -0
- package/dist/base-definition.js +17 -0
- package/dist/base-definition.js.map +1 -0
- package/dist/capabilities/capabilities/component.yaml +4 -0
- package/dist/capabilities/capabilities/executable.yaml +8 -0
- package/dist/capabilities/capabilities/handler.yaml +4 -0
- package/dist/capabilities/capabilities/listener.yaml +4 -0
- package/dist/capabilities/capabilities/provider.yaml +4 -0
- package/dist/capabilities/capabilities/template.yaml +4 -0
- package/dist/capabilities/capabilities/type.yaml +4 -0
- package/dist/capabilities/component.d.ts +3 -0
- package/dist/capabilities/component.d.ts.map +1 -0
- package/dist/capabilities/component.js +4 -0
- package/dist/capabilities/component.js.map +1 -0
- package/dist/capabilities/component.yaml +3 -0
- package/dist/capabilities/executable.d.ts +3 -0
- package/dist/capabilities/executable.d.ts.map +1 -0
- package/dist/capabilities/executable.js +5 -0
- package/dist/capabilities/executable.js.map +1 -0
- package/dist/capabilities/executable.yaml +7 -0
- package/dist/capabilities/handler.d.ts +3 -0
- package/dist/capabilities/handler.d.ts.map +1 -0
- package/dist/capabilities/handler.js +4 -0
- package/dist/capabilities/handler.js.map +1 -0
- package/dist/capabilities/handler.yaml +3 -0
- package/dist/capabilities/invokable.d.ts +3 -0
- package/dist/capabilities/invokable.d.ts.map +1 -0
- package/dist/capabilities/invokable.js +5 -0
- package/dist/capabilities/invokable.js.map +1 -0
- package/dist/capabilities/listener.d.ts +3 -0
- package/dist/capabilities/listener.d.ts.map +1 -0
- package/dist/capabilities/listener.js +5 -0
- package/dist/capabilities/listener.js.map +1 -0
- package/dist/capabilities/listener.yaml +3 -0
- package/dist/capabilities/mount.d.ts +3 -0
- package/dist/capabilities/mount.d.ts.map +1 -0
- package/dist/capabilities/mount.js +5 -0
- package/dist/capabilities/mount.js.map +1 -0
- package/dist/capabilities/provider.d.ts +3 -0
- package/dist/capabilities/provider.d.ts.map +1 -0
- package/dist/capabilities/provider.js +8 -0
- package/dist/capabilities/provider.js.map +1 -0
- package/dist/capabilities/provider.yaml +3 -0
- package/dist/capabilities/runnable.d.ts +3 -0
- package/dist/capabilities/runnable.d.ts.map +1 -0
- package/dist/capabilities/runnable.js +5 -0
- package/dist/capabilities/runnable.js.map +1 -0
- package/dist/capabilities/service.d.ts +3 -0
- package/dist/capabilities/service.d.ts.map +1 -0
- package/dist/capabilities/service.js +5 -0
- package/dist/capabilities/service.js.map +1 -0
- package/dist/capabilities/template.d.ts +3 -0
- package/dist/capabilities/template.d.ts.map +1 -0
- package/dist/capabilities/template.js +5 -0
- package/dist/capabilities/template.js.map +1 -0
- package/dist/capabilities/template.yaml +3 -0
- package/dist/capabilities/type.d.ts +3 -0
- package/dist/capabilities/type.d.ts.map +1 -0
- package/dist/capabilities/type.js +5 -0
- package/dist/capabilities/type.js.map +1 -0
- package/dist/capabilities/type.yaml +3 -0
- package/dist/controllers/capability/capability-controller.d.ts +32 -0
- package/dist/controllers/capability/capability-controller.d.ts.map +1 -0
- package/dist/controllers/capability/capability-controller.js +26 -0
- package/dist/controllers/capability/capability-controller.js.map +1 -0
- package/dist/controllers/module/module.json +48 -0
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +23 -15
- package/dist/kernel.js.map +1 -1
- package/dist/loader.d.ts +18 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +127 -0
- package/dist/loader.js.map +1 -0
- package/dist/manifest-adapters/http-adapter.d.ts +8 -0
- package/dist/manifest-adapters/http-adapter.d.ts.map +1 -0
- package/dist/manifest-adapters/http-adapter.js +31 -0
- package/dist/manifest-adapters/http-adapter.js.map +1 -0
- package/dist/manifest-adapters/local-file-adapter.d.ts +15 -0
- package/dist/manifest-adapters/local-file-adapter.d.ts.map +1 -0
- package/dist/manifest-adapters/local-file-adapter.js +95 -0
- package/dist/manifest-adapters/local-file-adapter.js.map +1 -0
- package/dist/manifest-adapters/manifest-adapter.d.ts +35 -0
- package/dist/manifest-adapters/manifest-adapter.d.ts.map +1 -0
- package/dist/manifest-adapters/manifest-adapter.js +2 -0
- package/dist/manifest-adapters/manifest-adapter.js.map +1 -0
- package/dist/manifest-adapters/registry-adapter.d.ts +9 -0
- package/dist/manifest-adapters/registry-adapter.d.ts.map +1 -0
- package/dist/manifest-adapters/registry-adapter.js +48 -0
- package/dist/manifest-adapters/registry-adapter.js.map +1 -0
- package/dist/module-context-registry.d.ts +48 -0
- package/dist/module-context-registry.d.ts.map +1 -0
- package/dist/module-context-registry.js +91 -0
- package/dist/module-context-registry.js.map +1 -0
- package/dist/module-context.d.ts +11 -5
- package/dist/module-context.d.ts.map +1 -1
- package/dist/module-context.js +49 -4
- package/dist/module-context.js.map +1 -1
- package/dist/schema-valiator.d.ts +15 -0
- package/dist/schema-valiator.d.ts.map +1 -0
- package/dist/schema-valiator.js +127 -0
- package/dist/schema-valiator.js.map +1 -0
- package/dist/schema-validator.d.ts.map +1 -1
- package/dist/schema-validator.js +1 -0
- package/dist/schema-validator.js.map +1 -1
- package/dist/snapshot-serializer.d.ts +62 -0
- package/dist/snapshot-serializer.d.ts.map +1 -0
- package/dist/snapshot-serializer.js +164 -0
- package/dist/snapshot-serializer.js.map +1 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +4 -4
- package/src/application-env.ts +74 -1
- package/src/kernel.ts +28 -17
- package/src/module-context.ts +57 -6
- 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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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.
|
|
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.
|
|
51
|
-
"@telorun/templating": "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.
|
|
64
|
+
"@telorun/sdk": "0.13.0"
|
|
65
65
|
},
|
|
66
66
|
"overrides": {
|
|
67
67
|
"@marcbachmann/cel-js": "$@marcbachmann/cel-js",
|
package/src/application-env.ts
CHANGED
|
@@ -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
|
|
396
|
-
//
|
|
397
|
-
// `!ref <name>` to
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
//
|
|
401
|
-
//
|
|
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
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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(
|
|
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
|
|
package/src/module-context.ts
CHANGED
|
@@ -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.
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
246
|
-
|
|
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
|
}
|