1
- import * as cookie from 'cookie' ;
2
1
import * as set_cookie_parser from 'set-cookie-parser' ;
3
- import { respond } from '../index.js' ;
4
- import { domain_matches , path_matches } from '../cookie.js' ;
2
+ import { respond } from './index.js' ;
5
3
6
4
/**
7
5
* @param {{
8
6
* event: import('types').RequestEvent;
9
7
* options: import('types').SSROptions;
10
8
* state: import('types').SSRState;
11
- * route: import('types').SSRRoute | import('types').SSRErrorPage;
12
- * prerender_default?: import('types').PrerenderOption;
13
- * resolve_opts: import('types').RequiredResolveOptions;
9
+ * get_cookie_header: (url: URL, header: string | null) => string;
14
10
* }} opts
11
+ * @returns {typeof fetch }
15
12
*/
16
- export function create_fetch ( { event, options, state, route, prerender_default, resolve_opts } ) {
17
- /** @type {import('./types').Fetched[] } */
18
- const fetched = [ ] ;
19
-
20
- const initial_cookies = cookie . parse ( event . request . headers . get ( 'cookie' ) || '' ) ;
21
-
22
- /** @type {import('./types').Cookie[] } */
23
- const set_cookies = [ ] ;
24
-
25
- /**
26
- * @param {URL } url
27
- * @param {string | null } header
28
- */
29
- function get_cookie_header ( url , header ) {
30
- /** @type {Record<string, string> } */
31
- const new_cookies = { } ;
32
-
33
- for ( const cookie of set_cookies ) {
34
- if ( ! domain_matches ( url . hostname , cookie . options . domain ) ) continue ;
35
- if ( ! path_matches ( url . pathname , cookie . options . path ) ) continue ;
36
-
37
- new_cookies [ cookie . name ] = cookie . value ;
38
- }
39
-
40
- // cookies from explicit `cookie` header take precedence over cookies previously set
41
- // during this load with `set-cookie`, which take precedence over the cookies
42
- // sent by the user agent
43
- const combined_cookies = {
44
- ...initial_cookies ,
45
- ...new_cookies ,
46
- ...cookie . parse ( header ?? '' )
47
- } ;
48
-
49
- return Object . entries ( combined_cookies )
50
- . map ( ( [ name , value ] ) => `${ name } =${ value } ` )
51
- . join ( '; ' ) ;
52
- }
53
-
54
- /** @type {typeof fetch } */
55
- const fetcher = async ( info , init ) => {
13
+ export function create_fetch ( { event, options, state, get_cookie_header } ) {
14
+ return async ( info , init ) => {
56
15
const request = normalize_fetch_input ( info , init , event . url ) ;
57
16
58
17
const request_body = init ?. body ;
59
18
60
19
/** @type {import('types').PrerenderDependency } */
61
20
let dependency ;
62
21
63
- const response = await options . hooks . handleFetch ( {
22
+ return await options . hooks . handleFetch ( {
64
23
event,
65
24
request,
66
25
fetch : async ( info , init ) => {
@@ -174,11 +133,7 @@ export function create_fetch({ event, options, state, route, prerender_default,
174
133
throw new Error ( 'Request body must be a string or TypedArray' ) ;
175
134
}
176
135
177
- response = await respond ( request , options , {
178
- prerender_default,
179
- ...state ,
180
- initiator : route
181
- } ) ;
136
+ response = await respond ( request , options , state ) ;
182
137
183
138
if ( state . prerendering ) {
184
139
dependency = { response, body : null } ;
@@ -187,104 +142,22 @@ export function create_fetch({ event, options, state, route, prerender_default,
187
142
188
143
const set_cookie = response . headers . get ( 'set-cookie' ) ;
189
144
if ( set_cookie ) {
190
- set_cookies . push (
191
- ...set_cookie_parser . splitCookiesString ( set_cookie ) . map ( ( str ) => {
192
- const { name, value, ...options } = set_cookie_parser . parseString ( str ) ;
193
- // options.sameSite is string, something more specific is required - type cast is safe
194
- return /** @type {import('./types').Cookie } */ ( { name, value, options } ) ;
195
- } )
196
- ) ;
197
- }
198
-
199
- return response ;
200
- }
201
- } ) ;
202
-
203
- const proxy = new Proxy ( response , {
204
- get ( response , key , _receiver ) {
205
- async function text ( ) {
206
- const body = await response . text ( ) ;
207
-
208
- if ( ! body || typeof body === 'string' ) {
209
- const status_number = Number ( response . status ) ;
210
- if ( isNaN ( status_number ) ) {
211
- throw new Error (
212
- `response.status is not a number. value: "${
213
- response . status
214
- } " type: ${ typeof response . status } `
215
- ) ;
216
- }
217
-
218
- fetched . push ( {
219
- url : request . url . startsWith ( event . url . origin )
220
- ? request . url . slice ( event . url . origin . length )
221
- : request . url ,
222
- method : request . method ,
223
- request_body : /** @type {string | ArrayBufferView | undefined } */ ( request_body ) ,
224
- response_body : body ,
225
- response : response
226
- } ) ;
227
-
228
- // ensure that excluded headers can't be read
229
- const get = response . headers . get ;
230
- response . headers . get = ( key ) => {
231
- const lower = key . toLowerCase ( ) ;
232
- const value = get . call ( response . headers , lower ) ;
233
- if ( value && ! lower . startsWith ( 'x-sveltekit-' ) ) {
234
- const included = resolve_opts . filterSerializedResponseHeaders ( lower , value ) ;
235
- if ( ! included ) {
236
- throw new Error (
237
- `Failed to get response header "${ lower } " — it must be included by the \`filterSerializedResponseHeaders\` option: https://kit.svelte.dev/docs/hooks#handle`
238
- ) ;
239
- }
240
- }
241
-
242
- return value ;
243
- } ;
145
+ for ( const str of set_cookie_parser . splitCookiesString ( set_cookie ) ) {
146
+ const { name, value, ...options } = set_cookie_parser . parseString ( str ) ;
147
+
148
+ // options.sameSite is string, something more specific is required - type cast is safe
149
+ event . cookies . set (
150
+ name ,
151
+ value ,
152
+ /** @type {import('cookie').CookieSerializeOptions } */ ( options )
153
+ ) ;
244
154
}
245
-
246
- if ( dependency ) {
247
- dependency . body = body ;
248
- }
249
-
250
- return body ;
251
155
}
252
156
253
- if ( key === 'arrayBuffer' ) {
254
- return async ( ) => {
255
- const buffer = await response . arrayBuffer ( ) ;
256
-
257
- if ( dependency ) {
258
- dependency . body = new Uint8Array ( buffer ) ;
259
- }
260
-
261
- // TODO should buffer be inlined into the page (albeit base64'd)?
262
- // any conditions in which it shouldn't be?
263
-
264
- return buffer ;
265
- } ;
266
- }
267
-
268
- if ( key === 'text' ) {
269
- return text ;
270
- }
271
-
272
- if ( key === 'json' ) {
273
- return async ( ) => {
274
- return JSON . parse ( await text ( ) ) ;
275
- } ;
276
- }
277
-
278
- // TODO arrayBuffer?
279
-
280
- return Reflect . get ( response , key , response ) ;
157
+ return response ;
281
158
}
282
159
} ) ;
283
-
284
- return proxy ;
285
160
} ;
286
-
287
- return { fetcher, fetched, cookies : set_cookies } ;
288
161
}
289
162
290
163
/**
0 commit comments