@wix/himalaya-cli 0.1015.0 → 0.1017.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +67 -1
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts +45 -3
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +18 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +7 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/genie-chat/src/index.d.ts +51 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +21 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +79 -6
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-genie-chat.mjs +23 -0
  9. package/dist/cli.mjs +1293 -679
  10. package/dist/preview-assets.generated.bin +0 -0
  11. package/guides/component-reference.json +1 -1
  12. package/guides/component-reference.md +25 -9
  13. package/guides/designing-himi-screens.md +6 -4
  14. package/guides/headless-loop.md +1 -0
  15. package/guides/sdk-reference.json +47 -5
  16. package/guides/tier-5-add-a-screen.md +40 -13
  17. package/guides/wix-api-usage.md +9 -0
  18. package/package.json +2 -2
  19. package/templates/beauty-salon/dev/index.ts +252 -7
  20. package/templates/beauty-salon/tier5-src/himi-booking-bookings/index.ts +5 -2
  21. package/templates/beauty-salon-owner/config.ts +1 -1
  22. package/templates/beauty-salon-owner/dev/index.ts +419 -2
  23. package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +226 -9
  24. package/templates/beauty-salon-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  25. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  26. package/templates/branded-lite/dev/index.ts +487 -14
  27. package/templates/branded-lite/tier5-src/himi-booking-bookings/index.ts +5 -2
  28. package/templates/community-club/dev/index.ts +196 -13
  29. package/templates/community-club-owner/config.ts +1 -1
  30. package/templates/community-club-owner/dev/index.ts +402 -2
  31. package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +226 -9
  32. package/templates/community-club-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  33. package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  34. package/templates/events-meetups/dev/index.ts +196 -13
  35. package/templates/events-meetups-owner/config.ts +1 -1
  36. package/templates/events-meetups-owner/dev/index.ts +348 -2
  37. package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +226 -9
  38. package/templates/events-meetups-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  39. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  40. package/templates/gym-fitness/dev/index.ts +324 -12
  41. package/templates/gym-fitness/tier5-src/himi-booking-bookings/index.ts +5 -2
  42. package/templates/gym-fitness-owner/config.ts +1 -1
  43. package/templates/gym-fitness-owner/dev/index.ts +440 -2
  44. package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +226 -9
  45. package/templates/gym-fitness-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  46. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  47. package/templates/himi-chat/dev/index.ts +2 -2
  48. package/templates/nonprofit-cause/dev/index.ts +212 -13
  49. package/templates/nonprofit-cause-owner/config.ts +1 -1
  50. package/templates/nonprofit-cause-owner/dev/index.ts +386 -2
  51. package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +226 -9
  52. package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  53. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  54. package/templates/owner-lite/config.ts +1 -1
  55. package/templates/owner-lite/dev/index.ts +446 -2
  56. package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +226 -9
  57. package/templates/owner-lite/tier5-src/_shared/aria-client-tools.ts +234 -0
  58. package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  59. package/templates/podcast-creator/dev/index.ts +206 -13
  60. package/templates/podcast-creator-owner/config.ts +1 -1
  61. package/templates/podcast-creator-owner/dev/index.ts +402 -2
  62. package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +226 -9
  63. package/templates/podcast-creator-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  64. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  65. package/templates/portfolio-creative/dev/index.ts +249 -11
  66. package/templates/portfolio-creative-owner/config.ts +1 -1
  67. package/templates/portfolio-creative-owner/dev/index.ts +419 -2
  68. package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +226 -9
  69. package/templates/portfolio-creative-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  70. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  71. package/templates/restaurant/dev/index.ts +219 -11
  72. package/templates/restaurant-owner/config.ts +1 -1
  73. package/templates/restaurant-owner/dev/index.ts +440 -2
  74. package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +226 -9
  75. package/templates/restaurant-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  76. package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  77. package/templates/retail-store/dev/index.ts +159 -6
  78. package/templates/retail-store-owner/config.ts +1 -1
  79. package/templates/retail-store-owner/dev/index.ts +381 -2
  80. package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +226 -9
  81. package/templates/retail-store-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  82. package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
  83. package/templates/yoga-studio/dev/index.ts +284 -12
  84. package/templates/yoga-studio/tier5-src/himi-booking-bookings/index.ts +5 -2
  85. package/templates/yoga-studio-owner/config.ts +1 -1
  86. package/templates/yoga-studio-owner/dev/index.ts +386 -2
  87. package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +226 -9
  88. package/templates/yoga-studio-owner/tier5-src/_shared/aria-client-tools.ts +234 -0
  89. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -0
package/dist/cli.mjs CHANGED
@@ -5345,6 +5345,7 @@ function walk(node, registry, path2, out) {
5345
5345
  var SYSTEM_FONT_FAMILY;
5346
5346
  var init_tokens = __esm({
5347
5347
  "../../core/ts/src/tokens.ts"() {
5348
+ "use strict";
5348
5349
  SYSTEM_FONT_FAMILY = "$system";
5349
5350
  }
5350
5351
  });
@@ -6516,6 +6517,260 @@ var init_l10n_strings = __esm({
6516
6517
  }
6517
6518
  });
6518
6519
 
6520
+ // ../../core/dev-server/src/a11y-contract.ts
6521
+ function isDynamicValue(v) {
6522
+ return typeof v === "string" && (v.startsWith("$service:") || v.startsWith("$item") || v.startsWith("$flag") || v.startsWith("$state") || v.startsWith("$t:"));
6523
+ }
6524
+ function isActionEnvelope(v) {
6525
+ return !!v && typeof v === "object" && !Array.isArray(v) && typeof v.actionId === "string";
6526
+ }
6527
+ function own(bag, key2) {
6528
+ return Object.prototype.hasOwnProperty.call(bag, key2) ? bag[key2] : void 0;
6529
+ }
6530
+ function atExposureOf(node) {
6531
+ const mods = node.modifiers;
6532
+ if (!mods || typeof mods !== "object" || Array.isArray(mods)) return "exposed";
6533
+ const m = mods;
6534
+ if (m.accessibilityHidden === true) return "hidden";
6535
+ if (m.accessibilityRole === "decorative" && !isInteractive(node)) return "decorative";
6536
+ return "exposed";
6537
+ }
6538
+ function isInteractive(node) {
6539
+ const raw = node.modifiers;
6540
+ const mods = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
6541
+ return TAP_MODIFIER_KEYS.some(
6542
+ (k) => !!mods[k] && typeof mods[k] === "object" || !!node[k] && typeof node[k] === "object"
6543
+ );
6544
+ }
6545
+ function ownName(n) {
6546
+ for (const k of ACCESSIBLE_NAME_KEYS) {
6547
+ const v = own(n, k);
6548
+ if (typeof v === "string" && v.trim() !== "" || isDynamicValue(v)) return true;
6549
+ }
6550
+ for (const k of CONTENT_ARM_KEYS) {
6551
+ const v = own(n, k);
6552
+ if (v !== void 0 && v !== null) return true;
6553
+ }
6554
+ return false;
6555
+ }
6556
+ function isWireWrapper(n) {
6557
+ return componentTypeOf(n) !== null && typeof n.body?.type === "string";
6558
+ }
6559
+ function nameIn(node, at) {
6560
+ if (!node || typeof node !== "object") return false;
6561
+ if (Array.isArray(node)) return node.some((v) => nameIn(v, at));
6562
+ if (isActionEnvelope(node)) return false;
6563
+ const n = node;
6564
+ let readOwnKeys = true;
6565
+ if (at === "descendant") {
6566
+ const exposure = atExposureOf(n);
6567
+ if (exposure === "hidden") return false;
6568
+ if (exposure === "decorative") readOwnKeys = false;
6569
+ } else if (at === "decorativeOwn") {
6570
+ if (componentTypeOf(n) !== null) return nameIn(n, "descendant");
6571
+ readOwnKeys = false;
6572
+ }
6573
+ if (readOwnKeys) {
6574
+ if (ownName(n)) return true;
6575
+ return Object.values(n).some((v) => nameIn(v, "descendant"));
6576
+ }
6577
+ const wrapper = isWireWrapper(n);
6578
+ return Object.entries(n).some(([k, v]) => {
6579
+ if (k === "body" && wrapper && v && typeof v === "object" && !Array.isArray(v)) {
6580
+ return Object.values(v).some((w) => nameIn(w, "decorativeOwn"));
6581
+ }
6582
+ return nameIn(v, "decorativeOwn");
6583
+ });
6584
+ }
6585
+ function hasAccessibleName(node) {
6586
+ return nameIn(node, "self");
6587
+ }
6588
+ function componentTypeOf(node) {
6589
+ const body = node.body;
6590
+ if (body && typeof body === "object" && !Array.isArray(body) && typeof body.type === "string" && typeof body.package === "string") {
6591
+ return body.type;
6592
+ }
6593
+ if (typeof node.type === "string" && typeof node.package === "string") return node.type;
6594
+ return null;
6595
+ }
6596
+ function accessibleNameGaps(descriptor, options = {}) {
6597
+ const out = [];
6598
+ const interactiveOnly = options.interactiveOnly === true;
6599
+ const walk2 = (node, path2, key2, suppressed = false) => {
6600
+ if (!node || typeof node !== "object") return;
6601
+ if (Array.isArray(node)) {
6602
+ node.forEach((v, i) => walk2(v, `${path2}[${i}]`, key2, suppressed));
6603
+ return;
6604
+ }
6605
+ const n = node;
6606
+ if (key2 === "args" || key2 === "input" && path2 === "input") return;
6607
+ const rawMods = n.modifiers;
6608
+ const hasMods = !!rawMods && typeof rawMods === "object" && !Array.isArray(rawMods);
6609
+ const exposure = atExposureOf(n);
6610
+ if (exposure === "hidden") return;
6611
+ const viaBody = componentTypeOf(n) !== null && typeof n.body?.type === "string";
6612
+ const bodyMods = viaBody ? n.body.modifiers : void 0;
6613
+ const deferToBody = viaBody && !hasMods && !!bodyMods && typeof bodyMods === "object" && !Array.isArray(bodyMods);
6614
+ if (key2 !== "modifiers" && !suppressed && !deferToBody) {
6615
+ if (exposure !== "decorative") {
6616
+ const tappable = isInteractive(n);
6617
+ const type = componentTypeOf(n);
6618
+ const row = type ? own(A11Y_CONTRACT, type) : void 0;
6619
+ const contractual = !interactiveOnly && row?.name === "required";
6620
+ if ((tappable || contractual) && !hasAccessibleName(n)) {
6621
+ out.push({
6622
+ at: path2 || "root",
6623
+ type: type ?? (n.icon ? "icon" : "node"),
6624
+ reason: tappable ? "interactive" : "contract",
6625
+ // §3.4: interactivity promotes the container to a BUTTON whatever its row says.
6626
+ role: tappable ? "button" : row?.role ?? "unspecified"
6627
+ });
6628
+ }
6629
+ }
6630
+ }
6631
+ for (const [k, v] of Object.entries(n)) {
6632
+ walk2(v, path2 ? `${path2}.${k}` : k, k, k === "body" && viaBody && !deferToBody);
6633
+ }
6634
+ };
6635
+ walk2(descriptor, "", "");
6636
+ return out;
6637
+ }
6638
+ var A11Y_CONTRACT, ACCESSIBLE_NAME_KEYS, CONTENT_ARM_KEYS, TAP_MODIFIER_KEYS;
6639
+ var init_a11y_contract = __esm({
6640
+ "../../core/dev-server/src/a11y-contract.ts"() {
6641
+ A11Y_CONTRACT = {
6642
+ // ---- Layout / structural containers -------------------------------------------------
6643
+ // Transparent by default: not AT stops, they expose their children directly. They become a
6644
+ // named GROUP only when they carry `accessibilityLabel` — or when an `onTap` promotes them
6645
+ // (§3.4), which is what the `conditional` arm catches.
6646
+ VStack: { role: "unspecified", name: "conditional", state: [], decorative: false },
6647
+ HStack: { role: "unspecified", name: "conditional", state: [], decorative: false },
6648
+ ZStack: { role: "unspecified", name: "conditional", state: [], decorative: false },
6649
+ Grid: { role: "unspecified", name: "conditional", state: [], decorative: false },
6650
+ LazyList: { role: "list", name: "conditional", state: ["item position", "item count"], decorative: false },
6651
+ Card: { role: "group", name: "conditional", state: [], decorative: false },
6652
+ Divider: { role: "decorative", name: "none", state: [], decorative: true },
6653
+ Spacer: { role: "decorative", name: "none", state: [], decorative: true },
6654
+ SplitView: { role: "unspecified", name: "conditional", state: [], decorative: false },
6655
+ Section: { role: "group", name: "conditional", state: [], decorative: false },
6656
+ LabeledContent: { role: "group", name: "required", state: ["value = the content"], decorative: false },
6657
+ // ---- Text and inline content --------------------------------------------------------
6658
+ // Named by themselves: the copy IS the name, so `required` here reads "this node must carry
6659
+ // some copy", which is also what makes an empty Text a finding rather than a silent stop.
6660
+ Text: { role: "text", name: "required", state: [], decorative: false },
6661
+ RichText: { role: "text", name: "required", state: [], decorative: false },
6662
+ Label: { role: "text", name: "required", state: [], decorative: false },
6663
+ Marquee: { role: "text", name: "required", state: [], decorative: false },
6664
+ Badge: { role: "status", name: "required", state: ["count/value"], decorative: false },
6665
+ Tag: { role: "text", name: "required", state: ["selected (if in a group)"], decorative: false },
6666
+ // ---- Images and media ---------------------------------------------------------------
6667
+ Image: { role: "image", name: "conditional", state: [], decorative: false },
6668
+ // `contentDescription` present ⇒ IMAGE; absent ⇒ DECORATIVE. That is exactly why this pass
6669
+ // can exist: before #2893 there was no way for an author to SAY "decorative", so a validator
6670
+ // could not tell a chevron from an unlabelled icon button and any rule would have been noise.
6671
+ Icon: { role: "decorative", name: "conditional", state: [], decorative: true },
6672
+ Avatar: { role: "image", name: "required", state: [], decorative: false },
6673
+ AvatarStrip: { role: "group", name: "required", state: ["count"], decorative: false },
6674
+ Video: { role: "group", name: "required", state: ["playing/paused", "position"], decorative: false },
6675
+ MediaPlayer: { role: "group", name: "required", state: ["playing/paused", "position"], decorative: false },
6676
+ Lottie: { role: "decorative", name: "conditional", state: [], decorative: true },
6677
+ Rive: { role: "decorative", name: "conditional", state: [], decorative: true },
6678
+ PdfView: { role: "group", name: "required", state: ["page N of M"], decorative: false },
6679
+ VoiceNote: { role: "group", name: "required", state: ["playing", "duration/position"], decorative: false },
6680
+ Map: { role: "image", name: "required", state: [], decorative: false },
6681
+ WebView: { role: "group", name: "required", state: [], decorative: false },
6682
+ // ---- Interactive controls -----------------------------------------------------------
6683
+ Button: { role: "button", name: "required", state: ["disabled"], decorative: false },
6684
+ Fab: { role: "button", name: "required", state: ["disabled"], decorative: false },
6685
+ TextField: { role: "textfield", name: "required", state: ["value", "error", "required"], decorative: false },
6686
+ SearchField: { role: "search", name: "required", state: ["value"], decorative: false },
6687
+ Toggle: { role: "toggle", name: "required", state: ["on/off"], decorative: false },
6688
+ Stepper: { role: "adjustable", name: "required", state: ["value", "increment/decrement"], decorative: false },
6689
+ Slider: { role: "adjustable", name: "required", state: ["value (+ min/max/pct)"], decorative: false },
6690
+ SelectionControl: { role: "checkbox", name: "required", state: ["checked", "group membership"], decorative: false },
6691
+ Picker: { role: "combobox", name: "required", state: ["current selection", "expanded"], decorative: false },
6692
+ DatePicker: { role: "combobox", name: "required", state: ["current selection", "expanded"], decorative: false },
6693
+ WheelPicker: { role: "combobox", name: "required", state: ["current selection", "expanded"], decorative: false },
6694
+ ColorPicker: { role: "combobox", name: "required", state: ["current selection", "expanded"], decorative: false },
6695
+ OtpInput: { role: "textfield", name: "required", state: ["value", "per-cell position"], decorative: false },
6696
+ ChipsInput: { role: "textfield", name: "required", state: ["value", "each chip removable"], decorative: false },
6697
+ Chip: { role: "button", name: "required", state: ["selected", "disabled"], decorative: false },
6698
+ FilterChips: { role: "group", name: "required", state: ["each chip selected"], decorative: false },
6699
+ SegmentedControl: { role: "tablist", name: "required", state: ["each segment selected"], decorative: false },
6700
+ Tabs: { role: "tablist", name: "required", state: ["selected tab", "index/count"], decorative: false },
6701
+ Menu: { role: "menu", name: "required", state: ["each item enabled/checked"], decorative: false },
6702
+ Rating: { role: "adjustable", name: "required", state: ['value "N of M"'], decorative: false },
6703
+ ListItem: { role: "listitem", name: "required", state: ["selected", "disabled", "position"], decorative: false },
6704
+ // ---- Navigation and progress structures ---------------------------------------------
6705
+ DisclosureGroup: { role: "button", name: "required", state: ["expanded/collapsed"], decorative: false },
6706
+ CollapsingHeader: { role: "heading", name: "required", state: ["expanded/collapsed"], decorative: false },
6707
+ Carousel: { role: "list", name: "required", state: ["item N of M"], decorative: false },
6708
+ Pager: { role: "list", name: "required", state: ["item N of M"], decorative: false },
6709
+ PageControl: { role: "adjustable", name: "required", state: ["page N of M"], decorative: false },
6710
+ StepIndicator: { role: "group", name: "required", state: ["step N of M", "current"], decorative: false },
6711
+ // ---- Status, feedback, and overlays -------------------------------------------------
6712
+ ProgressBar: { role: "progressbar", name: "conditional", state: ["value/pct or indeterminate"], decorative: false },
6713
+ ActivityIndicator: { role: "status", name: "conditional", state: ["busy"], decorative: false },
6714
+ Gauge: { role: "progressbar", name: "required", state: ["value + unit"], decorative: false },
6715
+ Skeleton: { role: "decorative", name: "none", state: [], decorative: true },
6716
+ Banner: { role: "status", name: "required", state: ["dismissible"], decorative: false },
6717
+ Snackbar: { role: "status", name: "required", state: [], decorative: false },
6718
+ AlertDialog: { role: "alert", name: "required", state: ["modal"], decorative: false },
6719
+ Tooltip: { role: "unspecified", name: "required", state: [], decorative: false },
6720
+ EmptyState: { role: "group", name: "required", state: [], decorative: false },
6721
+ StatefulSection: { role: "group", name: "conditional", state: ["loading/empty/error/loaded"], decorative: false },
6722
+ FieldError: { role: "alert", name: "required", state: ["associated field"], decorative: false },
6723
+ BottomSheet: { role: "dialog", name: "required", state: ["modal", "expanded"], decorative: false },
6724
+ Popover: { role: "dialog", name: "required", state: ["modal", "expanded"], decorative: false },
6725
+ Form: { role: "group", name: "conditional", state: ["field grouping", "errors"], decorative: false },
6726
+ FormField: { role: "group", name: "conditional", state: ["field grouping", "errors"], decorative: false },
6727
+ // ---- Data, visualization, and temporal ----------------------------------------------
6728
+ Chart: { role: "image", name: "required", state: ["a spoken data summary"], decorative: false },
6729
+ DonutChart: { role: "image", name: "required", state: ["a spoken data summary"], decorative: false },
6730
+ Legend: { role: "list", name: "required", state: ["each series name + value"], decorative: false },
6731
+ DataTable: { role: "group", name: "required", state: ["row/col headers", "cell position"], decorative: false },
6732
+ Table: { role: "group", name: "required", state: ["row/col headers", "cell position"], decorative: false },
6733
+ MonthCalendar: { role: "grid", name: "required", state: ["selected date", "today", "range"], decorative: false },
6734
+ TimeGrid: { role: "grid", name: "required", state: ["slot time", "availability", "selected"], decorative: false },
6735
+ Agenda: { role: "list", name: "required", state: ["each entry time + title"], decorative: false },
6736
+ Timeline: { role: "list", name: "required", state: ["each event position + label"], decorative: false },
6737
+ // ---- Fragment / worker composition --------------------------------------------------
6738
+ // Pass-through: the subtree they render is subject to the same contract, so scoring the
6739
+ // carrier as well would double-report its children.
6740
+ FragmentSlot: { role: "unspecified", name: "none", state: ["announcement on case change"], decorative: false },
6741
+ WorkerSubtree: { role: "unspecified", name: "none", state: [], decorative: false }
6742
+ };
6743
+ ACCESSIBLE_NAME_KEYS = [
6744
+ "accessibilityLabel",
6745
+ "contentDescription",
6746
+ "text",
6747
+ "title",
6748
+ "label",
6749
+ "placeholder",
6750
+ "message",
6751
+ "subtitle",
6752
+ "overline",
6753
+ "caption",
6754
+ "initials",
6755
+ "emptyText",
6756
+ "actionLabel",
6757
+ "confirmLabel",
6758
+ "cancelLabel",
6759
+ "helpText",
6760
+ "errorMessage",
6761
+ "centerTitle",
6762
+ "centerSubtitle",
6763
+ // The one `…Path` TWIN of a name prop in the whole vocabulary. Binding copy to worker state
6764
+ // is authoring it, not omitting it — `textPath: "$service:cart.title"` speaks on device.
6765
+ // (Checked: `textPath` is the only `<nameKey>Path` prop `KNOWN_PROPS` declares. The other
6766
+ // ~40 `…Path` props bind items, colours, dates and values, none of which is a name.)
6767
+ "textPath"
6768
+ ];
6769
+ CONTENT_ARM_KEYS = ["template", "timeRef"];
6770
+ TAP_MODIFIER_KEYS = ["onTap", "onLongPress", "onDoubleTap"];
6771
+ }
6772
+ });
6773
+
6519
6774
  // ../../stdlib/wix-sdk/media/src/index.ts
6520
6775
  function wixMediaId(reference) {
6521
6776
  return WIX_IMAGE.exec(reference)?.[1] ?? (reference.includes("/") || reference.includes(":") ? "" : reference);
@@ -7428,7 +7683,7 @@ function serviceFieldDeclared(state, path2) {
7428
7683
  function ellipsis(value, max) {
7429
7684
  return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
7430
7685
  }
7431
- function own(table, key2) {
7686
+ function own2(table, key2) {
7432
7687
  return Object.prototype.hasOwnProperty.call(table, key2) ? table[key2] : void 0;
7433
7688
  }
7434
7689
  function isOpaqueAuthorJson(key2, value, atRoot) {
@@ -7473,7 +7728,7 @@ function nativeRequiredFindings(descriptor) {
7473
7728
  value.forEach((v, i) => checkNested(v, of, `${path2}[${i}]`, from));
7474
7729
  return;
7475
7730
  }
7476
- const rule = own(NATIVE_NESTED_CLASSES, cls);
7731
+ const rule = own2(NATIVE_NESTED_CLASSES, cls);
7477
7732
  if (!rule) return;
7478
7733
  if (Array.isArray(value) || !value || typeof value !== "object") {
7479
7734
  reportKind(cls, value, path2, from);
@@ -7481,17 +7736,17 @@ function nativeRequiredFindings(descriptor) {
7481
7736
  }
7482
7737
  const bag = value;
7483
7738
  for (const name of rule.required) {
7484
- if (own(bag, name) !== void 0 && bag[name] !== null) continue;
7739
+ if (own2(bag, name) !== void 0 && bag[name] !== null) continue;
7485
7740
  out.push({
7486
7741
  path: `${path2}.${name}`,
7487
7742
  message: `${cls}.${name} is REQUIRED by the native decoder but is missing \u2014 native decode rejects it ("Field '${name}' is required for type with serial name 'io.himalaya.core.${cls}', but it was missing") and drops the WHOLE screen from the seed, while web renders it fine (reached from ${from})`
7488
7743
  });
7489
7744
  }
7490
7745
  for (const [name, sub] of Object.entries(rule.nested)) {
7491
- const inner = own(bag, name);
7746
+ const inner = own2(bag, name);
7492
7747
  if (inner !== void 0 && inner !== null) checkNested(inner, sub, `${path2}.${name}`, from);
7493
7748
  }
7494
- if (cls === "Action") checkActionParams(own(bag, "params"), `${path2}.params`, from);
7749
+ if (cls === "Action") checkActionParams(own2(bag, "params"), `${path2}.params`, from);
7495
7750
  };
7496
7751
  const checkActionParams = (params, path2, from) => {
7497
7752
  if (params === void 0 || params === null) return;
@@ -7524,22 +7779,22 @@ function nativeRequiredFindings(descriptor) {
7524
7779
  const props = body.props;
7525
7780
  const bag = props && typeof props === "object" && !Array.isArray(props) ? props : {};
7526
7781
  const base = at ? `${at}.body.props` : "body.props";
7527
- for (const name of own(NATIVE_REQUIRED_PROPS, type) ?? []) {
7528
- if (own(bag, name) !== void 0 && bag[name] !== null) continue;
7782
+ for (const name of own2(NATIVE_REQUIRED_PROPS, type) ?? []) {
7783
+ if (own2(bag, name) !== void 0 && bag[name] !== null) continue;
7529
7784
  const hint = type === "Button" && name === "title" && bag.iconOnly === true ? " \u2014 `iconOnly` HIDES the label, it does not make it optional; keep a title (it is also the accessibility label)" : "";
7530
7785
  out.push({
7531
7786
  path: `${base}.${name}`,
7532
7787
  message: `${type}.${name} is REQUIRED by the native decoder but is missing \u2014 native decode rejects it ("Field '${name}' is required for type with serial name 'io.himalaya.core.${type}Props', but it was missing") and drops the WHOLE screen from the seed, while web renders it fine${hint}`
7533
7788
  });
7534
7789
  }
7535
- for (const [prop, cls] of Object.entries(own(NATIVE_NESTED_PROPS, type) ?? {})) {
7536
- const value = own(bag, prop);
7790
+ for (const [prop, cls] of Object.entries(own2(NATIVE_NESTED_PROPS, type) ?? {})) {
7791
+ const value = own2(bag, prop);
7537
7792
  if (value === void 0 || value === null) continue;
7538
7793
  checkNested(value, cls, `${base}.${prop}`, `${type}.${prop}`);
7539
7794
  }
7540
7795
  }
7541
7796
  if (body && typeof body === "object" && typeof body.type === "string" && typeof body.package === "string") {
7542
- const modifiers = own(record2, "modifiers");
7797
+ const modifiers = own2(record2, "modifiers");
7543
7798
  if (modifiers !== void 0 && modifiers !== null) {
7544
7799
  checkNested(modifiers, NATIVE_MODIFIERS_CLASS, at ? `${at}.modifiers` : "modifiers", "modifiers");
7545
7800
  }
@@ -7553,7 +7808,7 @@ function nativeRequiredFindings(descriptor) {
7553
7808
  if (descriptor && typeof descriptor === "object" && !Array.isArray(descriptor)) {
7554
7809
  const root = descriptor;
7555
7810
  for (const [field, cls] of Object.entries(NATIVE_DESCRIPTOR_NESTED)) {
7556
- const value = own(root, field);
7811
+ const value = own2(root, field);
7557
7812
  if (value === void 0 || value === null) continue;
7558
7813
  checkNested(value, cls, field, `${NATIVE_DESCRIPTOR_CLASS}.${field}`);
7559
7814
  }
@@ -7583,14 +7838,14 @@ function componentPropFindings(descriptor) {
7583
7838
  const body = record2.body;
7584
7839
  if (typeof body?.package === "string" && CORE_PACKAGES.has(body.package) && typeof body.type === "string") {
7585
7840
  const type = body.type;
7586
- const declared = own(KNOWN_PROPS, type);
7841
+ const declared = own2(KNOWN_PROPS, type);
7587
7842
  const props = body.props;
7588
7843
  if (declared && props && typeof props === "object" && !Array.isArray(props)) {
7589
7844
  const bag = props;
7590
7845
  const base = at ? `${at}.body.props` : "body.props";
7591
7846
  for (const name of Object.keys(bag)) {
7592
7847
  const path2 = `${base}.${name}`;
7593
- const kind = own(declared, name);
7848
+ const kind = own2(declared, name);
7594
7849
  if (kind === void 0) {
7595
7850
  if (LEGACY_UNSCORED_KEYS.has(`${type}.${name}`)) continue;
7596
7851
  const hint = MODIFIER_KEYS.has(name) ? ` \u2014 \`${name}\` is a MODIFIER, not a prop: move it out of \`props\` and into the node's \`modifiers\` bag (\`{ id, body, modifiers: { ${name}: \u2026 } }\`)` : "";
@@ -7606,7 +7861,7 @@ function componentPropFindings(descriptor) {
7606
7861
  if (kind === "any") continue;
7607
7862
  if (typeof value === "string" && BINDING_SIGIL_RE.test(value)) {
7608
7863
  if (kind === "string") continue;
7609
- const twin = own(declared, `${name}Path`) !== void 0 ? `${name}Path` : void 0;
7864
+ const twin = own2(declared, `${name}Path`) !== void 0 ? `${name}Path` : void 0;
7610
7865
  const inArray = IN_ARRAY_BINDING_PROPS.has(`${type}.${name}`) && value.startsWith(SERVICE_SIGIL);
7611
7866
  out.push({
7612
7867
  path: path2,
@@ -7629,10 +7884,10 @@ function componentPropFindings(descriptor) {
7629
7884
  });
7630
7885
  continue;
7631
7886
  }
7632
- if (own(NATIVE_PROP_ENUMS, name) !== void 0) continue;
7887
+ if (own2(NATIVE_PROP_ENUMS, name) !== void 0) continue;
7633
7888
  const actual = wireKind(value);
7634
7889
  if (actual === kind) {
7635
- if (kind === "number" && typeof value === "number" && !Number.isInteger(value) && own(INTEGER_PROPS, type)?.includes(name)) {
7890
+ if (kind === "number" && typeof value === "number" && !Number.isInteger(value) && own2(INTEGER_PROPS, type)?.includes(name)) {
7636
7891
  out.push({
7637
7892
  path: path2,
7638
7893
  kind: "decode",
@@ -7650,13 +7905,13 @@ function componentPropFindings(descriptor) {
7650
7905
  }
7651
7906
  }
7652
7907
  if (body && typeof body === "object" && typeof body.type === "string" && typeof body.package === "string") {
7653
- const modifiers = own(record2, "modifiers");
7908
+ const modifiers = own2(record2, "modifiers");
7654
7909
  if (modifiers && typeof modifiers === "object" && !Array.isArray(modifiers)) {
7655
7910
  const schemaOwnsUnknownKeys = SCHEMA_SCORED_NODES.has(at);
7656
7911
  const bag = modifiers;
7657
7912
  for (const key2 of Object.keys(bag)) {
7658
7913
  if (MODIFIER_KEYS.has(key2)) {
7659
- const spec = own(MODIFIER_KINDS, key2);
7914
+ const spec = own2(MODIFIER_KINDS, key2);
7660
7915
  const value = bag[key2];
7661
7916
  if (!spec || value === void 0 || value === null) continue;
7662
7917
  const where = at ? `${at}.modifiers.${key2}` : `modifiers.${key2}`;
@@ -8252,7 +8507,7 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
8252
8507
  if (isOpaqueAuthorJson(k, val, at === "")) continue;
8253
8508
  if (k === "params" && typeof node.actionId === "string") continue;
8254
8509
  const here = at ? `${at}.${k}` : k;
8255
- const allowed2 = own(NATIVE_PROP_ENUMS, k);
8510
+ const allowed2 = own2(NATIVE_PROP_ENUMS, k);
8256
8511
  if (typeof val === "string" && enums.has(k) && DYNAMIC_PLACEHOLDER.test(val)) {
8257
8512
  issues.push({
8258
8513
  severity: "error",
@@ -8493,6 +8748,30 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
8493
8748
  });
8494
8749
  }
8495
8750
  }
8751
+ const a11yMode = opts.a11y?.enforce ?? "error";
8752
+ if (a11yMode !== "off") {
8753
+ const severity = a11yMode === "warn" && !strict ? "warning" : "error";
8754
+ const gaps = accessibleNameGaps(descriptor);
8755
+ const CAP4 = 20;
8756
+ for (const gap of gaps.slice(0, CAP4)) {
8757
+ const row = Object.prototype.hasOwnProperty.call(A11Y_CONTRACT, gap.type) ? A11Y_CONTRACT[gap.type] : void 0;
8758
+ const why = gap.reason === "interactive" ? `it carries an \`onTap\`/\`onLongPress\`/\`onDoubleTap\`, which promotes ANY node to a control that owes a name (RFC 0058 \xA73.4)` : `RFC 0058 \xA73.3 requires a name for \`${gap.type}\` (announced as \`${gap.role}\`)`;
8759
+ const fix = gap.reason === "contract" ? `Give it \`modifiers.accessibilityLabel\`, or copy on a descendant \u2014 or, if it really is presentational, say so with \`modifiers.accessibilityRole: "decorative"\` (node-local) or \`modifiers.accessibilityHidden: true\` (whole subtree).` : `Give it \`modifiers.accessibilityLabel\`, or put readable copy on a descendant. An icon-only control names itself with \`Icon.contentDescription\`. \`decorative\` does not silence a control${row?.decorative ? ` \u2014 a tappable \`${gap.type}\` is one` : ""}.`;
8760
+ issues.push({
8761
+ severity,
8762
+ pass: "a11y",
8763
+ path: gap.at,
8764
+ message: `${gap.type} renders no accessible name anywhere in its subtree, and ${why}. A screen reader announces this node as an unnamed \`${gap.role}\`. ${fix}`
8765
+ });
8766
+ }
8767
+ if (gaps.length > CAP4) {
8768
+ issues.push({
8769
+ severity,
8770
+ pass: "a11y",
8771
+ message: `+${gaps.length - CAP4} more node(s) on this screen render no accessible name (${gaps.length} in total). Fix the ${CAP4} above and re-run to see the rest.`
8772
+ });
8773
+ }
8774
+ }
8496
8775
  return {
8497
8776
  screenId,
8498
8777
  ok: !issues.some((i) => i.severity === "error"),
@@ -8507,6 +8786,7 @@ var init_validate_descriptor_core = __esm({
8507
8786
  init_validator();
8508
8787
  init_validator();
8509
8788
  init_l10n_strings();
8789
+ init_a11y_contract();
8510
8790
  init_bindings();
8511
8791
  init_media_value();
8512
8792
  init_frame_limits();
@@ -8957,6 +9237,7 @@ var init_validate_descriptor_core = __esm({
8957
9237
  interactive: "boolean",
8958
9238
  max: "number",
8959
9239
  onChange: "any",
9240
+ size: "string",
8960
9241
  value: "number",
8961
9242
  valuePath: "string"
8962
9243
  },
@@ -12729,8 +13010,8 @@ var init_tokens2 = __esm({
12729
13010
  // ../font-bake/web-fallback.ts
12730
13011
  function webRenderedFallback(family) {
12731
13012
  const stack = fontStack(family);
12732
- const own2 = `"${family}", `;
12733
- const tail = stack.startsWith(own2) ? stack.slice(own2.length) : stack;
13013
+ const own3 = `"${family}", `;
13014
+ const tail = stack.startsWith(own3) ? stack.slice(own3.length) : stack;
12734
13015
  return tail.split(",")[0].trim().replace(/^"(.*)"$/, "$1");
12735
13016
  }
12736
13017
  var init_web_fallback = __esm({
@@ -14076,7 +14357,7 @@ function parseIconConfig(configTs) {
14076
14357
  const block = /^ {2}icon\s*[:=]\s*\{([^}]*)\}/m.exec(src);
14077
14358
  if (!block) return {};
14078
14359
  const body = block[1];
14079
- const str6 = (k) => new RegExp(`\\b${k}\\s*:\\s*["']([^"']+)["']`).exec(body)?.[1];
14360
+ const str7 = (k) => new RegExp(`\\b${k}\\s*:\\s*["']([^"']+)["']`).exec(body)?.[1];
14080
14361
  const num3 = (k) => {
14081
14362
  const m = new RegExp(`\\b${k}\\s*:\\s*(-?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?)\\s*(?=[,}\\n]|$)`).exec(body);
14082
14363
  if (!m) return void 0;
@@ -14087,10 +14368,10 @@ function parseIconConfig(configTs) {
14087
14368
  return n;
14088
14369
  };
14089
14370
  const out = {};
14090
- const source = str6("source");
14091
- const glyph = str6("glyph");
14092
- const accentColor = str6("accentColor");
14093
- const backgroundColor = str6("backgroundColor");
14371
+ const source = str7("source");
14372
+ const glyph = str7("glyph");
14373
+ const accentColor = str7("accentColor");
14374
+ const backgroundColor = str7("backgroundColor");
14094
14375
  const glyphScale = num3("glyphScale");
14095
14376
  for (const [key2, parsed] of [
14096
14377
  ["source", source],
@@ -18732,13 +19013,13 @@ function parsePaddingShorthand(v) {
18732
19013
  }
18733
19014
  function addIntrinsicPadding(style, modPad) {
18734
19015
  if (!style) return void 0;
18735
- const own2 = parsePaddingShorthand(style.padding);
18736
- if (!own2) return void 0;
19016
+ const own3 = parsePaddingShorthand(style.padding);
19017
+ if (!own3) return void 0;
18737
19018
  const sides = [
18738
- ["paddingTop", own2.top],
18739
- ["paddingBottom", own2.bottom],
18740
- ["paddingLeft", own2.left],
18741
- ["paddingRight", own2.right]
19019
+ ["paddingTop", own3.top],
19020
+ ["paddingBottom", own3.bottom],
19021
+ ["paddingLeft", own3.left],
19022
+ ["paddingRight", own3.right]
18742
19023
  ];
18743
19024
  let out;
18744
19025
  for (const [key2, ownPx] of sides) {
@@ -24025,10 +24306,10 @@ function calSnap(minuteOfDay, step) {
24025
24306
  return Math.min(Math.max(Math.round(minuteOfDay / s) * s, 0), 24 * 60);
24026
24307
  }
24027
24308
  function calMoveEvent(startMinute, endMinute, deltaMinutes, step) {
24028
- const duration = Math.max(1, endMinute - startMinute);
24029
- const maxStart = Math.max(0, 24 * 60 - duration);
24309
+ const duration2 = Math.max(1, endMinute - startMinute);
24310
+ const maxStart = Math.max(0, 24 * 60 - duration2);
24030
24311
  const start = Math.min(Math.max(calSnap(startMinute + deltaMinutes, step), 0), maxStart);
24031
- return { startMinute: start, endMinute: start + duration };
24312
+ return { startMinute: start, endMinute: start + duration2 };
24032
24313
  }
24033
24314
  function calResizeEvent(startMinute, endMinute, deltaMinutes, step) {
24034
24315
  const s = Math.max(1, step);
@@ -24178,7 +24459,7 @@ function calKeyActivate(enabled, activate) {
24178
24459
  function applyA11ySemantics(node, ctx, extra) {
24179
24460
  const m = node?.modifiers;
24180
24461
  if (!m) return void 0;
24181
- const str6 = (v) => {
24462
+ const str7 = (v) => {
24182
24463
  if (v == null) return void 0;
24183
24464
  const r = resolveScalarStatic(v, ctx);
24184
24465
  const s = r == null ? "" : String(r).trim();
@@ -24189,7 +24470,7 @@ function applyA11ySemantics(node, ctx, extra) {
24189
24470
  extra.inert = "";
24190
24471
  return void 0;
24191
24472
  }
24192
- const role = str6(m.accessibilityRole ?? m.accessibility_role);
24473
+ const role = str7(m.accessibilityRole ?? m.accessibility_role);
24193
24474
  const headingLevel = m.headingLevel ?? m.heading_level;
24194
24475
  const tappable = Boolean((m.onTap ?? m.on_tap ?? m.onDoubleTap ?? m.on_double_tap) && ctx.onAction);
24195
24476
  if (role === "decorative" && !tappable) {
@@ -24204,8 +24485,8 @@ function applyA11ySemantics(node, ctx, extra) {
24204
24485
  if (typeof headingLevel === "number" && headingLevel >= 1 && headingLevel <= 6) {
24205
24486
  extra["aria-level"] = String(headingLevel);
24206
24487
  }
24207
- const hint = str6(m.accessibilityHint ?? m.accessibility_hint);
24208
- const value = str6(m.accessibilityValue ?? m.accessibility_value);
24488
+ const hint = str7(m.accessibilityHint ?? m.accessibility_hint);
24489
+ const value = str7(m.accessibilityValue ?? m.accessibility_value);
24209
24490
  if (value) extra["aria-valuetext"] = value;
24210
24491
  const traits = m.accessibilityTraits ?? m.accessibility_traits;
24211
24492
  if (Array.isArray(traits)) {
@@ -25079,7 +25360,7 @@ function renderInner(node, ctx) {
25079
25360
  }
25080
25361
  }
25081
25362
  }
25082
- var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, INFERRED_DECORATIVE, ICON_GLYPH, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, A11yHintDescription, WebRenderer;
25363
+ var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, INFERRED_DECORATIVE, ICON_GLYPH, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RATING_METRICS, ratingMetrics, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, A11yHintDescription, WebRenderer;
25083
25364
  var init_renderNode = __esm({
25084
25365
  "../../core/web-renderer/src/renderNode.tsx"() {
25085
25366
  "use strict";
@@ -25808,7 +26089,7 @@ var init_renderNode = __esm({
25808
26089
  }, [resolvedItems.length, startIndex, queueReady, seatKey]);
25809
26090
  const [status, setStatus] = React5.useState("idle");
25810
26091
  const [position, setPosition] = React5.useState(initialStartPosition);
25811
- const [duration, setDuration] = React5.useState(0);
26092
+ const [duration2, setDuration] = React5.useState(0);
25812
26093
  const [buffered, setBuffered] = React5.useState(0);
25813
26094
  const [rate, setRateState] = React5.useState(1);
25814
26095
  const [fullscreen, setFullscreen] = React5.useState(false);
@@ -25851,9 +26132,9 @@ var init_renderNode = __esm({
25851
26132
  artist: String(item?.artist ?? ""),
25852
26133
  artworkUrl: String(item?.artworkUrl ?? props.posterUrl ?? ""),
25853
26134
  positionSeconds: position,
25854
- durationSeconds: duration || Number(item?.durationSeconds ?? 0),
26135
+ durationSeconds: duration2 || Number(item?.durationSeconds ?? 0),
25855
26136
  bufferedSeconds: buffered,
25856
- progress: duration > 0 ? Math.max(0, Math.min(1, position / duration)) : 0,
26137
+ progress: duration2 > 0 ? Math.max(0, Math.min(1, position / duration2)) : 0,
25857
26138
  muted: mediaRef.current?.muted ?? props.muted === true,
25858
26139
  rate,
25859
26140
  fullscreen,
@@ -25881,7 +26162,7 @@ var init_renderNode = __esm({
25881
26162
  status,
25882
26163
  index,
25883
26164
  positionSeconds: position,
25884
- durationSeconds: duration || Number(item?.durationSeconds ?? 0),
26165
+ durationSeconds: duration2 || Number(item?.durationSeconds ?? 0),
25885
26166
  bufferedSeconds: buffered,
25886
26167
  rate,
25887
26168
  muted: mediaRef.current?.muted ?? props.muted === true,
@@ -25891,7 +26172,7 @@ var init_renderNode = __esm({
25891
26172
  error
25892
26173
  };
25893
26174
  ctx.onAction({ ...action, args: { ...action.args ?? {}, ...snapshot2, ...extra }, params: { ...action.params ?? {}, sessionId, index: String(index), ...Object.fromEntries(Object.entries(extra).map(([k, v]) => [k, String(v)])) } });
25894
- }, [ctx.onAction, sessionId, status, index, position, duration, item, buffered, rate, props.muted, fullscreen, error]);
26175
+ }, [ctx.onAction, sessionId, status, index, position, duration2, item, buffered, rate, props.muted, fullscreen, error]);
25895
26176
  React5.useEffect(() => {
25896
26177
  if (!isUnsupportedProvider || status === "error") return;
25897
26178
  setStatus("error");
@@ -26115,8 +26396,8 @@ var init_renderNode = __esm({
26115
26396
  /* @__PURE__ */ jsx6("button", { "aria-label": status === "playing" ? "Pause" : "Play", onClick: () => status === "playing" ? pause() : void play(), style: { width: 38, height: 38, borderRadius: "50%", color: background, background: foreground, border: 0, fontSize: 18 }, children: status === "playing" ? "\u275A\u275A" : "\u25B6" }),
26116
26397
  /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 }, children: [
26117
26398
  /* @__PURE__ */ jsx6("span", { style: { fontSize: 11, whiteSpace: "nowrap" }, children: time(position) }),
26118
- /* @__PURE__ */ jsx6("input", { "aria-label": "Media position", type: "range", min: 0, max: Math.max(duration, 1), step: 0.1, value: Math.min(position, Math.max(duration, 1)), onChange: (event) => seek(Number(event.currentTarget.value)), style: { width: "100%", accentColor: accent } }),
26119
- /* @__PURE__ */ jsx6("span", { style: { fontSize: 11, whiteSpace: "nowrap" }, children: time(duration) })
26399
+ /* @__PURE__ */ jsx6("input", { "aria-label": "Media position", type: "range", min: 0, max: Math.max(duration2, 1), step: 0.1, value: Math.min(position, Math.max(duration2, 1)), onChange: (event) => seek(Number(event.currentTarget.value)), style: { width: "100%", accentColor: accent } }),
26400
+ /* @__PURE__ */ jsx6("span", { style: { fontSize: 11, whiteSpace: "nowrap" }, children: time(duration2) })
26120
26401
  ] }),
26121
26402
  items.length > 1 && /* @__PURE__ */ jsx6("button", { "aria-label": "Next", onClick: () => select(index + 1), style: { color: "inherit", background: "transparent", border: 0, fontSize: 18 }, children: "\u25B6\u25B6" }),
26122
26403
  props.fullscreen !== "disabled" && /* @__PURE__ */ jsx6("button", { "aria-label": "Fullscreen", onClick: () => void toggleFullscreen(), style: { color: "inherit", background: "transparent", border: 0, fontSize: 18 }, children: "\u26F6" })
@@ -27003,20 +27284,26 @@ var init_renderNode = __esm({
27003
27284
  /* @__PURE__ */ jsx6("div", { style: { position: "absolute", inset: 0, display: "grid", placeItems: "center", fontFamily: fontStack(capF.family), fontSize: capF.remSize, fontWeight: capF.weight, color: C("textPrimary", "#13171e") }, children: txt(props.label, ctx) || `${Math.round(pct * 100)}%` })
27004
27285
  ] }) });
27005
27286
  });
27287
+ RATING_METRICS = {
27288
+ sm: { cell: 16, glyph: 14, gap: 2 },
27289
+ md: { cell: 22, glyph: 20, gap: 3 }
27290
+ };
27291
+ ratingMetrics = (size) => size === "sm" ? RATING_METRICS.sm : RATING_METRICS.md;
27006
27292
  RatingNode = withExtras("RatingNode", ({ props, ctx, wrap }) => {
27007
27293
  const C = ctx.color;
27008
27294
  const bound = useResolvedScalar(props.valuePath, ctx);
27009
27295
  const raw = props.valuePath != null ? bound : props.value;
27010
27296
  const val = typeof raw === "number" ? raw : 0;
27011
27297
  const max = props.max ?? 5;
27298
+ const m = ratingMetrics(props.size);
27012
27299
  const col = C(props.color ?? "warning", "#E89F00");
27013
27300
  const invalidIcon = props.icon != null && typeof props.icon !== "string";
27014
27301
  const base = invalidIcon ? ICON_FALLBACK : (typeof props.icon === "string" && props.icon ? props.icon : "star").replace(/_fill$/, "");
27015
27302
  const filledCount = Math.round(val);
27016
27303
  const onClickStar = (i) => ctx.onAction && props.interactive && props.onChange ? () => ctx.onAction({ ...props.onChange, params: { ...props.onChange?.params ?? {}, value: String(i + 1) } }) : void 0;
27017
- return /* @__PURE__ */ jsx6("span", { style: { display: "inline-flex", alignItems: "center", gap: 3, ...wrap }, children: Array.from({ length: max }).map((_, i) => {
27304
+ return /* @__PURE__ */ jsx6("span", { style: { display: "inline-flex", alignItems: "center", gap: m.gap, ...wrap }, children: Array.from({ length: max }).map((_, i) => {
27018
27305
  const filled = i < filledCount;
27019
- return /* @__PURE__ */ jsx6("span", { onClick: onClickStar(i), style: { display: "inline-grid", placeItems: "center", width: 22, height: 22, cursor: props.interactive ? "pointer" : "default", opacity: filled ? 1 : 0.28 }, children: iconSvg(filled ? `${base}_fill` : base, { size: 20, color: col }) }, i);
27306
+ return /* @__PURE__ */ jsx6("span", { onClick: onClickStar(i), style: { display: "inline-grid", placeItems: "center", width: m.cell, height: m.cell, cursor: props.interactive ? "pointer" : "default", opacity: filled ? 1 : 0.28 }, children: iconSvg(filled ? `${base}_fill` : base, { size: m.glyph, color: col }) }, i);
27020
27307
  }) });
27021
27308
  });
27022
27309
  AvatarStripNode = withExtras("AvatarStripNode", ({ props, ctx, wrap }) => {
@@ -28449,10 +28736,10 @@ var init_renderNode = __esm({
28449
28736
  };
28450
28737
  A11yHintDescription = ({ hint, idBase, children, ...forwarded }) => {
28451
28738
  const descId = `${idBase ?? "hm"}__hint${React5.useId()}`;
28452
- const own2 = children.props;
28739
+ const own3 = children.props;
28453
28740
  const next = { ...forwarded };
28454
- if (forwarded.style) next.style = { ...own2.style ?? {}, ...forwarded.style };
28455
- next["aria-describedby"] = [own2["aria-describedby"], descId].filter(Boolean).join(" ");
28741
+ if (forwarded.style) next.style = { ...own3.style ?? {}, ...forwarded.style };
28742
+ next["aria-describedby"] = [own3["aria-describedby"], descId].filter(Boolean).join(" ");
28456
28743
  return /* @__PURE__ */ jsxs3(Fragment3, { children: [
28457
28744
  React5.cloneElement(children, next),
28458
28745
  /* @__PURE__ */ jsx6("span", { id: descId, hidden: true, "data-hm-a11y-hint": "", children: hint })
@@ -31480,7 +31767,9 @@ async function runScreenDiagnostics(state, screenId, descriptor) {
31480
31767
  nativeActions,
31481
31768
  appWorkerActions,
31482
31769
  strict: false,
31483
- workerSubtreeScreens: new Set(state.app?.module.config.workerSubtreeScreens ?? [])
31770
+ workerSubtreeScreens: new Set(state.app?.module.config.workerSubtreeScreens ?? []),
31771
+ // Same a11y rung the build lint applies (RFC 0058 §5) — diagnostics must not disagree.
31772
+ a11y: state.app?.module.config.a11y
31484
31773
  });
31485
31774
  const telemetry = state.telemetryEvents.filter((e) => e.screenId === screenId && (/^worker_/.test(e.type) || e.type === "bundle_load_revoked")).slice(-20);
31486
31775
  const lastError = [...telemetry].reverse().find((e) => /crash|revoked|error|fail/i.test(e.type)) ?? null;
@@ -32136,8 +32425,8 @@ function startBundleSourceWatcher(state) {
32136
32425
  }
32137
32426
  function applyTopBarDefault(descriptor, config) {
32138
32427
  const fallback = config?.navigation?.topBarDefault;
32139
- const own2 = descriptor?.topBar;
32140
- if (!fallback || own2) return descriptor;
32428
+ const own3 = descriptor?.topBar;
32429
+ if (!fallback || own3) return descriptor;
32141
32430
  return { ...descriptor, topBar: fallback };
32142
32431
  }
32143
32432
  function syncNetMocksWithApp(state) {
@@ -32405,7 +32694,7 @@ async function handleWebWix(req, res, state) {
32405
32694
  const session = webWixSession(req, res, state);
32406
32695
  const auth = resolveWebWixAuth(state.app);
32407
32696
  const path2 = new URL(req.url ?? "", "http://localhost").pathname;
32408
- const readJson4 = async () => {
32697
+ const readJson5 = async () => {
32409
32698
  const chunks = [];
32410
32699
  for await (const c of req) chunks.push(c);
32411
32700
  const t = Buffer.concat(chunks).toString("utf8");
@@ -32422,7 +32711,7 @@ async function handleWebWix(req, res, state) {
32422
32711
  res.end(JSON.stringify(obj3));
32423
32712
  };
32424
32713
  if (path2 === "/v1/__webwix/login" && req.method === "POST") {
32425
- const b = await readJson4();
32714
+ const b = await readJson5();
32426
32715
  try {
32427
32716
  const { memberToken, visitorToken } = await memberDirectLogin(
32428
32717
  auth.clientId,
@@ -32439,7 +32728,7 @@ async function handleWebWix(req, res, state) {
32439
32728
  }
32440
32729
  }
32441
32730
  if (path2 === "/v1/__webwix/call" && req.method === "POST") {
32442
- const b = await readJson4();
32731
+ const b = await readJson5();
32443
32732
  if (b.ownerMsid !== void 0 || b.checkOwnerSession === true) {
32444
32733
  const msid = String(b.ownerMsid ?? "");
32445
32734
  if (!isSafeMsid(msid)) return reply(400, { error: "webwix_owner_bad_msid" });
@@ -32555,7 +32844,7 @@ async function handleWebWix(req, res, state) {
32555
32844
  });
32556
32845
  }
32557
32846
  if (path2 === "/v1/__webwix/register" && req.method === "POST") {
32558
- const b = await readJson4();
32847
+ const b = await readJson5();
32559
32848
  try {
32560
32849
  const { memberToken, visitorToken } = await memberDirectRegister(
32561
32850
  auth.clientId,
@@ -33105,7 +33394,8 @@ async function handleAdminPlayground(req, res, state) {
33105
33394
  nativeActions,
33106
33395
  appWorkerActions,
33107
33396
  strict,
33108
- workerSubtreeScreens: new Set(state.app?.module.config.workerSubtreeScreens ?? [])
33397
+ workerSubtreeScreens: new Set(state.app?.module.config.workerSubtreeScreens ?? []),
33398
+ a11y: state.app?.module.config.a11y
33109
33399
  });
33110
33400
  return sendJson(res, report2.ok ? 200 : 422, report2);
33111
33401
  }
@@ -37532,7 +37822,10 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
37532
37822
  appWorkerActions,
37533
37823
  strict: collect2.strict,
37534
37824
  workerSubtreeScreens: new Set(preloaded.module.config.workerSubtreeScreens ?? []),
37535
- l10n: l10nLintOptions(preloaded.module.config.locale, preloaded.dir)
37825
+ l10n: l10nLintOptions(preloaded.module.config.locale, preloaded.dir),
37826
+ // RFC 0058 §5 — the app's own rung of the a11y ladder. Omitted ⇒ the validator's
37827
+ // default, "error"; an in-repo app with ratcheted debt declares "warn".
37828
+ a11y: preloaded.module.config.a11y
37536
37829
  });
37537
37830
  lint.push({ screenId, ok: report2.ok, issues: report2.issues });
37538
37831
  }
@@ -37560,7 +37853,8 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
37560
37853
  nativeActions,
37561
37854
  appWorkerActions,
37562
37855
  strict: collect2.strict,
37563
- workerSubtreeScreens: new Set(preloaded.module.config.workerSubtreeScreens ?? [])
37856
+ workerSubtreeScreens: new Set(preloaded.module.config.workerSubtreeScreens ?? []),
37857
+ a11y: preloaded.module.config.a11y
37564
37858
  });
37565
37859
  lint.push({ screenId: wantedRender, ok: report2.ok, issues: report2.issues });
37566
37860
  }
@@ -38095,6 +38389,7 @@ __export(progress_exports, {
38095
38389
  appleScriptString: () => appleScriptString,
38096
38390
  archiveBytes: () => archiveBytes,
38097
38391
  archiveImage: () => archiveImage,
38392
+ imageExtension: () => imageExtension,
38098
38393
  journalPath: () => journalPath,
38099
38394
  notifyDesktop: () => notifyDesktop,
38100
38395
  parseStep: () => parseStep,
@@ -38335,6 +38630,7 @@ __export(studio_exports, {
38335
38630
  STUDIO_PAGE: () => STUDIO_PAGE,
38336
38631
  VALIDATE_RECORD: () => VALIDATE_RECORD,
38337
38632
  buildView: () => buildView,
38633
+ escapeHtml: () => escapeHtml,
38338
38634
  observeShots: () => observeShots,
38339
38635
  openStudio: () => openStudio,
38340
38636
  refreshStudio: () => refreshStudio,
@@ -38473,7 +38769,12 @@ function liveRun(dir) {
38473
38769
  const build2 = obj(rec?.build);
38474
38770
  try {
38475
38771
  process.kill(pid, 0);
38476
- return { url, buildError: build2?.ok === false ? text(build2.error) ?? "the last rebuild failed" : null };
38772
+ return {
38773
+ url,
38774
+ buildError: build2?.ok === false ? text(build2.error) ?? "the last rebuild failed" : null,
38775
+ // Only `--watch` wrote this record before plain runs did, so a record without the key is one.
38776
+ watching: rec?.watching !== false
38777
+ };
38477
38778
  } catch {
38478
38779
  return null;
38479
38780
  }
@@ -38661,7 +38962,7 @@ function render(s){
38661
38962
  $("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
38662
38963
  $("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
38663
38964
  var focus=$("focus");clear(focus);var film=$("film");clear(film);
38664
- if(s.live){$("focuslbl").textContent="Live preview";var f=el("div","phone");var fr=document.createElement("iframe");fr.src=s.live.url;fr.title="Live preview";f.appendChild(fr);focus.appendChild(f);if(s.live.buildError){var be=el("div","chip bad",null);be.style.display="block";be.style.marginTop="8px";be.textContent="Last edit did not build, still showing the last good version: "+s.live.buildError;focus.appendChild(be)}focus.appendChild(el("div","cap","Repaints as the app is edited \xB7 "+s.live.url))}
38965
+ if(s.live){$("focuslbl").textContent="Live preview";var f=el("div","phone");var fr=document.createElement("iframe");fr.src=s.live.url;fr.title="Live preview";f.appendChild(fr);focus.appendChild(f);if(s.live.buildError){var be=el("div","chip bad",null);be.style.display="block";be.style.marginTop="8px";be.textContent="Last edit did not build, still showing the last good version: "+s.live.buildError;focus.appendChild(be)}focus.appendChild(el("div","cap",(s.live.watching?"Repaints as the app is edited \xB7 ":"The build this run started with; himi run --watch repaints on every edit \xB7 ")+s.live.url))}
38665
38966
  else if(s.focus&&s.focus.frames.length){var fl=s.focus.frames;$("focuslbl").textContent="Latest \xB7 "+s.focus.id;var p=el("div","phone");p.appendChild(img(fl[fl.length-1].img));focus.appendChild(p);focus.appendChild(el("div","cap",fl.length+(fl.length===1?" version":" versions")+" so far"))}
38666
38967
  else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
38667
38968
  if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});
@@ -40659,8 +40960,8 @@ function rewriteNav(nav, removed, homeId) {
40659
40960
  return p;
40660
40961
  };
40661
40962
  const tabFor = (screenId) => {
40662
- const own2 = remainingRoots.find((t) => t.screenId === screenId);
40663
- return typeof own2?.id === "string" ? own2.id : void 0;
40963
+ const own3 = remainingRoots.find((t) => t.screenId === screenId);
40964
+ return typeof own3?.id === "string" ? own3.id : void 0;
40664
40965
  };
40665
40966
  const homeTab = tabFor(homeId) ?? (typeof remainingRoots[0]?.id === "string" ? remainingRoots[0].id : "");
40666
40967
  const finalTab = /* @__PURE__ */ new Map();
@@ -40795,8 +41096,8 @@ function planTrim(src, keepIds, links) {
40795
41096
  if (!linksOf(r).some((l) => removedTarget(l.to))) continue;
40796
41097
  const block = structuredClone(r.block);
40797
41098
  const isDead = (entry) => {
40798
- const own2 = tapTarget(entry);
40799
- const to = own2 && removedTarget(own2) ? own2 : rowTemplateTarget(entry, removedTarget);
41099
+ const own3 = tapTarget(entry);
41100
+ const to = own3 && removedTarget(own3) ? own3 : rowTemplateTarget(entry, removedTarget);
40800
41101
  if (!to) return false;
40801
41102
  dropped.push({ screen: r.label, node: entryLabel(entry), to });
40802
41103
  return true;
@@ -44922,6 +45223,254 @@ var init_functions = __esm({
44922
45223
  }
44923
45224
  });
44924
45225
 
45226
+ // src/studio-reel.ts
45227
+ var studio_reel_exports = {};
45228
+ __export(studio_reel_exports, {
45229
+ REEL_BUDGET_BYTES: () => REEL_BUDGET_BYTES,
45230
+ buildReel: () => buildReel,
45231
+ inlineImages: () => inlineImages,
45232
+ planReel: () => planReel,
45233
+ renderReel: () => renderReel,
45234
+ thin: () => thin,
45235
+ utcDay: () => utcDay
45236
+ });
45237
+ import { createHash as createHash24 } from "node:crypto";
45238
+ import { lstatSync as lstatSync7, readFileSync as readFileSync52 } from "node:fs";
45239
+ import { basename as basename11, join as join45 } from "node:path";
45240
+ function loadMemory2(dir) {
45241
+ const m = readJson4(join45(dir, ".himi", "studio", "memory.json"));
45242
+ if (!isObj(m) || m.version !== 1 || !isObj(m.shots) || !Array.isArray(m.timeline)) return null;
45243
+ const shots = [];
45244
+ for (const [id, s] of Object.entries(m.shots)) {
45245
+ if (!isObj(s)) continue;
45246
+ const file = historyName(s.sha, s.ext);
45247
+ const firstSeen = str(s.firstSeen);
45248
+ if (!file || !firstSeen) continue;
45249
+ const versions = typeof s.versions === "number" && Number.isSafeInteger(s.versions) && s.versions > 0 ? s.versions : 1;
45250
+ shots.push({ id, file, firstSeen, versions, present: s.present === true });
45251
+ }
45252
+ const timeline = [];
45253
+ for (const t of m.timeline) {
45254
+ if (!isObj(t)) continue;
45255
+ const file = historyName(t.sha, t.ext);
45256
+ const ts2 = str(t.ts);
45257
+ const id = str(t.id);
45258
+ if (file && ts2 && id) timeline.push({ ts: ts2, id, file });
45259
+ }
45260
+ return { createdAt: str(m.createdAt), shots, timeline };
45261
+ }
45262
+ function captionAt(entries, ts2) {
45263
+ let best = null;
45264
+ for (const e of entries) if (e.ts <= ts2) best = e;
45265
+ return best ? best.message : null;
45266
+ }
45267
+ function thin(items, max) {
45268
+ if (items.length <= max) return items;
45269
+ if (max < 2) return items.slice(-1);
45270
+ const out = [];
45271
+ for (let i = 0; i < max; i++) out.push(items[Math.round(i * (items.length - 1) / (max - 1))]);
45272
+ return out;
45273
+ }
45274
+ function planReel(dir) {
45275
+ const memory = loadMemory2(dir);
45276
+ const { entries } = readProgress(dir);
45277
+ const summary = summarizeProgress(entries);
45278
+ const manifest = readJson4(join45(dir, "himalaya.content.json"));
45279
+ const tokens = readJson4(join45(dir, "tokens.json"));
45280
+ const accentToken = tokens?.colors?.accentPrimary;
45281
+ const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
45282
+ const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
45283
+ const shots = memory?.shots ?? [];
45284
+ const present = shots.filter((s) => s.present).sort((a, b) => a.firstSeen.localeCompare(b.firstSeen) || a.id.localeCompare(b.id));
45285
+ const home = present.find((s) => /(^|_)home($|_)/i.test(s.id)) ?? present.find((s) => /home/i.test(s.id));
45286
+ const focusId = home?.id ?? present[0]?.id ?? null;
45287
+ const timeline = memory && focusId ? memory.timeline.filter((t) => t.id === focusId) : [];
45288
+ const frames = thin(timeline, MAX_FLIP_FRAMES).map((t) => ({ ts: t.ts, file: t.file, caption: captionAt(entries, t.ts) }));
45289
+ const finals = present.map((s) => ({ id: s.id, file: s.file }));
45290
+ const postcards = entries.map((e) => ({
45291
+ ts: e.ts,
45292
+ message: e.message,
45293
+ step: str(e.step),
45294
+ files: (Array.isArray(e.images) ? e.images : []).map((i) => isObj(i) && typeof i.file === "string" ? basename11(i.file) : "").filter((f) => HISTORY_NAME.test(f))
45295
+ }));
45296
+ const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
45297
+ const startedAt = times[0] ?? null;
45298
+ const endedAt = [summary.lastAt, ...timeline.map((t) => t.ts)].filter((x) => !!x).sort().pop() ?? null;
45299
+ return {
45300
+ app: typeof manifest?.name === "string" && manifest.name ? manifest.name : basename11(dir),
45301
+ accent,
45302
+ startedAt,
45303
+ endedAt,
45304
+ focusId,
45305
+ frames,
45306
+ finals,
45307
+ postcards,
45308
+ stats: {
45309
+ screens: finals.length,
45310
+ versions: shots.reduce((n, s) => n + s.versions, 0),
45311
+ postcards: entries.length,
45312
+ elapsedMs: startedAt && endedAt ? Date.parse(endedAt) - Date.parse(startedAt) : null
45313
+ },
45314
+ dropped: 0
45315
+ };
45316
+ }
45317
+ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
45318
+ const verified = (f) => {
45319
+ if (!HISTORY_NAME.test(f)) return null;
45320
+ try {
45321
+ const path2 = join45(dir, HISTORY_DIR, f);
45322
+ const st = lstatSync7(path2);
45323
+ if (!st.isFile() || st.nlink !== 1) return null;
45324
+ const bytes2 = readFileSync52(path2);
45325
+ return createHash24("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
45326
+ } catch {
45327
+ return null;
45328
+ }
45329
+ };
45330
+ const sizes = /* @__PURE__ */ new Map();
45331
+ const sizeOf = (f) => {
45332
+ if (!sizes.has(f)) sizes.set(f, verified(f)?.length ?? null);
45333
+ return sizes.get(f);
45334
+ };
45335
+ const total = (p) => {
45336
+ const blank = /* @__PURE__ */ new Map();
45337
+ let bytes2 = 0;
45338
+ for (const f of cited(p)) {
45339
+ const n = sizeOf(f);
45340
+ if (n === null) continue;
45341
+ blank.set(f, "");
45342
+ bytes2 += `data:${mimeOf(f)};base64,`.length + 4 * Math.ceil(n / 3);
45343
+ }
45344
+ return bytes2 + Buffer.byteLength(renderReel(p, blank));
45345
+ };
45346
+ let current = { ...plan };
45347
+ let dropped = 0;
45348
+ const over = () => total(current) > budget;
45349
+ while (over() && current.frames.length > 2) {
45350
+ const next = thin(current.frames, Math.max(2, Math.floor(current.frames.length * 0.7)));
45351
+ dropped += current.frames.length - next.length;
45352
+ current = { ...current, frames: next };
45353
+ }
45354
+ for (let i = 0; i < current.postcards.length && over(); i++) {
45355
+ if (!current.postcards[i].files.length) continue;
45356
+ dropped += current.postcards[i].files.length;
45357
+ current = { ...current, postcards: current.postcards.map((c, j) => j === i ? { ...c, files: [] } : c) };
45358
+ }
45359
+ const order = current.finals.map((f, j) => ({ f, j })).filter(({ f }) => f.file).sort((a, b) => Number(a.f.id === current.focusId) - Number(b.f.id === current.focusId) || b.j - a.j);
45360
+ for (const { j } of order) {
45361
+ if (!over()) break;
45362
+ dropped++;
45363
+ current = { ...current, finals: current.finals.map((f, k) => k === j ? { ...f, file: null } : f) };
45364
+ }
45365
+ if (over() && current.frames.length > 1) {
45366
+ dropped += current.frames.length - 1;
45367
+ current = { ...current, frames: current.frames.slice(-1) };
45368
+ }
45369
+ const images = /* @__PURE__ */ new Map();
45370
+ for (const f of new Set(cited(current))) {
45371
+ if (sizeOf(f) === null) continue;
45372
+ const bytes2 = verified(f);
45373
+ if (!bytes2 || bytes2.length !== sizeOf(f)) continue;
45374
+ images.set(f, `data:${mimeOf(f)};base64,${bytes2.toString("base64")}`);
45375
+ }
45376
+ return { plan: { ...current, dropped }, images };
45377
+ }
45378
+ function duration(ms) {
45379
+ if (ms === null || !Number.isFinite(ms) || ms < 0) return "\u2014";
45380
+ const m = Math.round(ms / 6e4);
45381
+ return m < 60 ? `${m} min` : `${Math.floor(m / 60)} h ${m % 60} min`;
45382
+ }
45383
+ function utcDay(ts2) {
45384
+ const d = new Date(ts2);
45385
+ return Number.isNaN(d.getTime()) ? "" : `${d.toUTCString().slice(0, 16)} (UTC)`;
45386
+ }
45387
+ function sinceStart(start, ts2) {
45388
+ if (!start) return "";
45389
+ const s = Math.max(0, Math.round((Date.parse(ts2) - Date.parse(start)) / 1e3));
45390
+ const h = Math.floor(s / 3600);
45391
+ const m = Math.floor(s % 3600 / 60);
45392
+ const sec = String(s % 60).padStart(2, "0");
45393
+ return h ? `${h}:${String(m).padStart(2, "0")}:${sec}` : `${m}:${sec}`;
45394
+ }
45395
+ function renderReel(plan, images) {
45396
+ const img = (f, alt, cls = "") => f && images.has(f) ? `<img class="${cls}" src="${images.get(f)}" alt="${escapeHtml(alt)}">` : "";
45397
+ const count = (n) => escapeHtml(String(Number.isSafeInteger(n) && n >= 0 ? n : 0));
45398
+ const accent = ACCENT.test(plan.accent) ? plan.accent : DEFAULT_ACCENT;
45399
+ const clock = (ts2) => sinceStart(plan.startedAt, ts2);
45400
+ const frames = plan.frames.filter((f) => images.has(f.file));
45401
+ const flip = frames.length ? `<section class="flip"><div class="phone">${frames.map((f, i) => `<img class="fr${i === 0 ? " on" : ""}" src="${images.get(f.file)}" alt="${escapeHtml(plan.focusId ?? "")} at ${clock(f.ts)}">`).join("")}</div>
45402
+ <div class="flipcap"><div class="t" id="ft">${frames[0] ? clock(frames[0].ts) : ""}</div><div id="fc">${escapeHtml(frames[0]?.caption ?? "")}</div><div class="bar"><div id="fb"></div></div></div></section>` : `<p class="muted">No screen versions were recorded \u2014 open the build board with <code>himi studio</code> before building to capture them.</p>`;
45403
+ const data = JSON.stringify(frames.map((f) => ({ t: clock(f.ts), c: f.caption ?? "" }))).replace(/</g, "\\u003c");
45404
+ return `<!doctype html>
45405
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
45406
+ <title>${escapeHtml(plan.app)} \xB7 the making of</title>
45407
+ <style>
45408
+ :root{--bg:#f6f5f2;--card:#fff;--ink:#1c1c1a;--muted:#6b6a64;--line:#e6e3dc;--accent:${accent}}
45409
+ @media (prefers-color-scheme:dark){:root{--bg:#121211;--card:#1c1c1a;--ink:#ecebe6;--muted:#a3a19a;--line:#2c2b28}}
45410
+ *{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.55 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
45411
+ .wrap{max-width:980px;margin:0 auto;padding:32px 20px 64px}h1{font-size:30px;margin:0 0 4px}h2{font-size:14px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin:40px 0 14px}
45412
+ .muted{color:var(--muted)}.stats{display:flex;gap:28px;flex-wrap:wrap;margin:18px 0 8px}.stats b{display:block;font-size:24px}
45413
+ .flip{display:flex;gap:28px;align-items:center;flex-wrap:wrap}.phone{position:relative;width:280px;aspect-ratio:390/844;border:10px solid #111;border-radius:38px;overflow:hidden;background:#fff;flex:none}
45414
+ .phone img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top;opacity:0;transition:opacity .35s}.phone img.on{opacity:1}
45415
+ .flipcap{flex:1;min-width:220px}.flipcap .t{font-size:40px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--accent)}.bar{height:4px;background:var(--line);border-radius:2px;margin-top:16px}.bar div{height:4px;background:var(--accent);border-radius:2px;width:0}
45416
+ .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:18px}.grid figure{margin:0;text-align:center}.grid img{width:100%;aspect-ratio:390/844;object-fit:cover;object-position:top;border:6px solid #111;border-radius:22px;background:#fff}
45417
+ figcaption{font-size:12px;color:var(--muted);margin-top:6px;word-break:break-all}
45418
+ .log{list-style:none;padding:0;margin:0}.log li{display:flex;gap:14px;padding:12px 0;border-top:1px solid var(--line)}.log .t{min-width:52px;color:var(--muted);font-variant-numeric:tabular-nums}.log .s{font-size:12px;color:var(--muted);text-transform:capitalize}
45419
+ .log .imgs{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}.log .imgs img{height:120px;border-radius:10px;border:1px solid var(--line)}
45420
+ footer{margin-top:48px;font-size:12px;color:var(--muted)}
45421
+ </style></head><body><div class="wrap">
45422
+ <h1>${escapeHtml(plan.app)}</h1><div class="muted">The making of \u2014 every version of the app as it was built${plan.startedAt ? `, ${escapeHtml(utcDay(plan.startedAt))}` : ""}</div>
45423
+ <div class="stats"><div><b>${duration(plan.stats.elapsedMs)}</b><span class="muted">from first picture to last</span></div><div><b>${count(plan.stats.screens)}</b><span class="muted">screens</span></div><div><b>${count(plan.stats.versions)}</b><span class="muted">versions rendered</span></div><div><b>${count(plan.stats.postcards)}</b><span class="muted">postcards</span></div></div>
45424
+ <h2>${escapeHtml(plan.focusId ?? "The app")}, version by version</h2>
45425
+ ${flip}
45426
+ <h2>Where it ended up</h2>
45427
+ <div class="grid">${plan.finals.map((f) => `<figure>${img(f.file, f.id)}<figcaption>${escapeHtml(f.id)}</figcaption></figure>`).join("")}</div>
45428
+ <h2>Postcards</h2>
45429
+ <ul class="log">${plan.postcards.map((c) => `<li><div class="t">${clock(c.ts)}</div><div><div>${escapeHtml(c.message)}</div>${c.step ? `<div class="s">step ${JOURNEY_STEPS.indexOf(c.step) + 1} \xB7 ${escapeHtml(c.step)}</div>` : ""}${c.files.length ? `<div class="imgs">${c.files.map((f) => img(f, c.message)).join("")}</div>` : ""}</div></li>`).join("") || `<li class="muted">No postcards were journaled.</li>`}</ul>
45430
+ <footer>Built with himi.${plan.dropped ? ` ${count(plan.dropped)} pictures were left out to keep this file small.` : ""}</footer>
45431
+ </div>
45432
+ <script>
45433
+ (function(){var F=${data};var imgs=document.querySelectorAll(".phone img");if(imgs.length<2)return;var i=0;
45434
+ function show(n){imgs[i].classList.remove("on");i=n;imgs[i].classList.add("on");document.getElementById("ft").textContent=F[i].t;document.getElementById("fc").textContent=F[i].c;document.getElementById("fb").style.width=(100*i/(imgs.length-1))+"%"}
45435
+ function tick(){show(i+1<imgs.length?i+1:0);setTimeout(tick,i+1<imgs.length?900:2500)}setTimeout(tick,1200);})();
45436
+ </script>
45437
+ </body></html>
45438
+ `;
45439
+ }
45440
+ function buildReel(dir, budget = REEL_BUDGET_BYTES) {
45441
+ const { plan, images } = inlineImages(dir, planReel(dir), budget);
45442
+ return { html: renderReel(plan, images), plan };
45443
+ }
45444
+ var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson4, isObj, str, historyName, cited;
45445
+ var init_studio_reel = __esm({
45446
+ "src/studio-reel.ts"() {
45447
+ init_progress();
45448
+ init_studio();
45449
+ REEL_BUDGET_BYTES = 12 * 1024 * 1024;
45450
+ MAX_FLIP_FRAMES = 40;
45451
+ DEFAULT_ACCENT = "#3b6fd8";
45452
+ ACCENT = /^#[0-9a-f]{3,8}$/i;
45453
+ HISTORY_NAME = /^[0-9a-f]{64}\.(png|jpg|gif|webp)$/;
45454
+ MIME2 = { png: "image/png", jpg: "image/jpeg", gif: "image/gif", webp: "image/webp" };
45455
+ mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
45456
+ readJson4 = (file) => {
45457
+ try {
45458
+ return JSON.parse(readFileSync52(file, "utf8"));
45459
+ } catch {
45460
+ return null;
45461
+ }
45462
+ };
45463
+ isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
45464
+ str = (v) => typeof v === "string" && v ? v : null;
45465
+ historyName = (sha, ext) => typeof sha === "string" && typeof ext === "string" && HISTORY_NAME.test(`${sha}.${ext}`) ? `${sha}.${ext}` : null;
45466
+ cited = (p) => [
45467
+ ...p.frames.map((f) => f.file),
45468
+ ...p.finals.flatMap((f) => f.file ? [f.file] : []),
45469
+ ...p.postcards.flatMap((c) => c.files)
45470
+ ];
45471
+ }
45472
+ });
45473
+
44925
45474
  // src/native-decode.ts
44926
45475
  var native_decode_exports = {};
44927
45476
  __export(native_decode_exports, {
@@ -44937,9 +45486,9 @@ __export(native_decode_exports, {
44937
45486
  runNativeDecode: () => runNativeDecode
44938
45487
  });
44939
45488
  import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
44940
- import { existsSync as existsSync48, mkdtempSync as mkdtempSync2, readFileSync as readFileSync52, rmSync as rmSync10, writeFileSync as writeFileSync20 } from "node:fs";
45489
+ import { existsSync as existsSync48, mkdtempSync as mkdtempSync2, readFileSync as readFileSync53, rmSync as rmSync10, writeFileSync as writeFileSync20 } from "node:fs";
44941
45490
  import { tmpdir as tmpdir3 } from "node:os";
44942
- import { join as join45 } from "node:path";
45491
+ import { join as join46 } from "node:path";
44943
45492
  import { fileURLToPath as fileURLToPath20 } from "node:url";
44944
45493
  function nativeDecodePackageDir() {
44945
45494
  return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
@@ -44949,8 +45498,8 @@ function nativeDecodeAndroidHarnessDir() {
44949
45498
  }
44950
45499
  function nativeOracleShipped() {
44951
45500
  return {
44952
- ios: existsSync48(join45(nativeDecodePackageDir(), "Package.swift")),
44953
- android: existsSync48(join45(nativeDecodeAndroidHarnessDir(), "gradlew"))
45501
+ ios: existsSync48(join46(nativeDecodePackageDir(), "Package.swift")),
45502
+ android: existsSync48(join46(nativeDecodeAndroidHarnessDir(), "gradlew"))
44954
45503
  };
44955
45504
  }
44956
45505
  function detectNativeDecode(options = {}) {
@@ -44961,7 +45510,7 @@ function detectNativeDecode(options = {}) {
44961
45510
  return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
44962
45511
  }
44963
45512
  if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
44964
- const packageAvailable = options.packageAvailable ?? existsSync48(join45(packageDir, "Package.swift"));
45513
+ const packageAvailable = options.packageAvailable ?? existsSync48(join46(packageDir, "Package.swift"));
44965
45514
  if (!packageAvailable) {
44966
45515
  return {
44967
45516
  platform: "ios",
@@ -44973,7 +45522,7 @@ function detectNativeDecode(options = {}) {
44973
45522
  }
44974
45523
  function localPropertiesSdk(harnessDir) {
44975
45524
  try {
44976
- const match = readFileSync52(join45(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
45525
+ const match = readFileSync53(join46(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
44977
45526
  return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
44978
45527
  } catch {
44979
45528
  return null;
@@ -44981,7 +45530,7 @@ function localPropertiesSdk(harnessDir) {
44981
45530
  }
44982
45531
  function detectAndroidNativeDecode(options = {}) {
44983
45532
  const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
44984
- const gradlew = join45(harnessDir, "gradlew");
45533
+ const gradlew = join46(harnessDir, "gradlew");
44985
45534
  const gradlewAvailable = options.gradlewAvailable ?? existsSync48(gradlew);
44986
45535
  if (!gradlewAvailable) {
44987
45536
  return {
@@ -45064,14 +45613,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
45064
45613
  return verdicts;
45065
45614
  }
45066
45615
  function runNativeDecode(options) {
45067
- const descriptorDir = mkdtempSync2(join45(tmpdir3(), "himi-native-decode-"));
45616
+ const descriptorDir = mkdtempSync2(join46(tmpdir3(), "himi-native-decode-"));
45068
45617
  const startedAt = Date.now();
45069
45618
  try {
45070
45619
  for (const descriptor of options.descriptors) {
45071
45620
  if (typeof descriptor.descriptorJson !== "string") {
45072
45621
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
45073
45622
  }
45074
- writeFileSync20(join45(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45623
+ writeFileSync20(join46(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45075
45624
  }
45076
45625
  options.progress?.("building cached Swift oracle");
45077
45626
  execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
@@ -45083,7 +45632,7 @@ function runNativeDecode(options) {
45083
45632
  encoding: "utf8"
45084
45633
  }).trim();
45085
45634
  options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
45086
- const stdout = execFileSync5(join45(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
45635
+ const stdout = execFileSync5(join46(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
45087
45636
  stdio: ["ignore", "pipe", "pipe"],
45088
45637
  encoding: "utf8"
45089
45638
  });
@@ -45101,15 +45650,15 @@ function runNativeDecode(options) {
45101
45650
  }
45102
45651
  }
45103
45652
  function runAndroidNativeDecode(options) {
45104
- const descriptorDir = mkdtempSync2(join45(tmpdir3(), "himi-native-decode-android-"));
45105
- const outputPath = join45(descriptorDir, "verdicts.ndjson");
45653
+ const descriptorDir = mkdtempSync2(join46(tmpdir3(), "himi-native-decode-android-"));
45654
+ const outputPath = join46(descriptorDir, "verdicts.ndjson");
45106
45655
  const startedAt = Date.now();
45107
45656
  try {
45108
45657
  for (const descriptor of options.descriptors) {
45109
45658
  if (typeof descriptor.descriptorJson !== "string") {
45110
45659
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
45111
45660
  }
45112
- writeFileSync20(join45(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45661
+ writeFileSync20(join46(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45113
45662
  }
45114
45663
  options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
45115
45664
  execFileSync5(options.gradlew, [
@@ -45124,7 +45673,7 @@ function runAndroidNativeDecode(options) {
45124
45673
  stdio: ["ignore", "ignore", "pipe"],
45125
45674
  encoding: "utf8"
45126
45675
  });
45127
- const stdout = readFileSync52(outputPath, "utf8");
45676
+ const stdout = readFileSync53(outputPath, "utf8");
45128
45677
  return {
45129
45678
  platform: "android",
45130
45679
  verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
@@ -45193,14 +45742,14 @@ __export(browser_authoring_exports, {
45193
45742
  sdkSubpathReader: () => sdkSubpathReader
45194
45743
  });
45195
45744
  import { createServer as createServer3 } from "node:http";
45196
- import { createHash as createHash24, randomBytes as randomBytes4 } from "node:crypto";
45197
- import { existsSync as existsSync49, readdirSync as readdirSync24, readFileSync as readFileSync53, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
45198
- import { join as join46, posix, relative as relative8, sep as sep12 } from "node:path";
45745
+ import { createHash as createHash25, randomBytes as randomBytes4 } from "node:crypto";
45746
+ import { existsSync as existsSync49, readdirSync as readdirSync24, readFileSync as readFileSync54, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
45747
+ import { join as join47, posix, relative as relative8, sep as sep12 } from "node:path";
45199
45748
  function humanMs(ms) {
45200
45749
  return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
45201
45750
  }
45202
45751
  function collectWorkerSources(tier5SrcDir, bundleName) {
45203
- const root = join46(tier5SrcDir, bundleName);
45752
+ const root = join47(tier5SrcDir, bundleName);
45204
45753
  const files = {};
45205
45754
  const visitedDirs = /* @__PURE__ */ new Set();
45206
45755
  const walk2 = (abs, rel) => {
@@ -45208,12 +45757,12 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
45208
45757
  if (visitedDirs.has(real)) return;
45209
45758
  visitedDirs.add(real);
45210
45759
  for (const name of readdirSync24(abs).sort()) {
45211
- const childAbs = join46(abs, name);
45760
+ const childAbs = join47(abs, name);
45212
45761
  const childRel = posix.join(rel, name);
45213
45762
  if (statSync12(childAbs).isDirectory()) {
45214
45763
  walk2(childAbs, childRel);
45215
45764
  } else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
45216
- files[childRel] = readFileSync53(childAbs, "utf8");
45765
+ files[childRel] = readFileSync54(childAbs, "utf8");
45217
45766
  }
45218
45767
  }
45219
45768
  };
@@ -45234,20 +45783,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
45234
45783
  const spec = m[1];
45235
45784
  const virtual = posix.normalize(posix.join(dir, spec));
45236
45785
  if (!virtual.startsWith("/tier5-src/")) continue;
45237
- const onDisk = join46(tier5SrcDir, virtual.slice("/tier5-src/".length));
45786
+ const onDisk = join47(tier5SrcDir, virtual.slice("/tier5-src/".length));
45238
45787
  const candidates = [
45239
45788
  onDisk,
45240
45789
  `${onDisk}.ts`,
45241
45790
  `${onDisk}.js`,
45242
45791
  onDisk.replace(/\.js$/, ".ts"),
45243
- join46(onDisk, "index.ts"),
45244
- join46(onDisk, "index.js")
45792
+ join47(onDisk, "index.ts"),
45793
+ join47(onDisk, "index.js")
45245
45794
  ];
45246
45795
  for (const abs of candidates) {
45247
45796
  if (!existsSync49(abs) || statSync12(abs).isDirectory()) continue;
45248
45797
  const key2 = `/tier5-src/${relative8(tier5SrcDir, abs).split(sep12).join(posix.sep)}`;
45249
45798
  if (key2 in files) break;
45250
- files[key2] = readFileSync53(abs, "utf8");
45799
+ files[key2] = readFileSync54(abs, "utf8");
45251
45800
  queue.push(key2);
45252
45801
  break;
45253
45802
  }
@@ -45282,7 +45831,7 @@ function collectSdkModules(files, resolveSubpath) {
45282
45831
  function sdkSubpathReader(resolve48) {
45283
45832
  return (sub) => {
45284
45833
  try {
45285
- return readFileSync53(resolve48(`@wix/himalaya/${sub}`), "utf8");
45834
+ return readFileSync54(resolve48(`@wix/himalaya/${sub}`), "utf8");
45286
45835
  } catch {
45287
45836
  return null;
45288
45837
  }
@@ -45292,7 +45841,7 @@ function encodeJob(job) {
45292
45841
  return Buffer.from(JSON.stringify(job), "utf8").toString("base64");
45293
45842
  }
45294
45843
  function mintToken2(payload, nonce = randomBytes4(16).toString("hex")) {
45295
- const digest2 = createHash24("sha256").update(payload, "utf8").digest("base64url");
45844
+ const digest2 = createHash25("sha256").update(payload, "utf8").digest("base64url");
45296
45845
  return `${nonce}.${digest2}`;
45297
45846
  }
45298
45847
  function defaultOpenBrowser2(url) {
@@ -45454,8 +46003,8 @@ __export(coverage_exports, {
45454
46003
  suppressedNativeKeys: () => suppressedNativeKeys,
45455
46004
  trendAndStore: () => trendAndStore
45456
46005
  });
45457
- import { existsSync as existsSync50, mkdirSync as mkdirSync24, readFileSync as readFileSync54, writeFileSync as writeFileSync21 } from "node:fs";
45458
- import { dirname as dirname26, join as join47 } from "node:path";
46006
+ import { existsSync as existsSync50, mkdirSync as mkdirSync24, readFileSync as readFileSync55, writeFileSync as writeFileSync21 } from "node:fs";
46007
+ import { dirname as dirname26, join as join48 } from "node:path";
45459
46008
  function suppressedNativeKeys(oracle) {
45460
46009
  return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
45461
46010
  }
@@ -45516,15 +46065,15 @@ function assembleLedger(r, options = {}) {
45516
46065
  remedy: SOURCEMAP_REMEDY[c.sourcemap]
45517
46066
  });
45518
46067
  }
45519
- const own2 = (c.uncoveredFunctions ?? []).filter((f) => f.source?.startsWith("tier5-src/") || f.source?.startsWith("core/dev-server/tier5-bundles-src/"));
45520
- if (!own2.length) continue;
45521
- const named = own2.slice(0, 6).map((f) => `${f.name} (${f.source})`).join(", ");
45522
- const more = own2.length > 6 ? ` +${own2.length - 6} more` : "";
46068
+ const own3 = (c.uncoveredFunctions ?? []).filter((f) => f.source?.startsWith("tier5-src/") || f.source?.startsWith("core/dev-server/tier5-bundles-src/"));
46069
+ if (!own3.length) continue;
46070
+ const named = own3.slice(0, 6).map((f) => `${f.name} (${f.source})`).join(", ");
46071
+ const more = own3.length > 6 ? ` +${own3.length - 6} more` : "";
45523
46072
  out.push({
45524
46073
  key: `code-uncovered|${c.screen}`,
45525
46074
  kind: "code-uncovered",
45526
46075
  screen: c.screen,
45527
- gap: `${own2.length} worker function${own2.length === 1 ? "" : "s"} never executed on any axis: ${named}${more}`,
46076
+ gap: `${own3.length} worker function${own3.length === 1 ? "" : "s"} never executed on any axis: ${named}${more}`,
45528
46077
  remedy: "usually an error/edge branch \u2014 give the crawl data that reaches it (a net-mocks rule, cms seed rows, or a nav edge with the right input), or verify the path on a preview"
45529
46078
  });
45530
46079
  }
@@ -45625,11 +46174,11 @@ function assembleLedger(r, options = {}) {
45625
46174
  return out;
45626
46175
  }
45627
46176
  function trendAndStore(dir, entries, suppressed) {
45628
- const p = join47(dir, LEDGER_FILE);
46177
+ const p = join48(dir, LEDGER_FILE);
45629
46178
  let previous = null;
45630
46179
  try {
45631
46180
  if (existsSync50(p)) {
45632
- const parsed = JSON.parse(readFileSync54(p, "utf8"));
46181
+ const parsed = JSON.parse(readFileSync55(p, "utf8"));
45633
46182
  if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
45634
46183
  }
45635
46184
  } catch {
@@ -45668,11 +46217,11 @@ function formatLedger(entries, trend) {
45668
46217
  return out.join("\n");
45669
46218
  }
45670
46219
  function diffAndStoreObservations(dir, current) {
45671
- const p = join47(dir, OBS_FILE);
46220
+ const p = join48(dir, OBS_FILE);
45672
46221
  let previous = null;
45673
46222
  try {
45674
46223
  if (existsSync50(p)) {
45675
- const parsed = JSON.parse(readFileSync54(p, "utf8"));
46224
+ const parsed = JSON.parse(readFileSync55(p, "utf8"));
45676
46225
  if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
45677
46226
  (v) => Array.isArray(v) && v.every((l) => typeof l === "string")
45678
46227
  )) {
@@ -45721,8 +46270,8 @@ var LEDGER_FILE, OBS_FILE;
45721
46270
  var init_coverage = __esm({
45722
46271
  "src/coverage.ts"() {
45723
46272
  init_native_decode();
45724
- LEDGER_FILE = join47(".himi", "test-ledger.json");
45725
- OBS_FILE = join47(".himi", "test-observations.json");
46273
+ LEDGER_FILE = join48(".himi", "test-ledger.json");
46274
+ OBS_FILE = join48(".himi", "test-observations.json");
45726
46275
  }
45727
46276
  });
45728
46277
 
@@ -45733,8 +46282,8 @@ __export(design_kits_exports, {
45733
46282
  kitsDir: () => kitsDir,
45734
46283
  listKits: () => listKits2
45735
46284
  });
45736
- import { existsSync as existsSync51, readFileSync as readFileSync55, readdirSync as readdirSync25 } from "node:fs";
45737
- import { join as join48, basename as basename11 } from "node:path";
46285
+ import { existsSync as existsSync51, readFileSync as readFileSync56, readdirSync as readdirSync25 } from "node:fs";
46286
+ import { join as join49, basename as basename12 } from "node:path";
45738
46287
  import { fileURLToPath as fileURLToPath21 } from "node:url";
45739
46288
  function kitsDir() {
45740
46289
  return KIT_DIR_CANDIDATES.find((p) => existsSync51(p));
@@ -45742,7 +46291,7 @@ function kitsDir() {
45742
46291
  function listKits2() {
45743
46292
  const dir = kitsDir();
45744
46293
  if (!dir) return [];
45745
- return readdirSync25(dir).filter((f) => f.endsWith(".json")).map((f) => basename11(f, ".json")).sort();
46294
+ return readdirSync25(dir).filter((f) => f.endsWith(".json")).map((f) => basename12(f, ".json")).sort();
45746
46295
  }
45747
46296
  function kitReport(name) {
45748
46297
  const dir = kitsDir();
@@ -45761,7 +46310,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
45761
46310
  if (!kits.includes(name)) {
45762
46311
  return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
45763
46312
  }
45764
- const raw = readFileSync55(join48(dir, `${name}.json`), "utf8");
46313
+ const raw = readFileSync56(join49(dir, `${name}.json`), "utf8");
45765
46314
  let parsed;
45766
46315
  try {
45767
46316
  parsed = JSON.parse(raw);
@@ -45785,9 +46334,9 @@ var init_design_kits = __esm({
45785
46334
  "src/design-kits.ts"() {
45786
46335
  KIT_DIR_CANDIDATES = [
45787
46336
  // in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
45788
- join48(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
46337
+ join49(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
45789
46338
  // published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
45790
- join48(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
46339
+ join49(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
45791
46340
  ];
45792
46341
  }
45793
46342
  });
@@ -45801,11 +46350,11 @@ __export(assets_exports, {
45801
46350
  removeAssetPayload: () => removeAssetPayload,
45802
46351
  verifyReport: () => verifyReport
45803
46352
  });
45804
- import { readFileSync as readFileSync56 } from "node:fs";
45805
- import { basename as basename12 } from "node:path";
46353
+ import { readFileSync as readFileSync57 } from "node:fs";
46354
+ import { basename as basename13 } from "node:path";
45806
46355
  function declaredAssets(dir) {
45807
46356
  return collectAssets(dir).map((a) => {
45808
- const bytes2 = readFileSync56(a.path);
46357
+ const bytes2 = readFileSync57(a.path);
45809
46358
  return {
45810
46359
  name: a.name,
45811
46360
  sha256: assetSha256(bytes2),
@@ -45882,8 +46431,8 @@ function verifyReport(dir, app, manifest) {
45882
46431
  };
45883
46432
  }
45884
46433
  function addAssetPayload(manifest, filePath, opts) {
45885
- const bytes2 = readFileSync56(filePath);
45886
- const name = opts.name ?? basename12(filePath);
46434
+ const bytes2 = readFileSync57(filePath);
46435
+ const name = opts.name ?? basename13(filePath);
45887
46436
  const sha2565 = assetSha256(bytes2);
45888
46437
  const record2 = {
45889
46438
  sha256: sha2565,
@@ -46767,12 +47316,13 @@ ${releaseId}`;
46767
47316
  const bytes2 = await store.getSource(app, m.sourceHash);
46768
47317
  if (!bytes2) return json3(404, { error: "template_source_not_found", app });
46769
47318
  const etag = `"${m.sourceHash}"`;
47319
+ const cache = { "cache-control": pin ? PINNED_CACHE_CONTROL : DOC_CACHE_CONTROL, ...pin ? { vary: "x-himalaya-release" } : {} };
46770
47320
  if (request.headers.get("if-none-match") === etag) {
46771
- return new Response(null, { status: 304, headers: { etag, "cache-control": DOC_CACHE_CONTROL } });
47321
+ return new Response(null, { status: 304, headers: { etag, ...cache } });
46772
47322
  }
46773
47323
  return new Response(bytes2, {
46774
47324
  status: 200,
46775
- headers: { "content-type": JSON_CT, etag, "cache-control": DOC_CACHE_CONTROL, "x-himalaya-app": app }
47325
+ headers: { "content-type": JSON_CT, etag, ...cache, "x-himalaya-app": app }
46776
47326
  });
46777
47327
  }
46778
47328
  if (path2 === "/v1/authoring-docs" || /^\/v1\/authoring-docs\/(spec|mobile-ux)$/.test(path2)) {
@@ -47449,19 +47999,19 @@ var init_preview_assets_generated = __esm({
47449
47999
  "../../packages/serve/src/preview-assets.generated.ts"() {
47450
48000
  init_preview_assets_format();
47451
48001
  PREVIEW_ASSET_MANIFEST = [
47452
- { key: "assets/index-TpXF5JLO.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1013412, sha256: "e6d1da59c13ca586b7834f4d08ca9e136b7fea8be9355d952d757fc66fc779a5" },
47453
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1013420, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
47454
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1104344, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
47455
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1195328, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
47456
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1286308, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
47457
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1377180, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
47458
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1468160, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
47459
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1576796, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
47460
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1685880, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
47461
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1794928, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
47462
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1902628, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
47463
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1990736, length: 4448, sha256: "5f0ee56640a5dfc73d3b2b78526aa1f7966de1bec39fe746e0d9ba39d57d829e" },
47464
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1995184, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
48002
+ { key: "assets/index-DRerTUYc.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1016478, sha256: "42a5b901a0a58a495e5261f68782d28d12aa95cf64df33d9d8d14236e8ea6ead" },
48003
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1016486, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
48004
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1107410, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
48005
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1198394, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
48006
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1289374, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
48007
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1380246, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
48008
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1471226, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
48009
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1579862, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
48010
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1688946, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
48011
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1797994, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
48012
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1905694, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
48013
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1993802, length: 4448, sha256: "98239860f1289aebffdb28d2b9f5ce15fbb95a657bb63d262c650ca21513dde3" },
48014
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1998250, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
47465
48015
  ];
47466
48016
  }
47467
48017
  });
@@ -47477,9 +48027,9 @@ __export(run_exports, {
47477
48027
  runPackage: () => runPackage,
47478
48028
  withoutProdServe: () => withoutProdServe
47479
48029
  });
47480
- import { cpSync as cpSync2, existsSync as existsSync52, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, readFileSync as readFileSync57, rmSync as rmSync11, statSync as statSync13 } from "node:fs";
48030
+ import { cpSync as cpSync2, existsSync as existsSync52, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, readFileSync as readFileSync58, rmSync as rmSync11, statSync as statSync13 } from "node:fs";
47481
48031
  import { tmpdir as tmpdir4 } from "node:os";
47482
- import { dirname as dirname27, join as join49 } from "node:path";
48032
+ import { dirname as dirname27, join as join50 } from "node:path";
47483
48033
  import { fileURLToPath as fileURLToPath22 } from "node:url";
47484
48034
  function makePackageRunHandler(opts) {
47485
48035
  return makeRunHandler({
@@ -47499,7 +48049,7 @@ async function fetchBytes(url) {
47499
48049
  async function resolvePackage(source, workDir) {
47500
48050
  const isUrl2 = /^https?:\/\//i.test(source);
47501
48051
  if (!isUrl2 && existsSync52(source) && statSync13(source).isDirectory()) {
47502
- const appDirManifest = join49(source, "release-manifest.json");
48052
+ const appDirManifest = join50(source, "release-manifest.json");
47503
48053
  if (existsSync52(appDirManifest)) {
47504
48054
  const opened2 = openPackageDir(source);
47505
48055
  if (!opened2.validation.ok) {
@@ -47509,9 +48059,9 @@ async function resolvePackage(source, workDir) {
47509
48059
  const app2 = opened2.header?.app ?? opened2.manifest?.app;
47510
48060
  if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
47511
48061
  if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
47512
- const root2 = workDir ?? mkdtempSync3(join49(tmpdir4(), "himi-run-"));
47513
- const target = join49(root2, app2);
47514
- if (join49(source) !== target) {
48062
+ const root2 = workDir ?? mkdtempSync3(join50(tmpdir4(), "himi-run-"));
48063
+ const target = join50(root2, app2);
48064
+ if (join50(source) !== target) {
47515
48065
  mkdirSync25(root2, { recursive: true });
47516
48066
  rmSync11(target, { recursive: true, force: true });
47517
48067
  cpSync2(source, target, { recursive: true });
@@ -47528,8 +48078,8 @@ async function resolvePackage(source, workDir) {
47528
48078
  }
47529
48079
  throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
47530
48080
  }
47531
- const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync57(source);
47532
- const root = workDir ?? mkdtempSync3(join49(tmpdir4(), "himi-run-"));
48081
+ const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync58(source);
48082
+ const root = workDir ?? mkdtempSync3(join50(tmpdir4(), "himi-run-"));
47533
48083
  const { app, appDir: appDir2 } = unpackTo(bytes2, root);
47534
48084
  const opened = openPackageDir(appDir2);
47535
48085
  if (!opened.validation.ok) {
@@ -47552,14 +48102,14 @@ async function loadPreviewAssets() {
47552
48102
  const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
47553
48103
  const here = dirname27(fileURLToPath22(import.meta.url));
47554
48104
  const candidates = [
47555
- join49(here, "preview-assets.generated.bin"),
48105
+ join50(here, "preview-assets.generated.bin"),
47556
48106
  // published: copied next to the bundled CLI
47557
- join49(here, "../../../packages/serve/src/preview-assets.generated.bin")
48107
+ join50(here, "../../../packages/serve/src/preview-assets.generated.bin")
47558
48108
  // in-repo checkout
47559
48109
  ];
47560
48110
  for (const path2 of candidates) {
47561
48111
  if (!existsSync52(path2)) continue;
47562
- const blob = readFileSync57(path2);
48112
+ const blob = readFileSync58(path2);
47563
48113
  return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
47564
48114
  }
47565
48115
  return /* @__PURE__ */ new Map();
@@ -47654,9 +48204,9 @@ __export(run_watch_exports, {
47654
48204
  watchedContentDir: () => watchedContentDir,
47655
48205
  writeRunRecord: () => writeRunRecord
47656
48206
  });
47657
- import { closeSync as closeSync2, constants, existsSync as existsSync53, fstatSync, lstatSync as lstatSync7, statSync as statSync14, mkdirSync as mkdirSync26, openSync as openSync2, readFileSync as readFileSync58, realpathSync as realpathSync6, renameSync as renameSync5, rmSync as rmSync12, writeFileSync as writeFileSync22, watch as fsWatch } from "node:fs";
48207
+ import { closeSync as closeSync2, constants, existsSync as existsSync53, fstatSync, lstatSync as lstatSync8, statSync as statSync14, mkdirSync as mkdirSync26, openSync as openSync2, readFileSync as readFileSync59, realpathSync as realpathSync6, renameSync as renameSync5, rmSync as rmSync12, writeFileSync as writeFileSync22, watch as fsWatch } from "node:fs";
47658
48208
  import { randomUUID as randomUUID3 } from "node:crypto";
47659
- import { extname as extname4, join as join50, resolve as resolve42, sep as sep13 } from "node:path";
48209
+ import { extname as extname4, join as join51, resolve as resolve42, sep as sep13 } from "node:path";
47660
48210
  function diffReleases(prev, next) {
47661
48211
  const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
47662
48212
  const changedBundles = new Set(bundles);
@@ -47696,7 +48246,7 @@ function watchContent(dir, onChange, opts = {}) {
47696
48246
  let timer = null;
47697
48247
  const pending = /* @__PURE__ */ new Set();
47698
48248
  const watcher = watch2(dir, { recursive: true }, (_event, file) => {
47699
- if (!file || ignoredChange(file, (rel) => isDir(join50(dir, rel)))) return;
48249
+ if (!file || ignoredChange(file, (rel) => isDir(join51(dir, rel)))) return;
47700
48250
  pending.add(file);
47701
48251
  if (timer) clearTimeout(timer);
47702
48252
  timer = setTimeout(() => {
@@ -47717,7 +48267,7 @@ function watchedContentDir(source) {
47717
48267
  if (!source || /^https?:\/\//i.test(source)) return null;
47718
48268
  const dir = resolve42(source);
47719
48269
  try {
47720
- return statSync14(dir).isDirectory() && existsSync53(join50(dir, "himalaya.content.json")) ? dir : null;
48270
+ return statSync14(dir).isDirectory() && existsSync53(join51(dir, "himalaya.content.json")) ? dir : null;
47721
48271
  } catch {
47722
48272
  return null;
47723
48273
  }
@@ -47774,45 +48324,54 @@ function serialize(task) {
47774
48324
  });
47775
48325
  }
47776
48326
  function himiDir(dir) {
47777
- const root = join50(dir, ".himi");
48327
+ const root = join51(dir, ".himi");
47778
48328
  try {
47779
- return lstatSync7(root).isDirectory() ? root : null;
48329
+ return lstatSync8(root).isDirectory() ? root : null;
47780
48330
  } catch (e) {
47781
48331
  if (e.code !== "ENOENT") return null;
47782
48332
  mkdirSync26(root, { recursive: true });
47783
- return lstatSync7(root).isDirectory() ? root : null;
48333
+ return lstatSync8(root).isDirectory() ? root : null;
47784
48334
  }
47785
48335
  }
47786
48336
  function writeRunRecord(dir, record2) {
47787
48337
  const root = himiDir(dir);
47788
48338
  if (!root) return false;
47789
- const tmp = join50(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
48339
+ const tmp = join51(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
47790
48340
  try {
47791
48341
  writeFileSync22(tmp, `${JSON.stringify(record2, null, 2)}
47792
48342
  `, { flag: "wx" });
47793
- renameSync5(tmp, join50(root, "run.json"));
48343
+ renameSync5(tmp, join51(root, "run.json"));
47794
48344
  } catch (e) {
47795
48345
  rmSync12(tmp, { force: true });
47796
48346
  throw e;
47797
48347
  }
47798
48348
  return true;
47799
48349
  }
47800
- function removeRunRecord(dir) {
47801
- const root = join50(dir, ".himi");
48350
+ function removeRunRecord(dir, owner) {
48351
+ const root = join51(dir, ".himi");
47802
48352
  try {
47803
- if (!lstatSync7(root).isDirectory()) return;
48353
+ if (!lstatSync8(root).isDirectory()) return;
47804
48354
  } catch {
47805
48355
  return;
47806
48356
  }
47807
- rmSync12(join50(root, "run.json"), { force: true });
48357
+ if (owner !== void 0) {
48358
+ const bytes2 = readConfined(root, "run.json");
48359
+ let pid;
48360
+ try {
48361
+ pid = bytes2 ? JSON.parse(bytes2.toString("utf8")).pid : void 0;
48362
+ } catch {
48363
+ }
48364
+ if (typeof pid === "number" && pid !== owner) return;
48365
+ }
48366
+ rmSync12(join51(root, "run.json"), { force: true });
47808
48367
  }
47809
48368
  function boardFile(dir, pathname) {
47810
48369
  let rel = null;
47811
- if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join50("studio", "index.html");
47812
- else if (pathname === "/__himi/studio/state.js") rel = join50("studio", "state.js");
48370
+ if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join51("studio", "index.html");
48371
+ else if (pathname === "/__himi/studio/state.js") rel = join51("studio", "state.js");
47813
48372
  else {
47814
48373
  const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
47815
- if (m) rel = join50("history", m[1]);
48374
+ if (m) rel = join51("history", m[1]);
47816
48375
  }
47817
48376
  if (!rel) return null;
47818
48377
  const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
@@ -47824,12 +48383,12 @@ function boardFile(dir, pathname) {
47824
48383
  }
47825
48384
  function readConfined(root, rel) {
47826
48385
  try {
47827
- if (!lstatSync7(root).isDirectory()) return null;
48386
+ if (!lstatSync8(root).isDirectory()) return null;
47828
48387
  const parts = rel.split(sep13);
47829
48388
  let at = root;
47830
48389
  for (let i = 0; i < parts.length; i++) {
47831
- at = join50(at, parts[i]);
47832
- const st = lstatSync7(at);
48390
+ at = join51(at, parts[i]);
48391
+ const st = lstatSync8(at);
47833
48392
  if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
47834
48393
  }
47835
48394
  const canonicalRoot = realpathSync6(root);
@@ -47837,7 +48396,7 @@ function readConfined(root, rel) {
47837
48396
  const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
47838
48397
  try {
47839
48398
  if (!fstatSync(fd).isFile()) return null;
47840
- return readFileSync58(fd);
48399
+ return readFileSync59(fd);
47841
48400
  } finally {
47842
48401
  closeSync2(fd);
47843
48402
  }
@@ -47888,7 +48447,7 @@ __export(run_browser_exports, {
47888
48447
  runInBrowser: () => runInBrowser
47889
48448
  });
47890
48449
  import { createServer as createServer5 } from "node:http";
47891
- import { existsSync as existsSync54, readFileSync as readFileSync59 } from "node:fs";
48450
+ import { existsSync as existsSync54, readFileSync as readFileSync60 } from "node:fs";
47892
48451
  import { spawnSync as spawnSync3 } from "node:child_process";
47893
48452
  import { dirname as dirname28, resolve as resolve43 } from "node:path";
47894
48453
  import { fileURLToPath as fileURLToPath23 } from "node:url";
@@ -47930,7 +48489,7 @@ async function releasePayloadFromDir(root, app, header) {
47930
48489
  await addDoc(meta.descriptorHash);
47931
48490
  }
47932
48491
  for (const hash of Object.values(manifest.catalogs ?? {})) await addDoc(hash);
47933
- for (const d of manifest.authoringDocs ?? []) await addDoc(d.sha256);
48492
+ for (const d of Object.values(manifest.authoringDocs ?? {})) await addDoc(d?.sha256);
47934
48493
  await addDoc(manifest.tokensHash);
47935
48494
  await addDoc(manifest.appConfigHash);
47936
48495
  await addDoc(manifest.sourceHash);
@@ -47996,7 +48555,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
47996
48555
  }
47997
48556
  let bytes2;
47998
48557
  try {
47999
- bytes2 = readFileSync59(resolve43(stagedDir(), name));
48558
+ bytes2 = readFileSync60(resolve43(stagedDir(), name));
48000
48559
  } catch (e) {
48001
48560
  res.writeHead(503, { "content-type": "application/json" });
48002
48561
  res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
@@ -48109,13 +48668,13 @@ async function runWixMobileRelease(pos, flags, io, deps) {
48109
48668
  };
48110
48669
  if (invokedAs !== "testflight" && !(invokedAs === "store" && pos[1] === "upload")) return fail2("Wix Mobile Release only supports `himi testflight <app>` or `himi store upload <app>`");
48111
48670
  if (app !== "himi-player") return fail2("Wix Mobile Release is reserved for the Wix-owned Himi Player binary", { app });
48112
- if (str(flags.artifact)) return fail2("--artifact is not accepted for Himi Player; pass --release so deployed serve can validate the Job Service IPA and call MRE with its service identity");
48671
+ if (str2(flags.artifact)) return fail2("--artifact is not accepted for Himi Player; pass --release so deployed serve can validate the Job Service IPA and call MRE with its service identity");
48113
48672
  if (on(flags["no-wait"])) return fail2("--no-wait is not supported for Himi Player TestFlight releases; wait for MRE processing to complete");
48114
- const release = str(flags.release);
48115
- const version2 = str(flags.version);
48673
+ const release = str2(flags.release);
48674
+ const version2 = str2(flags.version);
48116
48675
  if (!release) return fail2("--release is required for a Himi Player TestFlight release");
48117
48676
  if (!version2 || !/^\d+(?:\.\d+){0,2}$/.test(version2)) return fail2("--version needs the Player marketing version (for example 1.0.0)");
48118
- if (str(flags.track) && str(flags.track) !== "testflight" && str(flags.track) !== "internal") return fail2("Wix Mobile Release only supports TestFlight upload; public App Store release remains a separate human step");
48677
+ if (str2(flags.track) && str2(flags.track) !== "testflight" && str2(flags.track) !== "internal") return fail2("Wix Mobile Release only supports TestFlight upload; public App Store release remains a separate human step");
48119
48678
  const plan = {
48120
48679
  ok: true,
48121
48680
  dryRun: on(flags["dry-run"]),
@@ -48148,10 +48707,10 @@ async function runWixMobileRelease(pos, flags, io, deps) {
48148
48707
  return fail2(`could not complete the Himi Player TestFlight Job Service release: ${error.message}`);
48149
48708
  }
48150
48709
  }
48151
- var str, on;
48710
+ var str2, on;
48152
48711
  var init_wix_mobile_release = __esm({
48153
48712
  "src/wix-mobile-release.ts"() {
48154
- str = (value) => typeof value === "string" ? value : void 0;
48713
+ str2 = (value) => typeof value === "string" ? value : void 0;
48155
48714
  on = (value) => value === true || value === "true";
48156
48715
  }
48157
48716
  });
@@ -48231,7 +48790,7 @@ async function runStore(pos, flags, io, deps) {
48231
48790
  if (sub === "status") {
48232
48791
  let creds2;
48233
48792
  try {
48234
- creds2 = deps.resolveCredentials({ app, cfg, profileFlag: str2(flags.profile) });
48793
+ creds2 = deps.resolveCredentials({ app, cfg, profileFlag: str3(flags.profile) });
48235
48794
  } catch (e) {
48236
48795
  return fail2(e.message);
48237
48796
  }
@@ -48251,7 +48810,7 @@ async function runStore(pos, flags, io, deps) {
48251
48810
  }
48252
48811
  let findings;
48253
48812
  try {
48254
- findings = await deps.preflightApp(app, { profileFlag: str2(flags.profile) });
48813
+ findings = await deps.preflightApp(app, { profileFlag: str3(flags.profile) });
48255
48814
  } catch (e) {
48256
48815
  return fail2(e.message);
48257
48816
  }
@@ -48266,7 +48825,7 @@ async function runStore(pos, flags, io, deps) {
48266
48825
  }
48267
48826
  return errors.length === 0 ? 0 : 1;
48268
48827
  }
48269
- const explicitTrack = str2(flags.track);
48828
+ const explicitTrack = str3(flags.track);
48270
48829
  const configTrack = cfg.review?.defaultTrackIos;
48271
48830
  const track = explicitTrack ?? (invokedAs === "testflight" ? "testflight" : configTrack ?? "testflight");
48272
48831
  if (track === "appstore") {
@@ -48281,7 +48840,7 @@ async function runStore(pos, flags, io, deps) {
48281
48840
  let creds;
48282
48841
  let version2;
48283
48842
  try {
48284
- creds = deps.resolveCredentials({ app, cfg, profileFlag: str2(flags.profile) });
48843
+ creds = deps.resolveCredentials({ app, cfg, profileFlag: str3(flags.profile) });
48285
48844
  version2 = deps.readVersion(app);
48286
48845
  } catch (e) {
48287
48846
  return fail2(e.message);
@@ -48434,10 +48993,10 @@ function credsToEnv(c) {
48434
48993
  HIMALAYA_APPLE_TEAM_ID: c.team
48435
48994
  };
48436
48995
  }
48437
- var str2, on2, UPLOAD_STEPS, BUILD_STEPS, TRACKS, PROCESSING_POLL_MS, PROCESSING_TIMEOUT_MS;
48996
+ var str3, on2, UPLOAD_STEPS, BUILD_STEPS, TRACKS, PROCESSING_POLL_MS, PROCESSING_TIMEOUT_MS;
48438
48997
  var init_store3 = __esm({
48439
48998
  "src/store.ts"() {
48440
- str2 = (v) => typeof v === "string" ? v : void 0;
48999
+ str3 = (v) => typeof v === "string" ? v : void 0;
48441
49000
  on2 = (v) => v === true || v === "true";
48442
49001
  UPLOAD_STEPS = ["signing", "build", "validate", "upload"];
48443
49002
  BUILD_STEPS = /* @__PURE__ */ new Set(["signing", "build"]);
@@ -48456,7 +49015,7 @@ __export(preflight_exports, {
48456
49015
  parseStoreConfig: () => parseStoreConfig,
48457
49016
  requireEnv: () => requireEnv
48458
49017
  });
48459
- import { existsSync as existsSync55, readFileSync as readFileSync60 } from "node:fs";
49018
+ import { existsSync as existsSync55, readFileSync as readFileSync61 } from "node:fs";
48460
49019
  import { isAbsolute as isAbsolute3, relative as relative9, resolve as resolve44 } from "node:path";
48461
49020
  function isInsideRepo(p) {
48462
49021
  const rel = relative9(REPO_ROOT3, resolve44(p));
@@ -48516,7 +49075,7 @@ function loadStoreConfig(app) {
48516
49075
  if (!existsSync55(p)) {
48517
49076
  throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
48518
49077
  }
48519
- return parseStoreConfig(readFileSync60(p, "utf8"));
49078
+ return parseStoreConfig(readFileSync61(p, "utf8"));
48520
49079
  }
48521
49080
  var init_preflight = __esm({
48522
49081
  "../store-release/preflight.ts"() {
@@ -48535,19 +49094,19 @@ __export(credential_profile_exports, {
48535
49094
  profilePath: () => profilePath,
48536
49095
  resolveStoreCredentials: () => resolveStoreCredentials
48537
49096
  });
48538
- import { existsSync as existsSync56, readFileSync as readFileSync61 } from "node:fs";
49097
+ import { existsSync as existsSync56, readFileSync as readFileSync62 } from "node:fs";
48539
49098
  import { homedir as homedir5 } from "node:os";
48540
- import { join as join51 } from "node:path";
49099
+ import { join as join52 } from "node:path";
48541
49100
  function credentialsDir(home = homedir5()) {
48542
- return join51(home, ".himalaya", "store-credentials");
49101
+ return join52(home, ".himalaya", "store-credentials");
48543
49102
  }
48544
49103
  function profilePath(name, home = homedir5()) {
48545
49104
  if (!PROFILE_NAME.test(name)) {
48546
49105
  throw new Error(
48547
- `credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join51(credentialsDir(home), "<name>.json")}; it is never a path.`
49106
+ `credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join52(credentialsDir(home), "<name>.json")}; it is never a path.`
48548
49107
  );
48549
49108
  }
48550
- return join51(credentialsDir(home), `${name}.json`);
49109
+ return join52(credentialsDir(home), `${name}.json`);
48551
49110
  }
48552
49111
  function parseProfile(text5, label2) {
48553
49112
  let doc;
@@ -48578,7 +49137,7 @@ function resolveStoreCredentials(opts) {
48578
49137
  const { app, cfg } = opts;
48579
49138
  const env = opts.env ?? process.env;
48580
49139
  const home = opts.home ?? homedir5();
48581
- const read = opts.readProfile ?? ((p) => readFileSync61(p, "utf8"));
49140
+ const read = opts.readProfile ?? ((p) => readFileSync62(p, "utf8"));
48582
49141
  const exists = opts.profileExists ?? existsSync56;
48583
49142
  const ios = cfg.ios ?? {};
48584
49143
  const flagName = opts.profileFlag?.trim();
@@ -48659,9 +49218,9 @@ __export(preflight_app_exports, {
48659
49218
  preflightApp: () => preflightApp,
48660
49219
  profileAccount: () => profileAccount
48661
49220
  });
48662
- import { readFileSync as readFileSync62, existsSync as existsSync57, readdirSync as readdirSync26, statSync as statSync15 } from "node:fs";
48663
- import { createHash as createHash25 } from "node:crypto";
48664
- import { join as join52 } from "node:path";
49221
+ import { readFileSync as readFileSync63, existsSync as existsSync57, readdirSync as readdirSync26, statSync as statSync15 } from "node:fs";
49222
+ import { createHash as createHash26 } from "node:crypto";
49223
+ import { join as join53 } from "node:path";
48665
49224
  function analyze(projectYml, storeConfig, icon, account) {
48666
49225
  const f = [];
48667
49226
  const has = (re, s) => re.test(s);
@@ -48725,13 +49284,13 @@ function profileAccount(app, storeConfig, opts = {}) {
48725
49284
  }
48726
49285
  }
48727
49286
  async function preflightApp(app, opts = {}) {
48728
- const projectYml = existsSync57(iosProjectYml(app)) ? readFileSync62(iosProjectYml(app), "utf8") : "";
48729
- const storeConfig = existsSync57(storeConfigPath(app)) ? readFileSync62(storeConfigPath(app), "utf8") : "";
49287
+ const projectYml = existsSync57(iosProjectYml(app)) ? readFileSync63(iosProjectYml(app), "utf8") : "";
49288
+ const storeConfig = existsSync57(storeConfigPath(app)) ? readFileSync63(storeConfigPath(app), "utf8") : "";
48730
49289
  if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
48731
49290
  const findings = analyze(
48732
49291
  projectYml,
48733
49292
  storeConfig,
48734
- await appIconState(join52(appDir(app), "ios")),
49293
+ await appIconState(join53(appDir(app), "ios")),
48735
49294
  profileAccount(app, storeConfig, opts)
48736
49295
  );
48737
49296
  findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
@@ -48760,16 +49319,16 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
48760
49319
  return f;
48761
49320
  }
48762
49321
  function appLevelMetadataFiles(app, locale = "en-US") {
48763
- const root = join52(storeDir(app), "metadata");
49322
+ const root = join53(storeDir(app), "metadata");
48764
49323
  const out = /* @__PURE__ */ new Set();
48765
49324
  if (existsSync57(root)) {
48766
49325
  for (const n of readdirSync26(root)) if (n.endsWith(".txt")) out.add(n);
48767
49326
  }
48768
- if (existsSync57(join52(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
49327
+ if (existsSync57(join53(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
48769
49328
  return out;
48770
49329
  }
48771
49330
  function reviewInfoFiles(app) {
48772
- const dir = join52(storeDir(app), "review_information");
49331
+ const dir = join53(storeDir(app), "review_information");
48773
49332
  if (!existsSync57(dir)) return /* @__PURE__ */ new Set();
48774
49333
  return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
48775
49334
  }
@@ -48880,12 +49439,12 @@ function analyzePlayListing(assets) {
48880
49439
  return f;
48881
49440
  }
48882
49441
  function playListingAssets(app, locale = "en-US") {
48883
- const dir = join52(storeDir(app), "play", locale, "images");
49442
+ const dir = join53(storeDir(app), "play", locale, "images");
48884
49443
  const read = (names) => {
48885
49444
  for (const name of names) {
48886
- const p = join52(dir, name);
49445
+ const p = join53(dir, name);
48887
49446
  try {
48888
- if (statSync15(p).isFile()) return { name, bytes: readFileSync62(p) };
49447
+ if (statSync15(p).isFile()) return { name, bytes: readFileSync63(p) };
48889
49448
  } catch {
48890
49449
  }
48891
49450
  }
@@ -48916,26 +49475,26 @@ function analyzeListing(metaFiles, shots) {
48916
49475
  return f;
48917
49476
  }
48918
49477
  function metadataFilesPresent(app, locale = "en-US") {
48919
- const dir = join52(storeDir(app), "metadata", locale);
49478
+ const dir = join53(storeDir(app), "metadata", locale);
48920
49479
  if (!existsSync57(dir)) return /* @__PURE__ */ new Set();
48921
49480
  return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
48922
49481
  }
48923
49482
  function listScreenshots(app, locale = "en-US") {
48924
49483
  const out = [];
48925
- const flat = join52(storeDir(app), "screenshots", locale);
49484
+ const flat = join53(storeDir(app), "screenshots", locale);
48926
49485
  if (existsSync57(flat)) {
48927
49486
  for (const png of readdirSync26(flat).filter((n) => n.endsWith(".png"))) {
48928
- const sz = pngSize(readFileSync62(join52(flat, png)));
49487
+ const sz = pngSize(readFileSync63(join53(flat, png)));
48929
49488
  if (sz) out.push({ name: png, w: sz.w, h: sz.h });
48930
49489
  }
48931
49490
  }
48932
- const legacy = join52(storeDir(app), "metadata", locale, "screenshots");
49491
+ const legacy = join53(storeDir(app), "metadata", locale, "screenshots");
48933
49492
  if (existsSync57(legacy)) {
48934
49493
  for (const deviceDir of readdirSync26(legacy)) {
48935
- const d = join52(legacy, deviceDir);
49494
+ const d = join53(legacy, deviceDir);
48936
49495
  if (!statSync15(d).isDirectory()) continue;
48937
49496
  for (const png of readdirSync26(d).filter((n) => n.endsWith(".png"))) {
48938
- const sz = pngSize(readFileSync62(join52(d, png)));
49497
+ const sz = pngSize(readFileSync63(join53(d, png)));
48939
49498
  if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
48940
49499
  }
48941
49500
  }
@@ -48943,13 +49502,13 @@ function listScreenshots(app, locale = "en-US") {
48943
49502
  return out;
48944
49503
  }
48945
49504
  function placeholderHashes2() {
48946
- const templateIos = join52(appDir("_template"), "ios");
49505
+ const templateIos = join53(appDir("_template"), "ios");
48947
49506
  if (!existsSync57(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
48948
49507
  for (const target of readdirSync26(templateIos)) {
48949
- const p = join52(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
49508
+ const p = join53(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48950
49509
  try {
48951
49510
  if (!statSync15(p).isFile()) continue;
48952
- return [LEGACY_PLACEHOLDER_SHA2562, createHash25("sha256").update(readFileSync62(p)).digest("hex")];
49511
+ return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(readFileSync63(p)).digest("hex")];
48953
49512
  } catch {
48954
49513
  }
48955
49514
  }
@@ -48982,11 +49541,11 @@ async function pixelIssues(bytes2) {
48982
49541
  async function appIconState(iosDir) {
48983
49542
  if (!existsSync57(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
48984
49543
  for (const target of readdirSync26(iosDir)) {
48985
- const p = join52(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
49544
+ const p = join53(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48986
49545
  try {
48987
49546
  if (!statSync15(p).isFile()) continue;
48988
- const bytes2 = readFileSync62(p);
48989
- const hash = createHash25("sha256").update(bytes2).digest("hex");
49547
+ const bytes2 = readFileSync63(p);
49548
+ const hash = createHash26("sha256").update(bytes2).digest("hex");
48990
49549
  const pixels = await pixelIssues(bytes2);
48991
49550
  return {
48992
49551
  exists: true,
@@ -49057,7 +49616,7 @@ __export(version_exports, {
49057
49616
  setAndroidVersion: () => setAndroidVersion,
49058
49617
  setIosVersion: () => setIosVersion
49059
49618
  });
49060
- import { readFileSync as readFileSync63, writeFileSync as writeFileSync23 } from "node:fs";
49619
+ import { readFileSync as readFileSync64, writeFileSync as writeFileSync23 } from "node:fs";
49061
49620
  function readIosVersion(projectYml) {
49062
49621
  const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
49063
49622
  const build2 = matchScalar(projectYml, "CFBundleVersion");
@@ -49115,8 +49674,8 @@ function setAndroidVersion(gradle, v) {
49115
49674
  function bumpVersion(app, opts) {
49116
49675
  const iosPath = iosProjectYml(app);
49117
49676
  const gradlePath = androidGradle(app);
49118
- const iosYml = readFileSync63(iosPath, "utf8");
49119
- const gradle = readFileSync63(gradlePath, "utf8");
49677
+ const iosYml = readFileSync64(iosPath, "utf8");
49678
+ const gradle = readFileSync64(gradlePath, "utf8");
49120
49679
  const current = readIosVersion(iosYml);
49121
49680
  const next = {
49122
49681
  marketing: opts.marketing ?? current.marketing,
@@ -49133,7 +49692,7 @@ var init_version = __esm({
49133
49692
  });
49134
49693
 
49135
49694
  // ../store-release/register-bundle.ts
49136
- import { readFileSync as readFileSync64 } from "node:fs";
49695
+ import { readFileSync as readFileSync65 } from "node:fs";
49137
49696
  import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
49138
49697
  function b64url2(b) {
49139
49698
  return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -49151,7 +49710,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
49151
49710
  async function registerBundleId(opts) {
49152
49711
  const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
49153
49712
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
49154
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync64(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
49713
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync65(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
49155
49714
  const res = await fetch(`${ASC_API}/v1/bundleIds`, {
49156
49715
  method: "POST",
49157
49716
  headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
@@ -49205,7 +49764,7 @@ __export(asc_status_exports, {
49205
49764
  ascStatus: () => ascStatus,
49206
49765
  buildVerdict: () => buildVerdict
49207
49766
  });
49208
- import { readFileSync as readFileSync65 } from "node:fs";
49767
+ import { readFileSync as readFileSync66 } from "node:fs";
49209
49768
  function buildVerdict(builds) {
49210
49769
  if (!builds.length) {
49211
49770
  return "NO builds registered \u2014 if you uploaded recently and it's been >15 min, the binary was REJECTED IN PROCESSING (reason is email-only; run validate-binary.ts / scan-purpose-strings.ts to reproduce it).";
@@ -49219,7 +49778,7 @@ function buildVerdict(builds) {
49219
49778
  function client(creds) {
49220
49779
  const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
49221
49780
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
49222
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync65(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
49781
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync66(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
49223
49782
  return async (path2) => {
49224
49783
  const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
49225
49784
  return { status: r.status, json: await r.json().catch(() => ({})) };
@@ -49379,7 +49938,7 @@ __export(secrets_exports, {
49379
49938
  runRemoteSecretsCommand: () => runRemoteSecretsCommand,
49380
49939
  runSecretsCommand: () => runSecretsCommand
49381
49940
  });
49382
- import { readFileSync as readFileSync66 } from "node:fs";
49941
+ import { readFileSync as readFileSync67 } from "node:fs";
49383
49942
  function environment(value) {
49384
49943
  if (value === "preview" || value === "production") return value;
49385
49944
  throw new Error("--environment must be preview or production");
@@ -49410,7 +49969,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
49410
49969
  io.log(JSON.stringify(await vault.list({ app, environment: env })));
49411
49970
  return 0;
49412
49971
  }
49413
- const value = options.readValue ? options.readValue() : readFileSync66(0, "utf8").replace(/\r?\n$/, "");
49972
+ const value = options.readValue ? options.readValue() : readFileSync67(0, "utf8").replace(/\r?\n$/, "");
49414
49973
  if (operation === "set") await vault.set({ app, environment: env, name, value });
49415
49974
  else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
49416
49975
  else throw new Error(`unknown secrets operation ${operation}`);
@@ -49439,7 +49998,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
49439
49998
  }
49440
49999
  let body;
49441
50000
  if (operation !== "list") {
49442
- const value = options.readValue ? options.readValue() : readFileSync66(0, "utf8").replace(/\r?\n$/, "");
50001
+ const value = options.readValue ? options.readValue() : readFileSync67(0, "utf8").replace(/\r?\n$/, "");
49443
50002
  body = JSON.stringify({ value });
49444
50003
  }
49445
50004
  const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
@@ -49475,15 +50034,15 @@ __export(notify_exports, {
49475
50034
  runNotify: () => runNotify,
49476
50035
  saveAdminSession: () => saveAdminSession
49477
50036
  });
49478
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync67, writeFileSync as writeFileSync24 } from "node:fs";
50037
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync68, writeFileSync as writeFileSync24 } from "node:fs";
49479
50038
  import { homedir as homedir6 } from "node:os";
49480
- import { dirname as dirname30, join as join53 } from "node:path";
50039
+ import { dirname as dirname30, join as join54 } from "node:path";
49481
50040
  function defaultSessionsPath() {
49482
- return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join53(homedir6(), ".himalaya", "admin-sessions.json");
50041
+ return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join54(homedir6(), ".himalaya", "admin-sessions.json");
49483
50042
  }
49484
50043
  function loadSessionsFile(path2 = defaultSessionsPath()) {
49485
50044
  try {
49486
- return JSON.parse(readFileSync67(path2, "utf8"));
50045
+ return JSON.parse(readFileSync68(path2, "utf8"));
49487
50046
  } catch {
49488
50047
  return {};
49489
50048
  }
@@ -49532,7 +50091,7 @@ function parseDataFlag(raw) {
49532
50091
  }
49533
50092
  async function runNotify(pos, flags, io, deps = {}) {
49534
50093
  const doFetch = deps.fetchImpl ?? fetch;
49535
- const str6 = (v) => typeof v === "string" ? v : void 0;
50094
+ const str7 = (v) => typeof v === "string" ? v : void 0;
49536
50095
  const json5 = flags.json === true;
49537
50096
  const print = (v) => io.log(JSON.stringify(v, null, 2));
49538
50097
  const sub = pos[1];
@@ -49547,8 +50106,8 @@ async function runNotify(pos, flags, io, deps = {}) {
49547
50106
  return 2;
49548
50107
  }
49549
50108
  const { adminUrl, session } = resolveAuth({
49550
- adminUrl: str6(flags["admin-url"]),
49551
- adminSession: str6(flags["admin-session"]),
50109
+ adminUrl: str7(flags["admin-url"]),
50110
+ adminSession: str7(flags["admin-session"]),
49552
50111
  ...deps.env ? { env: deps.env } : {},
49553
50112
  ...deps.file ? { file: deps.file } : {}
49554
50113
  });
@@ -49599,14 +50158,14 @@ async function runNotify(pos, flags, io, deps = {}) {
49599
50158
  }
49600
50159
  return report2.ok ? 0 : 1;
49601
50160
  }
49602
- const app = str6(flags.app);
50161
+ const app = str7(flags.app);
49603
50162
  if (!app) {
49604
50163
  io.error(JSON.stringify({ error: "--app is required", usage: USAGE2 }));
49605
50164
  return 2;
49606
50165
  }
49607
50166
  if (sub === "tokens") {
49608
50167
  const query = new URLSearchParams();
49609
- const platform = str6(flags.platform);
50168
+ const platform = str7(flags.platform);
49610
50169
  if (platform) query.set("platform", platform);
49611
50170
  if (flags["include-disabled"] === true) query.set("includeDisabled", "1");
49612
50171
  const url = `${adminUrl}/v1/admin/push-tokens/${encodeURIComponent(app)}${query.size ? `?${query}` : ""}`;
@@ -49650,8 +50209,8 @@ async function runNotify(pos, flags, io, deps = {}) {
49650
50209
  }
49651
50210
  return 0;
49652
50211
  }
49653
- const token = str6(flags.token);
49654
- const device = str6(flags.device);
50212
+ const token = str7(flags.token);
50213
+ const device = str7(flags.device);
49655
50214
  const all = flags.all === true;
49656
50215
  const targets = [token && "--token", device && "--device", all && "--all"].filter(Boolean);
49657
50216
  if (targets.length === 0) {
@@ -49668,20 +50227,20 @@ async function runNotify(pos, flags, io, deps = {}) {
49668
50227
  return 2;
49669
50228
  }
49670
50229
  const silent = flags.silent === true;
49671
- const title = str6(flags.title);
50230
+ const title = str7(flags.title);
49672
50231
  if (!silent && !title) {
49673
50232
  io.error(JSON.stringify({ error: "--title is required for a visible notification (use --silent for a background push)", usage: USAGE2 }));
49674
50233
  return 2;
49675
50234
  }
49676
- const badgeRaw = str6(flags.badge);
50235
+ const badgeRaw = str7(flags.badge);
49677
50236
  const payload = {
49678
50237
  ...title ? { title } : {},
49679
- ...str6(flags.body) ? { body: str6(flags.body) } : {},
49680
- ...str6(flags.link) ? { link: str6(flags.link) } : {},
49681
- ...str6(flags.category) ? { category: str6(flags.category) } : {},
49682
- ...str6(flags.channel) ? { channelId: str6(flags.channel) } : {},
49683
- ...str6(flags.platform) ? { platform: str6(flags.platform) } : {},
49684
- ...str6(flags["bundle-id"]) ? { bundleId: str6(flags["bundle-id"]) } : {},
50238
+ ...str7(flags.body) ? { body: str7(flags.body) } : {},
50239
+ ...str7(flags.link) ? { link: str7(flags.link) } : {},
50240
+ ...str7(flags.category) ? { category: str7(flags.category) } : {},
50241
+ ...str7(flags.channel) ? { channelId: str7(flags.channel) } : {},
50242
+ ...str7(flags.platform) ? { platform: str7(flags.platform) } : {},
50243
+ ...str7(flags["bundle-id"]) ? { bundleId: str7(flags["bundle-id"]) } : {},
49685
50244
  ...badgeRaw !== void 0 && Number.isFinite(Number(badgeRaw)) ? { badge: Number(badgeRaw) } : {},
49686
50245
  ...silent ? { pushType: "background" } : {},
49687
50246
  ...flags["dry-run"] === true ? { dryRun: true } : {},
@@ -49946,7 +50505,7 @@ var init_copy_clean = __esm({
49946
50505
  function genericDescription(it) {
49947
50506
  for (const field of DESCRIPTION_FIELDS) {
49948
50507
  const raw = it[field];
49949
- const text5 = typeof raw === "string" ? raw : str3(raw?.text);
50508
+ const text5 = typeof raw === "string" ? raw : str4(raw?.text);
49950
50509
  if (!text5) continue;
49951
50510
  const plain2 = text5.replace(/<[^>]*>/g, " ").replace(/&nbsp;/g, " ");
49952
50511
  if (plain2.trim()) return plain2;
@@ -49994,18 +50553,18 @@ function planPrice(p) {
49994
50553
  const price = pricing?.price ?? p.price;
49995
50554
  if (typeof price === "string" && price.trim()) return price.trim();
49996
50555
  if (price && typeof price === "object") {
49997
- return str3(price.formatted) || str3(price.value) || void 0;
50556
+ return str4(price.formatted) || str4(price.value) || void 0;
49998
50557
  }
49999
- return str3(p.formattedPrice) || str3(pricing?.formattedPrice) || void 0;
50558
+ return str4(p.formattedPrice) || str4(pricing?.formattedPrice) || void 0;
50000
50559
  }
50001
50560
  function planDetail(p) {
50002
50561
  const pricing = p.pricing && typeof p.pricing === "object" ? p.pricing : void 0;
50003
50562
  const sub = pricing?.subscription && typeof pricing.subscription === "object" ? pricing.subscription : void 0;
50004
50563
  const cycleDur = sub?.cycleDuration && typeof sub.cycleDuration === "object" ? sub.cycleDuration : void 0;
50005
50564
  const count = cycleDur?.count;
50006
- const unit = str3(cycleDur?.unit ?? cycleDur?.period).toLowerCase();
50007
- const cycle = typeof count === "number" && unit ? `${count} ${unit}` : str3(sub?.cycle ?? pricing?.cycle ?? p.period ?? p.billingPeriod);
50008
- const perks = asArr(p.perks ?? p.benefits).map((x) => str3(x) || str3(x.name)).filter(Boolean);
50565
+ const unit = str4(cycleDur?.unit ?? cycleDur?.period).toLowerCase();
50566
+ const cycle = typeof count === "number" && unit ? `${count} ${unit}` : str4(sub?.cycle ?? pricing?.cycle ?? p.period ?? p.billingPeriod);
50567
+ const perks = asArr(p.perks ?? p.benefits).map((x) => str4(x) || str4(x.name)).filter(Boolean);
50009
50568
  const bits = [cycle, perks.slice(0, 4).join("; ")].filter(Boolean);
50010
50569
  return bits.length ? bits.join(" \xB7 ") : void 0;
50011
50570
  }
@@ -50017,7 +50576,7 @@ function formLabels(x, depth = 0, out = []) {
50017
50576
  }
50018
50577
  if (typeof x !== "object") return out;
50019
50578
  const o = x;
50020
- const label2 = str3(o.label ?? o.displayName ?? o.fieldTitle ?? o.title);
50579
+ const label2 = str4(o.label ?? o.displayName ?? o.fieldTitle ?? o.title);
50021
50580
  if (label2 && !UUID_RE.test(label2) && label2.length < 80 && !out.includes(label2)) out.push(label2);
50022
50581
  for (const k of ["fields", "formFields", "form", "schema", "properties"]) {
50023
50582
  if (o[k] != null) formLabels(o[k], depth + 1, out);
@@ -50060,10 +50619,10 @@ function side(call, def) {
50060
50619
  }
50061
50620
  function toItems(def, raw) {
50062
50621
  return raw.slice(0, 12).map((it, i) => ({
50063
- id: str3((def.idOf ? def.idOf(it) : it.id) ?? `row-${i}`),
50622
+ id: str4((def.idOf ? def.idOf(it) : it.id) ?? `row-${i}`),
50064
50623
  title: def.titleOf(it) || "(untitled)",
50065
50624
  imageUrl: def.imageOf?.(it),
50066
- price: def.priceOf?.(it) || str3(it.price?.formatted) || str3(it.formattedPrice) || void 0,
50625
+ price: def.priceOf?.(it) || str4(it.price?.formatted) || str4(it.formattedPrice) || void 0,
50067
50626
  detail: def.detailOf?.(it),
50068
50627
  description: copyOrDrop(def.descriptionOf ? def.descriptionOf(it) : genericDescription(it), 240) || void 0
50069
50628
  }));
@@ -50088,7 +50647,7 @@ async function readBookingsCategories(call) {
50088
50647
  const { data } = await probeCall(call, "POST", "/bookings/v2/categories/query", {
50089
50648
  query: { paging: { limit: 100 } }
50090
50649
  });
50091
- return asArr(data?.categories).map((c) => ({ id: str3(c.id), name: str3(c.name ?? c.title) }));
50650
+ return asArr(data?.categories).map((c) => ({ id: str4(c.id), name: str4(c.name ?? c.title) }));
50092
50651
  }
50093
50652
  async function readRedirects(call) {
50094
50653
  if (!call) return 0;
@@ -50101,27 +50660,27 @@ async function readStoreCategories(call) {
50101
50660
  query: { cursorPaging: { limit: 100 } },
50102
50661
  treeReference: { appNamespace: "@wix/stores" }
50103
50662
  });
50104
- return asArr(data?.categories).map((c) => ({ id: str3(c.id), name: str3(c.name), count: typeof c.numberOfProducts === "number" ? c.numberOfProducts : void 0 }));
50663
+ return asArr(data?.categories).map((c) => ({ id: str4(c.id), name: str4(c.name), count: typeof c.numberOfProducts === "number" ? c.numberOfProducts : void 0 }));
50105
50664
  }
50106
50665
  async function readBlogCategories(call) {
50107
50666
  if (!call) return [];
50108
50667
  const { data } = await probeCall(call, "POST", "/blog/v3/categories/query", {
50109
50668
  query: { paging: { limit: 100 } }
50110
50669
  });
50111
- return asArr(data?.categories).map((c) => ({ id: str3(c.id), name: str3(c.label ?? c.name) }));
50670
+ return asArr(data?.categories).map((c) => ({ id: str4(c.id), name: str4(c.label ?? c.name) }));
50112
50671
  }
50113
50672
  async function readMediaLibrary(call) {
50114
50673
  if (!call) return [];
50115
50674
  const { data } = await probeCall(call, "GET", "/site-media/v1/files?paging.limit=50");
50116
50675
  return asArr(data?.files).slice(0, 50).map((f) => ({
50117
- id: str3(f.id ?? f.fileId),
50118
- url: str3(f.url) || (str3(f.id) ? `https://static.wixstatic.com/media/${str3(f.id)}` : ""),
50119
- filename: str3(f.displayName ?? f.fileName ?? f.name) || void 0
50676
+ id: str4(f.id ?? f.fileId),
50677
+ url: str4(f.url) || (str4(f.id) ? `https://static.wixstatic.com/media/${str4(f.id)}` : ""),
50678
+ filename: str4(f.displayName ?? f.fileName ?? f.name) || void 0
50120
50679
  })).filter((f) => f.id && f.url);
50121
50680
  }
50122
50681
  function sampleTitle(data) {
50123
50682
  for (const k of ["title", "name", "headline", "slug", "label", "displayName"]) {
50124
- const v = str3(data[k]).trim();
50683
+ const v = str4(data[k]).trim();
50125
50684
  if (v && !v.includes("@") && v.length < 120) return v;
50126
50685
  }
50127
50686
  for (const [k, v] of Object.entries(data)) {
@@ -50145,13 +50704,13 @@ async function readCms(call, opts = {}) {
50145
50704
  const unread = Math.max(0, (total ?? all.length) - cols.length);
50146
50705
  const out = [];
50147
50706
  for (const c of cols) {
50148
- const id = str3(c.id);
50707
+ const id = str4(c.id);
50149
50708
  if (!id) continue;
50150
50709
  const fieldsRaw = asArr(c.fields ?? c.displayFields);
50151
50710
  const fields = fieldsRaw.map((f) => ({
50152
- key: str3(f.key ?? f.id),
50153
- displayName: str3(f.displayName) || void 0,
50154
- type: str3(f.type) || void 0,
50711
+ key: str4(f.key ?? f.id),
50712
+ displayName: str4(f.displayName) || void 0,
50713
+ type: str4(f.type) || void 0,
50155
50714
  ...f.systemField === true ? { systemField: true } : {},
50156
50715
  ...f.encrypted === true ? { encrypted: true } : {}
50157
50716
  })).filter((f) => f.key);
@@ -50164,17 +50723,17 @@ async function readCms(call, opts = {}) {
50164
50723
  const samples = items.slice(0, 5).map((row, i) => {
50165
50724
  const dataObj = row.data && typeof row.data === "object" ? row.data : row;
50166
50725
  const title = sampleTitle(dataObj);
50167
- return { id: str3(row.id ?? dataObj._id) || `row-${i}`, ...title ? { title } : {} };
50726
+ return { id: str4(row.id ?? dataObj._id) || `row-${i}`, ...title ? { title } : {} };
50168
50727
  });
50169
50728
  out.push({
50170
50729
  id,
50171
- displayName: str3(c.displayName ?? c.name) || void 0,
50730
+ displayName: str4(c.displayName ?? c.name) || void 0,
50172
50731
  // A Wix APP's collection (Stores, Bookings, …) — the generic CMS screen must not
50173
50732
  // advertise it, because its vertical already does, properly.
50174
- ...str3(c.ownerAppId) ? { ownerAppId: str3(c.ownerAppId) } : {},
50175
- ...str3(c.displayField) ? { displayField: str3(c.displayField) } : {},
50176
- readRole: str3(perms?.read) || str3(c.permissions) || void 0,
50177
- writeRole: str3(perms?.insert ?? perms?.update) || void 0,
50733
+ ...str4(c.ownerAppId) ? { ownerAppId: str4(c.ownerAppId) } : {},
50734
+ ...str4(c.displayField) ? { displayField: str4(c.displayField) } : {},
50735
+ readRole: str4(perms?.read) || str4(c.permissions) || void 0,
50736
+ writeRole: str4(perms?.insert ?? perms?.update) || void 0,
50178
50737
  fields,
50179
50738
  sampleCount: items.length,
50180
50739
  ...samples.length ? { samples } : {}
@@ -50198,8 +50757,8 @@ async function readInstalledApps(call) {
50198
50757
  if (!data) continue;
50199
50758
  const raw = asArr(data.apps ?? data.siteApps ?? data.items);
50200
50759
  const apps = raw.map((a) => ({
50201
- id: str3(a.id ?? a.appId ?? a.appDefId),
50202
- name: str3(a.name ?? a.appName ?? a.title) || void 0
50760
+ id: str4(a.id ?? a.appId ?? a.appDefId),
50761
+ name: str4(a.name ?? a.appName ?? a.title) || void 0
50203
50762
  })).filter((a) => a.id);
50204
50763
  if (apps.length) return apps.slice(0, 40);
50205
50764
  }
@@ -50218,7 +50777,7 @@ async function readMemberRoles(call) {
50218
50777
  }
50219
50778
  if (!data) continue;
50220
50779
  const raw = asArr(data.roles ?? data.items);
50221
- const names = raw.map((r) => str3(r.title ?? r.name ?? r.id)).filter((n) => n && !n.includes("@"));
50780
+ const names = raw.map((r) => str4(r.title ?? r.name ?? r.id)).filter((n) => n && !n.includes("@"));
50222
50781
  if (names.length) return { names: names.slice(0, 24), status: "ok" };
50223
50782
  sawEmptyPayload = true;
50224
50783
  }
@@ -50226,13 +50785,13 @@ async function readMemberRoles(call) {
50226
50785
  if (sawAuthError) return { names: [], status: "error" };
50227
50786
  return { names: [], status: "empty" };
50228
50787
  }
50229
- var asArr, str3, DESCRIPTION_FIELDS, UUID_RE, CORE_PROBES, OPTIONAL_PROBES, ALL, CMS_LIST_LIMIT;
50788
+ var asArr, str4, DESCRIPTION_FIELDS, UUID_RE, CORE_PROBES, OPTIONAL_PROBES, ALL, CMS_LIST_LIMIT;
50230
50789
  var init_probes = __esm({
50231
50790
  "src/site-analyze/probes.ts"() {
50232
50791
  init_rest();
50233
50792
  init_copy_clean();
50234
50793
  asArr = (x) => Array.isArray(x) ? x : [];
50235
- str3 = (x) => typeof x === "string" ? x : "";
50794
+ str4 = (x) => typeof x === "string" ? x : "";
50236
50795
  DESCRIPTION_FIELDS = ["plainDescription", "description", "shortDescription", "excerpt", "tagLine", "subtitle"];
50237
50796
  UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
50238
50797
  CORE_PROBES = [
@@ -50242,9 +50801,9 @@ var init_probes = __esm({
50242
50801
  path: "/stores/v3/products/query",
50243
50802
  body: { query: { cursorPaging: { limit: 50 } } },
50244
50803
  itemsOf: (d) => asArr(d.products),
50245
- titleOf: (p) => str3(p.name),
50804
+ titleOf: (p) => str4(p.name),
50246
50805
  imageOf: productImage,
50247
- priceOf: (p) => str3(p.price?.formatted) || str3(p.priceData?.formatted?.price) || str3(p.formattedPrice) || (typeof p.price === "number" ? String(p.price) : void 0),
50806
+ priceOf: (p) => str4(p.price?.formatted) || str4(p.priceData?.formatted?.price) || str4(p.formattedPrice) || (typeof p.price === "number" ? String(p.price) : void 0),
50248
50807
  fallbacks: [
50249
50808
  {
50250
50809
  method: "POST",
@@ -50266,7 +50825,7 @@ var init_probes = __esm({
50266
50825
  path: "/bookings/v2/services/query",
50267
50826
  body: { query: { paging: { limit: 50 } } },
50268
50827
  itemsOf: (d) => asArr(d.services),
50269
- titleOf: (s) => str3(s.name),
50828
+ titleOf: (s) => str4(s.name),
50270
50829
  imageOf: serviceImage
50271
50830
  },
50272
50831
  {
@@ -50275,8 +50834,8 @@ var init_probes = __esm({
50275
50834
  path: "/events/v3/events/query",
50276
50835
  body: { query: { paging: { limit: 50 } } },
50277
50836
  itemsOf: (d) => asArr(d.events),
50278
- titleOf: (e) => str3(e.title ?? e.name),
50279
- imageOf: (e) => str3(e.mainImage) || str3(e.mainImage?.url) || void 0
50837
+ titleOf: (e) => str4(e.title ?? e.name),
50838
+ imageOf: (e) => str4(e.mainImage) || str4(e.mainImage?.url) || void 0
50280
50839
  },
50281
50840
  {
50282
50841
  vertical: "blog",
@@ -50284,7 +50843,7 @@ var init_probes = __esm({
50284
50843
  path: "/blog/v3/posts/query",
50285
50844
  body: { query: { paging: { limit: 50 } } },
50286
50845
  itemsOf: (d) => asArr(d.posts),
50287
- titleOf: (p) => str3(p.title),
50846
+ titleOf: (p) => str4(p.title),
50288
50847
  imageOf: blogCover
50289
50848
  },
50290
50849
  {
@@ -50293,7 +50852,7 @@ var init_probes = __esm({
50293
50852
  path: "/social-groups-proxy/groups/v2/groups/query",
50294
50853
  body: { query: { paging: { limit: 50 } } },
50295
50854
  itemsOf: (d) => asArr(d.groups),
50296
- titleOf: (g) => str3(g.title ?? g.name),
50855
+ titleOf: (g) => str4(g.title ?? g.name),
50297
50856
  imageOf: (g) => deepImageUrl(g.coverImage) || deepImageUrl(g.image)
50298
50857
  },
50299
50858
  {
@@ -50302,7 +50861,7 @@ var init_probes = __esm({
50302
50861
  path: "/online-programs/v3/programs/query",
50303
50862
  body: { query: { cursorPaging: { limit: 50 } } },
50304
50863
  itemsOf: (d) => asArr(d.programs),
50305
- titleOf: (p) => str3(p.title ?? p.name),
50864
+ titleOf: (p) => str4(p.title ?? p.name),
50306
50865
  imageOf: (p) => deepImageUrl(p.image) || deepImageUrl(p.coverImage) || deepImageUrl(p.media)
50307
50866
  },
50308
50867
  {
@@ -50310,21 +50869,21 @@ var init_probes = __esm({
50310
50869
  method: "GET",
50311
50870
  path: "/restaurants/menus/v1/menus",
50312
50871
  itemsOf: (d) => asArr(d.menus),
50313
- titleOf: (m) => str3(m.name)
50872
+ titleOf: (m) => str4(m.name)
50314
50873
  }
50315
50874
  ];
50316
50875
  OPTIONAL_PROBES = [
50317
- { vertical: "plans", method: "GET", path: "/pricing-plans/v2/plans", itemsOf: (d) => asArr(d.plans), titleOf: (p) => str3(p.name), imageOf: (p) => deepImageUrl(p.image) || deepImageUrl(p.media), priceOf: planPrice, detailOf: planDetail },
50318
- { vertical: "reviews", method: "POST", path: "/reviews/v1/reviews/query", body: { query: { cursorPaging: { limit: 20 } } }, itemsOf: (d) => asArr(d.reviews), titleOf: (r) => str3(r.content ?? r.title) },
50319
- { vertical: "loyalty", method: "GET", path: "/loyalty-programs/v1/program", itemsOf: (d) => d.loyaltyProgram ? [d.loyaltyProgram] : [], titleOf: (p) => str3(p.name) || "Loyalty" },
50320
- { vertical: "forum", method: "POST", path: "/forum/v1/posts/query", body: { query: { paging: { limit: 10 } } }, itemsOf: (d) => asArr(d.posts), titleOf: (p) => str3(p.title) },
50321
- { vertical: "donations", method: "POST", path: "/donation-campaigns/v2/donation-campaigns/query", body: { query: { cursorPaging: { limit: 20 } } }, itemsOf: (d) => asArr(d.donationCampaigns), titleOf: (c) => str3(c.name) },
50322
- { vertical: "giftCards", method: "POST", path: "/gift-cards/v1/gift-cards/query", body: { query: { paging: { limit: 10 } } }, itemsOf: (d) => asArr(d.giftCards), titleOf: (g) => str3(g.name) },
50323
- { vertical: "reservations", method: "GET", path: "/table-reservations/reservation-locations/v1/reservation-locations", itemsOf: (d) => asArr(d.reservationLocations ?? d.reservations), titleOf: (l) => str3(l.name) },
50324
- { vertical: "badges", method: "POST", path: "/badges/v4/badges/query", body: { query: { cursorPaging: { limit: 50 } } }, itemsOf: (d) => asArr(d.badges), titleOf: (b) => str3(b.title ?? b.name) },
50325
- { vertical: "coupons", method: "POST", path: "/stores/v2/coupons/query", body: { query: { paging: { limit: 30 } } }, itemsOf: (d) => asArr(d.coupons), titleOf: (c) => str3(c.name) },
50326
- { vertical: "forms", method: "POST", path: "/form-schema-service/v4/forms/query", body: { query: { paging: { limit: 30 } }, namespace: "wix.form_app.form" }, itemsOf: (d) => asArr(d.forms), titleOf: (f) => str3(f.name), detailOf: formDetail },
50327
- { vertical: "portfolio", method: "GET", path: "/portfolio/v1/projects", itemsOf: (d) => asArr(d.projects), titleOf: (p) => str3(p.title ?? p.name), imageOf: (p) => deepImageUrl(p.coverImage) || deepImageUrl(p.image) },
50876
+ { vertical: "plans", method: "GET", path: "/pricing-plans/v2/plans", itemsOf: (d) => asArr(d.plans), titleOf: (p) => str4(p.name), imageOf: (p) => deepImageUrl(p.image) || deepImageUrl(p.media), priceOf: planPrice, detailOf: planDetail },
50877
+ { vertical: "reviews", method: "POST", path: "/reviews/v1/reviews/query", body: { query: { cursorPaging: { limit: 20 } } }, itemsOf: (d) => asArr(d.reviews), titleOf: (r) => str4(r.content ?? r.title) },
50878
+ { vertical: "loyalty", method: "GET", path: "/loyalty-programs/v1/program", itemsOf: (d) => d.loyaltyProgram ? [d.loyaltyProgram] : [], titleOf: (p) => str4(p.name) || "Loyalty" },
50879
+ { vertical: "forum", method: "POST", path: "/forum/v1/posts/query", body: { query: { paging: { limit: 10 } } }, itemsOf: (d) => asArr(d.posts), titleOf: (p) => str4(p.title) },
50880
+ { vertical: "donations", method: "POST", path: "/donation-campaigns/v2/donation-campaigns/query", body: { query: { cursorPaging: { limit: 20 } } }, itemsOf: (d) => asArr(d.donationCampaigns), titleOf: (c) => str4(c.name) },
50881
+ { vertical: "giftCards", method: "POST", path: "/gift-cards/v1/gift-cards/query", body: { query: { paging: { limit: 10 } } }, itemsOf: (d) => asArr(d.giftCards), titleOf: (g) => str4(g.name) },
50882
+ { vertical: "reservations", method: "GET", path: "/table-reservations/reservation-locations/v1/reservation-locations", itemsOf: (d) => asArr(d.reservationLocations ?? d.reservations), titleOf: (l) => str4(l.name) },
50883
+ { vertical: "badges", method: "POST", path: "/badges/v4/badges/query", body: { query: { cursorPaging: { limit: 50 } } }, itemsOf: (d) => asArr(d.badges), titleOf: (b) => str4(b.title ?? b.name) },
50884
+ { vertical: "coupons", method: "POST", path: "/stores/v2/coupons/query", body: { query: { paging: { limit: 30 } } }, itemsOf: (d) => asArr(d.coupons), titleOf: (c) => str4(c.name) },
50885
+ { vertical: "forms", method: "POST", path: "/form-schema-service/v4/forms/query", body: { query: { paging: { limit: 30 } }, namespace: "wix.form_app.form" }, itemsOf: (d) => asArr(d.forms), titleOf: (f) => str4(f.name), detailOf: formDetail },
50886
+ { vertical: "portfolio", method: "GET", path: "/portfolio/v1/projects", itemsOf: (d) => asArr(d.projects), titleOf: (p) => str4(p.title ?? p.name), imageOf: (p) => deepImageUrl(p.coverImage) || deepImageUrl(p.image) },
50328
50887
  {
50329
50888
  vertical: "members",
50330
50889
  method: "POST",
@@ -51428,7 +51987,7 @@ function veloArtifactRelPath(veloPath) {
51428
51987
  if (!parts.length || parts.some((s) => s === "..")) return void 0;
51429
51988
  return `${VELO_DIR}/${parts.join("/")}`;
51430
51989
  }
51431
- function str4(x) {
51990
+ function str5(x) {
51432
51991
  return typeof x === "string" ? x : "";
51433
51992
  }
51434
51993
  function asArr2(x) {
@@ -51446,9 +52005,9 @@ function filesFromOwnerPayload(data, redact = redactSecrets) {
51446
52005
  for (const item of raw) {
51447
52006
  if (!item || typeof item !== "object") continue;
51448
52007
  const f = item;
51449
- const path2 = str4(f.path || f.relativePath || f.fileName || f.name);
52008
+ const path2 = str5(f.path || f.relativePath || f.fileName || f.name);
51450
52009
  if (!path2 || isSecretVeloPath(path2)) continue;
51451
- const content = str4(f.content ?? f.source ?? f.code ?? f.body);
52010
+ const content = str5(f.content ?? f.source ?? f.code ?? f.body);
51452
52011
  const bytes2 = typeof f.bytes === "number" ? f.bytes : typeof f.size === "number" ? f.size : content.length;
51453
52012
  const redacted = content ? redact(content) : "";
51454
52013
  const forDisk = redacted.length > VELO_FILE_CAP ? redacted.slice(0, VELO_FILE_CAP) + "\n/* \u2026truncated */" : redacted;
@@ -53041,7 +53600,7 @@ var init_brand_font = __esm({
53041
53600
 
53042
53601
  // src/site-analyze/write-artifacts.ts
53043
53602
  import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync25 } from "node:fs";
53044
- import { join as join54 } from "node:path";
53603
+ import { join as join55 } from "node:path";
53045
53604
  function attachVeloSources(book, sources, put) {
53046
53605
  const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
53047
53606
  for (const f of book.velo.files) {
@@ -53196,12 +53755,12 @@ async function downloadMedia(book, fetchImpl, put) {
53196
53755
  }
53197
53756
  async function writeBusinessBook(result, opts) {
53198
53757
  const out = opts.outDir;
53199
- mkdirSync28(join54(out, "evidence/pages"), { recursive: true });
53200
- mkdirSync28(join54(out, "media/catalog"), { recursive: true });
53758
+ mkdirSync28(join55(out, "evidence/pages"), { recursive: true });
53759
+ mkdirSync28(join55(out, "media/catalog"), { recursive: true });
53201
53760
  const files = [];
53202
53761
  const put = (rel, body) => {
53203
- const p = join54(out, rel);
53204
- mkdirSync28(join54(p, ".."), { recursive: true });
53762
+ const p = join55(out, rel);
53763
+ mkdirSync28(join55(p, ".."), { recursive: true });
53205
53764
  writeFileSync25(p, body);
53206
53765
  files.push(rel);
53207
53766
  };
@@ -53295,8 +53854,8 @@ var init_customer_build = __esm({
53295
53854
  });
53296
53855
 
53297
53856
  // src/site-analyze/apply.ts
53298
- import { existsSync as existsSync58, readFileSync as readFileSync68, writeFileSync as writeFileSync26, copyFileSync as copyFileSync3, mkdirSync as mkdirSync29, realpathSync as realpathSync7, statSync as statSync16 } from "node:fs";
53299
- import { dirname as dirname31, isAbsolute as isAbsolute4, join as join55, resolve as resolve45, sep as sep14 } from "node:path";
53857
+ import { existsSync as existsSync58, readFileSync as readFileSync69, writeFileSync as writeFileSync26, copyFileSync as copyFileSync3, mkdirSync as mkdirSync29, realpathSync as realpathSync7, statSync as statSync16 } from "node:fs";
53858
+ import { dirname as dirname31, isAbsolute as isAbsolute4, join as join56, resolve as resolve45, sep as sep14 } from "node:path";
53300
53859
  import { spawnSync as spawnSync4 } from "node:child_process";
53301
53860
  function unpairedRedirectNote(overlay) {
53302
53861
  if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
@@ -53311,7 +53870,7 @@ function committedShellProvisioning(path2) {
53311
53870
  function findRepoRoot(cwd) {
53312
53871
  let dir = cwd;
53313
53872
  for (let i = 0; i < 8; i++) {
53314
- if (SHELL_NAMES2.some((name) => existsSync58(join55(dir, shellAppDir(name), "package.json")))) return dir;
53873
+ if (SHELL_NAMES2.some((name) => existsSync58(join56(dir, shellAppDir(name), "package.json")))) return dir;
53315
53874
  const next = dirname31(dir);
53316
53875
  if (next === dir) break;
53317
53876
  dir = next;
@@ -53379,11 +53938,11 @@ function mergeCustomerOwned(committed, overlay) {
53379
53938
  }
53380
53939
  function buildMergedContract(options) {
53381
53940
  const { appDir: appDir2, packageDir, overlay } = options;
53382
- const committedPath = join55(appDir2, "provisioning.json");
53941
+ const committedPath = join56(appDir2, "provisioning.json");
53383
53942
  if (!existsSync58(committedPath)) {
53384
53943
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
53385
53944
  }
53386
- const committed = JSON.parse(readFileSync68(committedPath, "utf8"));
53945
+ const committed = JSON.parse(readFileSync69(committedPath, "utf8"));
53387
53946
  const merged = mergeCustomerOwned(committed, overlay);
53388
53947
  const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
53389
53948
  const branding = merged.branding ?? {};
@@ -53395,7 +53954,7 @@ function buildMergedContract(options) {
53395
53954
  };
53396
53955
  const stage = (fromRel, toRel) => {
53397
53956
  const from = contained(packageDir, fromRel);
53398
- const to = contained(join55(appDir2, STAGED), toRel.slice(STAGED.length + 1));
53957
+ const to = contained(join56(appDir2, STAGED), toRel.slice(STAGED.length + 1));
53399
53958
  if (!from || !to || !existsSync58(from)) return void 0;
53400
53959
  let real;
53401
53960
  let realRoot;
@@ -53418,11 +53977,11 @@ function buildMergedContract(options) {
53418
53977
  };
53419
53978
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
53420
53979
  if (icon) branding.appIconPath = icon;
53421
- const facesPath = join55(packageDir, "media/fonts/faces.json");
53980
+ const facesPath = join56(packageDir, "media/fonts/faces.json");
53422
53981
  if (existsSync58(facesPath)) {
53423
53982
  let faces = [];
53424
53983
  try {
53425
- const parsed = JSON.parse(readFileSync68(facesPath, "utf8"));
53984
+ const parsed = JSON.parse(readFileSync69(facesPath, "utf8"));
53426
53985
  faces = Array.isArray(parsed) ? parsed : [];
53427
53986
  } catch {
53428
53987
  faces = [];
@@ -53443,9 +54002,9 @@ function buildMergedContract(options) {
53443
54002
  merged.branding = branding;
53444
54003
  const body = `${JSON.stringify(merged, null, 2)}
53445
54004
  `;
53446
- const path2 = join55(packageDir, "provisioning.contract.json");
54005
+ const path2 = join56(packageDir, "provisioning.contract.json");
53447
54006
  writeFileSync26(path2, body);
53448
- const localPath = join55(appDir2, LOCAL_CONTRACT_REL);
54007
+ const localPath = join56(appDir2, LOCAL_CONTRACT_REL);
53449
54008
  mkdirSync29(dirname31(localPath), { recursive: true });
53450
54009
  writeFileSync26(localPath, body);
53451
54010
  staged.push(localPath);
@@ -53455,8 +54014,8 @@ async function applyOverlays(input) {
53455
54014
  const cwd = resolve45(input.cwd);
53456
54015
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
53457
54016
  assertKnownShell(shell);
53458
- const overlay = JSON.parse(readFileSync68(input.overlayPath, "utf8"));
53459
- const tokens = JSON.parse(readFileSync68(input.tokensPath, "utf8"));
54017
+ const overlay = JSON.parse(readFileSync69(input.overlayPath, "utf8"));
54018
+ const tokens = JSON.parse(readFileSync69(input.tokensPath, "utf8"));
53460
54019
  const wrote = [];
53461
54020
  const notes = [];
53462
54021
  const repoRoot2 = findRepoRoot(cwd);
@@ -53466,7 +54025,7 @@ async function applyOverlays(input) {
53466
54025
  `shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
53467
54026
  );
53468
54027
  }
53469
- const appDir2 = join55(repoRoot2, shellAppDir(shell));
54028
+ const appDir2 = join56(repoRoot2, shellAppDir(shell));
53470
54029
  const packageDir = dirname31(resolve45(input.overlayPath));
53471
54030
  const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
53472
54031
  wrote.push(...staged);
@@ -53488,10 +54047,10 @@ async function applyOverlays(input) {
53488
54047
  note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
53489
54048
  };
53490
54049
  }
53491
- const pkgProv = join55(cwd, "provisioning.json");
54050
+ const pkgProv = join56(cwd, "provisioning.json");
53492
54051
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
53493
54052
  if (existsSync58(pkgProv)) {
53494
- const cur = JSON.parse(readFileSync68(pkgProv, "utf8"));
54053
+ const cur = JSON.parse(readFileSync69(pkgProv, "utf8"));
53495
54054
  const merged = deepMerge4(cur, overlay);
53496
54055
  writeFileSync26(pkgProv, JSON.stringify(merged, null, 2) + "\n");
53497
54056
  wrote.push(pkgProv);
@@ -53499,9 +54058,9 @@ async function applyOverlays(input) {
53499
54058
  writeFileSync26(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
53500
54059
  wrote.push(pkgProv);
53501
54060
  }
53502
- const pkgTokens = join55(cwd, "tokens.json");
54061
+ const pkgTokens = join56(cwd, "tokens.json");
53503
54062
  if (existsSync58(pkgTokens) && (tokens.colors || tokens.typography)) {
53504
- const cur = JSON.parse(readFileSync68(pkgTokens, "utf8"));
54063
+ const cur = JSON.parse(readFileSync69(pkgTokens, "utf8"));
53505
54064
  const merged = deepMerge4(cur, tokens);
53506
54065
  const mergedColors = merged.colors;
53507
54066
  if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
@@ -53520,9 +54079,9 @@ async function applyOverlays(input) {
53520
54079
  wrote.push(pkgTokens);
53521
54080
  }
53522
54081
  const homeAction = homeRefreshActionId(shell);
53523
- const homeSrc = join55(cwd, "dev/index.ts");
54082
+ const homeSrc = join56(cwd, "dev/index.ts");
53524
54083
  if (homeAction && existsSync58(homeSrc)) {
53525
- const prev = readFileSync68(homeSrc, "utf8");
54084
+ const prev = readFileSync69(homeSrc, "utf8");
53526
54085
  const patched = patchBrandParams(prev, overlay, homeAction);
53527
54086
  let next = patched.src;
53528
54087
  if (!patched.foreign && overlay.installedVerticals?.length) {
@@ -54558,20 +55117,20 @@ function canonicalDomain(domainName) {
54558
55117
  if (domainName == null) {
54559
55118
  return void 0;
54560
55119
  }
54561
- let str6 = domainName.trim().replace(/^\./, "");
54562
- if (IP_V6_REGEX_OBJECT.test(str6)) {
54563
- if (!str6.startsWith("[")) {
54564
- str6 = "[" + str6;
55120
+ let str7 = domainName.trim().replace(/^\./, "");
55121
+ if (IP_V6_REGEX_OBJECT.test(str7)) {
55122
+ if (!str7.startsWith("[")) {
55123
+ str7 = "[" + str7;
54565
55124
  }
54566
- if (!str6.endsWith("]")) {
54567
- str6 = str6 + "]";
55125
+ if (!str7.endsWith("]")) {
55126
+ str7 = str7 + "]";
54568
55127
  }
54569
- return domainToASCII(str6).slice(1, -1);
55128
+ return domainToASCII(str7).slice(1, -1);
54570
55129
  }
54571
- if (/[^\u0001-\u007f]/.test(str6)) {
54572
- return domainToASCII(str6);
55130
+ if (/[^\u0001-\u007f]/.test(str7)) {
55131
+ return domainToASCII(str7);
54573
55132
  }
54574
- return str6.toLowerCase();
55133
+ return str7.toLowerCase();
54575
55134
  }
54576
55135
  function formatDate(date) {
54577
55136
  return date.toUTCString();
@@ -54665,16 +55224,16 @@ function parseDate(cookieDate) {
54665
55224
  }
54666
55225
  return date;
54667
55226
  }
54668
- function trimTerminator(str6) {
54669
- if (isEmptyString(str6)) return str6;
55227
+ function trimTerminator(str7) {
55228
+ if (isEmptyString(str7)) return str7;
54670
55229
  for (let t = 0; t < TERMINATORS.length; t++) {
54671
55230
  const terminator = TERMINATORS[t];
54672
- const terminatorIdx = terminator ? str6.indexOf(terminator) : -1;
55231
+ const terminatorIdx = terminator ? str7.indexOf(terminator) : -1;
54673
55232
  if (terminatorIdx !== -1) {
54674
- str6 = str6.slice(0, terminatorIdx);
55233
+ str7 = str7.slice(0, terminatorIdx);
54675
55234
  }
54676
55235
  }
54677
- return str6;
55236
+ return str7;
54678
55237
  }
54679
55238
  function parseCookiePair(cookiePair, looseMode) {
54680
55239
  cookiePair = trimTerminator(cookiePair);
@@ -54705,13 +55264,13 @@ function parseCookiePair(cookiePair, looseMode) {
54705
55264
  c.value = cookieValue;
54706
55265
  return c;
54707
55266
  }
54708
- function parse(str6, options) {
54709
- if (isEmptyString(str6) || !isString(str6)) {
55267
+ function parse(str7, options) {
55268
+ if (isEmptyString(str7) || !isString(str7)) {
54710
55269
  return void 0;
54711
55270
  }
54712
- str6 = str6.trim();
54713
- const firstSemi = str6.indexOf(";");
54714
- const cookiePair = firstSemi === -1 ? str6 : str6.slice(0, firstSemi);
55271
+ str7 = str7.trim();
55272
+ const firstSemi = str7.indexOf(";");
55273
+ const cookiePair = firstSemi === -1 ? str7 : str7.slice(0, firstSemi);
54715
55274
  const c = parseCookiePair(cookiePair, options?.loose ?? false);
54716
55275
  if (!c) {
54717
55276
  return void 0;
@@ -54719,7 +55278,7 @@ function parse(str6, options) {
54719
55278
  if (firstSemi === -1) {
54720
55279
  return c;
54721
55280
  }
54722
- const unparsed = str6.slice(firstSemi + 1).trim();
55281
+ const unparsed = str7.slice(firstSemi + 1).trim();
54723
55282
  if (unparsed.length === 0) {
54724
55283
  return c;
54725
55284
  }
@@ -54800,19 +55359,19 @@ function parse(str6, options) {
54800
55359
  }
54801
55360
  return c;
54802
55361
  }
54803
- function fromJSON(str6) {
54804
- if (!str6 || isEmptyString(str6)) {
55362
+ function fromJSON(str7) {
55363
+ if (!str7 || isEmptyString(str7)) {
54805
55364
  return void 0;
54806
55365
  }
54807
55366
  let obj3;
54808
- if (typeof str6 === "string") {
55367
+ if (typeof str7 === "string") {
54809
55368
  try {
54810
- obj3 = JSON.parse(str6);
55369
+ obj3 = JSON.parse(str7);
54811
55370
  } catch {
54812
55371
  return void 0;
54813
55372
  }
54814
55373
  } else {
54815
- obj3 = str6;
55374
+ obj3 = str7;
54816
55375
  }
54817
55376
  const c = new Cookie();
54818
55377
  Cookie.serializableProperties.forEach((prop) => {
@@ -55530,42 +56089,42 @@ var init_dist = __esm({
55530
56089
  * @public
55531
56090
  */
55532
56091
  toString() {
55533
- let str6 = this.cookieString();
56092
+ let str7 = this.cookieString();
55534
56093
  if (this.expires != "Infinity") {
55535
56094
  if (this.expires instanceof Date) {
55536
- str6 += `; Expires=${formatDate(this.expires)}`;
56095
+ str7 += `; Expires=${formatDate(this.expires)}`;
55537
56096
  }
55538
56097
  }
55539
56098
  if (this.maxAge != null && this.maxAge != Infinity) {
55540
- str6 += `; Max-Age=${String(this.maxAge)}`;
56099
+ str7 += `; Max-Age=${String(this.maxAge)}`;
55541
56100
  }
55542
56101
  if (this.domain && !this.hostOnly) {
55543
- str6 += `; Domain=${this.domain}`;
56102
+ str7 += `; Domain=${this.domain}`;
55544
56103
  }
55545
56104
  if (this.path) {
55546
- str6 += `; Path=${this.path}`;
56105
+ str7 += `; Path=${this.path}`;
55547
56106
  }
55548
56107
  if (this.secure) {
55549
- str6 += "; Secure";
56108
+ str7 += "; Secure";
55550
56109
  }
55551
56110
  if (this.httpOnly) {
55552
- str6 += "; HttpOnly";
56111
+ str7 += "; HttpOnly";
55553
56112
  }
55554
56113
  if (this.sameSite && this.sameSite !== "none") {
55555
56114
  if (this.sameSite.toLowerCase() === _Cookie2.sameSiteCanonical.lax.toLowerCase()) {
55556
- str6 += `; SameSite=${_Cookie2.sameSiteCanonical.lax}`;
56115
+ str7 += `; SameSite=${_Cookie2.sameSiteCanonical.lax}`;
55557
56116
  } else if (this.sameSite.toLowerCase() === _Cookie2.sameSiteCanonical.strict.toLowerCase()) {
55558
- str6 += `; SameSite=${_Cookie2.sameSiteCanonical.strict}`;
56117
+ str7 += `; SameSite=${_Cookie2.sameSiteCanonical.strict}`;
55559
56118
  } else {
55560
- str6 += `; SameSite=${this.sameSite}`;
56119
+ str7 += `; SameSite=${this.sameSite}`;
55561
56120
  }
55562
56121
  }
55563
56122
  if (this.extensions) {
55564
56123
  this.extensions.forEach((ext) => {
55565
- str6 += `; ${ext}`;
56124
+ str7 += `; ${ext}`;
55566
56125
  });
55567
56126
  }
55568
- return str6;
56127
+ return str7;
55569
56128
  }
55570
56129
  /**
55571
56130
  * Computes the TTL relative to now (milliseconds).
@@ -55688,8 +56247,8 @@ var init_dist = __esm({
55688
56247
  * @param str - The `Set-Cookie` header or a Cookie string to parse.
55689
56248
  * @param options - Configures `strict` or `loose` mode for cookie parsing
55690
56249
  */
55691
- static parse(str6, options) {
55692
- return parse(str6, options);
56250
+ static parse(str7, options) {
56251
+ return parse(str7, options);
55693
56252
  }
55694
56253
  /**
55695
56254
  * Does the reverse of {@link Cookie.toJSON}.
@@ -55716,8 +56275,8 @@ var init_dist = __esm({
55716
56275
  *
55717
56276
  * @param str - An unparsed JSON string or a value that has already been parsed as JSON
55718
56277
  */
55719
- static fromJSON(str6) {
55720
- return fromJSON(str6);
56278
+ static fromJSON(str7) {
56279
+ return fromJSON(str7);
55721
56280
  }
55722
56281
  };
55723
56282
  _Cookie.cookiesCreated = 0;
@@ -57706,7 +58265,7 @@ __export(cli_exports, {
57706
58265
  runSiteAnalyze: () => runSiteAnalyze,
57707
58266
  runSiteFunctionCli: () => runSiteFunctionCli
57708
58267
  });
57709
- import { readFileSync as readFileSync69 } from "node:fs";
58268
+ import { readFileSync as readFileSync70 } from "node:fs";
57710
58269
  import { resolve as resolve46 } from "node:path";
57711
58270
  function assetFetchFor(_opts) {
57712
58271
  return pinnedFetch2;
@@ -57793,7 +58352,7 @@ async function runSiteFunctionCli(opts) {
57793
58352
  let source;
57794
58353
  if (opts.sourcePath) {
57795
58354
  const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
57796
- source = readFileSync69(p, "utf8");
58355
+ source = readFileSync70(p, "utf8");
57797
58356
  }
57798
58357
  let body;
57799
58358
  if (opts.bodyRaw != null) {
@@ -58050,7 +58609,7 @@ __export(site_create_exports, {
58050
58609
  runSiteList: () => runSiteList,
58051
58610
  writeProvisioningBinding: () => writeProvisioningBinding
58052
58611
  });
58053
- import { existsSync as existsSync59, readFileSync as readFileSync70, writeFileSync as writeFileSync27 } from "node:fs";
58612
+ import { existsSync as existsSync59, readFileSync as readFileSync71, writeFileSync as writeFileSync27 } from "node:fs";
58054
58613
  import { resolve as resolvePath2 } from "node:path";
58055
58614
  function oauthClientName(projectName) {
58056
58615
  return `${projectName} client`;
@@ -58199,7 +58758,7 @@ async function runSiteCreate(opts) {
58199
58758
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
58200
58759
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
58201
58760
  }
58202
- function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync59, readFileSync: readFileSync70, writeFileSync: writeFileSync27 }) {
58761
+ function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync59, readFileSync: readFileSync71, writeFileSync: writeFileSync27 }) {
58203
58762
  const msid = binding2.siteId;
58204
58763
  const path2 = resolvePath2(target);
58205
58764
  const committed = committedShellProvisioning(path2);
@@ -58872,11 +59431,11 @@ var init_context = __esm({
58872
59431
  });
58873
59432
 
58874
59433
  // src/cli.ts
58875
- import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync71, mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, existsSync as existsSync60, rmSync as rmSync13, readdirSync as readdirSync27, statSync as statSync17, lstatSync as lstatSync8, accessSync, constants as constants2, renameSync as renameSync6, cpSync as cpSync3 } from "node:fs";
59434
+ import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync72, mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, existsSync as existsSync60, rmSync as rmSync13, readdirSync as readdirSync27, statSync as statSync17, lstatSync as lstatSync9, accessSync, constants as constants2, renameSync as renameSync6, cpSync as cpSync3 } from "node:fs";
58876
59435
  import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
58877
- import { createHash as createHash26, randomUUID as randomUUID5 } from "node:crypto";
59436
+ import { createHash as createHash27, randomUUID as randomUUID5 } from "node:crypto";
58878
59437
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
58879
- import { join as join56, resolve as resolve47, relative as relative10, basename as basename13, dirname as dirname32 } from "node:path";
59438
+ import { join as join57, resolve as resolve47, relative as relative10, basename as basename14, dirname as dirname32 } from "node:path";
58880
59439
  import { fileURLToPath as fileURLToPath24 } from "node:url";
58881
59440
 
58882
59441
  // ../serve-cli/src/client.ts
@@ -62148,12 +62707,12 @@ function parseFlags(argv) {
62148
62707
  return { _, flags };
62149
62708
  }
62150
62709
  var caveatLead = (ni) => ni.severity === "category" ? "WARNING \u2014 not implemented" : "NOTE \u2014 implemented, but these props are inert";
62151
- var str5 = (v) => typeof v === "string" ? v : void 0;
62710
+ var str6 = (v) => typeof v === "string" ? v : void 0;
62152
62711
  var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
62153
62712
  function embeddedTemplateCatalog() {
62154
62713
  return availableTemplates().map((name) => {
62155
- const path2 = join56(templateSourceDir(name), TEMPLATE_META_FILE);
62156
- const meta = JSON.parse(readFileSync71(path2, "utf8"));
62714
+ const path2 = join57(templateSourceDir(name), TEMPLATE_META_FILE);
62715
+ const meta = JSON.parse(readFileSync72(path2, "utf8"));
62157
62716
  if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
62158
62717
  throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
62159
62718
  }
@@ -62215,6 +62774,10 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
62215
62774
  app is built \u2014 screens as they render, the journey step and the
62216
62775
  latest postcard, validate/test/UX/draft checks, site vs app.
62217
62776
  Updates itself; once open, other commands keep it current.
62777
+ himi studio reel [--out <file>] [--no-open]
62778
+ the making-of: one self-contained HTML file of the app taking
62779
+ shape \u2014 a flipbook of the home screen, the final screens, the
62780
+ postcards. Default .himi/making-of.html.
62218
62781
  himi progress ["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>]
62219
62782
  journal a postcard for the owner (.himi/progress.jsonl): what
62220
62783
  changed, which journey step, and the image that shows it (copied
@@ -62766,7 +63329,7 @@ var COMMANDS = [
62766
63329
  { name: "test", summary: "DERIVED behavioral crawl \u2014 no test files to write. Boots each screen's real worker, replays its onAppear, then dispatches every action site the descriptor already declares (each from a fresh boot) and checks a narrow set of unambiguous invariants: no uncaught throw, never stuck on `loading`, no `$service:` token or NaN/undefined/[object Object] reaching visible text, no binding aimed at state the worker never defines, no nav param silently dropped, no dead nav target. Catches what validate/render cannot \u2014 a WRONG REDUCER passes both with ok:true. Runs the worker in a DEVICE-PARITY sandbox (no setTimeout/setInterval, as on JSC/WebView) so a bundle that would die on device fails here. Crawls on HERMETIC DATA by default \u2014 zero network: the app's own dev/net-mocks.json first (--net <file> overrides), then the config's CMS `seed:` rows, then a canned fixture of frozen real vertical responses shipped with the CLI (exercises code paths, not API-contract truth) \u2014 so the success/mapping path runs, not just the failure UI. Two boot-only HOSTILE passes (every list empty; every request 500) then check the failure/empty day \u2014 corpus-proven, so their findings are errors. NAV EDGES are followed too: every himi.open site ($item params resolved against row 0 of its list, $service against worker state) and worker _nav directive is harvested, and each baked target is booted WITH the params the source sends \u2014 detail screens finally run their content arm; edge findings are errors tagged edge:<source>. --native runs both real native decoders over the exact baked JSON bytes; --native ios or --native android selects one. It is explicit, runs only from a Himalaya SOURCE CHECKOUT (the decoder oracles are that tree's own HimalayaCore Swift package and Gradle harness, which a published install does not ship), and needs the selected local toolchain. From a source checkout, default runs name missing native verdicts in the coverage ledger; elsewhere the ledger stays silent about them rather than offering a remedy you cannot run. --offline strips all data layers (the old reject-all axis); --no-hostile skips the hostile passes. --record (EXPLICIT, never automatic) refreshes dev/net-mocks.json from live reads first: it boots each screen (load + root onAppear ONLY \u2014 nothing the app's own launch would not fire; the tap/action crawl never sees the live transport, and only proven reads \u2014 GET, or read-shaped POST (/query, /search, /list*, \u2026) \u2014 ever reach the wire), freezes the round-trips, then crawls hermetically on the fresh fixture; record against a QA site, not production. Nodes it cannot judge headless are named, never silently passed. Exit 1 on any error. The CLI carries the authoring runtime off-repo; no per-app SDK install is required. --browser runs the whole loop (build \u2192 extract \u2192 validate \u2192 render \u2192 test) in YOUR browser instead of here, so the source never reaches a pod: it opens one screen's worker + descriptor in a tab, blocks on a loopback callback, and prints the report it posts back. One screen per tab \u2014 name it. --no-open prints the URL rather than launching a browser (SSH); --timeout <ms> bounds the wait, which matters because the page has no execution deadline of its own and an infinite loop in the worker hangs the tab.", required: "[<screenId>\u2026] [--content <dir>] [--net <file>] [--budget <ms>] [--deep [n]] [--record] [--native [ios|android]] [--no-shots] [--offline] [--no-hostile] [--all-screens] [--browser] [--no-open] [--timeout <ms>] [--json]" },
62767
63330
  { name: "ux", summary: "audit or record mobile UX evidence. `audit` checks the public-safe contract, seeded blank acceptance rows, placeholder source copy, app-specific mocks, and iOS/Android audit records. It warns while existing templates migrate; `--strict` promotes missing evidence. `record` stores checks performed on an installed iOS/Android build: `--checks` is required for passed|failed and empty for unavailable, which drove nothing and needs a `--reason` instead. `record` also STAMPS the release it audited (it resolves the id from a build, the same one a push would publish), because an unforced `himi push` of a release with screens refuses when no drive is recorded for THAT release, or when the one that is recorded says `failed` \u2014 the artifact stopped being advice nobody reads (#2955). `unavailable` still satisfies it; only `failed` refuses.", required: "audit [--content <dir>] [--strict] [--json] | record --content <dir> --platform ios|android --status passed|failed|unavailable [--checks back,keyboard,...] [--reason <text>]" },
62768
63331
  { name: "progress", summary: 'the build JOURNAL an agent keeps for the owner while it works. `himi progress "<what changed>" --step <1-8|name> --image <png>` appends one postcard to .himi/progress.jsonl \u2014 the step is one of the customer journey\'s eight (discover, classify, plan, implement, brand, validate, review, download) \u2014 and COPIES each image, content-addressed, into .himi/history/, because .himi/shots/ is overwritten by every render and cleared by every full `himi test`, so a path into it would later show a different picture than the one the owner was sent. --image repeats. --notify also raises a best-effort desktop notification for an owner who stepped away. A bare `himi progress` prints the journal with the current step and elapsed time \u2014 also how an agent recovers its place after its context was compacted. Local only: nothing is sent anywhere.', required: '["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>]' },
62769
- { name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI).", required: "[--content <dir>] [--no-open]" },
63332
+ { name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI). `himi studio reel` writes the MAKING-OF: one self-contained HTML file (every image inlined, nothing fetched) with a flipbook of the home screen version by version, captioned by the postcard in effect at the time, the final screens, and every postcard \u2014 sized to stay attachable, thinning frames first. Defaults to .himi/making-of.html (never archived by push); --out to put it elsewhere.", required: "[--content <dir>] [--no-open] | reel [--out <file>] [--no-open]" },
62770
63333
  { name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png <file>, --scheme dark, --tree. Local by default (content dir). Pass --remote --app --release to hit GET /v1/preview/\u2026/render on the serve plane after a push. Boots the worker so $service bindings resolve; --static raw bindings; --live real Wix fetches; --state injects worker state; --input supplies pre-boot navigation params; --width/--device for PNG viewport; --rtl for dir=rtl + $env:isRTL.", required: "<screenId> [--content <dir>] [--scheme dark] [--png <file>] [--tree] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--remote --app --release]" },
62771
63334
  { name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 it follows the list endpoint's pages, and `listingIncomplete: true` says when the walk stopped short of the end, with `unlistedCollections` counting what it left out when Wix gave a paging total \u2014 and `foreign.truncated` says how many of those went undescribed, each still NAMED in `foreign.others` (id + displayName), so a collection the site already has is never hidden behind the cap. The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
62772
63335
  { name: "data", summary: "read-only plan or explicitly provision/seed declared KV and Wix Data resources. Preview and production are separate scopes. KV administration uses the operator data plane from --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN; draft push never calls it.", required: "plan|create|seed [--site <msid>] [--environment preview|production] [--content <dir>] [--data-url <url>] [--dry-run] [--force]" },
@@ -62783,7 +63346,7 @@ var COMMANDS = [
62783
63346
  { name: "import", summary: "turn a `himi pack --dev` package back into an EDITABLE content package \u2014 the file counterpart of `himi pull`, needing no serve plane, no account and no network. Refuses an invalid package before trusting its source (the content hash is recomputed over every entry on open, so the archive is provably the one that was packed), and refuses a RELEASE package by naming the absence \u2014 it carries built output and no source \u2014 rather than reporting a missing file. `--name` re-substitutes the app identity through the same machinery `himi init --template` and `himi pull --name` use, so the restored tree is a NEW app rather than a second copy of the same one, and a name that also appears inside a screen id (`feed` in `feed_home`) is left alone. A non-empty destination needs `--force` and a merge NAMES what it kept (`left: [...]`), the same contract `himi pull --force` has; a shape clash is refused whole before anything is written. There is no `--replace`: a file you were handed is not the plane's per-release archive.", required: "<package.himi> [--out <dir>] [--name <new>] [--force]" },
62784
63347
  { name: "pull", summary: "restore an app's SOURCE from the serve plane into an editable content package \u2014 the other half of `himi push`, which archives the content package on every publish. Owner or editor only: a viewer may download the RUNNING app (`/v1/owner/package`), not the codebase it was built from. A PAST release is restorable, not only the live one \u2014 the archive is content-addressed per release, so it has none of the live-single-slot problem that makes `himi pack` current-release-only. Two limits: pruning keeps the current release plus the newest ~20 ledger entries, and a release id identifies OTA content rather than source, so a source-only change republishes under the same id and replaces that id's archive. A release published before source archiving shipped, or pushed with `--no-source`, answers `app_source_not_found` and says to push again. `--name` re-substitutes the app identity through the same machinery `himi init --template` uses, so the restored tree is a NEW app rather than a second copy of the same one, and a name that also appears inside a screen id (`feed` in `feed_home`) is left alone. A NON-EMPTY destination is refused unless you say which you mean: `--force` merges and reports \u2014 it writes the archive over what is there, keeps files the release does not carry, and NAMES every one of them as `left: [...]` so a tree that matches no release is never silent (#2437); `--replace` restores exactly what was archived, removing those files first (`removed: [...]`) and implying `--force`. `--replace` refuses a directory holding no `himalaya.content.json`, so a mistyped `--out` cannot clear an unrelated tree, and the only paths it can remove are the ones a push would have archived \u2014 `.git/`, `node_modules/`, `dist/`, `.env*` and key material are out of its reach by construction.", required: "<app> [--release <id>] [--out <dir>] [--name <new>] [--force|--replace] [--target <t>]" },
62785
63348
  { name: "share", summary: "publish or revoke a content-addressed `.himi` share link. The package must be a validated archive for an already-published release; the resulting https URL is safe to QR, copy, or open in Himi Player.", required: "--file <package.himi> [--expires-at <ISO>] | revoke --app <app> <shareId>" },
62786
- { name: "run", summary: "serve a .himi package on localhost and open it in a browser \u2014 no serve plane, no dev-server, no setup. Given no argument it builds the current content package first, so `himi run` is the inner loop: edit, run, look at it. The SPA and /v1 are served from ONE origin because Tier-5 bundle fetches on web are same-origin-only. --chrome preview frames the app in a device chassis; --chrome app serves it as a plain web app. Blocks until Ctrl-C, like any dev server. --browser runs the whole plane INSIDE the tab (service worker + in-memory store) so no app code executes in this process or on any pod. --watch keeps the preview LIVE: every save in the content package rebuilds it and repaints the open tab with only what changed (the dev-server's hot-reload events); a build that fails keeps the last good preview on screen and says why. It also frames itself on the build board (`himi studio`) and serves the board at /__himi/studio/ on the same origin.", required: "[<package.himi|dir|url>] [--browser] [--watch] [--content <dir>] [--port <n>] [--chrome preview|app] [--screen <id>] [--surface <id>] [--no-open] [--spa <url>]" },
63349
+ { name: "run", summary: "serve a .himi package on localhost and open it in a browser \u2014 no serve plane, no dev-server, no setup. Given no argument it builds the current content package first, so `himi run` is the inner loop: edit, run, look at it. The SPA and /v1 are served from ONE origin because Tier-5 bundle fetches on web are same-origin-only. --chrome preview frames the app in a device chassis; --chrome app serves it as a plain web app. Blocks until Ctrl-C, like any dev server. --browser runs the whole plane INSIDE the tab (service worker + in-memory store) so no app code executes in this process or on any pod. --watch keeps the preview LIVE: every save in the content package rebuilds it and repaints the open tab with only what changed (the dev-server's hot-reload events); a build that fails keeps the last good preview on screen and says why. Any `himi run` of a content package (plain, --watch or --browser) frames its preview on the build board (`himi studio`) while it serves, and all but --browser also serve that board at /__himi/studio/ on the preview's own origin.", required: "[<package.himi|dir|url>] [--browser] [--watch] [--content <dir>] [--port <n>] [--chrome preview|app] [--screen <id>] [--surface <id>] [--no-open] [--spa <url>]" },
62787
63350
  { name: "preview", summary: "print the shareable web URL + himi:// deep link + agent /v1/preview JSON URLs for an app+release; --surface frames the web preview as any catalog surface (?surface=)", required: "--app --release [--screen] [--surface]" },
62788
63351
  { name: "surfaces", summary: "the surface catalog vs this app's envelope (platforms.json): targeted surfaces, the opt-in key for the rest, per-surface preview links with --app --release, and which widget families the package produces with --measure-widgets (which runs its built bundles)", required: "[--content <dir>] [--app --release] [--measure-widgets]" },
62789
63352
  { name: "context", summary: "fetch the agent preview envelope (GET /v1/preview/a/<app>) \u2014 ok/issues/screens/links; exit 1 if ok:false", required: "--app --release [--screen] [--include telemetry]" },
@@ -62815,7 +63378,7 @@ var COMMANDS = [
62815
63378
  ];
62816
63379
  function cliVersion() {
62817
63380
  try {
62818
- return JSON.parse(readFileSync71(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
63381
+ return JSON.parse(readFileSync72(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
62819
63382
  } catch {
62820
63383
  return "unknown";
62821
63384
  }
@@ -62933,7 +63496,7 @@ function ageInDays(publishedAt, now = Date.now()) {
62933
63496
  }
62934
63497
  function packageVersion(path2) {
62935
63498
  try {
62936
- const version2 = JSON.parse(readFileSync71(path2, "utf8")).version;
63499
+ const version2 = JSON.parse(readFileSync72(path2, "utf8")).version;
62937
63500
  return typeof version2 === "string" && version2 ? version2 : void 0;
62938
63501
  } catch {
62939
63502
  return void 0;
@@ -62942,7 +63505,7 @@ function packageVersion(path2) {
62942
63505
  function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
62943
63506
  let dir = resolve47(fromDir);
62944
63507
  for (; ; ) {
62945
- const version2 = packageVersion(join56(dir, "node_modules", "@wix", "himalaya", "package.json"));
63508
+ const version2 = packageVersion(join57(dir, "node_modules", "@wix", "himalaya", "package.json"));
62946
63509
  if (version2) return { version: version2, source: "local" };
62947
63510
  const parent = dirname32(dir);
62948
63511
  if (parent === dir) break;
@@ -62952,7 +63515,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
62952
63515
  if (bundled) return { version: bundled, source: "bundled" };
62953
63516
  try {
62954
63517
  const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
62955
- const version2 = root ? packageVersion(join56(root, "@wix", "himalaya", "package.json")) : void 0;
63518
+ const version2 = root ? packageVersion(join57(root, "@wix", "himalaya", "package.json")) : void 0;
62956
63519
  return version2 ? { version: version2, source: "global" } : {};
62957
63520
  } catch {
62958
63521
  return {};
@@ -62999,11 +63562,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
62999
63562
  var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
63000
63563
  var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
63001
63564
  function updateCachePath(env = process.env) {
63002
- return env.HIMI_UPDATE_CACHE_FILE ?? join56(homedir7(), ".himalaya", "update-check.json");
63565
+ return env.HIMI_UPDATE_CACHE_FILE ?? join57(homedir7(), ".himalaya", "update-check.json");
63003
63566
  }
63004
63567
  function readUpdateCache(path2) {
63005
63568
  try {
63006
- const parsed = JSON.parse(readFileSync71(path2, "utf8"));
63569
+ const parsed = JSON.parse(readFileSync72(path2, "utf8"));
63007
63570
  return parsed && typeof parsed === "object" ? parsed : {};
63008
63571
  } catch {
63009
63572
  return {};
@@ -63071,11 +63634,11 @@ function createUpdateRunner(spawn7 = spawnSync5) {
63071
63634
  },
63072
63635
  installedVersion: () => {
63073
63636
  const root = globalNodeModulesRoot();
63074
- return root ? packageVersion(join56(root, "@wix", "himalaya-cli", "package.json")) : void 0;
63637
+ return root ? packageVersion(join57(root, "@wix", "himalaya-cli", "package.json")) : void 0;
63075
63638
  },
63076
63639
  reexec: (argv) => {
63077
63640
  const root = globalNodeModulesRoot();
63078
- const entry = root ? join56(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
63641
+ const entry = root ? join57(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
63079
63642
  if (!entry || !existsSync60(entry)) return void 0;
63080
63643
  const result = spawnSync5(process.execPath, [entry, ...argv], {
63081
63644
  // inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
@@ -63123,7 +63686,7 @@ function staleUpdateLockFile(cachePath, now) {
63123
63686
  for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
63124
63687
  let content;
63125
63688
  try {
63126
- content = readFileSync71(path2, "utf8");
63689
+ content = readFileSync72(path2, "utf8");
63127
63690
  } catch {
63128
63691
  continue;
63129
63692
  }
@@ -63146,7 +63709,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
63146
63709
  const mine = lockStamp(now);
63147
63710
  const readLock = (path2) => {
63148
63711
  try {
63149
- return readFileSync71(path2, "utf8");
63712
+ return readFileSync72(path2, "utf8");
63150
63713
  } catch {
63151
63714
  return void 0;
63152
63715
  }
@@ -63684,7 +64247,7 @@ function executableOnPath(name, env = process.env) {
63684
64247
  const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
63685
64248
  for (const dir of entries) {
63686
64249
  for (const suffix of suffixes) {
63687
- const candidate = join56(dir, `${name}${suffix}`);
64250
+ const candidate = join57(dir, `${name}${suffix}`);
63688
64251
  try {
63689
64252
  if (!statSync17(candidate).isFile()) continue;
63690
64253
  if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
@@ -63793,7 +64356,7 @@ async function nativeConfigAdvisories(app, configSource) {
63793
64356
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
63794
64357
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
63795
64358
  const iosYmlPath = iosProjectYml2(app);
63796
- const iosYml = existsSync60(iosYmlPath) ? readFileSync71(iosYmlPath, "utf8") : "";
64359
+ const iosYml = existsSync60(iosYmlPath) ? readFileSync72(iosYmlPath, "utf8") : "";
63797
64360
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
63798
64361
  if (!optedIn) {
63799
64362
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -63807,7 +64370,7 @@ async function nativeConfigAdvisories(app, configSource) {
63807
64370
  }
63808
64371
  function readConfigSource(dir) {
63809
64372
  try {
63810
- return readFileSync71(join56(dir, "config.ts"), "utf8");
64373
+ return readFileSync72(join57(dir, "config.ts"), "utf8");
63811
64374
  } catch {
63812
64375
  return null;
63813
64376
  }
@@ -63819,7 +64382,7 @@ function writePngFile(path2, base64) {
63819
64382
  }
63820
64383
  async function initFromRemoteTemplate(name, parentDir, template, c) {
63821
64384
  const dir = resolve47(parentDir, name);
63822
- if (existsSync60(join56(dir, "himalaya.content.json"))) {
64385
+ if (existsSync60(join57(dir, "himalaya.content.json"))) {
63823
64386
  throw new Error(`content package already exists at ${dir}`);
63824
64387
  }
63825
64388
  const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -63831,7 +64394,7 @@ async function initFromRemoteTemplate(name, parentDir, template, c) {
63831
64394
  return finishScaffold(materializeSource(archive.files, name, dir), template);
63832
64395
  }
63833
64396
  function contentDir(flags) {
63834
- return resolve47(str5(flags.content) ?? process.cwd());
64397
+ return resolve47(str6(flags.content) ?? process.cwd());
63835
64398
  }
63836
64399
  function renameRestoredSource(restored, declaredApp, renamed) {
63837
64400
  const text5 = {};
@@ -63849,7 +64412,7 @@ function renameRestoredSource(restored, declaredApp, renamed) {
63849
64412
  function symlinkDestinationIssue(dest) {
63850
64413
  let kind;
63851
64414
  try {
63852
- kind = lstatSync8(dest);
64415
+ kind = lstatSync9(dest);
63853
64416
  } catch {
63854
64417
  return null;
63855
64418
  }
@@ -63877,7 +64440,7 @@ function restoreDestinationIssue(dest, force) {
63877
64440
  function isHimalayaMonorepoCheckout(start) {
63878
64441
  let dir = resolve47(start);
63879
64442
  for (; ; ) {
63880
- if (existsSync60(join56(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync60(join56(dir, "core", "serve", "src", "server.ts"))) return true;
64443
+ if (existsSync60(join57(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync60(join57(dir, "core", "serve", "src", "server.ts"))) return true;
63881
64444
  const parent = dirname32(dir);
63882
64445
  if (parent === dir) return false;
63883
64446
  dir = parent;
@@ -63920,7 +64483,7 @@ function materializeForPreview(appDir2, slug, displayName) {
63920
64483
  Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
63921
64484
  );
63922
64485
  const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
63923
- const root = join56(repoRoot2, "node_modules", ".cache", "himi-template-preview");
64486
+ const root = join57(repoRoot2, "node_modules", ".cache", "himi-template-preview");
63924
64487
  const stillRunning = (pid) => {
63925
64488
  try {
63926
64489
  process.kill(pid, 0);
@@ -63934,12 +64497,12 @@ function materializeForPreview(appDir2, slug, displayName) {
63934
64497
  if (!entry.isDirectory()) continue;
63935
64498
  const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
63936
64499
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
63937
- rmSync13(join56(root, entry.name), { recursive: true, force: true });
64500
+ rmSync13(join57(root, entry.name), { recursive: true, force: true });
63938
64501
  }
63939
64502
  }
63940
64503
  } catch {
63941
64504
  }
63942
- const dest = join56(root, `${slug}-${process.pid}`);
64505
+ const dest = join57(root, `${slug}-${process.pid}`);
63943
64506
  rmSync13(dest, { recursive: true, force: true });
63944
64507
  mkdirSync30(dest, { recursive: true });
63945
64508
  materializeSource(forBuild, displayName, dest, slug);
@@ -63947,17 +64510,17 @@ function materializeForPreview(appDir2, slug, displayName) {
63947
64510
  }
63948
64511
  async function appId(dir) {
63949
64512
  try {
63950
- const { readFileSync: readFileSync72 } = await import("node:fs");
63951
- const m = JSON.parse(readFileSync72(join56(dir, "himalaya.content.json"), "utf8"));
64513
+ const { readFileSync: readFileSync73 } = await import("node:fs");
64514
+ const m = JSON.parse(readFileSync73(join57(dir, "himalaya.content.json"), "utf8"));
63952
64515
  if (m.name) return m.name;
63953
64516
  } catch {
63954
64517
  }
63955
- return basename13(dir);
64518
+ return basename14(dir);
63956
64519
  }
63957
64520
  async function contentVisibility(dir) {
63958
64521
  try {
63959
- const { readFileSync: readFileSync72 } = await import("node:fs");
63960
- const m = JSON.parse(readFileSync72(join56(dir, "himalaya.content.json"), "utf8"));
64522
+ const { readFileSync: readFileSync73 } = await import("node:fs");
64523
+ const m = JSON.parse(readFileSync73(join57(dir, "himalaya.content.json"), "utf8"));
63961
64524
  if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
63962
64525
  } catch {
63963
64526
  }
@@ -63965,7 +64528,7 @@ async function contentVisibility(dir) {
63965
64528
  }
63966
64529
  function visibilityFlag(flags, io) {
63967
64530
  if (flags.visibility === void 0) return {};
63968
- const v = str5(flags.visibility);
64531
+ const v = str6(flags.visibility);
63969
64532
  if (v !== "public" && v !== "unlisted") {
63970
64533
  io.error(JSON.stringify({ error: `--visibility must be public or unlisted (got "${v ?? ""}")` }));
63971
64534
  return null;
@@ -64159,7 +64722,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
64159
64722
  return 0;
64160
64723
  }
64161
64724
  case "agent-init": {
64162
- const dir = resolve47(str5(flags.dir) ?? process.cwd());
64725
+ const dir = resolve47(str6(flags.dir) ?? process.cwd());
64163
64726
  const res = writeAgentContext(dir);
64164
64727
  print({ ok: true, dir: res.dir, files: res.files, portalUrl: idx.portalUrl });
64165
64728
  return 0;
@@ -64181,7 +64744,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
64181
64744
  try {
64182
64745
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
64183
64746
  const bres = await buildContentForValidation2(dir, { resolution });
64184
- out = mkdtempSync4(join56(tmpdir5(), "himi-ux-record-"));
64747
+ out = mkdtempSync4(join57(tmpdir5(), "himi-ux-record-"));
64185
64748
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64186
64749
  const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
64187
64750
  const releaseId = outcome.manifest.releaseId;
@@ -64359,7 +64922,7 @@ async function producedWidgetFamilies(dir) {
64359
64922
  let js;
64360
64923
  for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
64361
64924
  try {
64362
- js = readFileSync71(join56(outDir, candidate), "utf8");
64925
+ js = readFileSync72(join57(outDir, candidate), "utf8");
64363
64926
  break;
64364
64927
  } catch {
64365
64928
  }
@@ -64390,7 +64953,7 @@ async function producedWidgetFamilies(dir) {
64390
64953
  }
64391
64954
  return { families, source: "dist/bundles" };
64392
64955
  }
64393
- var boardOpen = (dir) => existsSync60(join56(dir, ".himi", "studio", "index.html"));
64956
+ var boardOpen = (dir) => existsSync60(join57(dir, ".himi", "studio", "index.html"));
64394
64957
  var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
64395
64958
  async function leaveForBoard(dir, record2, value) {
64396
64959
  if (!boardOpen(dir)) return;
@@ -64445,20 +65008,20 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64445
65008
  if (update) updateNotice = update;
64446
65009
  }
64447
65010
  const contextualDefaultTarget = defaultTargetForCommand(command, contentDir(flags));
64448
- const targetName = () => resolveTargetName({ target: str5(flags.target), defaultTarget: contextualDefaultTarget });
65011
+ const targetName = () => resolveTargetName({ target: str6(flags.target), defaultTarget: contextualDefaultTarget });
64449
65012
  const client2 = () => new ServeCliClient(
64450
65013
  resolveTarget({
64451
- target: str5(flags.target),
65014
+ target: str6(flags.target),
64452
65015
  defaultTarget: contextualDefaultTarget,
64453
- serveUrl: str5(flags["serve-url"]),
64454
- telemetryUrl: str5(flags["telemetry-url"]),
64455
- controlUrl: str5(flags["control-url"]),
64456
- telemetryToken: str5(flags["telemetry-token"]),
64457
- controlToken: str5(flags["control-token"])
65016
+ serveUrl: str6(flags["serve-url"]),
65017
+ telemetryUrl: str6(flags["telemetry-url"]),
65018
+ controlUrl: str6(flags["control-url"]),
65019
+ telemetryToken: str6(flags["telemetry-token"]),
65020
+ controlToken: str6(flags["control-token"])
64458
65021
  })
64459
65022
  );
64460
- const serveBase = () => resolveTarget({ target: str5(flags.target), defaultTarget: contextualDefaultTarget, serveUrl: str5(flags["serve-url"]) }).serve;
64461
- const controlBase = () => resolveTarget({ target: str5(flags.target), defaultTarget: contextualDefaultTarget, controlUrl: str5(flags["control-url"]) }).control ?? "";
65023
+ const serveBase = () => resolveTarget({ target: str6(flags.target), defaultTarget: contextualDefaultTarget, serveUrl: str6(flags["serve-url"]) }).serve;
65024
+ const controlBase = () => resolveTarget({ target: str6(flags.target), defaultTarget: contextualDefaultTarget, controlUrl: str6(flags["control-url"]) }).control ?? "";
64462
65025
  const foreignPlaneRefusal = async () => {
64463
65026
  const base = serveBase();
64464
65027
  if (!isLoopbackBase(base)) return null;
@@ -64656,8 +65219,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64656
65219
  io.error(JSON.stringify({ ok: false, error: flagError }));
64657
65220
  return 2;
64658
65221
  }
64659
- const template = str5(flags.template);
64660
- const parentDir = resolve47(str5(flags.dir) ?? process.cwd());
65222
+ const template = str6(flags.template);
65223
+ const parentDir = resolve47(str6(flags.dir) ?? process.cwd());
64661
65224
  if (template && flags.remote === true) {
64662
65225
  try {
64663
65226
  const res2 = await initFromRemoteTemplate(name, parentDir, template, client2());
@@ -64774,11 +65337,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64774
65337
  return outcome.code;
64775
65338
  }
64776
65339
  if (sub === "publish") {
64777
- const appDir2 = resolve47(str5(flags.dir) ?? process.cwd());
64778
- const sourceDir = resolve47(str5(flags["source-dir"]) ?? appDir2);
65340
+ const appDir2 = resolve47(str6(flags.dir) ?? process.cwd());
65341
+ const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
64779
65342
  let meta;
64780
65343
  try {
64781
- meta = JSON.parse(readFileSync71(join56(sourceDir, TEMPLATE_META_FILE), "utf8"));
65344
+ meta = JSON.parse(readFileSync72(join57(sourceDir, TEMPLATE_META_FILE), "utf8"));
64782
65345
  } catch {
64783
65346
  io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
64784
65347
  return 2;
@@ -64788,11 +65351,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64788
65351
  return 2;
64789
65352
  }
64790
65353
  try {
64791
- const appearance = extractTemplateAppearance(JSON.parse(readFileSync71(join56(sourceDir, "tokens.json"), "utf8")));
65354
+ const appearance = extractTemplateAppearance(JSON.parse(readFileSync72(join57(sourceDir, "tokens.json"), "utf8")));
64792
65355
  meta = { ...appearance, ...meta };
64793
65356
  } catch {
64794
65357
  }
64795
- const name = str5(flags.name) ?? await appId(sourceDir);
65358
+ const name = str6(flags.name) ?? await appId(sourceDir);
64796
65359
  const templateAppId = TEMPLATE_APP_PREFIX + name;
64797
65360
  const buildDir = materializeForPreview(appDir2, name, meta.title);
64798
65361
  const app = await appId(buildDir);
@@ -64800,7 +65363,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64800
65363
  const force = flags.force === true;
64801
65364
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
64802
65365
  const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
64803
- const out = mkdtempSync4(join56(tmpdir5(), "himi-template-"));
65366
+ const out = mkdtempSync4(join57(tmpdir5(), "himi-template-"));
64804
65367
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64805
65368
  const outcome = await buildReleaseFromContent2(buildDir, out, {
64806
65369
  ...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
@@ -64849,13 +65412,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64849
65412
  }));
64850
65413
  return 1;
64851
65414
  }
64852
- const iconPath = str5(flags.icon) ? resolve47(str5(flags.icon)) : templateIconPath(name);
65415
+ const iconPath = str6(flags.icon) ? resolve47(str6(flags.icon)) : templateIconPath(name);
64853
65416
  let iconHash;
64854
65417
  if (iconPath) {
64855
65418
  try {
64856
- const bytes2 = readFileSync71(iconPath);
65419
+ const bytes2 = readFileSync72(iconPath);
64857
65420
  payload.icon = bytes2.toString("base64");
64858
- iconHash = createHash26("sha256").update(bytes2).digest("hex");
65421
+ iconHash = createHash27("sha256").update(bytes2).digest("hex");
64859
65422
  } catch {
64860
65423
  }
64861
65424
  }
@@ -64904,8 +65467,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64904
65467
  const tplVis = visibilityFlag(flags, io);
64905
65468
  if (!tplVis) return 2;
64906
65469
  const publishMeta = {
64907
- ...str5(flags.label) ? { label: str5(flags.label) } : {},
64908
- ...str5(flags.notes) ? { notes: str5(flags.notes) } : {},
65470
+ ...str6(flags.label) ? { label: str6(flags.label) } : {},
65471
+ ...str6(flags.notes) ? { notes: str6(flags.notes) } : {},
64909
65472
  ...tplVis.value ? { visibility: tplVis.value } : {}
64910
65473
  };
64911
65474
  let sendPayload = payload;
@@ -65005,7 +65568,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65005
65568
  return 1;
65006
65569
  }
65007
65570
  const releaseId = r.json?.releaseId ?? payload.manifest.releaseId;
65008
- const targetFlag = str5(flags.target) ? ` --target ${str5(flags.target)}` : "";
65571
+ const targetFlag = str6(flags.target) ? ` --target ${str6(flags.target)}` : "";
65009
65572
  print({
65010
65573
  ok: true,
65011
65574
  template: name,
@@ -65086,7 +65649,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65086
65649
  const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
65087
65650
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65088
65651
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
65089
- const out = mkdtempSync4(join56(tmpdir5(), "himi-validate-"));
65652
+ const out = mkdtempSync4(join57(tmpdir5(), "himi-validate-"));
65090
65653
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65091
65654
  const outcome = await buildReleaseFromContent2(dir, out, {
65092
65655
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65124,12 +65687,12 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65124
65687
  }
65125
65688
  case "functions": {
65126
65689
  const { buildLocalFunctions: buildLocalFunctions2, describeFunction: describeFunction2, invokeLocalFunction: invokeLocalFunction2, invokeRemoteFunction: invokeRemoteFunction2, listFunctions: listFunctions2, loadFunctionsApp: loadFunctionsApp2, openApiForFunctions: openApiForFunctions2, resolveFunctionsTarget: resolveFunctionsTarget2, runRemoteFunctionOperation: runRemoteFunctionOperation2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
65127
- const remoteTarget = str5(flags.target);
65690
+ const remoteTarget = str6(flags.target);
65128
65691
  const boCookie = () => {
65129
65692
  const path2 = dpxSessionTokenPath();
65130
65693
  let raw;
65131
65694
  try {
65132
- raw = readFileSync71(path2, "utf8");
65695
+ raw = readFileSync72(path2, "utf8");
65133
65696
  } catch {
65134
65697
  throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
65135
65698
  }
@@ -65147,14 +65710,14 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65147
65710
  io.error(JSON.stringify({ error: `functions ${sub} needs ${allowed2.join(" | ")}` }));
65148
65711
  return 2;
65149
65712
  }
65150
- const app = str5(flags.app);
65713
+ const app = str6(flags.app);
65151
65714
  const id = pos[3];
65152
65715
  if (!app || !["list", "dlq"].includes(action) && !id) {
65153
65716
  io.error(JSON.stringify({ error: `functions ${sub} ${action} needs --app${["list", "dlq"].includes(action) ? "" : " and an id/name"}` }));
65154
65717
  return 2;
65155
65718
  }
65156
- const target2 = resolveFunctionsTarget2({ target: remoteTarget, functionsUrl: str5(flags["functions-url"]), releaseId: str5(flags.release), requireRemote: true });
65157
- const result = await runRemoteFunctionOperation2({ baseUrl: target2.mode === "remote" ? target2.baseUrl : "", app, environment: str5(flags.environment) === "preview" ? "preview" : "production", resource: sub === "jobs" ? "jobs" : "schedules", action, id, releaseId: str5(flags.release), boCookie: boCookie(), previewToken: str5(flags["preview-token"]) });
65719
+ const target2 = resolveFunctionsTarget2({ target: remoteTarget, functionsUrl: str6(flags["functions-url"]), releaseId: str6(flags.release), requireRemote: true });
65720
+ const result = await runRemoteFunctionOperation2({ baseUrl: target2.mode === "remote" ? target2.baseUrl : "", app, environment: str6(flags.environment) === "preview" ? "preview" : "production", resource: sub === "jobs" ? "jobs" : "schedules", action, id, releaseId: str6(flags.release), boCookie: boCookie(), previewToken: str6(flags["preview-token"]) });
65158
65721
  print({ ...result.body, ok: result.ok, status: result.status });
65159
65722
  return result.ok ? 0 : 1;
65160
65723
  }
@@ -65190,7 +65753,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65190
65753
  }
65191
65754
  let input = { name: "Himi", value: "echo", ok: true };
65192
65755
  if (flags.body !== void 0) {
65193
- const raw = str5(flags.body);
65756
+ const raw = str6(flags.body);
65194
65757
  if (!raw) {
65195
65758
  io.error(JSON.stringify({ error: "--body must be non-empty JSON" }));
65196
65759
  return 2;
@@ -65204,7 +65767,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65204
65767
  }
65205
65768
  let params = {};
65206
65769
  if (flags.params !== void 0) {
65207
- const raw = str5(flags.params);
65770
+ const raw = str6(flags.params);
65208
65771
  try {
65209
65772
  const parsed = JSON.parse(raw ?? "");
65210
65773
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || Object.values(parsed).some((value) => typeof value !== "string")) throw new Error("must be a JSON object of string values");
@@ -65214,16 +65777,16 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65214
65777
  return 2;
65215
65778
  }
65216
65779
  }
65217
- const remoteRelease = str5(flags.release);
65218
- const target = resolveFunctionsTarget2({ target: remoteTarget, functionsUrl: str5(flags["functions-url"]), releaseId: remoteRelease });
65780
+ const remoteRelease = str6(flags.release);
65781
+ const target = resolveFunctionsTarget2({ target: remoteTarget, functionsUrl: str6(flags["functions-url"]), releaseId: remoteRelease });
65219
65782
  if (target.mode === "remote") {
65220
65783
  const definition = loaded.definitions.find((item) => item.name === name);
65221
65784
  if (!definition) {
65222
65785
  io.error(JSON.stringify({ error: `unknown function "${name}"` }));
65223
65786
  return 1;
65224
65787
  }
65225
- const app = str5(flags.app) ?? loaded.app;
65226
- const invoked2 = await invokeRemoteFunction2({ baseUrl: target.baseUrl, app, definition, body: input, params, releaseId: remoteRelease, previewToken: str5(flags["preview-token"]), boCookie: boCookie() });
65788
+ const app = str6(flags.app) ?? loaded.app;
65789
+ const invoked2 = await invokeRemoteFunction2({ baseUrl: target.baseUrl, app, definition, body: input, params, releaseId: remoteRelease, previewToken: str6(flags["preview-token"]), boCookie: boCookie() });
65227
65790
  const response = invoked2.response;
65228
65791
  const text6 = await response.text();
65229
65792
  let body2;
@@ -65249,10 +65812,41 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65249
65812
  case "studio": {
65250
65813
  const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
65251
65814
  const dir = contentDir(flags);
65252
- if (!existsSync60(join56(dir, "himalaya.content.json"))) {
65815
+ if (!existsSync60(join57(dir, "himalaya.content.json"))) {
65253
65816
  io.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
65254
65817
  return 2;
65255
65818
  }
65819
+ if (pos[1] === "reel") {
65820
+ const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
65821
+ const out = resolve47(str6(flags.out) ?? join57(dir, ".himi", "making-of.html"));
65822
+ const { html, plan } = buildReel2(dir);
65823
+ mkdirSync30(dirname32(out), { recursive: true });
65824
+ writeFileSync28(out, html);
65825
+ const { pathToFileURL: pathToFileURL9 } = await import("node:url");
65826
+ const url2 = pathToFileURL9(out).href;
65827
+ const open2 = flags["no-open"] !== true;
65828
+ if (open2) {
65829
+ const { openUrl: openUrl2 } = await Promise.resolve().then(() => (init_open_url(), open_url_exports));
65830
+ openUrl2(url2);
65831
+ }
65832
+ print({
65833
+ ok: true,
65834
+ file: out,
65835
+ url: url2,
65836
+ opened: open2,
65837
+ bytes: Buffer.byteLength(html),
65838
+ frames: plan.frames.length,
65839
+ screens: plan.stats.screens,
65840
+ postcards: plan.stats.postcards,
65841
+ ...plan.dropped ? { dropped: plan.dropped, note: "pictures were left out to keep the file attachable" } : {},
65842
+ ...plan.frames.length === 0 ? { hint: "no screen versions were recorded \u2014 run `himi studio` before building so the board keeps them" } : {}
65843
+ });
65844
+ return 0;
65845
+ }
65846
+ if (pos[1] !== void 0) {
65847
+ io.error(JSON.stringify({ ok: false, error: "unknown_subcommand", got: pos[1], expected: "himi studio [reel]" }));
65848
+ return 2;
65849
+ }
65256
65850
  const { page, url, view } = openStudio2(dir);
65257
65851
  const open = flags["no-open"] !== true;
65258
65852
  if (open) {
@@ -65274,7 +65868,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65274
65868
  const { appendProgress: appendProgress2, readProgress: readProgress2, summarizeProgress: summarizeProgress2, parseStep: parseStep2, notifyDesktop: notifyDesktop2, appLabel: appLabel2, journalPath: journalPath2, ProgressError: ProgressError2, JOURNEY_STEPS: JOURNEY_STEPS2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
65275
65869
  const dir = contentDir(flags);
65276
65870
  const journal = journalPath2(dir);
65277
- const hint = existsSync60(join56(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
65871
+ const hint = existsSync60(join57(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
65278
65872
  const message = pos.slice(1).join(" ").trim();
65279
65873
  if (!message) {
65280
65874
  if (flags.step !== void 0 || flags.image !== void 0 || flags.notify === true) {
@@ -65325,9 +65919,9 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65325
65919
  io.error(JSON.stringify({ error: "ux needs audit | record" }));
65326
65920
  return 2;
65327
65921
  }
65328
- const platform = str5(flags.platform);
65329
- const status = str5(flags.status);
65330
- const checks = str5(flags.checks)?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
65922
+ const platform = str6(flags.platform);
65923
+ const status = str6(flags.status);
65924
+ const checks = str6(flags.checks)?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
65331
65925
  if (!isNativePlatform(platform)) {
65332
65926
  io.error(JSON.stringify({ error: `ux record needs --platform ${NATIVE_PLATFORMS.join("|")}` }));
65333
65927
  return 2;
@@ -65341,7 +65935,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65341
65935
  drifting = workers;
65342
65936
  });
65343
65937
  try {
65344
- const evidence = recordNativeAudit(dir, platform, status, checks, str5(flags.reason), uxRelease ?? void 0);
65938
+ const evidence = recordNativeAudit(dir, platform, status, checks, str6(flags.reason), uxRelease ?? void 0);
65345
65939
  print({
65346
65940
  ok: true,
65347
65941
  content: dir,
@@ -65366,7 +65960,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65366
65960
  case "test": {
65367
65961
  const dir = contentDir(flags);
65368
65962
  const structuredOutput = flags.json === true || io.isTTY !== true;
65369
- if (existsSync60(join56(dir, "functions"))) {
65963
+ if (existsSync60(join57(dir, "functions"))) {
65370
65964
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
65371
65965
  const loaded = await loadFunctionsApp2(dir);
65372
65966
  const results = [];
@@ -65391,21 +65985,21 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65391
65985
  }
65392
65986
  let budgetMs;
65393
65987
  if (flags.budget !== void 0) {
65394
- budgetMs = Number(str5(flags.budget));
65988
+ budgetMs = Number(str6(flags.budget));
65395
65989
  if (!Number.isFinite(budgetMs) || budgetMs <= 0) {
65396
- io.error(JSON.stringify({ error: `--budget must be a positive number of ms (got "${str5(flags.budget) ?? ""}")` }));
65990
+ io.error(JSON.stringify({ error: `--budget must be a positive number of ms (got "${str6(flags.budget) ?? ""}")` }));
65397
65991
  return 2;
65398
65992
  }
65399
65993
  }
65400
65994
  let deep;
65401
65995
  if (flags.deep !== void 0) {
65402
- deep = flags.deep === true ? 3 : Number(str5(flags.deep));
65996
+ deep = flags.deep === true ? 3 : Number(str6(flags.deep));
65403
65997
  if (!Number.isFinite(deep) || deep < 2 || deep > 6) {
65404
65998
  io.error(JSON.stringify({ error: `--deep takes a chain depth between 2 and 6 (got "${String(flags.deep)}") \u2014 bare --deep means 3` }));
65405
65999
  return 2;
65406
66000
  }
65407
66001
  }
65408
- const netPath = str5(flags.net);
66002
+ const netPath = str6(flags.net);
65409
66003
  if (flags.net !== void 0 && !netPath) {
65410
66004
  io.error(JSON.stringify({ error: "--net was given but empty \u2014 pass a path to a net-mocks JSON file" }));
65411
66005
  return 2;
@@ -65436,7 +66030,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65436
66030
  const { detectAndroidNativeDecode: detectAndroidNativeDecode2, detectNativeDecode: detectNativeDecode2, nativeDecodePlatforms: nativeDecodePlatforms2 } = await Promise.resolve().then(() => (init_native_decode(), native_decode_exports));
65437
66031
  let platforms;
65438
66032
  try {
65439
- platforms = nativeDecodePlatforms2(flags.native === true ? true : str5(flags.native));
66033
+ platforms = nativeDecodePlatforms2(flags.native === true ? true : str6(flags.native));
65440
66034
  } catch (error) {
65441
66035
  io.error(JSON.stringify({ error: error.message }));
65442
66036
  return 2;
@@ -65453,7 +66047,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65453
66047
  }
65454
66048
  }
65455
66049
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
65456
- const out = mkdtempSync4(join56(tmpdir5(), "himi-test-"));
66050
+ const out = mkdtempSync4(join57(tmpdir5(), "himi-test-"));
65457
66051
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65458
66052
  const outcome = await buildReleaseFromContent2(dir, out, {
65459
66053
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65478,9 +66072,9 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65478
66072
  }
65479
66073
  let browserTimeoutMs;
65480
66074
  if (flags.timeout !== void 0) {
65481
- browserTimeoutMs = Number(str5(flags.timeout));
66075
+ browserTimeoutMs = Number(str6(flags.timeout));
65482
66076
  if (!Number.isFinite(browserTimeoutMs) || browserTimeoutMs <= 0) {
65483
- io.error(JSON.stringify({ error: `--timeout must be a positive number of ms (got "${str5(flags.timeout) ?? ""}")` }));
66077
+ io.error(JSON.stringify({ error: `--timeout must be a positive number of ms (got "${str6(flags.timeout) ?? ""}")` }));
65484
66078
  return 2;
65485
66079
  }
65486
66080
  }
@@ -65498,7 +66092,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65498
66092
  io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
65499
66093
  return 2;
65500
66094
  }
65501
- const sources = collectWorkerSources2(join56(dir, "tier5-src"), screen.bundleName);
66095
+ const sources = collectWorkerSources2(join57(dir, "tier5-src"), screen.bundleName);
65502
66096
  if (!sources) {
65503
66097
  io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
65504
66098
  return 2;
@@ -65659,7 +66253,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65659
66253
  const sp = await runShotsPass2({
65660
66254
  descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
65661
66255
  tokens: outcome.tokens,
65662
- outDir: join56(dir, ".himi", "shots"),
66256
+ outDir: join57(dir, ".himi", "shots"),
65663
66257
  width: 390,
65664
66258
  layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
65665
66259
  ...budgetMs ? { budgetMs } : {},
@@ -65697,7 +66291,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65697
66291
  releaseId: result.releaseId,
65698
66292
  releasePayload: release,
65699
66293
  descriptors: attestedDescriptors,
65700
- screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join56(dir, ".himi", "shots", name)])),
66294
+ screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join57(dir, ".himi", "shots", name)])),
65701
66295
  coverage: {
65702
66296
  screens: crawledScreens.size,
65703
66297
  actionsDispatched: result.actions.exercised,
@@ -65731,15 +66325,15 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65731
66325
  io.error(JSON.stringify({ error: "render --remote cannot --dump-state: the serve plane has no worker runtime. Render locally to inspect state." }));
65732
66326
  return 2;
65733
66327
  }
65734
- const app2 = str5(flags.app);
65735
- const release2 = str5(flags.release);
66328
+ const app2 = str6(flags.app);
66329
+ const release2 = str6(flags.release);
65736
66330
  if (!app2 || !release2) {
65737
66331
  io.error(JSON.stringify({ error: "render --remote needs --app and --release" }));
65738
66332
  return 2;
65739
66333
  }
65740
- const scheme2 = str5(flags.scheme) === "dark" ? "dark" : "light";
66334
+ const scheme2 = str6(flags.scheme) === "dark" ? "dark" : "light";
65741
66335
  const wantPng2 = flags.png === true || typeof flags.png === "string";
65742
- const widthRaw = str5(flags.width);
66336
+ const widthRaw = str6(flags.width);
65743
66337
  const width = widthRaw ? Number(widthRaw) : void 0;
65744
66338
  let r2;
65745
66339
  try {
@@ -65770,7 +66364,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65770
66364
  }
65771
66365
  const dir = contentDir(flags);
65772
66366
  const app = await appId(dir);
65773
- const scheme = str5(flags.scheme) === "dark" ? "dark" : "light";
66367
+ const scheme = str6(flags.scheme) === "dark" ? "dark" : "light";
65774
66368
  const wantPng = flags.png === true || typeof flags.png === "string";
65775
66369
  const hydrate = flags.static !== true;
65776
66370
  const live2 = flags.live === true;
@@ -65781,13 +66375,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65781
66375
  }
65782
66376
  let injectedState;
65783
66377
  if (flags.state !== void 0) {
65784
- const stateArg = str5(flags.state);
66378
+ const stateArg = str6(flags.state);
65785
66379
  if (!stateArg || !stateArg.trim()) {
65786
66380
  io.error(JSON.stringify({ error: "--state was given but empty \u2014 pass inline JSON `{\u2026}` or a path to a .json file" }));
65787
66381
  return 2;
65788
66382
  }
65789
66383
  try {
65790
- const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync71(stateArg.replace(/^@/, ""), "utf8");
66384
+ const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync72(stateArg.replace(/^@/, ""), "utf8");
65791
66385
  injectedState = JSON.parse(raw);
65792
66386
  } catch (e) {
65793
66387
  io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
@@ -65796,13 +66390,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65796
66390
  }
65797
66391
  let injectedInput;
65798
66392
  if (flags.input !== void 0) {
65799
- const inputArg = str5(flags.input);
66393
+ const inputArg = str6(flags.input);
65800
66394
  if (!inputArg || !inputArg.trim()) {
65801
66395
  io.error(JSON.stringify({ error: "--input was given but empty \u2014 pass inline JSON `{\u2026}` or a path to a .json file" }));
65802
66396
  return 2;
65803
66397
  }
65804
66398
  try {
65805
- const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync71(inputArg.replace(/^@/, ""), "utf8");
66399
+ const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync72(inputArg.replace(/^@/, ""), "utf8");
65806
66400
  const parsed = JSON.parse(raw);
65807
66401
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
65808
66402
  injectedInput = parsed;
@@ -65812,7 +66406,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65812
66406
  }
65813
66407
  }
65814
66408
  const DEVICE_WIDTHS = renderDeviceWidths();
65815
- const deviceName = str5(flags.device);
66409
+ const deviceName = str6(flags.device);
65816
66410
  let renderWidth;
65817
66411
  if (deviceName) {
65818
66412
  renderWidth = DEVICE_WIDTHS[deviceName.toLowerCase()];
@@ -65837,7 +66431,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65837
66431
  } else if (typeof flags.width === "string" && flags.width) {
65838
66432
  renderWidth = Math.round(Number(flags.width));
65839
66433
  if (!Number.isFinite(renderWidth) || renderWidth <= 0) {
65840
- io.error(JSON.stringify({ error: `--width must be a positive number of pixels (got "${str5(flags.width)}")` }));
66434
+ io.error(JSON.stringify({ error: `--width must be a positive number of pixels (got "${str6(flags.width)}")` }));
65841
66435
  return 2;
65842
66436
  }
65843
66437
  }
@@ -65845,13 +66439,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65845
66439
  if (typeof flags["load-budget"] === "string" && flags["load-budget"]) {
65846
66440
  loadBudgetMs = Number(flags["load-budget"]);
65847
66441
  if (!Number.isFinite(loadBudgetMs) || loadBudgetMs <= 0) {
65848
- io.error(JSON.stringify({ error: `--load-budget must be a positive number of ms (got "${str5(flags["load-budget"])}")` }));
66442
+ io.error(JSON.stringify({ error: `--load-budget must be a positive number of ms (got "${str6(flags["load-budget"])}")` }));
65849
66443
  return 2;
65850
66444
  }
65851
66445
  }
65852
66446
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65853
66447
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
65854
- const out = mkdtempSync4(join56(tmpdir5(), "himi-render-"));
66448
+ const out = mkdtempSync4(join57(tmpdir5(), "himi-render-"));
65855
66449
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65856
66450
  const outcome = await buildReleaseFromContent2(dir, out, {
65857
66451
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65865,8 +66459,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65865
66459
  const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
65866
66460
  let pngFile;
65867
66461
  let attestationPngFile;
65868
- const shotPath = join56(dir, ".himi", "shots", `${screenId}.png`);
65869
- const pngTarget = typeof flags.png === "string" ? str5(flags.png) : flags.png === true ? shotPath : void 0;
66462
+ const shotPath = join57(dir, ".himi", "shots", `${screenId}.png`);
66463
+ const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
65870
66464
  if (pngTarget && r.pngBase64) {
65871
66465
  pngFile = writePngFile(pngTarget, r.pngBase64);
65872
66466
  attestationPngFile = resolve47(pngTarget) === resolve47(shotPath) ? pngFile : writePngFile(shotPath, r.pngBase64);
@@ -66047,7 +66641,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
66047
66641
  return report2(res.status, { wrote: res.wrote, normalized: res.normalized, playListingIcon: res.playDerived });
66048
66642
  }
66049
66643
  if (sub === "from-site") {
66050
- const book = str5(flags.book) ?? ".himi/business-book";
66644
+ const book = str6(flags.book) ?? ".himi/business-book";
66051
66645
  const logo = siteBookIcon2(book);
66052
66646
  if (!logo) {
66053
66647
  const absence = siteLogoAbsence2(book);
@@ -66062,7 +66656,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
66062
66656
  return report2(res.status, { from: logo, wrote: res.wrote, normalized: res.normalized, playListingIcon: res.playDerived });
66063
66657
  }
66064
66658
  if (sub === "generate") {
66065
- const res = await generateIcon2(dir, { glyph: str5(flags.glyph), background: str5(flags.accent), derivePlay: true });
66659
+ const res = await generateIcon2(dir, { glyph: str6(flags.glyph), background: str6(flags.accent), derivePlay: true });
66066
66660
  return report2(res.status, { wrote: res.wrote });
66067
66661
  }
66068
66662
  if (sub === "glyphs") {
@@ -66094,8 +66688,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66094
66688
  return report2.ok ? 0 : 1;
66095
66689
  }
66096
66690
  if (sub === "verify") {
66097
- const app = str5(flags.app) ?? await appId(dir);
66098
- const found = await fetchReleaseManifest(client2, app, str5(flags.release));
66691
+ const app = str6(flags.app) ?? await appId(dir);
66692
+ const found = await fetchReleaseManifest(client2, app, str6(flags.release));
66099
66693
  if ("error" in found) {
66100
66694
  io.error(JSON.stringify(found));
66101
66695
  return 1;
@@ -66105,9 +66699,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66105
66699
  return report2.ok ? 0 : 1;
66106
66700
  }
66107
66701
  if (sub === "add" || sub === "rm") {
66108
- const app = str5(flags.app) ?? await appId(dir);
66702
+ const app = str6(flags.app) ?? await appId(dir);
66109
66703
  const { contentReleaseId: contentReleaseId2 } = await Promise.resolve().then(() => (init_build3(), build_exports2));
66110
- const found = await fetchReleaseManifest(client2, app, str5(flags.release));
66704
+ const found = await fetchReleaseManifest(client2, app, str6(flags.release));
66111
66705
  if ("error" in found) {
66112
66706
  io.error(JSON.stringify(found));
66113
66707
  return 1;
@@ -66123,7 +66717,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66123
66717
  io.error(JSON.stringify({ error: "assets add needs a file: himi assets add <file> [--name <logical/name>]" }));
66124
66718
  return 2;
66125
66719
  }
66126
- const { payload, record: record2, name: name2 } = addAssetPayload2(manifest, file, { name: str5(flags.name), mintReleaseId: contentReleaseId2 });
66720
+ const { payload, record: record2, name: name2 } = addAssetPayload2(manifest, file, { name: str6(flags.name), mintReleaseId: contentReleaseId2 });
66127
66721
  const r2 = await client2().publishRelease(payload, {}, flags.live !== true);
66128
66722
  if (!r2.ok) {
66129
66723
  print({ ok: false, status: r2.status, body: r2.json ?? r2.text });
@@ -66192,8 +66786,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66192
66786
  io.error(JSON.stringify({ error: "pull needs an <app>", usage: "himi pull <app> [--release <id>] [--out <dir>] [--name <new>]" }));
66193
66787
  return 2;
66194
66788
  }
66195
- const renamed = str5(flags.name);
66196
- const dest = resolve47(str5(flags.out) ?? process.cwd(), renamed ?? wanted);
66789
+ const renamed = str6(flags.name);
66790
+ const dest = resolve47(str6(flags.out) ?? process.cwd(), renamed ?? wanted);
66197
66791
  const replace = flags.replace === true;
66198
66792
  const force = replace || flags.force === true;
66199
66793
  const linked = symlinkDestinationIssue(dest);
@@ -66214,7 +66808,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66214
66808
  io.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
66215
66809
  return 1;
66216
66810
  }
66217
- if (replace && occupied && !existsSync60(join56(dest, "himalaya.content.json"))) {
66811
+ if (replace && occupied && !existsSync60(join57(dest, "himalaya.content.json"))) {
66218
66812
  io.error(JSON.stringify({
66219
66813
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
66220
66814
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -66222,7 +66816,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66222
66816
  return 1;
66223
66817
  }
66224
66818
  }
66225
- const pulled = await client2().ownerSource(wanted, str5(flags.release));
66819
+ const pulled = await client2().ownerSource(wanted, str6(flags.release));
66226
66820
  if (!pulled.ok) {
66227
66821
  io.error(JSON.stringify({ ok: false, app: wanted, status: pulled.status, ...pulled.json ?? {} }));
66228
66822
  return 1;
@@ -66295,7 +66889,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66295
66889
  const declared = await appId(dir);
66296
66890
  let onlyRaw;
66297
66891
  if (flags.only !== void 0) {
66298
- onlyRaw = str5(flags.only);
66892
+ onlyRaw = str6(flags.only);
66299
66893
  if (!onlyRaw) {
66300
66894
  io.error(JSON.stringify({ error: "--only needs a selector", usage: ONLY_USAGE }));
66301
66895
  return 2;
@@ -66317,7 +66911,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66317
66911
  return 2;
66318
66912
  }
66319
66913
  }
66320
- if (flags["from-release"] !== void 0 && !str5(flags["from-release"])) {
66914
+ if (flags["from-release"] !== void 0 && !str6(flags["from-release"])) {
66321
66915
  io.error(JSON.stringify({ ok: false, error: "from_release_needs_a_value", message: "--from-release takes a release id to branch from. Omit the flag entirely to patch the live release.", usage: ONLY_USAGE }));
66322
66916
  return 2;
66323
66917
  }
@@ -66327,7 +66921,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66327
66921
  let ownerIssue;
66328
66922
  let pushToken;
66329
66923
  try {
66330
- const t = resolveTarget({ target: pushTarget, controlToken: str5(flags["control-token"]) });
66924
+ const t = resolveTarget({ target: pushTarget, controlToken: str6(flags["control-token"]) });
66331
66925
  ownerIssue = t.ownerIssue;
66332
66926
  pushToken = t.controlToken;
66333
66927
  } catch {
@@ -66353,7 +66947,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66353
66947
  const force = flags.force === true;
66354
66948
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
66355
66949
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
66356
- const out = mkdtempSync4(join56(tmpdir5(), "himi-push-"));
66950
+ const out = mkdtempSync4(join57(tmpdir5(), "himi-push-"));
66357
66951
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
66358
66952
  const outcome = await buildReleaseFromContent2(dir, out, {
66359
66953
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -66392,7 +66986,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66392
66986
  io.error(JSON.stringify(parsed.error, null, 2));
66393
66987
  return 2;
66394
66988
  }
66395
- const fromRelease = str5(flags["from-release"]);
66989
+ const fromRelease = str6(flags["from-release"]);
66396
66990
  const baseForPlan = await fetchReleaseManifest(client2, app, fromRelease);
66397
66991
  if ("error" in baseForPlan) {
66398
66992
  io.error(JSON.stringify(baseForPlan));
@@ -66441,7 +67035,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66441
67035
  let localSourceHash;
66442
67036
  try {
66443
67037
  const { collectAppSource: collectAppSource2, zipAppSource: zipAppSource2 } = await Promise.resolve().then(() => (init_app_source(), app_source_exports));
66444
- localSourceHash = createHash26("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
67038
+ localSourceHash = createHash27("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
66445
67039
  } catch {
66446
67040
  }
66447
67041
  return runReleasePatch({
@@ -66460,8 +67054,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66460
67054
  acceptPartial: flags["accept-partial"] === true,
66461
67055
  force,
66462
67056
  meta: {
66463
- ...str5(flags.label) ? { label: str5(flags.label) } : {},
66464
- ...str5(flags.notes) ? { notes: str5(flags.notes) } : {},
67057
+ ...str6(flags.label) ? { label: str6(flags.label) } : {},
67058
+ ...str6(flags.notes) ? { notes: str6(flags.notes) } : {},
66465
67059
  ...hasErrors ? { forcedPastErrors: true } : {}
66466
67060
  },
66467
67061
  ...localSourceHash ? { localSourceHash } : {},
@@ -66581,8 +67175,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66581
67175
  if (!visArg) return 2;
66582
67176
  const visibility = visArg.value ?? await contentVisibility(dir);
66583
67177
  const meta = {
66584
- ...str5(flags.label) ? { label: str5(flags.label) } : {},
66585
- ...str5(flags.notes) ? { notes: str5(flags.notes) } : {},
67178
+ ...str6(flags.label) ? { label: str6(flags.label) } : {},
67179
+ ...str6(flags.notes) ? { notes: str6(flags.notes) } : {},
66586
67180
  ...visibility ? { visibility } : {},
66587
67181
  ...attestation ? { attestation } : {},
66588
67182
  ...forcedPastErrors ? { forcedPastErrors: true } : {}
@@ -66614,7 +67208,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66614
67208
  let adoptedSlug;
66615
67209
  if (flags["no-claim"] !== true) {
66616
67210
  if (ownerIssue && pushToken && !tokenCoversApp(pushToken, app)) {
66617
- const claim = await autoClaimSlug({ ownerIssue, controlToken: pushToken, app, accountId: str5(flags["account-id"]) });
67211
+ const claim = await autoClaimSlug({ ownerIssue, controlToken: pushToken, app, accountId: str6(flags["account-id"]) });
66618
67212
  if (claim.fatal) {
66619
67213
  io.error(JSON.stringify({
66620
67214
  ok: false,
@@ -66791,7 +67385,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66791
67385
  // goes. `push` hands it to a serve plane, `pack` hands it to a FILE, so an app can
66792
67386
  // be emailed, dropped on a static host, or opened from Files with no serve at all.
66793
67387
  case "pack": {
66794
- const format = str5(flags.format) ?? "zip";
67388
+ const format = str6(flags.format) ?? "zip";
66795
67389
  if (format !== "zip" && format !== "dir") {
66796
67390
  io.error(JSON.stringify({ error: `unknown --format ${JSON.stringify(format)}`, formats: ["zip", "dir"] }));
66797
67391
  return 2;
@@ -66806,13 +67400,13 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66806
67400
  return 2;
66807
67401
  }
66808
67402
  const { packRelease: packRelease2, packReleaseToDir: packReleaseToDir2 } = await Promise.resolve().then(() => (init_pack(), pack_exports));
66809
- const displayName = str5(flags.name);
67403
+ const displayName = str6(flags.name);
66810
67404
  const launchMode = flags.snapshot === true ? "snapshot" : "live";
66811
67405
  const packOpts = { createdBy: `himi-cli ${cliVersion()}`, launchMode, ...displayName ? { displayName } : {} };
66812
67406
  const writePack = (root, appName, out, source) => format === "dir" ? packReleaseToDir2(root, appName, out, packOpts) : packRelease2(root, appName, out, { ...packOpts, ...source ? { source } : {} });
66813
- const releaseDir = str5(flags["release-dir"]);
67407
+ const releaseDir = str6(flags["release-dir"]);
66814
67408
  if (releaseDir) {
66815
- const only = str5(flags.app);
67409
+ const only = str6(flags.app);
66816
67410
  if (!only) {
66817
67411
  io.error(JSON.stringify({ error: "--release-dir needs --app (a release store holds many apps)" }));
66818
67412
  return 2;
@@ -66825,7 +67419,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66825
67419
  return 2;
66826
67420
  }
66827
67421
  try {
66828
- const res = writePack(resolve47(releaseDir), only, resolve47(str5(flags.out) ?? process.cwd()));
67422
+ const res = writePack(resolve47(releaseDir), only, resolve47(str6(flags.out) ?? process.cwd()));
66829
67423
  print({
66830
67424
  ok: true,
66831
67425
  app: res.app,
@@ -66874,7 +67468,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66874
67468
  }
66875
67469
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
66876
67470
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
66877
- const built = mkdtempSync4(join56(tmpdir5(), "himi-pack-"));
67471
+ const built = mkdtempSync4(join57(tmpdir5(), "himi-pack-"));
66878
67472
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
66879
67473
  const outcome = await buildReleaseFromContent2(dir, built, {
66880
67474
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -66896,7 +67490,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66896
67490
  return 1;
66897
67491
  }
66898
67492
  try {
66899
- const res = writePack(built, app, resolve47(str5(flags.out) ?? dir), sourceArchive);
67493
+ const res = writePack(built, app, resolve47(str6(flags.out) ?? dir), sourceArchive);
66900
67494
  print({
66901
67495
  ok: true,
66902
67496
  app: res.app,
@@ -66964,7 +67558,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66964
67558
  io.error(JSON.stringify({ ok: false, error: "app_source_not_in_package", detail: `${HIMI_PACKAGE_SOURCE_PATH2} is absent despite the header declaring it` }));
66965
67559
  return 1;
66966
67560
  }
66967
- const renamed = str5(flags.name);
67561
+ const renamed = str6(flags.name);
66968
67562
  const idsToCheck = renamed ? [["--name", renamed]] : [["package", opened.header.app]];
66969
67563
  for (const [what, value] of idsToCheck) {
66970
67564
  if (!isSafeAppId2(value)) {
@@ -66977,7 +67571,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66977
67571
  return 1;
66978
67572
  }
66979
67573
  }
66980
- const dest = resolve47(str5(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
67574
+ const dest = resolve47(str6(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
66981
67575
  const issue2 = restoreDestinationIssue(dest, flags.force === true);
66982
67576
  if (issue2) {
66983
67577
  io.error(JSON.stringify(issue2));
@@ -67041,7 +67635,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67041
67635
  case "share": {
67042
67636
  const sub = pos[1];
67043
67637
  if (sub === "revoke") {
67044
- const app = str5(flags.app);
67638
+ const app = str6(flags.app);
67045
67639
  const shareId = pos[2];
67046
67640
  if (!app || !shareId) {
67047
67641
  io.error(JSON.stringify({ error: "himi share revoke needs --app <app> <shareId>" }));
@@ -67055,7 +67649,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67055
67649
  print({ ok: true, ...result.json });
67056
67650
  return 0;
67057
67651
  }
67058
- const file = str5(flags.file);
67652
+ const file = str6(flags.file);
67059
67653
  if (!file) {
67060
67654
  io.error(JSON.stringify({ error: "himi share needs --file <package.himi>; create it with `himi pack --out <file>`" }));
67061
67655
  return 2;
@@ -67077,13 +67671,13 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67077
67671
  }));
67078
67672
  return 1;
67079
67673
  }
67080
- const archive = readFileSync71(resolve47(file));
67674
+ const archive = readFileSync72(resolve47(file));
67081
67675
  const result = await client2().createPackageShare({
67082
67676
  app: opened.header.app,
67083
67677
  releaseId: opened.header.releaseId,
67084
67678
  launchMode: opened.header.launchMode ?? "snapshot",
67085
67679
  archiveBase64: archive.toString("base64"),
67086
- ...str5(flags["expires-at"]) ? { expiresAt: str5(flags["expires-at"]) } : {}
67680
+ ...str6(flags["expires-at"]) ? { expiresAt: str6(flags["expires-at"]) } : {}
67087
67681
  });
67088
67682
  if (!result.ok) {
67089
67683
  print({ ok: false, status: result.status, body: result.json ?? result.text });
@@ -67116,7 +67710,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67116
67710
  flags.content = watchedDir;
67117
67711
  source = void 0;
67118
67712
  }
67119
- const conflict = watchFlagConflict2({ source, browser: flags.browser === true, spa: str5(flags.spa) });
67713
+ const conflict = watchFlagConflict2({ source, browser: flags.browser === true, spa: str6(flags.spa) });
67120
67714
  if (conflict) {
67121
67715
  io.error(JSON.stringify({ ok: false, ...conflict }));
67122
67716
  return 2;
@@ -67124,31 +67718,62 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67124
67718
  }
67125
67719
  let served = null;
67126
67720
  let servedMissing = [];
67721
+ const fromContent = !source;
67127
67722
  try {
67128
67723
  if (!source) {
67129
67724
  const dir2 = contentDir(flags);
67130
67725
  const app = await appId(dir2);
67131
67726
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
67132
67727
  const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
67133
- temp = mkdtempSync4(join56(tmpdir5(), "himi-run-build-"));
67728
+ temp = mkdtempSync4(join57(tmpdir5(), "himi-run-build-"));
67134
67729
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
67135
67730
  const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
67136
67731
  servedMissing = initial.missingBundles;
67137
- source = join56(temp, app);
67732
+ source = join57(temp, app);
67138
67733
  }
67139
- const chromeArg = str5(flags.chrome) ?? "preview";
67734
+ const chromeArg = str6(flags.chrome) ?? "preview";
67140
67735
  if (chromeArg !== "preview" && chromeArg !== "app") {
67141
67736
  io.error(JSON.stringify({ error: `unknown --chrome ${JSON.stringify(chromeArg)}`, values: ["preview", "app"] }));
67142
67737
  return 2;
67143
67738
  }
67144
67739
  let port;
67145
67740
  if (flags.port !== void 0) {
67146
- port = Number(str5(flags.port));
67741
+ port = Number(str6(flags.port));
67147
67742
  if (!Number.isInteger(port) || port < 0 || port > 65535) {
67148
- io.error(JSON.stringify({ error: `--port needs a number 0-65535, got ${JSON.stringify(str5(flags.port) ?? "")}` }));
67743
+ io.error(JSON.stringify({ error: `--port needs a number 0-65535, got ${JSON.stringify(str6(flags.port) ?? "")}` }));
67149
67744
  return 2;
67150
67745
  }
67151
67746
  }
67747
+ const dir = contentDir(flags);
67748
+ const refreshBoard = async () => {
67749
+ if (!boardOpen(dir)) return;
67750
+ const { refreshStudio: refreshStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
67751
+ refreshStudio2(dir);
67752
+ };
67753
+ const recordKit = fromContent ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
67754
+ let recorded = false;
67755
+ let startedAt = "";
67756
+ const record2 = (served2, build2) => {
67757
+ try {
67758
+ if (recordKit?.writeRunRecord(dir, { url: served2.url, port: served2.port, pid: process.pid, startedAt, watching: watch2, build: build2 })) recorded = true;
67759
+ return null;
67760
+ } catch (e) {
67761
+ return e.message;
67762
+ }
67763
+ };
67764
+ const announce = async (served2) => {
67765
+ if (!recordKit) return;
67766
+ startedAt = (/* @__PURE__ */ new Date()).toISOString();
67767
+ const failure = record2(served2, { ok: true, at: startedAt });
67768
+ if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join57(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
67769
+ await refreshBoard();
67770
+ };
67771
+ const retract = async () => {
67772
+ if (!recorded) return;
67773
+ recorded = false;
67774
+ recordKit?.removeRunRecord(dir, process.pid);
67775
+ await refreshBoard();
67776
+ };
67152
67777
  if (flags.browser === true) {
67153
67778
  const { runInBrowser: runInBrowser2 } = await Promise.resolve().then(() => (init_run_browser(), run_browser_exports));
67154
67779
  const { resolvePackage: resolvePackage2 } = await Promise.resolve().then(() => (init_run(), run_exports));
@@ -67158,61 +67783,51 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67158
67783
  chrome: chromeArg,
67159
67784
  open: flags["no-open"] !== true
67160
67785
  });
67786
+ await announce(run2);
67161
67787
  print({ ok: true, app: run2.app, url: run2.url, port: run2.port, plane: "browser" });
67162
67788
  await new Promise((resolve48) => {
67163
67789
  const stop = () => {
67164
- void run2.close().finally(() => resolve48());
67790
+ void retract().catch((e) => io.error(JSON.stringify({ run: "stop_cleanup_failed", message: e.message }))).finally(() => run2.close().finally(() => resolve48()));
67165
67791
  };
67166
67792
  process.once("SIGINT", stop);
67167
67793
  process.once("SIGTERM", stop);
67168
67794
  });
67169
67795
  return 0;
67170
67796
  }
67171
- const dir = contentDir(flags);
67172
67797
  const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
67173
67798
  const bus = watchKit ? new watchKit.ReloadBus() : void 0;
67174
- if (watch2) served = mkdtempSync4(join56(tmpdir5(), "himi-run-served-"));
67799
+ if (watch2) served = mkdtempSync4(join57(tmpdir5(), "himi-run-served-"));
67175
67800
  const running = await runPackage2(source, {
67176
67801
  port,
67177
67802
  chrome: chromeArg,
67178
- screen: str5(flags.screen),
67179
- surface: str5(flags.surface),
67180
- spa: str5(flags.spa),
67803
+ screen: str6(flags.screen),
67804
+ surface: str6(flags.surface),
67805
+ spa: str6(flags.spa),
67181
67806
  open: flags["no-open"] !== true,
67182
- ...watchKit && served && bus ? { workDir: served, screenEvents: bus, extraRoutes: (request) => watchKit.boardFile(dir, new URL(request.url).pathname) } : {}
67807
+ // The build board on the preview's own origin, for any run of this content package.
67808
+ ...recordKit ? { extraRoutes: (request) => recordKit.boardFile(dir, new URL(request.url).pathname) } : {},
67809
+ ...watchKit && served && bus ? { workDir: served, screenEvents: bus } : {}
67183
67810
  });
67184
67811
  let watcher;
67185
67812
  let rebuild;
67186
- let recorded = false;
67187
67813
  let stopping = false;
67188
- const refreshBoard = async () => {
67189
- if (!boardOpen(dir)) return;
67190
- const { refreshStudio: refreshStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
67191
- refreshStudio2(dir);
67192
- };
67193
- if (watchKit && bus) {
67194
- try {
67195
- const startedAt = (/* @__PURE__ */ new Date()).toISOString();
67196
- const record2 = (build2) => {
67197
- if (watchKit.writeRunRecord(dir, { url: running.url, port: running.port, pid: process.pid, startedAt, build: build2 })) recorded = true;
67198
- };
67199
- record2({ ok: true, at: startedAt });
67200
- if (!recorded) io.error(JSON.stringify({ watch: "run_record_skipped", message: `${join56(dir, ".himi")} is not a real directory, so the build board will not frame this preview.` }));
67201
- await refreshBoard();
67814
+ try {
67815
+ await announce(running);
67816
+ if (watchKit && bus) {
67202
67817
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
67203
- const live2 = join56(running.releaseRoot, running.app);
67204
- const manifestOf = (tree) => JSON.parse(readFileSync71(join56(tree, "release-manifest.json"), "utf8"));
67818
+ const live2 = join57(running.releaseRoot, running.app);
67819
+ const manifestOf = (tree) => JSON.parse(readFileSync72(join57(tree, "release-manifest.json"), "utf8"));
67205
67820
  let current = manifestOf(live2);
67206
67821
  const failed2 = async (message) => {
67207
67822
  if (stopping) return;
67208
67823
  bus.publish("build.failed", { message });
67209
- record2({ ok: false, at: (/* @__PURE__ */ new Date()).toISOString(), error: message });
67824
+ record2(running, { ok: false, at: (/* @__PURE__ */ new Date()).toISOString(), error: message });
67210
67825
  await refreshBoard();
67211
67826
  io.error(JSON.stringify({ watch: "build_failed", keptLastGood: true, message }));
67212
67827
  };
67213
67828
  rebuild = watchKit.serialize(async () => {
67214
67829
  const t0 = Date.now();
67215
- const next = mkdtempSync4(join56(tmpdir5(), "himi-run-build-"));
67830
+ const next = mkdtempSync4(join57(tmpdir5(), "himi-run-build-"));
67216
67831
  try {
67217
67832
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
67218
67833
  if (bres.compileErrors.length) {
@@ -67229,20 +67844,20 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67229
67844
  return;
67230
67845
  }
67231
67846
  if (stopping) return;
67232
- const fresh = manifestOf(join56(next, running.app));
67847
+ const fresh = manifestOf(join57(next, running.app));
67233
67848
  const diff = watchKit.diffReleases(current, fresh);
67234
67849
  const retired = `${live2}.retired-${Date.now()}`;
67235
67850
  renameSync6(live2, retired);
67236
67851
  try {
67237
- renameSync6(join56(next, running.app), live2);
67852
+ renameSync6(join57(next, running.app), live2);
67238
67853
  } catch {
67239
- cpSync3(join56(next, running.app), live2, { recursive: true });
67854
+ cpSync3(join57(next, running.app), live2, { recursive: true });
67240
67855
  }
67241
67856
  rmSync13(retired, { recursive: true, force: true });
67242
67857
  current = fresh;
67243
67858
  servedMissing = outcome.missingBundles;
67244
67859
  for (const [event, data] of watchKit.reloadEvents(diff)) bus.publish(event, data);
67245
- record2({ ok: true, at: (/* @__PURE__ */ new Date()).toISOString() });
67860
+ record2(running, { ok: true, at: (/* @__PURE__ */ new Date()).toISOString() });
67246
67861
  await refreshBoard();
67247
67862
  io.error(JSON.stringify({ watch: "rebuilt", ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config, tabs: bus.listeners }));
67248
67863
  } catch (e) {
@@ -67252,11 +67867,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67252
67867
  }
67253
67868
  });
67254
67869
  watcher = watchKit.watchContent(dir, () => rebuild?.());
67255
- } catch (e) {
67256
- if (recorded) watchKit.removeRunRecord(dir);
67257
- await running.close();
67258
- throw e;
67259
67870
  }
67871
+ } catch (e) {
67872
+ await retract().catch(() => {
67873
+ });
67874
+ await running.close();
67875
+ throw e;
67260
67876
  }
67261
67877
  print({
67262
67878
  ok: true,
@@ -67264,7 +67880,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67264
67880
  releaseId: running.releaseId,
67265
67881
  url: running.url,
67266
67882
  port: running.port,
67267
- ...watch2 ? { watching: dir, ...boardOpen(dir) ? { board: `${running.origin}/__himi/studio/` } : {} } : {},
67883
+ ...watch2 ? { watching: dir } : {},
67884
+ ...recordKit && boardOpen(dir) ? { board: `${running.origin}/__himi/studio/` } : {},
67268
67885
  ...running.warnings.length ? { warnings: running.warnings } : {},
67269
67886
  stop: "Ctrl-C"
67270
67887
  });
@@ -67274,12 +67891,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67274
67891
  watcher?.close();
67275
67892
  try {
67276
67893
  await rebuild?.stop();
67277
- if (recorded) {
67278
- watchKit?.removeRunRecord(dir);
67279
- await refreshBoard();
67280
- }
67894
+ await retract();
67281
67895
  } catch (e) {
67282
- io.error(JSON.stringify({ watch: "stop_cleanup_failed", message: e.message }));
67896
+ io.error(JSON.stringify({ run: "stop_cleanup_failed", message: e.message }));
67283
67897
  } finally {
67284
67898
  await running.close();
67285
67899
  done();
@@ -67298,15 +67912,15 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67298
67912
  }
67299
67913
  }
67300
67914
  case "preview": {
67301
- const app = str5(flags.app);
67302
- const release = str5(flags.release);
67915
+ const app = str6(flags.app);
67916
+ const release = str6(flags.release);
67303
67917
  if (!app || !release) {
67304
67918
  io.error(JSON.stringify({ error: "preview needs --app and --release" }));
67305
67919
  return 2;
67306
67920
  }
67307
67921
  const base = serveBase();
67308
- const screen = str5(flags.screen);
67309
- const surface = str5(flags.surface);
67922
+ const screen = str6(flags.screen);
67923
+ const surface = str6(flags.surface);
67310
67924
  if (surface && !surfaceById(surface)) {
67311
67925
  io.error(JSON.stringify({
67312
67926
  error: `unknown --surface "${surface}"`,
@@ -67314,22 +67928,22 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67314
67928
  }));
67315
67929
  return 2;
67316
67930
  }
67317
- let previewToken = str5(flags["preview-token"]);
67931
+ let previewToken = str6(flags["preview-token"]);
67318
67932
  let previewTokenExpiresAt;
67319
67933
  let previewHandover;
67320
67934
  let mintedHere = false;
67321
67935
  let mintFailure;
67322
67936
  if (!previewToken) {
67323
67937
  const target = resolveTarget({
67324
- target: str5(flags.target),
67938
+ target: str6(flags.target),
67325
67939
  // Same default as `client()` (#2483.1) — without it this resolved a DIFFERENT target
67326
67940
  // than the request that follows, so off-repo the mint was attempted against `local`.
67327
67941
  defaultTarget: contextualDefaultTarget,
67328
- serveUrl: str5(flags["serve-url"]),
67329
- telemetryUrl: str5(flags["telemetry-url"]),
67330
- controlUrl: str5(flags["control-url"]),
67331
- telemetryToken: str5(flags["telemetry-token"]),
67332
- controlToken: str5(flags["control-token"])
67942
+ serveUrl: str6(flags["serve-url"]),
67943
+ telemetryUrl: str6(flags["telemetry-url"]),
67944
+ controlUrl: str6(flags["control-url"]),
67945
+ telemetryToken: str6(flags["telemetry-token"]),
67946
+ controlToken: str6(flags["control-token"])
67333
67947
  });
67334
67948
  if (!target.controlToken) {
67335
67949
  mintFailure = `this target has no stored control credential, so none was requested \u2014 run \`himi login --target ${targetName()}\`, or pass --control-token`;
@@ -67390,8 +68004,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67390
68004
  case "surfaces": {
67391
68005
  const dir = contentDir(flags);
67392
68006
  const platforms = readLocalPlatforms(dir);
67393
- const app = str5(flags.app);
67394
- const release = str5(flags.release);
68007
+ const app = str6(flags.app);
68008
+ const release = str6(flags.release);
67395
68009
  const base = serveBase();
67396
68010
  const withLinks = !!(app && release && base);
67397
68011
  const produced = flags["measure-widgets"] === true ? await producedWidgetFamilies(dir) : { families: void 0, source: "not-measured" };
@@ -67443,16 +68057,16 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67443
68057
  return 0;
67444
68058
  }
67445
68059
  case "context": {
67446
- const app = str5(flags.app);
67447
- const release = str5(flags.release);
68060
+ const app = str6(flags.app);
68061
+ const release = str6(flags.release);
67448
68062
  if (!app || !release) {
67449
68063
  io.error(JSON.stringify({ error: "context needs --app and --release" }));
67450
68064
  return 2;
67451
68065
  }
67452
- const include = str5(flags.include);
68066
+ const include = str6(flags.include);
67453
68067
  let r;
67454
68068
  try {
67455
- r = await client2().previewContext(app, release, { screen: str5(flags.screen), include });
68069
+ r = await client2().previewContext(app, release, { screen: str6(flags.screen), include });
67456
68070
  } catch (e) {
67457
68071
  io.error(JSON.stringify({
67458
68072
  error: `cannot reach serve for context: ${e.message}. Pass --target bo.`,
@@ -67467,8 +68081,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67467
68081
  }
67468
68082
  case "app-docs": {
67469
68083
  const subcommand = pos[1] ?? "list";
67470
- const app = str5(flags.app);
67471
- const release = str5(flags.release) ?? str5(flags.releaseId);
68084
+ const app = str6(flags.app);
68085
+ const release = str6(flags.release) ?? str6(flags.releaseId);
67472
68086
  if (!app) {
67473
68087
  io.error(JSON.stringify({ error: "app-docs needs --app" }));
67474
68088
  return 2;
@@ -67496,15 +68110,15 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67496
68110
  return 0;
67497
68111
  }
67498
68112
  case "telemetry": {
67499
- const app = str5(flags.app);
67500
- const release = str5(flags.release) ?? str5(flags.releaseId);
68113
+ const app = str6(flags.app);
68114
+ const release = str6(flags.release) ?? str6(flags.releaseId);
67501
68115
  if (!app || !release) {
67502
68116
  io.error(JSON.stringify({ error: "telemetry needs --app and --release" }));
67503
68117
  return 2;
67504
68118
  }
67505
68119
  const c = client2();
67506
68120
  const target = targetName();
67507
- const level = str5(flags.level);
68121
+ const level = str6(flags.level);
67508
68122
  const byLevel = (ls) => level ? ls.filter((l) => l.level === level) : ls;
67509
68123
  const includeEvents = flags["no-events"] !== true;
67510
68124
  const includeLogs = flags["no-logs"] !== true;
@@ -67519,8 +68133,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67519
68133
  if (includeEvents) {
67520
68134
  const r = await c.telemetryEvents(app, {
67521
68135
  releaseId: release,
67522
- screenId: str5(flags.screen) ?? str5(flags.screenId),
67523
- event: str5(flags.type) ?? str5(flags.event),
68136
+ screenId: str6(flags.screen) ?? str6(flags.screenId),
68137
+ event: str6(flags.type) ?? str6(flags.event),
67524
68138
  since: eventSince,
67525
68139
  limit: num2(flags.limit),
67526
68140
  crashesOnly: flags["crashes-only"] === true || flags.crashesOnly === true
@@ -67533,7 +68147,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67533
68147
  if (includeLogs) {
67534
68148
  const r = await c.telemetryLogs(app, {
67535
68149
  releaseId: release,
67536
- screenId: str5(flags.screen) ?? str5(flags.screenId),
68150
+ screenId: str6(flags.screen) ?? str6(flags.screenId),
67537
68151
  since: logSince,
67538
68152
  limit: num2(flags.limit)
67539
68153
  });
@@ -67555,7 +68169,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67555
68169
  }
67556
68170
  const eventCount = out.events?.length ?? 0;
67557
68171
  const logCount = out.logs?.length ?? 0;
67558
- const narrowed = !!(level || str5(flags.screen) || str5(flags.screenId) || str5(flags.type) || str5(flags.event) || flags["crashes-only"] === true || flags.crashesOnly === true || num2(flags.limit) !== void 0 || eventSince !== void 0 || logSince !== void 0);
68172
+ const narrowed = !!(level || str6(flags.screen) || str6(flags.screenId) || str6(flags.type) || str6(flags.event) || flags["crashes-only"] === true || flags.crashesOnly === true || num2(flags.limit) !== void 0 || eventSince !== void 0 || logSince !== void 0);
67559
68173
  const wholeChannels = includeEvents && includeLogs && !narrowed;
67560
68174
  if (wholeChannels && eventCount === 0 && logCount === 0 && !includeSummary && !includeCrashes) {
67561
68175
  out.note = "no events and no worker console output on this release \u2014 open the web preview or Himi Player link for it, then retry or use --follow";
@@ -67599,8 +68213,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67599
68213
  }
67600
68214
  }
67601
68215
  case "screens": {
67602
- const app = str5(flags.app);
67603
- const release = str5(flags.release);
68216
+ const app = str6(flags.app);
68217
+ const release = str6(flags.release);
67604
68218
  if (!app || !release) {
67605
68219
  io.error(JSON.stringify({ error: "screens needs --app and --release" }));
67606
68220
  return 2;
@@ -67621,8 +68235,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67621
68235
  }
67622
68236
  case "diagnose": {
67623
68237
  const screenId = pos[1];
67624
- const app = str5(flags.app);
67625
- const release = str5(flags.release);
68238
+ const app = str6(flags.app);
68239
+ const release = str6(flags.release);
67626
68240
  if (!screenId || !app || !release) {
67627
68241
  io.error(JSON.stringify({ error: "diagnose needs <screenId> --app --release" }));
67628
68242
  return 2;
@@ -67647,8 +68261,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67647
68261
  return body.ok === false ? 1 : 0;
67648
68262
  }
67649
68263
  case "deeplinks": {
67650
- const app = str5(flags.app);
67651
- const release = str5(flags.release);
68264
+ const app = str6(flags.app);
68265
+ const release = str6(flags.release);
67652
68266
  if (!app || !release) {
67653
68267
  io.error(JSON.stringify({ error: "deeplinks needs --app and --release" }));
67654
68268
  return 2;
@@ -67668,13 +68282,13 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67668
68282
  return 0;
67669
68283
  }
67670
68284
  case "logs": {
67671
- const app = str5(flags.app);
68285
+ const app = str6(flags.app);
67672
68286
  if (!app) {
67673
68287
  io.error(JSON.stringify({ error: "logs needs --app" }));
67674
68288
  return 2;
67675
68289
  }
67676
- const release = str5(flags.release);
67677
- const level = str5(flags.level);
68290
+ const release = str6(flags.release);
68291
+ const level = str6(flags.level);
67678
68292
  const byLevel = (ls) => level ? ls.filter((l) => l.level === level) : ls;
67679
68293
  const num3 = (v) => typeof v === "string" && v ? Number(v) : void 0;
67680
68294
  const c = client2();
@@ -67683,7 +68297,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67683
68297
  try {
67684
68298
  r = await c.telemetryLogs(app, {
67685
68299
  releaseId: release,
67686
- screenId: str5(flags.screen) ?? str5(flags.screenId),
68300
+ screenId: str6(flags.screen) ?? str6(flags.screenId),
67687
68301
  since: num3(flags.since),
67688
68302
  limit: num3(flags.limit)
67689
68303
  });
@@ -67701,7 +68315,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67701
68315
  }
67702
68316
  const rawLogs = r.json?.logs ?? [];
67703
68317
  const logs = byLevel(rawLogs);
67704
- const narrowed = !!(level || str5(flags.screen) || str5(flags.screenId) || num3(flags.since) !== void 0 || num3(flags.limit) !== void 0);
68318
+ const narrowed = !!(level || str6(flags.screen) || str6(flags.screenId) || num3(flags.since) !== void 0 || num3(flags.limit) !== void 0);
67705
68319
  const scope = release ? "this release" : "this app";
67706
68320
  const note = logs.length > 0 ? void 0 : narrowed ? `no worker \`console.*\` lines matched this query${level && rawLogs.length ? ` (${rawLogs.length} line(s) were hidden by --level ${level})` : ""}. Drop --level/--screen/--since/--limit to see the whole console channel for ${scope}; the telemetry EVENT stream is a separate channel, read with \`himi telemetry\`.` : `no worker \`console.*\` output on ${scope}. This is the console channel \u2014 distinct from the telemetry EVENT stream, which \`himi telemetry --app <app> --release <id>\` reads: ${scope} can carry many events and no console lines \u2014 commonly because the worker never logged any, though an empty channel can also mean the lines aged out or never made it through ingestion. Boot-time \`console.log\` is visible via \`himi validate\` / \`himi render\`.`;
67707
68321
  print({ ok: true, logs, ...note ? { note } : {} });
@@ -67711,7 +68325,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67711
68325
  const deadline = num3(flags.for) !== void 0 ? Date.now() + num3(flags.for) : Infinity;
67712
68326
  let since = num3(flags.since) ?? 0;
67713
68327
  for (; ; ) {
67714
- const r = await c.telemetryLogs(app, { releaseId: release, screenId: str5(flags.screen) ?? str5(flags.screenId), since });
68328
+ const r = await c.telemetryLogs(app, { releaseId: release, screenId: str6(flags.screen) ?? str6(flags.screenId), since });
67715
68329
  if (r.ok) {
67716
68330
  const logs = r.json?.logs ?? [];
67717
68331
  for (const l of byLevel(logs)) io.log(JSON.stringify(l));
@@ -67722,8 +68336,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67722
68336
  }
67723
68337
  }
67724
68338
  case "promote": {
67725
- const app = str5(flags.app);
67726
- const release = str5(flags.release);
68339
+ const app = str6(flags.app);
68340
+ const release = str6(flags.release);
67727
68341
  if (!app || !release) {
67728
68342
  io.error(JSON.stringify({ error: "promote needs --app and --release" }));
67729
68343
  return 2;
@@ -67731,7 +68345,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67731
68345
  const target = targetName();
67732
68346
  const force = flags.force === true;
67733
68347
  const ringGiven = flags.ring !== void 0;
67734
- const ring = str5(flags.ring);
68348
+ const ring = str6(flags.ring);
67735
68349
  if (ringGiven && !ring) {
67736
68350
  io.error(JSON.stringify({ error: "--ring needs a ring name, e.g. --ring ga" }));
67737
68351
  return 2;
@@ -67829,8 +68443,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67829
68443
  }));
67830
68444
  return 2;
67831
68445
  }
67832
- const app = str5(flags.app) ?? await appId(contentDir(flags));
67833
- const file = str5(flags.file);
68446
+ const app = str6(flags.app) ?? await appId(contentDir(flags));
68447
+ const file = str6(flags.file);
67834
68448
  if (!file) {
67835
68449
  io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
67836
68450
  return 2;
@@ -67841,7 +68455,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67841
68455
  }
67842
68456
  const draft = patchBlastRadius(PATCH_USAGE);
67843
68457
  if (draft === null) return 2;
67844
- const notes = str5(flags.notes);
68458
+ const notes = str6(flags.notes);
67845
68459
  if (!draft && (kind === "screen" || kind === "app-config") && !notes) {
67846
68460
  io.error(JSON.stringify({
67847
68461
  ok: false,
@@ -67852,11 +68466,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67852
68466
  }));
67853
68467
  return 2;
67854
68468
  }
67855
- if (flags["from-release"] !== void 0 && !str5(flags["from-release"])) {
68469
+ if (flags["from-release"] !== void 0 && !str6(flags["from-release"])) {
67856
68470
  io.error(JSON.stringify({ ok: false, error: "from_release_needs_a_value", message: "--from-release takes a release id to branch from. Omit the flag entirely to patch the live release.", usage: PATCH_USAGE }));
67857
68471
  return 2;
67858
68472
  }
67859
- const fromRelease = str5(flags["from-release"]);
68473
+ const fromRelease = str6(flags["from-release"]);
67860
68474
  const baseOrRefuse = (manifest) => {
67861
68475
  if (manifest) return true;
67862
68476
  io.error(JSON.stringify({
@@ -67874,7 +68488,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67874
68488
  const patchGitSha = defaultGitOps2(contentDir(flags)).shortSha() ?? "dev";
67875
68489
  const meta = {
67876
68490
  gitSha: patchGitSha,
67877
- ...str5(flags.label) ? { label: str5(flags.label) } : {},
68491
+ ...str6(flags.label) ? { label: str6(flags.label) } : {},
67878
68492
  ...notes ? { notes } : {}
67879
68493
  };
67880
68494
  const common = {
@@ -67891,7 +68505,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67891
68505
  lintNote: "`himi patch` sends a raw file. Nothing here built or linted your app \u2014 `himi push --only <selector>` is the same edit with the full lint gate in front of it."
67892
68506
  };
67893
68507
  if (kind === "tokens" || kind === "app-config") {
67894
- const body = readFileSync71(file, "utf8");
68508
+ const body = readFileSync72(file, "utf8");
67895
68509
  const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
67896
68510
  return runReleasePatch({
67897
68511
  ...common,
@@ -67906,7 +68520,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67906
68520
  io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
67907
68521
  return 2;
67908
68522
  }
67909
- const descriptor = readFileSync71(file, "utf8");
68523
+ const descriptor = readFileSync72(file, "utf8");
67910
68524
  try {
67911
68525
  JSON.parse(descriptor);
67912
68526
  } catch (e) {
@@ -67935,7 +68549,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67935
68549
  io.error(JSON.stringify({ ok: false, error: "bundle_flag_needs_a_value", message: "--bundle takes a bundle sha256, or the literal `none` to unbind the screen.", usage: PATCH_USAGE }));
67936
68550
  return 2;
67937
68551
  }
67938
- const bundleFlag = str5(flags.bundle);
68552
+ const bundleFlag = str6(flags.bundle);
67939
68553
  const bundle = bundleFlag === "none" ? null : bundleFlag;
67940
68554
  if (!baseOrRefuse(baseFound.manifest)) return 1;
67941
68555
  return runReleasePatch({
@@ -67946,9 +68560,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67946
68560
  extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
67947
68561
  });
67948
68562
  }
67949
- const bytes2 = readFileSync71(file);
67950
- const sha = createHash26("sha256").update(bytes2).digest("hex");
67951
- const forScreens = (str5(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
68563
+ const bytes2 = readFileSync72(file);
68564
+ const sha = createHash27("sha256").update(bytes2).digest("hex");
68565
+ const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
67952
68566
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
67953
68567
  io.error(JSON.stringify({ ok: false, error: "no_rebind_takes_no_value", message: "--no-rebind is a switch and takes no value; pass it bare.", usage: PATCH_USAGE }));
67954
68568
  return 2;
@@ -68037,7 +68651,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
68037
68651
  // READ of the device-facing door, and what that read says is what gets printed.
68038
68652
  case "flags": {
68039
68653
  const sub = pos[1];
68040
- const app = str5(flags.app) ?? await appId(contentDir(flags));
68654
+ const app = str6(flags.app) ?? await appId(contentDir(flags));
68041
68655
  const usage = "usage: himi flags list | set <key> --definition <json|@file> | ramp <key> [--percent 0-100] [--enabled true|false] | rm <key>";
68042
68656
  if (sub !== "list" && sub !== "set" && sub !== "ramp" && sub !== "rm") {
68043
68657
  io.error(JSON.stringify({ error: `unknown flags subcommand: ${sub ?? "(none)"}`, hint: usage }));
@@ -68083,14 +68697,14 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
68083
68697
  return 2;
68084
68698
  }
68085
68699
  if (sub === "set") {
68086
- const arg = str5(flags.definition);
68700
+ const arg = str6(flags.definition);
68087
68701
  if (!arg) {
68088
68702
  io.error(JSON.stringify({ error: "flags set needs --definition <json|@file>", hint: usage }));
68089
68703
  return 2;
68090
68704
  }
68091
68705
  let def;
68092
68706
  try {
68093
- const parsed = JSON.parse(arg.startsWith("@") ? readFileSync71(arg.slice(1), "utf8") : arg);
68707
+ const parsed = JSON.parse(arg.startsWith("@") ? readFileSync72(arg.slice(1), "utf8") : arg);
68094
68708
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
68095
68709
  io.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
68096
68710
  return 2;
@@ -68135,7 +68749,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
68135
68749
  return 2;
68136
68750
  }
68137
68751
  const enabledGiven = flags.enabled !== void 0;
68138
- const enabledRaw = flags.enabled === true ? "true" : str5(flags.enabled);
68752
+ const enabledRaw = flags.enabled === true ? "true" : str6(flags.enabled);
68139
68753
  if (enabledGiven && enabledRaw !== "true" && enabledRaw !== "false") {
68140
68754
  io.error(JSON.stringify({ error: `--enabled must be true or false, got ${String(flags.enabled)}` }));
68141
68755
  return 2;
@@ -68213,7 +68827,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
68213
68827
  io.error(JSON.stringify({ error: `visibility takes public|unlisted (got "${value}")` }));
68214
68828
  return 2;
68215
68829
  }
68216
- const app = str5(flags.app) ?? await appId(contentDir(flags));
68830
+ const app = str6(flags.app) ?? await appId(contentDir(flags));
68217
68831
  let r;
68218
68832
  try {
68219
68833
  r = value === void 0 ? await client2().appSettings(app) : await client2().setVisibility(app, value);
@@ -68235,8 +68849,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
68235
68849
  // a minBinaryVersion floor bump.
68236
68850
  case "store":
68237
68851
  case "testflight": {
68238
- if (str5(flags.provider) === "wix-mobile-release") {
68239
- const playerTarget = wixPlayerTestflightTarget(str5(flags.target));
68852
+ if (str6(flags.provider) === "wix-mobile-release") {
68853
+ const playerTarget = wixPlayerTestflightTarget(str6(flags.target));
68240
68854
  if (!playerTarget) {
68241
68855
  io.error(JSON.stringify({ error: "Wix Mobile Release requires deployed --target bo or --target prod; local/custom targets cannot hold the Himi service identity" }));
68242
68856
  return 2;
@@ -68470,8 +69084,8 @@ ${label2}`);
68470
69084
  io.error(JSON.stringify({ error: "dist watch needs a <jobId>" }));
68471
69085
  return 2;
68472
69086
  }
68473
- const intervalMs2 = Number(str5(flags.interval)) || 2e4;
68474
- const deadline2 = Date.now() + (Number(str5(flags.timeout)) || 45 * 6e4);
69087
+ const intervalMs2 = Number(str6(flags.interval)) || 2e4;
69088
+ const deadline2 = Date.now() + (Number(str6(flags.timeout)) || 45 * 6e4);
68475
69089
  let announced = false;
68476
69090
  for (; ; ) {
68477
69091
  let s;
@@ -68513,14 +69127,14 @@ ${label2}`);
68513
69127
  }
68514
69128
  }
68515
69129
  if (sub === "list") {
68516
- const app2 = str5(flags.app) ?? await appId(contentDir(flags));
69130
+ const app2 = str6(flags.app) ?? await appId(contentDir(flags));
68517
69131
  if (!app2) {
68518
69132
  io.error(JSON.stringify({ error: "dist list needs --app" }));
68519
69133
  return 2;
68520
69134
  }
68521
69135
  let r2;
68522
69136
  try {
68523
- r2 = await c.distList(app2, Number(str5(flags.limit)) || void 0);
69137
+ r2 = await c.distList(app2, Number(str6(flags.limit)) || void 0);
68524
69138
  } catch (e) {
68525
69139
  return distUnreachable(e);
68526
69140
  }
@@ -68546,15 +69160,15 @@ ${label2}`);
68546
69160
  io.error(JSON.stringify({ error: `unknown dist subcommand "${sub}" \u2014 use status | watch | list | cancel, or no subcommand to start a build` }));
68547
69161
  return 2;
68548
69162
  }
68549
- const app = str5(flags.app) ?? await appId(contentDir(flags));
69163
+ const app = str6(flags.app) ?? await appId(contentDir(flags));
68550
69164
  if (!app) {
68551
69165
  io.error(JSON.stringify({ error: "dist needs --app (or a content dir whose himalaya.content.json names one)" }));
68552
69166
  return 2;
68553
69167
  }
68554
- const platform = str5(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
69168
+ const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
68555
69169
  {
68556
69170
  const distDir = contentDir(flags);
68557
- if (existsSync60(join56(distDir, "himalaya.content.json"))) {
69171
+ if (existsSync60(join57(distDir, "himalaya.content.json"))) {
68558
69172
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
68559
69173
  const errors = issues.filter((i) => i.severity === "error");
68560
69174
  for (const i of issues.filter((i2) => i2.severity === "warning")) {
@@ -68572,31 +69186,31 @@ ${label2}`);
68572
69186
  }
68573
69187
  }
68574
69188
  const { captchaContentInput: captchaContentInput2 } = await Promise.resolve().then(() => (init_captcha2(), captcha_exports));
68575
- const captchaSiteId = str5(flags.site) ?? captchaContentInput2(contentDir(flags)).siteId;
69189
+ const captchaSiteId = str6(flags.site) ?? captchaContentInput2(contentDir(flags)).siteId;
68576
69190
  let r;
68577
69191
  try {
68578
69192
  r = await c.distCreate({
68579
69193
  app,
68580
69194
  ...platform?.length ? { platform } : {},
68581
- ...str5(flags.release) ? { release: str5(flags.release) } : {},
69195
+ ...str6(flags.release) ? { release: str6(flags.release) } : {},
68582
69196
  ...flags["allow-draft"] === true ? { allowDraft: true } : {},
68583
69197
  ...captchaSiteId ? { captchaSiteId } : {},
68584
- ...str5(flags.shell) ? { shell: str5(flags.shell) } : {},
69198
+ ...str6(flags.shell) ? { shell: str6(flags.shell) } : {},
68585
69199
  // INTERIM, iOS only: sign under an internal enterprise id the Mac pool already holds a
68586
69200
  // profile for, because no profile covers a himi shell's own id yet. The serve plane
68587
69201
  // refuses anything outside its allow-list (internal `ent.*` only — never a store id).
68588
69202
  // flags["borrow-ios-id"], NOT flags.borrowIosId — parseFlags does no kebab→camel
68589
69203
  // conversion (see line ~58), so the camel form reads undefined and the flag would be a
68590
69204
  // silent no-op. Every other multi-word flag here uses the bracket form for the same reason.
68591
- ...str5(flags["borrow-ios-id"]) ? { borrowIosBundleId: str5(flags["borrow-ios-id"]) } : {},
68592
- ...str5(flags.destination) ? { destination: str5(flags.destination) } : {},
68593
- ...str5(flags.signing) ? { signing: str5(flags.signing) } : {},
69205
+ ...str6(flags["borrow-ios-id"]) ? { borrowIosBundleId: str6(flags["borrow-ios-id"]) } : {},
69206
+ ...str6(flags.destination) ? { destination: str6(flags.destination) } : {},
69207
+ ...str6(flags.signing) ? { signing: str6(flags.signing) } : {},
68594
69208
  // WHICH KEYSTORE signs the APK. A separate axis from --signing (that one is the Apple
68595
69209
  // account), so a `--platform ios,android` build can say "Wix-managed on iOS, the QA
68596
69210
  // keystore on Android" — the normal combination — with one command.
68597
69211
  // flags["android-signing"], NOT flags.androidSigning: parseFlags does no kebab→camel
68598
69212
  // conversion, so the camel form reads undefined and the flag is a silent no-op.
68599
- ...str5(flags["android-signing"]) ? { androidSigning: str5(flags["android-signing"]) } : {}
69213
+ ...str6(flags["android-signing"]) ? { androidSigning: str6(flags["android-signing"]) } : {}
68600
69214
  });
68601
69215
  } catch (e) {
68602
69216
  return distUnreachable(e);
@@ -68611,14 +69225,14 @@ ${label2}`);
68611
69225
  if (noWait) {
68612
69226
  print({ status: r.status, ...r.json ?? {} });
68613
69227
  if (!flags.json) {
68614
- const t = str5(flags.target);
69228
+ const t = str6(flags.target);
68615
69229
  const targetArg = t ? ` --target ${t}` : "";
68616
69230
  for (const j of jobs) io.log(` ${j.platform} ${j.jobId} \u2192 himi dist status ${j.jobId}${targetArg}`);
68617
69231
  }
68618
69232
  return 0;
68619
69233
  }
68620
- const intervalMs = Number(str5(flags.interval)) || 2e4;
68621
- const timeoutMs = Number(str5(flags.timeout)) || 45 * 6e4;
69234
+ const intervalMs = Number(str6(flags.interval)) || 2e4;
69235
+ const timeoutMs = Number(str6(flags.timeout)) || 45 * 6e4;
68622
69236
  const deadline = Date.now() + timeoutMs;
68623
69237
  const pending = new Map(jobs.map((j) => [String(j.jobId), String(j.platform)]));
68624
69238
  const done = [];
@@ -68660,7 +69274,7 @@ ${label2}`);
68660
69274
  let issue2;
68661
69275
  let ownerIssue;
68662
69276
  try {
68663
- const t = resolveTarget({ target, issueUrl: str5(flags["issue-url"]), ownerIssueUrl: str5(flags["owner-issue-url"]) });
69277
+ const t = resolveTarget({ target, issueUrl: str6(flags["issue-url"]), ownerIssueUrl: str6(flags["owner-issue-url"]) });
68664
69278
  issue2 = t.issue;
68665
69279
  ownerIssue = t.ownerIssue;
68666
69280
  } catch (e) {
@@ -68823,7 +69437,7 @@ ${label2}`);
68823
69437
  const dpxPath = dpxSessionTokenPath();
68824
69438
  let dpx;
68825
69439
  try {
68826
- dpx = readFileSync71(dpxPath, "utf8").trim();
69440
+ dpx = readFileSync72(dpxPath, "utf8").trim();
68827
69441
  } catch {
68828
69442
  io.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
68829
69443
  return 1;
@@ -68859,7 +69473,7 @@ ${label2}`);
68859
69473
  const target = targetName();
68860
69474
  let ownerIssue;
68861
69475
  try {
68862
- ownerIssue = resolveTarget({ target, ownerIssueUrl: str5(flags["owner-issue-url"]) }).ownerIssue;
69476
+ ownerIssue = resolveTarget({ target, ownerIssueUrl: str6(flags["owner-issue-url"]) }).ownerIssue;
68863
69477
  } catch (e) {
68864
69478
  io.error(JSON.stringify({ error: e.message }));
68865
69479
  return 2;
@@ -68875,10 +69489,10 @@ ${label2}`);
68875
69489
  }
68876
69490
  const base = ownerIssue.replace(/\/$/, "");
68877
69491
  const sub = pos[1];
68878
- const cookie = str5(flags.cookie) ?? process.env.HIMI_WIX_COOKIE;
69492
+ const cookie = str6(flags.cookie) ?? process.env.HIMI_WIX_COOKIE;
68879
69493
  let ownerToken;
68880
69494
  try {
68881
- ownerToken = resolveTarget({ target, controlToken: str5(flags["control-token"]) }).controlToken;
69495
+ ownerToken = resolveTarget({ target, controlToken: str6(flags["control-token"]) }).controlToken;
68882
69496
  } catch {
68883
69497
  }
68884
69498
  if (!cookie && !ownerToken) {
@@ -68898,9 +69512,9 @@ ${label2}`);
68898
69512
  return 2;
68899
69513
  }
68900
69514
  const body = { slug };
68901
- const dn = str5(flags["display-name"]);
69515
+ const dn = str6(flags["display-name"]);
68902
69516
  if (dn) body.displayName = dn;
68903
- const acct = str5(flags["account-id"]);
69517
+ const acct = str6(flags["account-id"]);
68904
69518
  if (acct) body.accountId = acct;
68905
69519
  const r2 = await fetch(`${base}/v1/owner/apps/claim`, { method: "POST", redirect: "error", headers: { ...headers2, "content-type": "application/json" }, body: JSON.stringify(body) });
68906
69520
  const j2 = await r2.json().catch(() => ({}));
@@ -69020,8 +69634,8 @@ ${label2}`);
69020
69634
  try {
69021
69635
  const t = resolveTarget({
69022
69636
  target,
69023
- controlUrl: str5(flags["control-url"]),
69024
- controlToken: str5(flags["control-token"])
69637
+ controlUrl: str6(flags["control-url"]),
69638
+ controlToken: str6(flags["control-token"])
69025
69639
  });
69026
69640
  if (t.controlToken && t.control) {
69027
69641
  const revokeRefusal = credentialHostRefusal(t.control);
@@ -69099,8 +69713,8 @@ ${label2}`);
69099
69713
  }
69100
69714
  case "doctor": {
69101
69715
  const target = targetName();
69102
- const timeoutMs = Number(str5(flags.timeout)) > 0 ? Number(str5(flags.timeout)) : DOCTOR_TIMEOUT_MS;
69103
- const dataUrl = str5(flags["data-url"]) ?? process.env.HIMI_DATA_URL ?? PUBLIC_WIX_API_BASE;
69716
+ const timeoutMs = Number(str6(flags.timeout)) > 0 ? Number(str6(flags.timeout)) : DOCTOR_TIMEOUT_MS;
69717
+ const dataUrl = str6(flags["data-url"]) ?? process.env.HIMI_DATA_URL ?? PUBLIC_WIX_API_BASE;
69104
69718
  let resolved2;
69105
69719
  let serveUrl = "";
69106
69720
  let targetError;
@@ -69110,9 +69724,9 @@ ${label2}`);
69110
69724
  // Passing `str(flags.target)` re-ran resolution without `defaultTarget`, so off-repo
69111
69725
  // doctor labelled its report `wix` while probing the `local` URLs.
69112
69726
  target,
69113
- serveUrl: str5(flags["serve-url"]),
69114
- controlUrl: str5(flags["control-url"]),
69115
- controlToken: str5(flags["control-token"])
69727
+ serveUrl: str6(flags["serve-url"]),
69728
+ controlUrl: str6(flags["control-url"]),
69729
+ controlToken: str6(flags["control-token"])
69116
69730
  });
69117
69731
  serveUrl = resolved2.serve;
69118
69732
  } catch (e) {
@@ -69216,7 +69830,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69216
69830
  const { BO_FUNCTIONS_BASE_URL: BO_FUNCTIONS_BASE_URL2, resolveFunctionsTarget: resolveFunctionsTarget2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
69217
69831
  let secretTarget;
69218
69832
  try {
69219
- secretTarget = resolveFunctionsTarget2({ target: str5(flags.target), functionsUrl: str5(flags["functions-url"]), releaseId: str5(flags.release) });
69833
+ secretTarget = resolveFunctionsTarget2({ target: str6(flags.target), functionsUrl: str6(flags["functions-url"]), releaseId: str6(flags.release) });
69220
69834
  } catch (error) {
69221
69835
  io.error(JSON.stringify({ error: error.message }));
69222
69836
  return 1;
@@ -69225,7 +69839,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69225
69839
  const path2 = dpxSessionTokenPath();
69226
69840
  let raw;
69227
69841
  try {
69228
- raw = readFileSync71(path2, "utf8");
69842
+ raw = readFileSync72(path2, "utf8");
69229
69843
  } catch {
69230
69844
  io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
69231
69845
  return 1;
@@ -69269,20 +69883,20 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69269
69883
  let site;
69270
69884
  let call;
69271
69885
  try {
69272
- site = resolveSiteId(str5(flags.site));
69886
+ site = resolveSiteId(str6(flags.site));
69273
69887
  call = ownerTransport(site);
69274
69888
  } catch (error) {
69275
69889
  io.error(JSON.stringify({ error: error.message }));
69276
69890
  return 2;
69277
69891
  }
69278
- const environment2 = str5(flags.environment) ?? "preview";
69892
+ const environment2 = str6(flags.environment) ?? "preview";
69279
69893
  if (environment2 !== "preview" && environment2 !== "production") {
69280
69894
  io.error(JSON.stringify({ error: "--environment must be preview or production" }));
69281
69895
  return 2;
69282
69896
  }
69283
69897
  let kv;
69284
69898
  if (data.kv?.length) {
69285
- const baseUrl = str5(flags["data-url"]) ?? process.env.HIMI_DATA_ADMIN_URL;
69899
+ const baseUrl = str6(flags["data-url"]) ?? process.env.HIMI_DATA_ADMIN_URL;
69286
69900
  const token = process.env.HIMI_DATA_ADMIN_TOKEN;
69287
69901
  if (!baseUrl || !token) {
69288
69902
  io.error(JSON.stringify({ error: "KV declarations require --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN for the operator data plane", app, site, environment: environment2 }));
@@ -69354,7 +69968,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69354
69968
  return 1;
69355
69969
  }
69356
69970
  if (sub === "seed" && flags.ai === true) {
69357
- const res = await writeSeedRows({ app, cms, dir, count: Number(str5(flags.count)) || 8 });
69971
+ const res = await writeSeedRows({ app, cms, dir, count: Number(str6(flags.count)) || 8 });
69358
69972
  print(res);
69359
69973
  return res.ok ? 0 : 1;
69360
69974
  }
@@ -69371,7 +69985,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69371
69985
  let call;
69372
69986
  let site;
69373
69987
  try {
69374
- site = resolveSiteId(str5(flags.site));
69988
+ site = resolveSiteId(str6(flags.site));
69375
69989
  call = ownerTransport(site);
69376
69990
  } catch (e) {
69377
69991
  io.error(JSON.stringify({ error: e.message }));
@@ -69380,7 +69994,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69380
69994
  const common = { app, cms, call };
69381
69995
  let report2;
69382
69996
  try {
69383
- report2 = sub === "query" ? await queryCms({ ...common, all: flags.all === true }) : sub === "create" ? await createCms({ ...common, dryRun: flags["dry-run"] === true, allowDestructive: flags["allow-destructive"] === true, applyPermissions: flags["apply-permissions"] === true }) : await seedCms({ ...common, dir, dryRun: flags["dry-run"] === true, force: flags.force === true, only: str5(flags.only) });
69997
+ report2 = sub === "query" ? await queryCms({ ...common, all: flags.all === true }) : sub === "create" ? await createCms({ ...common, dryRun: flags["dry-run"] === true, allowDestructive: flags["allow-destructive"] === true, applyPermissions: flags["apply-permissions"] === true }) : await seedCms({ ...common, dir, dryRun: flags["dry-run"] === true, force: flags.force === true, only: str6(flags.only) });
69384
69998
  } catch (e) {
69385
69999
  const partial = e.partial;
69386
70000
  io.error(JSON.stringify({
@@ -69403,17 +70017,17 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69403
70017
  const r = await runSiteFunctionCli2({
69404
70018
  op: pos[2],
69405
70019
  name: pos[3],
69406
- siteFlag: str5(flags.site),
69407
- siteUrl: str5(flags.url) ?? str5(flags["site-url"]) ?? process.env.WIX_SITE_URL,
69408
- clientId: str5(flags["client-id"]) ?? process.env.WIX_CLIENT_ID,
69409
- method: str5(flags.method),
69410
- sourcePath: str5(flags.source),
69411
- bodyRaw: str5(flags.body),
70020
+ siteFlag: str6(flags.site),
70021
+ siteUrl: str6(flags.url) ?? str6(flags["site-url"]) ?? process.env.WIX_SITE_URL,
70022
+ clientId: str6(flags["client-id"]) ?? process.env.WIX_CLIENT_ID,
70023
+ method: str6(flags.method),
70024
+ sourcePath: str6(flags.source),
70025
+ bodyRaw: str6(flags.body),
69412
70026
  publish: flags.publish === true,
69413
70027
  invoke: flags.invoke === true,
69414
70028
  dryRun: flags["dry-run"] === true,
69415
70029
  visitor: flags.visitor === true,
69416
- cwd: str5(flags.content) ?? process.cwd()
70030
+ cwd: str6(flags.content) ?? process.cwd()
69417
70031
  });
69418
70032
  print(r);
69419
70033
  return r.ok ? 0 : 1;
@@ -69435,17 +70049,17 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69435
70049
  }
69436
70050
  try {
69437
70051
  const r = op === "list" ? await runSiteClientList2({
69438
- siteFlag: str5(flags.site),
69439
- redirectUri: str5(flags["redirect-uri"])
70052
+ siteFlag: str6(flags.site),
70053
+ redirectUri: str6(flags["redirect-uri"])
69440
70054
  }) : await runSiteClientEnsure2({
69441
- siteFlag: str5(flags.site),
69442
- name: str5(flags.name),
69443
- redirectUri: str5(flags["redirect-uri"]),
70055
+ siteFlag: str6(flags.site),
70056
+ name: str6(flags.name),
70057
+ redirectUri: str6(flags["redirect-uri"]),
69444
70058
  new: flags.new === true,
69445
70059
  yes: flags.yes === true,
69446
70060
  // Bare `--write-provisioning` is the default path; with a value it is that path.
69447
- writeProvisioning: flags["write-provisioning"] === true ? true : str5(flags["write-provisioning"]),
69448
- siteUrl: str5(flags["site-url"]) ?? str5(flags.url)
70061
+ writeProvisioning: flags["write-provisioning"] === true ? true : str6(flags["write-provisioning"]),
70062
+ siteUrl: str6(flags["site-url"]) ?? str6(flags.url)
69449
70063
  });
69450
70064
  print(r);
69451
70065
  return r.ok ? 0 : 1;
@@ -69468,15 +70082,15 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69468
70082
  try {
69469
70083
  const r = sub === "list" ? await runSiteList2() : await runSiteCreate2({
69470
70084
  name: pos[2],
69471
- type: str5(flags.type),
69472
- templateId: str5(flags.template),
69473
- verticals: str5(flags.verticals),
69474
- folderId: str5(flags.folder),
69475
- redirectUri: str5(flags["redirect-uri"]),
70085
+ type: str6(flags.type),
70086
+ templateId: str6(flags.template),
70087
+ verticals: str6(flags.verticals),
70088
+ folderId: str6(flags.folder),
70089
+ redirectUri: str6(flags["redirect-uri"]),
69476
70090
  noOauthApp: flags["no-oauth-app"] === true,
69477
70091
  // Bare `--write-provisioning` is the default path; with a value it is that path.
69478
- writeProvisioning: flags["write-provisioning"] === true ? true : str5(flags["write-provisioning"]),
69479
- siteUrl: str5(flags["site-url"]),
70092
+ writeProvisioning: flags["write-provisioning"] === true ? true : str6(flags["write-provisioning"]),
70093
+ siteUrl: str6(flags["site-url"]),
69480
70094
  yes: flags.yes === true,
69481
70095
  // The argv as typed, so the dry run echoes back a command that actually
69482
70096
  // recreates THIS plan. Reconstructing it from the fields above would
@@ -69495,14 +70109,14 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69495
70109
  io.error(JSON.stringify({ error: sub ? `unknown site subcommand "${sub}"` : "site needs a subcommand", usage: `himi site create <name> [--type wix|headless|branded-app|vibe] --yes | himi site list | himi site client ensure|list --site <msid> | himi site analyze --client-id <id> --url <https://\u2026> [--site <msid>] [--out <dir>] [--apply [--shell <id>]] | himi site function list|get|put|publish|invoke \u2026` }));
69496
70110
  return 2;
69497
70111
  }
69498
- const clientId = str5(flags["client-id"]) ?? process.env.WIX_CLIENT_ID;
69499
- const siteUrl = str5(flags.url) ?? str5(flags["site-url"]);
70112
+ const clientId = str6(flags["client-id"]) ?? process.env.WIX_CLIENT_ID;
70113
+ const siteUrl = str6(flags.url) ?? str6(flags["site-url"]);
69500
70114
  if (flags["read-only"] === true) {
69501
70115
  if (flags.apply || flags.out || flags.shell || flags["redirect-uri"]) {
69502
70116
  io.error(JSON.stringify({ error: "--read-only returns API context only; it cannot be combined with --apply, --out, --shell, or --redirect-uri" }));
69503
70117
  return 2;
69504
70118
  }
69505
- const siteId = str5(flags.site) ?? process.env.WIX_SITE_ID;
70119
+ const siteId = str6(flags.site) ?? process.env.WIX_SITE_ID;
69506
70120
  if (!clientId && !siteId && !process.env.WIX_TEST_TOKEN?.trim()) {
69507
70121
  io.error(JSON.stringify({ error: "--read-only needs --site, --client-id, or a site-scoped WIX_TEST_TOKEN" }));
69508
70122
  return 2;
@@ -69544,16 +70158,16 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
69544
70158
  const r = await runSiteAnalyze2({
69545
70159
  clientId,
69546
70160
  siteUrl,
69547
- siteFlag: str5(flags.site),
69548
- outDir: str5(flags.out),
70161
+ siteFlag: str6(flags.site),
70162
+ outDir: str6(flags.out),
69549
70163
  apply: flags.apply === true,
69550
- shell: str5(flags.shell),
70164
+ shell: str6(flags.shell),
69551
70165
  // A redirect already REGISTERED on --client-id, recorded into the applied binding.
69552
70166
  // Analyze cannot discover it (GET-only; the registered list lives behind
69553
70167
  // `oauth-app/v1`), and the shell refuses to reuse its own default once a customer
69554
70168
  // client is in play — so it is passed in by whoever registered it.
69555
- redirectUri: str5(flags["redirect-uri"]),
69556
- cwd: str5(flags.content) ?? process.cwd()
70169
+ redirectUri: str6(flags["redirect-uri"]),
70170
+ cwd: str6(flags.content) ?? process.cwd()
69557
70171
  });
69558
70172
  print({ ok: true, ...r });
69559
70173
  return 0;