waku 1.0.0-beta.6 → 1.0.0-beta.7
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 +3 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/lib/global-types.d.ts +0 -1
- package/dist/lib/types.d.ts +3 -0
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils/etags.d.ts +8 -0
- package/dist/lib/utils/etags.js +30 -0
- package/dist/lib/utils/etags.js.map +1 -0
- package/dist/lib/utils/path.d.ts +0 -41
- package/dist/lib/utils/path.js +0 -178
- package/dist/lib/utils/path.js.map +1 -1
- package/dist/lib/utils/render.js +6 -0
- package/dist/lib/utils/render.js.map +1 -1
- package/dist/lib/utils/request.d.ts +2 -1
- package/dist/lib/utils/request.js +18 -5
- package/dist/lib/utils/request.js.map +1 -1
- package/dist/lib/vite-plugins/fs-router-typegen.js +1 -1
- package/dist/lib/vite-plugins/fs-router-typegen.js.map +1 -1
- package/dist/minimal/client-utils/fetch-store.d.ts +3 -0
- package/dist/minimal/client-utils/fetch-store.js +1 -0
- package/dist/minimal/client-utils/fetch-store.js.map +1 -1
- package/dist/minimal/client.d.ts +21 -4
- package/dist/minimal/client.js +168 -76
- package/dist/minimal/client.js.map +1 -1
- package/dist/minimal/server.d.ts +16 -0
- package/dist/minimal/server.js +30 -0
- package/dist/minimal/server.js.map +1 -1
- package/dist/router/base-types.d.ts +2 -2
- package/dist/router/base-types.js.map +1 -1
- package/dist/router/client-utils/navigate.d.ts +39 -0
- package/dist/router/client-utils/navigate.js +95 -0
- package/dist/router/client-utils/navigate.js.map +1 -0
- package/dist/router/client.d.ts +15 -7
- package/dist/router/client.js +292 -303
- package/dist/router/client.js.map +1 -1
- package/dist/router/create-pages-utils/inferred-path-types.js.map +1 -1
- package/dist/router/create-pages-utils/path-spec.d.ts +6 -0
- package/dist/router/create-pages-utils/path-spec.js +22 -0
- package/dist/router/create-pages-utils/path-spec.js.map +1 -0
- package/dist/router/create-pages.d.ts +3 -3
- package/dist/router/create-pages.js +4 -4
- package/dist/router/create-pages.js.map +1 -1
- package/dist/router/define-router-utils/path-spec.d.ts +5 -0
- package/dist/router/define-router-utils/path-spec.js +19 -0
- package/dist/router/define-router-utils/path-spec.js.map +1 -0
- package/dist/router/define-router-utils/task-runner.js.map +1 -0
- package/dist/router/define-router.d.ts +1 -1
- package/dist/router/define-router.js +107 -93
- package/dist/router/define-router.js.map +1 -1
- package/dist/router/fs-router.d.ts +4 -4
- package/dist/router/fs-router.js +1 -1
- package/dist/router/fs-router.js.map +1 -1
- package/dist/router/isomorphic-utils/build-route-href.js +2 -2
- package/dist/router/isomorphic-utils/build-route-href.js.map +1 -1
- package/dist/router/isomorphic-utils/match-route-params.js +2 -2
- package/dist/router/isomorphic-utils/match-route-params.js.map +1 -1
- package/dist/router/isomorphic-utils/path-spec.d.ts +32 -0
- package/dist/router/isomorphic-utils/path-spec.js +143 -0
- package/dist/router/isomorphic-utils/path-spec.js.map +1 -0
- package/dist/router/isomorphic-utils/route-path.d.ts +0 -3
- package/dist/router/isomorphic-utils/route-path.js +0 -6
- package/dist/router/isomorphic-utils/route-path.js.map +1 -1
- package/dist/router/prefetch-cache.d.ts +22 -0
- package/dist/router/prefetch-cache.js +79 -0
- package/dist/router/prefetch-cache.js.map +1 -0
- package/package.json +1 -1
- package/dist/lib/utils/task-runner.js.map +0 -1
- package/dist/minimal/client-utils/prefetch-cache.d.ts +0 -15
- package/dist/minimal/client-utils/prefetch-cache.js +0 -37
- package/dist/minimal/client-utils/prefetch-cache.js.map +0 -1
- /package/dist/{lib/utils → router/define-router-utils}/task-runner.d.ts +0 -0
- /package/dist/{lib/utils → router/define-router-utils}/task-runner.js +0 -0
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ visit [waku.gg](https://waku.gg) or `npm create waku@latest`
|
|
|
13
13
|
|
|
14
14
|
## Introduction
|
|
15
15
|
|
|
16
|
-
**Waku** _(wah-ku)_ or **わく** is the minimal React framework. It's lightweight and designed for a fun developer experience, yet supports all the latest React 19 features like server components and actions. Built for marketing sites, headless commerce, and web apps
|
|
16
|
+
**Waku** _(wah-ku)_ or **わく** is the minimal React framework. It's lightweight and designed for a fun developer experience, yet supports all the latest React 19 features like server components and actions. Built for marketing sites, headless commerce, and full-stack web apps, small or large. Whether Waku fits is about the architecture you want, not the size of your project: Waku keeps its framework surface minimal and composes with ecosystem libraries, while heavier frameworks own more of those concerns for you.
|
|
17
17
|
|
|
18
18
|
## Getting started
|
|
19
19
|
|
|
@@ -31,6 +31,8 @@ npm create waku@latest
|
|
|
31
31
|
|
|
32
32
|
**Node.js version requirement:** `^26.0.0` or `^24.0.0` or `^22.15.0`
|
|
33
33
|
|
|
34
|
+
For a guided path, start with the [Quick Start](https://waku.gg/guides/quick-start) guide and continue with the Learn series on [waku.gg/guides](https://waku.gg/guides), which builds a small app step by step.
|
|
35
|
+
|
|
34
36
|
## Rendering
|
|
35
37
|
|
|
36
38
|
While there's a bit of a learning curve to modern React rendering, it introduces powerful new patterns of full-stack composability that are only possible with the advent of [server components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md).
|
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getErrorInfo } from './lib/utils/custom-errors.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Experimental, the name and the behavior might change.
|
|
4
4
|
*/ export const unstable_allowServer = (x)=>x;
|
|
5
5
|
/**
|
|
6
6
|
* Unsure if this is going to be a public API in the future.
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import { getErrorInfo } from './lib/utils/custom-errors.js';\n\n/**\n *
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import { getErrorInfo } from './lib/utils/custom-errors.js';\n\n/**\n * Experimental, the name and the behavior might change.\n */\nexport const unstable_allowServer = <T>(x: T) => x;\n\n/**\n * Unsure if this is going to be a public API in the future.\n */\nexport const unstable_defaultRootOptions = {\n onCaughtError(error: unknown) {\n if (getErrorInfo(error)) {\n return;\n }\n console.error(error);\n },\n};\n"],"names":["getErrorInfo","unstable_allowServer","x","unstable_defaultRootOptions","onCaughtError","error","console"],"mappings":"AAAA,SAASA,YAAY,QAAQ,+BAA+B;AAE5D;;CAEC,GACD,OAAO,MAAMC,uBAAuB,CAAIC,IAASA,EAAE;AAEnD;;CAEC,GACD,OAAO,MAAMC,8BAA8B;IACzCC,eAAcC,KAAc;QAC1B,IAAIL,aAAaK,QAAQ;YACvB;QACF;QACAC,QAAQD,KAAK,CAACA;IAChB;AACF,EAAE"}
|
|
@@ -4,7 +4,6 @@ declare global {
|
|
|
4
4
|
var __WAKU_REFETCH_ROUTE__: (() => void) | undefined;
|
|
5
5
|
var __WAKU_START_PREVIEW_SERVER__: (() => Promise<import('./vite-rsc/preview.js').PreviewServer>) | undefined;
|
|
6
6
|
var __WAKU_SERVER_ENV__: Readonly<Record<string, string>> | undefined;
|
|
7
|
-
var __WAKU_PREFETCHED__: import('../minimal/client-utils/prefetch-cache.js').PrefetchEntry[] | undefined;
|
|
8
7
|
var __WAKU_INITIAL_RSC__: import('./utils/initial-rsc.js').InitialRscEntry | undefined;
|
|
9
8
|
var __WAKU_DEBUG_CHANNELS__: Map<string, {
|
|
10
9
|
readable: ReadableStream;
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { Config } from '../config.js';
|
|
3
|
+
import type { Etags } from './utils/etags.js';
|
|
3
4
|
type Elements = Record<string, unknown>;
|
|
4
5
|
export type Unstable_RenderRsc = (elements: Elements, options?: {
|
|
5
6
|
value?: unknown;
|
|
7
|
+
etags?: Etags;
|
|
6
8
|
unstable_clientModuleCallback?: (ids: string[]) => void;
|
|
7
9
|
}) => Promise<ReadableStream>;
|
|
8
10
|
export type Unstable_ParseRsc = (rscStream: ReadableStream) => Promise<Elements>;
|
|
@@ -30,6 +32,7 @@ export type Unstable_HandleRequest = (input: ({
|
|
|
30
32
|
}) & {
|
|
31
33
|
pathname: string;
|
|
32
34
|
req: Request;
|
|
35
|
+
etags?: Etags;
|
|
33
36
|
}, utils: {
|
|
34
37
|
renderRsc: Unstable_RenderRsc;
|
|
35
38
|
parseRsc: Unstable_ParseRsc;
|
package/dist/lib/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/types.ts"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { Config } from '../config.js';\n\ntype Elements = Record<string, unknown>;\n\nexport type Unstable_RenderRsc = (\n elements: Elements,\n options?: {\n value?: unknown;\n unstable_clientModuleCallback?: (ids: string[]) => void;\n },\n) => Promise<ReadableStream>;\n\nexport type Unstable_ParseRsc = (\n rscStream: ReadableStream,\n) => Promise<Elements>;\n\nexport type Unstable_RenderHtml = (\n elementsStream: ReadableStream,\n html: ReactNode,\n options: {\n rscPath: string;\n formState?: unknown;\n status?: number;\n nonce?: string;\n unstable_extraScriptContent?: string;\n },\n) => Promise<Response>;\n\nexport type Unstable_EmitFile = (\n filePath: string,\n body: ReadableStream,\n) => Promise<void>;\n\nexport type Unstable_HandleRequest = (\n input: (\n | { type: 'component'; rscPath: string; rscParams: unknown }\n | {\n type: 'function';\n fn: (...args: unknown[]) => Promise<unknown>;\n args: unknown[];\n }\n | {\n type: 'action';\n fn: () => Promise<unknown>;\n }\n | { type: 'custom' }\n ) & {\n pathname: string;\n req: Request;\n },\n utils: {\n renderRsc: Unstable_RenderRsc;\n parseRsc: Unstable_ParseRsc;\n renderHtml: Unstable_RenderHtml;\n loadBuildMetadata: (key: string) => Promise<string | undefined>;\n },\n) => Promise<ReadableStream | Response | 'fallback' | null | undefined>;\n\nexport type Unstable_HandleBuild = (utils: {\n renderRsc: Unstable_RenderRsc;\n parseRsc: Unstable_ParseRsc;\n renderHtml: Unstable_RenderHtml;\n rscPath2pathname: (rscPath: string) => string;\n saveBuildMetadata: (key: string, value: string) => Promise<void>;\n generateFile: (\n fileName: string,\n body: ReadableStream | string,\n ) => Promise<void>;\n generateDefaultHtml: (fileName: string) => Promise<void>;\n unstable_registerPrunableFile: (srcPath: string) => void;\n}) => Promise<void>;\n\nexport type Unstable_Handlers = {\n handleRequest: Unstable_HandleRequest;\n handleBuild: Unstable_HandleBuild;\n [someOtherProperty: string]: unknown;\n};\n\nexport type Unstable_ServerEntry = {\n fetch: (req: Request, ...args: any[]) => Response | Promise<Response>;\n build: (\n utils: {\n emitFile: Unstable_EmitFile;\n unstable_registerPrunableFile: (srcPath: string) => void;\n },\n ...args: any[]\n ) => Promise<void>;\n buildOptions?: Record<string, unknown>;\n buildEnhancers?: string[]; // enhancer module ids\n defaultExport?: unknown;\n [someOtherProperty: string]: unknown;\n};\n\nexport type Unstable_ProcessRequest = (\n arg: Parameters<Unstable_ServerEntry['fetch']>[0],\n) => Promise<Response | null>;\n\nexport type Unstable_ProcessBuild = (\n arg: Parameters<Unstable_ServerEntry['build']>[0],\n) => Promise<void>;\n\nexport type Unstable_CreateServerEntryAdapter = <Options>(\n fn: (\n args: {\n handlers: Unstable_Handlers;\n processRequest: Unstable_ProcessRequest;\n processBuild: Unstable_ProcessBuild;\n setAllEnv: (newEnv: Readonly<Record<string, unknown>>) => void;\n config: Omit<Required<Config>, 'vite'>;\n isBuild: boolean;\n notFoundHtml: string;\n },\n options?: Options,\n ) => Unstable_ServerEntry,\n) => (handlers: Unstable_Handlers, options?: Options) => Unstable_ServerEntry;\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/lib/types.ts"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { Config } from '../config.js';\nimport type { Etags } from './utils/etags.js';\n\ntype Elements = Record<string, unknown>;\n\nexport type Unstable_RenderRsc = (\n elements: Elements,\n options?: {\n value?: unknown;\n etags?: Etags;\n unstable_clientModuleCallback?: (ids: string[]) => void;\n },\n) => Promise<ReadableStream>;\n\nexport type Unstable_ParseRsc = (\n rscStream: ReadableStream,\n) => Promise<Elements>;\n\nexport type Unstable_RenderHtml = (\n elementsStream: ReadableStream,\n html: ReactNode,\n options: {\n rscPath: string;\n formState?: unknown;\n status?: number;\n nonce?: string;\n unstable_extraScriptContent?: string;\n },\n) => Promise<Response>;\n\nexport type Unstable_EmitFile = (\n filePath: string,\n body: ReadableStream,\n) => Promise<void>;\n\nexport type Unstable_HandleRequest = (\n input: (\n | { type: 'component'; rscPath: string; rscParams: unknown }\n | {\n type: 'function';\n fn: (...args: unknown[]) => Promise<unknown>;\n args: unknown[];\n }\n | {\n type: 'action';\n fn: () => Promise<unknown>;\n }\n | { type: 'custom' }\n ) & {\n pathname: string;\n req: Request;\n etags?: Etags;\n },\n utils: {\n renderRsc: Unstable_RenderRsc;\n parseRsc: Unstable_ParseRsc;\n renderHtml: Unstable_RenderHtml;\n loadBuildMetadata: (key: string) => Promise<string | undefined>;\n },\n) => Promise<ReadableStream | Response | 'fallback' | null | undefined>;\n\nexport type Unstable_HandleBuild = (utils: {\n renderRsc: Unstable_RenderRsc;\n parseRsc: Unstable_ParseRsc;\n renderHtml: Unstable_RenderHtml;\n rscPath2pathname: (rscPath: string) => string;\n saveBuildMetadata: (key: string, value: string) => Promise<void>;\n generateFile: (\n fileName: string,\n body: ReadableStream | string,\n ) => Promise<void>;\n generateDefaultHtml: (fileName: string) => Promise<void>;\n unstable_registerPrunableFile: (srcPath: string) => void;\n}) => Promise<void>;\n\nexport type Unstable_Handlers = {\n handleRequest: Unstable_HandleRequest;\n handleBuild: Unstable_HandleBuild;\n [someOtherProperty: string]: unknown;\n};\n\nexport type Unstable_ServerEntry = {\n fetch: (req: Request, ...args: any[]) => Response | Promise<Response>;\n build: (\n utils: {\n emitFile: Unstable_EmitFile;\n unstable_registerPrunableFile: (srcPath: string) => void;\n },\n ...args: any[]\n ) => Promise<void>;\n buildOptions?: Record<string, unknown>;\n buildEnhancers?: string[]; // enhancer module ids\n defaultExport?: unknown;\n [someOtherProperty: string]: unknown;\n};\n\nexport type Unstable_ProcessRequest = (\n arg: Parameters<Unstable_ServerEntry['fetch']>[0],\n) => Promise<Response | null>;\n\nexport type Unstable_ProcessBuild = (\n arg: Parameters<Unstable_ServerEntry['build']>[0],\n) => Promise<void>;\n\nexport type Unstable_CreateServerEntryAdapter = <Options>(\n fn: (\n args: {\n handlers: Unstable_Handlers;\n processRequest: Unstable_ProcessRequest;\n processBuild: Unstable_ProcessBuild;\n setAllEnv: (newEnv: Readonly<Record<string, unknown>>) => void;\n config: Omit<Required<Config>, 'vite'>;\n isBuild: boolean;\n notFoundHtml: string;\n },\n options?: Options,\n ) => Unstable_ServerEntry,\n) => (handlers: Unstable_Handlers, options?: Options) => Unstable_ServerEntry;\n"],"names":[],"mappings":"AAyGA,WAa8E"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const ETAG_ID_PREFIX = "_etag:";
|
|
2
|
+
export declare const ETAGS_HEADER = "X-Waku-Etags";
|
|
3
|
+
export declare const IMMUTABLE_ETAG = 1;
|
|
4
|
+
export type Etag = string | typeof IMMUTABLE_ETAG;
|
|
5
|
+
export type Etags = Record<string, Etag>;
|
|
6
|
+
export declare const isValidEtag: (value: unknown) => value is Etag;
|
|
7
|
+
export declare const parseClientEtags: (serialized: string | null) => Etags;
|
|
8
|
+
export declare const serializeClientEtags: (etags: Etags) => string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const ETAG_ID_PREFIX = '_etag:';
|
|
2
|
+
export const ETAGS_HEADER = 'X-Waku-Etags';
|
|
3
|
+
// Non-string sentinel, so it cannot collide with a (string) content validator.
|
|
4
|
+
export const IMMUTABLE_ETAG = 1;
|
|
5
|
+
// '' clears a tag; only printable Latin-1 (no control chars) is header-safe
|
|
6
|
+
export const isValidEtag = (value)=>value === IMMUTABLE_ETAG || typeof value === 'string' && value !== '' && /^[\x20-\x7e\xa0-\xff]+$/.test(value);
|
|
7
|
+
export const parseClientEtags = (serialized)=>{
|
|
8
|
+
if (!serialized) {
|
|
9
|
+
return {};
|
|
10
|
+
}
|
|
11
|
+
let parsed;
|
|
12
|
+
try {
|
|
13
|
+
parsed = JSON.parse(serialized);
|
|
14
|
+
} catch {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
const etags = {};
|
|
21
|
+
for (const [key, value] of Object.entries(parsed)){
|
|
22
|
+
if (isValidEtag(value)) {
|
|
23
|
+
etags[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return etags;
|
|
27
|
+
};
|
|
28
|
+
export const serializeClientEtags = (etags)=>JSON.stringify(etags);
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=etags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils/etags.ts"],"sourcesContent":["export const ETAG_ID_PREFIX = '_etag:';\nexport const ETAGS_HEADER = 'X-Waku-Etags';\n\n// Non-string sentinel, so it cannot collide with a (string) content validator.\nexport const IMMUTABLE_ETAG = 1;\n\nexport type Etag = string | typeof IMMUTABLE_ETAG;\nexport type Etags = Record<string, Etag>;\n\n// '' clears a tag; only printable Latin-1 (no control chars) is header-safe\nexport const isValidEtag = (value: unknown): value is Etag =>\n value === IMMUTABLE_ETAG ||\n (typeof value === 'string' &&\n value !== '' &&\n /^[\\x20-\\x7e\\xa0-\\xff]+$/.test(value));\n\nexport const parseClientEtags = (serialized: string | null): Etags => {\n if (!serialized) {\n return {};\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(serialized);\n } catch {\n return {};\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return {};\n }\n const etags: Etags = {};\n for (const [key, value] of Object.entries(parsed)) {\n if (isValidEtag(value)) {\n etags[key] = value;\n }\n }\n return etags;\n};\n\nexport const serializeClientEtags = (etags: Etags): string =>\n JSON.stringify(etags);\n"],"names":["ETAG_ID_PREFIX","ETAGS_HEADER","IMMUTABLE_ETAG","isValidEtag","value","test","parseClientEtags","serialized","parsed","JSON","parse","Array","isArray","etags","key","Object","entries","serializeClientEtags","stringify"],"mappings":"AAAA,OAAO,MAAMA,iBAAiB,SAAS;AACvC,OAAO,MAAMC,eAAe,eAAe;AAE3C,+EAA+E;AAC/E,OAAO,MAAMC,iBAAiB,EAAE;AAKhC,4EAA4E;AAC5E,OAAO,MAAMC,cAAc,CAACC,QAC1BA,UAAUF,kBACT,OAAOE,UAAU,YAChBA,UAAU,MACV,0BAA0BC,IAAI,CAACD,OAAQ;AAE3C,OAAO,MAAME,mBAAmB,CAACC;IAC/B,IAAI,CAACA,YAAY;QACf,OAAO,CAAC;IACV;IACA,IAAIC;IACJ,IAAI;QACFA,SAASC,KAAKC,KAAK,CAACH;IACtB,EAAE,OAAM;QACN,OAAO,CAAC;IACV;IACA,IAAI,OAAOC,WAAW,YAAYA,WAAW,QAAQG,MAAMC,OAAO,CAACJ,SAAS;QAC1E,OAAO,CAAC;IACV;IACA,MAAMK,QAAe,CAAC;IACtB,KAAK,MAAM,CAACC,KAAKV,MAAM,IAAIW,OAAOC,OAAO,CAACR,QAAS;QACjD,IAAIL,YAAYC,QAAQ;YACtBS,KAAK,CAACC,IAAI,GAAGV;QACf;IACF;IACA,OAAOS;AACT,EAAE;AAEF,OAAO,MAAMI,uBAAuB,CAACJ,QACnCJ,KAAKS,SAAS,CAACL,OAAO"}
|
package/dist/lib/utils/path.d.ts
CHANGED
|
@@ -4,46 +4,5 @@ export declare const filePathToFileURL: (filePath: string) => string;
|
|
|
4
4
|
export declare const fileURLToFilePath: (fileURL: string) => string;
|
|
5
5
|
export declare const joinPath: (...paths: string[]) => string;
|
|
6
6
|
export declare const extname: (filePath: string) => string;
|
|
7
|
-
export type PathSpecItem = {
|
|
8
|
-
type: 'literal';
|
|
9
|
-
name: string;
|
|
10
|
-
} | {
|
|
11
|
-
type: 'group';
|
|
12
|
-
name?: string;
|
|
13
|
-
prefix?: string;
|
|
14
|
-
suffix?: string;
|
|
15
|
-
} | {
|
|
16
|
-
type: 'wildcard';
|
|
17
|
-
name?: string;
|
|
18
|
-
};
|
|
19
|
-
export type PathSpec = readonly PathSpecItem[];
|
|
20
|
-
export declare const parsePathWithSlug: (path: string) => PathSpec;
|
|
21
|
-
export declare const parseExactPath: (path: string) => PathSpec;
|
|
22
|
-
/**
|
|
23
|
-
* Transform a path spec to a regular expression.
|
|
24
|
-
*/
|
|
25
|
-
export declare const path2regexp: (path: PathSpec) => string;
|
|
26
|
-
/** Convert a path spec to a string for the path */
|
|
27
|
-
export declare const pathSpecAsString: (path: PathSpec) => string;
|
|
28
|
-
/**
|
|
29
|
-
* Helper function to get the path mapping from the path spec and the pathname.
|
|
30
|
-
*
|
|
31
|
-
* @param pathSpec
|
|
32
|
-
* @param pathname - route as a string
|
|
33
|
-
* @example
|
|
34
|
-
* getPathMapping(
|
|
35
|
-
* [
|
|
36
|
-
* { type: 'literal', name: 'foo' },
|
|
37
|
-
* { type: 'group', name: 'a' },
|
|
38
|
-
* ],
|
|
39
|
-
* '/foo/bar',
|
|
40
|
-
* );
|
|
41
|
-
* // => { a: 'bar' }
|
|
42
|
-
*/
|
|
43
|
-
export declare const getPathMapping: (pathSpec: PathSpec, pathname: string) => Record<string, string | string[]> | null;
|
|
44
7
|
export declare function removeBase(url: string, base: string): string;
|
|
45
8
|
export declare function addBase(url: string, base: string): string;
|
|
46
|
-
export declare function countSlugsAndWildcards(pathSpec: PathSpec): {
|
|
47
|
-
numSlugs: number;
|
|
48
|
-
numWildcards: number;
|
|
49
|
-
};
|
package/dist/lib/utils/path.js
CHANGED
|
@@ -59,168 +59,6 @@ export const extname = (filePath)=>{
|
|
|
59
59
|
}
|
|
60
60
|
return filePath.slice(index);
|
|
61
61
|
};
|
|
62
|
-
const SLUG_PATTERN = /^(.*?)\[([^\]]+)\](.*)$/;
|
|
63
|
-
export const parsePathWithSlug = (path)=>path.split('/').filter(Boolean).map((name)=>{
|
|
64
|
-
const match = SLUG_PATTERN.exec(name);
|
|
65
|
-
if (!match) {
|
|
66
|
-
return {
|
|
67
|
-
type: 'literal',
|
|
68
|
-
name
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
const [, prefix, inner, suffix] = match;
|
|
72
|
-
if (inner.startsWith('...')) {
|
|
73
|
-
return {
|
|
74
|
-
type: 'wildcard',
|
|
75
|
-
name: inner.slice(3)
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
type: 'group',
|
|
80
|
-
name: inner,
|
|
81
|
-
...prefix ? {
|
|
82
|
-
prefix
|
|
83
|
-
} : {},
|
|
84
|
-
...suffix ? {
|
|
85
|
-
suffix
|
|
86
|
-
} : {}
|
|
87
|
-
};
|
|
88
|
-
});
|
|
89
|
-
export const parseExactPath = (path)=>path.split('/').filter(Boolean).map((name)=>({
|
|
90
|
-
type: 'literal',
|
|
91
|
-
name
|
|
92
|
-
}));
|
|
93
|
-
const escapeRegExp = (s)=>s.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
|
|
94
|
-
/**
|
|
95
|
-
* Transform a path spec to a regular expression.
|
|
96
|
-
*/ export const path2regexp = (path)=>{
|
|
97
|
-
const parts = path.map((item)=>{
|
|
98
|
-
if (item.type === 'literal') {
|
|
99
|
-
return escapeRegExp(item.name);
|
|
100
|
-
} else if (item.type === 'group') {
|
|
101
|
-
const prefix = escapeRegExp(item.prefix ?? '');
|
|
102
|
-
const suffix = escapeRegExp(item.suffix ?? '');
|
|
103
|
-
return `${prefix}([^/]+)${suffix}`;
|
|
104
|
-
} else {
|
|
105
|
-
return `(.*)`;
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
return `^/${parts.join('/')}$`;
|
|
109
|
-
};
|
|
110
|
-
/** Convert a path spec to a string for the path */ export const pathSpecAsString = (path)=>{
|
|
111
|
-
return '/' + path.map((item)=>{
|
|
112
|
-
if (item.type === 'literal') {
|
|
113
|
-
return item.name;
|
|
114
|
-
} else if (item.type === 'group') {
|
|
115
|
-
const prefix = item.prefix ?? '';
|
|
116
|
-
const suffix = item.suffix ?? '';
|
|
117
|
-
return `${prefix}[${item.name}]${suffix}`;
|
|
118
|
-
} else {
|
|
119
|
-
return `[...${item.name}]`;
|
|
120
|
-
}
|
|
121
|
-
}).join('/');
|
|
122
|
-
};
|
|
123
|
-
const matchSpecSegment = (spec, segment, mapping)=>{
|
|
124
|
-
if (spec.type === 'literal') {
|
|
125
|
-
return spec.name === segment;
|
|
126
|
-
}
|
|
127
|
-
if (segment === undefined) {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
const prefix = spec.prefix ?? '';
|
|
131
|
-
const suffix = spec.suffix ?? '';
|
|
132
|
-
if (prefix || suffix) {
|
|
133
|
-
if (!segment.startsWith(prefix) || !segment.endsWith(suffix)) {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
const value = segment.slice(prefix.length, suffix ? -suffix.length : undefined);
|
|
137
|
-
if (!value) {
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
if (spec.name) {
|
|
141
|
-
mapping[spec.name] = value;
|
|
142
|
-
}
|
|
143
|
-
} else if (spec.name) {
|
|
144
|
-
mapping[spec.name] = segment;
|
|
145
|
-
}
|
|
146
|
-
return true;
|
|
147
|
-
};
|
|
148
|
-
/**
|
|
149
|
-
* Helper function to get the path mapping from the path spec and the pathname.
|
|
150
|
-
*
|
|
151
|
-
* @param pathSpec
|
|
152
|
-
* @param pathname - route as a string
|
|
153
|
-
* @example
|
|
154
|
-
* getPathMapping(
|
|
155
|
-
* [
|
|
156
|
-
* { type: 'literal', name: 'foo' },
|
|
157
|
-
* { type: 'group', name: 'a' },
|
|
158
|
-
* ],
|
|
159
|
-
* '/foo/bar',
|
|
160
|
-
* );
|
|
161
|
-
* // => { a: 'bar' }
|
|
162
|
-
*/ export const getPathMapping = (pathSpec, pathname)=>{
|
|
163
|
-
const actual = pathname.split('/').filter(Boolean);
|
|
164
|
-
if (pathSpec.length > actual.length) {
|
|
165
|
-
const wildcardIndex = pathSpec.findIndex((spec)=>spec.type === 'wildcard');
|
|
166
|
-
if (wildcardIndex === -1) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
const isTerminalWildcard = wildcardIndex === pathSpec.length - 1;
|
|
170
|
-
if (isTerminalWildcard) {
|
|
171
|
-
// Terminal wildcards only pass through with zero actual segments
|
|
172
|
-
// (handled by the root-wildcard special case below)
|
|
173
|
-
if (actual.length > 0) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
} else if (actual.length < pathSpec.length - 1) {
|
|
177
|
-
// Non-terminal wildcards can match zero segments; just need enough
|
|
178
|
-
// actual segments for every non-wildcard spec in the pathSpec
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
const mapping = {};
|
|
183
|
-
let wildcardStartIndex = -1;
|
|
184
|
-
for(let i = 0; i < pathSpec.length; i++){
|
|
185
|
-
const spec = pathSpec[i];
|
|
186
|
-
if (spec.type === 'wildcard') {
|
|
187
|
-
wildcardStartIndex = i;
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
if (!matchSpecSegment(spec, actual[i], mapping)) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (wildcardStartIndex === -1) {
|
|
195
|
-
if (pathSpec.length !== actual.length) {
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
return mapping;
|
|
199
|
-
}
|
|
200
|
-
if (wildcardStartIndex === 0 && actual.length === 0) {
|
|
201
|
-
const wildcardName = pathSpec[wildcardStartIndex].name;
|
|
202
|
-
if (wildcardName) {
|
|
203
|
-
mapping[wildcardName] = [];
|
|
204
|
-
}
|
|
205
|
-
return mapping;
|
|
206
|
-
}
|
|
207
|
-
let wildcardEndIndex = -1;
|
|
208
|
-
for(let i = 0; i < pathSpec.length; i++){
|
|
209
|
-
const spec = pathSpec[pathSpec.length - i - 1];
|
|
210
|
-
if (spec.type === 'wildcard') {
|
|
211
|
-
wildcardEndIndex = actual.length - i - 1;
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
if (!matchSpecSegment(spec, actual[actual.length - i - 1], mapping)) {
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
const wildcardName = pathSpec[wildcardStartIndex].name;
|
|
219
|
-
if (wildcardName) {
|
|
220
|
-
mapping[wildcardName] = actual.slice(wildcardStartIndex, wildcardEndIndex + 1);
|
|
221
|
-
}
|
|
222
|
-
return mapping;
|
|
223
|
-
};
|
|
224
62
|
// basePath config is ensured to have trailing slash (see plugin)
|
|
225
63
|
export function removeBase(url, base) {
|
|
226
64
|
if (base !== '/') {
|
|
@@ -237,21 +75,5 @@ export function addBase(url, base) {
|
|
|
237
75
|
}
|
|
238
76
|
return url;
|
|
239
77
|
}
|
|
240
|
-
export function countSlugsAndWildcards(pathSpec) {
|
|
241
|
-
let numSlugs = 0;
|
|
242
|
-
let numWildcards = 0;
|
|
243
|
-
for (const slug of pathSpec){
|
|
244
|
-
if (slug.type !== 'literal') {
|
|
245
|
-
numSlugs++;
|
|
246
|
-
}
|
|
247
|
-
if (slug.type === 'wildcard') {
|
|
248
|
-
numWildcards++;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return {
|
|
252
|
-
numSlugs,
|
|
253
|
-
numWildcards
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
78
|
|
|
257
79
|
//# sourceMappingURL=path.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/utils/path.ts"],"sourcesContent":["// Terminology:\n// - filePath: posix-like file path, e.g. `/foo/bar.js` or `c:/foo/bar.js`\n// This is used by Vite.\n// - fileURL: file URL, e.g. `file:///foo/bar.js` or `file:///c:/foo/bar.js`\n// This is used by import().\n// - osPath: os dependent path, e.g. `/foo/bar.js` or `c:\\foo\\bar.js`\n// This is used by node:fs.\n\nconst ABSOLUTE_WIN32_PATH_REGEXP = /^\\/[a-zA-Z]:\\//;\n\nexport const encodeFilePathToAbsolute = (filePath: string) => {\n if (ABSOLUTE_WIN32_PATH_REGEXP.test(filePath)) {\n throw new Error('Unsupported absolute file path: ' + filePath);\n }\n if (filePath.startsWith('/')) {\n return filePath;\n }\n return '/' + filePath;\n};\n\nexport const decodeFilePathFromAbsolute = (filePath: string) => {\n if (ABSOLUTE_WIN32_PATH_REGEXP.test(filePath)) {\n return filePath.slice(1);\n }\n return filePath;\n};\n\nexport const filePathToFileURL = (filePath: string) =>\n 'file://' + encodeURI(filePath);\n\nexport const fileURLToFilePath = (fileURL: string) => {\n if (!fileURL.startsWith('file://')) {\n throw new Error('Not a file URL');\n }\n return decodeURI(fileURL.slice('file://'.length));\n};\n\n// for filePath\nexport const joinPath = (...paths: string[]) => {\n const isAbsolute = paths[0]?.startsWith('/');\n const items = ([] as string[]).concat(\n ...paths.map((path) => path.split('/')),\n );\n const stack: string[] = [];\n for (const item of items) {\n if (item === '..') {\n if (stack.length && stack[stack.length - 1] !== '..') {\n stack.pop();\n } else if (!isAbsolute) {\n stack.push('..');\n }\n } else if (item && item !== '.') {\n stack.push(item);\n }\n }\n return (isAbsolute ? '/' : '') + stack.join('/') || '.';\n};\n\nexport const extname = (filePath: string) => {\n const index = filePath.lastIndexOf('.');\n if (index <= 0) {\n return '';\n }\n if (['/', '.'].includes(filePath[index - 1]!)) {\n return '';\n }\n return filePath.slice(index);\n};\n\nexport type PathSpecItem =\n | { type: 'literal'; name: string }\n | { type: 'group'; name?: string; prefix?: string; suffix?: string }\n | { type: 'wildcard'; name?: string };\nexport type PathSpec = readonly PathSpecItem[];\n\nconst SLUG_PATTERN = /^(.*?)\\[([^\\]]+)\\](.*)$/;\n\nexport const parsePathWithSlug = (path: string): PathSpec =>\n path\n .split('/')\n .filter(Boolean)\n .map((name) => {\n const match = SLUG_PATTERN.exec(name);\n if (!match) {\n return { type: 'literal' as const, name };\n }\n const [, prefix, inner, suffix] = match;\n if (inner!.startsWith('...')) {\n return {\n type: 'wildcard' as const,\n name: inner!.slice(3),\n };\n }\n return {\n type: 'group' as const,\n name: inner!,\n ...(prefix ? { prefix } : {}),\n ...(suffix ? { suffix } : {}),\n };\n });\n\nexport const parseExactPath = (path: string): PathSpec =>\n path\n .split('/')\n .filter(Boolean)\n .map((name) => ({ type: 'literal', name }));\n\nconst escapeRegExp = (s: string) => s.replace(/[\\\\^$.*+?()[\\]{}|]/g, '\\\\$&');\n\n/**\n * Transform a path spec to a regular expression.\n */\nexport const path2regexp = (path: PathSpec) => {\n const parts = path.map((item) => {\n if (item.type === 'literal') {\n return escapeRegExp(item.name);\n } else if (item.type === 'group') {\n const prefix = escapeRegExp(item.prefix ?? '');\n const suffix = escapeRegExp(item.suffix ?? '');\n return `${prefix}([^/]+)${suffix}`;\n } else {\n return `(.*)`;\n }\n });\n return `^/${parts.join('/')}$`;\n};\n\n/** Convert a path spec to a string for the path */\nexport const pathSpecAsString = (path: PathSpec) => {\n return (\n '/' +\n path\n .map((item) => {\n if (item.type === 'literal') {\n return item.name;\n } else if (item.type === 'group') {\n const prefix = item.prefix ?? '';\n const suffix = item.suffix ?? '';\n return `${prefix}[${item.name}]${suffix}`;\n } else {\n return `[...${item.name}]`;\n }\n })\n .join('/')\n );\n};\n\nconst matchSpecSegment = (\n spec: Exclude<PathSpecItem, { type: 'wildcard' }>,\n segment: string | undefined,\n mapping: Record<string, string | string[]>,\n): boolean => {\n if (spec.type === 'literal') {\n return spec.name === segment;\n }\n if (segment === undefined) {\n return false;\n }\n const prefix = spec.prefix ?? '';\n const suffix = spec.suffix ?? '';\n if (prefix || suffix) {\n if (!segment.startsWith(prefix) || !segment.endsWith(suffix)) {\n return false;\n }\n const value = segment.slice(\n prefix.length,\n suffix ? -suffix.length : undefined,\n );\n if (!value) {\n return false;\n }\n if (spec.name) {\n mapping[spec.name] = value;\n }\n } else if (spec.name) {\n mapping[spec.name] = segment;\n }\n return true;\n};\n\n/**\n * Helper function to get the path mapping from the path spec and the pathname.\n *\n * @param pathSpec\n * @param pathname - route as a string\n * @example\n * getPathMapping(\n * [\n * { type: 'literal', name: 'foo' },\n * { type: 'group', name: 'a' },\n * ],\n * '/foo/bar',\n * );\n * // => { a: 'bar' }\n */\nexport const getPathMapping = (\n pathSpec: PathSpec,\n pathname: string,\n): Record<string, string | string[]> | null => {\n const actual = pathname.split('/').filter(Boolean);\n if (pathSpec.length > actual.length) {\n const wildcardIndex = pathSpec.findIndex(\n (spec) => spec.type === 'wildcard',\n );\n if (wildcardIndex === -1) {\n return null;\n }\n const isTerminalWildcard = wildcardIndex === pathSpec.length - 1;\n if (isTerminalWildcard) {\n // Terminal wildcards only pass through with zero actual segments\n // (handled by the root-wildcard special case below)\n if (actual.length > 0) {\n return null;\n }\n } else if (actual.length < pathSpec.length - 1) {\n // Non-terminal wildcards can match zero segments; just need enough\n // actual segments for every non-wildcard spec in the pathSpec\n return null;\n }\n }\n const mapping: Record<string, string | string[]> = {};\n let wildcardStartIndex = -1;\n for (let i = 0; i < pathSpec.length; i++) {\n const spec = pathSpec[i]!;\n if (spec.type === 'wildcard') {\n wildcardStartIndex = i;\n break;\n }\n if (!matchSpecSegment(spec, actual[i], mapping)) {\n return null;\n }\n }\n if (wildcardStartIndex === -1) {\n if (pathSpec.length !== actual.length) {\n return null;\n }\n return mapping;\n }\n\n if (wildcardStartIndex === 0 && actual.length === 0) {\n const wildcardName = pathSpec[wildcardStartIndex]!.name;\n if (wildcardName) {\n mapping[wildcardName] = [];\n }\n return mapping;\n }\n\n let wildcardEndIndex = -1;\n for (let i = 0; i < pathSpec.length; i++) {\n const spec = pathSpec[pathSpec.length - i - 1]!;\n if (spec.type === 'wildcard') {\n wildcardEndIndex = actual.length - i - 1;\n break;\n }\n if (!matchSpecSegment(spec, actual[actual.length - i - 1], mapping)) {\n return null;\n }\n }\n const wildcardName = pathSpec[wildcardStartIndex]!.name;\n if (wildcardName) {\n mapping[wildcardName] = actual.slice(\n wildcardStartIndex,\n wildcardEndIndex + 1,\n );\n }\n return mapping;\n};\n\n// basePath config is ensured to have trailing slash (see plugin)\nexport function removeBase(url: string, base: string) {\n if (base !== '/') {\n if (!url.startsWith(base)) {\n throw new Error('pathname must start with basePath: ' + url);\n }\n return url.slice(base.length - 1);\n }\n return url;\n}\n\nexport function addBase(url: string, base: string) {\n if (base !== '/' && url.startsWith('/')) {\n return base.slice(0, -1) + url;\n }\n return url;\n}\n\nexport function countSlugsAndWildcards(pathSpec: PathSpec) {\n let numSlugs = 0;\n let numWildcards = 0;\n for (const slug of pathSpec) {\n if (slug.type !== 'literal') {\n numSlugs++;\n }\n if (slug.type === 'wildcard') {\n numWildcards++;\n }\n }\n return { numSlugs, numWildcards };\n}\n"],"names":["ABSOLUTE_WIN32_PATH_REGEXP","encodeFilePathToAbsolute","filePath","test","Error","startsWith","decodeFilePathFromAbsolute","slice","filePathToFileURL","encodeURI","fileURLToFilePath","fileURL","decodeURI","length","joinPath","paths","isAbsolute","items","concat","map","path","split","stack","item","pop","push","join","extname","index","lastIndexOf","includes","SLUG_PATTERN","parsePathWithSlug","filter","Boolean","name","match","exec","type","prefix","inner","suffix","parseExactPath","escapeRegExp","s","replace","path2regexp","parts","pathSpecAsString","matchSpecSegment","spec","segment","mapping","undefined","endsWith","value","getPathMapping","pathSpec","pathname","actual","wildcardIndex","findIndex","isTerminalWildcard","wildcardStartIndex","i","wildcardName","wildcardEndIndex","removeBase","url","base","addBase","countSlugsAndWildcards","numSlugs","numWildcards","slug"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils/path.ts"],"sourcesContent":["// Terminology:\n// - filePath: posix-like file path, e.g. `/foo/bar.js` or `c:/foo/bar.js`\n// This is used by Vite.\n// - fileURL: file URL, e.g. `file:///foo/bar.js` or `file:///c:/foo/bar.js`\n// This is used by import().\n// - osPath: os dependent path, e.g. `/foo/bar.js` or `c:\\foo\\bar.js`\n// This is used by node:fs.\n\nconst ABSOLUTE_WIN32_PATH_REGEXP = /^\\/[a-zA-Z]:\\//;\n\nexport const encodeFilePathToAbsolute = (filePath: string) => {\n if (ABSOLUTE_WIN32_PATH_REGEXP.test(filePath)) {\n throw new Error('Unsupported absolute file path: ' + filePath);\n }\n if (filePath.startsWith('/')) {\n return filePath;\n }\n return '/' + filePath;\n};\n\nexport const decodeFilePathFromAbsolute = (filePath: string) => {\n if (ABSOLUTE_WIN32_PATH_REGEXP.test(filePath)) {\n return filePath.slice(1);\n }\n return filePath;\n};\n\nexport const filePathToFileURL = (filePath: string) =>\n 'file://' + encodeURI(filePath);\n\nexport const fileURLToFilePath = (fileURL: string) => {\n if (!fileURL.startsWith('file://')) {\n throw new Error('Not a file URL');\n }\n return decodeURI(fileURL.slice('file://'.length));\n};\n\n// for filePath\nexport const joinPath = (...paths: string[]) => {\n const isAbsolute = paths[0]?.startsWith('/');\n const items = ([] as string[]).concat(\n ...paths.map((path) => path.split('/')),\n );\n const stack: string[] = [];\n for (const item of items) {\n if (item === '..') {\n if (stack.length && stack[stack.length - 1] !== '..') {\n stack.pop();\n } else if (!isAbsolute) {\n stack.push('..');\n }\n } else if (item && item !== '.') {\n stack.push(item);\n }\n }\n return (isAbsolute ? '/' : '') + stack.join('/') || '.';\n};\n\nexport const extname = (filePath: string) => {\n const index = filePath.lastIndexOf('.');\n if (index <= 0) {\n return '';\n }\n if (['/', '.'].includes(filePath[index - 1]!)) {\n return '';\n }\n return filePath.slice(index);\n};\n\n// basePath config is ensured to have trailing slash (see plugin)\nexport function removeBase(url: string, base: string) {\n if (base !== '/') {\n if (!url.startsWith(base)) {\n throw new Error('pathname must start with basePath: ' + url);\n }\n return url.slice(base.length - 1);\n }\n return url;\n}\n\nexport function addBase(url: string, base: string) {\n if (base !== '/' && url.startsWith('/')) {\n return base.slice(0, -1) + url;\n }\n return url;\n}\n"],"names":["ABSOLUTE_WIN32_PATH_REGEXP","encodeFilePathToAbsolute","filePath","test","Error","startsWith","decodeFilePathFromAbsolute","slice","filePathToFileURL","encodeURI","fileURLToFilePath","fileURL","decodeURI","length","joinPath","paths","isAbsolute","items","concat","map","path","split","stack","item","pop","push","join","extname","index","lastIndexOf","includes","removeBase","url","base","addBase"],"mappings":"AAAA,eAAe;AACf,0EAA0E;AAC1E,0BAA0B;AAC1B,4EAA4E;AAC5E,8BAA8B;AAC9B,qEAAqE;AACrE,6BAA6B;AAE7B,MAAMA,6BAA6B;AAEnC,OAAO,MAAMC,2BAA2B,CAACC;IACvC,IAAIF,2BAA2BG,IAAI,CAACD,WAAW;QAC7C,MAAM,IAAIE,MAAM,qCAAqCF;IACvD;IACA,IAAIA,SAASG,UAAU,CAAC,MAAM;QAC5B,OAAOH;IACT;IACA,OAAO,MAAMA;AACf,EAAE;AAEF,OAAO,MAAMI,6BAA6B,CAACJ;IACzC,IAAIF,2BAA2BG,IAAI,CAACD,WAAW;QAC7C,OAAOA,SAASK,KAAK,CAAC;IACxB;IACA,OAAOL;AACT,EAAE;AAEF,OAAO,MAAMM,oBAAoB,CAACN,WAChC,YAAYO,UAAUP,UAAU;AAElC,OAAO,MAAMQ,oBAAoB,CAACC;IAChC,IAAI,CAACA,QAAQN,UAAU,CAAC,YAAY;QAClC,MAAM,IAAID,MAAM;IAClB;IACA,OAAOQ,UAAUD,QAAQJ,KAAK,CAAC,UAAUM,MAAM;AACjD,EAAE;AAEF,eAAe;AACf,OAAO,MAAMC,WAAW,CAAC,GAAGC;IAC1B,MAAMC,aAAaD,KAAK,CAAC,EAAE,EAAEV,WAAW;IACxC,MAAMY,QAAQ,AAAC,EAAE,CAAcC,MAAM,IAChCH,MAAMI,GAAG,CAAC,CAACC,OAASA,KAAKC,KAAK,CAAC;IAEpC,MAAMC,QAAkB,EAAE;IAC1B,KAAK,MAAMC,QAAQN,MAAO;QACxB,IAAIM,SAAS,MAAM;YACjB,IAAID,MAAMT,MAAM,IAAIS,KAAK,CAACA,MAAMT,MAAM,GAAG,EAAE,KAAK,MAAM;gBACpDS,MAAME,GAAG;YACX,OAAO,IAAI,CAACR,YAAY;gBACtBM,MAAMG,IAAI,CAAC;YACb;QACF,OAAO,IAAIF,QAAQA,SAAS,KAAK;YAC/BD,MAAMG,IAAI,CAACF;QACb;IACF;IACA,OAAO,AAACP,CAAAA,aAAa,MAAM,EAAC,IAAKM,MAAMI,IAAI,CAAC,QAAQ;AACtD,EAAE;AAEF,OAAO,MAAMC,UAAU,CAACzB;IACtB,MAAM0B,QAAQ1B,SAAS2B,WAAW,CAAC;IACnC,IAAID,SAAS,GAAG;QACd,OAAO;IACT;IACA,IAAI;QAAC;QAAK;KAAI,CAACE,QAAQ,CAAC5B,QAAQ,CAAC0B,QAAQ,EAAE,GAAI;QAC7C,OAAO;IACT;IACA,OAAO1B,SAASK,KAAK,CAACqB;AACxB,EAAE;AAEF,iEAAiE;AACjE,OAAO,SAASG,WAAWC,GAAW,EAAEC,IAAY;IAClD,IAAIA,SAAS,KAAK;QAChB,IAAI,CAACD,IAAI3B,UAAU,CAAC4B,OAAO;YACzB,MAAM,IAAI7B,MAAM,wCAAwC4B;QAC1D;QACA,OAAOA,IAAIzB,KAAK,CAAC0B,KAAKpB,MAAM,GAAG;IACjC;IACA,OAAOmB;AACT;AAEA,OAAO,SAASE,QAAQF,GAAW,EAAEC,IAAY;IAC/C,IAAIA,SAAS,OAAOD,IAAI3B,UAAU,CAAC,MAAM;QACvC,OAAO4B,KAAK1B,KAAK,CAAC,GAAG,CAAC,KAAKyB;IAC7B;IACA,OAAOA;AACT"}
|
package/dist/lib/utils/render.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ETAG_ID_PREFIX } from './etags.js';
|
|
1
2
|
import { sanitizeLog } from './log.js';
|
|
2
3
|
const validateRscElementIds = (elements)=>{
|
|
3
4
|
for (const id of Object.keys(elements)){
|
|
@@ -25,6 +26,11 @@ export function createRenderUtils(temporaryReferences, renderToReadableStream, c
|
|
|
25
26
|
if (options && 'value' in options) {
|
|
26
27
|
data._value = options.value;
|
|
27
28
|
}
|
|
29
|
+
if (options?.etags) {
|
|
30
|
+
for (const [slotId, etag] of Object.entries(options.etags)){
|
|
31
|
+
data[ETAG_ID_PREFIX + slotId] = etag;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
28
34
|
return renderToReadableStream(data, {
|
|
29
35
|
temporaryReferences,
|
|
30
36
|
onError,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/utils/render.ts"],"sourcesContent":["import type {\n Unstable_ParseRsc,\n Unstable_RenderHtml,\n Unstable_RenderRsc,\n} from '../types.js';\nimport { sanitizeLog } from './log.js';\n\nconst validateRscElementIds = (elements: Record<string, unknown>) => {\n for (const id of Object.keys(elements)) {\n if (id.startsWith('_')) {\n throw new Error(\n `RSC element IDs starting with \"_\" are reserved for Waku internals: ${id}`,\n );\n }\n }\n};\n\nexport function createRenderUtils(\n temporaryReferences: unknown,\n renderToReadableStream: (\n data: unknown,\n options?: object,\n extraOptions?: object,\n ) => ReadableStream,\n createFromReadableStream: (\n stream: ReadableStream,\n options?: object,\n ) => Promise<unknown>,\n loadSsrEntryModule: () => Promise<\n typeof import('../vite-entries/entry.ssr.js')\n >,\n buildId: string,\n debugChannel?: { readable?: ReadableStream; writable?: WritableStream },\n debugId?: string,\n): {\n renderRsc: Unstable_RenderRsc;\n parseRsc: Unstable_ParseRsc;\n renderHtml: Unstable_RenderHtml;\n} {\n const onError = (e: unknown) => {\n if (\n e &&\n typeof e === 'object' &&\n 'digest' in e &&\n typeof e.digest === 'string'\n ) {\n return e.digest;\n }\n console.error('Error during rendering:', sanitizeLog(e));\n };\n\n return {\n async renderRsc(elements, options) {\n validateRscElementIds(elements);\n const data: Record<string, unknown> = buildId\n ? { ...elements, _buildId: buildId }\n : { ...elements };\n if (options && 'value' in options) {\n data._value = options.value;\n }\n return renderToReadableStream(\n data,\n {\n temporaryReferences,\n onError,\n debugChannel,\n },\n {\n onClientReference(metadata: {\n id: string;\n name: string;\n deps: { js: string[]; css: string[] };\n }) {\n options?.unstable_clientModuleCallback?.(metadata.deps.js);\n },\n },\n );\n },\n async parseRsc(stream) {\n return createFromReadableStream(stream, {}) as Promise<\n Record<string, unknown>\n >;\n },\n async renderHtml(elementsStream, html, options) {\n const { INTERNAL_renderHtmlStream: renderHtmlStream } =\n await loadSsrEntryModule();\n\n const rscHtmlStream = renderToReadableStream(html, {\n onError,\n });\n const htmlResult = await renderHtmlStream(elementsStream, rscHtmlStream, {\n rscPath: options.rscPath,\n formState: options.formState as never,\n nonce: options.nonce,\n extraScriptContent: options.unstable_extraScriptContent,\n debugId,\n });\n return new Response(htmlResult.stream, {\n status: htmlResult.status || options.status || 200,\n headers: { 'content-type': 'text/html; charset=utf-8' },\n });\n },\n };\n}\n"],"names":["sanitizeLog","validateRscElementIds","elements","id","Object","keys","startsWith","Error","createRenderUtils","temporaryReferences","renderToReadableStream","createFromReadableStream","loadSsrEntryModule","buildId","debugChannel","debugId","onError","e","digest","console","error","renderRsc","options","data","_buildId","_value","value","onClientReference","metadata","unstable_clientModuleCallback","deps","js","parseRsc","stream","renderHtml","elementsStream","html","INTERNAL_renderHtmlStream","renderHtmlStream","rscHtmlStream","htmlResult","rscPath","formState","nonce","extraScriptContent","unstable_extraScriptContent","Response","status","headers"],"mappings":"AAKA,SAASA,WAAW,QAAQ,WAAW;AAEvC,MAAMC,wBAAwB,CAACC;IAC7B,KAAK,MAAMC,MAAMC,OAAOC,IAAI,CAACH,UAAW;QACtC,IAAIC,GAAGG,UAAU,CAAC,MAAM;YACtB,MAAM,IAAIC,MACR,CAAC,mEAAmE,EAAEJ,IAAI;QAE9E;IACF;AACF;AAEA,OAAO,SAASK,kBACdC,mBAA4B,EAC5BC,sBAImB,EACnBC,wBAGqB,EACrBC,kBAEC,EACDC,OAAe,EACfC,YAAuE,EACvEC,OAAgB;IAMhB,MAAMC,UAAU,CAACC;QACf,IACEA,KACA,OAAOA,MAAM,YACb,YAAYA,KACZ,OAAOA,EAAEC,MAAM,KAAK,UACpB;YACA,OAAOD,EAAEC,MAAM;QACjB;QACAC,QAAQC,KAAK,CAAC,2BAA2BpB,YAAYiB;IACvD;IAEA,OAAO;QACL,MAAMI,WAAUnB,QAAQ,EAAEoB,OAAO;YAC/BrB,sBAAsBC;YACtB,MAAMqB,OAAgCV,UAClC;gBAAE,GAAGX,QAAQ;gBAAEsB,UAAUX;YAAQ,IACjC;gBAAE,GAAGX,QAAQ;YAAC;YAClB,IAAIoB,WAAW,WAAWA,SAAS;gBACjCC,KAAKE,MAAM,GAAGH,QAAQI,KAAK;YAC7B;YACA,
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils/render.ts"],"sourcesContent":["import type {\n Unstable_ParseRsc,\n Unstable_RenderHtml,\n Unstable_RenderRsc,\n} from '../types.js';\nimport { ETAG_ID_PREFIX } from './etags.js';\nimport { sanitizeLog } from './log.js';\n\nconst validateRscElementIds = (elements: Record<string, unknown>) => {\n for (const id of Object.keys(elements)) {\n if (id.startsWith('_')) {\n throw new Error(\n `RSC element IDs starting with \"_\" are reserved for Waku internals: ${id}`,\n );\n }\n }\n};\n\nexport function createRenderUtils(\n temporaryReferences: unknown,\n renderToReadableStream: (\n data: unknown,\n options?: object,\n extraOptions?: object,\n ) => ReadableStream,\n createFromReadableStream: (\n stream: ReadableStream,\n options?: object,\n ) => Promise<unknown>,\n loadSsrEntryModule: () => Promise<\n typeof import('../vite-entries/entry.ssr.js')\n >,\n buildId: string,\n debugChannel?: { readable?: ReadableStream; writable?: WritableStream },\n debugId?: string,\n): {\n renderRsc: Unstable_RenderRsc;\n parseRsc: Unstable_ParseRsc;\n renderHtml: Unstable_RenderHtml;\n} {\n const onError = (e: unknown) => {\n if (\n e &&\n typeof e === 'object' &&\n 'digest' in e &&\n typeof e.digest === 'string'\n ) {\n return e.digest;\n }\n console.error('Error during rendering:', sanitizeLog(e));\n };\n\n return {\n async renderRsc(elements, options) {\n validateRscElementIds(elements);\n const data: Record<string, unknown> = buildId\n ? { ...elements, _buildId: buildId }\n : { ...elements };\n if (options && 'value' in options) {\n data._value = options.value;\n }\n if (options?.etags) {\n for (const [slotId, etag] of Object.entries(options.etags)) {\n data[ETAG_ID_PREFIX + slotId] = etag;\n }\n }\n return renderToReadableStream(\n data,\n {\n temporaryReferences,\n onError,\n debugChannel,\n },\n {\n onClientReference(metadata: {\n id: string;\n name: string;\n deps: { js: string[]; css: string[] };\n }) {\n options?.unstable_clientModuleCallback?.(metadata.deps.js);\n },\n },\n );\n },\n async parseRsc(stream) {\n return createFromReadableStream(stream, {}) as Promise<\n Record<string, unknown>\n >;\n },\n async renderHtml(elementsStream, html, options) {\n const { INTERNAL_renderHtmlStream: renderHtmlStream } =\n await loadSsrEntryModule();\n\n const rscHtmlStream = renderToReadableStream(html, {\n onError,\n });\n const htmlResult = await renderHtmlStream(elementsStream, rscHtmlStream, {\n rscPath: options.rscPath,\n formState: options.formState as never,\n nonce: options.nonce,\n extraScriptContent: options.unstable_extraScriptContent,\n debugId,\n });\n return new Response(htmlResult.stream, {\n status: htmlResult.status || options.status || 200,\n headers: { 'content-type': 'text/html; charset=utf-8' },\n });\n },\n };\n}\n"],"names":["ETAG_ID_PREFIX","sanitizeLog","validateRscElementIds","elements","id","Object","keys","startsWith","Error","createRenderUtils","temporaryReferences","renderToReadableStream","createFromReadableStream","loadSsrEntryModule","buildId","debugChannel","debugId","onError","e","digest","console","error","renderRsc","options","data","_buildId","_value","value","etags","slotId","etag","entries","onClientReference","metadata","unstable_clientModuleCallback","deps","js","parseRsc","stream","renderHtml","elementsStream","html","INTERNAL_renderHtmlStream","renderHtmlStream","rscHtmlStream","htmlResult","rscPath","formState","nonce","extraScriptContent","unstable_extraScriptContent","Response","status","headers"],"mappings":"AAKA,SAASA,cAAc,QAAQ,aAAa;AAC5C,SAASC,WAAW,QAAQ,WAAW;AAEvC,MAAMC,wBAAwB,CAACC;IAC7B,KAAK,MAAMC,MAAMC,OAAOC,IAAI,CAACH,UAAW;QACtC,IAAIC,GAAGG,UAAU,CAAC,MAAM;YACtB,MAAM,IAAIC,MACR,CAAC,mEAAmE,EAAEJ,IAAI;QAE9E;IACF;AACF;AAEA,OAAO,SAASK,kBACdC,mBAA4B,EAC5BC,sBAImB,EACnBC,wBAGqB,EACrBC,kBAEC,EACDC,OAAe,EACfC,YAAuE,EACvEC,OAAgB;IAMhB,MAAMC,UAAU,CAACC;QACf,IACEA,KACA,OAAOA,MAAM,YACb,YAAYA,KACZ,OAAOA,EAAEC,MAAM,KAAK,UACpB;YACA,OAAOD,EAAEC,MAAM;QACjB;QACAC,QAAQC,KAAK,CAAC,2BAA2BpB,YAAYiB;IACvD;IAEA,OAAO;QACL,MAAMI,WAAUnB,QAAQ,EAAEoB,OAAO;YAC/BrB,sBAAsBC;YACtB,MAAMqB,OAAgCV,UAClC;gBAAE,GAAGX,QAAQ;gBAAEsB,UAAUX;YAAQ,IACjC;gBAAE,GAAGX,QAAQ;YAAC;YAClB,IAAIoB,WAAW,WAAWA,SAAS;gBACjCC,KAAKE,MAAM,GAAGH,QAAQI,KAAK;YAC7B;YACA,IAAIJ,SAASK,OAAO;gBAClB,KAAK,MAAM,CAACC,QAAQC,KAAK,IAAIzB,OAAO0B,OAAO,CAACR,QAAQK,KAAK,EAAG;oBAC1DJ,IAAI,CAACxB,iBAAiB6B,OAAO,GAAGC;gBAClC;YACF;YACA,OAAOnB,uBACLa,MACA;gBACEd;gBACAO;gBACAF;YACF,GACA;gBACEiB,mBAAkBC,QAIjB;oBACCV,SAASW,gCAAgCD,SAASE,IAAI,CAACC,EAAE;gBAC3D;YACF;QAEJ;QACA,MAAMC,UAASC,MAAM;YACnB,OAAO1B,yBAAyB0B,QAAQ,CAAC;QAG3C;QACA,MAAMC,YAAWC,cAAc,EAAEC,IAAI,EAAElB,OAAO;YAC5C,MAAM,EAAEmB,2BAA2BC,gBAAgB,EAAE,GACnD,MAAM9B;YAER,MAAM+B,gBAAgBjC,uBAAuB8B,MAAM;gBACjDxB;YACF;YACA,MAAM4B,aAAa,MAAMF,iBAAiBH,gBAAgBI,eAAe;gBACvEE,SAASvB,QAAQuB,OAAO;gBACxBC,WAAWxB,QAAQwB,SAAS;gBAC5BC,OAAOzB,QAAQyB,KAAK;gBACpBC,oBAAoB1B,QAAQ2B,2BAA2B;gBACvDlC;YACF;YACA,OAAO,IAAImC,SAASN,WAAWP,MAAM,EAAE;gBACrCc,QAAQP,WAAWO,MAAM,IAAI7B,QAAQ6B,MAAM,IAAI;gBAC/CC,SAAS;oBAAE,gBAAgB;gBAA2B;YACxD;QACF;IACF;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactFormState } from 'react-dom/client';
|
|
2
2
|
import type { Config } from '../../config.js';
|
|
3
|
-
export declare function getInput(req: Request, config: Omit<Required<Config>, 'vite'>, temporaryReferences: unknown, decodeReply: (body: string | FormData, options?: object) => Promise<unknown[]>, decodeAction: (body: FormData) => Promise<() => Promise<void
|
|
3
|
+
export declare function getInput(req: Request, config: Omit<Required<Config>, 'vite'>, temporaryReferences: unknown, decodeReply: (body: string | FormData, options?: object) => Promise<unknown[]>, decodeAction: (body: FormData) => Promise<() => Promise<void>> | null, decodeFormState: (actionResult: unknown, body: FormData) => Promise<ReactFormState | undefined>, loadServerAction: (id: string) => Promise<unknown>): Promise<({
|
|
4
4
|
type: "component";
|
|
5
5
|
rscPath: string;
|
|
6
6
|
rscParams: unknown;
|
|
@@ -16,4 +16,5 @@ export declare function getInput(req: Request, config: Omit<Required<Config>, 'v
|
|
|
16
16
|
}) & {
|
|
17
17
|
pathname: string;
|
|
18
18
|
req: Request;
|
|
19
|
+
etags?: import("./etags.js").Etags;
|
|
19
20
|
}>;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { decodeFuncId, decodeRscPath } from '../utils/rsc-path.js';
|
|
2
2
|
import { createCustomError } from './custom-errors.js';
|
|
3
|
+
import { ETAGS_HEADER, parseClientEtags } from './etags.js';
|
|
3
4
|
import { removeBase } from './path.js';
|
|
4
5
|
export async function getInput(req, config, temporaryReferences, decodeReply, decodeAction, decodeFormState, loadServerAction) {
|
|
5
6
|
const url = new URL(req.url);
|
|
6
7
|
const pathname = removeBase(url.pathname, config.basePath);
|
|
7
8
|
const rscPathPrefix = '/' + config.rscBase + '/';
|
|
9
|
+
const etags = parseClientEtags(req.headers.get(ETAGS_HEADER));
|
|
8
10
|
let rscPath;
|
|
9
11
|
let input;
|
|
10
12
|
if (pathname.startsWith(rscPathPrefix)) {
|
|
@@ -23,7 +25,8 @@ export async function getInput(req, config, temporaryReferences, decodeReply, de
|
|
|
23
25
|
fn: action,
|
|
24
26
|
args,
|
|
25
27
|
pathname,
|
|
26
|
-
req
|
|
28
|
+
req,
|
|
29
|
+
etags
|
|
27
30
|
};
|
|
28
31
|
} else {
|
|
29
32
|
// client RSC request
|
|
@@ -40,7 +43,8 @@ export async function getInput(req, config, temporaryReferences, decodeReply, de
|
|
|
40
43
|
rscPath,
|
|
41
44
|
rscParams,
|
|
42
45
|
pathname,
|
|
43
|
-
req
|
|
46
|
+
req,
|
|
47
|
+
etags
|
|
44
48
|
};
|
|
45
49
|
}
|
|
46
50
|
} else if (req.method === 'POST') {
|
|
@@ -53,18 +57,26 @@ export async function getInput(req, config, temporaryReferences, decodeReply, de
|
|
|
53
57
|
fn: async ()=>{
|
|
54
58
|
const formData = await getActionBody(req);
|
|
55
59
|
const decodedAction = await decodeAction(formData);
|
|
60
|
+
if (typeof decodedAction !== 'function') {
|
|
61
|
+
// multipart/form-data POST without an action reference (e.g. crawlers)
|
|
62
|
+
throw createCustomError('Bad Request', {
|
|
63
|
+
status: 400
|
|
64
|
+
});
|
|
65
|
+
}
|
|
56
66
|
const result = await decodedAction();
|
|
57
67
|
return await decodeFormState(result, formData);
|
|
58
68
|
},
|
|
59
69
|
pathname,
|
|
60
|
-
req
|
|
70
|
+
req,
|
|
71
|
+
etags
|
|
61
72
|
};
|
|
62
73
|
} else {
|
|
63
74
|
// POST API request
|
|
64
75
|
input = {
|
|
65
76
|
type: 'custom',
|
|
66
77
|
pathname,
|
|
67
|
-
req
|
|
78
|
+
req,
|
|
79
|
+
etags
|
|
68
80
|
};
|
|
69
81
|
}
|
|
70
82
|
} else {
|
|
@@ -72,7 +84,8 @@ export async function getInput(req, config, temporaryReferences, decodeReply, de
|
|
|
72
84
|
input = {
|
|
73
85
|
type: 'custom',
|
|
74
86
|
pathname,
|
|
75
|
-
req
|
|
87
|
+
req,
|
|
88
|
+
etags
|
|
76
89
|
};
|
|
77
90
|
}
|
|
78
91
|
return input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/utils/request.ts"],"sourcesContent":["import type { ReactFormState } from 'react-dom/client';\nimport type { Config } from '../../config.js';\nimport type { Unstable_HandleRequest as HandleRequest } from '../types.js';\nimport { decodeFuncId, decodeRscPath } from '../utils/rsc-path.js';\nimport { createCustomError } from './custom-errors.js';\nimport { removeBase } from './path.js';\n\ntype HandleRequestInput = Parameters<HandleRequest>[0];\n\nexport async function getInput(\n req: Request,\n config: Omit<Required<Config>, 'vite'>,\n temporaryReferences: unknown,\n decodeReply: (\n body: string | FormData,\n options?: object,\n ) => Promise<unknown[]>,\n decodeAction: (body: FormData) => Promise<() => Promise<void
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils/request.ts"],"sourcesContent":["import type { ReactFormState } from 'react-dom/client';\nimport type { Config } from '../../config.js';\nimport type { Unstable_HandleRequest as HandleRequest } from '../types.js';\nimport { decodeFuncId, decodeRscPath } from '../utils/rsc-path.js';\nimport { createCustomError } from './custom-errors.js';\nimport { ETAGS_HEADER, parseClientEtags } from './etags.js';\nimport { removeBase } from './path.js';\n\ntype HandleRequestInput = Parameters<HandleRequest>[0];\n\nexport async function getInput(\n req: Request,\n config: Omit<Required<Config>, 'vite'>,\n temporaryReferences: unknown,\n decodeReply: (\n body: string | FormData,\n options?: object,\n ) => Promise<unknown[]>,\n decodeAction: (body: FormData) => Promise<() => Promise<void>> | null,\n decodeFormState: (\n actionResult: unknown,\n body: FormData,\n ) => Promise<ReactFormState | undefined>,\n loadServerAction: (id: string) => Promise<unknown>,\n) {\n const url = new URL(req.url);\n const pathname = removeBase(url.pathname, config.basePath);\n const rscPathPrefix = '/' + config.rscBase + '/';\n const etags = parseClientEtags(req.headers.get(ETAGS_HEADER));\n let rscPath: string | undefined;\n let input: HandleRequestInput;\n if (pathname.startsWith(rscPathPrefix)) {\n rscPath = decodeRscPath(pathname.slice(rscPathPrefix.length));\n // server action: js\n const actionId = decodeFuncId(rscPath);\n if (actionId) {\n validateServerActionRequest(req);\n const body = await getActionBody(req);\n const args = await decodeReply(body, { temporaryReferences });\n const action = await loadServerAction(actionId);\n input = {\n type: 'function',\n fn: action as never,\n args,\n pathname,\n req,\n etags,\n };\n } else {\n // client RSC request\n let rscParams: unknown = url.searchParams;\n if (req.body) {\n validateServerActionRequest(req);\n const body = await getActionBody(req);\n rscParams = await decodeReply(body, {\n temporaryReferences,\n });\n }\n input = {\n type: 'component',\n rscPath,\n rscParams,\n pathname,\n req,\n etags,\n };\n }\n } else if (req.method === 'POST') {\n const contentType = req.headers.get('content-type');\n if (\n typeof contentType === 'string' &&\n contentType.startsWith('multipart/form-data')\n ) {\n // server action: no js (progressive enhancement)\n validateServerActionRequest(req);\n input = {\n type: 'action',\n fn: async () => {\n const formData = (await getActionBody(req)) as FormData;\n const decodedAction = await decodeAction(formData);\n if (typeof decodedAction !== 'function') {\n // multipart/form-data POST without an action reference (e.g. crawlers)\n throw createCustomError('Bad Request', { status: 400 });\n }\n const result = await decodedAction();\n return await decodeFormState(result, formData);\n },\n pathname,\n req,\n etags,\n };\n } else {\n // POST API request\n input = {\n type: 'custom',\n pathname,\n req,\n etags,\n };\n }\n } else {\n // SSR\n input = {\n type: 'custom',\n pathname,\n req,\n etags,\n };\n }\n return input;\n}\n\nfunction validateServerActionRequest(req: Request) {\n if (req.method !== 'POST') {\n throw createCustomError('Method Not Allowed', { status: 405 });\n }\n const origin = req.headers.get('origin');\n if (origin) {\n if (origin === 'null') {\n throw createCustomError('Forbidden', { status: 403 });\n }\n const requestOrigin = new URL(req.url).origin;\n let originUrl: URL;\n try {\n originUrl = new URL(origin);\n } catch {\n throw createCustomError('Forbidden', { status: 403 });\n }\n if (originUrl.origin !== requestOrigin) {\n throw createCustomError('Forbidden', { status: 403 });\n }\n } else if (req.headers.get('sec-fetch-site') === 'cross-site') {\n throw createCustomError('Forbidden', { status: 403 });\n }\n}\n\nasync function getActionBody(req: Request) {\n if (!req.body) {\n throw new Error('missing request body for server function');\n }\n const contentType = req.headers.get('content-type');\n if (contentType?.startsWith('multipart/form-data')) {\n return req.formData();\n } else {\n return req.text();\n }\n}\n"],"names":["decodeFuncId","decodeRscPath","createCustomError","ETAGS_HEADER","parseClientEtags","removeBase","getInput","req","config","temporaryReferences","decodeReply","decodeAction","decodeFormState","loadServerAction","url","URL","pathname","basePath","rscPathPrefix","rscBase","etags","headers","get","rscPath","input","startsWith","slice","length","actionId","validateServerActionRequest","body","getActionBody","args","action","type","fn","rscParams","searchParams","method","contentType","formData","decodedAction","status","result","origin","requestOrigin","originUrl","Error","text"],"mappings":"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"}
|
|
@@ -236,7 +236,7 @@ export async function generateFsRouterTypes(pagesDir) {
|
|
|
236
236
|
const result = lines.join('\n');
|
|
237
237
|
return result;
|
|
238
238
|
};
|
|
239
|
-
const files = await collectFiles(pagesDir);
|
|
239
|
+
const files = (await collectFiles(pagesDir)).sort();
|
|
240
240
|
if (!files.length) {
|
|
241
241
|
return;
|
|
242
242
|
}
|