@tanstack/start-server-core 1.166.9 → 1.166.10
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/constants.js +6 -7
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/createServerRpc.js +12 -11
- package/dist/esm/createServerRpc.js.map +1 -1
- package/dist/esm/createSsrRpc.js +17 -17
- package/dist/esm/createSsrRpc.js.map +1 -1
- package/dist/esm/createStartHandler.js +345 -407
- package/dist/esm/createStartHandler.js.map +1 -1
- package/dist/esm/fake-start-server-fn-resolver.js +6 -6
- package/dist/esm/fake-start-server-fn-resolver.js.map +1 -1
- package/dist/esm/frame-protocol.js +141 -127
- package/dist/esm/frame-protocol.js.map +1 -1
- package/dist/esm/getServerFnById.js +2 -0
- package/dist/esm/index.js +4 -42
- package/dist/esm/request-response.js +176 -185
- package/dist/esm/request-response.js.map +1 -1
- package/dist/esm/router-manifest.js +57 -53
- package/dist/esm/router-manifest.js.map +1 -1
- package/dist/esm/serializer/ServerFunctionSerializationAdapter.js +21 -22
- package/dist/esm/serializer/ServerFunctionSerializationAdapter.js.map +1 -1
- package/dist/esm/server-functions-handler.js +193 -269
- package/dist/esm/server-functions-handler.js.map +1 -1
- package/dist/esm/transformAssetUrls.js +93 -104
- package/dist/esm/transformAssetUrls.js.map +1 -1
- package/dist/esm/virtual-modules.js +9 -8
- package/dist/esm/virtual-modules.js.map +1 -1
- package/package.json +5 -5
- package/dist/esm/index.js.map +0 -1
|
@@ -1,439 +1,377 @@
|
|
|
1
|
-
import { createMemoryHistory } from "@tanstack/history";
|
|
2
|
-
import { flattenMiddlewares, createNullProtoObject, mergeHeaders, safeObjectMerge } from "@tanstack/start-client-core";
|
|
3
|
-
import { isRedirect, isResolvedRedirect, executeRewriteInput } from "@tanstack/router-core";
|
|
4
|
-
import { getNormalizedURL, getOrigin, attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
|
|
5
|
-
import { runWithStartContext } from "@tanstack/start-storage-context";
|
|
6
1
|
import { requestHandler } from "./request-response.js";
|
|
7
2
|
import { getStartManifest } from "./router-manifest.js";
|
|
8
3
|
import { handleServerAction } from "./server-functions-handler.js";
|
|
9
|
-
import { resolveTransformConfig, transformManifestUrls
|
|
4
|
+
import { buildManifestWithClientEntry, resolveTransformConfig, transformManifestUrls } from "./transformAssetUrls.js";
|
|
10
5
|
import { HEADERS } from "./constants.js";
|
|
11
6
|
import { ServerFunctionSerializationAdapter } from "./serializer/ServerFunctionSerializationAdapter.js";
|
|
7
|
+
import { createMemoryHistory } from "@tanstack/history";
|
|
8
|
+
import { createNullProtoObject, flattenMiddlewares, mergeHeaders, safeObjectMerge } from "@tanstack/start-client-core";
|
|
9
|
+
import { executeRewriteInput, isRedirect, isResolvedRedirect } from "@tanstack/router-core";
|
|
10
|
+
import { attachRouterServerSsrUtils, getNormalizedURL, getOrigin } from "@tanstack/router-core/ssr/server";
|
|
11
|
+
import { runWithStartContext } from "@tanstack/start-storage-context";
|
|
12
|
+
//#region src/createStartHandler.ts
|
|
12
13
|
function getStartResponseHeaders(opts) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
...opts.router.state.matches.map((match) => {
|
|
18
|
-
return match.headers;
|
|
19
|
-
})
|
|
20
|
-
);
|
|
21
|
-
return headers;
|
|
14
|
+
return mergeHeaders({ "Content-Type": "text/html; charset=utf-8" }, ...opts.router.state.matches.map((match) => {
|
|
15
|
+
return match.headers;
|
|
16
|
+
}));
|
|
22
17
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
var entriesPromise;
|
|
19
|
+
var baseManifestPromise;
|
|
20
|
+
/**
|
|
21
|
+
* Cached final manifest (with client entry script tag). In production,
|
|
22
|
+
* this is computed once and reused for every request when caching is enabled.
|
|
23
|
+
*/
|
|
24
|
+
var cachedFinalManifestPromise;
|
|
26
25
|
async function loadEntries() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const routerEntry = await import("#tanstack-router-entry");
|
|
27
|
+
return {
|
|
28
|
+
startEntry: await import("#tanstack-start-entry"),
|
|
29
|
+
routerEntry
|
|
30
|
+
};
|
|
30
31
|
}
|
|
31
32
|
function getEntries() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
return entriesPromise;
|
|
33
|
+
if (!entriesPromise) entriesPromise = loadEntries();
|
|
34
|
+
return entriesPromise;
|
|
36
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the raw manifest data (without client entry script tag baked in).
|
|
38
|
+
* In dev mode, always returns fresh data. In prod, cached.
|
|
39
|
+
*/
|
|
37
40
|
function getBaseManifest(matchedRoutes) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!baseManifestPromise) {
|
|
42
|
-
baseManifestPromise = getStartManifest();
|
|
43
|
-
}
|
|
44
|
-
return baseManifestPromise;
|
|
41
|
+
if (process.env.TSS_DEV_SERVER === "true") return getStartManifest(matchedRoutes);
|
|
42
|
+
if (!baseManifestPromise) baseManifestPromise = getStartManifest();
|
|
43
|
+
return baseManifestPromise;
|
|
45
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolves a final Manifest for a given request.
|
|
47
|
+
*
|
|
48
|
+
* - No transform: builds client entry script tag and returns (cached in prod).
|
|
49
|
+
* - Cached transform: transforms all URLs + builds script tag, caches result.
|
|
50
|
+
* - Per-request transform: deep-clones base manifest, transforms per-request.
|
|
51
|
+
*/
|
|
46
52
|
async function resolveManifest(matchedRoutes, transformFn, cache) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
return cachedFinalManifestPromise;
|
|
59
|
-
}
|
|
60
|
-
return computeFinalManifest();
|
|
53
|
+
const base = await getBaseManifest(matchedRoutes);
|
|
54
|
+
const computeFinalManifest = async () => {
|
|
55
|
+
return transformFn ? await transformManifestUrls(base, transformFn, { clone: !cache }) : buildManifestWithClientEntry(base);
|
|
56
|
+
};
|
|
57
|
+
if (process.env.TSS_DEV_SERVER === "true") return computeFinalManifest();
|
|
58
|
+
if (!transformFn || cache) {
|
|
59
|
+
if (!cachedFinalManifestPromise) cachedFinalManifestPromise = computeFinalManifest();
|
|
60
|
+
return cachedFinalManifestPromise;
|
|
61
|
+
}
|
|
62
|
+
return computeFinalManifest();
|
|
61
63
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
var ROUTER_BASEPATH = process.env.TSS_ROUTER_BASEPATH || "/";
|
|
65
|
+
var SERVER_FN_BASE = process.env.TSS_SERVER_FN_BASE;
|
|
66
|
+
var IS_PRERENDERING = process.env.TSS_PRERENDERING === "true";
|
|
67
|
+
var IS_SHELL_ENV = process.env.TSS_SHELL === "true";
|
|
68
|
+
var IS_DEV = process.env.NODE_ENV === "development";
|
|
69
|
+
var ERR_NO_RESPONSE = IS_DEV ? `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.` : "Internal Server Error";
|
|
70
|
+
var ERR_NO_DEFER = IS_DEV ? `You cannot defer to the app router if there is no component defined on this route.` : "Internal Server Error";
|
|
69
71
|
function throwRouteHandlerError() {
|
|
70
|
-
|
|
72
|
+
throw new Error(ERR_NO_RESPONSE);
|
|
71
73
|
}
|
|
72
74
|
function throwIfMayNotDefer() {
|
|
73
|
-
|
|
75
|
+
throw new Error(ERR_NO_DEFER);
|
|
74
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Check if a value is a special response (Response or Redirect)
|
|
79
|
+
*/
|
|
75
80
|
function isSpecialResponse(value) {
|
|
76
|
-
|
|
81
|
+
return value instanceof Response || isRedirect(value);
|
|
77
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Normalize middleware result to context shape
|
|
85
|
+
*/
|
|
78
86
|
function handleCtxResult(result) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
return result;
|
|
87
|
+
if (isSpecialResponse(result)) return { response: result };
|
|
88
|
+
return result;
|
|
83
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Execute a middleware chain
|
|
92
|
+
*/
|
|
84
93
|
function executeMiddleware(middlewares, ctx) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (normalized.context) {
|
|
116
|
-
ctx.context = safeObjectMerge(ctx.context, normalized.context);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return ctx;
|
|
120
|
-
};
|
|
121
|
-
return next();
|
|
94
|
+
let index = -1;
|
|
95
|
+
const next = async (nextCtx) => {
|
|
96
|
+
if (nextCtx) {
|
|
97
|
+
if (nextCtx.context) ctx.context = safeObjectMerge(ctx.context, nextCtx.context);
|
|
98
|
+
for (const key of Object.keys(nextCtx)) if (key !== "context") ctx[key] = nextCtx[key];
|
|
99
|
+
}
|
|
100
|
+
index++;
|
|
101
|
+
const middleware = middlewares[index];
|
|
102
|
+
if (!middleware) return ctx;
|
|
103
|
+
let result;
|
|
104
|
+
try {
|
|
105
|
+
result = await middleware({
|
|
106
|
+
...ctx,
|
|
107
|
+
next
|
|
108
|
+
});
|
|
109
|
+
} catch (err) {
|
|
110
|
+
if (isSpecialResponse(err)) {
|
|
111
|
+
ctx.response = err;
|
|
112
|
+
return ctx;
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
const normalized = handleCtxResult(result);
|
|
117
|
+
if (normalized) {
|
|
118
|
+
if (normalized.response !== void 0) ctx.response = normalized.response;
|
|
119
|
+
if (normalized.context) ctx.context = safeObjectMerge(ctx.context, normalized.context);
|
|
120
|
+
}
|
|
121
|
+
return ctx;
|
|
122
|
+
};
|
|
123
|
+
return next();
|
|
122
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Wrap a route handler as middleware
|
|
127
|
+
*/
|
|
123
128
|
function handlerToMiddleware(handler, mayDefer = false) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
};
|
|
129
|
+
if (mayDefer) return handler;
|
|
130
|
+
return async (ctx) => {
|
|
131
|
+
const response = await handler({
|
|
132
|
+
...ctx,
|
|
133
|
+
next: throwIfMayNotDefer
|
|
134
|
+
});
|
|
135
|
+
if (!response) throwRouteHandlerError();
|
|
136
|
+
return response;
|
|
137
|
+
};
|
|
134
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Creates the TanStack Start request handler.
|
|
141
|
+
*
|
|
142
|
+
* @example Backwards-compatible usage (handler callback only):
|
|
143
|
+
* ```ts
|
|
144
|
+
* export default createStartHandler(defaultStreamHandler)
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @example With CDN URL rewriting:
|
|
148
|
+
* ```ts
|
|
149
|
+
* export default createStartHandler({
|
|
150
|
+
* handler: defaultStreamHandler,
|
|
151
|
+
* transformAssetUrls: 'https://cdn.example.com',
|
|
152
|
+
* })
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* @example With per-request URL rewriting:
|
|
156
|
+
* ```ts
|
|
157
|
+
* export default createStartHandler({
|
|
158
|
+
* handler: defaultStreamHandler,
|
|
159
|
+
* transformAssetUrls: {
|
|
160
|
+
* transform: ({ url }) => {
|
|
161
|
+
* const cdnBase = getRequest().headers.get('x-cdn-base') || ''
|
|
162
|
+
* return `${cdnBase}${url}`
|
|
163
|
+
* },
|
|
164
|
+
* cache: false,
|
|
165
|
+
* },
|
|
166
|
+
* })
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
135
169
|
function createStartHandler(cbOrOptions) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
await routerInstance.serverSsr.dehydrate();
|
|
281
|
-
const responseHeaders = getStartResponseHeaders({
|
|
282
|
-
router: routerInstance
|
|
283
|
-
});
|
|
284
|
-
cbWillCleanup = true;
|
|
285
|
-
return cb({
|
|
286
|
-
request,
|
|
287
|
-
router: routerInstance,
|
|
288
|
-
responseHeaders
|
|
289
|
-
});
|
|
290
|
-
};
|
|
291
|
-
const requestHandlerMiddleware = async ({ context }) => {
|
|
292
|
-
return runWithStartContext(
|
|
293
|
-
{
|
|
294
|
-
getRouter,
|
|
295
|
-
startOptions: requestStartOptions,
|
|
296
|
-
contextAfterGlobalMiddlewares: context,
|
|
297
|
-
request,
|
|
298
|
-
executedRequestMiddlewares
|
|
299
|
-
},
|
|
300
|
-
async () => {
|
|
301
|
-
try {
|
|
302
|
-
return await handleServerRoutes({
|
|
303
|
-
getRouter,
|
|
304
|
-
request,
|
|
305
|
-
url,
|
|
306
|
-
executeRouter,
|
|
307
|
-
context,
|
|
308
|
-
executedRequestMiddlewares
|
|
309
|
-
});
|
|
310
|
-
} catch (err) {
|
|
311
|
-
if (err instanceof Response) {
|
|
312
|
-
return err;
|
|
313
|
-
}
|
|
314
|
-
throw err;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
);
|
|
318
|
-
};
|
|
319
|
-
const middlewares = flattenedRequestMiddlewares.map(
|
|
320
|
-
(d) => d.options.server
|
|
321
|
-
);
|
|
322
|
-
const ctx = await executeMiddleware(
|
|
323
|
-
[...middlewares, requestHandlerMiddleware],
|
|
324
|
-
{
|
|
325
|
-
request,
|
|
326
|
-
pathname: url.pathname,
|
|
327
|
-
context: createNullProtoObject(requestOpts?.context)
|
|
328
|
-
}
|
|
329
|
-
);
|
|
330
|
-
return handleRedirectResponse(ctx.response, request, getRouter);
|
|
331
|
-
} finally {
|
|
332
|
-
if (router && !cbWillCleanup) {
|
|
333
|
-
router.serverSsr?.cleanup();
|
|
334
|
-
}
|
|
335
|
-
router = null;
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
return requestHandler(startRequestResolver);
|
|
170
|
+
const cb = typeof cbOrOptions === "function" ? cbOrOptions : cbOrOptions.handler;
|
|
171
|
+
const transformAssetUrlsOption = typeof cbOrOptions === "function" ? void 0 : cbOrOptions.transformAssetUrls;
|
|
172
|
+
const warmupTransformManifest = !!transformAssetUrlsOption && typeof transformAssetUrlsOption === "object" && transformAssetUrlsOption.warmup === true;
|
|
173
|
+
const resolvedTransformConfig = transformAssetUrlsOption ? resolveTransformConfig(transformAssetUrlsOption) : void 0;
|
|
174
|
+
const cache = resolvedTransformConfig ? resolvedTransformConfig.cache : true;
|
|
175
|
+
let cachedCreateTransformPromise;
|
|
176
|
+
const getTransformFn = async (opts) => {
|
|
177
|
+
if (!resolvedTransformConfig) return void 0;
|
|
178
|
+
if (resolvedTransformConfig.type === "createTransform") {
|
|
179
|
+
if (cache) {
|
|
180
|
+
if (!cachedCreateTransformPromise) cachedCreateTransformPromise = Promise.resolve(resolvedTransformConfig.createTransform(opts));
|
|
181
|
+
return cachedCreateTransformPromise;
|
|
182
|
+
}
|
|
183
|
+
return resolvedTransformConfig.createTransform(opts);
|
|
184
|
+
}
|
|
185
|
+
return resolvedTransformConfig.transformFn;
|
|
186
|
+
};
|
|
187
|
+
if (warmupTransformManifest && cache && process.env.TSS_DEV_SERVER !== "true" && !cachedFinalManifestPromise) {
|
|
188
|
+
const warmupPromise = (async () => {
|
|
189
|
+
const base = await getBaseManifest(void 0);
|
|
190
|
+
const transformFn = await getTransformFn({ warmup: true });
|
|
191
|
+
return transformFn ? await transformManifestUrls(base, transformFn, { clone: false }) : buildManifestWithClientEntry(base);
|
|
192
|
+
})();
|
|
193
|
+
cachedFinalManifestPromise = warmupPromise;
|
|
194
|
+
warmupPromise.catch(() => {
|
|
195
|
+
if (cachedFinalManifestPromise === warmupPromise) cachedFinalManifestPromise = void 0;
|
|
196
|
+
cachedCreateTransformPromise = void 0;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
const startRequestResolver = async (request, requestOpts) => {
|
|
200
|
+
let router = null;
|
|
201
|
+
let cbWillCleanup = false;
|
|
202
|
+
try {
|
|
203
|
+
const { url, handledProtocolRelativeURL } = getNormalizedURL(request.url);
|
|
204
|
+
const href = url.pathname + url.search + url.hash;
|
|
205
|
+
const origin = getOrigin(request);
|
|
206
|
+
if (handledProtocolRelativeURL) return Response.redirect(url, 308);
|
|
207
|
+
const entries = await getEntries();
|
|
208
|
+
const startOptions = await entries.startEntry.startInstance?.getOptions() || {};
|
|
209
|
+
const serializationAdapters = [...startOptions.serializationAdapters || [], ServerFunctionSerializationAdapter];
|
|
210
|
+
const requestStartOptions = {
|
|
211
|
+
...startOptions,
|
|
212
|
+
serializationAdapters
|
|
213
|
+
};
|
|
214
|
+
const flattenedRequestMiddlewares = startOptions.requestMiddleware ? flattenMiddlewares(startOptions.requestMiddleware) : [];
|
|
215
|
+
const executedRequestMiddlewares = new Set(flattenedRequestMiddlewares);
|
|
216
|
+
const getRouter = async () => {
|
|
217
|
+
if (router) return router;
|
|
218
|
+
router = await entries.routerEntry.getRouter();
|
|
219
|
+
let isShell = IS_SHELL_ENV;
|
|
220
|
+
if (IS_PRERENDERING && !isShell) isShell = request.headers.get(HEADERS.TSS_SHELL) === "true";
|
|
221
|
+
const history = createMemoryHistory({ initialEntries: [href] });
|
|
222
|
+
router.update({
|
|
223
|
+
history,
|
|
224
|
+
isShell,
|
|
225
|
+
isPrerendering: IS_PRERENDERING,
|
|
226
|
+
origin: router.options.origin ?? origin,
|
|
227
|
+
defaultSsr: requestStartOptions.defaultSsr,
|
|
228
|
+
serializationAdapters: [...requestStartOptions.serializationAdapters, ...router.options.serializationAdapters || []],
|
|
229
|
+
basepath: ROUTER_BASEPATH
|
|
230
|
+
});
|
|
231
|
+
return router;
|
|
232
|
+
};
|
|
233
|
+
if (SERVER_FN_BASE && url.pathname.startsWith(SERVER_FN_BASE)) {
|
|
234
|
+
const serverFnId = url.pathname.slice(SERVER_FN_BASE.length).split("/")[0];
|
|
235
|
+
if (!serverFnId) throw new Error("Invalid server action param for serverFnId");
|
|
236
|
+
const serverFnHandler = async ({ context }) => {
|
|
237
|
+
return runWithStartContext({
|
|
238
|
+
getRouter,
|
|
239
|
+
startOptions: requestStartOptions,
|
|
240
|
+
contextAfterGlobalMiddlewares: context,
|
|
241
|
+
request,
|
|
242
|
+
executedRequestMiddlewares
|
|
243
|
+
}, () => handleServerAction({
|
|
244
|
+
request,
|
|
245
|
+
context: requestOpts?.context,
|
|
246
|
+
serverFnId
|
|
247
|
+
}));
|
|
248
|
+
};
|
|
249
|
+
return handleRedirectResponse((await executeMiddleware([...flattenedRequestMiddlewares.map((d) => d.options.server), serverFnHandler], {
|
|
250
|
+
request,
|
|
251
|
+
pathname: url.pathname,
|
|
252
|
+
context: createNullProtoObject(requestOpts?.context)
|
|
253
|
+
})).response, request, getRouter);
|
|
254
|
+
}
|
|
255
|
+
const executeRouter = async (serverContext, matchedRoutes) => {
|
|
256
|
+
const acceptParts = (request.headers.get("Accept") || "*/*").split(",");
|
|
257
|
+
if (!["*/*", "text/html"].some((mimeType) => acceptParts.some((part) => part.trim().startsWith(mimeType)))) return Response.json({ error: "Only HTML requests are supported here" }, { status: 500 });
|
|
258
|
+
const manifest = await resolveManifest(matchedRoutes, await getTransformFn({
|
|
259
|
+
warmup: false,
|
|
260
|
+
request
|
|
261
|
+
}), cache);
|
|
262
|
+
const routerInstance = await getRouter();
|
|
263
|
+
attachRouterServerSsrUtils({
|
|
264
|
+
router: routerInstance,
|
|
265
|
+
manifest
|
|
266
|
+
});
|
|
267
|
+
routerInstance.update({ additionalContext: { serverContext } });
|
|
268
|
+
await routerInstance.load();
|
|
269
|
+
if (routerInstance.state.redirect) return routerInstance.state.redirect;
|
|
270
|
+
await routerInstance.serverSsr.dehydrate();
|
|
271
|
+
const responseHeaders = getStartResponseHeaders({ router: routerInstance });
|
|
272
|
+
cbWillCleanup = true;
|
|
273
|
+
return cb({
|
|
274
|
+
request,
|
|
275
|
+
router: routerInstance,
|
|
276
|
+
responseHeaders
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
const requestHandlerMiddleware = async ({ context }) => {
|
|
280
|
+
return runWithStartContext({
|
|
281
|
+
getRouter,
|
|
282
|
+
startOptions: requestStartOptions,
|
|
283
|
+
contextAfterGlobalMiddlewares: context,
|
|
284
|
+
request,
|
|
285
|
+
executedRequestMiddlewares
|
|
286
|
+
}, async () => {
|
|
287
|
+
try {
|
|
288
|
+
return await handleServerRoutes({
|
|
289
|
+
getRouter,
|
|
290
|
+
request,
|
|
291
|
+
url,
|
|
292
|
+
executeRouter,
|
|
293
|
+
context,
|
|
294
|
+
executedRequestMiddlewares
|
|
295
|
+
});
|
|
296
|
+
} catch (err) {
|
|
297
|
+
if (err instanceof Response) return err;
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
return handleRedirectResponse((await executeMiddleware([...flattenedRequestMiddlewares.map((d) => d.options.server), requestHandlerMiddleware], {
|
|
303
|
+
request,
|
|
304
|
+
pathname: url.pathname,
|
|
305
|
+
context: createNullProtoObject(requestOpts?.context)
|
|
306
|
+
})).response, request, getRouter);
|
|
307
|
+
} finally {
|
|
308
|
+
if (router && !cbWillCleanup) router.serverSsr?.cleanup();
|
|
309
|
+
router = null;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
return requestHandler(startRequestResolver);
|
|
339
313
|
}
|
|
340
314
|
async function handleRedirectResponse(response, request, getRouter) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
throw new Error(
|
|
363
|
-
`Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys(
|
|
364
|
-
opts
|
|
365
|
-
).filter((d) => typeof opts[d] === "function").map((d) => `"${d}"`).join(", ")}`
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
const router = await getRouter();
|
|
369
|
-
const redirect = router.resolveRedirect(response);
|
|
370
|
-
if (request.headers.get("x-tsr-serverFn") === "true") {
|
|
371
|
-
return Response.json(
|
|
372
|
-
{ ...response.options, isSerializedRedirect: true },
|
|
373
|
-
{ headers: response.headers }
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
return redirect;
|
|
315
|
+
if (!isRedirect(response)) return response;
|
|
316
|
+
if (isResolvedRedirect(response)) {
|
|
317
|
+
if (request.headers.get("x-tsr-serverFn") === "true") return Response.json({
|
|
318
|
+
...response.options,
|
|
319
|
+
isSerializedRedirect: true
|
|
320
|
+
}, { headers: response.headers });
|
|
321
|
+
return response;
|
|
322
|
+
}
|
|
323
|
+
const opts = response.options;
|
|
324
|
+
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)}`);
|
|
325
|
+
if ([
|
|
326
|
+
"params",
|
|
327
|
+
"search",
|
|
328
|
+
"hash"
|
|
329
|
+
].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(", ")}`);
|
|
330
|
+
const redirect = (await getRouter()).resolveRedirect(response);
|
|
331
|
+
if (request.headers.get("x-tsr-serverFn") === "true") return Response.json({
|
|
332
|
+
...response.options,
|
|
333
|
+
isSerializedRedirect: true
|
|
334
|
+
}, { headers: response.headers });
|
|
335
|
+
return redirect;
|
|
377
336
|
}
|
|
378
|
-
async function handleServerRoutes({
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const handlerMiddlewares = flattenMiddlewares(handler.middleware);
|
|
415
|
-
for (const m of handlerMiddlewares) {
|
|
416
|
-
routeMiddlewares.push(m.options.server);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
if (handler.handler) {
|
|
420
|
-
routeMiddlewares.push(handlerToMiddleware(handler.handler, mayDefer));
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
routeMiddlewares.push(
|
|
426
|
-
(ctx2) => executeRouter(ctx2.context, matchedRoutes)
|
|
427
|
-
);
|
|
428
|
-
const ctx = await executeMiddleware(routeMiddlewares, {
|
|
429
|
-
request,
|
|
430
|
-
context,
|
|
431
|
-
params: routeParams,
|
|
432
|
-
pathname
|
|
433
|
-
});
|
|
434
|
-
return ctx.response;
|
|
337
|
+
async function handleServerRoutes({ getRouter, request, url, executeRouter, context, executedRequestMiddlewares }) {
|
|
338
|
+
const router = await getRouter();
|
|
339
|
+
const pathname = executeRewriteInput(router.rewrite, url).pathname;
|
|
340
|
+
const { matchedRoutes, foundRoute, routeParams } = router.getMatchedRoutes(pathname);
|
|
341
|
+
const isExactMatch = foundRoute && routeParams["**"] === void 0;
|
|
342
|
+
const routeMiddlewares = [];
|
|
343
|
+
for (const route of matchedRoutes) {
|
|
344
|
+
const serverMiddleware = route.options.server?.middleware;
|
|
345
|
+
if (serverMiddleware) {
|
|
346
|
+
const flattened = flattenMiddlewares(serverMiddleware);
|
|
347
|
+
for (const m of flattened) if (!executedRequestMiddlewares.has(m)) routeMiddlewares.push(m.options.server);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const server = foundRoute?.options.server;
|
|
351
|
+
if (server?.handlers && isExactMatch) {
|
|
352
|
+
const handlers = typeof server.handlers === "function" ? server.handlers({ createHandlers: (d) => d }) : server.handlers;
|
|
353
|
+
const handler = handlers[request.method.toUpperCase()] ?? handlers["ANY"];
|
|
354
|
+
if (handler) {
|
|
355
|
+
const mayDefer = !!foundRoute.options.component;
|
|
356
|
+
if (typeof handler === "function") routeMiddlewares.push(handlerToMiddleware(handler, mayDefer));
|
|
357
|
+
else {
|
|
358
|
+
if (handler.middleware?.length) {
|
|
359
|
+
const handlerMiddlewares = flattenMiddlewares(handler.middleware);
|
|
360
|
+
for (const m of handlerMiddlewares) routeMiddlewares.push(m.options.server);
|
|
361
|
+
}
|
|
362
|
+
if (handler.handler) routeMiddlewares.push(handlerToMiddleware(handler.handler, mayDefer));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
routeMiddlewares.push((ctx) => executeRouter(ctx.context, matchedRoutes));
|
|
367
|
+
return (await executeMiddleware(routeMiddlewares, {
|
|
368
|
+
request,
|
|
369
|
+
context,
|
|
370
|
+
params: routeParams,
|
|
371
|
+
pathname
|
|
372
|
+
})).response;
|
|
435
373
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
//# sourceMappingURL=createStartHandler.js.map
|
|
374
|
+
//#endregion
|
|
375
|
+
export { createStartHandler };
|
|
376
|
+
|
|
377
|
+
//# sourceMappingURL=createStartHandler.js.map
|