@wix/himalaya-cli 0.981.0 → 0.982.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
@@ -1901,6 +1901,20 @@ var init_himi_report = __esm({
1901
1901
  }
1902
1902
  });
1903
1903
 
1904
+ // ../../core/serve-storage/src/widget-identity.ts
1905
+ function stableWidgets(widgets) {
1906
+ if (!widgets || typeof widgets !== "object" || Array.isArray(widgets)) return widgets;
1907
+ return Object.fromEntries(Object.entries(widgets).map(([id, value]) => {
1908
+ if (!value || typeof value !== "object" || Array.isArray(value)) return [id, value];
1909
+ const { contentEtag: _regenerated, ...stable } = value;
1910
+ return [id, stable];
1911
+ }));
1912
+ }
1913
+ var init_widget_identity = __esm({
1914
+ "../../core/serve-storage/src/widget-identity.ts"() {
1915
+ }
1916
+ });
1917
+
1904
1918
  // ../../core/dev-server/src/wix-placeholders.ts
1905
1919
  var PLACEHOLDER_CLIENT_ID;
1906
1920
  var init_wix_placeholders = __esm({
@@ -11697,11 +11711,16 @@ var init_catalog = __esm({
11697
11711
  // ../font-bake/plan-fonts.ts
11698
11712
  function demandFromTokens(tokens) {
11699
11713
  const demand = /* @__PURE__ */ new Map();
11700
- for (const token of Object.values(tokens.typography ?? {})) {
11701
- const family = token?.family;
11702
- if (typeof family !== "string" || family.length === 0) continue;
11703
- const weight = typeof token?.weight === "number" ? token.weight : 400;
11704
- demand.set(family, (demand.get(family) ?? /* @__PURE__ */ new Set()).add(weight));
11714
+ const add = (family, weight) => {
11715
+ if (typeof family !== "string" || family.length === 0) return;
11716
+ demand.set(family, (demand.get(family) ?? /* @__PURE__ */ new Set()).add(typeof weight === "number" ? weight : 400));
11717
+ };
11718
+ const base = tokens.typography ?? {};
11719
+ for (const token of Object.values(base)) add(token?.family, token?.weight);
11720
+ for (const overlay of Object.values(tokens.idiom ?? {})) {
11721
+ for (const [role, token] of Object.entries(overlay?.typography ?? {})) {
11722
+ add(token?.family ?? base[role]?.family, token?.weight ?? base[role]?.weight);
11723
+ }
11705
11724
  }
11706
11725
  return demand;
11707
11726
  }
@@ -16234,7 +16253,7 @@ function assignStableIds(descriptor) {
16234
16253
  used.add(out);
16235
16254
  return out;
16236
16255
  };
16237
- const assign = (node, path) => {
16256
+ const assign2 = (node, path) => {
16238
16257
  const base = node.id && node.id.length > 0 ? node.id : path;
16239
16258
  node.id = uniquify(base);
16240
16259
  const typeCounts = {};
@@ -16243,12 +16262,12 @@ function assignStableIds(descriptor) {
16243
16262
  const n = typeCounts[t] ?? 0;
16244
16263
  typeCounts[t] = n + 1;
16245
16264
  const seg = n === 0 ? t : `${t}.${n}`;
16246
- assign(child, `${path}/${seg}`);
16265
+ assign2(child, `${path}/${seg}`);
16247
16266
  });
16248
16267
  };
16249
- if (isNode(descriptor.payload)) assign(descriptor.payload, descriptor.screenId);
16250
- if (isNode(descriptor.stickyHeader)) assign(descriptor.stickyHeader, `${descriptor.screenId}/stickyHeader`);
16251
- if (isNode(descriptor.stickyFooter)) assign(descriptor.stickyFooter, `${descriptor.screenId}/stickyFooter`);
16268
+ if (isNode(descriptor.payload)) assign2(descriptor.payload, descriptor.screenId);
16269
+ if (isNode(descriptor.stickyHeader)) assign2(descriptor.stickyHeader, `${descriptor.screenId}/stickyHeader`);
16270
+ if (isNode(descriptor.stickyFooter)) assign2(descriptor.stickyFooter, `${descriptor.screenId}/stickyFooter`);
16252
16271
  }
16253
16272
  var init_stable_ids = __esm({
16254
16273
  "../../core/dev-server/src/stable-ids.ts"() {
@@ -17633,6 +17652,70 @@ var init_env = __esm({
17633
17652
  }
17634
17653
  });
17635
17654
 
17655
+ // ../../core/ts/src/idiom.ts
17656
+ function authored(overlays, name) {
17657
+ return typeof name === "string" && overlays !== void 0 && Object.hasOwn(overlays, name) && overlays[name] !== null && typeof overlays[name] === "object" && !Array.isArray(overlays[name]);
17658
+ }
17659
+ function selectIdiomOverlay(doc, ctx = {}) {
17660
+ const policy = doc.idiomPolicy;
17661
+ const overlays = doc.idiom;
17662
+ const isRecord3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
17663
+ if (!isRecord3(policy) || !isRecord3(overlays)) return void 0;
17664
+ const kind = policy.policy ?? "follow-surface";
17665
+ if (kind === "none") return void 0;
17666
+ if (kind === "pinned") return authored(overlays, policy.pin) ? policy.pin : void 0;
17667
+ if (kind !== "follow-surface") return void 0;
17668
+ const surfaces = policy.surfaces;
17669
+ const candidates = [
17670
+ ctx.surface !== void 0 && isRecord3(surfaces) && Object.hasOwn(surfaces, ctx.surface) ? surfaces[ctx.surface] : void 0,
17671
+ ...ctx.native ?? [],
17672
+ policy.fallback
17673
+ ];
17674
+ return candidates.find((c) => authored(overlays, c));
17675
+ }
17676
+ function isPlainObject(v) {
17677
+ return v !== null && typeof v === "object" && !Array.isArray(v);
17678
+ }
17679
+ function deepMerge2(base, overlay) {
17680
+ if (!isPlainObject(overlay) || !isPlainObject(base)) return overlay;
17681
+ const out = { ...base };
17682
+ for (const [key2, value] of Object.entries(overlay)) {
17683
+ if (UNSAFE_KEYS.has(key2)) continue;
17684
+ out[key2] = Object.hasOwn(base, key2) ? deepMerge2(base[key2], value) : value;
17685
+ }
17686
+ return out;
17687
+ }
17688
+ function mergeIdiomOverlay(base, overlay) {
17689
+ const merged = deepMerge2(base, overlay);
17690
+ const baseColors = base.colors;
17691
+ const overlayColors = overlay.colors;
17692
+ if (isPlainObject(baseColors) && isPlainObject(overlayColors)) {
17693
+ const colors = { ...merged.colors };
17694
+ for (const [name, value] of Object.entries(overlayColors)) {
17695
+ if (UNSAFE_KEYS.has(name)) continue;
17696
+ const was = Object.hasOwn(baseColors, name) ? baseColors[name] : void 0;
17697
+ if (typeof was === "string" && isPlainObject(value)) colors[name] = { light: was, ...value };
17698
+ }
17699
+ merged.colors = colors;
17700
+ }
17701
+ return merged;
17702
+ }
17703
+ function resolveIdiom(tokens, ctx = {}) {
17704
+ const doc = tokens;
17705
+ const name = selectIdiomOverlay(doc, ctx);
17706
+ if (name === void 0) return tokens;
17707
+ const merged = mergeIdiomOverlay(tokens, doc.idiom[name]);
17708
+ const { idiomPolicy: _applied, ...final } = merged;
17709
+ return final;
17710
+ }
17711
+ var UNSAFE_KEYS;
17712
+ var init_idiom = __esm({
17713
+ "../../core/ts/src/idiom.ts"() {
17714
+ "use strict";
17715
+ UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
17716
+ }
17717
+ });
17718
+
17636
17719
  // ../../core/web-renderer/src/tokens.ts
17637
17720
  function isSerifFamily(family) {
17638
17721
  return !!family && SERIF_FAMILY_RE.test(family);
@@ -17758,7 +17841,8 @@ function resolveSchemeColor(o, scheme) {
17758
17841
  if (typeof o?.light === "string") return o.light;
17759
17842
  return typeof o?.dark === "string" ? o.dark : void 0;
17760
17843
  }
17761
- function makeTokenResolvers(tokens, scheme) {
17844
+ function makeTokenResolvers(source, scheme, idiom = WEB_IDIOM_CONTEXT) {
17845
+ const tokens = resolveIdiom(source, idiom);
17762
17846
  const color = (name, fallback = "#1a1a1a") => {
17763
17847
  if (name == null) return fallback;
17764
17848
  if (typeof name !== "string") {
@@ -17897,13 +17981,15 @@ function makeTokenResolvers(tokens, scheme) {
17897
17981
  scheme
17898
17982
  };
17899
17983
  }
17900
- var REM_ROOT_PX, pxToRem, DEFAULT_FONT_STACK, SERIF_FAMILY_RE;
17984
+ var REM_ROOT_PX, pxToRem, DEFAULT_FONT_STACK, SERIF_FAMILY_RE, WEB_IDIOM_CONTEXT;
17901
17985
  var init_tokens2 = __esm({
17902
17986
  "../../core/web-renderer/src/tokens.ts"() {
17987
+ init_idiom();
17903
17988
  REM_ROOT_PX = 16;
17904
17989
  pxToRem = (px) => `${px / REM_ROOT_PX}rem`;
17905
17990
  DEFAULT_FONT_STACK = '"Wix Madefor Text", system-ui';
17906
17991
  SERIF_FAMILY_RE = /\b(georgia|times|garamond|palatino|baskerville|didot|charter|bodoni|caslon|cambria|constantia|rockwell|playfair|merriweather|lora|literata|spectral|serif)\b/i;
17992
+ WEB_IDIOM_CONTEXT = { surface: "desktop" };
17907
17993
  }
17908
17994
  });
17909
17995
 
@@ -28889,6 +28975,7 @@ var init_src5 = __esm({
28889
28975
  init_widget_vocabulary();
28890
28976
  init_preview_surfaces();
28891
28977
  init_tokens();
28978
+ init_idiom();
28892
28979
  init_tier_caps();
28893
28980
  init_flags();
28894
28981
  init_flags_engine();
@@ -30252,11 +30339,11 @@ import { readFileSync as readFileSync40, existsSync as existsSync35, watch, mkdi
30252
30339
  import { extname, resolve as resolve30, normalize as normalize3, sep as sep7, join as join34 } from "node:path";
30253
30340
  import { createHash as createHash15, randomUUID } from "node:crypto";
30254
30341
  import { fileURLToPath as fileURLToPath18, pathToFileURL as pathToFileURL6 } from "node:url";
30255
- function deepMerge2(base, patch) {
30342
+ function deepMerge3(base, patch) {
30256
30343
  if (patch === null || typeof patch !== "object" || Array.isArray(patch)) return patch;
30257
30344
  const out = Array.isArray(base) ? [...base] : { ...base };
30258
30345
  for (const [k, v] of Object.entries(patch)) {
30259
- out[k] = k in out ? deepMerge2(out[k], v) : v;
30346
+ out[k] = k in out ? deepMerge3(out[k], v) : v;
30260
30347
  }
30261
30348
  return out;
30262
30349
  }
@@ -30317,15 +30404,15 @@ function effectiveAppConfigOverride(state) {
30317
30404
  }
30318
30405
  }
30319
30406
  if (!gitOverlay && !state.appConfigOverride) return void 0;
30320
- return deepMerge2(
30321
- deepMerge2({}, gitOverlay ?? {}),
30407
+ return deepMerge3(
30408
+ deepMerge3({}, gitOverlay ?? {}),
30322
30409
  state.appConfigOverride ?? {}
30323
30410
  );
30324
30411
  }
30325
30412
  function effectiveAppTokens(req, state) {
30326
30413
  const built = readAppTokens(state);
30327
30414
  if (!built) return null;
30328
- let tokens = state.tokensOverride ? deepMerge2(built, state.tokensOverride) : built;
30415
+ let tokens = state.tokensOverride ? deepMerge3(built, state.tokensOverride) : built;
30329
30416
  let motionToggles = [];
30330
30417
  try {
30331
30418
  const motionDefs = state.flagStore.list().filter((d) => d.enabled && d.key.startsWith("motion_"));
@@ -30342,6 +30429,9 @@ function effectiveAppTokens(req, state) {
30342
30429
  const fontFaces = servedFontFaces(state.app.dir, tokens);
30343
30430
  if (fontFaces) tokens = { ...tokens, fontFaces };
30344
30431
  }
30432
+ const config = state.app?.module.config;
30433
+ const idiomPolicy = config && "idiom" in config ? config.idiom : void 0;
30434
+ if (idiomPolicy !== void 0) tokens = { ...tokens, idiomPolicy };
30345
30435
  const body = JSON.stringify(tokens);
30346
30436
  return { tokens, etag: makeEtag(body), motionToggles };
30347
30437
  }
@@ -31164,6 +31254,8 @@ async function reloadAppModuleNow(state, opts) {
31164
31254
  }
31165
31255
  const oldMeta = current.meta;
31166
31256
  const oldNav = JSON.stringify(deriveNavigationConfig(oldMeta) ?? null);
31257
+ const idiomOf = (m) => JSON.stringify(m.config.idiom ?? null);
31258
+ const oldIdiom = idiomOf(current.module);
31167
31259
  state.app = {
31168
31260
  name: current.name,
31169
31261
  module: next,
@@ -31185,6 +31277,9 @@ async function reloadAppModuleNow(state, opts) {
31185
31277
  if (oldNav !== newNav) {
31186
31278
  publishSSE(state, "config.invalidated", { reason: opts.reason, at: Date.now() });
31187
31279
  }
31280
+ if (idiomOf(next) !== oldIdiom) {
31281
+ publishSSE(state, "tokens.changed", { reason: opts.reason, at: Date.now() });
31282
+ }
31188
31283
  console.log(`[himalaya-dev] reloaded app module in-process: ${current.name} (${opts.reason})`);
31189
31284
  return { ok: true };
31190
31285
  } catch (err) {
@@ -31315,7 +31410,7 @@ async function handleFlagsEval(req, res, state) {
31315
31410
  function currentFlagConfig(state) {
31316
31411
  if (!state.app) return void 0;
31317
31412
  const base = deriveNavigationConfig(state.app.meta);
31318
- const merged = state.appConfigOverride ? deepMerge2(base, state.appConfigOverride) : base;
31413
+ const merged = state.appConfigOverride ? deepMerge3(base, state.appConfigOverride) : base;
31319
31414
  return merged.flagConfig;
31320
31415
  }
31321
31416
  function attachAssignments(descriptor, state, ctx, overrides) {
@@ -32092,7 +32187,7 @@ async function handleAdminPlayground(req, res, state) {
32092
32187
  if (path === "/v1/admin/app-config" && state.app) {
32093
32188
  const built = deriveNavigationConfig(state.app.meta);
32094
32189
  if (req.method === "GET") {
32095
- const effective = state.appConfigOverride ? deepMerge2(built, state.appConfigOverride) : built;
32190
+ const effective = state.appConfigOverride ? deepMerge3(built, state.appConfigOverride) : built;
32096
32191
  return sendJson(res, 200, { source: state.appConfigOverride ? "override" : "built", built, effective });
32097
32192
  }
32098
32193
  if (req.method === "PUT") {
@@ -32104,9 +32199,9 @@ async function handleAdminPlayground(req, res, state) {
32104
32199
  }
32105
32200
  if (!patch || typeof patch !== "object" || Array.isArray(patch)) return sendJson(res, 400, { error: "object_required" });
32106
32201
  const nav = isNavControlPatch(patch);
32107
- state.appConfigOverride = nav && state.appConfigOverride ? deepMerge2(state.appConfigOverride, patch) : patch;
32202
+ state.appConfigOverride = nav && state.appConfigOverride ? deepMerge3(state.appConfigOverride, patch) : patch;
32108
32203
  publishSSE(state, "config.invalidated", { reason: nav ? "navigate" : "admin_override", at: Date.now() });
32109
- return sendJson(res, 200, { status: "ok", effective: deepMerge2(built, state.appConfigOverride) });
32204
+ return sendJson(res, 200, { status: "ok", effective: deepMerge3(built, state.appConfigOverride) });
32110
32205
  }
32111
32206
  if (req.method === "DELETE") {
32112
32207
  const existed = state.appConfigOverride !== void 0;
@@ -32117,7 +32212,7 @@ async function handleAdminPlayground(req, res, state) {
32117
32212
  if (path === "/v1/admin/tokens" && state.app) {
32118
32213
  const built = readAppTokens(state) ?? {};
32119
32214
  if (req.method === "GET") {
32120
- const effective = state.tokensOverride ? deepMerge2(built, state.tokensOverride) : built;
32215
+ const effective = state.tokensOverride ? deepMerge3(built, state.tokensOverride) : built;
32121
32216
  return sendJson(res, 200, { source: state.tokensOverride ? "override" : "built", built, effective });
32122
32217
  }
32123
32218
  if (req.method === "PUT") {
@@ -32130,7 +32225,7 @@ async function handleAdminPlayground(req, res, state) {
32130
32225
  if (!patch || typeof patch !== "object" || Array.isArray(patch)) return sendJson(res, 400, { error: "object_required" });
32131
32226
  state.tokensOverride = patch;
32132
32227
  publishSSE(state, "tokens.changed", { reason: "admin_override", at: Date.now() });
32133
- return sendJson(res, 200, { status: "ok", effective: deepMerge2(built, state.tokensOverride) });
32228
+ return sendJson(res, 200, { status: "ok", effective: deepMerge3(built, state.tokensOverride) });
32134
32229
  }
32135
32230
  if (req.method === "DELETE") {
32136
32231
  const existed = state.tokensOverride !== void 0;
@@ -37300,10 +37395,11 @@ function notCarriedDiff(local, base) {
37300
37395
  const CARRIED = /* @__PURE__ */ new Set(["screens", "bundles", "tokensHash", "appConfigHash"]);
37301
37396
  const PROVENANCE = /* @__PURE__ */ new Set(["releaseId", "gitSha", "shellSha", "label", "notes", "publishedAt", "publishedBy", "attestation", "forcedPastErrors", "app", "appSourceHash"]);
37302
37397
  const REPORTED_IN_DETAIL = /* @__PURE__ */ new Set(["assets", "minBinaryVersion", "iconHash"]);
37398
+ const comparable = (key2, value) => key2 === "widgets" ? stableWidgets(value) : value;
37303
37399
  for (const key2 of /* @__PURE__ */ new Set([...Object.keys(local), ...Object.keys(base)])) {
37304
37400
  if (CARRIED.has(key2) || PROVENANCE.has(key2) || REPORTED_IN_DETAIL.has(key2)) continue;
37305
- const l = local[key2] ?? null;
37306
- const b = base[key2] ?? null;
37401
+ const l = comparable(key2, local[key2] ?? null);
37402
+ const b = comparable(key2, base[key2] ?? null);
37307
37403
  const ls = JSON.stringify(l) ?? "null";
37308
37404
  const bs = JSON.stringify(b) ?? "null";
37309
37405
  if (ls === bs) continue;
@@ -37352,6 +37448,7 @@ function patchHonesty(opts) {
37352
37448
  var SELECTOR_KINDS;
37353
37449
  var init_release_patch = __esm({
37354
37450
  "src/release-patch.ts"() {
37451
+ init_widget_identity();
37355
37452
  SELECTOR_KINDS = ["changed", "screen:<id|glob>", "bundle:<name>", "tokens", "app-config"];
37356
37453
  }
37357
37454
  });
@@ -37512,7 +37609,7 @@ async function navIssues(dir, strict) {
37512
37609
  const nav = cfg.navigation;
37513
37610
  pushRouteIssues(cfg.push, nav, warn);
37514
37611
  if (nav === void 0 || nav === null) return issues;
37515
- if (!isPlainObject(nav)) {
37612
+ if (!isPlainObject2(nav)) {
37516
37613
  error("nav-not-an-object", `navigation must be an object (got ${Array.isArray(nav) ? "array" : typeof nav}).`);
37517
37614
  return issues;
37518
37615
  }
@@ -37542,10 +37639,10 @@ async function navIssues(dir, strict) {
37542
37639
  for (const key2 of ITEMS_BLOCKS) {
37543
37640
  const block = nav[key2];
37544
37641
  if (block === void 0) continue;
37545
- if (!isPlainObject(block) || !Array.isArray(block.items)) {
37642
+ if (!isPlainObject2(block) || !Array.isArray(block.items)) {
37546
37643
  error(
37547
37644
  "nav-chrome-shape",
37548
- `navigation.${key2} must be an object with an \`items\` array \u2014 \`${key2}: { items: [ \u2026 ] }\` (got ${Array.isArray(block) ? "an array" : isPlainObject(block) ? "an object with no `items` array" : typeof block}). The server forwards this verbatim, so the shell finds no destinations and draws none.`
37645
+ `navigation.${key2} must be an object with an \`items\` array \u2014 \`${key2}: { items: [ \u2026 ] }\` (got ${Array.isArray(block) ? "an array" : isPlainObject2(block) ? "an object with no `items` array" : typeof block}). The server forwards this verbatim, so the shell finds no destinations and draws none.`
37549
37646
  );
37550
37647
  }
37551
37648
  }
@@ -37561,7 +37658,7 @@ async function navIssues(dir, strict) {
37561
37658
  if (effectiveBottomTabs && !declaresOtherChrome && itemCount(nav.tabBar) === 0) {
37562
37659
  const linkables = Array.isArray(nav.linkableScreens) ? nav.linkableScreens : [];
37563
37660
  const topLevel = new Set(
37564
- linkables.filter((s) => isPlainObject(s) && !s.parentScreenId).map((s) => String(s.screenId ?? ""))
37661
+ linkables.filter((s) => isPlainObject2(s) && !s.parentScreenId).map((s) => String(s.screenId ?? ""))
37565
37662
  );
37566
37663
  topLevel.delete("");
37567
37664
  if (topLevel.size > 1) {
@@ -37579,8 +37676,8 @@ async function navIssues(dir, strict) {
37579
37676
  return issues;
37580
37677
  }
37581
37678
  function pushRouteIssues(push, nav, warn) {
37582
- if (!isPlainObject(push) || push.payloadAdapter !== "wix-ping") return;
37583
- const routes = Array.isArray(push.routes) ? push.routes.filter(isPlainObject) : [];
37679
+ if (!isPlainObject2(push) || push.payloadAdapter !== "wix-ping") return;
37680
+ const routes = Array.isArray(push.routes) ? push.routes.filter(isPlainObject2) : [];
37584
37681
  if (routes.length === 0) {
37585
37682
  warn(
37586
37683
  "push-routes-missing",
@@ -37588,10 +37685,10 @@ function pushRouteIssues(push, nav, warn) {
37588
37685
  );
37589
37686
  return;
37590
37687
  }
37591
- const linkables = isPlainObject(nav) ? nav.linkableScreens : void 0;
37688
+ const linkables = isPlainObject2(nav) ? nav.linkableScreens : void 0;
37592
37689
  if (!Array.isArray(linkables)) return;
37593
37690
  const declared = new Set(
37594
- linkables.filter(isPlainObject).map((s) => String(s.screenId ?? ""))
37691
+ linkables.filter(isPlainObject2).map((s) => String(s.screenId ?? ""))
37595
37692
  );
37596
37693
  for (const route of routes) {
37597
37694
  const screenId = /:\/\/screen\/([^?]+)/.exec(String(route.link ?? ""))?.[1];
@@ -37603,7 +37700,7 @@ function pushRouteIssues(push, nav, warn) {
37603
37700
  }
37604
37701
  }
37605
37702
  }
37606
- var NAVIGATION_KEYS, NAV_KINDS, ITEMS_BLOCKS, SERVED_ONLY_NAV_KEYS, MISPLACED_TOP_LEVEL_KEYS, isPlainObject, itemCount;
37703
+ var NAVIGATION_KEYS, NAV_KINDS, ITEMS_BLOCKS, SERVED_ONLY_NAV_KEYS, MISPLACED_TOP_LEVEL_KEYS, isPlainObject2, itemCount;
37607
37704
  var init_nav_lint = __esm({
37608
37705
  "src/nav-lint.ts"() {
37609
37706
  init_app_config_loader();
@@ -37648,8 +37745,8 @@ var init_nav_lint = __esm({
37648
37745
  "deepLinkPatterns",
37649
37746
  "linkableScreens"
37650
37747
  ];
37651
- isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
37652
- itemCount = (v) => isPlainObject(v) && Array.isArray(v.items) ? v.items.length : 0;
37748
+ isPlainObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
37749
+ itemCount = (v) => isPlainObject2(v) && Array.isArray(v.items) ? v.items.length : 0;
37653
37750
  }
37654
37751
  });
37655
37752
 
@@ -43388,29 +43485,49 @@ function scriptNonce() {
43388
43485
  function previewCsp(nonce) {
43389
43486
  return `script-src 'self' 'nonce-${nonce}'; base-uri 'self'; object-src 'none'`;
43390
43487
  }
43391
- function indexHtml(asset, pathname) {
43488
+ function inlineJson(value) {
43489
+ return JSON.stringify(value).replace(/</g, "\\u003c");
43490
+ }
43491
+ function previewCredentialsJs(creds) {
43492
+ return `(function(){var d=${inlineJson(creds)};window.__himalayaPreview__=d;try{sessionStorage.setItem("himalaya.preview."+d.app,JSON.stringify(d))}catch(e){}try{var u=new URL(location.href);if(u.searchParams.has("h")){u.searchParams.delete("h");history.replaceState(null,"",u.pathname+u.search+u.hash)}}catch(e){}})();`;
43493
+ }
43494
+ function stripHandoverParamJs() {
43495
+ return '(function(){window.__himalayaHandoverFailed__=true;try{var u=new URL(location.href);if(u.searchParams.has("h")){u.searchParams.delete("h");history.replaceState(null,"",u.pathname+u.search+u.hash)}}catch(e){}})();';
43496
+ }
43497
+ function indexHtml(asset, pathname, creds, handoverAttempted = false) {
43392
43498
  void pathname;
43393
43499
  const nonce = scriptNonce();
43394
43500
  const raw = new TextDecoder().decode(assetBytes(asset));
43395
- const html = raw.replace(/(=|url\()(["']?)\/preview\//g, "$1$2").replace(/<head(\s[^>]*)?>/i, (head) => `${head}<script nonce="${nonce}">${PREVIEW_BASE_JS}</script>`);
43501
+ const head = `<script nonce="${nonce}">${PREVIEW_BASE_JS}</script>` + (creds ? `<script nonce="${nonce}">${previewCredentialsJs(creds)}</script>` : handoverAttempted ? `<script nonce="${nonce}">${stripHandoverParamJs()}</script>` : "");
43502
+ const html = raw.replace(/(=|url\()(["']?)\/preview\//g, "$1$2").replace(/<head(\s[^>]*)?>/i, (tag) => `${tag}${head}`);
43396
43503
  return new Response(html, {
43397
43504
  status: 200,
43398
43505
  // The shell only changes on an artifact deploy, and everything it loads is
43399
43506
  // hash-addressed or release-pinned — so let repeat opens paint instantly from
43400
43507
  // cache while revalidating in the background (the measured cold TTFB through
43401
43508
  // the bo gateway was ~600ms, all of it this document).
43509
+ //
43510
+ // …UNLESS this document carries a redeemed bearer, OR reflects a FAILED handover attempt
43511
+ // (#3042). A redeemed bearer makes it a one-recipient credential delivery, where
43512
+ // `public, max-age=60` would authorize a shared cache to hand it to the next person who
43513
+ // asks. A failed attempt carries the same risk for a different reason: the request URL names
43514
+ // a code (`?h=`) that may still be live (a transient `store_unavailable`, say), and caching
43515
+ // an inert answer to that exact URL would let a shared cache stand between the code and a
43516
+ // legitimate retry. `no-store` also keeps either case out of the browser's own back/forward
43517
+ // cache on disk. The plain (no handover attempted at all) document is untouched and keeps
43518
+ // its cache.
43402
43519
  headers: {
43403
43520
  "content-type": asset.contentType || "text/html; charset=utf-8",
43404
- "cache-control": "public, max-age=60, stale-while-revalidate=600",
43521
+ "cache-control": creds || handoverAttempted ? "no-store" : "public, max-age=60, stale-while-revalidate=600",
43405
43522
  "content-security-policy": previewCsp(nonce)
43406
43523
  }
43407
43524
  });
43408
43525
  }
43409
- function previewResponse(pathname, assets, mount = "/preview") {
43526
+ function previewResponse(pathname, assets, mount = "/preview", creds, handoverAttempted = false) {
43410
43527
  const key2 = pathname.replace(MOUNT_STRIP[mount], "") || "index.html";
43411
43528
  const hit = assets.get(key2);
43412
43529
  if (hit) {
43413
- if (key2 === "index.html") return indexHtml(hit, pathname);
43530
+ if (key2 === "index.html") return indexHtml(hit, pathname, creds, handoverAttempted);
43414
43531
  if (key2 === "t5-frame.html") {
43415
43532
  return new Response(assetBytes(hit), {
43416
43533
  status: 200,
@@ -43427,7 +43544,7 @@ function previewResponse(pathname, assets, mount = "/preview") {
43427
43544
  });
43428
43545
  }
43429
43546
  const index = assets.get("index.html");
43430
- if (index) return indexHtml(index, pathname);
43547
+ if (index) return indexHtml(index, pathname, creds, handoverAttempted);
43431
43548
  return new Response(JSON.stringify({ error: "preview_not_built" }), {
43432
43549
  status: 503,
43433
43550
  headers: { "content-type": "application/json; charset=utf-8" }
@@ -43649,19 +43766,19 @@ var init_preview_assets_generated = __esm({
43649
43766
  "../../packages/serve/src/preview-assets.generated.ts"() {
43650
43767
  init_preview_assets_format();
43651
43768
  PREVIEW_ASSET_MANIFEST = [
43652
- { key: "assets/index-EUz_f6yu.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 987137, sha256: "7b526f22885a0dfed16aa63cc802e4d17c3565e78ba5a8a873bcb111ffe1a076" },
43653
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 987145, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
43654
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1078069, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
43655
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1169053, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
43656
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1260033, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
43657
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1350905, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
43658
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1441885, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
43659
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1550521, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
43660
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1659605, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
43661
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1768653, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
43662
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1876353, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
43663
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1964461, length: 4448, sha256: "78be80518ed0f28fbf085b806c0d4ef5ec796da109a3f2f257f4ee31e1c01214" },
43664
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1968909, length: 13784, sha256: "cfb9465254fab84f0e084bb4542c282758ea29774b5f172840cc0b9e4194ef89" }
43769
+ { key: "assets/index-BpbA_kgY.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 989132, sha256: "56294e0b1e3ed17b553d17b61856896ae8865ae57bc76443d12c5d6437a37d22" },
43770
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 989140, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
43771
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1080064, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
43772
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1171048, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
43773
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1262028, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
43774
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1352900, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
43775
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1443880, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
43776
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1552516, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
43777
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1661600, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
43778
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1770648, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
43779
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1878348, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
43780
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1966456, length: 4448, sha256: "4b295aeb4c64dc9378313f44a384fca9054809e665c6a06e00c1b11f7a1596b7" },
43781
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1970904, length: 13784, sha256: "cfb9465254fab84f0e084bb4542c282758ea29774b5f172840cc0b9e4194ef89" }
43665
43782
  ];
43666
43783
  }
43667
43784
  });
@@ -49089,12 +49206,12 @@ function findRepoRoot(cwd) {
49089
49206
  }
49090
49207
  return null;
49091
49208
  }
49092
- function deepMerge3(a, b) {
49209
+ function deepMerge4(a, b) {
49093
49210
  const out = { ...a };
49094
49211
  for (const [k, v] of Object.entries(b)) {
49095
49212
  const cur = out[k];
49096
49213
  if (v && typeof v === "object" && !Array.isArray(v) && cur && typeof cur === "object" && !Array.isArray(cur)) {
49097
- out[k] = deepMerge3(cur, v);
49214
+ out[k] = deepMerge4(cur, v);
49098
49215
  } else {
49099
49216
  out[k] = v;
49100
49217
  }
@@ -49146,7 +49263,7 @@ function mergeCustomerOwned(committed, overlay) {
49146
49263
  if (typeof value === "string" && value.trim() === "") delete overlayIdentity[key2];
49147
49264
  }
49148
49265
  if (customer.identity !== void 0) customer.identity = overlayIdentity;
49149
- return deepMerge3(committed, customer);
49266
+ return deepMerge4(committed, customer);
49150
49267
  }
49151
49268
  function buildMergedContract(options) {
49152
49269
  const { appDir: appDir2, packageDir, overlay } = options;
@@ -49263,7 +49380,7 @@ async function applyOverlays(input) {
49263
49380
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
49264
49381
  if (existsSync52(pkgProv)) {
49265
49382
  const cur = JSON.parse(readFileSync62(pkgProv, "utf8"));
49266
- const merged = deepMerge3(cur, overlay);
49383
+ const merged = deepMerge4(cur, overlay);
49267
49384
  writeFileSync21(pkgProv, JSON.stringify(merged, null, 2) + "\n");
49268
49385
  wrote.push(pkgProv);
49269
49386
  } else {
@@ -49273,7 +49390,7 @@ async function applyOverlays(input) {
49273
49390
  const pkgTokens = join50(cwd, "tokens.json");
49274
49391
  if (existsSync52(pkgTokens) && (tokens.colors || tokens.typography)) {
49275
49392
  const cur = JSON.parse(readFileSync62(pkgTokens, "utf8"));
49276
- const merged = deepMerge3(cur, tokens);
49393
+ const merged = deepMerge4(cur, tokens);
49277
49394
  const mergedColors = merged.colors;
49278
49395
  if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
49279
49396
  merged.colors = alignAccentsToSurfaces(mergedColors, tokens.colors);
@@ -52227,6 +52344,7 @@ if (process.argv[1] && basename(process.argv[1]) === "diff-hash.mjs" && import.m
52227
52344
  }
52228
52345
 
52229
52346
  // src/attestation.ts
52347
+ init_widget_identity();
52230
52348
  var DEFAULT_MAX_RUNS = 20;
52231
52349
  var ATTESTATION_VERSION = 2;
52232
52350
  function attestationVersionOf(value) {
@@ -52265,12 +52383,7 @@ function releasePayloadHash(payload) {
52265
52383
  const manifestRecord = manifest;
52266
52384
  const widgets = manifestRecord.widgets;
52267
52385
  if (!widgets || typeof widgets !== "object" || Array.isArray(widgets)) return sha256(canonical(payload));
52268
- const stableWidgets = Object.fromEntries(Object.entries(widgets).map(([id, value]) => {
52269
- if (!value || typeof value !== "object" || Array.isArray(value)) return [id, value];
52270
- const { contentEtag: _generatedContentEtag, ...stable } = value;
52271
- return [id, stable];
52272
- }));
52273
- return sha256(canonical({ ...record2, manifest: { ...manifestRecord, widgets: stableWidgets } }));
52386
+ return sha256(canonical({ ...record2, manifest: { ...manifestRecord, widgets: stableWidgets(widgets) } }));
52274
52387
  }
52275
52388
  function withoutSelfHash(attestation) {
52276
52389
  const { selfHash: _selfHash, ...body } = attestation;
@@ -54074,13 +54187,26 @@ function headers(session) {
54074
54187
  function truncate(token) {
54075
54188
  return token.length <= 20 ? token : `${token.slice(0, 8)}\u2026${token.slice(-8)}`;
54076
54189
  }
54190
+ function parseDataFlag(raw) {
54191
+ if (raw === void 0) return {};
54192
+ if (typeof raw === "boolean") return { error: "--data expects k=v" };
54193
+ const entries = Array.isArray(raw) ? raw : [raw];
54194
+ const out = {};
54195
+ for (const entry of entries) {
54196
+ if (typeof entry !== "string") return { error: "--data expects k=v" };
54197
+ const eq = entry.indexOf("=");
54198
+ if (eq <= 0) return { error: `--data expects k=v, got "${entry}"` };
54199
+ out[entry.slice(0, eq)] = entry.slice(eq + 1);
54200
+ }
54201
+ return Object.keys(out).length ? { value: out } : {};
54202
+ }
54077
54203
  async function runNotify(pos, flags, io, deps = {}) {
54078
54204
  const doFetch = deps.fetchImpl ?? fetch;
54079
54205
  const str6 = (v) => typeof v === "string" ? v : void 0;
54080
54206
  const json5 = flags.json === true;
54081
54207
  const print = (v) => io.log(JSON.stringify(v, null, 2));
54082
54208
  const sub = pos[1];
54083
- const USAGE2 = "himi notify send --app <app> (--token <t> | --device <id> | --all) --title <s> [--body <s>] [--link <url>]\n [--platform ios|android] [--category <c>] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]\nhimi notify tokens --app <app> [--platform ios|android] [--include-disabled] [--json]\nhimi notify doctor [--json]";
54209
+ const USAGE2 = "himi notify send --app <app> (--token <t> | --device <id> | --all) --title <s> [--body <s>] [--link <url>]\n [--platform ios|android] [--category <c>] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]\n [--data k=v ...]\nhimi notify tokens --app <app> [--platform ios|android] [--include-disabled] [--json]\nhimi notify doctor [--json]";
54084
54210
  if (!sub || !["send", "tokens", "doctor"].includes(sub)) {
54085
54211
  io.error(
54086
54212
  JSON.stringify({
@@ -54206,6 +54332,11 @@ async function runNotify(pos, flags, io, deps = {}) {
54206
54332
  io.error(JSON.stringify({ error: `targets are mutually exclusive \u2014 got ${targets.join(" and ")}`, usage: USAGE2 }));
54207
54333
  return 2;
54208
54334
  }
54335
+ const data = parseDataFlag(flags.data);
54336
+ if (data.error) {
54337
+ io.error(JSON.stringify({ error: data.error, usage: USAGE2 }));
54338
+ return 2;
54339
+ }
54209
54340
  const silent = flags.silent === true;
54210
54341
  const title = str6(flags.title);
54211
54342
  if (!silent && !title) {
@@ -54226,7 +54357,10 @@ async function runNotify(pos, flags, io, deps = {}) {
54226
54357
  ...flags["dry-run"] === true ? { dryRun: true } : {},
54227
54358
  ...all ? { all: true } : {},
54228
54359
  ...token ? { token } : {},
54229
- ...device ? { tokenId: Number(device) } : {}
54360
+ ...device ? { tokenId: Number(device) } : {},
54361
+ // Absent rather than `{}` when unset: the route distinguishes the two, and an
54362
+ // empty map is a request to send nothing rather than to send no map.
54363
+ ...data.value ? { data: data.value } : {}
54230
54364
  };
54231
54365
  if (device && !Number.isInteger(Number(device))) {
54232
54366
  io.error(JSON.stringify({ error: `--device takes a numeric registry id (from \`himi notify tokens\`), got "${device}"` }));
@@ -54781,6 +54915,7 @@ function writeAgentContext(targetDir) {
54781
54915
  // src/cli.ts
54782
54916
  init_wix_placeholders();
54783
54917
  var defaultIO = { log: (l) => console.log(l), error: (l) => console.error(l), isTTY: process.stdout.isTTY === true };
54918
+ var REPEATABLE_FLAGS = /* @__PURE__ */ new Set(["data"]);
54784
54919
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
54785
54920
  "browser",
54786
54921
  "no-open",
@@ -54872,6 +55007,14 @@ function switchFlagErrors(argv) {
54872
55007
  }
54873
55008
  return out;
54874
55009
  }
55010
+ function assign(flags, name, value) {
55011
+ if (!REPEATABLE_FLAGS.has(name)) {
55012
+ flags[name] = value;
55013
+ return;
55014
+ }
55015
+ const seen = flags[name];
55016
+ flags[name] = Array.isArray(seen) ? [...seen, value] : seen === void 0 ? value : [String(seen), value];
55017
+ }
54875
55018
  function parseFlags(argv) {
54876
55019
  const _ = [];
54877
55020
  const flags = {};
@@ -54880,13 +55023,13 @@ function parseFlags(argv) {
54880
55023
  if (a.startsWith("--")) {
54881
55024
  const eq = a.indexOf("=");
54882
55025
  if (eq >= 0) {
54883
- flags[a.slice(2, eq)] = a.slice(eq + 1);
55026
+ assign(flags, a.slice(2, eq), a.slice(eq + 1));
54884
55027
  } else {
54885
55028
  const next = argv[i + 1];
54886
55029
  const optionalNativeWithoutValue = a === "--native" && next !== "ios" && next !== "android";
54887
55030
  const booleanOnly = BOOLEAN_FLAGS.has(a.slice(2));
54888
55031
  if (!optionalNativeWithoutValue && !booleanOnly && next !== void 0 && !next.startsWith("--")) {
54889
- flags[a.slice(2)] = next;
55032
+ assign(flags, a.slice(2), next);
54890
55033
  i++;
54891
55034
  } else {
54892
55035
  flags[a.slice(2)] = true;
@@ -55564,6 +55707,34 @@ function trustedConfiguredRegistry(env) {
55564
55707
  const configured = normalizeRegistry(env.npm_config_registry ?? env.NPM_CONFIG_REGISTRY);
55565
55708
  return isTrustedRegistry(configured) ? configured : void 0;
55566
55709
  }
55710
+ function createScopedRegistryResolver(exec = execFileSync7) {
55711
+ let resolved2;
55712
+ return () => {
55713
+ if (resolved2) return resolved2.value;
55714
+ let value;
55715
+ try {
55716
+ const configured = (key2) => {
55717
+ const raw = exec("npm", ["config", "get", key2], {
55718
+ cwd: homedir7(),
55719
+ timeout: 5e3,
55720
+ stdio: ["ignore", "pipe", "ignore"]
55721
+ }).toString().trim();
55722
+ return raw && raw !== "undefined" ? raw : void 0;
55723
+ };
55724
+ const effective = normalizeRegistry(configured("@wix:registry") ?? configured("registry"));
55725
+ value = isTrustedRegistry(effective) ? effective : void 0;
55726
+ } catch {
55727
+ value = void 0;
55728
+ }
55729
+ resolved2 = { value };
55730
+ return value;
55731
+ };
55732
+ }
55733
+ var npmScopedWixRegistry = createScopedRegistryResolver();
55734
+ function registryCandidates(env, scoped) {
55735
+ const ordered = [isTrustedRegistry(scoped) ? normalizeRegistry(scoped) : void 0, trustedConfiguredRegistry(env), PUBLIC_NPM_REGISTRY];
55736
+ return [...new Set(ordered.filter((r) => r !== void 0))];
55737
+ }
55567
55738
  async function fetchPackumentFrom(registry, fetchImpl, timeoutMs) {
55568
55739
  const controller = new AbortController();
55569
55740
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -55584,10 +55755,8 @@ async function fetchPackumentFrom(registry, fetchImpl, timeoutMs) {
55584
55755
  clearTimeout(timer);
55585
55756
  }
55586
55757
  }
55587
- async function fetchCliPackument(fetchImpl = fetch, timeoutMs = DOCTOR_TIMEOUT_MS, env = process.env) {
55588
- const configured = trustedConfiguredRegistry(env);
55589
- const candidates = configured && configured !== PUBLIC_NPM_REGISTRY ? [configured, PUBLIC_NPM_REGISTRY] : [PUBLIC_NPM_REGISTRY];
55590
- for (const registry of candidates) {
55758
+ async function fetchCliPackument(fetchImpl = fetch, timeoutMs = DOCTOR_TIMEOUT_MS, env = process.env, scopedRegistry = npmScopedWixRegistry) {
55759
+ for (const registry of registryCandidates(env, scopedRegistry())) {
55591
55760
  const packument = await fetchPackumentFrom(registry, fetchImpl, timeoutMs);
55592
55761
  if (packument) return packument;
55593
55762
  }
@@ -55626,9 +55795,9 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
55626
55795
  return {};
55627
55796
  }
55628
55797
  }
55629
- async function doctorVersionReport(running, fetchImpl = fetch, sdk = resolvedSdkVersion()) {
55798
+ async function doctorVersionReport(running, fetchImpl = fetch, sdk = resolvedSdkVersion(), scopedRegistry = npmScopedWixRegistry) {
55630
55799
  const minimumSdk = "0.33.0";
55631
- const packument = await fetchCliPackument(fetchImpl);
55800
+ const packument = await fetchCliPackument(fetchImpl, DOCTOR_TIMEOUT_MS, process.env, scopedRegistry);
55632
55801
  const latest = packument?.latest;
55633
55802
  const publishedAt = packument?.time[running];
55634
55803
  const ageDays = ageInDays(publishedAt);
@@ -55889,7 +56058,7 @@ async function maybeSelfUpdate(argv, io, opts = {}) {
55889
56058
  let answeredBy;
55890
56059
  let answeredLatest;
55891
56060
  if (!fresh) {
55892
- const packument = await fetchCliPackument(opts.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env);
56061
+ const packument = await fetchCliPackument(opts.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env, opts.scopedRegistry);
55893
56062
  if (packument) {
55894
56063
  latest = packument.latest;
55895
56064
  runningPublishedAt = packument.time[running];
@@ -55939,7 +56108,7 @@ async function maybeSelfUpdate(argv, io, opts = {}) {
55939
56108
  }
55940
56109
  try {
55941
56110
  if (!answeredBy) {
55942
- const again = await fetchCliPackument(opts.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env);
56111
+ const again = await fetchCliPackument(opts.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env, opts.scopedRegistry);
55943
56112
  answeredBy = again?.registry;
55944
56113
  answeredLatest = again?.latest;
55945
56114
  }
@@ -55996,10 +56165,11 @@ function helpJson() {
55996
56165
  ]
55997
56166
  };
55998
56167
  }
55999
- function previewWebUrl(serveBase, app, release, screenId, surface, previewToken) {
56168
+ function previewWebUrl(serveBase, app, release, screenId, surface, previewToken, handover) {
56000
56169
  const base = serveBase.replace(/\/$/, "");
56001
56170
  const path = screenId ? `/preview/a/${app}/screen/${screenId}` : `/preview/a/${app}`;
56002
- return `${base}${path}?release=${encodeURIComponent(release)}${surface ? `&surface=${encodeURIComponent(surface)}` : ""}${previewToken ? `&pvt=${encodeURIComponent(previewToken)}` : ""}`;
56171
+ const query = handover ? `?h=${encodeURIComponent(handover)}` : `?release=${encodeURIComponent(release)}`;
56172
+ return `${base}${path}${query}${surface ? `&surface=${encodeURIComponent(surface)}` : ""}${!handover && previewToken ? `&pvt=${encodeURIComponent(previewToken)}` : ""}`;
56003
56173
  }
56004
56174
  function renderDeviceWidths() {
56005
56175
  return {
@@ -56064,14 +56234,16 @@ function servesAll(served, asked) {
56064
56234
  return Object.entries(asked).every(([k, v]) => stable(served[k]) === stable(v));
56065
56235
  }
56066
56236
  var GIT_FLAG_STORE_HALF_WRITE_NOTE = "the plane reported a failure, but this store writes flags.json BEFORE it commits \u2014 so the change may already be on the pod that served this request, uncommitted and lost on its next restart. servedNow says what that pod answers now; other pods may differ.";
56237
+ var PREVIEW_HANDOVER_NOTE = "the preview link carries a single-use code, not the bearer itself \u2014 it opens the draft ONCE, and the credential behind it has a limited lifetime this call has no usable expiry for. Run the `previewRenew` command printed beside this note \u2014 from the same plane and credentials as this call (any `--serve-url`/`--control-url`/token flags you passed) \u2014 for a fresh link.";
56067
56238
  var PREVIEW_TOKEN_NOTE = "the preview link carries a bearer with a limited lifetime, and this call has no usable expiry for it \u2014 the plane stated none, or the one it stated is unreadable, already past, or beyond the hour this CLI will reason about. Run the `previewRenew` command printed beside this note \u2014 from the same plane and credentials as this call (any `--serve-url`/`--control-url`/token flags you passed) \u2014 for a fresh one.";
56068
- function previewTokenNote(expiresAt, now = Date.now()) {
56239
+ function previewTokenNote(expiresAt, now = Date.now(), viaHandover = false) {
56240
+ const carrier = viaHandover ? "the preview link carries a single-use code, not the bearer itself" : "the preview link carries a bearer";
56069
56241
  const at = expiresAt ? Date.parse(expiresAt) : NaN;
56070
- if (!Number.isFinite(at)) return PREVIEW_TOKEN_NOTE;
56242
+ if (!Number.isFinite(at)) return viaHandover ? PREVIEW_HANDOVER_NOTE : PREVIEW_TOKEN_NOTE;
56071
56243
  const seconds = (at - now) / 1e3;
56072
- if (seconds <= 0 || seconds > 3600) return PREVIEW_TOKEN_NOTE;
56244
+ if (seconds <= 0 || seconds > 3600) return viaHandover ? PREVIEW_HANDOVER_NOTE : PREVIEW_TOKEN_NOTE;
56073
56245
  const minutes = Math.max(1, Math.round(seconds / 60));
56074
- return `the preview link carries a bearer that expires at ${expiresAt} \u2014 about ${minutes} minute${minutes === 1 ? "" : "s"} from now; run the \`previewRenew\` command printed beside this note \u2014 from the same plane and credentials as this call (any \`--serve-url\`/\`--control-url\`/token flags you passed) \u2014 for a fresh one.`;
56246
+ return `${carrier}, and it expires at ${expiresAt} \u2014 about ${minutes} minute${minutes === 1 ? "" : "s"} from now; run the \`previewRenew\` command printed beside this note \u2014 from the same plane and credentials as this call (any \`--serve-url\`/\`--control-url\`/token flags you passed) \u2014 for a fresh one.`;
56075
56247
  }
56076
56248
  function previewRenewCommand(app, release, target, scope = {}) {
56077
56249
  return `himi preview --app ${app} --release ${release}` + (scope.screen ? ` --screen ${scope.screen}` : "") + (scope.surface ? ` --surface ${scope.surface}` : "") + (target !== "local" ? ` --target ${target}` : "");
@@ -57183,6 +57355,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
57183
57355
  const out = r.json ?? {};
57184
57356
  const release = out.releaseId ?? "";
57185
57357
  const previewToken = out.previewToken;
57358
+ const previewHandover = out.previewHandover;
57186
57359
  const sbase = serveBase();
57187
57360
  const sourceMatchesLocal = opts.localSourceHash === void 0 ? null : opts.localSourceHash === (base.appSourceHash ?? null);
57188
57361
  const honesty = patchHonesty2({ door: opts.door, base, derivedReleaseId: release, sourceMatchesLocal, app });
@@ -57215,7 +57388,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
57215
57388
  ...opts.ux ? uxHandoverOverride(opts.ux.evidence, opts.ux.ctx) : {},
57216
57389
  ...out.visibility ? { visibility: out.visibility } : {},
57217
57390
  ...opts.extra ?? {},
57218
- previewWeb: sbase && release ? previewWebUrl(sbase, app, release, void 0, void 0, previewToken) : null,
57391
+ previewWeb: sbase && release ? previewWebUrl(sbase, app, release, void 0, void 0, previewToken, previewHandover) : null,
57219
57392
  previewTokenExpiresAt: out.previewTokenExpiresAt ?? null,
57220
57393
  previewPlayerDebug: release ? previewPlayerDebugLink(app, release, void 0, previewToken) : null,
57221
57394
  context: sbase && release ? previewContextUrl(sbase, app, release) : null,
@@ -59157,6 +59330,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
59157
59330
  const sourceStored = r.json?.sourceStored;
59158
59331
  const previewToken = draft ? r.json?.previewToken : void 0;
59159
59332
  const previewTokenExpiresAt = draft ? r.json?.previewTokenExpiresAt : void 0;
59333
+ const previewHandover = draft ? r.json?.previewHandover : void 0;
59160
59334
  const functionPreviewToken = r.json?.functionPreviewToken;
59161
59335
  const functionPreviewExpiresAt = r.json?.functionPreviewExpiresAt;
59162
59336
  const effectiveVisibility = r.json?.visibility;
@@ -59224,7 +59398,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
59224
59398
  }),
59225
59399
  ...loopbackWarning ? { warning: loopbackWarning } : {},
59226
59400
  ...report.issues ? { issues: report.issues } : {},
59227
- previewWeb: base ? previewWebUrl(base, app, release, void 0, void 0, previewToken) : null,
59401
+ previewWeb: base ? previewWebUrl(base, app, release, void 0, void 0, previewToken, previewHandover) : null,
59228
59402
  // A timestamp alone leaves the reader to work out both how long they have and how to
59229
59403
  // get another one. Print the duration and the re-mint command beside it (#2502 item 3).
59230
59404
  // No `mintedHere` guard is needed here, unlike `himi preview`: this bearer can only
@@ -59233,7 +59407,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
59233
59407
  ...previewToken ? {
59234
59408
  previewTokenExpiresAt: previewTokenExpiresAt ?? null,
59235
59409
  previewRenew: previewRenewCommand(app, release, targetName()),
59236
- previewTokenNote: previewTokenNote(previewTokenExpiresAt)
59410
+ previewTokenNote: previewTokenNote(previewTokenExpiresAt, Date.now(), previewHandover !== void 0)
59237
59411
  } : {},
59238
59412
  // RFC 0051 — the surfaces THIS RELEASE targets, read from the manifest the
59239
59413
  // push just published (never a re-read of the local file: review found the
@@ -59695,6 +59869,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
59695
59869
  }
59696
59870
  let previewToken = str5(flags["preview-token"]);
59697
59871
  let previewTokenExpiresAt;
59872
+ let previewHandover;
59698
59873
  let mintedHere = false;
59699
59874
  let mintFailure;
59700
59875
  if (!previewToken) {
@@ -59722,6 +59897,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
59722
59897
  const body = minted.json;
59723
59898
  previewToken = typeof body.previewToken === "string" ? body.previewToken : void 0;
59724
59899
  previewTokenExpiresAt = typeof body.previewTokenExpiresAt === "string" ? body.previewTokenExpiresAt : void 0;
59900
+ previewHandover = typeof body.previewHandover === "string" ? body.previewHandover : void 0;
59725
59901
  mintedHere = previewToken !== void 0;
59726
59902
  if (!mintedHere) mintFailure = "the plane answered the mint request without a token \u2014 HIMALAYA_PREVIEW_TOKEN_SECRET may be unconfigured there. Your credential is fine";
59727
59903
  }
@@ -59736,7 +59912,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
59736
59912
  release,
59737
59913
  ...screen ? { screen } : {},
59738
59914
  ...surface ? { surface } : {},
59739
- previewWeb: base ? previewWebUrl(base, app, release, screen, surface, previewToken) : null,
59915
+ previewWeb: base ? previewWebUrl(base, app, release, screen, surface, previewToken, previewHandover) : null,
59740
59916
  // Gated on the MINT, like the two fields below: a plane that returns an expiry but no
59741
59917
  // token would otherwise print a lifetime for a bearer the same envelope says does not
59742
59918
  // exist.
@@ -59751,7 +59927,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
59751
59927
  // in with `--preview-token` is one this command cannot promise to reissue.
59752
59928
  ...mintedHere ? {
59753
59929
  previewRenew: previewRenewCommand(app, release, targetName(), { screen, surface }),
59754
- previewTokenNote: previewTokenNote(previewTokenExpiresAt)
59930
+ previewTokenNote: previewTokenNote(previewTokenExpiresAt, Date.now(), previewHandover !== void 0)
59755
59931
  } : previewToken || !mintFailure ? {} : { previewTokenNote: `no preview bearer was minted \u2014 ${mintFailure}. The link above carries no \`pvt\`, so it opens a LIVE release and will not open a draft.` },
59756
59932
  previewPlayerDebug: previewPlayerDebugLink(app, release, screen, previewToken),
59757
59933
  context: base ? previewContextUrl(base, app, release, screen) : null,
@@ -61435,8 +61611,9 @@ ${label2}`);
61435
61611
  return 1;
61436
61612
  }
61437
61613
  try {
61438
- const answered = await fetchCliPackument(up.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env);
61439
- const registry = answered?.registry ?? trustedConfiguredRegistry(env) ?? PUBLIC_NPM_REGISTRY;
61614
+ const scoped = up.scopedRegistry ?? npmScopedWixRegistry;
61615
+ const answered = await fetchCliPackument(up.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env, scoped);
61616
+ const registry = answered?.registry ?? registryCandidates(env, scoped())[0];
61440
61617
  if (answered?.latest && compareVersions2(answered.latest, before) <= 0) {
61441
61618
  if (flags.json) print({ ok: true, running: before, installed: before, changed: false, registry, latest: answered.latest });
61442
61619
  else io.log(`himi ${before} (unchanged \u2014 ${registry} has nothing newer; its latest is ${answered.latest})`);
@@ -61918,6 +62095,7 @@ export {
61918
62095
  GIT_FLAG_STORE_NOTE,
61919
62096
  PLACEHOLDER_CLIENT_ID,
61920
62097
  PLACEHOLDER_SITE_URL,
62098
+ PREVIEW_HANDOVER_NOTE,
61921
62099
  PREVIEW_TOKEN_NOTE,
61922
62100
  PUBLIC_NPM_REGISTRY,
61923
62101
  PUBLIC_WIX_API_BASE,
@@ -61927,6 +62105,7 @@ export {
61927
62105
  autoClaimSlug,
61928
62106
  buildDoctorReport,
61929
62107
  compareVersions2 as compareVersions,
62108
+ createScopedRegistryResolver,
61930
62109
  createUpdateRunner,
61931
62110
  credentialKind,
61932
62111
  credentialSwapNotice,
@@ -61942,6 +62121,7 @@ export {
61942
62121
  formatSdkVersionLine,
61943
62122
  formatStaleLine,
61944
62123
  globalPrefixWritable,
62124
+ handoverUxEvidence,
61945
62125
  humanDuration,
61946
62126
  inspectControlToken,
61947
62127
  isHimalayaMonorepoCheckout,
@@ -61956,6 +62136,7 @@ export {
61956
62136
  nativeConfigAdvisories,
61957
62137
  nativeConfigTokenNotice,
61958
62138
  npmInstallArgs,
62139
+ npmScopedWixRegistry,
61959
62140
  ownerPlaneHint,
61960
62141
  ownerPlaneIsDark,
61961
62142
  parseFlags,
@@ -61976,6 +62157,7 @@ export {
61976
62157
  probeReachable,
61977
62158
  pushAuthHint,
61978
62159
  readUpdateCache,
62160
+ registryCandidates,
61979
62161
  renderDataSource,
61980
62162
  renderDeviceWidths,
61981
62163
  resolveAppSlug,