@sveltejs/kit 2.63.1 → 2.64.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "2.63.1",
3
+ "version": "2.64.0",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -152,7 +152,11 @@ export function build_server_nodes(
152
152
  /** @type {Set<string>} */
153
153
  const eager_assets = new Set();
154
154
 
155
- if (node.component && client_manifest) {
155
+ const uses_server_component = node.child_pages
156
+ ? node.child_pages.some((child) => child.page_options?.ssr !== false)
157
+ : node.page_options?.ssr !== false;
158
+
159
+ if (node.component && client_manifest && uses_server_component) {
156
160
  exports.push(
157
161
  'let component_cache;',
158
162
  `export const component = async () => component_cache ??= (await import('../${
@@ -4,7 +4,7 @@ import { app_dir, base } from '$app/paths/internal/client';
4
4
  import * as devalue from 'devalue';
5
5
  import { HttpError } from '@sveltejs/kit/internal';
6
6
  import { app } from '../client.js';
7
- import { stringify_remote_arg } from '../../shared.js';
7
+ import { stringify_command_arg } from '../../shared.js';
8
8
  import {
9
9
  get_remote_request_headers,
10
10
  apply_refreshes,
@@ -56,7 +56,7 @@ export function command(id) {
56
56
  const response = await fetch(`${base}/${app_dir}/remote/${id}`, {
57
57
  method: 'POST',
58
58
  body: JSON.stringify({
59
- payload: stringify_remote_arg(arg, app.hooks.transport, false),
59
+ payload: await stringify_command_arg(arg, app.hooks.transport),
60
60
  refreshes: Array.from(refreshes ?? [])
61
61
  }),
62
62
  headers
@@ -97,6 +97,8 @@ function to_sorted(value, clones) {
97
97
  const remote_object = '__skrao';
98
98
  const remote_map = '__skram';
99
99
  const remote_set = '__skras';
100
+ const remote_file = '__skraf';
101
+ const remote_promise_guard = '__skrap';
100
102
  const remote_regex_guard = '__skrag';
101
103
  const remote_arg_marker = Symbol(remote_object);
102
104
 
@@ -108,13 +110,12 @@ const remote_arg_marker = Symbol(remote_object);
108
110
  function create_remote_arg_reducers(transport, sort, remote_arg_clones) {
109
111
  /** @type {Record<string, (value: unknown) => unknown>} */
110
112
  const remote_fns_reducers = {
111
- [remote_regex_guard]:
112
- /** @type {(value: unknown) => void} */
113
- (value) => {
114
- if (value instanceof RegExp) {
115
- throw new Error('Regular expressions are not valid remote function arguments');
116
- }
113
+ /** @param {unknown} value */
114
+ [remote_regex_guard]: (value) => {
115
+ if (value instanceof RegExp) {
116
+ throw new Error('Regular expressions are not valid remote function arguments');
117
117
  }
118
+ }
118
119
  };
119
120
 
120
121
  if (sort) {
@@ -230,6 +231,24 @@ function create_remote_arg_revivers(transport) {
230
231
  }
231
232
 
232
233
  return set;
234
+ },
235
+ /** @type {(value: any) => File} */
236
+ [remote_file]: (value) => {
237
+ if (
238
+ !value ||
239
+ typeof value !== 'object' ||
240
+ typeof value.name !== 'string' ||
241
+ typeof value.type !== 'string' ||
242
+ typeof value.size !== 'number' ||
243
+ typeof value.lastModified !== 'number' ||
244
+ !(value.data instanceof ArrayBuffer)
245
+ ) {
246
+ throw new Error('Invalid data for File reviver');
247
+ }
248
+
249
+ const { data, name, ...meta } = value;
250
+
251
+ return new File([data], name, meta);
233
252
  }
234
253
  };
235
254
 
@@ -250,18 +269,69 @@ function create_remote_arg_revivers(transport) {
250
269
  * it is both a valid URL and a valid file name (necessary for prerendering).
251
270
  * @param {any} value
252
271
  * @param {Transport} transport
253
- * @param {boolean} [sort]
254
272
  */
255
- export function stringify_remote_arg(value, transport, sort = true) {
273
+ export function stringify_remote_arg(value, transport) {
256
274
  if (value === undefined) return '';
257
275
 
258
276
  // If people hit file/url size limits, we can look into using something like compress_and_encode_text from svelte.dev beyond a certain size
259
- const json_string = devalue.stringify(
260
- value,
261
- create_remote_arg_reducers(transport, sort, new Map())
262
- );
277
+ const json = devalue.stringify(value, create_remote_arg_reducers(transport, true, new Map()));
278
+
279
+ return url_friendly_base64_encode(json);
280
+ }
281
+
282
+ /**
283
+ * Stringifies command arguments, including `File` objects.
284
+ * @param {any} value
285
+ * @param {Transport} transport
286
+ */
287
+ export async function stringify_command_arg(value, transport) {
288
+ if (value === undefined) return '';
289
+
290
+ const reducers = create_remote_arg_reducers(transport, false, new Map());
263
291
 
264
- const bytes = text_encoder.encode(json_string);
292
+ /** @type {Set<Promise<any>>} */
293
+ const allowed_promises = new Set();
294
+
295
+ /** @param {any} value */
296
+ reducers[remote_file] = (value) => {
297
+ if (value instanceof File) {
298
+ const promise = value.arrayBuffer().then((data) => ({
299
+ data,
300
+ lastModified: value.lastModified,
301
+ name: value.name,
302
+ size: value.size,
303
+ type: value.type
304
+ }));
305
+
306
+ allowed_promises.add(promise);
307
+
308
+ return promise;
309
+ }
310
+ };
311
+
312
+ // we don't want to allow arbitrary promises, because they won't
313
+ // show up as promises on the other side. this is something
314
+ // we could potentially change in future. stringifyAsync
315
+ // will await them, so we need to explicitly deny them
316
+ /** @param {unknown} value */
317
+ reducers[remote_promise_guard] = (value) => {
318
+ if (value instanceof Promise && !allowed_promises.has(value)) {
319
+ throw new Error('Promises are not valid remote function arguments');
320
+ }
321
+ };
322
+
323
+ const json = await devalue.stringifyAsync(value, reducers);
324
+
325
+ return url_friendly_base64_encode(json);
326
+ }
327
+
328
+ /**
329
+ * Base64-encodes `string` in such a way that the result is safe to use
330
+ * as both a URI component and a filename
331
+ * @param {string} string
332
+ */
333
+ function url_friendly_base64_encode(string) {
334
+ const bytes = text_encoder.encode(string);
265
335
  return base64_encode(bytes).replaceAll('=', '').replaceAll('+', '-').replaceAll('/', '_');
266
336
  }
267
337
 
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // generated during release, do not modify
2
2
 
3
3
  /** @type {string} */
4
- export const VERSION = '2.63.1';
4
+ export const VERSION = '2.64.0';