@askrjs/askr 0.0.62 → 0.0.65

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 (37) hide show
  1. package/README.md +5 -5
  2. package/dist/actions/index.d.ts +1 -1
  3. package/dist/authoring-CXMPffwN.js +200 -0
  4. package/dist/benchmark.js +4 -4
  5. package/dist/boot/index.d.ts +12 -32
  6. package/dist/boot/index.js +1 -1
  7. package/dist/{boot-B0mMBddb.js → boot-OnYuVVfg.js} +64 -75
  8. package/dist/components/index.d.ts +1 -1
  9. package/dist/control/index.d.ts +1 -1
  10. package/dist/{control-CFIrGbD7.d.ts → control-CMzFPMjr.d.ts} +3 -0
  11. package/dist/csp-nonce-C-8E85El.js +33 -0
  12. package/dist/{deferred-BeNnjR4r.js → deferred-B71c2eio.js} +51 -10
  13. package/dist/foundations/index.d.ts +1 -1
  14. package/dist/foundations/state/index.d.ts +1 -1
  15. package/dist/foundations/structures/index.d.ts +1 -1
  16. package/dist/{index-DaWuMuIc.d.ts → index-Bjm0__Rr.d.ts} +1 -1
  17. package/dist/{index-DlvpxdSz.d.ts → index-Byqjltu2.d.ts} +1 -1
  18. package/dist/{index-CRck4XVe.d.ts → index-NKPpdRh9.d.ts} +6 -2
  19. package/dist/{index-Bce-RQg-.d.ts → index-PgRn5wmg.d.ts} +1 -1
  20. package/dist/index.d.ts +4 -4
  21. package/dist/index.js +3 -2
  22. package/dist/{navigate-DLi79IZr.js → navigate-DTZ2SM8_.js} +68 -279
  23. package/dist/{renderer-CVr_nktj.js → renderer-aUD-acDe.js} +1 -1
  24. package/dist/{route-matching-vJpvLVbX.js → route-matching-C93To416.js} +2 -2
  25. package/dist/router/index.d.ts +4 -10
  26. package/dist/router/index.js +4 -4
  27. package/dist/{router-lmH-Tmwh.d.ts → router-eRoaj11J.d.ts} +9 -6
  28. package/dist/ssg/index.d.ts +8 -33
  29. package/dist/ssg/index.js +34 -36
  30. package/dist/ssr/index.d.ts +10 -45
  31. package/dist/ssr/index.js +1 -1
  32. package/dist/{ssr-5HlhmLhU.js → ssr-C0hzqhY8.js} +65 -43
  33. package/dist/testing/index.d.ts +4 -5
  34. package/dist/testing/index.js +7 -10
  35. package/dist/{verify-hydration-13f0FOPd.js → verify-hydration-BdKE9Hi8.js} +3 -3
  36. package/package.json +1 -1
  37. package/dist/router-internal-BC0w1_xk.js +0 -4
@@ -1,26 +1,21 @@
1
- import { c as RenderableChild, d as DocumentRenderContext, f as DocumentRenderer, s as ComponentFunction, u as DocumentRenderArgs } from "../control-CFIrGbD7.js";
2
- import { E as RouteOptions, O as RoutePathParams, P as RouteRegistry, b as RouteHandler, k as RoutePolicy } from "../router-lmH-Tmwh.js";
1
+ import { d as DocumentRenderContext, f as DocumentRenderer, u as DocumentRenderArgs } from "../control-CMzFPMjr.js";
2
+ import { D as RoutePathParams, N as RouteRegistry, O as RoutePolicy, T as RouteOptions, y as RouteHandler } from "../router-eRoaj11J.js";
3
3
  import { AuthRequirement } from "@askrjs/auth";
4
4
  //#region src/ssg/types.d.ts
5
5
  type SSGMode = 'full' | 'incremental';
6
6
  type RouteRenderStatus = 'success' | 'error' | 'skipped' | 'removed';
7
7
  type RouteRenderReason = 'full' | 'changed-key' | 'changed-route' | 'new-route' | 'no-keys' | 'unchanged' | 'deleted' | 'runtime-only';
8
8
  type RouteConfigParams<Path extends string> = string extends Path ? Record<string, string> : RoutePathParams<Path>;
9
- type RouteComponentProps<Path extends string> = RouteConfigParams<Path> & Record<string, unknown>;
10
- type StaticRouteComponent<Path extends string> = (props: RouteComponentProps<Path>, context?: Parameters<ComponentFunction>[1]) => RenderableChild;
11
9
  /**
12
10
  * Route config accepted by SSG.
13
11
  *
14
- * `handler` is preferred and matches router/SSR naming.
15
- * `component` is kept for compatibility and is normalized to `handler`.
12
+ * The handler is defined by the route registry and matches router/SSR naming.
16
13
  */
17
14
  interface RouteConfig<Path extends string = string> {
18
15
  /** URL path to generate (e.g., "/blog/post-1", "/") */
19
16
  path: Path;
20
17
  /** Route handler compatible with router/SSR */
21
- handler?: RouteHandler;
22
- /** Backward-compatible alias for handler */
23
- component?: StaticRouteComponent<Path>;
18
+ handler: RouteHandler;
24
19
  /** Optional base props merged with route params during render */
25
20
  props?: Record<string, unknown>;
26
21
  /** Optional namespace for router compatibility */
@@ -72,13 +67,9 @@ interface SSGAssetSource {
72
67
  to?: string;
73
68
  }
74
69
  /** Options for createStaticGen */
75
- type SSGOptions<TRoutes extends readonly RouteConfig[] = RouteConfig[]> = SSGBaseOptions & ({
76
- /** Routes to generate. Prefer `registry` when routes are already defined through the router DSL. */routes: TRoutes;
77
- registry?: never;
78
- } | {
70
+ type SSGOptions<TRoutes extends readonly RouteConfig[] = RouteConfig[]> = SSGBaseOptions & {
79
71
  /** Explicit route registry captured with `createRouteRegistry()`. */registry: RouteRegistry;
80
- routes?: never;
81
- });
72
+ };
82
73
  /** Options for a single generation run */
83
74
  interface SSGGenerateOptions {
84
75
  /** Generation mode */
@@ -190,29 +181,13 @@ interface DiscoveredResources {
190
181
  }
191
182
  //#endregion
192
183
  //#region src/ssg/create-static-gen.d.ts
193
- type AnyRouteConfig = RouteConfig<string>;
194
- type StrictRouteConfig<TRoute extends AnyRouteConfig> = Omit<TRoute, 'params' | 'entries'> & {
195
- params?: RouteConfig<TRoute['path']>['params'];
196
- entries?: RouteConfig<TRoute['path']>['entries'];
197
- };
198
- type StrictRouteConfigs<TRoutes extends readonly AnyRouteConfig[]> = { [TIndex in keyof TRoutes]: TRoutes[TIndex] extends AnyRouteConfig ? StrictRouteConfig<TRoutes[TIndex]> : never };
199
- type StaticGenRouteSource<TRoutes extends readonly AnyRouteConfig[]> = {
200
- routes: TRoutes & StrictRouteConfigs<TRoutes>;
201
- registry?: never;
202
- } | {
203
- registry: RouteRegistry;
204
- routes?: never;
205
- };
206
184
  /**
207
185
  * Create a Static Site Generator
208
186
  *
209
187
  * Usage:
210
188
  * ```ts
211
189
  * const ssg = createStaticGen({
212
- * routes: [
213
- * { path: '/', component: HomePage },
214
- * { path: '/about', component: AboutPage },
215
- * ],
190
+ * registry,
216
191
  * outputDir: './dist',
217
192
  * dataOverrides: {
218
193
  * '/api/posts': { posts: [...] }
@@ -223,7 +198,7 @@ type StaticGenRouteSource<TRoutes extends readonly AnyRouteConfig[]> = {
223
198
  * console.log(`Generated ${result.successful}/${result.totalRoutes} routes`);
224
199
  * ```
225
200
  */
226
- declare function createStaticGen<const TRoutes extends readonly AnyRouteConfig[]>(options: Omit<SSGOptions<TRoutes>, 'routes' | 'registry'> & StaticGenRouteSource<TRoutes>): {
201
+ declare function createStaticGen(options: SSGOptions): {
227
202
  /**
228
203
  * Generate static HTML for all routes
229
204
  * Writes to outputDir with metadata.json
package/dist/ssg/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import "../access-ePqdQqkV.js";
2
- import { a as resolveDeferredValues, b as getRenderHandler, c as bindResolvedRouteData } from "../deferred-BeNnjR4r.js";
2
+ import { S as getRenderHandler, a as resolveDeferredValues, l as createRouteRegistry, u as bindResolvedRouteData } from "../deferred-B71c2eio.js";
3
+ import { a as route } from "../authoring-CXMPffwN.js";
3
4
  import { n as renderDocument } from "../ssr-CbQO5xd3.js";
4
- import { n as renderToString } from "../ssr-5HlhmLhU.js";
5
+ import { n as renderToString } from "../ssr-C0hzqhY8.js";
5
6
  import * as fs from "node:fs/promises";
6
7
  import * as pathModule from "node:path";
7
8
  import * as os from "node:os";
@@ -73,7 +74,7 @@ function isStringRecord(value) {
73
74
  }
74
75
  function validateRouteShape(route) {
75
76
  if (typeof route.path !== "string" || !route.path.startsWith("/")) throw new Error(`route path must be a string starting with "/", got "${route.path}"`);
76
- if (typeof (route.handler ?? route.component) !== "function") throw new Error(`route handler must be a function for path "${route.path}"`);
77
+ if (typeof route.handler !== "function") throw new Error(`route handler must be a function for path "${route.path}"`);
77
78
  if (route.params !== void 0 && !isStringRecord(route.params)) throw new Error(`route "${route.path}" params must be an object containing only string values`);
78
79
  if (route.invalidationKeys !== void 0) {
79
80
  if (!Array.isArray(route.invalidationKeys)) throw new Error(`route "${route.path}" invalidationKeys must be an array of strings`);
@@ -141,28 +142,25 @@ async function batchRenderRoutes(routes, options = {}) {
141
142
  const results = [];
142
143
  results.length = routes.length;
143
144
  let nextIndex = 0;
144
- const renderOne = async (route) => {
145
+ const sharedRegistry = new Set(routes.map((route) => route.path)).size === routes.length ? createRouteRegistry(() => {
146
+ for (const route$1 of routes) route(route$1.path, route$1.handler, { namespace: route$1.namespace });
147
+ }) : void 0;
148
+ const renderOne = async (route$2) => {
145
149
  const startTime = performance.now();
146
- const url = interpolateRoutePath(route.path, route.params);
150
+ const url = interpolateRoutePath(route$2.path, route$2.params);
147
151
  const requestUrl = new URL(url, "http://localhost");
148
- const resolvedData = resolveSsgRouteData(dataMap, route.path, url);
152
+ const resolvedData = resolveSsgRouteData(dataMap, route$2.path, url);
149
153
  const baseData = resolvedData.hasData ? resolvedData.data : void 0;
150
154
  const resourceCount = resolvedData.hasData && baseData ? Object.keys(baseData).length : 0;
151
- const mergedHandler = route.handler ? route.handler : (params, ctx) => {
152
- const component = route.component;
153
- return component({
154
- ...route.props,
155
- ...params
156
- }, ctx);
157
- };
155
+ const mergedHandler = route$2.handler;
158
156
  try {
159
157
  let routeData;
160
158
  let hasRouteData = false;
161
- if (route.loader) {
159
+ if (route$2.loader) {
162
160
  const controller = new AbortController();
163
161
  const loadContext = {
164
162
  mode: "ssg",
165
- params: route.params ?? {},
163
+ params: route$2.params ?? {},
166
164
  pathname: requestUrl.pathname,
167
165
  search: requestUrl.search,
168
166
  hash: requestUrl.hash,
@@ -175,7 +173,7 @@ async function batchRenderRoutes(routes, options = {}) {
175
173
  },
176
174
  signal: controller.signal
177
175
  };
178
- const loaded = await route.loader({
176
+ const loaded = await route$2.loader({
179
177
  ...loadContext,
180
178
  request: new Request(requestUrl)
181
179
  });
@@ -183,13 +181,12 @@ async function batchRenderRoutes(routes, options = {}) {
183
181
  routeData = loaded;
184
182
  hasRouteData = true;
185
183
  }
184
+ const renderedHandler = hasRouteData ? bindResolvedRouteData(mergedHandler, routeData) : mergedHandler;
186
185
  const html = renderToString({
187
186
  url,
188
- routes: [{
189
- path: route.path,
190
- handler: hasRouteData ? bindResolvedRouteData(mergedHandler, routeData) : mergedHandler,
191
- namespace: route.namespace
192
- }],
187
+ registry: hasRouteData || !sharedRegistry ? createRouteRegistry(() => {
188
+ route(route$2.path, renderedHandler, { namespace: route$2.namespace });
189
+ }) : sharedRegistry,
193
190
  seed,
194
191
  data: baseData,
195
192
  document: document === void 0 ? void 0 : ({ appHtml }) => renderDocument(document, {
@@ -200,12 +197,12 @@ async function batchRenderRoutes(routes, options = {}) {
200
197
  pathname: requestUrl.pathname,
201
198
  search: requestUrl.search,
202
199
  hash: requestUrl.hash,
203
- params: route.params ?? {},
200
+ params: route$2.params ?? {},
204
201
  data: baseData,
205
202
  seed,
206
203
  route: {
207
- path: route.path,
208
- namespace: route.namespace
204
+ path: route$2.path,
205
+ namespace: route$2.namespace
209
206
  }
210
207
  }
211
208
  }, "createStaticGen()")
@@ -579,21 +576,24 @@ async function splitStaticRoutes(routes) {
579
576
  };
580
577
  }
581
578
  function normalizeStaticRoutes(options) {
582
- if (options.registry) return routeRegistryToRouteConfigs(options.registry);
583
- return [...options.routes ?? []];
579
+ return routeRegistryToRouteConfigs(options.registry);
584
580
  }
585
581
  function routeRegistryToRouteConfigs(registry) {
586
582
  const routeConfigs = [];
587
583
  for (const record of registry.manifest.records) {
588
584
  if (record.isFallback) continue;
585
+ const options = record.options;
589
586
  routeConfigs.push({
590
587
  path: record.path,
591
588
  handler: getRenderHandler(record),
592
- namespace: record.options.namespace,
593
- auth: record.options.auth,
594
- policies: record.options.policies,
595
- entries: record.options.entries,
596
- loader: record.options.loader
589
+ params: options.params,
590
+ props: options.props,
591
+ invalidationKeys: options.invalidationKeys ? [...options.invalidationKeys] : void 0,
592
+ namespace: options.namespace,
593
+ auth: options.auth,
594
+ policies: options.policies,
595
+ entries: options.entries,
596
+ loader: options.loader
597
597
  });
598
598
  }
599
599
  return routeConfigs;
@@ -672,10 +672,7 @@ async function replaceOutputDirectory(stagingDir, outputDir, fileOperations = fs
672
672
  * Usage:
673
673
  * ```ts
674
674
  * const ssg = createStaticGen({
675
- * routes: [
676
- * { path: '/', component: HomePage },
677
- * { path: '/about', component: AboutPage },
678
- * ],
675
+ * registry,
679
676
  * outputDir: './dist',
680
677
  * dataOverrides: {
681
678
  * '/api/posts': { posts: [...] }
@@ -688,11 +685,12 @@ async function replaceOutputDirectory(stagingDir, outputDir, fileOperations = fs
688
685
  */
689
686
  function createStaticGen(options) {
690
687
  let result = null;
688
+ if (!options || !("registry" in options) || !options.registry) throw new Error("route registry is required");
691
689
  const configuredRoutes = normalizeStaticRoutes(options);
692
690
  const seed = options.seed ?? 12345;
693
691
  const resolvedParallelism = resolveParallelism(options.parallelism);
694
692
  const resolvedConcurrency = Math.max(1, options.concurrency ?? resolvedParallelism);
695
- if (configuredRoutes.length === 0) throw new Error("routes array or route registry is required");
693
+ if (configuredRoutes.length === 0) throw new Error("route registry is required");
696
694
  if (!options.outputDir || options.outputDir.trim().length === 0) throw new Error("outputDir is required");
697
695
  return {
698
696
  /**
@@ -1,7 +1,7 @@
1
- import { c as RenderableChild, d as DocumentRenderContext, f as DocumentRenderer, p as SSRData, u as DocumentRenderArgs } from "../control-CFIrGbD7.js";
1
+ import { c as RenderableChild, d as DocumentRenderContext, f as DocumentRenderer, p as SSRData, u as DocumentRenderArgs } from "../control-CMzFPMjr.js";
2
2
  import { r as JSXElement, s as Props } from "../jsx-Dvr2SGRG.js";
3
3
  import { D as QueryPrefetchContext, n as ServerQueryRegistry, u as CoreTelemetry, v as DataRuntime } from "../index-Bki2rqcr.js";
4
- import { L as RouteRequestResult, P as RouteRegistry, a as AccessRedirectDecision, b as RouteHandler, j as RouteRecord, m as RouteAuthOptions, p as Route, r as AccessDenyDecision, x as RouteManifest } from "../router-lmH-Tmwh.js";
4
+ import { A as RouteRecord, L as RouteRequestResult, N as RouteRegistry, a as AccessRedirectDecision, f as Route, p as RouteAuthOptions, r as AccessDenyDecision, y as RouteHandler } from "../router-eRoaj11J.js";
5
5
  import { AuthContext } from "@askrjs/auth";
6
6
 
7
7
  //#region src/common/page-render-envelope.d.ts
@@ -50,6 +50,7 @@ interface RenderContext {
50
50
  renderData: PageRenderEnvelope | null;
51
51
  hydrationData: PageRenderEnvelope | null;
52
52
  deferredBoundaries: DeferredBoundaryRegistration[];
53
+ cspNonce?: string;
53
54
  }
54
55
  declare function createRenderContext(seed?: number, opts?: {
55
56
  url?: string;
@@ -63,6 +64,7 @@ declare function createRenderContext(seed?: number, opts?: {
63
64
  queryPrefetch?: QueryPrefetchContext;
64
65
  framework?: Readonly<Record<string, unknown>>;
65
66
  envelope?: PageRenderEnvelope;
67
+ cspNonce?: string;
66
68
  }): RenderContext;
67
69
  /**
68
70
  * Run a function with the given render context.
@@ -84,10 +86,6 @@ type SSRRoute = {
84
86
  };
85
87
  type SSRRouteSource = {
86
88
  registry: RouteRegistry;
87
- routes?: readonly SSRRoute[];
88
- } | {
89
- registry?: RouteRegistry;
90
- routes: readonly SSRRoute[];
91
89
  };
92
90
  type RouteRenderOptions = SSRRouteSource & {
93
91
  url: string;
@@ -99,6 +97,7 @@ type RouteRenderOptions = SSRRouteSource & {
99
97
  queryPrefetch?: QueryPrefetchContext;
100
98
  telemetry?: Pick<CoreTelemetry, 'ssrRender'>; /** @internal Precomposed page state used by hydration verification. */
101
99
  envelope?: PageRenderEnvelope;
100
+ cspNonce?: string;
102
101
  };
103
102
  type RouteStreamOptions = RouteRenderOptions & {
104
103
  onChunk(html: string): void;
@@ -107,38 +106,6 @@ type RouteStreamOptions = RouteRenderOptions & {
107
106
  declare function resolveRequest(opts: {
108
107
  url: string;
109
108
  registry: RouteRegistry;
110
- manifest?: RouteManifest;
111
- routes?: Array<{
112
- path: string;
113
- handler: RouteHandler;
114
- namespace?: string;
115
- }>;
116
- auth?: RouteAuthOptions;
117
- authContext?: AuthContext;
118
- request?: Request;
119
- signal?: AbortSignal;
120
- } | {
121
- url: string;
122
- manifest: RouteManifest;
123
- registry?: RouteRegistry;
124
- routes?: Array<{
125
- path: string;
126
- handler: RouteHandler;
127
- namespace?: string;
128
- }>;
129
- auth?: RouteAuthOptions;
130
- authContext?: AuthContext;
131
- request?: Request;
132
- signal?: AbortSignal;
133
- } | {
134
- url: string;
135
- manifest?: RouteManifest;
136
- registry?: RouteRegistry;
137
- routes: Array<{
138
- path: string;
139
- handler: RouteHandler;
140
- namespace?: string;
141
- }>;
142
109
  auth?: RouteAuthOptions;
143
110
  authContext?: AuthContext;
144
111
  request?: Request;
@@ -167,16 +134,13 @@ declare function renderToStringSync(component: (props?: Record<string, unknown>)
167
134
  seed?: number;
168
135
  data?: SSRData; /** @internal A composed page render envelope. */
169
136
  envelope?: PageRenderEnvelope;
137
+ cspNonce?: string;
170
138
  }): string;
171
139
  //#endregion
172
140
  //#region src/ssr/render-resolved.d.ts
173
141
  declare function renderResolvedToStringSync(opts: {
174
142
  url: string;
175
- routes: ReadonlyArray<{
176
- path: string;
177
- handler: RouteHandler;
178
- namespace?: string;
179
- }>;
143
+ registry: RouteRegistry;
180
144
  handler: RouteHandler;
181
145
  params?: Record<string, string>;
182
146
  options?: {
@@ -184,14 +148,14 @@ declare function renderResolvedToStringSync(opts: {
184
148
  data?: SSRData;
185
149
  dataRuntime?: DataRuntime;
186
150
  envelope?: PageRenderEnvelope;
151
+ cspNonce?: string;
187
152
  };
188
153
  }): string;
189
154
  //#endregion
190
155
  //#region src/ssr/route-request-render.d.ts
191
156
  interface RenderRouteRequestOptions {
192
157
  url: string;
193
- manifest?: RouteManifest;
194
- registry?: RouteRegistry;
158
+ registry: RouteRegistry;
195
159
  auth?: RouteAuthOptions;
196
160
  authContext?: AuthContext;
197
161
  request?: Request;
@@ -204,6 +168,7 @@ interface RenderRouteRequestOptions {
204
168
  queryPrefetch?: QueryPrefetchContext;
205
169
  queryRegistry?: ServerQueryRegistry;
206
170
  telemetry?: CoreTelemetry;
171
+ cspNonce?: string;
207
172
  }
208
173
  type RenderRouteRequestResult = {
209
174
  kind: 'render';
package/dist/ssr/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { u as SSRDataMissingError } from "../render-context-Clw3rFiO.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-5HlhmLhU.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-C0hzqhY8.js";
3
3
  export { SSRDataMissingError, createRenderContext, getRenderContext, renderResolvedToStringSync, renderRouteRequest, renderRouteRequestToString, renderToStream, renderToString, renderToStringSync, resolveRequest, withRenderContext, withRenderContextAsync };
@@ -6,13 +6,15 @@ import { c as callWithContext, d as getExecutionContextFrame, f as getVNodeConte
6
6
  import { f as getCurrentComponentInstance, w as setCurrentComponentInstance } from "./component-scope-CC3cojX9.js";
7
7
  import { h as cleanupComponent, m as isPromiseLike } from "./component-lifecycle-DEMPihoZ.js";
8
8
  import { g as evaluateShowState, h as evaluateCaseState, i as evaluateForState, o as rollbackForStateTransaction, r as commitForStateTransaction } from "./for-internal-B2rBq6yB.js";
9
+ import { _ as isEmptyPageRenderEnvelope, g as createPageRenderEnvelope, i as isDeferred, l as createRouteRegistry, m as resolveRouteRequest, t as DEFERRED_BOUNDARY, v as isPageRenderEnvelope } from "./deferred-B71c2eio.js";
9
10
  import { c as stopRenderPhase$1, o as startRenderPhase$1, t as configureRenderContextProvider, u as SSRDataMissingError } from "./render-context-Clw3rFiO.js";
10
11
  import { a as disposeDefaultPortalScope, t as DefaultPortal } from "./portal-D2tPWNrC.js";
11
12
  import { t as getPublicAttributeName } from "./attr-names-CjhzmHOn.js";
13
+ import { r as validateCspNonce, t as CspNonceScope } from "./csp-nonce-C-8E85El.js";
12
14
  import { t as createDataRuntime } from "./data-runtime-SJ1BSUvk.js";
13
15
  import { c as withTelemetry, i as dehydrateDataRuntime, t as createQueryPrefetchContext } from "./query-registry-CQIT4mXr.js";
14
- import { a as resolveRouteFromRoutes, t as _resolveRouteMatchFromRoutes } from "./route-matching-vJpvLVbX.js";
15
- import { f as resolveRouteRequest, g as isPageRenderEnvelope, h as isEmptyPageRenderEnvelope, i as isDeferred, m as createPageRenderEnvelope, t as DEFERRED_BOUNDARY, x as _preloadRouteHandler } from "./deferred-BeNnjR4r.js";
16
+ import { a as resolveRouteFromRoutes, t as _resolveRouteMatchFromRoutes } from "./route-matching-C93To416.js";
17
+ import { a as route } from "./authoring-CXMPffwN.js";
16
18
  import { n as renderDocument, t as SSR_RENDER_DATA_ATTR } from "./ssr-CbQO5xd3.js";
17
19
  //#region src/ssr/escape.ts
18
20
  /**
@@ -260,7 +262,8 @@ function createRenderContext(seed = 12345, opts = {}) {
260
262
  keyCounter: 0,
261
263
  renderData: envelope,
262
264
  hydrationData: envelope,
263
- deferredBoundaries: []
265
+ deferredBoundaries: [],
266
+ cspNonce: opts.cspNonce
264
267
  };
265
268
  }
266
269
  /**
@@ -487,31 +490,20 @@ var StreamSink = class {
487
490
  //#endregion
488
491
  //#region src/ssr/route-render.ts
489
492
  async function resolveRequest(opts) {
493
+ if (!opts?.registry) throw new TypeError("resolveRequest requires opts.registry.");
490
494
  const { url, auth, authContext, request, signal } = opts;
491
- const manifest = opts.manifest ?? opts.registry?.manifest;
492
- const routes = opts.routes ?? opts.registry?.routes;
493
- if (manifest) return await resolveRouteRequest(url, {
494
- manifest,
495
+ return await resolveRouteRequest(url, {
496
+ manifest: opts.registry.manifest,
495
497
  mode: "ssr",
496
498
  auth,
497
499
  authContext,
498
500
  request,
499
501
  signal
500
502
  });
501
- if (!routes) throw new Error("resolveRequest requires a route manifest or route table.");
502
- const resolved = resolveRouteFromRoutes(new URL(url, "http://localhost").pathname, routes);
503
- if (!resolved) return null;
504
- await _preloadRouteHandler(resolved.handler);
505
- return {
506
- kind: "render",
507
- handler: resolved.handler,
508
- params: resolved.params
509
- };
510
503
  }
511
504
  function resolveSSRRouteSource(source) {
512
- const routes = source.routes ?? source.registry?.routes;
513
- if (!routes || routes.length === 0) throw new Error("SSR requires a route registry or route table.");
514
- return routes.map((route) => ({
505
+ if (source.registry.routes.length === 0) throw new Error("SSR requires a non-empty route registry.");
506
+ return source.registry.routes.map((route) => ({
515
507
  ...route,
516
508
  path: route.path,
517
509
  handler: route.handler,
@@ -520,6 +512,7 @@ function resolveSSRRouteSource(source) {
520
512
  }
521
513
  function resolveSSRRouteRender(opts) {
522
514
  const { seed = 12345, data, document } = opts;
515
+ const cspNonce = validateCspNonce(opts.cspNonce);
523
516
  const routeTable = resolveSSRRouteSource(opts);
524
517
  const resolvedRoute = resolvePolicyAwareSSRRoute(opts, routeTable);
525
518
  const requestUrl = new URL(resolvedRoute.url, "http://localhost");
@@ -530,7 +523,8 @@ function resolveSSRRouteRender(opts) {
530
523
  routes: routeTable,
531
524
  dataRuntime: opts.dataRuntime,
532
525
  queryPrefetch: opts.queryPrefetch,
533
- envelope: opts.envelope
526
+ envelope: opts.envelope,
527
+ cspNonce
534
528
  });
535
529
  return {
536
530
  url: resolvedRoute.url,
@@ -540,7 +534,8 @@ function resolveSSRRouteRender(opts) {
540
534
  seed,
541
535
  data,
542
536
  ctx,
543
- document
537
+ document,
538
+ cspNonce
544
539
  };
545
540
  }
546
541
  function buildDocumentRenderArgs(resolved, appHtml) {
@@ -558,7 +553,8 @@ function buildDocumentRenderArgs(resolved, appHtml) {
558
553
  route: {
559
554
  path: resolved.route.path,
560
555
  namespace: resolved.route.namespace
561
- }
556
+ },
557
+ cspNonce: resolved.cspNonce
562
558
  }
563
559
  };
564
560
  }
@@ -800,7 +796,10 @@ function withControlBoundaryChildren(node, render) {
800
796
  const ESCAPED_ATTR_VALUE_CACHE_LIMIT = 512;
801
797
  const escapedAttrValueCache = /* @__PURE__ */ new Map();
802
798
  function isEventHandler(key) {
803
- return key.length >= 3 && key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && key.charCodeAt(2) >= 65 && key.charCodeAt(2) <= 90;
799
+ return key.length >= 2 && key.slice(0, 2).toLowerCase() === "on";
800
+ }
801
+ function assertAttributeName(name) {
802
+ if (!/^[A-Za-z_:][A-Za-z0-9_.:-]*$/.test(name)) throw new TypeError(`Invalid SSR attribute name: ${JSON.stringify(name)}`);
804
803
  }
805
804
  function getEscapedAttrValue(value) {
806
805
  if (value.length > 64) return escapeAttr(value);
@@ -825,6 +824,7 @@ function renderAttrsDirect(props, sink) {
825
824
  if (isEventHandler(key)) continue;
826
825
  if (key.charCodeAt(0) === 95) continue;
827
826
  const attrName = getPublicAttributeName(key);
827
+ assertAttributeName(attrName);
828
828
  if (attrName === "style") {
829
829
  const css = typeof value === "string" ? value : styleObjToCss(value);
830
830
  if (!css) continue;
@@ -864,6 +864,7 @@ function renderAttrs(props, opts) {
864
864
  if (isEventHandler(key)) continue;
865
865
  if (key.charCodeAt(0) === 95) continue;
866
866
  const attrName = key === "class" ? "class" : getPublicAttributeName(key);
867
+ assertAttributeName(attrName);
867
868
  if (attrName === "style") {
868
869
  const css = typeof value === "string" ? value : styleObjToCss(value);
869
870
  if (css === null || css === "") continue;
@@ -1066,6 +1067,7 @@ function renderNodeSync(node, ctx) {
1066
1067
  throw new Error(`renderNodeSync: unsupported VNode symbol type: ${String(type)}`);
1067
1068
  }
1068
1069
  const typeStr = type;
1070
+ assertElementName(typeStr);
1069
1071
  if (VOID_ELEMENTS.has(typeStr)) return `<${typeStr}${renderAttrs(props)} />`;
1070
1072
  const maybeDangerous = props?.dangerouslySetInnerHTML;
1071
1073
  if (maybeDangerous !== void 0 && maybeDangerous !== null) {
@@ -1118,6 +1120,7 @@ function renderNodeSyncToSink(node, sink, ctx) {
1118
1120
  throw new Error(`renderNodeSyncToSink: unsupported VNode symbol type: ${String(type)}`);
1119
1121
  }
1120
1122
  const typeStr = type;
1123
+ assertElementName(typeStr);
1121
1124
  if (VOID_ELEMENTS.has(typeStr)) {
1122
1125
  sinkWrite2(sink, "<", typeStr);
1123
1126
  renderAttrsDirect(props, sink);
@@ -1171,14 +1174,19 @@ function renderNodeSyncToSink(node, sink, ctx) {
1171
1174
  sinkWrite3(sink, "</", typeStr, ">");
1172
1175
  }
1173
1176
  function renderToStringSync(component, props, options) {
1174
- const ctx = createRenderContext(options?.seed ?? 12345, {
1177
+ const seed = options?.seed ?? 12345;
1178
+ const nonce = validateCspNonce(options?.cspNonce);
1179
+ const ctx = createRenderContext(seed, {
1175
1180
  data: options?.data,
1176
1181
  envelope: options?.envelope
1177
1182
  });
1178
1183
  return withRenderContext(ctx, () => {
1179
1184
  startRenderPhase(ctx.renderData);
1180
1185
  try {
1181
- const node = renderSyncComponentRoot(component, props || {}, ctx);
1186
+ const node = renderSyncComponentRoot(nonce === void 0 ? component : () => CspNonceScope({
1187
+ value: nonce,
1188
+ children: () => component(props)
1189
+ }), props || {}, ctx);
1182
1190
  if (!node) throw new Error("renderToStringSync: wrapped component returned empty");
1183
1191
  const sink = new StringSink();
1184
1192
  renderNodeSyncToSink(node, sink, ctx);
@@ -1199,7 +1207,10 @@ function renderSSRRouteAppToSink(input) {
1199
1207
  withRenderContext(ctx, () => {
1200
1208
  startRenderPhase(ctx.renderData);
1201
1209
  try {
1202
- renderRenderableSyncToSink(executeComponentSync(route.handler, params, ctx), sink, ctx);
1210
+ renderRenderableSyncToSink(executeComponentSync(ctx.cspNonce === void 0 ? route.handler : () => CspNonceScope({
1211
+ value: ctx.cspNonce,
1212
+ children: () => route.handler(params)
1213
+ }), params, ctx), sink, ctx);
1203
1214
  if (ctx.deferredBoundaries.length === 0) sink.write(serializeHydrationRenderData(ctx.hydrationData ?? data, ctx.dataRuntime));
1204
1215
  } finally {
1205
1216
  try {
@@ -1210,6 +1221,9 @@ function renderSSRRouteAppToSink(input) {
1210
1221
  }
1211
1222
  });
1212
1223
  }
1224
+ function assertElementName(name) {
1225
+ if (!/^[A-Za-z][A-Za-z0-9._:-]*$/.test(name)) throw new TypeError(`Invalid SSR element name: ${JSON.stringify(name)}`);
1226
+ }
1213
1227
  //#endregion
1214
1228
  //#region src/ssr/render-resolved.ts
1215
1229
  function sameRouteParams(left, right) {
@@ -1221,23 +1235,28 @@ function sameRouteParams(left, right) {
1221
1235
  return true;
1222
1236
  }
1223
1237
  function renderResolvedToStringSync(opts) {
1224
- const { url, routes, handler, params, options } = opts;
1238
+ const { url, registry, handler, params, options } = opts;
1239
+ const routes = registry.routes;
1225
1240
  const requestUrl = new URL(url, "http://localhost");
1226
1241
  const matchedIndex = routes.findIndex((route) => {
1227
1242
  const resolved = resolveRouteFromRoutes(requestUrl.pathname, [route]);
1228
1243
  return resolved !== null && resolved.handler === route.handler && sameRouteParams(resolved.params, params);
1229
1244
  });
1230
1245
  if (matchedIndex < 0) throw new Error(`renderResolvedToStringSync: no route found for url: ${url}`);
1246
+ const effectiveRoutes = routes.map((route, index) => index === matchedIndex ? {
1247
+ ...route,
1248
+ handler
1249
+ } : route);
1231
1250
  return renderToString({
1232
1251
  url,
1233
- routes: routes.map((route, index) => index === matchedIndex ? {
1234
- ...route,
1235
- handler
1236
- } : route),
1252
+ registry: createRouteRegistry(() => {
1253
+ for (const route$1 of effectiveRoutes) route(route$1.path, route$1.handler, { namespace: route$1.namespace });
1254
+ }),
1237
1255
  seed: options?.seed,
1238
1256
  data: options?.data,
1239
1257
  dataRuntime: options?.dataRuntime,
1240
- envelope: options?.envelope
1258
+ envelope: options?.envelope,
1259
+ cspNonce: options?.cspNonce
1241
1260
  });
1242
1261
  }
1243
1262
  //#endregion
@@ -1264,17 +1283,18 @@ function settleWithSignal(promise, signal) {
1264
1283
  function stripHydrationPayload(html) {
1265
1284
  return html.replace(/<script type="application\/json" data-askr-render-data="true">[\s\S]*?<\/script>$/, "");
1266
1285
  }
1267
- function renderBoundary(boundary, state, payload, seed, data) {
1286
+ function renderBoundary(boundary, state, payload, seed, data, cspNonce) {
1268
1287
  return stripHydrationPayload(renderToStringSync(() => state === "fulfilled" ? boundary.fulfilled(payload) : boundary.rejected(payload), {}, {
1269
1288
  seed,
1270
- envelope: data ?? void 0
1289
+ envelope: data ?? void 0,
1290
+ cspNonce
1271
1291
  }));
1272
1292
  }
1273
- function patchChunk(id, html) {
1293
+ function patchChunk(id, html, cspNonce) {
1274
1294
  const selector = `askr-resolve[data-askr-deferred=${JSON.stringify(id)}]`;
1275
- return `<template data-askr-deferred-patch="${id}">${html}</template><script data-askr-deferred-apply="${id}">(function(s){var t=s.previousElementSibling;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>`;
1295
+ return `<template data-askr-deferred-patch="${id}">${html}</template><script${cspNonce ? ` nonce="${cspNonce}"` : ""} data-askr-deferred-apply="${id}">(function(s){var t=s.previousElementSibling;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>`;
1276
1296
  }
1277
- function createDeferredRenderStream(initialHtml, boundaries, signal, seed, data, runtime) {
1297
+ function createDeferredRenderStream(initialHtml, boundaries, signal, seed, data, runtime, cspNonce) {
1278
1298
  const encoder = new TextEncoder();
1279
1299
  const local = new AbortController();
1280
1300
  let cancelled = false;
@@ -1310,13 +1330,13 @@ function createDeferredRenderStream(initialHtml, boundaries, signal, seed, data,
1310
1330
  boundaryIndex += 1;
1311
1331
  try {
1312
1332
  const value = await settleWithSignal(boundary.promise, local.signal);
1313
- if (!cancelled && !closed) controller.enqueue(encoder.encode(patchChunk(boundary.id, renderBoundary(boundary, "fulfilled", value, seed, data))));
1333
+ if (!cancelled && !closed) controller.enqueue(encoder.encode(patchChunk(boundary.id, renderBoundary(boundary, "fulfilled", value, seed, data, cspNonce), cspNonce)));
1314
1334
  } catch (error) {
1315
1335
  if (local.signal.aborted) {
1316
1336
  if (!cancelled && !closed) close(controller);
1317
1337
  return;
1318
1338
  }
1319
- if (!cancelled && !closed) controller.enqueue(encoder.encode(patchChunk(boundary.id, renderBoundary(boundary, "rejected", error, seed, data))));
1339
+ if (!cancelled && !closed) controller.enqueue(encoder.encode(patchChunk(boundary.id, renderBoundary(boundary, "rejected", error, seed, data, cspNonce), cspNonce)));
1320
1340
  }
1321
1341
  return;
1322
1342
  }
@@ -1344,8 +1364,9 @@ async function renderRouteRequestToString(options) {
1344
1364
  };
1345
1365
  }
1346
1366
  async function renderRouteRequestInternal(options) {
1347
- const manifest = options.manifest ?? options.registry?.manifest;
1348
- if (!manifest) throw new Error("renderRouteRequestToString requires a route manifest or registry.");
1367
+ if (!options?.registry) throw new TypeError("renderRouteRequest requires options.registry.");
1368
+ const cspNonce = validateCspNonce(options.cspNonce);
1369
+ const manifest = options.registry.manifest;
1349
1370
  const signal = options.signal ?? options.request?.signal ?? new AbortController().signal;
1350
1371
  const request = options.request ?? new Request(new URL(options.url, "http://localhost"));
1351
1372
  const runtime = options.dataRuntime ?? createDataRuntime();
@@ -1364,7 +1385,8 @@ async function renderRouteRequestInternal(options) {
1364
1385
  signal,
1365
1386
  dataRuntime: runtime,
1366
1387
  queryPrefetch: prefetch,
1367
- mode: "ssr"
1388
+ mode: "ssr",
1389
+ cspNonce
1368
1390
  });
1369
1391
  return withTelemetry(options.telemetry?.ssrRender, {}, () => withRenderContextAsync(context, async () => {
1370
1392
  const resolved = await resolveRouteRequest(options.url, {
@@ -1395,7 +1417,7 @@ async function renderRouteRequestInternal(options) {
1395
1417
  const result = {
1396
1418
  kind: "render",
1397
1419
  html,
1398
- ...boundaries.length > 0 ? { stream: createDeferredRenderStream(html, boundaries, signal, options.seed, context.hydrationData, runtime) } : {},
1420
+ ...boundaries.length > 0 ? { stream: createDeferredRenderStream(html, boundaries, signal, options.seed, context.hydrationData, runtime, cspNonce) } : {},
1399
1421
  params: resolved.params
1400
1422
  };
1401
1423
  if (resolved.record) Object.defineProperty(result, "record", {