@kasperpeulen/vitest-plugin-nextjs 0.0.0-stage → 0.1.0-alpha.0
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 +249 -2
- package/dist/_virtual/_rolldown/runtime.js +14 -0
- package/dist/action-ids.d.ts +18 -0
- package/dist/action-ids.js +44 -0
- package/dist/adapter.d.ts +8 -0
- package/dist/adapter.js +12 -0
- package/dist/app-requests.d.ts +63 -0
- package/dist/app-requests.js +253 -0
- package/dist/browser-context.d.ts +24 -0
- package/dist/browser-context.js +157 -0
- package/dist/build-output.d.ts +68 -0
- package/dist/build-output.js +216 -0
- package/dist/build.d.ts +26 -0
- package/dist/build.js +39 -0
- package/dist/built-files.d.ts +9 -0
- package/dist/built-files.js +22 -0
- package/dist/cache.d.ts +44 -0
- package/dist/cache.js +99 -0
- package/dist/client-components.d.ts +3 -0
- package/dist/client-components.js +4 -0
- package/dist/client-file-key.d.ts +5 -0
- package/dist/client-file-key.js +5 -0
- package/dist/client-files.d.ts +83 -0
- package/dist/client-files.js +186 -0
- package/dist/client-graph.d.ts +94 -0
- package/dist/client-graph.js +266 -0
- package/dist/client-modules.d.ts +10 -0
- package/dist/client-modules.js +43 -0
- package/dist/client.d.ts +42 -0
- package/dist/client.js +263 -0
- package/dist/commonjs.d.ts +44 -0
- package/dist/commonjs.js +111 -0
- package/dist/compat/browser/client.d.ts +19 -0
- package/dist/compat/browser/client.js +13 -0
- package/dist/compat/build.d.ts +145 -0
- package/dist/compat/build.js +149 -0
- package/dist/compat/checks.d.ts +16 -0
- package/dist/compat/checks.js +148 -0
- package/dist/compat/patches.d.ts +13 -0
- package/dist/compat/patches.js +30 -0
- package/dist/compat/paths.d.ts +74 -0
- package/dist/compat/paths.js +160 -0
- package/dist/compat/rsc/handlers.d.ts +2 -0
- package/dist/compat/rsc/handlers.js +2 -0
- package/dist/compat/rsc/prerender.d.ts +10 -0
- package/dist/compat/rsc/prerender.js +9 -0
- package/dist/compat/server/headers.d.ts +3 -0
- package/dist/compat/server/headers.js +3 -0
- package/dist/compat/ssr/build-output.d.ts +4 -0
- package/dist/compat/ssr/build-output.js +3 -0
- package/dist/compat/ssr/cache.d.ts +6 -0
- package/dist/compat/ssr/cache.js +6 -0
- package/dist/compat/ssr/handler.d.ts +8 -0
- package/dist/compat/ssr/handler.js +8 -0
- package/dist/compat/ssr/node-server.d.ts +5 -0
- package/dist/compat/ssr/node-server.js +4 -0
- package/dist/compat/ssr/render-errors.d.ts +4 -0
- package/dist/compat/ssr/render-errors.js +4 -0
- package/dist/compat/ssr/senders.d.ts +6 -0
- package/dist/compat/ssr/senders.js +6 -0
- package/dist/compat/types.d.ts +8 -0
- package/dist/compat/types.js +1 -0
- package/dist/compile.d.ts +31 -0
- package/dist/compile.js +140 -0
- package/dist/disk.d.ts +16 -0
- package/dist/disk.js +13 -0
- package/dist/document-loads.d.ts +15 -0
- package/dist/document-loads.js +53 -0
- package/dist/document.d.ts +79 -0
- package/dist/document.js +328 -0
- package/dist/downloads.d.ts +15 -0
- package/dist/downloads.js +71 -0
- package/dist/esm-require.d.ts +11 -0
- package/dist/esm-require.js +32 -0
- package/dist/fast-crypto/index.js +1093 -0
- package/dist/fast-crypto.d.ts +20 -0
- package/dist/fast-crypto.js +151 -0
- package/dist/flight.d.ts +19 -0
- package/dist/flight.js +42 -0
- package/dist/form-submission.d.ts +15 -0
- package/dist/form-submission.js +27 -0
- package/dist/from-page.d.ts +5 -0
- package/dist/from-page.js +44 -0
- package/dist/globals.d.ts +1 -0
- package/dist/globals.js +197 -0
- package/dist/host-document.d.ts +26 -0
- package/dist/host-document.js +34 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.js +281 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +3 -0
- package/dist/leftovers.d.ts +11 -0
- package/dist/leftovers.js +55 -0
- package/dist/mode.d.ts +169 -0
- package/dist/mode.js +31 -0
- package/dist/node/LICENSES.md +3540 -0
- package/dist/node/assert/strict.js +29 -0
- package/dist/node/assert.js +3044 -0
- package/dist/node/buffer.js +1499 -0
- package/dist/node/child_process.js +45 -0
- package/dist/node/cluster.js +85 -0
- package/dist/node/console.js +96 -0
- package/dist/node/constants.js +495 -0
- package/dist/node/crypto.js +1388 -0
- package/dist/node/dgram.js +78 -0
- package/dist/node/diagnostics_channel.js +122 -0
- package/dist/node/dns/promises.js +129 -0
- package/dist/node/dns.js +137 -0
- package/dist/node/domain.js +43 -0
- package/dist/node/events.js +1155 -0
- package/dist/node/fs/promises.js +40 -0
- package/dist/node/fs.js +10375 -0
- package/dist/node/http.js +326 -0
- package/dist/node/http2.js +305 -0
- package/dist/node/https.js +57 -0
- package/dist/node/inspector/promises.js +66 -0
- package/dist/node/inspector.js +76 -0
- package/dist/node/module.js +205 -0
- package/dist/node/net.js +392 -0
- package/dist/node/os.js +259 -0
- package/dist/node/path/posix.js +25 -0
- package/dist/node/path/win32.js +25 -0
- package/dist/node/path.js +384 -0
- package/dist/node/perf_hooks.js +313 -0
- package/dist/node/process.js +452 -0
- package/dist/node/punycode.js +178 -0
- package/dist/node/querystring.js +934 -0
- package/dist/node/readline/promises.js +71 -0
- package/dist/node/readline.js +56 -0
- package/dist/node/repl.js +44 -0
- package/dist/node/sqlite.js +22 -0
- package/dist/node/stream/consumers.js +47 -0
- package/dist/node/stream/promises.js +6 -0
- package/dist/node/stream/web.js +52 -0
- package/dist/node/stream.js +4323 -0
- package/dist/node/string_decoder.js +276 -0
- package/dist/node/sys.js +6 -0
- package/dist/node/timers/promises.js +71 -0
- package/dist/node/timers.js +133 -0
- package/dist/node/tls.js +122 -0
- package/dist/node/trace_events.js +23 -0
- package/dist/node/tty.js +69 -0
- package/dist/node/url.js +1426 -0
- package/dist/node/util/types.js +1456 -0
- package/dist/node/util.js +4807 -0
- package/dist/node/v8.js +160 -0
- package/dist/node/vm.js +88 -0
- package/dist/node/wasi.js +16 -0
- package/dist/node/worker_threads.js +123 -0
- package/dist/node/zlib.js +1396 -0
- package/dist/node-builtins.d.ts +40 -0
- package/dist/node-builtins.js +74 -0
- package/dist/node-on-page.d.ts +46 -0
- package/dist/node-on-page.js +101 -0
- package/dist/node-platform.d.ts +36 -0
- package/dist/node-platform.js +152 -0
- package/dist/node-rendered.d.ts +21 -0
- package/dist/node-rendered.js +26 -0
- package/dist/node-server.d.ts +46 -0
- package/dist/node-server.js +193 -0
- package/dist/optimizer-cache-key.d.ts +26 -0
- package/dist/optimizer-cache-key.js +73 -0
- package/dist/own-package.d.ts +1 -0
- package/dist/own-package.js +6 -0
- package/dist/page-store.d.ts +33 -0
- package/dist/page-store.js +80 -0
- package/dist/page-timers.d.ts +22 -0
- package/dist/page-timers.js +47 -0
- package/dist/page.d.ts +112 -0
- package/dist/page.js +549 -0
- package/dist/paths.d.ts +13 -0
- package/dist/paths.js +47 -0
- package/dist/plugin.d.ts +22 -0
- package/dist/plugin.js +995 -0
- package/dist/prerender-verdict.d.ts +8 -0
- package/dist/prerender-verdict.js +67 -0
- package/dist/project/context.d.ts +546 -0
- package/dist/project/context.js +111 -0
- package/dist/project/entries.d.ts +42 -0
- package/dist/project/entries.js +189 -0
- package/dist/project/env-worker.d.ts +1 -0
- package/dist/project/env-worker.js +9 -0
- package/dist/project/env.d.ts +36 -0
- package/dist/project/env.js +82 -0
- package/dist/project/layers.d.ts +31 -0
- package/dist/project/layers.js +150 -0
- package/dist/project/loaders.d.ts +71 -0
- package/dist/project/loaders.js +300 -0
- package/dist/project/metadata.d.ts +8 -0
- package/dist/project/metadata.js +34 -0
- package/dist/project/module-exports.d.ts +29 -0
- package/dist/project/module-exports.js +77 -0
- package/dist/project/routes.d.ts +19 -0
- package/dist/project/routes.js +92 -0
- package/dist/project/routing.d.ts +46 -0
- package/dist/project/routing.js +280 -0
- package/dist/project/transform.d.ts +8 -0
- package/dist/project/transform.js +110 -0
- package/dist/project/webpack.d.ts +46 -0
- package/dist/project/webpack.js +160 -0
- package/dist/project.d.ts +264 -0
- package/dist/project.js +58 -0
- package/dist/registry-global.d.ts +5 -0
- package/dist/registry-global.js +5 -0
- package/dist/registry.d.ts +241 -0
- package/dist/registry.js +30 -0
- package/dist/route-chunks.d.ts +13 -0
- package/dist/route-chunks.js +32 -0
- package/dist/route-lookup.d.ts +34 -0
- package/dist/route-lookup.js +207 -0
- package/dist/routes-ahead-shared.d.ts +17 -0
- package/dist/routes-ahead-shared.js +9 -0
- package/dist/routes-ahead.d.ts +10 -0
- package/dist/routes-ahead.js +54 -0
- package/dist/rsc.d.ts +19 -0
- package/dist/rsc.js +171 -0
- package/dist/server-action.d.ts +9 -0
- package/dist/server-action.js +15 -0
- package/dist/server-code.d.ts +176 -0
- package/dist/server-code.js +357 -0
- package/dist/server-in-front.d.ts +37 -0
- package/dist/server-in-front.js +90 -0
- package/dist/server-layers.d.ts +22 -0
- package/dist/server-layers.js +33 -0
- package/dist/setup-browser.d.ts +1 -0
- package/dist/setup-browser.js +8 -0
- package/dist/setup-node.d.ts +1 -0
- package/dist/setup-node.js +6 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +62 -0
- package/dist/speed-features.d.ts +13 -0
- package/dist/speed-features.js +95 -0
- package/dist/ssr.d.ts +70 -0
- package/dist/ssr.js +480 -0
- package/dist/static-build.d.ts +36 -0
- package/dist/static-build.js +92 -0
- package/dist/storage.d.ts +31 -0
- package/dist/storage.js +94 -0
- package/dist/styles-shared.d.ts +137 -0
- package/dist/styles-shared.js +124 -0
- package/dist/styles.d.ts +102 -0
- package/dist/styles.js +730 -0
- package/dist/stylesheet-versions.d.ts +17 -0
- package/dist/stylesheet-versions.js +43 -0
- package/dist/tester.html +10 -0
- package/dist/use-cache.d.ts +15 -0
- package/dist/use-cache.js +93 -0
- package/dist/vitest-version.d.ts +6 -0
- package/dist/vitest-version.js +12 -0
- package/package.json +125 -3
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/fast-crypto.d.ts
|
|
2
|
+
/** The file of the stand-ins, which the modules below import. */
|
|
3
|
+
declare function fastCryptoFile(): string;
|
|
4
|
+
/**
|
|
5
|
+
* The name of the stand-in module for an import of a server layer, if it has
|
|
6
|
+
* one: a package that hashes passwords, or `node:crypto`, whose module is the
|
|
7
|
+
* layer's own with the stand-ins in it, `nodeCrypto`.
|
|
8
|
+
*/
|
|
9
|
+
declare function fastCryptoModuleOf(source: string): string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* The code of a stand-in module by its name: for `node-crypto`, the layer's
|
|
12
|
+
* `node:crypto`, `nodeCrypto`, with its `pbkdf2`, `scrypt` and `argon2` the
|
|
13
|
+
* stand-ins. That is the file of the package's module in a browser, and
|
|
14
|
+
* Node's own in a worker of Node.js (node-builtins.ts).
|
|
15
|
+
*/
|
|
16
|
+
declare function fastCryptoModule(name: string, nodeCrypto: string): string | undefined;
|
|
17
|
+
/** The module of the setup file: Web Crypto's PBKDF2 a stand-in, or nothing. */
|
|
18
|
+
declare function fastCryptoSetup(enabled: boolean): string;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { fastCryptoFile, fastCryptoModule, fastCryptoModuleOf, fastCryptoSetup };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { isBuiltin } from "node:module";
|
|
2
|
+
import { normalizePath } from "vite";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
//#region src/fast-crypto.ts
|
|
7
|
+
const ownFile = fileURLToPath(import.meta.url);
|
|
8
|
+
const standInsFile = normalizePath(path.join(path.dirname(ownFile), path.extname(ownFile) === ".ts" ? "../dist/fast-crypto/index.js" : "./fast-crypto/index.js"));
|
|
9
|
+
/** The file of the stand-ins, which the modules below import. */
|
|
10
|
+
function fastCryptoFile() {
|
|
11
|
+
if (!fs.existsSync(standInsFile)) throw new Error(`vitest-plugin-rsc: no ${standInsFile}, the package is not built: run \`pnpm build\``);
|
|
12
|
+
return standInsFile;
|
|
13
|
+
}
|
|
14
|
+
const packages = {
|
|
15
|
+
bcryptjs: {
|
|
16
|
+
factory: `bcrypt("bcryptjs")`,
|
|
17
|
+
names: [
|
|
18
|
+
"genSaltSync",
|
|
19
|
+
"genSalt",
|
|
20
|
+
"hashSync",
|
|
21
|
+
"hash",
|
|
22
|
+
"compareSync",
|
|
23
|
+
"compare",
|
|
24
|
+
"getRounds",
|
|
25
|
+
"getSalt",
|
|
26
|
+
"truncates",
|
|
27
|
+
"encodeBase64",
|
|
28
|
+
"decodeBase64",
|
|
29
|
+
"setRandomFallback"
|
|
30
|
+
],
|
|
31
|
+
specifiers: ["bcryptjs"]
|
|
32
|
+
},
|
|
33
|
+
bcrypt: {
|
|
34
|
+
factory: `bcrypt("bcrypt")`,
|
|
35
|
+
names: [
|
|
36
|
+
"genSaltSync",
|
|
37
|
+
"genSalt",
|
|
38
|
+
"hashSync",
|
|
39
|
+
"hash",
|
|
40
|
+
"compareSync",
|
|
41
|
+
"compare",
|
|
42
|
+
"getRounds"
|
|
43
|
+
],
|
|
44
|
+
specifiers: ["bcrypt"]
|
|
45
|
+
},
|
|
46
|
+
"node-rs-bcrypt": {
|
|
47
|
+
factory: "nodeRsBcrypt()",
|
|
48
|
+
names: [
|
|
49
|
+
"DEFAULT_COST",
|
|
50
|
+
"genSaltSync",
|
|
51
|
+
"genSalt",
|
|
52
|
+
"hashSync",
|
|
53
|
+
"hash",
|
|
54
|
+
"verifySync",
|
|
55
|
+
"verify",
|
|
56
|
+
"compareSync",
|
|
57
|
+
"compare"
|
|
58
|
+
],
|
|
59
|
+
specifiers: ["@node-rs/bcrypt"]
|
|
60
|
+
},
|
|
61
|
+
argon2: {
|
|
62
|
+
factory: "argon2()",
|
|
63
|
+
names: [
|
|
64
|
+
"argon2d",
|
|
65
|
+
"argon2i",
|
|
66
|
+
"argon2id",
|
|
67
|
+
"hash",
|
|
68
|
+
"verify",
|
|
69
|
+
"needsRehash"
|
|
70
|
+
],
|
|
71
|
+
specifiers: ["argon2"]
|
|
72
|
+
},
|
|
73
|
+
"node-rs-argon2": {
|
|
74
|
+
factory: "nodeRsArgon2()",
|
|
75
|
+
names: [
|
|
76
|
+
"Algorithm",
|
|
77
|
+
"Version",
|
|
78
|
+
"hash",
|
|
79
|
+
"hashSync",
|
|
80
|
+
"hashRaw",
|
|
81
|
+
"hashRawSync",
|
|
82
|
+
"verify",
|
|
83
|
+
"verifySync"
|
|
84
|
+
],
|
|
85
|
+
specifiers: ["@node-rs/argon2"]
|
|
86
|
+
},
|
|
87
|
+
"noble-scrypt": {
|
|
88
|
+
factory: "nobleScrypt()",
|
|
89
|
+
names: ["scrypt", "scryptAsync"],
|
|
90
|
+
specifiers: ["@noble/hashes/scrypt", "@noble/hashes/scrypt.js"]
|
|
91
|
+
},
|
|
92
|
+
"noble-pbkdf2": {
|
|
93
|
+
factory: "noblePbkdf2()",
|
|
94
|
+
names: ["pbkdf2", "pbkdf2Async"],
|
|
95
|
+
specifiers: ["@noble/hashes/pbkdf2", "@noble/hashes/pbkdf2.js"]
|
|
96
|
+
},
|
|
97
|
+
"noble-argon2": {
|
|
98
|
+
factory: "nobleArgon2()",
|
|
99
|
+
names: [
|
|
100
|
+
"argon2d",
|
|
101
|
+
"argon2i",
|
|
102
|
+
"argon2id",
|
|
103
|
+
"argon2dAsync",
|
|
104
|
+
"argon2iAsync",
|
|
105
|
+
"argon2idAsync"
|
|
106
|
+
],
|
|
107
|
+
specifiers: ["@noble/hashes/argon2", "@noble/hashes/argon2.js"]
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const moduleOfSpecifier = new Map(Object.entries(packages).flatMap(([name, { specifiers }]) => specifiers.map((specifier) => [specifier, name])));
|
|
111
|
+
/**
|
|
112
|
+
* The name of the stand-in module for an import of a server layer, if it has
|
|
113
|
+
* one: a package that hashes passwords, or `node:crypto`, whose module is the
|
|
114
|
+
* layer's own with the stand-ins in it, `nodeCrypto`.
|
|
115
|
+
*/
|
|
116
|
+
function fastCryptoModuleOf(source) {
|
|
117
|
+
if (source === "crypto" || source === "node:crypto") return "node-crypto";
|
|
118
|
+
return moduleOfSpecifier.get(source);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The code of a stand-in module by its name: for `node-crypto`, the layer's
|
|
122
|
+
* `node:crypto`, `nodeCrypto`, with its `pbkdf2`, `scrypt` and `argon2` the
|
|
123
|
+
* stand-ins. That is the file of the package's module in a browser, and
|
|
124
|
+
* Node's own in a worker of Node.js (node-builtins.ts).
|
|
125
|
+
*/
|
|
126
|
+
function fastCryptoModule(name, nodeCrypto) {
|
|
127
|
+
const from = JSON.stringify(fastCryptoFile());
|
|
128
|
+
if (name === "node-crypto") {
|
|
129
|
+
const own = JSON.stringify(nodeCrypto);
|
|
130
|
+
const names = [
|
|
131
|
+
"pbkdf2",
|
|
132
|
+
"pbkdf2Sync",
|
|
133
|
+
"scrypt",
|
|
134
|
+
"scryptSync",
|
|
135
|
+
"argon2",
|
|
136
|
+
"argon2Sync"
|
|
137
|
+
];
|
|
138
|
+
const reexports = isBuiltin(nodeCrypto) ? `export const { ${Object.keys(process.getBuiltinModule("node:crypto")).filter((key) => /^[A-Za-z_$][\w$]*$/.test(key) && !names.includes(key)).join(", ")} } = own;\n` : `export * from ${own};\n`;
|
|
139
|
+
return `import own from ${own};\nimport { Buffer } from "node:buffer";\nimport { nodeCrypto } from ${from};\n` + reexports + `const fast = nodeCrypto(Buffer);\nexport const { ${names.join(", ")} } = fast;\nexport default { ...own, ...fast };\n`;
|
|
140
|
+
}
|
|
141
|
+
const standIn = packages[name];
|
|
142
|
+
if (!standIn) return;
|
|
143
|
+
return `import { ${standIn.factory.replace(/\(.*$/, "")} } from ${from};\nconst standIns = ${standIn.factory};\nexport const { ${standIn.names.join(", ")} } = standIns;\nexport default standIns;\n`;
|
|
144
|
+
}
|
|
145
|
+
/** The module of the setup file: Web Crypto's PBKDF2 a stand-in, or nothing. */
|
|
146
|
+
function fastCryptoSetup(enabled) {
|
|
147
|
+
if (!enabled) return "export {};\n";
|
|
148
|
+
return `import { installWebCrypto } from ${JSON.stringify(fastCryptoFile())};\ninstallWebCrypto();\n`;
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
export { fastCryptoFile, fastCryptoModule, fastCryptoModuleOf, fastCryptoSetup };
|
package/dist/flight.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/flight.d.ts
|
|
2
|
+
declare const rscFlightCodec: {
|
|
3
|
+
readonly server: readonly ["renderToReadableStream", "decodeReply", "decodeReplyFromAsyncIterable", "decodeAction", "decodeFormState", "createTemporaryReferenceSet", "registerServerReference", "registerClientReference", "createClientModuleProxy"];
|
|
4
|
+
readonly static: readonly ["prerender"];
|
|
5
|
+
readonly client: readonly ["createFromReadableStream", "encodeReply", "createTemporaryReferenceSet"];
|
|
6
|
+
};
|
|
7
|
+
type FlightEntry = keyof typeof rscFlightCodec;
|
|
8
|
+
/** The adapters of one entry: a function for each of its exports. */
|
|
9
|
+
type FlightAdapters<Entry extends FlightEntry> = Record<(typeof rscFlightCodec)[Entry][number], (...args: any[]) => unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* The module that the rsc layer gets for an entry of Next's codec. It has
|
|
12
|
+
* every export of the entry, as the installed `next` has it, and forwards it
|
|
13
|
+
* to the adapter that rsc.ts puts in `registry`. The lookup is deferred to
|
|
14
|
+
* the call, so a pre-bundled chunk can load before rsc.ts has. An export
|
|
15
|
+
* without an adapter throws when it is called.
|
|
16
|
+
*/
|
|
17
|
+
declare function flightBridge(entry: FlightEntry, exports: string[], nextVersion: string, registry: string): string;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { FlightAdapters, FlightEntry, flightBridge, rscFlightCodec };
|
package/dist/flight.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/flight.ts
|
|
2
|
+
const rscFlightCodec = {
|
|
3
|
+
server: [
|
|
4
|
+
"renderToReadableStream",
|
|
5
|
+
"decodeReply",
|
|
6
|
+
"decodeReplyFromAsyncIterable",
|
|
7
|
+
"decodeAction",
|
|
8
|
+
"decodeFormState",
|
|
9
|
+
"createTemporaryReferenceSet",
|
|
10
|
+
"registerServerReference",
|
|
11
|
+
"registerClientReference",
|
|
12
|
+
"createClientModuleProxy"
|
|
13
|
+
],
|
|
14
|
+
static: ["prerender"],
|
|
15
|
+
client: [
|
|
16
|
+
"createFromReadableStream",
|
|
17
|
+
"encodeReply",
|
|
18
|
+
"createTemporaryReferenceSet"
|
|
19
|
+
]
|
|
20
|
+
};
|
|
21
|
+
const owners = {
|
|
22
|
+
server: "flightServer",
|
|
23
|
+
static: "flightStatic",
|
|
24
|
+
client: "flightClient"
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The module that the rsc layer gets for an entry of Next's codec. It has
|
|
28
|
+
* every export of the entry, as the installed `next` has it, and forwards it
|
|
29
|
+
* to the adapter that rsc.ts puts in `registry`. The lookup is deferred to
|
|
30
|
+
* the call, so a pre-bundled chunk can load before rsc.ts has. An export
|
|
31
|
+
* without an adapter throws when it is called.
|
|
32
|
+
*/
|
|
33
|
+
function flightBridge(entry, exports, nextVersion, registry) {
|
|
34
|
+
const adapted = rscFlightCodec[entry];
|
|
35
|
+
return exports.map((name) => {
|
|
36
|
+
if (adapted.includes(name)) return `export const ${name} = (...args) => ${registry}.${owners[entry]}.${name}(...args);`;
|
|
37
|
+
const message = `vitest-plugin-rsc: \`${name}\` of Next's Flight codec is not supported in the rsc layer (next@${nextVersion}).`;
|
|
38
|
+
return `export const ${name} = () => { throw new Error(${JSON.stringify(message)}); };`;
|
|
39
|
+
}).join("\n");
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { flightBridge, rscFlightCodec };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/form-submission.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The encoding of a submission whose navigation `source` is: the
|
|
4
|
+
* `formenctype` of the button that submits the form, or the `enctype` of the
|
|
5
|
+
* form, which `form.submit()` submits itself.
|
|
6
|
+
*/
|
|
7
|
+
declare function enctypeOf(source: Element | null): string;
|
|
8
|
+
/**
|
|
9
|
+
* The body of a form with the entries of `formData`, in the encoding
|
|
10
|
+
* `enctype`. A `Blob` with the type as a browser sends it, without a charset:
|
|
11
|
+
* Next's server tells a form from a Server Action by the exact type.
|
|
12
|
+
*/
|
|
13
|
+
declare function formBody(formData: FormData, enctype: string): FormData | Blob;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { enctypeOf, formBody };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/form-submission.ts
|
|
2
|
+
/**
|
|
3
|
+
* The encoding of a submission whose navigation `source` is: the
|
|
4
|
+
* `formenctype` of the button that submits the form, or the `enctype` of the
|
|
5
|
+
* form, which `form.submit()` submits itself.
|
|
6
|
+
*/
|
|
7
|
+
function enctypeOf(source) {
|
|
8
|
+
if (source instanceof HTMLFormElement) return source.enctype;
|
|
9
|
+
if (source instanceof HTMLButtonElement || source instanceof HTMLInputElement) {
|
|
10
|
+
if (source.hasAttribute("formenctype")) return source.formEnctype;
|
|
11
|
+
if (source.form) return source.form.enctype;
|
|
12
|
+
}
|
|
13
|
+
return "application/x-www-form-urlencoded";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The body of a form with the entries of `formData`, in the encoding
|
|
17
|
+
* `enctype`. A `Blob` with the type as a browser sends it, without a charset:
|
|
18
|
+
* Next's server tells a form from a Server Action by the exact type.
|
|
19
|
+
*/
|
|
20
|
+
function formBody(formData, enctype) {
|
|
21
|
+
if (enctype === "multipart/form-data") return formData;
|
|
22
|
+
const entries = Array.from(formData, ([name, value]) => [name, typeof value === "string" ? value : value.name]);
|
|
23
|
+
if (enctype === "text/plain") return new Blob([entries.map(([name, value]) => `${name}=${value}\r\n`).join("")], { type: "text/plain" });
|
|
24
|
+
return new Blob([String(new URLSearchParams(entries))], { type: "application/x-www-form-urlencoded" });
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { enctypeOf, formBody };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
//#region src/from-page.d.ts
|
|
2
|
+
/** `input` and `init` of a request of the page, as the server's `Request` takes them. */
|
|
3
|
+
declare function fromPage(input: RequestInfo | URL, init?: RequestInit): [RequestInfo | URL, RequestInit | undefined];
|
|
4
|
+
//#endregion
|
|
5
|
+
export { fromPage };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/from-page.ts
|
|
2
|
+
/** `input` and `init` of a request of the page, as the server's `Request` takes them. */
|
|
3
|
+
function fromPage(input, init) {
|
|
4
|
+
if (window.Request === globalThis.Request) return [input, init];
|
|
5
|
+
if (input instanceof window.Request) {
|
|
6
|
+
const { url, method, headers, body, signal, redirect, credentials } = input.body ? input.clone() : input;
|
|
7
|
+
init = {
|
|
8
|
+
method,
|
|
9
|
+
headers,
|
|
10
|
+
body,
|
|
11
|
+
signal,
|
|
12
|
+
redirect,
|
|
13
|
+
credentials,
|
|
14
|
+
...init
|
|
15
|
+
};
|
|
16
|
+
input = url;
|
|
17
|
+
}
|
|
18
|
+
input = new URL(String(input), window.location.href);
|
|
19
|
+
if (!init) return [input, init];
|
|
20
|
+
const headers = new Headers(init.headers ? [...new window.Headers(init.headers)] : void 0);
|
|
21
|
+
let { body, signal } = init;
|
|
22
|
+
if (body instanceof window.FormData || body instanceof window.Blob) {
|
|
23
|
+
const read = new window.Response(body);
|
|
24
|
+
const type = read.headers.get("content-type");
|
|
25
|
+
if (type && !headers.has("content-type")) headers.set("content-type", type);
|
|
26
|
+
body = read.body;
|
|
27
|
+
}
|
|
28
|
+
if (signal && !(signal instanceof AbortSignal)) {
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
const page = signal;
|
|
31
|
+
if (page.aborted) controller.abort(page.reason);
|
|
32
|
+
else page.addEventListener("abort", () => controller.abort(page.reason), { once: true });
|
|
33
|
+
signal = controller.signal;
|
|
34
|
+
}
|
|
35
|
+
return [input, {
|
|
36
|
+
...init,
|
|
37
|
+
headers,
|
|
38
|
+
body,
|
|
39
|
+
signal,
|
|
40
|
+
...body ? { duplex: "half" } : {}
|
|
41
|
+
}];
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { fromPage };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/globals.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
import env from "virtual:vitest-plugin-rsc/next-env";
|
|
5
|
+
import pageHost from "virtual:vitest-plugin-rsc/page-host";
|
|
6
|
+
import { SequentialAsyncLocalStorage, asyncFunctionHooks, enterAmbientScope } from "@kasperpeulen/vitest-plugin-rsc/internal/async-local-storage";
|
|
7
|
+
//#region src/globals.ts
|
|
8
|
+
const { Request: NativeRequest, Response: NativeResponse, Headers } = globalThis;
|
|
9
|
+
function headersOf(init, input) {
|
|
10
|
+
if (init?.headers) return new Headers(init.headers);
|
|
11
|
+
return new Headers(input instanceof NativeRequest ? input.headers : void 0);
|
|
12
|
+
}
|
|
13
|
+
var ServerRequest = class ServerRequest extends NativeRequest {
|
|
14
|
+
#headers;
|
|
15
|
+
constructor(input, init) {
|
|
16
|
+
const body = init?.body;
|
|
17
|
+
if (body && typeof body.on === "function" && typeof body.pipe === "function") init = {
|
|
18
|
+
...init,
|
|
19
|
+
body: new ReadableStream({
|
|
20
|
+
start(controller) {
|
|
21
|
+
body.on("data", (chunk) => controller.enqueue(typeof chunk === "string" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk)));
|
|
22
|
+
body.on("end", () => controller.close());
|
|
23
|
+
body.on("error", (error) => controller.error(error));
|
|
24
|
+
},
|
|
25
|
+
cancel: (reason) => body.destroy?.(reason)
|
|
26
|
+
})
|
|
27
|
+
};
|
|
28
|
+
super(input, init?.body ? {
|
|
29
|
+
duplex: "half",
|
|
30
|
+
...init
|
|
31
|
+
} : init);
|
|
32
|
+
this.#headers = headersOf(init, input);
|
|
33
|
+
const contentType = super.headers.get("content-type");
|
|
34
|
+
if (contentType && !this.#headers.has("content-type")) this.#headers.set("content-type", contentType);
|
|
35
|
+
}
|
|
36
|
+
get headers() {
|
|
37
|
+
return this.#headers;
|
|
38
|
+
}
|
|
39
|
+
clone() {
|
|
40
|
+
return new ServerRequest(super.clone(), { headers: this.#headers });
|
|
41
|
+
}
|
|
42
|
+
static [Symbol.hasInstance](value) {
|
|
43
|
+
return Function.prototype[Symbol.hasInstance].call(this === ServerRequest ? NativeRequest : this, value);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var ServerResponse = class ServerResponse extends NativeResponse {
|
|
47
|
+
#headers;
|
|
48
|
+
constructor(body, init) {
|
|
49
|
+
super(body, init);
|
|
50
|
+
this.#headers = headersOf(init);
|
|
51
|
+
const contentType = super.headers.get("content-type");
|
|
52
|
+
if (contentType && !this.#headers.has("content-type")) this.#headers.set("content-type", contentType);
|
|
53
|
+
}
|
|
54
|
+
get headers() {
|
|
55
|
+
return this.#headers;
|
|
56
|
+
}
|
|
57
|
+
clone() {
|
|
58
|
+
const clone = super.clone();
|
|
59
|
+
return new ServerResponse(clone.body, {
|
|
60
|
+
status: clone.status,
|
|
61
|
+
statusText: clone.statusText,
|
|
62
|
+
headers: this.#headers
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
static json(data, init) {
|
|
66
|
+
const json = NativeResponse.json(data, init);
|
|
67
|
+
const headers = headersOf(init);
|
|
68
|
+
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
69
|
+
return new ServerResponse(json.body, {
|
|
70
|
+
status: json.status,
|
|
71
|
+
statusText: json.statusText,
|
|
72
|
+
headers
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
static [Symbol.hasInstance](value) {
|
|
76
|
+
return Function.prototype[Symbol.hasInstance].call(this === ServerResponse ? NativeResponse : this, value);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
registry.Request = ServerRequest;
|
|
80
|
+
registry.Response = ServerResponse;
|
|
81
|
+
registry.Headers = Headers;
|
|
82
|
+
registry.serverDir = () => pageHost.serverDir;
|
|
83
|
+
registry.enterRequestScope = enterAmbientScope;
|
|
84
|
+
registry.openedByRequest = new SequentialAsyncLocalStorage();
|
|
85
|
+
registry.asyncFunctionHooks = asyncFunctionHooks;
|
|
86
|
+
const nativeQueueMicrotask = globalThis.queueMicrotask;
|
|
87
|
+
registry.queueMicrotask = (callback) => nativeQueueMicrotask(SequentialAsyncLocalStorage.bind(callback));
|
|
88
|
+
const renders = /* @__PURE__ */ new WeakMap();
|
|
89
|
+
registry.performWork = (request, performWork) => {
|
|
90
|
+
let inStores = renders.get(request);
|
|
91
|
+
if (!inStores) renders.set(request, inStores = SequentialAsyncLocalStorage.snapshot());
|
|
92
|
+
inStores(performWork, request);
|
|
93
|
+
};
|
|
94
|
+
registry.fetch = (input, init) => pageHost.serverFetch(input, init);
|
|
95
|
+
registry.network = (input, init) => pageHost.serverFetch(input, init);
|
|
96
|
+
const scope = globalThis;
|
|
97
|
+
scope.process ??= { env: {} };
|
|
98
|
+
scope.process.env ??= {};
|
|
99
|
+
for (const [name, value] of Object.entries(env)) scope.process.env[name] ??= value;
|
|
100
|
+
scope.global ??= scope;
|
|
101
|
+
scope.global.process ??= scope.process;
|
|
102
|
+
scope.Buffer ??= Buffer;
|
|
103
|
+
const takesUint8Array = (() => {
|
|
104
|
+
try {
|
|
105
|
+
return Buffer.from([0, 1]).indexOf(new Uint8Array([1])) === 1;
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
})();
|
|
110
|
+
for (const method of takesUint8Array ? [] : ["indexOf", "lastIndexOf"]) {
|
|
111
|
+
const original = Buffer.prototype[method];
|
|
112
|
+
Buffer.prototype[method] = function(value, ...rest) {
|
|
113
|
+
if (value instanceof Uint8Array && !Buffer.isBuffer(value)) value = Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
114
|
+
return original.call(this, value, ...rest);
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (!Buffer.isEncoding("base64url")) {
|
|
118
|
+
const isBase64url = (encoding) => typeof encoding === "string" && encoding.toLowerCase() === "base64url";
|
|
119
|
+
const base64 = (text) => text.replaceAll("-", "+").replaceAll("_", "/");
|
|
120
|
+
const base64url = (text) => text.replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
121
|
+
const statics = Buffer;
|
|
122
|
+
const { from, byteLength, isEncoding } = statics;
|
|
123
|
+
statics.from = function(value, encoding, ...rest) {
|
|
124
|
+
return isBase64url(encoding) && typeof value === "string" ? from.call(this, base64(value), "base64") : from.call(this, value, encoding, ...rest);
|
|
125
|
+
};
|
|
126
|
+
statics.byteLength = function(value, encoding) {
|
|
127
|
+
return isBase64url(encoding) && typeof value === "string" ? byteLength.call(this, base64(value), "base64") : byteLength.call(this, value, encoding);
|
|
128
|
+
};
|
|
129
|
+
statics.isEncoding = (encoding) => isBase64url(encoding) || isEncoding.call(Buffer, encoding);
|
|
130
|
+
const prototype = Buffer.prototype;
|
|
131
|
+
const toString = prototype.toString;
|
|
132
|
+
const write = prototype.write;
|
|
133
|
+
prototype.toString = function(encoding, ...rest) {
|
|
134
|
+
return isBase64url(encoding) ? base64url(toString.apply(this, ["base64", ...rest])) : toString.apply(this, [encoding, ...rest]);
|
|
135
|
+
};
|
|
136
|
+
prototype.write = function(text, ...rest) {
|
|
137
|
+
const at = rest.findLastIndex((value) => typeof value === "string");
|
|
138
|
+
if (at === -1 || !isBase64url(rest[at])) return write.apply(this, [text, ...rest]);
|
|
139
|
+
const args = [...rest];
|
|
140
|
+
args[at] = "base64";
|
|
141
|
+
return write.apply(this, [base64(text), ...args]);
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
scope.AsyncLocalStorage ??= AsyncLocalStorage;
|
|
145
|
+
const immediates = /* @__PURE__ */ new Map();
|
|
146
|
+
function immediate(callback, args) {
|
|
147
|
+
const id = Symbol("immediate");
|
|
148
|
+
const cancel = pageHost.serverImmediate(() => {
|
|
149
|
+
immediates.delete(id);
|
|
150
|
+
callback(...args);
|
|
151
|
+
});
|
|
152
|
+
immediates.set(id, cancel);
|
|
153
|
+
return id;
|
|
154
|
+
}
|
|
155
|
+
function clearImmediateOf(id) {
|
|
156
|
+
immediates.get(id)?.();
|
|
157
|
+
return immediates.delete(id);
|
|
158
|
+
}
|
|
159
|
+
{
|
|
160
|
+
const { process } = scope;
|
|
161
|
+
process.cwd ??= () => "/";
|
|
162
|
+
process.on ??= () => process;
|
|
163
|
+
process.off ??= () => process;
|
|
164
|
+
process.nextTick ??= (callback, ...args) => queueMicrotask(() => callback(...args));
|
|
165
|
+
process.hrtime ??= Object.assign(() => [0, 0], { bigint: () => BigInt(Math.round(performance.now() * 1e6)) });
|
|
166
|
+
const nativeSetTimeout = globalThis.setTimeout;
|
|
167
|
+
const nativeClearTimeout = globalThis.clearTimeout;
|
|
168
|
+
registry.setImmediate = (callback, ...args) => pageHost.immediatesOfRuntime || registry.speedFeatures?.immediates ? immediate(callback, args) : nativeSetTimeout(callback, 0, ...args);
|
|
169
|
+
registry.clearImmediate = (id) => typeof id === "symbol" ? clearImmediateOf(id) : nativeClearTimeout(id);
|
|
170
|
+
registry.setTimeout = (callback, delay, ...args) => registry.speedFeatures?.immediates && !(Number(delay) > 0) && typeof callback === "function" && globalThis.setTimeout === nativeSetTimeout ? immediate(callback, args) : globalThis.setTimeout(callback, delay, ...args);
|
|
171
|
+
registry.clearTimeout = (id) => typeof id === "symbol" ? clearImmediateOf(id) : globalThis.clearTimeout(id);
|
|
172
|
+
const latin1 = (bytes) => {
|
|
173
|
+
let text = "";
|
|
174
|
+
for (let at = 0; at < bytes.length; at += 8192) text += String.fromCharCode(...bytes.subarray(at, at + 8192));
|
|
175
|
+
return text;
|
|
176
|
+
};
|
|
177
|
+
const utf8 = new TextDecoder("utf-8");
|
|
178
|
+
const ucs2 = new TextDecoder("utf-16le");
|
|
179
|
+
const decoders = {
|
|
180
|
+
latin1,
|
|
181
|
+
ascii: latin1,
|
|
182
|
+
utf8: (bytes) => utf8.decode(bytes),
|
|
183
|
+
ucs2: (bytes) => ucs2.decode(bytes)
|
|
184
|
+
};
|
|
185
|
+
for (const [encoding, decode] of Object.entries(decoders)) {
|
|
186
|
+
if (`${encoding}Slice` in Uint8Array.prototype) continue;
|
|
187
|
+
Object.defineProperty(Uint8Array.prototype, `${encoding}Slice`, {
|
|
188
|
+
configurable: true,
|
|
189
|
+
writable: true,
|
|
190
|
+
value(start, end) {
|
|
191
|
+
return decode(this.subarray(start, end));
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//#endregion
|
|
197
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/host-document.d.ts
|
|
2
|
+
type NavigateEvent = Event & {
|
|
3
|
+
navigationType: "push" | "replace" | "reload" | "traverse";
|
|
4
|
+
destination: {
|
|
5
|
+
url: string;
|
|
6
|
+
sameDocument: boolean;
|
|
7
|
+
};
|
|
8
|
+
hashChange: boolean;
|
|
9
|
+
formData: FormData | null;
|
|
10
|
+
downloadRequest: string | null;
|
|
11
|
+
sourceElement: Element | null;
|
|
12
|
+
};
|
|
13
|
+
/** Says whether a browser context of the app is open: browser-context.ts does. */
|
|
14
|
+
declare function appHasNavigations(open: boolean): void;
|
|
15
|
+
/**
|
|
16
|
+
* Keeps the host's document while the host renders components outside a
|
|
17
|
+
* browser context of the app: a link or a form that would load another
|
|
18
|
+
* document is stopped, and `report` hears of it with the URL it would load.
|
|
19
|
+
* By default `reportError()` gets an error that says why. A declared
|
|
20
|
+
* download, like `<a download>`, is the browser's, and while a context is
|
|
21
|
+
* open, the app has the navigations. Until the function it returns is
|
|
22
|
+
* called.
|
|
23
|
+
*/
|
|
24
|
+
declare function keepHostDocument(report?: (url: URL) => void): () => void;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { NavigateEvent, appHasNavigations, keepHostDocument };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import pageHost from "virtual:vitest-plugin-rsc/page-host";
|
|
2
|
+
//#region src/host-document.ts
|
|
3
|
+
let inContext = false;
|
|
4
|
+
/** Says whether a browser context of the app is open: browser-context.ts does. */
|
|
5
|
+
function appHasNavigations(open) {
|
|
6
|
+
inContext = open;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Keeps the host's document while the host renders components outside a
|
|
10
|
+
* browser context of the app: a link or a form that would load another
|
|
11
|
+
* document is stopped, and `report` hears of it with the URL it would load.
|
|
12
|
+
* By default `reportError()` gets an error that says why. A declared
|
|
13
|
+
* download, like `<a download>`, is the browser's, and while a context is
|
|
14
|
+
* open, the app has the navigations. Until the function it returns is
|
|
15
|
+
* called.
|
|
16
|
+
*/
|
|
17
|
+
function keepHostDocument(report = reportLoad) {
|
|
18
|
+
const { navigation } = pageHost;
|
|
19
|
+
const keep = (event) => {
|
|
20
|
+
if (inContext || event.defaultPrevented) return;
|
|
21
|
+
const { destination, hashChange, downloadRequest } = event;
|
|
22
|
+
if (destination.sameDocument || hashChange || !event.cancelable) return;
|
|
23
|
+
if (downloadRequest !== null || destination.url === window.location.href) return;
|
|
24
|
+
event.preventDefault();
|
|
25
|
+
report(new URL(destination.url));
|
|
26
|
+
};
|
|
27
|
+
navigation?.addEventListener("navigate", keep);
|
|
28
|
+
return () => navigation?.removeEventListener("navigate", keep);
|
|
29
|
+
}
|
|
30
|
+
function reportLoad(url) {
|
|
31
|
+
reportError(/* @__PURE__ */ new Error(`vitest-plugin-rsc: a link or a form navigated to ${url.href}, which would load another document in place of the host's. The host renders it outside a browser context of the app, where there is no router of Next's: the host's document stays.`));
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { appHasNavigations, keepHostDocument };
|