@wix/himalaya-cli 0.1030.0 → 0.1032.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.
Files changed (124) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-config.d.ts +7 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/wix-gateway.d.ts +32 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/wix-gateway.rules.d.ts +2 -1
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +7 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/genie-chat/src/index.d.ts +64 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-genie-chat.mjs +41 -1
  7. package/dist/cli.mjs +386 -132
  8. package/dist/preview-assets.generated.bin +0 -0
  9. package/guides/mobile-ux.md +3 -2
  10. package/guides/qa-builds.md +22 -13
  11. package/guides/sdk-reference.json +50 -2
  12. package/package.json +2 -2
  13. package/templates/beauty-salon/tier5-src/_shared/owner-load-error.ts +7 -1
  14. package/templates/beauty-salon-owner/config.ts +1 -1
  15. package/templates/beauty-salon-owner/dev/index.ts +247 -9
  16. package/templates/beauty-salon-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  17. package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +405 -20
  18. package/templates/beauty-salon-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  19. package/templates/beauty-salon-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  20. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  21. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  22. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  23. package/templates/branded-lite/tier5-src/_shared/owner-load-error.ts +7 -1
  24. package/templates/community-club/tier5-src/_shared/owner-load-error.ts +7 -1
  25. package/templates/community-club-owner/config.ts +1 -1
  26. package/templates/community-club-owner/dev/index.ts +247 -9
  27. package/templates/community-club-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  28. package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +405 -20
  29. package/templates/community-club-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  30. package/templates/community-club-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  31. package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  32. package/templates/community-club-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  33. package/templates/community-club-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  34. package/templates/events-meetups/tier5-src/_shared/owner-load-error.ts +7 -1
  35. package/templates/events-meetups-owner/config.ts +1 -1
  36. package/templates/events-meetups-owner/dev/index.ts +247 -9
  37. package/templates/events-meetups-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  38. package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +405 -20
  39. package/templates/events-meetups-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  40. package/templates/events-meetups-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  41. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  42. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  43. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  44. package/templates/gym-fitness/tier5-src/_shared/owner-load-error.ts +7 -1
  45. package/templates/gym-fitness-owner/config.ts +1 -1
  46. package/templates/gym-fitness-owner/dev/index.ts +247 -9
  47. package/templates/gym-fitness-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  48. package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +405 -20
  49. package/templates/gym-fitness-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  50. package/templates/gym-fitness-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  51. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  52. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  53. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  54. package/templates/himi-chat/tier5-src/_shared/owner-load-error.ts +7 -1
  55. package/templates/nonprofit-cause/tier5-src/_shared/owner-load-error.ts +7 -1
  56. package/templates/nonprofit-cause-owner/config.ts +1 -1
  57. package/templates/nonprofit-cause-owner/dev/index.ts +247 -9
  58. package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  59. package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +405 -20
  60. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  61. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  62. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  63. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  64. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  65. package/templates/owner-lite/config.ts +1 -1
  66. package/templates/owner-lite/dev/index.ts +247 -9
  67. package/templates/owner-lite/tier5-src/_shared/aria-attachments.ts +179 -0
  68. package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +405 -20
  69. package/templates/owner-lite/tier5-src/_shared/owner-bookings.ts +20 -0
  70. package/templates/owner-lite/tier5-src/_shared/owner-load-error.ts +7 -1
  71. package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  72. package/templates/owner-lite/tier5-src/himi-owner-lite-home/index.ts +2 -12
  73. package/templates/owner-lite/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  74. package/templates/podcast-creator/tier5-src/_shared/owner-load-error.ts +7 -1
  75. package/templates/podcast-creator-owner/config.ts +1 -1
  76. package/templates/podcast-creator-owner/dev/index.ts +247 -9
  77. package/templates/podcast-creator-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  78. package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +405 -20
  79. package/templates/podcast-creator-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  80. package/templates/podcast-creator-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  81. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  82. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  83. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  84. package/templates/portfolio-creative/tier5-src/_shared/owner-load-error.ts +7 -1
  85. package/templates/portfolio-creative-owner/config.ts +1 -1
  86. package/templates/portfolio-creative-owner/dev/index.ts +247 -9
  87. package/templates/portfolio-creative-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  88. package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +405 -20
  89. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  90. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  91. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  92. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  93. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  94. package/templates/restaurant/tier5-src/_shared/owner-load-error.ts +7 -1
  95. package/templates/restaurant-owner/config.ts +1 -1
  96. package/templates/restaurant-owner/dev/index.ts +247 -9
  97. package/templates/restaurant-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  98. package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +405 -20
  99. package/templates/restaurant-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  100. package/templates/restaurant-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  101. package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  102. package/templates/restaurant-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  103. package/templates/restaurant-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  104. package/templates/retail-store/tier5-src/_shared/owner-load-error.ts +7 -1
  105. package/templates/retail-store-owner/config.ts +1 -1
  106. package/templates/retail-store-owner/dev/index.ts +247 -9
  107. package/templates/retail-store-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  108. package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +405 -20
  109. package/templates/retail-store-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  110. package/templates/retail-store-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  111. package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  112. package/templates/retail-store-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  113. package/templates/retail-store-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
  114. package/templates/surface-showcase/dev/index.ts +1 -1
  115. package/templates/yoga-studio/tier5-src/_shared/owner-load-error.ts +7 -1
  116. package/templates/yoga-studio-owner/config.ts +1 -1
  117. package/templates/yoga-studio-owner/dev/index.ts +247 -9
  118. package/templates/yoga-studio-owner/tier5-src/_shared/aria-attachments.ts +179 -0
  119. package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +405 -20
  120. package/templates/yoga-studio-owner/tier5-src/_shared/owner-bookings.ts +20 -0
  121. package/templates/yoga-studio-owner/tier5-src/_shared/owner-load-error.ts +7 -1
  122. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +40 -1
  123. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-home/index.ts +2 -12
  124. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-manage/index.ts +10 -4
package/dist/cli.mjs CHANGED
@@ -1264,6 +1264,26 @@ var init_compiler_options = __esm({
1264
1264
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync, lstatSync, copyFileSync } from "node:fs";
1265
1265
  import { resolve as resolve2, join as join3, dirname as dirname2 } from "node:path";
1266
1266
  import { fileURLToPath } from "node:url";
1267
+ function keptPlanNote(kept) {
1268
+ if (!kept?.length) return void 0;
1269
+ const pronoun = kept.length === 1 ? "it" : "them";
1270
+ return `kept your existing ${kept.join(" and ")} \u2014 init did not overwrite ${pronoun}. Check ${pronoun} against \`himi docs mobile-ux\` (the headings \`validate --strict\` requires) before implementing.`;
1271
+ }
1272
+ function gitignoreKey(line) {
1273
+ return line.trim().replace(/^\//, "").replace(/\/$/, "");
1274
+ }
1275
+ function ensurePackageGitignore(res) {
1276
+ const dest = join3(res.dir, ".gitignore");
1277
+ const existing = existsSync2(dest) ? readFileSync3(dest, "utf8") : null;
1278
+ const present = new Set((existing ?? "").split(/\r?\n/).map(gitignoreKey));
1279
+ const missing = PACKAGE_GITIGNORE.filter((entry) => !present.has(gitignoreKey(entry)));
1280
+ if (missing.length === 0) return res;
1281
+ const prefix = existing === null ? "" : existing.length === 0 || existing.endsWith("\n") ? existing : `${existing}
1282
+ `;
1283
+ writeFileSync3(dest, `${prefix}${missing.join("\n")}
1284
+ `);
1285
+ return res.files.includes(".gitignore") ? res : { ...res, files: [...res.files, ".gitignore"].sort() };
1286
+ }
1267
1287
  function defaultPackageJson(name) {
1268
1288
  return JSON.stringify(
1269
1289
  {
@@ -1364,9 +1384,14 @@ function sentinelizeArchive(raw, fallbackName) {
1364
1384
  }
1365
1385
  function materializeSource(files, name, destDir, slug = name) {
1366
1386
  const written = [];
1387
+ const kept = [];
1367
1388
  for (const [rel, body] of Object.entries(files)) {
1368
1389
  if (rel === TEMPLATE_META_FILE) continue;
1369
1390
  const dest = join3(destDir, rel);
1391
+ if (PLAN_FILES.has(rel) && existsSync2(dest)) {
1392
+ kept.push(rel);
1393
+ continue;
1394
+ }
1370
1395
  mkdirSync3(resolve2(dest, ".."), { recursive: true });
1371
1396
  const materialized = substituteIdentity(body, name, slug);
1372
1397
  writeFileSync3(dest, MODULE_SOURCE_FILE.test(rel) ? offRepoImports(materialized) : materialized);
@@ -1375,6 +1400,10 @@ function materializeSource(files, name, destDir, slug = name) {
1375
1400
  for (const [rel, body] of [["SPEC.md", SPEC_TEMPLATE], ["MOBILE-UX.md", MOBILE_UX_TEMPLATE]]) {
1376
1401
  if (Object.prototype.hasOwnProperty.call(files, rel)) continue;
1377
1402
  const dest = join3(destDir, rel);
1403
+ if (existsSync2(dest)) {
1404
+ kept.push(rel);
1405
+ continue;
1406
+ }
1378
1407
  mkdirSync3(resolve2(dest, ".."), { recursive: true });
1379
1408
  writeFileSync3(dest, body);
1380
1409
  written.push(rel);
@@ -1390,19 +1419,20 @@ function materializeSource(files, name, destDir, slug = name) {
1390
1419
  written.push("tsconfig.json");
1391
1420
  }
1392
1421
  written.sort();
1393
- return { dir: destDir, files: written };
1422
+ return { dir: destDir, files: written, ...kept.length ? { kept: kept.sort() } : {} };
1394
1423
  }
1395
- function finishScaffold(res, template) {
1424
+ function finishScaffold(scaffolded, template) {
1425
+ const res = ensurePackageGitignore(scaffolded);
1396
1426
  if (!template) return res;
1397
1427
  const dest = join3(res.dir, "icon.png");
1398
1428
  if (existsSync2(dest)) {
1399
1429
  if (res.files.includes("icon.png")) return res;
1400
- return { dir: res.dir, files: [...res.files, "icon.png"].sort() };
1430
+ return { ...res, files: [...res.files, "icon.png"].sort() };
1401
1431
  }
1402
1432
  const src = templateIconPath(template);
1403
1433
  if (!src) return res;
1404
1434
  copyFileSync(src, dest);
1405
- return { dir: res.dir, files: [...res.files, "icon.png"].sort() };
1435
+ return { ...res, files: [...res.files, "icon.png"].sort() };
1406
1436
  }
1407
1437
  function isBinaryTemplateFile(rel) {
1408
1438
  return BINARY_EXTENSIONS.has(extOf(rel));
@@ -1448,8 +1478,13 @@ function scaffoldContentPackage(name, parentDir, template) {
1448
1478
  const idSeg = name.replace(/[^a-z0-9]/gi, "").toLowerCase() || "app";
1449
1479
  const appId2 = `com.example.${idSeg}`;
1450
1480
  const files = [];
1481
+ const kept = [];
1451
1482
  const write2 = (rel, body) => {
1452
1483
  const p = join3(dir, rel);
1484
+ if (PLAN_FILES.has(rel) && existsSync2(p)) {
1485
+ kept.push(rel);
1486
+ return;
1487
+ }
1453
1488
  mkdirSync3(resolve2(p, ".."), { recursive: true });
1454
1489
  writeFileSync3(p, body);
1455
1490
  files.push(rel);
@@ -1641,14 +1676,16 @@ A per-app \`npm i @wix/himalaya\` is optional and only buys your editor local ty
1641
1676
  himi agent-init # seed this dir with HIMALAYA.md + reference + example
1642
1677
  `
1643
1678
  );
1644
- return { dir, files };
1679
+ return finishScaffold({ dir, files, ...kept.length ? { kept: kept.sort() } : {} });
1645
1680
  }
1646
- var MODULE_SOURCE_FILE, TEMPLATES_DIR, SHOWCASE_TEMPLATES_DIR, SHOWCASE_TEMPLATE_NAMES, TEMPLATE_META_FILE, TEMPLATE_ICONS_DIR, HEX_COLOR, PALETTE_KEYS, IDENTITY_SENTINELS, escapeRe, NAME_FIELDS, IDENTITY_FILES, DOTID_RE, BINARY_EXTENSIONS, extOf;
1681
+ var PLAN_FILES, PACKAGE_GITIGNORE, MODULE_SOURCE_FILE, TEMPLATES_DIR, SHOWCASE_TEMPLATES_DIR, SHOWCASE_TEMPLATE_NAMES, TEMPLATE_META_FILE, TEMPLATE_ICONS_DIR, HEX_COLOR, PALETTE_KEYS, IDENTITY_SENTINELS, escapeRe, NAME_FIELDS, IDENTITY_FILES, DOTID_RE, BINARY_EXTENSIONS, extOf;
1647
1682
  var init_scaffold = __esm({
1648
1683
  "src/scaffold.ts"() {
1649
1684
  init_source_deny();
1650
1685
  init_mobile_ux_contract();
1651
1686
  init_compiler_options();
1687
+ PLAN_FILES = /* @__PURE__ */ new Set(["SPEC.md", "MOBILE-UX.md"]);
1688
+ PACKAGE_GITIGNORE = [".himi/", "dist/", "node_modules/"];
1652
1689
  MODULE_SOURCE_FILE = /\.(?:[cm]?[jt]sx?)$/i;
1653
1690
  TEMPLATES_DIR = resolve2(dirname2(fileURLToPath(import.meta.url)), "../templates");
1654
1691
  SHOWCASE_TEMPLATES_DIR = resolve2(dirname2(fileURLToPath(import.meta.url)), "../showcase-apps");
@@ -16806,16 +16843,33 @@ function redactBodyString(body) {
16806
16843
  function createWixGatewayState() {
16807
16844
  return { mode: "record", rules: [], traffic: [], clients: /* @__PURE__ */ new Set(), seq: 0, ruleSeq: 0 };
16808
16845
  }
16846
+ function failsClosed(gw) {
16847
+ return gw.mode === "mock" && gw.unmatched === "fail";
16848
+ }
16849
+ function hermeticRefusal(method, path2) {
16850
+ return {
16851
+ status: 404,
16852
+ headers: { "content-type": "application/json; charset=utf-8" },
16853
+ body: JSON.stringify({
16854
+ message: `No hermetic fixture for ${method} ${path2}. The dev gateway is sealed (mode: mock, unmatched: fail), so this call was not sent to Wix. Add a rule to the app's net mocks.`,
16855
+ details: { applicationError: { code: "HIMI_HERMETIC_NO_FIXTURE", description: `${method} ${path2}` } }
16856
+ })
16857
+ };
16858
+ }
16859
+ function parseUnmatched(value) {
16860
+ return value === "fail" || value === "passthrough" ? value : void 0;
16861
+ }
16809
16862
  function applyNetMocks(gw, mocks) {
16810
16863
  const rules = Array.isArray(mocks.rules) ? mocks.rules : [];
16811
16864
  gw.rules = rules.map((r) => ({ ...r, id: r.id || ++gw.ruleSeq }));
16812
16865
  gw.mode = mocks.mode ?? (gw.rules.length > 0 ? "mock" : gw.mode);
16866
+ gw.unmatched = parseUnmatched(mocks.unmatched) ?? "passthrough";
16813
16867
  return { rules: gw.rules.length, mode: gw.mode };
16814
16868
  }
16815
16869
  function resolveNetMocks(fileMocks, appDeclared) {
16816
16870
  if (fileMocks) return { mocks: fileMocks, source: "file" };
16817
16871
  const declared = Array.isArray(appDeclared?.rules) ? appDeclared.rules : [];
16818
- if (declared.length > 0) return { mocks: { mode: appDeclared?.mode, rules: declared }, source: "app" };
16872
+ if (declared.length > 0) return { mocks: { mode: appDeclared?.mode, rules: declared, unmatched: appDeclared?.unmatched }, source: "app" };
16819
16873
  return null;
16820
16874
  }
16821
16875
  function readNetMocksFile(path2) {
@@ -16826,7 +16880,7 @@ function readNetMocksFile(path2) {
16826
16880
  if (raw && typeof raw === "object") {
16827
16881
  const o = raw;
16828
16882
  if (!Array.isArray(o.rules) || wixMockRuleErrors(o.rules).length) return null;
16829
- return { mode: o.mode, rules: o.rules };
16883
+ return { mode: o.mode, rules: o.rules, unmatched: parseUnmatched(o.unmatched) };
16830
16884
  }
16831
16885
  return null;
16832
16886
  } catch {
@@ -16984,17 +17038,22 @@ data: ${JSON.stringify({ mode: gw.mode })}
16984
17038
  }
16985
17039
  if (suffix === "mode" && method === "POST") {
16986
17040
  try {
16987
- const { mode } = JSON.parse(await readBody(req));
17041
+ const { mode, unmatched } = JSON.parse(await readBody(req));
16988
17042
  if (mode === "record" || mode === "mock") {
16989
17043
  gw.mode = mode;
16990
17044
  gw.operatorOverride = true;
16991
17045
  }
17046
+ const policy = parseUnmatched(unmatched);
17047
+ if (policy) {
17048
+ gw.unmatched = policy;
17049
+ gw.operatorOverride = true;
17050
+ }
16992
17051
  } catch {
16993
17052
  }
16994
- return json(res, 200, { ok: true, mode: gw.mode }), true;
17053
+ return json(res, 200, { ok: true, mode: gw.mode, unmatched: gw.unmatched ?? "passthrough" }), true;
16995
17054
  }
16996
17055
  if (suffix === "rules" && method === "GET") {
16997
- return json(res, 200, { mode: gw.mode, rules: gw.rules }), true;
17056
+ return json(res, 200, { mode: gw.mode, unmatched: gw.unmatched ?? "passthrough", rules: gw.rules }), true;
16998
17057
  }
16999
17058
  if (suffix === "rules" && method === "PUT") {
17000
17059
  try {
@@ -17048,8 +17107,38 @@ data: ${JSON.stringify({ mode: gw.mode })}
17048
17107
  return true;
17049
17108
  }
17050
17109
  if (!target) {
17110
+ recordWixTraffic(gw, app, adminUrl, {
17111
+ ts: started,
17112
+ source: "proxy",
17113
+ capability,
17114
+ host,
17115
+ method: upstreamMethod,
17116
+ url: "",
17117
+ path: targetPath,
17118
+ status: 400,
17119
+ durationMs: Date.now() - started
17120
+ });
17051
17121
  return json(res, 400, { error: "missing_target" }), true;
17052
17122
  }
17123
+ if (!match && failsClosed(gw)) {
17124
+ const refusal = hermeticRefusal(upstreamMethod, targetPath);
17125
+ recordWixTraffic(gw, app, adminUrl, {
17126
+ ts: started,
17127
+ source: "mock",
17128
+ capability,
17129
+ host,
17130
+ method: upstreamMethod,
17131
+ url: target,
17132
+ path: targetPath,
17133
+ status: refusal.status,
17134
+ durationMs: Date.now() - started,
17135
+ mockRuleId: UNMATCHED_FAIL_CLOSED_ID
17136
+ });
17137
+ res.statusCode = refusal.status;
17138
+ for (const [k, v] of Object.entries(refusal.headers)) res.setHeader(k, v);
17139
+ res.end(refusal.body);
17140
+ return true;
17141
+ }
17053
17142
  const fwdHeaders = {};
17054
17143
  for (const [k, v] of Object.entries(req.headers)) {
17055
17144
  const lk = k.toLowerCase();
@@ -17129,7 +17218,7 @@ data: ${JSON.stringify({ mode: gw.mode })}
17129
17218
  }
17130
17219
  return false;
17131
17220
  }
17132
- var WIX_DEV_CLIENT_ID, TRAFFIC_CAP, BODY_CAP, SECRET_HEADERS, SECRET_BODY_KEYS, REDACTED, normKey, FORM_ASSIGNMENT_RE, JSON_FIELD_RE, JSON_FIELD_UNTERMINATED_RE, BEARER_RE;
17221
+ var WIX_DEV_CLIENT_ID, TRAFFIC_CAP, BODY_CAP, SECRET_HEADERS, SECRET_BODY_KEYS, REDACTED, normKey, FORM_ASSIGNMENT_RE, JSON_FIELD_RE, JSON_FIELD_UNTERMINATED_RE, BEARER_RE, UNMATCHED_FAIL_CLOSED_ID;
17133
17222
  var init_wix_gateway = __esm({
17134
17223
  "../../core/dev-server/src/wix-gateway.ts"() {
17135
17224
  init_wix_gateway_rules();
@@ -17177,6 +17266,7 @@ var init_wix_gateway = __esm({
17177
17266
  JSON_FIELD_RE = /"([^"\\]+)"(\s*:\s*)"((?:\\.|[^"\\])*)"/g;
17178
17267
  JSON_FIELD_UNTERMINATED_RE = /"([^"\\]+)"(\s*:\s*)"(?:\\.|[^"\\])*$/;
17179
17268
  BEARER_RE = /\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/gi;
17269
+ UNMATCHED_FAIL_CLOSED_ID = "unmatched:fail-closed";
17180
17270
  }
17181
17271
  });
17182
17272
 
@@ -18781,21 +18871,22 @@ async function reseedIfDayChanged(host, today = todayYmd()) {
18781
18871
  if (host.wix.operatorOverride) return { reseeded: false, reason: "operator-override" };
18782
18872
  const declared = host.declaredRules();
18783
18873
  if (!declared?.rules?.length) {
18784
- const before = { mode: host.wix.mode, rules: [...host.wix.rules] };
18785
- host.seed({ mode: declared ? declared.mode : "record", rules: [] });
18786
- if (scenarioChanged(before, { mode: host.wix.mode, rules: host.wix.rules })) {
18874
+ const before = { mode: host.wix.mode, rules: [...host.wix.rules], unmatched: host.wix.unmatched };
18875
+ host.seed({ mode: declared ? declared.mode : "record", rules: [], ...declared?.unmatched ? { unmatched: declared.unmatched } : {} });
18876
+ if (scenarioChanged(before, { mode: host.wix.mode, rules: host.wix.rules, unmatched: host.wix.unmatched })) {
18787
18877
  host.publishConfigInvalidated("net-mocks scenario removed");
18788
18878
  }
18789
18879
  host.seededOn = today;
18790
18880
  return { reseeded: false, reason: "no-rules" };
18791
18881
  }
18792
- host.seed({ mode: declared.mode, rules: declared.rules });
18882
+ host.seed({ mode: declared.mode, rules: declared.rules, ...declared.unmatched ? { unmatched: declared.unmatched } : {} });
18793
18883
  host.seededOn = today;
18794
18884
  host.publishConfigInvalidated("net-mocks date rollover");
18795
18885
  return { reseeded: true, rules: declared.rules.length, from, to: today };
18796
18886
  }
18797
18887
  function scenarioChanged(before, after) {
18798
18888
  if (before.mode !== after.mode) return true;
18889
+ if ((before.unmatched ?? "passthrough") !== (after.unmatched ?? "passthrough")) return true;
18799
18890
  if (before.rules.length !== after.rules.length) return true;
18800
18891
  return serialise(before.rules) !== serialise(after.rules);
18801
18892
  }
@@ -20046,7 +20137,6 @@ function shouldRevealError(args) {
20046
20137
  var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
20047
20138
  var init_validation = __esm({
20048
20139
  "../../core/ts/src/validation.ts"() {
20049
- "use strict";
20050
20140
  EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
20051
20141
  URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
20052
20142
  INTEGER_RE = /^[+-]?[0-9]+$/;
@@ -23633,7 +23723,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
23633
23723
  var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
23634
23724
  var init_worker_subtree = __esm({
23635
23725
  "../../core/ts/src/worker-subtree.ts"() {
23636
- "use strict";
23637
23726
  init_worker_subtree_safe_types_generated();
23638
23727
  WORKER_SUBTREE_CEILINGS = Object.freeze({
23639
23728
  maxEncodedBytes: 65536,
@@ -24415,11 +24504,11 @@ function withExtras(name, render) {
24415
24504
  if (!React5.isValidElement(el)) return /* @__PURE__ */ jsx6(Fragment3, { children: el });
24416
24505
  const additive = addIntrinsicPadding(el.props.style, wrap ?? {});
24417
24506
  const inferredDecorative = el.props[INFERRED_DECORATIVE] === true;
24418
- const iconGlyph2 = el.props[ICON_GLYPH] === true;
24507
+ const selfRenderedLeaf = el.props[SELF_RENDERED_LEAF] === true;
24419
24508
  const roleWhenNamed = el.props[ROLE_WHEN_NAMED];
24420
24509
  if (!Object.keys(pass).length) {
24421
- if (inferredDecorative || iconGlyph2 || roleWhenNamed != null) {
24422
- return React5.cloneElement(el, { [INFERRED_DECORATIVE]: void 0, [ICON_GLYPH]: void 0, [ROLE_WHEN_NAMED]: void 0, ...additive ? { style: additive } : {} });
24510
+ if (inferredDecorative || selfRenderedLeaf || roleWhenNamed != null) {
24511
+ return React5.cloneElement(el, { [INFERRED_DECORATIVE]: void 0, [SELF_RENDERED_LEAF]: void 0, [ROLE_WHEN_NAMED]: void 0, [PENDING_RANGE]: void 0, ...additive ? { style: additive } : {} });
24423
24512
  }
24424
24513
  return additive ? React5.cloneElement(el, { style: additive }) : /* @__PURE__ */ jsx6(Fragment3, { children: el });
24425
24514
  }
@@ -24443,13 +24532,29 @@ function withExtras(name, render) {
24443
24532
  next.role = roleWhenNamed;
24444
24533
  }
24445
24534
  }
24446
- if (iconGlyph2) {
24447
- next[ICON_GLYPH] = void 0;
24535
+ const pendingRange = prev[PENDING_RANGE];
24536
+ if (pendingRange != null) {
24537
+ next[PENDING_RANGE] = void 0;
24538
+ const finalRole = next.role ?? pass.role ?? prev.role;
24539
+ if (typeof finalRole === "string" && RANGE_ROLES.has(finalRole) && typeof pendingRange === "object") Object.assign(next, pendingRange);
24540
+ }
24541
+ if (selfRenderedLeaf) {
24542
+ next[SELF_RENDERED_LEAF] = void 0;
24543
+ if (prev.role === "progressbar" && typeof pass.role === "string" && !RANGE_ROLES.has(pass.role)) {
24544
+ next["aria-valuenow"] = void 0;
24545
+ next["aria-valuemin"] = void 0;
24546
+ next["aria-valuemax"] = void 0;
24547
+ next["aria-valuetext"] = void 0;
24548
+ }
24448
24549
  if (pass.role === "presentation" && typeof pass.onClick !== "function" && typeof pass.onDoubleClick !== "function") {
24449
24550
  next["aria-hidden"] = "true";
24450
24551
  next["aria-label"] = void 0;
24451
24552
  next.title = void 0;
24452
24553
  next.role = void 0;
24554
+ next["aria-valuenow"] = void 0;
24555
+ next["aria-valuemin"] = void 0;
24556
+ next["aria-valuemax"] = void 0;
24557
+ next["aria-valuetext"] = void 0;
24453
24558
  }
24454
24559
  }
24455
24560
  const roleIsSynthetic = next[SYNTHETIC_TAP_ROLE] === true;
@@ -25589,14 +25694,43 @@ function renderInner(node, ctx) {
25589
25694
  const titleF = ctx.font(props.titleStyle ?? "body");
25590
25695
  const subF = ctx.font(props.subtitleStyle ?? "caption");
25591
25696
  const accessoryGlyph = props.accessory === "chevron" ? "\u203A" : props.accessory === "checkmark" ? "\u2713" : null;
25592
- const onClick = ctx.onAction && props.onTap ? () => ctx.onAction(resolveItemDeep2(props.onTap, ctx)) : void 0;
25593
- const ell = { whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" };
25594
- return /* @__PURE__ */ jsxs3("div", { onClick, style: { display: "flex", alignItems: "center", gap: 12, width: "100%", padding: "10px 4px", boxSizing: "border-box", cursor: onClick ? "pointer" : void 0, ...wrap }, children: [
25595
- props.leading && /* @__PURE__ */ jsx6("div", { style: { flex: "none", display: "flex" }, children: renderNode(props.leading, ctx) }),
25596
- /* @__PURE__ */ jsxs3("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 2 }, children: [
25597
- props.overline != null && /* @__PURE__ */ jsx6("span", { style: { fontFamily: bodyFont(ctx), fontSize: 11, fontWeight: 600, letterSpacing: 0.4, textTransform: "uppercase", color: C(props.overlineColor ?? "textSecondary", "#888"), ...ell }, children: txt(props.overline, ctx) }),
25598
- /* @__PURE__ */ jsx6("span", { style: { fontFamily: fontStack(titleF.family, ctx.idiom), fontSize: titleF.remSize, fontWeight: titleF.weight, color: C(props.titleColor ?? "textPrimary", "#13171e"), ...ell }, children: txt(props.title, ctx) ?? (ctx.empty ? "" : "") }),
25599
- props.subtitle != null && /* @__PURE__ */ jsx6("span", { style: { fontFamily: fontStack(subF.family, ctx.idiom), fontSize: subF.remSize, color: C(props.subtitleColor ?? "textSecondary", "#888"), ...ell }, children: txt(props.subtitle, ctx) })
25697
+ const rowDisabled = props.disabled === true || modifiers?.disabled === true || modifiers?.hitTestable === false || modifiers?.hit_testable === false;
25698
+ const onClick = ctx.onAction && props.onTap && !rowDisabled ? () => ctx.onAction(resolveItemDeep2(props.onTap, ctx)) : void 0;
25699
+ const ell = { display: "block", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" };
25700
+ const modifierTap = modifiers?.onTap ?? modifiers?.on_tap;
25701
+ const keyboardOperable = !!ctx.onAction && !rowDisabled && !!(props.onTap || modifierTap);
25702
+ const slotInteractive = (slot) => keyboardOperable && slot != null && hasInteractiveDescendant({ type: "ListItem", props: { slot } });
25703
+ const leadingInteractive = slotInteractive(props.leading);
25704
+ const trailingInteractive = slotInteractive(props.trailing);
25705
+ const splitButton = leadingInteractive || trailingInteractive;
25706
+ const authoredLabel = splitButton ? resolveScalarStatic(modifiers?.accessibilityLabel ?? modifiers?.accessibility_label, ctx) : void 0;
25707
+ const buttonA11y = keyboardOperable ? {
25708
+ role: "button",
25709
+ tabIndex: 0,
25710
+ ...authoredLabel != null && String(authoredLabel).trim() ? { "aria-label": String(authoredLabel) } : {},
25711
+ onKeyDown: (e) => {
25712
+ if (e.defaultPrevented || e.target !== e.currentTarget || e.repeat) return;
25713
+ if (e.key !== "Enter" && e.key !== " ") return;
25714
+ e.preventDefault();
25715
+ e.currentTarget.click();
25716
+ }
25717
+ } : void 0;
25718
+ const leadingEl = props.leading && /* @__PURE__ */ jsx6("div", { style: { flex: "none", display: "flex" }, children: renderNode(props.leading, ctx) });
25719
+ const textEl = /* @__PURE__ */ jsxs3("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 2 }, children: [
25720
+ props.overline != null && /* @__PURE__ */ jsx6("span", { style: { fontFamily: bodyFont(ctx), fontSize: 11, fontWeight: 600, letterSpacing: 0.4, textTransform: "uppercase", color: C(props.overlineColor ?? "textSecondary", "#888"), ...ell }, children: txt(props.overline, ctx) }),
25721
+ /* @__PURE__ */ jsx6("span", { style: { fontFamily: fontStack(titleF.family, ctx.idiom), fontSize: titleF.remSize, fontWeight: titleF.weight, color: C(props.titleColor ?? "textPrimary", "#13171e"), ...ell }, children: txt(props.title, ctx) ?? (ctx.empty ? "" : "") }),
25722
+ props.subtitle != null && /* @__PURE__ */ jsx6("span", { style: { fontFamily: fontStack(subF.family, ctx.idiom), fontSize: subF.remSize, color: C(props.subtitleColor ?? "textSecondary", "#888"), ...ell }, children: txt(props.subtitle, ctx) })
25723
+ ] });
25724
+ return /* @__PURE__ */ jsxs3("div", { onClick, ...splitButton ? void 0 : buttonA11y, style: { display: "flex", alignItems: "center", gap: 12, width: "100%", padding: "10px 4px", boxSizing: "border-box", cursor: onClick ? "pointer" : void 0, ...wrap }, children: [
25725
+ splitButton ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
25726
+ leadingInteractive && /* @__PURE__ */ jsx6("div", { onClick: (e) => e.stopPropagation(), style: { flex: "none", display: "flex" }, children: leadingEl }),
25727
+ /* @__PURE__ */ jsxs3("div", { ...buttonA11y, style: { flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 12 }, children: [
25728
+ !leadingInteractive && leadingEl,
25729
+ textEl
25730
+ ] })
25731
+ ] }) : /* @__PURE__ */ jsxs3(Fragment3, { children: [
25732
+ leadingEl,
25733
+ textEl
25600
25734
  ] }),
25601
25735
  props.trailing ? (
25602
25736
  // #1010 — the row's `onTap` lives on the outer flex div, and the trailing
@@ -25607,7 +25741,7 @@ function renderInner(node, ctx) {
25607
25741
  // Menu popup renders inside this slot, menu-item clicks don't double-fire
25608
25742
  // the row either. Mirrors the Button node, which stops for the same reason.
25609
25743
  /* @__PURE__ */ jsx6("div", { onClick: (e) => e.stopPropagation(), style: { flex: "none", display: "flex", alignItems: "center" }, children: renderNode(props.trailing, ctx) })
25610
- ) : accessoryGlyph && /* @__PURE__ */ jsx6("span", { style: { flex: "none", color: C("textTertiary", "#c0c4cc"), fontSize: 20, lineHeight: 1 }, children: accessoryGlyph })
25744
+ ) : accessoryGlyph && /* @__PURE__ */ jsx6("span", { "aria-hidden": props.accessory === "chevron" ? true : void 0, style: { flex: "none", color: C("textTertiary", "#c0c4cc"), fontSize: 20, lineHeight: 1 }, children: accessoryGlyph })
25611
25745
  ] });
25612
25746
  }
25613
25747
  case "Slider":
@@ -25925,7 +26059,7 @@ function renderInner(node, ctx) {
25925
26059
  }
25926
26060
  }
25927
26061
  }
25928
- var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, SYNTHETIC_TABINDEX, INFERRED_DECORATIVE, ICON_GLYPH, ROLE_WHEN_NAMED, AUTHORED_ROLE, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RATING_METRICS, ratingMetrics, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, initialFocusScheduled, initialFocusSeen, PRESENTED_SCOPE, presentedOpeners, presentedObserver, A11yHintDescription, WebRenderer;
26062
+ var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, SYNTHETIC_TABINDEX, INFERRED_DECORATIVE, SELF_RENDERED_LEAF, ROLE_WHEN_NAMED, AUTHORED_ROLE, PENDING_RANGE, RANGE_ROLES, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RATING_METRICS, ratingMetrics, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, initialFocusScheduled, initialFocusSeen, PRESENTED_SCOPE, presentedOpeners, presentedObserver, A11yHintDescription, WebRenderer;
25929
26063
  var init_renderNode = __esm({
25930
26064
  "../../core/web-renderer/src/renderNode.tsx"() {
25931
26065
  "use strict";
@@ -27489,9 +27623,11 @@ var init_renderNode = __esm({
27489
27623
  SYNTHETIC_TAP_ROLE = "data-hm-synthetic-role";
27490
27624
  SYNTHETIC_TABINDEX = "data-hm-synthetic-tabindex";
27491
27625
  INFERRED_DECORATIVE = "data-hm-inferred-decorative";
27492
- ICON_GLYPH = "data-hm-icon-glyph";
27626
+ SELF_RENDERED_LEAF = "data-hm-self-rendered-leaf";
27493
27627
  ROLE_WHEN_NAMED = "data-hm-role-when-named";
27494
27628
  AUTHORED_ROLE = "data-hm-authored-role";
27629
+ PENDING_RANGE = "data-hm-pending-range";
27630
+ RANGE_ROLES = /* @__PURE__ */ new Set(["progressbar", "slider", "scrollbar", "spinbutton", "meter"]);
27495
27631
  INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
27496
27632
  "button",
27497
27633
  "checkbox",
@@ -27673,7 +27809,11 @@ var init_renderNode = __esm({
27673
27809
  }
27674
27810
  return /* @__PURE__ */ jsx6("img", { src, alt: asText2(boundAlt), style: { width: w, height: boxHeight, aspectRatio: ar, objectFit, borderRadius: r, display: "block", flex: "none", background: ph, ...wrap } });
27675
27811
  }
27676
- if (imgInitials && typeof imgInitials === "string") return avatarCircle(String(imgInitials), typeof w === "number" ? w : 40, C, false, bodyFont(ctx));
27812
+ if (imgInitials && typeof imgInitials === "string") {
27813
+ const alt = asText2(boundAlt).trim();
27814
+ const circle = avatarCircle(String(imgInitials), typeof w === "number" ? w : 40, C, false, bodyFont(ctx));
27815
+ return React5.cloneElement(circle, alt ? { role: "img", "aria-label": alt, [SELF_RENDERED_LEAF]: true } : { [ROLE_WHEN_NAMED]: "img", [SELF_RENDERED_LEAF]: true });
27816
+ }
27677
27817
  if (props.icon != null && props.url == null && props.asset == null && imgInitials == null) {
27678
27818
  const side2 = typeof w === "number" ? w : 40;
27679
27819
  return /* @__PURE__ */ jsx6("div", { style: { width: side2, height: side2, borderRadius: "50%", background: ph ?? C("surfaceTertiary", "#e6e6e6"), display: "grid", placeItems: "center", flex: "none", ...wrap }, children: iconSvg(props.icon, { size: Math.max(14, Math.round(side2 * 0.5)), color: C("accentPrimary", "#116DFF") }) });
@@ -27699,7 +27839,7 @@ var init_renderNode = __esm({
27699
27839
  const iconName = isBinding(props.name) ? String(bound ?? "") : props.name;
27700
27840
  const contentDescription = useResolvedScalar(props.contentDescription, ctx);
27701
27841
  const described = contentDescription != null && String(contentDescription).trim() !== "";
27702
- const a11y = described ? { role: "img", "aria-label": String(contentDescription), [ICON_GLYPH]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [ICON_GLYPH]: true, [ROLE_WHEN_NAMED]: "img" };
27842
+ const a11y = described ? { role: "img", "aria-label": String(contentDescription), [SELF_RENDERED_LEAF]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [SELF_RENDERED_LEAF]: true, [ROLE_WHEN_NAMED]: "img" };
27703
27843
  return /* @__PURE__ */ jsx6("span", { ...a11y, style: { display: "inline-grid", placeItems: "center", width: size + 6, height: size + 6, lineHeight: 1, flex: "none", ...wrap }, children: iconSvg(iconName, { size, color: C(resolveScalarStatic(props.tint, ctx) ?? "textPrimary", "#636b78") }) });
27704
27844
  });
27705
27845
  ButtonNode = withExtras("ButtonNode", ({ props, ctx, wrap }) => {
@@ -27825,7 +27965,19 @@ var init_renderNode = __esm({
27825
27965
  const numP = typeof rawP === "number" ? rawP : typeof rawP === "string" && rawP.trim() !== "" && Number.isFinite(Number(rawP)) ? Number(rawP) : void 0;
27826
27966
  const p = numP !== void 0 ? Math.max(0, Math.min(1, numP)) : props.indeterminate ? 0.4 : null;
27827
27967
  const animatedFill = props.animated === true && !ctx.reduceMotion();
27828
- return /* @__PURE__ */ jsx6("div", { style: { width: "100%", height: 6, borderRadius: 999, background: C(boundTokenName(props.trackColorPath, props.trackColor, ctx) ?? "surfaceTertiary", "#eee"), overflow: "hidden", ...wrap }, children: /* @__PURE__ */ jsx6("div", { style: { width: `${Math.round((p ?? 0.4) * 100)}%`, height: "100%", borderRadius: 999, background: C(boundTokenName(props.tintPath, props.tint, ctx) ?? "accentPrimary", "#116DFF"), opacity: p == null ? 0.45 : 1, ...animatedFill ? { transition: ctx.motionTransition(ctx.kit?.motion) } : {} } }) });
27968
+ const a11y = {
27969
+ role: "progressbar",
27970
+ "aria-valuemin": 0,
27971
+ "aria-valuemax": 100,
27972
+ // `Number.isFinite`, not `!== undefined`: a worker's NaN (done/total, total 0) is a number
27973
+ // too, and would be announced as aria-valuenow="NaN".
27974
+ // A number wins over `indeterminate`, in the announcement as in the fill painted above:
27975
+ // `indeterminate` is "DEPRECATED web-only; not read by the native decoders" (core.proto),
27976
+ // so iOS and Android draw and speak the number.
27977
+ ...numP !== void 0 && Number.isFinite(numP) && p != null ? { "aria-valuenow": Math.round(p * 100) } : {},
27978
+ [SELF_RENDERED_LEAF]: true
27979
+ };
27980
+ return /* @__PURE__ */ jsx6("div", { ...a11y, style: { width: "100%", height: 6, borderRadius: 999, background: C(boundTokenName(props.trackColorPath, props.trackColor, ctx) ?? "surfaceTertiary", "#eee"), overflow: "hidden", ...wrap }, children: /* @__PURE__ */ jsx6("div", { style: { width: `${Math.round((p ?? 0.4) * 100)}%`, height: "100%", borderRadius: 999, background: C(boundTokenName(props.tintPath, props.tint, ctx) ?? "accentPrimary", "#116DFF"), opacity: p == null ? 0.45 : 1, ...animatedFill ? { transition: ctx.motionTransition(ctx.kit?.motion) } : {} } }) });
27829
27981
  });
27830
27982
  ActivityIndicatorNode = withExtras("ActivityIndicatorNode", ({ props, ctx, wrap }) => {
27831
27983
  const C = ctx.color;
@@ -27910,11 +28062,11 @@ var init_renderNode = __esm({
27910
28062
  GaugeRing = ({ ring, ctx, index, size, step, thick, track }) => {
27911
28063
  const bound = useResolvedScalar(ring?.valuePath, ctx);
27912
28064
  const rv = ring?.valuePath != null ? bound : ring?.value;
27913
- const rp = Math.max(0, Math.min(1, typeof rv === "number" ? rv : 0));
28065
+ const rp = Math.max(0, Math.min(1, typeof rv === "number" && Number.isFinite(rv) ? rv : 0));
27914
28066
  const rt = ctx.color(ring?.tint ?? "accentPrimary", "#116DFF");
27915
28067
  const d = size - index * step, off = (size - d) / 2;
27916
28068
  const mask = `radial-gradient(farthest-side, transparent calc(100% - ${thick}px), #000 calc(100% - ${thick}px))`;
27917
- return /* @__PURE__ */ jsx6("div", { style: { position: "absolute", top: off, left: off, width: d, height: d, borderRadius: "50%", background: `conic-gradient(${rt} ${rp * 360}deg, ${track} 0deg)`, WebkitMask: mask, mask } });
28069
+ return /* @__PURE__ */ jsx6("div", { "aria-hidden": "true", style: { position: "absolute", top: off, left: off, width: d, height: d, borderRadius: "50%", background: `conic-gradient(${rt} ${rp * 360}deg, ${track} 0deg)`, WebkitMask: mask, mask } });
27918
28070
  };
27919
28071
  GaugeNode = withExtras("GaugeNode", ({ props, ctx, wrap }) => {
27920
28072
  const C = ctx.color;
@@ -27926,19 +28078,25 @@ var init_renderNode = __esm({
27926
28078
  const tint = C(props.tint ?? "accentPrimary", "#116DFF");
27927
28079
  const track = C("surfaceTertiary", "#e3e6ea");
27928
28080
  const gaugeAnim = props.animated === true && !ctx.reduceMotion() ? { transition: ctx.motionTransition(ctx.kit?.motion) } : {};
28081
+ const labelName = useBoundString(props.label, ctx).trim();
28082
+ const hasValue = typeof gRaw === "number" && Number.isFinite(gRaw);
28083
+ const named = labelName ? { "aria-label": labelName } : hasValue && max > min ? { "aria-label": `${Math.round(pct * 100)}%` } : {};
28084
+ const fractionScale = min === 0 && max === 1;
28085
+ const range = max > min ? { "aria-valuemin": min, "aria-valuemax": max, ...hasValue ? { "aria-valuenow": Math.max(min, Math.min(max, v)), ...fractionScale ? { "aria-valuetext": `${Math.round(pct * 100)}%` } : {} } : {} } : {};
28086
+ const a11y = labelName || hasValue && max > min ? { role: "progressbar", ...named, ...range, [SELF_RENDERED_LEAF]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [ROLE_WHEN_NAMED]: "progressbar", [PENDING_RANGE]: range, [SELF_RENDERED_LEAF]: true };
27929
28087
  if (Array.isArray(props.rings) && props.rings.length) {
27930
28088
  const size = 96, thick = 9, step = 22;
27931
- return /* @__PURE__ */ jsx6("div", { style: { position: "relative", width: size, height: size, ...wrap }, children: props.rings.map((r, i) => /* @__PURE__ */ jsx6(GaugeRing, { ring: r, ctx, index: i, size, step, thick, track }, i)) });
28089
+ return /* @__PURE__ */ jsx6("div", { role: "group", ...named, ...{ [SELF_RENDERED_LEAF]: true }, style: { position: "relative", width: size, height: size, ...wrap }, children: props.rings.map((r, i) => /* @__PURE__ */ jsx6(GaugeRing, { ring: r, ctx, index: i, size, step, thick, track }, i)) });
27932
28090
  }
27933
28091
  if (props.kind === "linear") {
27934
- return /* @__PURE__ */ jsxs3("div", { style: { width: "100%", ...wrap }, children: [
28092
+ return /* @__PURE__ */ jsxs3("div", { ...a11y, style: { width: "100%", ...wrap }, children: [
27935
28093
  props.label != null && /* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontSize: 13, color: C("textSecondary", "#636b78"), marginBottom: 4 }, children: txt(props.label, ctx) }),
27936
28094
  /* @__PURE__ */ jsx6("div", { style: { width: "100%", height: 8, borderRadius: 999, background: track, overflow: "hidden" }, children: /* @__PURE__ */ jsx6("div", { style: { width: `${pct * 100}%`, height: "100%", background: tint, ...gaugeAnim } }) })
27937
28095
  ] });
27938
28096
  }
27939
28097
  const ringMask = "radial-gradient(farthest-side, transparent calc(100% - 8px), #000 calc(100% - 8px))";
27940
28098
  const capF = ctx.font("caption");
27941
- return /* @__PURE__ */ jsx6("div", { style: { display: "inline-flex", flexDirection: "column", alignItems: "center", gap: 4, ...wrap }, children: /* @__PURE__ */ jsxs3("div", { style: { position: "relative", width: 72, height: 72 }, children: [
28099
+ return /* @__PURE__ */ jsx6("div", { ...a11y, style: { display: "inline-flex", flexDirection: "column", alignItems: "center", gap: 4, ...wrap }, children: /* @__PURE__ */ jsxs3("div", { style: { position: "relative", width: 72, height: 72 }, children: [
27942
28100
  /* @__PURE__ */ jsx6("div", { style: { width: 72, height: 72, borderRadius: "50%", background: `conic-gradient(${tint} ${pct * 360}deg, ${track} 0deg)`, WebkitMask: ringMask, mask: ringMask, ...gaugeAnim } }),
27943
28101
  /* @__PURE__ */ jsx6("div", { style: { position: "absolute", inset: 0, display: "grid", placeItems: "center", fontFamily: fontStack(capF.family, ctx.idiom), fontSize: capF.remSize, fontWeight: capF.weight, color: C("textPrimary", "#13171e") }, children: txt(props.label, ctx) || `${Math.round(pct * 100)}%` })
27944
28102
  ] }) });
@@ -33125,11 +33283,11 @@ function syncNetMocksWithApp(state) {
33125
33283
  const declared = state.app?.meta.devGateway;
33126
33284
  const next = declared?.rules ?? [];
33127
33285
  const before = { mode: state.wix.mode, rules: state.wix.rules };
33128
- const beforeSnapshot = { mode: before.mode, rules: JSON.parse(JSON.stringify(before.rules)) };
33129
- applyNetMocks(state.wix, { mode: declared?.mode, rules: next });
33286
+ const beforeSnapshot = { mode: before.mode, rules: JSON.parse(JSON.stringify(before.rules)), unmatched: state.wix.unmatched };
33287
+ applyNetMocks(state.wix, { mode: declared?.mode, rules: next, unmatched: declared?.unmatched });
33130
33288
  state.wixSeededOn = todayYmd();
33131
33289
  state.wixReseedBackoffUntil = 0;
33132
- if (scenarioChanged(beforeSnapshot, { mode: state.wix.mode, rules: state.wix.rules })) {
33290
+ if (scenarioChanged(beforeSnapshot, { mode: state.wix.mode, rules: state.wix.rules, unmatched: state.wix.unmatched })) {
33133
33291
  publishSSE(state, "config.invalidated", { reason: "net-mocks scenario changed", at: Date.now() });
33134
33292
  console.error(`[himalaya-dev] net-mocks: re-synced ${next.length} rule(s) after an app reload`);
33135
33293
  }
@@ -33420,69 +33578,106 @@ async function handleWebWix(req, res, state) {
33420
33578
  }
33421
33579
  if (path2 === "/v1/__webwix/call" && req.method === "POST") {
33422
33580
  const b = await readJson5();
33423
- if (b.ownerMsid !== void 0 || b.checkOwnerSession === true) {
33424
- const msid = String(b.ownerMsid ?? "");
33425
- if (!isSafeMsid(msid)) return reply(400, { error: "webwix_owner_bad_msid" });
33426
- const cookie = req.headers.cookie ?? "";
33427
- if (!/wixSession2=/.test(cookie)) return reply(501, { error: "webwix_owner_no_session" });
33428
- try {
33429
- if (b.checkOwnerSession !== true && String(b.method ?? "GET").toUpperCase() === "POST" && isOwnerSitesPath(String(b.path ?? ""))) {
33430
- const body3 = b.body === void 0 ? void 0 : typeof b.body === "string" ? b.body : JSON.stringify(b.body);
33431
- return reply(200, await wixOwnerSitesCall(String(b.path), cookie, body3, fetch));
33432
- }
33433
- let instance = await webOwnerPreviewInstances.instance(msid, cookie);
33434
- res.setHeader("cache-control", "no-store");
33435
- if (b.checkOwnerSession === true) return reply(200, { status: 200, body: JSON.stringify({ ready: true }) });
33436
- const method2 = String(b.method ?? "GET").toUpperCase();
33437
- const requestPath = String(b.path ?? "/");
33438
- const body2 = b.body === void 0 ? void 0 : typeof b.body === "string" ? b.body : JSON.stringify(b.body);
33439
- const headers2 = normalizeWixForwardedHeaders(b.headers);
33440
- let result = await wixVisitorCall(method2, requestPath, body2, instance, fetch, headers2);
33441
- if (result.status === 401) {
33442
- webOwnerPreviewInstances.invalidate(msid, cookie);
33443
- instance = await webOwnerPreviewInstances.instance(msid, cookie);
33444
- result = await wixVisitorCall(method2, requestPath, body2, instance, fetch, headers2);
33445
- }
33446
- return reply(200, result);
33447
- } catch (e) {
33448
- if (String(e).includes("absolute URLs")) return reply(400, { error: "absolute_urls_not_allowed" });
33449
- const auth2 = /owner mint failed \(40[13]\)/.test(String(e?.message ?? e));
33450
- return reply(auth2 ? 501 : 502, { error: auth2 ? "webwix_owner_mint_failed" : "webwix_bridge_upstream_failed" });
33451
- }
33452
- }
33581
+ const ownerRung = b.ownerMsid !== void 0 || b.checkOwnerSession === true;
33582
+ const msid = String(b.ownerMsid ?? "");
33583
+ const cookie = req.headers.cookie ?? "";
33453
33584
  const method = String(b.method ?? "GET").toUpperCase();
33454
33585
  const requestedPath = String(b.path ?? "/");
33455
- const body = b.body === void 0 ? void 0 : typeof b.body === "string" ? b.body : JSON.stringify(b.body);
33456
- const forwardedHeaders = normalizeWixForwardedHeaders(b.headers, requestedPath);
33457
- const target = new URL(requestedPath, "https://www.wixapis.com");
33458
- const query = Object.fromEntries(target.searchParams.entries());
33459
33586
  const started = Date.now();
33460
- const matchCtx = { host: target.host, query, headers: forwardedHeaders, body };
33461
- let match = state.wix.mode === "mock" ? matchRuleEx(state.wix.rules, method, target.pathname, matchCtx) : void 0;
33462
- if (match && (match.rule.kind ?? "mock") !== "mock") {
33463
- console.error(`[himalaya-dev] net-mocks: rule "${match.rule.id}" is kind:"${match.rule.kind}", which the web bridge cannot apply \u2014 ignoring it for ${method} ${target.pathname}`);
33464
- match = matchRuleEx(state.wix.rules.filter((r) => (r.kind ?? "mock") === "mock"), method, target.pathname, matchCtx);
33587
+ const capability = ownerRung ? "wix_api.web.owner" : "wix_api.web";
33588
+ const refuseEarly = (status, error, parsed) => {
33589
+ recordWixTraffic(state.wix, state.appName, state.adminUrl, {
33590
+ ts: started,
33591
+ source: "proxy",
33592
+ capability,
33593
+ host: parsed?.host ?? "www.wixapis.com",
33594
+ method,
33595
+ url: parsed?.toString() ?? requestedPath.slice(0, 200),
33596
+ path: parsed?.pathname ?? requestedPath.slice(0, 200),
33597
+ status,
33598
+ durationMs: Date.now() - started
33599
+ });
33600
+ return reply(status, { error });
33601
+ };
33602
+ let target;
33603
+ try {
33604
+ target = new URL(requestedPath, "https://www.wixapis.com");
33605
+ } catch {
33606
+ return refuseEarly(400, "webwix_bad_path");
33465
33607
  }
33466
- if (match && (match.rule.kind ?? "mock") === "mock") {
33467
- const mocked = match.rule.response;
33468
- if (mocked.delayMs) await new Promise((resolve48) => setTimeout(resolve48, mocked.delayMs));
33469
- const responseBody = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
33608
+ if (ownerRung) {
33609
+ if (!isSafeMsid(msid)) return refuseEarly(400, "webwix_owner_bad_msid", target);
33610
+ if (!/wixSession2=/.test(cookie)) return refuseEarly(501, "webwix_owner_no_session", target);
33611
+ }
33612
+ const body = b.body === void 0 ? void 0 : typeof b.body === "string" ? b.body : JSON.stringify(b.body);
33613
+ const forwardedHeaders = normalizeWixForwardedHeaders(b.headers, requestedPath);
33614
+ const record2 = (source, status, respBody, mockRuleId, respHeaders) => {
33615
+ const redactBodies = source === "proxy" || mockRuleId === UNMATCHED_FAIL_CLOSED_ID;
33470
33616
  recordWixTraffic(state.wix, state.appName, state.adminUrl, {
33471
33617
  ts: started,
33472
- source: "mock",
33473
- capability: "wix_api.web",
33618
+ source,
33619
+ capability,
33474
33620
  host: target.host,
33475
33621
  method,
33476
33622
  url: target.toString(),
33477
33623
  path: target.pathname,
33478
- status: mocked.status,
33624
+ status,
33479
33625
  durationMs: Date.now() - started,
33480
- reqBody: body,
33481
- respHeaders: mocked.headers,
33482
- respBody: responseBody,
33483
- mockRuleId: match.rule.id
33626
+ reqBody: redactBodies ? void 0 : body,
33627
+ respHeaders: redactBodies ? void 0 : respHeaders,
33628
+ respBody: redactBodies ? void 0 : respBody,
33629
+ mockRuleId
33484
33630
  });
33485
- return reply(200, { status: mocked.status, body: responseBody ?? "" });
33631
+ };
33632
+ if (b.checkOwnerSession !== true && state.wix.mode === "mock" && (!ownerRung || failsClosed(state.wix))) {
33633
+ const matchCtx = { host: target.host, query: Object.fromEntries(target.searchParams.entries()), headers: forwardedHeaders, body };
33634
+ let match = matchRuleEx(state.wix.rules, method, target.pathname, matchCtx);
33635
+ if (match && (match.rule.kind ?? "mock") !== "mock") {
33636
+ console.error(`[himalaya-dev] net-mocks: rule "${match.rule.id}" is kind:"${match.rule.kind}", which the web bridge cannot apply \u2014 ignoring it for ${method} ${target.pathname}`);
33637
+ match = matchRuleEx(state.wix.rules.filter((r) => (r.kind ?? "mock") === "mock"), method, target.pathname, matchCtx);
33638
+ }
33639
+ if (match) {
33640
+ const mocked = match.rule.response;
33641
+ if (mocked.delayMs) await new Promise((resolve48) => setTimeout(resolve48, mocked.delayMs));
33642
+ const responseBody = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
33643
+ record2("mock", mocked.status, responseBody, match.rule.id, mocked.headers);
33644
+ return reply(200, { status: mocked.status, body: responseBody ?? "" });
33645
+ }
33646
+ if (failsClosed(state.wix)) {
33647
+ const refusal = hermeticRefusal(method, target.pathname);
33648
+ record2("mock", refusal.status, refusal.body, UNMATCHED_FAIL_CLOSED_ID, refusal.headers);
33649
+ return reply(200, { status: refusal.status, body: refusal.body });
33650
+ }
33651
+ }
33652
+ if (ownerRung) {
33653
+ try {
33654
+ if (b.checkOwnerSession !== true && method === "POST" && isOwnerSitesPath(requestedPath)) {
33655
+ const result2 = await wixOwnerSitesCall(requestedPath, cookie, body, fetch);
33656
+ record2("proxy", result2.status, result2.body);
33657
+ return reply(200, result2);
33658
+ }
33659
+ let instance = await webOwnerPreviewInstances.instance(msid, cookie);
33660
+ res.setHeader("cache-control", "no-store");
33661
+ if (b.checkOwnerSession === true) {
33662
+ record2("proxy", 200, void 0);
33663
+ return reply(200, { status: 200, body: JSON.stringify({ ready: true }) });
33664
+ }
33665
+ let result = await wixVisitorCall(method, requestedPath, body, instance, fetch, forwardedHeaders);
33666
+ if (result.status === 401) {
33667
+ webOwnerPreviewInstances.invalidate(msid, cookie);
33668
+ instance = await webOwnerPreviewInstances.instance(msid, cookie);
33669
+ result = await wixVisitorCall(method, requestedPath, body, instance, fetch, forwardedHeaders);
33670
+ }
33671
+ record2("proxy", result.status, result.body);
33672
+ return reply(200, result);
33673
+ } catch (e) {
33674
+ const absolute = String(e).includes("absolute URLs");
33675
+ const auth2 = /owner mint failed \(40[13]\)/.test(String(e?.message ?? e));
33676
+ const status = absolute ? 400 : auth2 ? 501 : 502;
33677
+ record2("proxy", status, void 0);
33678
+ if (absolute) return reply(400, { error: "absolute_urls_not_allowed" });
33679
+ return reply(status, { error: auth2 ? "webwix_owner_mint_failed" : "webwix_bridge_upstream_failed" });
33680
+ }
33486
33681
  }
33487
33682
  if (!session.visitorToken && !session.memberToken) {
33488
33683
  try {
@@ -33500,9 +33695,12 @@ async function handleWebWix(req, res, state) {
33500
33695
  } catch {
33501
33696
  }
33502
33697
  }
33698
+ record2("proxy", r.status, r.body);
33503
33699
  return reply(200, { status: r.status, body: r.body });
33504
33700
  } catch (e) {
33505
- return reply(200, { status: 0, body: JSON.stringify({ error: String(e?.message ?? e) }) });
33701
+ const message = JSON.stringify({ error: String(e?.message ?? e) });
33702
+ record2("proxy", 0, message);
33703
+ return reply(200, { status: 0, body: message });
33506
33704
  }
33507
33705
  }
33508
33706
  if (path2 === "/v1/__webwix/logout" && req.method === "POST") {
@@ -34664,7 +34862,7 @@ function createDevServer(opts = {}) {
34664
34862
  }
34665
34863
  const appScenario = state.app?.meta.devGateway;
34666
34864
  if (!netMocksDisabled && appScenario?.rules?.length && state.wix.rules.length === 0) {
34667
- const seeded = applyNetMocks(state.wix, { mode: appScenario.mode, rules: appScenario.rules });
34865
+ const seeded = applyNetMocks(state.wix, { mode: appScenario.mode, rules: appScenario.rules, unmatched: appScenario.unmatched });
34668
34866
  state.wixSeededOn = todayYmd();
34669
34867
  state.wixSeededFromApp = true;
34670
34868
  console.error(`[himalaya-dev] net-mocks: seeded ${seeded.rules} rule(s), mode=${seeded.mode} from the app's devGateway scenario`);
@@ -48365,7 +48563,7 @@ ${releaseId}`;
48365
48563
  if ((request.method === "GET" || request.method === "HEAD") && path2 === "/v1/__webwix/identity") {
48366
48564
  const headers2 = { "content-type": JSON_CT, "cache-control": "no-store" };
48367
48565
  if (request.method === "HEAD") return new Response(null, { status: 200, headers: headers2 });
48368
- const webwixDirect = opts.webwixBridge !== false;
48566
+ const webwixDirect = opts.webwixDirect ? await opts.webwixDirect() === true : opts.webwixBridge !== false;
48369
48567
  if (memberAuthOn()) {
48370
48568
  const app2 = memberApp(request);
48371
48569
  const store2 = memberSessions();
@@ -49310,6 +49508,32 @@ var init_node_adapter = __esm({
49310
49508
  }
49311
49509
  });
49312
49510
 
49511
+ // src/wix-client-id.ts
49512
+ function authConfigOf(appConfig) {
49513
+ if (!appConfig) return void 0;
49514
+ try {
49515
+ const text5 = typeof appConfig === "string" ? appConfig : new TextDecoder().decode(appConfig);
49516
+ return JSON.parse(text5)?.authConfig ?? void 0;
49517
+ } catch {
49518
+ return void 0;
49519
+ }
49520
+ }
49521
+ function appConfigWixClientId(appConfig) {
49522
+ const clientId = authConfigOf(appConfig)?.config?.clientId;
49523
+ return typeof clientId === "string" && clientId ? clientId : void 0;
49524
+ }
49525
+ function liveWixClientId(appConfig) {
49526
+ const auth = authConfigOf(appConfig);
49527
+ if (typeof auth?.providerId !== "string" || !auth.providerId.startsWith("wix")) return void 0;
49528
+ const clientId = appConfigWixClientId(appConfig);
49529
+ return clientId && clientId !== PLACEHOLDER_CLIENT_ID ? clientId : void 0;
49530
+ }
49531
+ var init_wix_client_id = __esm({
49532
+ "src/wix-client-id.ts"() {
49533
+ init_wix_placeholders();
49534
+ }
49535
+ });
49536
+
49313
49537
  // ../../packages/serve/src/preview-assets-format.ts
49314
49538
  function hasPreviewBlobMagic(blob) {
49315
49539
  if (blob.length < PREVIEW_BLOB_MAGIC.length) return false;
@@ -49351,21 +49575,21 @@ var init_preview_assets_generated = __esm({
49351
49575
  "../../packages/serve/src/preview-assets.generated.ts"() {
49352
49576
  init_preview_assets_format();
49353
49577
  PREVIEW_ASSET_MANIFEST = [
49354
- { key: "assets/index-BWTgWRYB.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1046928, sha256: "eded52b19e2f6c57d72a1206781cf42265d463761710cd36d3b9731e03702c79" },
49355
- { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1046936, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
49356
- { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1051546, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
49357
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1540130, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
49358
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1631054, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
49359
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1722038, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
49360
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1813018, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
49361
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1903890, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
49362
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1994870, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
49363
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2103506, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
49364
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2212590, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
49365
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2321638, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
49366
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2429338, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
49367
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2517446, length: 4947, sha256: "655f7d9b2d32c524443b698a25221375fdda4ea7d2cd91afa2aaec6f8922fdb0" },
49368
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2522393, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
49578
+ { key: "assets/index-CGsR5F0F.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1049558, sha256: "591c0803688d9807699f9ba9452bb09b73f05ffb51675e199287b6c8885cfeb7" },
49579
+ { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1049566, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
49580
+ { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1054176, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
49581
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1542760, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
49582
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1633684, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
49583
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1724668, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
49584
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1815648, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
49585
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1906520, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
49586
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1997500, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
49587
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2106136, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
49588
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2215220, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
49589
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2324268, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
49590
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2431968, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
49591
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2520076, length: 4947, sha256: "98dd4bdbeaa0bdbabf0f9df5b37a3408dec1e7e40d67dd39a89f64932c2c7a59" },
49592
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2525023, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
49369
49593
  ];
49370
49594
  }
49371
49595
  });
@@ -49386,13 +49610,22 @@ import { tmpdir as tmpdir4 } from "node:os";
49386
49610
  import { dirname as dirname27, join as join51 } from "node:path";
49387
49611
  import { fileURLToPath as fileURLToPath22 } from "node:url";
49388
49612
  function makePackageRunHandler(opts) {
49613
+ const store = new FileReleaseStore(opts.releaseRoot);
49614
+ const webwixDirect = async () => {
49615
+ try {
49616
+ return liveWixClientId(await store.getAppConfig(opts.app)) !== void 0;
49617
+ } catch {
49618
+ return false;
49619
+ }
49620
+ };
49389
49621
  return makeRunHandler({
49390
- store: new FileReleaseStore(opts.releaseRoot),
49622
+ store,
49391
49623
  app: opts.app,
49392
49624
  assets: opts.assets,
49393
49625
  ...opts.chrome ? { chrome: opts.chrome } : {},
49394
49626
  header: opts.header ?? null,
49395
- ...opts.screenEvents ? { screenEvents: opts.screenEvents } : {}
49627
+ ...opts.screenEvents ? { screenEvents: opts.screenEvents } : {},
49628
+ ...opts.liveWix ? { serve: { webwixDirect } } : {}
49396
49629
  });
49397
49630
  }
49398
49631
  async function fetchBytes(url) {
@@ -49493,7 +49726,8 @@ async function runPackage(source, opts = {}) {
49493
49726
  assets,
49494
49727
  chrome: opts.chrome,
49495
49728
  header: resolved2.header,
49496
- ...opts.screenEvents ? { screenEvents: opts.screenEvents } : {}
49729
+ ...opts.screenEvents ? { screenEvents: opts.screenEvents } : {},
49730
+ ...opts.liveWix ? { liveWix: true } : {}
49497
49731
  });
49498
49732
  const extra = opts.extraRoutes;
49499
49733
  const handler = extra ? (request) => extra(request) ?? plane(request) : plane;
@@ -49533,6 +49767,7 @@ var init_run = __esm({
49533
49767
  init_file_store();
49534
49768
  init_run_handler();
49535
49769
  init_node_adapter();
49770
+ init_wix_client_id();
49536
49771
  init_pack();
49537
49772
  init_himi_package();
49538
49773
  init_himi_package();
@@ -49631,7 +49866,7 @@ function watchFlagConflict(opts) {
49631
49866
  return { error: "watch_needs_source", message: "--watch rebuilds a content package on every save, so it cannot watch a packaged release or a URL. Pass the app's directory (the one with himalaya.content.json), --content <dir>, or run it from there with no argument." };
49632
49867
  }
49633
49868
  if (opts.browser) {
49634
- return { error: "watch_with_browser", message: "--watch rebuilds and serves from this process; --browser runs the whole plane inside the tab. Pick one." };
49869
+ return { error: "watch_with_browser", message: "--watch already opens the app in your browser, so drop --browser. (--browser is a different mode: it runs the whole serve plane inside the tab, leaving no process here to rebuild on save.) Under --watch a site-bound app shows the site's live data on its own." };
49635
49870
  }
49636
49871
  if (opts.spa) {
49637
49872
  return { error: "watch_with_spa", message: "--watch pushes each rebuild to the open tab over this server's own origin, and a hosted SPA (--spa) listens on its origin instead, so it would never repaint. Drop --spa to watch with the bundled web host, or drop --watch." };
@@ -49864,12 +50099,7 @@ async function releasePayloadFromDir(root, app, header) {
49864
50099
  if (w !== void 0) widgets[id] = w;
49865
50100
  }
49866
50101
  const appConfig = text5(await store.getAppConfig(app));
49867
- let wixClientId;
49868
- try {
49869
- const cfg = appConfig ? JSON.parse(appConfig) : null;
49870
- wixClientId = cfg?.authConfig?.config?.clientId;
49871
- } catch {
49872
- }
50102
+ const wixClientId = appConfigWixClientId(appConfig);
49873
50103
  return {
49874
50104
  app,
49875
50105
  manifest,
@@ -49950,6 +50180,7 @@ var init_run_browser = __esm({
49950
50180
  "src/run-browser.ts"() {
49951
50181
  init_open_url();
49952
50182
  init_file_store();
50183
+ init_wix_client_id();
49953
50184
  HERE = dirname28(fileURLToPath23(import.meta.url));
49954
50185
  REPO = resolve43(HERE, "..", "..", "..");
49955
50186
  SERVED = /* @__PURE__ */ new Set(["host.html", "sw.js", "package-reader.js"]);
@@ -61503,8 +61734,21 @@ function committedIdentity(root) {
61503
61734
  const records = raw === null ? null : committedRecords(raw);
61504
61735
  if (records !== null) return `base\0${base}\0${records}`;
61505
61736
  }
61506
- const tree = tryGit(["rev-parse", "HEAD^{tree}"], root)?.trim();
61507
- return tree ? `tree\0${tree}\0` : `commit\0${head}\0`;
61737
+ const listing = tryGit(["ls-tree", "-rz", "--full-tree", "HEAD"], root);
61738
+ const tree = listing === null ? null : treeRecords(listing);
61739
+ return tree !== null ? `tree-listing\0${tree}` : `commit\0${head}\0`;
61740
+ }
61741
+ function treeRecords(listing) {
61742
+ const records = [];
61743
+ for (const record2 of listing.split("\0")) {
61744
+ if (record2 === "") continue;
61745
+ const tab = record2.indexOf(" ");
61746
+ if (tab <= 0 || tab === record2.length - 1) return null;
61747
+ const path2 = record2.slice(tab + 1);
61748
+ if (isValidationMetadata(path2)) continue;
61749
+ records.push(`${Buffer.byteLength(path2)}:${path2}\0${record2.slice(0, tab)}\0`);
61750
+ }
61751
+ return records.sort().join("");
61508
61752
  }
61509
61753
  function treeEntries(output, index = false) {
61510
61754
  const entries = /* @__PURE__ */ new Map();
@@ -61535,14 +61779,15 @@ function blobOid(contents, algorithm) {
61535
61779
  }
61536
61780
  function validationDiffHash(cwd = process.cwd()) {
61537
61781
  const root = resolveRepoRoot(cwd);
61538
- const staged = git(["diff", "--cached", "--name-only", "--no-renames", "-z", "HEAD"], {
61782
+ const born = tryGit(["rev-parse", "--verify", "--quiet", "HEAD^{commit}"], root) !== null;
61783
+ const staged = git(["diff", "--cached", "--name-only", "--no-renames", "-z", ...born ? ["HEAD"] : []], {
61539
61784
  cwd: root
61540
61785
  }).split("\0").filter(Boolean);
61541
61786
  const unstaged = git(["diff", "--name-only", "--no-renames", "-z"], { cwd: root }).split("\0").filter(Boolean);
61542
61787
  const untracked = git(["ls-files", "--others", "--exclude-standard", "-z"], {
61543
61788
  cwd: root
61544
61789
  }).split("\0").filter(Boolean);
61545
- const headEntries = treeEntries(git(["ls-tree", "-rz", "--full-tree", "HEAD"], { cwd: root }));
61790
+ const headEntries = born ? treeEntries(git(["ls-tree", "-rz", "--full-tree", "HEAD"], { cwd: root })) : /* @__PURE__ */ new Map();
61546
61791
  const indexEntries = treeEntries(git(["ls-files", "--stage", "-z"], { cwd: root }), true);
61547
61792
  const objectAlgorithm = git(["rev-parse", "--show-object-format"], { cwd: root }).trim();
61548
61793
  let trustFilesystemMode = true;
@@ -61801,10 +62046,13 @@ function selfHashFor(attestation) {
61801
62046
  }
61802
62047
  function repoRoot(contentDir2) {
61803
62048
  try {
61804
- return execFileSync2("git", ["-C", contentDir2, "rev-parse", "--show-toplevel"], {
62049
+ const root = execFileSync2("git", ["-C", contentDir2, "rev-parse", "--show-toplevel"], {
61805
62050
  encoding: "utf8",
61806
62051
  stdio: ["ignore", "pipe", "ignore"]
61807
62052
  }).trim();
62053
+ if (!root) return null;
62054
+ execFileSync2("git", ["-C", root, "rev-parse", "--verify", "--quiet", "HEAD^{commit}"], { stdio: "ignore" });
62055
+ return root;
61808
62056
  } catch {
61809
62057
  return null;
61810
62058
  }
@@ -65738,6 +65986,10 @@ function writePngFile(path2, base64) {
65738
65986
  writeFileSync28(path2, Buffer.from(base64, "base64"));
65739
65987
  return path2;
65740
65988
  }
65989
+ function keptPlan(kept) {
65990
+ const note = keptPlanNote(kept);
65991
+ return note ? { kept, note } : {};
65992
+ }
65741
65993
  async function initFromRemoteTemplate(name, parentDir, template, c) {
65742
65994
  const dir = resolve47(parentDir, name);
65743
65995
  if (existsSync61(join58(dir, "himalaya.content.json"))) {
@@ -66583,7 +66835,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
66583
66835
  try {
66584
66836
  const res2 = await initFromRemoteTemplate(name, parentDir, template, client2());
66585
66837
  const pushSetup2 = await offerPushSetup2({ contentDir: res2.dir, flags, io });
66586
- print({ ok: true, app: name, dir: res2.dir, template, source: "remote", files: res2.files, pushSetup: pushSetup2 });
66838
+ print({ ok: true, app: name, dir: res2.dir, template, source: "remote", files: res2.files, ...keptPlan(res2.kept), pushSetup: pushSetup2 });
66587
66839
  return 0;
66588
66840
  } catch (e) {
66589
66841
  if (!availableTemplates().includes(template)) {
@@ -66595,7 +66847,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
66595
66847
  }
66596
66848
  const res = scaffoldContentPackage(name, parentDir, template);
66597
66849
  const pushSetup = await offerPushSetup2({ contentDir: res.dir, flags, io });
66598
- print({ ok: true, app: name, dir: res.dir, ...template ? { template, source: "embedded" } : {}, files: res.files, pushSetup });
66850
+ print({ ok: true, app: name, dir: res.dir, ...template ? { template, source: "embedded" } : {}, files: res.files, ...keptPlan(res.kept), pushSetup });
66599
66851
  return 0;
66600
66852
  }
66601
66853
  case "template": {
@@ -69164,7 +69416,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
69164
69416
  open: flags["no-open"] !== true,
69165
69417
  // The build board on the preview's own origin, for any run of this content package.
69166
69418
  ...recordKit ? { extraRoutes: (request) => recordKit.boardFile(dir, new URL(request.url).pathname) } : {},
69167
- ...watchKit && served && bus ? { workDir: served, screenEvents: bus } : {}
69419
+ // `liveWix` only with --watch: that is the "click around while you work" window, and a
69420
+ // site-bound app shows the site's data there (#3273). A packaged `himi run` stays offline.
69421
+ ...watchKit && served && bus ? { workDir: served, screenEvents: bus, liveWix: true } : {}
69168
69422
  });
69169
69423
  let watcher2;
69170
69424
  let rebuild;