@sveltejs/kit 2.50.1 → 2.51.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.
@@ -605,7 +605,8 @@ async function initialize(result, target, hydrate) {
605
605
  to: {
606
606
  params: current.params,
607
607
  route: { id: current.route?.id ?? null },
608
- url: new URL(location.href)
608
+ url: new URL(location.href),
609
+ scroll: scroll_positions[current_history_index] ?? scroll_state()
609
610
  },
610
611
  willUnload: false,
611
612
  type: 'enter',
@@ -1463,12 +1464,13 @@ function get_page_key(url) {
1463
1464
  * intent?: import('./types.js').NavigationIntent;
1464
1465
  * delta?: number;
1465
1466
  * event?: PopStateEvent | MouseEvent;
1467
+ * scroll?: { x: number, y: number };
1466
1468
  * }} opts
1467
1469
  */
1468
- function _before_navigate({ url, type, intent, delta, event }) {
1470
+ function _before_navigate({ url, type, intent, delta, event, scroll }) {
1469
1471
  let should_block = false;
1470
1472
 
1471
- const nav = create_navigation(current, intent, url, type);
1473
+ const nav = create_navigation(current, intent, url, type, scroll ?? null);
1472
1474
 
1473
1475
  if (delta !== undefined) {
1474
1476
  nav.navigation.delta = delta;
@@ -1543,6 +1545,7 @@ async function navigate({
1543
1545
  type,
1544
1546
  delta: popped?.delta,
1545
1547
  intent,
1548
+ scroll: popped?.scroll,
1546
1549
  // @ts-ignore
1547
1550
  event
1548
1551
  });
@@ -1808,6 +1811,11 @@ async function navigate({
1808
1811
 
1809
1812
  nav.fulfil(undefined);
1810
1813
 
1814
+ // Update to.scroll to the actual scroll position after navigation completed
1815
+ if (nav.navigation.to) {
1816
+ nav.navigation.to.scroll = scroll_state();
1817
+ }
1818
+
1811
1819
  after_navigate_callbacks.forEach((fn) =>
1812
1820
  fn(/** @type {import('@sveltejs/kit').AfterNavigate} */ (nav.navigation))
1813
1821
  );
@@ -3013,20 +3021,12 @@ function reset_focus(url, scroll = null) {
3013
3021
  const history_state = history.state;
3014
3022
 
3015
3023
  resetting_focus = true;
3016
- location.replace(`#${id}`);
3024
+ location.replace(new URL(`#${id}`, location.href));
3017
3025
 
3018
- // if we're using hash routing, we need to restore the original hash after
3019
- // setting the focus with `location.replace()`. Although we're calling
3020
- // `location.replace()` again, the focus won't shift to the new hash
3021
- // unless there's an element with the ID `/pathname#hash`, etc.
3022
- if (app.hash) {
3023
- location.replace(url.hash);
3024
- }
3025
-
3026
- // but Firefox has a bug that sets the history state to `null` so we
3027
- // need to restore it after.
3028
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
3029
- history.replaceState(history_state, '', url.hash);
3026
+ // Firefox has a bug that sets the history state to `null` so we need to
3027
+ // restore it after. See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
3028
+ // This is also needed to restore the original hash if we're using hash routing
3029
+ history.replaceState(history_state, '', url);
3030
3030
 
3031
3031
  // Scroll management has already happened earlier so we need to restore
3032
3032
  // the scroll position after setting the sequential focus navigation starting point
@@ -3102,8 +3102,9 @@ function reset_focus(url, scroll = null) {
3102
3102
  * @param {import('./types.js').NavigationIntent | undefined} intent
3103
3103
  * @param {URL | null} url
3104
3104
  * @param {T} type
3105
+ * @param {{ x: number, y: number } | null} [target_scroll] The scroll position for the target (for popstate navigations)
3105
3106
  */
3106
- function create_navigation(current, intent, url, type) {
3107
+ function create_navigation(current, intent, url, type, target_scroll = null) {
3107
3108
  /** @type {(value: any) => void} */
3108
3109
  let fulfil;
3109
3110
 
@@ -3123,12 +3124,14 @@ function create_navigation(current, intent, url, type) {
3123
3124
  from: {
3124
3125
  params: current.params,
3125
3126
  route: { id: current.route?.id ?? null },
3126
- url: current.url
3127
+ url: current.url,
3128
+ scroll: scroll_state()
3127
3129
  },
3128
3130
  to: url && {
3129
3131
  params: intent?.params ?? null,
3130
3132
  route: { id: intent?.route?.id ?? null },
3131
- url
3133
+ url,
3134
+ scroll: target_scroll
3132
3135
  },
3133
3136
  willUnload: !intent,
3134
3137
  type,
@@ -55,7 +55,12 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
55
55
  request.headers.delete('origin');
56
56
  }
57
57
 
58
- if (url.origin !== event.url.origin) {
58
+ const decoded = decodeURIComponent(url.pathname);
59
+
60
+ if (
61
+ url.origin !== event.url.origin ||
62
+ (paths.base && decoded !== paths.base && !decoded.startsWith(`${paths.base}/`))
63
+ ) {
59
64
  // Allow cookie passthrough for "credentials: same-origin" and "credentials: include"
60
65
  // if SvelteKit is serving my.domain.com:
61
66
  // - domain.com WILL NOT receive cookies
@@ -77,7 +82,6 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
77
82
  // handle fetch requests for static assets. e.g. prebaked data, etc.
78
83
  // we need to support everything the browser's fetch supports
79
84
  const prefix = paths.assets || paths.base;
80
- const decoded = decodeURIComponent(url.pathname);
81
85
  const filename = (
82
86
  decoded.startsWith(prefix) ? decoded.slice(prefix.length) : decoded
83
87
  ).slice(1);
@@ -53,21 +53,30 @@ class BaseProvider {
53
53
  /** @type {import('types').CspDirectives} */
54
54
  #directives;
55
55
 
56
- /** @type {import('types').Csp.Source[]} */
56
+ /** @type {Set<import('types').Csp.Source>} */
57
57
  #script_src;
58
58
 
59
- /** @type {import('types').Csp.Source[]} */
59
+ /** @type {Set<import('types').Csp.Source>} */
60
60
  #script_src_elem;
61
61
 
62
- /** @type {import('types').Csp.Source[]} */
62
+ /** @type {Set<import('types').Csp.Source>} */
63
63
  #style_src;
64
64
 
65
- /** @type {import('types').Csp.Source[]} */
65
+ /** @type {Set<import('types').Csp.Source>} */
66
66
  #style_src_attr;
67
67
 
68
- /** @type {import('types').Csp.Source[]} */
68
+ /** @type {Set<import('types').Csp.Source>} */
69
69
  #style_src_elem;
70
70
 
71
+ /** @type {boolean} */
72
+ script_needs_nonce;
73
+
74
+ /** @type {boolean} */
75
+ style_needs_nonce;
76
+
77
+ /** @type {boolean} */
78
+ script_needs_hash;
79
+
71
80
  /** @type {string} */
72
81
  #nonce;
73
82
 
@@ -82,11 +91,11 @@ class BaseProvider {
82
91
 
83
92
  const d = this.#directives;
84
93
 
85
- this.#script_src = [];
86
- this.#script_src_elem = [];
87
- this.#style_src = [];
88
- this.#style_src_attr = [];
89
- this.#style_src_elem = [];
94
+ this.#script_src = new Set();
95
+ this.#script_src_elem = new Set();
96
+ this.#style_src = new Set();
97
+ this.#style_src_attr = new Set();
98
+ this.#style_src_elem = new Set();
90
99
 
91
100
  const effective_script_src = d['script-src'] || d['default-src'];
92
101
  const script_src_elem = d['script-src-elem'];
@@ -138,14 +147,20 @@ class BaseProvider {
138
147
  }
139
148
 
140
149
  /** @param {(import('types').Csp.Source | import('types').Csp.ActionSource)[] | undefined} directive */
141
- const needs_csp = (directive) =>
150
+ const style_needs_csp = (directive) =>
142
151
  !!directive && !directive.some((value) => value === 'unsafe-inline');
143
152
 
144
- this.#script_src_needs_csp = needs_csp(effective_script_src);
145
- this.#script_src_elem_needs_csp = needs_csp(script_src_elem);
146
- this.#style_src_needs_csp = needs_csp(effective_style_src);
147
- this.#style_src_attr_needs_csp = needs_csp(style_src_attr);
148
- this.#style_src_elem_needs_csp = needs_csp(style_src_elem);
153
+ /** @param {(import('types').Csp.Source | import('types').Csp.ActionSource)[] | undefined} directive */
154
+ const script_needs_csp = (directive) =>
155
+ !!directive &&
156
+ (!directive.some((value) => value === 'unsafe-inline') ||
157
+ directive.some((value) => value === 'strict-dynamic'));
158
+
159
+ this.#script_src_needs_csp = script_needs_csp(effective_script_src);
160
+ this.#script_src_elem_needs_csp = script_needs_csp(script_src_elem);
161
+ this.#style_src_needs_csp = style_needs_csp(effective_style_src);
162
+ this.#style_src_attr_needs_csp = style_needs_csp(style_src_attr);
163
+ this.#style_src_elem_needs_csp = style_needs_csp(style_src_elem);
149
164
 
150
165
  this.#script_needs_csp = this.#script_src_needs_csp || this.#script_src_elem_needs_csp;
151
166
  this.#style_needs_csp =
@@ -156,6 +171,7 @@ class BaseProvider {
156
171
 
157
172
  this.script_needs_nonce = this.#script_needs_csp && !this.#use_hashes;
158
173
  this.style_needs_nonce = this.#style_needs_csp && !this.#use_hashes;
174
+ this.script_needs_hash = this.#script_needs_csp && this.#use_hashes;
159
175
 
160
176
  this.#nonce = nonce;
161
177
  }
@@ -168,11 +184,23 @@ class BaseProvider {
168
184
  const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
169
185
 
170
186
  if (this.#script_src_needs_csp) {
171
- this.#script_src.push(source);
187
+ this.#script_src.add(source);
172
188
  }
173
189
 
174
190
  if (this.#script_src_elem_needs_csp) {
175
- this.#script_src_elem.push(source);
191
+ this.#script_src_elem.add(source);
192
+ }
193
+ }
194
+
195
+ /** @param {`sha256-${string}`[]} hashes */
196
+ add_script_hashes(hashes) {
197
+ for (const hash of hashes) {
198
+ if (this.#script_src_needs_csp) {
199
+ this.#script_src.add(hash);
200
+ }
201
+ if (this.#script_src_elem_needs_csp) {
202
+ this.#script_src_elem.add(hash);
203
+ }
176
204
  }
177
205
  }
178
206
 
@@ -184,11 +212,11 @@ class BaseProvider {
184
212
  const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
185
213
 
186
214
  if (this.#style_src_needs_csp) {
187
- this.#style_src.push(source);
215
+ this.#style_src.add(source);
188
216
  }
189
217
 
190
218
  if (this.#style_src_attr_needs_csp) {
191
- this.#style_src_attr.push(source);
219
+ this.#style_src_attr.add(source);
192
220
  }
193
221
 
194
222
  if (this.#style_src_elem_needs_csp) {
@@ -201,13 +229,13 @@ class BaseProvider {
201
229
  if (
202
230
  d['style-src-elem'] &&
203
231
  !d['style-src-elem'].includes(sha256_empty_comment_hash) &&
204
- !this.#style_src_elem.includes(sha256_empty_comment_hash)
232
+ !this.#style_src_elem.has(sha256_empty_comment_hash)
205
233
  ) {
206
- this.#style_src_elem.push(sha256_empty_comment_hash);
234
+ this.#style_src_elem.add(sha256_empty_comment_hash);
207
235
  }
208
236
 
209
237
  if (source !== sha256_empty_comment_hash) {
210
- this.#style_src_elem.push(source);
238
+ this.#style_src_elem.add(source);
211
239
  }
212
240
  }
213
241
  }
@@ -224,35 +252,35 @@ class BaseProvider {
224
252
 
225
253
  const directives = { ...this.#directives };
226
254
 
227
- if (this.#style_src.length > 0) {
255
+ if (this.#style_src.size > 0) {
228
256
  directives['style-src'] = [
229
257
  ...(directives['style-src'] || directives['default-src'] || []),
230
258
  ...this.#style_src
231
259
  ];
232
260
  }
233
261
 
234
- if (this.#style_src_attr.length > 0) {
262
+ if (this.#style_src_attr.size > 0) {
235
263
  directives['style-src-attr'] = [
236
264
  ...(directives['style-src-attr'] || []),
237
265
  ...this.#style_src_attr
238
266
  ];
239
267
  }
240
268
 
241
- if (this.#style_src_elem.length > 0) {
269
+ if (this.#style_src_elem.size > 0) {
242
270
  directives['style-src-elem'] = [
243
271
  ...(directives['style-src-elem'] || []),
244
272
  ...this.#style_src_elem
245
273
  ];
246
274
  }
247
275
 
248
- if (this.#script_src.length > 0) {
276
+ if (this.#script_src.size > 0) {
249
277
  directives['script-src'] = [
250
278
  ...(directives['script-src'] || directives['default-src'] || []),
251
279
  ...this.#script_src
252
280
  ];
253
281
  }
254
282
 
255
- if (this.#script_src_elem.length > 0) {
283
+ if (this.#script_src_elem.size > 0) {
256
284
  directives['script-src-elem'] = [
257
285
  ...(directives['script-src-elem'] || []),
258
286
  ...this.#script_src_elem
@@ -345,6 +373,10 @@ export class Csp {
345
373
  this.report_only_provider = new CspReportOnlyProvider(use_hashes, reportOnly, this.nonce);
346
374
  }
347
375
 
376
+ get script_needs_hash() {
377
+ return this.csp_provider.script_needs_hash || this.report_only_provider.script_needs_hash;
378
+ }
379
+
348
380
  get script_needs_nonce() {
349
381
  return this.csp_provider.script_needs_nonce || this.report_only_provider.script_needs_nonce;
350
382
  }
@@ -359,6 +391,12 @@ export class Csp {
359
391
  this.report_only_provider.add_script(content);
360
392
  }
361
393
 
394
+ /** @param {`sha256-${string}`[]} hashes */
395
+ add_script_hashes(hashes) {
396
+ this.csp_provider.add_script_hashes(hashes);
397
+ this.report_only_provider.add_script_hashes(hashes);
398
+ }
399
+
362
400
  /** @param {string} content */
363
401
  add_style(content) {
364
402
  this.csp_provider.add_style(content);
@@ -1,5 +1,5 @@
1
1
  import { text } from '@sveltejs/kit';
2
- import { Redirect } from '@sveltejs/kit/internal';
2
+ import { HttpError, Redirect } from '@sveltejs/kit/internal';
3
3
  import { compact } from '../../../utils/array.js';
4
4
  import { get_status, normalize_error } from '../../../utils/error.js';
5
5
  import { add_data_suffix } from '../../pathname.js';
@@ -357,6 +357,11 @@ export async function render_page(
357
357
  ssr === false ? server_data_serializer(event, event_state, options) : data_serializer
358
358
  });
359
359
  } catch (e) {
360
+ // a remote function could have thrown a redirect during render
361
+ if (e instanceof Redirect) {
362
+ return redirect_response(e.status, e.location);
363
+ }
364
+
360
365
  // if we end up here, it means the data loaded successfully
361
366
  // but the page failed to render, or that a prerendering error occurred
362
367
  return await respond_with_error({
@@ -365,7 +370,7 @@ export async function render_page(
365
370
  options,
366
371
  manifest,
367
372
  state,
368
- status: 500,
373
+ status: e instanceof HttpError ? e.status : 500,
369
374
  error: e,
370
375
  resolve_opts
371
376
  });
@@ -80,17 +80,11 @@ export async function render_response({
80
80
  */
81
81
  const link_headers = new Set();
82
82
 
83
- /**
84
- * `<link>` tags that are added to prerendered responses
85
- * (note that stylesheets are always added, prerendered or not)
86
- * @type {Set<string>}
87
- */
88
- const link_tags = new Set();
89
-
90
83
  /** @type {Map<string, string>} */
91
84
  // TODO if we add a client entry point one day, we will need to include inline_styles with the entry, otherwise stylesheets will be linked even if they are below inlineStyleThreshold
92
85
  const inline_styles = new Map();
93
86
 
87
+ /** @type {ReturnType<typeof options.root.render>} */
94
88
  let rendered;
95
89
 
96
90
  const form_value =
@@ -110,6 +104,10 @@ export async function render_response({
110
104
  */
111
105
  let base_expression = s(paths.base);
112
106
 
107
+ const csp = new Csp(options.csp, {
108
+ prerender: !!state.prerendering
109
+ });
110
+
113
111
  // if appropriate, use relative paths for greater portability
114
112
  if (paths.relative) {
115
113
  if (!state.prerendering?.fallback) {
@@ -177,7 +175,8 @@ export async function render_response({
177
175
  page: props.page
178
176
  }
179
177
  ]
180
- ])
178
+ ]),
179
+ csp: csp.script_needs_nonce ? { nonce: csp.nonce } : { hash: csp.script_needs_hash }
181
180
  };
182
181
 
183
182
  const fetch = globalThis.fetch;
@@ -227,9 +226,15 @@ export async function render_response({
227
226
  paths.reset();
228
227
  }
229
228
 
230
- const { head, html, css } = options.async ? await rendered : rendered;
229
+ const { head, html, css, hashes } = /** @type {ReturnType<typeof options.root.render>} */ (
230
+ options.async ? await rendered : rendered
231
+ );
232
+
233
+ if (hashes) {
234
+ csp.add_script_hashes(hashes.script);
235
+ }
231
236
 
232
- return { head, html, css };
237
+ return { head, html, css, hashes };
233
238
  });
234
239
  } finally {
235
240
  if (DEV) {
@@ -245,20 +250,23 @@ export async function render_response({
245
250
  for (const url of node.fonts) fonts.add(url);
246
251
 
247
252
  if (node.inline_styles && !client.inline) {
248
- Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v));
253
+ Object.entries(await node.inline_styles()).forEach(([filename, css]) => {
254
+ if (typeof css === 'string') {
255
+ inline_styles.set(filename, css);
256
+ return;
257
+ }
258
+
259
+ inline_styles.set(filename, css(`${assets}/${paths.app_dir}/immutable/assets`, assets));
260
+ });
249
261
  }
250
262
  }
251
263
  } else {
252
- rendered = { head: '', html: '', css: { code: '', map: null } };
264
+ rendered = { head: '', html: '', css: { code: '', map: null }, hashes: { script: [] } };
253
265
  }
254
266
 
255
- let head = '';
267
+ const head = new Head(rendered.head, !!state.prerendering);
256
268
  let body = rendered.html;
257
269
 
258
- const csp = new Csp(options.csp, {
259
- prerender: !!state.prerendering
260
- });
261
-
262
270
  /** @param {string} path */
263
271
  const prefixed = (path) => {
264
272
  if (path.startsWith('/')) {
@@ -276,12 +284,10 @@ export async function render_response({
276
284
  : Array.from(inline_styles.values()).join('\n');
277
285
 
278
286
  if (style) {
279
- const attributes = DEV ? [' data-sveltekit'] : [];
280
- if (csp.style_needs_nonce) attributes.push(` nonce="${csp.nonce}"`);
281
-
287
+ const attributes = DEV ? ['data-sveltekit'] : [];
288
+ if (csp.style_needs_nonce) attributes.push(`nonce="${csp.nonce}"`);
282
289
  csp.add_style(style);
283
-
284
- head += `\n\t<style${attributes.join('')}>${style}</style>`;
290
+ head.add_style(style, attributes);
285
291
  }
286
292
 
287
293
  for (const dep of stylesheets) {
@@ -299,7 +305,7 @@ export async function render_response({
299
305
  }
300
306
  }
301
307
 
302
- head += `\n\t\t<link href="${path}" ${attributes.join(' ')}>`;
308
+ head.add_stylesheet(path, attributes);
303
309
  }
304
310
 
305
311
  for (const dep of fonts) {
@@ -308,7 +314,7 @@ export async function render_response({
308
314
  if (resolve_opts.preload({ type: 'font', path })) {
309
315
  const ext = dep.slice(dep.lastIndexOf('.') + 1);
310
316
 
311
- link_tags.add(`<link rel="preload" as="font" type="font/${ext}" href="${path}" crossorigin>`);
317
+ head.add_link_tag(path, ['rel="preload"', 'as="font"', `type="font/${ext}"`, 'crossorigin']);
312
318
 
313
319
  link_headers.add(
314
320
  `<${encodeURI(path)}>; rel="preload"; as="font"; type="font/${ext}"; crossorigin; nopush`
@@ -344,19 +350,13 @@ export async function render_response({
344
350
  link_headers.add(`<${encodeURI(path)}>; rel="modulepreload"; nopush`);
345
351
 
346
352
  if (options.preload_strategy !== 'modulepreload') {
347
- head += `\n\t\t<link rel="preload" as="script" crossorigin="anonymous" href="${path}">`;
353
+ head.add_script_preload(path);
348
354
  } else {
349
- link_tags.add(`<link rel="modulepreload" href="${path}">`);
355
+ head.add_link_tag(path, ['rel="modulepreload"']);
350
356
  }
351
357
  }
352
358
  }
353
359
 
354
- if (state.prerendering && link_tags.size > 0) {
355
- head += Array.from(link_tags)
356
- .map((tag) => `\n\t\t${tag}`)
357
- .join('');
358
- }
359
-
360
360
  // prerender a `/path/to/page/__route.js` module
361
361
  if (manifest._.client.routes && state.prerendering && !state.prerendering.fallback) {
362
362
  const pathname = add_resolution_suffix(event.url.pathname);
@@ -574,19 +574,15 @@ export async function render_response({
574
574
 
575
575
  if (state.prerendering) {
576
576
  // TODO read headers set with setHeaders and convert into http-equiv where possible
577
- const http_equiv = [];
578
-
579
577
  const csp_headers = csp.csp_provider.get_meta();
580
578
  if (csp_headers) {
581
- http_equiv.push(csp_headers);
579
+ head.add_http_equiv(csp_headers);
582
580
  }
583
581
 
584
582
  if (state.prerendering.cache) {
585
- http_equiv.push(`<meta http-equiv="cache-control" content="${state.prerendering.cache}">`);
586
- }
587
-
588
- if (http_equiv.length > 0) {
589
- head = http_equiv.join('\n') + head;
583
+ head.add_http_equiv(
584
+ `<meta http-equiv="cache-control" content="${state.prerendering.cache}">`
585
+ );
590
586
  }
591
587
  } else {
592
588
  const csp_header = csp.csp_provider.get_header();
@@ -603,11 +599,8 @@ export async function render_response({
603
599
  }
604
600
  }
605
601
 
606
- // add the content after the script/css links so the link elements are parsed first
607
- head += rendered.head;
608
-
609
602
  const html = options.templates.app({
610
- head,
603
+ head: head.build(),
611
604
  body,
612
605
  assets,
613
606
  nonce: /** @type {string} */ (csp.nonce),
@@ -665,3 +658,78 @@ export async function render_response({
665
658
  }
666
659
  );
667
660
  }
661
+
662
+ class Head {
663
+ #rendered;
664
+ #prerendering;
665
+ /** @type {string[]} */
666
+ #http_equiv = [];
667
+ /** @type {string[]} */
668
+ #link_tags = [];
669
+ /** @type {string[]} */
670
+ #script_preloads = [];
671
+ /** @type {string[]} */
672
+ #style_tags = [];
673
+ /** @type {string[]} */
674
+ #stylesheet_links = [];
675
+
676
+ /**
677
+ * @param {string} rendered
678
+ * @param {boolean} prerendering
679
+ */
680
+ constructor(rendered, prerendering) {
681
+ this.#rendered = rendered;
682
+ this.#prerendering = prerendering;
683
+ }
684
+
685
+ build() {
686
+ return [
687
+ ...this.#http_equiv,
688
+ ...this.#link_tags,
689
+ ...this.#script_preloads,
690
+ this.#rendered,
691
+ ...this.#style_tags,
692
+ ...this.#stylesheet_links
693
+ ].join('\n\t\t');
694
+ }
695
+
696
+ /**
697
+ * @param {string} style
698
+ * @param {string[]} attributes
699
+ */
700
+ add_style(style, attributes) {
701
+ this.#style_tags.push(
702
+ `<style${attributes.length ? ' ' + attributes.join(' ') : ''}>${style}</style>`
703
+ );
704
+ }
705
+
706
+ /**
707
+ * @param {string} href
708
+ * @param {string[]} attributes
709
+ */
710
+ add_stylesheet(href, attributes) {
711
+ this.#stylesheet_links.push(`<link href="${href}" ${attributes.join(' ')}>`);
712
+ }
713
+
714
+ /** @param {string} href */
715
+ add_script_preload(href) {
716
+ this.#script_preloads.push(
717
+ `<link rel="preload" as="script" crossorigin="anonymous" href="${href}">`
718
+ );
719
+ }
720
+
721
+ /**
722
+ * @param {string} href
723
+ * @param {string[]} attributes
724
+ */
725
+ add_link_tag(href, attributes) {
726
+ if (!this.#prerendering) return;
727
+ this.#link_tags.push(`<link href="${href}" ${attributes.join(' ')}>`);
728
+ }
729
+
730
+ /** @param {string} tag */
731
+ add_http_equiv(tag) {
732
+ if (!this.#prerendering) return;
733
+ this.#http_equiv.push(tag);
734
+ }
735
+ }
@@ -73,23 +73,12 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
73
73
  /** @type {{ payloads: string[] }} */
74
74
  const { payloads } = await event.request.json();
75
75
 
76
- const args = payloads.map((payload) => parse_remote_arg(payload, transport));
77
- const get_result = await with_request_store({ event, state }, () => info.run(args));
78
- const results = await Promise.all(
79
- args.map(async (arg, i) => {
80
- try {
81
- return { type: 'result', data: get_result(arg, i) };
82
- } catch (error) {
83
- return {
84
- type: 'error',
85
- error: await handle_error_and_jsonify(event, state, options, error),
86
- status:
87
- error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500
88
- };
89
- }
90
- })
76
+ const args = await Promise.all(
77
+ payloads.map((payload) => parse_remote_arg(payload, transport))
91
78
  );
92
79
 
80
+ const results = await with_request_store({ event, state }, () => info.run(args, options));
81
+
93
82
  return json(
94
83
  /** @type {RemoteFunctionResponse} */ ({
95
84
  type: 'result',