@sveltejs/kit 1.0.0-next.43 → 1.0.0-next.430
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 +12 -9
- package/package.json +95 -63
- package/src/cli.js +112 -0
- package/src/core/adapt/builder.js +207 -0
- package/src/core/adapt/index.js +19 -0
- package/src/core/config/index.js +86 -0
- package/src/core/config/options.js +488 -0
- package/src/core/config/types.d.ts +1 -0
- package/src/core/constants.js +5 -0
- package/src/core/env.js +97 -0
- package/src/core/generate_manifest/index.js +99 -0
- package/src/core/prerender/crawl.js +194 -0
- package/src/core/prerender/prerender.js +378 -0
- package/src/core/prerender/queue.js +80 -0
- package/src/core/sync/create_manifest_data/index.js +506 -0
- package/src/core/sync/create_manifest_data/types.d.ts +40 -0
- package/src/core/sync/sync.js +59 -0
- package/src/core/sync/utils.js +44 -0
- package/src/core/sync/write_ambient.js +27 -0
- package/src/core/sync/write_client_manifest.js +82 -0
- package/src/core/sync/write_matchers.js +25 -0
- package/src/core/sync/write_root.js +91 -0
- package/src/core/sync/write_tsconfig.js +195 -0
- package/src/core/sync/write_types.js +775 -0
- package/src/core/utils.js +70 -0
- package/src/hooks.js +26 -0
- package/src/index/index.js +45 -0
- package/src/index/private.js +33 -0
- package/src/node/index.js +145 -0
- package/src/node/polyfills.js +40 -0
- package/src/runtime/app/env.js +11 -0
- package/src/runtime/app/navigation.js +22 -0
- package/src/runtime/app/paths.js +1 -0
- package/src/runtime/app/stores.js +102 -0
- package/src/runtime/client/ambient.d.ts +17 -0
- package/src/runtime/client/client.js +1289 -0
- package/src/runtime/client/fetcher.js +60 -0
- package/src/runtime/client/parse.js +36 -0
- package/src/runtime/client/singletons.js +21 -0
- package/src/runtime/client/start.js +46 -0
- package/src/runtime/client/types.d.ts +105 -0
- package/src/runtime/client/utils.js +113 -0
- package/src/runtime/components/error.svelte +16 -0
- package/{assets → src/runtime}/components/layout.svelte +0 -0
- package/src/runtime/env/dynamic/private.js +1 -0
- package/src/runtime/env/dynamic/public.js +1 -0
- package/src/runtime/env-private.js +7 -0
- package/src/runtime/env-public.js +7 -0
- package/src/runtime/env.js +6 -0
- package/src/runtime/hash.js +16 -0
- package/src/runtime/paths.js +11 -0
- package/src/runtime/server/endpoint.js +58 -0
- package/src/runtime/server/index.js +448 -0
- package/src/runtime/server/page/cookie.js +25 -0
- package/src/runtime/server/page/crypto.js +239 -0
- package/src/runtime/server/page/csp.js +249 -0
- package/src/runtime/server/page/fetch.js +266 -0
- package/src/runtime/server/page/index.js +416 -0
- package/src/runtime/server/page/load_data.js +135 -0
- package/src/runtime/server/page/render.js +362 -0
- package/src/runtime/server/page/respond_with_error.js +94 -0
- package/src/runtime/server/page/types.d.ts +44 -0
- package/src/runtime/server/utils.js +116 -0
- package/src/utils/error.js +22 -0
- package/src/utils/escape.js +104 -0
- package/src/utils/filesystem.js +108 -0
- package/src/utils/http.js +55 -0
- package/src/utils/misc.js +1 -0
- package/src/utils/routing.js +108 -0
- package/src/utils/url.js +97 -0
- package/src/vite/build/build_server.js +337 -0
- package/src/vite/build/build_service_worker.js +90 -0
- package/src/vite/build/utils.js +160 -0
- package/src/vite/dev/index.js +551 -0
- package/src/vite/index.js +574 -0
- package/src/vite/preview/index.js +186 -0
- package/src/vite/types.d.ts +3 -0
- package/src/vite/utils.js +345 -0
- package/svelte-kit.js +1 -1
- package/types/ambient.d.ts +357 -0
- package/types/index.d.ts +343 -0
- package/types/internal.d.ts +308 -0
- package/types/private.d.ts +209 -0
- package/CHANGELOG.md +0 -431
- package/assets/components/error.svelte +0 -13
- package/assets/runtime/app/env.js +0 -5
- package/assets/runtime/app/navigation.js +0 -41
- package/assets/runtime/app/paths.js +0 -1
- package/assets/runtime/app/stores.js +0 -93
- package/assets/runtime/chunks/utils.js +0 -19
- package/assets/runtime/internal/singletons.js +0 -23
- package/assets/runtime/internal/start.js +0 -770
- package/assets/runtime/paths.js +0 -12
- package/dist/.DS_Store +0 -0
- package/dist/chunks/index.js +0 -3521
- package/dist/chunks/index2.js +0 -587
- package/dist/chunks/index3.js +0 -246
- package/dist/chunks/index4.js +0 -538
- package/dist/chunks/index5.js +0 -761
- package/dist/chunks/index6.js +0 -322
- package/dist/chunks/standard.js +0 -99
- package/dist/chunks/utils.js +0 -83
- package/dist/cli.js +0 -546
- package/dist/ssr.js +0 -2581
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import { negotiate } from '../../../utils/http.js';
|
|
2
|
+
import { render_response } from './render.js';
|
|
3
|
+
import { respond_with_error } from './respond_with_error.js';
|
|
4
|
+
import { method_not_allowed, error_to_pojo, allowed_methods } from '../utils.js';
|
|
5
|
+
import { create_fetch } from './fetch.js';
|
|
6
|
+
import { HttpError, Redirect } from '../../../index/private.js';
|
|
7
|
+
import { error, json } from '../../../index/index.js';
|
|
8
|
+
import { normalize_error } from '../../../utils/error.js';
|
|
9
|
+
import { load_data, load_server_data } from './load_data.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {import('./types.js').Loaded} Loaded
|
|
13
|
+
* @typedef {import('types').SSRNode} SSRNode
|
|
14
|
+
* @typedef {import('types').SSROptions} SSROptions
|
|
15
|
+
* @typedef {import('types').SSRState} SSRState
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {import('types').RequestEvent} event
|
|
20
|
+
* @param {import('types').SSRPage} route
|
|
21
|
+
* @param {import('types').SSROptions} options
|
|
22
|
+
* @param {import('types').SSRState} state
|
|
23
|
+
* @param {import('types').RequiredResolveOptions} resolve_opts
|
|
24
|
+
* @returns {Promise<Response>}
|
|
25
|
+
*/
|
|
26
|
+
export async function render_page(event, route, options, state, resolve_opts) {
|
|
27
|
+
if (state.initiator === route) {
|
|
28
|
+
// infinite request cycle detected
|
|
29
|
+
return new Response(`Not found: ${event.url.pathname}`, {
|
|
30
|
+
status: 404
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const accept = negotiate(event.request.headers.get('accept') || 'text/html', [
|
|
35
|
+
'text/html',
|
|
36
|
+
'application/json'
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
if (
|
|
40
|
+
accept === 'application/json' &&
|
|
41
|
+
event.request.method !== 'GET' &&
|
|
42
|
+
event.request.method !== 'HEAD'
|
|
43
|
+
) {
|
|
44
|
+
const node = await options.manifest._.nodes[route.leaf]();
|
|
45
|
+
if (node.server) {
|
|
46
|
+
return handle_json_request(event, options, node.server);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { fetcher, fetched, cookies } = create_fetch({ event, options, state, route });
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const nodes = await Promise.all([
|
|
54
|
+
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
55
|
+
...route.layouts.map((n) => (n == undefined ? n : options.manifest._.nodes[n]())),
|
|
56
|
+
options.manifest._.nodes[route.leaf]()
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const leaf_node = /** @type {import('types').SSRNode} */ (nodes.at(-1));
|
|
60
|
+
|
|
61
|
+
let status = 200;
|
|
62
|
+
|
|
63
|
+
/** @type {HttpError | Error} */
|
|
64
|
+
let mutation_error;
|
|
65
|
+
|
|
66
|
+
/** @type {Record<string, string> | undefined} */
|
|
67
|
+
let validation_errors;
|
|
68
|
+
|
|
69
|
+
if (leaf_node.server && event.request.method !== 'GET' && event.request.method !== 'HEAD') {
|
|
70
|
+
// for non-GET requests, first call handler in +page.server.js
|
|
71
|
+
// (this also determines status code)
|
|
72
|
+
try {
|
|
73
|
+
const method = /** @type {'POST' | 'PATCH' | 'PUT' | 'DELETE'} */ (event.request.method);
|
|
74
|
+
const handler = leaf_node.server[method];
|
|
75
|
+
if (handler) {
|
|
76
|
+
const result = await handler.call(null, event);
|
|
77
|
+
|
|
78
|
+
if (result?.errors) {
|
|
79
|
+
validation_errors = result.errors;
|
|
80
|
+
status = result.status ?? 400;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (event.request.method === 'POST' && result?.location) {
|
|
84
|
+
return redirect_response(303, result.location);
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
event.setHeaders({
|
|
88
|
+
allow: allowed_methods(leaf_node.server).join(', ')
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
mutation_error = error(405, 'Method not allowed');
|
|
92
|
+
}
|
|
93
|
+
} catch (e) {
|
|
94
|
+
if (e instanceof Redirect) {
|
|
95
|
+
return redirect_response(e.status, e.location);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
mutation_error = /** @type {HttpError | Error} */ (e);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const should_prerender_data = nodes.some((node) => node?.server);
|
|
103
|
+
const data_pathname = `${event.url.pathname.replace(/\/$/, '')}/__data.json`;
|
|
104
|
+
|
|
105
|
+
if (!resolve_opts.ssr) {
|
|
106
|
+
return await render_response({
|
|
107
|
+
branch: [],
|
|
108
|
+
validation_errors: undefined,
|
|
109
|
+
fetched,
|
|
110
|
+
cookies,
|
|
111
|
+
page_config: {
|
|
112
|
+
hydrate: true,
|
|
113
|
+
router: true
|
|
114
|
+
},
|
|
115
|
+
status,
|
|
116
|
+
error: null,
|
|
117
|
+
event,
|
|
118
|
+
options,
|
|
119
|
+
state,
|
|
120
|
+
resolve_opts
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const should_prerender =
|
|
125
|
+
leaf_node.shared?.prerender ?? leaf_node.server?.prerender ?? options.prerender.default;
|
|
126
|
+
if (should_prerender) {
|
|
127
|
+
const mod = leaf_node.server;
|
|
128
|
+
if (mod && (mod.POST || mod.PUT || mod.DELETE || mod.PATCH)) {
|
|
129
|
+
throw new Error('Cannot prerender pages that have endpoints with mutative methods');
|
|
130
|
+
}
|
|
131
|
+
} else if (state.prerendering) {
|
|
132
|
+
// if the page isn't marked as prerenderable (or is explicitly
|
|
133
|
+
// marked NOT prerenderable, if `prerender.default` is `true`),
|
|
134
|
+
// then bail out at this point
|
|
135
|
+
if (!should_prerender) {
|
|
136
|
+
return new Response(undefined, {
|
|
137
|
+
status: 204
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** @type {Array<Loaded | null>} */
|
|
143
|
+
let branch = [];
|
|
144
|
+
|
|
145
|
+
/** @type {Error | null} */
|
|
146
|
+
let load_error = null;
|
|
147
|
+
|
|
148
|
+
/** @type {Array<Promise<Record<string, any> | null>>} */
|
|
149
|
+
const server_promises = nodes.map((node, i) => {
|
|
150
|
+
if (load_error) {
|
|
151
|
+
// if an error happens immediately, don't bother with the rest of the nodes
|
|
152
|
+
throw load_error;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return Promise.resolve().then(async () => {
|
|
156
|
+
try {
|
|
157
|
+
if (node === leaf_node && mutation_error) {
|
|
158
|
+
// we wait until here to throw the error so that we can use
|
|
159
|
+
// any nested +error.svelte components that were defined
|
|
160
|
+
throw mutation_error;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return await load_server_data({
|
|
164
|
+
dev: options.dev,
|
|
165
|
+
event,
|
|
166
|
+
node,
|
|
167
|
+
parent: async () => {
|
|
168
|
+
/** @type {Record<string, any>} */
|
|
169
|
+
const data = {};
|
|
170
|
+
for (let j = 0; j < i; j += 1) {
|
|
171
|
+
Object.assign(data, await server_promises[j]);
|
|
172
|
+
}
|
|
173
|
+
return data;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
} catch (e) {
|
|
177
|
+
load_error = /** @type {Error} */ (e);
|
|
178
|
+
throw load_error;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/** @type {Array<Promise<Record<string, any> | null>>} */
|
|
184
|
+
const load_promises = nodes.map((node, i) => {
|
|
185
|
+
if (load_error) throw load_error;
|
|
186
|
+
return Promise.resolve().then(async () => {
|
|
187
|
+
try {
|
|
188
|
+
return await load_data({
|
|
189
|
+
event,
|
|
190
|
+
fetcher,
|
|
191
|
+
node,
|
|
192
|
+
parent: async () => {
|
|
193
|
+
const data = {};
|
|
194
|
+
for (let j = 0; j < i; j += 1) {
|
|
195
|
+
Object.assign(data, await load_promises[j]);
|
|
196
|
+
}
|
|
197
|
+
return data;
|
|
198
|
+
},
|
|
199
|
+
server_data_promise: server_promises[i],
|
|
200
|
+
state
|
|
201
|
+
});
|
|
202
|
+
} catch (e) {
|
|
203
|
+
load_error = /** @type {Error} */ (e);
|
|
204
|
+
throw load_error;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// if we don't do this, rejections will be unhandled
|
|
210
|
+
for (const p of server_promises) p.catch(() => {});
|
|
211
|
+
for (const p of load_promises) p.catch(() => {});
|
|
212
|
+
|
|
213
|
+
for (let i = 0; i < nodes.length; i += 1) {
|
|
214
|
+
const node = nodes[i];
|
|
215
|
+
|
|
216
|
+
if (node) {
|
|
217
|
+
try {
|
|
218
|
+
const server_data = await server_promises[i];
|
|
219
|
+
const data = await load_promises[i];
|
|
220
|
+
|
|
221
|
+
branch.push({ node, server_data, data });
|
|
222
|
+
} catch (e) {
|
|
223
|
+
const error = normalize_error(e);
|
|
224
|
+
|
|
225
|
+
if (error instanceof Redirect) {
|
|
226
|
+
if (state.prerendering && should_prerender_data) {
|
|
227
|
+
state.prerendering.dependencies.set(data_pathname, {
|
|
228
|
+
response: new Response(undefined),
|
|
229
|
+
body: JSON.stringify({
|
|
230
|
+
type: 'redirect',
|
|
231
|
+
location: error.location
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return redirect_response(error.status, error.location);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!(error instanceof HttpError)) {
|
|
240
|
+
options.handle_error(/** @type {Error} */ (error), event);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const status = error instanceof HttpError ? error.status : 500;
|
|
244
|
+
|
|
245
|
+
while (i--) {
|
|
246
|
+
if (route.errors[i]) {
|
|
247
|
+
const index = /** @type {number} */ (route.errors[i]);
|
|
248
|
+
const node = await options.manifest._.nodes[index]();
|
|
249
|
+
|
|
250
|
+
let j = i;
|
|
251
|
+
while (!branch[j]) j -= 1;
|
|
252
|
+
|
|
253
|
+
return await render_response({
|
|
254
|
+
event,
|
|
255
|
+
options,
|
|
256
|
+
state,
|
|
257
|
+
resolve_opts,
|
|
258
|
+
page_config: { router: true, hydrate: true },
|
|
259
|
+
status,
|
|
260
|
+
error,
|
|
261
|
+
branch: compact(branch.slice(0, j + 1)).concat({
|
|
262
|
+
node,
|
|
263
|
+
data: null,
|
|
264
|
+
server_data: null
|
|
265
|
+
}),
|
|
266
|
+
fetched,
|
|
267
|
+
cookies,
|
|
268
|
+
validation_errors: undefined
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// if we're still here, it means the error happened in the root layout,
|
|
274
|
+
// which means we have to fall back to a plain text response
|
|
275
|
+
// TODO since the requester is expecting HTML, maybe it makes sense to
|
|
276
|
+
// doll this up a bit
|
|
277
|
+
return new Response(
|
|
278
|
+
error instanceof HttpError ? error.message : options.get_stack(error),
|
|
279
|
+
{ status }
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
// push an empty slot so we can rewind past gaps to the
|
|
284
|
+
// layout that corresponds with an +error.svelte page
|
|
285
|
+
branch.push(null);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (state.prerendering && should_prerender_data) {
|
|
290
|
+
state.prerendering.dependencies.set(data_pathname, {
|
|
291
|
+
response: new Response(undefined),
|
|
292
|
+
body: JSON.stringify({
|
|
293
|
+
type: 'data',
|
|
294
|
+
nodes: branch.map((branch_node) => ({ data: branch_node?.server_data }))
|
|
295
|
+
})
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// TODO use validation_errors
|
|
300
|
+
|
|
301
|
+
return await render_response({
|
|
302
|
+
event,
|
|
303
|
+
options,
|
|
304
|
+
state,
|
|
305
|
+
resolve_opts,
|
|
306
|
+
page_config: get_page_config(leaf_node, options),
|
|
307
|
+
status,
|
|
308
|
+
error: null,
|
|
309
|
+
branch: compact(branch),
|
|
310
|
+
validation_errors,
|
|
311
|
+
fetched,
|
|
312
|
+
cookies
|
|
313
|
+
});
|
|
314
|
+
} catch (error) {
|
|
315
|
+
// if we end up here, it means the data loaded successfull
|
|
316
|
+
// but the page failed to render
|
|
317
|
+
options.handle_error(/** @type {Error} */ (error), event);
|
|
318
|
+
|
|
319
|
+
return await respond_with_error({
|
|
320
|
+
event,
|
|
321
|
+
options,
|
|
322
|
+
state,
|
|
323
|
+
status: 500,
|
|
324
|
+
error: /** @type {Error} */ (error),
|
|
325
|
+
resolve_opts
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @param {import('types').SSRNode} leaf
|
|
332
|
+
* @param {SSROptions} options
|
|
333
|
+
*/
|
|
334
|
+
function get_page_config(leaf, options) {
|
|
335
|
+
// TODO we can reinstate this now that it's in the module
|
|
336
|
+
if (leaf.shared && 'ssr' in leaf.shared) {
|
|
337
|
+
throw new Error(
|
|
338
|
+
'`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs/hooks#handle'
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
router: leaf.shared?.router ?? options.router,
|
|
344
|
+
hydrate: leaf.shared?.hydrate ?? options.hydrate
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* @param {import('types').RequestEvent} event
|
|
350
|
+
* @param {import('types').SSROptions} options
|
|
351
|
+
* @param {import('types').SSRNode['server']} mod
|
|
352
|
+
*/
|
|
353
|
+
export async function handle_json_request(event, options, mod) {
|
|
354
|
+
const method = /** @type {'POST' | 'PUT' | 'PATCH' | 'DELETE'} */ (event.request.method);
|
|
355
|
+
const handler = mod[method];
|
|
356
|
+
|
|
357
|
+
if (!handler) {
|
|
358
|
+
return method_not_allowed(mod, method);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
// @ts-ignore
|
|
363
|
+
const result = await handler.call(null, event);
|
|
364
|
+
|
|
365
|
+
if (result?.errors) {
|
|
366
|
+
// @ts-ignore
|
|
367
|
+
return json({ errors: result.errors }, { status: result.status || 400 });
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return new Response(undefined, {
|
|
371
|
+
status: 204,
|
|
372
|
+
// @ts-ignore
|
|
373
|
+
headers: result?.location ? { location: result.location } : undefined
|
|
374
|
+
});
|
|
375
|
+
} catch (e) {
|
|
376
|
+
const error = normalize_error(e);
|
|
377
|
+
|
|
378
|
+
if (error instanceof Redirect) {
|
|
379
|
+
return redirect_response(error.status, error.location);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (!(error instanceof HttpError)) {
|
|
383
|
+
options.handle_error(error, event);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return json(error_to_pojo(error, options.get_stack), {
|
|
387
|
+
status: error instanceof HttpError ? error.status : 500
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @param {number} status
|
|
394
|
+
* @param {string} location
|
|
395
|
+
*/
|
|
396
|
+
function redirect_response(status, location) {
|
|
397
|
+
return new Response(undefined, {
|
|
398
|
+
status,
|
|
399
|
+
headers: { location }
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @template T
|
|
405
|
+
* @param {Array<T | null>} array
|
|
406
|
+
* @returns {T[]}
|
|
407
|
+
*/
|
|
408
|
+
function compact(array) {
|
|
409
|
+
const compacted = [];
|
|
410
|
+
for (const item of array) {
|
|
411
|
+
if (item) {
|
|
412
|
+
compacted.push(item);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return compacted;
|
|
416
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { LoadURL, PrerenderingURL } from '../../../utils/url.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Calls the user's `load` function.
|
|
5
|
+
* @param {{
|
|
6
|
+
* dev: boolean;
|
|
7
|
+
* event: import('types').RequestEvent;
|
|
8
|
+
* node: import('types').SSRNode | undefined;
|
|
9
|
+
* parent: () => Promise<Record<string, any>>;
|
|
10
|
+
* }} opts
|
|
11
|
+
*/
|
|
12
|
+
export async function load_server_data({ dev, event, node, parent }) {
|
|
13
|
+
if (!node?.server) return null;
|
|
14
|
+
|
|
15
|
+
const server_data = await node.server.load?.call(null, {
|
|
16
|
+
// can't use destructuring here because it will always
|
|
17
|
+
// invoke event.clientAddress, which breaks prerendering
|
|
18
|
+
get clientAddress() {
|
|
19
|
+
return event.clientAddress;
|
|
20
|
+
},
|
|
21
|
+
locals: event.locals,
|
|
22
|
+
params: event.params,
|
|
23
|
+
parent,
|
|
24
|
+
platform: event.platform,
|
|
25
|
+
request: event.request,
|
|
26
|
+
routeId: event.routeId,
|
|
27
|
+
setHeaders: event.setHeaders,
|
|
28
|
+
url: event.url
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const result = server_data ? await unwrap_promises(server_data) : null;
|
|
32
|
+
|
|
33
|
+
if (dev) {
|
|
34
|
+
check_serializability(result, /** @type {string} */ (node.server_id), 'data');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Calls the user's `load` function.
|
|
42
|
+
* @param {{
|
|
43
|
+
* event: import('types').RequestEvent;
|
|
44
|
+
* fetcher: typeof fetch;
|
|
45
|
+
* node: import('types').SSRNode | undefined;
|
|
46
|
+
* parent: () => Promise<Record<string, any>>;
|
|
47
|
+
* server_data_promise: Promise<Record<string, any> | null>;
|
|
48
|
+
* state: import('types').SSRState;
|
|
49
|
+
* }} opts
|
|
50
|
+
*/
|
|
51
|
+
export async function load_data({ event, fetcher, node, parent, server_data_promise, state }) {
|
|
52
|
+
const server_data = await server_data_promise;
|
|
53
|
+
|
|
54
|
+
if (!node?.shared?.load) {
|
|
55
|
+
return server_data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const load_input = {
|
|
59
|
+
url: state.prerendering ? new PrerenderingURL(event.url) : new LoadURL(event.url),
|
|
60
|
+
params: event.params,
|
|
61
|
+
data: server_data,
|
|
62
|
+
routeId: event.routeId,
|
|
63
|
+
fetch: fetcher,
|
|
64
|
+
setHeaders: event.setHeaders,
|
|
65
|
+
depends: () => {},
|
|
66
|
+
parent
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// TODO remove this for 1.0
|
|
70
|
+
Object.defineProperties(load_input, {
|
|
71
|
+
session: {
|
|
72
|
+
get() {
|
|
73
|
+
throw new Error(
|
|
74
|
+
'session is no longer available. See https://github.com/sveltejs/kit/discussions/5883'
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
enumerable: false
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const data = await node.shared.load.call(null, load_input);
|
|
82
|
+
|
|
83
|
+
return data ? unwrap_promises(data) : null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** @param {Record<string, any>} object */
|
|
87
|
+
async function unwrap_promises(object) {
|
|
88
|
+
/** @type {Record<string, any>} */
|
|
89
|
+
const unwrapped = {};
|
|
90
|
+
|
|
91
|
+
for (const key in object) {
|
|
92
|
+
unwrapped[key] = await object[key];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return unwrapped;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check that the data can safely be serialized to JSON
|
|
100
|
+
* @param {any} value
|
|
101
|
+
* @param {string} id
|
|
102
|
+
* @param {string} path
|
|
103
|
+
*/
|
|
104
|
+
function check_serializability(value, id, path) {
|
|
105
|
+
const type = typeof value;
|
|
106
|
+
|
|
107
|
+
if (type === 'string' || type === 'boolean' || type === 'number' || type === 'undefined') {
|
|
108
|
+
// primitives are fine
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (type === 'object') {
|
|
113
|
+
// nulls are fine...
|
|
114
|
+
if (!value) return;
|
|
115
|
+
|
|
116
|
+
// ...so are plain arrays...
|
|
117
|
+
if (Array.isArray(value)) {
|
|
118
|
+
value.forEach((child, i) => {
|
|
119
|
+
check_serializability(child, id, `${path}[${i}]`);
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ...and objects
|
|
125
|
+
const tag = Object.prototype.toString.call(value);
|
|
126
|
+
if (tag === '[object Object]') {
|
|
127
|
+
for (const key in value) {
|
|
128
|
+
check_serializability(value[key], id, `${path}.${key}`);
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
throw new Error(`${path} returned from 'load' in ${id} cannot be serialized as JSON`);
|
|
135
|
+
}
|