@vesk/vesk-cli 0.2.50-canary.4 → 0.2.50-canary.6

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 +269 -20
  2. package/package.json +5 -5
package/dist/cli.js CHANGED
@@ -399,6 +399,13 @@ var init_ir = __esm({
399
399
  importedNames;
400
400
  staticProps;
401
401
  loadFn;
402
+ /**
403
+ * Source of `export const metadata = defineMetadata({...})`, when present.
404
+ * Static by construction: evaluated with only `defineMetadata` in scope, at
405
+ * build time where possible and in a sealed sandbox at request time
406
+ * otherwise, so the head never depends on the component's frame.
407
+ */
408
+ metadataSource;
402
409
  topLevelCode;
403
410
  /**
404
411
  * Same-file specifier exports (`export { A }`, `export { A as B }`) as
@@ -1966,8 +1973,16 @@ function writeCache(key, data2) {
1966
1973
  const entry = getClientCache().get(key);
1967
1974
  if (!entry || entry.data !== data2) getClientCache().set(key, { data: data2, fetchedAt: Date.now() });
1968
1975
  }
1969
- function trackSsrPromise(promise) {
1976
+ function trackSsrPromise(promise, defer = false) {
1970
1977
  const tk = g().__vsk_ssr_token || "";
1978
+ if (defer) {
1979
+ const deferredKey = tk ? `__vsk_ssr_deferred_${tk}` : "__vsk_ssr_deferred";
1980
+ if (!g()[deferredKey]) g()[deferredKey] = [];
1981
+ g()[deferredKey].push(promise);
1982
+ promise.then(void 0, () => {
1983
+ });
1984
+ return;
1985
+ }
1971
1986
  const promisesKey = tk ? `__vsk_ssr_promises_${tk}` : "__vsk_ssr_promises";
1972
1987
  if (!g()[promisesKey]) g()[promisesKey] = [];
1973
1988
  g()[promisesKey].push(promise);
@@ -2034,7 +2049,7 @@ function startRequest(handle2, skipCache) {
2034
2049
  } else {
2035
2050
  attachSettle(handle2, prom2);
2036
2051
  }
2037
- trackSsrPromise(prom2);
2052
+ trackSsrPromise(prom2, options.ssr === "defer");
2038
2053
  return prom2;
2039
2054
  }
2040
2055
  if (!skipCache && options.staleTime && options.staleTime > 0) {
@@ -21292,6 +21307,7 @@ function generateIR(ast, source, filename) {
21292
21307
  const importedNames = /* @__PURE__ */ new Set();
21293
21308
  let staticProps = null;
21294
21309
  let loadFn = null;
21310
+ let metadataSource = null;
21295
21311
  const topLevelCode = [];
21296
21312
  const exportAliases = [];
21297
21313
  const reexportSources = [];
@@ -21327,6 +21343,14 @@ function generateIR(ast, source, filename) {
21327
21343
  continue;
21328
21344
  }
21329
21345
  }
21346
+ if (node.type === "ExportNamedDeclaration" && node.declaration && !metadataSource) {
21347
+ const decl = node.declaration;
21348
+ const first = decl.type === "VariableDeclaration" ? decl.declarations[0] : null;
21349
+ if (first?.id?.name === "metadata") {
21350
+ metadataSource = first.init ? stripCodeTypes(getSource(source, first.init)) : null;
21351
+ continue;
21352
+ }
21353
+ }
21330
21354
  if (node.type === "ExportNamedDeclaration" && node.declaration && !loadFn) {
21331
21355
  const decl = node.declaration;
21332
21356
  const fnName = decl.type === "FunctionDeclaration" ? decl.id?.name : decl.type === "VariableDeclaration" ? decl.declarations[0]?.id?.name : null;
@@ -21543,7 +21567,9 @@ function generateIR(ast, source, filename) {
21543
21567
  imports.push(`import { ${missing.join(", ")} } from '@vesk/runtime';`);
21544
21568
  }
21545
21569
  }
21546
- return new IRRoot(components, imports, importedNames, staticProps, loadFn, topLevelCode, exportAliases, reexportSources);
21570
+ const irRoot = new IRRoot(components, imports, importedNames, staticProps, loadFn, topLevelCode, exportAliases, reexportSources);
21571
+ irRoot.metadataSource = metadataSource;
21572
+ return irRoot;
21547
21573
  } finally {
21548
21574
  currentVskNamespaceLocals = prevNamespaceLocals;
21549
21575
  currentSourceFile = prevSourceFile;
@@ -22836,18 +22862,20 @@ function webhook(options) {
22836
22862
  secret,
22837
22863
  handler,
22838
22864
  headerName = "x-webhook-signature",
22839
- signaturePrefix = "sha256="
22865
+ signaturePrefix = "sha256=",
22866
+ algorithm = "SHA-256",
22867
+ signedPayload
22840
22868
  } = options;
22841
22869
  if (!secret) throw new Error("webhook() requires a secret");
22842
22870
  if (!handler) throw new Error("webhook() requires a handler function");
22843
- async function computeSignature(body) {
22871
+ async function computeSignature(payload) {
22844
22872
  const key = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
22845
- const data2 = typeof body === "string" ? new TextEncoder().encode(body) : body;
22873
+ const data2 = new TextEncoder().encode(payload);
22846
22874
  const crypto2 = globalThis.crypto;
22847
22875
  if (!crypto2?.subtle) {
22848
22876
  throw new Error("Web Crypto API not available (required for webhook signature verification)");
22849
22877
  }
22850
- return crypto2.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]).then((k) => crypto2.subtle.sign("HMAC", k, data2)).then((sig) => {
22878
+ return crypto2.subtle.importKey("raw", key, { name: "HMAC", hash: algorithm }, false, ["sign"]).then((k) => crypto2.subtle.sign("HMAC", k, data2)).then((sig) => {
22851
22879
  const hex = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
22852
22880
  return hex;
22853
22881
  });
@@ -22867,7 +22895,25 @@ function webhook(options) {
22867
22895
  });
22868
22896
  }
22869
22897
  const body = await request.text();
22870
- const expectedSig = await computeSignature(body);
22898
+ let parsed;
22899
+ try {
22900
+ parsed = JSON.parse(body);
22901
+ } catch {
22902
+ parsed = body;
22903
+ }
22904
+ const event = parsed;
22905
+ let payload = body;
22906
+ if (signedPayload) {
22907
+ try {
22908
+ payload = signedPayload(event);
22909
+ } catch {
22910
+ return new Response(JSON.stringify({ error: "Invalid signature" }), {
22911
+ status: 401,
22912
+ headers: { "Content-Type": "application/json" }
22913
+ });
22914
+ }
22915
+ }
22916
+ const expectedSig = await computeSignature(payload);
22871
22917
  const prefixLen = signaturePrefix.length;
22872
22918
  const providedSig = signature.startsWith(signaturePrefix) ? signature.slice(prefixLen) : signature;
22873
22919
  if (providedSig.length !== expectedSig.length) {
@@ -22886,12 +22932,6 @@ function webhook(options) {
22886
22932
  headers: { "Content-Type": "application/json" }
22887
22933
  });
22888
22934
  }
22889
- let event;
22890
- try {
22891
- event = JSON.parse(body);
22892
- } catch {
22893
- event = body;
22894
- }
22895
22935
  return handler(event, request);
22896
22936
  }
22897
22937
  return webhookHandler;
@@ -26614,6 +26654,177 @@ var init_action = __esm({
26614
26654
  }
26615
26655
  });
26616
26656
 
26657
+ // ../runtime/src/metadata.ts
26658
+ function assertPlainObject(value, where) {
26659
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
26660
+ throw new Error(`defineMetadata: ${where} must be a plain object, got ${Array.isArray(value) ? "an array" : typeof value}`);
26661
+ }
26662
+ return value;
26663
+ }
26664
+ function defineMetadata(input) {
26665
+ const meta = assertPlainObject(input, "the argument");
26666
+ if ("title" in meta && meta.title !== void 0) {
26667
+ if (typeof meta.title !== "string" && typeof meta.title !== "object") {
26668
+ throw new Error("defineMetadata: `title` must be a string or { default, template }");
26669
+ }
26670
+ if (typeof meta.title === "object") {
26671
+ const t = assertPlainObject(meta.title, "`title`");
26672
+ for (const key of Object.keys(t)) {
26673
+ if (key !== "default" && key !== "template" && key !== "absolute") {
26674
+ throw new Error(`defineMetadata: unknown \`title.${key}\` (expected default, template or absolute)`);
26675
+ }
26676
+ }
26677
+ }
26678
+ }
26679
+ if ("description" in meta && meta.description !== void 0 && typeof meta.description !== "string") {
26680
+ throw new Error("defineMetadata: `description` must be a string");
26681
+ }
26682
+ for (const key of ["openGraph", "twitter"]) {
26683
+ if (key in meta && meta[key] !== void 0) assertPlainObject(meta[key], `\`${key}\``);
26684
+ }
26685
+ if ("alternates" in meta && meta.alternates !== void 0) {
26686
+ const alt = assertPlainObject(meta.alternates, "`alternates`");
26687
+ for (const key of Object.keys(alt)) {
26688
+ if (key !== "canonical" && key !== "languages") {
26689
+ throw new Error(`defineMetadata: unknown \`alternates.${key}\` (expected canonical or languages)`);
26690
+ }
26691
+ }
26692
+ }
26693
+ for (const key of Object.keys(meta)) {
26694
+ if (!KNOWN_KEYS.has(key)) {
26695
+ throw new Error(
26696
+ `defineMetadata: unknown key "${key}". Known keys: ${[...KNOWN_KEYS].join(", ")}. (\`openGraph\` carries og:* tags, not top-level \`ogTitle\`.)`
26697
+ );
26698
+ }
26699
+ }
26700
+ return meta;
26701
+ }
26702
+ function resolveTitle(meta, child) {
26703
+ if (!meta || meta.title === void 0 || meta.title === null) return null;
26704
+ if (typeof meta.title === "string") return meta.title;
26705
+ if (meta.title.absolute) return meta.title.absolute;
26706
+ if (meta.title.default) return meta.title.default;
26707
+ if (meta.title.template && child) {
26708
+ const childTitle = resolveTitle(child);
26709
+ return childTitle === null ? null : meta.title.template.replace("%s", childTitle);
26710
+ }
26711
+ return null;
26712
+ }
26713
+ function mergeMetadata(...sources) {
26714
+ const out = {};
26715
+ let template;
26716
+ let sawTemplate = false;
26717
+ for (const source of sources) {
26718
+ if (!source) continue;
26719
+ for (const [key, value] of Object.entries(source)) {
26720
+ if (value === void 0) continue;
26721
+ if (key === "openGraph" || key === "twitter") {
26722
+ out[key] = { ...out[key] || {}, ...value };
26723
+ continue;
26724
+ }
26725
+ if (key === "title") {
26726
+ if (value && typeof value === "object" && value.template) {
26727
+ sawTemplate = true;
26728
+ template = value.template || template;
26729
+ }
26730
+ out.title = value;
26731
+ continue;
26732
+ }
26733
+ out[key] = value;
26734
+ }
26735
+ }
26736
+ if (sawTemplate && out.title !== void 0) {
26737
+ const own = out.title;
26738
+ if (typeof own === "string") out.title = { absolute: own };
26739
+ else if (own && typeof own === "object" && own.template) {
26740
+ out.title = { default: own.default, template: own.template || template };
26741
+ } else if (own && typeof own === "object") {
26742
+ out.title = { ...own, template };
26743
+ }
26744
+ }
26745
+ return out;
26746
+ }
26747
+ function escapeAttr2(value) {
26748
+ return String(value).split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;").split('"').join("&quot;");
26749
+ }
26750
+ function escapeText(value) {
26751
+ return String(value).split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
26752
+ }
26753
+ function metadataToHtml(meta, opts = {}) {
26754
+ if (!meta) return "";
26755
+ const lines = [];
26756
+ const title = resolveTitle(meta, opts.child);
26757
+ if (title !== null) lines.push(`<title data-vesk-head>${escapeText(title)}</title>`);
26758
+ if (typeof meta.description === "string" && meta.description.length > 0) {
26759
+ lines.push(`<meta name="description" content="${escapeAttr2(meta.description)}" data-vesk-head />`);
26760
+ }
26761
+ if (meta.robots) {
26762
+ const content = typeof meta.robots === "string" ? meta.robots : Object.entries(meta.robots).filter(([, on]) => on).map(([k]) => k).join(", ");
26763
+ if (content) lines.push(`<meta name="robots" content="${escapeAttr2(content)}" data-vesk-head />`);
26764
+ }
26765
+ if (meta.themeColor) {
26766
+ lines.push(`<meta name="theme-color" content="${escapeAttr2(meta.themeColor)}" data-vesk-head />`);
26767
+ }
26768
+ const og = meta.openGraph;
26769
+ if (og) {
26770
+ const ogTitle = resolveTitle(og) ?? title;
26771
+ const ogFields = [
26772
+ ["og:title", ogTitle],
26773
+ ["og:description", og.description ?? meta.description],
26774
+ ["og:url", og.url],
26775
+ ["og:site_name", og.siteName],
26776
+ ["og:image", og.image],
26777
+ ["og:type", og.type]
26778
+ ];
26779
+ for (const [prop, value] of ogFields) {
26780
+ if (value === void 0 || value === null || value === "") continue;
26781
+ lines.push(`<meta property="${prop}" content="${escapeAttr2(value)}" data-vesk-head />`);
26782
+ }
26783
+ }
26784
+ const tw = meta.twitter;
26785
+ if (tw) {
26786
+ const twFields = [
26787
+ ["twitter:card", tw.card],
26788
+ ["twitter:site", tw.site],
26789
+ ["twitter:title", resolveTitle(tw) ?? title],
26790
+ ["twitter:description", tw.description ?? meta.description],
26791
+ ["twitter:image", tw.image]
26792
+ ];
26793
+ for (const [name, value] of twFields) {
26794
+ if (value === void 0 || value === null || value === "") continue;
26795
+ lines.push(`<meta name="${name}" content="${escapeAttr2(value)}" data-vesk-head />`);
26796
+ }
26797
+ }
26798
+ const alt = meta.alternates;
26799
+ if (alt) {
26800
+ if (typeof alt === "object" && typeof alt.canonical === "string") {
26801
+ lines.push(`<link rel="canonical" href="${escapeAttr2(alt.canonical)}" data-vesk-head />`);
26802
+ }
26803
+ const languages = alt.languages;
26804
+ if (languages && typeof languages === "object") {
26805
+ for (const [lang, href] of Object.entries(languages)) {
26806
+ lines.push(`<link rel="alternate" hreflang="${escapeAttr2(lang)}" href="${escapeAttr2(href)}" data-vesk-head />`);
26807
+ }
26808
+ }
26809
+ }
26810
+ return lines.join("\n");
26811
+ }
26812
+ var KNOWN_KEYS;
26813
+ var init_metadata = __esm({
26814
+ "../runtime/src/metadata.ts"() {
26815
+ "use strict";
26816
+ KNOWN_KEYS = /* @__PURE__ */ new Set([
26817
+ "title",
26818
+ "description",
26819
+ "robots",
26820
+ "openGraph",
26821
+ "twitter",
26822
+ "alternates",
26823
+ "themeColor"
26824
+ ]);
26825
+ }
26826
+ });
26827
+
26617
26828
  // ../runtime/src/index-server.ts
26618
26829
  var index_server_exports = {};
26619
26830
  __export(index_server_exports, {
@@ -26675,6 +26886,7 @@ __export(index_server_exports, {
26675
26886
  custom: () => custom,
26676
26887
  defineAction: () => defineAction,
26677
26888
  defineHook: () => defineHook,
26889
+ defineMetadata: () => defineMetadata,
26678
26890
  defineRoute: () => defineRoute,
26679
26891
  derived: () => derived,
26680
26892
  destroy_block: () => destroy_block,
@@ -26702,6 +26914,8 @@ __export(index_server_exports, {
26702
26914
  leaf: () => leaf,
26703
26915
  locals: () => locals,
26704
26916
  maxLength: () => maxLength,
26917
+ mergeMetadata: () => mergeMetadata,
26918
+ metadataToHtml: () => metadataToHtml,
26705
26919
  minLength: () => minLength,
26706
26920
  mutate: () => mutate,
26707
26921
  notFound: () => notFound,
@@ -26722,6 +26936,7 @@ __export(index_server_exports, {
26722
26936
  required: () => required,
26723
26937
  rerenderNode: () => rerenderNode,
26724
26938
  resolveSsrResources: () => resolveSsrResources,
26939
+ resolveTitle: () => resolveTitle,
26725
26940
  resume_block: () => resume_block,
26726
26941
  revalidateComponent: () => revalidateComponent,
26727
26942
  revalidatePath: () => revalidatePath,
@@ -26786,6 +27001,7 @@ var init_index_server = __esm({
26786
27001
  init_primitive();
26787
27002
  init_loading_indicator();
26788
27003
  init_action();
27004
+ init_metadata();
26789
27005
  }
26790
27006
  });
26791
27007
 
@@ -31410,6 +31626,17 @@ function irNodeToHeadHtml(node, ctx2, reconcileable = false) {
31410
31626
  }
31411
31627
  return "";
31412
31628
  }
31629
+ function renderStaticMetadataHtml(source) {
31630
+ if (!source) return "";
31631
+ try {
31632
+ const fn = new Function("defineMetadata", "return (" + source + ")");
31633
+ const meta = fn(defineMetadata);
31634
+ return metadataToHtml(meta);
31635
+ } catch (e) {
31636
+ console.error("vesk: static metadata could not be evaluated:", e instanceof Error ? e.message : e);
31637
+ return "";
31638
+ }
31639
+ }
31413
31640
  function renderHeadHtml(comp, props = {}, scope2 = {}) {
31414
31641
  const tracked2 = collectTrackedNames(comp.body);
31415
31642
  const needed = headNeededNames(comp);
@@ -31577,6 +31804,7 @@ var init_server_head = __esm({
31577
31804
  init_scan();
31578
31805
  init_parser();
31579
31806
  init_client_codegen();
31807
+ init_metadata();
31580
31808
  headRuntimeShims = () => ({
31581
31809
  track: (init) => headCell(init),
31582
31810
  derived: (fn) => headCell(typeof fn === "function" ? fn() : fn),
@@ -32244,6 +32472,7 @@ function compileFile(source, options) {
32244
32472
  const owners = new VskComponentOwners();
32245
32473
  const result = compileFileInternal(source, options?.sourcePath, /* @__PURE__ */ new Set(), owners);
32246
32474
  owners.report("SSR");
32475
+ result.metadataSource = result.ir.metadataSource || null;
32247
32476
  return result;
32248
32477
  }
32249
32478
  function compileFileInternal(source, sourcePath2, seenImportFiles, owners) {
@@ -32346,6 +32575,7 @@ function renderPage(source, componentName, props = {}, registry = /* @__PURE__ *
32346
32575
  if (!renderFn) throw new Error(`Component "${componentName}" not found in source`);
32347
32576
  const fullRegistry = new Map([...registry, ...componentMap]);
32348
32577
  const targetComp = ir.components.find((c) => c.name === componentName);
32578
+ const metadataSource = ir.metadataSource || null;
32349
32579
  const doRender = (ssrProps) => {
32350
32580
  globalThis.__vsk_ssr = true;
32351
32581
  if (!globalThis.__vsk_ssr_token) globalThis.__vsk_ssr_token = Math.random().toString(36).slice(2);
@@ -32364,9 +32594,11 @@ function renderPage(source, componentName, props = {}, registry = /* @__PURE__ *
32364
32594
  }
32365
32595
  return {
32366
32596
  body: bodyHtml2,
32367
- // The component's own scope, so head expressions that read an import
32368
- // resolve (see renderHeadHtml).
32369
- head: renderHeadHtml(targetComp, ssrProps, scopedVesk(renderFn, __vesk)),
32597
+ // A static `export const metadata` wins: it is evaluated in a sealed
32598
+ // sandbox, so it cannot depend on the component's frame resolving
32599
+ // (the failure mode that shipped an empty <title>). Whatever the
32600
+ // page's `<Head>` adds is appended, not lost.
32601
+ head: [renderStaticMetadataHtml(metadataSource), renderHeadHtml(targetComp, ssrProps, scopedVesk(renderFn, __vesk))].filter(Boolean).join("\n"),
32370
32602
  props: ssrProps
32371
32603
  };
32372
32604
  })();
@@ -32377,7 +32609,10 @@ function renderPage(source, componentName, props = {}, registry = /* @__PURE__ *
32377
32609
  } finally {
32378
32610
  delete globalThis.__vsk_ssr;
32379
32611
  }
32380
- const headHtml = targetComp ? renderHeadHtml(targetComp, ssrProps, scopedVesk(renderFn, __vesk)) : "";
32612
+ const headHtml = [
32613
+ renderStaticMetadataHtml(metadataSource),
32614
+ targetComp ? renderHeadHtml(targetComp, ssrProps, scopedVesk(renderFn, __vesk)) : ""
32615
+ ].filter(Boolean).join("\n");
32381
32616
  const pending = globalThis[`__vsk_ssr_promises_${renderToken}`];
32382
32617
  if (pending && pending.length > 0) {
32383
32618
  return (async () => {
@@ -32407,6 +32642,7 @@ function renderPage(source, componentName, props = {}, registry = /* @__PURE__ *
32407
32642
  function clearSsrCells(token) {
32408
32643
  if (!token) return;
32409
32644
  delete globalThis[`__vsk_ssr_promises_${token}`];
32645
+ delete globalThis[`__vsk_ssr_deferred_${token}`];
32410
32646
  delete globalThis[`__vsk_ssr_failures_${token}`];
32411
32647
  dropSsrSlot(token);
32412
32648
  const cells = globalThis.__vsk_ssr_cells;
@@ -32679,6 +32915,7 @@ function renderPageStream(source, componentName, props = {}, registry = /* @__PU
32679
32915
  if (!renderFn) throw new Error(`Component "${componentName}" not found in source`);
32680
32916
  resetVskState(!!options.hydrate, options.markerless !== false);
32681
32917
  const targetComp = ir.components.find((c) => c.name === componentName);
32918
+ const metadataSource = cached?.metadataSource ?? ir.metadataSource ?? null;
32682
32919
  const cssUrls = options.cssUrls || (options.cssUrl ? [options.cssUrl] : []);
32683
32920
  const cssLink = cssUrls.map((u) => ` <link rel="stylesheet" href="${u}" />
32684
32921
  `).join("");
@@ -32692,7 +32929,10 @@ function renderPageStream(source, componentName, props = {}, registry = /* @__PU
32692
32929
  }
32693
32930
  let streamHeadHtml = null;
32694
32931
  if (targetComp) {
32695
- let headHtml = renderHeadHtml(targetComp, ssrProps, scopedVesk(renderFn, __vesk));
32932
+ let headHtml = [
32933
+ renderStaticMetadataHtml(metadataSource),
32934
+ renderHeadHtml(targetComp, ssrProps, scopedVesk(renderFn, __vesk))
32935
+ ].filter(Boolean).join("\n");
32696
32936
  if (options.pageHead) {
32697
32937
  const merged = mergeHeadHtml(options.pageHead, headHtml);
32698
32938
  headHtml = merged.html;
@@ -46657,6 +46897,7 @@ function precompileFileInternal(source, sourcePath2, seenImportFiles) {
46657
46897
  setVskHydrate(false);
46658
46898
  }
46659
46899
  const topLevelCode = transformTopLevelForActions(ir.topLevelCode, "server");
46900
+ const metadataSource = ir.metadataSource || null;
46660
46901
  const runtimeImports = ir.imports.slice();
46661
46902
  const collector = { keysByAbs: /* @__PURE__ */ new Map(), modules: [] };
46662
46903
  const bindings = sourcePath2 !== void 0 ? collectModuleBundle(ir.imports, dirname6(sourcePath2), collector) : [];
@@ -46684,7 +46925,10 @@ function precompileFileInternal(source, sourcePath2, seenImportFiles) {
46684
46925
  modules: collector.modules,
46685
46926
  bindings,
46686
46927
  topLevelCode,
46687
- subFiles
46928
+ subFiles,
46929
+ // A static `export const metadata` rides along so a serverless function can
46930
+ // serialize the head without the `.vsk` source being present at all.
46931
+ ...metadataSource ? { metadataSource } : {}
46688
46932
  };
46689
46933
  }
46690
46934
 
@@ -62534,6 +62778,7 @@ __export(index_server_exports2, {
62534
62778
  custom: () => custom,
62535
62779
  defineAction: () => defineAction,
62536
62780
  defineHook: () => defineHook,
62781
+ defineMetadata: () => defineMetadata,
62537
62782
  defineRoute: () => defineRoute,
62538
62783
  derived: () => derived,
62539
62784
  destroy_block: () => destroy_block,
@@ -62561,6 +62806,8 @@ __export(index_server_exports2, {
62561
62806
  leaf: () => leaf,
62562
62807
  locals: () => locals,
62563
62808
  maxLength: () => maxLength,
62809
+ mergeMetadata: () => mergeMetadata,
62810
+ metadataToHtml: () => metadataToHtml,
62564
62811
  minLength: () => minLength,
62565
62812
  mutate: () => mutate,
62566
62813
  notFound: () => notFound,
@@ -62581,6 +62828,7 @@ __export(index_server_exports2, {
62581
62828
  required: () => required,
62582
62829
  rerenderNode: () => rerenderNode,
62583
62830
  resolveSsrResources: () => resolveSsrResources,
62831
+ resolveTitle: () => resolveTitle,
62584
62832
  resume_block: () => resume_block,
62585
62833
  revalidateComponent: () => revalidateComponent,
62586
62834
  revalidatePath: () => revalidatePath,
@@ -62642,6 +62890,7 @@ init_headless();
62642
62890
  init_primitive();
62643
62891
  init_loading_indicator();
62644
62892
  init_action();
62893
+ init_metadata();
62645
62894
 
62646
62895
  // src/index.ts
62647
62896
  var __filename2 = fileURLToPath9(import.meta.url);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/vesk-cli",
3
- "version": "0.2.50-canary.4",
3
+ "version": "0.2.50-canary.6",
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.4",
12
- "@vesk/compiler": "^0.2.50-canary.4",
13
- "@vesk/plugin-tailwind": "^0.2.50-canary.4",
14
- "@vesk/runtime": "^0.2.50-canary.4",
11
+ "@vesk/adapter": "^0.2.50-canary.6",
12
+ "@vesk/compiler": "^0.2.50-canary.6",
13
+ "@vesk/plugin-tailwind": "^0.2.50-canary.6",
14
+ "@vesk/runtime": "^0.2.50-canary.6",
15
15
  "esrap": "^2.3.0",
16
16
  "typescript": "^5.8.0",
17
17
  "ws": "^8.18.0",