@telorun/kernel 0.12.0 → 0.13.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/LICENSE +2 -2
- package/dist/application-env.d.ts +24 -0
- package/dist/application-env.d.ts.map +1 -0
- package/dist/application-env.js +156 -0
- package/dist/application-env.js.map +1 -0
- 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/controller-loaders/npm-loader.d.ts +32 -8
- package/dist/controller-loaders/npm-loader.d.ts.map +1 -1
- package/dist/controller-loaders/npm-loader.js +74 -101
- package/dist/controller-loaders/npm-loader.js.map +1 -1
- 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/import-controller.d.ts +3 -2
- package/dist/controllers/module/import-controller.d.ts.map +1 -1
- package/dist/controllers/module/import-controller.js +23 -25
- package/dist/controllers/module/import-controller.js.map +1 -1
- package/dist/controllers/module/module.json +48 -0
- package/dist/controllers/resource-definition/resource-definition-controller.d.ts +1 -0
- package/dist/controllers/resource-definition/resource-definition-controller.d.ts.map +1 -1
- package/dist/controllers/resource-definition/resource-definition-controller.js +3 -0
- package/dist/controllers/resource-definition/resource-definition-controller.js.map +1 -1
- package/dist/controllers/resource-definition/resource-template-controller.d.ts +5 -0
- package/dist/controllers/resource-definition/resource-template-controller.d.ts.map +1 -1
- package/dist/controllers/resource-definition/resource-template-controller.js +67 -6
- package/dist/controllers/resource-definition/resource-template-controller.js.map +1 -1
- package/dist/internal-context.d.ts +25 -0
- package/dist/internal-context.d.ts.map +1 -0
- package/dist/internal-context.js +2 -0
- package/dist/internal-context.js.map +1 -0
- package/dist/kernel.d.ts +21 -1
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +109 -5
- 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/manifest-schemas.d.ts +7 -23
- package/dist/manifest-schemas.d.ts.map +1 -1
- package/dist/manifest-schemas.js +18 -8
- package/dist/manifest-schemas.js.map +1 -1
- package/dist/manifest-sources/analysis-stamp.d.ts +25 -0
- package/dist/manifest-sources/analysis-stamp.d.ts.map +1 -0
- package/dist/manifest-sources/analysis-stamp.js +151 -0
- package/dist/manifest-sources/analysis-stamp.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/resource-context.d.ts +2 -0
- package/dist/resource-context.d.ts.map +1 -1
- package/dist/resource-context.js +28 -0
- package/dist/resource-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 +28 -0
- package/dist/schema-validator.d.ts.map +1 -1
- package/dist/schema-validator.js +161 -1
- 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 +9 -6
- package/src/application-env.ts +216 -0
- package/src/controller-loaders/npm-loader.ts +78 -103
- package/src/controllers/module/import-controller.ts +33 -36
- package/src/controllers/resource-definition/resource-definition-controller.ts +6 -0
- package/src/controllers/resource-definition/resource-template-controller.ts +95 -7
- package/src/internal-context.ts +25 -0
- package/src/kernel.ts +130 -5
- package/src/manifest-schemas.ts +31 -11
- package/src/manifest-sources/analysis-stamp.ts +169 -0
- package/src/resource-context.ts +34 -0
- package/src/schema-validator.ts +178 -2
- package/dist/generated/runtime-deps.json +0 -6
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { evaluate } from "@marcbachmann/cel-js";
|
|
2
|
+
import { RuntimeError } from "@telorun/sdk";
|
|
3
|
+
import AjvModule from "ajv";
|
|
4
|
+
import addFormats from "ajv-formats";
|
|
5
|
+
import { formatAjvErrors } from "./manifest-schemas.js";
|
|
6
|
+
const Ajv = AjvModule.default ?? AjvModule;
|
|
7
|
+
export class SchemaValidator {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.typeRules = new Map();
|
|
10
|
+
this.rawSchemas = new Map();
|
|
11
|
+
this.compiledValidators = new WeakMap();
|
|
12
|
+
this.ajv = new Ajv({
|
|
13
|
+
strict: false,
|
|
14
|
+
removeAdditional: false,
|
|
15
|
+
useDefaults: true,
|
|
16
|
+
});
|
|
17
|
+
addFormats.default(this.ajv);
|
|
18
|
+
for (const kw of [
|
|
19
|
+
"x-telo-ref",
|
|
20
|
+
"x-telo-eval",
|
|
21
|
+
"x-telo-scope",
|
|
22
|
+
"x-telo-context",
|
|
23
|
+
"x-telo-context-from",
|
|
24
|
+
"x-telo-context-ref-from",
|
|
25
|
+
"x-telo-schema-from",
|
|
26
|
+
"x-telo-topology-role",
|
|
27
|
+
"x-telo-step-context",
|
|
28
|
+
]) {
|
|
29
|
+
this.ajv.addKeyword(kw);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
addSchema(name, schema) {
|
|
33
|
+
if (!this.ajv.getSchema(name)) {
|
|
34
|
+
this.ajv.addSchema(schema, name);
|
|
35
|
+
}
|
|
36
|
+
this.rawSchemas.set(name, schema);
|
|
37
|
+
}
|
|
38
|
+
getSchema(name) {
|
|
39
|
+
return this.rawSchemas.get(name);
|
|
40
|
+
}
|
|
41
|
+
addTypeRules(name, rules) {
|
|
42
|
+
this.typeRules.set(name, rules);
|
|
43
|
+
}
|
|
44
|
+
getTypeRules(name) {
|
|
45
|
+
return this.typeRules.get(name);
|
|
46
|
+
}
|
|
47
|
+
compile(schema) {
|
|
48
|
+
if (schema && typeof schema === "object") {
|
|
49
|
+
const cached = this.compiledValidators.get(schema);
|
|
50
|
+
if (cached)
|
|
51
|
+
return cached;
|
|
52
|
+
}
|
|
53
|
+
const isFullSchema = ("type" in schema && typeof schema.type === "string") ||
|
|
54
|
+
"allOf" in schema ||
|
|
55
|
+
"anyOf" in schema ||
|
|
56
|
+
"oneOf" in schema ||
|
|
57
|
+
"$ref" in schema;
|
|
58
|
+
const normalized = isFullSchema
|
|
59
|
+
? schema
|
|
60
|
+
: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: schema,
|
|
63
|
+
required: Object.keys(schema),
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
};
|
|
66
|
+
const injected = normalized.additionalProperties === false
|
|
67
|
+
? {
|
|
68
|
+
...normalized,
|
|
69
|
+
properties: {
|
|
70
|
+
kind: { type: "string" },
|
|
71
|
+
metadata: { type: "object" },
|
|
72
|
+
...normalized.properties,
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
: normalized;
|
|
76
|
+
const validate = this.ajv.compile(injected);
|
|
77
|
+
const validator = {
|
|
78
|
+
validate: (data) => {
|
|
79
|
+
const isValid = validate(data);
|
|
80
|
+
if (!isValid) {
|
|
81
|
+
throw new RuntimeError("ERR_RESOURCE_SCHEMA_VALIDATION_FAILED", `Invalid value passed: ${JSON.stringify(data)}. Error: ${formatAjvErrors(validate.errors)}`);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
isValid: (data) => {
|
|
85
|
+
return validate(data);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
if (schema && typeof schema === "object") {
|
|
89
|
+
this.compiledValidators.set(schema, validator);
|
|
90
|
+
}
|
|
91
|
+
return validator;
|
|
92
|
+
}
|
|
93
|
+
composeWithRules(base, typeName, rules) {
|
|
94
|
+
return {
|
|
95
|
+
validate: (data) => {
|
|
96
|
+
base.validate(data);
|
|
97
|
+
for (const rule of rules) {
|
|
98
|
+
let result;
|
|
99
|
+
try {
|
|
100
|
+
result = evaluate(rule.condition, { this: data });
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
throw new RuntimeError("ERR_TYPE_VALIDATION_FAILED", `Type "${typeName}" rule evaluation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
104
|
+
}
|
|
105
|
+
if (result !== true) {
|
|
106
|
+
throw new RuntimeError(rule.code ?? "ERR_TYPE_VALIDATION_FAILED", rule.message ?? `Type "${typeName}" validation failed: rule "${rule.code}" not satisfied`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
isValid: (data) => {
|
|
111
|
+
if (!base.isValid(data))
|
|
112
|
+
return false;
|
|
113
|
+
for (const rule of rules) {
|
|
114
|
+
try {
|
|
115
|
+
if (evaluate(rule.condition, { this: data }) !== true)
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=schema-valiator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-valiator.js","sourceRoot":"","sources":["../src/schema-valiator.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,12 +4,40 @@ export declare class SchemaValidator {
|
|
|
4
4
|
private typeRules;
|
|
5
5
|
private rawSchemas;
|
|
6
6
|
private compiledValidators;
|
|
7
|
+
private cacheDir;
|
|
8
|
+
/** Tracks (schema-hash → in-memory compiled validator) so two distinct
|
|
9
|
+
* but content-equal schema objects share one compile across the kernel
|
|
10
|
+
* process — `compiledValidators` is keyed by object identity and would
|
|
11
|
+
* miss those cases. */
|
|
12
|
+
private hashCache;
|
|
7
13
|
constructor();
|
|
8
14
|
addSchema(name: string, schema: object): void;
|
|
9
15
|
getSchema(name: string): object | undefined;
|
|
10
16
|
addTypeRules(name: string, rules: TypeRule[]): void;
|
|
11
17
|
getTypeRules(name: string): TypeRule[] | undefined;
|
|
18
|
+
/** Enable the on-disk validator cache rooted at `dir`. Compiled AJV
|
|
19
|
+
* validators are written as standalone CJS modules keyed by content
|
|
20
|
+
* hash, so subsequent process invocations skip the ≈2–10 ms AJV
|
|
21
|
+
* codegen for each unseen schema. Safe to call before or after
|
|
22
|
+
* `compile()` — already-compiled in-memory entries are unaffected.
|
|
23
|
+
* The caller is responsible for choosing a writable directory; the
|
|
24
|
+
* kernel anchors this under `<entry-dir>/.telo/manifests/__validators/`
|
|
25
|
+
* so it lives next to the manifest cache and rides along in
|
|
26
|
+
* `COPY --from=build /srv /srv` Docker images. */
|
|
27
|
+
setCacheDir(dir: string | undefined): void;
|
|
12
28
|
compile(schema: any): DataValidator;
|
|
29
|
+
/** Load `<cacheDir>/<hash>.cjs` if present, else compile via AJV and
|
|
30
|
+
* persist as standalone CJS. Cached files start with a
|
|
31
|
+
* `// sha256:<hex>\n` header covering the rest of the file; a
|
|
32
|
+
* mismatch (truncated write, FS corruption, tampering inside a baked
|
|
33
|
+
* Docker image) is treated as a cache miss and the validator is
|
|
34
|
+
* recompiled — and overwritten — so the cache self-heals. The cached
|
|
35
|
+
* body is wrapped so its embedded `require("ajv/...")` /
|
|
36
|
+
* `require("ajv-formats/...")` calls resolve against the kernel
|
|
37
|
+
* package; the cache file lives outside any `node_modules` tree, so a
|
|
38
|
+
* bare `require()` from its own path would fail. Read/write failures
|
|
39
|
+
* surface to stderr but never abort compilation. */
|
|
40
|
+
private compileAjvOrLoadCached;
|
|
13
41
|
composeWithRules(base: DataValidator, typeName: string, rules: TypeRule[]): DataValidator;
|
|
14
42
|
}
|
|
15
43
|
//# sourceMappingURL=schema-validator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-validator.d.ts","sourceRoot":"","sources":["../src/schema-validator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAgB,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"schema-validator.d.ts","sourceRoot":"","sources":["../src/schema-validator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAgB,QAAQ,EAAE,MAAM,cAAc,CAAC;AA+ErE,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,kBAAkB,CAAwC;IAClE,OAAO,CAAC,QAAQ,CAAqB;IACrC;;;4BAGwB;IACxB,OAAO,CAAC,SAAS,CAAoC;;IAiCrD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAO7C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI;IAInD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,SAAS;IAIlD;;;;;;;;uDAQmD;IACnD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAI1C,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,aAAa;IAqEnC;;;;;;;;;;yDAUqD;IACrD,OAAO,CAAC,sBAAsB;IAoD9B,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,aAAa;CAmC1F"}
|
package/dist/schema-validator.js
CHANGED
|
@@ -1,18 +1,99 @@
|
|
|
1
1
|
import { evaluate } from "@marcbachmann/cel-js";
|
|
2
2
|
import { RuntimeError } from "@telorun/sdk";
|
|
3
3
|
import AjvModule from "ajv";
|
|
4
|
+
import standaloneCodeMod from "ajv/dist/standalone/index.js";
|
|
4
5
|
import addFormats from "ajv-formats";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import { createRequire } from "node:module";
|
|
9
|
+
import * as path from "node:path";
|
|
5
10
|
import { formatAjvErrors } from "./manifest-schemas.js";
|
|
11
|
+
import { ManifestRootSchema } from "@telorun/templating";
|
|
6
12
|
const Ajv = AjvModule.default ?? AjvModule;
|
|
13
|
+
// AJV's standalone subpath is CJS — the default export shows up as either
|
|
14
|
+
// the function itself or `.default` depending on how the bundler/loader
|
|
15
|
+
// rewrites it. Normalise once.
|
|
16
|
+
const standaloneCode = standaloneCodeMod.default ?? standaloneCodeMod;
|
|
17
|
+
/** `require` resolved from this file's URL — used to satisfy `ajv/dist/...`
|
|
18
|
+
* / `ajv-formats/...` imports embedded in standalone-compiled validators
|
|
19
|
+
* loaded back off disk. Anchored here so it always resolves through the
|
|
20
|
+
* kernel package's node_modules, regardless of where the cache file
|
|
21
|
+
* lives on disk. */
|
|
22
|
+
const kernelRequire = createRequire(import.meta.url);
|
|
23
|
+
/** Resolved AJV + ajv-formats versions, baked into every cache key so a
|
|
24
|
+
* pnpm/npm install that upgrades either package invalidates all stale
|
|
25
|
+
* `<hash>.cjs` files automatically. Standalone-compiled validators
|
|
26
|
+
* embed `require("ajv/dist/runtime/...")` — running a validator built
|
|
27
|
+
* against an older AJV against the current runtime is undefined
|
|
28
|
+
* behaviour, so the version pin must be part of the hash, not a manual
|
|
29
|
+
* bump. Falls back to walking up from the package's main entry when
|
|
30
|
+
* the dependency restricts subpath access via `exports`. */
|
|
31
|
+
function readDepVersion(spec) {
|
|
32
|
+
try {
|
|
33
|
+
const pkg = kernelRequire(`${spec}/package.json`);
|
|
34
|
+
if (typeof pkg.version === "string")
|
|
35
|
+
return pkg.version;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// restricted exports — try the filesystem walk below
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const entry = kernelRequire.resolve(spec);
|
|
42
|
+
let dir = path.dirname(entry);
|
|
43
|
+
while (dir !== path.dirname(dir)) {
|
|
44
|
+
const candidate = path.join(dir, "package.json");
|
|
45
|
+
try {
|
|
46
|
+
const pkg = JSON.parse(fs.readFileSync(candidate, "utf-8"));
|
|
47
|
+
const expectedName = spec.split("/").slice(0, spec.startsWith("@") ? 2 : 1).join("/");
|
|
48
|
+
if (typeof pkg.name === "string" && pkg.name === expectedName) {
|
|
49
|
+
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// keep walking — not at the package root yet
|
|
54
|
+
}
|
|
55
|
+
dir = path.dirname(dir);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// package not installed
|
|
60
|
+
}
|
|
61
|
+
return "unknown";
|
|
62
|
+
}
|
|
63
|
+
const AJV_VERSION = readDepVersion("ajv");
|
|
64
|
+
const AJV_FORMATS_VERSION = readDepVersion("ajv-formats");
|
|
65
|
+
const VALIDATOR_RUNTIME_TAG = `ajv@${AJV_VERSION}+ajv-formats@${AJV_FORMATS_VERSION}`;
|
|
66
|
+
const SHA256_HEADER_PATTERN = /^\/\/ sha256:([0-9a-f]{64})\n/;
|
|
67
|
+
/** Verify a cached validator file's SHA-256 integrity header and return
|
|
68
|
+
* the body when the digest matches. Returns `null` on any mismatch /
|
|
69
|
+
* malformed header — the caller treats that as a cache miss and
|
|
70
|
+
* recompiles + overwrites the file. */
|
|
71
|
+
function verifyAndExtractBody(text) {
|
|
72
|
+
const match = text.match(SHA256_HEADER_PATTERN);
|
|
73
|
+
if (!match)
|
|
74
|
+
return null;
|
|
75
|
+
const body = text.slice(match[0].length);
|
|
76
|
+
const actual = createHash("sha256").update(body).digest("hex");
|
|
77
|
+
return actual === match[1] ? body : null;
|
|
78
|
+
}
|
|
7
79
|
export class SchemaValidator {
|
|
8
80
|
constructor() {
|
|
9
81
|
this.typeRules = new Map();
|
|
10
82
|
this.rawSchemas = new Map();
|
|
11
83
|
this.compiledValidators = new WeakMap();
|
|
84
|
+
/** Tracks (schema-hash → in-memory compiled validator) so two distinct
|
|
85
|
+
* but content-equal schema objects share one compile across the kernel
|
|
86
|
+
* process — `compiledValidators` is keyed by object identity and would
|
|
87
|
+
* miss those cases. */
|
|
88
|
+
this.hashCache = new Map();
|
|
12
89
|
this.ajv = new Ajv({
|
|
13
90
|
strict: false,
|
|
14
91
|
removeAdditional: false,
|
|
15
92
|
useDefaults: true,
|
|
93
|
+
// Required for `standaloneCode` extraction — tells AJV to keep the
|
|
94
|
+
// generated validator's source available rather than wrapping it
|
|
95
|
+
// through `new Function`. The cost at compile time is negligible.
|
|
96
|
+
code: { source: true },
|
|
16
97
|
});
|
|
17
98
|
addFormats.default(this.ajv);
|
|
18
99
|
for (const kw of [
|
|
@@ -29,6 +110,10 @@ export class SchemaValidator {
|
|
|
29
110
|
]) {
|
|
30
111
|
this.ajv.addKeyword(kw);
|
|
31
112
|
}
|
|
113
|
+
// Register the shared manifest root so module schemas can
|
|
114
|
+
// `$ref: "telo://manifest#/$defs/ResourceRef"` without each manifest
|
|
115
|
+
// bundling its own copy. Mirrors the analyzer's createAjv().
|
|
116
|
+
this.ajv.addSchema(ManifestRootSchema);
|
|
32
117
|
}
|
|
33
118
|
addSchema(name, schema) {
|
|
34
119
|
if (!this.ajv.getSchema(name)) {
|
|
@@ -45,6 +130,18 @@ export class SchemaValidator {
|
|
|
45
130
|
getTypeRules(name) {
|
|
46
131
|
return this.typeRules.get(name);
|
|
47
132
|
}
|
|
133
|
+
/** Enable the on-disk validator cache rooted at `dir`. Compiled AJV
|
|
134
|
+
* validators are written as standalone CJS modules keyed by content
|
|
135
|
+
* hash, so subsequent process invocations skip the ≈2–10 ms AJV
|
|
136
|
+
* codegen for each unseen schema. Safe to call before or after
|
|
137
|
+
* `compile()` — already-compiled in-memory entries are unaffected.
|
|
138
|
+
* The caller is responsible for choosing a writable directory; the
|
|
139
|
+
* kernel anchors this under `<entry-dir>/.telo/manifests/__validators/`
|
|
140
|
+
* so it lives next to the manifest cache and rides along in
|
|
141
|
+
* `COPY --from=build /srv /srv` Docker images. */
|
|
142
|
+
setCacheDir(dir) {
|
|
143
|
+
this.cacheDir = dir;
|
|
144
|
+
}
|
|
48
145
|
compile(schema) {
|
|
49
146
|
if (schema && typeof schema === "object") {
|
|
50
147
|
const cached = this.compiledValidators.get(schema);
|
|
@@ -74,7 +171,18 @@ export class SchemaValidator {
|
|
|
74
171
|
},
|
|
75
172
|
}
|
|
76
173
|
: normalized;
|
|
77
|
-
const
|
|
174
|
+
const hash = createHash("sha256")
|
|
175
|
+
.update(JSON.stringify({ runtime: VALIDATOR_RUNTIME_TAG, schema: injected }))
|
|
176
|
+
.digest("hex")
|
|
177
|
+
.slice(0, 32);
|
|
178
|
+
const cachedByHash = this.hashCache.get(hash);
|
|
179
|
+
if (cachedByHash) {
|
|
180
|
+
if (schema && typeof schema === "object") {
|
|
181
|
+
this.compiledValidators.set(schema, cachedByHash);
|
|
182
|
+
}
|
|
183
|
+
return cachedByHash;
|
|
184
|
+
}
|
|
185
|
+
const validate = this.compileAjvOrLoadCached(injected, hash);
|
|
78
186
|
const validator = {
|
|
79
187
|
validate: (data) => {
|
|
80
188
|
const isValid = validate(data);
|
|
@@ -86,11 +194,63 @@ export class SchemaValidator {
|
|
|
86
194
|
return validate(data);
|
|
87
195
|
},
|
|
88
196
|
};
|
|
197
|
+
this.hashCache.set(hash, validator);
|
|
89
198
|
if (schema && typeof schema === "object") {
|
|
90
199
|
this.compiledValidators.set(schema, validator);
|
|
91
200
|
}
|
|
92
201
|
return validator;
|
|
93
202
|
}
|
|
203
|
+
/** Load `<cacheDir>/<hash>.cjs` if present, else compile via AJV and
|
|
204
|
+
* persist as standalone CJS. Cached files start with a
|
|
205
|
+
* `// sha256:<hex>\n` header covering the rest of the file; a
|
|
206
|
+
* mismatch (truncated write, FS corruption, tampering inside a baked
|
|
207
|
+
* Docker image) is treated as a cache miss and the validator is
|
|
208
|
+
* recompiled — and overwritten — so the cache self-heals. The cached
|
|
209
|
+
* body is wrapped so its embedded `require("ajv/...")` /
|
|
210
|
+
* `require("ajv-formats/...")` calls resolve against the kernel
|
|
211
|
+
* package; the cache file lives outside any `node_modules` tree, so a
|
|
212
|
+
* bare `require()` from its own path would fail. Read/write failures
|
|
213
|
+
* surface to stderr but never abort compilation. */
|
|
214
|
+
compileAjvOrLoadCached(schema, hash) {
|
|
215
|
+
const cacheDir = this.cacheDir;
|
|
216
|
+
if (cacheDir) {
|
|
217
|
+
const cachePath = path.join(cacheDir, `${hash}.cjs`);
|
|
218
|
+
try {
|
|
219
|
+
const text = fs.readFileSync(cachePath, "utf-8");
|
|
220
|
+
const body = verifyAndExtractBody(text);
|
|
221
|
+
if (body !== null) {
|
|
222
|
+
const factory = new Function("require", "module", "exports", `${body}\nreturn module.exports;`);
|
|
223
|
+
const mod = { exports: {} };
|
|
224
|
+
const loaded = factory(kernelRequire, mod, mod.exports);
|
|
225
|
+
if (typeof loaded === "function") {
|
|
226
|
+
return loaded;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Header missing / mismatched / non-function export — fall
|
|
230
|
+
// through and recompile. The write step below overwrites the
|
|
231
|
+
// stale file with a fresh hash header.
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
if (err?.code !== "ENOENT") {
|
|
235
|
+
process.stderr.write(`[telo:kernel] validator cache load failed (${hash}): ${err instanceof Error ? err.message : String(err)}\n`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const validate = this.ajv.compile(schema);
|
|
240
|
+
if (cacheDir) {
|
|
241
|
+
try {
|
|
242
|
+
const body = standaloneCode(this.ajv, validate);
|
|
243
|
+
const integrity = createHash("sha256").update(body).digest("hex");
|
|
244
|
+
const payload = `// sha256:${integrity}\n${body}`;
|
|
245
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
246
|
+
fs.writeFileSync(path.join(cacheDir, `${hash}.cjs`), payload, "utf-8");
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
process.stderr.write(`[telo:kernel] validator cache write failed (${hash}): ${err instanceof Error ? err.message : String(err)}\n`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return validate;
|
|
253
|
+
}
|
|
94
254
|
composeWithRules(base, typeName, rules) {
|
|
95
255
|
return {
|
|
96
256
|
validate: (data) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../src/schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAiB,YAAY,EAAY,MAAM,cAAc,CAAC;AACrE,OAAO,
|
|
1
|
+
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../src/schema-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|