@rsc-kit/core 0.30.13 → 0.30.14
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/dist/vite.d.ts +24 -0
- package/dist/vite.js +58 -5
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
package/dist/vite.d.ts
CHANGED
|
@@ -186,6 +186,24 @@ export interface RscKitOptions {
|
|
|
186
186
|
* alone before Nitro built the server from the same entry.
|
|
187
187
|
*/
|
|
188
188
|
devFallback?: string | false;
|
|
189
|
+
/**
|
|
190
|
+
* Paths that belong to the backend, whatever page would also match them.
|
|
191
|
+
*
|
|
192
|
+
* A url nothing here owns is handed to the backend, but a page that matches
|
|
193
|
+
* is this app's: a dynamic root route such as `[team]/[app]` matches every
|
|
194
|
+
* two-segment url, renders, says `notFound()` - and a page that said that is
|
|
195
|
+
* never forwarded, so `/gitlab/connect` was the not-found page and the
|
|
196
|
+
* backend never saw it. Naming the prefixes the backend owns forwards them
|
|
197
|
+
* before any page is matched:
|
|
198
|
+
*
|
|
199
|
+
* rscKit({ backendPaths: ['/auth', '/github', '/gitlab'] })
|
|
200
|
+
*
|
|
201
|
+
* Each is a prefix at a segment boundary - `/auth` is `/auth` and everything
|
|
202
|
+
* under it, never `/authors` - and every method goes, a POST as a GET. A
|
|
203
|
+
* team called `auth` is then unreachable, which is the price of the name.
|
|
204
|
+
* Without a backend where this runs, such a url is this app's not-found page.
|
|
205
|
+
*/
|
|
206
|
+
backendPaths?: string[];
|
|
189
207
|
/**
|
|
190
208
|
* This package's directory, holding the client runtime the browser entry
|
|
191
209
|
* imports. Vite stages configs through node_modules/.vite-temp, so
|
|
@@ -297,6 +315,12 @@ export interface RscKitOptions {
|
|
|
297
315
|
watch?: string[];
|
|
298
316
|
};
|
|
299
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* The prefixes a backend owns, as the matcher reads them: `/auth`, no trailing
|
|
320
|
+
* slash. Refused rather than corrected where a mistake would silently send the
|
|
321
|
+
* whole app, or its own endpoints, to the backend.
|
|
322
|
+
*/
|
|
323
|
+
export declare function normaliseBackendPaths(paths: readonly string[] | undefined): string[];
|
|
300
324
|
/**
|
|
301
325
|
* The service worker, written into the client output at build time.
|
|
302
326
|
*
|
package/dist/vite.js
CHANGED
|
@@ -157,6 +157,7 @@ let typesDir;
|
|
|
157
157
|
let hotFile;
|
|
158
158
|
let hostCallOptions;
|
|
159
159
|
let packageDir;
|
|
160
|
+
let backendPaths = [];
|
|
160
161
|
let hostGlobal;
|
|
161
162
|
let interceptManifestFile;
|
|
162
163
|
let packageAlias;
|
|
@@ -348,6 +349,34 @@ function aliasEntries() {
|
|
|
348
349
|
});
|
|
349
350
|
return entries;
|
|
350
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* The prefixes a backend owns, as the matcher reads them: `/auth`, no trailing
|
|
354
|
+
* slash. Refused rather than corrected where a mistake would silently send the
|
|
355
|
+
* whole app, or its own endpoints, to the backend.
|
|
356
|
+
*/
|
|
357
|
+
export function normaliseBackendPaths(paths) {
|
|
358
|
+
const out = [];
|
|
359
|
+
for (const raw of paths ?? []) {
|
|
360
|
+
const given = typeof raw === "string" ? raw.trim() : "";
|
|
361
|
+
if (!given.startsWith("/")) {
|
|
362
|
+
throw new Error(`[rsc-kit] backendPaths: ${JSON.stringify(raw)} is not a path. Each starts with a slash, as in '/auth'.`);
|
|
363
|
+
}
|
|
364
|
+
// After the slash check, so "/" is the root and not "not a path".
|
|
365
|
+
const path = given.replace(/\/+$/, "");
|
|
366
|
+
if (path === "") {
|
|
367
|
+
throw new Error("[rsc-kit] backendPaths: '/' is every url, and nothing would be left for this app. Name the prefixes the backend owns.");
|
|
368
|
+
}
|
|
369
|
+
if (path === "/_rsc" || path.startsWith("/_rsc/")) {
|
|
370
|
+
throw new Error(`[rsc-kit] backendPaths: ${JSON.stringify(raw)} is this package's own endpoint, which the renderer answers.`);
|
|
371
|
+
}
|
|
372
|
+
if (/[?#*]/.test(path)) {
|
|
373
|
+
throw new Error(`[rsc-kit] backendPaths: ${JSON.stringify(raw)} is a prefix, not a pattern: no query, fragment or wildcard.`);
|
|
374
|
+
}
|
|
375
|
+
if (!out.includes(path))
|
|
376
|
+
out.push(path);
|
|
377
|
+
}
|
|
378
|
+
return out;
|
|
379
|
+
}
|
|
351
380
|
function resolvePaths(options) {
|
|
352
381
|
projectRoot = resolve(options.projectRoot || process.env.RSC_PROJECT_ROOT || process.cwd());
|
|
353
382
|
sourceDir = resolve(options.sourceDir || process.env.RSC_SOURCE_DIR || join(projectRoot, "src"));
|
|
@@ -385,6 +414,7 @@ function resolvePaths(options) {
|
|
|
385
414
|
hotFile = options.hotFile || process.env.RSC_HOT_FILE || "";
|
|
386
415
|
hostCallOptions = options.hostCall;
|
|
387
416
|
packageDir = resolve(options.packageDir || process.env.RSC_PACKAGE_DIR || thisDir());
|
|
417
|
+
backendPaths = normaliseBackendPaths(options.backendPaths);
|
|
388
418
|
hostGlobal = options.hostGlobal || process.env.RSC_HOST_GLOBAL || "rpc";
|
|
389
419
|
interceptManifestFile = resolve(options.interceptManifestFile ||
|
|
390
420
|
process.env.RSC_INTERCEPT_MANIFEST ||
|
|
@@ -2769,17 +2799,40 @@ function fallbackOrigin(): string {
|
|
|
2769
2799
|
const FALLBACK_MARKER = 'x-rsc-renderer-fallback'
|
|
2770
2800
|
const PROXIED_MARKER = 'x-rsc-proxied-by-backend'
|
|
2771
2801
|
`;
|
|
2802
|
+
/**
|
|
2803
|
+
* The urls the app said belong to the backend, tested before any page is
|
|
2804
|
+
* matched. Emitted in both variants: a test's stand-in backend is reached by
|
|
2805
|
+
* the same prefixes as the real one.
|
|
2806
|
+
*/
|
|
2807
|
+
function backendPathConsts() {
|
|
2808
|
+
return `const BACKEND_PATHS: string[] = ${JSON.stringify(backendPaths)}
|
|
2809
|
+
|
|
2810
|
+
// A prefix at a segment boundary: '/auth' is '/auth' and what is under it, not '/authors'.
|
|
2811
|
+
function onBackendPath(pathname: string): boolean {
|
|
2812
|
+
return BACKEND_PATHS.some((prefix) => pathname === prefix || pathname.startsWith(prefix + '/'))
|
|
2813
|
+
}
|
|
2814
|
+
`;
|
|
2815
|
+
}
|
|
2772
2816
|
/** With no backend configured: this app's not-found page, or a test's backend. */
|
|
2773
|
-
const NO_FALLBACK_BODY = `
|
|
2817
|
+
const NO_FALLBACK_BODY = ` // The app named this prefix as the backend's: no page is asked about it, so one
|
|
2818
|
+
// that matches (a dynamic root route) cannot answer for it.
|
|
2819
|
+
const toBackend = onBackendPath(new URL(request.url).pathname)
|
|
2820
|
+
const answer = toBackend ? null : await devHandler(request)
|
|
2774
2821
|
|
|
2775
2822
|
if (answer) return answer
|
|
2776
2823
|
|
|
2777
|
-
if (backendForward && !pageSaidNotFound(request)) return await backendForward(request)
|
|
2824
|
+
if (backendForward && (toBackend || !pageSaidNotFound(request))) return await backendForward(request)
|
|
2778
2825
|
|
|
2779
2826
|
return await notFound(request)
|
|
2780
2827
|
`;
|
|
2781
2828
|
const FALLBACK_BODY = ` const FALLBACK_ORIGIN = fallbackOrigin()
|
|
2782
|
-
|
|
2829
|
+
|
|
2830
|
+
// The app named this prefix as the backend's (rscKit({ backendPaths })): no
|
|
2831
|
+
// page is asked about it. A dynamic root route such as [team]/[app] matches
|
|
2832
|
+
// /gitlab/connect, renders, says notFound() - and a page that said that is not
|
|
2833
|
+
// forwarded, so the backend's own route was the not-found page.
|
|
2834
|
+
const toBackend = onBackendPath(new URL(request.url).pathname)
|
|
2835
|
+
const answer = toBackend ? null : await devHandler(request)
|
|
2783
2836
|
|
|
2784
2837
|
if (answer) return answer
|
|
2785
2838
|
|
|
@@ -2787,7 +2840,7 @@ const FALLBACK_BODY = ` const FALLBACK_ORIGIN = fallbackOrigin()
|
|
|
2787
2840
|
// its guard, or a backend's 404. That is this app's not-found.tsx, not a
|
|
2788
2841
|
// url for the backend: forwarded, the backend answered with its own 404
|
|
2789
2842
|
// and the app's never showed.
|
|
2790
|
-
if (pageSaidNotFound(request)) return await notFound(request)
|
|
2843
|
+
if (!toBackend && pageSaidNotFound(request)) return await notFound(request)
|
|
2791
2844
|
|
|
2792
2845
|
// Nothing here owns this url. In development the backend usually does — a
|
|
2793
2846
|
// Blade page, /login, a webhook, an uploaded file under /storage — so the
|
|
@@ -5707,7 +5760,7 @@ export async function handleRscPprShell(
|
|
|
5707
5760
|
* server rendering live pages it had already frozen. The gate is the mode, not
|
|
5708
5761
|
* the file.
|
|
5709
5762
|
*/
|
|
5710
|
-
${fallbackOrigin === false ? "" : FALLBACK_CONSTS.replace("__ORIGIN__", JSON.stringify(fallbackOrigin))}${NITRO_HOST_CALLS}
|
|
5763
|
+
${backendPathConsts()}${fallbackOrigin === false ? "" : FALLBACK_CONSTS.replace("__ORIGIN__", JSON.stringify(fallbackOrigin))}${NITRO_HOST_CALLS}
|
|
5711
5764
|
let devHandler: ((request: Request) => Promise<Response | null>) | null = null
|
|
5712
5765
|
|
|
5713
5766
|
export default async function handler(request: Request): Promise<Response> {
|