@absolutejs/absolute 0.20.0-beta.169 → 0.20.0-beta.170

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 (238) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +232 -0
  3. package/changelog.json +228 -0
  4. package/dist/angular/browser.js +7 -8
  5. package/dist/angular/browser.js.map +6 -5
  6. package/dist/angular/components/core/streamingSlotRegistrar.js +6 -2
  7. package/dist/angular/components/core/streamingSlotRegistry.js +7 -3
  8. package/dist/angular/index.js +555 -156
  9. package/dist/angular/index.js.map +29 -23
  10. package/dist/angular/server.js +555 -156
  11. package/dist/angular/server.js.map +29 -23
  12. package/dist/build/buildWorker.js +14 -8
  13. package/dist/build.js +4949 -1941
  14. package/dist/build.js.map +72 -42
  15. package/dist/cli/{add-7azr0c83.js → add-6a7pjkn9.js} +11 -7
  16. package/dist/cli/{analyze-3cyek6v3.js → analyze-606fshwa.js} +1 -1
  17. package/dist/cli/{build-25rz8v25.js → build-g81xqbb9.js} +1 -1
  18. package/dist/cli/{compile-4jnfxts9.js → compile-9y1w9zpj.js} +3 -3
  19. package/dist/cli/config/server.js +10699 -1538
  20. package/dist/cli/{dev-9tk5hn2e.js → dev-hyeb89hp.js} +5 -1
  21. package/dist/cli/{doctor-4nv2c2j3.js → doctor-h55y9hj1.js} +1 -1
  22. package/dist/cli/{generate-v75p2fct.js → generate-20x1pkf7.js} +4 -4
  23. package/dist/cli/{htmx-427swtdz.js → htmx-6mz2h7k1.js} +2 -2
  24. package/dist/cli/{index-bhbs6d5z.js → index-32ge2w1f.js} +12 -4
  25. package/dist/cli/{index-a4ws2jwd.js → index-3wz3mktm.js} +1 -1
  26. package/dist/cli/{index-b7hjgknf.js → index-9sksd8c8.js} +13 -4
  27. package/dist/cli/{index-eyzwc7gz.js → index-qbrzvmh9.js} +4 -2
  28. package/dist/cli/index-qw98g1p6.js +269 -0
  29. package/dist/cli/{index-434b7j4a.js → index-vtp20gwf.js} +69 -1
  30. package/dist/cli/{index-h7qhz02e.js → index-wk0pyxrg.js} +3 -0
  31. package/dist/cli/{index-k3y8cb6c.js → index-z6f43b20.js} +1 -1
  32. package/dist/cli/index.js +16 -16
  33. package/dist/cli/{islands-8sgky9gh.js → islands-dc54e5y1.js} +1 -1
  34. package/dist/cli/{ls-4m4yqwww.js → ls-b6zz24nt.js} +1 -1
  35. package/dist/cli/{mobile-hcxjr2gf.js → mobile-ajnnvqtv.js} +3 -3
  36. package/dist/cli/prerender-fqpp0m1j.js +10 -0
  37. package/dist/cli/{remove-1ycjx85k.js → remove-t8x1mrxg.js} +4 -4
  38. package/dist/cli/{start-mbaejxhm.js → start-d6p831ny.js} +3 -3
  39. package/dist/cli/{typecheck-dr068pmh.js → typecheck-stbt0qt5.js} +6 -1
  40. package/dist/cli/{workspace-1sycp9g1.js → workspace-61hh6jq1.js} +1 -1
  41. package/dist/client/chunks/index-6b66nzyf.js +381 -0
  42. package/dist/client/chunks/index-6b66nzyf.js.map +11 -0
  43. package/dist/client/chunks/{islands-rc28k5sx.js → islands-s2ta5ajb.js} +5 -2
  44. package/dist/client/chunks/{islands-rc28k5sx.js.map → islands-s2ta5ajb.js.map} +7 -6
  45. package/dist/client/index.js +160 -3
  46. package/dist/client/index.js.map +6 -4
  47. package/dist/client/navigation.js +764 -0
  48. package/dist/client/navigation.js.map +10 -0
  49. package/dist/client/prefetch.js +33 -375
  50. package/dist/client/prefetch.js.map +3 -4
  51. package/dist/core/streamingSlotRegistrar.js +5 -2
  52. package/dist/core/streamingSlotRegistrar.js.map +5 -4
  53. package/dist/core/streamingSlotRegistry.js +5 -2
  54. package/dist/core/streamingSlotRegistry.js.map +5 -4
  55. package/dist/dev/client/cspNonce.ts +28 -0
  56. package/dist/dev/client/handlers/html.ts +4 -3
  57. package/dist/dev/client/handlers/htmx.ts +3 -2
  58. package/dist/dev/client/handlers/svelte.ts +15 -90
  59. package/dist/dev/client/syncDevtools.ts +2 -1
  60. package/dist/dev/serverBootstrap.js +11 -4
  61. package/dist/i18n/index.js +543 -0
  62. package/dist/i18n/index.js.map +15 -0
  63. package/dist/index.js +6339 -2233
  64. package/dist/index.js.map +89 -54
  65. package/dist/islands/index.js +282 -40
  66. package/dist/islands/index.js.map +14 -10
  67. package/dist/mobile/browser.js +7 -2
  68. package/dist/mobile/browser.js.map +5 -4
  69. package/dist/mobile/index.js +7 -2
  70. package/dist/mobile/index.js.map +5 -4
  71. package/dist/mobile/remoteMacAgentEntry.js +1 -1
  72. package/dist/react/components/browser/index.js +94 -4
  73. package/dist/react/components/index.js +150 -10
  74. package/dist/react/components/index.js.map +15 -10
  75. package/dist/react/hooks/index.js +479 -13
  76. package/dist/react/hooks/index.js.map +12 -4
  77. package/dist/react/index.js +769 -166
  78. package/dist/react/index.js.map +32 -21
  79. package/dist/react/router/browser.js +21 -4
  80. package/dist/react/router/browser.js.map +5 -4
  81. package/dist/react/router/index.js +21 -4
  82. package/dist/react/router/index.js.map +5 -4
  83. package/dist/react/server.js +597 -203
  84. package/dist/react/server.js.map +25 -15
  85. package/dist/src/angular/zoneRuntime.d.ts +5 -0
  86. package/dist/src/build/buildReactServerComponents.d.ts +22 -0
  87. package/dist/src/build/downlevelAsyncForZone.d.ts +1 -0
  88. package/dist/src/build/fileRoutes.d.ts +65 -0
  89. package/dist/src/build/fonts/buildFonts.d.ts +25 -0
  90. package/dist/src/build/fonts/fallbackMetrics.d.ts +13 -0
  91. package/dist/src/build/fonts/googleFonts.d.ts +18 -0
  92. package/dist/src/build/fonts/injectFontTags.d.ts +7 -0
  93. package/dist/src/build/fonts/parseFontMetrics.d.ts +4 -0
  94. package/dist/src/build/generateReactIndexes.d.ts +7 -1
  95. package/dist/src/build/htmlIncludes.d.ts +16 -0
  96. package/dist/src/build/inlineSourceMapComment.d.ts +1 -0
  97. package/dist/src/build/scanConventions.d.ts +3 -0
  98. package/dist/src/build/vitals.d.ts +21 -0
  99. package/dist/src/client/formActions.d.ts +29 -0
  100. package/dist/src/client/index.d.ts +2 -0
  101. package/dist/src/client/navigation.d.ts +16 -0
  102. package/dist/src/client/prefetch.d.ts +2 -30
  103. package/dist/src/core/build.d.ts +2 -2
  104. package/dist/src/core/cspNonce.d.ts +12 -0
  105. package/dist/src/core/fileRouteAdapter.d.ts +15 -0
  106. package/dist/src/core/fileRoutes.d.ts +5 -0
  107. package/dist/src/core/formActionFlash.d.ts +25 -0
  108. package/dist/src/core/formActions.d.ts +249 -0
  109. package/dist/src/core/index.d.ts +5 -0
  110. package/dist/src/core/partialPrerender.d.ts +28 -0
  111. package/dist/src/core/partialPrerenderServe.d.ts +24 -0
  112. package/dist/src/core/precompressed.d.ts +11 -1
  113. package/dist/src/core/prerenderNonce.d.ts +9 -0
  114. package/dist/src/core/productionRuntime.d.ts +4 -2
  115. package/dist/src/core/serverOnlyStaticFiles.d.ts +8 -0
  116. package/dist/src/core/staticHtmlNonce.d.ts +2 -0
  117. package/dist/src/core/vitals.d.ts +108 -0
  118. package/dist/src/dev/angular/fastHmrCompiler.d.ts +1 -1
  119. package/dist/src/dev/client/cspNonce.d.ts +2 -0
  120. package/dist/src/dev/fileRouteRefresher.d.ts +5 -0
  121. package/dist/src/dev/importCost/instrument.d.ts +1 -1
  122. package/dist/src/dev/reactServerComponentsRebuild.d.ts +3 -0
  123. package/dist/src/i18n/defineMessages.d.ts +5 -0
  124. package/dist/src/i18n/formatMessage.d.ts +26 -0
  125. package/dist/src/i18n/index.d.ts +6 -0
  126. package/dist/src/i18n/intlCache.d.ts +5 -0
  127. package/dist/src/i18n/routing.d.ts +28 -0
  128. package/dist/src/i18n/translator.d.ts +11 -0
  129. package/dist/src/mobile/androidRelease.d.ts +2 -2
  130. package/dist/src/mobile/iosRelease.d.ts +4 -4
  131. package/dist/src/mobile/materializedBundle.d.ts +1 -1
  132. package/dist/src/mobile/mobileInspect.d.ts +1 -1
  133. package/dist/src/mobile/releaseArtifact.d.ts +2 -2
  134. package/dist/src/mobile/remoteMacProtocol.d.ts +2 -2
  135. package/dist/src/plugins/i18n.d.ts +30 -0
  136. package/dist/src/plugins/index.d.ts +2 -1
  137. package/dist/src/plugins/secureHeaders.d.ts +48 -0
  138. package/dist/src/react/components/Head.d.ts +1 -1
  139. package/dist/src/react/components/StreamSlot.browser.d.ts +1 -0
  140. package/dist/src/react/components/StreamSlot.d.ts +5 -1
  141. package/dist/src/react/components/SuspenseSlot.browser.d.ts +2 -0
  142. package/dist/src/react/components/SuspenseSlot.d.ts +12 -0
  143. package/dist/src/react/fileRoute.d.ts +18 -0
  144. package/dist/src/react/hooks/index.d.ts +4 -0
  145. package/dist/src/react/hooks/useFormAction.d.ts +42 -0
  146. package/dist/src/react/hooks/useI18n.d.ts +15 -0
  147. package/dist/src/react/index.d.ts +2 -0
  148. package/dist/src/react/server.d.ts +2 -0
  149. package/dist/src/react/serverComponents/constants.d.ts +11 -0
  150. package/dist/src/react/serverComponents/flightPayload.d.ts +2 -0
  151. package/dist/src/react/serverComponents/pageHandler.d.ts +14 -0
  152. package/dist/src/svelte/browser.d.ts +1 -0
  153. package/dist/src/svelte/fileRoute.d.ts +15 -0
  154. package/dist/src/svelte/i18n.d.ts +8 -0
  155. package/dist/src/svelte/index.d.ts +2 -0
  156. package/dist/src/svelte/lowerAwaitSlotSyntax.d.ts +5 -1
  157. package/dist/src/svelte/renderToReadableStream.d.ts +10 -2
  158. package/dist/src/svelte/router/browser.d.ts +3 -1
  159. package/dist/src/svelte/router/goto.d.ts +13 -10
  160. package/dist/src/svelte/router/guards.d.ts +43 -0
  161. package/dist/src/svelte/router/index.d.ts +3 -1
  162. package/dist/src/svelte/router/lazy.d.ts +17 -0
  163. package/dist/src/svelte/router/lazyModule.d.ts +29 -0
  164. package/dist/src/svelte/router/navigation.d.ts +55 -0
  165. package/dist/src/svelte/router/pushState.d.ts +4 -2
  166. package/dist/src/svelte/router/scroll.d.ts +34 -0
  167. package/dist/src/svelte/routerSsr.d.ts +9 -0
  168. package/dist/src/svelte/server.d.ts +1 -0
  169. package/dist/src/utils/cspNonceRef.d.ts +8 -0
  170. package/dist/src/utils/fontAssets.d.ts +17 -0
  171. package/dist/src/utils/formActionProtocol.d.ts +10 -0
  172. package/dist/src/utils/generateHeadElement.d.ts +1 -1
  173. package/dist/src/utils/index.d.ts +1 -0
  174. package/dist/src/utils/inlinePageCss.d.ts +18 -0
  175. package/dist/src/utils/loadConfig.d.ts +5 -0
  176. package/dist/src/utils/localeRef.d.ts +10 -0
  177. package/dist/src/utils/resolveConvention.d.ts +6 -1
  178. package/dist/src/utils/streamingSlots.d.ts +5 -0
  179. package/dist/src/vue/browser.d.ts +2 -0
  180. package/dist/src/vue/components/Image.d.ts +2 -2
  181. package/dist/src/vue/index.d.ts +2 -0
  182. package/dist/src/vue/serverDataPayload.d.ts +32 -0
  183. package/dist/src/vue/serverDataState.d.ts +9 -0
  184. package/dist/src/vue/useServerData.browser.d.ts +6 -0
  185. package/dist/src/vue/useServerData.d.ts +24 -0
  186. package/dist/svelte/browser.js +330 -3
  187. package/dist/svelte/browser.js.map +8 -4
  188. package/dist/svelte/components/AwaitSlot.svelte +5 -0
  189. package/dist/svelte/components/Head.svelte +50 -0
  190. package/dist/svelte/components/JsonLd.svelte +9 -1
  191. package/dist/svelte/components/StreamSlot.svelte +5 -0
  192. package/dist/svelte/index.js +1017 -117
  193. package/dist/svelte/index.js.map +38 -24
  194. package/dist/svelte/router/Link.svelte +40 -8
  195. package/dist/svelte/router/Route.svelte +157 -12
  196. package/dist/svelte/router/Route.svelte.d.ts +39 -5
  197. package/dist/svelte/router/Router.svelte +140 -25
  198. package/dist/svelte/router/Router.svelte.d.ts +5 -1
  199. package/dist/svelte/router/browser.ts +10 -0
  200. package/dist/svelte/router/goto.ts +15 -86
  201. package/dist/svelte/router/guards.ts +112 -0
  202. package/dist/svelte/router/index.ts +10 -0
  203. package/dist/svelte/router/lazy.ts +82 -0
  204. package/dist/svelte/router/lazyModule.ts +74 -0
  205. package/dist/svelte/router/navigation.ts +412 -0
  206. package/dist/svelte/router/pushState.ts +7 -4
  207. package/dist/svelte/router/scroll.ts +286 -0
  208. package/dist/svelte/server.js +747 -252
  209. package/dist/svelte/server.js.map +30 -20
  210. package/dist/types/angular.d.ts +2 -0
  211. package/dist/types/build.d.ts +37 -0
  212. package/dist/types/conventions.d.ts +3 -0
  213. package/dist/types/fileRoutes.d.ts +72 -0
  214. package/dist/types/fonts.d.ts +86 -0
  215. package/dist/types/formAction.d.ts +54 -0
  216. package/dist/types/globals.d.ts +10 -0
  217. package/dist/types/i18n.d.ts +185 -0
  218. package/dist/types/index.d.ts +4 -0
  219. package/dist/types/metadata.d.ts +11 -0
  220. package/dist/types/navigation.d.ts +37 -0
  221. package/dist/types/prefetch.d.ts +10 -0
  222. package/dist/types/sitemap.d.ts +4 -0
  223. package/dist/types/svelteRouter.d.ts +89 -2
  224. package/dist/types/svelteRouter.ts +112 -2
  225. package/dist/types/vue.d.ts +46 -1
  226. package/dist/utils/iconVersion.ts +34 -0
  227. package/dist/vue/browser.js +107 -11
  228. package/dist/vue/browser.js.map +7 -4
  229. package/dist/vue/components/index.js +5 -2
  230. package/dist/vue/components/index.js.map +5 -4
  231. package/dist/vue/index.js +712 -158
  232. package/dist/vue/index.js.map +32 -23
  233. package/dist/vue/server.js +310 -79
  234. package/dist/vue/server.js.map +20 -15
  235. package/package.json +9 -1
  236. package/dist/cli/prerender-mfnwsvyt.js +0 -7
  237. package/dist/src/plugins/pageRouter.d.ts +0 -1
  238. /package/dist/cli/{index-j7m8pq48.js → index-rervww4p.js} +0 -0
@@ -72,13 +72,44 @@ var __esm = (fn, res, err) => () => {
72
72
  };
73
73
  var __require = import.meta.require;
74
74
 
75
+ // src/utils/escapeScriptContent.ts
76
+ var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
77
+ const escaped = ESCAPE_LOOKUP[char];
78
+ return escaped !== undefined ? escaped : char;
79
+ });
80
+ var init_escapeScriptContent = __esm(() => {
81
+ ESCAPE_LOOKUP = {
82
+ "\u2028": "\\u2028",
83
+ "\u2029": "\\u2029",
84
+ "<": "\\u003C"
85
+ };
86
+ ESCAPE_REGEX = /[<\u2028\u2029]/g;
87
+ });
88
+
89
+ // src/utils/cspNonceRef.ts
90
+ var GETTER_KEY, nonceAttr = (nonce = readCspNonce()) => nonce ? ` nonce="${nonce}"` : "", nonceSvelteHeadStyles = (head, nonce = readCspNonce()) => nonce ? head.replace(/<style(?=\s+id="svelte-[^"]*")(?![^>]*\snonce=)/g, `<style nonce="${nonce}"`) : head, readCspNonce = () => {
91
+ const getter = Reflect.get(globalThis, GETTER_KEY);
92
+ if (typeof getter !== "function")
93
+ return;
94
+ const nonce = getter();
95
+ return typeof nonce === "string" ? nonce : undefined;
96
+ }, registerCspNonceGetter = (getter) => {
97
+ Reflect.set(globalThis, GETTER_KEY, getter);
98
+ };
99
+ var init_cspNonceRef = __esm(() => {
100
+ GETTER_KEY = Symbol.for("absolutejs.cspNonceGetter");
101
+ });
102
+
103
+ // src/utils/runtimeMode.ts
104
+ var ENV_VAR = "NODE_ENV", getNodeEnv = () => process.env[ENV_VAR], isDevelopmentRuntime = () => process.env[ENV_VAR] === "development", isProductionRuntime = () => process.env[ENV_VAR] === "production";
105
+
75
106
  // src/utils/inlinePageCss.ts
76
107
  var siblingCssCache, clearSiblingCssCache = () => {
77
108
  siblingCssCache.clear();
78
109
  }, injectInlineCss = (headTag, css) => {
79
110
  if (!css)
80
111
  return headTag;
81
- const styleBlock = `<style data-absolute-page-css>${css}</style>`;
112
+ const styleBlock = `<style data-absolute-page-css${nonceAttr()}>${css}</style>`;
82
113
  return headTag.replace("</head>", `${styleBlock}</head>`);
83
114
  }, readSiblingCss = async (siblingJsPath) => {
84
115
  if (!siblingJsPath)
@@ -100,6 +131,7 @@ var siblingCssCache, clearSiblingCssCache = () => {
100
131
  }
101
132
  };
102
133
  var init_inlinePageCss = __esm(() => {
134
+ init_cspNonceRef();
103
135
  siblingCssCache = new Map;
104
136
  });
105
137
 
@@ -196,6 +228,45 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
196
228
  return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
197
229
  };
198
230
 
231
+ // src/core/staticHtmlNonce.ts
232
+ var nonceStaticHtml = async (html, nonce = readCspNonce()) => {
233
+ if (!nonce)
234
+ return html;
235
+ const stamp = {
236
+ element: (element) => {
237
+ if (!element.hasAttribute("nonce"))
238
+ element.setAttribute("nonce", nonce);
239
+ }
240
+ };
241
+ return new HTMLRewriter().on("script", stamp).on("style", stamp).transform(new Response(html)).text();
242
+ }, isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), parseHtmxConfig = (content) => {
243
+ try {
244
+ const parsed = JSON.parse(content ?? "{}");
245
+ return isRecord(parsed) ? parsed : {};
246
+ } catch {
247
+ return {};
248
+ }
249
+ }, withHtmxStyleNonce = async (html, nonce = readCspNonce()) => {
250
+ if (!nonce)
251
+ return html;
252
+ let found = false;
253
+ const merged = await new HTMLRewriter().on('meta[name="htmx-config"]', {
254
+ element: (element) => {
255
+ found = true;
256
+ const config = parseHtmxConfig(element.getAttribute("content"));
257
+ element.setAttribute("content", JSON.stringify({ ...config, inlineStyleNonce: nonce }));
258
+ }
259
+ }).transform(new Response(html)).text();
260
+ if (found)
261
+ return merged;
262
+ const meta = `<meta name="htmx-config" content='${JSON.stringify({ inlineStyleNonce: nonce })}'>`;
263
+ const headClose = merged.search(/<\/head>/i);
264
+ return headClose >= 0 ? `${merged.slice(0, headClose)}${meta}${merged.slice(headClose)}` : `${meta}${merged}`;
265
+ };
266
+ var init_staticHtmlNonce = __esm(() => {
267
+ init_cspNonceRef();
268
+ });
269
+
199
270
  // src/utils/resolveConvention.ts
200
271
  import { basename } from "path";
201
272
  var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boolean(value) && typeof value === "object", getMap = () => {
@@ -232,7 +303,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
232
303
  return conventions.defaults?.error;
233
304
  }, resolveNotFoundConventionPath = (framework) => getMap()[framework]?.defaults?.notFound, setConventions = (map) => {
234
305
  Reflect.set(globalThis, CONVENTIONS_KEY, map);
235
- }, isDev = () => true, buildErrorProps = (error) => {
306
+ }, isDev = () => isDevelopmentRuntime(), buildErrorProps = (error) => {
236
307
  if (error instanceof Error) {
237
308
  return {
238
309
  message: error.message,
@@ -249,7 +320,9 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
249
320
  if (typeof ErrorComponent !== "function")
250
321
  return null;
251
322
  const element = createElement(ErrorComponent, errorProps);
252
- const stream = await renderToReadableStream(element);
323
+ const stream = await renderToReadableStream(element, {
324
+ nonce: readCspNonce()
325
+ });
253
326
  return new Response(stream, {
254
327
  headers: { "Content-Type": "text/html" },
255
328
  status: 500
@@ -260,10 +333,12 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
260
333
  const ErrorComponent = mod.default;
261
334
  if (!ErrorComponent)
262
335
  return null;
336
+ const nonce = readCspNonce();
263
337
  const { head, body } = render(ErrorComponent, {
264
- props: errorProps
338
+ props: errorProps,
339
+ ...nonce ? { csp: { nonce } } : {}
265
340
  });
266
- const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
341
+ const html = `<!DOCTYPE html><html><head>${nonceSvelteHeadStyles(head)}</head><body>${body}</body></html>`;
267
342
  return new Response(html, {
268
343
  headers: { "Content-Type": "text/html" },
269
344
  status: 500
@@ -271,7 +346,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
271
346
  }, unescapeVueStyles = (ssrBody) => {
272
347
  let styles = "";
273
348
  const body = ssrBody.replace(/<style>([\s\S]*?)<\/style>/g, (_, css) => {
274
- styles += `<style>${css.replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">")}</style>`;
349
+ styles += `<style${nonceAttr()}>${css.replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">")}</style>`;
275
350
  return "";
276
351
  });
277
352
  return { body, styles };
@@ -303,7 +378,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
303
378
  status: 500
304
379
  });
305
380
  }, escapeHtml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;"), replaceErrorTokens = (template, errorProps) => template.replace(/\{\{\s*name\s*\}\}/g, escapeHtml(errorProps.name)).replace(/\{\{\s*message\s*\}\}/g, escapeHtml(errorProps.message)).replace(/\{\{\s*stack\s*\}\}/g, errorProps.stack ? escapeHtml(errorProps.stack) : ""), renderHtmlError = async (conventionPath, errorProps) => {
306
- const template = await Bun.file(conventionPath).text();
381
+ const template = await nonceStaticHtml(await Bun.file(conventionPath).text());
307
382
  const html = replaceErrorTokens(template, errorProps);
308
383
  return new Response(html, {
309
384
  headers: { "Content-Type": "text/html" },
@@ -358,7 +433,9 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
358
433
  if (typeof NotFoundComponent !== "function")
359
434
  return null;
360
435
  const element = createElement(NotFoundComponent);
361
- const stream = await renderToReadableStream(element);
436
+ const stream = await renderToReadableStream(element, {
437
+ nonce: readCspNonce()
438
+ });
362
439
  return new Response(stream, {
363
440
  headers: { "Content-Type": "text/html" },
364
441
  status: 404
@@ -369,8 +446,9 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
369
446
  const NotFoundComponent = mod.default;
370
447
  if (!NotFoundComponent)
371
448
  return null;
372
- const { head, body } = render(NotFoundComponent);
373
- const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
449
+ const nonce = readCspNonce();
450
+ const { head, body } = render(NotFoundComponent, nonce ? { csp: { nonce } } : {});
451
+ const html = `<!DOCTYPE html><html><head>${nonceSvelteHeadStyles(head)}</head><body>${body}</body></html>`;
374
452
  return new Response(html, {
375
453
  headers: { "Content-Type": "text/html" },
376
454
  status: 404
@@ -403,7 +481,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
403
481
  status: 404
404
482
  });
405
483
  }, renderHtmlNotFound = async (conventionPath) => {
406
- const html = await Bun.file(conventionPath).text();
484
+ const html = await nonceStaticHtml(await Bun.file(conventionPath).text());
407
485
  return new Response(html, {
408
486
  headers: { "Content-Type": "text/html" },
409
487
  status: 404
@@ -421,7 +499,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
421
499
  logConventionRenderError(framework, "not-found", renderError);
422
500
  }
423
501
  return null;
424
- }, NOT_FOUND_PRIORITY, renderFirstNotFound = async () => {
502
+ }, NOT_FOUND_PRIORITY, renderFirstNotFound = async (options = {}) => {
425
503
  const renderNext = async (frameworks) => {
426
504
  const [framework, ...remaining] = frameworks;
427
505
  if (!framework) {
@@ -436,13 +514,16 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
436
514
  }
437
515
  return renderNext(remaining);
438
516
  };
439
- return renderNext(NOT_FOUND_PRIORITY);
517
+ return renderNext(options.preferHtmx ? ["htmx", ...NOT_FOUND_PRIORITY.filter((key) => key !== "htmx")] : NOT_FOUND_PRIORITY);
440
518
  };
441
519
  var init_resolveConvention = __esm(() => {
520
+ init_cspNonceRef();
521
+ init_staticHtmlNonce();
442
522
  ERROR_RENDERERS = {
443
523
  angular: renderAngularError,
444
524
  ember: renderEmberError,
445
525
  html: renderHtmlError,
526
+ htmx: renderHtmlError,
446
527
  react: renderReactError,
447
528
  svelte: renderSvelteError,
448
529
  vue: renderVueError
@@ -451,6 +532,7 @@ var init_resolveConvention = __esm(() => {
451
532
  angular: renderAngularNotFound,
452
533
  ember: renderEmberNotFound,
453
534
  html: renderHtmlNotFound,
535
+ htmx: renderHtmlNotFound,
454
536
  react: renderReactNotFound,
455
537
  svelte: renderSvelteNotFound,
456
538
  vue: renderVueNotFound
@@ -460,7 +542,8 @@ var init_resolveConvention = __esm(() => {
460
542
  "svelte",
461
543
  "vue",
462
544
  "angular",
463
- "html"
545
+ "html",
546
+ "htmx"
464
547
  ];
465
548
  });
466
549
 
@@ -749,15 +832,15 @@ var ISLAND_BOOTSTRAP_MANIFEST_KEY = "AbsoluteIslandBootstrap", LEGACY_ISLAND_BOO
749
832
  var ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__", CLOSING_HEAD_TAG = "</head>", warnedMissingBootstrap = false, warnIfBootstrapMissing = (manifest) => {
750
833
  if (warnedMissingBootstrap || getIslandBootstrapPath(manifest))
751
834
  return;
752
- if (false)
753
- ;
835
+ if (isProductionRuntime())
836
+ return;
754
837
  warnedMissingBootstrap = true;
755
838
  logWarn("A page contains islands, but the build manifest has no islands bootstrap, so they will render without hydrating. Set `islands.registry` in absolute.config.ts (a default bootstrap is generated from it) or point `islands.bootstrap` at a file that calls startIslands().");
756
839
  }, buildIslandsHeadMarkup = (manifest) => {
757
- const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
758
- const islandStateScript = `<script>window.__ABS_ISLAND_STATE__ = ${JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {})}</script>`;
840
+ const manifestScript = `<script${nonceAttr()}>window.__ABSOLUTE_MANIFEST__ = ${escapeScriptContent(JSON.stringify(manifest))}</script>`;
841
+ const islandStateScript = `<script${nonceAttr()}>window.__ABS_ISLAND_STATE__ = ${escapeScriptContent(JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {}))}</script>`;
759
842
  const bootstrapPath = getIslandBootstrapPath(manifest);
760
- const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
843
+ const bootstrapScript = bootstrapPath ? `<script${nonceAttr()} type="module" src="${bootstrapPath}"></script>` : "";
761
844
  return `${manifestScript}${islandStateScript}${bootstrapScript}`;
762
845
  }, injectHeadMarkup = (html, markup) => {
763
846
  const closingHeadIndex = html.indexOf("</head>");
@@ -958,6 +1041,8 @@ var ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST
958
1041
  globalThis.__absoluteManifest = manifest;
959
1042
  };
960
1043
  var init_islandPageContext = __esm(() => {
1044
+ init_escapeScriptContent();
1045
+ init_cspNonceRef();
961
1046
  init_logger();
962
1047
  });
963
1048
 
@@ -1087,7 +1172,7 @@ var errorPageHtml = ({
1087
1172
  <meta charset="utf-8">
1088
1173
  <meta name="viewport" content="width=device-width, initial-scale=1">
1089
1174
  <title>SSR Error - AbsoluteJS</title>
1090
- <style>
1175
+ <style${nonceAttr()}>
1091
1176
  *{margin:0;padding:0;box-sizing:border-box}
1092
1177
  body{min-height:100vh;background:linear-gradient(135deg,rgba(15,23,42,0.98) 0%,rgba(30,41,59,0.98) 100%);color:#e2e8f0;font-family:"JetBrains Mono","Fira Code",ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:14px;line-height:1.6;display:flex;align-items:flex-start;justify-content:center;padding:32px}
1093
1178
  .card{max-width:720px;width:100%;background:rgba(30,41,59,0.6);border:1px solid rgba(71,85,105,0.5);border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5),0 0 0 1px rgba(255,255,255,0.05);overflow:hidden}
@@ -1119,20 +1204,23 @@ body{min-height:100vh;background:linear-gradient(135deg,rgba(15,23,42,0.98) 0%,r
1119
1204
  ${script}
1120
1205
  </body>
1121
1206
  </html>`;
1122
- }, RELOAD_ON_REBUILD = `<script>(()=>{const url=(location.protocol==='https:'?'wss://':'ws://')+location.host+'/hmr';let seen=false;const connect=()=>{const socket=new WebSocket(url);socket.onopen=()=>{if(seen)location.reload();seen=true;};socket.onmessage=(event)=>{try{const message=JSON.parse(event.data);const type=message&&typeof message.type==='string'?message.type:'';if(type==='rebuild-complete'||type==='server-entry-reloaded'||type.endsWith('-update'))location.reload();}catch{}};socket.onclose=()=>setTimeout(connect,500);};connect();})();</script>`, buildErrorPage = (framework, pageName, error) => errorPageHtml({
1207
+ }, reloadOnRebuild = () => `<script${nonceAttr()}>(()=>{const url=(location.protocol==='https:'?'wss://':'ws://')+location.host+'/hmr';let seen=false;const connect=()=>{const socket=new WebSocket(url);socket.onopen=()=>{if(seen)location.reload();seen=true;};socket.onmessage=(event)=>{try{const message=JSON.parse(event.data);const type=message&&typeof message.type==='string'?message.type:'';if(type==='rebuild-complete'||type==='server-entry-reloaded'||type.endsWith('-update'))location.reload();}catch{}};socket.onclose=()=>setTimeout(connect,500);};connect();})();</script>`, buildErrorPage = (framework, pageName, error) => errorPageHtml({
1123
1208
  framework,
1124
1209
  hint: "Fix the file and save. This page reloads by itself when the build succeeds.",
1125
1210
  kind: "Build Error",
1126
1211
  message: `${pageName || "This page"} could not be built.
1127
1212
 
1128
1213
  ${error ?? "The dev-server terminal has the build output."}`,
1129
- script: RELOAD_ON_REBUILD
1214
+ script: reloadOnRebuild()
1130
1215
  }), ssrErrorPage = (framework, error) => errorPageHtml({
1131
1216
  framework,
1132
1217
  hint: "A component threw during server-side rendering. Check the terminal for the full stack trace.",
1133
1218
  kind: "Server Render Error",
1134
1219
  message: error instanceof Error ? error.message : String(error)
1135
1220
  });
1221
+ var init_ssrErrorPage = __esm(() => {
1222
+ init_cspNonceRef();
1223
+ });
1136
1224
 
1137
1225
  // src/core/requestContext.ts
1138
1226
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
@@ -1206,6 +1294,7 @@ var REQUEST_STORAGE_KEY, PAGE_WARMER_KEY, isAbsoluteRequestStorage = (value) =>
1206
1294
  return headClose ? head.slice(0, headClose.index) + links + head.slice(headClose.index) : head + links;
1207
1295
  };
1208
1296
  var init_requestContext = __esm(() => {
1297
+ init_ssrErrorPage();
1209
1298
  REQUEST_STORAGE_KEY = Symbol.for("absolutejs.requestAsyncLocalStorage");
1210
1299
  PAGE_WARMER_KEY = Symbol.for("absolutejs.devPageWarmer");
1211
1300
  absoluteRequestContext = new Elysia2({
@@ -1333,13 +1422,13 @@ var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json", ABSO
1333
1422
  }, headerVaryValues, envelopeResponse = (response, status) => new Response(JSON.stringify({
1334
1423
  protocol: ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
1335
1424
  response
1336
- }), { headers: responseHeaders(), status }), isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeJsonValue = (value) => {
1425
+ }), { headers: responseHeaders(), status }), isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeJsonValue = (value) => {
1337
1426
  const serialized = JSON.stringify(value);
1338
1427
  if (serialized === undefined) {
1339
1428
  throw new TypeError("Mobile page props must be JSON-serializable.");
1340
1429
  }
1341
1430
  const parsed = JSON.parse(serialized);
1342
- if (!isRecord(parsed)) {
1431
+ if (!isRecord2(parsed)) {
1343
1432
  throw new TypeError("Mobile page props must serialize to an object.");
1344
1433
  }
1345
1434
  return parsed;
@@ -1369,7 +1458,9 @@ var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json", ABSO
1369
1458
  return createAbsoluteMobilePageErrorResponse(page.pageId);
1370
1459
  }
1371
1460
  }, finalizeAbsoluteNativeRouteDevelopmentPage = (input) => {
1372
- if (false) {}
1461
+ if (!isDevelopmentRuntime()) {
1462
+ return createAbsoluteMobileInvalidRequestResponse("The native-route development representation is disabled outside development.");
1463
+ }
1373
1464
  if (input.request?.method !== "GET") {
1374
1465
  return createAbsoluteMobileInvalidRequestResponse("Native-route data requests must use GET.");
1375
1466
  }
@@ -1711,22 +1802,15 @@ var streamSwapRuntime = () => {
1711
1802
  return value.slice(start + 1, end);
1712
1803
  }, getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
1713
1804
 
1714
- // src/utils/escapeScriptContent.ts
1715
- var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
1716
- const escaped = ESCAPE_LOOKUP[char];
1717
- return escaped !== undefined ? escaped : char;
1718
- });
1719
- var init_escapeScriptContent = __esm(() => {
1720
- ESCAPE_LOOKUP = {
1721
- "\u2028": "\\u2028",
1722
- "\u2029": "\\u2029",
1723
- "<": "\\u003C"
1724
- };
1725
- ESCAPE_REGEX = /[<\u2028\u2029]/g;
1726
- });
1727
-
1728
1805
  // src/utils/streamingSlots.ts
1729
- var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG2 = "</head>", CLOSING_BODY_TAG_LENGTH, CLOSING_HEAD_TAG_LENGTH, CLOSING_PAGE_TAG_REGEX, STREAMING_RUNTIME_GLOBAL = "__ABS_SLOT_ENQUEUE__", STREAMING_PENDING_GLOBAL = "__ABS_SLOT_PENDING__", STREAM_TAIL_LOOKBEHIND = 128, STREAMING_SLOT_TIMEOUT_MS = 5000, STREAMING_SLOT_MAX_PER_RESPONSE = 128, STREAMING_SLOT_MAX_HTML_BYTES = 64000, createSlotPatchStatement = (id, payload) => `(window.${STREAMING_RUNTIME_GLOBAL}||function(i,p){window.${STREAMING_PENDING_GLOBAL}=window.${STREAMING_PENDING_GLOBAL}||{};window.${STREAMING_PENDING_GLOBAL}[i]=p;})(${JSON.stringify(id)},${JSON.stringify(payload)});`, createNonceAttr = (nonce) => nonce ? ` nonce="${nonce}"` : "", createStreamingSlotId = () => `${SLOT_ID_PREFIX}${Math.random().toString(BASE_36_RADIX).slice(2, RANDOM_ID_END_INDEX)}`, getStreamingSlotsRuntimeScript = () => getStreamSwapRuntimeScript(), injectHtmlIntoBody = (html, injection) => {
1806
+ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG2 = "</head>", CLOSING_BODY_TAG_LENGTH, CLOSING_HEAD_TAG_LENGTH, CLOSING_PAGE_TAG_REGEX, STREAMING_RUNTIME_GLOBAL = "__ABS_SLOT_ENQUEUE__", STREAMING_PENDING_GLOBAL = "__ABS_SLOT_PENDING__", STREAM_TAIL_LOOKBEHIND = 128, STREAMING_SLOT_TIMEOUT_MS = 5000, findSafeFlushIndex = (text, cut) => {
1807
+ const head = text.slice(0, cut);
1808
+ const openScript = head.lastIndexOf("<script");
1809
+ const scriptCut = openScript > head.lastIndexOf("</script>") ? openScript : cut;
1810
+ const beforeScript = text.slice(0, scriptCut);
1811
+ const openTag = beforeScript.lastIndexOf("<");
1812
+ return openTag > beforeScript.lastIndexOf(">") ? openTag : scriptCut;
1813
+ }, STREAMING_SLOT_MAX_PER_RESPONSE = 128, STREAMING_SLOT_MAX_HTML_BYTES = 64000, createSlotPatchStatement = (id, payload) => `(window.${STREAMING_RUNTIME_GLOBAL}||function(i,p){window.${STREAMING_PENDING_GLOBAL}=window.${STREAMING_PENDING_GLOBAL}||{};window.${STREAMING_PENDING_GLOBAL}[i]=p;})(${JSON.stringify(id)},${JSON.stringify(payload)});`, createNonceAttr = (nonce) => nonceAttr(nonce), createStreamingSlotId = () => `${SLOT_ID_PREFIX}${Math.random().toString(BASE_36_RADIX).slice(2, RANDOM_ID_END_INDEX)}`, getStreamingSlotsRuntimeScript = () => getStreamSwapRuntimeScript(), injectHtmlIntoBody = (html, injection) => {
1730
1814
  const closingBodyIndex = html.indexOf(CLOSING_BODY_TAG);
1731
1815
  if (closingBodyIndex >= 0) {
1732
1816
  return `${html.slice(0, closingBodyIndex)}${injection}${html.slice(closingBodyIndex)}`;
@@ -1744,7 +1828,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
1744
1828
  getStreamingSlotsRuntimeScript()
1745
1829
  ].filter(Boolean).join(";");
1746
1830
  return `<script${createNonceAttr(nonce)}>${escapeScriptContent(runtimeBody)}</script>`;
1747
- }, toUint8 = (value, encoder) => encoder.encode(value), isRecord2 = (value) => Boolean(value) && typeof value === "object", isSafeHtmlLike = (value) => isRecord2(value) && typeof value.changingThisBreaksApplicationSecurity === "string", normalizeSafeHtml = (value) => {
1831
+ }, toUint8 = (value, encoder) => encoder.encode(value), isRecord3 = (value) => Boolean(value) && typeof value === "object", isSafeHtmlLike = (value) => isRecord3(value) && typeof value.changingThisBreaksApplicationSecurity === "string", normalizeSafeHtml = (value) => {
1748
1832
  if (isSafeHtmlLike(value)) {
1749
1833
  return value.changingThisBreaksApplicationSecurity;
1750
1834
  }
@@ -1805,7 +1889,8 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
1805
1889
  }, createTimeoutError = (slot, timeoutMs) => {
1806
1890
  const error = Object.assign(new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`), { __absTimeout: true });
1807
1891
  return error;
1808
- }, isSlotPatchPayloadObject = (value) => isRecord2(value) && ("html" in value), isTimeoutError = (error) => isRecord2(error) && error.__absTimeout === true, toStreamingSlot = (slot, policy) => ({
1892
+ }, isSlotPatchPayloadObject = (value) => isRecord3(value) && ("html" in value), isTimeoutError = (error) => isRecord3(error) && error.__absTimeout === true, toStreamingSlot = (slot, policy) => ({
1893
+ dynamic: slot.dynamic,
1809
1894
  errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
1810
1895
  fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
1811
1896
  id: slot.id ?? createStreamingSlotId(),
@@ -2030,9 +2115,10 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
2030
2115
  if (tail.length <= STREAM_TAIL_LOOKBEHIND) {
2031
2116
  return tail;
2032
2117
  }
2033
- const content = tail.slice(0, tail.length - STREAM_TAIL_LOOKBEHIND);
2034
- controller.enqueue(encoder.encode(content));
2035
- return tail.slice(-STREAM_TAIL_LOOKBEHIND);
2118
+ const cut = findSafeFlushIndex(tail, tail.length - STREAM_TAIL_LOOKBEHIND);
2119
+ if (cut > 0)
2120
+ controller.enqueue(encoder.encode(tail.slice(0, cut)));
2121
+ return tail.slice(cut);
2036
2122
  };
2037
2123
  const finalizeCompletedBaseWinner = (controller, decodedTail, baseRead) => {
2038
2124
  const footerStart = decodedTail.search(CLOSING_PAGE_TAG_REGEX);
@@ -2265,6 +2351,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
2265
2351
  });
2266
2352
  };
2267
2353
  var init_streamingSlots = __esm(() => {
2354
+ init_cspNonceRef();
2268
2355
  init_constants();
2269
2356
  init_escapeScriptContent();
2270
2357
  CLOSING_BODY_TAG_LENGTH = CLOSING_BODY_TAG.length;
@@ -2279,6 +2366,42 @@ var init_streamingSlots = __esm(() => {
2279
2366
  };
2280
2367
  });
2281
2368
 
2369
+ // src/core/partialPrerender.ts
2370
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
2371
+ import { existsSync, readFileSync } from "fs";
2372
+ import { rm } from "fs/promises";
2373
+ var PARTIAL_HOLES_HEADER = "X-Absolute-Partial-Holes", PARTIAL_SHELL_HEADER = "X-Absolute-Partial-Shell", SINK_STORAGE_KEY, isSinkStorage = (value) => value instanceof AsyncLocalStorage3, getSinkStorage = () => {
2374
+ const existing = Reflect.get(globalThis, SINK_STORAGE_KEY);
2375
+ if (isSinkStorage(existing))
2376
+ return existing;
2377
+ const created = new AsyncLocalStorage3;
2378
+ Reflect.set(globalThis, SINK_STORAGE_KEY, created);
2379
+ return created;
2380
+ }, activePartialHolesSink = () => getSinkStorage().getStore(), collectPartialHoles = async (render) => {
2381
+ const sink = { slots: undefined };
2382
+ const response = await getSinkStorage().run(sink, render);
2383
+ return { response, slots: sink.slots };
2384
+ }, decodePartialHoles = (value) => value ? value.split(",").filter(Boolean).map((id) => decodeURIComponent(id)) : [], encodePartialHoles = (ids) => ids.map((id) => encodeURIComponent(id)).join(","), isDynamicStreamingSlot = (slot) => slot.dynamic === true, isPartialShellCapture = (request) => request?.headers.get(PARTIAL_SHELL_HEADER) === "1", holesPath = (htmlPath) => htmlPath.replace(/\.html$/, ".holes"), readPartialHoles = (htmlPath) => {
2385
+ const path = holesPath(htmlPath);
2386
+ if (!existsSync(path))
2387
+ return [];
2388
+ return decodePartialHoles(readFileSync(path, "utf-8").trim().split(`
2389
+ `).join(","));
2390
+ }, writePartialHoles = async (htmlPath, response) => {
2391
+ const ids = decodePartialHoles(response.headers.get(PARTIAL_HOLES_HEADER));
2392
+ if (ids.length > 0) {
2393
+ await Bun.write(holesPath(htmlPath), `${encodePartialHoles(ids).split(",").join(`
2394
+ `)}
2395
+ `);
2396
+ } else {
2397
+ await rm(holesPath(htmlPath), { force: true });
2398
+ }
2399
+ return ids;
2400
+ };
2401
+ var init_partialPrerender = __esm(() => {
2402
+ SINK_STORAGE_KEY = Symbol.for("absolutejs.partialPrerenderHolesSink");
2403
+ });
2404
+
2282
2405
  // src/core/routeAssets.ts
2283
2406
  var LINK_TAG_RE, REL_STYLESHEET_RE, HREF_RE, TITLE_RE, ENTITIES, ENTITY_RE, decodeEntities = (value) => value.replace(ENTITY_RE, (match) => ENTITIES[match] ?? match), readHeadStylesheets = (head) => {
2284
2407
  if (!head)
@@ -2328,7 +2451,7 @@ var init_browserTranslationAttributes = __esm(() => {
2328
2451
  });
2329
2452
 
2330
2453
  // src/core/browserTranslation.ts
2331
- var BASELINE_MARKER = "__ABSOLUTE_SSR_TEXT_BASELINES__", BROWSER_TRANSLATION_BASELINE_SCRIPT, browserTranslationBaselineTag = () => `<script>${BROWSER_TRANSLATION_BASELINE_SCRIPT}</script>`, injectBrowserTranslationBaseline = (html) => {
2454
+ var BASELINE_MARKER = "__ABSOLUTE_SSR_TEXT_BASELINES__", BROWSER_TRANSLATION_BASELINE_SCRIPT, browserTranslationBaselineTag = () => `<script${nonceAttr()}>${BROWSER_TRANSLATION_BASELINE_SCRIPT}</script>`, injectBrowserTranslationBaseline = (html) => {
2332
2455
  if (html.includes(BASELINE_MARKER))
2333
2456
  return html;
2334
2457
  const script = browserTranslationBaselineTag();
@@ -2338,19 +2461,20 @@ var BASELINE_MARKER = "__ABSOLUTE_SSR_TEXT_BASELINES__", BROWSER_TRANSLATION_BAS
2338
2461
  return `${html.slice(0, closingBodyIndex)}${script}${html.slice(closingBodyIndex)}`;
2339
2462
  };
2340
2463
  var init_browserTranslation = __esm(() => {
2464
+ init_cspNonceRef();
2341
2465
  init_browserTranslationAttributes();
2342
2466
  BROWSER_TRANSLATION_BASELINE_SCRIPT = "window.__ABSOLUTE_SSR_TEXT_BASELINES__=new WeakMap();" + "window.__ABSOLUTE_SSR_ATTRIBUTE_BASELINES__=new WeakMap();" + "{const r=document.body,b=window.__ABSOLUTE_SSR_TEXT_BASELINES__," + "a=window.__ABSOLUTE_SSR_ATTRIBUTE_BASELINES__;" + 'if(r)for(const e of [r,...r.querySelectorAll("*")]){' + "const t=new Map();for(const [i,n]of[...e.childNodes].entries())" + 'if(n.nodeType===3)t.set(i,n.nodeValue??"");if(t.size)b.set(e,t);' + `const v=new Map();for(const k of ${JSON.stringify(TRANSLATABLE_ATTRIBUTES)}){` + "const s=e.getAttribute(k);if(s!==null)v.set(k,s);}if(v.size)a.set(e,v);}}";
2343
2467
  });
2344
2468
 
2345
2469
  // src/cli/scripts/telemetry.ts
2346
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2470
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
2347
2471
  import { homedir } from "os";
2348
2472
  import { join } from "path";
2349
2473
  var configDir, configPath, getTelemetryConfig = () => {
2350
2474
  try {
2351
- if (!existsSync(configPath))
2475
+ if (!existsSync2(configPath))
2352
2476
  return null;
2353
- const raw = readFileSync(configPath, "utf-8");
2477
+ const raw = readFileSync2(configPath, "utf-8");
2354
2478
  const config = JSON.parse(raw);
2355
2479
  return config;
2356
2480
  } catch {
@@ -2363,14 +2487,14 @@ var init_telemetry = __esm(() => {
2363
2487
  });
2364
2488
 
2365
2489
  // src/cli/telemetryEvent.ts
2366
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
2490
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
2367
2491
  import { arch, platform } from "os";
2368
2492
  import { dirname as dirname3, join as join2, parse } from "path";
2369
2493
  var checkCandidate = (candidate) => {
2370
- if (!existsSync2(candidate)) {
2494
+ if (!existsSync3(candidate)) {
2371
2495
  return null;
2372
2496
  }
2373
- const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
2497
+ const pkg = JSON.parse(readFileSync3(candidate, "utf-8"));
2374
2498
  if (pkg.name === "@absolutejs/absolute") {
2375
2499
  const ver = pkg.version;
2376
2500
  return ver;
@@ -2424,17 +2548,17 @@ var init_telemetryEvent = __esm(() => {
2424
2548
  });
2425
2549
 
2426
2550
  // src/dev/buildHMRClient.ts
2427
- import { existsSync as existsSync3 } from "fs";
2551
+ import { existsSync as existsSync4 } from "fs";
2428
2552
  import { resolve as resolve2 } from "path";
2429
2553
  var {build: bunBuild } = globalThis.Bun;
2430
2554
  var resolveHmrClientPath = () => {
2431
2555
  const projectRoot = process.cwd();
2432
2556
  const fromSource = resolve2(import.meta.dir, "client/hmrClient.ts");
2433
- if (existsSync3(fromSource) && fromSource.startsWith(projectRoot)) {
2557
+ if (existsSync4(fromSource) && fromSource.startsWith(projectRoot)) {
2434
2558
  return fromSource;
2435
2559
  }
2436
2560
  const fromNodeModules = resolve2(projectRoot, "node_modules/@absolutejs/absolute/dist/dev/client/hmrClient.ts");
2437
- if (existsSync3(fromNodeModules))
2561
+ if (existsSync4(fromNodeModules))
2438
2562
  return fromNodeModules;
2439
2563
  return resolve2(import.meta.dir, "dev/client/hmrClient.ts");
2440
2564
  }, hmrClientPath, buildHMRClient = async () => {
@@ -2464,6 +2588,8 @@ var init_buildHMRClient = __esm(() => {
2464
2588
  });
2465
2589
 
2466
2590
  // src/vue/pageHandler.ts
2591
+ init_escapeScriptContent();
2592
+ init_cspNonceRef();
2467
2593
  init_inlinePageCss();
2468
2594
  init_spaRouteCss();
2469
2595
  init_spaRouteManifest();
@@ -2476,6 +2602,8 @@ init_pageResponseCache();
2476
2602
  // src/core/responseEnhancers.ts
2477
2603
  init_streamingSlots();
2478
2604
  init_pageResponseCache();
2605
+ init_partialPrerender();
2606
+ init_requestContext();
2479
2607
 
2480
2608
  // src/core/streamingSlotRegistrar.ts
2481
2609
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
@@ -2518,7 +2646,7 @@ var setStreamingSlotWarningController = (controller) => {
2518
2646
  Reflect.set(globalThis, STREAMING_SLOT_WARNING_STORAGE_KEY, controller);
2519
2647
  };
2520
2648
  var warnMissingStreamingSlotCollector = (primitiveName) => {
2521
- if (isStreamingSlotCollectionActive()) {
2649
+ if (isProductionRuntime() || isStreamingSlotCollectionActive()) {
2522
2650
  return;
2523
2651
  }
2524
2652
  getWarningController()?.maybeWarn(primitiveName);
@@ -2626,18 +2754,51 @@ var mergeStreamingSlots = (registered, explicit) => {
2626
2754
  merged.set(slot.id, slot);
2627
2755
  return [...merged.values()];
2628
2756
  };
2757
+ var captureStaticShell = async (responseLike, slots, options) => {
2758
+ const holes = slots.filter(isDynamicStreamingSlot);
2759
+ const staticSlots = slots.filter((slot) => !isDynamicStreamingSlot(slot));
2760
+ const response = await withStreamingSlots(responseLike, {
2761
+ ...options,
2762
+ streamingSlots: staticSlots
2763
+ });
2764
+ if (holes.length === 0 || !response.body)
2765
+ return response;
2766
+ const headers = cloneHeaders(response);
2767
+ headers.set(PARTIAL_HOLES_HEADER, encodePartialHoles(holes.map((slot) => slot.id)));
2768
+ const body = staticSlots.length > 0 ? response.body : injectStreamingRuntimeIntoStream(response.body, options.nonce, options.runtimePlacement, options.runtimePreludeScript);
2769
+ return new Response(body, {
2770
+ headers,
2771
+ status: response.status,
2772
+ statusText: response.statusText
2773
+ });
2774
+ };
2775
+ var handOverHoles = async (responseLike, slots, sink) => {
2776
+ sink.slots = slots.filter(isDynamicStreamingSlot);
2777
+ const response = await toResponse(responseLike);
2778
+ await response.body?.cancel().catch(() => {
2779
+ return;
2780
+ });
2781
+ return new Response(null, { status: 204 });
2782
+ };
2629
2783
  var withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
2630
2784
  const { result, slots } = await runWithStreamingSlotRegistry(renderResponse);
2631
2785
  const explicit = options.streamingSlots ?? [];
2786
+ const streamingSlots = mergeStreamingSlots(slots, explicit);
2787
+ const holesSink = activePartialHolesSink();
2788
+ if (holesSink)
2789
+ return handOverHoles(result, streamingSlots, holesSink);
2790
+ if (isPartialShellCapture(getCurrentAbsoluteRequest())) {
2791
+ return captureStaticShell(result, streamingSlots, options);
2792
+ }
2632
2793
  return withStreamingSlots(result, {
2633
2794
  ...options,
2634
- streamingSlots: mergeStreamingSlots(slots, explicit)
2795
+ streamingSlots
2635
2796
  });
2636
2797
  };
2637
2798
 
2638
2799
  // src/core/streamingSlotWarningScope.ts
2639
2800
  init_logger();
2640
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
2801
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
2641
2802
  var STREAMING_SLOT_WARNING_STORAGE_KEY2 = Symbol.for("absolutejs.streamingSlotWarningAsyncLocalStorage");
2642
2803
  var isObjectRecord4 = (value) => Boolean(value) && typeof value === "object";
2643
2804
  var isAsyncLocalStorage3 = (value) => isObjectRecord4(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
@@ -2653,7 +2814,7 @@ var ensureWarningStorage = () => {
2653
2814
  if (existing) {
2654
2815
  return existing;
2655
2816
  }
2656
- const storage = new AsyncLocalStorage3;
2817
+ const storage = new AsyncLocalStorage4;
2657
2818
  Reflect.set(globalThis, STREAMING_SLOT_WARNING_STORAGE_KEY2, storage);
2658
2819
  return storage;
2659
2820
  };
@@ -2684,7 +2845,9 @@ setStreamingSlotWarningController({
2684
2845
  }
2685
2846
  });
2686
2847
  var captureStreamingSlotWarningCallsite = () => {
2687
- if (false) {}
2848
+ if (isProductionRuntime()) {
2849
+ return;
2850
+ }
2688
2851
  const { stack } = new Error;
2689
2852
  if (!stack) {
2690
2853
  return;
@@ -2694,6 +2857,7 @@ var captureStreamingSlotWarningCallsite = () => {
2694
2857
  var runWithStreamingSlotWarningScope = (task, metadata) => ensureWarningStorage().run({ handlerCallsite: metadata?.handlerCallsite, hasWarned: false }, task);
2695
2858
 
2696
2859
  // src/vue/pageHandler.ts
2860
+ init_ssrErrorPage();
2697
2861
  init_resolveConvention();
2698
2862
  init_routeAssets();
2699
2863
 
@@ -2737,23 +2901,87 @@ var ABSOLUTE_TELEPORT_TARGET = `#${ABSOLUTE_TELEPORT_TARGET_ID}`;
2737
2901
 
2738
2902
  // src/vue/pageHandler.ts
2739
2903
  init_browserTranslation();
2740
- var isRecord3 = (value) => typeof value === "object" && value !== null;
2741
- var isGenericVueComponent = (value) => typeof value === "function" || isRecord3(value);
2904
+
2905
+ // src/vue/serverDataPayload.ts
2906
+ init_cspNonceRef();
2907
+ init_escapeScriptContent();
2908
+ var SERVER_DATA_CONTEXT_KEY = "__absoluteServerData";
2909
+ var SERVER_DATA_GLOBAL = "__ABSOLUTE_SERVER_DATA__";
2910
+ var GENERIC_ERROR_MESSAGE = "Loading server data failed.";
2911
+ var toPublicError = (cause) => {
2912
+ const detail = cause instanceof Error ? cause.message : String(cause);
2913
+ const publicError = new Error(isProductionRuntime() ? GENERIC_ERROR_MESSAGE : detail);
2914
+ publicError.name = cause instanceof Error ? cause.name : "Error";
2915
+ return publicError;
2916
+ };
2917
+ var claimServerDataKey = (collector, key) => {
2918
+ if (!collector.claimed.has(key)) {
2919
+ collector.claimed.add(key);
2920
+ return true;
2921
+ }
2922
+ const message = `useServerData: the key "${key}" is used more than once while rendering this page. Each useServerData() call in one request needs its own key \u2014 include the component's identity (for example an id or route param) in the key.`;
2923
+ if (isProductionRuntime()) {
2924
+ console.warn(`${message} The repeated call will load in the browser.`);
2925
+ } else {
2926
+ collector.failure ??= new Error(message);
2927
+ }
2928
+ return false;
2929
+ };
2930
+ var createServerDataCollector = () => {
2931
+ const collector = {
2932
+ claimed: new Set,
2933
+ failure: null,
2934
+ json: new Map
2935
+ };
2936
+ return collector;
2937
+ };
2938
+ var isServerDataCollector = (value) => typeof value === "object" && value !== null && ("claimed" in value) && value.claimed instanceof Set && ("failure" in value) && (value.failure === null || value.failure instanceof Error) && ("json" in value) && value.json instanceof Map;
2939
+ var serializeServerDataScript = (collector) => {
2940
+ if (!collector || collector.json.size === 0)
2941
+ return "";
2942
+ const members = [...collector.json].map(([key, json]) => `${JSON.stringify(key)}:${json}`);
2943
+ return `<script${nonceAttr()}>window.${SERVER_DATA_GLOBAL}=${escapeScriptContent(`{${members.join(",")}}`)}</script>`;
2944
+ };
2945
+ var storeServerDataError = (collector, key, cause) => {
2946
+ console.error(`[SSR] useServerData("${key}") failed:`, cause);
2947
+ const publicError = toPublicError(cause);
2948
+ const { message, name } = publicError;
2949
+ collector.json.set(key, JSON.stringify({ error: { message, name } }));
2950
+ return publicError;
2951
+ };
2952
+ var storeServerDataValue = (collector, key, value) => {
2953
+ try {
2954
+ collector.json.set(key, `{"data":${JSON.stringify(value) ?? "null"}}`);
2955
+ return null;
2956
+ } catch (cause) {
2957
+ const reason = cause instanceof Error ? cause.message : String(cause);
2958
+ const failure = new Error(`useServerData: the value for "${key}" cannot be serialized to JSON (${reason}).`);
2959
+ return storeServerDataError(collector, key, failure);
2960
+ }
2961
+ };
2962
+ var throwServerDataFailure = (collector) => {
2963
+ if (collector.failure)
2964
+ throw collector.failure;
2965
+ };
2966
+
2967
+ // src/vue/pageHandler.ts
2968
+ var isRecord4 = (value) => typeof value === "object" && value !== null;
2969
+ var isGenericVueComponent = (value) => typeof value === "function" || isRecord4(value);
2742
2970
  var readHasIslands = (value) => {
2743
- if (!isRecord3(value))
2971
+ if (!isRecord4(value))
2744
2972
  return false;
2745
2973
  const hasIslands = value["__ABSOLUTE_PAGE_HAS_ISLANDS__"];
2746
2974
  return typeof hasIslands === "boolean" ? hasIslands : false;
2747
2975
  };
2748
2976
  var isVueSetupApp = (value) => typeof value === "function";
2749
2977
  var readSetupAppHook = (value) => {
2750
- if (!isRecord3(value))
2978
+ if (!isRecord4(value))
2751
2979
  return null;
2752
2980
  const { setupApp } = value;
2753
2981
  return isVueSetupApp(setupApp) ? setupApp : null;
2754
2982
  };
2755
- var readHasSpaRoutes = (value) => isRecord3(value) && Array.isArray(value["routes"]);
2756
- var readDefaultExport = (value) => isRecord3(value) ? value.default : undefined;
2983
+ var readHasSpaRoutes = (value) => isRecord4(value) && Array.isArray(value["routes"]);
2984
+ var readDefaultExport = (value) => isRecord4(value) ? value.default : undefined;
2757
2985
  var resolveRequestRenderUrl = (request) => {
2758
2986
  if (!request)
2759
2987
  return "/";
@@ -2769,17 +2997,16 @@ var primeVueStream = async (stream) => {
2769
2997
  const firstChunk = await reader.read();
2770
2998
  return { firstChunk, reader };
2771
2999
  };
2772
- var cachedSsrOnlyHmrShim = null;
2773
- var buildSsrOnlyHmrShim = async () => {
3000
+ var cachedSsrOnlyHmrBundle = null;
3001
+ var loadSsrOnlyHmrBundle = async () => {
2774
3002
  await Promise.resolve().then(() => init_buildHMRClient());
2775
- const bundle = await buildHMRClient();
2776
- return `<script>window.__HMR_FRAMEWORK__="vue";</script><script data-hmr-client>${bundle}</script>`;
3003
+ return buildHMRClient();
2777
3004
  };
2778
- var getSsrOnlyHmrShim = () => {
2779
- if (cachedSsrOnlyHmrShim)
2780
- return cachedSsrOnlyHmrShim;
2781
- cachedSsrOnlyHmrShim = buildSsrOnlyHmrShim();
2782
- return cachedSsrOnlyHmrShim;
3005
+ var getSsrOnlyHmrShim = async () => {
3006
+ cachedSsrOnlyHmrBundle ??= loadSsrOnlyHmrBundle();
3007
+ const bundle = await cachedSsrOnlyHmrBundle;
3008
+ const nonce = nonceAttr();
3009
+ return `<script${nonce}>window.__HMR_FRAMEWORK__="vue";</script><script${nonce} data-hmr-client>${bundle}</script>`;
2783
3010
  };
2784
3011
  var handleVuePageRequest = async (input) => {
2785
3012
  const passedPageComponent = input.Page;
@@ -2901,13 +3128,17 @@ var handleVuePageRequest = async (input) => {
2901
3128
  status: 404
2902
3129
  });
2903
3130
  }
2904
- const ssrContext = {};
3131
+ const serverData = createServerDataCollector();
3132
+ const ssrContext = {
3133
+ [SERVER_DATA_CONTEXT_KEY]: serverData
3134
+ };
2905
3135
  const head = `<!DOCTYPE html><html>${resolvedHeadTag}<body><div id="root">`;
2906
- const ssrOnlyHmrShim = clientMode === "none" ? await getSsrOnlyHmrShim() : "";
3136
+ const ssrOnlyHmrShim = clientMode === "none" && isDevelopmentRuntime() ? await getSsrOnlyHmrShim() : "";
2907
3137
  const buildTail = () => {
3138
+ throwServerDataFailure(serverData);
2908
3139
  const teleports = ssrContext.teleports?.[ABSOLUTE_TELEPORT_TARGET] ?? "";
2909
3140
  const teleportHost = `<div id="${ABSOLUTE_TELEPORT_TARGET_ID}">${teleports}</div>`;
2910
- return clientMode === "none" ? `</div>${teleportHost}${ssrOnlyHmrShim}</body></html>` : `</div>${teleportHost}<script>${BROWSER_TRANSLATION_BASELINE_SCRIPT}window.__INITIAL_PROPS__=${JSON.stringify(maybeProps ?? {})}</script><script type="module" src="${resolvedIndexPath}"></script></body></html>`;
3141
+ return clientMode === "none" ? `</div>${teleportHost}${ssrOnlyHmrShim}</body></html>` : `</div>${teleportHost}<script${nonceAttr()}>${BROWSER_TRANSLATION_BASELINE_SCRIPT}window.__INITIAL_PROPS__=${escapeScriptContent(JSON.stringify(maybeProps ?? {}))}</script>${serializeServerDataScript(serverData)}<script${nonceAttr()} type="module" src="${resolvedIndexPath}"></script></body></html>`;
2911
3142
  };
2912
3143
  if (resolvedPage.hasSpaRoutes && clientMode === "auto") {
2913
3144
  return new Response(`${head}${buildTail()}`, {
@@ -2990,5 +3221,5 @@ export {
2990
3221
  handleVuePageRequest
2991
3222
  };
2992
3223
 
2993
- //# debugId=49A4A37141A1E21564756E2164756E21
3224
+ //# debugId=EE8A9B61855702DE64756E2164756E21
2994
3225
  //# sourceMappingURL=server.js.map