@tanstack/router-core 1.171.14 → 1.171.16-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +3 -12
- package/dist/cjs/await-signal.cjs +21 -0
- package/dist/cjs/await-signal.cjs.map +1 -0
- package/dist/cjs/await-signal.d.cts +1 -0
- package/dist/cjs/index.cjs +3 -1
- package/dist/cjs/index.d.cts +3 -2
- package/dist/cjs/isServer/client.cjs +2 -0
- package/dist/cjs/isServer/client.cjs.map +1 -1
- package/dist/cjs/isServer/client.d.cts +1 -0
- package/dist/cjs/isServer/development.cjs +2 -0
- package/dist/cjs/isServer/development.cjs.map +1 -1
- package/dist/cjs/isServer/development.d.cts +1 -0
- package/dist/cjs/isServer/server.cjs +2 -0
- package/dist/cjs/isServer/server.cjs.map +1 -1
- package/dist/cjs/isServer/server.d.cts +1 -0
- package/dist/cjs/load-client.cjs +1470 -0
- package/dist/cjs/load-client.cjs.map +1 -0
- package/dist/cjs/load-client.d.cts +147 -0
- package/dist/cjs/load-server.cjs +565 -0
- package/dist/cjs/load-server.cjs.map +1 -0
- package/dist/cjs/load-server.d.cts +16 -0
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/redirect.d.cts +0 -1
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/router.cjs +187 -445
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +62 -52
- package/dist/cjs/scroll-restoration.cjs +27 -34
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/ssr/client.cjs +2 -2
- package/dist/cjs/ssr/createRequestHandler.cjs +60 -9
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/ssr/createRequestHandler.d.cts +1 -0
- package/dist/cjs/ssr/handlerCallback.cjs +49 -4
- package/dist/cjs/ssr/handlerCallback.cjs.map +1 -1
- package/dist/cjs/ssr/handlerCallback.d.cts +3 -0
- package/dist/cjs/ssr/server.cjs +4 -0
- package/dist/cjs/ssr/server.d.cts +2 -2
- package/dist/cjs/ssr/ssr-client.d.cts +1 -10
- package/dist/cjs/ssr/ssr-match-id.cjs +2 -2
- package/dist/cjs/ssr/ssr-match-id.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.cjs +6 -6
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/transformStreamWithRouter.cjs +27 -1
- package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
- package/dist/cjs/ssr/transformStreamWithRouter.d.cts +2 -0
- package/dist/cjs/ssr/types.d.cts +0 -1
- package/dist/cjs/stores.cjs +30 -104
- package/dist/cjs/stores.cjs.map +1 -1
- package/dist/cjs/stores.d.cts +7 -32
- package/dist/cjs/utils.cjs +0 -4
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/esm/Matches.d.ts +3 -12
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/await-signal.d.ts +1 -0
- package/dist/esm/await-signal.js +21 -0
- package/dist/esm/await-signal.js.map +1 -0
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +3 -2
- package/dist/esm/isServer/client.d.ts +1 -0
- package/dist/esm/isServer/client.js +2 -1
- package/dist/esm/isServer/client.js.map +1 -1
- package/dist/esm/isServer/development.d.ts +1 -0
- package/dist/esm/isServer/development.js +2 -1
- package/dist/esm/isServer/development.js.map +1 -1
- package/dist/esm/isServer/server.d.ts +1 -0
- package/dist/esm/isServer/server.js +2 -1
- package/dist/esm/isServer/server.js.map +1 -1
- package/dist/esm/load-client.d.ts +147 -0
- package/dist/esm/load-client.js +1462 -0
- package/dist/esm/load-client.js.map +1 -0
- package/dist/esm/load-server.d.ts +16 -0
- package/dist/esm/load-server.js +565 -0
- package/dist/esm/load-server.js.map +1 -0
- package/dist/esm/redirect.d.ts +0 -1
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +62 -52
- package/dist/esm/router.js +188 -446
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.js +27 -34
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/ssr/client.js +1 -1
- package/dist/esm/ssr/createRequestHandler.d.ts +1 -0
- package/dist/esm/ssr/createRequestHandler.js +61 -11
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- package/dist/esm/ssr/handlerCallback.d.ts +3 -0
- package/dist/esm/ssr/handlerCallback.js +47 -5
- package/dist/esm/ssr/handlerCallback.js.map +1 -1
- package/dist/esm/ssr/server.d.ts +2 -2
- package/dist/esm/ssr/server.js +3 -3
- package/dist/esm/ssr/ssr-client.d.ts +1 -10
- package/dist/esm/ssr/ssr-match-id.js +2 -2
- package/dist/esm/ssr/ssr-match-id.js.map +1 -1
- package/dist/esm/ssr/ssr-server.js +6 -6
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/transformStreamWithRouter.d.ts +2 -0
- package/dist/esm/ssr/transformStreamWithRouter.js +27 -1
- package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
- package/dist/esm/ssr/types.d.ts +0 -1
- package/dist/esm/stores.d.ts +7 -32
- package/dist/esm/stores.js +30 -104
- package/dist/esm/stores.js.map +1 -1
- package/dist/esm/utils.js +1 -4
- package/dist/esm/utils.js.map +1 -1
- package/package.json +3 -3
- package/src/Matches.ts +6 -21
- package/src/await-signal.ts +27 -0
- package/src/index.ts +1 -3
- package/src/isServer/client.ts +1 -0
- package/src/isServer/development.ts +1 -0
- package/src/isServer/server.ts +1 -0
- package/src/load-client.ts +2701 -0
- package/src/load-server.ts +849 -0
- package/src/redirect.ts +0 -1
- package/src/route.ts +2 -11
- package/src/router.ts +380 -774
- package/src/scroll-restoration.ts +40 -56
- package/src/ssr/createRequestHandler.ts +109 -16
- package/src/ssr/handlerCallback.ts +76 -10
- package/src/ssr/server.ts +4 -1
- package/src/ssr/ssr-client.ts +1 -310
- package/src/ssr/ssr-match-id.ts +11 -2
- package/src/ssr/ssr-server.ts +9 -8
- package/src/ssr/transformStreamWithRouter.ts +37 -1
- package/src/ssr/types.ts +0 -1
- package/src/stores.ts +46 -208
- package/dist/cjs/load-matches.cjs +0 -658
- package/dist/cjs/load-matches.cjs.map +0 -1
- package/dist/cjs/load-matches.d.cts +0 -18
- package/dist/cjs/ssr/ssr-client.cjs +0 -183
- package/dist/cjs/ssr/ssr-client.cjs.map +0 -1
- package/dist/esm/load-matches.d.ts +0 -18
- package/dist/esm/load-matches.js +0 -656
- package/dist/esm/load-matches.js.map +0 -1
- package/dist/esm/ssr/ssr-client.js +0 -183
- package/dist/esm/ssr/ssr-client.js.map +0 -1
- package/src/load-matches.ts +0 -1278
|
@@ -8,6 +8,26 @@ function normalizeSsrResponse(result) {
|
|
|
8
8
|
serverSsrCleanup: "none"
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
+
function disposeSsrResponse(response, reason) {
|
|
12
|
+
if (response.serverSsrCleanup !== "stream") return Promise.resolve();
|
|
13
|
+
try {
|
|
14
|
+
return Promise.resolve(response.dispose(reason));
|
|
15
|
+
} catch (error) {
|
|
16
|
+
return Promise.reject(error);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function disposeSsrResponseDetached(result, reason, onError = console.error) {
|
|
20
|
+
const ssrResponse = normalizeSsrResponse(result);
|
|
21
|
+
if (ssrResponse.serverSsrCleanup === "stream") {
|
|
22
|
+
disposeSsrResponse(ssrResponse, reason).catch(onError);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (ssrResponse.response.body) try {
|
|
26
|
+
ssrResponse.response.body.cancel(reason).catch(onError);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
onError(error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
11
31
|
function createSsrStreamResponse(router, response) {
|
|
12
32
|
if (!response.body) throw new Error("Invariant failed: SSR stream response requires a body");
|
|
13
33
|
let disposed = false;
|
|
@@ -17,16 +37,38 @@ function createSsrStreamResponse(router, response) {
|
|
|
17
37
|
async dispose(reason) {
|
|
18
38
|
if (disposed) return;
|
|
19
39
|
disposed = true;
|
|
40
|
+
router.serverSsr?.cleanup();
|
|
20
41
|
try {
|
|
21
42
|
await response.body.cancel(reason);
|
|
22
43
|
} catch {}
|
|
23
|
-
router.serverSsr?.cleanup();
|
|
24
44
|
}
|
|
25
45
|
};
|
|
26
46
|
}
|
|
27
|
-
|
|
47
|
+
function bindSsrResponseToRequest(router, result, signal) {
|
|
28
48
|
const ssrResponse = normalizeSsrResponse(result);
|
|
29
|
-
if (ssrResponse.serverSsrCleanup
|
|
49
|
+
if (ssrResponse.serverSsrCleanup !== "stream") {
|
|
50
|
+
if (signal.aborted) disposeSsrResponseDetached(result, signal.reason);
|
|
51
|
+
return ssrResponse;
|
|
52
|
+
}
|
|
53
|
+
const failed = (error) => {
|
|
54
|
+
router?.serverSsr?.cleanup();
|
|
55
|
+
console.error(error);
|
|
56
|
+
};
|
|
57
|
+
const abort = () => {
|
|
58
|
+
disposeSsrResponseDetached(ssrResponse, signal.reason, failed);
|
|
59
|
+
};
|
|
60
|
+
if (signal.aborted) {
|
|
61
|
+
abort();
|
|
62
|
+
return ssrResponse;
|
|
63
|
+
}
|
|
64
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
65
|
+
router?.serverSsr?.onCleanup(() => {
|
|
66
|
+
signal.removeEventListener("abort", abort);
|
|
67
|
+
});
|
|
68
|
+
return ssrResponse;
|
|
69
|
+
}
|
|
70
|
+
async function replaceSsrResponse(result, response, reason) {
|
|
71
|
+
await disposeSsrResponse(normalizeSsrResponse(result), reason);
|
|
30
72
|
return {
|
|
31
73
|
response,
|
|
32
74
|
serverSsrCleanup: "none"
|
|
@@ -34,7 +76,7 @@ async function replaceSsrResponse(result, response, reason) {
|
|
|
34
76
|
}
|
|
35
77
|
async function stripSsrResponseBody(result, reason) {
|
|
36
78
|
const ssrResponse = normalizeSsrResponse(result);
|
|
37
|
-
|
|
79
|
+
await disposeSsrResponse(ssrResponse, reason);
|
|
38
80
|
return {
|
|
39
81
|
response: new Response(null, ssrResponse.response),
|
|
40
82
|
serverSsrCleanup: "none"
|
|
@@ -44,8 +86,11 @@ function defineHandlerCallback(handler) {
|
|
|
44
86
|
return handler;
|
|
45
87
|
}
|
|
46
88
|
//#endregion
|
|
89
|
+
exports.bindSsrResponseToRequest = bindSsrResponseToRequest;
|
|
47
90
|
exports.createSsrStreamResponse = createSsrStreamResponse;
|
|
48
91
|
exports.defineHandlerCallback = defineHandlerCallback;
|
|
92
|
+
exports.disposeSsrResponse = disposeSsrResponse;
|
|
93
|
+
exports.disposeSsrResponseDetached = disposeSsrResponseDetached;
|
|
49
94
|
exports.isSsrResponse = isSsrResponse;
|
|
50
95
|
exports.normalizeSsrResponse = normalizeSsrResponse;
|
|
51
96
|
exports.replaceSsrResponse = replaceSsrResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlerCallback.cjs","names":[],"sources":["../../../src/ssr/handlerCallback.ts"],"sourcesContent":["import type { AnyRouter } from '../router'\n\nexport type SsrResponse =\n | {\n response: Response\n serverSsrCleanup: 'none'\n }\n | {\n response: Response\n serverSsrCleanup: 'stream'\n dispose: (reason?: unknown) => Promise<void>\n }\n\nexport type HandlerCallbackResult = Response | SsrResponse\n\nexport function isSsrResponse(value: unknown): value is SsrResponse {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'response' in value &&\n 'serverSsrCleanup' in value\n )\n}\n\nexport function normalizeSsrResponse(\n result: HandlerCallbackResult,\n): SsrResponse {\n return isSsrResponse(result)\n ? result\n : { response: result, serverSsrCleanup: 'none' }\n}\n\nexport function createSsrStreamResponse<TRouter extends AnyRouter>(\n router: TRouter,\n response: Response,\n): SsrResponse {\n if (!response.body) {\n throw new Error('Invariant failed: SSR stream response requires a body')\n }\n\n let disposed = false\n return {\n response,\n serverSsrCleanup: 'stream',\n async dispose(reason?: unknown) {\n if (disposed) return\n disposed = true\n\n try {\n await response.body!.cancel(reason)\n } catch {\n //
|
|
1
|
+
{"version":3,"file":"handlerCallback.cjs","names":[],"sources":["../../../src/ssr/handlerCallback.ts"],"sourcesContent":["import type { AnyRouter } from '../router'\n\nexport type SsrResponse =\n | {\n response: Response\n serverSsrCleanup: 'none'\n }\n | {\n response: Response\n serverSsrCleanup: 'stream'\n dispose: (reason?: unknown) => Promise<void>\n }\n\nexport type HandlerCallbackResult = Response | SsrResponse\n\nexport function isSsrResponse(value: unknown): value is SsrResponse {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'response' in value &&\n 'serverSsrCleanup' in value\n )\n}\n\nexport function normalizeSsrResponse(\n result: HandlerCallbackResult,\n): SsrResponse {\n return isSsrResponse(result)\n ? result\n : { response: result, serverSsrCleanup: 'none' }\n}\n\nexport function disposeSsrResponse(\n response: SsrResponse,\n reason?: unknown,\n): Promise<void> {\n if (response.serverSsrCleanup !== 'stream') {\n return Promise.resolve()\n }\n try {\n return Promise.resolve(response.dispose(reason))\n } catch (error) {\n return Promise.reject(error)\n }\n}\n\nexport function disposeSsrResponseDetached(\n result: HandlerCallbackResult,\n reason?: unknown,\n onError: (error: unknown) => void = console.error,\n): void {\n const ssrResponse = normalizeSsrResponse(result)\n if (ssrResponse.serverSsrCleanup === 'stream') {\n void disposeSsrResponse(ssrResponse, reason).catch(onError)\n return\n }\n\n if (ssrResponse.response.body) {\n try {\n void ssrResponse.response.body.cancel(reason).catch(onError)\n } catch (error) {\n onError(error)\n }\n }\n}\n\nexport function createSsrStreamResponse<TRouter extends AnyRouter>(\n router: TRouter,\n response: Response,\n): SsrResponse {\n if (!response.body) {\n throw new Error('Invariant failed: SSR stream response requires a body')\n }\n\n let disposed = false\n return {\n response,\n serverSsrCleanup: 'stream',\n async dispose(reason?: unknown) {\n if (disposed) {\n return\n }\n disposed = true\n\n // Sever router ownership before asking user/renderer stream machinery to\n // cancel. A custom stream is allowed to ignore cancellation forever.\n router.serverSsr?.cleanup()\n\n try {\n await response.body!.cancel(reason)\n } catch {\n // Cleanup above already released router SSR state.\n }\n },\n }\n}\n\nexport function bindSsrResponseToRequest(\n router: AnyRouter | undefined,\n result: HandlerCallbackResult,\n signal: AbortSignal,\n): SsrResponse {\n const ssrResponse = normalizeSsrResponse(result)\n if (ssrResponse.serverSsrCleanup !== 'stream') {\n if (signal.aborted) {\n disposeSsrResponseDetached(result, signal.reason)\n }\n return ssrResponse\n }\n\n const failed = (error: unknown) => {\n router?.serverSsr?.cleanup()\n console.error(error)\n }\n const abort = () => {\n disposeSsrResponseDetached(ssrResponse, signal.reason, failed)\n }\n if (signal.aborted) {\n abort()\n return ssrResponse\n }\n\n signal.addEventListener('abort', abort, { once: true })\n router?.serverSsr?.onCleanup(() => {\n signal.removeEventListener('abort', abort)\n })\n return ssrResponse\n}\n\nexport async function replaceSsrResponse(\n result: HandlerCallbackResult,\n response: Response,\n reason?: unknown,\n): Promise<SsrResponse> {\n const ssrResponse = normalizeSsrResponse(result)\n await disposeSsrResponse(ssrResponse, reason)\n return { response, serverSsrCleanup: 'none' }\n}\n\nexport async function stripSsrResponseBody(\n result: HandlerCallbackResult,\n reason?: unknown,\n): Promise<SsrResponse> {\n const ssrResponse = normalizeSsrResponse(result)\n await disposeSsrResponse(ssrResponse, reason)\n return {\n response: new Response(null, ssrResponse.response),\n serverSsrCleanup: 'none',\n }\n}\n\nexport interface HandlerCallback<TRouter extends AnyRouter> {\n (ctx: {\n request: Request\n router: TRouter\n responseHeaders: Headers\n }): HandlerCallbackResult | Promise<HandlerCallbackResult>\n}\n\nexport function defineHandlerCallback<TRouter extends AnyRouter>(\n handler: HandlerCallback<TRouter>,\n): HandlerCallback<TRouter> {\n return handler\n}\n"],"mappings":";AAeA,SAAgB,cAAc,OAAsC;CAClE,OACE,OAAO,UAAU,YACjB,UAAU,QACV,cAAc,SACd,sBAAsB;AAE1B;AAEA,SAAgB,qBACd,QACa;CACb,OAAO,cAAc,MAAM,IACvB,SACA;EAAE,UAAU;EAAQ,kBAAkB;CAAO;AACnD;AAEA,SAAgB,mBACd,UACA,QACe;CACf,IAAI,SAAS,qBAAqB,UAChC,OAAO,QAAQ,QAAQ;CAEzB,IAAI;EACF,OAAO,QAAQ,QAAQ,SAAS,QAAQ,MAAM,CAAC;CACjD,SAAS,OAAO;EACd,OAAO,QAAQ,OAAO,KAAK;CAC7B;AACF;AAEA,SAAgB,2BACd,QACA,QACA,UAAoC,QAAQ,OACtC;CACN,MAAM,cAAc,qBAAqB,MAAM;CAC/C,IAAI,YAAY,qBAAqB,UAAU;EAC7C,mBAAwB,aAAa,MAAM,EAAE,MAAM,OAAO;EAC1D;CACF;CAEA,IAAI,YAAY,SAAS,MACvB,IAAI;EACF,YAAiB,SAAS,KAAK,OAAO,MAAM,EAAE,MAAM,OAAO;CAC7D,SAAS,OAAO;EACd,QAAQ,KAAK;CACf;AAEJ;AAEA,SAAgB,wBACd,QACA,UACa;CACb,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,uDAAuD;CAGzE,IAAI,WAAW;CACf,OAAO;EACL;EACA,kBAAkB;EAClB,MAAM,QAAQ,QAAkB;GAC9B,IAAI,UACF;GAEF,WAAW;GAIX,OAAO,WAAW,QAAQ;GAE1B,IAAI;IACF,MAAM,SAAS,KAAM,OAAO,MAAM;GACpC,QAAQ,CAER;EACF;CACF;AACF;AAEA,SAAgB,yBACd,QACA,QACA,QACa;CACb,MAAM,cAAc,qBAAqB,MAAM;CAC/C,IAAI,YAAY,qBAAqB,UAAU;EAC7C,IAAI,OAAO,SACT,2BAA2B,QAAQ,OAAO,MAAM;EAElD,OAAO;CACT;CAEA,MAAM,UAAU,UAAmB;EACjC,QAAQ,WAAW,QAAQ;EAC3B,QAAQ,MAAM,KAAK;CACrB;CACA,MAAM,cAAc;EAClB,2BAA2B,aAAa,OAAO,QAAQ,MAAM;CAC/D;CACA,IAAI,OAAO,SAAS;EAClB,MAAM;EACN,OAAO;CACT;CAEA,OAAO,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;CACtD,QAAQ,WAAW,gBAAgB;EACjC,OAAO,oBAAoB,SAAS,KAAK;CAC3C,CAAC;CACD,OAAO;AACT;AAEA,eAAsB,mBACpB,QACA,UACA,QACsB;CAEtB,MAAM,mBADc,qBAAqB,MAChB,GAAa,MAAM;CAC5C,OAAO;EAAE;EAAU,kBAAkB;CAAO;AAC9C;AAEA,eAAsB,qBACpB,QACA,QACsB;CACtB,MAAM,cAAc,qBAAqB,MAAM;CAC/C,MAAM,mBAAmB,aAAa,MAAM;CAC5C,OAAO;EACL,UAAU,IAAI,SAAS,MAAM,YAAY,QAAQ;EACjD,kBAAkB;CACpB;AACF;AAUA,SAAgB,sBACd,SAC0B;CAC1B,OAAO;AACT"}
|
|
@@ -10,7 +10,10 @@ export type SsrResponse = {
|
|
|
10
10
|
export type HandlerCallbackResult = Response | SsrResponse;
|
|
11
11
|
export declare function isSsrResponse(value: unknown): value is SsrResponse;
|
|
12
12
|
export declare function normalizeSsrResponse(result: HandlerCallbackResult): SsrResponse;
|
|
13
|
+
export declare function disposeSsrResponse(response: SsrResponse, reason?: unknown): Promise<void>;
|
|
14
|
+
export declare function disposeSsrResponseDetached(result: HandlerCallbackResult, reason?: unknown, onError?: (error: unknown) => void): void;
|
|
13
15
|
export declare function createSsrStreamResponse<TRouter extends AnyRouter>(router: TRouter, response: Response): SsrResponse;
|
|
16
|
+
export declare function bindSsrResponseToRequest(router: AnyRouter | undefined, result: HandlerCallbackResult, signal: AbortSignal): SsrResponse;
|
|
14
17
|
export declare function replaceSsrResponse(result: HandlerCallbackResult, response: Response, reason?: unknown): Promise<SsrResponse>;
|
|
15
18
|
export declare function stripSsrResponseBody(result: HandlerCallbackResult, reason?: unknown): Promise<SsrResponse>;
|
|
16
19
|
export interface HandlerCallback<TRouter extends AnyRouter> {
|
package/dist/cjs/ssr/server.cjs
CHANGED
|
@@ -4,9 +4,12 @@ const require_handlerCallback = require("./handlerCallback.cjs");
|
|
|
4
4
|
const require_createRequestHandler = require("./createRequestHandler.cjs");
|
|
5
5
|
const require_transformStreamWithRouter = require("./transformStreamWithRouter.cjs");
|
|
6
6
|
exports.attachRouterServerSsrUtils = require_ssr_server.attachRouterServerSsrUtils;
|
|
7
|
+
exports.bindSsrResponseToRequest = require_handlerCallback.bindSsrResponseToRequest;
|
|
7
8
|
exports.createRequestHandler = require_createRequestHandler.createRequestHandler;
|
|
8
9
|
exports.createSsrStreamResponse = require_handlerCallback.createSsrStreamResponse;
|
|
9
10
|
exports.defineHandlerCallback = require_handlerCallback.defineHandlerCallback;
|
|
11
|
+
exports.disposeSsrResponse = require_handlerCallback.disposeSsrResponse;
|
|
12
|
+
exports.disposeSsrResponseDetached = require_handlerCallback.disposeSsrResponseDetached;
|
|
10
13
|
exports.getNormalizedURL = require_ssr_server.getNormalizedURL;
|
|
11
14
|
exports.getOrigin = require_ssr_server.getOrigin;
|
|
12
15
|
exports.isSsrResponse = require_handlerCallback.isSsrResponse;
|
|
@@ -16,3 +19,4 @@ exports.stripSsrResponseBody = require_handlerCallback.stripSsrResponseBody;
|
|
|
16
19
|
exports.transformPipeableStreamWithRouter = require_transformStreamWithRouter.transformPipeableStreamWithRouter;
|
|
17
20
|
exports.transformReadableStreamWithRouter = require_transformStreamWithRouter.transformReadableStreamWithRouter;
|
|
18
21
|
exports.transformStreamWithRouter = require_transformStreamWithRouter.transformStreamWithRouter;
|
|
22
|
+
exports.waitForRequest = require_createRequestHandler.waitForRequest;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { createRequestHandler } from './createRequestHandler.cjs';
|
|
1
|
+
export { createRequestHandler, waitForRequest } from './createRequestHandler.cjs';
|
|
2
2
|
export type { RequestHandler } from './createRequestHandler.cjs';
|
|
3
|
-
export { createSsrStreamResponse, defineHandlerCallback, isSsrResponse, normalizeSsrResponse, replaceSsrResponse, stripSsrResponseBody, } from './handlerCallback.cjs';
|
|
3
|
+
export { bindSsrResponseToRequest, createSsrStreamResponse, defineHandlerCallback, disposeSsrResponse, disposeSsrResponseDetached, isSsrResponse, normalizeSsrResponse, replaceSsrResponse, stripSsrResponseBody, } from './handlerCallback.cjs';
|
|
4
4
|
export type { HandlerCallback, HandlerCallbackResult, SsrResponse, } from './handlerCallback.cjs';
|
|
5
5
|
export { transformPipeableStreamWithRouter, transformStreamWithRouter, transformReadableStreamWithRouter, } from './transformStreamWithRouter.cjs';
|
|
6
6
|
export type { TransformStreamWithRouterOptions } from './transformStreamWithRouter.cjs';
|
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { TsrSsrGlobal } from './types.cjs';
|
|
3
|
-
import { AnyRouter } from '../router.cjs';
|
|
4
|
-
declare global {
|
|
5
|
-
interface Window {
|
|
6
|
-
[GLOBAL_TSR]?: TsrSsrGlobal;
|
|
7
|
-
[GLOBAL_SEROVAL]?: any;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
export declare function hydrate(router: AnyRouter): Promise<any>;
|
|
1
|
+
export { hydrate } from '../load-client.cjs';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
//#region src/ssr/ssr-match-id.ts
|
|
2
2
|
function dehydrateSsrMatchId(id) {
|
|
3
|
-
return id.replaceAll("/", "\0");
|
|
3
|
+
return id.replaceAll("~", "~~").replaceAll("\0", "~0").replaceAll("�", "~r").replaceAll("/", "\0");
|
|
4
4
|
}
|
|
5
5
|
function hydrateSsrMatchId(id) {
|
|
6
|
-
return id.replaceAll("\0", "/").replaceAll("�", "/");
|
|
6
|
+
return id.replaceAll("\0", "/").replaceAll("�", "/").replace(/~([~0r])/g, (_, code) => code === "0" ? "\0" : code === "r" ? "�" : code);
|
|
7
7
|
}
|
|
8
8
|
//#endregion
|
|
9
9
|
exports.dehydrateSsrMatchId = dehydrateSsrMatchId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-match-id.cjs","names":[],"sources":["../../../src/ssr/ssr-match-id.ts"],"sourcesContent":["export function dehydrateSsrMatchId(id: string): string {\n return id.replaceAll('/', '\\0')\n}\n\nexport function hydrateSsrMatchId(id: string): string {\n return id.replaceAll('\\0', '/').replaceAll('\\uFFFD', '/')\n}\n"],"mappings":";AAAA,SAAgB,oBAAoB,IAAoB;CACtD,OAAO,
|
|
1
|
+
{"version":3,"file":"ssr-match-id.cjs","names":[],"sources":["../../../src/ssr/ssr-match-id.ts"],"sourcesContent":["export function dehydrateSsrMatchId(id: string): string {\n return id\n .replaceAll('~', '~~')\n .replaceAll('\\0', '~0')\n .replaceAll('\\uFFFD', '~r')\n .replaceAll('/', '\\0')\n}\n\nexport function hydrateSsrMatchId(id: string): string {\n return id\n .replaceAll('\\0', '/')\n .replaceAll('\\uFFFD', '/')\n .replace(/~([~0r])/g, (_, code) =>\n code === '0' ? '\\0' : code === 'r' ? '\\uFFFD' : code,\n )\n}\n"],"mappings":";AAAA,SAAgB,oBAAoB,IAAoB;CACtD,OAAO,GACJ,WAAW,KAAK,IAAI,EACpB,WAAW,MAAM,IAAI,EACrB,WAAW,KAAU,IAAI,EACzB,WAAW,KAAK,IAAI;AACzB;AAEA,SAAgB,kBAAkB,IAAoB;CACpD,OAAO,GACJ,WAAW,MAAM,GAAG,EACpB,WAAW,KAAU,GAAG,EACxB,QAAQ,cAAc,GAAG,SACxB,SAAS,MAAM,OAAO,SAAS,MAAM,MAAW,IAClD;AACJ"}
|
|
@@ -2,11 +2,12 @@ const require_utils = require("../utils.cjs");
|
|
|
2
2
|
const require_invariant = require("../invariant.cjs");
|
|
3
3
|
const require_lru_cache = require("../lru-cache.cjs");
|
|
4
4
|
const require_root = require("../root.cjs");
|
|
5
|
+
const require_ssr_match_id = require("./ssr-match-id.cjs");
|
|
6
|
+
const require_load_client = require("../load-client.cjs");
|
|
5
7
|
const require_manifest = require("../manifest.cjs");
|
|
6
8
|
const require_constants = require("./constants.cjs");
|
|
7
9
|
const require_transformer = require("./serializer/transformer.cjs");
|
|
8
10
|
const require_seroval_plugins = require("./serializer/seroval-plugins.cjs");
|
|
9
|
-
const require_ssr_match_id = require("./ssr-match-id.cjs");
|
|
10
11
|
const require_tsrScript = require("./tsrScript.cjs");
|
|
11
12
|
let seroval = require("seroval");
|
|
12
13
|
//#region src/ssr/ssr-server.ts
|
|
@@ -26,7 +27,7 @@ function dehydrateMatch(match) {
|
|
|
26
27
|
["error", "e"],
|
|
27
28
|
["ssr", "ssr"]
|
|
28
29
|
]) if (match[key] !== void 0) dehydratedMatch[shorthand] = match[key];
|
|
29
|
-
if (match.
|
|
30
|
+
if (match._notFound) dehydratedMatch.g = true;
|
|
30
31
|
return dehydratedMatch;
|
|
31
32
|
}
|
|
32
33
|
const INITIAL_SCRIPTS = [(0, seroval.getCrossReferenceHeader)(SCOPE_ID), require_tsrScript.default];
|
|
@@ -223,7 +224,7 @@ function attachRouterServerSsrUtils({ router, manifest, getRequestAssets }) {
|
|
|
223
224
|
router.ssr = { get manifest() {
|
|
224
225
|
if (!manifest) return manifest;
|
|
225
226
|
const requestAssets = getRequestAssets?.();
|
|
226
|
-
const matches = router.stores.matches.get();
|
|
227
|
+
const matches = require_load_client._getRenderedMatches(router.stores.matches.get());
|
|
227
228
|
const hasAssets = hasRequestAssets(requestAssets);
|
|
228
229
|
if (!hasAssets && !manifest.inlineCss) return manifest;
|
|
229
230
|
let inlineCssAsset;
|
|
@@ -291,7 +292,7 @@ function attachRouterServerSsrUtils({ router, manifest, getRequestAssets }) {
|
|
|
291
292
|
if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: router is already dehydrated!");
|
|
292
293
|
require_invariant.invariant();
|
|
293
294
|
}
|
|
294
|
-
let matchesToDehydrate = router.stores.matches.get();
|
|
295
|
+
let matchesToDehydrate = require_load_client._getRenderedMatches(router.stores.matches.get());
|
|
295
296
|
if (router.isShell()) matchesToDehydrate = matchesToDehydrate.slice(0, 1);
|
|
296
297
|
const matches = matchesToDehydrate.map(dehydrateMatch);
|
|
297
298
|
let manifestToDehydrate = void 0;
|
|
@@ -316,9 +317,8 @@ function attachRouterServerSsrUtils({ router, manifest, getRequestAssets }) {
|
|
|
316
317
|
manifest: manifestToDehydrate,
|
|
317
318
|
matches
|
|
318
319
|
};
|
|
319
|
-
const lastMatchId = matchesToDehydrate[matchesToDehydrate.length - 1]?.id;
|
|
320
|
-
if (lastMatchId) dehydratedRouter.lastMatchId = require_ssr_match_id.dehydrateSsrMatchId(lastMatchId);
|
|
321
320
|
const dehydratedData = await router.options.dehydrate?.();
|
|
321
|
+
if (cleanupStarted) return;
|
|
322
322
|
if (dehydratedData) dehydratedRouter.dehydratedData = dehydratedData;
|
|
323
323
|
_dehydrated = true;
|
|
324
324
|
const trackPlugins = { didRun: false };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-server.cjs","names":[],"sources":["../../../src/ssr/ssr-server.ts"],"sourcesContent":["import { crossSerializeStream, getCrossReferenceHeader } from 'seroval'\nimport { invariant } from '../invariant'\nimport {\n createInlineCssPlaceholderAsset,\n createInlineCssStyleAsset,\n getStylesheetHref,\n} from '../manifest'\nimport { decodePath } from '../utils'\nimport { createLRUCache } from '../lru-cache'\nimport { rootRouteId } from '../root'\nimport minifiedTsrBootStrapScript from './tsrScript?script-string'\nimport { GLOBAL_TSR, TSR_SCRIPT_BARRIER_ID } from './constants'\nimport { dehydrateSsrMatchId } from './ssr-match-id'\nimport { defaultSerovalPlugins } from './serializer/seroval-plugins'\nimport { makeSsrSerovalPlugin } from './serializer/transformer'\nimport type { LRUCache } from '../lru-cache'\nimport type { DehydratedMatch, DehydratedRouter } from './types'\nimport type { AnySerializationAdapter } from './serializer/transformer'\nimport type { AnyRouter, ServerSsr } from '../router'\nimport type { AnyRouteMatch } from '../Matches'\nimport type {\n Manifest,\n ManifestRoute,\n ManifestRouteAssets,\n RouterManagedTag,\n ServerManifest,\n} from '../manifest'\n\nconst SCOPE_ID = 'tsr'\n\nconst TSR_PREFIX = GLOBAL_TSR + '.router='\nconst P_PREFIX = GLOBAL_TSR + '.p(()=>'\nconst P_SUFFIX = ')'\n\nexport function dehydrateMatch(match: AnyRouteMatch): DehydratedMatch {\n const dehydratedMatch: DehydratedMatch = {\n i: dehydrateSsrMatchId(match.id),\n u: match.updatedAt,\n s: match.status,\n }\n\n const properties = [\n ['__beforeLoadContext', 'b'],\n ['loaderData', 'l'],\n ['error', 'e'],\n ['ssr', 'ssr'],\n ] as const\n\n for (const [key, shorthand] of properties) {\n if (match[key] !== undefined) {\n dehydratedMatch[shorthand] = match[key]\n }\n }\n if (match.globalNotFound) {\n dehydratedMatch.g = true\n }\n return dehydratedMatch\n}\n\nconst INITIAL_SCRIPTS = [\n getCrossReferenceHeader(SCOPE_ID),\n minifiedTsrBootStrapScript,\n]\n\nclass ScriptBuffer {\n private injectScript: ((script: string) => void) | undefined\n private _queue: Array<string>\n private _scriptBarrierLifted = false\n private _cleanedUp = false\n private _microtaskVersion = 0\n private _pendingMicrotaskVersion = 0\n\n constructor(injectScript: (script: string) => void) {\n this.injectScript = injectScript\n // Copy INITIAL_SCRIPTS to avoid mutating the shared array\n this._queue = INITIAL_SCRIPTS.slice()\n }\n\n enqueue(script: string) {\n if (this._cleanedUp) return\n this._queue.push(script)\n if (this._scriptBarrierLifted) {\n this.scheduleInjectBufferedScripts()\n }\n }\n\n liftBarrier() {\n if (this._scriptBarrierLifted || this._cleanedUp) return\n this._scriptBarrierLifted = true\n if (this._queue.length > 0) {\n this.scheduleInjectBufferedScripts()\n }\n }\n\n scheduleInjectBufferedScripts() {\n if (this._pendingMicrotaskVersion !== 0) return\n const pendingVersion = ++this._microtaskVersion\n this._pendingMicrotaskVersion = pendingVersion\n queueMicrotask(() => {\n if (this._pendingMicrotaskVersion !== pendingVersion) return\n this._pendingMicrotaskVersion = 0\n this.injectBufferedScripts()\n })\n }\n\n clearPendingMicrotask() {\n if (this._pendingMicrotaskVersion === 0) return\n this._pendingMicrotaskVersion = 0\n this._microtaskVersion++\n }\n\n /**\n * Flushes any pending scripts synchronously.\n * Call this before signaling serialization finished to ensure all scripts are injected.\n *\n * IMPORTANT: Only injects if the barrier has been lifted. Before the barrier is lifted,\n * scripts should remain in the queue so takeBufferedScripts() can retrieve them\n */\n flush() {\n if (!this._scriptBarrierLifted) return\n if (this._cleanedUp) return\n this.clearPendingMicrotask()\n this.injectBufferedScripts()\n }\n\n takeAll() {\n return this.takeScripts(this._queue.length)\n }\n\n takeScripts(count: number) {\n if (count <= 0) return undefined\n const bufferedScripts = this._queue.splice(0, count)\n if (bufferedScripts.length === 0) {\n return undefined\n }\n // Optimization: if only one script, avoid join\n if (bufferedScripts.length === 1) {\n return bufferedScripts[0] + ';document.currentScript.remove()'\n }\n // Append cleanup script and join - avoid push() to not mutate then iterate\n return bufferedScripts.join(';') + ';document.currentScript.remove()'\n }\n\n hasPending() {\n return this._queue.length > 0\n }\n\n injectBufferedScripts() {\n if (this._cleanedUp) return\n // Early return if queue is empty (avoids unnecessary takeAll() call)\n if (this._queue.length === 0) return\n const scriptsToInject = this.takeAll()\n if (scriptsToInject) {\n this.injectScript?.(scriptsToInject)\n }\n }\n\n cleanup() {\n this._cleanedUp = true\n this.clearPendingMicrotask()\n this._queue = []\n this.injectScript = undefined\n }\n}\n\nconst isProd = process.env.NODE_ENV === 'production'\n\ntype FilteredRoutes = Manifest['routes']\n\ntype PreparedMatchedManifestRoutes = {\n routes: FilteredRoutes\n hasStrippedRoutes: boolean\n inlineCssHrefs?: Array<string>\n inlineCss?: string\n}\n\ntype ManifestLRU = LRUCache<string, PreparedMatchedManifestRoutes>\n\nconst MANIFEST_CACHE_SIZE = 100\nconst manifestCaches = new WeakMap<ServerManifest, ManifestLRU>()\n\nfunction getManifestCache(manifest: ServerManifest): ManifestLRU {\n const cache = manifestCaches.get(manifest)\n if (cache) return cache\n const newCache = createLRUCache<string, PreparedMatchedManifestRoutes>(\n MANIFEST_CACHE_SIZE,\n )\n manifestCaches.set(manifest, newCache)\n return newCache\n}\n\nfunction getInlineCssForPreparedRoutes(\n manifest: ServerManifest,\n preparedRoutes: PreparedMatchedManifestRoutes,\n) {\n if (preparedRoutes.inlineCss !== undefined) return preparedRoutes.inlineCss\n\n const styles = manifest.inlineCss?.styles\n const hrefs = preparedRoutes.inlineCssHrefs\n if (!styles || !hrefs?.length) return undefined\n\n let css = ''\n for (const href of hrefs) {\n css += styles[href]!\n }\n\n preparedRoutes.inlineCss = css\n return css\n}\n\nfunction getInlineCssAssetForPreparedRoutes(\n manifest: ServerManifest,\n preparedRoutes: PreparedMatchedManifestRoutes,\n) {\n const css = getInlineCssForPreparedRoutes(manifest, preparedRoutes)\n\n return css === undefined ? undefined : createInlineCssStyleAsset(css)\n}\n\nfunction getMatchedRoutesCacheKey(matches: Array<AnyRouteMatch>) {\n let cacheKey = ''\n for (let i = 0; i < matches.length; i++) {\n cacheKey += (i === 0 ? '' : '\\0') + matches[i]!.routeId\n }\n return cacheKey\n}\n\nfunction getPreparedMatchedManifestRoutes(\n manifest: ServerManifest,\n matches: Array<AnyRouteMatch>,\n cacheKey: string,\n) {\n if (isProd) {\n const cached = getManifestCache(manifest).get(cacheKey)\n if (cached) {\n return cached\n }\n }\n\n const preparedRoutes = prepareMatchedManifestRoutes(manifest, matches)\n\n if (isProd) {\n getManifestCache(manifest).set(cacheKey, preparedRoutes)\n }\n\n return preparedRoutes\n}\n\nfunction prepareMatchedManifestRoutes(\n manifest: ServerManifest,\n matches: Array<AnyRouteMatch>,\n): PreparedMatchedManifestRoutes {\n const inlineStyles = manifest.inlineCss?.styles\n const routes: FilteredRoutes = {}\n\n if (!inlineStyles) {\n for (const match of matches) {\n const route = manifest.routes[match.routeId]\n if (route) {\n routes[match.routeId] = route\n }\n }\n return { routes, hasStrippedRoutes: false }\n }\n\n const inlineCssHrefs: Array<string> = []\n const seenInlineCssHrefs = new Set<string>()\n let hasStrippedRoutes = false\n\n for (const match of matches) {\n const routeId = match.routeId\n const route = manifest.routes[routeId]\n if (!route) {\n continue\n }\n\n const nextRoute = stripInlinedStylesheetAssetsFromRoute(\n inlineStyles,\n route,\n inlineCssHrefs,\n seenInlineCssHrefs,\n )\n\n if (nextRoute !== route) {\n hasStrippedRoutes = true\n }\n routes[routeId] = nextRoute\n }\n\n return {\n routes,\n hasStrippedRoutes,\n ...(inlineCssHrefs.length ? { inlineCssHrefs } : {}),\n }\n}\n\nfunction stripInlinedStylesheetAssetsFromRoute(\n inlineStyles: Record<string, string>,\n route: ManifestRoute,\n inlineCssHrefs: Array<string>,\n seenInlineCssHrefs: Set<string>,\n): ManifestRoute {\n const css = route.css\n if (!css) {\n return route\n }\n\n if (css.length === 0) {\n const nextRoute = { ...route }\n delete nextRoute.css\n return nextRoute\n }\n\n let cssLinks: typeof css | undefined\n for (let i = 0; i < css.length; i++) {\n const link = css[i]!\n const href = getStylesheetHref(link)\n if (inlineStyles[href] === undefined) {\n if (cssLinks) {\n cssLinks.push(link)\n }\n continue\n }\n\n if (!seenInlineCssHrefs.has(href)) {\n seenInlineCssHrefs.add(href)\n inlineCssHrefs.push(href)\n }\n\n if (!cssLinks) {\n cssLinks = css.slice(0, i)\n }\n }\n\n if (!cssLinks) {\n return route\n }\n\n if (cssLinks.length > 0) {\n return { ...route, css: cssLinks }\n }\n\n const nextRoute = { ...route }\n delete nextRoute.css\n return nextRoute\n}\n\nfunction hasRouteAssets(route: ManifestRoute) {\n return !!route.scripts?.length || !!route.css?.length\n}\n\nfunction hasRequestAssets(assets: ManifestRouteAssets | undefined) {\n return !!assets && (!!assets.preloads?.length || hasRouteAssets(assets))\n}\n\nfunction mergeRequestAssetsIntoRootRoute(\n rootRoute: ManifestRoute | undefined,\n requestAssets: ManifestRouteAssets | undefined,\n): ManifestRoute {\n const preloads = requestAssets?.preloads?.length\n ? [...requestAssets.preloads, ...(rootRoute?.preloads ?? [])]\n : rootRoute?.preloads\n const scripts = requestAssets?.scripts?.length\n ? [...requestAssets.scripts, ...(rootRoute?.scripts ?? [])]\n : rootRoute?.scripts\n const cssLinks = requestAssets?.css?.length\n ? [...requestAssets.css, ...(rootRoute?.css ?? [])]\n : rootRoute?.css\n\n return {\n ...(rootRoute ?? {}),\n ...(preloads?.length ? { preloads } : {}),\n ...(scripts?.length ? { scripts } : {}),\n ...(cssLinks?.length ? { css: cssLinks } : {}),\n }\n}\n\nexport function attachRouterServerSsrUtils({\n router,\n manifest,\n getRequestAssets,\n}: {\n router: AnyRouter\n manifest: ServerManifest | undefined\n getRequestAssets?: () => ManifestRouteAssets | undefined\n}) {\n router.ssr = {\n get manifest() {\n if (!manifest) return manifest\n\n const requestAssets = getRequestAssets?.()\n const matches = router.stores.matches.get()\n const hasAssets = hasRequestAssets(requestAssets)\n\n if (!hasAssets && !manifest.inlineCss) {\n return manifest\n }\n\n let inlineCssAsset: Manifest['inlineStyle'] | undefined\n let routes = manifest.routes\n if (manifest.inlineCss) {\n const cacheKey = getMatchedRoutesCacheKey(matches)\n const preparedManifest = getPreparedMatchedManifestRoutes(\n manifest,\n matches,\n cacheKey,\n )\n inlineCssAsset = getInlineCssAssetForPreparedRoutes(\n manifest,\n preparedManifest,\n )\n if (preparedManifest.hasStrippedRoutes) {\n routes = { ...manifest.routes, ...preparedManifest.routes }\n }\n }\n\n if (!hasAssets) {\n return {\n ...(manifest.scriptFormat\n ? { scriptFormat: manifest.scriptFormat }\n : {}),\n ...(inlineCssAsset ? { inlineStyle: inlineCssAsset } : {}),\n routes,\n }\n }\n\n const rootRoute = routes[rootRouteId]\n\n // Merge request-scoped assets into root route without mutating cached manifest\n return {\n ...(manifest.scriptFormat\n ? { scriptFormat: manifest.scriptFormat }\n : {}),\n ...(inlineCssAsset ? { inlineStyle: inlineCssAsset } : {}),\n routes: {\n ...routes,\n [rootRouteId]: mergeRequestAssetsIntoRootRoute(\n rootRoute,\n requestAssets,\n ),\n },\n }\n },\n }\n let _dehydrated = false\n let _serializationFinished = false\n let streamFastPathReserved = false\n const renderFinishedListeners: Array<() => void> = []\n const injectedHtmlListeners: Array<() => void> = []\n const serializationFinishedListeners: Array<() => void> = []\n const cleanupListeners: Array<() => void> = []\n let cleanupStarted = false\n let injectedHtmlBuffer = ''\n\n const callListeners = (listeners: Array<() => void>, errorPrefix: string) => {\n const snapshot = listeners.slice()\n for (const l of snapshot) {\n try {\n l()\n } catch (err) {\n console.error(`${errorPrefix}:`, err)\n }\n }\n }\n\n const removeListener = (\n listeners: Array<() => void>,\n listener: () => void,\n ) => {\n const index = listeners.indexOf(listener)\n if (index >= 0) listeners.splice(index, 1)\n }\n\n const scriptBuffer = new ScriptBuffer((script) => {\n serverSsr.injectScript(script)\n })\n\n const serverSsr: ServerSsr = {\n injectHtml: (html: string) => {\n if (!html || cleanupStarted) return\n // Buffer the HTML so it can be retrieved via takeBufferedHtml()\n injectedHtmlBuffer += html\n callListeners(injectedHtmlListeners, 'SSR injected HTML listener error')\n },\n injectScript: (script: string) => {\n if (!script || cleanupStarted) return\n const html = `<script${router.options.ssr?.nonce ? ` nonce='${router.options.ssr.nonce}'` : ''}>${script}</script>`\n serverSsr.injectHtml(html)\n },\n dehydrate: async (opts?: { requestAssets?: ManifestRouteAssets }) => {\n if (_dehydrated) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: router is already dehydrated!')\n }\n\n invariant()\n }\n let matchesToDehydrate = router.stores.matches.get()\n if (router.isShell()) {\n // In SPA mode we only want to dehydrate the root match\n matchesToDehydrate = matchesToDehydrate.slice(0, 1)\n }\n const matches = matchesToDehydrate.map(dehydrateMatch)\n\n let manifestToDehydrate: Manifest | undefined = undefined\n // Only currently matched routes are dehydrated. Other route assets are\n // loaded through dynamic imports when those routes become active.\n if (manifest) {\n const cacheKey = getMatchedRoutesCacheKey(matchesToDehydrate)\n const preparedManifest = getPreparedMatchedManifestRoutes(\n manifest,\n matchesToDehydrate,\n cacheKey,\n )\n\n manifestToDehydrate = {\n ...(manifest.scriptFormat\n ? { scriptFormat: manifest.scriptFormat }\n : {}),\n ...(preparedManifest.inlineCssHrefs\n ? { inlineStyle: createInlineCssPlaceholderAsset() }\n : {}),\n routes: preparedManifest.routes,\n }\n\n // Merge request-scoped assets into root route (without mutating cached manifest)\n const requestAssets = opts?.requestAssets\n if (hasRequestAssets(requestAssets)) {\n const existingRoot = manifestToDehydrate.routes[rootRouteId]\n manifestToDehydrate.routes = {\n ...manifestToDehydrate.routes,\n [rootRouteId]: mergeRequestAssetsIntoRootRoute(\n existingRoot,\n requestAssets,\n ),\n }\n }\n }\n const dehydratedRouter: DehydratedRouter = {\n manifest: manifestToDehydrate,\n matches,\n }\n const lastMatchId = matchesToDehydrate[matchesToDehydrate.length - 1]?.id\n if (lastMatchId) {\n dehydratedRouter.lastMatchId = dehydrateSsrMatchId(lastMatchId)\n }\n const dehydratedData = await router.options.dehydrate?.()\n if (dehydratedData) {\n dehydratedRouter.dehydratedData = dehydratedData\n }\n _dehydrated = true\n\n const trackPlugins = { didRun: false }\n const serializationAdapters = router.options.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n const plugins = serializationAdapters\n ? serializationAdapters\n .map((t) => makeSsrSerovalPlugin(t, trackPlugins))\n .concat(defaultSerovalPlugins)\n : defaultSerovalPlugins\n\n let serializationCompleteSignaled = false\n const signalSerializationComplete = () => {\n if (serializationCompleteSignaled || cleanupStarted) return\n serializationCompleteSignaled = true\n _serializationFinished = true\n\n const listeners = serializationFinishedListeners.slice()\n serializationFinishedListeners.length = 0\n\n for (const l of listeners) {\n try {\n l()\n } catch (err) {\n console.error('Serialization listener error:', err)\n }\n }\n }\n\n const finishScriptSerialization = () => {\n if (serializationCompleteSignaled || cleanupStarted) return\n scriptBuffer.enqueue(GLOBAL_TSR + '.e()')\n // Must synchronously notify injected HTML listeners before signaling\n // completion; otherwise the held </body> tail could flush ahead of the\n // end script.\n scriptBuffer.flush()\n signalSerializationComplete()\n }\n\n crossSerializeStream(dehydratedRouter, {\n refs: new Map(),\n plugins,\n onSerialize: (data, initial) => {\n let serialized = initial ? TSR_PREFIX + data : data\n if (trackPlugins.didRun) {\n serialized = P_PREFIX + serialized + P_SUFFIX\n }\n scriptBuffer.enqueue(serialized)\n },\n onError: (err: unknown) => {\n console.error('Serialization error:', err)\n if (err && (err as any).stack) {\n console.error((err as any).stack)\n }\n finishScriptSerialization()\n },\n scopeId: SCOPE_ID,\n onDone: () => {\n finishScriptSerialization()\n },\n })\n },\n isDehydrated() {\n return _dehydrated\n },\n isSerializationFinished() {\n return _serializationFinished\n },\n reserveStreamFastPath() {\n if (\n !cleanupStarted &&\n _serializationFinished &&\n !streamFastPathReserved &&\n renderFinishedListeners.length === 0 &&\n !injectedHtmlBuffer &&\n !scriptBuffer.hasPending()\n ) {\n streamFastPathReserved = true\n return true\n }\n return false\n },\n onInjectedHtml: (listener) => {\n if (cleanupStarted) return () => {}\n injectedHtmlListeners.push(listener)\n return () => removeListener(injectedHtmlListeners, listener)\n },\n onRenderFinished: (listener) => {\n if (cleanupStarted || streamFastPathReserved) return\n renderFinishedListeners.push(listener)\n },\n onSerializationFinished: (listener) => {\n if (cleanupStarted) return () => {}\n if (_serializationFinished && !cleanupStarted) {\n try {\n listener()\n } catch (err) {\n console.error('Serialization listener error:', err)\n }\n return () => {}\n }\n serializationFinishedListeners.push(listener)\n return () => removeListener(serializationFinishedListeners, listener)\n },\n onCleanup: (listener) => {\n if (cleanupStarted) return\n cleanupListeners.push(listener)\n },\n setRenderFinished: () => {\n if (cleanupStarted) return\n scriptBuffer.liftBarrier()\n const listeners = renderFinishedListeners.slice()\n renderFinishedListeners.length = 0\n for (const l of listeners) {\n try {\n l()\n } catch (err) {\n console.error('Error in render finished listener:', err)\n }\n }\n if (_serializationFinished) {\n scriptBuffer.flush()\n }\n },\n takeBufferedScripts() {\n const scripts = scriptBuffer.takeAll()\n if (!scripts) return undefined\n const serverBufferedScript: RouterManagedTag = {\n tag: 'script',\n attrs: {\n nonce: router.options.ssr?.nonce,\n className: '$tsr',\n id: TSR_SCRIPT_BARRIER_ID,\n },\n children: scripts,\n }\n return serverBufferedScript\n },\n liftScriptBarrier() {\n scriptBuffer.liftBarrier()\n },\n takeBufferedHtml() {\n if (!injectedHtmlBuffer) {\n return undefined\n }\n const buffered = injectedHtmlBuffer\n injectedHtmlBuffer = ''\n return buffered\n },\n cleanup() {\n // Guard against multiple/reentrant cleanup calls. A listener could call\n // cleanup() again indirectly; snapshot + clear before invoking so each\n // listener runs exactly once and reentry is a no-op.\n if (cleanupStarted) return\n cleanupStarted = true\n const listeners = cleanupListeners.slice()\n cleanupListeners.length = 0\n for (const l of listeners) {\n try {\n l()\n } catch (err) {\n console.error('Error in SSR cleanup listener:', err)\n }\n }\n renderFinishedListeners.length = 0\n injectedHtmlListeners.length = 0\n serializationFinishedListeners.length = 0\n injectedHtmlBuffer = ''\n scriptBuffer.cleanup()\n router.serverSsr = undefined\n },\n }\n\n router.serverSsr = serverSsr\n for (const listener of router.serverSsrLifecycle?.onServerSsrAttach ?? []) {\n try {\n listener(serverSsr)\n } catch (err) {\n console.error('SSR attach listener error:', err)\n }\n }\n}\n\n/**\n * Get the origin for the request.\n *\n * SECURITY: We intentionally do NOT trust the Origin header for determining\n * the router's origin. The Origin header can be spoofed by attackers, which\n * could lead to SSRF-like vulnerabilities where redirects are constructed\n * using a malicious origin (CVE-2024-34351).\n *\n * Instead, we derive the origin from request.url, which is typically set by\n * the server infrastructure (not client-controlled headers).\n *\n * For applications behind proxies that need to trust forwarded headers,\n * use the router's `origin` option to explicitly configure a trusted origin.\n */\nexport function getOrigin(request: Request) {\n try {\n return new URL(request.url).origin\n } catch {}\n return 'http://localhost'\n}\n\n// server and browser can decode/encode characters differently in paths and search params.\n// Server generally strictly follows the WHATWG URL Standard, while browsers may differ for legacy reasons.\n// for example, in paths \"|\" is not encoded on the server but is encoded on chromium (and not on firefox) while \"대\" is encoded on both sides.\n// Another anomaly is that in Node new URLSearchParams and new URL also decode/encode characters differently.\n// new URLSearchParams() encodes \"|\" while new URL() does not, and in this instance\n// chromium treats search params differently than paths, i.e. \"|\" is not encoded in search params.\nexport function getNormalizedURL(url: string | URL, base?: string | URL) {\n // ensure backslashes are encoded correctly in the URL\n if (typeof url === 'string') url = url.replace('\\\\', '%5C')\n\n const rawUrl = new URL(url, base)\n const { path: decodedPathname, handledProtocolRelativeURL } = decodePath(\n rawUrl.pathname,\n )\n const searchParams = new URLSearchParams(rawUrl.search)\n const normalizedHref =\n decodedPathname +\n (searchParams.size > 0 ? '?' : '') +\n searchParams.toString() +\n rawUrl.hash\n\n return {\n url: new URL(normalizedHref, rawUrl.origin),\n handledProtocolRelativeURL,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ssr-server.cjs","names":[],"sources":["../../../src/ssr/ssr-server.ts"],"sourcesContent":["import { crossSerializeStream, getCrossReferenceHeader } from 'seroval'\nimport { invariant } from '../invariant'\nimport {\n createInlineCssPlaceholderAsset,\n createInlineCssStyleAsset,\n getStylesheetHref,\n} from '../manifest'\nimport { decodePath } from '../utils'\nimport { createLRUCache } from '../lru-cache'\nimport { rootRouteId } from '../root'\nimport { _getRenderedMatches } from '../load-client'\nimport minifiedTsrBootStrapScript from './tsrScript?script-string'\nimport { GLOBAL_TSR, TSR_SCRIPT_BARRIER_ID } from './constants'\nimport { dehydrateSsrMatchId } from './ssr-match-id'\nimport { defaultSerovalPlugins } from './serializer/seroval-plugins'\nimport { makeSsrSerovalPlugin } from './serializer/transformer'\nimport type { LRUCache } from '../lru-cache'\nimport type { DehydratedMatch, DehydratedRouter } from './types'\nimport type { AnySerializationAdapter } from './serializer/transformer'\nimport type { AnyRouter, ServerSsr } from '../router'\nimport type { AnyRouteMatch } from '../Matches'\nimport type {\n Manifest,\n ManifestRoute,\n ManifestRouteAssets,\n RouterManagedTag,\n ServerManifest,\n} from '../manifest'\n\nconst SCOPE_ID = 'tsr'\n\nconst TSR_PREFIX = GLOBAL_TSR + '.router='\nconst P_PREFIX = GLOBAL_TSR + '.p(()=>'\nconst P_SUFFIX = ')'\n\nexport function dehydrateMatch(match: AnyRouteMatch): DehydratedMatch {\n const dehydratedMatch: DehydratedMatch = {\n i: dehydrateSsrMatchId(match.id),\n u: match.updatedAt,\n s: match.status,\n }\n\n const properties = [\n ['__beforeLoadContext', 'b'],\n ['loaderData', 'l'],\n ['error', 'e'],\n ['ssr', 'ssr'],\n ] as const\n\n for (const [key, shorthand] of properties) {\n if (match[key] !== undefined) {\n dehydratedMatch[shorthand] = match[key]\n }\n }\n if (match._notFound) {\n dehydratedMatch.g = true\n }\n return dehydratedMatch\n}\n\nconst INITIAL_SCRIPTS = [\n getCrossReferenceHeader(SCOPE_ID),\n minifiedTsrBootStrapScript,\n]\n\nclass ScriptBuffer {\n private injectScript: ((script: string) => void) | undefined\n private _queue: Array<string>\n private _scriptBarrierLifted = false\n private _cleanedUp = false\n private _microtaskVersion = 0\n private _pendingMicrotaskVersion = 0\n\n constructor(injectScript: (script: string) => void) {\n this.injectScript = injectScript\n // Copy INITIAL_SCRIPTS to avoid mutating the shared array\n this._queue = INITIAL_SCRIPTS.slice()\n }\n\n enqueue(script: string) {\n if (this._cleanedUp) return\n this._queue.push(script)\n if (this._scriptBarrierLifted) {\n this.scheduleInjectBufferedScripts()\n }\n }\n\n liftBarrier() {\n if (this._scriptBarrierLifted || this._cleanedUp) return\n this._scriptBarrierLifted = true\n if (this._queue.length > 0) {\n this.scheduleInjectBufferedScripts()\n }\n }\n\n scheduleInjectBufferedScripts() {\n if (this._pendingMicrotaskVersion !== 0) return\n const pendingVersion = ++this._microtaskVersion\n this._pendingMicrotaskVersion = pendingVersion\n queueMicrotask(() => {\n if (this._pendingMicrotaskVersion !== pendingVersion) return\n this._pendingMicrotaskVersion = 0\n this.injectBufferedScripts()\n })\n }\n\n clearPendingMicrotask() {\n if (this._pendingMicrotaskVersion === 0) return\n this._pendingMicrotaskVersion = 0\n this._microtaskVersion++\n }\n\n /**\n * Flushes any pending scripts synchronously.\n * Call this before signaling serialization finished to ensure all scripts are injected.\n *\n * IMPORTANT: Only injects if the barrier has been lifted. Before the barrier is lifted,\n * scripts should remain in the queue so takeBufferedScripts() can retrieve them\n */\n flush() {\n if (!this._scriptBarrierLifted) return\n if (this._cleanedUp) return\n this.clearPendingMicrotask()\n this.injectBufferedScripts()\n }\n\n takeAll() {\n return this.takeScripts(this._queue.length)\n }\n\n takeScripts(count: number) {\n if (count <= 0) return undefined\n const bufferedScripts = this._queue.splice(0, count)\n if (bufferedScripts.length === 0) {\n return undefined\n }\n // Optimization: if only one script, avoid join\n if (bufferedScripts.length === 1) {\n return bufferedScripts[0] + ';document.currentScript.remove()'\n }\n // Append cleanup script and join - avoid push() to not mutate then iterate\n return bufferedScripts.join(';') + ';document.currentScript.remove()'\n }\n\n hasPending() {\n return this._queue.length > 0\n }\n\n injectBufferedScripts() {\n if (this._cleanedUp) return\n // Early return if queue is empty (avoids unnecessary takeAll() call)\n if (this._queue.length === 0) return\n const scriptsToInject = this.takeAll()\n if (scriptsToInject) {\n this.injectScript?.(scriptsToInject)\n }\n }\n\n cleanup() {\n this._cleanedUp = true\n this.clearPendingMicrotask()\n this._queue = []\n this.injectScript = undefined\n }\n}\n\nconst isProd = process.env.NODE_ENV === 'production'\n\ntype FilteredRoutes = Manifest['routes']\n\ntype PreparedMatchedManifestRoutes = {\n routes: FilteredRoutes\n hasStrippedRoutes: boolean\n inlineCssHrefs?: Array<string>\n inlineCss?: string\n}\n\ntype ManifestLRU = LRUCache<string, PreparedMatchedManifestRoutes>\n\nconst MANIFEST_CACHE_SIZE = 100\nconst manifestCaches = new WeakMap<ServerManifest, ManifestLRU>()\n\nfunction getManifestCache(manifest: ServerManifest): ManifestLRU {\n const cache = manifestCaches.get(manifest)\n if (cache) return cache\n const newCache = createLRUCache<string, PreparedMatchedManifestRoutes>(\n MANIFEST_CACHE_SIZE,\n )\n manifestCaches.set(manifest, newCache)\n return newCache\n}\n\nfunction getInlineCssForPreparedRoutes(\n manifest: ServerManifest,\n preparedRoutes: PreparedMatchedManifestRoutes,\n) {\n if (preparedRoutes.inlineCss !== undefined) return preparedRoutes.inlineCss\n\n const styles = manifest.inlineCss?.styles\n const hrefs = preparedRoutes.inlineCssHrefs\n if (!styles || !hrefs?.length) return undefined\n\n let css = ''\n for (const href of hrefs) {\n css += styles[href]!\n }\n\n preparedRoutes.inlineCss = css\n return css\n}\n\nfunction getInlineCssAssetForPreparedRoutes(\n manifest: ServerManifest,\n preparedRoutes: PreparedMatchedManifestRoutes,\n) {\n const css = getInlineCssForPreparedRoutes(manifest, preparedRoutes)\n\n return css === undefined ? undefined : createInlineCssStyleAsset(css)\n}\n\nfunction getMatchedRoutesCacheKey(matches: Array<AnyRouteMatch>) {\n let cacheKey = ''\n for (let i = 0; i < matches.length; i++) {\n cacheKey += (i === 0 ? '' : '\\0') + matches[i]!.routeId\n }\n return cacheKey\n}\n\nfunction getPreparedMatchedManifestRoutes(\n manifest: ServerManifest,\n matches: Array<AnyRouteMatch>,\n cacheKey: string,\n) {\n if (isProd) {\n const cached = getManifestCache(manifest).get(cacheKey)\n if (cached) {\n return cached\n }\n }\n\n const preparedRoutes = prepareMatchedManifestRoutes(manifest, matches)\n\n if (isProd) {\n getManifestCache(manifest).set(cacheKey, preparedRoutes)\n }\n\n return preparedRoutes\n}\n\nfunction prepareMatchedManifestRoutes(\n manifest: ServerManifest,\n matches: Array<AnyRouteMatch>,\n): PreparedMatchedManifestRoutes {\n const inlineStyles = manifest.inlineCss?.styles\n const routes: FilteredRoutes = {}\n\n if (!inlineStyles) {\n for (const match of matches) {\n const route = manifest.routes[match.routeId]\n if (route) {\n routes[match.routeId] = route\n }\n }\n return { routes, hasStrippedRoutes: false }\n }\n\n const inlineCssHrefs: Array<string> = []\n const seenInlineCssHrefs = new Set<string>()\n let hasStrippedRoutes = false\n\n for (const match of matches) {\n const routeId = match.routeId\n const route = manifest.routes[routeId]\n if (!route) {\n continue\n }\n\n const nextRoute = stripInlinedStylesheetAssetsFromRoute(\n inlineStyles,\n route,\n inlineCssHrefs,\n seenInlineCssHrefs,\n )\n\n if (nextRoute !== route) {\n hasStrippedRoutes = true\n }\n routes[routeId] = nextRoute\n }\n\n return {\n routes,\n hasStrippedRoutes,\n ...(inlineCssHrefs.length ? { inlineCssHrefs } : {}),\n }\n}\n\nfunction stripInlinedStylesheetAssetsFromRoute(\n inlineStyles: Record<string, string>,\n route: ManifestRoute,\n inlineCssHrefs: Array<string>,\n seenInlineCssHrefs: Set<string>,\n): ManifestRoute {\n const css = route.css\n if (!css) {\n return route\n }\n\n if (css.length === 0) {\n const nextRoute = { ...route }\n delete nextRoute.css\n return nextRoute\n }\n\n let cssLinks: typeof css | undefined\n for (let i = 0; i < css.length; i++) {\n const link = css[i]!\n const href = getStylesheetHref(link)\n if (inlineStyles[href] === undefined) {\n if (cssLinks) {\n cssLinks.push(link)\n }\n continue\n }\n\n if (!seenInlineCssHrefs.has(href)) {\n seenInlineCssHrefs.add(href)\n inlineCssHrefs.push(href)\n }\n\n if (!cssLinks) {\n cssLinks = css.slice(0, i)\n }\n }\n\n if (!cssLinks) {\n return route\n }\n\n if (cssLinks.length > 0) {\n return { ...route, css: cssLinks }\n }\n\n const nextRoute = { ...route }\n delete nextRoute.css\n return nextRoute\n}\n\nfunction hasRouteAssets(route: ManifestRoute) {\n return !!route.scripts?.length || !!route.css?.length\n}\n\nfunction hasRequestAssets(assets: ManifestRouteAssets | undefined) {\n return !!assets && (!!assets.preloads?.length || hasRouteAssets(assets))\n}\n\nfunction mergeRequestAssetsIntoRootRoute(\n rootRoute: ManifestRoute | undefined,\n requestAssets: ManifestRouteAssets | undefined,\n): ManifestRoute {\n const preloads = requestAssets?.preloads?.length\n ? [...requestAssets.preloads, ...(rootRoute?.preloads ?? [])]\n : rootRoute?.preloads\n const scripts = requestAssets?.scripts?.length\n ? [...requestAssets.scripts, ...(rootRoute?.scripts ?? [])]\n : rootRoute?.scripts\n const cssLinks = requestAssets?.css?.length\n ? [...requestAssets.css, ...(rootRoute?.css ?? [])]\n : rootRoute?.css\n\n return {\n ...(rootRoute ?? {}),\n ...(preloads?.length ? { preloads } : {}),\n ...(scripts?.length ? { scripts } : {}),\n ...(cssLinks?.length ? { css: cssLinks } : {}),\n }\n}\n\nexport function attachRouterServerSsrUtils({\n router,\n manifest,\n getRequestAssets,\n}: {\n router: AnyRouter\n manifest: ServerManifest | undefined\n getRequestAssets?: () => ManifestRouteAssets | undefined\n}) {\n router.ssr = {\n get manifest() {\n if (!manifest) return manifest\n\n const requestAssets = getRequestAssets?.()\n const matches = _getRenderedMatches(router.stores.matches.get())\n const hasAssets = hasRequestAssets(requestAssets)\n\n if (!hasAssets && !manifest.inlineCss) {\n return manifest\n }\n\n let inlineCssAsset: Manifest['inlineStyle'] | undefined\n let routes = manifest.routes\n if (manifest.inlineCss) {\n const cacheKey = getMatchedRoutesCacheKey(matches)\n const preparedManifest = getPreparedMatchedManifestRoutes(\n manifest,\n matches,\n cacheKey,\n )\n inlineCssAsset = getInlineCssAssetForPreparedRoutes(\n manifest,\n preparedManifest,\n )\n if (preparedManifest.hasStrippedRoutes) {\n routes = { ...manifest.routes, ...preparedManifest.routes }\n }\n }\n\n if (!hasAssets) {\n return {\n ...(manifest.scriptFormat\n ? { scriptFormat: manifest.scriptFormat }\n : {}),\n ...(inlineCssAsset ? { inlineStyle: inlineCssAsset } : {}),\n routes,\n }\n }\n\n const rootRoute = routes[rootRouteId]\n\n // Merge request-scoped assets into root route without mutating cached manifest\n return {\n ...(manifest.scriptFormat\n ? { scriptFormat: manifest.scriptFormat }\n : {}),\n ...(inlineCssAsset ? { inlineStyle: inlineCssAsset } : {}),\n routes: {\n ...routes,\n [rootRouteId]: mergeRequestAssetsIntoRootRoute(\n rootRoute,\n requestAssets,\n ),\n },\n }\n },\n }\n let _dehydrated = false\n let _serializationFinished = false\n let streamFastPathReserved = false\n const renderFinishedListeners: Array<() => void> = []\n const injectedHtmlListeners: Array<() => void> = []\n const serializationFinishedListeners: Array<() => void> = []\n const cleanupListeners: Array<() => void> = []\n let cleanupStarted = false\n let injectedHtmlBuffer = ''\n\n const callListeners = (listeners: Array<() => void>, errorPrefix: string) => {\n const snapshot = listeners.slice()\n for (const l of snapshot) {\n try {\n l()\n } catch (err) {\n console.error(`${errorPrefix}:`, err)\n }\n }\n }\n\n const removeListener = (\n listeners: Array<() => void>,\n listener: () => void,\n ) => {\n const index = listeners.indexOf(listener)\n if (index >= 0) listeners.splice(index, 1)\n }\n\n const scriptBuffer = new ScriptBuffer((script) => {\n serverSsr.injectScript(script)\n })\n\n const serverSsr: ServerSsr = {\n injectHtml: (html: string) => {\n if (!html || cleanupStarted) return\n // Buffer the HTML so it can be retrieved via takeBufferedHtml()\n injectedHtmlBuffer += html\n callListeners(injectedHtmlListeners, 'SSR injected HTML listener error')\n },\n injectScript: (script: string) => {\n if (!script || cleanupStarted) return\n const html = `<script${router.options.ssr?.nonce ? ` nonce='${router.options.ssr.nonce}'` : ''}>${script}</script>`\n serverSsr.injectHtml(html)\n },\n dehydrate: async (opts?: { requestAssets?: ManifestRouteAssets }) => {\n if (_dehydrated) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: router is already dehydrated!')\n }\n\n invariant()\n }\n let matchesToDehydrate = _getRenderedMatches(router.stores.matches.get())\n const isShell = router.isShell()\n if (isShell) {\n // In SPA mode we only want to dehydrate the root match\n matchesToDehydrate = matchesToDehydrate.slice(0, 1)\n }\n const matches = matchesToDehydrate.map(dehydrateMatch)\n\n let manifestToDehydrate: Manifest | undefined = undefined\n // Only currently matched routes are dehydrated. Other route assets are\n // loaded through dynamic imports when those routes become active.\n if (manifest) {\n const cacheKey = getMatchedRoutesCacheKey(matchesToDehydrate)\n const preparedManifest = getPreparedMatchedManifestRoutes(\n manifest,\n matchesToDehydrate,\n cacheKey,\n )\n\n manifestToDehydrate = {\n ...(manifest.scriptFormat\n ? { scriptFormat: manifest.scriptFormat }\n : {}),\n ...(preparedManifest.inlineCssHrefs\n ? { inlineStyle: createInlineCssPlaceholderAsset() }\n : {}),\n routes: preparedManifest.routes,\n }\n\n // Merge request-scoped assets into root route (without mutating cached manifest)\n const requestAssets = opts?.requestAssets\n if (hasRequestAssets(requestAssets)) {\n const existingRoot = manifestToDehydrate.routes[rootRouteId]\n manifestToDehydrate.routes = {\n ...manifestToDehydrate.routes,\n [rootRouteId]: mergeRequestAssetsIntoRootRoute(\n existingRoot,\n requestAssets,\n ),\n }\n }\n }\n const dehydratedRouter: DehydratedRouter = {\n manifest: manifestToDehydrate,\n matches,\n }\n const dehydratedData = await router.options.dehydrate?.()\n if (cleanupStarted) {\n return\n }\n if (dehydratedData) {\n dehydratedRouter.dehydratedData = dehydratedData\n }\n _dehydrated = true\n\n const trackPlugins = { didRun: false }\n const serializationAdapters = router.options.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n const plugins = serializationAdapters\n ? serializationAdapters\n .map((t) => makeSsrSerovalPlugin(t, trackPlugins))\n .concat(defaultSerovalPlugins)\n : defaultSerovalPlugins\n\n let serializationCompleteSignaled = false\n const signalSerializationComplete = () => {\n if (serializationCompleteSignaled || cleanupStarted) return\n serializationCompleteSignaled = true\n _serializationFinished = true\n\n const listeners = serializationFinishedListeners.slice()\n serializationFinishedListeners.length = 0\n\n for (const l of listeners) {\n try {\n l()\n } catch (err) {\n console.error('Serialization listener error:', err)\n }\n }\n }\n\n const finishScriptSerialization = () => {\n if (serializationCompleteSignaled || cleanupStarted) return\n scriptBuffer.enqueue(GLOBAL_TSR + '.e()')\n // Must synchronously notify injected HTML listeners before signaling\n // completion; otherwise the held </body> tail could flush ahead of the\n // end script.\n scriptBuffer.flush()\n signalSerializationComplete()\n }\n\n crossSerializeStream(dehydratedRouter, {\n refs: new Map(),\n plugins,\n onSerialize: (data, initial) => {\n let serialized = initial ? TSR_PREFIX + data : data\n if (trackPlugins.didRun) {\n serialized = P_PREFIX + serialized + P_SUFFIX\n }\n scriptBuffer.enqueue(serialized)\n },\n onError: (err: unknown) => {\n console.error('Serialization error:', err)\n if (err && (err as any).stack) {\n console.error((err as any).stack)\n }\n finishScriptSerialization()\n },\n scopeId: SCOPE_ID,\n onDone: () => {\n finishScriptSerialization()\n },\n })\n },\n isDehydrated() {\n return _dehydrated\n },\n isSerializationFinished() {\n return _serializationFinished\n },\n reserveStreamFastPath() {\n if (\n !cleanupStarted &&\n _serializationFinished &&\n !streamFastPathReserved &&\n renderFinishedListeners.length === 0 &&\n !injectedHtmlBuffer &&\n !scriptBuffer.hasPending()\n ) {\n streamFastPathReserved = true\n return true\n }\n return false\n },\n onInjectedHtml: (listener) => {\n if (cleanupStarted) return () => {}\n injectedHtmlListeners.push(listener)\n return () => removeListener(injectedHtmlListeners, listener)\n },\n onRenderFinished: (listener) => {\n if (cleanupStarted || streamFastPathReserved) return\n renderFinishedListeners.push(listener)\n },\n onSerializationFinished: (listener) => {\n if (cleanupStarted) return () => {}\n if (_serializationFinished && !cleanupStarted) {\n try {\n listener()\n } catch (err) {\n console.error('Serialization listener error:', err)\n }\n return () => {}\n }\n serializationFinishedListeners.push(listener)\n return () => removeListener(serializationFinishedListeners, listener)\n },\n onCleanup: (listener) => {\n if (cleanupStarted) return\n cleanupListeners.push(listener)\n },\n setRenderFinished: () => {\n if (cleanupStarted) return\n scriptBuffer.liftBarrier()\n const listeners = renderFinishedListeners.slice()\n renderFinishedListeners.length = 0\n for (const l of listeners) {\n try {\n l()\n } catch (err) {\n console.error('Error in render finished listener:', err)\n }\n }\n if (_serializationFinished) {\n scriptBuffer.flush()\n }\n },\n takeBufferedScripts() {\n const scripts = scriptBuffer.takeAll()\n if (!scripts) return undefined\n const serverBufferedScript: RouterManagedTag = {\n tag: 'script',\n attrs: {\n nonce: router.options.ssr?.nonce,\n className: '$tsr',\n id: TSR_SCRIPT_BARRIER_ID,\n },\n children: scripts,\n }\n return serverBufferedScript\n },\n liftScriptBarrier() {\n scriptBuffer.liftBarrier()\n },\n takeBufferedHtml() {\n if (!injectedHtmlBuffer) {\n return undefined\n }\n const buffered = injectedHtmlBuffer\n injectedHtmlBuffer = ''\n return buffered\n },\n cleanup() {\n // Guard against multiple/reentrant cleanup calls. A listener could call\n // cleanup() again indirectly; snapshot + clear before invoking so each\n // listener runs exactly once and reentry is a no-op.\n if (cleanupStarted) return\n cleanupStarted = true\n const listeners = cleanupListeners.slice()\n cleanupListeners.length = 0\n for (const l of listeners) {\n try {\n l()\n } catch (err) {\n console.error('Error in SSR cleanup listener:', err)\n }\n }\n renderFinishedListeners.length = 0\n injectedHtmlListeners.length = 0\n serializationFinishedListeners.length = 0\n injectedHtmlBuffer = ''\n scriptBuffer.cleanup()\n router.serverSsr = undefined\n },\n }\n\n router.serverSsr = serverSsr\n for (const listener of router.serverSsrLifecycle?.onServerSsrAttach ?? []) {\n try {\n listener(serverSsr)\n } catch (err) {\n console.error('SSR attach listener error:', err)\n }\n }\n}\n\n/**\n * Get the origin for the request.\n *\n * SECURITY: We intentionally do NOT trust the Origin header for determining\n * the router's origin. The Origin header can be spoofed by attackers, which\n * could lead to SSRF-like vulnerabilities where redirects are constructed\n * using a malicious origin (CVE-2024-34351).\n *\n * Instead, we derive the origin from request.url, which is typically set by\n * the server infrastructure (not client-controlled headers).\n *\n * For applications behind proxies that need to trust forwarded headers,\n * use the router's `origin` option to explicitly configure a trusted origin.\n */\nexport function getOrigin(request: Request) {\n try {\n return new URL(request.url).origin\n } catch {}\n return 'http://localhost'\n}\n\n// server and browser can decode/encode characters differently in paths and search params.\n// Server generally strictly follows the WHATWG URL Standard, while browsers may differ for legacy reasons.\n// for example, in paths \"|\" is not encoded on the server but is encoded on chromium (and not on firefox) while \"대\" is encoded on both sides.\n// Another anomaly is that in Node new URLSearchParams and new URL also decode/encode characters differently.\n// new URLSearchParams() encodes \"|\" while new URL() does not, and in this instance\n// chromium treats search params differently than paths, i.e. \"|\" is not encoded in search params.\nexport function getNormalizedURL(url: string | URL, base?: string | URL) {\n // ensure backslashes are encoded correctly in the URL\n if (typeof url === 'string') url = url.replace('\\\\', '%5C')\n\n const rawUrl = new URL(url, base)\n const { path: decodedPathname, handledProtocolRelativeURL } = decodePath(\n rawUrl.pathname,\n )\n const searchParams = new URLSearchParams(rawUrl.search)\n const normalizedHref =\n decodedPathname +\n (searchParams.size > 0 ? '?' : '') +\n searchParams.toString() +\n rawUrl.hash\n\n return {\n url: new URL(normalizedHref, rawUrl.origin),\n handledProtocolRelativeURL,\n }\n}\n"],"mappings":"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"}
|
|
@@ -99,6 +99,16 @@ function createAbortNotifier(opts) {
|
|
|
99
99
|
} catch {}
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
+
function listenToAbort(signal, onAbort) {
|
|
103
|
+
if (!signal) return;
|
|
104
|
+
if (signal.aborted) {
|
|
105
|
+
onAbort(signal.reason);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const listener = () => onAbort(signal.reason);
|
|
109
|
+
signal.addEventListener("abort", listener, { once: true });
|
|
110
|
+
return () => signal.removeEventListener("abort", listener);
|
|
111
|
+
}
|
|
102
112
|
function transformStreamWithRouter(router, appStream, opts) {
|
|
103
113
|
const serverSsr = router.serverSsr;
|
|
104
114
|
if (!serverSsr) throw new Error("Invariant failed: router.serverSsr is required");
|
|
@@ -110,6 +120,7 @@ function makeFastPathStream(appStream, opts, serverSsr) {
|
|
|
110
120
|
let controller;
|
|
111
121
|
let state = MergeState.ReadingBody;
|
|
112
122
|
let lifetimeTimeoutHandle;
|
|
123
|
+
let stopListeningToAbort;
|
|
113
124
|
let stopListeningToInjectedHtml;
|
|
114
125
|
const readerState = createReaderState(appStream);
|
|
115
126
|
const notifyAbort = createAbortNotifier(opts);
|
|
@@ -134,6 +145,8 @@ function makeFastPathStream(appStream, opts, serverSsr) {
|
|
|
134
145
|
clearTimeout(lifetimeTimeoutHandle);
|
|
135
146
|
lifetimeTimeoutHandle = void 0;
|
|
136
147
|
}
|
|
148
|
+
stopListeningToAbort?.();
|
|
149
|
+
stopListeningToAbort = void 0;
|
|
137
150
|
try {
|
|
138
151
|
stopListeningToInjectedHtml?.();
|
|
139
152
|
} catch {}
|
|
@@ -175,7 +188,7 @@ function makeFastPathStream(appStream, opts, serverSsr) {
|
|
|
175
188
|
cleanup(err);
|
|
176
189
|
}
|
|
177
190
|
}, lifetimeMs);
|
|
178
|
-
|
|
191
|
+
const stream = new node_stream_web.ReadableStream({
|
|
179
192
|
start(c) {
|
|
180
193
|
controller = c;
|
|
181
194
|
},
|
|
@@ -208,12 +221,18 @@ function makeFastPathStream(appStream, opts, serverSsr) {
|
|
|
208
221
|
return cleanup(reason);
|
|
209
222
|
}
|
|
210
223
|
});
|
|
224
|
+
stopListeningToAbort = listenToAbort(opts?.signal, (reason) => {
|
|
225
|
+
safeError(reason);
|
|
226
|
+
cleanup(reason);
|
|
227
|
+
});
|
|
228
|
+
return stream;
|
|
211
229
|
}
|
|
212
230
|
function makeMainStream(serverSsr, appStream, opts) {
|
|
213
231
|
let stopListeningToInjectedHtml;
|
|
214
232
|
let stopListeningToSerializationFinished;
|
|
215
233
|
let serializationTimeoutHandle;
|
|
216
234
|
let lifetimeTimeoutHandle;
|
|
235
|
+
let stopListeningToAbort;
|
|
217
236
|
let cleanedUp = false;
|
|
218
237
|
let controller;
|
|
219
238
|
let closeWhenDrained = false;
|
|
@@ -312,6 +331,8 @@ function makeMainStream(serverSsr, appStream, opts) {
|
|
|
312
331
|
} catch {}
|
|
313
332
|
stopListeningToInjectedHtml = void 0;
|
|
314
333
|
stopListeningToSerializationFinished = void 0;
|
|
334
|
+
stopListeningToAbort?.();
|
|
335
|
+
stopListeningToAbort = void 0;
|
|
315
336
|
if (serializationTimeoutHandle !== void 0) {
|
|
316
337
|
clearTimeout(serializationTimeoutHandle);
|
|
317
338
|
serializationTimeoutHandle = void 0;
|
|
@@ -496,6 +517,11 @@ function makeMainStream(serverSsr, appStream, opts) {
|
|
|
496
517
|
drainRouterHtml();
|
|
497
518
|
if (cleanedUp || isDone()) return stream;
|
|
498
519
|
}
|
|
520
|
+
stopListeningToAbort = listenToAbort(opts?.signal, (reason) => {
|
|
521
|
+
safeError(reason);
|
|
522
|
+
cleanup(reason);
|
|
523
|
+
});
|
|
524
|
+
if (cleanedUp || isDone()) return stream;
|
|
499
525
|
(async () => {
|
|
500
526
|
try {
|
|
501
527
|
while (true) {
|