@wix/himalaya-cli 0.1385.0 → 0.1387.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
@@ -3738,7 +3738,7 @@ async function browserLogin(opts) {
3738
3738
  const log = opts.log ?? (() => {
3739
3739
  });
3740
3740
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
3741
- return await new Promise((resolve63, reject) => {
3741
+ return await new Promise((resolve65, reject) => {
3742
3742
  let settled = false;
3743
3743
  let loginUrl = "";
3744
3744
  const server = createServer();
@@ -3804,7 +3804,7 @@ async function browserLogin(opts) {
3804
3804
  res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store", connection: "close" }).end(closePage(opts.doneTitle ?? "Signed in to himi"));
3805
3805
  const extra = {};
3806
3806
  for (const [k2, v2] of params) if (k2 !== "token" && k2 !== "state") extra[k2] = v2;
3807
- finish2(() => resolve63({ token, loginUrl, extra }));
3807
+ finish2(() => resolve65({ token, loginUrl, extra }));
3808
3808
  });
3809
3809
  });
3810
3810
  server.on("error", (err) => finish2(() => reject(err)));
@@ -3916,7 +3916,7 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
3916
3916
  tokenCache.set(cacheKey, fromEnv);
3917
3917
  return fromEnv;
3918
3918
  }
3919
- const token = await new Promise((resolve63, reject) => {
3919
+ const token = await new Promise((resolve65, reject) => {
3920
3920
  let child;
3921
3921
  try {
3922
3922
  child = spawnImpl("wix", [...args]);
@@ -3945,12 +3945,12 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
3945
3945
  child.stdout?.on("data", (d2) => {
3946
3946
  out2 += String(d2);
3947
3947
  const m2 = out2.match(TOKEN_RE);
3948
- if (m2) done(() => resolve63(m2[0]));
3948
+ if (m2) done(() => resolve65(m2[0]));
3949
3949
  });
3950
3950
  child.stderr?.on("data", (d2) => {
3951
3951
  out2 += String(d2);
3952
3952
  const m2 = out2.match(TOKEN_RE);
3953
- if (m2) done(() => resolve63(m2[0]));
3953
+ if (m2) done(() => resolve65(m2[0]));
3954
3954
  });
3955
3955
  child.on("error", (e2) => done(() => reject(new Error(mintHelp(label2, e2.message)))));
3956
3956
  child.on("exit", (code) => done(() => reject(new Error(
@@ -4160,8 +4160,8 @@ function committedProvisioningPath(name) {
4160
4160
  function committedShellFor(path2) {
4161
4161
  const normalized = path2.replace(/\\/g, "/");
4162
4162
  return SHELL_NAMES2.find((name) => {
4163
- const relative16 = committedProvisioningPath(name);
4164
- return normalized === relative16 || normalized.endsWith(`/${relative16}`);
4163
+ const relative17 = committedProvisioningPath(name);
4164
+ return normalized === relative17 || normalized.endsWith(`/${relative17}`);
4165
4165
  });
4166
4166
  }
4167
4167
  function isBrandable(repoRoot2, name) {
@@ -6876,9 +6876,9 @@ function compileV2(html, profile, options) {
6876
6876
  if (!row) error(el2, "HHP-BINDING-SCOPE", "Item bindings require a keyed list template.");
6877
6877
  return raw;
6878
6878
  }
6879
- const relative16 = statePath(raw);
6880
- if (!info4?.paths.has(relative16)) error(el2, "HHP-BINDING-PATH", `Unknown controller state path ${relative16}.`);
6881
- return `$service:${serviceName}.${relative16}`;
6879
+ const relative17 = statePath(raw);
6880
+ if (!info4?.paths.has(relative17)) error(el2, "HHP-BINDING-PATH", `Unknown controller state path ${relative17}.`);
6881
+ return `$service:${serviceName}.${relative17}`;
6882
6882
  }
6883
6883
  function coerce(raw, field) {
6884
6884
  if (field.schema.type === "boolean") return raw === "" || raw === "true" ? true : raw === "false" ? false : raw;
@@ -7708,7 +7708,6 @@ function resolveTranslation(value, catalog3, sourceCatalog) {
7708
7708
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
7709
7709
  var init_bindings = __esm({
7710
7710
  "../../core/ts/src/bindings.ts"() {
7711
- "use strict";
7712
7711
  BINDING_SIGILS = ["service", "flag", "item", "t"];
7713
7712
  BINDING_SIGIL_RE = new RegExp(
7714
7713
  `^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
@@ -10250,7 +10249,8 @@ async function bootBundleWorker(bundleJs, opts) {
10250
10249
  }
10251
10250
  return value;
10252
10251
  });
10253
- }
10252
+ },
10253
+ ...opts.wixApiSession ? { identityBound: opts.wixApiSession.identityBound, session: opts.wixApiSession.session } : {}
10254
10254
  };
10255
10255
  const dispatchHost = (action, params) => {
10256
10256
  if (action === "himi.open" && params && typeof params.screenId === "string") {
@@ -25434,10 +25434,10 @@ var init_preview = __esm({
25434
25434
  }
25435
25435
  },
25436
25436
  kill: (pid, signal) => process.kill(pid, signal),
25437
- portFree: (port) => new Promise((resolve63) => {
25437
+ portFree: (port) => new Promise((resolve65) => {
25438
25438
  const s2 = createServer2();
25439
- s2.once("error", () => resolve63(false));
25440
- s2.listen(port, "127.0.0.1", () => s2.close(() => resolve63(true)));
25439
+ s2.once("error", () => resolve65(false));
25440
+ s2.listen(port, "127.0.0.1", () => s2.close(() => resolve65(true)));
25441
25441
  }),
25442
25442
  sleep: (ms2) => new Promise((r2) => setTimeout(r2, ms2)),
25443
25443
  servingIdentity: async (origin) => {
@@ -29428,7 +29428,7 @@ async function injectRequest(listener, request) {
29428
29428
  req.headers.host ??= url.host;
29429
29429
  if (body && body.length > 0) req.push(body);
29430
29430
  req.push(null);
29431
- return await new Promise((resolve63, reject) => {
29431
+ return await new Promise((resolve65, reject) => {
29432
29432
  const streamed = () => {
29433
29433
  queueMicrotask(() => {
29434
29434
  req.emit("close");
@@ -29444,7 +29444,7 @@ async function injectRequest(listener, request) {
29444
29444
  else headers2.set(name, value);
29445
29445
  }
29446
29446
  const bodyless = out2.status === 204 || out2.status === 304 || request.method === "HEAD";
29447
- resolve63(new Response(bodyless ? null : out2.body, { status: out2.status, headers: headers2 }));
29447
+ resolve65(new Response(bodyless ? null : out2.body, { status: out2.status, headers: headers2 }));
29448
29448
  }, streamed);
29449
29449
  res.on("inject-error", reject);
29450
29450
  try {
@@ -35581,12 +35581,12 @@ function finalizeRecording(key2, rec) {
35581
35581
  if (rec.finalize) return rec.finalize;
35582
35582
  rec.finalize = (async () => {
35583
35583
  clearTimeout(rec.autoStop);
35584
- await new Promise((resolve63) => {
35584
+ await new Promise((resolve65) => {
35585
35585
  let done = false;
35586
35586
  const finish2 = () => {
35587
35587
  if (!done) {
35588
35588
  done = true;
35589
- resolve63();
35589
+ resolve65();
35590
35590
  }
35591
35591
  };
35592
35592
  rec.child.once("close", finish2);
@@ -35697,7 +35697,7 @@ var init_preview2 = __esm({
35697
35697
  DEVICE_LIST_TIMEOUT_MS = 5e3;
35698
35698
  defaultRunner2 = {
35699
35699
  capture(cmd, args, timeoutMs = DEFAULT_CAPTURE_TIMEOUT_MS) {
35700
- return new Promise((resolve63, reject) => {
35700
+ return new Promise((resolve65, reject) => {
35701
35701
  const child = spawn4(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
35702
35702
  const out2 = [];
35703
35703
  const err = [];
@@ -35719,7 +35719,7 @@ var init_preview2 = __esm({
35719
35719
  child.stderr.on("data", (b2) => err.push(b2));
35720
35720
  child.on("error", (e2) => settle(reject, e2));
35721
35721
  child.on("close", (code) => {
35722
- if (code === 0) settle(resolve63, Buffer.concat(out2));
35722
+ if (code === 0) settle(resolve65, Buffer.concat(out2));
35723
35723
  else settle(reject, new Error(`${cmd} exited ${code}: ${Buffer.concat(err).toString("utf8")}`));
35724
35724
  });
35725
35725
  });
@@ -38032,12 +38032,12 @@ function createRicosHostSession(o2) {
38032
38032
  flush() {
38033
38033
  if (!state.ready || state.unavailable || disposed) return Promise.resolve(null);
38034
38034
  const requestId2 = newId();
38035
- return new Promise((resolve63) => {
38035
+ return new Promise((resolve65) => {
38036
38036
  const timer = t2.setTimeout(() => {
38037
38037
  flushes.delete(requestId2);
38038
- resolve63(null);
38038
+ resolve65(null);
38039
38039
  }, flushMs);
38040
- flushes.set(requestId2, { resolve: resolve63, timer });
38040
+ flushes.set(requestId2, { resolve: resolve65, timer });
38041
38041
  o2.send({ v: 1, type: "requestContent", requestId: requestId2 });
38042
38042
  });
38043
38043
  },
@@ -38096,7 +38096,7 @@ async function runRicosImageUpload(o2) {
38096
38096
  };
38097
38097
  session.insertMediaPlaceholder(requestId2);
38098
38098
  try {
38099
- const entry = await new Promise((resolve63) => {
38099
+ const entry = await new Promise((resolve65) => {
38100
38100
  let done = false;
38101
38101
  let unsub = () => {
38102
38102
  };
@@ -38105,7 +38105,7 @@ async function runRicosImageUpload(o2) {
38105
38105
  done = true;
38106
38106
  t2.clearTimeout(timer);
38107
38107
  queueMicrotask(() => unsub());
38108
- resolve63(v2);
38108
+ resolve65(v2);
38109
38109
  };
38110
38110
  const timer = t2.setTimeout(() => finish2(null), o2.timeoutMs ?? RICOS_UPLOAD_TIMEOUT_MS);
38111
38111
  unsub = deps.subscribe(`${svc}.uploads.${requestId2}`, (v2) => {
@@ -38627,10 +38627,10 @@ async function runMediaFieldUpload(o2) {
38627
38627
  }, o2.timeoutMs ?? MEDIA_FIELD_UPLOAD_TIMEOUT_MS);
38628
38628
  const bounded2 = (p2) => {
38629
38629
  if (expired) return Promise.reject(new Deadline());
38630
- return new Promise((resolve63, reject) => {
38630
+ return new Promise((resolve65, reject) => {
38631
38631
  const stop = () => reject(new Deadline());
38632
38632
  onExpire.push(stop);
38633
- p2.then(resolve63, reject).finally(() => {
38633
+ p2.then(resolve65, reject).finally(() => {
38634
38634
  onExpire = onExpire.filter((f2) => f2 !== stop);
38635
38635
  });
38636
38636
  });
@@ -38653,7 +38653,7 @@ async function runMediaFieldUpload(o2) {
38653
38653
  const before = deps.value(urlPath);
38654
38654
  let uploadUrl;
38655
38655
  try {
38656
- uploadUrl = await bounded2(new Promise((resolve63, reject) => {
38656
+ uploadUrl = await bounded2(new Promise((resolve65, reject) => {
38657
38657
  let done = false;
38658
38658
  let unsub = () => {
38659
38659
  };
@@ -38661,7 +38661,7 @@ async function runMediaFieldUpload(o2) {
38661
38661
  if (done || typeof v2 !== "string" || v2 === "" || v2 === before) return;
38662
38662
  done = true;
38663
38663
  queueMicrotask(() => unsub());
38664
- resolve63(v2);
38664
+ resolve65(v2);
38665
38665
  });
38666
38666
  onExpire.push(() => {
38667
38667
  if (!done) {
@@ -38676,7 +38676,7 @@ async function runMediaFieldUpload(o2) {
38676
38676
  if (typeof now === "string" && now !== "" && now !== before) {
38677
38677
  done = true;
38678
38678
  queueMicrotask(() => unsub());
38679
- resolve63(now);
38679
+ resolve65(now);
38680
38680
  return;
38681
38681
  }
38682
38682
  }
@@ -39122,7 +39122,7 @@ var init_controls = __esm({
39122
39122
  }, [selectedId]);
39123
39123
  const current = local != null && tabs.some((t2) => t2.id === local) ? local : selectedId;
39124
39124
  const selIdx = Math.max(0, tabs.findIndex((t2) => t2.id === (current ?? tabs[0]?.id)));
39125
- const select = (i2) => {
39125
+ const select2 = (i2) => {
39126
39126
  if (pages2) setLocal(tabs[i2]?.id);
39127
39127
  const act = actOf(tabs[i2], props.onChange ?? props.onSelect);
39128
39128
  if (ctx.onAction && act) ctx.onAction(withSelection(act, { selectedId: String(tabs[i2]?.id ?? i2) }));
@@ -39135,7 +39135,7 @@ var init_controls = __esm({
39135
39135
  else if (e2.key === "End") ni2 = tabs.length - 1;
39136
39136
  else return;
39137
39137
  e2.preventDefault();
39138
- if (ni2 !== selIdx) select(ni2);
39138
+ if (ni2 !== selIdx) select2(ni2);
39139
39139
  };
39140
39140
  const pagerRef = React5.useRef(null);
39141
39141
  const settle = React5.useRef(void 0);
@@ -39152,7 +39152,7 @@ var init_controls = __esm({
39152
39152
  const el2 = pagerRef.current;
39153
39153
  if (!el2 || !el2.clientWidth) return;
39154
39154
  const i2 = Math.round(el2.scrollLeft / el2.clientWidth);
39155
- if (i2 >= 0 && i2 < tabs.length && i2 !== selIdx) select(i2);
39155
+ if (i2 >= 0 && i2 < tabs.length && i2 !== selIdx) select2(i2);
39156
39156
  }, 120);
39157
39157
  };
39158
39158
  const accent = C2("accentPrimary", "#116DFF");
@@ -39167,7 +39167,7 @@ var init_controls = __esm({
39167
39167
  role: "tab",
39168
39168
  "aria-selected": on4,
39169
39169
  tabIndex: on4 ? 0 : -1,
39170
- onClick: () => select(i2),
39170
+ onClick: () => select2(i2),
39171
39171
  style: { all: "unset", display: "flex", gap: 6, alignItems: "center", minWidth: 44, minHeight: 44, padding: "10px 0", fontFamily: FONT(ctx), fontWeight: 600, fontSize: pxToRem(14), cursor: "pointer", color: on4 ? activeLabel : C2("textSecondary", "#777"), borderBottom: on4 ? `2px solid ${activeTint}` : "2px solid transparent", marginBottom: -1 },
39172
39172
  children: [
39173
39173
  asText2(t2.label),
@@ -39210,7 +39210,7 @@ var init_controls = __esm({
39210
39210
  const awaitingBinding = isBinding(props.selectedId) && resolvedSel == null;
39211
39211
  const selId = ctx.empty || awaitingBinding ? null : resolvedSel ?? opts[0]?.id;
39212
39212
  const selIdx = Math.max(0, opts.findIndex((o2) => o2.id === selId));
39213
- const select = (i2) => {
39213
+ const select2 = (i2) => {
39214
39214
  const act = actOf(opts[i2], props.onChange ?? props.onSelect);
39215
39215
  if (ctx.onAction && act) ctx.onAction(withSelection(act, { selectedId: String(opts[i2]?.id ?? i2) }));
39216
39216
  };
@@ -39220,7 +39220,7 @@ var init_controls = __esm({
39220
39220
  else if (e2.key === "ArrowLeft" || e2.key === "ArrowUp") ni2 = (selIdx - 1 + opts.length) % opts.length;
39221
39221
  else return;
39222
39222
  e2.preventDefault();
39223
- if (ni2 !== selIdx) select(ni2);
39223
+ if (ni2 !== selIdx) select2(ni2);
39224
39224
  };
39225
39225
  return /* @__PURE__ */ jsx6("div", { role: "radiogroup", onKeyDown, style: { display: "flex", background: seg.outlined ? "transparent" : C2("surfaceTertiary", "#eee"), borderRadius: radius(seg.trackRadius, "md", 8), padding: seg.trackPadding, width: "100%", boxSizing: "border-box", ...wrap }, children: opts.map((o2, i2) => {
39226
39226
  const on4 = o2.id === selId;
@@ -39237,7 +39237,7 @@ var init_controls = __esm({
39237
39237
  role: "radio",
39238
39238
  "aria-checked": on4,
39239
39239
  tabIndex: on4 || selId == null && i2 === 0 ? 0 : -1,
39240
- onClick: () => select(i2),
39240
+ onClick: () => select2(i2),
39241
39241
  style: { all: "unset", flex: 1, minWidth: 44, minHeight: seg.height - 2 * seg.trackPadding, textAlign: "center", padding: "7px 4px", borderRadius: outerR, fontFamily: FONT(ctx), fontWeight: 600, fontSize: pxToRem(13), cursor: "pointer", boxSizing: "border-box", background: on4 ? C2("surfacePrimary", "#fff") : seg.outlined ? C2(pickRole(ctx.tokens.colors, seg.roles.inactive), "#eee") : "transparent", color: on4 ? C2("textPrimary", "#111") : C2("textSecondary", "#777"), boxShadow: on4 && !seg.outlined ? "0 1px 3px rgba(0,0,0,.12)" : "none", ...outlinedShape },
39242
39242
  children: [
39243
39243
  on4 && seg.selectedCheck ? /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\u2713 " }) : null,
@@ -40825,7 +40825,7 @@ async function fetchData(url, type = "text") {
40825
40825
  }
40826
40826
  return response.text();
40827
40827
  }
40828
- return new Promise((resolve63, reject) => {
40828
+ return new Promise((resolve65, reject) => {
40829
40829
  const request = new XMLHttpRequest();
40830
40830
  request.open("GET", url, true);
40831
40831
  request.responseType = type === "bytes" ? "arraybuffer" : type;
@@ -40836,14 +40836,14 @@ async function fetchData(url, type = "text") {
40836
40836
  if (request.status === 200 || request.status === 0) {
40837
40837
  switch (type) {
40838
40838
  case "bytes":
40839
- resolve63(new Uint8Array(request.response));
40839
+ resolve65(new Uint8Array(request.response));
40840
40840
  return;
40841
40841
  case "blob":
40842
40842
  case "json":
40843
- resolve63(request.response);
40843
+ resolve65(request.response);
40844
40844
  return;
40845
40845
  }
40846
- resolve63(request.responseText);
40846
+ resolve65(request.responseText);
40847
40847
  return;
40848
40848
  }
40849
40849
  reject(new Error(request.statusText));
@@ -43775,7 +43775,7 @@ var init_pdf = __esm({
43775
43775
  var defineProperty = Object.defineProperty;
43776
43776
  var stringSlice = uncurryThis("".slice);
43777
43777
  var replace = uncurryThis("".replace);
43778
- var join86 = uncurryThis([].join);
43778
+ var join88 = uncurryThis([].join);
43779
43779
  var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
43780
43780
  return defineProperty(function() {
43781
43781
  }, "length", { value: 8 }).length !== 8;
@@ -43802,7 +43802,7 @@ var init_pdf = __esm({
43802
43802
  }
43803
43803
  var state = enforceInternalState(value);
43804
43804
  if (!hasOwn(state, "source")) {
43805
- state.source = join86(TEMPLATE, typeof name == "string" ? name : "");
43805
+ state.source = join88(TEMPLATE, typeof name == "string" ? name : "");
43806
43806
  }
43807
43807
  return value;
43808
43808
  };
@@ -43847,13 +43847,13 @@ var init_pdf = __esm({
43847
43847
  var aCallable = __webpack_require__3(9306);
43848
43848
  var $TypeError = TypeError;
43849
43849
  var PromiseCapability = function(C2) {
43850
- var resolve63, reject;
43850
+ var resolve65, reject;
43851
43851
  this.promise = new C2(function($$resolve, $$reject) {
43852
- if (resolve63 !== void 0 || reject !== void 0) throw new $TypeError("Bad Promise constructor");
43853
- resolve63 = $$resolve;
43852
+ if (resolve65 !== void 0 || reject !== void 0) throw new $TypeError("Bad Promise constructor");
43853
+ resolve65 = $$resolve;
43854
43854
  reject = $$reject;
43855
43855
  });
43856
- this.resolve = aCallable(resolve63);
43856
+ this.resolve = aCallable(resolve65);
43857
43857
  this.reject = aCallable(reject);
43858
43858
  };
43859
43859
  module.exports.f = function(C2) {
@@ -44221,8 +44221,8 @@ var init_pdf = __esm({
44221
44221
  anObject(C2);
44222
44222
  if (isObject3(x2) && x2.constructor === C2) return x2;
44223
44223
  var promiseCapability = newPromiseCapability.f(C2);
44224
- var resolve63 = promiseCapability.resolve;
44225
- resolve63(x2);
44224
+ var resolve65 = promiseCapability.resolve;
44225
+ resolve65(x2);
44226
44226
  return promiseCapability.promise;
44227
44227
  };
44228
44228
  },
@@ -46325,7 +46325,7 @@ var init_pdf = __esm({
46325
46325
  var charAt = uncurryThis("".charAt);
46326
46326
  var Uint8Array2 = globalThis2.Uint8Array;
46327
46327
  var $Array = globalThis2.Array;
46328
- var join86 = uncurryThis([].join);
46328
+ var join88 = uncurryThis([].join);
46329
46329
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toBase64 || !(function() {
46330
46330
  try {
46331
46331
  var target = new Uint8Array2();
@@ -46371,7 +46371,7 @@ var init_pdf = __esm({
46371
46371
  result[written++] = "=";
46372
46372
  }
46373
46373
  }
46374
- return join86(result, "");
46374
+ return join88(result, "");
46375
46375
  }
46376
46376
  });
46377
46377
  },
@@ -46383,7 +46383,7 @@ var init_pdf = __esm({
46383
46383
  var anUint8Array = __webpack_require__3(4154);
46384
46384
  var notDetached = __webpack_require__3(5169);
46385
46385
  var numberToString2 = uncurryThis(1.1.toString);
46386
- var join86 = uncurryThis([].join);
46386
+ var join88 = uncurryThis([].join);
46387
46387
  var $Array = Array;
46388
46388
  var Uint8Array2 = globalThis2.Uint8Array;
46389
46389
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toHex || !(function() {
@@ -46403,7 +46403,7 @@ var init_pdf = __esm({
46403
46403
  var hex2 = numberToString2(this[i2], 16);
46404
46404
  result[i2] = hex2.length === 1 ? "0" + hex2 : hex2;
46405
46405
  }
46406
- return join86(result, "");
46406
+ return join88(result, "");
46407
46407
  }
46408
46408
  });
46409
46409
  },
@@ -48076,11 +48076,11 @@ var init_pdf = __esm({
48076
48076
  const mustRemoveAspectRatioPromise = _ImageManager._isSVGFittingCanvas;
48077
48077
  const fileReader = new FileReader();
48078
48078
  const imageElement = new Image();
48079
- const imagePromise = new Promise((resolve63, reject) => {
48079
+ const imagePromise = new Promise((resolve65, reject) => {
48080
48080
  imageElement.onload = () => {
48081
48081
  data.bitmap = imageElement;
48082
48082
  data.isSvg = true;
48083
- resolve63();
48083
+ resolve65();
48084
48084
  };
48085
48085
  fileReader.onload = async () => {
48086
48086
  const url = data.svgUrl = fileReader.result;
@@ -48766,13 +48766,13 @@ var init_pdf = __esm({
48766
48766
  return;
48767
48767
  }
48768
48768
  const {
48769
- resolve: resolve63,
48769
+ resolve: resolve65,
48770
48770
  promise
48771
48771
  } = Promise.withResolvers();
48772
48772
  const onEditorsRendered = (evt) => {
48773
48773
  if (evt.pageNumber === pageNumber) {
48774
48774
  this._eventBus.off("editorsrendered", onEditorsRendered);
48775
- resolve63();
48775
+ resolve65();
48776
48776
  }
48777
48777
  };
48778
48778
  this._eventBus.on("editorsrendered", onEditorsRendered, internalOpt);
@@ -53810,8 +53810,8 @@ var init_pdf = __esm({
53810
53810
  if (this.isSyncFontLoadingSupported) {
53811
53811
  return;
53812
53812
  }
53813
- await new Promise((resolve63) => {
53814
- const request = this._queueLoadingCallback(resolve63);
53813
+ await new Promise((resolve65) => {
53814
+ const request = this._queueLoadingCallback(resolve65);
53815
53815
  this._prepareFontLoadEvent(font, request);
53816
53816
  });
53817
53817
  }
@@ -70851,7 +70851,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
70851
70851
  input.type = "file";
70852
70852
  input.accept = SupportedImageMimeTypes.join(",");
70853
70853
  const signal = this._uiManager._signal;
70854
- this.#bitmapPromise = new Promise((resolve63) => {
70854
+ this.#bitmapPromise = new Promise((resolve65) => {
70855
70855
  input.addEventListener("change", async () => {
70856
70856
  if (!input.files || input.files.length === 0) {
70857
70857
  this.remove();
@@ -70866,13 +70866,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
70866
70866
  });
70867
70867
  this.#getBitmapFetched(data);
70868
70868
  }
70869
- resolve63();
70869
+ resolve65();
70870
70870
  }, {
70871
70871
  signal
70872
70872
  });
70873
70873
  input.addEventListener("cancel", () => {
70874
70874
  this.remove();
70875
- resolve63();
70875
+ resolve65();
70876
70876
  }, {
70877
70877
  signal
70878
70878
  });
@@ -125162,7 +125162,7 @@ var init_renderNode = __esm({
125162
125162
  media.currentTime = Math.max(0, Math.min(seconds, Number.isFinite(media.duration) ? media.duration : seconds));
125163
125163
  setPosition(media.currentTime);
125164
125164
  }, []);
125165
- const select = React9.useCallback((next) => {
125165
+ const select2 = React9.useCallback((next) => {
125166
125166
  if (resolvedItems.length === 0) return;
125167
125167
  const normalized = (next % resolvedItems.length + resolvedItems.length) % resolvedItems.length;
125168
125168
  const nextItem = resolvedItems[normalized];
@@ -125213,10 +125213,10 @@ var init_renderNode = __esm({
125213
125213
  seek(Number(detail.value ?? 0));
125214
125214
  break;
125215
125215
  case "next":
125216
- select(index + 1);
125216
+ select2(index + 1);
125217
125217
  break;
125218
125218
  case "previous":
125219
- select(index - 1);
125219
+ select2(index - 1);
125220
125220
  break;
125221
125221
  case "setRate": {
125222
125222
  const next = Number(detail.value ?? 1);
@@ -125241,7 +125241,7 @@ var init_renderNode = __esm({
125241
125241
  };
125242
125242
  window.addEventListener("himalaya-media-command", listener);
125243
125243
  return () => window.removeEventListener("himalaya-media-command", listener);
125244
- }, [sessionId, index, play, pause, seek, select, toggleFullscreen]);
125244
+ }, [sessionId, index, play, pause, seek, select2, toggleFullscreen]);
125245
125245
  React9.useEffect(() => {
125246
125246
  const listener = () => {
125247
125247
  const value = document.fullscreenElement === hostRef.current;
@@ -125297,10 +125297,10 @@ var init_renderNode = __esm({
125297
125297
  seek(Number(raw.seconds ?? raw.positionSeconds ?? 0));
125298
125298
  return;
125299
125299
  case "media.next":
125300
- select(index + 1);
125300
+ select2(index + 1);
125301
125301
  return;
125302
125302
  case "media.previous":
125303
- select(index - 1);
125303
+ select2(index - 1);
125304
125304
  return;
125305
125305
  case "media.fullscreen":
125306
125306
  void toggleFullscreen();
@@ -125343,14 +125343,14 @@ var init_renderNode = __esm({
125343
125343
  return `${Math.floor(safe / 60)}:${String(Math.floor(safe % 60)).padStart(2, "0")}`;
125344
125344
  };
125345
125345
  const builtInControls = /* @__PURE__ */ jsxs7("div", { "data-media-controls": "builtIn", style: { display: "grid", gridTemplateColumns: "auto auto 1fr auto auto", gap: 10, alignItems: "center", width: "100%", padding: "10px 12px", boxSizing: "border-box", color: foreground, background: "linear-gradient(transparent,rgba(0,0,0,.82))" }, children: [
125346
- items.length > 1 && /* @__PURE__ */ jsx10("button", { "aria-label": "Previous", onClick: () => select(index - 1), style: { color: "inherit", background: "transparent", border: 0, fontSize: pxToRem(18) }, children: "\u25C0\u25C0" }),
125346
+ items.length > 1 && /* @__PURE__ */ jsx10("button", { "aria-label": "Previous", onClick: () => select2(index - 1), style: { color: "inherit", background: "transparent", border: 0, fontSize: pxToRem(18) }, children: "\u25C0\u25C0" }),
125347
125347
  /* @__PURE__ */ jsx10("button", { "aria-label": status === "playing" ? "Pause" : "Play", onClick: () => status === "playing" ? pause() : void play(), style: { width: 38, height: 38, borderRadius: "50%", color: background, background: foreground, border: 0, fontSize: 18 }, children: status === "playing" ? "\u275A\u275A" : "\u25B6" }),
125348
125348
  /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 }, children: [
125349
125349
  /* @__PURE__ */ jsx10("span", { style: { fontSize: pxToRem(11), whiteSpace: "nowrap" }, children: time(position) }),
125350
125350
  /* @__PURE__ */ jsx10("input", { "aria-label": "Media position", type: "range", min: 0, max: Math.max(duration2, 1), step: 0.1, value: Math.min(position, Math.max(duration2, 1)), onChange: (event) => seek(Number(event.currentTarget.value)), style: { width: "100%", accentColor: accent } }),
125351
125351
  /* @__PURE__ */ jsx10("span", { style: { fontSize: pxToRem(11), whiteSpace: "nowrap" }, children: time(duration2) })
125352
125352
  ] }),
125353
- items.length > 1 && /* @__PURE__ */ jsx10("button", { "aria-label": "Next", onClick: () => select(index + 1), style: { color: "inherit", background: "transparent", border: 0, fontSize: pxToRem(18) }, children: "\u25B6\u25B6" }),
125353
+ items.length > 1 && /* @__PURE__ */ jsx10("button", { "aria-label": "Next", onClick: () => select2(index + 1), style: { color: "inherit", background: "transparent", border: 0, fontSize: pxToRem(18) }, children: "\u25B6\u25B6" }),
125354
125354
  props.fullscreen !== "disabled" && /* @__PURE__ */ jsx10("button", { "aria-label": "Fullscreen", onClick: () => void toggleFullscreen(), style: { color: "inherit", background: "transparent", border: 0, fontSize: pxToRem(18) }, children: "\u26F6" })
125355
125355
  ] });
125356
125356
  const customControls = chrome === "custom" ? slot("controls") : null;
@@ -125392,7 +125392,7 @@ var init_renderNode = __esm({
125392
125392
  return;
125393
125393
  }
125394
125394
  if (props.loop === "all" || index + 1 < items.length) {
125395
- select(index + 1);
125395
+ select2(index + 1);
125396
125396
  return;
125397
125397
  }
125398
125398
  setStatus("ended");
@@ -127708,7 +127708,7 @@ var init_renderNode = __esm({
127708
127708
  const currentRef = React9.useRef(current);
127709
127709
  const itemsPath = props.itemsPath ?? props.items_path;
127710
127710
  const boundRail = !!itemsPath && !!items[0] && !!ctx.provider;
127711
- const select = (index) => {
127711
+ const select2 = (index) => {
127712
127712
  if (index === currentRef.current) return;
127713
127713
  currentRef.current = index;
127714
127714
  setCurrent(index);
@@ -127725,7 +127725,7 @@ var init_renderNode = __esm({
127725
127725
  const timer = setInterval(() => {
127726
127726
  const next = (currentRef.current + 1) % pages2.length;
127727
127727
  if (rail.current) rail.current.scrollLeft = next * rail.current.clientWidth;
127728
- select(next);
127728
+ select2(next);
127729
127729
  }, interval);
127730
127730
  return () => clearInterval(timer);
127731
127731
  }, [props.autoplayIntervalMs, props.__pager, boundRail, pages2.length, props.onChange, ctx]);
@@ -127742,10 +127742,10 @@ var init_renderNode = __esm({
127742
127742
  event.preventDefault();
127743
127743
  const index = event.key === "Home" ? 0 : event.key === "End" ? pages2.length - 1 : Math.max(0, Math.min(pages2.length - 1, currentRef.current + (event.key === "ArrowRight" ? 1 : -1)));
127744
127744
  if (rail.current) rail.current.scrollLeft = index * rail.current.clientWidth;
127745
- select(index);
127745
+ select2(index);
127746
127746
  },
127747
127747
  onScroll: (event) => {
127748
- if (!boundRail && event.currentTarget.clientWidth > 0) select(Math.max(0, Math.min(pages2.length - 1, Math.round(event.currentTarget.scrollLeft / event.currentTarget.clientWidth))));
127748
+ if (!boundRail && event.currentTarget.clientWidth > 0) select2(Math.max(0, Math.min(pages2.length - 1, Math.round(event.currentTarget.scrollLeft / event.currentTarget.clientWidth))));
127749
127749
  },
127750
127750
  style: { display: "flex", overflowX: "auto", scrollSnapType: boundRail ? void 0 : "x mandatory", gap: boundRail ? 12 : void 0, width: "100%" },
127751
127751
  children: boundRail ? /* @__PURE__ */ jsx10(BoundList, { ctx, itemsPath, template: items[0], renderRow: (template, itemCtx) => /* @__PURE__ */ jsx10("div", { style: { flex: "0 0 auto" }, children: renderNode(template, itemCtx) }) }) : pages2.map((page, index) => /* @__PURE__ */ jsx10("div", { style: { minWidth: "100%", scrollSnapAlign: "start" }, children: renderNode(page, ctx) }, page?.id ?? index))
@@ -129146,13 +129146,13 @@ __export(render_descriptor_exports, {
129146
129146
  stabilizePngPage: () => stabilizePngPage,
129147
129147
  withRetry: () => withRetry2
129148
129148
  });
129149
- function a11ySemantics(type, props, modifiers, ancestorHidden, resolve63) {
129149
+ function a11ySemantics(type, props, modifiers, ancestorHidden, resolve65) {
129150
129150
  if (!A11Y_MODIFIER_KEYS.some((k2) => modifiers[k2] !== void 0)) return void 0;
129151
129151
  const literal = (v2) => typeof v2 === "string" && v2.trim() !== "" && !isDynamicValue(v2) ? v2 : void 0;
129152
129152
  const spoken = (v2) => {
129153
129153
  const lit = literal(v2);
129154
- if (lit !== void 0 || !resolve63 || typeof v2 !== "string" || !isDynamicValue(v2)) return lit;
129155
- const r2 = resolve63(v2);
129154
+ if (lit !== void 0 || !resolve65 || typeof v2 !== "string" || !isDynamicValue(v2)) return lit;
129155
+ const r2 = resolve65(v2);
129156
129156
  if (r2 === v2) return void 0;
129157
129157
  return typeof r2 === "string" && r2.trim() !== "" ? r2 : typeof r2 === "number" ? String(r2) : void 0;
129158
129158
  };
@@ -129166,7 +129166,7 @@ function a11ySemantics(type, props, modifiers, ancestorHidden, resolve63) {
129166
129166
  if (name !== void 0 && exposure === "exposed") out2.name = name;
129167
129167
  const hint = spoken(modifiers.accessibilityHint);
129168
129168
  if (hint !== void 0) out2.hint = hint;
129169
- const value = spoken(modifiers.accessibilityValue) ?? controlState(role, props, resolve63);
129169
+ const value = spoken(modifiers.accessibilityValue) ?? controlState(role, props, resolve65);
129170
129170
  if (value !== void 0) out2.value = value;
129171
129171
  if (typeof modifiers.headingLevel === "number") out2.headingLevel = modifiers.headingLevel;
129172
129172
  if (exposure !== "exposed") out2.exposure = exposure;
@@ -129187,13 +129187,13 @@ function a11ySemantics(type, props, modifiers, ancestorHidden, resolve63) {
129187
129187
  }
129188
129188
  return out2;
129189
129189
  }
129190
- function controlState(role, props, resolve63) {
129190
+ function controlState(role, props, resolve65) {
129191
129191
  if (role !== "toggle" && role !== "checkbox" && role !== "radio") return void 0;
129192
129192
  if (role === "checkbox" && props.indeterminate === true) return "mixed";
129193
129193
  const binding2 = typeof props.valuePath === "string" ? props.valuePath : typeof props.value === "string" && isDynamicValue(props.value) ? props.value : void 0;
129194
129194
  let on4;
129195
129195
  if (binding2 !== void 0) {
129196
- const v2 = resolve63 ? resolve63(binding2) : void 0;
129196
+ const v2 = resolve65 ? resolve65(binding2) : void 0;
129197
129197
  if (v2 === true || v2 === 1 || v2 === "true" || v2 === "1") on4 = true;
129198
129198
  else if (v2 === false || v2 === 0 || v2 === "false" || v2 === "0") on4 = false;
129199
129199
  else return void 0;
@@ -129523,7 +129523,7 @@ async function stabilizePngPage(page, scheme) {
129523
129523
  const browser = globalThis;
129524
129524
  browser.document.documentElement.style.colorScheme = selected;
129525
129525
  await browser.document.fonts?.ready;
129526
- await new Promise((resolve63) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve63())));
129526
+ await new Promise((resolve65) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve65())));
129527
129527
  }, scheme);
129528
129528
  }
129529
129529
  async function renderPngBatch(items) {
@@ -132144,7 +132144,7 @@ async function handleWebWix(req, res, state) {
132144
132144
  }
132145
132145
  if (match) {
132146
132146
  const mocked = match.rule.response;
132147
- if (mocked.delayMs) await new Promise((resolve63) => setTimeout(resolve63, mocked.delayMs));
132147
+ if (mocked.delayMs) await new Promise((resolve65) => setTimeout(resolve65, mocked.delayMs));
132148
132148
  const payload = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
132149
132149
  recordStream("mock", mocked.status, match.rule.id, mocked.headers);
132150
132150
  res.statusCode = mocked.status;
@@ -132209,14 +132209,14 @@ async function handleWebWix(req, res, state) {
132209
132209
  const chunk = await reader.read();
132210
132210
  if (chunk.done) break;
132211
132211
  if (chunk.value && !res.write(chunk.value)) {
132212
- await new Promise((resolve63) => {
132212
+ await new Promise((resolve65) => {
132213
132213
  let settled = false;
132214
132214
  const finish2 = () => {
132215
132215
  if (settled) return;
132216
132216
  settled = true;
132217
132217
  res.off("drain", finish2);
132218
132218
  res.off("close", finish2);
132219
- resolve63();
132219
+ resolve65();
132220
132220
  };
132221
132221
  if (res.destroyed || !res.writable) finish2();
132222
132222
  else {
@@ -132371,7 +132371,7 @@ async function handleWebWix(req, res, state) {
132371
132371
  }
132372
132372
  if (match) {
132373
132373
  const mocked = match.rule.response;
132374
- if (mocked.delayMs) await new Promise((resolve63) => setTimeout(resolve63, mocked.delayMs));
132374
+ if (mocked.delayMs) await new Promise((resolve65) => setTimeout(resolve65, mocked.delayMs));
132375
132375
  const responseBody = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
132376
132376
  record2("mock", mocked.status, responseBody, match.rule.id, mocked.headers);
132377
132377
  return reply(200, { status: mocked.status, body: responseBody ?? "" });
@@ -133410,8 +133410,8 @@ async function handleActionHandlerBundleGet(res, app) {
133410
133410
  }
133411
133411
  async function serveStatic(req, res, root, prefix) {
133412
133412
  const requested = decodeURIComponent((req.url ?? "").split("?")[0]);
133413
- const relative16 = requested.replace(prefix, "").replace(/^\//, "");
133414
- const safe = normalize3(relative16).replace(/^(\.\.[\/\\])+/, "");
133413
+ const relative17 = requested.replace(prefix, "").replace(/^\//, "");
133414
+ const safe = normalize3(relative17).replace(/^(\.\.[\/\\])+/, "");
133415
133415
  const fullPath = resolve38(root, safe);
133416
133416
  if (!fullPath.startsWith(root)) {
133417
133417
  return send(res, 403, "forbidden");
@@ -134575,12 +134575,12 @@ var init_query = __esm({
134575
134575
  });
134576
134576
 
134577
134577
  // ../../core/dev-server/src/crawl-input.ts
134578
- function resolved(v2, resolve63) {
134579
- if (typeof v2 === "string") return v2.startsWith("$service:") ? resolve63(v2) : v2;
134578
+ function resolved(v2, resolve65) {
134579
+ if (typeof v2 === "string") return v2.startsWith("$service:") ? resolve65(v2) : v2;
134580
134580
  if (Array.isArray(v2)) {
134581
134581
  const out2 = v2.flatMap((el2) => {
134582
134582
  if (typeof el2 !== "string" || !el2.startsWith("$service:")) return [el2];
134583
- const r2 = resolve63(el2);
134583
+ const r2 = resolve65(el2);
134584
134584
  return Array.isArray(r2) ? r2 : [r2];
134585
134585
  });
134586
134586
  return out2;
@@ -134594,9 +134594,9 @@ function hasRowBinding(props) {
134594
134594
  return itemToken(v2) || Array.isArray(v2) && v2.some(itemToken);
134595
134595
  });
134596
134596
  }
134597
- function declaredOptionIds(props, resolve63) {
134597
+ function declaredOptionIds(props, resolve65) {
134598
134598
  const literal = props.options ?? props.tabs ?? props.chips;
134599
- const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve63) : void 0;
134599
+ const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve65) : void 0;
134600
134600
  const raw = Array.isArray(bound) ? bound : literal;
134601
134601
  if (!Array.isArray(raw)) return [];
134602
134602
  const out2 = [];
@@ -134639,24 +134639,24 @@ function seedTokens(state, limit = 48) {
134639
134639
  walk2(state, 0);
134640
134640
  return out2;
134641
134641
  }
134642
- function synthesizeInput(control, resolve63, tokens2) {
134642
+ function synthesizeInput(control, resolve65, tokens2) {
134643
134643
  const id = `${control.type}.${control.callback}`;
134644
134644
  const row = SYNTHESIZED_CONTROLS[id];
134645
134645
  if (!row) return null;
134646
134646
  const props = control.props;
134647
134647
  if (hasRowBinding(props)) return null;
134648
134648
  if (row.from === "declared-options") {
134649
- const ids = declaredOptionIds(props, resolve63);
134649
+ const ids = declaredOptionIds(props, resolve65);
134650
134650
  if (!ids.length) return null;
134651
134651
  if (row.encoding === "string-array") {
134652
- const currentRaw2 = resolved(props.selectedIds, resolve63);
134652
+ const currentRaw2 = resolved(props.selectedIds, resolve65);
134653
134653
  const current3 = (Array.isArray(currentRaw2) ? currentRaw2 : []).filter((x2) => typeof x2 === "string");
134654
134654
  const pick4 = ids.find((o2) => !current3.includes(o2));
134655
134655
  if (pick4 === void 0) return null;
134656
134656
  const value = props.multiSelect === true ? [...current3, pick4] : [pick4];
134657
134657
  return { key: row.key, value, from: row.from, current: current3, control: id };
134658
134658
  }
134659
- const currentRaw = resolved(props.selectedId, resolve63);
134659
+ const currentRaw = resolved(props.selectedId, resolve65);
134660
134660
  const current2 = typeof currentRaw === "string" ? currentRaw : void 0;
134661
134661
  const pick3 = ids.find((o2) => o2 !== current2);
134662
134662
  if (pick3 === void 0) return null;
@@ -134664,7 +134664,7 @@ function synthesizeInput(control, resolve63, tokens2) {
134664
134664
  }
134665
134665
  if (!acceptsWords(props) || !acceptsWords(control.wrapper ?? {})) return null;
134666
134666
  const binding2 = typeof props.valuePath === "string" ? props.valuePath : typeof props.value === "string" && props.value.startsWith("$service:") ? props.value : void 0;
134667
- const bound = binding2 === void 0 ? void 0 : resolve63(binding2);
134667
+ const bound = binding2 === void 0 ? void 0 : resolve65(binding2);
134668
134668
  const literal = typeof props.value === "string" && !props.value.startsWith("$") ? props.value : void 0;
134669
134669
  const current = typeof bound === "string" ? bound : typeof bound === "number" ? String(bound) : literal ?? "";
134670
134670
  const max = typeof props.maxLength === "number" && props.maxLength > 0 ? props.maxLength : void 0;
@@ -137284,6 +137284,7 @@ __export(build_exports2, {
137284
137284
  bundleNameFromUrl: () => bundleNameFromUrl,
137285
137285
  collectComponentTypes: () => collectComponentTypes,
137286
137286
  contentReleaseId: () => contentReleaseId,
137287
+ countingHostAnswers: () => countingHostAnswers,
137287
137288
  countingWixCall: () => countingWixCall,
137288
137289
  declaresHostProvidedIdentity: () => declaresHostProvidedIdentity,
137289
137290
  gitSha: () => gitSha,
@@ -137657,17 +137658,39 @@ async function buildRelease(app, dest, opts = {}) {
137657
137658
  }
137658
137659
  function countingWixCall(base) {
137659
137660
  let returned = 0;
137661
+ const failed3 = [];
137660
137662
  return {
137661
137663
  call: async (method, path2, body) => {
137662
- const out2 = await base(method, path2, body);
137664
+ let out2;
137665
+ try {
137666
+ out2 = await base(method, path2, body);
137667
+ } catch (e2) {
137668
+ failed3.push(`${String(method).toUpperCase()} ${String(path2).split("?")[0]}`);
137669
+ throw e2;
137670
+ }
137663
137671
  returned += 1;
137664
137672
  return out2;
137665
137673
  },
137666
- returned: () => returned
137674
+ returned: () => returned,
137675
+ failed: () => [...failed3]
137676
+ };
137677
+ }
137678
+ function countingHostAnswers(host) {
137679
+ let answered = 0;
137680
+ const { wixCall } = host;
137681
+ if (!wixCall) return { host, answered: () => answered };
137682
+ return {
137683
+ host: { ...host, wixCall: (method, path2, body) => {
137684
+ const answer = wixCall(method, path2, body);
137685
+ if (answer !== void 0) answered += 1;
137686
+ return answer;
137687
+ } },
137688
+ answered: () => answered
137667
137689
  };
137668
137690
  }
137669
137691
  async function liveRenderServices(bundleJs, opts) {
137670
- const bus = hostDispatch(opts.localDbSchema, declaredCapabilitiesOf(opts.descriptor));
137692
+ const declared = declaredCapabilitiesOf(opts.descriptor);
137693
+ const bus = withHostAnswers(hostDispatch(opts.localDbSchema, declared), declared, opts.host);
137671
137694
  const appear = rootOnAppear(opts.descriptor);
137672
137695
  const fired = appear ? parseWorkerAction(appear.actionId) : null;
137673
137696
  if (fired) {
@@ -137690,16 +137713,46 @@ async function liveRenderServices(bundleJs, opts) {
137690
137713
  }
137691
137714
  }
137692
137715
  }
137716
+ if (opts.host) await settleUnawaitedWork();
137693
137717
  return { services: snapshot(w2).state, calls: w2.calls, errors: w2.errors };
137694
137718
  } finally {
137695
137719
  w2.dispose();
137696
137720
  }
137697
137721
  }
137722
+ if (opts.host) return loadAndSettle(bundleJs, liveBootOptions(opts, bus));
137698
137723
  return loadBundleServicesLive(bundleJs, liveBootOptions(opts, bus));
137699
137724
  }
137725
+ async function settleUnawaitedWork() {
137726
+ for (let turn = 0; turn < SETTLE_TURNS; turn++) await new Promise((resolve65) => setTimeout(resolve65, 0));
137727
+ }
137728
+ async function loadAndSettle(bundleJs, options) {
137729
+ const w2 = await bootBundleWorker(bundleJs, options);
137730
+ try {
137731
+ await settleUnawaitedWork();
137732
+ return { services: snapshot(w2).state, calls: w2.calls, errors: w2.errors };
137733
+ } finally {
137734
+ w2.dispose();
137735
+ }
137736
+ }
137737
+ function withHostAnswers(bus, declared, host) {
137738
+ if (!host) return bus;
137739
+ return (action, params) => {
137740
+ const capability = /^capability\.([^.]+)\./.exec(action)?.[1];
137741
+ const answer = capability === void 0 || declared.has(capability) ? host.dispatch(action, params) : void 0;
137742
+ return answer === void 0 ? bus(action, params) : Promise.resolve(answer);
137743
+ };
137744
+ }
137745
+ function memoryStorage() {
137746
+ const items = /* @__PURE__ */ new Map();
137747
+ return { getItem: (key2) => items.get(key2) ?? null, setItem: (key2, value) => void items.set(key2, value) };
137748
+ }
137700
137749
  function liveBootOptions(opts, bus) {
137750
+ const { host } = opts;
137751
+ const wixCall = host?.wixCall ? async (method, path2, body) => host.wixCall(method, path2, body) ?? opts.wixCall(method, path2, body) : opts.wixCall;
137701
137752
  return {
137702
- wixCall: opts.wixCall,
137753
+ wixCall,
137754
+ ...host ? { storage: memoryStorage() } : {},
137755
+ ...host?.wixApiSession ? { wixApiSession: host.wixApiSession } : {},
137703
137756
  input: opts.input,
137704
137757
  budgetMs: opts.budgetMs,
137705
137758
  // The capability arms, but NOT the signed-in-member arm. `hostDispatch` answers
@@ -137817,6 +137870,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
137817
137870
  let base2;
137818
137871
  let liveCalls;
137819
137872
  let liveReturned;
137873
+ let liveFailed;
137820
137874
  let liveErrors;
137821
137875
  let mockCalls;
137822
137876
  let mockBootFailed;
@@ -137827,16 +137881,20 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
137827
137881
  base2 = null;
137828
137882
  } else {
137829
137883
  const counting = countingWixCall(await ensureLiveWixCall());
137884
+ const host = collect2.render.host ? countingHostAnswers(collect2.render.host) : void 0;
137830
137885
  const live3 = await liveRenderServices(bundleJs, {
137831
137886
  wixCall: counting.call,
137832
137887
  input,
137833
137888
  budgetMs: collect2.render.loadBudgetMs ?? LIVE_LOAD_BUDGET_MS,
137834
137889
  localDbSchema: appLocalDbSchema,
137835
- descriptor
137890
+ descriptor,
137891
+ ...host ? { host: host.host } : {}
137836
137892
  });
137837
137893
  base2 = live3.services;
137838
137894
  liveCalls = [...live3.calls];
137839
137895
  liveReturned = counting.returned();
137896
+ if (host) liveReturned += host.answered();
137897
+ liveFailed = counting.failed();
137840
137898
  liveErrors = live3.errors;
137841
137899
  }
137842
137900
  } else if (collect2?.render?.mocks && collect2.render.hydrate !== false && bundleName && readBundle(bundleName)) {
@@ -137885,7 +137943,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
137885
137943
  services[svc] = { ...services[svc] ?? {}, ...st2 };
137886
137944
  }
137887
137945
  }
137888
- return { services, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveErrors ? { liveErrors } : {}, ...mockCalls ? { mockCalls, mockUnserved: mockUnserved ?? [] } : {}, ...mockBootFailed ? { mockBootFailed } : {} };
137946
+ return { services, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveFailed?.length ? { liveFailed } : {}, ...liveErrors ? { liveErrors } : {}, ...mockCalls ? { mockCalls, mockUnserved: mockUnserved ?? [] } : {}, ...mockBootFailed ? { mockBootFailed } : {} };
137889
137947
  };
137890
137948
  checkRegistry(preloaded.module.actions);
137891
137949
  const contentManifestPath2 = join47(preloaded.dir, "himalaya.content.json");
@@ -138180,9 +138238,9 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
138180
138238
  lint.push({ screenId, ok: report3.ok, issues: report3.issues });
138181
138239
  }
138182
138240
  if (collect2?.render && (!collect2.render.screenId || collect2.render.screenId === screenId)) {
138183
- const { services, liveCalls, liveReturned, liveErrors, mockCalls, mockUnserved, mockBootFailed } = await renderServicesFor(bundleName, descriptor, screenId);
138241
+ const { services, liveCalls, liveReturned, liveErrors, mockCalls, mockUnserved, mockBootFailed, liveFailed } = await renderServicesFor(bundleName, descriptor, screenId);
138184
138242
  const rr2 = await renderDescriptorWeb(descriptor, renderTokens, renderScheme, collect2.render.png === true, services, collect2.render.width, collect2.render.rtl === true);
138185
- renders.push({ screenId, scheme: renderScheme, ...rr2, ...await renderCompare(descriptor, services), ...collect2.render.dumpState && services ? { serviceState: services } : {}, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveErrors ? { liveErrors } : {}, ...mockCalls ? { mockCalls, mockUnserved } : {}, ...mockBootFailed ? { mockBootFailed } : {} });
138243
+ renders.push({ screenId, scheme: renderScheme, ...rr2, ...await renderCompare(descriptor, services), ...collect2.render.dumpState && services ? { serviceState: services } : {}, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveFailed ? { liveFailed } : {}, ...liveErrors ? { liveErrors } : {}, ...mockCalls ? { mockCalls, mockUnserved } : {}, ...mockBootFailed ? { mockBootFailed } : {} });
138186
138244
  }
138187
138245
  }
138188
138246
  const wantedRender = collect2?.render?.screenId;
@@ -138208,9 +138266,9 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
138208
138266
  });
138209
138267
  lint.push({ screenId: wantedRender, ok: report3.ok, issues: report3.issues });
138210
138268
  }
138211
- const { services, liveCalls, liveReturned, liveErrors, mockCalls, mockUnserved, mockBootFailed } = await renderServicesFor(bundleName, descriptor, wantedRender);
138269
+ const { services, liveCalls, liveReturned, liveErrors, mockCalls, mockUnserved, mockBootFailed, liveFailed } = await renderServicesFor(bundleName, descriptor, wantedRender);
138212
138270
  const rr2 = await renderDescriptorWeb(descriptor, renderTokens, renderScheme, collect2.render.png === true, services, collect2.render.width, collect2.render.rtl === true);
138213
- renders.push({ screenId: wantedRender, scheme: renderScheme, ...rr2, ...await renderCompare(descriptor, services), ...collect2.render.dumpState && services ? { serviceState: services } : {}, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveErrors ? { liveErrors } : {}, ...mockCalls ? { mockCalls, mockUnserved } : {}, ...mockBootFailed ? { mockBootFailed } : {} });
138271
+ renders.push({ screenId: wantedRender, scheme: renderScheme, ...rr2, ...await renderCompare(descriptor, services), ...collect2.render.dumpState && services ? { serviceState: services } : {}, ...liveCalls ? { liveCalls } : {}, ...liveReturned !== void 0 ? { liveReturned } : {}, ...liveFailed ? { liveFailed } : {}, ...liveErrors ? { liveErrors } : {}, ...mockCalls ? { mockCalls, mockUnserved } : {}, ...mockBootFailed ? { mockBootFailed } : {} });
138214
138272
  }
138215
138273
  }
138216
138274
  for (const t2 of preloaded.module.screens.templated ?? []) {
@@ -138581,7 +138639,7 @@ function declaresHostProvidedIdentity(auth) {
138581
138639
  const config = auth?.config;
138582
138640
  return typeof config === "object" && config !== null && config.hostProvided === true;
138583
138641
  }
138584
- var BAKE_OFFLINE_BASE, KNOWN_ICON_NAMES, KNOWN_ICONS, REPO_ROOT7, TIER5_DIR, requireFromHere, SOURCEMAP_ON_DEMAND_PATH, BAKED_SERVER_BASE_URL;
138642
+ var BAKE_OFFLINE_BASE, KNOWN_ICON_NAMES, KNOWN_ICONS, REPO_ROOT7, TIER5_DIR, requireFromHere, SOURCEMAP_ON_DEMAND_PATH, BAKED_SERVER_BASE_URL, SETTLE_TURNS;
138585
138643
  var init_build3 = __esm({
138586
138644
  "../release-build/build.ts"() {
138587
138645
  init_site_view_metadata();
@@ -138623,6 +138681,7 @@ var init_build3 = __esm({
138623
138681
  requireFromHere = createRequire2(import.meta.url);
138624
138682
  SOURCEMAP_ON_DEMAND_PATH = join47(REPO_ROOT7, "core/dev-server/tier5-bundles-src/sourcemap-on-demand.mjs");
138625
138683
  BAKED_SERVER_BASE_URL = "http://baked.himalaya.invalid";
138684
+ SETTLE_TURNS = 20;
138626
138685
  }
138627
138686
  });
138628
138687
 
@@ -152745,7 +152804,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
152745
152804
  const headers2 = Object.fromEntries(new Headers(init.headers).entries());
152746
152805
  const request = url.protocol === "https:" ? httpsRequest : httpRequest;
152747
152806
  const hostname3 = url.hostname.replace(/^\[|\]$/g, "");
152748
- return await new Promise((resolve63, reject) => {
152807
+ return await new Promise((resolve65, reject) => {
152749
152808
  let settled = false;
152750
152809
  const finish2 = (fn2) => {
152751
152810
  if (settled) return;
@@ -152782,7 +152841,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
152782
152841
  }
152783
152842
  const responseHeaders = new Headers();
152784
152843
  for (const [key2, value] of Object.entries(response.headers)) if (value !== void 0) responseHeaders.set(key2, Array.isArray(value) ? value.join(", ") : value);
152785
- resolve63(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
152844
+ resolve65(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
152786
152845
  }));
152787
152846
  });
152788
152847
  req.once("error", (error) => finish2(() => reject(error)));
@@ -153082,7 +153141,7 @@ function createLocalTestSandbox() {
153082
153141
  }
153083
153142
  })();
153084
153143
  `;
153085
- return await new Promise((resolve63, reject) => {
153144
+ return await new Promise((resolve65, reject) => {
153086
153145
  const { port1, port2 } = new MessageChannel();
153087
153146
  const serializableContext = {
153088
153147
  auth: context.auth,
@@ -153158,7 +153217,7 @@ function createLocalTestSandbox() {
153158
153217
  timer = setTimeout(() => finish2(() => reject(new SandboxError("timeout", `execution exceeded ${limits.timeoutMs}ms`))), Math.max(1, limits.timeoutMs));
153159
153218
  return;
153160
153219
  }
153161
- if (message.ok) finish2(() => resolve63({ value: message.value, durationMs: Date.now() - started }));
153220
+ if (message.ok) finish2(() => resolve65({ value: message.value, durationMs: Date.now() - started }));
153162
153221
  else finish2(() => reject(new SandboxError("execution_failed", message.message ?? "handler failed")));
153163
153222
  });
153164
153223
  worker.once("error", (error) => finish2(() => reject(new SandboxError("execution_failed", error.message))));
@@ -155057,12 +155116,12 @@ function createLoginSession(deps) {
155057
155116
  current = pending;
155058
155117
  const out2 = [];
155059
155118
  const err = [];
155060
- return new Promise((resolve63) => {
155119
+ return new Promise((resolve65) => {
155061
155120
  let answered = false;
155062
155121
  const answer = () => {
155063
155122
  if (answered) return;
155064
155123
  answered = true;
155065
- resolve63(current);
155124
+ resolve65(current);
155066
155125
  };
155067
155126
  let child;
155068
155127
  try {
@@ -155185,9 +155244,9 @@ async function startMcpServer(opts) {
155185
155244
  login: createLoginSession({ ...defaultLoginDeps, selfCommand: previewDeps.selfCommand, ...opts.login }),
155186
155245
  ...opts.workspace ? { workspaceBoundary: opts.workspace } : {}
155187
155246
  };
155188
- const closed = new Promise((resolve63) => {
155189
- stdin.once("end", resolve63);
155190
- stdin.once("close", resolve63);
155247
+ const closed = new Promise((resolve65) => {
155248
+ stdin.once("end", resolve65);
155249
+ stdin.once("close", resolve65);
155191
155250
  });
155192
155251
  const handle = serveStdio(
155193
155252
  () => {
@@ -155567,10 +155626,10 @@ function collectSdkModules(files, resolveSubpath) {
155567
155626
  for (const source of Object.values(files)) visit(source);
155568
155627
  return { modules, unsupported };
155569
155628
  }
155570
- function sdkSubpathReader(resolve63) {
155629
+ function sdkSubpathReader(resolve65) {
155571
155630
  return (sub) => {
155572
155631
  try {
155573
- return readFileSync79(resolve63(`@wix/himalaya/${sub}`), "utf8");
155632
+ return readFileSync79(resolve65(`@wix/himalaya/${sub}`), "utf8");
155574
155633
  } catch {
155575
155634
  return null;
155576
155635
  }
@@ -155648,7 +155707,7 @@ async function runBrowserAuthoring(opts) {
155648
155707
  const token = mintToken2(payload);
155649
155708
  const unusable = await probeAuthoringPage(opts.authoringBase, opts.fetchImpl, opts.probeTimeoutMs);
155650
155709
  if (unusable) throw new Error(unusable);
155651
- return await new Promise((resolve63, reject) => {
155710
+ return await new Promise((resolve65, reject) => {
155652
155711
  let settled = false;
155653
155712
  let url = "";
155654
155713
  const server = createServer5();
@@ -155700,7 +155759,7 @@ async function runBrowserAuthoring(opts) {
155700
155759
  }
155701
155760
  res.writeHead(200, { "content-type": "text/plain" }).end("ok");
155702
155761
  const report3 = body.result;
155703
- finish2(() => resolve63({ report: report3, url }));
155762
+ finish2(() => resolve65({ report: report3, url }));
155704
155763
  })();
155705
155764
  });
155706
155765
  server.on("error", (e2) => finish2(() => reject(e2)));
@@ -158606,6 +158665,15 @@ function retryAfterMs(header, nowMs) {
158606
158665
  const ms2 = /^\d+$/.test(trimmed) ? Number(trimmed) * 1e3 : Date.parse(trimmed) - nowMs;
158607
158666
  return Number.isFinite(ms2) ? Math.min(Math.max(ms2, 0), MAX_RETRY_WAIT_MS) : void 0;
158608
158667
  }
158668
+ function assetUploadUrl(operation, size) {
158669
+ const url = new URL(operation.url);
158670
+ const appleHost = url.hostname === "apple.com" || url.hostname.endsWith(".apple.com");
158671
+ const inFile = Number.isInteger(operation.offset) && Number.isInteger(operation.length) && operation.offset >= 0 && operation.length > 0 && operation.offset + operation.length <= size;
158672
+ if (url.protocol !== "https:" || !appleHost || url.username || url.password || operation.method !== "PUT" || !inFile) {
158673
+ throw new AscError("refused", `refusing an asset upload operation Apple would not issue (${operation.method} ${url.origin})`);
158674
+ }
158675
+ return url;
158676
+ }
158609
158677
  function backoffMs(attempt) {
158610
158678
  return Math.min(BASE_BACKOFF_MS * 2 ** (attempt - 1), MAX_RETRY_WAIT_MS);
158611
158679
  }
@@ -158668,7 +158736,7 @@ var init_iap_client = __esm({
158668
158736
  this.options = options;
158669
158737
  this.fetchImpl = options.fetchImpl ?? ((input, init) => globalThis.fetch(input, init));
158670
158738
  this.now = options.now ?? Date.now;
158671
- this.sleep = options.sleep ?? ((ms2) => new Promise((resolve63) => setTimeout(resolve63, ms2)));
158739
+ this.sleep = options.sleep ?? ((ms2) => new Promise((resolve65) => setTimeout(resolve65, ms2)));
158672
158740
  }
158673
158741
  fetchImpl;
158674
158742
  now;
@@ -158695,6 +158763,32 @@ var init_iap_client = __esm({
158695
158763
  async patch(path2, body) {
158696
158764
  return this.write("PATCH", this.resolve(path2), body);
158697
158765
  }
158766
+ async delete(path2) {
158767
+ await this.write("DELETE", this.resolve(path2));
158768
+ }
158769
+ async uploadParts(operations, bytes2) {
158770
+ for (const [i2, operation] of operations.entries()) {
158771
+ const where = `upload of part ${i2 + 1} of ${operations.length} to Apple's asset storage`;
158772
+ const response = await this.putPart(operation, bytes2, where);
158773
+ if (response.status >= 500) throw new AscError("server", `${where} \u2192 ${response.status}`, response.status);
158774
+ if (!response.ok) throw new AscError("invalid", `${where} \u2192 ${response.status} \u2014 the reserved upload was refused; make a new plan, which reserves a fresh one`, response.status);
158775
+ }
158776
+ }
158777
+ async putPart(operation, bytes2, where) {
158778
+ const url = assetUploadUrl(operation, bytes2.length);
158779
+ const headers2 = Object.fromEntries(operation.requestHeaders.filter((h2) => h2.name.toLowerCase() !== "authorization").map((h2) => [h2.name, h2.value]));
158780
+ try {
158781
+ return await this.fetchImpl(url.href, {
158782
+ method: "PUT",
158783
+ headers: headers2,
158784
+ body: bytes2.slice(operation.offset, operation.offset + operation.length),
158785
+ redirect: "error",
158786
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
158787
+ });
158788
+ } catch (e2) {
158789
+ throw new AscError("network", `${where} failed before a response: ${this.scrub(e2.message)}`);
158790
+ }
158791
+ }
158698
158792
  resolve(pathOrUrl) {
158699
158793
  const url = new URL(pathOrUrl, ASC_ORIGIN);
158700
158794
  const allowed2 = url.origin === ASC_ORIGIN && !url.username && !url.password && /^\/v[12]\//.test(url.pathname);
@@ -158819,6 +158913,20 @@ function toVersion(resource) {
158819
158913
  function toLocalization(resource) {
158820
158914
  return { id: resource.id, locale: attr(resource, "locale"), name: attr(resource, "name"), description: attr(resource, "description") };
158821
158915
  }
158916
+ function toReviewScreenshot(resource) {
158917
+ const attributes = resource.attributes ?? {};
158918
+ const delivery = attributes.assetDeliveryState ?? {};
158919
+ const errors = (delivery.errors ?? []).map((e2) => [e2.code, e2.description].filter((part2) => typeof part2 === "string").join(": "));
158920
+ const checksum = attr(resource, "sourceFileChecksum");
158921
+ return {
158922
+ id: resource.id,
158923
+ fileName: attr(resource, "fileName"),
158924
+ fileSize: typeof attributes.fileSize === "number" ? attributes.fileSize : 0,
158925
+ ...checksum ? { checksum } : {},
158926
+ state: typeof delivery.state === "string" ? delivery.state : "",
158927
+ errors
158928
+ };
158929
+ }
158822
158930
  function toManualPrice(price, included) {
158823
158931
  const point = included.find((r2) => r2.type === "inAppPurchasePricePoints" && r2.id === relatedId(price, "inAppPurchasePricePoint"));
158824
158932
  const date = (name) => typeof price.attributes?.[name] === "string" ? price.attributes[name] : null;
@@ -158840,7 +158948,7 @@ async function readOptional(read) {
158840
158948
  function createIapApi(client2) {
158841
158949
  return new AppStoreConnectIapApi(client2);
158842
158950
  }
158843
- var APPLE_PRODUCT_TYPES, PRICE_POINT_PAGE, INITIAL_PRICE_REF, PAGE, linkage, related, enc, AppStoreConnectIapApi;
158951
+ var APPLE_PRODUCT_TYPES, PRICE_POINT_PAGE, INITIAL_PRICE_REF, PAGE, linkage, related, enc, AppStoreConnectIapApi, SCREENSHOTS, SCREENSHOT_TYPE, ReviewScreenshotEndpoints;
158844
158952
  var init_iap_api = __esm({
158845
158953
  "../store-release/iap-api.ts"() {
158846
158954
  init_iap_client();
@@ -158854,7 +158962,9 @@ var init_iap_api = __esm({
158854
158962
  AppStoreConnectIapApi = class {
158855
158963
  constructor(client2) {
158856
158964
  this.client = client2;
158965
+ this.screenshots = new ReviewScreenshotEndpoints(client2);
158857
158966
  }
158967
+ screenshots;
158858
158968
  async readApp(appId2) {
158859
158969
  const app = requireSingle(await this.client.get(`/v1/apps/${enc(appId2)}?fields[apps]=bundleId`), "app");
158860
158970
  return { id: app.id, bundleId: attr(app, "bundleId") };
@@ -158974,6 +159084,50 @@ var init_iap_api = __esm({
158974
159084
  }
158975
159085
  });
158976
159086
  }
159087
+ async readReviewScreenshot(resourceId) {
159088
+ return this.screenshots.read(resourceId);
159089
+ }
159090
+ async reserveReviewScreenshot(resourceId, file2) {
159091
+ return this.screenshots.reserve(resourceId, file2);
159092
+ }
159093
+ async uploadReviewScreenshotParts(reservation, bytes2) {
159094
+ await this.client.uploadParts(reservation.uploadOperations, bytes2);
159095
+ }
159096
+ async commitReviewScreenshot(screenshotId, checksum) {
159097
+ return this.screenshots.commit(screenshotId, checksum);
159098
+ }
159099
+ async deleteReviewScreenshot(screenshotId) {
159100
+ await this.screenshots.delete(screenshotId);
159101
+ }
159102
+ };
159103
+ SCREENSHOTS = "/v1/inAppPurchaseAppStoreReviewScreenshots";
159104
+ SCREENSHOT_TYPE = "inAppPurchaseAppStoreReviewScreenshots";
159105
+ ReviewScreenshotEndpoints = class {
159106
+ constructor(client2) {
159107
+ this.client = client2;
159108
+ }
159109
+ async read(resourceId) {
159110
+ const screenshot = await readOptional(() => this.client.get(`/v2/inAppPurchases/${enc(resourceId)}/appStoreReviewScreenshot`));
159111
+ return screenshot && toReviewScreenshot(screenshot);
159112
+ }
159113
+ async reserve(resourceId, file2) {
159114
+ const doc = await this.client.post(SCREENSHOTS, {
159115
+ data: { type: SCREENSHOT_TYPE, attributes: file2, relationships: { inAppPurchaseV2: related("inAppPurchases", resourceId) } }
159116
+ });
159117
+ const reservation = requireSingle(doc, "review screenshot reservation");
159118
+ const operations = reservation.attributes?.uploadOperations;
159119
+ if (!Array.isArray(operations) || !operations.length) throw new AscError("server", "App Store Connect reserved the review screenshot without upload operations");
159120
+ return { id: reservation.id, uploadOperations: operations };
159121
+ }
159122
+ async commit(screenshotId, checksum) {
159123
+ const doc = await this.client.patch(`${SCREENSHOTS}/${enc(screenshotId)}`, {
159124
+ data: { type: SCREENSHOT_TYPE, id: screenshotId, attributes: { uploaded: true, sourceFileChecksum: checksum } }
159125
+ });
159126
+ return toReviewScreenshot(requireSingle(doc, "review screenshot"));
159127
+ }
159128
+ async delete(screenshotId) {
159129
+ await this.client.delete(`${SCREENSHOTS}/${enc(screenshotId)}`);
159130
+ }
158977
159131
  };
158978
159132
  }
158979
159133
  });
@@ -159058,6 +159212,7 @@ function readItem(reader, value, index) {
159058
159212
  const price = readPrice(reader, obj3, path2);
159059
159213
  const reviewNote = reader.optionalText(obj3, "reviewNote", path2);
159060
159214
  if (reviewNote) reader.maxLength(reviewNote, `${path2}.reviewNote`, APPLE_LIMITS.reviewNote);
159215
+ const reviewScreenshot = obj3.reviewScreenshot === void 0 ? void 0 : reader.text(obj3, "reviewScreenshot", path2, SCREENSHOT_PATH);
159061
159216
  return {
159062
159217
  ...readSubject(reader, obj3, path2, type),
159063
159218
  classification: reader.literal(obj3, "classification", path2, "digital", "physical goods and unclassified products are never registered as in-app purchases"),
@@ -159066,6 +159221,7 @@ function readItem(reader, value, index) {
159066
159221
  type,
159067
159222
  referenceName: limitedText(reader, obj3, "referenceName", path2, APPLE_LIMITS.referenceName),
159068
159223
  ...reviewNote === void 0 ? {} : { reviewNote },
159224
+ ...reviewScreenshot === void 0 ? {} : { reviewScreenshot },
159069
159225
  localizations: readLocalizations(reader, obj3, path2),
159070
159226
  price,
159071
159227
  territories: readTerritories(reader, obj3, path2, price.baseTerritory)
@@ -159128,7 +159284,7 @@ function sha256Digest(value) {
159128
159284
  function manifestDigest(manifest) {
159129
159285
  return sha256Digest(manifest);
159130
159286
  }
159131
- var IapManifestError, APPLE_APP_ID, TEAM_ID, BUNDLE_ID, PRODUCT_ID, TERRITORY, CURRENCY2, AMOUNT, LOCALE, CREDENTIAL_SHAPES, MANIFEST_KEYS, TARGET_KEYS, ITEM_KEYS, WIX_KEYS, UNLOCK_KEYS, LOCALIZATION_KEYS, PRICE_KEYS, PRODUCT_TYPES, PRICE_RULES, APPLE_LIMITS, childPath, ManifestReader;
159287
+ var IapManifestError, APPLE_APP_ID, TEAM_ID, BUNDLE_ID, PRODUCT_ID, TERRITORY, CURRENCY2, AMOUNT, LOCALE, SCREENSHOT_PATH, CREDENTIAL_SHAPES, MANIFEST_KEYS, TARGET_KEYS, ITEM_KEYS, WIX_KEYS, UNLOCK_KEYS, LOCALIZATION_KEYS, PRICE_KEYS, PRODUCT_TYPES, PRICE_RULES, APPLE_LIMITS, childPath, ManifestReader;
159132
159288
  var init_iap_manifest = __esm({
159133
159289
  "../store-release/iap-manifest.ts"() {
159134
159290
  IapManifestError = class extends Error {
@@ -159147,6 +159303,7 @@ var init_iap_manifest = __esm({
159147
159303
  CURRENCY2 = { pattern: /^[A-Z]{3}$/, hint: "an ISO 4217 currency code such as USD" };
159148
159304
  AMOUNT = { pattern: /^\d+(\.\d+)?$/, hint: 'an exact decimal string such as "0.99"' };
159149
159305
  LOCALE = { pattern: /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/, hint: "a locale such as en-US" };
159306
+ SCREENSHOT_PATH = { pattern: /\.(png|jpe?g)$/i, hint: "a path to a .png, .jpg or .jpeg file" };
159150
159307
  CREDENTIAL_SHAPES = [
159151
159308
  /-----BEGIN [A-Z ]*PRIVATE KEY-----/,
159152
159309
  /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/,
@@ -159163,6 +159320,7 @@ var init_iap_manifest = __esm({
159163
159320
  "type",
159164
159321
  "referenceName",
159165
159322
  "reviewNote",
159323
+ "reviewScreenshot",
159166
159324
  "localizations",
159167
159325
  "price",
159168
159326
  "territories"
@@ -159312,8 +159470,16 @@ var init_iap_pricing = __esm({
159312
159470
  });
159313
159471
 
159314
159472
  // ../store-release/iap-result.ts
159315
- function remainingRequirements(observed) {
159473
+ import { basename as basename18 } from "node:path";
159474
+ function missingMetadataRequirement(screenshotState, itemNamesFile) {
159475
+ if (screenshotState === void 0) return MISSING_SCREENSHOT;
159476
+ const leftover = LEFTOVER_STATES[screenshotState];
159477
+ if (!leftover) return MISSING_AFTER_SCREENSHOT;
159478
+ return leftover.problem + (itemNamesFile ? leftover.fix : ADD_FILE_FIRST);
159479
+ }
159480
+ function remainingRequirements(observed, itemNamesFile = true) {
159316
159481
  if (!observed) return ["the product does not exist in App Store Connect yet"];
159482
+ if (observed.state === "MISSING_METADATA") return [observed.reviewScreenshotRead ? missingMetadataRequirement(observed.reviewScreenshot?.state, itemNamesFile) : MISSING_UNREAD];
159317
159483
  const requirement = STATE_REQUIREMENTS[observed.state];
159318
159484
  return requirement ? [requirement] : [];
159319
159485
  }
@@ -159334,6 +159500,10 @@ function mappingFor(target, item, appleResourceId) {
159334
159500
  function metadataVersion(observed) {
159335
159501
  return observed?.versions.find((v2) => v2.id === observed.metadataVersionId);
159336
159502
  }
159503
+ function screenshotReport(path2, observed) {
159504
+ const held = observed?.reviewScreenshot;
159505
+ return { requested: basename18(path2), ...held ? { observed: { fileName: held.fileName, state: held.state } } : {} };
159506
+ }
159337
159507
  function itemResult(input) {
159338
159508
  const { target, item, observed } = input;
159339
159509
  const version4 = metadataVersion(observed);
@@ -159352,7 +159522,8 @@ function itemResult(input) {
159352
159522
  ...observed?.availability ? { observed: observed.availability.territories, availableInNewTerritories: observed.availability.availableInNewTerritories } : {}
159353
159523
  },
159354
159524
  localizations: { requested: item.localizations.map((l2) => l2.locale), observed: observed?.localizations.map((l2) => l2.locale) ?? [] },
159355
- remainingRequirements: [...input.requirements ?? [], ...remainingRequirements(observed)],
159525
+ ...item.reviewScreenshot ? { reviewScreenshot: screenshotReport(item.reviewScreenshot, observed) } : {},
159526
+ remainingRequirements: [...input.requirements ?? [], ...remainingRequirements(observed, item.reviewScreenshot !== void 0)],
159356
159527
  lastReadAt: input.readAt.toISOString()
159357
159528
  }
159358
159529
  };
@@ -159369,12 +159540,11 @@ function iapResult(args) {
159369
159540
  items: args.items
159370
159541
  };
159371
159542
  }
159372
- var COMPLETE_OUTCOMES, STATE_REQUIREMENTS;
159543
+ var COMPLETE_OUTCOMES, STATE_REQUIREMENTS, MISSING_SCREENSHOT, MISSING_UNREAD, REFUSED_SCREENSHOT, MISSING_AFTER_SCREENSHOT, UNFINISHED_SCREENSHOT, LEFTOVER_STATES, ADD_FILE_FIRST;
159373
159544
  var init_iap_result = __esm({
159374
159545
  "../store-release/iap-result.ts"() {
159375
159546
  COMPLETE_OUTCOMES = /* @__PURE__ */ new Set(["created", "updated", "reused"]);
159376
159547
  STATE_REQUIREMENTS = {
159377
- MISSING_METADATA: "App Store Connect reports MISSING_METADATA \u2014 usually the App Review screenshot, which this command does not upload",
159378
159548
  READY_TO_SUBMIT: "submit the product for App Review with an app version \u2014 this command never submits",
159379
159549
  DEVELOPER_ACTION_NEEDED: "resolve the App Review feedback in App Store Connect",
159380
159550
  REJECTED: "resolve the App Review rejection in App Store Connect",
@@ -159386,6 +159556,16 @@ var init_iap_result = __esm({
159386
159556
  WAITING_FOR_UPLOAD: "waiting for its hosted content to be uploaded",
159387
159557
  PROCESSING_CONTENT: "Apple is still processing its hosted content"
159388
159558
  };
159559
+ MISSING_SCREENSHOT = 'App Store Connect reports MISSING_METADATA and the product has no App Review screenshot \u2014 add "reviewScreenshot" to the item and apply, or upload one in App Store Connect';
159560
+ MISSING_UNREAD = 'App Store Connect reports MISSING_METADATA \u2014 check the product in App Store Connect; when it lacks the App Review screenshot, add "reviewScreenshot" to the item and apply';
159561
+ REFUSED_SCREENSHOT = "App Store Connect reports MISSING_METADATA \u2014 Apple could not process the review screenshot";
159562
+ MISSING_AFTER_SCREENSHOT = "App Store Connect still reports MISSING_METADATA \u2014 Apple may still be processing the review screenshot; if it stays, check the product in App Store Connect";
159563
+ UNFINISHED_SCREENSHOT = "App Store Connect reports MISSING_METADATA \u2014 the review screenshot upload is unfinished";
159564
+ LEFTOVER_STATES = {
159565
+ FAILED: { problem: REFUSED_SCREENSHOT, fix: "; replace the file and apply again" },
159566
+ AWAITING_UPLOAD: { problem: UNFINISHED_SCREENSHOT, fix: "; rerun plan and apply to replace it" }
159567
+ };
159568
+ ADD_FILE_FIRST = ' \u2014 add "reviewScreenshot" to the item first, then plan and apply';
159389
159569
  }
159390
159570
  });
159391
159571
 
@@ -159429,6 +159609,99 @@ var init_iap_price_status = __esm({
159429
159609
  }
159430
159610
  });
159431
159611
 
159612
+ // ../store-release/screenshot-display-types.ts
159613
+ function displayTypeForSize(w2, h2) {
159614
+ const key2 = `${Math.min(w2, h2)}x${Math.max(w2, h2)}`;
159615
+ const map = {
159616
+ "1320x2868": "APP_IPHONE_67",
159617
+ // 6.9" → 6.7"/6.9" combined slot
159618
+ "1290x2796": "APP_IPHONE_67",
159619
+ // 6.7"
159620
+ "1242x2688": "APP_IPHONE_65",
159621
+ // 6.5"
159622
+ "1284x2778": "APP_IPHONE_65",
159623
+ "1206x2622": "APP_IPHONE_61",
159624
+ // 6.3"/6.1"
159625
+ "1179x2556": "APP_IPHONE_61",
159626
+ "2048x2732": "APP_IPAD_PRO_129",
159627
+ "2064x2752": "APP_IPAD_PRO_3GEN_129"
159628
+ };
159629
+ return map[key2] ?? null;
159630
+ }
159631
+ var init_screenshot_display_types = __esm({
159632
+ "../store-release/screenshot-display-types.ts"() {
159633
+ }
159634
+ });
159635
+
159636
+ // ../store-release/iap-review-screenshot.ts
159637
+ import { createHash as createHash38 } from "node:crypto";
159638
+ import { basename as basename19, resolve as resolve56 } from "node:path";
159639
+ function pngSize(bytes2) {
159640
+ const signed = PNG_SIGNATURE.every((b2, i2) => bytes2[i2] === b2);
159641
+ if (!signed || bytes2.length < 24 || bytes2.toString("ascii", 12, 16) !== "IHDR") return void 0;
159642
+ return { format: "png", width: bytes2.readUInt32BE(16), height: bytes2.readUInt32BE(20) };
159643
+ }
159644
+ function jpegSize(bytes2) {
159645
+ if (bytes2[0] !== 255 || bytes2[1] !== 216) return void 0;
159646
+ for (let at2 = 2; at2 + 9 <= bytes2.length && bytes2[at2] === 255; at2 += 2 + bytes2.readUInt16BE(at2 + 2)) {
159647
+ if (JPEG_SOF_MARKERS.has(bytes2[at2 + 1])) return { format: "jpeg", height: bytes2.readUInt16BE(at2 + 5), width: bytes2.readUInt16BE(at2 + 7) };
159648
+ }
159649
+ return void 0;
159650
+ }
159651
+ function readImageSize(bytes2) {
159652
+ const buffer = Buffer.from(bytes2.buffer, bytes2.byteOffset, bytes2.byteLength);
159653
+ return pngSize(buffer) ?? jpegSize(buffer);
159654
+ }
159655
+ function md5Hex(bytes2) {
159656
+ return createHash38("md5").update(bytes2).digest("hex");
159657
+ }
159658
+ function isAppStoreScreenshotSize(file2) {
159659
+ return displayTypeForSize(file2.width, file2.height) !== null;
159660
+ }
159661
+ function screenshotNotes(file2) {
159662
+ const size = `${file2.width}\xD7${file2.height}`;
159663
+ const notes = [`review screenshot ${file2.fileName} (${size} ${file2.format.toUpperCase()})`];
159664
+ if (!isAppStoreScreenshotSize(file2)) notes.push(`${size} is not an App Store screenshot size this tool knows \u2014 Apple may refuse it; a full-size iPhone screenshot is safest`);
159665
+ return notes;
159666
+ }
159667
+ function readReviewScreenshot(path2, source) {
159668
+ if (!source.readBytes) throw new Error("this run cannot read files");
159669
+ const absolute = resolve56(source.manifestDir ?? process.cwd(), path2);
159670
+ let bytes2;
159671
+ try {
159672
+ bytes2 = source.readBytes(absolute);
159673
+ } catch (e2) {
159674
+ throw new Error(`cannot read ${absolute}: ${e2.message}`);
159675
+ }
159676
+ const size = readImageSize(bytes2);
159677
+ if (!size) throw new Error(`${absolute} is not a PNG or JPEG image`);
159678
+ return { ...size, path: absolute, fileName: basename19(absolute), bytes: bytes2, checksum: md5Hex(bytes2) };
159679
+ }
159680
+ function loadReviewScreenshots(manifest, source, indices = manifest.items.map((_2, i2) => i2)) {
159681
+ const files = /* @__PURE__ */ new Map();
159682
+ const problems = [];
159683
+ for (const i2 of indices) {
159684
+ const path2 = manifest.items[i2].reviewScreenshot;
159685
+ if (path2 === void 0) continue;
159686
+ try {
159687
+ files.set(i2, readReviewScreenshot(path2, source));
159688
+ } catch (e2) {
159689
+ problems.push(`items[${i2}].reviewScreenshot: ${e2.message}`);
159690
+ }
159691
+ }
159692
+ if (problems.length) throw new IapManifestError("the manifest", problems);
159693
+ return files;
159694
+ }
159695
+ var PNG_SIGNATURE, JPEG_SOF_MARKERS;
159696
+ var init_iap_review_screenshot = __esm({
159697
+ "../store-release/iap-review-screenshot.ts"() {
159698
+ init_iap_manifest();
159699
+ init_screenshot_display_types();
159700
+ PNG_SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10];
159701
+ JPEG_SOF_MARKERS = /* @__PURE__ */ new Set([192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207]);
159702
+ }
159703
+ });
159704
+
159432
159705
  // ../store-release/iap-plan.ts
159433
159706
  function priceNote(price, target) {
159434
159707
  if (price.rule !== "atLeast") return CONDITIONAL_PRICE_NOTE;
@@ -159568,6 +159841,47 @@ function availabilityDiff(item, observed) {
159568
159841
  function metadataDiffs(item, observed, target = exactTarget(item.price)) {
159569
159842
  return [...localizationDiffs(item, observed), ...priceDiff(item, observed, target), ...availabilityDiff(item, observed)];
159570
159843
  }
159844
+ function screenshotMatches(observed, checksum) {
159845
+ return observed?.checksum === checksum && observed.state !== "FAILED";
159846
+ }
159847
+ function describeScreenshotGap(observed, fileName) {
159848
+ if (!observed) return "the review screenshot is not uploaded";
159849
+ if (observed.state === "AWAITING_UPLOAD") return "the review screenshot is not uploaded \u2014 an unfinished upload is waiting";
159850
+ if (observed.state === "FAILED") return `Apple could not process the review screenshot: ${observed.errors.join("; ") || "no reason given"}`;
159851
+ return `the review screenshot differs from ${fileName}`;
159852
+ }
159853
+ function screenshotUnmet(planned2, observed) {
159854
+ if (!planned2 || !observed || screenshotMatches(observed.reviewScreenshot, planned2.checksum)) return [];
159855
+ return [describeScreenshotGap(observed.reviewScreenshot, planned2.fileName)];
159856
+ }
159857
+ async function withReviewScreenshot(api2, observed) {
159858
+ if (observed.reviewScreenshotRead) return observed;
159859
+ const reviewScreenshot = await api2.readReviewScreenshot(observed.resourceId);
159860
+ return { ...observed, reviewScreenshotRead: true, ...reviewScreenshot ? { reviewScreenshot } : {} };
159861
+ }
159862
+ function isScreenshotLeftover(held) {
159863
+ return LEFTOVER_SCREENSHOT_STATES.has(held.state);
159864
+ }
159865
+ function screenshotOp(observed, checksum) {
159866
+ return { kind: observed.reviewScreenshot ? "replaceReviewScreenshot" : "uploadReviewScreenshot", checksum };
159867
+ }
159868
+ async function planReviewScreenshot(api2, plan, file2) {
159869
+ if (!file2) return plan;
159870
+ const planned2 = { ...plan, notes: [...plan.notes, ...screenshotNotes(file2)], reviewScreenshot: { fileName: file2.fileName, checksum: file2.checksum } };
159871
+ if (plan.decision === "conflict") return plan.observed ? { ...planned2, observed: await withReviewScreenshot(api2, plan.observed) } : planned2;
159872
+ if (plan.decision === "create") return { ...planned2, ops: [...plan.ops, { kind: "uploadReviewScreenshot", checksum: file2.checksum }] };
159873
+ const observed = await withReviewScreenshot(api2, observationOf(plan));
159874
+ const [gap] = screenshotUnmet(planned2.reviewScreenshot, observed);
159875
+ if (!gap) return { ...planned2, observed };
159876
+ if (isLocked(observed)) {
159877
+ return { ...planned2, observed, decision: "conflict", ops: [], conflicts: [`${plan.productId} is ${observed.state} and this command never changes a live or in-review product: ${gap}`] };
159878
+ }
159879
+ return { ...planned2, observed, decision: "update", ops: [...plan.ops, screenshotOp(observed, file2.checksum)] };
159880
+ }
159881
+ function observationOf(plan) {
159882
+ if (!plan.observed) throw new Error(`internal: the plan for existing product ${plan.productId} has no observation`);
159883
+ return plan.observed;
159884
+ }
159571
159885
  function isLocked(observed) {
159572
159886
  return !EDITABLE_PRODUCT_STATES.has(observed.state) || observed.versions.some((v2) => LOCKED_VERSION_STATES.has(v2.state));
159573
159887
  }
@@ -159672,11 +159986,15 @@ async function planItem(pricing, api2, item, products, today) {
159672
159986
  }
159673
159987
  async function planItemsAt(context, manifest, indices = manifest.items.map((_2, i2) => i2)) {
159674
159988
  const pricing = context.pricing ?? new PriceGrid(context.api);
159989
+ const screenshots = loadReviewScreenshots(manifest, context, indices);
159675
159990
  return withAccessContext(context.identity, manifest.target, async () => {
159676
159991
  await verifyTarget(context.api, manifest, context.identity);
159677
159992
  const products = await discoverProducts(context, manifest);
159678
159993
  const plans = /* @__PURE__ */ new Map();
159679
- for (const i2 of indices) plans.set(i2, await planItem(pricing, context.api, manifest.items[i2], products, isoDay(context.now())));
159994
+ for (const i2 of indices) {
159995
+ const planned2 = await planItem(pricing, context.api, manifest.items[i2], products, isoDay(context.now()));
159996
+ plans.set(i2, await planReviewScreenshot(context.api, planned2, screenshots.get(i2)));
159997
+ }
159680
159998
  return plans;
159681
159999
  });
159682
160000
  }
@@ -159696,6 +160014,7 @@ async function planIap(manifest, context) {
159696
160014
  target: manifest.target,
159697
160015
  manifestDigest: manifestDigest(manifest),
159698
160016
  manifest,
160017
+ ...context.manifestDir ? { manifestDir: context.manifestDir } : {},
159699
160018
  items
159700
160019
  });
159701
160020
  }
@@ -159706,13 +160025,18 @@ function verifyOps(plan, manifest) {
159706
160025
  if (itemPlan2.productId !== item.productId || !Array.isArray(itemPlan2.ops)) throw planError(`plan item ${i2} does not match manifest product ${item.productId}`);
159707
160026
  for (const op of itemPlan2.ops) {
159708
160027
  const locales = item.localizations.map((l2) => l2.locale);
159709
- const knownShape = OP_KINDS.has(op.kind) && Object.keys(op).every((k2) => k2 === "kind" || k2 === "locale" && LOCALE_OPS.has(op.kind) || op.kind === "changePrice" && (k2 === "from" || k2 === "to"));
160028
+ const knownShape = OP_KINDS.has(op.kind) && Object.keys(op).every((k2) => k2 === "kind" || k2 === "locale" && LOCALE_OPS.has(op.kind) || op.kind === "changePrice" && (k2 === "from" || k2 === "to") || k2 === "checksum" && SCREENSHOT_OPS.has(op.kind));
159710
160029
  const localeOk = !LOCALE_OPS.has(op.kind) || locales.includes(op.locale);
159711
160030
  const priceOk = op.kind !== "changePrice" || item.price.rule === "atLeast" && [op.from, op.to].every((v2) => typeof v2 === "string" && /^\d+(\.\d+)?$/.test(v2) && compareAmounts(v2, "0") > 0) && itemPlan2.observed?.priceSchedule !== void 0 && itemPlan2.targetPrice === op.to;
159712
- if (!knownShape || !localeOk || !priceOk) throw planError(`plan item ${item.productId} has an unknown operation ${JSON.stringify(op)}`);
160031
+ const screenshotOk = !SCREENSHOT_OPS.has(op.kind) || screenshotOpOk(op, item, itemPlan2);
160032
+ if (!knownShape || !localeOk || !priceOk || !screenshotOk) throw planError(`plan item ${item.productId} has an unknown operation ${JSON.stringify(op)}`);
159713
160033
  }
159714
160034
  });
159715
160035
  }
160036
+ function screenshotOpOk(op, item, itemPlan2) {
160037
+ const { checksum } = op;
160038
+ return item.reviewScreenshot !== void 0 && typeof checksum === "string" && MD5_HEX.test(checksum) && itemPlan2.reviewScreenshot?.checksum === checksum;
160039
+ }
159716
160040
  function verifyPlan2(doc) {
159717
160041
  const plan = doc;
159718
160042
  if (!plan || typeof plan !== "object" || plan.planVersion !== 1) throw planError("not a himi store iap plan (planVersion 1)");
@@ -159729,8 +160053,9 @@ async function statusIap(manifest, context, catalog3) {
159729
160053
  const plans = await planItems({ ...context, pricing }, manifest);
159730
160054
  const readAt2 = context.now();
159731
160055
  const items = [];
159732
- for (const [i2, p2] of plans.entries()) {
160056
+ for (const [i2, planned2] of plans.entries()) {
159733
160057
  const item = manifest.items[i2];
160058
+ const p2 = planned2.observed ? { ...planned2, observed: await withAccessContext(context.identity, manifest.target, () => withReviewScreenshot(context.api, planned2.observed)) } : planned2;
159734
160059
  const target = p2.observed ? await pricing.targetAmount(item.price, p2.observed.resourceId) : void 0;
159735
160060
  const result = itemResult({
159736
160061
  target: manifest.target,
@@ -159738,7 +160063,7 @@ async function statusIap(manifest, context, catalog3) {
159738
160063
  observed: p2.observed,
159739
160064
  outcome: STATUS_OUTCOMES[p2.decision],
159740
160065
  conflicts: p2.conflicts,
159741
- unmet: p2.observed ? metadataDiffs(item, p2.observed, target) : [],
160066
+ unmet: p2.observed ? [...metadataDiffs(item, p2.observed, target), ...screenshotUnmet(p2.reviewScreenshot, p2.observed)] : [],
159742
160067
  readAt: readAt2
159743
160068
  });
159744
160069
  Object.assign(result.provisioning, await withAccessContext(context.identity, manifest.target, () => checkStatusPrice(item, p2.observed, pricing, catalog3)));
@@ -159746,7 +160071,7 @@ async function statusIap(manifest, context, catalog3) {
159746
160071
  }
159747
160072
  return iapResult({ target: manifest.target, identity: context.identity, items, generatedAt: readAt2 });
159748
160073
  }
159749
- var IapProvisionError, EDITABLE_VERSION_STATE, EDITABLE_PRODUCT_STATES, LOCKED_VERSION_STATES, OP_KINDS, LOCALE_OPS, CONDITIONAL_PRICE_NOTE, STATUS_OUTCOMES, isoDay, exactTarget, planError;
160074
+ var IapProvisionError, EDITABLE_VERSION_STATE, EDITABLE_PRODUCT_STATES, LOCKED_VERSION_STATES, SCREENSHOT_OPS, OP_KINDS, MD5_HEX, LOCALE_OPS, CONDITIONAL_PRICE_NOTE, STATUS_OUTCOMES, isoDay, exactTarget, LEFTOVER_SCREENSHOT_STATES, planError;
159750
160075
  var init_iap_plan = __esm({
159751
160076
  "../store-release/iap-plan.ts"() {
159752
160077
  init_iap_api();
@@ -159755,6 +160080,7 @@ var init_iap_plan = __esm({
159755
160080
  init_iap_pricing();
159756
160081
  init_iap_result();
159757
160082
  init_iap_price_status();
160083
+ init_iap_review_screenshot();
159758
160084
  IapProvisionError = class extends Error {
159759
160085
  constructor(reason, message) {
159760
160086
  super(message);
@@ -159765,12 +160091,15 @@ var init_iap_plan = __esm({
159765
160091
  EDITABLE_VERSION_STATE = "PREPARE_FOR_SUBMISSION";
159766
160092
  EDITABLE_PRODUCT_STATES = /* @__PURE__ */ new Set(["MISSING_METADATA", "READY_TO_SUBMIT", "DEVELOPER_ACTION_NEEDED", "REJECTED"]);
159767
160093
  LOCKED_VERSION_STATES = /* @__PURE__ */ new Set(["READY_FOR_REVIEW", "WAITING_FOR_REVIEW", "IN_REVIEW", "ACCEPTED", "APPROVED"]);
159768
- OP_KINDS = /* @__PURE__ */ new Set(["createProduct", "createVersion", "createLocalization", "updateLocalization", "setPrice", "changePrice", "setAvailability"]);
160094
+ SCREENSHOT_OPS = /* @__PURE__ */ new Set(["uploadReviewScreenshot", "replaceReviewScreenshot"]);
160095
+ OP_KINDS = /* @__PURE__ */ new Set(["createProduct", "createVersion", "createLocalization", "updateLocalization", "setPrice", "changePrice", "setAvailability", ...SCREENSHOT_OPS]);
160096
+ MD5_HEX = /^[0-9a-f]{32}$/;
159769
160097
  LOCALE_OPS = /* @__PURE__ */ new Set(["createLocalization", "updateLocalization"]);
159770
160098
  CONDITIONAL_PRICE_NOTE = "the exact price point can only be looked up after the product exists \u2014 apply stops with a partial result if Apple has no point of exactly the requested amount";
159771
160099
  STATUS_OUTCOMES = { create: "absent", update: "incomplete", reuse: "reused", conflict: "conflict" };
159772
160100
  isoDay = (date) => date.toISOString().slice(0, 10);
159773
160101
  exactTarget = (price) => price.rule === "atLeast" ? void 0 : price.amount;
160102
+ LEFTOVER_SCREENSHOT_STATES = /* @__PURE__ */ new Set(["AWAITING_UPLOAD", "FAILED"]);
159774
160103
  planError = (message) => new IapProvisionError("plan", message);
159775
160104
  }
159776
160105
  });
@@ -159778,6 +160107,7 @@ var init_iap_plan = __esm({
159778
160107
  // ../store-release/iap-apply.ts
159779
160108
  function sameOp(a2, b2) {
159780
160109
  if (a2.kind === "changePrice" && b2.kind === "changePrice") return a2.from === b2.from && a2.to === b2.to;
160110
+ if ("checksum" in a2 || "checksum" in b2) return "checksum" in a2 && "checksum" in b2 && a2.checksum === b2.checksum;
159781
160111
  return a2.kind === b2.kind && ("locale" in a2 ? a2.locale : void 0) === ("locale" in b2 ? b2.locale : void 0);
159782
160112
  }
159783
160113
  function assertSameAccount(planned2, current) {
@@ -159798,9 +160128,19 @@ function driftOf(planned2, live3, today) {
159798
160128
  const scheduleProblem = priceScheduleConflict(live3.observed?.priceSchedule, today);
159799
160129
  if (scheduleProblem) return `${live3.productId}: ${scheduleProblem}`;
159800
160130
  }
160131
+ const [plannedShot, liveShot] = [planned2.reviewScreenshot, live3.reviewScreenshot];
160132
+ if (plannedShot && liveShot && plannedShot.checksum !== liveShot.checksum) return `${live3.productId}: ${liveShot.fileName} changed since the plan was made`;
160133
+ if (replacesUnplannedScreenshot(planned2, live3)) return `${live3.productId}: a review screenshot was added in App Store Connect after the plan \u2014 make a new plan before replacing it`;
159801
160134
  const unplanned = live3.ops.filter((op) => !planned2.ops.some((p2) => sameOp(p2, op)));
159802
160135
  return unplanned.length ? `${live3.productId} now needs ${unplanned.map(describeOp).join(", ")}, which the plan did not list` : void 0;
159803
160136
  }
160137
+ function replacesUnplannedScreenshot(planned2, live3) {
160138
+ if (!live3.ops.some((op) => op.kind === "replaceReviewScreenshot")) return false;
160139
+ const held = live3.observed?.reviewScreenshot;
160140
+ if (!held || isScreenshotLeftover(held)) return false;
160141
+ const seen = planned2.observed?.reviewScreenshot;
160142
+ return !seen || seen.id !== held.id || isScreenshotLeftover(seen);
160143
+ }
159804
160144
  function assertNoDrift(plan, live3, today) {
159805
160145
  const drift = [...live3].map(([i2, current]) => driftOf(plan.items[i2], current, today)).filter((d2) => d2 !== void 0);
159806
160146
  if (!drift.length) return;
@@ -159853,6 +160193,50 @@ async function findLocalization(api2, versionId, locale, matchText) {
159853
160193
  if (!found || matchText && (found.name !== matchText.name || found.description !== matchText.description)) return void 0;
159854
160194
  return found;
159855
160195
  }
160196
+ function plannedScreenshot(item, op, context) {
160197
+ const file2 = readReviewScreenshot(required(item.reviewScreenshot, "the review screenshot path"), context);
160198
+ if (!("checksum" in op) || file2.checksum !== op.checksum) throw new UnresolvedWriteError(`${file2.fileName} changed after the plan was made \u2014 make a new plan`);
160199
+ return file2;
160200
+ }
160201
+ async function reserveScreenshot(api2, resourceId, file2, overValid) {
160202
+ try {
160203
+ return await api2.reserveReviewScreenshot(resourceId, { fileName: file2.fileName, fileSize: file2.bytes.length });
160204
+ } catch (e2) {
160205
+ if (overValid && e2 instanceof AscError && e2.kind === "conflict") throw new UnresolvedWriteError(KEPT_EXISTING_SCREENSHOT);
160206
+ if (!(e2 instanceof AscError) || !AMBIGUOUS_WRITE_KINDS.has(e2.kind)) throw e2;
160207
+ throw new UnresolvedWriteError(`could not confirm the review screenshot reservation (${e2.message}). Make a new plan \u2014 it replaces an unfinished reservation.`);
160208
+ }
160209
+ }
160210
+ async function settledScreenshot(api2, resourceId, committed, sleep) {
160211
+ if (SETTLED_SCREENSHOT_STATES.has(committed.state)) return committed;
160212
+ const read = async () => {
160213
+ const current = await api2.readReviewScreenshot(resourceId);
160214
+ return current && SETTLED_SCREENSHOT_STATES.has(current.state) ? current : void 0;
160215
+ };
160216
+ return await pollFor(read, sleep) ?? committed;
160217
+ }
160218
+ async function uploadScreenshot(context, resourceId, file2) {
160219
+ const { api: api2, sleep } = context;
160220
+ const current = await api2.readReviewScreenshot(resourceId);
160221
+ if (current && screenshotMatches(current, file2.checksum)) return { state: "reconciled", resourceId: current.id };
160222
+ const reservation = await reserveScreenshot(api2, resourceId, file2, current !== void 0 && !isScreenshotLeftover(current));
160223
+ await api2.uploadReviewScreenshotParts(reservation, file2.bytes);
160224
+ const committed = async () => {
160225
+ const screenshot = await api2.readReviewScreenshot(resourceId);
160226
+ return screenshot?.id === reservation.id && screenshot.checksum === file2.checksum ? screenshot : void 0;
160227
+ };
160228
+ const { value, state } = await ensure({ write: () => api2.commitReviewScreenshot(reservation.id, file2.checksum), find: committed }, sleep);
160229
+ const settled = await settledScreenshot(api2, resourceId, value, sleep);
160230
+ if (settled.state === "FAILED") throw new UnresolvedWriteError(`Apple could not process the review screenshot: ${settled.errors.join("; ") || "no reason given"}`);
160231
+ return { state, resourceId: reservation.id };
160232
+ }
160233
+ async function deleteLeftoverScreenshot(context, resourceId) {
160234
+ const { api: api2, sleep } = context;
160235
+ const stale = await api2.readReviewScreenshot(resourceId);
160236
+ if (!stale || !isScreenshotLeftover(stale)) return;
160237
+ const gone = async () => (await api2.readReviewScreenshot(resourceId))?.id !== stale.id ? true : void 0;
160238
+ await ensure({ write: async () => (await api2.deleteReviewScreenshot(stale.id), true), find: gone }, sleep);
160239
+ }
159856
160240
  function operationRunners(context, manifest) {
159857
160241
  const { api: api2, sleep, pricing } = context;
159858
160242
  const appId2 = manifest.target.appleAppId;
@@ -159918,6 +160302,13 @@ function operationRunners(context, manifest) {
159918
160302
  const matches = async () => availabilityMatches(await readObservedAvailability(api2, resourceId), territories) ? true : void 0;
159919
160303
  const { state } = await ensure({ write: async () => (await api2.createAvailability(resourceId, territories), true), find: matches }, sleep);
159920
160304
  return { state };
160305
+ },
160306
+ uploadReviewScreenshot: async (run2, op) => uploadScreenshot(context, required(run2.resourceId, "the product id"), plannedScreenshot(run2.item, op, context)),
160307
+ replaceReviewScreenshot: async (run2, op) => {
160308
+ const resourceId = required(run2.resourceId, "the product id");
160309
+ const file2 = plannedScreenshot(run2.item, op, context);
160310
+ await deleteLeftoverScreenshot(context, resourceId);
160311
+ return uploadScreenshot(context, resourceId, file2);
159921
160312
  }
159922
160313
  };
159923
160314
  }
@@ -159944,7 +160335,8 @@ async function runStep(runner2, run2, op, context, manifest) {
159944
160335
  async function resumeFromApple(run2, remaining, context) {
159945
160336
  const product = await context.api.readProduct(required(run2.resourceId, "the product id"));
159946
160337
  if (!product) return { reason: "the product exists but cannot be read back yet \u2014 rerun apply later" };
159947
- const replanned = await planForProduct(context.api, run2.item, product, context.pricing, context.now().toISOString().slice(0, 10));
160338
+ const file2 = run2.item.reviewScreenshot === void 0 ? void 0 : readReviewScreenshot(run2.item.reviewScreenshot, context);
160339
+ const replanned = await planReviewScreenshot(context.api, await planForProduct(context.api, run2.item, product, context.pricing, context.now().toISOString().slice(0, 10)), file2);
159948
160340
  if (replanned.decision === "conflict") return { reason: `the product already existed: ${replanned.conflicts.join("; ")}` };
159949
160341
  const unplanned = replanned.ops.filter((op) => !remaining.some((r2) => sameOp(r2, op)));
159950
160342
  if (unplanned.length) return { reason: `the product already existed and needs ${unplanned.map(describeOp).join(", ")}, which the plan did not list \u2014 make a new plan` };
@@ -159979,7 +160371,9 @@ async function readBack(run2, context, manifest) {
159979
160371
  if (!run2.resourceId) return {};
159980
160372
  try {
159981
160373
  const product = await context.api.readProduct(run2.resourceId);
159982
- return product ? { observed: await observeProduct(context.api, product, context.now().toISOString().slice(0, 10)) } : { failure: "Apple does not return it yet" };
160374
+ if (!product) return { failure: "Apple does not return it yet" };
160375
+ const observed = await observeProduct(context.api, product, context.now().toISOString().slice(0, 10));
160376
+ return { observed: run2.item.reviewScreenshot === void 0 ? observed : await withReviewScreenshot(context.api, observed) };
159983
160377
  } catch (e2) {
159984
160378
  return { failure: explainFailure(e2, context, manifest) };
159985
160379
  }
@@ -159989,7 +160383,8 @@ async function unmetFor(item, observed, context) {
159989
160383
  }
159990
160384
  async function knownUnmetFor(item, planned2, context) {
159991
160385
  if (!planned2.observed) return [];
159992
- return metadataDiffs(item, planned2.observed, planned2.targetPrice ?? await context.pricing.targetAmount(item.price));
160386
+ const metadata2 = metadataDiffs(item, planned2.observed, planned2.targetPrice ?? await context.pricing.targetAmount(item.price));
160387
+ return [...metadata2, ...screenshotUnmet(planned2.reviewScreenshot, planned2.observed)];
159993
160388
  }
159994
160389
  async function applyItem(item, live3, context, manifest) {
159995
160390
  const base = { target: manifest.target, item, readAt: context.now() };
@@ -160006,7 +160401,7 @@ async function applyItem(item, live3, context, manifest) {
160006
160401
  };
160007
160402
  const steps = await runOps(run2, live3.ops, context, manifest);
160008
160403
  const { observed, failure } = await readBack(run2, context, manifest);
160009
- const unmet = failure ? [`could not read the product back: ${failure}`] : await unmetFor(item, observed, context);
160404
+ const unmet = failure ? [`could not read the product back: ${failure}`] : [...await unmetFor(item, observed, context), ...screenshotUnmet(live3.reviewScreenshot, observed)];
160010
160405
  const outcome = outcomeOf(live3.ops, steps, unmet);
160011
160406
  return itemResult({ ...base, readAt: context.now(), observed, outcome, steps, unmet, appleResourceId: run2.resourceId });
160012
160407
  }
@@ -160024,7 +160419,8 @@ function plannedResult(item, planned2, plan, context, manifest) {
160024
160419
  async function applyIap(planDoc, applyContext) {
160025
160420
  const plan = verifyPlan2(planDoc);
160026
160421
  assertSameAccount(plan.identity, applyContext.identity);
160027
- const context = { ...applyContext, pricing: applyContext.pricing ?? new PriceGrid(applyContext.api) };
160422
+ const manifestDir = plan.manifestDir ?? applyContext.manifestDir;
160423
+ const context = { ...applyContext, ...manifestDir ? { manifestDir } : {}, pricing: applyContext.pricing ?? new PriceGrid(applyContext.api) };
160028
160424
  const manifest = plan.manifest;
160029
160425
  const refresh = plan.items.flatMap((planned2, i2) => needsRefresh(planned2) ? [i2] : []);
160030
160426
  const live3 = await planItemsAt(context, manifest, refresh);
@@ -160047,23 +160443,26 @@ async function applyIap(planDoc, applyContext) {
160047
160443
  }
160048
160444
  return iapResult({ target: manifest.target, identity: context.identity, items, generatedAt: context.now() });
160049
160445
  }
160050
- var DEFERRED_REQUIREMENT, RECONCILE_READS, RECONCILE_BASE_WAIT_MS, AMBIGUOUS_WRITE_KINDS, UnresolvedWriteError, required;
160446
+ var DEFERRED_REQUIREMENT, RECONCILE_READS, RECONCILE_BASE_WAIT_MS, AMBIGUOUS_WRITE_KINDS, SETTLED_SCREENSHOT_STATES, UnresolvedWriteError, required, KEPT_EXISTING_SCREENSHOT;
160051
160447
  var init_iap_apply = __esm({
160052
160448
  "../store-release/iap-apply.ts"() {
160053
160449
  init_iap_client();
160054
160450
  init_iap_plan();
160055
160451
  init_iap_pricing();
160452
+ init_iap_review_screenshot();
160056
160453
  init_iap_result();
160057
160454
  DEFERRED_REQUIREMENT = "deferred by --limit \u2014 rerun apply to continue; nothing was written for this product in this run";
160058
160455
  RECONCILE_READS = 4;
160059
160456
  RECONCILE_BASE_WAIT_MS = 1e3;
160060
160457
  AMBIGUOUS_WRITE_KINDS = /* @__PURE__ */ new Set(["uncertain", "rateLimited", "conflict"]);
160458
+ SETTLED_SCREENSHOT_STATES = /* @__PURE__ */ new Set(["COMPLETE", "FAILED"]);
160061
160459
  UnresolvedWriteError = class extends Error {
160062
160460
  };
160063
160461
  required = (value, what) => {
160064
160462
  if (!value) throw new Error(`internal: ${what} is not known yet`);
160065
160463
  return value;
160066
160464
  };
160465
+ KEPT_EXISTING_SCREENSHOT = "Apple kept the existing review screenshot and refused a second one \u2014 replace it in App Store Connect (a review screenshot can be updated there but not removed)";
160067
160466
  }
160068
160467
  });
160069
160468
 
@@ -160187,11 +160586,11 @@ var init_credential_profile = __esm({
160187
160586
  });
160188
160587
 
160189
160588
  // ../store-release/iap-credentials.ts
160190
- import { createHash as createHash38 } from "node:crypto";
160589
+ import { createHash as createHash39 } from "node:crypto";
160191
160590
  import { existsSync as existsSync73, readFileSync as readFileSync88, realpathSync as realpathSync12 } from "node:fs";
160192
160591
  import { homedir as homedir10 } from "node:os";
160193
160592
  function accountFingerprint(keyId, issuerId) {
160194
- return `sha256:${createHash38("sha256").update(`${issuerId}:${keyId}`).digest("hex").slice(0, 16)}`;
160593
+ return `sha256:${createHash39("sha256").update(`${issuerId}:${keyId}`).digest("hex").slice(0, 16)}`;
160195
160594
  }
160196
160595
  function requireExplicitProfile(profileFlag, target) {
160197
160596
  const profile = profileFlag?.trim();
@@ -160278,7 +160677,7 @@ var init_wix_payments_contract = __esm({
160278
160677
  });
160279
160678
 
160280
160679
  // ../store-release/iap-draft.ts
160281
- import { createHash as createHash39 } from "node:crypto";
160680
+ import { createHash as createHash40 } from "node:crypto";
160282
160681
  function fit(text9, max) {
160283
160682
  const chars = [...text9];
160284
160683
  return chars.length <= max ? text9 : `${chars.slice(0, max - 1).join("").trimEnd()}${ELLIPSIS}`;
@@ -160428,7 +160827,7 @@ var init_iap_draft = __esm({
160428
160827
  TIER_DESCRIPTION = "Unlocks one item in the app";
160429
160828
  ELLIPSIS = "\u2026";
160430
160829
  entityKey = (entityType, entityId) => `${entityType}:${entityId}`;
160431
- sha = (text9) => createHash39("sha256").update(text9).digest("hex");
160830
+ sha = (text9) => createHash40("sha256").update(text9).digest("hex");
160432
160831
  ENTITIES = { "&amp;": "&", "&nbsp;": " ", "&lt;": "<", "&gt;": ">", "&quot;": '"', "&#39;": "'" };
160433
160832
  MAX_SUFFIX = 24;
160434
160833
  ReferenceNames = class {
@@ -160745,7 +161144,7 @@ var init_store_spec = __esm({
160745
161144
 
160746
161145
  // src/iap-config-edit.ts
160747
161146
  import { existsSync as existsSync74, readFileSync as readFileSync90 } from "node:fs";
160748
- import { basename as basename18, join as join75 } from "node:path";
161147
+ import { basename as basename20, join as join75 } from "node:path";
160749
161148
  import ts8 from "typescript";
160750
161149
  function bindPurchasesAppInConfig(source, options) {
160751
161150
  const fileName = options.fileName ?? "config.ts";
@@ -160832,14 +161231,14 @@ function withStoreBundle(dir, options) {
160832
161231
  function previewIapConfigEdit(dir, options) {
160833
161232
  const path2 = configEntry(dir);
160834
161233
  if (!path2) return void 0;
160835
- if (isSymlink2(path2)) return { path: path2, changed: false, applied: [], conflicts: [], instructions: [`${basename18(path2)} is a symlink, so it would not be edited: add the purchases app in the file it points to.`] };
160836
- const { changed, applied, conflicts, instructions } = bindPurchasesAppInConfig(readFileSync90(path2, "utf8"), { ...withStoreBundle(dir, options), fileName: basename18(path2) });
161234
+ if (isSymlink2(path2)) return { path: path2, changed: false, applied: [], conflicts: [], instructions: [`${basename20(path2)} is a symlink, so it would not be edited: add the purchases app in the file it points to.`] };
161235
+ const { changed, applied, conflicts, instructions } = bindPurchasesAppInConfig(readFileSync90(path2, "utf8"), { ...withStoreBundle(dir, options), fileName: basename20(path2) });
160837
161236
  return { path: path2, changed, applied, conflicts, instructions };
160838
161237
  }
160839
161238
  async function applyIapConfigEdit(dir, options, validate4) {
160840
161239
  const path2 = configEntry(dir);
160841
161240
  if (!path2) return void 0;
160842
- const fileName = basename18(path2);
161241
+ const fileName = basename20(path2);
160843
161242
  const refuse7 = (why) => ({ path: path2, changed: false, applied: [], conflicts: [], instructions: [why] });
160844
161243
  if (isSymlink2(path2)) return refuse7(`${fileName} is a symlink, so it was not edited: add the purchases app in the file it points to.`);
160845
161244
  const original = readFileSync90(path2, "utf8");
@@ -161298,6 +161697,281 @@ var init_store_iap_connect = __esm({
161298
161697
  }
161299
161698
  });
161300
161699
 
161700
+ // src/store-iap-screenshots.ts
161701
+ import { dirname as dirname40, join as join76, relative as relative15 } from "node:path";
161702
+ function purchaseScreensFor(item) {
161703
+ const screen = item.wix && PURCHASE_SCREENS[item.wix.entityType];
161704
+ if (!screen || !item.wix) return [];
161705
+ const list = LIST_SCREENS[item.wix.entityType];
161706
+ return [{ screenId: `${screen}_${item.wix.entityId}` }, { screenId: screen, input: { id: item.wix.entityId } }, ...list ? [{ screenId: list }] : []];
161707
+ }
161708
+ function formatApplePrice(amount, currency, locale) {
161709
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(Number(amount));
161710
+ }
161711
+ function bindingHost(target, offers) {
161712
+ const appId2 = target.himiApp;
161713
+ const byEntity = new Map(offers.flatMap((offer) => offer.item.wix ? [[offer.item.wix.entityId, offer]] : []));
161714
+ const product = ({ item, displayPrice }) => ({ id: item.productId, type: item.type, displayName: item.localizations[0]?.name ?? item.referenceName, displayPrice });
161715
+ const answers = {
161716
+ "capability.app_info.get": () => ({ appId: appId2, bundleId: target.bundleId, platform: "ios" }),
161717
+ "capability.iap.appBinding": () => ({ status: "bound", binding: { purchasesAppId: RENDER_PURCHASES_APP_ID, himalayaAppId: appId2, bundleId: target.bundleId, siteId: target.wixSiteId } }),
161718
+ "capability.iap.getProducts": (params) => {
161719
+ const asked = new Set(String(params?.productIds ?? "").split(",").map((id) => id.trim()));
161720
+ return { products: offers.filter((offer) => asked.has(offer.item.productId)).map(product) };
161721
+ },
161722
+ "capability.iap.getUnfinishedTransactions": () => ({ status: "ok", transactions: [] })
161723
+ };
161724
+ const member = { generation: 1, kind: "member", memberId: RENDER_MEMBER_ID, siteId: target.wixSiteId, appId: appId2, ready: true };
161725
+ return {
161726
+ dispatch: (action, params) => answers[action]?.(params),
161727
+ wixCall: (method, path2, body) => {
161728
+ if (method === "GET") return MEMBER_OWN_READS.find((read) => read.path.test(path2))?.answer;
161729
+ if (method !== "POST" || !MAPPINGS_PATH.test(path2)) return void 0;
161730
+ const asked = body?.appProductIds;
161731
+ const ids = Array.isArray(asked) ? asked.filter((id) => typeof id === "string" && byEntity.has(id)) : [];
161732
+ return { mappings: ids.map((id) => {
161733
+ const { item } = byEntity.get(id);
161734
+ return { appProductId: id, storeProductId: item.productId, type: item.type === "consumable" ? "CONSUMABLE" : "NON_CONSUMABLE", active: true };
161735
+ }) };
161736
+ },
161737
+ wixApiSession: { identityBound: true, session: { current: () => member, subscribe: () => () => {
161738
+ } } }
161739
+ };
161740
+ }
161741
+ function offersPurchase(fields) {
161742
+ return PURCHASE_FLAGS.some((flag) => fields[`${flag}Disabled`] === false && fields[`${flag}Hidden`] !== true);
161743
+ }
161744
+ function isItemRow(fields, entityId, price) {
161745
+ const values = Object.values(fields).filter((v2) => typeof v2 === "string");
161746
+ return values.some((v2) => v2.toLowerCase() === entityId.toLowerCase()) && values.some((v2) => visibleText2(v2).includes(price));
161747
+ }
161748
+ function rowOffersPurchase(value, entityId, price) {
161749
+ if (Array.isArray(value)) return value.some((row) => rowOffersPurchase(row, entityId, price));
161750
+ if (!value || typeof value !== "object") return false;
161751
+ const fields = value;
161752
+ if (isItemRow(fields, entityId, price)) return offersPurchase(fields);
161753
+ return Object.values(fields).some((child) => rowOffersPurchase(child, entityId, price));
161754
+ }
161755
+ function purchaseEnabled(state, entityId, price) {
161756
+ return Object.values(state).some((service) => {
161757
+ if (!service || typeof service !== "object") return false;
161758
+ return offersPurchase(service) || Object.values(service).some((child) => rowOffersPurchase(child, entityId, price));
161759
+ });
161760
+ }
161761
+ function priceFor2(item, run2) {
161762
+ const amount = run2.applePrice(item) ?? (item.price.rule === "atLeast" ? void 0 : item.price.amount);
161763
+ if (amount === void 0) {
161764
+ return { skipped: run2.appleRead ? "App Store Connect has no price for it yet \u2014 run himi store iap apply first" : "Apple's price for an atLeast item is only known once App Store Connect is read \u2014 pass --profile" };
161765
+ }
161766
+ return formatApplePrice(amount, item.price.currency, item.localizations[0]?.locale ?? "en-US");
161767
+ }
161768
+ function unknownOnlyIds(run2) {
161769
+ const known = new Set(run2.manifest.items.map((item) => item.productId));
161770
+ return [...run2.only ?? []].filter((id) => !known.has(id)).map((productId) => ({ productId, skipped: "not in the manifest" }));
161771
+ }
161772
+ function select(run2) {
161773
+ return run2.manifest.items.flatMap((item, index) => {
161774
+ if (run2.only && !run2.only.has(item.productId)) return [];
161775
+ const screens = purchaseScreensFor(item);
161776
+ const report3 = { productId: item.productId, ...screens[0] ? { screenId: screens[0].screenId } : {} };
161777
+ const selected = (extra) => [{ index, item, screens, report: { ...report3, ...extra } }];
161778
+ if (!screens.length) return selected({ skipped: "no purchase screen: a price tier or an entity type the templates have no detail screen for" });
161779
+ const locked = run2.appleLocked?.(item);
161780
+ if (locked) return selected({ skipped: `is ${locked} \u2014 a live or in-review product's screenshot is never changed` });
161781
+ if (item.reviewScreenshot && !run2.force) return selected({ skipped: `already names ${item.reviewScreenshot} \u2014 pass --force to replace it` });
161782
+ const price = priceFor2(item, run2);
161783
+ return selected(typeof price === "string" ? { price } : price);
161784
+ });
161785
+ }
161786
+ function offersFor(selected, run2) {
161787
+ const others = run2.manifest.items.flatMap((item) => {
161788
+ if (item === selected.item || item.wix?.entityType !== selected.item.wix?.entityType) return [];
161789
+ const price = priceFor2(item, run2);
161790
+ return typeof price === "string" ? [{ item, displayPrice: price }] : [];
161791
+ });
161792
+ return [{ item: selected.item, displayPrice: selected.report.price }, ...others];
161793
+ }
161794
+ function notAPurchase(rendered, entityId, price) {
161795
+ if (rendered.problems.length) return `the screen reported problems while loading: ${rendered.problems.join("; ")}`;
161796
+ if (!visibleText2(rendered.html).includes(price)) return `did not show the Apple price ${price} \u2014 it is not a purchase screen this command knows, or it did not load`;
161797
+ if (!purchaseEnabled(rendered.state, entityId, price)) return "showed the price but no enabled buy or join action for this item";
161798
+ return void 0;
161799
+ }
161800
+ async function renderPurchaseScreen(selected, run2) {
161801
+ const host = bindingHost(run2.manifest.target, offersFor(selected, run2));
161802
+ const price = selected.report.price;
161803
+ const reasons = [];
161804
+ for (const screen of selected.screens) {
161805
+ let rendered;
161806
+ try {
161807
+ rendered = await run2.renderer.render({ contentDir: run2.contentDir, host, entityId: selected.item.wix.entityId, ...screen });
161808
+ } catch (e2) {
161809
+ if (e2 instanceof MissingScreenError) continue;
161810
+ return { skipped: `could not render ${screen.screenId}: ${e2.message}` };
161811
+ }
161812
+ const reason = notAPurchase(rendered, selected.item.wix.entityId, price);
161813
+ if (!reason) return { screenId: screen.screenId, html: rendered.html };
161814
+ reasons.push(`${screen.screenId} ${reason}`);
161815
+ }
161816
+ if (!reasons.length) return { skipped: `the app has none of these screens: ${selected.screens.map((s2) => s2.screenId).join(", ")}` };
161817
+ return { skipped: reasons.join("; ") };
161818
+ }
161819
+ async function shoot(selected, run2, outDir) {
161820
+ const found = await renderPurchaseScreen(selected, run2);
161821
+ if ("skipped" in found) return { ...selected.report, skipped: found.skipped };
161822
+ const report3 = { ...selected.report, screenId: found.screenId };
161823
+ const path2 = join76(outDir, `${selected.item.productId}.png`);
161824
+ try {
161825
+ run2.writeBytes(path2, await run2.renderer.capture(found.html, run2.contentDir));
161826
+ } catch (e2) {
161827
+ return { ...report3, skipped: `could not save the screenshot: ${e2.message}` };
161828
+ }
161829
+ return { ...report3, screenshot: relative15(dirname40(run2.manifestPath), path2) };
161830
+ }
161831
+ function visibleText2(html) {
161832
+ return html.replace(/&nbsp;|&#160;|&#xa0;/gi, "\xA0").replace(/&amp;/g, "&");
161833
+ }
161834
+ function manifestWithScreenshots(text9, shot) {
161835
+ const doc = JSON.parse(text9);
161836
+ for (const [index, path2] of shot) doc.items[index].reviewScreenshot = path2;
161837
+ return `${JSON.stringify(doc, null, 2)}
161838
+ `;
161839
+ }
161840
+ async function takeReviewScreenshots(run2) {
161841
+ const outDir = run2.outDir ?? join76(dirname40(run2.manifestPath), DEFAULT_OUT_DIR);
161842
+ const items = unknownOnlyIds(run2);
161843
+ const shot = /* @__PURE__ */ new Map();
161844
+ try {
161845
+ for (const selected of select(run2)) {
161846
+ const ready = !selected.report.skipped && !run2.dryRun;
161847
+ const report3 = ready ? await shoot(selected, run2, outDir) : selected.report;
161848
+ if (report3.screenshot) shot.set(selected.index, report3.screenshot);
161849
+ items.push(report3);
161850
+ }
161851
+ } finally {
161852
+ if (shot.size) run2.writeText(run2.manifestPath, manifestWithScreenshots(run2.manifestText, shot));
161853
+ }
161854
+ return { complete: items.every((i2) => !i2.skipped), items };
161855
+ }
161856
+ var MissingScreenError, REVIEW_SCREENSHOT_FRAME, DEFAULT_OUT_DIR, PURCHASE_SCREENS, LIST_SCREENS, RENDER_PURCHASES_APP_ID, RENDER_MEMBER_ID, MAPPINGS_PATH, MEMBER_OWN_READS, PURCHASE_FLAGS;
161857
+ var init_store_iap_screenshots = __esm({
161858
+ "src/store-iap-screenshots.ts"() {
161859
+ MissingScreenError = class extends Error {
161860
+ constructor(screenId) {
161861
+ super(`the app has no screen ${screenId}`);
161862
+ this.screenId = screenId;
161863
+ }
161864
+ };
161865
+ REVIEW_SCREENSHOT_FRAME = { width: 430, height: 932, scale: 3 };
161866
+ DEFAULT_OUT_DIR = "review-screenshots";
161867
+ PURCHASE_SCREENS = { storesProduct: "himi_product", onlineProgram: "himi_program", pricingPlan: "himi_plan" };
161868
+ LIST_SCREENS = { pricingPlan: "himi_plans" };
161869
+ RENDER_PURCHASES_APP_ID = "00000000-0000-4000-8000-00000000a99e";
161870
+ RENDER_MEMBER_ID = "00000000-0000-4000-8000-0000000be4e7";
161871
+ MAPPINGS_PATH = /\/v1\/iap\/mappings$/;
161872
+ MEMBER_OWN_READS = [{ path: /^\/pricing-plans\/v2\/member\/orders(\?|$)/, answer: { orders: [] } }];
161873
+ PURCHASE_FLAGS = ["buy", "join"];
161874
+ }
161875
+ });
161876
+
161877
+ // src/store-iap-screenshot-render.ts
161878
+ import { existsSync as existsSync75, mkdtempSync as mkdtempSync4, readFileSync as readFileSync91, rmSync as rmSync18 } from "node:fs";
161879
+ import { tmpdir as tmpdir5 } from "node:os";
161880
+ import { join as join77 } from "node:path";
161881
+ function renderProblems(render, entityId) {
161882
+ const problems = (render.liveErrors ?? []).map((e2) => `${e2.service}: ${e2.message}`);
161883
+ const ofItem = (call) => call.toLowerCase().includes(entityId.toLowerCase());
161884
+ const failed3 = (render.liveFailed ?? []).filter(ofItem);
161885
+ const attempted = (render.liveCalls ?? []).filter(ofItem).length;
161886
+ if (failed3.length > 0 && attempted <= failed3.length) problems.push(`reading the item failed (${failed3[0]}), so the screen could not show it`);
161887
+ return problems;
161888
+ }
161889
+ function workerBundleDir(result, dir) {
161890
+ if (result.compileErrors.length) {
161891
+ const detail = result.compileErrors.map((e2) => `${e2.bundle}: ${e2.errors.map((x2) => x2.text).join("; ")}`).join(" \xB7 ");
161892
+ throw new Error(`the app's screen code does not compile \u2014 fix it first (himi validate): ${detail}`);
161893
+ }
161894
+ return result.built.length > 0 ? dir : void 0;
161895
+ }
161896
+ function createReviewScreenRenderer() {
161897
+ const bundles = /* @__PURE__ */ new Map();
161898
+ let browser;
161899
+ function workerBundles(contentDir2) {
161900
+ let built = bundles.get(contentDir2);
161901
+ if (!built) {
161902
+ built = (async () => {
161903
+ const { buildContentBundles: buildContentBundles2, bundleOutDir: bundleOutDir2 } = await Promise.resolve().then(() => (init_build(), build_exports));
161904
+ return workerBundleDir(await buildContentBundles2(contentDir2, {}), bundleOutDir2(contentDir2));
161905
+ })();
161906
+ bundles.set(contentDir2, built);
161907
+ }
161908
+ return built;
161909
+ }
161910
+ async function launch() {
161911
+ let chromium;
161912
+ try {
161913
+ ({ chromium } = await import("playwright"));
161914
+ } catch {
161915
+ throw new Error("taking a screenshot needs Playwright's Chromium: run `npx playwright install chromium`");
161916
+ }
161917
+ return chromium.launch();
161918
+ }
161919
+ return {
161920
+ async render({ contentDir: contentDir2, screenId, input, host, entityId }) {
161921
+ const { buildReleaseFromContent: buildReleaseFromContent2 } = await Promise.resolve().then(() => (init_build3(), build_exports2));
161922
+ const tier5Dir = await workerBundles(contentDir2);
161923
+ const out2 = mkdtempSync4(join77(tmpdir5(), "himi-iap-shot-"));
161924
+ try {
161925
+ const outcome = await buildReleaseFromContent2(contentDir2, out2, {
161926
+ ...tier5Dir ? { tier5Dir } : {},
161927
+ collect: { render: { screenId, scheme: "light", png: false, hydrate: true, live: true, dumpState: true, width: REVIEW_SCREENSHOT_FRAME.width, host, ...input ? { input } : {} } }
161928
+ });
161929
+ const render = (outcome.renders ?? [])[0];
161930
+ if (!render) throw new MissingScreenError(screenId);
161931
+ if (!render.renderable || !render.html) throw new Error(render.reason ?? `${screenId} is not an SDUI screen`);
161932
+ return { html: render.html, problems: renderProblems(render, entityId), state: render.serviceState ?? {} };
161933
+ } finally {
161934
+ rmSync18(out2, { recursive: true, force: true });
161935
+ }
161936
+ },
161937
+ async capture(html, contentDir2) {
161938
+ const { pngPageHtml: pngPageHtml2, stabilizePngPage: stabilizePngPage2 } = await Promise.resolve().then(() => (init_render_descriptor(), render_descriptor_exports));
161939
+ const tokensPath = join77(contentDir2, "tokens.json");
161940
+ const tokens2 = existsSync75(tokensPath) ? JSON.parse(readFileSync91(tokensPath, "utf8")) : null;
161941
+ const { width, height, scale } = REVIEW_SCREENSHOT_FRAME;
161942
+ const page = await (await (browser ??= launch())).newPage({ viewport: { width, height }, deviceScaleFactor: scale, colorScheme: "light" });
161943
+ try {
161944
+ await page.setContent(await pngPageHtml2({ html, tokens: tokens2, hasStickyFooter: true }), { waitUntil: "load" });
161945
+ await stabilizePngPage2(page, "light");
161946
+ await page.evaluate(FILL_PAGE_WITH_SCREEN_BACKGROUND);
161947
+ return new Uint8Array(await page.screenshot({ fullPage: false }));
161948
+ } finally {
161949
+ await page.close().catch(() => {
161950
+ });
161951
+ }
161952
+ },
161953
+ async close() {
161954
+ if (browser) await (await browser.catch(() => void 0))?.close().catch(() => {
161955
+ });
161956
+ }
161957
+ };
161958
+ }
161959
+ var FILL_PAGE_WITH_SCREEN_BACKGROUND;
161960
+ var init_store_iap_screenshot_render = __esm({
161961
+ "src/store-iap-screenshot-render.ts"() {
161962
+ init_store_iap_screenshots();
161963
+ FILL_PAGE_WITH_SCREEN_BACKGROUND = `(() => {
161964
+ const root = [...document.body.children].find((el) => el.tagName !== "STYLE");
161965
+ if (!root) return;
161966
+ const style = getComputedStyle(root);
161967
+ for (const el of [document.documentElement, document.body]) {
161968
+ el.style.backgroundColor = style.backgroundColor;
161969
+ el.style.backgroundImage = style.backgroundImage;
161970
+ }
161971
+ })()`;
161972
+ }
161973
+ });
161974
+
161301
161975
  // src/serve-preview.ts
161302
161976
  function parsePreviewTag(value) {
161303
161977
  if (value === void 0 || value === "") return void 0;
@@ -161339,9 +162013,9 @@ __export(store_iap_exports, {
161339
162013
  runStoreIap: () => runStoreIap
161340
162014
  });
161341
162015
  import { randomUUID as randomUUID8 } from "node:crypto";
161342
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync34, readFileSync as readFileSync91, realpathSync as realpathSync13, rmSync as rmSync18, writeFileSync as writeFileSync30 } from "node:fs";
162016
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync34, readFileSync as readFileSync92, realpathSync as realpathSync13, renameSync as renameSync12, rmSync as rmSync19, writeFileSync as writeFileSync30 } from "node:fs";
161343
162017
  import { homedir as homedir11, hostname } from "node:os";
161344
- import { join as join76 } from "node:path";
162018
+ import { dirname as dirname41, join as join78, resolve as resolve57 } from "node:path";
161345
162019
  function scrubDeep(value, scrub) {
161346
162020
  if (typeof value === "string") return scrub(value);
161347
162021
  if (Array.isArray(value)) return value.map((v2) => scrubDeep(v2, scrub));
@@ -161349,7 +162023,7 @@ function scrubDeep(value, scrub) {
161349
162023
  return value;
161350
162024
  }
161351
162025
  function failFrom(error, out2) {
161352
- if (error instanceof IapManifestError) return out2.fail(`${error.label} is not a valid IAP manifest`, { problems: error.problems });
162026
+ if (error instanceof IapManifestError) return out2.fail(`${error.label} is not a valid IAP manifest`, { code: "manifest_invalid", problems: error.problems });
161353
162027
  if (error instanceof IapProvisionError) return out2.fail(error.message, { code: error.reason, reason: error.reason }, error.reason === "drift" ? 1 : 2);
161354
162028
  return out2.fail(error instanceof Error ? error.message : String(error));
161355
162029
  }
@@ -161372,6 +162046,9 @@ function readInput(deps, path2, what) {
161372
162046
  function readManifest2(deps, path2) {
161373
162047
  return parseIapManifest(readInput(deps, path2, "manifest"), path2);
161374
162048
  }
162049
+ function manifestDirOf(manifestPath) {
162050
+ return dirname41(resolve57(manifestPath));
162051
+ }
161375
162052
  function readPlan(deps, path2) {
161376
162053
  const text9 = readInput(deps, path2, "plan");
161377
162054
  try {
@@ -161397,7 +162074,7 @@ function openSession(deps, out2, target, profile) {
161397
162074
  const identity = { profile: creds.profile, team: creds.team, fingerprint: creds.fingerprint };
161398
162075
  const api2 = deps.createApi(creds.key);
161399
162076
  const journal2 = deps.openJournal(target.appleAppId);
161400
- return { identity, api: api2, journal: journal2, planContext: { api: api2, identity, now: deps.now } };
162077
+ return { identity, api: api2, journal: journal2, planContext: { api: api2, identity, now: deps.now, readBytes: deps.readBytes } };
161401
162078
  }
161402
162079
  function printHeader(out2, identity, target) {
161403
162080
  out2.line(` ${pad("account")}profile "${identity.profile}" \xB7 team ${identity.team} \xB7 key ${identity.fingerprint}`);
@@ -161466,6 +162143,7 @@ function printItemResult(out2, item) {
161466
162143
  out2.line(` price drift: Wix ${wix} \xB7 Apple ${apple} \xB7 target ${wouldBe} ${currency} in ${baseTerritory}`);
161467
162144
  }
161468
162145
  for (const step of provisioning.steps.filter((s2) => s2.detail)) out2.line(` ${step.kind}${step.locale ? ` ${step.locale}` : ""} ${step.state}: ${step.detail}`);
162146
+ if (provisioning.reviewScreenshot?.observed) out2.line(` review screenshot: ${provisioning.reviewScreenshot.observed.fileName} ${provisioning.reviewScreenshot.observed.state}`);
161469
162147
  for (const conflict of provisioning.conflicts) out2.line(` conflict: ${conflict}`);
161470
162148
  for (const unmet of provisioning.unmet) out2.line(` unmet: ${unmet}`);
161471
162149
  for (const remaining of provisioning.remainingRequirements) out2.line(` remaining: ${remaining}`);
@@ -161495,7 +162173,7 @@ async function planCommand(flags, deps, out2) {
161495
162173
  const planPath = requireFlag(flags, "out", "plan");
161496
162174
  const manifest = readManifest2(deps, manifestPath);
161497
162175
  const session = openSession(deps, out2, manifest.target, profile);
161498
- const plan = await planIap(manifest, session.planContext);
162176
+ const plan = await planIap(manifest, { ...session.planContext, manifestDir: manifestDirOf(manifestPath) });
161499
162177
  writePlan(deps, out2, planPath, plan);
161500
162178
  const summary2 = plan.items.map((i2) => ({ productId: i2.productId, decision: i2.decision, ops: i2.ops.length, conflicts: i2.conflicts }));
161501
162179
  if (out2.json) out2.print({ ok: true, plan: planPath, items: summary2 });
@@ -161511,7 +162189,7 @@ function createLimit(flags) {
161511
162189
  async function applyWithLock(deps, plan, session, limit) {
161512
162190
  const release2 = deps.acquireLock(plan.target.appleAppId);
161513
162191
  try {
161514
- const context = { api: session.api, identity: session.identity, now: deps.now, sleep: deps.sleep, journal: session.journal };
162192
+ const context = { ...session.planContext, sleep: deps.sleep, journal: session.journal };
161515
162193
  return await applyIap(plan, limit === void 0 ? context : { ...context, createLimit: limit });
161516
162194
  } finally {
161517
162195
  release2();
@@ -161557,7 +162235,7 @@ async function statusCommand(flags, deps, out2) {
161557
162235
  return out2.fail("could not read the current Wix catalog \u2014 check owner authentication and site access; no manifest fallback was used", { ok: false, code: "wix_catalog_unavailable" });
161558
162236
  }
161559
162237
  }
161560
- const result = await statusIap(manifest, session.planContext, catalog3?.items);
162238
+ const result = await statusIap(manifest, { ...session.planContext, manifestDir: manifestDirOf(manifestPath) }, catalog3?.items);
161561
162239
  if (resultPath) writeJson(deps, out2, resultPath, result);
161562
162240
  const code = result.complete ? void 0 : result.items.some((i2) => i2.provisioning.priceCheckIssue) ? "price_check_unavailable" : result.items.some((i2) => i2.provisioning.priceDrift) ? "price_drift" : "status_incomplete";
161563
162241
  if (out2.json) out2.print({ ok: result.complete, ...code ? { code } : {}, result });
@@ -161797,6 +162475,71 @@ async function connectWith(flags, deps, out2) {
161797
162475
  }
161798
162476
  return code ? 1 : 0;
161799
162477
  }
162478
+ async function appleFacts(flags, deps, out2, manifest) {
162479
+ const profile = textFlag(flags, "profile");
162480
+ if (!profile) return /* @__PURE__ */ new Map();
162481
+ const session = openSession(deps, out2, manifest.target, profile);
162482
+ const unscreenshotted = { ...manifest, items: manifest.items.map(({ reviewScreenshot: _shot, ...item }) => item) };
162483
+ const plans = await planItems(session.planContext, unscreenshotted);
162484
+ return new Map(plans.flatMap((plan, i2) => {
162485
+ const observed = plan.observed;
162486
+ if (!observed) return [];
162487
+ const base = observed.price?.baseTerritory === manifest.items[i2].price.baseTerritory && observed.price.customerPrices.length === 1;
162488
+ return [[plan.productId, { ...base ? { price: observed.price.customerPrices[0] } : {}, ...isLocked(observed) ? { locked: observed.state } : {} }]];
162489
+ }));
162490
+ }
162491
+ function printScreenshots(out2, report3, manifestPath, dryRun) {
162492
+ for (const item of report3.items) {
162493
+ if (item.skipped) out2.line(` \u2717 ${item.productId} ${item.skipped}`);
162494
+ else if (dryRun) out2.line(` \xB7 ${item.productId} would render ${item.screenId} at ${item.price}`);
162495
+ else out2.line(` \u2713 ${item.productId} ${item.screenshot} (${item.screenId}, ${item.price})`);
162496
+ }
162497
+ out2.line();
162498
+ if (dryRun) out2.line(" dry run \u2014 nothing was rendered or written.");
162499
+ else if (report3.items.some((i2) => i2.screenshot)) out2.line(` manifest updated: ${manifestPath} \u2014 next: himi store iap plan --manifest ${manifestPath} \u2026 uploads them.`);
162500
+ }
162501
+ async function screenshotsCommand(flags, deps, out2) {
162502
+ const manifestPath = requireFlag(flags, "manifest", "screenshots");
162503
+ const contentDir2 = requireFlag(flags, "content", "screenshots");
162504
+ const manifestText = readInput(deps, manifestPath, "manifest");
162505
+ const manifest = parseIapManifest(manifestText, manifestPath);
162506
+ const facts = await appleFacts(flags, deps, out2, manifest);
162507
+ const renderer = (deps.reviewScreenRenderer ?? createReviewScreenRenderer)();
162508
+ const only = textFlag(flags, "only");
162509
+ const outDir = textFlag(flags, "out-dir");
162510
+ const dryRun = flags["dry-run"] === true;
162511
+ let report3;
162512
+ try {
162513
+ report3 = await takeReviewScreenshots({
162514
+ manifest,
162515
+ manifestPath,
162516
+ manifestText,
162517
+ contentDir: contentDir2,
162518
+ renderer,
162519
+ applePrice: (item) => facts.get(item.productId)?.price,
162520
+ appleLocked: (item) => facts.get(item.productId)?.locked,
162521
+ appleRead: textFlag(flags, "profile") !== void 0,
162522
+ writeBytes: deps.writeBytes ?? writeBinaryFile,
162523
+ writeText: (path2, text9) => deps.writeFileAtomic(path2, text9),
162524
+ ...only ? { only: new Set(only.split(",").map((id) => id.trim()).filter(Boolean)) } : {},
162525
+ ...outDir ? { outDir: resolve57(outDir) } : {},
162526
+ force: flags.force === true,
162527
+ dryRun
162528
+ });
162529
+ } finally {
162530
+ await renderer.close?.();
162531
+ }
162532
+ const code = report3.complete ? void 0 : "screenshots_incomplete";
162533
+ if (out2.json) out2.print({ ok: report3.complete, ...code ? { code } : {}, manifest: manifestPath, items: report3.items });
162534
+ else printScreenshots(out2, report3, manifestPath, dryRun);
162535
+ return report3.complete ? 0 : 1;
162536
+ }
162537
+ function writeBinaryFile(path2, bytes2) {
162538
+ mkdirSync34(dirname41(path2), { recursive: true });
162539
+ const partial = `${path2}.${process.pid}.partial`;
162540
+ writeFileSync30(partial, bytes2);
162541
+ renameSync12(partial, path2);
162542
+ }
161800
162543
  async function runStoreIap(pos, flags, io2, deps) {
161801
162544
  const out2 = new CommandOutput(io2, flags.json === true);
161802
162545
  const sub = pos[2];
@@ -161817,14 +162560,14 @@ function fileJournal(path2) {
161817
162560
  }
161818
162561
  function readLockSummary(path2) {
161819
162562
  try {
161820
- const { pid, host, at: at2 } = JSON.parse(readFileSync91(path2, "utf8"));
162563
+ const { pid, host, at: at2 } = JSON.parse(readFileSync92(path2, "utf8"));
161821
162564
  return `pid ${pid} on ${host} since ${at2}`;
161822
162565
  } catch {
161823
162566
  return "unreadable lock";
161824
162567
  }
161825
162568
  }
161826
162569
  function acquireApplyLock(dir, appleAppId) {
161827
- const path2 = join76(dir, "apply.lock");
162570
+ const path2 = join78(dir, "apply.lock");
161828
162571
  const stamp = JSON.stringify({ pid: process.pid, host: hostname(), at: (/* @__PURE__ */ new Date()).toISOString(), token: randomUUID8() });
161829
162572
  try {
161830
162573
  writeFileSync30(path2, stamp, { flag: "wx", mode: 384 });
@@ -161837,15 +162580,15 @@ function acquireApplyLock(dir, appleAppId) {
161837
162580
  return () => {
161838
162581
  let current = "";
161839
162582
  try {
161840
- current = readFileSync91(path2, "utf8");
162583
+ current = readFileSync92(path2, "utf8");
161841
162584
  } catch {
161842
162585
  return;
161843
162586
  }
161844
- if (current === stamp) rmSync18(path2, { force: true });
162587
+ if (current === stamp) rmSync19(path2, { force: true });
161845
162588
  };
161846
162589
  }
161847
162590
  function stateDir(appleAppId) {
161848
- const dir = join76(homedir11(), ".himalaya", "store-iap", appleAppId);
162591
+ const dir = join78(homedir11(), ".himalaya", "store-iap", appleAppId);
161849
162592
  mkdirSync34(dir, { recursive: true, mode: 448 });
161850
162593
  return dir;
161851
162594
  }
@@ -161861,11 +162604,12 @@ async function confirmOnTerminal(question) {
161861
162604
  }
161862
162605
  function defaultStoreIapDeps() {
161863
162606
  return {
161864
- readFile: (path2) => readFileSync91(path2, "utf8"),
162607
+ readFile: (path2) => readFileSync92(path2, "utf8"),
162608
+ readBytes: (path2) => readFileSync92(path2),
161865
162609
  writeFileAtomic,
161866
162610
  resolveCredentials: ({ profileFlag, target }) => resolveIapCredentials({ profileFlag, target }),
161867
162611
  createApi: (key2) => createIapApi(createAscClient({ key: key2 })),
161868
- openJournal: (appleAppId) => fileJournal(join76(stateDir(appleAppId), "journal.jsonl")),
162612
+ openJournal: (appleAppId) => fileJournal(join78(stateDir(appleAppId), "journal.jsonl")),
161869
162613
  acquireLock: (appleAppId) => acquireApplyLock(stateDir(appleAppId), appleAppId),
161870
162614
  canPrompt: () => process.stdin.isTTY === true,
161871
162615
  wixTransport: (siteId) => ownerTransport(siteId),
@@ -161876,7 +162620,7 @@ function defaultStoreIapDeps() {
161876
162620
  profileTeam: (profile) => resolveStoreCredentials({ app: profile, cfg: {}, profileFlag: profile, env: {} }).team,
161877
162621
  confirm: confirmOnTerminal,
161878
162622
  now: () => /* @__PURE__ */ new Date(),
161879
- sleep: (ms2) => new Promise((resolve63) => setTimeout(resolve63, ms2))
162623
+ sleep: (ms2) => new Promise((resolve65) => setTimeout(resolve65, ms2))
161880
162624
  };
161881
162625
  }
161882
162626
  var STORE_IAP_USAGE, SUMMARY_THRESHOLD, SUMMARY_DETAIL_LIMIT, UsageError, CommandOutput, pad, DECISION_ORDER, OUTCOME_ORDER, COMPLETE, DRAFT_MODES, TERRITORY_CODE, LOCALE_CODE, GRID_UNAVAILABLE_NOTE, KeyError, CredentialsError, writesPlanned, COMMANDS;
@@ -161898,10 +162642,12 @@ var init_store_iap = __esm({
161898
162642
  init_iap_config_edit();
161899
162643
  init_store_iap_catalog();
161900
162644
  init_store_iap_connect();
162645
+ init_store_iap_screenshots();
162646
+ init_store_iap_screenshot_render();
161901
162647
  init_store_iap_purchases();
161902
162648
  init_serve_preview();
161903
162649
  init_wix_owner();
161904
- STORE_IAP_USAGE = "himi store iap draft|plan|apply|status|connect \u2014 draft --site <msid> --profile <name> --apple-app <id> --bundle <id> --base-territory <ISO3> --out <manifest.json> [--territories <a,b>] [--locale <l>] [--mode per-item|tiers] [--merge <manifest.json>] [--report <file>] \xB7 plan --manifest <file> --profile <name> --out <plan.json> \xB7 apply --plan <plan.json> --profile <name> --out <result.json> [--yes] [--limit <n>] \xB7 status --manifest <file> --profile <name> [--out <file>] [--refresh-wix] \xB7 connect --manifest <file> --profile <name> [--iap-key <AuthKey.p8> --iap-key-id <id>] [--content <dir>] [--preview-tag dp-<tag>] [--dry-run] [--yes] [--out <report.json>]";
162650
+ STORE_IAP_USAGE = "himi store iap draft|plan|apply|status|connect|screenshots \u2014 draft --site <msid> --profile <name> --apple-app <id> --bundle <id> --base-territory <ISO3> --out <manifest.json> [--territories <a,b>] [--locale <l>] [--mode per-item|tiers] [--merge <manifest.json>] [--report <file>] \xB7 plan --manifest <file> --profile <name> --out <plan.json> \xB7 apply --plan <plan.json> --profile <name> --out <result.json> [--yes] [--limit <n>] \xB7 status --manifest <file> --profile <name> [--out <file>] [--refresh-wix] \xB7 connect --manifest <file> --profile <name> [--iap-key <AuthKey.p8> --iap-key-id <id>] [--content <dir>] [--preview-tag dp-<tag>] [--dry-run] [--yes] [--out <report.json>] \xB7 screenshots --manifest <file> --content <app dir> [--profile <name>] [--out-dir <dir>] [--only <productId,\u2026>] [--force] [--dry-run]";
161905
162651
  SUMMARY_THRESHOLD = 50;
161906
162652
  SUMMARY_DETAIL_LIMIT = 20;
161907
162653
  UsageError = class extends Error {
@@ -161962,7 +162708,8 @@ var init_store_iap = __esm({
161962
162708
  plan: planCommand,
161963
162709
  apply: applyCommand,
161964
162710
  status: statusCommand,
161965
- connect: connectCommand
162711
+ connect: connectCommand,
162712
+ screenshots: screenshotsCommand
161966
162713
  };
161967
162714
  }
161968
162715
  });
@@ -162337,15 +163084,15 @@ __export(preflight_app_exports, {
162337
163084
  analyzeSubmissionRecord: () => analyzeSubmissionRecord,
162338
163085
  appIconState: () => appIconState,
162339
163086
  isValidAppStoreSize: () => isValidAppStoreSize,
162340
- jpegSize: () => jpegSize,
163087
+ jpegSize: () => jpegSize2,
162341
163088
  playListingAssets: () => playListingAssets,
162342
- pngSize: () => pngSize,
163089
+ pngSize: () => pngSize2,
162343
163090
  preflightApp: () => preflightApp,
162344
163091
  profileAccount: () => profileAccount
162345
163092
  });
162346
- import { readFileSync as readFileSync92, existsSync as existsSync75, readdirSync as readdirSync34, statSync as statSync21 } from "node:fs";
162347
- import { createHash as createHash40 } from "node:crypto";
162348
- import { join as join77 } from "node:path";
163093
+ import { readFileSync as readFileSync93, existsSync as existsSync76, readdirSync as readdirSync34, statSync as statSync21 } from "node:fs";
163094
+ import { createHash as createHash41 } from "node:crypto";
163095
+ import { join as join79 } from "node:path";
162349
163096
  function analyze(projectYml, storeConfig, icon, account) {
162350
163097
  const f2 = [];
162351
163098
  const has = (re2, s2) => re2.test(s2);
@@ -162409,13 +163156,13 @@ function profileAccount(app, storeConfig, opts = {}) {
162409
163156
  }
162410
163157
  }
162411
163158
  async function preflightApp(app, opts = {}) {
162412
- const projectYml = existsSync75(iosProjectYml(app)) ? readFileSync92(iosProjectYml(app), "utf8") : "";
162413
- const storeConfig = existsSync75(storeConfigPath(app)) ? readFileSync92(storeConfigPath(app), "utf8") : "";
163159
+ const projectYml = existsSync76(iosProjectYml(app)) ? readFileSync93(iosProjectYml(app), "utf8") : "";
163160
+ const storeConfig = existsSync76(storeConfigPath(app)) ? readFileSync93(storeConfigPath(app), "utf8") : "";
162414
163161
  if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
162415
163162
  const findings = analyze(
162416
163163
  projectYml,
162417
163164
  storeConfig,
162418
- await appIconState(join77(appDir(app), "ios")),
163165
+ await appIconState(join79(appDir(app), "ios")),
162419
163166
  profileAccount(app, storeConfig, opts)
162420
163167
  );
162421
163168
  findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
@@ -162444,17 +163191,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
162444
163191
  return f2;
162445
163192
  }
162446
163193
  function appLevelMetadataFiles(app, locale = "en-US") {
162447
- const root = join77(storeDir(app), "metadata");
163194
+ const root = join79(storeDir(app), "metadata");
162448
163195
  const out2 = /* @__PURE__ */ new Set();
162449
- if (existsSync75(root)) {
163196
+ if (existsSync76(root)) {
162450
163197
  for (const n2 of readdirSync34(root)) if (n2.endsWith(".txt")) out2.add(n2);
162451
163198
  }
162452
- if (existsSync75(join77(root, locale, "privacy_url.txt"))) out2.add("privacy_url.txt");
163199
+ if (existsSync76(join79(root, locale, "privacy_url.txt"))) out2.add("privacy_url.txt");
162453
163200
  return out2;
162454
163201
  }
162455
163202
  function reviewInfoFiles(app) {
162456
- const dir = join77(storeDir(app), "review_information");
162457
- if (!existsSync75(dir)) return /* @__PURE__ */ new Set();
163203
+ const dir = join79(storeDir(app), "review_information");
163204
+ if (!existsSync76(dir)) return /* @__PURE__ */ new Set();
162458
163205
  return new Set(readdirSync34(dir).filter((n2) => n2.endsWith(".txt")));
162459
163206
  }
162460
163207
  function isValidAppStoreSize(w2, h2) {
@@ -162463,7 +163210,7 @@ function isValidAppStoreSize(w2, h2) {
162463
163210
  function isRequired69(w2, h2) {
162464
163211
  return w2 === 1320 && h2 === 2868 || w2 === 1290 && h2 === 2796 || w2 === 2868 && h2 === 1320 || w2 === 2796 && h2 === 1290;
162465
163212
  }
162466
- function pngSize(buf) {
163213
+ function pngSize2(buf) {
162467
163214
  if (buf.length < 24 || buf.toString("ascii", 12, 16) !== "IHDR") return null;
162468
163215
  return { w: buf.readUInt32BE(16), h: buf.readUInt32BE(20) };
162469
163216
  }
@@ -162488,7 +163235,7 @@ function jpegStructure(bytes2) {
162488
163235
  }
162489
163236
  return null;
162490
163237
  }
162491
- function jpegSize(buf) {
163238
+ function jpegSize2(buf) {
162492
163239
  if (buf.length < 4 || buf[0] !== 255 || buf[1] !== 216) return null;
162493
163240
  let at2 = 2;
162494
163241
  while (at2 + 9 < buf.length) {
@@ -162520,7 +163267,7 @@ function analyzePlayListing(assets) {
162520
163267
  } else {
162521
163268
  const { name, bytes: bytes2 } = assets.featureGraphic;
162522
163269
  const isPng = bytes2.length > 8 && bytes2.toString("ascii", 1, 4) === "PNG";
162523
- const size = isPng ? pngSize(bytes2) : jpegSize(bytes2);
163270
+ const size = isPng ? pngSize2(bytes2) : jpegSize2(bytes2);
162524
163271
  if (!size) {
162525
163272
  f2.push({
162526
163273
  level: "error",
@@ -162564,12 +163311,12 @@ function analyzePlayListing(assets) {
162564
163311
  return f2;
162565
163312
  }
162566
163313
  function playListingAssets(app, locale = "en-US") {
162567
- const dir = join77(storeDir(app), "play", locale, "images");
163314
+ const dir = join79(storeDir(app), "play", locale, "images");
162568
163315
  const read = (names) => {
162569
163316
  for (const name of names) {
162570
- const p2 = join77(dir, name);
163317
+ const p2 = join79(dir, name);
162571
163318
  try {
162572
- if (statSync21(p2).isFile()) return { name, bytes: readFileSync92(p2) };
163319
+ if (statSync21(p2).isFile()) return { name, bytes: readFileSync93(p2) };
162573
163320
  } catch {
162574
163321
  }
162575
163322
  }
@@ -162600,26 +163347,26 @@ function analyzeListing(metaFiles, shots) {
162600
163347
  return f2;
162601
163348
  }
162602
163349
  function metadataFilesPresent(app, locale = "en-US") {
162603
- const dir = join77(storeDir(app), "metadata", locale);
162604
- if (!existsSync75(dir)) return /* @__PURE__ */ new Set();
163350
+ const dir = join79(storeDir(app), "metadata", locale);
163351
+ if (!existsSync76(dir)) return /* @__PURE__ */ new Set();
162605
163352
  return new Set(readdirSync34(dir).filter((n2) => n2.endsWith(".txt")));
162606
163353
  }
162607
163354
  function listScreenshots(app, locale = "en-US") {
162608
163355
  const out2 = [];
162609
- const flat = join77(storeDir(app), "screenshots", locale);
162610
- if (existsSync75(flat)) {
163356
+ const flat = join79(storeDir(app), "screenshots", locale);
163357
+ if (existsSync76(flat)) {
162611
163358
  for (const png of readdirSync34(flat).filter((n2) => n2.endsWith(".png"))) {
162612
- const sz = pngSize(readFileSync92(join77(flat, png)));
163359
+ const sz = pngSize2(readFileSync93(join79(flat, png)));
162613
163360
  if (sz) out2.push({ name: png, w: sz.w, h: sz.h });
162614
163361
  }
162615
163362
  }
162616
- const legacy = join77(storeDir(app), "metadata", locale, "screenshots");
162617
- if (existsSync75(legacy)) {
163363
+ const legacy = join79(storeDir(app), "metadata", locale, "screenshots");
163364
+ if (existsSync76(legacy)) {
162618
163365
  for (const deviceDir of readdirSync34(legacy)) {
162619
- const d2 = join77(legacy, deviceDir);
163366
+ const d2 = join79(legacy, deviceDir);
162620
163367
  if (!statSync21(d2).isDirectory()) continue;
162621
163368
  for (const png of readdirSync34(d2).filter((n2) => n2.endsWith(".png"))) {
162622
- const sz = pngSize(readFileSync92(join77(d2, png)));
163369
+ const sz = pngSize2(readFileSync93(join79(d2, png)));
162623
163370
  if (sz) out2.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
162624
163371
  }
162625
163372
  }
@@ -162627,13 +163374,13 @@ function listScreenshots(app, locale = "en-US") {
162627
163374
  return out2;
162628
163375
  }
162629
163376
  function placeholderHashes2() {
162630
- const templateIos = join77(appDir("_template"), "ios");
162631
- if (!existsSync75(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
163377
+ const templateIos = join79(appDir("_template"), "ios");
163378
+ if (!existsSync76(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
162632
163379
  for (const target of readdirSync34(templateIos)) {
162633
- const p2 = join77(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
163380
+ const p2 = join79(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
162634
163381
  try {
162635
163382
  if (!statSync21(p2).isFile()) continue;
162636
- return [LEGACY_PLACEHOLDER_SHA2562, createHash40("sha256").update(readFileSync92(p2)).digest("hex")];
163383
+ return [LEGACY_PLACEHOLDER_SHA2562, createHash41("sha256").update(readFileSync93(p2)).digest("hex")];
162637
163384
  } catch {
162638
163385
  }
162639
163386
  }
@@ -162664,13 +163411,13 @@ async function pixelIssues(bytes2) {
162664
163411
  }
162665
163412
  }
162666
163413
  async function appIconState(iosDir) {
162667
- if (!existsSync75(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
163414
+ if (!existsSync76(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
162668
163415
  for (const target of readdirSync34(iosDir)) {
162669
- const p2 = join77(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
163416
+ const p2 = join79(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
162670
163417
  try {
162671
163418
  if (!statSync21(p2).isFile()) continue;
162672
- const bytes2 = readFileSync92(p2);
162673
- const hash2 = createHash40("sha256").update(bytes2).digest("hex");
163419
+ const bytes2 = readFileSync93(p2);
163420
+ const hash2 = createHash41("sha256").update(bytes2).digest("hex");
162674
163421
  const pixels = await pixelIssues(bytes2);
162675
163422
  return {
162676
163423
  exists: true,
@@ -162736,7 +163483,7 @@ __export(asc_status_exports, {
162736
163483
  ascStatus: () => ascStatus,
162737
163484
  buildVerdict: () => buildVerdict
162738
163485
  });
162739
- import { readFileSync as readFileSync93 } from "node:fs";
163486
+ import { readFileSync as readFileSync94 } from "node:fs";
162740
163487
  function buildVerdict(builds) {
162741
163488
  if (!builds.length) {
162742
163489
  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).";
@@ -162750,7 +163497,7 @@ function buildVerdict(builds) {
162750
163497
  function client(creds) {
162751
163498
  const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
162752
163499
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
162753
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync93(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
163500
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync94(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
162754
163501
  return async (path2) => {
162755
163502
  const r2 = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
162756
163503
  return { status: r2.status, json: await r2.json().catch(() => ({})) };
@@ -162904,7 +163651,7 @@ var init_connector_token = __esm({
162904
163651
  // ../../core/functions-secrets/src/vault.ts
162905
163652
  import { createCipheriv, createDecipheriv as createDecipheriv2, randomBytes as randomBytes6 } from "node:crypto";
162906
163653
  import { mkdir, readFile as readFile2, rename, writeFile as writeFile2 } from "node:fs/promises";
162907
- import { dirname as dirname40 } from "node:path";
163654
+ import { dirname as dirname42 } from "node:path";
162908
163655
  function createJsonSecretStore(filePath) {
162909
163656
  const read = async () => {
162910
163657
  try {
@@ -162917,7 +163664,7 @@ function createJsonSecretStore(filePath) {
162917
163664
  }
162918
163665
  };
162919
163666
  const write2 = async (records) => {
162920
- await mkdir(dirname40(filePath), { recursive: true });
163667
+ await mkdir(dirname42(filePath), { recursive: true });
162921
163668
  const temporary = `${filePath}.${process.pid}.tmp`;
162922
163669
  await writeFile2(temporary, `${JSON.stringify(records, null, 2)}
162923
163670
  `, { mode: 384 });
@@ -163015,7 +163762,7 @@ __export(secrets_exports, {
163015
163762
  runRemoteSecretsCommand: () => runRemoteSecretsCommand,
163016
163763
  runSecretsCommand: () => runSecretsCommand
163017
163764
  });
163018
- import { readFileSync as readFileSync94 } from "node:fs";
163765
+ import { readFileSync as readFileSync95 } from "node:fs";
163019
163766
  function environment(value) {
163020
163767
  if (value === "preview" || value === "production") return value;
163021
163768
  throw new Error("--environment must be preview or production");
@@ -163046,7 +163793,7 @@ async function runSecretsCommand(operation, flags, io2, options = {}) {
163046
163793
  io2.log(JSON.stringify(await vault.list({ app, environment: env })));
163047
163794
  return 0;
163048
163795
  }
163049
- const value = options.readValue ? options.readValue() : readFileSync94(0, "utf8").replace(/\r?\n$/, "");
163796
+ const value = options.readValue ? options.readValue() : readFileSync95(0, "utf8").replace(/\r?\n$/, "");
163050
163797
  if (operation === "set") await vault.set({ app, environment: env, name, value });
163051
163798
  else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
163052
163799
  else throw new Error(`unknown secrets operation ${operation}`);
@@ -163075,7 +163822,7 @@ async function runRemoteSecretsCommand(operation, flags, io2, options) {
163075
163822
  }
163076
163823
  let body;
163077
163824
  if (operation !== "list") {
163078
- const value = options.readValue ? options.readValue() : readFileSync94(0, "utf8").replace(/\r?\n$/, "");
163825
+ const value = options.readValue ? options.readValue() : readFileSync95(0, "utf8").replace(/\r?\n$/, "");
163079
163826
  body = JSON.stringify({ value });
163080
163827
  }
163081
163828
  const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
@@ -163269,7 +164016,7 @@ var init_site_member = __esm({
163269
164016
  });
163270
164017
 
163271
164018
  // src/notify-ping-all.ts
163272
- import { createHash as createHash41 } from "node:crypto";
164019
+ import { createHash as createHash42 } from "node:crypto";
163273
164020
  async function listApprovedMembers(input) {
163274
164021
  const first = await scanMembers(input);
163275
164022
  const second = await scanMembers(input);
@@ -163323,7 +164070,7 @@ async function scanMembers(input) {
163323
164070
  }
163324
164071
  }
163325
164072
  function campaignRequestId(campaignId, memberId) {
163326
- const bytes2 = createHash41("sha256").update(JSON.stringify(["himi-push-campaign", campaignId, memberId])).digest().subarray(0, 16);
164073
+ const bytes2 = createHash42("sha256").update(JSON.stringify(["himi-push-campaign", campaignId, memberId])).digest().subarray(0, 16);
163327
164074
  bytes2[6] = bytes2[6] & 15 | 80;
163328
164075
  bytes2[8] = bytes2[8] & 63 | 128;
163329
164076
  const hex2 = bytes2.toString("hex");
@@ -163373,7 +164120,7 @@ __export(notify_ping_exports, {
163373
164120
  runNotifyPing: () => runNotifyPing
163374
164121
  });
163375
164122
  import { randomUUID as randomUUID9 } from "node:crypto";
163376
- import { resolve as resolve56 } from "node:path";
164123
+ import { resolve as resolve58 } from "node:path";
163377
164124
  function refuse6(io2, error, hint, exit = 2, extra = {}) {
163378
164125
  io2.error(JSON.stringify({ ok: false, error, ...hint ? { hint } : {}, ...extra }));
163379
164126
  return exit;
@@ -163384,7 +164131,7 @@ async function runNotifyPing(flags, io2, deps = {}) {
163384
164131
  const allMembers = flags["all-members"] === true;
163385
164132
  if (allMembers && text8(flags["member-email"])) return refuse6(io2, "recipient_conflict", "Choose --all-members or --member-email.");
163386
164133
  if (allMembers && flags["dry-run"] !== true && flags.yes !== true) return refuse6(io2, "confirmation_required", "Preview with --dry-run, then add --yes to send to every approved member.");
163387
- const input = mergePushInputs(pushInputsFromContent(resolve56(text8(flags.content) ?? process.cwd())), flags);
164134
+ const input = mergePushInputs(pushInputsFromContent(resolve58(text8(flags.content) ?? process.cwd())), flags);
163388
164135
  const missing = [...input.app ? [] : ["app"], ...input.site ? [] : ["site"], ...REQUIRED_FLAGS.filter((f2) => !(allMembers && f2 === "member-email") && !text8(flags[f2]))];
163389
164136
  if (missing.length) return refuse6(io2, "needs_input", "Name the app and site (or --content), the member's login email, a title and a link.", 2, { missing });
163390
164137
  const requestId2 = text8(flags["request-id"]) ?? (deps.newRequestId ?? randomUUID9)();
@@ -163470,7 +164217,7 @@ async function runAllMembers(args) {
163470
164217
  const result = await sendCampaign({
163471
164218
  recipients,
163472
164219
  campaignId: requestId2,
163473
- wait: deps.wait ?? ((ms2) => new Promise((resolve63) => setTimeout(resolve63, ms2))),
164220
+ wait: deps.wait ?? ((ms2) => new Promise((resolve65) => setTimeout(resolve65, ms2))),
163474
164221
  onProgress: (completed) => {
163475
164222
  if (completed % 10 === 0 || completed === recipients.length) {
163476
164223
  io2.log(JSON.stringify({ ok: true, state: "progress", campaignId: requestId2, completed, recipients: recipients.length }));
@@ -163573,15 +164320,15 @@ __export(notify_exports, {
163573
164320
  runNotify: () => runNotify,
163574
164321
  saveAdminSession: () => saveAdminSession
163575
164322
  });
163576
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync35, readFileSync as readFileSync95, writeFileSync as writeFileSync31 } from "node:fs";
164323
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync35, readFileSync as readFileSync96, writeFileSync as writeFileSync31 } from "node:fs";
163577
164324
  import { homedir as homedir12 } from "node:os";
163578
- import { dirname as dirname41, join as join78 } from "node:path";
164325
+ import { dirname as dirname43, join as join80 } from "node:path";
163579
164326
  function defaultSessionsPath() {
163580
- return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join78(homedir12(), ".himalaya", "admin-sessions.json");
164327
+ return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join80(homedir12(), ".himalaya", "admin-sessions.json");
163581
164328
  }
163582
164329
  function loadSessionsFile(path2 = defaultSessionsPath()) {
163583
164330
  try {
163584
- return JSON.parse(readFileSync95(path2, "utf8"));
164331
+ return JSON.parse(readFileSync96(path2, "utf8"));
163585
164332
  } catch {
163586
164333
  return {};
163587
164334
  }
@@ -163589,10 +164336,10 @@ function loadSessionsFile(path2 = defaultSessionsPath()) {
163589
164336
  function saveAdminSession(adminUrl, session, path2 = defaultSessionsPath()) {
163590
164337
  const file2 = loadSessionsFile(path2);
163591
164338
  file2.sessions = { ...file2.sessions, [adminUrl]: session };
163592
- mkdirSync35(dirname41(path2), { recursive: true, mode: 448 });
164339
+ mkdirSync35(dirname43(path2), { recursive: true, mode: 448 });
163593
164340
  writeFileSync31(path2, JSON.stringify(file2, null, 2) + "\n", { mode: 384 });
163594
164341
  try {
163595
- chmodSync3(dirname41(path2), 448);
164342
+ chmodSync3(dirname43(path2), 448);
163596
164343
  chmodSync3(path2, 384);
163597
164344
  } catch {
163598
164345
  }
@@ -163958,20 +164705,20 @@ __export(base44_auth_exports, {
163958
164705
  usableBase44Auth: () => usableBase44Auth,
163959
164706
  writeBase44Session: () => writeBase44Session
163960
164707
  });
163961
- import { chmodSync as chmodSync4, existsSync as existsSync76, mkdirSync as mkdirSync36, readFileSync as readFileSync96, rmSync as rmSync19, writeFileSync as writeFileSync32 } from "node:fs";
164708
+ import { chmodSync as chmodSync4, existsSync as existsSync77, mkdirSync as mkdirSync36, readFileSync as readFileSync97, rmSync as rmSync20, writeFileSync as writeFileSync32 } from "node:fs";
163962
164709
  import { homedir as homedir13 } from "node:os";
163963
- import { dirname as dirname42, join as join79 } from "node:path";
164710
+ import { dirname as dirname44, join as join81 } from "node:path";
163964
164711
  function base44ApiBase(env = process.env) {
163965
164712
  return (env.BASE44_API_URL?.trim() || "https://app.base44.com").replace(/\/+$/, "");
163966
164713
  }
163967
164714
  function base44SessionPath(home = homedir13()) {
163968
- return join79(home, ".himi", "base44", "session.json");
164715
+ return join81(home, ".himi", "base44", "session.json");
163969
164716
  }
163970
164717
  function readBase44Session(home) {
163971
164718
  const p2 = base44SessionPath(home);
163972
- if (!existsSync76(p2)) return void 0;
164719
+ if (!existsSync77(p2)) return void 0;
163973
164720
  try {
163974
- const s2 = JSON.parse(readFileSync96(p2, "utf8"));
164721
+ const s2 = JSON.parse(readFileSync97(p2, "utf8"));
163975
164722
  return typeof s2.accessToken === "string" && s2.accessToken ? s2 : void 0;
163976
164723
  } catch {
163977
164724
  return void 0;
@@ -163979,7 +164726,7 @@ function readBase44Session(home) {
163979
164726
  }
163980
164727
  function writeBase44Session(session, home) {
163981
164728
  const p2 = base44SessionPath(home);
163982
- mkdirSync36(dirname42(p2), { recursive: true, mode: 448 });
164729
+ mkdirSync36(dirname44(p2), { recursive: true, mode: 448 });
163983
164730
  writeFileSync32(p2, `${JSON.stringify(session, null, 2)}
163984
164731
  `, { mode: 384 });
163985
164732
  chmodSync4(p2, 384);
@@ -163987,8 +164734,8 @@ function writeBase44Session(session, home) {
163987
164734
  }
163988
164735
  function deleteBase44Session(home) {
163989
164736
  const p2 = base44SessionPath(home);
163990
- if (!existsSync76(p2)) return false;
163991
- rmSync19(p2, { force: true });
164737
+ if (!existsSync77(p2)) return false;
164738
+ rmSync20(p2, { force: true });
163992
164739
  return true;
163993
164740
  }
163994
164741
  function jwtClaims(token) {
@@ -164082,9 +164829,9 @@ async function base44DeviceLogin(opts) {
164082
164829
  throw new Error("the Base44 sign-in code expired before it was approved \u2014 run `himi base44 login` again");
164083
164830
  }
164084
164831
  function importBase44CliSession(home = homedir13(), env = process.env) {
164085
- const src = join79(home, ".base44", "auth", "auth.json");
164086
- if (!existsSync76(src)) throw new Error(`no Base44 CLI session at ${src} \u2014 run \`npx base44 login\` first, or use \`himi base44 login\``);
164087
- const a2 = JSON.parse(readFileSync96(src, "utf8"));
164832
+ const src = join81(home, ".base44", "auth", "auth.json");
164833
+ if (!existsSync77(src)) throw new Error(`no Base44 CLI session at ${src} \u2014 run \`npx base44 login\` first, or use \`himi base44 login\``);
164834
+ const a2 = JSON.parse(readFileSync97(src, "utf8"));
164088
164835
  if (typeof a2.accessToken !== "string" || !a2.accessToken) throw new Error(`${src} holds no access token`);
164089
164836
  const session = {
164090
164837
  accessToken: a2.accessToken,
@@ -164255,10 +165002,10 @@ function assertPublicSiteUrl(raw) {
164255
165002
  if (refusal) throw new Error(refusal);
164256
165003
  }
164257
165004
  function resolveAll(hostname3) {
164258
- return new Promise((resolve63, reject) => {
165005
+ return new Promise((resolve65, reject) => {
164259
165006
  dnsLookup(hostname3, { all: true, verbatim: true }, (err, addresses) => {
164260
165007
  if (err) reject(err);
164261
- else resolve63(addresses);
165008
+ else resolve65(addresses);
164262
165009
  });
164263
165010
  });
164264
165011
  }
@@ -164266,13 +165013,13 @@ function withAbort(start, signal, what) {
164266
165013
  if (signal?.aborted) return Promise.reject(new Error(`${what} aborted`));
164267
165014
  const work = start();
164268
165015
  if (!signal) return work;
164269
- return new Promise((resolve63, reject) => {
165016
+ return new Promise((resolve65, reject) => {
164270
165017
  const onAbort = () => reject(new Error(`${what} aborted`));
164271
165018
  signal.addEventListener("abort", onAbort, { once: true });
164272
- work.then(resolve63, reject).finally(() => signal.removeEventListener("abort", onAbort));
165019
+ work.then(resolve65, reject).finally(() => signal.removeEventListener("abort", onAbort));
164273
165020
  });
164274
165021
  }
164275
- async function pinAddress(url, resolve63 = resolveAll, signal) {
165022
+ async function pinAddress(url, resolve65 = resolveAll, signal) {
164276
165023
  const host = url.hostname.replace(/^\[|\]$/g, "");
164277
165024
  if (ipv4Octets(host)) {
164278
165025
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
@@ -164282,7 +165029,7 @@ async function pinAddress(url, resolve63 = resolveAll, signal) {
164282
165029
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
164283
165030
  return { address: host, family: 6 };
164284
165031
  }
164285
- const addresses = await withAbort(() => resolve63(host), signal, `${host} lookup`);
165032
+ const addresses = await withAbort(() => resolve65(host), signal, `${host} lookup`);
164286
165033
  if (!addresses.length) throw new Error(`${host} resolved to no address`);
164287
165034
  const blocked = addresses.filter((a2) => isBlockedAddress(a2.address)).map((a2) => a2.address);
164288
165035
  if (blocked.length) throw new Error(`${host} resolves to a blocked address (${blocked.join(", ")})`);
@@ -164322,7 +165069,7 @@ function copyIncomingHeaders(headers2) {
164322
165069
  return out2;
164323
165070
  }
164324
165071
  function requestOnce(url, pinned, init) {
164325
- return new Promise((resolve63, reject) => {
165072
+ return new Promise((resolve65, reject) => {
164326
165073
  const headers2 = { host: url.host, "accept-encoding": "identity" };
164327
165074
  new Headers(init.headers ?? {}).forEach((value, key2) => {
164328
165075
  if (key2.toLowerCase() !== "host") headers2[key2] = value;
@@ -164352,7 +165099,7 @@ function requestOnce(url, pinned, init) {
164352
165099
  reject(err);
164353
165100
  return;
164354
165101
  }
164355
- resolve63(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out2 }));
165102
+ resolve65(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out2 }));
164356
165103
  }
164357
165104
  );
164358
165105
  req.on("error", reject);
@@ -166324,7 +167071,7 @@ var init_brand_font = __esm({
166324
167071
 
166325
167072
  // src/site-analyze/write-artifacts.ts
166326
167073
  import { mkdirSync as mkdirSync37, writeFileSync as writeFileSync33 } from "node:fs";
166327
- import { join as join80 } from "node:path";
167074
+ import { join as join82 } from "node:path";
166328
167075
  function attachVeloSources(book, sources, put) {
166329
167076
  const byPath = new Map((sources ?? []).map((s2) => [s2.path, s2.text]));
166330
167077
  for (const f2 of book.velo.files) {
@@ -166479,12 +167226,12 @@ async function downloadMedia(book, fetchImpl, put) {
166479
167226
  }
166480
167227
  async function writeBusinessBook(result, opts) {
166481
167228
  const out2 = opts.outDir;
166482
- mkdirSync37(join80(out2, "evidence/pages"), { recursive: true });
166483
- mkdirSync37(join80(out2, "media/catalog"), { recursive: true });
167229
+ mkdirSync37(join82(out2, "evidence/pages"), { recursive: true });
167230
+ mkdirSync37(join82(out2, "media/catalog"), { recursive: true });
166484
167231
  const files = [];
166485
167232
  const put = (rel, body) => {
166486
- const p2 = join80(out2, rel);
166487
- mkdirSync37(join80(p2, ".."), { recursive: true });
167233
+ const p2 = join82(out2, rel);
167234
+ mkdirSync37(join82(p2, ".."), { recursive: true });
166488
167235
  writeFileSync33(p2, body);
166489
167236
  files.push(rel);
166490
167237
  };
@@ -167388,11 +168135,11 @@ var init_analyze = __esm({
167388
168135
  });
167389
168136
 
167390
168137
  // src/base44-analyze/write-artifacts.ts
167391
- import { existsSync as existsSync77, mkdirSync as mkdirSync38, readFileSync as readFileSync97, rmSync as rmSync20, writeFileSync as writeFileSync34 } from "node:fs";
167392
- import { dirname as dirname43, join as join81, resolve as resolve57, sep as sep19 } from "node:path";
168138
+ import { existsSync as existsSync78, mkdirSync as mkdirSync38, readFileSync as readFileSync98, rmSync as rmSync21, writeFileSync as writeFileSync34 } from "node:fs";
168139
+ import { dirname as dirname45, join as join83, resolve as resolve59, sep as sep19 } from "node:path";
167393
168140
  function isBookFolder(dir) {
167394
168141
  try {
167395
- return JSON.parse(readFileSync97(join81(dir, "book.json"), "utf8")).kind === "base44-app-book";
168142
+ return JSON.parse(readFileSync98(join83(dir, "book.json"), "utf8")).kind === "base44-app-book";
167396
168143
  } catch {
167397
168144
  return false;
167398
168145
  }
@@ -167466,7 +168213,7 @@ function renderBookMd(book) {
167466
168213
  return L2.join("\n");
167467
168214
  }
167468
168215
  function writeBase44Book(result, outDir, opts = {}) {
167469
- const out2 = resolve57(outDir);
168216
+ const out2 = resolve59(outDir);
167470
168217
  const book = result.book;
167471
168218
  const files = [];
167472
168219
  const shots = (opts.screenshots ?? []).filter((s2) => safeRel(s2.filename) && !s2.filename.includes("/"));
@@ -167479,26 +168226,26 @@ function writeBase44Book(result, outDir, opts = {}) {
167479
168226
  const md = renderBookMd(book);
167480
168227
  assertNoSecrets(json6);
167481
168228
  assertNoSecrets(md);
167482
- const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) => existsSync77(join81(out2, n2)));
168229
+ const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) => existsSync78(join83(out2, n2)));
167483
168230
  if (owned.length) {
167484
168231
  if (!isBookFolder(out2)) throw new Error(`refusing to write the app book into ${out2}: it already has ${owned.join(", ")} that ${owned.length === 1 ? "is" : "are"} not from an app book \u2014 pick an empty --out`);
167485
- for (const d2 of ["source", "screenshots"]) rmSync20(join81(out2, d2), { recursive: true, force: true });
168232
+ for (const d2 of ["source", "screenshots"]) rmSync21(join83(out2, d2), { recursive: true, force: true });
167486
168233
  }
167487
168234
  mkdirSync38(out2, { recursive: true });
167488
- writeFileSync34(join81(out2, "book.json"), json6);
167489
- writeFileSync34(join81(out2, "BOOK.md"), md);
168235
+ writeFileSync34(join83(out2, "book.json"), json6);
168236
+ writeFileSync34(join83(out2, "BOOK.md"), md);
167490
168237
  files.push("book.json", "BOOK.md");
167491
168238
  for (const s2 of shots) {
167492
- mkdirSync38(join81(out2, "screenshots"), { recursive: true });
167493
- writeFileSync34(join81(out2, "screenshots", s2.filename), s2.bytes);
168239
+ mkdirSync38(join83(out2, "screenshots"), { recursive: true });
168240
+ writeFileSync34(join83(out2, "screenshots", s2.filename), s2.bytes);
167494
168241
  files.push(`screenshots/${s2.filename}`);
167495
168242
  }
167496
- const sourceRoot = join81(out2, "source");
168243
+ const sourceRoot = join83(out2, "source");
167497
168244
  for (const f2 of result.sourceFiles) {
167498
168245
  if (!safeRel(f2.path)) continue;
167499
- const dest = join81(sourceRoot, ...f2.path.split("/"));
168246
+ const dest = join83(sourceRoot, ...f2.path.split("/"));
167500
168247
  if (!dest.startsWith(sourceRoot + sep19)) continue;
167501
- mkdirSync38(dirname43(dest), { recursive: true });
168248
+ mkdirSync38(dirname45(dest), { recursive: true });
167502
168249
  writeFileSync34(dest, f2.bytes);
167503
168250
  }
167504
168251
  if (result.sourceFiles.length) files.push(`source/ (${result.sourceFiles.length} files)`);
@@ -168369,10 +169116,10 @@ function permuteDomain(domain, allowSpecialUseDomain) {
168369
169116
  }
168370
169117
  function createPromiseCallback(cb) {
168371
169118
  let callback;
168372
- let resolve63;
169119
+ let resolve65;
168373
169120
  let reject;
168374
169121
  const promise = new Promise((_resolve, _reject) => {
168375
- resolve63 = _resolve;
169122
+ resolve65 = _resolve;
168376
169123
  reject = _reject;
168377
169124
  });
168378
169125
  if (typeof cb === "function") {
@@ -168388,7 +169135,7 @@ function createPromiseCallback(cb) {
168388
169135
  callback = (err, result) => {
168389
169136
  try {
168390
169137
  if (err) reject(err);
168391
- else resolve63(result);
169138
+ else resolve65(result);
168392
169139
  } catch (e2) {
168393
169140
  reject(e2 instanceof Error ? e2 : new Error());
168394
169141
  }
@@ -171040,9 +171787,9 @@ __export(cli_exports, {
171040
171787
  systemTar: () => systemTar
171041
171788
  });
171042
171789
  import { execFile } from "node:child_process";
171043
- import { mkdirSync as mkdirSync39, mkdtempSync as mkdtempSync4, rmSync as rmSync21, writeFileSync as writeFileSync35 } from "node:fs";
171044
- import { tmpdir as tmpdir5 } from "node:os";
171045
- import { join as join82, resolve as resolve58 } from "node:path";
171790
+ import { mkdirSync as mkdirSync39, mkdtempSync as mkdtempSync5, rmSync as rmSync22, writeFileSync as writeFileSync35 } from "node:fs";
171791
+ import { tmpdir as tmpdir6 } from "node:os";
171792
+ import { join as join84, resolve as resolve60 } from "node:path";
171046
171793
  import { promisify } from "node:util";
171047
171794
  function projectDownloader(apiFetch, apiBase, token, extract = systemTar) {
171048
171795
  return async (appId2) => {
@@ -171055,11 +171802,11 @@ function projectDownloader(apiFetch, apiBase, token, extract = systemTar) {
171055
171802
  }
171056
171803
  const bytes2 = await readCapped(res, MAX_TARBALL_BYTES);
171057
171804
  if (!bytes2) throw new Error(`project download is over the ${MAX_TARBALL_BYTES}-byte cap`);
171058
- const root = mkdtempSync4(join82(tmpdir5(), "himi-base44-"));
171059
- const cleanup = () => rmSync21(root, { recursive: true, force: true });
171805
+ const root = mkdtempSync5(join84(tmpdir6(), "himi-base44-"));
171806
+ const cleanup = () => rmSync22(root, { recursive: true, force: true });
171060
171807
  try {
171061
- const archive = join82(root, "project.tar");
171062
- const dir = join82(root, "project");
171808
+ const archive = join84(root, "project.tar");
171809
+ const dir = join84(root, "project");
171063
171810
  writeFileSync35(archive, bytes2);
171064
171811
  mkdirSync39(dir);
171065
171812
  await extract(archive, dir);
@@ -171097,7 +171844,7 @@ async function runBase44Analyze(opts) {
171097
171844
  now: opts.now ?? (() => /* @__PURE__ */ new Date())
171098
171845
  };
171099
171846
  const result = await analyzeBase44({ url: opts.url, appId: opts.appId, sample: opts.sample }, ports);
171100
- const written = writeBase44Book(result, resolve58(opts.cwd ?? process.cwd(), opts.outDir ?? ".himi/base44-book"), { screenshots });
171847
+ const written = writeBase44Book(result, resolve60(opts.cwd ?? process.cwd(), opts.outDir ?? ".himi/base44-book"), { screenshots });
171101
171848
  return { ok: true, out: written.outDir, files: written.files, mode: result.book.mode, gaps: result.book.gaps, book: result.book };
171102
171849
  }
171103
171850
  var MAX_TARBALL_BYTES, systemTar;
@@ -171131,7 +171878,7 @@ var init_errors2 = __esm({
171131
171878
  });
171132
171879
 
171133
171880
  // src/one-app/collect.ts
171134
- import { createHash as createHash42 } from "node:crypto";
171881
+ import { createHash as createHash43 } from "node:crypto";
171135
171882
  function isObject2(value) {
171136
171883
  return value !== null && typeof value === "object" && !Array.isArray(value);
171137
171884
  }
@@ -171203,7 +171950,7 @@ function semanticFingerprint(structure) {
171203
171950
  }
171204
171951
  return JSON.stringify(value);
171205
171952
  };
171206
- return createHash42("sha256").update(canonical4(structure, true)).digest("hex");
171953
+ return createHash43("sha256").update(canonical4(structure, true)).digest("hex");
171207
171954
  }
171208
171955
  async function collectOneApp(input, deps = {}) {
171209
171956
  if (typeof input.metaSiteId !== "string" || !UUID.test(input.metaSiteId)) {
@@ -171616,9 +172363,9 @@ __export(cli_exports2, {
171616
172363
  ONE_APP_WORKFLOW: () => ONE_APP_WORKFLOW,
171617
172364
  runOneAppCommand: () => runOneAppCommand
171618
172365
  });
171619
- import { closeSync as closeSync7, constants as constants4, lstatSync as lstatSync21, mkdirSync as mkdirSync40, openSync as openSync6, readFileSync as readFileSync98, realpathSync as realpathSync14, writeFileSync as writeFileSync36 } from "node:fs";
171620
- import { createHash as createHash43 } from "node:crypto";
171621
- import { dirname as dirname44, join as join83, parse as parse3, resolve as resolve59 } from "node:path";
172366
+ import { closeSync as closeSync7, constants as constants4, lstatSync as lstatSync21, mkdirSync as mkdirSync40, openSync as openSync6, readFileSync as readFileSync99, realpathSync as realpathSync14, writeFileSync as writeFileSync36 } from "node:fs";
172367
+ import { createHash as createHash44 } from "node:crypto";
172368
+ import { dirname as dirname46, join as join85, parse as parse3, resolve as resolve61 } from "node:path";
171622
172369
  function readOptions(argv, cwd, commandIncluded) {
171623
172370
  let cursor = 0;
171624
172371
  const skipGlobalSwitches = () => {
@@ -171659,10 +172406,10 @@ function readOptions(argv, cwd, commandIncluded) {
171659
172406
  let prompt = flags.prompt ?? "";
171660
172407
  if (flags["prompt-file"] !== void 0) {
171661
172408
  try {
171662
- const file2 = resolve59(cwd, flags["prompt-file"]);
172409
+ const file2 = resolve61(cwd, flags["prompt-file"]);
171663
172410
  const stat2 = lstatSync21(file2);
171664
172411
  if (!stat2.isFile() || stat2.size > MAX_PROMPT_BYTES) throw new Error("invalid prompt file");
171665
- prompt = readFileSync98(file2, "utf8");
172412
+ prompt = readFileSync99(file2, "utf8");
171666
172413
  } catch {
171667
172414
  throw new OneAppError("invalid_prompt", "Use a readable text file of at most 64 KiB for --prompt-file.");
171668
172415
  }
@@ -171677,8 +172424,8 @@ function readOptions(argv, cwd, commandIncluded) {
171677
172424
  if (flags.dir !== void 0 && !flags.dir.trim()) {
171678
172425
  throw new OneAppError("invalid_output_path", "Pass a parent directory with --dir.");
171679
172426
  }
171680
- const parentDir = resolve59(cwd, flags.dir ?? ".");
171681
- const workspace = join83(parentDir, name);
172427
+ const parentDir = resolve61(cwd, flags.dir ?? ".");
172428
+ const workspace = join85(parentDir, name);
171682
172429
  assertSafeParents(parentDir);
171683
172430
  if (pathExists(workspace)) throw new OneAppError("output_exists", "The destination already exists. Choose a new --name or --dir.");
171684
172431
  return { metaSiteId, appInstance, prompt, name, parentDir, workspace, target };
@@ -171707,7 +172454,7 @@ function assertSafeParents(path2) {
171707
172454
  throw new OneAppError("invalid_output_path", "The output parent cannot be inspected.");
171708
172455
  }
171709
172456
  }
171710
- current = dirname44(current);
172457
+ current = dirname46(current);
171711
172458
  }
171712
172459
  }
171713
172460
  function writePrivate(path2, contents, append) {
@@ -171735,7 +172482,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
171735
172482
  const hashes = {};
171736
172483
  const diskWrite = deps.writeFile ?? writePrivate;
171737
172484
  const put = (name, content) => {
171738
- const path2 = join83(evidenceDir, name);
172485
+ const path2 = join85(evidenceDir, name);
171739
172486
  try {
171740
172487
  assertSafeParents(evidenceDir);
171741
172488
  diskWrite(path2, content, false);
@@ -171743,7 +172490,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
171743
172490
  throw new OneAppError("artifact_write_failed", "Could not save the migration evidence. Existing files were kept.", { stage });
171744
172491
  }
171745
172492
  artifacts[name] = path2;
171746
- hashes[name] = createHash43("sha256").update(content).digest("hex");
172493
+ hashes[name] = createHash44("sha256").update(content).digest("hex");
171747
172494
  return path2;
171748
172495
  };
171749
172496
  const progress = (nextStage) => {
@@ -171751,7 +172498,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
171751
172498
  if (!evidenceDir) return;
171752
172499
  try {
171753
172500
  assertSafeParents(evidenceDir);
171754
- diskWrite(join83(evidenceDir, "progress.jsonl"), JSON.stringify({ stage, at: now() }) + "\n", true);
172501
+ diskWrite(join85(evidenceDir, "progress.jsonl"), JSON.stringify({ stage, at: now() }) + "\n", true);
171755
172502
  } catch {
171756
172503
  throw new OneAppError("artifact_write_failed", "Could not record migration progress. Existing files were kept.", { stage });
171757
172504
  }
@@ -171767,7 +172514,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
171767
172514
  assertSafeParents(options.parentDir);
171768
172515
  mkdirSync40(options.workspace, { mode: 448 });
171769
172516
  if (realpathSync14(options.workspace) !== options.workspace) throw new Error("destination changed");
171770
- evidenceDir = join83(options.workspace, ".himi", "one-app");
172517
+ evidenceDir = join85(options.workspace, ".himi", "one-app");
171771
172518
  mkdirSync40(evidenceDir, { recursive: true, mode: 448 });
171772
172519
  } catch (error) {
171773
172520
  if (error.code === "EEXIST") {
@@ -173583,15 +174330,15 @@ var init_customer_build = __esm({
173583
174330
  });
173584
174331
 
173585
174332
  // src/site-analyze/apply.ts
173586
- import { existsSync as existsSync78, readFileSync as readFileSync99, writeFileSync as writeFileSync37, copyFileSync as copyFileSync2, mkdirSync as mkdirSync41, realpathSync as realpathSync15, statSync as statSync22 } from "node:fs";
173587
- import { dirname as dirname45, isAbsolute as isAbsolute8, join as join84, resolve as resolve60, sep as sep20 } from "node:path";
174333
+ import { existsSync as existsSync79, readFileSync as readFileSync100, writeFileSync as writeFileSync37, copyFileSync as copyFileSync2, mkdirSync as mkdirSync41, realpathSync as realpathSync15, statSync as statSync22 } from "node:fs";
174334
+ import { dirname as dirname47, isAbsolute as isAbsolute8, join as join86, resolve as resolve62, sep as sep20 } from "node:path";
173588
174335
  import { spawnSync as spawnSync4 } from "node:child_process";
173589
174336
  function unpairedRedirectNote(overlay) {
173590
174337
  if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
173591
174338
  return `no OAuth redirect paired with client ${overlay.wix.clientId} \u2014 the app (and prepare:customer) will refuse to start until one is set. Register it with \`himi site client ensure --site ${overlay.siteId?.trim() || "<msid>"} --redirect-uri <uri> --yes\`, then re-run analyze with \`--redirect-uri <uri>\` (or export HIMI_BRANDED_LITE_WIX_REDIRECT_URI)`;
173592
174339
  }
173593
174340
  function posix4(p2) {
173594
- return resolve60(p2).replace(/\\/g, "/");
174341
+ return resolve62(p2).replace(/\\/g, "/");
173595
174342
  }
173596
174343
  function committedShellProvisioning(path2) {
173597
174344
  return committedShellFor(posix4(path2));
@@ -173599,8 +174346,8 @@ function committedShellProvisioning(path2) {
173599
174346
  function findRepoRoot(cwd) {
173600
174347
  let dir = cwd;
173601
174348
  for (let i2 = 0; i2 < 8; i2++) {
173602
- if (SHELL_NAMES2.some((name) => existsSync78(join84(dir, shellAppDir(name), "package.json")))) return dir;
173603
- const next = dirname45(dir);
174349
+ if (SHELL_NAMES2.some((name) => existsSync79(join86(dir, shellAppDir(name), "package.json")))) return dir;
174350
+ const next = dirname47(dir);
173604
174351
  if (next === dir) break;
173605
174352
  dir = next;
173606
174353
  }
@@ -173625,7 +174372,7 @@ function assertNotCommitted(path2, forbidden2) {
173625
174372
  `refusing to overwrite committed ${committedProvisioningPath(committed)} \u2014 use prepare:customer --contract`
173626
174373
  );
173627
174374
  }
173628
- if (forbidden2 && resolve60(path2) === resolve60(forbidden2)) {
174375
+ if (forbidden2 && resolve62(path2) === resolve62(forbidden2)) {
173629
174376
  const named = committedShellProvisioning(forbidden2);
173630
174377
  throw new Error(
173631
174378
  `refusing to overwrite committed ${named ? committedProvisioningPath(named) : forbidden2} \u2014 pass a content-package provisioning.json or use prepare:customer --contract`
@@ -173702,24 +174449,24 @@ function sameKnownSite(previous, next) {
173702
174449
  }
173703
174450
  function buildMergedContract(options) {
173704
174451
  const { appDir: appDir3, packageDir, overlay } = options;
173705
- const committedPath = join84(appDir3, "provisioning.json");
173706
- if (!existsSync78(committedPath)) {
174452
+ const committedPath = join86(appDir3, "provisioning.json");
174453
+ if (!existsSync79(committedPath)) {
173707
174454
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
173708
174455
  }
173709
- const committed = JSON.parse(readFileSync99(committedPath, "utf8"));
174456
+ const committed = JSON.parse(readFileSync100(committedPath, "utf8"));
173710
174457
  const merged = mergeCustomerOwned(committed, overlay);
173711
174458
  const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
173712
174459
  const branding = merged.branding ?? {};
173713
174460
  const staged = [];
173714
174461
  const contained = (root, rel) => {
173715
174462
  if (isAbsolute8(rel)) return void 0;
173716
- const full = resolve60(root, rel);
173717
- return full.startsWith(resolve60(root) + sep20) ? full : void 0;
174463
+ const full = resolve62(root, rel);
174464
+ return full.startsWith(resolve62(root) + sep20) ? full : void 0;
173718
174465
  };
173719
174466
  const stage = (fromRel, toRel) => {
173720
174467
  const from = contained(packageDir, fromRel);
173721
- const to2 = contained(join84(appDir3, STAGED), toRel.slice(STAGED.length + 1));
173722
- if (!from || !to2 || !existsSync78(from)) return void 0;
174468
+ const to2 = contained(join86(appDir3, STAGED), toRel.slice(STAGED.length + 1));
174469
+ if (!from || !to2 || !existsSync79(from)) return void 0;
173723
174470
  let real;
173724
174471
  let realRoot;
173725
174472
  try {
@@ -173731,7 +174478,7 @@ function buildMergedContract(options) {
173731
174478
  if (!real.startsWith(realRoot + sep20)) return void 0;
173732
174479
  try {
173733
174480
  if (!statSync22(real).isFile()) return void 0;
173734
- mkdirSync41(dirname45(to2), { recursive: true });
174481
+ mkdirSync41(dirname47(to2), { recursive: true });
173735
174482
  copyFileSync2(real, to2);
173736
174483
  } catch {
173737
174484
  return void 0;
@@ -173741,11 +174488,11 @@ function buildMergedContract(options) {
173741
174488
  };
173742
174489
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
173743
174490
  if (icon) branding.appIconPath = icon;
173744
- const facesPath = join84(packageDir, "media/fonts/faces.json");
173745
- if (existsSync78(facesPath)) {
174491
+ const facesPath = join86(packageDir, "media/fonts/faces.json");
174492
+ if (existsSync79(facesPath)) {
173746
174493
  let faces = [];
173747
174494
  try {
173748
- const parsed = JSON.parse(readFileSync99(facesPath, "utf8"));
174495
+ const parsed = JSON.parse(readFileSync100(facesPath, "utf8"));
173749
174496
  faces = Array.isArray(parsed) ? parsed : [];
173750
174497
  } catch {
173751
174498
  faces = [];
@@ -173766,10 +174513,10 @@ function buildMergedContract(options) {
173766
174513
  merged.branding = branding;
173767
174514
  const body = `${JSON.stringify(merged, null, 2)}
173768
174515
  `;
173769
- const path2 = join84(packageDir, "provisioning.contract.json");
174516
+ const path2 = join86(packageDir, "provisioning.contract.json");
173770
174517
  writeFileSync37(path2, body);
173771
- const localPath2 = join84(appDir3, LOCAL_CONTRACT_REL);
173772
- mkdirSync41(dirname45(localPath2), { recursive: true });
174518
+ const localPath2 = join86(appDir3, LOCAL_CONTRACT_REL);
174519
+ mkdirSync41(dirname47(localPath2), { recursive: true });
173773
174520
  writeFileSync37(localPath2, body);
173774
174521
  staged.push(localPath2);
173775
174522
  return { path: path2, staged };
@@ -173803,10 +174550,10 @@ function catalogTypography(overlay, template) {
173803
174550
  function staticFaqFor(overlay, overlayPath) {
173804
174551
  const own5 = overlay.faq;
173805
174552
  if (own5 !== void 0) return deriveStaticFaq(own5);
173806
- const bookPath = join84(dirname45(resolve60(overlayPath)), "book.json");
173807
- if (!existsSync78(bookPath)) return void 0;
174553
+ const bookPath = join86(dirname47(resolve62(overlayPath)), "book.json");
174554
+ if (!existsSync79(bookPath)) return void 0;
173808
174555
  try {
173809
- const book = JSON.parse(readFileSync99(bookPath, "utf8"));
174556
+ const book = JSON.parse(readFileSync100(bookPath, "utf8"));
173810
174557
  const copy = book?.copy;
173811
174558
  if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
173812
174559
  const pairs = deriveStaticFaq(copy.faq);
@@ -173820,10 +174567,10 @@ function staticGalleriesFor(overlay, overlayPath) {
173820
174567
  if (overlay.galleries !== void 0) return deriveStaticGalleries(
173821
174568
  overlay.galleries.map((gallery) => ({ role: "gallery", title: gallery.title, galleryImageUrls: gallery.photos }))
173822
174569
  );
173823
- const bookPath = join84(dirname45(resolve60(overlayPath)), "book.json");
173824
- if (!existsSync78(bookPath)) return void 0;
174570
+ const bookPath = join86(dirname47(resolve62(overlayPath)), "book.json");
174571
+ if (!existsSync79(bookPath)) return void 0;
173825
174572
  try {
173826
- const book = JSON.parse(readFileSync99(bookPath, "utf8"));
174573
+ const book = JSON.parse(readFileSync100(bookPath, "utf8"));
173827
174574
  if (!book.look || book.look.unavailable || !Array.isArray(book.look.pages)) return void 0;
173828
174575
  const galleries = deriveStaticGalleries(book.look.pages);
173829
174576
  return galleries.length || book.look.complete === true ? galleries : void 0;
@@ -173832,11 +174579,11 @@ function staticGalleriesFor(overlay, overlayPath) {
173832
174579
  }
173833
174580
  }
173834
174581
  async function applyOverlays(input) {
173835
- const cwd = resolve60(input.cwd);
174582
+ const cwd = resolve62(input.cwd);
173836
174583
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
173837
174584
  assertKnownShell(shell);
173838
- const overlay = JSON.parse(readFileSync99(input.overlayPath, "utf8"));
173839
- const tokens2 = JSON.parse(readFileSync99(input.tokensPath, "utf8"));
174585
+ const overlay = JSON.parse(readFileSync100(input.overlayPath, "utf8"));
174586
+ const tokens2 = JSON.parse(readFileSync100(input.tokensPath, "utf8"));
173840
174587
  const faq = staticFaqFor(overlay, input.overlayPath);
173841
174588
  if (faq !== void 0) overlay.faq = faq;
173842
174589
  const galleries = staticGalleriesFor(overlay, input.overlayPath);
@@ -173853,15 +174600,15 @@ async function applyOverlays(input) {
173853
174600
  `shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
173854
174601
  );
173855
174602
  }
173856
- const appDir3 = join84(repoRoot2, shellAppDir(shell));
173857
- const committedPath = join84(appDir3, "provisioning.json");
173858
- const committedSite = existsSync78(committedPath) ? JSON.parse(readFileSync99(committedPath, "utf8")).site : void 0;
174603
+ const appDir3 = join86(repoRoot2, shellAppDir(shell));
174604
+ const committedPath = join86(appDir3, "provisioning.json");
174605
+ const committedSite = existsSync79(committedPath) ? JSON.parse(readFileSync100(committedPath, "utf8")).site : void 0;
173859
174606
  if (committedSite !== void 0 && overlay.site === void 0) {
173860
174607
  throw new Error(
173861
174608
  `shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block), and this overlay has none. Re-run \`himi site analyze --url <site> --shell ${shell}\` to derive the site's page map (edit \`site.pages\` in provisioning.overlay.json if needed), then --apply.`
173862
174609
  );
173863
174610
  }
173864
- const packageDir = dirname45(resolve60(input.overlayPath));
174611
+ const packageDir = dirname47(resolve62(input.overlayPath));
173865
174612
  const { path: contract, staged } = buildMergedContract({ appDir: appDir3, packageDir, overlay });
173866
174613
  wrote.push(...staged);
173867
174614
  const r2 = spawnSync4("npm", ["run", "prepare:customer", "--", "--contract", contract], {
@@ -173882,9 +174629,9 @@ async function applyOverlays(input) {
173882
174629
  note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
173883
174630
  };
173884
174631
  }
173885
- const pkgProv = join84(cwd, "provisioning.json");
174632
+ const pkgProv = join86(cwd, "provisioning.json");
173886
174633
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
173887
- const contentPath = join84(cwd, "himalaya.content.json");
174634
+ const contentPath = join86(cwd, "himalaya.content.json");
173888
174635
  const syncViewNames = (before, after) => {
173889
174636
  const content = readContentManifest(cwd);
173890
174637
  if (!content) return;
@@ -173896,8 +174643,8 @@ async function applyOverlays(input) {
173896
174643
  };
173897
174644
  let packageFaq = faq;
173898
174645
  let packageGalleries = galleries;
173899
- if (existsSync78(pkgProv)) {
173900
- const cur = JSON.parse(readFileSync99(pkgProv, "utf8"));
174646
+ if (existsSync79(pkgProv)) {
174647
+ const cur = JSON.parse(readFileSync100(pkgProv, "utf8"));
173901
174648
  if (galleries === void 0 && !sameKnownSite(cur, overlay)) overlay.galleries = [];
173902
174649
  const merged = deepMerge4(cur, overlay);
173903
174650
  packageFaq = merged.faq;
@@ -173913,9 +174660,9 @@ async function applyOverlays(input) {
173913
174660
  if (Array.isArray(packageGalleries) && packageGalleries.length && !overlay.installedVerticals.includes("galleries")) {
173914
174661
  overlay.installedVerticals.push("galleries");
173915
174662
  }
173916
- const pkgTokens = join84(cwd, "tokens.json");
173917
- if (existsSync78(pkgTokens) && (tokens2.colors || tokens2.typography)) {
173918
- const cur = JSON.parse(readFileSync99(pkgTokens, "utf8"));
174663
+ const pkgTokens = join86(cwd, "tokens.json");
174664
+ if (existsSync79(pkgTokens) && (tokens2.colors || tokens2.typography)) {
174665
+ const cur = JSON.parse(readFileSync100(pkgTokens, "utf8"));
173919
174666
  let tokensIn = tokens2;
173920
174667
  if (tokens2.typography) {
173921
174668
  const fonts = catalogTypography(tokens2.typography, cur.typography);
@@ -173940,9 +174687,9 @@ async function applyOverlays(input) {
173940
174687
  wrote.push(pkgTokens);
173941
174688
  }
173942
174689
  const homeAction = homeRefreshActionId(shell);
173943
- const homeSrc = join84(cwd, "dev/index.ts");
173944
- if (homeAction && existsSync78(homeSrc)) {
173945
- const prev = readFileSync99(homeSrc, "utf8");
174690
+ const homeSrc = join86(cwd, "dev/index.ts");
174691
+ if (homeAction && existsSync79(homeSrc)) {
174692
+ const prev = readFileSync100(homeSrc, "utf8");
173946
174693
  const patched = patchBrandParams(prev, overlay, homeAction);
173947
174694
  let next = patched.src;
173948
174695
  if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
@@ -173977,13 +174724,13 @@ async function applyOverlays(input) {
173977
174724
  notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
173978
174725
  }
173979
174726
  }
173980
- if (!input.iconPath || !existsSync78(input.iconPath)) {
173981
- const book = input.iconPath ? dirname45(dirname45(resolve60(input.iconPath))) : void 0;
174727
+ if (!input.iconPath || !existsSync79(input.iconPath)) {
174728
+ const book = input.iconPath ? dirname47(dirname47(resolve62(input.iconPath))) : void 0;
173982
174729
  notes.push(
173983
174730
  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"
173984
174731
  );
173985
174732
  }
173986
- if (input.iconPath && existsSync78(input.iconPath)) {
174733
+ if (input.iconPath && existsSync79(input.iconPath)) {
173987
174734
  try {
173988
174735
  const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
173989
174736
  wrote.push(...installed.wrote);
@@ -174941,8 +175688,8 @@ __export(cli_exports3, {
174941
175688
  runSiteAnalyze: () => runSiteAnalyze,
174942
175689
  runSiteFunctionCli: () => runSiteFunctionCli
174943
175690
  });
174944
- import { existsSync as existsSync79, readFileSync as readFileSync100 } from "node:fs";
174945
- import { resolve as resolve61 } from "node:path";
175691
+ import { existsSync as existsSync80, readFileSync as readFileSync101 } from "node:fs";
175692
+ import { resolve as resolve63 } from "node:path";
174946
175693
  function applyNeedsClient(shell) {
174947
175694
  if (shell === void 0 || !SHELL_NAMES2.includes(shell)) return true;
174948
175695
  return !isSiteShell(shell);
@@ -174966,7 +175713,7 @@ async function runSiteAnalyze(opts) {
174966
175713
  const assetFetch = assetFetchFor(opts);
174967
175714
  const siteFetch = guardedSiteFetch;
174968
175715
  const cwd = opts.cwd ?? process.cwd();
174969
- const outDir = resolve61(cwd, opts.outDir ?? ".himi/business-book");
175716
+ const outDir = resolve63(cwd, opts.outDir ?? ".himi/business-book");
174970
175717
  let ownerAuth;
174971
175718
  let msid;
174972
175719
  const ownerSite = ownerSiteFor(opts);
@@ -174993,14 +175740,14 @@ async function runSiteAnalyze(opts) {
174993
175740
  if (opts.shell !== void 0 && isSiteShell(opts.shell)) {
174994
175741
  try {
174995
175742
  const kind = siteKindForOrigin(result.book.input.siteUrl);
174996
- const book = kind === "base44" ? base44BookRoutes(resolve61(cwd, ".himi/base44-book/book.json"), result.book.input.siteUrl) : void 0;
175743
+ const book = kind === "base44" ? base44BookRoutes(resolve63(cwd, ".himi/base44-book/book.json"), result.book.input.siteUrl) : void 0;
174997
175744
  const routes = book?.routes;
174998
175745
  if (book?.skipped) result.warnings = [...result.warnings ?? [], book.skipped];
174999
175746
  const derived = deriveSiteShell({ siteUrl: result.book.input.siteUrl, look: result.book.look, kind, routes });
175000
- const prevOverlayPath = resolve61(outDir, "provisioning.overlay.json");
175001
- const prevSite = existsSync79(prevOverlayPath) ? (() => {
175747
+ const prevOverlayPath = resolve63(outDir, "provisioning.overlay.json");
175748
+ const prevSite = existsSync80(prevOverlayPath) ? (() => {
175002
175749
  try {
175003
- return JSON.parse(readFileSync100(prevOverlayPath, "utf8")).site;
175750
+ return JSON.parse(readFileSync101(prevOverlayPath, "utf8")).site;
175004
175751
  } catch {
175005
175752
  return void 0;
175006
175753
  }
@@ -175017,9 +175764,9 @@ async function runSiteAnalyze(opts) {
175017
175764
  ];
175018
175765
  }
175019
175766
  }
175020
- const previousOverlay = resolve61(outDir, "provisioning.overlay.json");
175767
+ const previousOverlay = resolve63(outDir, "provisioning.overlay.json");
175021
175768
  carryOverGoals(
175022
- existsSync79(previousOverlay) ? readFileSync100(previousOverlay, "utf8") : void 0,
175769
+ existsSync80(previousOverlay) ? readFileSync101(previousOverlay, "utf8") : void 0,
175023
175770
  result.provisioningOverlay
175024
175771
  );
175025
175772
  const ownerCall = ownerAuth ? ownerTransportFrom(fetchImpl, ownerAuth) : void 0;
@@ -175038,9 +175785,9 @@ async function runSiteAnalyze(opts) {
175038
175785
  if (opts.apply) {
175039
175786
  applied = await applyOverlays({
175040
175787
  cwd,
175041
- overlayPath: resolve61(outDir, "provisioning.overlay.json"),
175042
- tokensPath: resolve61(outDir, "tokens.overlay.json"),
175043
- iconPath: resolve61(outDir, "media/icon.png"),
175788
+ overlayPath: resolve63(outDir, "provisioning.overlay.json"),
175789
+ tokensPath: resolve63(outDir, "tokens.overlay.json"),
175790
+ iconPath: resolve63(outDir, "media/icon.png"),
175044
175791
  shell: opts.shell
175045
175792
  });
175046
175793
  const note = noteWithWarnings(applied.note, warnings);
@@ -175076,8 +175823,8 @@ async function runSiteFunctionCli(opts) {
175076
175823
  const token = opts.token ?? await siteToken(msid);
175077
175824
  let source;
175078
175825
  if (opts.sourcePath) {
175079
- const p2 = resolve61(opts.cwd ?? process.cwd(), opts.sourcePath);
175080
- source = readFileSync100(p2, "utf8");
175826
+ const p2 = resolve63(opts.cwd ?? process.cwd(), opts.sourcePath);
175827
+ source = readFileSync101(p2, "utf8");
175081
175828
  }
175082
175829
  let body;
175083
175830
  if (opts.bodyRaw != null) {
@@ -175105,9 +175852,9 @@ async function runSiteFunctionCli(opts) {
175105
175852
  });
175106
175853
  }
175107
175854
  function base44BookRoutes(bookPath, siteUrl) {
175108
- if (!existsSync79(bookPath)) return void 0;
175855
+ if (!existsSync80(bookPath)) return void 0;
175109
175856
  try {
175110
- const book = JSON.parse(readFileSync100(bookPath, "utf8"));
175857
+ const book = JSON.parse(readFileSync101(bookPath, "utf8"));
175111
175858
  if (book.kind !== "base44-app-book" || !Array.isArray(book.routes)) return void 0;
175112
175859
  const host = (u2) => {
175113
175860
  try {
@@ -175156,7 +175903,7 @@ async function accountToken2(spawnImpl = spawn6) {
175156
175903
  cached2 = fromEnv;
175157
175904
  return fromEnv;
175158
175905
  }
175159
- const token = await new Promise((resolve63, reject) => {
175906
+ const token = await new Promise((resolve65, reject) => {
175160
175907
  let child;
175161
175908
  try {
175162
175909
  child = spawnImpl("wix", ["token"]);
@@ -175185,7 +175932,7 @@ async function accountToken2(spawnImpl = spawn6) {
175185
175932
  const scan = (d2) => {
175186
175933
  out2 += String(d2);
175187
175934
  const m2 = out2.match(TOKEN_RE2);
175188
- if (m2) done(() => resolve63(m2[0]));
175935
+ if (m2) done(() => resolve65(m2[0]));
175189
175936
  };
175190
175937
  child.stdout?.on("data", scan);
175191
175938
  child.stderr?.on("data", scan);
@@ -175362,7 +176109,7 @@ __export(site_create_exports, {
175362
176109
  runSiteList: () => runSiteList,
175363
176110
  writeProvisioningBinding: () => writeProvisioningBinding
175364
176111
  });
175365
- import { existsSync as existsSync80, readFileSync as readFileSync101, writeFileSync as writeFileSync38 } from "node:fs";
176112
+ import { existsSync as existsSync81, readFileSync as readFileSync102, writeFileSync as writeFileSync38 } from "node:fs";
175366
176113
  import { resolve as resolvePath2 } from "node:path";
175367
176114
  function oauthClientName(projectName) {
175368
176115
  return `${projectName} client`;
@@ -175511,7 +176258,7 @@ async function runSiteCreate(opts) {
175511
176258
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
175512
176259
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
175513
176260
  }
175514
- function writeProvisioningBinding(target, binding2, fs2 = { existsSync: existsSync80, readFileSync: readFileSync101, writeFileSync: writeFileSync38 }) {
176261
+ function writeProvisioningBinding(target, binding2, fs2 = { existsSync: existsSync81, readFileSync: readFileSync102, writeFileSync: writeFileSync38 }) {
175515
176262
  const msid = binding2.siteId;
175516
176263
  const path2 = resolvePath2(target);
175517
176264
  const committed = committedShellProvisioning(path2);
@@ -176208,12 +176955,12 @@ var init_context = __esm({
176208
176955
  });
176209
176956
 
176210
176957
  // src/cli.ts
176211
- import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync102, mkdirSync as mkdirSync42, writeFileSync as writeFileSync39, existsSync as existsSync81, rmSync as rmSync22, readdirSync as readdirSync35, statSync as statSync23, lstatSync as lstatSync22, accessSync, constants as constants5, renameSync as renameSync12, cpSync as cpSync3 } from "node:fs";
176958
+ import { mkdtempSync as mkdtempSync6, readFileSync as readFileSync103, mkdirSync as mkdirSync42, writeFileSync as writeFileSync39, existsSync as existsSync82, rmSync as rmSync23, readdirSync as readdirSync35, statSync as statSync23, lstatSync as lstatSync22, accessSync, constants as constants5, renameSync as renameSync13, cpSync as cpSync3 } from "node:fs";
176212
176959
  import { execFile as execFile2, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn7 } from "node:child_process";
176213
176960
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
176214
- import { createHash as createHash44, randomUUID as randomUUID11 } from "node:crypto";
176215
- import { tmpdir as tmpdir6, homedir as homedir14, hostname as hostname2 } from "node:os";
176216
- import { join as join85, resolve as resolve62, relative as relative15, basename as basename19, dirname as dirname46 } from "node:path";
176961
+ import { createHash as createHash45, randomUUID as randomUUID11 } from "node:crypto";
176962
+ import { tmpdir as tmpdir7, homedir as homedir14, hostname as hostname2 } from "node:os";
176963
+ import { join as join87, resolve as resolve64, relative as relative16, basename as basename21, dirname as dirname48 } from "node:path";
176217
176964
  import { fileURLToPath as fileURLToPath29 } from "node:url";
176218
176965
 
176219
176966
  // ../serve-cli/src/client.ts
@@ -176510,8 +177257,16 @@ var ServeCliClient = class {
176510
177257
  const { bytes: bytes2, gzip } = encodePublishBody(publishReleaseBody(payload, meta, draft));
176511
177258
  const headers2 = { ...this.ctrlHeaders(), ...gzip ? { "content-encoding": "gzip" } : {} };
176512
177259
  const res = await this.request("control", "POST", "/v1/admin/release", { rawBody: bytes2, headers: headers2 });
176513
- if (gzip && res.status === 400 && res.json?.error === "bad_json") {
176514
- const json6 = { code: "compressed_publish_unsupported", error: "compressed_publish_unsupported", hint: "this body is over the plain publish cap, and the plane did not accept it compressed: either the plane predates gzip publish bodies (it needs a serve deploy), or this is a self-serve credential, which keeps the plain 8 MB cap" };
177260
+ const refusal = res.json;
177261
+ const decodedOverPlainCap = res.status === 413 && refusal?.error === "payload_too_large" && refusal.limit === MAX_PUBLISH_BODY_BYTES && bytes2.byteLength <= MAX_PUBLISH_BODY_BYTES;
177262
+ if (gzip && (res.status === 400 && refusal?.error === "bad_json" || decodedOverPlainCap)) {
177263
+ const json6 = {
177264
+ code: "compressed_publish_unsupported",
177265
+ error: "compressed_publish_unsupported",
177266
+ hint: "this body is over the plain publish cap, and the plane did not accept it compressed: either the plane predates compressed publish bodies (it needs a serve deploy), or this is a self-serve credential, which keeps the plain 8 MB cap",
177267
+ sentBytes: bytes2.byteLength,
177268
+ ...typeof refusal?.bytes === "number" ? { planeCountedBytes: refusal.bytes } : {}
177269
+ };
176515
177270
  return { ...res, json: json6, text: JSON.stringify(json6) };
176516
177271
  }
176517
177272
  return res;
@@ -178287,8 +179042,8 @@ var str9 = (v2) => typeof v2 === "string" ? v2 : void 0;
178287
179042
  var num3 = (v2) => typeof v2 === "string" && v2 !== "" && Number.isFinite(Number(v2)) ? Number(v2) : void 0;
178288
179043
  function embeddedTemplateCatalog() {
178289
179044
  return availableTemplates().map((name) => {
178290
- const path2 = join85(templateSourceDir(name), TEMPLATE_META_FILE);
178291
- const meta = JSON.parse(readFileSync102(path2, "utf8"));
179045
+ const path2 = join87(templateSourceDir(name), TEMPLATE_META_FILE);
179046
+ const meta = JSON.parse(readFileSync103(path2, "utf8"));
178292
179047
  if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
178293
179048
  throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
178294
179049
  }
@@ -178848,6 +179603,13 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
178848
179603
  conflict, never overwritten. --content records the
178849
179604
  purchases app as wixIap in the app's config.ts.
178850
179605
  No build, signing or repo checkout. Guide: himi docs iap-products
179606
+ himi store iap screenshots --manifest <file> --content <app dir> [--profile <name>] [--out-dir <dir>]
179607
+ [--only <productId,\u2026>] [--force] [--dry-run] [--json]
179608
+ render each product's purchase screen from the app, as a
179609
+ signed-in member sees it on a bound iPhone (Apple price, buy
179610
+ button), save it at 1290\xD72796 and name it as the item's
179611
+ reviewScreenshot. --profile reads Apple's price (read-only)
179612
+ and skips live products. Guide: himi docs iap-products
178851
179613
  himi logout [--target <t>] clear the stored control token for a target
178852
179614
  himi notify setup --content <dir> [--target wix] [--yes] [--no-push-setup]
178853
179615
  Optional Branded/Ping setup. Prompts for site, native IDs and APNs key file.
@@ -179158,7 +179920,7 @@ var COMMANDS2 = [
179158
179920
  { name: "visibility", summary: "read (no value) or set whether the public registry (/v1/apps + the Himi Player picker) LISTS the app. `public` lists it for everyone; `unlisted` hides it from listings while direct reads by app id \u2014 deep links, previews \u2014 keep working. App from --app or the content dir. Setting it needs no republish.", required: "[public|unlisted] [--app <a>] [--content <dir>] (--control-token)" },
179159
179921
  { name: "dist", summary: "build an INSTALLABLE QA binary (signed IPA / APK) on the Wix Job Service Mac pool and return an install link \u2014 the serve plane brokers the job, the pool builds it. WAITS for the build by default (~4 min) and prints the install link; `--no-wait` returns a jobId immediately instead. Omitting `--release` builds whatever is LIVE for the app. A named draft is refused unless `--allow-draft` makes that exceptional build explicit. `status <jobId>` / `watch <jobId>` / `list --app <a>` / `cancel <jobId>` inspect and stop builds (`watch` reports up front whether the job mints its own signing identity or borrows one, so a doomed iOS build is cancellable in seconds rather than after the archive). Off-repo, name a target \u2014 `--target wix` for a self-serve Wix login or `--target bo` for the internal employee path (the in-repo default is a local dev plane that isn't reachable off-repo); self-serve callers may build their OWN apps under a tighter budget (2 in flight / 5 per 24h), while a manage-only owner-role credential is refused. `--shell` picks the native host to sign into (branded-lite | owner-lite | brandy | base44 | player | demo-app) and defaults to the content package's himalaya.content.json `shell` (templates carry the one they were written for), else branded-lite. The per-app shells ADD the release's declared capabilities to the binary, while Himi Player and demo-app refuse a release declaring one they lack; `--plan` previews it without building; `brandy` is the site shell \u2014 the customer's own website as native-framed tabs. `--signing` defaults to `wix-managed` \u2014 the Wix Apple account mints a per-app signing identity for the build, so the caller provisions no Apple credentials of their own; `--signing byo --site <id>` reuses an existing customer ad-hoc profile and certificate for iOS; requires an owned site and a completed personal signing binding. `--android-signing` is the Android counterpart and a SEPARATE axis (a keystore, not an Apple account): `qa-keystore` (default \u2014 the repo's committed QA key, identical on every pool machine, so a build installs over the previous one), `wix-keystore` (the Wix key the pool machine carries; the build FAILS naming the paths searched if it carries none, rather than quietly signing with something else), or `debug` (the old per-machine key \u2014 QA must uninstall any previous build first). NOT the normal way to ship: screens, Tier-5 bundles, tokens and app-config all go over the air with `himi push` in seconds \u2014 a binary trip is only needed for a NATIVE delta (a new SDUI component, a new declared capability/entitlement, a new bundle id, or a minBinaryVersion floor bump). Refuses to build an app whose launcher icon is missing, a placeholder, or one a store would reject \u2014 the one thing a binary carries that no later OTA push can fix; `--force` builds anyway", required: "[--app <a>] [--platform ios,android] [--release <id>] [--allow-draft] [--target <t>] [--shell branded-lite|owner-lite|brandy|base44|player|demo-app] [--signing wix-managed|byo] [--site <id>] [--android-signing qa-keystore|wix-keystore|debug] [--borrow-ios-id <bundleId>] [--no-wait] [--force] [--plan] | status <jobId> [--target <t>] | watch <jobId> [--target <t>] [--interval <ms>] | list --app <a> [--target <t>] | cancel <jobId> [--target <t>]" },
179160
179922
  { name: "testflight", summary: 'build, sign and upload an app to TestFlight (internal testers \u2014 no Beta App Review), then WAIT until App Store Connect finishes processing it. Sugar for `store upload --track testflight`. Prompts first: a build number is consumed permanently on a real Apple account and cannot be reused \u2014 `--yes` for CI, `--dry-run` to see the plan without touching anything. The wait is the real check, not a nicety: fastlane prints "Successfully uploaded" for a binary App Store Connect then rejects in processing, and a rejected binary leaves NO build record at all (the reason is emailed). Public App Store review is deliberately NOT automatable here \u2014 `--track appstore` is refused; use /submit-ios-app when you mean to go public', required: "<app> [--track testflight|internal] [--profile <name>] [--yes] [--dry-run] [--skip-build] [--no-wait] [--json]" },
179161
- { name: "store", summary: "the App Store Connect group behind `testflight`. `preflight <app>` checks readiness offline (icon, entitlements, encryption flag, version, store.config ids, listing + review record); `upload <app>` is what `testflight` runs; `status <app>` reads live build + processing state. `--profile` selects WHICH App Store Connect account: an app built for a Wix customer ships under the CUSTOMER's Apple team (Apple guideline 4.2.6 forbids an app-generation service submitting on a client's behalf), declared per-app as ios.credentialProfile in store.config.yaml and resolved from ~/.himalaya/store-credentials/<name>.json \u2014 the .p8 itself never enters the repo. `iap draft|plan|apply|status|connect` registers an app owner's digital products as in-app purchases (non-consumables, or consumable price tiers): draft reads the Wix catalog and writes the manifest, plan and status only read, apply is the one App Store mutation boundary, connect readies the Wix site to sell them (purchases app, In-App Purchase key, appleIAP provider, product mappings; --preview-tag routes only its Serve calls to a deploy preview), and none of them builds, signs or needs a checkout (`himi docs iap-products`)", required: "preflight <app> [--profile <n>] | upload <app> [--track <t>] [--profile <n>] [--yes] [--dry-run] | status <app> [--profile <n>] | iap draft --site <msid> --profile <n> --apple-app <id> --bundle <id> --base-territory <t> --out <f> [--territories <a,b>] [--locale <l>] [--mode per-item|tiers] [--merge <f>] [--report <f>] [--json] | iap plan --manifest <f> --profile <n> --out <f> [--json] | iap apply --plan <f> --profile <n> --out <f> [--yes] [--limit <n>] [--json] | iap status --manifest <f> --profile <n> [--out <f>] [--json] | iap connect --manifest <f> --profile <n> [--iap-key <AuthKey.p8> --iap-key-id <id>] [--content <dir>] [--preview-tag dp-<tag>] [--dry-run] [--yes] [--out <f>] [--json]" },
179923
+ { name: "store", summary: "the App Store Connect group behind `testflight`. `preflight <app>` checks readiness offline (icon, entitlements, encryption flag, version, store.config ids, listing + review record); `upload <app>` is what `testflight` runs; `status <app>` reads live build + processing state. `--profile` selects WHICH App Store Connect account: an app built for a Wix customer ships under the CUSTOMER's Apple team (Apple guideline 4.2.6 forbids an app-generation service submitting on a client's behalf), declared per-app as ios.credentialProfile in store.config.yaml and resolved from ~/.himalaya/store-credentials/<name>.json \u2014 the .p8 itself never enters the repo. `iap draft|plan|apply|status|connect|screenshots` registers an app owner's digital products as in-app purchases (non-consumables, or consumable price tiers): draft reads the Wix catalog and writes the manifest, plan and status only read, apply is the one App Store mutation boundary, connect readies the Wix site to sell them (purchases app, In-App Purchase key, appleIAP provider, product mappings; --preview-tag routes only its Serve calls to a deploy preview), screenshots renders each product's purchase screen from the app (--content) as a bound iPhone shows it to a signed-in member and names the 1290\xD72796 PNG as the item's App Review screenshot, and none of them builds, signs or needs a checkout (`himi docs iap-products`)", required: "preflight <app> [--profile <n>] | upload <app> [--track <t>] [--profile <n>] [--yes] [--dry-run] | status <app> [--profile <n>] | iap draft --site <msid> --profile <n> --apple-app <id> --bundle <id> --base-territory <t> --out <f> [--territories <a,b>] [--locale <l>] [--mode per-item|tiers] [--merge <f>] [--report <f>] [--json] | iap plan --manifest <f> --profile <n> --out <f> [--json] | iap apply --plan <f> --profile <n> --out <f> [--yes] [--limit <n>] [--json] | iap status --manifest <f> --profile <n> [--out <f>] [--json] | iap connect --manifest <f> --profile <n> [--iap-key <AuthKey.p8> --iap-key-id <id>] [--content <dir>] [--preview-tag dp-<tag>] [--dry-run] [--yes] [--out <f>] [--json] | iap screenshots --manifest <f> --content <dir> [--profile <n>] [--out-dir <d>] [--only <id,\u2026>] [--force] [--dry-run] [--json]" },
179162
179924
  { name: "guide", summary: "print the Himalaya overview + headless dev loop + available topics (offline)", required: "[--json]" },
179163
179925
  { name: "docs", summary: "print bundled/verified cached guides offline; status reports kit identity; refresh downloads compatible reference content independently of CLI without changing app source", required: "[<topic>|catalog [kind]|status|refresh] [--pin <version|digest>] [--unpin] [--no-network] [--json]" },
179164
179926
  { name: "components", summary: "print the SDUI component vocabulary + props; a name = that component (offline)", required: "[<Name>] [--json]" },
@@ -179175,7 +179937,7 @@ var COMMANDS2 = [
179175
179937
  ];
179176
179938
  function cliVersion() {
179177
179939
  try {
179178
- return JSON.parse(readFileSync102(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
179940
+ return JSON.parse(readFileSync103(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
179179
179941
  } catch {
179180
179942
  return "unknown";
179181
179943
  }
@@ -179226,18 +179988,18 @@ function createScopedRegistryResolver(exec = execNpmConfig) {
179226
179988
  }
179227
179989
  var SCOPED_REGISTRY_TIMEOUT_MS = 5e3;
179228
179990
  function execNpmConfig(file2, args, options) {
179229
- return new Promise((resolve63, reject) => {
179230
- execFile2(file2, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve63(String(stdout)));
179991
+ return new Promise((resolve65, reject) => {
179992
+ execFile2(file2, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve65(String(stdout)));
179231
179993
  });
179232
179994
  }
179233
179995
  var npmScopedWixRegistry = createScopedRegistryResolver();
179234
179996
  async function scopedRegistryBefore(lookup3, deadline, onTimeout) {
179235
179997
  let cancel = () => {
179236
179998
  };
179237
- const expired = new Promise((resolve63) => {
179999
+ const expired = new Promise((resolve65) => {
179238
180000
  const timer = setTimeout(() => {
179239
180001
  onTimeout?.();
179240
- resolve63(void 0);
180002
+ resolve65(void 0);
179241
180003
  }, Math.max(0, deadline - Date.now()));
179242
180004
  cancel = () => clearTimeout(timer);
179243
180005
  });
@@ -179300,18 +180062,18 @@ function ageInDays(publishedAt, now = Date.now()) {
179300
180062
  }
179301
180063
  function packageVersion(path2) {
179302
180064
  try {
179303
- const version4 = JSON.parse(readFileSync102(path2, "utf8")).version;
180065
+ const version4 = JSON.parse(readFileSync103(path2, "utf8")).version;
179304
180066
  return typeof version4 === "string" && version4 ? version4 : void 0;
179305
180067
  } catch {
179306
180068
  return void 0;
179307
180069
  }
179308
180070
  }
179309
180071
  function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
179310
- let dir = resolve62(fromDir);
180072
+ let dir = resolve64(fromDir);
179311
180073
  for (; ; ) {
179312
- const version4 = packageVersion(join85(dir, "node_modules", "@wix", "himalaya", "package.json"));
180074
+ const version4 = packageVersion(join87(dir, "node_modules", "@wix", "himalaya", "package.json"));
179313
180075
  if (version4) return { version: version4, source: "local" };
179314
- const parent = dirname46(dir);
180076
+ const parent = dirname48(dir);
179315
180077
  if (parent === dir) break;
179316
180078
  dir = parent;
179317
180079
  }
@@ -179319,7 +180081,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
179319
180081
  if (bundled) return { version: bundled, source: "bundled" };
179320
180082
  try {
179321
180083
  const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
179322
- const version4 = root ? packageVersion(join85(root, "@wix", "himalaya", "package.json")) : void 0;
180084
+ const version4 = root ? packageVersion(join87(root, "@wix", "himalaya", "package.json")) : void 0;
179323
180085
  return version4 ? { version: version4, source: "global" } : {};
179324
180086
  } catch {
179325
180087
  return {};
@@ -179366,11 +180128,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
179366
180128
  var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
179367
180129
  var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
179368
180130
  function updateCachePath(env = process.env) {
179369
- return env.HIMI_UPDATE_CACHE_FILE ?? join85(homedir14(), ".himalaya", "update-check.json");
180131
+ return env.HIMI_UPDATE_CACHE_FILE ?? join87(homedir14(), ".himalaya", "update-check.json");
179370
180132
  }
179371
180133
  function readUpdateCache(path2) {
179372
180134
  try {
179373
- const parsed = JSON.parse(readFileSync102(path2, "utf8"));
180135
+ const parsed = JSON.parse(readFileSync103(path2, "utf8"));
179374
180136
  return parsed && typeof parsed === "object" ? parsed : {};
179375
180137
  } catch {
179376
180138
  return {};
@@ -179378,7 +180140,7 @@ function readUpdateCache(path2) {
179378
180140
  }
179379
180141
  function writeUpdateCache(path2, cache) {
179380
180142
  try {
179381
- mkdirSync42(dirname46(path2), { recursive: true, mode: 448 });
180143
+ mkdirSync42(dirname48(path2), { recursive: true, mode: 448 });
179382
180144
  writeFileSync39(path2, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
179383
180145
  } catch {
179384
180146
  }
@@ -179439,12 +180201,12 @@ function createUpdateRunner(spawn8 = spawnSync5) {
179439
180201
  },
179440
180202
  installedVersion: () => {
179441
180203
  const root = globalNodeModulesRoot();
179442
- return root ? packageVersion(join85(root, "@wix", "himalaya-cli", "package.json")) : void 0;
180204
+ return root ? packageVersion(join87(root, "@wix", "himalaya-cli", "package.json")) : void 0;
179443
180205
  },
179444
180206
  reexec: (argv) => {
179445
180207
  const root = globalNodeModulesRoot();
179446
- const entry = root ? join85(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
179447
- if (!entry || !existsSync81(entry)) return void 0;
180208
+ const entry = root ? join87(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
180209
+ if (!entry || !existsSync82(entry)) return void 0;
179448
180210
  const result = spawnSync5(process.execPath, [entry, ...argv], {
179449
180211
  // inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
179450
180212
  stdio: "inherit",
@@ -179491,7 +180253,7 @@ function staleUpdateLockFile(cachePath, now) {
179491
180253
  for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
179492
180254
  let content;
179493
180255
  try {
179494
- content = readFileSync102(path2, "utf8");
180256
+ content = readFileSync103(path2, "utf8");
179495
180257
  } catch {
179496
180258
  continue;
179497
180259
  }
@@ -179514,7 +180276,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
179514
180276
  const mine = lockStamp(now);
179515
180277
  const readLock = (path2) => {
179516
180278
  try {
179517
- return readFileSync102(path2, "utf8");
180279
+ return readFileSync103(path2, "utf8");
179518
180280
  } catch {
179519
180281
  return void 0;
179520
180282
  }
@@ -179529,13 +180291,13 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
179529
180291
  };
179530
180292
  const removeIfMine = (path2) => {
179531
180293
  try {
179532
- if (readLock(path2) === mine) rmSync22(path2, { force: true });
180294
+ if (readLock(path2) === mine) rmSync23(path2, { force: true });
179533
180295
  } catch {
179534
180296
  }
179535
180297
  };
179536
180298
  const release2 = () => removeIfMine(lockPath);
179537
180299
  try {
179538
- mkdirSync42(dirname46(lockPath), { recursive: true, mode: 448 });
180300
+ mkdirSync42(dirname48(lockPath), { recursive: true, mode: 448 });
179539
180301
  } catch {
179540
180302
  return () => {
179541
180303
  };
@@ -179552,7 +180314,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
179552
180314
  hooks.underBreakLock?.();
179553
180315
  if (current === void 0) return tryCreate(lockPath) ? release2 : void 0;
179554
180316
  if (!isAbandoned(current)) return void 0;
179555
- rmSync22(lockPath, { force: true });
180317
+ rmSync23(lockPath, { force: true });
179556
180318
  return tryCreate(lockPath) ? release2 : void 0;
179557
180319
  } finally {
179558
180320
  removeIfMine(breakPath);
@@ -179648,7 +180410,7 @@ function createTrimValidator(deps = {}, spawnFn = spawn7) {
179648
180410
  return { code, counts, ...errors ? { errors } : {}, ...code !== 0 ? { tail: said.slice(-4e3) } : {} };
179649
180411
  };
179650
180412
  return async (dir, opts = {}) => {
179651
- const argv = ["validate", "--content", resolve62(dir), "--strict", "--skip-version-check"];
180413
+ const argv = ["validate", "--content", resolve64(dir), "--strict", "--skip-version-check"];
179652
180414
  if (!opts.fresh) {
179653
180415
  const out2 = [];
179654
180416
  const err = [];
@@ -180106,7 +180868,7 @@ function executableOnPath(name, env = process.env) {
180106
180868
  const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
180107
180869
  for (const dir of entries) {
180108
180870
  for (const suffix of suffixes) {
180109
- const candidate = join85(dir, `${name}${suffix}`);
180871
+ const candidate = join87(dir, `${name}${suffix}`);
180110
180872
  try {
180111
180873
  if (!statSync23(candidate).isFile()) continue;
180112
180874
  if (process.platform !== "win32") accessSync(candidate, constants5.X_OK);
@@ -180215,7 +180977,7 @@ async function nativeConfigAdvisories(app, configSource) {
180215
180977
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths2(), paths_exports));
180216
180978
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
180217
180979
  const iosYmlPath = iosProjectYml2(app);
180218
- const iosYml = existsSync81(iosYmlPath) ? readFileSync102(iosYmlPath, "utf8") : "";
180980
+ const iosYml = existsSync82(iosYmlPath) ? readFileSync103(iosYmlPath, "utf8") : "";
180219
180981
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
180220
180982
  if (!optedIn) {
180221
180983
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -180229,13 +180991,13 @@ async function nativeConfigAdvisories(app, configSource) {
180229
180991
  }
180230
180992
  function readConfigSource(dir) {
180231
180993
  try {
180232
- return readFileSync102(join85(dir, "config.ts"), "utf8");
180994
+ return readFileSync103(join87(dir, "config.ts"), "utf8");
180233
180995
  } catch {
180234
180996
  return null;
180235
180997
  }
180236
180998
  }
180237
180999
  function writePngFile(path2, base64) {
180238
- mkdirSync42(dirname46(path2), { recursive: true });
181000
+ mkdirSync42(dirname48(path2), { recursive: true });
180239
181001
  writeFileSync39(path2, Buffer.from(base64, "base64"));
180240
181002
  return path2;
180241
181003
  }
@@ -180282,8 +181044,8 @@ function keptPlan(kept) {
180282
181044
  var NoBase44SlotError = class extends Error {
180283
181045
  };
180284
181046
  async function initFromRemoteTemplate(name, parentDir, template, c2, opts = {}) {
180285
- const dir = resolve62(parentDir, name);
180286
- if (existsSync81(join85(dir, "himalaya.content.json"))) {
181047
+ const dir = resolve64(parentDir, name);
181048
+ if (existsSync82(join87(dir, "himalaya.content.json"))) {
180287
181049
  throw new Error(`content package already exists at ${dir}`);
180288
181050
  }
180289
181051
  const r2 = await c2.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -180298,7 +181060,7 @@ async function initFromRemoteTemplate(name, parentDir, template, c2, opts = {})
180298
181060
  return finishScaffold(materializeSource(archive.files, name, dir), template);
180299
181061
  }
180300
181062
  function contentDir(flags) {
180301
- return resolve62(str9(flags.content) ?? process.cwd());
181063
+ return resolve64(str9(flags.content) ?? process.cwd());
180302
181064
  }
180303
181065
  function renameRestoredSource(restored, declaredApp, renamed) {
180304
181066
  const text9 = {};
@@ -180329,7 +181091,7 @@ function symlinkDestinationIssue(dest) {
180329
181091
  function restoreDestinationIssue(dest, force) {
180330
181092
  const link = symlinkDestinationIssue(dest);
180331
181093
  if (link) return link;
180332
- if (!existsSync81(dest)) return null;
181094
+ if (!existsSync82(dest)) return null;
180333
181095
  if (!statSync23(dest).isDirectory()) {
180334
181096
  return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
180335
181097
  }
@@ -180342,10 +181104,10 @@ function restoreDestinationIssue(dest, force) {
180342
181104
  return null;
180343
181105
  }
180344
181106
  function isHimalayaMonorepoCheckout(start) {
180345
- let dir = resolve62(start);
181107
+ let dir = resolve64(start);
180346
181108
  for (; ; ) {
180347
- if (existsSync81(join85(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync81(join85(dir, "core", "serve", "src", "server.ts"))) return true;
180348
- const parent = dirname46(dir);
181109
+ if (existsSync82(join87(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync82(join87(dir, "core", "serve", "src", "server.ts"))) return true;
181110
+ const parent = dirname48(dir);
180349
181111
  if (parent === dir) return false;
180350
181112
  dir = parent;
180351
181113
  }
@@ -180382,7 +181144,7 @@ function shellShaDivergenceWarnings(jobs) {
180382
181144
  }
180383
181145
  async function templatePublishName(sourceDir) {
180384
181146
  const id = await appId(sourceDir);
180385
- return IDENTITY_SENTINELS.some((s2) => id.includes(s2)) ? basename19(sourceDir) : id;
181147
+ return IDENTITY_SENTINELS.some((s2) => id.includes(s2)) ? basename21(sourceDir) : id;
180386
181148
  }
180387
181149
  function templateNameError(name, from) {
180388
181150
  if (name.startsWith(TEMPLATE_APP_PREFIX)) {
@@ -180404,8 +181166,8 @@ function materializeForPreview(appDir3, slug, displayName2) {
180404
181166
  const forBuild = Object.fromEntries(
180405
181167
  Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
180406
181168
  );
180407
- const repoRoot2 = resolve62(fileURLToPath29(new URL("../../..", import.meta.url)));
180408
- const root = join85(repoRoot2, "node_modules", ".cache", "himi-template-preview");
181169
+ const repoRoot2 = resolve64(fileURLToPath29(new URL("../../..", import.meta.url)));
181170
+ const root = join87(repoRoot2, "node_modules", ".cache", "himi-template-preview");
180409
181171
  const stillRunning = (pid) => {
180410
181172
  try {
180411
181173
  process.kill(pid, 0);
@@ -180419,35 +181181,35 @@ function materializeForPreview(appDir3, slug, displayName2) {
180419
181181
  if (!entry.isDirectory()) continue;
180420
181182
  const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
180421
181183
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
180422
- rmSync22(join85(root, entry.name), { recursive: true, force: true });
181184
+ rmSync23(join87(root, entry.name), { recursive: true, force: true });
180423
181185
  }
180424
181186
  }
180425
181187
  } catch {
180426
181188
  }
180427
- const dest = join85(root, `${slug}-${process.pid}`);
180428
- rmSync22(dest, { recursive: true, force: true });
181189
+ const dest = join87(root, `${slug}-${process.pid}`);
181190
+ rmSync23(dest, { recursive: true, force: true });
180429
181191
  mkdirSync42(dest, { recursive: true });
180430
181192
  try {
180431
181193
  materializeSource(forBuild, displayName2, dest, slug);
180432
181194
  } catch (e2) {
180433
- rmSync22(dest, { recursive: true, force: true });
181195
+ rmSync23(dest, { recursive: true, force: true });
180434
181196
  throw e2;
180435
181197
  }
180436
181198
  return dest;
180437
181199
  }
180438
181200
  async function appId(dir) {
180439
181201
  try {
180440
- const { readFileSync: readFileSync103 } = await import("node:fs");
180441
- const m2 = JSON.parse(readFileSync103(join85(dir, "himalaya.content.json"), "utf8"));
181202
+ const { readFileSync: readFileSync104 } = await import("node:fs");
181203
+ const m2 = JSON.parse(readFileSync104(join87(dir, "himalaya.content.json"), "utf8"));
180442
181204
  if (m2.name) return m2.name;
180443
181205
  } catch {
180444
181206
  }
180445
- return basename19(dir);
181207
+ return basename21(dir);
180446
181208
  }
180447
181209
  async function contentVisibility(dir) {
180448
181210
  try {
180449
- const { readFileSync: readFileSync103 } = await import("node:fs");
180450
- const m2 = JSON.parse(readFileSync103(join85(dir, "himalaya.content.json"), "utf8"));
181211
+ const { readFileSync: readFileSync104 } = await import("node:fs");
181212
+ const m2 = JSON.parse(readFileSync104(join87(dir, "himalaya.content.json"), "utf8"));
180451
181213
  if (m2.visibility === "public" || m2.visibility === "unlisted") return m2.visibility;
180452
181214
  } catch {
180453
181215
  }
@@ -180717,7 +181479,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
180717
181479
  return 0;
180718
181480
  }
180719
181481
  case "agent-init": {
180720
- const dir = resolve62(str9(flags.dir) ?? process.cwd());
181482
+ const dir = resolve64(str9(flags.dir) ?? process.cwd());
180721
181483
  const { seedAgentFiles: seedAgentFiles2, NotAContentPackage: NotAContentPackage2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
180722
181484
  let res;
180723
181485
  try {
@@ -180739,7 +181501,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
180739
181501
  ...res.removed.length ? { removed: res.removed, note: "older copies at the app root, moved to .himi/legacy-agent-files/ (a backup, in case one became app code) \u2014 the current ones live in .agents/skills/himalaya/" } : {},
180740
181502
  // In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
180741
181503
  // hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
180742
- ...existsSync81(join85(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
181504
+ ...existsSync82(join87(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
180743
181505
  ...res.skipped.length ? { skipped: res.skipped } : {},
180744
181506
  portalUrl: idx.portalUrl
180745
181507
  });
@@ -180762,7 +181524,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
180762
181524
  try {
180763
181525
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
180764
181526
  const bres = await buildContentForValidation2(dir, { resolution });
180765
- out2 = mkdtempSync5(join85(tmpdir6(), "himi-ux-record-"));
181527
+ out2 = mkdtempSync6(join87(tmpdir7(), "himi-ux-record-"));
180766
181528
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
180767
181529
  const outcome = await buildReleaseFromContent2(dir, out2, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
180768
181530
  const releaseId = outcome.manifest.releaseId;
@@ -180775,7 +181537,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
180775
181537
  return null;
180776
181538
  } finally {
180777
181539
  if (out2 !== void 0) try {
180778
- rmSync22(out2, { recursive: true, force: true });
181540
+ rmSync23(out2, { recursive: true, force: true });
180779
181541
  } catch {
180780
181542
  }
180781
181543
  }
@@ -180941,7 +181703,7 @@ async function producedWidgetFamilies(dir) {
180941
181703
  let js2;
180942
181704
  for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
180943
181705
  try {
180944
- js2 = readFileSync102(join85(outDir, candidate), "utf8");
181706
+ js2 = readFileSync103(join87(outDir, candidate), "utf8");
180945
181707
  break;
180946
181708
  } catch {
180947
181709
  }
@@ -180972,7 +181734,7 @@ async function producedWidgetFamilies(dir) {
180972
181734
  }
180973
181735
  return { families, source: "dist/bundles" };
180974
181736
  }
180975
- var boardOpen = (dir) => existsSync81(join85(dir, ".himi", "studio", "index.html"));
181737
+ var boardOpen = (dir) => existsSync82(join87(dir, ".himi", "studio", "index.html"));
180976
181738
  var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
180977
181739
  async function leaveForBoard(dir, record2, value) {
180978
181740
  if (!boardOpen(dir)) return;
@@ -180996,7 +181758,7 @@ async function liveMapFor(dir) {
180996
181758
  }
180997
181759
  var commandScratch = new AsyncLocalStorage2();
180998
181760
  function commandScratchDir(prefix) {
180999
- const dir = mkdtempSync5(join85(tmpdir6(), prefix));
181761
+ const dir = mkdtempSync6(join87(tmpdir7(), prefix));
181000
181762
  commandScratch.getStore()?.push(dir);
181001
181763
  return dir;
181002
181764
  }
@@ -181007,7 +181769,7 @@ async function run(argv, io2 = defaultIO, deps = {}) {
181007
181769
  code = await commandScratch.run(scratch, () => runCommand(argv, io2, deps));
181008
181770
  } finally {
181009
181771
  for (const dir of scratch) try {
181010
- rmSync22(dir, { recursive: true, force: true });
181772
+ rmSync23(dir, { recursive: true, force: true });
181011
181773
  } catch {
181012
181774
  }
181013
181775
  }
@@ -181307,7 +182069,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
181307
182069
  return 2;
181308
182070
  }
181309
182071
  const template = str9(flags.template);
181310
- const parentDir = resolve62(str9(flags.dir) ?? process.cwd());
182072
+ const parentDir = resolve64(str9(flags.dir) ?? process.cwd());
181311
182073
  const base44AppId = flags["base44-app-id"] === void 0 ? void 0 : String(flags["base44-app-id"]);
181312
182074
  const base44AppUrl = flags["base44-app-url"] === void 0 ? void 0 : String(flags["base44-app-url"]);
181313
182075
  if (base44AppUrl !== void 0) {
@@ -181350,7 +182112,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
181350
182112
  const owed = openApprovals2(readApprovals2(dir).events).length;
181351
182113
  next.push(`carried the planning journal into the app (${carried.join(", ")}${owed ? `; ${owed} approval${owed === 1 ? "" : "s"} still owed` : ""}) \u2014 \`himi progress --brief\` there shows it`);
181352
182114
  }
181353
- const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) => existsSync81(join85(parentDir, f2)));
182115
+ const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) => existsSync82(join87(parentDir, f2)));
181354
182116
  if (planInParent.length) {
181355
182117
  next.push(`${planInParent.join(" and ")} in ${parentDir} ${planInParent.length > 1 ? "are" : "is"} not the app's \u2014 if that is the approved plan, move it over the template's boilerplate in ${dir}`);
181356
182118
  }
@@ -181511,13 +182273,13 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181511
182273
  if (adding) {
181512
182274
  const from = str9(flags.from);
181513
182275
  if (!from) throw new TrimRefusal2('--add <id> needs --from <file> holding the whole new SCREENS entry (` "<id>": { "screenId": "<id>", \u2026 },`)');
181514
- print(adopt.addScreen(dir, adding, readFileSync102(from, "utf8"), { parent: str9(flags.parent), tab: str9(flags.tab), displayName: str9(flags["display-name"]) }));
182276
+ print(adopt.addScreen(dir, adding, readFileSync103(from, "utf8"), { parent: str9(flags.parent), tab: str9(flags.tab), displayName: str9(flags["display-name"]) }));
181515
182277
  return 0;
181516
182278
  }
181517
182279
  if (target) {
181518
182280
  const from = str9(flags.from);
181519
182281
  if (!from) throw new TrimRefusal2("--write <id> needs --from <file> holding the whole entry, as --show prints it");
181520
- print(adopt.replaceScreen(dir, target, readFileSync102(from, "utf8")));
182282
+ print(adopt.replaceScreen(dir, target, readFileSync103(from, "utf8")));
181521
182283
  return 0;
181522
182284
  }
181523
182285
  if (show) {
@@ -181599,7 +182361,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181599
182361
  const { keepFromSpec: keepFromSpec2 } = await Promise.resolve().then(() => (init_template_adopt(), template_adopt_exports));
181600
182362
  const dir = contentDir(flags);
181601
182363
  try {
181602
- const spec = keepFromSpec2(dir, str9(flags["from-spec"]) ?? join85(dir, "SPEC.md"));
182364
+ const spec = keepFromSpec2(dir, str9(flags["from-spec"]) ?? join87(dir, "SPEC.md"));
181603
182365
  const own5 = typeof keep === "string" ? keep.split(",").map((k2) => k2.trim()).filter(Boolean) : [];
181604
182366
  keep = [.../* @__PURE__ */ new Set([...spec.keep, ...own5])].join(",");
181605
182367
  fromSpec = { fromSpec: {
@@ -181640,7 +182402,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181640
182402
  const result = { ...outcome.result, ...fromSpec };
181641
182403
  const adoptDir = contentDir(flags);
181642
182404
  const kept = flags["dry-run"] !== true && (outcome.code === 0 || outcome.result.forcedKeep === true);
181643
- if (kept && existsSync81(join85(adoptDir, adoptBits.ADOPT_FILE))) {
182405
+ if (kept && existsSync82(join87(adoptDir, adoptBits.ADOPT_FILE))) {
181644
182406
  try {
181645
182407
  const inv = adoptBits.inspectApp(adoptDir);
181646
182408
  adoptBits.writeInventory(adoptDir, inv, { companions: "if-missing" });
@@ -181665,11 +182427,11 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181665
182427
  return 2;
181666
182428
  }
181667
182429
  }
181668
- const appDir3 = resolve62(str9(flags.dir) ?? process.cwd());
181669
- const sourceDir = resolve62(str9(flags["source-dir"]) ?? appDir3);
182430
+ const appDir3 = resolve64(str9(flags.dir) ?? process.cwd());
182431
+ const sourceDir = resolve64(str9(flags["source-dir"]) ?? appDir3);
181670
182432
  let meta;
181671
182433
  try {
181672
- meta = JSON.parse(readFileSync102(join85(sourceDir, TEMPLATE_META_FILE), "utf8"));
182434
+ meta = JSON.parse(readFileSync103(join87(sourceDir, TEMPLATE_META_FILE), "utf8"));
181673
182435
  } catch {
181674
182436
  io2.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>)` }));
181675
182437
  return 2;
@@ -181679,7 +182441,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181679
182441
  return 2;
181680
182442
  }
181681
182443
  try {
181682
- const appearance = extractTemplateAppearance(JSON.parse(readFileSync102(join85(sourceDir, "tokens.json"), "utf8")));
182444
+ const appearance = extractTemplateAppearance(JSON.parse(readFileSync103(join87(sourceDir, "tokens.json"), "utf8")));
181683
182445
  meta = { ...appearance, ...meta };
181684
182446
  } catch {
181685
182447
  }
@@ -181701,14 +182463,14 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181701
182463
  const force = flags.force === true;
181702
182464
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
181703
182465
  const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
181704
- const out2 = mkdtempSync5(join85(tmpdir6(), "himi-template-"));
182466
+ const out2 = mkdtempSync6(join87(tmpdir7(), "himi-template-"));
181705
182467
  publishScratch.push(out2);
181706
182468
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
181707
182469
  const outcome = await buildReleaseFromContent2(buildDir, out2, {
181708
182470
  ...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
181709
182471
  collect: { lint: true, strict }
181710
182472
  });
181711
- const scaffoldSourceFindings = resolve62(sourceDir) === resolve62(appDir3) ? [] : [
182473
+ const scaffoldSourceFindings = resolve64(sourceDir) === resolve64(appDir3) ? [] : [
181712
182474
  ...(await Promise.resolve().then(() => (init_capabilities(), capabilities_exports))).capabilityConfigFindings(sourceDir, buildDir),
181713
182475
  ...tokenColorIssues(sourceDir),
181714
182476
  ...surfaceIssues(sourceDir, void 0, strict),
@@ -181754,13 +182516,13 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181754
182516
  }));
181755
182517
  return 1;
181756
182518
  }
181757
- const iconPath = str9(flags.icon) ? resolve62(str9(flags.icon)) : templateIconPath(name);
182519
+ const iconPath = str9(flags.icon) ? resolve64(str9(flags.icon)) : templateIconPath(name);
181758
182520
  let iconHash;
181759
182521
  if (iconPath) {
181760
182522
  try {
181761
- const bytes2 = readFileSync102(iconPath);
182523
+ const bytes2 = readFileSync103(iconPath);
181762
182524
  payload.icon = bytes2.toString("base64");
181763
- iconHash = createHash44("sha256").update(bytes2).digest("hex");
182525
+ iconHash = createHash45("sha256").update(bytes2).digest("hex");
181764
182526
  } catch {
181765
182527
  }
181766
182528
  }
@@ -181936,7 +182698,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
181936
182698
  } finally {
181937
182699
  for (const dir of publishScratch) {
181938
182700
  try {
181939
- rmSync22(dir, { recursive: true, force: true });
182701
+ rmSync23(dir, { recursive: true, force: true });
181940
182702
  } catch (e2) {
181941
182703
  io2.error(JSON.stringify({ warning: `could not remove temp dir ${dir}: ${e2.message}` }));
181942
182704
  }
@@ -182062,7 +182824,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
182062
182824
  const path2 = dpxSessionTokenPath();
182063
182825
  let raw;
182064
182826
  try {
182065
- raw = readFileSync102(path2, "utf8");
182827
+ raw = readFileSync103(path2, "utf8");
182066
182828
  } catch {
182067
182829
  throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
182068
182830
  }
@@ -182193,11 +182955,11 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
182193
182955
  return 1;
182194
182956
  }
182195
182957
  const { himiPluginFiles: himiPluginFiles2 } = await Promise.resolve().then(() => (init_claude_plugin(), claude_plugin_exports));
182196
- const dir = resolve62(out2);
182958
+ const dir = resolve64(out2);
182197
182959
  const files = himiPluginFiles2(skills.skillMd);
182198
182960
  for (const f2 of files) {
182199
- mkdirSync42(dirname46(join85(dir, f2.path)), { recursive: true });
182200
- writeFileSync39(join85(dir, f2.path), f2.text);
182961
+ mkdirSync42(dirname48(join87(dir, f2.path)), { recursive: true });
182962
+ writeFileSync39(join87(dir, f2.path), f2.text);
182201
182963
  }
182202
182964
  print({ ok: true, dir, files: files.map((f2) => f2.path), next: [`claude plugin validate ${dir}`, `claude --plugin-dir ${dir}`] });
182203
182965
  return 0;
@@ -182207,22 +182969,22 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
182207
182969
  run,
182208
182970
  version: cliVersion(),
182209
182971
  withFiles: flags["with-files"] === true,
182210
- ...process.env.HIMI_WORKSPACE ? { workspace: resolve62(process.env.HIMI_WORKSPACE) } : {}
182972
+ ...process.env.HIMI_WORKSPACE ? { workspace: resolve64(process.env.HIMI_WORKSPACE) } : {}
182211
182973
  });
182212
182974
  return 0;
182213
182975
  }
182214
182976
  case "studio": {
182215
182977
  const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
182216
182978
  const dir = contentDir(flags);
182217
- if (!existsSync81(join85(dir, "himalaya.content.json"))) {
182979
+ if (!existsSync82(join87(dir, "himalaya.content.json"))) {
182218
182980
  io2.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
182219
182981
  return 2;
182220
182982
  }
182221
182983
  if (pos[1] === "reel") {
182222
182984
  const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
182223
- const out2 = resolve62(str9(flags.out) ?? join85(dir, ".himi", "making-of.html"));
182985
+ const out2 = resolve64(str9(flags.out) ?? join87(dir, ".himi", "making-of.html"));
182224
182986
  const { html, plan } = buildReel2(dir);
182225
- mkdirSync42(dirname46(out2), { recursive: true });
182987
+ mkdirSync42(dirname48(out2), { recursive: true });
182226
182988
  writeFileSync39(out2, html);
182227
182989
  const { pathToFileURL: pathToFileURL9 } = await import("node:url");
182228
182990
  const url2 = pathToFileURL9(out2).href;
@@ -182231,7 +182993,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
182231
182993
  const { openUrl: openUrl2 } = await Promise.resolve().then(() => (init_open_url(), open_url_exports));
182232
182994
  openUrl2(url2);
182233
182995
  }
182234
- const handover = { file: out2, hint: `hand ${basename19(out2)} to the owner at the handover \u2014 one self-contained page of their app taking shape; send it beside the preview link, never instead of it` };
182996
+ const handover = { file: out2, hint: `hand ${basename21(out2)} to the owner at the handover \u2014 one self-contained page of their app taking shape; send it beside the preview link, never instead of it` };
182235
182997
  const report3 = {
182236
182998
  ok: true,
182237
182999
  file: out2,
@@ -182292,7 +183054,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
182292
183054
  } = await Promise.resolve().then(() => (init_progress(), progress_exports));
182293
183055
  const dir = contentDir(flags);
182294
183056
  const journal2 = journalPath2(dir);
182295
- const isContentPackage = existsSync81(join85(dir, "himalaya.content.json"));
183057
+ const isContentPackage = existsSync82(join87(dir, "himalaya.content.json"));
182296
183058
  const hint = isContentPackage ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
182297
183059
  const message = pos.slice(1).join(" ").trim();
182298
183060
  const approvalFlags = ["approve", "done", "drop"].filter((f2) => flags[f2] !== void 0);
@@ -182444,7 +183206,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
182444
183206
  case "test": {
182445
183207
  const dir = contentDir(flags);
182446
183208
  const structuredOutput = flags.json === true || io2.isTTY !== true;
182447
- if (existsSync81(join85(dir, "functions"))) {
183209
+ if (existsSync82(join87(dir, "functions"))) {
182448
183210
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
182449
183211
  const loaded = await loadFunctionsApp2(dir);
182450
183212
  const results = [];
@@ -182576,7 +183338,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
182576
183338
  io2.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
182577
183339
  return 2;
182578
183340
  }
182579
- const sources = collectWorkerSources2(join85(dir, "tier5-src"), screen.bundleName);
183341
+ const sources = collectWorkerSources2(join87(dir, "tier5-src"), screen.bundleName);
182580
183342
  if (!sources) {
182581
183343
  io2.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
182582
183344
  return 2;
@@ -182754,7 +183516,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
182754
183516
  const sp = await runShotsPass2({
182755
183517
  descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
182756
183518
  tokens: outcome.tokens,
182757
- outDir: join85(dir, ".himi", "shots"),
183519
+ outDir: join87(dir, ".himi", "shots"),
182758
183520
  width: 390,
182759
183521
  layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
182760
183522
  ...budgetMs ? { budgetMs } : {},
@@ -182765,7 +183527,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
182765
183527
  renderPngBatch: renderPngBatch2,
182766
183528
  isUnserved: isUnservedRequest2,
182767
183529
  writePng: (path2, base64) => writePngFile(path2, base64),
182768
- clearDir: (d2) => rmSync22(d2, { recursive: true, force: true })
183530
+ clearDir: (d2) => rmSync23(d2, { recursive: true, force: true })
182769
183531
  }
182770
183532
  });
182771
183533
  writtenShots = sp.written;
@@ -182794,7 +183556,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
182794
183556
  releaseId: result.releaseId,
182795
183557
  releasePayload: release2,
182796
183558
  descriptors: attestedDescriptors,
182797
- screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join85(dir, ".himi", "shots", name)])),
183559
+ screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join87(dir, ".himi", "shots", name)])),
182798
183560
  coverage: {
182799
183561
  screens: crawledScreens.size,
182800
183562
  actionsDispatched: result.actions.exercised,
@@ -182919,7 +183681,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
182919
183681
  return 2;
182920
183682
  }
182921
183683
  try {
182922
- const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync102(stateArg.replace(/^@/, ""), "utf8");
183684
+ const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync103(stateArg.replace(/^@/, ""), "utf8");
182923
183685
  injectedState = JSON.parse(raw);
182924
183686
  } catch (e2) {
182925
183687
  io2.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e2.message}` }));
@@ -182934,7 +183696,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
182934
183696
  return 2;
182935
183697
  }
182936
183698
  try {
182937
- const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync102(inputArg.replace(/^@/, ""), "utf8");
183699
+ const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync103(inputArg.replace(/^@/, ""), "utf8");
182938
183700
  const parsed = JSON.parse(raw);
182939
183701
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
182940
183702
  injectedInput = parsed;
@@ -183016,11 +183778,11 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
183016
183778
  const diagnostics = (outcome.lint ?? []).find((s2) => s2.screenId === screenId)?.issues ?? [];
183017
183779
  let pngFile;
183018
183780
  let attestationPngFile;
183019
- const shotPath = join85(dir, ".himi", "shots", `${screenId}.png`);
183781
+ const shotPath = join87(dir, ".himi", "shots", `${screenId}.png`);
183020
183782
  const pngTarget = typeof flags.png === "string" ? str9(flags.png) : flags.png === true ? shotPath : void 0;
183021
183783
  if (pngTarget && r2.pngBase64) {
183022
183784
  pngFile = writePngFile(pngTarget, r2.pngBase64);
183023
- attestationPngFile = resolve62(pngTarget) === resolve62(shotPath) ? pngFile : writePngFile(shotPath, r2.pngBase64);
183785
+ attestationPngFile = resolve64(pngTarget) === resolve64(shotPath) ? pngFile : writePngFile(shotPath, r2.pngBase64);
183024
183786
  }
183025
183787
  if (renderWidth !== void 0 && r2.renderable) {
183026
183788
  recordRenderWidth(dir, {
@@ -183367,7 +184129,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
183367
184129
  return 2;
183368
184130
  }
183369
184131
  const renamed = str9(flags.name);
183370
- const dest = resolve62(str9(flags.out) ?? process.cwd(), renamed ?? wanted);
184132
+ const dest = resolve64(str9(flags.out) ?? process.cwd(), renamed ?? wanted);
183371
184133
  const replace = flags.replace === true;
183372
184134
  const force = replace || flags.force === true;
183373
184135
  const linked = symlinkDestinationIssue(dest);
@@ -183375,7 +184137,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
183375
184137
  io2.error(JSON.stringify(linked));
183376
184138
  return 1;
183377
184139
  }
183378
- if (existsSync81(dest)) {
184140
+ if (existsSync82(dest)) {
183379
184141
  if (!statSync23(dest).isDirectory()) {
183380
184142
  io2.error(JSON.stringify({
183381
184143
  error: `${dest} exists and is not a directory`,
@@ -183388,7 +184150,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
183388
184150
  io2.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" }));
183389
184151
  return 1;
183390
184152
  }
183391
- if (replace && occupied && !existsSync81(join85(dest, "himalaya.content.json"))) {
184153
+ if (replace && occupied && !existsSync82(join87(dest, "himalaya.content.json"))) {
183392
184154
  io2.error(JSON.stringify({
183393
184155
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
183394
184156
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -183557,7 +184319,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
183557
184319
  const manifest = outcome.manifest;
183558
184320
  const payload = await loadReleaseFromDir(declared, out2);
183559
184321
  const { shellQuote: shellQuote3 } = await Promise.resolve().then(() => (init_shell_quote(), shell_quote_exports));
183560
- const contentRel = relative15(process.cwd(), dir) || ".";
184322
+ const contentRel = relative16(process.cwd(), dir) || ".";
183561
184323
  const contentArg2 = shellQuote3(contentRel);
183562
184324
  if (onlyRaw !== void 0) {
183563
184325
  const onlyDraft = flags.draft === true;
@@ -183619,7 +184381,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
183619
184381
  let localSourceHash;
183620
184382
  try {
183621
184383
  const { collectAppSource: collectAppSource2, zipAppSource: zipAppSource2 } = await Promise.resolve().then(() => (init_app_source(), app_source_exports));
183622
- localSourceHash = createHash44("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
184384
+ localSourceHash = createHash45("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
183623
184385
  } catch {
183624
184386
  }
183625
184387
  return runReleasePatch({
@@ -184047,7 +184809,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184047
184809
  return 2;
184048
184810
  }
184049
184811
  try {
184050
- const res = writePack(resolve62(releaseDir), only, resolve62(str9(flags.out) ?? process.cwd()));
184812
+ const res = writePack(resolve64(releaseDir), only, resolve64(str9(flags.out) ?? process.cwd()));
184051
184813
  print({
184052
184814
  ok: true,
184053
184815
  app: res.app,
@@ -184096,7 +184858,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184096
184858
  }
184097
184859
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
184098
184860
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
184099
- const built = mkdtempSync5(join85(tmpdir6(), "himi-pack-"));
184861
+ const built = mkdtempSync6(join87(tmpdir7(), "himi-pack-"));
184100
184862
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
184101
184863
  const outcome = await buildReleaseFromContent2(dir, built, {
184102
184864
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -184115,12 +184877,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184115
184877
  ...await navIssues2(dir, strict)
184116
184878
  ]);
184117
184879
  if (hasErrors && !force) {
184118
- rmSync22(built, { recursive: true, force: true });
184880
+ rmSync23(built, { recursive: true, force: true });
184119
184881
  print({ ...report3, packed: false, hint: "lint found errors \u2014 fix them, or re-run `himi pack --force` to pack anyway" });
184120
184882
  return 1;
184121
184883
  }
184122
184884
  try {
184123
- const res = writePack(built, app, resolve62(str9(flags.out) ?? dir), sourceArchive);
184885
+ const res = writePack(built, app, resolve64(str9(flags.out) ?? dir), sourceArchive);
184124
184886
  print({
184125
184887
  ok: true,
184126
184888
  app: res.app,
@@ -184151,7 +184913,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184151
184913
  io2.error(JSON.stringify({ error: e2.message }));
184152
184914
  return 1;
184153
184915
  } finally {
184154
- rmSync22(built, { recursive: true, force: true });
184916
+ rmSync23(built, { recursive: true, force: true });
184155
184917
  }
184156
184918
  }
184157
184919
  // ---- himi import — turn a dev .himi back into an editable content package ----
@@ -184165,7 +184927,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184165
184927
  const { HIMI_PACKAGE_SOURCE_PATH: HIMI_PACKAGE_SOURCE_PATH2, isSafeAppId: isSafeAppId2, packageContents: packageContents2 } = await Promise.resolve().then(() => (init_himi_package(), himi_package_exports));
184166
184928
  let opened;
184167
184929
  try {
184168
- opened = openPackageFile2(resolve62(file2));
184930
+ opened = openPackageFile2(resolve64(file2));
184169
184931
  } catch (e2) {
184170
184932
  io2.error(JSON.stringify({ error: e2.message }));
184171
184933
  return 1;
@@ -184178,7 +184940,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184178
184940
  io2.error(JSON.stringify({
184179
184941
  ok: false,
184180
184942
  error: "app_source_not_in_package",
184181
- detail: `${resolve62(file2)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
184943
+ detail: `${resolve64(file2)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
184182
184944
  hint: "re-pack it from the content package with `himi pack --dev`, or restore from the serve plane with `himi pull <app>`"
184183
184945
  }));
184184
184946
  return 1;
@@ -184201,7 +184963,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184201
184963
  return 1;
184202
184964
  }
184203
184965
  }
184204
- const dest = resolve62(str9(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
184966
+ const dest = resolve64(str9(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
184205
184967
  const issue2 = restoreDestinationIssue(dest, flags.force === true);
184206
184968
  if (issue2) {
184207
184969
  io2.error(JSON.stringify(issue2));
@@ -184288,7 +185050,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184288
185050
  }
184289
185051
  try {
184290
185052
  const { openPackageFile: openPackageFile2 } = await Promise.resolve().then(() => (init_pack(), pack_exports));
184291
- const opened = openPackageFile2(resolve62(file2));
185053
+ const opened = openPackageFile2(resolve64(file2));
184292
185054
  if (!opened.validation.ok || !opened.header) {
184293
185055
  io2.error(JSON.stringify({ error: "refusing to share an invalid package", issues: opened.validation.errors }));
184294
185056
  return 1;
@@ -184298,12 +185060,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184298
185060
  io2.error(JSON.stringify({
184299
185061
  ok: false,
184300
185062
  error: "refusing to share a package that carries the app's source",
184301
- detail: `${resolve62(file2)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
185063
+ detail: `${resolve64(file2)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
184302
185064
  hint: "share a release package instead (`himi pack` with no --dev), or hand the dev package over directly"
184303
185065
  }));
184304
185066
  return 1;
184305
185067
  }
184306
- const archive = readFileSync102(resolve62(file2));
185068
+ const archive = readFileSync103(resolve64(file2));
184307
185069
  const result = await client2().createPackageShare({
184308
185070
  app: opened.header.app,
184309
185071
  releaseId: opened.header.releaseId,
@@ -184400,11 +185162,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184400
185162
  const app = await appId(dir2);
184401
185163
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
184402
185164
  const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
184403
- temp = mkdtempSync5(join85(tmpdir6(), "himi-run-build-"));
185165
+ temp = mkdtempSync6(join87(tmpdir7(), "himi-run-build-"));
184404
185166
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
184405
185167
  const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
184406
185168
  servedMissing = initial.missingBundles;
184407
- source = join85(temp, app);
185169
+ source = join87(temp, app);
184408
185170
  }
184409
185171
  const chromeArg = str9(flags.chrome) ?? "preview";
184410
185172
  if (chromeArg !== "preview" && chromeArg !== "app") {
@@ -184443,7 +185205,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184443
185205
  if (!recordKit) return;
184444
185206
  startedAt = (/* @__PURE__ */ new Date()).toISOString();
184445
185207
  const failure = record2(served2, { ok: true, at: startedAt });
184446
- if (!recorded) io2.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join85(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
185208
+ if (!recorded) io2.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join87(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
184447
185209
  await refreshBoard();
184448
185210
  };
184449
185211
  const retract = async () => {
@@ -184466,9 +185228,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184466
185228
  });
184467
185229
  await announce(run2);
184468
185230
  print({ ok: true, app: run2.app, url: run2.url, port: run2.port, plane: "browser" });
184469
- await new Promise((resolve63) => {
185231
+ await new Promise((resolve65) => {
184470
185232
  const stop = () => {
184471
- void retract().catch((e2) => io2.error(JSON.stringify({ run: "stop_cleanup_failed", message: e2.message }))).finally(() => run2.close().finally(() => resolve63()));
185233
+ void retract().catch((e2) => io2.error(JSON.stringify({ run: "stop_cleanup_failed", message: e2.message }))).finally(() => run2.close().finally(() => resolve65()));
184472
185234
  };
184473
185235
  dropEarlySignals?.();
184474
185236
  process.once("SIGINT", stop);
@@ -184479,7 +185241,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184479
185241
  const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
184480
185242
  const hhpPreviewRoute = watch2 ? (await Promise.resolve().then(() => (init_hhp_preview(), hhp_preview_exports))).hhpPreviewResponse : null;
184481
185243
  const bus = watchKit ? new watchKit.ReloadBus() : void 0;
184482
- if (watch2) served = mkdtempSync5(join85(tmpdir6(), "himi-run-served-"));
185244
+ if (watch2) served = mkdtempSync6(join87(tmpdir7(), "himi-run-served-"));
184483
185245
  const running = await runPackage2(source, {
184484
185246
  port,
184485
185247
  chrome: chromeArg,
@@ -184508,8 +185270,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184508
185270
  await announce(running);
184509
185271
  if (watchKit && bus) {
184510
185272
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
184511
- const live3 = join85(running.releaseRoot, running.app);
184512
- const manifestOf = (tree) => JSON.parse(readFileSync102(join85(tree, "release-manifest.json"), "utf8"));
185273
+ const live3 = join87(running.releaseRoot, running.app);
185274
+ const manifestOf = (tree) => JSON.parse(readFileSync103(join87(tree, "release-manifest.json"), "utf8"));
184513
185275
  let current = manifestOf(live3);
184514
185276
  const failed3 = async (message) => {
184515
185277
  if (stopping) return;
@@ -184520,7 +185282,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184520
185282
  };
184521
185283
  rebuild = watchKit.serialize(async () => {
184522
185284
  const t0 = Date.now();
184523
- const next = mkdtempSync5(join85(tmpdir6(), "himi-run-build-"));
185285
+ const next = mkdtempSync6(join87(tmpdir7(), "himi-run-build-"));
184524
185286
  try {
184525
185287
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
184526
185288
  if (bres.compileErrors.length) {
@@ -184537,18 +185299,18 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184537
185299
  return;
184538
185300
  }
184539
185301
  if (stopping) return;
184540
- const fresh = manifestOf(join85(next, running.app));
185302
+ const fresh = manifestOf(join87(next, running.app));
184541
185303
  const diff = watchKit.diffReleases(current, fresh);
184542
185304
  const { describeChanges: describeChanges2, headline: headline2 } = await Promise.resolve().then(() => (init_build_changes(), build_changes_exports));
184543
- const changes = describeChanges2(live3, join85(next, running.app), diff);
185305
+ const changes = describeChanges2(live3, join87(next, running.app), diff);
184544
185306
  const retired = `${live3}.retired-${Date.now()}`;
184545
- renameSync12(live3, retired);
185307
+ renameSync13(live3, retired);
184546
185308
  try {
184547
- renameSync12(join85(next, running.app), live3);
185309
+ renameSync13(join87(next, running.app), live3);
184548
185310
  } catch {
184549
- cpSync3(join85(next, running.app), live3, { recursive: true });
185311
+ cpSync3(join87(next, running.app), live3, { recursive: true });
184550
185312
  }
184551
- rmSync22(retired, { recursive: true, force: true });
185313
+ rmSync23(retired, { recursive: true, force: true });
184552
185314
  current = fresh;
184553
185315
  servedMissing = outcome.missingBundles;
184554
185316
  for (const [event, data] of watchKit.reloadEvents(diff)) bus.publish(event, data);
@@ -184558,7 +185320,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184558
185320
  } catch (e2) {
184559
185321
  await failed3(e2.message.split("\n")[0]);
184560
185322
  } finally {
184561
- rmSync22(next, { recursive: true, force: true });
185323
+ rmSync23(next, { recursive: true, force: true });
184562
185324
  }
184563
185325
  });
184564
185326
  watcher2 = watchKit.watchContent(dir, () => {
@@ -184629,9 +185391,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
184629
185391
  } finally {
184630
185392
  dropEarlySignals?.();
184631
185393
  dropInitRecord?.();
184632
- if (temp) rmSync22(temp, { recursive: true, force: true });
184633
- if (served) rmSync22(served, { recursive: true, force: true });
184634
- if (browserCopy) rmSync22(browserCopy, { recursive: true, force: true });
185394
+ if (temp) rmSync23(temp, { recursive: true, force: true });
185395
+ if (served) rmSync23(served, { recursive: true, force: true });
185396
+ if (browserCopy) rmSync23(browserCopy, { recursive: true, force: true });
184635
185397
  }
184636
185398
  }
184637
185399
  case "preview": {
@@ -185173,7 +185935,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
185173
185935
  io2.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
185174
185936
  return 2;
185175
185937
  }
185176
- if (!existsSync81(file2)) {
185938
+ if (!existsSync82(file2)) {
185177
185939
  io2.error(JSON.stringify({ error: `no such file: ${file2}` }));
185178
185940
  return 2;
185179
185941
  }
@@ -185229,7 +185991,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
185229
185991
  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."
185230
185992
  };
185231
185993
  if (kind === "tokens" || kind === "app-config") {
185232
- const body = readFileSync102(file2, "utf8");
185994
+ const body = readFileSync103(file2, "utf8");
185233
185995
  const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
185234
185996
  return runReleasePatch({
185235
185997
  ...common,
@@ -185244,7 +186006,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
185244
186006
  io2.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
185245
186007
  return 2;
185246
186008
  }
185247
- const descriptor = readFileSync102(file2, "utf8");
186009
+ const descriptor = readFileSync103(file2, "utf8");
185248
186010
  try {
185249
186011
  JSON.parse(descriptor);
185250
186012
  } catch (e2) {
@@ -185284,8 +186046,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
185284
186046
  extra: { kind, screen: id, file: { path: file2, bytes: Buffer.byteLength(descriptor, "utf8") } }
185285
186047
  });
185286
186048
  }
185287
- const bytes2 = readFileSync102(file2);
185288
- const sha2 = createHash44("sha256").update(bytes2).digest("hex");
186049
+ const bytes2 = readFileSync103(file2);
186050
+ const sha2 = createHash45("sha256").update(bytes2).digest("hex");
185289
186051
  const forScreens = (str9(flags["for-screen"]) ?? "").split(",").map((s2) => s2.trim()).filter(Boolean);
185290
186052
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
185291
186053
  io2.error(JSON.stringify({ ok: false, error: "no_rebind_takes_no_value", message: "--no-rebind is a switch and takes no value; pass it bare.", usage: PATCH_USAGE }));
@@ -185428,7 +186190,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
185428
186190
  }
185429
186191
  let def;
185430
186192
  try {
185431
- const parsed = JSON.parse(arg.startsWith("@") ? readFileSync102(arg.slice(1), "utf8") : arg);
186193
+ const parsed = JSON.parse(arg.startsWith("@") ? readFileSync103(arg.slice(1), "utf8") : arg);
185432
186194
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
185433
186195
  io2.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
185434
186196
  return 2;
@@ -185710,7 +186472,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
185710
186472
  const rememberLastDist = async (jobs2) => {
185711
186473
  try {
185712
186474
  const dir = contentDir(flags);
185713
- if (!existsSync81(join85(dir, "himalaya.content.json"))) return;
186475
+ if (!existsSync82(join87(dir, "himalaya.content.json"))) return;
185714
186476
  const { lastDistFromJob: lastDistFromJob2, writeLastDist: writeLastDist2 } = await Promise.resolve().then(() => (init_capabilities(), capabilities_exports));
185715
186477
  const own5 = await appId(dir);
185716
186478
  for (const job of jobs2) {
@@ -185950,7 +186712,7 @@ ${label2}`);
185950
186712
  const platform = str9(flags.platform)?.split(",").map((p2) => p2.trim()).filter(Boolean);
185951
186713
  {
185952
186714
  const distDir = contentDir(flags);
185953
- if (existsSync81(join85(distDir, "himalaya.content.json"))) {
186715
+ if (existsSync82(join87(distDir, "himalaya.content.json"))) {
185954
186716
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
185955
186717
  const errors = issues.filter((i2) => i2.severity === "error");
185956
186718
  for (const i2 of issues.filter((i3) => i3.severity === "warning")) {
@@ -186290,7 +187052,7 @@ ${label2}`);
186290
187052
  const dpxPath = dpxSessionTokenPath();
186291
187053
  let dpx;
186292
187054
  try {
186293
- dpx = readFileSync102(dpxPath, "utf8").trim();
187055
+ dpx = readFileSync103(dpxPath, "utf8").trim();
186294
187056
  } catch {
186295
187057
  io2.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` }));
186296
187058
  return 1;
@@ -186753,7 +187515,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
186753
187515
  const path2 = dpxSessionTokenPath();
186754
187516
  let raw;
186755
187517
  try {
186756
- raw = readFileSync102(path2, "utf8");
187518
+ raw = readFileSync103(path2, "utf8");
186757
187519
  } catch {
186758
187520
  io2.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
186759
187521
  return 1;