netjes 0.0.2 → 0.0.4

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 (160) hide show
  1. package/README.md +13 -11
  2. package/cli/agents.mjs +25 -2
  3. package/cli/commands.mjs +56 -6
  4. package/cli/help.mjs +7 -2
  5. package/cli/info.mjs +275 -33
  6. package/cli/routes.mjs +35 -8
  7. package/cli/scaffold.mjs +31 -4
  8. package/dist/actions.d.ts +7 -2
  9. package/dist/actions.d.ts.map +1 -1
  10. package/dist/actions.js +9 -3
  11. package/dist/actions.js.map +1 -1
  12. package/dist/client-entry.d.ts +1 -0
  13. package/dist/client-entry.d.ts.map +1 -1
  14. package/dist/client-entry.js +19 -2
  15. package/dist/client-entry.js.map +1 -1
  16. package/dist/deferred.d.ts +11 -0
  17. package/dist/deferred.d.ts.map +1 -1
  18. package/dist/deferred.js +15 -1
  19. package/dist/deferred.js.map +1 -1
  20. package/dist/document.d.ts.map +1 -1
  21. package/dist/document.js +10 -1
  22. package/dist/document.js.map +1 -1
  23. package/dist/errors.d.ts +7 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +11 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/form.d.ts +5 -5
  28. package/dist/form.d.ts.map +1 -1
  29. package/dist/form.js +5 -2
  30. package/dist/form.js.map +1 -1
  31. package/dist/href.d.ts +31 -3
  32. package/dist/href.d.ts.map +1 -1
  33. package/dist/href.js +131 -10
  34. package/dist/href.js.map +1 -1
  35. package/dist/image.d.ts +3 -3
  36. package/dist/image.d.ts.map +1 -1
  37. package/dist/image.js.map +1 -1
  38. package/dist/index.d.ts +3 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/link.d.ts +15 -7
  43. package/dist/link.d.ts.map +1 -1
  44. package/dist/link.js +38 -7
  45. package/dist/link.js.map +1 -1
  46. package/dist/metadata.d.ts +8 -2
  47. package/dist/metadata.d.ts.map +1 -1
  48. package/dist/metadata.js +14 -5
  49. package/dist/metadata.js.map +1 -1
  50. package/dist/modules.d.ts +15 -1
  51. package/dist/modules.d.ts.map +1 -1
  52. package/dist/modules.js.map +1 -1
  53. package/dist/mounted.d.ts +55 -0
  54. package/dist/mounted.d.ts.map +1 -0
  55. package/dist/mounted.js +110 -0
  56. package/dist/mounted.js.map +1 -0
  57. package/dist/navigation-focus.d.ts +38 -0
  58. package/dist/navigation-focus.d.ts.map +1 -0
  59. package/dist/navigation-focus.js +71 -0
  60. package/dist/navigation-focus.js.map +1 -0
  61. package/dist/payload.d.ts +8 -0
  62. package/dist/payload.d.ts.map +1 -1
  63. package/dist/payload.js +28 -0
  64. package/dist/payload.js.map +1 -1
  65. package/dist/query.d.ts +5 -2
  66. package/dist/query.d.ts.map +1 -1
  67. package/dist/query.js +11 -8
  68. package/dist/query.js.map +1 -1
  69. package/dist/render-document.d.ts +74 -0
  70. package/dist/render-document.d.ts.map +1 -0
  71. package/dist/render-document.js +393 -0
  72. package/dist/render-document.js.map +1 -0
  73. package/dist/route-announcer.d.ts +18 -0
  74. package/dist/route-announcer.d.ts.map +1 -0
  75. package/dist/route-announcer.js +58 -0
  76. package/dist/route-announcer.js.map +1 -0
  77. package/dist/route-tree.d.ts +6 -2
  78. package/dist/route-tree.d.ts.map +1 -1
  79. package/dist/route-tree.js +17 -7
  80. package/dist/route-tree.js.map +1 -1
  81. package/dist/router.d.ts +28 -5
  82. package/dist/router.d.ts.map +1 -1
  83. package/dist/router.js +71 -26
  84. package/dist/router.js.map +1 -1
  85. package/dist/script.d.ts +28 -5
  86. package/dist/script.d.ts.map +1 -1
  87. package/dist/script.js +192 -21
  88. package/dist/script.js.map +1 -1
  89. package/dist/server-render.d.ts.map +1 -1
  90. package/dist/server-render.js +4 -1
  91. package/dist/server-render.js.map +1 -1
  92. package/dist/testing-vitest.d.ts +8 -0
  93. package/dist/testing-vitest.d.ts.map +1 -0
  94. package/dist/testing-vitest.js +26 -0
  95. package/dist/testing-vitest.js.map +1 -0
  96. package/dist/testing.d.ts +17 -1
  97. package/dist/testing.d.ts.map +1 -1
  98. package/dist/testing.js +18 -3
  99. package/dist/testing.js.map +1 -1
  100. package/dist/zod-jitless.d.ts +2 -0
  101. package/dist/zod-jitless.d.ts.map +1 -0
  102. package/dist/zod-jitless.js +4 -0
  103. package/dist/zod-jitless.js.map +1 -0
  104. package/package.json +1 -1
  105. package/sidecar/server.mjs +109 -15
  106. package/skills/netjes/SKILL.md +15 -7
  107. package/skills/netjes/references/caching-and-streaming.md +37 -4
  108. package/skills/netjes/references/data-and-actions.md +15 -7
  109. package/skills/netjes/references/deployment.md +7 -3
  110. package/skills/netjes/references/routing.md +32 -9
  111. package/skills/netjes/references/testing.md +23 -7
  112. package/src/actions.tsx +9 -3
  113. package/src/client-entry.tsx +20 -2
  114. package/src/deferred.ts +14 -1
  115. package/src/document.tsx +22 -3
  116. package/src/errors.ts +12 -0
  117. package/src/form.tsx +10 -7
  118. package/src/href.ts +137 -11
  119. package/src/image.tsx +3 -3
  120. package/src/index.ts +19 -1
  121. package/src/link.tsx +47 -13
  122. package/src/metadata.tsx +19 -6
  123. package/src/modules.ts +15 -2
  124. package/src/mounted.tsx +160 -0
  125. package/src/navigation-focus.ts +75 -0
  126. package/src/payload.ts +32 -0
  127. package/src/query.tsx +14 -8
  128. package/src/render-document.tsx +483 -0
  129. package/src/route-announcer.tsx +69 -0
  130. package/src/route-tree.tsx +17 -6
  131. package/src/router.tsx +116 -31
  132. package/src/script.tsx +214 -23
  133. package/src/server-render.tsx +4 -1
  134. package/src/testing-vitest.ts +37 -0
  135. package/src/testing.tsx +38 -5
  136. package/src/virtual.d.ts +8 -1
  137. package/src/zod-jitless.ts +15 -0
  138. package/template/.dockerignore +3 -0
  139. package/template/Dockerfile +11 -1
  140. package/template/README.md +11 -7
  141. package/template/_AGENTS.md +38 -9
  142. package/template/__NAME__.csproj +2 -0
  143. package/template/app/document.test.ts +29 -0
  144. package/template/app/error.tsx +3 -2
  145. package/template/app/layout.tsx +10 -1
  146. package/template/docker-compose.override.yml +4 -3
  147. package/template/docker-compose.prod.yml +2 -1
  148. package/template/e2e/home.spec.ts +32 -0
  149. package/template/generated/netjes.ts +43 -14
  150. package/template/package.json +4 -1
  151. package/template/playwright.config.ts +36 -0
  152. package/template/tests/__NAME__.Tests/AppFactory.cs +31 -0
  153. package/template/tests/__NAME__.Tests/HomePageTests.cs +55 -0
  154. package/template/tests/__NAME__.Tests/__NAME__.Tests.csproj +30 -0
  155. package/template/tsconfig.app.json +20 -0
  156. package/template/tsconfig.json +2 -17
  157. package/template/tsconfig.node.json +8 -0
  158. package/vite/packages.mjs +345 -0
  159. package/vite/plugin.d.ts +16 -1
  160. package/vite/plugin.mjs +224 -34
package/dist/query.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import type { InitialPayload, Params } from './payload.ts';
2
+ /** What {@link renderDocument} renders a page with: what the server would send with it. */
3
+ export type RenderDocumentOptions = {
4
+ /** The page's props, as its C# loader sends them. A Promise anywhere in them is a `Page.Defer` value. */
5
+ props?: Record<string, unknown>;
6
+ /** The route values, as `useParams()` returns them: a string per segment, an array per catch-all. Default none. */
7
+ params?: Params;
8
+ /** The page's URL, its path and query. Default `/`. */
9
+ url?: string;
10
+ /**
11
+ * The props of each layout's C# layout loader, by the layout's file, such as `app/blog/layout.tsx`. A Promise in
12
+ * them is a `Page.Defer` value. A layout that is not named here gets none.
13
+ */
14
+ layouts?: Record<string, Record<string, unknown>>;
15
+ /** What the server sends as the shared props (`UseSharedProps`). Default `null`. */
16
+ shared?: unknown;
17
+ /**
18
+ * The page's status. Default 200, or the status the server gives the file: 404 for a not-found file, 403 for a
19
+ * forbidden one, 401 for an unauthorized one and 500 for an error or global-error one.
20
+ */
21
+ status?: number;
22
+ /** A Content-Security-Policy nonce, which goes on every script and stylesheet, as for a policy with `{nonce}`. */
23
+ nonce?: string;
24
+ /** The `lang` of `<html>`. Default `en`, as `NetjesOptions.Lang`. */
25
+ lang?: string;
26
+ /** What `usePublicConfig()` reads, as the `Netjes:PublicConfig` section. */
27
+ publicConfig?: Record<string, unknown>;
28
+ /**
29
+ * The page packages the app mounts, by npm name, each at its prefix as `MapPagePackage` takes it:
30
+ * `{ '@acme/help-center': '/(marketing)/help' }`. Their files in the pages map go into the app's folders under the
31
+ * prefix, so an app page in a package's folder renders inside the package's layouts, and the payload's `mounts` gives
32
+ * each one's URL for the page's `params`. A package that `netjes({ packages })` does not list has its pages in `app`.
33
+ */
34
+ mounts?: Record<string, string>;
35
+ /**
36
+ * The page files, keyed `/app/...` as `import.meta.glob` keys them, and a page package's `/<npm name>/<its pages
37
+ * folder>/...`. Default: the app's and the listed packages', from the `netjes()` plugin.
38
+ */
39
+ modules?: Record<string, () => Promise<unknown>>;
40
+ /** Stops the render, which then rejects with the signal's reason: for a page that waits on a Promise that never settles. */
41
+ signal?: AbortSignal;
42
+ };
43
+ /** The options {@link documentPayload} reads, with any Promise in the props already a placeholder. */
44
+ type DocumentOptions = Omit<RenderDocumentOptions, 'modules' | 'signal'>;
45
+ /**
46
+ * The payload the server sends with the document of `page`, a file of the pages map named without its leading slash,
47
+ * for the values in `options`: the route, kind, status and segments by the server's rules, and a build with no
48
+ * stylesheets or scripts. The files of the page packages `options.mounts` names go under their prefixes, with their
49
+ * pages folders from `packages`. Throws for a file it cannot render: one not in `files`, a layout, a page in a private
50
+ * folder or under a parallel route slot, or a file of a package it does not mount.
51
+ */
52
+ export declare function documentPayload(page: string, options: DocumentOptions, files: readonly string[], appDir: string, packages?: readonly {
53
+ name: string;
54
+ pages: string;
55
+ }[]): InitialPayload;
56
+ /**
57
+ * Renders a page's whole document, from `<!DOCTYPE html>` to `</html>`, as the Node sidecar renders it for a crawler:
58
+ * the page from `page`, a file of the pages map such as `app/blog/[slug]/page.tsx`, inside the layouts the server
59
+ * would wrap it in, with the head, Netjes's inline scripts and the payload. It waits for every Suspense boundary, and
60
+ * a Promise in the props or in a layout's props is a `Page.Defer` value: rendered in place once it resolves, left as its
61
+ * Suspense fallback when it rejects. The build's stylesheets and scripts, development styles and an antiforgery token
62
+ * are left out, and no C# runs: the props come from `options`. Runs in Vitest's node environment, with the `netjes()`
63
+ * plugin, which provides the pages map, the app's folder and the query shell, also when `modules` is given.
64
+ */
65
+ export declare function renderDocument(page: string, options?: RenderDocumentOptions): Promise<string>;
66
+ /**
67
+ * The hash-sources, `'sha256-…'` in their quotes, of the inline scripts in `html` that a browser runs and checks
68
+ * against a Content-Security-Policy's script sources: each script element without `src` whose type a browser runs
69
+ * (none, a JavaScript type, `module`, `importmap` or `speculationrules`), with text. Each hash is listed once, in the
70
+ * order of the first script with it. Data blocks such as the page payload (`application/json`) are left out.
71
+ */
72
+ export declare function inlineScriptHashes(html: string): Promise<string[]>;
73
+ export {};
74
+ //# sourceMappingURL=render-document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-document.d.ts","sourceRoot":"","sources":["../src/render-document.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAY,MAAM,EAAc,MAAM,cAAc,CAAC;AAEjF,2FAA2F;AAC3F,MAAM,MAAM,qBAAqB,GAAG;IAClC,yGAAyG;IACzG,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,mHAAmH;IACnH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,oFAAoF;IACpF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kHAAkH;IAClH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,4HAA4H;IAC5H,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,sGAAsG;AACtG,KAAK,eAAe,GAAG,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,QAAQ,CAAC,CAAC;AAiMzE;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAO,GACxD,cAAc,CAkEhB;AAwCD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BvG;AA+DD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAWxE"}
@@ -0,0 +1,393 @@
1
+ // renderDocument and inlineScriptHashes, which netjes/testing exports: a page's whole document, rendered from its
2
+ // props as the Node sidecar renders it for a crawler, and the hashes of the inline scripts in it. The server builds
3
+ // the payload the sidecar renders; documentPayload builds one here from the pages map and the test's options, by the
4
+ // server's rules for the route and the segments (RouteTable and PageRenderer in src/Netjes). The two are checked
5
+ // against the same cases, test/fixtures/segments/cases.json, so a change to either rule fails a suite until both agree.
6
+ import { htmlSafeJson } from './deferred.js';
7
+ /** The files renderDocument renders besides pages, with the kind and the status the server gives them. */
8
+ const BOUNDARIES = new Map([
9
+ ['not-found', { kind: 'notFound', status: 404 }],
10
+ ['forbidden', { kind: 'forbidden', status: 403 }],
11
+ ['unauthorized', { kind: 'unauthorized', status: 401 }],
12
+ ['error', { kind: 'error', status: 500 }],
13
+ ['global-error', { kind: 'error', status: 500 }],
14
+ ]);
15
+ /** The files that make a folder a segment of the pages below it; the payload names the first four. */
16
+ const SEGMENT_FILES = ['layout', 'template', 'loading', 'error', 'not-found', 'forbidden', 'unauthorized'];
17
+ const PAGE_EXTENSION = /\.(?:tsx|jsx)$/i;
18
+ const isGroup = (folder) => folder.length > 2 && folder.startsWith('(') && folder.endsWith(')');
19
+ const isSlot = (folder) => folder.length > 1 && folder.startsWith('@');
20
+ const isPrivate = (folder) => folder.startsWith('_');
21
+ /** UTF-16 code unit order, as the server's ordinal order. */
22
+ const ordinal = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
23
+ /** "a", "a and b", "a, b and c". */
24
+ function list(items) {
25
+ return items.length < 2 ? (items[0] ?? '') : `${items.slice(0, -1).join(', ')} and ${items.at(-1) ?? ''}`;
26
+ }
27
+ const PREFIX_SEGMENT = /^(?:[\p{L}\p{N}._~-]+|\[[A-Za-z_][A-Za-z0-9_]*\]|\([\p{L}\p{N}_-]+\))$/u;
28
+ /** The mounts of `options.mounts`, with their pages folders from the plugin's list; throws for a prefix MapPagePackage refuses. */
29
+ function mountsOf(mounts, packages) {
30
+ return Object.entries(mounts ?? {}).map(([name, prefix]) => {
31
+ const folders = prefix === '/' ? [] : prefix.split('/').slice(1);
32
+ const refused = (folder) => folder === '.' || folder === '..' || isPrivate(folder) || !PREFIX_SEGMENT.test(folder);
33
+ // A parameter used twice, in any case, as MapPagePackage refuses it.
34
+ const parameters = folders.filter((folder) => folder.startsWith('[')).map((folder) => folder.toLowerCase());
35
+ if (!prefix.startsWith('/') || folders.some(refused) || new Set(parameters).size < parameters.length) {
36
+ throw new Error(`netjes: renderDocument cannot mount '${name}' at '${prefix}': write the prefix as MapPagePackage takes it, ` +
37
+ "such as '/help', '/(marketing)/help' or '/[tenant]/help'.");
38
+ }
39
+ return { name, folder: folders.join('/'), pages: packages.find((p) => p.name === name)?.pages ?? 'app' };
40
+ });
41
+ }
42
+ /** The files the server routes: the app's where they are, and a mounted package's under its prefix's folders. */
43
+ function routedFiles(files, appDir, mounts) {
44
+ return files.flatMap((id) => {
45
+ if (id.startsWith(`${appDir}/`))
46
+ return [{ id, path: id, source: 'app' }];
47
+ const mount = mounts.find((m) => id.startsWith(`${m.name}/${m.pages}/`));
48
+ if (!mount)
49
+ return [];
50
+ const below = id.slice(mount.name.length + mount.pages.length + 2);
51
+ return [{ id, path: [appDir, mount.folder, below].filter(Boolean).join('/'), source: mount.name }];
52
+ });
53
+ }
54
+ /**
55
+ * Each mount's URL for these route values, as the server sends it: the literal segments as written and each value
56
+ * encoded as one segment, or null when a value is missing, a list, empty, `.` or `..`.
57
+ */
58
+ function mountUrls(mounts, params) {
59
+ // As the server encodes a value (Uri.EscapeDataString), which encodeURIComponent leaves these five unencoded.
60
+ const encode = (value) => encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
61
+ return Object.fromEntries(mounts.map((mount) => {
62
+ const segments = [];
63
+ for (const folder of mount.folder.split('/').filter((f) => f && !isGroup(f))) {
64
+ const value = folder.startsWith('[') ? params[folder.slice(1, -1)] : folder;
65
+ if (typeof value !== 'string' || value === '' || value === '.' || value === '..')
66
+ return [mount.name, null];
67
+ segments.push(folder.startsWith('[') ? encode(value) : value);
68
+ }
69
+ return [mount.name, `/${segments.join('/')}`];
70
+ }));
71
+ }
72
+ /** A file in the app directory: the folders below the directory and the file's name without its extension; null for any other file. */
73
+ function parse(file, appDir) {
74
+ if (!file.startsWith(`${appDir}/`) || !PAGE_EXTENSION.test(file))
75
+ return null;
76
+ const folders = file.slice(appDir.length + 1).split('/');
77
+ const name = (folders.pop() ?? '').replace(PAGE_EXTENSION, '');
78
+ return { folders, name };
79
+ }
80
+ /** The convention files the server routes: none in private folders, and the slots that pages and defaults make. */
81
+ function appFiles(files, appDir) {
82
+ const folders = new Map();
83
+ const slots = new Map();
84
+ for (const file of [...files].sort((a, b) => ordinal(a.id, b.id))) {
85
+ const parsed = parse(file.path, appDir);
86
+ if (!parsed || parsed.folders.some(isPrivate))
87
+ continue;
88
+ const slot = parsed.folders.findIndex(isSlot);
89
+ if (slot >= 0) {
90
+ const parent = parsed.folders.slice(0, slot).join('/');
91
+ if ((parsed.name === 'page' || parsed.name === 'default') && !slots.has(parent)) {
92
+ slots.set(parent, [appDir, ...parsed.folders.slice(0, slot + 1)].join('/'));
93
+ }
94
+ continue;
95
+ }
96
+ const folder = parsed.folders.join('/');
97
+ let conventions = folders.get(folder);
98
+ if (!conventions)
99
+ folders.set(folder, (conventions = new Map()));
100
+ const other = conventions.get(parsed.name);
101
+ // As the server, which refuses two sources' segment files in one folder.
102
+ if (other && other.source !== file.source && parsed.name !== 'page') {
103
+ throw new Error(`netjes: renderDocument has two ${parsed.name} files for ${[appDir, folder].filter(Boolean).join('/')}: ${other.id} and ${file.id}.`);
104
+ }
105
+ if (!other)
106
+ conventions.set(parsed.name, file);
107
+ }
108
+ return { folders, slots };
109
+ }
110
+ /**
111
+ * How many URL segments a layout's folders cover for these route values, as the server counts them: one per folder,
112
+ * none for a route group, and a catch-all as many as its value has.
113
+ */
114
+ function urlDepth(folders, params) {
115
+ let depth = 0;
116
+ for (const folder of folders.filter((name) => !isGroup(name))) {
117
+ if (!folder.startsWith('[...') && !folder.startsWith('[[...')) {
118
+ depth++;
119
+ continue;
120
+ }
121
+ const value = params[folder.replace(/^[[\]]+|[[\]]+$/g, '').slice(3)];
122
+ depth += (Array.isArray(value) ? value.join('/') : (value ?? '')).split('/').filter(Boolean).length;
123
+ }
124
+ return depth;
125
+ }
126
+ function slotError(page, where, slot) {
127
+ return new Error(`netjes: renderDocument cannot render ${page}, which ${where} the parallel route slot ${slot}: the server chooses what a slot renders.`);
128
+ }
129
+ /**
130
+ * The folders above `folders` and the folder itself that are segments, outermost first, as the server sends them:
131
+ * each folder with a segment file, its layout's props from `layouts` and, for a layout, the URL depth it covers.
132
+ */
133
+ function segmentsFor(page, app, folders, appDir, options) {
134
+ const segments = [];
135
+ for (let end = 0; end <= folders.length; end++) {
136
+ const path = folders.slice(0, end);
137
+ const folder = path.join('/');
138
+ const slot = app.slots.get(folder);
139
+ if (slot)
140
+ throw slotError(page, 'renders under', slot);
141
+ const conventions = app.folders.get(folder);
142
+ if (!conventions || !SEGMENT_FILES.some((name) => conventions.has(name)))
143
+ continue;
144
+ const segment = { id: folder ? `${appDir}/${folder}` : appDir };
145
+ for (const name of ['layout', 'template', 'loading', 'error']) {
146
+ const file = conventions.get(name)?.id;
147
+ if (file)
148
+ segment[name] = file;
149
+ }
150
+ if (segment.layout) {
151
+ if (options.layouts && Object.hasOwn(options.layouts, segment.layout))
152
+ segment.props = options.layouts[segment.layout];
153
+ segment.depth = urlDepth(path, options.params ?? {});
154
+ }
155
+ segments.push(segment);
156
+ }
157
+ return segments;
158
+ }
159
+ /** Every file renderDocument could render from these: the pages and the boundary files, in ordinal order. */
160
+ function renderable(files, appDir) {
161
+ return files
162
+ .filter((file) => {
163
+ const parsed = parse(file.path, appDir);
164
+ if (!parsed || parsed.folders.some((folder) => isPrivate(folder) || isSlot(folder)))
165
+ return false;
166
+ return parsed.name === 'page' || (BOUNDARIES.has(parsed.name) && (parsed.name !== 'global-error' || isRootGlobalError(file, parsed)));
167
+ })
168
+ .map(({ id }) => id)
169
+ .sort(ordinal);
170
+ }
171
+ /** The global error page is the app's own, in the app directory itself; the server refuses one in a package. */
172
+ const isRootGlobalError = (file, parsed) => file.source === 'app' && parsed.folders.length === 0;
173
+ /**
174
+ * The payload the server sends with the document of `page`, a file of the pages map named without its leading slash,
175
+ * for the values in `options`: the route, kind, status and segments by the server's rules, and a build with no
176
+ * stylesheets or scripts. The files of the page packages `options.mounts` names go under their prefixes, with their
177
+ * pages folders from `packages`. Throws for a file it cannot render: one not in `files`, a layout, a page in a private
178
+ * folder or under a parallel route slot, or a file of a package it does not mount.
179
+ */
180
+ export function documentPayload(page, options, files, appDir, packages = []) {
181
+ const paths = files.map((file) => file.replace(/^\//, ''));
182
+ const mounts = mountsOf(options.mounts, packages);
183
+ const routed = routedFiles(paths, appDir, mounts);
184
+ if (!paths.includes(page)) {
185
+ const hint = page.startsWith('/') && paths.includes(page.slice(1))
186
+ ? `; name the file without the leading slash: ${page.slice(1)}.`
187
+ : `. The files it can render are ${list(renderable(routed, appDir))}.`;
188
+ throw new Error(`netjes: renderDocument has no ${page} in the pages map${hint}`);
189
+ }
190
+ const file = routed.find((routedFile) => routedFile.id === page);
191
+ const parsed = file && parse(file.path, appDir);
192
+ if (!parsed) {
193
+ const unmounted = packages.find((p) => page.startsWith(`${p.name}/`))?.name;
194
+ throw new Error(unmounted
195
+ ? `netjes: renderDocument cannot render ${page}, a file of the page package '${unmounted}', which it does not mount: ` +
196
+ `pass its prefix as MapPagePackage takes it, as in mounts: { '${unmounted}': '/help' }.`
197
+ : `netjes: renderDocument cannot render ${page}, which is not in the app's directory, ${appDir}, or in a mounted page package's pages.`);
198
+ }
199
+ if (parsed.folders.some(isPrivate))
200
+ throw new Error(`netjes: renderDocument cannot render ${page}: a private folder is not routed.`);
201
+ const slot = parsed.folders.findIndex(isSlot);
202
+ if (slot >= 0)
203
+ throw slotError(page, 'is in', [appDir, ...parsed.folders.slice(0, slot + 1)].join('/'));
204
+ const boundary = BOUNDARIES.get(parsed.name);
205
+ if ((parsed.name !== 'page' && !boundary) || (parsed.name === 'global-error' && !isRootGlobalError(file, parsed))) {
206
+ throw new Error(`netjes: renderDocument renders a page or a not-found, error, forbidden, unauthorized or global-error file, not ${page}.`);
207
+ }
208
+ // The global error page renders without any layout, the others inside the segments down to their own folder.
209
+ const segments = parsed.name === 'global-error' ? [] : segmentsFor(page, appFiles(routed, appDir), parsed.folders, appDir, options);
210
+ for (const file of Object.keys(options.layouts ?? {})) {
211
+ if (!segments.some((segment) => segment.layout === file)) {
212
+ const layouts = segments.flatMap((segment) => (segment.layout ? [segment.layout] : []));
213
+ throw new Error(`netjes: renderDocument has props for ${file}, which is not a layout of ${page}. ` +
214
+ (layouts.length > 0 ? `Its layouts are ${list(layouts)}.` : 'It has no layouts.'));
215
+ }
216
+ }
217
+ // An error boundary renders in place of the pages below its folder, so it is not wrapped in itself.
218
+ for (const segment of segments)
219
+ if (segment.error === page)
220
+ delete segment.error;
221
+ return {
222
+ kind: 'page',
223
+ route: parsed.name === 'page' ? `/${parsed.folders.filter((folder) => !isGroup(folder)).join('/')}` : null,
224
+ page,
225
+ ...(boundary ? { pageKind: boundary.kind } : {}),
226
+ segments,
227
+ props: options.props ?? {},
228
+ params: options.params ?? {},
229
+ shared: options.shared ?? null,
230
+ status: options.status ?? boundary?.status ?? 200,
231
+ url: options.url ?? '/',
232
+ version: 'test',
233
+ ...(mounts.length > 0 ? { mounts: mountUrls(mounts, options.params ?? {}) } : {}),
234
+ document: {
235
+ lang: options.lang ?? 'en',
236
+ assets: { stylesheets: [], modulePreloads: [], scripts: [] },
237
+ errorPage: null,
238
+ ...(options.publicConfig ? { publicConfig: options.publicConfig } : {}),
239
+ ...(options.nonce ? { nonce: options.nonce } : {}),
240
+ },
241
+ };
242
+ }
243
+ function isThenable(value) {
244
+ if ((typeof value !== 'object' && typeof value !== 'function') || value === null)
245
+ return false;
246
+ return typeof value.then === 'function';
247
+ }
248
+ function isPlainObject(value) {
249
+ if (typeof value !== 'object' || value === null)
250
+ return false;
251
+ const prototype = Object.getPrototypeOf(value);
252
+ return prototype === Object.prototype || prototype === null;
253
+ }
254
+ /** A JSON value with each Promise in it, at any depth, replaced by a `Page.Defer` placeholder; `values` keeps the Promises by id. */
255
+ function withPlaceholders(value, values) {
256
+ if (isThenable(value)) {
257
+ const id = `d${values.size}`;
258
+ values.set(id, value);
259
+ // Read once the document renders; until then a rejection is not an unhandled one.
260
+ Promise.resolve(value).catch(() => { });
261
+ return { $netjes: 'deferred', id };
262
+ }
263
+ if (Array.isArray(value))
264
+ return value.map((item) => withPlaceholders(item, values));
265
+ return isPlainObject(value) ? placeholdersIn(value, values) : value;
266
+ }
267
+ function placeholdersIn(props, values) {
268
+ // Keys are defined, not assigned, so a "__proto__" key stays a key.
269
+ return Object.fromEntries(Object.entries(props).map(([key, item]) => [key, withPlaceholders(item, values)]));
270
+ }
271
+ async function text(stream) {
272
+ const decoder = new TextDecoder();
273
+ let html = '';
274
+ for await (const chunk of stream) {
275
+ html += chunk instanceof Uint8Array ? decoder.decode(chunk, { stream: true }) : decoder.decode() + String(chunk);
276
+ }
277
+ return html + decoder.decode();
278
+ }
279
+ /**
280
+ * Renders a page's whole document, from `<!DOCTYPE html>` to `</html>`, as the Node sidecar renders it for a crawler:
281
+ * the page from `page`, a file of the pages map such as `app/blog/[slug]/page.tsx`, inside the layouts the server
282
+ * would wrap it in, with the head, Netjes's inline scripts and the payload. It waits for every Suspense boundary, and
283
+ * a Promise in the props or in a layout's props is a `Page.Defer` value: rendered in place once it resolves, left as its
284
+ * Suspense fallback when it rejects. The build's stylesheets and scripts, development styles and an antiforgery token
285
+ * are left out, and no C# runs: the props come from `options`. Runs in Vitest's node environment, with the `netjes()`
286
+ * plugin, which provides the pages map, the app's folder and the query shell, also when `modules` is given.
287
+ */
288
+ export async function renderDocument(page, options = {}) {
289
+ const { modules, signal, props, layouts, ...rest } = options;
290
+ // Before the first await, so that a Promise that has failed already gets its handler before Node looks for one.
291
+ const values = new Map();
292
+ const sent = {
293
+ ...rest,
294
+ props: placeholdersIn(props ?? {}, values),
295
+ ...(layouts
296
+ ? { layouts: Object.fromEntries(Object.entries(layouts).map(([file, layoutProps]) => [file, placeholdersIn(layoutProps, values)])) }
297
+ : {}),
298
+ };
299
+ // A form's server action, the query client and the router's first URL take their browser path where these exist.
300
+ if (typeof window !== 'undefined' || typeof document !== 'undefined') {
301
+ throw new Error('netjes: renderDocument renders a page as the Node sidecar does, without a DOM. ' +
302
+ "Put '// @vitest-environment node' at the top of the test file.");
303
+ }
304
+ signal?.throwIfAborted();
305
+ const app = await import('virtual:netjes/pages');
306
+ const pages = modules ?? app.pages;
307
+ const payload = documentPayload(page, sent, Object.keys(pages), app.appDir, app.packages);
308
+ // Loaded here, so that component tests, which import netjes/testing too, never load react-dom/server.
309
+ const { createServerRenderer } = await import('./server-render.js');
310
+ const stream = await createServerRenderer(pages).renderToStream(htmlSafeJson(payload), {
311
+ waitForAll: true,
312
+ deferred: (id) => values.get(id) ?? new Promise(() => { }),
313
+ ...(signal ? { signal } : {}),
314
+ });
315
+ return text(stream);
316
+ }
317
+ /** JavaScript MIME type essences: a script element whose type is one of them, in any case, runs as a classic script. */
318
+ const JAVASCRIPT_TYPES = new Set([
319
+ 'application/ecmascript',
320
+ 'application/javascript',
321
+ 'application/x-ecmascript',
322
+ 'application/x-javascript',
323
+ 'text/ecmascript',
324
+ 'text/javascript',
325
+ 'text/javascript1.0',
326
+ 'text/javascript1.1',
327
+ 'text/javascript1.2',
328
+ 'text/javascript1.3',
329
+ 'text/javascript1.4',
330
+ 'text/javascript1.5',
331
+ 'text/jscript',
332
+ 'text/livescript',
333
+ 'text/x-ecmascript',
334
+ 'text/x-javascript',
335
+ ]);
336
+ /** The other script types whose inline text a browser checks against a policy's script sources. */
337
+ const OTHER_SCRIPT_TYPES = new Set(['module', 'importmap', 'speculationrules']);
338
+ /** A script element: its start tag's attributes (quoted values can hold a `>`) and its text, up to `</script`. */
339
+ const SCRIPT = /<script(?=[\s/>])((?:"[^"]*"|'[^']*'|[^'">])*)>([\s\S]*?)<\/script(?=[\s/>])[^>]*>/gi;
340
+ const ATTRIBUTE = /([^\s"'>/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
341
+ const asciiLowerCase = (text) => text.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
342
+ function attributesOf(source) {
343
+ const attributes = new Map();
344
+ for (const [, name = '', double, single, bare] of source.matchAll(ATTRIBUTE)) {
345
+ const key = asciiLowerCase(name);
346
+ // As in HTML, the first of two attributes with one name counts.
347
+ if (!attributes.has(key))
348
+ attributes.set(key, double ?? single ?? bare ?? '');
349
+ }
350
+ return attributes;
351
+ }
352
+ /** Whether a browser runs an inline script element with these attributes, by HTML's rules for its type. */
353
+ function runs(attributes) {
354
+ const type = attributes.get('type');
355
+ const language = attributes.get('language');
356
+ const typeString = type === '' || (type === undefined && !language)
357
+ ? 'text/javascript'
358
+ : type === undefined
359
+ ? `text/${language ?? ''}`
360
+ : type.replace(/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g, '');
361
+ const kind = asciiLowerCase(typeString);
362
+ if (JAVASCRIPT_TYPES.has(kind))
363
+ return !attributes.has('nomodule');
364
+ return OTHER_SCRIPT_TYPES.has(kind);
365
+ }
366
+ async function hashSource(script) {
367
+ const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(script)));
368
+ let bytes = '';
369
+ for (const byte of digest)
370
+ bytes += String.fromCharCode(byte);
371
+ return `'sha256-${btoa(bytes)}'`;
372
+ }
373
+ /**
374
+ * The hash-sources, `'sha256-…'` in their quotes, of the inline scripts in `html` that a browser runs and checks
375
+ * against a Content-Security-Policy's script sources: each script element without `src` whose type a browser runs
376
+ * (none, a JavaScript type, `module`, `importmap` or `speculationrules`), with text. Each hash is listed once, in the
377
+ * order of the first script with it. Data blocks such as the page payload (`application/json`) are left out.
378
+ */
379
+ export async function inlineScriptHashes(html) {
380
+ const scripts = [];
381
+ for (const [, tag = '', body = ''] of html.matchAll(SCRIPT)) {
382
+ const attributes = attributesOf(tag);
383
+ if (attributes.has('src') || !runs(attributes))
384
+ continue;
385
+ // The HTML parser turns each CR LF, and each CR on its own, into LF before the script sees its text.
386
+ const script = body.replace(/\r\n?/g, '\n');
387
+ // A browser checks an empty script against no policy, since it does not run it.
388
+ if (script !== '')
389
+ scripts.push(script);
390
+ }
391
+ return [...new Set(await Promise.all(scripts.map(hashSource)))];
392
+ }
393
+ //# sourceMappingURL=render-document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-document.js","sourceRoot":"","sources":["../src/render-document.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ type RouteAnnouncerProps = {
2
+ /** The page's path and query: a navigation that changes neither (a refresh, a fragment link) names no page. */
3
+ location: string;
4
+ /** The path without the base path, the name of a page with neither a title nor an `h1`. */
5
+ path: string;
6
+ };
7
+ /**
8
+ * A polite live region that names the page after a client navigation, as a screen reader names the page a document
9
+ * load opens. It renders in the browser only, after hydration, so the server's HTML has none. It has no role, which
10
+ * would make it one more `status` or `alert` for an app's tests to find. Its effect runs after the app's, as a later
11
+ * sibling of the pages, so it reads the title and headings the new page has set. The first run records the name of
12
+ * the page the document loaded with; a later one, for another path or query, puts the new page's name in the region
13
+ * when it differs from the name of the page before. An intercepted page keeps the title of the page under it, so it
14
+ * is not named.
15
+ */
16
+ export declare function RouteAnnouncer({ location, path }: RouteAnnouncerProps): import("react").JSX.Element | null;
17
+ export {};
18
+ //# sourceMappingURL=route-announcer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-announcer.d.ts","sourceRoot":"","sources":["../src/route-announcer.tsx"],"names":[],"mappings":"AAqCA,KAAK,mBAAmB,GAAG;IACzB,+GAA+G;IAC/G,QAAQ,EAAE,MAAM,CAAC;IACjB,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,mBAAmB,sCAerE"}
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
3
+ /**
4
+ * Out of sight and still read by screen readers. React sets these styles through the CSSOM on an element it creates
5
+ * in the browser, which a Content-Security-Policy without `'unsafe-inline'` in `style-src` allows.
6
+ */
7
+ const VISUALLY_HIDDEN = {
8
+ position: 'absolute',
9
+ width: 1,
10
+ height: 1,
11
+ margin: -1,
12
+ padding: 0,
13
+ border: 0,
14
+ overflow: 'hidden',
15
+ clip: 'rect(0 0 0 0)',
16
+ clipPath: 'inset(50%)',
17
+ whiteSpace: 'nowrap',
18
+ };
19
+ const subscribe = () => () => { };
20
+ const inBrowser = () => true;
21
+ const onServer = () => false;
22
+ /** A segment as a person reads it, `café` rather than `caf%C3%A9`; one that does not decode stays as it is. */
23
+ function decodeSegment(segment) {
24
+ try {
25
+ return decodeURIComponent(segment);
26
+ }
27
+ catch {
28
+ return segment;
29
+ }
30
+ }
31
+ /** How a screen reader can name the page on screen: its title, else its first `h1`, else its path, decoded. */
32
+ function pageName(path) {
33
+ return document.title.trim() || document.querySelector('h1')?.textContent?.trim() || path.split('/').map(decodeSegment).join('/');
34
+ }
35
+ /**
36
+ * A polite live region that names the page after a client navigation, as a screen reader names the page a document
37
+ * load opens. It renders in the browser only, after hydration, so the server's HTML has none. It has no role, which
38
+ * would make it one more `status` or `alert` for an app's tests to find. Its effect runs after the app's, as a later
39
+ * sibling of the pages, so it reads the title and headings the new page has set. The first run records the name of
40
+ * the page the document loaded with; a later one, for another path or query, puts the new page's name in the region
41
+ * when it differs from the name of the page before. An intercepted page keeps the title of the page under it, so it
42
+ * is not named.
43
+ */
44
+ export function RouteAnnouncer({ location, path }) {
45
+ const rendered = useSyncExternalStore(subscribe, inBrowser, onServer);
46
+ const [message, setMessage] = useState('');
47
+ const named = useRef(null);
48
+ useEffect(() => {
49
+ const name = pageName(path);
50
+ if (named.current !== null && name !== named.current)
51
+ setMessage(name);
52
+ named.current = name;
53
+ }, [location, path]);
54
+ if (!rendered)
55
+ return null;
56
+ return (_jsx("div", { "aria-live": "polite", "aria-atomic": "true", "data-netjes-route-announcer": "", style: VISUALLY_HIDDEN, children: message }));
57
+ }
58
+ //# sourceMappingURL=route-announcer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-announcer.js","sourceRoot":"","sources":["../src/route-announcer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAsB,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE9F;;;GAGG;AACH,MAAM,eAAe,GAAkB;IACrC,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC,CAAC;IACV,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,CAAC;IACT,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,eAAe;IACrB,QAAQ,EAAE,YAAY;IACtB,UAAU,EAAE,QAAQ;CACrB,CAAC;AAEF,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;AACjC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;AAC7B,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC;AAE7B,+GAA+G;AAC/G,SAAS,aAAa,CAAC,OAAe;IACpC,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,+GAA+G;AAC/G,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpI,CAAC;AASD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAuB;IACpE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACtE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC1C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,CAAC,OAAO;YAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QACvE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;IACvB,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IACrB,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO,CACL,2BAAe,QAAQ,iBAAa,MAAM,iCAA6B,EAAE,EAAC,KAAK,EAAE,eAAe,YAC7F,OAAO,GACJ,CACP,CAAC;AACJ,CAAC"}