@askrjs/askr 0.0.84 → 0.0.85

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 (64) hide show
  1. package/dist/{access-ePqdQqkV.js → access-Dpfoi4cA.js} +7 -1
  2. package/dist/actions/index.d.ts +1 -1
  3. package/dist/actions/index.js +1 -1
  4. package/dist/{activity-pySy9t7Y.d.ts → activity-B1I5HJQI.d.ts} +1 -1
  5. package/dist/{activity-CZiPgZy0.js → activity-Jd9CgEa3.js} +52 -15
  6. package/dist/{authoring-DQPG0VAm.js → authoring-DdQ3pHqt.js} +6 -3
  7. package/dist/benchmark.js +8 -8
  8. package/dist/boot/index.d.ts +3 -3
  9. package/dist/boot/index.js +1 -1
  10. package/dist/{boot-D28lesMw.js → boot-DWe880Et.js} +16 -15
  11. package/dist/{cleanup-ARiXproi.js → cleanup-c837KVij.js} +16 -6
  12. package/dist/{component-cleanup-Bug5tSiG.js → component-cleanup-BUfUleGZ.js} +2 -2
  13. package/dist/{component-internal-Bw4Mf9fd.js → component-internal-DcrLymUJ.js} +5 -5
  14. package/dist/components/index.d.ts +1 -1
  15. package/dist/components/index.js +1 -1
  16. package/dist/control/index.d.ts +1 -1
  17. package/dist/control/index.js +1 -1
  18. package/dist/{control-Y8F73Uln.d.ts → control-DhUZU4_V.d.ts} +2 -1
  19. package/dist/{control-nrS65oG3.js → control-oLADku43.js} +4 -4
  20. package/dist/{csp-nonce-ZTlD_EnK.js → csp-nonce-Bc52OIVc.js} +19 -2
  21. package/dist/data/index.js +1 -1
  22. package/dist/{data-BRS5woEh.js → data-Dkqb8_QP.js} +3 -3
  23. package/dist/{deferred-oqtAJ4iH.js → deferred-vUOy-awa.js} +198 -16
  24. package/dist/{effect-B487asyz.js → effect-lnxQIpJG.js} +2 -2
  25. package/dist/{fastlane-BOr4lSLl.js → fastlane-CrfB3QG0.js} +2 -2
  26. package/dist/{for-internal-DjpV8ioj.js → for-internal-B_mnQhan.js} +18 -6
  27. package/dist/foundations/index.d.ts +1 -1
  28. package/dist/foundations/index.js +2 -2
  29. package/dist/foundations/state/index.d.ts +1 -1
  30. package/dist/foundations/state/index.js +1 -1
  31. package/dist/foundations/structures/index.d.ts +2 -2
  32. package/dist/foundations/structures/index.js +3 -3
  33. package/dist/fx/index.js +1 -1
  34. package/dist/{index-BApH3laU.d.ts → index-Bkh9S9-t.d.ts} +6 -2
  35. package/dist/{index-_UN08Pg1.d.ts → index-pIgGaXvS.d.ts} +19 -3
  36. package/dist/{index-DUXXZ31H.d.ts → index-r-nt13FE.d.ts} +1 -1
  37. package/dist/index.d.ts +3 -3
  38. package/dist/index.js +10 -10
  39. package/dist/{lifecycle-batch-CFI4NKpJ.js → lifecycle-batch-Dfpid9-A.js} +39 -20
  40. package/dist/{lifecycle-operations-KYOIcM5R.js → lifecycle-operations-BrYrBsXY.js} +1 -1
  41. package/dist/{navigate-CgVIrrSs.d.ts → navigate-NyIjQUwI.d.ts} +1 -1
  42. package/dist/{navigate-Dr3cjOSz.js → navigate-b4GGxO_l.js} +15 -14
  43. package/dist/{portal-pHBoqwYd.js → portal-BVWjAhNQ.js} +5 -5
  44. package/dist/{readable-_GQGe_St.js → readable-B5NtV7V0.js} +1 -1
  45. package/dist/{renderer-B9j5IV1q.js → renderer-CZzNtoj2.js} +57 -16
  46. package/dist/resources/index.d.ts +2 -2
  47. package/dist/resources/index.js +5 -5
  48. package/dist/{route-matching-IfQZmqkN.js → route-matching-DHduNiGk.js} +49 -6
  49. package/dist/router/index.d.ts +7 -7
  50. package/dist/router/index.js +9 -7
  51. package/dist/{selector-DJ1-N1K-.js → selector-Ck_Pp9av.js} +2 -2
  52. package/dist/ssg/index.d.ts +9 -3
  53. package/dist/ssg/index.js +30 -15
  54. package/dist/ssr/index.d.ts +7 -3
  55. package/dist/ssr/index.js +1 -1
  56. package/dist/{ssr-CtC4lChT.js → ssr-CpiBHMNv.js} +29 -18
  57. package/dist/ssr-DSHd_Q9K.js +25 -0
  58. package/dist/{state-BzIMC6-i.js → state-DCjONcHK.js} +4 -3
  59. package/dist/{structures-D3vO-WMN.js → structures-DSLF_iis.js} +4 -2
  60. package/dist/testing/index.d.ts +2 -2
  61. package/dist/testing/index.js +3 -3
  62. package/dist/{verify-hydration-BguOSco9.js → verify-hydration-C3QBBQqR.js} +2 -2
  63. package/package.json +1 -1
  64. package/dist/ssr-CbQO5xd3.js +0 -12
package/dist/ssg/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import "../access-ePqdQqkV.js";
2
- import { C as _preloadRouteHandler, S as getRenderHandler, a as resolveDeferredValues, l as createRouteRegistry, u as bindResolvedRouteData } from "../deferred-oqtAJ4iH.js";
3
- import { a as route } from "../authoring-DQPG0VAm.js";
4
- import { n as renderDocument } from "../ssr-CbQO5xd3.js";
5
- import { n as renderToString } from "../ssr-CtC4lChT.js";
1
+ import "../access-Dpfoi4cA.js";
2
+ import { D as _preloadRouteHandler, E as getRenderHandler, a as resolveDeferredValues, g as prepareRouteHydrationData, l as createRouteRegistry, u as bindResolvedRouteData } from "../deferred-vUOy-awa.js";
3
+ import { o as addRouteBasePath } from "../route-matching-DHduNiGk.js";
4
+ import { a as route } from "../authoring-DdQ3pHqt.js";
5
+ import { n as renderDocument } from "../ssr-DSHd_Q9K.js";
6
+ import { n as renderToString } from "../ssr-CpiBHMNv.js";
6
7
  import * as fs from "node:fs/promises";
7
8
  import * as pathModule from "node:path";
8
9
  import * as os from "node:os";
@@ -141,17 +142,21 @@ function validateRoutes(routes) {
141
142
  * Render multiple routes in parallel with error handling
142
143
  */
143
144
  async function batchRenderRoutes(routes, options = {}) {
144
- const { seed = 12345, dataMap = {}, concurrency = 1, document } = options;
145
+ const { seed = 12345, dataMap = {}, concurrency = 1, document, styleRegistrationValidation = "warn" } = options;
145
146
  const workerCount = Math.max(1, Math.min(concurrency, routes.length || 1));
146
147
  const results = [];
147
148
  results.length = routes.length;
148
149
  let nextIndex = 0;
149
- const sharedRegistry = new Set(routes.map((route) => route.path)).size === routes.length ? createRouteRegistry(() => {
150
+ const hasUniquePaths = new Set(routes.map((route) => route.path)).size === routes.length;
151
+ const basePaths = new Set(routes.map((route) => route.basePath ?? ""));
152
+ const sharedBasePath = basePaths.size === 1 ? routes[0]?.basePath : void 0;
153
+ const sharedRegistry = hasUniquePaths && basePaths.size <= 1 ? createRouteRegistry(() => {
150
154
  for (const route$1 of routes) route(route$1.path, route$1.handler, { namespace: route$1.namespace });
151
- }) : void 0;
155
+ }, { basePath: sharedBasePath }) : void 0;
152
156
  const renderOne = async (route$2) => {
153
157
  const startTime = performance.now();
154
158
  const url = interpolateRoutePath(route$2.path, route$2.params);
159
+ const publicUrl = addRouteBasePath(url, route$2.basePath ?? "");
155
160
  const requestUrl = new URL(url, "http://localhost");
156
161
  const resolvedData = resolveSsgRouteData(dataMap, route$2.path, url);
157
162
  const baseData = resolvedData.hasData ? resolvedData.data : void 0;
@@ -161,6 +166,7 @@ async function batchRenderRoutes(routes, options = {}) {
161
166
  try {
162
167
  await _preloadRouteHandler(mergedHandler);
163
168
  let routeData;
169
+ let routeHydration;
164
170
  let hasRouteData = false;
165
171
  if (route$2.loader) {
166
172
  const controller = new AbortController();
@@ -179,24 +185,30 @@ async function batchRenderRoutes(routes, options = {}) {
179
185
  },
180
186
  signal: controller.signal
181
187
  };
188
+ const request = new Request(requestUrl);
182
189
  const loaded = await route$2.loader({
183
190
  ...loadContext,
184
- request: new Request(requestUrl)
191
+ request
185
192
  });
186
193
  await resolveDeferredValues(loaded, controller.signal);
187
194
  routeData = loaded;
195
+ routeHydration = prepareRouteHydrationData(loaded, route$2.dehydrate, {
196
+ ...loadContext,
197
+ request
198
+ }, url);
188
199
  hasRouteData = true;
189
200
  }
190
- const renderedHandler = hasRouteData ? bindResolvedRouteData(mergedHandler, routeData) : mergedHandler;
201
+ const renderedHandler = hasRouteData ? bindResolvedRouteData(mergedHandler, routeData, routeHydration) : mergedHandler;
191
202
  const registry = hasRouteData || !sharedRegistry ? createRouteRegistry(() => {
192
203
  route(route$2.path, renderedHandler, { namespace: route$2.namespace });
193
- }) : sharedRegistry;
204
+ }, { basePath: route$2.basePath }) : sharedRegistry;
194
205
  phase = "render";
195
206
  const html = renderToString({
196
- url,
207
+ url: publicUrl,
197
208
  registry,
198
209
  seed,
199
210
  data: baseData,
211
+ styleRegistrationValidation: "off",
200
212
  document: document === void 0 ? void 0 : ({ appHtml, context }) => renderDocument(document, {
201
213
  appHtml,
202
214
  context: {
@@ -215,7 +227,7 @@ async function batchRenderRoutes(routes, options = {}) {
215
227
  cspNonce: context.cspNonce,
216
228
  styles: context.styles
217
229
  }
218
- }, "createStaticGen()")
230
+ }, "createStaticGen()", styleRegistrationValidation)
219
231
  });
220
232
  const duration = performance.now() - startTime;
221
233
  return {
@@ -632,7 +644,9 @@ function routeRegistryToRouteConfigs(registry) {
632
644
  auth: options.auth,
633
645
  policies: options.policies,
634
646
  entries: options.entries,
635
- loader: options.loader
647
+ loader: options.loader,
648
+ dehydrate: options.dehydrate,
649
+ basePath: registry.manifest.basePath
636
650
  });
637
651
  }
638
652
  return routeConfigs;
@@ -766,7 +780,8 @@ function createStaticGen(options) {
766
780
  seed,
767
781
  dataMap,
768
782
  concurrency: resolvedConcurrency,
769
- document: options.document
783
+ document: options.document,
784
+ styleRegistrationValidation: options.styleRegistrationValidation
770
785
  }) : [];
771
786
  performance.now() - renderStartTime;
772
787
  const renderedByRouteId = /* @__PURE__ */ new Map();
@@ -1,6 +1,6 @@
1
- import { f as DocumentRenderArgs, g as SSRStyleRegistration, h as SSRData, m as DocumentRenderer, p as DocumentRenderContext } from "../control-Y8F73Uln.js";
1
+ import { _ as SSRStyleRegistrationValidation, f as DocumentRenderArgs, g as SSRStyleRegistration, h as SSRData, m as DocumentRenderer, p as DocumentRenderContext } from "../control-DhUZU4_V.js";
2
2
  import { r as JSXElement, s as Props } from "../jsx-Dvr2SGRG.js";
3
- import { A as RouteHandler, C as Route, J as RouteRequestResult, V as RouteRecord, W as RouteRegistry, g as AccessRedirectDecision, l as DeferredBoundaryRegistration, m as AccessDenyDecision, u as SSRPortalState, w as RouteAuthOptions } from "../index-_UN08Pg1.js";
3
+ import { A as RouteHandler, C as Route, J as RouteRequestResult, V as RouteRecord, W as RouteRegistry, g as AccessRedirectDecision, l as DeferredBoundaryRegistration, m as AccessDenyDecision, u as SSRPortalState, w as RouteAuthOptions } from "../index-pIgGaXvS.js";
4
4
  import { D as QueryPrefetchContext, _ as CoreTelemetry, n as ServerQueryRegistry, v as DataRuntime } from "../index-5S-fi2xy.js";
5
5
  import { AuthContext } from "@askrjs/auth";
6
6
  //#region src/common/page-render-envelope.d.ts
@@ -29,6 +29,7 @@ interface RenderContext {
29
29
  params?: Record<string, string>;
30
30
  routes?: readonly Route[];
31
31
  routeAuth?: RouteAuthOptions;
32
+ basePath?: string;
32
33
  authContext?: AuthContext;
33
34
  signal?: AbortSignal;
34
35
  dataRuntime?: unknown;
@@ -51,6 +52,7 @@ declare function createRenderContext(seed?: number, opts?: {
51
52
  params?: Record<string, string>;
52
53
  routes?: readonly Route[];
53
54
  routeAuth?: RouteAuthOptions;
55
+ basePath?: string;
54
56
  signal?: AbortSignal;
55
57
  dataRuntime?: unknown;
56
58
  mode?: 'ssr' | 'spa';
@@ -92,6 +94,8 @@ type RouteRenderOptions = SSRRouteSource & {
92
94
  /** @internal Precomposed page state used by hydration verification. */
93
95
  envelope?: PageRenderEnvelope;
94
96
  cspNonce?: string;
97
+ /** Diagnose document renderers that omit request-local SSR style registrations. */
98
+ styleRegistrationValidation?: SSRStyleRegistrationValidation;
95
99
  };
96
100
  type RouteStreamOptions = RouteRenderOptions & {
97
101
  onChunk(html: string): void;
@@ -185,4 +189,4 @@ declare function renderToString(component: (props?: Record<string, unknown>) =>
185
189
  declare function renderToString(opts: RouteRenderOptions): string;
186
190
  declare function renderToStream(opts: RouteStreamOptions): void;
187
191
  //#endregion
188
- export { type DocumentRenderArgs, type DocumentRenderContext, type DocumentRenderer, type RenderRouteRequestOptions, type RenderRouteRequestResult, type SSRComponent, SSRDataMissingError, type SSRRoute, type SSRStyleRegistration, type VNode, createRenderContext, getRenderContext, renderResolvedToStringSync, renderRouteRequest, renderRouteRequestToString, renderToStream, renderToString, renderToStringSync, resolveRequest, withRenderContext, withRenderContextAsync };
192
+ 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 };
package/dist/ssr/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { d as SSRDataMissingError } from "../render-context-D-DFk2WN.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-CtC4lChT.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-CpiBHMNv.js";
3
3
  export { SSRDataMissingError, createRenderContext, getRenderContext, renderResolvedToStringSync, renderRouteRequest, renderRouteRequestToString, renderToStream, renderToString, renderToStringSync, resolveRequest, withRenderContext, withRenderContextAsync };
@@ -1,23 +1,23 @@
1
1
  import { t as __CONTROL_BOUNDARY__ } from "./control-C-ApnFs1.js";
2
2
  import { t as __ERROR_BOUNDARY__ } from "./vnode-D24p6IW2.js";
3
- import { v as logger } from "./access-ePqdQqkV.js";
4
- import { i as isFragmentType, n as Fragment, t as ELEMENT_TYPE } from "./jsx-C3IECePB.js";
5
- import { f as getExecutionContextFrame, h as markVNodeTreeWithContextFrame, l as callWithContext, n as createComponentInstance, p as getVNodeContextFrame } from "./component-internal-Bw4Mf9fd.js";
3
+ import { v as logger } from "./access-Dpfoi4cA.js";
6
4
  import { f as getCurrentComponentInstance, w as setCurrentComponentInstance } from "./component-scope-DzJEbYGE.js";
7
- import { t as cleanupComponent } from "./component-cleanup-Bug5tSiG.js";
8
- import { p as isPromiseLike } from "./lifecycle-batch-CFI4NKpJ.js";
9
- import { _ as setControlBoundaryContextFrame, g as evaluateShowState, h as evaluateCaseState, i as evaluateForState, o as rollbackForStateTransaction, r as commitForStateTransaction } from "./for-internal-DjpV8ioj.js";
10
- import { _ as isPageRenderEnvelope, g as isEmptyPageRenderEnvelope, h as createPageRenderEnvelope, i as isDeferred, l as createRouteRegistry, m as resolveRouteRequest, t as DEFERRED_BOUNDARY } from "./deferred-oqtAJ4iH.js";
5
+ import { i as isFragmentType, n as Fragment, t as ELEMENT_TYPE } from "./jsx-C3IECePB.js";
6
+ import { f as getExecutionContextFrame, h as markVNodeTreeWithContextFrame, l as callWithContext, n as createComponentInstance, p as getVNodeContextFrame } from "./component-internal-DcrLymUJ.js";
7
+ import { t as cleanupComponent } from "./component-cleanup-BUfUleGZ.js";
8
+ import { p as isPromiseLike } from "./lifecycle-batch-Dfpid9-A.js";
9
+ import { _ as setControlBoundaryContextFrame, g as evaluateShowState, h as evaluateCaseState, i as evaluateForState, o as rollbackForStateTransaction, r as commitForStateTransaction } from "./for-internal-B_mnQhan.js";
10
+ import { _ as validateRouteHydrationData, b as isEmptyPageRenderEnvelope, h as getRouteHydrationMetadata, i as isDeferred, l as createRouteRegistry, m as resolveRouteRequest, t as DEFERRED_BOUNDARY, x as isPageRenderEnvelope, y as createPageRenderEnvelope } from "./deferred-vUOy-awa.js";
11
11
  import { d as SSRDataMissingError, l as stopRenderPhase$1, s as startRenderPhase$1, t as configureRenderContextProvider } from "./render-context-D-DFk2WN.js";
12
- import { a as resolveRouteFromRoutes, t as _resolveRouteMatchFromRoutes } from "./route-matching-IfQZmqkN.js";
12
+ import { a as resolveRouteFromRoutes, c as removeRouteBasePath, s as normalizeRouteBasePath, t as _resolveRouteMatchFromRoutes } from "./route-matching-DHduNiGk.js";
13
13
  import { n as SSR_PORTAL_HOST, t as SSR_PORTAL_ANCHOR } from "./portal-w3oQ6oQU.js";
14
- import { a as disposeDefaultPortalScope, t as DefaultPortal } from "./portal-pHBoqwYd.js";
14
+ import { a as disposeDefaultPortalScope, t as DefaultPortal } from "./portal-BVWjAhNQ.js";
15
15
  import { n as getPublicAttributeName, t as sanitizeCssValue } from "./css-BuPaTOfe.js";
16
- import { a as isSafeHref, r as validateCspNonce, t as CspNonceScope } from "./csp-nonce-ZTlD_EnK.js";
16
+ import { o as isUnsafeUrlAttribute, r as validateCspNonce, t as CspNonceScope } from "./csp-nonce-Bc52OIVc.js";
17
17
  import { t as createDataRuntime } from "./data-runtime-D68YOo9L.js";
18
18
  import { c as withTelemetry, i as dehydrateDataRuntime, t as createQueryPrefetchContext } from "./query-registry-BL6rjGsO.js";
19
- import { a as route } from "./authoring-DQPG0VAm.js";
20
- import { n as renderDocument, t as SSR_RENDER_DATA_ATTR } from "./ssr-CbQO5xd3.js";
19
+ import { a as route } from "./authoring-DdQ3pHqt.js";
20
+ import { n as renderDocument, t as SSR_RENDER_DATA_ATTR } from "./ssr-DSHd_Q9K.js";
21
21
  //#region src/ssr/escape.ts
22
22
  /**
23
23
  * HTML escaping utilities for SSR
@@ -197,6 +197,7 @@ function createRenderContext(seed = 12345, opts = {}) {
197
197
  params: opts.params,
198
198
  routes: opts.routes,
199
199
  routeAuth: opts.routeAuth,
200
+ basePath: opts.basePath,
200
201
  signal: opts.signal,
201
202
  dataRuntime: opts.dataRuntime ?? createDataRuntime({ queryCache }),
202
203
  mode: opts.mode ?? "ssr",
@@ -307,7 +308,9 @@ function resolvePolicyAwareSSRRoute(opts, routeTable) {
307
308
  let href = opts.url;
308
309
  const visited = /* @__PURE__ */ new Set();
309
310
  for (let redirects = 0; redirects <= MAX_SSR_REDIRECTS; redirects += 1) {
310
- const matched = _resolveRouteMatchFromRoutes(new URL(href, "http://localhost").pathname, routeTable);
311
+ const logicalHref = removeRouteBasePath(href, normalizeRouteBasePath(manifest.basePath));
312
+ if (logicalHref === void 0) throw new Error(`SSR: no route found for url: ${href}`);
313
+ const matched = _resolveRouteMatchFromRoutes(new URL(logicalHref, "http://localhost").pathname, routeTable);
311
314
  if (!matched) throw new Error(`SSR: no route found for url: ${href}`);
312
315
  const resolved = getRouteRequestResultSync(resolveRouteRequest(href, {
313
316
  registry: opts.registry,
@@ -446,13 +449,14 @@ function resolveSSRRouteSource(source) {
446
449
  }));
447
450
  }
448
451
  function resolveSSRRouteRender(opts) {
449
- const { seed = 12345, data, document } = opts;
452
+ const { seed = 12345, data, document, styleRegistrationValidation = "warn" } = opts;
450
453
  const cspNonce = validateCspNonce(opts.cspNonce);
451
454
  const routeTable = resolveSSRRouteSource(opts);
452
455
  const resolvedRoute = resolvePolicyAwareSSRRoute(opts, routeTable);
453
456
  const requestUrl = new URL(resolvedRoute.url, "http://localhost");
454
457
  const ctx = createRenderContext(seed, {
455
458
  url: resolvedRoute.url,
459
+ basePath: opts.registry.manifest.basePath,
456
460
  data,
457
461
  params: resolvedRoute.params,
458
462
  routes: routeTable,
@@ -470,7 +474,8 @@ function resolveSSRRouteRender(opts) {
470
474
  data,
471
475
  ctx,
472
476
  document,
473
- cspNonce
477
+ cspNonce,
478
+ styleRegistrationValidation
474
479
  };
475
480
  }
476
481
  function buildDocumentRenderArgs(resolved, appHtml) {
@@ -514,7 +519,7 @@ function renderToSinkInternal(opts, host) {
514
519
  const appSink = new StringSink();
515
520
  renderResolvedRouteAppToSink(resolved, appSink, host);
516
521
  appSink.end();
517
- sink.write(renderDocument(resolved.document, buildDocumentRenderArgs(resolved, appSink.toString()), "renderToString()/renderToStream()"));
522
+ sink.write(renderDocument(resolved.document, buildDocumentRenderArgs(resolved, appSink.toString()), "renderToString()/renderToStream()", resolved.styleRegistrationValidation));
518
523
  });
519
524
  }
520
525
  function renderRouteToString(opts, host) {
@@ -781,7 +786,7 @@ function renderAttrsDirect(props, sink) {
781
786
  }
782
787
  if (value === false || value === null || value === void 0) continue;
783
788
  const strValue = String(value);
784
- if (attrName.toLowerCase() === "href" && !isSafeHref(strValue)) continue;
789
+ if (isUnsafeUrlAttribute(attrName, strValue)) continue;
785
790
  sink.write(" ");
786
791
  sink.write(attrName);
787
792
  sink.write("=\"");
@@ -816,7 +821,7 @@ function renderAttrs(props, opts) {
816
821
  else if (value === false || value === null || value === void 0) continue;
817
822
  else {
818
823
  const strValue = String(value);
819
- if (attrName.toLowerCase() === "href" && !isSafeHref(strValue)) continue;
824
+ if (isUnsafeUrlAttribute(attrName, strValue)) continue;
820
825
  attrParts.push(` ${attrName}="${getEscapedAttrValue(strValue)}"`);
821
826
  }
822
827
  }
@@ -853,6 +858,8 @@ function serializeHydrationRenderData(data, runtime) {
853
858
  route: current.route,
854
859
  framework: current.framework
855
860
  });
861
+ const routeHydration = getRouteHydrationMetadata(payload.framework);
862
+ if (routeHydration) validateRouteHydrationData(payload.route, routeHydration.r);
856
863
  if (isEmptyPageRenderEnvelope(payload)) return "";
857
864
  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>`;
858
865
  }
@@ -1401,6 +1408,9 @@ async function renderRouteRequestInternal(options) {
1401
1408
  });
1402
1409
  const context = createRenderContext(options.seed, {
1403
1410
  url: options.url,
1411
+ basePath: manifest.basePath,
1412
+ routes: options.registry.routes,
1413
+ routeAuth: options.auth ?? manifest.auth,
1404
1414
  data: options.data,
1405
1415
  framework: options.framework,
1406
1416
  signal,
@@ -1421,6 +1431,7 @@ async function renderRouteRequestInternal(options) {
1421
1431
  });
1422
1432
  if (!resolved) return { kind: "no-match" };
1423
1433
  if (resolved.kind !== "render") return resolved;
1434
+ context.params = resolved.params;
1424
1435
  const sink = new StringSink();
1425
1436
  renderSSRRouteAppToSink({
1426
1437
  route: {
@@ -0,0 +1,25 @@
1
+ //#region src/common/ssr.ts
2
+ function escapedStyleRawText(value) {
3
+ return value.replace(/<\//gi, "<\\/");
4
+ }
5
+ function validateDocumentStyleRegistrations(html, styles, apiName, validation) {
6
+ if (validation === "off" || !styles || styles.length === 0) return;
7
+ const dropped = styles.filter(({ cssText }) => !html.includes(cssText) && !html.includes(escapedStyleRawText(cssText)));
8
+ if (dropped.length === 0) return;
9
+ const registrations = dropped.map(({ id }) => JSON.stringify(id)).join(", ");
10
+ const message = `${apiName} document() dropped ${dropped.length} registered SSR style${dropped.length === 1 ? "" : "s"}: ${registrations}. Serialize context.styles into the returned document, or set styleRegistrationValidation to "off" when omission is intentional.`;
11
+ if (validation === "error") throw new Error(message);
12
+ console.warn(message);
13
+ }
14
+ function renderDocument(document, args, apiName, styleRegistrationValidation = "warn") {
15
+ const html = document(args);
16
+ 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;
18
+ throw new Error(`${apiName} document() must synchronously return a string; received ${received}.`);
19
+ }
20
+ validateDocumentStyleRegistrations(html, args.context.styles, apiName, styleRegistrationValidation);
21
+ return html;
22
+ }
23
+ const SSR_RENDER_DATA_ATTR = "data-askr-render-data";
24
+ //#endregion
25
+ export { renderDocument as n, SSR_RENDER_DATA_ATTR as t };
@@ -1,7 +1,7 @@
1
- import { x as isProductionEnvironment } from "./access-ePqdQqkV.js";
2
- import { t as isBulkCommitActive } from "./fastlane-BOr4lSLl.js";
3
- import { l as notifyReadableReaders, o as markReactivePropsDirtySource, s as markReadableDerivedSubscribersDirty, u as recordReadableRead } from "./readable-_GQGe_St.js";
1
+ import { v as logger, x as isProductionEnvironment } from "./access-Dpfoi4cA.js";
2
+ import { t as isBulkCommitActive } from "./fastlane-CrfB3QG0.js";
4
3
  import { i as claimHookIndex, p as getCurrentInstance } from "./component-scope-DzJEbYGE.js";
4
+ import { l as notifyReadableReaders, o as markReactivePropsDirtySource, s as markReadableDerivedSubscribersDirty, u as recordReadableRead } from "./readable-B5NtV7V0.js";
5
5
  //#region src/runtime/state.ts
6
6
  /**
7
7
  * State primitive for Askr components
@@ -77,6 +77,7 @@ function createStateCell(initialValue, instance) {
77
77
  else newValue = newValueOrUpdater;
78
78
  if (Object.is(value, newValue)) return;
79
79
  if (isBulkCommitActive()) {
80
+ if (!isProductionEnvironment()) logger.warn("[Askr] state.set() was called while a bulk commit (fast-lane reorder) was in progress. The value updated, but subscribers were not notified, so this change will not be reflected in the UI until an unrelated update triggers a re-render. This usually happens from a ref callback or a native focus/blur event fired synchronously during a large keyed-list reorder.");
80
81
  value = newValue;
81
82
  return;
82
83
  }
@@ -5,7 +5,9 @@ function isElement(value) {
5
5
  }
6
6
  function cloneElement(element, props) {
7
7
  return {
8
- ...element,
8
+ $$typeof: element.$$typeof,
9
+ type: element.type,
10
+ key: element.key,
9
11
  props: {
10
12
  ...element.props,
11
13
  ...props
@@ -218,4 +220,4 @@ function createLayer() {
218
220
  * }
219
221
  */
220
222
  //#endregion
221
- export { layout as a, Slot as i, createCollection as n, Presence as r, createLayer as t };
223
+ export { layout as a, Slot as i, createCollection as n, cloneElement as o, Presence as r, isElement as s, createLayer as t };
@@ -1,5 +1,5 @@
1
- import { l as ComponentFunction } from "../control-Y8F73Uln.js";
2
- import { M as RouteMatch, W as RouteRegistry, w as RouteAuthOptions } from "../index-_UN08Pg1.js";
1
+ import { l as ComponentFunction } from "../control-DhUZU4_V.js";
2
+ import { M as RouteMatch, W as RouteRegistry, w as RouteAuthOptions } from "../index-pIgGaXvS.js";
3
3
  import { C as Query, k as QueryStaleReason } from "../index-5S-fi2xy.js";
4
4
  //#region src/testing/render.d.ts
5
5
  interface RenderOptions {
@@ -1,7 +1,7 @@
1
- import { r as flushRuntimeScheduler } from "../access-ePqdQqkV.js";
2
- import { r as computeRouteActivityMatches } from "../route-matching-IfQZmqkN.js";
1
+ import { r as flushRuntimeScheduler } from "../access-Dpfoi4cA.js";
2
+ import { r as computeRouteActivityMatches } from "../route-matching-DHduNiGk.js";
3
3
  import { l as addInvalidationListener } from "../data-runtime-D68YOo9L.js";
4
- import { a as cleanupApp, r as createSPA, t as createIsland } from "../boot-D28lesMw.js";
4
+ import { a as cleanupApp, r as createSPA, t as createIsland } from "../boot-DWe880Et.js";
5
5
  //#region src/testing/render.ts
6
6
  const renderStates = /* @__PURE__ */ new WeakMap();
7
7
  const eventConstructorNames = {
@@ -1,5 +1,5 @@
1
- import { t as SSR_RENDER_DATA_ATTR } from "./ssr-CbQO5xd3.js";
2
- import { a as renderResolvedToStringSync } from "./ssr-CtC4lChT.js";
1
+ import { t as SSR_RENDER_DATA_ATTR } from "./ssr-DSHd_Q9K.js";
2
+ import { a as renderResolvedToStringSync } from "./ssr-CpiBHMNv.js";
3
3
  //#region src/ssr/verify-hydration.ts
4
4
  function normalizeHydrationHtml(html) {
5
5
  const template = document.createElement("template");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askrjs/askr",
3
- "version": "0.0.84",
3
+ "version": "0.0.85",
4
4
  "description": "Actor-backed deterministic UI framework",
5
5
  "keywords": [
6
6
  "askr",
@@ -1,12 +0,0 @@
1
- //#region src/common/ssr.ts
2
- function renderDocument(document, args, apiName) {
3
- const html = document(args);
4
- if (typeof html !== "string") {
5
- 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;
6
- throw new Error(`${apiName} document() must synchronously return a string; received ${received}.`);
7
- }
8
- return html;
9
- }
10
- const SSR_RENDER_DATA_ATTR = "data-askr-render-data";
11
- //#endregion
12
- export { renderDocument as n, SSR_RENDER_DATA_ATTR as t };