netjes 0.0.2 → 0.0.3
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/README.md +11 -11
- package/cli/agents.mjs +25 -2
- package/cli/commands.mjs +56 -6
- package/cli/help.mjs +7 -2
- package/cli/info.mjs +7 -2
- package/cli/scaffold.mjs +31 -4
- package/dist/actions.d.ts +7 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +9 -3
- package/dist/actions.js.map +1 -1
- package/dist/client-entry.d.ts +1 -0
- package/dist/client-entry.d.ts.map +1 -1
- package/dist/client-entry.js +19 -2
- package/dist/client-entry.js.map +1 -1
- package/dist/deferred.d.ts +11 -0
- package/dist/deferred.d.ts.map +1 -1
- package/dist/deferred.js +15 -1
- package/dist/deferred.js.map +1 -1
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +10 -1
- package/dist/document.js.map +1 -1
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/form.d.ts +5 -5
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +5 -2
- package/dist/form.js.map +1 -1
- package/dist/href.d.ts +24 -3
- package/dist/href.d.ts.map +1 -1
- package/dist/href.js +117 -7
- package/dist/href.js.map +1 -1
- package/dist/image.d.ts +3 -3
- package/dist/image.d.ts.map +1 -1
- package/dist/image.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/link.d.ts +15 -7
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +38 -7
- package/dist/link.js.map +1 -1
- package/dist/metadata.d.ts +8 -2
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +14 -5
- package/dist/metadata.js.map +1 -1
- package/dist/modules.d.ts +15 -1
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js.map +1 -1
- package/dist/navigation-focus.d.ts +38 -0
- package/dist/navigation-focus.d.ts.map +1 -0
- package/dist/navigation-focus.js +71 -0
- package/dist/navigation-focus.js.map +1 -0
- package/dist/query.d.ts +5 -2
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +11 -8
- package/dist/query.js.map +1 -1
- package/dist/render-document.d.ts +60 -0
- package/dist/render-document.d.ts.map +1 -0
- package/dist/render-document.js +330 -0
- package/dist/render-document.js.map +1 -0
- package/dist/route-announcer.d.ts +18 -0
- package/dist/route-announcer.d.ts.map +1 -0
- package/dist/route-announcer.js +58 -0
- package/dist/route-announcer.js.map +1 -0
- package/dist/route-tree.d.ts +6 -2
- package/dist/route-tree.d.ts.map +1 -1
- package/dist/route-tree.js +17 -7
- package/dist/route-tree.js.map +1 -1
- package/dist/router.d.ts +28 -5
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +71 -26
- package/dist/router.js.map +1 -1
- package/dist/script.d.ts +28 -5
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +192 -21
- package/dist/script.js.map +1 -1
- package/dist/server-render.d.ts.map +1 -1
- package/dist/server-render.js +4 -1
- package/dist/server-render.js.map +1 -1
- package/dist/testing-vitest.d.ts +8 -0
- package/dist/testing-vitest.d.ts.map +1 -0
- package/dist/testing-vitest.js +26 -0
- package/dist/testing-vitest.js.map +1 -0
- package/dist/testing.d.ts +11 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +17 -3
- package/dist/testing.js.map +1 -1
- package/dist/zod-jitless.d.ts +2 -0
- package/dist/zod-jitless.d.ts.map +1 -0
- package/dist/zod-jitless.js +4 -0
- package/dist/zod-jitless.js.map +1 -0
- package/package.json +1 -1
- package/sidecar/server.mjs +73 -6
- package/skills/netjes/SKILL.md +13 -6
- package/skills/netjes/references/caching-and-streaming.md +37 -4
- package/skills/netjes/references/data-and-actions.md +9 -5
- package/skills/netjes/references/deployment.md +7 -3
- package/skills/netjes/references/routing.md +18 -6
- package/skills/netjes/references/testing.md +23 -7
- package/src/actions.tsx +9 -3
- package/src/client-entry.tsx +20 -2
- package/src/deferred.ts +14 -1
- package/src/document.tsx +22 -3
- package/src/errors.ts +12 -0
- package/src/form.tsx +10 -7
- package/src/href.ts +123 -8
- package/src/image.tsx +3 -3
- package/src/index.ts +2 -1
- package/src/link.tsx +47 -13
- package/src/metadata.tsx +19 -6
- package/src/modules.ts +15 -2
- package/src/navigation-focus.ts +75 -0
- package/src/query.tsx +14 -8
- package/src/render-document.tsx +386 -0
- package/src/route-announcer.tsx +69 -0
- package/src/route-tree.tsx +17 -6
- package/src/router.tsx +116 -31
- package/src/script.tsx +214 -23
- package/src/server-render.tsx +4 -1
- package/src/testing-vitest.ts +37 -0
- package/src/testing.tsx +31 -5
- package/src/virtual.d.ts +2 -0
- package/src/zod-jitless.ts +15 -0
- package/template/.dockerignore +3 -0
- package/template/Dockerfile +11 -1
- package/template/README.md +11 -7
- package/template/_AGENTS.md +36 -8
- package/template/__NAME__.csproj +2 -0
- package/template/app/document.test.ts +29 -0
- package/template/app/error.tsx +3 -2
- package/template/app/layout.tsx +10 -1
- package/template/docker-compose.override.yml +4 -3
- package/template/docker-compose.prod.yml +2 -1
- package/template/e2e/home.spec.ts +32 -0
- package/template/generated/netjes.ts +43 -14
- package/template/package.json +4 -1
- package/template/playwright.config.ts +36 -0
- package/template/tests/__NAME__.Tests/AppFactory.cs +31 -0
- package/template/tests/__NAME__.Tests/HomePageTests.cs +55 -0
- package/template/tests/__NAME__.Tests/__NAME__.Tests.csproj +30 -0
- package/template/tsconfig.app.json +20 -0
- package/template/tsconfig.json +2 -17
- package/template/tsconfig.node.json +8 -0
- package/vite/plugin.d.ts +9 -1
- package/vite/plugin.mjs +17 -5
package/README.md
CHANGED
|
@@ -12,12 +12,12 @@ cd my-app
|
|
|
12
12
|
npm run dev # http://localhost:5080
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
`netjes new` writes an ASP.NET Core app with React pages, Tailwind CSS, TanStack Query, zod, Vitest and Docker files, and references `netjes` and `Netjes` at the same exact version.
|
|
15
|
+
`netjes new` writes an ASP.NET Core app with React pages, Tailwind CSS, TanStack Query, zod, Vitest, a C# test project, a Playwright suite and Docker files, and references `netjes` and `Netjes` at the same exact version.
|
|
16
16
|
|
|
17
17
|
## Add it to a project
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install netjes@0.0.
|
|
20
|
+
npm install netjes@0.0.3 react react-dom zod @tanstack/react-query
|
|
21
21
|
npm install -D vite tailwindcss @tailwindcss/vite
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -35,21 +35,21 @@ Tailwind CSS and the TanStack Query client are on by default; `netjes({ tailwind
|
|
|
35
35
|
|
|
36
36
|
| Import | What it holds |
|
|
37
37
|
|---|---|
|
|
38
|
-
| `netjes` | Components and hooks: `Link`, `Form`, `Image`, `Script`, `definePage`, `useAction`, `useRouter` and the rest |
|
|
38
|
+
| `netjes` | Components and hooks: `Link`, `Form`, `Image`, `Script`, `definePage`, `useAction`, `useRouter` and the rest, and `CSP_SCRIPT_HASHES`, the hashes of Netjes's inline scripts for a Content-Security-Policy without a nonce |
|
|
39
39
|
| `netjes/vite` | The Vite plugin |
|
|
40
|
-
| `netjes/testing` | `createTestApp()`, for rendering pages and components in Vitest |
|
|
40
|
+
| `netjes/testing` | `createTestApp()`, for rendering pages and components in Vitest, and `renderDocument()` and `inlineScriptHashes()`, for a page's whole document and the inline scripts in it |
|
|
41
41
|
| `netjes/vitals` | `useReportWebVitals` and `<WebVitals />` |
|
|
42
42
|
| `netjes/zod` | `deferred(schema)`, for values that loaders stream with `Page.Defer` |
|
|
43
43
|
| `netjes` (bin) | The command: `new`, `dev`, `build`, `start`, `generate`, `routes`, `export`, `info`, `agents` |
|
|
44
44
|
|
|
45
|
-
Each import is an ES module with its type declarations, so an app's `tsc` reads the declarations and checks only the app's own code, also under stricter compiler options such as `exactOptionalPropertyTypes` or `noPropertyAccessFromIndexSignature` (see [TypeScript setup](https://github.com/DennisVerhoeven/netjes/blob/
|
|
45
|
+
Each import is an ES module with its type declarations, so an app's `tsc` reads the declarations and checks only the app's own code, also under stricter compiler options such as `exactOptionalPropertyTypes` or `noPropertyAccessFromIndexSignature` (see [TypeScript setup](https://github.com/DennisVerhoeven/netjes/blob/v0.0.3/docs/reference/vite-plugin.md#typescript-setup)). The TypeScript sources are in the package too, for the source maps: an editor's go to definition and a stack trace lead to them.
|
|
46
46
|
|
|
47
47
|
## Documentation
|
|
48
48
|
|
|
49
|
-
- [Getting started](https://github.com/DennisVerhoeven/netjes/blob/
|
|
50
|
-
- [All guides](https://github.com/DennisVerhoeven/netjes/blob/
|
|
51
|
-
- [React API](https://github.com/DennisVerhoeven/netjes/blob/
|
|
52
|
-
- [Vite plugin](https://github.com/DennisVerhoeven/netjes/blob/
|
|
53
|
-
- [The netjes command](https://github.com/DennisVerhoeven/netjes/blob/
|
|
49
|
+
- [Getting started](https://github.com/DennisVerhoeven/netjes/blob/v0.0.3/docs/getting-started.md)
|
|
50
|
+
- [All guides](https://github.com/DennisVerhoeven/netjes/blob/v0.0.3/docs/README.md)
|
|
51
|
+
- [React API](https://github.com/DennisVerhoeven/netjes/blob/v0.0.3/docs/reference/react-api.md)
|
|
52
|
+
- [Vite plugin](https://github.com/DennisVerhoeven/netjes/blob/v0.0.3/docs/reference/vite-plugin.md)
|
|
53
|
+
- [The netjes command](https://github.com/DennisVerhoeven/netjes/blob/v0.0.3/docs/reference/cli.md)
|
|
54
54
|
|
|
55
|
-
Report bugs in the [issue tracker](https://github.com/DennisVerhoeven/netjes/issues), and security problems privately, as [
|
|
55
|
+
Report bugs in the [issue tracker](https://github.com/DennisVerhoeven/netjes/issues), and security problems privately, as the [security policy](https://github.com/DennisVerhoeven/netjes/security/policy) describes. MIT licensed.
|
package/cli/agents.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { existsSync, statSync } from 'node:fs';
|
|
5
5
|
import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
import { fillNames, projectNames, readTemplate, skillFiles } from './scaffold.mjs';
|
|
7
|
+
import { fillNames, keepSections, projectNames, readTemplate, skillFiles } from './scaffold.mjs';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* The app's names: from `--name`, else its one project file (whose name is its root namespace), else its directory,
|
|
@@ -26,6 +26,20 @@ async function namesOf(io, dir, name) {
|
|
|
26
26
|
return projectNames(folder);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Whether the app's package.json has that script; one that is missing or not valid JSON has none.
|
|
31
|
+
* @param {string} dir
|
|
32
|
+
* @param {string} name
|
|
33
|
+
*/
|
|
34
|
+
async function hasScript(dir, name) {
|
|
35
|
+
try {
|
|
36
|
+
const manifest = /** @type {{ scripts?: Record<string, unknown> }} */ (JSON.parse(await readFile(path.join(dir, 'package.json'), 'utf8')));
|
|
37
|
+
return typeof manifest.scripts?.[name] === 'string';
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
29
43
|
/**
|
|
30
44
|
* @param {import('./main.mjs').CliIo} io
|
|
31
45
|
* @param {string} dir
|
|
@@ -38,8 +52,17 @@ export async function agents(io, dir, options) {
|
|
|
38
52
|
return 1;
|
|
39
53
|
}
|
|
40
54
|
const names = await namesOf(io, dir, options.name);
|
|
55
|
+
// AGENTS.md sends an agent only to the test suites this app has where `netjes new` puts them, and to the script
|
|
56
|
+
// it names.
|
|
57
|
+
const has = {
|
|
58
|
+
tests: existsSync(path.join(dir, 'tests', `${names.dotnet}.Tests`, `${names.dotnet}.Tests.csproj`)),
|
|
59
|
+
e2e:
|
|
60
|
+
existsSync(path.join(dir, 'playwright.config.ts')) &&
|
|
61
|
+
statSync(path.join(dir, 'e2e'), { throwIfNoEntry: false })?.isDirectory() === true &&
|
|
62
|
+
(await hasScript(dir, 'test:e2e')),
|
|
63
|
+
};
|
|
41
64
|
const files = [
|
|
42
|
-
{ path: 'AGENTS.md', text: fillNames(await readTemplate('_AGENTS.md'), names) },
|
|
65
|
+
{ path: 'AGENTS.md', text: fillNames(keepSections(await readTemplate('_AGENTS.md'), has), names) },
|
|
43
66
|
{ path: 'CLAUDE.md', text: await readTemplate('_CLAUDE.md') },
|
|
44
67
|
...(await skillFiles()),
|
|
45
68
|
];
|
package/cli/commands.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// (NETJES_COMMAND=generate|routes|export) it binds a throwaway loopback port, writes its result and exits. Only export
|
|
4
4
|
// starts the Node sidecar, to render the pages.
|
|
5
5
|
import { existsSync, statSync } from 'node:fs';
|
|
6
|
-
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
6
|
+
import { mkdtemp, readFile, realpath, rm } from 'node:fs/promises';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { agents } from './agents.mjs';
|
|
@@ -116,6 +116,42 @@ async function build(io, cwd) {
|
|
|
116
116
|
return 0;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Whether a path that path.relative returned leads below the folder it started from: not the folder itself (''), not
|
|
121
|
+
* up out of it (`..`, `../site`) and not on another drive (absolute). A name that only starts with two dots (`..site`)
|
|
122
|
+
* is below.
|
|
123
|
+
* @param {string} relative
|
|
124
|
+
*/
|
|
125
|
+
function isBelow(relative) {
|
|
126
|
+
return relative !== '' && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Whether `target` is a folder inside the app in `app`, comparing paths as .NET does: on macOS and Windows it
|
|
131
|
+
* upper-cases each letter, so paths that differ only in case are one folder there (and a long s, ſ, is an s).
|
|
132
|
+
* @param {string} app
|
|
133
|
+
* @param {string} target
|
|
134
|
+
*/
|
|
135
|
+
function insideApp(app, target) {
|
|
136
|
+
const fold = process.platform === 'darwin' || process.platform === 'win32';
|
|
137
|
+
return isBelow(fold ? path.relative(app.toUpperCase(), target.toUpperCase()) : path.relative(app, target));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The folder an app run in `cwd` sees as its own: its working directory, which macOS and Linux report by the real
|
|
142
|
+
* path, as getcwd() does (every symlink resolved, each name as the disk spells it), and Windows as it was given. `cwd`
|
|
143
|
+
* itself when its real path cannot be read.
|
|
144
|
+
* @param {string} cwd
|
|
145
|
+
*/
|
|
146
|
+
async function appFolder(cwd) {
|
|
147
|
+
if (process.platform === 'win32') return cwd;
|
|
148
|
+
try {
|
|
149
|
+
return await realpath(cwd);
|
|
150
|
+
} catch {
|
|
151
|
+
return cwd;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
119
155
|
/**
|
|
120
156
|
* `target` as the user would type it from `from`: relative when it is below, else absolute.
|
|
121
157
|
* @param {string} from
|
|
@@ -123,7 +159,7 @@ async function build(io, cwd) {
|
|
|
123
159
|
*/
|
|
124
160
|
function displayPath(from, target) {
|
|
125
161
|
const relative = path.relative(from, target);
|
|
126
|
-
return relative
|
|
162
|
+
return relative === '' ? '.' : isBelow(relative) ? relative : target;
|
|
127
163
|
}
|
|
128
164
|
|
|
129
165
|
/**
|
|
@@ -204,6 +240,8 @@ function layout(name) {
|
|
|
204
240
|
['Features/', 'the C# side, one folder per feature: loaders and server actions'],
|
|
205
241
|
['Program.cs', `the ASP.NET Core app (${name}.csproj)`],
|
|
206
242
|
['generated/netjes.ts', 'types and zod schemas from C#, rewritten by netjes generate; never edit it'],
|
|
243
|
+
[`tests/${name}.Tests/`, `C# tests of loaders and actions, run by dotnet test tests/${name}.Tests`],
|
|
244
|
+
['e2e/', 'Playwright tests against a development and a production server, run by npm run test:e2e'],
|
|
207
245
|
['Dockerfile', 'and the docker-compose files: Docker for development and production'],
|
|
208
246
|
];
|
|
209
247
|
const width = Math.max(...rows.map(([entry]) => (entry ?? '').length)) + 2;
|
|
@@ -213,7 +251,7 @@ function layout(name) {
|
|
|
213
251
|
/** @type {Record<string, Command>} */
|
|
214
252
|
export const COMMANDS = {
|
|
215
253
|
new: {
|
|
216
|
-
summary: 'Create an app: ASP.NET Core with React pages, Tailwind CSS, TanStack Query, zod and
|
|
254
|
+
summary: 'Create an app: ASP.NET Core with React pages, Tailwind CSS, TanStack Query, zod, Vitest, xUnit and Playwright',
|
|
217
255
|
args: '<dir>',
|
|
218
256
|
arguments: { '<dir>': { description: 'The folder to create the app in; it must not exist yet, or be empty' } },
|
|
219
257
|
options: {
|
|
@@ -401,7 +439,7 @@ export const COMMANDS = {
|
|
|
401
439
|
},
|
|
402
440
|
|
|
403
441
|
export: {
|
|
404
|
-
summary: 'Build, then write every page
|
|
442
|
+
summary: 'Build, then write every page, and each endpoint marked IncludeInExport, into a folder as static files',
|
|
405
443
|
args: '[dir]',
|
|
406
444
|
arguments: { '[dir]': { description: 'The folder to write the site to, inside the app', default: 'out' } },
|
|
407
445
|
options: {
|
|
@@ -410,7 +448,19 @@ export const COMMANDS = {
|
|
|
410
448
|
examples: ['netjes export', 'netjes export site --no-build'],
|
|
411
449
|
project: () => true,
|
|
412
450
|
async run({ io, cwd, args, options }) {
|
|
451
|
+
// A relative folder is resolved against cwd as the app will see it, so that a --cwd through a symlink still
|
|
452
|
+
// names a folder inside the app; the app compares paths as text.
|
|
453
|
+
const app = await appFolder(cwd);
|
|
454
|
+
const output = path.resolve(app, args[0] ?? 'out');
|
|
413
455
|
if (!options['no-build']) {
|
|
456
|
+
// The app decides where the export may write (StaticExportService.OutputProblems, ADR 0007), before it
|
|
457
|
+
// renders anything: only it knows Netjes:Root and the folders it needs. A folder outside the app is refused
|
|
458
|
+
// here too, before the build, which runs in cwd, so the app is there. With --no-build only the app checks,
|
|
459
|
+
// since Netjes:Root can put the app above cwd.
|
|
460
|
+
if (!insideApp(app, output)) {
|
|
461
|
+
printError(io, `netjes export: the output folder ${output} must be inside the app (${app}), such as 'out'; nothing was built`);
|
|
462
|
+
return 1;
|
|
463
|
+
}
|
|
414
464
|
const code = await build(io, cwd);
|
|
415
465
|
if (code !== 0) return code;
|
|
416
466
|
}
|
|
@@ -423,7 +473,7 @@ export const COMMANDS = {
|
|
|
423
473
|
...commandEnv(io),
|
|
424
474
|
ASPNETCORE_ENVIRONMENT: io.env.ASPNETCORE_ENVIRONMENT ?? 'Production',
|
|
425
475
|
NETJES_COMMAND: 'export',
|
|
426
|
-
NETJES_OUTPUT:
|
|
476
|
+
NETJES_OUTPUT: output,
|
|
427
477
|
},
|
|
428
478
|
});
|
|
429
479
|
},
|
|
@@ -451,7 +501,7 @@ export const COMMANDS = {
|
|
|
451
501
|
name: {
|
|
452
502
|
type: 'string',
|
|
453
503
|
value: '<Name>',
|
|
454
|
-
description: "The app's name in AGENTS.md",
|
|
504
|
+
description: "The app's name in AGENTS.md, and the <Name> of the test project tests/<Name>.Tests it looks for",
|
|
455
505
|
default: 'the name of its .csproj, else the folder name',
|
|
456
506
|
},
|
|
457
507
|
force: { type: 'boolean', description: 'Replace the files that exist', default: 'off: keep them' },
|
package/cli/help.mjs
CHANGED
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
* @typedef {import('./commands.mjs').OptionSpec} OptionSpec
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The CLI reference at the release tag of `version`: the page on main can describe commands and options that this
|
|
11
|
+
* version does not have.
|
|
12
|
+
* @param {string} version
|
|
13
|
+
*/
|
|
14
|
+
export const docsUrl = (version) => `https://github.com/DennisVerhoeven/netjes/blob/v${version}/docs/reference/cli.md`;
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* Options every command takes.
|
|
@@ -55,7 +60,7 @@ export function overviewHelp(commands, version) {
|
|
|
55
60
|
columns(Object.entries(GLOBAL_OPTIONS).map(([name, option]) => [label(name, option), describe(option)])),
|
|
56
61
|
'',
|
|
57
62
|
'Run `netjes help <command>` for its options and examples.',
|
|
58
|
-
`Docs: ${
|
|
63
|
+
`Docs: ${docsUrl(version)}`,
|
|
59
64
|
'',
|
|
60
65
|
].join('\n');
|
|
61
66
|
}
|
package/cli/info.mjs
CHANGED
|
@@ -24,8 +24,10 @@ export const MIN_DOTNET = 10;
|
|
|
24
24
|
export const DOTNET_DOWNLOAD = 'https://dotnet.microsoft.com/download';
|
|
25
25
|
/** The npm packages a Netjes app runs on. */
|
|
26
26
|
const PACKAGES = ['netjes', 'vite', 'react', 'react-dom'];
|
|
27
|
-
/** Folders that hold no C# source of the app's own. */
|
|
27
|
+
/** Folders that hold no C# source of the app's own, at any depth. */
|
|
28
28
|
const SKIPPED = new Set(['bin', 'obj', 'node_modules', 'dist', 'out']);
|
|
29
|
+
/** The folder at the app's root that holds its test project, which the app's project leaves out, so its code generates no types. */
|
|
30
|
+
const TEST_PROJECTS = 'tests';
|
|
29
31
|
/** Files written within this long of each other, as a checkout or `netjes new` does, count as written together. */
|
|
30
32
|
const SAME_TIME_MS = 2000;
|
|
31
33
|
/** The Next.js pages router's special files, at the root of pages/, by the App Router file that takes their place. */
|
|
@@ -280,12 +282,15 @@ function checkReference(cwd, csproj, text, npmVersion, cliVersion) {
|
|
|
280
282
|
async function newestSource(cwd) {
|
|
281
283
|
/** @type {{ file: string; mtimeMs: number } | null} */
|
|
282
284
|
let newest = null;
|
|
285
|
+
// The build leaves out `Tests/` too where the file system ignores case, as it then finds `tests/` there.
|
|
286
|
+
const isTestProjects = (/** @type {string} */ file) =>
|
|
287
|
+
file.toLowerCase() === TEST_PROJECTS && (file === TEST_PROJECTS || existsSync(path.join(cwd, TEST_PROJECTS)));
|
|
283
288
|
/** @param {string} relative */
|
|
284
289
|
async function walk(relative) {
|
|
285
290
|
for (const entry of await readdir(path.join(cwd, relative), { withFileTypes: true })) {
|
|
286
291
|
const file = relative ? `${relative}/${entry.name}` : entry.name;
|
|
287
292
|
if (entry.isDirectory()) {
|
|
288
|
-
if (!SKIPPED.has(entry.name) && !entry.name.startsWith('.')) await walk(file);
|
|
293
|
+
if (!SKIPPED.has(entry.name) && !entry.name.startsWith('.') && !isTestProjects(file)) await walk(file);
|
|
289
294
|
} else if (entry.name.endsWith('.cs')) {
|
|
290
295
|
const { mtimeMs } = await stat(path.join(cwd, file));
|
|
291
296
|
if (!newest || mtimeMs > newest.mtimeMs) newest = { file, mtimeMs };
|
package/cli/scaffold.mjs
CHANGED
|
@@ -58,8 +58,9 @@ const CSHARP_KEYWORDS = new Set(
|
|
|
58
58
|
'unsafe ushort using virtual void volatile while').split(' '),
|
|
59
59
|
);
|
|
60
60
|
|
|
61
|
-
// Types the template's C# uses by their simple names
|
|
62
|
-
//
|
|
61
|
+
// Types the template's C# uses by their simple names, in the app and in its test project, whose namespace starts with
|
|
62
|
+
// the app's name. A root namespace of the same name hides the type from that code, and the build fails (CS0118, CS0234);
|
|
63
|
+
// Program is the class the top-level statements in Program.cs make (CS0101).
|
|
63
64
|
const TEMPLATE_TYPES = new Set([
|
|
64
65
|
'Program',
|
|
65
66
|
'SiteProps',
|
|
@@ -71,6 +72,17 @@ const TEMPLATE_TYPES = new Set([
|
|
|
71
72
|
'TimeProvider',
|
|
72
73
|
'IEndpointRouteBuilder',
|
|
73
74
|
'FromFormAttribute',
|
|
75
|
+
'IWebHostBuilder',
|
|
76
|
+
'NetjesOptions',
|
|
77
|
+
'ISsrRenderer',
|
|
78
|
+
'Task',
|
|
79
|
+
'CancellationToken',
|
|
80
|
+
'NetjesHeaders',
|
|
81
|
+
'JsonNode',
|
|
82
|
+
'TestContext',
|
|
83
|
+
'Assert',
|
|
84
|
+
'FormUrlEncodedContent',
|
|
85
|
+
'HttpStatusCode',
|
|
74
86
|
]);
|
|
75
87
|
|
|
76
88
|
/**
|
|
@@ -95,7 +107,7 @@ export async function namesFor(target, name) {
|
|
|
95
107
|
}
|
|
96
108
|
const names = name === undefined ? projectNames(path.basename(target)) : { ...projectNames(name), dotnet: name };
|
|
97
109
|
if (TEMPLATE_TYPES.has(names.dotnet)) {
|
|
98
|
-
return { problem: `'${names.dotnet}' is the name of a type the app's code uses; choose another name with --name` };
|
|
110
|
+
return { problem: `'${names.dotnet}' is the name of a type the app's code or its test project uses; choose another name with --name` };
|
|
99
111
|
}
|
|
100
112
|
const manifest = JSON.parse(await readFile(path.join(TEMPLATE, 'package.json'), 'utf8'));
|
|
101
113
|
if (Object.hasOwn({ ...manifest.dependencies, ...manifest.devDependencies }, names.npm)) {
|
|
@@ -125,6 +137,21 @@ export function fillNames(text, names) {
|
|
|
125
137
|
return text.replaceAll('__NAME__', names.dotnet).replaceAll('__name__', names.npm).replaceAll('__TITLE__', names.title);
|
|
126
138
|
}
|
|
127
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Keeps or drops the parts of a template file that apply only to some apps, and removes the markers around them, each
|
|
142
|
+
* on a line of its own: what is between `<!--netjes:if name-->` and `<!--netjes:else-->` or `<!--netjes:end-->` stays
|
|
143
|
+
* when the app has `name`, and what is between `<!--netjes:else-->` and `<!--netjes:end-->` stays when it does not.
|
|
144
|
+
* @param {string} text
|
|
145
|
+
* @param {{ tests: boolean; e2e: boolean }} has what the app has: a C# test project, a Playwright suite
|
|
146
|
+
*/
|
|
147
|
+
export function keepSections(text, has) {
|
|
148
|
+
return text.replace(
|
|
149
|
+
/^<!--netjes:if (tests|e2e)-->\n([\s\S]*?)(?:^<!--netjes:else-->\n([\s\S]*?))?^<!--netjes:end-->\n/gm,
|
|
150
|
+
(_, /** @type {'tests' | 'e2e'} */ name, /** @type {string} */ kept, /** @type {string | undefined} */ otherwise) =>
|
|
151
|
+
has[name] ? kept : (otherwise ?? ''),
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
128
155
|
/** @param {string} file a path in the template @returns {Promise<string>} */
|
|
129
156
|
export const readTemplate = (file) => readFile(path.join(TEMPLATE, file), 'utf8');
|
|
130
157
|
|
|
@@ -165,7 +192,7 @@ export async function scaffold(target, options = {}) {
|
|
|
165
192
|
const source = path.join(from, entry);
|
|
166
193
|
const destination = path.join(to, fill(RENAMED.get(entry) ?? entry));
|
|
167
194
|
if ((await stat(source)).isDirectory()) await copy(source, destination);
|
|
168
|
-
else await writeFile(destination, fill(await readFile(source, 'utf8')));
|
|
195
|
+
else await writeFile(destination, fill(keepSections(await readFile(source, 'utf8'), { tests: true, e2e: true })));
|
|
169
196
|
}
|
|
170
197
|
}
|
|
171
198
|
|
package/dist/actions.d.ts
CHANGED
|
@@ -23,11 +23,16 @@ export interface ServerAction<TInput, TResult> {
|
|
|
23
23
|
readonly actionName: string;
|
|
24
24
|
readonly url: string;
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Thrown into the nearest error boundary when the server could not run the action (not for validation errors).
|
|
28
|
+
* `status` is the status of the server's answer. `withheld` is true when the server sent no message, as for a 5xx
|
|
29
|
+
* with error details off: the message is then Netjes's own, which names the action and the status.
|
|
30
|
+
*/
|
|
27
31
|
export declare class ServerActionError extends Error {
|
|
28
32
|
name: string;
|
|
29
33
|
readonly status: number;
|
|
30
|
-
|
|
34
|
+
readonly withheld: boolean;
|
|
35
|
+
constructor(message: string, status: number, withheld?: boolean);
|
|
31
36
|
}
|
|
32
37
|
/** Runs action calls for the page: the router in the browser (fetch, then redirect/refresh/query updates), a fake in tests. */
|
|
33
38
|
export type ActionClient = {
|
package/dist/actions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAoD,MAAM,cAAc,CAAC;AAEhJ,OAAO,EAAE,KAAK,gBAAgB,EAAa,MAAM,aAAa,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,WAAW,CAAC,OAAO,IAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;CAAE,CAAC;AAEhH;;;GAGG;AACH,MAAM,WAAW,YAAY,CAAC,MAAM,EAAE,OAAO;IAC3C,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.tsx"],"names":[],"mappings":"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"}
|
package/dist/actions.js
CHANGED
|
@@ -3,13 +3,19 @@ import { encodeForm } from './form-data.js';
|
|
|
3
3
|
import { ANTIFORGERY_HEADER, COOKIES_HEADER, DATA_HEADER, parseActionResponse } from './payload.js';
|
|
4
4
|
import { usePagePayload } from './router.js';
|
|
5
5
|
import { parseWith } from './schema.js';
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Thrown into the nearest error boundary when the server could not run the action (not for validation errors).
|
|
8
|
+
* `status` is the status of the server's answer. `withheld` is true when the server sent no message, as for a 5xx
|
|
9
|
+
* with error details off: the message is then Netjes's own, which names the action and the status.
|
|
10
|
+
*/
|
|
7
11
|
export class ServerActionError extends Error {
|
|
8
12
|
name = 'ServerActionError';
|
|
9
13
|
status;
|
|
10
|
-
|
|
14
|
+
withheld;
|
|
15
|
+
constructor(message, status, withheld = false) {
|
|
11
16
|
super(message);
|
|
12
17
|
this.status = status;
|
|
18
|
+
this.withheld = withheld;
|
|
13
19
|
}
|
|
14
20
|
}
|
|
15
21
|
let client = null;
|
|
@@ -129,7 +135,7 @@ export function serverAction(name, options = {}) {
|
|
|
129
135
|
const active = client ?? (await readyClient(name));
|
|
130
136
|
const answer = await active.invoke(name, url, input);
|
|
131
137
|
if (!answer.ok && answer.status !== 422) {
|
|
132
|
-
throw new ServerActionError(answer.message ?? `Server action ${name} failed with status ${answer.status}`, answer.status);
|
|
138
|
+
throw new ServerActionError(answer.message ?? `Server action ${name} failed with status ${answer.status}`, answer.status, answer.message === undefined);
|
|
133
139
|
}
|
|
134
140
|
if (!answer.ok) {
|
|
135
141
|
const values = submittedValues(input, active.tokenField?.(), answer.fields);
|
package/dist/actions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAA8C,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAChJ,OAAO,EAAE,cAAc,EAAE,MAAM,aAAc,CAAC;AAC9C,OAAO,EAAyB,SAAS,EAAE,MAAM,aAAa,CAAC;AAqB/D
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.tsx"],"names":[],"mappings":"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"}
|
package/dist/client-entry.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-entry.d.ts","sourceRoot":"","sources":["../src/client-entry.tsx"],"names":[],"mappings":"AACA,OAAO,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"client-entry.d.ts","sourceRoot":"","sources":["../src/client-entry.tsx"],"names":[],"mappings":"AACA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,+BAA+B,CAAC"}
|
package/dist/client-entry.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// Must come first
|
|
2
|
+
// Must come first, ahead of anything that could make a zod schema: turns zod's compiled parsers off (ADR 0036).
|
|
3
|
+
import './zod-jitless.js';
|
|
4
|
+
// Must come before any component module: installs the React Fast Refresh runtime before one runs (empty in builds).
|
|
3
5
|
import '@vitejs/plugin-react/preamble';
|
|
4
6
|
import { createRoot, hydrateRoot } from 'react-dom/client';
|
|
5
7
|
import { pages } from 'virtual:netjes/pages';
|
|
@@ -8,6 +10,7 @@ import { createModuleLoader } from './modules.js';
|
|
|
8
10
|
import { DATA_ELEMENT_ID, SHELL_END_ID, parseInitialPayload } from './payload.js';
|
|
9
11
|
import { Root } from './root.js';
|
|
10
12
|
import { withClockOffset } from './router.js';
|
|
13
|
+
import { BEFORE_INTERACTIVE_MARKER, adoptServerScripts } from './script.js';
|
|
11
14
|
/**
|
|
12
15
|
* The payload is the body's first element, so it is normally parsed by the time this async script runs. If the
|
|
13
16
|
* script won the race, wait for the element rather than for the whole (streaming) document.
|
|
@@ -110,6 +113,17 @@ async function firstPageModules() {
|
|
|
110
113
|
return null;
|
|
111
114
|
}
|
|
112
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* A `<Script strategy="beforeInteractive">` in the server's document puts a marker in the head, which is complete by
|
|
118
|
+
* the time the payload is read. Such a page waits for the end of the shell, where the parser has run the inline ones,
|
|
119
|
+
* then runs the external ones in order and waits for them, before the page's modules run and hydrate (ADR 0044). A
|
|
120
|
+
* page without one loads its modules while the rest of the shell arrives (ADR 0022).
|
|
121
|
+
*/
|
|
122
|
+
const beforeInteractive = document.head.querySelector(`meta[name="${BEFORE_INTERACTIVE_MARKER}"]`) !== null;
|
|
123
|
+
if (beforeInteractive) {
|
|
124
|
+
await shellParsed();
|
|
125
|
+
await adoptServerScripts(payload.document.nonce);
|
|
126
|
+
}
|
|
113
127
|
const modules = await firstPageModules();
|
|
114
128
|
if (modules) {
|
|
115
129
|
const root = _jsx(Root, { payload: payload, modules: modules, loader: loader, dataJson: dataJson });
|
|
@@ -119,7 +133,10 @@ if (modules) {
|
|
|
119
133
|
createRoot(document).render(root);
|
|
120
134
|
}
|
|
121
135
|
else {
|
|
122
|
-
|
|
136
|
+
if (!beforeInteractive) {
|
|
137
|
+
await shellParsed();
|
|
138
|
+
await adoptServerScripts(payload.document.nonce);
|
|
139
|
+
}
|
|
123
140
|
hydrateRoot(document, root);
|
|
124
141
|
}
|
|
125
142
|
}
|
package/dist/client-entry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-entry.js","sourceRoot":"","sources":["../src/client-entry.tsx"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"client-entry.js","sourceRoot":"","sources":["../src/client-entry.tsx"],"names":[],"mappings":"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"}
|
package/dist/deferred.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export declare function revivePayload<T extends PagePayload>(payload: T, source:
|
|
|
21
21
|
export declare function deferredRegistry(): {
|
|
22
22
|
source: DeferredSource;
|
|
23
23
|
resolve(id: string, value: unknown): void;
|
|
24
|
+
/** Fails a value with the server's message; an empty one is a message the server withheld (no error details). */
|
|
24
25
|
reject(id: string, message: string): void;
|
|
25
26
|
/** Rejects every value still pending, e.g. when the stream that was to deliver them ended. */
|
|
26
27
|
rejectPending(message: (id: string) => string): void;
|
|
@@ -32,6 +33,16 @@ export declare function deferredRegistry(): {
|
|
|
32
33
|
* then, page markup with `id="__netjes_v"` would be what that name reads (DOM clobbering).
|
|
33
34
|
*/
|
|
34
35
|
export declare const DEFERRED_BOOTSTRAP = "self.__netjes_d=self.__netjes_d||function(i,v,e){self.__netjes_v[i]=[v,e]};Object.prototype.hasOwnProperty.call(self,'__netjes_v')||(self.__netjes_v={})";
|
|
36
|
+
/**
|
|
37
|
+
* The `script-src` sources that allow Netjes's fixed inline scripts by their hashes, for a policy without a nonce: each
|
|
38
|
+
* `'sha256-…'` in its quotes, separated by spaces, as in `` `script-src 'self' ${CSP_SCRIPT_HASHES}` ``. A fixed script
|
|
39
|
+
* has the same text in every document. In this version there is one, the bootstrap that collects streamed `Page.Defer`
|
|
40
|
+
* values, and a Netjes version that changes it or adds another changes the value. The scripts that deliver those
|
|
41
|
+
* values, and React's scripts that reveal Suspense boundaries, differ from render to render, so no hash covers them.
|
|
42
|
+
* React's script for form actions that are functions is left out too, since its text follows the React version. The
|
|
43
|
+
* same value as `NetjesContentSecurityPolicy.ScriptHashes` in C#.
|
|
44
|
+
*/
|
|
45
|
+
export declare const CSP_SCRIPT_HASHES: string;
|
|
35
46
|
/** JSON that can sit inside a <script> element. */
|
|
36
47
|
export declare function htmlSafeJson(value: unknown): string;
|
|
37
48
|
/** The script that hands one deferred value (or its error) to the browser. */
|
package/dist/deferred.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../src/deferred.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../src/deferred.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,cAAc,CAAC;AAE5D,wHAAwH;AACxH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAAC,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,CAAC;AAE3G,wBAAgB,cAAc,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAuB/C;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC;AAM/D,iHAAiH;AACjH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAoB9E;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,cAAc,GAAG,CAAC,CAW1F;AAED,yFAAyF;AACzF,wBAAgB,gBAAgB;IAa5B,MAAM,EAAiC,cAAc;IACrD,OAAO,KAAK,MAAM,SAAS,OAAO;IAGlC,iHAAiH;IACjH,MAAM,KAAK,MAAM,WAAW,MAAM;IAGlC,8FAA8F;IAC9F,aAAa,UAAU,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM;EAMhD;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,6JAC6H,CAAC;AAE7J;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAgE,CAAC;AAIjG,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAQjG"}
|
package/dist/deferred.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Deferred loader values (Page.Defer in C#): placeholders in the payload that become promises the page reads with
|
|
2
|
+
// React's use() inside a Suspense boundary.
|
|
3
|
+
import { withheldError } from './errors.js';
|
|
1
4
|
export function createDeferred() {
|
|
2
5
|
let resolve;
|
|
3
6
|
let reject;
|
|
@@ -86,8 +89,9 @@ export function deferredRegistry() {
|
|
|
86
89
|
resolve(id, value) {
|
|
87
90
|
entry(id).resolve(value);
|
|
88
91
|
},
|
|
92
|
+
/** Fails a value with the server's message; an empty one is a message the server withheld (no error details). */
|
|
89
93
|
reject(id, message) {
|
|
90
|
-
entry(id).reject(new Error(message));
|
|
94
|
+
entry(id).reject(message === '' ? withheldError() : new Error(message));
|
|
91
95
|
},
|
|
92
96
|
/** Rejects every value still pending, e.g. when the stream that was to deliver them ended. */
|
|
93
97
|
rejectPending(message) {
|
|
@@ -105,6 +109,16 @@ export function deferredRegistry() {
|
|
|
105
109
|
* then, page markup with `id="__netjes_v"` would be what that name reads (DOM clobbering).
|
|
106
110
|
*/
|
|
107
111
|
export const DEFERRED_BOOTSTRAP = "self.__netjes_d=self.__netjes_d||function(i,v,e){self.__netjes_v[i]=[v,e]};Object.prototype.hasOwnProperty.call(self,'__netjes_v')||(self.__netjes_v={})";
|
|
112
|
+
/**
|
|
113
|
+
* The `script-src` sources that allow Netjes's fixed inline scripts by their hashes, for a policy without a nonce: each
|
|
114
|
+
* `'sha256-…'` in its quotes, separated by spaces, as in `` `script-src 'self' ${CSP_SCRIPT_HASHES}` ``. A fixed script
|
|
115
|
+
* has the same text in every document. In this version there is one, the bootstrap that collects streamed `Page.Defer`
|
|
116
|
+
* values, and a Netjes version that changes it or adds another changes the value. The scripts that deliver those
|
|
117
|
+
* values, and React's scripts that reveal Suspense boundaries, differ from render to render, so no hash covers them.
|
|
118
|
+
* React's script for form actions that are functions is left out too, since its text follows the React version. The
|
|
119
|
+
* same value as `NetjesContentSecurityPolicy.ScriptHashes` in C#.
|
|
120
|
+
*/
|
|
121
|
+
export const CSP_SCRIPT_HASHES = "'sha256-FSjVV+FzmXP8KKrLKLdvst/5N/bEWSkde01XzpGKRgs='";
|
|
108
122
|
const UNSAFE = /[<>&\u2028\u2029]/g;
|
|
109
123
|
/** JSON that can sit inside a <script> element. */
|
|
110
124
|
export function htmlSafeJson(value) {
|
package/dist/deferred.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deferred.js","sourceRoot":"","sources":["../src/deferred.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deferred.js","sourceRoot":"","sources":["../src/deferred.ts"],"names":[],"mappings":"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"}
|