@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,6 +72,20 @@ var __esm = (fn, res, err) => () => {
72
72
  };
73
73
  var __require = import.meta.require;
74
74
 
75
+ // src/utils/cspNonceRef.ts
76
+ 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 = () => {
77
+ const getter = Reflect.get(globalThis, GETTER_KEY);
78
+ if (typeof getter !== "function")
79
+ return;
80
+ const nonce = getter();
81
+ return typeof nonce === "string" ? nonce : undefined;
82
+ }, registerCspNonceGetter = (getter) => {
83
+ Reflect.set(globalThis, GETTER_KEY, getter);
84
+ };
85
+ var init_cspNonceRef = __esm(() => {
86
+ GETTER_KEY = Symbol.for("absolutejs.cspNonceGetter");
87
+ });
88
+
75
89
  // src/build/resolvePackageImport.ts
76
90
  import { resolve, join } from "path";
77
91
  import { existsSync, readFileSync } from "fs";
@@ -220,47 +234,140 @@ var init_lowerIslandSyntax = __esm(() => {
220
234
  });
221
235
 
222
236
  // src/svelte/lowerAwaitSlotSyntax.ts
223
- var AWAIT_BLOCK_RE, escapeTemplateLiteral = (value) => value.replaceAll("\\", "\\\\").replaceAll("`", "\\`").replaceAll("${", "\\${"), markupToTemplateLiteral = (markup) => {
224
- const escaped = escapeTemplateLiteral(markup.trim());
225
- const withExpressions = escaped.replace(/\{([^{}]+)\}/g, (_, expression) => `\${${String(expression).trim()}}`);
226
- return `\`${withExpressions}\``;
227
- }, lowerSvelteAwaitSlotSyntax = (source) => {
228
- if (!source.includes("{#await")) {
237
+ var AWAIT_STREAM_DIRECTIVE = "<!-- absolute:stream -->", DIRECTIVE_RE, BRANCH_TAG_RE, SVELTE_ONLY_MARKUP_RE, QUOTES, scanCharacter = (scan, char) => {
238
+ if (scan.escaped) {
239
+ scan.escaped = false;
240
+ return;
241
+ }
242
+ if (scan.quote) {
243
+ scan.escaped = char === "\\";
244
+ if (char === scan.quote)
245
+ scan.quote = null;
246
+ return;
247
+ }
248
+ if (QUOTES.has(char))
249
+ scan.quote = char;
250
+ if (char === "{")
251
+ scan.depth += 1;
252
+ if (char === "}")
253
+ scan.depth -= 1;
254
+ }, findTagEnd = (source, start) => {
255
+ const scan = { depth: 0, escaped: false, quote: null };
256
+ for (let index = start;index < source.length; index += 1) {
257
+ scanCharacter(scan, source[index] ?? "");
258
+ if (scan.depth === 0)
259
+ return index + 1;
260
+ }
261
+ return -1;
262
+ }, topLevelTags = (markup) => {
263
+ const tags = [];
264
+ let index = markup.indexOf("{");
265
+ while (index !== -1) {
266
+ const end = findTagEnd(markup, index);
267
+ if (end === -1)
268
+ break;
269
+ tags.push({ end, start: index, text: markup.slice(index, end) });
270
+ index = markup.indexOf("{", end);
271
+ }
272
+ return tags;
273
+ }, escapeTemplateLiteral = (value) => value.replaceAll("\\", "\\\\").replaceAll("`", "\\`").replaceAll("${", "\\${"), markupToTemplateLiteral = (markup) => {
274
+ const parts = topLevelTags(markup.trim());
275
+ const trimmed = markup.trim();
276
+ let cursor = 0;
277
+ let literal = "";
278
+ for (const { end, start, text } of parts) {
279
+ literal += escapeTemplateLiteral(trimmed.slice(cursor, start));
280
+ literal += `\${${text.slice(1, -1).trim()}}`;
281
+ cursor = end;
282
+ }
283
+ literal += escapeTemplateLiteral(trimmed.slice(cursor));
284
+ return `\`${literal}\``;
285
+ }, fail = (filePath, message) => {
286
+ throw new Error(`${filePath ? `${filePath}: ` : ""}${message} (${AWAIT_STREAM_DIRECTIVE} streams plain HTML; remove the directive to let Svelte render the block and hydrate it)`);
287
+ }, assertPlainHtml = (markup, branch, filePath) => {
288
+ const withoutExpressions = topLevelTags(markup).reduceRight((text, { end, start }) => text.slice(0, start) + text.slice(end), markup);
289
+ const nestedTag = topLevelTags(markup).find(({ text }) => /^\{[#:/@]/.test(text));
290
+ if (nestedTag || SVELTE_ONLY_MARKUP_RE.test(withoutExpressions)) {
291
+ fail(filePath, `the ${branch} branch of a streamed {#await} holds Svelte markup (${nestedTag?.text ?? withoutExpressions.match(SVELTE_ONLY_MARKUP_RE)?.[0]}\u2026)`);
292
+ }
293
+ }, parseStreamedAwait = (source, start, filePath) => {
294
+ if (!source.startsWith("{#await", start)) {
295
+ fail(filePath, `${AWAIT_STREAM_DIRECTIVE} must come directly before an {#await} block`);
296
+ }
297
+ const headerEnd = findTagEnd(source, start);
298
+ if (headerEnd === -1)
299
+ fail(filePath, "unterminated {#await} tag");
300
+ const expression = source.slice(start + "{#await".length, headerEnd - 1).trim();
301
+ if (!expression)
302
+ fail(filePath, "{#await} without an expression");
303
+ if (/\s(?:then|catch)\b/.test(` ${expression}`)) {
304
+ fail(filePath, "a streamed {#await} needs a pending branch; the shorthand {#await \u2026 then \u2026} has none");
305
+ }
306
+ const close = source.indexOf("{/await}", headerEnd);
307
+ if (close === -1)
308
+ fail(filePath, "{#await} without a matching {/await}");
309
+ const body = source.slice(headerEnd, close);
310
+ const branchTags = topLevelTags(body).filter(({ text }) => /^\{:/.test(text));
311
+ const [thenTag, catchTag, extra] = branchTags;
312
+ const thenMatch = thenTag?.text.match(BRANCH_TAG_RE);
313
+ const catchMatch = catchTag?.text.match(BRANCH_TAG_RE);
314
+ if (!thenTag || thenMatch?.[1] !== "then" || catchTag && catchMatch?.[1] !== "catch" || extra) {
315
+ fail(filePath, "a streamed {#await} takes exactly one {:then} and at most one {:catch}, in that order");
316
+ }
317
+ const pendingMarkup = body.slice(0, thenTag?.start);
318
+ const thenMarkup = body.slice(thenTag?.end, catchTag?.start);
319
+ const catchMarkup = catchTag ? body.slice(catchTag.end) : undefined;
320
+ assertPlainHtml(pendingMarkup, "pending", filePath);
321
+ assertPlainHtml(thenMarkup, "then", filePath);
322
+ if (catchMarkup !== undefined)
323
+ assertPlainHtml(catchMarkup, "catch", filePath);
324
+ return {
325
+ catchIdentifier: catchMatch?.[2],
326
+ catchMarkup,
327
+ end: close + "{/await}".length,
328
+ expression,
329
+ pendingMarkup,
330
+ thenIdentifier: thenMatch?.[2],
331
+ thenMarkup
332
+ };
333
+ }, renderSlot = (block, slotId, dynamic) => {
334
+ const thenValueIdentifier = block.thenIdentifier ?? "__awaitValue";
335
+ const catchValueIdentifier = block.catchIdentifier ?? "__awaitError";
336
+ const catchBranch = block.catchMarkup === undefined ? "catch (_absoluteAwaitError) { throw _absoluteAwaitError; }" : `catch (${catchValueIdentifier}) { return ${markupToTemplateLiteral(block.catchMarkup)}; }`;
337
+ return `<AbsoluteAwaitSlot id="${slotId}"${dynamic ? " dynamic" : ""} fallbackHtml={${markupToTemplateLiteral(block.pendingMarkup)}} resolve={async () => { try { const ${thenValueIdentifier} = await (${block.expression}); return ${markupToTemplateLiteral(block.thenMarkup)}; } ${catchBranch} }} />`;
338
+ }, IMPORT_LINE = 'import AbsoluteAwaitSlot from "@absolutejs/absolute/svelte/components/AwaitSlot.svelte";', lowerSvelteAwaitSlotSyntax = (source, filePath) => {
339
+ if (!source.includes("absolute:stream")) {
229
340
  return { code: source, transformed: false };
230
341
  }
342
+ let lowered = "";
343
+ let cursor = 0;
231
344
  let awaitIndex = 0;
232
- let transformed = false;
233
- const lowered = source.replace(AWAIT_BLOCK_RE, (fullMatch, awaitExpression, pendingMarkup, thenIdentifier, thenMarkup, catchIdentifier, catchMarkup) => {
234
- const trimmedAwaitExpression = awaitExpression.trim();
235
- if (!trimmedAwaitExpression) {
236
- return fullMatch;
237
- }
345
+ for (const directive of source.matchAll(DIRECTIVE_RE)) {
346
+ const awaitStart = directive.index + directive[0].length;
347
+ if (awaitStart < cursor)
348
+ continue;
349
+ const block = parseStreamedAwait(source, awaitStart, filePath);
238
350
  const slotId = `absolute-svelte-await-${awaitIndex.toString(BASE_36_RADIX)}`;
239
351
  awaitIndex += 1;
240
- transformed = true;
241
- const thenValueIdentifier = thenIdentifier?.trim() || "__awaitValue";
242
- const catchValueIdentifier = catchIdentifier?.trim() || "__awaitError";
243
- const fallbackHtml = markupToTemplateLiteral(pendingMarkup);
244
- const resolvedHtml = markupToTemplateLiteral(thenMarkup);
245
- const rejectedHtml = typeof catchMarkup === "string" ? markupToTemplateLiteral(catchMarkup) : null;
246
- const catchBranch = rejectedHtml ? `catch (${catchValueIdentifier}) { return ${rejectedHtml}; }` : "catch (_absoluteAwaitError) { throw _absoluteAwaitError; }";
247
- return `<AbsoluteAwaitSlot id="${slotId}" fallbackHtml={${fallbackHtml}} resolve={async () => { try { const ${thenValueIdentifier} = await (${trimmedAwaitExpression}); return ${resolvedHtml}; } ${catchBranch} }} />`;
248
- });
249
- if (!transformed) {
352
+ lowered += source.slice(cursor, directive.index);
353
+ lowered += renderSlot(block, slotId, directive[1] !== undefined);
354
+ cursor = block.end;
355
+ }
356
+ if (awaitIndex === 0) {
250
357
  return { code: source, transformed: false };
251
358
  }
252
- const importLine = 'import AbsoluteAwaitSlot from "@absolutejs/absolute/svelte/components/AwaitSlot.svelte";';
359
+ lowered += source.slice(cursor);
253
360
  if (lowered.includes("<script")) {
254
361
  return {
255
362
  code: lowered.replace(/<script(\s[^>]*)?>/, (match) => `${match}
256
- ${importLine}
363
+ ${IMPORT_LINE}
257
364
  `),
258
365
  transformed: true
259
366
  };
260
367
  }
261
368
  return {
262
369
  code: `<script lang="ts">
263
- ${importLine}
370
+ ${IMPORT_LINE}
264
371
  </script>
265
372
  ${lowered}`,
266
373
  transformed: true
@@ -268,9 +375,15 @@ ${lowered}`,
268
375
  };
269
376
  var init_lowerAwaitSlotSyntax = __esm(() => {
270
377
  init_constants();
271
- AWAIT_BLOCK_RE = /\{#await\s+([^}]+)\}([\s\S]*?)\{:then(?:\s+([A-Za-z_$][\w$]*))?\}([\s\S]*?)(?:\{:catch(?:\s+([A-Za-z_$][\w$]*))?\}([\s\S]*?))?\{\/await\}/g;
378
+ DIRECTIVE_RE = /<!--\s*absolute:stream(\s+dynamic)?\s*-->\s*/g;
379
+ BRANCH_TAG_RE = /^\{:(then|catch)(?:\s+([A-Za-z_$][\w$]*))?\s*\}$/;
380
+ SVELTE_ONLY_MARKUP_RE = /\{[#:/@]|<[A-Z]|<svelte:/;
381
+ QUOTES = new Set(['"', "'", "`"]);
272
382
  });
273
383
 
384
+ // src/utils/runtimeMode.ts
385
+ var ENV_VAR = "NODE_ENV", getNodeEnv = () => process.env[ENV_VAR], isDevelopmentRuntime = () => process.env[ENV_VAR] === "development", isProductionRuntime = () => process.env[ENV_VAR] === "production";
386
+
274
387
  // src/build/stylePreprocessor.ts
275
388
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
276
389
  import { readFile } from "fs/promises";
@@ -460,7 +573,7 @@ ${contents}` : contents, normalizePostcssModule = (mod) => {
460
573
  const config = normalizePostcssModule(loaded);
461
574
  const value = typeof config === "function" ? await config({
462
575
  cwd: process.cwd(),
463
- env: "development"
576
+ env: getNodeEnv()
464
577
  }) : config;
465
578
  return normalizePostcssModule(value) ?? {};
466
579
  }, normalizePostcssPlugins = (plugins) => {
@@ -826,10 +939,10 @@ ${contents}` : contents, normalizePostcssModule = (mod) => {
826
939
  return resolveCssImportsSync(result.css, dirname(filePath), new Set([filePath]));
827
940
  }
828
941
  if (language === "less") {
829
- throw new Error(`Unable to compile ${filePath}: Less styleUrl preprocessing is async-only. Import the Less file from a bundled entrypoint or use SCSS/CSS for Angular styleUrl.`);
942
+ throw new Error(`Unable to compile ${filePath} synchronously: Less only has an async compiler. Compile it with compileStyleFileIfNeeded() instead.`);
830
943
  }
831
944
  if (language === "stylus") {
832
- throw new Error(`Unable to compile ${filePath}: Stylus styleUrl preprocessing is async-only. Import the Stylus file from a bundled entrypoint or use SCSS/CSS for Angular styleUrl.`);
945
+ throw new Error(`Unable to compile ${filePath} synchronously: Stylus only has an async compiler. Compile it with compileStyleFileIfNeeded() instead.`);
833
946
  }
834
947
  return resolveCssImportsSync(rawContents, dirname(filePath), new Set([filePath]));
835
948
  };
@@ -847,6 +960,32 @@ var init_stylePreprocessor = __esm(() => {
847
960
  CSS_IMPORT_PATTERN = /@import\s+["']([^"']+)["']\s*;?/g;
848
961
  });
849
962
 
963
+ // src/svelte/router/lazyModule.ts
964
+ var LAZY_RESOLVED_KEY, LAZY_SOURCE_EXPORT = "__ABSOLUTE_SVELTE_SOURCE__", isRecord = (value) => typeof value === "object" && value !== null, isComponent = (value) => typeof value === "function", toLazyComponent = (value) => {
965
+ if (isComponent(value))
966
+ return value;
967
+ if (!isRecord(value))
968
+ return;
969
+ const fallback = value.default;
970
+ return isComponent(fallback) ? fallback : undefined;
971
+ }, readSourceFrom = (value) => {
972
+ if (!isRecord(value) && !isComponent(value))
973
+ return;
974
+ const source = Reflect.get(value, LAZY_SOURCE_EXPORT);
975
+ return typeof source === "string" ? source : undefined;
976
+ }, lazyModuleRegistration = (sourceId, specifier) => `
977
+ ;(globalThis[Symbol.for("absolutejs.svelte.lazy-modules")] ??= new Map()).set(${JSON.stringify(sourceId)}, () => import(${JSON.stringify(specifier)}));`, readLazySource = (value) => {
978
+ const fromValue = readSourceFrom(value);
979
+ if (fromValue !== undefined)
980
+ return fromValue;
981
+ if (!isRecord(value))
982
+ return;
983
+ return readSourceFrom(value.default);
984
+ };
985
+ var init_lazyModule = __esm(() => {
986
+ LAZY_RESOLVED_KEY = Symbol.for("absolutejs.svelte.lazy-resolved");
987
+ });
988
+
850
989
  // src/core/svelteServerModule.ts
851
990
  import { mkdir, readdir } from "fs/promises";
852
991
  import { basename, dirname as dirname2, extname as extname2, join as join3, relative as relative2, resolve as resolve3 } from "path";
@@ -956,11 +1095,11 @@ var serverCacheRoot, compiledModuleCache, originalSourcePathCache, transpiler, e
956
1095
  const resolutionSourcePath = await resolveOriginalSourcePath(sourcePath);
957
1096
  const source = await Bun.file(sourcePath).text();
958
1097
  const { compile, preprocess } = await import("svelte/compiler");
959
- const loweredAwaitSource = lowerSvelteAwaitSlotSyntax(source);
1098
+ const loweredAwaitSource = lowerSvelteAwaitSlotSyntax(source, sourcePath);
960
1099
  const loweredSource = lowerSvelteIslandSyntax(loweredAwaitSource.code, "server");
961
1100
  const preprocessed = await preprocess(loweredSource.code, createSvelteStylePreprocessor());
962
1101
  let transpiled = sourcePath.endsWith(".ts") || sourcePath.endsWith(".svelte.ts") ? transpiler.transformSync(preprocessed.code) : preprocessed.code;
963
- const childImportSpecs = Array.from(transpiled.matchAll(/from\s+['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((value) => value !== undefined);
1102
+ const childImportSpecs = Array.from(new Set(Array.from(transpiled.matchAll(/(?:from\s+|\bimport\s*\(\s*)['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((value) => value !== undefined)));
964
1103
  const resolvedChildModules = await Promise.all(childImportSpecs.map((spec) => resolveSvelteImport(spec, resolutionSourcePath)));
965
1104
  const resolvedModuleImports = await Promise.all(childImportSpecs.map((spec) => resolveRelativeModule(spec, resolutionSourcePath)));
966
1105
  const childModulePaths = new Map;
@@ -1007,6 +1146,14 @@ var serverCacheRoot, compiledModuleCache, originalSourcePathCache, transpiler, e
1007
1146
  for (const [spec, resolvedModuleImport] of rewrittenModulePaths) {
1008
1147
  compiledCode = compiledCode.replaceAll(spec, resolvedModuleImport);
1009
1148
  }
1149
+ const sourceId = JSON.stringify(relative2(process.cwd(), resolutionSourcePath).replace(/\\/g, "/"));
1150
+ const componentName = /export default function ([\w$]+)\s*\(/.exec(compiledCode)?.[1];
1151
+ compiledCode += `
1152
+ export const ${LAZY_SOURCE_EXPORT} = ${sourceId};`;
1153
+ if (componentName) {
1154
+ compiledCode += `
1155
+ ${componentName}.${LAZY_SOURCE_EXPORT} = ${sourceId};`;
1156
+ }
1010
1157
  const compiledModulePath = getCachedModulePath(sourcePath);
1011
1158
  await mkdir(dirname2(compiledModulePath), { recursive: true });
1012
1159
  await writeIfChanged(compiledModulePath, compiledCode);
@@ -1018,6 +1165,7 @@ var init_svelteServerModule = __esm(() => {
1018
1165
  init_lowerIslandSyntax();
1019
1166
  init_lowerAwaitSlotSyntax();
1020
1167
  init_stylePreprocessor();
1168
+ init_lazyModule();
1021
1169
  serverCacheRoot = join3(process.cwd(), ".absolutejs", "islands", "svelte");
1022
1170
  compiledModuleCache = new Map;
1023
1171
  originalSourcePathCache = new Map;
@@ -1027,6 +1175,20 @@ var init_svelteServerModule = __esm(() => {
1027
1175
  });
1028
1176
  });
1029
1177
 
1178
+ // src/utils/escapeScriptContent.ts
1179
+ var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
1180
+ const escaped = ESCAPE_LOOKUP[char];
1181
+ return escaped !== undefined ? escaped : char;
1182
+ });
1183
+ var init_escapeScriptContent = __esm(() => {
1184
+ ESCAPE_LOOKUP = {
1185
+ "\u2028": "\\u2028",
1186
+ "\u2029": "\\u2029",
1187
+ "<": "\\u003C"
1188
+ };
1189
+ ESCAPE_REGEX = /[<\u2028\u2029]/g;
1190
+ });
1191
+
1030
1192
  // src/utils/getDurationString.ts
1031
1193
  var getDurationString = (duration) => {
1032
1194
  let durationString;
@@ -1223,15 +1385,15 @@ var ISLAND_BOOTSTRAP_MANIFEST_KEY = "AbsoluteIslandBootstrap", LEGACY_ISLAND_BOO
1223
1385
  var ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__", CLOSING_HEAD_TAG = "</head>", warnedMissingBootstrap = false, warnIfBootstrapMissing = (manifest) => {
1224
1386
  if (warnedMissingBootstrap || getIslandBootstrapPath(manifest))
1225
1387
  return;
1226
- if (false)
1227
- ;
1388
+ if (isProductionRuntime())
1389
+ return;
1228
1390
  warnedMissingBootstrap = true;
1229
1391
  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().");
1230
1392
  }, buildIslandsHeadMarkup = (manifest) => {
1231
- const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
1232
- const islandStateScript = `<script>window.__ABS_ISLAND_STATE__ = ${JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {})}</script>`;
1393
+ const manifestScript = `<script${nonceAttr()}>window.__ABSOLUTE_MANIFEST__ = ${escapeScriptContent(JSON.stringify(manifest))}</script>`;
1394
+ const islandStateScript = `<script${nonceAttr()}>window.__ABS_ISLAND_STATE__ = ${escapeScriptContent(JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {}))}</script>`;
1233
1395
  const bootstrapPath = getIslandBootstrapPath(manifest);
1234
- const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
1396
+ const bootstrapScript = bootstrapPath ? `<script${nonceAttr()} type="module" src="${bootstrapPath}"></script>` : "";
1235
1397
  return `${manifestScript}${islandStateScript}${bootstrapScript}`;
1236
1398
  }, injectHeadMarkup = (html, markup) => {
1237
1399
  const closingHeadIndex = html.indexOf("</head>");
@@ -1432,6 +1594,8 @@ var ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST
1432
1594
  globalThis.__absoluteManifest = manifest;
1433
1595
  };
1434
1596
  var init_islandPageContext = __esm(() => {
1597
+ init_escapeScriptContent();
1598
+ init_cspNonceRef();
1435
1599
  init_logger();
1436
1600
  });
1437
1601
 
@@ -1561,7 +1725,7 @@ var errorPageHtml = ({
1561
1725
  <meta charset="utf-8">
1562
1726
  <meta name="viewport" content="width=device-width, initial-scale=1">
1563
1727
  <title>SSR Error - AbsoluteJS</title>
1564
- <style>
1728
+ <style${nonceAttr()}>
1565
1729
  *{margin:0;padding:0;box-sizing:border-box}
1566
1730
  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}
1567
1731
  .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}
@@ -1593,20 +1757,23 @@ body{min-height:100vh;background:linear-gradient(135deg,rgba(15,23,42,0.98) 0%,r
1593
1757
  ${script}
1594
1758
  </body>
1595
1759
  </html>`;
1596
- }, 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({
1760
+ }, 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({
1597
1761
  framework,
1598
1762
  hint: "Fix the file and save. This page reloads by itself when the build succeeds.",
1599
1763
  kind: "Build Error",
1600
1764
  message: `${pageName || "This page"} could not be built.
1601
1765
 
1602
1766
  ${error ?? "The dev-server terminal has the build output."}`,
1603
- script: RELOAD_ON_REBUILD
1767
+ script: reloadOnRebuild()
1604
1768
  }), ssrErrorPage = (framework, error) => errorPageHtml({
1605
1769
  framework,
1606
1770
  hint: "A component threw during server-side rendering. Check the terminal for the full stack trace.",
1607
1771
  kind: "Server Render Error",
1608
1772
  message: error instanceof Error ? error.message : String(error)
1609
1773
  });
1774
+ var init_ssrErrorPage = __esm(() => {
1775
+ init_cspNonceRef();
1776
+ });
1610
1777
 
1611
1778
  // src/core/requestContext.ts
1612
1779
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
@@ -1680,6 +1847,7 @@ var REQUEST_STORAGE_KEY, PAGE_WARMER_KEY, isAbsoluteRequestStorage = (value) =>
1680
1847
  return headClose ? head.slice(0, headClose.index) + links + head.slice(headClose.index) : head + links;
1681
1848
  };
1682
1849
  var init_requestContext = __esm(() => {
1850
+ init_ssrErrorPage();
1683
1851
  REQUEST_STORAGE_KEY = Symbol.for("absolutejs.requestAsyncLocalStorage");
1684
1852
  PAGE_WARMER_KEY = Symbol.for("absolutejs.devPageWarmer");
1685
1853
  absoluteRequestContext = new Elysia2({
@@ -1807,13 +1975,13 @@ var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json", ABSO
1807
1975
  }, headerVaryValues, envelopeResponse = (response, status) => new Response(JSON.stringify({
1808
1976
  protocol: ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
1809
1977
  response
1810
- }), { headers: responseHeaders(), status }), isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeJsonValue = (value) => {
1978
+ }), { headers: responseHeaders(), status }), isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeJsonValue = (value) => {
1811
1979
  const serialized = JSON.stringify(value);
1812
1980
  if (serialized === undefined) {
1813
1981
  throw new TypeError("Mobile page props must be JSON-serializable.");
1814
1982
  }
1815
1983
  const parsed = JSON.parse(serialized);
1816
- if (!isRecord(parsed)) {
1984
+ if (!isRecord2(parsed)) {
1817
1985
  throw new TypeError("Mobile page props must serialize to an object.");
1818
1986
  }
1819
1987
  return parsed;
@@ -1843,7 +2011,9 @@ var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json", ABSO
1843
2011
  return createAbsoluteMobilePageErrorResponse(page.pageId);
1844
2012
  }
1845
2013
  }, finalizeAbsoluteNativeRouteDevelopmentPage = (input) => {
1846
- if (false) {}
2014
+ if (!isDevelopmentRuntime()) {
2015
+ return createAbsoluteMobileInvalidRequestResponse("The native-route development representation is disabled outside development.");
2016
+ }
1847
2017
  if (input.request?.method !== "GET") {
1848
2018
  return createAbsoluteMobileInvalidRequestResponse("Native-route data requests must use GET.");
1849
2019
  }
@@ -2185,22 +2355,15 @@ var streamSwapRuntime = () => {
2185
2355
  return value.slice(start + 1, end);
2186
2356
  }, getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
2187
2357
 
2188
- // src/utils/escapeScriptContent.ts
2189
- var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
2190
- const escaped = ESCAPE_LOOKUP[char];
2191
- return escaped !== undefined ? escaped : char;
2192
- });
2193
- var init_escapeScriptContent = __esm(() => {
2194
- ESCAPE_LOOKUP = {
2195
- "\u2028": "\\u2028",
2196
- "\u2029": "\\u2029",
2197
- "<": "\\u003C"
2198
- };
2199
- ESCAPE_REGEX = /[<\u2028\u2029]/g;
2200
- });
2201
-
2202
2358
  // src/utils/streamingSlots.ts
2203
- 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) => {
2359
+ 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) => {
2360
+ const head = text.slice(0, cut);
2361
+ const openScript = head.lastIndexOf("<script");
2362
+ const scriptCut = openScript > head.lastIndexOf("</script>") ? openScript : cut;
2363
+ const beforeScript = text.slice(0, scriptCut);
2364
+ const openTag = beforeScript.lastIndexOf("<");
2365
+ return openTag > beforeScript.lastIndexOf(">") ? openTag : scriptCut;
2366
+ }, 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) => {
2204
2367
  const closingBodyIndex = html.indexOf(CLOSING_BODY_TAG);
2205
2368
  if (closingBodyIndex >= 0) {
2206
2369
  return `${html.slice(0, closingBodyIndex)}${injection}${html.slice(closingBodyIndex)}`;
@@ -2218,7 +2381,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
2218
2381
  getStreamingSlotsRuntimeScript()
2219
2382
  ].filter(Boolean).join(";");
2220
2383
  return `<script${createNonceAttr(nonce)}>${escapeScriptContent(runtimeBody)}</script>`;
2221
- }, toUint8 = (value, encoder) => encoder.encode(value), isRecord2 = (value) => Boolean(value) && typeof value === "object", isSafeHtmlLike = (value) => isRecord2(value) && typeof value.changingThisBreaksApplicationSecurity === "string", normalizeSafeHtml = (value) => {
2384
+ }, toUint8 = (value, encoder) => encoder.encode(value), isRecord3 = (value) => Boolean(value) && typeof value === "object", isSafeHtmlLike = (value) => isRecord3(value) && typeof value.changingThisBreaksApplicationSecurity === "string", normalizeSafeHtml = (value) => {
2222
2385
  if (isSafeHtmlLike(value)) {
2223
2386
  return value.changingThisBreaksApplicationSecurity;
2224
2387
  }
@@ -2279,7 +2442,8 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
2279
2442
  }, createTimeoutError = (slot, timeoutMs) => {
2280
2443
  const error = Object.assign(new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`), { __absTimeout: true });
2281
2444
  return error;
2282
- }, isSlotPatchPayloadObject = (value) => isRecord2(value) && ("html" in value), isTimeoutError = (error) => isRecord2(error) && error.__absTimeout === true, toStreamingSlot = (slot, policy) => ({
2445
+ }, isSlotPatchPayloadObject = (value) => isRecord3(value) && ("html" in value), isTimeoutError = (error) => isRecord3(error) && error.__absTimeout === true, toStreamingSlot = (slot, policy) => ({
2446
+ dynamic: slot.dynamic,
2283
2447
  errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
2284
2448
  fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
2285
2449
  id: slot.id ?? createStreamingSlotId(),
@@ -2504,9 +2668,10 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
2504
2668
  if (tail.length <= STREAM_TAIL_LOOKBEHIND) {
2505
2669
  return tail;
2506
2670
  }
2507
- const content = tail.slice(0, tail.length - STREAM_TAIL_LOOKBEHIND);
2508
- controller.enqueue(encoder.encode(content));
2509
- return tail.slice(-STREAM_TAIL_LOOKBEHIND);
2671
+ const cut = findSafeFlushIndex(tail, tail.length - STREAM_TAIL_LOOKBEHIND);
2672
+ if (cut > 0)
2673
+ controller.enqueue(encoder.encode(tail.slice(0, cut)));
2674
+ return tail.slice(cut);
2510
2675
  };
2511
2676
  const finalizeCompletedBaseWinner = (controller, decodedTail, baseRead) => {
2512
2677
  const footerStart = decodedTail.search(CLOSING_PAGE_TAG_REGEX);
@@ -2739,6 +2904,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
2739
2904
  });
2740
2905
  };
2741
2906
  var init_streamingSlots = __esm(() => {
2907
+ init_cspNonceRef();
2742
2908
  init_constants();
2743
2909
  init_escapeScriptContent();
2744
2910
  CLOSING_BODY_TAG_LENGTH = CLOSING_BODY_TAG.length;
@@ -2753,6 +2919,42 @@ var init_streamingSlots = __esm(() => {
2753
2919
  };
2754
2920
  });
2755
2921
 
2922
+ // src/core/partialPrerender.ts
2923
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
2924
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
2925
+ import { rm } from "fs/promises";
2926
+ var PARTIAL_HOLES_HEADER = "X-Absolute-Partial-Holes", PARTIAL_SHELL_HEADER = "X-Absolute-Partial-Shell", SINK_STORAGE_KEY, isSinkStorage = (value) => value instanceof AsyncLocalStorage3, getSinkStorage = () => {
2927
+ const existing = Reflect.get(globalThis, SINK_STORAGE_KEY);
2928
+ if (isSinkStorage(existing))
2929
+ return existing;
2930
+ const created = new AsyncLocalStorage3;
2931
+ Reflect.set(globalThis, SINK_STORAGE_KEY, created);
2932
+ return created;
2933
+ }, activePartialHolesSink = () => getSinkStorage().getStore(), collectPartialHoles = async (render) => {
2934
+ const sink = { slots: undefined };
2935
+ const response = await getSinkStorage().run(sink, render);
2936
+ return { response, slots: sink.slots };
2937
+ }, 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) => {
2938
+ const path = holesPath(htmlPath);
2939
+ if (!existsSync3(path))
2940
+ return [];
2941
+ return decodePartialHoles(readFileSync3(path, "utf-8").trim().split(`
2942
+ `).join(","));
2943
+ }, writePartialHoles = async (htmlPath, response) => {
2944
+ const ids = decodePartialHoles(response.headers.get(PARTIAL_HOLES_HEADER));
2945
+ if (ids.length > 0) {
2946
+ await Bun.write(holesPath(htmlPath), `${encodePartialHoles(ids).split(",").join(`
2947
+ `)}
2948
+ `);
2949
+ } else {
2950
+ await rm(holesPath(htmlPath), { force: true });
2951
+ }
2952
+ return ids;
2953
+ };
2954
+ var init_partialPrerender = __esm(() => {
2955
+ SINK_STORAGE_KEY = Symbol.for("absolutejs.partialPrerenderHolesSink");
2956
+ });
2957
+
2756
2958
  // src/core/routeAssets.ts
2757
2959
  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) => {
2758
2960
  if (!head)
@@ -2796,7 +2998,7 @@ var siblingCssCache, clearSiblingCssCache = () => {
2796
2998
  }, injectInlineCss = (headTag, css) => {
2797
2999
  if (!css)
2798
3000
  return headTag;
2799
- const styleBlock = `<style data-absolute-page-css>${css}</style>`;
3001
+ const styleBlock = `<style data-absolute-page-css${nonceAttr()}>${css}</style>`;
2800
3002
  return headTag.replace("</head>", `${styleBlock}</head>`);
2801
3003
  }, readSiblingCss = async (siblingJsPath) => {
2802
3004
  if (!siblingJsPath)
@@ -2818,6 +3020,7 @@ var siblingCssCache, clearSiblingCssCache = () => {
2818
3020
  }
2819
3021
  };
2820
3022
  var init_inlinePageCss = __esm(() => {
3023
+ init_cspNonceRef();
2821
3024
  siblingCssCache = new Map;
2822
3025
  });
2823
3026
 
@@ -2829,6 +3032,45 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
2829
3032
  return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
2830
3033
  };
2831
3034
 
3035
+ // src/core/staticHtmlNonce.ts
3036
+ var nonceStaticHtml = async (html, nonce = readCspNonce()) => {
3037
+ if (!nonce)
3038
+ return html;
3039
+ const stamp = {
3040
+ element: (element) => {
3041
+ if (!element.hasAttribute("nonce"))
3042
+ element.setAttribute("nonce", nonce);
3043
+ }
3044
+ };
3045
+ return new HTMLRewriter().on("script", stamp).on("style", stamp).transform(new Response(html)).text();
3046
+ }, isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), parseHtmxConfig = (content) => {
3047
+ try {
3048
+ const parsed = JSON.parse(content ?? "{}");
3049
+ return isRecord4(parsed) ? parsed : {};
3050
+ } catch {
3051
+ return {};
3052
+ }
3053
+ }, withHtmxStyleNonce = async (html, nonce = readCspNonce()) => {
3054
+ if (!nonce)
3055
+ return html;
3056
+ let found = false;
3057
+ const merged = await new HTMLRewriter().on('meta[name="htmx-config"]', {
3058
+ element: (element) => {
3059
+ found = true;
3060
+ const config = parseHtmxConfig(element.getAttribute("content"));
3061
+ element.setAttribute("content", JSON.stringify({ ...config, inlineStyleNonce: nonce }));
3062
+ }
3063
+ }).transform(new Response(html)).text();
3064
+ if (found)
3065
+ return merged;
3066
+ const meta = `<meta name="htmx-config" content='${JSON.stringify({ inlineStyleNonce: nonce })}'>`;
3067
+ const headClose = merged.search(/<\/head>/i);
3068
+ return headClose >= 0 ? `${merged.slice(0, headClose)}${meta}${merged.slice(headClose)}` : `${meta}${merged}`;
3069
+ };
3070
+ var init_staticHtmlNonce = __esm(() => {
3071
+ init_cspNonceRef();
3072
+ });
3073
+
2832
3074
  // src/utils/resolveConvention.ts
2833
3075
  import { basename as basename2 } from "path";
2834
3076
  var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boolean(value) && typeof value === "object", getMap = () => {
@@ -2865,7 +3107,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
2865
3107
  return conventions.defaults?.error;
2866
3108
  }, resolveNotFoundConventionPath = (framework) => getMap()[framework]?.defaults?.notFound, setConventions = (map) => {
2867
3109
  Reflect.set(globalThis, CONVENTIONS_KEY, map);
2868
- }, isDev = () => true, buildErrorProps = (error) => {
3110
+ }, isDev = () => isDevelopmentRuntime(), buildErrorProps = (error) => {
2869
3111
  if (error instanceof Error) {
2870
3112
  return {
2871
3113
  message: error.message,
@@ -2882,7 +3124,9 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
2882
3124
  if (typeof ErrorComponent !== "function")
2883
3125
  return null;
2884
3126
  const element = createElement(ErrorComponent, errorProps);
2885
- const stream = await renderToReadableStream(element);
3127
+ const stream = await renderToReadableStream(element, {
3128
+ nonce: readCspNonce()
3129
+ });
2886
3130
  return new Response(stream, {
2887
3131
  headers: { "Content-Type": "text/html" },
2888
3132
  status: 500
@@ -2893,10 +3137,12 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
2893
3137
  const ErrorComponent = mod.default;
2894
3138
  if (!ErrorComponent)
2895
3139
  return null;
3140
+ const nonce = readCspNonce();
2896
3141
  const { head, body } = render(ErrorComponent, {
2897
- props: errorProps
3142
+ props: errorProps,
3143
+ ...nonce ? { csp: { nonce } } : {}
2898
3144
  });
2899
- const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
3145
+ const html = `<!DOCTYPE html><html><head>${nonceSvelteHeadStyles(head)}</head><body>${body}</body></html>`;
2900
3146
  return new Response(html, {
2901
3147
  headers: { "Content-Type": "text/html" },
2902
3148
  status: 500
@@ -2904,7 +3150,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
2904
3150
  }, unescapeVueStyles = (ssrBody) => {
2905
3151
  let styles = "";
2906
3152
  const body = ssrBody.replace(/<style>([\s\S]*?)<\/style>/g, (_, css) => {
2907
- styles += `<style>${css.replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">")}</style>`;
3153
+ styles += `<style${nonceAttr()}>${css.replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">")}</style>`;
2908
3154
  return "";
2909
3155
  });
2910
3156
  return { body, styles };
@@ -2936,7 +3182,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
2936
3182
  status: 500
2937
3183
  });
2938
3184
  }, 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) => {
2939
- const template = await Bun.file(conventionPath).text();
3185
+ const template = await nonceStaticHtml(await Bun.file(conventionPath).text());
2940
3186
  const html = replaceErrorTokens(template, errorProps);
2941
3187
  return new Response(html, {
2942
3188
  headers: { "Content-Type": "text/html" },
@@ -2991,7 +3237,9 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
2991
3237
  if (typeof NotFoundComponent !== "function")
2992
3238
  return null;
2993
3239
  const element = createElement(NotFoundComponent);
2994
- const stream = await renderToReadableStream(element);
3240
+ const stream = await renderToReadableStream(element, {
3241
+ nonce: readCspNonce()
3242
+ });
2995
3243
  return new Response(stream, {
2996
3244
  headers: { "Content-Type": "text/html" },
2997
3245
  status: 404
@@ -3002,8 +3250,9 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
3002
3250
  const NotFoundComponent = mod.default;
3003
3251
  if (!NotFoundComponent)
3004
3252
  return null;
3005
- const { head, body } = render(NotFoundComponent);
3006
- const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
3253
+ const nonce = readCspNonce();
3254
+ const { head, body } = render(NotFoundComponent, nonce ? { csp: { nonce } } : {});
3255
+ const html = `<!DOCTYPE html><html><head>${nonceSvelteHeadStyles(head)}</head><body>${body}</body></html>`;
3007
3256
  return new Response(html, {
3008
3257
  headers: { "Content-Type": "text/html" },
3009
3258
  status: 404
@@ -3036,7 +3285,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
3036
3285
  status: 404
3037
3286
  });
3038
3287
  }, renderHtmlNotFound = async (conventionPath) => {
3039
- const html = await Bun.file(conventionPath).text();
3288
+ const html = await nonceStaticHtml(await Bun.file(conventionPath).text());
3040
3289
  return new Response(html, {
3041
3290
  headers: { "Content-Type": "text/html" },
3042
3291
  status: 404
@@ -3054,7 +3303,7 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
3054
3303
  logConventionRenderError(framework, "not-found", renderError);
3055
3304
  }
3056
3305
  return null;
3057
- }, NOT_FOUND_PRIORITY, renderFirstNotFound = async () => {
3306
+ }, NOT_FOUND_PRIORITY, renderFirstNotFound = async (options = {}) => {
3058
3307
  const renderNext = async (frameworks) => {
3059
3308
  const [framework, ...remaining] = frameworks;
3060
3309
  if (!framework) {
@@ -3069,13 +3318,16 @@ var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boo
3069
3318
  }
3070
3319
  return renderNext(remaining);
3071
3320
  };
3072
- return renderNext(NOT_FOUND_PRIORITY);
3321
+ return renderNext(options.preferHtmx ? ["htmx", ...NOT_FOUND_PRIORITY.filter((key) => key !== "htmx")] : NOT_FOUND_PRIORITY);
3073
3322
  };
3074
3323
  var init_resolveConvention = __esm(() => {
3324
+ init_cspNonceRef();
3325
+ init_staticHtmlNonce();
3075
3326
  ERROR_RENDERERS = {
3076
3327
  angular: renderAngularError,
3077
3328
  ember: renderEmberError,
3078
3329
  html: renderHtmlError,
3330
+ htmx: renderHtmlError,
3079
3331
  react: renderReactError,
3080
3332
  svelte: renderSvelteError,
3081
3333
  vue: renderVueError
@@ -3084,6 +3336,7 @@ var init_resolveConvention = __esm(() => {
3084
3336
  angular: renderAngularNotFound,
3085
3337
  ember: renderEmberNotFound,
3086
3338
  html: renderHtmlNotFound,
3339
+ htmx: renderHtmlNotFound,
3087
3340
  react: renderReactNotFound,
3088
3341
  svelte: renderSvelteNotFound,
3089
3342
  vue: renderVueNotFound
@@ -3093,7 +3346,8 @@ var init_resolveConvention = __esm(() => {
3093
3346
  "svelte",
3094
3347
  "vue",
3095
3348
  "angular",
3096
- "html"
3349
+ "html",
3350
+ "htmx"
3097
3351
  ];
3098
3352
  });
3099
3353
 
@@ -3178,7 +3432,7 @@ var init_browserTranslationAttributes = __esm(() => {
3178
3432
  });
3179
3433
 
3180
3434
  // src/core/browserTranslation.ts
3181
- var BASELINE_MARKER = "__ABSOLUTE_SSR_TEXT_BASELINES__", BROWSER_TRANSLATION_BASELINE_SCRIPT, browserTranslationBaselineTag = () => `<script>${BROWSER_TRANSLATION_BASELINE_SCRIPT}</script>`, injectBrowserTranslationBaseline = (html) => {
3435
+ var BASELINE_MARKER = "__ABSOLUTE_SSR_TEXT_BASELINES__", BROWSER_TRANSLATION_BASELINE_SCRIPT, browserTranslationBaselineTag = () => `<script${nonceAttr()}>${BROWSER_TRANSLATION_BASELINE_SCRIPT}</script>`, injectBrowserTranslationBaseline = (html) => {
3182
3436
  if (html.includes(BASELINE_MARKER))
3183
3437
  return html;
3184
3438
  const script = browserTranslationBaselineTag();
@@ -3188,12 +3442,40 @@ var BASELINE_MARKER = "__ABSOLUTE_SSR_TEXT_BASELINES__", BROWSER_TRANSLATION_BAS
3188
3442
  return `${html.slice(0, closingBodyIndex)}${script}${html.slice(closingBodyIndex)}`;
3189
3443
  };
3190
3444
  var init_browserTranslation = __esm(() => {
3445
+ init_cspNonceRef();
3191
3446
  init_browserTranslationAttributes();
3192
3447
  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);}}";
3193
3448
  });
3194
3449
 
3450
+ // src/utils/localeRef.ts
3451
+ var GETTER_KEY2, isRequestLocale = (value) => typeof value === "object" && value !== null && ("locale" in value) && typeof value.locale === "string" && ("dir" in value) && (value.dir === "ltr" || value.dir === "rtl"), escapeAttribute = (value) => value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;"), htmlLangAttributes = (fallback = "en") => {
3452
+ const current = readRequestLocale();
3453
+ if (!current)
3454
+ return ` lang="${escapeAttribute(fallback)}"`;
3455
+ return ` lang="${escapeAttribute(current.locale)}" dir="${current.dir}"`;
3456
+ }, readRequestLocale = () => {
3457
+ const getter = Reflect.get(globalThis, GETTER_KEY2);
3458
+ if (typeof getter !== "function")
3459
+ return;
3460
+ const value = getter();
3461
+ return isRequestLocale(value) ? value : undefined;
3462
+ }, registerRequestLocaleGetter = (getter) => {
3463
+ Reflect.set(globalThis, GETTER_KEY2, getter);
3464
+ };
3465
+ var init_localeRef = __esm(() => {
3466
+ GETTER_KEY2 = Symbol.for("absolutejs.requestLocaleGetter");
3467
+ });
3468
+
3195
3469
  // src/svelte/renderToReadableStream.ts
3196
- var SVELTE_PAGE_ROOT_ID = "__absolute_svelte_root__", renderToReadableStream = async (component, props, {
3470
+ var SVELTE_PAGE_ROOT_ID = "__absolute_svelte_root__", MAX_RENDER_PASSES = 5, renderUntilSettled = async (renderPass, settle, pass = 1) => {
3471
+ const rendered = await renderPass();
3472
+ if (!settle || pass >= MAX_RENDER_PASSES)
3473
+ return rendered;
3474
+ const again = await settle();
3475
+ if (!again)
3476
+ return rendered;
3477
+ return renderUntilSettled(renderPass, settle, pass + 1);
3478
+ }, renderToReadableStream = async (component, props, {
3197
3479
  bootstrapScriptContent,
3198
3480
  bootstrapScripts = [],
3199
3481
  bootstrapModules = [],
@@ -3202,17 +3484,28 @@ var SVELTE_PAGE_ROOT_ID = "__absolute_svelte_root__", renderToReadableStream = a
3202
3484
  progressiveChunkSize = DEFAULT_CHUNK_SIZE,
3203
3485
  signal,
3204
3486
  headContent,
3205
- bodyContent
3487
+ bodyContent,
3488
+ context,
3489
+ settle
3206
3490
  } = {}) => {
3207
3491
  try {
3208
3492
  const { render } = await import("svelte/server");
3209
3493
  const renderComponent = render;
3210
- const rendered = typeof props === "undefined" ? await renderComponent(component) : await renderComponent(component, { props });
3494
+ const resolvedNonce = nonce ?? readCspNonce();
3495
+ const svelteCsp = resolvedNonce ? { csp: { nonce: resolvedNonce } } : {};
3496
+ const renderPass = async () => {
3497
+ if (typeof props === "undefined" && !context) {
3498
+ return renderComponent(component, svelteCsp);
3499
+ }
3500
+ return renderComponent(component, { ...svelteCsp, context, props });
3501
+ };
3502
+ const rendered = await renderUntilSettled(renderPass, settle);
3211
3503
  const { head, body } = rendered;
3212
- const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
3213
- const scripts = (bootstrapScriptContent ? `<script${nonceAttr}>${escapeScriptContent(bootstrapScriptContent)}</script>` : "") + bootstrapScripts.map((src) => `<script${nonceAttr} src="${src}"></script>`).join("") + bootstrapModules.map((src) => `<script${nonceAttr} type="module" src="${src}"></script>`).join("");
3504
+ const nonceAttr2 = nonceAttr(resolvedNonce);
3505
+ const inlineScript = typeof bootstrapScriptContent === "function" ? bootstrapScriptContent() : bootstrapScriptContent;
3506
+ const scripts = (inlineScript ? `<script${nonceAttr2}>${escapeScriptContent(inlineScript)}</script>` : "") + bootstrapScripts.map((src) => `<script${nonceAttr2} src="${src}"></script>`).join("") + bootstrapModules.map((src) => `<script${nonceAttr2} type="module" src="${src}"></script>`).join("");
3214
3507
  const encoder = new TextEncoder;
3215
- const full = encoder.encode(`<!DOCTYPE html><html lang="en"><head>${head}${headContent ?? ""}</head><body><div id="${SVELTE_PAGE_ROOT_ID}">${body}</div>${scripts}${bodyContent ?? ""}</body></html>`);
3508
+ const full = encoder.encode(`<!DOCTYPE html><html${htmlLangAttributes()}><head>${nonceSvelteHeadStyles(head, resolvedNonce)}${headContent ?? ""}</head><body><div id="${SVELTE_PAGE_ROOT_ID}">${body}</div>${scripts}${bodyContent ?? ""}</body></html>`);
3216
3509
  let offset = 0;
3217
3510
  return new ReadableStream({
3218
3511
  type: "bytes",
@@ -3239,26 +3532,28 @@ var SVELTE_PAGE_ROOT_ID = "__absolute_svelte_root__", renderToReadableStream = a
3239
3532
  }
3240
3533
  };
3241
3534
  var init_renderToReadableStream = __esm(() => {
3535
+ init_cspNonceRef();
3242
3536
  init_constants();
3243
3537
  init_escapeScriptContent();
3538
+ init_localeRef();
3244
3539
  });
3245
3540
 
3246
3541
  // src/angular/resolveAngularPackage.ts
3247
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
3542
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
3248
3543
  import { join as join4, resolve as resolve4 } from "path";
3249
3544
  var resolveAngularPackageDir = (specifier) => {
3250
3545
  const fromCompiledRuntime = process.env.ABSOLUTE_BUILD_DIR ? resolve4(process.env.ABSOLUTE_BUILD_DIR, "node_modules", specifier) : null;
3251
- if (fromCompiledRuntime && existsSync3(fromCompiledRuntime)) {
3546
+ if (fromCompiledRuntime && existsSync4(fromCompiledRuntime)) {
3252
3547
  return fromCompiledRuntime;
3253
3548
  }
3254
3549
  const fromProject = resolve4(process.cwd(), "node_modules", specifier);
3255
- if (existsSync3(fromProject)) {
3550
+ if (existsSync4(fromProject)) {
3256
3551
  return fromProject;
3257
3552
  }
3258
3553
  return null;
3259
3554
  }, resolvePackageEntry = (packageDir) => {
3260
3555
  try {
3261
- const pkg = JSON.parse(readFileSync3(join4(packageDir, "package.json"), "utf-8"));
3556
+ const pkg = JSON.parse(readFileSync4(join4(packageDir, "package.json"), "utf-8"));
3262
3557
  const rootExport = pkg.exports?.["."];
3263
3558
  const entry = (typeof rootExport === "string" ? rootExport : rootExport?.default) ?? pkg.module ?? pkg.main ?? "index.js";
3264
3559
  return join4(packageDir, entry);
@@ -3277,16 +3572,13 @@ var resolveAngularPackageDir = (specifier) => {
3277
3572
  ].filter((value) => Boolean(value));
3278
3573
  for (const buildDir of buildDirs) {
3279
3574
  const vendorPath = join4(buildDir, "angular", "vendor", "server", `${toSafeVendorName(specifier)}.js`);
3280
- if (existsSync3(vendorPath))
3575
+ if (existsSync4(vendorPath))
3281
3576
  return vendorPath;
3282
3577
  }
3283
3578
  return resolveAngularPackage(specifier);
3284
3579
  };
3285
3580
  var init_resolveAngularPackage = () => {};
3286
3581
 
3287
- // src/utils/runtimeMode.ts
3288
- var ENV_VAR = "NODE_ENV", isDevelopmentRuntime = () => process.env[ENV_VAR] === "development", isProductionRuntime = () => process.env[ENV_VAR] === "production";
3289
-
3290
3582
  // src/angular/angularPatch.ts
3291
3583
  var ensureHead = (doc) => {
3292
3584
  if (!doc || doc.head || !doc.documentElement) {
@@ -3460,6 +3752,7 @@ var initDominoAdapter = (platformServer) => {
3460
3752
  APP_BASE_HREF: common.APP_BASE_HREF,
3461
3753
  bootstrapApplication: platformBrowser.bootstrapApplication,
3462
3754
  Component: core.Component,
3755
+ CSP_NONCE: core.CSP_NONCE,
3463
3756
  DomSanitizer: platformBrowser.DomSanitizer,
3464
3757
  ENVIRONMENT_INITIALIZER: core.ENVIRONMENT_INITIALIZER,
3465
3758
  inject: core.inject,
@@ -3467,6 +3760,7 @@ var initDominoAdapter = (platformServer) => {
3467
3760
  NgComponentOutlet: common.NgComponentOutlet,
3468
3761
  provideClientHydration: platformBrowser.provideClientHydration,
3469
3762
  provideServerRendering: platformServer.provideServerRendering,
3763
+ provideZoneChangeDetection: core.provideZoneChangeDetection,
3470
3764
  provideZonelessChangeDetection: core.provideZonelessChangeDetection,
3471
3765
  reflectComponentType: core.reflectComponentType,
3472
3766
  renderApplication: platformServer.renderApplication,
@@ -3542,7 +3836,7 @@ var scriptRegistry, requestCounter = 0, getRequestId = () => `req_${Date.now()}_
3542
3836
  })();`;
3543
3837
  }).join(`
3544
3838
  `);
3545
- return `<script>
3839
+ return `<script${nonceAttr()}>
3546
3840
  (function() {
3547
3841
  ${scriptCode}
3548
3842
  })();
@@ -3560,6 +3854,7 @@ ${scriptCode}
3560
3854
  return scriptArray;
3561
3855
  };
3562
3856
  var init_registerClientScript = __esm(() => {
3857
+ init_cspNonceRef();
3563
3858
  scriptRegistry = new Map;
3564
3859
  if (typeof globalThis !== "undefined") {
3565
3860
  Object.assign(globalThis, { registerClientScript });
@@ -3588,6 +3883,81 @@ var buildRequestProviders = (deps, request, requestContext, responseInit) => [
3588
3883
  { provide: deps.RESPONSE_INIT, useValue: responseInit ?? null }
3589
3884
  ];
3590
3885
 
3886
+ // src/angular/zoneRuntime.ts
3887
+ var ZONE_NODE_SPECIFIER = "zone.js/node", MISSING_ZONE_MESSAGE = 'angular.changeDetection is "zone" but zone.js could not be loaded. Install it in your app (bun add zone.js).', isAngularZoneMode = () => globalThis.__absoluteAngularChangeDetection === "zone", setAngularChangeDetection = (mode) => {
3888
+ globalThis.__absoluteAngularChangeDetection = mode ?? "zoneless";
3889
+ }, isRecord7 = (value) => typeof value === "object" && value !== null, adoptIntoNativePromise = (NativePromise, value) => {
3890
+ if (value instanceof NativePromise || !isRecord7(value))
3891
+ return value;
3892
+ const { then } = value;
3893
+ if (typeof then !== "function")
3894
+ return value;
3895
+ return new NativePromise((resolve, reject) => {
3896
+ Reflect.apply(then, value, [resolve, reject]);
3897
+ });
3898
+ }, wrapHandler = (NativePromise, handler) => {
3899
+ if (typeof handler !== "function")
3900
+ return handler;
3901
+ return function nativePromiseHandler(...args) {
3902
+ return adoptIntoNativePromise(NativePromise, Reflect.apply(handler, this, args));
3903
+ };
3904
+ }, wrapRoute = (NativePromise, route) => {
3905
+ if (typeof route === "function")
3906
+ return wrapHandler(NativePromise, route);
3907
+ if (!isRecord7(route) || route instanceof Response || route instanceof Blob)
3908
+ return route;
3909
+ return Object.fromEntries(Object.entries(route).map(([method, handler]) => [
3910
+ method,
3911
+ wrapHandler(NativePromise, handler)
3912
+ ]));
3913
+ }, wrapServeOptions = (NativePromise, options) => {
3914
+ if (!isRecord7(options))
3915
+ return options;
3916
+ const wrapped = { ...options };
3917
+ if (options.fetch)
3918
+ wrapped.fetch = wrapHandler(NativePromise, options.fetch);
3919
+ if (options.error)
3920
+ wrapped.error = wrapHandler(NativePromise, options.error);
3921
+ if (isRecord7(options.routes))
3922
+ wrapped.routes = Object.fromEntries(Object.entries(options.routes).map(([path, route]) => [
3923
+ path,
3924
+ wrapRoute(NativePromise, route)
3925
+ ]));
3926
+ return wrapped;
3927
+ }, wrapServerReload = (NativePromise, server) => {
3928
+ if (!isRecord7(server))
3929
+ return;
3930
+ const { reload } = server;
3931
+ if (typeof reload !== "function")
3932
+ return;
3933
+ Reflect.set(server, "reload", (options) => Reflect.apply(reload, server, [
3934
+ wrapServeOptions(NativePromise, options)
3935
+ ]));
3936
+ }, patchBunServe = (NativePromise) => {
3937
+ const originalServe = Bun.serve;
3938
+ Reflect.set(Bun, "serve", (options) => {
3939
+ const server = Reflect.apply(originalServe, Bun, [
3940
+ wrapServeOptions(NativePromise, options)
3941
+ ]);
3942
+ wrapServerReload(NativePromise, server);
3943
+ return server;
3944
+ });
3945
+ wrapServerReload(NativePromise, globalThis.__absoluteBunServer);
3946
+ }, installation = null, isPromiseConstructor = (value) => typeof value === "function", install = async () => {
3947
+ setAngularChangeDetection("zone");
3948
+ const savedNative = Reflect.get(globalThis, "__zone_symbol__Promise");
3949
+ const NativePromise = isPromiseConstructor(savedNative) ? savedNative : globalThis.Promise;
3950
+ try {
3951
+ await import(ZONE_NODE_SPECIFIER);
3952
+ } catch (error) {
3953
+ throw new Error(MISSING_ZONE_MESSAGE, { cause: error });
3954
+ }
3955
+ patchBunServe(NativePromise);
3956
+ }, installAngularZoneRuntime = () => {
3957
+ installation ??= install();
3958
+ return installation;
3959
+ };
3960
+
3591
3961
  // src/angular/ssrRender.ts
3592
3962
  var routeContextCache, cacheRouteData = (pagePath, data) => {
3593
3963
  const cacheKey = pagePath.split("?")[0] ?? pagePath;
@@ -3595,7 +3965,7 @@ var routeContextCache, cacheRouteData = (pagePath, data) => {
3595
3965
  }, getCachedRouteData = (pagePath) => routeContextCache.get(pagePath), selectorCache, buildProviders = (deps, sanitizer, request, requestContext, responseInit, userProviders = []) => [
3596
3966
  deps.provideServerRendering(),
3597
3967
  deps.provideClientHydration(deps.withHttpTransferCacheOptions(buildAbsoluteHttpTransferCacheOptions())),
3598
- deps.provideZonelessChangeDetection(),
3968
+ isAngularZoneMode() ? deps.provideZoneChangeDetection({ eventCoalescing: true }) : deps.provideZonelessChangeDetection(),
3599
3969
  { provide: deps.APP_BASE_HREF, useValue: "/" },
3600
3970
  { provide: deps.DomSanitizer, useValue: sanitizer },
3601
3971
  { provide: deps.Sanitizer, useValue: sanitizer },
@@ -3624,15 +3994,17 @@ var routeContextCache, cacheRouteData = (pagePath, data) => {
3624
3994
  result = injectBeforeClose(result, generateClientScriptCode(registeredScripts));
3625
3995
  }
3626
3996
  if (requestContext !== undefined) {
3627
- result = injectBeforeClose(result, `<script>window.__ABS_ANGULAR_REQUEST_CONTEXT__ = ${JSON.stringify(requestContext)};</script>`);
3997
+ result = injectBeforeClose(result, `<script${nonceAttr()}>window.__ABS_ANGULAR_REQUEST_CONTEXT__ = ${escapeScriptContent(JSON.stringify(requestContext))};</script>`);
3628
3998
  }
3629
3999
  if (indexPath) {
3630
4000
  const escapedIndexPath = JSON.stringify(indexPath);
3631
- result = injectBeforeClose(result, `<script>import(${escapedIndexPath});</script>`);
4001
+ result = injectBeforeClose(result, `<script${nonceAttr()}>import(${escapeScriptContent(escapedIndexPath)});</script>`);
3632
4002
  }
3633
4003
  return result;
3634
4004
  }, renderAngularApp = async (deps, PageComponent, providers, document2, url = "/") => {
3635
- const bootstrap = (context) => deps.bootstrapApplication(PageComponent, { providers }, context);
4005
+ const nonce = readCspNonce();
4006
+ const cspProviders = nonce ? [{ provide: deps.CSP_NONCE, useValue: nonce }] : [];
4007
+ const bootstrap = (context) => deps.bootstrapApplication(PageComponent, { providers: [...providers, ...cspProviders] }, context);
3636
4008
  return withSuppressedAngularDevLogs(() => deps.renderApplication(bootstrap, {
3637
4009
  document: document2,
3638
4010
  platformProviders: [],
@@ -3653,6 +4025,8 @@ var routeContextCache, cacheRouteData = (pagePath, data) => {
3653
4025
  }
3654
4026
  };
3655
4027
  var init_ssrRender = __esm(() => {
4028
+ init_escapeScriptContent();
4029
+ init_cspNonceRef();
3656
4030
  init_registerClientScript();
3657
4031
  init_browserTranslation();
3658
4032
  routeContextCache = new Map;
@@ -4040,14 +4414,14 @@ var init_maskLiterals = __esm(() => {
4040
4414
  });
4041
4415
 
4042
4416
  // src/build/specifierRewriter.ts
4043
- var escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), PLACEHOLDER, GAP, QUOTE = `["']`, ADJACENT_PREFIXES, ADJACENT_DYNAMIC_PREFIX, ADJACENT_DYNAMIC_SUFFIX, SWEEP_PREFIXES, rewriterCache, cacheKey = (vendorPaths) => Object.entries(vendorPaths).sort(([left], [right]) => left.localeCompare(right)).map(([specifier, webPath]) => `${specifier}\x00${webPath}\x00`).join(""), compileRegex = (prefixes, alternation, withAdjacentDynamic) => {
4417
+ var escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), PLACEHOLDER, GAP, QUOTE = `["']`, ADJACENT_PREFIXES, ADJACENT_DYNAMIC_PREFIX, ADJACENT_DYNAMIC_SUFFIX, SWEEP_PREFIXES, rewriterCache, cacheKey2 = (vendorPaths) => Object.entries(vendorPaths).sort(([left], [right]) => left.localeCompare(right)).map(([specifier, webPath]) => `${specifier}\x00${webPath}\x00`).join(""), compileRegex = (prefixes, alternation, withAdjacentDynamic) => {
4044
4418
  const plain = `(${prefixes.join("|")})(${alternation})(${QUOTE})`;
4045
4419
  if (!withAdjacentDynamic)
4046
4420
  return new RegExp(plain, "g");
4047
4421
  const dynamic = `(${ADJACENT_DYNAMIC_PREFIX})(${alternation})(${ADJACENT_DYNAMIC_SUFFIX})`;
4048
4422
  return new RegExp(`${plain}|${dynamic}`, "g");
4049
4423
  }, compileSpecifierRewriter = (vendorPaths) => {
4050
- const key = cacheKey(vendorPaths);
4424
+ const key = cacheKey2(vendorPaths);
4051
4425
  const cached = rewriterCache.get(key);
4052
4426
  if (cached)
4053
4427
  return cached;
@@ -4291,7 +4665,7 @@ var createVueCompiler = async () => {
4291
4665
  };
4292
4666
 
4293
4667
  // src/core/vueServerModule.ts
4294
- import { readFileSync as readFileSync4, realpathSync } from "fs";
4668
+ import { readFileSync as readFileSync5, realpathSync } from "fs";
4295
4669
  import { mkdir as mkdir3 } from "fs/promises";
4296
4670
  import { dirname as dirname4, join as join7, relative as relative4, resolve as resolve5 } from "path";
4297
4671
  var {Transpiler } = globalThis.Bun;
@@ -4340,7 +4714,7 @@ var ISLAND_COMPONENT_ID_LENGTH = 8, serverCacheRoot3, compiledModuleCache3, tran
4340
4714
  fs: {
4341
4715
  fileExists: isFile,
4342
4716
  realpath: realpathSync,
4343
- readFile: (file) => isFile(file) ? readFileSync4(file, "utf-8") : undefined
4717
+ readFile: (file) => isFile(file) ? readFileSync5(file, "utf-8") : undefined
4344
4718
  },
4345
4719
  id: componentId,
4346
4720
  inlineTemplate: false
@@ -4402,14 +4776,14 @@ var defineIslandComponent = (component, options) => ({
4402
4776
  component,
4403
4777
  export: options.export,
4404
4778
  source: options.source
4405
- }), defineIslandRegistry = (registry) => registry, isRecord4 = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (component) => {
4779
+ }), defineIslandRegistry = (registry) => registry, isRecord8 = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (component) => {
4406
4780
  if (!isIslandComponentDefinition(component))
4407
4781
  return null;
4408
4782
  return {
4409
4783
  export: component.export,
4410
4784
  source: component.source
4411
4785
  };
4412
- }, isIslandComponentDefinition = (value) => isRecord4(value) && ("component" in value) && ("source" in value) && typeof value.source === "string", parseIslandProps = (rawProps) => {
4786
+ }, isIslandComponentDefinition = (value) => isRecord8(value) && ("component" in value) && ("source" in value) && typeof value.source === "string", parseIslandProps = (rawProps) => {
4413
4787
  if (!rawProps)
4414
4788
  return {};
4415
4789
  return JSON.parse(rawProps);
@@ -4433,7 +4807,7 @@ var init_islandMarkupAttributes = __esm(() => {
4433
4807
  var islandSequence = 0, resolvedServerComponentCache, resolvedServerBuildComponentCache, nextIslandId = () => {
4434
4808
  islandSequence += 1;
4435
4809
  return `island-${islandSequence}`;
4436
- }, isRecord5 = (value) => typeof value === "object" && value !== null, isReactServerIslandComponent = (value) => typeof value === "function", isSvelteServerIslandComponent = (value) => typeof value === "function", isVueServerIslandComponent = (value) => typeof value === "function" || isRecord5(value), isAngularServerIslandComponent = (value) => typeof value === "function", resolveBuildReferencePath = (source, registryPath) => {
4810
+ }, isRecord9 = (value) => typeof value === "object" && value !== null, isReactServerIslandComponent = (value) => typeof value === "function", isSvelteServerIslandComponent = (value) => typeof value === "function", isVueServerIslandComponent = (value) => typeof value === "function" || isRecord9(value), isAngularServerIslandComponent = (value) => typeof value === "function", resolveBuildReferencePath = (source, registryPath) => {
4437
4811
  if (source.startsWith("file://"))
4438
4812
  return new URL(source).pathname;
4439
4813
  if (source.startsWith("."))
@@ -4594,6 +4968,7 @@ var requireCurrentIslandRegistry = () => {
4594
4968
  };
4595
4969
 
4596
4970
  // src/svelte/pageHandler.ts
4971
+ init_cspNonceRef();
4597
4972
  init_svelteServerModule();
4598
4973
  init_islandPageContext();
4599
4974
  init_devRouteRegistrationCallsite();
@@ -4604,6 +4979,8 @@ init_pageResponseCache();
4604
4979
  // src/core/responseEnhancers.ts
4605
4980
  init_streamingSlots();
4606
4981
  init_pageResponseCache();
4982
+ init_partialPrerender();
4983
+ init_requestContext();
4607
4984
 
4608
4985
  // src/core/streamingSlotRegistrar.ts
4609
4986
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
@@ -4646,7 +5023,7 @@ var setStreamingSlotWarningController = (controller) => {
4646
5023
  Reflect.set(globalThis, STREAMING_SLOT_WARNING_STORAGE_KEY, controller);
4647
5024
  };
4648
5025
  var warnMissingStreamingSlotCollector = (primitiveName) => {
4649
- if (isStreamingSlotCollectionActive()) {
5026
+ if (isProductionRuntime() || isStreamingSlotCollectionActive()) {
4650
5027
  return;
4651
5028
  }
4652
5029
  getWarningController()?.maybeWarn(primitiveName);
@@ -4754,18 +5131,51 @@ var mergeStreamingSlots = (registered, explicit) => {
4754
5131
  merged.set(slot.id, slot);
4755
5132
  return [...merged.values()];
4756
5133
  };
5134
+ var captureStaticShell = async (responseLike, slots, options) => {
5135
+ const holes = slots.filter(isDynamicStreamingSlot);
5136
+ const staticSlots = slots.filter((slot) => !isDynamicStreamingSlot(slot));
5137
+ const response = await withStreamingSlots(responseLike, {
5138
+ ...options,
5139
+ streamingSlots: staticSlots
5140
+ });
5141
+ if (holes.length === 0 || !response.body)
5142
+ return response;
5143
+ const headers = cloneHeaders(response);
5144
+ headers.set(PARTIAL_HOLES_HEADER, encodePartialHoles(holes.map((slot) => slot.id)));
5145
+ const body = staticSlots.length > 0 ? response.body : injectStreamingRuntimeIntoStream(response.body, options.nonce, options.runtimePlacement, options.runtimePreludeScript);
5146
+ return new Response(body, {
5147
+ headers,
5148
+ status: response.status,
5149
+ statusText: response.statusText
5150
+ });
5151
+ };
5152
+ var handOverHoles = async (responseLike, slots, sink) => {
5153
+ sink.slots = slots.filter(isDynamicStreamingSlot);
5154
+ const response = await toResponse(responseLike);
5155
+ await response.body?.cancel().catch(() => {
5156
+ return;
5157
+ });
5158
+ return new Response(null, { status: 204 });
5159
+ };
4757
5160
  var withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
4758
5161
  const { result, slots } = await runWithStreamingSlotRegistry(renderResponse);
4759
5162
  const explicit = options.streamingSlots ?? [];
5163
+ const streamingSlots = mergeStreamingSlots(slots, explicit);
5164
+ const holesSink = activePartialHolesSink();
5165
+ if (holesSink)
5166
+ return handOverHoles(result, streamingSlots, holesSink);
5167
+ if (isPartialShellCapture(getCurrentAbsoluteRequest())) {
5168
+ return captureStaticShell(result, streamingSlots, options);
5169
+ }
4760
5170
  return withStreamingSlots(result, {
4761
5171
  ...options,
4762
- streamingSlots: mergeStreamingSlots(slots, explicit)
5172
+ streamingSlots
4763
5173
  });
4764
5174
  };
4765
5175
 
4766
5176
  // src/core/streamingSlotWarningScope.ts
4767
5177
  init_logger();
4768
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
5178
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
4769
5179
  var STREAMING_SLOT_WARNING_STORAGE_KEY2 = Symbol.for("absolutejs.streamingSlotWarningAsyncLocalStorage");
4770
5180
  var isObjectRecord4 = (value) => Boolean(value) && typeof value === "object";
4771
5181
  var isAsyncLocalStorage3 = (value) => isObjectRecord4(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
@@ -4781,7 +5191,7 @@ var ensureWarningStorage = () => {
4781
5191
  if (existing) {
4782
5192
  return existing;
4783
5193
  }
4784
- const storage = new AsyncLocalStorage3;
5194
+ const storage = new AsyncLocalStorage4;
4785
5195
  Reflect.set(globalThis, STREAMING_SLOT_WARNING_STORAGE_KEY2, storage);
4786
5196
  return storage;
4787
5197
  };
@@ -4812,7 +5222,9 @@ setStreamingSlotWarningController({
4812
5222
  }
4813
5223
  });
4814
5224
  var captureStreamingSlotWarningCallsite = () => {
4815
- if (false) {}
5225
+ if (isProductionRuntime()) {
5226
+ return;
5227
+ }
4816
5228
  const { stack } = new Error;
4817
5229
  if (!stack) {
4818
5230
  return;
@@ -4824,18 +5236,112 @@ var runWithStreamingSlotWarningScope = (task, metadata) => ensureWarningStorage(
4824
5236
  // src/svelte/pageHandler.ts
4825
5237
  init_routeAssets();
4826
5238
  init_inlinePageCss();
5239
+ init_ssrErrorPage();
4827
5240
  init_spaRouteManifest();
4828
5241
  init_resolveConvention();
4829
5242
  init_browserTranslation();
4830
- var isRecord3 = (value) => typeof value === "object" && value !== null;
4831
- var isGenericSvelteComponent = (value) => typeof value === "function" || isRecord3(value);
5243
+
5244
+ // src/svelte/routerSsr.ts
5245
+ init_lazyModule();
5246
+ var SVELTE_ROUTER_SSR_CONTEXT_KEY = Symbol.for("absolutejs.svelte-router.ssr");
5247
+ var REDIRECT_STATUS = 302;
5248
+ var FORBIDDEN_STATUS = 403;
5249
+ var runSequentially = async (tasks, index = 0) => {
5250
+ const task = tasks[index];
5251
+ if (!task)
5252
+ return;
5253
+ await task();
5254
+ await runSequentially(tasks, index + 1);
5255
+ };
5256
+ var toResolved = (value) => {
5257
+ const component = toLazyComponent(value);
5258
+ const resolved = component ? { component, source: readLazySource(value) } : {
5259
+ error: new Error('A lazy <Route> loader must resolve to a Svelte component or to a module whose default export is one, e.g. `() => import("./Page.svelte")`.')
5260
+ };
5261
+ return resolved;
5262
+ };
5263
+ var createSvelteRouterSsr = (request) => {
5264
+ const tasks = [];
5265
+ const pending = new Map;
5266
+ const resolved = new Map;
5267
+ let outcome;
5268
+ const state = {
5269
+ request,
5270
+ resolved,
5271
+ settledGuards: new Set,
5272
+ afterRender: (task) => {
5273
+ tasks.push(task);
5274
+ },
5275
+ load: (key, loader) => {
5276
+ if (resolved.has(key) || pending.has(key))
5277
+ return;
5278
+ const settle = Promise.resolve().then(loader).then((value) => {
5279
+ resolved.set(key, toResolved(value));
5280
+ }, (error) => {
5281
+ resolved.set(key, { error });
5282
+ });
5283
+ pending.set(key, settle);
5284
+ },
5285
+ outcome: () => outcome,
5286
+ setOutcome: (next) => {
5287
+ outcome ??= next;
5288
+ }
5289
+ };
5290
+ const settle = async () => {
5291
+ await runSequentially(tasks.splice(0));
5292
+ if (outcome !== undefined)
5293
+ return false;
5294
+ if (pending.size === 0)
5295
+ return false;
5296
+ const loads = Array.from(pending.values());
5297
+ pending.clear();
5298
+ await Promise.all(loads);
5299
+ return true;
5300
+ };
5301
+ const response = () => {
5302
+ if (!outcome)
5303
+ return;
5304
+ if (outcome.kind === "redirect") {
5305
+ return new Response(null, {
5306
+ headers: { Location: outcome.location },
5307
+ status: REDIRECT_STATUS
5308
+ });
5309
+ }
5310
+ return new Response("Forbidden", {
5311
+ headers: { "Content-Type": "text/plain; charset=utf-8" },
5312
+ status: FORBIDDEN_STATUS
5313
+ });
5314
+ };
5315
+ const bootstrapScript = () => {
5316
+ const sources = {};
5317
+ for (const [key, entry] of resolved) {
5318
+ if ("component" in entry && entry.source)
5319
+ sources[key] = entry.source;
5320
+ }
5321
+ if (Object.keys(sources).length === 0)
5322
+ return "";
5323
+ return `window.__ABS_SVELTE_LAZY_ROUTES__=${JSON.stringify(sources)};`;
5324
+ };
5325
+ return {
5326
+ bootstrapScript,
5327
+ context: new Map([
5328
+ [SVELTE_ROUTER_SSR_CONTEXT_KEY, state]
5329
+ ]),
5330
+ response,
5331
+ settle
5332
+ };
5333
+ };
5334
+
5335
+ // src/svelte/pageHandler.ts
5336
+ var isRecord5 = (value) => typeof value === "object" && value !== null;
5337
+ var isGenericSvelteComponent = (value) => typeof value === "function" || isRecord5(value);
4832
5338
  var readHasIslands = (value) => {
4833
- if (!isRecord3(value))
5339
+ if (!isRecord5(value))
4834
5340
  return false;
4835
5341
  const hasIslands = value["__ABSOLUTE_PAGE_HAS_ISLANDS__"];
4836
5342
  return typeof hasIslands === "boolean" ? hasIslands : false;
4837
5343
  };
4838
- var readDefaultExport = (value) => isRecord3(value) ? value.default : undefined;
5344
+ var readDefaultExport = (value) => isRecord5(value) ? value.default : undefined;
4839
5345
  var primeSvelteStream = async (stream) => {
4840
5346
  const reader = stream.getReader();
4841
5347
  const firstChunk = await reader.read();
@@ -4881,7 +5387,7 @@ var handleSveltePageRequest = async (input) => {
4881
5387
  const userProps = input.props;
4882
5388
  const request = input.request ?? getCurrentAbsoluteRequest();
4883
5389
  const requestPathname = resolveRequestPathname(request);
4884
- const resolvedProps = requestPathname !== undefined && (!isRecord3(userProps) || !("url" in userProps)) ? {
5390
+ const resolvedProps = requestPathname !== undefined && (!isRecord5(userProps) || !("url" in userProps)) ? {
4885
5391
  ...userProps ?? {},
4886
5392
  url: requestPathname
4887
5393
  } : userProps;
@@ -4947,13 +5453,19 @@ var handleSveltePageRequest = async (input) => {
4947
5453
  await Promise.resolve().then(() => init_renderToReadableStream());
4948
5454
  const resolvedPage = await resolvePageComponent();
4949
5455
  const siblingCss = await readSiblingCss(resolvedPagePath);
4950
- const cssBlock = siblingCss ? `<style data-absolute-page-css>${siblingCss}</style>` : "";
5456
+ const cssBlock = siblingCss ? `<style data-absolute-page-css${nonceAttr()}>${siblingCss}</style>` : "";
4951
5457
  const composedHeadContent = `${cssBlock}${withDeferredStylesheets(resolvedOptions?.headContent ?? "", deferredAssets)}`;
5458
+ const routerSsr = createSvelteRouterSsr(request);
4952
5459
  const stream = await renderToReadableStream(resolvedPage.component, resolvedProps, {
4953
5460
  bodyContent: resolvedOptions?.bodyContent,
4954
- bootstrapScriptContent: `${BROWSER_TRANSLATION_BASELINE_SCRIPT}window.__ABS_SLOT_HYDRATION_PENDING__=true;window.__INITIAL_PROPS__=${JSON.stringify(resolvedProps)};${resolvedIndexPath ? `import(${JSON.stringify(resolvedIndexPath)});` : ""}`,
4955
- headContent: composedHeadContent
5461
+ context: routerSsr.context,
5462
+ headContent: composedHeadContent,
5463
+ settle: routerSsr.settle,
5464
+ bootstrapScriptContent: () => `${BROWSER_TRANSLATION_BASELINE_SCRIPT}window.__ABS_SLOT_HYDRATION_PENDING__=true;${routerSsr.bootstrapScript()}window.__INITIAL_PROPS__=${JSON.stringify(resolvedProps)};${resolvedIndexPath ? `import(${JSON.stringify(resolvedIndexPath)});` : ""}`
4956
5465
  });
5466
+ const routerResponse = routerSsr.response();
5467
+ if (routerResponse)
5468
+ return routerResponse;
4957
5469
  const htmlStream = injectIslandPageContextStream(stream, {
4958
5470
  hasIslands: resolvedPage.hasIslands ? true : undefined
4959
5471
  });
@@ -4982,6 +5494,391 @@ var handleSveltePageRequest = async (input) => {
4982
5494
  }), request);
4983
5495
  }
4984
5496
  };
5497
+ // src/core/fileRouteAdapter.ts
5498
+ var PARAM_NAME_RE = /:([A-Za-z_$][\w$]*)/g;
5499
+ var paramNamesOf = (path) => [...path.matchAll(PARAM_NAME_RE)].map((match) => match[1]).filter((name) => name !== undefined);
5500
+ var hasRouteParams = (context, names) => names.every((name) => typeof context.params[name] === "string");
5501
+ var serverHooksOf = ({
5502
+ path,
5503
+ server
5504
+ }) => {
5505
+ if (!server)
5506
+ return {};
5507
+ const names = paramNamesOf(path);
5508
+ const withParams = async (context, run) => {
5509
+ const module = await server();
5510
+ if (!module || !hasRouteParams(context, names))
5511
+ return;
5512
+ return run(module, context);
5513
+ };
5514
+ const hooks = {
5515
+ beforeHandle: (context) => withParams(context, (module, typed) => module.beforeHandle?.(typed)),
5516
+ load: (context) => withParams(context, (module, typed) => module.load?.(typed))
5517
+ };
5518
+ return hooks;
5519
+ };
5520
+ var defineFileRouteWith = (framework, route, render) => {
5521
+ const definition = {
5522
+ framework,
5523
+ name: route.name,
5524
+ path: route.path,
5525
+ render,
5526
+ source: route.source,
5527
+ ...serverHooksOf(route)
5528
+ };
5529
+ return definition;
5530
+ };
5531
+
5532
+ // src/core/lookup.ts
5533
+ init_requestContext();
5534
+ var asset = (source, name) => {
5535
+ const assetPath = source[name];
5536
+ if (assetPath === undefined) {
5537
+ if (isProductionRuntime()) {
5538
+ throw new Error(`Asset "${name}" not found in manifest.`);
5539
+ }
5540
+ recordMissingAsset(name);
5541
+ const page = getDevPageWarmer()?.describe(name);
5542
+ if (page !== undefined && !page.built)
5543
+ return "";
5544
+ console.warn(`[asset] key "${name}" not found in manifest (dev mode \u2014 skipping)`);
5545
+ return "";
5546
+ }
5547
+ return assetPath;
5548
+ };
5549
+
5550
+ // src/svelte/fileRoute.ts
5551
+ var svelteFileRoute = (route) => defineFileRouteWith("svelte", route, async ({ manifest, props, request }) => handleSveltePageRequest({
5552
+ indexPath: asset(manifest, `${route.name}Index`),
5553
+ pagePath: asset(manifest, route.name),
5554
+ props,
5555
+ request
5556
+ }));
5557
+ // src/svelte/i18n.ts
5558
+ import { getContext, hasContext, setContext } from "svelte";
5559
+
5560
+ // src/i18n/intlCache.ts
5561
+ var numberFormats = new Map;
5562
+ var dateTimeFormats = new Map;
5563
+ var pluralRules = new Map;
5564
+ var relativeTimeFormats = new Map;
5565
+ var listFormats = new Map;
5566
+ var cacheKey = (locale, options) => `${locale}|${options ? JSON.stringify(options) : ""}`;
5567
+ var cached = (cache, key, create) => {
5568
+ const existing = cache.get(key);
5569
+ if (existing)
5570
+ return existing;
5571
+ const created = create();
5572
+ cache.set(key, created);
5573
+ return created;
5574
+ };
5575
+ var getDateTimeFormat = (locale, options) => cached(dateTimeFormats, cacheKey(locale, options), () => new Intl.DateTimeFormat(locale, options));
5576
+ var getListFormat = (locale, options) => cached(listFormats, cacheKey(locale, options), () => new Intl.ListFormat(locale, options));
5577
+ var getNumberFormat = (locale, options) => cached(numberFormats, cacheKey(locale, options), () => new Intl.NumberFormat(locale, options));
5578
+ var getPluralRules = (locale, options) => cached(pluralRules, cacheKey(locale, options), () => new Intl.PluralRules(locale, options));
5579
+ var getRelativeTimeFormat = (locale, options) => cached(relativeTimeFormats, cacheKey(locale, options), () => new Intl.RelativeTimeFormat(locale, options));
5580
+
5581
+ // src/i18n/formatMessage.ts
5582
+ var SYNTAX_CHARS = new Set(["{", "}", "#", "|"]);
5583
+ var WHITESPACE = /\s/;
5584
+ var isBranchKind = (value) => value === "plural" || value === "select" || value === "selectordinal";
5585
+ var skipWhitespace = (cursor) => {
5586
+ while (cursor.index < cursor.source.length && WHITESPACE.test(cursor.source.charAt(cursor.index))) {
5587
+ cursor.index += 1;
5588
+ }
5589
+ };
5590
+ var syntaxError = (cursor, expected) => new SyntaxError(`Invalid ICU message (expected ${expected} at ${cursor.index}): ${cursor.source}`);
5591
+ var readToken = (cursor, stops) => {
5592
+ const start = cursor.index;
5593
+ while (cursor.index < cursor.source.length && !stops.includes(cursor.source.charAt(cursor.index))) {
5594
+ cursor.index += 1;
5595
+ }
5596
+ return cursor.source.slice(start, cursor.index).trim();
5597
+ };
5598
+ var expectChar = (cursor, char) => {
5599
+ skipWhitespace(cursor);
5600
+ if (cursor.source.charAt(cursor.index) !== char)
5601
+ throw syntaxError(cursor, `"${char}"`);
5602
+ cursor.index += 1;
5603
+ };
5604
+ var readQuoted = (cursor, inPlural) => {
5605
+ const next = cursor.source.charAt(cursor.index + 1);
5606
+ if (next === "'") {
5607
+ cursor.index += 2;
5608
+ return "'";
5609
+ }
5610
+ const opensQuote = SYNTAX_CHARS.has(next) && (next !== "#" || inPlural);
5611
+ if (!opensQuote) {
5612
+ cursor.index += 1;
5613
+ return "'";
5614
+ }
5615
+ cursor.index += 1;
5616
+ let text = "";
5617
+ while (cursor.index < cursor.source.length) {
5618
+ const char = cursor.source.charAt(cursor.index);
5619
+ const isEscapedQuote = char === "'" && cursor.source.charAt(cursor.index + 1) === "'";
5620
+ if (char === "'" && !isEscapedQuote)
5621
+ break;
5622
+ text += char;
5623
+ cursor.index += isEscapedQuote ? 2 : 1;
5624
+ }
5625
+ cursor.index += 1;
5626
+ return text;
5627
+ };
5628
+ var pushText = (nodes, value) => {
5629
+ const last = nodes[nodes.length - 1];
5630
+ if (last?.kind === "text") {
5631
+ last.value += value;
5632
+ return;
5633
+ }
5634
+ nodes.push({ kind: "text", value });
5635
+ };
5636
+ var parseBranchOption = (cursor, kind, branches) => {
5637
+ if (cursor.index >= cursor.source.length)
5638
+ throw syntaxError(cursor, '"}"');
5639
+ const selector = readToken(cursor, `{}
5640
+ \r`);
5641
+ const offsetMatch = /^offset:(\d+)$/.exec(selector);
5642
+ if (offsetMatch && kind !== "select") {
5643
+ branches.offset = Number(offsetMatch[1]);
5644
+ skipWhitespace(cursor);
5645
+ return;
5646
+ }
5647
+ if (selector === "")
5648
+ throw syntaxError(cursor, "a selector");
5649
+ expectChar(cursor, "{");
5650
+ branches.options[selector] = parseNodes(cursor, kind !== "select");
5651
+ expectChar(cursor, "}");
5652
+ skipWhitespace(cursor);
5653
+ };
5654
+ var parseBranchOptions = (cursor, kind) => {
5655
+ const branches = { offset: 0, options: {} };
5656
+ skipWhitespace(cursor);
5657
+ while (cursor.source.charAt(cursor.index) !== "}") {
5658
+ parseBranchOption(cursor, kind, branches);
5659
+ }
5660
+ if (branches.options.other === undefined)
5661
+ throw syntaxError(cursor, 'an "other" branch');
5662
+ return branches;
5663
+ };
5664
+ var parseArgument = (cursor) => {
5665
+ skipWhitespace(cursor);
5666
+ const name = readToken(cursor, ",}");
5667
+ if (name === "")
5668
+ throw syntaxError(cursor, "an argument name");
5669
+ if (cursor.source.charAt(cursor.index) === "}") {
5670
+ cursor.index += 1;
5671
+ return { format: undefined, kind: "argument", name, style: undefined };
5672
+ }
5673
+ cursor.index += 1;
5674
+ const format = readToken(cursor, ",}");
5675
+ if (isBranchKind(format)) {
5676
+ expectChar(cursor, ",");
5677
+ const { offset, options } = parseBranchOptions(cursor, format);
5678
+ expectChar(cursor, "}");
5679
+ return { kind: format, name, offset, options };
5680
+ }
5681
+ let style;
5682
+ if (cursor.source.charAt(cursor.index) === ",") {
5683
+ cursor.index += 1;
5684
+ style = readToken(cursor, "}");
5685
+ }
5686
+ expectChar(cursor, "}");
5687
+ return { format, kind: "argument", name, style };
5688
+ };
5689
+ var parseNode = (cursor, inPlural, nodes) => {
5690
+ const char = cursor.source.charAt(cursor.index);
5691
+ if (char === "{") {
5692
+ cursor.index += 1;
5693
+ nodes.push(parseArgument(cursor));
5694
+ return;
5695
+ }
5696
+ if (char === "#" && inPlural) {
5697
+ cursor.index += 1;
5698
+ nodes.push({ kind: "pound" });
5699
+ return;
5700
+ }
5701
+ if (char === "'") {
5702
+ pushText(nodes, readQuoted(cursor, inPlural));
5703
+ return;
5704
+ }
5705
+ pushText(nodes, char);
5706
+ cursor.index += 1;
5707
+ };
5708
+ var parseNodes = (cursor, inPlural) => {
5709
+ const nodes = [];
5710
+ while (cursor.index < cursor.source.length && cursor.source.charAt(cursor.index) !== "}") {
5711
+ parseNode(cursor, inPlural, nodes);
5712
+ }
5713
+ return nodes;
5714
+ };
5715
+ var parseMessage = (source) => {
5716
+ const cursor = { index: 0, source };
5717
+ const nodes = parseNodes(cursor, false);
5718
+ if (cursor.index < source.length)
5719
+ throw syntaxError(cursor, "end of message");
5720
+ return nodes;
5721
+ };
5722
+ var parsedCache = new Map;
5723
+ var parseCached = (source) => {
5724
+ const cached = parsedCache.get(source);
5725
+ if (cached)
5726
+ return cached;
5727
+ let parsed;
5728
+ try {
5729
+ parsed = parseMessage(source);
5730
+ } catch (error) {
5731
+ parsed = error instanceof SyntaxError ? error : new SyntaxError(String(error));
5732
+ }
5733
+ parsedCache.set(source, parsed);
5734
+ return parsed;
5735
+ };
5736
+ var INTEGER_OPTIONS = { maximumFractionDigits: 0 };
5737
+ var PERCENT_OPTIONS = { style: "percent" };
5738
+ var numberOptions = (style) => {
5739
+ if (style === "integer")
5740
+ return INTEGER_OPTIONS;
5741
+ if (style === "percent")
5742
+ return PERCENT_OPTIONS;
5743
+ const currency = /^::currency\/([A-Za-z]{3})$/.exec(style ?? "");
5744
+ const options = currency?.[1] ? { currency: currency[1].toUpperCase(), style: "currency" } : {};
5745
+ return options;
5746
+ };
5747
+ var toDate = (value) => {
5748
+ if (value instanceof Date)
5749
+ return value;
5750
+ if (typeof value === "number" || typeof value === "string")
5751
+ return new Date(value);
5752
+ return;
5753
+ };
5754
+ var dateStyleOf = (style) => {
5755
+ if (style === "full" || style === "long" || style === "short")
5756
+ return style;
5757
+ return "medium";
5758
+ };
5759
+ var formatDateArgument = (locale, value, format, style) => {
5760
+ const date = toDate(value);
5761
+ if (!date || Number.isNaN(date.getTime()))
5762
+ return String(value);
5763
+ const resolvedStyle = dateStyleOf(style);
5764
+ const options = format === "date" ? { dateStyle: resolvedStyle } : { timeStyle: resolvedStyle };
5765
+ return getDateTimeFormat(locale, options).format(date);
5766
+ };
5767
+ var formatValue = (locale, value) => {
5768
+ if (typeof value === "number" || typeof value === "bigint")
5769
+ return getNumberFormat(locale).format(value);
5770
+ if (value instanceof Date)
5771
+ return getDateTimeFormat(locale).format(value);
5772
+ return String(value);
5773
+ };
5774
+ var formatArgument = (locale, node, params) => {
5775
+ if (!(node.name in params))
5776
+ return `{${node.name}}`;
5777
+ const value = params[node.name];
5778
+ if (node.format === "number") {
5779
+ const numeric = typeof value === "bigint" ? value : Number(value);
5780
+ return getNumberFormat(locale, numberOptions(node.style)).format(numeric);
5781
+ }
5782
+ if (node.format === "date" || node.format === "time")
5783
+ return formatDateArgument(locale, value, node.format, node.style);
5784
+ return formatValue(locale, value);
5785
+ };
5786
+ var selectBranch = (locale, node, value) => {
5787
+ if (node.kind === "select") {
5788
+ return node.options[String(value)] ?? node.options.other ?? [];
5789
+ }
5790
+ const numeric = Number(value);
5791
+ const exact = node.options[`=${numeric}`];
5792
+ if (exact)
5793
+ return exact;
5794
+ const category = getPluralRules(locale, {
5795
+ type: node.kind === "selectordinal" ? "ordinal" : "cardinal"
5796
+ }).select(numeric - node.offset);
5797
+ return node.options[category] ?? node.options.other ?? [];
5798
+ };
5799
+ var formatNodes = (locale, nodes, params, pound) => nodes.map((node) => {
5800
+ if (node.kind === "text")
5801
+ return node.value;
5802
+ if (node.kind === "pound")
5803
+ return pound ?? "#";
5804
+ if (node.kind === "argument")
5805
+ return formatArgument(locale, node, params);
5806
+ if (!(node.name in params))
5807
+ return `{${node.name}}`;
5808
+ const value = params[node.name];
5809
+ const branch = selectBranch(locale, node, value);
5810
+ const branchPound = node.kind === "select" ? pound : getNumberFormat(locale).format(Number(value) - node.offset);
5811
+ return formatNodes(locale, branch, params, branchPound);
5812
+ }).join("");
5813
+ var formatMessage = (locale, message, params = {}) => {
5814
+ if (!message.includes("{") && !message.includes("'"))
5815
+ return message;
5816
+ const parsed = parseCached(message);
5817
+ if (parsed instanceof SyntaxError)
5818
+ return message;
5819
+ return formatNodes(locale, parsed, params, undefined);
5820
+ };
5821
+
5822
+ // src/i18n/translator.ts
5823
+ var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5824
+ var lookupMessage = (messages, key) => {
5825
+ let node = messages;
5826
+ for (const segment of key.split(".")) {
5827
+ if (typeof node !== "object")
5828
+ return;
5829
+ node = node[segment];
5830
+ }
5831
+ return typeof node === "string" ? node : undefined;
5832
+ };
5833
+ var isMessageTreeValue = (value) => typeof value === "string" || isMessageTree(value);
5834
+ var isI18nPayload = (value) => isRecord6(value) && typeof value.locale === "string" && typeof value.defaultLocale === "string" && (value.dir === "ltr" || value.dir === "rtl") && isMessageTree(value.messages);
5835
+ var isMessageTree = (value) => isRecord6(value) && Object.values(value).every(isMessageTreeValue);
5836
+ var toDate2 = (value) => value instanceof Date ? value : new Date(value);
5837
+ var warnedKeys = new Set;
5838
+ var warnMissing = (locale, key) => {
5839
+ const id = `${locale}:${key}`;
5840
+ if (warnedKeys.has(id))
5841
+ return;
5842
+ warnedKeys.add(id);
5843
+ console.warn(`[i18n] Missing message "${key}" for locale "${locale}"`);
5844
+ };
5845
+ var createTranslator = (payload) => {
5846
+ const { locale, messages } = payload;
5847
+ const t = (key, ...args) => {
5848
+ const message = lookupMessage(messages, key);
5849
+ if (message === undefined) {
5850
+ warnMissing(locale, key);
5851
+ return key;
5852
+ }
5853
+ const [params] = args;
5854
+ return formatMessage(locale, message, isRecord6(params) ? params : {});
5855
+ };
5856
+ const translator = {
5857
+ dir: payload.dir,
5858
+ locale,
5859
+ t,
5860
+ formatDate: (value, options) => getDateTimeFormat(locale, options).format(toDate2(value)),
5861
+ formatList: (items, options) => getListFormat(locale, options).format(items),
5862
+ formatNumber: (value, options) => getNumberFormat(locale, options).format(value),
5863
+ formatRelativeTime: (value, unit, options) => getRelativeTimeFormat(locale, options).format(value, unit),
5864
+ has: (key) => lookupMessage(messages, key) !== undefined
5865
+ };
5866
+ return translator;
5867
+ };
5868
+
5869
+ // src/svelte/i18n.ts
5870
+ var I18N_CONTEXT = Symbol.for("absolutejs.i18n");
5871
+ var getI18n = () => {
5872
+ const payload = hasContext(I18N_CONTEXT) ? getContext(I18N_CONTEXT) : undefined;
5873
+ if (!isI18nPayload(payload)) {
5874
+ throw new Error("getI18n() found no messages: call setI18n(payload) in the page component first");
5875
+ }
5876
+ return createTranslator(payload);
5877
+ };
5878
+ var setI18n = (payload) => {
5879
+ setContext(I18N_CONTEXT, payload);
5880
+ return createTranslator(payload);
5881
+ };
4985
5882
  // src/svelte/createIsland.ts
4986
5883
  init_renderIslandMarkup();
4987
5884
  var createTypedIsland = (registry) => (props) => renderIslandMarkup(registry, props);
@@ -5100,12 +5997,15 @@ var resolveIslandHtml = (_slotId, props) => renderIslandMarkup(requireCurrentIsl
5100
5997
  init_renderToReadableStream();
5101
5998
  export {
5102
5999
  createTypedIsland,
6000
+ getI18n,
5103
6001
  handleSveltePageRequest,
5104
6002
  renderIsland,
5105
6003
  renderToReadableStream,
5106
6004
  resolveIslandHtml,
6005
+ setI18n,
6006
+ svelteFileRoute,
5107
6007
  useIslandStore
5108
6008
  };
5109
6009
 
5110
- //# debugId=AC27A68B02DE194B64756E2164756E21
6010
+ //# debugId=BBD497D139E396B564756E2164756E21
5111
6011
  //# sourceMappingURL=index.js.map