@askrjs/askr 0.2.3 → 0.3.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 (117) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/access-CEA2pOry.js +1046 -0
  3. package/dist/actions/index.d.ts +16 -2
  4. package/dist/actions/index.js +5 -5
  5. package/dist/{activity-ZxJXI9hF.js → activity-oy2YFTFF.js} +22 -16
  6. package/dist/benchmark.js +8 -9
  7. package/dist/boot/index.d.ts +21 -9
  8. package/dist/boot/index.js +1 -1
  9. package/dist/{boot-D4GaLA0d.js → boot-BMBMWUGI.js} +680 -440
  10. package/dist/capabilities-Bbf0mlp9.js +42 -0
  11. package/dist/components/index.d.ts +11 -8
  12. package/dist/components/index.js +1 -1
  13. package/dist/{compose-ref-Bfaf4kUC.js → compose-ref-v0qGlHoN.js} +7 -1
  14. package/dist/control/index.d.ts +20 -2
  15. package/dist/control/index.js +1 -1
  16. package/dist/{control-57x3wa4J.js → control-BR_mrX__.js} +4 -4
  17. package/dist/core.d.ts +163 -0
  18. package/dist/csp-nonce-BfFWcd0w.js +173 -0
  19. package/dist/data/index.d.ts +74 -2
  20. package/dist/data/index.js +3 -3
  21. package/dist/{data-B7XCDeC8.js → data-2edW0jhF.js} +133 -138
  22. package/dist/{data-runtime-7t_Y0iv3.js → data-runtime-CxoY98lX.js} +22 -15
  23. package/dist/{deferred-BELyvMsC.js → deferred-CbgNhf67.js} +5 -5
  24. package/dist/dom-renderer.d.ts +77 -0
  25. package/dist/domains/actions.d.ts +70 -0
  26. package/dist/domains/component.d.ts +119 -0
  27. package/dist/domains/context.d.ts +73 -0
  28. package/dist/domains/control.d.ts +328 -0
  29. package/dist/domains/data.d.ts +461 -0
  30. package/dist/domains/diagnostics.d.ts +21 -0
  31. package/dist/domains/lifecycle.d.ts +112 -0
  32. package/dist/domains/refs.d.ts +18 -0
  33. package/dist/domains/renderer.d.ts +127 -0
  34. package/dist/domains/routing.d.ts +501 -0
  35. package/dist/domains/scheduler.d.ts +79 -0
  36. package/dist/domains/server.d.ts +112 -0
  37. package/dist/domains/state.d.ts +129 -0
  38. package/dist/domains/telemetry.d.ts +29 -0
  39. package/dist/eager-control.d.ts +8 -0
  40. package/dist/{effect-4LwBwV58.js → effect-C3Zsc1k6.js} +14 -41
  41. package/dist/{types-DkVJhVs9.d.ts → elements.d.ts} +84 -42
  42. package/dist/{for-internal-DeoSg_AV.js → for-state-BDykeOJL.js} +623 -511
  43. package/dist/foundations/icon/index.d.ts +67 -16
  44. package/dist/foundations/icon/index.js +1 -1
  45. package/dist/foundations/index.d.ts +26 -3
  46. package/dist/foundations/index.js +1 -1
  47. package/dist/foundations/interactions/index.d.ts +73 -34
  48. package/dist/foundations/interactions/index.js +1 -1
  49. package/dist/foundations/state/index.d.ts +12 -5
  50. package/dist/foundations/state/index.js +1 -1
  51. package/dist/foundations/structures/index.d.ts +44 -3
  52. package/dist/foundations/structures/index.js +1 -1
  53. package/dist/foundations/utilities/index.d.ts +34 -3
  54. package/dist/foundations/utilities/index.js +1 -1
  55. package/dist/fx/index.d.ts +72 -25
  56. package/dist/fx/index.js +8 -8
  57. package/dist/index.d.ts +121 -4
  58. package/dist/index.js +316 -47
  59. package/dist/{component-internal-Dl02WQKS.js → instance-VAFYVJOa.js} +495 -283
  60. package/dist/{interactions-D102JxBR.js → interactions-CTeACdT_.js} +1 -1
  61. package/dist/jsx-dev-runtime.d.ts +51 -11
  62. package/dist/jsx-globals.d.ts +2 -0
  63. package/dist/jsx-runtime-CPJXAOBF.js +43 -0
  64. package/dist/jsx-runtime.d.ts +17 -3
  65. package/dist/jsx-runtime.js +2 -42
  66. package/dist/jsx.d.ts +108 -0
  67. package/dist/{manifest-D6rfj_jC.js → manifest-D1P3UNWV.js} +4 -9
  68. package/dist/{navigate-C46GtScG.js → navigate-prC5V8XV.js} +204 -476
  69. package/dist/{navigate-wel1e6cU.d.ts → navigation.d.ts} +10 -8
  70. package/dist/{readable-CEcteIDE.js → notify-DxxuDPeY.js} +96 -34
  71. package/dist/{query-registry-Bua3cDyb.js → query-registry-LrYpQsDJ.js} +1 -1
  72. package/dist/{compose-ref-DOJHoW5X.d.ts → refs.d.ts} +11 -7
  73. package/dist/{ssr-BaC5qHEw.js → render-resolved-BC0W7_5b.js} +165 -558
  74. package/dist/{renderer-BhXofszH.js → renderer-CT0HeY58.js} +6866 -5715
  75. package/dist/{resolution-t8J0yNaU.js → resolution-3DskUkjG.js} +189 -180
  76. package/dist/{resource-operation-B8q-QRUx.js → resource-18-sFRl9.js} +98 -58
  77. package/dist/resources/index.d.ts +64 -46
  78. package/dist/resources/index.js +215 -9
  79. package/dist/route-activity.d.ts +21 -0
  80. package/dist/{route-matching-Bo6UqG-5.js → route-matching-CUzZ31gT.js} +68 -82
  81. package/dist/router/index.d.ts +378 -79
  82. package/dist/router/index.js +9 -9
  83. package/dist/router-internal-7nuNEHfG.js +36 -0
  84. package/dist/scope-Cq_iYbTR.js +403 -0
  85. package/dist/{selector-C7rIpOnN.js → selector-BSPVkjKP.js} +41 -41
  86. package/dist/{shared-CGrx2AOL.js → shared-kU8yvryp.js} +3 -6
  87. package/dist/{snapshot-source-BB42xgwb.js → snapshot-source-An4iKajG.js} +1 -1
  88. package/dist/ssg/index.d.ts +51 -15
  89. package/dist/ssg/index.js +269 -209
  90. package/dist/ssr/index.d.ts +121 -68
  91. package/dist/ssr/index.js +2 -1
  92. package/dist/ssr-CiNm6Vzl.js +393 -0
  93. package/dist/{ssr-DSHd_Q9K.js → ssr-EPjwJH5R.js} +5 -1
  94. package/dist/{state-BzhOW2TX.js → state-BXJfudq1.js} +10 -15
  95. package/dist/{structures-BwfeO4Iz.js → structures-CjEzfj4h.js} +37 -57
  96. package/dist/{index-r5THqzPN.d.ts → structures.d.ts} +57 -36
  97. package/dist/testing/index.d.ts +125 -24
  98. package/dist/testing/index.js +26 -62
  99. package/dist/timer-C7uqnJVt.js +85 -0
  100. package/dist/{index-B1gu0_m0.d.ts → utilities.d.ts} +24 -13
  101. package/dist/{verify-hydration-_Q6avFp0.js → verify-hydration-ikaxotf7.js} +8 -5
  102. package/package.json +13 -15
  103. package/dist/access-Rr7CMa06.js +0 -507
  104. package/dist/activity-CAJ5eho-.d.ts +0 -14
  105. package/dist/benchmark.d.ts +0 -26
  106. package/dist/cleanup-DsrbV-rr.js +0 -535
  107. package/dist/component-cleanup-DjpwO9WX.js +0 -143
  108. package/dist/component-scope-4I3yEMkb.js +0 -195
  109. package/dist/control-DdFw-Caz.d.ts +0 -8
  110. package/dist/csp-nonce-C9OuML0U.js +0 -72
  111. package/dist/css-BuPaTOfe.js +0 -70
  112. package/dist/fastlane-Buz1Rvlr.js +0 -166
  113. package/dist/index-DSqXWc77.d.ts +0 -1402
  114. package/dist/jsx-runtime-BTzDdBJ_.d.ts +0 -2
  115. package/dist/jsx-runtime-Cdd6Gkb0.d.ts +0 -38
  116. package/dist/lifecycle-batch-Be-CLDjV.js +0 -253
  117. package/dist/lifecycle-operations-C5m03NQc.js +0 -195
@@ -1,7 +1,27 @@
1
- import { Bt as DataRuntime, D as SSRPortalState, E as DeferredBoundaryRegistration, Ft as RouteRequestResult, Ot as RouteRecord, _t as RouteHandler, c as ServerQueryRegistry, dn as DocumentRenderContext, dt as RouteAuthOptions, en as QueryPrefetchContext, fn as DocumentRenderer, hn as SSRStyleRegistrationValidation, jt as RouteRegistry, mn as SSRStyleRegistration, pn as SSRData, rt as AccessRedirectDecision, tt as AccessDenyDecision, un as DocumentRenderArgs, ut as Route, zt as CoreTelemetry } from "../index-DSqXWc77.js";
2
- import { r as JSXElement, s as Props } from "../types-DkVJhVs9.js";
3
- import { AuthContext } from "@askrjs/auth";
4
- //#region src/common/page-render-envelope.d.ts
1
+ import {
2
+ SSRStyleRegistrationValidation,
3
+ SSRPortalState,
4
+ DocumentRenderer,
5
+ DeferredBoundaryRegistration,
6
+ DocumentRenderContext,
7
+ RouteAuthOptions,
8
+ RouteRegistry,
9
+ RouteHandler,
10
+ SSRData,
11
+ DocumentRenderArgs,
12
+ Route,
13
+ RouteRecord,
14
+ RouteRequestResult,
15
+ ServerQueryRegistry,
16
+ CoreTelemetry,
17
+ AccessDenyDecision,
18
+ QueryPrefetchContext,
19
+ SSRStyleRegistration,
20
+ DataRuntime,
21
+ AccessRedirectDecision,
22
+ } from '../core.js';
23
+ import { JSXElement, Props } from '../elements.js';
24
+ import { AuthContext } from '@askrjs/auth';
5
25
  declare const PAGE_RENDER_ENVELOPE_VERSION: 1;
6
26
  interface PageRenderEnvelope {
7
27
  readonly version: typeof PAGE_RENDER_ENVELOPE_VERSION;
@@ -9,17 +29,13 @@ interface PageRenderEnvelope {
9
29
  readonly route: unknown;
10
30
  readonly framework: Readonly<Record<string, unknown>>;
11
31
  }
12
- //#endregion
13
- //#region src/common/ssr-errors.d.ts
14
32
  /**
15
33
  * Common call contracts: SSR error types
16
34
  */
17
35
  declare class SSRDataMissingError extends Error {
18
- readonly code = "SSR_DATA_MISSING";
36
+ readonly code = 'SSR_DATA_MISSING';
19
37
  constructor(message?: string);
20
38
  }
21
- //#endregion
22
- //#region src/ssr/context.d.ts
23
39
  interface RenderContext {
24
40
  url: string;
25
41
  seed: number;
@@ -45,36 +61,40 @@ interface RenderContext {
45
61
  cspNonce?: string;
46
62
  }
47
63
  /** Build a fresh SSR render context (data cache, routes, seed) for a render pass. */
48
- declare function createRenderContext(seed?: number, opts?: {
49
- url?: string;
50
- data?: SSRData;
51
- params?: Record<string, string>;
52
- routes?: readonly Route[];
53
- routeAuth?: RouteAuthOptions;
54
- authContext?: AuthContext;
55
- basePath?: string;
56
- signal?: AbortSignal;
57
- dataRuntime?: unknown;
58
- mode?: 'ssr' | 'spa';
59
- queryPrefetch?: QueryPrefetchContext;
60
- framework?: Readonly<Record<string, unknown>>;
61
- envelope?: PageRenderEnvelope;
62
- cspNonce?: string;
63
- }): RenderContext;
64
+ declare function createRenderContext(
65
+ seed?: number,
66
+ opts?: {
67
+ url?: string;
68
+ data?: SSRData;
69
+ params?: Record<string, string>;
70
+ routes?: readonly Route[];
71
+ routeAuth?: RouteAuthOptions;
72
+ authContext?: AuthContext;
73
+ basePath?: string;
74
+ signal?: AbortSignal;
75
+ dataRuntime?: unknown;
76
+ mode?: 'ssr' | 'spa';
77
+ queryPrefetch?: QueryPrefetchContext;
78
+ framework?: Readonly<Record<string, unknown>>;
79
+ envelope?: PageRenderEnvelope;
80
+ cspNonce?: string;
81
+ }
82
+ ): RenderContext;
64
83
  /**
65
84
  * Run a function with the given render context.
66
85
  * Concurrency-safe in Node.js via AsyncLocalStorage.
67
86
  */
68
87
  declare function withRenderContext<T>(ctx: RenderContext, fn: () => T): T;
69
88
  /** Run `fn` with `ctx` as the active SSR render context, using async-local storage. */
70
- declare function withRenderContextAsync<T>(ctx: RenderContext, fn: () => T | PromiseLike<T>): Promise<T>;
89
+ declare function withRenderContextAsync<T>(
90
+ ctx: RenderContext,
91
+ fn: () => T | PromiseLike<T>
92
+ ): Promise<T>;
71
93
  /**
72
94
  * Get the current render context.
73
95
  * Returns null if not inside a render.
74
96
  */
75
97
  declare function getRenderContext(): RenderContext | null;
76
- //#endregion
77
- //#region src/ssr/route-render.d.ts
78
98
  /** A single path-to-handler route binding accepted by low-level SSR route rendering. */
79
99
  type SSRRoute = {
80
100
  path: string;
@@ -115,8 +135,6 @@ declare function resolveRequest(opts: {
115
135
  request?: Request;
116
136
  signal?: AbortSignal;
117
137
  }): Promise<RouteRequestResult>;
118
- //#endregion
119
- //#region src/ssr/types.d.ts
120
138
  /** VNode representation for SSR rendering */
121
139
  type VNode = {
122
140
  type: string | SSRComponent | symbol;
@@ -128,26 +146,31 @@ type VNode = {
128
146
  * Component function signature for SSR.
129
147
  * Components receive props and an optional context with signal and SSR context.
130
148
  */
131
- type SSRComponent = (props: Props, context?: {
132
- signal?: AbortSignal;
133
- ssr?: RenderContext;
134
- }) => VNode | JSXElement | string | number | boolean | null | undefined;
135
- //#endregion
136
- //#region src/ssr/render-sync.d.ts
149
+ type SSRComponent = (
150
+ props: Props,
151
+ context?: {
152
+ signal?: AbortSignal;
153
+ ssr?: RenderContext;
154
+ }
155
+ ) => VNode | JSXElement | string | number | boolean | null | undefined;
137
156
  /** Synchronously render a component to an HTML string, without route resolution. */
138
- declare function renderToStringSync(component: (props?: Record<string, unknown>) => VNode | JSXElement | string | number | boolean | null | undefined, props?: Record<string, unknown>, options?: {
139
- seed?: number;
140
- data?: SSRData;
141
- /** @internal A composed page render envelope. */
142
- envelope?: PageRenderEnvelope;
143
- cspNonce?: string;
144
- /** @internal Request-local authentication for deferred SSR passes. */
145
- authContext?: import('@askrjs/auth').AuthContext;
146
- /** @internal Capture request-local registrations produced by this pass. */
147
- onContext?: (ctx: RenderContext) => void;
148
- }): string;
149
- //#endregion
150
- //#region src/ssr/render-resolved.d.ts
157
+ declare function renderToStringSync(
158
+ component: (
159
+ props?: Record<string, unknown>
160
+ ) => VNode | JSXElement | string | number | boolean | null | undefined,
161
+ props?: Record<string, unknown>,
162
+ options?: {
163
+ seed?: number;
164
+ data?: SSRData;
165
+ /** @internal A composed page render envelope. */
166
+ envelope?: PageRenderEnvelope;
167
+ cspNonce?: string;
168
+ /** @internal Request-local authentication for deferred SSR passes. */
169
+ authContext?: import('@askrjs/auth').AuthContext;
170
+ /** @internal Capture request-local registrations produced by this pass. */
171
+ onContext?: (ctx: RenderContext) => void;
172
+ }
173
+ ): string;
151
174
  /** Synchronously render an already-resolved route handler to an HTML string. */
152
175
  declare function renderResolvedToStringSync(opts: {
153
176
  url: string;
@@ -162,8 +185,6 @@ declare function renderResolvedToStringSync(opts: {
162
185
  cspNonce?: string;
163
186
  };
164
187
  }): string;
165
- //#endregion
166
- //#region src/ssr/route-request-render.d.ts
167
188
  /** Options for {@link renderRouteRequest} and {@link renderRouteRequestToString}. */
168
189
  interface RenderRouteRequestOptions {
169
190
  url: string;
@@ -183,28 +204,60 @@ interface RenderRouteRequestOptions {
183
204
  cspNonce?: string;
184
205
  }
185
206
  /** Outcome of rendering a route request for SSR: a render, redirect, deny, or no-match. */
186
- type RenderRouteRequestResult = {
187
- kind: 'render';
188
- html: string;
189
- stream?: ReadableStream<Uint8Array>;
190
- styles: readonly SSRStyleRegistration[];
191
- params: Record<string, string>;
192
- record?: RouteRecord;
193
- } | AccessRedirectDecision | AccessDenyDecision | {
194
- kind: 'no-match';
195
- };
207
+ type RenderRouteRequestResult =
208
+ | {
209
+ kind: 'render';
210
+ html: string;
211
+ stream?: ReadableStream<Uint8Array>;
212
+ styles: readonly SSRStyleRegistration[];
213
+ params: Record<string, string>;
214
+ record?: RouteRecord;
215
+ }
216
+ | AccessRedirectDecision
217
+ | AccessDenyDecision
218
+ | {
219
+ kind: 'no-match';
220
+ };
196
221
  /** Resolve and render a route request for SSR, streaming the body when possible. */
197
- declare function renderRouteRequest(options: RenderRouteRequestOptions): Promise<RenderRouteRequestResult>;
222
+ declare function renderRouteRequest(
223
+ options: RenderRouteRequestOptions
224
+ ): Promise<RenderRouteRequestResult>;
198
225
  /** Resolve and render a route request for SSR, always fully buffering the HTML. */
199
- declare function renderRouteRequestToString(options: RenderRouteRequestOptions): Promise<RenderRouteRequestResult>;
200
- //#endregion
201
- //#region src/ssr/index-internal.d.ts
226
+ declare function renderRouteRequestToString(
227
+ options: RenderRouteRequestOptions
228
+ ): Promise<RenderRouteRequestResult>;
202
229
  /**
203
230
  * Render a component or route request to a complete HTML string, synchronously.
204
231
  */
205
- declare function renderToString(component: (props?: Record<string, unknown>) => VNode | JSXElement | string | number | null): string;
232
+ declare function renderToString(
233
+ component: (
234
+ props?: Record<string, unknown>
235
+ ) => VNode | JSXElement | string | number | null
236
+ ): string;
206
237
  declare function renderToString(opts: RouteRenderOptions): string;
207
238
  /** Stream a route request's rendered HTML to the response sink described by `opts`. */
208
239
  declare function renderToStream(opts: RouteStreamOptions): void;
209
- //#endregion
210
- export { type DocumentRenderArgs, type DocumentRenderContext, type DocumentRenderer, type RenderRouteRequestOptions, type RenderRouteRequestResult, type SSRComponent, SSRDataMissingError, type SSRRoute, type SSRStyleRegistration, type SSRStyleRegistrationValidation, type VNode, createRenderContext, getRenderContext, renderResolvedToStringSync, renderRouteRequest, renderRouteRequestToString, renderToStream, renderToString, renderToStringSync, resolveRequest, withRenderContext, withRenderContextAsync };
240
+ export {
241
+ type DocumentRenderArgs,
242
+ type DocumentRenderContext,
243
+ type DocumentRenderer,
244
+ type RenderRouteRequestOptions,
245
+ type RenderRouteRequestResult,
246
+ type SSRComponent,
247
+ SSRDataMissingError,
248
+ type SSRRoute,
249
+ type SSRStyleRegistration,
250
+ type SSRStyleRegistrationValidation,
251
+ type VNode,
252
+ createRenderContext,
253
+ getRenderContext,
254
+ renderResolvedToStringSync,
255
+ renderRouteRequest,
256
+ renderRouteRequestToString,
257
+ renderToStream,
258
+ renderToString,
259
+ renderToStringSync,
260
+ resolveRequest,
261
+ withRenderContext,
262
+ withRenderContextAsync,
263
+ };
package/dist/ssr/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import { C as SSRDataMissingError } from "../render-context-B7ohlh6t.js";
2
- import { a as renderResolvedToStringSync, c as createRenderContext, d as withRenderContextAsync, i as renderRouteRequestToString, l as getRenderContext, n as renderToString, o as renderToStringSync, r as renderRouteRequest, s as resolveRequest, t as renderToStream, u as withRenderContext } from "../ssr-BaC5qHEw.js";
2
+ import { c as createRenderContext, d as withRenderContext, f as withRenderContextAsync, i as renderToStringSync, l as getRenderContext, n as renderResolvedToStringSync } from "../render-resolved-BC0W7_5b.js";
3
+ import { a as resolveRequest, i as renderRouteRequestToString, n as renderToString, r as renderRouteRequest, t as renderToStream } from "../ssr-CiNm6Vzl.js";
3
4
  export { SSRDataMissingError, createRenderContext, getRenderContext, renderResolvedToStringSync, renderRouteRequest, renderRouteRequestToString, renderToStream, renderToString, renderToStringSync, resolveRequest, withRenderContext, withRenderContextAsync };
@@ -0,0 +1,393 @@
1
+ import { P as isPromiseLike } from "./instance-VAFYVJOa.js";
2
+ import { r as validateCspNonce } from "./csp-nonce-BfFWcd0w.js";
3
+ import { t as createDataRuntime } from "./data-runtime-CxoY98lX.js";
4
+ import { c as withTelemetry, t as createQueryPrefetchContext } from "./query-registry-LrYpQsDJ.js";
5
+ import { a as resolveRouteRequest, n as getRouteRenderContext, o as resolvedRouteHasLoader } from "./resolution-3DskUkjG.js";
6
+ import { c as removeRouteBasePath, s as normalizeRouteBasePath, t as _resolveRouteMatchFromRoutes } from "./route-matching-CUzZ31gT.js";
7
+ import { n as renderDocument } from "./ssr-EPjwJH5R.js";
8
+ import { a as serializeHydrationRenderData, c as createRenderContext, f as withRenderContextAsync, i as renderToStringSync, o as StreamSink, r as renderSSRRouteAppToSink, s as StringSink, u as throwSSRDataMissing } from "./render-resolved-BC0W7_5b.js";
9
+ //#region src/ssr/route-policy-resolution.ts
10
+ const MAX_SSR_REDIRECTS = 20;
11
+ function getRouteRequestResultSync(result) {
12
+ if (isPromiseLike(result)) throwSSRDataMissing();
13
+ return result;
14
+ }
15
+ function buildDeniedRoute(route, status) {
16
+ return {
17
+ ...route,
18
+ handler: () => ({
19
+ type: "div",
20
+ props: { "data-route-denied": String(status) },
21
+ children: [String(status)]
22
+ })
23
+ };
24
+ }
25
+ function resolvePolicyAwareSSRRoute(opts, routeTable) {
26
+ const manifest = opts.registry.manifest;
27
+ let href = opts.url;
28
+ const visited = /* @__PURE__ */ new Set();
29
+ for (let redirects = 0; redirects <= MAX_SSR_REDIRECTS; redirects += 1) {
30
+ const logicalHref = removeRouteBasePath(href, normalizeRouteBasePath(manifest.basePath));
31
+ if (logicalHref === void 0) throw new Error(`SSR: no route found for url: ${href}`);
32
+ const logicalUrl = new URL(logicalHref, "http://localhost");
33
+ const matched = _resolveRouteMatchFromRoutes(logicalUrl.pathname, routeTable);
34
+ if (!matched) throw new Error(`SSR: no route found for url: ${href}`);
35
+ const resolved = getRouteRequestResultSync(resolveRouteRequest(href, {
36
+ registry: opts.registry,
37
+ mode: "ssr",
38
+ auth: opts.auth,
39
+ authContext: opts.authContext,
40
+ request: opts.request,
41
+ signal: opts.signal
42
+ }));
43
+ if (resolved === null) throw new Error(`SSR: no route found for url: ${href}`);
44
+ if (resolved.kind === "redirect") {
45
+ const redirectTarget = new URL(resolved.to, "http://localhost");
46
+ const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;
47
+ if (redirectHref === href || visited.has(redirectHref)) throw new Error(`[Askr] SSR redirect cycle detected at ${redirectHref}.`);
48
+ if (redirects >= MAX_SSR_REDIRECTS) throw new Error(`[Askr] SSR redirect limit exceeded (${MAX_SSR_REDIRECTS}).`);
49
+ visited.add(redirectHref);
50
+ href = redirectHref;
51
+ continue;
52
+ }
53
+ if (resolved.kind === "deny") return {
54
+ url: href,
55
+ route: buildDeniedRoute(matched.route, resolved.status),
56
+ params: matched.params
57
+ };
58
+ return {
59
+ url: href,
60
+ route: {
61
+ ...matched.route,
62
+ handler: resolvedRouteHasLoader(resolved) ? resolved.handler : matched.route.handler
63
+ },
64
+ params: matched.params,
65
+ authContext: getRouteRenderContext(resolved)?.auth
66
+ };
67
+ }
68
+ throw new Error(`[Askr] SSR redirect limit exceeded (${MAX_SSR_REDIRECTS}).`);
69
+ }
70
+ //#endregion
71
+ //#region src/ssr/route-render.ts
72
+ /** Resolve a URL against a route registry for SSR, applying auth/policies before render. */
73
+ async function resolveRequest(opts) {
74
+ if (!opts?.registry) throw new TypeError("resolveRequest requires opts.registry.");
75
+ const { url, auth, authContext, request, signal } = opts;
76
+ return await resolveRouteRequest(url, {
77
+ registry: opts.registry,
78
+ mode: "ssr",
79
+ auth,
80
+ authContext,
81
+ request,
82
+ signal
83
+ });
84
+ }
85
+ function resolveSSRRouteSource(source) {
86
+ if (source.registry.routes.length === 0) throw new Error("SSR requires a non-empty route registry.");
87
+ return source.registry.routes.map((route) => ({
88
+ ...route,
89
+ path: route.path,
90
+ handler: route.handler,
91
+ namespace: route.namespace
92
+ }));
93
+ }
94
+ function resolveSSRRouteRender(opts) {
95
+ const { seed = 12345, data, document, styleRegistrationValidation = "warn" } = opts;
96
+ const cspNonce = validateCspNonce(opts.cspNonce);
97
+ const routeTable = resolveSSRRouteSource(opts);
98
+ const resolvedRoute = resolvePolicyAwareSSRRoute(opts, routeTable);
99
+ const requestUrl = new URL(resolvedRoute.url, "http://localhost");
100
+ const ctx = createRenderContext(seed, {
101
+ url: resolvedRoute.url,
102
+ basePath: opts.registry.manifest.basePath,
103
+ data,
104
+ params: resolvedRoute.params,
105
+ routes: routeTable,
106
+ routeAuth: opts.auth ?? opts.registry.manifest.auth,
107
+ signal: opts.signal ?? opts.request?.signal,
108
+ dataRuntime: opts.dataRuntime,
109
+ queryPrefetch: opts.queryPrefetch,
110
+ authContext: resolvedRoute.authContext,
111
+ envelope: opts.envelope,
112
+ cspNonce
113
+ });
114
+ return {
115
+ url: resolvedRoute.url,
116
+ requestUrl,
117
+ route: resolvedRoute.route,
118
+ params: resolvedRoute.params,
119
+ seed,
120
+ data,
121
+ ctx,
122
+ document,
123
+ cspNonce,
124
+ styleRegistrationValidation
125
+ };
126
+ }
127
+ function buildDocumentRenderArgs(resolved, appHtml) {
128
+ return {
129
+ appHtml,
130
+ context: {
131
+ mode: "ssr",
132
+ url: resolved.url,
133
+ pathname: resolved.requestUrl.pathname,
134
+ search: resolved.requestUrl.search,
135
+ hash: resolved.requestUrl.hash,
136
+ params: resolved.params,
137
+ data: resolved.data,
138
+ seed: resolved.seed,
139
+ route: {
140
+ path: resolved.route.path,
141
+ namespace: resolved.route.namespace
142
+ },
143
+ cspNonce: resolved.cspNonce,
144
+ styles: Array.from(resolved.ctx.ssrStyles.values())
145
+ }
146
+ };
147
+ }
148
+ function renderResolvedRouteAppToSink(resolved, sink, host) {
149
+ host.renderAppToSink({
150
+ route: resolved.route,
151
+ params: resolved.params,
152
+ data: resolved.data,
153
+ ctx: resolved.ctx,
154
+ sink
155
+ });
156
+ }
157
+ function renderToSinkInternal(opts, host) {
158
+ const { sink, ...renderOptions } = opts;
159
+ return withTelemetry(renderOptions.telemetry?.ssrRender, {}, () => {
160
+ const resolved = resolveSSRRouteRender(renderOptions);
161
+ if (!resolved.document) {
162
+ renderResolvedRouteAppToSink(resolved, sink, host);
163
+ return;
164
+ }
165
+ const appSink = new StringSink();
166
+ renderResolvedRouteAppToSink(resolved, appSink, host);
167
+ appSink.end();
168
+ sink.write(renderDocument(resolved.document, buildDocumentRenderArgs(resolved, appSink.toString()), "renderToString()/renderToStream()", resolved.styleRegistrationValidation));
169
+ });
170
+ }
171
+ function renderRouteToString(opts, host) {
172
+ const sink = new StringSink();
173
+ renderToSinkInternal({
174
+ ...opts,
175
+ sink
176
+ }, host);
177
+ sink.end();
178
+ return sink.toString();
179
+ }
180
+ function renderRouteToStream(opts, host) {
181
+ const sink = new StreamSink(opts.onChunk, opts.onComplete);
182
+ renderToSinkInternal({
183
+ ...opts,
184
+ sink
185
+ }, host);
186
+ sink.end();
187
+ }
188
+ //#endregion
189
+ //#region src/ssr/route-request-render.ts
190
+ function abortError() {
191
+ const error = /* @__PURE__ */ new Error("Deferred route rendering was aborted.");
192
+ error.name = "AbortError";
193
+ return error;
194
+ }
195
+ function settleWithSignal(promise, signal) {
196
+ if (signal.aborted) return Promise.reject(abortError());
197
+ return new Promise((resolve, reject) => {
198
+ const abort = () => reject(abortError());
199
+ signal.addEventListener("abort", abort, { once: true });
200
+ promise.then((value) => {
201
+ signal.removeEventListener("abort", abort);
202
+ resolve(value);
203
+ }, (error) => {
204
+ signal.removeEventListener("abort", abort);
205
+ reject(error);
206
+ });
207
+ });
208
+ }
209
+ function stripHydrationPayload(html) {
210
+ return html.replace(/<script type="application\/json" data-askr-render-data="true">[\s\S]*?<\/script>$/, "");
211
+ }
212
+ function renderBoundary(boundary, state, payload, seed, data, cspNonce, authContext) {
213
+ const styles = [];
214
+ return {
215
+ html: stripHydrationPayload(renderToStringSync(() => state === "fulfilled" ? boundary.fulfilled(payload) : boundary.rejected(payload), {}, {
216
+ seed,
217
+ envelope: data ?? void 0,
218
+ cspNonce,
219
+ authContext,
220
+ onContext: (context) => styles.push(...context.ssrStyles.values())
221
+ })),
222
+ styles
223
+ };
224
+ }
225
+ function escapeHtmlAttribute(value) {
226
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
227
+ }
228
+ function escapeStyleRawText(value) {
229
+ return value.replace(/<\/style/gi, "<\\/style");
230
+ }
231
+ function patchChunk(id, html, styles, cspNonce) {
232
+ const selector = `askr-resolve[data-askr-deferred=${JSON.stringify(id)}]`;
233
+ return `${styles.length === 0 ? "" : `<style data-askr-style-registry="true" data-askr-deferred-style="true"${cspNonce ? ` nonce="${escapeHtmlAttribute(cspNonce)}"` : ""}>${escapeStyleRawText(styles.map((style) => style.cssText).join("\n"))}\n</style>`}<template data-askr-deferred-patch="${escapeHtmlAttribute(id)}">${html}</template><script${cspNonce ? ` nonce="${escapeHtmlAttribute(cspNonce)}"` : ""} data-askr-deferred-apply="${escapeHtmlAttribute(id)}">(function(s){var t=s.previousElementSibling;var c=t&&t.previousElementSibling;var r=document.querySelector('style[data-askr-style-registry="true"]:not([data-askr-deferred-style])');if(c&&c.tagName==='STYLE'&&r&&r!==c){r.append(c.textContent||'');c.remove();}else if(c&&c.tagName==='STYLE'){c.removeAttribute('data-askr-deferred-style');}var b=document.querySelector(${JSON.stringify(selector)});if(b&&t){b.replaceWith(t.content.cloneNode(true));}if(t)t.remove();s.remove();})(document.currentScript)<\/script>`;
234
+ }
235
+ function createDeferredRenderStream(initialHtml, boundaries, signal, seed, data, runtime, cspNonce, authContext) {
236
+ const encoder = new TextEncoder();
237
+ const local = new AbortController();
238
+ let cancelled = false;
239
+ let closed = false;
240
+ let initialPending = true;
241
+ let boundaryIndex = 0;
242
+ let controllerRef;
243
+ const cleanup = () => signal.removeEventListener("abort", abort);
244
+ const close = (controller) => {
245
+ if (closed) return;
246
+ closed = true;
247
+ cleanup();
248
+ controller.close();
249
+ };
250
+ const abort = () => {
251
+ local.abort(signal.reason);
252
+ if (controllerRef) close(controllerRef);
253
+ };
254
+ signal.addEventListener("abort", abort, { once: true });
255
+ return new ReadableStream({
256
+ start(controller) {
257
+ controllerRef = controller;
258
+ },
259
+ async pull(controller) {
260
+ if (cancelled || closed) return;
261
+ if (initialPending) {
262
+ initialPending = false;
263
+ controller.enqueue(encoder.encode(stripHydrationPayload(initialHtml)));
264
+ return;
265
+ }
266
+ const boundary = boundaries[boundaryIndex];
267
+ if (boundary) {
268
+ boundaryIndex += 1;
269
+ try {
270
+ const value = await settleWithSignal(boundary.promise, local.signal);
271
+ if (!cancelled && !closed) {
272
+ const rendered = renderBoundary(boundary, "fulfilled", value, seed, data, cspNonce, authContext);
273
+ controller.enqueue(encoder.encode(patchChunk(boundary.id, rendered.html, rendered.styles, cspNonce)));
274
+ }
275
+ } catch (error) {
276
+ if (local.signal.aborted) {
277
+ if (!cancelled && !closed) close(controller);
278
+ return;
279
+ }
280
+ if (!cancelled && !closed) {
281
+ const rendered = renderBoundary(boundary, "rejected", error, seed, data, cspNonce, authContext);
282
+ controller.enqueue(encoder.encode(patchChunk(boundary.id, rendered.html, rendered.styles, cspNonce)));
283
+ }
284
+ }
285
+ return;
286
+ }
287
+ const hydration = serializeHydrationRenderData(data ?? void 0, runtime);
288
+ if (hydration) controller.enqueue(encoder.encode(hydration));
289
+ close(controller);
290
+ },
291
+ cancel(reason) {
292
+ cancelled = true;
293
+ local.abort(reason);
294
+ cleanup();
295
+ }
296
+ });
297
+ }
298
+ /** Resolve and render a route request for SSR, streaming the body when possible. */
299
+ async function renderRouteRequest(options) {
300
+ return renderRouteRequestInternal(options);
301
+ }
302
+ /** Resolve and render a route request for SSR, always fully buffering the HTML. */
303
+ async function renderRouteRequestToString(options) {
304
+ const result = await renderRouteRequestInternal(options);
305
+ if (result.kind !== "render" || !result.stream) return result;
306
+ return {
307
+ ...result,
308
+ html: await new Response(result.stream).text(),
309
+ stream: void 0
310
+ };
311
+ }
312
+ async function renderRouteRequestInternal(options) {
313
+ if (!options?.registry) throw new TypeError("renderRouteRequest requires options.registry.");
314
+ const cspNonce = validateCspNonce(options.cspNonce);
315
+ const manifest = options.registry.manifest;
316
+ const signal = options.signal ?? options.request?.signal ?? new AbortController().signal;
317
+ const request = options.request ?? new Request(new URL(options.url, "http://localhost"));
318
+ const runtime = options.dataRuntime ?? createDataRuntime();
319
+ const prefetch = options.queryPrefetch ?? createQueryPrefetchContext({
320
+ runtime,
321
+ registry: options.queryRegistry,
322
+ request,
323
+ signal,
324
+ mode: "ssr",
325
+ telemetry: options.telemetry
326
+ });
327
+ const context = createRenderContext(options.seed, {
328
+ url: options.url,
329
+ basePath: manifest.basePath,
330
+ routes: options.registry.routes,
331
+ routeAuth: options.auth ?? manifest.auth,
332
+ data: options.data,
333
+ framework: options.framework,
334
+ signal,
335
+ dataRuntime: runtime,
336
+ queryPrefetch: prefetch,
337
+ mode: "ssr",
338
+ cspNonce
339
+ });
340
+ return withTelemetry(options.telemetry?.ssrRender, {}, () => withRenderContextAsync(context, async () => {
341
+ const resolved = await resolveRouteRequest(options.url, {
342
+ registry: options.registry,
343
+ mode: "ssr",
344
+ auth: options.auth ?? manifest.auth,
345
+ authContext: options.authContext,
346
+ request,
347
+ signal,
348
+ telemetry: options.telemetry
349
+ });
350
+ if (!resolved) return { kind: "no-match" };
351
+ if (resolved.kind !== "render") return resolved;
352
+ context.params = resolved.params;
353
+ const sink = new StringSink();
354
+ renderSSRRouteAppToSink({
355
+ route: {
356
+ path: "",
357
+ handler: resolved.handler
358
+ },
359
+ params: resolved.params,
360
+ data: options.data,
361
+ ctx: context,
362
+ sink
363
+ });
364
+ sink.end();
365
+ const html = sink.toString();
366
+ const boundaries = [...context.deferredBoundaries];
367
+ const result = {
368
+ kind: "render",
369
+ html,
370
+ styles: Array.from(context.ssrStyles.values()),
371
+ ...boundaries.length > 0 ? { stream: createDeferredRenderStream(html, boundaries, signal, options.seed, context.hydrationData, runtime, cspNonce, context.authContext) } : {},
372
+ params: resolved.params
373
+ };
374
+ if (resolved.record) Object.defineProperty(result, "record", {
375
+ value: resolved.record,
376
+ enumerable: false
377
+ });
378
+ return result;
379
+ }));
380
+ }
381
+ //#endregion
382
+ //#region src/ssr/index-internal.ts
383
+ const routeRenderHost = { renderAppToSink: renderSSRRouteAppToSink };
384
+ function renderToString(arg) {
385
+ if (typeof arg === "function") return renderToStringSync(arg);
386
+ return renderRouteToString(arg, routeRenderHost);
387
+ }
388
+ /** Stream a route request's rendered HTML to the response sink described by `opts`. */
389
+ function renderToStream(opts) {
390
+ renderRouteToStream(opts, routeRenderHost);
391
+ }
392
+ //#endregion
393
+ export { resolveRequest as a, renderRouteRequestToString as i, renderToString as n, renderRouteRequest as r, renderToStream as t };
@@ -1,4 +1,8 @@
1
+ import { P as isPromiseLike } from "./instance-VAFYVJOa.js";
1
2
  //#region src/common/ssr.ts
3
+ /**
4
+ * Common call contracts: SSR types
5
+ */
2
6
  function escapedStyleRawText(value) {
3
7
  return value.replace(/<\//gi, "<\\/");
4
8
  }
@@ -14,7 +18,7 @@ function validateDocumentStyleRegistrations(html, styles, apiName, validation) {
14
18
  function renderDocument(document, args, apiName, styleRegistrationValidation = "warn") {
15
19
  const html = document(args);
16
20
  if (typeof html !== "string") {
17
- const received = typeof html === "object" && html !== null && "then" in html && typeof html.then === "function" ? "a Promise-like value" : html === null ? "null" : Array.isArray(html) ? "an array" : typeof html;
21
+ const received = isPromiseLike(html) ? "a Promise-like value" : html === null ? "null" : Array.isArray(html) ? "an array" : typeof html;
18
22
  throw new Error(`${apiName} document() must synchronously return a string; received ${received}.`);
19
23
  }
20
24
  validateDocumentStyleRegistrations(html, args.context.styles, apiName, styleRegistrationValidation);