@kasperpeulen/vitest-plugin-nextjs 0.0.0-alpha.0 → 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 -4
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
import { restoreIncrementalCache } from "./cache.js";
|
|
3
|
+
import { MockedResponse, fromNodeOutgoingHttpHeaders, isDynamicServerError, toNodeOutgoingHttpHeaders } from "./compat/ssr/node-server.js";
|
|
4
|
+
import { Readable } from "@kasperpeulen/vitest-plugin-nextjs/node/stream";
|
|
5
|
+
//#region src/node-server.ts
|
|
6
|
+
const nativeSetTimeout = globalThis.setTimeout;
|
|
7
|
+
const leftBeforeSent = () => new DOMException("The page was left before the server had sent it.", "AbortError");
|
|
8
|
+
/** The `http.IncomingMessage` of a request: a stream of its body, with what Next reads of it. */
|
|
9
|
+
function createNodeRequest(request) {
|
|
10
|
+
const url = new URL(request.url);
|
|
11
|
+
const { body } = request;
|
|
12
|
+
const stream = body instanceof Uint8Array ? Readable.from([body]) : body && Readable.fromWeb(body);
|
|
13
|
+
return Object.assign(stream || Readable.from([]), {
|
|
14
|
+
method: request.method,
|
|
15
|
+
url: url.pathname + url.search,
|
|
16
|
+
headers: {
|
|
17
|
+
host: url.host,
|
|
18
|
+
...toNodeOutgoingHttpHeaders(request.headers)
|
|
19
|
+
},
|
|
20
|
+
httpVersion: "1.1",
|
|
21
|
+
socket: { encrypted: url.protocol === "https:" }
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const writings = /* @__PURE__ */ new WeakMap();
|
|
25
|
+
/** The `Writing` of a response of `handleRequest()` with a body. */
|
|
26
|
+
const writingOf = (response) => writings.get(response);
|
|
27
|
+
/**
|
|
28
|
+
* The `http.ServerResponse` of a request, which is Next's own stand-in for
|
|
29
|
+
* one, and the `Response` the browser gets of it: once its head is there, while
|
|
30
|
+
* Next goes on to write the body.
|
|
31
|
+
*
|
|
32
|
+
* A request that is left before its head has no response. It lasts until
|
|
33
|
+
* Next's handler is done with it, which can be much later, when the data it
|
|
34
|
+
* waited for comes: its stores have to be there until then.
|
|
35
|
+
*/
|
|
36
|
+
function createNodeResponse(request) {
|
|
37
|
+
let controller;
|
|
38
|
+
let headSent = false;
|
|
39
|
+
let wrote = false;
|
|
40
|
+
let finished = false;
|
|
41
|
+
let cancelled = false;
|
|
42
|
+
let sendHead;
|
|
43
|
+
const head = new Promise((resolve) => sendHead = resolve).then(() => headSent = true);
|
|
44
|
+
const encoder = new TextEncoder();
|
|
45
|
+
let ended;
|
|
46
|
+
const bodyWritten = new Promise((resolve) => ended = resolve);
|
|
47
|
+
const body = new ReadableStream({
|
|
48
|
+
start: (c) => void (controller = c),
|
|
49
|
+
cancel() {
|
|
50
|
+
cancelled = true;
|
|
51
|
+
res.destroy();
|
|
52
|
+
ended();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
const stop = () => {
|
|
56
|
+
cancelled = true;
|
|
57
|
+
controller.error(AbortSignal.abort().reason);
|
|
58
|
+
res.destroy();
|
|
59
|
+
ended();
|
|
60
|
+
};
|
|
61
|
+
const res = new MockedResponse({ resWriter(chunk) {
|
|
62
|
+
if (res.destroyed) return false;
|
|
63
|
+
sendHead();
|
|
64
|
+
wrote = headSent = res.headersSent = true;
|
|
65
|
+
controller.enqueue(typeof chunk === "string" ? encoder.encode(chunk) : new Uint8Array(chunk));
|
|
66
|
+
return true;
|
|
67
|
+
} });
|
|
68
|
+
const appendHeader = res.appendHeader.bind(res);
|
|
69
|
+
res.appendHeader = (name, value) => name.toLowerCase() === "location" && res.getHeader(name) === value ? res : appendHeader(name, value);
|
|
70
|
+
const end = res.end.bind(res);
|
|
71
|
+
res.end = ((...args) => {
|
|
72
|
+
end(...args);
|
|
73
|
+
if (res.destroyed) return res;
|
|
74
|
+
if (!wrote) finished = true;
|
|
75
|
+
headSent = res.headersSent = true;
|
|
76
|
+
sendHead();
|
|
77
|
+
return res;
|
|
78
|
+
});
|
|
79
|
+
res._writableState.autoDestroy = false;
|
|
80
|
+
res.on("finish", () => {
|
|
81
|
+
finished = true;
|
|
82
|
+
Object.defineProperty(res, "writableFinished", {
|
|
83
|
+
value: true,
|
|
84
|
+
configurable: true
|
|
85
|
+
});
|
|
86
|
+
controller.close();
|
|
87
|
+
ended();
|
|
88
|
+
nativeSetTimeout(() => res.destroy());
|
|
89
|
+
});
|
|
90
|
+
let failure;
|
|
91
|
+
res.on("error", (error) => failure ??= error);
|
|
92
|
+
res.on("close", () => {
|
|
93
|
+
if (!headSent || finished || cancelled) return;
|
|
94
|
+
controller.error(failure ?? leftBeforeSent());
|
|
95
|
+
ended();
|
|
96
|
+
});
|
|
97
|
+
res.hasStreamed.catch(() => {});
|
|
98
|
+
const { signal } = request;
|
|
99
|
+
const leave = () => res.destroy();
|
|
100
|
+
signal?.addEventListener("abort", leave, { once: true });
|
|
101
|
+
res.once("close", () => signal?.removeEventListener("abort", leave));
|
|
102
|
+
const response = (written) => {
|
|
103
|
+
const sent = head.then(() => {
|
|
104
|
+
const empty = finished && !wrote || [
|
|
105
|
+
101,
|
|
106
|
+
204,
|
|
107
|
+
205,
|
|
108
|
+
304
|
|
109
|
+
].includes(res.statusCode);
|
|
110
|
+
const answer = new registry.Response(empty ? null : body, {
|
|
111
|
+
status: res.statusCode,
|
|
112
|
+
statusText: res.statusMessage,
|
|
113
|
+
headers: fromNodeOutgoingHttpHeaders(res.getHeaders())
|
|
114
|
+
});
|
|
115
|
+
if (!empty) writings.set(answer, {
|
|
116
|
+
written: bodyWritten,
|
|
117
|
+
stop
|
|
118
|
+
});
|
|
119
|
+
return answer;
|
|
120
|
+
});
|
|
121
|
+
const settled = written.then(() => {
|
|
122
|
+
if (headSent) return sent;
|
|
123
|
+
res.destroy();
|
|
124
|
+
throw failure ?? leftBeforeSent();
|
|
125
|
+
}, (error) => {
|
|
126
|
+
if (!headSent) {
|
|
127
|
+
res.destroy();
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
res.destroy(error ?? /* @__PURE__ */ new Error("The request handler failed."));
|
|
131
|
+
return sent;
|
|
132
|
+
});
|
|
133
|
+
return Promise.race([sent, settled]);
|
|
134
|
+
};
|
|
135
|
+
return {
|
|
136
|
+
res,
|
|
137
|
+
response
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const staticToDynamic = "Page changed from static to dynamic at runtime ";
|
|
141
|
+
const isPrerenderBailout = (error) => isDynamicServerError(error) || error instanceof Error && error.message.startsWith(staticToDynamic);
|
|
142
|
+
const prerenders = [];
|
|
143
|
+
const routerServerContexts = Symbol.for("@next/router-server-methods");
|
|
144
|
+
globalThis[routerServerContexts] = { "": { logErrorWithOriginalStack(error) {
|
|
145
|
+
const prerender = prerenders.at(-1);
|
|
146
|
+
if (!isPrerenderBailout(error)) console.error(error);
|
|
147
|
+
else if (prerender) prerender.bailouts++;
|
|
148
|
+
} } };
|
|
149
|
+
/**
|
|
150
|
+
* Counts the bail-outs that Next's handler reports for the prerender that
|
|
151
|
+
* starts now: also those it answers with its error page itself, where its
|
|
152
|
+
* render of a page recovers from the error (`app-page-runtime.js:1133-1224`).
|
|
153
|
+
* The function it returns ends the count and answers it, once: a count that
|
|
154
|
+
* stays would get the bail-outs of the prerenders after it.
|
|
155
|
+
*/
|
|
156
|
+
function countBailouts() {
|
|
157
|
+
const prerender = { bailouts: 0 };
|
|
158
|
+
prerenders.push(prerender);
|
|
159
|
+
return () => {
|
|
160
|
+
const at = prerenders.lastIndexOf(prerender);
|
|
161
|
+
if (at !== -1) prerenders.splice(at, 1);
|
|
162
|
+
return prerender.bailouts;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function requestMetaOf(request, routed = {}) {
|
|
166
|
+
return {
|
|
167
|
+
...routed.params && { params: routed.params },
|
|
168
|
+
...routed.query && { query: routed.query },
|
|
169
|
+
initURL: request.url,
|
|
170
|
+
initProtocol: new URL(request.url).protocol.slice(0, -1)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* One request, by the request handler Next's build makes for its route:
|
|
175
|
+
* `templates/app-page-runtime` for a page and `templates/app-route` for a
|
|
176
|
+
* route handler, as `next start` calls them.
|
|
177
|
+
*/
|
|
178
|
+
async function handleRequest(request, context, handler, routed, { statusCode, headers } = {}) {
|
|
179
|
+
const { res, response } = createNodeResponse(request);
|
|
180
|
+
if (statusCode !== void 0) res.statusCode = statusCode;
|
|
181
|
+
headers?.forEach((value, name) => {
|
|
182
|
+
if (name !== "set-cookie") res.setHeader(name, value);
|
|
183
|
+
});
|
|
184
|
+
return response(handler(createNodeRequest(request), res, {
|
|
185
|
+
waitUntil: context.waitUntil,
|
|
186
|
+
requestMeta: {
|
|
187
|
+
...requestMetaOf(request, routed),
|
|
188
|
+
incrementalCache: globalThis.__incrementalCache
|
|
189
|
+
}
|
|
190
|
+
}).finally(restoreIncrementalCache));
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
export { countBailouts, handleRequest, isPrerenderBailout, writingOf };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NextLayer, NextProject } from "./project.js";
|
|
2
|
+
|
|
3
|
+
//#region src/optimizer-cache-key.d.ts
|
|
4
|
+
type OptimizerInputs = Pick<NextProject, "aliases" | "appAliases" | "dependencyCompileOptions" | "newExports" | "version">;
|
|
5
|
+
/**
|
|
6
|
+
* What the project gives the optimizer's plugins of a layer: Next's alias
|
|
7
|
+
* table and the app's, which the resolver picks from by the importer, and the
|
|
8
|
+
* options of Next's transform for a dependency. The tables in their order,
|
|
9
|
+
* not sorted: the resolver takes the first entry that matches, and a prefix
|
|
10
|
+
* like `next` can match where a later one would. The order is the code's,
|
|
11
|
+
* the same for every run. And the stubs of the stand-ins, of the version of
|
|
12
|
+
* Next.
|
|
13
|
+
*/
|
|
14
|
+
declare function projectKey(project: OptimizerInputs, layer: NextLayer): string;
|
|
15
|
+
/**
|
|
16
|
+
* The code of a directory of the plugin: the contents of every file of it.
|
|
17
|
+
* The contents, not the version, which a build of this repository keeps, and
|
|
18
|
+
* not the times of the files, which every build changes. All of the code,
|
|
19
|
+
* not just the modules that compile a dependency: a bundle of `dist` mixes
|
|
20
|
+
* modules, and what those import is just as much the compile.
|
|
21
|
+
*/
|
|
22
|
+
declare function codeKey(dir: string): string;
|
|
23
|
+
/** For the `define` of the optimizer of a layer, which Vite keys its cache on. */
|
|
24
|
+
declare function optimizerCacheKey(project: OptimizerInputs, layer: NextLayer): Record<string, string>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { codeKey, optimizerCacheKey, projectKey };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
//#region src/optimizer-cache-key.ts
|
|
7
|
+
const hash = (text) => createHash("sha256").update(text).digest("hex").slice(0, 16);
|
|
8
|
+
/**
|
|
9
|
+
* What the project gives the optimizer's plugins of a layer: Next's alias
|
|
10
|
+
* table and the app's, which the resolver picks from by the importer, and the
|
|
11
|
+
* options of Next's transform for a dependency. The tables in their order,
|
|
12
|
+
* not sorted: the resolver takes the first entry that matches, and a prefix
|
|
13
|
+
* like `next` can match where a later one would. The order is the code's,
|
|
14
|
+
* the same for every run. And the stubs of the stand-ins, of the version of
|
|
15
|
+
* Next.
|
|
16
|
+
*/
|
|
17
|
+
function projectKey(project, layer) {
|
|
18
|
+
return hash(JSON.stringify([
|
|
19
|
+
Object.entries(project.aliases[layer]),
|
|
20
|
+
Object.entries(project.appAliases[layer]),
|
|
21
|
+
project.dependencyCompileOptions[layer],
|
|
22
|
+
project.newExports,
|
|
23
|
+
project.version
|
|
24
|
+
]));
|
|
25
|
+
}
|
|
26
|
+
const isCode = (file) => /\.[cm]?[jt]sx?$/.test(file) && !/\.test\.[cm]?[jt]sx?$/.test(file) && !/\.d\.[cm]?ts$/.test(file);
|
|
27
|
+
/**
|
|
28
|
+
* The code of a directory of the plugin: the contents of every file of it.
|
|
29
|
+
* The contents, not the version, which a build of this repository keeps, and
|
|
30
|
+
* not the times of the files, which every build changes. All of the code,
|
|
31
|
+
* not just the modules that compile a dependency: a bundle of `dist` mixes
|
|
32
|
+
* modules, and what those import is just as much the compile.
|
|
33
|
+
*/
|
|
34
|
+
function codeKey(dir) {
|
|
35
|
+
const content = createHash("sha256");
|
|
36
|
+
const files = fs.readdirSync(dir, {
|
|
37
|
+
recursive: true,
|
|
38
|
+
encoding: "utf8"
|
|
39
|
+
}).map((file) => file.split(path.sep).join("/")).filter(isCode).sort();
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
const full = path.join(dir, file);
|
|
42
|
+
if (!fs.statSync(full).isFile()) continue;
|
|
43
|
+
content.update(`${file}\0`).update(fs.readFileSync(full)).update("\0");
|
|
44
|
+
}
|
|
45
|
+
return content.digest("hex").slice(0, 16);
|
|
46
|
+
}
|
|
47
|
+
function ownCodeDirs() {
|
|
48
|
+
const file = fileURLToPath(import.meta.url);
|
|
49
|
+
for (let dir = path.dirname(file); dir !== path.dirname(dir); dir = path.dirname(dir)) {
|
|
50
|
+
const manifest = path.join(dir, "package.json");
|
|
51
|
+
if (!fs.existsSync(manifest)) continue;
|
|
52
|
+
const { name } = JSON.parse(fs.readFileSync(manifest, "utf8"));
|
|
53
|
+
if (name !== "@kasperpeulen/vitest-plugin-nextjs") return [];
|
|
54
|
+
const core = path.dirname(createRequire(import.meta.url).resolve("@kasperpeulen/vitest-plugin-rsc/package.json"));
|
|
55
|
+
return [dir, core].flatMap((pkg) => ["src", "dist"].map((code) => path.join(pkg, code))).filter((code) => fs.statSync(code, { throwIfNoEntry: false })?.isDirectory());
|
|
56
|
+
}
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
let ownCodeKey;
|
|
60
|
+
/** For the `define` of the optimizer of a layer, which Vite keys its cache on. */
|
|
61
|
+
function optimizerCacheKey(project, layer) {
|
|
62
|
+
if (ownCodeKey === void 0) try {
|
|
63
|
+
ownCodeKey = hash(ownCodeDirs().map((dir) => `${path.basename(dir)}:${codeKey(dir)}`).join(","));
|
|
64
|
+
} catch {
|
|
65
|
+
ownCodeKey = "";
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
__vitest_plugin_rsc_project__: JSON.stringify(projectKey(project, layer)),
|
|
69
|
+
__vitest_plugin_rsc_code__: JSON.stringify(ownCodeKey)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { codeKey, optimizerCacheKey, projectKey };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { addOwnPackage } from "@kasperpeulen/vitest-plugin-rsc/internal/own-packages";
|
|
3
|
+
//#region src/own-package.ts
|
|
4
|
+
addOwnPackage("@kasperpeulen/vitest-plugin-nextjs", fileURLToPath(new URL("./", import.meta.url)));
|
|
5
|
+
//#endregion
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/page-store.d.ts
|
|
2
|
+
type Cookie = {
|
|
3
|
+
value: string;
|
|
4
|
+
httpOnly: boolean;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* What the browser's requests to the app carry, besides what a browser adds
|
|
8
|
+
* itself. One for the document, from what the test opened until the test
|
|
9
|
+
* ends: `cleanup()` makes a new one.
|
|
10
|
+
*/
|
|
11
|
+
declare class PageStore {
|
|
12
|
+
#private;
|
|
13
|
+
/** The `headers` of what the test opened, until it opens something else. */
|
|
14
|
+
headers: Headers;
|
|
15
|
+
/** The app's cookies, by name, with the values the server wrote. */
|
|
16
|
+
readonly cookies: Map<string, Cookie>;
|
|
17
|
+
/** Sets the cookies of a `cookie` header, as a `Set-Cookie` of each would. */
|
|
18
|
+
seed(cookie: string): void;
|
|
19
|
+
/** Sets and deletes cookies by the `Set-Cookie` headers of a response of the app. */
|
|
20
|
+
receive(setCookies: Iterable<string>): void;
|
|
21
|
+
/**
|
|
22
|
+
* Sets or deletes a cookie as a script of the page does, with
|
|
23
|
+
* `document.cookie`. As in a browser, a script cannot write an `HttpOnly`
|
|
24
|
+
* cookie, nor change or delete one.
|
|
25
|
+
*/
|
|
26
|
+
write(setCookie: string): void;
|
|
27
|
+
/** The `cookie` header of a request: empty without cookies. */
|
|
28
|
+
cookieHeader(): string;
|
|
29
|
+
/** What `document.cookie` has: the cookies that are not `HttpOnly`. */
|
|
30
|
+
documentCookie(): string;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { PageStore };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//#region src/page-store.ts
|
|
2
|
+
/** A name and a value: of a `cookie` header, or of a `Set-Cookie` before its first `;`. */
|
|
3
|
+
function pairOf(text) {
|
|
4
|
+
const at = text.indexOf("=");
|
|
5
|
+
return at === -1 ? ["", text.trim()] : [text.slice(0, at).trim(), text.slice(at + 1).trim()];
|
|
6
|
+
}
|
|
7
|
+
/** The name of an attribute of a `Set-Cookie`, in lower case, and its value. */
|
|
8
|
+
function attributeOf(text) {
|
|
9
|
+
const at = text.indexOf("=");
|
|
10
|
+
return at === -1 ? [text.trim().toLowerCase(), ""] : [text.slice(0, at).trim().toLowerCase(), text.slice(at + 1).trim()];
|
|
11
|
+
}
|
|
12
|
+
function expiresAt(value) {
|
|
13
|
+
if (!/\d{1,2}:\d{1,2}:\d{1,2}/.test(value)) return void 0;
|
|
14
|
+
if (!/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/i.test(value)) return void 0;
|
|
15
|
+
const time = Date.parse(value);
|
|
16
|
+
return Number.isNaN(time) ? void 0 : time;
|
|
17
|
+
}
|
|
18
|
+
function deletes(attributes) {
|
|
19
|
+
let maxAge;
|
|
20
|
+
let expires;
|
|
21
|
+
for (const [name, value] of attributes.map(attributeOf)) {
|
|
22
|
+
if (name === "max-age" && /^-?\d+$/.test(value)) maxAge = Number(value);
|
|
23
|
+
if (name === "expires") expires = expiresAt(value) ?? expires;
|
|
24
|
+
}
|
|
25
|
+
if (maxAge !== void 0) return maxAge <= 0;
|
|
26
|
+
return expires !== void 0 && expires <= Date.now();
|
|
27
|
+
}
|
|
28
|
+
/** The cookies as a `cookie` header, or as `document.cookie` has them. */
|
|
29
|
+
function serialize(cookies) {
|
|
30
|
+
return Array.from(cookies, ([name, { value }]) => name ? `${name}=${value}` : value).join("; ");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* What the browser's requests to the app carry, besides what a browser adds
|
|
34
|
+
* itself. One for the document, from what the test opened until the test
|
|
35
|
+
* ends: `cleanup()` makes a new one.
|
|
36
|
+
*/
|
|
37
|
+
var PageStore = class {
|
|
38
|
+
/** The `headers` of what the test opened, until it opens something else. */
|
|
39
|
+
headers = new Headers();
|
|
40
|
+
/** The app's cookies, by name, with the values the server wrote. */
|
|
41
|
+
cookies = /* @__PURE__ */ new Map();
|
|
42
|
+
/** Sets the cookies of a `cookie` header, as a `Set-Cookie` of each would. */
|
|
43
|
+
seed(cookie) {
|
|
44
|
+
this.receive(cookie.split(";"));
|
|
45
|
+
}
|
|
46
|
+
/** Sets and deletes cookies by the `Set-Cookie` headers of a response of the app. */
|
|
47
|
+
receive(setCookies) {
|
|
48
|
+
for (const setCookie of setCookies) this.#set(setCookie, false);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Sets or deletes a cookie as a script of the page does, with
|
|
52
|
+
* `document.cookie`. As in a browser, a script cannot write an `HttpOnly`
|
|
53
|
+
* cookie, nor change or delete one.
|
|
54
|
+
*/
|
|
55
|
+
write(setCookie) {
|
|
56
|
+
this.#set(setCookie, true);
|
|
57
|
+
}
|
|
58
|
+
/** The `cookie` header of a request: empty without cookies. */
|
|
59
|
+
cookieHeader() {
|
|
60
|
+
return serialize(this.cookies);
|
|
61
|
+
}
|
|
62
|
+
/** What `document.cookie` has: the cookies that are not `HttpOnly`. */
|
|
63
|
+
documentCookie() {
|
|
64
|
+
return serialize(Array.from(this.cookies).filter(([, { httpOnly }]) => !httpOnly));
|
|
65
|
+
}
|
|
66
|
+
#set(setCookie, byScript) {
|
|
67
|
+
const [pair = "", ...attributes] = setCookie.split(";");
|
|
68
|
+
const [name, value] = pairOf(pair);
|
|
69
|
+
if (!name && !value) return;
|
|
70
|
+
const httpOnly = attributes.some((attribute) => attributeOf(attribute)[0] === "httponly");
|
|
71
|
+
if (byScript && (httpOnly || this.cookies.get(name)?.httpOnly)) return;
|
|
72
|
+
if (deletes(attributes)) this.cookies.delete(name);
|
|
73
|
+
else this.cookies.set(name, {
|
|
74
|
+
value,
|
|
75
|
+
httpOnly
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { PageStore };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/page-timers.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Those uses, to the module runner's. Also for the dependency optimizer of
|
|
6
|
+
* the browser layer, by its `transform.define`: the bundler replaces them in
|
|
7
|
+
* every module of the pre-bundle, natively and in parallel, and the result
|
|
8
|
+
* stays on disk, where the plugin below would compile each pre-bundled file
|
|
9
|
+
* again in every run. None of them is a file of the host, and the packages
|
|
10
|
+
* of the host are not in it (`vitest-plugin-rsc:next-host-packages`).
|
|
11
|
+
*/
|
|
12
|
+
declare const pageTimersDefine: {
|
|
13
|
+
[k: string]: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* For the modules of the browser layer, by the name of its environment, but
|
|
17
|
+
* those of a file that `isHostFile()`, and the pre-bundled dependencies,
|
|
18
|
+
* which have `pageTimersDefine`.
|
|
19
|
+
*/
|
|
20
|
+
declare function pageTimersPlugin(environment: string, isHostFile: (file: string) => boolean): Plugin;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { pageTimersDefine, pageTimersPlugin };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { fileOfModule } from "./client-files.js";
|
|
2
|
+
import { runnerGlobalNames, timersKey } from "@kasperpeulen/vitest-plugin-rsc/internal/timers";
|
|
3
|
+
import { normalizePath, transformWithOxc } from "vite";
|
|
4
|
+
import { ssrImportMetaKey } from "vite/module-runner";
|
|
5
|
+
//#region src/page-timers.ts
|
|
6
|
+
/**
|
|
7
|
+
* Those uses, to the module runner's. Also for the dependency optimizer of
|
|
8
|
+
* the browser layer, by its `transform.define`: the bundler replaces them in
|
|
9
|
+
* every module of the pre-bundle, natively and in parallel, and the result
|
|
10
|
+
* stays on disk, where the plugin below would compile each pre-bundled file
|
|
11
|
+
* again in every run. None of them is a file of the host, and the packages
|
|
12
|
+
* of the host are not in it (`vitest-plugin-rsc:next-host-packages`).
|
|
13
|
+
*/
|
|
14
|
+
const pageTimersDefine = Object.fromEntries(runnerGlobalNames.map((name) => [name, `${ssrImportMetaKey}.${timersKey}.${name}`]));
|
|
15
|
+
const mentionsTimer = new RegExp(`\\b(?:${runnerGlobalNames.join("|")})\\b`);
|
|
16
|
+
/**
|
|
17
|
+
* For the modules of the browser layer, by the name of its environment, but
|
|
18
|
+
* those of a file that `isHostFile()`, and the pre-bundled dependencies,
|
|
19
|
+
* which have `pageTimersDefine`.
|
|
20
|
+
*/
|
|
21
|
+
function pageTimersPlugin(environment, isHostFile) {
|
|
22
|
+
return {
|
|
23
|
+
name: "vitest-plugin-rsc:next-page-timers",
|
|
24
|
+
enforce: "post",
|
|
25
|
+
applyToEnvironment: ({ name }) => name === environment,
|
|
26
|
+
transform: {
|
|
27
|
+
filter: { code: mentionsTimer },
|
|
28
|
+
async handler(code, id) {
|
|
29
|
+
const { environment } = this;
|
|
30
|
+
if (environment.mode === "dev" && environment.depsOptimizer?.isOptimizedDepFile(id)) return;
|
|
31
|
+
const file = fileOfModule(id);
|
|
32
|
+
if (file !== void 0 && isHostFile(file)) return;
|
|
33
|
+
try {
|
|
34
|
+
return await transformWithOxc(code, normalizePath(id), {
|
|
35
|
+
lang: "js",
|
|
36
|
+
define: pageTimersDefine
|
|
37
|
+
});
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const reason = String(error instanceof Error ? error.message : error);
|
|
40
|
+
this.warn(`vitest-plugin-rsc: the timers of ${id} keep running after its page is left, it does not parse as JavaScript. ${reason.replace(/\s+/g, " ")}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { pageTimersDefine, pageTimersPlugin };
|
package/dist/page.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Opened } from "./registry.js";
|
|
2
|
+
import { PageStore } from "./page-store.js";
|
|
3
|
+
import { NodeOnPage } from "./node-on-page.js";
|
|
4
|
+
import { HistoryEntry } from "./document.js";
|
|
5
|
+
import { ShellErrorAnswer } from "./ssr.js";
|
|
6
|
+
|
|
7
|
+
//#region src/page.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* A navigation without a page of the app, which has the router, under
|
|
10
|
+
* Vitest: a component that a test file with `"use client"` rendered has none.
|
|
11
|
+
*/
|
|
12
|
+
declare function noRouter(url: URL): Error;
|
|
13
|
+
/**
|
|
14
|
+
* A page of the app, from the first line of its load until it is left, with
|
|
15
|
+
* the node of `renderServer()` on it, and where it reports its errors. Its
|
|
16
|
+
* load makes it part by part, and each part that would outlive the page says
|
|
17
|
+
* how it is released. Leaving stops the load at once, and releases the
|
|
18
|
+
* parts, the last first.
|
|
19
|
+
*/
|
|
20
|
+
declare class Page {
|
|
21
|
+
#private;
|
|
22
|
+
readonly errors: unknown[];
|
|
23
|
+
readonly nodeOnPage?: NodeOnPage | undefined;
|
|
24
|
+
/** Whether the page renders in the app kept from the page before: see `kept`. */
|
|
25
|
+
readonly inKeptApp: boolean;
|
|
26
|
+
/** Aborts as the page is left: what the load does takes it. */
|
|
27
|
+
readonly signal: AbortSignal;
|
|
28
|
+
constructor(errors: unknown[], nodeOnPage?: NodeOnPage | undefined, /** Whether the page renders in the app kept from the page before: see `kept`. */
|
|
29
|
+
|
|
30
|
+
inKeptApp?: boolean);
|
|
31
|
+
/** Whether the page is open: from when its client starts until it is left. */
|
|
32
|
+
get open(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Runs `release` as the page is left: before what the load made before
|
|
35
|
+
* it. As `defer()` of a `DisposableStack`.
|
|
36
|
+
*/
|
|
37
|
+
defer(release: () => void): void;
|
|
38
|
+
/**
|
|
39
|
+
* Opens the page: its client starts. Leaving waits for `started` to
|
|
40
|
+
* settle, at most `startTimeout`, before it releases what the page holds.
|
|
41
|
+
* `stopped` runs once the start is over for the page: once `started` has
|
|
42
|
+
* settled, or once leaving stops waiting for it.
|
|
43
|
+
*/
|
|
44
|
+
starts(started: Promise<unknown>, stopped: () => void): void;
|
|
45
|
+
/**
|
|
46
|
+
* Leaves the page: `by` is what leaves it, for its node. Stops its load at
|
|
47
|
+
* once. Resolves once what the page holds is released, or rejects with the
|
|
48
|
+
* first error of a release, after every release has run. A page still
|
|
49
|
+
* starting after `startTimeout` is released once it has stopped, and
|
|
50
|
+
* `reportError()` gets that error: leaving resolves without it. Once:
|
|
51
|
+
* leaving it again gets the same promise.
|
|
52
|
+
*/
|
|
53
|
+
leave(by: string): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Leaves the page of the kept app that is open, as `leavePage()` does with
|
|
57
|
+
* `by`, and then the kept app: a test file ends with them. The app goes also
|
|
58
|
+
* after a page that could not be left, and the first error rejects.
|
|
59
|
+
*/
|
|
60
|
+
declare function leaveKeptAppWithPage(by: string): Promise<void>;
|
|
61
|
+
/** The page that is open: see `Page.open`. */
|
|
62
|
+
declare function currentPage(): Page | undefined;
|
|
63
|
+
type Opening = {
|
|
64
|
+
container?: Element;
|
|
65
|
+
opened: Opened;
|
|
66
|
+
headers: Headers;
|
|
67
|
+
cookie: string | null; /** For a node: what `rerender()` waits for. */
|
|
68
|
+
nodeOnPage?: NodeOnPage; /** What stops the load: see `RequestOptions.signal` in index.ts. */
|
|
69
|
+
signal?: AbortSignal; /** Where the page, and the pages the app loads from it, report their errors. */
|
|
70
|
+
errors: unknown[];
|
|
71
|
+
/**
|
|
72
|
+
* Renders the page in the app of the page before, if it is kept, and else
|
|
73
|
+
* keeps the app it starts for the pages after it: see `kept`. A page of
|
|
74
|
+
* `keepApp` without HTML of the server.
|
|
75
|
+
*/
|
|
76
|
+
inKeptApp?: boolean;
|
|
77
|
+
};
|
|
78
|
+
type PageDocument = {
|
|
79
|
+
response: Response;
|
|
80
|
+
html: string;
|
|
81
|
+
after?: HistoryEntry;
|
|
82
|
+
payload?: Uint8Array<ArrayBuffer>;
|
|
83
|
+
};
|
|
84
|
+
declare function loadPage(url: URL, request: RequestInit | PageDocument, from: PageStore, opening?: Opening): Promise<Response>;
|
|
85
|
+
/** The Flight payload in the scripts of a document of Next. */
|
|
86
|
+
declare function payloadInDocument(html: string): Uint8Array;
|
|
87
|
+
/**
|
|
88
|
+
* How the server would have answered the document of the page of a Flight
|
|
89
|
+
* payload, had it rendered its HTML, by the errors in the payload (see
|
|
90
|
+
* `shellErrorAnswer()` in ssr.ts): the first `redirect()`, wherever it is in
|
|
91
|
+
* the tree, as Next's router follows it (its RedirectBoundary), else the
|
|
92
|
+
* status of the first other error. Undefined for a payload without an error.
|
|
93
|
+
* A path of the app's has the app's `basePath` before it, which `redirect()`
|
|
94
|
+
* takes without it, as Next's server puts it in the `Location` of the 307 of
|
|
95
|
+
* a document.
|
|
96
|
+
*/
|
|
97
|
+
declare function renderFailureOf(payload: Uint8Array, answerOf: (digest: string) => ShellErrorAnswer): ShellErrorAnswer | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* A navigation of the app without its router, as a browser makes it: a
|
|
100
|
+
* `<form>`, an `<a>` that React does not handle, `location.assign()`. The
|
|
101
|
+
* page that is open stays until the answer is there, and for good when the
|
|
102
|
+
* answer is a download (downloads.ts). Else the answer is the next page,
|
|
103
|
+
* which needs a page of the app to navigate in. `downloadRequest` is the
|
|
104
|
+
* navigation's, and `from` the store of the browser context it is in. With
|
|
105
|
+
* `push` the next page gets an entry of the history of its own, as after a
|
|
106
|
+
* link or a form in a browser. Else it takes the entry of the page, as
|
|
107
|
+
* after a reload or `location.replace()`.
|
|
108
|
+
*/
|
|
109
|
+
declare function navigate(url: URL, init: RequestInit, downloadRequest: string | null, from: PageStore, push: boolean): Promise<void>;
|
|
110
|
+
declare function leavePage(by: string): Promise<void>;
|
|
111
|
+
//#endregion
|
|
112
|
+
export { Page, currentPage, leaveKeptAppWithPage, leavePage, loadPage, navigate, noRouter, payloadInDocument, renderFailureOf };
|