@vesk/vesk-cli 0.2.50-canary.9 → 0.2.50

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 +595 -55
  2. package/package.json +5 -5
package/dist/cli.js CHANGED
@@ -147,7 +147,10 @@ var init_errors = __esm({
147
147
  suggestions;
148
148
  nextSteps;
149
149
  tip;
150
+ /** The V-diagnostic code, e.g. `V0501`. */
150
151
  code;
152
+ /** The rendered code frame. Used to be written into `code`, which silently replaced the V-code. */
153
+ frame;
151
154
  constructor(message, opts = {}) {
152
155
  super(message);
153
156
  this.name = "VeskError";
@@ -157,7 +160,8 @@ var init_errors = __esm({
157
160
  this.suggestions = opts.suggestions || [];
158
161
  this.nextSteps = opts.nextSteps || [];
159
162
  this.tip = opts.tip || "";
160
- if (opts.code !== void 0) this.code = opts.code;
163
+ if (opts.code !== void 0 && !opts.code.includes("\n")) this.code = opts.code;
164
+ if (opts.frame !== void 0) this.frame = opts.frame;
161
165
  }
162
166
  static notFound(name, candidates = [], context = {}) {
163
167
  const allCandidates = [.../* @__PURE__ */ new Set([...candidates, ...VESK_BUILTINS])];
@@ -236,6 +240,84 @@ var init_errors = __esm({
236
240
  }
237
241
  );
238
242
  }
243
+ /**
244
+ * A browser-only global used in code the SERVER evaluates.
245
+ *
246
+ * On the server these are either absent (`window is not defined`) or, worse,
247
+ * silently present-but-wrong (`navigator` exists in modern Node, so
248
+ * `navigator.onLine` is `undefined` and a page renders as if it were offline).
249
+ * A raw `ReferenceError` at request time is the worst possible report: it
250
+ * names neither the component nor the fix. This points at the line.
251
+ */
252
+ static ssrUnsafeGlobal(name, context = {}) {
253
+ return new _VeskError(
254
+ `\`${name}\` is browser-only, and this component body runs during SSR.`,
255
+ {
256
+ ...context,
257
+ code: context.code || "V0501",
258
+ suggestions: [
259
+ `Wrap the part that needs the DOM in a {#client} block.`,
260
+ `Move the code into an event handler \u2014 handlers never run on the server.`,
261
+ `Do the setup in on_destroy(), which the compiler only emits on the client.`
262
+ ],
263
+ nextSteps: [
264
+ `component ${context.inComponent ?? "this component"}: wrap the \`${name}\` access in {#client}...{/client}.`,
265
+ `Or guard it: if (typeof ${name} !== 'undefined') { ... }`
266
+ ],
267
+ tip: "SSR renders this component before the client exists. Reading a browser global here either throws during the request or (for `navigator`) silently returns undefined."
268
+ }
269
+ );
270
+ }
271
+ /**
272
+ * The second name from `track()` called as a function.
273
+ *
274
+ * `const &[count, setCount] = track(0)` returns a CELL, not a setter function, so
275
+ * `setCount(1)` throws `setCount is not a function` from generated code with
276
+ * no line of user code in the message. The cell is the writer: `.set(v)`.
277
+ */
278
+ static cellCalledAsFunction(name, context = {}) {
279
+ return new _VeskError(
280
+ `\`${name}\` is a cell, not a function \u2014 cells are written with \`.set()\`.`,
281
+ {
282
+ ...context,
283
+ code: context.code || "V0502",
284
+ suggestions: [
285
+ `Use \`${name}.set(...)\` instead of \`${name}(...)\`.`,
286
+ `Or use the tracked spelling inside an event handler: set(${context.value ?? "value"}, ...)`
287
+ ],
288
+ nextSteps: [
289
+ `const &[${context.value ?? "value"}, ${name}] = track(0) \u2192 \`${name}.set(v)\``,
290
+ "The value read in markup is the first name; the second is the cell object."
291
+ ],
292
+ tip: `\`track()\` returns [value, cell]. \`${name}\` is the cell half.`
293
+ }
294
+ );
295
+ }
296
+ /**
297
+ * `set(value, …)` used outside a rewritten expression.
298
+ *
299
+ * The compiler rewrites `set(count, v)` to `countCell.set(v)` inside JSX and
300
+ * event handlers — but a bare statement in the component body is NOT
301
+ * rewritten, so the runtime `set` receives the value and throws
302
+ * "Cannot read properties of undefined". Pass the CELL, not the value.
303
+ */
304
+ static setWithValueName(name, context = {}) {
305
+ return new _VeskError(
306
+ `\`set(${name}, \u2026)\` needs the CELL, and \`${name}\` is the value half of track().`,
307
+ {
308
+ ...context,
309
+ code: context.code || "V0503",
310
+ suggestions: [
311
+ `Use \`set(${context.cell ?? "cell"}, \u2026)\` or \`${context.cell ?? "cell"}.set(\u2026)\`.`,
312
+ `Or move the set() into an event handler, where the compiler rewrites it for you.`
313
+ ],
314
+ nextSteps: [
315
+ `const &[${name}, ${context.cell ?? "cell"}] = track(0) \u2192 \`${context.cell ?? "cell"}.set(v)\``
316
+ ],
317
+ tip: "set(cell, value) is only rewritten inside JSX and handlers; in a body statement it reaches the runtime untouched."
318
+ }
319
+ );
320
+ }
239
321
  static serverBlockInClient(compName, context = {}) {
240
322
  return new _VeskError(
241
323
  `{#server} block found in client island "${compName}". Client islands render on both server and client, so {#server} blocks have no effect.`,
@@ -18025,6 +18107,52 @@ function containsForOfIn(text) {
18025
18107
  }
18026
18108
  return false;
18027
18109
  }
18110
+ function callsIdentifier(text, ident) {
18111
+ let i = 0;
18112
+ const len = text.length;
18113
+ let afterDot = false;
18114
+ while (i < len) {
18115
+ const ch = text[i];
18116
+ if (isWhitespaceChar(ch)) {
18117
+ i++;
18118
+ continue;
18119
+ }
18120
+ const commentEnd = skipComment(text, i);
18121
+ if (commentEnd !== i) {
18122
+ i = commentEnd;
18123
+ continue;
18124
+ }
18125
+ if (ch === '"' || ch === "'" || ch === "`") {
18126
+ i = skipString(text, i);
18127
+ afterDot = false;
18128
+ continue;
18129
+ }
18130
+ if (ch === "." || ch === "?" && text[i + 1] === ".") {
18131
+ afterDot = true;
18132
+ i += ch === "." ? 1 : 2;
18133
+ continue;
18134
+ }
18135
+ if (isIdentStartCode2(ch.charCodeAt(0))) {
18136
+ let j = i + 1;
18137
+ while (j < len && isIdentCharCode2(text.charCodeAt(j))) j++;
18138
+ const name = text.slice(i, j);
18139
+ let k = skipWhitespace(text, j);
18140
+ if (text[k] === "<") {
18141
+ k = skipTrackGeneric(text, k);
18142
+ k = skipWhitespace(text, k);
18143
+ }
18144
+ if (name === ident && text[k] === "(" && !afterDot) {
18145
+ return true;
18146
+ }
18147
+ afterDot = false;
18148
+ i = j;
18149
+ continue;
18150
+ }
18151
+ afterDot = false;
18152
+ i++;
18153
+ }
18154
+ return false;
18155
+ }
18028
18156
  function unwrapTrackCall(init) {
18029
18157
  const text = init.trim();
18030
18158
  if (!startsWithIdentifier(text, "track")) return init;
@@ -21236,7 +21364,7 @@ function validateBlocks(compName, isClient, body, file, source) {
21236
21364
  const { line, column } = offsetToLineCol2(source, pos);
21237
21365
  opts.line = line;
21238
21366
  opts.column = column;
21239
- opts.code = codeFrame(source, line, column);
21367
+ opts.frame = codeFrame(source, line, column);
21240
21368
  }
21241
21369
  throw VeskError.serverBlockInClient(compName, opts);
21242
21370
  }
@@ -21248,7 +21376,7 @@ function validateBlocks(compName, isClient, body, file, source) {
21248
21376
  const { line, column } = offsetToLineCol2(source, pos);
21249
21377
  opts.line = line;
21250
21378
  opts.column = column;
21251
- opts.code = codeFrame(source, line, column);
21379
+ opts.frame = codeFrame(source, line, column);
21252
21380
  }
21253
21381
  throw VeskError.clientBlockInServer(compName, opts);
21254
21382
  }
@@ -25844,8 +25972,8 @@ function isPublicMarkdownPath(v) {
25844
25972
  const c = s.charCodeAt(i);
25845
25973
  if (c === 63 || c === 35 || c === 92) return false;
25846
25974
  }
25847
- const lower = s.toLowerCase();
25848
- return stringEndsWith(lower, ".md") || stringEndsWith(lower, ".markdown");
25975
+ const lower2 = s.toLowerCase();
25976
+ return stringEndsWith(lower2, ".md") || stringEndsWith(lower2, ".markdown");
25849
25977
  }
25850
25978
  function getMdPathCell(path) {
25851
25979
  let cell = mdPathCells.get(path);
@@ -26517,9 +26645,9 @@ function toDomNode(value) {
26517
26645
  }
26518
26646
  if (typeof value !== "string") return value;
26519
26647
  if (value === "") return document.createDocumentFragment();
26520
- const template = document.createElement("template");
26521
- template.innerHTML = value;
26522
- const { content } = template;
26648
+ const template2 = document.createElement("template");
26649
+ template2.innerHTML = value;
26650
+ const { content } = template2;
26523
26651
  if (content.childNodes.length === 1) {
26524
26652
  const only = content.firstChild;
26525
26653
  content.removeChild(only);
@@ -26712,7 +26840,7 @@ function resolveTitle(meta, child) {
26712
26840
  }
26713
26841
  function mergeMetadata(...sources) {
26714
26842
  const out = {};
26715
- let template;
26843
+ let template2;
26716
26844
  let sawTemplate = false;
26717
26845
  for (const source of sources) {
26718
26846
  if (!source) continue;
@@ -26725,7 +26853,7 @@ function mergeMetadata(...sources) {
26725
26853
  if (key === "title") {
26726
26854
  if (value && typeof value === "object" && value.template) {
26727
26855
  sawTemplate = true;
26728
- template = value.template || template;
26856
+ template2 = value.template || template2;
26729
26857
  }
26730
26858
  out.title = value;
26731
26859
  continue;
@@ -26737,9 +26865,9 @@ function mergeMetadata(...sources) {
26737
26865
  const own = out.title;
26738
26866
  if (typeof own === "string") out.title = { absolute: own };
26739
26867
  else if (own && typeof own === "object" && own.template) {
26740
- out.title = { default: own.default, template: own.template || template };
26868
+ out.title = { default: own.default, template: own.template || template2 };
26741
26869
  } else if (own && typeof own === "object") {
26742
- out.title = { ...own, template };
26870
+ out.title = { ...own, template: template2 };
26743
26871
  }
26744
26872
  }
26745
26873
  return out;
@@ -26825,6 +26953,56 @@ var init_metadata = __esm({
26825
26953
  }
26826
26954
  });
26827
26955
 
26956
+ // ../runtime/src/nested-update.ts
26957
+ function isObject(value) {
26958
+ return value !== null && typeof value === "object";
26959
+ }
26960
+ function setIn(value, path, next) {
26961
+ if (path.length === 0) return next;
26962
+ const [key, ...rest] = path;
26963
+ const container = Array.isArray(value) ? value : isObject(value) ? value : null;
26964
+ if (container === null) return value;
26965
+ const current2 = Array.isArray(container) ? container[typeof key === "number" ? key : Number(key)] : container[String(key)];
26966
+ if (rest.length > 0 && current2 === void 0) return value;
26967
+ if (Array.isArray(value)) {
26968
+ const index = typeof key === "number" ? key : Number(key);
26969
+ if (!Number.isInteger(index) || index < 0) return value;
26970
+ const copy2 = value.slice();
26971
+ copy2[index] = rest.length === 0 ? next : setIn(value[index], rest, next);
26972
+ return copy2;
26973
+ }
26974
+ if (!isObject(value)) return value;
26975
+ const copy = { ...value };
26976
+ copy[String(key)] = rest.length === 0 ? next : setIn(value[String(key)], rest, next);
26977
+ return copy;
26978
+ }
26979
+ function updateIn(value, path, fn) {
26980
+ if (path.length === 0) return fn(value);
26981
+ const [key, ...rest] = path;
26982
+ const child = getIn(value, [key]);
26983
+ const next = rest.length === 0 ? fn(child) : updateIn(child, rest, fn);
26984
+ return setIn(value, [key], next);
26985
+ }
26986
+ function getIn(value, path) {
26987
+ let current2 = value;
26988
+ for (const key of path) {
26989
+ if (Array.isArray(current2)) {
26990
+ const index = typeof key === "number" ? key : Number(key);
26991
+ if (!Number.isInteger(index)) return void 0;
26992
+ current2 = current2[index];
26993
+ continue;
26994
+ }
26995
+ if (!isObject(current2)) return void 0;
26996
+ current2 = current2[String(key)];
26997
+ }
26998
+ return current2;
26999
+ }
27000
+ var init_nested_update = __esm({
27001
+ "../runtime/src/nested-update.ts"() {
27002
+ "use strict";
27003
+ }
27004
+ });
27005
+
26828
27006
  // ../runtime/src/index-server.ts
26829
27007
  var index_server_exports = {};
26830
27008
  __export(index_server_exports, {
@@ -26897,6 +27075,7 @@ __export(index_server_exports, {
26897
27075
  get: () => get,
26898
27076
  getAction: () => getAction,
26899
27077
  getActiveComponent: () => getActiveComponent,
27078
+ getIn: () => getIn,
26900
27079
  getLoadingError: () => getLoadingError,
26901
27080
  getLoadingProgress: () => getLoadingProgress,
26902
27081
  getServerContext: () => getServerContext,
@@ -26950,6 +27129,7 @@ __export(index_server_exports, {
26950
27129
  server_locals: () => server_locals,
26951
27130
  set: () => set,
26952
27131
  setActiveComponent: () => setActiveComponent,
27132
+ setIn: () => setIn,
26953
27133
  setServerContext: () => setServerContext,
26954
27134
  setSignedCookie: () => setSignedCookie2,
26955
27135
  setSsrData: () => setSsrData,
@@ -26964,6 +27144,7 @@ __export(index_server_exports, {
26964
27144
  unlink_block: () => unlink_block,
26965
27145
  unsignCookie: () => unsignCookie2,
26966
27146
  untrack: () => untrack2,
27147
+ updateIn: () => updateIn,
26967
27148
  useBody: () => useBody,
26968
27149
  useFetch: () => useFetch,
26969
27150
  useLoadingIndicator: () => useLoadingIndicator,
@@ -27002,6 +27183,7 @@ var init_index_server = __esm({
27002
27183
  init_loading_indicator();
27003
27184
  init_action();
27004
27185
  init_metadata();
27186
+ init_nested_update();
27005
27187
  }
27006
27188
  });
27007
27189
 
@@ -29243,8 +29425,8 @@ function looksLikeMarkdownPath(value) {
29243
29425
  const v = value.trim();
29244
29426
  if (v.length === 0 || v.length > 4096) return false;
29245
29427
  if (v.includes("\n") || v.includes("\r")) return false;
29246
- const lower = v.toLowerCase();
29247
- return lower.endsWith(MD_EXT_MARKER) || lower.endsWith(".markdown");
29428
+ const lower2 = v.toLowerCase();
29429
+ return lower2.endsWith(MD_EXT_MARKER) || lower2.endsWith(".markdown");
29248
29430
  }
29249
29431
  function isRelativeSpecifier(v) {
29250
29432
  return v.startsWith("./") || v.startsWith("../");
@@ -31817,7 +31999,202 @@ var init_server_head = __esm({
31817
31999
  }
31818
32000
  });
31819
32001
 
32002
+ // ../compiler/src/server-jsx-lowering.ts
32003
+ function containsJsx2(node, depth = 0) {
32004
+ if (!node || typeof node !== "object" || depth > 40) return false;
32005
+ if (Array.isArray(node)) {
32006
+ for (const item of node) if (containsJsx2(item, depth + 1)) return true;
32007
+ return false;
32008
+ }
32009
+ const type = node.type;
32010
+ if (type === "JSXElement" || type === "JSXFragment") return true;
32011
+ for (const key of Object.keys(node)) {
32012
+ const value = node[key];
32013
+ if (value && typeof value === "object" && containsJsx2(value, depth + 1)) return true;
32014
+ }
32015
+ return false;
32016
+ }
32017
+ function normalizeJsxText(value) {
32018
+ const lines = value.split(/\r\n|\n|\r/);
32019
+ let lastNonEmpty = -1;
32020
+ for (let i = 0; i < lines.length; i++) {
32021
+ if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
32022
+ }
32023
+ let out = "";
32024
+ for (let i = 0; i < lines.length; i++) {
32025
+ let line = lines[i].replace(/\t/g, " ");
32026
+ if (i !== 0) line = line.replace(/^ +/, "");
32027
+ if (i !== lines.length - 1) line = line.replace(/ +$/, "");
32028
+ if (line) {
32029
+ if (i !== lastNonEmpty) line += " ";
32030
+ out += line;
32031
+ }
32032
+ }
32033
+ return out;
32034
+ }
32035
+ function lower(node, ctx2) {
32036
+ if (Array.isArray(node)) return node.map((n2) => lower(n2, ctx2));
32037
+ if (!node || typeof node !== "object") return node;
32038
+ const n = node;
32039
+ if (n.type === "JSXElement") {
32040
+ const opening = n.openingElement;
32041
+ const name = jsxTagName(opening.name);
32042
+ const attrs = lowerAttributes(opening.attributes, ctx2);
32043
+ const children = lowerChildren(n.children, ctx2);
32044
+ const statics = [`<${name}`, ...attrs.statics.slice(1)];
32045
+ statics[statics.length - 1] += ">";
32046
+ const quasis = [...statics, `</${name}>`];
32047
+ const expressions = [...attrs.exprs, ...children];
32048
+ return template(quasis, expressions);
32049
+ }
32050
+ if (n.type === "JSXFragment") {
32051
+ return template(["", ""], lowerChildren(n.children, ctx2));
32052
+ }
32053
+ const out = {};
32054
+ for (const key of Object.keys(n)) {
32055
+ if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "range") {
32056
+ out[key] = n[key];
32057
+ continue;
32058
+ }
32059
+ const value = n[key];
32060
+ out[key] = value && typeof value === "object" ? lower(value, ctx2) : value;
32061
+ }
32062
+ return out;
32063
+ }
32064
+ function jsxTagName(nameNode) {
32065
+ const n = nameNode;
32066
+ if (!n) return "div";
32067
+ if (n.type === "JSXIdentifier") return String(n.name);
32068
+ if (n.type === "JSXMemberExpression") {
32069
+ const object = jsxTagName(n.object);
32070
+ const property = n.property;
32071
+ return `${object}.${String(property?.name)}`;
32072
+ }
32073
+ if (n.type === "JSXNamespacedName") {
32074
+ const ns = n.namespace;
32075
+ const name = n.name;
32076
+ return `${String(ns?.name)}:${String(name?.name)}`;
32077
+ }
32078
+ return "div";
32079
+ }
32080
+ function lowerAttributes(attrs, ctx2) {
32081
+ const statics = [""];
32082
+ const exprs = [];
32083
+ const push = (text, expr) => {
32084
+ if (expr === void 0) {
32085
+ statics[statics.length - 1] += text;
32086
+ return;
32087
+ }
32088
+ statics[statics.length - 1] += text;
32089
+ statics.push("");
32090
+ exprs.push(expr);
32091
+ };
32092
+ for (const attr of attrs || []) {
32093
+ const a = attr;
32094
+ if (a.type === "JSXSpreadAttribute") {
32095
+ console.error("[vesk] a spread attribute in a JSX expression is not supported yet (dropped):", String(a.argument ?? "").slice(0, 60));
32096
+ continue;
32097
+ }
32098
+ const name = jsxAttrName(a.name);
32099
+ const value = a.value;
32100
+ if (value === null || value === void 0) {
32101
+ push(` ${name}`);
32102
+ continue;
32103
+ }
32104
+ if (value.type === "StringLiteral") {
32105
+ push(` ${name}="${escapeAttrText(String(value.value))}"`);
32106
+ continue;
32107
+ }
32108
+ if (value.type === "JSXExpressionContainer") {
32109
+ const inner = value.expression;
32110
+ if (!inner || inner.type === "JSXEmptyExpression") {
32111
+ push(` ${name}="true"`);
32112
+ continue;
32113
+ }
32114
+ push(` ${name}="`, callNode(ATTR, [literal3(name), coerceString(lower(inner, ctx2))]));
32115
+ push('"');
32116
+ continue;
32117
+ }
32118
+ push(` ${name}="`, callNode(ATTR, [literal3(name), coerceString(lower(value, ctx2))]));
32119
+ push('"');
32120
+ }
32121
+ return { statics, exprs };
32122
+ }
32123
+ function jsxAttrName(nameNode) {
32124
+ const n = nameNode;
32125
+ if (!n) return "data";
32126
+ if (n.type === "JSXIdentifier") return String(n.name);
32127
+ return jsxTagName(n);
32128
+ }
32129
+ function lowerChildren(children, ctx2) {
32130
+ const out = [];
32131
+ for (const child of children || []) {
32132
+ const c = child;
32133
+ if (c.type === "JSXText") {
32134
+ const text = normalizeJsxText(String(c.value ?? ""));
32135
+ if (text) out.push(literal3(text));
32136
+ continue;
32137
+ }
32138
+ if (c.type === "JSXExpressionContainer") {
32139
+ const inner = c.expression;
32140
+ if (!inner || inner.type === "JSXEmptyExpression") continue;
32141
+ const lowered2 = lower(inner, ctx2);
32142
+ out.push(coerceString(lowered2));
32143
+ continue;
32144
+ }
32145
+ const lowered = lower(c, ctx2);
32146
+ out.push(coerceString(lowered));
32147
+ }
32148
+ return out;
32149
+ }
32150
+ function coerceString(node) {
32151
+ if (!node || typeof node !== "object") return callNode(ESCAPE, [literal3(String(node))]);
32152
+ const n = node;
32153
+ if (n.type === "TemplateLiteral") return n;
32154
+ if (n.type === "Literal" || n.type === "StringLiteral") return callNode(ESCAPE, [node]);
32155
+ return callNode(ESCAPE, [callNode("String", [node])]);
32156
+ }
32157
+ function template(statics, expressions) {
32158
+ const quasis = statics.map((raw2, i) => ({
32159
+ type: "TemplateElement",
32160
+ value: { raw: raw2 },
32161
+ tail: i === statics.length - 1
32162
+ }));
32163
+ return { type: "TemplateLiteral", quasis, expressions };
32164
+ }
32165
+ function literal3(value) {
32166
+ return { type: "Literal", value };
32167
+ }
32168
+ function callNode(callee, args2) {
32169
+ return {
32170
+ type: "CallExpression",
32171
+ callee: { type: "Identifier", name: callee },
32172
+ arguments: args2,
32173
+ optional: false
32174
+ };
32175
+ }
32176
+ function escapeAttrText(value) {
32177
+ return value.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;").split('"').join("&quot;");
32178
+ }
32179
+ function lowerJsxInExpression(ast) {
32180
+ if (!containsJsx2(ast)) return ast;
32181
+ return lower(ast, { track: false });
32182
+ }
32183
+ var ESCAPE, ATTR;
32184
+ var init_server_jsx_lowering = __esm({
32185
+ "../compiler/src/server-jsx-lowering.ts"() {
32186
+ "use strict";
32187
+ ESCAPE = "__escape";
32188
+ ATTR = "__attr";
32189
+ }
32190
+ });
32191
+
31820
32192
  // ../compiler/src/server-jsgen.ts
32193
+ import { print as print6 } from "esrap";
32194
+ import tsPrinter from "esrap/languages/ts";
32195
+ function printLoweredTs(ast) {
32196
+ return print6(ast, tsPrinter()).code;
32197
+ }
31821
32198
  function sanitizeMarkerName(name) {
31822
32199
  return String(name).split("--").join("-").split("<").join("").split(">").join("");
31823
32200
  }
@@ -31868,7 +32245,19 @@ function irNodeToJS(node, importedNames, isAsync = false, tracked2) {
31868
32245
  `})();`
31869
32246
  ].join("\n");
31870
32247
  }
31871
- if (node instanceof RuntimeStatement) return semicolonizeStatement(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
32248
+ if (node instanceof RuntimeStatement) {
32249
+ const stmt = node;
32250
+ const lowered = stmt.ast ? lowerJsxInExpression(stmt.ast) : null;
32251
+ if (lowered && lowered !== stmt.ast && (tracked2?.size ?? 0) === 0) {
32252
+ return semicolonizeStatement(printLoweredTs(lowered));
32253
+ }
32254
+ if (lowered && lowered !== stmt.ast) {
32255
+ return semicolonizeStatement(
32256
+ transformTracked({ ...node, ast: lowered }, tracked2 || /* @__PURE__ */ new Map())
32257
+ );
32258
+ }
32259
+ return semicolonizeStatement(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
32260
+ }
31872
32261
  if (node instanceof SlotNode) {
31873
32262
  if (__vskMarkerless) return `__out.push(props.children || '');`;
31874
32263
  const sid = `s${nextVskId()}`;
@@ -31885,7 +32274,12 @@ function isEvent(target) {
31885
32274
  return !!target && target.startsWith("on") && target.length > 2;
31886
32275
  }
31887
32276
  function exprJSX(node, tracked2) {
31888
- return exprJS(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
32277
+ const lowered = node.ast ? lowerJsxInExpression(node.ast) : null;
32278
+ const didLower = lowered !== node.ast;
32279
+ if (didLower && (tracked2?.size ?? 0) === 0) {
32280
+ return exprJS(printLoweredTs(lowered));
32281
+ }
32282
+ return exprJS(transformTracked({ ...node, ast: lowered }, tracked2 || /* @__PURE__ */ new Map()));
31889
32283
  }
31890
32284
  function staticNodeToJS(node, isAsync = false, tracked2) {
31891
32285
  const lines = [];
@@ -32033,13 +32427,13 @@ function mapRegionToJS(node, isAsync = false, tracked2) {
32033
32427
  }
32034
32428
  function keyedItemTemplate(node) {
32035
32429
  if (!node.keyExpr) return node.bodyTemplate;
32036
- const template = node.bodyTemplate;
32037
- const idx = template.findIndex((n) => n instanceof StaticNode);
32038
- if (idx === -1) return template;
32039
- const root3 = template[idx];
32430
+ const template2 = node.bodyTemplate;
32431
+ const idx = template2.findIndex((n) => n instanceof StaticNode);
32432
+ if (idx === -1) return template2;
32433
+ const root3 = template2[idx];
32040
32434
  const copy = new StaticNode(root3.tag, root3.attributes, [...root3.children, new DynamicBinding(node.keyExpr, "attribute", "data-vsk-key")], root3.keyExpr);
32041
32435
  copy.selfClosing = root3.selfClosing;
32042
- const out = template.slice();
32436
+ const out = template2.slice();
32043
32437
  out[idx] = copy;
32044
32438
  return out;
32045
32439
  }
@@ -32151,18 +32545,24 @@ function componentCallToJS(node, importedNames, isAsync = false, tracked2) {
32151
32545
  }
32152
32546
  }
32153
32547
  if (regularChildren.length > 0) {
32154
- const childLines = [];
32155
- for (const child of regularChildren) {
32156
- const code = irNodeToJS(child, importedNames, isAsync, tracked2);
32157
- if (code) childLines.push(code);
32158
- }
32159
- if (childLines.length > 0) {
32160
- const childrenVar = `__ch${nextVskId()}`;
32161
- propsEntries.push(`children: ${childrenVar}`);
32162
- lines.push(`const ${childrenVar} = ${isAsync ? "await (async " : "("}() => {`);
32163
- lines.push(`const __out = [];`);
32164
- lines.push(indent(childLines.join("\n")));
32165
- lines.push(`return __out.join(''); })();`);
32548
+ const fnType = regularChildren.length === 1 && regularChildren[0] instanceof DynamicBinding && regularChildren[0].kind === "text" ? regularChildren[0].expression.ast?.type : null;
32549
+ const isFnChild = fnType === "ArrowFunctionExpression" || fnType === "FunctionExpression" || fnType === "Identifier" || fnType === "MemberExpression";
32550
+ if (isFnChild) {
32551
+ propsEntries.push(`children: ${exprJSX(regularChildren[0].expression, tracked2)}`);
32552
+ } else {
32553
+ const childLines = [];
32554
+ for (const child of regularChildren) {
32555
+ const code = irNodeToJS(child, importedNames, isAsync, tracked2);
32556
+ if (code) childLines.push(code);
32557
+ }
32558
+ if (childLines.length > 0) {
32559
+ const childrenVar = `__ch${nextVskId()}`;
32560
+ propsEntries.push(`children: ${childrenVar}`);
32561
+ lines.push(`const ${childrenVar} = ${isAsync ? "await (async " : "("}() => {`);
32562
+ lines.push(`const __out = [];`);
32563
+ lines.push(indent(childLines.join("\n")));
32564
+ lines.push(`return __out.join(''); })();`);
32565
+ }
32166
32566
  }
32167
32567
  }
32168
32568
  const propsObj = `{ ${propsEntries.join(", ")} }`;
@@ -32179,9 +32579,9 @@ function componentCallToJS(node, importedNames, isAsync = false, tracked2) {
32179
32579
  }
32180
32580
  const callExpr3 = `${awaitKw}${calleeVar}(${propsObj}, __registry, (${calleeVar}.__veskScope || __vesk))`;
32181
32581
  if (__vskHydrate && !__vskMarkerless) {
32182
- lines.push(`__out.push(${JSON.stringify(componentMarker(compName))} + (${callExpr3} || ''));`);
32582
+ lines.push(`__out.push(${JSON.stringify(componentMarker(compName))} + __flat(${callExpr3}));`);
32183
32583
  } else {
32184
- lines.push(`__out.push(${callExpr3} || '');`);
32584
+ lines.push(`__out.push(__flat(${callExpr3}));`);
32185
32585
  }
32186
32586
  return lines.join("\n");
32187
32587
  }
@@ -32199,6 +32599,7 @@ function generateFunctionBody(comp, importedNames) {
32199
32599
  lines.push(`const __styleText = (v) => { if (typeof v === 'string') return v; if (v && typeof v === 'object') { let s = ''; for (const k in v) { const x = v[k]; if (x == null || x === false) continue; s += k.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()) + ':' + x + ';'; } return s; } return String(v); };`);
32200
32600
  lines.push(`const __attr = (n, v) => (v == null || v === false) ? '' : ' ' + n + '="' + __escape(n === 'style' ? __styleText(v) : String(v)) + '"';`);
32201
32601
  lines.push(`const raw = (s) => s == null ? '' : String(s);`);
32602
+ lines.push(`const __flat = (v) => Array.isArray(v) ? v.join('') : (v == null ? '' : String(v));`);
32202
32603
  lines.push(`const __tk = globalThis.__vsk_ssr_token || '';`);
32203
32604
  if (asyncMode) {
32204
32605
  lines.push(`const __pk = __tk ? '__vsk_ssr_promises_' + __tk : '__vsk_ssr_promises';`);
@@ -32235,6 +32636,64 @@ function generateFunctionBody(comp, importedNames) {
32235
32636
  __currentCompName = "";
32236
32637
  return lines.join("\n");
32237
32638
  }
32639
+ function bodyNeedsRuntimeCells(nodes) {
32640
+ for (const node of nodes) {
32641
+ if (node instanceof TrackDecl) return true;
32642
+ if (node instanceof RuntimeStatement && callsIdentifier(node.raw, "track")) return true;
32643
+ if (node instanceof Expression && callsIdentifier(node.raw, "track")) return true;
32644
+ if (node instanceof ForLoop) {
32645
+ if (callsIdentifier(node.init, "track")) return true;
32646
+ if (callsIdentifier(node.update, "track")) return true;
32647
+ if (callsIdentifier(node.condition.raw, "track")) return true;
32648
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
32649
+ }
32650
+ if (node instanceof StaticNode) {
32651
+ for (const attr of node.attributes) {
32652
+ if (callsIdentifier(attr.value, "track")) return true;
32653
+ }
32654
+ if (bodyNeedsRuntimeCells(node.children)) return true;
32655
+ }
32656
+ if (node instanceof ComponentCall) {
32657
+ for (const prop of node.props) {
32658
+ if (callsIdentifier(prop.value.raw, "track")) return true;
32659
+ }
32660
+ for (const spread of node.spreadProps) {
32661
+ if (callsIdentifier(spread.raw, "track")) return true;
32662
+ }
32663
+ if (bodyNeedsRuntimeCells(node.children)) return true;
32664
+ }
32665
+ if (node instanceof ServerBlock || node instanceof ClientBlock || node instanceof HeadBlock) {
32666
+ if (bodyNeedsRuntimeCells(node.children)) return true;
32667
+ }
32668
+ if (node instanceof PropSlot && bodyNeedsRuntimeCells(node.body)) return true;
32669
+ if (node instanceof MapRegion) {
32670
+ if (callsIdentifier(node.expression.raw, "track")) return true;
32671
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
32672
+ if (bodyNeedsRuntimeCells(node.alternateNodes)) return true;
32673
+ }
32674
+ if (node instanceof OpaqueDynamicRegion) {
32675
+ if (callsIdentifier(node.condition.raw, "track")) return true;
32676
+ if (bodyNeedsRuntimeCells(node.consequentNodes)) return true;
32677
+ if (bodyNeedsRuntimeCells(node.alternateNodes)) return true;
32678
+ }
32679
+ if (node instanceof WhileLoop) {
32680
+ if (callsIdentifier(node.condition.raw, "track")) return true;
32681
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
32682
+ }
32683
+ if (node instanceof SwitchBlock) {
32684
+ if (callsIdentifier(node.discriminant.raw, "track")) return true;
32685
+ for (const c of node.cases) {
32686
+ if (c.test && callsIdentifier(c.test.raw, "track")) return true;
32687
+ if (bodyNeedsRuntimeCells(c.body)) return true;
32688
+ }
32689
+ }
32690
+ if (node instanceof TryCatch) {
32691
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
32692
+ if (bodyNeedsRuntimeCells(node.catchBody)) return true;
32693
+ }
32694
+ }
32695
+ return false;
32696
+ }
32238
32697
  function buildComponentEntries(irRoot) {
32239
32698
  const runtimeNames = extractRuntimeNames(irRoot.imports);
32240
32699
  const localValueNames = localValueImportNames(irRoot.imports);
@@ -32242,7 +32701,7 @@ function buildComponentEntries(irRoot) {
32242
32701
  const componentNames = new Set(irRoot.components.map((c) => c.name));
32243
32702
  const topValueNames = topNames.filter((n) => !componentNames.has(n));
32244
32703
  const importedNames = /* @__PURE__ */ new Set([...runtimeNames, ...localValueNames, ...topValueNames]);
32245
- const hasTracked = irRoot.components.some((c) => c.body.some((n) => n instanceof TrackDecl));
32704
+ const hasTracked = irRoot.components.some((c) => bodyNeedsRuntimeCells(c.body));
32246
32705
  const extraNames = hasTracked ? ["get", "set", "track"] : [];
32247
32706
  const vskValueNames = vskImportValueNames(irRoot.imports);
32248
32707
  const allNames = [.../* @__PURE__ */ new Set([...runtimeNames, ...topNames, ...extraNames, ...localValueNames, ...vskValueNames])];
@@ -32286,6 +32745,7 @@ var init_server_jsgen = __esm({
32286
32745
  init_scan();
32287
32746
  init_server_utils();
32288
32747
  init_module_imports();
32748
+ init_server_jsx_lowering();
32289
32749
  init_vsk_imports();
32290
32750
  __currentCompName = "";
32291
32751
  }
@@ -33050,8 +33510,8 @@ function installMdReadHook(publicDirs) {
33050
33510
  while (rel.length > 0 && rel.charCodeAt(0) === 47) rel = rel.slice(1);
33051
33511
  const abs = resolveWithin(dir, rel);
33052
33512
  if (!abs) continue;
33053
- const lower = abs.toLowerCase();
33054
- if (!lower.endsWith(".md") && !lower.endsWith(".markdown")) continue;
33513
+ const lower2 = abs.toLowerCase();
33514
+ if (!lower2.endsWith(".md") && !lower2.endsWith(".markdown")) continue;
33055
33515
  if (existsSync12(abs) && statSync4(abs).isFile()) return readFileSync12(abs, "utf8");
33056
33516
  } catch {
33057
33517
  }
@@ -37478,8 +37938,8 @@ function isPublicMarkdownPath2(v) {
37478
37938
  if (c === 63 || c === 35 || c === 92)
37479
37939
  return false;
37480
37940
  }
37481
- const lower = s.toLowerCase();
37482
- return stringEndsWith2(lower, ".md") || stringEndsWith2(lower, ".markdown");
37941
+ const lower2 = s.toLowerCase();
37942
+ return stringEndsWith2(lower2, ".md") || stringEndsWith2(lower2, ".markdown");
37483
37943
  }
37484
37944
  function getMdPathCell2(path) {
37485
37945
  let cell = mdPathCells2.get(path);
@@ -38219,7 +38679,10 @@ var init_errors2 = __esm({
38219
38679
  suggestions;
38220
38680
  nextSteps;
38221
38681
  tip;
38682
+ /** The V-diagnostic code, e.g. `V0501`. */
38222
38683
  code;
38684
+ /** The rendered code frame. Used to be written into `code`, which silently replaced the V-code. */
38685
+ frame;
38223
38686
  constructor(message, opts = {}) {
38224
38687
  super(message);
38225
38688
  this.name = "VeskError";
@@ -38229,8 +38692,10 @@ var init_errors2 = __esm({
38229
38692
  this.suggestions = opts.suggestions || [];
38230
38693
  this.nextSteps = opts.nextSteps || [];
38231
38694
  this.tip = opts.tip || "";
38232
- if (opts.code !== void 0)
38695
+ if (opts.code !== void 0 && !opts.code.includes("\n"))
38233
38696
  this.code = opts.code;
38697
+ if (opts.frame !== void 0)
38698
+ this.frame = opts.frame;
38234
38699
  }
38235
38700
  static notFound(name, candidates = [], context = {}) {
38236
38701
  const allCandidates = [.../* @__PURE__ */ new Set([...candidates, ...VESK_BUILTINS2])];
@@ -38303,6 +38768,75 @@ var init_errors2 = __esm({
38303
38768
  tip: "Use plain objects for data and factory functions for constructors inside .vsk files."
38304
38769
  });
38305
38770
  }
38771
+ /**
38772
+ * A browser-only global used in code the SERVER evaluates.
38773
+ *
38774
+ * On the server these are either absent (`window is not defined`) or, worse,
38775
+ * silently present-but-wrong (`navigator` exists in modern Node, so
38776
+ * `navigator.onLine` is `undefined` and a page renders as if it were offline).
38777
+ * A raw `ReferenceError` at request time is the worst possible report: it
38778
+ * names neither the component nor the fix. This points at the line.
38779
+ */
38780
+ static ssrUnsafeGlobal(name, context = {}) {
38781
+ return new _VeskError(`\`${name}\` is browser-only, and this component body runs during SSR.`, {
38782
+ ...context,
38783
+ code: context.code || "V0501",
38784
+ suggestions: [
38785
+ `Wrap the part that needs the DOM in a {#client} block.`,
38786
+ `Move the code into an event handler \u2014 handlers never run on the server.`,
38787
+ `Do the setup in on_destroy(), which the compiler only emits on the client.`
38788
+ ],
38789
+ nextSteps: [
38790
+ `component ${context.inComponent ?? "this component"}: wrap the \`${name}\` access in {#client}...{/client}.`,
38791
+ `Or guard it: if (typeof ${name} !== 'undefined') { ... }`
38792
+ ],
38793
+ tip: "SSR renders this component before the client exists. Reading a browser global here either throws during the request or (for `navigator`) silently returns undefined."
38794
+ });
38795
+ }
38796
+ /**
38797
+ * The second name from `track()` called as a function.
38798
+ *
38799
+ * `const &[count, setCount] = track(0)` returns a CELL, not a setter function, so
38800
+ * `setCount(1)` throws `setCount is not a function` from generated code with
38801
+ * no line of user code in the message. The cell is the writer: `.set(v)`.
38802
+ */
38803
+ static cellCalledAsFunction(name, context = {}) {
38804
+ return new _VeskError(`\`${name}\` is a cell, not a function \u2014 cells are written with \`.set()\`.`, {
38805
+ ...context,
38806
+ code: context.code || "V0502",
38807
+ suggestions: [
38808
+ `Use \`${name}.set(...)\` instead of \`${name}(...)\`.`,
38809
+ `Or use the tracked spelling inside an event handler: set(${context.value ?? "value"}, ...)`
38810
+ ],
38811
+ nextSteps: [
38812
+ `const &[${context.value ?? "value"}, ${name}] = track(0) \u2192 \`${name}.set(v)\``,
38813
+ "The value read in markup is the first name; the second is the cell object."
38814
+ ],
38815
+ tip: `\`track()\` returns [value, cell]. \`${name}\` is the cell half.`
38816
+ });
38817
+ }
38818
+ /**
38819
+ * `set(value, …)` used outside a rewritten expression.
38820
+ *
38821
+ * The compiler rewrites `set(count, v)` to `countCell.set(v)` inside JSX and
38822
+ * event handlers — but a bare statement in the component body is NOT
38823
+ * rewritten, so the runtime `set` receives the value and throws
38824
+ * "Cannot read properties of undefined". Pass the CELL, not the value.
38825
+ */
38826
+ static setWithValueName(name, context = {}) {
38827
+ return new _VeskError(`\`set(${name}, \u2026)\` needs the CELL, and \`${name}\` is the value half of track().`, {
38828
+ ...context,
38829
+ code: context.code || "V0503",
38830
+ suggestions: [
38831
+ `Use \`set(${context.cell ?? "cell"}, \u2026)\` or \`${context.cell ?? "cell"}.set(\u2026)\`.`,
38832
+ `Or move the set() into an event handler, where the compiler rewrites it for you.`
38833
+ ],
38834
+ nextSteps: [
38835
+ `const &[${name}, ${context.cell ?? "cell"}] = track(0) \u2192 \`${context.cell ?? "cell"}.set(v)\``
38836
+ ],
38837
+ tip: "set(cell, value) is only rewritten inside JSX and handlers; in a body statement it reaches the runtime untouched."
38838
+ });
38839
+ }
38306
38840
  static serverBlockInClient(compName, context = {}) {
38307
38841
  return new _VeskError(`{#server} block found in client island "${compName}". Client islands render on both server and client, so {#server} blocks have no effect.`, {
38308
38842
  ...context,
@@ -50051,7 +50585,7 @@ import { WebSocketServer as WebSocketServer2 } from "ws";
50051
50585
  // ../compiler/dist/strip-ts.js
50052
50586
  init_parser();
50053
50587
  import { walk as walk6 } from "zimmerframe";
50054
- import { print as print6 } from "esrap";
50588
+ import { print as print7 } from "esrap";
50055
50589
  import ts6 from "esrap/languages/ts";
50056
50590
  var TS_NODE_TYPES2 = /* @__PURE__ */ new Set([
50057
50591
  "TSAsExpression",
@@ -50248,7 +50782,7 @@ function stripCodeTypes2(code) {
50248
50782
  stripped.body = stripped.body.filter((n) => !isTypeOnlyStatement2(n));
50249
50783
  }
50250
50784
  try {
50251
- return print6(stripped, ts6()).code;
50785
+ return print7(stripped, ts6()).code;
50252
50786
  } catch {
50253
50787
  return code;
50254
50788
  }
@@ -50387,7 +50921,7 @@ init_vsk_imports();
50387
50921
  init_md_inline();
50388
50922
  init_strip_ts();
50389
50923
  import { walk as walk7 } from "zimmerframe";
50390
- import { print as print7 } from "esrap";
50924
+ import { print as print8 } from "esrap";
50391
50925
  import ts7 from "esrap/languages/ts";
50392
50926
  import tsx2 from "esrap/languages/tsx";
50393
50927
  function callExpr2(callee, args2 = []) {
@@ -50454,12 +50988,12 @@ function semicolonizeStatement2(code) {
50454
50988
  return code;
50455
50989
  return code + ";";
50456
50990
  }
50457
- function containsJsx2(node, depth = 0) {
50991
+ function containsJsx3(node, depth = 0) {
50458
50992
  if (!node || typeof node !== "object" || depth > 40)
50459
50993
  return false;
50460
50994
  if (Array.isArray(node)) {
50461
50995
  for (const item of node) {
50462
- if (containsJsx2(item, depth + 1))
50996
+ if (containsJsx3(item, depth + 1))
50463
50997
  return true;
50464
50998
  }
50465
50999
  return false;
@@ -50468,13 +51002,13 @@ function containsJsx2(node, depth = 0) {
50468
51002
  return true;
50469
51003
  for (const key of Object.keys(node)) {
50470
51004
  const v = node[key];
50471
- if (v && typeof v === "object" && containsJsx2(v, depth + 1))
51005
+ if (v && typeof v === "object" && containsJsx3(v, depth + 1))
50472
51006
  return true;
50473
51007
  }
50474
51008
  return false;
50475
51009
  }
50476
51010
  function printAst2(ast) {
50477
- return print7(ast, containsJsx2(ast) ? tsx2() : ts7()).code;
51011
+ return print8(ast, containsJsx3(ast) ? tsx2() : ts7()).code;
50478
51012
  }
50479
51013
  function effectBlockToHandlerExpr2(eff) {
50480
51014
  try {
@@ -50595,7 +51129,7 @@ function transformTracked2(irNode, tracked2) {
50595
51129
  return context.next();
50596
51130
  }
50597
51131
  });
50598
- return print7(transformed, containsJsx2(transformed) ? tsx2() : ts7()).code;
51132
+ return print8(transformed, containsJsx3(transformed) ? tsx2() : ts7()).code;
50599
51133
  }
50600
51134
  function collectTrackedNames2(body) {
50601
51135
  const names = /* @__PURE__ */ new Map();
@@ -53730,8 +54264,8 @@ function looksLikeMarkdownPath2(value) {
53730
54264
  return false;
53731
54265
  if (v.includes("\n") || v.includes("\r"))
53732
54266
  return false;
53733
- const lower = v.toLowerCase();
53734
- return lower.endsWith(MD_EXT_MARKER2) || lower.endsWith(".markdown");
54267
+ const lower2 = v.toLowerCase();
54268
+ return lower2.endsWith(MD_EXT_MARKER2) || lower2.endsWith(".markdown");
53735
54269
  }
53736
54270
  function isRelativeSpecifier2(v) {
53737
54271
  return v.startsWith("./") || v.startsWith("../");
@@ -54937,8 +55471,8 @@ function installMdReadHook2(publicDirs) {
54937
55471
  const abs = resolveWithin2(dir, rel);
54938
55472
  if (!abs)
54939
55473
  continue;
54940
- const lower = abs.toLowerCase();
54941
- if (!lower.endsWith(".md") && !lower.endsWith(".markdown"))
55474
+ const lower2 = abs.toLowerCase();
55475
+ if (!lower2.endsWith(".md") && !lower2.endsWith(".markdown"))
54942
55476
  continue;
54943
55477
  if (existsSync29(abs) && statSync15(abs).isFile())
54944
55478
  return readFileSync25(abs, "utf8");
@@ -62809,6 +63343,7 @@ __export(index_server_exports2, {
62809
63343
  get: () => get,
62810
63344
  getAction: () => getAction,
62811
63345
  getActiveComponent: () => getActiveComponent,
63346
+ getIn: () => getIn,
62812
63347
  getLoadingError: () => getLoadingError,
62813
63348
  getLoadingProgress: () => getLoadingProgress,
62814
63349
  getServerContext: () => getServerContext,
@@ -62862,6 +63397,7 @@ __export(index_server_exports2, {
62862
63397
  server_locals: () => server_locals,
62863
63398
  set: () => set,
62864
63399
  setActiveComponent: () => setActiveComponent,
63400
+ setIn: () => setIn,
62865
63401
  setServerContext: () => setServerContext,
62866
63402
  setSignedCookie: () => setSignedCookie2,
62867
63403
  setSsrData: () => setSsrData,
@@ -62876,6 +63412,7 @@ __export(index_server_exports2, {
62876
63412
  unlink_block: () => unlink_block,
62877
63413
  unsignCookie: () => unsignCookie2,
62878
63414
  untrack: () => untrack2,
63415
+ updateIn: () => updateIn,
62879
63416
  useBody: () => useBody,
62880
63417
  useFetch: () => useFetch,
62881
63418
  useLoadingIndicator: () => useLoadingIndicator,
@@ -62911,6 +63448,7 @@ init_primitive();
62911
63448
  init_loading_indicator();
62912
63449
  init_action();
62913
63450
  init_metadata();
63451
+ init_nested_update();
62914
63452
 
62915
63453
  // src/index.ts
62916
63454
  var __filename2 = fileURLToPath9(import.meta.url);
@@ -63056,12 +63594,14 @@ if (cmd === "build") {
63056
63594
  const l = err.line;
63057
63595
  const c = err.column;
63058
63596
  const code = err.code;
63597
+ const frame = err.frame;
63059
63598
  let out = `vesk build: error \u2014 ${err.message}`;
63599
+ if (code) out = `vesk build: [${code}] ${err.message}`;
63060
63600
  if (f) out += `
63061
63601
  File: ${f}${l ? `:${l}${c ? `:${c}` : ""}` : ""}`;
63062
- if (code) out += `
63602
+ if (frame) out += `
63063
63603
 
63064
- ${code}`;
63604
+ ${frame}`;
63065
63605
  console.error(out);
63066
63606
  if (err.stack && !String(err.stack).includes(err.message)) console.error(err.stack);
63067
63607
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/vesk-cli",
3
- "version": "0.2.50-canary.9",
3
+ "version": "0.2.50",
4
4
  "type": "module",
5
5
  "description": "Vesk — compiler-first framework for the post-VDOM web. vesk dev, vesk build.",
6
6
  "bin": {
@@ -8,10 +8,10 @@
8
8
  },
9
9
  "main": "./dist/cli.js",
10
10
  "dependencies": {
11
- "@vesk/adapter": "^0.2.50-canary.9",
12
- "@vesk/compiler": "^0.2.50-canary.9",
13
- "@vesk/plugin-tailwind": "^0.2.50-canary.9",
14
- "@vesk/runtime": "^0.2.50-canary.9",
11
+ "@vesk/adapter": "^0.2.50",
12
+ "@vesk/compiler": "^0.2.50",
13
+ "@vesk/plugin-tailwind": "^0.2.50",
14
+ "@vesk/runtime": "^0.2.50",
15
15
  "esrap": "^2.3.0",
16
16
  "typescript": "^5.8.0",
17
17
  "ws": "^8.18.0",