@tanstack/start-server-core 1.121.0-alpha.27 → 1.121.0-alpha.28
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.d.ts +3 -0
- package/dist/esm/constants.js +7 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/createStartHandler.d.ts +4 -7
- package/dist/esm/createStartHandler.js +169 -102
- package/dist/esm/createStartHandler.js.map +1 -1
- package/dist/esm/index.d.ts +6 -8
- package/dist/esm/index.js +10 -97
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/loadVirtualModule.js +2 -0
- package/dist/esm/loadVirtualModule.js.map +1 -1
- package/dist/esm/request-response.d.ts +124 -0
- package/dist/esm/request-response.js +177 -0
- package/dist/esm/request-response.js.map +1 -0
- package/dist/esm/router-manifest.d.ts +1 -0
- package/dist/esm/router-manifest.js +17 -17
- package/dist/esm/router-manifest.js.map +1 -1
- package/dist/esm/server-functions-handler.js +6 -7
- package/dist/esm/server-functions-handler.js.map +1 -1
- package/dist/esm/serverRoute.d.ts +6 -2
- package/dist/esm/serverRoute.js +3 -2
- package/dist/esm/serverRoute.js.map +1 -1
- package/dist/esm/session.d.ts +66 -0
- package/dist/esm/virtual-modules.d.ts +2 -0
- package/dist/esm/virtual-modules.js +2 -1
- package/dist/esm/virtual-modules.js.map +1 -1
- package/package.json +9 -19
- package/src/constants.ts +3 -0
- package/src/createStartHandler.ts +241 -143
- package/src/global.d.ts +10 -2
- package/src/index.tsx +42 -13
- package/src/loadVirtualModule.ts +2 -0
- package/src/request-response.ts +335 -0
- package/src/router-manifest.ts +17 -38
- package/src/server-functions-handler.ts +6 -5
- package/src/serverRoute.ts +22 -3
- package/src/session.ts +75 -0
- package/src/tanstack-start.d.ts +18 -5
- package/src/virtual-modules.ts +2 -0
- package/dist/cjs/createRequestHandler.cjs +0 -50
- package/dist/cjs/createRequestHandler.cjs.map +0 -1
- package/dist/cjs/createRequestHandler.d.cts +0 -8
- package/dist/cjs/createStartHandler.cjs +0 -274
- package/dist/cjs/createStartHandler.cjs.map +0 -1
- package/dist/cjs/createStartHandler.d.cts +0 -10
- package/dist/cjs/h3.cjs +0 -355
- package/dist/cjs/h3.cjs.map +0 -1
- package/dist/cjs/h3.d.cts +0 -109
- package/dist/cjs/handlerCallback.cjs +0 -7
- package/dist/cjs/handlerCallback.cjs.map +0 -1
- package/dist/cjs/handlerCallback.d.cts +0 -9
- package/dist/cjs/index.cjs +0 -245
- package/dist/cjs/index.cjs.map +0 -1
- package/dist/cjs/index.d.cts +0 -12
- package/dist/cjs/loadVirtualModule.cjs +0 -39
- package/dist/cjs/loadVirtualModule.cjs.map +0 -1
- package/dist/cjs/loadVirtualModule.d.cts +0 -6
- package/dist/cjs/router-manifest.cjs +0 -49
- package/dist/cjs/router-manifest.cjs.map +0 -1
- package/dist/cjs/router-manifest.d.cts +0 -16
- package/dist/cjs/server-functions-handler.cjs +0 -148
- package/dist/cjs/server-functions-handler.cjs.map +0 -1
- package/dist/cjs/server-functions-handler.d.cts +0 -3
- package/dist/cjs/serverRoute.cjs +0 -102
- package/dist/cjs/serverRoute.cjs.map +0 -1
- package/dist/cjs/serverRoute.d.cts +0 -120
- package/dist/cjs/ssr-server.cjs +0 -247
- package/dist/cjs/ssr-server.cjs.map +0 -1
- package/dist/cjs/ssr-server.d.cts +0 -29
- package/dist/cjs/transformStreamWithRouter.cjs +0 -183
- package/dist/cjs/transformStreamWithRouter.cjs.map +0 -1
- package/dist/cjs/transformStreamWithRouter.d.cts +0 -6
- package/dist/cjs/tsrScript.cjs +0 -4
- package/dist/cjs/tsrScript.cjs.map +0 -1
- package/dist/cjs/tsrScript.d.cts +0 -1
- package/dist/cjs/virtual-modules.cjs +0 -9
- package/dist/cjs/virtual-modules.cjs.map +0 -1
- package/dist/cjs/virtual-modules.d.cts +0 -10
- package/dist/esm/createRequestHandler.d.ts +0 -8
- package/dist/esm/createRequestHandler.js +0 -50
- package/dist/esm/createRequestHandler.js.map +0 -1
- package/dist/esm/h3.d.ts +0 -109
- package/dist/esm/h3.js +0 -248
- package/dist/esm/h3.js.map +0 -1
- package/dist/esm/handlerCallback.d.ts +0 -9
- package/dist/esm/handlerCallback.js +0 -7
- package/dist/esm/handlerCallback.js.map +0 -1
- package/dist/esm/ssr-server.d.ts +0 -29
- package/dist/esm/ssr-server.js +0 -247
- package/dist/esm/ssr-server.js.map +0 -1
- package/dist/esm/transformStreamWithRouter.d.ts +0 -6
- package/dist/esm/transformStreamWithRouter.js +0 -183
- package/dist/esm/transformStreamWithRouter.js.map +0 -1
- package/dist/esm/tsrScript.d.ts +0 -1
- package/dist/esm/tsrScript.js +0 -5
- package/dist/esm/tsrScript.js.map +0 -1
- package/src/createRequestHandler.ts +0 -73
- package/src/h3.ts +0 -492
- package/src/handlerCallback.ts +0 -15
- package/src/ssr-server.ts +0 -352
- package/src/transformStreamWithRouter.ts +0 -258
- package/src/tsrScript.ts +0 -91
- package/src/vite-env.d.ts +0 -4
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
H3Event,
|
|
5
|
+
clearSession as h3_clearSession,
|
|
6
|
+
deleteCookie as h3_deleteCookie,
|
|
7
|
+
getRequestHost as h3_getRequestHost,
|
|
8
|
+
getRequestIP as h3_getRequestIP,
|
|
9
|
+
getRequestProtocol as h3_getRequestProtocol,
|
|
10
|
+
getRequestURL as h3_getRequestURL,
|
|
11
|
+
getSession as h3_getSession,
|
|
12
|
+
getValidatedQuery as h3_getValidatedQuery,
|
|
13
|
+
parseCookies as h3_parseCookies,
|
|
14
|
+
sanitizeStatusCode as h3_sanitizeStatusCode,
|
|
15
|
+
sanitizeStatusMessage as h3_sanitizeStatusMessage,
|
|
16
|
+
sealSession as h3_sealSession,
|
|
17
|
+
setCookie as h3_setCookie,
|
|
18
|
+
toResponse as h3_toResponse,
|
|
19
|
+
unsealSession as h3_unsealSession,
|
|
20
|
+
updateSession as h3_updateSession,
|
|
21
|
+
useSession as h3_useSession,
|
|
22
|
+
} from 'h3'
|
|
23
|
+
import type {
|
|
24
|
+
RequestHeaderMap,
|
|
25
|
+
RequestHeaderName,
|
|
26
|
+
ResponseHeaderMap,
|
|
27
|
+
ResponseHeaderName,
|
|
28
|
+
TypedHeaders,
|
|
29
|
+
} from 'fetchdts'
|
|
30
|
+
|
|
31
|
+
import type { CookieSerializeOptions } from 'cookie-es'
|
|
32
|
+
import type {
|
|
33
|
+
Session,
|
|
34
|
+
SessionConfig,
|
|
35
|
+
SessionData,
|
|
36
|
+
SessionManager,
|
|
37
|
+
SessionUpdate,
|
|
38
|
+
} from './session'
|
|
39
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
40
|
+
|
|
41
|
+
interface StartEvent {
|
|
42
|
+
h3Event: H3Event
|
|
43
|
+
}
|
|
44
|
+
const eventStorage = new AsyncLocalStorage<StartEvent>()
|
|
45
|
+
|
|
46
|
+
export type RequestHandler = (request: Request) => Promise<Response> | Response
|
|
47
|
+
|
|
48
|
+
export type { ResponseHeaderName, RequestHeaderName }
|
|
49
|
+
|
|
50
|
+
export function requestHandler(handler: RequestHandler) {
|
|
51
|
+
return (request: Request): Promise<Response> | Response => {
|
|
52
|
+
const h3Event = new H3Event(request)
|
|
53
|
+
|
|
54
|
+
const response = eventStorage.run({ h3Event }, () => handler(request))
|
|
55
|
+
return h3_toResponse(response, h3Event)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getH3Event() {
|
|
60
|
+
const event = eventStorage.getStore()
|
|
61
|
+
if (!event) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`No StartEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.`,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
return event.h3Event
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getRequest(): Request {
|
|
70
|
+
const event = getH3Event()
|
|
71
|
+
return event.req
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function getRequestHeaders(): TypedHeaders<RequestHeaderMap> {
|
|
75
|
+
// TODO `as any` not needed when fetchdts is updated
|
|
76
|
+
return getH3Event().req.headers as any
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function getRequestHeader(name: RequestHeaderName): string | undefined {
|
|
80
|
+
return getRequestHeaders().get(name) || undefined
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function getRequestIP(opts?: {
|
|
84
|
+
/**
|
|
85
|
+
* Use the X-Forwarded-For HTTP header set by proxies.
|
|
86
|
+
*
|
|
87
|
+
* Note: Make sure that this header can be trusted (your application running behind a CDN or reverse proxy) before enabling.
|
|
88
|
+
*/
|
|
89
|
+
xForwardedFor?: boolean
|
|
90
|
+
}) {
|
|
91
|
+
return h3_getRequestIP(getH3Event(), opts)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get the request hostname.
|
|
96
|
+
*
|
|
97
|
+
* If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists.
|
|
98
|
+
*
|
|
99
|
+
* If no host header is found, it will default to "localhost".
|
|
100
|
+
*/
|
|
101
|
+
export function getRequestHost(opts?: { xForwardedHost?: boolean }) {
|
|
102
|
+
return h3_getRequestHost(getH3Event(), opts)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get the full incoming request URL.
|
|
107
|
+
*
|
|
108
|
+
* If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists.
|
|
109
|
+
*
|
|
110
|
+
* If `xForwardedProto` is `false`, it will not use the `x-forwarded-proto` header.
|
|
111
|
+
*/
|
|
112
|
+
export function getRequestUrl(opts?: {
|
|
113
|
+
xForwardedHost?: boolean
|
|
114
|
+
xForwardedProto?: boolean
|
|
115
|
+
}) {
|
|
116
|
+
return h3_getRequestURL(getH3Event(), opts)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get the request protocol.
|
|
121
|
+
*
|
|
122
|
+
* If `x-forwarded-proto` header is set to "https", it will return "https". You can disable this behavior by setting `xForwardedProto` to `false`.
|
|
123
|
+
*
|
|
124
|
+
* If protocol cannot be determined, it will default to "http".
|
|
125
|
+
*/
|
|
126
|
+
export function getRequestProtocol(opts?: {
|
|
127
|
+
xForwardedProto?: boolean
|
|
128
|
+
}): 'http' | 'https' | (string & {}) {
|
|
129
|
+
return h3_getRequestProtocol(getH3Event(), opts)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function setResponseHeaders(
|
|
133
|
+
headers: TypedHeaders<ResponseHeaderMap>,
|
|
134
|
+
): void {
|
|
135
|
+
const event = getH3Event()
|
|
136
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
137
|
+
event.res.headers.set(name, value)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function getResponseHeaders(): TypedHeaders<ResponseHeaderMap> {
|
|
142
|
+
const event = getH3Event()
|
|
143
|
+
return Object.fromEntries(event.res.headers.entries()) as any
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function getResponseHeader(
|
|
147
|
+
name: ResponseHeaderName,
|
|
148
|
+
): string | undefined {
|
|
149
|
+
const event = getH3Event()
|
|
150
|
+
return event.res.headers.get(name) || undefined
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function setResponseHeader(
|
|
154
|
+
name: ResponseHeaderName,
|
|
155
|
+
value: string | Array<string>,
|
|
156
|
+
): void {
|
|
157
|
+
const event = getH3Event()
|
|
158
|
+
if (Array.isArray(value)) {
|
|
159
|
+
event.res.headers.delete(name)
|
|
160
|
+
for (const valueItem of value) {
|
|
161
|
+
event.res.headers.append(name, valueItem)
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
event.res.headers.set(name, value)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export function removeResponseHeader(name: ResponseHeaderName): void {
|
|
168
|
+
const event = getH3Event()
|
|
169
|
+
event.res.headers.delete(name)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function clearResponseHeaders(
|
|
173
|
+
headerNames?: Array<ResponseHeaderName>,
|
|
174
|
+
): void {
|
|
175
|
+
const event = getH3Event()
|
|
176
|
+
// If headerNames is provided, clear only those headers
|
|
177
|
+
if (headerNames && headerNames.length > 0) {
|
|
178
|
+
for (const name of headerNames) {
|
|
179
|
+
event.res.headers.delete(name)
|
|
180
|
+
}
|
|
181
|
+
// Otherwise, clear all headers
|
|
182
|
+
} else {
|
|
183
|
+
for (const name of event.res.headers.keys()) {
|
|
184
|
+
event.res.headers.delete(name)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function getResponseStatus(): number {
|
|
190
|
+
return getH3Event().res.status || 200
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function setResponseStatus(code?: number, text?: string): void {
|
|
194
|
+
const event = getH3Event()
|
|
195
|
+
if (code) {
|
|
196
|
+
event.res.status = h3_sanitizeStatusCode(code, event.res.status)
|
|
197
|
+
}
|
|
198
|
+
if (text) {
|
|
199
|
+
event.res.statusText = h3_sanitizeStatusMessage(text)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Parse the request to get HTTP Cookie header string and return an object of all cookie name-value pairs.
|
|
205
|
+
* @returns Object of cookie name-value pairs
|
|
206
|
+
* ```ts
|
|
207
|
+
* const cookies = getCookies()
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export function getCookies(): Record<string, string> {
|
|
211
|
+
const event = getH3Event()
|
|
212
|
+
return h3_parseCookies(event)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get a cookie value by name.
|
|
217
|
+
* @param name Name of the cookie to get
|
|
218
|
+
* @returns {*} Value of the cookie (String or undefined)
|
|
219
|
+
* ```ts
|
|
220
|
+
* const authorization = getCookie('Authorization')
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
export function getCookie(name: string): string | undefined {
|
|
224
|
+
return getCookies()[name] || undefined
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Set a cookie value by name.
|
|
229
|
+
* @param name Name of the cookie to set
|
|
230
|
+
* @param value Value of the cookie to set
|
|
231
|
+
* @param options {CookieSerializeOptions} Options for serializing the cookie
|
|
232
|
+
* ```ts
|
|
233
|
+
* setCookie('Authorization', '1234567')
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export function setCookie(
|
|
237
|
+
name: string,
|
|
238
|
+
value: string,
|
|
239
|
+
options?: CookieSerializeOptions,
|
|
240
|
+
): void {
|
|
241
|
+
const event = getH3Event()
|
|
242
|
+
h3_setCookie(event, name, value, options)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Remove a cookie by name.
|
|
247
|
+
* @param name Name of the cookie to delete
|
|
248
|
+
* @param serializeOptions {CookieSerializeOptions} Cookie options
|
|
249
|
+
* ```ts
|
|
250
|
+
* deleteCookie('SessionId')
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
export function deleteCookie(
|
|
254
|
+
name: string,
|
|
255
|
+
options?: CookieSerializeOptions,
|
|
256
|
+
): void {
|
|
257
|
+
const event = getH3Event()
|
|
258
|
+
h3_deleteCookie(event, name, options)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function getDefaultSessionConfig(config: SessionConfig): SessionConfig {
|
|
262
|
+
return {
|
|
263
|
+
name: 'start',
|
|
264
|
+
...config,
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Create a session manager for the current request.
|
|
270
|
+
*/
|
|
271
|
+
export function useSession<TSessionData extends SessionData = SessionData>(
|
|
272
|
+
config: SessionConfig,
|
|
273
|
+
): Promise<SessionManager<TSessionData>> {
|
|
274
|
+
const event = getH3Event()
|
|
275
|
+
return h3_useSession(event, getDefaultSessionConfig(config))
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Get the session for the current request
|
|
279
|
+
*/
|
|
280
|
+
export function getSession<TSessionData extends SessionData = SessionData>(
|
|
281
|
+
config: SessionConfig,
|
|
282
|
+
): Promise<Session<TSessionData>> {
|
|
283
|
+
const event = getH3Event()
|
|
284
|
+
return h3_getSession(event, getDefaultSessionConfig(config))
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Update the session data for the current request.
|
|
289
|
+
*/
|
|
290
|
+
export function updateSession<TSessionData extends SessionData = SessionData>(
|
|
291
|
+
config: SessionConfig,
|
|
292
|
+
update?: SessionUpdate<TSessionData>,
|
|
293
|
+
): Promise<Session<TSessionData>> {
|
|
294
|
+
const event = getH3Event()
|
|
295
|
+
return h3_updateSession(event, getDefaultSessionConfig(config), update)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Encrypt and sign the session data for the current request.
|
|
300
|
+
*/
|
|
301
|
+
export function sealSession(config: SessionConfig): Promise<string> {
|
|
302
|
+
const event = getH3Event()
|
|
303
|
+
return h3_sealSession(event, getDefaultSessionConfig(config))
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Decrypt and verify the session data for the current request.
|
|
307
|
+
*/
|
|
308
|
+
export function unsealSession(
|
|
309
|
+
config: SessionConfig,
|
|
310
|
+
sealed: string,
|
|
311
|
+
): Promise<Partial<Session>> {
|
|
312
|
+
const event = getH3Event()
|
|
313
|
+
return h3_unsealSession(event, getDefaultSessionConfig(config), sealed)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Clear the session data for the current request.
|
|
318
|
+
*/
|
|
319
|
+
export function clearSession(config: Partial<SessionConfig>): Promise<void> {
|
|
320
|
+
const event = getH3Event()
|
|
321
|
+
return h3_clearSession(event, { name: 'start', ...config })
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// not public API
|
|
325
|
+
export function getResponse() {
|
|
326
|
+
const event = getH3Event()
|
|
327
|
+
return event._res
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// not public API (yet)
|
|
331
|
+
export function getValidatedQuery<TSchema extends StandardSchemaV1>(
|
|
332
|
+
schema: StandardSchemaV1,
|
|
333
|
+
): Promise<StandardSchemaV1.InferOutput<TSchema>> {
|
|
334
|
+
return h3_getValidatedQuery(getH3Event(), schema)
|
|
335
|
+
}
|
package/src/router-manifest.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rootRouteId } from '@tanstack/router-core'
|
|
2
2
|
import { VIRTUAL_MODULES } from './virtual-modules'
|
|
3
3
|
import { loadVirtualModule } from './loadVirtualModule'
|
|
4
4
|
|
|
@@ -19,45 +19,24 @@ export async function getStartManifest(opts: { basePath: string }) {
|
|
|
19
19
|
|
|
20
20
|
rootRoute.assets = rootRoute.assets || []
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// ClientManifest.inputs[ClientManifest.handler]?.output.path
|
|
27
|
-
// if (!importPath) {
|
|
28
|
-
// invariant(importPath, 'Could not find client entry in manifest')
|
|
29
|
-
// }
|
|
30
|
-
|
|
31
|
-
if (process.env.NODE_ENV === 'development' && !process.env.TSS_CLIENT_ENTRY) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
'tanstack/start-server-core: TSS_CLIENT_ENTRY must be defined in your environment for getStartManifest()',
|
|
22
|
+
let script = `import('${startManifest.clientEntry}')`
|
|
23
|
+
if (process.env.TSS_DEV_SERVER === 'true') {
|
|
24
|
+
const { injectedHeadScripts } = await loadVirtualModule(
|
|
25
|
+
VIRTUAL_MODULES.injectedHeadScripts,
|
|
34
26
|
)
|
|
27
|
+
if (injectedHeadScripts) {
|
|
28
|
+
script = `${injectedHeadScripts + ';'}${script}`
|
|
29
|
+
}
|
|
35
30
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// }
|
|
46
|
-
|
|
47
|
-
const clientEntry = joinPaths([opts.basePath, process.env.TSS_CLIENT_ENTRY])
|
|
48
|
-
|
|
49
|
-
const script = `${globalThis.TSS_INJECTED_HEAD_SCRIPTS ? globalThis.TSS_INJECTED_HEAD_SCRIPTS + '; ' : ''}import('${clientEntry}')`
|
|
50
|
-
|
|
51
|
-
rootRoute.assets.push({
|
|
52
|
-
tag: 'script',
|
|
53
|
-
attrs: {
|
|
54
|
-
type: 'module',
|
|
55
|
-
suppressHydrationWarning: true,
|
|
56
|
-
async: true,
|
|
57
|
-
},
|
|
58
|
-
children: script,
|
|
59
|
-
})
|
|
60
|
-
}
|
|
31
|
+
rootRoute.assets.push({
|
|
32
|
+
tag: 'script',
|
|
33
|
+
attrs: {
|
|
34
|
+
type: 'module',
|
|
35
|
+
suppressHydrationWarning: true,
|
|
36
|
+
async: true,
|
|
37
|
+
},
|
|
38
|
+
children: script,
|
|
39
|
+
})
|
|
61
40
|
|
|
62
41
|
const manifest = {
|
|
63
42
|
...startManifest,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isNotFound } from '@tanstack/router-core'
|
|
2
2
|
import invariant from 'tiny-invariant'
|
|
3
3
|
import { startSerializer } from '@tanstack/start-client-core'
|
|
4
|
-
import { getEvent, getResponseStatus } from './h3'
|
|
5
4
|
import { VIRTUAL_MODULES } from './virtual-modules'
|
|
6
5
|
import { loadVirtualModule } from './loadVirtualModule'
|
|
6
|
+
import { getResponse } from './request-response'
|
|
7
7
|
|
|
8
8
|
function sanitizeBase(base: string | undefined) {
|
|
9
9
|
if (!base) {
|
|
@@ -55,8 +55,7 @@ export const handleServerAction = async ({ request }: { request: Request }) => {
|
|
|
55
55
|
throw new Error('Server function info not found for ' + serverFnId)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
const fnModule
|
|
59
|
-
await serverFnInfo.importer()
|
|
58
|
+
const fnModule = await serverFnInfo.importer()
|
|
60
59
|
|
|
61
60
|
if (!fnModule) {
|
|
62
61
|
console.info('serverFnInfo', serverFnInfo)
|
|
@@ -188,10 +187,12 @@ export const handleServerAction = async ({ request }: { request: Request }) => {
|
|
|
188
187
|
return isNotFoundResponse(result)
|
|
189
188
|
}
|
|
190
189
|
|
|
190
|
+
const response = getResponse()
|
|
191
191
|
return new Response(
|
|
192
192
|
result !== undefined ? startSerializer.stringify(result) : undefined,
|
|
193
193
|
{
|
|
194
|
-
status:
|
|
194
|
+
status: response?.status,
|
|
195
|
+
statusText: response?.statusText,
|
|
195
196
|
headers: {
|
|
196
197
|
'Content-Type': 'application/json',
|
|
197
198
|
},
|
|
@@ -246,7 +247,7 @@ function isNotFoundResponse(error: any) {
|
|
|
246
247
|
const { headers, ...rest } = error
|
|
247
248
|
|
|
248
249
|
return new Response(JSON.stringify(rest), {
|
|
249
|
-
status:
|
|
250
|
+
status: 404,
|
|
250
251
|
headers: {
|
|
251
252
|
'Content-Type': 'application/json',
|
|
252
253
|
...(headers || {}),
|
package/src/serverRoute.ts
CHANGED
|
@@ -42,10 +42,25 @@ export interface ServerRouteOptions<
|
|
|
42
42
|
pathname: TFullPath
|
|
43
43
|
originalIndex: number
|
|
44
44
|
getParentRoute?: () => TParentRoute
|
|
45
|
-
middleware
|
|
46
|
-
methods
|
|
45
|
+
middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>
|
|
46
|
+
methods?: Record<
|
|
47
47
|
string,
|
|
48
|
-
ServerRouteMethodHandlerFn<
|
|
48
|
+
| ServerRouteMethodHandlerFn<
|
|
49
|
+
TParentRoute,
|
|
50
|
+
TFullPath,
|
|
51
|
+
TMiddlewares,
|
|
52
|
+
any,
|
|
53
|
+
any
|
|
54
|
+
>
|
|
55
|
+
| {
|
|
56
|
+
_options: ServerRouteMethodBuilderOptions<
|
|
57
|
+
TParentRoute,
|
|
58
|
+
TFullPath,
|
|
59
|
+
TMiddlewares,
|
|
60
|
+
unknown,
|
|
61
|
+
unknown
|
|
62
|
+
>
|
|
63
|
+
}
|
|
49
64
|
>
|
|
50
65
|
caseSensitive?: boolean
|
|
51
66
|
}
|
|
@@ -70,6 +85,7 @@ export function createServerRoute<
|
|
|
70
85
|
const options = __opts || {}
|
|
71
86
|
|
|
72
87
|
const route: ServerRoute<TParentRoute, TId, TPath, TFullPath, TChildren> = {
|
|
88
|
+
isRoot: false as any,
|
|
73
89
|
path: '' as TPath,
|
|
74
90
|
id: '' as TId,
|
|
75
91
|
fullPath: '' as TFullPath,
|
|
@@ -162,6 +178,7 @@ export function createServerRoute<
|
|
|
162
178
|
route.id = id as TId
|
|
163
179
|
route.fullPath = fullPath as TFullPath
|
|
164
180
|
route.to = fullPath as TrimPathRight<TFullPath>
|
|
181
|
+
route.isRoot = isRoot as any
|
|
165
182
|
},
|
|
166
183
|
|
|
167
184
|
_addFileChildren: (children) => {
|
|
@@ -290,6 +307,7 @@ export interface ServerRouteWithTypes<
|
|
|
290
307
|
TMiddlewares,
|
|
291
308
|
TMethods
|
|
292
309
|
>
|
|
310
|
+
isRoot: TParentRoute extends AnyServerRouteWithTypes ? true : false
|
|
293
311
|
path: TPath
|
|
294
312
|
id: TId
|
|
295
313
|
fullPath: TFullPath
|
|
@@ -329,6 +347,7 @@ export interface ServerRouteTypes<
|
|
|
329
347
|
TMiddlewares,
|
|
330
348
|
TMethods,
|
|
331
349
|
> {
|
|
350
|
+
isRoot: TParentRoute extends AnyServerRouteWithTypes ? true : false
|
|
332
351
|
id: TId
|
|
333
352
|
path: TPath
|
|
334
353
|
fullPath: TFullPath
|
package/src/session.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// TODO discuss do we want to copy this interface into Start we well?
|
|
2
|
+
import type { CookieSerializeOptions } from 'cookie-es'
|
|
3
|
+
|
|
4
|
+
// TODO discuss do we want to copy this interface into Start as shown below?
|
|
5
|
+
|
|
6
|
+
/** Algorithm used for encryption and decryption. */
|
|
7
|
+
type EncryptionAlgorithm = 'aes-128-ctr' | 'aes-256-cbc'
|
|
8
|
+
/** Algorithm used for integrity verification. */
|
|
9
|
+
type IntegrityAlgorithm = 'sha256'
|
|
10
|
+
/** @internal */
|
|
11
|
+
type _Algorithm = EncryptionAlgorithm | IntegrityAlgorithm
|
|
12
|
+
/**
|
|
13
|
+
* Options for customizing the key derivation algorithm used to generate encryption and integrity verification keys as well as the algorithms and salt sizes used.
|
|
14
|
+
*/
|
|
15
|
+
type SealOptions = Readonly<{
|
|
16
|
+
/** Encryption step options. */
|
|
17
|
+
encryption: SealOptionsSub<EncryptionAlgorithm>
|
|
18
|
+
/** Integrity step options. */
|
|
19
|
+
integrity: SealOptionsSub<IntegrityAlgorithm>
|
|
20
|
+
/* Sealed object lifetime in milliseconds where 0 means forever. Defaults to 0. */
|
|
21
|
+
ttl: number
|
|
22
|
+
/** Number of seconds of permitted clock skew for incoming expirations. Defaults to 60 seconds. */
|
|
23
|
+
timestampSkewSec: number
|
|
24
|
+
/**
|
|
25
|
+
* Local clock time offset, expressed in number of milliseconds (positive or negative). Defaults to 0.
|
|
26
|
+
*/
|
|
27
|
+
localtimeOffsetMsec: number
|
|
28
|
+
}>
|
|
29
|
+
/** `seal()` method options. */
|
|
30
|
+
type SealOptionsSub<TAlgorithm extends _Algorithm = _Algorithm> = Readonly<{
|
|
31
|
+
/** The length of the salt (random buffer used to ensure that two identical objects will generate a different encrypted result). Defaults to 256. */
|
|
32
|
+
saltBits: number
|
|
33
|
+
/** The algorithm used. Defaults to 'aes-256-cbc' for encryption and 'sha256' for integrity. */
|
|
34
|
+
algorithm: TAlgorithm
|
|
35
|
+
/** The number of iterations used to derive a key from the password. Defaults to 1. */
|
|
36
|
+
iterations: number
|
|
37
|
+
/** Minimum password size. Defaults to 32. */
|
|
38
|
+
minPasswordlength: number
|
|
39
|
+
}>
|
|
40
|
+
/** Password secret string or buffer.*/
|
|
41
|
+
|
|
42
|
+
type SessionDataT = Record<string, any>
|
|
43
|
+
export type SessionData<T extends SessionDataT = SessionDataT> = Partial<T>
|
|
44
|
+
export interface Session<T extends SessionDataT = SessionDataT> {
|
|
45
|
+
id: string
|
|
46
|
+
createdAt: number
|
|
47
|
+
data: SessionData<T>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type SessionUpdate<T extends SessionData = SessionData> =
|
|
51
|
+
| Partial<SessionData<T>>
|
|
52
|
+
| ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined)
|
|
53
|
+
|
|
54
|
+
export interface SessionManager<T extends SessionDataT = SessionDataT> {
|
|
55
|
+
readonly id: string | undefined
|
|
56
|
+
readonly data: SessionData<T>
|
|
57
|
+
update: (update: SessionUpdate<T>) => Promise<SessionManager<T>>
|
|
58
|
+
clear: () => Promise<SessionManager<T>>
|
|
59
|
+
}
|
|
60
|
+
export interface SessionConfig {
|
|
61
|
+
/** Private key used to encrypt session tokens */
|
|
62
|
+
password: string
|
|
63
|
+
/** Session expiration time in seconds */
|
|
64
|
+
maxAge?: number
|
|
65
|
+
/** default is 'start' */
|
|
66
|
+
name?: string
|
|
67
|
+
/** Default is secure, httpOnly, / */
|
|
68
|
+
cookie?: false | CookieSerializeOptions
|
|
69
|
+
/** Default is x-start-session / x-{name}-session */
|
|
70
|
+
sessionHeader?: false | string
|
|
71
|
+
seal?: SealOptions
|
|
72
|
+
crypto?: Crypto
|
|
73
|
+
/** Default is Crypto.randomUUID */
|
|
74
|
+
generateId?: () => string
|
|
75
|
+
}
|
package/src/tanstack-start.d.ts
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
declare module 'tanstack-start-manifest:v' {
|
|
2
2
|
import type { Manifest } from '@tanstack/router-core'
|
|
3
3
|
|
|
4
|
-
export const tsrStartManifest: () => Manifest
|
|
4
|
+
export const tsrStartManifest: () => Manifest & { clientEntry: string }
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
declare module 'tanstack-start-route-tree:v' {
|
|
8
|
-
import type {
|
|
8
|
+
import type { AnyServerRouteWithTypes } from '@tanstack/start-server-core'
|
|
9
|
+
import type { AnyRoute } from '@tanstack/router-core'
|
|
9
10
|
|
|
10
|
-
export const
|
|
11
|
+
export const routeTree: AnyRoute | undefined
|
|
12
|
+
export const serverRouteTree: AnyServerRouteWithTypes | undefined
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
declare module 'tanstack-start-server-fn-manifest:v' {
|
|
14
|
-
|
|
16
|
+
const serverFnManifest: Record<
|
|
17
|
+
string,
|
|
18
|
+
{
|
|
19
|
+
importer: () => Promise<
|
|
20
|
+
Record<string, (...args: Array<any>) => Promise<any>> | undefined
|
|
21
|
+
>
|
|
22
|
+
functionName: string
|
|
23
|
+
}
|
|
24
|
+
>
|
|
15
25
|
|
|
16
|
-
const serverFnManifest: Record<string, DirectiveFn>
|
|
17
26
|
export default serverFnManifest
|
|
18
27
|
}
|
|
28
|
+
|
|
29
|
+
declare module 'tanstack-start-injected-head-scripts:v' {
|
|
30
|
+
export const injectedHeadScripts: string | undefined
|
|
31
|
+
}
|
package/src/virtual-modules.ts
CHANGED
|
@@ -4,10 +4,12 @@ export const VIRTUAL_MODULES = {
|
|
|
4
4
|
routeTree: 'tanstack-start-route-tree:v',
|
|
5
5
|
startManifest: 'tanstack-start-manifest:v',
|
|
6
6
|
serverFnManifest: 'tanstack-start-server-fn-manifest:v',
|
|
7
|
+
injectedHeadScripts: 'tanstack-start-injected-head-scripts:v',
|
|
7
8
|
} as const
|
|
8
9
|
|
|
9
10
|
export type VirtualModules = {
|
|
10
11
|
[VIRTUAL_MODULES.routeTree]: typeof import('tanstack-start-route-tree:v')
|
|
11
12
|
[VIRTUAL_MODULES.startManifest]: typeof import('tanstack-start-manifest:v')
|
|
12
13
|
[VIRTUAL_MODULES.serverFnManifest]: typeof import('tanstack-start-server-fn-manifest:v')
|
|
14
|
+
[VIRTUAL_MODULES.injectedHeadScripts]: typeof import('tanstack-start-injected-head-scripts:v')
|
|
13
15
|
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const history = require("@tanstack/history");
|
|
4
|
-
const startClientCore = require("@tanstack/start-client-core");
|
|
5
|
-
const ssrServer = require("./ssr-server.cjs");
|
|
6
|
-
function createRequestHandler({
|
|
7
|
-
createRouter,
|
|
8
|
-
request,
|
|
9
|
-
getRouterManifest
|
|
10
|
-
}) {
|
|
11
|
-
return async (cb) => {
|
|
12
|
-
const router = createRouter();
|
|
13
|
-
ssrServer.attachRouterServerSsrUtils(router, await (getRouterManifest == null ? void 0 : getRouterManifest()));
|
|
14
|
-
const url = new URL(request.url, "http://localhost");
|
|
15
|
-
const href = url.href.replace(url.origin, "");
|
|
16
|
-
const history$1 = history.createMemoryHistory({
|
|
17
|
-
initialEntries: [href]
|
|
18
|
-
});
|
|
19
|
-
router.update({
|
|
20
|
-
history: history$1
|
|
21
|
-
});
|
|
22
|
-
await router.load();
|
|
23
|
-
ssrServer.dehydrateRouter(router);
|
|
24
|
-
const responseHeaders = getRequestHeaders({
|
|
25
|
-
router
|
|
26
|
-
});
|
|
27
|
-
return cb({
|
|
28
|
-
request,
|
|
29
|
-
router,
|
|
30
|
-
responseHeaders
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function getRequestHeaders(opts) {
|
|
35
|
-
let headers = startClientCore.mergeHeaders(
|
|
36
|
-
{
|
|
37
|
-
"Content-Type": "text/html; charset=UTF-8"
|
|
38
|
-
},
|
|
39
|
-
...opts.router.state.matches.map((match) => {
|
|
40
|
-
return match.headers;
|
|
41
|
-
})
|
|
42
|
-
);
|
|
43
|
-
const { redirect } = opts.router.state;
|
|
44
|
-
if (redirect) {
|
|
45
|
-
headers = startClientCore.mergeHeaders(headers, redirect.headers);
|
|
46
|
-
}
|
|
47
|
-
return headers;
|
|
48
|
-
}
|
|
49
|
-
exports.createRequestHandler = createRequestHandler;
|
|
50
|
-
//# sourceMappingURL=createRequestHandler.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createRequestHandler.cjs","sources":["../../src/createRequestHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport { mergeHeaders } from '@tanstack/start-client-core'\nimport { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server'\nimport type { HandlerCallback } from './handlerCallback'\nimport type { AnyRouter, Manifest } from '@tanstack/router-core'\n\nexport type RequestHandler<TRouter extends AnyRouter> = (\n cb: HandlerCallback<TRouter>,\n) => Promise<Response>\n\nexport function createRequestHandler<TRouter extends AnyRouter>({\n createRouter,\n request,\n getRouterManifest,\n}: {\n createRouter: () => TRouter\n request: Request\n getRouterManifest?: () => Manifest | Promise<Manifest>\n}): RequestHandler<TRouter> {\n return async (cb) => {\n const router = createRouter()\n\n attachRouterServerSsrUtils(router, await getRouterManifest?.())\n\n const url = new URL(request.url, 'http://localhost')\n\n const href = url.href.replace(url.origin, '')\n\n // Create a history for the router\n const history = createMemoryHistory({\n initialEntries: [href],\n })\n\n // Update the router with the history and context\n router.update({\n history,\n })\n\n await router.load()\n\n dehydrateRouter(router)\n\n const responseHeaders = getRequestHeaders({\n router,\n })\n\n return cb({\n request,\n router,\n responseHeaders,\n } as any)\n }\n}\n\nfunction getRequestHeaders(opts: { router: AnyRouter }): Headers {\n let headers = mergeHeaders(\n {\n 'Content-Type': 'text/html; charset=UTF-8',\n },\n ...opts.router.state.matches.map((match) => {\n return match.headers\n }),\n )\n\n // Handle Redirects\n const { redirect } = opts.router.state\n\n if (redirect) {\n headers = mergeHeaders(headers, redirect.headers)\n }\n\n return headers\n}\n"],"names":["attachRouterServerSsrUtils","history","createMemoryHistory","dehydrateRouter","mergeHeaders"],"mappings":";;;;;AAUO,SAAS,qBAAgD;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AACF,GAI4B;AAC1B,SAAO,OAAO,OAAO;AACnB,UAAM,SAAS,aAAa;AAEDA,yCAAA,QAAQ,OAAM,yDAAqB;AAE9D,UAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,kBAAkB;AAEnD,UAAM,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,EAAE;AAG5C,UAAMC,YAAUC,QAAAA,oBAAoB;AAAA,MAClC,gBAAgB,CAAC,IAAI;AAAA,IAAA,CACtB;AAGD,WAAO,OAAO;AAAA,MACZD,SAAAA;AAAAA,IAAA,CACD;AAED,UAAM,OAAO,KAAK;AAElBE,cAAAA,gBAAgB,MAAM;AAEtB,UAAM,kBAAkB,kBAAkB;AAAA,MACxC;AAAA,IAAA,CACD;AAED,WAAO,GAAG;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACM;AAAA,EACV;AACF;AAEA,SAAS,kBAAkB,MAAsC;AAC/D,MAAI,UAAUC,gBAAA;AAAA,IACZ;AAAA,MACE,gBAAgB;AAAA,IAClB;AAAA,IACA,GAAG,KAAK,OAAO,MAAM,QAAQ,IAAI,CAAC,UAAU;AAC1C,aAAO,MAAM;AAAA,IACd,CAAA;AAAA,EACH;AAGA,QAAM,EAAE,SAAA,IAAa,KAAK,OAAO;AAEjC,MAAI,UAAU;AACF,cAAAA,gBAAA,aAAa,SAAS,SAAS,OAAO;AAAA,EAAA;AAG3C,SAAA;AACT;;"}
|