@tanstack/start-server-core 1.120.4-alpha.8 → 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.
Files changed (62) hide show
  1. package/README.md +27 -6
  2. package/dist/cjs/createRequestHandler.cjs +3 -1
  3. package/dist/cjs/createRequestHandler.cjs.map +1 -1
  4. package/dist/cjs/createStartHandler.cjs +30 -235
  5. package/dist/cjs/createStartHandler.cjs.map +1 -1
  6. package/dist/cjs/createStartHandler.d.cts +6 -8
  7. package/dist/cjs/h3.cjs +73 -30
  8. package/dist/cjs/h3.cjs.map +1 -1
  9. package/dist/cjs/h3.d.cts +7 -11
  10. package/dist/cjs/handlerCallback.cjs.map +1 -1
  11. package/dist/cjs/handlerCallback.d.cts +4 -3
  12. package/dist/cjs/index.cjs +14 -20
  13. package/dist/cjs/index.cjs.map +1 -1
  14. package/dist/cjs/index.d.cts +1 -7
  15. package/dist/esm/createRequestHandler.js +3 -1
  16. package/dist/esm/createRequestHandler.js.map +1 -1
  17. package/dist/esm/createStartHandler.d.ts +6 -8
  18. package/dist/esm/createStartHandler.js +32 -215
  19. package/dist/esm/createStartHandler.js.map +1 -1
  20. package/dist/esm/h3.d.ts +7 -11
  21. package/dist/esm/h3.js +63 -26
  22. package/dist/esm/h3.js.map +1 -1
  23. package/dist/esm/handlerCallback.d.ts +4 -3
  24. package/dist/esm/handlerCallback.js.map +1 -1
  25. package/dist/esm/index.d.ts +1 -7
  26. package/dist/esm/index.js +5 -17
  27. package/dist/esm/index.js.map +1 -1
  28. package/package.json +6 -9
  29. package/src/createRequestHandler.ts +3 -1
  30. package/src/createStartHandler.ts +48 -325
  31. package/src/h3.ts +78 -71
  32. package/src/handlerCallback.ts +12 -5
  33. package/src/index.tsx +1 -13
  34. package/dist/cjs/router-manifest.cjs +0 -44
  35. package/dist/cjs/router-manifest.cjs.map +0 -1
  36. package/dist/cjs/router-manifest.d.cts +0 -17
  37. package/dist/cjs/server-functions-handler.cjs +0 -154
  38. package/dist/cjs/server-functions-handler.cjs.map +0 -1
  39. package/dist/cjs/server-functions-handler.d.cts +0 -4
  40. package/dist/cjs/serverRoute.cjs +0 -100
  41. package/dist/cjs/serverRoute.cjs.map +0 -1
  42. package/dist/cjs/serverRoute.d.cts +0 -115
  43. package/dist/cjs/undici.cjs +0 -14
  44. package/dist/cjs/undici.cjs.map +0 -1
  45. package/dist/cjs/undici.d.cts +0 -43
  46. package/dist/esm/router-manifest.d.ts +0 -17
  47. package/dist/esm/router-manifest.js +0 -44
  48. package/dist/esm/router-manifest.js.map +0 -1
  49. package/dist/esm/server-functions-handler.d.ts +0 -4
  50. package/dist/esm/server-functions-handler.js +0 -154
  51. package/dist/esm/server-functions-handler.js.map +0 -1
  52. package/dist/esm/serverRoute.d.ts +0 -115
  53. package/dist/esm/serverRoute.js +0 -100
  54. package/dist/esm/serverRoute.js.map +0 -1
  55. package/dist/esm/undici.d.ts +0 -43
  56. package/dist/esm/undici.js +0 -14
  57. package/dist/esm/undici.js.map +0 -1
  58. package/src/router-manifest.ts +0 -79
  59. package/src/server-functions-handler.ts +0 -273
  60. package/src/serverRoute.ts +0 -661
  61. package/src/tanstack-start.d.ts +0 -5
  62. package/src/undici.ts +0 -60
@@ -1,359 +1,82 @@
1
1
  import { createMemoryHistory } from '@tanstack/history'
2
- import {
3
- flattenMiddlewares,
4
- json,
5
- mergeHeaders,
6
- } from '@tanstack/start-client-core'
7
- import {
8
- getMatchedRoutes,
9
- isRedirect,
10
- joinPaths,
11
- processRouteTree,
12
- rootRouteId,
13
- trimPath,
14
- tsrRedirectHeaderKey,
15
- } from '@tanstack/router-core'
16
- import { getResponseHeaders, requestHandler } from './h3'
2
+ import { mergeHeaders } from '@tanstack/start-client-core'
3
+ import { eventHandler, getResponseHeaders, toWebRequest } from 'h3'
17
4
  import { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server'
18
- import { getStartManifest } from './router-manifest'
19
- import { handleServerAction } from './server-functions-handler'
20
- import type { AnyServerRoute, AnyServerRouteWithTypes } from './serverRoute'
21
- import type { RequestHandler } from './h3'
22
- import type { AnyRouter } from '@tanstack/router-core'
23
5
  import type { HandlerCallback } from './handlerCallback'
24
-
25
- type TODO = any
26
-
27
- export type CustomizeStartHandler<TRouter extends AnyRouter> = (
28
- cb: HandlerCallback<TRouter>,
29
- ) => RequestHandler
30
-
31
- export function getStartResponseHeaders(opts: { router: AnyRouter }) {
32
- let headers = mergeHeaders(
33
- getResponseHeaders(),
34
- {
35
- 'Content-Type': 'text/html; charset=UTF-8',
36
- },
37
- ...opts.router.state.matches.map((match) => {
38
- return match.headers
39
- }),
40
- )
41
- // Handle Redirects
42
- const { redirect } = opts.router.state
43
-
44
- if (redirect) {
45
- headers = mergeHeaders(headers, redirect.headers)
46
- }
47
- return headers
48
- }
49
-
50
- 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
+ >({
51
18
  createRouter,
19
+ getRouterManifest,
52
20
  }: {
53
21
  createRouter: () => TRouter
54
- }): CustomizeStartHandler<TRouter> {
22
+ getRouterManifest?: () => Manifest | Promise<Manifest>
23
+ }): CustomizeStartHandler<TRouter, TResponse> {
55
24
  return (cb) => {
56
- return requestHandler(async ({ request }) => {
25
+ return eventHandler(async (event) => {
26
+ const request = toWebRequest(event)
27
+
57
28
  const url = new URL(request.url)
58
29
  const href = url.href.replace(url.origin, '')
59
30
 
60
- // Create a history for the client-side router
31
+ // Create a history for the router
61
32
  const history = createMemoryHistory({
62
33
  initialEntries: [href],
63
34
  })
64
35
 
65
- // Create the client-side router
66
36
  const router = createRouter()
67
37
 
68
- // Attach the server-side SSR utils to the client-side router
69
- attachRouterServerSsrUtils(router, getStartManifest())
38
+ attachRouterServerSsrUtils(router, await getRouterManifest?.())
70
39
 
71
- // Update the client-side router with the history and context
40
+ // Update the router with the history and context
72
41
  router.update({
73
42
  history,
74
43
  })
75
44
 
76
- const response = await (async () => {
77
- try {
78
- if (!process.env.TSS_SERVER_FN_BASE) {
79
- throw new Error(
80
- 'tanstack/start-server-core: TSS_SERVER_FN_BASE must be defined in your environment for createStartHandler()',
81
- )
82
- }
83
-
84
- // First, let's attempt to handle server functions
85
- // Add trailing slash to sanitise user defined TSS_SERVER_FN_BASE
86
- const serverFnBase = joinPaths([
87
- '/',
88
- trimPath(process.env.TSS_SERVER_FN_BASE),
89
- '/',
90
- ])
91
- if (href.startsWith(serverFnBase)) {
92
- return await handleServerAction({ request })
93
- }
45
+ await router.load()
94
46
 
95
- // Then move on to attempting to load server routes
96
- const serverRouteTreeModule = await (async () => {
97
- try {
98
- // @ts-expect-error
99
- return (await import('tanstack:server-routes')) as {
100
- routeTree: AnyServerRoute
101
- }
102
- } catch (e) {
103
- console.log(e)
104
- return undefined
105
- }
106
- })()
47
+ dehydrateRouter(router)
107
48
 
108
- // If we have a server route tree, then we try matching to see if we have a
109
- // server route that matches the request.
110
- if (serverRouteTreeModule) {
111
- const [_matchedRoutes, response] = await handleServerRoutes({
112
- routeTree: serverRouteTreeModule.routeTree,
113
- request,
114
- })
115
-
116
- if (response) return response
117
- }
118
-
119
- const requestAcceptHeader = request.headers.get('Accept') || '*/*'
120
- const splitRequestAcceptHeader = requestAcceptHeader.split(',')
121
-
122
- const supportedMimeTypes = ['*/*', 'text/html']
123
- const isRouterAcceptSupported = supportedMimeTypes.some((mimeType) =>
124
- splitRequestAcceptHeader.some((acceptedMimeType) =>
125
- acceptedMimeType.trim().startsWith(mimeType),
126
- ),
127
- )
128
-
129
- if (!isRouterAcceptSupported) {
130
- return json(
131
- {
132
- error: 'Only HTML requests are supported here',
133
- },
134
- {
135
- status: 500,
136
- },
137
- )
138
- }
139
-
140
- // If no Server Routes were found, so fallback to normal SSR matching using
141
- // the router
142
-
143
- await router.load()
144
-
145
- // If there was a redirect, skip rendering the page at all
146
- if (router.state.redirect) return router.state.redirect
147
-
148
- dehydrateRouter(router)
149
-
150
- const responseHeaders = getStartResponseHeaders({ router })
151
- const response = await cb({
152
- request,
153
- router,
154
- responseHeaders,
155
- })
156
-
157
- return response
158
- } catch (err) {
159
- if (err instanceof Response) {
160
- return err
161
- }
162
-
163
- throw err
164
- }
165
- })()
166
-
167
- if (isRedirect(response)) {
168
- if (
169
- response.options.to &&
170
- typeof response.options.to === 'string' &&
171
- !response.options.to.startsWith('/')
172
- ) {
173
- throw new Error(
174
- `Server side redirects must use absolute paths via the 'href' or 'to' options. Received: ${JSON.stringify(response.options)}`,
175
- )
176
- }
177
-
178
- if (
179
- ['params', 'search', 'hash'].some(
180
- (d) => typeof (response.options as any)[d] === 'function',
181
- )
182
- ) {
183
- throw new Error(
184
- `Server side redirects must use static search, params, and hash values and do not support functional values. Received functional values for: ${Object.keys(
185
- response.options,
186
- )
187
- .filter((d) => typeof (response.options as any)[d] === 'function')
188
- .map((d) => `"${d}"`)
189
- .join(', ')}`,
190
- )
191
- }
192
-
193
- const redirect = router.resolveRedirect(response)
194
-
195
- if (request.headers.get('x-tsr-redirect') === 'manual') {
196
- return json(
197
- {
198
- ...response.options,
199
- isSerializedRedirect: true,
200
- },
201
- {
202
- headers: redirect.headers,
203
- },
204
- )
205
- }
206
-
207
- return redirect
208
- }
209
-
210
- // Add Access-Control-Expose-Headers
211
- // With HTTPs the response/header objects are immutable, therefore we must clone them
212
- const body =
213
- response.status === 204 ? null : await response.clone().blob()
214
- const headers = new Headers(response.headers)
215
- headers.append('Access-Control-Expose-Headers', tsrRedirectHeaderKey)
216
-
217
- return new Response(body, {
218
- status: response.status,
219
- statusText: response.statusText,
220
- headers,
49
+ const responseHeaders = getStartResponseHeaders({ event, router })
50
+ const response = await cb({
51
+ request,
52
+ router,
53
+ responseHeaders,
221
54
  })
222
- })
223
- }
224
- }
225
-
226
- async function handleServerRoutes({
227
- routeTree,
228
- request,
229
- }: {
230
- routeTree: AnyServerRouteWithTypes
231
- request: Request
232
- }) {
233
- const { flatRoutes, routesById, routesByPath } = processRouteTree({
234
- routeTree,
235
- initRoute: (route, i) => {
236
- route.init({
237
- originalIndex: i,
238
- })
239
- },
240
- })
241
55
 
242
- const url = new URL(request.url)
243
- const pathname = url.pathname
244
-
245
- const history = createMemoryHistory({
246
- initialEntries: [pathname],
247
- })
248
-
249
- const { matchedRoutes, foundRoute, routeParams } =
250
- getMatchedRoutes<AnyServerRouteWithTypes>({
251
- pathname: history.location.pathname,
252
- basepath: '/',
253
- caseSensitive: true,
254
- routesByPath,
255
- routesById,
256
- flatRoutes,
56
+ return response
257
57
  })
258
-
259
- let response: Response | undefined
260
-
261
- if (foundRoute && foundRoute.id !== rootRouteId) {
262
- // We've found a server route that matches the request, so we can call it.
263
- // TODO: Get the input type-signature correct
264
- // TODO: Perform the middlewares?
265
- // TODO: Error handling? What happens when its `throw redirect()` vs `throw new Error()`?
266
-
267
- const method = Object.keys(foundRoute.options.methods).find(
268
- (method) => method.toLowerCase() === request.method.toLowerCase(),
269
- )
270
-
271
- if (method) {
272
- const handler = foundRoute.options.methods[method]
273
-
274
- if (handler) {
275
- const middlewares = flattenMiddlewares(
276
- matchedRoutes.flatMap((r) => r.options.middleware).filter(Boolean),
277
- ).map((d) => d.options.server)
278
-
279
- middlewares.push(handlerToMiddleware(handler) as TODO)
280
-
281
- // TODO: This is starting to feel too much like a server function
282
- // Do generalize the existing middleware execution? Or do we need to
283
- // build a new middleware execution system for server routes?
284
- const ctx = await executeMiddleware(middlewares, {
285
- request,
286
- context: {},
287
- params: routeParams,
288
- pathname: history.location.pathname,
289
- })
290
-
291
- response = ctx.response
292
- }
293
- }
294
58
  }
295
-
296
- // We return the matched routes too so if
297
- // the app router happens to match the same path,
298
- // it can use any request middleware from server routes
299
- return [matchedRoutes, response] as const
300
- }
301
-
302
- function handlerToMiddleware(
303
- handler: AnyServerRouteWithTypes['options']['methods'][string],
304
- ) {
305
- return async ({ next, ...rest }: TODO) => ({
306
- response: await handler(rest),
307
- })
308
59
  }
309
60
 
310
- function executeMiddleware(middlewares: TODO, ctx: TODO) {
311
- let index = -1
312
-
313
- const next = async (ctx: TODO) => {
314
- index++
315
- const middleware = middlewares[index]
316
- if (!middleware) return ctx
317
-
318
- const result = await middleware({
319
- ...ctx,
320
- // Allow the middleware to call the next middleware in the chain
321
- next: async (nextCtx: TODO) => {
322
- // Allow the caller to extend the context for the next middleware
323
- 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
+ )
324
72
 
325
- // Merge the result into the context\
326
- return Object.assign(ctx, handleCtxResult(nextResult))
327
- },
328
- // Allow the middleware result to extend the return context
329
- }).catch((err: TODO) => {
330
- if (isSpecialResponse(err)) {
331
- return {
332
- response: err,
333
- }
334
- }
73
+ // Handle Redirects
74
+ const { redirect } = opts.router.state
335
75
 
336
- throw err
76
+ if (redirect) {
77
+ headers = mergeHeaders(headers, redirect.headers, {
78
+ Location: redirect.href,
337
79
  })
338
-
339
- // Merge the middleware result into the context, just in case it
340
- // returns a partial context
341
- return Object.assign(ctx, handleCtxResult(result))
342
- }
343
-
344
- return handleCtxResult(next(ctx))
345
- }
346
-
347
- function handleCtxResult(result: TODO) {
348
- if (isSpecialResponse(result)) {
349
- return {
350
- response: result,
351
- }
352
80
  }
353
-
354
- return result
355
- }
356
-
357
- function isSpecialResponse(err: TODO) {
358
- return err instanceof Response || isRedirect(err)
81
+ return headers
359
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
- // function toWebRequestH3(event: H3Event) {
100
- // /**
101
- // * @type {ReadableStream | undefined}
102
- // */
103
- // let readableStream: ReadableStream | undefined
93
+ function toWebRequestH3(event: H3Event) {
94
+ /**
95
+ * @type {ReadableStream | undefined}
96
+ */
97
+ let readableStream: ReadableStream | undefined
104
98
 
105
- // const url = _getRequestURL(event)
106
- // const base = {
107
- // // @ts-ignore Undici option
108
- // duplex: 'half',
109
- // method: event.method,
110
- // headers: event.headers,
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
- // if ((event.node.req as any).body instanceof ArrayBuffer) {
114
- // return new Request(url, {
115
- // ...base,
116
- // body: (event.node.req as any).body,
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
- // return new Request(url, {
121
- // ...base,
122
- // get body() {
123
- // if (readableStream) {
124
- // return readableStream
125
- // }
126
- // readableStream = _getRequestWebStream(event)
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
- export function defineEventHandler(handler: EventHandler) {
222
- return _defineEventHandler((event) => {
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
- args.unshift(getEvent())
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 type RequestHandler = (ctx: {
487
- request: Request
488
- }) => Promise<Response> | Response
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 requestHandler(handler: RequestHandler) {
491
- return handler
497
+ export async function handleHTTPEvent(event: H3Event) {
498
+ return await (globalThis as any).$handle(event)
492
499
  }
@@ -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<TRouter extends AnyRouter> {
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
- }): Response | Promise<Response>
12
+ }): TResponse
9
13
  }
10
14
 
11
- export function defineHandlerCallback<TRouter extends AnyRouter>(
12
- handler: HandlerCallback<TRouter>,
13
- ): HandlerCallback<TRouter> {
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'