@tanstack/start-server-core 1.169.4 → 1.169.6
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/esm/createStartHandler.js +75 -35
- package/dist/esm/createStartHandler.js.map +1 -1
- package/dist/esm/finalManifest.d.ts +5 -5
- package/dist/esm/finalManifest.js +2 -2
- package/dist/esm/finalManifest.js.map +1 -1
- package/dist/esm/router-manifest.d.ts +2 -6
- package/dist/esm/router-manifest.js +3 -9
- package/dist/esm/router-manifest.js.map +1 -1
- package/dist/esm/transformAssetUrls.d.ts +5 -14
- package/dist/esm/transformAssetUrls.js +10 -45
- package/dist/esm/transformAssetUrls.js.map +1 -1
- package/package.json +4 -4
- package/src/createStartHandler.ts +150 -57
- package/src/finalManifest.ts +10 -15
- package/src/router-manifest.ts +7 -10
- package/src/tanstack-start.d.ts +1 -1
- package/src/transformAssetUrls.ts +10 -88
|
@@ -8,7 +8,7 @@ import { ServerFunctionSerializationAdapter } from "./serializer/ServerFunctionS
|
|
|
8
8
|
import { createMemoryHistory } from "@tanstack/history";
|
|
9
9
|
import { createCsrfMiddleware, createNullProtoObject, csrfSymbol, flattenMiddlewares, mergeHeaders, safeObjectMerge } from "@tanstack/start-client-core";
|
|
10
10
|
import { executeRewriteInput, isRedirect, isResolvedRedirect } from "@tanstack/router-core";
|
|
11
|
-
import { attachRouterServerSsrUtils, getNormalizedURL, getOrigin } from "@tanstack/router-core/ssr/server";
|
|
11
|
+
import { attachRouterServerSsrUtils, getNormalizedURL, getOrigin, isSsrResponse, normalizeSsrResponse, replaceSsrResponse, stripSsrResponseBody } from "@tanstack/router-core/ssr/server";
|
|
12
12
|
import { getStartContext, runWithStartContext } from "@tanstack/start-storage-context";
|
|
13
13
|
//#region src/createStartHandler.ts
|
|
14
14
|
function getStartResponseHeaders(opts) {
|
|
@@ -90,18 +90,48 @@ function isSpecialResponse(value) {
|
|
|
90
90
|
* Normalize middleware result to context shape
|
|
91
91
|
*/
|
|
92
92
|
function handleCtxResult(result) {
|
|
93
|
-
if (isSpecialResponse(result)) return { response: result };
|
|
93
|
+
if (isSsrResponse(result) || isSpecialResponse(result)) return { response: result };
|
|
94
94
|
return result;
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* Execute a middleware chain
|
|
98
98
|
*/
|
|
99
|
-
function executeMiddleware(middlewares, ctx) {
|
|
99
|
+
async function executeMiddleware(middlewares, ctx) {
|
|
100
100
|
let index = -1;
|
|
101
|
+
let streamResponse;
|
|
102
|
+
const setResponse = (response) => {
|
|
103
|
+
if (isSsrResponse(response)) {
|
|
104
|
+
if (response.serverSsrCleanup === "stream") streamResponse = response;
|
|
105
|
+
ctx.response = response.response;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
ctx.response = response;
|
|
109
|
+
};
|
|
110
|
+
const disposeStreamResponse = async (reason) => {
|
|
111
|
+
const response = streamResponse;
|
|
112
|
+
if (!response) return;
|
|
113
|
+
streamResponse = void 0;
|
|
114
|
+
const currentResponse = ctx.response;
|
|
115
|
+
if (currentResponse === response.response || currentResponse instanceof Response && response.response.body !== null && currentResponse.body === response.response.body) ctx.response = void 0;
|
|
116
|
+
await response.dispose(reason);
|
|
117
|
+
};
|
|
118
|
+
const getFinalResponse = async () => {
|
|
119
|
+
const response = ctx.response;
|
|
120
|
+
if (!response) throwRouteHandlerError();
|
|
121
|
+
if (!streamResponse) return response;
|
|
122
|
+
if (response === streamResponse.response) return streamResponse;
|
|
123
|
+
if (streamResponse.response.body !== null && response.body === streamResponse.response.body) return {
|
|
124
|
+
...streamResponse,
|
|
125
|
+
response
|
|
126
|
+
};
|
|
127
|
+
await disposeStreamResponse("middleware response replaced");
|
|
128
|
+
return response;
|
|
129
|
+
};
|
|
101
130
|
const next = async (nextCtx) => {
|
|
102
131
|
if (nextCtx) {
|
|
103
132
|
if (nextCtx.context) ctx.context = safeObjectMerge(ctx.context, nextCtx.context);
|
|
104
|
-
for (const key of Object.keys(nextCtx)) if (key
|
|
133
|
+
for (const key of Object.keys(nextCtx)) if (key === "response") setResponse(nextCtx.response);
|
|
134
|
+
else if (key !== "context") ctx[key] = nextCtx[key];
|
|
105
135
|
}
|
|
106
136
|
index++;
|
|
107
137
|
const middleware = middlewares[index];
|
|
@@ -114,19 +144,24 @@ function executeMiddleware(middlewares, ctx) {
|
|
|
114
144
|
});
|
|
115
145
|
} catch (err) {
|
|
116
146
|
if (isSpecialResponse(err)) {
|
|
117
|
-
|
|
147
|
+
setResponse(err);
|
|
118
148
|
return ctx;
|
|
119
149
|
}
|
|
150
|
+
await disposeStreamResponse("middleware error");
|
|
120
151
|
throw err;
|
|
121
152
|
}
|
|
122
153
|
const normalized = handleCtxResult(result);
|
|
123
154
|
if (normalized) {
|
|
124
|
-
if (normalized.response !== void 0)
|
|
155
|
+
if (normalized.response !== void 0) setResponse(normalized.response);
|
|
125
156
|
if (normalized.context) ctx.context = safeObjectMerge(ctx.context, normalized.context);
|
|
126
157
|
}
|
|
127
158
|
return ctx;
|
|
128
159
|
};
|
|
129
|
-
|
|
160
|
+
await next();
|
|
161
|
+
return {
|
|
162
|
+
ctx,
|
|
163
|
+
response: await getFinalResponse()
|
|
164
|
+
};
|
|
130
165
|
}
|
|
131
166
|
/**
|
|
132
167
|
* Wrap a route handler as middleware
|
|
@@ -183,7 +218,7 @@ function createStartHandler(cbOrOptions) {
|
|
|
183
218
|
if (process.env.TSS_DEV_SERVER !== "true") finalManifestResolver.warmup({ getBaseManifest: () => getBaseManifest(void 0) });
|
|
184
219
|
const startRequestResolver = async (request, requestOpts) => {
|
|
185
220
|
let router = null;
|
|
186
|
-
let
|
|
221
|
+
let responseOwnsCleanup = false;
|
|
187
222
|
try {
|
|
188
223
|
const { url, handledProtocolRelativeURL } = getNormalizedURL(request.url);
|
|
189
224
|
const href = url.pathname + url.search + url.hash;
|
|
@@ -240,16 +275,19 @@ function createStartHandler(cbOrOptions) {
|
|
|
240
275
|
serverFnId
|
|
241
276
|
}));
|
|
242
277
|
};
|
|
243
|
-
|
|
278
|
+
const { response: middlewareResponse } = await executeMiddleware([...flattenedRequestMiddlewares.map((d) => d.options.server), serverFnHandler], {
|
|
244
279
|
request,
|
|
245
280
|
pathname: url.pathname,
|
|
246
281
|
handlerType: "serverFn",
|
|
247
282
|
context: createNullProtoObject(requestOpts?.context)
|
|
248
|
-
})
|
|
283
|
+
});
|
|
284
|
+
const result = await handleRedirectResponse(middlewareResponse, request, getRouter);
|
|
285
|
+
responseOwnsCleanup = result.serverSsrCleanup === "stream";
|
|
286
|
+
return result.response;
|
|
249
287
|
}
|
|
250
288
|
const executeRouter = async (serverContext, matchedRoutes) => {
|
|
251
289
|
const acceptParts = (request.headers.get("Accept") || "*/*").split(",");
|
|
252
|
-
if (!["*/*", "text/html"].some((mimeType) => acceptParts.some((part) => part.trim().startsWith(mimeType)))) return Response.json({ error: "Only HTML requests are supported here" }, { status: 500 });
|
|
290
|
+
if (!["*/*", "text/html"].some((mimeType) => acceptParts.some((part) => part.trim().startsWith(mimeType)))) return normalizeSsrResponse(Response.json({ error: "Only HTML requests are supported here" }, { status: 500 }));
|
|
253
291
|
const manifest = await resolveManifestForRequest({
|
|
254
292
|
request,
|
|
255
293
|
requestInlineCss: requestOpts?.inlineCss,
|
|
@@ -271,18 +309,17 @@ function createStartHandler(cbOrOptions) {
|
|
|
271
309
|
});
|
|
272
310
|
routerInstance.update({ additionalContext: { serverContext } });
|
|
273
311
|
await routerInstance.load();
|
|
274
|
-
if (routerInstance.state.redirect) return routerInstance.state.redirect;
|
|
312
|
+
if (routerInstance.state.redirect) return normalizeSsrResponse(routerInstance.state.redirect);
|
|
275
313
|
earlyHints?.collectDynamic(routerInstance.stores.matches.get());
|
|
276
314
|
const ctx = getStartContext({ throwIfNotFound: false });
|
|
277
315
|
await routerInstance.serverSsr.dehydrate({ requestAssets: ctx?.requestAssets });
|
|
278
316
|
const responseHeaders = getStartResponseHeaders({ router: routerInstance });
|
|
279
317
|
earlyHints?.appendResponseHeaders(responseHeaders);
|
|
280
|
-
|
|
281
|
-
return cb({
|
|
318
|
+
return normalizeSsrResponse(await cb({
|
|
282
319
|
request,
|
|
283
320
|
router: routerInstance,
|
|
284
321
|
responseHeaders
|
|
285
|
-
});
|
|
322
|
+
}));
|
|
286
323
|
};
|
|
287
324
|
const requestHandlerMiddleware = async ({ context }) => {
|
|
288
325
|
return runWithStartContext({
|
|
@@ -308,41 +345,45 @@ function createStartHandler(cbOrOptions) {
|
|
|
308
345
|
}
|
|
309
346
|
});
|
|
310
347
|
};
|
|
311
|
-
|
|
348
|
+
const { response: middlewareResponse } = await executeMiddleware([...flattenedRequestMiddlewares.map((d) => d.options.server), requestHandlerMiddleware], {
|
|
312
349
|
request,
|
|
313
350
|
pathname: url.pathname,
|
|
314
351
|
handlerType: "router",
|
|
315
352
|
context: createNullProtoObject(requestOpts?.context)
|
|
316
|
-
})
|
|
353
|
+
});
|
|
354
|
+
const response = await handleRedirectResponse(middlewareResponse, request, getRouter);
|
|
355
|
+
responseOwnsCleanup = response.serverSsrCleanup === "stream";
|
|
356
|
+
return response.response;
|
|
317
357
|
} finally {
|
|
318
|
-
if (router && !
|
|
358
|
+
if (router?.serverSsr && !responseOwnsCleanup) router.serverSsr.cleanup();
|
|
319
359
|
router = null;
|
|
320
360
|
}
|
|
321
361
|
};
|
|
322
362
|
return requestHandler(startRequestResolver);
|
|
323
363
|
}
|
|
324
364
|
async function handleRedirectResponse(response, request, getRouter) {
|
|
325
|
-
|
|
326
|
-
if (
|
|
327
|
-
|
|
328
|
-
|
|
365
|
+
const ssrResponse = normalizeSsrResponse(response);
|
|
366
|
+
if (!isRedirect(ssrResponse.response)) return ssrResponse;
|
|
367
|
+
if (isResolvedRedirect(ssrResponse.response)) {
|
|
368
|
+
if (request.headers.get("x-tsr-serverFn") === "true") return replaceSsrResponse(ssrResponse, Response.json({
|
|
369
|
+
...ssrResponse.response.options,
|
|
329
370
|
isSerializedRedirect: true
|
|
330
|
-
}, { headers: response.headers });
|
|
331
|
-
return
|
|
371
|
+
}, { headers: ssrResponse.response.headers }), "redirect response replaced");
|
|
372
|
+
return ssrResponse;
|
|
332
373
|
}
|
|
333
|
-
const opts = response.options;
|
|
374
|
+
const opts = ssrResponse.response.options;
|
|
334
375
|
if (opts.to && typeof opts.to === "string" && !opts.to.startsWith("/")) throw new Error(`Server side redirects must use absolute paths via the 'href' or 'to' options. The redirect() method's "to" property accepts an internal path only. Use the "href" property to provide an external URL. Received: ${JSON.stringify(opts)}`);
|
|
335
376
|
if ([
|
|
336
377
|
"params",
|
|
337
378
|
"search",
|
|
338
379
|
"hash"
|
|
339
380
|
].some((d) => typeof opts[d] === "function")) throw new Error(`Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys(opts).filter((d) => typeof opts[d] === "function").map((d) => `"${d}"`).join(", ")}`);
|
|
340
|
-
const redirect = (await getRouter()).resolveRedirect(response);
|
|
341
|
-
if (request.headers.get("x-tsr-serverFn") === "true") return Response.json({
|
|
342
|
-
...response.options,
|
|
381
|
+
const redirect = (await getRouter()).resolveRedirect(ssrResponse.response);
|
|
382
|
+
if (request.headers.get("x-tsr-serverFn") === "true") return replaceSsrResponse(ssrResponse, Response.json({
|
|
383
|
+
...ssrResponse.response.options,
|
|
343
384
|
isSerializedRedirect: true
|
|
344
|
-
}, { headers: response.headers });
|
|
345
|
-
return redirect;
|
|
385
|
+
}, { headers: ssrResponse.response.headers }), "redirect response replaced");
|
|
386
|
+
return replaceSsrResponse(ssrResponse, redirect, "redirect response replaced");
|
|
346
387
|
}
|
|
347
388
|
async function handleServerRoutes({ getRouter, request, url, executeRouter, context, executedRequestMiddlewares }) {
|
|
348
389
|
const router = await getRouter();
|
|
@@ -376,8 +417,8 @@ async function handleServerRoutes({ getRouter, request, url, executeRouter, cont
|
|
|
376
417
|
}
|
|
377
418
|
}
|
|
378
419
|
}
|
|
379
|
-
routeMiddlewares.push((ctx) => executeRouter(ctx.context, matchedRoutes));
|
|
380
|
-
const ctx = await executeMiddleware(routeMiddlewares, {
|
|
420
|
+
routeMiddlewares.push(((ctx) => executeRouter(ctx.context, matchedRoutes)));
|
|
421
|
+
const { ctx, response } = await executeMiddleware(routeMiddlewares, {
|
|
381
422
|
request,
|
|
382
423
|
context,
|
|
383
424
|
params: routeParams,
|
|
@@ -386,10 +427,9 @@ async function handleServerRoutes({ getRouter, request, url, executeRouter, cont
|
|
|
386
427
|
});
|
|
387
428
|
if (isHeadFallback) {
|
|
388
429
|
if (!ctx.response) throwRouteHandlerError();
|
|
389
|
-
|
|
390
|
-
return new Response(null, resolved);
|
|
430
|
+
return stripSsrResponseBody(await handleRedirectResponse(response, request, getRouter), "HEAD body stripped");
|
|
391
431
|
}
|
|
392
|
-
return
|
|
432
|
+
return normalizeSsrResponse(response);
|
|
393
433
|
}
|
|
394
434
|
//#endregion
|
|
395
435
|
export { createStartHandler };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createStartHandler.js","names":[],"sources":["../../src/createStartHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport {\n createCsrfMiddleware,\n createNullProtoObject,\n csrfSymbol,\n flattenMiddlewares,\n mergeHeaders,\n safeObjectMerge,\n} from '@tanstack/start-client-core'\nimport {\n executeRewriteInput,\n isRedirect,\n isResolvedRedirect,\n} from '@tanstack/router-core'\nimport {\n attachRouterServerSsrUtils,\n getNormalizedURL,\n getOrigin,\n} from '@tanstack/router-core/ssr/server'\nimport {\n getStartContext,\n runWithStartContext,\n} from '@tanstack/start-storage-context'\nimport { requestHandler } from './request-response'\nimport { getStartManifest } from './router-manifest'\nimport { handleServerAction } from './server-functions-handler'\nimport { createEarlyHintsCollector } from './early-hints'\nimport {\n createCachedBaseManifestLoader,\n createFinalManifestResolver,\n} from './finalManifest'\n\nimport { HEADERS } from './constants'\nimport { ServerFunctionSerializationAdapter } from './serializer/ServerFunctionSerializationAdapter'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AnyStartInstanceOptions,\n RouteMethod,\n RouteMethodHandlerFn,\n RouterEntry,\n StartEntry,\n} from '@tanstack/start-client-core'\nimport type { RequestHandler } from './request-handler'\nimport type {\n AnyRoute,\n AnyRouter,\n AnySerializationAdapter,\n Register,\n} from '@tanstack/router-core'\nimport type { HandlerCallback } from '@tanstack/router-core/ssr/server'\nimport type { FinalManifestOptions } from './finalManifest'\n\ntype TODO = any\n\ntype AnyMiddlewareServerFn =\n | AnyRequestMiddleware['options']['server']\n | AnyFunctionMiddleware['options']['server']\n\nexport interface CreateStartHandlerOptions extends FinalManifestOptions {\n handler: HandlerCallback<AnyRouter>\n}\n\nfunction getStartResponseHeaders(opts: { router: AnyRouter }) {\n const headers = mergeHeaders(\n {\n 'Content-Type': 'text/html; charset=utf-8',\n },\n ...opts.router.stores.matches.get().map((match) => {\n return match.headers\n }),\n )\n return headers\n}\n\ninterface PluginAdaptersEntry {\n hasPluginAdapters: boolean\n pluginSerializationAdapters: Array<AnySerializationAdapter>\n}\n\ninterface Entries {\n startEntry: StartEntry\n routerEntry: RouterEntry\n pluginAdapters: PluginAdaptersEntry\n}\n\n// Cached entries - promises stored immediately to prevent concurrent imports\n// that can cause race conditions during module initialization\nlet entriesPromise: Promise<Entries> | undefined\nlet hasWarnedMissingCsrfMiddleware = false\nconst defaultCsrfMiddleware = createCsrfMiddleware({\n filter: (ctx) => ctx.handlerType === 'serverFn',\n})\nconst getCachedBaseManifest = createCachedBaseManifestLoader(() =>\n getStartManifest(),\n)\nconst getProdBaseManifest: typeof getStartManifest = () =>\n getCachedBaseManifest()\nconst getBaseManifest =\n process.env.TSS_DEV_SERVER === 'true' ? getStartManifest : getProdBaseManifest\nconst createEarlyHintsForRequest: typeof createEarlyHintsCollector =\n process.env.TSS_DEV_SERVER === 'true'\n ? () => undefined\n : createEarlyHintsCollector\n\nasync function loadEntries(): Promise<Entries> {\n const [routerEntry, startEntry, pluginAdapters] = await Promise.all([\n // @ts-ignore When building, we currently don't respect tsconfig.ts' `include` so we are not picking up the .d.ts from start-client-core\n import('#tanstack-router-entry'),\n // @ts-ignore When building, we currently don't respect tsconfig.ts' `include` so we are not picking up the .d.ts from start-client-core\n import('#tanstack-start-entry'),\n // @ts-ignore When building, we currently don't respect tsconfig.ts' `include` so we are not picking up the .d.ts from start-client-core\n import('#tanstack-start-plugin-adapters'),\n ])\n return {\n routerEntry: routerEntry as unknown as RouterEntry,\n startEntry: startEntry as unknown as StartEntry,\n pluginAdapters: pluginAdapters as unknown as PluginAdaptersEntry,\n }\n}\n\nfunction getEntries() {\n if (!entriesPromise) {\n entriesPromise = loadEntries()\n }\n return entriesPromise\n}\n\nfunction hasCsrfMiddleware(\n middlewares: Array<AnyRequestMiddleware | AnyFunctionMiddleware>,\n): boolean {\n return middlewares.some((middleware) => csrfSymbol in middleware)\n}\n\nfunction warnMissingCsrfMiddlewareOnce() {\n if (hasWarnedMissingCsrfMiddleware) return\n hasWarnedMissingCsrfMiddleware = true\n\n console.warn(`TanStack Start server functions are not protected by the CSRF middleware.\n\nServer functions are same-origin RPC endpoints and should be protected from cross-site requests.\n\nAdd the CSRF middleware in src/start.ts:\n\n const csrfMiddleware = createCsrfMiddleware({\n filter: (ctx) => ctx.handlerType === 'serverFn',\n })\n\n export const startInstance = createStart(() => ({\n requestMiddleware: [csrfMiddleware],\n }))\n\nIf you intentionally handle CSRF another way, disable this warning:\n\n tanstackStart({\n serverFns: {\n disableCsrfMiddlewareWarning: true,\n },\n })`)\n}\n\n// Pre-computed constants\nconst ROUTER_BASEPATH = process.env.TSS_ROUTER_BASEPATH || '/'\nconst SERVER_FN_BASE = process.env.TSS_SERVER_FN_BASE\nconst IS_PRERENDERING = process.env.TSS_PRERENDERING === 'true'\nconst IS_SHELL_ENV = process.env.TSS_SHELL === 'true'\nconst IS_DEV = process.env.NODE_ENV === 'development'\n\n// Reusable error messages\nconst ERR_NO_RESPONSE = IS_DEV\n ? `It looks like you forgot to return a response from your server route handler. If you want to defer to the app router, make sure to have a component set in this route.`\n : 'Internal Server Error'\n\nconst ERR_NO_DEFER = IS_DEV\n ? `You cannot defer to the app router if there is no component defined on this route.`\n : 'Internal Server Error'\n\nfunction throwRouteHandlerError(): never {\n throw new Error(ERR_NO_RESPONSE)\n}\n\nfunction throwIfMayNotDefer(): never {\n throw new Error(ERR_NO_DEFER)\n}\n\n/**\n * Check if a value is a special response (Response or Redirect)\n */\nfunction isSpecialResponse(value: unknown): value is Response {\n return value instanceof Response || isRedirect(value)\n}\n\n/**\n * Normalize middleware result to context shape\n */\nfunction handleCtxResult(result: TODO) {\n if (isSpecialResponse(result)) {\n return { response: result }\n }\n return result\n}\n\n/**\n * Execute a middleware chain\n */\nfunction executeMiddleware(middlewares: Array<TODO>, ctx: TODO): Promise<TODO> {\n let index = -1\n\n const next = async (nextCtx?: TODO): Promise<TODO> => {\n // Merge context if provided using safeObjectMerge for prototype pollution prevention\n if (nextCtx) {\n if (nextCtx.context) {\n ctx.context = safeObjectMerge(ctx.context, nextCtx.context)\n }\n // Copy own properties except context (Object.keys returns only own enumerable properties)\n for (const key of Object.keys(nextCtx)) {\n if (key !== 'context') {\n ctx[key] = nextCtx[key]\n }\n }\n }\n\n index++\n const middleware = middlewares[index]\n if (!middleware) return ctx\n\n let result: TODO\n try {\n result = await middleware({ ...ctx, next })\n } catch (err) {\n if (isSpecialResponse(err)) {\n ctx.response = err\n return ctx\n }\n throw err\n }\n\n const normalized = handleCtxResult(result)\n if (normalized) {\n if (normalized.response !== undefined) {\n ctx.response = normalized.response\n }\n if (normalized.context) {\n ctx.context = safeObjectMerge(ctx.context, normalized.context)\n }\n }\n\n return ctx\n }\n\n return next()\n}\n\n/**\n * Wrap a route handler as middleware\n */\nfunction handlerToMiddleware(\n handler: RouteMethodHandlerFn<any, AnyRoute, any, any, any, any, any>,\n mayDefer: boolean = false,\n): TODO {\n if (mayDefer) {\n return handler\n }\n return async (ctx: TODO) => {\n const response = await handler({ ...ctx, next: throwIfMayNotDefer })\n if (!response) {\n throwRouteHandlerError()\n }\n return response\n }\n}\n\n/**\n * Creates the TanStack Start request handler.\n *\n * @example Backwards-compatible usage (handler callback only):\n * ```ts\n * export default createStartHandler(defaultStreamHandler)\n * ```\n *\n * @example With CDN URL rewriting:\n * ```ts\n * export default createStartHandler({\n * handler: defaultStreamHandler,\n * transformAssets: 'https://cdn.example.com',\n * })\n * ```\n *\n * @example With per-request URL rewriting:\n * ```ts\n * export default createStartHandler({\n * handler: defaultStreamHandler,\n * transformAssets: {\n * transform: ({ url }) => {\n * const cdnBase = getRequest().headers.get('x-cdn-base') || ''\n * return { href: `${cdnBase}${url}` }\n * },\n * cache: false,\n * },\n * })\n * ```\n */\nexport function createStartHandler<TRegister = Register>(\n cbOrOptions: HandlerCallback<AnyRouter> | CreateStartHandlerOptions,\n): RequestHandler<TRegister> {\n const handlerOptions: FinalManifestOptions =\n typeof cbOrOptions === 'function' ? {} : cbOrOptions\n const cb: HandlerCallback<AnyRouter> =\n typeof cbOrOptions === 'function' ? cbOrOptions : cbOrOptions.handler\n const finalManifestResolver = createFinalManifestResolver({\n ...handlerOptions,\n cacheCreateTransform: process.env.TSS_DEV_SERVER !== 'true',\n })\n const resolveManifestForRequest =\n process.env.TSS_DEV_SERVER === 'true'\n ? finalManifestResolver.resolveUncached\n : finalManifestResolver.resolveCached\n\n if (process.env.TSS_DEV_SERVER !== 'true') {\n finalManifestResolver.warmup({\n getBaseManifest: () => getBaseManifest(undefined),\n })\n }\n\n const startRequestResolver: RequestHandler<Register> = async (\n request,\n requestOpts,\n ) => {\n let router: AnyRouter | null = null as AnyRouter | null\n let cbWillCleanup = false as boolean\n\n try {\n // normalizing and sanitizing the pathname here for server, so we always deal with the same format during SSR.\n // during normalization paths like '//posts' are flattened to '/posts'.\n // in these cases we would prefer to redirect to the new path\n const { url, handledProtocolRelativeURL } = getNormalizedURL(request.url)\n const href = url.pathname + url.search + url.hash\n const origin = getOrigin(request)\n\n if (handledProtocolRelativeURL) {\n return Response.redirect(url, 308)\n }\n\n const entries = await getEntries()\n const hasStartInstance = !!entries.startEntry.startInstance\n const startOptions: AnyStartInstanceOptions =\n (await entries.startEntry.startInstance?.getOptions()) ||\n ({} as AnyStartInstanceOptions)\n\n const { hasPluginAdapters, pluginSerializationAdapters } =\n entries.pluginAdapters\n\n const serializationAdapters = [\n ...(startOptions.serializationAdapters || []),\n ...(hasPluginAdapters ? pluginSerializationAdapters : []),\n ServerFunctionSerializationAdapter,\n ]\n\n const requestStartOptions = {\n ...startOptions,\n requestMiddleware: hasStartInstance\n ? startOptions.requestMiddleware\n : [defaultCsrfMiddleware],\n serializationAdapters,\n }\n\n // Flatten request middlewares once\n const flattenedRequestMiddlewares = requestStartOptions.requestMiddleware\n ? flattenMiddlewares(requestStartOptions.requestMiddleware)\n : []\n\n // Create set for deduplication\n const executedRequestMiddlewares = new Set<TODO>(\n flattenedRequestMiddlewares,\n )\n\n // Memoized router getter\n const getRouter = async (): Promise<AnyRouter> => {\n if (router) return router\n\n router = await entries.routerEntry.getRouter()\n\n let isShell = IS_SHELL_ENV\n if (IS_PRERENDERING && !isShell) {\n isShell = request.headers.get(HEADERS.TSS_SHELL) === 'true'\n }\n\n const history = createMemoryHistory({\n initialEntries: [href],\n })\n\n router.update({\n history,\n isShell,\n isPrerendering: IS_PRERENDERING,\n origin: router.options.origin ?? origin,\n ...{\n defaultSsr: requestStartOptions.defaultSsr,\n serializationAdapters: [\n ...requestStartOptions.serializationAdapters,\n ...(router.options.serializationAdapters || []),\n ],\n },\n basepath: ROUTER_BASEPATH,\n })\n\n return router\n }\n\n // Check for server function requests first (early exit)\n if (SERVER_FN_BASE && url.pathname.startsWith(SERVER_FN_BASE)) {\n if (\n process.env.NODE_ENV !== 'production' &&\n process.env.TSS_DISABLE_CSRF_MIDDLEWARE_WARNING !== 'true' &&\n !hasCsrfMiddleware(flattenedRequestMiddlewares)\n ) {\n warnMissingCsrfMiddlewareOnce()\n }\n\n const serverFnId = url.pathname\n .slice(SERVER_FN_BASE.length)\n .split('/')[0]\n\n if (!serverFnId) {\n throw new Error('Invalid server action param for serverFnId')\n }\n\n const serverFnHandler = async ({ context }: TODO) => {\n return runWithStartContext(\n {\n getRouter,\n startOptions: requestStartOptions,\n contextAfterGlobalMiddlewares: context,\n request,\n executedRequestMiddlewares,\n handlerType: 'serverFn',\n },\n () =>\n handleServerAction({\n request,\n context: requestOpts?.context,\n serverFnId,\n }),\n )\n }\n\n const middlewares = flattenedRequestMiddlewares.map(\n (d) => d.options.server,\n )\n const ctx = await executeMiddleware([...middlewares, serverFnHandler], {\n request,\n pathname: url.pathname,\n handlerType: 'serverFn',\n context: createNullProtoObject(requestOpts?.context),\n })\n\n return handleRedirectResponse(ctx.response, request, getRouter)\n }\n\n // Router execution function\n const executeRouter = async (\n serverContext: TODO,\n matchedRoutes?: ReadonlyArray<AnyRoute>,\n ): Promise<Response> => {\n const acceptHeader = request.headers.get('Accept') || '*/*'\n const acceptParts = acceptHeader.split(',')\n const supportedMimeTypes = ['*/*', 'text/html']\n\n const isSupported = supportedMimeTypes.some((mimeType) =>\n acceptParts.some((part) => part.trim().startsWith(mimeType)),\n )\n\n if (!isSupported) {\n return Response.json(\n { error: 'Only HTML requests are supported here' },\n { status: 500 },\n )\n }\n\n const manifest = await resolveManifestForRequest({\n request,\n requestInlineCss: requestOpts?.inlineCss,\n getBaseManifest: () => getBaseManifest(matchedRoutes),\n })\n\n const earlyHints = createEarlyHintsForRequest({\n onEarlyHints: requestOpts?.onEarlyHints,\n responseLinkHeader: requestOpts?.responseLinkHeader,\n })\n\n earlyHints?.collectStatic({ manifest, matchedRoutes })\n\n const routerInstance = await getRouter()\n\n attachRouterServerSsrUtils({\n router: routerInstance,\n manifest,\n getRequestAssets: () =>\n getStartContext({ throwIfNotFound: false })?.requestAssets,\n })\n\n routerInstance.update({ additionalContext: { serverContext } })\n await routerInstance.load()\n\n if (routerInstance.state.redirect) {\n return routerInstance.state.redirect\n }\n\n earlyHints?.collectDynamic(routerInstance.stores.matches.get())\n\n // Pass request-scoped assets to dehydrate for manifest injection\n const ctx = getStartContext({ throwIfNotFound: false })\n await routerInstance.serverSsr!.dehydrate({\n requestAssets: ctx?.requestAssets,\n })\n\n const responseHeaders = getStartResponseHeaders({\n router: routerInstance,\n })\n earlyHints?.appendResponseHeaders(responseHeaders)\n cbWillCleanup = true\n\n return cb({\n request,\n router: routerInstance,\n responseHeaders,\n })\n }\n\n // Main request handler\n const requestHandlerMiddleware = async ({ context }: TODO) => {\n return runWithStartContext(\n {\n getRouter,\n startOptions: requestStartOptions,\n contextAfterGlobalMiddlewares: context,\n request,\n executedRequestMiddlewares,\n handlerType: 'router',\n },\n async () => {\n try {\n return await handleServerRoutes({\n getRouter,\n request,\n url,\n executeRouter,\n context,\n executedRequestMiddlewares,\n })\n } catch (err) {\n if (err instanceof Response) {\n return err\n }\n throw err\n }\n },\n )\n }\n\n const middlewares = flattenedRequestMiddlewares.map(\n (d) => d.options.server,\n )\n const ctx = await executeMiddleware(\n [...middlewares, requestHandlerMiddleware],\n {\n request,\n pathname: url.pathname,\n handlerType: 'router',\n context: createNullProtoObject(requestOpts?.context),\n },\n )\n\n return handleRedirectResponse(ctx.response, request, getRouter)\n } finally {\n if (router && !cbWillCleanup) {\n // Clean up router SSR state if it was set up but won't be cleaned up by the callback\n // (e.g., in redirect cases or early returns before the callback is invoked).\n // When the callback runs, it handles cleanup (either via transformStreamWithRouter\n // for streaming, or directly in renderRouterToString for non-streaming).\n router.serverSsr?.cleanup()\n }\n router = null\n }\n }\n\n return requestHandler(startRequestResolver)\n}\n\nasync function handleRedirectResponse(\n response: Response,\n request: Request,\n getRouter: () => Promise<AnyRouter>,\n): Promise<Response> {\n if (!isRedirect(response)) {\n return response\n }\n\n if (isResolvedRedirect(response)) {\n if (request.headers.get('x-tsr-serverFn') === 'true') {\n return Response.json(\n { ...response.options, isSerializedRedirect: true },\n { headers: response.headers },\n )\n }\n return response\n }\n\n const opts = response.options\n if (opts.to && typeof opts.to === 'string' && !opts.to.startsWith('/')) {\n throw new Error(\n `Server side redirects must use absolute paths via the 'href' or 'to' options. The redirect() method's \"to\" property accepts an internal path only. Use the \"href\" property to provide an external URL. Received: ${JSON.stringify(opts)}`,\n )\n }\n\n if (\n ['params', 'search', 'hash'].some(\n (d) => typeof (opts as TODO)[d] === 'function',\n )\n ) {\n throw new Error(\n `Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys(\n opts,\n )\n .filter((d) => typeof (opts as TODO)[d] === 'function')\n .map((d) => `\"${d}\"`)\n .join(', ')}`,\n )\n }\n\n const router = await getRouter()\n const redirect = router.resolveRedirect(response)\n\n if (request.headers.get('x-tsr-serverFn') === 'true') {\n return Response.json(\n { ...response.options, isSerializedRedirect: true },\n { headers: response.headers },\n )\n }\n\n return redirect\n}\n\nasync function handleServerRoutes({\n getRouter,\n request,\n url,\n executeRouter,\n context,\n executedRequestMiddlewares,\n}: {\n getRouter: () => Promise<AnyRouter>\n request: Request\n url: URL\n executeRouter: (\n serverContext: any,\n matchedRoutes?: ReadonlyArray<AnyRoute>,\n ) => Promise<Response>\n context: any\n executedRequestMiddlewares: Set<AnyRequestMiddleware>\n}): Promise<Response> {\n const router = await getRouter()\n const rewrittenUrl = executeRewriteInput(router.rewrite, url)\n const pathname = rewrittenUrl.pathname\n // this will perform a fuzzy match, however for server routes we need an exact match\n // if the route is not an exact match, executeRouter will handle rendering the app router\n // the match will be cached internally, so no extra work is done during the app router render\n const { matchedRoutes, foundRoute, routeParams } =\n router.getMatchedRoutes(pathname)\n\n const isExactMatch = foundRoute && routeParams['**'] === undefined\n\n // Collect and dedupe route middlewares\n const routeMiddlewares: Array<AnyMiddlewareServerFn> = []\n\n // Collect middleware from matched routes, filtering out those already executed\n // in the request phase\n for (const route of matchedRoutes) {\n const serverMiddleware = route.options.server?.middleware as\n | Array<AnyRequestMiddleware>\n | undefined\n if (serverMiddleware) {\n const flattened = flattenMiddlewares(serverMiddleware)\n for (const m of flattened) {\n if (!executedRequestMiddlewares.has(m)) {\n routeMiddlewares.push(m.options.server)\n }\n }\n }\n }\n\n // Add handler middleware if exact match\n const server = foundRoute?.options.server\n let isHeadFallback = false\n if (server?.handlers && isExactMatch) {\n const handlers =\n typeof server.handlers === 'function'\n ? server.handlers({ createHandlers: (d: any) => d })\n : server.handlers\n\n const requestMethod = request.method.toUpperCase() as RouteMethod\n // Per RFC 9110 §9.3.2, HEAD must return the same header fields as GET.\n // Priority for HEAD: explicit HEAD handler → GET → ANY (last resort).\n const handler =\n requestMethod === 'HEAD'\n ? (handlers['HEAD'] ?? handlers['GET'] ?? handlers['ANY'])\n : (handlers[requestMethod] ?? handlers['ANY'])\n isHeadFallback =\n requestMethod === 'HEAD' && handler !== undefined && !handlers['HEAD']\n\n if (handler) {\n const mayDefer = !!foundRoute.options.component\n\n if (typeof handler === 'function') {\n routeMiddlewares.push(handlerToMiddleware(handler, mayDefer))\n } else {\n if (handler.middleware?.length) {\n const handlerMiddlewares = flattenMiddlewares(handler.middleware)\n for (const m of handlerMiddlewares) {\n routeMiddlewares.push(m.options.server)\n }\n }\n if (handler.handler) {\n routeMiddlewares.push(handlerToMiddleware(handler.handler, mayDefer))\n }\n }\n }\n }\n\n // Final middleware: execute router with matched routes for dev styles\n routeMiddlewares.push((ctx: TODO) =>\n executeRouter(ctx.context, matchedRoutes),\n )\n\n const ctx = await executeMiddleware(routeMiddlewares, {\n request,\n context,\n params: routeParams,\n pathname,\n handlerType: 'router',\n })\n\n // RFC 9110 §9.3.2: HEAD must carry the same header fields as GET but no body.\n // Resolve any redirect before stripping so the Location header survives.\n if (isHeadFallback) {\n if (!ctx.response) {\n throwRouteHandlerError()\n }\n\n const resolved = await handleRedirectResponse(\n ctx.response,\n request,\n getRouter,\n )\n return new Response(null, resolved)\n }\n\n return ctx.response\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createStartHandler.js","names":[],"sources":["../../src/createStartHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport {\n createCsrfMiddleware,\n createNullProtoObject,\n csrfSymbol,\n flattenMiddlewares,\n mergeHeaders,\n safeObjectMerge,\n} from '@tanstack/start-client-core'\nimport {\n executeRewriteInput,\n isRedirect,\n isResolvedRedirect,\n} from '@tanstack/router-core'\nimport {\n attachRouterServerSsrUtils,\n getNormalizedURL,\n getOrigin,\n isSsrResponse,\n normalizeSsrResponse,\n replaceSsrResponse,\n stripSsrResponseBody,\n} from '@tanstack/router-core/ssr/server'\nimport {\n getStartContext,\n runWithStartContext,\n} from '@tanstack/start-storage-context'\nimport { requestHandler } from './request-response'\nimport { getStartManifest } from './router-manifest'\nimport { handleServerAction } from './server-functions-handler'\nimport { createEarlyHintsCollector } from './early-hints'\nimport {\n createCachedBaseManifestLoader,\n createFinalManifestResolver,\n} from './finalManifest'\n\nimport { HEADERS } from './constants'\nimport { ServerFunctionSerializationAdapter } from './serializer/ServerFunctionSerializationAdapter'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AnyStartInstanceOptions,\n RouteMethod,\n RouteMethodHandlerFn,\n RouterEntry,\n StartEntry,\n} from '@tanstack/start-client-core'\nimport type { RequestHandler } from './request-handler'\nimport type {\n AnyRoute,\n AnyRouter,\n AnySerializationAdapter,\n Register,\n} from '@tanstack/router-core'\nimport type {\n HandlerCallback,\n HandlerCallbackResult,\n SsrResponse,\n} from '@tanstack/router-core/ssr/server'\nimport type { FinalManifestOptions } from './finalManifest'\n\ntype TODO = any\n\ntype AnyMiddlewareServerFn =\n | AnyRequestMiddleware['options']['server']\n | AnyFunctionMiddleware['options']['server']\n\nexport interface CreateStartHandlerOptions extends FinalManifestOptions {\n handler: HandlerCallback<AnyRouter>\n}\n\nfunction getStartResponseHeaders(opts: { router: AnyRouter }) {\n const headers = mergeHeaders(\n {\n 'Content-Type': 'text/html; charset=utf-8',\n },\n ...opts.router.stores.matches.get().map((match) => {\n return match.headers\n }),\n )\n return headers\n}\n\ninterface PluginAdaptersEntry {\n hasPluginAdapters: boolean\n pluginSerializationAdapters: Array<AnySerializationAdapter>\n}\n\ninterface Entries {\n startEntry: StartEntry\n routerEntry: RouterEntry\n pluginAdapters: PluginAdaptersEntry\n}\n\n// Cached entries - promises stored immediately to prevent concurrent imports\n// that can cause race conditions during module initialization\nlet entriesPromise: Promise<Entries> | undefined\nlet hasWarnedMissingCsrfMiddleware = false\nconst defaultCsrfMiddleware = createCsrfMiddleware({\n filter: (ctx) => ctx.handlerType === 'serverFn',\n})\nconst getCachedBaseManifest = createCachedBaseManifestLoader(() =>\n getStartManifest(),\n)\nconst getProdBaseManifest: typeof getStartManifest = () =>\n getCachedBaseManifest()\nconst getBaseManifest =\n process.env.TSS_DEV_SERVER === 'true' ? getStartManifest : getProdBaseManifest\nconst createEarlyHintsForRequest: typeof createEarlyHintsCollector =\n process.env.TSS_DEV_SERVER === 'true'\n ? () => undefined\n : createEarlyHintsCollector\n\nasync function loadEntries(): Promise<Entries> {\n const [routerEntry, startEntry, pluginAdapters] = await Promise.all([\n // @ts-ignore When building, we currently don't respect tsconfig.ts' `include` so we are not picking up the .d.ts from start-client-core\n import('#tanstack-router-entry'),\n // @ts-ignore When building, we currently don't respect tsconfig.ts' `include` so we are not picking up the .d.ts from start-client-core\n import('#tanstack-start-entry'),\n // @ts-ignore When building, we currently don't respect tsconfig.ts' `include` so we are not picking up the .d.ts from start-client-core\n import('#tanstack-start-plugin-adapters'),\n ])\n return {\n routerEntry: routerEntry as unknown as RouterEntry,\n startEntry: startEntry as unknown as StartEntry,\n pluginAdapters: pluginAdapters as unknown as PluginAdaptersEntry,\n }\n}\n\nfunction getEntries() {\n if (!entriesPromise) {\n entriesPromise = loadEntries()\n }\n return entriesPromise\n}\n\nfunction hasCsrfMiddleware(\n middlewares: Array<AnyRequestMiddleware | AnyFunctionMiddleware>,\n): boolean {\n return middlewares.some((middleware) => csrfSymbol in middleware)\n}\n\nfunction warnMissingCsrfMiddlewareOnce() {\n if (hasWarnedMissingCsrfMiddleware) return\n hasWarnedMissingCsrfMiddleware = true\n\n console.warn(`TanStack Start server functions are not protected by the CSRF middleware.\n\nServer functions are same-origin RPC endpoints and should be protected from cross-site requests.\n\nAdd the CSRF middleware in src/start.ts:\n\n const csrfMiddleware = createCsrfMiddleware({\n filter: (ctx) => ctx.handlerType === 'serverFn',\n })\n\n export const startInstance = createStart(() => ({\n requestMiddleware: [csrfMiddleware],\n }))\n\nIf you intentionally handle CSRF another way, disable this warning:\n\n tanstackStart({\n serverFns: {\n disableCsrfMiddlewareWarning: true,\n },\n })`)\n}\n\n// Pre-computed constants\nconst ROUTER_BASEPATH = process.env.TSS_ROUTER_BASEPATH || '/'\nconst SERVER_FN_BASE = process.env.TSS_SERVER_FN_BASE\nconst IS_PRERENDERING = process.env.TSS_PRERENDERING === 'true'\nconst IS_SHELL_ENV = process.env.TSS_SHELL === 'true'\nconst IS_DEV = process.env.NODE_ENV === 'development'\n\n// Reusable error messages\nconst ERR_NO_RESPONSE = IS_DEV\n ? `It looks like you forgot to return a response from your server route handler. If you want to defer to the app router, make sure to have a component set in this route.`\n : 'Internal Server Error'\n\nconst ERR_NO_DEFER = IS_DEV\n ? `You cannot defer to the app router if there is no component defined on this route.`\n : 'Internal Server Error'\n\nfunction throwRouteHandlerError(): never {\n throw new Error(ERR_NO_RESPONSE)\n}\n\nfunction throwIfMayNotDefer(): never {\n throw new Error(ERR_NO_DEFER)\n}\n\n/**\n * Check if a value is a special response (Response or Redirect)\n */\nfunction isSpecialResponse(value: unknown): value is Response {\n return value instanceof Response || isRedirect(value)\n}\n\n/**\n * Normalize middleware result to context shape\n */\nfunction handleCtxResult(result: TODO) {\n if (isSsrResponse(result) || isSpecialResponse(result)) {\n return { response: result }\n }\n return result\n}\n\n/**\n * Execute a middleware chain\n */\nasync function executeMiddleware(\n middlewares: Array<TODO>,\n ctx: TODO,\n): Promise<{ ctx: TODO; response: HandlerCallbackResult }> {\n let index = -1\n let streamResponse:\n | Extract<SsrResponse, { serverSsrCleanup: 'stream' }>\n | undefined\n\n const setResponse = (response: TODO) => {\n if (isSsrResponse(response)) {\n if (response.serverSsrCleanup === 'stream') {\n streamResponse = response\n }\n ctx.response = response.response\n return\n }\n\n ctx.response = response\n }\n\n const disposeStreamResponse = async (reason: string) => {\n const response = streamResponse\n if (!response) {\n return\n }\n\n streamResponse = undefined\n const currentResponse = ctx.response\n if (\n currentResponse === response.response ||\n (currentResponse instanceof Response &&\n response.response.body !== null &&\n currentResponse.body === response.response.body)\n ) {\n ctx.response = undefined\n }\n await response.dispose(reason)\n }\n\n const getFinalResponse = async (): Promise<HandlerCallbackResult> => {\n const response = ctx.response\n if (!response) {\n throwRouteHandlerError()\n }\n\n if (!streamResponse) {\n return response\n }\n\n if (response === streamResponse.response) {\n return streamResponse\n }\n\n if (\n streamResponse.response.body !== null &&\n response.body === streamResponse.response.body\n ) {\n return { ...streamResponse, response }\n }\n\n await disposeStreamResponse('middleware response replaced')\n return response\n }\n\n const next = async (nextCtx?: TODO): Promise<TODO> => {\n // Merge context if provided using safeObjectMerge for prototype pollution prevention\n if (nextCtx) {\n if (nextCtx.context) {\n ctx.context = safeObjectMerge(ctx.context, nextCtx.context)\n }\n // Copy own properties except context (Object.keys returns only own enumerable properties)\n for (const key of Object.keys(nextCtx)) {\n if (key === 'response') {\n setResponse(nextCtx.response)\n } else if (key !== 'context') {\n ctx[key] = nextCtx[key]\n }\n }\n }\n\n index++\n const middleware = middlewares[index]\n if (!middleware) return ctx\n\n let result: TODO\n try {\n result = await middleware({ ...ctx, next })\n } catch (err) {\n if (isSpecialResponse(err)) {\n setResponse(err)\n return ctx\n }\n await disposeStreamResponse('middleware error')\n throw err\n }\n\n const normalized = handleCtxResult(result)\n if (normalized) {\n if (normalized.response !== undefined) {\n setResponse(normalized.response)\n }\n if (normalized.context) {\n ctx.context = safeObjectMerge(ctx.context, normalized.context)\n }\n }\n\n return ctx\n }\n\n await next()\n return { ctx, response: await getFinalResponse() }\n}\n\n/**\n * Wrap a route handler as middleware\n */\nfunction handlerToMiddleware(\n handler: RouteMethodHandlerFn<any, AnyRoute, any, any, any, any, any>,\n mayDefer: boolean = false,\n): TODO {\n if (mayDefer) {\n return handler\n }\n return async (ctx: TODO) => {\n const response = await handler({ ...ctx, next: throwIfMayNotDefer })\n if (!response) {\n throwRouteHandlerError()\n }\n return response\n }\n}\n\n/**\n * Creates the TanStack Start request handler.\n *\n * @example Backwards-compatible usage (handler callback only):\n * ```ts\n * export default createStartHandler(defaultStreamHandler)\n * ```\n *\n * @example With CDN URL rewriting:\n * ```ts\n * export default createStartHandler({\n * handler: defaultStreamHandler,\n * transformAssets: 'https://cdn.example.com',\n * })\n * ```\n *\n * @example With per-request URL rewriting:\n * ```ts\n * export default createStartHandler({\n * handler: defaultStreamHandler,\n * transformAssets: {\n * transform: ({ url }) => {\n * const cdnBase = getRequest().headers.get('x-cdn-base') || ''\n * return { href: `${cdnBase}${url}` }\n * },\n * cache: false,\n * },\n * })\n * ```\n */\nexport function createStartHandler<TRegister = Register>(\n cbOrOptions: HandlerCallback<AnyRouter> | CreateStartHandlerOptions,\n): RequestHandler<TRegister> {\n const handlerOptions: FinalManifestOptions =\n typeof cbOrOptions === 'function' ? {} : cbOrOptions\n const cb: HandlerCallback<AnyRouter> =\n typeof cbOrOptions === 'function' ? cbOrOptions : cbOrOptions.handler\n const finalManifestResolver = createFinalManifestResolver({\n ...handlerOptions,\n cacheCreateTransform: process.env.TSS_DEV_SERVER !== 'true',\n })\n const resolveManifestForRequest =\n process.env.TSS_DEV_SERVER === 'true'\n ? finalManifestResolver.resolveUncached\n : finalManifestResolver.resolveCached\n\n if (process.env.TSS_DEV_SERVER !== 'true') {\n finalManifestResolver.warmup({\n getBaseManifest: () => getBaseManifest(undefined),\n })\n }\n\n const startRequestResolver: RequestHandler<Register> = async (\n request,\n requestOpts,\n ) => {\n let router: AnyRouter | null = null as AnyRouter | null\n let responseOwnsCleanup = false as boolean\n\n try {\n // normalizing and sanitizing the pathname here for server, so we always deal with the same format during SSR.\n // during normalization paths like '//posts' are flattened to '/posts'.\n // in these cases we would prefer to redirect to the new path\n const { url, handledProtocolRelativeURL } = getNormalizedURL(request.url)\n const href = url.pathname + url.search + url.hash\n const origin = getOrigin(request)\n\n if (handledProtocolRelativeURL) {\n return Response.redirect(url, 308)\n }\n\n const entries = await getEntries()\n const hasStartInstance = !!entries.startEntry.startInstance\n const startOptions: AnyStartInstanceOptions =\n (await entries.startEntry.startInstance?.getOptions()) ||\n ({} as AnyStartInstanceOptions)\n\n const { hasPluginAdapters, pluginSerializationAdapters } =\n entries.pluginAdapters\n\n const serializationAdapters = [\n ...(startOptions.serializationAdapters || []),\n ...(hasPluginAdapters ? pluginSerializationAdapters : []),\n ServerFunctionSerializationAdapter,\n ]\n\n const requestStartOptions = {\n ...startOptions,\n requestMiddleware: hasStartInstance\n ? startOptions.requestMiddleware\n : [defaultCsrfMiddleware],\n serializationAdapters,\n }\n\n // Flatten request middlewares once\n const flattenedRequestMiddlewares = requestStartOptions.requestMiddleware\n ? flattenMiddlewares(requestStartOptions.requestMiddleware)\n : []\n\n // Create set for deduplication\n const executedRequestMiddlewares = new Set<TODO>(\n flattenedRequestMiddlewares,\n )\n\n // Memoized router getter\n const getRouter = async (): Promise<AnyRouter> => {\n if (router) return router\n\n router = await entries.routerEntry.getRouter()\n\n let isShell = IS_SHELL_ENV\n if (IS_PRERENDERING && !isShell) {\n isShell = request.headers.get(HEADERS.TSS_SHELL) === 'true'\n }\n\n const history = createMemoryHistory({\n initialEntries: [href],\n })\n\n router.update({\n history,\n isShell,\n isPrerendering: IS_PRERENDERING,\n origin: router.options.origin ?? origin,\n ...{\n defaultSsr: requestStartOptions.defaultSsr,\n serializationAdapters: [\n ...requestStartOptions.serializationAdapters,\n ...(router.options.serializationAdapters || []),\n ],\n },\n basepath: ROUTER_BASEPATH,\n })\n\n return router\n }\n\n // Check for server function requests first (early exit)\n if (SERVER_FN_BASE && url.pathname.startsWith(SERVER_FN_BASE)) {\n if (\n process.env.NODE_ENV !== 'production' &&\n process.env.TSS_DISABLE_CSRF_MIDDLEWARE_WARNING !== 'true' &&\n !hasCsrfMiddleware(flattenedRequestMiddlewares)\n ) {\n warnMissingCsrfMiddlewareOnce()\n }\n\n const serverFnId = url.pathname\n .slice(SERVER_FN_BASE.length)\n .split('/')[0]\n\n if (!serverFnId) {\n throw new Error('Invalid server action param for serverFnId')\n }\n\n const serverFnHandler = async ({ context }: TODO) => {\n return runWithStartContext(\n {\n getRouter,\n startOptions: requestStartOptions,\n contextAfterGlobalMiddlewares: context,\n request,\n executedRequestMiddlewares,\n handlerType: 'serverFn',\n },\n () =>\n handleServerAction({\n request,\n context: requestOpts?.context,\n serverFnId,\n }),\n )\n }\n\n const middlewares = flattenedRequestMiddlewares.map(\n (d) => d.options.server,\n )\n const { response: middlewareResponse } = await executeMiddleware(\n [...middlewares, serverFnHandler],\n {\n request,\n pathname: url.pathname,\n handlerType: 'serverFn',\n context: createNullProtoObject(requestOpts?.context),\n },\n )\n\n const result = await handleRedirectResponse(\n middlewareResponse,\n request,\n getRouter,\n )\n responseOwnsCleanup = result.serverSsrCleanup === 'stream'\n return result.response\n }\n\n // Router execution function\n const executeRouter = async (\n serverContext: TODO,\n matchedRoutes?: ReadonlyArray<AnyRoute>,\n ): Promise<SsrResponse> => {\n const acceptHeader = request.headers.get('Accept') || '*/*'\n const acceptParts = acceptHeader.split(',')\n const supportedMimeTypes = ['*/*', 'text/html']\n\n const isSupported = supportedMimeTypes.some((mimeType) =>\n acceptParts.some((part) => part.trim().startsWith(mimeType)),\n )\n\n if (!isSupported) {\n return normalizeSsrResponse(\n Response.json(\n { error: 'Only HTML requests are supported here' },\n { status: 500 },\n ),\n )\n }\n\n const manifest = await resolveManifestForRequest({\n request,\n requestInlineCss: requestOpts?.inlineCss,\n getBaseManifest: () => getBaseManifest(matchedRoutes),\n })\n\n const earlyHints = createEarlyHintsForRequest({\n onEarlyHints: requestOpts?.onEarlyHints,\n responseLinkHeader: requestOpts?.responseLinkHeader,\n })\n\n earlyHints?.collectStatic({ manifest, matchedRoutes })\n\n const routerInstance = await getRouter()\n\n attachRouterServerSsrUtils({\n router: routerInstance,\n manifest,\n getRequestAssets: () =>\n getStartContext({ throwIfNotFound: false })?.requestAssets,\n })\n\n routerInstance.update({ additionalContext: { serverContext } })\n await routerInstance.load()\n\n if (routerInstance.state.redirect) {\n return normalizeSsrResponse(routerInstance.state.redirect)\n }\n\n earlyHints?.collectDynamic(routerInstance.stores.matches.get())\n\n // Pass request-scoped assets to dehydrate for manifest injection\n const ctx = getStartContext({ throwIfNotFound: false })\n await routerInstance.serverSsr!.dehydrate({\n requestAssets: ctx?.requestAssets,\n })\n\n const responseHeaders = getStartResponseHeaders({\n router: routerInstance,\n })\n earlyHints?.appendResponseHeaders(responseHeaders)\n const response = await cb({\n request,\n router: routerInstance,\n responseHeaders,\n })\n return normalizeSsrResponse(response)\n }\n\n // Main request handler\n const requestHandlerMiddleware = async ({ context }: TODO) => {\n return runWithStartContext(\n {\n getRouter,\n startOptions: requestStartOptions,\n contextAfterGlobalMiddlewares: context,\n request,\n executedRequestMiddlewares,\n handlerType: 'router',\n },\n async () => {\n try {\n return await handleServerRoutes({\n getRouter,\n request,\n url,\n executeRouter,\n context,\n executedRequestMiddlewares,\n })\n } catch (err) {\n if (err instanceof Response) {\n return err\n }\n throw err\n }\n },\n )\n }\n\n const middlewares = flattenedRequestMiddlewares.map(\n (d) => d.options.server,\n )\n const { response: middlewareResponse } = await executeMiddleware(\n [...middlewares, requestHandlerMiddleware],\n {\n request,\n pathname: url.pathname,\n handlerType: 'router',\n context: createNullProtoObject(requestOpts?.context),\n },\n )\n\n const response = await handleRedirectResponse(\n middlewareResponse,\n request,\n getRouter,\n )\n responseOwnsCleanup = response.serverSsrCleanup === 'stream'\n return response.response\n } finally {\n if (router?.serverSsr && !responseOwnsCleanup) {\n // Clean up router SSR state if it was set up but won't be cleaned up by the callback\n // (e.g., in redirect cases or early returns before the callback is invoked).\n // Transformed streaming response bodies clean up when consumed/cancelled.\n router.serverSsr.cleanup()\n }\n router = null\n }\n }\n\n return requestHandler(startRequestResolver)\n}\n\nasync function handleRedirectResponse(\n response: HandlerCallbackResult,\n request: Request,\n getRouter: () => Promise<AnyRouter>,\n): Promise<SsrResponse> {\n const ssrResponse = normalizeSsrResponse(response)\n if (!isRedirect(ssrResponse.response)) {\n return ssrResponse\n }\n\n if (isResolvedRedirect(ssrResponse.response)) {\n if (request.headers.get('x-tsr-serverFn') === 'true') {\n return replaceSsrResponse(\n ssrResponse,\n Response.json(\n { ...ssrResponse.response.options, isSerializedRedirect: true },\n { headers: ssrResponse.response.headers },\n ),\n 'redirect response replaced',\n )\n }\n return ssrResponse\n }\n\n const opts = ssrResponse.response.options\n if (opts.to && typeof opts.to === 'string' && !opts.to.startsWith('/')) {\n throw new Error(\n `Server side redirects must use absolute paths via the 'href' or 'to' options. The redirect() method's \"to\" property accepts an internal path only. Use the \"href\" property to provide an external URL. Received: ${JSON.stringify(opts)}`,\n )\n }\n\n if (\n ['params', 'search', 'hash'].some(\n (d) => typeof (opts as TODO)[d] === 'function',\n )\n ) {\n throw new Error(\n `Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys(\n opts,\n )\n .filter((d) => typeof (opts as TODO)[d] === 'function')\n .map((d) => `\"${d}\"`)\n .join(', ')}`,\n )\n }\n\n const router = await getRouter()\n const redirect = router.resolveRedirect(ssrResponse.response)\n\n if (request.headers.get('x-tsr-serverFn') === 'true') {\n return replaceSsrResponse(\n ssrResponse,\n Response.json(\n { ...ssrResponse.response.options, isSerializedRedirect: true },\n { headers: ssrResponse.response.headers },\n ),\n 'redirect response replaced',\n )\n }\n\n return replaceSsrResponse(ssrResponse, redirect, 'redirect response replaced')\n}\n\nasync function handleServerRoutes({\n getRouter,\n request,\n url,\n executeRouter,\n context,\n executedRequestMiddlewares,\n}: {\n getRouter: () => Promise<AnyRouter>\n request: Request\n url: URL\n executeRouter: (\n serverContext: any,\n matchedRoutes?: ReadonlyArray<AnyRoute>,\n ) => Promise<SsrResponse>\n context: any\n executedRequestMiddlewares: Set<AnyRequestMiddleware>\n}): Promise<SsrResponse> {\n const router = await getRouter()\n const rewrittenUrl = executeRewriteInput(router.rewrite, url)\n const pathname = rewrittenUrl.pathname\n // this will perform a fuzzy match, however for server routes we need an exact match\n // if the route is not an exact match, executeRouter will handle rendering the app router\n // the match will be cached internally, so no extra work is done during the app router render\n const { matchedRoutes, foundRoute, routeParams } =\n router.getMatchedRoutes(pathname)\n\n const isExactMatch = foundRoute && routeParams['**'] === undefined\n\n // Collect and dedupe route middlewares\n const routeMiddlewares: Array<AnyMiddlewareServerFn> = []\n\n // Collect middleware from matched routes, filtering out those already executed\n // in the request phase\n for (const route of matchedRoutes) {\n const serverMiddleware = route.options.server?.middleware as\n | Array<AnyRequestMiddleware>\n | undefined\n if (serverMiddleware) {\n const flattened = flattenMiddlewares(serverMiddleware)\n for (const m of flattened) {\n if (!executedRequestMiddlewares.has(m)) {\n routeMiddlewares.push(m.options.server)\n }\n }\n }\n }\n\n // Add handler middleware if exact match\n const server = foundRoute?.options.server\n let isHeadFallback = false\n if (server?.handlers && isExactMatch) {\n const handlers =\n typeof server.handlers === 'function'\n ? server.handlers({ createHandlers: (d: any) => d })\n : server.handlers\n\n const requestMethod = request.method.toUpperCase() as RouteMethod\n // Per RFC 9110 §9.3.2, HEAD must return the same header fields as GET.\n // Priority for HEAD: explicit HEAD handler → GET → ANY (last resort).\n const handler =\n requestMethod === 'HEAD'\n ? (handlers['HEAD'] ?? handlers['GET'] ?? handlers['ANY'])\n : (handlers[requestMethod] ?? handlers['ANY'])\n isHeadFallback =\n requestMethod === 'HEAD' && handler !== undefined && !handlers['HEAD']\n\n if (handler) {\n const mayDefer = !!foundRoute.options.component\n\n if (typeof handler === 'function') {\n routeMiddlewares.push(handlerToMiddleware(handler, mayDefer))\n } else {\n if (handler.middleware?.length) {\n const handlerMiddlewares = flattenMiddlewares(handler.middleware)\n for (const m of handlerMiddlewares) {\n routeMiddlewares.push(m.options.server)\n }\n }\n if (handler.handler) {\n routeMiddlewares.push(handlerToMiddleware(handler.handler, mayDefer))\n }\n }\n }\n }\n\n // Final middleware: execute router with matched routes for dev styles\n routeMiddlewares.push(((ctx: TODO) =>\n executeRouter(ctx.context, matchedRoutes)) as TODO)\n\n const { ctx, response } = await executeMiddleware(routeMiddlewares, {\n request,\n context,\n params: routeParams,\n pathname,\n handlerType: 'router',\n })\n\n // RFC 9110 §9.3.2: HEAD must carry the same header fields as GET but no body.\n // Resolve any redirect before stripping so the Location header survives.\n if (isHeadFallback) {\n if (!ctx.response) {\n throwRouteHandlerError()\n }\n\n const resolved = await handleRedirectResponse(response, request, getRouter)\n return stripSsrResponseBody(resolved, 'HEAD body stripped')\n }\n\n return normalizeSsrResponse(response)\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ServerManifest } from '@tanstack/router-core';
|
|
2
2
|
import { HandlerInlineCssOption } from './inlineCss.js';
|
|
3
|
-
import {
|
|
4
|
-
export type { HandlerInlineCssOption,
|
|
3
|
+
import { TransformAssets } from './transformAssetUrls.js';
|
|
4
|
+
export type { HandlerInlineCssOption, TransformAssets };
|
|
5
5
|
export interface FinalManifestOptions {
|
|
6
6
|
/**
|
|
7
7
|
* Controls whether Start inlines build-collected CSS by default at runtime.
|
|
@@ -17,13 +17,13 @@ export interface FinalManifestOptions {
|
|
|
17
17
|
* Transform manifest-managed asset URLs and attributes at runtime, e.g. to
|
|
18
18
|
* prepend a CDN prefix.
|
|
19
19
|
*
|
|
20
|
-
* This covers JS preloads,
|
|
21
|
-
*
|
|
20
|
+
* This covers JS preloads, manifest script tags, CSS links, and URLs inside
|
|
21
|
+
* build-collected inline CSS. Asset imports used directly in
|
|
22
22
|
* components should be handled by the bundler instead.
|
|
23
23
|
*/
|
|
24
24
|
transformAssets?: TransformAssets;
|
|
25
25
|
}
|
|
26
|
-
export type GetBaseManifest = () => Promise<
|
|
26
|
+
export type GetBaseManifest = () => Promise<ServerManifest>;
|
|
27
27
|
export interface FinalManifestRequestOptions {
|
|
28
28
|
request: Request;
|
|
29
29
|
requestInlineCss: boolean | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildManifest, resolveTransformAssetsConfig, transformManifestAssets } from "./transformAssetUrls.js";
|
|
2
2
|
import { getStaticHandlerInlineCssDefault, resolveInlineCssForRequest } from "./inlineCss.js";
|
|
3
3
|
//#region src/finalManifest.ts
|
|
4
4
|
function createCachedBaseManifestLoader(loadBaseManifest) {
|
|
@@ -93,7 +93,7 @@ function getOrCreateCachedFinalManifestPromise(cachedFinalManifestPromises, cach
|
|
|
93
93
|
return cacheFinalManifestPromise(cachedFinalManifestPromises, cacheKey, Promise.resolve().then(computeFinalManifest));
|
|
94
94
|
}
|
|
95
95
|
async function buildFinalManifest(opts) {
|
|
96
|
-
return opts.transformFn ? await transformManifestAssets(opts.base, opts.transformFn, { inlineCss: opts.inlineCss }) :
|
|
96
|
+
return opts.transformFn ? await transformManifestAssets(opts.base, opts.transformFn, { inlineCss: opts.inlineCss }) : buildManifest(opts.base, { inlineCss: opts.inlineCss });
|
|
97
97
|
}
|
|
98
98
|
async function resolveFinalManifest(opts) {
|
|
99
99
|
const computeFinalManifest = async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finalManifest.js","names":[],"sources":["../../src/finalManifest.ts"],"sourcesContent":["import {\n buildManifestWithClientEntry,\n resolveTransformAssetsConfig,\n transformManifestAssets,\n} from './transformAssetUrls'\nimport {\n getStaticHandlerInlineCssDefault,\n resolveInlineCssForRequest,\n} from './inlineCss'\nimport type { ServerManifest } from '@tanstack/router-core'\nimport type { HandlerInlineCssOption } from './inlineCss'\nimport type {\n CreateTransformAssetsContext,\n StartManifestWithClientEntry,\n TransformAssets,\n TransformAssetsFn,\n} from './transformAssetUrls'\n\nexport type {\n HandlerInlineCssOption,\n StartManifestWithClientEntry,\n TransformAssets,\n}\n\nexport interface FinalManifestOptions {\n /**\n * Controls whether Start inlines build-collected CSS by default at runtime.\n *\n * This only has an effect when the build was created with\n * `server.build.inlineCss` enabled. Pass a callback to decide per request.\n * `handler(request, { inlineCss })` overrides this value for that request.\n *\n * @default true\n */\n inlineCss?: HandlerInlineCssOption\n /**\n * Transform manifest-managed asset URLs and attributes at runtime, e.g. to\n * prepend a CDN prefix.\n *\n * This covers JS preloads, CSS links, the client entry script, and URLs\n * inside build-collected inline CSS. Asset imports used directly in\n * components should be handled by the bundler instead.\n */\n transformAssets?: TransformAssets\n}\n\ntype FinalManifestCacheKey = 'inline-css' | 'linked-css'\ntype FinalManifestCache = Map<FinalManifestCacheKey, Promise<ServerManifest>>\nexport type GetBaseManifest = () => Promise<StartManifestWithClientEntry>\n\nexport interface FinalManifestRequestOptions {\n request: Request\n requestInlineCss: boolean | undefined\n getBaseManifest: GetBaseManifest\n}\n\ninterface FinalManifestTransformResolver {\n cache: boolean\n warmup: boolean\n getTransformFn: (\n ctx: CreateTransformAssetsContext,\n ) => Promise<TransformAssetsFn | undefined>\n clearCachedCreateTransform: () => void\n}\n\nexport interface FinalManifestResolver {\n warmup: (opts: {\n getBaseManifest: GetBaseManifest\n }) => Promise<ServerManifest> | undefined\n resolveCached: (opts: FinalManifestRequestOptions) => Promise<ServerManifest>\n resolveUncached: (\n opts: FinalManifestRequestOptions,\n ) => Promise<ServerManifest>\n}\n\nexport function createCachedBaseManifestLoader(\n loadBaseManifest: GetBaseManifest,\n): GetBaseManifest {\n let baseManifestPromise: Promise<StartManifestWithClientEntry> | undefined\n\n return () => {\n if (!baseManifestPromise) {\n baseManifestPromise = loadBaseManifest().catch((error) => {\n baseManifestPromise = undefined\n throw error\n })\n }\n\n return baseManifestPromise\n }\n}\n\nfunction createFinalManifestTransformResolver(\n transformAssets: TransformAssets | undefined,\n opts: { cacheCreateTransform: boolean },\n): FinalManifestTransformResolver {\n const transformConfig =\n transformAssets !== undefined\n ? resolveTransformAssetsConfig(transformAssets)\n : undefined\n const cache = transformConfig ? transformConfig.cache : true\n const warmup =\n !!transformAssets &&\n typeof transformAssets === 'object' &&\n 'warmup' in transformAssets &&\n transformAssets.warmup === true\n\n let cachedCreateTransformPromise: Promise<TransformAssetsFn> | undefined\n\n const clearCachedCreateTransform = () => {\n cachedCreateTransformPromise = undefined\n }\n\n return {\n cache,\n warmup,\n clearCachedCreateTransform,\n getTransformFn: async (ctx) => {\n if (!transformConfig) return undefined\n\n if (transformConfig.type !== 'createTransform') {\n return transformConfig.transformFn\n }\n\n if (!cache || !opts.cacheCreateTransform) {\n return transformConfig.createTransform(ctx)\n }\n\n if (!cachedCreateTransformPromise) {\n cachedCreateTransformPromise = Promise.resolve(\n transformConfig.createTransform(ctx),\n ).catch((error) => {\n clearCachedCreateTransform()\n throw error\n })\n }\n\n return cachedCreateTransformPromise\n },\n }\n}\n\nexport function createFinalManifestResolver(\n opts: FinalManifestOptions & { cacheCreateTransform: boolean },\n): FinalManifestResolver {\n const finalManifestCache: FinalManifestCache = new Map()\n const transformResolver = createFinalManifestTransformResolver(\n opts.transformAssets,\n { cacheCreateTransform: opts.cacheCreateTransform },\n )\n const handlerDefaultInlineCss = getStaticHandlerInlineCssDefault(\n opts.inlineCss,\n )\n\n const getRequestManifestOptions = async (\n requestOpts: FinalManifestRequestOptions,\n ) => {\n const transformFn = await transformResolver.getTransformFn({\n warmup: false,\n request: requestOpts.request,\n })\n const inlineCss = await resolveInlineCssForRequest({\n request: requestOpts.request,\n handlerInlineCss: opts.inlineCss,\n requestInlineCss: requestOpts.requestInlineCss,\n })\n\n return {\n getBaseManifest: requestOpts.getBaseManifest,\n transformFn,\n cache: transformResolver.cache,\n inlineCss,\n }\n }\n\n const resolveRequest = async (\n requestOpts: FinalManifestRequestOptions,\n cache: FinalManifestCache | undefined,\n ) => {\n return resolveFinalManifest({\n ...(await getRequestManifestOptions(requestOpts)),\n finalManifestCache: cache,\n })\n }\n\n return {\n warmup: ({ getBaseManifest }) =>\n warmupFinalManifest({\n enabled: transformResolver.warmup,\n handlerDefaultInlineCss,\n cache: transformResolver.cache,\n finalManifestCache,\n getBaseManifest,\n getTransformFn: () =>\n transformResolver.getTransformFn({ warmup: true }),\n onError: transformResolver.clearCachedCreateTransform,\n }),\n resolveCached: (requestOpts) =>\n resolveRequest(requestOpts, finalManifestCache),\n resolveUncached: (requestOpts) => resolveRequest(requestOpts, undefined),\n }\n}\n\nfunction getFinalManifestCacheKey(inlineCss: boolean): FinalManifestCacheKey {\n return inlineCss ? 'inline-css' : 'linked-css'\n}\n\nfunction cacheFinalManifestPromise(\n cachedFinalManifestPromises: FinalManifestCache,\n cacheKey: FinalManifestCacheKey,\n promise: Promise<ServerManifest>,\n): Promise<ServerManifest> {\n const cachedFinalManifestPromise = promise.catch((error) => {\n if (\n cachedFinalManifestPromises.get(cacheKey) === cachedFinalManifestPromise\n ) {\n cachedFinalManifestPromises.delete(cacheKey)\n }\n throw error\n })\n\n cachedFinalManifestPromises.set(cacheKey, cachedFinalManifestPromise)\n return cachedFinalManifestPromise\n}\n\nfunction getOrCreateCachedFinalManifestPromise(\n cachedFinalManifestPromises: FinalManifestCache,\n cacheKey: FinalManifestCacheKey,\n computeFinalManifest: () => Promise<ServerManifest>,\n): Promise<ServerManifest> {\n const cachedFinalManifestPromise = cachedFinalManifestPromises.get(cacheKey)\n if (cachedFinalManifestPromise) {\n return cachedFinalManifestPromise\n }\n\n return cacheFinalManifestPromise(\n cachedFinalManifestPromises,\n cacheKey,\n Promise.resolve().then(computeFinalManifest),\n )\n}\n\nasync function buildFinalManifest(opts: {\n base: StartManifestWithClientEntry\n transformFn: TransformAssetsFn | undefined\n inlineCss: boolean\n}): Promise<ServerManifest> {\n return opts.transformFn\n ? await transformManifestAssets(opts.base, opts.transformFn, {\n inlineCss: opts.inlineCss,\n })\n : buildManifestWithClientEntry(opts.base, { inlineCss: opts.inlineCss })\n}\n\nasync function resolveFinalManifest(opts: {\n getBaseManifest: () => Promise<StartManifestWithClientEntry>\n transformFn: TransformAssetsFn | undefined\n cache: boolean\n inlineCss: boolean\n finalManifestCache?: FinalManifestCache\n}): Promise<ServerManifest> {\n const computeFinalManifest = async () => {\n return buildFinalManifest({\n base: await opts.getBaseManifest(),\n transformFn: opts.transformFn,\n inlineCss: opts.inlineCss,\n })\n }\n\n if (opts.finalManifestCache && (!opts.transformFn || opts.cache)) {\n return getOrCreateCachedFinalManifestPromise(\n opts.finalManifestCache,\n getFinalManifestCacheKey(opts.inlineCss),\n computeFinalManifest,\n )\n }\n\n return computeFinalManifest()\n}\n\nfunction warmupFinalManifest(opts: {\n enabled: boolean\n handlerDefaultInlineCss: boolean | undefined\n cache: boolean\n finalManifestCache: FinalManifestCache\n getBaseManifest: () => Promise<StartManifestWithClientEntry>\n getTransformFn: () => Promise<TransformAssetsFn | undefined>\n onError?: () => void\n}): Promise<ServerManifest> | undefined {\n if (\n !opts.enabled ||\n opts.handlerDefaultInlineCss === undefined ||\n !opts.cache\n ) {\n return undefined\n }\n\n const inlineCss = opts.handlerDefaultInlineCss\n const warmupPromise = getOrCreateCachedFinalManifestPromise(\n opts.finalManifestCache,\n getFinalManifestCacheKey(inlineCss),\n async () => {\n const [base, transformFn] = await Promise.all([\n opts.getBaseManifest(),\n opts.getTransformFn(),\n ])\n\n return buildFinalManifest({\n base,\n transformFn,\n inlineCss,\n })\n },\n )\n\n if (opts.onError) {\n void warmupPromise.catch(opts.onError)\n }\n\n return warmupPromise\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"finalManifest.js","names":[],"sources":["../../src/finalManifest.ts"],"sourcesContent":["import {\n buildManifest,\n resolveTransformAssetsConfig,\n transformManifestAssets,\n} from './transformAssetUrls'\nimport {\n getStaticHandlerInlineCssDefault,\n resolveInlineCssForRequest,\n} from './inlineCss'\nimport type { ServerManifest } from '@tanstack/router-core'\nimport type { HandlerInlineCssOption } from './inlineCss'\nimport type {\n CreateTransformAssetsContext,\n TransformAssets,\n TransformAssetsFn,\n} from './transformAssetUrls'\n\nexport type { HandlerInlineCssOption, TransformAssets }\n\nexport interface FinalManifestOptions {\n /**\n * Controls whether Start inlines build-collected CSS by default at runtime.\n *\n * This only has an effect when the build was created with\n * `server.build.inlineCss` enabled. Pass a callback to decide per request.\n * `handler(request, { inlineCss })` overrides this value for that request.\n *\n * @default true\n */\n inlineCss?: HandlerInlineCssOption\n /**\n * Transform manifest-managed asset URLs and attributes at runtime, e.g. to\n * prepend a CDN prefix.\n *\n * This covers JS preloads, manifest script tags, CSS links, and URLs inside\n * build-collected inline CSS. Asset imports used directly in\n * components should be handled by the bundler instead.\n */\n transformAssets?: TransformAssets\n}\n\ntype FinalManifestCacheKey = 'inline-css' | 'linked-css'\ntype FinalManifestCache = Map<FinalManifestCacheKey, Promise<ServerManifest>>\nexport type GetBaseManifest = () => Promise<ServerManifest>\n\nexport interface FinalManifestRequestOptions {\n request: Request\n requestInlineCss: boolean | undefined\n getBaseManifest: GetBaseManifest\n}\n\ninterface FinalManifestTransformResolver {\n cache: boolean\n warmup: boolean\n getTransformFn: (\n ctx: CreateTransformAssetsContext,\n ) => Promise<TransformAssetsFn | undefined>\n clearCachedCreateTransform: () => void\n}\n\nexport interface FinalManifestResolver {\n warmup: (opts: {\n getBaseManifest: GetBaseManifest\n }) => Promise<ServerManifest> | undefined\n resolveCached: (opts: FinalManifestRequestOptions) => Promise<ServerManifest>\n resolveUncached: (\n opts: FinalManifestRequestOptions,\n ) => Promise<ServerManifest>\n}\n\nexport function createCachedBaseManifestLoader(\n loadBaseManifest: GetBaseManifest,\n): GetBaseManifest {\n let baseManifestPromise: Promise<ServerManifest> | undefined\n\n return () => {\n if (!baseManifestPromise) {\n baseManifestPromise = loadBaseManifest().catch((error) => {\n baseManifestPromise = undefined\n throw error\n })\n }\n\n return baseManifestPromise\n }\n}\n\nfunction createFinalManifestTransformResolver(\n transformAssets: TransformAssets | undefined,\n opts: { cacheCreateTransform: boolean },\n): FinalManifestTransformResolver {\n const transformConfig =\n transformAssets !== undefined\n ? resolveTransformAssetsConfig(transformAssets)\n : undefined\n const cache = transformConfig ? transformConfig.cache : true\n const warmup =\n !!transformAssets &&\n typeof transformAssets === 'object' &&\n 'warmup' in transformAssets &&\n transformAssets.warmup === true\n\n let cachedCreateTransformPromise: Promise<TransformAssetsFn> | undefined\n\n const clearCachedCreateTransform = () => {\n cachedCreateTransformPromise = undefined\n }\n\n return {\n cache,\n warmup,\n clearCachedCreateTransform,\n getTransformFn: async (ctx) => {\n if (!transformConfig) return undefined\n\n if (transformConfig.type !== 'createTransform') {\n return transformConfig.transformFn\n }\n\n if (!cache || !opts.cacheCreateTransform) {\n return transformConfig.createTransform(ctx)\n }\n\n if (!cachedCreateTransformPromise) {\n cachedCreateTransformPromise = Promise.resolve(\n transformConfig.createTransform(ctx),\n ).catch((error) => {\n clearCachedCreateTransform()\n throw error\n })\n }\n\n return cachedCreateTransformPromise\n },\n }\n}\n\nexport function createFinalManifestResolver(\n opts: FinalManifestOptions & { cacheCreateTransform: boolean },\n): FinalManifestResolver {\n const finalManifestCache: FinalManifestCache = new Map()\n const transformResolver = createFinalManifestTransformResolver(\n opts.transformAssets,\n { cacheCreateTransform: opts.cacheCreateTransform },\n )\n const handlerDefaultInlineCss = getStaticHandlerInlineCssDefault(\n opts.inlineCss,\n )\n\n const getRequestManifestOptions = async (\n requestOpts: FinalManifestRequestOptions,\n ) => {\n const transformFn = await transformResolver.getTransformFn({\n warmup: false,\n request: requestOpts.request,\n })\n const inlineCss = await resolveInlineCssForRequest({\n request: requestOpts.request,\n handlerInlineCss: opts.inlineCss,\n requestInlineCss: requestOpts.requestInlineCss,\n })\n\n return {\n getBaseManifest: requestOpts.getBaseManifest,\n transformFn,\n cache: transformResolver.cache,\n inlineCss,\n }\n }\n\n const resolveRequest = async (\n requestOpts: FinalManifestRequestOptions,\n cache: FinalManifestCache | undefined,\n ) => {\n return resolveFinalManifest({\n ...(await getRequestManifestOptions(requestOpts)),\n finalManifestCache: cache,\n })\n }\n\n return {\n warmup: ({ getBaseManifest }) =>\n warmupFinalManifest({\n enabled: transformResolver.warmup,\n handlerDefaultInlineCss,\n cache: transformResolver.cache,\n finalManifestCache,\n getBaseManifest,\n getTransformFn: () =>\n transformResolver.getTransformFn({ warmup: true }),\n onError: transformResolver.clearCachedCreateTransform,\n }),\n resolveCached: (requestOpts) =>\n resolveRequest(requestOpts, finalManifestCache),\n resolveUncached: (requestOpts) => resolveRequest(requestOpts, undefined),\n }\n}\n\nfunction getFinalManifestCacheKey(inlineCss: boolean): FinalManifestCacheKey {\n return inlineCss ? 'inline-css' : 'linked-css'\n}\n\nfunction cacheFinalManifestPromise(\n cachedFinalManifestPromises: FinalManifestCache,\n cacheKey: FinalManifestCacheKey,\n promise: Promise<ServerManifest>,\n): Promise<ServerManifest> {\n const cachedFinalManifestPromise = promise.catch((error) => {\n if (\n cachedFinalManifestPromises.get(cacheKey) === cachedFinalManifestPromise\n ) {\n cachedFinalManifestPromises.delete(cacheKey)\n }\n throw error\n })\n\n cachedFinalManifestPromises.set(cacheKey, cachedFinalManifestPromise)\n return cachedFinalManifestPromise\n}\n\nfunction getOrCreateCachedFinalManifestPromise(\n cachedFinalManifestPromises: FinalManifestCache,\n cacheKey: FinalManifestCacheKey,\n computeFinalManifest: () => Promise<ServerManifest>,\n): Promise<ServerManifest> {\n const cachedFinalManifestPromise = cachedFinalManifestPromises.get(cacheKey)\n if (cachedFinalManifestPromise) {\n return cachedFinalManifestPromise\n }\n\n return cacheFinalManifestPromise(\n cachedFinalManifestPromises,\n cacheKey,\n Promise.resolve().then(computeFinalManifest),\n )\n}\n\nasync function buildFinalManifest(opts: {\n base: ServerManifest\n transformFn: TransformAssetsFn | undefined\n inlineCss: boolean\n}): Promise<ServerManifest> {\n return opts.transformFn\n ? await transformManifestAssets(opts.base, opts.transformFn, {\n inlineCss: opts.inlineCss,\n })\n : buildManifest(opts.base, { inlineCss: opts.inlineCss })\n}\n\nasync function resolveFinalManifest(opts: {\n getBaseManifest: () => Promise<ServerManifest>\n transformFn: TransformAssetsFn | undefined\n cache: boolean\n inlineCss: boolean\n finalManifestCache?: FinalManifestCache\n}): Promise<ServerManifest> {\n const computeFinalManifest = async () => {\n return buildFinalManifest({\n base: await opts.getBaseManifest(),\n transformFn: opts.transformFn,\n inlineCss: opts.inlineCss,\n })\n }\n\n if (opts.finalManifestCache && (!opts.transformFn || opts.cache)) {\n return getOrCreateCachedFinalManifestPromise(\n opts.finalManifestCache,\n getFinalManifestCacheKey(opts.inlineCss),\n computeFinalManifest,\n )\n }\n\n return computeFinalManifest()\n}\n\nfunction warmupFinalManifest(opts: {\n enabled: boolean\n handlerDefaultInlineCss: boolean | undefined\n cache: boolean\n finalManifestCache: FinalManifestCache\n getBaseManifest: () => Promise<ServerManifest>\n getTransformFn: () => Promise<TransformAssetsFn | undefined>\n onError?: () => void\n}): Promise<ServerManifest> | undefined {\n if (\n !opts.enabled ||\n opts.handlerDefaultInlineCss === undefined ||\n !opts.cache\n ) {\n return undefined\n }\n\n const inlineCss = opts.handlerDefaultInlineCss\n const warmupPromise = getOrCreateCachedFinalManifestPromise(\n opts.finalManifestCache,\n getFinalManifestCacheKey(inlineCss),\n async () => {\n const [base, transformFn] = await Promise.all([\n opts.getBaseManifest(),\n opts.getTransformFn(),\n ])\n\n return buildFinalManifest({\n base,\n transformFn,\n inlineCss,\n })\n },\n )\n\n if (opts.onError) {\n void warmupPromise.catch(opts.onError)\n }\n\n return warmupPromise\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { AnyRoute } from '@tanstack/router-core';
|
|
2
|
-
import { StartManifestWithClientEntry } from './transformAssetUrls.js';
|
|
1
|
+
import { AnyRoute, ServerManifest } from '@tanstack/router-core';
|
|
3
2
|
/**
|
|
4
3
|
* @description Returns the router manifest data that should be sent to the client.
|
|
5
4
|
* This includes only the assets and preloads for the current route and any
|
|
6
5
|
* special assets that are needed for the client. It does not include relationships
|
|
7
6
|
* between routes or any other data that is not needed for the client.
|
|
8
7
|
*
|
|
9
|
-
* The client entry URL is returned separately so that it can be transformed
|
|
10
|
-
* (e.g. for CDN rewriting) before being embedded into the `<script>` tag.
|
|
11
|
-
*
|
|
12
8
|
* @param matchedRoutes - In dev mode, the matched routes are used to build
|
|
13
9
|
* the dev styles URL for route-scoped CSS collection.
|
|
14
10
|
*/
|
|
15
|
-
export declare function getStartManifest(matchedRoutes?: ReadonlyArray<AnyRoute>): Promise<
|
|
11
|
+
export declare function getStartManifest(matchedRoutes?: ReadonlyArray<AnyRoute>): Promise<ServerManifest>;
|
|
@@ -7,9 +7,6 @@ var DEV_SSR_STYLES_BASEPATH = process.env.TSS_DEV_SSR_STYLES_BASEPATH || "/";
|
|
|
7
7
|
* special assets that are needed for the client. It does not include relationships
|
|
8
8
|
* between routes or any other data that is not needed for the client.
|
|
9
9
|
*
|
|
10
|
-
* The client entry URL is returned separately so that it can be transformed
|
|
11
|
-
* (e.g. for CDN rewriting) before being embedded into the `<script>` tag.
|
|
12
|
-
*
|
|
13
10
|
* @param matchedRoutes - In dev mode, the matched routes are used to build
|
|
14
11
|
* the dev styles URL for route-scoped CSS collection.
|
|
15
12
|
*/
|
|
@@ -45,12 +42,9 @@ async function getStartManifest(matchedRoutes) {
|
|
|
45
42
|
if (result.preloads || result.scripts || result.css) manifestRoutes[k] = result;
|
|
46
43
|
}
|
|
47
44
|
return {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
routes: manifestRoutes
|
|
52
|
-
},
|
|
53
|
-
clientEntry: startManifest.clientEntry
|
|
45
|
+
...startManifest.scriptFormat ? { scriptFormat: startManifest.scriptFormat } : {},
|
|
46
|
+
...startManifest.inlineCss ? { inlineCss: startManifest.inlineCss } : {},
|
|
47
|
+
routes: manifestRoutes
|
|
54
48
|
};
|
|
55
49
|
}
|
|
56
50
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router-manifest.js","names":[],"sources":["../../src/router-manifest.ts"],"sourcesContent":["import {\n DEV_STYLES_ATTR,\n buildDevStylesUrl,\n rootRouteId,\n} from '@tanstack/router-core'\nimport type {
|
|
1
|
+
{"version":3,"file":"router-manifest.js","names":[],"sources":["../../src/router-manifest.ts"],"sourcesContent":["import {\n DEV_STYLES_ATTR,\n buildDevStylesUrl,\n rootRouteId,\n} from '@tanstack/router-core'\nimport type {\n AnyRoute,\n ServerManifest,\n ServerManifestRoute,\n} from '@tanstack/router-core'\n\n// Pre-computed constant for dev styles URL basepath.\n// Defaults to vite `base` (set via TSS_DEV_SSR_STYLES_BASEPATH in the plugin),\n// aligning dev styles with how other CSS/JS assets are served.\nconst DEV_SSR_STYLES_BASEPATH = process.env.TSS_DEV_SSR_STYLES_BASEPATH || '/'\n/**\n * @description Returns the router manifest data that should be sent to the client.\n * This includes only the assets and preloads for the current route and any\n * special assets that are needed for the client. It does not include relationships\n * between routes or any other data that is not needed for the client.\n *\n * @param matchedRoutes - In dev mode, the matched routes are used to build\n * the dev styles URL for route-scoped CSS collection.\n */\nexport async function getStartManifest(\n matchedRoutes?: ReadonlyArray<AnyRoute>,\n): Promise<ServerManifest> {\n const { tsrStartManifest } = await import('tanstack-start-manifest:v')\n const startManifest = tsrStartManifest()\n let routes = startManifest.routes\n let rootRoute = routes[rootRouteId]\n\n const updateRootRoute = (nextRootRoute: ServerManifestRoute) => {\n rootRoute = nextRootRoute\n routes = {\n ...routes,\n [rootRouteId]: rootRoute,\n }\n }\n\n // Inject dev styles link in dev mode (when SSR styles are enabled)\n if (\n process.env.TSS_DEV_SERVER === 'true' &&\n process.env.TSS_DEV_SSR_STYLES_ENABLED !== 'false' &&\n matchedRoutes\n ) {\n const matchedRouteIds = matchedRoutes.map((route) => route.id)\n updateRootRoute({\n ...rootRoute,\n css: [\n ...(rootRoute?.css ?? []),\n {\n href: buildDevStylesUrl(DEV_SSR_STYLES_BASEPATH, matchedRouteIds),\n [DEV_STYLES_ATTR]: true,\n },\n ],\n })\n }\n\n const manifestRoutes: Record<string, ServerManifestRoute> = {}\n\n for (const k in routes) {\n const v = routes[k]!\n const result = {} as ServerManifestRoute\n\n if (v.preloads && v.preloads.length > 0) {\n result.preloads = v.preloads\n }\n if (v.scripts && v.scripts.length > 0) {\n result.scripts = v.scripts\n }\n if (v.css?.length) {\n result.css = v.css\n }\n if (result.preloads || result.scripts || result.css) {\n manifestRoutes[k] = result\n }\n }\n\n const manifest = {\n ...(startManifest.scriptFormat\n ? { scriptFormat: startManifest.scriptFormat }\n : {}),\n ...(startManifest.inlineCss ? { inlineCss: startManifest.inlineCss } : {}),\n routes: manifestRoutes,\n }\n\n return manifest\n}\n"],"mappings":";;AAcA,IAAM,0BAA0B,QAAQ,IAAI,+BAA+B;;;;;;;;;;AAU3E,eAAsB,iBACpB,eACyB;CACzB,MAAM,EAAE,qBAAqB,MAAM,OAAO;CAC1C,MAAM,gBAAgB,iBAAiB;CACvC,IAAI,SAAS,cAAc;CAC3B,IAAI,YAAY,OAAO;CAEvB,MAAM,mBAAmB,kBAAuC;EAC9D,YAAY;EACZ,SAAS;GACP,GAAG;IACF,cAAc;EACjB;CACF;CAGA,IACE,QAAQ,IAAI,mBAAmB,UAC/B,QAAQ,IAAI,+BAA+B,WAC3C,eACA;EACA,MAAM,kBAAkB,cAAc,KAAK,UAAU,MAAM,EAAE;EAC7D,gBAAgB;GACd,GAAG;GACH,KAAK,CACH,GAAI,WAAW,OAAO,CAAC,GACvB;IACE,MAAM,kBAAkB,yBAAyB,eAAe;KAC/D,kBAAkB;GACrB,CACF;EACF,CAAC;CACH;CAEA,MAAM,iBAAsD,CAAC;CAE7D,KAAK,MAAM,KAAK,QAAQ;EACtB,MAAM,IAAI,OAAO;EACjB,MAAM,SAAS,CAAC;EAEhB,IAAI,EAAE,YAAY,EAAE,SAAS,SAAS,GACpC,OAAO,WAAW,EAAE;EAEtB,IAAI,EAAE,WAAW,EAAE,QAAQ,SAAS,GAClC,OAAO,UAAU,EAAE;EAErB,IAAI,EAAE,KAAK,QACT,OAAO,MAAM,EAAE;EAEjB,IAAI,OAAO,YAAY,OAAO,WAAW,OAAO,KAC9C,eAAe,KAAK;CAExB;CAUA,OAAO;EAPL,GAAI,cAAc,eACd,EAAE,cAAc,cAAc,aAAa,IAC3C,CAAC;EACL,GAAI,cAAc,YAAY,EAAE,WAAW,cAAc,UAAU,IAAI,CAAC;EACxE,QAAQ;CAGH;AACT"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AssetCrossOrigin, Awaitable,
|
|
1
|
+
import { AssetCrossOrigin, Awaitable, ServerManifest } from '@tanstack/router-core';
|
|
2
2
|
export type { AssetCrossOrigin };
|
|
3
3
|
export type TransformAssetsContext = {
|
|
4
4
|
url: string;
|
|
@@ -110,25 +110,16 @@ export type ResolvedTransformAssetsConfig = {
|
|
|
110
110
|
cache: boolean;
|
|
111
111
|
};
|
|
112
112
|
export declare function resolveTransformAssetsConfig(transform: TransformAssets): ResolvedTransformAssetsConfig;
|
|
113
|
-
export
|
|
114
|
-
manifest: ServerManifest;
|
|
115
|
-
clientEntry: string;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Builds the client entry `<script>` tag from a (possibly transformed) client
|
|
119
|
-
* entry URL.
|
|
120
|
-
*/
|
|
121
|
-
export declare function buildClientEntryScriptTag(clientEntry: string, scriptFormat?: ScriptFormat, crossOrigin?: AssetCrossOrigin): ManifestScript;
|
|
122
|
-
export declare function transformManifestAssets(source: StartManifestWithClientEntry, transformFn: TransformAssetsFn, _opts?: {
|
|
113
|
+
export declare function transformManifestAssets(source: ServerManifest, transformFn: TransformAssetsFn, _opts?: {
|
|
123
114
|
clone?: boolean;
|
|
124
115
|
inlineCss?: boolean;
|
|
125
116
|
}): Promise<ServerManifest>;
|
|
126
117
|
/**
|
|
127
|
-
* Builds a final ServerManifest
|
|
128
|
-
*
|
|
118
|
+
* Builds a final ServerManifest without URL transforms. Used when no
|
|
119
|
+
* transformAssets option is provided.
|
|
129
120
|
*
|
|
130
121
|
* Returns a new manifest object so the cached base manifest is never mutated.
|
|
131
122
|
*/
|
|
132
|
-
export declare function
|
|
123
|
+
export declare function buildManifest(source: ServerManifest, opts?: {
|
|
133
124
|
inlineCss?: boolean;
|
|
134
125
|
}): ServerManifest;
|