@stacksjs/stx 0.2.345 → 0.2.346

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 (60) hide show
  1. package/dist/{chunk-kqzpmwx2.js → chunk-1bws4afs.js} +183 -171
  2. package/dist/{chunk-72yrrggn.js → chunk-1caep9rn.js} +1 -1
  3. package/dist/{chunk-qr3zcm87.js → chunk-1djdz98r.js} +1 -1
  4. package/dist/{chunk-nqz501eq.js → chunk-1vyz6kr8.js} +2 -2
  5. package/dist/{chunk-1t4ece3v.js → chunk-1xayahc6.js} +1 -1
  6. package/dist/{chunk-fp868yhg.js → chunk-1xts7768.js} +1 -1
  7. package/dist/{chunk-z8wb7kbj.js → chunk-21mmq3aj.js} +1 -1
  8. package/dist/{chunk-8rhjt6fh.js → chunk-3pggfwbf.js} +1 -1
  9. package/dist/{chunk-7g5vk4c3.js → chunk-5hhng72w.js} +1 -1
  10. package/dist/{chunk-rzda6bd6.js → chunk-7hjjckat.js} +1 -1
  11. package/dist/{chunk-h1vax4wg.js → chunk-7w66sc17.js} +1 -1
  12. package/dist/{chunk-jnbg3e4r.js → chunk-864m3xp2.js} +1 -1
  13. package/dist/{chunk-6wmjwbq9.js → chunk-8tghv8cf.js} +1 -1
  14. package/dist/{chunk-9qtf2b1p.js → chunk-akb6mgrb.js} +1 -1
  15. package/dist/{chunk-ybx8n794.js → chunk-b08taxsf.js} +1 -1
  16. package/dist/{chunk-1vtdege3.js → chunk-bxwanj4g.js} +1 -1
  17. package/dist/{chunk-6fwp7gee.js → chunk-byn0ptqt.js} +1 -1
  18. package/dist/{chunk-7m9qk7da.js → chunk-ddsgfmhv.js} +1 -1
  19. package/dist/{chunk-1vv9g6cj.js → chunk-dyy74sdv.js} +1 -1
  20. package/dist/{chunk-b5mnam29.js → chunk-es275g3w.js} +1 -1
  21. package/dist/{chunk-3zm4hgcf.js → chunk-fvvdq3ev.js} +1 -1
  22. package/dist/{chunk-66tgkvqw.js → chunk-fynb9e02.js} +1 -1
  23. package/dist/{chunk-77p1kjg2.js → chunk-hfvknn03.js} +1 -1
  24. package/dist/{chunk-xq0e2y4x.js → chunk-j8s9akdq.js} +1 -1
  25. package/dist/{chunk-qkdcbeaw.js → chunk-jwe0cwff.js} +1 -1
  26. package/dist/{chunk-1qyg1q6d.js → chunk-k5hv1qqy.js} +1 -1
  27. package/dist/{chunk-gvemapw4.js → chunk-k80kr2t2.js} +1 -1
  28. package/dist/{chunk-xrjx7b2v.js → chunk-km92eab7.js} +1 -1
  29. package/dist/{chunk-zwr4bn6a.js → chunk-maq5jag2.js} +1 -1
  30. package/dist/{chunk-yca761bm.js → chunk-p04rck27.js} +1 -1
  31. package/dist/{chunk-c4tf1vpy.js → chunk-pc8np1bb.js} +1 -1
  32. package/dist/{chunk-mr8ccsnm.js → chunk-q45fva8h.js} +1 -1
  33. package/dist/{chunk-ek2m0kkw.js → chunk-qp7sk0ex.js} +1 -1
  34. package/dist/{chunk-aapqf6bj.js → chunk-rf2cejt3.js} +1 -1
  35. package/dist/{chunk-vhg91hnw.js → chunk-rwk5hwvk.js} +1 -1
  36. package/dist/{chunk-cypg8qwn.js → chunk-s11e8aq9.js} +1 -1
  37. package/dist/{chunk-zmazqcb8.js → chunk-s3jyec9k.js} +1 -1
  38. package/dist/{chunk-r38xq7fp.js → chunk-skd72bn4.js} +2 -2
  39. package/dist/{chunk-nrt99ptw.js → chunk-t2py7vc3.js} +1 -1
  40. package/dist/{chunk-2fhk4e68.js → chunk-t83m2pkm.js} +1 -1
  41. package/dist/{chunk-223makqc.js → chunk-tnm0nez5.js} +1 -1
  42. package/dist/{chunk-pajk5680.js → chunk-vw83y4we.js} +2 -2
  43. package/dist/{chunk-c8e2deyp.js → chunk-vzbcdxd5.js} +1 -1
  44. package/dist/{chunk-57t402mn.js → chunk-washyj03.js} +1 -1
  45. package/dist/{chunk-e7gs18rc.js → chunk-wbp4vbm0.js} +1 -1
  46. package/dist/{chunk-esjcyxa9.js → chunk-xytgvfbf.js} +2 -2
  47. package/dist/{chunk-4spaszfn.js → chunk-zdq7emrd.js} +322 -322
  48. package/dist/{chunk-eqzc88et.js → chunk-zz2yxsf9.js} +1 -1
  49. package/dist/cli.js +7 -7
  50. package/dist/component-library.d.ts +0 -31
  51. package/dist/component-library.js +279 -17
  52. package/dist/craft-entry.js +1 -1
  53. package/dist/craft.js +1 -1
  54. package/dist/process.js +25 -3
  55. package/dist/pwa.js +1 -1
  56. package/dist/ssg.js +2 -2
  57. package/dist/theme-tokens.js +9 -5
  58. package/dist/variable-extractor.d.ts +31 -0
  59. package/dist/variable-extractor.js +9 -5
  60. package/package.json +5 -5
package/dist/process.js CHANGED
@@ -641,23 +641,45 @@ function scriptSourceOf(attrs) {
641
641
  const match = new RegExp(`${SCRIPT_SOURCE_ATTR}="([^"]*)"`).exec(attrs);
642
642
  return match ? decodeURIComponent(match[1]) : void 0;
643
643
  }
644
+ function escapeForBoundary(value) {
645
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
646
+ }
647
+ function serverScriptErrorBoundary(sourcePath, kind, message) {
648
+ return `<div data-stx-server-script-error role="alert" style="padding:12px 14px;border:1px solid #f0b4b4;border-left-width:4px;background:#fff5f5;color:#7a1f1f;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace"><strong style="display:block;margin-bottom:4px">stx: a &lt;script server&gt; ${kind === "module-resolution" ? "imports a module that does not resolve" : kind === "syntax" ? "does not parse" : "names something that does not exist"}, so this component rendered nothing.</strong><span style="display:block;opacity:.85">${escapeForBoundary(sourcePath)}</span><span style="display:block;margin-top:4px">${escapeForBoundary(message)}</span></div>`;
649
+ }
644
650
  async function extractServerScriptVariables(output, context, filePath) {
645
651
  const scriptRegex = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
646
652
  let scriptMatch;
653
+ const boundaries = [], showBoundaries = !isProduction() && !isTest();
647
654
  while ((scriptMatch = scriptRegex.exec(output)) !== null) {
648
655
  const attrs = scriptMatch[1], scriptContent = scriptMatch[2];
649
656
  if (!/\bserver\b/.test(attrs) || !scriptContent.trim())
650
657
  continue;
651
- const sourcePath = scriptSourceOf(attrs) ?? filePath;
658
+ const sourcePath = scriptSourceOf(attrs) ?? filePath, at = { index: scriptMatch.index, length: scriptMatch[0].length };
652
659
  try {
653
660
  const { extractVariables } = await importOnce("stx/variable-extractor", () => import("./variable-extractor.js"));
654
- await extractVariables(scriptContent, context, sourcePath, { preserveExisting: !0 });
661
+ await extractVariables(scriptContent, context, sourcePath, {
662
+ preserveExisting: !0,
663
+ onFailure: (failure) => {
664
+ if (!showBoundaries || failure.kind === "unknown")
665
+ return;
666
+ boundaries.push({ ...at, markup: serverScriptErrorBoundary(sourcePath, failure.kind, failure.message) });
667
+ }
668
+ });
655
669
  } catch (e) {
656
670
  const err = e instanceof Error ? e : Error(String(e));
657
671
  errorLogger.log(err, { filePath: sourcePath, phase: "server-script-extraction" }, "warning");
658
672
  console.warn(`[stx] server <script> extraction failed in ${sourcePath}: ${err.message}`);
673
+ if (showBoundaries)
674
+ boundaries.push({ ...at, markup: serverScriptErrorBoundary(sourcePath, "unknown", err.message) });
659
675
  }
660
676
  }
677
+ if (boundaries.length === 0)
678
+ return output;
679
+ let result = output;
680
+ for (const boundary of boundaries.sort((a, b) => b.index - a.index))
681
+ result = result.slice(0, boundary.index) + boundary.markup + result.slice(boundary.index + boundary.length);
682
+ return result;
661
683
  }
662
684
  async function interpolateClientScriptExpressions(output, context, filePath) {
663
685
  try {
@@ -673,7 +695,7 @@ async function interpolateClientScriptExpressions(output, context, filePath) {
673
695
  async function processOtherDirectives(template, context, filePath, options, dependencies) {
674
696
  let output = template;
675
697
  const opts = options;
676
- await extractServerScriptVariables(output, context, filePath);
698
+ output = await extractServerScriptVariables(output, context, filePath);
677
699
  output = await interpolateClientScriptExpressions(output, context, filePath);
678
700
  output = await processJsDirectives(output, context, filePath);
679
701
  output = await processTsDirectives(output, context, filePath);
package/dist/pwa.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  import{Fk as wq,Gk as dq,Hk as Cq,Ik as mq,Jk as gq}from"./chunk-wvc7t11n.js";import{Kk as S,Lk as Tq,Mk as _q,Nk as z,Ok as D,Pk as P,Qk as kq,Rk as vq,Sk as w,Tk as Iq,Uk as d,Vk as Hq,Wk as Oq,Xk as Mq}from"./chunk-c30qnb6z.js";import{Ew as Aq,Fw as bq,Gw as Sq,Hw as zq,Iw as Dq,Jw as Pq}from"./chunk-9nrgjtah.js";import{Nw as N}from"./chunk-ejqpq0wc.js";import p from"fs";import E from"path";import C from"fs";import L from"path";var k=[72,96,128,144,152,192,384,512],v=[120,152,167,180],I=[16,32];async function H(G,B){let q={success:!0,generatedFiles:[],errors:[],warnings:[]},K=G.pwa?.icons;if(!K?.src)return q.errors.push("No source icon specified in pwa.icons.src"),q.success=!1,q;let Y=L.isAbsolute(K.src)?K.src:L.resolve(process.cwd(),K.src);if(!await Bun.file(Y).exists())return q.errors.push(`Source icon not found: ${Y}`),q.success=!1,q;let Q=L.resolve(B,K.outputDir||"pwa-icons");try{C.mkdirSync(Q,{recursive:!0})}catch{return q.errors.push(`Failed to create output directory: ${Q}`),q.success=!1,q}let X=K.sizes||k,j=K.generateWebP??!0,J=K.generateAppleIcons??!0;try{let y;try{y=await import("sharp")}catch{return q.errors.push(`sharp is not installed. Install it with: bun add sharp
3
- Icon generation requires the sharp package for image processing.`),q.success=!1,q}let R=await y.default(Y).metadata();if(R.width&&R.width<512)q.warnings.push(`Source icon is ${R.width}x${R.height}. Recommend using at least 512x512 for best quality.`);for(let $ of X){let x=L.join(Q,`icon-${$}x${$}.png`);if(await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x),j){let F=L.join(Q,`icon-${$}x${$}.webp`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(F),q.generatedFiles.push(F)}}if(J){for(let x of v){let F=L.join(Q,`apple-touch-icon-${x}x${x}.png`);await y.default(Y).resize(x,x,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(F),q.generatedFiles.push(F)}let $=L.join(Q,"apple-touch-icon.png");await y.default(Y).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile($),q.generatedFiles.push($)}for(let $ of I){let x=L.join(Q,`favicon-${$}x${$}.png`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x)}let U=512,T=L.join(Q,`icon-maskable-${U}x${U}.png`),Z=Math.floor(U*0.1),_=U-Z*2;await y.default(Y).resize(_,_,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:Z,bottom:Z,left:Z,right:Z,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(T),q.generatedFiles.push(T)}catch(y){let V=y instanceof Error?y.message:String(y);q.errors.push(`Icon generation failed: ${V}`),q.success=!1}return q}function n(G){let B=G.sizes||k,q=G.outputDir?`/${G.outputDir}`:"/pwa-icons",K=G.generateWebP??!0,Y=G.generateAppleIcons??!0,Q=[];for(let X of B)if(Q.push(`${q}/icon-${X}x${X}.png`),K)Q.push(`${q}/icon-${X}x${X}.webp`);if(Y){Q.push(`${q}/apple-touch-icon.png`);for(let X of v)Q.push(`${q}/apple-touch-icon-${X}x${X}.png`)}for(let X of I)Q.push(`${q}/favicon-${X}x${X}.png`);return Q.push(`${q}/icon-maskable-512x512.png`),Q}async function O(){try{return await import("sharp"),!0}catch{return!1}}function m(G,B,q,K){let Y=[],Q=K.join(" ");for(let X of G)if(Y.push({src:`${B}/icon-${X}x${X}.png`,sizes:`${X}x${X}`,type:"image/png",purpose:Q}),q)Y.push({src:`${B}/icon-${X}x${X}.webp`,sizes:`${X}x${X}`,type:"image/webp",purpose:Q});return Y}function g(G){return G.map((B)=>({name:B.name,short_name:B.shortName,description:B.description,url:B.url,icons:B.icons?.map((q)=>({src:q.src,sizes:q.sizes,type:q.type}))}))}function h(G){let B=G.pwa?.shareTarget;if(!B?.enabled)return;let q={action:B.action||"/share",method:B.method||"POST",enctype:B.enctype||"multipart/form-data",params:{title:B.params?.title||"title",text:B.params?.text||"text",url:B.params?.url||"url"}};if(B.acceptFiles&&B.acceptFiles.length>0)q.params.files=B.acceptFiles.map((K)=>({name:K.name,accept:K.accept}));return q}function c(G){let B=G.pwa?.fileHandlers;if(!B?.enabled||!B.accept)return;let q=[{action:B.action||"/",accept:B.accept,launch_type:B.launchType||"single-client"}];if(B.icons)q[0].icons=B.icons.map((K)=>({src:K.src,sizes:K.sizes,type:K.type}));return q}function l(G){let B=G.pwa?.protocolHandlers;if(!B||B.length===0)return;return B.map((q)=>({protocol:q.protocol,url:q.url}))}function u(G){let B=G.pwa;if(!B?.enabled||!B.manifest)return null;let{manifest:q,icons:K}=B,Y=K?.sizes||[72,96,128,144,152,192,384,512],Q=K?.outputDir?`/${K.outputDir}`:"/pwa-icons",X=K?.generateWebP??!0,j=K?.purpose||["any","maskable"],J={name:q.name,short_name:q.shortName||q.name,description:q.description,start_url:q.startUrl||"/",display:q.display||"standalone",display_override:q.displayOverride,orientation:q.orientation,theme_color:q.themeColor,background_color:q.backgroundColor,scope:q.scope||"/",lang:q.lang,dir:q.dir,id:q.id,categories:q.categories,icons:m(Y,Q,X,j)};if(q.shortcuts&&q.shortcuts.length>0)J.shortcuts=g(q.shortcuts);if(q.screenshots&&q.screenshots.length>0)J.screenshots=q.screenshots.map((U)=>({src:U.src,sizes:U.sizes,type:U.type,label:U.label,form_factor:U.platform}));let y=h(G);if(y)J.share_target=y;let V=c(G);if(V)J.file_handlers=V;let R=l(G);if(R)J.protocol_handlers=R;if(q.launchHandler)J.launch_handler={client_mode:q.launchHandler};if(q.handleLinks)J.handle_links=q.handleLinks;if(q.edgeSidePanel?.enabled)J.edge_side_panel={preferred_width:q.edgeSidePanel.preferredWidth};return J}function M(G){let B=u(G);if(!B)return"";let q=JSON.parse(JSON.stringify(B));return JSON.stringify(q,null,2)}function i(G,B){return{...B,...G,shortcuts:G.shortcuts||B.shortcuts,screenshots:G.screenshots||B.screenshots,categories:G.categories||B.categories}}function s(G){let B=[],q=G.pwa;if(!q?.enabled)return B;let K=q.manifest;if(!K)return B.push("PWA manifest configuration is missing"),B;if(!K.name)B.push("Manifest name is required");let Y=["fullscreen","standalone","minimal-ui","browser"];if(K.display&&!Y.includes(K.display))B.push(`Invalid display mode: ${K.display}. Must be one of: ${Y.join(", ")}`);let Q=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(K.orientation&&!Q.includes(K.orientation))B.push(`Invalid orientation: ${K.orientation}`);let X=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(K.themeColor&&!X.test(K.themeColor))B.push(`Invalid theme color: ${K.themeColor}. Must be a valid hex color.`);if(K.backgroundColor&&!X.test(K.backgroundColor))B.push(`Invalid background color: ${K.backgroundColor}. Must be a valid hex color.`);if(q.shareTarget?.enabled){if(!q.shareTarget.action)B.push("Share target action URL is required")}if(q.fileHandlers?.enabled){if(!q.fileHandlers.accept||Object.keys(q.fileHandlers.accept).length===0)B.push("File handlers must specify accepted MIME types")}if(q.protocolHandlers)for(let j of q.protocolHandlers){if(!j.protocol)B.push("Protocol handler missing protocol");if(!j.url||!j.url.includes("%s"))B.push(`Protocol handler URL must contain %s placeholder: ${j.protocol}`)}return B}import A from"path";async function b(G){let B=G.pwa?.offline;if(!B?.enabled)return"";if(B.page){let q=A.isAbsolute(B.page)?B.page:A.resolve(process.cwd(),B.page);if(await Bun.file(q).exists())try{let{processDirectives:K}=await import("./chunk-2fhk4e68.js"),Y=await Bun.file(q).text();return await K(Y,{},q,G,new Set)}catch(K){console.warn(`[PWA] Failed to process custom offline page: ${K}`)}else console.warn(`[PWA] Custom offline page not found: ${q}`)}return f(G)}function f(G){let B=G.pwa?.offline,q=G.pwa?.manifest,K=B?.fallbackTitle||"You are offline",Y=B?.fallbackMessage||"Please check your internet connection and try again.",Q=q?.themeColor||"#4f46e5",X=q?.shortName||q?.name||"App";return`<!DOCTYPE html>
3
+ Icon generation requires the sharp package for image processing.`),q.success=!1,q}let R=await y.default(Y).metadata();if(R.width&&R.width<512)q.warnings.push(`Source icon is ${R.width}x${R.height}. Recommend using at least 512x512 for best quality.`);for(let $ of X){let x=L.join(Q,`icon-${$}x${$}.png`);if(await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x),j){let F=L.join(Q,`icon-${$}x${$}.webp`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(F),q.generatedFiles.push(F)}}if(J){for(let x of v){let F=L.join(Q,`apple-touch-icon-${x}x${x}.png`);await y.default(Y).resize(x,x,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(F),q.generatedFiles.push(F)}let $=L.join(Q,"apple-touch-icon.png");await y.default(Y).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile($),q.generatedFiles.push($)}for(let $ of I){let x=L.join(Q,`favicon-${$}x${$}.png`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x)}let U=512,T=L.join(Q,`icon-maskable-${U}x${U}.png`),Z=Math.floor(U*0.1),_=U-Z*2;await y.default(Y).resize(_,_,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:Z,bottom:Z,left:Z,right:Z,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(T),q.generatedFiles.push(T)}catch(y){let V=y instanceof Error?y.message:String(y);q.errors.push(`Icon generation failed: ${V}`),q.success=!1}return q}function n(G){let B=G.sizes||k,q=G.outputDir?`/${G.outputDir}`:"/pwa-icons",K=G.generateWebP??!0,Y=G.generateAppleIcons??!0,Q=[];for(let X of B)if(Q.push(`${q}/icon-${X}x${X}.png`),K)Q.push(`${q}/icon-${X}x${X}.webp`);if(Y){Q.push(`${q}/apple-touch-icon.png`);for(let X of v)Q.push(`${q}/apple-touch-icon-${X}x${X}.png`)}for(let X of I)Q.push(`${q}/favicon-${X}x${X}.png`);return Q.push(`${q}/icon-maskable-512x512.png`),Q}async function O(){try{return await import("sharp"),!0}catch{return!1}}function m(G,B,q,K){let Y=[],Q=K.join(" ");for(let X of G)if(Y.push({src:`${B}/icon-${X}x${X}.png`,sizes:`${X}x${X}`,type:"image/png",purpose:Q}),q)Y.push({src:`${B}/icon-${X}x${X}.webp`,sizes:`${X}x${X}`,type:"image/webp",purpose:Q});return Y}function g(G){return G.map((B)=>({name:B.name,short_name:B.shortName,description:B.description,url:B.url,icons:B.icons?.map((q)=>({src:q.src,sizes:q.sizes,type:q.type}))}))}function h(G){let B=G.pwa?.shareTarget;if(!B?.enabled)return;let q={action:B.action||"/share",method:B.method||"POST",enctype:B.enctype||"multipart/form-data",params:{title:B.params?.title||"title",text:B.params?.text||"text",url:B.params?.url||"url"}};if(B.acceptFiles&&B.acceptFiles.length>0)q.params.files=B.acceptFiles.map((K)=>({name:K.name,accept:K.accept}));return q}function c(G){let B=G.pwa?.fileHandlers;if(!B?.enabled||!B.accept)return;let q=[{action:B.action||"/",accept:B.accept,launch_type:B.launchType||"single-client"}];if(B.icons)q[0].icons=B.icons.map((K)=>({src:K.src,sizes:K.sizes,type:K.type}));return q}function l(G){let B=G.pwa?.protocolHandlers;if(!B||B.length===0)return;return B.map((q)=>({protocol:q.protocol,url:q.url}))}function u(G){let B=G.pwa;if(!B?.enabled||!B.manifest)return null;let{manifest:q,icons:K}=B,Y=K?.sizes||[72,96,128,144,152,192,384,512],Q=K?.outputDir?`/${K.outputDir}`:"/pwa-icons",X=K?.generateWebP??!0,j=K?.purpose||["any","maskable"],J={name:q.name,short_name:q.shortName||q.name,description:q.description,start_url:q.startUrl||"/",display:q.display||"standalone",display_override:q.displayOverride,orientation:q.orientation,theme_color:q.themeColor,background_color:q.backgroundColor,scope:q.scope||"/",lang:q.lang,dir:q.dir,id:q.id,categories:q.categories,icons:m(Y,Q,X,j)};if(q.shortcuts&&q.shortcuts.length>0)J.shortcuts=g(q.shortcuts);if(q.screenshots&&q.screenshots.length>0)J.screenshots=q.screenshots.map((U)=>({src:U.src,sizes:U.sizes,type:U.type,label:U.label,form_factor:U.platform}));let y=h(G);if(y)J.share_target=y;let V=c(G);if(V)J.file_handlers=V;let R=l(G);if(R)J.protocol_handlers=R;if(q.launchHandler)J.launch_handler={client_mode:q.launchHandler};if(q.handleLinks)J.handle_links=q.handleLinks;if(q.edgeSidePanel?.enabled)J.edge_side_panel={preferred_width:q.edgeSidePanel.preferredWidth};return J}function M(G){let B=u(G);if(!B)return"";let q=JSON.parse(JSON.stringify(B));return JSON.stringify(q,null,2)}function i(G,B){return{...B,...G,shortcuts:G.shortcuts||B.shortcuts,screenshots:G.screenshots||B.screenshots,categories:G.categories||B.categories}}function s(G){let B=[],q=G.pwa;if(!q?.enabled)return B;let K=q.manifest;if(!K)return B.push("PWA manifest configuration is missing"),B;if(!K.name)B.push("Manifest name is required");let Y=["fullscreen","standalone","minimal-ui","browser"];if(K.display&&!Y.includes(K.display))B.push(`Invalid display mode: ${K.display}. Must be one of: ${Y.join(", ")}`);let Q=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(K.orientation&&!Q.includes(K.orientation))B.push(`Invalid orientation: ${K.orientation}`);let X=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(K.themeColor&&!X.test(K.themeColor))B.push(`Invalid theme color: ${K.themeColor}. Must be a valid hex color.`);if(K.backgroundColor&&!X.test(K.backgroundColor))B.push(`Invalid background color: ${K.backgroundColor}. Must be a valid hex color.`);if(q.shareTarget?.enabled){if(!q.shareTarget.action)B.push("Share target action URL is required")}if(q.fileHandlers?.enabled){if(!q.fileHandlers.accept||Object.keys(q.fileHandlers.accept).length===0)B.push("File handlers must specify accepted MIME types")}if(q.protocolHandlers)for(let j of q.protocolHandlers){if(!j.protocol)B.push("Protocol handler missing protocol");if(!j.url||!j.url.includes("%s"))B.push(`Protocol handler URL must contain %s placeholder: ${j.protocol}`)}return B}import A from"path";async function b(G){let B=G.pwa?.offline;if(!B?.enabled)return"";if(B.page){let q=A.isAbsolute(B.page)?B.page:A.resolve(process.cwd(),B.page);if(await Bun.file(q).exists())try{let{processDirectives:K}=await import("./chunk-t83m2pkm.js"),Y=await Bun.file(q).text();return await K(Y,{},q,G,new Set)}catch(K){console.warn(`[PWA] Failed to process custom offline page: ${K}`)}else console.warn(`[PWA] Custom offline page not found: ${q}`)}return f(G)}function f(G){let B=G.pwa?.offline,q=G.pwa?.manifest,K=B?.fallbackTitle||"You are offline",Y=B?.fallbackMessage||"Please check your internet connection and try again.",Q=q?.themeColor||"#4f46e5",X=q?.shortName||q?.name||"App";return`<!DOCTYPE html>
4
4
  <html lang="en">
5
5
  <head>
6
6
  <meta charset="UTF-8">
package/dist/ssg.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{Bk as Fq,wk as Uq,xk as Iq}from"./chunk-v7aa7v85.js";import{Ck as Eq,Dk as Tq,Ek as Dq}from"./chunk-c0n802j1.js";import{Zk as _q,al as zq,bl as Aq}from"./chunk-223makqc.js";import"./chunk-77p1kjg2.js";import"./chunk-fvsefztj.js";import{Jp as P,Sm as Oq,io as l,lo as Hq,sr as n}from"./chunk-4spaszfn.js";import"./chunk-8y1ve8tc.js";import"./chunk-njx93b4z.js";import"./chunk-bqdfbwdf.js";import"./chunk-89mqnh67.js";import"./chunk-xvh1k1a4.js";import{it as Xq}from"./chunk-r38xq7fp.js";import{nt as d}from"./chunk-y2f41kaq.js";import"./chunk-xj6bcwqa.js";import"./chunk-z8wb7kbj.js";import"./chunk-vhta1be7.js";import{Ut as Bq}from"./chunk-tc4pj651.js";import"./chunk-san1eq0r.js";import"./chunk-avwywzsj.js";import"./chunk-wj21f1e0.js";import"./chunk-d86q27j8.js";import"./chunk-72x62kch.js";import{rw as Yq,sw as Vq,tw as jq,uw as Gq,vw as Lq,ww as Nq}from"./chunk-yg5r7bnm.js";import"./chunk-9nrgjtah.js";import{Nw as y}from"./chunk-ejqpq0wc.js";import O from"fs";import j from"path";import{createHash as xq}from"crypto";function yq(q){try{return new Bun.Transpiler({loader:"js",minifyWhitespace:!0}).transformSync(q).replace(/\}(var |let |const |function )/g,"};$1").trim()}catch{return q}}var Pq=/<script\s+type="stx\/island"\s+data-stx-island="([^"]+)"([^>]*)>([\s\S]*?)<\/script>/g;function Cq(q){return Bun.hash(q).toString(16)}function Qq(q,Z={}){if(!q.includes('type="stx/island"'))return{html:q,chunks:[]};let $=new Map,Q=q.replace(Pq,(J,W,z,A)=>{let G=A.trim();if(!G)return J;if(/\bdata-stx-src=/.test(z))return J;if(Z.minify)G=yq(G);let X=Cq(G);if(!$.has(X))$.set(X,G);let B=Z.integrity?` data-stx-integrity="sha384-${xq("sha384").update(G).digest("base64")}"`:"";return`<script type="stx/island" data-stx-island="${W}" data-stx-src="/_stx/islands/${X}.js"${B}${z}></script>`}),K=Array.from($,([J,W])=>({hash:J,code:W}));return{html:Q,chunks:K}}var gq=new Set(["visible","idle"]);function Zq(q){if(!q.includes("data-stx-src="))return q;let Z=new Map,$=/data-stx-scope="([^"]+)"[^>]*?stx-hydrate="([^"]+)"/g,Q;while((Q=$.exec(q))!==null)Z.set(Q[1],Q[2]);let K=new Set,J=/data-stx-island="([^"]+)"[^>]*?data-stx-src="([^"]+)"/g,W;while((W=J.exec(q))!==null)if(gq.has(Z.get(W[1])||""))K.add(W[2]);let z=q.lastIndexOf("</head>");if(K.size===0||z===-1)return q;let A=Array.from(K).filter((G)=>!q.includes(`rel="prefetch" href="${G}"`)).map((G)=>`<link rel="prefetch" href="${G}" as="script">`).join("");if(!A)return q;return q.slice(0,z)+A+q.slice(z)}var fq=["STX_SITE_URL","SITE_URL","URL","VERCEL_URL","CF_PAGES_URL"];function h(q){let Z=q.trim();if(!Z)return null;let $=/^https?:\/\//i.test(Z)?Z:`https://${Z}`;try{return new URL($).origin+new URL($).pathname.replace(/\/$/,"")}catch{return null}}function mq(q){for(let Z of fq){let $=q[Z];if(!$)continue;let Q=h($);if(Q)return{url:Q,source:"env",via:Z}}return null}function $q(q){if(!q||typeof q!=="object")return null;let Z=q,$=Z.site?.url??Z.url??Z.app?.url;return typeof $==="string"?h($):null}async function dq(q){let{existsSync:Z}=await import("fs"),$=await import("path");for(let Q of["site.config.ts","site.config.js",".config/site.config.ts"]){let K=$.resolve(q,Q);if(!Z(K))continue;try{let J=await import(K),W=$q(J.default??J);if(W)return W}catch{}}return null}async function Kq(q={}){let Z=q.cwd??process.cwd(),$=q.env??process.env;if(q.explicit){let W=h(q.explicit);if(W)return{url:W,source:"option"}}let Q=$q(q.stxConfig);if(Q)return{url:Q,source:"stx.config",via:"site.url"};let K=await dq(Z);if(K)return{url:K,source:"site.config",via:"url"};let J=mq($);if(J)return J;return{url:"http://localhost",source:"fallback"}}function Wq(){return["No site URL configured \u2014 sitemap.xml and robots.txt will point at http://localhost."," Set one in stx.config.ts (site: { url: 'https://example.com' }), in site.config.ts,"," via --domain, or with SITE_URL in the build environment."].join(`
2
+ import{Bk as Fq,wk as Uq,xk as Iq}from"./chunk-v7aa7v85.js";import{Ck as Eq,Dk as Tq,Ek as Dq}from"./chunk-c0n802j1.js";import{Zk as _q,al as zq,bl as Aq}from"./chunk-tnm0nez5.js";import"./chunk-hfvknn03.js";import"./chunk-fvsefztj.js";import{Jp as P,Sm as Oq,io as l,lo as Hq,sr as n}from"./chunk-zdq7emrd.js";import"./chunk-8y1ve8tc.js";import"./chunk-njx93b4z.js";import"./chunk-bqdfbwdf.js";import"./chunk-89mqnh67.js";import"./chunk-xvh1k1a4.js";import{it as Xq}from"./chunk-skd72bn4.js";import{nt as d}from"./chunk-y2f41kaq.js";import"./chunk-xj6bcwqa.js";import"./chunk-21mmq3aj.js";import"./chunk-vhta1be7.js";import{Ut as Bq}from"./chunk-tc4pj651.js";import"./chunk-san1eq0r.js";import"./chunk-avwywzsj.js";import"./chunk-wj21f1e0.js";import"./chunk-d86q27j8.js";import"./chunk-72x62kch.js";import{rw as Yq,sw as Vq,tw as jq,uw as Gq,vw as Lq,ww as Nq}from"./chunk-yg5r7bnm.js";import"./chunk-9nrgjtah.js";import{Nw as y}from"./chunk-ejqpq0wc.js";import O from"fs";import j from"path";import{createHash as xq}from"crypto";function yq(q){try{return new Bun.Transpiler({loader:"js",minifyWhitespace:!0}).transformSync(q).replace(/\}(var |let |const |function )/g,"};$1").trim()}catch{return q}}var Pq=/<script\s+type="stx\/island"\s+data-stx-island="([^"]+)"([^>]*)>([\s\S]*?)<\/script>/g;function Cq(q){return Bun.hash(q).toString(16)}function Qq(q,Z={}){if(!q.includes('type="stx/island"'))return{html:q,chunks:[]};let $=new Map,Q=q.replace(Pq,(J,W,z,A)=>{let G=A.trim();if(!G)return J;if(/\bdata-stx-src=/.test(z))return J;if(Z.minify)G=yq(G);let X=Cq(G);if(!$.has(X))$.set(X,G);let B=Z.integrity?` data-stx-integrity="sha384-${xq("sha384").update(G).digest("base64")}"`:"";return`<script type="stx/island" data-stx-island="${W}" data-stx-src="/_stx/islands/${X}.js"${B}${z}></script>`}),K=Array.from($,([J,W])=>({hash:J,code:W}));return{html:Q,chunks:K}}var gq=new Set(["visible","idle"]);function Zq(q){if(!q.includes("data-stx-src="))return q;let Z=new Map,$=/data-stx-scope="([^"]+)"[^>]*?stx-hydrate="([^"]+)"/g,Q;while((Q=$.exec(q))!==null)Z.set(Q[1],Q[2]);let K=new Set,J=/data-stx-island="([^"]+)"[^>]*?data-stx-src="([^"]+)"/g,W;while((W=J.exec(q))!==null)if(gq.has(Z.get(W[1])||""))K.add(W[2]);let z=q.lastIndexOf("</head>");if(K.size===0||z===-1)return q;let A=Array.from(K).filter((G)=>!q.includes(`rel="prefetch" href="${G}"`)).map((G)=>`<link rel="prefetch" href="${G}" as="script">`).join("");if(!A)return q;return q.slice(0,z)+A+q.slice(z)}var fq=["STX_SITE_URL","SITE_URL","URL","VERCEL_URL","CF_PAGES_URL"];function h(q){let Z=q.trim();if(!Z)return null;let $=/^https?:\/\//i.test(Z)?Z:`https://${Z}`;try{return new URL($).origin+new URL($).pathname.replace(/\/$/,"")}catch{return null}}function mq(q){for(let Z of fq){let $=q[Z];if(!$)continue;let Q=h($);if(Q)return{url:Q,source:"env",via:Z}}return null}function $q(q){if(!q||typeof q!=="object")return null;let Z=q,$=Z.site?.url??Z.url??Z.app?.url;return typeof $==="string"?h($):null}async function dq(q){let{existsSync:Z}=await import("fs"),$=await import("path");for(let Q of["site.config.ts","site.config.js",".config/site.config.ts"]){let K=$.resolve(q,Q);if(!Z(K))continue;try{let J=await import(K),W=$q(J.default??J);if(W)return W}catch{}}return null}async function Kq(q={}){let Z=q.cwd??process.cwd(),$=q.env??process.env;if(q.explicit){let W=h(q.explicit);if(W)return{url:W,source:"option"}}let Q=$q(q.stxConfig);if(Q)return{url:Q,source:"stx.config",via:"site.url"};let K=await dq(Z);if(K)return{url:K,source:"site.config",via:"url"};let J=mq($);if(J)return J;return{url:"http://localhost",source:"fallback"}}function Wq(){return["No site URL configured \u2014 sitemap.xml and robots.txt will point at http://localhost."," Set one in stx.config.ts (site: { url: 'https://example.com' }), in site.config.ts,"," via --domain, or with SITE_URL in the build environment."].join(`
3
3
  `)}class wq{cacheDir;cache=new Map;loaded=!1;salt;constructor(q,Z=""){this.cacheDir=q,this.salt=Z}async load(){if(this.loaded)return;let q=j.join(this.cacheDir,"build-cache.json");if(await Bun.file(q).exists())try{let Z=JSON.parse(await Bun.file(q).text());for(let[$,Q]of Object.entries(Z))this.cache.set($,Q)}catch{}this.loaded=!0}async save(){await O.promises.mkdir(this.cacheDir,{recursive:!0});let q=j.join(this.cacheDir,"build-cache.json"),Z={};for(let[$,Q]of this.cache)Z[$]=Q;await Bun.write(q,JSON.stringify(Z))}getHash(q,Z){let $=O.statSync(q),Q=`${this.salt}|${q}:${$.mtimeMs}`;for(let J of Z)if(O.existsSync(J)){let W=O.statSync(J);Q+=`:${J}:${W.mtimeMs}`}let K=0;for(let J=0;J<Q.length;J++){let W=Q.charCodeAt(J);K=(K<<5)-K+W,K=K&K}return Math.abs(K).toString(36)}get(q,Z){let $=this.cache.get(q);if(!$)return null;let Q=this.getHash(Z,$.dependencies??[]);if($.hash!==Q)return this.cache.delete(q),null;return $.html}set(q,Z,$,Q){let K=this.getHash(Z,$);this.cache.set(q,{hash:K,html:Q,generatedAt:Date.now(),dependencies:$})}}class Rq{cacheDir;constructor(q){this.cacheDir=q}getFilePath(q){let Z=q.replace(/[^a-zA-Z0-9]/g,"_")+".json";return j.join(this.cacheDir,"isr",Z)}async get(q){let Z=this.getFilePath(q);if(!await Bun.file(Z).exists())return null;try{return JSON.parse(await Bun.file(Z).text())}catch{return null}}async set(q,Z){let $=this.getFilePath(q);await O.promises.mkdir(j.dirname($),{recursive:!0}),await Bun.write($,JSON.stringify(Z))}async invalidate(q){let Z=this.getFilePath(q);if(await Bun.file(Z).exists())await O.promises.unlink(Z)}async invalidatePattern(q){let Z=j.join(this.cacheDir,"isr");if(!O.existsSync(Z))return;let $=await O.promises.readdir(Z);for(let Q of $){let K=Q.replace(/_/g,"/").replace(".json","");if(q.test(K))await O.promises.unlink(j.join(Z,Q))}}async needsRevalidation(q){let Z=await this.get(q);if(!Z)return!0;return Date.now()>Z.revalidateAfter}}async function pq(q){try{let $=(await Bun.file(q).text()).match(/<script\s+server\b[^>]*>([\s\S]*?)<\/script>/i);if(!$)return null;let Q=$[1];if(!Q.includes("getStaticPaths"))return null;let K=Q.match(/(?:export\s+)?(?:async\s+)?function\s+getStaticPaths\s*\([^)]*\)\s*\{([\s\S]*?)\n[\t ]*\}/);if(!K)return null;return await Function(`
4
4
  return (async function getStaticPaths() {
5
5
  ${K[1]}
@@ -41,7 +41,7 @@ ${q.map((Q)=>{let K=new URL(Q.loc,Z).href,J=` <url>
41
41
  ${$.join(`
42
42
  `)}
43
43
  </channel>
44
- </rss>`}async function aq(q={}){let Z=Date.now();Aq();let $=await n(process.cwd()),Q=$.build||{},K=await Kq({explicit:q.domain||Q.domain,stxConfig:$});if(K.source==="fallback"&&(q.sitemap??Q.sitemap??!0))console.warn(Wq());let J={router:q.router??$?.router??{},pagesDir:q.pagesDir||Q.pagesDir||"pages",outputDir:q.outputDir||Q.outputDir||"dist",baseUrl:q.baseUrl||Q.baseUrl||"/",domain:K.url,revalidate:q.revalidate??Q.revalidate??!1,sitemap:q.sitemap??Q.sitemap??!0,sitemapExclude:q.sitemapExclude||Q.sitemapExclude||[],robots:q.robots??Q.robots??!0,rss:q.rss??Q.rss??!1,concurrency:q.concurrency||Q.concurrency||10,cache:q.cache??Q.cache??!0,cacheDir:q.cacheDir||Q.cacheDir||d(process.cwd(),"ssg-cache"),contentLoaders:q.contentLoaders||[],hooks:q.hooks||{},minify:q.minify??Q.minify??!0,generate404:q.generate404??Q.generate404??!0,publicDir:q.publicDir||Q.publicDir||"public",trailingSlash:q.trailingSlash??Q.trailingSlash??!1,cleanOutput:q.cleanOutput??Q.cleanOutput??!0,cacheSalt:q.cacheSalt??"",partialsDir:q.partialsDir||$?.partialsDir||"",componentsDir:q.componentsDir||$?.componentsDir||"",failOnIncludeError:q.failOnIncludeError??!0,chunkIslands:q.chunkIslands===!0,prefetchIslands:q.prefetchIslands===!0,integrityIslands:q.integrityIslands===!0},W={totalPages:0,successCount:0,failedCount:0,cachedCount:0,buildTime:0,pages:[],errors:[]},z=new Set,A=0,G={},X={};await J.hooks.onBuildStart?.();try{if(J.cleanOutput&&O.existsSync(J.outputDir))await O.promises.rm(J.outputDir,{recursive:!0});await O.promises.mkdir(J.outputDir,{recursive:!0});let L=J.cacheSalt;if(!L){let{resolveUserCssConfig:Y,fingerprintConfig:N}=await import("./chunk-jnbg3e4r.js");try{L=N(await Y(process.cwd()))}catch{}}let{prepareImageDelivery:_}=await import("./chunk-e631svvs.js"),F=await _(J.publicDir,J.outputDir);if(F.count>0)console.log(`Optimized ${F.count} image(s) for responsive delivery`),L=[L,F.fingerprint].filter(Boolean).join(":");let C=new wq(J.cacheDir,L);if(J.cache)await C.load();try{let{generateCss:Y}=await import("./chunk-jnbg3e4r.js");await Y('<div class="bg-black"></div>')}catch{}Yq();let kq=$?.routeMiddleware?.dir||"middleware";await jq(process.cwd(),kq);let p=Vq();if(p.length>0)console.log(`Loaded ${p.length} middleware: ${p.join(", ")}`);let bq=$?.routeMiddleware?.global||[];Fq($?.layoutsDir,d(process.cwd()));let i=l(".",{pagesDir:J.pagesDir,pagesDirs:$?._layerPageDirs});console.log(`Found ${i.length} routes`);let g=[];for(let Y of i){let N=await uq(Y);for(let H of N)g.push({route:Y,url:H.url,params:H.params,props:H.props,revalidate:H.revalidate??J.revalidate})}W.totalPages=g.length,console.log(`Generating ${W.totalPages} pages...`);let b=[],s=[];for(let Y=0;Y<g.length;Y+=J.concurrency)s.push(g.slice(Y,Y+J.concurrency));for(let Y of s)await Promise.all(Y.map(async(N)=>{let{route:H,url:V,params:S,props:Sq,revalidate:a}=N;try{await J.hooks.onPageStart?.(V);let w=await Bun.file(H.filePath).text(),R=JJ(w),vq=R?.middleware?Array.isArray(R.middleware)?R.middleware:[R.middleware]:[],t=[...bq,...vq];if(t.length>0){let D=Gq(V,S,R||{}),M=Lq(D,null,void 0,{isServer:!0}),E=await Nq(t,M);if(E.redirect){let U=typeof E.redirect==="string"?E.redirect:E.redirect.path||E.redirect,x=QJ(String(U),V),k=ZJ(V,J);await O.promises.mkdir(j.dirname(k),{recursive:!0}),await Bun.write(k,x),W.successCount++,W.pages.push({route:V,outputPath:k,size:Buffer.byteLength(x),cached:!1}),b.push({loc:V,lastmod:new Date().toISOString()}),console.log(` \u21B3 ${V} \u2192 redirect to ${U}`);return}if(E.abort){let U=typeof E.abort==="string"?E.abort:E.abort?.error?.message||"aborted";console.warn(` \u21B3 ${V} \u2014 middleware aborted: ${U}`);return}}let e=w.match(/definePageMeta\s*\(\s*\{[\s\S]*?validate\s*:\s*((?:\([^)]*\)|[^,}])*(?:\{[\s\S]*?\})?)/m);if(e)try{if(!await Function("route",`
44
+ </rss>`}async function aq(q={}){let Z=Date.now();Aq();let $=await n(process.cwd()),Q=$.build||{},K=await Kq({explicit:q.domain||Q.domain,stxConfig:$});if(K.source==="fallback"&&(q.sitemap??Q.sitemap??!0))console.warn(Wq());let J={router:q.router??$?.router??{},pagesDir:q.pagesDir||Q.pagesDir||"pages",outputDir:q.outputDir||Q.outputDir||"dist",baseUrl:q.baseUrl||Q.baseUrl||"/",domain:K.url,revalidate:q.revalidate??Q.revalidate??!1,sitemap:q.sitemap??Q.sitemap??!0,sitemapExclude:q.sitemapExclude||Q.sitemapExclude||[],robots:q.robots??Q.robots??!0,rss:q.rss??Q.rss??!1,concurrency:q.concurrency||Q.concurrency||10,cache:q.cache??Q.cache??!0,cacheDir:q.cacheDir||Q.cacheDir||d(process.cwd(),"ssg-cache"),contentLoaders:q.contentLoaders||[],hooks:q.hooks||{},minify:q.minify??Q.minify??!0,generate404:q.generate404??Q.generate404??!0,publicDir:q.publicDir||Q.publicDir||"public",trailingSlash:q.trailingSlash??Q.trailingSlash??!1,cleanOutput:q.cleanOutput??Q.cleanOutput??!0,cacheSalt:q.cacheSalt??"",partialsDir:q.partialsDir||$?.partialsDir||"",componentsDir:q.componentsDir||$?.componentsDir||"",failOnIncludeError:q.failOnIncludeError??!0,chunkIslands:q.chunkIslands===!0,prefetchIslands:q.prefetchIslands===!0,integrityIslands:q.integrityIslands===!0},W={totalPages:0,successCount:0,failedCount:0,cachedCount:0,buildTime:0,pages:[],errors:[]},z=new Set,A=0,G={},X={};await J.hooks.onBuildStart?.();try{if(J.cleanOutput&&O.existsSync(J.outputDir))await O.promises.rm(J.outputDir,{recursive:!0});await O.promises.mkdir(J.outputDir,{recursive:!0});let L=J.cacheSalt;if(!L){let{resolveUserCssConfig:Y,fingerprintConfig:N}=await import("./chunk-864m3xp2.js");try{L=N(await Y(process.cwd()))}catch{}}let{prepareImageDelivery:_}=await import("./chunk-e631svvs.js"),F=await _(J.publicDir,J.outputDir);if(F.count>0)console.log(`Optimized ${F.count} image(s) for responsive delivery`),L=[L,F.fingerprint].filter(Boolean).join(":");let C=new wq(J.cacheDir,L);if(J.cache)await C.load();try{let{generateCss:Y}=await import("./chunk-864m3xp2.js");await Y('<div class="bg-black"></div>')}catch{}Yq();let kq=$?.routeMiddleware?.dir||"middleware";await jq(process.cwd(),kq);let p=Vq();if(p.length>0)console.log(`Loaded ${p.length} middleware: ${p.join(", ")}`);let bq=$?.routeMiddleware?.global||[];Fq($?.layoutsDir,d(process.cwd()));let i=l(".",{pagesDir:J.pagesDir,pagesDirs:$?._layerPageDirs});console.log(`Found ${i.length} routes`);let g=[];for(let Y of i){let N=await uq(Y);for(let H of N)g.push({route:Y,url:H.url,params:H.params,props:H.props,revalidate:H.revalidate??J.revalidate})}W.totalPages=g.length,console.log(`Generating ${W.totalPages} pages...`);let b=[],s=[];for(let Y=0;Y<g.length;Y+=J.concurrency)s.push(g.slice(Y,Y+J.concurrency));for(let Y of s)await Promise.all(Y.map(async(N)=>{let{route:H,url:V,params:S,props:Sq,revalidate:a}=N;try{await J.hooks.onPageStart?.(V);let w=await Bun.file(H.filePath).text(),R=JJ(w),vq=R?.middleware?Array.isArray(R.middleware)?R.middleware:[R.middleware]:[],t=[...bq,...vq];if(t.length>0){let D=Gq(V,S,R||{}),M=Lq(D,null,void 0,{isServer:!0}),E=await Nq(t,M);if(E.redirect){let U=typeof E.redirect==="string"?E.redirect:E.redirect.path||E.redirect,x=QJ(String(U),V),k=ZJ(V,J);await O.promises.mkdir(j.dirname(k),{recursive:!0}),await Bun.write(k,x),W.successCount++,W.pages.push({route:V,outputPath:k,size:Buffer.byteLength(x),cached:!1}),b.push({loc:V,lastmod:new Date().toISOString()}),console.log(` \u21B3 ${V} \u2192 redirect to ${U}`);return}if(E.abort){let U=typeof E.abort==="string"?E.abort:E.abort?.error?.message||"aborted";console.warn(` \u21B3 ${V} \u2014 middleware aborted: ${U}`);return}}let e=w.match(/definePageMeta\s*\(\s*\{[\s\S]*?validate\s*:\s*((?:\([^)]*\)|[^,}])*(?:\{[\s\S]*?\})?)/m);if(e)try{if(!await Function("route",`
45
45
  const validate = ${e[1]};
46
46
  return validate(route);
47
47
  `)({params:S})){console.warn(`Validation failed for ${V}, skipping...`);return}}catch{}let I=null,qq=!1;if(J.cache){if(I=C.get(V,H.filePath),I)qq=!0,W.cachedCount++}if(!I){let D=await Mq(H,S,Sq,J,$);if(I=D.html,J.failOnIncludeError&&D.includeFailures.length>0)throw Error(`${D.includeFailures.length} include(s) failed to resolve, so this page would have shipped with an error banner where the markup should be:
@@ -3,22 +3,26 @@ export const SEMANTIC_TOKENS = {
3
3
  "fg-strong": { light: "neutral-700", dark: "neutral-300", description: "Labels, secondary headings" },
4
4
  "fg-muted": { light: "neutral-600", dark: "neutral-400", description: "Supporting text" },
5
5
  "fg-soft": { light: "neutral-500", dark: "neutral-400", description: "De-emphasised text" },
6
- "fg-subtle": { light: "neutral-400", dark: "neutral-500", description: "Placeholders, disabled text" },
6
+ "fg-subtle": { light: "neutral-400", dark: "neutral-500", description: "Recessive, non-essential text" },
7
7
  surface: { light: "neutral-50", dark: "neutral-800", description: "Page and panel background" },
8
8
  "surface-raised": { light: "neutral-100", dark: "neutral-700", description: "Cards, popovers" },
9
9
  "surface-sunken": { light: "neutral-200", dark: "neutral-700", description: "Wells, track backgrounds" },
10
10
  panel: { light: "white", dark: "neutral-800", description: "Card, menu, dialog surface" },
11
11
  field: { light: "white", dark: "neutral-700", description: "Form control surface" },
12
+ page: { light: "neutral-50", dark: "neutral-900", description: "Page background, behind panels" },
13
+ content: { light: "white", dark: "neutral-900", description: "Content area under a chrome header - a table or list body" },
12
14
  "surface-hover": { light: "neutral-100", dark: "neutral-700", description: "Row or item highlight on a page or panel" },
13
15
  "surface-raised-hover": { light: "neutral-200", dark: "neutral-600", description: "Raised surface, hovered" },
14
16
  "surface-sunken-hover": { light: "neutral-300", dark: "neutral-600", description: "Sunken surface, hovered" },
15
17
  "field-hover": { light: "neutral-50", dark: "neutral-600", description: "Form control surface, hovered" },
18
+ link: { light: "blue-500", dark: "blue-400", description: "Hyperlink" },
19
+ "link-hover": { light: "blue-600", dark: "blue-300", description: "Hyperlink, hovered" },
16
20
  inverse: { light: "neutral-900", dark: "neutral-700", description: "Tooltip bubble, inverted surface" },
17
21
  "inverse-ink": { light: "white", dark: "white", description: "Text on an inverted surface" },
18
22
  line: { light: "neutral-200", dark: "neutral-700", description: "Default border, divider" },
19
23
  "line-strong": { light: "neutral-300", dark: "neutral-600", description: "Input border, focus ring track" },
20
24
  accent: { light: "blue-600", dark: "blue-400", description: "Primary action, selected state" },
21
- info: { light: "cyan-600", dark: "cyan-400", description: "Informational emphasis, links" },
25
+ info: { light: "cyan-600", dark: "cyan-400", description: "Informational emphasis" },
22
26
  danger: { light: "red-600", dark: "red-400", description: "Errors, destructive actions" },
23
27
  success: { light: "green-600", dark: "green-400", description: "Confirmation" },
24
28
  warning: { light: "yellow-600", dark: "yellow-400", description: "Caution" },
@@ -33,9 +37,9 @@ export const SEMANTIC_TOKENS = {
33
37
  "success-solid-hover": { light: "green-600", dark: "green-700", description: "Confirmation fill, hovered" },
34
38
  "warning-solid-hover": { light: "yellow-600", dark: "yellow-700", description: "Caution fill, hovered" },
35
39
  "accent-ink": { light: "white", dark: "white", description: "Text on a primary fill" },
36
- "info-ink": { light: "white", dark: "white", description: "Text on an informational fill" },
40
+ "info-ink": { light: "neutral-900", dark: "neutral-900", description: "Text on an informational fill" },
37
41
  "danger-ink": { light: "white", dark: "white", description: "Text on a destructive fill" },
38
- "success-ink": { light: "white", dark: "white", description: "Text on a confirmation fill" },
42
+ "success-ink": { light: "neutral-900", dark: "neutral-900", description: "Text on a confirmation fill" },
39
43
  "warning-ink": { light: "neutral-900", dark: "neutral-900", description: "Text on a caution fill" },
40
44
  "accent-soft": { light: "blue-100", dark: "blue-900", description: "Tinted primary fill" },
41
45
  "accent-soft-ink": { light: "blue-800", dark: "blue-200", description: "Text on a tinted primary fill" },
@@ -54,7 +58,7 @@ export const SEMANTIC_TOKENS = {
54
58
  "secondary-soft": { light: "purple-100", dark: "purple-900", description: "Tinted secondary fill" },
55
59
  "secondary-soft-ink": { light: "purple-800", dark: "purple-200", description: "Text on a tinted secondary fill" },
56
60
  "danger-fg": { light: "red-900", dark: "red-300", description: "Text in a field with an error" },
57
- "danger-fg-subtle": { light: "red-300", dark: "red-500", description: "Placeholder in a field with an error" },
61
+ "danger-fg-subtle": { light: "red-300", dark: "red-500", description: "Recessive text in a field with an error" },
58
62
  "danger-line": { light: "red-300", dark: "red-600", description: "Border of a field with an error" },
59
63
  "danger-focus": { light: "red-500", dark: "red-400", description: "Focus ring of a field with an error" }
60
64
  };
@@ -33,6 +33,18 @@ export declare function stripTypeScript(scriptContent: string): string;
33
33
  * Matched on the message because the failure arrives as a plain Error from the
34
34
  * runtime's loader rather than a typed one, and the wording differs between
35
35
  * Bun and Node.
36
+ *
37
+ * `cannot find package` is the important one and was missing. An ESM import
38
+ * that does not resolve says
39
+ *
40
+ * Cannot find package 'bunfig' imported from /…/dist/index.js
41
+ *
42
+ * and only a `require()` says "module". So the case stacksjs/stx#1991 was
43
+ * filed for - a dependency importing a package it had not declared, which
44
+ * threw wherever that package was unreachable - was classified as an unknown
45
+ * failure and got the generic warning instead of the one naming the cause.
46
+ * That one is also deduplicated per cause, so the clearest failure in the set
47
+ * was getting the quietest treatment.
36
48
  */
37
49
  export declare function isModuleResolutionFailure(message: string): boolean;
38
50
  /**
@@ -76,6 +88,25 @@ export interface ExtractVariablesOptions {
76
88
  * passes this flag on.
77
89
  */
78
90
  preserveExisting?: boolean;
91
+ /**
92
+ * Called when the script failed, so every variable it declared is undefined
93
+ * and anything reading one renders empty (stacksjs/stx#1991).
94
+ *
95
+ * `kind` says how certain that is a bug. The first three always are.
96
+ * `unknown` is not: a server script reaching for `window` or constructing a
97
+ * Chart lands there, which is the case the quiet fallback exists for, so a
98
+ * caller showing the developer something should leave that one alone.
99
+ *
100
+ * Reported rather than thrown, because one failed script must not take the
101
+ * page down with it. Before this a caller could not find out at all: the
102
+ * extractor warned and returned normally, which is why the component became
103
+ * a hole that nothing could put a boundary around.
104
+ */
105
+ onFailure?: (failure: {
106
+ kind: 'module-resolution' | 'syntax' | 'missing-binding' | 'unknown';
107
+ message: string;
108
+ error: unknown;
109
+ }) => void;
79
110
  }
80
111
  export declare function extractVariables(scriptContent: string, context: Record<string, unknown>, filePath: string, options?: ExtractVariablesOptions): Promise<void>;
81
112
  /**
@@ -274,7 +274,7 @@ export function stripTypeScript(scriptContent) {
274
274
  return result;
275
275
  }
276
276
  export function isModuleResolutionFailure(message) {
277
- return /cannot find module|could not resolve|module not found|failed to resolve/i.test(message);
277
+ return /cannot find module|cannot find package|could not resolve|module not found|failed to resolve/i.test(message);
278
278
  }
279
279
  export function isSyntaxFailure(error) {
280
280
  if (error instanceof SyntaxError)
@@ -569,18 +569,22 @@ export async function extractVariables(scriptContent, context, filePath, options
569
569
  if (context.__stx_strict_hydration)
570
570
  throw primaryError;
571
571
  const msg = primaryError instanceof Error ? primaryError.message : String(primaryError);
572
- if (isModuleResolutionFailure(msg))
572
+ if (isModuleResolutionFailure(msg)) {
573
573
  console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} imports a module that does not resolve, so every variable in that script is undefined. Cause: ${msg}`);
574
- else if (isSyntaxFailure(primaryError))
574
+ options.onFailure?.({ kind: "module-resolution", message: msg, error: primaryError });
575
+ } else if (isSyntaxFailure(primaryError)) {
575
576
  console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} does not parse, so every variable in that script is undefined. Cause: ${msg}`);
576
- else if (isMissingBindingFailure(msg))
577
+ options.onFailure?.({ kind: "syntax", message: msg, error: primaryError });
578
+ } else if (isMissingBindingFailure(msg)) {
577
579
  console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} names something that does not exist, so every variable in that script is undefined. Optional chaining does not help here: an undefined identifier throws before the chain is reached. Cause: ${msg}`);
578
- else {
580
+ options.onFailure?.({ kind: "missing-binding", message: msg, error: primaryError });
581
+ } else {
579
582
  const seenKey = `${filePath ?? "<unknown>"}\x00${msg}`;
580
583
  if (process.env.STX_DEBUG || !reportedServerScriptFailures.has(seenKey)) {
581
584
  reportedServerScriptFailures.add(seenKey);
582
585
  console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} threw, so every variable in that script is undefined and anything that reads one renders empty. Cause: ${msg}`);
583
586
  }
587
+ options.onFailure?.({ kind: "unknown", message: msg, error: primaryError });
584
588
  }
585
589
  try {
586
590
  await fallbackVariableExtraction(jsContent, context, filePath);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/stx",
3
3
  "type": "module",
4
- "version": "0.2.345",
4
+ "version": "0.2.346",
5
5
  "description": "A performant UI Framework. Powered by Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",
@@ -117,12 +117,12 @@
117
117
  "dependencies": {
118
118
  "@stacksjs/ts-css": "^0.3.2",
119
119
  "@stacksjs/clapp": "^0.2.16",
120
- "@stacksjs/desktop": "0.2.345",
121
- "@stacksjs/sanitizer": "0.2.345",
120
+ "@stacksjs/desktop": "0.2.346",
121
+ "@stacksjs/sanitizer": "0.2.346",
122
122
  "@stacksjs/ts-i18n": "^0.1.11",
123
- "bun-plugin-stx": "0.2.345",
123
+ "bun-plugin-stx": "0.2.346",
124
124
  "bunfig": "^0.15.19",
125
- "stx-router": "0.2.345",
125
+ "stx-router": "0.2.346",
126
126
  "ts-broadcasting": "^0.0.10",
127
127
  "ts-images": "^0.2.22",
128
128
  "ts-syntax-highlighter": "^0.2.1"