@sveltejs/kit 2.37.0 → 2.38.0
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/package.json +1 -1
- package/src/exports/internal/remote-functions.js +8 -2
- package/src/runtime/app/server/remote/query.js +149 -10
- package/src/runtime/app/server/remote/shared.js +5 -7
- package/src/runtime/client/remote-functions/form.svelte.js +2 -2
- package/src/runtime/client/remote-functions/index.js +1 -1
- package/src/runtime/client/remote-functions/query.svelte.js +95 -1
- package/src/runtime/server/data/index.js +5 -93
- package/src/runtime/server/page/data_serializer.js +202 -0
- package/src/runtime/server/page/index.js +21 -12
- package/src/runtime/server/page/load_data.js +6 -34
- package/src/runtime/server/page/render.js +6 -105
- package/src/runtime/server/page/respond_with_error.js +5 -1
- package/src/runtime/server/page/types.d.ts +21 -1
- package/src/runtime/server/remote.js +46 -1
- package/src/runtime/server/respond.js +3 -1
- package/src/runtime/server/utils.js +7 -0
- package/src/types/internal.d.ts +10 -0
- package/src/utils/routing.js +4 -1
- package/src/utils/streaming.js +35 -21
- package/src/version.js +1 -1
- package/types/index.d.ts +18 -0
- package/types/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -10,9 +10,15 @@ export function validate_remote_functions(module, file) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
for (const name in module) {
|
|
13
|
-
const type = module[name]?.__?.type;
|
|
13
|
+
const type = /** @type {import('types').RemoteInfo['type']} */ (module[name]?.__?.type);
|
|
14
14
|
|
|
15
|
-
if (
|
|
15
|
+
if (
|
|
16
|
+
type !== 'form' &&
|
|
17
|
+
type !== 'command' &&
|
|
18
|
+
type !== 'query' &&
|
|
19
|
+
type !== 'query_batch' &&
|
|
20
|
+
type !== 'prerender'
|
|
21
|
+
) {
|
|
16
22
|
throw new Error(
|
|
17
23
|
`\`${name}\` exported from ${file} is invalid — all exports from this file must be remote functions`
|
|
18
24
|
);
|
|
@@ -72,21 +72,15 @@ export function query(validate_or_fn, maybe_fn) {
|
|
|
72
72
|
|
|
73
73
|
const { event, state } = get_request_store();
|
|
74
74
|
|
|
75
|
-
const abort_controller = new AbortController();
|
|
76
75
|
/** @type {Promise<any> & Partial<RemoteQuery<any>>} */
|
|
77
|
-
const promise = get_response(
|
|
78
|
-
|
|
79
|
-
arg,
|
|
80
|
-
state,
|
|
81
|
-
() => run_remote_function(event, state, false, arg, validate, fn),
|
|
82
|
-
abort_controller.signal
|
|
76
|
+
const promise = get_response(__.id, arg, state, () =>
|
|
77
|
+
run_remote_function(event, state, false, arg, validate, fn)
|
|
83
78
|
);
|
|
84
79
|
|
|
85
80
|
promise.catch(() => {});
|
|
86
81
|
|
|
87
82
|
/** @param {Output} value */
|
|
88
83
|
promise.set = (value) => {
|
|
89
|
-
abort_controller.abort();
|
|
90
84
|
const { state } = get_request_store();
|
|
91
85
|
const refreshes = state.refreshes;
|
|
92
86
|
|
|
@@ -97,7 +91,7 @@ export function query(validate_or_fn, maybe_fn) {
|
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
const cache_key = create_remote_cache_key(__.id, stringify_remote_arg(arg, state.transport));
|
|
100
|
-
refreshes[cache_key] = Promise.resolve(value);
|
|
94
|
+
refreshes[cache_key] = (state.remote_data ??= {})[cache_key] = Promise.resolve(value);
|
|
101
95
|
};
|
|
102
96
|
|
|
103
97
|
promise.refresh = () => {
|
|
@@ -118,7 +112,6 @@ export function query(validate_or_fn, maybe_fn) {
|
|
|
118
112
|
};
|
|
119
113
|
|
|
120
114
|
promise.withOverride = () => {
|
|
121
|
-
abort_controller.abort();
|
|
122
115
|
throw new Error(`Cannot call '${__.name}.withOverride()' on the server`);
|
|
123
116
|
};
|
|
124
117
|
|
|
@@ -129,3 +122,149 @@ export function query(validate_or_fn, maybe_fn) {
|
|
|
129
122
|
|
|
130
123
|
return wrapper;
|
|
131
124
|
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Creates a batch query function that collects multiple calls and executes them in a single request
|
|
128
|
+
*
|
|
129
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query.batch) for full documentation.
|
|
130
|
+
*
|
|
131
|
+
* @template Input
|
|
132
|
+
* @template Output
|
|
133
|
+
* @overload
|
|
134
|
+
* @param {'unchecked'} validate
|
|
135
|
+
* @param {(args: Input[]) => MaybePromise<(arg: Input, idx: number) => Output>} fn
|
|
136
|
+
* @returns {RemoteQueryFunction<Input, Output>}
|
|
137
|
+
* @since 2.35
|
|
138
|
+
*/
|
|
139
|
+
/**
|
|
140
|
+
* Creates a batch query function that collects multiple calls and executes them in a single request
|
|
141
|
+
*
|
|
142
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query.batch) for full documentation.
|
|
143
|
+
*
|
|
144
|
+
* @template {StandardSchemaV1} Schema
|
|
145
|
+
* @template Output
|
|
146
|
+
* @overload
|
|
147
|
+
* @param {Schema} schema
|
|
148
|
+
* @param {(args: StandardSchemaV1.InferOutput<Schema>[]) => MaybePromise<(arg: StandardSchemaV1.InferOutput<Schema>, idx: number) => Output>} fn
|
|
149
|
+
* @returns {RemoteQueryFunction<StandardSchemaV1.InferInput<Schema>, Output>}
|
|
150
|
+
* @since 2.35
|
|
151
|
+
*/
|
|
152
|
+
/**
|
|
153
|
+
* @template Input
|
|
154
|
+
* @template Output
|
|
155
|
+
* @param {any} validate_or_fn
|
|
156
|
+
* @param {(args?: Input[]) => MaybePromise<(arg: Input, idx: number) => Output>} [maybe_fn]
|
|
157
|
+
* @returns {RemoteQueryFunction<Input, Output>}
|
|
158
|
+
* @since 2.35
|
|
159
|
+
*/
|
|
160
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
161
|
+
function batch(validate_or_fn, maybe_fn) {
|
|
162
|
+
/** @type {(args?: Input[]) => (arg: Input, idx: number) => Output} */
|
|
163
|
+
const fn = maybe_fn ?? validate_or_fn;
|
|
164
|
+
|
|
165
|
+
/** @type {(arg?: any) => MaybePromise<Input>} */
|
|
166
|
+
const validate = create_validator(validate_or_fn, maybe_fn);
|
|
167
|
+
|
|
168
|
+
/** @type {RemoteInfo & { type: 'query_batch' }} */
|
|
169
|
+
const __ = {
|
|
170
|
+
type: 'query_batch',
|
|
171
|
+
id: '',
|
|
172
|
+
name: '',
|
|
173
|
+
run: (args) => {
|
|
174
|
+
const { event, state } = get_request_store();
|
|
175
|
+
|
|
176
|
+
return run_remote_function(
|
|
177
|
+
event,
|
|
178
|
+
state,
|
|
179
|
+
false,
|
|
180
|
+
args,
|
|
181
|
+
(array) => Promise.all(array.map(validate)),
|
|
182
|
+
fn
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/** @type {{ args: any[], resolvers: Array<{resolve: (value: any) => void, reject: (error: any) => void}> }} */
|
|
188
|
+
let batching = { args: [], resolvers: [] };
|
|
189
|
+
|
|
190
|
+
/** @type {RemoteQueryFunction<Input, Output> & { __: RemoteInfo }} */
|
|
191
|
+
const wrapper = (arg) => {
|
|
192
|
+
if (prerendering) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`Cannot call query.batch '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const { event, state } = get_request_store();
|
|
199
|
+
|
|
200
|
+
/** @type {Promise<any> & Partial<RemoteQuery<any>>} */
|
|
201
|
+
const promise = get_response(__.id, arg, state, () => {
|
|
202
|
+
// Collect all the calls to the same query in the same macrotask,
|
|
203
|
+
// then execute them as one backend request.
|
|
204
|
+
return new Promise((resolve, reject) => {
|
|
205
|
+
// We don't need to deduplicate args here, because get_response already caches/reuses identical calls
|
|
206
|
+
batching.args.push(arg);
|
|
207
|
+
batching.resolvers.push({ resolve, reject });
|
|
208
|
+
|
|
209
|
+
if (batching.args.length > 1) return;
|
|
210
|
+
|
|
211
|
+
setTimeout(async () => {
|
|
212
|
+
const batched = batching;
|
|
213
|
+
batching = { args: [], resolvers: [] };
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const get_result = await run_remote_function(
|
|
217
|
+
event,
|
|
218
|
+
state,
|
|
219
|
+
false,
|
|
220
|
+
batched.args,
|
|
221
|
+
(array) => Promise.all(array.map(validate)),
|
|
222
|
+
fn
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
for (let i = 0; i < batched.resolvers.length; i++) {
|
|
226
|
+
try {
|
|
227
|
+
batched.resolvers[i].resolve(get_result(batched.args[i], i));
|
|
228
|
+
} catch (error) {
|
|
229
|
+
batched.resolvers[i].reject(error);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} catch (error) {
|
|
233
|
+
for (const resolver of batched.resolvers) {
|
|
234
|
+
resolver.reject(error);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}, 0);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
promise.catch(() => {});
|
|
242
|
+
|
|
243
|
+
promise.refresh = async () => {
|
|
244
|
+
const { state } = get_request_store();
|
|
245
|
+
const refreshes = state.refreshes;
|
|
246
|
+
|
|
247
|
+
if (!refreshes) {
|
|
248
|
+
throw new Error(
|
|
249
|
+
`Cannot call refresh on query.batch '${__.name}' because it is not executed in the context of a command/form remote function`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const cache_key = create_remote_cache_key(__.id, stringify_remote_arg(arg, state.transport));
|
|
254
|
+
refreshes[cache_key] = await /** @type {Promise<any>} */ (promise);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
promise.withOverride = () => {
|
|
258
|
+
throw new Error(`Cannot call '${__.name}.withOverride()' on the server`);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
return /** @type {RemoteQuery<Output>} */ (promise);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
Object.defineProperty(wrapper, '__', { value: __ });
|
|
265
|
+
|
|
266
|
+
return wrapper;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Add batch as a property to the query function
|
|
270
|
+
Object.defineProperty(query, 'batch', { value: batch, enumerable: true });
|
|
@@ -66,16 +66,14 @@ export function create_validator(validate_or_fn, maybe_fn) {
|
|
|
66
66
|
* @param {any} arg
|
|
67
67
|
* @param {RequestState} state
|
|
68
68
|
* @param {() => Promise<T>} get_result
|
|
69
|
-
* @param {AbortSignal | undefined=} signal
|
|
70
69
|
* @returns {Promise<T>}
|
|
71
70
|
*/
|
|
72
|
-
export async function get_response(id, arg, state, get_result
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
const cache_key = create_remote_cache_key(id, stringify_remote_arg(arg, state.transport));
|
|
71
|
+
export async function get_response(id, arg, state, get_result) {
|
|
72
|
+
// wait a beat, in case `myQuery().set(...)` is immediately called
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
74
|
+
await 0;
|
|
78
75
|
|
|
76
|
+
const cache_key = create_remote_cache_key(id, stringify_remote_arg(arg, state.transport));
|
|
79
77
|
return ((state.remote_data ??= {})[cache_key] ??= get_result());
|
|
80
78
|
}
|
|
81
79
|
|
|
@@ -32,7 +32,7 @@ export function form(id) {
|
|
|
32
32
|
const action = '?/remote=' + encodeURIComponent(action_id);
|
|
33
33
|
|
|
34
34
|
/** @type {any} */
|
|
35
|
-
let result = $state(started ? undefined : remote_responses[action_id]);
|
|
35
|
+
let result = $state.raw(started ? undefined : remote_responses[action_id]);
|
|
36
36
|
|
|
37
37
|
/** @type {number} */
|
|
38
38
|
let pending_count = $state(0);
|
|
@@ -105,7 +105,7 @@ export function form(id) {
|
|
|
105
105
|
void _goto(form_result.location, { invalidateAll }, 0);
|
|
106
106
|
} else {
|
|
107
107
|
result = undefined;
|
|
108
|
-
throw new HttpError(500, form_result.error);
|
|
108
|
+
throw new HttpError(form_result.status ?? 500, form_result.error);
|
|
109
109
|
}
|
|
110
110
|
} catch (e) {
|
|
111
111
|
result = undefined;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/** @import { RemoteQueryFunction } from '@sveltejs/kit' */
|
|
2
|
+
/** @import { RemoteFunctionResponse } from 'types' */
|
|
2
3
|
import { app_dir, base } from '__sveltekit/paths';
|
|
3
|
-
import { remote_responses, started } from '../client.js';
|
|
4
|
+
import { app, goto, remote_responses, started } from '../client.js';
|
|
4
5
|
import { tick } from 'svelte';
|
|
5
6
|
import { create_remote_function, remote_request } from './shared.svelte.js';
|
|
7
|
+
import * as devalue from 'devalue';
|
|
8
|
+
import { HttpError, Redirect } from '@sveltejs/kit/internal';
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* @param {string} id
|
|
@@ -25,6 +28,97 @@ export function query(id) {
|
|
|
25
28
|
});
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
/**
|
|
32
|
+
* @param {string} id
|
|
33
|
+
* @returns {(arg: any) => Query<any>}
|
|
34
|
+
*/
|
|
35
|
+
export function query_batch(id) {
|
|
36
|
+
/** @type {Map<string, Array<{resolve: (value: any) => void, reject: (error: any) => void}>>} */
|
|
37
|
+
let batching = new Map();
|
|
38
|
+
|
|
39
|
+
return create_remote_function(id, (cache_key, payload) => {
|
|
40
|
+
return new Query(cache_key, () => {
|
|
41
|
+
if (!started) {
|
|
42
|
+
const result = remote_responses[cache_key];
|
|
43
|
+
if (result) {
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Collect all the calls to the same query in the same macrotask,
|
|
49
|
+
// then execute them as one backend request.
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
// create_remote_function caches identical calls, but in case a refresh to the same query is called multiple times this function
|
|
52
|
+
// is invoked multiple times with the same payload, so we need to deduplicate here
|
|
53
|
+
const entry = batching.get(payload) ?? [];
|
|
54
|
+
entry.push({ resolve, reject });
|
|
55
|
+
batching.set(payload, entry);
|
|
56
|
+
|
|
57
|
+
if (batching.size > 1) return;
|
|
58
|
+
|
|
59
|
+
// Wait for the next macrotask - don't use microtask as Svelte runtime uses these to collect changes and flush them,
|
|
60
|
+
// and flushes could reveal more queries that should be batched.
|
|
61
|
+
setTimeout(async () => {
|
|
62
|
+
const batched = batching;
|
|
63
|
+
batching = new Map();
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const response = await fetch(`${base}/${app_dir}/remote/${id}`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
payloads: Array.from(batched.keys())
|
|
70
|
+
}),
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'application/json'
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
throw new Error('Failed to execute batch query');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const result = /** @type {RemoteFunctionResponse} */ (await response.json());
|
|
81
|
+
if (result.type === 'error') {
|
|
82
|
+
throw new HttpError(result.status ?? 500, result.error);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (result.type === 'redirect') {
|
|
86
|
+
// TODO double-check this
|
|
87
|
+
await goto(result.location);
|
|
88
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
89
|
+
throw new Redirect(307, result.location);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const results = devalue.parse(result.result, app.decoders);
|
|
93
|
+
|
|
94
|
+
// Resolve individual queries
|
|
95
|
+
// Maps guarantee insertion order so we can do it like this
|
|
96
|
+
let i = 0;
|
|
97
|
+
|
|
98
|
+
for (const resolvers of batched.values()) {
|
|
99
|
+
for (const { resolve, reject } of resolvers) {
|
|
100
|
+
if (results[i].type === 'error') {
|
|
101
|
+
reject(new HttpError(results[i].status, results[i].error));
|
|
102
|
+
} else {
|
|
103
|
+
resolve(results[i].data);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
i++;
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
// Reject all queries in the batch
|
|
110
|
+
for (const resolver of batched.values()) {
|
|
111
|
+
for (const { reject } of resolver) {
|
|
112
|
+
reject(error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}, 0);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
28
122
|
/**
|
|
29
123
|
* @template T
|
|
30
124
|
* @implements {Partial<Promise<T>>}
|
|
@@ -2,11 +2,10 @@ import { text } from '@sveltejs/kit';
|
|
|
2
2
|
import { HttpError, SvelteKitError, Redirect } from '@sveltejs/kit/internal';
|
|
3
3
|
import { normalize_error } from '../../../utils/error.js';
|
|
4
4
|
import { once } from '../../../utils/functions.js';
|
|
5
|
+
import { server_data_serializer_json } from '../page/data_serializer.js';
|
|
5
6
|
import { load_server_data } from '../page/load_data.js';
|
|
6
|
-
import {
|
|
7
|
+
import { handle_error_and_jsonify } from '../utils.js';
|
|
7
8
|
import { normalize_path } from '../../../utils/url.js';
|
|
8
|
-
import * as devalue from 'devalue';
|
|
9
|
-
import { create_async_iterator } from '../../../utils/streaming.js';
|
|
10
9
|
import { text_encoder } from '../../utils.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -120,7 +119,9 @@ export async function render_data(
|
|
|
120
119
|
)
|
|
121
120
|
);
|
|
122
121
|
|
|
123
|
-
const
|
|
122
|
+
const data_serializer = server_data_serializer_json(event, event_state, options);
|
|
123
|
+
for (let i = 0; i < nodes.length; i++) data_serializer.add_node(i, nodes[i]);
|
|
124
|
+
const { data, chunks } = data_serializer.get_data();
|
|
124
125
|
|
|
125
126
|
if (!chunks) {
|
|
126
127
|
// use a normal JSON response where possible, so we get `content-length`
|
|
@@ -185,92 +186,3 @@ export function redirect_json_response(redirect) {
|
|
|
185
186
|
})
|
|
186
187
|
);
|
|
187
188
|
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* If the serialized data contains promises, `chunks` will be an
|
|
191
|
-
* async iterable containing their resolutions
|
|
192
|
-
* @param {import('@sveltejs/kit').RequestEvent} event
|
|
193
|
-
* @param {import('types').RequestState} event_state
|
|
194
|
-
* @param {import('types').SSROptions} options
|
|
195
|
-
* @param {Array<import('types').ServerDataSkippedNode | import('types').ServerDataNode | import('types').ServerErrorNode | null | undefined>} nodes
|
|
196
|
-
* @returns {{ data: string, chunks: AsyncIterable<string> | null }}
|
|
197
|
-
*/
|
|
198
|
-
export function get_data_json(event, event_state, options, nodes) {
|
|
199
|
-
let promise_id = 1;
|
|
200
|
-
let count = 0;
|
|
201
|
-
|
|
202
|
-
const { iterator, push, done } = create_async_iterator();
|
|
203
|
-
|
|
204
|
-
const reducers = {
|
|
205
|
-
...Object.fromEntries(
|
|
206
|
-
Object.entries(options.hooks.transport).map(([key, value]) => [key, value.encode])
|
|
207
|
-
),
|
|
208
|
-
/** @param {any} thing */
|
|
209
|
-
Promise: (thing) => {
|
|
210
|
-
if (typeof thing?.then === 'function') {
|
|
211
|
-
const id = promise_id++;
|
|
212
|
-
count += 1;
|
|
213
|
-
|
|
214
|
-
/** @type {'data' | 'error'} */
|
|
215
|
-
let key = 'data';
|
|
216
|
-
|
|
217
|
-
thing
|
|
218
|
-
.catch(
|
|
219
|
-
/** @param {any} e */ async (e) => {
|
|
220
|
-
key = 'error';
|
|
221
|
-
return handle_error_and_jsonify(event, event_state, options, /** @type {any} */ (e));
|
|
222
|
-
}
|
|
223
|
-
)
|
|
224
|
-
.then(
|
|
225
|
-
/** @param {any} value */
|
|
226
|
-
async (value) => {
|
|
227
|
-
let str;
|
|
228
|
-
try {
|
|
229
|
-
str = devalue.stringify(value, reducers);
|
|
230
|
-
} catch {
|
|
231
|
-
const error = await handle_error_and_jsonify(
|
|
232
|
-
event,
|
|
233
|
-
event_state,
|
|
234
|
-
options,
|
|
235
|
-
new Error(`Failed to serialize promise while rendering ${event.route.id}`)
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
key = 'error';
|
|
239
|
-
str = devalue.stringify(error, reducers);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
count -= 1;
|
|
243
|
-
|
|
244
|
-
push(`{"type":"chunk","id":${id},"${key}":${str}}\n`);
|
|
245
|
-
if (count === 0) done();
|
|
246
|
-
}
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
return id;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
try {
|
|
255
|
-
const strings = nodes.map((node) => {
|
|
256
|
-
if (!node) return 'null';
|
|
257
|
-
|
|
258
|
-
if (node.type === 'error' || node.type === 'skip') {
|
|
259
|
-
return JSON.stringify(node);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return `{"type":"data","data":${devalue.stringify(node.data, reducers)},"uses":${JSON.stringify(
|
|
263
|
-
serialize_uses(node)
|
|
264
|
-
)}${node.slash ? `,"slash":${JSON.stringify(node.slash)}` : ''}}`;
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
return {
|
|
268
|
-
data: `{"type":"data","nodes":[${strings.join(',')}]}\n`,
|
|
269
|
-
chunks: count > 0 ? iterator : null
|
|
270
|
-
};
|
|
271
|
-
} catch (e) {
|
|
272
|
-
// @ts-expect-error
|
|
273
|
-
e.path = 'data' + e.path;
|
|
274
|
-
throw new Error(clarify_devalue_error(event, /** @type {any} */ (e)));
|
|
275
|
-
}
|
|
276
|
-
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import * as devalue from 'devalue';
|
|
2
|
+
import { create_async_iterator } from '../../../utils/streaming.js';
|
|
3
|
+
import {
|
|
4
|
+
clarify_devalue_error,
|
|
5
|
+
get_global_name,
|
|
6
|
+
handle_error_and_jsonify,
|
|
7
|
+
serialize_uses
|
|
8
|
+
} from '../utils.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* If the serialized data contains promises, `chunks` will be an
|
|
12
|
+
* async iterable containing their resolutions
|
|
13
|
+
* @param {import('@sveltejs/kit').RequestEvent} event
|
|
14
|
+
* @param {import('types').RequestState} event_state
|
|
15
|
+
* @param {import('types').SSROptions} options
|
|
16
|
+
* @returns {import('./types.js').ServerDataSerializer}
|
|
17
|
+
*/
|
|
18
|
+
export function server_data_serializer(event, event_state, options) {
|
|
19
|
+
let promise_id = 1;
|
|
20
|
+
|
|
21
|
+
const iterator = create_async_iterator();
|
|
22
|
+
const global = get_global_name(options);
|
|
23
|
+
|
|
24
|
+
/** @param {any} thing */
|
|
25
|
+
function replacer(thing) {
|
|
26
|
+
if (typeof thing?.then === 'function') {
|
|
27
|
+
const id = promise_id++;
|
|
28
|
+
|
|
29
|
+
const promise = thing
|
|
30
|
+
.then(/** @param {any} data */ (data) => ({ data }))
|
|
31
|
+
.catch(
|
|
32
|
+
/** @param {any} error */ async (error) => ({
|
|
33
|
+
error: await handle_error_and_jsonify(event, event_state, options, error)
|
|
34
|
+
})
|
|
35
|
+
)
|
|
36
|
+
.then(
|
|
37
|
+
/**
|
|
38
|
+
* @param {{data: any; error: any}} result
|
|
39
|
+
*/
|
|
40
|
+
async ({ data, error }) => {
|
|
41
|
+
let str;
|
|
42
|
+
try {
|
|
43
|
+
str = devalue.uneval(error ? [, error] : [data], replacer);
|
|
44
|
+
} catch {
|
|
45
|
+
error = await handle_error_and_jsonify(
|
|
46
|
+
event,
|
|
47
|
+
event_state,
|
|
48
|
+
options,
|
|
49
|
+
new Error(`Failed to serialize promise while rendering ${event.route.id}`)
|
|
50
|
+
);
|
|
51
|
+
data = undefined;
|
|
52
|
+
str = devalue.uneval([, error], replacer);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return `${global}.resolve(${id}, ${str.includes('app.decode') ? `(app) => ${str}` : `() => ${str}`})`;
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
iterator.add(promise);
|
|
60
|
+
|
|
61
|
+
return `${global}.defer(${id})`;
|
|
62
|
+
} else {
|
|
63
|
+
for (const key in options.hooks.transport) {
|
|
64
|
+
const encoded = options.hooks.transport[key].encode(thing);
|
|
65
|
+
if (encoded) {
|
|
66
|
+
return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const strings = /** @type {string[]} */ ([]);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
add_node(i, node) {
|
|
76
|
+
try {
|
|
77
|
+
if (!node) {
|
|
78
|
+
strings[i] = 'null';
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** @type {any} */
|
|
83
|
+
const payload = { type: 'data', data: node.data, uses: serialize_uses(node) };
|
|
84
|
+
if (node.slash) payload.slash = node.slash;
|
|
85
|
+
|
|
86
|
+
strings[i] = devalue.uneval(payload, replacer);
|
|
87
|
+
} catch (e) {
|
|
88
|
+
// @ts-expect-error
|
|
89
|
+
e.path = e.path.slice(1);
|
|
90
|
+
throw new Error(clarify_devalue_error(event, /** @type {any} */ (e)));
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
get_data(csp) {
|
|
95
|
+
const open = `<script${csp.script_needs_nonce ? ` nonce="${csp.nonce}"` : ''}>`;
|
|
96
|
+
const close = `</script>\n`;
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
data: `[${strings.join(',')}]`,
|
|
100
|
+
chunks: promise_id > 1 ? iterator.iterate((str) => open + str + close) : null
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* If the serialized data contains promises, `chunks` will be an
|
|
108
|
+
* async iterable containing their resolutions
|
|
109
|
+
* @param {import('@sveltejs/kit').RequestEvent} event
|
|
110
|
+
* @param {import('types').RequestState} event_state
|
|
111
|
+
* @param {import('types').SSROptions} options
|
|
112
|
+
* @returns {import('./types.js').ServerDataSerializerJson}
|
|
113
|
+
*/
|
|
114
|
+
export function server_data_serializer_json(event, event_state, options) {
|
|
115
|
+
let promise_id = 1;
|
|
116
|
+
|
|
117
|
+
const iterator = create_async_iterator();
|
|
118
|
+
|
|
119
|
+
const reducers = {
|
|
120
|
+
...Object.fromEntries(
|
|
121
|
+
Object.entries(options.hooks.transport).map(([key, value]) => [key, value.encode])
|
|
122
|
+
),
|
|
123
|
+
/** @param {any} thing */
|
|
124
|
+
Promise: (thing) => {
|
|
125
|
+
if (typeof thing?.then !== 'function') {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const id = promise_id++;
|
|
130
|
+
|
|
131
|
+
/** @type {'data' | 'error'} */
|
|
132
|
+
let key = 'data';
|
|
133
|
+
|
|
134
|
+
const promise = thing
|
|
135
|
+
.catch(
|
|
136
|
+
/** @param {any} e */ async (e) => {
|
|
137
|
+
key = 'error';
|
|
138
|
+
return handle_error_and_jsonify(event, event_state, options, /** @type {any} */ (e));
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
.then(
|
|
142
|
+
/** @param {any} value */
|
|
143
|
+
async (value) => {
|
|
144
|
+
let str;
|
|
145
|
+
try {
|
|
146
|
+
str = devalue.stringify(value, reducers);
|
|
147
|
+
} catch {
|
|
148
|
+
const error = await handle_error_and_jsonify(
|
|
149
|
+
event,
|
|
150
|
+
event_state,
|
|
151
|
+
options,
|
|
152
|
+
new Error(`Failed to serialize promise while rendering ${event.route.id}`)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
key = 'error';
|
|
156
|
+
str = devalue.stringify(error, reducers);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return `{"type":"chunk","id":${id},"${key}":${str}}\n`;
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
iterator.add(promise);
|
|
164
|
+
|
|
165
|
+
return id;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const strings = /** @type {string[]} */ ([]);
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
add_node(i, node) {
|
|
173
|
+
try {
|
|
174
|
+
if (!node) {
|
|
175
|
+
strings[i] = 'null';
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (node.type === 'error' || node.type === 'skip') {
|
|
180
|
+
strings[i] = JSON.stringify(node);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
strings[i] =
|
|
185
|
+
`{"type":"data","data":${devalue.stringify(node.data, reducers)},"uses":${JSON.stringify(
|
|
186
|
+
serialize_uses(node)
|
|
187
|
+
)}${node.slash ? `,"slash":${JSON.stringify(node.slash)}` : ''}}`;
|
|
188
|
+
} catch (e) {
|
|
189
|
+
// @ts-expect-error
|
|
190
|
+
e.path = 'data' + e.path;
|
|
191
|
+
throw new Error(clarify_devalue_error(event, /** @type {any} */ (e)));
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
get_data() {
|
|
196
|
+
return {
|
|
197
|
+
data: `{"type":"data","nodes":[${strings.join(',')}]}\n`,
|
|
198
|
+
chunks: promise_id > 1 ? iterator.iterate() : null
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
is_action_json_request,
|
|
11
11
|
is_action_request
|
|
12
12
|
} from './actions.js';
|
|
13
|
+
import { server_data_serializer, server_data_serializer_json } from './data_serializer.js';
|
|
13
14
|
import { load_data, load_server_data } from './load_data.js';
|
|
14
15
|
import { render_response } from './render.js';
|
|
15
16
|
import { respond_with_error } from './respond_with_error.js';
|
|
16
|
-
import { get_data_json } from '../data/index.js';
|
|
17
17
|
import { DEV } from 'esm-env';
|
|
18
18
|
import { get_remote_action, handle_remote_form_post } from '../remote.js';
|
|
19
19
|
import { PageNodes } from '../../../utils/page_nodes.js';
|
|
@@ -147,7 +147,8 @@ export async function render_page(
|
|
|
147
147
|
options,
|
|
148
148
|
manifest,
|
|
149
149
|
state,
|
|
150
|
-
resolve_opts
|
|
150
|
+
resolve_opts,
|
|
151
|
+
data_serializer: server_data_serializer(event, event_state, options)
|
|
151
152
|
});
|
|
152
153
|
}
|
|
153
154
|
|
|
@@ -157,6 +158,12 @@ export async function render_page(
|
|
|
157
158
|
/** @type {Error | null} */
|
|
158
159
|
let load_error = null;
|
|
159
160
|
|
|
161
|
+
const data_serializer = server_data_serializer(event, event_state, options);
|
|
162
|
+
const data_serializer_json =
|
|
163
|
+
state.prerendering && should_prerender_data
|
|
164
|
+
? server_data_serializer_json(event, event_state, options)
|
|
165
|
+
: null;
|
|
166
|
+
|
|
160
167
|
/** @type {Array<Promise<import('types').ServerDataNode | null>>} */
|
|
161
168
|
const server_promises = nodes.data.map((node, i) => {
|
|
162
169
|
if (load_error) {
|
|
@@ -172,7 +179,7 @@ export async function render_page(
|
|
|
172
179
|
throw action_result.error;
|
|
173
180
|
}
|
|
174
181
|
|
|
175
|
-
|
|
182
|
+
const server_data = await load_server_data({
|
|
176
183
|
event,
|
|
177
184
|
event_state,
|
|
178
185
|
state,
|
|
@@ -187,6 +194,11 @@ export async function render_page(
|
|
|
187
194
|
return data;
|
|
188
195
|
}
|
|
189
196
|
});
|
|
197
|
+
|
|
198
|
+
data_serializer.add_node(i, server_data);
|
|
199
|
+
data_serializer_json?.add_node(i, server_data);
|
|
200
|
+
|
|
201
|
+
return server_data;
|
|
190
202
|
} catch (e) {
|
|
191
203
|
load_error = /** @type {Error} */ (e);
|
|
192
204
|
throw load_error;
|
|
@@ -287,7 +299,8 @@ export async function render_page(
|
|
|
287
299
|
data: null,
|
|
288
300
|
server_data: null
|
|
289
301
|
}),
|
|
290
|
-
fetched
|
|
302
|
+
fetched,
|
|
303
|
+
data_serializer: server_data_serializer(event, event_state, options)
|
|
291
304
|
});
|
|
292
305
|
}
|
|
293
306
|
}
|
|
@@ -303,14 +316,9 @@ export async function render_page(
|
|
|
303
316
|
}
|
|
304
317
|
}
|
|
305
318
|
|
|
306
|
-
if (state.prerendering &&
|
|
319
|
+
if (state.prerendering && data_serializer_json) {
|
|
307
320
|
// ndjson format
|
|
308
|
-
let { data, chunks } =
|
|
309
|
-
event,
|
|
310
|
-
event_state,
|
|
311
|
-
options,
|
|
312
|
-
branch.map((node) => node?.server_data)
|
|
313
|
-
);
|
|
321
|
+
let { data, chunks } = data_serializer_json.get_data();
|
|
314
322
|
|
|
315
323
|
if (chunks) {
|
|
316
324
|
for await (const chunk of chunks) {
|
|
@@ -339,7 +347,8 @@ export async function render_page(
|
|
|
339
347
|
error: null,
|
|
340
348
|
branch: ssr === false ? [] : compact(branch),
|
|
341
349
|
action_result,
|
|
342
|
-
fetched
|
|
350
|
+
fetched,
|
|
351
|
+
data_serializer
|
|
343
352
|
});
|
|
344
353
|
} catch (e) {
|
|
345
354
|
// if we end up here, it means the data loaded successfully
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { DEV } from 'esm-env';
|
|
2
|
-
import * as devalue from 'devalue';
|
|
3
2
|
import { disable_search, make_trackable } from '../../../utils/url.js';
|
|
4
3
|
import { validate_depends, validate_load_response } from '../../shared.js';
|
|
5
4
|
import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server';
|
|
6
5
|
import { record_span } from '../../telemetry/record_span.js';
|
|
7
|
-
import { clarify_devalue_error, get_node_type } from '../utils.js';
|
|
8
6
|
import { base64_encode, text_decoder } from '../../utils.js';
|
|
9
7
|
import { NULL_BODY_STATUS } from '../constants.js';
|
|
8
|
+
import { get_node_type } from '../utils.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Calls the user's server `load` function.
|
|
@@ -234,38 +233,11 @@ export async function load_data({
|
|
|
234
233
|
},
|
|
235
234
|
fn: async (current) => {
|
|
236
235
|
const traced_event = merge_tracing(event, current);
|
|
237
|
-
return await with_request_store({ event: traced_event, state: event_state }, () =>
|
|
238
|
-
|
|
239
|
-
let data = null;
|
|
240
|
-
|
|
241
|
-
return load.call(null, {
|
|
236
|
+
return await with_request_store({ event: traced_event, state: event_state }, () =>
|
|
237
|
+
load.call(null, {
|
|
242
238
|
url: event.url,
|
|
243
239
|
params: event.params,
|
|
244
|
-
|
|
245
|
-
if (data === null && server_data_node?.data != null) {
|
|
246
|
-
/** @type {Record<string, (value: any) => any>} */
|
|
247
|
-
const reducers = {};
|
|
248
|
-
|
|
249
|
-
/** @type {Record<string, (value: any) => any>} */
|
|
250
|
-
const revivers = {};
|
|
251
|
-
|
|
252
|
-
for (const key in event_state.transport) {
|
|
253
|
-
reducers[key] = event_state.transport[key].encode;
|
|
254
|
-
revivers[key] = event_state.transport[key].decode;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// run it through devalue so that the developer can't accidentally mutate it
|
|
258
|
-
try {
|
|
259
|
-
data = devalue.parse(devalue.stringify(server_data_node.data, reducers), revivers);
|
|
260
|
-
} catch (e) {
|
|
261
|
-
// @ts-expect-error
|
|
262
|
-
e.path = e.path.slice(1);
|
|
263
|
-
throw new Error(clarify_devalue_error(event, /** @type {any} */ (e)));
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return data;
|
|
268
|
-
},
|
|
240
|
+
data: server_data_node?.data ?? null,
|
|
269
241
|
route: event.route,
|
|
270
242
|
fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts),
|
|
271
243
|
setHeaders: event.setHeaders,
|
|
@@ -273,8 +245,8 @@ export async function load_data({
|
|
|
273
245
|
parent,
|
|
274
246
|
untrack: (fn) => fn(),
|
|
275
247
|
tracing: traced_event.tracing
|
|
276
|
-
})
|
|
277
|
-
|
|
248
|
+
})
|
|
249
|
+
);
|
|
278
250
|
}
|
|
279
251
|
});
|
|
280
252
|
|
|
@@ -8,15 +8,14 @@ import { serialize_data } from './serialize_data.js';
|
|
|
8
8
|
import { s } from '../../../utils/misc.js';
|
|
9
9
|
import { Csp } from './csp.js';
|
|
10
10
|
import { uneval_action_response } from './actions.js';
|
|
11
|
-
import { clarify_devalue_error, handle_error_and_jsonify, serialize_uses } from '../utils.js';
|
|
12
11
|
import { public_env } from '../../shared-server.js';
|
|
13
|
-
import { create_async_iterator } from '../../../utils/streaming.js';
|
|
14
12
|
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
15
13
|
import { SCHEME } from '../../../utils/url.js';
|
|
16
14
|
import { create_server_routing_response, generate_route_object } from './server_routing.js';
|
|
17
15
|
import { add_resolution_suffix } from '../../pathname.js';
|
|
18
16
|
import { with_request_store } from '@sveltejs/kit/internal/server';
|
|
19
17
|
import { text_encoder } from '../../utils.js';
|
|
18
|
+
import { get_global_name } from '../utils.js';
|
|
20
19
|
|
|
21
20
|
// TODO rename this function/module
|
|
22
21
|
|
|
@@ -40,6 +39,7 @@ const updated = {
|
|
|
40
39
|
* event_state: import('types').RequestState;
|
|
41
40
|
* resolve_opts: import('types').RequiredResolveOptions;
|
|
42
41
|
* action_result?: import('@sveltejs/kit').ActionResult;
|
|
42
|
+
* data_serializer: import('./types.js').ServerDataSerializer
|
|
43
43
|
* }} opts
|
|
44
44
|
*/
|
|
45
45
|
export async function render_response({
|
|
@@ -54,7 +54,8 @@ export async function render_response({
|
|
|
54
54
|
event,
|
|
55
55
|
event_state,
|
|
56
56
|
resolve_opts,
|
|
57
|
-
action_result
|
|
57
|
+
action_result,
|
|
58
|
+
data_serializer
|
|
58
59
|
}) {
|
|
59
60
|
if (state.prerendering) {
|
|
60
61
|
if (options.csp.mode === 'nonce') {
|
|
@@ -295,16 +296,8 @@ export async function render_response({
|
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
|
|
298
|
-
const global =
|
|
299
|
-
|
|
300
|
-
const { data, chunks } = get_data(
|
|
301
|
-
event,
|
|
302
|
-
event_state,
|
|
303
|
-
options,
|
|
304
|
-
branch.map((b) => b.server_data),
|
|
305
|
-
csp,
|
|
306
|
-
global
|
|
307
|
-
);
|
|
299
|
+
const global = get_global_name(options);
|
|
300
|
+
const { data, chunks } = data_serializer.get_data(csp);
|
|
308
301
|
|
|
309
302
|
if (page_config.ssr && page_config.csr) {
|
|
310
303
|
body += `\n\t\t\t${fetched
|
|
@@ -644,95 +637,3 @@ export async function render_response({
|
|
|
644
637
|
}
|
|
645
638
|
);
|
|
646
639
|
}
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* If the serialized data contains promises, `chunks` will be an
|
|
650
|
-
* async iterable containing their resolutions
|
|
651
|
-
* @param {import('@sveltejs/kit').RequestEvent} event
|
|
652
|
-
* @param {import('types').RequestState} event_state
|
|
653
|
-
* @param {import('types').SSROptions} options
|
|
654
|
-
* @param {Array<import('types').ServerDataNode | null>} nodes
|
|
655
|
-
* @param {import('./csp.js').Csp} csp
|
|
656
|
-
* @param {string} global
|
|
657
|
-
* @returns {{ data: string, chunks: AsyncIterable<string> | null }}
|
|
658
|
-
*/
|
|
659
|
-
function get_data(event, event_state, options, nodes, csp, global) {
|
|
660
|
-
let promise_id = 1;
|
|
661
|
-
let count = 0;
|
|
662
|
-
|
|
663
|
-
const { iterator, push, done } = create_async_iterator();
|
|
664
|
-
|
|
665
|
-
/** @param {any} thing */
|
|
666
|
-
function replacer(thing) {
|
|
667
|
-
if (typeof thing?.then === 'function') {
|
|
668
|
-
const id = promise_id++;
|
|
669
|
-
count += 1;
|
|
670
|
-
|
|
671
|
-
thing
|
|
672
|
-
.then(/** @param {any} data */ (data) => ({ data }))
|
|
673
|
-
.catch(
|
|
674
|
-
/** @param {any} error */ async (error) => ({
|
|
675
|
-
error: await handle_error_and_jsonify(event, event_state, options, error)
|
|
676
|
-
})
|
|
677
|
-
)
|
|
678
|
-
.then(
|
|
679
|
-
/**
|
|
680
|
-
* @param {{data: any; error: any}} result
|
|
681
|
-
*/
|
|
682
|
-
async ({ data, error }) => {
|
|
683
|
-
count -= 1;
|
|
684
|
-
|
|
685
|
-
let str;
|
|
686
|
-
try {
|
|
687
|
-
str = devalue.uneval(error ? [, error] : [data], replacer);
|
|
688
|
-
} catch {
|
|
689
|
-
error = await handle_error_and_jsonify(
|
|
690
|
-
event,
|
|
691
|
-
event_state,
|
|
692
|
-
options,
|
|
693
|
-
new Error(`Failed to serialize promise while rendering ${event.route.id}`)
|
|
694
|
-
);
|
|
695
|
-
data = undefined;
|
|
696
|
-
str = devalue.uneval([, error], replacer);
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
const nonce = csp.script_needs_nonce ? ` nonce="${csp.nonce}"` : '';
|
|
700
|
-
push(
|
|
701
|
-
`<script${nonce}>${global}.resolve(${id}, ${str.includes('app.decode') ? `(app) => ${str}` : `() => ${str}`})</script>\n`
|
|
702
|
-
);
|
|
703
|
-
if (count === 0) done();
|
|
704
|
-
}
|
|
705
|
-
);
|
|
706
|
-
|
|
707
|
-
return `${global}.defer(${id})`;
|
|
708
|
-
} else {
|
|
709
|
-
for (const key in options.hooks.transport) {
|
|
710
|
-
const encoded = options.hooks.transport[key].encode(thing);
|
|
711
|
-
if (encoded) {
|
|
712
|
-
return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
try {
|
|
719
|
-
const strings = nodes.map((node) => {
|
|
720
|
-
if (!node) return 'null';
|
|
721
|
-
|
|
722
|
-
/** @type {any} */
|
|
723
|
-
const payload = { type: 'data', data: node.data, uses: serialize_uses(node) };
|
|
724
|
-
if (node.slash) payload.slash = node.slash;
|
|
725
|
-
|
|
726
|
-
return devalue.uneval(payload, replacer);
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
return {
|
|
730
|
-
data: `[${strings.join(',')}]`,
|
|
731
|
-
chunks: count > 0 ? iterator : null
|
|
732
|
-
};
|
|
733
|
-
} catch (e) {
|
|
734
|
-
// @ts-expect-error
|
|
735
|
-
e.path = e.path.slice(1);
|
|
736
|
-
throw new Error(clarify_devalue_error(event, /** @type {any} */ (e)));
|
|
737
|
-
}
|
|
738
|
-
}
|
|
@@ -4,6 +4,7 @@ import { load_data, load_server_data } from './load_data.js';
|
|
|
4
4
|
import { handle_error_and_jsonify, static_error_page, redirect_response } from '../utils.js';
|
|
5
5
|
import { get_status } from '../../../utils/error.js';
|
|
6
6
|
import { PageNodes } from '../../../utils/page_nodes.js';
|
|
7
|
+
import { server_data_serializer } from './data_serializer.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @typedef {import('./types.js').Loaded} Loaded
|
|
@@ -45,6 +46,7 @@ export async function respond_with_error({
|
|
|
45
46
|
const nodes = new PageNodes([default_layout]);
|
|
46
47
|
const ssr = nodes.ssr();
|
|
47
48
|
const csr = nodes.csr();
|
|
49
|
+
const data_serializer = server_data_serializer(event, event_state, options);
|
|
48
50
|
|
|
49
51
|
if (ssr) {
|
|
50
52
|
state.error = true;
|
|
@@ -59,6 +61,7 @@ export async function respond_with_error({
|
|
|
59
61
|
});
|
|
60
62
|
|
|
61
63
|
const server_data = await server_data_promise;
|
|
64
|
+
data_serializer.add_node(0, server_data);
|
|
62
65
|
|
|
63
66
|
const data = await load_data({
|
|
64
67
|
event,
|
|
@@ -101,7 +104,8 @@ export async function respond_with_error({
|
|
|
101
104
|
fetched,
|
|
102
105
|
event,
|
|
103
106
|
event_state,
|
|
104
|
-
resolve_opts
|
|
107
|
+
resolve_opts,
|
|
108
|
+
data_serializer
|
|
105
109
|
});
|
|
106
110
|
} catch (e) {
|
|
107
111
|
// Edge case: If route is a 404 and the user redirects to somewhere from the root layout,
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { CookieSerializeOptions } from 'cookie';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
CspDirectives,
|
|
4
|
+
ServerDataNode,
|
|
5
|
+
SSRNode,
|
|
6
|
+
ServerDataSkippedNode,
|
|
7
|
+
ServerErrorNode
|
|
8
|
+
} from 'types';
|
|
9
|
+
import { Csp } from './csp.js';
|
|
3
10
|
|
|
4
11
|
export interface Fetched {
|
|
5
12
|
url: string;
|
|
@@ -34,3 +41,16 @@ export interface Cookie {
|
|
|
34
41
|
value: string;
|
|
35
42
|
options: CookieSerializeOptions & { path: string };
|
|
36
43
|
}
|
|
44
|
+
|
|
45
|
+
export type ServerDataSerializer = {
|
|
46
|
+
add_node(i: number, node: ServerDataNode | null): void;
|
|
47
|
+
get_data(csp: Csp): { data: string; chunks: AsyncIterable<string> | null };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type ServerDataSerializerJson = {
|
|
51
|
+
add_node(
|
|
52
|
+
i: number,
|
|
53
|
+
node: ServerDataSkippedNode | ServerDataNode | ServerErrorNode | null | undefined
|
|
54
|
+
): void;
|
|
55
|
+
get_data(): { data: string; chunks: AsyncIterable<string> | null };
|
|
56
|
+
};
|
|
@@ -60,12 +60,57 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
|
|
|
60
60
|
let form_client_refreshes;
|
|
61
61
|
|
|
62
62
|
try {
|
|
63
|
+
if (info.type === 'query_batch') {
|
|
64
|
+
if (event.request.method !== 'POST') {
|
|
65
|
+
throw new SvelteKitError(
|
|
66
|
+
405,
|
|
67
|
+
'Method Not Allowed',
|
|
68
|
+
`\`query.batch\` functions must be invoked via POST request, not ${event.request.method}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** @type {{ payloads: string[] }} */
|
|
73
|
+
const { payloads } = await event.request.json();
|
|
74
|
+
|
|
75
|
+
const args = payloads.map((payload) => parse_remote_arg(payload, transport));
|
|
76
|
+
const get_result = await with_request_store({ event, state }, () => info.run(args));
|
|
77
|
+
const results = await Promise.all(
|
|
78
|
+
args.map(async (arg, i) => {
|
|
79
|
+
try {
|
|
80
|
+
return { type: 'result', data: get_result(arg, i) };
|
|
81
|
+
} catch (error) {
|
|
82
|
+
return {
|
|
83
|
+
type: 'error',
|
|
84
|
+
error: await handle_error_and_jsonify(event, state, options, error),
|
|
85
|
+
status:
|
|
86
|
+
error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
return json(
|
|
93
|
+
/** @type {RemoteFunctionResponse} */ ({
|
|
94
|
+
type: 'result',
|
|
95
|
+
result: stringify(results, transport)
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
63
100
|
if (info.type === 'form') {
|
|
101
|
+
if (event.request.method !== 'POST') {
|
|
102
|
+
throw new SvelteKitError(
|
|
103
|
+
405,
|
|
104
|
+
'Method Not Allowed',
|
|
105
|
+
`\`form\` functions must be invoked via POST request, not ${event.request.method}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
64
109
|
if (!is_form_content_type(event.request)) {
|
|
65
110
|
throw new SvelteKitError(
|
|
66
111
|
415,
|
|
67
112
|
'Unsupported Media Type',
|
|
68
|
-
|
|
113
|
+
`\`form\` functions expect form-encoded data — received ${event.request.headers.get(
|
|
69
114
|
'content-type'
|
|
70
115
|
)}`
|
|
71
116
|
);
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
strip_data_suffix,
|
|
36
36
|
strip_resolution_suffix
|
|
37
37
|
} from '../pathname.js';
|
|
38
|
+
import { server_data_serializer } from './page/data_serializer.js';
|
|
38
39
|
import { get_remote_id, handle_remote_call } from './remote.js';
|
|
39
40
|
import { record_span } from '../telemetry/record_span.js';
|
|
40
41
|
import { otel } from '../telemetry/otel.js';
|
|
@@ -542,7 +543,8 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
542
543
|
error: null,
|
|
543
544
|
branch: [],
|
|
544
545
|
fetched: [],
|
|
545
|
-
resolve_opts
|
|
546
|
+
resolve_opts,
|
|
547
|
+
data_serializer: server_data_serializer(event, event_state, options)
|
|
546
548
|
});
|
|
547
549
|
}
|
|
548
550
|
|
|
@@ -44,6 +44,13 @@ export function allowed_methods(mod) {
|
|
|
44
44
|
return allowed;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @param {import('types').SSROptions} options
|
|
49
|
+
*/
|
|
50
|
+
export function get_global_name(options) {
|
|
51
|
+
return DEV ? '__sveltekit_dev' : `__sveltekit_${options.version_hash}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
47
54
|
/**
|
|
48
55
|
* Return as a response that renders the error.html
|
|
49
56
|
*
|
package/src/types/internal.d.ts
CHANGED
|
@@ -553,6 +553,16 @@ export type RemoteInfo =
|
|
|
553
553
|
id: string;
|
|
554
554
|
name: string;
|
|
555
555
|
}
|
|
556
|
+
| {
|
|
557
|
+
/**
|
|
558
|
+
* Corresponds to the name of the client-side exports (that's why we use underscores and not dots)
|
|
559
|
+
*/
|
|
560
|
+
type: 'query_batch';
|
|
561
|
+
id: string;
|
|
562
|
+
name: string;
|
|
563
|
+
/** Direct access to the function without batching etc logic, for remote functions called from the client */
|
|
564
|
+
run: (args: any[]) => Promise<(arg: any, idx: number) => any>;
|
|
565
|
+
}
|
|
556
566
|
| {
|
|
557
567
|
type: 'form';
|
|
558
568
|
id: string;
|
package/src/utils/routing.js
CHANGED
|
@@ -240,6 +240,8 @@ const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
|
|
|
240
240
|
*/
|
|
241
241
|
export function resolve_route(id, params) {
|
|
242
242
|
const segments = get_route_segments(id);
|
|
243
|
+
const has_id_trailing_slash = id != '/' && id.endsWith('/');
|
|
244
|
+
|
|
243
245
|
return (
|
|
244
246
|
'/' +
|
|
245
247
|
segments
|
|
@@ -262,7 +264,8 @@ export function resolve_route(id, params) {
|
|
|
262
264
|
})
|
|
263
265
|
)
|
|
264
266
|
.filter(Boolean)
|
|
265
|
-
.join('/')
|
|
267
|
+
.join('/') +
|
|
268
|
+
(has_id_trailing_slash ? '/' : '')
|
|
266
269
|
);
|
|
267
270
|
}
|
|
268
271
|
|
package/src/utils/streaming.js
CHANGED
|
@@ -16,36 +16,50 @@ function defer() {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Create an async iterator and a function to push values into it
|
|
19
|
+
* @template T
|
|
19
20
|
* @returns {{
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* done: () => void;
|
|
21
|
+
* iterate: (transform?: (input: T) => T) => AsyncIterable<T>;
|
|
22
|
+
* add: (promise: Promise<T>) => void;
|
|
23
23
|
* }}
|
|
24
24
|
*/
|
|
25
25
|
export function create_async_iterator() {
|
|
26
|
+
let count = 0;
|
|
27
|
+
|
|
26
28
|
const deferred = [defer()];
|
|
27
29
|
|
|
28
30
|
return {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
iterate: (transform = (x) => x) => {
|
|
32
|
+
return {
|
|
33
|
+
[Symbol.asyncIterator]() {
|
|
34
|
+
return {
|
|
35
|
+
next: async () => {
|
|
36
|
+
const next = await deferred[0].promise;
|
|
37
|
+
|
|
38
|
+
if (!next.done) {
|
|
39
|
+
deferred.shift();
|
|
40
|
+
return { value: transform(next.value), done: false };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return next;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
};
|
|
39
48
|
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
add: (promise) => {
|
|
50
|
+
count += 1;
|
|
51
|
+
|
|
52
|
+
void promise.then((value) => {
|
|
53
|
+
deferred[deferred.length - 1].fulfil({
|
|
54
|
+
value,
|
|
55
|
+
done: false
|
|
56
|
+
});
|
|
57
|
+
deferred.push(defer());
|
|
58
|
+
|
|
59
|
+
if (--count === 0) {
|
|
60
|
+
deferred[deferred.length - 1].fulfil({ done: true });
|
|
61
|
+
}
|
|
44
62
|
});
|
|
45
|
-
deferred.push(defer());
|
|
46
|
-
},
|
|
47
|
-
done: () => {
|
|
48
|
-
deferred[deferred.length - 1].fulfil({ done: true });
|
|
49
63
|
}
|
|
50
64
|
};
|
|
51
65
|
}
|
package/src/version.js
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -2922,6 +2922,24 @@ declare module '$app/server' {
|
|
|
2922
2922
|
* @since 2.27
|
|
2923
2923
|
*/
|
|
2924
2924
|
export function query<Schema extends StandardSchemaV1, Output>(schema: Schema, fn: (arg: StandardSchemaV1.InferOutput<Schema>) => MaybePromise<Output>): RemoteQueryFunction<StandardSchemaV1.InferInput<Schema>, Output>;
|
|
2925
|
+
export namespace query {
|
|
2926
|
+
/**
|
|
2927
|
+
* Creates a batch query function that collects multiple calls and executes them in a single request
|
|
2928
|
+
*
|
|
2929
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query.batch) for full documentation.
|
|
2930
|
+
*
|
|
2931
|
+
* @since 2.35
|
|
2932
|
+
*/
|
|
2933
|
+
function batch<Input, Output>(validate: "unchecked", fn: (args: Input[]) => MaybePromise<(arg: Input, idx: number) => Output>): RemoteQueryFunction<Input, Output>;
|
|
2934
|
+
/**
|
|
2935
|
+
* Creates a batch query function that collects multiple calls and executes them in a single request
|
|
2936
|
+
*
|
|
2937
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query.batch) for full documentation.
|
|
2938
|
+
*
|
|
2939
|
+
* @since 2.35
|
|
2940
|
+
*/
|
|
2941
|
+
function batch<Schema extends StandardSchemaV1, Output>(schema: Schema, fn: (args: StandardSchemaV1.InferOutput<Schema>[]) => MaybePromise<(arg: StandardSchemaV1.InferOutput<Schema>, idx: number) => Output>): RemoteQueryFunction<StandardSchemaV1.InferInput<Schema>, Output>;
|
|
2942
|
+
}
|
|
2925
2943
|
type RemotePrerenderInputsGenerator<Input = any> = () => MaybePromise<Input[]>;
|
|
2926
2944
|
type MaybePromise<T> = T | Promise<T>;
|
|
2927
2945
|
|
package/types/index.d.ts.map
CHANGED
|
@@ -187,6 +187,6 @@
|
|
|
187
187
|
null,
|
|
188
188
|
null
|
|
189
189
|
],
|
|
190
|
-
"mappings": "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
|
|
190
|
+
"mappings": "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",
|
|
191
191
|
"ignoreList": []
|
|
192
192
|
}
|