@vesk/vesk-cli 0.2.59 → 0.2.61

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 (2) hide show
  1. package/dist/cli.js +748 -64
  2. package/package.json +5 -5
package/dist/cli.js CHANGED
@@ -495,7 +495,7 @@ ${this.code}`;
495
495
  });
496
496
 
497
497
  // ../compiler/src/ir.ts
498
- var Expression, IRRoot, ComponentIR, StaticNode, TextNode, DynamicBinding, OpaqueDynamicRegion, MapRegion, ComponentRef, ComponentCall, SlotNode, PropSlot, PropSlotRender, WhileLoop, SwitchCase, SwitchBlock, TryCatch, TrackDecl, RuntimeStatement, ForLoop, ServerBlock, ClientBlock, HeadBlock;
498
+ var Expression, IRRoot, ComponentIR, StaticNode, TextNode, DynamicBinding, OpaqueDynamicRegion, MapRegion, ComponentRef, ComponentCall, SlotNode, PropSlot, PropSlotRender, WhileLoop, SwitchCase, SwitchBlock, TryCatch, TrackDecl, RuntimeStatement, BreakSignal, ForLoop, ServerBlock, ClientBlock, HeadBlock;
499
499
  var init_ir = __esm({
500
500
  "../compiler/src/ir.ts"() {
501
501
  "use strict";
@@ -742,6 +742,10 @@ var init_ir = __esm({
742
742
  this.source = source;
743
743
  }
744
744
  };
745
+ BreakSignal = class {
746
+ constructor() {
747
+ }
748
+ };
745
749
  ForLoop = class {
746
750
  init;
747
751
  condition;
@@ -889,6 +893,9 @@ function block(flags, fn, state = null, co) {
889
893
  }
890
894
  if (active_block !== null) {
891
895
  push_block(newBlock, active_block);
896
+ } else {
897
+ newBlock.p = get_orphan_root();
898
+ push_block(newBlock, newBlock.p);
892
899
  }
893
900
  if ((flags & EFFECT_BLOCK) !== 0) {
894
901
  schedule_update(newBlock);
@@ -978,6 +985,7 @@ function is_destroyed(target_block) {
978
985
  }
979
986
  function destroy_block(block2, remove_dom = true) {
980
987
  block2.f ^= DESTROYED;
988
+ unsubscribe_reaction(block2);
981
989
  let removed = false;
982
990
  const f = block2.f;
983
991
  if (remove_dom && (f & (BRANCH_BLOCK | ROOT_BLOCK)) !== 0 && (f & TRY_BLOCK) === 0 || (f & HEAD_BLOCK) !== 0) {
@@ -1013,6 +1021,28 @@ var init_ripple_utils = __esm({
1013
1021
  });
1014
1022
 
1015
1023
  // ../runtime/src/ripple-runtime.ts
1024
+ function get_orphan_root() {
1025
+ if (orphan_root === null) {
1026
+ orphan_root = {
1027
+ co: null,
1028
+ d: null,
1029
+ first: null,
1030
+ f: ROOT_BLOCK,
1031
+ fn: null,
1032
+ last: null,
1033
+ next: null,
1034
+ p: null,
1035
+ prev: null,
1036
+ s: null,
1037
+ t: null,
1038
+ tc: null
1039
+ };
1040
+ }
1041
+ return orphan_root;
1042
+ }
1043
+ function is_orphan(block2) {
1044
+ return block2 === null || block2 === void 0 || block2 === orphan_root;
1045
+ }
1016
1046
  function increment_clock() {
1017
1047
  return ++clock;
1018
1048
  }
@@ -1138,6 +1168,7 @@ function run_block(block2) {
1138
1168
  try {
1139
1169
  active_block = block2;
1140
1170
  active_reaction = block2;
1171
+ unsubscribe_reaction(block2);
1141
1172
  active_component = block2.co;
1142
1173
  destroy_non_branch_children(block2);
1143
1174
  run_teardown(block2);
@@ -1167,10 +1198,10 @@ function run_block(block2) {
1167
1198
  }
1168
1199
  }
1169
1200
  function tracked(v, block2, get2, set2) {
1170
- return new TrackedValue(v, block2 || active_block, get2 || set2 ? { get: get2, set: set2 } : empty_get_set);
1201
+ return new TrackedValue(v, block2 || active_block || get_orphan_root(), get2 || set2 ? { get: get2, set: set2 } : empty_get_set);
1171
1202
  }
1172
1203
  function derived(fn, block2, get2, set2) {
1173
- return new DerivedValue(fn, block2 || active_block, get2 || set2 ? { get: get2, set: set2 } : empty_get_set);
1204
+ return new DerivedValue(fn, block2 || active_block || get_orphan_root(), get2 || set2 ? { get: get2, set: set2 } : empty_get_set);
1174
1205
  }
1175
1206
  function track(v, b, get2, set2) {
1176
1207
  if (is_ripple_object(v)) {
@@ -1193,6 +1224,9 @@ function track(v, b, get2, set2) {
1193
1224
  }
1194
1225
  function create_dependency(tracked2) {
1195
1226
  const reaction = active_reaction;
1227
+ if (is_orphan(tracked2.b)) {
1228
+ (tracked2.r ??= /* @__PURE__ */ new Set()).add(reaction);
1229
+ }
1196
1230
  const existing = reaction.d;
1197
1231
  if (existing !== null) {
1198
1232
  reaction.d = existing.n;
@@ -1367,6 +1401,7 @@ function queue_microtask(fn) {
1367
1401
  }
1368
1402
  function schedule_update(block2) {
1369
1403
  if (block2 === null) return;
1404
+ if (block2.p === get_orphan_root() && globalThis.__vsk_ssr) return;
1370
1405
  if (scheduler_mode === FLUSH_MICROTASK) {
1371
1406
  queue_microtask();
1372
1407
  }
@@ -1426,6 +1461,36 @@ function register_dependency(tracked2) {
1426
1461
  current2.n = dependency;
1427
1462
  }
1428
1463
  }
1464
+ function unsubscribe_reaction(reaction) {
1465
+ if (reaction === null) return;
1466
+ let dep = reaction.d;
1467
+ while (dep !== null) {
1468
+ const t = dep.t;
1469
+ if (is_orphan(t.b) && t.r !== null) {
1470
+ t.r.delete(reaction);
1471
+ }
1472
+ dep = dep.n;
1473
+ }
1474
+ }
1475
+ function schedule_ownerless_update(tracked2, visited) {
1476
+ const subscribers = tracked2.r;
1477
+ if (subscribers === null) return;
1478
+ for (const reaction of Array.from(subscribers)) {
1479
+ if (visited !== null) {
1480
+ if (visited.has(reaction)) continue;
1481
+ visited.add(reaction);
1482
+ }
1483
+ if (reaction.f & DESTROYED) {
1484
+ subscribers.delete(reaction);
1485
+ continue;
1486
+ }
1487
+ if ((reaction.f & DERIVED) !== 0) {
1488
+ schedule_ownerless_update(reaction, visited ?? /* @__PURE__ */ new Set());
1489
+ continue;
1490
+ }
1491
+ schedule_update(reaction);
1492
+ }
1493
+ }
1429
1494
  function get_derived(computed) {
1430
1495
  update_derived(computed);
1431
1496
  if (tracking) {
@@ -1493,7 +1558,11 @@ function set(tracked2, value) {
1493
1558
  }
1494
1559
  tracked2.__v = value;
1495
1560
  tracked2.c = increment_clock();
1496
- schedule_update(tracked_block);
1561
+ if (!is_orphan(tracked_block)) {
1562
+ schedule_update(tracked_block);
1563
+ } else {
1564
+ schedule_ownerless_update(tracked2, null);
1565
+ }
1497
1566
  }
1498
1567
  }
1499
1568
  function untrack2(fn) {
@@ -1590,7 +1659,7 @@ function pop_component() {
1590
1659
  }
1591
1660
  active_component = component.p;
1592
1661
  }
1593
- var FLUSH_MICROTASK, FLUSH_SYNC, active_block, active_reaction, active_scope, active_component, is_mutating_allowed, old_values, scheduler_mode, is_micro_task_queued, clock, queued_root_blocks, disable_scoped_flush, queued_microtasks, flush_count, queued_post_block_flush, active_dependency, tracking, teardown, empty_get_set, TrackedValue, DerivedValue;
1662
+ var FLUSH_MICROTASK, FLUSH_SYNC, active_block, active_reaction, active_scope, active_component, is_mutating_allowed, old_values, orphan_root, scheduler_mode, is_micro_task_queued, clock, queued_root_blocks, disable_scoped_flush, queued_microtasks, flush_count, queued_post_block_flush, active_dependency, tracking, teardown, empty_get_set, TrackedValue, DerivedValue;
1594
1663
  var init_ripple_runtime = __esm({
1595
1664
  "../runtime/src/ripple-runtime.ts"() {
1596
1665
  "use strict";
@@ -1605,6 +1674,7 @@ var init_ripple_runtime = __esm({
1605
1674
  active_component = null;
1606
1675
  is_mutating_allowed = true;
1607
1676
  old_values = /* @__PURE__ */ new Map();
1677
+ orphan_root = null;
1608
1678
  scheduler_mode = FLUSH_MICROTASK;
1609
1679
  is_micro_task_queued = false;
1610
1680
  clock = 0;
@@ -1623,6 +1693,7 @@ var init_ripple_runtime = __esm({
1623
1693
  c;
1624
1694
  d;
1625
1695
  f;
1696
+ r;
1626
1697
  __v;
1627
1698
  constructor(v, block2, a) {
1628
1699
  this.a = a;
@@ -1630,6 +1701,7 @@ var init_ripple_runtime = __esm({
1630
1701
  this.c = 0;
1631
1702
  this.d = null;
1632
1703
  this.f = TRACKED;
1704
+ this.r = null;
1633
1705
  this.__v = v;
1634
1706
  }
1635
1707
  get() {
@@ -1670,6 +1742,7 @@ var init_ripple_runtime = __esm({
1670
1742
  d;
1671
1743
  f;
1672
1744
  fn;
1745
+ r;
1673
1746
  __v;
1674
1747
  constructor(fn, block2, a) {
1675
1748
  this.a = a;
@@ -1680,6 +1753,7 @@ var init_ripple_runtime = __esm({
1680
1753
  this.d = null;
1681
1754
  this.f = DERIVED;
1682
1755
  this.fn = fn;
1756
+ this.r = null;
1683
1757
  this.__v = UNINITIALIZED;
1684
1758
  }
1685
1759
  get() {
@@ -4769,7 +4843,7 @@ async function renderNotFound(router, match, container) {
4769
4843
  }
4770
4844
  if (container.replaceChildren) container.replaceChildren();
4771
4845
  else container.innerHTML = "";
4772
- container.innerHTML = "<h1>404 \u2014 Not Found</h1>";
4846
+ container.innerHTML = defaultErrorHtml(404, "Not Found");
4773
4847
  router._currentMatch = match;
4774
4848
  }
4775
4849
  function defaultOfflineHtml(url) {
@@ -4778,6 +4852,9 @@ function defaultOfflineHtml(url) {
4778
4852
  function escapeOfflineUrl(url) {
4779
4853
  return String(url).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
4780
4854
  }
4855
+ function defaultErrorHtml(status, message) {
4856
+ return '<div data-vesk-default-error="' + status + '" style="display:flex;align-items:center;justify-content:center;min-height:50vh;padding:32px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:inherit"><div style="display:flex;align-items:center"><span style="font-size:24px;font-weight:500;line-height:49px;padding-right:23px;margin-right:20px;border-right:1px solid currentColor;opacity:.85">' + status + '</span><span style="font-size:14px;line-height:49px;opacity:.7">' + message + "</span></div></div>";
4857
+ }
4781
4858
  async function renderOfflinePage(router, match, container) {
4782
4859
  const url = match.pathname || (typeof window !== "undefined" ? window.location.pathname : "");
4783
4860
  const chain = match.matchChain;
@@ -5066,7 +5143,7 @@ function renderMatch(router, match, container, navToken) {
5066
5143
  } else {
5067
5144
  container.innerHTML = "";
5068
5145
  }
5069
- container.innerHTML = "<h1>404 \u2014 Not Found</h1>";
5146
+ container.innerHTML = defaultErrorHtml(404, "Not Found");
5070
5147
  return;
5071
5148
  }
5072
5149
  if (pageNode._pageName && (!pageNode.page || typeof pageNode.page === "string")) {
@@ -5254,7 +5331,7 @@ async function renderErrorPage(router, match, container, error) {
5254
5331
  if (!errorFn) {
5255
5332
  if (container.replaceChildren) container.replaceChildren();
5256
5333
  else container.innerHTML = "";
5257
- container.innerHTML = "<h1>500 \u2014 Internal Server Error</h1>";
5334
+ container.innerHTML = defaultErrorHtml(500, "Internal Server Error");
5258
5335
  return;
5259
5336
  }
5260
5337
  const layoutNodes = chain.filter((n) => n.layout);
@@ -5318,7 +5395,7 @@ async function hydrateInitial(router, match, container, strategy) {
5318
5395
  });
5319
5396
  return;
5320
5397
  }
5321
- container.innerHTML = "<h1>404 \u2014 Not Found</h1>";
5398
+ container.innerHTML = defaultErrorHtml(404, "Not Found");
5322
5399
  return;
5323
5400
  }
5324
5401
  const ssrErrorMarker = (() => {
@@ -5975,7 +6052,7 @@ function createFileRouter(routeTree, options = {}) {
5975
6052
  }
5976
6053
  })();
5977
6054
  } else {
5978
- container.innerHTML = "<h1>404 \u2014 Not Found</h1>";
6055
+ container.innerHTML = defaultErrorHtml(404, "Not Found");
5979
6056
  }
5980
6057
  return;
5981
6058
  }
@@ -18320,6 +18397,20 @@ function tokenizeCode(code) {
18320
18397
  }
18321
18398
  });
18322
18399
  }
18400
+ function collectStringDelimiters(code, tokens) {
18401
+ const t = tokens == null ? tokenizeCode(code) : tokens;
18402
+ if (t === null) return null;
18403
+ const starts = /* @__PURE__ */ new Set();
18404
+ let ti = 0;
18405
+ for (let i = 0; i < code.length; i++) {
18406
+ const c = code.charCodeAt(i);
18407
+ if (c !== 34 && c !== 39 && c !== 96) continue;
18408
+ while (ti < t.length && t[ti].end <= i) ti++;
18409
+ const covered = ti < t.length && t[ti].start <= i;
18410
+ if (!covered || QUOTED_LABELS.has(t[ti].label)) starts.add(i);
18411
+ }
18412
+ return starts;
18413
+ }
18323
18414
  function containsIdentifier(code, name) {
18324
18415
  const tokens = tokenizeCode(code);
18325
18416
  if (tokens !== null) {
@@ -18511,33 +18602,33 @@ function manualExtractImportNames(importText) {
18511
18602
  }
18512
18603
  return names;
18513
18604
  }
18514
- function hasTopLevelValueDeclaration(code, name) {
18515
- const tokens = tokenizeCode(code);
18516
- if (tokens === null) return false;
18605
+ function hasTopLevelValueDeclaration(code, name, tokens) {
18606
+ const t = tokens == null ? tokenizeCode(code) : tokens;
18607
+ if (t === null) return false;
18517
18608
  const declWords = ["const", "let", "var", "function", "class"];
18518
- for (let i = 1; i < tokens.length; i++) {
18519
- if (tokens[i].label !== "name" || tokens[i].value !== name) continue;
18520
- const prev = tokens[i - 1];
18609
+ for (let i = 1; i < t.length; i++) {
18610
+ if (t[i].label !== "name" || t[i].value !== name) continue;
18611
+ const prev = t[i - 1];
18521
18612
  if (!prev || !declWords.includes(prev.value)) continue;
18522
18613
  if (i >= 2) {
18523
- const pp2 = tokens[i - 2];
18614
+ const pp2 = t[i - 2];
18524
18615
  if (pp2 && pp2.label === "name" && pp2.value === "export") continue;
18525
18616
  }
18526
18617
  return true;
18527
18618
  }
18528
18619
  return false;
18529
18620
  }
18530
- function findSpecifierExports(code) {
18531
- const tokens = tokenizeCode(code);
18532
- if (tokens === null) return [];
18621
+ function findSpecifierExports(code, tokens) {
18622
+ const t = tokens == null ? tokenizeCode(code) : tokens;
18623
+ if (t === null) return [];
18533
18624
  const out = [];
18534
- for (let i = 0; i < tokens.length; i++) {
18535
- if (tokens[i].label !== "export") continue;
18536
- if (!tokens[i + 1] || tokens[i + 1].label !== "{") continue;
18625
+ for (let i = 0; i < t.length; i++) {
18626
+ if (t[i].label !== "export") continue;
18627
+ if (!t[i + 1] || t[i + 1].label !== "{") continue;
18537
18628
  let k = i + 2;
18538
18629
  let depth = 1;
18539
- for (; k < tokens.length; k++) {
18540
- const lbl = tokens[k].label;
18630
+ for (; k < t.length; k++) {
18631
+ const lbl = t[k].label;
18541
18632
  if (lbl === "string") {
18542
18633
  continue;
18543
18634
  }
@@ -18548,8 +18639,8 @@ function findSpecifierExports(code) {
18548
18639
  }
18549
18640
  }
18550
18641
  let isReexport = false;
18551
- for (let j = k + 1; j < tokens.length; j++) {
18552
- const lbl = tokens[j].label;
18642
+ for (let j = k + 1; j < t.length; j++) {
18643
+ const lbl = t[j].label;
18553
18644
  if (lbl === "string") {
18554
18645
  isReexport = true;
18555
18646
  break;
@@ -18557,10 +18648,10 @@ function findSpecifierExports(code) {
18557
18648
  if (lbl === ";" || lbl === "export" || lbl === "import" || lbl === "}") break;
18558
18649
  }
18559
18650
  if (depth !== 0 || isReexport) continue;
18560
- const pairs = readSpecifierPairs(code, tokens[i + 1].end, tokens[k].end);
18651
+ const pairs = readSpecifierPairs(code, t[i + 1].end, t[k].end);
18561
18652
  if (pairs === null) continue;
18562
- const stmtEnd = tokens[k].end;
18563
- for (const [local, exported] of pairs) out.push({ local, exported, start: tokens[i].start, end: stmtEnd });
18653
+ const stmtEnd = t[k].end;
18654
+ for (const [local, exported] of pairs) out.push({ local, exported, start: t[i].start, end: stmtEnd });
18564
18655
  i = k;
18565
18656
  }
18566
18657
  return out;
@@ -18620,12 +18711,14 @@ function stripTrackDeclMarkers(text, base, node) {
18620
18711
  }
18621
18712
  return out + text.slice(prev);
18622
18713
  }
18714
+ var QUOTED_LABELS;
18623
18715
  var init_tokens = __esm({
18624
18716
  "../compiler/src/tokens.ts"() {
18625
18717
  "use strict";
18626
18718
  init_parser();
18627
18719
  init_vesk_plugin();
18628
18720
  init_scan();
18721
+ QUOTED_LABELS = /* @__PURE__ */ new Set(["string", "template", "`", "backQuote"]);
18629
18722
  }
18630
18723
  });
18631
18724
 
@@ -18649,7 +18742,7 @@ function offsetToLineCol(source, offset2) {
18649
18742
  }
18650
18743
  return { line, column };
18651
18744
  }
18652
- function preprocessForClauses(source) {
18745
+ function preprocessForClauses(source, delimiters) {
18653
18746
  const annotations = [];
18654
18747
  const chars = source.split("");
18655
18748
  const isString = (ch) => ch === '"' || ch === "'" || ch === "`";
@@ -18657,6 +18750,10 @@ function preprocessForClauses(source) {
18657
18750
  while (i < source.length) {
18658
18751
  const ch = source[i];
18659
18752
  if (isString(ch)) {
18753
+ if (delimiters && !delimiters.has(i)) {
18754
+ i++;
18755
+ continue;
18756
+ }
18660
18757
  const quote = ch;
18661
18758
  let j = i + 1;
18662
18759
  let tplDepth = 0;
@@ -19011,9 +19108,11 @@ function parseGeneratedJs(source) {
19011
19108
  }
19012
19109
  function parse4(source, options = {}) {
19013
19110
  const ParserClass = createBaseParser();
19014
- const { code, annotations } = preprocessForClauses(blankGenericArrowTypeParams(blankComments(source)));
19111
+ const sourceTokens = tokenizeCode(source);
19112
+ const delimiters = sourceTokens === null ? null : collectStringDelimiters(source, sourceTokens);
19113
+ const { code, annotations } = preprocessForClauses(blankGenericArrowTypeParams(blankComments(source)), delimiters);
19015
19114
  const vskSource = !options.filename || String(options.filename).endsWith(".vsk");
19016
- const specifierExports = vskSource ? findSpecifierExports(code).filter((e) => !hasTopLevelValueDeclaration(code, e.local)) : [];
19115
+ const specifierExports = vskSource && sourceTokens !== null ? findSpecifierExports(code, sourceTokens).filter((e) => !hasTopLevelValueDeclaration(code, e.local, sourceTokens)) : [];
19017
19116
  let parseable = code;
19018
19117
  if (specifierExports.length > 0) {
19019
19118
  const edits = specifierExports.map((e) => code.slice(e.start, e.end)).map((text) => text.split("").map((ch) => ch === "\n" ? "\n" : " ").join(""));
@@ -21463,6 +21562,7 @@ function processJSXCallbackBody(source, body) {
21463
21562
  for (const c of body.children) nodes.push(...processJSXChildren(source, [c]));
21464
21563
  return nodes;
21465
21564
  }
21565
+ if (body.type === "BlockStatement") return processStatementModeBody(source, body.body);
21466
21566
  if (body.type === "ParenthesizedExpression") return exprToIR(source, body.expression);
21467
21567
  return exprToIR(source, body);
21468
21568
  }
@@ -21621,6 +21721,29 @@ function getReturnStatement(node) {
21621
21721
  }
21622
21722
  return null;
21623
21723
  }
21724
+ function containsLoopControl(node) {
21725
+ if (!node) return false;
21726
+ if (node.type === "ContinueStatement" || node.type === "BreakStatement") return true;
21727
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") return false;
21728
+ if (node.type === "ForStatement" || node.type === "ForInStatement" || node.type === "ForOfStatement" || node.type === "WhileStatement" || node.type === "DoWhileStatement") return false;
21729
+ if (node.type === "BlockStatement") return node.body.some(containsLoopControl);
21730
+ if (node.type === "IfStatement") return containsLoopControl(node.consequent) || containsLoopControl(node.alternate);
21731
+ if (node.type === "SwitchStatement") return node.cases.some((c) => (c.consequent || []).some(containsLoopControl));
21732
+ if (node.type === "TryStatement") {
21733
+ return containsLoopControl(node.block) || containsLoopControl(node.handler) || containsLoopControl(node.finalizer);
21734
+ }
21735
+ if (node.type === "CatchClause") return containsLoopControl(node.body);
21736
+ if (node.type === "LabeledStatement") return containsLoopControl(node.body);
21737
+ return false;
21738
+ }
21739
+ function getLoopControlGuard(consequent, kind) {
21740
+ const stmts = consequent.type === "BlockStatement" ? consequent.body : [consequent];
21741
+ if (stmts.length === 0) return null;
21742
+ const want = kind === "continue" ? "ContinueStatement" : "BreakStatement";
21743
+ const last = stmts[stmts.length - 1];
21744
+ if (!last || last.type !== want) return null;
21745
+ return { pre: stmts.slice(0, -1), node: last };
21746
+ }
21624
21747
  function isStatementMode(bodyStmts) {
21625
21748
  if (bodyStmts.some((s) => s.type === "JSXElement" || s.type === "JSXExpressionContainer" || s.type === "JSXFragment")) return true;
21626
21749
  for (const stmt of bodyStmts) {
@@ -21659,6 +21782,9 @@ function processIfStatement(source, stmt) {
21659
21782
  return [new OpaqueDynamicRegion(condExpr, consequent, alternate)];
21660
21783
  }
21661
21784
  function processForStatement(source, stmt, alternate = []) {
21785
+ if (stmt.body && !hasJSXInSubtree(stmt.body) && containsLoopControl(stmt.body)) {
21786
+ return [new RuntimeStatement(getSource(source, stmt), stmt, source)];
21787
+ }
21662
21788
  if (stmt.type === "ForOfStatement") {
21663
21789
  const left = stmt.left;
21664
21790
  let itemVar = "item";
@@ -21692,6 +21818,9 @@ function processForStatement(source, stmt, alternate = []) {
21692
21818
  return [];
21693
21819
  }
21694
21820
  function processWhileStatement(source, stmt) {
21821
+ if (stmt.body && !hasJSXInSubtree(stmt.body) && containsLoopControl(stmt.body)) {
21822
+ return [new RuntimeStatement(getSource(source, stmt), stmt, source)];
21823
+ }
21695
21824
  const condition = toExpression(source, stmt.test);
21696
21825
  const bodyTemplate = processBlockBody(source, stmt.body);
21697
21826
  const isDoWhile = stmt.type === "DoWhileStatement";
@@ -21757,6 +21886,18 @@ function processStatementModeBody(source, bodyStmts, filename) {
21757
21886
  nodes.push(new OpaqueDynamicRegion(toExpression(source, stmt.test), consequent, alternate));
21758
21887
  break;
21759
21888
  }
21889
+ if (!stmt.alternate) {
21890
+ const guardContinue = getLoopControlGuard(stmt.consequent, "continue");
21891
+ const guardBreak = guardContinue ? null : getLoopControlGuard(stmt.consequent, "break");
21892
+ const guard = guardContinue || guardBreak;
21893
+ if (guard) {
21894
+ const consequent = guard.pre.length ? processStatementModeBody(source, guard.pre, filename) : [];
21895
+ if (guardBreak) consequent.push(new BreakSignal());
21896
+ const alternate = processStatementModeBody(source, bodyStmts.slice(i + 1), filename);
21897
+ nodes.push(new OpaqueDynamicRegion(toExpression(source, stmt.test), consequent, alternate));
21898
+ break;
21899
+ }
21900
+ }
21760
21901
  nodes.push(...processIfStatement(source, stmt));
21761
21902
  } else if (stmt.type === "ForOfStatement") {
21762
21903
  let alternate = [];
@@ -21794,6 +21935,11 @@ function processStatementModeBody(source, bodyStmts, filename) {
21794
21935
  } else if (stmt.type === "ClassDeclaration") {
21795
21936
  const { line, column } = offsetToLineCol2(source, stmt.start ?? 0);
21796
21937
  throw VeskError.classDecl({ file: filename || "", line, column, code: codeFrame(source, line, column) });
21938
+ } else if (stmt.type === "ContinueStatement") {
21939
+ break;
21940
+ } else if (stmt.type === "BreakStatement") {
21941
+ nodes.push(new BreakSignal());
21942
+ break;
21797
21943
  } else {
21798
21944
  const raw2 = getSource(source, stmt);
21799
21945
  if (raw2) nodes.push(new RuntimeStatement(raw2, stmt, source));
@@ -21925,6 +22071,7 @@ function warnStaleConstBindings(comp, file) {
21925
22071
  if (d.id?.type !== "Identifier" || !d.init) continue;
21926
22072
  if (reactive.has(d.id.name)) continue;
21927
22073
  if (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression") continue;
22074
+ if (isReactiveFactoryCall(d.init)) continue;
21928
22075
  if (d.init.type === "Identifier" && reactive.has(d.init.name)) continue;
21929
22076
  const seen = /* @__PURE__ */ new Set();
21930
22077
  collectIdentifiers(d.init, seen);
@@ -21965,6 +22112,16 @@ function warnStaleConstBindings(comp, file) {
21965
22112
  }
21966
22113
  });
21967
22114
  }
22115
+ function isReactiveFactoryCall(node) {
22116
+ if (!node || node.type !== "CallExpression") return false;
22117
+ const callee = node.callee;
22118
+ if (!callee) return false;
22119
+ if (callee.type === "Identifier") return callee.name === "derived";
22120
+ if (callee.type === "MemberExpression" && !callee.computed) {
22121
+ return callee.property?.type === "Identifier" && callee.property.name === "derived";
22122
+ }
22123
+ return false;
22124
+ }
21968
22125
  function collectIdentifiers(node, into) {
21969
22126
  if (!node || typeof node !== "object") return;
21970
22127
  if (Array.isArray(node)) {
@@ -21972,6 +22129,15 @@ function collectIdentifiers(node, into) {
21972
22129
  return;
21973
22130
  }
21974
22131
  if (typeof node.type !== "string") return;
22132
+ if (node.type === "MemberExpression" && !node.computed) {
22133
+ collectIdentifiers(node.object, into);
22134
+ if (node.property?.type === "MemberExpression") collectIdentifiers(node.property, into);
22135
+ return;
22136
+ }
22137
+ if ((node.type === "Property" || node.type === "PropertyDefinition" || node.type === "MethodDefinition") && !node.computed) {
22138
+ collectIdentifiers(node.value, into);
22139
+ return;
22140
+ }
21975
22141
  if (node.type === "Identifier" && typeof node.name === "string") into.add(node.name);
21976
22142
  for (const key of Object.keys(node)) {
21977
22143
  if (key === "loc" || key === "range" || key === "start" || key === "end") continue;
@@ -30303,14 +30469,36 @@ function transformTracked(irNode, tracked2) {
30303
30469
  }
30304
30470
  function collectTrackedNames(body) {
30305
30471
  const names = /* @__PURE__ */ new Map();
30472
+ collectTrackedNamesInto(body, names);
30473
+ return names;
30474
+ }
30475
+ function collectTrackedNamesInto(body, names) {
30306
30476
  for (const node of body) {
30307
30477
  if (node instanceof TrackDecl) {
30308
30478
  const cellName = node.rawName || node.name;
30309
30479
  names.set(node.name, { cellName, kind: "virtual" });
30310
30480
  if (node.rawName) names.set(node.rawName, { cellName, kind: "cell" });
30481
+ } else if (node instanceof StaticNode || node instanceof ServerBlock || node instanceof ClientBlock || node instanceof HeadBlock) {
30482
+ collectTrackedNamesInto(node.children, names);
30483
+ } else if (node instanceof ComponentCall) {
30484
+ collectTrackedNamesInto(node.children, names);
30485
+ } else if (node instanceof PropSlot) {
30486
+ collectTrackedNamesInto(node.body, names);
30487
+ } else if (node instanceof MapRegion) {
30488
+ collectTrackedNamesInto(node.bodyTemplate, names);
30489
+ collectTrackedNamesInto(node.alternateNodes, names);
30490
+ } else if (node instanceof OpaqueDynamicRegion) {
30491
+ collectTrackedNamesInto(node.consequentNodes, names);
30492
+ collectTrackedNamesInto(node.alternateNodes, names);
30493
+ } else if (node instanceof WhileLoop || node instanceof ForLoop) {
30494
+ collectTrackedNamesInto(node.bodyTemplate, names);
30495
+ } else if (node instanceof TryCatch) {
30496
+ collectTrackedNamesInto(node.bodyTemplate, names);
30497
+ collectTrackedNamesInto(node.catchBody, names);
30498
+ } else if (node instanceof SwitchBlock) {
30499
+ for (const c of node.cases) collectTrackedNamesInto(c.body, names);
30311
30500
  }
30312
30501
  }
30313
- return names;
30314
30502
  }
30315
30503
  function collectTrackedDeps(value, tracked2) {
30316
30504
  const ast = value?.ast;
@@ -30396,11 +30584,20 @@ function emitNode(ctx2, node, tracked2, effectsVar, parentVar, compPrefix = "__c
30396
30584
  ctx2.push(semicolonizeStatement(transformTracked(node, tracked2)));
30397
30585
  return null;
30398
30586
  }
30587
+ if (node instanceof BreakSignal) {
30588
+ if (ctx2.breakFlag) ctx2.push(`${ctx2.breakFlag} = true;`);
30589
+ return null;
30590
+ }
30399
30591
  if (node instanceof SlotNode) {
30400
30592
  if (!parentVar) {
30401
30593
  if (ctx2.hydrate) {
30594
+ const promptExpr = ctx2.markerless && (regionBudget || skipK > 0) ? markerlessSkipExpr(regionBudget, skipK) : null;
30402
30595
  ctx2.push(`if (props.children !== undefined && props.children !== null) {`);
30403
30596
  ctx2.push(` if (typeof props.children === 'function') {`);
30597
+ if (promptExpr) {
30598
+ ctx2.push(` ${ctx2.walker}.injectSkipK(${promptExpr});`);
30599
+ if (regionBudget && ctx2.markerless) ctx2.push(` ${regionBudget} = 0;`);
30600
+ }
30404
30601
  ctx2.push(` __pendingChild = props.children(__hydrate);`);
30405
30602
  ctx2.push(` } else if (__hydrate && __hydrate.root) {`);
30406
30603
  ctx2.push(` __hydrate.root.appendChild(toDomNode(props.children));`);
@@ -31197,12 +31394,18 @@ function emitWhileLoop(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget)
31197
31394
  ctx2.push(`const ${endAnchor} = document.createComment('while-end');`);
31198
31395
  emitHydrateFenceAnchoring(ctx2, anchor, endAnchor, parent === "$root", budget || void 0);
31199
31396
  const renderLoop = ctx2.n();
31397
+ const hasBreak = bodyHasBreak(node.bodyTemplate);
31398
+ const breakVar = hasBreak ? ctx2.n() : null;
31200
31399
  ctx2.push(`const ${renderLoop} = ${ctx2.isAsyncScope ? "async () => {" : "() => {"}`);
31201
31400
  if (!hyd) ctx2.push(indent2(`const __p = ${anchor}.parentNode;`));
31202
31401
  if (!hyd) ctx2.push(indent2(`const __b = document.createDocumentFragment();`));
31203
31402
  if (hyd) ctx2.push(indent2(`const __cl = [];`));
31403
+ if (breakVar) ctx2.push(indent2(`let ${breakVar} = false;`));
31404
+ const savedBreakFlag = ctx2.breakFlag;
31405
+ ctx2.breakFlag = breakVar;
31204
31406
  if (node.isDoWhile) {
31205
31407
  ctx2.push(indent2(`do {`));
31408
+ if (breakVar) ctx2.push(indent2(indent2(`if (${breakVar}) break;`)));
31206
31409
  for (const n of node.bodyTemplate) {
31207
31410
  const v = emitNode(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
31208
31411
  if (v) {
@@ -31213,6 +31416,7 @@ function emitWhileLoop(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget)
31213
31416
  ctx2.push(indent2(`} while (${condExpr});`));
31214
31417
  } else {
31215
31418
  ctx2.push(indent2(`while (${condExpr}) {`));
31419
+ if (breakVar) ctx2.push(indent2(indent2(`if (${breakVar}) break;`)));
31216
31420
  for (const n of node.bodyTemplate) {
31217
31421
  const v = emitNode(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
31218
31422
  if (v) {
@@ -31222,6 +31426,7 @@ function emitWhileLoop(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget)
31222
31426
  }
31223
31427
  ctx2.push(indent2(`}`));
31224
31428
  }
31429
+ ctx2.breakFlag = savedBreakFlag;
31225
31430
  if (!hyd) ctx2.push(indent2(`__p.insertBefore(__b, ${endAnchor});`));
31226
31431
  if (hyd) ctx2.push(indent2(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
31227
31432
  ctx2.push(`};`);
@@ -31261,13 +31466,19 @@ function emitForLoop(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget) {
31261
31466
  ctx2.push(`const ${endAnchor} = document.createComment('for-end');`);
31262
31467
  emitHydrateFenceAnchoring(ctx2, anchor, endAnchor, parent === "$root", budget || void 0);
31263
31468
  const renderLoop = ctx2.n();
31469
+ const forHasBreak = bodyHasBreak(node.bodyTemplate);
31470
+ const forBreakVar = forHasBreak ? ctx2.n() : null;
31264
31471
  ctx2.push(`const ${renderLoop} = ${ctx2.isAsyncScope ? "async () => {" : "() => {"}`);
31265
31472
  if (!hyd) ctx2.push(indent2(`const __p = ${anchor}.parentNode;`));
31266
31473
  if (!hyd) ctx2.push(indent2(`const __b = document.createDocumentFragment();`));
31267
31474
  if (hyd) ctx2.push(indent2(`const __cl = [];`));
31475
+ if (forBreakVar) ctx2.push(indent2(`let ${forBreakVar} = false;`));
31476
+ const savedForBreakFlag = ctx2.breakFlag;
31477
+ ctx2.breakFlag = forBreakVar;
31268
31478
  if (node.kind === "for-in") {
31269
31479
  const srcExpr = transformTracked(node.condition, tracked2);
31270
31480
  ctx2.push(indent2(`for (${node.init} of (Array.isArray(${srcExpr}) ? ${srcExpr} : (${srcExpr} == null ? [] : Object.keys(${srcExpr})))) {`));
31481
+ if (forBreakVar) ctx2.push(indent2(indent2(`if (${forBreakVar}) break;`)));
31271
31482
  for (const n of node.bodyTemplate) {
31272
31483
  const v = emitNode(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
31273
31484
  if (v) {
@@ -31284,6 +31495,7 @@ function emitForLoop(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget) {
31284
31495
  if (updatePart.endsWith(";")) updatePart = updatePart.slice(0, -1).trim();
31285
31496
  const head = initPart ? `${initPart}; ${condExpr}` : `; ${condExpr}`;
31286
31497
  ctx2.push(indent2(`for (${head}; ${updatePart}) {`));
31498
+ if (forBreakVar) ctx2.push(indent2(indent2(`if (${forBreakVar}) break;`)));
31287
31499
  for (const n of node.bodyTemplate) {
31288
31500
  const v = emitNode(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
31289
31501
  if (v) {
@@ -31293,6 +31505,7 @@ function emitForLoop(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget) {
31293
31505
  }
31294
31506
  ctx2.push(indent2(`}`));
31295
31507
  }
31508
+ ctx2.breakFlag = savedForBreakFlag;
31296
31509
  if (!hyd) ctx2.push(indent2(`__p.insertBefore(__b, ${endAnchor});`));
31297
31510
  if (hyd) ctx2.push(indent2(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
31298
31511
  ctx2.push(`};`);
@@ -31453,6 +31666,27 @@ function emitSwitchBlock(ctx2, node, tracked2, parentVar, skipK = 0, regionBudge
31453
31666
  }`);
31454
31667
  return null;
31455
31668
  }
31669
+ function bodyHasBreak(nodes) {
31670
+ for (const n of nodes) {
31671
+ if (n instanceof BreakSignal) return true;
31672
+ if (n instanceof OpaqueDynamicRegion) {
31673
+ if (bodyHasBreak([...n.consequentNodes, ...n.alternateNodes])) return true;
31674
+ } else if (n instanceof SwitchBlock) {
31675
+ for (const c of n.cases) if (bodyHasBreak(c.body)) return true;
31676
+ } else if (n instanceof TryCatch) {
31677
+ if (bodyHasBreak([...n.bodyTemplate, ...n.catchBody])) return true;
31678
+ } else if (n instanceof StaticNode) {
31679
+ if (bodyHasBreak(n.children)) return true;
31680
+ } else if (n instanceof ComponentCall) {
31681
+ if (bodyHasBreak(n.children)) return true;
31682
+ } else if (n instanceof ServerBlock || n instanceof ClientBlock || n instanceof HeadBlock) {
31683
+ if (bodyHasBreak(n.children)) return true;
31684
+ } else if (n instanceof PropSlot) {
31685
+ if (bodyHasBreak(n.body)) return true;
31686
+ }
31687
+ }
31688
+ return false;
31689
+ }
31456
31690
  function emitMap(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBudget) {
31457
31691
  const arrExpr = transformTracked(node.expression, tracked2);
31458
31692
  const itemVar = node.itemVariable;
@@ -31485,9 +31719,13 @@ function emitMap(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBu
31485
31719
  ctx2.push(`let ${effectsVar} = [];`);
31486
31720
  ctx2.push(`const ${endAnchor} = document.createComment('map-end');`);
31487
31721
  const renderItem = ctx2.n();
31722
+ const hasBreak = bodyHasBreak(node.bodyTemplate);
31723
+ const breakVar = hasBreak ? ctx2.n() : null;
31724
+ if (breakVar) ctx2.push(`let ${breakVar} = false;`);
31488
31725
  const indexParam = node.indexVariable ? ", __i" : "";
31489
31726
  ctx2.push(`const ${renderItem} = ${ctx2.isAsyncScope ? "async " : ""}(${itemVar}${indexParam}, __e, __r${hyd ? ", __cl" : ""}${hydKeyed ? ", __root" : ""}) => {`);
31490
31727
  ctx2.push(indent2(`__r = __r || ${endAnchor};`));
31728
+ if (breakVar) ctx2.push(indent2(`if (${breakVar}) return;`));
31491
31729
  if (node.indexVariable) ctx2.push(indent2(`const ${node.indexVariable} = __i;`));
31492
31730
  if (hyd) {
31493
31731
  ctx2.push(indent2(`const __p = ${anchor}.parentNode;`));
@@ -31496,6 +31734,8 @@ function emitMap(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBu
31496
31734
  ctx2.push(indent2(`const __it = document.createDocumentFragment();`));
31497
31735
  }
31498
31736
  if (hydKeyed) ctx2.rootClaim = true;
31737
+ const savedMapBreak = ctx2.breakFlag;
31738
+ ctx2.breakFlag = breakVar;
31499
31739
  for (const n of node.bodyTemplate) {
31500
31740
  const v = emitNode(ctx2, n, tracked2, "__e", hyd ? void 0 : "__it", "__components", 0, budget || void 0);
31501
31741
  if (v) {
@@ -31508,6 +31748,7 @@ function emitMap(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBu
31508
31748
  }
31509
31749
  }
31510
31750
  }
31751
+ ctx2.breakFlag = savedMapBreak;
31511
31752
  if (hydKeyed) ctx2.rootClaim = false;
31512
31753
  if (!hyd) ctx2.push(indent2(`if (__it.childNodes.length > 0) __p.insertBefore(__it, __r);`));
31513
31754
  ctx2.push(`};`);
@@ -31543,11 +31784,12 @@ function emitMap(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBu
31543
31784
  const keyFnSrc = `(${itemVar}${node.indexVariable ? `, ${node.indexVariable}` : ""}) => ${keyExpr}`;
31544
31785
  const reconciler = ctx2.n();
31545
31786
  const initList = ctx2.n();
31787
+ const breakReset = breakVar ? `${breakVar} = false; ` : "";
31546
31788
  ctx2.push(`let ${reconciler} = () => {};`);
31547
31789
  if (hydKeyed) {
31548
- ctx2.push(`const ${initList} = () => { ${reconciler} = reconcileHydrated(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e, __root) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"}, null, __root), __hydrate, ${parent}, ${skipK}); };`);
31790
+ ctx2.push(`const ${initList} = () => { ${breakReset}${reconciler} = reconcileHydrated(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e, __root) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"}, null, __root), __hydrate, ${parent}, ${skipK}); };`);
31549
31791
  } else {
31550
- ctx2.push(`const ${initList} = () => { ${reconciler} = reconcile(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"})); };`);
31792
+ ctx2.push(`const ${initList} = () => { ${breakReset}${reconciler} = reconcile(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"})); };`);
31551
31793
  }
31552
31794
  if (emptyRenderName) {
31553
31795
  const isEmptyVar = ctx2.n();
@@ -31558,7 +31800,7 @@ function emitMap(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBu
31558
31800
  const __new = ${hasItems}();
31559
31801
  if (__first) { __first = false; __new; return; }
31560
31802
  if (__new !== ${isEmptyVar}) {
31561
- if (__new) ${reconciler}(${arrExpr});
31803
+ if (__new) {${breakVar ? ` ${breakVar} = false;` : ""} ${reconciler}(${arrExpr}); }
31562
31804
  return;
31563
31805
  }
31564
31806
  ${isEmptyVar} = !__new;
@@ -31572,22 +31814,25 @@ function emitMap(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBu
31572
31814
  if (!reactiveSource) return null;
31573
31815
  pushEffect(`let __first = true;`, `effect(() => {
31574
31816
  const __nv = ${arrExpr};
31575
- if (__first) { __first = false; __nv; ${reconciler}(${arrExpr}); return; }
31576
- ${reconciler}(${arrExpr});
31817
+ if (__first) { __first = false; __nv; ${breakReset}${reconciler}(${arrExpr}); return; }
31818
+ ${breakVar ? `if (${breakVar}) ${breakVar} = false;` : ""}${reconciler}(${arrExpr});
31577
31819
  })`);
31578
31820
  }
31579
31821
  } else {
31580
31822
  const renderAllItems = (ind, collect) => {
31581
31823
  const lines = [];
31824
+ if (breakVar) lines.push(`${ind}${breakVar} = false;`);
31582
31825
  if (node.indexVariable) {
31583
31826
  lines.push(`${ind}let __i = 0;`);
31584
31827
  lines.push(`${ind}for (const ${itemVar} of ${arrExpr}) {`);
31585
31828
  lines.push(`${ind} ${aw}${renderItem}(${itemVar}, __i, ${effectsVar}${collect ? `, null, ${collect}` : ""});`);
31586
31829
  lines.push(`${ind} __i++;`);
31830
+ if (breakVar) lines.push(`${ind} if (${breakVar}) break;`);
31587
31831
  lines.push(`${ind}}`);
31588
31832
  } else {
31589
31833
  lines.push(`${ind}for (const ${itemVar} of ${arrExpr}) {`);
31590
31834
  lines.push(`${ind} ${aw}${renderItem}(${itemVar}, ${effectsVar}${collect ? `, null, ${collect}` : ""});`);
31835
+ if (breakVar) lines.push(`${ind} if (${breakVar}) break;`);
31591
31836
  lines.push(`${ind}}`);
31592
31837
  }
31593
31838
  return lines.join("\n");
@@ -32160,6 +32405,9 @@ var init_client_codegen = __esm({
32160
32405
  walker = "__hydrate";
32161
32406
  asyncComps = /* @__PURE__ */ new Set();
32162
32407
  isAsyncScope = false;
32408
+ // While emitting a loop body, names the boolean flag a `break` sets (see
32409
+ // BreakSignal). Null outside a break-capable loop body.
32410
+ breakFlag = null;
32163
32411
  constructor(alloc) {
32164
32412
  this.alloc = alloc ?? { c: 0 };
32165
32413
  }
@@ -32881,6 +33129,7 @@ function irNodeToJS(node, importedNames, isAsync = false, tracked2) {
32881
33129
  }
32882
33130
  return semicolonizeStatement(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
32883
33131
  }
33132
+ if (node instanceof BreakSignal) return `break;`;
32884
33133
  if (node instanceof SlotNode) {
32885
33134
  if (__vskMarkerless) return `__out.push(props.children || '');`;
32886
33135
  const sid = `s${nextVskId()}`;
@@ -33031,14 +33280,15 @@ function mapRegionToJS(node, isAsync = false, tracked2) {
33031
33280
  }
33032
33281
  const loopArr = arrVar || arr;
33033
33282
  if (node.indexVariable) {
33034
- lines.push("let __i = 0;");
33283
+ const counter = `__i${nextVskId()}`;
33284
+ lines.push(`let ${counter} = 0;`);
33035
33285
  lines.push(`for (const ${item} of ${loopArr}) {`);
33036
- lines.push(indent(`const ${node.indexVariable} = __i;`));
33286
+ lines.push(indent(`const ${node.indexVariable} = ${counter};`));
33037
33287
  for (const n of bodyForItem) {
33038
33288
  const code = irNodeToJS(n, null, isAsync, tracked2);
33039
33289
  if (code) lines.push(indent(code));
33040
33290
  }
33041
- lines.push(indent("__i++;"));
33291
+ lines.push(indent(`${counter}++;`));
33042
33292
  lines.push(`}`);
33043
33293
  } else {
33044
33294
  lines.push(`for (const ${item} of ${loopArr}) {`);
@@ -34121,6 +34371,94 @@ var init_server_render = __esm({
34121
34371
  }
34122
34372
  });
34123
34373
 
34374
+ // ../adapter/src/default-pages.ts
34375
+ function escapeDefaultPageHtml(value) {
34376
+ return String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
34377
+ }
34378
+ function renderDefaultPage(opts = {}) {
34379
+ const status = opts.status ?? 404;
34380
+ const title = escapeDefaultPageHtml(opts.title ?? `${status} \u2014 Vesk`);
34381
+ const message = escapeDefaultPageHtml(opts.message ?? "This page could not be found.");
34382
+ const url = opts.url ? escapeDefaultPageHtml(opts.url) : "";
34383
+ const headExtra = opts.headExtra || "";
34384
+ const homeHref = opts.homeHref === void 0 ? "/" : opts.homeHref;
34385
+ const homeLabel = escapeDefaultPageHtml(opts.homeLabel ?? "Back to home");
34386
+ const variant = `vsk-page${opts.accentStatus ? " vsk-page--error" : ""}`;
34387
+ const action = homeHref === null ? "" : `<a class="vsk-page__btn" href="${escapeDefaultPageHtml(homeHref)}">${homeLabel}</a>`;
34388
+ return `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="robots" content="noindex"><title>${title}</title><style>${DEFAULT_PAGE_CSS}</style>` + headExtra + `</head><body><main class="${variant}" data-vesk-default-page="${status}"><div class="vsk-page__card"><p class="vsk-page__brand"><b>Vesk</b> \xB7 built-in error page</p><div class="vsk-page__row"><span class="vsk-page__status">${status}</span><span class="vsk-page__msg">${message}</span></div>` + (url ? `<p class="vsk-page__detail">${url}</p>` : "") + (action ? `<div class="vsk-page__actions">${action}</div>` : "") + "</div></main></body></html>";
34389
+ }
34390
+ function renderDefaultNotFoundPage(opts = {}) {
34391
+ return renderDefaultPage({
34392
+ status: 404,
34393
+ title: "404 \u2014 Not Found",
34394
+ message: "This page could not be found.",
34395
+ url: opts.url,
34396
+ headExtra: opts.headExtra
34397
+ });
34398
+ }
34399
+ function renderDefaultErrorPage(opts = {}) {
34400
+ const status = opts.status ?? 500;
34401
+ return renderDefaultPage({
34402
+ status,
34403
+ title: `${status} \u2014 Internal Server Error`,
34404
+ message: opts.message || "Internal Server Error",
34405
+ url: opts.url,
34406
+ headExtra: opts.headExtra,
34407
+ accentStatus: true,
34408
+ homeHref: null
34409
+ });
34410
+ }
34411
+ function renderDefaultErrorFragment(opts = {}) {
34412
+ const status = opts.status ?? 500;
34413
+ const message = escapeDefaultPageHtml(opts.message || "Internal Server Error");
34414
+ return '<div data-vesk-default-error-fragment="' + status + '" style="display:flex;align-items:center;justify-content:center;min-height:60vh;padding:32px"><div style="display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace"><div style="display:flex;align-items:center"><span style="font-size:24px;font-weight:500;line-height:49px;padding-right:23px;margin-right:20px;border-right:1px solid currentColor;opacity:.85">' + status + '</span><span style="font-size:14px;line-height:49px;opacity:.7">' + message + "</span></div></div></div>";
34415
+ }
34416
+ var DEFAULT_PAGE_CSS;
34417
+ var init_default_pages = __esm({
34418
+ "../adapter/src/default-pages.ts"() {
34419
+ "use strict";
34420
+ DEFAULT_PAGE_CSS = [
34421
+ ":root{color-scheme:light;",
34422
+ "--vsk-bg:oklch(0.941 0.014 88);",
34423
+ "--vsk-fg:oklch(0.185 0.008 62);",
34424
+ "--vsk-surface:oklch(0.965 0.012 88);",
34425
+ "--vsk-muted:oklch(0.475 0.014 72);",
34426
+ "--vsk-accent:oklch(0.560 0.140 42);",
34427
+ "--vsk-border:oklch(0.86 0.012 82);",
34428
+ "--vsk-border-strong:oklch(0.72 0.014 80);",
34429
+ '--vsk-font:"Space Grotesk",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;',
34430
+ '--vsk-mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;}',
34431
+ "@media (prefers-color-scheme:dark){:root{color-scheme:dark;",
34432
+ "--vsk-bg:oklch(0.155 0.006 60);",
34433
+ "--vsk-fg:oklch(0.931 0.014 88);",
34434
+ "--vsk-surface:oklch(0.196 0.008 70);",
34435
+ "--vsk-muted:oklch(0.618 0.016 80);",
34436
+ "--vsk-accent:oklch(0.632 0.132 45);",
34437
+ "--vsk-border:oklch(0.29 0.009 75);",
34438
+ "--vsk-border-strong:oklch(0.40 0.011 75);}}",
34439
+ "*{box-sizing:border-box}",
34440
+ "html,body{margin:0;min-height:100%}",
34441
+ "body{background:var(--vsk-bg);color:var(--vsk-fg);font-family:var(--vsk-font);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}",
34442
+ ".vsk-page{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}",
34443
+ ".vsk-page__card{width:100%;max-width:540px;border:1px solid var(--vsk-border);background:var(--vsk-surface);padding:clamp(28px,6vw,44px);text-align:center}",
34444
+ "@supports (background:color-mix(in oklab,red,red)){.vsk-page__card{background:color-mix(in oklab,var(--vsk-surface) 60%,transparent)}}",
34445
+ ".vsk-page__brand{margin:0 0 26px;font-family:var(--vsk-mono);font-size:10px;line-height:1;letter-spacing:.24em;text-transform:uppercase;color:var(--vsk-muted)}",
34446
+ ".vsk-page__brand b{color:var(--vsk-fg);font-weight:600}",
34447
+ ".vsk-page__row{display:flex;align-items:center;justify-content:center;gap:0;flex-wrap:wrap}",
34448
+ ".vsk-page__status{font-size:clamp(34px,9vw,46px);font-weight:600;line-height:1;letter-spacing:-.03em;padding-right:22px;margin-right:22px;border-right:1px solid var(--vsk-border-strong)}",
34449
+ ".vsk-page--error .vsk-page__status{color:var(--vsk-accent)}",
34450
+ ".vsk-page__msg{font-family:var(--vsk-mono);font-size:13px;line-height:1.5;color:var(--vsk-muted);text-align:left;max-width:270px}",
34451
+ "@media (max-width:440px){.vsk-page__row{flex-direction:column}.vsk-page__status{padding:0 0 16px;margin:0 0 16px;border-right:0;border-bottom:1px solid var(--vsk-border-strong)}.vsk-page__msg{text-align:center}}",
34452
+ ".vsk-page__detail{margin:20px 0 0;font-family:var(--vsk-mono);font-size:11px;line-height:1.6;color:var(--vsk-muted);word-break:break-all}",
34453
+ ".vsk-page__actions{margin-top:30px;display:flex;justify-content:center;gap:10px;flex-wrap:wrap}",
34454
+ ".vsk-page__btn{display:inline-block;padding:11px 22px;font-size:13px;font-weight:500;line-height:1;text-decoration:none;border:1px solid var(--vsk-fg);background:var(--vsk-fg);color:var(--vsk-bg);transition:opacity .18s cubic-bezier(.2,0,0,1)}",
34455
+ ".vsk-page__btn:hover{opacity:.86}",
34456
+ ".vsk-page__btn--ghost{background:transparent;color:var(--vsk-fg);border-color:var(--vsk-border-strong)}",
34457
+ ".vsk-page__btn--ghost:hover{background:var(--vsk-fg);color:var(--vsk-bg);border-color:var(--vsk-fg);opacity:1}"
34458
+ ].join("");
34459
+ }
34460
+ });
34461
+
34124
34462
  // ../adapter/src/paths.ts
34125
34463
  import { resolve as resolve11, sep as sep2 } from "node:path";
34126
34464
  import { existsSync as existsSync12, statSync as statSync4, readFileSync as readFileSync12 } from "node:fs";
@@ -35707,6 +36045,7 @@ function generatePlatformHandlerSource(input) {
35707
36045
  const prerenderedList = prerenderedPaths.length > 0 ? `const __prerendered = new Set(${JSON.stringify(prerenderedPaths)});
35708
36046
  ` : "const __prerendered = new Set();\n";
35709
36047
  const isrCache = "const __isrCache = new Map();";
36048
+ const defaultNotFoundLine = `const __defaultNotFoundHtml = ${JSON.stringify(renderDefaultNotFoundPage())};`;
35710
36049
  const serverStoreLine = hasEvents ? "const __serverStore = globalThis.__vesk_server_ctx || {};" : "";
35711
36050
  const eventsStartLine = hasEvents ? " await __eventsStart({ server: null });" : "";
35712
36051
  const eventsRequestLine = hasEvents ? " await __eventsRequest(mwCtx);" : "";
@@ -35720,6 +36059,7 @@ ${mwImport}
35720
36059
  ${eventsImport}
35721
36060
  ${prerenderedList}
35722
36061
  ${isrCache}
36062
+ ${defaultNotFoundLine}
35723
36063
  const __routes = [${routeEntries.join(",\n")}];
35724
36064
 
35725
36065
  async function __invokeRoute(route, request) {
@@ -35733,7 +36073,7 @@ async function __invokeRoute(route, request) {
35733
36073
  });
35734
36074
  }
35735
36075
  if (e && typeof e === 'object' && e.name === 'NotFoundError') {
35736
- return new Response('<!DOCTYPE html><html><body><h1>404</h1><p>Not Found</p></body></html>', {
36076
+ return new Response(__defaultNotFoundHtml, {
35737
36077
  status: 404,
35738
36078
  headers: { 'Content-Type': 'text/html' },
35739
36079
  });
@@ -35794,6 +36134,20 @@ ${serverStoreLine}
35794
36134
  });
35795
36135
  }
35796
36136
 
36137
+ // Persisted-store pre-paint payload (buildStorePrePaintPayload) \u2014 same
36138
+ // token-stash/consume contract as /ssr-data.js, own store so neither handoff
36139
+ // can eat the other.
36140
+ if (pathname === '/store-init.js') {
36141
+ const initToken = url.searchParams.get('t') || '';
36142
+ const initStore = (globalThis.__vsk_store_init_payload_store || {});
36143
+ const initPayload = initStore[initToken];
36144
+ if (initPayload !== undefined) delete initStore[initToken];
36145
+ return new Response(initPayload ?? '// no store init', {
36146
+ status: 200,
36147
+ headers: { 'Content-Type': 'application/javascript', 'Cache-Control': 'no-store' },
36148
+ });
36149
+ }
36150
+
35797
36151
  ${eventsStartLine}
35798
36152
  let mwCtx = { params: {}, url, locals: ${localsSeed}, cookies: {}, request, resolveUrl(u) { return new URL(u, request.url).href; }, set() {}, get() { return undefined; } };
35799
36153
  if (${hasMwLiteral}) {
@@ -35846,7 +36200,7 @@ ${eventsRequestLine}
35846
36200
  return response;
35847
36201
  }
35848
36202
 
35849
- return new Response('<!DOCTYPE html><html><body><h1>404</h1><p>Not Found</p></body></html>', {
36203
+ return new Response(__defaultNotFoundHtml, {
35850
36204
  status: 404,
35851
36205
  headers: { 'Content-Type': 'text/html' },
35852
36206
  });
@@ -35941,6 +36295,7 @@ var __dirname5;
35941
36295
  var init_platform_handler = __esm({
35942
36296
  "../adapter/src/platform-handler.ts"() {
35943
36297
  "use strict";
36298
+ init_default_pages();
35944
36299
  __dirname5 = dirname13(fileURLToPath4(import.meta.url));
35945
36300
  }
35946
36301
  });
@@ -46693,7 +47048,7 @@ function offsetToLineCol3(source, offset2) {
46693
47048
  }
46694
47049
  return { line, column };
46695
47050
  }
46696
- function preprocessForClauses2(source) {
47051
+ function preprocessForClauses2(source, delimiters) {
46697
47052
  const annotations = [];
46698
47053
  const chars = source.split("");
46699
47054
  const isString = (ch) => ch === '"' || ch === "'" || ch === "`";
@@ -46701,6 +47056,10 @@ function preprocessForClauses2(source) {
46701
47056
  while (i < source.length) {
46702
47057
  const ch = source[i];
46703
47058
  if (isString(ch)) {
47059
+ if (delimiters && !delimiters.has(i)) {
47060
+ i++;
47061
+ continue;
47062
+ }
46704
47063
  const quote = ch;
46705
47064
  let j = i + 1;
46706
47065
  let tplDepth = 0;
@@ -47077,9 +47436,11 @@ function createBaseParser2() {
47077
47436
  }
47078
47437
  function parse5(source, options = {}) {
47079
47438
  const ParserClass = createBaseParser2();
47080
- const { code, annotations } = preprocessForClauses2(blankGenericArrowTypeParams2(blankComments(source)));
47439
+ const sourceTokens = tokenizeCode(source);
47440
+ const delimiters = sourceTokens === null ? null : collectStringDelimiters(source, sourceTokens);
47441
+ const { code, annotations } = preprocessForClauses2(blankGenericArrowTypeParams2(blankComments(source)), delimiters);
47081
47442
  const vskSource = !options.filename || String(options.filename).endsWith(".vsk");
47082
- const specifierExports = vskSource ? findSpecifierExports(code).filter((e) => !hasTopLevelValueDeclaration(code, e.local)) : [];
47443
+ const specifierExports = vskSource && sourceTokens !== null ? findSpecifierExports(code, sourceTokens).filter((e) => !hasTopLevelValueDeclaration(code, e.local, sourceTokens)) : [];
47083
47444
  let parseable = code;
47084
47445
  if (specifierExports.length > 0) {
47085
47446
  const edits = specifierExports.map((e) => code.slice(e.start, e.end)).map((text) => text.split("").map((ch) => ch === "\n" ? "\n" : " ").join(""));
@@ -48034,6 +48395,7 @@ async function bundleRuntime(appDir, outDir) {
48034
48395
  `import { renderPage, renderFullPage, renderPageStream, compileFile, setRuntimeModule, setVskHydrate, hydratePrecompile, assertSameOrigin, withSsrStore } from ${JSON.stringify(resolve3(compilerRoot, "server-codegen.js"))};`,
48035
48396
  `import { parseCookies } from ${JSON.stringify(resolve3(compilerRoot, "server-cookies.js"))};`,
48036
48397
  `import * as __veskRuntime from ${JSON.stringify(resolve3(runtimeRoot, "index-server.js"))};`,
48398
+ `import * as __persistence from ${JSON.stringify(resolve3(runtimeRoot, "store-persistence.js"))};`,
48037
48399
  "",
48038
48400
  "// Inject runtime module so server-codegen can find components like NavLink, Link, etc.",
48039
48401
  "setRuntimeModule(__veskRuntime);",
@@ -48099,6 +48461,40 @@ async function bundleRuntime(appDir, outDir) {
48099
48461
  " return '/ssr-data.js?t=' + token;",
48100
48462
  "}",
48101
48463
  "",
48464
+ "// Persisted-store SSR continuity. `installPersistedStoreServerHooks` installs the",
48465
+ "// adapter-side read hook; `get/getReset` handle the per-request key registry",
48466
+ "// the server drains into the pre-paint payload. The init payload is delivered",
48467
+ "// as an origin-served script (/store-init.js?t=...) exactly like /ssr-data.js",
48468
+ "// so strict CSP (no unsafe-inline) cannot block it; it is never inlined.",
48469
+ "export const installPersistedStoreServerHooks = __persistence.installPersistedStoreServerHooks;",
48470
+ "export const persistedStoreCookieName = __persistence.persistedStoreCookieName;",
48471
+ "export const getPersistedStoreKeys = __persistence.getPersistedStoreKeys;",
48472
+ "export const resetPersistedStoreKeys = __persistence.resetPersistedStoreKeys;",
48473
+ "export const buildStorePrePaintPayload = __persistence.buildStorePrePaintPayload;",
48474
+ "export const storeInitScriptTag = __persistence.storeInitScriptTag;",
48475
+ "",
48476
+ "// Stash the pre-paint payload under a CSPRNG token and return the origin URL",
48477
+ "// the blocking <head> script points at. Own token store (NOT __vsk_ssr_payload_store)",
48478
+ "// so consuming the page hydration handoff never eats the store-init payload",
48479
+ "// and vice versa. Same 100-entry bound as /ssr-data.js.",
48480
+ "export function storeInitScriptGlobal(payload) {",
48481
+ " if (!payload) return null;",
48482
+ " const bytes = new Uint8Array(12);",
48483
+ " crypto.getRandomValues(bytes);",
48484
+ " let tk = '';",
48485
+ " for (const b of bytes) tk += b.toString(16).padStart(2, '0');",
48486
+ " const token = tk;",
48487
+ " const store = (globalThis.__vsk_store_init_payload_store ||= {});",
48488
+ " store[token] = payload;",
48489
+ " const keys = Object.keys(store);",
48490
+ " if (keys.length > 100) {",
48491
+ " for (let i = 0; i < keys.length - 100; i++) {",
48492
+ " delete store[keys[i]];",
48493
+ " }",
48494
+ " }",
48495
+ " return '/store-init.js?t=' + token;",
48496
+ "}",
48497
+ "",
48102
48498
  "// Re-export runtime classes used by API routes",
48103
48499
  "export const VeskRequest = __veskRuntime.VeskRequest;",
48104
48500
  "export const PayloadTooLargeError = __veskRuntime.PayloadTooLargeError;",
@@ -48349,6 +48745,7 @@ function resolveCssUrls(opts) {
48349
48745
  }
48350
48746
 
48351
48747
  // ../adapter/src/ssr-function.ts
48748
+ init_default_pages();
48352
48749
  function resolveErrorFile(sourceDir, appDir) {
48353
48750
  const rel = relative(appDir, sourceDir).split("/").filter(Boolean);
48354
48751
  for (let depth = rel.length; depth >= 0; depth--) {
@@ -48409,6 +48806,51 @@ function buildParamExtraction(node, urlParts) {
48409
48806
  walk9(node);
48410
48807
  return parts;
48411
48808
  }
48809
+ function persistedStoreSsrCode() {
48810
+ return [
48811
+ "// \u2500\u2500 Persisted-store SSR continuity (createStore / createPathStore persist) \u2500\u2500",
48812
+ "// Reads a persisted store's cookie value through the adapter request context.",
48813
+ "// Client writes mirror URL-encoded; decode on the way back (best effort).",
48814
+ "function __persistRead(key) {",
48815
+ " const cookieName = persistedStoreCookieName(key);",
48816
+ " const req = globalThis.__vesk_request;",
48817
+ " if (!req) return null;",
48818
+ " const c = req.cookies || {};",
48819
+ " const v = typeof c.get === 'function' ? c.get(cookieName) : c[cookieName];",
48820
+ " if (v == null) return null;",
48821
+ " try { return decodeURIComponent(String(v)); } catch { return String(v); }",
48822
+ "}",
48823
+ "",
48824
+ "// Drain this request's registered persisted keys into a served pre-paint",
48825
+ "// script (/store-init.js?t=...) then forget them. `token` selects the",
48826
+ "// render's bucket for callers outside the ALS scope (the no-layout stream",
48827
+ "// path captures its token at the renderPageStream call site); the layout",
48828
+ "// path runs this inside the scope and relies on the ambient token.",
48829
+ "function __storeInitTag(token) {",
48830
+ " const keys = getPersistedStoreKeys(token);",
48831
+ " if (keys.length === 0) { resetPersistedStoreKeys(token); return ''; }",
48832
+ " const values = {};",
48833
+ " for (let __i = 0; __i < keys.length; __i++) values[keys[__i]] = __persistRead(keys[__i]);",
48834
+ " resetPersistedStoreKeys(token);",
48835
+ " const payload = buildStorePrePaintPayload(values);",
48836
+ " const url = storeInitScriptGlobal(payload);",
48837
+ " return url ? storeInitScriptTag(url) : '';",
48838
+ "}",
48839
+ "",
48840
+ "// Inject the blocking store-init <script src> into a full HTML string",
48841
+ "// (before </head>; append if the document has no head).",
48842
+ "function __injectStoreInit(html) {",
48843
+ " const tag = __storeInitTag();",
48844
+ " if (tag === '') return html;",
48845
+ " const idx = html.lastIndexOf('</head>');",
48846
+ " if (idx === -1) return html + tag;",
48847
+ " return html.slice(0, idx) + tag + html.slice(idx);",
48848
+ "}",
48849
+ "",
48850
+ "installPersistedStoreServerHooks({ read: __persistRead });",
48851
+ ""
48852
+ ].join("\n");
48853
+ }
48412
48854
  function generateSsrFunction(routeNode, appDir, outDir, componentMap, options) {
48413
48855
  const ancestorLayouts = options?.ancestorLayouts || [];
48414
48856
  const middlewareCode = options?.middlewareCode || null;
@@ -48504,12 +48946,13 @@ ${layoutDecls.map((d) => " " + d.compiled + ",").join("\n")}
48504
48946
  " const result = await renderPage('', _errorComp, props, __componentRegistry, { hydrate: true, cached: _errorCompiled });",
48505
48947
  " return result.body;",
48506
48948
  " } catch {",
48507
- " return '<h1>500 \\u2014 Internal Server Error</h1>';",
48949
+ ` return ${JSON.stringify(renderDefaultErrorFragment())};`,
48508
48950
  " }",
48509
48951
  "}",
48510
48952
  "",
48511
48953
  "async function __renderHtml(params, requestUrl) {",
48512
48954
  " return withSsrStore(async () => {",
48955
+ " resetPersistedStoreKeys();",
48513
48956
  " let page;",
48514
48957
  " let caughtError = null;",
48515
48958
  " const __expose = process.env.NODE_ENV !== 'production';",
@@ -48530,7 +48973,7 @@ ${layoutDecls.map((d) => " " + d.compiled + ",").join("\n")}
48530
48973
  " if (_inner.head) _head = _inner.head + _head;",
48531
48974
  " }",
48532
48975
  " const html = await renderFullPage('', _layoutCompList[0], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[0]" + bakedOptions + clientScriptOption + dataScriptOption + ", pageHead: _head });",
48533
- " return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
48976
+ " return new Response(__injectStoreInit(html), { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
48534
48977
  " });",
48535
48978
  "}",
48536
48979
  ""
@@ -48549,25 +48992,48 @@ ${layoutDecls.map((d) => " " + d.compiled + ",").join("\n")}
48549
48992
  "async function __renderHtml(params, requestUrl) {",
48550
48993
  " return withSsrStore(async () => {",
48551
48994
  " let stream;",
48995
+ // The streamed no-layout page emits its <head> before the component body
48996
+ // renders, so its persisted stores don't exist yet when the head is
48997
+ // flushed — the pre-paint tag therefore goes into the final chunk, right
48998
+ // before </body> (still a blocking, pre-paint script). Capture the render
48999
+ // token now (renderPageStream adopts this exact ambient store) so the
49000
+ // registry drain in the consumer's start() can hit the right bucket even
49001
+ // though it runs outside the ALS scope.
49002
+ " const __streamToken = globalThis.__vsk_ssr_token || '';",
48552
49003
  " try {",
48553
49004
  " stream = renderPageStream('', _comp, { params }, __componentRegistry, { hydrate: true, cached: _compiled" + bakedOptions + clientScriptOption + dataScriptOption + " });",
48554
49005
  " } catch (err) {",
48555
49006
  " if (err && (err.name === 'NotFoundError' || err.name === 'Redirect')) throw err;",
48556
49007
  " const html = await __renderErrorFullPage(params, requestUrl, err);",
48557
- " return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: 500 });",
49008
+ " return new Response(__injectStoreInit(html), { headers: { 'Content-Type': 'text/html' }, status: 500 });",
48558
49009
  " }",
48559
49010
  " return new Response(new ReadableStream({",
48560
49011
  " async start(controller) {",
48561
49012
  " const enc = new TextEncoder();",
49013
+ " let __tail = null;",
49014
+ " resetPersistedStoreKeys(__streamToken);",
48562
49015
  " try {",
48563
49016
  " for await (const chunk of stream) {",
48564
- " controller.enqueue(enc.encode(chunk));",
49017
+ " if (__tail !== null) controller.enqueue(enc.encode(__tail));",
49018
+ " __tail = chunk;",
49019
+ " }",
49020
+ " if (__tail !== null) {",
49021
+ " const __tag = __storeInitTag(__streamToken);",
49022
+ " if (__tag !== '') {",
49023
+ " const __bi = __tail.lastIndexOf('</body>');",
49024
+ " __tail = __bi === -1 ? __tail + __tag : __tail.slice(0, __bi) + __tag + __tail.slice(__bi);",
49025
+ " }",
49026
+ " controller.enqueue(enc.encode(__tail));",
49027
+ " } else {",
49028
+ " // Empty stream (no chunks) \u2014 nothing to attach the tag to; just",
49029
+ " // clear the registry so a later render can't inherit these keys.",
49030
+ " resetPersistedStoreKeys(__streamToken);",
48565
49031
  " }",
48566
49032
  " } catch (err) {",
48567
49033
  " if (err && (err.name === 'NotFoundError' || err.name === 'Redirect')) throw err;",
48568
49034
  " try {",
48569
49035
  " const html = await __renderErrorFullPage(params, requestUrl, err);",
48570
- " controller.enqueue(enc.encode(html));",
49036
+ " controller.enqueue(enc.encode(__injectStoreInit(html)));",
48571
49037
  " } catch {}",
48572
49038
  " }",
48573
49039
  " controller.close();",
@@ -48578,6 +49044,7 @@ ${layoutDecls.map((d) => " " + d.compiled + ",").join("\n")}
48578
49044
  ""
48579
49045
  ].join("\n");
48580
49046
  }
49047
+ const persistCode = persistedStoreSsrCode();
48581
49048
  let dataCode;
48582
49049
  const exposeErr = "process.env.NODE_ENV !== 'production'";
48583
49050
  const dataNavCleanup = [
@@ -48591,6 +49058,9 @@ ${layoutDecls.map((d) => " " + d.compiled + ",").join("\n")}
48591
49058
  // process-global token — the cross-request data-slot race, for good. The
48592
49059
  // token dies with the withSsrStore scope wrapped around this block instead.
48593
49060
  " delete globalThis.__vsk_ssr_data;",
49061
+ // SPA data-nav only runs renderPage, so the persisted-store registration
49062
+ // bucket would otherwise keep this request's keys forever.
49063
+ " resetPersistedStoreKeys();",
48594
49064
  " }"
48595
49065
  ];
48596
49066
  const dataNavWrap = (body) => [
@@ -48775,7 +49245,7 @@ ${layoutDecls.map((d) => " " + d.compiled + ",").join("\n")}
48775
49245
  ""
48776
49246
  ].join("\n");
48777
49247
  const funcCode = [
48778
- "import { renderFullPage, renderPageStream, renderPage, hydratePrecompile, parseCookies, getAction, validateActionInput, issuesToFieldMap, storeDataScriptGlobal, withSsrStore, assertSameOrigin, VeskRequest } from '../runtime.js';",
49248
+ "import { renderFullPage, renderPageStream, renderPage, hydratePrecompile, parseCookies, getAction, validateActionInput, issuesToFieldMap, storeDataScriptGlobal, withSsrStore, assertSameOrigin, VeskRequest, installPersistedStoreServerHooks, persistedStoreCookieName, getPersistedStoreKeys, resetPersistedStoreKeys, buildStorePrePaintPayload, storeInitScriptGlobal, storeInitScriptTag } from '../runtime.js';",
48779
49249
  "",
48780
49250
  middlewareCode || "",
48781
49251
  registryCode,
@@ -48784,6 +49254,8 @@ ${layoutDecls.map((d) => " " + d.compiled + ",").join("\n")}
48784
49254
  paramsCode,
48785
49255
  htmlFnCode,
48786
49256
  "",
49257
+ persistCode,
49258
+ "",
48787
49259
  "export async function handle(request) {",
48788
49260
  " const url = new URL(request.url);",
48789
49261
  " const params = __paramsFor(url.pathname);",
@@ -50680,6 +51152,7 @@ async function loadVeskConfig2(projectDir) {
50680
51152
  }
50681
51153
 
50682
51154
  // ../adapter/src/prod-server.ts
51155
+ init_default_pages();
50683
51156
  var __dirname4 = dirname10(fileURLToPath3(import.meta.url));
50684
51157
  async function deliverResponse(res, response) {
50685
51158
  res.writeHead(response.status, Object.fromEntries(response.headers));
@@ -50918,6 +51391,15 @@ async function startProdServer(outDir, options) {
50918
51391
  res.end(lines.join("\n") || "// no ssr data");
50919
51392
  return;
50920
51393
  }
51394
+ if (url.pathname === "/store-init.js") {
51395
+ const token = url.searchParams.get("t") || "";
51396
+ const store = globalThis.__vsk_store_init_payload_store;
51397
+ const payload = store?.[token];
51398
+ if (payload) delete store[token];
51399
+ res.writeHead(200, { "Content-Type": "application/javascript", "Cache-Control": "no-store" });
51400
+ res.end(payload ?? "// no store init");
51401
+ return;
51402
+ }
50921
51403
  if (url.pathname === "/_vesk/runtime.js") {
50922
51404
  const clientFile = buildConfig?.assets?.client?.file || "client.js";
50923
51405
  const clientPath = resolve13(staticDir, clientFile);
@@ -51131,7 +51613,7 @@ async function startProdServer(outDir, options) {
51131
51613
  }
51132
51614
  if (err.name === "NotFoundError") {
51133
51615
  res.writeHead(404, { "Content-Type": "text/html" });
51134
- res.end(notFoundHtml || "<!DOCTYPE html><html><body><h1>404</h1><p>Not Found</p></body></html>");
51616
+ res.end(notFoundHtml || renderDefaultNotFoundPage({ url: url.pathname, headExtra: bakedHeadExtra }));
51135
51617
  return;
51136
51618
  }
51137
51619
  console.error("vesk ssr error:", err.message);
@@ -51159,7 +51641,7 @@ async function startProdServer(outDir, options) {
51159
51641
  }
51160
51642
  }
51161
51643
  res.writeHead(500, { "Content-Type": "text/html" });
51162
- res.end(errorHtml || "<!DOCTYPE html><html><body><h1>500</h1><pre>Internal Server Error</pre></body></html>");
51644
+ res.end(errorHtml || renderDefaultErrorPage({ message: process.env.NODE_ENV !== "production" ? err.message : void 0, url: url.pathname, headExtra: bakedHeadExtra }));
51163
51645
  return;
51164
51646
  }
51165
51647
  }
@@ -51167,7 +51649,7 @@ async function startProdServer(outDir, options) {
51167
51649
  }
51168
51650
  }
51169
51651
  res.writeHead(404, { "Content-Type": "text/html" });
51170
- res.end(notFoundHtml || "<!DOCTYPE html><html><body><h1>404</h1><p>Not Found</p></body></html>");
51652
+ res.end(notFoundHtml || renderDefaultNotFoundPage({ url: url.pathname, headExtra: bakedHeadExtra }));
51171
51653
  });
51172
51654
  try {
51173
51655
  await eventsMod?.executeStart?.({ server, port, host });
@@ -51224,6 +51706,29 @@ async function resolveCompilerApi(name) {
51224
51706
  }
51225
51707
  return import(`@vesk/compiler/src/${name.replace(/\.js$/, "")}`);
51226
51708
  }
51709
+ function findRouteConflicts(routeTree, appDir) {
51710
+ const projectRoot = resolve21(appDir, "..");
51711
+ const byPath = /* @__PURE__ */ new Map();
51712
+ const walk9 = (nodes) => {
51713
+ for (const node of nodes) {
51714
+ if (node.page) {
51715
+ const pageFile = join15(node.sourceDir, "page.vsk");
51716
+ const files = byPath.get(node.fullPath) ?? [];
51717
+ files.push(relative4(projectRoot, pageFile));
51718
+ byPath.set(node.fullPath, files);
51719
+ }
51720
+ if (node.children && node.children.length > 0)
51721
+ walk9(node.children);
51722
+ }
51723
+ };
51724
+ walk9(routeTree);
51725
+ const conflicts = [];
51726
+ for (const [fullPath, files] of byPath) {
51727
+ if (files.length > 1)
51728
+ conflicts.push({ fullPath, files });
51729
+ }
51730
+ return conflicts;
51731
+ }
51227
51732
  function filterActivePlugins2(plugins, records) {
51228
51733
  if (!records || records.length === 0)
51229
51734
  return plugins;
@@ -51357,6 +51862,14 @@ async function build2(appDir, options) {
51357
51862
  console.error("vesk build: no routes found in", appDir);
51358
51863
  return;
51359
51864
  }
51865
+ const routeConflicts = findRouteConflicts(routeTree, appDir);
51866
+ if (routeConflicts.length > 0) {
51867
+ for (const conflict of routeConflicts) {
51868
+ console.error(`vesk build: conflicting routes for ${conflict.fullPath}: ${conflict.files.join(", ")}`);
51869
+ }
51870
+ const first = routeConflicts[0];
51871
+ throw new Error(`conflicting routes: ${first.fullPath} is claimed by both ${first.files.join(" and ")}`);
51872
+ }
51360
51873
  const projectRoot = resolve21(appDir, "..");
51361
51874
  const componentsDir = resolve21(projectRoot, "components");
51362
51875
  const componentMap = scanComponents2(componentsDir);
@@ -52154,15 +52667,38 @@ function transformTracked2(irNode, tracked2) {
52154
52667
  }
52155
52668
  function collectTrackedNames2(body) {
52156
52669
  const names = /* @__PURE__ */ new Map();
52670
+ collectTrackedNamesInto2(body, names);
52671
+ return names;
52672
+ }
52673
+ function collectTrackedNamesInto2(body, names) {
52157
52674
  for (const node of body) {
52158
52675
  if (node instanceof TrackDecl) {
52159
52676
  const cellName = node.rawName || node.name;
52160
52677
  names.set(node.name, { cellName, kind: "virtual" });
52161
52678
  if (node.rawName)
52162
52679
  names.set(node.rawName, { cellName, kind: "cell" });
52680
+ } else if (node instanceof StaticNode || node instanceof ServerBlock || node instanceof ClientBlock || node instanceof HeadBlock) {
52681
+ collectTrackedNamesInto2(node.children, names);
52682
+ } else if (node instanceof ComponentCall) {
52683
+ collectTrackedNamesInto2(node.children, names);
52684
+ } else if (node instanceof PropSlot) {
52685
+ collectTrackedNamesInto2(node.body, names);
52686
+ } else if (node instanceof MapRegion) {
52687
+ collectTrackedNamesInto2(node.bodyTemplate, names);
52688
+ collectTrackedNamesInto2(node.alternateNodes, names);
52689
+ } else if (node instanceof OpaqueDynamicRegion) {
52690
+ collectTrackedNamesInto2(node.consequentNodes, names);
52691
+ collectTrackedNamesInto2(node.alternateNodes, names);
52692
+ } else if (node instanceof WhileLoop || node instanceof ForLoop) {
52693
+ collectTrackedNamesInto2(node.bodyTemplate, names);
52694
+ } else if (node instanceof TryCatch) {
52695
+ collectTrackedNamesInto2(node.bodyTemplate, names);
52696
+ collectTrackedNamesInto2(node.catchBody, names);
52697
+ } else if (node instanceof SwitchBlock) {
52698
+ for (const c of node.cases)
52699
+ collectTrackedNamesInto2(c.body, names);
52163
52700
  }
52164
52701
  }
52165
- return names;
52166
52702
  }
52167
52703
  function collectTrackedDeps2(value, tracked2) {
52168
52704
  const ast = value?.ast;
@@ -52277,6 +52813,9 @@ var Ctx2 = class {
52277
52813
  walker = "__hydrate";
52278
52814
  asyncComps = /* @__PURE__ */ new Set();
52279
52815
  isAsyncScope = false;
52816
+ // While emitting a loop body, names the boolean flag a `break` sets (see
52817
+ // BreakSignal). Null outside a break-capable loop body.
52818
+ breakFlag = null;
52280
52819
  constructor(alloc) {
52281
52820
  this.alloc = alloc ?? { c: 0 };
52282
52821
  }
@@ -52364,11 +52903,22 @@ function emitNode2(ctx2, node, tracked2, effectsVar, parentVar, compPrefix = "__
52364
52903
  ctx2.push(semicolonizeStatement2(transformTracked2(node, tracked2)));
52365
52904
  return null;
52366
52905
  }
52906
+ if (node instanceof BreakSignal) {
52907
+ if (ctx2.breakFlag)
52908
+ ctx2.push(`${ctx2.breakFlag} = true;`);
52909
+ return null;
52910
+ }
52367
52911
  if (node instanceof SlotNode) {
52368
52912
  if (!parentVar) {
52369
52913
  if (ctx2.hydrate) {
52914
+ const promptExpr = ctx2.markerless && (regionBudget || skipK > 0) ? markerlessSkipExpr2(regionBudget, skipK) : null;
52370
52915
  ctx2.push(`if (props.children !== undefined && props.children !== null) {`);
52371
52916
  ctx2.push(` if (typeof props.children === 'function') {`);
52917
+ if (promptExpr) {
52918
+ ctx2.push(` ${ctx2.walker}.injectSkipK(${promptExpr});`);
52919
+ if (regionBudget && ctx2.markerless)
52920
+ ctx2.push(` ${regionBudget} = 0;`);
52921
+ }
52372
52922
  ctx2.push(` __pendingChild = props.children(__hydrate);`);
52373
52923
  ctx2.push(` } else if (__hydrate && __hydrate.root) {`);
52374
52924
  ctx2.push(` __hydrate.root.appendChild(toDomNode(props.children));`);
@@ -53270,6 +53820,8 @@ function emitWhileLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget
53270
53820
  ctx2.push(`const ${endAnchor} = document.createComment('while-end');`);
53271
53821
  emitHydrateFenceAnchoring2(ctx2, anchor, endAnchor, parent === "$root", budget || void 0);
53272
53822
  const renderLoop = ctx2.n();
53823
+ const hasBreak = bodyHasBreak2(node.bodyTemplate);
53824
+ const breakVar = hasBreak ? ctx2.n() : null;
53273
53825
  ctx2.push(`const ${renderLoop} = ${ctx2.isAsyncScope ? "async () => {" : "() => {"}`);
53274
53826
  if (!hyd)
53275
53827
  ctx2.push(indent3(`const __p = ${anchor}.parentNode;`));
@@ -53277,8 +53829,14 @@ function emitWhileLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget
53277
53829
  ctx2.push(indent3(`const __b = document.createDocumentFragment();`));
53278
53830
  if (hyd)
53279
53831
  ctx2.push(indent3(`const __cl = [];`));
53832
+ if (breakVar)
53833
+ ctx2.push(indent3(`let ${breakVar} = false;`));
53834
+ const savedBreakFlag = ctx2.breakFlag;
53835
+ ctx2.breakFlag = breakVar;
53280
53836
  if (node.isDoWhile) {
53281
53837
  ctx2.push(indent3(`do {`));
53838
+ if (breakVar)
53839
+ ctx2.push(indent3(indent3(`if (${breakVar}) break;`)));
53282
53840
  for (const n of node.bodyTemplate) {
53283
53841
  const v = emitNode2(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
53284
53842
  if (v) {
@@ -53291,6 +53849,8 @@ function emitWhileLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget
53291
53849
  ctx2.push(indent3(`} while (${condExpr});`));
53292
53850
  } else {
53293
53851
  ctx2.push(indent3(`while (${condExpr}) {`));
53852
+ if (breakVar)
53853
+ ctx2.push(indent3(indent3(`if (${breakVar}) break;`)));
53294
53854
  for (const n of node.bodyTemplate) {
53295
53855
  const v = emitNode2(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
53296
53856
  if (v) {
@@ -53302,6 +53862,7 @@ function emitWhileLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget
53302
53862
  }
53303
53863
  ctx2.push(indent3(`}`));
53304
53864
  }
53865
+ ctx2.breakFlag = savedBreakFlag;
53305
53866
  if (!hyd)
53306
53867
  ctx2.push(indent3(`__p.insertBefore(__b, ${endAnchor});`));
53307
53868
  if (hyd)
@@ -53345,6 +53906,8 @@ function emitForLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget)
53345
53906
  ctx2.push(`const ${endAnchor} = document.createComment('for-end');`);
53346
53907
  emitHydrateFenceAnchoring2(ctx2, anchor, endAnchor, parent === "$root", budget || void 0);
53347
53908
  const renderLoop = ctx2.n();
53909
+ const forHasBreak = bodyHasBreak2(node.bodyTemplate);
53910
+ const forBreakVar = forHasBreak ? ctx2.n() : null;
53348
53911
  ctx2.push(`const ${renderLoop} = ${ctx2.isAsyncScope ? "async () => {" : "() => {"}`);
53349
53912
  if (!hyd)
53350
53913
  ctx2.push(indent3(`const __p = ${anchor}.parentNode;`));
@@ -53352,9 +53915,15 @@ function emitForLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget)
53352
53915
  ctx2.push(indent3(`const __b = document.createDocumentFragment();`));
53353
53916
  if (hyd)
53354
53917
  ctx2.push(indent3(`const __cl = [];`));
53918
+ if (forBreakVar)
53919
+ ctx2.push(indent3(`let ${forBreakVar} = false;`));
53920
+ const savedForBreakFlag = ctx2.breakFlag;
53921
+ ctx2.breakFlag = forBreakVar;
53355
53922
  if (node.kind === "for-in") {
53356
53923
  const srcExpr = transformTracked2(node.condition, tracked2);
53357
53924
  ctx2.push(indent3(`for (${node.init} of (Array.isArray(${srcExpr}) ? ${srcExpr} : (${srcExpr} == null ? [] : Object.keys(${srcExpr})))) {`));
53925
+ if (forBreakVar)
53926
+ ctx2.push(indent3(indent3(`if (${forBreakVar}) break;`)));
53358
53927
  for (const n of node.bodyTemplate) {
53359
53928
  const v = emitNode2(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
53360
53929
  if (v) {
@@ -53375,6 +53944,8 @@ function emitForLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget)
53375
53944
  updatePart = updatePart.slice(0, -1).trim();
53376
53945
  const head = initPart ? `${initPart}; ${condExpr}` : `; ${condExpr}`;
53377
53946
  ctx2.push(indent3(`for (${head}; ${updatePart}) {`));
53947
+ if (forBreakVar)
53948
+ ctx2.push(indent3(indent3(`if (${forBreakVar}) break;`)));
53378
53949
  for (const n of node.bodyTemplate) {
53379
53950
  const v = emitNode2(ctx2, n, tracked2, effectsVar, hyd ? parentVar : "__b", "__components", 0, budget || void 0);
53380
53951
  if (v) {
@@ -53386,6 +53957,7 @@ function emitForLoop2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudget)
53386
53957
  }
53387
53958
  ctx2.push(indent3(`}`));
53388
53959
  }
53960
+ ctx2.breakFlag = savedForBreakFlag;
53389
53961
  if (!hyd)
53390
53962
  ctx2.push(indent3(`__p.insertBefore(__b, ${endAnchor});`));
53391
53963
  if (hyd)
@@ -53557,6 +54129,36 @@ function emitSwitchBlock2(ctx2, node, tracked2, parentVar, skipK = 0, regionBudg
53557
54129
  }`);
53558
54130
  return null;
53559
54131
  }
54132
+ function bodyHasBreak2(nodes) {
54133
+ for (const n of nodes) {
54134
+ if (n instanceof BreakSignal)
54135
+ return true;
54136
+ if (n instanceof OpaqueDynamicRegion) {
54137
+ if (bodyHasBreak2([...n.consequentNodes, ...n.alternateNodes]))
54138
+ return true;
54139
+ } else if (n instanceof SwitchBlock) {
54140
+ for (const c of n.cases)
54141
+ if (bodyHasBreak2(c.body))
54142
+ return true;
54143
+ } else if (n instanceof TryCatch) {
54144
+ if (bodyHasBreak2([...n.bodyTemplate, ...n.catchBody]))
54145
+ return true;
54146
+ } else if (n instanceof StaticNode) {
54147
+ if (bodyHasBreak2(n.children))
54148
+ return true;
54149
+ } else if (n instanceof ComponentCall) {
54150
+ if (bodyHasBreak2(n.children))
54151
+ return true;
54152
+ } else if (n instanceof ServerBlock || n instanceof ClientBlock || n instanceof HeadBlock) {
54153
+ if (bodyHasBreak2(n.children))
54154
+ return true;
54155
+ } else if (n instanceof PropSlot) {
54156
+ if (bodyHasBreak2(n.body))
54157
+ return true;
54158
+ }
54159
+ }
54160
+ return false;
54161
+ }
53560
54162
  function emitMap2(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionBudget) {
53561
54163
  const arrExpr = transformTracked2(node.expression, tracked2);
53562
54164
  const itemVar = node.itemVariable;
@@ -53590,9 +54192,15 @@ function emitMap2(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionB
53590
54192
  ctx2.push(`let ${effectsVar} = [];`);
53591
54193
  ctx2.push(`const ${endAnchor} = document.createComment('map-end');`);
53592
54194
  const renderItem = ctx2.n();
54195
+ const hasBreak = bodyHasBreak2(node.bodyTemplate);
54196
+ const breakVar = hasBreak ? ctx2.n() : null;
54197
+ if (breakVar)
54198
+ ctx2.push(`let ${breakVar} = false;`);
53593
54199
  const indexParam = node.indexVariable ? ", __i" : "";
53594
54200
  ctx2.push(`const ${renderItem} = ${ctx2.isAsyncScope ? "async " : ""}(${itemVar}${indexParam}, __e, __r${hyd ? ", __cl" : ""}${hydKeyed ? ", __root" : ""}) => {`);
53595
54201
  ctx2.push(indent3(`__r = __r || ${endAnchor};`));
54202
+ if (breakVar)
54203
+ ctx2.push(indent3(`if (${breakVar}) return;`));
53596
54204
  if (node.indexVariable)
53597
54205
  ctx2.push(indent3(`const ${node.indexVariable} = __i;`));
53598
54206
  if (hyd) {
@@ -53603,6 +54211,8 @@ function emitMap2(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionB
53603
54211
  }
53604
54212
  if (hydKeyed)
53605
54213
  ctx2.rootClaim = true;
54214
+ const savedMapBreak = ctx2.breakFlag;
54215
+ ctx2.breakFlag = breakVar;
53606
54216
  for (const n of node.bodyTemplate) {
53607
54217
  const v = emitNode2(ctx2, n, tracked2, "__e", hyd ? void 0 : "__it", "__components", 0, budget || void 0);
53608
54218
  if (v) {
@@ -53615,6 +54225,7 @@ function emitMap2(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionB
53615
54225
  }
53616
54226
  }
53617
54227
  }
54228
+ ctx2.breakFlag = savedMapBreak;
53618
54229
  if (hydKeyed)
53619
54230
  ctx2.rootClaim = false;
53620
54231
  if (!hyd)
@@ -53658,11 +54269,12 @@ function emitMap2(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionB
53658
54269
  const keyFnSrc = `(${itemVar}${node.indexVariable ? `, ${node.indexVariable}` : ""}) => ${keyExpr}`;
53659
54270
  const reconciler = ctx2.n();
53660
54271
  const initList = ctx2.n();
54272
+ const breakReset = breakVar ? `${breakVar} = false; ` : "";
53661
54273
  ctx2.push(`let ${reconciler} = () => {};`);
53662
54274
  if (hydKeyed) {
53663
- ctx2.push(`const ${initList} = () => { ${reconciler} = reconcileHydrated(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e, __root) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"}, null, __root), __hydrate, ${parent}, ${skipK}); };`);
54275
+ ctx2.push(`const ${initList} = () => { ${breakReset}${reconciler} = reconcileHydrated(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e, __root) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"}, null, __root), __hydrate, ${parent}, ${skipK}); };`);
53664
54276
  } else {
53665
- ctx2.push(`const ${initList} = () => { ${reconciler} = reconcile(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"})); };`);
54277
+ ctx2.push(`const ${initList} = () => { ${breakReset}${reconciler} = reconcile(${anchor}, ${endAnchor}, ${arrExpr}, ${keyFnSrc}, (${itemVar}, __i, __e) => ${renderItem}(${itemVar}${indexParam ? ", __i, __e" : ", __e"})); };`);
53666
54278
  }
53667
54279
  if (emptyRenderName) {
53668
54280
  const isEmptyVar = ctx2.n();
@@ -53674,7 +54286,7 @@ function emitMap2(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionB
53674
54286
  const __new = ${hasItems}();
53675
54287
  if (__first) { __first = false; __new; return; }
53676
54288
  if (__new !== ${isEmptyVar}) {
53677
- if (__new) ${reconciler}(${arrExpr});
54289
+ if (__new) {${breakVar ? ` ${breakVar} = false;` : ""} ${reconciler}(${arrExpr}); }
53678
54290
  return;
53679
54291
  }
53680
54292
  ${isEmptyVar} = !__new;
@@ -53689,22 +54301,28 @@ function emitMap2(ctx2, node, tracked2, effTarget, parentVar, skipK = 0, regionB
53689
54301
  return null;
53690
54302
  pushEffect(`let __first = true;`, `effect(() => {
53691
54303
  const __nv = ${arrExpr};
53692
- if (__first) { __first = false; __nv; ${reconciler}(${arrExpr}); return; }
53693
- ${reconciler}(${arrExpr});
54304
+ if (__first) { __first = false; __nv; ${breakReset}${reconciler}(${arrExpr}); return; }
54305
+ ${breakVar ? `if (${breakVar}) ${breakVar} = false;` : ""}${reconciler}(${arrExpr});
53694
54306
  })`);
53695
54307
  }
53696
54308
  } else {
53697
54309
  const renderAllItems = (ind, collect) => {
53698
54310
  const lines = [];
54311
+ if (breakVar)
54312
+ lines.push(`${ind}${breakVar} = false;`);
53699
54313
  if (node.indexVariable) {
53700
54314
  lines.push(`${ind}let __i = 0;`);
53701
54315
  lines.push(`${ind}for (const ${itemVar} of ${arrExpr}) {`);
53702
54316
  lines.push(`${ind} ${aw}${renderItem}(${itemVar}, __i, ${effectsVar}${collect ? `, null, ${collect}` : ""});`);
53703
54317
  lines.push(`${ind} __i++;`);
54318
+ if (breakVar)
54319
+ lines.push(`${ind} if (${breakVar}) break;`);
53704
54320
  lines.push(`${ind}}`);
53705
54321
  } else {
53706
54322
  lines.push(`${ind}for (const ${itemVar} of ${arrExpr}) {`);
53707
54323
  lines.push(`${ind} ${aw}${renderItem}(${itemVar}, ${effectsVar}${collect ? `, null, ${collect}` : ""});`);
54324
+ if (breakVar)
54325
+ lines.push(`${ind} if (${breakVar}) break;`);
53708
54326
  lines.push(`${ind}}`);
53709
54327
  }
53710
54328
  return lines.join("\n");
@@ -61574,6 +62192,71 @@ function createVeskTools(deps) {
61574
62192
  return tools;
61575
62193
  }
61576
62194
 
62195
+ // ../adapter/dist/default-pages.js
62196
+ function escapeDefaultPageHtml2(value) {
62197
+ return String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
62198
+ }
62199
+ var DEFAULT_PAGE_CSS2 = [
62200
+ ":root{color-scheme:light;",
62201
+ "--vsk-bg:oklch(0.941 0.014 88);",
62202
+ "--vsk-fg:oklch(0.185 0.008 62);",
62203
+ "--vsk-surface:oklch(0.965 0.012 88);",
62204
+ "--vsk-muted:oklch(0.475 0.014 72);",
62205
+ "--vsk-accent:oklch(0.560 0.140 42);",
62206
+ "--vsk-border:oklch(0.86 0.012 82);",
62207
+ "--vsk-border-strong:oklch(0.72 0.014 80);",
62208
+ '--vsk-font:"Space Grotesk",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;',
62209
+ '--vsk-mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;}',
62210
+ "@media (prefers-color-scheme:dark){:root{color-scheme:dark;",
62211
+ "--vsk-bg:oklch(0.155 0.006 60);",
62212
+ "--vsk-fg:oklch(0.931 0.014 88);",
62213
+ "--vsk-surface:oklch(0.196 0.008 70);",
62214
+ "--vsk-muted:oklch(0.618 0.016 80);",
62215
+ "--vsk-accent:oklch(0.632 0.132 45);",
62216
+ "--vsk-border:oklch(0.29 0.009 75);",
62217
+ "--vsk-border-strong:oklch(0.40 0.011 75);}}",
62218
+ "*{box-sizing:border-box}",
62219
+ "html,body{margin:0;min-height:100%}",
62220
+ "body{background:var(--vsk-bg);color:var(--vsk-fg);font-family:var(--vsk-font);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}",
62221
+ ".vsk-page{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}",
62222
+ ".vsk-page__card{width:100%;max-width:540px;border:1px solid var(--vsk-border);background:var(--vsk-surface);padding:clamp(28px,6vw,44px);text-align:center}",
62223
+ "@supports (background:color-mix(in oklab,red,red)){.vsk-page__card{background:color-mix(in oklab,var(--vsk-surface) 60%,transparent)}}",
62224
+ ".vsk-page__brand{margin:0 0 26px;font-family:var(--vsk-mono);font-size:10px;line-height:1;letter-spacing:.24em;text-transform:uppercase;color:var(--vsk-muted)}",
62225
+ ".vsk-page__brand b{color:var(--vsk-fg);font-weight:600}",
62226
+ ".vsk-page__row{display:flex;align-items:center;justify-content:center;gap:0;flex-wrap:wrap}",
62227
+ ".vsk-page__status{font-size:clamp(34px,9vw,46px);font-weight:600;line-height:1;letter-spacing:-.03em;padding-right:22px;margin-right:22px;border-right:1px solid var(--vsk-border-strong)}",
62228
+ ".vsk-page--error .vsk-page__status{color:var(--vsk-accent)}",
62229
+ ".vsk-page__msg{font-family:var(--vsk-mono);font-size:13px;line-height:1.5;color:var(--vsk-muted);text-align:left;max-width:270px}",
62230
+ "@media (max-width:440px){.vsk-page__row{flex-direction:column}.vsk-page__status{padding:0 0 16px;margin:0 0 16px;border-right:0;border-bottom:1px solid var(--vsk-border-strong)}.vsk-page__msg{text-align:center}}",
62231
+ ".vsk-page__detail{margin:20px 0 0;font-family:var(--vsk-mono);font-size:11px;line-height:1.6;color:var(--vsk-muted);word-break:break-all}",
62232
+ ".vsk-page__actions{margin-top:30px;display:flex;justify-content:center;gap:10px;flex-wrap:wrap}",
62233
+ ".vsk-page__btn{display:inline-block;padding:11px 22px;font-size:13px;font-weight:500;line-height:1;text-decoration:none;border:1px solid var(--vsk-fg);background:var(--vsk-fg);color:var(--vsk-bg);transition:opacity .18s cubic-bezier(.2,0,0,1)}",
62234
+ ".vsk-page__btn:hover{opacity:.86}",
62235
+ ".vsk-page__btn--ghost{background:transparent;color:var(--vsk-fg);border-color:var(--vsk-border-strong)}",
62236
+ ".vsk-page__btn--ghost:hover{background:var(--vsk-fg);color:var(--vsk-bg);border-color:var(--vsk-fg);opacity:1}"
62237
+ ].join("");
62238
+ function renderDefaultPage2(opts = {}) {
62239
+ const status = opts.status ?? 404;
62240
+ const title = escapeDefaultPageHtml2(opts.title ?? `${status} \u2014 Vesk`);
62241
+ const message = escapeDefaultPageHtml2(opts.message ?? "This page could not be found.");
62242
+ const url = opts.url ? escapeDefaultPageHtml2(opts.url) : "";
62243
+ const headExtra = opts.headExtra || "";
62244
+ const homeHref = opts.homeHref === void 0 ? "/" : opts.homeHref;
62245
+ const homeLabel = escapeDefaultPageHtml2(opts.homeLabel ?? "Back to home");
62246
+ const variant = `vsk-page${opts.accentStatus ? " vsk-page--error" : ""}`;
62247
+ const action = homeHref === null ? "" : `<a class="vsk-page__btn" href="${escapeDefaultPageHtml2(homeHref)}">${homeLabel}</a>`;
62248
+ return `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="robots" content="noindex"><title>${title}</title><style>${DEFAULT_PAGE_CSS2}</style>` + headExtra + `</head><body><main class="${variant}" data-vesk-default-page="${status}"><div class="vsk-page__card"><p class="vsk-page__brand"><b>Vesk</b> \xB7 built-in error page</p><div class="vsk-page__row"><span class="vsk-page__status">${status}</span><span class="vsk-page__msg">${message}</span></div>` + (url ? `<p class="vsk-page__detail">${url}</p>` : "") + (action ? `<div class="vsk-page__actions">${action}</div>` : "") + "</div></main></body></html>";
62249
+ }
62250
+ function renderDefaultNotFoundPage2(opts = {}) {
62251
+ return renderDefaultPage2({
62252
+ status: 404,
62253
+ title: "404 \u2014 Not Found",
62254
+ message: "This page could not be found.",
62255
+ url: opts.url,
62256
+ headExtra: opts.headExtra
62257
+ });
62258
+ }
62259
+
61577
62260
  // ../adapter/dist/css.js
61578
62261
  import { readFileSync as readFileSync33, existsSync as existsSync37 } from "node:fs";
61579
62262
  import { resolve as resolve33 } from "node:path";
@@ -61605,6 +62288,7 @@ import { WebSocketServer } from "ws";
61605
62288
  import { readFileSync as readFileSync34, existsSync as existsSync38, writeFileSync as writeFileSync19 } from "node:fs";
61606
62289
  import { resolve as resolve34, dirname as dirname24 } from "node:path";
61607
62290
  import { fileURLToPath as fileURLToPath7 } from "node:url";
62291
+ init_default_pages();
61608
62292
  init_paths();
61609
62293
 
61610
62294
  // ../adapter/src/error-codeframe.ts
@@ -64003,7 +64687,7 @@ Object.defineProperty(__components, ${JSON.stringify(cname)}, { get: () => __com
64003
64687
  }
64004
64688
  logRequest(404);
64005
64689
  res.writeHead(404, { "Content-Type": "text/html" });
64006
- res.end(notFoundHtml || `<!DOCTYPE html><html><body><h1>404</h1><p>${url.pathname}</p></body></html>`);
64690
+ res.end(notFoundHtml || renderDefaultNotFoundPage2({ url: url.pathname }));
64007
64691
  return;
64008
64692
  }
64009
64693
  const urlParts = url.pathname.split("/").filter(Boolean);
@@ -64302,7 +64986,7 @@ ${prettifyHtml(body)}
64302
64986
  }
64303
64987
  logRequest(404);
64304
64988
  res.writeHead(404, { "Content-Type": "text/html" });
64305
- res.end(notFoundHtml || "<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>");
64989
+ res.end(notFoundHtml || renderDefaultNotFoundPage2({ url: url.pathname }));
64306
64990
  } else {
64307
64991
  let devPayload = null;
64308
64992
  try {