@wix/himalaya-cli 0.996.0 → 0.998.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -5307,7 +5307,6 @@ function walk(node, registry, path, out) {
5307
5307
  var SYSTEM_FONT_FAMILY;
5308
5308
  var init_tokens = __esm({
5309
5309
  "../../core/ts/src/tokens.ts"() {
5310
- "use strict";
5311
5310
  SYSTEM_FONT_FAMILY = "$system";
5312
5311
  }
5313
5312
  });
@@ -5333,7 +5332,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
5333
5332
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
5334
5333
  var init_bindings = __esm({
5335
5334
  "../../core/ts/src/bindings.ts"() {
5336
- "use strict";
5337
5335
  BINDING_SIGILS = ["service", "flag", "item", "t"];
5338
5336
  BINDING_SIGIL_RE = new RegExp(
5339
5337
  `^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
@@ -6607,8 +6605,10 @@ __export(validate_descriptor_core_exports, {
6607
6605
  isOpaqueAuthorJson: () => isOpaqueAuthorJson,
6608
6606
  loadBundleServicesLive: () => loadBundleServicesLive,
6609
6607
  nativeRequiredFindings: () => nativeRequiredFindings,
6608
+ nondeterministicServices: () => nondeterministicServices,
6610
6609
  pathCrossesOpaqueAuthorJson: () => pathCrossesOpaqueAuthorJson,
6611
6610
  pathValue: () => pathValue,
6611
+ pinnedIntrinsicsSource: () => pinnedIntrinsicsSource,
6612
6612
  resolveActionEvaluator: () => resolveActionEvaluator,
6613
6613
  resolveBootEvaluator: () => resolveBootEvaluator,
6614
6614
  resolveEvaluator: () => resolveEvaluator,
@@ -6704,12 +6704,17 @@ function runBundleSandbox(bundleJs, opts) {
6704
6704
  TextEncoder,
6705
6705
  TextDecoder,
6706
6706
  AbortController
6707
+ // NO `Date` / `Math` here, pinned or not: a pinned pair built on this side would be the host's
6708
+ // intrinsics wearing a sandbox name. The realm builds them from its own (`pinnedIntrinsicsSource`).
6707
6709
  };
6708
6710
  try {
6709
6711
  resolveBootEvaluator(opts.evaluator).run(bundleJs, sandbox, {
6710
6712
  timeoutMs: opts.timeoutMs ?? BOOT_EVAL_TIMEOUT_MS,
6711
6713
  filename: "himi-bundle.js",
6712
- captureConsole: Boolean(opts.captureConsole)
6714
+ captureConsole: Boolean(opts.captureConsole),
6715
+ ...opts.clock === void 0 ? {} : { clock: opts.clock },
6716
+ ...opts.seed === void 0 ? {} : { seed: opts.seed },
6717
+ ...opts.mirrorRandom ? { mirrorRandom: true } : {}
6713
6718
  });
6714
6719
  return { services, actions, console: consoleLines, threw: null };
6715
6720
  } catch (err) {
@@ -6735,6 +6740,59 @@ function dryRunBundle(bundleJs, opts = {}) {
6735
6740
  const r = runBundleSandbox(bundleJs, { rethrow: false, captureConsole: true, ...opts });
6736
6741
  return { services: Object.keys(r.services), console: r.console, threw: r.threw };
6737
6742
  }
6743
+ function pinnedIntrinsicsSource(pins) {
6744
+ const clock = pins.clock === void 0 ? void 0 : Number(pins.clock);
6745
+ const seed2 = pins.seed === void 0 ? void 0 : Math.trunc(Number(pins.seed)) >>> 0 || 1;
6746
+ if (clock === void 0 && seed2 === void 0) return null;
6747
+ const date = clock === void 0 ? "" : `
6748
+ var pinned = ${clock};
6749
+ // Captured NOW, before any bundle code runs: resolved per call, a worker that deletes or
6750
+ // overwrites \`globalThis.Reflect\` would make every pinned \`new Date()\` throw, both drift probes
6751
+ // would fail, and the drift check would stay silent about a worker the real build boots fine.
6752
+ var construct = Reflect.construct;
6753
+ // \`new Date()\` \u2192 the pinned instant; \`new Date(<args>)\` keeps its meaning; \`Date()\` called as a
6754
+ // function returns the pinned instant's string, as it would the current one.
6755
+ var PinnedDate = function Date() {
6756
+ if (new.target === undefined) return new RealDate(pinned).toString();
6757
+ return arguments.length ? construct(RealDate, arguments, new.target) : construct(RealDate, [pinned], new.target);
6758
+ };
6759
+ PinnedDate.prototype = Object.create(RealDate.prototype, { constructor: { value: PinnedDate, writable: true, configurable: true } });
6760
+ PinnedDate.now = function now() { return pinned; };
6761
+ PinnedDate.parse = RealDate.parse;
6762
+ PinnedDate.UTC = RealDate.UTC;
6763
+ out.Date = PinnedDate;`;
6764
+ const math = seed2 === void 0 ? "" : `
6765
+ var s = ${seed2};
6766
+ var imul = RealMath.imul;
6767
+ var M = Object.create(Object.getPrototypeOf(RealMath));
6768
+ Object.getOwnPropertyNames(RealMath).forEach(function (k) { Object.defineProperty(M, k, Object.getOwnPropertyDescriptor(RealMath, k)); });
6769
+ Object.getOwnPropertySymbols(RealMath).forEach(function (k) { Object.defineProperty(M, k, Object.getOwnPropertyDescriptor(RealMath, k)); });
6770
+ // Non-writable, so a bundle cannot put an unseeded PRNG back and make a seeded run vary.
6771
+ Object.defineProperty(M, "random", {
6772
+ value: function random() {
6773
+ s = (s + 0x6d2b79f5) >>> 0;
6774
+ var t = imul(s ^ (s >>> 15), 1 | s);
6775
+ t = (t + imul(t ^ (t >>> 7), 61 | t)) ^ t;
6776
+ var u = (t ^ (t >>> 14)) >>> 0;
6777
+ return ${pins.mirrorRandom ? "(~u >>> 0)" : "u"} / 4294967296;
6778
+ },
6779
+ writable: false, enumerable: false, configurable: false,
6780
+ });
6781
+ out.Math = M;`;
6782
+ return `(function (RealDate, RealMath) {
6783
+ var out = {};${date}${math}
6784
+ return out;
6785
+ })`;
6786
+ }
6787
+ function nondeterministicServices(bundleJs, opts = {}) {
6788
+ const boots = DRIFT_PROBES.map((probe) => runBundleSandbox(bundleJs, { rethrow: false, ...opts, ...probe }));
6789
+ const threw = boots.filter((b2) => b2.threw !== null).length;
6790
+ if (threw === boots.length) return [];
6791
+ const [a, b] = boots.map((boot) => boot.services);
6792
+ const names = [.../* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])];
6793
+ if (threw > 0) return names.sort();
6794
+ return names.filter((name) => safeStringify(a[name]) !== safeStringify(b[name])).sort();
6795
+ }
6738
6796
  function setDefaultEvaluator(evaluator) {
6739
6797
  defaultEvaluator = evaluator;
6740
6798
  }
@@ -6875,26 +6933,10 @@ async function bootBundleWorker(bundleJs, opts) {
6875
6933
  timers.delete(t);
6876
6934
  }
6877
6935
  };
6878
- const frozenDate = opts.clock === void 0 ? void 0 : new Proxy(Date, {
6879
- get: (t, p) => p === "now" ? () => opts.clock : Reflect.get(t, p),
6880
- // `new Date()` → the pinned instant; `new Date(<args>)` keeps its normal meaning.
6881
- construct: (t, args) => args.length ? new t(...args) : new t(opts.clock),
6882
- apply: () => new Date(opts.clock).toString()
6883
- });
6884
- const seededMath = opts.seed === void 0 ? void 0 : (() => {
6885
- let s = opts.seed >>> 0 || 1;
6886
- const m = Object.create(Math);
6887
- Object.defineProperty(m, "random", {
6888
- value: () => {
6889
- s = s + 1831565813 >>> 0;
6890
- let t = Math.imul(s ^ s >>> 15, 1 | s);
6891
- t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
6892
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
6893
- },
6894
- enumerable: true
6895
- });
6896
- return m;
6897
- })();
6936
+ const pins = {
6937
+ ...opts.clock === void 0 ? {} : { clock: opts.clock },
6938
+ ...opts.seed === void 0 ? {} : { seed: opts.seed }
6939
+ };
6898
6940
  const sandbox = {
6899
6941
  himalaya,
6900
6942
  globalThis: void 0,
@@ -6922,8 +6964,6 @@ async function bootBundleWorker(bundleJs, opts) {
6922
6964
  clearInterval: () => {
6923
6965
  }
6924
6966
  },
6925
- ...frozenDate ? { Date: frozenDate } : {},
6926
- ...seededMath ? { Math: seededMath } : {},
6927
6967
  // HOST globals, not ECMAScript built-ins: a bare vm context has Object/Array/Date/Intl/JSON
6928
6968
  // but NOT these. Injecting them unconditionally — INCLUDING under deviceParity — rested on
6929
6969
  // "every real worker runtime (JSC, Hermes, the web-host Worker) does" have them. **A bare
@@ -6974,7 +7014,7 @@ async function bootBundleWorker(bundleJs, opts) {
6974
7014
  errors.push({ service: "(boot)", message: ran.error });
6975
7015
  }
6976
7016
  } else {
6977
- realm.run(bundleJs, sandbox, { timeoutMs: 2e3, filename: "himi-bundle.js", hide });
7017
+ realm.run(bundleJs, sandbox, { timeoutMs: 2e3, filename: "himi-bundle.js", hide, ...pins });
6978
7018
  }
6979
7019
  } catch (err) {
6980
7020
  errors.push({ service: "(boot)", message: err?.message ?? String(err), ...err?.stack ? { stack: err.stack } : {} });
@@ -8376,7 +8416,7 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
8376
8416
  services: Object.keys(services)
8377
8417
  };
8378
8418
  }
8379
- var CRAWL_BLOCKING_PASSES, BOOT_EVAL_TIMEOUT_MS, DEVICE_PARITY_WITHHELD, defaultEvaluator, bootEvaluator, actionEvaluator, NATIVE_PROP_ENUMS, KNOWN_PROPS, IN_ARRAY_BINDING_PROPS, SERVICE_SIGIL, INTEGER_PROPS, NATIVE_REQUIRED_PROPS, bareNestedClass, NATIVE_NESTED_CLASSES, NATIVE_MODIFIERS_CLASS, NATIVE_DESCRIPTOR_CLASS, NATIVE_DESCRIPTOR_NESTED, NATIVE_NESTED_PROPS, MODIFIER_KEYS, INTEGER_MODIFIERS, MODIFIER_KINDS, SCHEMA_SCORED_NODES, CORE_PACKAGES, LEGACY_UNSCORED_KEYS, DYNAMIC_PLACEHOLDER, LITERAL_ONLY_PROPS, SERVICE_ONLY_BINDING_PROPS, WHOLE_VALUE_BINDING, EMBEDDED_BINDING, OPTIONS_BINDING_PROPS;
8419
+ var CRAWL_BLOCKING_PASSES, BOOT_EVAL_TIMEOUT_MS, DRIFT_PROBES, DEVICE_PARITY_WITHHELD, defaultEvaluator, bootEvaluator, actionEvaluator, NATIVE_PROP_ENUMS, KNOWN_PROPS, IN_ARRAY_BINDING_PROPS, SERVICE_SIGIL, INTEGER_PROPS, NATIVE_REQUIRED_PROPS, bareNestedClass, NATIVE_NESTED_CLASSES, NATIVE_MODIFIERS_CLASS, NATIVE_DESCRIPTOR_CLASS, NATIVE_DESCRIPTOR_NESTED, NATIVE_NESTED_PROPS, MODIFIER_KEYS, INTEGER_MODIFIERS, MODIFIER_KINDS, SCHEMA_SCORED_NODES, CORE_PACKAGES, LEGACY_UNSCORED_KEYS, DYNAMIC_PLACEHOLDER, LITERAL_ONLY_PROPS, SERVICE_ONLY_BINDING_PROPS, WHOLE_VALUE_BINDING, EMBEDDED_BINDING, OPTIONS_BINDING_PROPS;
8380
8420
  var init_validate_descriptor_core = __esm({
8381
8421
  "../../core/dev-server/src/validate-descriptor.core.ts"() {
8382
8422
  init_validator();
@@ -8395,6 +8435,12 @@ var init_validate_descriptor_core = __esm({
8395
8435
  "strict-enum"
8396
8436
  ]);
8397
8437
  BOOT_EVAL_TIMEOUT_MS = 2e3;
8438
+ DRIFT_PROBES = [
8439
+ { clock: Date.UTC(2020, 0, 1, 12, 0, 0, 0), seed: 1 },
8440
+ // a Wednesday, the 1st/2nd, everywhere in -11h…+14h
8441
+ { clock: Date.UTC(2021, 7, 28, 19, 35, 57, 789), seed: 1, mirrorRandom: true }
8442
+ // a Saturday or Sunday, the 28th/29th
8443
+ ];
8398
8444
  DEVICE_PARITY_WITHHELD = [
8399
8445
  "setTimeout",
8400
8446
  "clearTimeout",
@@ -9388,25 +9434,10 @@ function preludeFor(opts) {
9388
9434
  var consoleJson = "";
9389
9435
  var stringify = JSON.stringify;
9390
9436
  ${GUEST_NONFINITE_CODEC}${opts.seed === void 0 ? "" : `
9391
- // mulberry32, bit-identical to the host's seeded Math in validate-descriptor.core.ts. Math.imul
9392
- // and the >>> 0 coercions are what keep it identical: the algorithm is defined over 32-bit
9393
- // integers, and float arithmetic would drift apart after a handful of draws. Installed
9394
- // non-writable so a bundle cannot put the engine's PRNG back and make a seeded run vary.
9395
- (function () {
9396
- var s = (${Math.trunc(opts.seed) >>> 0}) || 1;
9397
- var $imul = Math.imul;
9398
- Object.defineProperty(Math, "random", {
9399
- value: function () {
9400
- s = (s + 0x6d2b79f5) >>> 0;
9401
- var t = $imul(s ^ (s >>> 15), 1 | s);
9402
- t = (t + $imul(t ^ (t >>> 7), 61 | t)) ^ t;
9403
- return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
9404
- },
9405
- enumerable: true,
9406
- configurable: false,
9407
- writable: false,
9408
- });
9409
- })();
9437
+ // A seeded Math \u2014 a copy of this realm's own, whose \`random\` is mulberry32, non-writable so a
9438
+ // bundle cannot put the engine's PRNG back and make a seeded run vary. The same source every
9439
+ // realm evaluates, so the stream is bit-identical to node:vm's by construction.
9440
+ globalThis.Math = (${pinnedIntrinsicsSource({ seed: opts.seed, ...opts.mirrorRandom ? { mirrorRandom: true } : {} })})(Date, Math).Math;
9410
9441
  `}
9411
9442
  var parse = JSON.parse;
9412
9443
  var stringValue = String;
@@ -9733,7 +9764,7 @@ ${opts.liveTransport ? ` var handle = { getState: function () { return def
9733
9764
  // GREEN on exactly the floor gate this realm exists to enforce. The URL family is never
9734
9765
  // installed here at all, which is why only these four need the guard.
9735
9766
  ${timerGlobals(opts.hide, opts.liveTransport === true)}
9736
- ${opts.clock !== void 0 ? ` globalThis.Date.now = function () { return ${opts.clock}; };` : ""}${opts.liveTransport ? `
9767
+ ${opts.clock === void 0 ? "" : opts.freezeDate ? ` globalThis.Date = (${pinnedIntrinsicsSource({ clock: opts.clock })})(globalThis.Date, Math).Date;` : ` globalThis.Date.now = function () { return ${opts.clock}; };`}${opts.liveTransport ? `
9737
9768
  // THE LOAD SWEEP, INSIDE THE GUEST. It has to live here: the service definitions are
9738
9769
  // closure-held and deliberately unnameable from guest code, so the host cannot reach the action
9739
9770
  // FUNCTIONS at all \u2014 which is precisely why the sync realm could not run them and silently
@@ -9877,7 +9908,17 @@ async function createQuickJsEvaluator(options = {}) {
9877
9908
  let readback = null;
9878
9909
  try {
9879
9910
  const pre = ctx.evalCode(
9880
- preludeFor({ input: himalaya?.input ?? {}, captureConsole, clock: options.clock, hide: opts.hide }),
9911
+ // A per-run clock/seed (#3049's drift probe) wins over the realm-wide pinned clock. Built
9912
+ // in the guest from the guest's own intrinsics, like every realm's (`pinnedIntrinsicsSource`).
9913
+ preludeFor({
9914
+ input: himalaya?.input ?? {},
9915
+ captureConsole,
9916
+ clock: opts.clock ?? options.clock,
9917
+ freezeDate: opts.clock !== void 0,
9918
+ hide: opts.hide,
9919
+ ...opts.seed === void 0 ? {} : { seed: opts.seed },
9920
+ ...opts.mirrorRandom ? { mirrorRandom: true } : {}
9921
+ }),
9881
9922
  "himi-sandbox.js"
9882
9923
  );
9883
9924
  if (pre.error) {
@@ -19358,7 +19399,6 @@ function shouldRevealError(args) {
19358
19399
  var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
19359
19400
  var init_validation = __esm({
19360
19401
  "../../core/ts/src/validation.ts"() {
19361
- "use strict";
19362
19402
  EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
19363
19403
  URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
19364
19404
  INTEGER_RE = /^[+-]?[0-9]+$/;
@@ -22783,7 +22823,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
22783
22823
  var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
22784
22824
  var init_worker_subtree = __esm({
22785
22825
  "../../core/ts/src/worker-subtree.ts"() {
22786
- "use strict";
22787
22826
  init_worker_subtree_safe_types_generated();
22788
22827
  WORKER_SUBTREE_CEILINGS = Object.freeze({
22789
22828
  maxEncodedBytes: 65536,
@@ -22901,7 +22940,7 @@ function ensureHListStyles() {
22901
22940
  if (hListStylesInjected || typeof document === "undefined") return;
22902
22941
  hListStylesInjected = true;
22903
22942
  const el = document.createElement("style");
22904
- el.textContent = "[data-himalaya-hlist]>*{flex:0 0 auto}";
22943
+ el.textContent = HLIST_CHILD_CSS;
22905
22944
  document.head.appendChild(el);
22906
22945
  }
22907
22946
  function ensureListAnimateRuntime() {
@@ -24134,10 +24173,16 @@ function renderNode(node, ctx) {
24134
24173
  function renderInner(node, ctx) {
24135
24174
  if (!node || typeof node !== "object") return null;
24136
24175
  const { type, props, modifiers } = normalize(node);
24176
+ const hListItem = ctx.hListItem === true;
24137
24177
  if (modifiers?.theme) ctx = withTheme(ctx, modifiers.theme);
24178
+ if (ctx.hListItem) ctx = { ...ctx, hListItem: false };
24138
24179
  const pkg = node.body?.package;
24139
24180
  const C = ctx.color;
24140
24181
  const wrap = ctx.modStyle(resolveModBindings(modifiers, ctx));
24182
+ const rowItemHold = hListItem && wrap.flex == null && wrap.flexShrink == null;
24183
+ if (rowItemHold) wrap.flexShrink = 0;
24184
+ const rowItem = rowItemHold ? { flexShrink: 0 } : {};
24185
+ const itemCtx = hListItem ? { ...ctx, hListItem: true } : ctx;
24141
24186
  {
24142
24187
  const m = modifiers;
24143
24188
  const hp = boundModNumber(m?.heightPath ?? m?.height_path, ctx);
@@ -24194,25 +24239,25 @@ function renderInner(node, ctx) {
24194
24239
  if (spec) {
24195
24240
  ensureTransitionKeyframes();
24196
24241
  ensureRevealRuntime();
24197
- const inner = renderNode({ ...node, modifiers: { ...modifiers, transition: void 0, revealOnScroll: void 0 } }, ctx);
24198
- const style = { opacity: 0 };
24242
+ const inner = renderNode({ ...node, modifiers: { ...modifiers, transition: void 0, revealOnScroll: void 0 } }, itemCtx);
24243
+ const style = { opacity: 0, ...rowItem };
24199
24244
  if (spec.distance != null) style["--hm-d"] = `${spec.distance}px`;
24200
24245
  return /* @__PURE__ */ jsx6("div", { "data-himalaya-reveal": spec.animation, style, children: inner });
24201
24246
  }
24202
24247
  }
24203
24248
  if (typeof modifiers?.parallax === "number" && modifiers.parallax !== 0 && !ctx.reduceMotion()) {
24204
24249
  ensureParallaxRuntime();
24205
- const inner = renderNode({ ...node, modifiers: { ...modifiers, parallax: void 0 } }, ctx);
24206
- return /* @__PURE__ */ jsx6("div", { "data-himalaya-parallax": String(modifiers.parallax), children: inner });
24250
+ const inner = renderNode({ ...node, modifiers: { ...modifiers, parallax: void 0 } }, itemCtx);
24251
+ return /* @__PURE__ */ jsx6("div", { "data-himalaya-parallax": String(modifiers.parallax), style: rowItemHold ? rowItem : void 0, children: inner });
24207
24252
  }
24208
24253
  if (modifiers?.scrollProgress) {
24209
24254
  ensureScrollProgressRuntime();
24210
24255
  const sticky = !!modifiers.sticky;
24211
24256
  const inner = renderNode(
24212
24257
  { ...node, modifiers: { ...modifiers, scrollProgress: void 0, sticky: void 0 } },
24213
- ctx
24258
+ itemCtx
24214
24259
  );
24215
- const barStyle = { transformOrigin: "left", transform: "scaleX(0)", alignSelf: "stretch" };
24260
+ const barStyle = { transformOrigin: "left", transform: "scaleX(0)", alignSelf: "stretch", ...rowItem };
24216
24261
  if (sticky) {
24217
24262
  barStyle.position = "sticky";
24218
24263
  barStyle.top = 0;
@@ -24224,16 +24269,16 @@ function renderInner(node, ctx) {
24224
24269
  ensureVectorAnimStyles();
24225
24270
  const name = modifiers.vectorAnim;
24226
24271
  const col = C(resolveScalarStatic(modifiers.color, ctx) ?? "accentPrimary", "#116DFF");
24227
- const inner = renderNode({ ...node, modifiers: { ...modifiers, vectorAnim: void 0 } }, ctx);
24228
- return /* @__PURE__ */ jsxs3("div", { "data-himalaya-vectoranim": name, style: { position: "relative", display: "inline-flex", alignItems: "center", justifyContent: "center" }, children: [
24272
+ const inner = renderNode({ ...node, modifiers: { ...modifiers, vectorAnim: void 0 } }, itemCtx);
24273
+ return /* @__PURE__ */ jsxs3("div", { "data-himalaya-vectoranim": name, style: { position: "relative", display: "inline-flex", alignItems: "center", justifyContent: "center", ...rowItem }, children: [
24229
24274
  inner,
24230
24275
  vectorAnimSvg(name, col, 36, !ctx.reduceMotion())
24231
24276
  ] });
24232
24277
  }
24233
24278
  if (modifiers?.confetti && !ctx.reduceMotion()) {
24234
24279
  ensureConfettiRuntime();
24235
- const inner = renderNode({ ...node, modifiers: { ...modifiers, confetti: void 0 } }, ctx);
24236
- return /* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
24280
+ const inner = renderNode({ ...node, modifiers: { ...modifiers, confetti: void 0 } }, itemCtx);
24281
+ return /* @__PURE__ */ jsxs3("div", { style: { position: "relative", ...rowItem }, children: [
24237
24282
  inner,
24238
24283
  /* @__PURE__ */ jsx6("div", { "data-himalaya-confetti": true, style: { position: "absolute", inset: 0, pointerEvents: "none", overflow: "hidden" } })
24239
24284
  ] });
@@ -24255,7 +24300,8 @@ function renderInner(node, ctx) {
24255
24300
  const hasW = modifiers?.width != null || modifiers?.fillMaxWidth === true;
24256
24301
  const hasH = modifiers?.height != null;
24257
24302
  const justifyItems = zJustifyItems(props.alignment);
24258
- return /* @__PURE__ */ jsx6("div", { style: { position: "relative", display: "grid", justifyItems, alignItems: "center", ...hasW ? {} : { width: "100%" }, ...hasH ? {} : { minHeight: 40 }, ...wrap }, children: (props.children ?? []).map((c, i) => /* @__PURE__ */ jsx6("div", { style: { gridArea: "1 / 1", display: "grid", justifyItems, alignItems: "center", width: "100%" }, children: renderNode(c, ctx) }, c?.id ?? i)) });
24303
+ const fillsWidth = !hasW && !hListItem;
24304
+ return /* @__PURE__ */ jsx6("div", { style: { position: "relative", display: "grid", justifyItems, alignItems: "center", ...fillsWidth ? { width: "100%" } : {}, ...hasH ? {} : { minHeight: 40 }, ...wrap }, children: (props.children ?? []).map((c, i) => /* @__PURE__ */ jsx6("div", { style: { gridArea: "1 / 1", display: "grid", justifyItems, alignItems: "center", width: "100%" }, children: renderNode(c, ctx) }, c?.id ?? i)) });
24259
24305
  }
24260
24306
  case "LazyList": {
24261
24307
  const itemsPath = props.itemsPath ?? props.items_path;
@@ -24281,6 +24327,7 @@ function renderInner(node, ctx) {
24281
24327
  };
24282
24328
  if (props.horizontal) ensureHListStyles();
24283
24329
  const hListAttr = props.horizontal ? { "data-himalaya-hlist": "1" } : {};
24330
+ const asItem = (c) => props.horizontal ? { ...c, hListItem: true } : c;
24284
24331
  if (itemsPath && items[0] && ctx.provider) {
24285
24332
  const boundSwipe = props.rowSwipeActions ?? props.row_swipe_actions;
24286
24333
  const boundRefresh = props.onPullToRefresh ?? props.on_pull_to_refresh;
@@ -24293,7 +24340,7 @@ function renderInner(node, ctx) {
24293
24340
  itemsPath,
24294
24341
  template: items[0],
24295
24342
  renderRow: (t, ic) => {
24296
- let row = renderNode(t, ic);
24343
+ let row = renderNode(t, asItem(ic));
24297
24344
  if (boundStagger > 0 && React5.isValidElement(row)) {
24298
24345
  const i = Number(ic.itemScope?.__index ?? 0);
24299
24346
  const prev = row.props.style ?? {};
@@ -24350,7 +24397,7 @@ function renderInner(node, ctx) {
24350
24397
  if (animateItems) ensureListAnimateRuntime();
24351
24398
  const stickyHeader = props.stickyHeader ?? props.sticky_header;
24352
24399
  const stickyEl = stickyHeader && !props.horizontal ? /* @__PURE__ */ jsx6("div", { style: { position: "sticky", top: 0, zIndex: 2, background: C("surfacePrimary", "#fff") }, children: renderNode(stickyHeader, ctx) }) : null;
24353
- const rendered = staggerMs > 0 ? staggeredKids(items, ctx, staggerMs) : kids(items, ctx);
24400
+ const rendered = staggerMs > 0 ? staggeredKids(items, asItem(ctx), staggerMs) : kids(items, asItem(ctx));
24354
24401
  let body = rendered;
24355
24402
  if (swipe && ctx.onAction && !props.horizontal) {
24356
24403
  const leading = swipe.leading ?? [];
@@ -24422,7 +24469,7 @@ function renderInner(node, ctx) {
24422
24469
  return /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center", width: "100%", padding: 12, boxSizing: "border-box", ...wrap }, children: [
24423
24470
  /* @__PURE__ */ jsx6("div", { style: { width: 46, height: 46, borderRadius: 13, background: C("surfaceTertiary", "#eee"), display: "grid", placeItems: "center", margin: "0 auto 12px", color: C("textSecondary", "#9aa2ad") }, children: iconSvg(props.icon, { size: 24 }) }),
24424
24471
  /* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontWeight: 600, fontSize: 16, color: C("textPrimary", "#111") }, children: asBoundText(props.title, ctx) || "Empty" }),
24425
- props.subtitle && /* @__PURE__ */ jsx6("div", { style: { fontSize: 13, color: C("textSecondary", "#888"), marginTop: 3 }, children: txt(props.subtitle, ctx) }),
24472
+ props.subtitle && /* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontSize: 13, color: C("textSecondary", "#888"), marginTop: 3 }, children: txt(props.subtitle, ctx) }),
24426
24473
  actionTextButton(ctx, props.action, asBoundText(props.actionLabel, ctx) || "Take action", C("accentPrimary", "#116DFF"), { margin: "12px auto 0", textAlign: "center" })
24427
24474
  ] });
24428
24475
  // ───────────── atoms ─────────────
@@ -24767,7 +24814,7 @@ function renderInner(node, ctx) {
24767
24814
  /* @__PURE__ */ jsx6("div", { style: { width: 3, borderRadius: 3, background: accent, flex: "none" } }),
24768
24815
  /* @__PURE__ */ jsxs3("div", { children: [
24769
24816
  /* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontWeight: 600, fontSize: 14, color: C("textPrimary", "#111") }, children: txt(props.title, ctx) }),
24770
- props.message && /* @__PURE__ */ jsx6("div", { style: { fontSize: 13, lineHeight: 1.4, color: C("textSecondary", "#666"), marginTop: 2 }, children: txt(props.message, ctx) }),
24817
+ props.message && /* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontSize: 13, lineHeight: 1.4, color: C("textSecondary", "#666"), marginTop: 2 }, children: txt(props.message, ctx) }),
24771
24818
  actionTextButton(ctx, props.action, asBoundText(props.actionLabel, ctx) || "Take action", C("textPrimary", "#111"), { marginTop: 7, textDecoration: "underline" })
24772
24819
  ] })
24773
24820
  ] });
@@ -24783,7 +24830,7 @@ function renderInner(node, ctx) {
24783
24830
  case "AlertDialog":
24784
24831
  return /* @__PURE__ */ jsxs3("div", { role: "alertdialog", "aria-modal": "true", "aria-label": props.title != null ? asBoundText(props.title, ctx) : "Alert", style: { background: C("surfacePrimary", "#fff"), borderRadius: ctx.radius("lg", 14), padding: 18, width: "100%", boxSizing: "border-box", border: `1px solid ${C("border", "#e3e3e3")}`, boxShadow: "0 12px 30px -12px rgba(0,0,0,.4)", ...wrap }, children: [
24785
24832
  /* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontWeight: 700, fontSize: 17, color: C("textPrimary", "#111") }, children: txt(props.title, ctx) }),
24786
- /* @__PURE__ */ jsx6("div", { style: { fontSize: 14, lineHeight: 1.45, color: C("textSecondary", "#666"), margin: "6px 0 16px" }, children: txt(props.message, ctx) }),
24833
+ /* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontSize: 14, lineHeight: 1.45, color: C("textSecondary", "#666"), margin: "6px 0 16px" }, children: txt(props.message, ctx) }),
24787
24834
  /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: 10 }, children: [
24788
24835
  props.cancelAction != null && /* @__PURE__ */ jsx6("button", { type: "button", onClick: actionClick(ctx, props.cancelAction), style: { flex: 1, textAlign: "center", padding: 11, borderRadius: ctx.radius("md", 8), appearance: "none", WebkitAppearance: "none", border: "none", fontFamily: bodyFont(ctx), fontWeight: 600, fontSize: 15, background: C("surfaceTertiary", "#eee"), color: C("textPrimary", "#111"), cursor: ctx.onAction ? "pointer" : "default" }, children: asBoundText(props.cancelLabel, ctx) || "Cancel" }),
24789
24836
  props.confirmAction != null && /* @__PURE__ */ jsx6("button", { type: "button", onClick: actionClick(ctx, props.confirmAction), style: { flex: 1, textAlign: "center", padding: 11, borderRadius: ctx.radius("md", 8), appearance: "none", WebkitAppearance: "none", border: "none", fontFamily: bodyFont(ctx), fontWeight: 600, fontSize: 15, background: props.destructive ? C("danger", "#E62214") : C("accentPrimary", "#116DFF"), color: "#fff", cursor: ctx.onAction ? "pointer" : "default" }, children: asBoundText(props.confirmLabel, ctx) || (props.destructive ? "Delete" : "Confirm") })
@@ -24804,7 +24851,7 @@ function renderInner(node, ctx) {
24804
24851
  }
24805
24852
  }
24806
24853
  }
24807
- var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, 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, 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, WebRenderer;
24854
+ 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, 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, WebRenderer;
24808
24855
  var init_renderNode = __esm({
24809
24856
  "../../core/web-renderer/src/renderNode.tsx"() {
24810
24857
  "use strict";
@@ -24890,6 +24937,7 @@ var init_renderNode = __esm({
24890
24937
  pressStylesInjected = false;
24891
24938
  FOCUS_RING_CSS = ':where(button,a,[href],input,select,textarea,[role="button"],[tabindex]):focus-visible{outline:2px solid var(--himi-accent,#116DFF);outline-offset:2px;border-radius:4px}';
24892
24939
  focusStylesInjected = false;
24940
+ HLIST_CHILD_CSS = "[data-himalaya-hlist]>*{flex:0 0 auto}";
24893
24941
  hListStylesInjected = false;
24894
24942
  listAnimateRuntimeInstalled = false;
24895
24943
  transitionKeyframesInjected = false;
@@ -28279,13 +28327,16 @@ var init_src3 = __esm({
28279
28327
  // ../../core/dev-server/src/render-descriptor.ts
28280
28328
  var render_descriptor_exports = {};
28281
28329
  __export(render_descriptor_exports, {
28330
+ HOST_PAGE_FONT: () => HOST_PAGE_FONT,
28282
28331
  buildRenderTree: () => buildRenderTree,
28283
28332
  clientEnvFor: () => clientEnvFor,
28284
28333
  collectNativeOnly: () => collectNativeOnly,
28285
28334
  isMissingPlaywrightExecutable: () => isMissingPlaywrightExecutable,
28286
28335
  pngAvailable: () => pngAvailable,
28336
+ pngPageHtml: () => pngPageHtml,
28287
28337
  renderDescriptorWeb: () => renderDescriptorWeb,
28288
28338
  renderPngBatch: () => renderPngBatch,
28339
+ setPngFontCss: () => setPngFontCss,
28289
28340
  stabilizePngPage: () => stabilizePngPage,
28290
28341
  withRetry: () => withRetry2
28291
28342
  });
@@ -28518,7 +28569,7 @@ async function renderDescriptorWeb(descriptor, tokens, scheme, wantPng, services
28518
28569
  const nativeOnly = collectNativeOnly(renderTree);
28519
28570
  if (nativeOnly.length) result.nativeOnly = nativeOnly;
28520
28571
  if (wantPng) {
28521
- const png = await renderPng(html, scheme, width, isRTL);
28572
+ const png = await renderPng(html, scheme, width, isRTL, tokens);
28522
28573
  if (png) result.pngBase64 = png;
28523
28574
  else result.pngUnavailable = true;
28524
28575
  }
@@ -28535,10 +28586,24 @@ async function withRetry2(op, attempts = 2) {
28535
28586
  }
28536
28587
  throw lastErr;
28537
28588
  }
28538
- async function renderPng(html, scheme, width, isRTL) {
28539
- const out = await renderPngBatch([{ html, scheme, width, isRTL }]);
28589
+ async function renderPng(html, scheme, width, isRTL, tokens) {
28590
+ const out = await renderPngBatch([{ html, scheme, width, isRTL, tokens }]);
28540
28591
  return out?.[0] ?? null;
28541
28592
  }
28593
+ function setPngFontCss(source) {
28594
+ const previous = pngFontCss;
28595
+ pngFontCss = source;
28596
+ return previous;
28597
+ }
28598
+ async function pngPageHtml(item) {
28599
+ let faces = "";
28600
+ try {
28601
+ faces = await pngFontCss?.(item.tokens ?? null) ?? "";
28602
+ } catch {
28603
+ faces = "";
28604
+ }
28605
+ return `<!doctype html><html${item.isRTL ? ' dir="rtl"' : ""}><head><meta charset="utf-8"><style>${faces}body{font-family:${HOST_PAGE_FONT}}</style></head><body style="margin:0">${item.html}</body></html>`;
28606
+ }
28542
28607
  function isMissingPlaywrightExecutable(error) {
28543
28608
  const message = error?.message ?? "";
28544
28609
  return /Executable doesn't exist at/.test(message) && /playwright install/.test(message);
@@ -28598,10 +28663,7 @@ async function renderPngBatch(items) {
28598
28663
  try {
28599
28664
  const page = await browser.newPage({ colorScheme: it.scheme, ...it.width && it.width > 0 ? { viewport: { width: Math.round(it.width), height: 900 } } : {} });
28600
28665
  try {
28601
- await page.setContent(
28602
- `<!doctype html><html${it.isRTL ? ' dir="rtl"' : ""}><head><meta charset="utf-8"></head><body style="margin:0">${it.html}</body></html>`,
28603
- { waitUntil: "load" }
28604
- );
28666
+ await page.setContent(await pngPageHtml(it), { waitUntil: "load" });
28605
28667
  await stabilizePngPage(page, it.scheme);
28606
28668
  const buf = await page.screenshot({ fullPage: true });
28607
28669
  out.push(Buffer.from(buf).toString("base64"));
@@ -28619,7 +28681,7 @@ async function renderPngBatch(items) {
28619
28681
  });
28620
28682
  }
28621
28683
  }
28622
- var TREE_TEXT_VALUE_PROPS, asStringOrNumber, asStringOnly, asOtpCode, VALUE_PATH_TEXT, MEDIA_PLAYER_QUEUE_PROPERTIES, NATIVE_ONLY_TYPES;
28684
+ var TREE_TEXT_VALUE_PROPS, asStringOrNumber, asStringOnly, asOtpCode, VALUE_PATH_TEXT, MEDIA_PLAYER_QUEUE_PROPERTIES, NATIVE_ONLY_TYPES, HOST_PAGE_FONT, pngFontCss;
28623
28685
  var init_render_descriptor = __esm({
28624
28686
  "../../core/dev-server/src/render-descriptor.ts"() {
28625
28687
  init_FakeServiceProvider();
@@ -28642,6 +28704,111 @@ var init_render_descriptor = __esm({
28642
28704
  ]);
28643
28705
  MEDIA_PLAYER_QUEUE_PROPERTIES = /* @__PURE__ */ new Set(["items", "itemsPath", "items_path"]);
28644
28706
  NATIVE_ONLY_TYPES = /* @__PURE__ */ new Set(["Map", "Video", "Lottie", "Rive", "WebView"]);
28707
+ HOST_PAGE_FONT = '"Wix Madefor Text", system-ui, sans-serif';
28708
+ }
28709
+ });
28710
+
28711
+ // ../../core/dev-server/src/render-fonts.ts
28712
+ import { existsSync as existsSync34, readFileSync as readFileSync34 } from "node:fs";
28713
+ import { extname, join as join31 } from "node:path";
28714
+ function servedFontFaces(appDir2, tokens) {
28715
+ try {
28716
+ const policyPath = join31(appDir2, "fonts.json");
28717
+ const policy = existsSync34(policyPath) ? JSON.parse(readFileSync34(policyPath, "utf8")) : {};
28718
+ let plan = planFonts(tokens, policy);
28719
+ if (!hasVendoredFloor()) plan = { ...plan, families: plan.families.filter((f) => !isHostProvided(f.name)) };
28720
+ if (plan.families.length === 0) return void 0;
28721
+ return servedProjection(plan);
28722
+ } catch {
28723
+ return void 0;
28724
+ }
28725
+ }
28726
+ function withServedFontFaces(tokens, appDir2) {
28727
+ const fontFaces = servedFontFaces(appDir2, tokens);
28728
+ return fontFaces ? { ...tokens, fontFaces } : tokens;
28729
+ }
28730
+ function declaredFamilies(tokens) {
28731
+ const decl = tokens?.fontFaces;
28732
+ return decl && typeof decl === "object" && !Array.isArray(decl) ? Object.keys(decl) : [];
28733
+ }
28734
+ async function faceBytes(face, catalog, opts) {
28735
+ try {
28736
+ if (opts.source) {
28737
+ const path = opts.source(face.file, face.sha256);
28738
+ return path ? readFileSync34(path) : null;
28739
+ }
28740
+ const bytes2 = await catalogFaceBytes(face.sha256, { catalog, ...opts.fetchFace ? { fetchFace: opts.fetchFace } : {} });
28741
+ return bytes2 ?? null;
28742
+ } catch {
28743
+ return null;
28744
+ }
28745
+ }
28746
+ async function pngFontFaceCss(tokens, opts = {}) {
28747
+ const cache = opts.source || opts.fetchFace ? void 0 : encoded;
28748
+ let catalog;
28749
+ try {
28750
+ catalog = opts.catalog ?? loadCatalog();
28751
+ } catch {
28752
+ return "";
28753
+ }
28754
+ const wanted = [];
28755
+ const seen = /* @__PURE__ */ new Set();
28756
+ const want = (family, face, variable) => {
28757
+ const key2 = `${family}\0${face.sha256}`;
28758
+ if (seen.has(key2)) return;
28759
+ seen.add(key2);
28760
+ wanted.push({ family, face, variable });
28761
+ };
28762
+ for (const [name, family] of Object.entries(catalog.bundled)) {
28763
+ for (const face of family.faces) want(name, face, family.variable);
28764
+ }
28765
+ let planned = [];
28766
+ try {
28767
+ planned = planFonts(tokens ?? {}, { families: declaredFamilies(tokens) }, catalog).families;
28768
+ } catch {
28769
+ planned = [];
28770
+ }
28771
+ for (const family of planned) {
28772
+ if (family.builtin) continue;
28773
+ for (const face of family.faces) want(family.name, face, family.variable);
28774
+ }
28775
+ const data = await Promise.all(
28776
+ wanted.map(async ({ face }) => {
28777
+ const hit = cache?.get(face.sha256);
28778
+ if (hit !== void 0) return hit;
28779
+ const bytes2 = await faceBytes(face, catalog, opts);
28780
+ if (!bytes2) return null;
28781
+ const b64 = bytes2.toString("base64");
28782
+ cache?.set(face.sha256, b64);
28783
+ return b64;
28784
+ })
28785
+ );
28786
+ const rules = [];
28787
+ wanted.forEach(({ family, face, variable }, i) => {
28788
+ const b64 = data[i];
28789
+ if (b64 == null) return;
28790
+ const [mime, format] = FORMATS[extname(face.file).toLowerCase()] ?? ["font/ttf", "truetype"];
28791
+ const wght = variable?.axes?.["wght"];
28792
+ const weight = wght ? `${wght.min} ${wght.max}` : String(face.weight);
28793
+ rules.push(
28794
+ `@font-face{font-family:${cssString(family)};font-weight:${weight};font-style:${face.style ?? "normal"};font-display:block;src:url(data:${mime};base64,${b64}) format("${format}")}`
28795
+ );
28796
+ });
28797
+ return rules.join("");
28798
+ }
28799
+ var encoded, cssString, FORMATS;
28800
+ var init_render_fonts = __esm({
28801
+ "../../core/dev-server/src/render-fonts.ts"() {
28802
+ init_catalog();
28803
+ init_plan_fonts();
28804
+ init_face_source();
28805
+ encoded = /* @__PURE__ */ new Map();
28806
+ cssString = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/</g, "\\3c ").replace(/\n/g, "\\a ")}"`;
28807
+ FORMATS = {
28808
+ ".woff2": ["font/woff2", "woff2"],
28809
+ ".woff": ["font/woff", "woff"],
28810
+ ".otf": ["font/otf", "opentype"]
28811
+ };
28645
28812
  }
28646
28813
  });
28647
28814
 
@@ -29518,7 +29685,7 @@ var init_src5 = __esm({
29518
29685
  });
29519
29686
 
29520
29687
  // ../../core/dev-server/src/flags/index.ts
29521
- import { readFileSync as readFileSync34 } from "node:fs";
29688
+ import { readFileSync as readFileSync35 } from "node:fs";
29522
29689
  import { resolve as resolve26 } from "node:path";
29523
29690
  function selectProvider(config, store) {
29524
29691
  const local = new LocalFlagProvider(store, () => config?.overrides);
@@ -29614,7 +29781,7 @@ var init_flags2 = __esm({
29614
29781
  if (now - this.lastFetch < this.ttlMs) return;
29615
29782
  this.lastFetch = now;
29616
29783
  try {
29617
- const defs = JSON.parse(readFileSync34(resolve26(appDir2, "flags.json"), "utf8"));
29784
+ const defs = JSON.parse(readFileSync35(resolve26(appDir2, "flags.json"), "utf8"));
29618
29785
  if (Array.isArray(defs) && defs.length > 0) store.replaceAll(defs);
29619
29786
  } catch {
29620
29787
  }
@@ -29664,19 +29831,19 @@ var init_motion_flags = __esm({
29664
29831
  });
29665
29832
 
29666
29833
  // ../../core/dev-server/src/kits.ts
29667
- import { readdirSync as readdirSync17, readFileSync as readFileSync35 } from "node:fs";
29668
- import { resolve as resolve27, join as join31 } from "node:path";
29834
+ import { readdirSync as readdirSync17, readFileSync as readFileSync36 } from "node:fs";
29835
+ import { resolve as resolve27, join as join32 } from "node:path";
29669
29836
  import { fileURLToPath as fileURLToPath16 } from "node:url";
29670
29837
  function listKits() {
29671
29838
  return readdirSync17(CATALOG).filter((f) => f.endsWith(".json")).map((f) => {
29672
- const { tokens, ...meta } = JSON.parse(readFileSync35(join31(CATALOG, f), "utf8"));
29839
+ const { tokens, ...meta } = JSON.parse(readFileSync36(join32(CATALOG, f), "utf8"));
29673
29840
  return meta;
29674
29841
  });
29675
29842
  }
29676
29843
  function readKit(id) {
29677
29844
  if (!/^[a-z0-9-]+$/.test(id)) return null;
29678
29845
  try {
29679
- return JSON.parse(readFileSync35(join31(CATALOG, `${id}.json`), "utf8"));
29846
+ return JSON.parse(readFileSync36(join32(CATALOG, `${id}.json`), "utf8"));
29680
29847
  } catch {
29681
29848
  return null;
29682
29849
  }
@@ -29685,7 +29852,7 @@ var ROOT5, CATALOG;
29685
29852
  var init_kits = __esm({
29686
29853
  "../../core/dev-server/src/kits.ts"() {
29687
29854
  ROOT5 = resolve27(fileURLToPath16(new URL("../../..", import.meta.url)));
29688
- CATALOG = join31(ROOT5, "stdlib/design-kits");
29855
+ CATALOG = join32(ROOT5, "stdlib/design-kits");
29689
29856
  }
29690
29857
  });
29691
29858
 
@@ -30414,8 +30581,10 @@ __export(validate_descriptor_exports, {
30414
30581
  nativeRequiredFindings: () => nativeRequiredFindings,
30415
30582
  navLogicBundleUrl: () => navLogicBundleUrl,
30416
30583
  nodeVmEvaluator: () => nodeVmEvaluator,
30584
+ nondeterministicServices: () => nondeterministicServices,
30417
30585
  pathCrossesOpaqueAuthorJson: () => pathCrossesOpaqueAuthorJson,
30418
30586
  pathValue: () => pathValue,
30587
+ pinnedIntrinsicsSource: () => pinnedIntrinsicsSource,
30419
30588
  readBuiltBundle: () => readBuiltBundle,
30420
30589
  readBuiltBundleMap: () => readBuiltBundleMap,
30421
30590
  resolveActionEvaluator: () => resolveActionEvaluator,
@@ -30428,12 +30597,12 @@ __export(validate_descriptor_exports, {
30428
30597
  validateScreenDescriptor: () => validateScreenDescriptor,
30429
30598
  workerSubtreeAllowed: () => workerSubtreeAllowed
30430
30599
  });
30431
- import { readFileSync as readFileSync36, existsSync as existsSync34, readdirSync as readdirSync18 } from "node:fs";
30600
+ import { readFileSync as readFileSync37, existsSync as existsSync35, readdirSync as readdirSync18 } from "node:fs";
30432
30601
  import { resolve as resolve28 } from "node:path";
30433
- import { runInNewContext } from "node:vm";
30602
+ import { createContext, runInContext } from "node:vm";
30434
30603
  async function loadAllowedComponents(appDir2) {
30435
30604
  const modPath = resolve28(appDir2, "components.ts");
30436
- if (!existsSync34(modPath)) return void 0;
30605
+ if (!existsSync35(modPath)) return void 0;
30437
30606
  try {
30438
30607
  const { pathToFileURL: pathToFileURL8 } = await import("node:url");
30439
30608
  const mod = await import(pathToFileURL8(modPath).href);
@@ -30446,7 +30615,7 @@ async function loadAllowedComponents(appDir2) {
30446
30615
  }
30447
30616
  function readBuiltBundle(tier5Root, bundleName) {
30448
30617
  const p = resolve28(tier5Root, `${bundleName}.bundle.js`);
30449
- return existsSync34(p) ? readFileSync36(p, "utf8") : void 0;
30618
+ return existsSync35(p) ? readFileSync37(p, "utf8") : void 0;
30450
30619
  }
30451
30620
  function bundleNameFromUrl(url) {
30452
30621
  if (typeof url !== "string") return null;
@@ -30474,10 +30643,10 @@ function appWorkerActionsFor(config, tier5Root) {
30474
30643
  }
30475
30644
  function readBuiltBundleMap(tier5Root, bundleName) {
30476
30645
  const p = resolve28(tier5Root, `${bundleName}.bundle.js.map`);
30477
- return existsSync34(p) ? readFileSync36(p, "utf8") : void 0;
30646
+ return existsSync35(p) ? readFileSync37(p, "utf8") : void 0;
30478
30647
  }
30479
30648
  function nativeSourceFiles(directory, extension, buildDirMaxDepth, depth = 1) {
30480
- if (!existsSync34(directory)) return [];
30649
+ if (!existsSync35(directory)) return [];
30481
30650
  let entries;
30482
30651
  try {
30483
30652
  entries = readdirSync18(directory, { withFileTypes: true });
@@ -30497,12 +30666,12 @@ function registeredActions(source) {
30497
30666
  return [...source.matchAll(/ActionDispatcher(?:\.shared)?\s*\.\s*register\s*\(\s*"([A-Za-z0-9_.]+)"/g)].map((match) => match[1]);
30498
30667
  }
30499
30668
  function discoverNativeActions(appDir2) {
30500
- const roots = NATIVE_SOURCE_ROOTS.filter(({ directory }) => existsSync34(resolve28(appDir2, directory)));
30669
+ const roots = NATIVE_SOURCE_ROOTS.filter(({ directory }) => existsSync35(resolve28(appDir2, directory)));
30501
30670
  const sources = roots.flatMap(({ directory, extension, buildDirMaxDepth }) => nativeSourceFiles(resolve28(appDir2, directory), extension, buildDirMaxDepth));
30502
30671
  const registered = sources.flatMap((source) => {
30503
30672
  let text4;
30504
30673
  try {
30505
- text4 = readFileSync36(source, "utf8");
30674
+ text4 = readFileSync37(source, "utf8");
30506
30675
  } catch (err) {
30507
30676
  if (!vanished(err)) throw err;
30508
30677
  return [];
@@ -30521,7 +30690,14 @@ var init_validate_descriptor = __esm({
30521
30690
  init_validate_descriptor_core();
30522
30691
  nodeVmEvaluator = {
30523
30692
  run(code, sandbox, opts) {
30524
- runInNewContext(code, sandbox, { timeout: opts.timeoutMs, filename: opts.filename });
30693
+ const context = createContext(sandbox);
30694
+ const pins = pinnedIntrinsicsSource(opts);
30695
+ if (pins) {
30696
+ const pinned = runInContext(`(${pins})(Date, Math)`, context, { timeout: opts.timeoutMs, filename: "himi-pins.js" });
30697
+ if (pinned.Date) sandbox.Date = pinned.Date;
30698
+ if (pinned.Math) sandbox.Math = pinned.Math;
30699
+ }
30700
+ runInContext(code, context, { timeout: opts.timeoutMs, filename: opts.filename });
30525
30701
  }
30526
30702
  };
30527
30703
  setDefaultEvaluator(nodeVmEvaluator);
@@ -30619,8 +30795,8 @@ __export(config_exports2, {
30619
30795
  serializeRolloutYaml: () => serializeRolloutYaml,
30620
30796
  validateOverlayPatch: () => validateOverlayPatch
30621
30797
  });
30622
- import { mkdirSync as mkdirSync15, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "node:fs";
30623
- import { dirname as dirname20, join as join32, resolve as resolve29 } from "node:path";
30798
+ import { mkdirSync as mkdirSync15, readFileSync as readFileSync38, writeFileSync as writeFileSync12 } from "node:fs";
30799
+ import { dirname as dirname20, join as join33, resolve as resolve29 } from "node:path";
30624
30800
  import { fileURLToPath as fileURLToPath17 } from "node:url";
30625
30801
  function strip(line) {
30626
30802
  const h = line.indexOf("#");
@@ -30685,14 +30861,14 @@ function parseRevocationsYaml(text4) {
30685
30861
  function appConfigPath(app, file, root = REPO_ROOT6) {
30686
30862
  assertAppId(app, "appConfigPath");
30687
30863
  for (const base of ["apps", "test-apps"]) {
30688
- const p = join32(root, base, app, file);
30864
+ const p = join33(root, base, app, file);
30689
30865
  try {
30690
- readFileSync37(p);
30866
+ readFileSync38(p);
30691
30867
  return p;
30692
30868
  } catch {
30693
30869
  }
30694
30870
  }
30695
- return join32(root, "apps", app, file);
30871
+ return join33(root, "apps", app, file);
30696
30872
  }
30697
30873
  function serializeRolloutYaml(cfg) {
30698
30874
  const lines = [`app: ${cfg.app}`, "rings:"];
@@ -30740,7 +30916,7 @@ function validateOverlayPatch(patch) {
30740
30916
  }
30741
30917
  function readJsonAt(app, file, root) {
30742
30918
  try {
30743
- return JSON.parse(readFileSync37(appConfigPath(app, file, root), "utf8"));
30919
+ return JSON.parse(readFileSync38(appConfigPath(app, file, root), "utf8"));
30744
30920
  } catch {
30745
30921
  return null;
30746
30922
  }
@@ -30778,14 +30954,14 @@ function saveLocalFlags(app, defs, root = REPO_ROOT6) {
30778
30954
  }
30779
30955
  function loadRollout(app) {
30780
30956
  try {
30781
- return parseRolloutYaml(readFileSync37(appConfigPath(app, "rollout.yaml"), "utf8"));
30957
+ return parseRolloutYaml(readFileSync38(appConfigPath(app, "rollout.yaml"), "utf8"));
30782
30958
  } catch {
30783
30959
  return null;
30784
30960
  }
30785
30961
  }
30786
30962
  function loadRevocations(app) {
30787
30963
  try {
30788
- return parseRevocationsYaml(readFileSync37(appConfigPath(app, "revocations.yaml"), "utf8")).revoked;
30964
+ return parseRevocationsYaml(readFileSync38(appConfigPath(app, "revocations.yaml"), "utf8")).revoked;
30789
30965
  } catch {
30790
30966
  return [];
30791
30967
  }
@@ -30863,8 +31039,8 @@ var init_config2 = __esm({
30863
31039
  // ../../core/dev-server/src/index.ts
30864
31040
  import { createServer as createServer2 } from "node:http";
30865
31041
  import { readFile, stat } from "node:fs/promises";
30866
- import { readFileSync as readFileSync38, existsSync as existsSync35, watch, mkdirSync as mkdirSync16, rmSync as rmSync5 } from "node:fs";
30867
- import { extname, resolve as resolve30, normalize as normalize3, sep as sep7, join as join33 } from "node:path";
31042
+ import { readFileSync as readFileSync39, existsSync as existsSync36, watch, mkdirSync as mkdirSync16, rmSync as rmSync5 } from "node:fs";
31043
+ import { extname as extname2, resolve as resolve30, normalize as normalize3, sep as sep7 } from "node:path";
30868
31044
  import { createHash as createHash15, randomUUID } from "node:crypto";
30869
31045
  import { fileURLToPath as fileURLToPath18, pathToFileURL as pathToFileURL6 } from "node:url";
30870
31046
  function deepMerge3(base, patch) {
@@ -30914,7 +31090,7 @@ function readAppTokens(state) {
30914
31090
  if (!state.app) return null;
30915
31091
  try {
30916
31092
  const tokenPath = state.app.module.designTokensPath ?? resolve30(state.app.dir, state.app.module.config.designTokensPath ?? "tokens.json");
30917
- const parsed = JSON.parse(readFileSync38(tokenPath, "utf8"));
31093
+ const parsed = JSON.parse(readFileSync39(tokenPath, "utf8"));
30918
31094
  delete parsed._meta;
30919
31095
  return parsed;
30920
31096
  } catch {
@@ -30926,7 +31102,7 @@ function effectiveAppConfigOverride(state) {
30926
31102
  if (state.app) {
30927
31103
  try {
30928
31104
  gitOverlay = JSON.parse(
30929
- readFileSync38(resolve30(state.app.dir, "app-config.overlay.json"), "utf8")
31105
+ readFileSync39(resolve30(state.app.dir, "app-config.overlay.json"), "utf8")
30930
31106
  );
30931
31107
  } catch {
30932
31108
  }
@@ -30986,7 +31162,7 @@ function handleL10nRequest(req, res, state) {
30986
31162
  return sendJson(res, 404, { error: "unknown_app", app }, cors);
30987
31163
  }
30988
31164
  const path = resolve30(state.app.dir, "l10n", `${tag}.json`);
30989
- if (!existsSync35(path)) {
31165
+ if (!existsSync36(path)) {
30990
31166
  res.writeHead(204, cors);
30991
31167
  res.end();
30992
31168
  return;
@@ -30995,7 +31171,7 @@ function handleL10nRequest(req, res, state) {
30995
31171
  let messages;
30996
31172
  try {
30997
31173
  messages = Object.fromEntries(
30998
- keyMap(parseCatalog(readFileSync38(path, "utf8")), { sourceFallback: tag === sourceLocale })
31174
+ keyMap(parseCatalog(readFileSync39(path, "utf8")), { sourceFallback: tag === sourceLocale })
30999
31175
  );
31000
31176
  } catch {
31001
31177
  return sendJson(res, 500, { error: "catalog_unreadable", app, tag }, cors);
@@ -31040,18 +31216,6 @@ async function runScreenDiagnostics(state, screenId, descriptor) {
31040
31216
  evidence: { runId: `dev:${state.startedAt}:${screenId}`, ts: (/* @__PURE__ */ new Date()).toISOString() }
31041
31217
  });
31042
31218
  }
31043
- function servedFontFaces(appDir2, tokens) {
31044
- try {
31045
- const policyPath = join33(appDir2, "fonts.json");
31046
- const policy = existsSync35(policyPath) ? JSON.parse(readFileSync38(policyPath, "utf8")) : {};
31047
- let plan = planFonts(tokens, policy);
31048
- if (!hasVendoredFloor()) plan = { ...plan, families: plan.families.filter((f) => !isHostProvided(f.name)) };
31049
- if (plan.families.length === 0) return void 0;
31050
- return servedProjection(plan);
31051
- } catch {
31052
- return void 0;
31053
- }
31054
- }
31055
31219
  async function fontFaceBytesBySha(_appDir, sha) {
31056
31220
  try {
31057
31221
  return await catalogFaceBytes(sha);
@@ -31399,7 +31563,7 @@ async function buildDescriptorForScreenId(state, screenId, query = new URLSearch
31399
31563
  function bundleIntegritySync(name, dir) {
31400
31564
  for (const root of dir ? [dir, TIER5_ROOT2] : [TIER5_ROOT2]) {
31401
31565
  try {
31402
- const bytes2 = readFileSync38(resolve30(root, `${name}.bundle.js`));
31566
+ const bytes2 = readFileSync39(resolve30(root, `${name}.bundle.js`));
31403
31567
  return "sha256-" + createHash15("sha256").update(bytes2).digest("base64");
31404
31568
  } catch {
31405
31569
  }
@@ -32174,9 +32338,10 @@ async function handleDev(req, res, state) {
32174
32338
  }
32175
32339
  const screenId = descriptor.screenId ?? body.screenId ?? "render";
32176
32340
  const diagnostics = await runScreenDiagnostics(state, screenId, descriptor);
32341
+ const appTokens = readAppTokens(state);
32177
32342
  const render = await renderDescriptorWeb(
32178
32343
  descriptor,
32179
- readAppTokens(state),
32344
+ appTokens && state.app ? withServedFontFaces(appTokens, state.app.dir) : appTokens,
32180
32345
  scheme,
32181
32346
  body.png === true,
32182
32347
  body.services ?? null,
@@ -32980,8 +33145,8 @@ function readActionHandlerManifest(app) {
32980
33145
  let decls;
32981
33146
  let bytes2;
32982
33147
  try {
32983
- decls = JSON.parse(readFileSync38(manifestPath, "utf8"));
32984
- bytes2 = readFileSync38(bundlePath);
33148
+ decls = JSON.parse(readFileSync39(manifestPath, "utf8"));
33149
+ bytes2 = readFileSync39(bundlePath);
32985
33150
  } catch {
32986
33151
  return { handlers: [] };
32987
33152
  }
@@ -33021,7 +33186,7 @@ async function serveStatic(req, res, root, prefix) {
33021
33186
  const s = await stat(fullPath);
33022
33187
  if (s.isDirectory()) return send(res, 404, "directory");
33023
33188
  const data = await readFile(fullPath);
33024
- const ext = extname(fullPath).toLowerCase();
33189
+ const ext = extname2(fullPath).toLowerCase();
33025
33190
  res.setHeader("content-type", MIME[ext] ?? "application/octet-stream");
33026
33191
  res.setHeader("cache-control", "max-age=60");
33027
33192
  if (req.url?.startsWith("/tier4/")) {
@@ -33284,7 +33449,7 @@ function createDevServer(opts = {}) {
33284
33449
  const q = new URLSearchParams(url.split("?")[1] ?? "");
33285
33450
  const assetApp = q.get("app") ?? state.appName;
33286
33451
  const assetDir = state.app && assetApp === state.app.name ? state.app.dir : resolveAppDir(assetApp);
33287
- const hit = assetDir ? collectAssets(assetDir).find((a) => assetSha256(readFileSync38(a.path)) === sha) : void 0;
33452
+ const hit = assetDir ? collectAssets(assetDir).find((a) => assetSha256(readFileSync39(a.path)) === sha) : void 0;
33288
33453
  if (!hit && assetDir) {
33289
33454
  const fontBytes = await fontFaceBytesBySha(assetDir, sha);
33290
33455
  if (fontBytes) {
@@ -33307,7 +33472,7 @@ function createDevServer(opts = {}) {
33307
33472
  res.end(JSON.stringify({ error: "asset_not_found", app: assetApp, sha }));
33308
33473
  return;
33309
33474
  }
33310
- const bytes2 = readFileSync38(hit.path);
33475
+ const bytes2 = readFileSync39(hit.path);
33311
33476
  res.writeHead(200, {
33312
33477
  "content-type": hit.contentType,
33313
33478
  "content-length": String(bytes2.length),
@@ -33394,7 +33559,7 @@ function createDevServer(opts = {}) {
33394
33559
  if (url === "/v1/schema/screen-descriptor.json" && req.method === "GET") {
33395
33560
  try {
33396
33561
  const schemaPath = resolve30(ROOT6, "core/schema/generated/screen-descriptor.schema.json");
33397
- const body = readFileSync38(schemaPath, "utf8");
33562
+ const body = readFileSync39(schemaPath, "utf8");
33398
33563
  return send(res, 200, body, {
33399
33564
  "content-type": "application/schema+json; charset=utf-8",
33400
33565
  "cache-control": "no-store",
@@ -33428,7 +33593,7 @@ function createDevServer(opts = {}) {
33428
33593
  try {
33429
33594
  const { parseRevocationsYaml: parseRevocationsYaml2 } = await Promise.resolve().then(() => (init_config2(), config_exports2));
33430
33595
  revoked = parseRevocationsYaml2(
33431
- readFileSync38(resolve30(state.app.dir, "revocations.yaml"), "utf8")
33596
+ readFileSync39(resolve30(state.app.dir, "revocations.yaml"), "utf8")
33432
33597
  ).revoked;
33433
33598
  } catch {
33434
33599
  }
@@ -33636,7 +33801,6 @@ var ROOT6, TIER3_ROOT, TIER4_ROOT, tier4Verifier, TIER5_ROOT2, ACTION_HANDLERS_R
33636
33801
  var init_src6 = __esm({
33637
33802
  "../../core/dev-server/src/index.ts"() {
33638
33803
  init_inject();
33639
- init_plan_fonts();
33640
33804
  init_face_source();
33641
33805
  init_himi_report();
33642
33806
  init_store2();
@@ -33662,6 +33826,7 @@ var init_src6 = __esm({
33662
33826
  init_check();
33663
33827
  init_openapi();
33664
33828
  init_render_descriptor();
33829
+ init_render_fonts();
33665
33830
  init_app_config();
33666
33831
  init_tier();
33667
33832
  init_flags2();
@@ -33670,6 +33835,7 @@ var init_src6 = __esm({
33670
33835
  init_kits();
33671
33836
  init_widgets();
33672
33837
  ROOT6 = resolve30(fileURLToPath18(new URL("../../..", import.meta.url)));
33838
+ setPngFontCss((tokens) => pngFontFaceCss(tokens));
33673
33839
  TIER3_ROOT = resolve30(ROOT6, "core/dev-server/web");
33674
33840
  TIER4_ROOT = resolve30(ROOT6, "core/dev-server/tier4-bundles");
33675
33841
  tier4Verifier = new TierFourVerifier(TIER4_ROOT);
@@ -36353,7 +36519,7 @@ __export(build_exports2, {
36353
36519
  withStoreNavBundle: () => withStoreNavBundle
36354
36520
  });
36355
36521
  import { createHash as createHash18 } from "node:crypto";
36356
- import { readFileSync as readFileSync39, readdirSync as readdirSync19, existsSync as existsSync36 } from "node:fs";
36522
+ import { readFileSync as readFileSync40, readdirSync as readdirSync19, existsSync as existsSync37 } from "node:fs";
36357
36523
  import { dirname as dirname21, join as join34, resolve as resolve31 } from "node:path";
36358
36524
  import { fileURLToPath as fileURLToPath19 } from "node:url";
36359
36525
  import { createRequire as createRequire2 } from "node:module";
@@ -36393,9 +36559,9 @@ function l10nLintOptions(locale, appDir2) {
36393
36559
  const catalog = /* @__PURE__ */ new Set();
36394
36560
  for (const tag of tags) {
36395
36561
  const path = join34(appDir2, "l10n", `${tag}.json`);
36396
- if (!existsSync36(path)) continue;
36562
+ if (!existsSync37(path)) continue;
36397
36563
  try {
36398
- const parsed = JSON.parse(readFileSync39(path, "utf8"));
36564
+ const parsed = JSON.parse(readFileSync40(path, "utf8"));
36399
36565
  for (const m of Object.values(parsed.messages ?? {})) {
36400
36566
  if (typeof m?.source === "string" && typeof m.translation === "string" && m.translation.length > 0) {
36401
36567
  catalog.add(m.source);
@@ -36560,7 +36726,7 @@ function shellSha(root = REPO_ROOT7) {
36560
36726
  function isMonorepoCheckout(dir) {
36561
36727
  try {
36562
36728
  const top = execFileSync4("git", ["rev-parse", "--show-toplevel"], { cwd: dir, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
36563
- return top.length > 0 && existsSync36(join34(top, "core", "schema", "core.proto"));
36729
+ return top.length > 0 && existsSync37(join34(top, "core", "schema", "core.proto"));
36564
36730
  } catch {
36565
36731
  return false;
36566
36732
  }
@@ -36697,7 +36863,7 @@ async function buildReleaseFromContent(contentDir2, dest, opts = {}) {
36697
36863
  function readTokensForLint(preloaded) {
36698
36864
  try {
36699
36865
  const tokenPath = preloaded.module.designTokensPath ?? resolve31(preloaded.dir, preloaded.module.config.designTokensPath ?? "tokens.json");
36700
- const parsed = JSON.parse(readFileSync39(tokenPath, "utf8"));
36866
+ const parsed = JSON.parse(readFileSync40(tokenPath, "utf8"));
36701
36867
  delete parsed._meta;
36702
36868
  return parsed;
36703
36869
  } catch {
@@ -36721,6 +36887,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36721
36887
  const baked = [];
36722
36888
  const linkable = /* @__PURE__ */ new Set();
36723
36889
  const lintTokens = collect2?.lint || collect2?.render ? readTokensForLint(preloaded) : void 0;
36890
+ const renderTokens = lintTokens && withServedFontFaces(lintTokens, preloaded.dir);
36724
36891
  const allowedComponents = await loadAllowedComponents(preloaded.dir);
36725
36892
  const nativeActions = discoverNativeActions(preloaded.dir);
36726
36893
  const appWorkerActions = appWorkerActionsFor(preloaded.module.config, tier5Dir);
@@ -36728,7 +36895,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36728
36895
  const compareScheme = collect2?.render?.compareScheme;
36729
36896
  const renderCompare = async (descriptor, services) => {
36730
36897
  if (!compareScheme || compareScheme === renderScheme) return {};
36731
- const rr = await renderDescriptorWeb(descriptor, lintTokens, compareScheme, false, services, collect2?.render?.width, collect2?.render?.rtl === true);
36898
+ const rr = await renderDescriptorWeb(descriptor, renderTokens, compareScheme, false, services, collect2?.render?.width, collect2?.render?.rtl === true);
36732
36899
  return { compare: { scheme: compareScheme, renderable: rr.renderable, ...rr.html ? { html: rr.html } : {}, ...rr.reason ? { reason: rr.reason } : {} } };
36733
36900
  };
36734
36901
  const LIVE_LOAD_BUDGET_MS = 3e4;
@@ -36834,7 +37001,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36834
37001
  if (addrCache.has(name)) return addrCache.get(name);
36835
37002
  let bytes2;
36836
37003
  try {
36837
- bytes2 = readFileSync39(join34(tier5Dir, `${name}.bundle.js`));
37004
+ bytes2 = readFileSync40(join34(tier5Dir, `${name}.bundle.js`));
36838
37005
  } catch {
36839
37006
  return null;
36840
37007
  }
@@ -36856,8 +37023,8 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36856
37023
  if (store.putDoc) {
36857
37024
  for (const [name, file] of [["spec", "SPEC.md"], ["mobile-ux", "MOBILE-UX.md"]]) {
36858
37025
  const path = join34(preloaded.dir, file);
36859
- if (!existsSync36(path)) continue;
36860
- const bytes2 = readFileSync39(path);
37026
+ if (!existsSync37(path)) continue;
37027
+ const bytes2 = readFileSync40(path);
36861
37028
  if (bytes2.length === 0 || bytes2.length > MAX_AUTHORING_DOC_BYTES) {
36862
37029
  throw new Error(`${file} must be non-empty and at most ${MAX_AUTHORING_DOC_BYTES} bytes to ship with a release.`);
36863
37030
  }
@@ -36872,7 +37039,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36872
37039
  const iconPath = resolveAppDirIcon(preloaded.dir);
36873
37040
  if (iconPath) {
36874
37041
  try {
36875
- const bytes2 = readFileSync39(iconPath);
37042
+ const bytes2 = readFileSync40(iconPath);
36876
37043
  await store.putIcon(app, bytes2);
36877
37044
  iconHash = sha2564(bytes2);
36878
37045
  } catch {
@@ -36894,7 +37061,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36894
37061
  }
36895
37062
  const seenAssetSha = /* @__PURE__ */ new Set();
36896
37063
  for (const a of collected) {
36897
- const bytes2 = readFileSync39(a.path);
37064
+ const bytes2 = readFileSync40(a.path);
36898
37065
  const hash = sha2564(bytes2);
36899
37066
  if (!seenAssetSha.has(hash)) {
36900
37067
  await store.putAsset(app, hash, bytes2, a.contentType);
@@ -36916,7 +37083,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36916
37083
  const fontWarnings = [];
36917
37084
  try {
36918
37085
  const appTokens = readTokensForLint(preloaded) ?? {};
36919
- const policy = existsSync36(join34(preloaded.dir, "fonts.json")) ? JSON.parse(readFileSync39(join34(preloaded.dir, "fonts.json"), "utf8")) : {};
37086
+ const policy = existsSync37(join34(preloaded.dir, "fonts.json")) ? JSON.parse(readFileSync40(join34(preloaded.dir, "fonts.json"), "utf8")) : {};
36920
37087
  fontPlan = planFonts(appTokens, policy);
36921
37088
  } catch (err) {
36922
37089
  throw new Error(
@@ -36932,7 +37099,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36932
37099
  `[release-build] ${family.name} face ${face.postScriptName} has no local bytes (sha ${face.sha256.slice(0, 12)}\u2026), so the release would declare a face the asset route cannot serve. Run \`npm run fonts:catalog\` to warm the cache before publishing.`
36933
37100
  );
36934
37101
  }
36935
- const bytes2 = readFileSync39(src);
37102
+ const bytes2 = readFileSync40(src);
36936
37103
  const hash = sha2564(bytes2);
36937
37104
  if (hash !== face.sha256) {
36938
37105
  throw new Error(
@@ -36982,7 +37149,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36982
37149
  if (store.putAsset) {
36983
37150
  for (const face of collectBrandFonts(preloaded.dir)) {
36984
37151
  try {
36985
- const bytes2 = readFileSync39(face.path);
37152
+ const bytes2 = readFileSync40(face.path);
36986
37153
  if (bytes2.length === 0) continue;
36987
37154
  const hash = sha2564(bytes2);
36988
37155
  await store.putAsset(app, hash, bytes2, "font/ttf");
@@ -37078,7 +37245,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
37078
37245
  }
37079
37246
  if (collect2?.render && (!collect2.render.screenId || collect2.render.screenId === screenId)) {
37080
37247
  const { services, liveCalls, liveReturned, liveErrors } = await renderServicesFor(bundleName, descriptor);
37081
- const rr = await renderDescriptorWeb(descriptor, lintTokens, renderScheme, collect2.render.png === true, services, collect2.render.width, collect2.render.rtl === true);
37248
+ const rr = await renderDescriptorWeb(descriptor, renderTokens, renderScheme, collect2.render.png === true, services, collect2.render.width, collect2.render.rtl === true);
37082
37249
  renders.push({ screenId, scheme: renderScheme, ...rr, ...await renderCompare(descriptor, services), ...collect2.render.dumpState && services ? { serviceState: services } : {}, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveErrors ? { liveErrors } : {} });
37083
37250
  }
37084
37251
  }
@@ -37105,7 +37272,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
37105
37272
  lint.push({ screenId: wantedRender, ok: report2.ok, issues: report2.issues });
37106
37273
  }
37107
37274
  const { services, liveCalls, liveReturned, liveErrors } = await renderServicesFor(bundleName, descriptor);
37108
- const rr = await renderDescriptorWeb(descriptor, lintTokens, renderScheme, collect2.render.png === true, services, collect2.render.width, collect2.render.rtl === true);
37275
+ const rr = await renderDescriptorWeb(descriptor, renderTokens, renderScheme, collect2.render.png === true, services, collect2.render.width, collect2.render.rtl === true);
37109
37276
  renders.push({ screenId: wantedRender, scheme: renderScheme, ...rr, ...await renderCompare(descriptor, services), ...collect2.render.dumpState && services ? { serviceState: services } : {}, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveErrors ? { liveErrors } : {} });
37110
37277
  }
37111
37278
  }
@@ -37365,7 +37532,12 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
37365
37532
  const js = readBuiltBundle(tier5Dir, name);
37366
37533
  if (!js) continue;
37367
37534
  const input = bundleInputs.get(name);
37368
- workers.push({ bundle: name, ...dryRunBundle(js, input ? { input } : {}) });
37535
+ const drifting = bundles[name]?.servicesHash ? nondeterministicServices(js, input ? { input } : {}) : [];
37536
+ workers.push({
37537
+ bundle: name,
37538
+ ...dryRunBundle(js, input ? { input } : {}),
37539
+ ...drifting.length ? { nondeterministicServices: drifting } : {}
37540
+ });
37369
37541
  }
37370
37542
  }
37371
37543
  return {
@@ -37387,7 +37559,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
37387
37559
  ...collect2?.lint ? { lint, workers } : {},
37388
37560
  ...collect2?.render ? { renders } : {},
37389
37561
  ...collect2?.descriptors ? { descriptors: baked, linkableScreenIds: [...linkable] } : {},
37390
- ...lintTokens !== void 0 ? { tokens: lintTokens } : {},
37562
+ ...renderTokens !== void 0 ? { tokens: renderTokens } : {},
37391
37563
  ...preloaded.meta.surfaces ? { surfaceNav: preloaded.meta.surfaces } : {},
37392
37564
  auth: (() => {
37393
37565
  const a = preloaded.module.config.auth;
@@ -37407,9 +37579,9 @@ async function buildFunctionsOnlyRelease(preloaded, dest) {
37407
37579
  const sources = {};
37408
37580
  for (const definition of config.functions.functions) {
37409
37581
  const candidates = [".ts", ".js", ".mts", ".mjs"].map((extension) => join34(preloaded.dir, "functions", `${definition.name}${extension}`));
37410
- const source = candidates.find((candidate) => existsSync36(candidate));
37582
+ const source = candidates.find((candidate) => existsSync37(candidate));
37411
37583
  if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
37412
- sources[definition.name] = readFileSync39(source, "utf8");
37584
+ sources[definition.name] = readFileSync40(source, "utf8");
37413
37585
  }
37414
37586
  const built = await buildFunctions(config.functions.functions, sources);
37415
37587
  const bundles = {};
@@ -37459,6 +37631,7 @@ var init_build3 = __esm({
37459
37631
  init_wix_member_login();
37460
37632
  init_wix_placeholders();
37461
37633
  init_render_descriptor();
37634
+ init_render_fonts();
37462
37635
  init_screen_crawl();
37463
37636
  init_icons();
37464
37637
  init_build2();
@@ -38089,11 +38262,11 @@ __export(captcha_exports, {
38089
38262
  captchaContentInput: () => captchaContentInput,
38090
38263
  runCaptcha: () => runCaptcha
38091
38264
  });
38092
- import { readFileSync as readFileSync40 } from "node:fs";
38265
+ import { readFileSync as readFileSync41 } from "node:fs";
38093
38266
  import { resolve as resolve32 } from "node:path";
38094
38267
  function readObject(path) {
38095
38268
  try {
38096
- return JSON.parse(readFileSync40(path, "utf8"));
38269
+ return JSON.parse(readFileSync41(path, "utf8"));
38097
38270
  } catch {
38098
38271
  return {};
38099
38272
  }
@@ -38237,11 +38410,11 @@ var init_push_setup_apple_credentials = __esm({
38237
38410
  });
38238
38411
 
38239
38412
  // src/push-onboarding.ts
38240
- import { existsSync as existsSync37, mkdirSync as mkdirSync17, readFileSync as readFileSync41, statSync as statSync7, writeFileSync as writeFileSync13, chmodSync as chmodSync2 } from "node:fs";
38413
+ import { existsSync as existsSync38, mkdirSync as mkdirSync17, readFileSync as readFileSync42, statSync as statSync7, writeFileSync as writeFileSync13, chmodSync as chmodSync2 } from "node:fs";
38241
38414
  import { basename as basename9, dirname as dirname22, join as join35, resolve as resolve33 } from "node:path";
38242
38415
  function readJson2(path) {
38243
38416
  try {
38244
- const parsed = JSON.parse(readFileSync41(path, "utf8"));
38417
+ const parsed = JSON.parse(readFileSync42(path, "utf8"));
38245
38418
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
38246
38419
  } catch {
38247
38420
  return {};
@@ -38249,7 +38422,7 @@ function readJson2(path) {
38249
38422
  }
38250
38423
  function pushInputsFromContent(dir) {
38251
38424
  const root = resolve33(dir);
38252
- if (!existsSync37(join35(root, "himalaya.content.json"))) return { initialized: false };
38425
+ if (!existsSync38(join35(root, "himalaya.content.json"))) return { initialized: false };
38253
38426
  const content = readJson2(join35(root, "himalaya.content.json"));
38254
38427
  const provisioning = readJson2(join35(root, "provisioning.json"));
38255
38428
  const native = provisioning.native ?? {};
@@ -38326,7 +38499,7 @@ function readKeyFile(path) {
38326
38499
  }
38327
38500
  let body;
38328
38501
  try {
38329
- body = readFileSync41(path, "utf8");
38502
+ body = readFileSync42(path, "utf8");
38330
38503
  } catch {
38331
38504
  return { ok: false, code: "key_file_unreadable", reason: "cannot read the selected key file; check its path and file permissions" };
38332
38505
  }
@@ -38381,7 +38554,7 @@ function buildPushSetupBody(i, keys) {
38381
38554
  }
38382
38555
  function readPushOnboarding(dir) {
38383
38556
  const path = join35(resolve33(dir), PUSH_ONBOARDING_PATH);
38384
- if (!existsSync37(path)) return { version: 1 };
38557
+ if (!existsSync38(path)) return { version: 1 };
38385
38558
  const parsed = readJson2(path);
38386
38559
  return { version: 1, ...parsed };
38387
38560
  }
@@ -38416,7 +38589,7 @@ function recordPushDeferral(dir, d) {
38416
38589
  }
38417
38590
  function clearPushDeferral(dir) {
38418
38591
  const path = join35(resolve33(dir), PUSH_ONBOARDING_PATH);
38419
- if (!existsSync37(path)) return;
38592
+ if (!existsSync38(path)) return;
38420
38593
  const { push: _dropped, ...rest } = readPushOnboarding(dir);
38421
38594
  writeFile(dir, { ...rest, version: 1 });
38422
38595
  }
@@ -39376,7 +39549,7 @@ __export(pack_exports, {
39376
39549
  });
39377
39550
  import { createHash as createHash19 } from "node:crypto";
39378
39551
  import { deflateRawSync, inflateRawSync } from "node:zlib";
39379
- import { existsSync as existsSync38, mkdirSync as mkdirSync18, readFileSync as readFileSync42, readdirSync as readdirSync20, rmSync as rmSync6, statSync as statSync8, writeFileSync as writeFileSync14 } from "node:fs";
39552
+ import { existsSync as existsSync39, mkdirSync as mkdirSync18, readFileSync as readFileSync43, readdirSync as readdirSync20, rmSync as rmSync6, statSync as statSync8, writeFileSync as writeFileSync14 } from "node:fs";
39380
39553
  import { dirname as dirname23, join as join36, resolve as resolve35 } from "node:path";
39381
39554
  function writeZip(entries) {
39382
39555
  const sorted = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
@@ -39471,10 +39644,10 @@ function inflateEntry(buf, entry) {
39471
39644
  return bytes2;
39472
39645
  }
39473
39646
  function readIf(path) {
39474
- return existsSync38(path) && statSync8(path).isFile() ? readFileSync42(path) : null;
39647
+ return existsSync39(path) && statSync8(path).isFile() ? readFileSync43(path) : null;
39475
39648
  }
39476
39649
  function listDir(dir) {
39477
- return existsSync38(dir) ? readdirSync20(dir).filter((f) => statSync8(join36(dir, f)).isFile()) : [];
39650
+ return existsSync39(dir) ? readdirSync20(dir).filter((f) => statSync8(join36(dir, f)).isFile()) : [];
39478
39651
  }
39479
39652
  function gatherReleaseEntries(appDir2) {
39480
39653
  const manifestPath = join36(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
@@ -39553,7 +39726,7 @@ function packRelease(releaseRoot, app, out, opts = {}) {
39553
39726
  const appDir2 = join36(resolve35(releaseRoot), app);
39554
39727
  const { all, header, skipped } = buildEntries(appDir2, app, opts);
39555
39728
  const buf = writeZip(all);
39556
- const isDir = existsSync38(out) && statSync8(out).isDirectory();
39729
+ const isDir = existsSync39(out) && statSync8(out).isDirectory();
39557
39730
  const outFile = isDir ? join36(resolve35(out), packageFileName(app, header.releaseId)) : resolve35(out);
39558
39731
  mkdirSync18(dirname23(outFile), { recursive: true });
39559
39732
  writeFileSync14(outFile, buf);
@@ -39570,11 +39743,11 @@ function resolvePackageDirDest(outDir, app, releaseId) {
39570
39743
  }
39571
39744
  };
39572
39745
  const replaceable = (dir) => {
39573
- if (!existsSync38(dir)) return true;
39746
+ if (!existsSync39(dir)) return true;
39574
39747
  if (!statSync8(dir).isDirectory()) return false;
39575
39748
  return readdirSync20(dir).length === 0 || packagedApp(dir) === app;
39576
39749
  };
39577
- if (existsSync38(outDir) && !statSync8(outDir).isDirectory()) {
39750
+ if (existsSync39(outDir) && !statSync8(outDir).isDirectory()) {
39578
39751
  throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
39579
39752
  }
39580
39753
  if (replaceable(outDir)) return outDir;
@@ -39621,7 +39794,7 @@ function openPackageBuffer(buf) {
39621
39794
  return openFromEntries(readZip(buf), { requireHeader: true });
39622
39795
  }
39623
39796
  function openPackageFile(file) {
39624
- return openPackageBuffer(readFileSync42(file));
39797
+ return openPackageBuffer(readFileSync43(file));
39625
39798
  }
39626
39799
  function openPackageDir(dir) {
39627
39800
  const root = resolve35(dir);
@@ -39632,10 +39805,10 @@ function openPackageDir(dir) {
39632
39805
  const childRel = rel ? `${rel}/${name}` : name;
39633
39806
  const childAbs = join36(abs, name);
39634
39807
  if (statSync8(childAbs).isDirectory()) walk2(childRel);
39635
- else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync42(childAbs));
39808
+ else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync43(childAbs));
39636
39809
  }
39637
39810
  };
39638
- if (!existsSync38(root)) throw new Error(`no such package directory: ${root}`);
39811
+ if (!existsSync39(root)) throw new Error(`no such package directory: ${root}`);
39639
39812
  walk2("");
39640
39813
  const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
39641
39814
  if (manifestBytes) {
@@ -39716,7 +39889,7 @@ __export(app_source_exports, {
39716
39889
  writeConflicts: () => writeConflicts,
39717
39890
  zipAppSource: () => zipAppSource
39718
39891
  });
39719
- import { readdirSync as readdirSync21, lstatSync as lstatSync5, readFileSync as readFileSync43, mkdirSync as mkdirSync19, writeFileSync as writeFileSync15, existsSync as existsSync39, rmSync as rmSync7, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
39892
+ import { readdirSync as readdirSync21, lstatSync as lstatSync5, readFileSync as readFileSync44, mkdirSync as mkdirSync19, writeFileSync as writeFileSync15, existsSync as existsSync40, rmSync as rmSync7, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
39720
39893
  import { join as join37, resolve as resolve36, sep as sep8 } from "node:path";
39721
39894
  import { deflateRawSync as deflateRawSync2 } from "node:zlib";
39722
39895
  function walkSourceTree(dir, file, skip) {
@@ -39729,7 +39902,7 @@ function walkSourceTree(dir, file, skip) {
39729
39902
  continue;
39730
39903
  }
39731
39904
  if (st.isDirectory()) {
39732
- if (isDeniedSourceDir(name, relDir) || existsSync39(join37(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
39905
+ if (isDeniedSourceDir(name, relDir) || existsSync40(join37(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
39733
39906
  else walk2(rel);
39734
39907
  continue;
39735
39908
  }
@@ -39747,7 +39920,7 @@ function collectAppSource(dir) {
39747
39920
  const skipped = [];
39748
39921
  walkSourceTree(
39749
39922
  dir,
39750
- (archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync43(join37(dir, hostRel)) }),
39923
+ (archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync44(join37(dir, hostRel)) }),
39751
39924
  (hostRel) => skipped.push(hostRel)
39752
39925
  );
39753
39926
  entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
@@ -39815,7 +39988,7 @@ function writeAppSource(entries, destDir) {
39815
39988
  return written;
39816
39989
  }
39817
39990
  function staleSourcePaths(entries, destDir) {
39818
- if (!existsSync39(destDir)) return [];
39991
+ if (!existsSync40(destDir)) return [];
39819
39992
  const archived = new Set(entries.map((e) => e.path));
39820
39993
  const stale = [];
39821
39994
  walkSourceTree(destDir, (archivePath) => {
@@ -39871,7 +40044,7 @@ function removeStaleSource(entries, destDir) {
39871
40044
  const segments = entry.path.split("/");
39872
40045
  for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
39873
40046
  }
39874
- if (existsSync39(root)) pruneEmptyDirs(root, "", needed, removed);
40047
+ if (existsSync40(root)) pruneEmptyDirs(root, "", needed, removed);
39875
40048
  return removed.sort();
39876
40049
  }
39877
40050
  function pruneEmptyDirs(root, rel, needed, removed) {
@@ -39944,13 +40117,13 @@ __export(eject_exports, {
39944
40117
  EJECTABLE: () => EJECTABLE,
39945
40118
  ejectModule: () => ejectModule
39946
40119
  });
39947
- import { existsSync as existsSync40, mkdirSync as mkdirSync20, readFileSync as readFileSync44, writeFileSync as writeFileSync16 } from "node:fs";
40120
+ import { existsSync as existsSync41, mkdirSync as mkdirSync20, readFileSync as readFileSync45, writeFileSync as writeFileSync16 } from "node:fs";
39948
40121
  import { dirname as dirname24, join as join38, relative as relative5, resolve as resolve37, sep as sep9 } from "node:path";
39949
40122
  function locate(repoRootOrCwd, mod) {
39950
40123
  const inRepo = resolve37(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
39951
- if (existsSync40(inRepo)) return { path: inRepo, form: "source" };
40124
+ if (existsSync41(inRepo)) return { path: inRepo, form: "source" };
39952
40125
  const dist = resolve37(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
39953
- if (existsSync40(dist)) return { path: dist, form: "bundle" };
40126
+ if (existsSync41(dist)) return { path: dist, form: "bundle" };
39954
40127
  return null;
39955
40128
  }
39956
40129
  function specifiersFor(mod) {
@@ -39988,15 +40161,15 @@ function ejectModule(opts) {
39988
40161
  // gate still applies. Ejecting buys layout and flow, never the floor.
39989
40162
 
39990
40163
  `;
39991
- const normalized = readFileSync44(found.path, "utf8").replace(
40164
+ const normalized = readFileSync45(found.path, "utf8").replace(
39992
40165
  /(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
39993
40166
  (_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
39994
40167
  );
39995
40168
  writeFileSync16(target, banner + normalized);
39996
40169
  const rewired = [];
39997
40170
  for (const f of files) {
39998
- if (!existsSync40(f)) continue;
39999
- const before = readFileSync44(f, "utf8");
40171
+ if (!existsSync41(f)) continue;
40172
+ const before = readFileSync45(f, "utf8");
40000
40173
  let after = before;
40001
40174
  let rel = relative5(dirname24(f), target).split(sep9).join("/").replace(/\.tsx?$/, ".js");
40002
40175
  if (!rel.startsWith(".")) rel = `./${rel}`;
@@ -40044,14 +40217,14 @@ __export(test_exports, {
40044
40217
  scopeDescriptors: () => scopeDescriptors,
40045
40218
  writeRecordedMocks: () => writeRecordedMocks
40046
40219
  });
40047
- import { existsSync as existsSync41, mkdirSync as mkdirSync21, readFileSync as readFileSync45, writeFileSync as writeFileSync17 } from "node:fs";
40220
+ import { existsSync as existsSync42, mkdirSync as mkdirSync21, readFileSync as readFileSync46, writeFileSync as writeFileSync17 } from "node:fs";
40048
40221
  import { join as join39, resolve as resolve38 } from "node:path";
40049
40222
  function readTestConfig(dir) {
40050
40223
  const p = resolve38(dir, TEST_CONFIG_FILE);
40051
- if (!existsSync41(p)) return {};
40224
+ if (!existsSync42(p)) return {};
40052
40225
  let parsed;
40053
40226
  try {
40054
- parsed = JSON.parse(readFileSync45(p, "utf8"));
40227
+ parsed = JSON.parse(readFileSync46(p, "utf8"));
40055
40228
  } catch (e) {
40056
40229
  throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
40057
40230
  }
@@ -40094,7 +40267,7 @@ function readTestConfig(dir) {
40094
40267
  function readNetRules(path) {
40095
40268
  let parsed;
40096
40269
  try {
40097
- parsed = JSON.parse(readFileSync45(path, "utf8"));
40270
+ parsed = JSON.parse(readFileSync46(path, "utf8"));
40098
40271
  } catch (e) {
40099
40272
  throw new Error(`--net ${path} could not be read as JSON \u2014 ${e.message}`);
40100
40273
  }
@@ -40115,7 +40288,7 @@ function readNetRules(path) {
40115
40288
  function defaultNetRules(dir) {
40116
40289
  for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
40117
40290
  const p = resolve38(dir, rel);
40118
- if (existsSync41(p)) {
40291
+ if (existsSync42(p)) {
40119
40292
  const rules = readNetRules(p);
40120
40293
  if (rules.length) return { rules, from: rel };
40121
40294
  }
@@ -40131,7 +40304,7 @@ function readCannedResponses() {
40131
40304
  ];
40132
40305
  for (const url of candidates) {
40133
40306
  try {
40134
- const parsed = JSON.parse(readFileSync45(url, "utf8"));
40307
+ const parsed = JSON.parse(readFileSync46(url, "utf8"));
40135
40308
  const byKey = {};
40136
40309
  for (const [k, v] of Object.entries(parsed)) {
40137
40310
  if (!k.startsWith("//")) byKey[k] = v;
@@ -40248,7 +40421,7 @@ async function runShotsPass(opts) {
40248
40421
  const rr = await opts.deps.renderDescriptorWeb(baked.descriptor, opts.tokens, scheme, false, state, opts.width);
40249
40422
  if (rr.renderable && rr.html) shots.push({ screenId: baked.screenId, html: rr.html });
40250
40423
  }
40251
- const pngs = await opts.deps.renderPngBatch(shots.map((x) => ({ html: x.html, scheme, ...opts.width ? { width: opts.width } : {} })));
40424
+ const pngs = await opts.deps.renderPngBatch(shots.map((x) => ({ html: x.html, scheme, tokens: opts.tokens, ...opts.width ? { width: opts.width } : {} })));
40252
40425
  if (pngs === null) return { dir: opts.outDir, written: [], unavailable: true };
40253
40426
  if (opts.clearDir) opts.deps.clearDir?.(opts.outDir);
40254
40427
  const written = [];
@@ -40681,14 +40854,14 @@ var mobile_ux_lint_exports = {};
40681
40854
  __export(mobile_ux_lint_exports, {
40682
40855
  mobileUxIssues: () => mobileUxIssues
40683
40856
  });
40684
- import { existsSync as existsSync42, readFileSync as readFileSync46 } from "node:fs";
40857
+ import { existsSync as existsSync43, readFileSync as readFileSync47 } from "node:fs";
40685
40858
  import { join as join40 } from "node:path";
40686
40859
  function mobileUxIssues(dir, strict) {
40687
40860
  const file = join40(dir, "MOBILE-UX.md");
40688
- if (!existsSync42(file)) return [];
40861
+ if (!existsSync43(file)) return [];
40689
40862
  let text4;
40690
40863
  try {
40691
- text4 = readFileSync46(file, "utf8");
40864
+ text4 = readFileSync47(file, "utf8");
40692
40865
  } catch {
40693
40866
  return [];
40694
40867
  }
@@ -41949,18 +42122,18 @@ function createFunctionDataCapability(options) {
41949
42122
  }));
41950
42123
  };
41951
42124
  const encodeQuery = (query) => {
41952
- const encoded = { ...query };
41953
- if (query.filter !== void 0) encoded.filter = mapFilter(query.filter);
41954
- if (Array.isArray(query.sort)) encoded.sort = query.sort.map((sort) => {
42125
+ const encoded2 = { ...query };
42126
+ if (query.filter !== void 0) encoded2.filter = mapFilter(query.filter);
42127
+ if (Array.isArray(query.sort)) encoded2.sort = query.sort.map((sort) => {
41955
42128
  if (!sort || typeof sort !== "object") return sort;
41956
42129
  const record2 = sort;
41957
42130
  const logical = typeof record2.fieldName === "string" ? record2.fieldName : "";
41958
42131
  return { ...record2, fieldName: queryField(logical) };
41959
42132
  });
41960
- if (Array.isArray(query.fields)) encoded.fields = query.fields.map((logical) => {
42133
+ if (Array.isArray(query.fields)) encoded2.fields = query.fields.map((logical) => {
41961
42134
  return queryField(String(logical));
41962
42135
  });
41963
- return encoded;
42136
+ return encoded2;
41964
42137
  };
41965
42138
  const decode = (result) => {
41966
42139
  if (!result || typeof result !== "object") return result;
@@ -42352,7 +42525,7 @@ __export(functions_exports, {
42352
42525
  resolveFunctionsTarget: () => resolveFunctionsTarget,
42353
42526
  runRemoteFunctionOperation: () => runRemoteFunctionOperation
42354
42527
  });
42355
- import { readFileSync as readFileSync47, existsSync as existsSync43 } from "node:fs";
42528
+ import { readFileSync as readFileSync48, existsSync as existsSync44 } from "node:fs";
42356
42529
  import { join as join41, resolve as resolve39 } from "node:path";
42357
42530
  function resolveFunctionsTarget(input) {
42358
42531
  const explicitUrl = input.functionsUrl?.trim();
@@ -42372,9 +42545,9 @@ async function loadFunctionsApp(dir) {
42372
42545
  }
42373
42546
  const sources = {};
42374
42547
  for (const definition of config.functions.functions) {
42375
- const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join41(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync43);
42548
+ const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join41(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync44);
42376
42549
  if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
42377
- sources[definition.name] = readFileSync47(source, "utf8");
42550
+ sources[definition.name] = readFileSync48(source, "utf8");
42378
42551
  }
42379
42552
  const data = config.cms || config.data ? mergeDataResources(config) : void 0;
42380
42553
  const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
@@ -42529,7 +42702,7 @@ __export(native_decode_exports, {
42529
42702
  runNativeDecode: () => runNativeDecode
42530
42703
  });
42531
42704
  import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
42532
- import { existsSync as existsSync44, mkdtempSync as mkdtempSync2, readFileSync as readFileSync48, rmSync as rmSync8, writeFileSync as writeFileSync18 } from "node:fs";
42705
+ import { existsSync as existsSync45, mkdtempSync as mkdtempSync2, readFileSync as readFileSync49, rmSync as rmSync8, writeFileSync as writeFileSync18 } from "node:fs";
42533
42706
  import { tmpdir as tmpdir3 } from "node:os";
42534
42707
  import { join as join42 } from "node:path";
42535
42708
  import { fileURLToPath as fileURLToPath20 } from "node:url";
@@ -42541,8 +42714,8 @@ function nativeDecodeAndroidHarnessDir() {
42541
42714
  }
42542
42715
  function nativeOracleShipped() {
42543
42716
  return {
42544
- ios: existsSync44(join42(nativeDecodePackageDir(), "Package.swift")),
42545
- android: existsSync44(join42(nativeDecodeAndroidHarnessDir(), "gradlew"))
42717
+ ios: existsSync45(join42(nativeDecodePackageDir(), "Package.swift")),
42718
+ android: existsSync45(join42(nativeDecodeAndroidHarnessDir(), "gradlew"))
42546
42719
  };
42547
42720
  }
42548
42721
  function detectNativeDecode(options = {}) {
@@ -42553,7 +42726,7 @@ function detectNativeDecode(options = {}) {
42553
42726
  return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
42554
42727
  }
42555
42728
  if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
42556
- const packageAvailable = options.packageAvailable ?? existsSync44(join42(packageDir, "Package.swift"));
42729
+ const packageAvailable = options.packageAvailable ?? existsSync45(join42(packageDir, "Package.swift"));
42557
42730
  if (!packageAvailable) {
42558
42731
  return {
42559
42732
  platform: "ios",
@@ -42565,7 +42738,7 @@ function detectNativeDecode(options = {}) {
42565
42738
  }
42566
42739
  function localPropertiesSdk(harnessDir) {
42567
42740
  try {
42568
- const match = readFileSync48(join42(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
42741
+ const match = readFileSync49(join42(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
42569
42742
  return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
42570
42743
  } catch {
42571
42744
  return null;
@@ -42574,7 +42747,7 @@ function localPropertiesSdk(harnessDir) {
42574
42747
  function detectAndroidNativeDecode(options = {}) {
42575
42748
  const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
42576
42749
  const gradlew = join42(harnessDir, "gradlew");
42577
- const gradlewAvailable = options.gradlewAvailable ?? existsSync44(gradlew);
42750
+ const gradlewAvailable = options.gradlewAvailable ?? existsSync45(gradlew);
42578
42751
  if (!gradlewAvailable) {
42579
42752
  return {
42580
42753
  platform: "android",
@@ -42584,7 +42757,7 @@ function detectAndroidNativeDecode(options = {}) {
42584
42757
  }
42585
42758
  const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
42586
42759
  const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
42587
- const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync44(sdk));
42760
+ const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync45(sdk));
42588
42761
  if (!sdkAvailable) {
42589
42762
  return {
42590
42763
  platform: "android",
@@ -42716,7 +42889,7 @@ function runAndroidNativeDecode(options) {
42716
42889
  stdio: ["ignore", "ignore", "pipe"],
42717
42890
  encoding: "utf8"
42718
42891
  });
42719
- const stdout = readFileSync48(outputPath, "utf8");
42892
+ const stdout = readFileSync49(outputPath, "utf8");
42720
42893
  return {
42721
42894
  platform: "android",
42722
42895
  verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
@@ -42787,7 +42960,7 @@ __export(browser_authoring_exports, {
42787
42960
  import { createServer as createServer3 } from "node:http";
42788
42961
  import { createHash as createHash22, randomBytes as randomBytes4 } from "node:crypto";
42789
42962
  import { execFile as execFile2 } from "node:child_process";
42790
- import { existsSync as existsSync45, readdirSync as readdirSync22, readFileSync as readFileSync49, realpathSync as realpathSync4, statSync as statSync9 } from "node:fs";
42963
+ import { existsSync as existsSync46, readdirSync as readdirSync22, readFileSync as readFileSync50, realpathSync as realpathSync4, statSync as statSync9 } from "node:fs";
42791
42964
  import { join as join43, posix, relative as relative6, sep as sep10 } from "node:path";
42792
42965
  function humanMs(ms) {
42793
42966
  return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
@@ -42806,11 +42979,11 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
42806
42979
  if (statSync9(childAbs).isDirectory()) {
42807
42980
  walk2(childAbs, childRel);
42808
42981
  } else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
42809
- files[childRel] = readFileSync49(childAbs, "utf8");
42982
+ files[childRel] = readFileSync50(childAbs, "utf8");
42810
42983
  }
42811
42984
  }
42812
42985
  };
42813
- if (!existsSync45(root)) return null;
42986
+ if (!existsSync46(root)) return null;
42814
42987
  walk2(root, `/tier5-src/${bundleName}`);
42815
42988
  const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
42816
42989
  if (!entry) return null;
@@ -42837,10 +43010,10 @@ function collectRelativeSiblings(files, tier5SrcDir) {
42837
43010
  join43(onDisk, "index.js")
42838
43011
  ];
42839
43012
  for (const abs of candidates) {
42840
- if (!existsSync45(abs) || statSync9(abs).isDirectory()) continue;
43013
+ if (!existsSync46(abs) || statSync9(abs).isDirectory()) continue;
42841
43014
  const key2 = `/tier5-src/${relative6(tier5SrcDir, abs).split(sep10).join(posix.sep)}`;
42842
43015
  if (key2 in files) break;
42843
- files[key2] = readFileSync49(abs, "utf8");
43016
+ files[key2] = readFileSync50(abs, "utf8");
42844
43017
  queue.push(key2);
42845
43018
  break;
42846
43019
  }
@@ -42875,7 +43048,7 @@ function collectSdkModules(files, resolveSubpath) {
42875
43048
  function sdkSubpathReader(resolve45) {
42876
43049
  return (sub) => {
42877
43050
  try {
42878
- return readFileSync49(resolve45(`@wix/himalaya/${sub}`), "utf8");
43051
+ return readFileSync50(resolve45(`@wix/himalaya/${sub}`), "utf8");
42879
43052
  } catch {
42880
43053
  return null;
42881
43054
  }
@@ -43049,7 +43222,7 @@ __export(coverage_exports, {
43049
43222
  suppressedNativeKeys: () => suppressedNativeKeys,
43050
43223
  trendAndStore: () => trendAndStore
43051
43224
  });
43052
- import { existsSync as existsSync46, mkdirSync as mkdirSync22, readFileSync as readFileSync50, writeFileSync as writeFileSync19 } from "node:fs";
43225
+ import { existsSync as existsSync47, mkdirSync as mkdirSync22, readFileSync as readFileSync51, writeFileSync as writeFileSync19 } from "node:fs";
43053
43226
  import { dirname as dirname25, join as join44 } from "node:path";
43054
43227
  function suppressedNativeKeys(oracle) {
43055
43228
  return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
@@ -43223,8 +43396,8 @@ function trendAndStore(dir, entries, suppressed) {
43223
43396
  const p = join44(dir, LEDGER_FILE);
43224
43397
  let previous = null;
43225
43398
  try {
43226
- if (existsSync46(p)) {
43227
- const parsed = JSON.parse(readFileSync50(p, "utf8"));
43399
+ if (existsSync47(p)) {
43400
+ const parsed = JSON.parse(readFileSync51(p, "utf8"));
43228
43401
  if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
43229
43402
  }
43230
43403
  } catch {
@@ -43266,8 +43439,8 @@ function diffAndStoreObservations(dir, current) {
43266
43439
  const p = join44(dir, OBS_FILE);
43267
43440
  let previous = null;
43268
43441
  try {
43269
- if (existsSync46(p)) {
43270
- const parsed = JSON.parse(readFileSync50(p, "utf8"));
43442
+ if (existsSync47(p)) {
43443
+ const parsed = JSON.parse(readFileSync51(p, "utf8"));
43271
43444
  if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
43272
43445
  (v) => Array.isArray(v) && v.every((l) => typeof l === "string")
43273
43446
  )) {
@@ -43328,11 +43501,11 @@ __export(design_kits_exports, {
43328
43501
  kitsDir: () => kitsDir,
43329
43502
  listKits: () => listKits2
43330
43503
  });
43331
- import { existsSync as existsSync47, readFileSync as readFileSync51, readdirSync as readdirSync23 } from "node:fs";
43504
+ import { existsSync as existsSync48, readFileSync as readFileSync52, readdirSync as readdirSync23 } from "node:fs";
43332
43505
  import { join as join45, basename as basename10 } from "node:path";
43333
43506
  import { fileURLToPath as fileURLToPath21 } from "node:url";
43334
43507
  function kitsDir() {
43335
- return KIT_DIR_CANDIDATES.find((p) => existsSync47(p));
43508
+ return KIT_DIR_CANDIDATES.find((p) => existsSync48(p));
43336
43509
  }
43337
43510
  function listKits2() {
43338
43511
  const dir = kitsDir();
@@ -43356,7 +43529,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
43356
43529
  if (!kits.includes(name)) {
43357
43530
  return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
43358
43531
  }
43359
- const raw = readFileSync51(join45(dir, `${name}.json`), "utf8");
43532
+ const raw = readFileSync52(join45(dir, `${name}.json`), "utf8");
43360
43533
  let parsed;
43361
43534
  try {
43362
43535
  parsed = JSON.parse(raw);
@@ -43396,11 +43569,11 @@ __export(assets_exports, {
43396
43569
  removeAssetPayload: () => removeAssetPayload,
43397
43570
  verifyReport: () => verifyReport
43398
43571
  });
43399
- import { readFileSync as readFileSync52 } from "node:fs";
43572
+ import { readFileSync as readFileSync53 } from "node:fs";
43400
43573
  import { basename as basename11 } from "node:path";
43401
43574
  function declaredAssets(dir) {
43402
43575
  return collectAssets(dir).map((a) => {
43403
- const bytes2 = readFileSync52(a.path);
43576
+ const bytes2 = readFileSync53(a.path);
43404
43577
  return {
43405
43578
  name: a.name,
43406
43579
  sha256: assetSha256(bytes2),
@@ -43477,7 +43650,7 @@ function verifyReport(dir, app, manifest) {
43477
43650
  };
43478
43651
  }
43479
43652
  function addAssetPayload(manifest, filePath, opts) {
43480
- const bytes2 = readFileSync52(filePath);
43653
+ const bytes2 = readFileSync53(filePath);
43481
43654
  const name = opts.name ?? basename11(filePath);
43482
43655
  const sha2565 = assetSha256(bytes2);
43483
43656
  const record2 = {
@@ -44944,19 +45117,19 @@ var init_preview_assets_generated = __esm({
44944
45117
  "../../packages/serve/src/preview-assets.generated.ts"() {
44945
45118
  init_preview_assets_format();
44946
45119
  PREVIEW_ASSET_MANIFEST = [
44947
- { key: "assets/index-D0JRTirJ.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1004613, sha256: "7e32dc45ae043c4ec3176c5defcadbb434e6748aef2c6b6135aee97d5ef2c093" },
44948
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1004621, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
44949
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1095545, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
44950
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1186529, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
44951
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1277509, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
44952
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1368381, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
44953
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1459361, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
44954
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1567997, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
44955
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1677081, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
44956
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1786129, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
44957
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1893829, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
44958
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1981937, length: 4448, sha256: "d37ab02eeaf4e6de05cd6b1928427b05e2585a871df0821d7879894db5155a76" },
44959
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1986385, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
45120
+ { key: "assets/index-CD7rJtUy.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1006255, sha256: "1f775ada818f0f8d26665e3fb4eeff5ef99a4eb2d8dd493a0bf76e64569eef4a" },
45121
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1006263, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
45122
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1097187, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
45123
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1188171, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
45124
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1279151, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
45125
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1370023, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
45126
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1461003, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
45127
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1569639, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
45128
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1678723, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
45129
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1787771, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
45130
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1895471, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
45131
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1983579, length: 4448, sha256: "c1e9a6eea6af68bc7e7ae1044a9f46f5938c69b8a5998ea02c3fed7c7db5523a" },
45132
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1988027, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
44960
45133
  ];
44961
45134
  }
44962
45135
  });
@@ -44972,7 +45145,7 @@ __export(run_exports, {
44972
45145
  runPackage: () => runPackage,
44973
45146
  withoutProdServe: () => withoutProdServe
44974
45147
  });
44975
- import { cpSync, existsSync as existsSync48, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, readFileSync as readFileSync53, rmSync as rmSync9, statSync as statSync10 } from "node:fs";
45148
+ import { cpSync, existsSync as existsSync49, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, readFileSync as readFileSync54, rmSync as rmSync9, statSync as statSync10 } from "node:fs";
44976
45149
  import { tmpdir as tmpdir4 } from "node:os";
44977
45150
  import { dirname as dirname26, join as join46 } from "node:path";
44978
45151
  import { fileURLToPath as fileURLToPath22 } from "node:url";
@@ -44993,9 +45166,9 @@ async function fetchBytes(url) {
44993
45166
  }
44994
45167
  async function resolvePackage(source, workDir) {
44995
45168
  const isUrl2 = /^https?:\/\//i.test(source);
44996
- if (!isUrl2 && existsSync48(source) && statSync10(source).isDirectory()) {
45169
+ if (!isUrl2 && existsSync49(source) && statSync10(source).isDirectory()) {
44997
45170
  const appDirManifest = join46(source, "release-manifest.json");
44998
- if (existsSync48(appDirManifest)) {
45171
+ if (existsSync49(appDirManifest)) {
44999
45172
  const opened2 = openPackageDir(source);
45000
45173
  if (!opened2.validation.ok) {
45001
45174
  throw new Error(`package is not valid:
@@ -45023,7 +45196,7 @@ async function resolvePackage(source, workDir) {
45023
45196
  }
45024
45197
  throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
45025
45198
  }
45026
- const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync53(source);
45199
+ const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync54(source);
45027
45200
  const root = workDir ?? mkdtempSync3(join46(tmpdir4(), "himi-run-"));
45028
45201
  const { app, appDir: appDir2 } = unpackTo(bytes2, root);
45029
45202
  const opened = openPackageDir(appDir2);
@@ -45053,8 +45226,8 @@ async function loadPreviewAssets() {
45053
45226
  // in-repo checkout
45054
45227
  ];
45055
45228
  for (const path of candidates) {
45056
- if (!existsSync48(path)) continue;
45057
- const blob = readFileSync53(path);
45229
+ if (!existsSync49(path)) continue;
45230
+ const blob = readFileSync54(path);
45058
45231
  return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
45059
45232
  }
45060
45233
  return /* @__PURE__ */ new Map();
@@ -45136,7 +45309,7 @@ __export(run_browser_exports, {
45136
45309
  runInBrowser: () => runInBrowser
45137
45310
  });
45138
45311
  import { createServer as createServer5 } from "node:http";
45139
- import { existsSync as existsSync49, readFileSync as readFileSync54 } from "node:fs";
45312
+ import { existsSync as existsSync50, readFileSync as readFileSync55 } from "node:fs";
45140
45313
  import { spawnSync as spawnSync3, execFile as execFile3 } from "node:child_process";
45141
45314
  import { dirname as dirname27, resolve as resolve40 } from "node:path";
45142
45315
  import { fileURLToPath as fileURLToPath23 } from "node:url";
@@ -45144,7 +45317,7 @@ function stagedDir() {
45144
45317
  return process.env.HIMI_BROWSER_PLANE_OUT ? resolve40(process.env.HIMI_BROWSER_PLANE_OUT) : resolve40(REPO, "packages", "serve", "dist", "browser-plane");
45145
45318
  }
45146
45319
  function missingStaged() {
45147
- return [...SERVED].filter((f) => !existsSync49(resolve40(stagedDir(), f))).sort();
45320
+ return [...SERVED].filter((f) => !existsSync50(resolve40(stagedDir(), f))).sort();
45148
45321
  }
45149
45322
  function ensureBrowserPlaneStaged() {
45150
45323
  if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
@@ -45234,7 +45407,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
45234
45407
  }
45235
45408
  const name = path === "/" || path === "/index.html" ? "host.html" : path.slice(1);
45236
45409
  if (SERVED.has(name)) {
45237
- if (!existsSync49(resolve40(stagedDir(), name))) {
45410
+ if (!existsSync50(resolve40(stagedDir(), name))) {
45238
45411
  const restaged = ensureBrowserPlaneStaged();
45239
45412
  if (!restaged.ok) {
45240
45413
  res.writeHead(503, { "content-type": "application/json" });
@@ -45244,7 +45417,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
45244
45417
  }
45245
45418
  let bytes2;
45246
45419
  try {
45247
- bytes2 = readFileSync54(resolve40(stagedDir(), name));
45420
+ bytes2 = readFileSync55(resolve40(stagedDir(), name));
45248
45421
  } catch (e) {
45249
45422
  res.writeHead(503, { "content-type": "application/json" });
45250
45423
  res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
@@ -45707,7 +45880,7 @@ __export(preflight_exports, {
45707
45880
  parseStoreConfig: () => parseStoreConfig,
45708
45881
  requireEnv: () => requireEnv
45709
45882
  });
45710
- import { existsSync as existsSync50, readFileSync as readFileSync55 } from "node:fs";
45883
+ import { existsSync as existsSync51, readFileSync as readFileSync56 } from "node:fs";
45711
45884
  import { isAbsolute as isAbsolute3, relative as relative7, resolve as resolve41 } from "node:path";
45712
45885
  function isInsideRepo(p) {
45713
45886
  const rel = relative7(REPO_ROOT3, resolve41(p));
@@ -45764,10 +45937,10 @@ function parseStoreConfig(text4) {
45764
45937
  }
45765
45938
  function loadStoreConfig(app) {
45766
45939
  const p = storeConfigPath(app);
45767
- if (!existsSync50(p)) {
45940
+ if (!existsSync51(p)) {
45768
45941
  throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
45769
45942
  }
45770
- return parseStoreConfig(readFileSync55(p, "utf8"));
45943
+ return parseStoreConfig(readFileSync56(p, "utf8"));
45771
45944
  }
45772
45945
  var init_preflight = __esm({
45773
45946
  "../store-release/preflight.ts"() {
@@ -45786,7 +45959,7 @@ __export(credential_profile_exports, {
45786
45959
  profilePath: () => profilePath,
45787
45960
  resolveStoreCredentials: () => resolveStoreCredentials
45788
45961
  });
45789
- import { existsSync as existsSync51, readFileSync as readFileSync56 } from "node:fs";
45962
+ import { existsSync as existsSync52, readFileSync as readFileSync57 } from "node:fs";
45790
45963
  import { homedir as homedir5 } from "node:os";
45791
45964
  import { join as join47 } from "node:path";
45792
45965
  function credentialsDir(home = homedir5()) {
@@ -45829,8 +46002,8 @@ function resolveStoreCredentials(opts) {
45829
46002
  const { app, cfg } = opts;
45830
46003
  const env = opts.env ?? process.env;
45831
46004
  const home = opts.home ?? homedir5();
45832
- const read = opts.readProfile ?? ((p) => readFileSync56(p, "utf8"));
45833
- const exists = opts.profileExists ?? existsSync51;
46005
+ const read = opts.readProfile ?? ((p) => readFileSync57(p, "utf8"));
46006
+ const exists = opts.profileExists ?? existsSync52;
45834
46007
  const ios = cfg.ios ?? {};
45835
46008
  const flagName = opts.profileFlag?.trim();
45836
46009
  const named = namedProfile(cfg, opts.profileFlag);
@@ -45910,7 +46083,7 @@ __export(preflight_app_exports, {
45910
46083
  preflightApp: () => preflightApp,
45911
46084
  profileAccount: () => profileAccount
45912
46085
  });
45913
- import { readFileSync as readFileSync57, existsSync as existsSync52, readdirSync as readdirSync24, statSync as statSync11 } from "node:fs";
46086
+ import { readFileSync as readFileSync58, existsSync as existsSync53, readdirSync as readdirSync24, statSync as statSync11 } from "node:fs";
45914
46087
  import { createHash as createHash23 } from "node:crypto";
45915
46088
  import { join as join48 } from "node:path";
45916
46089
  function analyze(projectYml, storeConfig, icon, account) {
@@ -45976,8 +46149,8 @@ function profileAccount(app, storeConfig, opts = {}) {
45976
46149
  }
45977
46150
  }
45978
46151
  async function preflightApp(app, opts = {}) {
45979
- const projectYml = existsSync52(iosProjectYml(app)) ? readFileSync57(iosProjectYml(app), "utf8") : "";
45980
- const storeConfig = existsSync52(storeConfigPath(app)) ? readFileSync57(storeConfigPath(app), "utf8") : "";
46152
+ const projectYml = existsSync53(iosProjectYml(app)) ? readFileSync58(iosProjectYml(app), "utf8") : "";
46153
+ const storeConfig = existsSync53(storeConfigPath(app)) ? readFileSync58(storeConfigPath(app), "utf8") : "";
45981
46154
  if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
45982
46155
  const findings = analyze(
45983
46156
  projectYml,
@@ -46013,15 +46186,15 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
46013
46186
  function appLevelMetadataFiles(app, locale = "en-US") {
46014
46187
  const root = join48(storeDir(app), "metadata");
46015
46188
  const out = /* @__PURE__ */ new Set();
46016
- if (existsSync52(root)) {
46189
+ if (existsSync53(root)) {
46017
46190
  for (const n of readdirSync24(root)) if (n.endsWith(".txt")) out.add(n);
46018
46191
  }
46019
- if (existsSync52(join48(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
46192
+ if (existsSync53(join48(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
46020
46193
  return out;
46021
46194
  }
46022
46195
  function reviewInfoFiles(app) {
46023
46196
  const dir = join48(storeDir(app), "review_information");
46024
- if (!existsSync52(dir)) return /* @__PURE__ */ new Set();
46197
+ if (!existsSync53(dir)) return /* @__PURE__ */ new Set();
46025
46198
  return new Set(readdirSync24(dir).filter((n) => n.endsWith(".txt")));
46026
46199
  }
46027
46200
  function isValidAppStoreSize(w, h) {
@@ -46136,7 +46309,7 @@ function playListingAssets(app, locale = "en-US") {
46136
46309
  for (const name of names) {
46137
46310
  const p = join48(dir, name);
46138
46311
  try {
46139
- if (statSync11(p).isFile()) return { name, bytes: readFileSync57(p) };
46312
+ if (statSync11(p).isFile()) return { name, bytes: readFileSync58(p) };
46140
46313
  } catch {
46141
46314
  }
46142
46315
  }
@@ -46168,25 +46341,25 @@ function analyzeListing(metaFiles, shots) {
46168
46341
  }
46169
46342
  function metadataFilesPresent(app, locale = "en-US") {
46170
46343
  const dir = join48(storeDir(app), "metadata", locale);
46171
- if (!existsSync52(dir)) return /* @__PURE__ */ new Set();
46344
+ if (!existsSync53(dir)) return /* @__PURE__ */ new Set();
46172
46345
  return new Set(readdirSync24(dir).filter((n) => n.endsWith(".txt")));
46173
46346
  }
46174
46347
  function listScreenshots(app, locale = "en-US") {
46175
46348
  const out = [];
46176
46349
  const flat = join48(storeDir(app), "screenshots", locale);
46177
- if (existsSync52(flat)) {
46350
+ if (existsSync53(flat)) {
46178
46351
  for (const png of readdirSync24(flat).filter((n) => n.endsWith(".png"))) {
46179
- const sz = pngSize(readFileSync57(join48(flat, png)));
46352
+ const sz = pngSize(readFileSync58(join48(flat, png)));
46180
46353
  if (sz) out.push({ name: png, w: sz.w, h: sz.h });
46181
46354
  }
46182
46355
  }
46183
46356
  const legacy = join48(storeDir(app), "metadata", locale, "screenshots");
46184
- if (existsSync52(legacy)) {
46357
+ if (existsSync53(legacy)) {
46185
46358
  for (const deviceDir of readdirSync24(legacy)) {
46186
46359
  const d = join48(legacy, deviceDir);
46187
46360
  if (!statSync11(d).isDirectory()) continue;
46188
46361
  for (const png of readdirSync24(d).filter((n) => n.endsWith(".png"))) {
46189
- const sz = pngSize(readFileSync57(join48(d, png)));
46362
+ const sz = pngSize(readFileSync58(join48(d, png)));
46190
46363
  if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
46191
46364
  }
46192
46365
  }
@@ -46195,12 +46368,12 @@ function listScreenshots(app, locale = "en-US") {
46195
46368
  }
46196
46369
  function placeholderHashes2() {
46197
46370
  const templateIos = join48(appDir("_template"), "ios");
46198
- if (!existsSync52(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
46371
+ if (!existsSync53(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
46199
46372
  for (const target of readdirSync24(templateIos)) {
46200
46373
  const p = join48(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
46201
46374
  try {
46202
46375
  if (!statSync11(p).isFile()) continue;
46203
- return [LEGACY_PLACEHOLDER_SHA2562, createHash23("sha256").update(readFileSync57(p)).digest("hex")];
46376
+ return [LEGACY_PLACEHOLDER_SHA2562, createHash23("sha256").update(readFileSync58(p)).digest("hex")];
46204
46377
  } catch {
46205
46378
  }
46206
46379
  }
@@ -46231,12 +46404,12 @@ async function pixelIssues(bytes2) {
46231
46404
  }
46232
46405
  }
46233
46406
  async function appIconState(iosDir) {
46234
- if (!existsSync52(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
46407
+ if (!existsSync53(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
46235
46408
  for (const target of readdirSync24(iosDir)) {
46236
46409
  const p = join48(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
46237
46410
  try {
46238
46411
  if (!statSync11(p).isFile()) continue;
46239
- const bytes2 = readFileSync57(p);
46412
+ const bytes2 = readFileSync58(p);
46240
46413
  const hash = createHash23("sha256").update(bytes2).digest("hex");
46241
46414
  const pixels = await pixelIssues(bytes2);
46242
46415
  return {
@@ -46308,7 +46481,7 @@ __export(version_exports, {
46308
46481
  setAndroidVersion: () => setAndroidVersion,
46309
46482
  setIosVersion: () => setIosVersion
46310
46483
  });
46311
- import { readFileSync as readFileSync58, writeFileSync as writeFileSync20 } from "node:fs";
46484
+ import { readFileSync as readFileSync59, writeFileSync as writeFileSync20 } from "node:fs";
46312
46485
  function readIosVersion(projectYml) {
46313
46486
  const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
46314
46487
  const build2 = matchScalar(projectYml, "CFBundleVersion");
@@ -46366,8 +46539,8 @@ function setAndroidVersion(gradle, v) {
46366
46539
  function bumpVersion(app, opts) {
46367
46540
  const iosPath = iosProjectYml(app);
46368
46541
  const gradlePath = androidGradle(app);
46369
- const iosYml = readFileSync58(iosPath, "utf8");
46370
- const gradle = readFileSync58(gradlePath, "utf8");
46542
+ const iosYml = readFileSync59(iosPath, "utf8");
46543
+ const gradle = readFileSync59(gradlePath, "utf8");
46371
46544
  const current = readIosVersion(iosYml);
46372
46545
  const next = {
46373
46546
  marketing: opts.marketing ?? current.marketing,
@@ -46384,7 +46557,7 @@ var init_version = __esm({
46384
46557
  });
46385
46558
 
46386
46559
  // ../store-release/register-bundle.ts
46387
- import { readFileSync as readFileSync59 } from "node:fs";
46560
+ import { readFileSync as readFileSync60 } from "node:fs";
46388
46561
  import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
46389
46562
  function b64url2(b) {
46390
46563
  return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -46402,7 +46575,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
46402
46575
  async function registerBundleId(opts) {
46403
46576
  const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
46404
46577
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
46405
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync59(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
46578
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync60(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
46406
46579
  const res = await fetch(`${ASC_API}/v1/bundleIds`, {
46407
46580
  method: "POST",
46408
46581
  headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
@@ -46456,7 +46629,7 @@ __export(asc_status_exports, {
46456
46629
  ascStatus: () => ascStatus,
46457
46630
  buildVerdict: () => buildVerdict
46458
46631
  });
46459
- import { readFileSync as readFileSync60 } from "node:fs";
46632
+ import { readFileSync as readFileSync61 } from "node:fs";
46460
46633
  function buildVerdict(builds) {
46461
46634
  if (!builds.length) {
46462
46635
  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).";
@@ -46470,7 +46643,7 @@ function buildVerdict(builds) {
46470
46643
  function client(creds) {
46471
46644
  const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
46472
46645
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
46473
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync60(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
46646
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync61(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
46474
46647
  return async (path) => {
46475
46648
  const r = await fetch(`${ASC}${path}`, { headers: { Authorization: `Bearer ${jwt}` } });
46476
46649
  return { status: r.status, json: await r.json().catch(() => ({})) };
@@ -46630,7 +46803,7 @@ __export(secrets_exports, {
46630
46803
  runRemoteSecretsCommand: () => runRemoteSecretsCommand,
46631
46804
  runSecretsCommand: () => runSecretsCommand
46632
46805
  });
46633
- import { readFileSync as readFileSync61 } from "node:fs";
46806
+ import { readFileSync as readFileSync62 } from "node:fs";
46634
46807
  function environment(value) {
46635
46808
  if (value === "preview" || value === "production") return value;
46636
46809
  throw new Error("--environment must be preview or production");
@@ -46640,9 +46813,9 @@ function required(value, flag) {
46640
46813
  return value;
46641
46814
  }
46642
46815
  function masterKey() {
46643
- const encoded = process.env.HIMI_SECRET_MASTER_KEY;
46644
- if (!encoded) throw new Error("HIMI_SECRET_MASTER_KEY is required (base64url-encoded 32-byte key)");
46645
- const key2 = Buffer.from(encoded, "base64url");
46816
+ const encoded2 = process.env.HIMI_SECRET_MASTER_KEY;
46817
+ if (!encoded2) throw new Error("HIMI_SECRET_MASTER_KEY is required (base64url-encoded 32-byte key)");
46818
+ const key2 = Buffer.from(encoded2, "base64url");
46646
46819
  if (key2.byteLength !== 32) throw new Error("HIMI_SECRET_MASTER_KEY must decode to exactly 32 bytes");
46647
46820
  return key2;
46648
46821
  }
@@ -46661,7 +46834,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
46661
46834
  io.log(JSON.stringify(await vault.list({ app, environment: env })));
46662
46835
  return 0;
46663
46836
  }
46664
- const value = options.readValue ? options.readValue() : readFileSync61(0, "utf8").replace(/\r?\n$/, "");
46837
+ const value = options.readValue ? options.readValue() : readFileSync62(0, "utf8").replace(/\r?\n$/, "");
46665
46838
  if (operation === "set") await vault.set({ app, environment: env, name, value });
46666
46839
  else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
46667
46840
  else throw new Error(`unknown secrets operation ${operation}`);
@@ -46690,7 +46863,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
46690
46863
  }
46691
46864
  let body;
46692
46865
  if (operation !== "list") {
46693
- const value = options.readValue ? options.readValue() : readFileSync61(0, "utf8").replace(/\r?\n$/, "");
46866
+ const value = options.readValue ? options.readValue() : readFileSync62(0, "utf8").replace(/\r?\n$/, "");
46694
46867
  body = JSON.stringify({ value });
46695
46868
  }
46696
46869
  const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
@@ -46726,7 +46899,7 @@ __export(notify_exports, {
46726
46899
  runNotify: () => runNotify,
46727
46900
  saveAdminSession: () => saveAdminSession
46728
46901
  });
46729
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync24, readFileSync as readFileSync62, writeFileSync as writeFileSync21 } from "node:fs";
46902
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync24, readFileSync as readFileSync63, writeFileSync as writeFileSync21 } from "node:fs";
46730
46903
  import { homedir as homedir6 } from "node:os";
46731
46904
  import { dirname as dirname29, join as join49 } from "node:path";
46732
46905
  function defaultSessionsPath() {
@@ -46734,7 +46907,7 @@ function defaultSessionsPath() {
46734
46907
  }
46735
46908
  function loadSessionsFile(path = defaultSessionsPath()) {
46736
46909
  try {
46737
- return JSON.parse(readFileSync62(path, "utf8"));
46910
+ return JSON.parse(readFileSync63(path, "utf8"));
46738
46911
  } catch {
46739
46912
  return {};
46740
46913
  }
@@ -50710,10 +50883,10 @@ function patchGrids(src, installed, patch) {
50710
50883
  return out + src.slice(cursor);
50711
50884
  }
50712
50885
  function patchModules(src, installed, patch) {
50713
- return src.replace(/"homeModules": "((?:[^"\\]|\\.)*)"/g, (whole, encoded) => {
50886
+ return src.replace(/"homeModules": "((?:[^"\\]|\\.)*)"/g, (whole, encoded2) => {
50714
50887
  let modules;
50715
50888
  try {
50716
- const parsed = JSON.parse(JSON.parse(`"${encoded}"`));
50889
+ const parsed = JSON.parse(JSON.parse(`"${encoded2}"`));
50717
50890
  if (!Array.isArray(parsed)) return whole;
50718
50891
  modules = parsed;
50719
50892
  } catch {
@@ -50901,7 +51074,7 @@ var init_home_descriptor = __esm({
50901
51074
  });
50902
51075
 
50903
51076
  // src/site-analyze/apply.ts
50904
- import { existsSync as existsSync53, readFileSync as readFileSync63, writeFileSync as writeFileSync23, copyFileSync as copyFileSync3, mkdirSync as mkdirSync26, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
51077
+ import { existsSync as existsSync54, readFileSync as readFileSync64, writeFileSync as writeFileSync23, copyFileSync as copyFileSync3, mkdirSync as mkdirSync26, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
50905
51078
  import { dirname as dirname30, isAbsolute as isAbsolute4, join as join51, resolve as resolve42, sep as sep11 } from "node:path";
50906
51079
  import { spawnSync as spawnSync4 } from "node:child_process";
50907
51080
  function unpairedRedirectNote(overlay) {
@@ -50917,7 +51090,7 @@ function committedShellProvisioning(path) {
50917
51090
  function findRepoRoot(cwd) {
50918
51091
  let dir = cwd;
50919
51092
  for (let i = 0; i < 8; i++) {
50920
- if (SHELL_NAMES2.some((name) => existsSync53(join51(dir, shellAppDir(name), "package.json")))) return dir;
51093
+ if (SHELL_NAMES2.some((name) => existsSync54(join51(dir, shellAppDir(name), "package.json")))) return dir;
50921
51094
  const next = dirname30(dir);
50922
51095
  if (next === dir) break;
50923
51096
  dir = next;
@@ -50986,10 +51159,10 @@ function mergeCustomerOwned(committed, overlay) {
50986
51159
  function buildMergedContract(options) {
50987
51160
  const { appDir: appDir2, packageDir, overlay } = options;
50988
51161
  const committedPath = join51(appDir2, "provisioning.json");
50989
- if (!existsSync53(committedPath)) {
51162
+ if (!existsSync54(committedPath)) {
50990
51163
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
50991
51164
  }
50992
- const committed = JSON.parse(readFileSync63(committedPath, "utf8"));
51165
+ const committed = JSON.parse(readFileSync64(committedPath, "utf8"));
50993
51166
  const merged = mergeCustomerOwned(committed, overlay);
50994
51167
  const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
50995
51168
  const branding = merged.branding ?? {};
@@ -51002,7 +51175,7 @@ function buildMergedContract(options) {
51002
51175
  const stage = (fromRel, toRel) => {
51003
51176
  const from = contained(packageDir, fromRel);
51004
51177
  const to = contained(join51(appDir2, STAGED), toRel.slice(STAGED.length + 1));
51005
- if (!from || !to || !existsSync53(from)) return void 0;
51178
+ if (!from || !to || !existsSync54(from)) return void 0;
51006
51179
  let real;
51007
51180
  let realRoot;
51008
51181
  try {
@@ -51025,10 +51198,10 @@ function buildMergedContract(options) {
51025
51198
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
51026
51199
  if (icon) branding.appIconPath = icon;
51027
51200
  const facesPath = join51(packageDir, "media/fonts/faces.json");
51028
- if (existsSync53(facesPath)) {
51201
+ if (existsSync54(facesPath)) {
51029
51202
  let faces = [];
51030
51203
  try {
51031
- const parsed = JSON.parse(readFileSync63(facesPath, "utf8"));
51204
+ const parsed = JSON.parse(readFileSync64(facesPath, "utf8"));
51032
51205
  faces = Array.isArray(parsed) ? parsed : [];
51033
51206
  } catch {
51034
51207
  faces = [];
@@ -51061,8 +51234,8 @@ async function applyOverlays(input) {
51061
51234
  const cwd = resolve42(input.cwd);
51062
51235
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
51063
51236
  assertKnownShell(shell);
51064
- const overlay = JSON.parse(readFileSync63(input.overlayPath, "utf8"));
51065
- const tokens = JSON.parse(readFileSync63(input.tokensPath, "utf8"));
51237
+ const overlay = JSON.parse(readFileSync64(input.overlayPath, "utf8"));
51238
+ const tokens = JSON.parse(readFileSync64(input.tokensPath, "utf8"));
51066
51239
  const wrote = [];
51067
51240
  const notes = [];
51068
51241
  const repoRoot2 = findRepoRoot(cwd);
@@ -51096,8 +51269,8 @@ async function applyOverlays(input) {
51096
51269
  }
51097
51270
  const pkgProv = join51(cwd, "provisioning.json");
51098
51271
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
51099
- if (existsSync53(pkgProv)) {
51100
- const cur = JSON.parse(readFileSync63(pkgProv, "utf8"));
51272
+ if (existsSync54(pkgProv)) {
51273
+ const cur = JSON.parse(readFileSync64(pkgProv, "utf8"));
51101
51274
  const merged = deepMerge4(cur, overlay);
51102
51275
  writeFileSync23(pkgProv, JSON.stringify(merged, null, 2) + "\n");
51103
51276
  wrote.push(pkgProv);
@@ -51106,8 +51279,8 @@ async function applyOverlays(input) {
51106
51279
  wrote.push(pkgProv);
51107
51280
  }
51108
51281
  const pkgTokens = join51(cwd, "tokens.json");
51109
- if (existsSync53(pkgTokens) && (tokens.colors || tokens.typography)) {
51110
- const cur = JSON.parse(readFileSync63(pkgTokens, "utf8"));
51282
+ if (existsSync54(pkgTokens) && (tokens.colors || tokens.typography)) {
51283
+ const cur = JSON.parse(readFileSync64(pkgTokens, "utf8"));
51111
51284
  const merged = deepMerge4(cur, tokens);
51112
51285
  const mergedColors = merged.colors;
51113
51286
  if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
@@ -51118,8 +51291,8 @@ async function applyOverlays(input) {
51118
51291
  }
51119
51292
  const homeAction = homeRefreshActionId(shell);
51120
51293
  const homeSrc = join51(cwd, "dev/index.ts");
51121
- if (homeAction && existsSync53(homeSrc)) {
51122
- const prev = readFileSync63(homeSrc, "utf8");
51294
+ if (homeAction && existsSync54(homeSrc)) {
51295
+ const prev = readFileSync64(homeSrc, "utf8");
51123
51296
  const patched = patchBrandParams(prev, overlay, homeAction);
51124
51297
  let next = patched.src;
51125
51298
  if (!patched.foreign && overlay.installedVerticals?.length) {
@@ -51142,13 +51315,13 @@ async function applyOverlays(input) {
51142
51315
  notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
51143
51316
  }
51144
51317
  }
51145
- if (!input.iconPath || !existsSync53(input.iconPath)) {
51318
+ if (!input.iconPath || !existsSync54(input.iconPath)) {
51146
51319
  const book = input.iconPath ? dirname30(dirname30(resolve42(input.iconPath))) : void 0;
51147
51320
  notes.push(
51148
51321
  book ? `no icon installed \u2014 ${siteLogoAbsence(book).hint}` : "no icon installed and no business book to say why \u2014 `himi icon generate` draws one from the accent, or `himi icon set <file.png>` installs the customer's own mark"
51149
51322
  );
51150
51323
  }
51151
- if (input.iconPath && existsSync53(input.iconPath)) {
51324
+ if (input.iconPath && existsSync54(input.iconPath)) {
51152
51325
  try {
51153
51326
  const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
51154
51327
  wrote.push(...installed.wrote);
@@ -55302,7 +55475,7 @@ __export(cli_exports, {
55302
55475
  runSiteAnalyze: () => runSiteAnalyze,
55303
55476
  runSiteFunctionCli: () => runSiteFunctionCli
55304
55477
  });
55305
- import { readFileSync as readFileSync64 } from "node:fs";
55478
+ import { readFileSync as readFileSync65 } from "node:fs";
55306
55479
  import { resolve as resolve43 } from "node:path";
55307
55480
  function assetFetchFor(_opts) {
55308
55481
  return pinnedFetch2;
@@ -55389,7 +55562,7 @@ async function runSiteFunctionCli(opts) {
55389
55562
  let source;
55390
55563
  if (opts.sourcePath) {
55391
55564
  const p = resolve43(opts.cwd ?? process.cwd(), opts.sourcePath);
55392
- source = readFileSync64(p, "utf8");
55565
+ source = readFileSync65(p, "utf8");
55393
55566
  }
55394
55567
  let body;
55395
55568
  if (opts.bodyRaw != null) {
@@ -55646,7 +55819,7 @@ __export(site_create_exports, {
55646
55819
  runSiteList: () => runSiteList,
55647
55820
  writeProvisioningBinding: () => writeProvisioningBinding
55648
55821
  });
55649
- import { existsSync as existsSync54, readFileSync as readFileSync65, writeFileSync as writeFileSync24 } from "node:fs";
55822
+ import { existsSync as existsSync55, readFileSync as readFileSync66, writeFileSync as writeFileSync24 } from "node:fs";
55650
55823
  import { resolve as resolvePath2 } from "node:path";
55651
55824
  function oauthClientName(projectName) {
55652
55825
  return `${projectName} client`;
@@ -55795,7 +55968,7 @@ async function runSiteCreate(opts) {
55795
55968
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
55796
55969
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
55797
55970
  }
55798
- function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync54, readFileSync: readFileSync65, writeFileSync: writeFileSync24 }) {
55971
+ function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync55, readFileSync: readFileSync66, writeFileSync: writeFileSync24 }) {
55799
55972
  const msid = binding2.siteId;
55800
55973
  const path = resolvePath2(target);
55801
55974
  const committed = committedShellProvisioning(path);
@@ -56127,7 +56300,7 @@ var init_site_oauth_client = __esm({
56127
56300
  });
56128
56301
 
56129
56302
  // src/cli.ts
56130
- import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync66, mkdirSync as mkdirSync27, writeFileSync as writeFileSync25, existsSync as existsSync55, rmSync as rmSync10, readdirSync as readdirSync25, statSync as statSync13, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
56303
+ import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync67, mkdirSync as mkdirSync27, writeFileSync as writeFileSync25, existsSync as existsSync56, rmSync as rmSync10, readdirSync as readdirSync25, statSync as statSync13, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
56131
56304
  import { execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn5 } from "node:child_process";
56132
56305
  import { createHash as createHash24, randomUUID as randomUUID3 } from "node:crypto";
56133
56306
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
@@ -58574,6 +58747,14 @@ init_splash();
58574
58747
 
58575
58748
  // src/lint-report.ts
58576
58749
  init_himi_report();
58750
+ function nondeterministicWorkers(workers) {
58751
+ return (workers ?? []).filter((w) => w.nondeterministicServices?.length).map((w) => ({ bundle: w.bundle ?? "(unnamed)", services: [...w.nondeterministicServices] }));
58752
+ }
58753
+ function describeNondeterministicWorkers(workers) {
58754
+ const one = (w) => `worker "${w.bundle}" (${w.services.length === 1 ? "service" : "services"} ${w.services.join(", ")})`;
58755
+ return workers.length <= 1 ? workers.map(one).join("") : `${workers.slice(0, -1).map(one).join(", ")} and ${one(workers[workers.length - 1])}`;
58756
+ }
58757
+ var NONDETERMINISTIC_FIX = "move those clock or random values out of the service's initial state and compute them in an action instead (for example one the screen's onAppear dispatches)";
58577
58758
  function summarizeLint(app, bres, outcome, strict, extraIssues = []) {
58578
58759
  const issues = (outcome.lint ?? []).flatMap((s) => s.issues.map((i) => ({ screen: s.screenId, ...i })));
58579
58760
  issues.push(...extraIssues);
@@ -58622,8 +58803,20 @@ function summarizeLint(app, bres, outcome, strict, extraIssues = []) {
58622
58803
  message: failure.message
58623
58804
  });
58624
58805
  }
58806
+ for (const w of nondeterministicWorkers(outcome.workers)) {
58807
+ issues.push({
58808
+ screen: null,
58809
+ pass: "initial-state",
58810
+ severity: "warning",
58811
+ ruleCode: "nondeterministic-initial-state",
58812
+ bundle: w.bundle,
58813
+ path: w.bundle,
58814
+ services: w.services,
58815
+ message: `${describeNondeterministicWorkers([w])} builds a different initial state depending on when it is built \u2014 it reads the clock or Math.random() while it boots, and that state is hashed into the release. So builds of this unchanged source produce different releases (a new releaseId off-repo; new content under the same id in-repo), and a mobile-UX drive or attestation recorded against one build will not match the release a later push builds. To fix it, ${NONDETERMINISTIC_FIX}.`
58816
+ });
58817
+ }
58625
58818
  const errorIssues = issues.filter((i) => i.severity === "error");
58626
- const workers = (outcome.workers ?? []).filter((w) => w.threw || w.console.length);
58819
+ const workers = (outcome.workers ?? []).filter((w) => w.threw || w.console.length || w.nondeterministicServices?.length);
58627
58820
  const workerThrows = workers.filter((w) => w.threw);
58628
58821
  const hasErrors = bres.compileErrors.length > 0 || outcome.failedToBuild.length > 0 || outcome.missingBundles.length > 0 || errorIssues.length > 0 || workerThrows.length > 0;
58629
58822
  const legacy = {
@@ -59389,7 +59582,7 @@ var num = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v))
59389
59582
  function embeddedTemplateCatalog() {
59390
59583
  return availableTemplates().map((name) => {
59391
59584
  const path = join52(templateSourceDir(name), TEMPLATE_META_FILE);
59392
- const meta = JSON.parse(readFileSync66(path, "utf8"));
59585
+ const meta = JSON.parse(readFileSync67(path, "utf8"));
59393
59586
  if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
59394
59587
  throw new Error(`${path} must be { title: string, description: string, tags: string[], category?: string }`);
59395
59588
  }
@@ -60031,7 +60224,7 @@ var COMMANDS = [
60031
60224
  ];
60032
60225
  function cliVersion() {
60033
60226
  try {
60034
- return JSON.parse(readFileSync66(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
60227
+ return JSON.parse(readFileSync67(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
60035
60228
  } catch {
60036
60229
  return "unknown";
60037
60230
  }
@@ -60126,7 +60319,7 @@ function ageInDays(publishedAt, now = Date.now()) {
60126
60319
  }
60127
60320
  function packageVersion(path) {
60128
60321
  try {
60129
- const version2 = JSON.parse(readFileSync66(path, "utf8")).version;
60322
+ const version2 = JSON.parse(readFileSync67(path, "utf8")).version;
60130
60323
  return typeof version2 === "string" && version2 ? version2 : void 0;
60131
60324
  } catch {
60132
60325
  return void 0;
@@ -60196,7 +60389,7 @@ function updateCachePath(env = process.env) {
60196
60389
  }
60197
60390
  function readUpdateCache(path) {
60198
60391
  try {
60199
- const parsed = JSON.parse(readFileSync66(path, "utf8"));
60392
+ const parsed = JSON.parse(readFileSync67(path, "utf8"));
60200
60393
  return parsed && typeof parsed === "object" ? parsed : {};
60201
60394
  } catch {
60202
60395
  return {};
@@ -60269,7 +60462,7 @@ function createUpdateRunner(spawn6 = spawnSync5) {
60269
60462
  reexec: (argv) => {
60270
60463
  const root = globalNodeModulesRoot();
60271
60464
  const entry = root ? join52(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
60272
- if (!entry || !existsSync55(entry)) return void 0;
60465
+ if (!entry || !existsSync56(entry)) return void 0;
60273
60466
  const result = spawnSync5(process.execPath, [entry, ...argv], {
60274
60467
  // inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
60275
60468
  stdio: "inherit",
@@ -60316,7 +60509,7 @@ function staleUpdateLockFile(cachePath, now) {
60316
60509
  for (const path of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
60317
60510
  let content;
60318
60511
  try {
60319
- content = readFileSync66(path, "utf8");
60512
+ content = readFileSync67(path, "utf8");
60320
60513
  } catch {
60321
60514
  continue;
60322
60515
  }
@@ -60339,7 +60532,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
60339
60532
  const mine = lockStamp(now);
60340
60533
  const readLock = (path) => {
60341
60534
  try {
60342
- return readFileSync66(path, "utf8");
60535
+ return readFileSync67(path, "utf8");
60343
60536
  } catch {
60344
60537
  return void 0;
60345
60538
  }
@@ -60979,7 +61172,7 @@ async function nativeConfigAdvisories(app, configSource) {
60979
61172
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
60980
61173
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
60981
61174
  const iosYmlPath = iosProjectYml2(app);
60982
- const iosYml = existsSync55(iosYmlPath) ? readFileSync66(iosYmlPath, "utf8") : "";
61175
+ const iosYml = existsSync56(iosYmlPath) ? readFileSync67(iosYmlPath, "utf8") : "";
60983
61176
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
60984
61177
  if (!optedIn) {
60985
61178
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -60993,7 +61186,7 @@ async function nativeConfigAdvisories(app, configSource) {
60993
61186
  }
60994
61187
  function readConfigSource(dir) {
60995
61188
  try {
60996
- return readFileSync66(join52(dir, "config.ts"), "utf8");
61189
+ return readFileSync67(join52(dir, "config.ts"), "utf8");
60997
61190
  } catch {
60998
61191
  return null;
60999
61192
  }
@@ -61005,7 +61198,7 @@ function writePngFile(path, base64) {
61005
61198
  }
61006
61199
  async function initFromRemoteTemplate(name, parentDir, template, c) {
61007
61200
  const dir = resolve44(parentDir, name);
61008
- if (existsSync55(join52(dir, "himalaya.content.json"))) {
61201
+ if (existsSync56(join52(dir, "himalaya.content.json"))) {
61009
61202
  throw new Error(`content package already exists at ${dir}`);
61010
61203
  }
61011
61204
  const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -61048,7 +61241,7 @@ function symlinkDestinationIssue(dest) {
61048
61241
  function restoreDestinationIssue(dest, force) {
61049
61242
  const link = symlinkDestinationIssue(dest);
61050
61243
  if (link) return link;
61051
- if (!existsSync55(dest)) return null;
61244
+ if (!existsSync56(dest)) return null;
61052
61245
  if (!statSync13(dest).isDirectory()) {
61053
61246
  return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
61054
61247
  }
@@ -61063,7 +61256,7 @@ function restoreDestinationIssue(dest, force) {
61063
61256
  function isHimalayaMonorepoCheckout(start) {
61064
61257
  let dir = resolve44(start);
61065
61258
  for (; ; ) {
61066
- if (existsSync55(join52(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync55(join52(dir, "core", "serve", "src", "server.ts"))) return true;
61259
+ if (existsSync56(join52(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync56(join52(dir, "core", "serve", "src", "server.ts"))) return true;
61067
61260
  const parent = dirname31(dir);
61068
61261
  if (parent === dir) return false;
61069
61262
  dir = parent;
@@ -61133,8 +61326,8 @@ function materializeForPreview(appDir2, slug, displayName) {
61133
61326
  }
61134
61327
  async function appId(dir) {
61135
61328
  try {
61136
- const { readFileSync: readFileSync67 } = await import("node:fs");
61137
- const m = JSON.parse(readFileSync67(join52(dir, "himalaya.content.json"), "utf8"));
61329
+ const { readFileSync: readFileSync68 } = await import("node:fs");
61330
+ const m = JSON.parse(readFileSync68(join52(dir, "himalaya.content.json"), "utf8"));
61138
61331
  if (m.name) return m.name;
61139
61332
  } catch {
61140
61333
  }
@@ -61142,8 +61335,8 @@ async function appId(dir) {
61142
61335
  }
61143
61336
  async function contentVisibility(dir) {
61144
61337
  try {
61145
- const { readFileSync: readFileSync67 } = await import("node:fs");
61146
- const m = JSON.parse(readFileSync67(join52(dir, "himalaya.content.json"), "utf8"));
61338
+ const { readFileSync: readFileSync68 } = await import("node:fs");
61339
+ const m = JSON.parse(readFileSync68(join52(dir, "himalaya.content.json"), "utf8"));
61147
61340
  if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
61148
61341
  } catch {
61149
61342
  }
@@ -61362,16 +61555,18 @@ function resolutionFlag(flags) {
61362
61555
  if (flags.source === true) return "source";
61363
61556
  return void 0;
61364
61557
  }
61365
- async function recordedReleaseForContentQuietly(dir, resolution) {
61558
+ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
61366
61559
  let out;
61367
61560
  try {
61368
61561
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
61369
61562
  const bres = await buildContentForValidation2(dir, { resolution });
61370
61563
  out = mkdtempSync4(join52(tmpdir5(), "himi-ux-record-"));
61371
61564
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
61372
- const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {} });
61565
+ const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
61373
61566
  const releaseId = outcome.manifest.releaseId;
61374
61567
  if (!releaseId) return null;
61568
+ const drifting = nondeterministicWorkers(outcome.workers);
61569
+ if (drifting.length) onDrift?.(drifting);
61375
61570
  const payload = await loadReleaseFromDir(await appId(dir), out);
61376
61571
  return { releaseId, releaseHash: releasePayloadHash(payload) };
61377
61572
  } catch {
@@ -61400,6 +61595,10 @@ function handoverUxEvidence(dir, release) {
61400
61595
  }
61401
61596
  return evidence;
61402
61597
  }
61598
+ function releaseDriftCause(workers, redo, evidence) {
61599
+ const one = workers.length === 1;
61600
+ return `${redo} alone cannot reliably clear this: ${describeNondeterministicWorkers(workers)} ${one ? "builds" : "build"} a different initial state depending on when ${one ? "it is" : "they are"} built \u2014 ${one ? "it reads" : "they read"} the clock or Math.random() while booting, and that state is hashed into the release \u2014 so this unchanged package builds a different release from one run to the next, and ${evidence} recorded now cannot be relied on to match the release the next push builds. First ${NONDETERMINISTIC_FIX}`;
61601
+ }
61403
61602
  function uxRecordCommands(contentPath) {
61404
61603
  return `\`himi ux audit --content ${contentPath} --strict\`, then \`himi ux record --content ${contentPath} --platform ios --status unavailable --reason "<why you could not drive it>"\``;
61405
61604
  }
@@ -61421,7 +61620,11 @@ function uxHandoverHint(uxEvidence, ctx) {
61421
61620
  if (uxEvidence.state === "failed") {
61422
61621
  return `a mobile-UX drive for ${releaseId} IS recorded, and it FAILED on ${uxEvidence.failedPlatforms.join(", ")} (see ${uxEvidence.path}). A published draft is the owner-private preview a customer is handed, so fix what the drive found and re-record it \u2014 re-running \`himi ux record\` over a failure without changing the app just writes the same failure down again. Only if you intend to hand a customer a preview whose UX you already know is broken, \`${door} --force\`.`;
61423
61622
  }
61424
- const why = uxEvidence.state === "absent" ? `nothing has recorded a mobile-UX drive for this package \u2014 ${uxEvidence.path} does not exist` : uxEvidence.state === "unrecorded" ? uxEvidence.malformed.length ? `${uxEvidence.path} has no iOS or Android drive this gate can read \u2014 ${uxEvidence.malformed.join("; ")}` : `${uxEvidence.path} exists but carries no iOS or Android drive (\`himi render\` writes its rendered widths there too, so the file alone proves nothing)` : uxEvidence.state === "unreadable" ? `${ctx.quote(`${ctx.contentDir}/${uxEvidence.path}`)} ${uxEvidence.error} \u2014 delete it and record again, because re-recording over a malformed store does not repair it` : uxEvidence.state === "outdated" ? `a mobile-UX drive for ${releaseId} is recorded, but the package has CHANGED since \u2014 in-repo a release id is the git HEAD sha, so editing a screen, a token or a worker without committing keeps the id while replacing everything it identifies (a record written before this check also lands here, carrying no content hash)` : `the recorded mobile-UX drive is about ${uxEvidence.otherReleases.length ? `release ${uxEvidence.otherReleases.join(", ")}` : "no release at all"}, not ${releaseId}${uxEvidence.unstamped ? ` (${uxEvidence.unstamped} drive(s) name no release)` : ""}`;
61623
+ const why = uxEvidence.state === "absent" ? `nothing has recorded a mobile-UX drive for this package \u2014 ${uxEvidence.path} does not exist` : uxEvidence.state === "unrecorded" ? uxEvidence.malformed.length ? `${uxEvidence.path} has no iOS or Android drive this gate can read \u2014 ${uxEvidence.malformed.join("; ")}` : `${uxEvidence.path} exists but carries no iOS or Android drive (\`himi render\` writes its rendered widths there too, so the file alone proves nothing)` : uxEvidence.state === "unreadable" ? `${ctx.quote(`${ctx.contentDir}/${uxEvidence.path}`)} ${uxEvidence.error} \u2014 delete it and record again, because re-recording over a malformed store does not repair it` : uxEvidence.state === "outdated" && ctx.nondeterministicWorkers?.length ? `a mobile-UX drive for ${releaseId} is recorded, but it describes different content from the release this push just built \u2014 an uncommitted edit since the record would do that, and so does the worker named below` : uxEvidence.state === "outdated" ? `a mobile-UX drive for ${releaseId} is recorded, but the package has CHANGED since \u2014 in-repo a release id is the git HEAD sha, so editing a screen, a token or a worker without committing keeps the id while replacing everything it identifies (a record written before this check also lands here, carrying no content hash)` : `the recorded mobile-UX drive is about ${uxEvidence.otherReleases.length ? `release ${uxEvidence.otherReleases.join(", ")}` : "no release at all"}, not ${releaseId}${uxEvidence.unstamped ? ` (${uxEvidence.unstamped} drive(s) name no release)` : ""}`;
61624
+ const drifting = ctx.nondeterministicWorkers ?? [];
61625
+ if (drifting.length > 0) {
61626
+ return `${why}. ${releaseDriftCause(drifting, "Re-recording", "a drive")}; then record the drive: ${uxRemedy}, and re-run \`${door}\`. Only if you intend to hand over a preview WITHOUT that evidence, \`${door} --force\`.`;
61627
+ }
61425
61628
  return `${why}. A published draft is the owner-private preview a customer is handed, so record the drive first: ${uxRemedy}, then re-run \`${door}\`. Only if you intend to hand over a preview WITHOUT that evidence, \`${door} --force\`.`;
61426
61629
  }
61427
61630
  var SECRET_FLAG_NAME = /token|secret|password|cookie|auth/i;
@@ -61448,10 +61651,18 @@ function uxHandoverNote(uxEvidence, ctx) {
61448
61651
  if (uxEvidence.state === "failed") {
61449
61652
  return `published over a FAILED mobile-UX drive for ${ctx.releaseId} on ${uxEvidence.failedPlatforms.join(", ")}. The preview link below is the owner-private handover \u2014 fix what the drive found and publish again before a customer reviews it.`;
61450
61653
  }
61654
+ const drifting = ctx.nondeterministicWorkers ?? [];
61655
+ const driftCause = drifting.length > 0 ? releaseDriftCause(drifting, "Re-recording", "a drive") : null;
61451
61656
  if (uxEvidence.state === "unreadable") {
61452
61657
  const why = uxEvidence.error ? ` \u2014 ${uxEvidence.path} ${uxEvidence.error}` : ` \u2014 ${uxEvidence.path} could not be read`;
61658
+ if (driftCause) {
61659
+ return `published with no mobile-UX drive this gate accepts for ${ctx.releaseId} (unreadable)${why}. The preview link below is the owner-private handover \u2014 DELETE ${ctx.quote(`${ctx.contentDir}/${uxEvidence.path}`)}, because re-recording over a malformed store does not repair it. ${driftCause}; then record the drive again with \`himi ux record --content ${ctx.contentArg} \u2026\`, and publish again before a customer reviews it.`;
61660
+ }
61453
61661
  return `published with no mobile-UX drive this gate accepts for ${ctx.releaseId} (unreadable)${why}. The preview link below is the owner-private handover \u2014 DELETE ${ctx.quote(`${ctx.contentDir}/${uxEvidence.path}`)} and record the drive again with \`himi ux record --content ${ctx.contentArg} \u2026\`, because re-recording over a malformed store does not repair it, then publish again before a customer reviews it.`;
61454
61662
  }
61663
+ if (driftCause) {
61664
+ return `published with no mobile-UX drive this gate accepts for ${ctx.releaseId} (${uxEvidence.state}). The preview link below is the owner-private handover. ${driftCause}; then record the drive with \`himi ux record --content ${ctx.contentArg} \u2026\` and publish again before a customer reviews it.`;
61665
+ }
61455
61666
  return `published with no mobile-UX drive this gate accepts for ${ctx.releaseId} (${uxEvidence.state}). The preview link below is the owner-private handover \u2014 record the drive with \`himi ux record --content ${ctx.contentArg} \u2026\` and publish again before a customer reviews it.`;
61456
61667
  }
61457
61668
  function uxHandoverOverride(uxEvidence, ctx) {
@@ -61527,7 +61738,7 @@ async function producedWidgetFamilies(dir) {
61527
61738
  let js;
61528
61739
  for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
61529
61740
  try {
61530
- js = readFileSync66(join52(outDir, candidate), "utf8");
61741
+ js = readFileSync67(join52(outDir, candidate), "utf8");
61531
61742
  break;
61532
61743
  } catch {
61533
61744
  }
@@ -61902,7 +62113,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
61902
62113
  const sourceDir = resolve44(str5(flags["source-dir"]) ?? appDir2);
61903
62114
  let meta;
61904
62115
  try {
61905
- meta = JSON.parse(readFileSync66(join52(sourceDir, TEMPLATE_META_FILE), "utf8"));
62116
+ meta = JSON.parse(readFileSync67(join52(sourceDir, TEMPLATE_META_FILE), "utf8"));
61906
62117
  } catch {
61907
62118
  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>)` }));
61908
62119
  return 2;
@@ -61912,7 +62123,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
61912
62123
  return 2;
61913
62124
  }
61914
62125
  try {
61915
- const appearance = extractTemplateAppearance(JSON.parse(readFileSync66(join52(sourceDir, "tokens.json"), "utf8")));
62126
+ const appearance = extractTemplateAppearance(JSON.parse(readFileSync67(join52(sourceDir, "tokens.json"), "utf8")));
61916
62127
  meta = { ...appearance, ...meta };
61917
62128
  } catch {
61918
62129
  }
@@ -61977,7 +62188,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
61977
62188
  let iconHash;
61978
62189
  if (iconPath) {
61979
62190
  try {
61980
- const bytes2 = readFileSync66(iconPath);
62191
+ const bytes2 = readFileSync67(iconPath);
61981
62192
  payload.icon = bytes2.toString("base64");
61982
62193
  iconHash = createHash24("sha256").update(bytes2).digest("hex");
61983
62194
  } catch {
@@ -62247,7 +62458,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62247
62458
  const path = dpxSessionTokenPath();
62248
62459
  let raw;
62249
62460
  try {
62250
- raw = readFileSync66(path, "utf8");
62461
+ raw = readFileSync67(path, "utf8");
62251
62462
  } catch {
62252
62463
  throw new Error(`no DPX BO session at ${path}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
62253
62464
  }
@@ -62387,7 +62598,10 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62387
62598
  io.error(JSON.stringify({ error: `ux record needs --status ${NATIVE_AUDIT_STATUSES.join("|")}` }));
62388
62599
  return 2;
62389
62600
  }
62390
- const uxRelease = await recordedReleaseForContentQuietly(dir, resolutionFlag(flags));
62601
+ let drifting = [];
62602
+ const uxRelease = await recordedReleaseForContentQuietly(dir, resolutionFlag(flags), (workers) => {
62603
+ drifting = workers;
62604
+ });
62391
62605
  try {
62392
62606
  const evidence = recordNativeAudit(dir, platform, status, checks, str5(flags.reason), uxRelease ?? void 0);
62393
62607
  print({
@@ -62398,6 +62612,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62398
62612
  ...uxRelease ? {} : {
62399
62613
  releaseIdNote: "this package could not be built, so the record names no release \u2014 `himi push` will not accept it as evidence for the release it publishes. Fix the build and re-run this command."
62400
62614
  },
62615
+ // #3049 — still written (it is honest about what was driven), but said NOW: the push is
62616
+ // the next step, and without this line it is where the author would find out.
62617
+ ...drifting.length ? {
62618
+ releaseIdWarning: `this record will not reliably match the release \`himi push\` builds: ${describeNondeterministicWorkers(drifting)} ${drifting.length === 1 ? "builds" : "build"} a different initial state depending on when ${drifting.length === 1 ? "it is" : "they are"} built, and that state is hashed into the release. First ${NONDETERMINISTIC_FIX}; then record again, immediately before the push.`
62619
+ } : {},
62401
62620
  evidence
62402
62621
  });
62403
62622
  return 0;
@@ -62409,7 +62628,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62409
62628
  case "test": {
62410
62629
  const dir = contentDir(flags);
62411
62630
  const structuredOutput = flags.json === true || io.isTTY !== true;
62412
- if (existsSync55(join52(dir, "functions"))) {
62631
+ if (existsSync56(join52(dir, "functions"))) {
62413
62632
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
62414
62633
  const loaded = await loadFunctionsApp2(dir);
62415
62634
  const results = [];
@@ -62829,7 +63048,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62829
63048
  return 2;
62830
63049
  }
62831
63050
  try {
62832
- const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync66(stateArg.replace(/^@/, ""), "utf8");
63051
+ const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync67(stateArg.replace(/^@/, ""), "utf8");
62833
63052
  injectedState = JSON.parse(raw);
62834
63053
  } catch (e) {
62835
63054
  io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
@@ -62844,7 +63063,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62844
63063
  return 2;
62845
63064
  }
62846
63065
  try {
62847
- const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync66(inputArg.replace(/^@/, ""), "utf8");
63066
+ const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync67(inputArg.replace(/^@/, ""), "utf8");
62848
63067
  const parsed = JSON.parse(raw);
62849
63068
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
62850
63069
  injectedInput = parsed;
@@ -63241,7 +63460,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63241
63460
  io.error(JSON.stringify(linked));
63242
63461
  return 1;
63243
63462
  }
63244
- if (existsSync55(dest)) {
63463
+ if (existsSync56(dest)) {
63245
63464
  if (!statSync13(dest).isDirectory()) {
63246
63465
  io.error(JSON.stringify({
63247
63466
  error: `${dest} exists and is not a directory`,
@@ -63254,7 +63473,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63254
63473
  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" }));
63255
63474
  return 1;
63256
63475
  }
63257
- if (replace && occupied && !existsSync55(join52(dest, "himalaya.content.json"))) {
63476
+ if (replace && occupied && !existsSync56(join52(dest, "himalaya.content.json"))) {
63258
63477
  io.error(JSON.stringify({
63259
63478
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
63260
63479
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -63473,7 +63692,10 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63473
63692
  // bytes to drive.
63474
63693
  baseReleaseId: baseForPlan.manifest.releaseId,
63475
63694
  quote: shellQuote2,
63476
- planeArgs: planeArguments(flags, shellQuote2)
63695
+ planeArgs: planeArguments(flags, shellQuote2),
63696
+ // The patch door reads the same build, so a drifting worker makes its record just as
63697
+ // unmatchable — the partial publish is not exempt from the loop (#3049).
63698
+ nondeterministicWorkers: nondeterministicWorkers(outcome.workers)
63477
63699
  };
63478
63700
  let localSourceHash;
63479
63701
  try {
@@ -63528,15 +63750,15 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63528
63750
  return 1;
63529
63751
  }
63530
63752
  const zip = zipAppSource2(collected.entries);
63531
- const encoded = zip.toString("base64");
63532
- if (encoded.length > MAX_APP_SOURCE_BYTES2) {
63753
+ const encoded2 = zip.toString("base64");
63754
+ if (encoded2.length > MAX_APP_SOURCE_BYTES2) {
63533
63755
  const largest = largestEntries2(collected.entries);
63534
63756
  io.error(JSON.stringify({
63535
63757
  ok: false,
63536
63758
  pushed: false,
63537
63759
  error: "app_source_too_large",
63538
63760
  archivedBytes: zip.length,
63539
- encodedBytes: encoded.length,
63761
+ encodedBytes: encoded2.length,
63540
63762
  limit: MAX_APP_SOURCE_BYTES2,
63541
63763
  files: collected.entries.length,
63542
63764
  largest,
@@ -63544,7 +63766,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63544
63766
  }));
63545
63767
  return 1;
63546
63768
  }
63547
- appSourceB64 = encoded;
63769
+ appSourceB64 = encoded2;
63548
63770
  sourceSummary = {
63549
63771
  files: collected.entries.length,
63550
63772
  compressed: zip.length,
@@ -63552,6 +63774,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63552
63774
  };
63553
63775
  }
63554
63776
  const evidence = pushEvidence(dir, manifest.releaseId, (candidate) => verifyAttestation(candidate, dir, payload.screens, declared, payload, { requireLatest: false }).ok);
63777
+ const drifting = nondeterministicWorkers(outcome.workers);
63555
63778
  const staleEvidence = evidence.staleRuns > 0 ? `${evidence.staleRuns} retained attestation(s) carry this release id, but none describes the content being published` : null;
63556
63779
  const attestationErrors = [...evidence.historyErrors, ...staleEvidence ? [staleEvidence] : []];
63557
63780
  if (attestationErrors.length > 0 && !force) {
@@ -63561,7 +63784,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63561
63784
  ok: false,
63562
63785
  pushed: false,
63563
63786
  errors: attestationErrors,
63564
- hint: corrupted ? `attestation history in .himi/attestations/ is corrupt, so the retained runs cannot be trusted \u2014 a fresh run does not remove the bad entry. Delete .himi/attestations/, re-attest with ${remedy}, then re-run \`himi push\`. Only if you intend to publish WITHOUT that evidence, \`himi push --force\`.` : `no retained attestation for this release passed live verification \u2014 a release id is the HEAD sha, so runs recorded before your latest edits still carry it while describing a tree that no longer exists. Re-attest the CURRENT release with ${remedy}, then re-run \`himi push\`. Only if you intend to publish WITHOUT that evidence, \`himi push --force\`.`
63787
+ hint: corrupted ? `attestation history in .himi/attestations/ is corrupt, so the retained runs cannot be trusted \u2014 a fresh run does not remove the bad entry. Delete .himi/attestations/, re-attest with ${remedy}, then re-run \`himi push\`. Only if you intend to publish WITHOUT that evidence, \`himi push --force\`.` : `no retained attestation for this release passed live verification${drifting.length ? `. ${releaseDriftCause(drifting, "Re-attesting", "an attestation")}, then re-attest` : " \u2014 a release id is the HEAD sha, so runs recorded before your latest edits still carry it while describing a tree that no longer exists. Re-attest"} the CURRENT release with ${remedy}, then re-run \`himi push\`. Only if you intend to publish WITHOUT that evidence, \`himi push --force\`.`
63565
63788
  });
63566
63789
  return 1;
63567
63790
  }
@@ -63597,9 +63820,10 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63597
63820
  contentDir: contentRel,
63598
63821
  app,
63599
63822
  door: echoedInvocation("himi push", flags, shellQuote2),
63600
- quote: shellQuote2
63823
+ quote: shellQuote2,
63601
63824
  // No `baseReleaseId`: a full push derives from nothing, so it can never produce
63602
63825
  // `inherited-screens` and has no base to restore.
63826
+ nondeterministicWorkers: drifting
63603
63827
  })
63604
63828
  });
63605
63829
  return 1;
@@ -63758,7 +63982,10 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63758
63982
  contentDir: contentRel,
63759
63983
  app,
63760
63984
  door: echoedInvocation("himi push", flags, shellQuote2),
63761
- quote: shellQuote2
63985
+ quote: shellQuote2,
63986
+ // #3049 — the same workers the refusal above was told about, so the forced note does
63987
+ // not answer "record it and publish again" to a build that moves the release itself.
63988
+ nondeterministicWorkers: drifting
63762
63989
  }),
63763
63990
  ...loopbackWarning ? { warning: loopbackWarning } : {},
63764
63991
  ...report2.issues ? { issues: report2.issues } : {},
@@ -64108,7 +64335,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
64108
64335
  }));
64109
64336
  return 1;
64110
64337
  }
64111
- const archive = readFileSync66(resolve44(file));
64338
+ const archive = readFileSync67(resolve44(file));
64112
64339
  const result = await client2().createPackageShare({
64113
64340
  app: opened.header.app,
64114
64341
  releaseId: opened.header.releaseId,
@@ -64752,7 +64979,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
64752
64979
  io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
64753
64980
  return 2;
64754
64981
  }
64755
- if (!existsSync55(file)) {
64982
+ if (!existsSync56(file)) {
64756
64983
  io.error(JSON.stringify({ error: `no such file: ${file}` }));
64757
64984
  return 2;
64758
64985
  }
@@ -64808,7 +65035,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
64808
65035
  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."
64809
65036
  };
64810
65037
  if (kind === "tokens" || kind === "app-config") {
64811
- const body = readFileSync66(file, "utf8");
65038
+ const body = readFileSync67(file, "utf8");
64812
65039
  const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
64813
65040
  return runReleasePatch({
64814
65041
  ...common,
@@ -64823,7 +65050,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
64823
65050
  io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
64824
65051
  return 2;
64825
65052
  }
64826
- const descriptor = readFileSync66(file, "utf8");
65053
+ const descriptor = readFileSync67(file, "utf8");
64827
65054
  try {
64828
65055
  JSON.parse(descriptor);
64829
65056
  } catch (e) {
@@ -64863,7 +65090,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
64863
65090
  extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
64864
65091
  });
64865
65092
  }
64866
- const bytes2 = readFileSync66(file);
65093
+ const bytes2 = readFileSync67(file);
64867
65094
  const sha = createHash24("sha256").update(bytes2).digest("hex");
64868
65095
  const forScreens = (str5(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
64869
65096
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
@@ -65007,7 +65234,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65007
65234
  }
65008
65235
  let def;
65009
65236
  try {
65010
- const parsed = JSON.parse(arg.startsWith("@") ? readFileSync66(arg.slice(1), "utf8") : arg);
65237
+ const parsed = JSON.parse(arg.startsWith("@") ? readFileSync67(arg.slice(1), "utf8") : arg);
65011
65238
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
65012
65239
  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}`] }));
65013
65240
  return 2;
@@ -65471,7 +65698,7 @@ ${label2}`);
65471
65698
  const platform = str5(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
65472
65699
  {
65473
65700
  const distDir = contentDir(flags);
65474
- if (existsSync55(join52(distDir, "himalaya.content.json"))) {
65701
+ if (existsSync56(join52(distDir, "himalaya.content.json"))) {
65475
65702
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
65476
65703
  const errors = issues.filter((i) => i.severity === "error");
65477
65704
  for (const i of issues.filter((i2) => i2.severity === "warning")) {
@@ -65740,7 +65967,7 @@ ${label2}`);
65740
65967
  const dpxPath = dpxSessionTokenPath();
65741
65968
  let dpx;
65742
65969
  try {
65743
- dpx = readFileSync66(dpxPath, "utf8").trim();
65970
+ dpx = readFileSync67(dpxPath, "utf8").trim();
65744
65971
  } catch {
65745
65972
  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` }));
65746
65973
  return 1;
@@ -66141,7 +66368,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
66141
66368
  const path = dpxSessionTokenPath();
66142
66369
  let raw;
66143
66370
  try {
66144
- raw = readFileSync66(path, "utf8");
66371
+ raw = readFileSync67(path, "utf8");
66145
66372
  } catch {
66146
66373
  io.error(JSON.stringify({ error: `no DPX BO session at ${path}` }));
66147
66374
  return 1;
@@ -66553,6 +66780,7 @@ export {
66553
66780
  readUpdateCache,
66554
66781
  refreshUpdateCache,
66555
66782
  registryCandidates,
66783
+ releaseDriftCause,
66556
66784
  renderDataSource,
66557
66785
  renderDeviceWidths,
66558
66786
  resolveAppSlug,