@askrjs/askr 0.0.64 → 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.
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-vBQJwHl5.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-CAYo-kNy.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
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-Dz7ZoLja.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
@@ -86,10 +86,6 @@ type SSRRoute = {
86
86
  };
87
87
  type SSRRouteSource = {
88
88
  registry: RouteRegistry;
89
- routes?: readonly SSRRoute[];
90
- } | {
91
- registry?: RouteRegistry;
92
- routes: readonly SSRRoute[];
93
89
  };
94
90
  type RouteRenderOptions = SSRRouteSource & {
95
91
  url: string;
@@ -110,38 +106,6 @@ type RouteStreamOptions = RouteRenderOptions & {
110
106
  declare function resolveRequest(opts: {
111
107
  url: string;
112
108
  registry: RouteRegistry;
113
- manifest?: RouteManifest;
114
- routes?: Array<{
115
- path: string;
116
- handler: RouteHandler;
117
- namespace?: string;
118
- }>;
119
- auth?: RouteAuthOptions;
120
- authContext?: AuthContext;
121
- request?: Request;
122
- signal?: AbortSignal;
123
- } | {
124
- url: string;
125
- manifest: RouteManifest;
126
- registry?: RouteRegistry;
127
- routes?: Array<{
128
- path: string;
129
- handler: RouteHandler;
130
- namespace?: string;
131
- }>;
132
- auth?: RouteAuthOptions;
133
- authContext?: AuthContext;
134
- request?: Request;
135
- signal?: AbortSignal;
136
- } | {
137
- url: string;
138
- manifest?: RouteManifest;
139
- registry?: RouteRegistry;
140
- routes: Array<{
141
- path: string;
142
- handler: RouteHandler;
143
- namespace?: string;
144
- }>;
145
109
  auth?: RouteAuthOptions;
146
110
  authContext?: AuthContext;
147
111
  request?: Request;
@@ -176,11 +140,7 @@ declare function renderToStringSync(component: (props?: Record<string, unknown>)
176
140
  //#region src/ssr/render-resolved.d.ts
177
141
  declare function renderResolvedToStringSync(opts: {
178
142
  url: string;
179
- routes: ReadonlyArray<{
180
- path: string;
181
- handler: RouteHandler;
182
- namespace?: string;
183
- }>;
143
+ registry: RouteRegistry;
184
144
  handler: RouteHandler;
185
145
  params?: Record<string, string>;
186
146
  options?: {
@@ -195,8 +155,7 @@ declare function renderResolvedToStringSync(opts: {
195
155
  //#region src/ssr/route-request-render.d.ts
196
156
  interface RenderRouteRequestOptions {
197
157
  url: string;
198
- manifest?: RouteManifest;
199
- registry?: RouteRegistry;
158
+ registry: RouteRegistry;
200
159
  auth?: RouteAuthOptions;
201
160
  authContext?: AuthContext;
202
161
  request?: Request;
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-CAYo-kNy.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,14 +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";
12
13
  import { r as validateCspNonce, t as CspNonceScope } from "./csp-nonce-C-8E85El.js";
13
14
  import { t as createDataRuntime } from "./data-runtime-SJ1BSUvk.js";
14
15
  import { c as withTelemetry, i as dehydrateDataRuntime, t as createQueryPrefetchContext } from "./query-registry-CQIT4mXr.js";
15
- import { a as resolveRouteFromRoutes, t as _resolveRouteMatchFromRoutes } from "./route-matching-vJpvLVbX.js";
16
- 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-vBQJwHl5.js";
16
+ import { a as resolveRouteFromRoutes, t as _resolveRouteMatchFromRoutes } from "./route-matching-C93To416.js";
17
+ import { a as route } from "./authoring-CXMPffwN.js";
17
18
  import { n as renderDocument, t as SSR_RENDER_DATA_ATTR } from "./ssr-CbQO5xd3.js";
18
19
  //#region src/ssr/escape.ts
19
20
  /**
@@ -489,31 +490,20 @@ var StreamSink = class {
489
490
  //#endregion
490
491
  //#region src/ssr/route-render.ts
491
492
  async function resolveRequest(opts) {
493
+ if (!opts?.registry) throw new TypeError("resolveRequest requires opts.registry.");
492
494
  const { url, auth, authContext, request, signal } = opts;
493
- const manifest = opts.manifest ?? opts.registry?.manifest;
494
- const routes = opts.routes ?? opts.registry?.routes;
495
- if (manifest) return await resolveRouteRequest(url, {
496
- manifest,
495
+ return await resolveRouteRequest(url, {
496
+ manifest: opts.registry.manifest,
497
497
  mode: "ssr",
498
498
  auth,
499
499
  authContext,
500
500
  request,
501
501
  signal
502
502
  });
503
- if (!routes) throw new Error("resolveRequest requires a route manifest or route table.");
504
- const resolved = resolveRouteFromRoutes(new URL(url, "http://localhost").pathname, routes);
505
- if (!resolved) return null;
506
- await _preloadRouteHandler(resolved.handler);
507
- return {
508
- kind: "render",
509
- handler: resolved.handler,
510
- params: resolved.params
511
- };
512
503
  }
513
504
  function resolveSSRRouteSource(source) {
514
- const routes = source.routes ?? source.registry?.routes;
515
- if (!routes || routes.length === 0) throw new Error("SSR requires a route registry or route table.");
516
- 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) => ({
517
507
  ...route,
518
508
  path: route.path,
519
509
  handler: route.handler,
@@ -1245,19 +1235,23 @@ function sameRouteParams(left, right) {
1245
1235
  return true;
1246
1236
  }
1247
1237
  function renderResolvedToStringSync(opts) {
1248
- const { url, routes, handler, params, options } = opts;
1238
+ const { url, registry, handler, params, options } = opts;
1239
+ const routes = registry.routes;
1249
1240
  const requestUrl = new URL(url, "http://localhost");
1250
1241
  const matchedIndex = routes.findIndex((route) => {
1251
1242
  const resolved = resolveRouteFromRoutes(requestUrl.pathname, [route]);
1252
1243
  return resolved !== null && resolved.handler === route.handler && sameRouteParams(resolved.params, params);
1253
1244
  });
1254
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);
1255
1250
  return renderToString({
1256
1251
  url,
1257
- routes: routes.map((route, index) => index === matchedIndex ? {
1258
- ...route,
1259
- handler
1260
- } : route),
1252
+ registry: createRouteRegistry(() => {
1253
+ for (const route$1 of effectiveRoutes) route(route$1.path, route$1.handler, { namespace: route$1.namespace });
1254
+ }),
1261
1255
  seed: options?.seed,
1262
1256
  data: options?.data,
1263
1257
  dataRuntime: options?.dataRuntime,
@@ -1370,9 +1364,9 @@ async function renderRouteRequestToString(options) {
1370
1364
  };
1371
1365
  }
1372
1366
  async function renderRouteRequestInternal(options) {
1367
+ if (!options?.registry) throw new TypeError("renderRouteRequest requires options.registry.");
1373
1368
  const cspNonce = validateCspNonce(options.cspNonce);
1374
- const manifest = options.manifest ?? options.registry?.manifest;
1375
- if (!manifest) throw new Error("renderRouteRequestToString requires a route manifest or registry.");
1369
+ const manifest = options.registry.manifest;
1376
1370
  const signal = options.signal ?? options.request?.signal ?? new AbortController().signal;
1377
1371
  const request = options.request ?? new Request(new URL(options.url, "http://localhost"));
1378
1372
  const runtime = options.dataRuntime ?? createDataRuntime();
@@ -1,5 +1,5 @@
1
1
  import { C as Query, k as QueryStaleReason } from "../index-Bki2rqcr.js";
2
- import { S as RouteMatch, p as Route, x as RouteManifest } from "../router-Dz7ZoLja.js";
2
+ import { N as RouteRegistry, x as RouteMatch } from "../router-eRoaj11J.js";
3
3
 
4
4
  //#region src/testing/index.d.ts
5
5
  type MockRefresh = () => void | Promise<void>;
@@ -17,8 +17,7 @@ interface InvalidationRecorder {
17
17
  stop(): void;
18
18
  }
19
19
  interface MatchRouteOptions {
20
- manifest?: RouteManifest;
21
- routes?: readonly Route[];
20
+ registry: RouteRegistry;
22
21
  }
23
22
  interface RoutePatternWarning {
24
23
  kind: 'route-collision';
@@ -46,7 +45,7 @@ declare const queryState: {
46
45
  pendingWrite: <T extends {}>(data: T, options?: MockQueryOptions) => Query<T>;
47
46
  };
48
47
  declare function createInvalidationRecorder(): InvalidationRecorder;
49
- declare function matchRoute(path: string, options?: MatchRouteOptions): RouteMatch | null;
50
- declare function getRouteWarnings(options?: MatchRouteOptions): RoutePatternWarning[];
48
+ declare function matchRoute(path: string, options: MatchRouteOptions): RouteMatch | null;
49
+ declare function getRouteWarnings(options: MatchRouteOptions): RoutePatternWarning[];
51
50
  //#endregion
52
51
  export { InvalidationRecord, InvalidationRecorder, MockQueryOptions, MockRefresh, RoutePatternWarning, createInvalidationRecorder, getRouteWarnings, matchRoute, mockQuery, queryState };
@@ -1,5 +1,5 @@
1
1
  import { t as addInvalidationListener } from "../invalidation-listeners-Des3AHYs.js";
2
- import { R as parseSegments, r as computeRouteActivityMatches } from "../route-matching-vJpvLVbX.js";
2
+ import { r as computeRouteActivityMatches } from "../route-matching-C93To416.js";
3
3
  //#region src/testing/index.ts
4
4
  function normalizeRefresh(options) {
5
5
  return async () => {
@@ -114,20 +114,17 @@ function createInvalidationRecorder() {
114
114
  }
115
115
  };
116
116
  }
117
- function matchRoute(path, options = {}) {
118
- return computeRouteActivityMatches(path, options)[0] ?? null;
117
+ function matchRoute(path, options) {
118
+ if (!options?.registry) throw new TypeError("matchRoute requires options.registry.");
119
+ return computeRouteActivityMatches(path, { manifest: options.registry.manifest })[0] ?? null;
119
120
  }
120
121
  function getRoutePatternRecords(options) {
121
- if (options.manifest) return options.manifest.records.map((record) => ({
122
+ if (!options?.registry) throw new TypeError("getRouteWarnings requires options.registry.");
123
+ return options.registry.manifest.records.map((record) => ({
122
124
  path: record.path,
123
125
  segments: record.segments,
124
126
  namespace: record.options.namespace
125
127
  }));
126
- return (options.routes ?? []).map((route) => ({
127
- path: route.path,
128
- segments: parseSegments(route.path),
129
- namespace: route.namespace
130
- }));
131
128
  }
132
129
  function routePrefixMatches(splatPrefix, routeSegments) {
133
130
  if (routeSegments.length <= splatPrefix.length) return false;
@@ -138,7 +135,7 @@ function routePrefixMatches(splatPrefix, routeSegments) {
138
135
  }
139
136
  return true;
140
137
  }
141
- function getRouteWarnings(options = {}) {
138
+ function getRouteWarnings(options) {
142
139
  const records = getRoutePatternRecords(options);
143
140
  const warnings = [];
144
141
  for (const record of records) {
@@ -1,5 +1,5 @@
1
1
  import { t as SSR_RENDER_DATA_ATTR } from "./ssr-CbQO5xd3.js";
2
- import { a as renderResolvedToStringSync } from "./ssr-CAYo-kNy.js";
2
+ import { a as renderResolvedToStringSync } from "./ssr-C0hzqhY8.js";
3
3
  //#region src/ssr/verify-hydration.ts
4
4
  function normalizeHydrationHtml(html) {
5
5
  const template = document.createElement("template");
@@ -8,10 +8,10 @@ function normalizeHydrationHtml(html) {
8
8
  return template.innerHTML.replace(/<!--[\s\S]*?-->/g, "");
9
9
  }
10
10
  function verifyHydrationSyncForUrl(opts) {
11
- const { root, url, routes, resolved, options } = opts;
11
+ const { root, url, registry, resolved, options } = opts;
12
12
  const expected = renderResolvedToStringSync({
13
13
  url,
14
- routes,
14
+ registry,
15
15
  handler: resolved.handler,
16
16
  params: resolved.params,
17
17
  options
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askrjs/askr",
3
- "version": "0.0.64",
3
+ "version": "0.0.65",
4
4
  "description": "Actor-backed deterministic UI framework",
5
5
  "keywords": [
6
6
  "askr",