@wix/himalaya-cli 0.1014.0 → 0.1015.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
@@ -1341,7 +1341,7 @@ function sentinelizeIdentity(body, identity) {
1341
1341
  }
1342
1342
  if (identity.name) {
1343
1343
  const re = new RegExp(`\\b(${NAME_FIELDS.join("|")})(["']?\\s*[:=]\\s*)(["'])${escapeRe(identity.name)}\\3`, "g");
1344
- out = out.replace(re, (_m, key2, sep14, q) => `${key2}${sep14}${q}__HIMI_APP_NAME__${q}`);
1344
+ out = out.replace(re, (_m, key2, sep15, q) => `${key2}${sep15}${q}__HIMI_APP_NAME__${q}`);
1345
1345
  }
1346
1346
  return out;
1347
1347
  }
@@ -2368,7 +2368,7 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
2368
2368
  tokenCache.set(cacheKey, fromEnv);
2369
2369
  return fromEnv;
2370
2370
  }
2371
- const token = await new Promise((resolve47, reject) => {
2371
+ const token = await new Promise((resolve48, reject) => {
2372
2372
  let child;
2373
2373
  try {
2374
2374
  child = spawnImpl("wix", [...args]);
@@ -2397,12 +2397,12 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
2397
2397
  child.stdout?.on("data", (d) => {
2398
2398
  out += String(d);
2399
2399
  const m = out.match(TOKEN_RE);
2400
- if (m) done(() => resolve47(m[0]));
2400
+ if (m) done(() => resolve48(m[0]));
2401
2401
  });
2402
2402
  child.stderr?.on("data", (d) => {
2403
2403
  out += String(d);
2404
2404
  const m = out.match(TOKEN_RE);
2405
- if (m) done(() => resolve47(m[0]));
2405
+ if (m) done(() => resolve48(m[0]));
2406
2406
  });
2407
2407
  child.on("error", (e) => done(() => reject(new Error(mintHelp(label2, e.message)))));
2408
2408
  child.on("exit", (code) => done(() => reject(new Error(
@@ -5345,7 +5345,6 @@ function walk(node, registry, path2, out) {
5345
5345
  var SYSTEM_FONT_FAMILY;
5346
5346
  var init_tokens = __esm({
5347
5347
  "../../core/ts/src/tokens.ts"() {
5348
- "use strict";
5349
5348
  SYSTEM_FONT_FAMILY = "$system";
5350
5349
  }
5351
5350
  });
@@ -15593,7 +15592,7 @@ async function injectRequest(listener, request) {
15593
15592
  req.headers.host ??= url.host;
15594
15593
  if (body && body.length > 0) req.push(body);
15595
15594
  req.push(null);
15596
- return await new Promise((resolve47, reject) => {
15595
+ return await new Promise((resolve48, reject) => {
15597
15596
  const streamed = () => {
15598
15597
  queueMicrotask(() => {
15599
15598
  req.emit("close");
@@ -15609,7 +15608,7 @@ async function injectRequest(listener, request) {
15609
15608
  else headers2.set(name, value);
15610
15609
  }
15611
15610
  const bodyless = out.status === 204 || out.status === 304 || request.method === "HEAD";
15612
- resolve47(new Response(bodyless ? null : out.body, { status: out.status, headers: headers2 }));
15611
+ resolve48(new Response(bodyless ? null : out.body, { status: out.status, headers: headers2 }));
15613
15612
  }, streamed);
15614
15613
  res.on("inject-error", reject);
15615
15614
  try {
@@ -16304,7 +16303,7 @@ function redactBodyString(body) {
16304
16303
  } catch {
16305
16304
  }
16306
16305
  }
16307
- return body.replace(FORM_ASSIGNMENT_RE, (m, name) => isSensitiveBodyName(name) ? `${name}=${REDACTED}` : m).replace(JSON_FIELD_RE, (m, name, sep14) => isSensitiveBodyName(name) ? `"${name}"${sep14}"${REDACTED}"` : m).replace(JSON_FIELD_UNTERMINATED_RE, (m, name, sep14) => isSensitiveBodyName(name) ? `"${name}"${sep14}"${REDACTED}` : m).replace(BEARER_RE, (_m, s) => `${s} ${REDACTED}`);
16306
+ return body.replace(FORM_ASSIGNMENT_RE, (m, name) => isSensitiveBodyName(name) ? `${name}=${REDACTED}` : m).replace(JSON_FIELD_RE, (m, name, sep15) => isSensitiveBodyName(name) ? `"${name}"${sep15}"${REDACTED}"` : m).replace(JSON_FIELD_UNTERMINATED_RE, (m, name, sep15) => isSensitiveBodyName(name) ? `"${name}"${sep15}"${REDACTED}` : m).replace(BEARER_RE, (_m, s) => `${s} ${REDACTED}`);
16308
16307
  }
16309
16308
  function createWixGatewayState() {
16310
16309
  return { mode: "record", rules: [], traffic: [], clients: /* @__PURE__ */ new Set(), seq: 0, ruleSeq: 0 };
@@ -17996,12 +17995,12 @@ function finalizeRecording(key2, rec) {
17996
17995
  if (rec.finalize) return rec.finalize;
17997
17996
  rec.finalize = (async () => {
17998
17997
  clearTimeout(rec.autoStop);
17999
- await new Promise((resolve47) => {
17998
+ await new Promise((resolve48) => {
18000
17999
  let done = false;
18001
18000
  const finish2 = () => {
18002
18001
  if (!done) {
18003
18002
  done = true;
18004
- resolve47();
18003
+ resolve48();
18005
18004
  }
18006
18005
  };
18007
18006
  rec.child.once("close", finish2);
@@ -18112,7 +18111,7 @@ var init_preview = __esm({
18112
18111
  DEVICE_LIST_TIMEOUT_MS = 5e3;
18113
18112
  defaultRunner2 = {
18114
18113
  capture(cmd, args, timeoutMs = DEFAULT_CAPTURE_TIMEOUT_MS) {
18115
- return new Promise((resolve47, reject) => {
18114
+ return new Promise((resolve48, reject) => {
18116
18115
  const child = spawn3(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
18117
18116
  const out = [];
18118
18117
  const err = [];
@@ -18134,7 +18133,7 @@ var init_preview = __esm({
18134
18133
  child.stderr.on("data", (b) => err.push(b));
18135
18134
  child.on("error", (e) => settle(reject, e));
18136
18135
  child.on("close", (code) => {
18137
- if (code === 0) settle(resolve47, Buffer.concat(out));
18136
+ if (code === 0) settle(resolve48, Buffer.concat(out));
18138
18137
  else settle(reject, new Error(`${cmd} exited ${code}: ${Buffer.concat(err).toString("utf8")}`));
18139
18138
  });
18140
18139
  });
@@ -23189,8 +23188,8 @@ function ensureCountUpRuntime() {
23189
23188
  const neg = fixed.startsWith("-");
23190
23189
  const body = neg ? fixed.slice(1) : fixed;
23191
23190
  const [int, frac] = body.split(".");
23192
- const sep14 = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
23193
- return (neg ? "-" : "") + sep14 + (frac ? "." + frac : "");
23191
+ const sep15 = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
23192
+ return (neg ? "-" : "") + sep15 + (frac ? "." + frac : "");
23194
23193
  };
23195
23194
  const animateEl = (el) => {
23196
23195
  const node = el;
@@ -28914,7 +28913,7 @@ async function stabilizePngPage(page, scheme) {
28914
28913
  const browser = globalThis;
28915
28914
  browser.document.documentElement.style.colorScheme = selected;
28916
28915
  await browser.document.fonts?.ready;
28917
- await new Promise((resolve47) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve47())));
28916
+ await new Promise((resolve48) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve48())));
28918
28917
  }, scheme);
28919
28918
  }
28920
28919
  async function renderPngBatch(items) {
@@ -32486,7 +32485,7 @@ async function handleWebWix(req, res, state) {
32486
32485
  }
32487
32486
  if (match && (match.rule.kind ?? "mock") === "mock") {
32488
32487
  const mocked = match.rule.response;
32489
- if (mocked.delayMs) await new Promise((resolve47) => setTimeout(resolve47, mocked.delayMs));
32488
+ if (mocked.delayMs) await new Promise((resolve48) => setTimeout(resolve48, mocked.delayMs));
32490
32489
  const responseBody = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
32491
32490
  recordWixTraffic(state.wix, state.appName, state.adminUrl, {
32492
32491
  ts: started,
@@ -34488,12 +34487,12 @@ var init_query = __esm({
34488
34487
  });
34489
34488
 
34490
34489
  // ../../core/dev-server/src/crawl-input.ts
34491
- function resolved(v, resolve47) {
34492
- if (typeof v === "string") return v.startsWith("$service:") ? resolve47(v) : v;
34490
+ function resolved(v, resolve48) {
34491
+ if (typeof v === "string") return v.startsWith("$service:") ? resolve48(v) : v;
34493
34492
  if (Array.isArray(v)) {
34494
34493
  const out = v.flatMap((el) => {
34495
34494
  if (typeof el !== "string" || !el.startsWith("$service:")) return [el];
34496
- const r = resolve47(el);
34495
+ const r = resolve48(el);
34497
34496
  return Array.isArray(r) ? r : [r];
34498
34497
  });
34499
34498
  return out;
@@ -34507,9 +34506,9 @@ function hasRowBinding(props) {
34507
34506
  return itemToken(v) || Array.isArray(v) && v.some(itemToken);
34508
34507
  });
34509
34508
  }
34510
- function declaredOptionIds(props, resolve47) {
34509
+ function declaredOptionIds(props, resolve48) {
34511
34510
  const literal = props.options ?? props.tabs ?? props.chips;
34512
- const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve47) : void 0;
34511
+ const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve48) : void 0;
34513
34512
  const raw = Array.isArray(bound) ? bound : literal;
34514
34513
  if (!Array.isArray(raw)) return [];
34515
34514
  const out = [];
@@ -34552,24 +34551,24 @@ function seedTokens(state, limit = 48) {
34552
34551
  walk2(state, 0);
34553
34552
  return out;
34554
34553
  }
34555
- function synthesizeInput(control, resolve47, tokens) {
34554
+ function synthesizeInput(control, resolve48, tokens) {
34556
34555
  const id = `${control.type}.${control.callback}`;
34557
34556
  const row = SYNTHESIZED_CONTROLS[id];
34558
34557
  if (!row) return null;
34559
34558
  const props = control.props;
34560
34559
  if (hasRowBinding(props)) return null;
34561
34560
  if (row.from === "declared-options") {
34562
- const ids = declaredOptionIds(props, resolve47);
34561
+ const ids = declaredOptionIds(props, resolve48);
34563
34562
  if (!ids.length) return null;
34564
34563
  if (row.encoding === "string-array") {
34565
- const currentRaw2 = resolved(props.selectedIds, resolve47);
34564
+ const currentRaw2 = resolved(props.selectedIds, resolve48);
34566
34565
  const current3 = (Array.isArray(currentRaw2) ? currentRaw2 : []).filter((x) => typeof x === "string");
34567
34566
  const pick4 = ids.find((o) => !current3.includes(o));
34568
34567
  if (pick4 === void 0) return null;
34569
34568
  const value = props.multiSelect === true ? [...current3, pick4] : [pick4];
34570
34569
  return { key: row.key, value, from: row.from, current: current3, control: id };
34571
34570
  }
34572
- const currentRaw = resolved(props.selectedId, resolve47);
34571
+ const currentRaw = resolved(props.selectedId, resolve48);
34573
34572
  const current2 = typeof currentRaw === "string" ? currentRaw : void 0;
34574
34573
  const pick3 = ids.find((o) => o !== current2);
34575
34574
  if (pick3 === void 0) return null;
@@ -34577,7 +34576,7 @@ function synthesizeInput(control, resolve47, tokens) {
34577
34576
  }
34578
34577
  if (!acceptsWords(props) || !acceptsWords(control.wrapper ?? {})) return null;
34579
34578
  const binding2 = typeof props.valuePath === "string" ? props.valuePath : typeof props.value === "string" && props.value.startsWith("$service:") ? props.value : void 0;
34580
- const bound = binding2 === void 0 ? void 0 : resolve47(binding2);
34579
+ const bound = binding2 === void 0 ? void 0 : resolve48(binding2);
34581
34580
  const literal = typeof props.value === "string" && !props.value.startsWith("$") ? props.value : void 0;
34582
34581
  const current = typeof bound === "string" ? bound : typeof bound === "number" ? String(bound) : literal ?? "";
34583
34582
  const max = typeof props.maxLength === "number" && props.maxLength > 0 ? props.maxLength : void 0;
@@ -35835,8 +35834,8 @@ async function crawlScreenInner(opts) {
35835
35834
  if (linkable.has(target)) return true;
35836
35835
  for (const base of linkable) {
35837
35836
  if (target.length > base.length + 1 && target.startsWith(base)) {
35838
- const sep14 = target[base.length];
35839
- if (sep14 === "_" || sep14 === "/") return true;
35837
+ const sep15 = target[base.length];
35838
+ if (sep15 === "_" || sep15 === "/") return true;
35840
35839
  }
35841
35840
  }
35842
35841
  return false;
@@ -38090,6 +38089,7 @@ __export(progress_exports, {
38090
38089
  MAX_MESSAGE_CHARS: () => MAX_MESSAGE_CHARS,
38091
38090
  PROGRESS_FILE: () => PROGRESS_FILE,
38092
38091
  ProgressError: () => ProgressError,
38092
+ UnsafeHimiDirError: () => UnsafeHimiDirError,
38093
38093
  appLabel: () => appLabel,
38094
38094
  appendProgress: () => appendProgress,
38095
38095
  appleScriptString: () => appleScriptString,
@@ -38099,11 +38099,14 @@ __export(progress_exports, {
38099
38099
  notifyDesktop: () => notifyDesktop,
38100
38100
  parseStep: () => parseStep,
38101
38101
  readProgress: () => readProgress,
38102
- summarizeProgress: () => summarizeProgress
38102
+ realDirIn: () => realDirIn,
38103
+ summarizeProgress: () => summarizeProgress,
38104
+ writeFileAtomic: () => writeFileAtomic
38103
38105
  });
38104
38106
  import { spawn as spawn4 } from "node:child_process";
38105
38107
  import { createHash as createHash19 } from "node:crypto";
38106
- import { appendFileSync, closeSync, existsSync as existsSync38, mkdirSync as mkdirSync17, openSync, readFileSync as readFileSync41, readSync, renameSync as renameSync3, statSync as statSync7, writeFileSync as writeFileSync13 } from "node:fs";
38108
+ import { randomUUID as randomUUID2 } from "node:crypto";
38109
+ import { appendFileSync, closeSync, existsSync as existsSync38, lstatSync as lstatSync5, mkdirSync as mkdirSync17, openSync, readFileSync as readFileSync41, readSync, renameSync as renameSync3, rmSync as rmSync6, statSync as statSync7, writeFileSync as writeFileSync13 } from "node:fs";
38107
38110
  import { join as join35, relative as relative5, resolve as resolve32, sep as sep8 } from "node:path";
38108
38111
  function parseStep(raw) {
38109
38112
  const v = raw.trim().toLowerCase();
@@ -38131,21 +38134,49 @@ function archiveImage(dir, src) {
38131
38134
  if (size > MAX_IMAGE_BYTES) {
38132
38135
  throw new ProgressError("image_too_large", `${src} is ${size} bytes; a progress image is capped at ${MAX_IMAGE_BYTES} \u2014 render at phone width (--device iphone)`);
38133
38136
  }
38134
- const archived = archiveBytes(dir, readFileSync41(abs));
38137
+ let archived;
38138
+ try {
38139
+ archived = archiveBytes(dir, readFileSync41(abs));
38140
+ } catch (e) {
38141
+ if (e instanceof UnsafeHimiDirError) throw new ProgressError("unsafe_himi_dir", e.message);
38142
+ throw e;
38143
+ }
38135
38144
  if (!archived) throw new ProgressError("not_an_image", `${src} is not a PNG, JPEG, GIF or WebP image`);
38136
38145
  return { file: archived.file, sha256: archived.sha256, source: src };
38137
38146
  }
38147
+ function realDirIn(dir, rel) {
38148
+ let at = dir;
38149
+ for (const part of rel.split(/[\\/]+/).filter(Boolean)) {
38150
+ at = join35(at, part);
38151
+ try {
38152
+ if (!lstatSync5(at).isDirectory()) return null;
38153
+ } catch (e) {
38154
+ if (e.code !== "ENOENT") return null;
38155
+ mkdirSync17(at);
38156
+ if (!lstatSync5(at).isDirectory()) return null;
38157
+ }
38158
+ }
38159
+ return at;
38160
+ }
38161
+ function writeFileAtomic(file, content) {
38162
+ const tmp = `${file}.${process.pid}.${randomUUID2()}.tmp`;
38163
+ try {
38164
+ writeFileSync13(tmp, content, { flag: "wx" });
38165
+ renameSync3(tmp, file);
38166
+ } catch (e) {
38167
+ rmSync6(tmp, { force: true });
38168
+ throw e;
38169
+ }
38170
+ }
38138
38171
  function archiveBytes(dir, bytes2) {
38139
38172
  const ext = imageExtension(bytes2);
38140
38173
  if (!ext) return null;
38141
38174
  const sha2565 = createHash19("sha256").update(bytes2).digest("hex");
38142
38175
  const rel = join35(HISTORY_DIR, `${sha2565}.${ext}`);
38143
38176
  const dest = join35(dir, rel);
38177
+ if (!realDirIn(dir, HISTORY_DIR)) throw new UnsafeHimiDirError(HISTORY_DIR);
38144
38178
  if (!existsSync38(dest)) {
38145
- mkdirSync17(join35(dir, HISTORY_DIR), { recursive: true });
38146
- const tmp = `${dest}.${process.pid}.tmp`;
38147
- writeFileSync13(tmp, bytes2);
38148
- renameSync3(tmp, dest);
38179
+ writeFileAtomic(dest, bytes2);
38149
38180
  }
38150
38181
  return { sha256: sha2565, ext, file: toPosix(rel) };
38151
38182
  }
@@ -38165,8 +38196,9 @@ function appendProgress(dir, input) {
38165
38196
  ...input.step ? { step: input.step, stepNumber: JOURNEY_STEPS.indexOf(input.step) + 1 } : {},
38166
38197
  ...images.length ? { images } : {}
38167
38198
  };
38168
- mkdirSync17(join35(dir, ".himi"), { recursive: true });
38199
+ if (!realDirIn(dir, ".himi")) throw new ProgressError("unsafe_himi_dir", new UnsafeHimiDirError(".himi").message);
38169
38200
  const file = join35(dir, PROGRESS_FILE);
38201
+ if (existsSync38(file) && lstatSync5(file).isSymbolicLink()) throw new ProgressError("unsafe_himi_dir", `${PROGRESS_FILE} is a symlink \u2014 refusing to append through it`);
38170
38202
  appendFileSync(file, `${endsWithNewline(file) ? "" : "\n"}${JSON.stringify(entry)}
38171
38203
  `);
38172
38204
  return entry;
@@ -38269,7 +38301,7 @@ function journalPath(dir) {
38269
38301
  const rel = relative5(process.cwd(), abs);
38270
38302
  return rel && !rel.startsWith("..") ? rel : abs;
38271
38303
  }
38272
- var JOURNEY_STEPS, PROGRESS_FILE, HISTORY_DIR, MAX_MESSAGE_CHARS, MAX_IMAGE_BYTES, ProgressError, toPosix, NOTIFY_TIMEOUT_MS;
38304
+ var JOURNEY_STEPS, PROGRESS_FILE, HISTORY_DIR, MAX_MESSAGE_CHARS, MAX_IMAGE_BYTES, ProgressError, toPosix, UnsafeHimiDirError, NOTIFY_TIMEOUT_MS;
38273
38305
  var init_progress = __esm({
38274
38306
  "src/progress.ts"() {
38275
38307
  JOURNEY_STEPS = ["discover", "classify", "plan", "implement", "brand", "validate", "review", "download"];
@@ -38284,6 +38316,11 @@ var init_progress = __esm({
38284
38316
  }
38285
38317
  };
38286
38318
  toPosix = (p) => p.split(sep8).join("/");
38319
+ UnsafeHimiDirError = class extends Error {
38320
+ constructor(rel) {
38321
+ super(`${rel} is not a real directory inside the content package (a symlink?) \u2014 refusing to write through it`);
38322
+ }
38323
+ };
38287
38324
  NOTIFY_TIMEOUT_MS = 3e3;
38288
38325
  }
38289
38326
  });
@@ -38305,7 +38342,7 @@ __export(studio_exports, {
38305
38342
  writeStudioRecord: () => writeStudioRecord
38306
38343
  });
38307
38344
  import { createHash as createHash20 } from "node:crypto";
38308
- import { existsSync as existsSync39, mkdirSync as mkdirSync18, readdirSync as readdirSync20, readFileSync as readFileSync42, realpathSync as realpathSync4, renameSync as renameSync4, statSync as statSync8, writeFileSync as writeFileSync14 } from "node:fs";
38345
+ import { existsSync as existsSync39, readdirSync as readdirSync20, readFileSync as readFileSync42, realpathSync as realpathSync4, statSync as statSync8 } from "node:fs";
38309
38346
  import { basename as basename9, extname as extname3, join as join36, relative as relative6, resolve as resolve33, sep as sep9 } from "node:path";
38310
38347
  import { pathToFileURL as pathToFileURL7 } from "node:url";
38311
38348
  function realInside(dir, abs) {
@@ -38433,9 +38470,10 @@ function liveRun(dir) {
38433
38470
  const url = text(rec?.url);
38434
38471
  const pid = rec?.pid;
38435
38472
  if (!url || !/^https?:\/\//i.test(url) || typeof pid !== "number") return null;
38473
+ const build2 = obj(rec?.build);
38436
38474
  try {
38437
38475
  process.kill(pid, 0);
38438
- return { url };
38476
+ return { url, buildError: build2?.ok === false ? text(build2.error) ?? "the last rebuild failed" : null };
38439
38477
  } catch {
38440
38478
  return null;
38441
38479
  }
@@ -38509,14 +38547,13 @@ function buildView(dir, memory, now) {
38509
38547
  return { v, ...view };
38510
38548
  }
38511
38549
  function writeAtomic(file, content) {
38512
- const tmp = `${file}.${process.pid}.tmp`;
38513
- writeFileSync14(tmp, content);
38514
- renameSync4(tmp, file);
38550
+ writeFileAtomic(file, content);
38515
38551
  }
38516
38552
  function writeBoard(dir, now) {
38553
+ if (!realDirIn(dir, STUDIO_DIR)) throw new UnsafeHimiDirError(STUDIO_DIR);
38554
+ if (!realDirIn(dir, HISTORY_DIR)) throw new UnsafeHimiDirError(HISTORY_DIR);
38517
38555
  const memory = observeShots(dir, loadMemory(dir, now), now);
38518
38556
  const view = buildView(dir, memory, now);
38519
- mkdirSync18(join36(dir, STUDIO_DIR), { recursive: true });
38520
38557
  writeAtomic(join36(dir, MEMORY_FILE), JSON.stringify(memory));
38521
38558
  writeAtomic(join36(dir, STATE_FILE), `window.__himiStudio && window.__himiStudio(${scriptJson(view)});
38522
38559
  `);
@@ -38538,7 +38575,7 @@ function openStudio(dir, now = /* @__PURE__ */ new Date()) {
38538
38575
  }
38539
38576
  function writeStudioRecord(dir, record2, value) {
38540
38577
  try {
38541
- mkdirSync18(join36(dir, ".himi"), { recursive: true });
38578
+ if (!realDirIn(dir, ".himi")) return;
38542
38579
  writeAtomic(join36(dir, record2), `${JSON.stringify(value, null, 2)}
38543
38580
  `);
38544
38581
  } catch {
@@ -38624,7 +38661,7 @@ function render(s){
38624
38661
  $("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
38625
38662
  $("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
38626
38663
  var focus=$("focus");clear(focus);var film=$("film");clear(film);
38627
- if(s.live){$("focuslbl").textContent="Live preview";var f=el("div","phone");var fr=document.createElement("iframe");fr.src=s.live.url;fr.title="Live preview";f.appendChild(fr);focus.appendChild(f);focus.appendChild(el("div","cap","Repaints as the app is edited \xB7 "+s.live.url))}
38664
+ if(s.live){$("focuslbl").textContent="Live preview";var f=el("div","phone");var fr=document.createElement("iframe");fr.src=s.live.url;fr.title="Live preview";f.appendChild(fr);focus.appendChild(f);if(s.live.buildError){var be=el("div","chip bad",null);be.style.display="block";be.style.marginTop="8px";be.textContent="Last edit did not build, still showing the last good version: "+s.live.buildError;focus.appendChild(be)}focus.appendChild(el("div","cap","Repaints as the app is edited \xB7 "+s.live.url))}
38628
38665
  else if(s.focus&&s.focus.frames.length){var fl=s.focus.frames;$("focuslbl").textContent="Latest \xB7 "+s.focus.id;var p=el("div","phone");p.appendChild(img(fl[fl.length-1].img));focus.appendChild(p);focus.appendChild(el("div","cap",fl.length+(fl.length===1?" version":" versions")+" so far"))}
38629
38666
  else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
38630
38667
  if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});
@@ -39318,7 +39355,7 @@ var init_push_setup_apple_credentials = __esm({
39318
39355
  });
39319
39356
 
39320
39357
  // src/push-onboarding.ts
39321
- import { existsSync as existsSync40, mkdirSync as mkdirSync19, readFileSync as readFileSync44, statSync as statSync9, writeFileSync as writeFileSync15, chmodSync as chmodSync2 } from "node:fs";
39358
+ import { existsSync as existsSync40, mkdirSync as mkdirSync18, readFileSync as readFileSync44, statSync as statSync9, writeFileSync as writeFileSync14, chmodSync as chmodSync2 } from "node:fs";
39322
39359
  import { basename as basename10, dirname as dirname22, join as join37, resolve as resolve35 } from "node:path";
39323
39360
  function readJson3(path2) {
39324
39361
  try {
@@ -39468,8 +39505,8 @@ function readPushOnboarding(dir) {
39468
39505
  }
39469
39506
  function writeFile(dir, file) {
39470
39507
  const path2 = join37(resolve35(dir), PUSH_ONBOARDING_PATH);
39471
- mkdirSync19(dirname22(path2), { recursive: true, mode: 448 });
39472
- writeFileSync15(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
39508
+ mkdirSync18(dirname22(path2), { recursive: true, mode: 448 });
39509
+ writeFileSync14(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
39473
39510
  try {
39474
39511
  chmodSync2(path2, 384);
39475
39512
  } catch {
@@ -40230,7 +40267,7 @@ __export(template_trim_exports, {
40230
40267
  routeMatcher: () => routeMatcher,
40231
40268
  runTemplateTrim: () => runTemplateTrim
40232
40269
  });
40233
- import { cpSync, existsSync as existsSync41, mkdirSync as mkdirSync20, readdirSync as readdirSync21, readFileSync as readFileSync45, renameSync as renameSync5, rmSync as rmSync6, statSync as statSync10, writeFileSync as writeFileSync16 } from "node:fs";
40270
+ import { cpSync, existsSync as existsSync41, mkdirSync as mkdirSync19, readdirSync as readdirSync21, readFileSync as readFileSync45, renameSync as renameSync4, rmSync as rmSync7, statSync as statSync10, writeFileSync as writeFileSync15 } from "node:fs";
40234
40271
  import { dirname as dirname23, join as join38 } from "node:path";
40235
40272
  function routeMatcher(pattern) {
40236
40273
  const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
@@ -40988,16 +41025,16 @@ async function runTemplateTrim(req, deps) {
40988
41025
  const restore = () => {
40989
41026
  for (const [path2, rel] of originals) {
40990
41027
  const original = readFileSync45(join38(backup, rel));
40991
- if (!existsSync41(path2) || !readFileSync45(path2).equals(original)) writeFileSync16(path2, original);
41028
+ if (!existsSync41(path2) || !readFileSync45(path2).equals(original)) writeFileSync15(path2, original);
40992
41029
  }
40993
- for (const name of [...moved].reverse()) renameSync5(join38(backup, "tier5-src", name), join38(dir, "tier5-src", name));
41030
+ for (const name of [...moved].reverse()) renameSync4(join38(backup, "tier5-src", name), join38(dir, "tier5-src", name));
40994
41031
  };
40995
41032
  const dropBackup = () => {
40996
- rmSync6(backup, { recursive: true, force: true });
41033
+ rmSync7(backup, { recursive: true, force: true });
40997
41034
  for (const d of [dirname23(backup), join38(dir, ".himi")]) {
40998
41035
  if (d === join38(dir, ".himi") && hadHimi) break;
40999
41036
  try {
41000
- if (!readdirSync21(d).length) rmSync6(d, { recursive: true });
41037
+ if (!readdirSync21(d).length) rmSync7(d, { recursive: true });
41001
41038
  } catch {
41002
41039
  }
41003
41040
  }
@@ -41021,21 +41058,21 @@ async function runTemplateTrim(req, deps) {
41021
41058
  return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
41022
41059
  };
41023
41060
  try {
41024
- mkdirSync20(join38(backup, "dev"), { recursive: true });
41061
+ mkdirSync19(join38(backup, "dev"), { recursive: true });
41025
41062
  for (const [path2, rel] of originals) cpSync(path2, join38(backup, rel));
41026
- if (plan.removedWorkers.length) mkdirSync20(join38(backup, "tier5-src"), { recursive: true });
41063
+ if (plan.removedWorkers.length) mkdirSync19(join38(backup, "tier5-src"), { recursive: true });
41027
41064
  } catch (e) {
41028
41065
  dropBackup();
41029
41066
  return { code: 1, result: { ok: false, error: `could not back up the app before trimming it (${e.message}); nothing was changed`, rolledBack: true, ...base() } };
41030
41067
  }
41031
41068
  try {
41032
- const moveDir = deps.moveDir ?? renameSync5;
41069
+ const moveDir = deps.moveDir ?? renameSync4;
41033
41070
  for (const name of plan.removedWorkers) {
41034
41071
  moveDir(join38(dir, "tier5-src", name), join38(backup, "tier5-src", name));
41035
41072
  moved.push(name);
41036
41073
  }
41037
- if (plan.dev !== dev) writeFileSync16(devPath, plan.dev);
41038
- if (plan.config !== config) writeFileSync16(configPath, plan.config);
41074
+ if (plan.dev !== dev) writeFileSync15(devPath, plan.dev);
41075
+ if (plan.config !== config) writeFileSync15(configPath, plan.config);
41039
41076
  } catch (e) {
41040
41077
  return abort("the trim failed while writing", e);
41041
41078
  }
@@ -41736,7 +41773,7 @@ __export(pack_exports, {
41736
41773
  });
41737
41774
  import { createHash as createHash21 } from "node:crypto";
41738
41775
  import { deflateRawSync, inflateRawSync } from "node:zlib";
41739
- import { existsSync as existsSync42, mkdirSync as mkdirSync21, readFileSync as readFileSync46, readdirSync as readdirSync22, rmSync as rmSync7, statSync as statSync11, writeFileSync as writeFileSync17 } from "node:fs";
41776
+ import { existsSync as existsSync42, mkdirSync as mkdirSync20, readFileSync as readFileSync46, readdirSync as readdirSync22, rmSync as rmSync8, statSync as statSync11, writeFileSync as writeFileSync16 } from "node:fs";
41740
41777
  import { dirname as dirname24, join as join39, resolve as resolve37 } from "node:path";
41741
41778
  function writeZip(entries) {
41742
41779
  const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
@@ -41913,10 +41950,10 @@ function packRelease(releaseRoot, app, out, opts = {}) {
41913
41950
  const appDir2 = join39(resolve37(releaseRoot), app);
41914
41951
  const { all, header, skipped } = buildEntries(appDir2, app, opts);
41915
41952
  const buf = writeZip(all);
41916
- const isDir = existsSync42(out) && statSync11(out).isDirectory();
41917
- const outFile = isDir ? join39(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
41918
- mkdirSync21(dirname24(outFile), { recursive: true });
41919
- writeFileSync17(outFile, buf);
41953
+ const isDir2 = existsSync42(out) && statSync11(out).isDirectory();
41954
+ const outFile = isDir2 ? join39(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
41955
+ mkdirSync20(dirname24(outFile), { recursive: true });
41956
+ writeFileSync16(outFile, buf);
41920
41957
  return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
41921
41958
  }
41922
41959
  function resolvePackageDirDest(outDir, app, releaseId) {
@@ -41955,12 +41992,12 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
41955
41992
  const appDir2 = join39(resolve37(releaseRoot), app);
41956
41993
  const { all, header, skipped } = buildEntries(appDir2, app, opts);
41957
41994
  const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
41958
- rmSync7(dest, { recursive: true, force: true });
41995
+ rmSync8(dest, { recursive: true, force: true });
41959
41996
  let bytes2 = 0;
41960
41997
  for (const entry of all) {
41961
41998
  const target = join39(dest, entry.path);
41962
- mkdirSync21(dirname24(target), { recursive: true });
41963
- writeFileSync17(target, entry.bytes);
41999
+ mkdirSync20(dirname24(target), { recursive: true });
42000
+ writeFileSync16(target, entry.bytes);
41964
42001
  bytes2 += entry.bytes.length;
41965
42002
  }
41966
42003
  return { app, releaseId: header.releaseId, header, out: dest, bytes: bytes2, entryCount: all.length, skipped };
@@ -42038,11 +42075,11 @@ function unpackTo(buf, dest, appFallback) {
42038
42075
  if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
42039
42076
  const root = resolve37(dest);
42040
42077
  const appDir2 = join39(root, app);
42041
- rmSync7(appDir2, { recursive: true, force: true });
42078
+ rmSync8(appDir2, { recursive: true, force: true });
42042
42079
  for (const [rel, bytes2] of entries) {
42043
42080
  const target = join39(appDir2, rel);
42044
- mkdirSync21(dirname24(target), { recursive: true });
42045
- writeFileSync17(target, bytes2);
42081
+ mkdirSync20(dirname24(target), { recursive: true });
42082
+ writeFileSync16(target, bytes2);
42046
42083
  }
42047
42084
  return { root, appDir: appDir2, app };
42048
42085
  }
@@ -42076,14 +42113,14 @@ __export(app_source_exports, {
42076
42113
  writeConflicts: () => writeConflicts,
42077
42114
  zipAppSource: () => zipAppSource
42078
42115
  });
42079
- import { readdirSync as readdirSync23, lstatSync as lstatSync5, readFileSync as readFileSync47, mkdirSync as mkdirSync22, writeFileSync as writeFileSync18, existsSync as existsSync43, rmSync as rmSync8, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
42116
+ import { readdirSync as readdirSync23, lstatSync as lstatSync6, readFileSync as readFileSync47, mkdirSync as mkdirSync21, writeFileSync as writeFileSync17, existsSync as existsSync43, rmSync as rmSync9, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
42080
42117
  import { join as join40, resolve as resolve38, sep as sep10 } from "node:path";
42081
42118
  import { deflateRawSync as deflateRawSync2 } from "node:zlib";
42082
42119
  function walkSourceTree(dir, file, skip) {
42083
42120
  const walk2 = (relDir) => {
42084
42121
  for (const name of readdirSync23(join40(dir, relDir))) {
42085
42122
  const rel = relDir ? join40(relDir, name) : name;
42086
- const st = lstatSync5(join40(dir, rel));
42123
+ const st = lstatSync6(join40(dir, rel));
42087
42124
  if (st.isSymbolicLink()) {
42088
42125
  skip(rel);
42089
42126
  continue;
@@ -42142,7 +42179,7 @@ function readAppSource(zip) {
42142
42179
  }
42143
42180
  function pathKind(p) {
42144
42181
  try {
42145
- return lstatSync5(p);
42182
+ return lstatSync6(p);
42146
42183
  } catch {
42147
42184
  return null;
42148
42185
  }
@@ -42154,7 +42191,7 @@ function writeAppSource(entries, destDir) {
42154
42191
  `refusing to restore into ${root}: the destination itself is a symlink, so every file would be written outside it. Remove it, or pass --out/--name somewhere else.`
42155
42192
  );
42156
42193
  }
42157
- mkdirSync22(root, { recursive: true });
42194
+ mkdirSync21(root, { recursive: true });
42158
42195
  const written = [];
42159
42196
  for (const entry of entries) {
42160
42197
  if (isDeniedSourcePath(entry.path)) continue;
@@ -42165,11 +42202,11 @@ function writeAppSource(entries, destDir) {
42165
42202
  const kind = pathKind(dir);
42166
42203
  if (kind?.isSymbolicLink()) unlinkSync3(dir);
42167
42204
  else if (kind) continue;
42168
- mkdirSync22(dir);
42205
+ mkdirSync21(dir);
42169
42206
  }
42170
42207
  const target = join40(root, ...segments);
42171
42208
  if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
42172
- writeFileSync18(target, entry.bytes);
42209
+ writeFileSync17(target, entry.bytes);
42173
42210
  written.push(entry.path);
42174
42211
  }
42175
42212
  return written;
@@ -42224,7 +42261,7 @@ function writeConflicts(entries, destDir) {
42224
42261
  function removeStaleSource(entries, destDir) {
42225
42262
  const root = resolve38(destDir);
42226
42263
  const removed = staleSourcePaths(entries, root);
42227
- for (const rel of removed) rmSync8(join40(root, ...rel.split("/")), { force: true });
42264
+ for (const rel of removed) rmSync9(join40(root, ...rel.split("/")), { force: true });
42228
42265
  const needed = /* @__PURE__ */ new Set();
42229
42266
  for (const entry of entries) {
42230
42267
  if (isDeniedSourcePath(entry.path)) continue;
@@ -42239,7 +42276,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
42239
42276
  for (const name of readdirSync23(rel ? join40(root, rel) : root)) {
42240
42277
  const childRel = rel ? join40(rel, name) : name;
42241
42278
  const posix3 = childRel.split(sep10).join("/");
42242
- const kind = lstatSync5(join40(root, childRel));
42279
+ const kind = lstatSync6(join40(root, childRel));
42243
42280
  if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
42244
42281
  empty = false;
42245
42282
  continue;
@@ -42304,7 +42341,7 @@ __export(eject_exports, {
42304
42341
  EJECTABLE: () => EJECTABLE,
42305
42342
  ejectModule: () => ejectModule
42306
42343
  });
42307
- import { existsSync as existsSync44, mkdirSync as mkdirSync23, readFileSync as readFileSync48, writeFileSync as writeFileSync19 } from "node:fs";
42344
+ import { existsSync as existsSync44, mkdirSync as mkdirSync22, readFileSync as readFileSync48, writeFileSync as writeFileSync18 } from "node:fs";
42308
42345
  import { dirname as dirname25, join as join41, relative as relative7, resolve as resolve39, sep as sep11 } from "node:path";
42309
42346
  function locate(repoRootOrCwd, mod) {
42310
42347
  const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
@@ -42335,7 +42372,7 @@ function ejectModule(opts) {
42335
42372
  }
42336
42373
  const ext = found.form === "source" ? "ts" : "mjs";
42337
42374
  const target = join41(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
42338
- mkdirSync23(dirname25(target), { recursive: true });
42375
+ mkdirSync22(dirname25(target), { recursive: true });
42339
42376
  const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
42340
42377
  //
42341
42378
  // Central fixes to @wix/himalaya/${mod} NO LONGER REACH THIS APP \u2014 including any
@@ -42352,7 +42389,7 @@ function ejectModule(opts) {
42352
42389
  /(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
42353
42390
  (_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
42354
42391
  );
42355
- writeFileSync19(target, banner + normalized);
42392
+ writeFileSync18(target, banner + normalized);
42356
42393
  const rewired = [];
42357
42394
  for (const f of files) {
42358
42395
  if (!existsSync44(f)) continue;
@@ -42368,7 +42405,7 @@ function ejectModule(opts) {
42368
42405
  );
42369
42406
  }
42370
42407
  if (after !== before) {
42371
- writeFileSync19(f, after);
42408
+ writeFileSync18(f, after);
42372
42409
  rewired.push(f);
42373
42410
  }
42374
42411
  }
@@ -42404,7 +42441,7 @@ __export(test_exports, {
42404
42441
  scopeDescriptors: () => scopeDescriptors,
42405
42442
  writeRecordedMocks: () => writeRecordedMocks
42406
42443
  });
42407
- import { existsSync as existsSync45, mkdirSync as mkdirSync24, readFileSync as readFileSync49, writeFileSync as writeFileSync20 } from "node:fs";
42444
+ import { existsSync as existsSync45, mkdirSync as mkdirSync23, readFileSync as readFileSync49, writeFileSync as writeFileSync19 } from "node:fs";
42408
42445
  import { join as join42, resolve as resolve40 } from "node:path";
42409
42446
  function readTestConfig(dir) {
42410
42447
  const p = resolve40(dir, TEST_CONFIG_FILE);
@@ -42580,8 +42617,8 @@ function writeRecordedMocks(opts) {
42580
42617
  };
42581
42618
  }
42582
42619
  const fs = opts.io ?? {
42583
- mkdir: (p) => mkdirSync24(p, { recursive: true }),
42584
- write: (p, s) => writeFileSync20(p, s)
42620
+ mkdir: (p) => mkdirSync23(p, { recursive: true }),
42621
+ write: (p, s) => writeFileSync19(p, s)
42585
42622
  };
42586
42623
  fs.mkdir(join42(opts.dir, "dev"));
42587
42624
  fs.write(join42(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
@@ -43342,7 +43379,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
43342
43379
  const headers2 = Object.fromEntries(new Headers(init.headers).entries());
43343
43380
  const request = url.protocol === "https:" ? httpsRequest : httpRequest;
43344
43381
  const hostname2 = url.hostname.replace(/^\[|\]$/g, "");
43345
- return await new Promise((resolve47, reject) => {
43382
+ return await new Promise((resolve48, reject) => {
43346
43383
  let settled = false;
43347
43384
  const finish2 = (fn) => {
43348
43385
  if (settled) return;
@@ -43379,7 +43416,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
43379
43416
  }
43380
43417
  const responseHeaders = new Headers();
43381
43418
  for (const [key2, value] of Object.entries(response.headers)) if (value !== void 0) responseHeaders.set(key2, Array.isArray(value) ? value.join(", ") : value);
43382
- resolve47(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
43419
+ resolve48(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
43383
43420
  }));
43384
43421
  });
43385
43422
  req.once("error", (error) => finish2(() => reject(error)));
@@ -43679,7 +43716,7 @@ function createLocalTestSandbox() {
43679
43716
  }
43680
43717
  })();
43681
43718
  `;
43682
- return await new Promise((resolve47, reject) => {
43719
+ return await new Promise((resolve48, reject) => {
43683
43720
  const { port1, port2 } = new MessageChannel();
43684
43721
  const serializableContext = {
43685
43722
  auth: context.auth,
@@ -43755,7 +43792,7 @@ function createLocalTestSandbox() {
43755
43792
  timer = setTimeout(() => finish2(() => reject(new SandboxError("timeout", `execution exceeded ${limits.timeoutMs}ms`))), Math.max(1, limits.timeoutMs));
43756
43793
  return;
43757
43794
  }
43758
- if (message.ok) finish2(() => resolve47({ value: message.value, durationMs: Date.now() - started }));
43795
+ if (message.ok) finish2(() => resolve48({ value: message.value, durationMs: Date.now() - started }));
43759
43796
  else finish2(() => reject(new SandboxError("execution_failed", message.message ?? "handler failed")));
43760
43797
  });
43761
43798
  worker.once("error", (error) => finish2(() => reject(new SandboxError("execution_failed", error.message))));
@@ -44900,7 +44937,7 @@ __export(native_decode_exports, {
44900
44937
  runNativeDecode: () => runNativeDecode
44901
44938
  });
44902
44939
  import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
44903
- import { existsSync as existsSync48, mkdtempSync as mkdtempSync2, readFileSync as readFileSync52, rmSync as rmSync9, writeFileSync as writeFileSync21 } from "node:fs";
44940
+ import { existsSync as existsSync48, mkdtempSync as mkdtempSync2, readFileSync as readFileSync52, rmSync as rmSync10, writeFileSync as writeFileSync20 } from "node:fs";
44904
44941
  import { tmpdir as tmpdir3 } from "node:os";
44905
44942
  import { join as join45 } from "node:path";
44906
44943
  import { fileURLToPath as fileURLToPath20 } from "node:url";
@@ -45034,7 +45071,7 @@ function runNativeDecode(options) {
45034
45071
  if (typeof descriptor.descriptorJson !== "string") {
45035
45072
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
45036
45073
  }
45037
- writeFileSync21(join45(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45074
+ writeFileSync20(join45(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45038
45075
  }
45039
45076
  options.progress?.("building cached Swift oracle");
45040
45077
  execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
@@ -45060,7 +45097,7 @@ function runNativeDecode(options) {
45060
45097
  const stderr = failure.stderr ? ` \u2014 ${String(failure.stderr).trim().slice(0, 2e3)}` : "";
45061
45098
  throw new Error(`iOS decoder oracle failed: ${failure.message}${stderr}`);
45062
45099
  } finally {
45063
- rmSync9(descriptorDir, { recursive: true, force: true });
45100
+ rmSync10(descriptorDir, { recursive: true, force: true });
45064
45101
  }
45065
45102
  }
45066
45103
  function runAndroidNativeDecode(options) {
@@ -45072,7 +45109,7 @@ function runAndroidNativeDecode(options) {
45072
45109
  if (typeof descriptor.descriptorJson !== "string") {
45073
45110
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
45074
45111
  }
45075
- writeFileSync21(join45(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45112
+ writeFileSync20(join45(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
45076
45113
  }
45077
45114
  options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
45078
45115
  execFileSync5(options.gradlew, [
@@ -45098,7 +45135,7 @@ function runAndroidNativeDecode(options) {
45098
45135
  const stderr = failure.stderr ? ` \u2014 ${String(failure.stderr).trim().slice(0, 2e3)}` : "";
45099
45136
  throw new Error(`Android decoder oracle failed: ${failure.message}${stderr}`);
45100
45137
  } finally {
45101
- rmSync9(descriptorDir, { recursive: true, force: true });
45138
+ rmSync10(descriptorDir, { recursive: true, force: true });
45102
45139
  }
45103
45140
  }
45104
45141
  function fieldAt(path2) {
@@ -45242,10 +45279,10 @@ function collectSdkModules(files, resolveSubpath) {
45242
45279
  for (const source of Object.values(files)) visit(source);
45243
45280
  return { modules, unsupported };
45244
45281
  }
45245
- function sdkSubpathReader(resolve47) {
45282
+ function sdkSubpathReader(resolve48) {
45246
45283
  return (sub) => {
45247
45284
  try {
45248
- return readFileSync53(resolve47(`@wix/himalaya/${sub}`), "utf8");
45285
+ return readFileSync53(resolve48(`@wix/himalaya/${sub}`), "utf8");
45249
45286
  } catch {
45250
45287
  return null;
45251
45288
  }
@@ -45323,7 +45360,7 @@ async function runBrowserAuthoring(opts) {
45323
45360
  const token = mintToken2(payload);
45324
45361
  const unusable = await probeAuthoringPage(opts.authoringBase, opts.fetchImpl, opts.probeTimeoutMs);
45325
45362
  if (unusable) throw new Error(unusable);
45326
- return await new Promise((resolve47, reject) => {
45363
+ return await new Promise((resolve48, reject) => {
45327
45364
  let settled = false;
45328
45365
  let url = "";
45329
45366
  const server = createServer3();
@@ -45375,7 +45412,7 @@ async function runBrowserAuthoring(opts) {
45375
45412
  }
45376
45413
  res.writeHead(200, { "content-type": "text/plain" }).end("ok");
45377
45414
  const report2 = body.result;
45378
- finish2(() => resolve47({ report: report2, url }));
45415
+ finish2(() => resolve48({ report: report2, url }));
45379
45416
  })();
45380
45417
  });
45381
45418
  server.on("error", (e) => finish2(() => reject(e)));
@@ -45417,7 +45454,7 @@ __export(coverage_exports, {
45417
45454
  suppressedNativeKeys: () => suppressedNativeKeys,
45418
45455
  trendAndStore: () => trendAndStore
45419
45456
  });
45420
- import { existsSync as existsSync50, mkdirSync as mkdirSync25, readFileSync as readFileSync54, writeFileSync as writeFileSync22 } from "node:fs";
45457
+ import { existsSync as existsSync50, mkdirSync as mkdirSync24, readFileSync as readFileSync54, writeFileSync as writeFileSync21 } from "node:fs";
45421
45458
  import { dirname as dirname26, join as join47 } from "node:path";
45422
45459
  function suppressedNativeKeys(oracle) {
45423
45460
  return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
@@ -45600,8 +45637,8 @@ function trendAndStore(dir, entries, suppressed) {
45600
45637
  const current = entries.map((e) => e.key);
45601
45638
  const stored = [.../* @__PURE__ */ new Set([...current, ...(previous ?? []).filter((key2) => (suppressed ?? []).includes(key2))])];
45602
45639
  try {
45603
- mkdirSync25(dirname26(p), { recursive: true });
45604
- writeFileSync22(p, JSON.stringify({ keys: stored, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
45640
+ mkdirSync24(dirname26(p), { recursive: true });
45641
+ writeFileSync21(p, JSON.stringify({ keys: stored, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
45605
45642
  } catch {
45606
45643
  return null;
45607
45644
  }
@@ -45645,8 +45682,8 @@ function diffAndStoreObservations(dir, current) {
45645
45682
  } catch {
45646
45683
  }
45647
45684
  try {
45648
- mkdirSync25(dirname26(p), { recursive: true });
45649
- writeFileSync22(p, JSON.stringify({ screens: current, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
45685
+ mkdirSync24(dirname26(p), { recursive: true });
45686
+ writeFileSync21(p, JSON.stringify({ screens: current, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
45650
45687
  } catch {
45651
45688
  return null;
45652
45689
  }
@@ -46116,6 +46153,15 @@ function json3(status, body, headers2 = {}) {
46116
46153
  function isCookieAuthorizedPath(path2) {
46117
46154
  return path2 === "/v1/__webwix/call" || path2 === "/v1/owner" || path2.startsWith("/v1/owner/") || path2 === "/v1/__webwix/identity" || path2 === "/v1/__webwix/login" || path2 === "/v1/__webwix/register" || path2 === "/v1/__webwix/logout" || path2 === MEMBER_CALLBACK_PATH;
46118
46155
  }
46156
+ function webwixCallLog(served, status) {
46157
+ const directRung = served.rung === "visitor" || served.rung === "owner";
46158
+ return {
46159
+ rung: served.rung,
46160
+ ...directRung ? { fallback: served.fallback === true } : {},
46161
+ ...served.app ? { app: served.app } : {},
46162
+ status
46163
+ };
46164
+ }
46119
46165
  function makeServeHandler(opts) {
46120
46166
  let storePromise = null;
46121
46167
  const getStore = () => storePromise ??= (async () => {
@@ -46422,83 +46468,109 @@ ${releaseId}`;
46422
46468
  return json3(200, { authenticated: false, userId: null, email: null, webwixDirect }, { "cache-control": "no-store" });
46423
46469
  }
46424
46470
  if (request.method === "POST" && path2 === "/v1/__webwix/call") {
46425
- if (opts.webwixBridge === false) {
46426
- return json3(503, { error: "webwix_bridge_disabled" });
46427
- }
46428
- const app2 = resolveApp(request, url);
46429
- if (!app2) return json3(400, { error: "app_required" });
46430
- const resolvedCfg = await appConfigFor(request, url, app2);
46431
- if (!resolvedCfg.ok) return resolvedCfg.response;
46432
- const cfgBytes = resolvedCfg.bytes;
46433
- let call;
46471
+ const served = { rung: "none" };
46472
+ let status = 500;
46434
46473
  try {
46435
- call = await request.json();
46436
- } catch {
46437
- return json3(400, { error: "invalid_json" });
46438
- }
46439
- if (call.checkOwnerSession !== void 0 && (typeof call.checkOwnerSession !== "boolean" || call.checkOwnerSession && call.ownerMsid === void 0)) {
46440
- return json3(400, { error: "invalid_owner_session_check" });
46441
- }
46442
- const method = String(call.method ?? "GET").toUpperCase();
46443
- const reqPath = String(call.path ?? "/");
46444
- const body = call.body === void 0 ? void 0 : typeof call.body === "string" ? call.body : JSON.stringify(call.body);
46445
- const forwardedHeaders = normalizeWixForwardedHeaders(call.headers);
46446
- const callerCookie = request.headers.get("cookie") ?? "";
46447
- if (!call.checkOwnerSession && webwixOwnerRungOn() && method === "POST" && isOwnerSitesPath(reqPath) && /wixSession2=/.test(callerCookie)) {
46448
- try {
46449
- const envelope = await wixOwnerSitesCall(reqPath, callerCookie, body, webwixFetch);
46450
- if (envelope.status >= 200 && envelope.status < 300) return json3(200, envelope);
46451
- return json3(200, {
46452
- status: 501,
46453
- body: JSON.stringify({ error: "webwix_owner_sites_failed", upstream: envelope.status })
46454
- });
46455
- } catch (e) {
46456
- return json3(200, {
46457
- status: 501,
46458
- body: JSON.stringify({ error: "webwix_owner_sites_failed", detail: String(e?.message ?? e).slice(0, 200) })
46459
- });
46460
- }
46461
- }
46462
- if (call.ownerMsid !== void 0) {
46463
- if (!webwixOwnerRungOn()) {
46464
- return json3(503, { error: "webwix_owner_disabled" });
46465
- }
46466
- const msid = String(call.ownerMsid);
46467
- if (!isSafeMsid(msid)) return json3(400, { error: "webwix_owner_bad_msid" });
46468
- const cookie = request.headers.get("cookie") ?? "";
46469
- if (!/wixSession2=/.test(cookie)) return json3(501, { error: "webwix_owner_no_session", app: app2 });
46470
- try {
46471
- const instance = await webwixOwnerInstances.instance(msid, cookie);
46472
- if (call.checkOwnerSession === true) return json3(200, { status: 200, body: JSON.stringify({ ready: true }) }, { "cache-control": "no-store" });
46473
- const first = await wixVisitorCall(method, reqPath, body, instance, webwixFetch, forwardedHeaders);
46474
- if (first.status !== 401) return json3(200, first);
46475
- webwixOwnerInstances.invalidate(msid, cookie);
46476
- const fresh = await webwixOwnerInstances.instance(msid, cookie);
46477
- return json3(200, await wixVisitorCall(method, reqPath, body, fresh, webwixFetch, forwardedHeaders));
46478
- } catch (e) {
46479
- const msg = String(e?.message ?? e);
46480
- if (msg.includes("absolute URLs")) {
46481
- return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
46474
+ const res = await (async () => {
46475
+ if (opts.webwixBridge === false) {
46476
+ return json3(503, { error: "webwix_bridge_disabled" });
46477
+ }
46478
+ const app2 = resolveApp(request, url);
46479
+ if (!app2) return json3(400, { error: "app_required" });
46480
+ const resolvedCfg = await appConfigFor(request, url, app2);
46481
+ if (!resolvedCfg.ok) return resolvedCfg.response;
46482
+ served.app = app2;
46483
+ const cfgBytes = resolvedCfg.bytes;
46484
+ let call;
46485
+ try {
46486
+ call = await request.json();
46487
+ } catch {
46488
+ return json3(400, { error: "invalid_json" });
46482
46489
  }
46483
- if (msg.includes("owner mint failed")) {
46484
- if (/owner mint failed \(5\d\d\)/.test(msg)) return json3(502, { error: "webwix_bridge_upstream_failed" });
46485
- return json3(501, { error: "webwix_owner_mint_failed", app: app2 });
46490
+ served.fallback = call.fallback === true;
46491
+ if (call.checkOwnerSession !== void 0 && (typeof call.checkOwnerSession !== "boolean" || call.checkOwnerSession && call.ownerMsid === void 0)) {
46492
+ return json3(400, { error: "invalid_owner_session_check" });
46493
+ }
46494
+ const method = String(call.method ?? "GET").toUpperCase();
46495
+ const reqPath = String(call.path ?? "/");
46496
+ const body = call.body === void 0 ? void 0 : typeof call.body === "string" ? call.body : JSON.stringify(call.body);
46497
+ const forwardedHeaders = normalizeWixForwardedHeaders(call.headers);
46498
+ const callerCookie = request.headers.get("cookie") ?? "";
46499
+ if (!call.checkOwnerSession && webwixOwnerRungOn() && method === "POST" && isOwnerSitesPath(reqPath) && /wixSession2=/.test(callerCookie)) {
46500
+ served.rung = "sites";
46501
+ try {
46502
+ const envelope = await wixOwnerSitesCall(reqPath, callerCookie, body, webwixFetch);
46503
+ if (envelope.status >= 200 && envelope.status < 300) return json3(200, envelope);
46504
+ return json3(200, {
46505
+ status: 501,
46506
+ body: JSON.stringify({ error: "webwix_owner_sites_failed", upstream: envelope.status })
46507
+ });
46508
+ } catch (e) {
46509
+ return json3(200, {
46510
+ status: 501,
46511
+ body: JSON.stringify({ error: "webwix_owner_sites_failed", detail: String(e?.message ?? e).slice(0, 200) })
46512
+ });
46513
+ }
46514
+ }
46515
+ if (call.ownerMsid !== void 0) {
46516
+ served.rung = call.checkOwnerSession === true ? "gate" : "owner";
46517
+ if (!webwixOwnerRungOn()) {
46518
+ return json3(503, { error: "webwix_owner_disabled" });
46519
+ }
46520
+ const msid = String(call.ownerMsid);
46521
+ if (!isSafeMsid(msid)) return json3(400, { error: "webwix_owner_bad_msid" });
46522
+ const cookie = request.headers.get("cookie") ?? "";
46523
+ if (!/wixSession2=/.test(cookie)) return json3(501, { error: "webwix_owner_no_session", app: app2 });
46524
+ try {
46525
+ const instance = await webwixOwnerInstances.instance(msid, cookie);
46526
+ if (call.checkOwnerSession === true) return json3(200, { status: 200, body: JSON.stringify({ ready: true }) }, { "cache-control": "no-store" });
46527
+ const first = await wixVisitorCall(method, reqPath, body, instance, webwixFetch, forwardedHeaders);
46528
+ if (first.status !== 401) return json3(200, first);
46529
+ webwixOwnerInstances.invalidate(msid, cookie);
46530
+ const fresh = await webwixOwnerInstances.instance(msid, cookie);
46531
+ return json3(200, await wixVisitorCall(method, reqPath, body, fresh, webwixFetch, forwardedHeaders));
46532
+ } catch (e) {
46533
+ const msg = String(e?.message ?? e);
46534
+ if (msg.includes("absolute URLs")) {
46535
+ return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
46536
+ }
46537
+ if (msg.includes("owner mint failed")) {
46538
+ if (/owner mint failed \(5\d\d\)/.test(msg)) return json3(502, { error: "webwix_bridge_upstream_failed" });
46539
+ return json3(501, { error: "webwix_owner_mint_failed", app: app2 });
46540
+ }
46541
+ return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
46542
+ }
46543
+ }
46544
+ const resolved2 = wixClientIdOf(utf8Decode(cfgBytes));
46545
+ if ("error" in resolved2) {
46546
+ return json3(501, { error: `webwix_bridge_${resolved2.error}`, app: app2 });
46547
+ }
46548
+ served.rung = "visitor";
46549
+ const memberStore = memberSessions();
46550
+ const memberBoundApp = memberApp(request);
46551
+ if (memberAuthOn() && memberStore && memberBoundApp !== null && memberBoundApp === app2) {
46552
+ const nowAuth = wixMemberAuthOf(utf8Decode(cfgBytes), callbackUrlFor(url));
46553
+ const memberToken = nowAuth.ok ? await memberTokenFor(memberStore, readSessionCookie(request.headers.get("cookie")), memberBoundApp, nowAuth.config.clientId) : null;
46554
+ if (memberToken) {
46555
+ served.rung = "member";
46556
+ try {
46557
+ return json3(200, await wixVisitorCall(method, reqPath, body, memberToken, webwixFetch, forwardedHeaders), { "cache-control": "no-store" });
46558
+ } catch (e) {
46559
+ const msg = String(e?.message ?? e);
46560
+ if (msg.includes("absolute URLs")) {
46561
+ return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
46562
+ }
46563
+ return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
46564
+ }
46565
+ }
46486
46566
  }
46487
- return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
46488
- }
46489
- }
46490
- const resolved2 = wixClientIdOf(utf8Decode(cfgBytes));
46491
- if ("error" in resolved2) {
46492
- return json3(501, { error: `webwix_bridge_${resolved2.error}`, app: app2 });
46493
- }
46494
- const memberStore = memberSessions();
46495
- const memberBoundApp = memberApp(request);
46496
- if (memberAuthOn() && memberStore && memberBoundApp !== null && memberBoundApp === app2) {
46497
- const nowAuth = wixMemberAuthOf(utf8Decode(cfgBytes), callbackUrlFor(url));
46498
- const memberToken = nowAuth.ok ? await memberTokenFor(memberStore, readSessionCookie(request.headers.get("cookie")), memberBoundApp, nowAuth.config.clientId) : null;
46499
- if (memberToken) {
46500
46567
  try {
46501
- return json3(200, await wixVisitorCall(method, reqPath, body, memberToken, webwixFetch, forwardedHeaders), { "cache-control": "no-store" });
46568
+ const token = await webwixTokens.token(resolved2.clientId);
46569
+ const first = await wixVisitorCall(method, reqPath, body, token, webwixFetch, forwardedHeaders);
46570
+ if (first.status !== 401) return json3(200, first);
46571
+ webwixTokens.invalidate(resolved2.clientId);
46572
+ const fresh = await webwixTokens.token(resolved2.clientId);
46573
+ return json3(200, await wixVisitorCall(method, reqPath, body, fresh, webwixFetch, forwardedHeaders));
46502
46574
  } catch (e) {
46503
46575
  const msg = String(e?.message ?? e);
46504
46576
  if (msg.includes("absolute URLs")) {
@@ -46506,22 +46578,15 @@ ${releaseId}`;
46506
46578
  }
46507
46579
  return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
46508
46580
  }
46581
+ })();
46582
+ status = res.status;
46583
+ return res;
46584
+ } finally {
46585
+ try {
46586
+ opts.onWebwixCall?.(webwixCallLog(served, status));
46587
+ } catch {
46509
46588
  }
46510
46589
  }
46511
- try {
46512
- const token = await webwixTokens.token(resolved2.clientId);
46513
- const first = await wixVisitorCall(method, reqPath, body, token, webwixFetch, forwardedHeaders);
46514
- if (first.status !== 401) return json3(200, first);
46515
- webwixTokens.invalidate(resolved2.clientId);
46516
- const fresh = await webwixTokens.token(resolved2.clientId);
46517
- return json3(200, await wixVisitorCall(method, reqPath, body, fresh, webwixFetch, forwardedHeaders));
46518
- } catch (e) {
46519
- const msg = String(e?.message ?? e);
46520
- if (msg.includes("absolute URLs")) {
46521
- return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
46522
- }
46523
- return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
46524
- }
46525
46590
  }
46526
46591
  if (request.method !== "GET") return json3(405, { error: "method_not_allowed" });
46527
46592
  if (path2 === "/__health") return json3(200, { ok: true });
@@ -46556,6 +46621,11 @@ ${releaseId}`;
46556
46621
  }
46557
46622
  if (path2 === "/v1/owner/instance") {
46558
46623
  if (opts.webwixBridge === false) return json3(503, { error: "webwix_bridge_disabled" });
46624
+ const gateApp = url.searchParams.get("app");
46625
+ if (gateApp) {
46626
+ const cfg = await appConfigFor(request, url, gateApp);
46627
+ if (!cfg.ok) return cfg.response;
46628
+ }
46559
46629
  if (!webwixOwnerRungOn()) return json3(503, { error: "webwix_owner_disabled" });
46560
46630
  const msid = url.searchParams.get("msid") ?? "";
46561
46631
  if (!isSafeMsid(msid)) return json3(400, { error: "webwix_owner_bad_msid" });
@@ -47214,8 +47284,29 @@ function makeRunHandler(opts) {
47214
47284
  return new Response(null, { status: 204 });
47215
47285
  }
47216
47286
  if (path2 === "/v1/screen-events") {
47217
- return new Response(new ReadableStream({ start() {
47218
- } }), {
47287
+ const source = opts.screenEvents;
47288
+ let unsubscribe;
47289
+ const body = new ReadableStream({
47290
+ start(controller) {
47291
+ if (!source) return;
47292
+ const encoder = new TextEncoder();
47293
+ controller.enqueue(encoder.encode(": himi run --watch\n\n"));
47294
+ unsubscribe = source.subscribe((event, data) => {
47295
+ try {
47296
+ controller.enqueue(encoder.encode(`event: ${event}
47297
+ data: ${JSON.stringify(data ?? {})}
47298
+
47299
+ `));
47300
+ } catch {
47301
+ unsubscribe?.();
47302
+ }
47303
+ });
47304
+ },
47305
+ cancel() {
47306
+ unsubscribe?.();
47307
+ }
47308
+ });
47309
+ return new Response(body, {
47219
47310
  status: 200,
47220
47311
  headers: { "content-type": "text/event-stream", "cache-control": "no-store", connection: "keep-alive" }
47221
47312
  });
@@ -47278,6 +47369,24 @@ async function toRequest(req) {
47278
47369
  async function writeResponse(res, response) {
47279
47370
  res.statusCode = response.status;
47280
47371
  response.headers.forEach((value, key2) => res.setHeader(key2, value));
47372
+ if (response.body && /^text\/event-stream\b/i.test(response.headers.get("content-type") ?? "")) {
47373
+ res.flushHeaders();
47374
+ const reader = response.body.getReader();
47375
+ res.on("close", () => {
47376
+ void reader.cancel().catch(() => {
47377
+ });
47378
+ });
47379
+ try {
47380
+ for (; ; ) {
47381
+ const { done, value } = await reader.read();
47382
+ if (done) break;
47383
+ res.write(value);
47384
+ }
47385
+ } catch {
47386
+ }
47387
+ res.end();
47388
+ return;
47389
+ }
47281
47390
  const ab = await response.arrayBuffer();
47282
47391
  res.end(ab.byteLength ? Buffer.from(ab) : void 0);
47283
47392
  }
@@ -47340,19 +47449,19 @@ var init_preview_assets_generated = __esm({
47340
47449
  "../../packages/serve/src/preview-assets.generated.ts"() {
47341
47450
  init_preview_assets_format();
47342
47451
  PREVIEW_ASSET_MANIFEST = [
47343
- { key: "assets/index-tPdez24X.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1012335, sha256: "9af3d246668e3b69acbdbaebf33129e45f99fdaa32230f782b675fcdeeb38773" },
47344
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1012343, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
47345
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1103267, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
47346
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1194251, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
47347
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1285231, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
47348
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1376103, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
47349
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1467083, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
47350
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1575719, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
47351
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1684803, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
47352
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1793851, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
47353
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1901551, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
47354
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1989659, length: 4448, sha256: "c4235c7ba4a7bdea831017711424c9e4f8a8b33466bef53f4def1bfcea6a3b15" },
47355
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1994107, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
47452
+ { key: "assets/index-TpXF5JLO.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1013412, sha256: "e6d1da59c13ca586b7834f4d08ca9e136b7fea8be9355d952d757fc66fc779a5" },
47453
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1013420, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
47454
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1104344, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
47455
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1195328, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
47456
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1286308, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
47457
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1377180, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
47458
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1468160, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
47459
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1576796, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
47460
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1685880, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
47461
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1794928, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
47462
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1902628, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
47463
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1990736, length: 4448, sha256: "5f0ee56640a5dfc73d3b2b78526aa1f7966de1bec39fe746e0d9ba39d57d829e" },
47464
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1995184, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
47356
47465
  ];
47357
47466
  }
47358
47467
  });
@@ -47368,7 +47477,7 @@ __export(run_exports, {
47368
47477
  runPackage: () => runPackage,
47369
47478
  withoutProdServe: () => withoutProdServe
47370
47479
  });
47371
- import { cpSync as cpSync2, existsSync as existsSync52, mkdirSync as mkdirSync26, mkdtempSync as mkdtempSync3, readFileSync as readFileSync57, rmSync as rmSync10, statSync as statSync13 } from "node:fs";
47480
+ import { cpSync as cpSync2, existsSync as existsSync52, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, readFileSync as readFileSync57, rmSync as rmSync11, statSync as statSync13 } from "node:fs";
47372
47481
  import { tmpdir as tmpdir4 } from "node:os";
47373
47482
  import { dirname as dirname27, join as join49 } from "node:path";
47374
47483
  import { fileURLToPath as fileURLToPath22 } from "node:url";
@@ -47378,7 +47487,8 @@ function makePackageRunHandler(opts) {
47378
47487
  app: opts.app,
47379
47488
  assets: opts.assets,
47380
47489
  ...opts.chrome ? { chrome: opts.chrome } : {},
47381
- header: opts.header ?? null
47490
+ header: opts.header ?? null,
47491
+ ...opts.screenEvents ? { screenEvents: opts.screenEvents } : {}
47382
47492
  });
47383
47493
  }
47384
47494
  async function fetchBytes(url) {
@@ -47402,8 +47512,8 @@ async function resolvePackage(source, workDir) {
47402
47512
  const root2 = workDir ?? mkdtempSync3(join49(tmpdir4(), "himi-run-"));
47403
47513
  const target = join49(root2, app2);
47404
47514
  if (join49(source) !== target) {
47405
- mkdirSync26(root2, { recursive: true });
47406
- rmSync10(target, { recursive: true, force: true });
47515
+ mkdirSync25(root2, { recursive: true });
47516
+ rmSync11(target, { recursive: true, force: true });
47407
47517
  cpSync2(source, target, { recursive: true });
47408
47518
  }
47409
47519
  return {
@@ -47423,7 +47533,7 @@ async function resolvePackage(source, workDir) {
47423
47533
  const { app, appDir: appDir2 } = unpackTo(bytes2, root);
47424
47534
  const opened = openPackageDir(appDir2);
47425
47535
  if (!opened.validation.ok) {
47426
- rmSync10(workDir ? appDir2 : root, { recursive: true, force: true });
47536
+ rmSync11(workDir ? appDir2 : root, { recursive: true, force: true });
47427
47537
  throw new Error(`package is not valid:
47428
47538
  ${opened.validation.errors.join("\n ")}`);
47429
47539
  }
@@ -47470,16 +47580,19 @@ async function runPackage(source, opts = {}) {
47470
47580
  const resolved2 = await resolvePackage(source, opts.workDir);
47471
47581
  const assets = opts.assets ?? (opts.spa ? /* @__PURE__ */ new Map() : await loadPreviewAssets());
47472
47582
  if (!opts.spa && assets.size === 0) {
47473
- if (resolved2.temp) rmSync10(resolved2.temp, { recursive: true, force: true });
47583
+ if (resolved2.temp) rmSync11(resolved2.temp, { recursive: true, force: true });
47474
47584
  throw new Error(NO_SPA_MESSAGE);
47475
47585
  }
47476
- const handler = makePackageRunHandler({
47586
+ const plane = makePackageRunHandler({
47477
47587
  releaseRoot: resolved2.releaseRoot,
47478
47588
  app: resolved2.app,
47479
47589
  assets,
47480
47590
  chrome: opts.chrome,
47481
- header: resolved2.header
47591
+ header: resolved2.header,
47592
+ ...opts.screenEvents ? { screenEvents: opts.screenEvents } : {}
47482
47593
  });
47594
+ const extra = opts.extraRoutes;
47595
+ const handler = extra ? (request) => extra(request) ?? plane(request) : plane;
47483
47596
  const server = nodeAdapter(handler);
47484
47597
  const host = opts.host ?? "127.0.0.1";
47485
47598
  const port = await new Promise((resolvePort, reject) => {
@@ -47497,10 +47610,13 @@ async function runPackage(source, opts = {}) {
47497
47610
  releaseId: resolved2.releaseId,
47498
47611
  port,
47499
47612
  url,
47613
+ releaseRoot: resolved2.releaseRoot,
47614
+ origin,
47500
47615
  warnings: resolved2.warnings,
47501
47616
  close: () => new Promise((done) => {
47617
+ server.closeAllConnections?.();
47502
47618
  server.close(() => {
47503
- if (resolved2.temp) rmSync10(resolved2.temp, { recursive: true, force: true });
47619
+ if (resolved2.temp) rmSync11(resolved2.temp, { recursive: true, force: true });
47504
47620
  done();
47505
47621
  });
47506
47622
  })
@@ -47520,6 +47636,250 @@ var init_run = __esm({
47520
47636
  }
47521
47637
  });
47522
47638
 
47639
+ // src/run-watch.ts
47640
+ var run_watch_exports = {};
47641
+ __export(run_watch_exports, {
47642
+ ReloadBus: () => ReloadBus,
47643
+ boardFile: () => boardFile,
47644
+ diffReleases: () => diffReleases,
47645
+ himiDir: () => himiDir,
47646
+ ignoredChange: () => ignoredChange,
47647
+ isEmptyDiff: () => isEmptyDiff,
47648
+ rebuildBlocker: () => rebuildBlocker,
47649
+ reloadEvents: () => reloadEvents,
47650
+ removeRunRecord: () => removeRunRecord,
47651
+ serialize: () => serialize,
47652
+ watchContent: () => watchContent,
47653
+ watchFlagConflict: () => watchFlagConflict,
47654
+ watchedContentDir: () => watchedContentDir,
47655
+ writeRunRecord: () => writeRunRecord
47656
+ });
47657
+ import { closeSync as closeSync2, constants, existsSync as existsSync53, fstatSync, lstatSync as lstatSync7, statSync as statSync14, mkdirSync as mkdirSync26, openSync as openSync2, readFileSync as readFileSync58, realpathSync as realpathSync6, renameSync as renameSync5, rmSync as rmSync12, writeFileSync as writeFileSync22, watch as fsWatch } from "node:fs";
47658
+ import { randomUUID as randomUUID3 } from "node:crypto";
47659
+ import { extname as extname4, join as join50, resolve as resolve42, sep as sep13 } from "node:path";
47660
+ function diffReleases(prev, next) {
47661
+ const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
47662
+ const changedBundles = new Set(bundles);
47663
+ const screens = Object.entries(next.screens).filter(([id, s]) => {
47664
+ const before = prev.screens[id];
47665
+ return !before || before.descriptorHash !== s.descriptorHash || before.bundle !== s.bundle || s.bundle !== null && changedBundles.has(s.bundle);
47666
+ }).map(([id]) => id).sort();
47667
+ const prevIds = Object.keys(prev.screens).sort().join("\n");
47668
+ const nextIds = Object.keys(next.screens).sort().join("\n");
47669
+ return {
47670
+ screens,
47671
+ bundles,
47672
+ tokens: prev.tokensHash !== next.tokensHash,
47673
+ config: prev.appConfigHash !== next.appConfigHash || prevIds !== nextIds
47674
+ };
47675
+ }
47676
+ function reloadEvents(d) {
47677
+ const out = [];
47678
+ if (d.bundles.length) out.push(["bundle.invalidated", { bundles: d.bundles }]);
47679
+ if (d.screens.length) out.push(["screen.invalidated", { screenIds: d.screens }]);
47680
+ if (d.tokens) out.push(["tokens.changed", {}]);
47681
+ if (d.config) out.push(["config.invalidated", {}]);
47682
+ return out;
47683
+ }
47684
+ function ignoredChange(relPath, isDirectory = () => false) {
47685
+ const parts = relPath.split(/[\\/]/).filter(Boolean);
47686
+ if (!parts.length) return true;
47687
+ const [top] = parts;
47688
+ if ([".himi", "dist", "node_modules", ".git", ".build"].includes(top)) return true;
47689
+ if ((top === "shots" || top === "evidence") && (parts.length > 1 || isDirectory(top))) return true;
47690
+ const name = parts[parts.length - 1];
47691
+ return /(^\.#|~$|\.sw[a-p]$|^\.DS_Store$|\.tmp$)/.test(name);
47692
+ }
47693
+ function watchContent(dir, onChange, opts = {}) {
47694
+ const debounceMs = opts.debounceMs ?? 200;
47695
+ const watch2 = opts.watch ?? ((p, o, l) => fsWatch(p, o, (event, file) => l(event, file === null ? null : String(file))));
47696
+ let timer = null;
47697
+ const pending = /* @__PURE__ */ new Set();
47698
+ const watcher = watch2(dir, { recursive: true }, (_event, file) => {
47699
+ if (!file || ignoredChange(file, (rel) => isDir(join50(dir, rel)))) return;
47700
+ pending.add(file);
47701
+ if (timer) clearTimeout(timer);
47702
+ timer = setTimeout(() => {
47703
+ timer = null;
47704
+ const paths = [...pending];
47705
+ pending.clear();
47706
+ onChange(paths);
47707
+ }, debounceMs);
47708
+ });
47709
+ return {
47710
+ close() {
47711
+ if (timer) clearTimeout(timer);
47712
+ watcher.close();
47713
+ }
47714
+ };
47715
+ }
47716
+ function watchedContentDir(source) {
47717
+ if (!source || /^https?:\/\//i.test(source)) return null;
47718
+ const dir = resolve42(source);
47719
+ try {
47720
+ return statSync14(dir).isDirectory() && existsSync53(join50(dir, "himalaya.content.json")) ? dir : null;
47721
+ } catch {
47722
+ return null;
47723
+ }
47724
+ }
47725
+ function watchFlagConflict(opts) {
47726
+ if (opts.source) {
47727
+ return { error: "watch_needs_source", message: "--watch rebuilds a content package on every save, so it cannot watch a packaged release or a URL. Pass the app's directory (the one with himalaya.content.json), --content <dir>, or run it from there with no argument." };
47728
+ }
47729
+ if (opts.browser) {
47730
+ return { error: "watch_with_browser", message: "--watch rebuilds and serves from this process; --browser runs the whole plane inside the tab. Pick one." };
47731
+ }
47732
+ if (opts.spa) {
47733
+ return { error: "watch_with_spa", message: "--watch pushes each rebuild to the open tab over this server's own origin, and a hosted SPA (--spa) listens on its origin instead, so it would never repaint. Drop --spa to watch with the bundled web host, or drop --watch." };
47734
+ }
47735
+ return null;
47736
+ }
47737
+ function rebuildBlocker(outcome, servedMissing) {
47738
+ const failed2 = outcome.failedToBuild[0];
47739
+ if (failed2) return `${failed2.screenId}: ${failed2.error.split("\n")[0]}`;
47740
+ const had = new Set(servedMissing.map((m) => `${m.screen}\0${m.bundle}`));
47741
+ const lost = outcome.missingBundles.find((m) => !had.has(`${m.screen}\0${m.bundle}`));
47742
+ if (lost) return `${lost.screen}: its worker bundle "${lost.bundle}" is referenced but was not built`;
47743
+ return null;
47744
+ }
47745
+ function serialize(task) {
47746
+ let running = null;
47747
+ let again = false;
47748
+ let stopped = false;
47749
+ const go = () => {
47750
+ if (stopped) return;
47751
+ if (running) {
47752
+ again = true;
47753
+ return;
47754
+ }
47755
+ running = (async () => {
47756
+ try {
47757
+ await task();
47758
+ } finally {
47759
+ running = null;
47760
+ if (again && !stopped) {
47761
+ again = false;
47762
+ go();
47763
+ }
47764
+ }
47765
+ })();
47766
+ };
47767
+ return Object.assign(() => go(), {
47768
+ async stop() {
47769
+ stopped = true;
47770
+ again = false;
47771
+ await running?.catch(() => {
47772
+ });
47773
+ }
47774
+ });
47775
+ }
47776
+ function himiDir(dir) {
47777
+ const root = join50(dir, ".himi");
47778
+ try {
47779
+ return lstatSync7(root).isDirectory() ? root : null;
47780
+ } catch (e) {
47781
+ if (e.code !== "ENOENT") return null;
47782
+ mkdirSync26(root, { recursive: true });
47783
+ return lstatSync7(root).isDirectory() ? root : null;
47784
+ }
47785
+ }
47786
+ function writeRunRecord(dir, record2) {
47787
+ const root = himiDir(dir);
47788
+ if (!root) return false;
47789
+ const tmp = join50(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
47790
+ try {
47791
+ writeFileSync22(tmp, `${JSON.stringify(record2, null, 2)}
47792
+ `, { flag: "wx" });
47793
+ renameSync5(tmp, join50(root, "run.json"));
47794
+ } catch (e) {
47795
+ rmSync12(tmp, { force: true });
47796
+ throw e;
47797
+ }
47798
+ return true;
47799
+ }
47800
+ function removeRunRecord(dir) {
47801
+ const root = join50(dir, ".himi");
47802
+ try {
47803
+ if (!lstatSync7(root).isDirectory()) return;
47804
+ } catch {
47805
+ return;
47806
+ }
47807
+ rmSync12(join50(root, "run.json"), { force: true });
47808
+ }
47809
+ function boardFile(dir, pathname) {
47810
+ let rel = null;
47811
+ if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join50("studio", "index.html");
47812
+ else if (pathname === "/__himi/studio/state.js") rel = join50("studio", "state.js");
47813
+ else {
47814
+ const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
47815
+ if (m) rel = join50("history", m[1]);
47816
+ }
47817
+ if (!rel) return null;
47818
+ const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
47819
+ if (!bytes2) return new Response("not found", { status: 404 });
47820
+ return new Response(bytes2, {
47821
+ status: 200,
47822
+ headers: { "content-type": BOARD_TYPES[extname4(rel)] ?? "application/octet-stream", "cache-control": rel.startsWith("history") ? "public, max-age=31536000, immutable" : "no-store" }
47823
+ });
47824
+ }
47825
+ function readConfined(root, rel) {
47826
+ try {
47827
+ if (!lstatSync7(root).isDirectory()) return null;
47828
+ const parts = rel.split(sep13);
47829
+ let at = root;
47830
+ for (let i = 0; i < parts.length; i++) {
47831
+ at = join50(at, parts[i]);
47832
+ const st = lstatSync7(at);
47833
+ if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
47834
+ }
47835
+ const canonicalRoot = realpathSync6(root);
47836
+ if (!realpathSync6(at).startsWith(canonicalRoot + sep13)) return null;
47837
+ const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
47838
+ try {
47839
+ if (!fstatSync(fd).isFile()) return null;
47840
+ return readFileSync58(fd);
47841
+ } finally {
47842
+ closeSync2(fd);
47843
+ }
47844
+ } catch {
47845
+ return null;
47846
+ }
47847
+ }
47848
+ var isEmptyDiff, ReloadBus, isDir, BOARD_TYPES;
47849
+ var init_run_watch = __esm({
47850
+ "src/run-watch.ts"() {
47851
+ isEmptyDiff = (d) => !d.screens.length && !d.bundles.length && !d.tokens && !d.config;
47852
+ ReloadBus = class {
47853
+ subscribers = /* @__PURE__ */ new Set();
47854
+ subscribe(send2) {
47855
+ this.subscribers.add(send2);
47856
+ return () => this.subscribers.delete(send2);
47857
+ }
47858
+ publish(event, data) {
47859
+ for (const send2 of [...this.subscribers]) send2(event, data);
47860
+ }
47861
+ get listeners() {
47862
+ return this.subscribers.size;
47863
+ }
47864
+ };
47865
+ isDir = (path2) => {
47866
+ try {
47867
+ return statSync14(path2).isDirectory();
47868
+ } catch {
47869
+ return false;
47870
+ }
47871
+ };
47872
+ BOARD_TYPES = {
47873
+ ".html": "text/html; charset=utf-8",
47874
+ ".js": "text/javascript; charset=utf-8",
47875
+ ".png": "image/png",
47876
+ ".jpg": "image/jpeg",
47877
+ ".gif": "image/gif",
47878
+ ".webp": "image/webp"
47879
+ };
47880
+ }
47881
+ });
47882
+
47523
47883
  // src/run-browser.ts
47524
47884
  var run_browser_exports = {};
47525
47885
  __export(run_browser_exports, {
@@ -47528,19 +47888,19 @@ __export(run_browser_exports, {
47528
47888
  runInBrowser: () => runInBrowser
47529
47889
  });
47530
47890
  import { createServer as createServer5 } from "node:http";
47531
- import { existsSync as existsSync53, readFileSync as readFileSync58 } from "node:fs";
47891
+ import { existsSync as existsSync54, readFileSync as readFileSync59 } from "node:fs";
47532
47892
  import { spawnSync as spawnSync3 } from "node:child_process";
47533
- import { dirname as dirname28, resolve as resolve42 } from "node:path";
47893
+ import { dirname as dirname28, resolve as resolve43 } from "node:path";
47534
47894
  import { fileURLToPath as fileURLToPath23 } from "node:url";
47535
47895
  function stagedDir() {
47536
- return process.env.HIMI_BROWSER_PLANE_OUT ? resolve42(process.env.HIMI_BROWSER_PLANE_OUT) : resolve42(REPO, "packages", "serve", "dist", "browser-plane");
47896
+ return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
47537
47897
  }
47538
47898
  function missingStaged() {
47539
- return [...SERVED].filter((f) => !existsSync53(resolve42(stagedDir(), f))).sort();
47899
+ return [...SERVED].filter((f) => !existsSync54(resolve43(stagedDir(), f))).sort();
47540
47900
  }
47541
47901
  function ensureBrowserPlaneStaged() {
47542
47902
  if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
47543
- const r = spawnSync3(process.execPath, [resolve42(REPO, "core/serve/scripts/stage-browser-plane.mjs")], {
47903
+ const r = spawnSync3(process.execPath, [resolve43(REPO, "core/serve/scripts/stage-browser-plane.mjs")], {
47544
47904
  cwd: REPO,
47545
47905
  encoding: "utf8"
47546
47906
  });
@@ -47626,7 +47986,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
47626
47986
  }
47627
47987
  const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
47628
47988
  if (SERVED.has(name)) {
47629
- if (!existsSync53(resolve42(stagedDir(), name))) {
47989
+ if (!existsSync54(resolve43(stagedDir(), name))) {
47630
47990
  const restaged = ensureBrowserPlaneStaged();
47631
47991
  if (!restaged.ok) {
47632
47992
  res.writeHead(503, { "content-type": "application/json" });
@@ -47636,7 +47996,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
47636
47996
  }
47637
47997
  let bytes2;
47638
47998
  try {
47639
- bytes2 = readFileSync58(resolve42(stagedDir(), name));
47999
+ bytes2 = readFileSync59(resolve43(stagedDir(), name));
47640
48000
  } catch (e) {
47641
48001
  res.writeHead(503, { "content-type": "application/json" });
47642
48002
  res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
@@ -47677,7 +48037,7 @@ var init_run_browser = __esm({
47677
48037
  init_open_url();
47678
48038
  init_file_store();
47679
48039
  HERE = dirname28(fileURLToPath23(import.meta.url));
47680
- REPO = resolve42(HERE, "..", "..", "..");
48040
+ REPO = resolve43(HERE, "..", "..", "..");
47681
48041
  SERVED = /* @__PURE__ */ new Set(["host.html", "sw.js", "package-reader.js"]);
47682
48042
  }
47683
48043
  });
@@ -48096,10 +48456,10 @@ __export(preflight_exports, {
48096
48456
  parseStoreConfig: () => parseStoreConfig,
48097
48457
  requireEnv: () => requireEnv
48098
48458
  });
48099
- import { existsSync as existsSync54, readFileSync as readFileSync59 } from "node:fs";
48100
- import { isAbsolute as isAbsolute3, relative as relative9, resolve as resolve43 } from "node:path";
48459
+ import { existsSync as existsSync55, readFileSync as readFileSync60 } from "node:fs";
48460
+ import { isAbsolute as isAbsolute3, relative as relative9, resolve as resolve44 } from "node:path";
48101
48461
  function isInsideRepo(p) {
48102
- const rel = relative9(REPO_ROOT3, resolve43(p));
48462
+ const rel = relative9(REPO_ROOT3, resolve44(p));
48103
48463
  return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
48104
48464
  }
48105
48465
  function assertCredentialOutsideRepo(label2, p) {
@@ -48153,10 +48513,10 @@ function parseStoreConfig(text5) {
48153
48513
  }
48154
48514
  function loadStoreConfig(app) {
48155
48515
  const p = storeConfigPath(app);
48156
- if (!existsSync54(p)) {
48516
+ if (!existsSync55(p)) {
48157
48517
  throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
48158
48518
  }
48159
- return parseStoreConfig(readFileSync59(p, "utf8"));
48519
+ return parseStoreConfig(readFileSync60(p, "utf8"));
48160
48520
  }
48161
48521
  var init_preflight = __esm({
48162
48522
  "../store-release/preflight.ts"() {
@@ -48175,19 +48535,19 @@ __export(credential_profile_exports, {
48175
48535
  profilePath: () => profilePath,
48176
48536
  resolveStoreCredentials: () => resolveStoreCredentials
48177
48537
  });
48178
- import { existsSync as existsSync55, readFileSync as readFileSync60 } from "node:fs";
48538
+ import { existsSync as existsSync56, readFileSync as readFileSync61 } from "node:fs";
48179
48539
  import { homedir as homedir5 } from "node:os";
48180
- import { join as join50 } from "node:path";
48540
+ import { join as join51 } from "node:path";
48181
48541
  function credentialsDir(home = homedir5()) {
48182
- return join50(home, ".himalaya", "store-credentials");
48542
+ return join51(home, ".himalaya", "store-credentials");
48183
48543
  }
48184
48544
  function profilePath(name, home = homedir5()) {
48185
48545
  if (!PROFILE_NAME.test(name)) {
48186
48546
  throw new Error(
48187
- `credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join50(credentialsDir(home), "<name>.json")}; it is never a path.`
48547
+ `credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join51(credentialsDir(home), "<name>.json")}; it is never a path.`
48188
48548
  );
48189
48549
  }
48190
- return join50(credentialsDir(home), `${name}.json`);
48550
+ return join51(credentialsDir(home), `${name}.json`);
48191
48551
  }
48192
48552
  function parseProfile(text5, label2) {
48193
48553
  let doc;
@@ -48218,8 +48578,8 @@ function resolveStoreCredentials(opts) {
48218
48578
  const { app, cfg } = opts;
48219
48579
  const env = opts.env ?? process.env;
48220
48580
  const home = opts.home ?? homedir5();
48221
- const read = opts.readProfile ?? ((p) => readFileSync60(p, "utf8"));
48222
- const exists = opts.profileExists ?? existsSync55;
48581
+ const read = opts.readProfile ?? ((p) => readFileSync61(p, "utf8"));
48582
+ const exists = opts.profileExists ?? existsSync56;
48223
48583
  const ios = cfg.ios ?? {};
48224
48584
  const flagName = opts.profileFlag?.trim();
48225
48585
  const named = namedProfile(cfg, opts.profileFlag);
@@ -48299,9 +48659,9 @@ __export(preflight_app_exports, {
48299
48659
  preflightApp: () => preflightApp,
48300
48660
  profileAccount: () => profileAccount
48301
48661
  });
48302
- import { readFileSync as readFileSync61, existsSync as existsSync56, readdirSync as readdirSync26, statSync as statSync14 } from "node:fs";
48662
+ import { readFileSync as readFileSync62, existsSync as existsSync57, readdirSync as readdirSync26, statSync as statSync15 } from "node:fs";
48303
48663
  import { createHash as createHash25 } from "node:crypto";
48304
- import { join as join51 } from "node:path";
48664
+ import { join as join52 } from "node:path";
48305
48665
  function analyze(projectYml, storeConfig, icon, account) {
48306
48666
  const f = [];
48307
48667
  const has = (re, s) => re.test(s);
@@ -48365,13 +48725,13 @@ function profileAccount(app, storeConfig, opts = {}) {
48365
48725
  }
48366
48726
  }
48367
48727
  async function preflightApp(app, opts = {}) {
48368
- const projectYml = existsSync56(iosProjectYml(app)) ? readFileSync61(iosProjectYml(app), "utf8") : "";
48369
- const storeConfig = existsSync56(storeConfigPath(app)) ? readFileSync61(storeConfigPath(app), "utf8") : "";
48728
+ const projectYml = existsSync57(iosProjectYml(app)) ? readFileSync62(iosProjectYml(app), "utf8") : "";
48729
+ const storeConfig = existsSync57(storeConfigPath(app)) ? readFileSync62(storeConfigPath(app), "utf8") : "";
48370
48730
  if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
48371
48731
  const findings = analyze(
48372
48732
  projectYml,
48373
48733
  storeConfig,
48374
- await appIconState(join51(appDir(app), "ios")),
48734
+ await appIconState(join52(appDir(app), "ios")),
48375
48735
  profileAccount(app, storeConfig, opts)
48376
48736
  );
48377
48737
  findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
@@ -48400,17 +48760,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
48400
48760
  return f;
48401
48761
  }
48402
48762
  function appLevelMetadataFiles(app, locale = "en-US") {
48403
- const root = join51(storeDir(app), "metadata");
48763
+ const root = join52(storeDir(app), "metadata");
48404
48764
  const out = /* @__PURE__ */ new Set();
48405
- if (existsSync56(root)) {
48765
+ if (existsSync57(root)) {
48406
48766
  for (const n of readdirSync26(root)) if (n.endsWith(".txt")) out.add(n);
48407
48767
  }
48408
- if (existsSync56(join51(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
48768
+ if (existsSync57(join52(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
48409
48769
  return out;
48410
48770
  }
48411
48771
  function reviewInfoFiles(app) {
48412
- const dir = join51(storeDir(app), "review_information");
48413
- if (!existsSync56(dir)) return /* @__PURE__ */ new Set();
48772
+ const dir = join52(storeDir(app), "review_information");
48773
+ if (!existsSync57(dir)) return /* @__PURE__ */ new Set();
48414
48774
  return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
48415
48775
  }
48416
48776
  function isValidAppStoreSize(w, h) {
@@ -48520,12 +48880,12 @@ function analyzePlayListing(assets) {
48520
48880
  return f;
48521
48881
  }
48522
48882
  function playListingAssets(app, locale = "en-US") {
48523
- const dir = join51(storeDir(app), "play", locale, "images");
48883
+ const dir = join52(storeDir(app), "play", locale, "images");
48524
48884
  const read = (names) => {
48525
48885
  for (const name of names) {
48526
- const p = join51(dir, name);
48886
+ const p = join52(dir, name);
48527
48887
  try {
48528
- if (statSync14(p).isFile()) return { name, bytes: readFileSync61(p) };
48888
+ if (statSync15(p).isFile()) return { name, bytes: readFileSync62(p) };
48529
48889
  } catch {
48530
48890
  }
48531
48891
  }
@@ -48556,26 +48916,26 @@ function analyzeListing(metaFiles, shots) {
48556
48916
  return f;
48557
48917
  }
48558
48918
  function metadataFilesPresent(app, locale = "en-US") {
48559
- const dir = join51(storeDir(app), "metadata", locale);
48560
- if (!existsSync56(dir)) return /* @__PURE__ */ new Set();
48919
+ const dir = join52(storeDir(app), "metadata", locale);
48920
+ if (!existsSync57(dir)) return /* @__PURE__ */ new Set();
48561
48921
  return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
48562
48922
  }
48563
48923
  function listScreenshots(app, locale = "en-US") {
48564
48924
  const out = [];
48565
- const flat = join51(storeDir(app), "screenshots", locale);
48566
- if (existsSync56(flat)) {
48925
+ const flat = join52(storeDir(app), "screenshots", locale);
48926
+ if (existsSync57(flat)) {
48567
48927
  for (const png of readdirSync26(flat).filter((n) => n.endsWith(".png"))) {
48568
- const sz = pngSize(readFileSync61(join51(flat, png)));
48928
+ const sz = pngSize(readFileSync62(join52(flat, png)));
48569
48929
  if (sz) out.push({ name: png, w: sz.w, h: sz.h });
48570
48930
  }
48571
48931
  }
48572
- const legacy = join51(storeDir(app), "metadata", locale, "screenshots");
48573
- if (existsSync56(legacy)) {
48932
+ const legacy = join52(storeDir(app), "metadata", locale, "screenshots");
48933
+ if (existsSync57(legacy)) {
48574
48934
  for (const deviceDir of readdirSync26(legacy)) {
48575
- const d = join51(legacy, deviceDir);
48576
- if (!statSync14(d).isDirectory()) continue;
48935
+ const d = join52(legacy, deviceDir);
48936
+ if (!statSync15(d).isDirectory()) continue;
48577
48937
  for (const png of readdirSync26(d).filter((n) => n.endsWith(".png"))) {
48578
- const sz = pngSize(readFileSync61(join51(d, png)));
48938
+ const sz = pngSize(readFileSync62(join52(d, png)));
48579
48939
  if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
48580
48940
  }
48581
48941
  }
@@ -48583,13 +48943,13 @@ function listScreenshots(app, locale = "en-US") {
48583
48943
  return out;
48584
48944
  }
48585
48945
  function placeholderHashes2() {
48586
- const templateIos = join51(appDir("_template"), "ios");
48587
- if (!existsSync56(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
48946
+ const templateIos = join52(appDir("_template"), "ios");
48947
+ if (!existsSync57(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
48588
48948
  for (const target of readdirSync26(templateIos)) {
48589
- const p = join51(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48949
+ const p = join52(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48590
48950
  try {
48591
- if (!statSync14(p).isFile()) continue;
48592
- return [LEGACY_PLACEHOLDER_SHA2562, createHash25("sha256").update(readFileSync61(p)).digest("hex")];
48951
+ if (!statSync15(p).isFile()) continue;
48952
+ return [LEGACY_PLACEHOLDER_SHA2562, createHash25("sha256").update(readFileSync62(p)).digest("hex")];
48593
48953
  } catch {
48594
48954
  }
48595
48955
  }
@@ -48620,12 +48980,12 @@ async function pixelIssues(bytes2) {
48620
48980
  }
48621
48981
  }
48622
48982
  async function appIconState(iosDir) {
48623
- if (!existsSync56(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
48983
+ if (!existsSync57(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
48624
48984
  for (const target of readdirSync26(iosDir)) {
48625
- const p = join51(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48985
+ const p = join52(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48626
48986
  try {
48627
- if (!statSync14(p).isFile()) continue;
48628
- const bytes2 = readFileSync61(p);
48987
+ if (!statSync15(p).isFile()) continue;
48988
+ const bytes2 = readFileSync62(p);
48629
48989
  const hash = createHash25("sha256").update(bytes2).digest("hex");
48630
48990
  const pixels = await pixelIssues(bytes2);
48631
48991
  return {
@@ -48697,7 +49057,7 @@ __export(version_exports, {
48697
49057
  setAndroidVersion: () => setAndroidVersion,
48698
49058
  setIosVersion: () => setIosVersion
48699
49059
  });
48700
- import { readFileSync as readFileSync62, writeFileSync as writeFileSync23 } from "node:fs";
49060
+ import { readFileSync as readFileSync63, writeFileSync as writeFileSync23 } from "node:fs";
48701
49061
  function readIosVersion(projectYml) {
48702
49062
  const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
48703
49063
  const build2 = matchScalar(projectYml, "CFBundleVersion");
@@ -48755,8 +49115,8 @@ function setAndroidVersion(gradle, v) {
48755
49115
  function bumpVersion(app, opts) {
48756
49116
  const iosPath = iosProjectYml(app);
48757
49117
  const gradlePath = androidGradle(app);
48758
- const iosYml = readFileSync62(iosPath, "utf8");
48759
- const gradle = readFileSync62(gradlePath, "utf8");
49118
+ const iosYml = readFileSync63(iosPath, "utf8");
49119
+ const gradle = readFileSync63(gradlePath, "utf8");
48760
49120
  const current = readIosVersion(iosYml);
48761
49121
  const next = {
48762
49122
  marketing: opts.marketing ?? current.marketing,
@@ -48773,7 +49133,7 @@ var init_version = __esm({
48773
49133
  });
48774
49134
 
48775
49135
  // ../store-release/register-bundle.ts
48776
- import { readFileSync as readFileSync63 } from "node:fs";
49136
+ import { readFileSync as readFileSync64 } from "node:fs";
48777
49137
  import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
48778
49138
  function b64url2(b) {
48779
49139
  return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -48791,7 +49151,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
48791
49151
  async function registerBundleId(opts) {
48792
49152
  const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
48793
49153
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
48794
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync63(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
49154
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync64(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
48795
49155
  const res = await fetch(`${ASC_API}/v1/bundleIds`, {
48796
49156
  method: "POST",
48797
49157
  headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
@@ -48845,7 +49205,7 @@ __export(asc_status_exports, {
48845
49205
  ascStatus: () => ascStatus,
48846
49206
  buildVerdict: () => buildVerdict
48847
49207
  });
48848
- import { readFileSync as readFileSync64 } from "node:fs";
49208
+ import { readFileSync as readFileSync65 } from "node:fs";
48849
49209
  function buildVerdict(builds) {
48850
49210
  if (!builds.length) {
48851
49211
  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).";
@@ -48859,7 +49219,7 @@ function buildVerdict(builds) {
48859
49219
  function client(creds) {
48860
49220
  const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
48861
49221
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
48862
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync64(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
49222
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync65(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
48863
49223
  return async (path2) => {
48864
49224
  const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
48865
49225
  return { status: r.status, json: await r.json().catch(() => ({})) };
@@ -49019,7 +49379,7 @@ __export(secrets_exports, {
49019
49379
  runRemoteSecretsCommand: () => runRemoteSecretsCommand,
49020
49380
  runSecretsCommand: () => runSecretsCommand
49021
49381
  });
49022
- import { readFileSync as readFileSync65 } from "node:fs";
49382
+ import { readFileSync as readFileSync66 } from "node:fs";
49023
49383
  function environment(value) {
49024
49384
  if (value === "preview" || value === "production") return value;
49025
49385
  throw new Error("--environment must be preview or production");
@@ -49050,7 +49410,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
49050
49410
  io.log(JSON.stringify(await vault.list({ app, environment: env })));
49051
49411
  return 0;
49052
49412
  }
49053
- const value = options.readValue ? options.readValue() : readFileSync65(0, "utf8").replace(/\r?\n$/, "");
49413
+ const value = options.readValue ? options.readValue() : readFileSync66(0, "utf8").replace(/\r?\n$/, "");
49054
49414
  if (operation === "set") await vault.set({ app, environment: env, name, value });
49055
49415
  else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
49056
49416
  else throw new Error(`unknown secrets operation ${operation}`);
@@ -49079,7 +49439,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
49079
49439
  }
49080
49440
  let body;
49081
49441
  if (operation !== "list") {
49082
- const value = options.readValue ? options.readValue() : readFileSync65(0, "utf8").replace(/\r?\n$/, "");
49442
+ const value = options.readValue ? options.readValue() : readFileSync66(0, "utf8").replace(/\r?\n$/, "");
49083
49443
  body = JSON.stringify({ value });
49084
49444
  }
49085
49445
  const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
@@ -49115,15 +49475,15 @@ __export(notify_exports, {
49115
49475
  runNotify: () => runNotify,
49116
49476
  saveAdminSession: () => saveAdminSession
49117
49477
  });
49118
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync66, writeFileSync as writeFileSync24 } from "node:fs";
49478
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync67, writeFileSync as writeFileSync24 } from "node:fs";
49119
49479
  import { homedir as homedir6 } from "node:os";
49120
- import { dirname as dirname30, join as join52 } from "node:path";
49480
+ import { dirname as dirname30, join as join53 } from "node:path";
49121
49481
  function defaultSessionsPath() {
49122
- return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join52(homedir6(), ".himalaya", "admin-sessions.json");
49482
+ return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join53(homedir6(), ".himalaya", "admin-sessions.json");
49123
49483
  }
49124
49484
  function loadSessionsFile(path2 = defaultSessionsPath()) {
49125
49485
  try {
49126
- return JSON.parse(readFileSync66(path2, "utf8"));
49486
+ return JSON.parse(readFileSync67(path2, "utf8"));
49127
49487
  } catch {
49128
49488
  return {};
49129
49489
  }
@@ -51780,10 +52140,10 @@ function assertPublicSiteUrl(raw) {
51780
52140
  if (refusal) throw new Error(refusal);
51781
52141
  }
51782
52142
  function resolveAll(hostname2) {
51783
- return new Promise((resolve47, reject) => {
52143
+ return new Promise((resolve48, reject) => {
51784
52144
  dnsLookup(hostname2, { all: true, verbatim: true }, (err, addresses) => {
51785
52145
  if (err) reject(err);
51786
- else resolve47(addresses);
52146
+ else resolve48(addresses);
51787
52147
  });
51788
52148
  });
51789
52149
  }
@@ -51791,13 +52151,13 @@ function withAbort(start, signal, what) {
51791
52151
  if (signal?.aborted) return Promise.reject(new Error(`${what} aborted`));
51792
52152
  const work = start();
51793
52153
  if (!signal) return work;
51794
- return new Promise((resolve47, reject) => {
52154
+ return new Promise((resolve48, reject) => {
51795
52155
  const onAbort = () => reject(new Error(`${what} aborted`));
51796
52156
  signal.addEventListener("abort", onAbort, { once: true });
51797
- work.then(resolve47, reject).finally(() => signal.removeEventListener("abort", onAbort));
52157
+ work.then(resolve48, reject).finally(() => signal.removeEventListener("abort", onAbort));
51798
52158
  });
51799
52159
  }
51800
- async function pinAddress(url, resolve47 = resolveAll, signal) {
52160
+ async function pinAddress(url, resolve48 = resolveAll, signal) {
51801
52161
  const host = url.hostname.replace(/^\[|\]$/g, "");
51802
52162
  if (ipv4Octets(host)) {
51803
52163
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
@@ -51807,7 +52167,7 @@ async function pinAddress(url, resolve47 = resolveAll, signal) {
51807
52167
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
51808
52168
  return { address: host, family: 6 };
51809
52169
  }
51810
- const addresses = await withAbort(() => resolve47(host), signal, `${host} lookup`);
52170
+ const addresses = await withAbort(() => resolve48(host), signal, `${host} lookup`);
51811
52171
  if (!addresses.length) throw new Error(`${host} resolved to no address`);
51812
52172
  const blocked = addresses.filter((a) => isBlockedAddress(a.address)).map((a) => a.address);
51813
52173
  if (blocked.length) throw new Error(`${host} resolves to a blocked address (${blocked.join(", ")})`);
@@ -51847,7 +52207,7 @@ function copyIncomingHeaders(headers2) {
51847
52207
  return out;
51848
52208
  }
51849
52209
  function requestOnce(url, pinned, init) {
51850
- return new Promise((resolve47, reject) => {
52210
+ return new Promise((resolve48, reject) => {
51851
52211
  const headers2 = { host: url.host, "accept-encoding": "identity" };
51852
52212
  new Headers(init.headers ?? {}).forEach((value, key2) => {
51853
52213
  if (key2.toLowerCase() !== "host") headers2[key2] = value;
@@ -51877,7 +52237,7 @@ function requestOnce(url, pinned, init) {
51877
52237
  reject(err);
51878
52238
  return;
51879
52239
  }
51880
- resolve47(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out }));
52240
+ resolve48(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out }));
51881
52241
  }
51882
52242
  );
51883
52243
  req.on("error", reject);
@@ -52681,7 +53041,7 @@ var init_brand_font = __esm({
52681
53041
 
52682
53042
  // src/site-analyze/write-artifacts.ts
52683
53043
  import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync25 } from "node:fs";
52684
- import { join as join53 } from "node:path";
53044
+ import { join as join54 } from "node:path";
52685
53045
  function attachVeloSources(book, sources, put) {
52686
53046
  const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
52687
53047
  for (const f of book.velo.files) {
@@ -52836,12 +53196,12 @@ async function downloadMedia(book, fetchImpl, put) {
52836
53196
  }
52837
53197
  async function writeBusinessBook(result, opts) {
52838
53198
  const out = opts.outDir;
52839
- mkdirSync28(join53(out, "evidence/pages"), { recursive: true });
52840
- mkdirSync28(join53(out, "media/catalog"), { recursive: true });
53199
+ mkdirSync28(join54(out, "evidence/pages"), { recursive: true });
53200
+ mkdirSync28(join54(out, "media/catalog"), { recursive: true });
52841
53201
  const files = [];
52842
53202
  const put = (rel, body) => {
52843
- const p = join53(out, rel);
52844
- mkdirSync28(join53(p, ".."), { recursive: true });
53203
+ const p = join54(out, rel);
53204
+ mkdirSync28(join54(p, ".."), { recursive: true });
52845
53205
  writeFileSync25(p, body);
52846
53206
  files.push(rel);
52847
53207
  };
@@ -52935,15 +53295,15 @@ var init_customer_build = __esm({
52935
53295
  });
52936
53296
 
52937
53297
  // src/site-analyze/apply.ts
52938
- import { existsSync as existsSync57, readFileSync as readFileSync67, writeFileSync as writeFileSync26, copyFileSync as copyFileSync3, mkdirSync as mkdirSync29, realpathSync as realpathSync6, statSync as statSync15 } from "node:fs";
52939
- import { dirname as dirname31, isAbsolute as isAbsolute4, join as join54, resolve as resolve44, sep as sep13 } from "node:path";
53298
+ import { existsSync as existsSync58, readFileSync as readFileSync68, writeFileSync as writeFileSync26, copyFileSync as copyFileSync3, mkdirSync as mkdirSync29, realpathSync as realpathSync7, statSync as statSync16 } from "node:fs";
53299
+ import { dirname as dirname31, isAbsolute as isAbsolute4, join as join55, resolve as resolve45, sep as sep14 } from "node:path";
52940
53300
  import { spawnSync as spawnSync4 } from "node:child_process";
52941
53301
  function unpairedRedirectNote(overlay) {
52942
53302
  if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
52943
53303
  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)`;
52944
53304
  }
52945
53305
  function posix2(p) {
52946
- return resolve44(p).replace(/\\/g, "/");
53306
+ return resolve45(p).replace(/\\/g, "/");
52947
53307
  }
52948
53308
  function committedShellProvisioning(path2) {
52949
53309
  return committedShellFor(posix2(path2));
@@ -52951,7 +53311,7 @@ function committedShellProvisioning(path2) {
52951
53311
  function findRepoRoot(cwd) {
52952
53312
  let dir = cwd;
52953
53313
  for (let i = 0; i < 8; i++) {
52954
- if (SHELL_NAMES2.some((name) => existsSync57(join54(dir, shellAppDir(name), "package.json")))) return dir;
53314
+ if (SHELL_NAMES2.some((name) => existsSync58(join55(dir, shellAppDir(name), "package.json")))) return dir;
52955
53315
  const next = dirname31(dir);
52956
53316
  if (next === dir) break;
52957
53317
  dir = next;
@@ -52977,7 +53337,7 @@ function assertNotCommitted(path2, forbidden) {
52977
53337
  `refusing to overwrite committed ${committedProvisioningPath(committed)} \u2014 use prepare:customer --contract`
52978
53338
  );
52979
53339
  }
52980
- if (forbidden && resolve44(path2) === resolve44(forbidden)) {
53340
+ if (forbidden && resolve45(path2) === resolve45(forbidden)) {
52981
53341
  const named = committedShellProvisioning(forbidden);
52982
53342
  throw new Error(
52983
53343
  `refusing to overwrite committed ${named ? committedProvisioningPath(named) : forbidden} \u2014 pass a content-package provisioning.json or use prepare:customer --contract`
@@ -53019,35 +53379,35 @@ function mergeCustomerOwned(committed, overlay) {
53019
53379
  }
53020
53380
  function buildMergedContract(options) {
53021
53381
  const { appDir: appDir2, packageDir, overlay } = options;
53022
- const committedPath = join54(appDir2, "provisioning.json");
53023
- if (!existsSync57(committedPath)) {
53382
+ const committedPath = join55(appDir2, "provisioning.json");
53383
+ if (!existsSync58(committedPath)) {
53024
53384
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
53025
53385
  }
53026
- const committed = JSON.parse(readFileSync67(committedPath, "utf8"));
53386
+ const committed = JSON.parse(readFileSync68(committedPath, "utf8"));
53027
53387
  const merged = mergeCustomerOwned(committed, overlay);
53028
53388
  const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
53029
53389
  const branding = merged.branding ?? {};
53030
53390
  const staged = [];
53031
53391
  const contained = (root, rel) => {
53032
53392
  if (isAbsolute4(rel)) return void 0;
53033
- const full = resolve44(root, rel);
53034
- return full.startsWith(resolve44(root) + sep13) ? full : void 0;
53393
+ const full = resolve45(root, rel);
53394
+ return full.startsWith(resolve45(root) + sep14) ? full : void 0;
53035
53395
  };
53036
53396
  const stage = (fromRel, toRel) => {
53037
53397
  const from = contained(packageDir, fromRel);
53038
- const to = contained(join54(appDir2, STAGED), toRel.slice(STAGED.length + 1));
53039
- if (!from || !to || !existsSync57(from)) return void 0;
53398
+ const to = contained(join55(appDir2, STAGED), toRel.slice(STAGED.length + 1));
53399
+ if (!from || !to || !existsSync58(from)) return void 0;
53040
53400
  let real;
53041
53401
  let realRoot;
53042
53402
  try {
53043
- real = realpathSync6(from);
53044
- realRoot = realpathSync6(packageDir);
53403
+ real = realpathSync7(from);
53404
+ realRoot = realpathSync7(packageDir);
53045
53405
  } catch {
53046
53406
  return void 0;
53047
53407
  }
53048
- if (!real.startsWith(realRoot + sep13)) return void 0;
53408
+ if (!real.startsWith(realRoot + sep14)) return void 0;
53049
53409
  try {
53050
- if (!statSync15(real).isFile()) return void 0;
53410
+ if (!statSync16(real).isFile()) return void 0;
53051
53411
  mkdirSync29(dirname31(to), { recursive: true });
53052
53412
  copyFileSync3(real, to);
53053
53413
  } catch {
@@ -53058,11 +53418,11 @@ function buildMergedContract(options) {
53058
53418
  };
53059
53419
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
53060
53420
  if (icon) branding.appIconPath = icon;
53061
- const facesPath = join54(packageDir, "media/fonts/faces.json");
53062
- if (existsSync57(facesPath)) {
53421
+ const facesPath = join55(packageDir, "media/fonts/faces.json");
53422
+ if (existsSync58(facesPath)) {
53063
53423
  let faces = [];
53064
53424
  try {
53065
- const parsed = JSON.parse(readFileSync67(facesPath, "utf8"));
53425
+ const parsed = JSON.parse(readFileSync68(facesPath, "utf8"));
53066
53426
  faces = Array.isArray(parsed) ? parsed : [];
53067
53427
  } catch {
53068
53428
  faces = [];
@@ -53083,20 +53443,20 @@ function buildMergedContract(options) {
53083
53443
  merged.branding = branding;
53084
53444
  const body = `${JSON.stringify(merged, null, 2)}
53085
53445
  `;
53086
- const path2 = join54(packageDir, "provisioning.contract.json");
53446
+ const path2 = join55(packageDir, "provisioning.contract.json");
53087
53447
  writeFileSync26(path2, body);
53088
- const localPath = join54(appDir2, LOCAL_CONTRACT_REL);
53448
+ const localPath = join55(appDir2, LOCAL_CONTRACT_REL);
53089
53449
  mkdirSync29(dirname31(localPath), { recursive: true });
53090
53450
  writeFileSync26(localPath, body);
53091
53451
  staged.push(localPath);
53092
53452
  return { path: path2, staged };
53093
53453
  }
53094
53454
  async function applyOverlays(input) {
53095
- const cwd = resolve44(input.cwd);
53455
+ const cwd = resolve45(input.cwd);
53096
53456
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
53097
53457
  assertKnownShell(shell);
53098
- const overlay = JSON.parse(readFileSync67(input.overlayPath, "utf8"));
53099
- const tokens = JSON.parse(readFileSync67(input.tokensPath, "utf8"));
53458
+ const overlay = JSON.parse(readFileSync68(input.overlayPath, "utf8"));
53459
+ const tokens = JSON.parse(readFileSync68(input.tokensPath, "utf8"));
53100
53460
  const wrote = [];
53101
53461
  const notes = [];
53102
53462
  const repoRoot2 = findRepoRoot(cwd);
@@ -53106,8 +53466,8 @@ async function applyOverlays(input) {
53106
53466
  `shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
53107
53467
  );
53108
53468
  }
53109
- const appDir2 = join54(repoRoot2, shellAppDir(shell));
53110
- const packageDir = dirname31(resolve44(input.overlayPath));
53469
+ const appDir2 = join55(repoRoot2, shellAppDir(shell));
53470
+ const packageDir = dirname31(resolve45(input.overlayPath));
53111
53471
  const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
53112
53472
  wrote.push(...staged);
53113
53473
  const r = spawnSync4("npm", ["run", "prepare:customer", "--", "--contract", contract], {
@@ -53128,10 +53488,10 @@ async function applyOverlays(input) {
53128
53488
  note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
53129
53489
  };
53130
53490
  }
53131
- const pkgProv = join54(cwd, "provisioning.json");
53491
+ const pkgProv = join55(cwd, "provisioning.json");
53132
53492
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
53133
- if (existsSync57(pkgProv)) {
53134
- const cur = JSON.parse(readFileSync67(pkgProv, "utf8"));
53493
+ if (existsSync58(pkgProv)) {
53494
+ const cur = JSON.parse(readFileSync68(pkgProv, "utf8"));
53135
53495
  const merged = deepMerge4(cur, overlay);
53136
53496
  writeFileSync26(pkgProv, JSON.stringify(merged, null, 2) + "\n");
53137
53497
  wrote.push(pkgProv);
@@ -53139,9 +53499,9 @@ async function applyOverlays(input) {
53139
53499
  writeFileSync26(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
53140
53500
  wrote.push(pkgProv);
53141
53501
  }
53142
- const pkgTokens = join54(cwd, "tokens.json");
53143
- if (existsSync57(pkgTokens) && (tokens.colors || tokens.typography)) {
53144
- const cur = JSON.parse(readFileSync67(pkgTokens, "utf8"));
53502
+ const pkgTokens = join55(cwd, "tokens.json");
53503
+ if (existsSync58(pkgTokens) && (tokens.colors || tokens.typography)) {
53504
+ const cur = JSON.parse(readFileSync68(pkgTokens, "utf8"));
53145
53505
  const merged = deepMerge4(cur, tokens);
53146
53506
  const mergedColors = merged.colors;
53147
53507
  if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
@@ -53160,9 +53520,9 @@ async function applyOverlays(input) {
53160
53520
  wrote.push(pkgTokens);
53161
53521
  }
53162
53522
  const homeAction = homeRefreshActionId(shell);
53163
- const homeSrc = join54(cwd, "dev/index.ts");
53164
- if (homeAction && existsSync57(homeSrc)) {
53165
- const prev = readFileSync67(homeSrc, "utf8");
53523
+ const homeSrc = join55(cwd, "dev/index.ts");
53524
+ if (homeAction && existsSync58(homeSrc)) {
53525
+ const prev = readFileSync68(homeSrc, "utf8");
53166
53526
  const patched = patchBrandParams(prev, overlay, homeAction);
53167
53527
  let next = patched.src;
53168
53528
  if (!patched.foreign && overlay.installedVerticals?.length) {
@@ -53185,13 +53545,13 @@ async function applyOverlays(input) {
53185
53545
  notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
53186
53546
  }
53187
53547
  }
53188
- if (!input.iconPath || !existsSync57(input.iconPath)) {
53189
- const book = input.iconPath ? dirname31(dirname31(resolve44(input.iconPath))) : void 0;
53548
+ if (!input.iconPath || !existsSync58(input.iconPath)) {
53549
+ const book = input.iconPath ? dirname31(dirname31(resolve45(input.iconPath))) : void 0;
53190
53550
  notes.push(
53191
53551
  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"
53192
53552
  );
53193
53553
  }
53194
- if (input.iconPath && existsSync57(input.iconPath)) {
53554
+ if (input.iconPath && existsSync58(input.iconPath)) {
53195
53555
  try {
53196
53556
  const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
53197
53557
  wrote.push(...installed.wrote);
@@ -54129,10 +54489,10 @@ function permuteDomain(domain, allowSpecialUseDomain) {
54129
54489
  }
54130
54490
  function createPromiseCallback(cb) {
54131
54491
  let callback;
54132
- let resolve47;
54492
+ let resolve48;
54133
54493
  let reject;
54134
54494
  const promise = new Promise((_resolve, _reject) => {
54135
- resolve47 = _resolve;
54495
+ resolve48 = _resolve;
54136
54496
  reject = _reject;
54137
54497
  });
54138
54498
  if (typeof cb === "function") {
@@ -54148,7 +54508,7 @@ function createPromiseCallback(cb) {
54148
54508
  callback = (err, result) => {
54149
54509
  try {
54150
54510
  if (err) reject(err);
54151
- else resolve47(result);
54511
+ else resolve48(result);
54152
54512
  } catch (e) {
54153
54513
  reject(e instanceof Error ? e : new Error());
54154
54514
  }
@@ -56720,7 +57080,7 @@ var init_crawl_look = __esm({
56720
57080
  });
56721
57081
 
56722
57082
  // src/site-analyze/site-function.ts
56723
- import { randomUUID as randomUUID2 } from "node:crypto";
57083
+ import { randomUUID as randomUUID4 } from "node:crypto";
56724
57084
  function createRevisionUrl(msid, esi) {
56725
57085
  const q = new URLSearchParams({ editorSessionId: esi, esi, metaSiteId: msid });
56726
57086
  return `https://editor.wix.com/html/v1/create_revision?${q}`;
@@ -57165,7 +57525,7 @@ function codeAppIdFromRevision(json5) {
57165
57525
  async function snapshotAndPublish(fetchImpl, token, msid, opts = {}) {
57166
57526
  const production = opts.production !== false;
57167
57527
  const initiator = opts.initiator ?? "himi";
57168
- const esi = randomUUID2();
57528
+ const esi = randomUUID4();
57169
57529
  const rev = await veloCall(fetchImpl, "POST", createRevisionUrl(msid, esi), {
57170
57530
  token,
57171
57531
  msid,
@@ -57346,8 +57706,8 @@ __export(cli_exports, {
57346
57706
  runSiteAnalyze: () => runSiteAnalyze,
57347
57707
  runSiteFunctionCli: () => runSiteFunctionCli
57348
57708
  });
57349
- import { readFileSync as readFileSync68 } from "node:fs";
57350
- import { resolve as resolve45 } from "node:path";
57709
+ import { readFileSync as readFileSync69 } from "node:fs";
57710
+ import { resolve as resolve46 } from "node:path";
57351
57711
  function assetFetchFor(_opts) {
57352
57712
  return pinnedFetch2;
57353
57713
  }
@@ -57356,7 +57716,7 @@ async function runSiteAnalyze(opts) {
57356
57716
  const assetFetch = assetFetchFor(opts);
57357
57717
  const siteFetch = guardedSiteFetch;
57358
57718
  const cwd = opts.cwd ?? process.cwd();
57359
- const outDir = resolve45(cwd, opts.outDir ?? ".himi/business-book");
57719
+ const outDir = resolve46(cwd, opts.outDir ?? ".himi/business-book");
57360
57720
  let ownerAuth;
57361
57721
  let msid;
57362
57722
  try {
@@ -57394,9 +57754,9 @@ async function runSiteAnalyze(opts) {
57394
57754
  if (opts.apply) {
57395
57755
  applied = await applyOverlays({
57396
57756
  cwd,
57397
- overlayPath: resolve45(outDir, "provisioning.overlay.json"),
57398
- tokensPath: resolve45(outDir, "tokens.overlay.json"),
57399
- iconPath: resolve45(outDir, "media/icon.png"),
57757
+ overlayPath: resolve46(outDir, "provisioning.overlay.json"),
57758
+ tokensPath: resolve46(outDir, "tokens.overlay.json"),
57759
+ iconPath: resolve46(outDir, "media/icon.png"),
57400
57760
  shell: opts.shell
57401
57761
  });
57402
57762
  const note = noteWithWarnings(applied.note, warnings);
@@ -57432,8 +57792,8 @@ async function runSiteFunctionCli(opts) {
57432
57792
  const token = opts.token ?? await siteToken(msid);
57433
57793
  let source;
57434
57794
  if (opts.sourcePath) {
57435
- const p = resolve45(opts.cwd ?? process.cwd(), opts.sourcePath);
57436
- source = readFileSync68(p, "utf8");
57795
+ const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
57796
+ source = readFileSync69(p, "utf8");
57437
57797
  }
57438
57798
  let body;
57439
57799
  if (opts.bodyRaw != null) {
@@ -57484,7 +57844,7 @@ async function accountToken2(spawnImpl = spawn5) {
57484
57844
  cached2 = fromEnv;
57485
57845
  return fromEnv;
57486
57846
  }
57487
- const token = await new Promise((resolve47, reject) => {
57847
+ const token = await new Promise((resolve48, reject) => {
57488
57848
  let child;
57489
57849
  try {
57490
57850
  child = spawnImpl("wix", ["token"]);
@@ -57513,7 +57873,7 @@ async function accountToken2(spawnImpl = spawn5) {
57513
57873
  const scan = (d) => {
57514
57874
  out += String(d);
57515
57875
  const m = out.match(TOKEN_RE2);
57516
- if (m) done(() => resolve47(m[0]));
57876
+ if (m) done(() => resolve48(m[0]));
57517
57877
  };
57518
57878
  child.stdout?.on("data", scan);
57519
57879
  child.stderr?.on("data", scan);
@@ -57690,7 +58050,7 @@ __export(site_create_exports, {
57690
58050
  runSiteList: () => runSiteList,
57691
58051
  writeProvisioningBinding: () => writeProvisioningBinding
57692
58052
  });
57693
- import { existsSync as existsSync58, readFileSync as readFileSync69, writeFileSync as writeFileSync27 } from "node:fs";
58053
+ import { existsSync as existsSync59, readFileSync as readFileSync70, writeFileSync as writeFileSync27 } from "node:fs";
57694
58054
  import { resolve as resolvePath2 } from "node:path";
57695
58055
  function oauthClientName(projectName) {
57696
58056
  return `${projectName} client`;
@@ -57839,7 +58199,7 @@ async function runSiteCreate(opts) {
57839
58199
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
57840
58200
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
57841
58201
  }
57842
- function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync58, readFileSync: readFileSync69, writeFileSync: writeFileSync27 }) {
58202
+ function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync59, readFileSync: readFileSync70, writeFileSync: writeFileSync27 }) {
57843
58203
  const msid = binding2.siteId;
57844
58204
  const path2 = resolvePath2(target);
57845
58205
  const committed = committedShellProvisioning(path2);
@@ -58512,11 +58872,11 @@ var init_context = __esm({
58512
58872
  });
58513
58873
 
58514
58874
  // src/cli.ts
58515
- import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync70, mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, existsSync as existsSync59, rmSync as rmSync11, readdirSync as readdirSync27, statSync as statSync16, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
58875
+ import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync71, mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, existsSync as existsSync60, rmSync as rmSync13, readdirSync as readdirSync27, statSync as statSync17, lstatSync as lstatSync8, accessSync, constants as constants2, renameSync as renameSync6, cpSync as cpSync3 } from "node:fs";
58516
58876
  import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
58517
- import { createHash as createHash26, randomUUID as randomUUID3 } from "node:crypto";
58877
+ import { createHash as createHash26, randomUUID as randomUUID5 } from "node:crypto";
58518
58878
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
58519
- import { join as join55, resolve as resolve46, relative as relative10, basename as basename13, dirname as dirname32 } from "node:path";
58879
+ import { join as join56, resolve as resolve47, relative as relative10, basename as basename13, dirname as dirname32 } from "node:path";
58520
58880
  import { fileURLToPath as fileURLToPath24 } from "node:url";
58521
58881
 
58522
58882
  // ../serve-cli/src/client.ts
@@ -60225,7 +60585,7 @@ async function browserLogin(opts) {
60225
60585
  const log = opts.log ?? (() => {
60226
60586
  });
60227
60587
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
60228
- return await new Promise((resolve47, reject) => {
60588
+ return await new Promise((resolve48, reject) => {
60229
60589
  let settled = false;
60230
60590
  let loginUrl = "";
60231
60591
  const server = createServer();
@@ -60289,7 +60649,7 @@ async function browserLogin(opts) {
60289
60649
  return;
60290
60650
  }
60291
60651
  res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store", connection: "close" }).end(CLOSE_PAGE);
60292
- finish2(() => resolve47({ token, loginUrl }));
60652
+ finish2(() => resolve48({ token, loginUrl }));
60293
60653
  });
60294
60654
  });
60295
60655
  server.on("error", (err) => finish2(() => reject(err)));
@@ -61792,8 +62152,8 @@ var str5 = (v) => typeof v === "string" ? v : void 0;
61792
62152
  var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
61793
62153
  function embeddedTemplateCatalog() {
61794
62154
  return availableTemplates().map((name) => {
61795
- const path2 = join55(templateSourceDir(name), TEMPLATE_META_FILE);
61796
- const meta = JSON.parse(readFileSync70(path2, "utf8"));
62155
+ const path2 = join56(templateSourceDir(name), TEMPLATE_META_FILE);
62156
+ const meta = JSON.parse(readFileSync71(path2, "utf8"));
61797
62157
  if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
61798
62158
  throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
61799
62159
  }
@@ -62075,11 +62435,12 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
62075
62435
  file is not the plane's per-release archive.
62076
62436
  himi share --file <package.himi> [--expires-at <ISO>] | revoke --app <app> <shareId>
62077
62437
  publish a content-addressed package link for a released app
62078
- himi run [<package.himi|dir|url>] [--browser] [--port <n>] [--chrome preview|app] [--screen <id>] [--surface <id>] [--no-open]
62438
+ himi run [<package.himi|dir|url>] [--browser] [--watch] [--port <n>] [--chrome preview|app] [--screen <id>] [--surface <id>] [--no-open]
62079
62439
  serve a package on localhost + open it in a browser. No serve
62080
62440
  plane, no dev-server. With no argument it packs the current
62081
62441
  content package first \u2014 edit, run, look at it.
62082
- Blocks until Ctrl-C.
62442
+ --watch rebuilds on every save and repaints the open tab
62443
+ (a failed build keeps the last good preview). Blocks until Ctrl-C.
62083
62444
  himi flags list|set|ramp|rm [<key>] [--app <a>]
62084
62445
  read/change operational flags (RFC 0013); writes report
62085
62446
  servedNow from the device door, never just ok
@@ -62422,7 +62783,7 @@ var COMMANDS = [
62422
62783
  { name: "import", summary: "turn a `himi pack --dev` package back into an EDITABLE content package \u2014 the file counterpart of `himi pull`, needing no serve plane, no account and no network. Refuses an invalid package before trusting its source (the content hash is recomputed over every entry on open, so the archive is provably the one that was packed), and refuses a RELEASE package by naming the absence \u2014 it carries built output and no source \u2014 rather than reporting a missing file. `--name` re-substitutes the app identity through the same machinery `himi init --template` and `himi pull --name` use, so the restored tree is a NEW app rather than a second copy of the same one, and a name that also appears inside a screen id (`feed` in `feed_home`) is left alone. A non-empty destination needs `--force` and a merge NAMES what it kept (`left: [...]`), the same contract `himi pull --force` has; a shape clash is refused whole before anything is written. There is no `--replace`: a file you were handed is not the plane's per-release archive.", required: "<package.himi> [--out <dir>] [--name <new>] [--force]" },
62423
62784
  { name: "pull", summary: "restore an app's SOURCE from the serve plane into an editable content package \u2014 the other half of `himi push`, which archives the content package on every publish. Owner or editor only: a viewer may download the RUNNING app (`/v1/owner/package`), not the codebase it was built from. A PAST release is restorable, not only the live one \u2014 the archive is content-addressed per release, so it has none of the live-single-slot problem that makes `himi pack` current-release-only. Two limits: pruning keeps the current release plus the newest ~20 ledger entries, and a release id identifies OTA content rather than source, so a source-only change republishes under the same id and replaces that id's archive. A release published before source archiving shipped, or pushed with `--no-source`, answers `app_source_not_found` and says to push again. `--name` re-substitutes the app identity through the same machinery `himi init --template` uses, so the restored tree is a NEW app rather than a second copy of the same one, and a name that also appears inside a screen id (`feed` in `feed_home`) is left alone. A NON-EMPTY destination is refused unless you say which you mean: `--force` merges and reports \u2014 it writes the archive over what is there, keeps files the release does not carry, and NAMES every one of them as `left: [...]` so a tree that matches no release is never silent (#2437); `--replace` restores exactly what was archived, removing those files first (`removed: [...]`) and implying `--force`. `--replace` refuses a directory holding no `himalaya.content.json`, so a mistyped `--out` cannot clear an unrelated tree, and the only paths it can remove are the ones a push would have archived \u2014 `.git/`, `node_modules/`, `dist/`, `.env*` and key material are out of its reach by construction.", required: "<app> [--release <id>] [--out <dir>] [--name <new>] [--force|--replace] [--target <t>]" },
62424
62785
  { name: "share", summary: "publish or revoke a content-addressed `.himi` share link. The package must be a validated archive for an already-published release; the resulting https URL is safe to QR, copy, or open in Himi Player.", required: "--file <package.himi> [--expires-at <ISO>] | revoke --app <app> <shareId>" },
62425
- { name: "run", summary: "serve a .himi package on localhost and open it in a browser \u2014 no serve plane, no dev-server, no setup. Given no argument it builds the current content package first, so `himi run` is the inner loop: edit, run, look at it. The SPA and /v1 are served from ONE origin because Tier-5 bundle fetches on web are same-origin-only. --chrome preview frames the app in a device chassis; --chrome app serves it as a plain web app. Blocks until Ctrl-C, like any dev server. --browser runs the whole plane INSIDE the tab (service worker + in-memory store) so no app code executes in this process or on any pod.", required: "[<package.himi|dir|url>] [--browser] [--content <dir>] [--port <n>] [--chrome preview|app] [--screen <id>] [--surface <id>] [--no-open] [--spa <url>]" },
62786
+ { name: "run", summary: "serve a .himi package on localhost and open it in a browser \u2014 no serve plane, no dev-server, no setup. Given no argument it builds the current content package first, so `himi run` is the inner loop: edit, run, look at it. The SPA and /v1 are served from ONE origin because Tier-5 bundle fetches on web are same-origin-only. --chrome preview frames the app in a device chassis; --chrome app serves it as a plain web app. Blocks until Ctrl-C, like any dev server. --browser runs the whole plane INSIDE the tab (service worker + in-memory store) so no app code executes in this process or on any pod. --watch keeps the preview LIVE: every save in the content package rebuilds it and repaints the open tab with only what changed (the dev-server's hot-reload events); a build that fails keeps the last good preview on screen and says why. It also frames itself on the build board (`himi studio`) and serves the board at /__himi/studio/ on the same origin.", required: "[<package.himi|dir|url>] [--browser] [--watch] [--content <dir>] [--port <n>] [--chrome preview|app] [--screen <id>] [--surface <id>] [--no-open] [--spa <url>]" },
62426
62787
  { name: "preview", summary: "print the shareable web URL + himi:// deep link + agent /v1/preview JSON URLs for an app+release; --surface frames the web preview as any catalog surface (?surface=)", required: "--app --release [--screen] [--surface]" },
62427
62788
  { name: "surfaces", summary: "the surface catalog vs this app's envelope (platforms.json): targeted surfaces, the opt-in key for the rest, per-surface preview links with --app --release, and which widget families the package produces with --measure-widgets (which runs its built bundles)", required: "[--content <dir>] [--app --release] [--measure-widgets]" },
62428
62789
  { name: "context", summary: "fetch the agent preview envelope (GET /v1/preview/a/<app>) \u2014 ok/issues/screens/links; exit 1 if ok:false", required: "--app --release [--screen] [--include telemetry]" },
@@ -62454,7 +62815,7 @@ var COMMANDS = [
62454
62815
  ];
62455
62816
  function cliVersion() {
62456
62817
  try {
62457
- return JSON.parse(readFileSync70(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
62818
+ return JSON.parse(readFileSync71(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
62458
62819
  } catch {
62459
62820
  return "unknown";
62460
62821
  }
@@ -62505,16 +62866,16 @@ function createScopedRegistryResolver(exec = execNpmConfig) {
62505
62866
  }
62506
62867
  var SCOPED_REGISTRY_TIMEOUT_MS = 5e3;
62507
62868
  function execNpmConfig(file, args, options) {
62508
- return new Promise((resolve47, reject) => {
62509
- execFile(file, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve47(String(stdout)));
62869
+ return new Promise((resolve48, reject) => {
62870
+ execFile(file, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve48(String(stdout)));
62510
62871
  });
62511
62872
  }
62512
62873
  var npmScopedWixRegistry = createScopedRegistryResolver();
62513
62874
  async function scopedRegistryBefore(lookup2, deadline) {
62514
62875
  let cancel = () => {
62515
62876
  };
62516
- const expired = new Promise((resolve47) => {
62517
- const timer = setTimeout(() => resolve47(void 0), Math.max(0, deadline - Date.now()));
62877
+ const expired = new Promise((resolve48) => {
62878
+ const timer = setTimeout(() => resolve48(void 0), Math.max(0, deadline - Date.now()));
62518
62879
  cancel = () => clearTimeout(timer);
62519
62880
  });
62520
62881
  try {
@@ -62572,16 +62933,16 @@ function ageInDays(publishedAt, now = Date.now()) {
62572
62933
  }
62573
62934
  function packageVersion(path2) {
62574
62935
  try {
62575
- const version2 = JSON.parse(readFileSync70(path2, "utf8")).version;
62936
+ const version2 = JSON.parse(readFileSync71(path2, "utf8")).version;
62576
62937
  return typeof version2 === "string" && version2 ? version2 : void 0;
62577
62938
  } catch {
62578
62939
  return void 0;
62579
62940
  }
62580
62941
  }
62581
62942
  function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
62582
- let dir = resolve46(fromDir);
62943
+ let dir = resolve47(fromDir);
62583
62944
  for (; ; ) {
62584
- const version2 = packageVersion(join55(dir, "node_modules", "@wix", "himalaya", "package.json"));
62945
+ const version2 = packageVersion(join56(dir, "node_modules", "@wix", "himalaya", "package.json"));
62585
62946
  if (version2) return { version: version2, source: "local" };
62586
62947
  const parent = dirname32(dir);
62587
62948
  if (parent === dir) break;
@@ -62591,7 +62952,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
62591
62952
  if (bundled) return { version: bundled, source: "bundled" };
62592
62953
  try {
62593
62954
  const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
62594
- const version2 = root ? packageVersion(join55(root, "@wix", "himalaya", "package.json")) : void 0;
62955
+ const version2 = root ? packageVersion(join56(root, "@wix", "himalaya", "package.json")) : void 0;
62595
62956
  return version2 ? { version: version2, source: "global" } : {};
62596
62957
  } catch {
62597
62958
  return {};
@@ -62638,11 +62999,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
62638
62999
  var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
62639
63000
  var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
62640
63001
  function updateCachePath(env = process.env) {
62641
- return env.HIMI_UPDATE_CACHE_FILE ?? join55(homedir7(), ".himalaya", "update-check.json");
63002
+ return env.HIMI_UPDATE_CACHE_FILE ?? join56(homedir7(), ".himalaya", "update-check.json");
62642
63003
  }
62643
63004
  function readUpdateCache(path2) {
62644
63005
  try {
62645
- const parsed = JSON.parse(readFileSync70(path2, "utf8"));
63006
+ const parsed = JSON.parse(readFileSync71(path2, "utf8"));
62646
63007
  return parsed && typeof parsed === "object" ? parsed : {};
62647
63008
  } catch {
62648
63009
  return {};
@@ -62681,7 +63042,7 @@ function globalPrefixWritable() {
62681
63042
  const root = globalNodeModulesRoot();
62682
63043
  if (!root) return false;
62683
63044
  try {
62684
- accessSync(root, constants.W_OK);
63045
+ accessSync(root, constants2.W_OK);
62685
63046
  return true;
62686
63047
  } catch {
62687
63048
  return false;
@@ -62710,12 +63071,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
62710
63071
  },
62711
63072
  installedVersion: () => {
62712
63073
  const root = globalNodeModulesRoot();
62713
- return root ? packageVersion(join55(root, "@wix", "himalaya-cli", "package.json")) : void 0;
63074
+ return root ? packageVersion(join56(root, "@wix", "himalaya-cli", "package.json")) : void 0;
62714
63075
  },
62715
63076
  reexec: (argv) => {
62716
63077
  const root = globalNodeModulesRoot();
62717
- const entry = root ? join55(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
62718
- if (!entry || !existsSync59(entry)) return void 0;
63078
+ const entry = root ? join56(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
63079
+ if (!entry || !existsSync60(entry)) return void 0;
62719
63080
  const result = spawnSync5(process.execPath, [entry, ...argv], {
62720
63081
  // inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
62721
63082
  stdio: "inherit",
@@ -62743,7 +63104,7 @@ function thisHost() {
62743
63104
  return hostname().replace(/\s+/g, "_");
62744
63105
  }
62745
63106
  function lockStamp(now) {
62746
- return `${now} ${process.pid} ${thisHost()} ${randomUUID3()}`;
63107
+ return `${now} ${process.pid} ${thisHost()} ${randomUUID5()}`;
62747
63108
  }
62748
63109
  function processAlive(pid) {
62749
63110
  try {
@@ -62762,7 +63123,7 @@ function staleUpdateLockFile(cachePath, now) {
62762
63123
  for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
62763
63124
  let content;
62764
63125
  try {
62765
- content = readFileSync70(path2, "utf8");
63126
+ content = readFileSync71(path2, "utf8");
62766
63127
  } catch {
62767
63128
  continue;
62768
63129
  }
@@ -62770,7 +63131,7 @@ function staleUpdateLockFile(cachePath, now) {
62770
63131
  let since = stamped;
62771
63132
  if (!Number.isFinite(since)) {
62772
63133
  try {
62773
- since = statSync16(path2).mtimeMs;
63134
+ since = statSync17(path2).mtimeMs;
62774
63135
  } catch {
62775
63136
  continue;
62776
63137
  }
@@ -62785,7 +63146,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
62785
63146
  const mine = lockStamp(now);
62786
63147
  const readLock = (path2) => {
62787
63148
  try {
62788
- return readFileSync70(path2, "utf8");
63149
+ return readFileSync71(path2, "utf8");
62789
63150
  } catch {
62790
63151
  return void 0;
62791
63152
  }
@@ -62800,7 +63161,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
62800
63161
  };
62801
63162
  const removeIfMine = (path2) => {
62802
63163
  try {
62803
- if (readLock(path2) === mine) rmSync11(path2, { force: true });
63164
+ if (readLock(path2) === mine) rmSync13(path2, { force: true });
62804
63165
  } catch {
62805
63166
  }
62806
63167
  };
@@ -62823,7 +63184,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
62823
63184
  hooks.underBreakLock?.();
62824
63185
  if (current === void 0) return tryCreate(lockPath) ? release : void 0;
62825
63186
  if (!isAbandoned(current)) return void 0;
62826
- rmSync11(lockPath, { force: true });
63187
+ rmSync13(lockPath, { force: true });
62827
63188
  return tryCreate(lockPath) ? release : void 0;
62828
63189
  } finally {
62829
63190
  removeIfMine(breakPath);
@@ -63323,10 +63684,10 @@ function executableOnPath(name, env = process.env) {
63323
63684
  const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
63324
63685
  for (const dir of entries) {
63325
63686
  for (const suffix of suffixes) {
63326
- const candidate = join55(dir, `${name}${suffix}`);
63687
+ const candidate = join56(dir, `${name}${suffix}`);
63327
63688
  try {
63328
- if (!statSync16(candidate).isFile()) continue;
63329
- if (process.platform !== "win32") accessSync(candidate, constants.X_OK);
63689
+ if (!statSync17(candidate).isFile()) continue;
63690
+ if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
63330
63691
  return true;
63331
63692
  } catch {
63332
63693
  }
@@ -63432,7 +63793,7 @@ async function nativeConfigAdvisories(app, configSource) {
63432
63793
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
63433
63794
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
63434
63795
  const iosYmlPath = iosProjectYml2(app);
63435
- const iosYml = existsSync59(iosYmlPath) ? readFileSync70(iosYmlPath, "utf8") : "";
63796
+ const iosYml = existsSync60(iosYmlPath) ? readFileSync71(iosYmlPath, "utf8") : "";
63436
63797
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
63437
63798
  if (!optedIn) {
63438
63799
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -63446,7 +63807,7 @@ async function nativeConfigAdvisories(app, configSource) {
63446
63807
  }
63447
63808
  function readConfigSource(dir) {
63448
63809
  try {
63449
- return readFileSync70(join55(dir, "config.ts"), "utf8");
63810
+ return readFileSync71(join56(dir, "config.ts"), "utf8");
63450
63811
  } catch {
63451
63812
  return null;
63452
63813
  }
@@ -63457,8 +63818,8 @@ function writePngFile(path2, base64) {
63457
63818
  return path2;
63458
63819
  }
63459
63820
  async function initFromRemoteTemplate(name, parentDir, template, c) {
63460
- const dir = resolve46(parentDir, name);
63461
- if (existsSync59(join55(dir, "himalaya.content.json"))) {
63821
+ const dir = resolve47(parentDir, name);
63822
+ if (existsSync60(join56(dir, "himalaya.content.json"))) {
63462
63823
  throw new Error(`content package already exists at ${dir}`);
63463
63824
  }
63464
63825
  const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -63470,7 +63831,7 @@ async function initFromRemoteTemplate(name, parentDir, template, c) {
63470
63831
  return finishScaffold(materializeSource(archive.files, name, dir), template);
63471
63832
  }
63472
63833
  function contentDir(flags) {
63473
- return resolve46(str5(flags.content) ?? process.cwd());
63834
+ return resolve47(str5(flags.content) ?? process.cwd());
63474
63835
  }
63475
63836
  function renameRestoredSource(restored, declaredApp, renamed) {
63476
63837
  const text5 = {};
@@ -63488,7 +63849,7 @@ function renameRestoredSource(restored, declaredApp, renamed) {
63488
63849
  function symlinkDestinationIssue(dest) {
63489
63850
  let kind;
63490
63851
  try {
63491
- kind = lstatSync6(dest);
63852
+ kind = lstatSync8(dest);
63492
63853
  } catch {
63493
63854
  return null;
63494
63855
  }
@@ -63501,8 +63862,8 @@ function symlinkDestinationIssue(dest) {
63501
63862
  function restoreDestinationIssue(dest, force) {
63502
63863
  const link = symlinkDestinationIssue(dest);
63503
63864
  if (link) return link;
63504
- if (!existsSync59(dest)) return null;
63505
- if (!statSync16(dest).isDirectory()) {
63865
+ if (!existsSync60(dest)) return null;
63866
+ if (!statSync17(dest).isDirectory()) {
63506
63867
  return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
63507
63868
  }
63508
63869
  if (readdirSync27(dest).length > 0 && !force) {
@@ -63514,9 +63875,9 @@ function restoreDestinationIssue(dest, force) {
63514
63875
  return null;
63515
63876
  }
63516
63877
  function isHimalayaMonorepoCheckout(start) {
63517
- let dir = resolve46(start);
63878
+ let dir = resolve47(start);
63518
63879
  for (; ; ) {
63519
- if (existsSync59(join55(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync59(join55(dir, "core", "serve", "src", "server.ts"))) return true;
63880
+ if (existsSync60(join56(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync60(join56(dir, "core", "serve", "src", "server.ts"))) return true;
63520
63881
  const parent = dirname32(dir);
63521
63882
  if (parent === dir) return false;
63522
63883
  dir = parent;
@@ -63558,8 +63919,8 @@ function materializeForPreview(appDir2, slug, displayName) {
63558
63919
  const forBuild = Object.fromEntries(
63559
63920
  Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
63560
63921
  );
63561
- const repoRoot2 = resolve46(fileURLToPath24(new URL("../../..", import.meta.url)));
63562
- const root = join55(repoRoot2, "node_modules", ".cache", "himi-template-preview");
63922
+ const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
63923
+ const root = join56(repoRoot2, "node_modules", ".cache", "himi-template-preview");
63563
63924
  const stillRunning = (pid) => {
63564
63925
  try {
63565
63926
  process.kill(pid, 0);
@@ -63573,21 +63934,21 @@ function materializeForPreview(appDir2, slug, displayName) {
63573
63934
  if (!entry.isDirectory()) continue;
63574
63935
  const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
63575
63936
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
63576
- rmSync11(join55(root, entry.name), { recursive: true, force: true });
63937
+ rmSync13(join56(root, entry.name), { recursive: true, force: true });
63577
63938
  }
63578
63939
  }
63579
63940
  } catch {
63580
63941
  }
63581
- const dest = join55(root, `${slug}-${process.pid}`);
63582
- rmSync11(dest, { recursive: true, force: true });
63942
+ const dest = join56(root, `${slug}-${process.pid}`);
63943
+ rmSync13(dest, { recursive: true, force: true });
63583
63944
  mkdirSync30(dest, { recursive: true });
63584
63945
  materializeSource(forBuild, displayName, dest, slug);
63585
63946
  return dest;
63586
63947
  }
63587
63948
  async function appId(dir) {
63588
63949
  try {
63589
- const { readFileSync: readFileSync71 } = await import("node:fs");
63590
- const m = JSON.parse(readFileSync71(join55(dir, "himalaya.content.json"), "utf8"));
63950
+ const { readFileSync: readFileSync72 } = await import("node:fs");
63951
+ const m = JSON.parse(readFileSync72(join56(dir, "himalaya.content.json"), "utf8"));
63591
63952
  if (m.name) return m.name;
63592
63953
  } catch {
63593
63954
  }
@@ -63595,8 +63956,8 @@ async function appId(dir) {
63595
63956
  }
63596
63957
  async function contentVisibility(dir) {
63597
63958
  try {
63598
- const { readFileSync: readFileSync71 } = await import("node:fs");
63599
- const m = JSON.parse(readFileSync71(join55(dir, "himalaya.content.json"), "utf8"));
63959
+ const { readFileSync: readFileSync72 } = await import("node:fs");
63960
+ const m = JSON.parse(readFileSync72(join56(dir, "himalaya.content.json"), "utf8"));
63600
63961
  if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
63601
63962
  } catch {
63602
63963
  }
@@ -63798,7 +64159,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
63798
64159
  return 0;
63799
64160
  }
63800
64161
  case "agent-init": {
63801
- const dir = resolve46(str5(flags.dir) ?? process.cwd());
64162
+ const dir = resolve47(str5(flags.dir) ?? process.cwd());
63802
64163
  const res = writeAgentContext(dir);
63803
64164
  print({ ok: true, dir: res.dir, files: res.files, portalUrl: idx.portalUrl });
63804
64165
  return 0;
@@ -63820,7 +64181,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
63820
64181
  try {
63821
64182
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
63822
64183
  const bres = await buildContentForValidation2(dir, { resolution });
63823
- out = mkdtempSync4(join55(tmpdir5(), "himi-ux-record-"));
64184
+ out = mkdtempSync4(join56(tmpdir5(), "himi-ux-record-"));
63824
64185
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
63825
64186
  const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
63826
64187
  const releaseId = outcome.manifest.releaseId;
@@ -63833,7 +64194,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
63833
64194
  return null;
63834
64195
  } finally {
63835
64196
  if (out !== void 0) try {
63836
- rmSync11(out, { recursive: true, force: true });
64197
+ rmSync13(out, { recursive: true, force: true });
63837
64198
  } catch {
63838
64199
  }
63839
64200
  }
@@ -63998,7 +64359,7 @@ async function producedWidgetFamilies(dir) {
63998
64359
  let js;
63999
64360
  for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
64000
64361
  try {
64001
- js = readFileSync70(join55(outDir, candidate), "utf8");
64362
+ js = readFileSync71(join56(outDir, candidate), "utf8");
64002
64363
  break;
64003
64364
  } catch {
64004
64365
  }
@@ -64029,7 +64390,7 @@ async function producedWidgetFamilies(dir) {
64029
64390
  }
64030
64391
  return { families, source: "dist/bundles" };
64031
64392
  }
64032
- var boardOpen = (dir) => existsSync59(join55(dir, ".himi", "studio", "index.html"));
64393
+ var boardOpen = (dir) => existsSync60(join56(dir, ".himi", "studio", "index.html"));
64033
64394
  var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
64034
64395
  async function leaveForBoard(dir, record2, value) {
64035
64396
  if (!boardOpen(dir)) return;
@@ -64296,7 +64657,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64296
64657
  return 2;
64297
64658
  }
64298
64659
  const template = str5(flags.template);
64299
- const parentDir = resolve46(str5(flags.dir) ?? process.cwd());
64660
+ const parentDir = resolve47(str5(flags.dir) ?? process.cwd());
64300
64661
  if (template && flags.remote === true) {
64301
64662
  try {
64302
64663
  const res2 = await initFromRemoteTemplate(name, parentDir, template, client2());
@@ -64413,11 +64774,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64413
64774
  return outcome.code;
64414
64775
  }
64415
64776
  if (sub === "publish") {
64416
- const appDir2 = resolve46(str5(flags.dir) ?? process.cwd());
64417
- const sourceDir = resolve46(str5(flags["source-dir"]) ?? appDir2);
64777
+ const appDir2 = resolve47(str5(flags.dir) ?? process.cwd());
64778
+ const sourceDir = resolve47(str5(flags["source-dir"]) ?? appDir2);
64418
64779
  let meta;
64419
64780
  try {
64420
- meta = JSON.parse(readFileSync70(join55(sourceDir, TEMPLATE_META_FILE), "utf8"));
64781
+ meta = JSON.parse(readFileSync71(join56(sourceDir, TEMPLATE_META_FILE), "utf8"));
64421
64782
  } catch {
64422
64783
  io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
64423
64784
  return 2;
@@ -64427,7 +64788,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64427
64788
  return 2;
64428
64789
  }
64429
64790
  try {
64430
- const appearance = extractTemplateAppearance(JSON.parse(readFileSync70(join55(sourceDir, "tokens.json"), "utf8")));
64791
+ const appearance = extractTemplateAppearance(JSON.parse(readFileSync71(join56(sourceDir, "tokens.json"), "utf8")));
64431
64792
  meta = { ...appearance, ...meta };
64432
64793
  } catch {
64433
64794
  }
@@ -64439,13 +64800,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64439
64800
  const force = flags.force === true;
64440
64801
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
64441
64802
  const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
64442
- const out = mkdtempSync4(join55(tmpdir5(), "himi-template-"));
64803
+ const out = mkdtempSync4(join56(tmpdir5(), "himi-template-"));
64443
64804
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64444
64805
  const outcome = await buildReleaseFromContent2(buildDir, out, {
64445
64806
  ...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
64446
64807
  collect: { lint: true, strict }
64447
64808
  });
64448
- const scaffoldSourceFindings = resolve46(sourceDir) === resolve46(appDir2) ? [] : [
64809
+ const scaffoldSourceFindings = resolve47(sourceDir) === resolve47(appDir2) ? [] : [
64449
64810
  ...tokenColorIssues(sourceDir),
64450
64811
  ...surfaceIssues(sourceDir, void 0, strict),
64451
64812
  ...await fontIssues(sourceDir, strict),
@@ -64488,11 +64849,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64488
64849
  }));
64489
64850
  return 1;
64490
64851
  }
64491
- const iconPath = str5(flags.icon) ? resolve46(str5(flags.icon)) : templateIconPath(name);
64852
+ const iconPath = str5(flags.icon) ? resolve47(str5(flags.icon)) : templateIconPath(name);
64492
64853
  let iconHash;
64493
64854
  if (iconPath) {
64494
64855
  try {
64495
- const bytes2 = readFileSync70(iconPath);
64856
+ const bytes2 = readFileSync71(iconPath);
64496
64857
  payload.icon = bytes2.toString("base64");
64497
64858
  iconHash = createHash26("sha256").update(bytes2).digest("hex");
64498
64859
  } catch {
@@ -64725,7 +65086,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64725
65086
  const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
64726
65087
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
64727
65088
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
64728
- const out = mkdtempSync4(join55(tmpdir5(), "himi-validate-"));
65089
+ const out = mkdtempSync4(join56(tmpdir5(), "himi-validate-"));
64729
65090
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64730
65091
  const outcome = await buildReleaseFromContent2(dir, out, {
64731
65092
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -64768,7 +65129,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64768
65129
  const path2 = dpxSessionTokenPath();
64769
65130
  let raw;
64770
65131
  try {
64771
- raw = readFileSync70(path2, "utf8");
65132
+ raw = readFileSync71(path2, "utf8");
64772
65133
  } catch {
64773
65134
  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`);
64774
65135
  }
@@ -64888,7 +65249,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64888
65249
  case "studio": {
64889
65250
  const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
64890
65251
  const dir = contentDir(flags);
64891
- if (!existsSync59(join55(dir, "himalaya.content.json"))) {
65252
+ if (!existsSync60(join56(dir, "himalaya.content.json"))) {
64892
65253
  io.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
64893
65254
  return 2;
64894
65255
  }
@@ -64913,7 +65274,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64913
65274
  const { appendProgress: appendProgress2, readProgress: readProgress2, summarizeProgress: summarizeProgress2, parseStep: parseStep2, notifyDesktop: notifyDesktop2, appLabel: appLabel2, journalPath: journalPath2, ProgressError: ProgressError2, JOURNEY_STEPS: JOURNEY_STEPS2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
64914
65275
  const dir = contentDir(flags);
64915
65276
  const journal = journalPath2(dir);
64916
- const hint = existsSync59(join55(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
65277
+ const hint = existsSync60(join56(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
64917
65278
  const message = pos.slice(1).join(" ").trim();
64918
65279
  if (!message) {
64919
65280
  if (flags.step !== void 0 || flags.image !== void 0 || flags.notify === true) {
@@ -65005,7 +65366,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65005
65366
  case "test": {
65006
65367
  const dir = contentDir(flags);
65007
65368
  const structuredOutput = flags.json === true || io.isTTY !== true;
65008
- if (existsSync59(join55(dir, "functions"))) {
65369
+ if (existsSync60(join56(dir, "functions"))) {
65009
65370
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
65010
65371
  const loaded = await loadFunctionsApp2(dir);
65011
65372
  const results = [];
@@ -65092,7 +65453,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65092
65453
  }
65093
65454
  }
65094
65455
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
65095
- const out = mkdtempSync4(join55(tmpdir5(), "himi-test-"));
65456
+ const out = mkdtempSync4(join56(tmpdir5(), "himi-test-"));
65096
65457
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65097
65458
  const outcome = await buildReleaseFromContent2(dir, out, {
65098
65459
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65137,7 +65498,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65137
65498
  io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
65138
65499
  return 2;
65139
65500
  }
65140
- const sources = collectWorkerSources2(join55(dir, "tier5-src"), screen.bundleName);
65501
+ const sources = collectWorkerSources2(join56(dir, "tier5-src"), screen.bundleName);
65141
65502
  if (!sources) {
65142
65503
  io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
65143
65504
  return 2;
@@ -65298,7 +65659,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65298
65659
  const sp = await runShotsPass2({
65299
65660
  descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
65300
65661
  tokens: outcome.tokens,
65301
- outDir: join55(dir, ".himi", "shots"),
65662
+ outDir: join56(dir, ".himi", "shots"),
65302
65663
  width: 390,
65303
65664
  layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
65304
65665
  ...budgetMs ? { budgetMs } : {},
@@ -65308,7 +65669,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65308
65669
  renderDescriptorWeb: renderDescriptorWeb2,
65309
65670
  renderPngBatch: renderPngBatch2,
65310
65671
  writePng: (path2, base64) => writePngFile(path2, base64),
65311
- clearDir: (d) => rmSync11(d, { recursive: true, force: true })
65672
+ clearDir: (d) => rmSync13(d, { recursive: true, force: true })
65312
65673
  }
65313
65674
  });
65314
65675
  writtenShots = sp.written;
@@ -65336,7 +65697,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65336
65697
  releaseId: result.releaseId,
65337
65698
  releasePayload: release,
65338
65699
  descriptors: attestedDescriptors,
65339
- screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join55(dir, ".himi", "shots", name)])),
65700
+ screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join56(dir, ".himi", "shots", name)])),
65340
65701
  coverage: {
65341
65702
  screens: crawledScreens.size,
65342
65703
  actionsDispatched: result.actions.exercised,
@@ -65426,7 +65787,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65426
65787
  return 2;
65427
65788
  }
65428
65789
  try {
65429
- const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync70(stateArg.replace(/^@/, ""), "utf8");
65790
+ const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync71(stateArg.replace(/^@/, ""), "utf8");
65430
65791
  injectedState = JSON.parse(raw);
65431
65792
  } catch (e) {
65432
65793
  io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
@@ -65441,7 +65802,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65441
65802
  return 2;
65442
65803
  }
65443
65804
  try {
65444
- const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync70(inputArg.replace(/^@/, ""), "utf8");
65805
+ const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync71(inputArg.replace(/^@/, ""), "utf8");
65445
65806
  const parsed = JSON.parse(raw);
65446
65807
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
65447
65808
  injectedInput = parsed;
@@ -65490,7 +65851,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65490
65851
  }
65491
65852
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65492
65853
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
65493
- const out = mkdtempSync4(join55(tmpdir5(), "himi-render-"));
65854
+ const out = mkdtempSync4(join56(tmpdir5(), "himi-render-"));
65494
65855
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65495
65856
  const outcome = await buildReleaseFromContent2(dir, out, {
65496
65857
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65504,11 +65865,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
65504
65865
  const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
65505
65866
  let pngFile;
65506
65867
  let attestationPngFile;
65507
- const shotPath = join55(dir, ".himi", "shots", `${screenId}.png`);
65868
+ const shotPath = join56(dir, ".himi", "shots", `${screenId}.png`);
65508
65869
  const pngTarget = typeof flags.png === "string" ? str5(flags.png) : flags.png === true ? shotPath : void 0;
65509
65870
  if (pngTarget && r.pngBase64) {
65510
65871
  pngFile = writePngFile(pngTarget, r.pngBase64);
65511
- attestationPngFile = resolve46(pngTarget) === resolve46(shotPath) ? pngFile : writePngFile(shotPath, r.pngBase64);
65872
+ attestationPngFile = resolve47(pngTarget) === resolve47(shotPath) ? pngFile : writePngFile(shotPath, r.pngBase64);
65512
65873
  }
65513
65874
  if (renderWidth !== void 0 && r.renderable) {
65514
65875
  recordRenderWidth(dir, {
@@ -65832,7 +66193,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65832
66193
  return 2;
65833
66194
  }
65834
66195
  const renamed = str5(flags.name);
65835
- const dest = resolve46(str5(flags.out) ?? process.cwd(), renamed ?? wanted);
66196
+ const dest = resolve47(str5(flags.out) ?? process.cwd(), renamed ?? wanted);
65836
66197
  const replace = flags.replace === true;
65837
66198
  const force = replace || flags.force === true;
65838
66199
  const linked = symlinkDestinationIssue(dest);
@@ -65840,8 +66201,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65840
66201
  io.error(JSON.stringify(linked));
65841
66202
  return 1;
65842
66203
  }
65843
- if (existsSync59(dest)) {
65844
- if (!statSync16(dest).isDirectory()) {
66204
+ if (existsSync60(dest)) {
66205
+ if (!statSync17(dest).isDirectory()) {
65845
66206
  io.error(JSON.stringify({
65846
66207
  error: `${dest} exists and is not a directory`,
65847
66208
  hint: "pass --out/--name to land somewhere else, or remove the file"
@@ -65853,7 +66214,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65853
66214
  io.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
65854
66215
  return 1;
65855
66216
  }
65856
- if (replace && occupied && !existsSync59(join55(dest, "himalaya.content.json"))) {
66217
+ if (replace && occupied && !existsSync60(join56(dest, "himalaya.content.json"))) {
65857
66218
  io.error(JSON.stringify({
65858
66219
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
65859
66220
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -65992,7 +66353,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65992
66353
  const force = flags.force === true;
65993
66354
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65994
66355
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
65995
- const out = mkdtempSync4(join55(tmpdir5(), "himi-push-"));
66356
+ const out = mkdtempSync4(join56(tmpdir5(), "himi-push-"));
65996
66357
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65997
66358
  const outcome = await buildReleaseFromContent2(dir, out, {
65998
66359
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -66464,7 +66825,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66464
66825
  return 2;
66465
66826
  }
66466
66827
  try {
66467
- const res = writePack(resolve46(releaseDir), only, resolve46(str5(flags.out) ?? process.cwd()));
66828
+ const res = writePack(resolve47(releaseDir), only, resolve47(str5(flags.out) ?? process.cwd()));
66468
66829
  print({
66469
66830
  ok: true,
66470
66831
  app: res.app,
@@ -66513,7 +66874,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66513
66874
  }
66514
66875
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
66515
66876
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
66516
- const built = mkdtempSync4(join55(tmpdir5(), "himi-pack-"));
66877
+ const built = mkdtempSync4(join56(tmpdir5(), "himi-pack-"));
66517
66878
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
66518
66879
  const outcome = await buildReleaseFromContent2(dir, built, {
66519
66880
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -66530,12 +66891,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66530
66891
  ...await navIssues2(dir, strict)
66531
66892
  ]);
66532
66893
  if (hasErrors && !force) {
66533
- rmSync11(built, { recursive: true, force: true });
66894
+ rmSync13(built, { recursive: true, force: true });
66534
66895
  print({ ...report2, packed: false, hint: "lint found errors \u2014 fix them, or re-run `himi pack --force` to pack anyway" });
66535
66896
  return 1;
66536
66897
  }
66537
66898
  try {
66538
- const res = writePack(built, app, resolve46(str5(flags.out) ?? dir), sourceArchive);
66899
+ const res = writePack(built, app, resolve47(str5(flags.out) ?? dir), sourceArchive);
66539
66900
  print({
66540
66901
  ok: true,
66541
66902
  app: res.app,
@@ -66566,7 +66927,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66566
66927
  io.error(JSON.stringify({ error: e.message }));
66567
66928
  return 1;
66568
66929
  } finally {
66569
- rmSync11(built, { recursive: true, force: true });
66930
+ rmSync13(built, { recursive: true, force: true });
66570
66931
  }
66571
66932
  }
66572
66933
  // ---- himi import — turn a dev .himi back into an editable content package ----
@@ -66580,7 +66941,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66580
66941
  const { HIMI_PACKAGE_SOURCE_PATH: HIMI_PACKAGE_SOURCE_PATH2, isSafeAppId: isSafeAppId2, packageContents: packageContents2 } = await Promise.resolve().then(() => (init_himi_package(), himi_package_exports));
66581
66942
  let opened;
66582
66943
  try {
66583
- opened = openPackageFile2(resolve46(file));
66944
+ opened = openPackageFile2(resolve47(file));
66584
66945
  } catch (e) {
66585
66946
  io.error(JSON.stringify({ error: e.message }));
66586
66947
  return 1;
@@ -66593,7 +66954,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66593
66954
  io.error(JSON.stringify({
66594
66955
  ok: false,
66595
66956
  error: "app_source_not_in_package",
66596
- detail: `${resolve46(file)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
66957
+ detail: `${resolve47(file)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
66597
66958
  hint: "re-pack it from the content package with `himi pack --dev`, or restore from the serve plane with `himi pull <app>`"
66598
66959
  }));
66599
66960
  return 1;
@@ -66616,7 +66977,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66616
66977
  return 1;
66617
66978
  }
66618
66979
  }
66619
- const dest = resolve46(str5(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
66980
+ const dest = resolve47(str5(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
66620
66981
  const issue2 = restoreDestinationIssue(dest, flags.force === true);
66621
66982
  if (issue2) {
66622
66983
  io.error(JSON.stringify(issue2));
@@ -66701,7 +67062,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66701
67062
  }
66702
67063
  try {
66703
67064
  const { openPackageFile: openPackageFile2 } = await Promise.resolve().then(() => (init_pack(), pack_exports));
66704
- const opened = openPackageFile2(resolve46(file));
67065
+ const opened = openPackageFile2(resolve47(file));
66705
67066
  if (!opened.validation.ok || !opened.header) {
66706
67067
  io.error(JSON.stringify({ error: "refusing to share an invalid package", issues: opened.validation.errors }));
66707
67068
  return 1;
@@ -66711,12 +67072,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66711
67072
  io.error(JSON.stringify({
66712
67073
  ok: false,
66713
67074
  error: "refusing to share a package that carries the app's source",
66714
- detail: `${resolve46(file)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
67075
+ detail: `${resolve47(file)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
66715
67076
  hint: "share a release package instead (`himi pack` with no --dev), or hand the dev package over directly"
66716
67077
  }));
66717
67078
  return 1;
66718
67079
  }
66719
- const archive = readFileSync70(resolve46(file));
67080
+ const archive = readFileSync71(resolve47(file));
66720
67081
  const result = await client2().createPackageShare({
66721
67082
  app: opened.header.app,
66722
67083
  releaseId: opened.header.releaseId,
@@ -66747,16 +67108,33 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66747
67108
  const { runPackage: runPackage2 } = await Promise.resolve().then(() => (init_run(), run_exports));
66748
67109
  let source = pos[1];
66749
67110
  let temp = null;
67111
+ const watch2 = flags.watch === true;
67112
+ if (watch2) {
67113
+ const { watchFlagConflict: watchFlagConflict2, watchedContentDir: watchedContentDir2 } = await Promise.resolve().then(() => (init_run_watch(), run_watch_exports));
67114
+ const watchedDir = watchedContentDir2(source);
67115
+ if (watchedDir) {
67116
+ flags.content = watchedDir;
67117
+ source = void 0;
67118
+ }
67119
+ const conflict = watchFlagConflict2({ source, browser: flags.browser === true, spa: str5(flags.spa) });
67120
+ if (conflict) {
67121
+ io.error(JSON.stringify({ ok: false, ...conflict }));
67122
+ return 2;
67123
+ }
67124
+ }
67125
+ let served = null;
67126
+ let servedMissing = [];
66750
67127
  try {
66751
67128
  if (!source) {
66752
- const dir = contentDir(flags);
66753
- const app = await appId(dir);
67129
+ const dir2 = contentDir(flags);
67130
+ const app = await appId(dir2);
66754
67131
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
66755
- const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
66756
- temp = mkdtempSync4(join55(tmpdir5(), "himi-run-build-"));
67132
+ const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
67133
+ temp = mkdtempSync4(join56(tmpdir5(), "himi-run-build-"));
66757
67134
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
66758
- await buildReleaseFromContent2(dir, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {} });
66759
- source = join55(temp, app);
67135
+ const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
67136
+ servedMissing = initial.missingBundles;
67137
+ source = join56(temp, app);
66760
67138
  }
66761
67139
  const chromeArg = str5(flags.chrome) ?? "preview";
66762
67140
  if (chromeArg !== "preview" && chromeArg !== "app") {
@@ -66781,45 +67159,142 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66781
67159
  open: flags["no-open"] !== true
66782
67160
  });
66783
67161
  print({ ok: true, app: run2.app, url: run2.url, port: run2.port, plane: "browser" });
66784
- await new Promise((resolve47) => {
67162
+ await new Promise((resolve48) => {
66785
67163
  const stop = () => {
66786
- void run2.close().finally(() => resolve47());
67164
+ void run2.close().finally(() => resolve48());
66787
67165
  };
66788
67166
  process.once("SIGINT", stop);
66789
67167
  process.once("SIGTERM", stop);
66790
67168
  });
66791
67169
  return 0;
66792
67170
  }
67171
+ const dir = contentDir(flags);
67172
+ const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
67173
+ const bus = watchKit ? new watchKit.ReloadBus() : void 0;
67174
+ if (watch2) served = mkdtempSync4(join56(tmpdir5(), "himi-run-served-"));
66793
67175
  const running = await runPackage2(source, {
66794
67176
  port,
66795
67177
  chrome: chromeArg,
66796
67178
  screen: str5(flags.screen),
66797
67179
  surface: str5(flags.surface),
66798
67180
  spa: str5(flags.spa),
66799
- open: flags["no-open"] !== true
67181
+ open: flags["no-open"] !== true,
67182
+ ...watchKit && served && bus ? { workDir: served, screenEvents: bus, extraRoutes: (request) => watchKit.boardFile(dir, new URL(request.url).pathname) } : {}
66800
67183
  });
67184
+ let watcher;
67185
+ let rebuild;
67186
+ let recorded = false;
67187
+ let stopping = false;
67188
+ const refreshBoard = async () => {
67189
+ if (!boardOpen(dir)) return;
67190
+ const { refreshStudio: refreshStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
67191
+ refreshStudio2(dir);
67192
+ };
67193
+ if (watchKit && bus) {
67194
+ try {
67195
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
67196
+ const record2 = (build2) => {
67197
+ if (watchKit.writeRunRecord(dir, { url: running.url, port: running.port, pid: process.pid, startedAt, build: build2 })) recorded = true;
67198
+ };
67199
+ record2({ ok: true, at: startedAt });
67200
+ if (!recorded) io.error(JSON.stringify({ watch: "run_record_skipped", message: `${join56(dir, ".himi")} is not a real directory, so the build board will not frame this preview.` }));
67201
+ await refreshBoard();
67202
+ const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
67203
+ const live2 = join56(running.releaseRoot, running.app);
67204
+ const manifestOf = (tree) => JSON.parse(readFileSync71(join56(tree, "release-manifest.json"), "utf8"));
67205
+ let current = manifestOf(live2);
67206
+ const failed2 = async (message) => {
67207
+ if (stopping) return;
67208
+ bus.publish("build.failed", { message });
67209
+ record2({ ok: false, at: (/* @__PURE__ */ new Date()).toISOString(), error: message });
67210
+ await refreshBoard();
67211
+ io.error(JSON.stringify({ watch: "build_failed", keptLastGood: true, message }));
67212
+ };
67213
+ rebuild = watchKit.serialize(async () => {
67214
+ const t0 = Date.now();
67215
+ const next = mkdtempSync4(join56(tmpdir5(), "himi-run-build-"));
67216
+ try {
67217
+ const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
67218
+ if (bres.compileErrors.length) {
67219
+ const first = bres.compileErrors[0];
67220
+ const diag = first.errors[0];
67221
+ await failed2(`${first.bundle}: ${diag ? `${diag.file ? `${diag.file}${diag.line ? `:${diag.line}` : ""} ` : ""}${diag.text}` : "did not compile"}`);
67222
+ return;
67223
+ }
67224
+ const hasWorkers = bres.built.length > 0;
67225
+ const outcome = await buildReleaseFromContent2(dir, next, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {} });
67226
+ const blocker = watchKit.rebuildBlocker(outcome, servedMissing);
67227
+ if (blocker) {
67228
+ await failed2(blocker);
67229
+ return;
67230
+ }
67231
+ if (stopping) return;
67232
+ const fresh = manifestOf(join56(next, running.app));
67233
+ const diff = watchKit.diffReleases(current, fresh);
67234
+ const retired = `${live2}.retired-${Date.now()}`;
67235
+ renameSync6(live2, retired);
67236
+ try {
67237
+ renameSync6(join56(next, running.app), live2);
67238
+ } catch {
67239
+ cpSync3(join56(next, running.app), live2, { recursive: true });
67240
+ }
67241
+ rmSync13(retired, { recursive: true, force: true });
67242
+ current = fresh;
67243
+ servedMissing = outcome.missingBundles;
67244
+ for (const [event, data] of watchKit.reloadEvents(diff)) bus.publish(event, data);
67245
+ record2({ ok: true, at: (/* @__PURE__ */ new Date()).toISOString() });
67246
+ await refreshBoard();
67247
+ io.error(JSON.stringify({ watch: "rebuilt", ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config, tabs: bus.listeners }));
67248
+ } catch (e) {
67249
+ await failed2(e.message.split("\n")[0]);
67250
+ } finally {
67251
+ rmSync13(next, { recursive: true, force: true });
67252
+ }
67253
+ });
67254
+ watcher = watchKit.watchContent(dir, () => rebuild?.());
67255
+ } catch (e) {
67256
+ if (recorded) watchKit.removeRunRecord(dir);
67257
+ await running.close();
67258
+ throw e;
67259
+ }
67260
+ }
66801
67261
  print({
66802
67262
  ok: true,
66803
67263
  app: running.app,
66804
67264
  releaseId: running.releaseId,
66805
67265
  url: running.url,
66806
67266
  port: running.port,
67267
+ ...watch2 ? { watching: dir, ...boardOpen(dir) ? { board: `${running.origin}/__himi/studio/` } : {} } : {},
66807
67268
  ...running.warnings.length ? { warnings: running.warnings } : {},
66808
67269
  stop: "Ctrl-C"
66809
67270
  });
66810
67271
  await new Promise((done) => {
66811
- const stop = () => {
66812
- void running.close().then(done);
67272
+ const stop = async () => {
67273
+ stopping = true;
67274
+ watcher?.close();
67275
+ try {
67276
+ await rebuild?.stop();
67277
+ if (recorded) {
67278
+ watchKit?.removeRunRecord(dir);
67279
+ await refreshBoard();
67280
+ }
67281
+ } catch (e) {
67282
+ io.error(JSON.stringify({ watch: "stop_cleanup_failed", message: e.message }));
67283
+ } finally {
67284
+ await running.close();
67285
+ done();
67286
+ }
66813
67287
  };
66814
- process.once("SIGINT", stop);
66815
- process.once("SIGTERM", stop);
67288
+ process.once("SIGINT", () => void stop());
67289
+ process.once("SIGTERM", () => void stop());
66816
67290
  });
66817
67291
  return 0;
66818
67292
  } catch (e) {
66819
67293
  io.error(JSON.stringify({ error: e.message }));
66820
67294
  return 1;
66821
67295
  } finally {
66822
- if (temp) rmSync11(temp, { recursive: true, force: true });
67296
+ if (temp) rmSync13(temp, { recursive: true, force: true });
67297
+ if (served) rmSync13(served, { recursive: true, force: true });
66823
67298
  }
66824
67299
  }
66825
67300
  case "preview": {
@@ -67360,7 +67835,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67360
67835
  io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
67361
67836
  return 2;
67362
67837
  }
67363
- if (!existsSync59(file)) {
67838
+ if (!existsSync60(file)) {
67364
67839
  io.error(JSON.stringify({ error: `no such file: ${file}` }));
67365
67840
  return 2;
67366
67841
  }
@@ -67416,7 +67891,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67416
67891
  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."
67417
67892
  };
67418
67893
  if (kind === "tokens" || kind === "app-config") {
67419
- const body = readFileSync70(file, "utf8");
67894
+ const body = readFileSync71(file, "utf8");
67420
67895
  const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
67421
67896
  return runReleasePatch({
67422
67897
  ...common,
@@ -67431,7 +67906,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67431
67906
  io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
67432
67907
  return 2;
67433
67908
  }
67434
- const descriptor = readFileSync70(file, "utf8");
67909
+ const descriptor = readFileSync71(file, "utf8");
67435
67910
  try {
67436
67911
  JSON.parse(descriptor);
67437
67912
  } catch (e) {
@@ -67471,7 +67946,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67471
67946
  extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
67472
67947
  });
67473
67948
  }
67474
- const bytes2 = readFileSync70(file);
67949
+ const bytes2 = readFileSync71(file);
67475
67950
  const sha = createHash26("sha256").update(bytes2).digest("hex");
67476
67951
  const forScreens = (str5(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
67477
67952
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
@@ -67615,7 +68090,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
67615
68090
  }
67616
68091
  let def;
67617
68092
  try {
67618
- const parsed = JSON.parse(arg.startsWith("@") ? readFileSync70(arg.slice(1), "utf8") : arg);
68093
+ const parsed = JSON.parse(arg.startsWith("@") ? readFileSync71(arg.slice(1), "utf8") : arg);
67619
68094
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
67620
68095
  io.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
67621
68096
  return 2;
@@ -68079,7 +68554,7 @@ ${label2}`);
68079
68554
  const platform = str5(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
68080
68555
  {
68081
68556
  const distDir = contentDir(flags);
68082
- if (existsSync59(join55(distDir, "himalaya.content.json"))) {
68557
+ if (existsSync60(join56(distDir, "himalaya.content.json"))) {
68083
68558
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
68084
68559
  const errors = issues.filter((i) => i.severity === "error");
68085
68560
  for (const i of issues.filter((i2) => i2.severity === "warning")) {
@@ -68348,7 +68823,7 @@ ${label2}`);
68348
68823
  const dpxPath = dpxSessionTokenPath();
68349
68824
  let dpx;
68350
68825
  try {
68351
- dpx = readFileSync70(dpxPath, "utf8").trim();
68826
+ dpx = readFileSync71(dpxPath, "utf8").trim();
68352
68827
  } catch {
68353
68828
  io.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
68354
68829
  return 1;
@@ -68750,7 +69225,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
68750
69225
  const path2 = dpxSessionTokenPath();
68751
69226
  let raw;
68752
69227
  try {
68753
- raw = readFileSync70(path2, "utf8");
69228
+ raw = readFileSync71(path2, "utf8");
68754
69229
  } catch {
68755
69230
  io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
68756
69231
  return 1;