@askrjs/askr 0.3.0 → 0.4.0

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 (123) hide show
  1. package/CHANGELOG.md +874 -0
  2. package/README.md +61 -29
  3. package/capabilities.json +19 -9
  4. package/dist/actions/index.js +56 -12
  5. package/dist/benchmark.js +10 -15
  6. package/dist/boot/index.d.ts +3 -2
  7. package/dist/boot/index.js +1 -1
  8. package/dist/boot-DaoTYoCw.js +3989 -0
  9. package/dist/browser-activity-CB8e-V4f.js +220 -0
  10. package/dist/components/index.d.ts +8 -1
  11. package/dist/components/index.js +1 -43
  12. package/dist/{aria-hKjThHcp.js → compose-ref-DWzdbxsD.js} +41 -4
  13. package/dist/control/index.d.ts +2 -0
  14. package/dist/control/index.js +1 -1
  15. package/dist/control-nfpT2fbK.js +209 -0
  16. package/dist/core.d.ts +5 -9
  17. package/dist/csp-nonce-DwGw1A6Q.js +35 -0
  18. package/dist/data/index.js +3 -3
  19. package/dist/{data-2edW0jhF.js → data-BCwClJiF.js} +283 -94
  20. package/dist/data-runtime-C1bFAlba.js +242 -0
  21. package/dist/{deferred-CbgNhf67.js → deferred-bEEHHvic.js} +42 -20
  22. package/dist/domains/actions.d.ts +8 -3
  23. package/dist/domains/component.d.ts +1 -107
  24. package/dist/domains/context.d.ts +0 -15
  25. package/dist/domains/control.d.ts +36 -249
  26. package/dist/domains/data.d.ts +31 -13
  27. package/dist/domains/diagnostics.d.ts +1 -2
  28. package/dist/domains/lifecycle.d.ts +2 -5
  29. package/dist/domains/refs.d.ts +0 -2
  30. package/dist/domains/routing.d.ts +43 -8
  31. package/dist/domains/scheduler.d.ts +1 -76
  32. package/dist/domains/server.d.ts +5 -2
  33. package/dist/domains/state.d.ts +2 -5
  34. package/dist/domains/telemetry.d.ts +0 -2
  35. package/dist/elements.d.ts +214 -51
  36. package/dist/error-boundary-Bpwofwps.js +293 -0
  37. package/dist/foundations/icon/index.d.ts +0 -58
  38. package/dist/foundations/icon/index.js +2 -2
  39. package/dist/foundations/index.js +2 -1
  40. package/dist/foundations/interactions/index.js +1 -1
  41. package/dist/foundations/state/index.d.ts +3 -3
  42. package/dist/foundations/state/index.js +5 -3
  43. package/dist/foundations/structures/index.js +2 -1
  44. package/dist/foundations/utilities/index.d.ts +2 -0
  45. package/dist/foundations/utilities/index.js +1 -2
  46. package/dist/fx/index.d.ts +31 -58
  47. package/dist/fx/index.js +313 -195
  48. package/dist/hooks-BimKStr4.js +202 -0
  49. package/dist/index.d.ts +11 -74
  50. package/dist/index.js +8 -447
  51. package/dist/instance-BAnfmXOR.js +988 -0
  52. package/dist/{interactions-CTeACdT_.js → interactions-D2BoREb-.js} +3 -2
  53. package/dist/jsx-dev-runtime.d.ts +41 -18
  54. package/dist/jsx-dev-runtime.js +1 -6
  55. package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
  56. package/dist/jsx-runtime.js +1 -1
  57. package/dist/jsx.d.ts +61 -37
  58. package/dist/{manifest-D1P3UNWV.js → manifest-CW9gyNBY.js} +3 -3
  59. package/dist/{navigate-prC5V8XV.js → navigate-CP_0Zy5U.js} +454 -87
  60. package/dist/navigation.d.ts +12 -3
  61. package/dist/peer-types.d.ts +8 -0
  62. package/dist/portal-DuOKfnLa.js +349 -0
  63. package/dist/promise-Dz8iIHAm.js +16 -0
  64. package/dist/query-registry-WMCN0BJL.js +320 -0
  65. package/dist/readable-DFWOsTac.js +21 -0
  66. package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
  67. package/dist/render-sync-IC5lMFpq.js +1240 -0
  68. package/dist/resolution-Cx82-xjW.js +1244 -0
  69. package/dist/resource-CLjB7RBQ.js +377 -0
  70. package/dist/resources/index.d.ts +21 -11
  71. package/dist/resources/index.js +45 -244
  72. package/dist/router/index.d.ts +14 -5
  73. package/dist/router/index.js +22 -53
  74. package/dist/scope-CwpVSHVf.js +55 -0
  75. package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
  76. package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
  77. package/dist/ssg/index.d.ts +1 -2
  78. package/dist/ssg/index.js +5 -13
  79. package/dist/ssr/index.d.ts +26 -28
  80. package/dist/ssr/index.js +4 -4
  81. package/dist/{ssr-CiNm6Vzl.js → ssr-BJ8ug7zH.js} +133 -122
  82. package/dist/ssr-DoV-vJ-5.js +229 -0
  83. package/dist/state-DWO1KzkX.js +232 -0
  84. package/dist/structures-D4dDMqHX.js +231 -0
  85. package/dist/testing/index.d.ts +8 -4
  86. package/dist/testing/index.js +29 -34
  87. package/dist/url-CnbfpX0K.js +185 -0
  88. package/dist/utilities.d.ts +48 -2
  89. package/dist/verify-hydration-DpVaDnqz.js +152 -0
  90. package/package.json +19 -9
  91. package/dist/access-CEA2pOry.js +0 -1046
  92. package/dist/activity-oy2YFTFF.js +0 -201
  93. package/dist/boot-BMBMWUGI.js +0 -1084
  94. package/dist/capabilities-Bbf0mlp9.js +0 -42
  95. package/dist/compose-ref-v0qGlHoN.js +0 -26
  96. package/dist/control-BR_mrX__.js +0 -173
  97. package/dist/control-C-ApnFs1.js +0 -20
  98. package/dist/csp-nonce-BfFWcd0w.js +0 -173
  99. package/dist/data-runtime-CxoY98lX.js +0 -149
  100. package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
  101. package/dist/dom-renderer.d.ts +0 -77
  102. package/dist/domains/renderer.d.ts +0 -127
  103. package/dist/eager-control.d.ts +0 -8
  104. package/dist/effect-C3Zsc1k6.js +0 -292
  105. package/dist/for-state-BDykeOJL.js +0 -1753
  106. package/dist/instance-VAFYVJOa.js +0 -1027
  107. package/dist/notify-DxxuDPeY.js +0 -266
  108. package/dist/portal-w3oQ6oQU.js +0 -29
  109. package/dist/query-registry-LrYpQsDJ.js +0 -83
  110. package/dist/render-resolved-BC0W7_5b.js +0 -1123
  111. package/dist/renderer-CT0HeY58.js +0 -8623
  112. package/dist/resolution-3DskUkjG.js +0 -577
  113. package/dist/resource-18-sFRl9.js +0 -344
  114. package/dist/route-matching-CUzZ31gT.js +0 -551
  115. package/dist/router-internal-7nuNEHfG.js +0 -36
  116. package/dist/scope-Cq_iYbTR.js +0 -403
  117. package/dist/selector-BSPVkjKP.js +0 -311
  118. package/dist/ssr-EPjwJH5R.js +0 -29
  119. package/dist/state-BXJfudq1.js +0 -91
  120. package/dist/structures-CjEzfj4h.js +0 -654
  121. package/dist/timer-C7uqnJVt.js +0 -85
  122. package/dist/verify-hydration-ikaxotf7.js +0 -27
  123. package/dist/vnode-D24p6IW2.js +0 -7
@@ -0,0 +1,1240 @@
1
+ import { A as untrack, F as logger, j as Owner, t as ComponentInstance } from "./instance-BAnfmXOR.js";
2
+ import { n as readValue } from "./readable-DFWOsTac.js";
3
+ import { n as Fragment, t as ELEMENT_TYPE } from "./jsx-DRS-qjiN.js";
4
+ import { v as clarifyRenderOverflow } from "./hooks-BimKStr4.js";
5
+ import { r as validateCspNonce, t as CspNonceScope } from "./csp-nonce-DwGw1A6Q.js";
6
+ import { C as withHydrationRenderUrl, T as SSRDataMissingError, _ as createPageRenderEnvelope, b as isPageRenderEnvelope, f as startRenderPhase$1, m as stopRenderPhase$1, r as getCurrentRenderData, t as configureRenderContextProvider, w as withPageFramework, y as isEmptyPageRenderEnvelope } from "./render-context-DGHnEveC.js";
7
+ import { o as functionChildOutput, s as normalizeChildren } from "./error-boundary-Bpwofwps.js";
8
+ import { n as isPromiseLike } from "./promise-Dz8iIHAm.js";
9
+ import { d as DEFERRED_BOUNDARY, i as dehydrateDataRuntime, p as isDeferred } from "./query-registry-WMCN0BJL.js";
10
+ import { ft as getRouteHydrationMetadata, ht as validateRouteHydrationData } from "./resolution-Cx82-xjW.js";
11
+ import { a as SSR_PORTAL_HOST, n as Portal, o as comparePortalWriterOrder, s as createSSRPortalAnchorToken, t as DefaultPortal } from "./portal-DuOKfnLa.js";
12
+ import { t as createDataRuntime } from "./data-runtime-C1bFAlba.js";
13
+ import { d as isCustomElementName, o as isUnsafeUrlAttribute, s as rejectUnsafeUrlAttribute, u as getPublicAttributeName } from "./url-CnbfpX0K.js";
14
+ import { d as booleanAttributeValue, f as isSkippedProp, h as styleValueText, l as isPropertyOnlyProp, m as normalizeStylePropertyName, p as keepsFalseValue, r as sanitizeCssValue, t as SSR_RENDER_DATA_ATTR } from "./ssr-DoV-vJ-5.js";
15
+ //#region src/ssr/escape.ts
16
+ /**
17
+ * HTML escaping utilities for SSR
18
+ *
19
+ * Centralizes text and attribute escaping to avoid duplication
20
+ * between sync and streaming SSR renderers.
21
+ */
22
+ const VOID_ELEMENTS = /* @__PURE__ */ new Set([
23
+ "area",
24
+ "base",
25
+ "br",
26
+ "col",
27
+ "embed",
28
+ "hr",
29
+ "img",
30
+ "input",
31
+ "link",
32
+ "meta",
33
+ "param",
34
+ "source",
35
+ "track",
36
+ "wbr"
37
+ ]);
38
+ const escapeCache = /* @__PURE__ */ new Map();
39
+ const MAX_CACHE_SIZE = 256;
40
+ const STYLE_PROP_CACHE = /* @__PURE__ */ new Map();
41
+ const MAX_STYLE_PROP_CACHE_SIZE = 512;
42
+ function toKebabCached(prop) {
43
+ const cached = STYLE_PROP_CACHE.get(prop);
44
+ if (cached !== void 0) return cached;
45
+ const kebab = normalizeStylePropertyName(prop);
46
+ if (STYLE_PROP_CACHE.size < MAX_STYLE_PROP_CACHE_SIZE) STYLE_PROP_CACHE.set(prop, kebab);
47
+ return kebab;
48
+ }
49
+ /**
50
+ * Clear the escape cache. Call between SSR requests in long-running servers
51
+ * to prevent memory buildup from unique strings.
52
+ */
53
+ function clearEscapeCache() {
54
+ escapeCache.clear();
55
+ }
56
+ /**
57
+ * Fast check if a string needs text escaping.
58
+ * Used to skip the full escape call when not needed.
59
+ */
60
+ function needsEscapeText(text) {
61
+ for (let i = 0; i < text.length; i++) {
62
+ const ch = text.charCodeAt(i);
63
+ if (ch === 38 || ch === 60 || ch === 62) return true;
64
+ }
65
+ return false;
66
+ }
67
+ /**
68
+ * Fast check if a string needs attribute escaping.
69
+ * Checks for & " ' < > characters.
70
+ */
71
+ function needsEscapeAttr(value) {
72
+ for (let i = 0; i < value.length; i++) {
73
+ const ch = value.charCodeAt(i);
74
+ if (ch === 38 || ch === 34 || ch === 39 || ch === 60 || ch === 62) return true;
75
+ }
76
+ return false;
77
+ }
78
+ /**
79
+ * Escape HTML special characters in text content
80
+ * Fast-path: cache first, then scan-then-escape for new strings
81
+ */
82
+ function escapeText(text) {
83
+ const useCache = text.length <= 64;
84
+ if (useCache) {
85
+ const cached = escapeCache.get(text);
86
+ if (cached !== void 0) return cached;
87
+ }
88
+ if (!needsEscapeText(text)) {
89
+ if (useCache && escapeCache.size < MAX_CACHE_SIZE) escapeCache.set(text, text);
90
+ return text;
91
+ }
92
+ let escaped = "";
93
+ let lastIndex = 0;
94
+ for (let i = 0; i < text.length; i++) {
95
+ const ch = text.charCodeAt(i);
96
+ let entity;
97
+ if (ch === 38) entity = "&amp;";
98
+ else if (ch === 60) entity = "&lt;";
99
+ else if (ch === 62) entity = "&gt;";
100
+ else continue;
101
+ escaped += text.slice(lastIndex, i) + entity;
102
+ lastIndex = i + 1;
103
+ }
104
+ const result = escaped + text.slice(lastIndex);
105
+ if (useCache && escapeCache.size < MAX_CACHE_SIZE) escapeCache.set(text, result);
106
+ return result;
107
+ }
108
+ /** Return the raw text element kind for a lower-case HTML tag name. */
109
+ function getRawTextElement(tag) {
110
+ return tag === "script" || tag === "style" ? tag : null;
111
+ }
112
+ const SCRIPT_RAW_TEXT_RE = /<(\/|!--|script)/gi;
113
+ /**
114
+ * Make text safe to emit verbatim inside an HTML raw text element.
115
+ *
116
+ * `<style>`: every `<` becomes the CSS escape `\3c ` (the space ends the
117
+ * escape and is consumed), so no markup can form whatever context the parser
118
+ * reads the text in. Inside CSS strings, `url()` and comments this denotes the
119
+ * original `<`; elsewhere (custom property values, range media queries) it
120
+ * reads back as an escaped identifier, since no escape can represent a bare
121
+ * `<` there.
122
+ *
123
+ * `<script>`: every `</` becomes `<\/`, so no end tag of this element or of
124
+ * any ancestor can form, and the `<` of `<!--` and `<script` is written as
125
+ * `\u003C`, which keeps the parser out of the script data (double) escaped
126
+ * states. Inside JS string, template and regex literals, and inside JSON
127
+ * strings (`application/json`, `importmap`, `application/ld+json`), each
128
+ * rewrite denotes the original characters; outside literals these sequences
129
+ * cannot be represented and may change meaning or fail to parse.
130
+ *
131
+ * Matching is case-insensitive. The whole text must be escaped at once: a
132
+ * sequence split across children only forms once they are concatenated.
133
+ */
134
+ function escapeRawText(text, element) {
135
+ if (!text.includes("<")) return text;
136
+ if (element === "style") return text.replaceAll("<", "\\3c ");
137
+ return text.replace(SCRIPT_RAW_TEXT_RE, (_match, rest) => rest === "/" ? "<\\/" : `\\u003C${rest}`);
138
+ }
139
+ /**
140
+ * Escape HTML special characters in attribute values.
141
+ * Single-pass scan: returns the original string unchanged when no special
142
+ * characters are found, so callers can drop separate needsEscapeAttr checks.
143
+ */
144
+ function escapeAttr(value) {
145
+ let escaped = "";
146
+ let lastIndex = 0;
147
+ for (let i = 0; i < value.length; i++) {
148
+ const ch = value.charCodeAt(i);
149
+ let entity;
150
+ if (ch === 38) entity = "&amp;";
151
+ else if (ch === 34) entity = "&quot;";
152
+ else if (ch === 39) entity = "&#x27;";
153
+ else if (ch === 60) entity = "&lt;";
154
+ else if (ch === 62) entity = "&gt;";
155
+ else continue;
156
+ escaped += value.slice(lastIndex, i) + entity;
157
+ lastIndex = i + 1;
158
+ }
159
+ return lastIndex === 0 ? value : escaped + value.slice(lastIndex);
160
+ }
161
+ /**
162
+ * Escape a string for interpolation into a hand-written HTML document template,
163
+ * either as text content or inside a quoted attribute value. Replaces `&`, `<`,
164
+ * `>`, `"` and `'` with character references. Use it for every request-derived
165
+ * value a `document` renderer interpolates, such as `context.pathname`,
166
+ * `context.params` or loader data. Do not use it for `appHtml`, which is
167
+ * already rendered markup, or inside `<script>`/`<style>` raw text.
168
+ * `null` and `undefined` render as an empty string; other values are
169
+ * converted with `String()`.
170
+ */
171
+ function escapeHtml(value) {
172
+ return value == null ? "" : escapeAttr(String(value));
173
+ }
174
+ /**
175
+ * Convert a style object to a CSS string, omitting unsafe values.
176
+ * Optimized to avoid Object.entries allocation
177
+ */
178
+ function styleObjToCss(value) {
179
+ if (!value || typeof value !== "object") return null;
180
+ const styleObj = value;
181
+ let result = "";
182
+ for (const k in styleObj) {
183
+ const v = styleObj[k];
184
+ if (v === null || v === void 0 || v === false) continue;
185
+ const prop = toKebabCached(k);
186
+ const safeValue = sanitizeCssValue(styleValueText(prop, v));
187
+ if (safeValue) result += `${prop}:${safeValue};`;
188
+ }
189
+ return result || null;
190
+ }
191
+ //#endregion
192
+ //#region src/ssr/context.ts
193
+ /**
194
+ * SSR Context Management
195
+ *
196
+ * Provides render-context storage for server-side rendering.
197
+ * The first render installs AsyncLocalStorage from `globalThis` or, on Node and
198
+ * Node-compatible runtimes (Deno, Bun, Workers with `nodejs_compat`), from
199
+ * `process.getBuiltinModule('node:async_hooks')`. Neither is a static import,
200
+ * so browser bundles never pull in the Node builtin. Runtimes without either
201
+ * use a synchronous fallback stack and reject async render contexts.
202
+ */
203
+ const FALLBACK_ASYNC_CONTEXT_ERROR = "[Askr] async SSR render context fallback is unsupported in this environment. Use synchronous SSR rendering or a runtime with AsyncLocalStorage (globalThis.AsyncLocalStorage or process.getBuiltinModule('node:async_hooks')).";
204
+ let renderContextAccessor = null;
205
+ let renderContextAccessorInitialized = false;
206
+ let fallbackStack = null;
207
+ function resolveAsyncLocalStorage() {
208
+ const host = globalThis;
209
+ return host.AsyncLocalStorage ?? host.process?.getBuiltinModule?.("node:async_hooks")?.AsyncLocalStorage;
210
+ }
211
+ function ensureRenderContextAccessor() {
212
+ if (renderContextAccessorInitialized) return;
213
+ renderContextAccessorInitialized = true;
214
+ const AsyncLocalStorage = resolveAsyncLocalStorage();
215
+ if (AsyncLocalStorage) renderContextAccessor = new AsyncLocalStorage();
216
+ }
217
+ function createRenderContext(seed = 12345, opts = {}) {
218
+ clearEscapeCache();
219
+ const queryCache = /* @__PURE__ */ new Map();
220
+ const envelope = opts.envelope ?? createPageRenderEnvelope({
221
+ resources: opts.data,
222
+ framework: opts.framework
223
+ });
224
+ const hydrationEnvelope = opts.url ? withHydrationRenderUrl(envelope, opts.url) : envelope;
225
+ return {
226
+ url: opts.url ?? "",
227
+ seed,
228
+ data: opts.data,
229
+ params: opts.params,
230
+ routes: opts.routes,
231
+ routeAuth: opts.routeAuth,
232
+ authContext: opts.authContext,
233
+ basePath: opts.basePath,
234
+ signal: opts.signal,
235
+ dataRuntime: opts.dataRuntime ?? createDataRuntime({ queryCache }),
236
+ mode: opts.mode ?? "ssr",
237
+ queryPrefetch: opts.queryPrefetch,
238
+ queryCache,
239
+ resourceDataProvided: opts.envelope ? Object.keys(envelope.resources).some((key) => key.startsWith("r:")) : opts.data !== void 0,
240
+ ssrCleanupFns: [],
241
+ keyCounter: 0,
242
+ renderData: envelope,
243
+ hydrationData: hydrationEnvelope,
244
+ deferredBoundaries: [],
245
+ ssrStyles: /* @__PURE__ */ new Map(),
246
+ ssrPortals: {
247
+ slots: /* @__PURE__ */ new Map(),
248
+ nextHostId: 0,
249
+ nextWriteOrder: 0
250
+ },
251
+ cspNonce: opts.cspNonce
252
+ };
253
+ }
254
+ /**
255
+ * Run a function with the given render context.
256
+ * Concurrency-safe on runtimes with AsyncLocalStorage (Node.js, Deno, Bun,
257
+ * Workers with `nodejs_compat`); elsewhere only synchronous work is accepted.
258
+ */
259
+ function withRenderContext(ctx, fn) {
260
+ ensureRenderContextProvider();
261
+ ensureRenderContextAccessor();
262
+ if (renderContextAccessor) return renderContextAccessor.run(ctx, fn);
263
+ const prev = fallbackStack;
264
+ fallbackStack = ctx;
265
+ try {
266
+ const result = fn();
267
+ if (isPromiseLike(result)) throw new Error(FALLBACK_ASYNC_CONTEXT_ERROR);
268
+ return result;
269
+ } finally {
270
+ fallbackStack = prev;
271
+ }
272
+ }
273
+ /** Run `fn` with `ctx` as the active SSR render context, using async-local storage. */
274
+ async function withRenderContextAsync(ctx, fn) {
275
+ ensureRenderContextProvider();
276
+ ensureRenderContextAccessor();
277
+ if (renderContextAccessor) return renderContextAccessor.run(ctx, () => Promise.resolve(fn()));
278
+ throw new Error(FALLBACK_ASYNC_CONTEXT_ERROR);
279
+ }
280
+ /**
281
+ * Get the current render context.
282
+ * Returns null if not inside a render.
283
+ */
284
+ function getRenderContext() {
285
+ ensureRenderContextAccessor();
286
+ if (renderContextAccessor) return renderContextAccessor.getStore() ?? null;
287
+ return fallbackStack;
288
+ }
289
+ let renderContextProvided = false;
290
+ /**
291
+ * Publish this module's render-context accessor to `common/render-context`.
292
+ *
293
+ * Runtime code (resources, portals, deferred routes) asks that module for the
294
+ * active SSR context, and it cannot import SSR. Installing the accessor at
295
+ * module scope meant the answer depended on whether anything had imported this
296
+ * module; entering a render context composes it instead. Consumers only ever
297
+ * observe a context from inside one, so this covers every reader.
298
+ */
299
+ function ensureRenderContextProvider() {
300
+ if (renderContextProvided) return;
301
+ renderContextProvided = true;
302
+ configureRenderContextProvider({ getRenderContext });
303
+ }
304
+ /**
305
+ * Centralized SSR enforcement helper — throws a consistent error when async
306
+ * data is encountered during synchronous SSR.
307
+ */
308
+ function throwSSRDataMissing() {
309
+ throw new SSRDataMissingError();
310
+ }
311
+ //#endregion
312
+ //#region src/ssr/hydration-data.ts
313
+ const DEFERRED_PAYLOAD = "__askr_deferred__";
314
+ /** Client-visible reason for a rejected deferred value that did not opt in to exposure. */
315
+ const REDACTED_DEFERRED_ERROR = "Deferred value rejected.";
316
+ /**
317
+ * Rejection reasons reach the page only when the error opts in with
318
+ * `expose: true`. Anything else can carry server internals (connection
319
+ * strings, hosts, SQL) into public HTML.
320
+ */
321
+ function exposedDeferredError(error) {
322
+ return error instanceof Error && error.expose === true ? error.message : REDACTED_DEFERRED_ERROR;
323
+ }
324
+ function hydrationReplacer(_key, value) {
325
+ if (!isDeferred(value)) return value;
326
+ if (value.state === "fulfilled") return {
327
+ [DEFERRED_PAYLOAD]: "fulfilled",
328
+ value: value.value
329
+ };
330
+ if (value.state === "rejected") return {
331
+ [DEFERRED_PAYLOAD]: "rejected",
332
+ error: exposedDeferredError(value.error)
333
+ };
334
+ return { [DEFERRED_PAYLOAD]: "pending" };
335
+ }
336
+ /**
337
+ * Add the app's opted-in identity projection to a hydration envelope. Without
338
+ * `auth.dehydrate`, nothing about the identity reaches the page. The session is
339
+ * never sent; `authenticated`, `principal`, `tenant`, and `scopes` are sent
340
+ * verbatim.
341
+ */
342
+ function withHydratedAuth(envelope, options, context) {
343
+ if (!options?.dehydrate || !context) return envelope;
344
+ const { authenticated, principal, tenant, scopes } = options.dehydrate(context);
345
+ return withPageFramework(envelope, {
346
+ ...envelope.framework,
347
+ ["au"]: {
348
+ authenticated,
349
+ principal,
350
+ tenant,
351
+ ...scopes ? { scopes } : {}
352
+ }
353
+ });
354
+ }
355
+ function serializeHydrationRenderData(data, runtime) {
356
+ const queryCache = runtime ? dehydrateDataRuntime(runtime) : void 0;
357
+ const current = isPageRenderEnvelope(data) ? data : createPageRenderEnvelope({ resources: data });
358
+ const queries = {
359
+ ...current.queries,
360
+ ...queryCache
361
+ };
362
+ const payload = createPageRenderEnvelope({
363
+ resources: current.resources,
364
+ queries: Object.keys(queries).length > 0 ? queries : void 0,
365
+ route: current.route,
366
+ framework: current.framework
367
+ });
368
+ const routeHydration = getRouteHydrationMetadata(payload.framework);
369
+ if (routeHydration) validateRouteHydrationData(payload.route, routeHydration.r);
370
+ if (isEmptyPageRenderEnvelope(payload)) return "";
371
+ return `<script type="application/json" ${SSR_RENDER_DATA_ATTR}="true">${JSON.stringify(payload, hydrationReplacer).replace(/</g, "\\u003C").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")}<\/script>`;
372
+ }
373
+ //#endregion
374
+ //#region src/ssr/sink.ts
375
+ var StringSink = class StringSink {
376
+ constructor() {
377
+ this.chunks = [];
378
+ this.bufferChunks = [];
379
+ this.bufferLen = 0;
380
+ }
381
+ static {
382
+ this.FLUSH_THRESHOLD = 32768;
383
+ }
384
+ write(html) {
385
+ if (!html) return;
386
+ this.bufferChunks.push(html);
387
+ this.bufferLen += html.length;
388
+ if (this.bufferLen >= StringSink.FLUSH_THRESHOLD) {
389
+ this.chunks.push(this.bufferChunks.join(""));
390
+ this.bufferChunks.length = 0;
391
+ this.bufferLen = 0;
392
+ }
393
+ }
394
+ write2(a, b) {
395
+ if (a) {
396
+ this.bufferChunks.push(a);
397
+ this.bufferLen += a.length;
398
+ }
399
+ if (b) {
400
+ this.bufferChunks.push(b);
401
+ this.bufferLen += b.length;
402
+ }
403
+ if (this.bufferLen >= StringSink.FLUSH_THRESHOLD) {
404
+ this.chunks.push(this.bufferChunks.join(""));
405
+ this.bufferChunks.length = 0;
406
+ this.bufferLen = 0;
407
+ }
408
+ }
409
+ write3(a, b, c) {
410
+ if (a) {
411
+ this.bufferChunks.push(a);
412
+ this.bufferLen += a.length;
413
+ }
414
+ if (b) {
415
+ this.bufferChunks.push(b);
416
+ this.bufferLen += b.length;
417
+ }
418
+ if (c) {
419
+ this.bufferChunks.push(c);
420
+ this.bufferLen += c.length;
421
+ }
422
+ if (this.bufferLen >= StringSink.FLUSH_THRESHOLD) {
423
+ this.chunks.push(this.bufferChunks.join(""));
424
+ this.bufferChunks.length = 0;
425
+ this.bufferLen = 0;
426
+ }
427
+ }
428
+ end() {
429
+ if (this.bufferLen) {
430
+ this.chunks.push(this.bufferChunks.join(""));
431
+ this.bufferChunks.length = 0;
432
+ this.bufferLen = 0;
433
+ }
434
+ }
435
+ toString() {
436
+ if (this.bufferLen) {
437
+ this.chunks.push(this.bufferChunks.join(""));
438
+ this.bufferChunks.length = 0;
439
+ this.bufferLen = 0;
440
+ }
441
+ return this.chunks.join("");
442
+ }
443
+ };
444
+ var StreamSink = class {
445
+ constructor(onChunk, onComplete) {
446
+ this.onChunk = onChunk;
447
+ this.onComplete = onComplete;
448
+ }
449
+ write(html) {
450
+ if (html) this.onChunk(html);
451
+ }
452
+ end() {
453
+ this.onComplete();
454
+ }
455
+ };
456
+ //#endregion
457
+ //#region src/ssr/attrs.ts
458
+ const ESCAPED_ATTR_VALUE_CACHE_LIMIT = 512;
459
+ const escapedAttrValueCache = /* @__PURE__ */ new Map();
460
+ function isEventHandler(key) {
461
+ return key.length >= 2 && key.slice(0, 2).toLowerCase() === "on";
462
+ }
463
+ /**
464
+ * A function or readable prop is reactive on the client; the server renders
465
+ * its current value once, without subscribing to it. A function that returns
466
+ * a readable renders the readable's value, as on the client.
467
+ */
468
+ function resolvePropValue(value) {
469
+ return typeof value === "function" ? untrack(() => readValue(value)) : value;
470
+ }
471
+ /**
472
+ * `props` with every function or readable attribute value read once, for an
473
+ * element whose attributes are inspected before they are written. Returns
474
+ * `props` itself when nothing needs reading.
475
+ */
476
+ function resolveReactiveAttributeProps(props) {
477
+ if (!props || typeof props !== "object") return props;
478
+ let resolved = null;
479
+ const propsObj = props;
480
+ for (const key in propsObj) {
481
+ const value = propsObj[key];
482
+ if (typeof value !== "function" || isSkippedProp(key) || isEventHandler(key)) continue;
483
+ resolved ??= { ...propsObj };
484
+ resolved[key] = resolvePropValue(value);
485
+ }
486
+ return resolved ?? props;
487
+ }
488
+ function assertAttributeName(name) {
489
+ if (!/^[A-Za-z_:][A-Za-z0-9_.:-]*$/.test(name)) throw new TypeError(`Invalid SSR attribute name: ${JSON.stringify(name)}`);
490
+ }
491
+ function getEscapedAttrValue(value) {
492
+ if (value.length > 64) return escapeAttr(value);
493
+ const cached = escapedAttrValueCache.get(value);
494
+ if (cached !== void 0) return cached;
495
+ const escaped = escapeAttr(value);
496
+ if (escaped === value) return value;
497
+ if (escapedAttrValueCache.size >= ESCAPED_ATTR_VALUE_CACHE_LIMIT) escapedAttrValueCache.clear();
498
+ escapedAttrValueCache.set(value, escaped);
499
+ return escaped;
500
+ }
501
+ /**
502
+ * Render attributes directly to a sink without intermediate string allocations.
503
+ * This is the hot path for streaming SSR.
504
+ *
505
+ * Props the DOM renderer writes only as properties (`prop:*`, `indeterminate`,
506
+ * object values on custom elements) have no markup and are left out; the
507
+ * client applies them when it hydrates.
508
+ */
509
+ function renderAttrsDirect(props, sink, tagName = "") {
510
+ if (!props || typeof props !== "object") return;
511
+ const customElement = isCustomElementName(tagName);
512
+ const propsObj = props;
513
+ for (const key in propsObj) {
514
+ if (isSkippedProp(key) || key === "dangerouslySetInnerHTML") continue;
515
+ if (isEventHandler(key)) continue;
516
+ if (key.charCodeAt(0) === 95) continue;
517
+ const value = resolvePropValue(propsObj[key]);
518
+ if (isPropertyOnlyProp(tagName, key, value)) continue;
519
+ if (value !== null && typeof value === "object" && key.startsWith("attr:")) continue;
520
+ const attrName = getPublicAttributeName(key, customElement);
521
+ if (attrName !== key && isEventHandler(attrName)) continue;
522
+ assertAttributeName(attrName);
523
+ if (attrName === "style") {
524
+ const css = typeof value === "string" ? value : styleObjToCss(value);
525
+ if (!css) continue;
526
+ sink.write(" style=\"");
527
+ if (needsEscapeAttr(css)) sink.write(getEscapedAttrValue(css));
528
+ else sink.write(css);
529
+ sink.write("\"");
530
+ continue;
531
+ }
532
+ if (value === true) {
533
+ sink.write(" ");
534
+ sink.write(attrName);
535
+ const booleanValue = booleanAttributeValue(attrName);
536
+ if (booleanValue) {
537
+ sink.write("=\"");
538
+ sink.write(booleanValue);
539
+ sink.write("\"");
540
+ }
541
+ continue;
542
+ }
543
+ if (value === null || value === void 0 || value === false && !keepsFalseValue(attrName)) continue;
544
+ const strValue = String(value);
545
+ if (rejectUnsafeUrlAttribute(attrName, strValue)) continue;
546
+ sink.write(" ");
547
+ sink.write(attrName);
548
+ sink.write("=\"");
549
+ sink.write(getEscapedAttrValue(strValue));
550
+ sink.write("\"");
551
+ }
552
+ }
553
+ /**
554
+ * The value the HTML parser sees for attribute `name` (lower-case) on an
555
+ * element whose attributes `renderAttrsDirect` writes, or `null` when it is
556
+ * not written. Mirrors the emitted attributes: names compare
557
+ * case-insensitively and the first written occurrence wins, as the parser
558
+ * drops later duplicates.
559
+ */
560
+ function getRenderedAttributeValue(props, name) {
561
+ if (!props || typeof props !== "object") return null;
562
+ const propsObj = props;
563
+ for (const key in propsObj) {
564
+ if (isSkippedProp(key) || key === "dangerouslySetInnerHTML") continue;
565
+ if (isEventHandler(key)) continue;
566
+ if (key.charCodeAt(0) === 95) continue;
567
+ const attrName = getPublicAttributeName(key);
568
+ if (attrName.toLowerCase() !== name) continue;
569
+ const value = resolvePropValue(propsObj[key]);
570
+ if (attrName === "style") {
571
+ const css = typeof value === "string" ? value : styleObjToCss(value);
572
+ if (!css) continue;
573
+ return css;
574
+ }
575
+ if (value === true) return booleanAttributeValue(attrName);
576
+ if (value === null || value === void 0 || value === false && !keepsFalseValue(attrName)) continue;
577
+ const strValue = String(value);
578
+ if (isUnsafeUrlAttribute(attrName, strValue)) continue;
579
+ return strValue;
580
+ }
581
+ return null;
582
+ }
583
+ //#endregion
584
+ //#region src/ssr/namespace.ts
585
+ /** HTML elements whose content the parser reads as text, not markup. */
586
+ const TEXT_CONTENT_ELEMENTS = /* @__PURE__ */ new Set([
587
+ "iframe",
588
+ "noembed",
589
+ "noframes",
590
+ "noscript",
591
+ "plaintext",
592
+ "script",
593
+ "style",
594
+ "textarea",
595
+ "title",
596
+ "xmp"
597
+ ]);
598
+ /** The namespace an element with lower-case tag `tag` gets in `context`. */
599
+ function getElementNamespace(context, tag) {
600
+ switch (context) {
601
+ case "text": return "text";
602
+ case "svg": return "svg";
603
+ case "math": return "math";
604
+ case "math-annotation": return tag === "svg" ? "svg" : "math";
605
+ case "math-text": if (tag === "mglyph" || tag === "malignmark") return "math";
606
+ }
607
+ if (tag === "svg") return "svg";
608
+ if (tag === "math") return "math";
609
+ return "html";
610
+ }
611
+ /**
612
+ * The context the children of an element in `namespace`, itself written in
613
+ * `context`, are parsed in.
614
+ */
615
+ function getChildNamespace(context, namespace, tag, props) {
616
+ if (namespace === "text") return "text";
617
+ if (namespace === "html") {
618
+ if (TEXT_CONTENT_ELEMENTS.has(tag)) return "text";
619
+ if (tag === "template") return "html";
620
+ return tag === "select" || context === "select" ? "select" : "html";
621
+ }
622
+ if (namespace === "svg") return tag === "foreignobject" || tag === "desc" || tag === "title" ? "html" : "svg";
623
+ switch (tag) {
624
+ case "mi":
625
+ case "mo":
626
+ case "mn":
627
+ case "ms":
628
+ case "mtext": return "math-text";
629
+ case "annotation-xml": return isHtmlAnnotationEncoding(getRenderedAttributeValue(props, "encoding")) ? "html" : "math-annotation";
630
+ default: return "math";
631
+ }
632
+ }
633
+ /**
634
+ * Whether an element with lower-case tag `tag`, in `namespace` and written in
635
+ * `context`, is parsed as an HTML raw text element whose text may be written
636
+ * verbatim.
637
+ */
638
+ function getRawTextElementInContext(context, namespace, tag) {
639
+ if (namespace !== "html") return null;
640
+ const element = getRawTextElement(tag);
641
+ return element === "style" && context === "select" ? null : element;
642
+ }
643
+ function isHtmlAnnotationEncoding(encoding) {
644
+ if (encoding === null) return false;
645
+ const value = encoding.toLowerCase();
646
+ return value === "text/html" || value === "application/xhtml+xml";
647
+ }
648
+ //#endregion
649
+ //#region src/ssr/render-keys.ts
650
+ /**
651
+ * SSR Data Management
652
+ *
653
+ * Manages render-phase keying for deterministic SSR data lookup.
654
+ * All state is stored in the per-render context for concurrency safety.
655
+ */
656
+ function startRenderPhase(data) {
657
+ startRenderPhase$1(data === null ? null : isPageRenderEnvelope(data) ? data : createPageRenderEnvelope({ resources: data }));
658
+ }
659
+ function stopRenderPhase() {
660
+ stopRenderPhase$1();
661
+ }
662
+ //#endregion
663
+ //#region src/ssr/render-sync.ts
664
+ /**
665
+ * Synchronous server rendering.
666
+ *
667
+ * Components run on the same execution path as in the browser (a component
668
+ * instance per element, positional hooks, scopes through the owner tree) and
669
+ * their output is interpreted with the same child descriptors as the DOM
670
+ * renderer. The server reads function children and props once, never
671
+ * subscribes, and ends every lifetime when the render finishes.
672
+ *
673
+ * The output is plain HTML apart from private hydration markers when the
674
+ * render contains preloaded resource slots. Portal hosts write tokens that
675
+ * are replaced with their final content once the render root completes.
676
+ */
677
+ /**
678
+ * Collects writes so they can be published or dropped. An ErrorBoundary's
679
+ * subtree renders into one first, so markup from a subtree that then throws
680
+ * never reaches the response.
681
+ */
682
+ var BufferedSink = class {
683
+ constructor() {
684
+ this.operations = [];
685
+ }
686
+ write(html) {
687
+ if (html) this.operations.push({
688
+ portalHost: false,
689
+ text: html
690
+ });
691
+ }
692
+ writePortalHost(token) {
693
+ this.operations.push({
694
+ portalHost: true,
695
+ text: token
696
+ });
697
+ }
698
+ /** The buffered markup, without portal host tokens. */
699
+ html() {
700
+ let html = "";
701
+ for (const operation of this.operations) if (!operation.portalHost) html += operation.text;
702
+ return html;
703
+ }
704
+ publishTo(sink) {
705
+ for (const operation of this.operations) if (operation.portalHost && sink.writePortalHost) sink.writePortalHost(operation.text);
706
+ else sink.write(operation.text);
707
+ }
708
+ };
709
+ /** Buffers output once a portal host appears so tokens can be resolved. */
710
+ var PortalSink = class {
711
+ constructor(sink) {
712
+ this.sink = sink;
713
+ this.buffered = null;
714
+ }
715
+ write(html) {
716
+ if (!html) return;
717
+ if (this.buffered) this.buffered.push(html);
718
+ else this.sink.write(html);
719
+ }
720
+ writePortalHost(token) {
721
+ (this.buffered ??= []).push(token);
722
+ }
723
+ flush(ctx) {
724
+ if (this.buffered) this.sink.write(resolvePortals(this.buffered.join(""), ctx));
725
+ }
726
+ };
727
+ let current = null;
728
+ function state() {
729
+ if (!current) throw new Error("[Askr] No server render is active.");
730
+ return current;
731
+ }
732
+ function withOwner(owner, fn) {
733
+ const render = state();
734
+ const previous = render.owner;
735
+ render.owner = owner;
736
+ try {
737
+ return fn();
738
+ } finally {
739
+ render.owner = previous;
740
+ }
741
+ }
742
+ function withNamespace(namespace, fn) {
743
+ const render = state();
744
+ const previous = render.namespace;
745
+ render.namespace = namespace;
746
+ try {
747
+ return fn();
748
+ } finally {
749
+ render.namespace = previous;
750
+ }
751
+ }
752
+ function runComponent(instance) {
753
+ try {
754
+ const output = instance.render();
755
+ if (isPromiseLike(output)) throwSSRDataMissing();
756
+ return output;
757
+ } finally {}
758
+ }
759
+ function componentOutput(value) {
760
+ return typeof value === "function" ? null : value;
761
+ }
762
+ function renderComponent(fn, props, sink) {
763
+ const render = state();
764
+ let owner = render.owner;
765
+ for (;;) {
766
+ const instance = new ComponentInstance(owner, fn, props);
767
+ instance.server = true;
768
+ instance.serverContext = render.ctx;
769
+ const output = runComponent(instance);
770
+ const resources = getCurrentRenderData()?.resources;
771
+ if (instance.serverResourceKeys.length && resources && Object.keys(resources).some((key) => /^r:\d+$/.test(key))) sink.write(`<!--askr-resource:${instance.serverResourceKeys.join(",")}-->`);
772
+ if (fn === Portal) sink.write(createSSRPortalAnchorToken(render.ctx.ssrPortals.nextHostId++));
773
+ const next = instance.hooks.length === 0 && !instance.boundary ? selfComponentChild(output, fn) : null;
774
+ if (next) {
775
+ owner = instance;
776
+ fn = next.fn;
777
+ props = next.props;
778
+ continue;
779
+ }
780
+ if (!instance.boundary) {
781
+ withOwner(instance, () => renderValue(componentOutput(output), sink));
782
+ return;
783
+ }
784
+ const buffer = new BufferedSink();
785
+ const restorePortals = capturePortalWrites(render.ctx);
786
+ try {
787
+ withOwner(instance, () => renderValue(componentOutput(output), buffer));
788
+ } catch (caught) {
789
+ const error = clarifyRenderOverflow(caught);
790
+ restorePortals();
791
+ const cleanupErrors = disposeFailedSubtree(instance);
792
+ try {
793
+ if (!instance.boundary(error)) throw error;
794
+ const fallback = runComponent(instance);
795
+ withOwner(instance, () => renderValue(componentOutput(fallback), sink));
796
+ } finally {
797
+ reportBoundaryCleanupErrors(cleanupErrors);
798
+ }
799
+ return;
800
+ }
801
+ buffer.publishTo(sink);
802
+ return;
803
+ }
804
+ }
805
+ /**
806
+ * End the lifetimes a failed boundary subtree started, newest first as in
807
+ * `Owner.dispose()`, keeping the boundary's own render computation.
808
+ */
809
+ function disposeFailedSubtree(instance) {
810
+ const errors = [];
811
+ const owned = instance.owned ? [...instance.owned] : [];
812
+ for (let index = owned.length - 1; index >= 0; index--) {
813
+ const child = owned[index];
814
+ if (child && child !== instance.computation) errors.push(...child.dispose());
815
+ }
816
+ return errors;
817
+ }
818
+ function reportBoundaryCleanupErrors(errors) {
819
+ if (errors.length === 0) return;
820
+ const failure = errors.length === 1 ? errors[0] : new AggregateError(errors, "SSR ErrorBoundary cleanup failed");
821
+ logger.error("[Askr] SSR ErrorBoundary cleanup failed:", failure);
822
+ }
823
+ function selfComponentChild(output, fn) {
824
+ if (!output || typeof output !== "object" || Array.isArray(output) || output.type !== fn) return null;
825
+ const children = normalizeChildren(output);
826
+ return children.length === 1 && children[0].kind === 2 ? children[0] : null;
827
+ }
828
+ function capturePortalWrites(ctx) {
829
+ const saved = /* @__PURE__ */ new Map();
830
+ for (const [key, slot] of ctx.ssrPortals.slots) saved.set(key, new Map(slot.writers));
831
+ return () => {
832
+ for (const [key, slot] of ctx.ssrPortals.slots) {
833
+ slot.writers = new Map(saved.get(key) ?? []);
834
+ const ordered = [...slot.writers.values()].sort((left, right) => comparePortalWriterOrder(left.owner, right.owner, left.order, right.order));
835
+ const latest = ordered[ordered.length - 1];
836
+ slot.hasValue = latest !== void 0;
837
+ slot.value = latest?.value;
838
+ slot.owner = latest?.owner;
839
+ }
840
+ };
841
+ }
842
+ function isVNodeOf(value, type) {
843
+ return typeof value === "object" && value !== null && value.type === type;
844
+ }
845
+ /** Render any renderable value. */
846
+ function renderValue(value, sink) {
847
+ if (Array.isArray(value)) {
848
+ for (const item of value) renderValue(item, sink);
849
+ return;
850
+ }
851
+ if (isVNodeOf(value, SSR_PORTAL_HOST)) {
852
+ const token = String(value.props?.token ?? "");
853
+ state().portalNamespaces.set(token, state().namespace);
854
+ if (sink.writePortalHost) sink.writePortalHost(token);
855
+ else sink.write(token);
856
+ return;
857
+ }
858
+ if (isVNodeOf(value, DEFERRED_BOUNDARY)) {
859
+ const id = String(value.props?.id ?? "");
860
+ sink.write(`<askr-resolve data-askr-deferred="${id}">`);
861
+ renderValue(value.props?.pending, sink);
862
+ sink.write("</askr-resolve>");
863
+ return;
864
+ }
865
+ for (const child of normalizeChildren(value)) renderChild(child, sink);
866
+ }
867
+ function renderChild(child, sink) {
868
+ switch (child.kind) {
869
+ case 1:
870
+ sink.write(escapeText(child.text));
871
+ return;
872
+ case 0:
873
+ renderElement(child.tag, child.props, sink);
874
+ return;
875
+ case 2:
876
+ renderComponent(child.fn, child.props, sink);
877
+ return;
878
+ case 3: {
879
+ const owner = child.owner;
880
+ if (owner) withOwner(owner, () => renderValue(child.children, sink));
881
+ else renderValue(child.children, sink);
882
+ return;
883
+ }
884
+ case 4:
885
+ renderComponent(() => functionChildOutput(readValue(child.fn)), {}, sink);
886
+ return;
887
+ case 7: return;
888
+ }
889
+ }
890
+ function assertElementName(name) {
891
+ if (!/^[A-Za-z][A-Za-z0-9._:-]*$/.test(name)) throw new TypeError(`Invalid SSR element name: ${JSON.stringify(name)}`);
892
+ }
893
+ function renderElement(tag, props, sink) {
894
+ assertElementName(tag);
895
+ if (VOID_ELEMENTS.has(tag)) {
896
+ sink.write("<" + tag);
897
+ renderAttrsDirect(props, sink, tag);
898
+ sink.write(" />");
899
+ return;
900
+ }
901
+ const render = state();
902
+ const parentNamespace = render.namespace;
903
+ const lower = tag.toLowerCase();
904
+ const namespace = getElementNamespace(parentNamespace, lower);
905
+ let elementProps = lower === "annotation-xml" || namespace === "html" && (lower === "select" || lower === "option" && parentNamespace === "select") ? resolveReactiveAttributeProps(props) ?? props : props;
906
+ const selection = render.selectSelections[render.selectSelections.length - 1];
907
+ let renderedChildren = null;
908
+ if (lower === "option" && parentNamespace === "select" && selection) {
909
+ let value;
910
+ const own = elementProps.value;
911
+ if (own === void 0 || own === null || own === false) {
912
+ const buffer = new BufferedSink();
913
+ const props = elementProps;
914
+ withNamespace(getChildNamespace(parentNamespace, namespace, lower, props), () => writeContent(props, null, buffer));
915
+ renderedChildren = buffer;
916
+ value = optionTextValue(buffer.html());
917
+ } else value = String(own);
918
+ const selected = selection.values.has(value) && (selection.multiple || !selection.matched);
919
+ if (selected) selection.matched = true;
920
+ elementProps = {
921
+ ...elementProps,
922
+ selected
923
+ };
924
+ }
925
+ if (renderedChildren) {
926
+ sink.write("<" + tag);
927
+ renderAttrsDirect(elementProps, sink, tag);
928
+ sink.write(">");
929
+ renderedChildren.publishTo(sink);
930
+ sink.write("</" + tag + ">");
931
+ return;
932
+ }
933
+ let nextSelection = null;
934
+ if (lower === "select" && namespace === "html" && elementProps.value != null) {
935
+ const multiple = Boolean(elementProps.multiple);
936
+ const value = elementProps.value;
937
+ nextSelection = {
938
+ values: new Set(multiple && Array.isArray(value) ? value.map(String) : [String(value)]),
939
+ multiple,
940
+ matched: false
941
+ };
942
+ render.selectSelections.push(nextSelection);
943
+ }
944
+ const rawText = getRawTextElementInContext(parentNamespace, namespace, lower);
945
+ try {
946
+ withNamespace(getChildNamespace(parentNamespace, namespace, lower, elementProps), () => writeElement(tag, elementProps, rawText, sink));
947
+ } finally {
948
+ if (nextSelection) render.selectSelections.pop();
949
+ }
950
+ }
951
+ const NAMED_ENTITIES = {
952
+ amp: "&",
953
+ lt: "<",
954
+ gt: ">",
955
+ quot: "\"",
956
+ apos: "'",
957
+ nbsp: "\xA0"
958
+ };
959
+ /** Decode the entity starting at `start` (`&...;`), or null if unknown. */
960
+ function decodeEntity(html, start) {
961
+ const end = html.indexOf(";", start + 1);
962
+ if (end < 0 || end - start > 12) return null;
963
+ const name = html.slice(start + 1, end);
964
+ if (name.startsWith("#")) {
965
+ const hex = name[1] === "x" || name[1] === "X";
966
+ const code = Number.parseInt(name.slice(hex ? 2 : 1), hex ? 16 : 10);
967
+ if (!Number.isFinite(code) || code < 0 || code > 1114111) return null;
968
+ return {
969
+ text: String.fromCodePoint(code),
970
+ end
971
+ };
972
+ }
973
+ const text = NAMED_ENTITIES[name];
974
+ return text === void 0 ? null : {
975
+ text,
976
+ end
977
+ };
978
+ }
979
+ function isAsciiWhitespace(code) {
980
+ return code === 32 || code === 9 || code === 10 || code === 12 || code === 13;
981
+ }
982
+ /**
983
+ * The value a browser gives a value-less `<option>` rendered as `html`: its
984
+ * text content with ASCII whitespace stripped and collapsed. The markup is
985
+ * this renderer's own output, so tags, comments, and the three entities the
986
+ * text escaper emits are all there is to undo.
987
+ */
988
+ function optionTextValue(html) {
989
+ let text = "";
990
+ let pendingSpace = false;
991
+ let i = 0;
992
+ while (i < html.length) {
993
+ const ch = html[i];
994
+ if (ch === "<") {
995
+ if (html.startsWith("<!--", i)) {
996
+ const end = html.indexOf("-->", i + 4);
997
+ i = end < 0 ? html.length : end + 3;
998
+ continue;
999
+ }
1000
+ const end = html.indexOf(">", i + 1);
1001
+ if (end < 0) break;
1002
+ if (html.slice(i + 1, i + 7).toLowerCase() === "script") {
1003
+ const close = html.toLowerCase().indexOf("<\/script", end);
1004
+ const closeEnd = close < 0 ? -1 : html.indexOf(">", close);
1005
+ i = closeEnd < 0 ? html.length : closeEnd + 1;
1006
+ continue;
1007
+ }
1008
+ i = end + 1;
1009
+ continue;
1010
+ }
1011
+ let decoded = ch;
1012
+ if (ch === "&") {
1013
+ const entity = decodeEntity(html, i);
1014
+ if (entity) {
1015
+ decoded = entity.text;
1016
+ i = entity.end;
1017
+ }
1018
+ }
1019
+ i++;
1020
+ for (const part of decoded) {
1021
+ if (isAsciiWhitespace(part.charCodeAt(0))) {
1022
+ pendingSpace = text.length > 0;
1023
+ continue;
1024
+ }
1025
+ if (pendingSpace) text += " ";
1026
+ pendingSpace = false;
1027
+ text += part;
1028
+ }
1029
+ }
1030
+ return text;
1031
+ }
1032
+ function writeElement(tag, props, rawText, sink) {
1033
+ sink.write("<" + tag);
1034
+ renderAttrsDirect(props, sink, rawText === null ? tag : void 0);
1035
+ sink.write(">");
1036
+ writeContent(props, rawText, sink);
1037
+ sink.write("</" + tag + ">");
1038
+ }
1039
+ /** An element's content: raw HTML, raw text, or rendered children. */
1040
+ function writeContent(props, rawText, sink) {
1041
+ const dangerous = props.dangerouslySetInnerHTML;
1042
+ if (dangerous !== void 0 && dangerous !== null) {
1043
+ if (typeof dangerous === "object" && "__html" in dangerous) {
1044
+ const html = dangerous.__html;
1045
+ if (html !== null && html !== void 0) sink.write(String(html));
1046
+ } else renderValue(props.children, sink);
1047
+ } else if (rawText !== null) sink.write(escapeRawText(collectRawText(props.children, rawText), rawText));
1048
+ else if (!props.imperativeChildren) renderValue(props.children, sink);
1049
+ }
1050
+ /**
1051
+ * The text of a `<script>` or `<style>`: collected unescaped and neutralized
1052
+ * as a whole. Element children are rejected rather than serialized as markup
1053
+ * the parser would read back as literal text.
1054
+ */
1055
+ function collectRawText(value, element) {
1056
+ return flattenText(value, element).join("");
1057
+ }
1058
+ function flattenText(value, element) {
1059
+ const out = [];
1060
+ const visit = (item) => {
1061
+ if (Array.isArray(item)) {
1062
+ for (const entry of item) visit(entry);
1063
+ return;
1064
+ }
1065
+ for (const child of normalizeChildren(item)) switch (child.kind) {
1066
+ case 1:
1067
+ out.push(child.text);
1068
+ break;
1069
+ case 3:
1070
+ visit(child.children);
1071
+ break;
1072
+ case 4:
1073
+ visit(functionChildOutput(untrack(() => readValue(child.fn))));
1074
+ break;
1075
+ case 2: {
1076
+ const render = state();
1077
+ const instance = new ComponentInstance(render.owner, child.fn, child.props);
1078
+ instance.server = true;
1079
+ instance.serverContext = render.ctx;
1080
+ const output = runComponent(instance);
1081
+ if (!instance.boundary) {
1082
+ withOwner(instance, () => visit(componentOutput(output)));
1083
+ break;
1084
+ }
1085
+ const start = out.length;
1086
+ const restorePortals = capturePortalWrites(render.ctx);
1087
+ try {
1088
+ withOwner(instance, () => visit(componentOutput(output)));
1089
+ } catch (caught) {
1090
+ const error = clarifyRenderOverflow(caught);
1091
+ out.length = start;
1092
+ restorePortals();
1093
+ const cleanupErrors = disposeFailedSubtree(instance);
1094
+ try {
1095
+ if (!instance.boundary(error)) throw error;
1096
+ const fallback = runComponent(instance);
1097
+ withOwner(instance, () => visit(componentOutput(fallback)));
1098
+ } finally {
1099
+ reportBoundaryCleanupErrors(cleanupErrors);
1100
+ }
1101
+ }
1102
+ break;
1103
+ }
1104
+ case 0: throw new Error(`SSR: <${element}> children must be text, but received an element <${child.tag}>.`);
1105
+ default: throw new Error(`SSR: <${element}> children must be text, but received a non-text node.`);
1106
+ }
1107
+ };
1108
+ visit(value);
1109
+ return out;
1110
+ }
1111
+ function renderToString(value, namespace) {
1112
+ const sink = new StringSink();
1113
+ withNamespace(namespace, () => renderValue(value, sink));
1114
+ sink.end();
1115
+ return sink.toString();
1116
+ }
1117
+ /** Replace portal host tokens with their portal's final content. */
1118
+ function resolvePortals(html, ctx) {
1119
+ let resolved = html;
1120
+ const rendered = /* @__PURE__ */ new Set();
1121
+ for (;;) {
1122
+ let found = false;
1123
+ for (const slot of ctx.ssrPortals.slots.values()) {
1124
+ const explicit = slot.hosts.filter((host) => !host.automatic);
1125
+ for (const host of slot.hosts) {
1126
+ if (rendered.has(host.token)) continue;
1127
+ found = true;
1128
+ rendered.add(host.token);
1129
+ const active = host.automatic ? explicit.length === 0 : true;
1130
+ const content = active ? [...slot.writers.values()].sort((left, right) => comparePortalWriterOrder(left.owner, right.owner, left.order, right.order)).map((write) => withOwner(write.owner ?? state().owner, () => renderToString(write.value, state().portalNamespaces.get(host.token) ?? "html"))).join("") : "";
1131
+ const hostContent = host.automatic && (!active || !slot.hasValue) ? "" : host.automatic && content === "" ? host.token : host.defaultPortal && active && slot.hasValue ? `<!--askr-range-start-->${content}<!--askr-range-end-->` : content;
1132
+ resolved = resolved.replace(host.token, () => hostContent);
1133
+ }
1134
+ }
1135
+ if (!found) return resolved;
1136
+ }
1137
+ }
1138
+ function withServerRender(ctx, fn) {
1139
+ const previous = current;
1140
+ const owner = new Owner(null);
1141
+ current = {
1142
+ ctx,
1143
+ owner,
1144
+ namespace: "html",
1145
+ portalNamespaces: /* @__PURE__ */ new Map(),
1146
+ selectSelections: []
1147
+ };
1148
+ let result;
1149
+ try {
1150
+ result = fn();
1151
+ } catch (error) {
1152
+ current = previous;
1153
+ const cleanupErrors = owner.dispose();
1154
+ const failure = clarifyRenderOverflow(error);
1155
+ if (cleanupErrors.length > 0) throw new AggregateError([failure, ...cleanupErrors], "SSR render failed and temporary owner cleanup also failed");
1156
+ throw failure;
1157
+ }
1158
+ current = previous;
1159
+ const errors = owner.dispose();
1160
+ if (errors.length === 1) throw errors[0];
1161
+ if (errors.length > 1) throw new AggregateError(errors, "SSR temporary owner cleanup failed");
1162
+ return result;
1163
+ }
1164
+ const AUTO_PORTAL = {
1165
+ $$typeof: ELEMENT_TYPE,
1166
+ type: DefaultPortal,
1167
+ props: { __askrAutoDefaultPortal: true },
1168
+ key: "__default_portal"
1169
+ };
1170
+ /** A root's output followed by the automatic default portal host. */
1171
+ function withDefaultPortal(output) {
1172
+ return {
1173
+ $$typeof: ELEMENT_TYPE,
1174
+ type: Fragment,
1175
+ props: { children: output == null ? [AUTO_PORTAL] : [output, AUTO_PORTAL] },
1176
+ key: null
1177
+ };
1178
+ }
1179
+ function rootElement(component, props, nonce) {
1180
+ const Root = (_props, context) => {
1181
+ const output = component(props, context);
1182
+ if (isPromiseLike(output)) throwSSRDataMissing();
1183
+ return withDefaultPortal(output);
1184
+ };
1185
+ Object.defineProperty(Root, "name", { value: component.name || "Component" });
1186
+ const element = {
1187
+ $$typeof: ELEMENT_TYPE,
1188
+ type: Root,
1189
+ props: {},
1190
+ key: null
1191
+ };
1192
+ return nonce === void 0 ? element : CspNonceScope({
1193
+ value: nonce,
1194
+ children: element
1195
+ });
1196
+ }
1197
+ /** Synchronously render a component to an HTML string, without route resolution. */
1198
+ function renderToStringSync(component, props, options) {
1199
+ const nonce = validateCspNonce(options?.cspNonce);
1200
+ const ctx = createRenderContext(options?.seed ?? 12345, {
1201
+ data: options?.data,
1202
+ envelope: options?.envelope,
1203
+ cspNonce: nonce,
1204
+ authContext: options?.authContext,
1205
+ ...options?.route
1206
+ });
1207
+ return withRenderContext(ctx, () => {
1208
+ startRenderPhase(ctx.renderData);
1209
+ try {
1210
+ return withServerRender(ctx, () => {
1211
+ const sink = new StringSink();
1212
+ renderValue(rootElement(component, props ?? {}, nonce), sink);
1213
+ sink.end();
1214
+ const html = resolvePortals(sink.toString(), ctx);
1215
+ options?.onContext?.(ctx);
1216
+ return html + serializeHydrationRenderData(ctx.hydrationData ?? void 0, ctx.dataRuntime);
1217
+ });
1218
+ } finally {
1219
+ stopRenderPhase();
1220
+ }
1221
+ });
1222
+ }
1223
+ function renderSSRRouteAppToSink(input) {
1224
+ const { ctx, data, route, params, sink } = input;
1225
+ withRenderContext(ctx, () => {
1226
+ startRenderPhase(ctx.renderData);
1227
+ try {
1228
+ withServerRender(ctx, () => {
1229
+ const appSink = new PortalSink(sink);
1230
+ renderValue(rootElement(((routeParams) => route.handler(routeParams)), params, ctx.cspNonce), appSink);
1231
+ appSink.flush(ctx);
1232
+ });
1233
+ if (ctx.deferredBoundaries.length === 0) sink.write(serializeHydrationRenderData(ctx.hydrationData ?? data, ctx.dataRuntime));
1234
+ } finally {
1235
+ stopRenderPhase();
1236
+ }
1237
+ });
1238
+ }
1239
+ //#endregion
1240
+ export { serializeHydrationRenderData as a, getRenderContext as c, escapeHtml as d, StringSink as i, withRenderContext as l, renderToStringSync as n, withHydratedAuth as o, StreamSink as r, createRenderContext as s, renderSSRRouteAppToSink as t, withRenderContextAsync as u };