@reckona/mreact-router 0.0.152 → 0.0.153
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 +1 -1
- package/dist/actions.d.ts +10 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +6 -0
- package/dist/actions.js.map +1 -1
- package/dist/adapters/aws-lambda.d.ts +18 -0
- package/dist/adapters/aws-lambda.d.ts.map +1 -1
- package/dist/adapters/aws-lambda.js +18 -0
- package/dist/adapters/aws-lambda.js.map +1 -1
- package/dist/adapters/cloudflare.d.ts +33 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +33 -0
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/edge.d.ts +5 -0
- package/dist/adapters/edge.d.ts.map +1 -1
- package/dist/adapters/edge.js +5 -0
- package/dist/adapters/edge.js.map +1 -1
- package/dist/adapters/node.d.ts +5 -0
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +5 -0
- package/dist/adapters/node.js.map +1 -1
- package/dist/adapters/static.d.ts +5 -0
- package/dist/adapters/static.d.ts.map +1 -1
- package/dist/adapters/static.js +5 -0
- package/dist/adapters/static.js.map +1 -1
- package/dist/build.d.ts +15 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +19 -0
- package/dist/build.js.map +1 -1
- package/dist/cache.d.ts +15 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +15 -0
- package/dist/cache.js.map +1 -1
- package/dist/cookies.d.ts +16 -0
- package/dist/cookies.d.ts.map +1 -1
- package/dist/cookies.js +16 -0
- package/dist/cookies.js.map +1 -1
- package/dist/dev-server.d.ts +5 -0
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +5 -0
- package/dist/dev-server.js.map +1 -1
- package/dist/link.d.ts +10 -0
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +5 -0
- package/dist/link.js.map +1 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +39 -4
- package/dist/middleware.js.map +1 -1
- package/dist/navigation.d.ts +53 -0
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +48 -0
- package/dist/navigation.js.map +1 -1
- package/dist/render.d.ts +28 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +127 -27
- package/dist/render.js.map +1 -1
- package/dist/route-module-loader.d.ts +6 -1
- package/dist/route-module-loader.d.ts.map +1 -1
- package/dist/route-module-loader.js +8 -1
- package/dist/route-module-loader.js.map +1 -1
- package/dist/serve.d.ts +5 -0
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +5 -0
- package/dist/serve.js.map +1 -1
- package/dist/session.d.ts +19 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +19 -0
- package/dist/session.js.map +1 -1
- package/dist/typed-routes.d.ts +5 -0
- package/dist/typed-routes.d.ts.map +1 -1
- package/dist/typed-routes.js +5 -0
- package/dist/typed-routes.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -1
- package/package.json +11 -11
- package/src/actions.ts +18 -0
- package/src/adapters/aws-lambda.ts +18 -0
- package/src/adapters/cloudflare.ts +33 -0
- package/src/adapters/edge.ts +5 -0
- package/src/adapters/node.ts +5 -0
- package/src/adapters/static.ts +5 -0
- package/src/build.ts +19 -0
- package/src/cache.ts +15 -0
- package/src/cookies.ts +16 -0
- package/src/dev-server.ts +5 -0
- package/src/link.ts +10 -0
- package/src/middleware.ts +54 -4
- package/src/navigation.ts +53 -0
- package/src/render.ts +164 -25
- package/src/route-module-loader.ts +15 -0
- package/src/serve.ts +5 -0
- package/src/session.ts +19 -0
- package/src/typed-routes.ts +5 -0
- package/src/types.ts +15 -0
package/dist/session.d.ts
CHANGED
|
@@ -21,9 +21,28 @@ export interface SessionCookieOptions {
|
|
|
21
21
|
sameSite?: "Strict" | "Lax" | "None";
|
|
22
22
|
secure?: boolean;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a process-local session store backed by an in-memory LRU-like map.
|
|
26
|
+
*
|
|
27
|
+
* Use it for development, tests, or single-process deployments; production multi-instance deployments should provide a shared `SessionStore`.
|
|
28
|
+
*/
|
|
24
29
|
export declare function createMemorySessionStore<TData>(options?: MemorySessionStoreOptions): SessionStore<TData>;
|
|
30
|
+
/**
|
|
31
|
+
* Reads the current session cookie, loads the matching session record, and deletes expired records.
|
|
32
|
+
*/
|
|
25
33
|
export declare function getSession<TData>(request: Request, store: SessionStore<TData>, options?: SessionCookieOptions): Promise<SessionRecord<TData> | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new session record, stores it, and appends the session cookie to the response.
|
|
36
|
+
*/
|
|
26
37
|
export declare function createSession<TData>(response: Response, store: SessionStore<TData>, data: TData, options?: SessionCookieOptions): Promise<SessionRecord<TData>>;
|
|
38
|
+
/**
|
|
39
|
+
* Deletes the current session record when present and appends an expiring session cookie to the response.
|
|
40
|
+
*/
|
|
27
41
|
export declare function destroySession<TData>(request: Request, response: Response, store: SessionStore<TData>, options?: SessionCookieOptions): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Replaces the current session id while preserving the stored session data.
|
|
44
|
+
*
|
|
45
|
+
* Use this after authentication or privilege changes to reduce session fixation risk.
|
|
46
|
+
*/
|
|
28
47
|
export declare function rotateSession<TData>(request: Request, response: Response, store: SessionStore<TData>, options?: SessionCookieOptions): Promise<SessionRecord<TData> | undefined>;
|
|
29
48
|
//# sourceMappingURL=session.d.ts.map
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY,CAAC,KAAK,GAAG,OAAO;IAC3C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC;IAC9F,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA+CD,wBAAgB,wBAAwB,CAAC,KAAK,EAC5C,OAAO,GAAE,yBAA8B,GACtC,YAAY,CAAC,KAAK,CAAC,CAoErB;AAUD,wBAAsB,UAAU,CAAC,KAAK,EACpC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAmB3C;AAED,wBAAsB,aAAa,CAAC,KAAK,EACvC,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,IAAI,EAAE,KAAK,EACX,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAgB/B;AAED,wBAAsB,cAAc,CAAC,KAAK,EACxC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,wBAAsB,aAAa,CAAC,KAAK,EACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAW3C"}
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY,CAAC,KAAK,GAAG,OAAO;IAC3C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC;IAC9F,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA+CD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAC5C,OAAO,GAAE,yBAA8B,GACtC,YAAY,CAAC,KAAK,CAAC,CAoErB;AAUD;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EACpC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAmB3C;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EACvC,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,IAAI,EAAE,KAAK,EACX,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAgB/B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EACxC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,KAAK,EACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAW3C"}
|
package/dist/session.js
CHANGED
|
@@ -31,6 +31,11 @@ function createSessionId() {
|
|
|
31
31
|
}
|
|
32
32
|
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a process-local session store backed by an in-memory LRU-like map.
|
|
36
|
+
*
|
|
37
|
+
* Use it for development, tests, or single-process deployments; production multi-instance deployments should provide a shared `SessionStore`.
|
|
38
|
+
*/
|
|
34
39
|
export function createMemorySessionStore(options = {}) {
|
|
35
40
|
const maxEntries = positiveIntegerOrDefault(options.maxEntries, 100_000);
|
|
36
41
|
const sweepIntervalMs = nonNegativeIntegerOrDefault(options.sweepIntervalMs, 60_000);
|
|
@@ -94,6 +99,9 @@ function positiveIntegerOrDefault(value, fallback) {
|
|
|
94
99
|
function nonNegativeIntegerOrDefault(value, fallback) {
|
|
95
100
|
return value === undefined || !Number.isInteger(value) || value < 0 ? fallback : value;
|
|
96
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Reads the current session cookie, loads the matching session record, and deletes expired records.
|
|
104
|
+
*/
|
|
97
105
|
export async function getSession(request, store, options = {}) {
|
|
98
106
|
const id = readSessionId(request, options);
|
|
99
107
|
if (id === undefined || id.length === 0) {
|
|
@@ -109,6 +117,9 @@ export async function getSession(request, store, options = {}) {
|
|
|
109
117
|
}
|
|
110
118
|
return record;
|
|
111
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Creates a new session record, stores it, and appends the session cookie to the response.
|
|
122
|
+
*/
|
|
112
123
|
export async function createSession(response, store, data, options = {}) {
|
|
113
124
|
const now = Date.now();
|
|
114
125
|
const maxAgeSeconds = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;
|
|
@@ -124,6 +135,9 @@ export async function createSession(response, store, data, options = {}) {
|
|
|
124
135
|
});
|
|
125
136
|
return record;
|
|
126
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Deletes the current session record when present and appends an expiring session cookie to the response.
|
|
140
|
+
*/
|
|
127
141
|
export async function destroySession(request, response, store, options = {}) {
|
|
128
142
|
const id = readSessionId(request, options);
|
|
129
143
|
if (id !== undefined) {
|
|
@@ -135,6 +149,11 @@ export async function destroySession(request, response, store, options = {}) {
|
|
|
135
149
|
secure: options.secure ?? isProduction(),
|
|
136
150
|
});
|
|
137
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Replaces the current session id while preserving the stored session data.
|
|
154
|
+
*
|
|
155
|
+
* Use this after authentication or privilege changes to reduce session fixation risk.
|
|
156
|
+
*/
|
|
138
157
|
export async function rotateSession(request, response, store, options = {}) {
|
|
139
158
|
const current = await getSession(request, store, options);
|
|
140
159
|
if (current === undefined) {
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteCookie, parseCookieHeader, setCookie } from \"./cookies.js\";\n\nexport interface SessionRecord<TData = unknown> {\n createdAt: number;\n data: TData;\n expiresAt: number;\n id: string;\n rotatedAt?: number;\n}\n\nexport interface SessionStore<TData = unknown> {\n delete(id: string): void | Promise<void>;\n get(id: string): SessionRecord<TData> | undefined | Promise<SessionRecord<TData> | undefined>;\n set(record: SessionRecord<TData>): void | Promise<void>;\n}\n\nexport interface MemorySessionStoreOptions {\n maxEntries?: number;\n sweepIntervalMs?: number;\n}\n\nexport interface SessionCookieOptions {\n cookieName?: string;\n maxAgeSeconds?: number;\n path?: string;\n sameSite?: \"Strict\" | \"Lax\" | \"None\";\n secure?: boolean;\n}\n\nconst DEFAULT_MAX_AGE_SECONDS = 7 * 24 * 60 * 60;\nconst SESSION_COOKIE_DEV = \"mreact.session\";\nconst SESSION_COOKIE_PROD = \"__Host-mreact.session\";\n\nfunction isProduction(): boolean {\n return process.env.NODE_ENV === \"production\";\n}\n\nfunction defaultCookieName(): string {\n return isProduction() ? SESSION_COOKIE_PROD : SESSION_COOKIE_DEV;\n}\n\nfunction sessionCookieOptions(options: SessionCookieOptions = {}) {\n const production = isProduction();\n\n return {\n httpOnly: true,\n maxAge: options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS,\n path: production ? \"/\" : options.path ?? \"/\",\n sameSite: options.sameSite ?? \"Lax\",\n secure: options.secure ?? production,\n } as const;\n}\n\nfunction readSessionId(\n request: Request,\n options: SessionCookieOptions = {},\n): string | undefined {\n const values = parseCookieHeader(request.headers.get(\"cookie\"));\n return values.get(options.cookieName ?? defaultCookieName());\n}\n\nfunction createSessionId(): string {\n const bytes = new Uint8Array(32);\n\n globalThis.crypto.getRandomValues(bytes);\n\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nexport function createMemorySessionStore<TData>(\n options: MemorySessionStoreOptions = {},\n): SessionStore<TData> {\n const maxEntries = positiveIntegerOrDefault(options.maxEntries, 100_000);\n const sweepIntervalMs = nonNegativeIntegerOrDefault(options.sweepIntervalMs, 60_000);\n const records = new Map<string, SessionRecord<TData>>();\n let nextSweepAt = 0;\n\n function sweepExpired(now: number): void {\n for (const [id, value] of records) {\n if (value.expiresAt <= now) {\n records.delete(id);\n }\n }\n\n nextSweepAt = now + sweepIntervalMs;\n }\n\n function maybeSweepExpired(now: number): void {\n if (sweepIntervalMs === 0 || now >= nextSweepAt) {\n sweepExpired(now);\n }\n }\n\n function evictOldestEntries(): void {\n while (records.size > maxEntries) {\n const oldestId = records.keys().next().value;\n\n if (oldestId === undefined) {\n return;\n }\n\n records.delete(oldestId);\n }\n }\n\n return {\n delete(id) {\n records.delete(id);\n },\n get(id) {\n const now = Date.now();\n maybeSweepExpired(now);\n const record = records.get(id);\n\n if (record !== undefined && record.expiresAt <= now) {\n records.delete(id);\n return undefined;\n }\n\n if (record !== undefined) {\n records.delete(id);\n records.set(id, record);\n }\n\n return record;\n },\n set(record) {\n const now = Date.now();\n maybeSweepExpired(now);\n\n records.delete(record.id);\n records.set(record.id, record);\n\n if (records.size > maxEntries) {\n sweepExpired(now);\n evictOldestEntries();\n }\n },\n };\n}\n\nfunction positiveIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 1 ? fallback : value;\n}\n\nfunction nonNegativeIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 0 ? fallback : value;\n}\n\nexport async function getSession<TData>(\n request: Request,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const id = readSessionId(request, options);\n\n if (id === undefined || id.length === 0) {\n return undefined;\n }\n\n const record = await store.get(id);\n\n if (record === undefined) {\n return undefined;\n }\n\n if (record.expiresAt <= Date.now()) {\n await store.delete(id);\n return undefined;\n }\n\n return record;\n}\n\nexport async function createSession<TData>(\n response: Response,\n store: SessionStore<TData>,\n data: TData,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData>> {\n const now = Date.now();\n const maxAgeSeconds = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n const record: SessionRecord<TData> = {\n createdAt: now,\n data,\n expiresAt: now + maxAgeSeconds * 1000,\n id: createSessionId(),\n };\n\n await store.set(record);\n setCookie(response, options.cookieName ?? defaultCookieName(), record.id, {\n ...sessionCookieOptions({ ...options, maxAgeSeconds }),\n });\n\n return record;\n}\n\nexport async function destroySession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<void> {\n const id = readSessionId(request, options);\n\n if (id !== undefined) {\n await store.delete(id);\n }\n\n deleteCookie(response, options.cookieName ?? defaultCookieName(), {\n path: isProduction() ? \"/\" : options.path ?? \"/\",\n sameSite: options.sameSite ?? \"Lax\",\n secure: options.secure ?? isProduction(),\n });\n}\n\nexport async function rotateSession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const current = await getSession(request, store, options);\n\n if (current === undefined) {\n return undefined;\n }\n\n await store.delete(current.id);\n const next = await createSession(response, store, current.data, options);\n\n return { ...next, rotatedAt: Date.now() };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteCookie, parseCookieHeader, setCookie } from \"./cookies.js\";\n\nexport interface SessionRecord<TData = unknown> {\n createdAt: number;\n data: TData;\n expiresAt: number;\n id: string;\n rotatedAt?: number;\n}\n\nexport interface SessionStore<TData = unknown> {\n delete(id: string): void | Promise<void>;\n get(id: string): SessionRecord<TData> | undefined | Promise<SessionRecord<TData> | undefined>;\n set(record: SessionRecord<TData>): void | Promise<void>;\n}\n\nexport interface MemorySessionStoreOptions {\n maxEntries?: number;\n sweepIntervalMs?: number;\n}\n\nexport interface SessionCookieOptions {\n cookieName?: string;\n maxAgeSeconds?: number;\n path?: string;\n sameSite?: \"Strict\" | \"Lax\" | \"None\";\n secure?: boolean;\n}\n\nconst DEFAULT_MAX_AGE_SECONDS = 7 * 24 * 60 * 60;\nconst SESSION_COOKIE_DEV = \"mreact.session\";\nconst SESSION_COOKIE_PROD = \"__Host-mreact.session\";\n\nfunction isProduction(): boolean {\n return process.env.NODE_ENV === \"production\";\n}\n\nfunction defaultCookieName(): string {\n return isProduction() ? SESSION_COOKIE_PROD : SESSION_COOKIE_DEV;\n}\n\nfunction sessionCookieOptions(options: SessionCookieOptions = {}) {\n const production = isProduction();\n\n return {\n httpOnly: true,\n maxAge: options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS,\n path: production ? \"/\" : options.path ?? \"/\",\n sameSite: options.sameSite ?? \"Lax\",\n secure: options.secure ?? production,\n } as const;\n}\n\nfunction readSessionId(\n request: Request,\n options: SessionCookieOptions = {},\n): string | undefined {\n const values = parseCookieHeader(request.headers.get(\"cookie\"));\n return values.get(options.cookieName ?? defaultCookieName());\n}\n\nfunction createSessionId(): string {\n const bytes = new Uint8Array(32);\n\n globalThis.crypto.getRandomValues(bytes);\n\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/**\n * Creates a process-local session store backed by an in-memory LRU-like map.\n *\n * Use it for development, tests, or single-process deployments; production multi-instance deployments should provide a shared `SessionStore`.\n */\nexport function createMemorySessionStore<TData>(\n options: MemorySessionStoreOptions = {},\n): SessionStore<TData> {\n const maxEntries = positiveIntegerOrDefault(options.maxEntries, 100_000);\n const sweepIntervalMs = nonNegativeIntegerOrDefault(options.sweepIntervalMs, 60_000);\n const records = new Map<string, SessionRecord<TData>>();\n let nextSweepAt = 0;\n\n function sweepExpired(now: number): void {\n for (const [id, value] of records) {\n if (value.expiresAt <= now) {\n records.delete(id);\n }\n }\n\n nextSweepAt = now + sweepIntervalMs;\n }\n\n function maybeSweepExpired(now: number): void {\n if (sweepIntervalMs === 0 || now >= nextSweepAt) {\n sweepExpired(now);\n }\n }\n\n function evictOldestEntries(): void {\n while (records.size > maxEntries) {\n const oldestId = records.keys().next().value;\n\n if (oldestId === undefined) {\n return;\n }\n\n records.delete(oldestId);\n }\n }\n\n return {\n delete(id) {\n records.delete(id);\n },\n get(id) {\n const now = Date.now();\n maybeSweepExpired(now);\n const record = records.get(id);\n\n if (record !== undefined && record.expiresAt <= now) {\n records.delete(id);\n return undefined;\n }\n\n if (record !== undefined) {\n records.delete(id);\n records.set(id, record);\n }\n\n return record;\n },\n set(record) {\n const now = Date.now();\n maybeSweepExpired(now);\n\n records.delete(record.id);\n records.set(record.id, record);\n\n if (records.size > maxEntries) {\n sweepExpired(now);\n evictOldestEntries();\n }\n },\n };\n}\n\nfunction positiveIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 1 ? fallback : value;\n}\n\nfunction nonNegativeIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 0 ? fallback : value;\n}\n\n/**\n * Reads the current session cookie, loads the matching session record, and deletes expired records.\n */\nexport async function getSession<TData>(\n request: Request,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const id = readSessionId(request, options);\n\n if (id === undefined || id.length === 0) {\n return undefined;\n }\n\n const record = await store.get(id);\n\n if (record === undefined) {\n return undefined;\n }\n\n if (record.expiresAt <= Date.now()) {\n await store.delete(id);\n return undefined;\n }\n\n return record;\n}\n\n/**\n * Creates a new session record, stores it, and appends the session cookie to the response.\n */\nexport async function createSession<TData>(\n response: Response,\n store: SessionStore<TData>,\n data: TData,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData>> {\n const now = Date.now();\n const maxAgeSeconds = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n const record: SessionRecord<TData> = {\n createdAt: now,\n data,\n expiresAt: now + maxAgeSeconds * 1000,\n id: createSessionId(),\n };\n\n await store.set(record);\n setCookie(response, options.cookieName ?? defaultCookieName(), record.id, {\n ...sessionCookieOptions({ ...options, maxAgeSeconds }),\n });\n\n return record;\n}\n\n/**\n * Deletes the current session record when present and appends an expiring session cookie to the response.\n */\nexport async function destroySession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<void> {\n const id = readSessionId(request, options);\n\n if (id !== undefined) {\n await store.delete(id);\n }\n\n deleteCookie(response, options.cookieName ?? defaultCookieName(), {\n path: isProduction() ? \"/\" : options.path ?? \"/\",\n sameSite: options.sameSite ?? \"Lax\",\n secure: options.secure ?? isProduction(),\n });\n}\n\n/**\n * Replaces the current session id while preserving the stored session data.\n *\n * Use this after authentication or privilege changes to reduce session fixation risk.\n */\nexport async function rotateSession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const current = await getSession(request, store, options);\n\n if (current === undefined) {\n return undefined;\n }\n\n await store.delete(current.id);\n const next = await createSession(response, store, current.data, options);\n\n return { ...next, rotatedAt: Date.now() };\n}\n"]}
|
package/dist/typed-routes.d.ts
CHANGED
|
@@ -24,6 +24,11 @@ export type AppRouteLinkHrefSuffix = "" | `?${string}` | `#${string}` | `?${stri
|
|
|
24
24
|
export type AppRouteLinkPathname<Path extends `/${string}`> = Path extends "/" ? "/" : Path extends `/${infer Segments}` ? `/${AppRouteLinkSegments<Segments>}` : never;
|
|
25
25
|
export type AppRouteLinkSegments<Segments extends string> = Segments extends `${infer Segment}/${infer Rest}` ? `${AppRouteLinkSegment<Segment>}/${AppRouteLinkSegments<Rest>}` : AppRouteLinkSegment<Segments>;
|
|
26
26
|
export type AppRouteLinkSegment<Segment extends string> = Segment extends `:${string}` ? string : Segment;
|
|
27
|
+
/**
|
|
28
|
+
* Builds an internal app-route URL from a route pattern and typed params/search options.
|
|
29
|
+
*
|
|
30
|
+
* Dynamic `:param` and `:...catchAll` segments are URL-encoded, search values are serialized with `URLSearchParams`, and protocol-relative or external paths are rejected.
|
|
31
|
+
*/
|
|
27
32
|
export declare function href<const Path extends `/${string}`>(path: Path, ...args: HasRouteParams<Path> extends true ? [options: DynamicHrefOptions<Path>] : [options?: StaticHrefOptions]): string;
|
|
28
33
|
export {};
|
|
29
34
|
//# sourceMappingURL=typed-routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typed-routes.d.ts","sourceRoot":"","sources":["../src/typed-routes.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"typed-routes.d.ts","sourceRoot":"","sources":["../src/typed-routes.ts"],"names":[],"mappings":"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"}
|
package/dist/typed-routes.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an internal app-route URL from a route pattern and typed params/search options.
|
|
3
|
+
*
|
|
4
|
+
* Dynamic `:param` and `:...catchAll` segments are URL-encoded, search values are serialized with `URLSearchParams`, and protocol-relative or external paths are rejected.
|
|
5
|
+
*/
|
|
1
6
|
export function href(path, ...args) {
|
|
2
7
|
assertInternalRoutePath(path);
|
|
3
8
|
const options = args[0];
|
package/dist/typed-routes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typed-routes.js","sourceRoot":"","sources":["../src/typed-routes.ts"],"names":[],"mappings":"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","sourcesContent":["export type RouteSearchValue = boolean | number | string | null | undefined;\nexport type RouteSearchParams = Record<\n string,\n RouteSearchValue | readonly RouteSearchValue[]\n>;\n\nexport type RouteParamsFor<Path extends `/${string}`> = Simplify<ExtractRouteParams<Path>>;\n\nexport type AppRouteHref<Path extends `/${string}`> = keyof RouteParamsFor<Path> extends never\n ? (options?: StaticHrefOptions) => string\n : (options: DynamicHrefOptions<Path>) => string;\n\nexport type AppRouteLinkHref<Path extends `/${string}`> =\n `${AppRouteLinkPathname<Path>}${AppRouteLinkHrefSuffix}`;\n\nexport interface StaticHrefOptions {\n hash?: string | undefined;\n search?: RouteSearchParams | undefined;\n}\n\nexport interface DynamicHrefOptions<Path extends `/${string}`> extends StaticHrefOptions {\n params: RouteParamsFor<Path>;\n}\n\ntype HasRouteParams<Path extends `/${string}`> = keyof RouteParamsFor<Path> extends never\n ? false\n : true;\n\ntype ExtractRouteParams<Path extends string> = Path extends `${infer Segment}/${infer Rest}`\n ? SegmentRouteParam<Segment> & ExtractRouteParams<Rest>\n : SegmentRouteParam<Path>;\n\ntype SegmentRouteParam<Segment extends string> = Segment extends `:...${infer Name}`\n ? { [Key in Name]: readonly string[] }\n : Segment extends `:${infer Name}`\n ? { [Key in Name]: string }\n : Record<never, never>;\n\ntype Simplify<T> = { [Key in keyof T]: T[Key] } & {};\n\nexport type AppRouteLinkHrefSuffix = \"\" | `?${string}` | `#${string}` | `?${string}#${string}`;\n\nexport type AppRouteLinkPathname<Path extends `/${string}`> = Path extends \"/\"\n ? \"/\"\n : Path extends `/${infer Segments}`\n ? `/${AppRouteLinkSegments<Segments>}`\n : never;\n\nexport type AppRouteLinkSegments<Segments extends string> = Segments extends `${infer Segment}/${infer Rest}`\n ? `${AppRouteLinkSegment<Segment>}/${AppRouteLinkSegments<Rest>}`\n : AppRouteLinkSegment<Segments>;\n\nexport type AppRouteLinkSegment<Segment extends string> = Segment extends `:${string}`\n ? string\n : Segment;\n\nexport function href<const Path extends `/${string}`>(\n path: Path,\n ...args: HasRouteParams<Path> extends true\n ? [options: DynamicHrefOptions<Path>]\n : [options?: StaticHrefOptions]\n): string {\n assertInternalRoutePath(path);\n\n const options = args[0] as\n | (StaticHrefOptions & { params?: Record<string, readonly string[] | string> | undefined })\n | undefined;\n const params =\n options !== undefined && \"params\" in options && options.params !== undefined\n ? (options.params as Record<string, readonly string[] | string>)\n : {};\n const pathname = path\n .split(\"/\")\n .map((segment) => {\n if (segment.startsWith(\":...\")) {\n const name = segment.slice(4);\n const value = params[name];\n\n if (!Array.isArray(value)) {\n throw new Error(`Missing catch-all route param ${JSON.stringify(name)} for ${path}.`);\n }\n\n return value.map((part) => encodeURIComponent(part)).join(\"/\");\n }\n\n if (segment.startsWith(\":\")) {\n const name = segment.slice(1);\n const value = params[name];\n\n if (typeof value !== \"string\") {\n throw new Error(`Missing route param ${JSON.stringify(name)} for ${path}.`);\n }\n\n return encodeURIComponent(value);\n }\n\n return segment;\n })\n .join(\"/\");\n const search = searchString(options?.search);\n const hash = options?.hash === undefined ? \"\" : `#${encodeURIComponent(options.hash)}`;\n\n return `${pathname}${search}${hash}`;\n}\n\nfunction assertInternalRoutePath(path: string): void {\n if (!path.startsWith(\"/\") || path.startsWith(\"//\")) {\n throw new Error(`href() expected an internal route path, received ${JSON.stringify(path)}.`);\n }\n\n for (let index = 0; index < path.length; index += 1) {\n const code = path.charCodeAt(index);\n\n if (code <= 0x1f || code === 0x7f) {\n throw new Error(\"href() route paths must not contain control characters.\");\n }\n }\n}\n\nfunction searchString(search: RouteSearchParams | undefined): string {\n if (search === undefined) {\n return \"\";\n }\n\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(search)) {\n const values = Array.isArray(value) ? value : [value];\n\n for (const entry of values) {\n if (entry !== undefined && entry !== null) {\n params.append(key, String(entry));\n }\n }\n }\n\n const value = params.toString();\n\n return value === \"\" ? \"\" : `?${value}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"typed-routes.js","sourceRoot":"","sources":["../src/typed-routes.ts"],"names":[],"mappings":"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","sourcesContent":["export type RouteSearchValue = boolean | number | string | null | undefined;\nexport type RouteSearchParams = Record<\n string,\n RouteSearchValue | readonly RouteSearchValue[]\n>;\n\nexport type RouteParamsFor<Path extends `/${string}`> = Simplify<ExtractRouteParams<Path>>;\n\nexport type AppRouteHref<Path extends `/${string}`> = keyof RouteParamsFor<Path> extends never\n ? (options?: StaticHrefOptions) => string\n : (options: DynamicHrefOptions<Path>) => string;\n\nexport type AppRouteLinkHref<Path extends `/${string}`> =\n `${AppRouteLinkPathname<Path>}${AppRouteLinkHrefSuffix}`;\n\nexport interface StaticHrefOptions {\n hash?: string | undefined;\n search?: RouteSearchParams | undefined;\n}\n\nexport interface DynamicHrefOptions<Path extends `/${string}`> extends StaticHrefOptions {\n params: RouteParamsFor<Path>;\n}\n\ntype HasRouteParams<Path extends `/${string}`> = keyof RouteParamsFor<Path> extends never\n ? false\n : true;\n\ntype ExtractRouteParams<Path extends string> = Path extends `${infer Segment}/${infer Rest}`\n ? SegmentRouteParam<Segment> & ExtractRouteParams<Rest>\n : SegmentRouteParam<Path>;\n\ntype SegmentRouteParam<Segment extends string> = Segment extends `:...${infer Name}`\n ? { [Key in Name]: readonly string[] }\n : Segment extends `:${infer Name}`\n ? { [Key in Name]: string }\n : Record<never, never>;\n\ntype Simplify<T> = { [Key in keyof T]: T[Key] } & {};\n\nexport type AppRouteLinkHrefSuffix = \"\" | `?${string}` | `#${string}` | `?${string}#${string}`;\n\nexport type AppRouteLinkPathname<Path extends `/${string}`> = Path extends \"/\"\n ? \"/\"\n : Path extends `/${infer Segments}`\n ? `/${AppRouteLinkSegments<Segments>}`\n : never;\n\nexport type AppRouteLinkSegments<Segments extends string> = Segments extends `${infer Segment}/${infer Rest}`\n ? `${AppRouteLinkSegment<Segment>}/${AppRouteLinkSegments<Rest>}`\n : AppRouteLinkSegment<Segments>;\n\nexport type AppRouteLinkSegment<Segment extends string> = Segment extends `:${string}`\n ? string\n : Segment;\n\n/**\n * Builds an internal app-route URL from a route pattern and typed params/search options.\n *\n * Dynamic `:param` and `:...catchAll` segments are URL-encoded, search values are serialized with `URLSearchParams`, and protocol-relative or external paths are rejected.\n */\nexport function href<const Path extends `/${string}`>(\n path: Path,\n ...args: HasRouteParams<Path> extends true\n ? [options: DynamicHrefOptions<Path>]\n : [options?: StaticHrefOptions]\n): string {\n assertInternalRoutePath(path);\n\n const options = args[0] as\n | (StaticHrefOptions & { params?: Record<string, readonly string[] | string> | undefined })\n | undefined;\n const params =\n options !== undefined && \"params\" in options && options.params !== undefined\n ? (options.params as Record<string, readonly string[] | string>)\n : {};\n const pathname = path\n .split(\"/\")\n .map((segment) => {\n if (segment.startsWith(\":...\")) {\n const name = segment.slice(4);\n const value = params[name];\n\n if (!Array.isArray(value)) {\n throw new Error(`Missing catch-all route param ${JSON.stringify(name)} for ${path}.`);\n }\n\n return value.map((part) => encodeURIComponent(part)).join(\"/\");\n }\n\n if (segment.startsWith(\":\")) {\n const name = segment.slice(1);\n const value = params[name];\n\n if (typeof value !== \"string\") {\n throw new Error(`Missing route param ${JSON.stringify(name)} for ${path}.`);\n }\n\n return encodeURIComponent(value);\n }\n\n return segment;\n })\n .join(\"/\");\n const search = searchString(options?.search);\n const hash = options?.hash === undefined ? \"\" : `#${encodeURIComponent(options.hash)}`;\n\n return `${pathname}${search}${hash}`;\n}\n\nfunction assertInternalRoutePath(path: string): void {\n if (!path.startsWith(\"/\") || path.startsWith(\"//\")) {\n throw new Error(`href() expected an internal route path, received ${JSON.stringify(path)}.`);\n }\n\n for (let index = 0; index < path.length; index += 1) {\n const code = path.charCodeAt(index);\n\n if (code <= 0x1f || code === 0x7f) {\n throw new Error(\"href() route paths must not contain control characters.\");\n }\n }\n}\n\nfunction searchString(search: RouteSearchParams | undefined): string {\n if (search === undefined) {\n return \"\";\n }\n\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(search)) {\n const values = Array.isArray(value) ? value : [value];\n\n for (const entry of values) {\n if (entry !== undefined && entry !== null) {\n params.append(key, String(entry));\n }\n }\n }\n\n const value = params.toString();\n\n return value === \"\" ? \"\" : `?${value}`;\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -12,6 +12,11 @@ export interface LoaderContext<TParams extends RouteParams = RouteParams> {
|
|
|
12
12
|
queryClient: QueryClient;
|
|
13
13
|
request: Request;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Context passed to a route `generateMetadata` export.
|
|
17
|
+
*
|
|
18
|
+
* Metadata is evaluated on the server after loader data is available, so it can derive head tags, robots data, sitemap entries, and security header directives from the same request and route params as the page.
|
|
19
|
+
*/
|
|
15
20
|
export interface GenerateMetadataContext<TData = unknown, TParams extends RouteParams = RouteParams> {
|
|
16
21
|
data: TData;
|
|
17
22
|
params: TParams;
|
|
@@ -27,6 +32,11 @@ export interface PageProps<TData = unknown, TParams extends RouteParams = RouteP
|
|
|
27
32
|
request: Request;
|
|
28
33
|
}
|
|
29
34
|
export type PageComponent<TLoader extends RouteLoader> = (props: PageProps<InferLoaderData<TLoader>, InferLoaderParams<TLoader>>) => ReactCompatNode;
|
|
35
|
+
/**
|
|
36
|
+
* Preserves the relationship between a page component and its loader when authoring route files.
|
|
37
|
+
*
|
|
38
|
+
* Wrap a default page export with `definePage<typeof loader>(...)` to infer `data` and `params` props from the route loader without changing runtime behavior.
|
|
39
|
+
*/
|
|
30
40
|
export declare function definePage<TLoader extends RouteLoader>(component: PageComponent<TLoader>): PageComponent<TLoader>;
|
|
31
41
|
export interface LayoutProps<TParams extends RouteParams = RouteParams> {
|
|
32
42
|
children: ReactCompatNode;
|
|
@@ -42,6 +52,11 @@ export interface MetadataImage {
|
|
|
42
52
|
url: MetadataScalar;
|
|
43
53
|
width?: MetadataScalar;
|
|
44
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Declarative metadata returned by route metadata exports.
|
|
57
|
+
*
|
|
58
|
+
* Values are rendered into the document head and response headers by the app router; use `generateMetadata` when the values depend on loader data, params, or the current request.
|
|
59
|
+
*/
|
|
45
60
|
export interface RouteMetadata {
|
|
46
61
|
alternates?: {
|
|
47
62
|
canonical?: MetadataScalar;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC;AAExD,MAAM,MAAM,eAAe,CAAC,OAAO,SAAS,WAAW,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAExF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;AAErE,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,WAAW,IAAI,OAAO,SAAS,CAC3E,OAAO,EAAE,MAAM,QAAQ,EACvB,GAAG,IAAI,EAAE,KAAK,EAAE,KACb,OAAO,GACR,QAAQ,SAAS;IAAE,MAAM,EAAE,MAAM,OAAO,CAAA;CAAE,GACxC,OAAO,SAAS,WAAW,GACzB,OAAO,GACP,WAAW,GACb,WAAW,GACb,WAAW,CAAC;AAEhB,MAAM,WAAW,aAAa,CAAC,OAAO,SAAS,WAAW,GAAG,WAAW;IACtE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB,CACtC,KAAK,GAAG,OAAO,EACf,OAAO,SAAS,WAAW,GAAG,WAAW;IAEzC,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO,SAAS,WAAW,GAAG,WAAW;IAC5E,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,SAAS,WAAW,GAAG,WAAW;IACnF,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,WAAW,IAAI,CACvD,KAAK,EAAE,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,KACnE,eAAe,CAAC;AAErB,wBAAgB,UAAU,CAAC,OAAO,SAAS,WAAW,EACpD,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,GAChC,aAAa,CAAC,OAAO,CAAC,CAExB;AAED,MAAM,WAAW,WAAW,CAAC,OAAO,SAAS,WAAW,GAAG,WAAW;IACpE,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC;AAEzC,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,GAAG,EAAE,cAAc,CAAC;IACpB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE;QACX,SAAS,CAAC,EAAE,cAAc,CAAC;KAC5B,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;QACxD,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;KACtD,CAAC;IACF,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,IAAI,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACtC,KAAK,CAAC,EAAE;QACN,KAAK,CAAC,EAAE,cAAc,CAAC;QACvB,IAAI,CAAC,EAAE,cAAc,CAAC;KACvB,CAAC;IACF,SAAS,CAAC,EAAE;QACV,WAAW,CAAC,EAAE,cAAc,CAAC;QAC7B,KAAK,CAAC,EAAE,aAAa,GAAG,cAAc,CAAC;QACvC,MAAM,CAAC,EAAE,SAAS,CAAC,aAAa,GAAG,cAAc,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,EAAE,cAAc,CAAC;KACxB,CAAC;IACF,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,MAAM,CAAC,EACH,MAAM,GACN;QACE,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IACN,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,UAAU,CAAC,EAAE,cAAc,GAAG,kBAAkB,CAAC;IACjD,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,gBAAgB,CAAC;CAC9C;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEjF,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CACpD;AAED,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD,IAAI,CAAC,EAAE,4BAA4B,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/D,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5F,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,4BAA4B;IAC3C,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE,GAAG,SAAS,CAAC;IACvD,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAClD;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAClD,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preserves the relationship between a page component and its loader when authoring route files.
|
|
3
|
+
*
|
|
4
|
+
* Wrap a default page export with `definePage<typeof loader>(...)` to infer `data` and `params` props from the route loader without changing runtime behavior.
|
|
5
|
+
*/
|
|
1
6
|
export function definePage(component) {
|
|
2
7
|
return component;
|
|
3
8
|
}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAwDA;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,SAAiC;IAEjC,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { ReactCompatNode } from \"@reckona/mreact-compat\";\nimport type { QueryClient } from \"@reckona/mreact-query\";\n\nexport type RouteLoader = (...args: never[]) => unknown;\n\nexport type InferLoaderData<TLoader extends RouteLoader> = Awaited<ReturnType<TLoader>>;\n\nexport type RouteParams = Record<string, readonly string[] | string>;\n\nexport type InferLoaderParams<TLoader extends RouteLoader> = TLoader extends (\n context: infer TContext,\n ...args: never[]\n) => unknown\n ? TContext extends { params: infer TParams }\n ? TParams extends RouteParams\n ? TParams\n : RouteParams\n : RouteParams\n : RouteParams;\n\nexport interface LoaderContext<TParams extends RouteParams = RouteParams> {\n env?: unknown;\n params: TParams;\n queryClient: QueryClient;\n request: Request;\n}\n\n/**\n * Context passed to a route `generateMetadata` export.\n *\n * Metadata is evaluated on the server after loader data is available, so it can derive head tags, robots data, sitemap entries, and security header directives from the same request and route params as the page.\n */\nexport interface GenerateMetadataContext<\n TData = unknown,\n TParams extends RouteParams = RouteParams,\n> {\n data: TData;\n params: TParams;\n request: Request;\n}\n\nexport interface RouteHandlerContext<TParams extends RouteParams = RouteParams> {\n params: TParams;\n request: Request;\n}\n\nexport interface PageProps<TData = unknown, TParams extends RouteParams = RouteParams> {\n data: TData;\n params: TParams;\n request: Request;\n}\n\nexport type PageComponent<TLoader extends RouteLoader> = (\n props: PageProps<InferLoaderData<TLoader>, InferLoaderParams<TLoader>>,\n) => ReactCompatNode;\n\n/**\n * Preserves the relationship between a page component and its loader when authoring route files.\n *\n * Wrap a default page export with `definePage<typeof loader>(...)` to infer `data` and `params` props from the route loader without changing runtime behavior.\n */\nexport function definePage<TLoader extends RouteLoader>(\n component: PageComponent<TLoader>,\n): PageComponent<TLoader> {\n return component;\n}\n\nexport interface LayoutProps<TParams extends RouteParams = RouteParams> {\n children: ReactCompatNode;\n params: TParams;\n request: Request;\n}\n\nexport type MReactNode = ReactCompatNode;\n\nexport type MetadataScalar = boolean | number | string;\n\nexport interface MetadataImage {\n alt?: MetadataScalar;\n height?: MetadataScalar;\n type?: MetadataScalar;\n url: MetadataScalar;\n width?: MetadataScalar;\n}\n\n/**\n * Declarative metadata returned by route metadata exports.\n *\n * Values are rendered into the document head and response headers by the app router; use `generateMetadata` when the values depend on loader data, params, or the current request.\n */\nexport interface RouteMetadata {\n alternates?: {\n canonical?: MetadataScalar;\n };\n csp?: {\n disable?: boolean;\n directives?: Record<string, readonly string[] | string>;\n nonce?: string;\n remove?: readonly string[];\n replace?: Record<string, readonly string[] | string>;\n };\n description?: MetadataScalar;\n head?: readonly RouteHeadDescriptor[];\n icons?: {\n apple?: MetadataScalar;\n icon?: MetadataScalar;\n };\n openGraph?: {\n description?: MetadataScalar;\n image?: MetadataImage | MetadataScalar;\n images?: readonly (MetadataImage | MetadataScalar)[];\n title?: MetadataScalar;\n };\n lang?: MetadataScalar;\n robots?:\n | string\n | {\n follow?: boolean;\n index?: boolean;\n };\n security?: RouteSecurityHeaders;\n themeColor?: MetadataScalar | MetadataThemeColor;\n title?: MetadataScalar;\n viewport?: MetadataScalar | MetadataViewport;\n}\n\nexport type MetadataViewport = Record<string, MetadataScalar | null | undefined>;\n\nexport interface MetadataThemeColor {\n color?: MetadataScalar;\n media?: MetadataScalar;\n}\n\nexport interface RouteHeadDescriptor {\n attrs?: Record<string, boolean | number | string | undefined>;\n content?: string;\n nonce?: boolean | string;\n tag: \"base\" | \"link\" | \"meta\" | \"script\" | \"style\";\n}\n\nexport interface RouteSecurityHeaders {\n contentTypeOptions?: \"nosniff\" | null | undefined;\n frameOptions?: \"DENY\" | \"SAMEORIGIN\" | null | undefined;\n hsts?: RouteStrictTransportSecurity | false | null | undefined;\n permissionsPolicy?: Record<string, readonly string[] | null | undefined> | null | undefined;\n referrerPolicy?: string | null | undefined;\n}\n\nexport interface RouteStrictTransportSecurity {\n includeSubDomains?: boolean | undefined;\n maxAge: number;\n preload?: boolean | undefined;\n}\n\nexport interface RobotsContext {\n baseUrl: string;\n host: string;\n request: Request;\n}\n\nexport interface RobotsManifest {\n host?: string | undefined;\n rules?: RobotsRule | readonly RobotsRule[] | undefined;\n sitemap?: string | readonly string[] | undefined;\n}\n\nexport interface RobotsRule {\n allow?: string | readonly string[] | undefined;\n disallow?: string | readonly string[] | undefined;\n userAgent: string | readonly string[];\n}\n\nexport interface SitemapContext {\n baseUrl: string;\n host: string;\n request: Request;\n}\n\nexport interface SitemapEntry {\n changeFrequency?: string | undefined;\n lastModified?: Date | string | number | undefined;\n priority?: number | undefined;\n url: string;\n}\n\nexport interface ManifestContext {\n baseUrl: string;\n host: string;\n request: Request;\n}\n\nexport type ManifestDescriptor = Record<string, unknown>;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-router",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.153",
|
|
4
4
|
"description": "File-system app router, SSR, actions, and deployment adapters for mreact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jsx",
|
|
@@ -105,20 +105,20 @@
|
|
|
105
105
|
},
|
|
106
106
|
"dependencies": {
|
|
107
107
|
"typescript": "^6.0.3",
|
|
108
|
-
"@reckona/mreact": "0.0.
|
|
109
|
-
"@reckona/mreact-
|
|
110
|
-
"@reckona/mreact-
|
|
111
|
-
"@reckona/mreact-
|
|
112
|
-
"@reckona/mreact-
|
|
113
|
-
"@reckona/mreact-
|
|
114
|
-
"@reckona/mreact-reactive-dom": "0.0.
|
|
115
|
-
"@reckona/mreact-server": "0.0.
|
|
116
|
-
"@reckona/mreact-shared": "0.0.
|
|
108
|
+
"@reckona/mreact": "0.0.153",
|
|
109
|
+
"@reckona/mreact-compat": "0.0.153",
|
|
110
|
+
"@reckona/mreact-compiler": "0.0.153",
|
|
111
|
+
"@reckona/mreact-devtools": "0.0.153",
|
|
112
|
+
"@reckona/mreact-query": "0.0.153",
|
|
113
|
+
"@reckona/mreact-reactive-core": "0.0.153",
|
|
114
|
+
"@reckona/mreact-reactive-dom": "0.0.153",
|
|
115
|
+
"@reckona/mreact-server": "0.0.153",
|
|
116
|
+
"@reckona/mreact-shared": "0.0.153"
|
|
117
117
|
},
|
|
118
118
|
"peerDependencies": {
|
|
119
119
|
"vite": ">=8 <9"
|
|
120
120
|
},
|
|
121
121
|
"optionalDependencies": {
|
|
122
|
-
"@reckona/mreact-router-native": "0.0.
|
|
122
|
+
"@reckona/mreact-router-native": "0.0.153"
|
|
123
123
|
}
|
|
124
124
|
}
|
package/src/actions.ts
CHANGED
|
@@ -67,6 +67,11 @@ const DEFAULT_ACTION_BODY_MAX_BYTES = 10 * 1024 * 1024;
|
|
|
67
67
|
const DEFAULT_ACTION_FORM_MAX_FIELDS = 1_000;
|
|
68
68
|
let warnedUnrestrictedServerActions = false;
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Request context passed to authorized server actions.
|
|
72
|
+
*
|
|
73
|
+
* It exposes normalized cookies, headers, the original `Request`, and an optional client IP so authorization hooks can make request-aware decisions.
|
|
74
|
+
*/
|
|
70
75
|
export interface ServerActionContext {
|
|
71
76
|
clientIp?: string | undefined;
|
|
72
77
|
cookies: RequestCookies;
|
|
@@ -145,6 +150,11 @@ export function __readDefaultReplayStore(): BoundedReplayStore {
|
|
|
145
150
|
return usedFormActionNonces;
|
|
146
151
|
}
|
|
147
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Configures app-router server action dispatch, authorization, body limits, and replay protection.
|
|
155
|
+
*
|
|
156
|
+
* Production multi-instance deployments should provide a shared `replayStore` and a stable `MREACT_SERVER_ACTION_SECRET`.
|
|
157
|
+
*/
|
|
148
158
|
export interface AppRouterServerActionOptions {
|
|
149
159
|
allowedActions?: readonly AppRouterAllowedServerAction[] | "any" | undefined;
|
|
150
160
|
authorize?: ServerActionHandlerOptions["authorize"] | undefined;
|
|
@@ -1208,6 +1218,10 @@ async function collectFiles(directory: string): Promise<string[]> {
|
|
|
1208
1218
|
const path = join(directory, entry.name);
|
|
1209
1219
|
|
|
1210
1220
|
if (entry.isDirectory()) {
|
|
1221
|
+
if (shouldSkipServerActionScanDirectory(entry.name)) {
|
|
1222
|
+
continue;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1211
1225
|
files.push(...(await collectFiles(path)));
|
|
1212
1226
|
continue;
|
|
1213
1227
|
}
|
|
@@ -1220,6 +1234,10 @@ async function collectFiles(directory: string): Promise<string[]> {
|
|
|
1220
1234
|
return files;
|
|
1221
1235
|
}
|
|
1222
1236
|
|
|
1237
|
+
function shouldSkipServerActionScanDirectory(name: string): boolean {
|
|
1238
|
+
return name === "node_modules" || name === "__tests__" || name.startsWith(".");
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1223
1241
|
async function resolveSourceFile(directory: string, source: string): Promise<string | undefined> {
|
|
1224
1242
|
const base = join(directory, source);
|
|
1225
1243
|
const tsEsmBase = /\.[cm]?js$/.test(base) ? base.replace(/\.[cm]?js$/, "") : undefined;
|
|
@@ -127,6 +127,11 @@ export type AwsLambdaStreamingRequestHandler<TContext = unknown> = (
|
|
|
127
127
|
context: TContext,
|
|
128
128
|
) => Promise<void>;
|
|
129
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Creates a buffered AWS Lambda HTTP API v2 handler for built app-router output.
|
|
132
|
+
*
|
|
133
|
+
* The handler materializes runtime files under `/tmp` by default, starts middleware-focused background preload, applies the generated import policy when requested, and returns API Gateway v2 response objects.
|
|
134
|
+
*/
|
|
130
135
|
export function createAwsLambdaRequestHandler(
|
|
131
136
|
options: AwsLambdaRequestHandlerOptions,
|
|
132
137
|
): AwsLambdaRequestHandler {
|
|
@@ -147,6 +152,11 @@ export function createAwsLambdaRequestHandler(
|
|
|
147
152
|
);
|
|
148
153
|
}
|
|
149
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Creates a buffered AWS Lambda handler after eagerly preparing and preloading the built runtime.
|
|
157
|
+
*
|
|
158
|
+
* Use this when startup code can await preload work before the first request instead of letting the first invocation share that cost.
|
|
159
|
+
*/
|
|
150
160
|
export async function createPreloadedAwsLambdaRequestHandler(
|
|
151
161
|
options: AwsLambdaRequestHandlerOptions,
|
|
152
162
|
): Promise<AwsLambdaRequestHandler> {
|
|
@@ -249,6 +259,11 @@ function createAwsLambdaRequestHandlerFromRuntime(
|
|
|
249
259
|
};
|
|
250
260
|
}
|
|
251
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Creates an AWS Lambda streaming response handler for built app-router output.
|
|
264
|
+
*
|
|
265
|
+
* Use this with Lambda response streaming runtimes when HTML or route responses should be written progressively instead of buffered into an API Gateway result.
|
|
266
|
+
*/
|
|
252
267
|
export function createAwsLambdaStreamingRequestHandler<TContext = unknown>(
|
|
253
268
|
options: AwsLambdaRequestHandlerOptions,
|
|
254
269
|
): AwsLambdaStreamingRequestHandler<TContext> {
|
|
@@ -271,6 +286,9 @@ export function createAwsLambdaStreamingRequestHandler<TContext = unknown>(
|
|
|
271
286
|
);
|
|
272
287
|
}
|
|
273
288
|
|
|
289
|
+
/**
|
|
290
|
+
* Creates a streaming AWS Lambda handler after eagerly preparing and preloading the built runtime.
|
|
291
|
+
*/
|
|
274
292
|
export async function createPreloadedAwsLambdaStreamingRequestHandler<TContext = unknown>(
|
|
275
293
|
options: AwsLambdaRequestHandlerOptions,
|
|
276
294
|
): Promise<AwsLambdaStreamingRequestHandler<TContext>> {
|
|
@@ -239,6 +239,11 @@ const clientPrefix = "/_mreact/client/";
|
|
|
239
239
|
const defaultPrerenderCacheOrigin = "https://mreact.local";
|
|
240
240
|
const defaultPrerenderCachePrefix = "/_mreact/prerender";
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Creates a Cloudflare Worker `fetch` handler from manifests, asset loading, and an optional renderer.
|
|
244
|
+
*
|
|
245
|
+
* The handler serves generated client assets and prerendered routes before calling `render`, preserves streamed HTML responses, and routes errors through `onError` when provided.
|
|
246
|
+
*/
|
|
242
247
|
export function createCloudflareRequestHandler<Env = unknown>(
|
|
243
248
|
options: CloudflareRequestHandlerOptions<Env>,
|
|
244
249
|
): CloudflareRequestHandler<Env> {
|
|
@@ -276,6 +281,11 @@ export function createCloudflareRequestHandler<Env = unknown>(
|
|
|
276
281
|
};
|
|
277
282
|
}
|
|
278
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Creates a Cloudflare Worker handler that matches built app-router routes before rendering.
|
|
286
|
+
*
|
|
287
|
+
* Pair it with `createCloudflareRouteModuleRenderer()` and the generated route module registry from Cloudflare-target builds.
|
|
288
|
+
*/
|
|
279
289
|
export function createCloudflareBuiltRequestHandler<Env = unknown>(
|
|
280
290
|
options: CloudflareBuiltRequestHandlerOptions<Env>,
|
|
281
291
|
): CloudflareRequestHandler<Env> {
|
|
@@ -302,6 +312,11 @@ export function createCloudflareBuiltRequestHandler<Env = unknown>(
|
|
|
302
312
|
});
|
|
303
313
|
}
|
|
304
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Creates the renderer used by the generated Cloudflare Worker route registry.
|
|
317
|
+
*
|
|
318
|
+
* It loads matched route modules, dispatches server route handlers, evaluates loaders and metadata, and renders page routes with Cloudflare request context.
|
|
319
|
+
*/
|
|
305
320
|
export function createCloudflareRouteModuleRenderer<Env = unknown>(
|
|
306
321
|
options: CloudflareRouteModuleRendererOptions<Env>,
|
|
307
322
|
): NonNullable<CloudflareBuiltRequestHandlerOptions<Env>["renderRoute"]> {
|
|
@@ -723,6 +738,11 @@ function withDefaultSecurityHeaders(
|
|
|
723
738
|
});
|
|
724
739
|
}
|
|
725
740
|
|
|
741
|
+
/**
|
|
742
|
+
* Validates and normalizes a Vite `import.meta.glob` map into a Cloudflare route module registry.
|
|
743
|
+
*
|
|
744
|
+
* Every manifest route that needs a module must be present, and extra glob entries are rejected to catch stale generated workers.
|
|
745
|
+
*/
|
|
726
746
|
export function collectCloudflareRouteModules<Env = unknown>(
|
|
727
747
|
glob: CloudflareRouteModuleGlob<Env>,
|
|
728
748
|
options: CollectCloudflareRouteModulesOptions,
|
|
@@ -756,6 +776,11 @@ export function collectCloudflareRouteModules<Env = unknown>(
|
|
|
756
776
|
return modules;
|
|
757
777
|
}
|
|
758
778
|
|
|
779
|
+
/**
|
|
780
|
+
* Creates a Cloudflare asset loader that forwards only manifest-listed client and public asset paths.
|
|
781
|
+
*
|
|
782
|
+
* This keeps the Worker from passing arbitrary paths to the `ASSETS` binding while still serving generated route scripts, CSS, imports, source maps, and allowed public files.
|
|
783
|
+
*/
|
|
759
784
|
export function createCloudflareStaticAssetLoader<Env = unknown>(
|
|
760
785
|
options: CloudflareStaticAssetLoaderOptions<Env>,
|
|
761
786
|
): CloudflareAssetLoader<Env> {
|
|
@@ -787,6 +812,9 @@ export function createCloudflareStaticAssetLoader<Env = unknown>(
|
|
|
787
812
|
};
|
|
788
813
|
}
|
|
789
814
|
|
|
815
|
+
/**
|
|
816
|
+
* Returns the set of client and public asset paths a Cloudflare Worker is allowed to serve.
|
|
817
|
+
*/
|
|
790
818
|
export function cloudflareClientAssetPaths(
|
|
791
819
|
manifest: CloudflareClientManifest,
|
|
792
820
|
options: { extraPaths?: readonly string[] | undefined; prefix?: string | undefined } = {},
|
|
@@ -845,6 +873,11 @@ function safePublicAssetPath(asset: string): string | undefined {
|
|
|
845
873
|
return asset;
|
|
846
874
|
}
|
|
847
875
|
|
|
876
|
+
/**
|
|
877
|
+
* Creates an app-router prerender store backed by the Cloudflare Cache API.
|
|
878
|
+
*
|
|
879
|
+
* Keys are represented as synthetic requests so Workers cache entries can be shared by path and optional key prefix.
|
|
880
|
+
*/
|
|
848
881
|
export function createCloudflarePrerenderStore(
|
|
849
882
|
options: CloudflarePrerenderStoreOptions,
|
|
850
883
|
): AppRouterPrerenderStore {
|
package/src/adapters/edge.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface EdgeRequestHandlerOptions {
|
|
|
16
16
|
render: EdgeRequestHandler;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Wraps a Web `Request` renderer with edge-runtime logging and error handling.
|
|
21
|
+
*
|
|
22
|
+
* Use this for environments that already provide standard `Request` and `Response` objects and do not need Node or Cloudflare-specific adapters.
|
|
23
|
+
*/
|
|
19
24
|
export function createEdgeRequestHandler(options: EdgeRequestHandlerOptions): EdgeRequestHandler {
|
|
20
25
|
return async (request) => {
|
|
21
26
|
const startedAt = logNow();
|
package/src/adapters/node.ts
CHANGED
|
@@ -53,6 +53,11 @@ export type NodeRequestHandler = (
|
|
|
53
53
|
outgoing: ServerResponse,
|
|
54
54
|
) => Promise<void>;
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Creates a Node `IncomingMessage`/`ServerResponse` handler for built app-router output.
|
|
58
|
+
*
|
|
59
|
+
* The handler converts Node requests to Web `Request` objects, enforces configured host trust, applies the built renderer, and writes the Web `Response` back to the Node socket.
|
|
60
|
+
*/
|
|
56
61
|
export function createNodeRequestHandler(options: NodeRequestHandlerOptions): NodeRequestHandler {
|
|
57
62
|
warnIfImplicitHostTrust(options);
|
|
58
63
|
|
package/src/adapters/static.ts
CHANGED
|
@@ -12,6 +12,11 @@ export interface StaticExportResult {
|
|
|
12
12
|
routes: string[];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Exports prerendered app-router routes and client assets to a static filesystem directory.
|
|
17
|
+
*
|
|
18
|
+
* Only routes present in the built prerender manifest can be exported; the export directory is removed and recreated, and route paths are checked to prevent traversal outside it.
|
|
19
|
+
*/
|
|
15
20
|
export async function exportStaticApp(options: StaticExportOptions): Promise<StaticExportResult> {
|
|
16
21
|
const manifest = JSON.parse(
|
|
17
22
|
await readFile(join(options.outDir, "server", "manifest.json"), "utf8"),
|
package/src/build.ts
CHANGED
|
@@ -334,6 +334,11 @@ export interface BuiltPrerenderedRoute {
|
|
|
334
334
|
|
|
335
335
|
type StaticParams = Record<string, string | number | boolean | readonly string[]>;
|
|
336
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Builds an app-router project into server, client, and optional deployment-target artifacts.
|
|
339
|
+
*
|
|
340
|
+
* Use this from custom build scripts when the CLI is too coarse-grained; the returned manifest paths describe the files written under `outDir`. The build reads route files, loaders, middleware, metadata, server actions, and client references, so callers should pass the same project root and source allow-list they expect to deploy.
|
|
341
|
+
*/
|
|
337
342
|
export async function buildApp(options: BuildAppOptions): Promise<BuildAppResult> {
|
|
338
343
|
const timingSink = options.onBuildPhaseTiming;
|
|
339
344
|
const progressSink = options.onBuildProgress;
|
|
@@ -2134,6 +2139,10 @@ async function buildServerModuleArtifacts(options: {
|
|
|
2134
2139
|
filename: join(options.projectRoot, file),
|
|
2135
2140
|
moduleContextCache: options.clientRouteInferenceCache,
|
|
2136
2141
|
serverOutput,
|
|
2142
|
+
...(serverOutput === "stream" &&
|
|
2143
|
+
(routeAnalysis?.clientRoute ?? clientInference?.client) === true
|
|
2144
|
+
? { serverAwaitHydration: true as const }
|
|
2145
|
+
: {}),
|
|
2137
2146
|
});
|
|
2138
2147
|
const fatalDiagnostics = output.diagnostics.filter(
|
|
2139
2148
|
(diagnostic) => diagnostic.code !== "MR_UNSUPPORTED_SERVER_EVENT_HANDLER",
|
|
@@ -5612,6 +5621,11 @@ async function writeCloudflareWorkerArtifact(options: {
|
|
|
5612
5621
|
);
|
|
5613
5622
|
}
|
|
5614
5623
|
|
|
5624
|
+
/**
|
|
5625
|
+
* Packages a built app-router output directory into the minimal AWS Lambda artifact layout.
|
|
5626
|
+
*
|
|
5627
|
+
* The package contains `.mreact`, a Lambda handler, project package metadata, production dependencies, and `mreact-lambda-artifact.json`; it intentionally excludes source files and development tooling that are not needed at runtime.
|
|
5628
|
+
*/
|
|
5615
5629
|
export async function packageAwsLambdaArtifact(
|
|
5616
5630
|
options: PackageAwsLambdaArtifactOptions,
|
|
5617
5631
|
): Promise<AwsLambdaArtifactManifest> {
|
|
@@ -5719,6 +5733,11 @@ async function assertAwsLambdaRuntimeDependencies(outDir: string): Promise<void>
|
|
|
5719
5733
|
);
|
|
5720
5734
|
}
|
|
5721
5735
|
|
|
5736
|
+
/**
|
|
5737
|
+
* Packages a Cloudflare-target build for Cloudflare Pages advanced mode.
|
|
5738
|
+
*
|
|
5739
|
+
* The package writes `_worker.js`, generated client assets, public assets, and `mreact-cloudflare-pages-artifact.json`; deploy the output directory rather than the raw `.mreact` build tree.
|
|
5740
|
+
*/
|
|
5722
5741
|
export async function packageCloudflarePagesArtifact(
|
|
5723
5742
|
options: PackageCloudflarePagesArtifactOptions,
|
|
5724
5743
|
): Promise<CloudflarePagesArtifactManifest> {
|