@kasperpeulen/vitest-plugin-nextjs 0.0.0-stage → 0.1.0-alpha.1
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 +39 -0
- package/dist/compile.js +175 -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 +330 -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/host-return-shared.d.ts +5 -0
- package/dist/host-return-shared.js +5 -0
- package/dist/host-return.d.ts +5 -0
- package/dist/host-return.js +16 -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/not-found-page.d.ts +19 -0
- package/dist/not-found-page.js +74 -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 +23 -0
- package/dist/plugin.js +1006 -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 +65 -0
- package/dist/project/webpack.js +191 -0
- package/dist/project.d.ts +269 -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
package/dist/ssr.js
ADDED
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
import { openedAt, registry } from "./registry.js";
|
|
2
|
+
import { actionIdsOf } from "./action-ids.js";
|
|
3
|
+
import { incoming, middlewareResult, redirectStatus, resolve } from "./server-in-front.js";
|
|
4
|
+
import { demoteRoute, isPrerendered, nodeRouteDistDir, prerenderManifest, recordRoute, setServerActions, setStylesheets, withoutRoute } from "./build-output.js";
|
|
5
|
+
import { loadCacheHandlers, resetCaches, shareIncrementalCache } from "./cache.js";
|
|
6
|
+
import { registerModuleLoader } from "./client-modules.js";
|
|
7
|
+
import { countBailouts, handleRequest as handleRequest$1, isPrerenderBailout, writingOf } from "./node-server.js";
|
|
8
|
+
import { NEXT_REWRITTEN_PATH_HEADER, NEXT_REWRITTEN_QUERY_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_RSC_UNION_QUERY, RSC_HEADER, appPageModule, getIsPossibleServerAction, getRouteMatcher, getRouteRegex, isRSCRequestHeader, normalizeNextQueryParam } from "./compat/ssr/handler.js";
|
|
9
|
+
import { getAccessFallbackHTTPStatus, getRedirectStatusCodeFromError, getURLFromRedirectError, isHTTPAccessFallbackError, isRedirectError } from "./compat/ssr/render-errors.js";
|
|
10
|
+
import { build, routes, routing } from "virtual:vitest-plugin-rsc/next-manifest";
|
|
11
|
+
//#region src/ssr.ts
|
|
12
|
+
registry.ssr = appPageModule;
|
|
13
|
+
registerModuleLoader("ssr");
|
|
14
|
+
const routes$1 = new Map(routes.filter((route) => !route.component).map((route) => [route.page, route]));
|
|
15
|
+
const componentRoutes = new Map(routes.filter((route) => route.component && !route.layouts).map((route) => [route.pathname, route]));
|
|
16
|
+
const componentLayoutRoutes = new Map(routes.filter((route) => route.layouts).map((route) => [route.page, route]));
|
|
17
|
+
const notFoundPage = "/_not-found/page";
|
|
18
|
+
function appQuery(query) {
|
|
19
|
+
const result = Object.create(null);
|
|
20
|
+
for (const [name, value] of query) {
|
|
21
|
+
if (normalizeNextQueryParam(name) !== null) continue;
|
|
22
|
+
result[name] = name in result ? [result[name], value].flat() : value;
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function searchOf(query) {
|
|
27
|
+
const search = new URLSearchParams();
|
|
28
|
+
for (const [name, value] of Object.entries(query)) {
|
|
29
|
+
if (name === NEXT_RSC_UNION_QUERY) continue;
|
|
30
|
+
for (const item of [value].flat()) search.append(name, item);
|
|
31
|
+
}
|
|
32
|
+
return search.toString();
|
|
33
|
+
}
|
|
34
|
+
const paramMatchers = /* @__PURE__ */ new Map();
|
|
35
|
+
function paramsOf(route, pathname) {
|
|
36
|
+
let match = paramMatchers.get(route);
|
|
37
|
+
if (!match) {
|
|
38
|
+
const { re, groups } = getRouteRegex(route);
|
|
39
|
+
match = getRouteMatcher({
|
|
40
|
+
re: new RegExp(re.source, "i"),
|
|
41
|
+
groups
|
|
42
|
+
});
|
|
43
|
+
paramMatchers.set(route, match);
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return match(pathname) || void 0;
|
|
47
|
+
} catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function withoutBasePath(pathname) {
|
|
52
|
+
const { basePath } = routing;
|
|
53
|
+
return basePath && pathname.startsWith(basePath) ? pathname.slice(basePath.length) || "/" : pathname;
|
|
54
|
+
}
|
|
55
|
+
const setTimeout = globalThis.setTimeout;
|
|
56
|
+
const clearTimeout = globalThis.clearTimeout;
|
|
57
|
+
const now = performance.now.bind(performance);
|
|
58
|
+
let queue = Promise.resolve();
|
|
59
|
+
let queued = 0;
|
|
60
|
+
let requestQueued = Promise.withResolvers();
|
|
61
|
+
const nextRequest = () => queued > 0 ? Promise.resolve() : requestQueued.promise;
|
|
62
|
+
const rendering = /* @__PURE__ */ new Set();
|
|
63
|
+
let generation = 0;
|
|
64
|
+
const backgroundWorkTimeout = 1e3;
|
|
65
|
+
const backgroundWork = /* @__PURE__ */ new Set();
|
|
66
|
+
const unanswered = /* @__PURE__ */ new Map();
|
|
67
|
+
const settleTimeout = 5e3;
|
|
68
|
+
function streamOf(body) {
|
|
69
|
+
return new ReadableStream({ start(controller) {
|
|
70
|
+
if (body) controller.enqueue(body);
|
|
71
|
+
controller.close();
|
|
72
|
+
} });
|
|
73
|
+
}
|
|
74
|
+
function handleRequest(request, { nested = false, unrouted = "not-found", opened, pageLoad = false } = {}) {
|
|
75
|
+
if (nested) return untilAnswered(request, handle(request, unrouted, true, opened, pageLoad)).then(({ response }) => response);
|
|
76
|
+
const requested = generation;
|
|
77
|
+
queued++;
|
|
78
|
+
requestQueued.resolve();
|
|
79
|
+
const timing = registry.requestTimings && timingOf(request);
|
|
80
|
+
if (timing) registry.requestTimings.push(timing);
|
|
81
|
+
const result = queue.then(() => {
|
|
82
|
+
if (requested !== generation) throw new DOMException("The page was left before the server responded.", "AbortError");
|
|
83
|
+
queued--;
|
|
84
|
+
requestQueued = Promise.withResolvers();
|
|
85
|
+
if (timing) timing.started = performance.now();
|
|
86
|
+
const handled = untilAnswered(request, handle(request, unrouted, false, opened, pageLoad));
|
|
87
|
+
if (timing) handled.then(({ finished }) => {
|
|
88
|
+
timing.answered = performance.now();
|
|
89
|
+
const record = () => timing.finished = performance.now();
|
|
90
|
+
finished.then(record, record);
|
|
91
|
+
}, () => {});
|
|
92
|
+
return handled;
|
|
93
|
+
});
|
|
94
|
+
queue = result.then(({ finished }) => finished, () => {});
|
|
95
|
+
return result.then(({ response }) => response);
|
|
96
|
+
}
|
|
97
|
+
function timingOf(request) {
|
|
98
|
+
const { headers } = request;
|
|
99
|
+
const flight = headers.has("rsc") && (headers.has("next-router-state-tree") || headers.has("next-router-prefetch"));
|
|
100
|
+
const kind = headers.has("next-action") ? "action" : flight ? "flight" : "page";
|
|
101
|
+
return {
|
|
102
|
+
method: request.method,
|
|
103
|
+
url: request.url,
|
|
104
|
+
kind,
|
|
105
|
+
queued: performance.now()
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function untilAnswered(request, handled) {
|
|
109
|
+
const settled = handled.then(() => {}, () => {});
|
|
110
|
+
unanswered.set(settled, `${request.method} ${new URL(request.url).pathname}`);
|
|
111
|
+
settled.then(() => unanswered.delete(settled));
|
|
112
|
+
return handled;
|
|
113
|
+
}
|
|
114
|
+
async function stopResponses(written) {
|
|
115
|
+
await Promise.race([written, new Promise((resolve) => setTimeout(resolve, 100))]);
|
|
116
|
+
for (const stop of rendering) stop();
|
|
117
|
+
rendering.clear();
|
|
118
|
+
}
|
|
119
|
+
async function untilDone(work, deadline) {
|
|
120
|
+
let done = true;
|
|
121
|
+
for (let waiting = [...work()]; waiting.length > 0 && done; waiting = [...work()]) {
|
|
122
|
+
let timeout;
|
|
123
|
+
done = await Promise.race([Promise.all(waiting).then(() => true), new Promise((resolve) => timeout = setTimeout(resolve, Math.max(0, deadline - now()), false))]);
|
|
124
|
+
clearTimeout(timeout);
|
|
125
|
+
}
|
|
126
|
+
return done;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* How Next's server answers the document of a page when an error fails the
|
|
130
|
+
* render of its HTML before any of it is out, by the digest of the error, as
|
|
131
|
+
* Next's renderer does in the `catch` of `renderToStream()` (app-render.js):
|
|
132
|
+
* the status of a `notFound()`, `forbidden()` or `unauthorized()`, the 307 or
|
|
133
|
+
* 308 of a `redirect()` and where it goes, without the app's `basePath`, and
|
|
134
|
+
* 500 for any other error. For a page that the server renders no HTML of: see
|
|
135
|
+
* `renderFailureOf()` in page.ts.
|
|
136
|
+
*/
|
|
137
|
+
function shellErrorAnswer(digest) {
|
|
138
|
+
const error = Object.assign(/* @__PURE__ */ new Error(), { digest });
|
|
139
|
+
if (isHTTPAccessFallbackError(error)) return { status: getAccessFallbackHTTPStatus(error) };
|
|
140
|
+
if (isRedirectError(error)) return {
|
|
141
|
+
status: getRedirectStatusCodeFromError(error),
|
|
142
|
+
location: getURLFromRedirectError(error)
|
|
143
|
+
};
|
|
144
|
+
return { status: 500 };
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Ends the requests the server is still handling, when a page is left.
|
|
148
|
+
*
|
|
149
|
+
* A request that has its answer is writing the body: a short wait, then a
|
|
150
|
+
* stop. A test can end while a page streams, on data that will never come.
|
|
151
|
+
*
|
|
152
|
+
* A request that has no answer yet runs code of the app, like a Server Action
|
|
153
|
+
* or a route handler, and nothing can stop that. So it is waited for, and
|
|
154
|
+
* then for the body it writes. So is what requests do after their response,
|
|
155
|
+
* like `after()`. What comes next is not to run while any of that still reads
|
|
156
|
+
* or sets the stores of a request, which would be the ones of the requests
|
|
157
|
+
* that come next. A request that is sent in the meantime waits for all of
|
|
158
|
+
* that, and is dropped: it is one of the page that was left.
|
|
159
|
+
*/
|
|
160
|
+
async function settleRequests() {
|
|
161
|
+
generation++;
|
|
162
|
+
const written = queue;
|
|
163
|
+
const settled = Promise.withResolvers();
|
|
164
|
+
queue = settled.promise;
|
|
165
|
+
queued = 0;
|
|
166
|
+
const waited = requestQueued;
|
|
167
|
+
requestQueued = Promise.withResolvers();
|
|
168
|
+
const deadline = now() + settleTimeout;
|
|
169
|
+
try {
|
|
170
|
+
await stopResponses(written);
|
|
171
|
+
if (unanswered.size > 0) {
|
|
172
|
+
if (!await untilDone(() => unanswered.keys(), deadline)) {
|
|
173
|
+
console.warn(`vitest-plugin-rsc: the server was still handling ${[...unanswered.values()].join(", ")} ${settleTimeout / 1e3}s after the page was left. What comes next runs anyway. Until that request is done, its code and the requests that come next can read and set each other's cookies, headers and other values of a request.`);
|
|
174
|
+
unanswered.clear();
|
|
175
|
+
}
|
|
176
|
+
await stopResponses(new Promise(() => {}));
|
|
177
|
+
}
|
|
178
|
+
const worked = await untilDone(() => backgroundWork, deadline);
|
|
179
|
+
waited.resolve();
|
|
180
|
+
if (!worked) {
|
|
181
|
+
backgroundWork.clear();
|
|
182
|
+
console.warn(`vitest-plugin-rsc: \`after()\` or \`waitUntil()\` work of a request was still running ${settleTimeout / 1e3}s after a page was left. What comes next runs anyway, and that work may read the stores of the requests that come next.`);
|
|
183
|
+
}
|
|
184
|
+
} finally {
|
|
185
|
+
generation++;
|
|
186
|
+
queued = 0;
|
|
187
|
+
waited.resolve();
|
|
188
|
+
requestQueued.resolve();
|
|
189
|
+
requestQueued = Promise.withResolvers();
|
|
190
|
+
settled.resolve();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function nodeRouteFor(opened, matched) {
|
|
194
|
+
const node = opened?.node;
|
|
195
|
+
if (!node) return void 0;
|
|
196
|
+
if (!node.layouts) return componentRoutes.get(matched?.pathname ?? "/") ?? componentRoutes.get("/");
|
|
197
|
+
const withLayouts = componentLayoutRoutes.get(matched?.page ?? "");
|
|
198
|
+
if (!withLayouts) throw new Error(`vitest-plugin-rsc: \`layouts: true\` renders a node in place of the \`page\` file of its \`url\`, and the app has none for ${opened.pathname}.`);
|
|
199
|
+
return withLayouts;
|
|
200
|
+
}
|
|
201
|
+
const verdicts = /* @__PURE__ */ new Map();
|
|
202
|
+
function verdictOf(route) {
|
|
203
|
+
let verdict = verdicts.get(route.page);
|
|
204
|
+
if (!verdict) {
|
|
205
|
+
const endScope = registry.enterRequestScope();
|
|
206
|
+
verdict = registry.prerenderVerdict(route).finally(endScope);
|
|
207
|
+
verdicts.set(route.page, verdict);
|
|
208
|
+
verdict.catch(() => verdicts.delete(route.page));
|
|
209
|
+
}
|
|
210
|
+
return verdict;
|
|
211
|
+
}
|
|
212
|
+
const recorded = /* @__PURE__ */ new Set();
|
|
213
|
+
async function recordVerdict(route) {
|
|
214
|
+
const verdict = await verdictOf(route);
|
|
215
|
+
if (recorded.has(route.page)) return;
|
|
216
|
+
recorded.add(route.page);
|
|
217
|
+
recordRoute(route, verdict);
|
|
218
|
+
}
|
|
219
|
+
async function isUnlisted(route, pathname) {
|
|
220
|
+
if (recorded.has(route.page)) return prerenderManifest.dynamicRoutes[route.pathname]?.fallback === false && !(pathname in prerenderManifest.routes);
|
|
221
|
+
const verdict = await verdictOf(route);
|
|
222
|
+
return verdict?.fallback === false && !verdict.pathnames.includes(pathname);
|
|
223
|
+
}
|
|
224
|
+
async function prerenderFirst(route, scope, respond) {
|
|
225
|
+
if (!route || !isPrerendered(route)) return respond();
|
|
226
|
+
const endPrerender = scope.enterInner();
|
|
227
|
+
const bailouts = countBailouts();
|
|
228
|
+
try {
|
|
229
|
+
const response = await respond();
|
|
230
|
+
const bailedOut = bailouts() > 0;
|
|
231
|
+
if (response.status !== 500 || !bailedOut) return response;
|
|
232
|
+
await response.body?.cancel();
|
|
233
|
+
} catch (error) {
|
|
234
|
+
bailouts();
|
|
235
|
+
if (!isPrerenderBailout(error)) throw error;
|
|
236
|
+
}
|
|
237
|
+
endPrerender();
|
|
238
|
+
demoteRoute(route);
|
|
239
|
+
return respond();
|
|
240
|
+
}
|
|
241
|
+
async function serverActionsOf(request) {
|
|
242
|
+
const own = await registry.ownServerAction;
|
|
243
|
+
const ids = new Set(own ? [own] : []);
|
|
244
|
+
for (const id of await actionIdsOf(request)) if (await registry.hasServerAction(id)) ids.add(id);
|
|
245
|
+
return ids;
|
|
246
|
+
}
|
|
247
|
+
function enterScope(waited) {
|
|
248
|
+
const endScope = registry.enterRequestScope();
|
|
249
|
+
const background = [];
|
|
250
|
+
const waitUntil = (promise) => {
|
|
251
|
+
background.push(promise);
|
|
252
|
+
const work = promise.then(() => {}, () => {});
|
|
253
|
+
backgroundWork.add(work);
|
|
254
|
+
work.then(() => backgroundWork.delete(work));
|
|
255
|
+
};
|
|
256
|
+
const backgroundSettled = async () => {
|
|
257
|
+
for (let settled = 0; settled < background.length;) {
|
|
258
|
+
const waiting = background.slice(settled);
|
|
259
|
+
settled = background.length;
|
|
260
|
+
await Promise.allSettled(waiting);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const inner = [];
|
|
264
|
+
const enterInner = () => {
|
|
265
|
+
const endInner = registry.enterRequestScope();
|
|
266
|
+
inner.push(endInner);
|
|
267
|
+
return endInner;
|
|
268
|
+
};
|
|
269
|
+
const endAll = () => {
|
|
270
|
+
for (const endInner of inner) endInner();
|
|
271
|
+
endScope();
|
|
272
|
+
};
|
|
273
|
+
const end = async () => {
|
|
274
|
+
await Promise.race([backgroundSettled(), waited().then(() => new Promise((resolve) => setTimeout(resolve, backgroundWorkTimeout)))]);
|
|
275
|
+
endAll();
|
|
276
|
+
};
|
|
277
|
+
return {
|
|
278
|
+
waitUntil,
|
|
279
|
+
end,
|
|
280
|
+
endScope: endAll,
|
|
281
|
+
enterInner
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
async function handle(received, unrouted, nested, openedByRequest, pageLoad) {
|
|
285
|
+
const request = incoming(received);
|
|
286
|
+
const url = new URL(request.url);
|
|
287
|
+
const opened = openedByRequest === null ? void 0 : openedByRequest ?? openedAt(url);
|
|
288
|
+
const scope = enterScope(nested ? () => Promise.resolve() : nextRequest);
|
|
289
|
+
registry.openedByRequest.run(opened, () => {});
|
|
290
|
+
const context = { waitUntil: scope.waitUntil };
|
|
291
|
+
const endRequest = scope.end;
|
|
292
|
+
try {
|
|
293
|
+
let { body } = request;
|
|
294
|
+
let middlewareBody;
|
|
295
|
+
if (body instanceof ReadableStream) [middlewareBody, body] = body.tee();
|
|
296
|
+
else middlewareBody = streamOf(body);
|
|
297
|
+
let responded;
|
|
298
|
+
let { headers } = request;
|
|
299
|
+
const invokeMiddleware = async (target) => {
|
|
300
|
+
const middlewareScope = enterScope(() => Promise.resolve());
|
|
301
|
+
let response;
|
|
302
|
+
try {
|
|
303
|
+
response = await (await registry.loadMiddleware())({
|
|
304
|
+
...request,
|
|
305
|
+
url: target.url.href,
|
|
306
|
+
headers: target.headers,
|
|
307
|
+
body: target.requestBody
|
|
308
|
+
}, {
|
|
309
|
+
waitUntil: middlewareScope.waitUntil,
|
|
310
|
+
signal: request.signal
|
|
311
|
+
});
|
|
312
|
+
} catch (error) {
|
|
313
|
+
if (request.signal?.aborted) throw error;
|
|
314
|
+
console.error(error);
|
|
315
|
+
responded = new registry.Response("Internal Server Error", { status: 500 });
|
|
316
|
+
return { bodySent: true };
|
|
317
|
+
} finally {
|
|
318
|
+
await middlewareScope.end();
|
|
319
|
+
}
|
|
320
|
+
const result = middlewareResult(response, target.headers, target.url);
|
|
321
|
+
if (result.bodySent) responded = response;
|
|
322
|
+
else headers = result.requestHeaders ?? headers;
|
|
323
|
+
return result;
|
|
324
|
+
};
|
|
325
|
+
const proxy = opened?.proxy ?? true;
|
|
326
|
+
await loadCacheHandlers();
|
|
327
|
+
const resolved = await resolve(request, middlewareBody, invokeMiddleware, proxy);
|
|
328
|
+
shareIncrementalCache(headers);
|
|
329
|
+
const routedHeaders = resolved.resolvedHeaders ?? new registry.Headers();
|
|
330
|
+
if (responded) return finishWithBody(request, responded, endRequest);
|
|
331
|
+
const redirect = redirectStatus(resolved);
|
|
332
|
+
if (redirect !== void 0) return finishWithBody(request, new registry.Response(null, {
|
|
333
|
+
status: redirect,
|
|
334
|
+
headers: routedHeaders
|
|
335
|
+
}), endRequest);
|
|
336
|
+
if (resolved.externalRewrite) {
|
|
337
|
+
const hasBody = request.method !== "GET" && request.method !== "HEAD";
|
|
338
|
+
return finishWithBody(request, await registry.network(resolved.externalRewrite, {
|
|
339
|
+
method: request.method,
|
|
340
|
+
headers,
|
|
341
|
+
body: hasBody ? await new registry.Response(body).arrayBuffer() : void 0,
|
|
342
|
+
signal: request.signal
|
|
343
|
+
}), endRequest, routedHeaders);
|
|
344
|
+
}
|
|
345
|
+
const matched = routes$1.get(routing.outputs[resolved.resolvedPathname ?? ""] ?? "");
|
|
346
|
+
const component = nodeRouteFor(opened, matched);
|
|
347
|
+
if (!matched && !component && unrouted === "pass") return { finished: endRequest() };
|
|
348
|
+
const page = component?.page ?? matched?.page ?? notFoundPage;
|
|
349
|
+
const entry = component?.component ?? page;
|
|
350
|
+
const routed = {
|
|
351
|
+
...request,
|
|
352
|
+
headers,
|
|
353
|
+
body
|
|
354
|
+
};
|
|
355
|
+
const target = resolved.invocationTarget;
|
|
356
|
+
const query = target && appQuery(Object.entries(target.query));
|
|
357
|
+
const rewrittenPath = target !== void 0 && target.pathname !== url.pathname;
|
|
358
|
+
const rewrittenQuery = query !== void 0 && searchOf(query) !== searchOf(appQuery(url.searchParams));
|
|
359
|
+
const namesParam = [...url.searchParams.keys()].some((name) => normalizeNextQueryParam(name) !== null);
|
|
360
|
+
const requestMeta = {
|
|
361
|
+
params: target && matched?.pathname.includes("[") ? paramsOf(matched.pathname, withoutBasePath(target.pathname)) : void 0,
|
|
362
|
+
query: rewrittenPath || rewrittenQuery || namesParam ? query : void 0
|
|
363
|
+
};
|
|
364
|
+
if (target && query && isRSCRequestHeader(headers.get(RSC_HEADER) ?? void 0)) {
|
|
365
|
+
if (rewrittenPath) routedHeaders.set(NEXT_REWRITTEN_PATH_HEADER, withoutBasePath(target.pathname));
|
|
366
|
+
if (rewrittenQuery && !routedHeaders.has(NEXT_REWRITTEN_QUERY_HEADER)) routedHeaders.set(NEXT_REWRITTEN_QUERY_HEADER, searchOf(query));
|
|
367
|
+
}
|
|
368
|
+
const prerenders = build === "production" && !component && matched && matched.page !== notFoundPage ? matched : void 0;
|
|
369
|
+
const prefetch = prerenders?.kind === "page" && headers.get(NEXT_ROUTER_PREFETCH_HEADER) === "1" && isRSCRequestHeader(headers.get(RSC_HEADER) ?? void 0);
|
|
370
|
+
if (prerenders && !prefetch) await recordVerdict(prerenders);
|
|
371
|
+
if (prerenders && isPrerendered(prerenders) && request.method !== "GET" && request.method !== "HEAD" && !getIsPossibleServerAction({
|
|
372
|
+
method: request.method,
|
|
373
|
+
headers
|
|
374
|
+
})) return finishWithBody(request, new registry.Response("Method Not Allowed", {
|
|
375
|
+
status: 405,
|
|
376
|
+
headers: { allow: "GET, HEAD" }
|
|
377
|
+
}), endRequest, routedHeaders);
|
|
378
|
+
const renderPage = async (page, entry, meta = requestMeta) => {
|
|
379
|
+
setServerActions(await serverActionsOf(routed));
|
|
380
|
+
const inline = !isRSCRequestHeader(headers.get(RSC_HEADER) ?? void 0);
|
|
381
|
+
const files = component ? opened?.node?.files ?? [] : [];
|
|
382
|
+
if (pageLoad && inline) await registry.preloadRoute(entry, files, request.signal);
|
|
383
|
+
const [stylesheets, { handler, routeModule }] = await Promise.all([registry.loadStylesheets(entry, inline, files), registry.loadAppPage(entry)]);
|
|
384
|
+
setStylesheets(stylesheets);
|
|
385
|
+
if (component) routeModule.distDir = nodeRouteDistDir;
|
|
386
|
+
const statusCode = page === notFoundPage ? 404 : void 0;
|
|
387
|
+
const respond = () => handleRequest$1(routed, context, handler, meta, {
|
|
388
|
+
statusCode,
|
|
389
|
+
headers: routedHeaders
|
|
390
|
+
});
|
|
391
|
+
if (page === notFoundPage) return respond();
|
|
392
|
+
if (prefetch) return withoutRoute(prerenders, respond);
|
|
393
|
+
return prerenderFirst(prerenders, scope, respond);
|
|
394
|
+
};
|
|
395
|
+
const renderNotFound = async () => finishWithBody(request, await renderPage(notFoundPage, notFoundPage, {}), endRequest, cookiesOf(routedHeaders));
|
|
396
|
+
if (!component && matched?.kind === "route") {
|
|
397
|
+
const handler = await registry.loadRouteHandler(page);
|
|
398
|
+
let response;
|
|
399
|
+
try {
|
|
400
|
+
response = await prerenderFirst(prerenders, scope, () => handleRequest$1(routed, context, handler, requestMeta, { headers: routedHeaders }));
|
|
401
|
+
} catch (error) {
|
|
402
|
+
if (registry.isNoFallbackError(error)) return renderNotFound();
|
|
403
|
+
if (!prerenders || request.signal?.aborted) throw error;
|
|
404
|
+
response = new registry.Response(null, { status: 500 });
|
|
405
|
+
}
|
|
406
|
+
if (prerenders && !(response.status < 400 || response.status === 404)) demoteRoute(prerenders);
|
|
407
|
+
return finishWithBody(request, response, endRequest, cookiesOf(routedHeaders));
|
|
408
|
+
}
|
|
409
|
+
if (prefetch) {
|
|
410
|
+
const pathname = withoutBasePath(target?.pathname ?? url.pathname);
|
|
411
|
+
if (await isUnlisted(prerenders, pathname.length > 1 ? pathname.replace(/\/$/, "") : pathname)) return renderNotFound();
|
|
412
|
+
}
|
|
413
|
+
let response;
|
|
414
|
+
try {
|
|
415
|
+
response = await renderPage(page, entry);
|
|
416
|
+
} catch (error) {
|
|
417
|
+
if (page === notFoundPage || !registry.isNoFallbackError(error)) throw error;
|
|
418
|
+
return renderNotFound();
|
|
419
|
+
}
|
|
420
|
+
return finishWithBody(request, response, endRequest, cookiesOf(routedHeaders));
|
|
421
|
+
} catch (error) {
|
|
422
|
+
scope.endScope();
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function cookiesOf(headers) {
|
|
427
|
+
const cookies = new registry.Headers();
|
|
428
|
+
for (const cookie of headers.getSetCookie()) cookies.append("set-cookie", cookie);
|
|
429
|
+
return cookies;
|
|
430
|
+
}
|
|
431
|
+
function finishWithBody(request, response, onFinish, routedHeaders) {
|
|
432
|
+
let finished;
|
|
433
|
+
let body = null;
|
|
434
|
+
const writing = writingOf(response);
|
|
435
|
+
if (writing) {
|
|
436
|
+
rendering.add(writing.stop);
|
|
437
|
+
body = response.body;
|
|
438
|
+
finished = writing.written.finally(() => {
|
|
439
|
+
rendering.delete(writing.stop);
|
|
440
|
+
return onFinish();
|
|
441
|
+
});
|
|
442
|
+
} else if (response.body) {
|
|
443
|
+
const pipe = new TransformStream(void 0, void 0, { highWaterMark: Infinity });
|
|
444
|
+
const stopping = new AbortController();
|
|
445
|
+
const stop = () => stopping.abort();
|
|
446
|
+
rendering.add(stop);
|
|
447
|
+
body = pipe.readable;
|
|
448
|
+
const source = response.body;
|
|
449
|
+
finished = source.pipeTo(pipe.writable, {
|
|
450
|
+
signal: stopping.signal,
|
|
451
|
+
preventCancel: true
|
|
452
|
+
}).catch(() => source.cancel(new DOMException("The page was left before the server had sent it.", "AbortError"))).catch(() => {}).finally(() => {
|
|
453
|
+
rendering.delete(stop);
|
|
454
|
+
return onFinish();
|
|
455
|
+
});
|
|
456
|
+
} else finished = onFinish();
|
|
457
|
+
const adds = routedHeaders !== void 0 && !routedHeaders.keys().next().done;
|
|
458
|
+
if (writing && !adds && request.method !== "HEAD") return {
|
|
459
|
+
response,
|
|
460
|
+
finished
|
|
461
|
+
};
|
|
462
|
+
let { headers } = response;
|
|
463
|
+
if (routedHeaders) {
|
|
464
|
+
headers = new registry.Headers(routedHeaders);
|
|
465
|
+
response.headers.forEach((value, name) => {
|
|
466
|
+
if (name === "set-cookie") headers.append(name, value);
|
|
467
|
+
else headers.set(name, value);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
return {
|
|
471
|
+
response: new registry.Response(request.method === "HEAD" ? null : body, {
|
|
472
|
+
status: response.status,
|
|
473
|
+
statusText: response.statusText,
|
|
474
|
+
headers
|
|
475
|
+
}),
|
|
476
|
+
finished
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
//#endregion
|
|
480
|
+
export { handleRequest, resetCaches, settleRequests, shellErrorAnswer };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/static-build.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The `next.config` of the app as the layers of a static build have it: with
|
|
6
|
+
* each option that is a path of the machine as a path from the root of the
|
|
7
|
+
* project, like `next.config.ts` and `../..`. Next's build reads them, and its
|
|
8
|
+
* server reads none for a request but the cache handlers, which the plugin
|
|
9
|
+
* imports by a module of its own, which the build bundles. A build would
|
|
10
|
+
* otherwise have the directory it was built in, and differ from machine to
|
|
11
|
+
* machine.
|
|
12
|
+
*
|
|
13
|
+
* By the options, not by what a value looks like: `basePath: "/app"` of a
|
|
14
|
+
* project in `/app` is no path of the machine.
|
|
15
|
+
*/
|
|
16
|
+
declare function withPathsFromRoot<T>(config: T, root: string): T;
|
|
17
|
+
type NextStaticBuildOptions = {
|
|
18
|
+
/** The Vite environment of each layer. */environments: {
|
|
19
|
+
rsc: string;
|
|
20
|
+
ssr: string;
|
|
21
|
+
browser: string;
|
|
22
|
+
}; /** What the page imports to start the layers that run through a module runner. */
|
|
23
|
+
entries: {
|
|
24
|
+
ssr: string;
|
|
25
|
+
browser: string;
|
|
26
|
+
}; /** The files Next's loaders made for the browser, by the path it asks for. */
|
|
27
|
+
emittedFiles(): {
|
|
28
|
+
pathname: string;
|
|
29
|
+
body: Uint8Array;
|
|
30
|
+
}[]; /** The plugin's module of the rsc layer, which renders the routes: rsc.ts. */
|
|
31
|
+
rscModule: string; /** Whether a module of the rsc layer's build is a file of the host. */
|
|
32
|
+
isHostFile(id: string): boolean;
|
|
33
|
+
};
|
|
34
|
+
declare function nextStaticBuild(options: NextStaticBuildOptions): Plugin;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { NextStaticBuildOptions, nextStaticBuild, withPathsFromRoot };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { normalizePath } from "vite";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getPluginApi } from "@vitejs/plugin-rsc/plugin";
|
|
4
|
+
import { withStaticBuild } from "@kasperpeulen/vitest-plugin-rsc/internal/static-build";
|
|
5
|
+
//#region src/static-build.ts
|
|
6
|
+
const configPaths = [
|
|
7
|
+
["configFile"],
|
|
8
|
+
["outputFileTracingRoot"],
|
|
9
|
+
["repoRoot"],
|
|
10
|
+
["turbopack", "root"],
|
|
11
|
+
["images", "loaderFile"],
|
|
12
|
+
["cacheHandler"],
|
|
13
|
+
["cacheHandlers", "*"],
|
|
14
|
+
["adapterPath"]
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* The `next.config` of the app as the layers of a static build have it: with
|
|
18
|
+
* each option that is a path of the machine as a path from the root of the
|
|
19
|
+
* project, like `next.config.ts` and `../..`. Next's build reads them, and its
|
|
20
|
+
* server reads none for a request but the cache handlers, which the plugin
|
|
21
|
+
* imports by a module of its own, which the build bundles. A build would
|
|
22
|
+
* otherwise have the directory it was built in, and differ from machine to
|
|
23
|
+
* machine.
|
|
24
|
+
*
|
|
25
|
+
* By the options, not by what a value looks like: `basePath: "/app"` of a
|
|
26
|
+
* project in `/app` is no path of the machine.
|
|
27
|
+
*/
|
|
28
|
+
function withPathsFromRoot(config, root) {
|
|
29
|
+
const copy = JSON.parse(JSON.stringify(config));
|
|
30
|
+
const relativize = (object, [key, ...rest]) => {
|
|
31
|
+
for (const name of key === "*" ? Object.keys(object) : [key]) {
|
|
32
|
+
const value = object[name];
|
|
33
|
+
if (rest.length > 0) {
|
|
34
|
+
if (value && typeof value === "object") relativize(value, rest);
|
|
35
|
+
} else if (typeof value === "string" && path.isAbsolute(value)) object[name] = normalizePath(path.relative(root, value)) || ".";
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
for (const keys of configPaths) relativize(copy, keys);
|
|
39
|
+
return copy;
|
|
40
|
+
}
|
|
41
|
+
function nextStaticBuild(options) {
|
|
42
|
+
const { rsc, ssr, browser } = options.environments;
|
|
43
|
+
let manager;
|
|
44
|
+
let reached;
|
|
45
|
+
return {
|
|
46
|
+
name: "vitest-plugin-rsc:next-static-build",
|
|
47
|
+
config(_config, { command }) {
|
|
48
|
+
if (command !== "build") return;
|
|
49
|
+
return withStaticBuild({
|
|
50
|
+
entries: {
|
|
51
|
+
[ssr]: options.entries.ssr,
|
|
52
|
+
[browser]: options.entries.browser
|
|
53
|
+
},
|
|
54
|
+
directives: ["use turbopack: no side effects"],
|
|
55
|
+
strictExecutionOrder: true,
|
|
56
|
+
files: options.emittedFiles,
|
|
57
|
+
clientReferences: { [ssr]: () => reached }
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
configResolved(resolved) {
|
|
61
|
+
if (resolved.command !== "build") return;
|
|
62
|
+
manager = getPluginApi(resolved)?.manager;
|
|
63
|
+
if (!resolved.plugins.some((plugin) => plugin.name === "vitest-plugin-rsc:static-build")) throw new Error("vitest-plugin-rsc: vitestPluginNext() needs vitestPluginRSC().");
|
|
64
|
+
},
|
|
65
|
+
buildEnd(error) {
|
|
66
|
+
if (error || this.environment.mode !== "build" || this.environment.name !== rsc) return;
|
|
67
|
+
if (!manager || manager.isScanBuild) return;
|
|
68
|
+
reached = void 0;
|
|
69
|
+
if (!this.getModuleInfo(options.rscModule)) return;
|
|
70
|
+
const references = manager.clientReferenceMetaMap;
|
|
71
|
+
const found = /* @__PURE__ */ new Set();
|
|
72
|
+
const queue = [...this.getModuleIds()].filter((id) => id === options.rscModule || options.isHostFile(id) && !references[id]);
|
|
73
|
+
const seen = new Set(queue);
|
|
74
|
+
for (const id of queue) {
|
|
75
|
+
const reference = references[id];
|
|
76
|
+
if (reference) {
|
|
77
|
+
found.add(reference.referenceKey);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const info = this.getModuleInfo(id);
|
|
81
|
+
for (const imported of [...info?.importedIds ?? [], ...info?.dynamicallyImportedIds ?? []]) {
|
|
82
|
+
if (seen.has(imported)) continue;
|
|
83
|
+
seen.add(imported);
|
|
84
|
+
queue.push(imported);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
reached = found;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { nextStaticBuild, withPathsFromRoot };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/storage.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The items of the page's `localStorage` and `sessionStorage`. One for each
|
|
4
|
+
* browser context of the app.
|
|
5
|
+
*/
|
|
6
|
+
declare class PageStorage {
|
|
7
|
+
readonly localStorage: Map<string, string>;
|
|
8
|
+
readonly sessionStorage: Map<string, string>;
|
|
9
|
+
}
|
|
10
|
+
/** The items of a storage, as a map has them: the page's, or the browser's. */
|
|
11
|
+
type Items = {
|
|
12
|
+
get(key: string): string | undefined;
|
|
13
|
+
set(key: string, value: string): void;
|
|
14
|
+
delete(key: string): boolean;
|
|
15
|
+
has(key: string): boolean;
|
|
16
|
+
clear(): void;
|
|
17
|
+
keys(): Iterable<string>;
|
|
18
|
+
readonly size: number;
|
|
19
|
+
};
|
|
20
|
+
/** The items of a `Storage` of the browser's, as a map. */
|
|
21
|
+
declare function itemsOfStorage(storage: Storage): Items;
|
|
22
|
+
/**
|
|
23
|
+
* A `Storage` of the items that `items()` returns each time it is used. Its
|
|
24
|
+
* items are its properties too, as in a browser: `storage.theme`,
|
|
25
|
+
* `Object.keys(storage)` and `JSON.stringify(storage)` have them, and setting
|
|
26
|
+
* or deleting a property sets or removes an item. A name of `Storage`, like
|
|
27
|
+
* `key` or `length`, hides the item of that name.
|
|
28
|
+
*/
|
|
29
|
+
declare function storageOf(items: () => Items): Storage;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { Items, PageStorage, itemsOfStorage, storageOf };
|