@fuaran-ui/ops 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -386,9 +386,12 @@ var binding = (b, staticEnc = objValue) => {
386
386
  }
387
387
  case "Computed":
388
388
  return caseObj("Computed", [["fn", CLOSURE]]);
389
- // No wire fields: the instant is host-furnished at resolve time.
389
+ // Phase 765 the INSTANT is never on the wire: it is host-furnished at
390
+ // resolve time. Phase 1533 — the declared GRAIN is, and only when it is not
391
+ // the `Second` default, so a grain-less `Now` is the same bytes it has
392
+ // always been.
390
393
  case "Now":
391
- return caseObj("Now", []);
394
+ return caseObj("Now", b.grain !== void 0 ? [["grain", str(b.grain)]] : []);
392
395
  case "I18n": {
393
396
  const fields = [];
394
397
  if (b.args !== void 0) {
@@ -400,14 +403,18 @@ var binding = (b, staticEnc = objValue) => {
400
403
  fields.push(["key", str(b.key)]);
401
404
  return caseObj("I18n", fields);
402
405
  }
403
- case "Local":
404
- return caseObj("Local", [
406
+ case "Local": {
407
+ const localFields = [
405
408
  ["flushOn", flushTrigger(b.local.flushOn)],
406
409
  ["format", CLOSURE],
407
410
  ["initialFrom", binding(b.local.initialFrom, staticEnc)],
408
- ["onCommit", CLOSURE],
409
411
  ["parse", CLOSURE]
410
- ]);
412
+ ];
413
+ if (b.local.codec !== void 0) localFields.push(["codec", formatIntent(b.local.codec)]);
414
+ if (b.local.commitTo !== void 0) localFields.push(["commitTo", str(b.local.commitTo)]);
415
+ if (b.local.onCommit !== void 0) localFields.push(["onCommit", CLOSURE]);
416
+ return caseObj("Local", localFields);
417
+ }
411
418
  case "Format":
412
419
  return caseObj("Format", [
413
420
  ["format", formatIntent(b.format)],
@@ -437,6 +444,22 @@ var binding = (b, staticEnc = objValue) => {
437
444
  ]
438
445
  ]);
439
446
  }
447
+ case "Expr": {
448
+ const exprParams = b.params !== void 0 && b.params.length > 0 ? [
449
+ [
450
+ "params",
451
+ jArray(
452
+ b.params.map(
453
+ (p) => jObject([
454
+ ["from", binding(p.from)],
455
+ ["name", str(p.name)]
456
+ ])
457
+ )
458
+ )
459
+ ]
460
+ ] : [];
461
+ return caseObj("Expr", [["expr", colExpr(b.expr)], ...exprParams]);
462
+ }
440
463
  case "Invoke":
441
464
  return caseObj("Invoke", [
442
465
  ["args", invokeArgs(b.args)],
@@ -466,8 +489,11 @@ var action = (a) => {
466
489
  ["channel", str(a.channel)],
467
490
  ["payload", jsonValue(a.payload)]
468
491
  ]);
469
- case "Navigate":
470
- return caseObj("Navigate", [["route", str(a.route)]]);
492
+ case "Navigate": {
493
+ const fields = [["route", textSource(a.route)]];
494
+ if (a.target !== "Self") fields.push(["target", str(a.target)]);
495
+ return caseObj("Navigate", fields);
496
+ }
471
497
  case "SetState": {
472
498
  const fields = [["key", str(a.key)]];
473
499
  if (a.value !== void 0) fields.push(["value", jsonValue(a.value)]);
@@ -487,6 +513,15 @@ var action = (a) => {
487
513
  return caseObj("WriteToClipboard", [["text", textSource(a.text)]]);
488
514
  case "Print":
489
515
  return caseObj("Print", []);
516
+ case "Confirm": {
517
+ const fields = [];
518
+ if (a.onCancel !== void 0) fields.push(["onCancel", action(a.onCancel)]);
519
+ fields.push(["onConfirm", action(a.onConfirm)]);
520
+ fields.push(["prompt", textSource(a.prompt)]);
521
+ return caseObj("Confirm", fields);
522
+ }
523
+ case "Focus":
524
+ return caseObj("Focus", [["nodeId", str(a.nodeId)]]);
490
525
  case "ReadFileBody":
491
526
  return caseObj("ReadFileBody", [
492
527
  ["encoding", str(a.encoding)],
@@ -561,6 +596,10 @@ var formatIntent = (f) => {
561
596
  ["style", str(f.style)],
562
597
  ["unit", str(f.unit)]
563
598
  ]);
599
+ // Phase 1533 — `unit` omitted when absent: its absence is the
600
+ // auto-selection request, not a default that could be spelled out.
601
+ case "Since":
602
+ return caseObj("Since", f.unit !== void 0 ? [["unit", str(f.unit)]] : []);
564
603
  default:
565
604
  return assertNever(f);
566
605
  }
@@ -1343,15 +1382,34 @@ var gridSpec = (s) => {
1343
1382
  }
1344
1383
  return jObject(fields);
1345
1384
  };
1385
+ var chartAnnotationX = (a) => a.kind === "Category" ? caseObj("Category", [["key", str(a.key)]]) : caseObj("Date", [["iso", str(a.iso)]]);
1386
+ var chartAnnotationRange = (r) => r.kind === "ValueRange" ? caseObj("ValueRange", [
1387
+ ["from", num(r.from)],
1388
+ ["to", num(r.to)]
1389
+ ]) : caseObj("XRange", [
1390
+ ["from", chartAnnotationX(r.from)],
1391
+ ["to", chartAnnotationX(r.to)]
1392
+ ]);
1393
+ var chartAnnotation = (a) => {
1394
+ const label = a.label !== void 0 ? [["label", textSource(a.label)]] : [];
1395
+ switch (a.kind) {
1396
+ case "ReferenceLine":
1397
+ return caseObj("ReferenceLine", [["value", num(a.value)], ...label]);
1398
+ case "EventMarker":
1399
+ return caseObj("EventMarker", [["at", chartAnnotationX(a.at)], ...label]);
1400
+ default:
1401
+ return caseObj("RangeBand", [["range", chartAnnotationRange(a.range)], ...label]);
1402
+ }
1403
+ };
1346
1404
  var chartSpec = (s) => {
1347
1405
  const fields = [
1348
1406
  ["kind", str(s.kind)],
1349
1407
  // fuaran#665 — rows are a typed Static payload now, not the opaque residual.
1350
1408
  ["source", binding(s.source, staticRowSeq)],
1351
- ["stacked", bool(s.stacked)],
1352
1409
  ["xField", str(s.xField)],
1353
1410
  ["yFields", jArray(s.yFields.map(str))]
1354
1411
  ];
1412
+ if (s.stacked) fields.push(["stacked", bool(s.stacked)]);
1355
1413
  if (s.title !== void 0) fields.push(["title", textSource(s.title)]);
1356
1414
  if (s.valueFormat !== void 0) fields.push(["valueFormat", formatIntent(s.valueFormat)]);
1357
1415
  if (s.xTitle !== void 0) fields.push(["xTitle", textSource(s.xTitle)]);
@@ -1360,6 +1418,8 @@ var chartSpec = (s) => {
1360
1418
  if (s.legendPosition !== void 0) fields.push(["legendPosition", str(s.legendPosition)]);
1361
1419
  if (s.dataLabels !== void 0) fields.push(["dataLabels", str(s.dataLabels)]);
1362
1420
  if (s.xScale !== void 0) fields.push(["xScale", str(s.xScale)]);
1421
+ if (s.annotations !== void 0)
1422
+ fields.push(["annotations", jArray(s.annotations.map(chartAnnotation))]);
1363
1423
  if (s.onPointClick !== void 0) fields.push(["onPointClick", CLOSURE]);
1364
1424
  return jObject(fields);
1365
1425
  };
@@ -1642,10 +1702,14 @@ var nodeKind = (k) => {
1642
1702
  [
1643
1703
  "cases",
1644
1704
  jArray(
1705
+ // Phase 1535 — exactly one of `match` and `when` is present, so
1706
+ // exactly one is emitted. `jObject` sorts, so the pair's relative
1707
+ // order here is immaterial.
1645
1708
  k.spec.cases.map(
1646
1709
  (c) => jObject([
1647
1710
  ["child", node(c.child)],
1648
- ["match", str(c.match)]
1711
+ ...c.match !== void 0 ? [["match", str(c.match)]] : [],
1712
+ ...c.when !== void 0 ? [["when", binding(c.when, bool)]] : []
1649
1713
  ])
1650
1714
  )
1651
1715
  )
@@ -1740,6 +1804,7 @@ var node = (n) => {
1740
1804
  if (!isDefaultStyle(n.style)) fields.push(["style", semanticStyle(n.style)]);
1741
1805
  if (n.accessibility !== void 0) fields.push(["accessibility", accessibility(n.accessibility)]);
1742
1806
  if (n.tooltip !== void 0) fields.push(["tooltip", textSource(n.tooltip)]);
1807
+ if (n.visible !== void 0) fields.push(["visible", binding(n.visible, bool)]);
1743
1808
  return jObject(fields);
1744
1809
  };
1745
1810
  var treeOp = (op) => {
@@ -2895,6 +2960,51 @@ var substituteListParams = (listEnv, pipeline) => pipeline.map((t) => {
2895
2960
  return t;
2896
2961
  }
2897
2962
  });
2963
+
2964
+ // src/localCodec.ts
2965
+ var identityFormat = (v) => {
2966
+ if (v === null || v === void 0) return "";
2967
+ if (typeof v === "string") return v;
2968
+ if (typeof v === "boolean") return v ? "true" : "false";
2969
+ if (typeof v === "number") {
2970
+ if (Number.isNaN(v)) return "NaN";
2971
+ if (v === Infinity) return "Infinity";
2972
+ if (v === -Infinity) return "-Infinity";
2973
+ return formatFiniteDouble(v);
2974
+ }
2975
+ return String(v);
2976
+ };
2977
+ var tryNumberText = (text) => {
2978
+ const s = text.replace(/^[ \t\n\r]+|[ \t\n\r]+$/g, "");
2979
+ if (!/^-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?$/.test(s)) return void 0;
2980
+ const v = Number(s);
2981
+ return Number.isFinite(v) ? v : void 0;
2982
+ };
2983
+ var scalarOfText = (text) => {
2984
+ if (text === "true") return true;
2985
+ if (text === "false") return false;
2986
+ return tryNumberText(text);
2987
+ };
2988
+ var fixedText = (decimals, v) => {
2989
+ if (!Number.isFinite(v)) return identityFormat(v);
2990
+ const d = decimals < 0 ? 0 : Math.trunc(decimals);
2991
+ const neg = v < 0;
2992
+ const scaled = Math.floor(Math.abs(v) * Math.pow(10, d) + 0.5);
2993
+ const whole = formatFiniteDouble(scaled);
2994
+ const body = d === 0 ? whole : (() => {
2995
+ const padded = whole.length <= d ? "0".repeat(d + 1 - whole.length) + whole : whole;
2996
+ return padded.slice(0, padded.length - d) + "." + padded.slice(padded.length - d);
2997
+ })();
2998
+ return neg && scaled !== 0 ? "-" + body : body;
2999
+ };
3000
+ var numberText = (decimals, v) => decimals !== void 0 && typeof v === "number" ? fixedText(decimals, v) : identityFormat(v);
3001
+ var WireSurvivabilityError = class extends Error {
3002
+ constructor(message) {
3003
+ super(message);
3004
+ this.name = "WireSurvivabilityError";
3005
+ }
3006
+ };
3007
+ var DECODED_COMPUTED_MESSAGE = "Binding.Computed has no wire projection (decoded from a '<closure>' sentinel) \u2014 use Binding.Expr / Transform / State";
2898
3008
  var peek = (s) => s.pos < s.text.length ? s.text[s.pos] : " ";
2899
3009
  var advance = (s) => {
2900
3010
  s.pos += 1;
@@ -2925,51 +3035,94 @@ var expectChar = (s, ch) => {
2925
3035
  return fail(s, `expected '${ch}' but found '${peek(s)}'`);
2926
3036
  };
2927
3037
  var HEX_DIGIT = /[0-9a-fA-F]/;
3038
+ var HIGH_SURROGATE_FIRST = 55296;
3039
+ var HIGH_SURROGATE_LAST = 56319;
3040
+ var LOW_SURROGATE_FIRST = 56320;
3041
+ var LOW_SURROGATE_LAST = 57343;
2928
3042
  var parseStringRaw = (s) => {
2929
3043
  const open = expectChar(s, '"');
2930
3044
  if (!open.ok) return open;
2931
3045
  let out = "";
3046
+ let codePoints = 0;
3047
+ let pendingHigh = false;
3048
+ const append = (unit) => {
3049
+ const code = unit.charCodeAt(0);
3050
+ const isHigh = code >= HIGH_SURROGATE_FIRST && code <= HIGH_SURROGATE_LAST;
3051
+ const isLow = code >= LOW_SURROGATE_FIRST && code <= LOW_SURROGATE_LAST;
3052
+ if (isHigh) {
3053
+ if (pendingHigh) {
3054
+ return {
3055
+ message: "unpaired high surrogate: it must be followed by a low surrogate",
3056
+ offset: s.pos
3057
+ };
3058
+ }
3059
+ pendingHigh = true;
3060
+ codePoints += 1;
3061
+ } else if (isLow) {
3062
+ if (!pendingHigh) {
3063
+ return {
3064
+ message: "unpaired low surrogate: it must be preceded by a high surrogate",
3065
+ offset: s.pos
3066
+ };
3067
+ }
3068
+ pendingHigh = false;
3069
+ } else if (pendingHigh) {
3070
+ return {
3071
+ message: "unpaired high surrogate: it must be followed by a low surrogate",
3072
+ offset: s.pos
3073
+ };
3074
+ } else {
3075
+ codePoints += 1;
3076
+ }
3077
+ if (codePoints > schema.MAX_STRING_LENGTH) {
3078
+ return {
3079
+ message: `string is longer than the wire limit MAX_STRING_LENGTH = ${schema.MAX_STRING_LENGTH}`,
3080
+ offset: s.pos,
3081
+ limit: true
3082
+ };
3083
+ }
3084
+ out += unit;
3085
+ return void 0;
3086
+ };
2932
3087
  for (; ; ) {
2933
3088
  if (s.pos >= s.text.length) return fail(s, "unterminated string");
2934
3089
  const c = s.text[s.pos];
2935
3090
  advance(s);
2936
3091
  if (c === '"') {
3092
+ if (pendingHigh) {
3093
+ return fail(s, "unpaired high surrogate at the end of a string");
3094
+ }
2937
3095
  return { ok: true, value: out };
2938
3096
  }
2939
- if (out.length > schema.MAX_STRING_LENGTH) {
2940
- return failLimit(
2941
- s,
2942
- `string is longer than the wire limit MAX_STRING_LENGTH = ${schema.MAX_STRING_LENGTH}`
2943
- );
2944
- }
2945
3097
  if (c === "\\") {
2946
3098
  if (s.pos >= s.text.length) return fail(s, "unterminated escape");
2947
3099
  const esc = s.text[s.pos];
2948
3100
  advance(s);
3101
+ let unit;
2949
3102
  switch (esc) {
2950
3103
  case '"':
2951
- out += '"';
3104
+ unit = '"';
2952
3105
  break;
2953
3106
  case "\\":
2954
- out += "\\";
3107
+ unit = "\\";
2955
3108
  break;
2956
3109
  case "/":
2957
- out += "/";
3110
+ unit = "/";
2958
3111
  break;
2959
3112
  case "b":
2960
- out += "\b";
3113
+ unit = "\b";
2961
3114
  break;
2962
3115
  case "f":
2963
- out += "\f";
3116
+ unit = "\f";
2964
3117
  break;
2965
3118
  case "n":
2966
- out += "\n";
3119
+ unit = "\n";
2967
3120
  break;
2968
3121
  case "r":
2969
- out += "\r";
3122
+ unit = "\r";
2970
3123
  break;
2971
3124
  case "t":
2972
- out += " ";
3125
+ unit = " ";
2973
3126
  break;
2974
3127
  case "u": {
2975
3128
  if (s.pos + 4 > s.text.length) return fail(s, "incomplete \\u escape");
@@ -2978,26 +3131,58 @@ var parseStringRaw = (s) => {
2978
3131
  return fail(s, `invalid \\u escape '${hex}'`);
2979
3132
  }
2980
3133
  s.pos += 4;
2981
- out += String.fromCharCode(parseInt(hex, 16));
3134
+ unit = String.fromCharCode(parseInt(hex, 16));
2982
3135
  break;
2983
3136
  }
2984
3137
  default:
2985
3138
  return fail(s, `unknown escape '\\${esc}'`);
2986
3139
  }
3140
+ const bad = append(unit);
3141
+ if (bad) return { ok: false, error: bad };
3142
+ } else if (c.charCodeAt(0) < 32) {
3143
+ return fail(
3144
+ s,
3145
+ `raw control character U+${c.charCodeAt(0).toString(16).padStart(4, "0").toUpperCase()} in a string must be escaped`
3146
+ );
2987
3147
  } else {
2988
- out += c;
3148
+ const bad = append(c);
3149
+ if (bad) return { ok: false, error: bad };
2989
3150
  }
2990
3151
  }
2991
3152
  };
2992
3153
  var isNumberChar = (c) => c === "-" || c === "+" || c === "." || c === "e" || c === "E" || c >= "0" && c <= "9";
3154
+ var isRfc8259Number = (slice) => {
3155
+ const n = slice.length;
3156
+ let i = 0;
3157
+ const digit = (k) => k < n && slice[k] >= "0" && slice[k] <= "9";
3158
+ if (i < n && slice[i] === "-") i += 1;
3159
+ if (!digit(i)) return false;
3160
+ if (slice[i] === "0") {
3161
+ i += 1;
3162
+ } else {
3163
+ while (digit(i)) i += 1;
3164
+ }
3165
+ if (i < n && slice[i] === ".") {
3166
+ i += 1;
3167
+ if (!digit(i)) return false;
3168
+ while (digit(i)) i += 1;
3169
+ }
3170
+ if (i < n && (slice[i] === "e" || slice[i] === "E")) {
3171
+ i += 1;
3172
+ if (i < n && (slice[i] === "+" || slice[i] === "-")) i += 1;
3173
+ if (!digit(i)) return false;
3174
+ while (digit(i)) i += 1;
3175
+ }
3176
+ return i === n;
3177
+ };
2993
3178
  var parseNumberRaw = (s) => {
2994
3179
  const start = s.pos;
2995
3180
  while (s.pos < s.text.length && isNumberChar(s.text[s.pos])) {
2996
3181
  advance(s);
2997
3182
  }
2998
3183
  const slice = s.text.substring(start, s.pos);
2999
- if (slice.length === 0) {
3000
- return fail(s, `invalid number '${slice}'`);
3184
+ if (!isRfc8259Number(slice)) {
3185
+ return fail(s, `'${slice}' is not a JSON number (RFC 8259 grammar)`);
3001
3186
  }
3002
3187
  const n = Number(slice);
3003
3188
  if (Number.isNaN(n)) {
@@ -3084,6 +3269,10 @@ var parseObjectValue = (s) => {
3084
3269
  `object has more members than the wire limit MAX_ARRAY_LENGTH = ${schema.MAX_ARRAY_LENGTH}`
3085
3270
  );
3086
3271
  }
3272
+ if (fields.has(keyR.value)) {
3273
+ s.depth -= 1;
3274
+ return fail(s, `duplicate object member '${keyR.value}'`);
3275
+ }
3087
3276
  fields.set(keyR.value, valR.value);
3088
3277
  skipWs(s);
3089
3278
  const c = peek(s);
@@ -3143,13 +3332,52 @@ var parseArrayValue = (s) => {
3143
3332
  }
3144
3333
  }
3145
3334
  };
3335
+ var documentBytes = (input) => {
3336
+ if (input.length > schema.MAX_DOCUMENT_BYTES) return input.length;
3337
+ if (input.length <= schema.MAX_DOCUMENT_BYTES / 3) return input.length;
3338
+ let total = 0;
3339
+ for (let i = 0; i < input.length; i += 1) {
3340
+ const c = input.charCodeAt(i);
3341
+ if (c < 128) {
3342
+ total += 1;
3343
+ } else if (c < 2048) {
3344
+ total += 2;
3345
+ } else if (c >= HIGH_SURROGATE_FIRST && c <= HIGH_SURROGATE_LAST && i + 1 < input.length) {
3346
+ total += 4;
3347
+ i += 1;
3348
+ } else {
3349
+ total += 3;
3350
+ }
3351
+ }
3352
+ return total;
3353
+ };
3146
3354
  var parse = (input) => {
3355
+ const bytes = documentBytes(input);
3356
+ if (bytes > schema.MAX_DOCUMENT_BYTES) {
3357
+ return {
3358
+ ok: false,
3359
+ error: {
3360
+ message: `document of ${bytes} UTF-8 bytes exceeds the wire limit MAX_DOCUMENT_BYTES = ${schema.MAX_DOCUMENT_BYTES}`,
3361
+ offset: 0,
3362
+ limit: true
3363
+ }
3364
+ };
3365
+ }
3147
3366
  const s = { text: input, pos: 0, depth: 0 };
3148
3367
  skipWs(s);
3149
3368
  if (s.pos >= s.text.length) {
3150
3369
  return { ok: false, error: { message: "input is empty", offset: 0 } };
3151
3370
  }
3152
- return parseValue(s);
3371
+ const value = parseValue(s);
3372
+ if (!value.ok) return value;
3373
+ skipWs(s);
3374
+ if (s.pos < s.text.length) {
3375
+ return fail(
3376
+ s,
3377
+ `unexpected content after the root value ('${s.text[s.pos]}'); a wire artefact is a single JSON document`
3378
+ );
3379
+ }
3380
+ return value;
3153
3381
  };
3154
3382
  var field = (fields, key) => fields.get(key);
3155
3383
 
@@ -3194,9 +3422,31 @@ var requireFloat = (path, jRaw) => {
3194
3422
  }
3195
3423
  return wrongType(path, "JSON number (or 'NaN' / 'Infinity' / '-Infinity' sentinel string)");
3196
3424
  };
3425
+ var INT32_MIN = -2147483648;
3426
+ var INT32_MAX = 2147483647;
3427
+ var isInt32Slot = (n) => Number.isFinite(n) && Number.isInteger(n) && n >= INT32_MIN && n <= INT32_MAX;
3197
3428
  var requireInt = (path, jRaw) => {
3198
3429
  const j = unwrapStaticEnvelope(jRaw);
3199
- return j.kind === "JNumber" ? ok(Math.trunc(j.value)) : wrongType(path, "JSON number (integer)");
3430
+ if (j.kind !== "JNumber") return wrongType(path, "JSON number (integer)");
3431
+ if (!Number.isFinite(j.value)) {
3432
+ return wrongType(
3433
+ path,
3434
+ "JSON number (a finite 32-bit integer; the non-finite sentinels are a float slot's, not an integer slot's)"
3435
+ );
3436
+ }
3437
+ if (!Number.isInteger(j.value)) {
3438
+ return wrongType(
3439
+ path,
3440
+ "JSON number (a 32-bit integer; a fractional value is not truncated at an integer slot)"
3441
+ );
3442
+ }
3443
+ if (!isInt32Slot(j.value)) {
3444
+ return wrongType(
3445
+ path,
3446
+ "JSON number (a 32-bit integer; the value is outside the range this slot can hold)"
3447
+ );
3448
+ }
3449
+ return ok(j.value);
3200
3450
  };
3201
3451
  var requireArray = (path, j) => j.kind === "JArray" ? ok(j.items) : wrongType(path, "JSON array");
3202
3452
  var tryField = (fields, key) => fields.get(key);
@@ -3355,6 +3605,7 @@ var decodeHeadingVariant = (p, j) => {
3355
3605
  var decodeImageVariant = (p, j) => bareEnum(p, j, ["Default", "Avatar", "Rounded"], "ImageVariant");
3356
3606
  var decodeImageFit = (p, j) => bareEnum(p, j, ["Natural", "Cover", "Contain"], "ImageFit");
3357
3607
  var decodeModalityKind = (p, j) => bareEnum(p, j, ["Modal", "Popover"], "ModalityKind");
3608
+ var decodeNavigateTarget = (p, j) => bareEnum(p, j, ["Self", "Blank"], "NavigateTarget");
3358
3609
  var decodeImageAspect = (p, j) => bareEnum(
3359
3610
  p,
3360
3611
  j,
@@ -3432,6 +3683,149 @@ var decodeChartKind = (p, j) => bareEnum(p, j, ["Line", "Bar", "Area", "Pie", "S
3432
3683
  var decodeChartLegendPosition = (p, j) => bareEnum(p, j, ["Top", "Right", "Bottom", "None"], "ChartLegendPosition");
3433
3684
  var decodeChartDataLabels = (p, j) => bareEnum(p, j, ["Off", "Ends"], "ChartDataLabels");
3434
3685
  var decodeChartXScale = (p, j) => bareEnum(p, j, ["Category", "Temporal"], "ChartXScale");
3686
+ var annotationIsLeapYear = (y) => y % 4 === 0 && y % 100 !== 0 || y % 400 === 0;
3687
+ var annotationDaysInMonth = (y, m) => m === 2 ? annotationIsLeapYear(y) ? 29 : 28 : m === 4 || m === 6 || m === 9 || m === 11 ? 30 : 31;
3688
+ var isCanonicalIsoDay = (text) => {
3689
+ if (text.length < 10) return false;
3690
+ if (text[4] !== "-" || text[7] !== "-") return false;
3691
+ if (text.length > 10 && text[10] !== "T") return false;
3692
+ const digits = (start, len) => {
3693
+ let acc = 0;
3694
+ for (let k = start; k < start + len; k += 1) {
3695
+ const c = text.charCodeAt(k);
3696
+ if (c < 48 || c > 57) return void 0;
3697
+ acc = acc * 10 + (c - 48);
3698
+ }
3699
+ return acc;
3700
+ };
3701
+ const y = digits(0, 4);
3702
+ const m = digits(5, 2);
3703
+ const d = digits(8, 2);
3704
+ if (y === void 0 || m === void 0 || d === void 0) return false;
3705
+ return m >= 1 && m <= 12 && d >= 1 && d <= annotationDaysInMonth(y, m);
3706
+ };
3707
+ var decodeChartAnnotationX = (path, j) => {
3708
+ const fo = requireObject(path, j);
3709
+ if (!fo.ok) return fo;
3710
+ const f = fo.value;
3711
+ const disc = requireDiscriminator(path, f);
3712
+ if (!disc.ok) return disc;
3713
+ switch (disc.value) {
3714
+ case "Category": {
3715
+ const key = reqField(path, f, "key", "category key (the band's own label)", requireString);
3716
+ if (!key.ok) return key;
3717
+ return ok({ kind: "Category", key: key.value });
3718
+ }
3719
+ case "Date": {
3720
+ const iso = reqField(path, f, "iso", "ISO-8601 date (YYYY-MM-DD)", requireString);
3721
+ if (!iso.ok) return iso;
3722
+ if (!isCanonicalIsoDay(iso.value))
3723
+ return wrongType(
3724
+ `${path}.iso`,
3725
+ "a canonical ISO-8601 date (YYYY-MM-DD, optionally followed by a time) naming a real calendar day \u2014 an event marker\u2019s date is the address it is drawn at, and an unreadable one would place the marker at 1970-01-01 and drag the axis back with it"
3726
+ );
3727
+ return ok({ kind: "Date", iso: iso.value });
3728
+ }
3729
+ default:
3730
+ return unknownDuCase(path, disc.value, "Category, Date");
3731
+ }
3732
+ };
3733
+ var decodeChartAnnotationRange = (path, j) => {
3734
+ const finite = (slot, v) => {
3735
+ const r = requireFloat(`${path}.${slot}`, v);
3736
+ if (!r.ok) return r;
3737
+ return Number.isFinite(r.value) ? r : wrongType(
3738
+ `${path}.${slot}`,
3739
+ "a FINITE JSON number \u2014 a range band's end names a place on the value axis, and NaN / Infinity names none; give the value in the axis's own units, or drop the annotation"
3740
+ );
3741
+ };
3742
+ const fo = requireObject(path, j);
3743
+ if (!fo.ok) return fo;
3744
+ const f = fo.value;
3745
+ const disc = requireDiscriminator(path, f);
3746
+ if (!disc.ok) return disc;
3747
+ switch (disc.value) {
3748
+ case "ValueRange": {
3749
+ const fromJ = requireField(path, f, "from", "range-band lower value (a finite JSON number)");
3750
+ if (!fromJ.ok) return fromJ;
3751
+ const from = finite("from", fromJ.value);
3752
+ if (!from.ok) return from;
3753
+ const toJ = requireField(path, f, "to", "range-band upper value (a finite JSON number)");
3754
+ if (!toJ.ok) return toJ;
3755
+ const to = finite("to", toJ.value);
3756
+ if (!to.ok) return to;
3757
+ if (from.value > to.value)
3758
+ return wrongType(
3759
+ path,
3760
+ "an ORDERED pair \u2014 a range band runs from its lower value to its upper one, and this pair runs backwards; swapping the ends silently would draw a band the author did not describe"
3761
+ );
3762
+ return ok({ kind: "ValueRange", from: from.value, to: to.value });
3763
+ }
3764
+ case "XRange": {
3765
+ const fromJ = requireField(
3766
+ path,
3767
+ f,
3768
+ "from",
3769
+ "range-band lower x address (a ChartAnnotationX)"
3770
+ );
3771
+ if (!fromJ.ok) return fromJ;
3772
+ const from = decodeChartAnnotationX(`${path}.from`, fromJ.value);
3773
+ if (!from.ok) return from;
3774
+ const toJ = requireField(path, f, "to", "range-band upper x address (a ChartAnnotationX)");
3775
+ if (!toJ.ok) return toJ;
3776
+ const to = decodeChartAnnotationX(`${path}.to`, toJ.value);
3777
+ if (!to.ok) return to;
3778
+ if (from.value.kind === "Date" && to.value.kind === "Date" && from.value.iso > to.value.iso)
3779
+ return wrongType(
3780
+ path,
3781
+ "an ORDERED pair \u2014 a range band runs from its earlier date to its later one, and this pair runs backwards; swapping the ends silently would draw a band the author did not describe"
3782
+ );
3783
+ return ok({ kind: "XRange", from: from.value, to: to.value });
3784
+ }
3785
+ default:
3786
+ return unknownDuCase(path, disc.value, "ValueRange, XRange");
3787
+ }
3788
+ };
3789
+ var decodeChartAnnotation = (path, j) => {
3790
+ const fo = requireObject(path, j);
3791
+ if (!fo.ok) return fo;
3792
+ const f = fo.value;
3793
+ const disc = requireDiscriminator(path, f);
3794
+ if (!disc.ok) return disc;
3795
+ const label = optField(path, f, "label", decodeTextSource);
3796
+ if (!label.ok) return label;
3797
+ const withLabel = label.value !== void 0 ? { label: label.value } : {};
3798
+ switch (disc.value) {
3799
+ case "ReferenceLine": {
3800
+ const valueJ = requireField(path, f, "value", "reference-line value (a finite JSON number)");
3801
+ if (!valueJ.ok) return valueJ;
3802
+ const value = requireFloat(`${path}.value`, valueJ.value);
3803
+ if (!value.ok) return value;
3804
+ if (!Number.isFinite(value.value))
3805
+ return wrongType(
3806
+ `${path}.value`,
3807
+ "a FINITE JSON number \u2014 a reference line names a place on the value axis, and NaN / Infinity names none; give the value in the axis's own units, or drop the annotation"
3808
+ );
3809
+ return ok({ kind: "ReferenceLine", value: value.value, ...withLabel });
3810
+ }
3811
+ case "EventMarker": {
3812
+ const atJ = requireField(path, f, "at", "event-marker x address (a ChartAnnotationX)");
3813
+ if (!atJ.ok) return atJ;
3814
+ const at = decodeChartAnnotationX(`${path}.at`, atJ.value);
3815
+ if (!at.ok) return at;
3816
+ return ok({ kind: "EventMarker", at: at.value, ...withLabel });
3817
+ }
3818
+ case "RangeBand": {
3819
+ const rangeJ = requireField(path, f, "range", "range-band pair (a ChartAnnotationRange)");
3820
+ if (!rangeJ.ok) return rangeJ;
3821
+ const range = decodeChartAnnotationRange(`${path}.range`, rangeJ.value);
3822
+ if (!range.ok) return range;
3823
+ return ok({ kind: "RangeBand", range: range.value, ...withLabel });
3824
+ }
3825
+ default:
3826
+ return unknownDuCase(path, disc.value, "ReferenceLine, EventMarker, RangeBand");
3827
+ }
3828
+ };
3435
3829
  var decodeFileReadEncoding = (p, j) => bareEnum(p, j, ["Text", "Base64", "DataUrl"], "FileReadEncoding");
3436
3830
  var decodeAriaRole = (p, j) => {
3437
3831
  if (j.kind !== "JString") return wrongType(p, "JSON string (ARIA role)");
@@ -3446,6 +3840,7 @@ var decodeRelativeTimeUnit = (p, j) => bareEnum(
3446
3840
  ["Second", "Minute", "Hour", "Day", "Week", "Month", "Year"],
3447
3841
  "RelativeTimeUnit"
3448
3842
  );
3843
+ var decodeTimeGrain = (p, j) => bareEnum(p, j, ["Second", "Minute", "Hour", "Day"], "TimeGrain");
3449
3844
  var decodeCellFormat = (path, j) => {
3450
3845
  const fo = requireObject(path, j);
3451
3846
  if (!fo.ok) return fo;
@@ -3545,11 +3940,17 @@ var decodeFormat = (path, j) => {
3545
3940
  if (!style.ok) return style;
3546
3941
  return ok({ kind: "Duration", unit: unit.value, style: style.value });
3547
3942
  }
3943
+ case "Since": {
3944
+ const u = tryField(f, "unit");
3945
+ if (u === void 0) return ok({ kind: "Since" });
3946
+ const r = decodeRelativeTimeUnit(`${path}.unit`, u);
3947
+ return r.ok ? ok({ kind: "Since", unit: r.value }) : r;
3948
+ }
3548
3949
  default:
3549
3950
  return unknownDuCase(
3550
3951
  path,
3551
3952
  d.value,
3552
- "Number | Currency | Percent | Date | RelativeTime | Duration"
3953
+ "Number | Currency | Percent | Date | RelativeTime | Duration | Since"
3553
3954
  );
3554
3955
  }
3555
3956
  };
@@ -3703,7 +4104,13 @@ var cFieldAliased = (f, canonical, alias) => {
3703
4104
  };
3704
4105
  var cStr = (j) => j.kind === "JString" ? cok(j.value) : cerr("malformed: expected string, got " + astKind(j));
3705
4106
  var cArr = (j) => j.kind === "JArray" ? cok(j.items) : cerr("malformed: expected array, got " + astKind(j));
3706
- var cInt = (j) => j.kind === "JNumber" ? cok(Math.trunc(j.value)) : cerr("malformed: expected int, got " + astKind(j));
4107
+ var cInt = (j) => {
4108
+ if (j.kind !== "JNumber") return cerr("malformed: expected int, got " + astKind(j));
4109
+ if (!isInt32Slot(j.value)) {
4110
+ return cerr(`malformed: expected a 32-bit integer, got ${j.value}`);
4111
+ }
4112
+ return cok(j.value);
4113
+ };
3707
4114
  var cMapM = (xs, fn) => {
3708
4115
  const out = [];
3709
4116
  for (const x of xs) {
@@ -3734,7 +4141,7 @@ var decodeCellLit = (j) => {
3734
4141
  if (v === void 0) return mismatch;
3735
4142
  switch (t) {
3736
4143
  case "Int":
3737
- return v.kind === "JNumber" ? cok({ kind: "Int", value: Math.trunc(v.value) }) : mismatch;
4144
+ return v.kind === "JNumber" && isInt32Slot(v.value) ? cok({ kind: "Int", value: v.value }) : mismatch;
3738
4145
  case "Float":
3739
4146
  return v.kind === "JNumber" ? cok({ kind: "Float", value: v.value }) : mismatch;
3740
4147
  case "Bool":
@@ -4437,6 +4844,137 @@ var decodeInvokeArgs = (path, j) => {
4437
4844
  return ok({ addr: addr.value, value: value.value });
4438
4845
  });
4439
4846
  };
4847
+ var exprAdmissible = (root) => {
4848
+ let count = 0;
4849
+ let sawCol = false;
4850
+ const walk = (e) => {
4851
+ count += 1;
4852
+ if (sawCol || count > schema.MAX_EXPR_NODES) return;
4853
+ switch (e.kind) {
4854
+ case "col":
4855
+ sawCol = true;
4856
+ return;
4857
+ case "lit":
4858
+ case "param":
4859
+ return;
4860
+ case "binary":
4861
+ walk(e.left);
4862
+ walk(e.right);
4863
+ return;
4864
+ case "not":
4865
+ case "cast":
4866
+ case "isNull":
4867
+ walk(e.expr);
4868
+ return;
4869
+ case "coalesce":
4870
+ e.exprs.forEach(walk);
4871
+ return;
4872
+ case "apply":
4873
+ e.args.forEach(walk);
4874
+ return;
4875
+ case "case":
4876
+ for (const c of e.cases) {
4877
+ walk(c.when);
4878
+ walk(c.then);
4879
+ }
4880
+ walk(e.else);
4881
+ return;
4882
+ case "in":
4883
+ walk(e.expr);
4884
+ e.items.forEach(walk);
4885
+ return;
4886
+ case "inParam":
4887
+ walk(e.expr);
4888
+ return;
4889
+ }
4890
+ };
4891
+ walk(root);
4892
+ if (sawCol) return "col";
4893
+ if (count > schema.MAX_EXPR_NODES) return "limit";
4894
+ return "ok";
4895
+ };
4896
+ var colExprParamNames = (root) => {
4897
+ const seen = [];
4898
+ const push = (n) => {
4899
+ if (!seen.includes(n)) seen.push(n);
4900
+ };
4901
+ const walk = (e) => {
4902
+ switch (e.kind) {
4903
+ case "col":
4904
+ case "lit":
4905
+ return;
4906
+ case "param":
4907
+ push(e.name);
4908
+ return;
4909
+ case "binary":
4910
+ walk(e.left);
4911
+ walk(e.right);
4912
+ return;
4913
+ case "not":
4914
+ case "cast":
4915
+ case "isNull":
4916
+ walk(e.expr);
4917
+ return;
4918
+ case "coalesce":
4919
+ e.exprs.forEach(walk);
4920
+ return;
4921
+ case "apply":
4922
+ e.args.forEach(walk);
4923
+ return;
4924
+ case "case":
4925
+ for (const c of e.cases) {
4926
+ walk(c.when);
4927
+ walk(c.then);
4928
+ }
4929
+ walk(e.else);
4930
+ return;
4931
+ case "in":
4932
+ walk(e.expr);
4933
+ e.items.forEach(walk);
4934
+ return;
4935
+ case "inParam":
4936
+ walk(e.expr);
4937
+ push(e.param);
4938
+ return;
4939
+ }
4940
+ };
4941
+ walk(root);
4942
+ return seen;
4943
+ };
4944
+ var decodeExprParams = (path, f) => {
4945
+ const paramsField = tryField(f, "params");
4946
+ if (paramsField === void 0) return ok(void 0);
4947
+ if (paramsField.kind === "JObject") {
4948
+ const entries = [...paramsField.fields.entries()].sort(
4949
+ ([a], [b]) => a < b ? -1 : a > b ? 1 : 0
4950
+ );
4951
+ const out = [];
4952
+ for (const [name, v] of entries) {
4953
+ const from = decodeBinding(`${path}.params.${name}.from`, v);
4954
+ if (!from.ok) return from;
4955
+ out.push({ name, from: from.value });
4956
+ }
4957
+ return ok(out);
4958
+ }
4959
+ const arr = requireArray(`${path}.params`, paramsField);
4960
+ if (!arr.ok) return arr;
4961
+ return traverseIndexed(arr.value, (_i, el) => {
4962
+ const po = requireObject(`${path}.params[]`, el);
4963
+ if (!po.ok) return po;
4964
+ const name = reqField(`${path}.params[]`, po.value, "name", "param name string", requireString);
4965
+ if (!name.ok) return name;
4966
+ const from = reqFieldAliased(
4967
+ `${path}.params[]`,
4968
+ po.value,
4969
+ "from",
4970
+ ["value"],
4971
+ "param source Binding",
4972
+ decodeBinding
4973
+ );
4974
+ if (!from.ok) return from;
4975
+ return ok({ name: name.value, from: from.value });
4976
+ });
4977
+ };
4440
4978
  var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), placeholder = OPAQUE2) => {
4441
4979
  if (j.kind === "JArray" || j.kind === "JString" || j.kind === "JNumber" || j.kind === "JBool") {
4442
4980
  const parsed = parseStatic(path, j);
@@ -4535,14 +5073,23 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4535
5073
  return ok({ kind: "State", key: key.value, defaultValue });
4536
5074
  }
4537
5075
  case "Computed":
4538
- return ok({ kind: "Computed", compute: () => void 0 });
5076
+ return ok({
5077
+ kind: "Computed",
5078
+ compute: () => {
5079
+ throw new WireSurvivabilityError(DECODED_COMPUTED_MESSAGE);
5080
+ }
5081
+ });
4539
5082
  // The projection decodes to the IDENTITY (the Phase 427 Selection fix
4540
5083
  // replayed): the host-furnished instant is already the wire-shaped string,
4541
5084
  // so a decoded reader receives it as-is. A value-discarding placeholder
4542
5085
  // here would make every decoded `Now` resolve to nothing even when the
4543
5086
  // host furnishes the instant.
4544
- case "Now":
4545
- return ok({ kind: "Now", project: (iso) => iso });
5087
+ case "Now": {
5088
+ const g = tryField(f, "grain");
5089
+ if (g === void 0) return ok({ kind: "Now", project: (iso) => iso });
5090
+ const r = decodeTimeGrain(`${path}.grain`, g);
5091
+ return r.ok ? ok({ kind: "Now", project: (iso) => iso, grain: r.value }) : r;
5092
+ }
4546
5093
  case "I18n": {
4547
5094
  const key = reqField(path, f, "key", "i18n key string", requireString);
4548
5095
  if (!key.ok) return key;
@@ -4557,6 +5104,37 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4557
5104
  return ok(b);
4558
5105
  }
4559
5106
  case "Local": {
5107
+ const codecJ = tryField(f, "codec");
5108
+ let codec;
5109
+ if (codecJ !== void 0) {
5110
+ const c = decodeFormat(`${path}.codec`, codecJ);
5111
+ if (!c.ok) return c;
5112
+ if (c.value.kind !== "Number") {
5113
+ return makeError(
5114
+ "WRONG_TYPE",
5115
+ `${path}.codec`,
5116
+ "Binding.Local 'codec' must be a Format case with a total, locale-independent inverse \u2014 only 'Number' has one",
5117
+ 'use {"$type":"Number","decimals":2}, or drop the codec and let the buffer use the identity; a locale-rendered format (Currency / Date / RelativeTime / Since / Duration) cannot be parsed back from what the reader typed'
5118
+ );
5119
+ }
5120
+ codec = c.value;
5121
+ }
5122
+ const onCommitPresent = tryField(f, "onCommit") !== void 0;
5123
+ const commitToJ = tryField(f, "commitTo");
5124
+ let commitTo;
5125
+ if (commitToJ !== void 0) {
5126
+ if (onCommitPresent) {
5127
+ return makeError(
5128
+ "WRONG_TYPE",
5129
+ `${path}.commitTo`,
5130
+ "Binding.Local carries both 'onCommit' and 'commitTo' \u2014 exactly one commit destination is allowed",
5131
+ "either onCommit (a host closure, which crosses the wire only as the closure sentinel) or commitTo (the State key the flush writes); a decoding host can honour only the second, so keeping both makes the same document commit to two different places depending on who read it"
5132
+ );
5133
+ }
5134
+ const ct = requireString(`${path}.commitTo`, commitToJ);
5135
+ if (!ct.ok) return ct;
5136
+ commitTo = ct.value;
5137
+ }
4560
5138
  const initial = reqField(
4561
5139
  path,
4562
5140
  f,
@@ -4568,15 +5146,35 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4568
5146
  const flushJ = tryField(f, "flushOn");
4569
5147
  const flush = flushJ === void 0 ? ok({ kind: "OnBlur" }) : decodeLocalFlushTrigger(`${path}.flushOn`, flushJ);
4570
5148
  if (!flush.ok) return flush;
4571
- const b = {
4572
- kind: "Local",
4573
- local: {
4574
- initialFrom: initial.value,
4575
- flushOn: flush.value,
4576
- onCommit: () => void 0,
4577
- parse: () => ({ ok: false, error: CLOSURE2 })
4578
- }
5149
+ const refusalOf = (raw) => `Binding.Local: '${raw}' is not a value this field accepts`;
5150
+ const identityParse = (raw) => {
5151
+ const asText = parseStatic(`${path}.parse`, { kind: "JString", value: raw });
5152
+ if (asText.ok) return { ok: true, value: asText.value };
5153
+ const scalar = scalarOfText(raw);
5154
+ if (scalar === void 0) return { ok: false, error: refusalOf(raw) };
5155
+ const asScalar = parseStatic(
5156
+ `${path}.parse`,
5157
+ typeof scalar === "number" ? { kind: "JNumber", value: scalar } : { kind: "JBool", value: scalar }
5158
+ );
5159
+ return asScalar.ok ? { ok: true, value: asScalar.value } : { ok: false, error: refusalOf(raw) };
4579
5160
  };
5161
+ const decimals = codec !== void 0 && codec.kind === "Number" ? codec.decimals : void 0;
5162
+ const codecParse = (raw) => {
5163
+ const n = tryNumberText(raw);
5164
+ if (n === void 0) return { ok: false, error: refusalOf(raw) };
5165
+ const parsed = parseStatic(`${path}.parse`, { kind: "JNumber", value: n });
5166
+ return parsed.ok ? { ok: true, value: parsed.value } : { ok: false, error: refusalOf(raw) };
5167
+ };
5168
+ const local = {
5169
+ initialFrom: initial.value,
5170
+ flushOn: flush.value,
5171
+ format: codec !== void 0 ? (v) => numberText(decimals, v) : (v) => identityFormat(v),
5172
+ parse: codec !== void 0 ? codecParse : identityParse,
5173
+ ...onCommitPresent ? { onCommit: () => void 0 } : {},
5174
+ ...codec !== void 0 ? { codec } : {},
5175
+ ...commitTo !== void 0 ? { commitTo } : {}
5176
+ };
5177
+ const b = { kind: "Local", local };
4580
5178
  return ok(b);
4581
5179
  }
4582
5180
  case "Format": {
@@ -4648,52 +5246,9 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4648
5246
  }
4649
5247
  const pipe = decodePipelineCore(pipeJ.value);
4650
5248
  if (!pipe.ok) return makeError("WRONG_TYPE", `${path}.pipeline`, pipe.error);
4651
- const paramsField = tryField(f, "params");
4652
- let params;
4653
- if (paramsField !== void 0 && paramsField.kind === "JObject") {
4654
- const entries = [...paramsField.fields.entries()].sort(
4655
- ([a], [b2]) => a < b2 ? -1 : a > b2 ? 1 : 0
4656
- );
4657
- const out = [];
4658
- let coerceErr;
4659
- for (const [name, v] of entries) {
4660
- const from = decodeBinding(`${path}.params.${name}.from`, v);
4661
- if (!from.ok) {
4662
- coerceErr = from;
4663
- break;
4664
- }
4665
- out.push({ name, from: from.value });
4666
- }
4667
- if (coerceErr !== void 0) return coerceErr;
4668
- params = out;
4669
- } else if (paramsField !== void 0) {
4670
- const arr = requireArray(`${path}.params`, paramsField);
4671
- if (!arr.ok) return arr;
4672
- const decoded = traverseIndexed(arr.value, (_i, el) => {
4673
- const po = requireObject(`${path}.params[]`, el);
4674
- if (!po.ok) return po;
4675
- const name = reqField(
4676
- `${path}.params[]`,
4677
- po.value,
4678
- "name",
4679
- "param name string",
4680
- requireString
4681
- );
4682
- if (!name.ok) return name;
4683
- const from = reqFieldAliased(
4684
- `${path}.params[]`,
4685
- po.value,
4686
- "from",
4687
- ["value"],
4688
- "param source Binding",
4689
- decodeBinding
4690
- );
4691
- if (!from.ok) return from;
4692
- return ok({ name: name.value, from: from.value });
4693
- });
4694
- if (!decoded.ok) return decoded;
4695
- params = decoded.value;
4696
- }
5249
+ const paramsR = decodeExprParams(path, f);
5250
+ if (!paramsR.ok) return paramsR;
5251
+ const params = paramsR.value;
4697
5252
  const b = {
4698
5253
  kind: "Transform",
4699
5254
  source,
@@ -4702,6 +5257,47 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4702
5257
  };
4703
5258
  return ok(b);
4704
5259
  }
5260
+ case "Expr": {
5261
+ const exprJ = requireField(path, f, "expr", "ColExpr object");
5262
+ if (!exprJ.ok) return exprJ;
5263
+ const expr = decodeColExprCore(exprJ.value);
5264
+ if (!expr.ok) return makeError("WRONG_TYPE", `${path}.expr`, expr.error);
5265
+ const verdict = exprAdmissible(expr.value);
5266
+ if (verdict === "col") {
5267
+ return makeError(
5268
+ "WRONG_TYPE",
5269
+ `${path}.expr`,
5270
+ "a `col` reference is not admitted inside an Expr binding \u2014 an Expr evaluates against its params alone and has no row for a column name to read. Use `Binding.Transform`, whose source supplies the frame, and put the column expression in a `derive` step",
5271
+ "a ColExpr over `param` / `lit` / operators only (no `col`)"
5272
+ );
5273
+ }
5274
+ if (verdict === "limit") {
5275
+ return makeError(
5276
+ "LIMIT_EXCEEDED",
5277
+ `${path}.expr`,
5278
+ `expression exceeds the maximum of ${schema.MAX_EXPR_NODES} expression nodes (WIRE_FORMAT 21)`,
5279
+ `at most ${schema.MAX_EXPR_NODES} ColExpr nodes in one Expr binding`
5280
+ );
5281
+ }
5282
+ const exprParams = decodeExprParams(path, f);
5283
+ if (!exprParams.ok) return exprParams;
5284
+ const bound = new Set((exprParams.value ?? []).map((p) => p.name));
5285
+ const missing = colExprParamNames(expr.value).filter((n) => !bound.has(n));
5286
+ if (missing.length > 0) {
5287
+ return makeError(
5288
+ "WRONG_TYPE",
5289
+ `${path}.expr`,
5290
+ `the expression reads param(s) ${missing.map((n) => `'${n}'`).join(", ")} that this binding's \`params\` does not bind \u2014 an Expr has no rows and no filter to prune, so an unbound param has no value to take; add a params entry naming each, or drop the reference`,
5291
+ '{"$type":"Expr","expr":{\u2026},"params":[{"name":"<name>","from":<Binding>}]}'
5292
+ );
5293
+ }
5294
+ const b = {
5295
+ kind: "Expr",
5296
+ expr: expr.value,
5297
+ ...exprParams.value !== void 0 ? { params: exprParams.value } : {}
5298
+ };
5299
+ return ok(b);
5300
+ }
4705
5301
  case "Invoke": {
4706
5302
  const cid = reqField(path, f, "capabilityId", "capability id string", requireString);
4707
5303
  if (!cid.ok) return cid;
@@ -5045,10 +5641,14 @@ var decodeAction = (path, j) => {
5045
5641
  f,
5046
5642
  "route",
5047
5643
  ["href", "url", "to"],
5048
- "route string",
5049
- requireString
5644
+ "route TextSource",
5645
+ decodeTextSource
5050
5646
  );
5051
- return r.ok ? ok({ kind: "Navigate", route: r.value }) : r;
5647
+ if (!r.ok) return r;
5648
+ const targetJ = tryField(f, "target");
5649
+ const target = targetJ === void 0 ? ok("Self") : decodeNavigateTarget(`${path}.target`, targetJ);
5650
+ if (!target.ok) return target;
5651
+ return ok({ kind: "Navigate", route: r.value, target: target.value });
5052
5652
  }
5053
5653
  case "SetState": {
5054
5654
  const key = reqField(path, f, "key", "state key string", requireString);
@@ -5118,6 +5718,51 @@ var decodeAction = (path, j) => {
5118
5718
  }
5119
5719
  return ok({ kind: "Print" });
5120
5720
  }
5721
+ case "Confirm": {
5722
+ const nestedConfirmPath = (p, a) => {
5723
+ if (a.kind === "Confirm") return p;
5724
+ if (a.kind === "Chain") {
5725
+ for (let i = 0; i < a.actions.length; i++) {
5726
+ const found = nestedConfirmPath(`${p}.ops[${i}]`, a.actions[i]);
5727
+ if (found !== void 0) return found;
5728
+ }
5729
+ }
5730
+ return void 0;
5731
+ };
5732
+ const prompt = reqField(path, f, "prompt", "confirm prompt TextSource", decodeTextSource);
5733
+ if (!prompt.ok) return prompt;
5734
+ const confirmJ = requireField(path, f, "onConfirm", "Action to dispatch on acceptance");
5735
+ if (!confirmJ.ok) return confirmJ;
5736
+ const onConfirm = decodeAction(`${path}.onConfirm`, confirmJ.value);
5737
+ if (!onConfirm.ok) return onConfirm;
5738
+ const nestedInConfirm = nestedConfirmPath(`${path}.onConfirm`, onConfirm.value);
5739
+ if (nestedInConfirm !== void 0)
5740
+ return wrongType(
5741
+ nestedInConfirm,
5742
+ "any action but Confirm \u2014 confirmation is bounded at one question (WIRE_FORMAT.md \xA73.6.22)"
5743
+ );
5744
+ const cancelJ = f.get("onCancel");
5745
+ if (cancelJ === void 0)
5746
+ return ok({ kind: "Confirm", prompt: prompt.value, onConfirm: onConfirm.value });
5747
+ const onCancel = decodeAction(`${path}.onCancel`, cancelJ);
5748
+ if (!onCancel.ok) return onCancel;
5749
+ const nestedInCancel = nestedConfirmPath(`${path}.onCancel`, onCancel.value);
5750
+ if (nestedInCancel !== void 0)
5751
+ return wrongType(
5752
+ nestedInCancel,
5753
+ "any action but Confirm \u2014 confirmation is bounded at one question (WIRE_FORMAT.md \xA73.6.22)"
5754
+ );
5755
+ return ok({
5756
+ kind: "Confirm",
5757
+ prompt: prompt.value,
5758
+ onConfirm: onConfirm.value,
5759
+ onCancel: onCancel.value
5760
+ });
5761
+ }
5762
+ case "Focus": {
5763
+ const r = reqField(path, f, "nodeId", "NodeId string of the node to focus", requireString);
5764
+ return r.ok ? ok({ kind: "Focus", nodeId: r.value }) : r;
5765
+ }
5121
5766
  case "ReadFileBody": {
5122
5767
  const fileId = reqField(path, f, "fileRef", "FileRef id string", requireString);
5123
5768
  if (!fileId.ok) return fileId;
@@ -7105,6 +7750,18 @@ var decodeChartSpec = (path, j) => {
7105
7750
  if (!dataLabels.ok) return dataLabels;
7106
7751
  const xScale = optField(path, f, "xScale", decodeChartXScale);
7107
7752
  if (!xScale.ok) return xScale;
7753
+ const annotationsJ = tryField(f, "annotations");
7754
+ let annotations;
7755
+ if (annotationsJ !== void 0) {
7756
+ const arr2 = requireArray(`${path}.annotations`, annotationsJ);
7757
+ if (!arr2.ok) return arr2;
7758
+ const decoded = traverseIndexed(
7759
+ arr2.value,
7760
+ (i, item) => decodeChartAnnotation(`${path}.annotations[${i}]`, item)
7761
+ );
7762
+ if (!decoded.ok) return decoded;
7763
+ annotations = decoded.value;
7764
+ }
7108
7765
  const hasPointClick = tryField(f, "onPointClick") !== void 0;
7109
7766
  const stacked = optField(path, f, "stacked", requireBool);
7110
7767
  if (!stacked.ok) return stacked;
@@ -7122,6 +7779,7 @@ var decodeChartSpec = (path, j) => {
7122
7779
  ...legendPosition.value !== void 0 ? { legendPosition: legendPosition.value } : {},
7123
7780
  ...dataLabels.value !== void 0 ? { dataLabels: dataLabels.value } : {},
7124
7781
  ...xScale.value !== void 0 ? { xScale: xScale.value } : {},
7782
+ ...annotations !== void 0 ? { annotations } : {},
7125
7783
  ...hasPointClick ? { onPointClick: () => placeholderAction } : {}
7126
7784
  });
7127
7785
  };
@@ -7820,11 +8478,29 @@ var decodeNodeKind = (path, j) => {
7820
8478
  const cp = `${path}.cases[${i}]`;
7821
8479
  const co = requireObject(cp, item);
7822
8480
  if (!co.ok) return co;
7823
- const m = reqField(cp, co.value, "match", "Switch case match string", requireString);
7824
- if (!m.ok) return m;
8481
+ const mJ = tryField(co.value, "match");
8482
+ const wJ = tryField(co.value, "when");
8483
+ if (mJ !== void 0 && wJ !== void 0)
8484
+ return wrongType(
8485
+ `${cp}.when`,
8486
+ "either 'match' (a literal string compared against the switch's `on` selector) or 'when' (a Binding<bool> predicate evaluated at render time, needing no selector); remove one"
8487
+ );
8488
+ if (mJ === void 0 && wJ === void 0)
8489
+ return missingField(
8490
+ cp,
8491
+ "match",
8492
+ "a literal string under 'match' (compared against the switch's `on` selector), or a Binding<bool> under 'when' (a predicate evaluated at render time)"
8493
+ );
7825
8494
  const c = reqField(cp, co.value, "child", "Switch case child Node", decodeNodeAst);
7826
8495
  if (!c.ok) return c;
7827
- return ok({ match: m.value, child: c.value });
8496
+ if (mJ !== void 0) {
8497
+ const m = requireString(`${cp}.match`, mJ);
8498
+ if (!m.ok) return m;
8499
+ return ok({ match: m.value, child: c.value });
8500
+ }
8501
+ const w = decodeBindingBool(`${cp}.when`, wJ);
8502
+ if (!w.ok) return w;
8503
+ return ok({ when: w.value, child: c.value });
7828
8504
  });
7829
8505
  if (!cases.ok) return cases;
7830
8506
  const def = reqField(path, f, "default", "Switch default Node", decodeNodeAst);
@@ -8170,13 +8846,16 @@ var decodeNodeAstInner = (path, j) => {
8170
8846
  if (!accessibility2.ok) return accessibility2;
8171
8847
  const tooltip = optField(path, f, "tooltip", decodeTextSource);
8172
8848
  if (!tooltip.ok) return tooltip;
8849
+ const visible = optField(path, f, "visible", decodeBindingBool);
8850
+ if (!visible.ok) return visible;
8173
8851
  return ok({
8174
8852
  id: idStr.value,
8175
8853
  kind: kind.value,
8176
8854
  state: state.value,
8177
8855
  style: style.value,
8178
8856
  ...accessibility2.value !== void 0 ? { accessibility: accessibility2.value } : {},
8179
- ...tooltip.value !== void 0 ? { tooltip: tooltip.value } : {}
8857
+ ...tooltip.value !== void 0 ? { tooltip: tooltip.value } : {},
8858
+ ...visible.value !== void 0 ? { visible: visible.value } : {}
8180
8859
  });
8181
8860
  };
8182
8861
  var decodeTreeOpAst = (path, j) => {
@@ -8385,10 +9064,238 @@ var decodeOp = (json, policy) => {
8385
9064
  resetWalk(policy);
8386
9065
  return decodeTreeOpAst("$", parsed.value);
8387
9066
  };
9067
+ var decodeOps = (json, policy) => {
9068
+ const parsed = parse(json);
9069
+ if (!parsed.ok) return parseFailure(parsed.error);
9070
+ resetWalk(policy);
9071
+ const entries = parsed.value.kind === "JArray" ? parsed.value.items : [parsed.value];
9072
+ const ops = [];
9073
+ for (let i = 0; i < entries.length; i += 1) {
9074
+ const path = parsed.value.kind === "JArray" ? `$[${i}]` : "$";
9075
+ const decoded = decodeTreeOpAst(path, entries[i]);
9076
+ if (!decoded.ok) return decoded;
9077
+ ops.push(decoded.value);
9078
+ }
9079
+ return ok(ops);
9080
+ };
9081
+
9082
+ // src/capabilityDecl.ts
9083
+ var dok2 = (value) => ({ ok: true, value });
9084
+ var derr2 = (error) => ({ ok: false, error });
9085
+ var HOST_WIRE = {
9086
+ Pure: "pure",
9087
+ ReadsHost: "readsHost",
9088
+ WritesHost: "writesHost"
9089
+ };
9090
+ var DETERMINISM_WIRE = {
9091
+ Deterministic: "deterministic",
9092
+ Clock: "clock",
9093
+ Random: "random",
9094
+ Network: "network"
9095
+ };
9096
+ var PLACEMENT_WIRE = {
9097
+ BuildTime: "buildTime",
9098
+ Server: "server",
9099
+ ClientDeclarative: "clientDeclarative",
9100
+ ClientIsland: "clientIsland",
9101
+ Precomputed: "precomputed"
9102
+ };
9103
+ var SPACE_WIRE = {
9104
+ IntRange: "intRange",
9105
+ FloatRange: "floatRange",
9106
+ StringLen: "stringLen",
9107
+ Enum: "enum",
9108
+ AnyString: "anyString"
9109
+ };
9110
+ var ISLANDS = ["pyodide", "fable", "js"];
9111
+ var invert = (m) => Object.fromEntries(Object.entries(m).map(([k, v]) => [v, k]));
9112
+ var HOST_OF = invert(HOST_WIRE);
9113
+ var DETERMINISM_OF = invert(DETERMINISM_WIRE);
9114
+ var PLACEMENT_OF = invert(PLACEMENT_WIRE);
9115
+ var SPACE_OF = invert(SPACE_WIRE);
9116
+ var spaceJson = (s) => {
9117
+ switch (s.kind) {
9118
+ case "IntRange":
9119
+ return caseObj(SPACE_WIRE[s.kind], [
9120
+ ["min", num(s.min)],
9121
+ ["max", num(s.max)]
9122
+ ]);
9123
+ case "FloatRange":
9124
+ return caseObj(SPACE_WIRE[s.kind], [
9125
+ ["min", num(s.min)],
9126
+ ["max", num(s.max)]
9127
+ ]);
9128
+ case "StringLen":
9129
+ return caseObj(SPACE_WIRE[s.kind], [
9130
+ ["min", num(s.minLen)],
9131
+ ["max", num(s.maxLen)]
9132
+ ]);
9133
+ case "Enum":
9134
+ return caseObj(SPACE_WIRE[s.kind], [["values", jArray(s.choices.map(str))]]);
9135
+ case "AnyString":
9136
+ return caseObj(SPACE_WIRE[s.kind], []);
9137
+ }
9138
+ };
9139
+ var entryJson = (e) => {
9140
+ const fields = [
9141
+ ["addr", str(e.addr)],
9142
+ ["name", str(e.name)],
9143
+ ["kind", str(e.kind)],
9144
+ ["required", bool(e.required)]
9145
+ ];
9146
+ if (e.space !== void 0) fields.push(["space", spaceJson(e.space)]);
9147
+ if (e.slotKind !== void 0) fields.push(["slotKind", str(e.slotKind)]);
9148
+ return jObject(fields);
9149
+ };
9150
+ var placementJson = (p) => p.kind === "ClientIsland" ? caseObj(PLACEMENT_WIRE[p.kind], [["island", str(p.island)]]) : caseObj(PLACEMENT_WIRE[p.kind], []);
9151
+ var signatureJson = (sg) => jObject([
9152
+ ["name", str(sg.name)],
9153
+ [
9154
+ "effect",
9155
+ jObject([
9156
+ ["host", str(HOST_WIRE[sg.effect.hostEffect])],
9157
+ ["determinism", str(DETERMINISM_WIRE[sg.effect.determinism])]
9158
+ ])
9159
+ ],
9160
+ ["holes", jArray(sg.holes.map(entryJson))]
9161
+ ]);
9162
+ var encodeCapabilityDeclaration = (cap) => caseObj("capability", [
9163
+ ["id", str(cap.id)],
9164
+ ["signature", signatureJson(cap.signature)],
9165
+ ["determinism", str(DETERMINISM_WIRE[cap.determinism])],
9166
+ ["placement", placementJson(cap.placement)]
9167
+ ]);
9168
+ var DeclError = class extends Error {
9169
+ };
9170
+ var fail2 = (message) => {
9171
+ throw new DeclError(message);
9172
+ };
9173
+ var asObject = (v, what) => typeof v !== "object" || v === null || Array.isArray(v) ? fail2(`${what} is not an object`) : v;
9174
+ var strAt = (o, k) => {
9175
+ const v = o[k];
9176
+ return typeof v === "string" ? v : fail2(`missing or non-string field: ${k}`);
9177
+ };
9178
+ var numAt = (o, k) => {
9179
+ const v = o[k];
9180
+ return typeof v === "number" && Number.isFinite(v) ? v : fail2(`missing or non-finite numeric field: ${k}`);
9181
+ };
9182
+ var spaceOf = (raw) => {
9183
+ const o = asObject(raw, "value-space");
9184
+ const tag = strAt(o, "$type");
9185
+ const kind = SPACE_OF[tag];
9186
+ switch (kind) {
9187
+ case "IntRange":
9188
+ return { kind, min: numAt(o, "min"), max: numAt(o, "max") };
9189
+ case "FloatRange":
9190
+ return { kind, min: numAt(o, "min"), max: numAt(o, "max") };
9191
+ case "StringLen":
9192
+ return { kind, minLen: numAt(o, "min"), maxLen: numAt(o, "max") };
9193
+ case "Enum": {
9194
+ const values = o["values"];
9195
+ if (!Array.isArray(values) || values.some((x) => typeof x !== "string"))
9196
+ fail2("enum values must be a string array");
9197
+ return { kind, choices: values };
9198
+ }
9199
+ case "AnyString":
9200
+ return { kind };
9201
+ default:
9202
+ return fail2(
9203
+ `unknown value-space kind: ${tag}; expected one of: ${Object.values(SPACE_WIRE).join(", ")}`
9204
+ );
9205
+ }
9206
+ };
9207
+ var entryOf = (raw) => {
9208
+ const o = asObject(raw, "signature hole");
9209
+ if ("actionEffect" in o) {
9210
+ fail2(
9211
+ "this host's signature entry carries no action-effect axis, so a hole declaring `actionEffect` cannot round-trip"
9212
+ );
9213
+ }
9214
+ const kind = strAt(o, "kind");
9215
+ if (kind !== "value" && kind !== "slot" && kind !== "repeat")
9216
+ fail2(`unknown hole kind: ${kind}; expected one of: value, slot, repeat`);
9217
+ const required = o["required"];
9218
+ if (typeof required !== "boolean") fail2("missing or non-boolean field: required");
9219
+ return {
9220
+ addr: strAt(o, "addr"),
9221
+ name: strAt(o, "name"),
9222
+ kind,
9223
+ required,
9224
+ ..."space" in o ? { space: spaceOf(o["space"]) } : {},
9225
+ ..."slotKind" in o ? { slotKind: strAt(o, "slotKind") } : {}
9226
+ };
9227
+ };
9228
+ var placementOf = (raw) => {
9229
+ const o = asObject(raw, "placement");
9230
+ const tag = strAt(o, "$type");
9231
+ const kind = PLACEMENT_OF[tag];
9232
+ if (kind === void 0)
9233
+ fail2(`unknown placement: ${tag}; expected one of: ${Object.values(PLACEMENT_WIRE).join(", ")}`);
9234
+ if (kind === "ClientIsland") {
9235
+ const island = strAt(o, "island");
9236
+ if (!ISLANDS.includes(island))
9237
+ fail2(`unknown island kind: ${island}; expected one of: ${ISLANDS.join(", ")}`);
9238
+ return { kind, island };
9239
+ }
9240
+ return { kind };
9241
+ };
9242
+ var declarationOf = (json) => {
9243
+ let parsed;
9244
+ try {
9245
+ parsed = JSON.parse(json);
9246
+ } catch {
9247
+ return fail2("capability declaration is not well-formed JSON");
9248
+ }
9249
+ const o = asObject(parsed, "capability declaration");
9250
+ const tag = o["$type"];
9251
+ if (tag !== void 0 && tag !== "capability")
9252
+ fail2(`not a capability declaration: $type '${String(tag)}'`);
9253
+ const sigObj = asObject(o["signature"], "signature");
9254
+ const effectObj = asObject(sigObj["effect"], "effect");
9255
+ const hostTag = strAt(effectObj, "host");
9256
+ const hostEffect = HOST_OF[hostTag];
9257
+ if (hostEffect === void 0)
9258
+ fail2(
9259
+ `unknown host effect: ${hostTag}; expected one of: ${Object.values(HOST_WIRE).join(", ")}`
9260
+ );
9261
+ const detTag = strAt(effectObj, "determinism");
9262
+ const determinism = DETERMINISM_OF[detTag];
9263
+ if (determinism === void 0)
9264
+ fail2(
9265
+ `unknown determinism: ${detTag}; expected one of: ${Object.values(DETERMINISM_WIRE).join(", ")}`
9266
+ );
9267
+ const holes = sigObj["holes"];
9268
+ if (!Array.isArray(holes)) fail2("missing or non-array field: holes");
9269
+ const signature = {
9270
+ name: strAt(sigObj, "name"),
9271
+ holes: holes.map(entryOf),
9272
+ effect: { hostEffect, determinism }
9273
+ };
9274
+ const wireTag = strAt(o, "determinism");
9275
+ const expectedTag = DETERMINISM_WIRE[determinism];
9276
+ if (wireTag !== expectedTag)
9277
+ fail2(
9278
+ `capability determinism disagrees with signature effect: wire '${wireTag}' vs signature '${expectedTag}'`
9279
+ );
9280
+ return {
9281
+ id: strAt(o, "id"),
9282
+ signature,
9283
+ determinism,
9284
+ placement: placementOf(o["placement"])
9285
+ };
9286
+ };
9287
+ var decodeCapabilityDeclaration = (json) => {
9288
+ try {
9289
+ return dok2(declarationOf(json));
9290
+ } catch (e) {
9291
+ if (e instanceof DeclError) return derr2(e.message);
9292
+ throw e;
9293
+ }
9294
+ };
8388
9295
 
8389
9296
  // src/apply.ts
8390
9297
  var ok2 = (value) => ({ ok: true, value });
8391
- var fail2 = (code, message, batchIndex) => ({
9298
+ var fail3 = (code, message, batchIndex) => ({
8392
9299
  ok: false,
8393
9300
  error: batchIndex === void 0 ? { code, message } : { code, message, batchIndex }
8394
9301
  });
@@ -9225,22 +10132,22 @@ var applyOne = (op, root, telem) => {
9225
10132
  case "EditNode": {
9226
10133
  const updatedTree = mapNode(op.target, (n) => ({ ...n, kind: op.newKind }), root);
9227
10134
  if (updatedTree === void 0)
9228
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10135
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9229
10136
  telem.push({ op: "EditNode", targetId: op.target });
9230
10137
  return ok2(updatedTree);
9231
10138
  }
9232
10139
  case "UpdateProp": {
9233
10140
  const parsed = parsePath(op.path);
9234
10141
  if (!parsed.ok)
9235
- return fail2("PathInvalid", `Path '${op.path}' is structurally invalid: ${parsed.error}.`);
10142
+ return fail3("PathInvalid", `Path '${op.path}' is structurally invalid: ${parsed.error}.`);
9236
10143
  const targetNode = findNode(op.target, root);
9237
10144
  if (targetNode === void 0)
9238
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10145
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9239
10146
  const segs = parsed.value;
9240
10147
  const finish = (kind) => {
9241
10148
  const newTree = mapNode(op.target, (n) => ({ ...n, kind }), root);
9242
10149
  if (newTree === void 0)
9243
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10150
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9244
10151
  telem.push({ op: "UpdateProp", targetId: op.target });
9245
10152
  return ok2(newTree);
9246
10153
  };
@@ -9250,14 +10157,14 @@ var applyOne = (op, root, telem) => {
9250
10157
  case "updated":
9251
10158
  return finish(outcome2.kind);
9252
10159
  case "unknownField":
9253
- return fail2("FieldNotFound", `Field '${op.path}' not found on node '${op.target}'.`);
10160
+ return fail3("FieldNotFound", `Field '${op.path}' not found on node '${op.target}'.`);
9254
10161
  case "notSupported":
9255
- return fail2(
10162
+ return fail3(
9256
10163
  "PathNotSupportedYet",
9257
10164
  `Path '${op.path}' on node '${op.target}' is not yet supported by the apply engine.`
9258
10165
  );
9259
10166
  case "typeMismatch":
9260
- return fail2(
10167
+ return fail3(
9261
10168
  "KindMismatch",
9262
10169
  `UpdateProp value for '${op.path}' on node '${op.target}' does not match the field's expected type: ${outcome2.detail}`
9263
10170
  );
@@ -9269,27 +10176,27 @@ var applyOne = (op, root, telem) => {
9269
10176
  case "updated":
9270
10177
  return finish(outcome.kind);
9271
10178
  case "missingIndex":
9272
- return fail2(
10179
+ return fail3(
9273
10180
  "PathInvalid",
9274
10181
  `Field '${outcome.listField}' on node '${op.target}' is a list \u2014 address an element with a 0-based index (the list has ${outcome.count} element(s)).`
9275
10182
  );
9276
10183
  case "indexOutOfRange":
9277
- return fail2(
10184
+ return fail3(
9278
10185
  "PositionOutOfRange",
9279
10186
  `Index ${outcome.requested} is out of range for '${outcome.listField}' on node '${op.target}' (${outcome.count === 0 ? "the list is empty" : `valid: 0..${outcome.count - 1}`}).`
9280
10187
  );
9281
10188
  case "fieldNotFound":
9282
- return fail2(
10189
+ return fail3(
9283
10190
  "FieldNotFound",
9284
10191
  `Field '${outcome.segment}' (in path '${op.path}') not found on node '${op.target}'. Available at this segment: ${outcome.available.join(", ")}.`
9285
10192
  );
9286
10193
  case "notSupported":
9287
- return fail2(
10194
+ return fail3(
9288
10195
  "PathNotSupportedYet",
9289
10196
  `Path '${op.path}' on node '${op.target}' is not yet supported by the apply engine.`
9290
10197
  );
9291
10198
  case "typeMismatch":
9292
- return fail2(
10199
+ return fail3(
9293
10200
  "KindMismatch",
9294
10201
  `UpdateProp value for '${op.path}' on node '${op.target}' does not match the field's expected type: ${outcome.detail}`
9295
10202
  );
@@ -9299,20 +10206,20 @@ var applyOne = (op, root, telem) => {
9299
10206
  case "ReplaceBinding": {
9300
10207
  const targetNode = findNode(op.target, root);
9301
10208
  if (targetNode === void 0)
9302
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10209
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9303
10210
  const newKind = replaceBinding(op.slot, op.binding, targetNode.kind);
9304
10211
  if (newKind === void 0)
9305
- return fail2("SlotNotFound", `Binding slot '${op.slot}' not found on node '${op.target}'.`);
10212
+ return fail3("SlotNotFound", `Binding slot '${op.slot}' not found on node '${op.target}'.`);
9306
10213
  const newTree = mapNode(op.target, (n) => ({ ...n, kind: newKind }), root);
9307
10214
  if (newTree === void 0)
9308
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10215
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9309
10216
  telem.push({ op: "ReplaceBinding", targetId: op.target });
9310
10217
  return ok2(newTree);
9311
10218
  }
9312
10219
  case "UpdateStyle": {
9313
10220
  const newTree = mapNode(op.target, (n) => ({ ...n, style: op.style }), root);
9314
10221
  if (newTree === void 0)
9315
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10222
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9316
10223
  telem.push({ op: "UpdateStyle", targetId: op.target });
9317
10224
  return ok2(newTree);
9318
10225
  }
@@ -9323,39 +10230,39 @@ var applyOne = (op, root, telem) => {
9323
10230
  root
9324
10231
  );
9325
10232
  if (newTree === void 0)
9326
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10233
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9327
10234
  telem.push({ op: "UpdateState", targetId: op.target });
9328
10235
  return ok2(newTree);
9329
10236
  }
9330
10237
  case "InsertChild": {
9331
10238
  const parent = findNode(op.parentId, root);
9332
10239
  if (parent === void 0)
9333
- return fail2("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
10240
+ return fail3("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
9334
10241
  const children = layoutChildren(parent);
9335
10242
  if (children === void 0)
9336
- return fail2(
10243
+ return fail3(
9337
10244
  "ChildlessKind",
9338
10245
  `Node '${op.parentId}' (kind=${parent.kind.kind}) has no children field \u2014 only Layout kinds accept structural child ops.`
9339
10246
  );
9340
10247
  const existing = new Set(allNodeIds(root));
9341
10248
  const duplicate = allNodeIds(op.child).find((id) => existing.has(id));
9342
10249
  if (duplicate !== void 0)
9343
- return fail2(
10250
+ return fail3(
9344
10251
  "DuplicateNodeId",
9345
10252
  `NodeId '${duplicate}' is already present in the tree; ids must be unique.`
9346
10253
  );
9347
10254
  const newChildren = [...children, op.child];
9348
10255
  const newTree = mapNode(op.parentId, (n) => withLayoutChildren(n, newChildren), root);
9349
10256
  if (newTree === void 0)
9350
- return fail2("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
10257
+ return fail3("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
9351
10258
  telem.push({ op: "InsertChild", targetId: op.parentId });
9352
10259
  return ok2(newTree);
9353
10260
  }
9354
10261
  case "RemoveNode": {
9355
- if (idOf(root) === op.target) return fail2("KindMismatch", "Cannot RemoveNode the root.");
10262
+ if (idOf(root) === op.target) return fail3("KindMismatch", "Cannot RemoveNode the root.");
9356
10263
  const parent = findLayoutParent(op.target, root);
9357
10264
  if (parent === void 0)
9358
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10265
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9359
10266
  const children = layoutChildren(parent);
9360
10267
  const newTree = mapNode(
9361
10268
  idOf(parent),
@@ -9366,26 +10273,26 @@ var applyOne = (op, root, telem) => {
9366
10273
  root
9367
10274
  );
9368
10275
  if (newTree === void 0)
9369
- return fail2("ParentNotFound", `Parent node '${idOf(parent)}' not found in tree.`);
10276
+ return fail3("ParentNotFound", `Parent node '${idOf(parent)}' not found in tree.`);
9370
10277
  telem.push({ op: "RemoveNode", targetId: op.target });
9371
10278
  return ok2(newTree);
9372
10279
  }
9373
10280
  case "MoveNode": {
9374
10281
  if (op.target === op.newParentId)
9375
- return fail2("KindMismatch", "Cannot move a node into itself.");
10282
+ return fail3("KindMismatch", "Cannot move a node into itself.");
9376
10283
  if (isAncestor(op.target, op.newParentId, root))
9377
- return fail2(
10284
+ return fail3(
9378
10285
  "KindMismatch",
9379
10286
  "Cannot move a node into its own descendant (would create a cycle)."
9380
10287
  );
9381
10288
  const moving = findNode(op.target, root);
9382
10289
  if (moving === void 0)
9383
- return fail2("NodeNotFound", `Node '${op.target}' not found in tree.`);
10290
+ return fail3("NodeNotFound", `Node '${op.target}' not found in tree.`);
9384
10291
  const newParent = findNode(op.newParentId, root);
9385
10292
  if (newParent === void 0)
9386
- return fail2("ParentNotFound", `Parent node '${op.newParentId}' not found in tree.`);
10293
+ return fail3("ParentNotFound", `Parent node '${op.newParentId}' not found in tree.`);
9387
10294
  if (layoutChildren(newParent) === void 0)
9388
- return fail2(
10295
+ return fail3(
9389
10296
  "ChildlessKind",
9390
10297
  `Node '${op.newParentId}' (kind=${newParent.kind.kind}) has no children field.`
9391
10298
  );
@@ -9403,10 +10310,10 @@ var applyOne = (op, root, telem) => {
9403
10310
  case "ReorderChildren": {
9404
10311
  const parent = findNode(op.parentId, root);
9405
10312
  if (parent === void 0)
9406
- return fail2("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
10313
+ return fail3("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
9407
10314
  const children = layoutChildren(parent);
9408
10315
  if (children === void 0)
9409
- return fail2(
10316
+ return fail3(
9410
10317
  "ChildlessKind",
9411
10318
  `Node '${op.parentId}' (kind=${parent.kind.kind}) has no children field.`
9412
10319
  );
@@ -9414,7 +10321,7 @@ var applyOne = (op, root, telem) => {
9414
10321
  const sortedCurrent = [...currentIds].sort();
9415
10322
  const sortedNew = [...op.newOrder].map((x) => x).sort();
9416
10323
  if (sortedCurrent.length !== sortedNew.length || sortedCurrent.some((id, i) => id !== sortedNew[i]))
9417
- return fail2(
10324
+ return fail3(
9418
10325
  "OrderingMismatch",
9419
10326
  `ReorderChildren for '${op.parentId}' did not list exactly the current child ids.`
9420
10327
  );
@@ -9422,7 +10329,7 @@ var applyOne = (op, root, telem) => {
9422
10329
  const reordered = op.newOrder.map((id) => byId.get(id)).filter((c) => c !== void 0);
9423
10330
  const newTree = mapNode(op.parentId, (n) => withLayoutChildren(n, reordered), root);
9424
10331
  if (newTree === void 0)
9425
- return fail2("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
10332
+ return fail3("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
9426
10333
  telem.push({ op: "ReorderChildren", targetId: op.parentId });
9427
10334
  return ok2(newTree);
9428
10335
  }
@@ -9447,7 +10354,7 @@ var applyOne = (op, root, telem) => {
9447
10354
  return ok2(state);
9448
10355
  }
9449
10356
  }
9450
- return fail2("KindMismatch", "unreachable apply branch");
10357
+ return fail3("KindMismatch", "unreachable apply branch");
9451
10358
  };
9452
10359
  var apply = (tree, op) => {
9453
10360
  const telem = [];
@@ -9770,11 +10677,20 @@ var isPureAddition = (baseIds, headIds) => {
9770
10677
  return survive.length === baseIds.length && survive.every((v, i) => v === baseIds[i]) && headKept.length === baseIds.length && headKept.every((v, i) => v === baseIds[i]);
9771
10678
  };
9772
10679
  var eqOpt = (x, y) => (x ?? null) === (y ?? null);
9773
- var pickField = (conflicts, nodeId, facet, baseV, aV, bV) => {
10680
+ var refusal = (nodeId, facet, cls, base, aValue, bValue) => ({
10681
+ nodeId,
10682
+ facet,
10683
+ class: cls,
10684
+ base,
10685
+ a: { value: aValue },
10686
+ b: { value: bValue },
10687
+ primacyHeld: false
10688
+ });
10689
+ var pickField = (conflicts, nodeId, facet, dflt, baseV, aV, bV) => {
9774
10690
  const aCh = !eqOpt(aV, baseV);
9775
10691
  const bCh = !eqOpt(bV, baseV);
9776
10692
  if (aCh && bCh && !eqOpt(aV, bV)) {
9777
- conflicts.push({ nodeId, facet });
10693
+ conflicts.push(refusal(nodeId, facet, "ConcurrentEdit", baseV ?? dflt, aV ?? dflt, bV ?? dflt));
9778
10694
  return baseV;
9779
10695
  }
9780
10696
  if (aCh) return aV;
@@ -9785,7 +10701,7 @@ var pickCanonical = (conflicts, nodeId, facet, baseC, aC, bC) => {
9785
10701
  const aCh = aC !== baseC;
9786
10702
  const bCh = bC !== baseC;
9787
10703
  if (aCh && bCh && aC !== bC) {
9788
- conflicts.push({ nodeId, facet });
10704
+ conflicts.push(refusal(nodeId, facet, "ConcurrentEdit", baseC, aC, bC));
9789
10705
  return 0;
9790
10706
  }
9791
10707
  if (aCh) return 1;
@@ -9796,18 +10712,28 @@ var mergeStyle = (conflicts, id, base, a, b) => {
9796
10712
  const bs = base.style;
9797
10713
  const as_ = a.style;
9798
10714
  const bsB = b.style;
9799
- const tone = pickField(conflicts, id, "style.tone", bs.tone, as_.tone, bsB.tone);
9800
- const weight = pickField(conflicts, id, "style.weight", bs.weight, as_.weight, bsB.weight);
10715
+ const d = schema.defaults.style;
10716
+ const tone = pickField(conflicts, id, "style.tone", d.tone, bs.tone, as_.tone, bsB.tone);
10717
+ const weight = pickField(
10718
+ conflicts,
10719
+ id,
10720
+ "style.weight",
10721
+ d.weight,
10722
+ bs.weight,
10723
+ as_.weight,
10724
+ bsB.weight
10725
+ );
9801
10726
  const emphasis = pickField(
9802
10727
  conflicts,
9803
10728
  id,
9804
10729
  "style.emphasis",
10730
+ d.emphasis,
9805
10731
  bs.emphasis,
9806
10732
  as_.emphasis,
9807
10733
  bsB.emphasis
9808
10734
  );
9809
- const role = pickField(conflicts, id, "style.role", bs.role, as_.role, bsB.role);
9810
- const voice = pickField(conflicts, id, "style.voice", bs.voice, as_.voice, bsB.voice);
10735
+ const role = pickField(conflicts, id, "style.role", d.role, bs.role, as_.role, bsB.role);
10736
+ const voice = pickField(conflicts, id, "style.voice", d.voice, bs.voice, as_.voice, bsB.voice);
9811
10737
  const style = { tone, weight, emphasis };
9812
10738
  return {
9813
10739
  ...style,
@@ -9863,8 +10789,15 @@ var merge3 = (conflicts, base, aOpt, bOpt) => {
9863
10789
  const bc = baseMap.get(cid);
9864
10790
  if (bc !== void 0) return merge3(conflicts, bc, aMap.get(cid), bMap.get(cid));
9865
10791
  const ac = aMap.get(cid);
9866
- if (ac !== void 0) return ac;
9867
10792
  const bb = bMap.get(cid);
10793
+ if (ac !== void 0 && bb !== void 0) {
10794
+ const acC = encodeNode(ac);
10795
+ const bcC = encodeNode(bb);
10796
+ if (acC === bcC) return ac;
10797
+ conflicts.push(refusal(cid, "insert", "ConcurrentEdit", "", acC, bcC));
10798
+ return ordinal(acC, bcC) <= 0 ? ac : bb;
10799
+ }
10800
+ if (ac !== void 0) return ac;
9868
10801
  if (bb !== void 0) return bb;
9869
10802
  throw new Error(`merge3: child id ${cid} vanished`);
9870
10803
  };
@@ -9875,6 +10808,8 @@ var merge3 = (conflicts, base, aOpt, bOpt) => {
9875
10808
  mergedChildren = aIds.map(recurseChild);
9876
10809
  } else if (!aStruct && bStruct) {
9877
10810
  mergedChildren = bIds.map(recurseChild);
10811
+ } else if (JSON.stringify(aIds) === JSON.stringify(bIds)) {
10812
+ mergedChildren = aIds.map(recurseChild);
9878
10813
  } else {
9879
10814
  const baseSet = new Set(baseIds);
9880
10815
  const aNew = aIds.filter((i) => !baseSet.has(i));
@@ -9886,7 +10821,16 @@ var merge3 = (conflicts, base, aOpt, bOpt) => {
9886
10821
  const newIds = [.../* @__PURE__ */ new Set([...aNew, ...bNew])].sort(ordinal);
9887
10822
  mergedChildren = [...survivors, ...newIds.map(recurseChild)];
9888
10823
  } else {
9889
- conflicts.push({ nodeId: id, facet: "children" });
10824
+ conflicts.push(
10825
+ refusal(
10826
+ id,
10827
+ "children",
10828
+ "ReorderVsStructural",
10829
+ baseIds.join(","),
10830
+ aIds.join(","),
10831
+ bIds.join(",")
10832
+ )
10833
+ );
9890
10834
  mergedChildren = baseIds.map(recurseChild);
9891
10835
  }
9892
10836
  }
@@ -9898,6 +10842,21 @@ var merge3Way = (base, a, b) => {
9898
10842
  const merged = merge3(conflicts, base, a, b);
9899
10843
  return conflicts.length === 0 ? { ok: true, tree: merged } : { ok: false, conflicts };
9900
10844
  };
10845
+ var sortConflictsCanonical = (conflicts) => [...conflicts].sort((x, y) => ordinal(x.nodeId, y.nodeId) || ordinal(x.facet, y.facet));
10846
+ var escapeJson = (s) => {
10847
+ let out = '"';
10848
+ for (const ch of s) {
10849
+ if (ch === '"') out += '\\"';
10850
+ else if (ch === "\\") out += "\\\\";
10851
+ else if (ch < " ") out += `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`;
10852
+ else out += ch;
10853
+ }
10854
+ return out + '"';
10855
+ };
10856
+ var encodeSide = (side) => `{"tag":${side.tag === void 0 ? "null" : escapeJson(side.tag)},"value":${escapeJson(side.value)}}`;
10857
+ var encodeMergeEnvelope = (conflicts) => "[" + sortConflictsCanonical(conflicts).map(
10858
+ (c) => `{"a":${encodeSide(c.a)},"b":${encodeSide(c.b)},"base":${escapeJson(c.base)},"class":${escapeJson(c.class)},"facet":${escapeJson(c.facet)},"nodeId":${escapeJson(c.nodeId)},"primacyHeld":${c.primacyHeld ? "true" : "false"}}`
10859
+ ).join(",") + "]";
9901
10860
 
9902
10861
  // src/versioning.ts
9903
10862
  var renderProfile = (p) => `${p.name}@${p.major}.${p.minor}`;
@@ -10785,19 +11744,23 @@ var withStateSeeds = (tree, sources) => {
10785
11744
  return { ...sources, state: { ...seeds, ...sources.state ?? {} } };
10786
11745
  };
10787
11746
 
11747
+ exports.DECODED_COMPUTED_MESSAGE = DECODED_COMPUTED_MESSAGE;
10788
11748
  exports.ELICITATION_KEY = ELICITATION_KEY;
10789
11749
  exports.ELICITATION_VERSION = ELICITATION_VERSION;
10790
11750
  exports.HOST_RESERVED_PREFIX = HOST_RESERVED_PREFIX;
10791
11751
  exports.PAYLOAD_KEY = PAYLOAD_KEY;
10792
11752
  exports.PROFILE_KEY = PROFILE_KEY;
10793
11753
  exports.REQUIRED_PROFILE_KEY = REQUIRED_PROFILE_KEY;
11754
+ exports.WireSurvivabilityError = WireSurvivabilityError;
10794
11755
  exports.apply = apply;
10795
11756
  exports.canPlace = canPlace;
10796
11757
  exports.cellString = cellString;
10797
11758
  exports.coerce = coerce;
10798
11759
  exports.collectStateSeeds = collectStateSeeds;
10799
11760
  exports.coreV1 = coreV1;
11761
+ exports.decodeCapabilityDeclaration = decodeCapabilityDeclaration;
10800
11762
  exports.decodeDagRecord = decodeDagRecord;
11763
+ exports.decodeDataSource = decodeDataSource;
10801
11764
  exports.decodeElicitation = decodeElicitation;
10802
11765
  exports.decodeElicitationOutcome = decodeElicitationOutcome;
10803
11766
  exports.decodeEnvelope = decodeEnvelope;
@@ -10805,10 +11768,13 @@ exports.decodeEnvelopeAst = decodeEnvelopeAst;
10805
11768
  exports.decodeNode = decodeNode;
10806
11769
  exports.decodeNodeTolerant = decodeNodeTolerant;
10807
11770
  exports.decodeOp = decodeOp;
11771
+ exports.decodeOps = decodeOps;
11772
+ exports.decodePipeline = decodePipelineCore;
10808
11773
  exports.decodeTolerant = decodeTolerant;
10809
11774
  exports.derivedFreshIds = derivedFreshIds;
10810
11775
  exports.duplicateOp = duplicateOp;
10811
11776
  exports.duplicateOpWith = duplicateOpWith;
11777
+ exports.encodeCapabilityDeclaration = encodeCapabilityDeclaration;
10812
11778
  exports.encodeCell = encodeCell;
10813
11779
  exports.encodeColExpr = encodeColExpr;
10814
11780
  exports.encodeDagRecord = encodeDagRecord;
@@ -10816,6 +11782,7 @@ exports.encodeDataSource = encodeDataSource;
10816
11782
  exports.encodeElicitation = encodeElicitation;
10817
11783
  exports.encodeElicitationOutcome = encodeElicitationOutcome;
10818
11784
  exports.encodeEnvelope = encodeEnvelope2;
11785
+ exports.encodeMergeEnvelope = encodeMergeEnvelope;
10819
11786
  exports.encodeNode = encodeNode;
10820
11787
  exports.encodeOp = encodeOp;
10821
11788
  exports.encodePipeline = encodePipeline;
@@ -10825,6 +11792,8 @@ exports.evalPipelineInEnv = evalPipelineInEnv;
10825
11792
  exports.evalPipelineWith = evalPipelineWith;
10826
11793
  exports.evalPipelineWithInEnv = evalPipelineWithInEnv;
10827
11794
  exports.evalSource = evalSource;
11795
+ exports.fixedText = fixedText;
11796
+ exports.identityFormat = identityFormat;
10828
11797
  exports.jsonField = field;
10829
11798
  exports.liveValueToTable = liveValueToTable;
10830
11799
  exports.merge3Way = merge3Way;
@@ -10833,6 +11802,7 @@ exports.negotiate = negotiate;
10833
11802
  exports.negotiateEnvelope = negotiateEnvelope;
10834
11803
  exports.noResolve = noResolve;
10835
11804
  exports.nudgeOp = nudgeOp;
11805
+ exports.numberText = numberText;
10836
11806
  exports.parse = parse;
10837
11807
  exports.pasteOp = pasteOp;
10838
11808
  exports.pasteOpWith = pasteOpWith;
@@ -10841,9 +11811,12 @@ exports.placeOp = placeOp;
10841
11811
  exports.reencodeNode = reencodeNode;
10842
11812
  exports.renderAstCanonical = renderAstCanonical;
10843
11813
  exports.renderProfile = renderProfile;
11814
+ exports.scalarOfText = scalarOfText;
10844
11815
  exports.sequentialFreshIds = sequentialFreshIds;
11816
+ exports.sortConflictsCanonical = sortConflictsCanonical;
10845
11817
  exports.stepParams = stepParams;
10846
11818
  exports.substituteListParams = substituteListParams;
11819
+ exports.tryNumberText = tryNumberText;
10847
11820
  exports.tryParseProfile = tryParseProfile;
10848
11821
  exports.validateAnswer = validateAnswer;
10849
11822
  exports.validateAnswerAt = validateAnswerAt;