@tanstack/start-server-core 1.143.9 → 1.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/createStartHandler.js +268 -257
- package/dist/esm/createStartHandler.js.map +1 -1
- package/dist/esm/frame-protocol.d.ts +32 -0
- package/dist/esm/frame-protocol.js +139 -0
- package/dist/esm/frame-protocol.js.map +1 -0
- package/dist/esm/server-functions-handler.d.ts +2 -1
- package/dist/esm/server-functions-handler.js +147 -93
- package/dist/esm/server-functions-handler.js.map +1 -1
- package/package.json +4 -4
- package/src/createStartHandler.ts +386 -343
- package/src/frame-protocol.ts +216 -0
- package/src/server-functions-handler.ts +182 -103
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createMemoryHistory } from "@tanstack/history";
|
|
2
|
-
import { flattenMiddlewares, mergeHeaders } from "@tanstack/start-client-core";
|
|
2
|
+
import { flattenMiddlewares, createNullProtoObject, mergeHeaders, safeObjectMerge } from "@tanstack/start-client-core";
|
|
3
3
|
import { isRedirect, isResolvedRedirect, executeRewriteInput } from "@tanstack/router-core";
|
|
4
4
|
import { getOrigin, attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
|
|
5
5
|
import { runWithStartContext } from "@tanstack/start-storage-context";
|
|
@@ -19,31 +19,110 @@ function getStartResponseHeaders(opts) {
|
|
|
19
19
|
);
|
|
20
20
|
return headers;
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
let cachedStartEntry = null;
|
|
23
|
+
let cachedRouterEntry = null;
|
|
24
|
+
let cachedManifest = null;
|
|
25
|
+
async function getEntries() {
|
|
26
|
+
if (cachedRouterEntry === null) {
|
|
27
|
+
cachedRouterEntry = await import("#tanstack-router-entry");
|
|
28
|
+
}
|
|
29
|
+
if (cachedStartEntry === null) {
|
|
30
|
+
cachedStartEntry = await import("#tanstack-start-entry");
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
startEntry: cachedStartEntry,
|
|
34
|
+
routerEntry: cachedRouterEntry
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function getManifest() {
|
|
38
|
+
if (cachedManifest === null) {
|
|
39
|
+
cachedManifest = await getStartManifest();
|
|
40
|
+
}
|
|
41
|
+
return cachedManifest;
|
|
42
|
+
}
|
|
43
|
+
const ROUTER_BASEPATH = process.env.TSS_ROUTER_BASEPATH || "/";
|
|
44
|
+
const SERVER_FN_BASE = process.env.TSS_SERVER_FN_BASE;
|
|
45
|
+
const IS_PRERENDERING = process.env.TSS_PRERENDERING === "true";
|
|
46
|
+
const IS_SHELL_ENV = process.env.TSS_SHELL === "true";
|
|
47
|
+
const IS_DEV = process.env.NODE_ENV === "development";
|
|
48
|
+
const 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";
|
|
49
|
+
const ERR_NO_DEFER = IS_DEV ? `You cannot defer to the app router if there is no component defined on this route.` : "Internal Server Error";
|
|
50
|
+
function throwRouteHandlerError() {
|
|
51
|
+
throw new Error(ERR_NO_RESPONSE);
|
|
52
|
+
}
|
|
53
|
+
function throwIfMayNotDefer() {
|
|
54
|
+
throw new Error(ERR_NO_DEFER);
|
|
55
|
+
}
|
|
56
|
+
function isSpecialResponse(value) {
|
|
57
|
+
return value instanceof Response || isRedirect(value);
|
|
58
|
+
}
|
|
59
|
+
function handleCtxResult(result) {
|
|
60
|
+
if (isSpecialResponse(result)) {
|
|
61
|
+
return { response: result };
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
function executeMiddleware(middlewares, ctx) {
|
|
66
|
+
let index = -1;
|
|
67
|
+
const next = async (nextCtx) => {
|
|
68
|
+
if (nextCtx) {
|
|
69
|
+
if (nextCtx.context) {
|
|
70
|
+
ctx.context = safeObjectMerge(ctx.context, nextCtx.context);
|
|
71
|
+
}
|
|
72
|
+
for (const key of Object.keys(nextCtx)) {
|
|
73
|
+
if (key !== "context") {
|
|
74
|
+
ctx[key] = nextCtx[key];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
30
77
|
}
|
|
31
|
-
|
|
32
|
-
|
|
78
|
+
index++;
|
|
79
|
+
const middleware = middlewares[index];
|
|
80
|
+
if (!middleware) return ctx;
|
|
81
|
+
let result;
|
|
82
|
+
try {
|
|
83
|
+
result = await middleware({ ...ctx, next });
|
|
84
|
+
} catch (err) {
|
|
85
|
+
if (isSpecialResponse(err)) {
|
|
86
|
+
ctx.response = err;
|
|
87
|
+
return ctx;
|
|
88
|
+
}
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
const normalized = handleCtxResult(result);
|
|
92
|
+
if (normalized) {
|
|
93
|
+
if (normalized.response !== void 0) {
|
|
94
|
+
ctx.response = normalized.response;
|
|
95
|
+
}
|
|
96
|
+
if (normalized.context) {
|
|
97
|
+
ctx.context = safeObjectMerge(ctx.context, normalized.context);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return ctx;
|
|
101
|
+
};
|
|
102
|
+
return next();
|
|
103
|
+
}
|
|
104
|
+
function handlerToMiddleware(handler, mayDefer = false) {
|
|
105
|
+
if (mayDefer) {
|
|
106
|
+
return handler;
|
|
107
|
+
}
|
|
108
|
+
return async (ctx) => {
|
|
109
|
+
const response = await handler({ ...ctx, next: throwIfMayNotDefer });
|
|
110
|
+
if (!response) {
|
|
111
|
+
throwRouteHandlerError();
|
|
33
112
|
}
|
|
34
|
-
return
|
|
35
|
-
startEntry,
|
|
36
|
-
routerEntry
|
|
37
|
-
};
|
|
113
|
+
return response;
|
|
38
114
|
};
|
|
115
|
+
}
|
|
116
|
+
function createStartHandler(cb) {
|
|
39
117
|
const startRequestResolver = async (request, requestOpts) => {
|
|
40
118
|
let router = null;
|
|
41
119
|
let cbWillCleanup = false;
|
|
42
120
|
try {
|
|
43
|
-
const origin = getOrigin(request);
|
|
44
121
|
const url = new URL(request.url);
|
|
45
122
|
const href = url.href.replace(url.origin, "");
|
|
46
|
-
const
|
|
123
|
+
const origin = getOrigin(request);
|
|
124
|
+
const entries = await getEntries();
|
|
125
|
+
const startOptions = await entries.startEntry.startInstance?.getOptions() || {};
|
|
47
126
|
const serializationAdapters = [
|
|
48
127
|
...startOptions.serializationAdapters || [],
|
|
49
128
|
ServerFunctionSerializationAdapter
|
|
@@ -52,12 +131,15 @@ function createStartHandler(cb) {
|
|
|
52
131
|
...startOptions,
|
|
53
132
|
serializationAdapters
|
|
54
133
|
};
|
|
134
|
+
const flattenedRequestMiddlewares = startOptions.requestMiddleware ? flattenMiddlewares(startOptions.requestMiddleware) : [];
|
|
135
|
+
const executedRequestMiddlewares = new Set(
|
|
136
|
+
flattenedRequestMiddlewares
|
|
137
|
+
);
|
|
55
138
|
const getRouter = async () => {
|
|
56
139
|
if (router) return router;
|
|
57
|
-
router = await
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (isPrerendering && !isShell) {
|
|
140
|
+
router = await entries.routerEntry.getRouter();
|
|
141
|
+
let isShell = IS_SHELL_ENV;
|
|
142
|
+
if (IS_PRERENDERING && !isShell) {
|
|
61
143
|
isShell = request.headers.get(HEADERS.TSS_SHELL) === "true";
|
|
62
144
|
}
|
|
63
145
|
const history = createMemoryHistory({
|
|
@@ -66,7 +148,7 @@ function createStartHandler(cb) {
|
|
|
66
148
|
router.update({
|
|
67
149
|
history,
|
|
68
150
|
isShell,
|
|
69
|
-
isPrerendering,
|
|
151
|
+
isPrerendering: IS_PRERENDERING,
|
|
70
152
|
origin: router.options.origin ?? origin,
|
|
71
153
|
...{
|
|
72
154
|
defaultSsr: requestStartOptions.defaultSsr,
|
|
@@ -79,140 +161,107 @@ function createStartHandler(cb) {
|
|
|
79
161
|
});
|
|
80
162
|
return router;
|
|
81
163
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
164
|
+
if (SERVER_FN_BASE && url.pathname.startsWith(SERVER_FN_BASE)) {
|
|
165
|
+
const serverFnId = url.pathname.slice(SERVER_FN_BASE.length).split("/")[0];
|
|
166
|
+
if (!serverFnId) {
|
|
167
|
+
throw new Error("Invalid server action param for serverFnId");
|
|
168
|
+
}
|
|
169
|
+
const serverFnHandler = async ({ context }) => {
|
|
170
|
+
return runWithStartContext(
|
|
85
171
|
{
|
|
86
172
|
getRouter,
|
|
87
173
|
startOptions: requestStartOptions,
|
|
88
174
|
contextAfterGlobalMiddlewares: context,
|
|
89
|
-
request
|
|
175
|
+
request,
|
|
176
|
+
executedRequestMiddlewares
|
|
90
177
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
context: requestOpts?.context
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
const executeRouter = async ({
|
|
100
|
-
serverContext
|
|
101
|
-
}) => {
|
|
102
|
-
const requestAcceptHeader = request.headers.get("Accept") || "*/*";
|
|
103
|
-
const splitRequestAcceptHeader = requestAcceptHeader.split(",");
|
|
104
|
-
const supportedMimeTypes = ["*/*", "text/html"];
|
|
105
|
-
const isRouterAcceptSupported = supportedMimeTypes.some(
|
|
106
|
-
(mimeType) => splitRequestAcceptHeader.some(
|
|
107
|
-
(acceptedMimeType) => acceptedMimeType.trim().startsWith(mimeType)
|
|
108
|
-
)
|
|
109
|
-
);
|
|
110
|
-
if (!isRouterAcceptSupported) {
|
|
111
|
-
return Response.json(
|
|
112
|
-
{
|
|
113
|
-
error: "Only HTML requests are supported here"
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
status: 500
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
if (startRoutesManifest === null) {
|
|
121
|
-
startRoutesManifest = await getStartManifest();
|
|
122
|
-
}
|
|
123
|
-
const router2 = await getRouter();
|
|
124
|
-
attachRouterServerSsrUtils({
|
|
125
|
-
router: router2,
|
|
126
|
-
manifest: startRoutesManifest
|
|
127
|
-
});
|
|
128
|
-
router2.update({ additionalContext: { serverContext } });
|
|
129
|
-
await router2.load();
|
|
130
|
-
if (router2.state.redirect) {
|
|
131
|
-
return router2.state.redirect;
|
|
132
|
-
}
|
|
133
|
-
await router2.serverSsr.dehydrate();
|
|
134
|
-
const responseHeaders = getStartResponseHeaders({ router: router2 });
|
|
135
|
-
cbWillCleanup = true;
|
|
136
|
-
const response4 = await cb({
|
|
137
|
-
request,
|
|
138
|
-
router: router2,
|
|
139
|
-
responseHeaders
|
|
140
|
-
});
|
|
141
|
-
return response4;
|
|
142
|
-
};
|
|
143
|
-
const response3 = await handleServerRoutes({
|
|
144
|
-
getRouter,
|
|
145
|
-
request,
|
|
146
|
-
executeRouter,
|
|
147
|
-
context
|
|
148
|
-
});
|
|
149
|
-
return response3;
|
|
150
|
-
} catch (err) {
|
|
151
|
-
if (err instanceof Response) {
|
|
152
|
-
return err;
|
|
153
|
-
}
|
|
154
|
-
throw err;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
178
|
+
() => handleServerAction({
|
|
179
|
+
request,
|
|
180
|
+
context: requestOpts?.context,
|
|
181
|
+
serverFnId
|
|
182
|
+
})
|
|
157
183
|
);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const ctx = await executeMiddleware(
|
|
164
|
-
[...middlewares, requestHandlerMiddleware],
|
|
165
|
-
{
|
|
184
|
+
};
|
|
185
|
+
const middlewares2 = flattenedRequestMiddlewares.map(
|
|
186
|
+
(d) => d.options.server
|
|
187
|
+
);
|
|
188
|
+
const ctx2 = await executeMiddleware([...middlewares2, serverFnHandler], {
|
|
166
189
|
request,
|
|
167
|
-
context: requestOpts?.context
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
return response;
|
|
185
|
-
}
|
|
186
|
-
if (response.options.to && typeof response.options.to === "string" && !response.options.to.startsWith("/")) {
|
|
187
|
-
throw new Error(
|
|
188
|
-
`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(response.options)}`
|
|
190
|
+
context: createNullProtoObject(requestOpts?.context)
|
|
191
|
+
});
|
|
192
|
+
return handleRedirectResponse(ctx2.response, request, getRouter);
|
|
193
|
+
}
|
|
194
|
+
const executeRouter = async (serverContext) => {
|
|
195
|
+
const acceptHeader = request.headers.get("Accept") || "*/*";
|
|
196
|
+
const acceptParts = acceptHeader.split(",");
|
|
197
|
+
const supportedMimeTypes = ["*/*", "text/html"];
|
|
198
|
+
const isSupported = supportedMimeTypes.some(
|
|
199
|
+
(mimeType) => acceptParts.some((part) => part.trim().startsWith(mimeType))
|
|
200
|
+
);
|
|
201
|
+
if (!isSupported) {
|
|
202
|
+
return Response.json(
|
|
203
|
+
{ error: "Only HTML requests are supported here" },
|
|
204
|
+
{ status: 500 }
|
|
189
205
|
);
|
|
190
206
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
207
|
+
const manifest = await getManifest();
|
|
208
|
+
const routerInstance = await getRouter();
|
|
209
|
+
attachRouterServerSsrUtils({
|
|
210
|
+
router: routerInstance,
|
|
211
|
+
manifest
|
|
212
|
+
});
|
|
213
|
+
routerInstance.update({ additionalContext: { serverContext } });
|
|
214
|
+
await routerInstance.load();
|
|
215
|
+
if (routerInstance.state.redirect) {
|
|
216
|
+
return routerInstance.state.redirect;
|
|
199
217
|
}
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
218
|
+
await routerInstance.serverSsr.dehydrate();
|
|
219
|
+
const responseHeaders = getStartResponseHeaders({
|
|
220
|
+
router: routerInstance
|
|
221
|
+
});
|
|
222
|
+
cbWillCleanup = true;
|
|
223
|
+
return cb({
|
|
224
|
+
request,
|
|
225
|
+
router: routerInstance,
|
|
226
|
+
responseHeaders
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
const requestHandlerMiddleware = async ({ context }) => {
|
|
230
|
+
return runWithStartContext(
|
|
231
|
+
{
|
|
232
|
+
getRouter,
|
|
233
|
+
startOptions: requestStartOptions,
|
|
234
|
+
contextAfterGlobalMiddlewares: context,
|
|
235
|
+
request,
|
|
236
|
+
executedRequestMiddlewares
|
|
237
|
+
},
|
|
238
|
+
async () => {
|
|
239
|
+
try {
|
|
240
|
+
return await handleServerRoutes({
|
|
241
|
+
getRouter,
|
|
242
|
+
request,
|
|
243
|
+
url,
|
|
244
|
+
executeRouter,
|
|
245
|
+
context,
|
|
246
|
+
executedRequestMiddlewares
|
|
247
|
+
});
|
|
248
|
+
} catch (err) {
|
|
249
|
+
if (err instanceof Response) {
|
|
250
|
+
return err;
|
|
251
|
+
}
|
|
252
|
+
throw err;
|
|
210
253
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
};
|
|
257
|
+
const middlewares = flattenedRequestMiddlewares.map(
|
|
258
|
+
(d) => d.options.server
|
|
259
|
+
);
|
|
260
|
+
const ctx = await executeMiddleware(
|
|
261
|
+
[...middlewares, requestHandlerMiddleware],
|
|
262
|
+
{ request, context: createNullProtoObject(requestOpts?.context) }
|
|
263
|
+
);
|
|
264
|
+
return handleRedirectResponse(ctx.response, request, getRouter);
|
|
216
265
|
} finally {
|
|
217
266
|
if (router && !cbWillCleanup) {
|
|
218
267
|
router.serverSsr?.cleanup();
|
|
@@ -222,137 +271,99 @@ function createStartHandler(cb) {
|
|
|
222
271
|
};
|
|
223
272
|
return requestHandler(startRequestResolver);
|
|
224
273
|
}
|
|
274
|
+
async function handleRedirectResponse(response, request, getRouter) {
|
|
275
|
+
if (!isRedirect(response)) {
|
|
276
|
+
return response;
|
|
277
|
+
}
|
|
278
|
+
if (isResolvedRedirect(response)) {
|
|
279
|
+
if (request.headers.get("x-tsr-serverFn") === "true") {
|
|
280
|
+
return Response.json(
|
|
281
|
+
{ ...response.options, isSerializedRedirect: true },
|
|
282
|
+
{ headers: response.headers }
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
return response;
|
|
286
|
+
}
|
|
287
|
+
const opts = response.options;
|
|
288
|
+
if (opts.to && typeof opts.to === "string" && !opts.to.startsWith("/")) {
|
|
289
|
+
throw new Error(
|
|
290
|
+
`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)}`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
if (["params", "search", "hash"].some(
|
|
294
|
+
(d) => typeof opts[d] === "function"
|
|
295
|
+
)) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys(
|
|
298
|
+
opts
|
|
299
|
+
).filter((d) => typeof opts[d] === "function").map((d) => `"${d}"`).join(", ")}`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
const router = await getRouter();
|
|
303
|
+
const redirect = router.resolveRedirect(response);
|
|
304
|
+
if (request.headers.get("x-tsr-serverFn") === "true") {
|
|
305
|
+
return Response.json(
|
|
306
|
+
{ ...response.options, isSerializedRedirect: true },
|
|
307
|
+
{ headers: response.headers }
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
return redirect;
|
|
311
|
+
}
|
|
225
312
|
async function handleServerRoutes({
|
|
226
313
|
getRouter,
|
|
227
314
|
request,
|
|
315
|
+
url,
|
|
228
316
|
executeRouter,
|
|
229
|
-
context
|
|
317
|
+
context,
|
|
318
|
+
executedRequestMiddlewares
|
|
230
319
|
}) {
|
|
231
320
|
const router = await getRouter();
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const pathname = url.pathname;
|
|
321
|
+
const rewrittenUrl = executeRewriteInput(router.rewrite, url);
|
|
322
|
+
const pathname = rewrittenUrl.pathname;
|
|
235
323
|
const { matchedRoutes, foundRoute, routeParams } = router.getMatchedRoutes(pathname);
|
|
236
324
|
const isExactMatch = foundRoute && routeParams["**"] === void 0;
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
325
|
+
const routeMiddlewares = [];
|
|
326
|
+
for (const route of matchedRoutes) {
|
|
327
|
+
const serverMiddleware = route.options.server?.middleware;
|
|
328
|
+
if (serverMiddleware) {
|
|
329
|
+
const flattened = flattenMiddlewares(serverMiddleware);
|
|
330
|
+
for (const m of flattened) {
|
|
331
|
+
if (!executedRequestMiddlewares.has(m)) {
|
|
332
|
+
routeMiddlewares.push(m.options.server);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
240
337
|
const server = foundRoute?.options.server;
|
|
241
|
-
if (server && isExactMatch) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (middleware && middleware.length) {
|
|
255
|
-
middlewares.push(
|
|
256
|
-
...flattenMiddlewares(middleware).map((d) => d.options.server)
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
if (handler.handler) {
|
|
260
|
-
middlewares.push(handlerToMiddleware(handler.handler, mayDefer));
|
|
338
|
+
if (server?.handlers && isExactMatch) {
|
|
339
|
+
const handlers = typeof server.handlers === "function" ? server.handlers({ createHandlers: (d) => d }) : server.handlers;
|
|
340
|
+
const requestMethod = request.method.toUpperCase();
|
|
341
|
+
const handler = handlers[requestMethod] ?? handlers["ANY"];
|
|
342
|
+
if (handler) {
|
|
343
|
+
const mayDefer = !!foundRoute.options.component;
|
|
344
|
+
if (typeof handler === "function") {
|
|
345
|
+
routeMiddlewares.push(handlerToMiddleware(handler, mayDefer));
|
|
346
|
+
} else {
|
|
347
|
+
if (handler.middleware?.length) {
|
|
348
|
+
const handlerMiddlewares = flattenMiddlewares(handler.middleware);
|
|
349
|
+
for (const m of handlerMiddlewares) {
|
|
350
|
+
routeMiddlewares.push(m.options.server);
|
|
261
351
|
}
|
|
262
352
|
}
|
|
353
|
+
if (handler.handler) {
|
|
354
|
+
routeMiddlewares.push(handlerToMiddleware(handler.handler, mayDefer));
|
|
355
|
+
}
|
|
263
356
|
}
|
|
264
357
|
}
|
|
265
358
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
);
|
|
269
|
-
const ctx = await executeMiddleware(middlewares, {
|
|
359
|
+
routeMiddlewares.push((ctx2) => executeRouter(ctx2.context));
|
|
360
|
+
const ctx = await executeMiddleware(routeMiddlewares, {
|
|
270
361
|
request,
|
|
271
362
|
context,
|
|
272
363
|
params: routeParams,
|
|
273
364
|
pathname
|
|
274
365
|
});
|
|
275
|
-
|
|
276
|
-
return response;
|
|
277
|
-
}
|
|
278
|
-
function throwRouteHandlerError() {
|
|
279
|
-
if (process.env.NODE_ENV === "development") {
|
|
280
|
-
throw new Error(
|
|
281
|
-
`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.`
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
throw new Error("Internal Server Error");
|
|
285
|
-
}
|
|
286
|
-
function throwIfMayNotDefer() {
|
|
287
|
-
if (process.env.NODE_ENV === "development") {
|
|
288
|
-
throw new Error(
|
|
289
|
-
`You cannot defer to the app router if there is no component defined on this route.`
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
throw new Error("Internal Server Error");
|
|
293
|
-
}
|
|
294
|
-
function handlerToMiddleware(handler, mayDefer = false) {
|
|
295
|
-
if (mayDefer) {
|
|
296
|
-
return handler;
|
|
297
|
-
}
|
|
298
|
-
return async ({ next: _next, ...rest }) => {
|
|
299
|
-
const response = await handler({ ...rest, next: throwIfMayNotDefer });
|
|
300
|
-
if (!response) {
|
|
301
|
-
throwRouteHandlerError();
|
|
302
|
-
}
|
|
303
|
-
return response;
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
function executeMiddleware(middlewares, ctx) {
|
|
307
|
-
let index = -1;
|
|
308
|
-
const next = async (ctx2) => {
|
|
309
|
-
index++;
|
|
310
|
-
const middleware = middlewares[index];
|
|
311
|
-
if (!middleware) return ctx2;
|
|
312
|
-
let result;
|
|
313
|
-
try {
|
|
314
|
-
result = await middleware({
|
|
315
|
-
...ctx2,
|
|
316
|
-
// Allow the middleware to call the next middleware in the chain
|
|
317
|
-
next: async (nextCtx) => {
|
|
318
|
-
const nextResult = await next({
|
|
319
|
-
...ctx2,
|
|
320
|
-
...nextCtx,
|
|
321
|
-
context: {
|
|
322
|
-
...ctx2.context,
|
|
323
|
-
...nextCtx?.context || {}
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
return Object.assign(ctx2, handleCtxResult(nextResult));
|
|
327
|
-
}
|
|
328
|
-
// Allow the middleware result to extend the return context
|
|
329
|
-
});
|
|
330
|
-
} catch (err) {
|
|
331
|
-
if (isSpecialResponse(err)) {
|
|
332
|
-
result = {
|
|
333
|
-
response: err
|
|
334
|
-
};
|
|
335
|
-
} else {
|
|
336
|
-
throw err;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return Object.assign(ctx2, handleCtxResult(result));
|
|
340
|
-
};
|
|
341
|
-
return handleCtxResult(next(ctx));
|
|
342
|
-
}
|
|
343
|
-
function handleCtxResult(result) {
|
|
344
|
-
if (isSpecialResponse(result)) {
|
|
345
|
-
return {
|
|
346
|
-
response: result
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
return result;
|
|
350
|
-
}
|
|
351
|
-
function isSpecialResponse(err) {
|
|
352
|
-
return isResponse(err) || isRedirect(err);
|
|
353
|
-
}
|
|
354
|
-
function isResponse(response) {
|
|
355
|
-
return response instanceof Response;
|
|
366
|
+
return ctx.response;
|
|
356
367
|
}
|
|
357
368
|
export {
|
|
358
369
|
createStartHandler
|