litedbmodel 1.2.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +1 -1
  2. package/dist/DBModel.d.ts.map +1 -1
  3. package/dist/DBModel.js +6 -0
  4. package/dist/DBModel.js.map +1 -1
  5. package/dist/scp/authoring-sql.d.ts +56 -0
  6. package/dist/scp/authoring-sql.d.ts.map +1 -0
  7. package/dist/scp/authoring-sql.js +83 -0
  8. package/dist/scp/authoring-sql.js.map +1 -0
  9. package/dist/scp/authoring.d.ts +155 -0
  10. package/dist/scp/authoring.d.ts.map +1 -0
  11. package/dist/scp/authoring.js +162 -0
  12. package/dist/scp/authoring.js.map +1 -0
  13. package/dist/scp/bridge.d.ts +64 -0
  14. package/dist/scp/bridge.d.ts.map +1 -0
  15. package/dist/scp/bridge.js +329 -0
  16. package/dist/scp/bridge.js.map +1 -0
  17. package/dist/scp/catalog.d.ts +91 -0
  18. package/dist/scp/catalog.d.ts.map +1 -0
  19. package/dist/scp/catalog.js +203 -0
  20. package/dist/scp/catalog.js.map +1 -0
  21. package/dist/scp/codegen.d.ts +131 -0
  22. package/dist/scp/codegen.d.ts.map +1 -0
  23. package/dist/scp/codegen.js +137 -0
  24. package/dist/scp/codegen.js.map +1 -0
  25. package/dist/scp/compile-dialect.d.ts +39 -0
  26. package/dist/scp/compile-dialect.d.ts.map +1 -0
  27. package/dist/scp/compile-dialect.js +62 -0
  28. package/dist/scp/compile-dialect.js.map +1 -0
  29. package/dist/scp/compile-sqlite.d.ts +114 -0
  30. package/dist/scp/compile-sqlite.d.ts.map +1 -0
  31. package/dist/scp/compile-sqlite.js +149 -0
  32. package/dist/scp/compile-sqlite.js.map +1 -0
  33. package/dist/scp/dialect.d.ts +141 -0
  34. package/dist/scp/dialect.d.ts.map +1 -0
  35. package/dist/scp/dialect.js +194 -0
  36. package/dist/scp/dialect.js.map +1 -0
  37. package/dist/scp/errors.d.ts +36 -0
  38. package/dist/scp/errors.d.ts.map +1 -0
  39. package/dist/scp/errors.js +72 -0
  40. package/dist/scp/errors.js.map +1 -0
  41. package/dist/scp/guard.d.ts +47 -0
  42. package/dist/scp/guard.d.ts.map +1 -0
  43. package/dist/scp/guard.js +137 -0
  44. package/dist/scp/guard.js.map +1 -0
  45. package/dist/scp/index.cjs +4744 -0
  46. package/dist/scp/index.d.ts +49 -0
  47. package/dist/scp/index.d.ts.map +1 -0
  48. package/dist/scp/index.js +164 -0
  49. package/dist/scp/index.js.map +1 -0
  50. package/dist/scp/index.mjs +2000 -0
  51. package/dist/scp/ir.d.ts +92 -0
  52. package/dist/scp/ir.d.ts.map +1 -0
  53. package/dist/scp/ir.js +28 -0
  54. package/dist/scp/ir.js.map +1 -0
  55. package/dist/scp/relation.d.ts +136 -0
  56. package/dist/scp/relation.d.ts.map +1 -0
  57. package/dist/scp/relation.js +191 -0
  58. package/dist/scp/relation.js.map +1 -0
  59. package/dist/scp/render.d.ts +40 -0
  60. package/dist/scp/render.d.ts.map +1 -0
  61. package/dist/scp/render.js +170 -0
  62. package/dist/scp/render.js.map +1 -0
  63. package/dist/scp/runtime.d.ts +295 -0
  64. package/dist/scp/runtime.d.ts.map +1 -0
  65. package/dist/scp/runtime.js +665 -0
  66. package/dist/scp/runtime.js.map +1 -0
  67. package/dist/scp/typed-object.d.ts +88 -0
  68. package/dist/scp/typed-object.d.ts.map +1 -0
  69. package/dist/scp/typed-object.js +163 -0
  70. package/dist/scp/typed-object.js.map +1 -0
  71. package/dist/scp/write-plan.d.ts +161 -0
  72. package/dist/scp/write-plan.d.ts.map +1 -0
  73. package/dist/scp/write-plan.js +528 -0
  74. package/dist/scp/write-plan.js.map +1 -0
  75. package/dist/scp/write-runtime.d.ts +80 -0
  76. package/dist/scp/write-runtime.d.ts.map +1 -0
  77. package/dist/scp/write-runtime.js +167 -0
  78. package/dist/scp/write-runtime.js.map +1 -0
  79. package/dist/scp/writes.d.ts +251 -0
  80. package/dist/scp/writes.d.ts.map +1 -0
  81. package/dist/scp/writes.js +176 -0
  82. package/dist/scp/writes.js.map +1 -0
  83. package/docs/proposal/contracts-architecture-feasibility.md +328 -0
  84. package/docs/proposal/contracts-architecture.md +579 -0
  85. package/docs/proposal/litedbmodel-v2-scp-architecture.md +382 -0
  86. package/docs/proposal/sql-dynamic-expansion-spec.md +175 -0
  87. package/package.json +27 -5
  88. package/docs/README_REVIEW.md +0 -23
@@ -0,0 +1,4744 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
19
+
20
+ // src/scp/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ CATALOG_NAMES: () => CATALOG_NAMES,
24
+ CODEGEN_LANGUAGES: () => CODEGEN_LANGUAGES,
25
+ ENTITY_ROOT: () => ENTITY_ROOT,
26
+ IN_SENTINEL: () => IN_SENTINEL,
27
+ LITEDBMODEL_CATALOG: () => LITEDBMODEL_CATALOG,
28
+ MYSQL: () => MYSQL,
29
+ POSTGRES: () => POSTGRES,
30
+ RELATION_CONTEXT: () => RELATION_CONTEXT,
31
+ RELATION_KEYS_HEAD: () => RELATION_KEYS_HEAD,
32
+ RelationContext: () => RelationContext,
33
+ SQLITE: () => SQLITE,
34
+ SemanticBehavior: () => SemanticBehavior,
35
+ SqlFailure: () => SqlFailure,
36
+ WHERE_SLOT: () => WHERE_SLOT,
37
+ WRITE_CATALOG_NAMES: () => WRITE_CATALOG_NAMES,
38
+ WRITE_PORT_FAMILIES: () => WRITE_PORT_FAMILIES,
39
+ add: () => add,
40
+ and: () => and,
41
+ assertComponentGraphPortable: () => assertComponentGraphPortable,
42
+ assertComponentPortable: () => assertComponentPortable,
43
+ assertComponentsInCatalog: () => assertComponentsInCatalog,
44
+ assertExprPortable: () => assertExprPortable,
45
+ assertLanguageSupported: () => assertLanguageSupported,
46
+ assertOperationPortable: () => assertOperationPortable,
47
+ behavior: () => behavior,
48
+ buildHandlers: () => buildHandlers,
49
+ buildResultSet: () => buildResultSet,
50
+ bundleToPortableIR: () => bundleToPortableIR,
51
+ catalogEntry: () => catalogEntry,
52
+ coalesce: () => coalesce,
53
+ codegenExecuteBundleForTest: () => codegenExecuteBundleForTest,
54
+ compileBundle: () => compileBundle,
55
+ compileComponentNodes: () => compileComponentNodes,
56
+ compileCompositeWriteBundle: () => compileCompositeWriteBundle,
57
+ compileDelete: () => compileDelete,
58
+ compileEager: () => compileEager,
59
+ compileInsert: () => compileInsert,
60
+ compileInsertFor: () => compileInsertFor,
61
+ compileNode: () => compileNode,
62
+ compileRelationOp: () => compileRelationOp,
63
+ compileSelect: () => compileSelect,
64
+ compileUpdate: () => compileUpdate,
65
+ compileWriteBundle: () => compileWriteBundle,
66
+ components: () => components,
67
+ concat: () => concat,
68
+ countingDriver: () => countingDriver,
69
+ deriveContractEffect: () => deriveContractEffect,
70
+ deriveTransactionPlan: () => deriveTransactionPlan,
71
+ dialectFor: () => dialectFor,
72
+ distributeToParent: () => distributeToParent,
73
+ div: () => div,
74
+ edgeWrites: () => edgeWrites,
75
+ entityWrites: () => entityWrites,
76
+ eq: () => eq,
77
+ executeBehavior: () => executeBehavior,
78
+ executeBundle: () => executeBundle,
79
+ executeCommand: () => executeCommand,
80
+ executeCompositeCommand: () => executeCompositeCommand,
81
+ executeTransaction: () => executeTransaction,
82
+ executeTransactionBundle: () => executeTransactionBundle,
83
+ ge: () => ge,
84
+ generateCodegenArtifact: () => generateCodegenArtifact,
85
+ gt: () => gt,
86
+ inColumn: () => inColumn,
87
+ le: () => le,
88
+ len: () => len,
89
+ lifecycleFor: () => lifecycleFor,
90
+ lt: () => lt,
91
+ mapSqliteError: () => mapSqliteError,
92
+ mod: () => mod,
93
+ mul: () => mul,
94
+ ne: () => ne,
95
+ neg: () => neg,
96
+ normalizeInput: () => normalizeInput,
97
+ not: () => not,
98
+ opt: () => opt,
99
+ or: () => or,
100
+ parseEffectPath: () => parseEffectPath,
101
+ publishBehaviors: () => publishBehaviors,
102
+ read: () => read,
103
+ readBundle: () => readBundle,
104
+ readRelationContext: () => readRelationContext,
105
+ renderOperation: () => renderOperation,
106
+ resolveRelationViaPlan: () => resolveRelationViaPlan,
107
+ runRelationOp: () => runRelationOp,
108
+ sub: () => sub,
109
+ toDollarPlaceholders: () => toDollarPlaceholders,
110
+ when: () => when,
111
+ whereEq: () => whereEq,
112
+ whereGe: () => whereGe,
113
+ whereGt: () => whereGt,
114
+ whereIn: () => whereIn,
115
+ whereIsNull: () => whereIsNull,
116
+ whereLe: () => whereLe,
117
+ whereLt: () => whereLt,
118
+ whereNe: () => whereNe
119
+ });
120
+ module.exports = __toCommonJS(index_exports);
121
+
122
+ // node_modules/behavior-contracts/dist/expr-eval.js
123
+ var ExprFailure = class extends Error {
124
+ code;
125
+ constructor(code, message) {
126
+ super(message);
127
+ this.code = code;
128
+ this.name = "ExprFailure";
129
+ }
130
+ };
131
+ function fail(code, message) {
132
+ throw new ExprFailure(code, message);
133
+ }
134
+ var I64_MIN = -(2n ** 63n);
135
+ var I64_MAX = 2n ** 63n - 1n;
136
+ var WIDEN_EXACT = 2n ** 53n;
137
+ function checkI64(v) {
138
+ if (v < I64_MIN || v > I64_MAX)
139
+ fail("INT_OVERFLOW", `i64 overflow: ${v}`);
140
+ return v;
141
+ }
142
+ function checkFinite(v) {
143
+ if (!Number.isFinite(v))
144
+ fail("NAN_OR_INF", `non-finite float: ${v}`);
145
+ return v;
146
+ }
147
+ function widenToFloat(v) {
148
+ if (typeof v === "number")
149
+ return v;
150
+ if (typeof v === "bigint") {
151
+ if (v > WIDEN_EXACT || v < -WIDEN_EXACT)
152
+ fail("PRECISION_LOSS", `int ${v} exceeds exact float range (\xB12^53)`);
153
+ return Number(v);
154
+ }
155
+ fail("TYPE_MISMATCH", `numeric operand expected, got ${typeName(v)}`);
156
+ }
157
+ function cmpCodePoints(a, b) {
158
+ const ia = a[Symbol.iterator]();
159
+ const ib = b[Symbol.iterator]();
160
+ for (; ; ) {
161
+ const ra = ia.next();
162
+ const rb = ib.next();
163
+ if (ra.done && rb.done)
164
+ return 0;
165
+ if (ra.done)
166
+ return -1;
167
+ if (rb.done)
168
+ return 1;
169
+ const ca = ra.value.codePointAt(0);
170
+ const cb = rb.value.codePointAt(0);
171
+ if (ca !== cb)
172
+ return ca < cb ? -1 : 1;
173
+ }
174
+ }
175
+ function typeName(v) {
176
+ if (v === null)
177
+ return "null";
178
+ if (typeof v === "bigint")
179
+ return "int";
180
+ if (typeof v === "number")
181
+ return "float";
182
+ if (Array.isArray(v))
183
+ return "arr";
184
+ return typeof v;
185
+ }
186
+ function requireBool(v, ctx) {
187
+ if (typeof v !== "boolean")
188
+ fail("TYPE_MISMATCH", `${ctx}: bool expected, got ${typeName(v)}\uFF08truthiness \u306F\u5B58\u5728\u3057\u306A\u3044\uFF09`);
189
+ return v;
190
+ }
191
+ function isPlainObject(v) {
192
+ return typeof v === "object" && v !== null && !Array.isArray(v);
193
+ }
194
+ var FORBIDDEN_OBJECT_KEY = "__proto__";
195
+ function evaluate(node, scope = {}) {
196
+ if (node === null)
197
+ return null;
198
+ if (typeof node === "boolean" || typeof node === "string")
199
+ return node;
200
+ if (typeof node === "number") {
201
+ if (Number.isInteger(node)) {
202
+ if (!Number.isSafeInteger(node))
203
+ fail("INVALID_LITERAL", `integral number literal ${node} exceeds safe range; use {int:"..."}`);
204
+ return BigInt(node);
205
+ }
206
+ return checkFinite(node);
207
+ }
208
+ if (Array.isArray(node))
209
+ fail("INVALID_NODE", "bare array is not an expression (use {arr:[...]})");
210
+ if (!isPlainObject(node))
211
+ fail("INVALID_NODE", `invalid node: ${String(node)}`);
212
+ const keys = Object.keys(node);
213
+ if (keys.length !== 1)
214
+ fail("INVALID_NODE", `operator node must have exactly one key, got [${keys.join(", ")}]`);
215
+ const op = keys[0];
216
+ const arg = node[op];
217
+ switch (op) {
218
+ // ── リテラルラッパ ──
219
+ case "int": {
220
+ if (typeof arg !== "string")
221
+ fail("INVALID_NODE", "{int: ...} expects a string");
222
+ let v;
223
+ try {
224
+ v = BigInt(arg);
225
+ } catch {
226
+ fail("INVALID_LITERAL", `invalid int literal: ${arg}`);
227
+ }
228
+ return checkI64(v);
229
+ }
230
+ case "float": {
231
+ if (typeof arg !== "number")
232
+ fail("INVALID_NODE", "{float: ...} expects a number");
233
+ return checkFinite(arg);
234
+ }
235
+ // ── 参照 ──
236
+ case "ref":
237
+ case "refOpt": {
238
+ const path = argArray(op, arg);
239
+ if (path.length === 0 || !path.every((p) => typeof p === "string"))
240
+ fail("INVALID_NODE", `${op} expects a non-empty string path`);
241
+ const [head, ...rest] = path;
242
+ if (!Object.prototype.hasOwnProperty.call(scope, head))
243
+ fail("UNKNOWN_BINDING", `unknown binding: ${head}`);
244
+ let cur = scope[head];
245
+ for (const seg of rest) {
246
+ if (cur === null) {
247
+ if (op === "refOpt")
248
+ return null;
249
+ fail("NULL_REF", `null intermediate at .${seg}\uFF08?. \u3092\u4F7F\u3046\uFF09`);
250
+ }
251
+ if (!isPlainObject(cur))
252
+ fail("TYPE_MISMATCH", `cannot access .${seg} on ${typeName(cur)}`);
253
+ if (!Object.prototype.hasOwnProperty.call(cur, seg))
254
+ fail("MISSING_PROP", `missing property .${seg}`);
255
+ cur = cur[seg];
256
+ }
257
+ return cur;
258
+ }
259
+ // ── 構築 ──
260
+ case "obj": {
261
+ if (!isPlainObject(arg))
262
+ fail("INVALID_NODE", "{obj: ...} expects an object");
263
+ const out = {};
264
+ for (const k of Object.keys(arg)) {
265
+ if (k === FORBIDDEN_OBJECT_KEY)
266
+ fail("FORBIDDEN_KEY", `obj key "${FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed)`);
267
+ out[k] = evaluate(arg[k], scope);
268
+ }
269
+ return out;
270
+ }
271
+ case "arr":
272
+ return argArray(op, arg).map((e) => evaluate(e, scope));
273
+ // ── 数値(モノモーフィック・checked)──
274
+ case "add":
275
+ case "sub":
276
+ case "mul": {
277
+ const [a, b] = evalBinary(op, arg, scope);
278
+ if (typeof a === "bigint" && typeof b === "bigint") {
279
+ const r = op === "add" ? a + b : op === "sub" ? a - b : a * b;
280
+ return checkI64(r);
281
+ }
282
+ if (typeof a === "number" && typeof b === "number") {
283
+ const r = op === "add" ? a + b : op === "sub" ? a - b : a * b;
284
+ return checkFinite(r);
285
+ }
286
+ fail("TYPE_MISMATCH", `${op}: int\xD7int \u304B float\xD7float\uFF08got ${typeName(a)}\xD7${typeName(b)}\u3002\u6DF7\u5728\u306F\u660E\u793A\u5909\u63DB\u304C\u5FC5\u8981\uFF09`);
287
+ }
288
+ case "neg": {
289
+ const a = evaluate(argUnary(op, arg), scope);
290
+ if (typeof a === "bigint")
291
+ return checkI64(-a);
292
+ if (typeof a === "number")
293
+ return checkFinite(-a);
294
+ fail("TYPE_MISMATCH", `neg: numeric expected, got ${typeName(a)}`);
295
+ }
296
+ case "div": {
297
+ const [a, b] = evalBinary(op, arg, scope);
298
+ return checkFinite(widenToFloat(a) / widenToFloat(b));
299
+ }
300
+ case "mod": {
301
+ const [a, b] = evalBinary(op, arg, scope);
302
+ if (typeof a === "bigint" && typeof b === "bigint") {
303
+ if (b === 0n)
304
+ fail("MOD_ZERO", "int mod by zero");
305
+ return checkI64(a % b);
306
+ }
307
+ if (typeof a === "number" && typeof b === "number")
308
+ return checkFinite(a % b);
309
+ fail("TYPE_MISMATCH", `mod: int\xD7int \u304B float\xD7float\uFF08got ${typeName(a)}\xD7${typeName(b)}\uFF09`);
310
+ }
311
+ // ── 文字列 ──
312
+ case "concat": {
313
+ const rawParts = argArray(op, arg);
314
+ if (rawParts.length < 2)
315
+ fail("INVALID_NODE", `concat expects >= 2 args, got ${rawParts.length}`);
316
+ const parts = rawParts.map((e) => evaluate(e, scope));
317
+ for (const p of parts)
318
+ if (typeof p !== "string")
319
+ fail("TYPE_MISMATCH", `concat: string \u306E\u307F\uFF08got ${typeName(p)}\u3002\u6570\u5024\u306E\u6697\u9ED9 toString \u306F\u5B58\u5728\u3057\u306A\u3044\uFF09`);
320
+ return parts.join("");
321
+ }
322
+ // ── 比較 ──
323
+ case "eq":
324
+ case "ne": {
325
+ const [a, b] = evalBinary(op, arg, scope);
326
+ const equal = valueEquals(a, b);
327
+ return op === "eq" ? equal : !equal;
328
+ }
329
+ case "lt":
330
+ case "le":
331
+ case "gt":
332
+ case "ge": {
333
+ const [a, b] = evalBinary(op, arg, scope);
334
+ let c;
335
+ if (typeof a === "bigint" && typeof b === "bigint")
336
+ c = a < b ? -1 : a > b ? 1 : 0;
337
+ else if (typeof a === "number" && typeof b === "number")
338
+ c = a < b ? -1 : a > b ? 1 : 0;
339
+ else if (typeof a === "string" && typeof b === "string")
340
+ c = cmpCodePoints(a, b);
341
+ else
342
+ fail("TYPE_MISMATCH", `${op}: \u540C\u4E00\u578B\u306E int/float/string \u306E\u307F\uFF08got ${typeName(a)}\xD7${typeName(b)}\uFF09`);
343
+ switch (op) {
344
+ case "lt":
345
+ return c < 0;
346
+ case "le":
347
+ return c <= 0;
348
+ case "gt":
349
+ return c > 0;
350
+ case "ge":
351
+ return c >= 0;
352
+ }
353
+ }
354
+ // ── bool / null(短絡評価)──
355
+ case "and":
356
+ case "or": {
357
+ const [ea, eb] = rawBinary(op, arg);
358
+ const a = requireBool(evaluate(ea, scope), op);
359
+ if (op === "and" && !a)
360
+ return false;
361
+ if (op === "or" && a)
362
+ return true;
363
+ return requireBool(evaluate(eb, scope), op);
364
+ }
365
+ case "not":
366
+ return !requireBool(evaluate(argUnary(op, arg), scope), "not");
367
+ case "coalesce": {
368
+ const [ea, eb] = rawBinary(op, arg);
369
+ const a = evaluate(ea, scope);
370
+ return a === null ? evaluate(eb, scope) : a;
371
+ }
372
+ case "cond": {
373
+ if (!Array.isArray(arg) || arg.length !== 3)
374
+ fail("INVALID_NODE", "cond expects [c, t, e]");
375
+ const c = requireBool(evaluate(arg[0], scope), "cond");
376
+ return evaluate(c ? arg[1] : arg[2], scope);
377
+ }
378
+ // ── その他 ──
379
+ case "len": {
380
+ const a = evaluate(argUnary(op, arg), scope);
381
+ if (!Array.isArray(a))
382
+ fail("TYPE_MISMATCH", `len: \u914D\u5217\u306E\u307F\uFF08string length \u306F v1 \u306B\u5B58\u5728\u3057\u306A\u3044\u3002got ${typeName(a)}\uFF09`);
383
+ return BigInt(a.length);
384
+ }
385
+ default:
386
+ fail("UNKNOWN_OP", `unknown operator: ${op}\uFF08fail-closed\uFF09`);
387
+ }
388
+ }
389
+ function argArray(op, arg) {
390
+ if (!Array.isArray(arg))
391
+ fail("INVALID_NODE", `${op} expects an args array`);
392
+ return arg;
393
+ }
394
+ function argUnary(op, arg) {
395
+ const a = argArray(op, arg);
396
+ if (a.length !== 1)
397
+ fail("INVALID_NODE", `${op} expects 1 arg`);
398
+ return a[0];
399
+ }
400
+ function rawBinary(op, arg) {
401
+ const a = argArray(op, arg);
402
+ if (a.length !== 2)
403
+ fail("INVALID_NODE", `${op} expects 2 args`);
404
+ return [a[0], a[1]];
405
+ }
406
+ function evalBinary(op, arg, scope) {
407
+ const [ea, eb] = rawBinary(op, arg);
408
+ return [evaluate(ea, scope), evaluate(eb, scope)];
409
+ }
410
+ function valueEquals(a, b) {
411
+ if (a === null || b === null)
412
+ return a === null && b === null;
413
+ const ta = typeName(a);
414
+ const tb = typeName(b);
415
+ if (ta !== tb)
416
+ fail("TYPE_MISMATCH", `eq/ne: \u540C\u4E00\u578B\u306E\u307F\uFF08got ${ta}\xD7${tb}\uFF09`);
417
+ if (ta === "arr" || ta === "object")
418
+ fail("TYPE_MISMATCH", "eq/ne: obj/arr \u306E\u7B49\u4FA1\u306F v1 \u3067\u672A\u5B9A\u7FA9");
419
+ return a === b;
420
+ }
421
+
422
+ // node_modules/behavior-contracts/dist/canonical.js
423
+ var CanonicalFailure = class extends Error {
424
+ code;
425
+ constructor(code, message) {
426
+ super(message);
427
+ this.code = code;
428
+ this.name = "CanonicalFailure";
429
+ }
430
+ };
431
+ function fail2(code, message) {
432
+ throw new CanonicalFailure(code, message);
433
+ }
434
+ function pyFloatRepr(n) {
435
+ if (Number.isNaN(n) || !Number.isFinite(n))
436
+ fail2("NAN_OR_INF", `non-finite float cannot be serialized: ${n}`);
437
+ if (n === 0)
438
+ return Object.is(n, -0) ? "-0.0" : "0.0";
439
+ const neg2 = n < 0;
440
+ const abs = Math.abs(n);
441
+ const { digits, decpt } = shortestDigits(abs);
442
+ const body = decpt <= -4 || decpt > 16 ? formatScientific(digits, decpt) : formatFixed(digits, decpt);
443
+ return neg2 ? "-" + body : body;
444
+ }
445
+ function shortestDigits(abs) {
446
+ const s = abs.toString();
447
+ let mantissa;
448
+ let exp;
449
+ const eIdx = s.indexOf("e");
450
+ if (eIdx >= 0) {
451
+ mantissa = s.slice(0, eIdx);
452
+ exp = parseInt(s.slice(eIdx + 1), 10);
453
+ } else {
454
+ mantissa = s;
455
+ exp = 0;
456
+ }
457
+ const dot = mantissa.indexOf(".");
458
+ let intPart;
459
+ let fracPart;
460
+ if (dot >= 0) {
461
+ intPart = mantissa.slice(0, dot);
462
+ fracPart = mantissa.slice(dot + 1);
463
+ } else {
464
+ intPart = mantissa;
465
+ fracPart = "";
466
+ }
467
+ let allDigits = intPart + fracPart;
468
+ let decpt = intPart.length + exp;
469
+ let lead = 0;
470
+ while (lead < allDigits.length - 1 && allDigits[lead] === "0")
471
+ lead++;
472
+ if (lead > 0) {
473
+ allDigits = allDigits.slice(lead);
474
+ decpt -= lead;
475
+ }
476
+ allDigits = allDigits.replace(/0+$/, "");
477
+ if (allDigits === "") {
478
+ return { digits: "0", decpt: 1 };
479
+ }
480
+ return { digits: allDigits, decpt };
481
+ }
482
+ function formatFixed(digits, decpt) {
483
+ if (decpt <= 0) {
484
+ return "0." + "0".repeat(-decpt) + digits;
485
+ }
486
+ if (decpt >= digits.length) {
487
+ return digits + "0".repeat(decpt - digits.length) + ".0";
488
+ }
489
+ return digits.slice(0, decpt) + "." + digits.slice(decpt);
490
+ }
491
+ function formatScientific(digits, decpt) {
492
+ const first = digits[0];
493
+ const rest = digits.slice(1);
494
+ const mant = rest.length > 0 ? `${first}.${rest}` : first;
495
+ const e = decpt - 1;
496
+ const sign = e < 0 ? "-" : "+";
497
+ const mag = Math.abs(e).toString().padStart(2, "0");
498
+ return `${mant}e${sign}${mag}`;
499
+ }
500
+ function canonicalJson(v) {
501
+ if (isPlainObject2(v)) {
502
+ guardKeys(Object.keys(v));
503
+ const keys = Object.keys(v).sort(cmpCodePoints);
504
+ const parts = keys.map((k) => `${jsonString(k)}:${canonicalJson(v[k])}`);
505
+ return `{${parts.join(",")}}`;
506
+ }
507
+ if (Array.isArray(v))
508
+ return `[${v.map(canonicalJson).join(",")}]`;
509
+ return scalarJson(v);
510
+ }
511
+ function scalarJson(v) {
512
+ if (v === null)
513
+ return "null";
514
+ if (typeof v === "boolean")
515
+ return v ? "true" : "false";
516
+ if (typeof v === "string")
517
+ return jsonString(v);
518
+ if (typeof v === "bigint")
519
+ return v.toString();
520
+ if (typeof v === "number")
521
+ return pyFloatRepr(v);
522
+ fail2("INVALID_VALUE", `cannot serialize value of unknown type`);
523
+ }
524
+ function jsonString(s) {
525
+ return JSON.stringify(s);
526
+ }
527
+ function isPlainObject2(v) {
528
+ return typeof v === "object" && v !== null && !Array.isArray(v);
529
+ }
530
+ function guardKeys(keys) {
531
+ if (keys.includes(FORBIDDEN_OBJECT_KEY))
532
+ fail2("FORBIDDEN_KEY", `object key "${FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed)`);
533
+ }
534
+
535
+ // node_modules/behavior-contracts/dist/plan.js
536
+ var PlanFailure = class extends Error {
537
+ code;
538
+ constructor(code, message) {
539
+ super(message);
540
+ this.code = code;
541
+ this.name = "PlanFailure";
542
+ }
543
+ };
544
+ function fail3(code, message) {
545
+ throw new PlanFailure(code, message);
546
+ }
547
+ function runPlan(plan, ops, exec) {
548
+ const states = new Array(ops.length);
549
+ const executedIdx = [];
550
+ const skippedIdx = [];
551
+ const stages = plan ? plan.groups : ops.map((_, i) => [i]);
552
+ const concurrency = plan ? plan.concurrency : 1;
553
+ validateCoverage(stages, ops.length);
554
+ for (const stage of stages) {
555
+ const ordered = [...stage].sort((a, b) => a - b);
556
+ void concurrency;
557
+ for (const i of ordered) {
558
+ states[i] = runOp(i, ops[i], states, exec, executedIdx, skippedIdx);
559
+ }
560
+ }
561
+ return {
562
+ states,
563
+ executed: executedIdx.sort((a, b) => a - b).map((i) => ops[i].id),
564
+ skipped: skippedIdx.sort((a, b) => a - b).map((i) => ops[i].id)
565
+ };
566
+ }
567
+ function preflightOp(i, op, states) {
568
+ const policy = op.policy ?? "fail";
569
+ if (policy !== "fail" && policy !== "retry" && policy !== "continue")
570
+ return { kind: "invalid-policy", message: `unknown policy kind: ${policy}` };
571
+ let boundValue = void 0;
572
+ if (op.parent !== null) {
573
+ const parent = states[op.parent];
574
+ if (!parent || parent.status !== "ok")
575
+ return { kind: "skip" };
576
+ if (op.bindField !== void 0) {
577
+ const pv = parent.value;
578
+ const bound = pv !== null && typeof pv === "object" && !Array.isArray(pv) ? pv[op.bindField] : void 0;
579
+ if (bound === void 0 || bound === null)
580
+ return { kind: "skip" };
581
+ boundValue = bound;
582
+ }
583
+ }
584
+ return { kind: "exec", policy, bound: boundValue };
585
+ }
586
+ function interpretOutcome(i, op, policy, outcome, executedIdx, skippedIdx) {
587
+ executedIdx.push(i);
588
+ if ("ok" in outcome)
589
+ return { status: "ok", value: outcome.ok };
590
+ if (policy === "fail") {
591
+ fail3("OP_FAILED", `operation '${op.id}' failed under 'fail' policy: ${outcome.error}`);
592
+ }
593
+ if (policy === "retry") {
594
+ fail3("OP_FAILED", `operation '${op.id}' failed under 'retry' policy (exhausted): ${outcome.error}`);
595
+ }
596
+ skippedIdx.push(i);
597
+ executedIdx.pop();
598
+ return { status: "skipped" };
599
+ }
600
+ function runOp(i, op, states, exec, executedIdx, skippedIdx) {
601
+ const pre = preflightOp(i, op, states);
602
+ if (pre.kind === "invalid-policy")
603
+ fail3("UNKNOWN_POLICY", pre.message);
604
+ if (pre.kind === "skip") {
605
+ skippedIdx.push(i);
606
+ return { status: "skipped" };
607
+ }
608
+ const outcome = exec(op, pre.bound);
609
+ return interpretOutcome(i, op, pre.policy, outcome, executedIdx, skippedIdx);
610
+ }
611
+ function validateCoverage(stages, n) {
612
+ const seen = /* @__PURE__ */ new Set();
613
+ for (const stage of stages) {
614
+ for (const i of stage) {
615
+ if (i < 0 || i >= n)
616
+ fail3("INVALID_PLAN", `stage index ${i} out of range [0,${n})`);
617
+ if (seen.has(i))
618
+ fail3("INVALID_PLAN", `operation ${i} appears in more than one stage`);
619
+ seen.add(i);
620
+ }
621
+ }
622
+ if (seen.size !== n)
623
+ fail3("INVALID_PLAN", `plan does not cover all ${n} operations (covered ${seen.size})`);
624
+ }
625
+
626
+ // node_modules/behavior-contracts/dist/guard.js
627
+ var PortabilityError = class extends Error {
628
+ path;
629
+ constructor(path, message) {
630
+ super(message);
631
+ this.path = path;
632
+ this.name = "PortabilityError";
633
+ }
634
+ };
635
+ function assertPortable(value, path = "$") {
636
+ if (typeof value === "function")
637
+ throw new PortabilityError(path, `Portability Guard: functions cannot be placed in IR (at ${path})`);
638
+ if (value instanceof Date || value instanceof Promise)
639
+ throw new PortabilityError(path, `Portability Guard: ${value.constructor.name} cannot be placed in IR (at ${path})`);
640
+ if (Array.isArray(value)) {
641
+ value.forEach((v, i) => assertPortable(v, `${path}[${i}]`));
642
+ } else if (value && typeof value === "object") {
643
+ for (const [k, v] of Object.entries(value))
644
+ assertPortable(v, `${path}.${k}`);
645
+ }
646
+ }
647
+ var PORTABLE_EXPR_OPERATORS = /* @__PURE__ */ new Set([
648
+ "int",
649
+ "float",
650
+ "ref",
651
+ "refOpt",
652
+ "obj",
653
+ "arr",
654
+ "add",
655
+ "sub",
656
+ "mul",
657
+ "neg",
658
+ "div",
659
+ "mod",
660
+ "concat",
661
+ "eq",
662
+ "ne",
663
+ "lt",
664
+ "le",
665
+ "gt",
666
+ "ge",
667
+ "and",
668
+ "or",
669
+ "not",
670
+ "coalesce",
671
+ "cond",
672
+ "len"
673
+ ]);
674
+ function assertPortableComponentGraph(ir, path = "$") {
675
+ assertPortable(ir, path);
676
+ if (!ir || typeof ir !== "object")
677
+ throw new PortabilityError(path, `Portability Guard: IR root must be an object (at ${path})`);
678
+ const root = ir;
679
+ if (!Array.isArray(root.components))
680
+ throw new PortabilityError(`${path}.components`, `Portability Guard: IR.components must be an array`);
681
+ root.components.forEach((c, ci) => assertPortableComponent(c, `${path}.components[${ci}]`));
682
+ }
683
+ function assertPortableComponent(c, path) {
684
+ if (!c || typeof c !== "object")
685
+ throw new PortabilityError(path, `Portability Guard: component must be an object (at ${path})`);
686
+ const comp = c;
687
+ if (typeof comp.name !== "string")
688
+ throw new PortabilityError(`${path}.name`, `Portability Guard: component.name must be a string`);
689
+ if (!Array.isArray(comp.body))
690
+ throw new PortabilityError(`${path}.body`, `Portability Guard: component.body must be an array`);
691
+ comp.body.forEach((n, ni) => assertPortableBodyNode(n, `${path}.body[${ni}]`));
692
+ assertPortableExpr(comp.output, `${path}.output`);
693
+ }
694
+ function assertPortableBodyNode(n, path) {
695
+ if (!n || typeof n !== "object")
696
+ throw new PortabilityError(path, `Portability Guard: body node must be an object (at ${path})`);
697
+ const node = n;
698
+ if ("map" in node) {
699
+ const m = node.map;
700
+ requireStringComponent(m.component, `${path}.map.component`);
701
+ assertPortableExpr(m.over, `${path}.map.over`);
702
+ assertPortablePorts(m.ports, `${path}.map.ports`);
703
+ if (m.when !== void 0)
704
+ assertPortableExpr(m.when, `${path}.map.when`);
705
+ if (m.into !== void 0 && typeof m.into !== "string")
706
+ throw new PortabilityError(`${path}.map.into`, `Portability Guard: 'into' must be a string key (at ${path}.map.into)`);
707
+ if (m.batched !== void 0 && typeof m.batched !== "boolean")
708
+ throw new PortabilityError(`${path}.map.batched`, `Portability Guard: 'batched' must be a boolean (at ${path}.map.batched)`);
709
+ } else if ("cond" in node) {
710
+ const co = node.cond;
711
+ assertPortableExpr(co.if, `${path}.cond.if`);
712
+ assertPortableExpr(co.then, `${path}.cond.then`);
713
+ assertPortableExpr(co.else, `${path}.cond.else`);
714
+ } else if ("component" in node) {
715
+ requireStringComponent(node.component, `${path}.component`);
716
+ assertPortablePorts(node.ports, `${path}.ports`);
717
+ } else {
718
+ throw new PortabilityError(path, `Portability Guard: unknown body node kind (not componentRef/map/cond) at ${path}`);
719
+ }
720
+ }
721
+ function requireStringComponent(v, path) {
722
+ if (typeof v !== "string")
723
+ throw new PortabilityError(path, `Portability Guard: 'component' must be a string catalog reference, not ${typeof v} (at ${path})`);
724
+ }
725
+ function assertPortablePorts(ports, path) {
726
+ if (!ports || typeof ports !== "object" || Array.isArray(ports))
727
+ throw new PortabilityError(path, `Portability Guard: ports must be an object (at ${path})`);
728
+ for (const [k, v] of Object.entries(ports))
729
+ assertPortableExpr(v, `${path}.${k}`);
730
+ }
731
+ function assertPortableExpr(node, path) {
732
+ if (node === null || typeof node === "boolean" || typeof node === "string" || typeof node === "number")
733
+ return;
734
+ if (typeof node === "function")
735
+ throw new PortabilityError(path, `Portability Guard: functions cannot be placed in IR (at ${path})`);
736
+ if (Array.isArray(node)) {
737
+ node.forEach((e, i) => assertPortableExpr(e, `${path}[${i}]`));
738
+ return;
739
+ }
740
+ if (typeof node !== "object")
741
+ throw new PortabilityError(path, `Portability Guard: invalid expression node at ${path}`);
742
+ const keys = Object.keys(node);
743
+ if (keys.length === 1) {
744
+ const op = keys[0];
745
+ if (!PORTABLE_EXPR_OPERATORS.has(op))
746
+ throw new PortabilityError(path, `Portability Guard: unknown operator '${op}' (fail-closed) at ${path}`);
747
+ if (op === "obj") {
748
+ const arg = node[op];
749
+ if (!arg || typeof arg !== "object" || Array.isArray(arg))
750
+ throw new PortabilityError(`${path}.obj`, `Portability Guard: {obj: ...} expects an object (at ${path}.obj)`);
751
+ for (const [k, v] of Object.entries(arg)) {
752
+ if (k === FORBIDDEN_OBJECT_KEY)
753
+ throw new PortabilityError(`${path}.obj`, `Portability Guard: object key "${FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed) at ${path}.obj`);
754
+ assertPortableExpr(v, `${path}.obj.${k}`);
755
+ }
756
+ return;
757
+ }
758
+ assertPortableExpr(node[op], `${path}.${op}`);
759
+ return;
760
+ }
761
+ for (const [k, v] of Object.entries(node))
762
+ assertPortableExpr(v, `${path}.${k}`);
763
+ }
764
+
765
+ // node_modules/behavior-contracts/dist/behavior.js
766
+ var BehaviorFailure = class extends Error {
767
+ code;
768
+ constructor(code, message) {
769
+ super(message);
770
+ this.code = code;
771
+ this.name = "BehaviorFailure";
772
+ }
773
+ };
774
+ function bfail(code, message) {
775
+ throw new BehaviorFailure(code, message);
776
+ }
777
+ function nodeKind(n) {
778
+ if ("map" in n)
779
+ return "map";
780
+ if ("cond" in n)
781
+ return "cond";
782
+ if ("component" in n)
783
+ return "componentRef";
784
+ bfail("UNKNOWN_NODE_KIND", `body node '${n.id ?? "?"}' is not componentRef/map/cond`);
785
+ }
786
+ function nodeParent(n) {
787
+ if ("map" in n)
788
+ return n.map.parent;
789
+ if ("cond" in n)
790
+ return n.cond.parent;
791
+ return n.parent;
792
+ }
793
+ function nodeBindField(n) {
794
+ if ("map" in n || "cond" in n)
795
+ return void 0;
796
+ return n.bindField;
797
+ }
798
+ function nodePolicy(n) {
799
+ if ("map" in n)
800
+ return n.map.policy;
801
+ if ("cond" in n)
802
+ return void 0;
803
+ return n.policy;
804
+ }
805
+ function nodeRelationKind(n) {
806
+ if ("map" in n)
807
+ return n.map.relationKind;
808
+ if ("cond" in n)
809
+ return void 0;
810
+ return n.relationKind;
811
+ }
812
+ function evalPorts(ports, scope) {
813
+ const out = {};
814
+ for (const k of Object.keys(ports))
815
+ out[k] = evaluate(ports[k], scope);
816
+ return out;
817
+ }
818
+ function resolveEntry(ir, entry2) {
819
+ const comp = entry2 ? ir.components.find((c) => c.name === entry2) : ir.components[0];
820
+ if (!comp)
821
+ bfail("UNKNOWN_ENTRY", `component '${entry2 ?? "<first>"}' not found in IR`);
822
+ return comp;
823
+ }
824
+ function buildOps(body, idToIndex) {
825
+ return body.map((n) => {
826
+ const pid = nodeParent(n);
827
+ const parent = pid !== void 0 ? idToIndex.get(pid) ?? null : null;
828
+ const spec = { id: n.id, parent };
829
+ const bf = nodeBindField(n);
830
+ if (bf !== void 0)
831
+ spec.bindField = bf;
832
+ const rk = nodeRelationKind(n);
833
+ if (rk !== void 0)
834
+ spec.relationKind = rk;
835
+ const pol = nodePolicy(n);
836
+ if (pol !== void 0)
837
+ spec.policy = pol;
838
+ return spec;
839
+ });
840
+ }
841
+ function checkBatchAligned(opId, r, want) {
842
+ if (!Array.isArray(r) || r.length !== want)
843
+ bfail("MAP_BATCH_RESULT_MISMATCH", `map '${opId}': batched handler must return a list aligned to items (want ${want}, got ${Array.isArray(r) ? r.length : typeof r})`);
844
+ return r;
845
+ }
846
+ function applyInto(opId, into, over, keptIdx, collected) {
847
+ const augmented = [];
848
+ let k = 0;
849
+ for (let i = 0; i < over.length; i++) {
850
+ const el = over[i];
851
+ if (k < keptIdx.length && keptIdx[k] === i) {
852
+ if (el === null || typeof el !== "object" || Array.isArray(el))
853
+ bfail("MAP_INTO_ELEMENT_NOT_OBJECT", `map '${opId}': 'into' requires object elements (element ${i} is not an object)`);
854
+ augmented.push({ ...el, [into]: collected[k] });
855
+ k++;
856
+ } else {
857
+ augmented.push(el);
858
+ }
859
+ }
860
+ return augmented;
861
+ }
862
+ function writeUnproduced(states, ops, body, results) {
863
+ states.forEach((s, i) => {
864
+ if (s.status === "skipped") {
865
+ results[ops[i].id] = nodeRelationKind(body[i]) === "connection" ? { items: [], cursor: null } : null;
866
+ }
867
+ });
868
+ }
869
+ function runBehavior(ir, handlers, input = {}, entry2) {
870
+ const comp = resolveEntry(ir, entry2);
871
+ const body = comp.body;
872
+ const idToIndex = /* @__PURE__ */ new Map();
873
+ body.forEach((n, i) => idToIndex.set(n.id, i));
874
+ const ops = buildOps(body, idToIndex);
875
+ const results = {};
876
+ const baseScope = () => ({ ...input, ...results });
877
+ const exec = (op) => {
878
+ const idx = idToIndex.get(op.id);
879
+ const node = body[idx];
880
+ const kind = nodeKind(node);
881
+ if (kind === "cond") {
882
+ const c = node.cond;
883
+ const value = evaluate({ cond: [c.if, c.then, c.else] }, baseScope());
884
+ return { ok: value };
885
+ }
886
+ if (kind === "map") {
887
+ const m = node.map;
888
+ const over = evaluate(m.over, baseScope());
889
+ if (!Array.isArray(over))
890
+ bfail("MAP_OVER_NOT_ARRAY", `map '${op.id}': 'over' did not evaluate to an array`);
891
+ const handler2 = handlers[m.component];
892
+ if (!handler2)
893
+ bfail("UNKNOWN_COMPONENT", `component '${m.component}' has no handler (fail-closed)`);
894
+ const ctx = { nodeId: op.id, component: m.component };
895
+ const keep = (el, scope) => m.when === void 0 || evaluate({ cond: [m.when, true, false] }, scope) === true;
896
+ const keptIdx = [];
897
+ let collected;
898
+ if (m.batched === true) {
899
+ const items = [];
900
+ over.forEach((el, i) => {
901
+ const scope = { ...baseScope(), [m.as]: el };
902
+ if (!keep(el, scope))
903
+ return;
904
+ items.push(evalPorts(m.ports, scope));
905
+ keptIdx.push(i);
906
+ });
907
+ if (items.length === 0) {
908
+ collected = [];
909
+ } else {
910
+ const outcome = handler2({ items }, ctx);
911
+ if ("error" in outcome)
912
+ return outcome;
913
+ collected = checkBatchAligned(op.id, outcome.ok, items.length);
914
+ }
915
+ } else {
916
+ collected = [];
917
+ for (let i = 0; i < over.length; i++) {
918
+ const el = over[i];
919
+ const scope = { ...baseScope(), [m.as]: el };
920
+ if (!keep(el, scope))
921
+ continue;
922
+ const ports2 = evalPorts(m.ports, scope);
923
+ const outcome = handler2(ports2, { ...ctx, bound: el });
924
+ if ("error" in outcome)
925
+ return outcome;
926
+ collected.push(outcome.ok);
927
+ keptIdx.push(i);
928
+ }
929
+ }
930
+ if (m.into === void 0)
931
+ return { ok: collected };
932
+ return { ok: applyInto(op.id, m.into, over, keptIdx, collected) };
933
+ }
934
+ const cr = node;
935
+ const handler = handlers[cr.component];
936
+ if (!handler)
937
+ bfail("UNKNOWN_COMPONENT", `component '${cr.component}' has no handler (fail-closed)`);
938
+ const ports = evalPorts(cr.ports, baseScope());
939
+ return handler(ports, { nodeId: op.id, component: cr.component });
940
+ };
941
+ const wrappedExec = (op, bound) => {
942
+ const outcome = exec(op, bound);
943
+ if ("ok" in outcome)
944
+ results[op.id] = outcome.ok;
945
+ return outcome;
946
+ };
947
+ const plan = comp.plan ?? null;
948
+ const run = runPlan(plan, ops, wrappedExec);
949
+ writeUnproduced(run.states, ops, body, results);
950
+ return evaluate(comp.output, baseScope());
951
+ }
952
+
953
+ // node_modules/behavior-contracts/dist/builder.js
954
+ var BuilderFailure = class extends Error {
955
+ code;
956
+ constructor(code, message) {
957
+ super(message);
958
+ this.code = code;
959
+ this.name = "BuilderFailure";
960
+ }
961
+ };
962
+ function bfail2(code, message) {
963
+ throw new BuilderFailure(code, message);
964
+ }
965
+ function checkPortableEntry(name, entry2, fail4) {
966
+ if (entry2.portableToIR === false)
967
+ fail4("NOT_PORTABLE_COMPONENT", `component '${name}' is declared portableToIR: false and cannot be referenced from portable IR`);
968
+ }
969
+ function checkPortNames(name, entry2, portNames, fail4) {
970
+ const schema = entry2.inputPorts ?? {};
971
+ if (entry2.additionalPorts !== true) {
972
+ for (const k of portNames)
973
+ if (!Object.hasOwn(schema, k))
974
+ fail4("UNKNOWN_PORT", `component '${name}': unknown port '${k}' (catalog schema is the contract; declare it or opt in with additionalPorts: true)`);
975
+ }
976
+ for (const [k, s] of Object.entries(schema))
977
+ if (s.required === true && !portNames.includes(k))
978
+ fail4("MISSING_PORT", `component '${name}': required port '${k}' is missing`);
979
+ }
980
+ var SCALAR_TYPE_KINDS = {
981
+ string: "string",
982
+ number: "number",
983
+ int: "number",
984
+ float: "number",
985
+ boolean: "boolean",
986
+ bool: "boolean"
987
+ };
988
+ function literalKind(v) {
989
+ if (typeof v === "string")
990
+ return "string";
991
+ if (typeof v === "number")
992
+ return "number";
993
+ if (typeof v === "boolean")
994
+ return "boolean";
995
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) {
996
+ const keys = Object.keys(v);
997
+ if (keys.length === 1 && (keys[0] === "int" || keys[0] === "float"))
998
+ return "number";
999
+ }
1000
+ return null;
1001
+ }
1002
+ function checkDeclaredPortTypes(name, entry2, ports, fail4) {
1003
+ for (const [k, s] of Object.entries(entry2.inputPorts ?? {})) {
1004
+ if (!Object.hasOwn(ports, k))
1005
+ continue;
1006
+ const want = SCALAR_TYPE_KINDS[s.type];
1007
+ if (want === void 0)
1008
+ continue;
1009
+ const got = literalKind(ports[k]);
1010
+ if (got !== null && got !== want)
1011
+ fail4("PORT_TYPE_MISMATCH", `component '${name}': port '${k}' is declared '${s.type}' but is wired a ${got} literal (declared ports are type-checked)`);
1012
+ }
1013
+ }
1014
+ function collectNodeIdRefs(node, ids, out = []) {
1015
+ if (Array.isArray(node)) {
1016
+ for (const e of node)
1017
+ collectNodeIdRefs(e, ids, out);
1018
+ return out;
1019
+ }
1020
+ if (node && typeof node === "object") {
1021
+ const keys = Object.keys(node);
1022
+ if (keys.length === 1 && (keys[0] === "ref" || keys[0] === "refOpt")) {
1023
+ const path = node[keys[0]];
1024
+ if (Array.isArray(path) && typeof path[0] === "string" && ids.has(path[0]) && !out.includes(path[0]))
1025
+ out.push(path[0]);
1026
+ return out;
1027
+ }
1028
+ for (const k of keys)
1029
+ collectNodeIdRefs(node[k], ids, out);
1030
+ }
1031
+ return out;
1032
+ }
1033
+ var DEFAULT_PLAN_CONCURRENCY = 16;
1034
+ function derivePlanFromDeps(nodes, depsByIndex, concurrency) {
1035
+ if (nodes.length === 0)
1036
+ return void 0;
1037
+ const level = /* @__PURE__ */ new Map();
1038
+ let pending = nodes.length;
1039
+ while (pending > 0) {
1040
+ let progress = false;
1041
+ nodes.forEach((n, i) => {
1042
+ if (level.has(n.id))
1043
+ return;
1044
+ let l = 0;
1045
+ for (const d of depsByIndex[i]) {
1046
+ const dl = d === n.id ? void 0 : level.get(d);
1047
+ if (dl === void 0) {
1048
+ l = -1;
1049
+ break;
1050
+ }
1051
+ l = Math.max(l, dl + 1);
1052
+ }
1053
+ if (l < 0)
1054
+ return;
1055
+ level.set(n.id, l);
1056
+ pending--;
1057
+ progress = true;
1058
+ });
1059
+ if (!progress) {
1060
+ const stuck = nodes.filter((n) => !level.has(n.id)).map((n) => `'${n.id}'`);
1061
+ bfail2("DEPENDENCY_CYCLE", `component body has a dependency cycle among nodes [${stuck.join(", ")}]`);
1062
+ }
1063
+ }
1064
+ const groups = [];
1065
+ nodes.forEach((n, i) => {
1066
+ const l = level.get(n.id);
1067
+ (groups[l] ??= []).push(i);
1068
+ });
1069
+ return { groups, concurrency };
1070
+ }
1071
+ function canonicalizeDeep(v) {
1072
+ if (Array.isArray(v))
1073
+ return v.map(canonicalizeDeep);
1074
+ if (v !== null && typeof v === "object") {
1075
+ const src = v;
1076
+ const out = {};
1077
+ for (const k of Object.keys(src).sort(cmpCodePoints))
1078
+ out[k] = canonicalizeDeep(src[k]);
1079
+ return out;
1080
+ }
1081
+ return v;
1082
+ }
1083
+ var DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "inputPorts", "body", "output", "plan"]);
1084
+ var REF_NODE_KEYS = /* @__PURE__ */ new Set(["id", "component", "ports", "parent", "bindField", "relationKind", "policy"]);
1085
+ var MAP_NODE_KEYS = /* @__PURE__ */ new Set(["id", "map"]);
1086
+ var MAP_KEYS = /* @__PURE__ */ new Set(["over", "as", "component", "ports", "when", "into", "batched", "parent", "relationKind", "policy"]);
1087
+ var COND_NODE_KEYS = /* @__PURE__ */ new Set(["id", "cond"]);
1088
+ var COND_KEYS = /* @__PURE__ */ new Set(["if", "then", "else", "parent"]);
1089
+ var SCHEMA_KEYS = /* @__PURE__ */ new Set(["type", "required"]);
1090
+ var PLAN_KEYS = /* @__PURE__ */ new Set(["groups", "concurrency"]);
1091
+ var RELATION_KINDS = /* @__PURE__ */ new Set(["single", "connection"]);
1092
+ var POLICY_KINDS = /* @__PURE__ */ new Set(["fail", "retry", "continue"]);
1093
+ function isPlainObject3(v) {
1094
+ return v !== null && typeof v === "object" && !Array.isArray(v);
1095
+ }
1096
+ function checkAllowedKeys(rec, allowed, code, at) {
1097
+ for (const k of Object.keys(rec))
1098
+ if (!allowed.has(k))
1099
+ bfail2(code, `${at}: unknown key '${k}' (fail-closed)`);
1100
+ }
1101
+ function checkScopeKeyName(name, what, at) {
1102
+ if (typeof name !== "string" || name === "")
1103
+ bfail2("INVALID_NODE", `${at}: ${what} must be a non-empty string`);
1104
+ if (name === FORBIDDEN_OBJECT_KEY)
1105
+ bfail2("INVALID_NODE", `${at}: ${what} "${FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed)`);
1106
+ return name;
1107
+ }
1108
+ function checkNodeWire(rec, ids, at) {
1109
+ const out = {};
1110
+ if (rec.parent !== void 0) {
1111
+ if (typeof rec.parent !== "string")
1112
+ bfail2("INVALID_NODE", `${at}: 'parent' must be a node id string`);
1113
+ if (!ids.has(rec.parent))
1114
+ bfail2("UNKNOWN_PARENT", `${at}: parent '${rec.parent}' is not a body node id`);
1115
+ out.parent = rec.parent;
1116
+ }
1117
+ if (rec.relationKind !== void 0) {
1118
+ if (typeof rec.relationKind !== "string" || !RELATION_KINDS.has(rec.relationKind))
1119
+ bfail2("INVALID_NODE", `${at}: 'relationKind' must be "single" or "connection"`);
1120
+ out.relationKind = rec.relationKind;
1121
+ }
1122
+ if (rec.policy !== void 0) {
1123
+ if (typeof rec.policy !== "string" || !POLICY_KINDS.has(rec.policy))
1124
+ bfail2("INVALID_NODE", `${at}: 'policy' must be "fail", "retry" or "continue"`);
1125
+ out.policy = rec.policy;
1126
+ }
1127
+ return out;
1128
+ }
1129
+ function checkPortsShape(ports, at) {
1130
+ if (!isPlainObject3(ports))
1131
+ bfail2("INVALID_NODE", `${at}: 'ports' must be a plain object`);
1132
+ for (const k of Object.keys(ports))
1133
+ if (k === FORBIDDEN_OBJECT_KEY)
1134
+ bfail2("INVALID_NODE", `${at}: port name "${FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed)`);
1135
+ return ports;
1136
+ }
1137
+ function normalizeNode(raw, ids, at) {
1138
+ const rec = raw;
1139
+ const id = rec.id;
1140
+ if (rec.map !== void 0) {
1141
+ checkAllowedKeys(rec, MAP_NODE_KEYS, "INVALID_NODE", at);
1142
+ if (!isPlainObject3(rec.map))
1143
+ bfail2("INVALID_NODE", `${at}: 'map' must be a plain object`);
1144
+ const m = rec.map;
1145
+ checkAllowedKeys(m, MAP_KEYS, "INVALID_NODE", `${at}.map`);
1146
+ if (m.over === void 0)
1147
+ bfail2("INVALID_NODE", `${at}.map: 'over' is required`);
1148
+ const as = checkScopeKeyName(m.as, "'as'", `${at}.map`);
1149
+ if (!as.startsWith("$") || as.length < 2)
1150
+ bfail2("INVALID_NODE", `${at}.map: 'as' must be a "$"-prefixed element binding (e.g. "$el"), got '${as}'`);
1151
+ if (ids.has(as))
1152
+ bfail2("INVALID_NODE", `${at}.map: 'as' binding '${as}' collides with a body node id`);
1153
+ if (typeof m.component !== "string" || m.component === "")
1154
+ bfail2("INVALID_NODE", `${at}.map: 'component' must be a non-empty catalog name string`);
1155
+ const ports = checkPortsShape(m.ports, `${at}.map`);
1156
+ const node = { id, map: { over: m.over, as, component: m.component, ports } };
1157
+ if (m.when !== void 0)
1158
+ node.map.when = m.when;
1159
+ if (m.into !== void 0)
1160
+ node.map.into = checkScopeKeyName(m.into, "'into'", `${at}.map`);
1161
+ if (m.batched !== void 0) {
1162
+ if (typeof m.batched !== "boolean")
1163
+ bfail2("INVALID_NODE", `${at}.map: 'batched' must be a boolean`);
1164
+ node.map.batched = m.batched;
1165
+ }
1166
+ const wire = checkNodeWire(m, ids, `${at}.map`);
1167
+ if (wire.parent !== void 0)
1168
+ node.map.parent = wire.parent;
1169
+ if (wire.relationKind !== void 0)
1170
+ node.map.relationKind = wire.relationKind;
1171
+ if (wire.policy !== void 0)
1172
+ node.map.policy = wire.policy;
1173
+ return node;
1174
+ }
1175
+ if (rec.cond !== void 0) {
1176
+ checkAllowedKeys(rec, COND_NODE_KEYS, "INVALID_NODE", at);
1177
+ if (!isPlainObject3(rec.cond))
1178
+ bfail2("INVALID_NODE", `${at}: 'cond' must be a plain object`);
1179
+ const c = rec.cond;
1180
+ checkAllowedKeys(c, COND_KEYS, "INVALID_NODE", `${at}.cond`);
1181
+ if (c.if === void 0)
1182
+ bfail2("INVALID_NODE", `${at}.cond: 'if' is required`);
1183
+ if (c.then === void 0)
1184
+ bfail2("INVALID_NODE", `${at}.cond: 'then' is required (use null for an empty branch)`);
1185
+ if (c.else === void 0)
1186
+ bfail2("INVALID_NODE", `${at}.cond: 'else' is required (use null for an empty branch)`);
1187
+ const node = { id, cond: { if: c.if, then: c.then, else: c.else } };
1188
+ const wire = checkNodeWire(c, ids, `${at}.cond`);
1189
+ if (wire.parent !== void 0)
1190
+ node.cond.parent = wire.parent;
1191
+ return node;
1192
+ }
1193
+ if (rec.component !== void 0) {
1194
+ checkAllowedKeys(rec, REF_NODE_KEYS, "INVALID_NODE", at);
1195
+ if (typeof rec.component !== "string" || rec.component === "")
1196
+ bfail2("INVALID_NODE", `${at}: 'component' must be a non-empty catalog name string`);
1197
+ const ports = checkPortsShape(rec.ports, at);
1198
+ const node = { id, component: rec.component, ports };
1199
+ const wire = checkNodeWire(rec, ids, at);
1200
+ if (wire.parent !== void 0)
1201
+ node.parent = wire.parent;
1202
+ if (rec.bindField !== void 0) {
1203
+ if (typeof rec.bindField !== "string" || rec.bindField === "")
1204
+ bfail2("INVALID_NODE", `${at}: 'bindField' must be a non-empty string`);
1205
+ node.bindField = rec.bindField;
1206
+ }
1207
+ if (wire.relationKind !== void 0)
1208
+ node.relationKind = wire.relationKind;
1209
+ if (wire.policy !== void 0)
1210
+ node.policy = wire.policy;
1211
+ return node;
1212
+ }
1213
+ bfail2("INVALID_NODE", `${at}: body node must be componentRef ('component'), 'map' or 'cond'`);
1214
+ }
1215
+ function walkRefs(node, binding, ctx, at) {
1216
+ if (node === null || typeof node !== "object")
1217
+ return;
1218
+ if (Array.isArray(node)) {
1219
+ node.forEach((e, i) => walkRefs(e, binding, ctx, `${at}[${i}]`));
1220
+ return;
1221
+ }
1222
+ const rec = node;
1223
+ const keys = Object.keys(rec);
1224
+ if (keys.length === 1) {
1225
+ const op = keys[0];
1226
+ const arg = rec[op];
1227
+ if (op === "ref" || op === "refOpt") {
1228
+ if (!Array.isArray(arg) || arg.length === 0 || arg.some((s) => typeof s !== "string"))
1229
+ bfail2("UNKNOWN_REF", `${at}: '${op}' path must be a non-empty array of strings`);
1230
+ const root = arg[0];
1231
+ if (ctx.ids.has(root)) {
1232
+ ctx.addDep(root);
1233
+ return;
1234
+ }
1235
+ if (ctx.inputs.has(root) || binding !== null && root === binding)
1236
+ return;
1237
+ bfail2("UNKNOWN_REF", `${at}: reference root '${root}' is not a body node id, a declared input port${binding !== null ? `, or the map binding '${binding}'` : ""} (fail-closed)`);
1238
+ }
1239
+ if (op === "obj") {
1240
+ if (isPlainObject3(arg))
1241
+ for (const [k, v] of Object.entries(arg))
1242
+ walkRefs(v, binding, ctx, `${at}.obj.${k}`);
1243
+ return;
1244
+ }
1245
+ if (op === "int" || op === "float")
1246
+ return;
1247
+ walkRefs(arg, binding, ctx, `${at}.${op}`);
1248
+ return;
1249
+ }
1250
+ for (const [k, v] of Object.entries(rec))
1251
+ walkRefs(v, binding, ctx, `${at}.${k}`);
1252
+ }
1253
+ function nodeRefsAndDeps(n, ids, inputs, at) {
1254
+ const deps = [];
1255
+ const ctx = {
1256
+ ids,
1257
+ inputs,
1258
+ addDep: (d) => {
1259
+ if (!deps.includes(d))
1260
+ deps.push(d);
1261
+ }
1262
+ };
1263
+ if ("map" in n) {
1264
+ walkRefs(n.map.over, null, ctx, `${at}.map.over`);
1265
+ walkRefs(n.map.ports, n.map.as, ctx, `${at}.map.ports`);
1266
+ if (n.map.when !== void 0)
1267
+ walkRefs(n.map.when, n.map.as, ctx, `${at}.map.when`);
1268
+ if (n.map.parent !== void 0 && !deps.includes(n.map.parent))
1269
+ deps.push(n.map.parent);
1270
+ } else if ("cond" in n) {
1271
+ walkRefs(n.cond.if, null, ctx, `${at}.cond.if`);
1272
+ walkRefs(n.cond.then, null, ctx, `${at}.cond.then`);
1273
+ walkRefs(n.cond.else, null, ctx, `${at}.cond.else`);
1274
+ if (n.cond.parent !== void 0 && !deps.includes(n.cond.parent))
1275
+ deps.push(n.cond.parent);
1276
+ } else {
1277
+ walkRefs(n.ports, null, ctx, `${at}.ports`);
1278
+ if (n.parent !== void 0 && !deps.includes(n.parent))
1279
+ deps.push(n.parent);
1280
+ }
1281
+ return deps;
1282
+ }
1283
+ function validateSuppliedPlan(raw, body, depsByIndex) {
1284
+ if (!isPlainObject3(raw))
1285
+ bfail2("INVALID_PLAN", "'plan' must be an object, null (no plan) or omitted (derived)");
1286
+ checkAllowedKeys(raw, PLAN_KEYS, "INVALID_PLAN", "plan");
1287
+ const { groups, concurrency } = raw;
1288
+ if (typeof concurrency !== "number" || !Number.isSafeInteger(concurrency) || concurrency < 1)
1289
+ bfail2("INVALID_PLAN", "plan.concurrency must be a positive integer");
1290
+ if (!Array.isArray(groups))
1291
+ bfail2("INVALID_PLAN", "plan.groups must be an array of stages");
1292
+ const n = body.length;
1293
+ const stageOf = new Array(n);
1294
+ const seen = /* @__PURE__ */ new Set();
1295
+ groups.forEach((stage, s) => {
1296
+ if (!Array.isArray(stage))
1297
+ bfail2("INVALID_PLAN", `plan.groups[${s}] must be an array of body indexes`);
1298
+ for (const i of stage) {
1299
+ if (typeof i !== "number" || !Number.isSafeInteger(i) || i < 0 || i >= n)
1300
+ bfail2("INVALID_PLAN", `plan.groups[${s}]: index ${String(i)} out of range [0,${n})`);
1301
+ if (seen.has(i))
1302
+ bfail2("INVALID_PLAN", `plan: body index ${i} appears in more than one stage`);
1303
+ seen.add(i);
1304
+ stageOf[i] = s;
1305
+ }
1306
+ });
1307
+ if (seen.size !== n)
1308
+ bfail2("INVALID_PLAN", `plan does not cover all ${n} body nodes (covered ${seen.size})`);
1309
+ const idToIndex = new Map(body.map((node, i) => [node.id, i]));
1310
+ body.forEach((node, i) => {
1311
+ for (const d of depsByIndex[i]) {
1312
+ const di = idToIndex.get(d);
1313
+ if (stageOf[di] >= stageOf[i])
1314
+ bfail2("INVALID_PLAN", `plan: node '${node.id}' (stage ${stageOf[i]}) depends on '${d}' (stage ${stageOf[di]}) \u2014 dependencies must be staged earlier`);
1315
+ }
1316
+ });
1317
+ return { groups: groups.map((stage) => [...stage]), concurrency };
1318
+ }
1319
+ function buildComponentCore(data, opts) {
1320
+ if (!isPlainObject3(data))
1321
+ bfail2("INVALID_DEFINITION", "component definition must be a plain object");
1322
+ const rec = data;
1323
+ checkAllowedKeys(rec, DEFINITION_KEYS, "INVALID_DEFINITION", "definition");
1324
+ if (typeof rec.name !== "string" || rec.name === "")
1325
+ bfail2("INVALID_DEFINITION", "component 'name' must be a non-empty string");
1326
+ const name = rec.name;
1327
+ if (rec.output === void 0)
1328
+ bfail2("INVALID_DEFINITION", `component '${name}': 'output' is required (use null for no output)`);
1329
+ const inputPorts = {};
1330
+ if (rec.inputPorts !== void 0) {
1331
+ if (!isPlainObject3(rec.inputPorts))
1332
+ bfail2("INVALID_DEFINITION", `component '${name}': 'inputPorts' must be an object`);
1333
+ for (const [k, s] of Object.entries(rec.inputPorts)) {
1334
+ if (k === FORBIDDEN_OBJECT_KEY)
1335
+ bfail2("INVALID_DEFINITION", `component '${name}': input port name "${FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed)`);
1336
+ if (!isPlainObject3(s))
1337
+ bfail2("INVALID_DEFINITION", `component '${name}': inputPorts['${k}'] must be an object`);
1338
+ checkAllowedKeys(s, SCHEMA_KEYS, "INVALID_DEFINITION", `component '${name}': inputPorts['${k}']`);
1339
+ if (typeof s.type !== "string")
1340
+ bfail2("INVALID_DEFINITION", `component '${name}': inputPorts['${k}'].type must be a string`);
1341
+ if (s.required !== void 0 && typeof s.required !== "boolean")
1342
+ bfail2("INVALID_DEFINITION", `component '${name}': inputPorts['${k}'].required must be a boolean`);
1343
+ inputPorts[k] = s.required !== void 0 ? { type: s.type, required: s.required } : { type: s.type };
1344
+ }
1345
+ }
1346
+ if (!Array.isArray(rec.body))
1347
+ bfail2("INVALID_DEFINITION", `component '${name}': 'body' must be an array`);
1348
+ const ids = /* @__PURE__ */ new Set();
1349
+ rec.body.forEach((raw, i) => {
1350
+ if (!isPlainObject3(raw))
1351
+ bfail2("INVALID_NODE", `body[${i}]: node must be a plain object`);
1352
+ const id = checkScopeKeyName(raw.id, "node 'id'", `body[${i}]`);
1353
+ if (ids.has(id))
1354
+ bfail2("DUPLICATE_NODE_ID", `body[${i}]: duplicate node id '${id}'`);
1355
+ if (Object.hasOwn(inputPorts, id))
1356
+ bfail2("INVALID_NODE", `body[${i}]: node id '${id}' collides with an input port name (the runBehavior scope would be ambiguous)`);
1357
+ ids.add(id);
1358
+ });
1359
+ const body = rec.body.map((raw, i) => normalizeNode(raw, ids, `body[${i}]`));
1360
+ if (opts.catalog !== void 0) {
1361
+ const catalog = opts.catalog;
1362
+ body.forEach((n, i) => {
1363
+ const cname = "map" in n ? n.map.component : "cond" in n ? null : n.component;
1364
+ if (cname === null)
1365
+ return;
1366
+ const ports = "map" in n ? n.map.ports : n.ports;
1367
+ if (!Object.hasOwn(catalog, cname))
1368
+ bfail2("UNKNOWN_COMPONENT", `body[${i}]: component '${cname}' is not in the catalog (fail-closed)`);
1369
+ const entry2 = catalog[cname];
1370
+ checkPortableEntry(cname, entry2, bfail2);
1371
+ checkPortNames(cname, entry2, Object.keys(ports), bfail2);
1372
+ checkDeclaredPortTypes(cname, entry2, ports, bfail2);
1373
+ });
1374
+ }
1375
+ const inputs = new Set(Object.keys(inputPorts));
1376
+ const depsByIndex = body.map((n, i) => nodeRefsAndDeps(n, ids, inputs, `body[${i}]`));
1377
+ walkRefs(rec.output, null, { ids, inputs, addDep: () => {
1378
+ } }, "output");
1379
+ let plan;
1380
+ if (rec.plan === null)
1381
+ plan = void 0;
1382
+ else if (rec.plan === void 0)
1383
+ plan = derivePlanFromDeps(body, depsByIndex, opts.concurrency);
1384
+ else
1385
+ plan = validateSuppliedPlan(rec.plan, body, depsByIndex);
1386
+ const assembled = { name, inputPorts, body, output: rec.output };
1387
+ if (plan !== void 0)
1388
+ assembled.plan = plan;
1389
+ const component = canonicalizeDeep(assembled);
1390
+ assertPortableComponentGraph({ irVersion: 1, exprVersion: SPEC_VERSIONS.expression, components: [component] });
1391
+ return component;
1392
+ }
1393
+
1394
+ // node_modules/behavior-contracts/dist/authoring.js
1395
+ var AuthoringFailure = class extends Error {
1396
+ code;
1397
+ constructor(code, message) {
1398
+ super(message);
1399
+ this.code = code;
1400
+ this.name = "AuthoringFailure";
1401
+ }
1402
+ };
1403
+ function afail(code, message) {
1404
+ throw new AuthoringFailure(code, message);
1405
+ }
1406
+ var BEHAVIOR_MARK = /* @__PURE__ */ Symbol.for("behavior-contracts.authoring.behavior");
1407
+ var SemanticBehavior = class {
1408
+ };
1409
+ function behavior(cls, _context) {
1410
+ Object.defineProperty(cls, BEHAVIOR_MARK, { value: true, configurable: true });
1411
+ return cls;
1412
+ }
1413
+ function isBehaviorClass(cls) {
1414
+ if (typeof cls !== "function")
1415
+ return false;
1416
+ if (cls[BEHAVIOR_MARK] === true)
1417
+ return true;
1418
+ return cls === SemanticBehavior || cls.prototype instanceof SemanticBehavior;
1419
+ }
1420
+ var EXPR_META = /* @__PURE__ */ Symbol("behavior-contracts.authoring.expr");
1421
+ function exprMetaOf(v) {
1422
+ if (v === null || typeof v !== "object" && typeof v !== "function")
1423
+ return void 0;
1424
+ return v[EXPR_META];
1425
+ }
1426
+ function makeExpr(meta) {
1427
+ return new Proxy({}, {
1428
+ get(_t, prop) {
1429
+ if (prop === EXPR_META)
1430
+ return meta;
1431
+ if (typeof prop === "symbol") {
1432
+ if (prop === Symbol.toPrimitive)
1433
+ return () => notRecordable("implicit coercion of a recorded value (use concat/add/eq/... builders)");
1434
+ return void 0;
1435
+ }
1436
+ if (prop === "then" || prop === "constructor" || prop === "inspect")
1437
+ return void 0;
1438
+ if (prop === "valueOf" || prop === "toString" || prop === "toJSON")
1439
+ return () => notRecordable(`'${prop}' on a recorded value (implicit coercion is not statically interpretable)`);
1440
+ if (prop === "map")
1441
+ return (cb, opts) => recordMap(meta, cb, opts);
1442
+ if (meta.refPath === null)
1443
+ afail("COMPUTED_ACCESS", `property '.${prop}' on a computed expression cannot be lowered (bind the value through a component result or restructure the wiring)`);
1444
+ if (meta.isInput && meta.refPath.length === 0)
1445
+ recordInputPort(prop);
1446
+ const path = [...meta.refPath, prop];
1447
+ return makeExpr({ node: { [meta.refOp]: path }, refPath: path, refOp: meta.refOp, isInput: meta.isInput });
1448
+ },
1449
+ ownKeys() {
1450
+ return notRecordable("spread / enumeration of a recorded value (Expression IR has no object-merge operator; wire explicit keys)");
1451
+ },
1452
+ getOwnPropertyDescriptor() {
1453
+ return notRecordable("property enumeration of a recorded value");
1454
+ },
1455
+ set() {
1456
+ return notRecordable("assignment into a recorded value (authoring is declarative)");
1457
+ }
1458
+ });
1459
+ }
1460
+ function notRecordable(what) {
1461
+ afail("NOT_RECORDABLE", `not statically interpretable: ${what}`);
1462
+ }
1463
+ function opExpr(node) {
1464
+ return makeExpr({ node, refPath: null, refOp: "ref", isInput: false });
1465
+ }
1466
+ function nodeHandle(id) {
1467
+ return makeExpr({ node: { ref: [id] }, refPath: [id], refOp: "ref", isInput: false });
1468
+ }
1469
+ function lowerValue(v, at) {
1470
+ const meta = exprMetaOf(v);
1471
+ if (meta) {
1472
+ if (meta.refPath !== null && meta.refPath.length === 0)
1473
+ afail("WHOLE_INPUT", `${at}: the whole '$' input cannot be wired; reference a field of it`);
1474
+ return meta.node;
1475
+ }
1476
+ if (v === null)
1477
+ return null;
1478
+ switch (typeof v) {
1479
+ case "boolean":
1480
+ case "string":
1481
+ return v;
1482
+ case "number":
1483
+ if (Number.isInteger(v) && !Number.isSafeInteger(v))
1484
+ afail("BAD_PORT_VALUE", `${at}: integral literal ${v} exceeds the safe range (use a bigint literal)`);
1485
+ if (!Number.isFinite(v))
1486
+ afail("BAD_PORT_VALUE", `${at}: non-finite number literal`);
1487
+ return v;
1488
+ case "bigint":
1489
+ return { int: v.toString() };
1490
+ case "undefined":
1491
+ afail("BAD_PORT_VALUE", `${at}: undefined cannot be wired`);
1492
+ break;
1493
+ case "function":
1494
+ afail("BAD_PORT_VALUE", `${at}: functions cannot be placed in IR (Portability Guard)`);
1495
+ break;
1496
+ }
1497
+ if (Array.isArray(v))
1498
+ return { arr: v.map((e, i) => lowerValue(e, `${at}[${i}]`)) };
1499
+ if (v instanceof Date || v instanceof Promise)
1500
+ afail("BAD_PORT_VALUE", `${at}: ${v.constructor.name} cannot be placed in IR (Portability Guard)`);
1501
+ if (typeof v === "object") {
1502
+ const out = {};
1503
+ for (const k of Object.keys(v)) {
1504
+ if (k === "__proto__")
1505
+ afail("BAD_PORT_VALUE", `${at}: object key "__proto__" is forbidden (fail-closed)`);
1506
+ out[k] = lowerValue(v[k], `${at}.${k}`);
1507
+ }
1508
+ return { obj: out };
1509
+ }
1510
+ afail("BAD_PORT_VALUE", `${at}: value cannot be wired`);
1511
+ }
1512
+ function binOp(op) {
1513
+ return (a, b) => opExpr({ [op]: [lowerValue(a, op), lowerValue(b, op)] });
1514
+ }
1515
+ function unOp(op) {
1516
+ return (a) => opExpr({ [op]: [lowerValue(a, op)] });
1517
+ }
1518
+ function concat(...parts) {
1519
+ if (parts.length < 2)
1520
+ afail("BAD_PORT_VALUE", `concat expects >= 2 args, got ${parts.length}`);
1521
+ return opExpr({ concat: parts.map((p, i) => lowerValue(p, `concat[${i}]`)) });
1522
+ }
1523
+ var add = /* @__PURE__ */ binOp("add");
1524
+ var sub = /* @__PURE__ */ binOp("sub");
1525
+ var mul = /* @__PURE__ */ binOp("mul");
1526
+ var div = /* @__PURE__ */ binOp("div");
1527
+ var mod = /* @__PURE__ */ binOp("mod");
1528
+ var neg = /* @__PURE__ */ unOp("neg");
1529
+ var eq = /* @__PURE__ */ binOp("eq");
1530
+ var ne = /* @__PURE__ */ binOp("ne");
1531
+ var lt = /* @__PURE__ */ binOp("lt");
1532
+ var le = /* @__PURE__ */ binOp("le");
1533
+ var gt = /* @__PURE__ */ binOp("gt");
1534
+ var ge = /* @__PURE__ */ binOp("ge");
1535
+ var and = /* @__PURE__ */ binOp("and");
1536
+ var or = /* @__PURE__ */ binOp("or");
1537
+ var not = /* @__PURE__ */ unOp("not");
1538
+ var coalesce = /* @__PURE__ */ binOp("coalesce");
1539
+ var len = /* @__PURE__ */ unOp("len");
1540
+ function opt(x) {
1541
+ const meta = exprMetaOf(x);
1542
+ if (!meta || meta.refPath === null || meta.refPath.length === 0)
1543
+ afail("BAD_PORT_VALUE", "opt(...) expects a reference (a recorded '$' field or node result)");
1544
+ return makeExpr({ node: { refOpt: meta.refPath }, refPath: meta.refPath, refOp: "refOpt", isInput: meta.isInput });
1545
+ }
1546
+ var currentFrame = null;
1547
+ function requireFrame(what) {
1548
+ if (!currentFrame)
1549
+ afail("NO_FRAME", `${what} was used outside compileBehaviors() (recorders only work during build-time evaluation)`);
1550
+ return currentFrame;
1551
+ }
1552
+ function recordInputPort(name) {
1553
+ const f = requireFrame(`$.${name}`);
1554
+ if (!f.inputPorts.has(name))
1555
+ f.inputPorts.set(name, { type: "unknown", required: true });
1556
+ }
1557
+ function nextId(f) {
1558
+ const id = `n${f.seq++}`;
1559
+ f.nodeIds.add(id);
1560
+ return id;
1561
+ }
1562
+ function composedCond(f) {
1563
+ const conds = f.branchStack.map((b) => b.cond);
1564
+ return conds.reduce((acc, c) => acc === void 0 ? c : { and: [acc, c] }, void 0);
1565
+ }
1566
+ function ensureGate(f) {
1567
+ const bf = f.branchStack[f.branchStack.length - 1];
1568
+ if (!bf)
1569
+ return null;
1570
+ if (f.branchStack.length > 1)
1571
+ afail("NESTED_BRANCH", `method '${f.method}': a when(...) branch containing components cannot nest inside another when(...) branch (authoring v1; flatten to sibling gates)`);
1572
+ if (bf.gateId === null) {
1573
+ const id = nextId(f);
1574
+ const gate = { id, cond: { if: composedCond(f), then: { obj: { ok: true } }, else: null } };
1575
+ f.nodes.push(gate);
1576
+ bf.gateId = id;
1577
+ }
1578
+ return bf;
1579
+ }
1580
+ function chooseParent(f, deps, bf) {
1581
+ if (bf) {
1582
+ const inBranch = deps.find((d) => {
1583
+ const idx = f.nodes.findIndex((n) => n.id === d);
1584
+ return idx >= bf.startLen;
1585
+ });
1586
+ if (inBranch !== void 0)
1587
+ return { parent: inBranch };
1588
+ return { parent: bf.gateId, bindField: "ok" };
1589
+ }
1590
+ if (deps.length > 0)
1591
+ return { parent: deps[0] };
1592
+ return {};
1593
+ }
1594
+ function catalogComponents(catalog) {
1595
+ const out = {};
1596
+ for (const name of Object.keys(catalog)) {
1597
+ const entry2 = catalog[name];
1598
+ out[name] = (ports) => recordComponentCall(name, entry2, ports);
1599
+ }
1600
+ return out;
1601
+ }
1602
+ function recordComponentCall(name, entry2, portsIn) {
1603
+ const f = requireFrame(`component '${name}'`);
1604
+ checkPortableEntry(name, entry2, afail);
1605
+ if (!portsIn || typeof portsIn !== "object" || Array.isArray(portsIn) || exprMetaOf(portsIn))
1606
+ afail("BAD_PORT_VALUE", `component '${name}': ports must be a plain object literal`);
1607
+ checkPortNames(name, entry2, Object.keys(portsIn), afail);
1608
+ const ports = {};
1609
+ for (const k of Object.keys(portsIn))
1610
+ ports[k] = lowerValue(portsIn[k], `component '${name}' port '${k}'`);
1611
+ checkDeclaredPortTypes(name, entry2, ports, afail);
1612
+ if (f.pendingMap) {
1613
+ if (f.pendingMap.component !== null)
1614
+ afail("MAP_MULTI_COMPONENT", `method '${f.method}': a .map callback must invoke exactly one component (got a second call: '${name}')`);
1615
+ f.pendingMap.component = name;
1616
+ f.pendingMap.ports = ports;
1617
+ return opExpr(null);
1618
+ }
1619
+ const bf = ensureGate(f);
1620
+ const deps = collectNodeIdRefs(ports, f.nodeIds);
1621
+ const id = nextId(f);
1622
+ const wire = chooseParent(f, deps, bf);
1623
+ const node = { id, component: name, ports };
1624
+ if (wire.parent !== void 0)
1625
+ node.parent = wire.parent;
1626
+ if (wire.bindField !== void 0)
1627
+ node.bindField = wire.bindField;
1628
+ f.nodes.push(node);
1629
+ return nodeHandle(id);
1630
+ }
1631
+ function recordMap(overMeta, cb, opts) {
1632
+ const f = requireFrame(".map");
1633
+ if (f.pendingMap)
1634
+ afail("NESTED_MAP", `method '${f.method}': nested .map is not in the v2 vocabulary (chain a second map over the augmented list \u2014 scp-ir-architecture.md \xA75.1)`);
1635
+ if (f.branchStack.length > 0)
1636
+ afail("MAP_IN_BRANCH", `method '${f.method}': .map inside a when(...) branch is not expressible in the IR (guard the 'over' expression instead)`);
1637
+ if (typeof cb !== "function")
1638
+ afail("MAP_NOT_LOWERABLE", `method '${f.method}': .map expects an inline arrow callback`);
1639
+ if (cb.length > 1)
1640
+ afail("MAP_NOT_LOWERABLE", `method '${f.method}': .map callback takes exactly one element binding (v1)`);
1641
+ if (overMeta.refPath !== null && overMeta.refPath.length === 0)
1642
+ afail("WHOLE_INPUT", `method '${f.method}': the whole '$' input cannot be iterated; reference an array field`);
1643
+ if (opts !== void 0) {
1644
+ if (opts === null || typeof opts !== "object")
1645
+ afail("MAP_NOT_LOWERABLE", ".map options must be an object");
1646
+ if (opts.into !== void 0 && typeof opts.into !== "string")
1647
+ afail("MAP_NOT_LOWERABLE", ".map option 'into' must be a string key");
1648
+ if (opts.batched !== void 0 && typeof opts.batched !== "boolean")
1649
+ afail("MAP_NOT_LOWERABLE", ".map option 'batched' must be a boolean");
1650
+ }
1651
+ const as = `$e${f.mapSeq++}`;
1652
+ const binding = makeExpr({ node: { ref: [as] }, refPath: [as], refOp: "ref", isInput: false });
1653
+ f.pendingMap = { as, component: null, ports: null, when: void 0 };
1654
+ let pm;
1655
+ try {
1656
+ cb(binding);
1657
+ } finally {
1658
+ pm = f.pendingMap;
1659
+ f.pendingMap = null;
1660
+ }
1661
+ if (pm.component === null)
1662
+ afail("MAP_NOT_LOWERABLE", `method '${f.method}': a .map callback must invoke a catalog component (a pure-transform map has no operator in the portable Expression IR v2 vocabulary)`);
1663
+ const over = overMeta.node;
1664
+ const deps = collectNodeIdRefs(over, f.nodeIds);
1665
+ collectNodeIdRefs(pm.ports, f.nodeIds, deps);
1666
+ if (pm.when !== void 0)
1667
+ collectNodeIdRefs(pm.when, f.nodeIds, deps);
1668
+ const id = nextId(f);
1669
+ const node = {
1670
+ id,
1671
+ map: { over, as, component: pm.component, ports: pm.ports }
1672
+ };
1673
+ if (pm.when !== void 0)
1674
+ node.map.when = pm.when;
1675
+ if (opts?.into !== void 0)
1676
+ node.map.into = opts.into;
1677
+ if (opts?.batched === true)
1678
+ node.map.batched = true;
1679
+ if (deps.length > 0)
1680
+ node.map.parent = deps[0];
1681
+ f.nodes.push(node);
1682
+ return nodeHandle(id);
1683
+ }
1684
+ function when(condition, then, otherwise) {
1685
+ const f = requireFrame("when");
1686
+ if (!exprMetaOf(condition))
1687
+ afail("BAD_CONDITION", `method '${f.method}': when(...) condition must be a recorded expression (native ===/&&/?: over recorded values cannot be observed at build time \u2014 use eq/ne/and/... builders)`);
1688
+ if (typeof then !== "function" || otherwise !== void 0 && typeof otherwise !== "function")
1689
+ afail("BAD_BRANCH", `method '${f.method}': when(...) branches must be thunks (() => ...)`);
1690
+ const c = lowerValue(condition, "when condition");
1691
+ if (f.pendingMap) {
1692
+ if (otherwise !== void 0)
1693
+ afail("BAD_BRANCH", `method '${f.method}': when(...) inside a .map callback is guard-form only (no else \u2014 v2 'map.when' skips the element)`);
1694
+ const before = f.pendingMap.component;
1695
+ const result = then();
1696
+ if (f.pendingMap.component === before) {
1697
+ return opExpr({ cond: [c, lowerValue(result, "when then"), null] });
1698
+ }
1699
+ if (f.pendingMap.when !== void 0)
1700
+ afail("BAD_CONDITION", `method '${f.method}': a .map callback records at most one when(...) guard`);
1701
+ f.pendingMap.when = c;
1702
+ return result;
1703
+ }
1704
+ const thenFrame = { cond: c, gateId: null, startLen: f.nodes.length };
1705
+ f.branchStack.push(thenFrame);
1706
+ let thenVal;
1707
+ try {
1708
+ thenVal = then();
1709
+ } finally {
1710
+ f.branchStack.pop();
1711
+ }
1712
+ const thenHasComponents = f.nodes.length > thenFrame.startLen;
1713
+ let elseVal = null;
1714
+ let elseHasComponents = false;
1715
+ if (otherwise !== void 0) {
1716
+ const elseFrame = { cond: { not: [c] }, gateId: null, startLen: f.nodes.length };
1717
+ f.branchStack.push(elseFrame);
1718
+ try {
1719
+ elseVal = otherwise();
1720
+ } finally {
1721
+ f.branchStack.pop();
1722
+ }
1723
+ elseHasComponents = f.nodes.length > elseFrame.startLen;
1724
+ }
1725
+ if (!thenHasComponents && !elseHasComponents)
1726
+ return opExpr({ cond: [c, lowerValue(thenVal, "when then"), lowerValue(elseVal, "when else")] });
1727
+ if (otherwise === void 0)
1728
+ return thenVal;
1729
+ const id = nextId(f);
1730
+ const phi = {
1731
+ id,
1732
+ cond: { if: c, then: lowerValue(thenVal, "when then"), else: lowerValue(elseVal, "when else") }
1733
+ };
1734
+ f.nodes.push(phi);
1735
+ return nodeHandle(id);
1736
+ }
1737
+ var NATIVE_CONTROL_TOKEN = /\?\?=|&&=|\|\|=|\?\?|\?\.|&&|\|\||===|!==|==|!=|\bif\s*\(|\bswitch\s*\(|[?!]/;
1738
+ var REGEX_PRECEDING_KEYWORDS = /* @__PURE__ */ new Set([
1739
+ "return",
1740
+ "typeof",
1741
+ "instanceof",
1742
+ "in",
1743
+ "of",
1744
+ "case",
1745
+ "do",
1746
+ "else",
1747
+ "void",
1748
+ "delete",
1749
+ "throw",
1750
+ "new",
1751
+ "yield",
1752
+ "await"
1753
+ ]);
1754
+ var WORD_CHAR = /[A-Za-z0-9_$#]/;
1755
+ function regexCanFollow(prev, word) {
1756
+ if (prev === "")
1757
+ return true;
1758
+ if (WORD_CHAR.test(prev))
1759
+ return REGEX_PRECEDING_KEYWORDS.has(word);
1760
+ return !")]}\"'`.".includes(prev);
1761
+ }
1762
+ function stripNonCode(src) {
1763
+ const out = src.split("");
1764
+ const blank = (idx) => {
1765
+ if (out[idx] !== "\n")
1766
+ out[idx] = " ";
1767
+ };
1768
+ const stack = [{ tpl: false, braces: 0 }];
1769
+ let prev = "";
1770
+ let word = "";
1771
+ let prevWasWord = false;
1772
+ let i = 0;
1773
+ while (i < src.length) {
1774
+ const top = stack[stack.length - 1];
1775
+ const ch = src[i];
1776
+ if (top.tpl) {
1777
+ if (ch === "\\") {
1778
+ blank(i);
1779
+ if (i + 1 < src.length)
1780
+ blank(i + 1);
1781
+ i += 2;
1782
+ continue;
1783
+ }
1784
+ if (ch === "`") {
1785
+ stack.pop();
1786
+ i++;
1787
+ prev = "`";
1788
+ word = "";
1789
+ prevWasWord = false;
1790
+ continue;
1791
+ }
1792
+ if (ch === "$" && src[i + 1] === "{") {
1793
+ stack.push({ tpl: false, braces: 0 });
1794
+ i += 2;
1795
+ prev = "{";
1796
+ word = "";
1797
+ prevWasWord = false;
1798
+ continue;
1799
+ }
1800
+ blank(i);
1801
+ i++;
1802
+ continue;
1803
+ }
1804
+ const nx = src[i + 1];
1805
+ if (ch === "/" && nx === "/") {
1806
+ while (i < src.length && src[i] !== "\n")
1807
+ blank(i++);
1808
+ continue;
1809
+ }
1810
+ if (ch === "/" && nx === "*") {
1811
+ blank(i);
1812
+ blank(i + 1);
1813
+ i += 2;
1814
+ while (i < src.length && !(src[i] === "*" && src[i + 1] === "/"))
1815
+ blank(i++);
1816
+ if (i < src.length) {
1817
+ blank(i);
1818
+ blank(i + 1);
1819
+ i += 2;
1820
+ }
1821
+ continue;
1822
+ }
1823
+ if (ch === '"' || ch === "'") {
1824
+ i++;
1825
+ while (i < src.length && src[i] !== ch && src[i] !== "\n") {
1826
+ if (src[i] === "\\") {
1827
+ blank(i);
1828
+ i++;
1829
+ if (i < src.length) {
1830
+ blank(i);
1831
+ i++;
1832
+ }
1833
+ continue;
1834
+ }
1835
+ blank(i);
1836
+ i++;
1837
+ }
1838
+ if (i < src.length && src[i] === ch)
1839
+ i++;
1840
+ prev = ch;
1841
+ word = "";
1842
+ prevWasWord = false;
1843
+ continue;
1844
+ }
1845
+ if (ch === "`") {
1846
+ stack.push({ tpl: true, braces: 0 });
1847
+ i++;
1848
+ prev = "`";
1849
+ word = "";
1850
+ prevWasWord = false;
1851
+ continue;
1852
+ }
1853
+ if (ch === "/" && regexCanFollow(prev, word)) {
1854
+ blank(i);
1855
+ i++;
1856
+ let inClass = false;
1857
+ while (i < src.length && (inClass || src[i] !== "/") && src[i] !== "\n") {
1858
+ if (src[i] === "\\") {
1859
+ blank(i);
1860
+ i++;
1861
+ if (i < src.length) {
1862
+ blank(i);
1863
+ i++;
1864
+ }
1865
+ continue;
1866
+ }
1867
+ if (src[i] === "[")
1868
+ inClass = true;
1869
+ else if (src[i] === "]")
1870
+ inClass = false;
1871
+ blank(i);
1872
+ i++;
1873
+ }
1874
+ if (i < src.length && src[i] === "/") {
1875
+ blank(i);
1876
+ i++;
1877
+ }
1878
+ while (i < src.length && /[a-z]/i.test(src[i])) {
1879
+ blank(i);
1880
+ i++;
1881
+ }
1882
+ prev = "/";
1883
+ word = "";
1884
+ prevWasWord = false;
1885
+ continue;
1886
+ }
1887
+ if (ch === "{")
1888
+ top.braces++;
1889
+ else if (ch === "}") {
1890
+ if (top.braces === 0 && stack.length > 1) {
1891
+ stack.pop();
1892
+ i++;
1893
+ prev = "}";
1894
+ word = "";
1895
+ prevWasWord = false;
1896
+ continue;
1897
+ }
1898
+ top.braces--;
1899
+ }
1900
+ if (WORD_CHAR.test(ch)) {
1901
+ word = prevWasWord ? word + ch : ch;
1902
+ prevWasWord = true;
1903
+ } else {
1904
+ prevWasWord = false;
1905
+ if (!/\s/.test(ch))
1906
+ word = "";
1907
+ }
1908
+ if (!/\s/.test(ch))
1909
+ prev = ch;
1910
+ i++;
1911
+ }
1912
+ return out.join("");
1913
+ }
1914
+ function nativeControlHint(token) {
1915
+ if (token.startsWith("if"))
1916
+ return { name: "if (...)", hint: "use when(cond, () => then, () => else)" };
1917
+ if (token.startsWith("switch"))
1918
+ return { name: "switch (...)", hint: "use when(...) chains with eq(...) conditions" };
1919
+ switch (token) {
1920
+ case "??=":
1921
+ case "&&=":
1922
+ case "||=":
1923
+ return { name: token, hint: "authoring is declarative; bind a fresh const via coalesce/and/or builders" };
1924
+ case "??":
1925
+ return { name: "??", hint: "use coalesce(a, b)" };
1926
+ case "?.":
1927
+ return { name: "?.", hint: "use opt(x).field (refOpt)" };
1928
+ case "&&":
1929
+ return { name: "&&", hint: "use when(cond, () => x) for a guard, or and(a, b) for a boolean" };
1930
+ case "||":
1931
+ return { name: "||", hint: "use or(a, b) for a boolean, or coalesce(a, b) for a default" };
1932
+ case "===":
1933
+ case "==":
1934
+ return { name: token, hint: "use eq(a, b)" };
1935
+ case "!==":
1936
+ case "!=":
1937
+ return { name: token, hint: "use ne(a, b)" };
1938
+ case "?":
1939
+ return { name: "?:", hint: "use when(cond, () => then, () => else)" };
1940
+ default:
1941
+ return { name: "!", hint: "use not(x) or ne(a, b)" };
1942
+ }
1943
+ }
1944
+ function scanNativeControlSyntax(source, label) {
1945
+ const stripped = stripNonCode(source);
1946
+ const bodyStart = stripped.indexOf("{");
1947
+ if (bodyStart < 0)
1948
+ return;
1949
+ const m = NATIVE_CONTROL_TOKEN.exec(stripped.slice(bodyStart + 1));
1950
+ if (!m)
1951
+ return;
1952
+ const at = bodyStart + 1 + m.index;
1953
+ const excerpt = source.slice(Math.max(0, at - 30), Math.min(source.length, at + 30)).replace(/\s+/g, " ").trim();
1954
+ const { name, hint } = nativeControlHint(m[0]);
1955
+ afail("NATIVE_CONTROL_SYNTAX", `${label}: native control syntax '${name}' cannot be observed over recorded values at build time (JS Proxy has no ToBoolean/equality trap) and would silently mislower the DAG \u2014 ${hint} (near \`${excerpt}\`)`);
1956
+ }
1957
+ function compileBehaviors(cls, opts = {}) {
1958
+ if (!isBehaviorClass(cls))
1959
+ afail("NOT_A_BEHAVIOR_CLASS", `class '${cls?.name ?? String(cls)}' is not a behavior class (extend SemanticBehavior or mark it with @behavior)`);
1960
+ const proto = cls.prototype;
1961
+ const methodNames = Object.getOwnPropertyNames(proto).filter((name) => {
1962
+ if (name === "constructor" || name.startsWith("_") || name.startsWith("#"))
1963
+ return false;
1964
+ const d = Object.getOwnPropertyDescriptor(proto, name);
1965
+ return typeof d?.value === "function";
1966
+ });
1967
+ if (methodNames.length === 0)
1968
+ afail("NO_PUBLIC_METHOD", `class '${cls.name}' declares no public method (each public method is one root Behavior)`);
1969
+ for (const method of methodNames)
1970
+ scanNativeControlSyntax(proto[method].toString(), `method '${method}'`);
1971
+ for (const name of Object.getOwnPropertyNames(proto)) {
1972
+ if (name === "constructor" || methodNames.includes(name))
1973
+ continue;
1974
+ const d = Object.getOwnPropertyDescriptor(proto, name);
1975
+ if (typeof d?.value === "function")
1976
+ scanNativeControlSyntax(d.value.toString(), `helper '${name}'`);
1977
+ }
1978
+ for (let k = cls; typeof k === "function" && k !== SemanticBehavior && k !== Function.prototype; k = Object.getPrototypeOf(k)) {
1979
+ const src = Function.prototype.toString.call(k);
1980
+ if (!/\{\s*\[native code\]\s*\}/.test(src))
1981
+ scanNativeControlSyntax(src, `class '${k.name || "<anonymous>"}'`);
1982
+ }
1983
+ const instance = new cls();
1984
+ const components2 = [];
1985
+ for (const method of methodNames) {
1986
+ const frame = {
1987
+ method,
1988
+ nodes: [],
1989
+ nodeIds: /* @__PURE__ */ new Set(),
1990
+ inputPorts: /* @__PURE__ */ new Map(),
1991
+ seq: 0,
1992
+ mapSeq: 0,
1993
+ branchStack: [],
1994
+ pendingMap: null
1995
+ };
1996
+ const dollar = makeExpr({ node: { ref: [] }, refPath: [], refOp: "ref", isInput: true });
1997
+ currentFrame = frame;
1998
+ let returned;
1999
+ try {
2000
+ returned = proto[method].call(instance, dollar);
2001
+ } finally {
2002
+ currentFrame = null;
2003
+ }
2004
+ if (returned === void 0)
2005
+ afail("BAD_OUTPUT", `method '${method}' must return its Output Port (got undefined)`);
2006
+ if (returned instanceof Promise)
2007
+ afail("BAD_OUTPUT", `method '${method}' must be synchronous and declarative (async/await is derived by the compiler, not written)`);
2008
+ const output = lowerValue(returned, `method '${method}' output`);
2009
+ const inputPorts = {};
2010
+ for (const [k, s] of frame.inputPorts)
2011
+ inputPorts[k] = opts.inputPorts?.[method]?.[k] ?? s;
2012
+ for (const [k, s] of Object.entries(opts.inputPorts?.[method] ?? {}))
2013
+ if (!(k in inputPorts))
2014
+ inputPorts[k] = s;
2015
+ components2.push(buildComponentCore({ name: method, inputPorts, body: frame.nodes, output }, { concurrency: opts.concurrency ?? DEFAULT_PLAN_CONCURRENCY }));
2016
+ }
2017
+ const ir = { irVersion: 1, exprVersion: opts.exprVersion ?? SPEC_VERSIONS.expression, components: components2 };
2018
+ assertPortableComponentGraph(ir);
2019
+ return ir;
2020
+ }
2021
+ function referencedComponents(component) {
2022
+ const out = [];
2023
+ for (const n of component.body) {
2024
+ const name = "map" in n ? n.map.component : "cond" in n ? null : n.component;
2025
+ if (name !== null && !out.includes(name))
2026
+ out.push(name);
2027
+ }
2028
+ return out;
2029
+ }
2030
+ function classifyBehaviorEffect(component, writeComponents) {
2031
+ const writes = new Set(writeComponents);
2032
+ return referencedComponents(component).some((c) => writes.has(c)) ? "writing" : "read-only";
2033
+ }
2034
+
2035
+ // node_modules/behavior-contracts/dist/generator/fingerprint.js
2036
+ var FingerprintFailure = class extends Error {
2037
+ code;
2038
+ constructor(code, message) {
2039
+ super(message);
2040
+ this.code = code;
2041
+ this.name = "FingerprintFailure";
2042
+ }
2043
+ };
2044
+ function toValueDomain(doc, path) {
2045
+ if (doc === null || typeof doc === "boolean" || typeof doc === "string")
2046
+ return doc;
2047
+ if (typeof doc === "number") {
2048
+ if (Number.isInteger(doc) && !Object.is(doc, -0)) {
2049
+ if (Math.abs(doc) >= 2 ** 53)
2050
+ throw new FingerprintFailure("UNSAFE_NUMBER", `integral number ${doc} at ${path} exceeds float64-exact range; portable IR must use {int:"..."} (fail-closed)`);
2051
+ return BigInt(doc);
2052
+ }
2053
+ return doc;
2054
+ }
2055
+ if (Array.isArray(doc))
2056
+ return doc.map((v, i) => toValueDomain(v, `${path}[${i}]`));
2057
+ if (typeof doc === "object") {
2058
+ const out = {};
2059
+ for (const [k, v] of Object.entries(doc))
2060
+ out[k] = toValueDomain(v, `${path}.${k}`);
2061
+ return out;
2062
+ }
2063
+ throw new FingerprintFailure("INVALID_VALUE", `value of type ${typeof doc} at ${path} cannot appear in a portable IR document (fail-closed)`);
2064
+ }
2065
+ function utf8Bytes(s) {
2066
+ const out = [];
2067
+ for (const ch of s) {
2068
+ const cp = ch.codePointAt(0);
2069
+ if (cp <= 127)
2070
+ out.push(cp);
2071
+ else if (cp <= 2047)
2072
+ out.push(192 | cp >> 6, 128 | cp & 63);
2073
+ else if (cp <= 65535)
2074
+ out.push(224 | cp >> 12, 128 | cp >> 6 & 63, 128 | cp & 63);
2075
+ else
2076
+ out.push(240 | cp >> 18, 128 | cp >> 12 & 63, 128 | cp >> 6 & 63, 128 | cp & 63);
2077
+ }
2078
+ return out;
2079
+ }
2080
+ function fnv1a64(bytes) {
2081
+ let h = 0xcbf29ce484222325n;
2082
+ const prime = 0x100000001b3n;
2083
+ const mask = 0xffffffffffffffffn;
2084
+ for (const b of bytes) {
2085
+ h ^= BigInt(b);
2086
+ h = h * prime & mask;
2087
+ }
2088
+ return h.toString(16).padStart(16, "0");
2089
+ }
2090
+ function fingerprintComponentGraph(doc) {
2091
+ const s = canonicalJson(toValueDomain(doc, "$"));
2092
+ return "fnv1a64:" + fnv1a64(utf8Bytes(s));
2093
+ }
2094
+
2095
+ // node_modules/behavior-contracts/dist/generator/core.js
2096
+ var GeneratorFailure = class extends Error {
2097
+ code;
2098
+ constructor(code, message) {
2099
+ super(message);
2100
+ this.code = code;
2101
+ this.name = "GeneratorFailure";
2102
+ }
2103
+ };
2104
+ function gfail(code, message) {
2105
+ throw new GeneratorFailure(code, message);
2106
+ }
2107
+ var registry = /* @__PURE__ */ new Map();
2108
+ function registerEmitter(plugin) {
2109
+ registry.set(plugin.language, plugin);
2110
+ }
2111
+ function registeredLanguages() {
2112
+ return [...registry.keys()].sort();
2113
+ }
2114
+ function validateGeneratorInput(ir) {
2115
+ if (ir === null || typeof ir !== "object" || Array.isArray(ir))
2116
+ gfail("INPUT_NOT_PORTABLE_IR", "generator input must be a portable component-graph IR document ({irVersion, exprVersion, components[]} \u2014 scp-ir-architecture.md \xA75); got a non-object (fail-closed)");
2117
+ const doc = ir;
2118
+ if (doc.irVersion === void 0 || doc.components === void 0)
2119
+ gfail("INPUT_NOT_PORTABLE_IR", "generator input must be a portable component-graph IR document ({irVersion, exprVersion, components[]}); the codegen path consumes portable IR ONLY \u2014 never source/internal IR or consumer bundles (fail-closed)");
2120
+ if (doc.irVersion !== 1)
2121
+ gfail("UNSUPPORTED_IR_VERSION", `irVersion ${String(doc.irVersion)} is not supported (supported: 1) (fail-closed)`);
2122
+ const exprVersion = doc.exprVersion;
2123
+ if (typeof exprVersion !== "number" || !Number.isInteger(exprVersion) || exprVersion < 1)
2124
+ gfail("INPUT_NOT_PORTABLE_IR", `exprVersion must be a positive integer, got ${String(exprVersion)} (fail-closed)`);
2125
+ if (exprVersion > SPEC_VERSIONS.expression)
2126
+ gfail("UNSUPPORTED_EXPR_VERSION", `exprVersion ${exprVersion} exceeds supported expression version ${SPEC_VERSIONS.expression} (fail-closed)`);
2127
+ assertPortableComponentGraph(ir);
2128
+ const components2 = doc.components;
2129
+ if (components2.length === 0)
2130
+ gfail("EMPTY_IR", "IR has no components \u2014 nothing to generate (fail-closed)");
2131
+ const seen = /* @__PURE__ */ new Set();
2132
+ for (const c of components2) {
2133
+ if (seen.has(c.name))
2134
+ gfail("DUPLICATE_COMPONENT", `component name '${c.name}' appears more than once \u2014 bind() keys must be unique (fail-closed)`);
2135
+ seen.add(c.name);
2136
+ }
2137
+ return ir;
2138
+ }
2139
+ function generateModule(ir, options) {
2140
+ const plugin = registry.get(options.language);
2141
+ if (!plugin)
2142
+ gfail("UNKNOWN_LANGUAGE", `no emitter registered for language '${options.language}' (registered: ${registeredLanguages().join(", ")}) (fail-closed)`);
2143
+ const validated = validateGeneratorInput(ir);
2144
+ const fingerprint = fingerprintComponentGraph(validated);
2145
+ const specVersions = {
2146
+ behavior: SPEC_VERSIONS.behavior,
2147
+ expression: SPEC_VERSIONS.expression,
2148
+ plan: SPEC_VERSIONS.plan
2149
+ };
2150
+ const componentNames = validated.components.map((c) => c.name);
2151
+ const ctx = {
2152
+ ir: validated,
2153
+ fingerprint,
2154
+ specVersions,
2155
+ componentNames,
2156
+ runtimeImport: options.runtimeImport ?? plugin.defaultRuntimeImport
2157
+ };
2158
+ return {
2159
+ language: plugin.language,
2160
+ code: plugin.emit(ctx),
2161
+ fingerprint,
2162
+ specVersions,
2163
+ componentNames,
2164
+ filenameHint: plugin.filenameHint ?? `behaviors.generated${plugin.fileExtension}`
2165
+ };
2166
+ }
2167
+
2168
+ // node_modules/behavior-contracts/dist/generator/literal.js
2169
+ function rustStr(s) {
2170
+ let out = '"';
2171
+ for (const ch of s) {
2172
+ const cp = ch.codePointAt(0);
2173
+ if (ch === '"')
2174
+ out += '\\"';
2175
+ else if (ch === "\\")
2176
+ out += "\\\\";
2177
+ else if (ch === "\n")
2178
+ out += "\\n";
2179
+ else if (ch === "\r")
2180
+ out += "\\r";
2181
+ else if (ch === " ")
2182
+ out += "\\t";
2183
+ else if (cp < 32)
2184
+ out += `\\u{${cp.toString(16)}}`;
2185
+ else
2186
+ out += ch;
2187
+ }
2188
+ return out + '"';
2189
+ }
2190
+ function phpStr(s) {
2191
+ let out = '"';
2192
+ for (const ch of s) {
2193
+ const cp = ch.codePointAt(0);
2194
+ if (ch === '"')
2195
+ out += '\\"';
2196
+ else if (ch === "\\")
2197
+ out += "\\\\";
2198
+ else if (ch === "$")
2199
+ out += "\\$";
2200
+ else if (ch === "\n")
2201
+ out += "\\n";
2202
+ else if (ch === "\r")
2203
+ out += "\\r";
2204
+ else if (ch === " ")
2205
+ out += "\\t";
2206
+ else if (cp < 32)
2207
+ out += `\\u{${cp.toString(16)}}`;
2208
+ else
2209
+ out += ch;
2210
+ }
2211
+ return out + '"';
2212
+ }
2213
+ var jsonishArr = (open, close) => (items, pad, padIn) => `${open}
2214
+ ${items.map((v) => padIn + v).join(",\n")}
2215
+ ${pad}${close}`;
2216
+ var DIALECTS = {
2217
+ ts: {
2218
+ indentUnit: " ",
2219
+ null: "null",
2220
+ true: "true",
2221
+ false: "false",
2222
+ str: (s) => JSON.stringify(s),
2223
+ int: (t) => t,
2224
+ float: (t) => t,
2225
+ emptyArr: "[]",
2226
+ emptyObj: "{}",
2227
+ arr: jsonishArr("[", "]"),
2228
+ obj: (entries, pad, padIn) => `{
2229
+ ${entries.map(([k, v]) => `${padIn}${JSON.stringify(k)}: ${v}`).join(",\n")}
2230
+ ${pad}}`
2231
+ },
2232
+ py: {
2233
+ indentUnit: " ",
2234
+ null: "None",
2235
+ true: "True",
2236
+ false: "False",
2237
+ str: (s) => JSON.stringify(s),
2238
+ int: (t) => t,
2239
+ float: (t) => t,
2240
+ emptyArr: "[]",
2241
+ emptyObj: "{}",
2242
+ arr: jsonishArr("[", "]"),
2243
+ obj: (entries, pad, padIn) => `{
2244
+ ${entries.map(([k, v]) => `${padIn}${JSON.stringify(k)}: ${v}`).join(",\n")}
2245
+ ${pad}}`
2246
+ },
2247
+ go: {
2248
+ indentUnit: " ",
2249
+ null: "nil",
2250
+ true: "true",
2251
+ false: "false",
2252
+ str: (s) => JSON.stringify(s),
2253
+ // JSON エスケープは Go 文字列リテラルとして合法
2254
+ int: (t) => `json.Number("${t}")`,
2255
+ float: (t) => `json.Number("${t}")`,
2256
+ emptyArr: "[]dslcontracts.JNode{}",
2257
+ emptyObj: "dslcontracts.JObjOf()",
2258
+ arr: (items, pad, padIn) => `[]dslcontracts.JNode{
2259
+ ${items.map((v) => `${padIn}${v},`).join("\n")}
2260
+ ${pad}}`,
2261
+ obj: (entries, pad, padIn) => `dslcontracts.JObjOf(
2262
+ ${entries.map(([k, v]) => `${padIn}${JSON.stringify(k)}, ${v},`).join("\n")}
2263
+ ${pad})`
2264
+ },
2265
+ rust: {
2266
+ indentUnit: " ",
2267
+ null: "null",
2268
+ // json! マクロ内の JSON トークン
2269
+ true: "true",
2270
+ false: "false",
2271
+ str: rustStr,
2272
+ int: (t) => t,
2273
+ float: (t) => t,
2274
+ emptyArr: "[]",
2275
+ emptyObj: "{}",
2276
+ arr: jsonishArr("[", "]"),
2277
+ obj: (entries, pad, padIn) => `{
2278
+ ${entries.map(([k, v]) => `${padIn}${rustStr(k)}: ${v}`).join(",\n")}
2279
+ ${pad}}`
2280
+ },
2281
+ php: {
2282
+ indentUnit: " ",
2283
+ null: "null",
2284
+ true: "true",
2285
+ false: "false",
2286
+ str: phpStr,
2287
+ int: (t) => t,
2288
+ float: (t) => t,
2289
+ emptyArr: "[]",
2290
+ emptyObj: "(object) []",
2291
+ arr: (items, pad, padIn) => `[
2292
+ ${items.map((v) => `${padIn}${v},`).join("\n")}
2293
+ ${pad}]`,
2294
+ obj: (entries, pad, padIn) => `(object) [
2295
+ ${entries.map(([k, v]) => `${padIn}${phpStr(k)} => ${v},`).join("\n")}
2296
+ ${pad}]`
2297
+ }
2298
+ };
2299
+ function scalarNumber(n, path, d) {
2300
+ if (!Number.isFinite(n))
2301
+ throw new FingerprintFailure("INVALID_VALUE", `non-finite number at ${path} cannot be emitted (fail-closed)`);
2302
+ if (Object.is(n, -0))
2303
+ return d.float("-0.0");
2304
+ if (Number.isInteger(n)) {
2305
+ if (Math.abs(n) >= 2 ** 53)
2306
+ throw new FingerprintFailure("UNSAFE_NUMBER", `integral number ${n} at ${path} exceeds float64-exact range; portable IR must use {int:"..."} (fail-closed)`);
2307
+ return d.int(String(n));
2308
+ }
2309
+ return d.float(String(n));
2310
+ }
2311
+ function emitDocLiteral(doc, style, indent = 0, path = "$") {
2312
+ const d = DIALECTS[style];
2313
+ const pad = d.indentUnit.repeat(indent);
2314
+ const padIn = d.indentUnit.repeat(indent + 1);
2315
+ if (doc === null)
2316
+ return d.null;
2317
+ if (typeof doc === "boolean")
2318
+ return doc ? d.true : d.false;
2319
+ if (typeof doc === "string")
2320
+ return d.str(doc);
2321
+ if (typeof doc === "number")
2322
+ return scalarNumber(doc, path, d);
2323
+ if (Array.isArray(doc)) {
2324
+ if (doc.length === 0)
2325
+ return d.emptyArr;
2326
+ const items = doc.map((v, i) => emitDocLiteral(v, style, indent + 1, `${path}[${i}]`));
2327
+ return d.arr(items, pad, padIn);
2328
+ }
2329
+ if (typeof doc === "object") {
2330
+ const entries = Object.entries(doc);
2331
+ if (entries.length === 0)
2332
+ return d.emptyObj;
2333
+ const emitted = entries.map(([k, v]) => [
2334
+ k,
2335
+ emitDocLiteral(v, style, indent + 1, `${path}.${k}`)
2336
+ ]);
2337
+ return d.obj(emitted, pad, padIn);
2338
+ }
2339
+ throw new FingerprintFailure("INVALID_VALUE", `value of type ${typeof doc} at ${path} cannot be emitted as a portable IR literal (fail-closed)`);
2340
+ }
2341
+
2342
+ // node_modules/behavior-contracts/dist/generator/emit-typescript.js
2343
+ function emit(ctx) {
2344
+ const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
2345
+ const spec = runtimeImport;
2346
+ const names = componentNames.map((n) => JSON.stringify(n)).join(", ");
2347
+ const irLiteral = emitDocLiteral(ctx.ir, "ts");
2348
+ return `// GENERATED by behavior-contracts common generator (bc#13) \u2014 DO NOT EDIT.
2349
+ // Input: portable component-graph IR only (scp-ir-architecture.md \xA75/\xA77.4).
2350
+ // This module is the codegen endpoint (\xA77.3 endpoint 3): the IR is embedded as a
2351
+ // typed native literal and handed to the EXISTING runtime core (runBehavior) \u2014
2352
+ // no execution logic is generated. Handlers are ALWAYS injected at the boundary
2353
+ // (IR + {effects,config,hooks} \u2014 concept.md \xA74.4); they are never generated.
2354
+ // irFingerprint: ${fingerprint}
2355
+ import { SPEC_VERSIONS, fingerprintComponentGraph, runBehavior, runBehaviorAsync } from ${JSON.stringify(spec)};
2356
+ import type { AsyncHandlers, ComponentGraphIR, Handlers, Scope, Value } from ${JSON.stringify(spec)};
2357
+
2358
+ /** Spec versions baked at generation time (fail-closed constant comparison at load). */
2359
+ export const EXPECTED_SPEC_VERSIONS = { behavior: ${specVersions.behavior}, expression: ${specVersions.expression}, plan: ${specVersions.plan} } as const;
2360
+
2361
+ /** FNV-1a 64 fingerprint of the source portable IR (canonicalJson discipline, #208). */
2362
+ export const IR_FINGERPRINT = ${JSON.stringify(fingerprint)};
2363
+
2364
+ /** Component names exposed by bind()/bindAsync(), in IR declaration order. */
2365
+ export const COMPONENT_NAMES: readonly string[] = [${names}];
2366
+
2367
+ /** The portable component-graph IR, embedded as a typed native literal (no JSON parse at runtime). */
2368
+ export const IR: ComponentGraphIR = ${irLiteral};
2369
+
2370
+ // \u2500\u2500 load-time fail-closed checks (#208 prepared-artifact discipline) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2371
+ for (const [k, want] of Object.entries(EXPECTED_SPEC_VERSIONS)) {
2372
+ const got = (SPEC_VERSIONS as Record<string, number>)[k];
2373
+ if (got !== want)
2374
+ throw new Error(
2375
+ \`behavior-contracts generated module: spec-version skew for '\${k}' (generated=\${want}, runtime=\${got}) \u2014 regenerate against this runtime (fail-closed)\`,
2376
+ );
2377
+ }
2378
+ if (fingerprintComponentGraph(IR) !== IR_FINGERPRINT)
2379
+ throw new Error(
2380
+ \`behavior-contracts generated module: IR fingerprint mismatch (baked=\${IR_FINGERPRINT}, embedded literal=\${fingerprintComponentGraph(IR)}) \u2014 the generated code was modified or corrupted (fail-closed)\`,
2381
+ );
2382
+
2383
+ /**
2384
+ * bind \u2014 inject handlers (boundary injection; catalog name \u2192 implementation) and
2385
+ * get one callable per component. Each call delegates to the runtime core's
2386
+ * runBehavior over the embedded IR (dynamic-path equivalent \u2014 \xA77.3).
2387
+ */
2388
+ export function bind(handlers: Handlers): Record<string, (input?: Scope) => Value> {
2389
+ const bound: Record<string, (input?: Scope) => Value> = {};
2390
+ for (const name of COMPONENT_NAMES) bound[name] = (input: Scope = {}) => runBehavior(IR, handlers, input, name);
2391
+ return bound;
2392
+ }
2393
+
2394
+ /** bindAsync \u2014 as bind, over runBehaviorAsync (bounded stage parallelism per plan.concurrency). */
2395
+ export function bindAsync(handlers: AsyncHandlers): Record<string, (input?: Scope) => Promise<Value>> {
2396
+ const bound: Record<string, (input?: Scope) => Promise<Value>> = {};
2397
+ for (const name of COMPONENT_NAMES)
2398
+ bound[name] = (input: Scope = {}) => runBehaviorAsync(IR, handlers, input, name);
2399
+ return bound;
2400
+ }
2401
+ `;
2402
+ }
2403
+ var typescriptEmitter = {
2404
+ language: "typescript",
2405
+ fileExtension: ".ts",
2406
+ defaultRuntimeImport: "behavior-contracts",
2407
+ emit
2408
+ };
2409
+
2410
+ // node_modules/behavior-contracts/dist/generator/emit-python.js
2411
+ function pyStr(s) {
2412
+ return JSON.stringify(s);
2413
+ }
2414
+ function emit2(ctx) {
2415
+ const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
2416
+ const names = componentNames.map(pyStr).join(", ");
2417
+ const namesTuple = componentNames.length === 1 ? `(${names},)` : `(${names})`;
2418
+ const irLiteral = emitDocLiteral(ctx.ir, "py");
2419
+ return `# GENERATED by behavior-contracts common generator (bc#13) \u2014 DO NOT EDIT.
2420
+ # Input: portable component-graph IR only (scp-ir-architecture.md \xA75/\xA77.4).
2421
+ # This module is the codegen endpoint (\xA77.3 endpoint 3): the IR is embedded as a
2422
+ # native dict literal and handed to the EXISTING runtime core (run_behavior) \u2014
2423
+ # no execution logic is generated. Handlers are ALWAYS injected at the boundary
2424
+ # (IR + {effects,config,hooks}); they are never generated.
2425
+ # irFingerprint: ${fingerprint}
2426
+ from ${runtimeImport} import SPEC_VERSIONS, fingerprint_component_graph, run_behavior
2427
+
2428
+ # Spec versions baked at generation time (fail-closed constant comparison at load).
2429
+ EXPECTED_SPEC_VERSIONS = {"behavior": ${specVersions.behavior}, "expression": ${specVersions.expression}, "plan": ${specVersions.plan}}
2430
+
2431
+ # FNV-1a 64 fingerprint of the source portable IR (canonical_json discipline, #208).
2432
+ IR_FINGERPRINT = ${pyStr(fingerprint)}
2433
+
2434
+ # Component names exposed by bind(), in IR declaration order.
2435
+ COMPONENT_NAMES = ${namesTuple}
2436
+
2437
+ # The portable component-graph IR, embedded as a native dict literal (no JSON parse at runtime).
2438
+ IR = ${irLiteral}
2439
+
2440
+
2441
+ def _check_generated_module() -> None:
2442
+ # load-time fail-closed checks (#208 prepared-artifact discipline).
2443
+ for _k, _want in EXPECTED_SPEC_VERSIONS.items():
2444
+ _got = SPEC_VERSIONS.get(_k)
2445
+ if _got != _want:
2446
+ raise RuntimeError(
2447
+ "behavior-contracts generated module: spec-version skew for '%s' "
2448
+ "(generated=%s, runtime=%s) \u2014 regenerate against this runtime (fail-closed)"
2449
+ % (_k, _want, _got)
2450
+ )
2451
+ _got_fp = fingerprint_component_graph(IR)
2452
+ if _got_fp != IR_FINGERPRINT:
2453
+ raise RuntimeError(
2454
+ "behavior-contracts generated module: IR fingerprint mismatch "
2455
+ "(baked=%s, embedded literal=%s) \u2014 the generated code was modified or corrupted (fail-closed)"
2456
+ % (IR_FINGERPRINT, _got_fp)
2457
+ )
2458
+
2459
+
2460
+ _check_generated_module()
2461
+
2462
+
2463
+ def bind(handlers):
2464
+ """Inject handlers (boundary injection; catalog name -> implementation) and get
2465
+ one callable per component. Each call delegates to the runtime core's
2466
+ run_behavior over the embedded IR (dynamic-path equivalent \u2014 \xA77.3)."""
2467
+
2468
+ def _make(name):
2469
+ def _call(input=None):
2470
+ return run_behavior(IR, handlers, dict(input or {}), name)
2471
+
2472
+ return _call
2473
+
2474
+ return {name: _make(name) for name in COMPONENT_NAMES}
2475
+ `;
2476
+ }
2477
+ var pythonEmitter = {
2478
+ language: "python",
2479
+ fileExtension: ".py",
2480
+ defaultRuntimeImport: "behavior_contracts",
2481
+ emit: emit2
2482
+ };
2483
+
2484
+ // node_modules/behavior-contracts/dist/generator/emit-go.js
2485
+ function emit3(ctx) {
2486
+ const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
2487
+ const names = componentNames.map((n) => JSON.stringify(n)).join(", ");
2488
+ const irLiteral = emitDocLiteral(ctx.ir, "go");
2489
+ return `// GENERATED by behavior-contracts common generator (bc#13) \u2014 DO NOT EDIT.
2490
+ // Input: portable component-graph IR only (scp-ir-architecture.md \xA75/\xA77.4).
2491
+ // This module is the codegen endpoint (\xA77.3 endpoint 3): the IR is embedded as a
2492
+ // native JNode composite literal and handed to the EXISTING runtime core
2493
+ // (RunBehavior) \u2014 no execution logic is generated. Handlers are ALWAYS injected
2494
+ // at the boundary (IR + {effects,config,hooks} \u2014 concept.md \xA74.4); they are
2495
+ // never generated.
2496
+ // irFingerprint: ${fingerprint}
2497
+
2498
+ package behaviors
2499
+
2500
+ import (
2501
+ "encoding/json"
2502
+ "fmt"
2503
+
2504
+ dslcontracts ${JSON.stringify(runtimeImport)}
2505
+ )
2506
+
2507
+ // ExpectedSpecVersions are the spec versions baked at generation time
2508
+ // (fail-closed constant comparison at init).
2509
+ var ExpectedSpecVersions = map[string]int64{"behavior": ${specVersions.behavior}, "expression": ${specVersions.expression}, "plan": ${specVersions.plan}}
2510
+
2511
+ // IRFingerprint is the FNV-1a 64 fingerprint of the source portable IR
2512
+ // (CanonicalJSON discipline, #208).
2513
+ const IRFingerprint = ${JSON.stringify(fingerprint)}
2514
+
2515
+ // ComponentNames are the components exposed by Bind(), in IR declaration order.
2516
+ var ComponentNames = []string{${names}}
2517
+
2518
+ // IR is the portable component-graph IR, embedded as a native JNode composite
2519
+ // literal (no JSON parse at runtime).
2520
+ var IR dslcontracts.JNode = ${irLiteral}
2521
+
2522
+ // init \u2014 load-time fail-closed checks (#208 prepared-artifact discipline).
2523
+ // A spec-version skew or fingerprint mismatch panics at package initialization,
2524
+ // so importing a stale/tampered generated module fails LOUDLY before any
2525
+ // behavior can run.
2526
+ func init() {
2527
+ for k, want := range ExpectedSpecVersions {
2528
+ if got := dslcontracts.SpecVersions[k]; got != want {
2529
+ panic(fmt.Sprintf("behavior-contracts generated module: spec-version skew for '%s' (generated=%d, runtime=%d) \u2014 regenerate against this runtime (fail-closed)", k, want, got))
2530
+ }
2531
+ }
2532
+ got, err := dslcontracts.FingerprintComponentGraph(IR)
2533
+ if err != nil {
2534
+ panic(fmt.Sprintf("behavior-contracts generated module: fingerprint recompute failed: %v (fail-closed)", err))
2535
+ }
2536
+ if got != IRFingerprint {
2537
+ panic(fmt.Sprintf("behavior-contracts generated module: IR fingerprint mismatch (baked=%s, embedded literal=%s) \u2014 the generated code was modified or corrupted (fail-closed)", IRFingerprint, got))
2538
+ }
2539
+ }
2540
+
2541
+ // Bind \u2014 inject handlers (boundary injection; catalog name \u2192 implementation) and
2542
+ // get one executor func per component. Each call delegates to the runtime core's
2543
+ // RunBehavior over the embedded IR (dynamic-path equivalent \u2014 \xA77.3).
2544
+ func Bind(handlers dslcontracts.ComponentExec) map[string]func(input *dslcontracts.Obj) (dslcontracts.Value, error) {
2545
+ bound := make(map[string]func(input *dslcontracts.Obj) (dslcontracts.Value, error), len(ComponentNames))
2546
+ for _, name := range ComponentNames {
2547
+ n := name
2548
+ bound[n] = func(input *dslcontracts.Obj) (dslcontracts.Value, error) {
2549
+ return dslcontracts.RunBehavior(IR, handlers, input, n)
2550
+ }
2551
+ }
2552
+ return bound
2553
+ }
2554
+ `;
2555
+ }
2556
+ var goEmitter = {
2557
+ language: "go",
2558
+ fileExtension: ".go",
2559
+ defaultRuntimeImport: "github.com/foo-ogawa/behavior-contracts/go",
2560
+ emit: emit3
2561
+ };
2562
+
2563
+ // node_modules/behavior-contracts/dist/generator/emit-rust.js
2564
+ function rustStrLit(s) {
2565
+ return JSON.stringify(s);
2566
+ }
2567
+ function componentNamesConst(names) {
2568
+ const items = names.map(rustStrLit);
2569
+ const oneLine = `pub const COMPONENT_NAMES: [&str; ${names.length}] = [${items.join(", ")}];`;
2570
+ if (oneLine.length <= 100)
2571
+ return oneLine;
2572
+ return `pub const COMPONENT_NAMES: [&str; ${names.length}] = [
2573
+ ${items.map((s) => ` ${s},`).join("\n")}
2574
+ ];`;
2575
+ }
2576
+ function emit4(ctx) {
2577
+ const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
2578
+ const irLiteral = emitDocLiteral(ctx.ir, "rust", 1);
2579
+ return `// GENERATED by behavior-contracts common generator (bc#13) \u2014 DO NOT EDIT.
2580
+ // Input: portable component-graph IR only (scp-ir-architecture.md \xA75/\xA77.4).
2581
+ // This module is the codegen endpoint (\xA77.3 endpoint 3): the IR is embedded as
2582
+ // NATIVE json! constructor code (compile-time checked; no JSON-text parsing at
2583
+ // runtime) and handed to the EXISTING runtime core (run_behavior) \u2014 no execution
2584
+ // logic is generated. Handlers are ALWAYS injected at the boundary
2585
+ // (IR + {effects,config,hooks} \u2014 concept.md \xA74.4); they are never generated.
2586
+ //
2587
+ // Const deviation (documented): serde_json::Value is not const-constructible, so
2588
+ // the IR is built ONCE on first use behind std::sync::LazyLock (requires Rust
2589
+ // >= 1.80). The first-use fail-closed checks (#208 prepared-artifact discipline)
2590
+ // run inside the initializer: a spec-version skew or fingerprint mismatch panics
2591
+ // LOUDLY before any behavior can run.
2592
+ // irFingerprint: ${fingerprint}
2593
+
2594
+ use ${runtimeImport}::{
2595
+ fingerprint_component_graph, run_behavior, BehaviorError, ComponentExec, SpecVersions, Value,
2596
+ };
2597
+ use serde_json::{json, Value as J};
2598
+ use std::sync::LazyLock;
2599
+
2600
+ /// Spec versions baked at generation time (fail-closed comparison on first use).
2601
+ pub const EXPECTED_SPEC_VERSIONS: [(&str, i64); 3] =
2602
+ [("behavior", ${specVersions.behavior}), ("expression", ${specVersions.expression}), ("plan", ${specVersions.plan})];
2603
+
2604
+ /// FNV-1a 64 fingerprint of the source portable IR (canonical_json discipline, #208).
2605
+ pub const IR_FINGERPRINT: &str = ${rustStrLit(fingerprint)};
2606
+
2607
+ /// Component names exposed by bind(), in IR declaration order.
2608
+ ${componentNamesConst(componentNames)}
2609
+
2610
+ /// The portable component-graph IR, built once on first use from native json!
2611
+ /// constructor code (no JSON-text parsing at runtime; see the const-deviation
2612
+ /// note in the module header).
2613
+ pub static IR: LazyLock<J> = LazyLock::new(|| {
2614
+ let ir = json!(${irLiteral});
2615
+ check_generated_module(&ir);
2616
+ ir
2617
+ });
2618
+
2619
+ fn runtime_spec_version(key: &str) -> i64 {
2620
+ match key {
2621
+ "behavior" => SpecVersions::BEHAVIOR,
2622
+ "expression" => SpecVersions::EXPRESSION,
2623
+ "plan" => SpecVersions::PLAN,
2624
+ other => {
2625
+ panic!("behavior-contracts generated module: unknown spec key '{other}' (fail-closed)")
2626
+ }
2627
+ }
2628
+ }
2629
+
2630
+ // First-use fail-closed checks (#208 prepared-artifact discipline).
2631
+ fn check_generated_module(ir: &J) {
2632
+ for (key, want) in EXPECTED_SPEC_VERSIONS {
2633
+ let got = runtime_spec_version(key);
2634
+ if got != want {
2635
+ panic!("behavior-contracts generated module: spec-version skew for '{key}' (generated={want}, runtime={got}) \u2014 regenerate against this runtime (fail-closed)");
2636
+ }
2637
+ }
2638
+ for name in COMPONENT_NAMES {
2639
+ let found = ir["components"]
2640
+ .as_array()
2641
+ .is_some_and(|cs| cs.iter().any(|c| c["name"] == name));
2642
+ if !found {
2643
+ panic!("behavior-contracts generated module: component '{name}' missing from the embedded IR \u2014 the generated code was modified or corrupted (fail-closed)");
2644
+ }
2645
+ }
2646
+ let got_fp = fingerprint_component_graph(ir).unwrap_or_else(|e| {
2647
+ panic!(
2648
+ "behavior-contracts generated module: fingerprint recompute failed: {e} (fail-closed)"
2649
+ )
2650
+ });
2651
+ if got_fp != IR_FINGERPRINT {
2652
+ panic!("behavior-contracts generated module: IR fingerprint mismatch (baked={IR_FINGERPRINT}, embedded literal={got_fp}) \u2014 the generated code was modified or corrupted (fail-closed)");
2653
+ }
2654
+ }
2655
+
2656
+ /// Injected-handler accessor over the embedded IR (see [\`bind\`]). Rust ownership
2657
+ /// makes a map of per-component closures sharing one \`&mut handlers\` impractical,
2658
+ /// so the per-component executor surface is \`call(name, input)\` with the
2659
+ /// component name checked against [\`COMPONENT_NAMES\`] by the runtime core.
2660
+ pub struct Bound<H: ComponentExec> {
2661
+ handlers: H,
2662
+ }
2663
+
2664
+ /// bind \u2014 inject handlers (boundary injection; catalog name \u2192 implementation)
2665
+ /// and get an executor over the embedded IR. Each \`call\` delegates to the
2666
+ /// runtime core's run_behavior (dynamic-path equivalent \u2014 \xA77.3). Forces the
2667
+ /// first-use fail-closed checks.
2668
+ pub fn bind<H: ComponentExec>(handlers: H) -> Bound<H> {
2669
+ LazyLock::force(&IR);
2670
+ Bound { handlers }
2671
+ }
2672
+
2673
+ impl<H: ComponentExec> Bound<H> {
2674
+ pub fn call(&mut self, name: &str, input: &[(String, Value)]) -> Result<Value, BehaviorError> {
2675
+ run_behavior(&IR, &mut self.handlers, input, Some(name))
2676
+ }
2677
+ }
2678
+ `;
2679
+ }
2680
+ var rustEmitter = {
2681
+ language: "rust",
2682
+ fileExtension: ".rs",
2683
+ defaultRuntimeImport: "behavior_contracts",
2684
+ filenameHint: "behaviors_generated.rs",
2685
+ emit: emit4
2686
+ };
2687
+
2688
+ // node_modules/behavior-contracts/dist/generator/emit-php.js
2689
+ function phpSq(s) {
2690
+ return `'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
2691
+ }
2692
+ function emit5(ctx) {
2693
+ const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
2694
+ const names = componentNames.map(phpSq).join(", ");
2695
+ const irLiteral = emitDocLiteral(ctx.ir, "php");
2696
+ return `<?php
2697
+
2698
+ // GENERATED by behavior-contracts common generator (bc#13) \u2014 DO NOT EDIT.
2699
+ // Input: portable component-graph IR only (scp-ir-architecture.md \xA75/\xA77.4).
2700
+ // This module is the codegen endpoint (\xA77.3 endpoint 3): the IR is embedded as a
2701
+ // native stdClass/array literal and handed to the EXISTING runtime core
2702
+ // (Behavior::runBehavior) \u2014 no execution logic is generated. Handlers are ALWAYS
2703
+ // injected at the boundary (IR + {effects,config,hooks} \u2014 concept.md \xA74.4); they
2704
+ // are never generated.
2705
+ // irFingerprint: ${fingerprint}
2706
+
2707
+ declare(strict_types=1);
2708
+
2709
+ // Spec versions baked at generation time (fail-closed constant comparison at require).
2710
+ $expectedSpecVersions = ['behavior' => ${specVersions.behavior}, 'expression' => ${specVersions.expression}, 'plan' => ${specVersions.plan}];
2711
+
2712
+ // FNV-1a 64 fingerprint of the source portable IR (canonical-json discipline, #208).
2713
+ $irFingerprint = ${phpSq(fingerprint)};
2714
+
2715
+ // Component names exposed by bind(), in IR declaration order.
2716
+ $componentNames = [${names}];
2717
+
2718
+ // The portable component-graph IR, embedded as a native literal (no JSON parse at require).
2719
+ $ir = ${irLiteral};
2720
+
2721
+ // Require-time fail-closed checks (#208 prepared-artifact discipline).
2722
+ $runtimeSpecVersions = [
2723
+ 'behavior' => \\${runtimeImport}\\SpecVersions::BEHAVIOR,
2724
+ 'expression' => \\${runtimeImport}\\SpecVersions::EXPRESSION,
2725
+ 'plan' => \\${runtimeImport}\\SpecVersions::PLAN,
2726
+ ];
2727
+ foreach ($expectedSpecVersions as $specKey => $specWant) {
2728
+ $specGot = $runtimeSpecVersions[$specKey] ?? null;
2729
+ if ($specGot !== $specWant) {
2730
+ throw new \\RuntimeException("behavior-contracts generated module: spec-version skew for '{$specKey}' (generated={$specWant}, runtime={$specGot}) \u2014 regenerate against this runtime (fail-closed)");
2731
+ }
2732
+ }
2733
+ $gotFingerprint = \\${runtimeImport}\\Fingerprint::componentGraph($ir);
2734
+ if ($gotFingerprint !== $irFingerprint) {
2735
+ throw new \\RuntimeException("behavior-contracts generated module: IR fingerprint mismatch (baked={$irFingerprint}, embedded literal={$gotFingerprint}) \u2014 the generated code was modified or corrupted (fail-closed)");
2736
+ }
2737
+
2738
+ // bind \u2014 inject handlers (boundary injection; catalog name \u2192 implementation) and
2739
+ // get one executor closure per component. Each call delegates to the runtime
2740
+ // core's Behavior::runBehavior over the embedded IR (dynamic-path equivalent \u2014 \xA77.3).
2741
+ return (object) [
2742
+ 'EXPECTED_SPEC_VERSIONS' => $expectedSpecVersions,
2743
+ 'IR_FINGERPRINT' => $irFingerprint,
2744
+ 'COMPONENT_NAMES' => $componentNames,
2745
+ 'IR' => $ir,
2746
+ 'bind' => static function (array $handlers) use ($ir, $componentNames): array {
2747
+ $bound = [];
2748
+ foreach ($componentNames as $name) {
2749
+ $bound[$name] = static fn (array $input = []): mixed => \\${runtimeImport}\\Behavior::runBehavior($ir, $handlers, $input, $name);
2750
+ }
2751
+ return $bound;
2752
+ },
2753
+ ];
2754
+ `;
2755
+ }
2756
+ var phpEmitter = {
2757
+ language: "php",
2758
+ fileExtension: ".php",
2759
+ defaultRuntimeImport: "BehaviorContracts",
2760
+ emit: emit5
2761
+ };
2762
+
2763
+ // node_modules/behavior-contracts/dist/generator/index.js
2764
+ registerEmitter(typescriptEmitter);
2765
+ registerEmitter(pythonEmitter);
2766
+ registerEmitter(goEmitter);
2767
+ registerEmitter(rustEmitter);
2768
+ registerEmitter(phpEmitter);
2769
+
2770
+ // node_modules/behavior-contracts/dist/index.js
2771
+ var SPEC_VERSIONS = {
2772
+ expression: 2,
2773
+ // v2: obj の __proto__ own key を FORBIDDEN_KEY に(fail-closed)
2774
+ template: 1,
2775
+ plan: 1,
2776
+ canonical: 2,
2777
+ // v2: obj 値の __proto__ own key を FORBIDDEN_KEY に(fail-closed)
2778
+ behavior: 2,
2779
+ // v2: map.when / map.into / map.batched / handler ctx(bc#22。v1 IR の意味論は不変)
2780
+ guard: 1,
2781
+ // 初版(bc#25: assertPortableComponentGraph の accept/reject を vector-pin)
2782
+ c2: 1
2783
+ // 初版(bc#28: c2-catalog-swap — catalog-swap 実行 + IR 構造一致の 5 言語 pin)
2784
+ };
2785
+
2786
+ // src/scp/catalog.ts
2787
+ var P = (type, required) => required ? { type, required } : { type };
2788
+ var SELECT_PORTS = {
2789
+ table: P("string", true),
2790
+ select: P("string[]", true),
2791
+ where: P("fragment"),
2792
+ order: P("string"),
2793
+ limit: P("expr"),
2794
+ offset: P("expr"),
2795
+ group: P("string")
2796
+ };
2797
+ var WRITE_PORTS = {
2798
+ table: P("string", true),
2799
+ where: P("fragment"),
2800
+ returning: P("string"),
2801
+ onConflict: P("string"),
2802
+ onConflictAction: P("string")
2803
+ };
2804
+ var entry = (name, inputPorts, shape, portableToIR) => ({
2805
+ name,
2806
+ inputPorts,
2807
+ output: { shape },
2808
+ portableToIR,
2809
+ // Dynamic port families (where/set/values record ports) are validated by
2810
+ // assertComponentsInCatalog, not statically enumerable. Tx overrides back to
2811
+ // fail-closed (its one port is static).
2812
+ additionalPorts: true
2813
+ });
2814
+ var LITEDBMODEL_CATALOG = {
2815
+ // Read: `items` (a Select root yields a row list; per-row collapse to `item` is the
2816
+ // consumer's cardinality concern, mirrored from graphddb Query's `cardinality` port).
2817
+ Select: entry("Select", { ...SELECT_PORTS, cardinality: P("string") }, "items", true),
2818
+ // Writes yield the RETURNING row list (`items`); a single-row write collapses at the
2819
+ // consumer boundary, same as reads.
2820
+ Insert: entry("Insert", WRITE_PORTS, "items", true),
2821
+ Update: entry("Update", WRITE_PORTS, "items", true),
2822
+ Delete: entry("Delete", WRITE_PORTS, "items", true),
2823
+ // The dynamic WHERE/SET fragment-tree component (§8). Its ports carry the fragment
2824
+ // tree; the compiler resolves SKIP/AND-OR structure to fragment existence rules.
2825
+ Fragment: entry("Fragment", { tree: P("fragment", true) }, "item", true),
2826
+ // The runtime-side atomic envelope: never referenced by the portable IR (a transaction
2827
+ // IS a component over the CRUD primitives) — runtime-only. Its single port is static,
2828
+ // so it keeps bc's fail-closed default (no additionalPorts opt-in).
2829
+ Tx: {
2830
+ ...entry("Tx", { statements: P("map[]", true) }, "item", false),
2831
+ additionalPorts: false
2832
+ }
2833
+ };
2834
+ function catalogEntry(name) {
2835
+ return LITEDBMODEL_CATALOG[name];
2836
+ }
2837
+ var CATALOG_NAMES = [
2838
+ "Select",
2839
+ "Insert",
2840
+ "Update",
2841
+ "Delete",
2842
+ "Fragment",
2843
+ "Tx"
2844
+ ];
2845
+ var WRITE_CATALOG_NAMES = [
2846
+ "Insert",
2847
+ "Update",
2848
+ "Delete",
2849
+ "Tx"
2850
+ ];
2851
+ var WRITE_SET = new Set(WRITE_CATALOG_NAMES);
2852
+ var WRITE_PORT_FAMILIES = [
2853
+ "values.",
2854
+ "set."
2855
+ ];
2856
+ function assertComponentsInCatalog(components2) {
2857
+ const errs = [];
2858
+ for (const c of components2) {
2859
+ for (const n of c.body) {
2860
+ if ("cond" in n) continue;
2861
+ const ref = "map" in n ? n.map : n;
2862
+ const entryDef = LITEDBMODEL_CATALOG[ref.component];
2863
+ if (entryDef === void 0) {
2864
+ errs.push(`${c.name}/${n.id}: references '${ref.component}', not a LITEDBMODEL_CATALOG entry (known: ${CATALOG_NAMES.join(", ")})`);
2865
+ continue;
2866
+ }
2867
+ const ports = ref.ports;
2868
+ for (const [p, s] of Object.entries(entryDef.inputPorts)) {
2869
+ if (s.required === true && !(p in ports)) {
2870
+ errs.push(`${c.name}/${n.id} (${ref.component}): required port '${p}' is not wired`);
2871
+ }
2872
+ }
2873
+ const isWriteItem = WRITE_SET.has(ref.component);
2874
+ for (const p of Object.keys(ports)) {
2875
+ if (p in entryDef.inputPorts) continue;
2876
+ if (isWriteItem && WRITE_PORT_FAMILIES.some((f) => p.startsWith(f))) continue;
2877
+ errs.push(`${c.name}/${n.id} (${ref.component}): port '${p}' is not declared by the catalog entry (nor a write record-family port)`);
2878
+ }
2879
+ }
2880
+ }
2881
+ if (errs.length > 0) {
2882
+ throw new Error(`litedbmodel catalog validation failed (${errs.length} violation${errs.length === 1 ? "" : "s"}):
2883
+ - ${errs.join("\n - ")}`);
2884
+ }
2885
+ }
2886
+ function deriveContractEffect(component) {
2887
+ return classifyBehaviorEffect(component, WRITE_CATALOG_NAMES) === "writing" ? "command" : "query";
2888
+ }
2889
+
2890
+ // src/scp/ir.ts
2891
+ var WHERE_SLOT = "{where}";
2892
+
2893
+ // src/scp/dialect.ts
2894
+ function toDollarPlaceholders(sql) {
2895
+ let n = 0;
2896
+ let out = "";
2897
+ for (const ch of sql) {
2898
+ if (ch === "?") {
2899
+ n += 1;
2900
+ out += `$${n}`;
2901
+ } else {
2902
+ out += ch;
2903
+ }
2904
+ }
2905
+ return out;
2906
+ }
2907
+ function onConflictClause(conflictColumns, action, excludedRef) {
2908
+ const target = conflictColumns.length > 0 ? ` (${conflictColumns.join(", ")})` : "";
2909
+ if (action === "ignore") {
2910
+ return ` ON CONFLICT${target} DO NOTHING`;
2911
+ }
2912
+ const sets = action.updateColumns.map((c) => `${c} = ${excludedRef(c)}`);
2913
+ return ` ON CONFLICT${target} DO UPDATE SET ${sets.join(", ")}`;
2914
+ }
2915
+ function guardInsertText(table, columns, placeholders, form) {
2916
+ const head = form === "insertIgnore" ? "INSERT IGNORE INTO" : "INSERT INTO";
2917
+ const tail = form === "trailingDoNothing" ? " ON CONFLICT DO NOTHING" : "";
2918
+ return `${head} ${table} (${columns.join(", ")}) VALUES (${placeholders})${tail}`;
2919
+ }
2920
+ var SQLITE = Object.freeze({
2921
+ name: "sqlite",
2922
+ ignoreIsTrailingClause: false,
2923
+ insertVerb(action) {
2924
+ return action === "ignore" ? "INSERT OR IGNORE INTO" : "INSERT INTO";
2925
+ },
2926
+ insertConflictClause(conflictColumns, action) {
2927
+ if (action === "ignore") return "";
2928
+ return onConflictClause(conflictColumns, action, (c) => `excluded.${c}`);
2929
+ },
2930
+ guardInsert(table, columns, placeholders) {
2931
+ return guardInsertText(table, columns, placeholders, "trailingDoNothing");
2932
+ },
2933
+ finalizePlaceholders(sql) {
2934
+ return sql;
2935
+ },
2936
+ orderByNulls(expr, dir, nulls) {
2937
+ return `${expr} ${dir} NULLS ${nulls}`;
2938
+ }
2939
+ });
2940
+ var POSTGRES = Object.freeze({
2941
+ name: "postgres",
2942
+ ignoreIsTrailingClause: true,
2943
+ insertVerb(_action) {
2944
+ return "INSERT INTO";
2945
+ },
2946
+ insertConflictClause(conflictColumns, action) {
2947
+ return onConflictClause(conflictColumns, action, (c) => `EXCLUDED.${c}`);
2948
+ },
2949
+ guardInsert(table, columns, placeholders) {
2950
+ return guardInsertText(table, columns, placeholders, "trailingDoNothing");
2951
+ },
2952
+ finalizePlaceholders(sql) {
2953
+ return toDollarPlaceholders(sql);
2954
+ },
2955
+ orderByNulls(expr, dir, nulls) {
2956
+ return `${expr} ${dir} NULLS ${nulls}`;
2957
+ }
2958
+ });
2959
+ var MYSQL = Object.freeze({
2960
+ name: "mysql",
2961
+ ignoreIsTrailingClause: false,
2962
+ insertVerb(action) {
2963
+ return action === "ignore" ? "INSERT IGNORE INTO" : "INSERT INTO";
2964
+ },
2965
+ insertConflictClause(_conflictColumns, action) {
2966
+ if (action === "ignore") return "";
2967
+ const sets = action.updateColumns.map((c) => `${c} = VALUES(${c})`);
2968
+ return ` ON DUPLICATE KEY UPDATE ${sets.join(", ")}`;
2969
+ },
2970
+ guardInsert(table, columns, placeholders) {
2971
+ return guardInsertText(table, columns, placeholders, "insertIgnore");
2972
+ },
2973
+ finalizePlaceholders(sql) {
2974
+ return sql;
2975
+ },
2976
+ orderByNulls(expr, dir, nulls) {
2977
+ const flagDir = nulls === "FIRST" ? "DESC" : "ASC";
2978
+ return `${expr} IS NULL ${flagDir}, ${expr} ${dir}`;
2979
+ }
2980
+ });
2981
+ var DIALECTS2 = Object.freeze({
2982
+ sqlite: SQLITE,
2983
+ postgres: POSTGRES,
2984
+ mysql: MYSQL
2985
+ });
2986
+ function dialectFor(name) {
2987
+ const d = DIALECTS2[name];
2988
+ if (d === void 0) {
2989
+ throw new Error(`scp dialect: unknown dialect '${String(name)}' (known: ${Object.keys(DIALECTS2).join(", ")})`);
2990
+ }
2991
+ return d;
2992
+ }
2993
+
2994
+ // src/scp/compile-dialect.ts
2995
+ var assembly = (shape) => ({ shape });
2996
+ function compileInsertFor(dialect, desc) {
2997
+ const columns = Object.keys(desc.values);
2998
+ if (columns.length === 0) throw new Error("INSERT requires at least one value column");
2999
+ const placeholders = columns.map(() => "?").join(", ");
3000
+ const params = columns.map((c) => desc.values[c]);
3001
+ const conflictAction = resolveConflictAction(desc, columns);
3002
+ const verb = dialect.insertVerb(conflictAction);
3003
+ let sql = `${verb} ${desc.table} (${columns.join(", ")}) VALUES (${placeholders})`;
3004
+ if (conflictAction !== void 0) {
3005
+ sql += dialect.insertConflictClause(desc.onConflict ?? [], conflictAction);
3006
+ }
3007
+ if (desc.returning !== void 0) sql += ` RETURNING ${desc.returning.join(", ")}`;
3008
+ return { component: "Insert", sql, where: null, params, assembly: assembly("items") };
3009
+ }
3010
+ function resolveConflictAction(desc, columns) {
3011
+ if (desc.onConflict === void 0 || desc.onConflictAction === void 0) return void 0;
3012
+ if (desc.onConflictAction === "ignore") return "ignore";
3013
+ const cols = desc.onConflictAction.updateColumns === "all" ? columns : desc.onConflictAction.updateColumns;
3014
+ return { updateColumns: cols };
3015
+ }
3016
+
3017
+ // src/scp/compile-sqlite.ts
3018
+ function lowerCondition(c) {
3019
+ if (c.kind === "group") {
3020
+ const tree = {
3021
+ connector: c.connector,
3022
+ fragments: c.conditions.map(lowerCondition)
3023
+ };
3024
+ if (c.skipWhen !== void 0) {
3025
+ throw new Error("a conditional (SKIP) group is not supported in WS1; guard the member conditions individually");
3026
+ }
3027
+ return tree;
3028
+ }
3029
+ let f;
3030
+ switch (c.kind) {
3031
+ case "eq":
3032
+ f = { always: true, sql: `${c.column} = ?`, params: [c.value] };
3033
+ break;
3034
+ case "cmp":
3035
+ f = { always: true, sql: `${c.column} ${c.op} ?`, params: [c.value] };
3036
+ break;
3037
+ case "isNull":
3038
+ f = { always: true, sql: `${c.column} IS NULL`, params: [] };
3039
+ break;
3040
+ case "in":
3041
+ f = { always: true, sql: `${c.column} IN (?)`, params: [c.value], expand: 0 };
3042
+ break;
3043
+ }
3044
+ if (c.skipWhen !== void 0) {
3045
+ delete f.always;
3046
+ f.when = c.skipWhen;
3047
+ }
3048
+ return f;
3049
+ }
3050
+ function lowerWhere(conditions) {
3051
+ if (conditions === void 0 || conditions.length === 0) return null;
3052
+ return { connector: "AND", fragments: conditions.map(lowerCondition) };
3053
+ }
3054
+ var assembly2 = (shape) => ({ shape });
3055
+ function compileSelect(desc) {
3056
+ const cols = desc.select.length === 1 && desc.select[0] === "*" ? "*" : desc.select.join(", ");
3057
+ let sql = `SELECT ${cols} FROM ${desc.table}`;
3058
+ const where = lowerWhere(desc.where);
3059
+ if (where !== null) sql += WHERE_SLOT;
3060
+ if (desc.group !== void 0) sql += ` GROUP BY ${desc.group}`;
3061
+ if (desc.order !== void 0) sql += ` ORDER BY ${desc.order}`;
3062
+ const params = [];
3063
+ if (desc.limit !== void 0) {
3064
+ sql += ` LIMIT ?`;
3065
+ params.push(desc.limit);
3066
+ }
3067
+ if (desc.offset !== void 0) {
3068
+ sql += ` OFFSET ?`;
3069
+ params.push(desc.offset);
3070
+ }
3071
+ return { component: "Select", sql, where, params, assembly: assembly2("items") };
3072
+ }
3073
+ function compileInsert(desc) {
3074
+ return compileInsertFor(SQLITE, desc);
3075
+ }
3076
+ function compileUpdate(desc) {
3077
+ const setCols = Object.keys(desc.set);
3078
+ if (setCols.length === 0) throw new Error("UPDATE requires at least one SET column");
3079
+ const setClauses = setCols.map((c) => `${c} = ?`);
3080
+ const params = setCols.map((c) => desc.set[c]);
3081
+ const where = lowerWhere(desc.where);
3082
+ if (where === null) throw new Error("UPDATE requires conditions");
3083
+ let sql = `UPDATE ${desc.table} SET ${setClauses.join(", ")}${WHERE_SLOT}`;
3084
+ if (desc.returning !== void 0) sql += ` RETURNING ${desc.returning.join(", ")}`;
3085
+ return { component: "Update", sql, where, params, assembly: assembly2("items") };
3086
+ }
3087
+ function compileDelete(desc) {
3088
+ const where = lowerWhere(desc.where);
3089
+ if (where === null) throw new Error("DELETE requires conditions");
3090
+ let sql = `DELETE FROM ${desc.table}${WHERE_SLOT}`;
3091
+ if (desc.returning !== void 0) sql += ` RETURNING ${desc.returning.join(", ")}`;
3092
+ return { component: "Delete", sql, where, params: [], assembly: assembly2("items") };
3093
+ }
3094
+
3095
+ // src/scp/render.ts
3096
+ function isTree(node) {
3097
+ return "connector" in node;
3098
+ }
3099
+ function fragmentPresent(f, scope) {
3100
+ if (f.always === true) return true;
3101
+ if (f.when === void 0) return false;
3102
+ const v = evaluate(f.when, scope);
3103
+ return v !== null && v !== false;
3104
+ }
3105
+ function renderFragment(f, scope, params) {
3106
+ if (f.expand === void 0) {
3107
+ for (const slot of f.params) params.push(evaluate(slot, scope));
3108
+ return f.sql;
3109
+ }
3110
+ let sql = f.sql;
3111
+ for (let i = 0; i < f.params.length; i++) {
3112
+ const v = evaluate(f.params[i], scope);
3113
+ if (i === f.expand) {
3114
+ if (!Array.isArray(v)) {
3115
+ throw new Error(`IN-list expansion slot ${i} did not bind to an array (got ${v === null ? "null" : typeof v})`);
3116
+ }
3117
+ if (v.length === 0) {
3118
+ sql = "1 = 0";
3119
+ } else {
3120
+ sql = sql.replace("(?)", `(${v.map(() => "?").join(", ")})`);
3121
+ for (const el of v) params.push(el);
3122
+ }
3123
+ } else {
3124
+ params.push(v);
3125
+ }
3126
+ }
3127
+ return sql;
3128
+ }
3129
+ function renderTree(tree, scope, params) {
3130
+ const parts = [];
3131
+ for (const node of tree.fragments) {
3132
+ if (isTree(node)) {
3133
+ const inner = renderTree(node, scope, params);
3134
+ if (inner !== "") parts.push(`(${inner})`);
3135
+ } else if (fragmentPresent(node, scope)) {
3136
+ parts.push(renderFragment(node, scope, params));
3137
+ }
3138
+ }
3139
+ if (parts.length === 0) return "";
3140
+ return parts.join(` ${tree.connector} `);
3141
+ }
3142
+ function renderOperation(op, input, dialect = SQLITE) {
3143
+ const params = [];
3144
+ const markerIdx = op.sql.indexOf(WHERE_SLOT);
3145
+ if (markerIdx === -1) {
3146
+ for (const slot of op.params) params.push(evaluate(slot, input));
3147
+ return { sql: finalize(op.sql, dialect), params };
3148
+ }
3149
+ const before = op.sql.slice(0, markerIdx);
3150
+ const after = op.sql.slice(markerIdx + WHERE_SLOT.length);
3151
+ const beforeQ = countPlaceholders(before);
3152
+ const preStatics = op.params.slice(0, beforeQ);
3153
+ const postStatics = op.params.slice(beforeQ);
3154
+ for (const slot of preStatics) params.push(evaluate(slot, input));
3155
+ let whereSql = "";
3156
+ if (op.where !== null) {
3157
+ const body = renderTree(op.where, input, params);
3158
+ if (body !== "") whereSql = ` WHERE ${body}`;
3159
+ }
3160
+ for (const slot of postStatics) params.push(evaluate(slot, input));
3161
+ return { sql: finalize(before + whereSql + after, dialect), params };
3162
+ }
3163
+ function finalize(sql, dialect) {
3164
+ return dialect.finalizePlaceholders(sql);
3165
+ }
3166
+ function countPlaceholders(sql) {
3167
+ let n = 0;
3168
+ for (const ch of sql) if (ch === "?") n++;
3169
+ return n;
3170
+ }
3171
+
3172
+ // src/scp/guard.ts
3173
+ function assertExprPortable(node, path = "$") {
3174
+ assertPortable(node, path);
3175
+ walkExpr(node, path);
3176
+ }
3177
+ function walkExpr(node, path) {
3178
+ if (node === null || typeof node !== "object") return;
3179
+ if (Array.isArray(node)) {
3180
+ node.forEach((el, i) => walkExpr(el, `${path}[${i}]`));
3181
+ return;
3182
+ }
3183
+ const keys = Object.keys(node);
3184
+ if (keys.length === 1) {
3185
+ const op = keys[0];
3186
+ if (!PORTABLE_EXPR_OPERATORS.has(op)) {
3187
+ throw new PortabilityError(path, `Portability Guard: '${op}' is not a portable Expression IR operator (closed set: ${[...PORTABLE_EXPR_OPERATORS].join(", ")})`);
3188
+ }
3189
+ const arg = node[op];
3190
+ if (op === "obj") {
3191
+ if (arg === null || typeof arg !== "object" || Array.isArray(arg)) {
3192
+ throw new PortabilityError(`${path}.obj`, `Portability Guard: {obj: ...} expects an object (at ${path}.obj)`);
3193
+ }
3194
+ for (const [k, v] of Object.entries(arg)) {
3195
+ if (k === FORBIDDEN_OBJECT_KEY) {
3196
+ throw new PortabilityError(`${path}.obj`, `Portability Guard: object key "${FORBIDDEN_OBJECT_KEY}" is forbidden (fail-closed) at ${path}.obj`);
3197
+ }
3198
+ walkExpr(v, `${path}.obj.${k}`);
3199
+ }
3200
+ return;
3201
+ }
3202
+ walkExpr(arg, `${path}.${op}`);
3203
+ return;
3204
+ }
3205
+ for (const k of keys) walkExpr(node[k], `${path}.${k}`);
3206
+ }
3207
+ function assertFragmentPortable(node, path) {
3208
+ if ("connector" in node) {
3209
+ node.fragments.forEach((f, i) => assertFragmentPortable(f, `${path}.fragments[${i}]`));
3210
+ return;
3211
+ }
3212
+ if (node.when !== void 0) assertExprPortable(node.when, `${path}.when`);
3213
+ node.params.forEach((p, i) => assertExprPortable(p, `${path}.params[${i}]`));
3214
+ }
3215
+ function assertOperationPortable(op) {
3216
+ op.params.forEach((p, i) => assertExprPortable(p, `$.params[${i}]`));
3217
+ if (op.where !== null) assertFragmentPortable(op.where, "$.where");
3218
+ }
3219
+ function assertComponentPortable(component) {
3220
+ const at = `component '${component.name}'`;
3221
+ for (const n of component.body) {
3222
+ if ("map" in n) {
3223
+ assertExprPortable(n.map.over, `${at}/${n.id}.map.over`);
3224
+ assertExprPortable(n.map.ports, `${at}/${n.id}.map.ports`);
3225
+ if (n.map.when !== void 0) assertExprPortable(n.map.when, `${at}/${n.id}.map.when`);
3226
+ } else if ("cond" in n) {
3227
+ assertExprPortable(n.cond.if, `${at}/${n.id}.cond.if`);
3228
+ assertExprPortable(n.cond.then, `${at}/${n.id}.cond.then`);
3229
+ assertExprPortable(n.cond.else, `${at}/${n.id}.cond.else`);
3230
+ } else {
3231
+ assertExprPortable(n.ports, `${at}/${n.id}.ports`);
3232
+ }
3233
+ }
3234
+ assertExprPortable(component.output, `${at}.output`);
3235
+ }
3236
+ function assertComponentGraphPortable(ir) {
3237
+ for (const c of ir.components) assertComponentPortable(c);
3238
+ }
3239
+
3240
+ // src/scp/authoring.ts
3241
+ var boundComponents;
3242
+ function components() {
3243
+ if (boundComponents === void 0) {
3244
+ boundComponents = catalogComponents(LITEDBMODEL_CATALOG);
3245
+ }
3246
+ return boundComponents;
3247
+ }
3248
+ function lowerBehaviorClass(cls, options) {
3249
+ const ir = compileBehaviors(cls, {
3250
+ ...options.inputPorts !== void 0 ? { inputPorts: options.inputPorts } : {},
3251
+ ...options.concurrency !== void 0 ? { concurrency: options.concurrency } : {}
3252
+ });
3253
+ assertComponentsInCatalog(ir.components);
3254
+ assertComponentGraphPortable(ir);
3255
+ const methods = {};
3256
+ for (const component of ir.components) {
3257
+ methods[component.name] = {
3258
+ name: component.name,
3259
+ effect: deriveContractEffect(component),
3260
+ component
3261
+ };
3262
+ }
3263
+ return {
3264
+ className: cls.name ?? "<anonymous>",
3265
+ ir,
3266
+ components: ir.components,
3267
+ methods
3268
+ };
3269
+ }
3270
+ function publishBehaviors(cls, options = {}) {
3271
+ return lowerBehaviorClass(cls, options);
3272
+ }
3273
+ function compileEager(name, fn, options = {}) {
3274
+ const cls = makeEagerClass(name, fn);
3275
+ return lowerBehaviorClass(cls, options);
3276
+ }
3277
+ function makeEagerClass(name, fn) {
3278
+ const L = components();
3279
+ const cls = class extends SemanticBehavior {
3280
+ };
3281
+ const method = function($) {
3282
+ return fn($, L);
3283
+ };
3284
+ Object.defineProperty(method, "toString", { value: () => fn.toString(), configurable: true });
3285
+ Object.defineProperty(cls.prototype, name, {
3286
+ value: method,
3287
+ writable: true,
3288
+ enumerable: false,
3289
+ configurable: true
3290
+ });
3291
+ Object.defineProperty(cls, "name", { value: name, configurable: true });
3292
+ return cls;
3293
+ }
3294
+
3295
+ // src/scp/bridge.ts
3296
+ var IN_SENTINEL = "@in";
3297
+ function isMap(n) {
3298
+ return "map" in n;
3299
+ }
3300
+ function nodeRef(n) {
3301
+ return isMap(n) ? { component: n.map.component, ports: n.map.ports } : { component: n.component, ports: n.ports };
3302
+ }
3303
+ function stringPort(ports, name) {
3304
+ const v = ports[name];
3305
+ if (v === void 0) return void 0;
3306
+ if (typeof v !== "string") {
3307
+ throw new Error(`bridge: port '${name}' must be a literal string in the IR (got ${JSON.stringify(v)})`);
3308
+ }
3309
+ return v;
3310
+ }
3311
+ function arrPort(ports, name) {
3312
+ const v = ports[name];
3313
+ if (v === void 0) return void 0;
3314
+ if (typeof v === "object" && v !== null && "arr" in v && Array.isArray(v.arr)) {
3315
+ return v.arr;
3316
+ }
3317
+ throw new Error(`bridge: port '${name}' must be an {arr:[...]} literal in the IR (got ${JSON.stringify(v)})`);
3318
+ }
3319
+ function stringArrayPort(ports, name) {
3320
+ const arr = arrPort(ports, name);
3321
+ if (arr === void 0) return void 0;
3322
+ return arr.map((e) => {
3323
+ if (typeof e !== "string") throw new Error(`bridge: '${name}' entries must be literal strings (got ${JSON.stringify(e)})`);
3324
+ return e;
3325
+ });
3326
+ }
3327
+ function opKey(node) {
3328
+ if (node === null || typeof node !== "object" || Array.isArray(node)) return void 0;
3329
+ const keys = Object.keys(node);
3330
+ return keys.length === 1 ? keys[0] : void 0;
3331
+ }
3332
+ function columnOf(node, ctx) {
3333
+ const op = opKey(node);
3334
+ if (op !== "ref" && op !== "refOpt") {
3335
+ throw new Error(`bridge: ${ctx}: the column operand must be a {ref:[...]} / {refOpt:[...]} path, got ${JSON.stringify(node)}`);
3336
+ }
3337
+ const path = node[op];
3338
+ if (!Array.isArray(path) || path.length === 0 || typeof path[path.length - 1] !== "string") {
3339
+ throw new Error(`bridge: ${ctx}: column ref path must be a non-empty string path`);
3340
+ }
3341
+ return path[path.length - 1];
3342
+ }
3343
+ var CMP_OPS = {
3344
+ lt: "<",
3345
+ le: "<=",
3346
+ gt: ">",
3347
+ ge: ">=",
3348
+ ne: "<>"
3349
+ };
3350
+ function inSentinelColumn(node) {
3351
+ const op = opKey(node);
3352
+ if (op !== "ref" && op !== "refOpt") return void 0;
3353
+ const path = node[op];
3354
+ if (Array.isArray(path) && path.length >= 2 && path[0] === IN_SENTINEL && typeof path[path.length - 1] === "string") {
3355
+ return path[path.length - 1];
3356
+ }
3357
+ return void 0;
3358
+ }
3359
+ function lowerWhereMember(node, at) {
3360
+ const op = opKey(node);
3361
+ if (op === void 0) {
3362
+ throw new Error(`bridge: ${at}: a where member must be a single-operator Expression node, got ${JSON.stringify(node)}`);
3363
+ }
3364
+ if (op === "cond") {
3365
+ const args = node.cond;
3366
+ if (!Array.isArray(args) || args.length !== 3 || args[2] !== null) {
3367
+ throw new Error(`bridge: ${at}: a SKIP-optional condition must be {cond:[c, <member>, null]} (else = null)`);
3368
+ }
3369
+ const inner = lowerWhereMember(args[1], `${at}.cond.then`);
3370
+ if (inner.skipWhen !== void 0) {
3371
+ throw new Error(`bridge: ${at}: nested SKIP guards are not supported (one cond per member)`);
3372
+ }
3373
+ return { ...inner, skipWhen: args[0] };
3374
+ }
3375
+ if (op === "and" || op === "or") {
3376
+ const args = node[op];
3377
+ if (!Array.isArray(args) || args.length < 2) {
3378
+ throw new Error(`bridge: ${at}: '${op}' group expects >= 2 members`);
3379
+ }
3380
+ return {
3381
+ kind: "group",
3382
+ connector: op === "and" ? "AND" : "OR",
3383
+ conditions: args.map((m, i) => lowerWhereMember(m, `${at}.${op}[${i}]`))
3384
+ };
3385
+ }
3386
+ if (op === "eq") {
3387
+ const [col, val] = binOperands(node, op, at);
3388
+ const inCol = inSentinelColumn(col);
3389
+ if (inCol !== void 0) {
3390
+ return { kind: "in", column: inCol, value: val };
3391
+ }
3392
+ if (val === null) {
3393
+ return { kind: "isNull", column: columnOf(col, at) };
3394
+ }
3395
+ return { kind: "eq", column: columnOf(col, at), value: val };
3396
+ }
3397
+ if (op in CMP_OPS) {
3398
+ const [col, val] = binOperands(node, op, at);
3399
+ return { kind: "cmp", column: columnOf(col, at), op: CMP_OPS[op], value: val };
3400
+ }
3401
+ throw new Error(`bridge: ${at}: unsupported where operator '${op}' (supported: eq/ne/lt/le/gt/ge/and/or/cond; IN via ${IN_SENTINEL} column head; IS NULL via eq(col,null))`);
3402
+ }
3403
+ function binOperands(node, op, at) {
3404
+ const args = node[op];
3405
+ if (!Array.isArray(args) || args.length !== 2) {
3406
+ throw new Error(`bridge: ${at}: '${op}' expects exactly 2 operands`);
3407
+ }
3408
+ return [args[0], args[1]];
3409
+ }
3410
+ function lowerWherePort(ports, at) {
3411
+ const arr = arrPort(ports, "where");
3412
+ if (arr === void 0) return void 0;
3413
+ return arr.map((m, i) => lowerWhereMember(m, `${at}.where[${i}]`));
3414
+ }
3415
+ function collectFamily(ports, prefix) {
3416
+ const out = {};
3417
+ for (const k of Object.keys(ports)) {
3418
+ if (k.startsWith(`${prefix}.`)) out[k.slice(prefix.length + 1)] = ports[k];
3419
+ }
3420
+ return out;
3421
+ }
3422
+ function conflictOf(ports) {
3423
+ const onConflict = stringPort(ports, "onConflict");
3424
+ const action = stringPort(ports, "onConflictAction");
3425
+ if (onConflict === void 0) return {};
3426
+ const keys = onConflict.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
3427
+ if (action === void 0 || action === "ignore") {
3428
+ return { onConflict: keys, onConflictAction: "ignore" };
3429
+ }
3430
+ if (action === "update") {
3431
+ return { onConflict: keys, onConflictAction: { updateColumns: "all" } };
3432
+ }
3433
+ const m = /^update:(.+)$/.exec(action);
3434
+ if (m) {
3435
+ return { onConflict: keys, onConflictAction: { updateColumns: m[1].split(",").map((s) => s.trim()) } };
3436
+ }
3437
+ throw new Error(`bridge: unsupported onConflictAction '${action}' (expected 'ignore' / 'update' / 'update:col,col')`);
3438
+ }
3439
+ function returningOf(ports) {
3440
+ const r = stringPort(ports, "returning");
3441
+ if (r === void 0) return void 0;
3442
+ return r.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
3443
+ }
3444
+ function compileNode(node, dialect = SQLITE) {
3445
+ const { component, ports } = nodeRef(node);
3446
+ const table = stringPort(ports, "table");
3447
+ if (table === void 0) throw new Error(`bridge: ${component} node requires a literal 'table' port`);
3448
+ const at = `${component}`;
3449
+ switch (component) {
3450
+ case "Select": {
3451
+ const select = stringArrayPort(ports, "select");
3452
+ if (select === void 0) throw new Error(`bridge: Select requires a 'select' {arr:[...]} port`);
3453
+ const desc = { table, select };
3454
+ const where = lowerWherePort(ports, at);
3455
+ if (where !== void 0) desc.where = where;
3456
+ const order = stringPort(ports, "order");
3457
+ if (order !== void 0) desc.order = order;
3458
+ const group = stringPort(ports, "group");
3459
+ if (group !== void 0) desc.group = group;
3460
+ if (ports.limit !== void 0) desc.limit = ports.limit;
3461
+ if (ports.offset !== void 0) desc.offset = ports.offset;
3462
+ return compileSelect(desc);
3463
+ }
3464
+ case "Insert": {
3465
+ const values = collectFamily(ports, "values");
3466
+ if (Object.keys(values).length === 0) throw new Error(`bridge: Insert requires at least one 'values.<field>' port`);
3467
+ const desc = { table, values, ...conflictOf(ports) };
3468
+ const returning = returningOf(ports);
3469
+ if (returning !== void 0) desc.returning = returning;
3470
+ return compileInsertFor(dialect, desc);
3471
+ }
3472
+ case "Update": {
3473
+ const set = collectFamily(ports, "set");
3474
+ if (Object.keys(set).length === 0) throw new Error(`bridge: Update requires at least one 'set.<field>' port`);
3475
+ const where = lowerWherePort(ports, at);
3476
+ if (where === void 0) throw new Error(`bridge: Update requires a 'where' port`);
3477
+ const desc = { table, set, where };
3478
+ const returning = returningOf(ports);
3479
+ if (returning !== void 0) desc.returning = returning;
3480
+ return compileUpdate(desc);
3481
+ }
3482
+ case "Delete": {
3483
+ const where = lowerWherePort(ports, at);
3484
+ if (where === void 0) throw new Error(`bridge: Delete requires a 'where' port`);
3485
+ const desc = { table, where };
3486
+ const returning = returningOf(ports);
3487
+ if (returning !== void 0) desc.returning = returning;
3488
+ return compileDelete(desc);
3489
+ }
3490
+ default:
3491
+ throw new Error(`bridge: catalog component '${component}' has no Backend-Compile (SQL CRUD only: Select/Insert/Update/Delete)`);
3492
+ }
3493
+ }
3494
+ function compileComponentNodes(component, dialect = SQLITE) {
3495
+ const out = /* @__PURE__ */ new Map();
3496
+ for (const n of component.body) {
3497
+ if ("cond" in n) continue;
3498
+ out.set(n.id, compileNode(n, dialect));
3499
+ }
3500
+ return out;
3501
+ }
3502
+
3503
+ // src/scp/authoring-sql.ts
3504
+ function whereEq(col, value) {
3505
+ return eq(col, value);
3506
+ }
3507
+ function whereNe(col, value) {
3508
+ return ne(col, value);
3509
+ }
3510
+ function whereLt(col, value) {
3511
+ return lt(col, value);
3512
+ }
3513
+ function whereLe(col, value) {
3514
+ return le(col, value);
3515
+ }
3516
+ function whereGt(col, value) {
3517
+ return gt(col, value);
3518
+ }
3519
+ function whereGe(col, value) {
3520
+ return ge(col, value);
3521
+ }
3522
+ function whereIsNull(col) {
3523
+ return eq(col, null);
3524
+ }
3525
+ function whereIn(col, value) {
3526
+ return eq(col, value);
3527
+ }
3528
+ function inColumn($, name) {
3529
+ return $[IN_SENTINEL][name];
3530
+ }
3531
+
3532
+ // src/scp/errors.ts
3533
+ var SqlFailure = class extends Error {
3534
+ constructor(kind, policy, sqliteCode, message) {
3535
+ super(message);
3536
+ this.kind = kind;
3537
+ this.policy = policy;
3538
+ this.sqliteCode = sqliteCode;
3539
+ this.name = "SqlFailure";
3540
+ }
3541
+ kind;
3542
+ policy;
3543
+ sqliteCode;
3544
+ };
3545
+ function isSqliteError(e) {
3546
+ return typeof e === "object" && e !== null && typeof e.code === "string" && e.code.startsWith("SQLITE_");
3547
+ }
3548
+ function mapSqliteError(e) {
3549
+ if (!isSqliteError(e)) {
3550
+ const message2 = e instanceof Error ? e.message : String(e);
3551
+ return new SqlFailure("driver_error", "fail", void 0, `non-SQLite driver error: ${message2}`);
3552
+ }
3553
+ const { code, message } = e;
3554
+ const tagged = `[${code}] ${message}`;
3555
+ if (code === "SQLITE_CONSTRAINT_FOREIGNKEY") {
3556
+ return new SqlFailure("foreign_key_violation", "fail", code, tagged);
3557
+ }
3558
+ if (code.startsWith("SQLITE_CONSTRAINT")) {
3559
+ return new SqlFailure("constraint_violation", "fail", code, tagged);
3560
+ }
3561
+ if (code === "SQLITE_BUSY" || code === "SQLITE_LOCKED") {
3562
+ return new SqlFailure("retryable", "retry", code, tagged);
3563
+ }
3564
+ return new SqlFailure("driver_error", "fail", code, tagged);
3565
+ }
3566
+
3567
+ // src/scp/relation.ts
3568
+ var RELATION_KEYS_HEAD = "__keys";
3569
+ function compileRelationOp(decl) {
3570
+ if (decl.kind !== "hasMany" && decl.limit !== void 0) {
3571
+ throw new Error(`relation '${decl.name}': a per-parent 'limit' is only valid for hasMany (got ${decl.kind})`);
3572
+ }
3573
+ const query = decl.limit !== void 0 ? compileLimitedBatch(decl) : compilePlainBatch(decl);
3574
+ return {
3575
+ name: decl.name,
3576
+ kind: decl.kind,
3577
+ parentKey: decl.parentKey,
3578
+ targetKey: decl.targetKey,
3579
+ query
3580
+ };
3581
+ }
3582
+ function keysRef() {
3583
+ return { ref: [RELATION_KEYS_HEAD] };
3584
+ }
3585
+ function compilePlainBatch(decl) {
3586
+ const cols = decl.select.join(", ");
3587
+ const inFragment = {
3588
+ always: true,
3589
+ sql: `${decl.targetKey} IN (?)`,
3590
+ params: [keysRef()],
3591
+ expand: 0
3592
+ };
3593
+ const where = { connector: "AND", fragments: [inFragment] };
3594
+ let sql = `SELECT ${cols} FROM ${decl.targetTable}${WHERE_SLOT}`;
3595
+ if (decl.order !== void 0) sql += ` ORDER BY ${decl.order}`;
3596
+ return { component: "Select", sql, where, params: [], assembly: { shape: "items" } };
3597
+ }
3598
+ function compileLimitedBatch(decl) {
3599
+ const cols = decl.select.join(", ");
3600
+ const limit = decl.limit;
3601
+ if (!Number.isInteger(limit) || limit < 0) {
3602
+ throw new Error(`relation '${decl.name}': per-parent limit must be a non-negative integer (got ${String(limit)})`);
3603
+ }
3604
+ if (decl.order === void 0) {
3605
+ throw new Error(
3606
+ `relation '${decl.name}': a per-parent 'limit' requires an explicit 'order' (the ROW_NUMBER() window needs a deterministic ordering to decide which ${limit} rows each parent keeps)`
3607
+ );
3608
+ }
3609
+ const order = decl.order;
3610
+ const inFragment = {
3611
+ always: true,
3612
+ sql: `${decl.targetKey} IN (?)`,
3613
+ params: [keysRef()],
3614
+ expand: 0
3615
+ };
3616
+ const where = { connector: "AND", fragments: [inFragment] };
3617
+ const sql = `WITH ranked AS (SELECT ${cols}, ROW_NUMBER() OVER (PARTITION BY ${decl.targetKey} ORDER BY ${order}) AS _rn FROM ${decl.targetTable}${WHERE_SLOT}) SELECT ${cols} FROM ranked WHERE _rn <= ${limit}`;
3618
+ return { component: "Select", sql, where, params: [], assembly: { shape: "items" } };
3619
+ }
3620
+ function runRelationOp(op, parents, db) {
3621
+ const keys = dedupeKeys(parents, op.parentKey);
3622
+ const batch = /* @__PURE__ */ new Map();
3623
+ if (keys.length === 0) {
3624
+ const rendered2 = renderOperation(op.query, { [RELATION_KEYS_HEAD]: [] });
3625
+ return { sql: rendered2.sql, keys, batch };
3626
+ }
3627
+ const rendered = renderOperation(op.query, { [RELATION_KEYS_HEAD]: keys });
3628
+ const rows = db.prepare(rendered.sql).all(...rendered.params);
3629
+ for (const row of rows) {
3630
+ const k = String(row[op.targetKey]);
3631
+ const list = batch.get(k);
3632
+ if (list === void 0) batch.set(k, [row]);
3633
+ else list.push(row);
3634
+ }
3635
+ return { sql: rendered.sql, keys, batch };
3636
+ }
3637
+ function dedupeKeys(parents, parentKey) {
3638
+ const seen = /* @__PURE__ */ new Set();
3639
+ const out = [];
3640
+ for (const p of parents) {
3641
+ const v = p[parentKey];
3642
+ if (v === void 0 || v === null) continue;
3643
+ const s = String(v);
3644
+ if (seen.has(s)) continue;
3645
+ seen.add(s);
3646
+ out.push(v);
3647
+ }
3648
+ return out;
3649
+ }
3650
+ function distributeToParent(op, parent, batch) {
3651
+ const key = parent[op.parentKey];
3652
+ const rows = key === void 0 || key === null ? void 0 : batch.get(String(key));
3653
+ if (op.kind === "hasMany") return rows ?? [];
3654
+ return rows !== void 0 && rows.length > 0 ? rows[0] : null;
3655
+ }
3656
+
3657
+ // src/scp/typed-object.ts
3658
+ var RELATION_CONTEXT = /* @__PURE__ */ Symbol("litedbmodel:relation-context");
3659
+ var RelationContext = class {
3660
+ siblings;
3661
+ ops;
3662
+ db;
3663
+ hydrate;
3664
+ /** Per-relation resolved batch (name → grouping), memoized: one batch query per relation. */
3665
+ resolved = /* @__PURE__ */ new Map();
3666
+ constructor(siblings, ops, db, hydrate) {
3667
+ this.siblings = siblings;
3668
+ this.ops = ops;
3669
+ this.db = db;
3670
+ this.hydrate = hydrate;
3671
+ }
3672
+ /**
3673
+ * Resolve `relationName` for `parent` (lazy access). The relation is batch-loaded across
3674
+ * ALL siblings on first access and memoized, so N sibling accesses issue ONE query. Returns
3675
+ * the hydrated child(ren) per cardinality (`hasMany` → array, else single-or-null).
3676
+ */
3677
+ resolve(relationName, parent) {
3678
+ const op = this.ops[relationName];
3679
+ if (op === void 0) {
3680
+ throw new Error(`relation '${relationName}' is not declared on this result set`);
3681
+ }
3682
+ let batch = this.resolved.get(relationName);
3683
+ if (batch === void 0) {
3684
+ batch = runRelationOp(op, this.siblings, this.db).batch;
3685
+ this.resolved.set(relationName, batch);
3686
+ }
3687
+ return applyHydrate(distributeToParent(op, parent, batch), this.hydrate);
3688
+ }
3689
+ };
3690
+ function readRelationContext(o) {
3691
+ const v = o[RELATION_CONTEXT];
3692
+ return v instanceof RelationContext ? v : void 0;
3693
+ }
3694
+ function applyHydrate(value, hydrate) {
3695
+ if (hydrate === void 0) return value;
3696
+ if (value === null) return null;
3697
+ if (Array.isArray(value)) return value.map((v) => v === null ? null : hydrate(v));
3698
+ return hydrate(value);
3699
+ }
3700
+ function buildResultSet(rawRows, ops, db, options = {}) {
3701
+ const selected = options.with ?? {};
3702
+ const hydrate = options.hydrate;
3703
+ const proto = {};
3704
+ for (const name of Object.keys(ops)) {
3705
+ if (selected[name] === true) continue;
3706
+ Object.defineProperty(proto, name, {
3707
+ enumerable: false,
3708
+ configurable: true,
3709
+ get() {
3710
+ const ctx2 = readRelationContext(this);
3711
+ if (ctx2 === void 0) {
3712
+ return Promise.reject(
3713
+ new Error(
3714
+ `lazy relation '${name}': the batch context was dropped (spread/clone/JSON); re-read through the query API or declaratively select it via { with: { ${name}: true } }`
3715
+ )
3716
+ );
3717
+ }
3718
+ return Promise.resolve(ctx2.resolve(name, this));
3719
+ }
3720
+ });
3721
+ }
3722
+ const rows = rawRows.map((raw) => {
3723
+ const o = Object.create(proto);
3724
+ for (const k of Object.keys(raw)) o[k] = raw[k];
3725
+ return o;
3726
+ });
3727
+ const ctx = new RelationContext(rows, ops, db, hydrate);
3728
+ for (const o of rows) {
3729
+ Object.defineProperty(o, RELATION_CONTEXT, {
3730
+ value: ctx,
3731
+ enumerable: false,
3732
+ writable: false,
3733
+ configurable: false
3734
+ });
3735
+ }
3736
+ for (const name of Object.keys(selected)) {
3737
+ const op = ops[name];
3738
+ if (op === void 0) throw new Error(`declarative select: relation '${name}' is not declared on this model`);
3739
+ const { batch } = runRelationOp(op, rows, db);
3740
+ for (const o of rows) {
3741
+ o[name] = applyHydrate(distributeToParent(op, o, batch), hydrate);
3742
+ }
3743
+ }
3744
+ if (hydrate === void 0) return rows;
3745
+ return rows.map((o) => hydrate(o));
3746
+ }
3747
+
3748
+ // src/scp/writes.ts
3749
+ var ENTITY_ROOT = "__entity";
3750
+ var PATH_RE = /^\$\.(input|entity)\.([A-Za-z_][A-Za-z0-9_]*)$/;
3751
+ var REF_PATH_RE = /^\$\.ref\.([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)$/;
3752
+ function parseEffectPath(value) {
3753
+ const m = PATH_RE.exec(value);
3754
+ if (m !== null) return { root: m[1], field: m[2] };
3755
+ const r = REF_PATH_RE.exec(value);
3756
+ if (r !== null) return { root: "ref", writeName: r[1], field: r[2] };
3757
+ throw new Error(
3758
+ `write-time relations: '${value}' is not a valid path-rooted value; use '$.input.<field>' (the Command input), '$.entity.<field>' (the sole written row), or '$.ref.<writeName>.<field>' (a named upstream write's RETURNING row).`
3759
+ );
3760
+ }
3761
+ function assertPaths(map) {
3762
+ for (const v of Object.values(map)) parseEffectPath(v);
3763
+ }
3764
+ var recorder = {
3765
+ lifecycle(effects = {}) {
3766
+ for (const r of effects.requires ?? []) assertPaths(r.keys);
3767
+ if (effects.idempotency !== void 0) parseEffectPath(effects.idempotency.token);
3768
+ for (const u of effects.unique ?? []) {
3769
+ u.scope.forEach((p) => parseEffectPath(p));
3770
+ u.fields.forEach((p) => parseEffectPath(p));
3771
+ }
3772
+ for (const d of effects.derive ?? []) assertPaths(d.keys);
3773
+ for (const e of effects.edges ?? []) {
3774
+ assertPaths(e.columns);
3775
+ if (e.where !== void 0) assertPaths(e.where);
3776
+ }
3777
+ for (const em of effects.emits ?? []) assertPaths(em.payload);
3778
+ return { effects: freezeEffects(effects) };
3779
+ },
3780
+ exists(table, keys) {
3781
+ return { kind: "requires", table, keys };
3782
+ },
3783
+ unique(spec) {
3784
+ return { kind: "unique", name: spec.name, guardTable: spec.guardTable, scope: spec.scope, fields: spec.fields };
3785
+ },
3786
+ increment(table, keys, attribute, amount) {
3787
+ if (!Number.isFinite(amount)) {
3788
+ throw new Error(`entityWrites: increment amount for '${table}.${attribute}' must be a finite number (got ${String(amount)})`);
3789
+ }
3790
+ return { kind: "derive", table, keys, attribute, amount };
3791
+ },
3792
+ edge(spec) {
3793
+ if (spec.relation === "fk" && spec.where === void 0) {
3794
+ throw new Error(`entityWrites: a 'fk' edge on '${spec.table}' requires a 'where' key map (the matched row's identity)`);
3795
+ }
3796
+ return {
3797
+ kind: "edge",
3798
+ relation: spec.relation,
3799
+ action: spec.action,
3800
+ table: spec.table,
3801
+ columns: spec.columns,
3802
+ ...spec.where !== void 0 ? { where: spec.where } : {}
3803
+ };
3804
+ },
3805
+ event(name, outboxTable, payload) {
3806
+ return { kind: "emit", name, outboxTable, payload };
3807
+ },
3808
+ idempotentBy(table, column, token) {
3809
+ return { kind: "idempotency", table, column, token };
3810
+ }
3811
+ };
3812
+ function freezeEffects(effects) {
3813
+ const out = {};
3814
+ if (effects.requires !== void 0) out.requires = effects.requires;
3815
+ if (effects.idempotency !== void 0) out.idempotency = effects.idempotency;
3816
+ if (effects.unique !== void 0) out.unique = effects.unique;
3817
+ if (effects.derive !== void 0) out.derive = effects.derive;
3818
+ if (effects.edges !== void 0) out.edges = effects.edges;
3819
+ if (effects.emits !== void 0) out.emits = effects.emits;
3820
+ return out;
3821
+ }
3822
+ function entityWrites(builder) {
3823
+ const shape = builder(recorder);
3824
+ if (shape.create === void 0 && shape.update === void 0 && shape.remove === void 0) {
3825
+ throw new Error(
3826
+ "entityWrites(...) must declare at least one lifecycle (`create` / `update` / `remove`)."
3827
+ );
3828
+ }
3829
+ return {
3830
+ ...shape.create !== void 0 ? { create: shape.create } : {},
3831
+ ...shape.update !== void 0 ? { update: shape.update } : {},
3832
+ ...shape.remove !== void 0 ? { remove: shape.remove } : {}
3833
+ };
3834
+ }
3835
+ function edgeWrites(builder) {
3836
+ const def = entityWrites(builder);
3837
+ for (const phase of ["create", "update", "remove"]) {
3838
+ const c = def[phase];
3839
+ if (c === void 0) continue;
3840
+ const e = c.effects;
3841
+ if (e.requires !== void 0 || e.unique !== void 0 || e.derive !== void 0 || e.emits !== void 0 || e.idempotency !== void 0) {
3842
+ throw new Error(
3843
+ `edgeWrites: the '${phase}' lifecycle may declare ONLY 'edges' effects (an edge entity carries only edge writes; use entityWrites for a full save contract).`
3844
+ );
3845
+ }
3846
+ }
3847
+ return def;
3848
+ }
3849
+ function lifecycleFor(def, phase) {
3850
+ return def[phase];
3851
+ }
3852
+
3853
+ // src/scp/write-plan.ts
3854
+ function pathToRef(value) {
3855
+ const p = parseEffectPath(value);
3856
+ if (p.root === "input") return { ref: [p.field] };
3857
+ if (p.root === "entity") return { ref: [ENTITY_ROOT, p.field] };
3858
+ return { ref: [p.writeName, p.field] };
3859
+ }
3860
+ function makeIdGen() {
3861
+ let n = 0;
3862
+ return (role) => `tx_${role}_${n++}`;
3863
+ }
3864
+ function compileRequires(e, nextId2) {
3865
+ const cols = Object.keys(e.keys);
3866
+ if (cols.length === 0) throw new Error(`write-plan: requires on '${e.table}' declares no keys`);
3867
+ const whereSql = cols.map((c) => `${c} = ?`).join(" AND ");
3868
+ const params = cols.map((c) => pathToRef(e.keys[c]));
3869
+ const op = {
3870
+ component: "Select",
3871
+ sql: `SELECT 1 FROM ${e.table} WHERE ${whereSql}`,
3872
+ where: null,
3873
+ params,
3874
+ assembly: { shape: "items" }
3875
+ };
3876
+ return { id: nextId2("requires"), role: "gate:requires", op, gate: "existsElseRollback", label: `requires ${e.table}` };
3877
+ }
3878
+ function compileIdempotency(e, nextId2, dialect) {
3879
+ const op = {
3880
+ component: "Insert",
3881
+ sql: dialect.guardInsert(e.table, [e.column], "?"),
3882
+ where: null,
3883
+ params: [pathToRef(e.token)],
3884
+ assembly: { shape: "items" }
3885
+ };
3886
+ return { id: nextId2("idem"), role: "gate:idempotency", op, gate: "insertedElseNoop", label: `idempotency ${e.table}` };
3887
+ }
3888
+ function compileUnique(e, nextId2, dialect) {
3889
+ const scopeCols = e.scope.map((_, i) => `s${i}`);
3890
+ const fieldCols = e.fields.map((_, i) => `f${i}`);
3891
+ const cols = ["name", ...scopeCols, ...fieldCols];
3892
+ const placeholders = cols.map(() => "?").join(", ");
3893
+ const params = [
3894
+ e.name,
3895
+ // literal discriminator (a closed-set string literal)
3896
+ ...e.scope.map(pathToRef),
3897
+ ...e.fields.map(pathToRef)
3898
+ ];
3899
+ const op = {
3900
+ component: "Insert",
3901
+ sql: dialect.guardInsert(e.guardTable, cols, placeholders),
3902
+ where: null,
3903
+ params,
3904
+ assembly: { shape: "items" }
3905
+ };
3906
+ return { id: nextId2("unique"), role: "gate:unique", op, gate: "insertedElseRollback", label: `unique ${e.name}` };
3907
+ }
3908
+ function compileDerive(e, nextId2) {
3909
+ const keyCols = Object.keys(e.keys);
3910
+ if (keyCols.length === 0) throw new Error(`write-plan: derive on '${e.table}' declares no keys`);
3911
+ const op = {
3912
+ component: "Update",
3913
+ sql: `UPDATE ${e.table} SET ${e.attribute} = ${e.attribute} + ?${WHERE_SLOT}`,
3914
+ where: {
3915
+ connector: "AND",
3916
+ fragments: keyCols.map((c) => ({ always: true, sql: `${c} = ?`, params: [pathToRef(e.keys[c])] }))
3917
+ },
3918
+ params: [e.amount],
3919
+ assembly: { shape: "items" }
3920
+ };
3921
+ return { id: nextId2("derive"), role: "derive", op, label: `derive ${e.table}.${e.attribute}` };
3922
+ }
3923
+ function compileEdge(e, nextId2) {
3924
+ if (e.relation === "m2m") {
3925
+ const cols = Object.keys(e.columns);
3926
+ if (e.action === "set") {
3927
+ const placeholders = cols.map(() => "?").join(", ");
3928
+ const op3 = {
3929
+ component: "Insert",
3930
+ sql: `INSERT INTO ${e.table} (${cols.join(", ")}) VALUES (${placeholders})`,
3931
+ where: null,
3932
+ params: cols.map((c) => pathToRef(e.columns[c])),
3933
+ assembly: { shape: "items" }
3934
+ };
3935
+ return { id: nextId2("edge"), role: "edge", op: op3, label: `edge m2m link ${e.table}` };
3936
+ }
3937
+ const op2 = {
3938
+ component: "Delete",
3939
+ sql: `DELETE FROM ${e.table}${WHERE_SLOT}`,
3940
+ where: { connector: "AND", fragments: cols.map((c) => ({ always: true, sql: `${c} = ?`, params: [pathToRef(e.columns[c])] })) },
3941
+ params: [],
3942
+ assembly: { shape: "items" }
3943
+ };
3944
+ return { id: nextId2("edge"), role: "edge", op: op2, label: `edge m2m unlink ${e.table}` };
3945
+ }
3946
+ const setCols = Object.keys(e.columns);
3947
+ const whereCols = Object.keys(e.where);
3948
+ const setClauses = setCols.map((c) => e.action === "set" ? `${c} = ?` : `${c} = NULL`);
3949
+ const setParams = e.action === "set" ? setCols.map((c) => pathToRef(e.columns[c])) : [];
3950
+ const op = {
3951
+ component: "Update",
3952
+ sql: `UPDATE ${e.table} SET ${setClauses.join(", ")}${WHERE_SLOT}`,
3953
+ where: { connector: "AND", fragments: whereCols.map((c) => ({ always: true, sql: `${c} = ?`, params: [pathToRef(e.where[c])] })) },
3954
+ params: setParams,
3955
+ assembly: { shape: "items" }
3956
+ };
3957
+ return { id: nextId2("edge"), role: "edge", op, label: `edge fk ${e.action} ${e.table}` };
3958
+ }
3959
+ function compileEmit(e, nextId2) {
3960
+ const payloadObj = {};
3961
+ for (const [k, v] of Object.entries(e.payload)) payloadObj[k] = pathToRef(v);
3962
+ const op = {
3963
+ component: "Insert",
3964
+ sql: `INSERT INTO ${e.outboxTable} (type, payload) VALUES (?, ?)`,
3965
+ where: null,
3966
+ params: [e.name, { obj: payloadObj }],
3967
+ assembly: { shape: "items" }
3968
+ };
3969
+ return { id: nextId2("emit"), role: "emit", op, label: `emit ${e.name}` };
3970
+ }
3971
+ function compileWriteGroup(base, lifecycle, nextId2, dialect, seqRef) {
3972
+ const e = lifecycle.effects;
3973
+ const nodes = [];
3974
+ const mk = (stmt, isGate) => {
3975
+ const consumes = refHeadsOf(stmt).filter((h) => h !== ENTITY_ROOT && !isInputHead(h, stmt));
3976
+ return { stmt, seq: seqRef.n++, consumes, produces: stmt.binds ?? null, isGate };
3977
+ };
3978
+ for (const r of e.requires ?? []) nodes.push(mk(compileRequires(r, nextId2), true));
3979
+ if (e.idempotency !== void 0) nodes.push(mk(compileIdempotency(e.idempotency, nextId2, dialect), true));
3980
+ for (const u of e.unique ?? []) nodes.push(mk(compileUnique(u, nextId2, dialect), true));
3981
+ const bodyId = nextId2("body");
3982
+ const bodyStmt = {
3983
+ id: bodyId,
3984
+ role: "body",
3985
+ op: base.op,
3986
+ label: base.label,
3987
+ ...base.name !== void 0 ? { binds: base.name } : {}
3988
+ };
3989
+ nodes.push(mk(bodyStmt, false));
3990
+ for (const d of e.derive ?? []) nodes.push(mk(compileDerive(d, nextId2), false));
3991
+ for (const ed of e.edges ?? []) nodes.push(mk(compileEdge(ed, nextId2), false));
3992
+ for (const em of e.emits ?? []) nodes.push(mk(compileEmit(em, nextId2), false));
3993
+ return { nodes, bodyId };
3994
+ }
3995
+ function topoOrder(nodes) {
3996
+ const byName = /* @__PURE__ */ new Map();
3997
+ for (const n of nodes) {
3998
+ if (n.produces !== null) {
3999
+ if (byName.has(n.produces)) {
4000
+ throw new Error(`write-plan: two writes both bind the name '${n.produces}' \u2014 write names must be unique in a composite Command.`);
4001
+ }
4002
+ byName.set(n.produces, n);
4003
+ }
4004
+ }
4005
+ const idOf = /* @__PURE__ */ new Map();
4006
+ for (const n of nodes) idOf.set(n, n.stmt.id);
4007
+ const succ = /* @__PURE__ */ new Map();
4008
+ const indeg = /* @__PURE__ */ new Map();
4009
+ const nodeById = /* @__PURE__ */ new Map();
4010
+ for (const n of nodes) {
4011
+ nodeById.set(n.stmt.id, n);
4012
+ succ.set(n.stmt.id, /* @__PURE__ */ new Set());
4013
+ indeg.set(n.stmt.id, 0);
4014
+ }
4015
+ const addEdge = (fromId, toId) => {
4016
+ if (fromId === toId) return;
4017
+ const s = succ.get(fromId);
4018
+ if (!s.has(toId)) {
4019
+ s.add(toId);
4020
+ indeg.set(toId, indeg.get(toId) + 1);
4021
+ }
4022
+ };
4023
+ for (const n of nodes) {
4024
+ for (const dep of n.consumes) {
4025
+ const producer = byName.get(dep);
4026
+ if (producer === void 0) {
4027
+ throw new Error(
4028
+ `write-plan: statement '${n.stmt.label}' references '$.ref.${dep}.*' but no write in this Command binds the name '${dep}' \u2014 a dangling write reference (fail-closed; no silent skip).`
4029
+ );
4030
+ }
4031
+ addEdge(producer.stmt.id, n.stmt.id);
4032
+ }
4033
+ }
4034
+ const gates = nodes.filter((n) => n.isGate);
4035
+ const nonGates = nodes.filter((n) => !n.isGate);
4036
+ for (const g of gates) for (const b of nonGates) addEdge(g.stmt.id, b.stmt.id);
4037
+ const ordered = [];
4038
+ const ready = nodes.filter((n) => indeg.get(n.stmt.id) === 0).sort((a, b) => a.seq - b.seq);
4039
+ while (ready.length > 0) {
4040
+ const n = ready.shift();
4041
+ ordered.push(n.stmt);
4042
+ for (const depId of succ.get(n.stmt.id)) {
4043
+ indeg.set(depId, indeg.get(depId) - 1);
4044
+ if (indeg.get(depId) === 0) {
4045
+ const dn = nodeById.get(depId);
4046
+ let lo = 0;
4047
+ while (lo < ready.length && ready[lo].seq < dn.seq) lo++;
4048
+ ready.splice(lo, 0, dn);
4049
+ }
4050
+ }
4051
+ }
4052
+ if (ordered.length !== nodes.length) {
4053
+ const stuck = nodes.filter((n) => !ordered.includes(n.stmt)).map((n) => n.stmt.label);
4054
+ throw new Error(
4055
+ `write-plan: the write-time transaction DAG has a CYCLE (unresolvable ordering among [${stuck.join(", ")}]). This is either a mutual '$.ref' data dependency or a gate that depends on a body row (a gate cannot depend on a not-yet-written row). ESCALATE: the Command's write dependencies are contradictory \u2014 no order satisfies both the data dependencies and gate-first. (Fail-closed; the derivation never guesses an order.)`
4056
+ );
4057
+ }
4058
+ return ordered;
4059
+ }
4060
+ function deriveTransactionPlan(phase, bases, lifecycle, dialect = SQLITE) {
4061
+ if (bases.length === 0) {
4062
+ throw new Error("write-plan: a Command must declare at least one base write (Insert/Update/Delete).");
4063
+ }
4064
+ const nextId2 = makeIdGen();
4065
+ const seqRef = { n: 0 };
4066
+ const composite = bases.length > 1;
4067
+ const allNodes = [];
4068
+ const bodyIds = [];
4069
+ bases.forEach((base, i) => {
4070
+ const lc = base.effects !== void 0 ? { effects: base.effects } : i === 0 ? lifecycle : { effects: {} };
4071
+ const { nodes, bodyId } = compileWriteGroup(base, lc, nextId2, dialect, seqRef);
4072
+ allNodes.push(...nodes);
4073
+ bodyIds.push(bodyId);
4074
+ });
4075
+ const statements = topoOrder(allNodes);
4076
+ const soleBody = bases[0];
4077
+ const soleBodyId = bodyIds[0];
4078
+ const usesEntity = referencesHead(statements, ENTITY_ROOT);
4079
+ const soleBodyReturns = /\breturning\b/i.test(soleBody.op.sql);
4080
+ if (usesEntity && composite) {
4081
+ throw new Error(
4082
+ `write-plan: a composite (multi-write) Command uses '$.entity.*' \u2014 ambiguous which write it denotes. Address each write's row by name via '$.ref.<writeName>.<field>' (fail-closed).`
4083
+ );
4084
+ }
4085
+ if (usesEntity && !soleBodyReturns) {
4086
+ throw new Error(
4087
+ `write-plan: a derive/edges/emits stage references '$.entity.*' but the body write ('${soleBody.label}') has no RETURNING clause \u2014 the written row cannot be exposed to later stages. Add a RETURNING to the base write (fail-closed; no absent-entity default).`
4088
+ );
4089
+ }
4090
+ const entityFrom = usesEntity || !composite && soleBodyReturns ? soleBodyId : null;
4091
+ for (const base of bases) {
4092
+ if (base.name === void 0) continue;
4093
+ if (referencesHead(statements, base.name) && !/\breturning\b/i.test(base.op.sql)) {
4094
+ throw new Error(
4095
+ `write-plan: write '${base.name}' is referenced as '$.ref.${base.name}.*' by a later statement but its op has no RETURNING clause \u2014 its row cannot be bound for downstream writes. Add a RETURNING to write '${base.name}' (fail-closed; no absent-row default).`
4096
+ );
4097
+ }
4098
+ }
4099
+ for (const s of statements) assertOperationPortable(s.op);
4100
+ return { phase, entityFrom, statements, onIdempotentHit: "rollback" };
4101
+ }
4102
+ function refHeadsOf(stmt) {
4103
+ const heads = /* @__PURE__ */ new Set();
4104
+ collectRefHeads(stmt.op.params, heads);
4105
+ if (stmt.op.where !== null) collectWhereHeads(stmt.op.where, heads);
4106
+ return [...heads];
4107
+ }
4108
+ function isInputHead(head, stmt) {
4109
+ return refPathLengthFor(stmt, head) === 1;
4110
+ }
4111
+ function refPathLengthFor(stmt, head) {
4112
+ let maxLen = 0;
4113
+ const walk = (node) => {
4114
+ if (node === null || typeof node !== "object") return;
4115
+ if (Array.isArray(node)) {
4116
+ for (const el of node) walk(el);
4117
+ return;
4118
+ }
4119
+ const keys = Object.keys(node);
4120
+ if (keys.length === 1 && keys[0] === "ref") {
4121
+ const path = node.ref;
4122
+ if (Array.isArray(path) && path[0] === head) maxLen = Math.max(maxLen, path.length);
4123
+ return;
4124
+ }
4125
+ for (const k of keys) walk(node[k]);
4126
+ };
4127
+ walk(stmt.op.params);
4128
+ if (stmt.op.where !== null) {
4129
+ const collectWhere = (node) => {
4130
+ if (node === null || typeof node !== "object") return;
4131
+ const n = node;
4132
+ if ("connector" in n && Array.isArray(n.fragments)) {
4133
+ for (const f of n.fragments) collectWhere(f);
4134
+ return;
4135
+ }
4136
+ if (Array.isArray(n.params)) walk(n.params);
4137
+ };
4138
+ collectWhere(stmt.op.where);
4139
+ }
4140
+ return maxLen;
4141
+ }
4142
+ function referencesHead(statements, head) {
4143
+ const heads = /* @__PURE__ */ new Set();
4144
+ for (const s of statements) {
4145
+ collectRefHeads(s.op.params, heads);
4146
+ if (s.op.where !== null) collectWhereHeads(s.op.where, heads);
4147
+ }
4148
+ return heads.has(head);
4149
+ }
4150
+ function collectRefHeads(node, heads) {
4151
+ if (node === null || typeof node !== "object") return;
4152
+ if (Array.isArray(node)) {
4153
+ for (const el of node) collectRefHeads(el, heads);
4154
+ return;
4155
+ }
4156
+ const keys = Object.keys(node);
4157
+ if (keys.length === 1 && keys[0] === "ref") {
4158
+ const path = node.ref;
4159
+ if (Array.isArray(path) && typeof path[0] === "string") heads.add(path[0]);
4160
+ return;
4161
+ }
4162
+ for (const k of keys) collectRefHeads(node[k], heads);
4163
+ }
4164
+ function collectWhereHeads(node, heads) {
4165
+ if (node === null || typeof node !== "object") return;
4166
+ const n = node;
4167
+ if ("connector" in n && Array.isArray(n.fragments)) {
4168
+ for (const f of n.fragments) collectWhereHeads(f, heads);
4169
+ return;
4170
+ }
4171
+ if (Array.isArray(n.params)) collectRefHeads(n.params, heads);
4172
+ }
4173
+
4174
+ // src/scp/write-runtime.ts
4175
+ function toDriverParam(v) {
4176
+ if (typeof v === "bigint") {
4177
+ if (v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER)) return Number(v);
4178
+ return v;
4179
+ }
4180
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) return JSON.stringify(v);
4181
+ return v;
4182
+ }
4183
+ function execStatement(db, op, scope, dialect) {
4184
+ const rendered = renderOperation(op, scope, dialect);
4185
+ const params = rendered.params.map(toDriverParam);
4186
+ const stmt = db.prepare(rendered.sql);
4187
+ const hasReturn = op.component === "Select" || /\breturning\b/i.test(rendered.sql);
4188
+ if (hasReturn) {
4189
+ const rows = stmt.all(...params);
4190
+ return { rows, changes: rows.length };
4191
+ }
4192
+ const info = stmt.run(...params);
4193
+ return { rows: [], changes: info.changes };
4194
+ }
4195
+ function gateShortCircuit(gate, result) {
4196
+ switch (gate) {
4197
+ case "existsElseRollback":
4198
+ return result.rows.length === 0 ? "requires_absent" : null;
4199
+ case "insertedElseRollback":
4200
+ return result.changes === 0 ? "unique_collision" : null;
4201
+ case "insertedElseNoop":
4202
+ return result.changes === 0 ? "idempotent_duplicate" : null;
4203
+ }
4204
+ }
4205
+ function executeTransaction(db, plan, input, dialect = SQLITE) {
4206
+ db.prepare("BEGIN").run();
4207
+ const executed = [];
4208
+ const scope = { ...input };
4209
+ let entity = null;
4210
+ try {
4211
+ for (const stmt of plan.statements) {
4212
+ const result = runOne(db, stmt, scope, executed, dialect);
4213
+ if (stmt.gate !== void 0) {
4214
+ const reason = gateShortCircuit(stmt.gate, result);
4215
+ if (reason !== null) {
4216
+ db.prepare("ROLLBACK").run();
4217
+ return { committed: false, shortCircuit: { statementId: stmt.id, reason }, entity: null, executed };
4218
+ }
4219
+ }
4220
+ if (stmt.id === plan.entityFrom) {
4221
+ entity = result.rows.length > 0 ? result.rows[0] : null;
4222
+ if (entity !== null) scope[ENTITY_ROOT] = entity;
4223
+ }
4224
+ if (stmt.binds !== void 0 && result.rows.length > 0) {
4225
+ scope[stmt.binds] = result.rows[0];
4226
+ }
4227
+ }
4228
+ db.prepare("COMMIT").run();
4229
+ return { committed: true, entity, executed };
4230
+ } catch (e) {
4231
+ try {
4232
+ db.prepare("ROLLBACK").run();
4233
+ } catch {
4234
+ }
4235
+ throw mapSqliteError(e);
4236
+ }
4237
+ }
4238
+ function runOne(db, stmt, scope, executed, dialect) {
4239
+ const result = execStatement(db, stmt.op, scope, dialect);
4240
+ executed.push(stmt.id);
4241
+ return result;
4242
+ }
4243
+ function countingDriver(db) {
4244
+ const prepared = [];
4245
+ const wrapped = {
4246
+ prepare(sql) {
4247
+ prepared.push(sql);
4248
+ return db.prepare(sql);
4249
+ }
4250
+ };
4251
+ return { db: wrapped, prepared };
4252
+ }
4253
+
4254
+ // src/scp/runtime.ts
4255
+ var SCOPE_PORT = "__scope";
4256
+ function toDriverParam2(v) {
4257
+ if (typeof v === "bigint") {
4258
+ if (v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER)) return Number(v);
4259
+ return v;
4260
+ }
4261
+ return v;
4262
+ }
4263
+ function collectHeads(node, heads) {
4264
+ if (node === null || typeof node !== "object") return;
4265
+ if (Array.isArray(node)) {
4266
+ for (const el of node) collectHeads(el, heads);
4267
+ return;
4268
+ }
4269
+ const keys = Object.keys(node);
4270
+ if (keys.length === 1 && (keys[0] === "ref" || keys[0] === "refOpt")) {
4271
+ const path = node[keys[0]];
4272
+ if (Array.isArray(path) && typeof path[0] === "string") heads.add(path[0]);
4273
+ return;
4274
+ }
4275
+ for (const k of keys) collectHeads(node[k], heads);
4276
+ }
4277
+ function collectRefOptHeads(node, heads) {
4278
+ if (node === null || typeof node !== "object") return;
4279
+ if (Array.isArray(node)) {
4280
+ for (const el of node) collectRefOptHeads(el, heads);
4281
+ return;
4282
+ }
4283
+ const keys = Object.keys(node);
4284
+ if (keys.length === 1 && keys[0] === "refOpt") {
4285
+ const path = node.refOpt;
4286
+ if (Array.isArray(path) && typeof path[0] === "string") heads.add(path[0]);
4287
+ return;
4288
+ }
4289
+ for (const k of keys) collectRefOptHeads(node[k], heads);
4290
+ }
4291
+ function collectFragmentHeads(node, heads) {
4292
+ if ("connector" in node) {
4293
+ for (const f of node.fragments) collectFragmentHeads(f, heads);
4294
+ return;
4295
+ }
4296
+ if (node.when !== void 0) collectHeads(node.when, heads);
4297
+ for (const p of node.params) collectHeads(p, heads);
4298
+ }
4299
+ function operationHeads(op) {
4300
+ const heads = /* @__PURE__ */ new Set();
4301
+ for (const p of op.params) collectHeads(p, heads);
4302
+ if (op.where !== null) collectFragmentHeads(op.where, heads);
4303
+ return heads;
4304
+ }
4305
+ function skipGuardedHeads(node, heads) {
4306
+ if ("connector" in node) {
4307
+ for (const f of node.fragments) skipGuardedHeads(f, heads);
4308
+ return;
4309
+ }
4310
+ if (node.when !== void 0) {
4311
+ collectHeads(node.when, heads);
4312
+ for (const p of node.params) collectHeads(p, heads);
4313
+ }
4314
+ }
4315
+ function operationRefOptHeads(op, heads) {
4316
+ for (const p of op.params) collectRefOptHeads(p, heads);
4317
+ if (op.where !== null) collectFragmentRefOptHeads(op.where, heads);
4318
+ }
4319
+ function collectFragmentRefOptHeads(node, heads) {
4320
+ if ("connector" in node) {
4321
+ for (const f of node.fragments) collectFragmentRefOptHeads(f, heads);
4322
+ return;
4323
+ }
4324
+ if (node.when !== void 0) collectRefOptHeads(node.when, heads);
4325
+ for (const p of node.params) collectRefOptHeads(p, heads);
4326
+ }
4327
+ function optionalHeadsOf(compiled) {
4328
+ const heads = /* @__PURE__ */ new Set();
4329
+ for (const op of Object.values(compiled)) {
4330
+ if (op.where !== null) skipGuardedHeads(op.where, heads);
4331
+ operationRefOptHeads(op, heads);
4332
+ }
4333
+ return heads;
4334
+ }
4335
+ function scopePort(op) {
4336
+ const obj = {};
4337
+ for (const head of operationHeads(op)) {
4338
+ if (head === "@in") continue;
4339
+ obj[head] = { ref: [head] };
4340
+ }
4341
+ return { obj };
4342
+ }
4343
+ function surrogateNode(node, compiled) {
4344
+ if ("cond" in node) return node;
4345
+ if ("map" in node) {
4346
+ const op2 = compiled[node.id];
4347
+ if (op2 === void 0) return node;
4348
+ return { ...node, map: { ...node.map, ports: { [SCOPE_PORT]: scopePort(op2) } } };
4349
+ }
4350
+ const op = compiled[node.id];
4351
+ if (op === void 0) return node;
4352
+ return { ...node, ports: { [SCOPE_PORT]: scopePort(op) } };
4353
+ }
4354
+ function surrogateComponent(component, compiled) {
4355
+ return { ...component, body: component.body.map((n) => surrogateNode(n, compiled)) };
4356
+ }
4357
+ function executeRendered(db, op, scope, dialect) {
4358
+ const rendered = renderOperation(op, scope, dialect);
4359
+ const params = rendered.params.map(toDriverParam2);
4360
+ let stmt;
4361
+ try {
4362
+ stmt = db.prepare(rendered.sql);
4363
+ } catch (e) {
4364
+ return { error: mapSqliteError(e).message };
4365
+ }
4366
+ const hasReturn = op.component === "Select" || /\breturning\b/i.test(rendered.sql);
4367
+ try {
4368
+ if (hasReturn) {
4369
+ const rows = stmt.all(...params);
4370
+ return { ok: rows };
4371
+ }
4372
+ const info = stmt.run(...params);
4373
+ return {
4374
+ ok: [{ changes: info.changes, lastInsertRowid: toDriverParam2(BigInt(info.lastInsertRowid)) }]
4375
+ };
4376
+ } catch (e) {
4377
+ return { error: mapSqliteError(e).message };
4378
+ }
4379
+ }
4380
+ function buildHandlers(db, compiled, dialect) {
4381
+ const handle = (ports, ctx) => {
4382
+ const op = compiled[ctx.nodeId];
4383
+ if (op === void 0) {
4384
+ return { error: `scp runtime: no compiled operation for node '${ctx.nodeId}' (${ctx.component})` };
4385
+ }
4386
+ const scope = ports[SCOPE_PORT];
4387
+ if (scope === null || typeof scope !== "object" || Array.isArray(scope)) {
4388
+ return { error: `scp runtime: node '${ctx.nodeId}' surrogate scope did not evaluate to an object` };
4389
+ }
4390
+ return executeRendered(db, op, scope, dialect);
4391
+ };
4392
+ return { Select: handle, Insert: handle, Update: handle, Delete: handle };
4393
+ }
4394
+ function normalizeInput(component, optionalHeads, input) {
4395
+ const out = { ...input };
4396
+ for (const [port, schema] of Object.entries(component.inputPorts)) {
4397
+ if (schema.required !== true && !(port in out)) out[port] = null;
4398
+ }
4399
+ for (const head of optionalHeads) {
4400
+ if (!(head in out)) out[head] = null;
4401
+ }
4402
+ return out;
4403
+ }
4404
+ function executeBehavior(contract, input, options) {
4405
+ return executeBundle(compileBundle(contract, options.entry, options.relations, options.dialect), input, options);
4406
+ }
4407
+ function compileBundle(contract, entry2, relations = [], dialectName = "sqlite") {
4408
+ const dialect = dialectFor(dialectName);
4409
+ const component = entry2 ? contract.components.find((c) => c.name === entry2) : contract.components[0];
4410
+ if (component === void 0) {
4411
+ throw new Error(`scp runtime: entry component '${entry2 ?? "<first>"}' not found in contract`);
4412
+ }
4413
+ const operations = {};
4414
+ for (const [id, op] of compileComponentNodes(component, dialect)) operations[id] = op;
4415
+ const surrogate = surrogateComponent(component, operations);
4416
+ const relationOps = {};
4417
+ for (const decl of relations) {
4418
+ if (relationOps[decl.name] !== void 0) {
4419
+ throw new Error(`scp runtime: duplicate relation declaration '${decl.name}'`);
4420
+ }
4421
+ relationOps[decl.name] = compileRelationOp(decl);
4422
+ }
4423
+ return {
4424
+ irVersion: contract.ir.irVersion,
4425
+ exprVersion: contract.ir.exprVersion,
4426
+ dialect: dialectName,
4427
+ component: surrogate,
4428
+ operations,
4429
+ optionalHeads: [...optionalHeadsOf(operations)],
4430
+ relations: relationOps
4431
+ };
4432
+ }
4433
+ function executeBundle(bundle, input, options) {
4434
+ const surrogate = bundle.component;
4435
+ const ir = {
4436
+ irVersion: bundle.irVersion,
4437
+ exprVersion: bundle.exprVersion,
4438
+ components: [surrogate]
4439
+ };
4440
+ const handlers = buildHandlers(options.db, bundle.operations, dialectFor(bundle.dialect));
4441
+ const optionalHeads = new Set(bundle.optionalHeads);
4442
+ const normalized = normalizeInput(surrogate, optionalHeads, input);
4443
+ try {
4444
+ return runBehavior(ir, handlers, normalized, surrogate.name);
4445
+ } catch (e) {
4446
+ throw reErrorToSqlFailure(e);
4447
+ }
4448
+ }
4449
+ function baseWriteNodeOf(component) {
4450
+ const writes = component.body.filter(
4451
+ (n) => !("cond" in n) && !("map" in n) && (n.component === "Insert" || n.component === "Update" || n.component === "Delete")
4452
+ );
4453
+ if (writes.length === 0) {
4454
+ throw new Error(`scp write: Command '${component.name}' has no base write (Insert/Update/Delete) node`);
4455
+ }
4456
+ if (writes.length > 1) {
4457
+ throw new Error(
4458
+ `scp write: Command '${component.name}' has ${writes.length} base write nodes; WS5 initial scope is a SINGLE-statement Command + write-time relations (multi-write DAG is WS8, spec \xA76/\xA713).`
4459
+ );
4460
+ }
4461
+ return writes[0];
4462
+ }
4463
+ function compileWriteBundle(contract, entry2, writes, phase, dialectName = "sqlite") {
4464
+ const dialect = dialectFor(dialectName);
4465
+ const component = contract.components.find((c) => c.name === entry2);
4466
+ if (component === void 0) {
4467
+ throw new Error(`scp write: entry component '${entry2}' not found in contract`);
4468
+ }
4469
+ const lifecycle = lifecycleFor(writes, phase);
4470
+ if (lifecycle === void 0) {
4471
+ throw new Error(`scp write: the '${phase}' lifecycle is not declared in the entityWrites save contract`);
4472
+ }
4473
+ const writeNode = baseWriteNodeOf(component);
4474
+ const baseOp = compileNode(writeNode, dialect);
4475
+ const base = { op: baseOp, label: `${baseOp.component} ${writeNode.component}` };
4476
+ const plan = deriveTransactionPlan(phase, [base], lifecycle, dialect);
4477
+ const operations = {};
4478
+ for (const [id, op] of compileComponentNodes(component, dialect)) operations[id] = op;
4479
+ const surrogate = surrogateComponent(component, operations);
4480
+ return {
4481
+ irVersion: contract.ir.irVersion,
4482
+ exprVersion: contract.ir.exprVersion,
4483
+ dialect: dialectName,
4484
+ component: surrogate,
4485
+ operations,
4486
+ optionalHeads: [...optionalHeadsOf(operations)],
4487
+ relations: {},
4488
+ transaction: plan
4489
+ };
4490
+ }
4491
+ function compileCompositeWriteBundle(contract, entries, phase, dialectName = "sqlite") {
4492
+ if (entries.length < 2) {
4493
+ throw new Error("scp write: a composite write bundle needs at least 2 named write members (use compileWriteBundle for a single write).");
4494
+ }
4495
+ const dialect = dialectFor(dialectName);
4496
+ const bases = [];
4497
+ const operations = {};
4498
+ let firstComponent;
4499
+ for (const e of entries) {
4500
+ const component = contract.components.find((c) => c.name === e.entry);
4501
+ if (component === void 0) throw new Error(`scp write: entry component '${e.entry}' not found in contract`);
4502
+ if (firstComponent === void 0) firstComponent = component;
4503
+ const writeNode = baseWriteNodeOf(component);
4504
+ const baseOp = compileNode(writeNode, dialect);
4505
+ bases.push({ op: baseOp, label: `${writeNode.component} ${e.name}`, name: e.name, effects: e.lifecycle.effects });
4506
+ for (const [id, op] of compileComponentNodes(component, dialect)) operations[`${e.name}.${id}`] = op;
4507
+ }
4508
+ const plan = deriveTransactionPlan(phase, bases, { effects: {} }, dialect);
4509
+ const surrogate = surrogateComponent(firstComponent, operations);
4510
+ return {
4511
+ irVersion: contract.ir.irVersion,
4512
+ exprVersion: contract.ir.exprVersion,
4513
+ dialect: dialectName,
4514
+ component: surrogate,
4515
+ operations,
4516
+ optionalHeads: [...optionalHeadsOf(operations)],
4517
+ relations: {},
4518
+ transaction: plan
4519
+ };
4520
+ }
4521
+ function executeCompositeCommand(contract, entries, phase, input, options) {
4522
+ const bundle = compileCompositeWriteBundle(contract, entries, phase, options.dialect);
4523
+ return executeTransactionBundle(bundle, input, options);
4524
+ }
4525
+ function executeCommand(contract, writes, phase, input, options) {
4526
+ const bundle = compileWriteBundle(contract, options.entry, writes, phase, options.dialect);
4527
+ return executeTransactionBundle(bundle, input, options);
4528
+ }
4529
+ function executeTransactionBundle(bundle, input, options) {
4530
+ if (bundle.transaction === void 0) {
4531
+ throw new Error("scp write: this bundle carries no transaction plan (not a write-time-relations Command bundle)");
4532
+ }
4533
+ return executeTransaction(options.db, bundle.transaction, input, dialectFor(bundle.dialect));
4534
+ }
4535
+ function read(contract, input, options) {
4536
+ return readBundle(compileBundle(contract, options.entry, options.relations), input, options);
4537
+ }
4538
+ function readBundle(bundle, input, options) {
4539
+ const out = executeBundle(bundle, input, options);
4540
+ if (!Array.isArray(out)) {
4541
+ throw new Error(
4542
+ `scp read: the read behavior output is not a row list (got ${out === null ? "null" : typeof out}); the typed-object read surface expects a Select-shaped output`
4543
+ );
4544
+ }
4545
+ const rawRows = out;
4546
+ const readOpts = {
4547
+ ...options.with !== void 0 ? { with: options.with } : {},
4548
+ ...options.hydrate !== void 0 ? { hydrate: options.hydrate } : {}
4549
+ };
4550
+ return buildResultSet(rawRows, bundle.relations, options.db, readOpts);
4551
+ }
4552
+ var RELATION_BATCH_COMPONENT = "__RelationBatch";
4553
+ var RELATION_KEY_PORT = "__key";
4554
+ function resolveRelationViaPlan(op, parents, db) {
4555
+ const elemAs = "$p";
4556
+ const node = {
4557
+ id: "rel",
4558
+ map: {
4559
+ over: { ref: ["__parents"] },
4560
+ as: elemAs,
4561
+ component: RELATION_BATCH_COMPONENT,
4562
+ ports: { [RELATION_KEY_PORT]: { ref: [elemAs, op.parentKey] } },
4563
+ into: op.name,
4564
+ batched: true
4565
+ }
4566
+ };
4567
+ const component = {
4568
+ name: "__resolveRelation",
4569
+ inputPorts: { __parents: { required: true } },
4570
+ body: [node],
4571
+ output: { ref: ["rel"] }
4572
+ };
4573
+ const ir = {
4574
+ irVersion: 1,
4575
+ exprVersion: 1,
4576
+ components: [component]
4577
+ };
4578
+ const handlers = {
4579
+ [RELATION_BATCH_COMPONENT]: (portsOrItems) => {
4580
+ const items = portsOrItems.items;
4581
+ if (!Array.isArray(items)) {
4582
+ return { error: `${RELATION_BATCH_COMPONENT}: expected a batched {items:[\u2026]} invocation` };
4583
+ }
4584
+ const keyRows = items.map((it) => ({ [op.parentKey]: it[RELATION_KEY_PORT] }));
4585
+ const { batch } = runRelationOp(op, keyRows, db);
4586
+ const aligned = keyRows.map((r) => distributeToParent(op, r, batch));
4587
+ return { ok: aligned };
4588
+ }
4589
+ };
4590
+ const out = runBehavior(ir, handlers, { __parents: parents }, "__resolveRelation");
4591
+ return out;
4592
+ }
4593
+ function reErrorToSqlFailure(e) {
4594
+ const message = e instanceof Error ? e.message : String(e);
4595
+ const m = /(SQLITE_[A-Z_]+)/.exec(message);
4596
+ if (m) {
4597
+ return mapSqliteError({ code: m[1], message });
4598
+ }
4599
+ return e;
4600
+ }
4601
+
4602
+ // src/scp/codegen.ts
4603
+ var CODEGEN_LANGUAGES = ["typescript", "python", "go", "rust", "php"];
4604
+ function bundleToPortableIR(bundle) {
4605
+ return {
4606
+ irVersion: bundle.irVersion,
4607
+ exprVersion: bundle.exprVersion,
4608
+ components: [bundle.component]
4609
+ };
4610
+ }
4611
+ function companionOf(bundle) {
4612
+ const base = {
4613
+ operations: bundle.operations,
4614
+ dialect: bundle.dialect,
4615
+ optionalHeads: bundle.optionalHeads,
4616
+ relations: bundle.relations
4617
+ };
4618
+ return bundle.transaction === void 0 ? base : { ...base, transaction: bundle.transaction };
4619
+ }
4620
+ function assertLanguageSupported(language, registered) {
4621
+ if (!CODEGEN_LANGUAGES.includes(language)) {
4622
+ throw new Error(
4623
+ `litedbmodel codegen: language '${language}' is not a supported target (supported: ${CODEGEN_LANGUAGES.join(", ")})`
4624
+ );
4625
+ }
4626
+ if (!registered.includes(language)) {
4627
+ throw new Error(
4628
+ `litedbmodel codegen: bc's shared generator does not register an emitter for '${language}' (bc registered: ${[...registered].sort().join(", ")}). This is a bc#13 capability limit \u2014 ESCALATE to bc (bc#22 pattern), never fork a litedbmodel-local generator (codegen \u306F\u4E0A\u6D41\u6240\u6709, spec \xA79).`
4629
+ );
4630
+ }
4631
+ }
4632
+ function generateCodegenArtifact(bundle, language, registeredLanguages2, runtimeImport) {
4633
+ assertLanguageSupported(language, registeredLanguages2);
4634
+ const ir = bundleToPortableIR(bundle);
4635
+ const module2 = generateModule(ir, runtimeImport === void 0 ? { language } : { language, runtimeImport });
4636
+ return { language, module: module2, companion: companionOf(bundle), ir };
4637
+ }
4638
+ function codegenExecuteBundleForTest(artifact, input, db) {
4639
+ const { ir } = artifact;
4640
+ const component = ir.components[0];
4641
+ const { operations, dialect, optionalHeads } = artifact.companion;
4642
+ const handlers = buildHandlers(db, operations, dialectFor(dialect));
4643
+ const normalized = normalizeInput(component, new Set(optionalHeads), input);
4644
+ return runBehavior(ir, handlers, normalized, component.name);
4645
+ }
4646
+ // Annotate the CommonJS export names for ESM import in node:
4647
+ 0 && (module.exports = {
4648
+ CATALOG_NAMES,
4649
+ CODEGEN_LANGUAGES,
4650
+ ENTITY_ROOT,
4651
+ IN_SENTINEL,
4652
+ LITEDBMODEL_CATALOG,
4653
+ MYSQL,
4654
+ POSTGRES,
4655
+ RELATION_CONTEXT,
4656
+ RELATION_KEYS_HEAD,
4657
+ RelationContext,
4658
+ SQLITE,
4659
+ SemanticBehavior,
4660
+ SqlFailure,
4661
+ WHERE_SLOT,
4662
+ WRITE_CATALOG_NAMES,
4663
+ WRITE_PORT_FAMILIES,
4664
+ add,
4665
+ and,
4666
+ assertComponentGraphPortable,
4667
+ assertComponentPortable,
4668
+ assertComponentsInCatalog,
4669
+ assertExprPortable,
4670
+ assertLanguageSupported,
4671
+ assertOperationPortable,
4672
+ behavior,
4673
+ buildHandlers,
4674
+ buildResultSet,
4675
+ bundleToPortableIR,
4676
+ catalogEntry,
4677
+ coalesce,
4678
+ codegenExecuteBundleForTest,
4679
+ compileBundle,
4680
+ compileComponentNodes,
4681
+ compileCompositeWriteBundle,
4682
+ compileDelete,
4683
+ compileEager,
4684
+ compileInsert,
4685
+ compileInsertFor,
4686
+ compileNode,
4687
+ compileRelationOp,
4688
+ compileSelect,
4689
+ compileUpdate,
4690
+ compileWriteBundle,
4691
+ components,
4692
+ concat,
4693
+ countingDriver,
4694
+ deriveContractEffect,
4695
+ deriveTransactionPlan,
4696
+ dialectFor,
4697
+ distributeToParent,
4698
+ div,
4699
+ edgeWrites,
4700
+ entityWrites,
4701
+ eq,
4702
+ executeBehavior,
4703
+ executeBundle,
4704
+ executeCommand,
4705
+ executeCompositeCommand,
4706
+ executeTransaction,
4707
+ executeTransactionBundle,
4708
+ ge,
4709
+ generateCodegenArtifact,
4710
+ gt,
4711
+ inColumn,
4712
+ le,
4713
+ len,
4714
+ lifecycleFor,
4715
+ lt,
4716
+ mapSqliteError,
4717
+ mod,
4718
+ mul,
4719
+ ne,
4720
+ neg,
4721
+ normalizeInput,
4722
+ not,
4723
+ opt,
4724
+ or,
4725
+ parseEffectPath,
4726
+ publishBehaviors,
4727
+ read,
4728
+ readBundle,
4729
+ readRelationContext,
4730
+ renderOperation,
4731
+ resolveRelationViaPlan,
4732
+ runRelationOp,
4733
+ sub,
4734
+ toDollarPlaceholders,
4735
+ when,
4736
+ whereEq,
4737
+ whereGe,
4738
+ whereGt,
4739
+ whereIn,
4740
+ whereIsNull,
4741
+ whereLe,
4742
+ whereLt,
4743
+ whereNe
4744
+ });