@kalada/host 0.1.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/README.md +101 -0
- package/dist/index.cjs +2329 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +562 -0
- package/dist/index.d.ts +562 -0
- package/dist/index.js +2310 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2310 @@
|
|
|
1
|
+
import { compileKaladaV1Program, decodeKaladaValue, encodeKaladaValue, isOption, isResult as isResult$1, isInstant, isDuration } from '@kalada/core';
|
|
2
|
+
import { parseKaladaV1Expression, lowerKaladaV1Expression } from '@kalada/syntax';
|
|
3
|
+
|
|
4
|
+
// src/compile-expression.ts
|
|
5
|
+
|
|
6
|
+
// src/serializable.ts
|
|
7
|
+
var DEFAULT_SERIALIZABLE_LIMITS = Object.freeze({
|
|
8
|
+
maxDepth: 32,
|
|
9
|
+
maxNodes: 1e4,
|
|
10
|
+
maxCollectionSize: 1e4,
|
|
11
|
+
maxStringLength: 1e5
|
|
12
|
+
});
|
|
13
|
+
function readOwnDataRecord(input, maximumKeys = 1e4) {
|
|
14
|
+
if (typeof input !== "object" || input === null) return shallowFailure("invalid-value");
|
|
15
|
+
const array = safelyReflect(() => Array.isArray(input));
|
|
16
|
+
if (!array.ok || array.value) return shallowFailure("invalid-value");
|
|
17
|
+
const prototype = safelyReflect(() => Object.getPrototypeOf(input));
|
|
18
|
+
if (!prototype.ok || prototype.value !== Object.prototype && prototype.value !== null) {
|
|
19
|
+
return shallowFailure("invalid-value");
|
|
20
|
+
}
|
|
21
|
+
const keys = safelyReflect(() => Reflect.ownKeys(input));
|
|
22
|
+
if (!keys.ok) return shallowFailure("invalid-value");
|
|
23
|
+
if (keys.value.length > maximumKeys) return shallowFailure("size-limit");
|
|
24
|
+
return readRecordDescriptors(input, keys.value);
|
|
25
|
+
}
|
|
26
|
+
function cloneSerializableData(input, limits = DEFAULT_SERIALIZABLE_LIMITS) {
|
|
27
|
+
const state = { limits, active: /* @__PURE__ */ new WeakSet(), nodes: 0 };
|
|
28
|
+
return cloneValue(input, Object.freeze([]), 0, state);
|
|
29
|
+
}
|
|
30
|
+
function cloneValue(input, path, depth, state) {
|
|
31
|
+
if (depth > state.limits.maxDepth) return failure("depth-limit", path);
|
|
32
|
+
if (typeof input === "string") return cloneString(input, path, state.limits);
|
|
33
|
+
if (input === null || typeof input === "boolean") return success(input);
|
|
34
|
+
if (typeof input === "number") {
|
|
35
|
+
return Number.isFinite(input) ? success(input) : failure("invalid-value", path);
|
|
36
|
+
}
|
|
37
|
+
if (typeof input !== "object") return failure("invalid-value", path);
|
|
38
|
+
const array = safelyReflect(() => Array.isArray(input));
|
|
39
|
+
if (!array.ok) return failure("invalid-value", path);
|
|
40
|
+
if (state.active.has(input)) return failure("cycle", path);
|
|
41
|
+
state.nodes += 1;
|
|
42
|
+
if (state.nodes > state.limits.maxNodes) return failure("size-limit", path);
|
|
43
|
+
state.active.add(input);
|
|
44
|
+
const result = array.value ? cloneArray(input, path, depth, state) : cloneRecord(input, path, depth, state);
|
|
45
|
+
state.active.delete(input);
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
function cloneArray(input, path, depth, state) {
|
|
49
|
+
const lengthDescriptor = ownDescriptor(input, "length");
|
|
50
|
+
if (!lengthDescriptor.ok) return failure("invalid-value", path);
|
|
51
|
+
if (!lengthDescriptor.value || !("value" in lengthDescriptor.value)) {
|
|
52
|
+
return failure("accessor", path);
|
|
53
|
+
}
|
|
54
|
+
const length = lengthDescriptor.value.value;
|
|
55
|
+
if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0 || length > state.limits.maxCollectionSize) {
|
|
56
|
+
return failure("size-limit", path);
|
|
57
|
+
}
|
|
58
|
+
const output = [];
|
|
59
|
+
for (let index = 0; index < length; index += 1) {
|
|
60
|
+
const descriptor = ownDescriptor(input, String(index));
|
|
61
|
+
const childPath = Object.freeze([...path, index]);
|
|
62
|
+
if (!descriptor.ok) return failure("invalid-value", childPath);
|
|
63
|
+
if (!descriptor.value || !("value" in descriptor.value)) return failure("accessor", childPath);
|
|
64
|
+
const cloned = cloneValue(descriptor.value.value, childPath, depth + 1, state);
|
|
65
|
+
if (!cloned.ok) return cloned;
|
|
66
|
+
output.push(cloned.value);
|
|
67
|
+
}
|
|
68
|
+
return success(Object.freeze(output));
|
|
69
|
+
}
|
|
70
|
+
function cloneRecord(input, path, depth, state) {
|
|
71
|
+
const inspected = readOwnDataRecord(input, state.limits.maxCollectionSize);
|
|
72
|
+
if (!inspected.ok) return failure(inspected.reason, path);
|
|
73
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
74
|
+
for (const [key, value] of Object.entries(inspected.value)) {
|
|
75
|
+
const keyResult = cloneString(key, path, state.limits);
|
|
76
|
+
if (!keyResult.ok) return keyResult;
|
|
77
|
+
const childPath = Object.freeze([...path, key]);
|
|
78
|
+
const cloned = cloneValue(value, childPath, depth + 1, state);
|
|
79
|
+
if (!cloned.ok) return cloned;
|
|
80
|
+
output[key] = cloned.value;
|
|
81
|
+
}
|
|
82
|
+
return success(Object.freeze(output));
|
|
83
|
+
}
|
|
84
|
+
function readRecordDescriptors(input, keys) {
|
|
85
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
86
|
+
for (const key of keys) {
|
|
87
|
+
if (typeof key !== "string") return shallowFailure("invalid-value");
|
|
88
|
+
const descriptor = ownDescriptor(input, key);
|
|
89
|
+
if (!descriptor.ok) return shallowFailure("invalid-value");
|
|
90
|
+
if (!descriptor.value || !("value" in descriptor.value)) return shallowFailure("accessor");
|
|
91
|
+
output[key] = descriptor.value.value;
|
|
92
|
+
}
|
|
93
|
+
return Object.freeze({ ok: true, value: output });
|
|
94
|
+
}
|
|
95
|
+
function ownDescriptor(input, key) {
|
|
96
|
+
return safelyReflect(() => Object.getOwnPropertyDescriptor(input, key));
|
|
97
|
+
}
|
|
98
|
+
function safelyReflect(operation) {
|
|
99
|
+
try {
|
|
100
|
+
return { ok: true, value: operation() };
|
|
101
|
+
} catch {
|
|
102
|
+
return { ok: false };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function shallowFailure(reason) {
|
|
106
|
+
return Object.freeze({ ok: false, reason });
|
|
107
|
+
}
|
|
108
|
+
function cloneString(input, path, limits) {
|
|
109
|
+
return input.length <= limits.maxStringLength ? success(input) : failure("size-limit", path);
|
|
110
|
+
}
|
|
111
|
+
function success(value) {
|
|
112
|
+
return Object.freeze({ ok: true, value });
|
|
113
|
+
}
|
|
114
|
+
function failure(reason, path) {
|
|
115
|
+
return Object.freeze({ ok: false, reason, path: Object.freeze([...path]) });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/compile-options.ts
|
|
119
|
+
var HOST_COMPILE_OPTIONS_CONTRACT = "kalada-host-compile-options-v1";
|
|
120
|
+
var MAXIMUM = Object.freeze({
|
|
121
|
+
maxAstDepth: 256,
|
|
122
|
+
maxAstNodes: 1e5,
|
|
123
|
+
maxValueDepth: 256,
|
|
124
|
+
maxValueNodes: 1e5,
|
|
125
|
+
maxStringLength: 1e6,
|
|
126
|
+
maxReferenceLength: 1e5,
|
|
127
|
+
maxEvaluationSteps: 1e5,
|
|
128
|
+
maxFunctionParameters: 256,
|
|
129
|
+
maxFunctionGroupSize: 1024,
|
|
130
|
+
maxCapturesPerClosure: 256,
|
|
131
|
+
maxCapturedBindings: 1e5,
|
|
132
|
+
maxClosures: 1e5,
|
|
133
|
+
maxCallDepth: 4096,
|
|
134
|
+
maxContinuationFrames: 1e5,
|
|
135
|
+
maxCollectionLength: 1e5,
|
|
136
|
+
maxCollectionIterations: 1e5
|
|
137
|
+
});
|
|
138
|
+
function normalizeCompileOptions(input) {
|
|
139
|
+
if (input === void 0) return frozenOptions("default", Object.freeze({}));
|
|
140
|
+
const inspected = readOwnDataRecord(input, 2);
|
|
141
|
+
if (!inspected.ok || hasUnknownKeys(inspected.value, ["profile", "limits"])) return null;
|
|
142
|
+
const profile = inspected.value.profile ?? "default";
|
|
143
|
+
if (typeof profile !== "string" || profile.length === 0 || profile.length > 1e3) return null;
|
|
144
|
+
const limits = normalizeLimits(inspected.value.limits);
|
|
145
|
+
return limits ? frozenOptions(profile, limits) : null;
|
|
146
|
+
}
|
|
147
|
+
function normalizeLimits(input) {
|
|
148
|
+
if (input === void 0) return Object.freeze({});
|
|
149
|
+
const inspected = readOwnDataRecord(input, Object.keys(MAXIMUM).length);
|
|
150
|
+
if (!inspected.ok) return null;
|
|
151
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
152
|
+
for (const [key, value] of Object.entries(inspected.value)) {
|
|
153
|
+
if (!Object.hasOwn(MAXIMUM, key) || !validLimit(key, value)) return null;
|
|
154
|
+
output[key] = value;
|
|
155
|
+
}
|
|
156
|
+
return Object.freeze(output);
|
|
157
|
+
}
|
|
158
|
+
function validLimit(key, value) {
|
|
159
|
+
return Number.isSafeInteger(value) && value >= 1 && value <= MAXIMUM[key];
|
|
160
|
+
}
|
|
161
|
+
function hasUnknownKeys(input, allowed) {
|
|
162
|
+
return Object.keys(input).some((key) => !allowed.includes(key));
|
|
163
|
+
}
|
|
164
|
+
function frozenOptions(profile, limits) {
|
|
165
|
+
return Object.freeze({ profile, limits });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/compiled-artifact.ts
|
|
169
|
+
var constructionToken = Object.freeze({});
|
|
170
|
+
var AuthenticCompiledExpression = class {
|
|
171
|
+
format = "kalada-host-compiled-expression-v1";
|
|
172
|
+
source;
|
|
173
|
+
parsed;
|
|
174
|
+
program;
|
|
175
|
+
sourceMap;
|
|
176
|
+
coreCompilation;
|
|
177
|
+
dependencies;
|
|
178
|
+
resultType;
|
|
179
|
+
compileProjectionFingerprint;
|
|
180
|
+
compileFingerprint;
|
|
181
|
+
#integrity;
|
|
182
|
+
constructor(token, input, core) {
|
|
183
|
+
if (token !== constructionToken) throw new TypeError("Invalid compiled artifact construction.");
|
|
184
|
+
this.source = input.source;
|
|
185
|
+
this.parsed = input.parsed;
|
|
186
|
+
this.program = input.program;
|
|
187
|
+
this.sourceMap = input.sourceMap;
|
|
188
|
+
this.coreCompilation = immutableCoreCompilation(core);
|
|
189
|
+
this.dependencies = this.coreCompilation.dependencies;
|
|
190
|
+
this.resultType = input.resultType;
|
|
191
|
+
this.compileProjectionFingerprint = input.compileProjectionFingerprint;
|
|
192
|
+
this.compileFingerprint = input.compileFingerprint;
|
|
193
|
+
this.#integrity = integrityRecord(this);
|
|
194
|
+
Object.freeze(this);
|
|
195
|
+
}
|
|
196
|
+
static authentic(input) {
|
|
197
|
+
if (typeof input !== "object" || input === null || !(#integrity in input)) return false;
|
|
198
|
+
return integrityMatches(input, input.#integrity);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
Object.freeze(AuthenticCompiledExpression.authentic);
|
|
202
|
+
Object.freeze(AuthenticCompiledExpression.prototype);
|
|
203
|
+
Object.freeze(AuthenticCompiledExpression);
|
|
204
|
+
function createCompiledArtifact(input, core) {
|
|
205
|
+
return new AuthenticCompiledExpression(constructionToken, input, core);
|
|
206
|
+
}
|
|
207
|
+
function isAuthenticCompiledExpression(input) {
|
|
208
|
+
return AuthenticCompiledExpression.authentic(input);
|
|
209
|
+
}
|
|
210
|
+
function immutableCoreCompilation(core) {
|
|
211
|
+
const evaluate = Object.freeze(
|
|
212
|
+
(resolve, inputs) => core.evaluate(resolve, inputs)
|
|
213
|
+
);
|
|
214
|
+
const evaluateWithClock = Object.freeze(
|
|
215
|
+
(resolve, clock) => core.evaluateWithClock(resolve, clock)
|
|
216
|
+
);
|
|
217
|
+
return Object.freeze({
|
|
218
|
+
program: core.program,
|
|
219
|
+
dependencies: core.dependencies,
|
|
220
|
+
functions: core.functions,
|
|
221
|
+
evaluate,
|
|
222
|
+
evaluateWithClock
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
function integrityRecord(input) {
|
|
226
|
+
return Object.freeze({
|
|
227
|
+
source: input.source,
|
|
228
|
+
parsed: input.parsed,
|
|
229
|
+
program: input.program,
|
|
230
|
+
sourceMap: input.sourceMap,
|
|
231
|
+
coreCompilation: input.coreCompilation,
|
|
232
|
+
dependencies: input.dependencies,
|
|
233
|
+
resultType: input.resultType,
|
|
234
|
+
compileProjectionFingerprint: input.compileProjectionFingerprint,
|
|
235
|
+
compileFingerprint: input.compileFingerprint
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function integrityMatches(input, expected) {
|
|
239
|
+
if (!Object.isFrozen(input) || input.format !== "kalada-host-compiled-expression-v1")
|
|
240
|
+
return false;
|
|
241
|
+
return Object.entries(expected).every(
|
|
242
|
+
([key, value]) => input[key] === value
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// src/execution-diagnostics.ts
|
|
247
|
+
var MESSAGES = Object.freeze({
|
|
248
|
+
HOST_PARSE_INVALID_SOURCE: "The expression source declaration is invalid.",
|
|
249
|
+
HOST_COMPILE_INVALID_OPTIONS: "The expression compile options are invalid.",
|
|
250
|
+
HOST_COMPILE_INVALID_PROJECTION: "The environment compile projection is invalid.",
|
|
251
|
+
HOST_LINK_INCOMPATIBLE_ENVIRONMENT: "The compiled expression is incompatible with the environment.",
|
|
252
|
+
HOST_LINK_MISSING_BINDING: "A compiled dependency is unavailable in the environment.",
|
|
253
|
+
HOST_LINK_INVALID_CAPABILITY: "A linked capability snapshot is invalid.",
|
|
254
|
+
HOST_LINK_ASYNC_UNSUPPORTED: "An asynchronous declaration is unsupported by synchronous execution.",
|
|
255
|
+
HOST_BINDING_MISSING: "A linked binding is not an own data property.",
|
|
256
|
+
HOST_BINDING_DECODE: "A linked binding could not be decoded synchronously.",
|
|
257
|
+
HOST_BINDING_CONVERSION: "A linked binding could not be converted synchronously.",
|
|
258
|
+
HOST_BINDING_SEMANTIC: "A linked binding is not a valid value of its semantic type."
|
|
259
|
+
});
|
|
260
|
+
function executionDiagnostic(code, phase, bindingPath, provenance) {
|
|
261
|
+
return Object.freeze({
|
|
262
|
+
code,
|
|
263
|
+
phase,
|
|
264
|
+
message: MESSAGES[code],
|
|
265
|
+
...bindingPath ? { bindingPath: Object.freeze([...bindingPath]) } : {},
|
|
266
|
+
...provenance ? { provenance: sanitizedProvenance(provenance) } : {}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
function syntaxDiagnostics(diagnostics, source) {
|
|
270
|
+
return Object.freeze(
|
|
271
|
+
diagnostics.map(
|
|
272
|
+
(cause) => Object.freeze({
|
|
273
|
+
code: cause.code,
|
|
274
|
+
phase: cause.phase === "lower" ? "lower" : "parse",
|
|
275
|
+
message: cause.message,
|
|
276
|
+
source: sourceLocation(source, cause.range),
|
|
277
|
+
cause
|
|
278
|
+
})
|
|
279
|
+
)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
function coreDiagnostic(phase, cause, source, sourceMap) {
|
|
283
|
+
const fallback = Object.freeze({ start: 0, end: source.text.length });
|
|
284
|
+
return Object.freeze({
|
|
285
|
+
code: cause.code,
|
|
286
|
+
phase,
|
|
287
|
+
message: cause.message,
|
|
288
|
+
source: sourceLocation(source, mappedRange(sourceMap, cause.path, fallback)),
|
|
289
|
+
cause
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
function mappedRange(entries, path, fallback) {
|
|
293
|
+
const exact = entries.filter((entry) => equalPath(entry.path, path)).sort(byNarrowest)[0];
|
|
294
|
+
if (exact) return exact.range;
|
|
295
|
+
for (let length = path.length - 1; length > 0; length -= 1) {
|
|
296
|
+
const found = entries.find(
|
|
297
|
+
(entry) => entry.role === "node" && equalPath(entry.path, path.slice(0, length))
|
|
298
|
+
);
|
|
299
|
+
if (found) return found.range;
|
|
300
|
+
}
|
|
301
|
+
return fallback;
|
|
302
|
+
}
|
|
303
|
+
function sourceLocation(source, range) {
|
|
304
|
+
return Object.freeze({
|
|
305
|
+
uri: source.uri,
|
|
306
|
+
range: Object.freeze({
|
|
307
|
+
start: positionAt(source.text, range.start),
|
|
308
|
+
end: positionAt(source.text, range.end)
|
|
309
|
+
})
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
function positionAt(source, offset) {
|
|
313
|
+
const prefix = source.slice(0, offset);
|
|
314
|
+
const lastBreak = prefix.lastIndexOf("\n");
|
|
315
|
+
return Object.freeze({
|
|
316
|
+
line: prefix.split("\n").length - 1,
|
|
317
|
+
character: offset - lastBreak - 1
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
function equalPath(left, right) {
|
|
321
|
+
return left.length === right.length && left.every((part, index) => part === right[index]);
|
|
322
|
+
}
|
|
323
|
+
function byNarrowest(left, right) {
|
|
324
|
+
return left.range.end - left.range.start - (right.range.end - right.range.start);
|
|
325
|
+
}
|
|
326
|
+
function sanitizedProvenance(input) {
|
|
327
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
328
|
+
for (const key of ["providerId", "providerVersion", "source", "extractor", "override"]) {
|
|
329
|
+
const value = input[key];
|
|
330
|
+
if (value !== void 0) output[key] = value;
|
|
331
|
+
}
|
|
332
|
+
return Object.freeze(output);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/fingerprint.ts
|
|
336
|
+
var HOST_COMPILE_FINGERPRINT_VERSION = "kalada-host-compile-fingerprint-v1";
|
|
337
|
+
var HOST_LINK_FINGERPRINT_VERSION = "kalada-host-link-fingerprint-v1";
|
|
338
|
+
function createFingerprint(marker, input) {
|
|
339
|
+
return `${marker}:sha256:${sha256(stableText(input))}`;
|
|
340
|
+
}
|
|
341
|
+
function stableText(input) {
|
|
342
|
+
if (input === null || typeof input === "boolean" || typeof input === "number") {
|
|
343
|
+
return JSON.stringify(input);
|
|
344
|
+
}
|
|
345
|
+
if (typeof input === "string") return JSON.stringify(input);
|
|
346
|
+
if (Array.isArray(input)) return `[${input.map(stableText).join(",")}]`;
|
|
347
|
+
if (typeof input !== "object") return JSON.stringify(String(input));
|
|
348
|
+
return stableRecord(input);
|
|
349
|
+
}
|
|
350
|
+
function stableRecord(input) {
|
|
351
|
+
return `{${Object.keys(input).sort().map((key) => `${JSON.stringify(key)}:${stableText(input[key])}`).join(",")}}`;
|
|
352
|
+
}
|
|
353
|
+
var ROUND_CONSTANTS = Object.freeze([
|
|
354
|
+
1116352408,
|
|
355
|
+
1899447441,
|
|
356
|
+
3049323471,
|
|
357
|
+
3921009573,
|
|
358
|
+
961987163,
|
|
359
|
+
1508970993,
|
|
360
|
+
2453635748,
|
|
361
|
+
2870763221,
|
|
362
|
+
3624381080,
|
|
363
|
+
310598401,
|
|
364
|
+
607225278,
|
|
365
|
+
1426881987,
|
|
366
|
+
1925078388,
|
|
367
|
+
2162078206,
|
|
368
|
+
2614888103,
|
|
369
|
+
3248222580,
|
|
370
|
+
3835390401,
|
|
371
|
+
4022224774,
|
|
372
|
+
264347078,
|
|
373
|
+
604807628,
|
|
374
|
+
770255983,
|
|
375
|
+
1249150122,
|
|
376
|
+
1555081692,
|
|
377
|
+
1996064986,
|
|
378
|
+
2554220882,
|
|
379
|
+
2821834349,
|
|
380
|
+
2952996808,
|
|
381
|
+
3210313671,
|
|
382
|
+
3336571891,
|
|
383
|
+
3584528711,
|
|
384
|
+
113926993,
|
|
385
|
+
338241895,
|
|
386
|
+
666307205,
|
|
387
|
+
773529912,
|
|
388
|
+
1294757372,
|
|
389
|
+
1396182291,
|
|
390
|
+
1695183700,
|
|
391
|
+
1986661051,
|
|
392
|
+
2177026350,
|
|
393
|
+
2456956037,
|
|
394
|
+
2730485921,
|
|
395
|
+
2820302411,
|
|
396
|
+
3259730800,
|
|
397
|
+
3345764771,
|
|
398
|
+
3516065817,
|
|
399
|
+
3600352804,
|
|
400
|
+
4094571909,
|
|
401
|
+
275423344,
|
|
402
|
+
430227734,
|
|
403
|
+
506948616,
|
|
404
|
+
659060556,
|
|
405
|
+
883997877,
|
|
406
|
+
958139571,
|
|
407
|
+
1322822218,
|
|
408
|
+
1537002063,
|
|
409
|
+
1747873779,
|
|
410
|
+
1955562222,
|
|
411
|
+
2024104815,
|
|
412
|
+
2227730452,
|
|
413
|
+
2361852424,
|
|
414
|
+
2428436474,
|
|
415
|
+
2756734187,
|
|
416
|
+
3204031479,
|
|
417
|
+
3329325298
|
|
418
|
+
]);
|
|
419
|
+
function sha256(input) {
|
|
420
|
+
const bytes = paddedBytes(new TextEncoder().encode(input));
|
|
421
|
+
const state = new Uint32Array([
|
|
422
|
+
1779033703,
|
|
423
|
+
3144134277,
|
|
424
|
+
1013904242,
|
|
425
|
+
2773480762,
|
|
426
|
+
1359893119,
|
|
427
|
+
2600822924,
|
|
428
|
+
528734635,
|
|
429
|
+
1541459225
|
|
430
|
+
]);
|
|
431
|
+
for (let offset = 0; offset < bytes.length; offset += 64) compress(bytes, offset, state);
|
|
432
|
+
return [...state].map((value) => value.toString(16).padStart(8, "0")).join("");
|
|
433
|
+
}
|
|
434
|
+
function paddedBytes(input) {
|
|
435
|
+
const length = Math.ceil((input.length + 9) / 64) * 64;
|
|
436
|
+
const output = new Uint8Array(length);
|
|
437
|
+
output.set(input);
|
|
438
|
+
output[input.length] = 128;
|
|
439
|
+
const bits = BigInt(input.length) * 8n;
|
|
440
|
+
for (let index = 0; index < 8; index += 1) {
|
|
441
|
+
output[length - 1 - index] = Number(bits >> BigInt(index * 8) & 0xffn);
|
|
442
|
+
}
|
|
443
|
+
return output;
|
|
444
|
+
}
|
|
445
|
+
function compress(bytes, offset, state) {
|
|
446
|
+
const words = new Uint32Array(64);
|
|
447
|
+
for (let index = 0; index < 16; index += 1) words[index] = readWord(bytes, offset + index * 4);
|
|
448
|
+
for (let index = 16; index < 64; index += 1) {
|
|
449
|
+
const first = words[index - 15];
|
|
450
|
+
const second = words[index - 2];
|
|
451
|
+
words[index] = add(
|
|
452
|
+
smallSigma0(first),
|
|
453
|
+
words[index - 16],
|
|
454
|
+
smallSigma1(second),
|
|
455
|
+
words[index - 7]
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
const working = [...state];
|
|
459
|
+
for (let index = 0; index < 64; index += 1) shaRound(working, words[index], index);
|
|
460
|
+
for (let index = 0; index < 8; index += 1) state[index] = add(state[index], working[index]);
|
|
461
|
+
}
|
|
462
|
+
function shaRound(working, word, index) {
|
|
463
|
+
const [a, b, c, d, e, f, g, h] = working;
|
|
464
|
+
const first = add(h, bigSigma1(e), e & f ^ ~e & g, ROUND_CONSTANTS[index], word);
|
|
465
|
+
const second = add(bigSigma0(a), a & b ^ a & c ^ b & c);
|
|
466
|
+
working[0] = add(first, second);
|
|
467
|
+
working[1] = a;
|
|
468
|
+
working[2] = b;
|
|
469
|
+
working[3] = c;
|
|
470
|
+
working[4] = add(d, first);
|
|
471
|
+
working[5] = e;
|
|
472
|
+
working[6] = f;
|
|
473
|
+
working[7] = g;
|
|
474
|
+
}
|
|
475
|
+
function readWord(bytes, offset) {
|
|
476
|
+
return bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3];
|
|
477
|
+
}
|
|
478
|
+
function add(...values) {
|
|
479
|
+
let result = 0;
|
|
480
|
+
for (const value of values) result = result + (value ?? 0) >>> 0;
|
|
481
|
+
return result;
|
|
482
|
+
}
|
|
483
|
+
function rotate(value, count) {
|
|
484
|
+
return value >>> count | value << 32 - count;
|
|
485
|
+
}
|
|
486
|
+
function smallSigma0(value) {
|
|
487
|
+
return rotate(value, 7) ^ rotate(value, 18) ^ value >>> 3;
|
|
488
|
+
}
|
|
489
|
+
function smallSigma1(value) {
|
|
490
|
+
return rotate(value, 17) ^ rotate(value, 19) ^ value >>> 10;
|
|
491
|
+
}
|
|
492
|
+
function bigSigma0(value) {
|
|
493
|
+
return rotate(value, 2) ^ rotate(value, 13) ^ rotate(value, 22);
|
|
494
|
+
}
|
|
495
|
+
function bigSigma1(value) {
|
|
496
|
+
return rotate(value, 6) ^ rotate(value, 11) ^ rotate(value, 25);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// src/input-readers.ts
|
|
500
|
+
function readArray(input, maximum) {
|
|
501
|
+
const result = readArrayPrefix(input, maximum);
|
|
502
|
+
return result && !result.truncated ? result.items : null;
|
|
503
|
+
}
|
|
504
|
+
function readArrayPrefix(input, maximum) {
|
|
505
|
+
if (!Array.isArray(input)) return null;
|
|
506
|
+
try {
|
|
507
|
+
const lengthDescriptor = Object.getOwnPropertyDescriptor(input, "length");
|
|
508
|
+
if (!lengthDescriptor || !("value" in lengthDescriptor)) return null;
|
|
509
|
+
const length = lengthDescriptor.value;
|
|
510
|
+
if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0 || !Number.isSafeInteger(maximum) || maximum < 0)
|
|
511
|
+
return null;
|
|
512
|
+
const output = [];
|
|
513
|
+
const readLength = Math.min(length, maximum);
|
|
514
|
+
for (let index = 0; index < readLength; index += 1) {
|
|
515
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, String(index));
|
|
516
|
+
if (!descriptor || !("value" in descriptor)) return null;
|
|
517
|
+
output.push(descriptor.value);
|
|
518
|
+
}
|
|
519
|
+
return Object.freeze({ items: Object.freeze(output), truncated: length > maximum });
|
|
520
|
+
} catch {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function readStringArray(input, maximum) {
|
|
525
|
+
const items = readArray(input, maximum);
|
|
526
|
+
if (!items || items.some((item) => !validName(item))) return null;
|
|
527
|
+
return Object.freeze(items);
|
|
528
|
+
}
|
|
529
|
+
function validName(input) {
|
|
530
|
+
return typeof input === "string" && input.length > 0 && input.length <= 256;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/semantic-type.ts
|
|
534
|
+
var primitiveNames = /* @__PURE__ */ new Set([
|
|
535
|
+
"null",
|
|
536
|
+
"boolean",
|
|
537
|
+
"number",
|
|
538
|
+
"string",
|
|
539
|
+
"json",
|
|
540
|
+
"Instant",
|
|
541
|
+
"Duration"
|
|
542
|
+
]);
|
|
543
|
+
function cloneSemanticType(input) {
|
|
544
|
+
if (input === "dynamic") return Object.freeze({ ok: true, value: "dynamic" });
|
|
545
|
+
const cloned = cloneSerializableData(input);
|
|
546
|
+
if (!cloned.ok || !isKaladaType(cloned.value, 0)) return Object.freeze({ ok: false });
|
|
547
|
+
return Object.freeze({ ok: true, value: cloned.value });
|
|
548
|
+
}
|
|
549
|
+
function readSemanticType(input) {
|
|
550
|
+
return cloneSemanticType(input);
|
|
551
|
+
}
|
|
552
|
+
function isKaladaType(input, depth) {
|
|
553
|
+
if (depth > 32) return false;
|
|
554
|
+
const inspected = readOwnDataRecord(input, 64);
|
|
555
|
+
if (!inspected.ok || typeof inspected.value.kind !== "string") return false;
|
|
556
|
+
const record = inspected.value;
|
|
557
|
+
if (record.kind === "primitive-type") return isPrimitive(record);
|
|
558
|
+
if (record.kind === "array-type") return isUnary(record, "element", depth);
|
|
559
|
+
if (record.kind === "option-type") return isUnary(record, "value", depth);
|
|
560
|
+
if (record.kind === "result-type") return isResult(record, depth);
|
|
561
|
+
if (record.kind === "function-type") return isFunction(record, depth);
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
function isPrimitive(record) {
|
|
565
|
+
return exactKeys(record, ["kind", "name"]) && primitiveNames.has(record.name);
|
|
566
|
+
}
|
|
567
|
+
function isUnary(record, field, depth) {
|
|
568
|
+
return exactKeys(record, ["kind", field]) && isKaladaType(record[field], depth + 1);
|
|
569
|
+
}
|
|
570
|
+
function isResult(record, depth) {
|
|
571
|
+
return exactKeys(record, ["kind", "ok", "error"]) && isKaladaType(record.ok, depth + 1) && isKaladaType(record.error, depth + 1);
|
|
572
|
+
}
|
|
573
|
+
function isFunction(record, depth) {
|
|
574
|
+
if (!exactKeys(record, ["kind", "parameters", "returns"])) return false;
|
|
575
|
+
if (!Array.isArray(record.parameters)) return false;
|
|
576
|
+
return record.parameters.every((parameter) => isKaladaType(parameter, depth + 1)) && isKaladaType(record.returns, depth + 1);
|
|
577
|
+
}
|
|
578
|
+
function exactKeys(record, expected) {
|
|
579
|
+
const keys = Object.keys(record);
|
|
580
|
+
return keys.length === expected.length && expected.every((key) => keys.includes(key));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// src/compile-expression.ts
|
|
584
|
+
var DEFAULT_URI = "memory:///expression.kalada";
|
|
585
|
+
var SYNTAX_CONTRACT = "kalada-syntax-lowering-result-v1";
|
|
586
|
+
var CORE_CONTRACT = "kalada-core-compiled-program-v1";
|
|
587
|
+
function parseExpression(source, options) {
|
|
588
|
+
const normalized = normalizeParseInput(source, options);
|
|
589
|
+
if (!normalized) return failed(executionDiagnostic("HOST_PARSE_INVALID_SOURCE", "parse"));
|
|
590
|
+
const syntax = parseKaladaV1Expression(source, normalized.syntax);
|
|
591
|
+
if (syntax.diagnostics.length > 0)
|
|
592
|
+
return failures(syntaxDiagnostics(syntax.diagnostics, normalized.source));
|
|
593
|
+
return success2(
|
|
594
|
+
Object.freeze({
|
|
595
|
+
format: "kalada-host-parsed-expression-v1",
|
|
596
|
+
source: normalized.source,
|
|
597
|
+
syntax,
|
|
598
|
+
parseFingerprintInput: normalized.fingerprintInput
|
|
599
|
+
})
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
function compileExpression(parsed, projection, options) {
|
|
603
|
+
const normalizedProjection = normalizeProjection(projection);
|
|
604
|
+
if (!normalizedProjection) {
|
|
605
|
+
return failed(executionDiagnostic("HOST_COMPILE_INVALID_PROJECTION", "compile"));
|
|
606
|
+
}
|
|
607
|
+
const normalizedOptions = normalizeCompileOptions(options);
|
|
608
|
+
if (!normalizedOptions)
|
|
609
|
+
return failed(executionDiagnostic("HOST_COMPILE_INVALID_OPTIONS", "compile"));
|
|
610
|
+
const references = Object.fromEntries(
|
|
611
|
+
normalizedProjection.bindings.map(({ id, name, semanticType }) => [
|
|
612
|
+
name,
|
|
613
|
+
Object.freeze({ reference: id, type: semanticType })
|
|
614
|
+
])
|
|
615
|
+
);
|
|
616
|
+
const lower = lowerKaladaV1Expression(parsed.syntax, {
|
|
617
|
+
references,
|
|
618
|
+
coreOptions: { limits: normalizedOptions.limits }
|
|
619
|
+
});
|
|
620
|
+
if (!lower.ok) return failures(syntaxDiagnostics(lower.diagnostics, parsed.source));
|
|
621
|
+
const core = compileKaladaV1Program(lower.program, { limits: normalizedOptions.limits });
|
|
622
|
+
if (!core.ok) {
|
|
623
|
+
return failed(coreDiagnostic("compile", core.diagnostic, parsed.source, lower.sourceMap));
|
|
624
|
+
}
|
|
625
|
+
return success2(
|
|
626
|
+
compiledArtifact(parsed, normalizedProjection, normalizedOptions, lower, core.value)
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
function compiledArtifact(parsed, projection, options, lower, core) {
|
|
630
|
+
const projectionFingerprint = createFingerprint(projection.format, projection);
|
|
631
|
+
const compileFingerprint = createFingerprint(HOST_COMPILE_FINGERPRINT_VERSION, {
|
|
632
|
+
syntaxContract: SYNTAX_CONTRACT,
|
|
633
|
+
coreContract: CORE_CONTRACT,
|
|
634
|
+
compileOptionsContract: HOST_COMPILE_OPTIONS_CONTRACT,
|
|
635
|
+
source: parsed.source,
|
|
636
|
+
parseOptions: parsed.parseFingerprintInput,
|
|
637
|
+
profile: options.profile,
|
|
638
|
+
limits: options.limits,
|
|
639
|
+
projection,
|
|
640
|
+
program: lower.program
|
|
641
|
+
});
|
|
642
|
+
return createCompiledArtifact(
|
|
643
|
+
{
|
|
644
|
+
source: parsed.source,
|
|
645
|
+
parsed,
|
|
646
|
+
program: lower.program,
|
|
647
|
+
sourceMap: lower.sourceMap,
|
|
648
|
+
resultType: lower.resultType,
|
|
649
|
+
compileProjectionFingerprint: projectionFingerprint,
|
|
650
|
+
compileFingerprint
|
|
651
|
+
},
|
|
652
|
+
core
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
function normalizeParseInput(source, options) {
|
|
656
|
+
if (typeof source !== "string") return null;
|
|
657
|
+
if (options === void 0) return parseInput(source, DEFAULT_URI, void 0);
|
|
658
|
+
const inspected = readOwnDataRecord(options, 4);
|
|
659
|
+
if (!inspected.ok) return null;
|
|
660
|
+
const uri = inspected.value.sourceUri ?? DEFAULT_URI;
|
|
661
|
+
if (typeof uri !== "string" || uri.length === 0) return null;
|
|
662
|
+
if (inspected.value.syntax === void 0) return parseInput(source, uri, void 0);
|
|
663
|
+
const cloned = cloneSerializableData(inspected.value.syntax);
|
|
664
|
+
if (!cloned.ok) return null;
|
|
665
|
+
return parseInput(source, uri, cloned.value);
|
|
666
|
+
}
|
|
667
|
+
function parseInput(text, uri, syntax) {
|
|
668
|
+
const source = Object.freeze({ uri, text });
|
|
669
|
+
const fingerprintInput = Object.freeze({ uri, syntax: syntax ?? null });
|
|
670
|
+
return { source, syntax, fingerprintInput };
|
|
671
|
+
}
|
|
672
|
+
function normalizeProjection(input) {
|
|
673
|
+
const cloned = cloneSerializableData(input);
|
|
674
|
+
if (!cloned.ok) return null;
|
|
675
|
+
const value = cloned.value;
|
|
676
|
+
if (value.format !== "kalada-host-compile-projection-v1" || !Array.isArray(value.bindings)) {
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
const identities = /* @__PURE__ */ new Set();
|
|
680
|
+
const names = /* @__PURE__ */ new Set();
|
|
681
|
+
const bindings = [];
|
|
682
|
+
for (const inputBinding of value.bindings) {
|
|
683
|
+
const inspected = readOwnDataRecord(inputBinding, 4);
|
|
684
|
+
if (!inspected.ok) return null;
|
|
685
|
+
const { id, name, semanticType } = inspected.value;
|
|
686
|
+
const semantic = cloneSemanticType(semanticType);
|
|
687
|
+
if (!validName(id) || !validName(name) || !semantic.ok) return null;
|
|
688
|
+
if (identities.has(id) || names.has(name)) return null;
|
|
689
|
+
identities.add(id);
|
|
690
|
+
names.add(name);
|
|
691
|
+
bindings.push(
|
|
692
|
+
Object.freeze({ id, name, semanticType: semantic.value })
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
return Object.freeze({
|
|
696
|
+
format: "kalada-host-compile-projection-v1",
|
|
697
|
+
bindings: Object.freeze(bindings)
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
function success2(value) {
|
|
701
|
+
return Object.freeze({ ok: true, value });
|
|
702
|
+
}
|
|
703
|
+
function failed(diagnostic) {
|
|
704
|
+
return failures([diagnostic]);
|
|
705
|
+
}
|
|
706
|
+
function failures(diagnostics) {
|
|
707
|
+
return Object.freeze({ ok: false, diagnostics: Object.freeze([...diagnostics]) });
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/editor-admission.ts
|
|
711
|
+
function calculateEditorGraphAdmission(request) {
|
|
712
|
+
const B = boundedCount(request.maxEdges);
|
|
713
|
+
const D = boundedCount(request.definitions);
|
|
714
|
+
const requestedChildren = boundedCount(request.children);
|
|
715
|
+
const V = boundedCount(request.resolutions);
|
|
716
|
+
const R = boundedCount(request.roots);
|
|
717
|
+
const Q = boundedCount(request.evidenceReserve ?? 0);
|
|
718
|
+
const fixed = D + V + R + Q;
|
|
719
|
+
const backboneAdmitted = fixed <= B;
|
|
720
|
+
const C = backboneAdmitted ? Math.min(requestedChildren, B - fixed) : 0;
|
|
721
|
+
const total = backboneAdmitted ? fixed + C : 0;
|
|
722
|
+
return Object.freeze({
|
|
723
|
+
model: Object.freeze({ B, D, C, V, R, Q }),
|
|
724
|
+
requestedChildren,
|
|
725
|
+
backboneAdmitted,
|
|
726
|
+
truncated: !backboneAdmitted || C < requestedChildren,
|
|
727
|
+
total,
|
|
728
|
+
remaining: B - total
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
function createEditorGraphEdgeMeter(maxEdges) {
|
|
732
|
+
const budget = boundedCount(maxEdges);
|
|
733
|
+
const counts = {
|
|
734
|
+
root: 0,
|
|
735
|
+
definition: 0,
|
|
736
|
+
child: 0,
|
|
737
|
+
resolution: 0
|
|
738
|
+
};
|
|
739
|
+
return Object.freeze({
|
|
740
|
+
claim(category) {
|
|
741
|
+
if (sumCounts(counts) >= budget) return false;
|
|
742
|
+
counts[category] += 1;
|
|
743
|
+
return true;
|
|
744
|
+
},
|
|
745
|
+
snapshot() {
|
|
746
|
+
const total = sumCounts(counts);
|
|
747
|
+
return Object.freeze({ budget, ...counts, total, remaining: budget - total });
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
function boundedCount(value) {
|
|
752
|
+
return Number.isSafeInteger(value) && value > 0 ? value : 0;
|
|
753
|
+
}
|
|
754
|
+
function sumCounts(counts) {
|
|
755
|
+
return counts.root + counts.definition + counts.child + counts.resolution;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// src/editor-cycle.ts
|
|
759
|
+
function markReferenceCycles(nodes, references) {
|
|
760
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
761
|
+
for (const reference of references) {
|
|
762
|
+
const node = nodes[reference.index];
|
|
763
|
+
if (node?.kind !== "reference" || !node.target) continue;
|
|
764
|
+
if (!isReachable(byId, node.target.nodeId, node.id)) continue;
|
|
765
|
+
nodes[reference.index] = {
|
|
766
|
+
...node,
|
|
767
|
+
target: cycleEdge(node.target)
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
function isReachable(nodes, start, target) {
|
|
772
|
+
const pending = [start];
|
|
773
|
+
const discovered = /* @__PURE__ */ new Set([start]);
|
|
774
|
+
while (pending.length > 0) {
|
|
775
|
+
const id = pending.pop();
|
|
776
|
+
if (!id) continue;
|
|
777
|
+
if (id === target) return true;
|
|
778
|
+
const node = nodes.get(id);
|
|
779
|
+
if (node) addUndiscovered(outgoingNodeIds(node), discovered, pending);
|
|
780
|
+
}
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
function addUndiscovered(next, discovered, pending) {
|
|
784
|
+
for (const id of next) {
|
|
785
|
+
if (discovered.has(id)) continue;
|
|
786
|
+
discovered.add(id);
|
|
787
|
+
pending.push(id);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
function outgoingNodeIds(node) {
|
|
791
|
+
const relations = (node.relations ?? []).map(({ nodeId }) => nodeId);
|
|
792
|
+
if (node.kind === "object") {
|
|
793
|
+
return [
|
|
794
|
+
...relations,
|
|
795
|
+
...node.properties.map(({ nodeId }) => nodeId),
|
|
796
|
+
...node.additionalProperties ? [node.additionalProperties.nodeId] : []
|
|
797
|
+
];
|
|
798
|
+
}
|
|
799
|
+
if (node.kind === "array") return [...relations, node.element.nodeId];
|
|
800
|
+
if (node.kind === "tuple") {
|
|
801
|
+
return [
|
|
802
|
+
...relations,
|
|
803
|
+
...node.items.map(({ nodeId }) => nodeId),
|
|
804
|
+
...node.rest ? [node.rest.nodeId] : []
|
|
805
|
+
];
|
|
806
|
+
}
|
|
807
|
+
if (node.kind === "union") return [...relations, ...node.variants.map(({ nodeId }) => nodeId)];
|
|
808
|
+
if (node.kind === "intersection")
|
|
809
|
+
return [...relations, ...node.operands.map(({ nodeId }) => nodeId)];
|
|
810
|
+
if (node.kind === "record") return [...relations, node.key.nodeId, node.value.nodeId];
|
|
811
|
+
if (node.kind === "wrapper") return [...relations, node.inner.nodeId];
|
|
812
|
+
if (node.kind === "reference" && node.target) return [...relations, node.target.nodeId];
|
|
813
|
+
return relations;
|
|
814
|
+
}
|
|
815
|
+
function cycleEdge(edge2) {
|
|
816
|
+
return Object.freeze({ nodeId: edge2.nodeId, path: edge2.path, cycle: true });
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// src/editor-node-builders.ts
|
|
820
|
+
function withNodeEvidence(node, record, path, context) {
|
|
821
|
+
const relations = relationEdges(record.relations, path, context);
|
|
822
|
+
if (!relations) return unknownNode(node.id, path, "invalid-shape");
|
|
823
|
+
const annotations = optionalData(record.annotations);
|
|
824
|
+
const constraints = optionalData(record.constraints);
|
|
825
|
+
if (!annotations.ok || !constraints.ok) return unknownNode(node.id, path, "invalid-shape");
|
|
826
|
+
return {
|
|
827
|
+
...node,
|
|
828
|
+
...validText(record.sourceId) ? { sourceId: record.sourceId } : {},
|
|
829
|
+
...annotations.value === void 0 ? {} : { annotations: annotations.value },
|
|
830
|
+
...constraints.value === void 0 ? {} : { constraints: constraints.value },
|
|
831
|
+
relations: Object.freeze(relations)
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function scalarNode(record, id, path) {
|
|
835
|
+
const names = [
|
|
836
|
+
"null",
|
|
837
|
+
"boolean",
|
|
838
|
+
"number",
|
|
839
|
+
"integer",
|
|
840
|
+
"string",
|
|
841
|
+
"undefined",
|
|
842
|
+
"void",
|
|
843
|
+
"bigint",
|
|
844
|
+
"symbol",
|
|
845
|
+
"date",
|
|
846
|
+
"NaN",
|
|
847
|
+
"json",
|
|
848
|
+
"instant",
|
|
849
|
+
"duration"
|
|
850
|
+
];
|
|
851
|
+
if (typeof record.name !== "string" || !names.includes(record.name)) {
|
|
852
|
+
return unknownNode(id, path, "invalid-shape");
|
|
853
|
+
}
|
|
854
|
+
return { id, path, kind: "scalar", name: record.name, ...available() };
|
|
855
|
+
}
|
|
856
|
+
function declaredUnknownNode(record, id, path) {
|
|
857
|
+
const reason = typeof record.reason === "string" ? record.reason.slice(0, 256) : void 0;
|
|
858
|
+
const code = validUnknownCode(record.evidenceCode) ? record.evidenceCode : "unsupported-shape";
|
|
859
|
+
return {
|
|
860
|
+
...unknownNode(id, path, code),
|
|
861
|
+
...reason === void 0 ? {} : { reason }
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
function validUnknownCode(value) {
|
|
865
|
+
return [
|
|
866
|
+
"invalid-shape",
|
|
867
|
+
"unsupported-shape",
|
|
868
|
+
"depth-limit",
|
|
869
|
+
"node-limit",
|
|
870
|
+
"edge-limit",
|
|
871
|
+
"unresolved-reference"
|
|
872
|
+
].includes(value);
|
|
873
|
+
}
|
|
874
|
+
function objectNode(record, id, path, context) {
|
|
875
|
+
const items = readArray(record.properties, context.maximumCollectionSize);
|
|
876
|
+
if (!items) return unknownNode(id, path, "invalid-shape");
|
|
877
|
+
const properties = [];
|
|
878
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
879
|
+
const property = propertyEdge(items[index], index, path, context);
|
|
880
|
+
if (!property) return partialObjectNode(id, path, properties);
|
|
881
|
+
properties.push(property);
|
|
882
|
+
}
|
|
883
|
+
const additionalProperties = optionalChild(record.additionalProperties, [...path, "*"], context);
|
|
884
|
+
if (additionalProperties === null) return partialObjectNode(id, path, properties);
|
|
885
|
+
const requiredNames = stringList(record.requiredNames);
|
|
886
|
+
if (!requiredNames) return unknownNode(id, path, "invalid-shape");
|
|
887
|
+
const unknownKeys = validUnknownKeys(record.unknownKeys) ? record.unknownKeys : void 0;
|
|
888
|
+
return {
|
|
889
|
+
id,
|
|
890
|
+
path,
|
|
891
|
+
kind: "object",
|
|
892
|
+
properties: Object.freeze(properties),
|
|
893
|
+
requiredNames: Object.freeze(requiredNames),
|
|
894
|
+
...additionalProperties ? { additionalProperties } : {},
|
|
895
|
+
...unknownKeys ? { unknownKeys } : {},
|
|
896
|
+
...available()
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
function propertyEdge(input, index, path, context) {
|
|
900
|
+
const inspected = readOwnDataRecord(input, 4);
|
|
901
|
+
const record = inspected.ok ? inspected.value : /* @__PURE__ */ Object.create(null);
|
|
902
|
+
const name = typeof record.name === "string" ? record.name : `<invalid:${index}>`;
|
|
903
|
+
const childPath = freezePath([...path, name]);
|
|
904
|
+
const child = context.child(record.shape, childPath);
|
|
905
|
+
const presence = readPresence(record);
|
|
906
|
+
return child ? Object.freeze({ ...child, name, required: presence === "required", presence }) : null;
|
|
907
|
+
}
|
|
908
|
+
function arrayNode(record, id, path, context) {
|
|
909
|
+
const element = context.child(record.element, freezePath([...path, "[]"]));
|
|
910
|
+
return element ? { id, path, kind: "array", element, ...available() } : unknownNode(id, path, "edge-limit");
|
|
911
|
+
}
|
|
912
|
+
function tupleNode(record, id, path, context) {
|
|
913
|
+
const sourceItems = readArray(record.items, context.maximumCollectionSize);
|
|
914
|
+
if (!sourceItems) return unknownNode(id, path, "invalid-shape");
|
|
915
|
+
const built = buildIndexedEdges(sourceItems, path, context);
|
|
916
|
+
if (!built.complete) return partialTupleNode(id, path, built.items);
|
|
917
|
+
const items = built.items;
|
|
918
|
+
if (record.rest === void 0) {
|
|
919
|
+
return { id, path, kind: "tuple", items: Object.freeze(items), ...available() };
|
|
920
|
+
}
|
|
921
|
+
const rest = context.child(record.rest, freezePath([...path, "..."]));
|
|
922
|
+
return rest ? { id, path, kind: "tuple", items: Object.freeze(items), rest, ...available() } : partialTupleNode(id, path, items);
|
|
923
|
+
}
|
|
924
|
+
function buildIndexedEdges(inputs, path, context) {
|
|
925
|
+
const items = [];
|
|
926
|
+
for (let index = 0; index < inputs.length; index += 1) {
|
|
927
|
+
const item = context.child(inputs[index], freezePath([...path, index]));
|
|
928
|
+
if (!item) return { complete: false, items };
|
|
929
|
+
items.push(item);
|
|
930
|
+
}
|
|
931
|
+
return { complete: true, items };
|
|
932
|
+
}
|
|
933
|
+
function unionNode(record, id, path, context) {
|
|
934
|
+
const inputs = readArray(record.variants, context.maximumCollectionSize);
|
|
935
|
+
if (!inputs) return unknownNode(id, path, "invalid-shape");
|
|
936
|
+
const variants = [];
|
|
937
|
+
for (let index = 0; index < inputs.length; index += 1) {
|
|
938
|
+
const variant = context.child(inputs[index], freezePath([...path, "$variant", index]));
|
|
939
|
+
if (!variant) return partialUnionNode(id, path, variants);
|
|
940
|
+
variants.push(variant);
|
|
941
|
+
}
|
|
942
|
+
const discriminator = optionalData(record.discriminator);
|
|
943
|
+
if (!discriminator.ok) return unknownNode(id, path, "invalid-shape");
|
|
944
|
+
return {
|
|
945
|
+
id,
|
|
946
|
+
path,
|
|
947
|
+
kind: "union",
|
|
948
|
+
variants: Object.freeze(variants),
|
|
949
|
+
...validText(record.semantics) ? { semantics: record.semantics } : {},
|
|
950
|
+
...discriminator.value === void 0 ? {} : { discriminator: discriminator.value },
|
|
951
|
+
...available()
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
function unknownNode(id, path, code) {
|
|
955
|
+
return {
|
|
956
|
+
id,
|
|
957
|
+
path,
|
|
958
|
+
kind: "unknown",
|
|
959
|
+
availability: "unknown",
|
|
960
|
+
evidence: evidence(code, path),
|
|
961
|
+
relations: Object.freeze([])
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
function evidence(code, path) {
|
|
965
|
+
return Object.freeze([Object.freeze({ code, path })]);
|
|
966
|
+
}
|
|
967
|
+
function partialObjectNode(id, path, properties) {
|
|
968
|
+
return {
|
|
969
|
+
id,
|
|
970
|
+
path,
|
|
971
|
+
kind: "object",
|
|
972
|
+
properties: Object.freeze(properties),
|
|
973
|
+
requiredNames: Object.freeze([]),
|
|
974
|
+
...unavailable("edge-limit", path)
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
function partialTupleNode(id, path, items) {
|
|
978
|
+
return {
|
|
979
|
+
id,
|
|
980
|
+
path,
|
|
981
|
+
kind: "tuple",
|
|
982
|
+
items: Object.freeze(items),
|
|
983
|
+
...unavailable("edge-limit", path)
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
function partialUnionNode(id, path, variants) {
|
|
987
|
+
return {
|
|
988
|
+
id,
|
|
989
|
+
path,
|
|
990
|
+
kind: "union",
|
|
991
|
+
variants: Object.freeze(variants),
|
|
992
|
+
...unavailable("edge-limit", path)
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
function available() {
|
|
996
|
+
return { availability: "available", evidence: Object.freeze([]), relations: Object.freeze([]) };
|
|
997
|
+
}
|
|
998
|
+
function unavailable(code, path) {
|
|
999
|
+
return {
|
|
1000
|
+
availability: "unknown",
|
|
1001
|
+
evidence: evidence(code, path),
|
|
1002
|
+
relations: Object.freeze([])
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
function freezePath(path) {
|
|
1006
|
+
return Object.freeze([...path]);
|
|
1007
|
+
}
|
|
1008
|
+
function readPresence(record) {
|
|
1009
|
+
if (["required", "optional", "unknown"].includes(record.presence)) {
|
|
1010
|
+
return record.presence;
|
|
1011
|
+
}
|
|
1012
|
+
return record.required === true ? "required" : "optional";
|
|
1013
|
+
}
|
|
1014
|
+
function optionalChild(value, path, context) {
|
|
1015
|
+
return value === void 0 ? void 0 : context.child(value, freezePath(path));
|
|
1016
|
+
}
|
|
1017
|
+
function optionalData(value) {
|
|
1018
|
+
if (value === void 0) return Object.freeze({ ok: true });
|
|
1019
|
+
const cloned = cloneSerializableData(value);
|
|
1020
|
+
return cloned.ok ? Object.freeze({ ok: true, value: cloned.value }) : Object.freeze({ ok: false });
|
|
1021
|
+
}
|
|
1022
|
+
function stringList(value) {
|
|
1023
|
+
if (value === void 0) return [];
|
|
1024
|
+
const items = readArray(value, 8192);
|
|
1025
|
+
return items?.every((item) => typeof item === "string") ? items : null;
|
|
1026
|
+
}
|
|
1027
|
+
function validUnknownKeys(value) {
|
|
1028
|
+
return ["strip", "reject", "passthrough", "schema", "unknown"].includes(value);
|
|
1029
|
+
}
|
|
1030
|
+
function validText(value) {
|
|
1031
|
+
return typeof value === "string" && value.length > 0 && value.length <= 1024;
|
|
1032
|
+
}
|
|
1033
|
+
function relationEdges(input, path, context) {
|
|
1034
|
+
if (input === void 0) return [];
|
|
1035
|
+
const items = readArray(input, context.maximumCollectionSize);
|
|
1036
|
+
if (!items) return null;
|
|
1037
|
+
const output = [];
|
|
1038
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
1039
|
+
const inspected = readOwnDataRecord(items[index], 4);
|
|
1040
|
+
if (!inspected.ok || !validText(inspected.value.name)) return null;
|
|
1041
|
+
const child = context.child(inspected.value.shape, freezePath([...path, "$relation", index]));
|
|
1042
|
+
if (!child) return null;
|
|
1043
|
+
const key = validText(inspected.value.key) ? inspected.value.key : void 0;
|
|
1044
|
+
output.push(Object.freeze({ ...child, name: inspected.value.name, ...key ? { key } : {} }));
|
|
1045
|
+
}
|
|
1046
|
+
return output;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/editor-evidence-builders.ts
|
|
1050
|
+
var available2 = Object.freeze({
|
|
1051
|
+
availability: "available",
|
|
1052
|
+
evidence: Object.freeze([]),
|
|
1053
|
+
relations: Object.freeze([])
|
|
1054
|
+
});
|
|
1055
|
+
function evidenceNode(record, id, path) {
|
|
1056
|
+
if (record.kind === "literal") return dataNode("literal", "value", record, id, path);
|
|
1057
|
+
if (record.kind === "enum") return enumNode(record, id, path);
|
|
1058
|
+
if (record.kind === "never") return { id, path, kind: "never", ...available2 };
|
|
1059
|
+
if (record.kind === "unconstrained") return unconstrainedNode(record, id, path);
|
|
1060
|
+
if (record.kind === "opaque") return opaqueNode(record, id, path);
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
function compositeEvidenceNode(record, id, path, context) {
|
|
1064
|
+
if (record.kind === "record") return recordNode(record, id, path, context);
|
|
1065
|
+
if (record.kind === "intersection") return intersectionNode(record, id, path, context);
|
|
1066
|
+
if (record.kind === "wrapper") return wrapperNode(record, id, path, context);
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
function dataNode(kind, field, record, id, path) {
|
|
1070
|
+
const cloned = cloneSerializableData(record[field]);
|
|
1071
|
+
return cloned.ok ? { id, path, kind, [field]: cloned.value, ...available2 } : unknownNode(id, path, "invalid-shape");
|
|
1072
|
+
}
|
|
1073
|
+
function enumNode(record, id, path) {
|
|
1074
|
+
const cloned = cloneSerializableData(record.values);
|
|
1075
|
+
if (!cloned.ok || !Array.isArray(cloned.value)) return unknownNode(id, path, "invalid-shape");
|
|
1076
|
+
return { id, path, kind: "enum", values: cloned.value, ...available2 };
|
|
1077
|
+
}
|
|
1078
|
+
function unconstrainedNode(record, id, path) {
|
|
1079
|
+
return record.domain === "json" || record.domain === "js" ? { id, path, kind: "unconstrained", domain: record.domain, ...available2 } : unknownNode(id, path, "invalid-shape");
|
|
1080
|
+
}
|
|
1081
|
+
function opaqueNode(record, id, path) {
|
|
1082
|
+
return typeof record.reason === "string" ? { id, path, kind: "opaque", reason: record.reason.slice(0, 256), ...available2 } : unknownNode(id, path, "invalid-shape");
|
|
1083
|
+
}
|
|
1084
|
+
function recordNode(record, id, path, context) {
|
|
1085
|
+
const key = context.child(record.key, Object.freeze([...path, "$key"]));
|
|
1086
|
+
const value = context.child(record.value, Object.freeze([...path, "$value"]));
|
|
1087
|
+
const exhaustive = record.exhaustive;
|
|
1088
|
+
if (!key || !value || exhaustive !== true && exhaustive !== false && exhaustive !== "unknown") {
|
|
1089
|
+
return unknownNode(id, path, "invalid-shape");
|
|
1090
|
+
}
|
|
1091
|
+
return { id, path, kind: "record", key, value, exhaustive, ...available2 };
|
|
1092
|
+
}
|
|
1093
|
+
function intersectionNode(record, id, path, context) {
|
|
1094
|
+
const operands = childList(record.operands, path, "$operand", context);
|
|
1095
|
+
return operands ? { id, path, kind: "intersection", operands: Object.freeze(operands), ...available2 } : unknownNode(id, path, "invalid-shape");
|
|
1096
|
+
}
|
|
1097
|
+
function wrapperNode(record, id, path, context) {
|
|
1098
|
+
const inner = context.child(record.inner, Object.freeze([...path, "$inner"]));
|
|
1099
|
+
if (!inner || typeof record.wrapper !== "string") return unknownNode(id, path, "invalid-shape");
|
|
1100
|
+
const value = record.value === void 0 ? void 0 : cloneSerializableData(record.value);
|
|
1101
|
+
if (value && !value.ok) return unknownNode(id, path, "invalid-shape");
|
|
1102
|
+
return {
|
|
1103
|
+
id,
|
|
1104
|
+
path,
|
|
1105
|
+
kind: "wrapper",
|
|
1106
|
+
wrapper: record.wrapper.slice(0, 256),
|
|
1107
|
+
inner,
|
|
1108
|
+
...value?.ok ? { value: value.value } : {},
|
|
1109
|
+
...available2
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
function childList(input, path, segment, context) {
|
|
1113
|
+
const items = readArray(input, context.maximumCollectionSize);
|
|
1114
|
+
if (!items) return null;
|
|
1115
|
+
const output = [];
|
|
1116
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
1117
|
+
const child = context.child(items[index], Object.freeze([...path, segment, index]));
|
|
1118
|
+
if (!child) return null;
|
|
1119
|
+
output.push(child);
|
|
1120
|
+
}
|
|
1121
|
+
return output;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// src/editor-input-validation.ts
|
|
1125
|
+
function validateEditorDocument(document) {
|
|
1126
|
+
const state = { seen: /* @__PURE__ */ new WeakSet(), nodes: 0 };
|
|
1127
|
+
if (!validateShape(document.root, 0, state)) return false;
|
|
1128
|
+
const definitions = readArray(document.definitions ?? [], 2048);
|
|
1129
|
+
if (!definitions) return false;
|
|
1130
|
+
for (const definition of definitions) {
|
|
1131
|
+
const inspected = readOwnDataRecord(definition, 3);
|
|
1132
|
+
if (!inspected.ok || !validateShape(inspected.value.shape, 0, state)) return false;
|
|
1133
|
+
}
|
|
1134
|
+
return true;
|
|
1135
|
+
}
|
|
1136
|
+
function readEditorEvidence(value) {
|
|
1137
|
+
const items = readArray(value, 8192) ?? [];
|
|
1138
|
+
const allowed = [
|
|
1139
|
+
"invalid-shape",
|
|
1140
|
+
"unsupported-shape",
|
|
1141
|
+
"depth-limit",
|
|
1142
|
+
"node-limit",
|
|
1143
|
+
"edge-limit",
|
|
1144
|
+
"unresolved-reference"
|
|
1145
|
+
];
|
|
1146
|
+
return items.filter(
|
|
1147
|
+
(item) => typeof item === "string" && allowed.includes(item)
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
function validateShape(input, depth, state) {
|
|
1151
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) return false;
|
|
1152
|
+
if (state.seen.has(input)) return true;
|
|
1153
|
+
state.nodes += 1;
|
|
1154
|
+
if (depth > 32 || state.nodes > 2048) return true;
|
|
1155
|
+
state.seen.add(input);
|
|
1156
|
+
const inspected = readOwnDataRecord(input, 8192);
|
|
1157
|
+
if (!inspected.ok) return false;
|
|
1158
|
+
const record = inspected.value;
|
|
1159
|
+
if (!validateRelations(record.relations, depth, state)) return false;
|
|
1160
|
+
if (record.kind === "object") return validateObject(record, depth, state);
|
|
1161
|
+
if (record.kind === "array") return validateShape(record.element, depth + 1, state);
|
|
1162
|
+
if (record.kind === "tuple") return validateTuple(record, depth, state);
|
|
1163
|
+
if (record.kind === "union") return validateCollection(record.variants, depth, state);
|
|
1164
|
+
if (record.kind === "intersection") return validateCollection(record.operands, depth, state);
|
|
1165
|
+
if (record.kind === "record") {
|
|
1166
|
+
return validateShape(record.key, depth + 1, state) && validateShape(record.value, depth + 1, state);
|
|
1167
|
+
}
|
|
1168
|
+
if (record.kind === "wrapper") return validateShape(record.inner, depth + 1, state);
|
|
1169
|
+
return true;
|
|
1170
|
+
}
|
|
1171
|
+
function validateObject(record, depth, state) {
|
|
1172
|
+
if (!validateProperties(record.properties, depth, state)) return false;
|
|
1173
|
+
return record.additionalProperties === void 0 || validateShape(record.additionalProperties, depth + 1, state);
|
|
1174
|
+
}
|
|
1175
|
+
function validateRelations(input, depth, state) {
|
|
1176
|
+
if (input === void 0) return true;
|
|
1177
|
+
const relations = readArray(input, 8192);
|
|
1178
|
+
if (!relations) return false;
|
|
1179
|
+
for (const relation of relations) {
|
|
1180
|
+
const inspected = readOwnDataRecord(relation, 4);
|
|
1181
|
+
if (!inspected.ok || !validateShape(inspected.value.shape, depth + 1, state)) return false;
|
|
1182
|
+
}
|
|
1183
|
+
return true;
|
|
1184
|
+
}
|
|
1185
|
+
function validateProperties(input, depth, state) {
|
|
1186
|
+
const properties = readArray(input, 8192);
|
|
1187
|
+
if (!properties) return false;
|
|
1188
|
+
for (const property of properties) {
|
|
1189
|
+
const inspected = readOwnDataRecord(property, 4);
|
|
1190
|
+
if (!inspected.ok || !validateShape(inspected.value.shape, depth + 1, state)) return false;
|
|
1191
|
+
}
|
|
1192
|
+
return true;
|
|
1193
|
+
}
|
|
1194
|
+
function validateTuple(record, depth, state) {
|
|
1195
|
+
if (!validateCollection(record.items, depth, state)) return false;
|
|
1196
|
+
return record.rest === void 0 || validateShape(record.rest, depth + 1, state);
|
|
1197
|
+
}
|
|
1198
|
+
function validateCollection(input, depth, state) {
|
|
1199
|
+
const items = readArray(input, 8192);
|
|
1200
|
+
if (!items) return false;
|
|
1201
|
+
return items.every((item) => validateShape(item, depth + 1, state));
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// src/editor-graph.ts
|
|
1205
|
+
var DEFAULT_EDITOR_GRAPH_LIMITS = Object.freeze({
|
|
1206
|
+
maxDepth: 32,
|
|
1207
|
+
maxNodes: 2048,
|
|
1208
|
+
maxEdges: 8192
|
|
1209
|
+
});
|
|
1210
|
+
function createEditorGraph(inputs, requestedLimits = {}) {
|
|
1211
|
+
let limits = DEFAULT_EDITOR_GRAPH_LIMITS;
|
|
1212
|
+
try {
|
|
1213
|
+
const normalized = normalizeLimits2(requestedLimits);
|
|
1214
|
+
if (!normalized) return invalidGraph(limits);
|
|
1215
|
+
limits = normalized;
|
|
1216
|
+
return buildGraph(inputs, limits);
|
|
1217
|
+
} catch {
|
|
1218
|
+
return invalidGraph(limits);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
function buildGraph(inputs, limits) {
|
|
1222
|
+
const sourceDocuments = readArrayPrefix(inputs, limits.maxEdges + 1);
|
|
1223
|
+
if (!sourceDocuments) return invalidGraph(limits, "invalid-shape");
|
|
1224
|
+
const state = createState(limits);
|
|
1225
|
+
const roots = [];
|
|
1226
|
+
const definitions = [];
|
|
1227
|
+
const targets = /* @__PURE__ */ new Map();
|
|
1228
|
+
for (const input of sourceDocuments.items) {
|
|
1229
|
+
const inspected = readGraphInput(input);
|
|
1230
|
+
if (!inspected) return invalidGraph(limits, "invalid-shape");
|
|
1231
|
+
addDocument(inspected, state, roots, definitions, targets);
|
|
1232
|
+
}
|
|
1233
|
+
if (sourceDocuments.truncated) recordEvidence("edge-limit", Object.freeze([]), state);
|
|
1234
|
+
resolveReferences(state, targets);
|
|
1235
|
+
markReferenceCycles(state.nodes, state.references);
|
|
1236
|
+
const nodes = state.nodes.map((node) => Object.freeze(node));
|
|
1237
|
+
return Object.freeze({
|
|
1238
|
+
format: "kalada-editor-graph-v1",
|
|
1239
|
+
nodeIdScope: "document-local",
|
|
1240
|
+
limits,
|
|
1241
|
+
roots: Object.freeze(roots),
|
|
1242
|
+
nodes: Object.freeze(nodes),
|
|
1243
|
+
definitions: Object.freeze(definitions),
|
|
1244
|
+
evidence: Object.freeze(state.evidence),
|
|
1245
|
+
admission: state.meter.snapshot()
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
function invalidGraph(limits, code = "invalid-shape") {
|
|
1249
|
+
const path = Object.freeze([]);
|
|
1250
|
+
const node = Object.freeze(unknownNode("n0", path, code));
|
|
1251
|
+
const root = Object.freeze({ ...edge("n0", path, false), bindingId: "<invalid>" });
|
|
1252
|
+
return Object.freeze({
|
|
1253
|
+
format: "kalada-editor-graph-v1",
|
|
1254
|
+
nodeIdScope: "document-local",
|
|
1255
|
+
limits,
|
|
1256
|
+
roots: Object.freeze([root]),
|
|
1257
|
+
nodes: Object.freeze([node]),
|
|
1258
|
+
definitions: Object.freeze([]),
|
|
1259
|
+
evidence: evidence(code, path),
|
|
1260
|
+
admission: createEditorGraphEdgeMeter(limits.maxEdges).snapshot()
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
function createState(limits) {
|
|
1264
|
+
return {
|
|
1265
|
+
limits,
|
|
1266
|
+
nodes: [],
|
|
1267
|
+
active: /* @__PURE__ */ new WeakMap(),
|
|
1268
|
+
references: [],
|
|
1269
|
+
evidence: [],
|
|
1270
|
+
meter: createEditorGraphEdgeMeter(limits.maxEdges)
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
function addDocument(input, state, roots, definitions, targets) {
|
|
1274
|
+
const path = freezePath2(input.path);
|
|
1275
|
+
if (!claimEdge("root", path, state)) return;
|
|
1276
|
+
const root = addNode(input.document.root, path, 0, input.bindingId, state);
|
|
1277
|
+
roots.push(Object.freeze({ ...root, bindingId: input.bindingId }));
|
|
1278
|
+
const bindingTargets = /* @__PURE__ */ new Map();
|
|
1279
|
+
targets.set(input.bindingId, bindingTargets);
|
|
1280
|
+
const sourceDefinitions = readArrayPrefix(
|
|
1281
|
+
input.document.definitions ?? [],
|
|
1282
|
+
state.limits.maxEdges + 1
|
|
1283
|
+
);
|
|
1284
|
+
if (!sourceDefinitions) {
|
|
1285
|
+
recordEvidence("invalid-shape", path, state);
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
for (const definition of sourceDefinitions.items) {
|
|
1289
|
+
const inspected = readDefinition(definition);
|
|
1290
|
+
if (!inspected) {
|
|
1291
|
+
recordEvidence("invalid-shape", path, state);
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1294
|
+
addDefinition(input, inspected, state, definitions, bindingTargets);
|
|
1295
|
+
}
|
|
1296
|
+
if (sourceDefinitions.truncated) recordEvidence("edge-limit", path, state);
|
|
1297
|
+
for (const code of input.document.evidence ?? []) recordEvidence(code, path, state);
|
|
1298
|
+
}
|
|
1299
|
+
function addDefinition(input, definition, state, definitions, targets) {
|
|
1300
|
+
const path = freezePath2([...input.path, "$defs", definition.name]);
|
|
1301
|
+
if (!claimEdge("definition", path, state)) return;
|
|
1302
|
+
const edge2 = addNode(definition.shape, path, 0, input.bindingId, state);
|
|
1303
|
+
const item = Object.freeze({
|
|
1304
|
+
bindingId: input.bindingId,
|
|
1305
|
+
name: definition.name,
|
|
1306
|
+
nodeId: edge2.nodeId,
|
|
1307
|
+
path
|
|
1308
|
+
});
|
|
1309
|
+
definitions.push(item);
|
|
1310
|
+
if (!targets.has(definition.name)) targets.set(definition.name, edge2.nodeId);
|
|
1311
|
+
}
|
|
1312
|
+
function addNode(shape, path, depth, bindingId, state) {
|
|
1313
|
+
if (depth > state.limits.maxDepth) return unknownEdge("depth-limit", path, state);
|
|
1314
|
+
if (typeof shape !== "object" || shape === null || Array.isArray(shape)) {
|
|
1315
|
+
return unknownEdge("invalid-shape", path, state);
|
|
1316
|
+
}
|
|
1317
|
+
const prior = state.active.get(shape);
|
|
1318
|
+
if (prior) return edge(prior, path, true);
|
|
1319
|
+
if (state.nodes.length >= state.limits.maxNodes - 1)
|
|
1320
|
+
return unknownEdge("node-limit", path, state);
|
|
1321
|
+
const id = `n${state.nodes.length}`;
|
|
1322
|
+
state.active.set(shape, id);
|
|
1323
|
+
const index = state.nodes.length;
|
|
1324
|
+
state.nodes.push(unknownNode(id, path, "invalid-shape"));
|
|
1325
|
+
state.nodes[index] = readNode(shape, id, path, depth, bindingId, state);
|
|
1326
|
+
state.active.delete(shape);
|
|
1327
|
+
return edge(id, path, false);
|
|
1328
|
+
}
|
|
1329
|
+
function readNode(shape, id, path, depth, bindingId, state) {
|
|
1330
|
+
const inspected = readOwnDataRecord(shape, state.limits.maxEdges);
|
|
1331
|
+
if (!inspected.ok) return unknownNode(id, path, "invalid-shape");
|
|
1332
|
+
const record = inspected.value;
|
|
1333
|
+
const context = nodeContext(depth, bindingId, state);
|
|
1334
|
+
const node = buildNode(record, id, path, bindingId, state, context);
|
|
1335
|
+
return withNodeEvidence(node, record, path, context);
|
|
1336
|
+
}
|
|
1337
|
+
function buildNode(record, id, path, bindingId, state, context) {
|
|
1338
|
+
if (record.kind === "scalar") return scalarNode(record, id, path);
|
|
1339
|
+
if (record.kind === "unknown") return declaredUnknownNode(record, id, path);
|
|
1340
|
+
if (record.kind === "object") return objectNode(record, id, path, context);
|
|
1341
|
+
if (record.kind === "array") return arrayNode(record, id, path, context);
|
|
1342
|
+
if (record.kind === "tuple") return tupleNode(record, id, path, context);
|
|
1343
|
+
if (record.kind === "union") return unionNode(record, id, path, context);
|
|
1344
|
+
if (record.kind === "reference") return referenceNode(record, id, path, bindingId, state);
|
|
1345
|
+
return evidenceNode(record, id, path) ?? compositeEvidenceNode(record, id, path, context) ?? unknownNode(id, path, "unsupported-shape");
|
|
1346
|
+
}
|
|
1347
|
+
function nodeContext(depth, bindingId, state) {
|
|
1348
|
+
return {
|
|
1349
|
+
maximumCollectionSize: state.limits.maxEdges + 1,
|
|
1350
|
+
child: (shape, path) => childEdge(shape, path, depth, bindingId, state)
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
function referenceNode(record, id, path, bindingId, state) {
|
|
1354
|
+
if (typeof record.definition !== "string" || record.definition.length === 0) {
|
|
1355
|
+
return unknownNode(id, path, "invalid-shape");
|
|
1356
|
+
}
|
|
1357
|
+
const unresolved = typeof record.unresolved === "string" ? record.unresolved : void 0;
|
|
1358
|
+
const node = {
|
|
1359
|
+
id,
|
|
1360
|
+
path,
|
|
1361
|
+
kind: "reference",
|
|
1362
|
+
definition: record.definition,
|
|
1363
|
+
status: "unresolved",
|
|
1364
|
+
availability: unresolved === void 0 ? "unknown" : "unavailable",
|
|
1365
|
+
evidence: evidence("unresolved-reference", path),
|
|
1366
|
+
relations: Object.freeze([]),
|
|
1367
|
+
...typeof record.reference === "string" ? { reference: record.reference } : {},
|
|
1368
|
+
...unresolved === void 0 ? {} : { unresolved }
|
|
1369
|
+
};
|
|
1370
|
+
state.references.push({ index: state.nodes.length - 1, bindingId });
|
|
1371
|
+
return node;
|
|
1372
|
+
}
|
|
1373
|
+
function childEdge(shape, path, depth, bindingId, state) {
|
|
1374
|
+
if (!claimEdge("child", path, state)) return null;
|
|
1375
|
+
return addNode(shape, path, depth + 1, bindingId, state);
|
|
1376
|
+
}
|
|
1377
|
+
function unknownEdge(code, path, state) {
|
|
1378
|
+
if (state.limitNodeIndex !== void 0) {
|
|
1379
|
+
const index = state.limitNodeIndex;
|
|
1380
|
+
appendUnknownEvidence(index, code, path, state);
|
|
1381
|
+
return edge(`n${index}`, path, false);
|
|
1382
|
+
}
|
|
1383
|
+
const id = `n${state.nodes.length}`;
|
|
1384
|
+
state.limitNodeIndex = state.nodes.length;
|
|
1385
|
+
state.nodes.push(unknownNode(id, path, code));
|
|
1386
|
+
return edge(id, path, false);
|
|
1387
|
+
}
|
|
1388
|
+
function appendUnknownEvidence(index, code, path, state) {
|
|
1389
|
+
const node = state.nodes[index];
|
|
1390
|
+
if (node?.kind !== "unknown" || node.evidence.length >= state.limits.maxEdges) return;
|
|
1391
|
+
if (node.evidence.some((item2) => item2.code === code && samePath(item2.path, path))) return;
|
|
1392
|
+
const item = Object.freeze({ code, path: freezePath2(path) });
|
|
1393
|
+
state.nodes[index] = { ...node, evidence: Object.freeze([...node.evidence, item]) };
|
|
1394
|
+
}
|
|
1395
|
+
function resolveReferences(state, targets) {
|
|
1396
|
+
for (const reference of state.references) {
|
|
1397
|
+
const node = state.nodes[reference.index];
|
|
1398
|
+
if (node?.kind !== "reference" || node.unresolved !== void 0) continue;
|
|
1399
|
+
const target = targets.get(reference.bindingId)?.get(node.definition);
|
|
1400
|
+
if (!target) continue;
|
|
1401
|
+
if (!claimEdge("resolution", node.path, state)) {
|
|
1402
|
+
state.nodes[reference.index] = {
|
|
1403
|
+
...node,
|
|
1404
|
+
evidence: evidence("edge-limit", node.path)
|
|
1405
|
+
};
|
|
1406
|
+
continue;
|
|
1407
|
+
}
|
|
1408
|
+
state.nodes[reference.index] = {
|
|
1409
|
+
...node,
|
|
1410
|
+
status: "resolved",
|
|
1411
|
+
target: edge(target, node.path, false),
|
|
1412
|
+
availability: "available",
|
|
1413
|
+
evidence: Object.freeze([])
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
function edge(nodeId, path, cycle) {
|
|
1418
|
+
return Object.freeze({ nodeId, path, cycle });
|
|
1419
|
+
}
|
|
1420
|
+
function claimEdge(category, path, state) {
|
|
1421
|
+
if (!state.meter.claim(category)) {
|
|
1422
|
+
recordEvidence("edge-limit", path, state);
|
|
1423
|
+
return false;
|
|
1424
|
+
}
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
function recordEvidence(code, path, state) {
|
|
1428
|
+
if (state.evidence.length >= state.limits.maxEdges) return;
|
|
1429
|
+
if (state.evidence.some((item) => item.code === code && samePath(item.path, path))) return;
|
|
1430
|
+
state.evidence.push(Object.freeze({ code, path: freezePath2(path) }));
|
|
1431
|
+
}
|
|
1432
|
+
function samePath(left, right) {
|
|
1433
|
+
return left.length === right.length && left.every((part, index) => part === right[index]);
|
|
1434
|
+
}
|
|
1435
|
+
function readGraphInput(input) {
|
|
1436
|
+
const inspected = readOwnDataRecord(input, 4);
|
|
1437
|
+
if (!inspected.ok || typeof inspected.value.bindingId !== "string") return null;
|
|
1438
|
+
const path = readArray(inspected.value.path, 256);
|
|
1439
|
+
const document = readOwnDataRecord(inspected.value.document, 4);
|
|
1440
|
+
if (!path || !document.ok || document.value.root === void 0) return null;
|
|
1441
|
+
if (!path.every((part) => typeof part === "string" || typeof part === "number")) return null;
|
|
1442
|
+
return {
|
|
1443
|
+
bindingId: inspected.value.bindingId,
|
|
1444
|
+
path: freezePath2(path),
|
|
1445
|
+
document: {
|
|
1446
|
+
root: document.value.root,
|
|
1447
|
+
definitions: document.value.definitions,
|
|
1448
|
+
evidence: readEditorEvidence(document.value.evidence)
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
function readDefinition(input) {
|
|
1453
|
+
const inspected = readOwnDataRecord(input, 3);
|
|
1454
|
+
if (!inspected.ok || typeof inspected.value.name !== "string") return null;
|
|
1455
|
+
return Object.freeze({ name: inspected.value.name, shape: inspected.value.shape });
|
|
1456
|
+
}
|
|
1457
|
+
function freezePath2(path) {
|
|
1458
|
+
return Object.freeze([...path]);
|
|
1459
|
+
}
|
|
1460
|
+
function normalizeLimits2(input) {
|
|
1461
|
+
const inspected = readOwnDataRecord(input, 3);
|
|
1462
|
+
if (!inspected.ok) return null;
|
|
1463
|
+
const record = inspected.value;
|
|
1464
|
+
return Object.freeze({
|
|
1465
|
+
maxDepth: positiveInteger(record.maxDepth, DEFAULT_EDITOR_GRAPH_LIMITS.maxDepth),
|
|
1466
|
+
maxNodes: positiveInteger(record.maxNodes, DEFAULT_EDITOR_GRAPH_LIMITS.maxNodes),
|
|
1467
|
+
maxEdges: positiveInteger(record.maxEdges, DEFAULT_EDITOR_GRAPH_LIMITS.maxEdges)
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
function positiveInteger(input, fallback) {
|
|
1471
|
+
return typeof input === "number" && Number.isSafeInteger(input) && input > 0 ? input : fallback;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// src/editor-traversal.ts
|
|
1475
|
+
function traverseEditorGraph(graph, options = {}) {
|
|
1476
|
+
const state = {
|
|
1477
|
+
nodes: new Map(graph.nodes.map((node) => [node.id, node])),
|
|
1478
|
+
steps: [],
|
|
1479
|
+
active: /* @__PURE__ */ new Set(),
|
|
1480
|
+
maxDepth: bounded(options.maxDepth, graph.limits.maxDepth),
|
|
1481
|
+
maxVisits: bounded(options.maxVisits, graph.limits.maxEdges + graph.limits.maxNodes)
|
|
1482
|
+
};
|
|
1483
|
+
for (const root of graph.roots) {
|
|
1484
|
+
walk(root, "root", 0, state);
|
|
1485
|
+
if (state.steps.length >= state.maxVisits) break;
|
|
1486
|
+
}
|
|
1487
|
+
return Object.freeze(state.steps);
|
|
1488
|
+
}
|
|
1489
|
+
function walk(edge2, via, depth, state) {
|
|
1490
|
+
if (depth > state.maxDepth || state.steps.length >= state.maxVisits) return;
|
|
1491
|
+
const node = state.nodes.get(edge2.nodeId);
|
|
1492
|
+
if (!node) return;
|
|
1493
|
+
const cycle = state.active.has(edge2.nodeId);
|
|
1494
|
+
state.steps.push(
|
|
1495
|
+
Object.freeze({
|
|
1496
|
+
nodeId: edge2.nodeId,
|
|
1497
|
+
path: Object.freeze([...edge2.path]),
|
|
1498
|
+
depth,
|
|
1499
|
+
via,
|
|
1500
|
+
cycle,
|
|
1501
|
+
availability: node.availability
|
|
1502
|
+
})
|
|
1503
|
+
);
|
|
1504
|
+
if (cycle || depth === state.maxDepth) return;
|
|
1505
|
+
state.active.add(edge2.nodeId);
|
|
1506
|
+
walkChildren(node, depth, state);
|
|
1507
|
+
state.active.delete(edge2.nodeId);
|
|
1508
|
+
}
|
|
1509
|
+
function walkChildren(node, depth, state) {
|
|
1510
|
+
for (const relation of node.relations ?? []) walk(relation, "relation", depth + 1, state);
|
|
1511
|
+
if (node.kind === "object") {
|
|
1512
|
+
for (const property of node.properties) walk(property, "property", depth + 1, state);
|
|
1513
|
+
if (node.additionalProperties) {
|
|
1514
|
+
walk(node.additionalProperties, "additional-property", depth + 1, state);
|
|
1515
|
+
}
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
if (node.kind === "array") {
|
|
1519
|
+
walk(node.element, "element", depth + 1, state);
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
if (node.kind === "tuple") {
|
|
1523
|
+
walkTuple(node, depth, state);
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
if (node.kind === "union") {
|
|
1527
|
+
for (const variant of node.variants) walk(variant, "variant", depth + 1, state);
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
walkComposite(node, depth, state);
|
|
1531
|
+
}
|
|
1532
|
+
function walkComposite(node, depth, state) {
|
|
1533
|
+
if (node.kind === "intersection") {
|
|
1534
|
+
for (const operand of node.operands) walk(operand, "operand", depth + 1, state);
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
if (node.kind === "record") {
|
|
1538
|
+
walk(node.key, "record-key", depth + 1, state);
|
|
1539
|
+
walk(node.value, "record-value", depth + 1, state);
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
if (node.kind === "wrapper") {
|
|
1543
|
+
walk(node.inner, "wrapper", depth + 1, state);
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
if (node.kind === "reference" && node.target) {
|
|
1547
|
+
walk(node.target, "reference", depth + 1, state);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
function walkTuple(node, depth, state) {
|
|
1551
|
+
for (const item of node.items) walk(item, "item", depth + 1, state);
|
|
1552
|
+
if (node.rest) walk(node.rest, "rest", depth + 1, state);
|
|
1553
|
+
}
|
|
1554
|
+
function bounded(input, fallback) {
|
|
1555
|
+
if (typeof input !== "number" || !Number.isSafeInteger(input) || input < 0) return fallback;
|
|
1556
|
+
return Math.min(input, fallback);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
// src/capability-snapshot.ts
|
|
1560
|
+
var constructionToken2 = Object.freeze({});
|
|
1561
|
+
var AuthenticCapabilitySnapshot = class {
|
|
1562
|
+
scope = "instance";
|
|
1563
|
+
capabilities;
|
|
1564
|
+
#environment;
|
|
1565
|
+
constructor(token, environment, capabilities) {
|
|
1566
|
+
if (token !== constructionToken2)
|
|
1567
|
+
throw new TypeError("Invalid capability snapshot construction.");
|
|
1568
|
+
this.#environment = environment;
|
|
1569
|
+
this.capabilities = capabilities;
|
|
1570
|
+
Object.freeze(this);
|
|
1571
|
+
}
|
|
1572
|
+
static compatible(input, environment) {
|
|
1573
|
+
if (typeof input !== "object" || input === null || !(#environment in input)) return false;
|
|
1574
|
+
if (input.#environment === environment) return true;
|
|
1575
|
+
return cacheableEquivalent(input.#environment, environment);
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
Object.freeze(AuthenticCapabilitySnapshot.compatible);
|
|
1579
|
+
Object.freeze(AuthenticCapabilitySnapshot.prototype);
|
|
1580
|
+
Object.freeze(AuthenticCapabilitySnapshot);
|
|
1581
|
+
function createCapabilitySnapshot(environment, capabilities) {
|
|
1582
|
+
return new AuthenticCapabilitySnapshot(constructionToken2, environment, capabilities);
|
|
1583
|
+
}
|
|
1584
|
+
function capabilitySnapshotMatches(snapshot, environment) {
|
|
1585
|
+
return AuthenticCapabilitySnapshot.compatible(snapshot, environment);
|
|
1586
|
+
}
|
|
1587
|
+
function cacheableEquivalent(left, right) {
|
|
1588
|
+
if (!left.cacheability.cacheable || !right.cacheability.cacheable) return false;
|
|
1589
|
+
return JSON.stringify(left.provider.identity) === JSON.stringify(right.provider.identity) && JSON.stringify(left.capabilities) === JSON.stringify(right.capabilities);
|
|
1590
|
+
}
|
|
1591
|
+
function canonicalValue(input) {
|
|
1592
|
+
try {
|
|
1593
|
+
const value = decodeKaladaValue(encodeKaladaValue(input));
|
|
1594
|
+
return Object.freeze({ ok: true, value });
|
|
1595
|
+
} catch {
|
|
1596
|
+
return Object.freeze({ ok: false });
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
function matchesSemanticType(value, expected) {
|
|
1600
|
+
if (expected === "dynamic") return true;
|
|
1601
|
+
return matchesKnownType(value, expected);
|
|
1602
|
+
}
|
|
1603
|
+
function matchesKnownType(value, expected) {
|
|
1604
|
+
if (expected.kind === "primitive-type") return matchesPrimitive(value, expected.name);
|
|
1605
|
+
if (expected.kind === "array-type") {
|
|
1606
|
+
return Array.isArray(value) && value.every((item) => matchesKnownType(item, expected.element));
|
|
1607
|
+
}
|
|
1608
|
+
if (expected.kind === "option-type") {
|
|
1609
|
+
return isOption(value) && (value.variant === "none" || matchesKnownType(value.value, expected.value));
|
|
1610
|
+
}
|
|
1611
|
+
if (expected.kind === "result-type") {
|
|
1612
|
+
return isResult$1(value) && matchesKnownType(value.value, value.variant === "ok" ? expected.ok : expected.error);
|
|
1613
|
+
}
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1616
|
+
function matchesPrimitive(value, name) {
|
|
1617
|
+
if (name === "json") {
|
|
1618
|
+
return !isOption(value) && !isResult$1(value) && !isInstant(value) && !isDuration(value);
|
|
1619
|
+
}
|
|
1620
|
+
if (name === "Instant") return isInstant(value);
|
|
1621
|
+
if (name === "Duration") return isDuration(value);
|
|
1622
|
+
if (name === "null") return value === null;
|
|
1623
|
+
return typeof value === name;
|
|
1624
|
+
}
|
|
1625
|
+
function isThenableWithoutGet(input) {
|
|
1626
|
+
if ((typeof input !== "object" || input === null) && typeof input !== "function") return false;
|
|
1627
|
+
let current = input;
|
|
1628
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1629
|
+
try {
|
|
1630
|
+
while (current !== null && !visited.has(current)) {
|
|
1631
|
+
visited.add(current);
|
|
1632
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, "then");
|
|
1633
|
+
if (descriptor) return !("value" in descriptor) || typeof descriptor.value === "function";
|
|
1634
|
+
current = Object.getPrototypeOf(current);
|
|
1635
|
+
}
|
|
1636
|
+
return false;
|
|
1637
|
+
} catch {
|
|
1638
|
+
return true;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
function readOwnValue(input, name) {
|
|
1642
|
+
if ((typeof input !== "object" || input === null) && typeof input !== "function") {
|
|
1643
|
+
return Object.freeze({ ok: false });
|
|
1644
|
+
}
|
|
1645
|
+
try {
|
|
1646
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, name);
|
|
1647
|
+
if (!descriptor || !("value" in descriptor)) return Object.freeze({ ok: false });
|
|
1648
|
+
return Object.freeze({ ok: true, value: descriptor.value });
|
|
1649
|
+
} catch {
|
|
1650
|
+
return Object.freeze({ ok: false });
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// src/evaluate-expression.ts
|
|
1655
|
+
function evaluateLinked(compiled, slots, values) {
|
|
1656
|
+
const bound = /* @__PURE__ */ new Map();
|
|
1657
|
+
for (const slot of slots) {
|
|
1658
|
+
const result = bindSlot(slot, values);
|
|
1659
|
+
if (!result.ok) return result;
|
|
1660
|
+
bound.set(slot.plan.bindingId, result.value);
|
|
1661
|
+
}
|
|
1662
|
+
const outcome = compiled.coreCompilation.evaluate(
|
|
1663
|
+
(reference) => bound.has(reference) ? Object.freeze({ found: true, value: bound.get(reference) }) : Object.freeze({ found: false, reason: "missing" })
|
|
1664
|
+
);
|
|
1665
|
+
if (!outcome.ok) {
|
|
1666
|
+
return failure2(
|
|
1667
|
+
coreDiagnostic("evaluate", outcome.diagnostic, compiled.source, compiled.sourceMap)
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
return Object.freeze({ ok: true, value: outcome.value });
|
|
1671
|
+
}
|
|
1672
|
+
function bindSlot(slot, values) {
|
|
1673
|
+
const input = readOwnValue(values, slot.plan.name);
|
|
1674
|
+
if (!input.ok) return bindingFailure("HOST_BINDING_MISSING", slot);
|
|
1675
|
+
const decoded = invokeValidator(slot, input.value);
|
|
1676
|
+
if (!decoded.ok) return decoded;
|
|
1677
|
+
const converted = invokeCodec(slot, decoded.value);
|
|
1678
|
+
if (!converted.ok) return converted;
|
|
1679
|
+
const canonical = canonicalValue(converted.value);
|
|
1680
|
+
if (!canonical.ok || !matchesSemanticType(canonical.value, slot.plan.semanticType)) {
|
|
1681
|
+
return bindingFailure("HOST_BINDING_SEMANTIC", slot);
|
|
1682
|
+
}
|
|
1683
|
+
return Object.freeze({ ok: true, value: canonical.value });
|
|
1684
|
+
}
|
|
1685
|
+
function invokeValidator(slot, value) {
|
|
1686
|
+
if (!slot.validator) return Object.freeze({ ok: true, value });
|
|
1687
|
+
try {
|
|
1688
|
+
const output = slot.validator.decode(value);
|
|
1689
|
+
return isThenableWithoutGet(output) ? bindingFailure("HOST_BINDING_DECODE", slot) : Object.freeze({ ok: true, value: output });
|
|
1690
|
+
} catch {
|
|
1691
|
+
return bindingFailure("HOST_BINDING_DECODE", slot);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
function invokeCodec(slot, value) {
|
|
1695
|
+
if (!slot.codec) return Object.freeze({ ok: true, value });
|
|
1696
|
+
try {
|
|
1697
|
+
const output = slot.codec.convert(value);
|
|
1698
|
+
return isThenableWithoutGet(output) ? bindingFailure("HOST_BINDING_CONVERSION", slot) : Object.freeze({ ok: true, value: output });
|
|
1699
|
+
} catch {
|
|
1700
|
+
return bindingFailure("HOST_BINDING_CONVERSION", slot);
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
function bindingFailure(code, slot) {
|
|
1704
|
+
return failure2(executionDiagnostic(code, "bind", slot.plan.path, slot.provenance));
|
|
1705
|
+
}
|
|
1706
|
+
function failure2(diagnostic) {
|
|
1707
|
+
return Object.freeze({ ok: false, diagnostics: Object.freeze([diagnostic]) });
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
// src/link-expression.ts
|
|
1711
|
+
function linkExpression(compiled, environment, snapshot) {
|
|
1712
|
+
try {
|
|
1713
|
+
if (!isAuthenticCompiledExpression(compiled)) return incompatible();
|
|
1714
|
+
if (!compatibleProjection(compiled, environment)) return incompatible();
|
|
1715
|
+
if (!capabilitySnapshotMatches(snapshot, environment)) return invalidSnapshot();
|
|
1716
|
+
if (environment.provider.mode === "async") return asyncUnsupported();
|
|
1717
|
+
const slots = [];
|
|
1718
|
+
for (const dependency of compiled.dependencies) {
|
|
1719
|
+
const binding = environment.bindings.find(({ id }) => id === dependency);
|
|
1720
|
+
if (!binding) return missingBinding();
|
|
1721
|
+
const linked = linkSlot(binding, slots.length, snapshot);
|
|
1722
|
+
if (!linked.ok) return linked.result;
|
|
1723
|
+
slots.push(linked.slot);
|
|
1724
|
+
}
|
|
1725
|
+
return linkedArtifact(compiled, environment, slots);
|
|
1726
|
+
} catch {
|
|
1727
|
+
return incompatible();
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
function linkSlot(binding, index, snapshot) {
|
|
1731
|
+
if (binding.validator?.mode === "async" || binding.codec?.mode === "async") {
|
|
1732
|
+
return Object.freeze({ ok: false, result: asyncUnsupported(binding) });
|
|
1733
|
+
}
|
|
1734
|
+
const validator = resolveCapability(binding.validator, snapshot);
|
|
1735
|
+
const codec = resolveCapability(binding.codec, snapshot);
|
|
1736
|
+
if (validator === null || codec === null || validator && validator.kind !== "validator" || codec && codec.kind !== "codec") {
|
|
1737
|
+
return Object.freeze({ ok: false, result: invalidCapability(binding) });
|
|
1738
|
+
}
|
|
1739
|
+
const plan = createPlan(binding, index);
|
|
1740
|
+
return Object.freeze({
|
|
1741
|
+
ok: true,
|
|
1742
|
+
slot: Object.freeze({ plan, validator, codec, provenance: binding.provenance[0] })
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
function resolveCapability(declaration, snapshot) {
|
|
1746
|
+
if (!declaration) return void 0;
|
|
1747
|
+
if (snapshot.scope !== "instance") return null;
|
|
1748
|
+
const descriptor = Object.getOwnPropertyDescriptor(snapshot.capabilities, declaration.handle);
|
|
1749
|
+
if (!descriptor || !("value" in descriptor)) return null;
|
|
1750
|
+
const live = descriptor.value;
|
|
1751
|
+
if (!sameDeclaration(live, declaration)) return null;
|
|
1752
|
+
if (live.kind === "validator" && typeof live.decode !== "function") return null;
|
|
1753
|
+
if (live.kind === "codec" && typeof live.convert !== "function") return null;
|
|
1754
|
+
return live;
|
|
1755
|
+
}
|
|
1756
|
+
function sameDeclaration(live, expected) {
|
|
1757
|
+
return live.handle === expected.handle && live.kind === expected.kind && live.mode === expected.mode && live.capabilityId === expected.capabilityId && live.capabilityVersion === expected.capabilityVersion && live.configurationDigest === expected.configurationDigest && JSON.stringify(live.identity) === JSON.stringify(expected.identity);
|
|
1758
|
+
}
|
|
1759
|
+
function createPlan(binding, index) {
|
|
1760
|
+
return Object.freeze({
|
|
1761
|
+
index,
|
|
1762
|
+
bindingId: binding.id,
|
|
1763
|
+
name: binding.name,
|
|
1764
|
+
path: Object.freeze([...binding.path]),
|
|
1765
|
+
semanticType: binding.semanticType,
|
|
1766
|
+
...binding.validator ? { validator: binding.validator } : {},
|
|
1767
|
+
...binding.codec ? { codec: binding.codec } : {}
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
function linkedArtifact(compiled, environment, slots) {
|
|
1771
|
+
const internal = Object.freeze([...slots]);
|
|
1772
|
+
const linkPlan = Object.freeze(slots.map(({ plan }) => plan));
|
|
1773
|
+
const linkFingerprint = reusable(environment) ? createFingerprint(
|
|
1774
|
+
HOST_LINK_FINGERPRINT_VERSION,
|
|
1775
|
+
linkFingerprintInput(compiled, environment, linkPlan)
|
|
1776
|
+
) : void 0;
|
|
1777
|
+
const evaluate = Object.freeze((values) => evaluateLinked(compiled, internal, values));
|
|
1778
|
+
const prepared = Object.freeze({
|
|
1779
|
+
format: "kalada-host-prepared-expression-v1",
|
|
1780
|
+
compiled,
|
|
1781
|
+
environment,
|
|
1782
|
+
linkPlan,
|
|
1783
|
+
...linkFingerprint ? { linkFingerprint } : {},
|
|
1784
|
+
evaluate
|
|
1785
|
+
});
|
|
1786
|
+
return Object.freeze({ ok: true, value: prepared });
|
|
1787
|
+
}
|
|
1788
|
+
function compatibleProjection(compiled, environment) {
|
|
1789
|
+
if (compiled.format !== "kalada-host-compiled-expression-v1") return false;
|
|
1790
|
+
if (environment.format !== "kalada-host-environment-v1") return false;
|
|
1791
|
+
return compiled.compileProjectionFingerprint === createFingerprint(environment.compileProjection.format, environment.compileProjection);
|
|
1792
|
+
}
|
|
1793
|
+
function reusable(environment) {
|
|
1794
|
+
return environment.cacheability.cacheable;
|
|
1795
|
+
}
|
|
1796
|
+
function linkFingerprintInput(compiled, environment, linkPlan) {
|
|
1797
|
+
return {
|
|
1798
|
+
compileFingerprint: compiled.compileFingerprint,
|
|
1799
|
+
provider: environment.provider.identity,
|
|
1800
|
+
bindings: environment.bindings.map(({ id, name, path, editorShapeRoot, validator, codec }) => ({
|
|
1801
|
+
id,
|
|
1802
|
+
name,
|
|
1803
|
+
path,
|
|
1804
|
+
editorShapeRoot,
|
|
1805
|
+
validator,
|
|
1806
|
+
codec
|
|
1807
|
+
})),
|
|
1808
|
+
editorGraph: environment.editorGraph,
|
|
1809
|
+
linkPlan
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
function incompatible() {
|
|
1813
|
+
return failure3(executionDiagnostic("HOST_LINK_INCOMPATIBLE_ENVIRONMENT", "link"));
|
|
1814
|
+
}
|
|
1815
|
+
function missingBinding() {
|
|
1816
|
+
return failure3(executionDiagnostic("HOST_LINK_MISSING_BINDING", "link"));
|
|
1817
|
+
}
|
|
1818
|
+
function invalidCapability(binding) {
|
|
1819
|
+
return failure3(bindingDiagnostic("HOST_LINK_INVALID_CAPABILITY", binding));
|
|
1820
|
+
}
|
|
1821
|
+
function invalidSnapshot() {
|
|
1822
|
+
return failure3(executionDiagnostic("HOST_LINK_INVALID_CAPABILITY", "link"));
|
|
1823
|
+
}
|
|
1824
|
+
function asyncUnsupported(binding) {
|
|
1825
|
+
return failure3(
|
|
1826
|
+
binding ? bindingDiagnostic("HOST_LINK_ASYNC_UNSUPPORTED", binding) : executionDiagnostic("HOST_LINK_ASYNC_UNSUPPORTED", "link")
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
function bindingDiagnostic(code, binding) {
|
|
1830
|
+
return executionDiagnostic(code, "link", binding.path, binding.provenance[0]);
|
|
1831
|
+
}
|
|
1832
|
+
function failure3(diagnostic) {
|
|
1833
|
+
return Object.freeze({ ok: false, diagnostics: Object.freeze([diagnostic]) });
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
// src/diagnostics.ts
|
|
1837
|
+
var messages = Object.freeze({
|
|
1838
|
+
HOST_ENVIRONMENT_INVALID_PROVIDER: "The manual provider declaration is invalid.",
|
|
1839
|
+
HOST_ENVIRONMENT_INVALID_IDENTITY: "A stable identity declaration is invalid.",
|
|
1840
|
+
HOST_ENVIRONMENT_INVALID_CAPABILITY: "A capability declaration is invalid.",
|
|
1841
|
+
HOST_ENVIRONMENT_DUPLICATE_CAPABILITY: "A capability handle is duplicated.",
|
|
1842
|
+
HOST_ENVIRONMENT_INVALID_BINDING: "A binding declaration is invalid.",
|
|
1843
|
+
HOST_ENVIRONMENT_DUPLICATE_BINDING: "A binding identity or path is duplicated.",
|
|
1844
|
+
HOST_ENVIRONMENT_INVALID_SEMANTIC_TYPE: "A binding semantic projection is invalid.",
|
|
1845
|
+
HOST_ENVIRONMENT_INVALID_METADATA: "Binding metadata is not bounded serializable data.",
|
|
1846
|
+
HOST_ENVIRONMENT_INVALID_PROVENANCE: "Binding provenance is invalid.",
|
|
1847
|
+
HOST_ENVIRONMENT_UNKNOWN_CAPABILITY: "A binding references an unavailable capability handle."
|
|
1848
|
+
});
|
|
1849
|
+
function environmentDiagnostic(code, bindingPath, provenance) {
|
|
1850
|
+
const diagnostic = {
|
|
1851
|
+
code,
|
|
1852
|
+
phase: "environment",
|
|
1853
|
+
message: messages[code],
|
|
1854
|
+
...bindingPath ? { bindingPath: Object.freeze([...bindingPath]) } : {},
|
|
1855
|
+
...provenance ? { provenance: sanitizeProvenance(provenance) } : {}
|
|
1856
|
+
};
|
|
1857
|
+
return Object.freeze(diagnostic);
|
|
1858
|
+
}
|
|
1859
|
+
function sanitizeProvenance(input) {
|
|
1860
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
1861
|
+
for (const key of ["providerId", "providerVersion", "source", "extractor", "override"]) {
|
|
1862
|
+
const value = input[key];
|
|
1863
|
+
if (value !== void 0) output[key] = value;
|
|
1864
|
+
}
|
|
1865
|
+
return Object.freeze(output);
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
// src/binding-normalization.ts
|
|
1869
|
+
function normalizeBindings(input, capabilities, providerProvenance2) {
|
|
1870
|
+
const state = {
|
|
1871
|
+
bindings: [],
|
|
1872
|
+
graphInputs: [],
|
|
1873
|
+
diagnostics: [],
|
|
1874
|
+
providerProvenance: providerProvenance2
|
|
1875
|
+
};
|
|
1876
|
+
const items = readArray(input, 1e4);
|
|
1877
|
+
if (!items) {
|
|
1878
|
+
state.diagnostics.push(environmentDiagnostic("HOST_ENVIRONMENT_INVALID_PROVIDER"));
|
|
1879
|
+
return state;
|
|
1880
|
+
}
|
|
1881
|
+
const identities = /* @__PURE__ */ new Set();
|
|
1882
|
+
const names = /* @__PURE__ */ new Set();
|
|
1883
|
+
const paths = /* @__PURE__ */ new Set();
|
|
1884
|
+
for (const item of items) addBinding(item, capabilities, identities, names, paths, state);
|
|
1885
|
+
return state;
|
|
1886
|
+
}
|
|
1887
|
+
function addBinding(input, capabilities, identities, names, paths, state) {
|
|
1888
|
+
const inspected = readOwnDataRecord(input, 16);
|
|
1889
|
+
if (!inspected.ok) {
|
|
1890
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_BINDING");
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
const record = inspected.value;
|
|
1894
|
+
const path = readStringArray(record.path, 64);
|
|
1895
|
+
if (!validName(record.id) || !validName(record.name) || !path) {
|
|
1896
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_BINDING");
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
if (identities.has(record.id) || names.has(record.name) || paths.has(JSON.stringify(path))) {
|
|
1900
|
+
bindingError(state, "HOST_ENVIRONMENT_DUPLICATE_BINDING", path);
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
identities.add(record.id);
|
|
1904
|
+
names.add(record.name);
|
|
1905
|
+
paths.add(JSON.stringify(path));
|
|
1906
|
+
addValidBinding(record, path, capabilities, state);
|
|
1907
|
+
}
|
|
1908
|
+
function addValidBinding(record, path, capabilities, state) {
|
|
1909
|
+
const semantic = cloneSemanticType(record.semanticType);
|
|
1910
|
+
if (!semantic.ok) {
|
|
1911
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_SEMANTIC_TYPE", path);
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
const metadata = normalizeMetadata(record.metadata, path, state);
|
|
1915
|
+
if (!metadata.ok) return;
|
|
1916
|
+
const provenance = normalizeProvenance(record.provenance, path, state);
|
|
1917
|
+
if (!provenance) return;
|
|
1918
|
+
const refs = resolveCapabilityRefs(record, capabilities, path, state);
|
|
1919
|
+
if (!refs) return;
|
|
1920
|
+
const editor = normalizeEditorDocument(record.editorShape, record.id, path, state);
|
|
1921
|
+
if (editor === null) return;
|
|
1922
|
+
state.bindings.push(makeBinding(record, path, semantic.value, metadata.value, provenance, refs));
|
|
1923
|
+
if (editor) state.graphInputs.push(editor);
|
|
1924
|
+
}
|
|
1925
|
+
function makeBinding(record, path, semanticType, metadata, provenance, refs) {
|
|
1926
|
+
return Object.freeze({
|
|
1927
|
+
id: record.id,
|
|
1928
|
+
name: record.name,
|
|
1929
|
+
path,
|
|
1930
|
+
semanticType,
|
|
1931
|
+
...refs,
|
|
1932
|
+
...metadata === void 0 ? {} : { metadata },
|
|
1933
|
+
provenance
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
function normalizeMetadata(input, path, state) {
|
|
1937
|
+
if (input === void 0) return { ok: true, value: void 0 };
|
|
1938
|
+
const cloned = cloneSerializableData(input);
|
|
1939
|
+
if (cloned.ok) return { ok: true, value: cloned.value };
|
|
1940
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_METADATA", path);
|
|
1941
|
+
return { ok: false };
|
|
1942
|
+
}
|
|
1943
|
+
function normalizeProvenance(input, path, state) {
|
|
1944
|
+
const base = state.providerProvenance;
|
|
1945
|
+
if (input === void 0) return Object.freeze([base]);
|
|
1946
|
+
const items = readArray(input, 256);
|
|
1947
|
+
if (!items) return provenanceError(state, path);
|
|
1948
|
+
const entries = [base];
|
|
1949
|
+
for (const item of items) {
|
|
1950
|
+
const entry = readProvenance(item);
|
|
1951
|
+
if (!entry) return provenanceError(state, path);
|
|
1952
|
+
entries.push(entry);
|
|
1953
|
+
}
|
|
1954
|
+
return Object.freeze(entries);
|
|
1955
|
+
}
|
|
1956
|
+
function readProvenance(input) {
|
|
1957
|
+
const inspected = readOwnDataRecord(input, 8);
|
|
1958
|
+
if (!inspected.ok || !validName(inspected.value.providerId)) return null;
|
|
1959
|
+
const record = inspected.value;
|
|
1960
|
+
const providerId = record.providerId;
|
|
1961
|
+
for (const key of ["providerVersion", "source", "extractor", "override"]) {
|
|
1962
|
+
if (record[key] !== void 0 && !validName(record[key])) return null;
|
|
1963
|
+
}
|
|
1964
|
+
return Object.freeze({
|
|
1965
|
+
providerId,
|
|
1966
|
+
...record.providerVersion ? { providerVersion: record.providerVersion } : {},
|
|
1967
|
+
...record.source ? { source: record.source } : {},
|
|
1968
|
+
...record.extractor ? { extractor: record.extractor } : {},
|
|
1969
|
+
...record.override ? { override: record.override } : {}
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
function resolveCapabilityRefs(record, state, path, bindings) {
|
|
1973
|
+
const validator = resolveCapability2(record.validatorHandle, "validator", state, path, bindings);
|
|
1974
|
+
const codec = resolveCapability2(record.codecHandle, "codec", state, path, bindings);
|
|
1975
|
+
return validator === null || codec === null ? null : { ...validator ? { validator } : {}, ...codec ? { codec } : {} };
|
|
1976
|
+
}
|
|
1977
|
+
function resolveCapability2(handle, kind, state, path, bindings) {
|
|
1978
|
+
if (handle === void 0) return void 0;
|
|
1979
|
+
if (!validName(handle)) return unknownCapability(bindings, path);
|
|
1980
|
+
const found = state.declarations.find((item) => item.handle === handle && item.kind === kind);
|
|
1981
|
+
return found ?? unknownCapability(bindings, path);
|
|
1982
|
+
}
|
|
1983
|
+
function normalizeEditorDocument(input, bindingId, path, state) {
|
|
1984
|
+
if (input === void 0) return void 0;
|
|
1985
|
+
const inspected = readOwnDataRecord(input, 4);
|
|
1986
|
+
if (!inspected.ok || inspected.value.root === void 0) {
|
|
1987
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_BINDING", path);
|
|
1988
|
+
return null;
|
|
1989
|
+
}
|
|
1990
|
+
const definitions = normalizeDefinitions(inspected.value.definitions);
|
|
1991
|
+
const evidence2 = normalizeEditorEvidence(inspected.value.evidence);
|
|
1992
|
+
if (definitions === null || evidence2 === null) {
|
|
1993
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_BINDING", path);
|
|
1994
|
+
return null;
|
|
1995
|
+
}
|
|
1996
|
+
const document = {
|
|
1997
|
+
root: inspected.value.root,
|
|
1998
|
+
definitions,
|
|
1999
|
+
evidence: evidence2
|
|
2000
|
+
};
|
|
2001
|
+
if (!validateEditorDocument(document)) {
|
|
2002
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_BINDING", path);
|
|
2003
|
+
return null;
|
|
2004
|
+
}
|
|
2005
|
+
return { bindingId, path, document };
|
|
2006
|
+
}
|
|
2007
|
+
function normalizeEditorEvidence(input) {
|
|
2008
|
+
if (input === void 0) return Object.freeze([]);
|
|
2009
|
+
const items = readArray(input, 8192);
|
|
2010
|
+
if (!items) return null;
|
|
2011
|
+
const allowed = [
|
|
2012
|
+
"invalid-shape",
|
|
2013
|
+
"unsupported-shape",
|
|
2014
|
+
"depth-limit",
|
|
2015
|
+
"node-limit",
|
|
2016
|
+
"edge-limit",
|
|
2017
|
+
"unresolved-reference"
|
|
2018
|
+
];
|
|
2019
|
+
return items.every((item) => typeof item === "string" && allowed.includes(item)) ? Object.freeze(items) : null;
|
|
2020
|
+
}
|
|
2021
|
+
function normalizeDefinitions(input) {
|
|
2022
|
+
if (input === void 0) return Object.freeze([]);
|
|
2023
|
+
const items = readArray(input, 2048);
|
|
2024
|
+
if (!items) return null;
|
|
2025
|
+
const output = [];
|
|
2026
|
+
for (const item of items) {
|
|
2027
|
+
const inspected = readOwnDataRecord(item, 4);
|
|
2028
|
+
if (!inspected.ok || !validName(inspected.value.name)) return null;
|
|
2029
|
+
output.push(
|
|
2030
|
+
Object.freeze({ name: inspected.value.name, shape: inspected.value.shape })
|
|
2031
|
+
);
|
|
2032
|
+
}
|
|
2033
|
+
return Object.freeze(output);
|
|
2034
|
+
}
|
|
2035
|
+
function bindingError(state, code, path) {
|
|
2036
|
+
state.diagnostics.push(environmentDiagnostic(code, path, state.providerProvenance));
|
|
2037
|
+
}
|
|
2038
|
+
function provenanceError(state, path) {
|
|
2039
|
+
bindingError(state, "HOST_ENVIRONMENT_INVALID_PROVENANCE", path);
|
|
2040
|
+
return null;
|
|
2041
|
+
}
|
|
2042
|
+
function unknownCapability(state, path) {
|
|
2043
|
+
bindingError(state, "HOST_ENVIRONMENT_UNKNOWN_CAPABILITY", path);
|
|
2044
|
+
return null;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// src/identity.ts
|
|
2048
|
+
function normalizeIdentity(input) {
|
|
2049
|
+
const inspected = readOwnDataRecord(input, 8);
|
|
2050
|
+
if (!inspected.ok) return Object.freeze({ ok: false });
|
|
2051
|
+
const record = inspected.value;
|
|
2052
|
+
if (!validOptionalBoolean(record.cacheable)) return Object.freeze({ ok: false });
|
|
2053
|
+
if (!validOptionalString(record.id) || !validOptionalString(record.version)) {
|
|
2054
|
+
return Object.freeze({ ok: false });
|
|
2055
|
+
}
|
|
2056
|
+
if (!validOptionalString(record.configurationDigest)) return Object.freeze({ ok: false });
|
|
2057
|
+
if (record.cacheable === false) return nonCacheable("explicitly-disabled");
|
|
2058
|
+
if (!record.id || !record.version || !record.configurationDigest) {
|
|
2059
|
+
return nonCacheable("missing-identity");
|
|
2060
|
+
}
|
|
2061
|
+
return Object.freeze({
|
|
2062
|
+
ok: true,
|
|
2063
|
+
value: Object.freeze({
|
|
2064
|
+
cacheable: true,
|
|
2065
|
+
id: record.id,
|
|
2066
|
+
version: record.version,
|
|
2067
|
+
configurationDigest: record.configurationDigest
|
|
2068
|
+
})
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2071
|
+
function subordinateIdentity(identity, provider) {
|
|
2072
|
+
if (!provider.cacheable && identity.cacheable) {
|
|
2073
|
+
return Object.freeze({ cacheable: false, reason: "provider-not-cacheable" });
|
|
2074
|
+
}
|
|
2075
|
+
return identity;
|
|
2076
|
+
}
|
|
2077
|
+
function nonCacheable(reason) {
|
|
2078
|
+
return Object.freeze({
|
|
2079
|
+
ok: true,
|
|
2080
|
+
value: Object.freeze({ cacheable: false, reason })
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
function validOptionalString(input) {
|
|
2084
|
+
return input === void 0 || typeof input === "string" && input.length > 0 && input.length <= 256;
|
|
2085
|
+
}
|
|
2086
|
+
function validOptionalBoolean(input) {
|
|
2087
|
+
return input === void 0 || typeof input === "boolean";
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
// src/capability-normalization.ts
|
|
2091
|
+
function normalizeCapabilities(input, provider) {
|
|
2092
|
+
const state = { declarations: [], live: /* @__PURE__ */ Object.create(null), diagnostics: [] };
|
|
2093
|
+
if (input === void 0) return state;
|
|
2094
|
+
const items = readArray(input, 4096);
|
|
2095
|
+
if (!items) {
|
|
2096
|
+
state.diagnostics.push(environmentDiagnostic("HOST_ENVIRONMENT_INVALID_CAPABILITY"));
|
|
2097
|
+
return state;
|
|
2098
|
+
}
|
|
2099
|
+
for (const item of items) addCapability(item, provider, state);
|
|
2100
|
+
return state;
|
|
2101
|
+
}
|
|
2102
|
+
function addCapability(input, provider, state) {
|
|
2103
|
+
const inspected = readOwnDataRecord(input, 12);
|
|
2104
|
+
if (!inspected.ok || !validCapabilityFields(inspected.value)) {
|
|
2105
|
+
state.diagnostics.push(environmentDiagnostic("HOST_ENVIRONMENT_INVALID_CAPABILITY"));
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
const record = inspected.value;
|
|
2109
|
+
if (state.live[record.handle]) {
|
|
2110
|
+
state.diagnostics.push(environmentDiagnostic("HOST_ENVIRONMENT_DUPLICATE_CAPABILITY"));
|
|
2111
|
+
return;
|
|
2112
|
+
}
|
|
2113
|
+
const identity = normalizeCapabilityIdentity(record);
|
|
2114
|
+
if (!identity) {
|
|
2115
|
+
state.diagnostics.push(environmentDiagnostic("HOST_ENVIRONMENT_INVALID_IDENTITY"));
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
addLiveCapability(record, subordinateIdentity(identity, provider), state);
|
|
2119
|
+
}
|
|
2120
|
+
function normalizeCapabilityIdentity(record) {
|
|
2121
|
+
const result = normalizeIdentity({
|
|
2122
|
+
id: record.capabilityId,
|
|
2123
|
+
version: record.capabilityVersion,
|
|
2124
|
+
configurationDigest: record.configurationDigest,
|
|
2125
|
+
cacheable: record.cacheable
|
|
2126
|
+
});
|
|
2127
|
+
return result.ok ? result.value : null;
|
|
2128
|
+
}
|
|
2129
|
+
function addLiveCapability(record, identity, state) {
|
|
2130
|
+
const declaration = createDeclaration(record, identity);
|
|
2131
|
+
const live = declaration.kind === "validator" ? Object.freeze({
|
|
2132
|
+
...declaration,
|
|
2133
|
+
kind: "validator",
|
|
2134
|
+
decode: record.decode
|
|
2135
|
+
}) : Object.freeze({ ...declaration, kind: "codec", convert: record.convert });
|
|
2136
|
+
state.declarations.push(declaration);
|
|
2137
|
+
state.live[declaration.handle] = live;
|
|
2138
|
+
}
|
|
2139
|
+
function createDeclaration(record, identity) {
|
|
2140
|
+
return Object.freeze({
|
|
2141
|
+
handle: record.handle,
|
|
2142
|
+
kind: record.kind,
|
|
2143
|
+
mode: record.mode,
|
|
2144
|
+
...record.capabilityId ? { capabilityId: record.capabilityId } : {},
|
|
2145
|
+
...record.capabilityVersion ? { capabilityVersion: record.capabilityVersion } : {},
|
|
2146
|
+
...record.configurationDigest ? { configurationDigest: record.configurationDigest } : {},
|
|
2147
|
+
identity
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
function validCapabilityFields(record) {
|
|
2151
|
+
if (!validName(record.handle) || record.mode !== "sync" && record.mode !== "async")
|
|
2152
|
+
return false;
|
|
2153
|
+
if (record.kind === "validator") return typeof record.decode === "function";
|
|
2154
|
+
if (record.kind === "codec") return typeof record.convert === "function";
|
|
2155
|
+
return false;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
// src/manual-provider.ts
|
|
2159
|
+
var manualProviderBrand = /* @__PURE__ */ Symbol("@kalada/host/manual-provider");
|
|
2160
|
+
function createManualProvider(input) {
|
|
2161
|
+
const outcome = safelyNormalize(input);
|
|
2162
|
+
return Object.freeze({
|
|
2163
|
+
kind: "manual",
|
|
2164
|
+
[manualProviderBrand]: true,
|
|
2165
|
+
describe: () => outcome
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
function describeEnvironment(provider) {
|
|
2169
|
+
try {
|
|
2170
|
+
const candidate = provider;
|
|
2171
|
+
if (candidate?.kind !== "manual" || candidate[manualProviderBrand] !== true) {
|
|
2172
|
+
return providerFailure();
|
|
2173
|
+
}
|
|
2174
|
+
return candidate.describe();
|
|
2175
|
+
} catch {
|
|
2176
|
+
return providerFailure();
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
function normalizeManualEnvironment(input) {
|
|
2180
|
+
return safelyNormalize(input);
|
|
2181
|
+
}
|
|
2182
|
+
function safelyNormalize(input) {
|
|
2183
|
+
try {
|
|
2184
|
+
return normalize(input);
|
|
2185
|
+
} catch {
|
|
2186
|
+
return providerFailure();
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
function normalize(input) {
|
|
2190
|
+
const inspected = readOwnDataRecord(input, 16);
|
|
2191
|
+
if (!inspected.ok) return providerFailure();
|
|
2192
|
+
const record = inspected.value;
|
|
2193
|
+
if (record.mode !== "sync" && record.mode !== "async") return providerFailure();
|
|
2194
|
+
const providerIdentity = normalizeProviderIdentity(record);
|
|
2195
|
+
if (!providerIdentity) return failure4("HOST_ENVIRONMENT_INVALID_IDENTITY");
|
|
2196
|
+
const capabilities = normalizeCapabilities(record.capabilities, providerIdentity);
|
|
2197
|
+
const bindings = normalizeBindings(record.bindings, capabilities, providerProvenance(record));
|
|
2198
|
+
const diagnostics = [...capabilities.diagnostics, ...bindings.diagnostics];
|
|
2199
|
+
if (diagnostics.length > 0) return failedDiagnostics(diagnostics);
|
|
2200
|
+
return success3(record, providerIdentity, capabilities, bindings);
|
|
2201
|
+
}
|
|
2202
|
+
function normalizeProviderIdentity(record) {
|
|
2203
|
+
const result = normalizeIdentity({
|
|
2204
|
+
id: record.providerId,
|
|
2205
|
+
version: record.providerVersion,
|
|
2206
|
+
configurationDigest: record.configurationDigest,
|
|
2207
|
+
cacheable: record.cacheable
|
|
2208
|
+
});
|
|
2209
|
+
return result.ok ? result.value : null;
|
|
2210
|
+
}
|
|
2211
|
+
function providerProvenance(record) {
|
|
2212
|
+
return Object.freeze({
|
|
2213
|
+
providerId: typeof record.providerId === "string" ? record.providerId : "manual",
|
|
2214
|
+
...typeof record.providerVersion === "string" ? { providerVersion: record.providerVersion } : {}
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
function success3(providerRecord, providerIdentity, capabilities, bindings) {
|
|
2218
|
+
const graph = createEditorGraph(bindings.graphInputs);
|
|
2219
|
+
const roots = new Map(graph.roots.map((root) => [root.bindingId, root.nodeId]));
|
|
2220
|
+
const normalized = bindings.bindings.map(
|
|
2221
|
+
(binding) => Object.freeze({
|
|
2222
|
+
...binding,
|
|
2223
|
+
...roots.has(binding.id) ? { editorShapeRoot: roots.get(binding.id) } : {}
|
|
2224
|
+
})
|
|
2225
|
+
);
|
|
2226
|
+
const environment = Object.freeze({
|
|
2227
|
+
format: "kalada-host-environment-v1",
|
|
2228
|
+
provider: providerDeclaration(providerRecord, providerIdentity),
|
|
2229
|
+
cacheability: environmentCacheability(providerIdentity, capabilities.declarations),
|
|
2230
|
+
compileProjection: Object.freeze({
|
|
2231
|
+
format: "kalada-host-compile-projection-v1",
|
|
2232
|
+
bindings: Object.freeze(
|
|
2233
|
+
normalized.map(({ id, name, semanticType }) => Object.freeze({ id, name, semanticType }))
|
|
2234
|
+
)
|
|
2235
|
+
}),
|
|
2236
|
+
bindings: Object.freeze(normalized),
|
|
2237
|
+
capabilities: Object.freeze(capabilities.declarations),
|
|
2238
|
+
editorGraph: graph
|
|
2239
|
+
});
|
|
2240
|
+
const snapshot = createCapabilitySnapshot(environment, Object.freeze(capabilities.live));
|
|
2241
|
+
return Object.freeze({
|
|
2242
|
+
ok: true,
|
|
2243
|
+
environment,
|
|
2244
|
+
capabilitySnapshot: snapshot
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
function providerDeclaration(record, identity) {
|
|
2248
|
+
return Object.freeze({
|
|
2249
|
+
mode: record.mode,
|
|
2250
|
+
...record.providerId ? { providerId: record.providerId } : {},
|
|
2251
|
+
...record.providerVersion ? { providerVersion: record.providerVersion } : {},
|
|
2252
|
+
...record.configurationDigest ? { configurationDigest: record.configurationDigest } : {},
|
|
2253
|
+
identity
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
function environmentCacheability(provider, capabilities) {
|
|
2257
|
+
if (!provider.cacheable) return provider;
|
|
2258
|
+
if (capabilities.some((item) => !item.identity.cacheable)) {
|
|
2259
|
+
return Object.freeze({ cacheable: false, reason: "capability-not-cacheable" });
|
|
2260
|
+
}
|
|
2261
|
+
return provider;
|
|
2262
|
+
}
|
|
2263
|
+
function failedDiagnostics(diagnostics) {
|
|
2264
|
+
return Object.freeze({ ok: false, diagnostics: Object.freeze(diagnostics) });
|
|
2265
|
+
}
|
|
2266
|
+
function failure4(code) {
|
|
2267
|
+
return failedDiagnostics([environmentDiagnostic(code)]);
|
|
2268
|
+
}
|
|
2269
|
+
function providerFailure() {
|
|
2270
|
+
return failure4("HOST_ENVIRONMENT_INVALID_PROVIDER");
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
// src/execution.ts
|
|
2274
|
+
function prepareExpression(source, provider, options) {
|
|
2275
|
+
const described = describeEnvironment(provider);
|
|
2276
|
+
if (!described.ok) return described;
|
|
2277
|
+
const normalized = normalizeOptions(options);
|
|
2278
|
+
if (!normalized) {
|
|
2279
|
+
return Object.freeze({
|
|
2280
|
+
ok: false,
|
|
2281
|
+
diagnostics: Object.freeze([executionDiagnostic("HOST_COMPILE_INVALID_OPTIONS", "compile")])
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2284
|
+
const parsed = parseExpression(source, normalized.parse);
|
|
2285
|
+
if (!parsed.ok) return parsed;
|
|
2286
|
+
const compiled = compileExpression(
|
|
2287
|
+
parsed.value,
|
|
2288
|
+
described.environment.compileProjection,
|
|
2289
|
+
normalized.compile
|
|
2290
|
+
);
|
|
2291
|
+
if (!compiled.ok) return compiled;
|
|
2292
|
+
return linkExpression(compiled.value, described.environment, described.capabilitySnapshot);
|
|
2293
|
+
}
|
|
2294
|
+
function normalizeOptions(options) {
|
|
2295
|
+
if (options === void 0) return Object.freeze({});
|
|
2296
|
+
const inspected = readOwnDataRecord(options, 2);
|
|
2297
|
+
if (!inspected.ok) return null;
|
|
2298
|
+
return Object.freeze({
|
|
2299
|
+
...inspected.value.parse === void 0 ? {} : { parse: inspected.value.parse },
|
|
2300
|
+
...inspected.value.compile === void 0 ? {} : { compile: inspected.value.compile }
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
function evaluateExpression(source, provider, values, options) {
|
|
2304
|
+
const prepared = prepareExpression(source, provider, options);
|
|
2305
|
+
return prepared.ok ? prepared.value.evaluate(values) : prepared;
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
export { DEFAULT_EDITOR_GRAPH_LIMITS, DEFAULT_SERIALIZABLE_LIMITS, HOST_COMPILE_FINGERPRINT_VERSION, HOST_LINK_FINGERPRINT_VERSION, calculateEditorGraphAdmission, cloneSerializableData, compileExpression, createEditorGraph, createEditorGraphEdgeMeter, createManualProvider, describeEnvironment, evaluateExpression, linkExpression, normalizeManualEnvironment, parseExpression, prepareExpression, readSemanticType, traverseEditorGraph };
|
|
2309
|
+
//# sourceMappingURL=index.js.map
|
|
2310
|
+
//# sourceMappingURL=index.js.map
|