@fuaran-ui/ops 0.9.0 → 0.19.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
@@ -80,10 +80,11 @@ var formatFiniteDouble = (n) => {
80
80
  return neg ? "-" + out : out;
81
81
  };
82
82
  var num = (n) => {
83
- if (Number.isNaN(n)) return '"NaN"';
84
- if (n === Infinity) return '"Infinity"';
85
- if (n === -Infinity) return '"-Infinity"';
86
- return formatFiniteDouble(n);
83
+ const v = Number(n);
84
+ if (Number.isNaN(v)) return '"NaN"';
85
+ if (v === Infinity) return '"Infinity"';
86
+ if (v === -Infinity) return '"-Infinity"';
87
+ return formatFiniteDouble(v);
87
88
  };
88
89
  var bool = (b) => b ? "true" : "false";
89
90
  var jObject = (fields) => {
@@ -593,6 +594,9 @@ var pushWeightOptional = (fields, w) => {
593
594
  var pushEmphasisOptional = (fields, e) => {
594
595
  if (e !== "Normal") fields.push(["emphasis", str(e)]);
595
596
  };
597
+ var pushTrendPolarityOptional = (fields, p) => {
598
+ if (p !== "HigherIsBetter") fields.push(["trendPolarity", str(p)]);
599
+ };
596
600
  var pushCellFormatOptional = (fields, key, f) => {
597
601
  if (f.kind !== "None") fields.push([key, cellFormat(f)]);
598
602
  };
@@ -610,6 +614,7 @@ var metricSpec = (s) => {
610
614
  pushEmphasisOptional(fields, s.emphasis);
611
615
  if (s.trend !== void 0) fields.push(["trend", binding(s.trend)]);
612
616
  if (s.trendFormat !== void 0) fields.push(["trendFormat", cellFormat(s.trendFormat)]);
617
+ pushTrendPolarityOptional(fields, s.trendPolarity);
613
618
  if (s.icon !== void 0) fields.push(["icon", str(s.icon)]);
614
619
  if (s.subtext !== void 0) fields.push(["subtext", textSource(s.subtext)]);
615
620
  return jObject(fields);
@@ -656,11 +661,40 @@ var linkSpec = (s) => {
656
661
  if (s.protection !== void 0) fields.push(["protection", str(s.protection)]);
657
662
  return jObject(fields);
658
663
  };
659
- var imageSpec = (s) => jObject([
660
- ["alt", textSource(s.alt)],
661
- ["src", binding(s.src)],
662
- ["variant", str(s.variant)]
664
+ var srcSetEntry = (e) => jObject([
665
+ ["src", binding(e.src)],
666
+ ["width", num(e.width)]
663
667
  ]);
668
+ var imageSpec = (s) => {
669
+ const fields = [
670
+ ["alt", textSource(s.alt)],
671
+ ["src", binding(s.src)],
672
+ ["variant", str(s.variant)]
673
+ ];
674
+ if (s.fit !== "Natural") fields.push(["fit", str(s.fit)]);
675
+ if (s.aspectRatio !== "Natural") fields.push(["aspectRatio", str(s.aspectRatio)]);
676
+ if (s.loading !== "Eager") fields.push(["loading", str(s.loading)]);
677
+ if (s.caption !== void 0) fields.push(["caption", textSource(s.caption)]);
678
+ if (s.srcSet.length > 0) fields.push(["srcSet", jArray(s.srcSet.map(srcSetEntry))]);
679
+ if (s.expandable) fields.push(["expandable", bool(true)]);
680
+ return jObject(fields);
681
+ };
682
+ var mediaKind = (k) => {
683
+ if (k.$type === "Audio") return caseObj("Audio", []);
684
+ const fields = [];
685
+ if (k.autoplay) fields.push(["autoplay", bool(true)]);
686
+ if (k.poster !== void 0) fields.push(["poster", binding(k.poster)]);
687
+ return caseObj("Video", fields);
688
+ };
689
+ var mediaSpec = (s) => {
690
+ const fields = [];
691
+ if (!s.controls) fields.push(["controls", bool(false)]);
692
+ fields.push(["kind", mediaKind(s.kind)]);
693
+ fields.push(["label", textSource(s.label)]);
694
+ if (s.loop) fields.push(["loop", bool(true)]);
695
+ fields.push(["src", binding(s.src)]);
696
+ return jObject(fields);
697
+ };
664
698
  var listSpec = (s) => jObject([
665
699
  ["items", jArray(s.items.map(textSource))],
666
700
  ["ordered", bool(s.ordered)]
@@ -869,6 +903,8 @@ var displayKind = (d) => {
869
903
  return hoistSpec("Link", linkSpec(d.spec));
870
904
  case "Image":
871
905
  return hoistSpec("Image", imageSpec(d.spec));
906
+ case "Media":
907
+ return hoistSpec("Media", mediaSpec(d.spec));
872
908
  case "List":
873
909
  return hoistSpec("List", listSpec(d.spec));
874
910
  case "Toast":
@@ -996,6 +1032,20 @@ var formFieldKind = (autoBind, k) => {
996
1032
  return assertNever(k);
997
1033
  }
998
1034
  };
1035
+ var compareRule = (c) => jObject([
1036
+ ["against", binding(c.against)],
1037
+ ["op", str(c.op)]
1038
+ ]);
1039
+ var fieldRule = (r) => {
1040
+ const fields = [];
1041
+ if (r.compare !== void 0) fields.push(["compare", compareRule(r.compare)]);
1042
+ if (r.format !== void 0) fields.push(["format", str(r.format)]);
1043
+ if (r.maxLength !== void 0) fields.push(["maxLength", intLit(r.maxLength)]);
1044
+ if (r.message !== void 0) fields.push(["message", textSource(r.message)]);
1045
+ if (r.minLength !== void 0) fields.push(["minLength", intLit(r.minLength)]);
1046
+ if (r.pattern !== void 0) fields.push(["pattern", str(r.pattern)]);
1047
+ return jObject(fields);
1048
+ };
999
1049
  var formField = (f) => {
1000
1050
  const fields = [
1001
1051
  ["id", str(f.id)],
@@ -1004,6 +1054,7 @@ var formField = (f) => {
1004
1054
  ["required", bool(f.required)]
1005
1055
  ];
1006
1056
  if (f.help !== void 0) fields.push(["help", textSource(f.help)]);
1057
+ if (f.rule !== void 0) fields.push(["rule", fieldRule(f.rule)]);
1007
1058
  return jObject(fields);
1008
1059
  };
1009
1060
  var formSpec = (s) => {
@@ -1271,6 +1322,11 @@ var boxLayout = (l) => {
1271
1322
  if (l.templateColumns !== void 0) fields.push(["templateColumns", str(l.templateColumns)]);
1272
1323
  return caseObj("Grid", fields);
1273
1324
  }
1325
+ case "Masonry": {
1326
+ const fields = [["cols", intLit(l.cols)]];
1327
+ if (l.gap !== void 0) fields.push(["gap", intLit(l.gap)]);
1328
+ return caseObj("Masonry", fields);
1329
+ }
1274
1330
  case "Auto":
1275
1331
  return caseObj("Auto", []);
1276
1332
  default:
@@ -2683,8 +2739,6 @@ var stepParams = (t) => {
2683
2739
  var pipelineParams = (pipeline) => [
2684
2740
  ...new Set(pipeline.flatMap((t) => stepParams(t)))
2685
2741
  ];
2686
-
2687
- // src/parse.ts
2688
2742
  var peek = (s) => s.pos < s.text.length ? s.text[s.pos] : " ";
2689
2743
  var advance = (s) => {
2690
2744
  s.pos += 1;
@@ -2699,6 +2753,10 @@ var skipWs = (s) => {
2699
2753
  }
2700
2754
  }
2701
2755
  };
2756
+ var failLimit = (s, message) => ({
2757
+ ok: false,
2758
+ error: { message, offset: s.pos, limit: true }
2759
+ });
2702
2760
  var fail = (s, message) => ({
2703
2761
  ok: false,
2704
2762
  error: { message, offset: s.pos }
@@ -2721,7 +2779,14 @@ var parseStringRaw = (s) => {
2721
2779
  advance(s);
2722
2780
  if (c === '"') {
2723
2781
  return { ok: true, value: out };
2724
- } else if (c === "\\") {
2782
+ }
2783
+ if (out.length > schema.MAX_STRING_LENGTH) {
2784
+ return failLimit(
2785
+ s,
2786
+ `string is longer than the wire limit MAX_STRING_LENGTH = ${schema.MAX_STRING_LENGTH}`
2787
+ );
2788
+ }
2789
+ if (c === "\\") {
2725
2790
  if (s.pos >= s.text.length) return fail(s, "unterminated escape");
2726
2791
  const esc = s.text[s.pos];
2727
2792
  advance(s);
@@ -2821,6 +2886,12 @@ var parseValue = (s) => {
2821
2886
  }
2822
2887
  };
2823
2888
  var parseObjectValue = (s) => {
2889
+ if (s.depth >= schema.MAX_JSON_DEPTH) {
2890
+ return failLimit(
2891
+ s,
2892
+ `JSON nesting deeper than the wire limit MAX_JSON_DEPTH = ${schema.MAX_JSON_DEPTH}`
2893
+ );
2894
+ }
2824
2895
  const open = expectChar(s, "{");
2825
2896
  if (!open.ok) return open;
2826
2897
  skipWs(s);
@@ -2829,15 +2900,34 @@ var parseObjectValue = (s) => {
2829
2900
  advance(s);
2830
2901
  return { ok: true, value: { kind: "JObject", fields } };
2831
2902
  }
2903
+ s.depth += 1;
2904
+ let count = 0;
2832
2905
  for (; ; ) {
2833
2906
  skipWs(s);
2834
2907
  const keyR = parseStringRaw(s);
2835
- if (!keyR.ok) return keyR;
2908
+ if (!keyR.ok) {
2909
+ s.depth -= 1;
2910
+ return keyR;
2911
+ }
2836
2912
  skipWs(s);
2837
2913
  const colon = expectChar(s, ":");
2838
- if (!colon.ok) return colon;
2914
+ if (!colon.ok) {
2915
+ s.depth -= 1;
2916
+ return colon;
2917
+ }
2839
2918
  const valR = parseValue(s);
2840
- if (!valR.ok) return valR;
2919
+ if (!valR.ok) {
2920
+ s.depth -= 1;
2921
+ return valR;
2922
+ }
2923
+ count += 1;
2924
+ if (count > schema.MAX_ARRAY_LENGTH) {
2925
+ s.depth -= 1;
2926
+ return failLimit(
2927
+ s,
2928
+ `object has more members than the wire limit MAX_ARRAY_LENGTH = ${schema.MAX_ARRAY_LENGTH}`
2929
+ );
2930
+ }
2841
2931
  fields.set(keyR.value, valR.value);
2842
2932
  skipWs(s);
2843
2933
  const c = peek(s);
@@ -2845,13 +2935,21 @@ var parseObjectValue = (s) => {
2845
2935
  advance(s);
2846
2936
  } else if (c === "}") {
2847
2937
  advance(s);
2938
+ s.depth -= 1;
2848
2939
  return { ok: true, value: { kind: "JObject", fields } };
2849
2940
  } else {
2941
+ s.depth -= 1;
2850
2942
  return fail(s, `expected ',' or '}' but found '${c}'`);
2851
2943
  }
2852
2944
  }
2853
2945
  };
2854
2946
  var parseArrayValue = (s) => {
2947
+ if (s.depth >= schema.MAX_JSON_DEPTH) {
2948
+ return failLimit(
2949
+ s,
2950
+ `JSON nesting deeper than the wire limit MAX_JSON_DEPTH = ${schema.MAX_JSON_DEPTH}`
2951
+ );
2952
+ }
2855
2953
  const open = expectChar(s, "[");
2856
2954
  if (!open.ok) return open;
2857
2955
  skipWs(s);
@@ -2860,24 +2958,37 @@ var parseArrayValue = (s) => {
2860
2958
  advance(s);
2861
2959
  return { ok: true, value: { kind: "JArray", items } };
2862
2960
  }
2961
+ s.depth += 1;
2863
2962
  for (; ; ) {
2864
2963
  const valR = parseValue(s);
2865
- if (!valR.ok) return valR;
2964
+ if (!valR.ok) {
2965
+ s.depth -= 1;
2966
+ return valR;
2967
+ }
2866
2968
  items.push(valR.value);
2969
+ if (items.length > schema.MAX_ARRAY_LENGTH) {
2970
+ s.depth -= 1;
2971
+ return failLimit(
2972
+ s,
2973
+ `array is longer than the wire limit MAX_ARRAY_LENGTH = ${schema.MAX_ARRAY_LENGTH}`
2974
+ );
2975
+ }
2867
2976
  skipWs(s);
2868
2977
  const c = peek(s);
2869
2978
  if (c === ",") {
2870
2979
  advance(s);
2871
2980
  } else if (c === "]") {
2872
2981
  advance(s);
2982
+ s.depth -= 1;
2873
2983
  return { ok: true, value: { kind: "JArray", items } };
2874
2984
  } else {
2985
+ s.depth -= 1;
2875
2986
  return fail(s, `expected ',' or ']' but found '${c}'`);
2876
2987
  }
2877
2988
  }
2878
2989
  };
2879
2990
  var parse = (input) => {
2880
- const s = { text: input, pos: 0 };
2991
+ const s = { text: input, pos: 0, depth: 0 };
2881
2992
  skipWs(s);
2882
2993
  if (s.pos >= s.text.length) {
2883
2994
  return { ok: false, error: { message: "input is empty", offset: 0 } };
@@ -2895,6 +3006,7 @@ var makeError = (code, path, message, expectedShape) => ({
2895
3006
  var missingField = (path, key, expected) => makeError("MISSING_FIELD", `${path}.${key}`, `missing required field '${key}'`, expected);
2896
3007
  var wrongType = (path, expected) => makeError("WRONG_TYPE", path, `expected ${expected}`, expected);
2897
3008
  var unknownDuCase = (path, got, expected) => makeError("UNKNOWN_DU_CASE", `${path}.$type`, `unknown discriminator '${got}'`, expected);
3009
+ var unknownEnumCase = (path, got, expected) => makeError("UNKNOWN_DU_CASE", path, `unknown discriminator '${got}'`, expected);
2898
3010
  var CLOSURE2 = "<closure>";
2899
3011
  var OPAQUE2 = "<opaque>";
2900
3012
  var requireObject = (path, j) => j.kind === "JObject" ? ok(j.fields) : wrongType(path, "JSON object");
@@ -3047,7 +3159,7 @@ var decodeJValMap = (path, j) => {
3047
3159
  var bareEnum = (path, j, valid, label) => {
3048
3160
  if (j.kind !== "JString") return wrongType(path, `JSON string (${label})`);
3049
3161
  if (valid.includes(j.value)) return ok(j.value);
3050
- return unknownDuCase(path, j.value, valid.join(" | "));
3162
+ return unknownEnumCase(path, j.value, valid.join(" | "));
3051
3163
  };
3052
3164
  var ORIENTATION_ALIASES = {
3053
3165
  // CSS flex-direction prior: a row lays out horizontally, a column vertically.
@@ -3085,6 +3197,14 @@ var decodeHeadingVariant = (p, j) => {
3085
3197
  return bareEnum(p, j, ["Standard", "Eyebrow", "Caption", "Lead"], "HeadingVariant");
3086
3198
  };
3087
3199
  var decodeImageVariant = (p, j) => bareEnum(p, j, ["Default", "Avatar", "Rounded"], "ImageVariant");
3200
+ var decodeImageFit = (p, j) => bareEnum(p, j, ["Natural", "Cover", "Contain"], "ImageFit");
3201
+ var decodeImageAspect = (p, j) => bareEnum(
3202
+ p,
3203
+ j,
3204
+ ["Natural", "Square", "FourThree", "ThreeTwo", "SixteenNine"],
3205
+ "ImageAspect"
3206
+ );
3207
+ var decodeImageLoading = (p, j) => bareEnum(p, j, ["Eager", "Lazy"], "ImageLoading");
3088
3208
  var decodeScrollOrientation = (p, j) => bareEnum(p, j, ["Vertical", "Horizontal", "Both"], "ScrollOrientation");
3089
3209
  var decodeDateVariant = (p, j) => bareEnum(p, j, ["Date", "Time", "DateTime"], "DateVariant");
3090
3210
  var decodeMathDisplay = (p, j) => bareEnum(p, j, ["Inline", "Block"], "MathDisplay");
@@ -3118,6 +3238,7 @@ var decodeWeight = (p, j) => (
3118
3238
  // Compact|Standard|Spacious means density (WIRE_FORMAT.md §3.6).
3119
3239
  bareEnum(p, j, ["Compact", "Standard", "Spacious"], "StyleWeight")
3120
3240
  );
3241
+ var decodeTrendPolarity = (p, j) => bareEnum(p, j, ["HigherIsBetter", "LowerIsBetter"], "TrendPolarity");
3121
3242
  var decodeEmphasis = (p, j) => {
3122
3243
  if (j.kind === "JString" && j.value in EMPHASIS_ALIASES) return ok(EMPHASIS_ALIASES[j.value]);
3123
3244
  if (j.kind === "JBool") return ok(j.value ? "Loud" : "Normal");
@@ -4319,29 +4440,43 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4319
4440
  if (!pipeJ.ok) return pipeJ;
4320
4441
  const liveTagAst = srcJ.value.kind === "JObject" ? srcJ.value.fields.get("$type") : void 0;
4321
4442
  const liveTag = liveTagAst !== void 0 && liveTagAst.kind === "JString" && (liveTagAst.value === "State" || liveTagAst.value === "Selection" || liveTagAst.value === "Query") ? liveTagAst.value : void 0;
4322
- const hasCarried = srcJ.value.kind === "JObject" && srcJ.value.fields.has("defaultValue");
4323
4443
  let source;
4324
- if (liveTag === void 0 || liveTag === "State" && !hasCarried) {
4444
+ if (liveTag === void 0) {
4325
4445
  const src = decodeDataSource(normaliseTransformSource(srcJ.value));
4326
4446
  if (!src.ok) return makeError("WRONG_TYPE", `${path}.source`, src.error);
4327
4447
  source = { kind: "Data", source: src.value };
4328
4448
  } else {
4329
4449
  const b2 = decodeBinding(`${path}.source`, srcJ.value, decodeJVal, void 0);
4330
4450
  if (!b2.ok) return b2;
4451
+ const liveBinding = (() => {
4452
+ const raw = b2.value;
4453
+ const declared = srcJ.value.kind === "JObject" && srcJ.value.fields.has("defaultValue");
4454
+ return raw.kind === "State" && !declared ? { ...raw, defaultValue: void 0 } : raw;
4455
+ })();
4331
4456
  if (liveTag === "State") {
4332
- const snap = decodeDataSource(normaliseTransformSource(srcJ.value));
4333
- if (!snap.ok) return makeError("WRONG_TYPE", `${path}.source`, snap.error);
4334
- source = {
4335
- kind: "Live",
4336
- binding: b2.value,
4337
- initial: snap.value
4338
- };
4457
+ const carriedJ = srcJ.value.kind === "JObject" ? srcJ.value.fields.get("defaultValue") : void 0;
4458
+ const carriesNoData = carriedJ === void 0 || carriedJ.kind === "JArray" && carriedJ.items.length === 0;
4459
+ if (carriesNoData) {
4460
+ source = {
4461
+ kind: "Live",
4462
+ binding: liveBinding,
4463
+ initial: { kind: "Embedded", table: { schema: [], columns: [] } }
4464
+ };
4465
+ } else {
4466
+ const snap = decodeDataSource(normaliseTransformSource(srcJ.value));
4467
+ if (!snap.ok) return makeError("WRONG_TYPE", `${path}.source`, snap.error);
4468
+ source = {
4469
+ kind: "Live",
4470
+ binding: liveBinding,
4471
+ initial: snap.value
4472
+ };
4473
+ }
4339
4474
  } else {
4340
4475
  const dv = srcJ.value.kind === "JObject" ? srcJ.value.fields.get("defaultValue") : void 0;
4341
4476
  const snap = dv !== void 0 ? decodeDataSource(normaliseTransformSource(dv)) : void 0;
4342
4477
  source = {
4343
4478
  kind: "Live",
4344
- binding: b2.value,
4479
+ binding: liveBinding,
4345
4480
  initial: snap !== void 0 && snap.ok ? snap.value : { kind: "Embedded", table: { schema: [], columns: [] } }
4346
4481
  };
4347
4482
  }
@@ -4498,8 +4633,10 @@ var decodeBindingArgs = (path, j) => {
4498
4633
  }
4499
4634
  return ok(out);
4500
4635
  };
4501
- var decodeBindingString = (p, j) => decodeBinding(p, j);
4502
- var decodeBindingBool = (p, j) => decodeBinding(p, j);
4636
+ var decodeBindingString = (p, j) => decodeBinding(p, j, requireString, "");
4637
+ var decodeBindingBool = (p, j) => decodeBinding(p, j, requireBool, false);
4638
+ var decodeBindingFloat = (p, j) => decodeBinding(p, j, requireFloat, 0);
4639
+ var decodeBindingInt = (p, j) => decodeBinding(p, j, requireInt, 0);
4503
4640
  var OPTIONS_PLACEHOLDER = [
4504
4641
  { value: OPAQUE2, label: { kind: "Literal", value: OPAQUE2 } }
4505
4642
  ];
@@ -4842,7 +4979,14 @@ var decodeMetricSpec = (path, j) => {
4842
4979
  const f = fo.value;
4843
4980
  const label = reqField(path, f, "label", "Metric label TextSource", decodeTextSource);
4844
4981
  if (!label.ok) return label;
4845
- const source = reqFieldAliased(path, f, "value", ["data"], "Metric value binding", decodeBinding);
4982
+ const source = reqFieldAliased(
4983
+ path,
4984
+ f,
4985
+ "value",
4986
+ ["data"],
4987
+ "Metric value binding",
4988
+ decodeBindingFloat
4989
+ );
4846
4990
  if (!source.ok) {
4847
4991
  if (source.error.message.includes("expected JSON number")) {
4848
4992
  return {
@@ -4863,10 +5007,12 @@ var decodeMetricSpec = (path, j) => {
4863
5007
  if (!weight.ok) return weight;
4864
5008
  const emphasis = optField(path, f, "emphasis", decodeEmphasis);
4865
5009
  if (!emphasis.ok) return emphasis;
4866
- const trend = optField(path, f, "trend", decodeBinding);
5010
+ const trend = optField(path, f, "trend", decodeBindingFloat);
4867
5011
  if (!trend.ok) return trend;
4868
5012
  const trendFormat = optField(path, f, "trendFormat", decodeCellFormat);
4869
5013
  if (!trendFormat.ok) return trendFormat;
5014
+ const trendPolarity = optField(path, f, "trendPolarity", decodeTrendPolarity);
5015
+ if (!trendPolarity.ok) return trendPolarity;
4870
5016
  const icon = optField(path, f, "icon", decodeIconSource);
4871
5017
  if (!icon.ok) return icon;
4872
5018
  const subtext = optField(path, f, "subtext", decodeTextSource);
@@ -4880,6 +5026,7 @@ var decodeMetricSpec = (path, j) => {
4880
5026
  emphasis: emphasis.value ?? "Normal",
4881
5027
  ...trend.value !== void 0 ? { trend: trend.value } : {},
4882
5028
  ...trendFormat.value !== void 0 ? { trendFormat: trendFormat.value } : {},
5029
+ trendPolarity: trendPolarity.value ?? "HigherIsBetter",
4883
5030
  ...icon.value !== void 0 ? { icon: icon.value } : {},
4884
5031
  ...subtext.value !== void 0 ? { subtext: subtext.value } : {}
4885
5032
  });
@@ -4908,7 +5055,7 @@ var decodeLabelValueRowSpec = (path, j) => {
4908
5055
  "value",
4909
5056
  ["data"],
4910
5057
  "row Binding<float> value",
4911
- decodeBinding
5058
+ decodeBindingFloat
4912
5059
  );
4913
5060
  if (!source.ok) return source;
4914
5061
  const format = optField(path, f, "format", decodeCellFormat);
@@ -4997,6 +5144,23 @@ var decodeLinkSpec = (path, j) => {
4997
5144
  });
4998
5145
  };
4999
5146
  var decodeLinkProtection = (p, j) => bareEnum(p, j, ["email"], "LinkProtection");
5147
+ var decodeSrcSetEntry = (path, j) => {
5148
+ const fo = requireObject(path, j);
5149
+ if (!fo.ok) return fo;
5150
+ const src = reqField(
5151
+ path,
5152
+ fo.value,
5153
+ "src",
5154
+ "srcSet entry Binding<string> src",
5155
+ decodeBindingString
5156
+ );
5157
+ if (!src.ok) return src;
5158
+ const widthJ = tryField(fo.value, "width");
5159
+ if (widthJ === void 0) return missingField(path, "width", "positive intrinsic pixel width");
5160
+ if (widthJ.kind !== "JNumber" || widthJ.value <= 0 || !Number.isInteger(widthJ.value))
5161
+ return wrongType(`${path}.width`, "JSON number (positive integer pixel width)");
5162
+ return ok({ src: src.value, width: widthJ.value });
5163
+ };
5000
5164
  var decodeImageSpec = (path, j) => {
5001
5165
  const fo = requireObject(path, j);
5002
5166
  if (!fo.ok) return fo;
@@ -5007,7 +5171,90 @@ var decodeImageSpec = (path, j) => {
5007
5171
  if (!src.ok) return src;
5008
5172
  const variant = reqField(path, f, "variant", "ImageVariant", decodeImageVariant);
5009
5173
  if (!variant.ok) return variant;
5010
- return ok({ alt: alt.value, src: src.value, variant: variant.value });
5174
+ const fitJ = tryField(f, "fit");
5175
+ const fit = fitJ === void 0 ? ok("Natural") : decodeImageFit(`${path}.fit`, fitJ);
5176
+ if (!fit.ok) return fit;
5177
+ const aspectJ = tryField(f, "aspectRatio");
5178
+ const aspectRatio = aspectJ === void 0 ? ok("Natural") : decodeImageAspect(`${path}.aspectRatio`, aspectJ);
5179
+ if (!aspectRatio.ok) return aspectRatio;
5180
+ const loadingJ = tryField(f, "loading");
5181
+ const loading = loadingJ === void 0 ? ok("Eager") : decodeImageLoading(`${path}.loading`, loadingJ);
5182
+ if (!loading.ok) return loading;
5183
+ const caption = optField(path, f, "caption", decodeTextSource);
5184
+ if (!caption.ok) return caption;
5185
+ const srcSetJ = tryField(f, "srcSet");
5186
+ const srcSet = srcSetJ === void 0 ? ok([]) : (() => {
5187
+ const arr = requireArray(`${path}.srcSet`, srcSetJ);
5188
+ if (!arr.ok) return arr;
5189
+ return traverseIndexed(
5190
+ arr.value,
5191
+ (i, el) => decodeSrcSetEntry(`${path}.srcSet[${i}]`, el)
5192
+ );
5193
+ })();
5194
+ if (!srcSet.ok) return srcSet;
5195
+ const expandableJ = tryField(f, "expandable");
5196
+ const expandable = expandableJ === void 0 ? ok(false) : requireBool(`${path}.expandable`, expandableJ);
5197
+ if (!expandable.ok) return expandable;
5198
+ return ok({
5199
+ alt: alt.value,
5200
+ src: src.value,
5201
+ variant: variant.value,
5202
+ fit: fit.value,
5203
+ aspectRatio: aspectRatio.value,
5204
+ loading: loading.value,
5205
+ srcSet: srcSet.value,
5206
+ expandable: expandable.value,
5207
+ ...caption.value !== void 0 ? { caption: caption.value } : {}
5208
+ });
5209
+ };
5210
+ var decodeMediaKind = (path, j) => {
5211
+ const fo = requireObject(path, j);
5212
+ if (!fo.ok) return fo;
5213
+ const f = fo.value;
5214
+ const d = requireDiscriminator(path, f);
5215
+ if (!d.ok) return d;
5216
+ switch (d.value) {
5217
+ case "Video": {
5218
+ const autoplayJ = tryField(f, "autoplay");
5219
+ const autoplay = autoplayJ === void 0 ? ok(false) : requireBool(`${path}.autoplay`, autoplayJ);
5220
+ if (!autoplay.ok) return autoplay;
5221
+ const poster = optField(path, f, "poster", decodeBindingString);
5222
+ if (!poster.ok) return poster;
5223
+ return ok({
5224
+ $type: "Video",
5225
+ autoplay: autoplay.value,
5226
+ ...poster.value !== void 0 ? { poster: poster.value } : {}
5227
+ });
5228
+ }
5229
+ case "Audio":
5230
+ return ok({ $type: "Audio" });
5231
+ default:
5232
+ return unknownDuCase(path, d.value, "Video | Audio");
5233
+ }
5234
+ };
5235
+ var decodeMediaSpec = (path, j) => {
5236
+ const fo = requireObject(path, j);
5237
+ if (!fo.ok) return fo;
5238
+ const f = fo.value;
5239
+ const src = reqField(path, f, "src", "Media Binding<string> Src", decodeBindingString);
5240
+ if (!src.ok) return src;
5241
+ const label = reqField(path, f, "label", "Media accessible label TextSource", decodeTextSource);
5242
+ if (!label.ok) return label;
5243
+ const kind = reqField(path, f, "kind", "MediaKind (Video | Audio)", decodeMediaKind);
5244
+ if (!kind.ok) return kind;
5245
+ const controlsJ = tryField(f, "controls");
5246
+ const controls = controlsJ === void 0 ? ok(true) : requireBool(`${path}.controls`, controlsJ);
5247
+ if (!controls.ok) return controls;
5248
+ const loopJ = tryField(f, "loop");
5249
+ const loop = loopJ === void 0 ? ok(false) : requireBool(`${path}.loop`, loopJ);
5250
+ if (!loop.ok) return loop;
5251
+ return ok({
5252
+ src: src.value,
5253
+ label: label.value,
5254
+ controls: controls.value,
5255
+ loop: loop.value,
5256
+ kind: kind.value
5257
+ });
5011
5258
  };
5012
5259
  var decodeListSpec = (path, j) => {
5013
5260
  const fo = requireObject(path, j);
@@ -5151,7 +5398,7 @@ var decodeProgressSpec = (path, j) => {
5151
5398
  const fo = requireObject(path, j);
5152
5399
  if (!fo.ok) return fo;
5153
5400
  const f = fo.value;
5154
- const fraction = reqField(path, f, "fraction", "Progress fraction binding", decodeBinding);
5401
+ const fraction = reqField(path, f, "fraction", "Progress fraction binding", decodeBindingFloat);
5155
5402
  if (!fraction.ok) return fraction;
5156
5403
  const indeterminate = optField(path, f, "indeterminate", requireBool);
5157
5404
  if (!indeterminate.ok) return indeterminate;
@@ -5201,9 +5448,9 @@ var decodeDrawStyle = (path, j) => {
5201
5448
  if (!fill.ok) return fill;
5202
5449
  const stroke = optField(path, f, "stroke", decodeBindingString);
5203
5450
  if (!stroke.ok) return stroke;
5204
- const strokeWidth = optField(path, f, "strokeWidth", decodeBinding);
5451
+ const strokeWidth = optField(path, f, "strokeWidth", decodeBindingFloat);
5205
5452
  if (!strokeWidth.ok) return strokeWidth;
5206
- const opacity = optField(path, f, "opacity", decodeBinding);
5453
+ const opacity = optField(path, f, "opacity", decodeBindingFloat);
5207
5454
  if (!opacity.ok) return opacity;
5208
5455
  const textAnchor = optField(path, f, "textAnchor", decodeTextAnchor);
5209
5456
  if (!textAnchor.ok) return textAnchor;
@@ -5482,6 +5729,10 @@ var decodeDisplayKind = (path, j) => {
5482
5729
  const r = decodeImageSpec(path, j);
5483
5730
  return r.ok ? ok({ kind: "Image", spec: r.value }) : r;
5484
5731
  }
5732
+ case "Media": {
5733
+ const r = decodeMediaSpec(path, j);
5734
+ return r.ok ? ok({ kind: "Media", spec: r.value }) : r;
5735
+ }
5485
5736
  case "List": {
5486
5737
  const r = decodeListSpec(path, j);
5487
5738
  return r.ok ? ok({ kind: "List", spec: r.value }) : r;
@@ -5533,7 +5784,11 @@ var decodeFormFieldKind = (autoBind, path, j) => {
5533
5784
  return v.ok ? ok({ kind: "Text", value: v.value, ...onChangeField }) : v;
5534
5785
  }
5535
5786
  case "Number": {
5536
- const v = valueOr(decodeBinding, schema.controlValueDefaults.number, "Number value binding");
5787
+ const v = valueOr(
5788
+ decodeBindingFloat,
5789
+ schema.controlValueDefaults.number,
5790
+ "Number value binding"
5791
+ );
5537
5792
  return v.ok ? ok({ kind: "Number", value: v.value, ...onChangeField }) : v;
5538
5793
  }
5539
5794
  case "Checkbox": {
@@ -5585,7 +5840,7 @@ var decodeFormFieldKind = (autoBind, path, j) => {
5585
5840
  }
5586
5841
  case "RangedNumber": {
5587
5842
  const value = valueOr(
5588
- decodeBinding,
5843
+ decodeBindingFloat,
5589
5844
  schema.controlValueDefaults.number,
5590
5845
  "RangedNumber value binding"
5591
5846
  );
@@ -5699,6 +5954,77 @@ var decodeFormFieldKind = (autoBind, path, j) => {
5699
5954
  return unknownDuCase(path, d.value, WRONG_FORM_FIELD_KIND_HINT);
5700
5955
  }
5701
5956
  };
5957
+ var TEXT_FORMATS = ["email", "url", "tel"];
5958
+ var COMPARE_OPS = ["eq", "neq", "lt", "lte", "gt", "gte"];
5959
+ var decodeTextFormat = (path, j) => bareEnum(path, j, TEXT_FORMATS, "TextFormat");
5960
+ var decodeCompareOp = (path, j) => bareEnum(path, j, COMPARE_OPS, "CompareOp");
5961
+ var decodeCompareRule = (path, j) => {
5962
+ const fo = requireObject(path, j);
5963
+ if (!fo.ok) return fo;
5964
+ const f = fo.value;
5965
+ const op = reqField(path, f, "op", "CompareOp", decodeCompareOp);
5966
+ if (!op.ok) return op;
5967
+ const against = reqField(path, f, "against", "Binding", (p, v) => decodeBinding(p, v));
5968
+ if (!against.ok) return against;
5969
+ return ok({ op: op.value, against: against.value });
5970
+ };
5971
+ var decodeFieldRule = (path, j) => {
5972
+ const fo = requireObject(path, j);
5973
+ if (!fo.ok) return fo;
5974
+ const f = fo.value;
5975
+ const format = optField(path, f, "format", decodeTextFormat);
5976
+ if (!format.ok) return format;
5977
+ const pattern = optField(path, f, "pattern", requireString);
5978
+ if (!pattern.ok) return pattern;
5979
+ const minLength = optField(path, f, "minLength", requireInt);
5980
+ if (!minLength.ok) return minLength;
5981
+ const maxLength = optField(path, f, "maxLength", requireInt);
5982
+ if (!maxLength.ok) return maxLength;
5983
+ const compare = optField(path, f, "compare", decodeCompareRule);
5984
+ if (!compare.ok) return compare;
5985
+ const message = optField(path, f, "message", decodeTextSource);
5986
+ if (!message.ok) return message;
5987
+ const constrains = format.value !== void 0 || pattern.value !== void 0 || minLength.value !== void 0 || maxLength.value !== void 0 || compare.value !== void 0;
5988
+ if (!constrains)
5989
+ return makeError(
5990
+ "WRONG_TYPE",
5991
+ path,
5992
+ "a rule that constrains nothing is a defect, not a no-op \u2014 declare at least one of format / pattern / minLength / maxLength / compare, or omit 'rule' entirely",
5993
+ "FieldRule with at least one constraint slot"
5994
+ );
5995
+ if (minLength.value !== void 0 && maxLength.value !== void 0 && minLength.value > maxLength.value)
5996
+ return makeError(
5997
+ "WRONG_TYPE",
5998
+ path,
5999
+ `minLength ${minLength.value} is above maxLength ${maxLength.value} \u2014 an inverted length bound admits no value at all, so the field could never be submitted`,
6000
+ "minLength <= maxLength"
6001
+ );
6002
+ return ok({
6003
+ ...format.value !== void 0 ? { format: format.value } : {},
6004
+ ...pattern.value !== void 0 ? { pattern: pattern.value } : {},
6005
+ ...minLength.value !== void 0 ? { minLength: minLength.value } : {},
6006
+ ...maxLength.value !== void 0 ? { maxLength: maxLength.value } : {},
6007
+ ...compare.value !== void 0 ? { compare: compare.value } : {},
6008
+ ...message.value !== void 0 ? { message: message.value } : {}
6009
+ });
6010
+ };
6011
+ var FORM_FIELD_NEAR_MISSES = [
6012
+ ["validation", "rule"],
6013
+ ["constraints", "rule"],
6014
+ ["validate", "rule"]
6015
+ ];
6016
+ var checkFormFieldNearMisses = (path, f) => {
6017
+ for (const [name, canonical] of FORM_FIELD_NEAR_MISSES) {
6018
+ if (tryField(f, name) !== void 0)
6019
+ return makeError(
6020
+ "WRONG_TYPE",
6021
+ `${path}.${name}`,
6022
+ `'${name}' is not part of the form vocabulary \u2014 it would be ignored, not honoured, and the field would accept anything`,
6023
+ canonical
6024
+ );
6025
+ }
6026
+ return ok(void 0);
6027
+ };
5702
6028
  var decodeFormField = (path, j) => {
5703
6029
  const fo = requireObject(path, j);
5704
6030
  if (!fo.ok) return fo;
@@ -5720,12 +6046,17 @@ var decodeFormField = (path, j) => {
5720
6046
  if (!required.ok) return required;
5721
6047
  const help = optField(path, f, "help", decodeTextSource);
5722
6048
  if (!help.ok) return help;
6049
+ const nm = checkFormFieldNearMisses(path, f);
6050
+ if (!nm.ok) return nm;
6051
+ const rule = optField(path, f, "rule", decodeFieldRule);
6052
+ if (!rule.ok) return rule;
5723
6053
  return ok({
5724
6054
  id: id.value,
5725
6055
  kind: kind.value,
5726
6056
  label: label.value,
5727
6057
  required: required.value,
5728
- ...help.value !== void 0 ? { help: help.value } : {}
6058
+ ...help.value !== void 0 ? { help: help.value } : {},
6059
+ ...rule.value !== void 0 ? { rule: rule.value } : {}
5729
6060
  });
5730
6061
  };
5731
6062
  var decodeFormSpec = (path, j) => {
@@ -6464,10 +6795,23 @@ var decodeBoxLayout = (path, j) => {
6464
6795
  ...templateColumns.value !== void 0 ? { templateColumns: templateColumns.value } : {}
6465
6796
  });
6466
6797
  }
6798
+ case "Masonry": {
6799
+ const colsJ = tryField(f, "cols") ?? tryField(f, "columns");
6800
+ if (colsJ === void 0) return missingField(path, "cols", "positive integer column count");
6801
+ if (colsJ.kind !== "JNumber" || colsJ.value <= 0 || !Number.isInteger(colsJ.value))
6802
+ return wrongType(`${path}.cols`, "JSON number (positive integer column count)");
6803
+ const masonryGap = optField(path, f, "gap", requireInt);
6804
+ if (!masonryGap.ok) return masonryGap;
6805
+ return ok({
6806
+ kind: "Masonry",
6807
+ cols: colsJ.value,
6808
+ ...masonryGap.value !== void 0 ? { gap: masonryGap.value } : {}
6809
+ });
6810
+ }
6467
6811
  case "Auto":
6468
6812
  return ok({ kind: "Auto" });
6469
6813
  default:
6470
- return unknownDuCase(path, d.value, "Flex | Grid | Auto");
6814
+ return unknownDuCase(path, d.value, "Flex | Grid | Masonry | Auto");
6471
6815
  }
6472
6816
  };
6473
6817
  var decodeBoxRole = (path, j) => {
@@ -6480,7 +6824,7 @@ var decodeBoxRole = (path, j) => {
6480
6824
  case "Separator":
6481
6825
  return ok(s.value);
6482
6826
  default:
6483
- return unknownDuCase(path, s.value, "Group | Card | Dashboard | Separator");
6827
+ return unknownEnumCase(path, s.value, "Group | Card | Dashboard | Separator");
6484
6828
  }
6485
6829
  };
6486
6830
  var decodeBox = (path, j) => {
@@ -6563,7 +6907,7 @@ var decodeTabsSpec = (path, j) => {
6563
6907
  }
6564
6908
  const activeTag = optField(path, f, "activeTag", decodeBindingString);
6565
6909
  if (!activeTag.ok) return activeTag;
6566
- const activeIndex = optField(path, f, "activeIndex", decodeBinding);
6910
+ const activeIndex = optField(path, f, "activeIndex", decodeBindingInt);
6567
6911
  if (!activeIndex.ok) return activeIndex;
6568
6912
  return ok({
6569
6913
  children: children.value,
@@ -6580,7 +6924,7 @@ var decodeStepperSpec = (path, j) => {
6580
6924
  const fo = requireObject(path, j);
6581
6925
  if (!fo.ok) return fo;
6582
6926
  const f = fo.value;
6583
- const activeStep = reqField(path, f, "activeStep", "activeStep binding", decodeBinding);
6927
+ const activeStep = reqField(path, f, "activeStep", "activeStep binding", decodeBindingInt);
6584
6928
  if (!activeStep.ok) return activeStep;
6585
6929
  const children = decodeChildren(path, f);
6586
6930
  if (!children.ok) return children;
@@ -6745,7 +7089,7 @@ var decodeContentHash = (path, j) => {
6745
7089
  if (!strictnessR.ok) return strictnessR;
6746
7090
  const s = strictnessR.value;
6747
7091
  if (s !== "StrictReplay" && s !== "AdvisoryWarning" && s !== "Enforced") {
6748
- return unknownDuCase(`${path}.strictness`, s, "StrictReplay | AdvisoryWarning | Enforced");
7092
+ return unknownEnumCase(`${path}.strictness`, s, "StrictReplay | AdvisoryWarning | Enforced");
6749
7093
  }
6750
7094
  return ok({ algorithm: algorithm.value, hash: hash.value, strictness: s });
6751
7095
  };
@@ -6876,11 +7220,11 @@ var decodeEffectClass = (path, j) => {
6876
7220
  const host = reqField(path, fo.value, "hostEffect", "EffectClass hostEffect", requireString);
6877
7221
  if (!host.ok) return host;
6878
7222
  if (host.value !== "Pure" && host.value !== "ReadsHost" && host.value !== "WritesHost")
6879
- return unknownDuCase(`${path}.hostEffect`, host.value, "Pure | ReadsHost | WritesHost");
7223
+ return unknownEnumCase(`${path}.hostEffect`, host.value, "Pure | ReadsHost | WritesHost");
6880
7224
  const det = reqField(path, fo.value, "determinism", "EffectClass determinism", requireString);
6881
7225
  if (!det.ok) return det;
6882
7226
  if (det.value !== "Deterministic" && det.value !== "Clock" && det.value !== "Random" && det.value !== "Network")
6883
- return unknownDuCase(
7227
+ return unknownEnumCase(
6884
7228
  `${path}.determinism`,
6885
7229
  det.value,
6886
7230
  "Deterministic | Clock | Random | Network"
@@ -6900,6 +7244,14 @@ var decodeNodeKind = (path, j) => {
6900
7244
  const f = fo.value;
6901
7245
  const d = requireDiscriminator(path, f);
6902
7246
  if (!d.ok) return d;
7247
+ if (schema.narrows(walkPolicy) && schema.NODE_KIND_NAMES.includes(d.value) && !schema.admits(walkPolicy, d.value)) {
7248
+ return makeError(
7249
+ "KIND_NOT_ADMITTED",
7250
+ `${path}.$type`,
7251
+ `node kind '${d.value}' is not admitted by decode policy '${walkPolicy.identity}'`,
7252
+ schema.policyHint(walkPolicy)
7253
+ );
7254
+ }
6903
7255
  switch (d.value) {
6904
7256
  // The four behavioural categories are flat on the wire (WIRE_FORMAT §3.2):
6905
7257
  // the `kind` object carries the primitive discriminator directly, so route
@@ -6929,6 +7281,7 @@ var decodeNodeKind = (path, j) => {
6929
7281
  case "Fact":
6930
7282
  case "Link":
6931
7283
  case "Image":
7284
+ case "Media":
6932
7285
  case "List":
6933
7286
  case "Toast":
6934
7287
  case "CodeBlock":
@@ -7204,10 +7557,54 @@ var decodeSemanticStyle = (path, j) => {
7204
7557
  voice: voice.value ?? "Default"
7205
7558
  });
7206
7559
  };
7560
+ var A11Y_NEAR_MISSES = [
7561
+ [
7562
+ "aria-label",
7563
+ "label \u2014 the accessible name, a Binding<string> (a bare string is the \xA73.6 shorthand)"
7564
+ ],
7565
+ [
7566
+ "ariaLabel",
7567
+ "label \u2014 the accessible name, a Binding<string> (a bare string is the \xA73.6 shorthand)"
7568
+ ],
7569
+ ["aria-labelledby", "labelledBy \u2014 the id of a sibling node whose text carries the name"],
7570
+ ["ariaLabelledBy", "labelledBy \u2014 the id of a sibling node whose text carries the name"],
7571
+ [
7572
+ "labelledby",
7573
+ "labelledBy \u2014 the slot name is camelCase on the wire, not the ARIA attribute spelling"
7574
+ ],
7575
+ ["aria-describedby", "describedBy \u2014 the id of a sibling node whose text carries the description"],
7576
+ ["ariaDescribedBy", "describedBy \u2014 the id of a sibling node whose text carries the description"],
7577
+ [
7578
+ "describedby",
7579
+ "describedBy \u2014 the slot name is camelCase on the wire, not the ARIA attribute spelling"
7580
+ ],
7581
+ ["aria-role", "role \u2014 the ARIA role NAME as a bare string"],
7582
+ ["ariaRole", "role \u2014 the ARIA role NAME as a bare string"],
7583
+ ["aria-live", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7584
+ ["ariaLive", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7585
+ ["live", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7586
+ ["liveregion", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7587
+ ["aria-hidden", "hidden \u2014 a Binding<bool> (a bare bool is the \xA73.6 shorthand)"],
7588
+ ["ariaHidden", "hidden \u2014 a Binding<bool> (a bare bool is the \xA73.6 shorthand)"]
7589
+ ];
7590
+ var checkA11yNearMisses = (path, f) => {
7591
+ for (const [name, canonical] of A11Y_NEAR_MISSES) {
7592
+ if (tryField(f, name) !== void 0)
7593
+ return makeError(
7594
+ "WRONG_TYPE",
7595
+ `${path}.${name}`,
7596
+ `'${name}' is not part of the accessibility vocabulary \u2014 it would be ignored, not honoured, and the intent would reach assistive technology as nothing at all`,
7597
+ canonical
7598
+ );
7599
+ }
7600
+ return ok(void 0);
7601
+ };
7207
7602
  var decodeAccessibility = (path, j) => {
7208
7603
  const fo = requireObject(path, j);
7209
7604
  if (!fo.ok) return fo;
7210
7605
  const f = fo.value;
7606
+ const nearMiss2 = checkA11yNearMisses(path, f);
7607
+ if (!nearMiss2.ok) return nearMiss2;
7211
7608
  const label = optField(path, f, "label", decodeBindingString);
7212
7609
  if (!label.ok) return label;
7213
7610
  const labelledBy = optField(path, f, "labelledBy", requireString);
@@ -7252,7 +7649,39 @@ var placeholderClosureNode = {
7252
7649
  voice: "Default"
7253
7650
  }
7254
7651
  };
7652
+ var walkDepth = 0;
7653
+ var walkNodes = 0;
7654
+ var opDepth = 0;
7655
+ var walkPolicy = schema.admitAll;
7656
+ var resetWalk = (policy = schema.admitAll) => {
7657
+ walkDepth = 0;
7658
+ walkNodes = 0;
7659
+ opDepth = 0;
7660
+ walkPolicy = policy;
7661
+ };
7662
+ var limitError = (path, message, expected) => makeError("LIMIT_EXCEEDED", path, message, expected);
7255
7663
  var decodeNodeAst = (path, j) => {
7664
+ if (walkDepth >= schema.MAX_NODE_DEPTH) {
7665
+ return limitError(
7666
+ path,
7667
+ `node nesting deeper than the wire limit MAX_NODE_DEPTH = ${schema.MAX_NODE_DEPTH}`,
7668
+ `a tree nesting nodes no more than ${schema.MAX_NODE_DEPTH} levels deep`
7669
+ );
7670
+ }
7671
+ walkNodes += 1;
7672
+ if (walkNodes > schema.MAX_NODES) {
7673
+ return limitError(
7674
+ path,
7675
+ `the document holds more than the wire limit MAX_NODES = ${schema.MAX_NODES} nodes`,
7676
+ `a tree of no more than ${schema.MAX_NODES} nodes in total`
7677
+ );
7678
+ }
7679
+ walkDepth += 1;
7680
+ const r = decodeNodeAstInner(path, j);
7681
+ walkDepth -= 1;
7682
+ return r;
7683
+ };
7684
+ var decodeNodeAstInner = (path, j) => {
7256
7685
  const fo = requireObject(path, j);
7257
7686
  if (!fo.ok) return fo;
7258
7687
  const f = fo.value;
@@ -7280,6 +7709,25 @@ var decodeNodeAst = (path, j) => {
7280
7709
  });
7281
7710
  };
7282
7711
  var decodeTreeOpAst = (path, j) => {
7712
+ if (opDepth >= schema.MAX_NODE_DEPTH) {
7713
+ return limitError(
7714
+ path,
7715
+ `op nesting deeper than the wire limit MAX_NODE_DEPTH = ${schema.MAX_NODE_DEPTH}`,
7716
+ `a Batch nesting ops no more than ${schema.MAX_NODE_DEPTH} levels deep`
7717
+ );
7718
+ }
7719
+ opDepth += 1;
7720
+ const r = decodeTreeOpAstInner(path, j);
7721
+ opDepth -= 1;
7722
+ return r;
7723
+ };
7724
+ var retiredPositionalField = (path, f, name, opKind) => tryField(f, name) !== void 0 ? makeError(
7725
+ "WRONG_TYPE",
7726
+ `${path}.${name}`,
7727
+ `'${name}' was removed from the wire format \u2014 ${opKind} appends, and order is stated by naming ids with ReorderChildren`,
7728
+ "a Batch of the structural op followed by ReorderChildren"
7729
+ ) : ok(void 0);
7730
+ var decodeTreeOpAstInner = (path, j) => {
7283
7731
  const fo = requireObject(path, j);
7284
7732
  if (!fo.ok) return fo;
7285
7733
  const f = fo.value;
@@ -7332,6 +7780,8 @@ var decodeTreeOpAst = (path, j) => {
7332
7780
  return state.ok ? ok({ kind: "UpdateState", target: t.value, state: state.value }) : state;
7333
7781
  }
7334
7782
  case "InsertChild": {
7783
+ const retired = retiredPositionalField(path, f, "position", "InsertChild");
7784
+ if (!retired.ok) return retired;
7335
7785
  const parentJ = reqField(path, f, "parentId", "parent NodeId", requireString);
7336
7786
  if (!parentJ.ok) return parentJ;
7337
7787
  const child = reqField(path, f, "child", "child Node object", decodeNodeAst);
@@ -7346,6 +7796,8 @@ var decodeTreeOpAst = (path, j) => {
7346
7796
  return t.ok ? ok({ kind: "RemoveNode", target: t.value }) : t;
7347
7797
  }
7348
7798
  case "MoveNode": {
7799
+ const retired = retiredPositionalField(path, f, "newPosition", "MoveNode");
7800
+ if (!retired.ok) return retired;
7349
7801
  const t = target();
7350
7802
  if (!t.ok) return t;
7351
7803
  const newParent = reqField(path, f, "newParentId", "new parent NodeId", requireString);
@@ -7427,6 +7879,8 @@ var coerce = {
7427
7879
  tone: (v) => viaAst(v, decodeTone),
7428
7880
  weight: (v) => viaAst(v, decodeWeight),
7429
7881
  emphasis: (v) => viaAst(v, decodeEmphasis),
7882
+ /** `Metric.TrendPolarity` (Phase 867) - the UpdateProp twin of `decodeTrendPolarity`. */
7883
+ trendPolarity: (v) => viaAst(v, decodeTrendPolarity),
7430
7884
  /**
7431
7885
  * The behavioural `emphasis` BOOL on Fact / LabelValueRow — the UpdateProp
7432
7886
  * twin of `decodeEmphasisFlag`, so a TreeOp edit gets the same
@@ -7447,13 +7901,18 @@ var invalidJson = (parseMessage) => makeError(
7447
7901
  `input is not valid JSON: ${parseMessage}`,
7448
7902
  "well-formed JSON object per the canonical-JSON shape"
7449
7903
  );
7450
- var decodeNode = (json) => {
7904
+ var parseFailure = (e) => e.limit === true ? makeError("LIMIT_EXCEEDED", "$", e.message, "a document within the WIRE_FORMAT \xA721 limits") : invalidJson(e.message);
7905
+ var decodeNode = (json, policy) => {
7451
7906
  const parsed = parse(json);
7452
- return parsed.ok ? decodeNodeAst("$", parsed.value) : invalidJson(parsed.error.message);
7907
+ if (!parsed.ok) return parseFailure(parsed.error);
7908
+ resetWalk(policy);
7909
+ return decodeNodeAst("$", parsed.value);
7453
7910
  };
7454
- var decodeOp = (json) => {
7911
+ var decodeOp = (json, policy) => {
7455
7912
  const parsed = parse(json);
7456
- return parsed.ok ? decodeTreeOpAst("$", parsed.value) : invalidJson(parsed.error.message);
7913
+ if (!parsed.ok) return parseFailure(parsed.error);
7914
+ resetWalk(policy);
7915
+ return decodeTreeOpAst("$", parsed.value);
7457
7916
  };
7458
7917
 
7459
7918
  // src/apply.ts
@@ -7620,6 +8079,11 @@ var updateField = (field2, value, kind) => {
7620
8079
  coerce.cellFormat(value),
7621
8080
  (x) => disp({ kind: "Metric", spec: { ...s, trendFormat: x } })
7622
8081
  );
8082
+ case "TrendPolarity":
8083
+ return patch(
8084
+ coerce.trendPolarity(value),
8085
+ (x) => disp({ kind: "Metric", spec: { ...s, trendPolarity: x } })
8086
+ );
7623
8087
  case "Icon":
7624
8088
  return patch(
7625
8089
  coerce.iconSource(value),
@@ -7903,6 +8367,12 @@ var updateField = (field2, value, kind) => {
7903
8367
  (x) => lay({ kind: "Box", spec: { ...s, layout: { ...mode, cols: x } } })
7904
8368
  );
7905
8369
  }
8370
+ if (field2 === "Cols" && mode.kind === "Masonry") {
8371
+ return patch(
8372
+ coerce.int(value),
8373
+ (x) => lay({ kind: "Box", spec: { ...s, layout: { ...mode, cols: x } } })
8374
+ );
8375
+ }
7906
8376
  if (field2 === "TemplateColumns" && mode.kind === "Grid") {
7907
8377
  return patch(
7908
8378
  coerce.string(value),
@@ -9767,9 +10237,64 @@ var validateAnswerDocument = (json) => {
9767
10237
  if (!answer.ok) return answer;
9768
10238
  return validateAnswerAt("$.answer", contract.value, answer.value);
9769
10239
  };
10240
+ var HOST_RESERVED_PREFIX = "host.";
10241
+ var isHostReserved = (key) => typeof key === "string" && key.startsWith(HOST_RESERVED_PREFIX);
10242
+ var isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
10243
+ var isStateDeclaration = (v) => isPlainObject(v) && v["kind"] === "State" && typeof v["key"] === "string" && "defaultValue" in v && v["defaultValue"] !== void 0;
10244
+ var controlDefaults = Object.values(schema.controlValueDefaults);
10245
+ var deepEqual = (a, b) => {
10246
+ try {
10247
+ return JSON.stringify(a) === JSON.stringify(b);
10248
+ } catch {
10249
+ return false;
10250
+ }
10251
+ };
10252
+ var isAutoBoundFieldValue = (binding2, fieldId) => binding2.key === fieldId && controlDefaults.some((d) => deepEqual(d, binding2.defaultValue));
10253
+ var isEmptyDeclaration = (value) => {
10254
+ if (Array.isArray(value)) return value.length === 0;
10255
+ if (isPlainObject(value)) {
10256
+ const columns = value["columns"];
10257
+ if (isPlainObject(columns)) return Object.keys(columns).length === 0;
10258
+ }
10259
+ return false;
10260
+ };
10261
+ var collectStateSeeds = (tree) => {
10262
+ const seeds = {};
10263
+ const seen = /* @__PURE__ */ new Set();
10264
+ const visit = (value, autoBindFieldId) => {
10265
+ if (value === null || typeof value !== "object") return;
10266
+ if (seen.has(value)) return;
10267
+ seen.add(value);
10268
+ if (Array.isArray(value)) {
10269
+ for (const item of value) visit(item, autoBindFieldId);
10270
+ return;
10271
+ }
10272
+ const obj = value;
10273
+ if (isStateDeclaration(obj)) {
10274
+ const key = obj.key;
10275
+ const shouldSkip = isHostReserved(key) || Object.prototype.hasOwnProperty.call(seeds, key) || isEmptyDeclaration(obj.defaultValue) || autoBindFieldId !== void 0 && isAutoBoundFieldValue(obj, autoBindFieldId);
10276
+ if (!shouldSkip) seeds[key] = obj.defaultValue;
10277
+ }
10278
+ const record = obj;
10279
+ const ownId = record["id"];
10280
+ const fieldId = typeof ownId === "string" && typeof record["required"] === "boolean" ? ownId : void 0;
10281
+ for (const [k, v] of Object.entries(obj)) {
10282
+ const established = k === "kind" && fieldId !== void 0 ? fieldId : void 0;
10283
+ visit(v, established ?? autoBindFieldId);
10284
+ }
10285
+ };
10286
+ visit(tree, void 0);
10287
+ return seeds;
10288
+ };
10289
+ var withStateSeeds = (tree, sources) => {
10290
+ const seeds = collectStateSeeds(tree);
10291
+ if (Object.keys(seeds).length === 0) return sources;
10292
+ return { ...sources, state: { ...seeds, ...sources.state ?? {} } };
10293
+ };
9770
10294
 
9771
10295
  exports.ELICITATION_KEY = ELICITATION_KEY;
9772
10296
  exports.ELICITATION_VERSION = ELICITATION_VERSION;
10297
+ exports.HOST_RESERVED_PREFIX = HOST_RESERVED_PREFIX;
9773
10298
  exports.PAYLOAD_KEY = PAYLOAD_KEY;
9774
10299
  exports.PROFILE_KEY = PROFILE_KEY;
9775
10300
  exports.REQUIRED_PROFILE_KEY = REQUIRED_PROFILE_KEY;
@@ -9777,6 +10302,7 @@ exports.apply = apply;
9777
10302
  exports.canPlace = canPlace;
9778
10303
  exports.cellString = cellString;
9779
10304
  exports.coerce = coerce;
10305
+ exports.collectStateSeeds = collectStateSeeds;
9780
10306
  exports.coreV1 = coreV1;
9781
10307
  exports.decodeDagRecord = decodeDagRecord;
9782
10308
  exports.decodeElicitation = decodeElicitation;
@@ -9828,5 +10354,6 @@ exports.tryParseProfile = tryParseProfile;
9828
10354
  exports.validateAnswer = validateAnswer;
9829
10355
  exports.validateAnswerAt = validateAnswerAt;
9830
10356
  exports.validateAnswerDocument = validateAnswerDocument;
10357
+ exports.withStateSeeds = withStateSeeds;
9831
10358
  //# sourceMappingURL=index.cjs.map
9832
10359
  //# sourceMappingURL=index.cjs.map