@sveltejs/kit 3.0.0-next.12 → 3.0.0-next.13

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.
Files changed (46) hide show
  1. package/package.json +10 -10
  2. package/src/core/postbuild/prerender.js +3 -3
  3. package/src/core/sync/write_app_types.js +1 -2
  4. package/src/core/sync/write_tsconfig/index.js +13 -1
  5. package/src/exports/index.js +23 -12
  6. package/src/exports/internal/shared.js +4 -12
  7. package/src/exports/public.d.ts +59 -11
  8. package/src/exports/vite/build/remote.js +10 -12
  9. package/src/exports/vite/dev/index.js +32 -19
  10. package/src/exports/vite/index.js +118 -123
  11. package/src/runtime/app/server/remote/form.js +9 -1
  12. package/src/runtime/app/server/remote/prerender.js +13 -9
  13. package/src/runtime/app/server/remote/requested.js +4 -4
  14. package/src/runtime/app/state/client.js +3 -0
  15. package/src/runtime/app/state/index.js +2 -2
  16. package/src/runtime/app/state/server.js +3 -0
  17. package/src/runtime/client/client.js +584 -305
  18. package/src/runtime/client/constants.js +2 -6
  19. package/src/runtime/client/fetcher.js +27 -17
  20. package/src/runtime/client/remote-functions/form.svelte.js +39 -7
  21. package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
  22. package/src/runtime/client/remote-functions/query/instance.svelte.js +2 -2
  23. package/src/runtime/client/remote-functions/query-batch.svelte.js +1 -1
  24. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +2 -2
  25. package/src/runtime/client/remote-functions/query-live/iterator.js +10 -8
  26. package/src/runtime/client/remote-functions/shared.svelte.js +11 -10
  27. package/src/runtime/client/state.svelte.js +10 -22
  28. package/src/runtime/client/types.d.ts +1 -2
  29. package/src/runtime/client/utils.js +21 -14
  30. package/src/runtime/components/root.svelte +4 -14
  31. package/src/runtime/props.svelte.js +71 -0
  32. package/src/runtime/server/fetch.js +4 -6
  33. package/src/runtime/server/page/csp.js +86 -103
  34. package/src/runtime/server/page/index.js +1 -2
  35. package/src/runtime/server/page/load_data.js +15 -5
  36. package/src/runtime/server/page/render.js +27 -24
  37. package/src/runtime/server/page/respond_with_error.js +1 -3
  38. package/src/runtime/server/respond.js +0 -2
  39. package/src/types/ambient-private.d.ts +1 -1
  40. package/src/types/ambient.d.ts +1 -1
  41. package/src/types/internal.d.ts +2 -7
  42. package/src/types/private.d.ts +3 -12
  43. package/src/version.js +1 -1
  44. package/types/index.d.ts +92 -57
  45. package/types/index.d.ts.map +2 -1
  46. package/src/runtime/types.d.ts +0 -8
@@ -53,19 +53,19 @@ class BaseProvider {
53
53
  #directives;
54
54
 
55
55
  /** @type {Set<import('types').Csp.Source>} */
56
- #script_src;
56
+ #script_src = new Set();
57
57
 
58
58
  /** @type {Set<import('types').Csp.Source>} */
59
- #script_src_elem;
59
+ #script_src_elem = new Set();
60
60
 
61
61
  /** @type {Set<import('types').Csp.Source>} */
62
- #style_src;
62
+ #style_src = new Set();
63
63
 
64
64
  /** @type {Set<import('types').Csp.Source>} */
65
- #style_src_attr;
65
+ #style_src_attr = new Set();
66
66
 
67
67
  /** @type {Set<import('types').Csp.Source>} */
68
- #style_src_elem;
68
+ #style_src_elem = new Set();
69
69
 
70
70
  /** @type {boolean} */
71
71
  script_needs_nonce;
@@ -90,12 +90,6 @@ class BaseProvider {
90
90
 
91
91
  const d = this.#directives;
92
92
 
93
- this.#script_src = new Set();
94
- this.#script_src_elem = new Set();
95
- this.#style_src = new Set();
96
- this.#style_src_attr = new Set();
97
- this.#style_src_elem = new Set();
98
-
99
93
  const effective_script_src = d['script-src'] || d['default-src'];
100
94
  const script_src_elem = d['script-src-elem'];
101
95
  const effective_style_src = d['style-src'] || d['default-src'];
@@ -117,32 +111,25 @@ class BaseProvider {
117
111
 
118
112
  // ...and add unsafe-inline so we can inject <style> elements
119
113
  // Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list, so we remove those during dev when injecting unsafe-inline
120
- if (effective_style_src && !effective_style_src.includes('unsafe-inline')) {
121
- d['style-src'] = [
122
- ...effective_style_src.filter(
123
- (value) => !(value.startsWith('sha256-') || value.startsWith('nonce-'))
124
- ),
125
- 'unsafe-inline'
126
- ];
127
- }
128
-
129
- if (style_src_attr && !style_src_attr.includes('unsafe-inline')) {
130
- d['style-src-attr'] = [
131
- ...style_src_attr.filter(
132
- (value) => !(value.startsWith('sha256-') || value.startsWith('nonce-'))
133
- ),
134
- 'unsafe-inline'
135
- ];
136
- }
137
-
138
- if (style_src_elem && !style_src_elem.includes('unsafe-inline')) {
139
- d['style-src-elem'] = [
140
- ...style_src_elem.filter(
141
- (value) => !(value.startsWith('sha256-') || value.startsWith('nonce-'))
142
- ),
143
- 'unsafe-inline'
144
- ];
145
- }
114
+ /**
115
+ * @template {'style-src' | 'style-src-attr' | 'style-src-elem'} K
116
+ * @param {K} key
117
+ * @param {import('types').CspDirectives[K]} directive
118
+ */
119
+ const add_unsafe_inline = (key, directive) => {
120
+ if (directive && !directive.includes('unsafe-inline')) {
121
+ d[key] = /** @type {import('types').CspDirectives[K]} */ ([
122
+ ...directive.filter(
123
+ (value) => !(value.startsWith('sha256-') || value.startsWith('nonce-'))
124
+ ),
125
+ 'unsafe-inline'
126
+ ]);
127
+ }
128
+ };
129
+
130
+ add_unsafe_inline('style-src', effective_style_src);
131
+ add_unsafe_inline('style-src-attr', style_src_attr);
132
+ add_unsafe_inline('style-src-elem', style_src_elem);
146
133
  }
147
134
 
148
135
  /** @param {(import('types').Csp.Source | import('types').Csp.ActionSource)[] | undefined} directive */
@@ -175,13 +162,16 @@ class BaseProvider {
175
162
  this.#nonce = nonce;
176
163
  }
177
164
 
178
- /** @param {string} content */
179
- add_script(content) {
180
- if (!this.#script_needs_csp) return;
181
-
182
- /** @type {`nonce-${string}` | `sha256-${string}`} */
183
- const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
165
+ /**
166
+ * @param {string} content
167
+ * @returns {`nonce-${string}` | `sha256-${string}`}
168
+ */
169
+ #get_source(content) {
170
+ return this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
171
+ }
184
172
 
173
+ /** @param {`nonce-${string}` | `sha256-${string}`} source */
174
+ #add_script_source(source) {
185
175
  if (this.#script_src_needs_csp) {
186
176
  this.#script_src.add(source);
187
177
  }
@@ -191,15 +181,17 @@ class BaseProvider {
191
181
  }
192
182
  }
193
183
 
184
+ /** @param {string} content */
185
+ add_script(content) {
186
+ if (!this.#script_needs_csp) return;
187
+
188
+ this.#add_script_source(this.#get_source(content));
189
+ }
190
+
194
191
  /** @param {`sha256-${string}`[]} hashes */
195
192
  add_script_hashes(hashes) {
196
193
  for (const hash of hashes) {
197
- if (this.#script_src_needs_csp) {
198
- this.#script_src.add(hash);
199
- }
200
- if (this.#script_src_elem_needs_csp) {
201
- this.#script_src_elem.add(hash);
202
- }
194
+ this.#add_script_source(hash);
203
195
  }
204
196
  }
205
197
 
@@ -207,8 +199,7 @@ class BaseProvider {
207
199
  add_style(content) {
208
200
  if (!this.#style_needs_csp) return;
209
201
 
210
- /** @type {`nonce-${string}` | `sha256-${string}`} */
211
- const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
202
+ const source = this.#get_source(content);
212
203
 
213
204
  if (this.#style_src_needs_csp) {
214
205
  this.#style_src.add(source);
@@ -251,40 +242,34 @@ class BaseProvider {
251
242
 
252
243
  const directives = { ...this.#directives };
253
244
 
254
- if (this.#style_src.size > 0) {
255
- directives['style-src'] = [
256
- ...(directives['style-src'] || directives['default-src'] || []),
257
- ...this.#style_src
258
- ];
259
- }
260
-
261
- if (this.#style_src_attr.size > 0) {
262
- directives['style-src-attr'] = [
263
- ...(directives['style-src-attr'] || []),
264
- ...this.#style_src_attr
265
- ];
266
- }
267
-
268
- if (this.#style_src_elem.size > 0) {
269
- directives['style-src-elem'] = [
270
- ...(directives['style-src-elem'] || []),
271
- ...this.#style_src_elem
272
- ];
273
- }
274
-
275
- if (this.#script_src.size > 0) {
276
- directives['script-src'] = [
277
- ...(directives['script-src'] || directives['default-src'] || []),
278
- ...this.#script_src
279
- ];
280
- }
281
-
282
- if (this.#script_src_elem.size > 0) {
283
- directives['script-src-elem'] = [
284
- ...(directives['script-src-elem'] || []),
285
- ...this.#script_src_elem
286
- ];
287
- }
245
+ /**
246
+ * @template {'style-src' | 'style-src-attr' | 'style-src-elem' | 'script-src' | 'script-src-elem'} K
247
+ * @param {K} key
248
+ * @param {Set<import('types').Csp.Source>} sources
249
+ * @param {import('types').CspDirectives[K]} [base]
250
+ */
251
+ const merge_sources = (key, sources, base) => {
252
+ if (sources.size > 0) {
253
+ directives[key] = /** @type {import('types').CspDirectives[K]} */ ([
254
+ ...(base || []),
255
+ ...sources
256
+ ]);
257
+ }
258
+ };
259
+
260
+ merge_sources(
261
+ 'style-src',
262
+ this.#style_src,
263
+ directives['style-src'] || directives['default-src']
264
+ );
265
+ merge_sources('style-src-attr', this.#style_src_attr, directives['style-src-attr']);
266
+ merge_sources('style-src-elem', this.#style_src_elem, directives['style-src-elem']);
267
+ merge_sources(
268
+ 'script-src',
269
+ this.#script_src,
270
+ directives['script-src'] || directives['default-src']
271
+ );
272
+ merge_sources('script-src-elem', this.#script_src_elem, directives['script-src-elem']);
288
273
 
289
274
  for (const key in directives) {
290
275
  if (is_meta && (key === 'frame-ancestors' || key === 'report-uri' || key === 'sandbox')) {
@@ -300,13 +285,11 @@ class BaseProvider {
300
285
 
301
286
  const directive = [key];
302
287
  if (Array.isArray(value)) {
303
- value.forEach((value) => {
304
- if (quoted.has(value) || crypto_pattern.test(value)) {
305
- directive.push(`'${value}'`);
306
- } else {
307
- directive.push(value);
308
- }
309
- });
288
+ for (const source of value) {
289
+ directive.push(
290
+ quoted.has(source) || crypto_pattern.test(source) ? `'${source}'` : source
291
+ );
292
+ }
310
293
  }
311
294
 
312
295
  header.push(directive.join(' '));
@@ -337,17 +320,17 @@ class CspReportOnlyProvider extends BaseProvider {
337
320
  constructor(use_hashes, directives, nonce) {
338
321
  super(use_hashes, directives, nonce);
339
322
 
340
- if (Object.values(directives).filter((v) => !!v).length > 0) {
341
- // If we're generating content-security-policy-report-only,
342
- // if there are any directives, we need a report-uri or report-to (or both)
343
- // else it's just an expensive noop.
344
- const has_report_to = directives['report-to']?.length ?? 0 > 0;
345
- const has_report_uri = directives['report-uri']?.length ?? 0 > 0;
346
- if (!has_report_to && !has_report_uri) {
347
- throw Error(
348
- '`content-security-policy-report-only` must be specified with either the `report-to` or `report-uri` directives, or both'
349
- );
350
- }
323
+ // If we're generating content-security-policy-report-only,
324
+ // if there are any directives, we need a report-uri or report-to (or both)
325
+ // else it's just an expensive noop.
326
+ if (
327
+ Object.values(directives).some((v) => !!v) &&
328
+ !directives['report-to']?.length &&
329
+ !directives['report-uri']?.length
330
+ ) {
331
+ throw Error(
332
+ '`content-security-policy-report-only` must be specified with either the `report-to` or `report-uri` directives, or both'
333
+ );
351
334
  }
352
335
  }
353
336
  }
@@ -2,7 +2,7 @@
2
2
  /** @import { ActionResult, RequestEvent, SSRManifest } from '@sveltejs/kit' */
3
3
  /** @import { PageNodeIndexes, RequestState, RequiredResolveOptions, ServerDataNode, SSRNode, SSROptions, SSRState } from 'types' */
4
4
  import { text } from '@sveltejs/kit';
5
- import { HttpError, Redirect } from '@sveltejs/kit/internal';
5
+ import { Redirect } from '@sveltejs/kit/internal';
6
6
  import { compact } from '../../../utils/array.js';
7
7
  import { get_status, normalize_error } from '../../../utils/error.js';
8
8
  import { noop } from '../../../utils/functions.js';
@@ -386,7 +386,6 @@ export async function render_page(
386
386
  options,
387
387
  manifest,
388
388
  state,
389
- status: e instanceof HttpError ? e.status : 500,
390
389
  error: e,
391
390
  resolve_opts
392
391
  });
@@ -334,14 +334,24 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
334
334
  );
335
335
  }
336
336
 
337
+ const request_body =
338
+ input instanceof Request && cloned_body
339
+ ? await stream_to_string(cloned_body)
340
+ : init?.body;
341
+
342
+ if (
343
+ request_body &&
344
+ typeof request_body !== 'string' &&
345
+ !ArrayBuffer.isView(request_body)
346
+ ) {
347
+ // requests whose body can't be hashed aren't serialized — the browser repeats the fetch
348
+ return;
349
+ }
350
+
337
351
  fetched.push({
338
352
  url: same_origin ? url.href.slice(event.url.origin.length) : url.href,
339
353
  method: event.request.method,
340
- request_body: /** @type {string | ArrayBufferView | undefined} */ (
341
- input instanceof Request && cloned_body
342
- ? await stream_to_string(cloned_body)
343
- : init?.body
344
- ),
354
+ request_body: /** @type {string | ArrayBufferView | null | undefined} */ (request_body),
345
355
  request_headers: cloned_headers,
346
356
  response_body: body,
347
357
  response,
@@ -1,4 +1,4 @@
1
- /** @import { RenderNode } from '../../types.js' */
1
+ /** @import { Component } from 'svelte'; */
2
2
  import * as devalue from 'devalue';
3
3
  import { DEV } from 'esm-env';
4
4
  import { isRedirect, text } from '@sveltejs/kit';
@@ -20,6 +20,7 @@ import * as env from '__sveltekit/env';
20
20
  import { collect_remote_data } from '../remote-functions.js';
21
21
  import Root from '../../components/root.svelte';
22
22
  import { render } from 'svelte/server';
23
+ import { Props, RenderNode } from '../../props.svelte.js';
23
24
 
24
25
  // TODO rename this function/module
25
26
 
@@ -134,25 +135,29 @@ export async function render_response({
134
135
  }
135
136
 
136
137
  if (page_config.ssr) {
137
- /** @type {Record<string, any>} */
138
- const props = {
139
- components: [],
140
- resetters: [],
141
- form: form_value,
142
- tree: /** @type {RenderNode} */ ({}),
138
+ const page = {
143
139
  error,
144
- page: {
145
- error,
146
- params: /** @type {Record<string, any>} */ (event.params),
147
- route: event.route,
148
- status,
149
- url: event.url,
150
- data: {},
151
- form: form_value,
152
- state: {}
153
- }
140
+ params: /** @type {Record<string, any>} */ (event.params),
141
+ route: event.route,
142
+ status,
143
+ url: event.url,
144
+ data: {},
145
+ form: form_value,
146
+ shallow: null,
147
+ state: {}
154
148
  };
155
149
 
150
+ const props = new Props({
151
+ page,
152
+ tree: new RenderNode(
153
+ // TODO tidy up
154
+ /** @type {Component} */ (await branch[0].node.component?.()),
155
+ /** @type {Component} */ (error_components?.[1])
156
+ ),
157
+ form: form_value,
158
+ error: error ?? undefined
159
+ });
160
+
156
161
  let current_node = props.tree;
157
162
  let data = props.page.data;
158
163
 
@@ -161,16 +166,14 @@ export async function render_response({
161
166
 
162
167
  data = { ...data, ...node.data };
163
168
 
164
- // TODO this is undefined sometimes... where does the default error component come from?
165
- const error = error_components?.slice(0, i + 1).findLast((x) => x);
166
-
167
- current_node.error = error;
168
- current_node.component = await node.node.component?.();
169
169
  current_node.data = data;
170
170
 
171
171
  if (i < branch.length - 1) {
172
- current_node.child = /** @type {import('../../types.js').RenderNode} */ ({});
173
- current_node = current_node.child;
172
+ current_node = current_node.child = new RenderNode(
173
+ // TODO tidy up
174
+ /** @type {Component} */ (await branch[i + 1].node.component?.()),
175
+ /** @type {Component} */ (error_components?.slice(0, i + 2).findLast((x) => x))
176
+ );
174
177
  }
175
178
  }
176
179
 
@@ -17,7 +17,6 @@ import { server_data_serializer } from './data_serializer.js';
17
17
  * options: import('types').SSROptions;
18
18
  * manifest: import('@sveltejs/kit').SSRManifest;
19
19
  * state: import('types').SSRState;
20
- * status: number;
21
20
  * error: unknown;
22
21
  * resolve_opts: import('types').RequiredResolveOptions;
23
22
  * }} opts
@@ -28,14 +27,13 @@ export async function respond_with_error({
28
27
  options,
29
28
  manifest,
30
29
  state,
31
- status,
32
30
  error,
33
31
  resolve_opts
34
32
  }) {
35
33
  // reroute to the fallback page to prevent an infinite chain of requests.
36
34
  if (event.request.headers.get('x-sveltekit-error')) {
37
35
  const transformed = await handle_error_and_jsonify(event, event_state, options, error);
38
- return static_error_page(options, status, transformed.message);
36
+ return static_error_page(options, transformed.status, transformed.message);
39
37
  }
40
38
 
41
39
  /** @type {import('./types.js').Fetched[]} */
@@ -604,7 +604,6 @@ export async function internal_respond(request, options, manifest, state) {
604
604
  options,
605
605
  manifest,
606
606
  state,
607
- status: 400,
608
607
  error: new SvelteKitError(
609
608
  400,
610
609
  'Malformed URI',
@@ -781,7 +780,6 @@ export async function internal_respond(request, options, manifest, state) {
781
780
  options,
782
781
  manifest,
783
782
  state,
784
- status: 404,
785
783
  error: new SvelteKitError(404, 'Not Found', `Not found: ${event.url.pathname}`),
786
784
  resolve_opts
787
785
  });
@@ -25,7 +25,7 @@ declare module '__sveltekit/env' {
25
25
  // exported environment variables are defined in env.d.ts
26
26
 
27
27
  /** Populate exported environment variables */
28
- export function set_env(environment: Record<string, string>): void;
28
+ export function set_env(environment: Record<string, string | undefined>): void;
29
29
 
30
30
  /** public env vars */
31
31
  export const explicit_public_env: Record<string, any>;
@@ -44,7 +44,7 @@ declare namespace App {
44
44
  export interface PageData {}
45
45
 
46
46
  /**
47
- * The shape of the `page.state` object, which can be manipulated using the [`pushState`](https://svelte.dev/docs/kit/$app-navigation#pushState) and [`replaceState`](https://svelte.dev/docs/kit/$app-navigation#replaceState) functions from `$app/navigation`.
47
+ * The shape of the `page.state` object, which can be manipulated using [`goto`](https://svelte.dev/docs/kit/$app-navigation#goto).
48
48
  */
49
49
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
50
50
  export interface PageState {}
@@ -659,15 +659,10 @@ export interface RemotePrerenderInternals extends BaseRemoteInternals {
659
659
  }
660
660
 
661
661
  export type RemoteAnyQueryInternals =
662
- | RemoteQueryInternals
663
- | RemoteQueryBatchInternals
664
- | RemoteQueryLiveInternals;
662
+ RemoteQueryInternals | RemoteQueryBatchInternals | RemoteQueryLiveInternals;
665
663
 
666
664
  export type RemoteInternals =
667
- | RemoteAnyQueryInternals
668
- | RemoteCommandInternals
669
- | RemoteFormInternals
670
- | RemotePrerenderInternals;
665
+ RemoteAnyQueryInternals | RemoteCommandInternals | RemoteFormInternals | RemotePrerenderInternals;
671
666
 
672
667
  export interface InternalRemoteFormIssue extends RemoteFormIssue {
673
668
  name: string;
@@ -239,20 +239,11 @@ export interface PrerenderInvalidUrlHandler {
239
239
  export type PrerenderHttpErrorHandlerValue = 'fail' | 'warn' | 'ignore' | PrerenderHttpErrorHandler;
240
240
  export type PrerenderMissingIdHandlerValue = 'fail' | 'warn' | 'ignore' | PrerenderMissingIdHandler;
241
241
  export type PrerenderUnseenRoutesHandlerValue =
242
- | 'fail'
243
- | 'warn'
244
- | 'ignore'
245
- | PrerenderUnseenRoutesHandler;
242
+ 'fail' | 'warn' | 'ignore' | PrerenderUnseenRoutesHandler;
246
243
  export type PrerenderEntryGeneratorMismatchHandlerValue =
247
- | 'fail'
248
- | 'warn'
249
- | 'ignore'
250
- | PrerenderEntryGeneratorMismatchHandler;
244
+ 'fail' | 'warn' | 'ignore' | PrerenderEntryGeneratorMismatchHandler;
251
245
  export type PrerenderInvalidUrlHandlerValue =
252
- | 'fail'
253
- | 'warn'
254
- | 'ignore'
255
- | PrerenderInvalidUrlHandler;
246
+ 'fail' | 'warn' | 'ignore' | PrerenderInvalidUrlHandler;
256
247
 
257
248
  export type PrerenderOption = boolean | 'auto';
258
249
 
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 = '3.0.0-next.12';
4
+ export const VERSION = '3.0.0-next.13';