@wix/himalaya-cli 0.995.0 → 0.996.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
@@ -5304,8 +5304,11 @@ function walk(node, registry, path, out) {
5304
5304
  walk(value, registry, `${path}.${key2}`, out);
5305
5305
  }
5306
5306
  }
5307
+ var SYSTEM_FONT_FAMILY;
5307
5308
  var init_tokens = __esm({
5308
5309
  "../../core/ts/src/tokens.ts"() {
5310
+ "use strict";
5311
+ SYSTEM_FONT_FAMILY = "$system";
5309
5312
  }
5310
5313
  });
5311
5314
 
@@ -11851,6 +11854,11 @@ import { fileURLToPath as fileURLToPath8 } from "node:url";
11851
11854
  import { join as join20 } from "node:path";
11852
11855
  function loadCatalog() {
11853
11856
  if (cached) return cached;
11857
+ const override = process.env.HIMI_FONTS_CATALOG;
11858
+ if (override) {
11859
+ cached = JSON.parse(readFileSync17(override, "utf8"));
11860
+ return cached;
11861
+ }
11854
11862
  const path = CATALOG_CANDIDATES.find((p) => existsSync17(p));
11855
11863
  if (!path) {
11856
11864
  throw new Error(
@@ -11876,6 +11884,10 @@ function findFamily(name, catalog = loadCatalog()) {
11876
11884
  if (!canonical3) return void 0;
11877
11885
  return catalog.families[canonical3] ?? catalog.bundled[canonical3];
11878
11886
  }
11887
+ function canonicalFamilyName(name, catalog = loadCatalog()) {
11888
+ if (catalog.families[name] ?? catalog.bundled[name] ?? catalog.system[name]) return name;
11889
+ return familyIndex(catalog).get(normalizeFamily(name));
11890
+ }
11879
11891
  function isSystemFamily(name, catalog = loadCatalog()) {
11880
11892
  return catalog.system[name] !== void 0;
11881
11893
  }
@@ -11930,7 +11942,7 @@ var init_catalog = __esm({
11930
11942
  function demandFromTokens(tokens) {
11931
11943
  const demand = /* @__PURE__ */ new Map();
11932
11944
  const add = (family, weight) => {
11933
- if (typeof family !== "string" || family.length === 0) return;
11945
+ if (typeof family !== "string" || family.length === 0 || family === SYSTEM_FONT_FAMILY) return;
11934
11946
  demand.set(family, (demand.get(family) ?? /* @__PURE__ */ new Set()).add(typeof weight === "number" ? weight : 400));
11935
11947
  };
11936
11948
  const base = tokens.typography ?? {};
@@ -11950,11 +11962,11 @@ function planFonts(tokens, policy = {}, catalog = loadCatalog()) {
11950
11962
  return new Set(fam ? fam.faces.map((f) => f.weight) : [400]);
11951
11963
  };
11952
11964
  for (const family of policy.families ?? []) {
11953
- if (demand.has(family)) continue;
11965
+ if (demand.has(family) || family === SYSTEM_FONT_FAMILY) continue;
11954
11966
  demand.set(family, allWeights(family));
11955
11967
  }
11956
11968
  for (const family of policy.otaOnly ?? []) {
11957
- if (demand.has(family)) continue;
11969
+ if (demand.has(family) || family === SYSTEM_FONT_FAMILY) continue;
11958
11970
  demand.set(family, allWeights(family));
11959
11971
  }
11960
11972
  for (const family of TIER1_FLOOR) if (!demand.has(family)) demand.set(family, allWeights(family));
@@ -12021,13 +12033,14 @@ var TIER1_FLOOR;
12021
12033
  var init_plan_fonts = __esm({
12022
12034
  "../font-bake/plan-fonts.ts"() {
12023
12035
  init_catalog();
12036
+ init_tokens();
12024
12037
  TIER1_FLOOR = ["Wix Madefor Text"];
12025
12038
  }
12026
12039
  });
12027
12040
 
12028
12041
  // ../font-bake/face-source.ts
12029
12042
  import { createHash as createHash6 } from "node:crypto";
12030
- import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
12043
+ import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync18, renameSync, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
12031
12044
  import { homedir as homedir3 } from "node:os";
12032
12045
  import { basename as basename6, join as join21 } from "node:path";
12033
12046
  import { fileURLToPath as fileURLToPath9 } from "node:url";
@@ -12043,12 +12056,563 @@ function faceSource(file, sha2565) {
12043
12056
  if (existsSync18(cached3)) return cached3;
12044
12057
  return null;
12045
12058
  }
12046
- var REPO_ROOT5, VENDORED_DIR, CACHE_DIR;
12059
+ function upstreamFaceUrl(ref, dir, file) {
12060
+ return `${RAW}/google/fonts/${ref}/${dir}/${encodeURIComponent(file)}`;
12061
+ }
12062
+ function faceUpstream(sha2565, catalog = loadCatalog()) {
12063
+ for (const [name, fam] of Object.entries(catalog.families)) {
12064
+ if (!fam.dir || !UPSTREAM_DIR.test(fam.dir)) continue;
12065
+ const face = fam.faces.find((f) => f.sha256 === sha2565);
12066
+ if (face) return { family: name, url: upstreamFaceUrl(catalog.source.ref, fam.dir, face.file) };
12067
+ }
12068
+ return null;
12069
+ }
12070
+ async function fetchUpstreamBytes(url) {
12071
+ const res = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
12072
+ if (!res.ok) throw new Error(`GET ${url} -> ${res.status} ${res.statusText}`);
12073
+ return new Uint8Array(await res.arrayBuffer());
12074
+ }
12075
+ function writeCachedFace(bytes2) {
12076
+ const hash = sha256Hex2(bytes2);
12077
+ mkdirSync9(CACHE_DIR, { recursive: true });
12078
+ const tmp = join21(CACHE_DIR, `.${hash}.${process.pid}.${Date.now()}.tmp`);
12079
+ try {
12080
+ writeFileSync8(tmp, bytes2);
12081
+ renameSync(tmp, join21(CACHE_DIR, hash));
12082
+ } catch (err) {
12083
+ rmSync3(tmp, { force: true });
12084
+ throw err;
12085
+ }
12086
+ return hash;
12087
+ }
12088
+ async function ensureFaceBytes(face, opts = {}) {
12089
+ const local = faceSource(face.file, face.sha256);
12090
+ if (local) {
12091
+ const bytes2 = readFileSync18(local);
12092
+ if (local !== join21(CACHE_DIR, face.sha256) || sha256Hex2(bytes2) === face.sha256) {
12093
+ return { ok: true, bytes: bytes2, from: "local" };
12094
+ }
12095
+ }
12096
+ const upstream = faceUpstream(face.sha256, opts.catalog);
12097
+ if (!upstream) {
12098
+ return { ok: false, reason: `${face.file} has no upstream in the font catalog \u2014 its bytes ship only in the vendored tree` };
12099
+ }
12100
+ const fetcher = opts.fetchFace ?? fetchUpstreamBytes;
12101
+ let memo = recentFetches.get(fetcher);
12102
+ if (!memo) recentFetches.set(fetcher, memo = /* @__PURE__ */ new Map());
12103
+ const recent = memo.get(face.sha256);
12104
+ if (recent && Date.now() - recent.at < FAILURE_MEMO_MS) return recent.result;
12105
+ const result = fetchVerifyAndCache(upstream.url, face.sha256, fetcher);
12106
+ memo.set(face.sha256, { at: Date.now(), result });
12107
+ void result.then((r) => {
12108
+ if (r.ok) memo.delete(face.sha256);
12109
+ });
12110
+ return result;
12111
+ }
12112
+ async function fetchVerifyAndCache(url, sha2565, fetcher) {
12113
+ let bytes2;
12114
+ try {
12115
+ bytes2 = Buffer.from(await fetcher(url));
12116
+ } catch (err) {
12117
+ return { ok: false, reason: `fetching ${url} failed: ${err.message}` };
12118
+ }
12119
+ const got = sha256Hex2(bytes2);
12120
+ if (got !== sha2565) {
12121
+ return {
12122
+ ok: false,
12123
+ reason: `${url} returned bytes hashing to ${got.slice(0, 12)}\u2026, but the catalog pins ${sha2565.slice(0, 12)}\u2026 \u2014 refused`
12124
+ };
12125
+ }
12126
+ try {
12127
+ writeCachedFace(bytes2);
12128
+ } catch {
12129
+ }
12130
+ return { ok: true, bytes: bytes2, from: "fetched" };
12131
+ }
12132
+ function isHostProvided(familyName, catalog = loadCatalog()) {
12133
+ return catalog.bundled[canonicalFamilyName(familyName, catalog) ?? familyName] !== void 0;
12134
+ }
12135
+ async function offRepoFontBytes(plan, opts = {}) {
12136
+ const catalog = opts.catalog ?? loadCatalog();
12137
+ const out = { ready: [], hostProvided: [], unavailable: [] };
12138
+ const families = plan.families.filter((f) => !f.builtin);
12139
+ const resolved2 = await Promise.all(
12140
+ families.map(async (family) => {
12141
+ if (isHostProvided(family.name, catalog)) return { family, hostProvided: true };
12142
+ const faces = await Promise.all(
12143
+ family.faces.map(async (face) => ({ face, got: await ensureFaceBytes(face, { ...opts, catalog }) }))
12144
+ );
12145
+ return { family, faces };
12146
+ })
12147
+ );
12148
+ for (const r of resolved2) {
12149
+ if ("hostProvided" in r) {
12150
+ out.hostProvided.push(r.family);
12151
+ continue;
12152
+ }
12153
+ const failed = r.faces.find((f) => !f.got.ok);
12154
+ if (failed && !failed.got.ok) {
12155
+ out.unavailable.push({ family: r.family, reason: failed.got.reason });
12156
+ continue;
12157
+ }
12158
+ out.ready.push({
12159
+ family: r.family,
12160
+ faces: r.faces.map(({ face, got }) => ({ face, bytes: got.bytes }))
12161
+ });
12162
+ }
12163
+ return out;
12164
+ }
12165
+ async function catalogFaceBytes(sha2565, opts = {}) {
12166
+ const catalog = opts.catalog ?? loadCatalog();
12167
+ for (const family of [...Object.values(catalog.families), ...Object.values(catalog.bundled)]) {
12168
+ const face = family.faces.find((f) => f.sha256 === sha2565);
12169
+ if (!face) continue;
12170
+ if (hasVendoredFloor()) {
12171
+ const local = faceSource(face.file, face.sha256);
12172
+ return local ? readFileSync18(local) : void 0;
12173
+ }
12174
+ const got = await ensureFaceBytes(face, { ...opts, catalog });
12175
+ return got.ok ? got.bytes : void 0;
12176
+ }
12177
+ return void 0;
12178
+ }
12179
+ var REPO_ROOT5, VENDORED_DIR, CACHE_DIR, sha256Hex2, RAW, UPSTREAM_DIR, FETCH_TIMEOUT_MS, FAILURE_MEMO_MS, recentFetches;
12047
12180
  var init_face_source = __esm({
12048
12181
  "../font-bake/face-source.ts"() {
12182
+ init_catalog();
12049
12183
  REPO_ROOT5 = fileURLToPath9(new URL("../..", import.meta.url));
12050
12184
  VENDORED_DIR = process.env.HIMI_FONTS_VENDORED_DIR || join21(REPO_ROOT5, "stdlib", "fonts", "vendored", "wix-madefor");
12051
12185
  CACHE_DIR = join21(process.env.XDG_CACHE_HOME || join21(homedir3(), ".cache"), "himi", "fonts");
12186
+ sha256Hex2 = (bytes2) => createHash6("sha256").update(bytes2).digest("hex");
12187
+ RAW = ["https://", "raw.", "githubuser", "content.com"].join("");
12188
+ UPSTREAM_DIR = /^(ofl|apache|ufl)\/[a-z0-9_-]+$/;
12189
+ FETCH_TIMEOUT_MS = 2e4;
12190
+ FAILURE_MEMO_MS = 6e4;
12191
+ recentFetches = /* @__PURE__ */ new WeakMap();
12192
+ }
12193
+ });
12194
+
12195
+ // ../../core/ts/src/idiom.ts
12196
+ function authored(overlays, name) {
12197
+ return typeof name === "string" && overlays !== void 0 && Object.hasOwn(overlays, name) && overlays[name] !== null && typeof overlays[name] === "object" && !Array.isArray(overlays[name]);
12198
+ }
12199
+ function selectIdiomOverlay(doc, ctx = {}) {
12200
+ const policy = doc.idiomPolicy;
12201
+ const overlays = doc.idiom;
12202
+ const isRecord3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
12203
+ if (!isRecord3(policy) || !isRecord3(overlays)) return void 0;
12204
+ const kind = policy.policy ?? "follow-surface";
12205
+ if (kind === "none") return void 0;
12206
+ if (kind === "pinned") return authored(overlays, policy.pin) ? policy.pin : void 0;
12207
+ if (kind !== "follow-surface") return void 0;
12208
+ const surfaces = policy.surfaces;
12209
+ const candidates = [
12210
+ ctx.surface !== void 0 && isRecord3(surfaces) && Object.hasOwn(surfaces, ctx.surface) ? surfaces[ctx.surface] : void 0,
12211
+ ...ctx.native ?? [],
12212
+ policy.fallback
12213
+ ];
12214
+ return candidates.find((c) => authored(overlays, c));
12215
+ }
12216
+ function isPlainObject(v) {
12217
+ return v !== null && typeof v === "object" && !Array.isArray(v);
12218
+ }
12219
+ function deepMerge(base, overlay) {
12220
+ if (!isPlainObject(overlay) || !isPlainObject(base)) return overlay;
12221
+ const out = { ...base };
12222
+ for (const [key2, value] of Object.entries(overlay)) {
12223
+ if (UNSAFE_KEYS.has(key2)) continue;
12224
+ out[key2] = Object.hasOwn(base, key2) ? deepMerge(base[key2], value) : value;
12225
+ }
12226
+ return out;
12227
+ }
12228
+ function mergeIdiomOverlay(base, overlay) {
12229
+ const merged = deepMerge(base, overlay);
12230
+ const baseColors = base.colors;
12231
+ const overlayColors = overlay.colors;
12232
+ if (isPlainObject(baseColors) && isPlainObject(overlayColors)) {
12233
+ const colors = { ...merged.colors };
12234
+ for (const [name, value] of Object.entries(overlayColors)) {
12235
+ if (UNSAFE_KEYS.has(name)) continue;
12236
+ const was = Object.hasOwn(baseColors, name) ? baseColors[name] : void 0;
12237
+ if (typeof was === "string" && isPlainObject(value)) colors[name] = { light: was, ...value };
12238
+ }
12239
+ merged.colors = colors;
12240
+ }
12241
+ return merged;
12242
+ }
12243
+ function resolveIdiom(tokens, ctx = {}) {
12244
+ const doc = tokens;
12245
+ const name = selectIdiomOverlay(doc, ctx);
12246
+ if (name === void 0) return tokens;
12247
+ const merged = mergeIdiomOverlay(tokens, doc.idiom[name]);
12248
+ const { idiomPolicy: _applied, ...final } = merged;
12249
+ return final;
12250
+ }
12251
+ var UNSAFE_KEYS;
12252
+ var init_idiom = __esm({
12253
+ "../../core/ts/src/idiom.ts"() {
12254
+ "use strict";
12255
+ UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
12256
+ }
12257
+ });
12258
+
12259
+ // ../../core/web-renderer/src/tokens.ts
12260
+ function isSerifFamily(family) {
12261
+ return !!family && SERIF_FAMILY_RE.test(family);
12262
+ }
12263
+ function fontStack(family) {
12264
+ if (!family) return DEFAULT_FONT_STACK;
12265
+ if (family === SYSTEM_FONT_FAMILY) return SYSTEM_FONT_STACK;
12266
+ if (isSerifFamily(family)) return `"${family}", serif`;
12267
+ return `"${family}", ${DEFAULT_FONT_STACK}`;
12268
+ }
12269
+ function clamp(n, lo = 0, hi = 1) {
12270
+ return Math.max(lo, Math.min(hi, n));
12271
+ }
12272
+ function hexToRgb2(hex2) {
12273
+ let h = hex2.trim().replace(/^#/, "");
12274
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
12275
+ if (!/^[\da-f]{6}$/i.test(h)) return null;
12276
+ const int = parseInt(h, 16);
12277
+ return [int >> 16 & 255, int >> 8 & 255, int & 255];
12278
+ }
12279
+ function rgba(color, alpha2) {
12280
+ const rgb = hexToRgb2(color);
12281
+ return rgb ? `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${clamp(alpha2)})` : color;
12282
+ }
12283
+ function normalizeSpring(spring, durationMs) {
12284
+ return {
12285
+ response: clampTo(finite(spring.response) ?? durationMs / 1e3, SPRING_MIN_RESPONSE, SPRING_MAX_RESPONSE),
12286
+ dampingFraction: clampTo(finite(spring.dampingFraction) ?? 0.8, SPRING_MIN_DAMPING, SPRING_MAX_DAMPING)
12287
+ };
12288
+ }
12289
+ function springStep(response, zeta) {
12290
+ const w0 = 2 * Math.PI / response;
12291
+ if (zeta < 1) {
12292
+ const wd = w0 * Math.sqrt(1 - zeta * zeta);
12293
+ return (t) => 1 - Math.exp(-zeta * w0 * t) * (Math.cos(wd * t) + zeta * w0 / wd * Math.sin(wd * t));
12294
+ }
12295
+ if (zeta === 1) return (t) => 1 - Math.exp(-w0 * t) * (1 + w0 * t);
12296
+ const root = Math.sqrt(zeta * zeta - 1);
12297
+ const r1 = -w0 * (zeta - root), r2 = -w0 * (zeta + root);
12298
+ return (t) => 1 - (r2 * Math.exp(r1 * t) - r1 * Math.exp(r2 * t)) / (r2 - r1);
12299
+ }
12300
+ function springCurve(spring, durationMs) {
12301
+ const { response, dampingFraction: zeta } = normalizeSpring(spring, durationMs);
12302
+ const key2 = `${response}|${zeta}`;
12303
+ const cached3 = springCurves.get(key2);
12304
+ if (cached3) return cached3;
12305
+ const x = springStep(response, zeta);
12306
+ const step = response / 64;
12307
+ let settle = 0;
12308
+ for (let t = 0; t <= SPRING_MAX_SECS; t += step) if (Math.abs(1 - x(t)) > SPRING_SETTLE_TOLERANCE) settle = t;
12309
+ const secs = Math.min(settle + step, SPRING_MAX_SECS);
12310
+ const samples = Math.min(200, Math.max(24, Math.ceil(12 * secs / response)));
12311
+ const points = [];
12312
+ for (let i = 0; i <= samples; i++) points.push(i === 0 ? 0 : i === samples ? 1 : Number(x(secs * i / samples).toFixed(3)));
12313
+ const curve = { durationMs: Math.round(secs * 1e3), easing: `linear(${points.join(", ")})` };
12314
+ springCurves.set(key2, curve);
12315
+ return curve;
12316
+ }
12317
+ function linearEasingSupported() {
12318
+ const css = globalThis.CSS;
12319
+ return typeof css?.supports === "function" && css.supports("animation-timing-function", "linear(0, 1)");
12320
+ }
12321
+ function easingCss(e) {
12322
+ switch (e) {
12323
+ case "linear":
12324
+ return "linear";
12325
+ case "easeIn":
12326
+ return "cubic-bezier(0.4,0,1,1)";
12327
+ case "easeOut":
12328
+ return "cubic-bezier(0,0,0.2,1)";
12329
+ case "spring":
12330
+ return "cubic-bezier(0.34,1.56,0.64,1)";
12331
+ // Material 3's emphasized easing (#2930).
12332
+ case "emphasized":
12333
+ return "cubic-bezier(0.2,0,0,1)";
12334
+ default:
12335
+ return "cubic-bezier(0.4,0,0.2,1)";
12336
+ }
12337
+ }
12338
+ function motionCss(m) {
12339
+ if (m.easing === "spring" && m.spring && linearEasingSupported()) return springCurve(m.spring, m.duration);
12340
+ return { durationMs: m.duration, easing: easingCss(m.easing) };
12341
+ }
12342
+ function hexToHsl(hex2) {
12343
+ const m = /^#?([\da-f]{6})$/i.exec(hex2.trim());
12344
+ if (!m) return null;
12345
+ const int = parseInt(m[1], 16);
12346
+ const r = (int >> 16 & 255) / 255, g = (int >> 8 & 255) / 255, b = (int & 255) / 255;
12347
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
12348
+ let h = 0, s = 0;
12349
+ const l = (max + min) / 2;
12350
+ if (max !== min) {
12351
+ const d = max - min;
12352
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
12353
+ if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
12354
+ else if (max === g) h = (b - r) / d + 2;
12355
+ else h = (r - g) / d + 4;
12356
+ h /= 6;
12357
+ }
12358
+ return [h, s, l];
12359
+ }
12360
+ function hslToHex(h, s, l) {
12361
+ const hue = (p, q, t) => {
12362
+ if (t < 0) t += 1;
12363
+ if (t > 1) t -= 1;
12364
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
12365
+ if (t < 1 / 2) return q;
12366
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
12367
+ return p;
12368
+ };
12369
+ let r, g, b;
12370
+ if (s === 0) {
12371
+ r = g = b = l;
12372
+ } else {
12373
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
12374
+ const p = 2 * l - q;
12375
+ r = hue(p, q, h + 1 / 3);
12376
+ g = hue(p, q, h);
12377
+ b = hue(p, q, h - 1 / 3);
12378
+ }
12379
+ const to = (x) => Math.round(clamp(x) * 255).toString(16).padStart(2, "0");
12380
+ return `#${to(r)}${to(g)}${to(b)}`;
12381
+ }
12382
+ function roleOf(name) {
12383
+ const n = name.toLowerCase();
12384
+ if (n.startsWith("surface") || n.includes("background") || n.includes("canvas")) return "surface";
12385
+ if (n.startsWith("text") || n.startsWith("on")) return "text";
12386
+ if (n.includes("border") || n.includes("divider") || n.includes("separator")) return "border";
12387
+ if (n.includes("accent") || n.includes("primary") || n.includes("link")) return "accent";
12388
+ return "other";
12389
+ }
12390
+ function synthScheme(hex2, name, scheme) {
12391
+ if (scheme === "light") return hex2;
12392
+ const hsl = hexToHsl(hex2);
12393
+ if (!hsl) return hex2;
12394
+ const [h, s, l] = hsl;
12395
+ const role = roleOf(name);
12396
+ if (scheme === "dark") {
12397
+ switch (role) {
12398
+ case "surface":
12399
+ return hslToHex(h, clamp(s * 0.6), clamp(0.07 + (1 - l) * 0.12, 0.06, 0.22));
12400
+ case "text":
12401
+ return hslToHex(h, clamp(s * 0.5), clamp(0.97 - l * 0.25, 0.7, 0.97));
12402
+ case "border":
12403
+ return hslToHex(h, clamp(s * 0.5), clamp(0.18 + (1 - l) * 0.12, 0.18, 0.34));
12404
+ case "accent":
12405
+ return hslToHex(h, s, clamp(l + 0.1, 0, 0.72));
12406
+ default:
12407
+ return hslToHex(h, s, clamp(l + 0.06));
12408
+ }
12409
+ }
12410
+ switch (role) {
12411
+ case "surface":
12412
+ return l > 0.5 ? "#FFFFFF" : "#000000";
12413
+ case "text":
12414
+ return l > 0.5 ? "#FFFFFF" : "#000000";
12415
+ case "border":
12416
+ return "#000000";
12417
+ case "accent":
12418
+ return hslToHex(h, clamp(s + 0.2), clamp(l - 0.18, 0.18, 0.5));
12419
+ default:
12420
+ return hex2;
12421
+ }
12422
+ }
12423
+ function resolveSchemeColor(o, scheme) {
12424
+ const exact = o?.[scheme];
12425
+ if (typeof exact === "string") return exact;
12426
+ if (scheme === "highContrast" && typeof o?.dark === "string") return o.dark;
12427
+ if (typeof o?.light === "string") return o.light;
12428
+ return typeof o?.dark === "string" ? o.dark : void 0;
12429
+ }
12430
+ function makeTokenResolvers(source, scheme, idiom = WEB_IDIOM_CONTEXT) {
12431
+ const tokens = resolveIdiom(source, idiom);
12432
+ const color = (name, fallback = "#1a1a1a") => {
12433
+ if (name == null) return fallback;
12434
+ if (typeof name !== "string") {
12435
+ const o = name;
12436
+ const direct = resolveSchemeColor(o, scheme);
12437
+ if (typeof direct === "string") return direct;
12438
+ if (typeof o?.token === "string") return color(o.token, fallback);
12439
+ if (typeof o?.name === "string") return color(o.name, fallback);
12440
+ return fallback;
12441
+ }
12442
+ if (name.startsWith("#")) return name;
12443
+ const v = tokens.colors?.[name];
12444
+ if (v == null) return fallback;
12445
+ if (typeof v === "object") {
12446
+ const direct = resolveSchemeColor(v, scheme);
12447
+ return typeof direct === "string" ? direct : fallback;
12448
+ }
12449
+ return synthScheme(v, name, scheme);
12450
+ };
12451
+ const font = (style = "body") => {
12452
+ const t = tokens.typography?.[style] ?? tokens.fonts?.[style] ?? tokens.typography?.body ?? tokens.fonts?.body;
12453
+ const size = t?.size ?? 14;
12454
+ return {
12455
+ size,
12456
+ remSize: pxToRem(size),
12457
+ weight: t?.weight ?? 400,
12458
+ line: t?.line ?? 1.4,
12459
+ family: t?.family,
12460
+ letterSpacing: t?.letterSpacing
12461
+ };
12462
+ };
12463
+ const radius = (name, fallback = 0) => {
12464
+ if (typeof name === "number") return name;
12465
+ if (typeof name === "string") return tokens.radius?.[name] ?? fallback;
12466
+ return fallback;
12467
+ };
12468
+ const sp = (n) => typeof n === "number" ? n : 0;
12469
+ const shadow = (name) => {
12470
+ const key2 = typeof name === "string" ? name : name?.token ?? name?.name;
12471
+ if (!key2) return void 0;
12472
+ const v = tokens.shadows?.[key2];
12473
+ if (v == null) return void 0;
12474
+ if (typeof v === "string") return v;
12475
+ const x = v.x ?? 0, y = v.y ?? 0;
12476
+ return `${x}px ${y}px ${v.radius}px ${rgba(v.color ?? "#000000", v.opacity)}`;
12477
+ };
12478
+ const gradient = (name) => {
12479
+ const key2 = typeof name === "string" ? name : name?.token;
12480
+ if (!key2) return void 0;
12481
+ const v = tokens.gradients?.[key2];
12482
+ if (v == null) return void 0;
12483
+ if (typeof v === "string") return v;
12484
+ const stops = v.colors.map((c, i) => {
12485
+ const at = v.locations?.[i];
12486
+ return `${color(c)}${at != null ? ` ${Math.round(at * 100)}%` : ""}`;
12487
+ });
12488
+ return `linear-gradient(${v.angle ?? 0}deg, ${stops.join(", ")})`;
12489
+ };
12490
+ const meshGradient = (name) => {
12491
+ const key2 = typeof name === "string" ? name : name?.token;
12492
+ if (!key2) return void 0;
12493
+ const v = tokens.gradients?.[key2];
12494
+ if (v == null || typeof v === "string") return void 0;
12495
+ const cols = v.colors.map((c) => color(c));
12496
+ if (cols.length === 0) return void 0;
12497
+ const pts = [[18, 22], [82, 18], [25, 82], [78, 80], [50, 45], [10, 55], [90, 60]];
12498
+ const blobs = cols.map((c, i) => {
12499
+ const [x, y] = pts[i % pts.length];
12500
+ return `radial-gradient(circle at ${x}% ${y}%, ${c} 0%, transparent 55%)`;
12501
+ });
12502
+ return `${blobs.join(", ")}, ${cols[cols.length - 1]}`;
12503
+ };
12504
+ const material = (name) => {
12505
+ const key2 = typeof name === "string" ? name : name?.token ?? name?.name;
12506
+ if (!key2) return void 0;
12507
+ const v = tokens.materials?.[key2];
12508
+ if (v == null) return void 0;
12509
+ if (!("style" in v)) return { background: v.background, backdropFilter: v.backdropFilter };
12510
+ const m = v;
12511
+ const tint = m.tint ? color(m.tint, "#000000") : void 0;
12512
+ if (m.style === "glass" || m.style === "frosted") {
12513
+ return {
12514
+ background: tint ? rgba(tint, m.opacity ?? 0.6) : void 0,
12515
+ backdropFilter: `blur(${m.blur ?? 20}px) saturate(180%)`
12516
+ };
12517
+ }
12518
+ return tint ? { background: rgba(tint, m.opacity ?? 1) } : void 0;
12519
+ };
12520
+ const densityScale = (density) => {
12521
+ switch (density) {
12522
+ case "compact":
12523
+ return 0.75;
12524
+ case "spacious":
12525
+ return 1.25;
12526
+ default:
12527
+ return 1;
12528
+ }
12529
+ };
12530
+ const motionTransition = (motion) => {
12531
+ switch (motion) {
12532
+ case "crisp":
12533
+ return "all 120ms cubic-bezier(0.2,0,0,1)";
12534
+ case "bouncy":
12535
+ return "all 320ms cubic-bezier(0.34,1.56,0.64,1)";
12536
+ default:
12537
+ return "all 240ms cubic-bezier(0.4,0,0.2,1)";
12538
+ }
12539
+ };
12540
+ const appearMotion = (name) => {
12541
+ if (!name) return void 0;
12542
+ const m = tokens.motions?.[name];
12543
+ if (!m) return void 0;
12544
+ return motionCss(m);
12545
+ };
12546
+ const reduceMotion = () => {
12547
+ const policy = tokens.kit?.reduceMotion ?? "system";
12548
+ if (policy === "always") return true;
12549
+ if (policy === "never") return false;
12550
+ return typeof globalThis !== "undefined" && typeof globalThis.matchMedia === "function" && globalThis.matchMedia("(prefers-reduced-motion: reduce)").matches;
12551
+ };
12552
+ return {
12553
+ color,
12554
+ font,
12555
+ radius,
12556
+ sp,
12557
+ shadow,
12558
+ gradient,
12559
+ meshGradient,
12560
+ material,
12561
+ densityScale,
12562
+ motionTransition,
12563
+ appearMotion,
12564
+ reduceMotion,
12565
+ kit: tokens.kit ?? {},
12566
+ tokens,
12567
+ scheme
12568
+ };
12569
+ }
12570
+ var REM_ROOT_PX, pxToRem, DEFAULT_FONT_STACK, SYSTEM_FONT_STACK, SERIF_FAMILY_RE, SPRING_MIN_RESPONSE, SPRING_MAX_RESPONSE, SPRING_MIN_DAMPING, SPRING_MAX_DAMPING, clampTo, finite, SPRING_SETTLE_TOLERANCE, SPRING_MAX_SECS, springCurves, WEB_IDIOM_CONTEXT;
12571
+ var init_tokens2 = __esm({
12572
+ "../../core/web-renderer/src/tokens.ts"() {
12573
+ init_idiom();
12574
+ init_tokens();
12575
+ REM_ROOT_PX = 16;
12576
+ pxToRem = (px) => `${px / REM_ROOT_PX}rem`;
12577
+ DEFAULT_FONT_STACK = '"Wix Madefor Text", system-ui';
12578
+ SYSTEM_FONT_STACK = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
12579
+ SERIF_FAMILY_RE = /\b(georgia|times|garamond|palatino|baskerville|didot|charter|bodoni|caslon|cambria|constantia|rockwell|playfair|merriweather|lora|literata|spectral|serif)\b/i;
12580
+ SPRING_MIN_RESPONSE = 0.05;
12581
+ SPRING_MAX_RESPONSE = 10;
12582
+ SPRING_MIN_DAMPING = 0.1;
12583
+ SPRING_MAX_DAMPING = 4;
12584
+ clampTo = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
12585
+ finite = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
12586
+ SPRING_SETTLE_TOLERANCE = 1e-3;
12587
+ SPRING_MAX_SECS = 10;
12588
+ springCurves = /* @__PURE__ */ new Map();
12589
+ WEB_IDIOM_CONTEXT = { surface: "desktop" };
12590
+ }
12591
+ });
12592
+
12593
+ // ../font-bake/web-fallback.ts
12594
+ function webRenderedFallback(family) {
12595
+ const stack = fontStack(family);
12596
+ const own2 = `"${family}", `;
12597
+ const tail = stack.startsWith(own2) ? stack.slice(own2.length) : stack;
12598
+ return tail.split(",")[0].trim().replace(/^"(.*)"$/, "$1");
12599
+ }
12600
+ var init_web_fallback = __esm({
12601
+ "../font-bake/web-fallback.ts"() {
12602
+ init_tokens2();
12603
+ }
12604
+ });
12605
+
12606
+ // src/shell-quote.ts
12607
+ var shell_quote_exports = {};
12608
+ __export(shell_quote_exports, {
12609
+ shellQuote: () => shellQuote
12610
+ });
12611
+ function shellQuote(arg) {
12612
+ return /^[A-Za-z0-9_./:@=-]+$/.test(arg) ? arg : `'${arg.replace(/'/g, `'\\''`)}'`;
12613
+ }
12614
+ var init_shell_quote = __esm({
12615
+ "src/shell-quote.ts"() {
12052
12616
  }
12053
12617
  });
12054
12618
 
@@ -12093,7 +12657,7 @@ function listReport(opts = {}) {
12093
12657
  }
12094
12658
  return { ok: true, count: families.length, totalBytes, families };
12095
12659
  }
12096
- function fontFindings(appDir2) {
12660
+ async function fontFindings(appDir2, opts = {}) {
12097
12661
  const tokensPath = join22(appDir2, configuredTokensPath(appDir2).path ?? "tokens.json");
12098
12662
  if (!existsSync19(tokensPath)) return null;
12099
12663
  const catalog = loadCatalog();
@@ -12107,7 +12671,28 @@ function fontFindings(appDir2) {
12107
12671
  message: `"${family}" is not in the catalog \u2014 it will render as the system font. Add it to stdlib/fonts/catalog.source.json and run \`npm run fonts:catalog\`, or pick one from \`himi fonts list\`.`
12108
12672
  });
12109
12673
  }
12110
- if (hasVendoredFloor()) {
12674
+ let offRepo;
12675
+ if (!hasVendoredFloor()) {
12676
+ const bytes2 = await offRepoFontBytes(plan, { ...opts.fetchFace ? { fetchFace: opts.fetchFace } : {}, catalog });
12677
+ const published = new Map(
12678
+ bytes2.ready.map(({ family }) => [
12679
+ family.name,
12680
+ { faces: family.faces.length, bytes: family.faces.reduce((n, f) => n + f.bytes, 0) }
12681
+ ])
12682
+ );
12683
+ offRepo = {
12684
+ published,
12685
+ publishedBytes: [...published.values()].reduce((n, f) => n + f.bytes, 0),
12686
+ hostProvided: new Set(bytes2.hostProvided.map((f) => f.name))
12687
+ };
12688
+ for (const { family, reason } of bytes2.unavailable) {
12689
+ findings.push({
12690
+ severity: "error",
12691
+ webFallback: true,
12692
+ message: `${family.name} will render as ${webRenderedFallback(family.name)} on web \u2014 its faces could not be fetched (${reason}), so the release will not declare it. Check the network and re-run \`himi fonts check\`.`
12693
+ });
12694
+ }
12695
+ } else {
12111
12696
  for (const fam of plan.families) {
12112
12697
  for (const f of fam.faces.filter((f2) => !faceSource(f2.file, f2.sha256))) {
12113
12698
  findings.push({
@@ -12117,41 +12702,55 @@ function fontFindings(appDir2) {
12117
12702
  }
12118
12703
  }
12119
12704
  }
12120
- const share = plan.packedBytes / DEFAULT_ASSET_BUDGET_BYTES;
12705
+ const share = (offRepo ? offRepo.publishedBytes : plan.packedBytes) / DEFAULT_ASSET_BUDGET_BYTES;
12121
12706
  if (share > 0.25) {
12122
12707
  findings.push({
12123
12708
  severity: "warning",
12124
12709
  message: `fonts are ${(share * 100).toFixed(0)}% of the ${DEFAULT_ASSET_BUDGET_BYTES / 1024 / 1024} MB per-app asset budget \u2014 consider moving a family to \`otaOnly\` in fonts.json.`
12125
12710
  });
12126
12711
  }
12127
- return { plan, findings };
12712
+ return { plan, findings, ...offRepo ? { offRepo } : {} };
12128
12713
  }
12129
- function checkReport(appDir2) {
12130
- const result = fontFindings(appDir2);
12714
+ async function checkReport(appDir2, opts = {}) {
12715
+ const result = await fontFindings(appDir2, opts);
12131
12716
  if (!result) {
12132
12717
  const looked = configuredTokensPath(appDir2).path ?? "tokens.json";
12133
12718
  return { ok: false, count: 0, totalBytes: 0, problems: [`${appDir2}: no ${looked}`], hint: "run inside an app directory" };
12134
12719
  }
12135
- const { plan, findings } = result;
12720
+ const { plan, findings, offRepo } = result;
12136
12721
  const catalog = loadCatalog();
12137
- const families = plan.families.map((fam) => ({
12138
- family: fam.name,
12139
- reason: fam.reason,
12140
- packedFaces: fam.faces.filter((f) => f.packed).length,
12141
- otaFaces: fam.faces.filter((f) => !f.packed).length,
12142
- kb: Math.round(fam.faces.reduce((n, f) => n + f.bytes, 0) / 1024),
12143
- ...isSystemFamily(fam.name, catalog) ? { note: "platform font \u2014 zero bytes" } : {}
12144
- }));
12722
+ const families = plan.families.map((fam) => {
12723
+ const common = {
12724
+ family: fam.name,
12725
+ reason: fam.reason,
12726
+ kb: Math.round(fam.faces.reduce((n, f) => n + f.bytes, 0) / 1024),
12727
+ ...isSystemFamily(fam.name, catalog) ? { note: "platform font \u2014 zero bytes" } : {}
12728
+ };
12729
+ if (!offRepo) {
12730
+ return {
12731
+ ...common,
12732
+ packedFaces: fam.faces.filter((f) => f.packed).length,
12733
+ otaFaces: fam.faces.filter((f) => !f.packed).length
12734
+ };
12735
+ }
12736
+ return {
12737
+ ...common,
12738
+ packedFaces: 0,
12739
+ otaFaces: offRepo.published.get(fam.name)?.faces ?? 0,
12740
+ ...offRepo.hostProvided.has(fam.name) ? { note: "carried by every himi shell \u2014 not published" } : {}
12741
+ };
12742
+ });
12743
+ const published = offRepo?.publishedBytes ?? 0;
12145
12744
  return {
12146
12745
  // Only an ERROR fails the exit code. A budget warning is real information, but it
12147
12746
  // describes an app that renders correctly, and turning CI red for it would teach people
12148
12747
  // to stop reading the output — which is how the silent degrade survived this long.
12149
12748
  ok: !findings.some((f) => f.severity === "error"),
12150
12749
  count: plan.families.length,
12151
- totalBytes: plan.packedBytes,
12750
+ totalBytes: offRepo ? published : plan.packedBytes,
12152
12751
  problems: findings.map((f) => f.message),
12153
12752
  families,
12154
- hint: plan.otaBytes > 0 ? `${Math.round(plan.otaBytes / 1024)} KB declared OTA (fetched on first use)` : void 0
12753
+ hint: offRepo ? published > 0 ? `${Math.round(published / 1024)} KB published with the release by \`himi push\` (fetched on first use)` : void 0 : plan.otaBytes > 0 ? `${Math.round(plan.otaBytes / 1024)} KB declared OTA (fetched on first use)` : void 0
12155
12754
  };
12156
12755
  }
12157
12756
  function resolveFamilyName(input) {
@@ -12179,13 +12778,21 @@ function addReport(appDir2, family) {
12179
12778
  }
12180
12779
  const fam = findFamily(resolved2);
12181
12780
  const bytes2 = fam?.faces.reduce((n, f) => n + f.bytes, 0) ?? 0;
12781
+ const licence = `Licence: ${fam?.license.id ?? "system"}${fam?.license.copyright ? ` \u2014 ${fam.license.copyright}` : ""}`;
12182
12782
  return {
12183
12783
  ok: true,
12184
12784
  count: 1,
12185
12785
  totalBytes: bytes2,
12186
12786
  problems: [],
12187
12787
  families: [{ family: resolved2, license: fam?.license.id ?? "system", copyright: fam?.license.copyright, kb: Math.round(bytes2 / 1024) }],
12188
- hint: `add "${resolved2}" to ${join22(appDir2, "fonts.json")} under "families" (or name it in tokens.json typography), then run gen.sh. Licence: ${fam?.license.id ?? "system"}${fam?.license.copyright ? ` \u2014 ${fam.license.copyright}` : ""}`
12788
+ // Where the faces go next depends on where this runs (#3047). In a checkout, the app's
12789
+ // `gen.sh` bakes them into the binaries. Off-repo there is no gen.sh and no packer — the
12790
+ // hint used to send authors to a script that does not exist; what gets the faces to a
12791
+ // device there is `himi push`, which publishes them with the release.
12792
+ //
12793
+ // The gen.sh command is SHELL-QUOTED: it is pasted into a shell, and a checkout path with a
12794
+ // space in it (`…/New Mobile Arc/…`) otherwise splits into a script that does not exist.
12795
+ hint: hasVendoredFloor() ? `add "${resolved2}" to ${join22(appDir2, "fonts.json")} under "families" (or name it in tokens.json typography), then run \`bash ${shellQuote(join22(appDir2, "scripts", "gen.sh"))}\` to bake it into the app's binaries. ${licence}` : `name "${resolved2}" in tokens.json typography (or list it under "families" in ${join22(appDir2, "fonts.json")}); \`himi push\` publishes its faces with the release. ${licence}`
12189
12796
  };
12190
12797
  }
12191
12798
  var DEFAULT_ASSET_BUDGET_BYTES;
@@ -12194,7 +12801,9 @@ var init_fonts = __esm({
12194
12801
  init_catalog();
12195
12802
  init_plan_fonts();
12196
12803
  init_face_source();
12804
+ init_web_fallback();
12197
12805
  init_token_lint();
12806
+ init_shell_quote();
12198
12807
  DEFAULT_ASSET_BUDGET_BYTES = 32 * 1024 * 1024;
12199
12808
  }
12200
12809
  });
@@ -12361,16 +12970,16 @@ function applyTransform(t, upstream, caps) {
12361
12970
  try {
12362
12971
  const base = JSON.parse(body || "{}");
12363
12972
  const patch = JSON.parse(patchStr);
12364
- body = JSON.stringify(deepMerge(base, patch));
12973
+ body = JSON.stringify(deepMerge2(base, patch));
12365
12974
  } catch {
12366
12975
  }
12367
12976
  }
12368
12977
  return { status, body, headers: headers2 };
12369
12978
  }
12370
- function deepMerge(a, b) {
12979
+ function deepMerge2(a, b) {
12371
12980
  if (a && b && typeof a === "object" && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b)) {
12372
12981
  const out = { ...a };
12373
- for (const [k, v] of Object.entries(b)) out[k] = deepMerge(out[k], v);
12982
+ for (const [k, v] of Object.entries(b)) out[k] = deepMerge2(out[k], v);
12374
12983
  return out;
12375
12984
  }
12376
12985
  return b;
@@ -12381,7 +12990,7 @@ var init_wix_gateway_rules = __esm({
12381
12990
  });
12382
12991
 
12383
12992
  // src/ux-evidence.ts
12384
- import { existsSync as existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync21, writeFileSync as writeFileSync8 } from "node:fs";
12993
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync21, writeFileSync as writeFileSync9 } from "node:fs";
12385
12994
  import { dirname as dirname13, isAbsolute as isAbsolute2, join as join24, relative as relative3, resolve as resolve15 } from "node:path";
12386
12995
  function isNativePlatform(value) {
12387
12996
  return typeof value === "string" && NATIVE_PLATFORMS.includes(value);
@@ -12426,8 +13035,8 @@ function recordedRenderWidths(content) {
12426
13035
  return renderEvidenceEntries(evidence).map((entry) => entry.width);
12427
13036
  }
12428
13037
  function writeEvidence(path, evidence) {
12429
- mkdirSync9(dirname13(path), { recursive: true });
12430
- writeFileSync8(path, JSON.stringify(evidence, null, 2) + "\n");
13038
+ mkdirSync10(dirname13(path), { recursive: true });
13039
+ writeFileSync9(path, JSON.stringify(evidence, null, 2) + "\n");
12431
13040
  }
12432
13041
  function recordedFilePath(dir, file) {
12433
13042
  const rel = relative3(dir, resolve15(file));
@@ -13861,7 +14470,7 @@ __export(gen_native_config_exports, {
13861
14470
  tvInfoPlan: () => tvInfoPlan,
13862
14471
  watchInfoPlan: () => watchInfoPlan
13863
14472
  });
13864
- import { existsSync as existsSync26, mkdirSync as mkdirSync11, readFileSync as readFileSync26, readdirSync as readdirSync13, rmSync as rmSync3, writeFileSync as writeFileSync10 } from "node:fs";
14473
+ import { existsSync as existsSync26, mkdirSync as mkdirSync12, readFileSync as readFileSync26, readdirSync as readdirSync13, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "node:fs";
13865
14474
  import { dirname as dirname16, join as join29 } from "node:path";
13866
14475
  function parseStringArray(configTs, field) {
13867
14476
  const m = new RegExp(`${field}:\\s*\\[([^\\]]*)\\]`).exec(configTs);
@@ -14041,21 +14650,21 @@ function applyToFile(path, kind, label2, render, check) {
14041
14650
  const after = injectBlock(before, kind, label2, render);
14042
14651
  if (after === before) return { path, outcome: "unchanged" };
14043
14652
  if (check) return { path, outcome: "drift" };
14044
- writeFileSync10(path, after);
14653
+ writeFileSync11(path, after);
14045
14654
  return { path, outcome: "written" };
14046
14655
  }
14047
14656
  function applyWholeFile(path, content, check) {
14048
14657
  const current = existsSync26(path) ? readFileSync26(path, "utf8") : null;
14049
14658
  if (current === content) return { path, outcome: "unchanged" };
14050
14659
  if (check) return { path, outcome: "drift" };
14051
- mkdirSync11(dirname16(path), { recursive: true });
14052
- writeFileSync10(path, content);
14660
+ mkdirSync12(dirname16(path), { recursive: true });
14661
+ writeFileSync11(path, content);
14053
14662
  return { path, outcome: "written" };
14054
14663
  }
14055
14664
  function removeWholeFile(path, check) {
14056
14665
  if (!existsSync26(path)) return { path, outcome: "skipped" };
14057
14666
  if (check) return { path, outcome: "drift" };
14058
- rmSync3(path);
14667
+ rmSync4(path);
14059
14668
  return { path, outcome: "removed" };
14060
14669
  }
14061
14670
  function genNativeConfig(app, opts = {}) {
@@ -14661,7 +15270,7 @@ var init_contained_dev_module = __esm({
14661
15270
 
14662
15271
  // ../../core/dev-server/src/loader.ts
14663
15272
  import { resolve as resolve21, basename as basename8, dirname as dirname17 } from "node:path";
14664
- import { existsSync as existsSync29, readdirSync as readdirSync16, readFileSync as readFileSync28, mkdirSync as mkdirSync12 } from "node:fs";
15273
+ import { existsSync as existsSync29, readdirSync as readdirSync16, readFileSync as readFileSync28, mkdirSync as mkdirSync13 } from "node:fs";
14665
15274
  import { pathToFileURL as pathToFileURL5, fileURLToPath as fileURLToPath12 } from "node:url";
14666
15275
  function resolveWixWebAuthConfig(app) {
14667
15276
  const auth = app?.meta.auth;
@@ -14700,7 +15309,7 @@ async function devModuleUrl(entry, dir) {
14700
15309
  const hasTypeScriptLoader = process.execArgv.some((arg) => arg.includes("tsx"));
14701
15310
  if (!isOffRepo() && hasTypeScriptLoader) return pathToFileURL5(entry).href;
14702
15311
  const out = resolve21(dir, "dist/.himi/dev.mjs");
14703
- mkdirSync12(dirname17(out), { recursive: true });
15312
+ mkdirSync13(dirname17(out), { recursive: true });
14704
15313
  await buildAppEntry(entry, out, {
14705
15314
  // Plain Node must resolve the published-style umbrella entry points for
14706
15315
  // both standalone and in-repo CLI content. In-repo workspace packages
@@ -14965,7 +15574,7 @@ var init_inject = __esm({
14965
15574
  });
14966
15575
 
14967
15576
  // ../../core/dev-server/src/store.ts
14968
- import { mkdirSync as mkdirSync13 } from "node:fs";
15577
+ import { mkdirSync as mkdirSync14 } from "node:fs";
14969
15578
  import { dirname as dirname18, resolve as resolve22 } from "node:path";
14970
15579
  import { fileURLToPath as fileURLToPath13 } from "node:url";
14971
15580
  import { createRequire } from "node:module";
@@ -14984,7 +15593,7 @@ var init_store2 = __esm({
14984
15593
  /** The node:sqlite handle — opened, bootstrapped, and seeded on first access. */
14985
15594
  get db() {
14986
15595
  if (this._db) return this._db;
14987
- mkdirSync13(dirname18(this.dbPath), { recursive: true });
15596
+ mkdirSync14(dirname18(this.dbPath), { recursive: true });
14988
15597
  const { DatabaseSync } = nodeRequire("node:sqlite");
14989
15598
  this._db = new DatabaseSync(this.dbPath, { timeout: 5e3 });
14990
15599
  this.bootstrap();
@@ -15997,7 +16606,7 @@ function sha2562(input) {
15997
16606
  o.setUint32(28, h7);
15998
16607
  return out;
15999
16608
  }
16000
- function sha256Hex2(input) {
16609
+ function sha256Hex3(input) {
16001
16610
  return hex(sha2562(input));
16002
16611
  }
16003
16612
  async function sha256HexAsync(input) {
@@ -16204,7 +16813,7 @@ var init_wix_bridge = __esm({
16204
16813
  * header with no session cookie falls back to itself — callers refuse that case before here. */
16205
16814
  key(msid, cookieHeader) {
16206
16815
  const session = /(?:^|;\s*)wixSession2=([^;]*)/.exec(cookieHeader)?.[1] ?? cookieHeader;
16207
- return sha256Hex2(`${msid}
16816
+ return sha256Hex3(`${msid}
16208
16817
  ${session}`);
16209
16818
  }
16210
16819
  async instance(msid, cookieHeader, now = Date.now()) {
@@ -16245,7 +16854,7 @@ ${session}`);
16245
16854
  }
16246
16855
  cache = /* @__PURE__ */ new Map();
16247
16856
  key(cookieHeader, limit) {
16248
- return sha256Hex2(`${limit}
16857
+ return sha256Hex3(`${limit}
16249
16858
  ${cookieHeader}`);
16250
16859
  }
16251
16860
  async sites(cookieHeader, limit, now = Date.now()) {
@@ -16536,7 +17145,7 @@ var init_stable_ids = __esm({
16536
17145
  // ../../core/dev-server/src/preview.ts
16537
17146
  import { spawn as spawn2 } from "node:child_process";
16538
17147
  import { createHash as createHash11 } from "node:crypto";
16539
- import { existsSync as existsSync32, createReadStream, statSync as statSync6, readFileSync as readFileSync32, renameSync, unlinkSync as unlinkSync2 } from "node:fs";
17148
+ import { existsSync as existsSync32, createReadStream, statSync as statSync6, readFileSync as readFileSync32, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "node:fs";
16540
17149
  import { homedir as homedir4, tmpdir as tmpdir2 } from "node:os";
16541
17150
  import { resolve as resolvePath, dirname as dirname19 } from "node:path";
16542
17151
  import { fileURLToPath as fileURLToPath15 } from "node:url";
@@ -16603,7 +17212,7 @@ async function buildMacosWinlist(bin) {
16603
17212
  return interpretWinlist();
16604
17213
  }
16605
17214
  try {
16606
- renameSync(staging, bin);
17215
+ renameSync2(staging, bin);
16607
17216
  } catch {
16608
17217
  try {
16609
17218
  unlinkSync2(staging);
@@ -16742,7 +17351,7 @@ async function handlePreviewStream(req, res, url) {
16742
17351
  return;
16743
17352
  }
16744
17353
  const q = new URLSearchParams(url.split("?")[1] ?? "");
16745
- const fps = clamp(parseInt(q.get("fps") ?? "8", 10) || 8, 1, 15);
17354
+ const fps = clamp2(parseInt(q.get("fps") ?? "8", 10) || 8, 1, 15);
16746
17355
  const intervalMs = Math.floor(1e3 / fps);
16747
17356
  const format = q.get("format") === "png" ? "png" : "jpeg";
16748
17357
  res.statusCode = 200;
@@ -16796,7 +17405,7 @@ ${note}\r
16796
17405
  }
16797
17406
  });
16798
17407
  }
16799
- function clamp(n, lo, hi) {
17408
+ function clamp2(n, lo, hi) {
16800
17409
  return Math.max(lo, Math.min(hi, n));
16801
17410
  }
16802
17411
  async function getIosLogicalDims(udid) {
@@ -16848,8 +17457,8 @@ async function getAndroidPixelDims(serial) {
16848
17457
  }
16849
17458
  async function handlePreviewTap(res, payload) {
16850
17459
  const platform = payload.platform === "android" ? "android" : "ios";
16851
- const nx = clamp(Number(payload.nx ?? 0), 0, 1);
16852
- const ny = clamp(Number(payload.ny ?? 0), 0, 1);
17460
+ const nx = clamp2(Number(payload.nx ?? 0), 0, 1);
17461
+ const ny = clamp2(Number(payload.ny ?? 0), 0, 1);
16853
17462
  if (!Number.isFinite(nx) || !Number.isFinite(ny)) {
16854
17463
  res.statusCode = 400;
16855
17464
  res.setHeader("content-type", "application/json");
@@ -16904,16 +17513,16 @@ async function handlePreviewTap(res, payload) {
16904
17513
  }
16905
17514
  async function handlePreviewSwipe(res, payload) {
16906
17515
  const platform = payload.platform === "android" ? "android" : "ios";
16907
- const nx1 = clamp(Number(payload.nx1 ?? 0), 0, 1);
16908
- const ny1 = clamp(Number(payload.ny1 ?? 0), 0, 1);
16909
- const nx2 = clamp(Number(payload.nx2 ?? 0), 0, 1);
16910
- const ny2 = clamp(Number(payload.ny2 ?? 0), 0, 1);
17516
+ const nx1 = clamp2(Number(payload.nx1 ?? 0), 0, 1);
17517
+ const ny1 = clamp2(Number(payload.ny1 ?? 0), 0, 1);
17518
+ const nx2 = clamp2(Number(payload.nx2 ?? 0), 0, 1);
17519
+ const ny2 = clamp2(Number(payload.ny2 ?? 0), 0, 1);
16911
17520
  if (![nx1, ny1, nx2, ny2].every(Number.isFinite)) {
16912
17521
  res.statusCode = 400;
16913
17522
  res.setHeader("content-type", "application/json");
16914
17523
  return void res.end(JSON.stringify({ error: "invalid_coords", hint: "nx1,ny1,nx2,ny2 must be numbers in [0,1]" }));
16915
17524
  }
16916
- const durationMs = clamp(Number(payload.durationMs ?? 250), 50, 5e3);
17525
+ const durationMs = clamp2(Number(payload.durationMs ?? 250), 50, 5e3);
16917
17526
  try {
16918
17527
  if (platform === "ios") {
16919
17528
  const udid = payload.device || await firstBootedIosUdid();
@@ -17140,8 +17749,8 @@ async function handlePreviewHitTest(res, payload) {
17140
17749
  res.statusCode = 404;
17141
17750
  return void res.end(JSON.stringify({ error: "no_layout", hint: "The app hasn't reported a layout yet (dev build + on a reported screen)." }));
17142
17751
  }
17143
- const nx = clamp(Number(payload.nx ?? 0), 0, 1);
17144
- const ny = clamp(Number(payload.ny ?? 0), 0, 1);
17752
+ const nx = clamp2(Number(payload.nx ?? 0), 0, 1);
17753
+ const ny = clamp2(Number(payload.ny ?? 0), 0, 1);
17145
17754
  const px = nx * snap.width, py = ny * snap.height;
17146
17755
  let best = null;
17147
17756
  for (const [id, f] of Object.entries(snap.frames)) {
@@ -17911,401 +18520,6 @@ var init_env = __esm({
17911
18520
  }
17912
18521
  });
17913
18522
 
17914
- // ../../core/ts/src/idiom.ts
17915
- function authored(overlays, name) {
17916
- return typeof name === "string" && overlays !== void 0 && Object.hasOwn(overlays, name) && overlays[name] !== null && typeof overlays[name] === "object" && !Array.isArray(overlays[name]);
17917
- }
17918
- function selectIdiomOverlay(doc, ctx = {}) {
17919
- const policy = doc.idiomPolicy;
17920
- const overlays = doc.idiom;
17921
- const isRecord3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
17922
- if (!isRecord3(policy) || !isRecord3(overlays)) return void 0;
17923
- const kind = policy.policy ?? "follow-surface";
17924
- if (kind === "none") return void 0;
17925
- if (kind === "pinned") return authored(overlays, policy.pin) ? policy.pin : void 0;
17926
- if (kind !== "follow-surface") return void 0;
17927
- const surfaces = policy.surfaces;
17928
- const candidates = [
17929
- ctx.surface !== void 0 && isRecord3(surfaces) && Object.hasOwn(surfaces, ctx.surface) ? surfaces[ctx.surface] : void 0,
17930
- ...ctx.native ?? [],
17931
- policy.fallback
17932
- ];
17933
- return candidates.find((c) => authored(overlays, c));
17934
- }
17935
- function isPlainObject(v) {
17936
- return v !== null && typeof v === "object" && !Array.isArray(v);
17937
- }
17938
- function deepMerge2(base, overlay) {
17939
- if (!isPlainObject(overlay) || !isPlainObject(base)) return overlay;
17940
- const out = { ...base };
17941
- for (const [key2, value] of Object.entries(overlay)) {
17942
- if (UNSAFE_KEYS.has(key2)) continue;
17943
- out[key2] = Object.hasOwn(base, key2) ? deepMerge2(base[key2], value) : value;
17944
- }
17945
- return out;
17946
- }
17947
- function mergeIdiomOverlay(base, overlay) {
17948
- const merged = deepMerge2(base, overlay);
17949
- const baseColors = base.colors;
17950
- const overlayColors = overlay.colors;
17951
- if (isPlainObject(baseColors) && isPlainObject(overlayColors)) {
17952
- const colors = { ...merged.colors };
17953
- for (const [name, value] of Object.entries(overlayColors)) {
17954
- if (UNSAFE_KEYS.has(name)) continue;
17955
- const was = Object.hasOwn(baseColors, name) ? baseColors[name] : void 0;
17956
- if (typeof was === "string" && isPlainObject(value)) colors[name] = { light: was, ...value };
17957
- }
17958
- merged.colors = colors;
17959
- }
17960
- return merged;
17961
- }
17962
- function resolveIdiom(tokens, ctx = {}) {
17963
- const doc = tokens;
17964
- const name = selectIdiomOverlay(doc, ctx);
17965
- if (name === void 0) return tokens;
17966
- const merged = mergeIdiomOverlay(tokens, doc.idiom[name]);
17967
- const { idiomPolicy: _applied, ...final } = merged;
17968
- return final;
17969
- }
17970
- var UNSAFE_KEYS;
17971
- var init_idiom = __esm({
17972
- "../../core/ts/src/idiom.ts"() {
17973
- "use strict";
17974
- UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
17975
- }
17976
- });
17977
-
17978
- // ../../core/web-renderer/src/tokens.ts
17979
- function isSerifFamily(family) {
17980
- return !!family && SERIF_FAMILY_RE.test(family);
17981
- }
17982
- function fontStack(family) {
17983
- if (!family) return DEFAULT_FONT_STACK;
17984
- if (isSerifFamily(family)) return `"${family}", serif`;
17985
- return `"${family}", ${DEFAULT_FONT_STACK}`;
17986
- }
17987
- function clamp2(n, lo = 0, hi = 1) {
17988
- return Math.max(lo, Math.min(hi, n));
17989
- }
17990
- function hexToRgb2(hex2) {
17991
- let h = hex2.trim().replace(/^#/, "");
17992
- if (h.length === 3) h = h.split("").map((c) => c + c).join("");
17993
- if (!/^[\da-f]{6}$/i.test(h)) return null;
17994
- const int = parseInt(h, 16);
17995
- return [int >> 16 & 255, int >> 8 & 255, int & 255];
17996
- }
17997
- function rgba(color, alpha2) {
17998
- const rgb = hexToRgb2(color);
17999
- return rgb ? `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${clamp2(alpha2)})` : color;
18000
- }
18001
- function normalizeSpring(spring, durationMs) {
18002
- return {
18003
- response: clampTo(finite(spring.response) ?? durationMs / 1e3, SPRING_MIN_RESPONSE, SPRING_MAX_RESPONSE),
18004
- dampingFraction: clampTo(finite(spring.dampingFraction) ?? 0.8, SPRING_MIN_DAMPING, SPRING_MAX_DAMPING)
18005
- };
18006
- }
18007
- function springStep(response, zeta) {
18008
- const w0 = 2 * Math.PI / response;
18009
- if (zeta < 1) {
18010
- const wd = w0 * Math.sqrt(1 - zeta * zeta);
18011
- return (t) => 1 - Math.exp(-zeta * w0 * t) * (Math.cos(wd * t) + zeta * w0 / wd * Math.sin(wd * t));
18012
- }
18013
- if (zeta === 1) return (t) => 1 - Math.exp(-w0 * t) * (1 + w0 * t);
18014
- const root = Math.sqrt(zeta * zeta - 1);
18015
- const r1 = -w0 * (zeta - root), r2 = -w0 * (zeta + root);
18016
- return (t) => 1 - (r2 * Math.exp(r1 * t) - r1 * Math.exp(r2 * t)) / (r2 - r1);
18017
- }
18018
- function springCurve(spring, durationMs) {
18019
- const { response, dampingFraction: zeta } = normalizeSpring(spring, durationMs);
18020
- const key2 = `${response}|${zeta}`;
18021
- const cached3 = springCurves.get(key2);
18022
- if (cached3) return cached3;
18023
- const x = springStep(response, zeta);
18024
- const step = response / 64;
18025
- let settle = 0;
18026
- for (let t = 0; t <= SPRING_MAX_SECS; t += step) if (Math.abs(1 - x(t)) > SPRING_SETTLE_TOLERANCE) settle = t;
18027
- const secs = Math.min(settle + step, SPRING_MAX_SECS);
18028
- const samples = Math.min(200, Math.max(24, Math.ceil(12 * secs / response)));
18029
- const points = [];
18030
- for (let i = 0; i <= samples; i++) points.push(i === 0 ? 0 : i === samples ? 1 : Number(x(secs * i / samples).toFixed(3)));
18031
- const curve = { durationMs: Math.round(secs * 1e3), easing: `linear(${points.join(", ")})` };
18032
- springCurves.set(key2, curve);
18033
- return curve;
18034
- }
18035
- function linearEasingSupported() {
18036
- const css = globalThis.CSS;
18037
- return typeof css?.supports === "function" && css.supports("animation-timing-function", "linear(0, 1)");
18038
- }
18039
- function easingCss(e) {
18040
- switch (e) {
18041
- case "linear":
18042
- return "linear";
18043
- case "easeIn":
18044
- return "cubic-bezier(0.4,0,1,1)";
18045
- case "easeOut":
18046
- return "cubic-bezier(0,0,0.2,1)";
18047
- case "spring":
18048
- return "cubic-bezier(0.34,1.56,0.64,1)";
18049
- // Material 3's emphasized easing (#2930).
18050
- case "emphasized":
18051
- return "cubic-bezier(0.2,0,0,1)";
18052
- default:
18053
- return "cubic-bezier(0.4,0,0.2,1)";
18054
- }
18055
- }
18056
- function motionCss(m) {
18057
- if (m.easing === "spring" && m.spring && linearEasingSupported()) return springCurve(m.spring, m.duration);
18058
- return { durationMs: m.duration, easing: easingCss(m.easing) };
18059
- }
18060
- function hexToHsl(hex2) {
18061
- const m = /^#?([\da-f]{6})$/i.exec(hex2.trim());
18062
- if (!m) return null;
18063
- const int = parseInt(m[1], 16);
18064
- const r = (int >> 16 & 255) / 255, g = (int >> 8 & 255) / 255, b = (int & 255) / 255;
18065
- const max = Math.max(r, g, b), min = Math.min(r, g, b);
18066
- let h = 0, s = 0;
18067
- const l = (max + min) / 2;
18068
- if (max !== min) {
18069
- const d = max - min;
18070
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
18071
- if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
18072
- else if (max === g) h = (b - r) / d + 2;
18073
- else h = (r - g) / d + 4;
18074
- h /= 6;
18075
- }
18076
- return [h, s, l];
18077
- }
18078
- function hslToHex(h, s, l) {
18079
- const hue = (p, q, t) => {
18080
- if (t < 0) t += 1;
18081
- if (t > 1) t -= 1;
18082
- if (t < 1 / 6) return p + (q - p) * 6 * t;
18083
- if (t < 1 / 2) return q;
18084
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
18085
- return p;
18086
- };
18087
- let r, g, b;
18088
- if (s === 0) {
18089
- r = g = b = l;
18090
- } else {
18091
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
18092
- const p = 2 * l - q;
18093
- r = hue(p, q, h + 1 / 3);
18094
- g = hue(p, q, h);
18095
- b = hue(p, q, h - 1 / 3);
18096
- }
18097
- const to = (x) => Math.round(clamp2(x) * 255).toString(16).padStart(2, "0");
18098
- return `#${to(r)}${to(g)}${to(b)}`;
18099
- }
18100
- function roleOf(name) {
18101
- const n = name.toLowerCase();
18102
- if (n.startsWith("surface") || n.includes("background") || n.includes("canvas")) return "surface";
18103
- if (n.startsWith("text") || n.startsWith("on")) return "text";
18104
- if (n.includes("border") || n.includes("divider") || n.includes("separator")) return "border";
18105
- if (n.includes("accent") || n.includes("primary") || n.includes("link")) return "accent";
18106
- return "other";
18107
- }
18108
- function synthScheme(hex2, name, scheme) {
18109
- if (scheme === "light") return hex2;
18110
- const hsl = hexToHsl(hex2);
18111
- if (!hsl) return hex2;
18112
- const [h, s, l] = hsl;
18113
- const role = roleOf(name);
18114
- if (scheme === "dark") {
18115
- switch (role) {
18116
- case "surface":
18117
- return hslToHex(h, clamp2(s * 0.6), clamp2(0.07 + (1 - l) * 0.12, 0.06, 0.22));
18118
- case "text":
18119
- return hslToHex(h, clamp2(s * 0.5), clamp2(0.97 - l * 0.25, 0.7, 0.97));
18120
- case "border":
18121
- return hslToHex(h, clamp2(s * 0.5), clamp2(0.18 + (1 - l) * 0.12, 0.18, 0.34));
18122
- case "accent":
18123
- return hslToHex(h, s, clamp2(l + 0.1, 0, 0.72));
18124
- default:
18125
- return hslToHex(h, s, clamp2(l + 0.06));
18126
- }
18127
- }
18128
- switch (role) {
18129
- case "surface":
18130
- return l > 0.5 ? "#FFFFFF" : "#000000";
18131
- case "text":
18132
- return l > 0.5 ? "#FFFFFF" : "#000000";
18133
- case "border":
18134
- return "#000000";
18135
- case "accent":
18136
- return hslToHex(h, clamp2(s + 0.2), clamp2(l - 0.18, 0.18, 0.5));
18137
- default:
18138
- return hex2;
18139
- }
18140
- }
18141
- function resolveSchemeColor(o, scheme) {
18142
- const exact = o?.[scheme];
18143
- if (typeof exact === "string") return exact;
18144
- if (scheme === "highContrast" && typeof o?.dark === "string") return o.dark;
18145
- if (typeof o?.light === "string") return o.light;
18146
- return typeof o?.dark === "string" ? o.dark : void 0;
18147
- }
18148
- function makeTokenResolvers(source, scheme, idiom = WEB_IDIOM_CONTEXT) {
18149
- const tokens = resolveIdiom(source, idiom);
18150
- const color = (name, fallback = "#1a1a1a") => {
18151
- if (name == null) return fallback;
18152
- if (typeof name !== "string") {
18153
- const o = name;
18154
- const direct = resolveSchemeColor(o, scheme);
18155
- if (typeof direct === "string") return direct;
18156
- if (typeof o?.token === "string") return color(o.token, fallback);
18157
- if (typeof o?.name === "string") return color(o.name, fallback);
18158
- return fallback;
18159
- }
18160
- if (name.startsWith("#")) return name;
18161
- const v = tokens.colors?.[name];
18162
- if (v == null) return fallback;
18163
- if (typeof v === "object") {
18164
- const direct = resolveSchemeColor(v, scheme);
18165
- return typeof direct === "string" ? direct : fallback;
18166
- }
18167
- return synthScheme(v, name, scheme);
18168
- };
18169
- const font = (style = "body") => {
18170
- const t = tokens.typography?.[style] ?? tokens.fonts?.[style] ?? tokens.typography?.body ?? tokens.fonts?.body;
18171
- const size = t?.size ?? 14;
18172
- return {
18173
- size,
18174
- remSize: pxToRem(size),
18175
- weight: t?.weight ?? 400,
18176
- line: t?.line ?? 1.4,
18177
- family: t?.family,
18178
- letterSpacing: t?.letterSpacing
18179
- };
18180
- };
18181
- const radius = (name, fallback = 0) => {
18182
- if (typeof name === "number") return name;
18183
- if (typeof name === "string") return tokens.radius?.[name] ?? fallback;
18184
- return fallback;
18185
- };
18186
- const sp = (n) => typeof n === "number" ? n : 0;
18187
- const shadow = (name) => {
18188
- const key2 = typeof name === "string" ? name : name?.token ?? name?.name;
18189
- if (!key2) return void 0;
18190
- const v = tokens.shadows?.[key2];
18191
- if (v == null) return void 0;
18192
- if (typeof v === "string") return v;
18193
- const x = v.x ?? 0, y = v.y ?? 0;
18194
- return `${x}px ${y}px ${v.radius}px ${rgba(v.color ?? "#000000", v.opacity)}`;
18195
- };
18196
- const gradient = (name) => {
18197
- const key2 = typeof name === "string" ? name : name?.token;
18198
- if (!key2) return void 0;
18199
- const v = tokens.gradients?.[key2];
18200
- if (v == null) return void 0;
18201
- if (typeof v === "string") return v;
18202
- const stops = v.colors.map((c, i) => {
18203
- const at = v.locations?.[i];
18204
- return `${color(c)}${at != null ? ` ${Math.round(at * 100)}%` : ""}`;
18205
- });
18206
- return `linear-gradient(${v.angle ?? 0}deg, ${stops.join(", ")})`;
18207
- };
18208
- const meshGradient = (name) => {
18209
- const key2 = typeof name === "string" ? name : name?.token;
18210
- if (!key2) return void 0;
18211
- const v = tokens.gradients?.[key2];
18212
- if (v == null || typeof v === "string") return void 0;
18213
- const cols = v.colors.map((c) => color(c));
18214
- if (cols.length === 0) return void 0;
18215
- const pts = [[18, 22], [82, 18], [25, 82], [78, 80], [50, 45], [10, 55], [90, 60]];
18216
- const blobs = cols.map((c, i) => {
18217
- const [x, y] = pts[i % pts.length];
18218
- return `radial-gradient(circle at ${x}% ${y}%, ${c} 0%, transparent 55%)`;
18219
- });
18220
- return `${blobs.join(", ")}, ${cols[cols.length - 1]}`;
18221
- };
18222
- const material = (name) => {
18223
- const key2 = typeof name === "string" ? name : name?.token ?? name?.name;
18224
- if (!key2) return void 0;
18225
- const v = tokens.materials?.[key2];
18226
- if (v == null) return void 0;
18227
- if (!("style" in v)) return { background: v.background, backdropFilter: v.backdropFilter };
18228
- const m = v;
18229
- const tint = m.tint ? color(m.tint, "#000000") : void 0;
18230
- if (m.style === "glass" || m.style === "frosted") {
18231
- return {
18232
- background: tint ? rgba(tint, m.opacity ?? 0.6) : void 0,
18233
- backdropFilter: `blur(${m.blur ?? 20}px) saturate(180%)`
18234
- };
18235
- }
18236
- return tint ? { background: rgba(tint, m.opacity ?? 1) } : void 0;
18237
- };
18238
- const densityScale = (density) => {
18239
- switch (density) {
18240
- case "compact":
18241
- return 0.75;
18242
- case "spacious":
18243
- return 1.25;
18244
- default:
18245
- return 1;
18246
- }
18247
- };
18248
- const motionTransition = (motion) => {
18249
- switch (motion) {
18250
- case "crisp":
18251
- return "all 120ms cubic-bezier(0.2,0,0,1)";
18252
- case "bouncy":
18253
- return "all 320ms cubic-bezier(0.34,1.56,0.64,1)";
18254
- default:
18255
- return "all 240ms cubic-bezier(0.4,0,0.2,1)";
18256
- }
18257
- };
18258
- const appearMotion = (name) => {
18259
- if (!name) return void 0;
18260
- const m = tokens.motions?.[name];
18261
- if (!m) return void 0;
18262
- return motionCss(m);
18263
- };
18264
- const reduceMotion = () => {
18265
- const policy = tokens.kit?.reduceMotion ?? "system";
18266
- if (policy === "always") return true;
18267
- if (policy === "never") return false;
18268
- return typeof globalThis !== "undefined" && typeof globalThis.matchMedia === "function" && globalThis.matchMedia("(prefers-reduced-motion: reduce)").matches;
18269
- };
18270
- return {
18271
- color,
18272
- font,
18273
- radius,
18274
- sp,
18275
- shadow,
18276
- gradient,
18277
- meshGradient,
18278
- material,
18279
- densityScale,
18280
- motionTransition,
18281
- appearMotion,
18282
- reduceMotion,
18283
- kit: tokens.kit ?? {},
18284
- tokens,
18285
- scheme
18286
- };
18287
- }
18288
- var REM_ROOT_PX, pxToRem, DEFAULT_FONT_STACK, SERIF_FAMILY_RE, SPRING_MIN_RESPONSE, SPRING_MAX_RESPONSE, SPRING_MIN_DAMPING, SPRING_MAX_DAMPING, clampTo, finite, SPRING_SETTLE_TOLERANCE, SPRING_MAX_SECS, springCurves, WEB_IDIOM_CONTEXT;
18289
- var init_tokens2 = __esm({
18290
- "../../core/web-renderer/src/tokens.ts"() {
18291
- init_idiom();
18292
- REM_ROOT_PX = 16;
18293
- pxToRem = (px) => `${px / REM_ROOT_PX}rem`;
18294
- DEFAULT_FONT_STACK = '"Wix Madefor Text", system-ui';
18295
- SERIF_FAMILY_RE = /\b(georgia|times|garamond|palatino|baskerville|didot|charter|bodoni|caslon|cambria|constantia|rockwell|playfair|merriweather|lora|literata|spectral|serif)\b/i;
18296
- SPRING_MIN_RESPONSE = 0.05;
18297
- SPRING_MAX_RESPONSE = 10;
18298
- SPRING_MIN_DAMPING = 0.1;
18299
- SPRING_MAX_DAMPING = 4;
18300
- clampTo = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
18301
- finite = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
18302
- SPRING_SETTLE_TOLERANCE = 1e-3;
18303
- SPRING_MAX_SECS = 10;
18304
- springCurves = /* @__PURE__ */ new Map();
18305
- WEB_IDIOM_CONTEXT = { surface: "desktop" };
18306
- }
18307
- });
18308
-
18309
18523
  // ../../core/web-renderer/src/modifiers.ts
18310
18524
  function padStyle(p, scale = 1) {
18311
18525
  if (p == null) return {};
@@ -19144,6 +19358,7 @@ function shouldRevealError(args) {
19144
19358
  var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
19145
19359
  var init_validation = __esm({
19146
19360
  "../../core/ts/src/validation.ts"() {
19361
+ "use strict";
19147
19362
  EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
19148
19363
  URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
19149
19364
  INTEGER_RE = /^[+-]?[0-9]+$/;
@@ -22568,6 +22783,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
22568
22783
  var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
22569
22784
  var init_worker_subtree = __esm({
22570
22785
  "../../core/ts/src/worker-subtree.ts"() {
22786
+ "use strict";
22571
22787
  init_worker_subtree_safe_types_generated();
22572
22788
  WORKER_SUBTREE_CEILINGS = Object.freeze({
22573
22789
  maxEncodedBytes: 65536,
@@ -30354,7 +30570,7 @@ var init_errors = __esm({
30354
30570
 
30355
30571
  // ../../core/serve-storage/src/contract.ts
30356
30572
  function strongEtag(body) {
30357
- return strongEtagForSha256(sha256Hex2(body));
30573
+ return strongEtagForSha256(sha256Hex3(body));
30358
30574
  }
30359
30575
  function strongEtagForSha256(hex2) {
30360
30576
  return `"${hex2.slice(0, 32)}"`;
@@ -30403,7 +30619,7 @@ __export(config_exports2, {
30403
30619
  serializeRolloutYaml: () => serializeRolloutYaml,
30404
30620
  validateOverlayPatch: () => validateOverlayPatch
30405
30621
  });
30406
- import { mkdirSync as mkdirSync14, readFileSync as readFileSync37, writeFileSync as writeFileSync11 } from "node:fs";
30622
+ import { mkdirSync as mkdirSync15, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "node:fs";
30407
30623
  import { dirname as dirname20, join as join32, resolve as resolve29 } from "node:path";
30408
30624
  import { fileURLToPath as fileURLToPath17 } from "node:url";
30409
30625
  function strip(line) {
@@ -30531,8 +30747,8 @@ function readJsonAt(app, file, root) {
30531
30747
  }
30532
30748
  function writeJsonAt(app, file, root, value) {
30533
30749
  const path = appConfigPath(app, file, root);
30534
- mkdirSync14(dirname20(path), { recursive: true });
30535
- writeFileSync11(path, JSON.stringify(value, null, 2) + "\n");
30750
+ mkdirSync15(dirname20(path), { recursive: true });
30751
+ writeFileSync12(path, JSON.stringify(value, null, 2) + "\n");
30536
30752
  return path;
30537
30753
  }
30538
30754
  function sanitizeOverlay(raw) {
@@ -30647,7 +30863,7 @@ var init_config2 = __esm({
30647
30863
  // ../../core/dev-server/src/index.ts
30648
30864
  import { createServer as createServer2 } from "node:http";
30649
30865
  import { readFile, stat } from "node:fs/promises";
30650
- import { readFileSync as readFileSync38, existsSync as existsSync35, watch, mkdirSync as mkdirSync15, rmSync as rmSync4 } from "node:fs";
30866
+ import { readFileSync as readFileSync38, existsSync as existsSync35, watch, mkdirSync as mkdirSync16, rmSync as rmSync5 } from "node:fs";
30651
30867
  import { extname, resolve as resolve30, normalize as normalize3, sep as sep7, join as join33 } from "node:path";
30652
30868
  import { createHash as createHash15, randomUUID } from "node:crypto";
30653
30869
  import { fileURLToPath as fileURLToPath18, pathToFileURL as pathToFileURL6 } from "node:url";
@@ -30828,23 +31044,17 @@ function servedFontFaces(appDir2, tokens) {
30828
31044
  try {
30829
31045
  const policyPath = join33(appDir2, "fonts.json");
30830
31046
  const policy = existsSync35(policyPath) ? JSON.parse(readFileSync38(policyPath, "utf8")) : {};
30831
- const plan = planFonts(tokens, policy);
31047
+ let plan = planFonts(tokens, policy);
31048
+ if (!hasVendoredFloor()) plan = { ...plan, families: plan.families.filter((f) => !isHostProvided(f.name)) };
30832
31049
  if (plan.families.length === 0) return void 0;
30833
31050
  return servedProjection(plan);
30834
31051
  } catch {
30835
31052
  return void 0;
30836
31053
  }
30837
31054
  }
30838
- function fontFaceBytesBySha(_appDir, sha) {
31055
+ async function fontFaceBytesBySha(_appDir, sha) {
30839
31056
  try {
30840
- const catalog = loadCatalog();
30841
- for (const family of [...Object.values(catalog.families), ...Object.values(catalog.bundled)]) {
30842
- for (const face of family.faces) {
30843
- if (face.sha256 !== sha) continue;
30844
- const src = faceSource(face.file, face.sha256);
30845
- if (src) return readFileSync38(src);
30846
- }
30847
- }
31057
+ return await catalogFaceBytes(sha);
30848
31058
  } catch {
30849
31059
  }
30850
31060
  return void 0;
@@ -31554,7 +31764,7 @@ async function reloadAppModuleNow(state, opts) {
31554
31764
  const current = state.app;
31555
31765
  if (!current) return { ok: false, error: "no_app" };
31556
31766
  const entry = resolve30(current.dir, "dev/index.ts");
31557
- mkdirSync15(HMR_TMP_DIR, { recursive: true });
31767
+ mkdirSync16(HMR_TMP_DIR, { recursive: true });
31558
31768
  const outfile = resolve30(HMR_TMP_DIR, `${current.name}-${++appReloadSeq}.mjs`);
31559
31769
  try {
31560
31770
  const lib = await import(pathToFileURL6(resolve30(TIER5_SRC_ROOT, "build-lib.mjs")).href);
@@ -31600,7 +31810,7 @@ async function reloadAppModuleNow(state, opts) {
31600
31810
  return { ok: false, error };
31601
31811
  } finally {
31602
31812
  try {
31603
- rmSync4(outfile, { force: true });
31813
+ rmSync5(outfile, { force: true });
31604
31814
  } catch {
31605
31815
  }
31606
31816
  }
@@ -33076,7 +33286,7 @@ function createDevServer(opts = {}) {
33076
33286
  const assetDir = state.app && assetApp === state.app.name ? state.app.dir : resolveAppDir(assetApp);
33077
33287
  const hit = assetDir ? collectAssets(assetDir).find((a) => assetSha256(readFileSync38(a.path)) === sha) : void 0;
33078
33288
  if (!hit && assetDir) {
33079
- const fontBytes = fontFaceBytesBySha(assetDir, sha);
33289
+ const fontBytes = await fontFaceBytesBySha(assetDir, sha);
33080
33290
  if (fontBytes) {
33081
33291
  res.writeHead(200, {
33082
33292
  "content-type": "font/ttf",
@@ -33428,7 +33638,6 @@ var init_src6 = __esm({
33428
33638
  init_inject();
33429
33639
  init_plan_fonts();
33430
33640
  init_face_source();
33431
- init_catalog();
33432
33641
  init_himi_report();
33433
33642
  init_store2();
33434
33643
  init_derive_transport_capability();
@@ -34944,7 +35153,7 @@ async function crawlScreenInner(opts) {
34944
35153
  severity: "error",
34945
35154
  message: `service "${svc}" never left its loading state (${waiting})`,
34946
35155
  actual: waiting,
34947
- hint: "the screen shows its skeleton forever \u2014 every path out of load() must clear the loading flag, including the failure path"
35156
+ hint: `the screen shows its skeleton forever \u2014 every path out of load() must clear the loading flag, including the failure path; ${STALE_SNAPSHOT_HINT}`
34948
35157
  });
34949
35158
  }
34950
35159
  }
@@ -35282,7 +35491,7 @@ async function crawlScreenHostileInner(opts, variant) {
35282
35491
  axis,
35283
35492
  message: `under ${axis}, service "${svc}" never left its loading state (${waiting})`,
35284
35493
  actual: waiting,
35285
- hint: "the failure/empty path must also clear the loading flag \u2014 otherwise the skeleton shows forever the day the backend misbehaves"
35494
+ hint: `the failure/empty path must also clear the loading flag \u2014 otherwise the skeleton shows forever the day the backend misbehaves; ${STALE_SNAPSHOT_HINT}`
35286
35495
  });
35287
35496
  }
35288
35497
  }
@@ -35745,7 +35954,7 @@ async function crawlScreenRelations(opts) {
35745
35954
  return { findings: dedupe(findings), checked, byKind };
35746
35955
  });
35747
35956
  }
35748
- var ACTION_KEYS, UNTRACKED_ITEMS, NESTED_ITEMS_SEP, REJECT_ALL_MESSAGE, VLQ, WIX_DATA_QUERY, WIX_DATA_ANY, CAPABILITY_ACTION, detached, CRAWL_CLOCK, MEMBER_IDENTITY_ACTION, BLANK_WHEN_BOUND, UNBINDABLE_ROW;
35957
+ var ACTION_KEYS, UNTRACKED_ITEMS, NESTED_ITEMS_SEP, REJECT_ALL_MESSAGE, VLQ, WIX_DATA_QUERY, WIX_DATA_ANY, CAPABILITY_ACTION, detached, CRAWL_CLOCK, MEMBER_IDENTITY_ACTION, BLANK_WHEN_BOUND, STALE_SNAPSHOT_HINT, UNBINDABLE_ROW;
35749
35958
  var init_screen_crawl = __esm({
35750
35959
  "../../core/dev-server/src/screen-crawl.ts"() {
35751
35960
  init_validate_descriptor_core();
@@ -35785,6 +35994,7 @@ var init_screen_crawl = __esm({
35785
35994
  Marquee: ["items", "itemsPath", "text"],
35786
35995
  MediaPlayer: ["items", "itemsPath"]
35787
35996
  };
35997
+ STALE_SNAPSHOT_HINT = 'if every path already does, look for a stale-snapshot write-back: `return s` (or `{ ...s }`) after an await or from an early-return guard writes back the state as it was BEFORE the await, loading flag included \u2014 to change nothing, return `undefined` instead (not `null` or `{}`); see `himi docs tier-5-add-a-screen`, "Should this result be committed at all?"';
35788
35998
  UNBINDABLE_ROW = Symbol("unbindable-row");
35789
35999
  }
35790
36000
  });
@@ -36444,10 +36654,13 @@ function withProdServeAppConfig(text4, prod) {
36444
36654
  function pinnedReleaseFromEnv(env = process.env) {
36445
36655
  return env.HIMI_DIST_RELEASE_PIN?.trim() || void 0;
36446
36656
  }
36447
- async function buildRelease(app, dest, _opts = {}) {
36657
+ async function buildRelease(app, dest, opts = {}) {
36448
36658
  const loaded = await loadApp(app);
36449
36659
  const tier5Dir = hasBuiltBundles(loaded.dir) ? bundleOutDir(loaded.dir) : void 0;
36450
- return (await buildFromLoaded(loaded, dest, tier5Dir ? { tier5Dir } : {})).manifest;
36660
+ return (await buildFromLoaded(loaded, dest, {
36661
+ ...tier5Dir ? { tier5Dir } : {},
36662
+ ...opts.fetchFace ? { fetchFace: opts.fetchFace } : {}
36663
+ })).manifest;
36451
36664
  }
36452
36665
  function countingWixCall(base) {
36453
36666
  let returned = 0;
@@ -36699,7 +36912,8 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36699
36912
  }
36700
36913
  let fontPlan;
36701
36914
  let publishedFontPlan;
36702
- const canEmitFonts = hasVendoredFloor();
36915
+ const inRepo = hasVendoredFloor();
36916
+ const fontWarnings = [];
36703
36917
  try {
36704
36918
  const appTokens = readTokensForLint(preloaded) ?? {};
36705
36919
  const policy = existsSync36(join34(preloaded.dir, "fonts.json")) ? JSON.parse(readFileSync39(join34(preloaded.dir, "fonts.json"), "utf8")) : {};
@@ -36709,7 +36923,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36709
36923
  `[release-build] font plan failed for "${app}": ${String(err)}. Refusing to publish a release whose tokens name families it declares no faces for \u2014 fix apps/${app}/fonts.json or run \`npm run fonts:catalog\`.`
36710
36924
  );
36711
36925
  }
36712
- if (canEmitFonts && fontPlan && fontPlan.families.length > 0 && store.putAsset) {
36926
+ if (inRepo && fontPlan && fontPlan.families.length > 0 && store.putAsset) {
36713
36927
  for (const family of fontPlan.families) {
36714
36928
  for (const face of family.faces) {
36715
36929
  const src = faceSource(face.file, face.sha256);
@@ -36731,12 +36945,38 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
36731
36945
  sri: sri2(bytes2),
36732
36946
  bytes: bytes2.length,
36733
36947
  contentType: "font/ttf",
36734
- origin: "repo",
36948
+ origin: "catalog",
36735
36949
  ...face.packed ? { baked: true } : {}
36736
36950
  };
36737
36951
  }
36738
36952
  }
36739
36953
  publishedFontPlan = fontPlan;
36954
+ } else if (!inRepo && fontPlan && fontPlan.families.length > 0 && store.putAsset) {
36955
+ const off = await offRepoFontBytes(fontPlan, opts.fetchFace ? { fetchFace: opts.fetchFace } : {});
36956
+ for (const { family, reason } of off.unavailable) {
36957
+ const line = `[release-build] ${family.name} will render as ${webRenderedFallback(family.name)} on web: its faces could not be fetched (${reason}), so this release does not declare it. Re-run once the upstream is reachable.`;
36958
+ fontWarnings.push(line);
36959
+ console.warn(line);
36960
+ }
36961
+ for (const { faces } of off.ready) {
36962
+ for (const { face, bytes: bytes2 } of faces) {
36963
+ await store.putAsset(app, face.sha256, bytes2, "font/ttf");
36964
+ assets[`fonts/${face.sha256}.ttf`] = {
36965
+ sha256: face.sha256,
36966
+ sri: sri2(bytes2),
36967
+ bytes: bytes2.length,
36968
+ contentType: "font/ttf",
36969
+ origin: "catalog"
36970
+ };
36971
+ }
36972
+ }
36973
+ const declared = /* @__PURE__ */ new Set([
36974
+ ...off.ready.map((r) => r.family),
36975
+ ...fontPlan.families.filter((f) => f.builtin)
36976
+ ]);
36977
+ if (declared.size > 0) {
36978
+ publishedFontPlan = { ...fontPlan, families: fontPlan.families.filter((f) => declared.has(f)) };
36979
+ }
36740
36980
  }
36741
36981
  const brandFonts = [];
36742
36982
  if (store.putAsset) {
@@ -37143,6 +37383,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
37143
37383
  }),
37144
37384
  ...tokensSnapshotFailure ? { tokensSnapshotFailure } : {},
37145
37385
  ...widgetBakeFailures.length ? { widgetBakeFailures } : {},
37386
+ ...fontWarnings.length ? { fontWarnings } : {},
37146
37387
  ...collect2?.lint ? { lint, workers } : {},
37147
37388
  ...collect2?.render ? { renders } : {},
37148
37389
  ...collect2?.descriptors ? { descriptors: baked, linkableScreenIds: [...linkable] } : {},
@@ -37210,6 +37451,7 @@ var init_build3 = __esm({
37210
37451
  init_app_assets();
37211
37452
  init_plan_fonts();
37212
37453
  init_face_source();
37454
+ init_web_fallback();
37213
37455
  init_src6();
37214
37456
  init_check();
37215
37457
  init_file_store();
@@ -37315,14 +37557,26 @@ function freezeTrafficToMocks(events, opts = {}) {
37315
37557
  if (ev.respBody === void 0) continue;
37316
37558
  if (!includeErrors && (ev.status < 200 || ev.status >= 300)) continue;
37317
37559
  if (hostFilter && ev.host && !hostFilter.has(ev.host)) continue;
37318
- const key2 = `${ev.method} ${scopeByHost ? ev.host ?? "" : ""} ${ev.path}`;
37319
- byKey.set(key2, ev);
37320
- }
37560
+ const bodyContains = collectionMatcher(ev.reqBody);
37561
+ const request = `${ev.method} ${scopeByHost ? ev.host ?? "" : ""} ${ev.path}`;
37562
+ byKey.set(`${request} ${bodyContains ?? ""}`, { ev, request, bodyContains });
37563
+ }
37564
+ const kept = [...byKey.values()];
37565
+ const firstPathOnly = /* @__PURE__ */ new Map();
37566
+ kept.forEach((k, i) => {
37567
+ if (!k.bodyContains && !firstPathOnly.has(k.request)) firstPathOnly.set(k.request, i);
37568
+ });
37569
+ const rank = (k, i) => {
37570
+ const p = k.bodyContains ? firstPathOnly.get(k.request) : void 0;
37571
+ return p !== void 0 && p < i ? p - 0.5 : i;
37572
+ };
37573
+ const ordered = kept.map((k, i) => ({ k, i, r: rank(k, i) })).sort((a, b) => a.r - b.r || a.i - b.i).map(({ k }) => k);
37321
37574
  const rules = [];
37322
37575
  let id = 0;
37323
- for (const ev of byKey.values()) {
37576
+ for (const { ev, bodyContains } of ordered) {
37324
37577
  const matcher = { method: ev.method, pathGlob: ev.path };
37325
37578
  if (scopeByHost && ev.host) matcher.host = ev.host;
37579
+ if (bodyContains) matcher.bodyContains = bodyContains;
37326
37580
  rules.push({
37327
37581
  id: ++id,
37328
37582
  enabled: true,
@@ -37337,6 +37591,17 @@ function freezeTrafficToMocks(events, opts = {}) {
37337
37591
  }
37338
37592
  return { mode: "mock", rules };
37339
37593
  }
37594
+ function collectionMatcher(reqBody) {
37595
+ if (!reqBody || !reqBody.includes('"dataCollectionId"')) return void 0;
37596
+ try {
37597
+ const parsed = JSON.parse(reqBody);
37598
+ const id = parsed && typeof parsed === "object" ? parsed.dataCollectionId : void 0;
37599
+ return typeof id === "string" && id ? `"dataCollectionId":${JSON.stringify(id)}` : void 0;
37600
+ } catch {
37601
+ const m = /"dataCollectionId"\s*:\s*"((?:[^"\\]|\\.)+)"/.exec(reqBody);
37602
+ return m ? `"dataCollectionId":"${m[1]}"` : void 0;
37603
+ }
37604
+ }
37340
37605
  function pickContentType(headers2) {
37341
37606
  if (!headers2) return void 0;
37342
37607
  for (const [k, v] of Object.entries(headers2)) {
@@ -37972,7 +38237,7 @@ var init_push_setup_apple_credentials = __esm({
37972
38237
  });
37973
38238
 
37974
38239
  // src/push-onboarding.ts
37975
- import { existsSync as existsSync37, mkdirSync as mkdirSync16, readFileSync as readFileSync41, statSync as statSync7, writeFileSync as writeFileSync12, chmodSync as chmodSync2 } from "node:fs";
38240
+ import { existsSync as existsSync37, mkdirSync as mkdirSync17, readFileSync as readFileSync41, statSync as statSync7, writeFileSync as writeFileSync13, chmodSync as chmodSync2 } from "node:fs";
37976
38241
  import { basename as basename9, dirname as dirname22, join as join35, resolve as resolve33 } from "node:path";
37977
38242
  function readJson2(path) {
37978
38243
  try {
@@ -38122,8 +38387,8 @@ function readPushOnboarding(dir) {
38122
38387
  }
38123
38388
  function writeFile(dir, file) {
38124
38389
  const path = join35(resolve33(dir), PUSH_ONBOARDING_PATH);
38125
- mkdirSync16(dirname22(path), { recursive: true, mode: 448 });
38126
- writeFileSync12(path, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
38390
+ mkdirSync17(dirname22(path), { recursive: true, mode: 448 });
38391
+ writeFileSync13(path, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
38127
38392
  try {
38128
38393
  chmodSync2(path, 384);
38129
38394
  } catch {
@@ -39111,7 +39376,7 @@ __export(pack_exports, {
39111
39376
  });
39112
39377
  import { createHash as createHash19 } from "node:crypto";
39113
39378
  import { deflateRawSync, inflateRawSync } from "node:zlib";
39114
- import { existsSync as existsSync38, mkdirSync as mkdirSync17, readFileSync as readFileSync42, readdirSync as readdirSync20, rmSync as rmSync5, statSync as statSync8, writeFileSync as writeFileSync13 } from "node:fs";
39379
+ import { existsSync as existsSync38, mkdirSync as mkdirSync18, readFileSync as readFileSync42, readdirSync as readdirSync20, rmSync as rmSync6, statSync as statSync8, writeFileSync as writeFileSync14 } from "node:fs";
39115
39380
  import { dirname as dirname23, join as join36, resolve as resolve35 } from "node:path";
39116
39381
  function writeZip(entries) {
39117
39382
  const sorted = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
@@ -39258,18 +39523,18 @@ function gatherReleaseEntries(appDir2) {
39258
39523
  }
39259
39524
  return { entries, manifest, skipped };
39260
39525
  }
39261
- function sha256Hex3(bytes2) {
39526
+ function sha256Hex4(bytes2) {
39262
39527
  return createHash19("sha256").update(bytes2).digest("hex");
39263
39528
  }
39264
39529
  function computeContentHash(entries) {
39265
- const input = packageHashInput(entries.map((e) => ({ path: e.path, hash: sha256Hex3(e.bytes) })));
39530
+ const input = packageHashInput(entries.map((e) => ({ path: e.path, hash: sha256Hex4(e.bytes) })));
39266
39531
  return "sha256-" + createHash19("sha256").update(input).digest("base64");
39267
39532
  }
39268
39533
  function buildEntries(appDir2, app, opts) {
39269
39534
  const { entries: released, manifest, skipped } = gatherReleaseEntries(appDir2);
39270
39535
  const entries = opts.source ? [...released, { path: HIMI_PACKAGE_SOURCE_PATH, bytes: opts.source }] : released;
39271
39536
  const contentHash = computeContentHash(entries);
39272
- const files = Object.fromEntries(entries.map((e) => [e.path, sha256Hex3(e.bytes)]));
39537
+ const files = Object.fromEntries(entries.map((e) => [e.path, sha256Hex4(e.bytes)]));
39273
39538
  const header = buildPackageHeader({
39274
39539
  manifest,
39275
39540
  app,
@@ -39290,8 +39555,8 @@ function packRelease(releaseRoot, app, out, opts = {}) {
39290
39555
  const buf = writeZip(all);
39291
39556
  const isDir = existsSync38(out) && statSync8(out).isDirectory();
39292
39557
  const outFile = isDir ? join36(resolve35(out), packageFileName(app, header.releaseId)) : resolve35(out);
39293
- mkdirSync17(dirname23(outFile), { recursive: true });
39294
- writeFileSync13(outFile, buf);
39558
+ mkdirSync18(dirname23(outFile), { recursive: true });
39559
+ writeFileSync14(outFile, buf);
39295
39560
  return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
39296
39561
  }
39297
39562
  function resolvePackageDirDest(outDir, app, releaseId) {
@@ -39330,12 +39595,12 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
39330
39595
  const appDir2 = join36(resolve35(releaseRoot), app);
39331
39596
  const { all, header, skipped } = buildEntries(appDir2, app, opts);
39332
39597
  const dest = resolvePackageDirDest(resolve35(outDir), app, header.releaseId);
39333
- rmSync5(dest, { recursive: true, force: true });
39598
+ rmSync6(dest, { recursive: true, force: true });
39334
39599
  let bytes2 = 0;
39335
39600
  for (const entry of all) {
39336
39601
  const target = join36(dest, entry.path);
39337
- mkdirSync17(dirname23(target), { recursive: true });
39338
- writeFileSync13(target, entry.bytes);
39602
+ mkdirSync18(dirname23(target), { recursive: true });
39603
+ writeFileSync14(target, entry.bytes);
39339
39604
  bytes2 += entry.bytes.length;
39340
39605
  }
39341
39606
  return { app, releaseId: header.releaseId, header, out: dest, bytes: bytes2, entryCount: all.length, skipped };
@@ -39413,11 +39678,11 @@ function unpackTo(buf, dest, appFallback) {
39413
39678
  if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
39414
39679
  const root = resolve35(dest);
39415
39680
  const appDir2 = join36(root, app);
39416
- rmSync5(appDir2, { recursive: true, force: true });
39681
+ rmSync6(appDir2, { recursive: true, force: true });
39417
39682
  for (const [rel, bytes2] of entries) {
39418
39683
  const target = join36(appDir2, rel);
39419
- mkdirSync17(dirname23(target), { recursive: true });
39420
- writeFileSync13(target, bytes2);
39684
+ mkdirSync18(dirname23(target), { recursive: true });
39685
+ writeFileSync14(target, bytes2);
39421
39686
  }
39422
39687
  return { root, appDir: appDir2, app };
39423
39688
  }
@@ -39451,7 +39716,7 @@ __export(app_source_exports, {
39451
39716
  writeConflicts: () => writeConflicts,
39452
39717
  zipAppSource: () => zipAppSource
39453
39718
  });
39454
- import { readdirSync as readdirSync21, lstatSync as lstatSync5, readFileSync as readFileSync43, mkdirSync as mkdirSync18, writeFileSync as writeFileSync14, existsSync as existsSync39, rmSync as rmSync6, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
39719
+ import { readdirSync as readdirSync21, lstatSync as lstatSync5, readFileSync as readFileSync43, mkdirSync as mkdirSync19, writeFileSync as writeFileSync15, existsSync as existsSync39, rmSync as rmSync7, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
39455
39720
  import { join as join37, resolve as resolve36, sep as sep8 } from "node:path";
39456
39721
  import { deflateRawSync as deflateRawSync2 } from "node:zlib";
39457
39722
  function walkSourceTree(dir, file, skip) {
@@ -39529,7 +39794,7 @@ function writeAppSource(entries, destDir) {
39529
39794
  `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.`
39530
39795
  );
39531
39796
  }
39532
- mkdirSync18(root, { recursive: true });
39797
+ mkdirSync19(root, { recursive: true });
39533
39798
  const written = [];
39534
39799
  for (const entry of entries) {
39535
39800
  if (isDeniedSourcePath(entry.path)) continue;
@@ -39540,11 +39805,11 @@ function writeAppSource(entries, destDir) {
39540
39805
  const kind = pathKind(dir);
39541
39806
  if (kind?.isSymbolicLink()) unlinkSync3(dir);
39542
39807
  else if (kind) continue;
39543
- mkdirSync18(dir);
39808
+ mkdirSync19(dir);
39544
39809
  }
39545
39810
  const target = join37(root, ...segments);
39546
39811
  if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
39547
- writeFileSync14(target, entry.bytes);
39812
+ writeFileSync15(target, entry.bytes);
39548
39813
  written.push(entry.path);
39549
39814
  }
39550
39815
  return written;
@@ -39599,7 +39864,7 @@ function writeConflicts(entries, destDir) {
39599
39864
  function removeStaleSource(entries, destDir) {
39600
39865
  const root = resolve36(destDir);
39601
39866
  const removed = staleSourcePaths(entries, root);
39602
- for (const rel of removed) rmSync6(join37(root, ...rel.split("/")), { force: true });
39867
+ for (const rel of removed) rmSync7(join37(root, ...rel.split("/")), { force: true });
39603
39868
  const needed = /* @__PURE__ */ new Set();
39604
39869
  for (const entry of entries) {
39605
39870
  if (isDeniedSourcePath(entry.path)) continue;
@@ -39679,7 +39944,7 @@ __export(eject_exports, {
39679
39944
  EJECTABLE: () => EJECTABLE,
39680
39945
  ejectModule: () => ejectModule
39681
39946
  });
39682
- import { existsSync as existsSync40, mkdirSync as mkdirSync19, readFileSync as readFileSync44, writeFileSync as writeFileSync15 } from "node:fs";
39947
+ import { existsSync as existsSync40, mkdirSync as mkdirSync20, readFileSync as readFileSync44, writeFileSync as writeFileSync16 } from "node:fs";
39683
39948
  import { dirname as dirname24, join as join38, relative as relative5, resolve as resolve37, sep as sep9 } from "node:path";
39684
39949
  function locate(repoRootOrCwd, mod) {
39685
39950
  const inRepo = resolve37(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
@@ -39710,7 +39975,7 @@ function ejectModule(opts) {
39710
39975
  }
39711
39976
  const ext = found.form === "source" ? "ts" : "mjs";
39712
39977
  const target = join38(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
39713
- mkdirSync19(dirname24(target), { recursive: true });
39978
+ mkdirSync20(dirname24(target), { recursive: true });
39714
39979
  const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
39715
39980
  //
39716
39981
  // Central fixes to @wix/himalaya/${mod} NO LONGER REACH THIS APP \u2014 including any
@@ -39727,7 +39992,7 @@ function ejectModule(opts) {
39727
39992
  /(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
39728
39993
  (_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
39729
39994
  );
39730
- writeFileSync15(target, banner + normalized);
39995
+ writeFileSync16(target, banner + normalized);
39731
39996
  const rewired = [];
39732
39997
  for (const f of files) {
39733
39998
  if (!existsSync40(f)) continue;
@@ -39743,7 +40008,7 @@ function ejectModule(opts) {
39743
40008
  );
39744
40009
  }
39745
40010
  if (after !== before) {
39746
- writeFileSync15(f, after);
40011
+ writeFileSync16(f, after);
39747
40012
  rewired.push(f);
39748
40013
  }
39749
40014
  }
@@ -39779,7 +40044,7 @@ __export(test_exports, {
39779
40044
  scopeDescriptors: () => scopeDescriptors,
39780
40045
  writeRecordedMocks: () => writeRecordedMocks
39781
40046
  });
39782
- import { existsSync as existsSync41, mkdirSync as mkdirSync20, readFileSync as readFileSync45, writeFileSync as writeFileSync16 } from "node:fs";
40047
+ import { existsSync as existsSync41, mkdirSync as mkdirSync21, readFileSync as readFileSync45, writeFileSync as writeFileSync17 } from "node:fs";
39783
40048
  import { join as join39, resolve as resolve38 } from "node:path";
39784
40049
  function readTestConfig(dir) {
39785
40050
  const p = resolve38(dir, TEST_CONFIG_FILE);
@@ -39955,8 +40220,8 @@ function writeRecordedMocks(opts) {
39955
40220
  };
39956
40221
  }
39957
40222
  const fs = opts.io ?? {
39958
- mkdir: (p) => mkdirSync20(p, { recursive: true }),
39959
- write: (p, s) => writeFileSync16(p, s)
40223
+ mkdir: (p) => mkdirSync21(p, { recursive: true }),
40224
+ write: (p, s) => writeFileSync17(p, s)
39960
40225
  };
39961
40226
  fs.mkdir(join39(opts.dir, "dev"));
39962
40227
  fs.write(join39(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
@@ -42264,7 +42529,7 @@ __export(native_decode_exports, {
42264
42529
  runNativeDecode: () => runNativeDecode
42265
42530
  });
42266
42531
  import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
42267
- import { existsSync as existsSync44, mkdtempSync as mkdtempSync2, readFileSync as readFileSync48, rmSync as rmSync7, writeFileSync as writeFileSync17 } from "node:fs";
42532
+ import { existsSync as existsSync44, mkdtempSync as mkdtempSync2, readFileSync as readFileSync48, rmSync as rmSync8, writeFileSync as writeFileSync18 } from "node:fs";
42268
42533
  import { tmpdir as tmpdir3 } from "node:os";
42269
42534
  import { join as join42 } from "node:path";
42270
42535
  import { fileURLToPath as fileURLToPath20 } from "node:url";
@@ -42398,7 +42663,7 @@ function runNativeDecode(options) {
42398
42663
  if (typeof descriptor.descriptorJson !== "string") {
42399
42664
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
42400
42665
  }
42401
- writeFileSync17(join42(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
42666
+ writeFileSync18(join42(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
42402
42667
  }
42403
42668
  options.progress?.("building cached Swift oracle");
42404
42669
  execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
@@ -42424,7 +42689,7 @@ function runNativeDecode(options) {
42424
42689
  const stderr = failure.stderr ? ` \u2014 ${String(failure.stderr).trim().slice(0, 2e3)}` : "";
42425
42690
  throw new Error(`iOS decoder oracle failed: ${failure.message}${stderr}`);
42426
42691
  } finally {
42427
- rmSync7(descriptorDir, { recursive: true, force: true });
42692
+ rmSync8(descriptorDir, { recursive: true, force: true });
42428
42693
  }
42429
42694
  }
42430
42695
  function runAndroidNativeDecode(options) {
@@ -42436,7 +42701,7 @@ function runAndroidNativeDecode(options) {
42436
42701
  if (typeof descriptor.descriptorJson !== "string") {
42437
42702
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
42438
42703
  }
42439
- writeFileSync17(join42(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
42704
+ writeFileSync18(join42(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
42440
42705
  }
42441
42706
  options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
42442
42707
  execFileSync5(options.gradlew, [
@@ -42462,7 +42727,7 @@ function runAndroidNativeDecode(options) {
42462
42727
  const stderr = failure.stderr ? ` \u2014 ${String(failure.stderr).trim().slice(0, 2e3)}` : "";
42463
42728
  throw new Error(`Android decoder oracle failed: ${failure.message}${stderr}`);
42464
42729
  } finally {
42465
- rmSync7(descriptorDir, { recursive: true, force: true });
42730
+ rmSync8(descriptorDir, { recursive: true, force: true });
42466
42731
  }
42467
42732
  }
42468
42733
  function fieldAt(path) {
@@ -42784,7 +43049,7 @@ __export(coverage_exports, {
42784
43049
  suppressedNativeKeys: () => suppressedNativeKeys,
42785
43050
  trendAndStore: () => trendAndStore
42786
43051
  });
42787
- import { existsSync as existsSync46, mkdirSync as mkdirSync21, readFileSync as readFileSync50, writeFileSync as writeFileSync18 } from "node:fs";
43052
+ import { existsSync as existsSync46, mkdirSync as mkdirSync22, readFileSync as readFileSync50, writeFileSync as writeFileSync19 } from "node:fs";
42788
43053
  import { dirname as dirname25, join as join44 } from "node:path";
42789
43054
  function suppressedNativeKeys(oracle) {
42790
43055
  return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
@@ -42967,8 +43232,8 @@ function trendAndStore(dir, entries, suppressed) {
42967
43232
  const current = entries.map((e) => e.key);
42968
43233
  const stored = [.../* @__PURE__ */ new Set([...current, ...(previous ?? []).filter((key2) => (suppressed ?? []).includes(key2))])];
42969
43234
  try {
42970
- mkdirSync21(dirname25(p), { recursive: true });
42971
- writeFileSync18(p, JSON.stringify({ keys: stored, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
43235
+ mkdirSync22(dirname25(p), { recursive: true });
43236
+ writeFileSync19(p, JSON.stringify({ keys: stored, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
42972
43237
  } catch {
42973
43238
  return null;
42974
43239
  }
@@ -43012,8 +43277,8 @@ function diffAndStoreObservations(dir, current) {
43012
43277
  } catch {
43013
43278
  }
43014
43279
  try {
43015
- mkdirSync21(dirname25(p), { recursive: true });
43016
- writeFileSync18(p, JSON.stringify({ screens: current, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
43280
+ mkdirSync22(dirname25(p), { recursive: true });
43281
+ writeFileSync19(p, JSON.stringify({ screens: current, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
43017
43282
  } catch {
43018
43283
  return null;
43019
43284
  }
@@ -43168,6 +43433,7 @@ function verifyReport(dir, app, manifest) {
43168
43433
  const drift = [];
43169
43434
  const inSync = [];
43170
43435
  for (const [name, rec] of published) {
43436
+ if (rec.origin === "catalog") continue;
43171
43437
  const mine = local.get(name);
43172
43438
  if (!mine) {
43173
43439
  drift.push(
@@ -43253,19 +43519,6 @@ var init_assets = __esm({
43253
43519
  }
43254
43520
  });
43255
43521
 
43256
- // src/shell-quote.ts
43257
- var shell_quote_exports = {};
43258
- __export(shell_quote_exports, {
43259
- shellQuote: () => shellQuote
43260
- });
43261
- function shellQuote(arg) {
43262
- return /^[A-Za-z0-9_./:@=-]+$/.test(arg) ? arg : `'${arg.replace(/'/g, `'\\''`)}'`;
43263
- }
43264
- var init_shell_quote = __esm({
43265
- "src/shell-quote.ts"() {
43266
- }
43267
- });
43268
-
43269
43522
  // ../../core/serve-runtime/package-share.ts
43270
43523
  function parseStored(bytes2, id) {
43271
43524
  if (!bytes2) return null;
@@ -43516,7 +43769,7 @@ function makeServeHandler(opts) {
43516
43769
  }
43517
43770
  const PINNED_MANIFEST_CACHE_CAP = 100;
43518
43771
  const pinnedManifestCache = /* @__PURE__ */ new Map();
43519
- const sha256hex = (b) => sha256Hex2(b);
43772
+ const sha256hex = (b) => sha256Hex3(b);
43520
43773
  function resolvePin(request, url) {
43521
43774
  return request.headers.get("x-himalaya-release") || url.searchParams.get("release") || null;
43522
43775
  }
@@ -44691,19 +44944,19 @@ var init_preview_assets_generated = __esm({
44691
44944
  "../../packages/serve/src/preview-assets.generated.ts"() {
44692
44945
  init_preview_assets_format();
44693
44946
  PREVIEW_ASSET_MANIFEST = [
44694
- { key: "assets/index-CeKHbRna.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 998645, sha256: "4e1a78d6443c5e1ccf0a16a87b5ca4ab1a62fb5b989182a5faa3f31b43932c47" },
44695
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 998653, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
44696
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1089577, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
44697
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1180561, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
44698
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1271541, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
44699
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1362413, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
44700
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1453393, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
44701
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1562029, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
44702
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1671113, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
44703
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1780161, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
44704
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1887861, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
44705
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1975969, length: 4448, sha256: "79979ee36bb97117452963ece8b9816095ddcec8cc95fa1798448d0c9fc6402b" },
44706
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1980417, length: 13784, sha256: "cfb9465254fab84f0e084bb4542c282758ea29774b5f172840cc0b9e4194ef89" }
44947
+ { key: "assets/index-D0JRTirJ.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1004613, sha256: "7e32dc45ae043c4ec3176c5defcadbb434e6748aef2c6b6135aee97d5ef2c093" },
44948
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1004621, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
44949
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1095545, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
44950
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1186529, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
44951
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1277509, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
44952
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1368381, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
44953
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1459361, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
44954
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1567997, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
44955
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1677081, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
44956
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1786129, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
44957
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1893829, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
44958
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1981937, length: 4448, sha256: "d37ab02eeaf4e6de05cd6b1928427b05e2585a871df0821d7879894db5155a76" },
44959
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1986385, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
44707
44960
  ];
44708
44961
  }
44709
44962
  });
@@ -44719,7 +44972,7 @@ __export(run_exports, {
44719
44972
  runPackage: () => runPackage,
44720
44973
  withoutProdServe: () => withoutProdServe
44721
44974
  });
44722
- import { cpSync, existsSync as existsSync48, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync3, readFileSync as readFileSync53, rmSync as rmSync8, statSync as statSync10 } from "node:fs";
44975
+ import { cpSync, existsSync as existsSync48, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, readFileSync as readFileSync53, rmSync as rmSync9, statSync as statSync10 } from "node:fs";
44723
44976
  import { tmpdir as tmpdir4 } from "node:os";
44724
44977
  import { dirname as dirname26, join as join46 } from "node:path";
44725
44978
  import { fileURLToPath as fileURLToPath22 } from "node:url";
@@ -44754,8 +45007,8 @@ async function resolvePackage(source, workDir) {
44754
45007
  const root2 = workDir ?? mkdtempSync3(join46(tmpdir4(), "himi-run-"));
44755
45008
  const target = join46(root2, app2);
44756
45009
  if (join46(source) !== target) {
44757
- mkdirSync22(root2, { recursive: true });
44758
- rmSync8(target, { recursive: true, force: true });
45010
+ mkdirSync23(root2, { recursive: true });
45011
+ rmSync9(target, { recursive: true, force: true });
44759
45012
  cpSync(source, target, { recursive: true });
44760
45013
  }
44761
45014
  return {
@@ -44775,7 +45028,7 @@ async function resolvePackage(source, workDir) {
44775
45028
  const { app, appDir: appDir2 } = unpackTo(bytes2, root);
44776
45029
  const opened = openPackageDir(appDir2);
44777
45030
  if (!opened.validation.ok) {
44778
- rmSync8(workDir ? appDir2 : root, { recursive: true, force: true });
45031
+ rmSync9(workDir ? appDir2 : root, { recursive: true, force: true });
44779
45032
  throw new Error(`package is not valid:
44780
45033
  ${opened.validation.errors.join("\n ")}`);
44781
45034
  }
@@ -44826,7 +45079,7 @@ async function runPackage(source, opts = {}) {
44826
45079
  const resolved2 = await resolvePackage(source, opts.workDir);
44827
45080
  const assets = opts.assets ?? (opts.spa ? /* @__PURE__ */ new Map() : await loadPreviewAssets());
44828
45081
  if (!opts.spa && assets.size === 0) {
44829
- if (resolved2.temp) rmSync8(resolved2.temp, { recursive: true, force: true });
45082
+ if (resolved2.temp) rmSync9(resolved2.temp, { recursive: true, force: true });
44830
45083
  throw new Error(NO_SPA_MESSAGE);
44831
45084
  }
44832
45085
  const handler = makePackageRunHandler({
@@ -44856,7 +45109,7 @@ async function runPackage(source, opts = {}) {
44856
45109
  warnings: resolved2.warnings,
44857
45110
  close: () => new Promise((done) => {
44858
45111
  server.close(() => {
44859
- if (resolved2.temp) rmSync8(resolved2.temp, { recursive: true, force: true });
45112
+ if (resolved2.temp) rmSync9(resolved2.temp, { recursive: true, force: true });
44860
45113
  done();
44861
45114
  });
44862
45115
  })
@@ -46055,7 +46308,7 @@ __export(version_exports, {
46055
46308
  setAndroidVersion: () => setAndroidVersion,
46056
46309
  setIosVersion: () => setIosVersion
46057
46310
  });
46058
- import { readFileSync as readFileSync58, writeFileSync as writeFileSync19 } from "node:fs";
46311
+ import { readFileSync as readFileSync58, writeFileSync as writeFileSync20 } from "node:fs";
46059
46312
  function readIosVersion(projectYml) {
46060
46313
  const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
46061
46314
  const build2 = matchScalar(projectYml, "CFBundleVersion");
@@ -46120,8 +46373,8 @@ function bumpVersion(app, opts) {
46120
46373
  marketing: opts.marketing ?? current.marketing,
46121
46374
  build: opts.build === "increment" || opts.build === void 0 ? current.build + (opts.build === "increment" ? 1 : 0) : opts.build
46122
46375
  };
46123
- writeFileSync19(iosPath, setIosVersion(iosYml, next));
46124
- writeFileSync19(gradlePath, setAndroidVersion(gradle, next));
46376
+ writeFileSync20(iosPath, setIosVersion(iosYml, next));
46377
+ writeFileSync20(gradlePath, setAndroidVersion(gradle, next));
46125
46378
  return next;
46126
46379
  }
46127
46380
  var init_version = __esm({
@@ -46473,7 +46726,7 @@ __export(notify_exports, {
46473
46726
  runNotify: () => runNotify,
46474
46727
  saveAdminSession: () => saveAdminSession
46475
46728
  });
46476
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync23, readFileSync as readFileSync62, writeFileSync as writeFileSync20 } from "node:fs";
46729
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync24, readFileSync as readFileSync62, writeFileSync as writeFileSync21 } from "node:fs";
46477
46730
  import { homedir as homedir6 } from "node:os";
46478
46731
  import { dirname as dirname29, join as join49 } from "node:path";
46479
46732
  function defaultSessionsPath() {
@@ -46489,8 +46742,8 @@ function loadSessionsFile(path = defaultSessionsPath()) {
46489
46742
  function saveAdminSession(adminUrl, session, path = defaultSessionsPath()) {
46490
46743
  const file = loadSessionsFile(path);
46491
46744
  file.sessions = { ...file.sessions, [adminUrl]: session };
46492
- mkdirSync23(dirname29(path), { recursive: true, mode: 448 });
46493
- writeFileSync20(path, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
46745
+ mkdirSync24(dirname29(path), { recursive: true, mode: 448 });
46746
+ writeFileSync21(path, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
46494
46747
  try {
46495
46748
  chmodSync3(dirname29(path), 448);
46496
46749
  chmodSync3(path, 384);
@@ -50066,7 +50319,7 @@ var init_brand_font = __esm({
50066
50319
  });
50067
50320
 
50068
50321
  // src/site-analyze/write-artifacts.ts
50069
- import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync21 } from "node:fs";
50322
+ import { mkdirSync as mkdirSync25, writeFileSync as writeFileSync22 } from "node:fs";
50070
50323
  import { join as join50 } from "node:path";
50071
50324
  function attachVeloSources(book, sources, put) {
50072
50325
  const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
@@ -50222,13 +50475,13 @@ async function downloadMedia(book, fetchImpl, put) {
50222
50475
  }
50223
50476
  async function writeBusinessBook(result, opts) {
50224
50477
  const out = opts.outDir;
50225
- mkdirSync24(join50(out, "evidence/pages"), { recursive: true });
50226
- mkdirSync24(join50(out, "media/catalog"), { recursive: true });
50478
+ mkdirSync25(join50(out, "evidence/pages"), { recursive: true });
50479
+ mkdirSync25(join50(out, "media/catalog"), { recursive: true });
50227
50480
  const files = [];
50228
50481
  const put = (rel, body) => {
50229
50482
  const p = join50(out, rel);
50230
- mkdirSync24(join50(p, ".."), { recursive: true });
50231
- writeFileSync21(p, body);
50483
+ mkdirSync25(join50(p, ".."), { recursive: true });
50484
+ writeFileSync22(p, body);
50232
50485
  files.push(rel);
50233
50486
  };
50234
50487
  const book = result.book;
@@ -50648,7 +50901,7 @@ var init_home_descriptor = __esm({
50648
50901
  });
50649
50902
 
50650
50903
  // src/site-analyze/apply.ts
50651
- import { existsSync as existsSync53, readFileSync as readFileSync63, writeFileSync as writeFileSync22, copyFileSync as copyFileSync3, mkdirSync as mkdirSync25, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
50904
+ import { existsSync as existsSync53, readFileSync as readFileSync63, writeFileSync as writeFileSync23, copyFileSync as copyFileSync3, mkdirSync as mkdirSync26, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
50652
50905
  import { dirname as dirname30, isAbsolute as isAbsolute4, join as join51, resolve as resolve42, sep as sep11 } from "node:path";
50653
50906
  import { spawnSync as spawnSync4 } from "node:child_process";
50654
50907
  function unpairedRedirectNote(overlay) {
@@ -50761,7 +51014,7 @@ function buildMergedContract(options) {
50761
51014
  if (!real.startsWith(realRoot + sep11)) return void 0;
50762
51015
  try {
50763
51016
  if (!statSync12(real).isFile()) return void 0;
50764
- mkdirSync25(dirname30(to), { recursive: true });
51017
+ mkdirSync26(dirname30(to), { recursive: true });
50765
51018
  copyFileSync3(real, to);
50766
51019
  } catch {
50767
51020
  return void 0;
@@ -50797,10 +51050,10 @@ function buildMergedContract(options) {
50797
51050
  const body = `${JSON.stringify(merged, null, 2)}
50798
51051
  `;
50799
51052
  const path = join51(packageDir, "provisioning.contract.json");
50800
- writeFileSync22(path, body);
51053
+ writeFileSync23(path, body);
50801
51054
  const localPath = join51(appDir2, LOCAL_CONTRACT_REL);
50802
- mkdirSync25(dirname30(localPath), { recursive: true });
50803
- writeFileSync22(localPath, body);
51055
+ mkdirSync26(dirname30(localPath), { recursive: true });
51056
+ writeFileSync23(localPath, body);
50804
51057
  staged.push(localPath);
50805
51058
  return { path, staged };
50806
51059
  }
@@ -50846,10 +51099,10 @@ async function applyOverlays(input) {
50846
51099
  if (existsSync53(pkgProv)) {
50847
51100
  const cur = JSON.parse(readFileSync63(pkgProv, "utf8"));
50848
51101
  const merged = deepMerge4(cur, overlay);
50849
- writeFileSync22(pkgProv, JSON.stringify(merged, null, 2) + "\n");
51102
+ writeFileSync23(pkgProv, JSON.stringify(merged, null, 2) + "\n");
50850
51103
  wrote.push(pkgProv);
50851
51104
  } else {
50852
- writeFileSync22(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
51105
+ writeFileSync23(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
50853
51106
  wrote.push(pkgProv);
50854
51107
  }
50855
51108
  const pkgTokens = join51(cwd, "tokens.json");
@@ -50860,7 +51113,7 @@ async function applyOverlays(input) {
50860
51113
  if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
50861
51114
  merged.colors = alignAccentsToSurfaces(mergedColors, tokens.colors);
50862
51115
  }
50863
- writeFileSync22(pkgTokens, JSON.stringify(merged, null, 2) + "\n");
51116
+ writeFileSync23(pkgTokens, JSON.stringify(merged, null, 2) + "\n");
50864
51117
  wrote.push(pkgTokens);
50865
51118
  }
50866
51119
  const homeAction = homeRefreshActionId(shell);
@@ -50882,7 +51135,7 @@ async function applyOverlays(input) {
50882
51135
  }
50883
51136
  }
50884
51137
  if (next !== prev) {
50885
- writeFileSync22(homeSrc, next);
51138
+ writeFileSync23(homeSrc, next);
50886
51139
  wrote.push(homeSrc);
50887
51140
  }
50888
51141
  if (patched.unparsed) {
@@ -55393,7 +55646,7 @@ __export(site_create_exports, {
55393
55646
  runSiteList: () => runSiteList,
55394
55647
  writeProvisioningBinding: () => writeProvisioningBinding
55395
55648
  });
55396
- import { existsSync as existsSync54, readFileSync as readFileSync65, writeFileSync as writeFileSync23 } from "node:fs";
55649
+ import { existsSync as existsSync54, readFileSync as readFileSync65, writeFileSync as writeFileSync24 } from "node:fs";
55397
55650
  import { resolve as resolvePath2 } from "node:path";
55398
55651
  function oauthClientName(projectName) {
55399
55652
  return `${projectName} client`;
@@ -55542,7 +55795,7 @@ async function runSiteCreate(opts) {
55542
55795
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
55543
55796
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
55544
55797
  }
55545
- function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync54, readFileSync: readFileSync65, writeFileSync: writeFileSync23 }) {
55798
+ function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync54, readFileSync: readFileSync65, writeFileSync: writeFileSync24 }) {
55546
55799
  const msid = binding2.siteId;
55547
55800
  const path = resolvePath2(target);
55548
55801
  const committed = committedShellProvisioning(path);
@@ -55874,7 +56127,7 @@ var init_site_oauth_client = __esm({
55874
56127
  });
55875
56128
 
55876
56129
  // src/cli.ts
55877
- import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync66, mkdirSync as mkdirSync26, writeFileSync as writeFileSync24, existsSync as existsSync55, rmSync as rmSync9, readdirSync as readdirSync25, statSync as statSync13, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
56130
+ import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync66, mkdirSync as mkdirSync27, writeFileSync as writeFileSync25, existsSync as existsSync55, rmSync as rmSync10, readdirSync as readdirSync25, statSync as statSync13, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
55878
56131
  import { execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn5 } from "node:child_process";
55879
56132
  import { createHash as createHash24, randomUUID as randomUUID3 } from "node:crypto";
55880
56133
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
@@ -57685,16 +57938,47 @@ init_wix_owner();
57685
57938
  import { existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
57686
57939
  import { join as join8 } from "node:path";
57687
57940
  var FOREIGN_DETAIL_LIMIT = 25;
57941
+ var MAX_COLLECTION_PAGES = 40;
57688
57942
  async function listCollections(call) {
57689
57943
  try {
57690
- const r = await withRetry(
57691
- "list collections",
57692
- () => call("GET", "/data/v2/collections")
57693
- );
57694
- const collections = r.collections ?? [];
57695
- const total = r.pagingMetadata?.total;
57696
- const unlisted = typeof total === "number" && Number.isFinite(total) ? Math.max(0, total - collections.length) : 0;
57697
- return unlisted > 0 ? { collections, unlisted } : { collections };
57944
+ const collections = [];
57945
+ const seen = /* @__PURE__ */ new Set();
57946
+ let offset = 0;
57947
+ let total;
57948
+ let reachedEnd = false;
57949
+ for (let page = 0; page < MAX_COLLECTION_PAGES; page++) {
57950
+ const path = offset ? `/data/v2/collections?paging.offset=${offset}` : "/data/v2/collections";
57951
+ const r = await withRetry(
57952
+ "list collections",
57953
+ () => call("GET", path)
57954
+ );
57955
+ const batch = r.collections ?? [];
57956
+ const t = r.pagingMetadata?.total;
57957
+ if (typeof t === "number" && Number.isFinite(t)) total = t;
57958
+ let fresh = 0;
57959
+ for (const c of batch) {
57960
+ if (c.id && seen.has(c.id)) continue;
57961
+ if (c.id) seen.add(c.id);
57962
+ collections.push(c);
57963
+ fresh++;
57964
+ }
57965
+ offset += batch.length;
57966
+ if (batch.length === 0) {
57967
+ reachedEnd = true;
57968
+ break;
57969
+ }
57970
+ if (fresh === 0) break;
57971
+ const more = total !== void 0 ? offset < total : r.pagingMetadata?.tooManyToCount === true;
57972
+ if (!more) {
57973
+ reachedEnd = true;
57974
+ break;
57975
+ }
57976
+ }
57977
+ if (total !== void 0) {
57978
+ const unlisted = Math.max(0, total - collections.length);
57979
+ return unlisted > 0 ? { collections, unlisted, incomplete: true } : { collections };
57980
+ }
57981
+ return reachedEnd ? { collections } : { collections, incomplete: true };
57698
57982
  } catch (err) {
57699
57983
  if (err instanceof WixApiError && err.isAppNotInstalled) {
57700
57984
  throw new Error(
@@ -57812,10 +58096,18 @@ async function queryCms(opts) {
57812
58096
  let remote;
57813
58097
  const foreign = [];
57814
58098
  let unlisted = 0;
58099
+ let incomplete = false;
57815
58100
  if (all) {
57816
58101
  const listing = await listCollections(call);
57817
58102
  remote = listing.collections;
57818
58103
  unlisted = listing.unlisted ?? 0;
58104
+ incomplete = listing.incomplete === true;
58105
+ if (incomplete) {
58106
+ const listed = new Set(remote.map((c) => c.id));
58107
+ const unreached = [...declared.keys()].filter((id) => !listed.has(id));
58108
+ const found = await mapLimit(unreached, 4, (id) => getCollection(call, id));
58109
+ remote = [...remote, ...found.filter((c) => c !== null)];
58110
+ }
57819
58111
  } else {
57820
58112
  const found = await mapLimit([...declared.keys()], 4, (id) => getCollection(call, id));
57821
58113
  remote = found.filter((c) => c !== null);
@@ -57861,10 +58153,17 @@ async function queryCms(opts) {
57861
58153
  foreign: {
57862
58154
  count: foreign.length,
57863
58155
  collections: foreign.slice(0, FOREIGN_DETAIL_LIMIT).map(describeForeign),
57864
- ...foreign.length > FOREIGN_DETAIL_LIMIT ? { truncated: foreign.length - FOREIGN_DETAIL_LIMIT } : {}
58156
+ ...foreign.length > FOREIGN_DETAIL_LIMIT ? {
58157
+ truncated: foreign.length - FOREIGN_DETAIL_LIMIT,
58158
+ others: foreign.slice(FOREIGN_DETAIL_LIMIT).map((c) => ({
58159
+ id: c.id,
58160
+ ...c.displayName ? { displayName: c.displayName } : {}
58161
+ }))
58162
+ } : {}
57865
58163
  }
57866
58164
  } : {},
57867
58165
  ...unlisted ? { unlistedCollections: unlisted } : {},
58166
+ ...incomplete ? { listingIncomplete: true } : {},
57868
58167
  siteScanned: all,
57869
58168
  drift
57870
58169
  };
@@ -58593,10 +58892,10 @@ async function iconIssues(dir, strict, opts = {}) {
58593
58892
 
58594
58893
  // src/font-lint.ts
58595
58894
  init_fonts();
58596
- function fontIssues(dir, strict) {
58895
+ async function fontIssues(dir, strict, opts = {}) {
58597
58896
  let result;
58598
58897
  try {
58599
- result = fontFindings(dir);
58898
+ result = await fontFindings(dir, opts);
58600
58899
  } catch {
58601
58900
  return [];
58602
58901
  }
@@ -58605,8 +58904,10 @@ function fontIssues(dir, strict) {
58605
58904
  screen: null,
58606
58905
  pass: "fonts",
58607
58906
  // A warning stays a warning under --strict only if it is genuinely advisory; the
58608
- // budget note is. Everything `fontFindings` calls an error already is one.
58609
- severity: f.severity === "error" ? "error" : strict ? "error" : "warning",
58907
+ // budget note is. Everything `fontFindings` calls an error already is one — except a
58908
+ // family that falls back on web because its faces could not be fetched off-repo, which
58909
+ // this door, feeding `himi push`, reports as a warning: see `FontFinding.webFallback`.
58910
+ severity: f.severity === "error" && !f.webFallback ? "error" : strict ? "error" : "warning",
58610
58911
  message: f.message
58611
58912
  }));
58612
58913
  }
@@ -58769,7 +59070,7 @@ function auditUx(content, strict = false) {
58769
59070
 
58770
59071
  // src/guides.ts
58771
59072
  init_mobile_ux_contract();
58772
- import { readFileSync as readFileSync23, existsSync as existsSync23, mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, copyFileSync as copyFileSync2 } from "node:fs";
59073
+ import { readFileSync as readFileSync23, existsSync as existsSync23, mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, copyFileSync as copyFileSync2 } from "node:fs";
58773
59074
  import { fileURLToPath as fileURLToPath10 } from "node:url";
58774
59075
  import { dirname as dirname14, join as join26, resolve as resolve17 } from "node:path";
58775
59076
  var GUIDES_DIR = resolve17(dirname14(fileURLToPath10(import.meta.url)), "../guides");
@@ -58913,13 +59214,13 @@ function writeAgentContext(targetDir) {
58913
59214
  const files = [];
58914
59215
  const write2 = (rel, body) => {
58915
59216
  const p = join26(targetDir, rel);
58916
- mkdirSync10(dirname14(p), { recursive: true });
58917
- writeFileSync9(p, body);
59217
+ mkdirSync11(dirname14(p), { recursive: true });
59218
+ writeFileSync10(p, body);
58918
59219
  files.push(rel);
58919
59220
  };
58920
59221
  const copy = (srcRel, destRel) => {
58921
59222
  const p = join26(targetDir, destRel);
58922
- mkdirSync10(dirname14(p), { recursive: true });
59223
+ mkdirSync11(dirname14(p), { recursive: true });
58923
59224
  copyFileSync2(join26(GUIDES_DIR, srcRel), p);
58924
59225
  files.push(destRel);
58925
59226
  };
@@ -59168,9 +59469,11 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
59168
59469
  tokenless discovery path. Foreign collections are
59169
59470
  described up to a cap and never item-counted;
59170
59471
  foreign.truncated says how many of the LISTED ones
59171
- went undescribed, and unlistedCollections what the
59172
- listing left out (the list endpoint is paged and is
59173
- not followed, so foreign.count is not a census).
59472
+ went undescribed, and foreign.others still names
59473
+ each of them (id + displayName). The listing's pages
59474
+ are followed; listingIncomplete: true says the walk
59475
+ stopped short of the end, and unlistedCollections
59476
+ says how many it left out when Wix gave a total.
59174
59477
  create reconciles only himi_<app>_* ; seed fills
59175
59478
  EMPTY owned collections from the config's seed: rows
59176
59479
  (--ai writes rows for you to review first)
@@ -59681,7 +59984,7 @@ var COMMANDS = [
59681
59984
  { name: "test", summary: "DERIVED behavioral crawl \u2014 no test files to write. Boots each screen's real worker, replays its onAppear, then dispatches every action site the descriptor already declares (each from a fresh boot) and checks a narrow set of unambiguous invariants: no uncaught throw, never stuck on `loading`, no `$service:` token or NaN/undefined/[object Object] reaching visible text, no binding aimed at state the worker never defines, no nav param silently dropped, no dead nav target. Catches what validate/render cannot \u2014 a WRONG REDUCER passes both with ok:true. Runs the worker in a DEVICE-PARITY sandbox (no setTimeout/setInterval, as on JSC/WebView) so a bundle that would die on device fails here. Crawls on HERMETIC DATA by default \u2014 zero network: the app's own dev/net-mocks.json first (--net <file> overrides), then the config's CMS `seed:` rows, then a canned fixture of frozen real vertical responses shipped with the CLI (exercises code paths, not API-contract truth) \u2014 so the success/mapping path runs, not just the failure UI. Two boot-only HOSTILE passes (every list empty; every request 500) then check the failure/empty day \u2014 corpus-proven, so their findings are errors. NAV EDGES are followed too: every himi.open site ($item params resolved against row 0 of its list, $service against worker state) and worker _nav directive is harvested, and each baked target is booted WITH the params the source sends \u2014 detail screens finally run their content arm; edge findings are errors tagged edge:<source>. --native runs both real native decoders over the exact baked JSON bytes; --native ios or --native android selects one. It is explicit, runs only from a Himalaya SOURCE CHECKOUT (the decoder oracles are that tree's own HimalayaCore Swift package and Gradle harness, which a published install does not ship), and needs the selected local toolchain. From a source checkout, default runs name missing native verdicts in the coverage ledger; elsewhere the ledger stays silent about them rather than offering a remedy you cannot run. --offline strips all data layers (the old reject-all axis); --no-hostile skips the hostile passes. --record (EXPLICIT, never automatic) refreshes dev/net-mocks.json from live reads first: it boots each screen (load + root onAppear ONLY \u2014 nothing the app's own launch would not fire; the tap/action crawl never sees the live transport, and only proven reads \u2014 GET, or read-shaped POST (/query, /search, /list*, \u2026) \u2014 ever reach the wire), freezes the round-trips, then crawls hermetically on the fresh fixture; record against a QA site, not production. Nodes it cannot judge headless are named, never silently passed. Exit 1 on any error. The CLI carries the authoring runtime off-repo; no per-app SDK install is required. --browser runs the whole loop (build \u2192 extract \u2192 validate \u2192 render \u2192 test) in YOUR browser instead of here, so the source never reaches a pod: it opens one screen's worker + descriptor in a tab, blocks on a loopback callback, and prints the report it posts back. One screen per tab \u2014 name it. --no-open prints the URL rather than launching a browser (SSH); --timeout <ms> bounds the wait, which matters because the page has no execution deadline of its own and an infinite loop in the worker hangs the tab.", required: "[<screenId>\u2026] [--content <dir>] [--net <file>] [--budget <ms>] [--deep [n]] [--record] [--native [ios|android]] [--no-shots] [--offline] [--no-hostile] [--all-screens] [--browser] [--no-open] [--timeout <ms>] [--json]" },
59682
59985
  { name: "ux", summary: "audit or record mobile UX evidence. `audit` checks the public-safe contract, seeded blank acceptance rows, placeholder source copy, app-specific mocks, and iOS/Android audit records. It warns while existing templates migrate; `--strict` promotes missing evidence. `record` stores checks performed on an installed iOS/Android build: `--checks` is required for passed|failed and empty for unavailable, which drove nothing and needs a `--reason` instead. `record` also STAMPS the release it audited (it resolves the id from a build, the same one a push would publish), because an unforced `himi push` of a release with screens refuses when no drive is recorded for THAT release, or when the one that is recorded says `failed` \u2014 the artifact stopped being advice nobody reads (#2955). `unavailable` still satisfies it; only `failed` refuses.", required: "audit [--content <dir>] [--strict] [--json] | record --content <dir> --platform ios|android --status passed|failed|unavailable [--checks back,keyboard,...] [--reason <text>]" },
59683
59986
  { name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png <file>, --scheme dark, --tree. Local by default (content dir). Pass --remote --app --release to hit GET /v1/preview/\u2026/render on the serve plane after a push. Boots the worker so $service bindings resolve; --static raw bindings; --live real Wix fetches; --state injects worker state; --input supplies pre-boot navigation params; --width/--device for PNG viewport; --rtl for dir=rtl + $env:isRTL.", required: "<screenId> [--content <dir>] [--scheme dark] [--png <file>] [--tree] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--remote --app --release]" },
59684
- { name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 NOT a site census, since the list endpoint is paged and is not followed \u2014 and `foreign.truncated` says how many of those went undescribed, while `unlistedCollections` reports what the listing itself left out (from Wix's own paging total). The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
59987
+ { name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 it follows the list endpoint's pages, and `listingIncomplete: true` says when the walk stopped short of the end, with `unlistedCollections` counting what it left out when Wix gave a paging total \u2014 and `foreign.truncated` says how many of those went undescribed, each still NAMED in `foreign.others` (id + displayName), so a collection the site already has is never hidden behind the cap. The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
59685
59988
  { name: "data", summary: "read-only plan or explicitly provision/seed declared KV and Wix Data resources. Preview and production are separate scopes. KV administration uses the operator data plane from --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN; draft push never calls it.", required: "plan|create|seed [--site <msid>] [--environment preview|production] [--content <dir>] [--data-url <url>] [--dry-run] [--force]" },
59686
59989
  { name: "icons", summary: "list the valid Icon.name vocabulary (an unknown name renders a fallback glyph; validate warns on unknown names) (offline)", required: "[--json]" },
59687
59990
  { name: "icon", summary: "the app's LAUNCHER icon \u2014 the home-screen / store mark, which is BINARY-floor and never over-the-air (distinct from `himi icons`, the in-screen glyph vocabulary). `status`/`check` report what this app would actually ship and validate it against both stores: exact 1024x1024, no tRNS chunk, non-interlaced, and \u2014 when the optional image toolchain is installed \u2014 no transparent regions (Apple permits an alpha channel but not transparent pixels: ITMS-90717), no pre-masked corners, no letterboxed wordmark; they also print the store-policy checklist no checker can decide. `set <file.png>` installs supplied art, `from-site` installs the logo `himi site analyze` downloaded, and `generate` makes a gradient tile + glyph \u2014 all three trim, flatten onto the app's accent, write the 1024 opaque master plus the 512 Play listing icon (Play wants 32-bit WITH alpha, so it is a separate file), and DECLARE it in himalaya.content.json, without which the release bakes no icon at all", required: "[status|check] | set <file.png> | from-site [--book <dir>] | generate [--glyph <g>] [--accent <hex>] | glyphs [--content <dir>] [--json]" },
@@ -59901,8 +60204,8 @@ function readUpdateCache(path) {
59901
60204
  }
59902
60205
  function writeUpdateCache(path, cache) {
59903
60206
  try {
59904
- mkdirSync26(dirname31(path), { recursive: true, mode: 448 });
59905
- writeFileSync24(path, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
60207
+ mkdirSync27(dirname31(path), { recursive: true, mode: 448 });
60208
+ writeFileSync25(path, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
59906
60209
  } catch {
59907
60210
  }
59908
60211
  }
@@ -60043,7 +60346,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
60043
60346
  };
60044
60347
  const tryCreate = (path) => {
60045
60348
  try {
60046
- writeFileSync24(path, mine, { flag: "wx", mode: 384 });
60349
+ writeFileSync25(path, mine, { flag: "wx", mode: 384 });
60047
60350
  return true;
60048
60351
  } catch {
60049
60352
  return false;
@@ -60051,13 +60354,13 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
60051
60354
  };
60052
60355
  const removeIfMine = (path) => {
60053
60356
  try {
60054
- if (readLock(path) === mine) rmSync9(path, { force: true });
60357
+ if (readLock(path) === mine) rmSync10(path, { force: true });
60055
60358
  } catch {
60056
60359
  }
60057
60360
  };
60058
60361
  const release = () => removeIfMine(lockPath);
60059
60362
  try {
60060
- mkdirSync26(dirname31(lockPath), { recursive: true, mode: 448 });
60363
+ mkdirSync27(dirname31(lockPath), { recursive: true, mode: 448 });
60061
60364
  } catch {
60062
60365
  return () => {
60063
60366
  };
@@ -60074,7 +60377,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
60074
60377
  hooks.underBreakLock?.();
60075
60378
  if (current === void 0) return tryCreate(lockPath) ? release : void 0;
60076
60379
  if (!isAbandoned(current)) return void 0;
60077
- rmSync9(lockPath, { force: true });
60380
+ rmSync10(lockPath, { force: true });
60078
60381
  return tryCreate(lockPath) ? release : void 0;
60079
60382
  } finally {
60080
60383
  removeIfMine(breakPath);
@@ -60696,8 +60999,8 @@ function readConfigSource(dir) {
60696
60999
  }
60697
61000
  }
60698
61001
  function writePngFile(path, base64) {
60699
- mkdirSync26(dirname31(path), { recursive: true });
60700
- writeFileSync24(path, Buffer.from(base64, "base64"));
61002
+ mkdirSync27(dirname31(path), { recursive: true });
61003
+ writeFileSync25(path, Buffer.from(base64, "base64"));
60701
61004
  return path;
60702
61005
  }
60703
61006
  async function initFromRemoteTemplate(name, parentDir, template, c) {
@@ -60817,14 +61120,14 @@ function materializeForPreview(appDir2, slug, displayName) {
60817
61120
  if (!entry.isDirectory()) continue;
60818
61121
  const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
60819
61122
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
60820
- rmSync9(join52(root, entry.name), { recursive: true, force: true });
61123
+ rmSync10(join52(root, entry.name), { recursive: true, force: true });
60821
61124
  }
60822
61125
  }
60823
61126
  } catch {
60824
61127
  }
60825
61128
  const dest = join52(root, `${slug}-${process.pid}`);
60826
- rmSync9(dest, { recursive: true, force: true });
60827
- mkdirSync26(dest, { recursive: true });
61129
+ rmSync10(dest, { recursive: true, force: true });
61130
+ mkdirSync27(dest, { recursive: true });
60828
61131
  materializeSource(forBuild, displayName, dest, slug);
60829
61132
  return dest;
60830
61133
  }
@@ -61075,7 +61378,7 @@ async function recordedReleaseForContentQuietly(dir, resolution) {
61075
61378
  return null;
61076
61379
  } finally {
61077
61380
  if (out !== void 0) try {
61078
- rmSync9(out, { recursive: true, force: true });
61381
+ rmSync10(out, { recursive: true, force: true });
61079
61382
  } catch {
61080
61383
  }
61081
61384
  }
@@ -61630,7 +61933,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
61630
61933
  const scaffoldSourceFindings = resolve44(sourceDir) === resolve44(appDir2) ? [] : [
61631
61934
  ...tokenColorIssues(sourceDir),
61632
61935
  ...surfaceIssues(sourceDir, void 0, strict),
61633
- ...fontIssues(sourceDir, strict),
61936
+ ...await fontIssues(sourceDir, strict),
61634
61937
  ...storesV1Issues(sourceDir, strict)
61635
61938
  ].map((issue2) => ({
61636
61939
  ...issue2,
@@ -61643,7 +61946,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
61643
61946
  ...await cmsIssues(buildDir, app, strict, { local: true }),
61644
61947
  ...surfaceIssues(buildDir, outcome.surfaceNav, strict),
61645
61948
  ...tokenColorIssues(buildDir),
61646
- ...fontIssues(buildDir, strict),
61949
+ ...await fontIssues(buildDir, strict),
61647
61950
  ...storesV1Issues(buildDir, strict),
61648
61951
  ...await navIssues2(buildDir, strict),
61649
61952
  ...scaffoldSourceFindings
@@ -61918,7 +62221,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
61918
62221
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
61919
62222
  ...tokenColorIssues(dir),
61920
62223
  ...await iconIssues(dir, strict),
61921
- ...fontIssues(dir, strict),
62224
+ ...await fontIssues(dir, strict),
61922
62225
  ...mobileUxIssues2(dir, strict),
61923
62226
  ...await navIssues2(dir, strict),
61924
62227
  ...storesV1Issues(dir, strict),
@@ -62409,7 +62712,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62409
62712
  renderDescriptorWeb: renderDescriptorWeb2,
62410
62713
  renderPngBatch: renderPngBatch2,
62411
62714
  writePng: (path, base64) => writePngFile(path, base64),
62412
- clearDir: (d) => rmSync9(d, { recursive: true, force: true })
62715
+ clearDir: (d) => rmSync10(d, { recursive: true, force: true })
62413
62716
  }
62414
62717
  });
62415
62718
  writtenShots = sp.written;
@@ -62702,7 +63005,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
62702
63005
  return report2.ok ? 0 : 1;
62703
63006
  }
62704
63007
  if (sub === "check") {
62705
- const report2 = checkReport2(dir);
63008
+ const report2 = await checkReport2(dir);
62706
63009
  print(report2);
62707
63010
  return report2.ok ? 0 : 1;
62708
63011
  }
@@ -63102,7 +63405,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63102
63405
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
63103
63406
  ...tokenColorIssues(dir),
63104
63407
  ...await iconIssues(dir, strict),
63105
- ...fontIssues(dir, strict),
63408
+ ...await fontIssues(dir, strict),
63106
63409
  ...storesV1Issues(dir, strict),
63107
63410
  ...await navIssues2(dir, strict)
63108
63411
  ]);
@@ -63614,12 +63917,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63614
63917
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
63615
63918
  ...tokenColorIssues(dir),
63616
63919
  ...await iconIssues(dir, strict),
63617
- ...fontIssues(dir, strict),
63920
+ ...await fontIssues(dir, strict),
63618
63921
  ...storesV1Issues(dir, strict),
63619
63922
  ...await navIssues2(dir, strict)
63620
63923
  ]);
63621
63924
  if (hasErrors && !force) {
63622
- rmSync9(built, { recursive: true, force: true });
63925
+ rmSync10(built, { recursive: true, force: true });
63623
63926
  print({ ...report2, packed: false, hint: "lint found errors \u2014 fix them, or re-run `himi pack --force` to pack anyway" });
63624
63927
  return 1;
63625
63928
  }
@@ -63655,7 +63958,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63655
63958
  io.error(JSON.stringify({ error: e.message }));
63656
63959
  return 1;
63657
63960
  } finally {
63658
- rmSync9(built, { recursive: true, force: true });
63961
+ rmSync10(built, { recursive: true, force: true });
63659
63962
  }
63660
63963
  }
63661
63964
  // ---- himi import — turn a dev .himi back into an editable content package ----
@@ -63908,7 +64211,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63908
64211
  io.error(JSON.stringify({ error: e.message }));
63909
64212
  return 1;
63910
64213
  } finally {
63911
- if (temp) rmSync9(temp, { recursive: true, force: true });
64214
+ if (temp) rmSync10(temp, { recursive: true, force: true });
63912
64215
  }
63913
64216
  }
63914
64217
  case "preview": {