@tanstack/start-server-core 1.120.4-alpha.7 → 1.120.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -6
- package/dist/cjs/createRequestHandler.cjs +3 -1
- package/dist/cjs/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/createStartHandler.cjs +30 -231
- package/dist/cjs/createStartHandler.cjs.map +1 -1
- package/dist/cjs/createStartHandler.d.cts +6 -8
- package/dist/cjs/h3.cjs +73 -30
- package/dist/cjs/h3.cjs.map +1 -1
- package/dist/cjs/h3.d.cts +7 -11
- package/dist/cjs/handlerCallback.cjs.map +1 -1
- package/dist/cjs/handlerCallback.d.cts +4 -3
- package/dist/cjs/index.cjs +14 -20
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -7
- package/dist/esm/createRequestHandler.js +3 -1
- package/dist/esm/createRequestHandler.js.map +1 -1
- package/dist/esm/createStartHandler.d.ts +6 -8
- package/dist/esm/createStartHandler.js +32 -211
- package/dist/esm/createStartHandler.js.map +1 -1
- package/dist/esm/h3.d.ts +7 -11
- package/dist/esm/h3.js +63 -26
- package/dist/esm/h3.js.map +1 -1
- package/dist/esm/handlerCallback.d.ts +4 -3
- package/dist/esm/handlerCallback.js.map +1 -1
- package/dist/esm/index.d.ts +1 -7
- package/dist/esm/index.js +5 -17
- package/dist/esm/index.js.map +1 -1
- package/package.json +6 -9
- package/src/createRequestHandler.ts +3 -1
- package/src/createStartHandler.ts +48 -321
- package/src/h3.ts +78 -71
- package/src/handlerCallback.ts +12 -5
- package/src/index.tsx +1 -13
- package/dist/cjs/router-manifest.cjs +0 -44
- package/dist/cjs/router-manifest.cjs.map +0 -1
- package/dist/cjs/router-manifest.d.cts +0 -17
- package/dist/cjs/server-functions-handler.cjs +0 -154
- package/dist/cjs/server-functions-handler.cjs.map +0 -1
- package/dist/cjs/server-functions-handler.d.cts +0 -4
- package/dist/cjs/serverRoute.cjs +0 -100
- package/dist/cjs/serverRoute.cjs.map +0 -1
- package/dist/cjs/serverRoute.d.cts +0 -115
- package/dist/cjs/undici.cjs +0 -14
- package/dist/cjs/undici.cjs.map +0 -1
- package/dist/cjs/undici.d.cts +0 -43
- package/dist/esm/router-manifest.d.ts +0 -17
- package/dist/esm/router-manifest.js +0 -44
- package/dist/esm/router-manifest.js.map +0 -1
- package/dist/esm/server-functions-handler.d.ts +0 -4
- package/dist/esm/server-functions-handler.js +0 -154
- package/dist/esm/server-functions-handler.js.map +0 -1
- package/dist/esm/serverRoute.d.ts +0 -115
- package/dist/esm/serverRoute.js +0 -100
- package/dist/esm/serverRoute.js.map +0 -1
- package/dist/esm/undici.d.ts +0 -43
- package/dist/esm/undici.js +0 -14
- package/dist/esm/undici.js.map +0 -1
- package/src/router-manifest.ts +0 -79
- package/src/server-functions-handler.ts +0 -273
- package/src/serverRoute.ts +0 -661
- package/src/tanstack-start.d.ts +0 -5
- package/src/undici.ts +0 -60
|
@@ -1,355 +1,82 @@
|
|
|
1
1
|
import { createMemoryHistory } from '@tanstack/history'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
json,
|
|
5
|
-
mergeHeaders,
|
|
6
|
-
} from '@tanstack/start-client-core'
|
|
7
|
-
import {
|
|
8
|
-
getMatchedRoutes,
|
|
9
|
-
isRedirect,
|
|
10
|
-
processRouteTree,
|
|
11
|
-
rootRouteId,
|
|
12
|
-
tsrRedirectHeaderKey,
|
|
13
|
-
} from '@tanstack/router-core'
|
|
14
|
-
import { getResponseHeaders, requestHandler } from './h3'
|
|
2
|
+
import { mergeHeaders } from '@tanstack/start-client-core'
|
|
3
|
+
import { eventHandler, getResponseHeaders, toWebRequest } from 'h3'
|
|
15
4
|
import { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server'
|
|
16
|
-
import { getStartManifest } from './router-manifest'
|
|
17
|
-
import { handleServerAction } from './server-functions-handler'
|
|
18
|
-
import type { AnyServerRoute, AnyServerRouteWithTypes } from './serverRoute'
|
|
19
|
-
import type { RequestHandler } from './h3'
|
|
20
|
-
import type { AnyRouter } from '@tanstack/router-core'
|
|
21
5
|
import type { HandlerCallback } from './handlerCallback'
|
|
22
|
-
|
|
23
|
-
type
|
|
24
|
-
|
|
25
|
-
export type CustomizeStartHandler<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
},
|
|
35
|
-
...opts.router.state.matches.map((match) => {
|
|
36
|
-
return match.headers
|
|
37
|
-
}),
|
|
38
|
-
)
|
|
39
|
-
// Handle Redirects
|
|
40
|
-
const { redirect } = opts.router.state
|
|
41
|
-
|
|
42
|
-
if (redirect) {
|
|
43
|
-
headers = mergeHeaders(headers, redirect.headers)
|
|
44
|
-
}
|
|
45
|
-
return headers
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function createStartHandler<TRouter extends AnyRouter>({
|
|
6
|
+
import type { EventHandlerResponse, H3Event } from 'h3'
|
|
7
|
+
import type { AnyRouter, Manifest } from '@tanstack/router-core'
|
|
8
|
+
|
|
9
|
+
export type CustomizeStartHandler<
|
|
10
|
+
TRouter extends AnyRouter,
|
|
11
|
+
TResponse extends EventHandlerResponse = EventHandlerResponse,
|
|
12
|
+
> = (cb: HandlerCallback<TRouter, TResponse>) => ReturnType<typeof eventHandler>
|
|
13
|
+
|
|
14
|
+
export function createStartHandler<
|
|
15
|
+
TRouter extends AnyRouter,
|
|
16
|
+
TResponse extends EventHandlerResponse = EventHandlerResponse,
|
|
17
|
+
>({
|
|
49
18
|
createRouter,
|
|
19
|
+
getRouterManifest,
|
|
50
20
|
}: {
|
|
51
21
|
createRouter: () => TRouter
|
|
52
|
-
|
|
22
|
+
getRouterManifest?: () => Manifest | Promise<Manifest>
|
|
23
|
+
}): CustomizeStartHandler<TRouter, TResponse> {
|
|
53
24
|
return (cb) => {
|
|
54
|
-
return
|
|
25
|
+
return eventHandler(async (event) => {
|
|
26
|
+
const request = toWebRequest(event)
|
|
27
|
+
|
|
55
28
|
const url = new URL(request.url)
|
|
56
29
|
const href = url.href.replace(url.origin, '')
|
|
57
30
|
|
|
58
|
-
// Create a history for the
|
|
31
|
+
// Create a history for the router
|
|
59
32
|
const history = createMemoryHistory({
|
|
60
33
|
initialEntries: [href],
|
|
61
34
|
})
|
|
62
35
|
|
|
63
|
-
// Create the client-side router
|
|
64
36
|
const router = createRouter()
|
|
65
37
|
|
|
66
|
-
|
|
67
|
-
attachRouterServerSsrUtils(router, getStartManifest())
|
|
38
|
+
attachRouterServerSsrUtils(router, await getRouterManifest?.())
|
|
68
39
|
|
|
69
|
-
// Update the
|
|
40
|
+
// Update the router with the history and context
|
|
70
41
|
router.update({
|
|
71
42
|
history,
|
|
72
43
|
})
|
|
73
44
|
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
if (!process.env.TSS_SERVER_FN_BASE) {
|
|
77
|
-
throw new Error(
|
|
78
|
-
'tanstack/start-server-core: TSS_SERVER_FN_BASE must be defined in your environment for createStartHandler()',
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// First, let's attempt to handle server functions
|
|
83
|
-
// Add trailing slash to sanitise user defined TSS_SERVER_FN_BASE
|
|
84
|
-
const serverFnBase = process.env.TSS_SERVER_FN_BASE.startsWith('/')
|
|
85
|
-
? process.env.TSS_SERVER_FN_BASE
|
|
86
|
-
: '/' + process.env.TSS_SERVER_FN_BASE
|
|
87
|
-
if (href.startsWith(serverFnBase)) {
|
|
88
|
-
return await handleServerAction({ request })
|
|
89
|
-
}
|
|
45
|
+
await router.load()
|
|
90
46
|
|
|
91
|
-
|
|
92
|
-
const serverRouteTreeModule = await (async () => {
|
|
93
|
-
try {
|
|
94
|
-
// @ts-expect-error
|
|
95
|
-
return (await import('tanstack:server-routes')) as {
|
|
96
|
-
routeTree: AnyServerRoute
|
|
97
|
-
}
|
|
98
|
-
} catch (e) {
|
|
99
|
-
console.log(e)
|
|
100
|
-
return undefined
|
|
101
|
-
}
|
|
102
|
-
})()
|
|
47
|
+
dehydrateRouter(router)
|
|
103
48
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
request,
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
if (response) return response
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const requestAcceptHeader = request.headers.get('Accept') || '*/*'
|
|
116
|
-
const splitRequestAcceptHeader = requestAcceptHeader.split(',')
|
|
117
|
-
|
|
118
|
-
const supportedMimeTypes = ['*/*', 'text/html']
|
|
119
|
-
const isRouterAcceptSupported = supportedMimeTypes.some((mimeType) =>
|
|
120
|
-
splitRequestAcceptHeader.some((acceptedMimeType) =>
|
|
121
|
-
acceptedMimeType.trim().startsWith(mimeType),
|
|
122
|
-
),
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
if (!isRouterAcceptSupported) {
|
|
126
|
-
return json(
|
|
127
|
-
{
|
|
128
|
-
error: 'Only HTML requests are supported here',
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
status: 500,
|
|
132
|
-
},
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// If no Server Routes were found, so fallback to normal SSR matching using
|
|
137
|
-
// the router
|
|
138
|
-
|
|
139
|
-
await router.load()
|
|
140
|
-
|
|
141
|
-
// If there was a redirect, skip rendering the page at all
|
|
142
|
-
if (router.state.redirect) return router.state.redirect
|
|
143
|
-
|
|
144
|
-
dehydrateRouter(router)
|
|
145
|
-
|
|
146
|
-
const responseHeaders = getStartResponseHeaders({ router })
|
|
147
|
-
const response = await cb({
|
|
148
|
-
request,
|
|
149
|
-
router,
|
|
150
|
-
responseHeaders,
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
return response
|
|
154
|
-
} catch (err) {
|
|
155
|
-
if (err instanceof Response) {
|
|
156
|
-
return err
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
throw err
|
|
160
|
-
}
|
|
161
|
-
})()
|
|
162
|
-
|
|
163
|
-
if (isRedirect(response)) {
|
|
164
|
-
if (
|
|
165
|
-
response.options.to &&
|
|
166
|
-
typeof response.options.to === 'string' &&
|
|
167
|
-
!response.options.to.startsWith('/')
|
|
168
|
-
) {
|
|
169
|
-
throw new Error(
|
|
170
|
-
`Server side redirects must use absolute paths via the 'href' or 'to' options. Received: ${JSON.stringify(response.options)}`,
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (
|
|
175
|
-
['params', 'search', 'hash'].some(
|
|
176
|
-
(d) => typeof (response.options as any)[d] === 'function',
|
|
177
|
-
)
|
|
178
|
-
) {
|
|
179
|
-
throw new Error(
|
|
180
|
-
`Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys(
|
|
181
|
-
response.options,
|
|
182
|
-
)
|
|
183
|
-
.filter((d) => typeof (response.options as any)[d] === 'function')
|
|
184
|
-
.map((d) => `"${d}"`)
|
|
185
|
-
.join(', ')}`,
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const redirect = router.resolveRedirect(response)
|
|
190
|
-
|
|
191
|
-
if (request.headers.get('x-tsr-redirect') === 'manual') {
|
|
192
|
-
return json(
|
|
193
|
-
{
|
|
194
|
-
...response.options,
|
|
195
|
-
isSerializedRedirect: true,
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
headers: redirect.headers,
|
|
199
|
-
},
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return redirect
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Add Access-Control-Expose-Headers
|
|
207
|
-
// With HTTPs the response/header objects are immutable, therefore we must clone them
|
|
208
|
-
const body =
|
|
209
|
-
response.status === 204 ? null : await response.clone().blob()
|
|
210
|
-
const headers = new Headers(response.headers)
|
|
211
|
-
headers.append('Access-Control-Expose-Headers', tsrRedirectHeaderKey)
|
|
212
|
-
|
|
213
|
-
return new Response(body, {
|
|
214
|
-
status: response.status,
|
|
215
|
-
statusText: response.statusText,
|
|
216
|
-
headers,
|
|
49
|
+
const responseHeaders = getStartResponseHeaders({ event, router })
|
|
50
|
+
const response = await cb({
|
|
51
|
+
request,
|
|
52
|
+
router,
|
|
53
|
+
responseHeaders,
|
|
217
54
|
})
|
|
218
|
-
})
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async function handleServerRoutes({
|
|
223
|
-
routeTree,
|
|
224
|
-
request,
|
|
225
|
-
}: {
|
|
226
|
-
routeTree: AnyServerRouteWithTypes
|
|
227
|
-
request: Request
|
|
228
|
-
}) {
|
|
229
|
-
const { flatRoutes, routesById, routesByPath } = processRouteTree({
|
|
230
|
-
routeTree,
|
|
231
|
-
initRoute: (route, i) => {
|
|
232
|
-
route.init({
|
|
233
|
-
originalIndex: i,
|
|
234
|
-
})
|
|
235
|
-
},
|
|
236
|
-
})
|
|
237
55
|
|
|
238
|
-
|
|
239
|
-
const pathname = url.pathname
|
|
240
|
-
|
|
241
|
-
const history = createMemoryHistory({
|
|
242
|
-
initialEntries: [pathname],
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
const { matchedRoutes, foundRoute, routeParams } =
|
|
246
|
-
getMatchedRoutes<AnyServerRouteWithTypes>({
|
|
247
|
-
pathname: history.location.pathname,
|
|
248
|
-
basepath: '/',
|
|
249
|
-
caseSensitive: true,
|
|
250
|
-
routesByPath,
|
|
251
|
-
routesById,
|
|
252
|
-
flatRoutes,
|
|
56
|
+
return response
|
|
253
57
|
})
|
|
254
|
-
|
|
255
|
-
let response: Response | undefined
|
|
256
|
-
|
|
257
|
-
if (foundRoute && foundRoute.id !== rootRouteId) {
|
|
258
|
-
// We've found a server route that matches the request, so we can call it.
|
|
259
|
-
// TODO: Get the input type-signature correct
|
|
260
|
-
// TODO: Perform the middlewares?
|
|
261
|
-
// TODO: Error handling? What happens when its `throw redirect()` vs `throw new Error()`?
|
|
262
|
-
|
|
263
|
-
const method = Object.keys(foundRoute.options.methods).find(
|
|
264
|
-
(method) => method.toLowerCase() === request.method.toLowerCase(),
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
if (method) {
|
|
268
|
-
const handler = foundRoute.options.methods[method]
|
|
269
|
-
|
|
270
|
-
if (handler) {
|
|
271
|
-
const middlewares = flattenMiddlewares(
|
|
272
|
-
matchedRoutes.flatMap((r) => r.options.middleware).filter(Boolean),
|
|
273
|
-
).map((d) => d.options.server)
|
|
274
|
-
|
|
275
|
-
middlewares.push(handlerToMiddleware(handler) as TODO)
|
|
276
|
-
|
|
277
|
-
// TODO: This is starting to feel too much like a server function
|
|
278
|
-
// Do generalize the existing middleware execution? Or do we need to
|
|
279
|
-
// build a new middleware execution system for server routes?
|
|
280
|
-
const ctx = await executeMiddleware(middlewares, {
|
|
281
|
-
request,
|
|
282
|
-
context: {},
|
|
283
|
-
params: routeParams,
|
|
284
|
-
pathname: history.location.pathname,
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
response = ctx.response
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
58
|
}
|
|
291
|
-
|
|
292
|
-
// We return the matched routes too so if
|
|
293
|
-
// the app router happens to match the same path,
|
|
294
|
-
// it can use any request middleware from server routes
|
|
295
|
-
return [matchedRoutes, response] as const
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function handlerToMiddleware(
|
|
299
|
-
handler: AnyServerRouteWithTypes['options']['methods'][string],
|
|
300
|
-
) {
|
|
301
|
-
return async ({ next, ...rest }: TODO) => ({
|
|
302
|
-
response: await handler(rest),
|
|
303
|
-
})
|
|
304
59
|
}
|
|
305
60
|
|
|
306
|
-
function
|
|
307
|
-
let
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
next: async (nextCtx: TODO) => {
|
|
318
|
-
// Allow the caller to extend the context for the next middleware
|
|
319
|
-
const nextResult = await next({ ...ctx, ...nextCtx })
|
|
61
|
+
function getStartResponseHeaders(opts: { event: H3Event; router: AnyRouter }) {
|
|
62
|
+
let headers = mergeHeaders(
|
|
63
|
+
getResponseHeaders(opts.event),
|
|
64
|
+
(opts.event as any).___ssrRpcResponseHeaders,
|
|
65
|
+
{
|
|
66
|
+
'Content-Type': 'text/html; charset=UTF-8',
|
|
67
|
+
},
|
|
68
|
+
...opts.router.state.matches.map((match) => {
|
|
69
|
+
return match.headers
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
320
72
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
},
|
|
324
|
-
// Allow the middleware result to extend the return context
|
|
325
|
-
}).catch((err: TODO) => {
|
|
326
|
-
if (isSpecialResponse(err)) {
|
|
327
|
-
return {
|
|
328
|
-
response: err,
|
|
329
|
-
}
|
|
330
|
-
}
|
|
73
|
+
// Handle Redirects
|
|
74
|
+
const { redirect } = opts.router.state
|
|
331
75
|
|
|
332
|
-
|
|
76
|
+
if (redirect) {
|
|
77
|
+
headers = mergeHeaders(headers, redirect.headers, {
|
|
78
|
+
Location: redirect.href,
|
|
333
79
|
})
|
|
334
|
-
|
|
335
|
-
// Merge the middleware result into the context, just in case it
|
|
336
|
-
// returns a partial context
|
|
337
|
-
return Object.assign(ctx, handleCtxResult(result))
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return handleCtxResult(next(ctx))
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function handleCtxResult(result: TODO) {
|
|
344
|
-
if (isSpecialResponse(result)) {
|
|
345
|
-
return {
|
|
346
|
-
response: result,
|
|
347
|
-
}
|
|
348
80
|
}
|
|
349
|
-
|
|
350
|
-
return result
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function isSpecialResponse(err: TODO) {
|
|
354
|
-
return err instanceof Response || isRedirect(err)
|
|
81
|
+
return headers
|
|
355
82
|
}
|
package/src/h3.ts
CHANGED
|
@@ -11,9 +11,7 @@ import {
|
|
|
11
11
|
clearResponseHeaders as _clearResponseHeaders,
|
|
12
12
|
clearSession as _clearSession,
|
|
13
13
|
defaultContentType as _defaultContentType,
|
|
14
|
-
defineEventHandler as _defineEventHandler,
|
|
15
14
|
deleteCookie as _deleteCookie,
|
|
16
|
-
eventHandler as _eventHandler,
|
|
17
15
|
fetchWithEvent as _fetchWithEvent,
|
|
18
16
|
getCookie as _getCookie,
|
|
19
17
|
getHeader as _getHeader,
|
|
@@ -63,24 +61,20 @@ import {
|
|
|
63
61
|
setResponseHeader as _setResponseHeader,
|
|
64
62
|
setResponseHeaders as _setResponseHeaders,
|
|
65
63
|
setResponseStatus as _setResponseStatus,
|
|
66
|
-
toWebRequest as _toWebRequest,
|
|
67
64
|
unsealSession as _unsealSession,
|
|
68
65
|
updateSession as _updateSession,
|
|
69
66
|
useSession as _useSession,
|
|
70
67
|
writeEarlyHints as _writeEarlyHints,
|
|
71
68
|
} from 'h3'
|
|
72
|
-
|
|
69
|
+
import { getContext as getUnctxContext } from 'unctx'
|
|
73
70
|
import type {
|
|
74
71
|
Encoding,
|
|
75
|
-
EventHandler,
|
|
76
72
|
HTTPHeaderName,
|
|
77
73
|
InferEventInput,
|
|
78
74
|
_RequestMiddleware,
|
|
79
75
|
_ResponseMiddleware,
|
|
80
76
|
} from 'h3'
|
|
81
77
|
|
|
82
|
-
const eventStorage = new AsyncLocalStorage()
|
|
83
|
-
|
|
84
78
|
function _setContext(event: H3Event, key: string, value: any) {
|
|
85
79
|
event.context[key] = value
|
|
86
80
|
}
|
|
@@ -96,38 +90,46 @@ export function defineMiddleware(options: {
|
|
|
96
90
|
return options
|
|
97
91
|
}
|
|
98
92
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
function toWebRequestH3(event: H3Event) {
|
|
94
|
+
/**
|
|
95
|
+
* @type {ReadableStream | undefined}
|
|
96
|
+
*/
|
|
97
|
+
let readableStream: ReadableStream | undefined
|
|
104
98
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
99
|
+
const url = getRequestURL(event)
|
|
100
|
+
const base = {
|
|
101
|
+
// @ts-ignore Undici option
|
|
102
|
+
duplex: 'half',
|
|
103
|
+
method: event.method,
|
|
104
|
+
headers: event.headers,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if ((event.node.req as any).body instanceof ArrayBuffer) {
|
|
108
|
+
return new Request(url, {
|
|
109
|
+
...base,
|
|
110
|
+
body: (event.node.req as any).body,
|
|
111
|
+
})
|
|
112
|
+
}
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
return new Request(url, {
|
|
115
|
+
...base,
|
|
116
|
+
get body() {
|
|
117
|
+
if (readableStream) {
|
|
118
|
+
return readableStream
|
|
119
|
+
}
|
|
120
|
+
readableStream = getRequestWebStream(event)
|
|
121
|
+
return readableStream
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
}
|
|
119
125
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
// return readableStream
|
|
128
|
-
// },
|
|
129
|
-
// })
|
|
130
|
-
// }
|
|
126
|
+
export function toWebRequest(event: H3Event) {
|
|
127
|
+
event.web ??= {
|
|
128
|
+
request: toWebRequestH3(event),
|
|
129
|
+
url: getRequestURL(event),
|
|
130
|
+
}
|
|
131
|
+
return event.web.request
|
|
132
|
+
}
|
|
131
133
|
|
|
132
134
|
export {
|
|
133
135
|
H3Error,
|
|
@@ -138,6 +140,7 @@ export {
|
|
|
138
140
|
createAppEventHandler,
|
|
139
141
|
createEvent,
|
|
140
142
|
createRouter,
|
|
143
|
+
defineEventHandler,
|
|
141
144
|
defineLazyEventHandler,
|
|
142
145
|
defineNodeListener,
|
|
143
146
|
defineNodeMiddleware,
|
|
@@ -145,6 +148,7 @@ export {
|
|
|
145
148
|
defineResponseMiddleware,
|
|
146
149
|
dynamicEventHandler,
|
|
147
150
|
defineWebSocket,
|
|
151
|
+
eventHandler,
|
|
148
152
|
splitCookiesString,
|
|
149
153
|
fromNodeMiddleware,
|
|
150
154
|
fromPlainHandler,
|
|
@@ -159,7 +163,6 @@ export {
|
|
|
159
163
|
toNodeListener,
|
|
160
164
|
toPlainHandler,
|
|
161
165
|
toWebHandler,
|
|
162
|
-
toWebRequest,
|
|
163
166
|
isCorsOriginAllowed,
|
|
164
167
|
isStream,
|
|
165
168
|
createError,
|
|
@@ -218,33 +221,8 @@ export {
|
|
|
218
221
|
type _ResponseMiddleware,
|
|
219
222
|
} from 'h3'
|
|
220
223
|
|
|
221
|
-
|
|
222
|
-
return
|
|
223
|
-
return runWithEvent(event, () => handler(event))
|
|
224
|
-
})
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export function eventHandler(handler: EventHandler) {
|
|
228
|
-
return _eventHandler((event) => {
|
|
229
|
-
return runWithEvent(event, () => handler(event))
|
|
230
|
-
})
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export async function runWithEvent<T>(
|
|
234
|
-
event: H3Event,
|
|
235
|
-
fn: () => T | Promise<T>,
|
|
236
|
-
): Promise<T> {
|
|
237
|
-
return eventStorage.run(event, fn)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export function getEvent() {
|
|
241
|
-
const event = eventStorage.getStore() as H3Event | undefined
|
|
242
|
-
if (!event) {
|
|
243
|
-
throw new Error(
|
|
244
|
-
`No HTTPEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.`,
|
|
245
|
-
)
|
|
246
|
-
}
|
|
247
|
-
return event
|
|
224
|
+
function getHTTPEvent() {
|
|
225
|
+
return getEvent()
|
|
248
226
|
}
|
|
249
227
|
|
|
250
228
|
export const HTTPEventSymbol = Symbol('$HTTPEvent')
|
|
@@ -284,7 +262,12 @@ function createWrapperFunction<TFn extends (...args: Array<any>) => any>(
|
|
|
284
262
|
return function (...args: Array<any>) {
|
|
285
263
|
const event = args[0]
|
|
286
264
|
if (!isEvent(event)) {
|
|
287
|
-
|
|
265
|
+
if (!(globalThis as any).app.config.server.experimental?.asyncContext) {
|
|
266
|
+
throw new Error(
|
|
267
|
+
'AsyncLocalStorage was not enabled. Use the `server.experimental.asyncContext: true` option in your app configuration to enable it. Or, pass the instance of HTTPEvent that you have as the first argument to the function.',
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
args.unshift(getHTTPEvent())
|
|
288
271
|
} else {
|
|
289
272
|
args[0] =
|
|
290
273
|
event instanceof H3Event || (event as any).__is_event__
|
|
@@ -480,13 +463,37 @@ export const readValidatedBody: PrependOverload<
|
|
|
480
463
|
export const removeResponseHeader = createWrapperFunction(_removeResponseHeader)
|
|
481
464
|
export const getContext = createWrapperFunction(_getContext)
|
|
482
465
|
export const setContext = createWrapperFunction(_setContext)
|
|
466
|
+
|
|
483
467
|
export const clearResponseHeaders = createWrapperFunction(_clearResponseHeaders)
|
|
484
|
-
export const getWebRequest = createWrapperFunction(_toWebRequest)
|
|
485
468
|
|
|
486
|
-
export
|
|
487
|
-
|
|
488
|
-
|
|
469
|
+
export const getWebRequest = createWrapperFunction(toWebRequest)
|
|
470
|
+
|
|
471
|
+
export { createApp as createServer } from 'h3'
|
|
472
|
+
|
|
473
|
+
function getNitroAsyncContext() {
|
|
474
|
+
const nitroAsyncContext = getUnctxContext('nitro-app', {
|
|
475
|
+
asyncContext: (globalThis as any).app.config.server.experimental
|
|
476
|
+
?.asyncContext
|
|
477
|
+
? true
|
|
478
|
+
: false,
|
|
479
|
+
AsyncLocalStorage,
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
return nitroAsyncContext
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export function getEvent() {
|
|
486
|
+
const event = (getNitroAsyncContext().use() as any).event as
|
|
487
|
+
| H3Event
|
|
488
|
+
| undefined
|
|
489
|
+
if (!event) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
`No HTTPEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.`,
|
|
492
|
+
)
|
|
493
|
+
}
|
|
494
|
+
return event
|
|
495
|
+
}
|
|
489
496
|
|
|
490
|
-
export function
|
|
491
|
-
return
|
|
497
|
+
export async function handleHTTPEvent(event: H3Event) {
|
|
498
|
+
return await (globalThis as any).$handle(event)
|
|
492
499
|
}
|
package/src/handlerCallback.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
|
+
import type { EventHandlerResponse } from 'h3'
|
|
1
2
|
import type { AnyRouter } from '@tanstack/router-core'
|
|
2
3
|
|
|
3
|
-
export interface HandlerCallback<
|
|
4
|
+
export interface HandlerCallback<
|
|
5
|
+
TRouter extends AnyRouter,
|
|
6
|
+
TResponse extends EventHandlerResponse = EventHandlerResponse,
|
|
7
|
+
> {
|
|
4
8
|
(ctx: {
|
|
5
9
|
request: Request
|
|
6
10
|
router: TRouter
|
|
7
11
|
responseHeaders: Headers
|
|
8
|
-
}):
|
|
12
|
+
}): TResponse
|
|
9
13
|
}
|
|
10
14
|
|
|
11
|
-
export function defineHandlerCallback<
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
export function defineHandlerCallback<
|
|
16
|
+
TRouter extends AnyRouter,
|
|
17
|
+
TResponse = EventHandlerResponse,
|
|
18
|
+
>(
|
|
19
|
+
handler: HandlerCallback<TRouter, TResponse>,
|
|
20
|
+
): HandlerCallback<TRouter, TResponse> {
|
|
14
21
|
return handler
|
|
15
22
|
}
|
package/src/index.tsx
CHANGED
|
@@ -3,22 +3,10 @@ export {
|
|
|
3
3
|
transformPipeableStreamWithRouter,
|
|
4
4
|
} from './transformStreamWithRouter'
|
|
5
5
|
|
|
6
|
-
export {
|
|
7
|
-
getStartResponseHeaders,
|
|
8
|
-
createStartHandler,
|
|
9
|
-
} from './createStartHandler'
|
|
10
|
-
export type { CustomizeStartHandler } from './createStartHandler'
|
|
6
|
+
export { createStartHandler } from './createStartHandler'
|
|
11
7
|
export { createRequestHandler } from './createRequestHandler'
|
|
12
8
|
|
|
13
9
|
export { defineHandlerCallback } from './handlerCallback'
|
|
14
10
|
export type { HandlerCallback } from './handlerCallback'
|
|
15
11
|
|
|
16
|
-
export { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server'
|
|
17
|
-
export { handleServerAction } from './server-functions-handler'
|
|
18
|
-
|
|
19
12
|
export * from './h3'
|
|
20
|
-
|
|
21
|
-
export { createServerRoute, createServerFileRoute } from './serverRoute'
|
|
22
|
-
export type { CreateServerFileRoute } from './serverRoute'
|
|
23
|
-
|
|
24
|
-
export { __getAbsoluteUrl, __setGlobalOrigin } from './undici'
|