@sveltejs/kit 1.0.0-next.524 → 1.0.0-next.526

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": "1.0.0-next.524",
3
+ "version": "1.0.0-next.526",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -10,7 +10,7 @@
10
10
  "homepage": "https://kit.svelte.dev",
11
11
  "type": "module",
12
12
  "dependencies": {
13
- "@sveltejs/vite-plugin-svelte": "^1.0.5",
13
+ "@sveltejs/vite-plugin-svelte": "^1.1.0",
14
14
  "@types/cookie": "^0.5.1",
15
15
  "cookie": "^0.5.0",
16
16
  "devalue": "^4.0.0",
@@ -21,7 +21,7 @@
21
21
  "set-cookie-parser": "^2.4.8",
22
22
  "sirv": "^2.0.2",
23
23
  "tiny-glob": "^0.2.9",
24
- "undici": "^5.11.0"
24
+ "undici": "5.12.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@playwright/test": "^1.25.0",
@@ -66,6 +66,7 @@ export function generate_manifest({ build_data, relative_path, routes, format =
66
66
  pattern: ${route.pattern},
67
67
  names: ${s(route.names)},
68
68
  types: ${s(route.types)},
69
+ optional: ${s(route.optional)},
69
70
  page: ${route.page ? `{ layouts: ${get_nodes(route.page.layouts)}, errors: ${get_nodes(route.page.errors)}, leaf: ${route.page.leaf} }` : 'null'},
70
71
  endpoint: ${route.endpoint ? loader(`${relative_path}/${resolve_symlinks(build_data.server.vite_manifest, route.endpoint.file).chunk.file}`) : 'null'}
71
72
  }`;
@@ -121,7 +121,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
121
121
  );
122
122
  }
123
123
 
124
- const { pattern, names, types } = parse_route_id(id);
124
+ const { pattern, names, types, optional } = parse_route_id(id);
125
125
 
126
126
  /** @type {import('types').RouteData} */
127
127
  const route = {
@@ -132,6 +132,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
132
132
  pattern,
133
133
  names,
134
134
  types,
135
+ optional,
135
136
 
136
137
  layout: null,
137
138
  error: null,
@@ -228,6 +229,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
228
229
  pattern: /^$/,
229
230
  names: [],
230
231
  types: [],
232
+ optional: [],
231
233
  parent: null,
232
234
  layout: null,
233
235
  error: null,
@@ -195,7 +195,9 @@ function update_types(config, routes, route, to_delete = new Set()) {
195
195
  // Makes sure a type is "repackaged" and therefore more readable
196
196
  declarations.push('type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;');
197
197
  declarations.push(
198
- `type RouteParams = { ${route.names.map((param) => `${param}: string`).join('; ')} }`
198
+ `type RouteParams = { ${route.names
199
+ .map((param, idx) => `${param}${route.optional[idx] ? '?' : ''}: string`)
200
+ .join('; ')} }`
199
201
  );
200
202
 
201
203
  // These could also be placed in our public types, but it would bloat them unnecessarily and we may want to change these in the future
@@ -95,6 +95,8 @@ function get_raw_body(req, body_size_limit) {
95
95
  /** @type {import('@sveltejs/kit/node').getRequest} */
96
96
  export async function getRequest({ request, base, bodySizeLimit }) {
97
97
  return new Request(base + request.url, {
98
+ // @ts-expect-error
99
+ duplex: 'half',
98
100
  method: request.method,
99
101
  headers: /** @type {Record<string, string>} */ (request.headers),
100
102
  body: get_raw_body(request, bodySizeLimit)
@@ -172,6 +172,7 @@ export async function dev(vite, vite_config, svelte_config) {
172
172
  pattern: route.pattern,
173
173
  names: route.names,
174
174
  types: route.types,
175
+ optional: route.optional,
175
176
  page: route.page,
176
177
  endpoint: endpoint
177
178
  ? async () => {
@@ -61,7 +61,7 @@ const enforced_config = {
61
61
 
62
62
  /** @return {import('vite').Plugin[]} */
63
63
  export function sveltekit() {
64
- return [...svelte(), kit()];
64
+ return [...svelte({ prebundleSvelteLibraries: true }), kit()];
65
65
  }
66
66
 
67
67
  /**
@@ -86,6 +86,7 @@ export function enhance(form, submit = () => {}) {
86
86
  accept: 'application/json',
87
87
  'x-sveltekit-action': 'true'
88
88
  },
89
+ cache: 'no-store',
89
90
  body: data,
90
91
  signal: controller.signal
91
92
  });
@@ -11,14 +11,14 @@ export function parse(nodes, server_loads, dictionary, matchers) {
11
11
  const layouts_with_server_load = new Set(server_loads);
12
12
 
13
13
  return Object.entries(dictionary).map(([id, [leaf, layouts, errors]]) => {
14
- const { pattern, names, types } = parse_route_id(id);
14
+ const { pattern, names, types, optional } = parse_route_id(id);
15
15
 
16
16
  const route = {
17
17
  id,
18
18
  /** @param {string} path */
19
19
  exec: (path) => {
20
20
  const match = pattern.exec(path);
21
- if (match) return exec(match, id, names, types, matchers);
21
+ if (match) return exec(match, { names, types, optional }, matchers);
22
22
  },
23
23
  errors: [1, ...(errors || [])].map((n) => nodes[n]),
24
24
  layouts: [0, ...(layouts || [])].map(create_layout_loader),
@@ -14,7 +14,7 @@ export interface Client {
14
14
  // public API, exposed via $app/navigation
15
15
  after_navigate: typeof afterNavigate;
16
16
  before_navigate: typeof beforeNavigate;
17
- disable_scroll_handling: () => void;
17
+ disable_scroll_handling(): void;
18
18
  goto: typeof goto;
19
19
  invalidate: typeof invalidate;
20
20
  invalidateAll: typeof invalidateAll;
@@ -23,7 +23,7 @@ export interface Client {
23
23
  apply_action: typeof applyAction;
24
24
 
25
25
  // private API
26
- _hydrate: (opts: {
26
+ _hydrate(opts: {
27
27
  status: number;
28
28
  error: App.Error;
29
29
  node_ids: number[];
@@ -31,8 +31,8 @@ export interface Client {
31
31
  routeId: string | null;
32
32
  data: Array<import('types').ServerDataNode | null>;
33
33
  form: Record<string, any> | null;
34
- }) => Promise<void>;
35
- _start_router: () => void;
34
+ }): Promise<void>;
35
+ _start_router(): void;
36
36
  }
37
37
 
38
38
  export type NavigationIntent = {
@@ -67,7 +67,7 @@ export async function respond(request, options, state) {
67
67
  const match = candidate.pattern.exec(decoded);
68
68
  if (!match) continue;
69
69
 
70
- const matched = exec(match, candidate.id, candidate.names, candidate.types, matchers);
70
+ const matched = exec(match, candidate, matchers);
71
71
  if (matched) {
72
72
  route = candidate;
73
73
  params = decode_params(matched);
@@ -182,6 +182,20 @@ export async function render_response({
182
182
  `Data returned from \`load\` while rendering ${event.routeId} is not serializable: ${error.message} (data.${match[2]})`
183
183
  );
184
184
  }
185
+
186
+ const nonPojoError = /pojo/i.exec(error.message);
187
+
188
+ if (nonPojoError) {
189
+ const constructorName = branch.find(({ server_data }) => server_data?.data?.constructor?.name)
190
+ ?.server_data?.data?.constructor?.name;
191
+
192
+ throw new Error(
193
+ `Data returned from \`load\` (while rendering ${event.routeId}) must be a plain object${
194
+ constructorName ? ` rather than an instance of ${constructorName}` : ''
195
+ }`
196
+ );
197
+ }
198
+
185
199
  throw error;
186
200
  }
187
201
 
@@ -8,6 +8,9 @@ export function parse_route_id(id) {
8
8
  /** @type {string[]} */
9
9
  const types = [];
10
10
 
11
+ /** @type {boolean[]} */
12
+ const optional = [];
13
+
11
14
  // `/foo` should get an optional trailing slash, `/foo.json` should not
12
15
  // const add_trailing_slash = !/\.[a-z]+$/.test(key);
13
16
  let add_trailing_slash = true;
@@ -24,6 +27,7 @@ export function parse_route_id(id) {
24
27
  if (rest_match) {
25
28
  names.push(rest_match[1]);
26
29
  types.push(rest_match[2]);
30
+ optional.push(false);
27
31
  return '(?:/(.*))?';
28
32
  }
29
33
  // special case — /[[optional]]/ could contain zero segments
@@ -31,6 +35,7 @@ export function parse_route_id(id) {
31
35
  if (optional_match) {
32
36
  names.push(optional_match[1]);
33
37
  types.push(optional_match[2]);
38
+ optional.push(true);
34
39
  return '(?:/([^/]+))?';
35
40
  }
36
41
 
@@ -51,14 +56,15 @@ export function parse_route_id(id) {
51
56
  );
52
57
  }
53
58
 
54
- const [, optional, rest, name, type] = match;
59
+ const [, is_optional, is_rest, name, type] = match;
55
60
  // It's assumed that the following invalid route id cases are already checked
56
61
  // - unbalanced brackets
57
62
  // - optional param following rest param
58
63
 
59
64
  names.push(name);
60
65
  types.push(type);
61
- return rest ? '(.*?)' : optional ? '([^/]*)?' : '([^/]+?)';
66
+ optional.push(!!is_optional);
67
+ return is_rest ? '(.*?)' : is_optional ? '([^/]*)?' : '([^/]+?)';
62
68
  }
63
69
 
64
70
  if (is_last && content.includes('.')) add_trailing_slash = false;
@@ -88,7 +94,7 @@ export function parse_route_id(id) {
88
94
  .join('')}${add_trailing_slash ? '/?' : ''}$`
89
95
  );
90
96
 
91
- return { pattern, names, types };
97
+ return { pattern, names, types, optional };
92
98
  }
93
99
 
94
100
  /**
@@ -112,34 +118,32 @@ export function get_route_segments(route) {
112
118
 
113
119
  /**
114
120
  * @param {RegExpMatchArray} match
115
- * @param {string} routeId
116
- * @param {string[]} names
117
- * @param {string[]} types
121
+ * @param {{
122
+ * names: string[];
123
+ * types: string[];
124
+ * optional: boolean[];
125
+ * }} candidate
118
126
  * @param {Record<string, import('types').ParamMatcher>} matchers
119
127
  */
120
- export function exec(match, routeId, names, types, matchers) {
128
+ export function exec(match, { names, types, optional }, matchers) {
121
129
  /** @type {Record<string, string>} */
122
130
  const params = {};
123
- let last_type_idx = -1;
124
131
 
125
132
  for (let i = 0; i < names.length; i += 1) {
126
133
  const name = names[i];
127
134
  const type = types[i];
128
- let value = match[i + 1] || '';
129
-
130
- if (type) {
131
- const matcher = matchers[type];
132
- if (!matcher) throw new Error(`Missing "${type}" param matcher`); // TODO do this ahead of time?
133
-
134
- last_type_idx = routeId.indexOf(`=${type}`, last_type_idx + 1);
135
- const is_empty_optional_param =
136
- !value &&
137
- // a param without a value can only be an optional or rest param
138
- routeId.lastIndexOf('[[', last_type_idx) > routeId.lastIndexOf('[...', last_type_idx);
139
- if (!is_empty_optional_param && !matcher(value)) return;
140
- }
135
+ let value = match[i + 1];
136
+
137
+ if (value || !optional[i]) {
138
+ if (type) {
139
+ const matcher = matchers[type];
140
+ if (!matcher) throw new Error(`Missing "${type}" param matcher`); // TODO do this ahead of time?
141
141
 
142
- params[name] = value;
142
+ if (!matcher(value)) return;
143
+ }
144
+
145
+ params[name] = value ?? '';
146
+ }
143
147
  }
144
148
 
145
149
  return params;
@@ -103,7 +103,7 @@ declare module '$app/forms' {
103
103
  data: FormData;
104
104
  form: HTMLFormElement;
105
105
  controller: AbortController;
106
- cancel: () => void;
106
+ cancel(): void;
107
107
  }) =>
108
108
  | void
109
109
  | ((opts: {
@@ -114,7 +114,7 @@ declare module '$app/forms' {
114
114
  * Call this to get the default behavior of a form submission response.
115
115
  * @param options Set `reset: false` if you don't want the `<form>` values to be reset after a successful submission.
116
116
  */
117
- update: (options?: { reset: boolean }) => Promise<void>;
117
+ update(options?: { reset: boolean }): Promise<void>;
118
118
  }) => void);
119
119
 
120
120
  /**
@@ -144,7 +144,7 @@ declare module '$app/forms' {
144
144
  * If you provide a custom function with a callback and want to use the default behavior, invoke `update` in your callback.
145
145
  */
146
146
  submit?: SubmitFunction<Success, Invalid>
147
- ): { destroy: () => void };
147
+ ): { destroy(): void };
148
148
 
149
149
  /**
150
150
  * This action updates the `form` property of the current page with the given data and updates `$page.status`.
@@ -244,7 +244,7 @@ declare module '$app/navigation' {
244
244
  * `beforeNavigate` must be called during a component initialization. It remains active as long as the component is mounted.
245
245
  */
246
246
  export function beforeNavigate(
247
- callback: (navigation: Navigation & { cancel: () => void }) => void
247
+ callback: (navigation: Navigation & { cancel(): void }) => void
248
248
  ): void;
249
249
 
250
250
  /**
@@ -303,7 +303,7 @@ declare module '$app/stores' {
303
303
  /**
304
304
  * A readable store whose initial value is `false`. If [`version.pollInterval`](https://kit.svelte.dev/docs/configuration#version) is a non-zero value, SvelteKit will poll for new versions of the app and update the store value to `true` when it detects one. `updated.check()` will force an immediate check, regardless of polling.
305
305
  */
306
- export const updated: Readable<boolean> & { check: () => boolean };
306
+ export const updated: Readable<boolean> & { check(): boolean };
307
307
 
308
308
  /**
309
309
  * A function that returns all of the contextual stores. On the server, this must be called during component initialization.
package/types/index.d.ts CHANGED
@@ -79,7 +79,7 @@ export interface Builder {
79
79
  */
80
80
  createEntries(fn: (route: RouteDefinition) => AdapterEntry): Promise<void>;
81
81
 
82
- generateManifest: (opts: { relativePath: string; format?: 'esm' | 'cjs' }) => string;
82
+ generateManifest(opts: { relativePath: string; format?: 'esm' | 'cjs' }): string;
83
83
 
84
84
  getBuildDirectory(name: string): string;
85
85
  getClientDirectory(): string;
@@ -118,7 +118,7 @@ export interface Builder {
118
118
  from: string,
119
119
  to: string,
120
120
  opts?: {
121
- filter?: (basename: string) => boolean;
121
+ filter?(basename: string): boolean;
122
122
  replace?: Record<string, string>;
123
123
  }
124
124
  ): string[];
@@ -137,8 +137,8 @@ export interface Config {
137
137
  source?: string;
138
138
  dir?: string;
139
139
  emitTypes?: boolean;
140
- exports?: (filepath: string) => boolean;
141
- files?: (filepath: string) => boolean;
140
+ exports?(filepath: string): boolean;
141
+ files?(filepath: string): boolean;
142
142
  };
143
143
  preprocess?: any;
144
144
  [key: string]: any;
@@ -225,7 +225,7 @@ export interface KitConfig {
225
225
  };
226
226
  serviceWorker?: {
227
227
  register?: boolean;
228
- files?: (filepath: string) => boolean;
228
+ files?(filepath: string): boolean;
229
229
  };
230
230
  trailingSlash?: TrailingSlash;
231
231
  version?: {
@@ -311,14 +311,14 @@ export interface LoadEvent<
311
311
  *
312
312
  * `setHeaders` has no effect when a `load` function runs in the browser.
313
313
  */
314
- setHeaders: (headers: Record<string, string>) => void;
314
+ setHeaders(headers: Record<string, string>): void;
315
315
  /**
316
316
  * `await parent()` returns data from parent `+layout.js` `load` functions.
317
317
  * Implicitly, a missing `+layout.js` is treated as a `({ data }) => data` function, meaning that it will return and forward data from parent `+layout.server.js` files.
318
318
  *
319
319
  * Be careful not to introduce accidental waterfalls when using `await parent()`. If for example you only want to merge parent data into the returned output, call it _after_ fetching your other data.
320
320
  */
321
- parent: () => Promise<ParentData>;
321
+ parent(): Promise<ParentData>;
322
322
  /**
323
323
  * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](/docs/modules#$app-navigation-invalidate) to cause `load` to rerun.
324
324
  *
@@ -356,7 +356,7 @@ export interface LoadEvent<
356
356
  * <button on:click={increase}>Increase Count</button>
357
357
  * ```
358
358
  */
359
- depends: (...deps: string[]) => void;
359
+ depends(...deps: string[]): void;
360
360
  }
361
361
 
362
362
  export interface NavigationEvent<
@@ -449,7 +449,7 @@ export interface RequestEvent<
449
449
  /**
450
450
  * The client's IP address, set by the adapter.
451
451
  */
452
- getClientAddress: () => string;
452
+ getClientAddress(): string;
453
453
  /**
454
454
  * Contains custom data that was added to the request within the [`handle hook`](https://kit.svelte.dev/docs/hooks#server-hooks-handle).
455
455
  */
@@ -492,7 +492,7 @@ export interface RequestEvent<
492
492
  *
493
493
  * You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://kit.svelte.dev/docs/types#sveltejs-kit-cookies) API instead.
494
494
  */
495
- setHeaders: (headers: Record<string, string>) => void;
495
+ setHeaders(headers: Record<string, string>): void;
496
496
  /**
497
497
  * The URL of the current page or endpoint
498
498
  */
@@ -511,8 +511,8 @@ export interface RequestHandler<
511
511
  }
512
512
 
513
513
  export interface ResolveOptions {
514
- transformPageChunk?: (input: { html: string; done: boolean }) => MaybePromise<string | undefined>;
515
- filterSerializedResponseHeaders?: (name: string, value: string) => boolean;
514
+ transformPageChunk?(input: { html: string; done: boolean }): MaybePromise<string | undefined>;
515
+ filterSerializedResponseHeaders?(name: string, value: string): boolean;
516
516
  }
517
517
 
518
518
  export class Server {
@@ -540,7 +540,7 @@ export interface SSRManifest {
540
540
  };
541
541
  nodes: SSRNodeLoader[];
542
542
  routes: SSRRoute[];
543
- matchers: () => Promise<Record<string, ParamMatcher>>;
543
+ matchers(): Promise<Record<string, ParamMatcher>>;
544
544
  };
545
545
  }
546
546
 
@@ -565,7 +565,7 @@ export interface ServerLoadEvent<
565
565
  *
566
566
  * Be careful not to introduce accidental waterfalls when using `await parent()`. If for example you only want to merge parent data into the returned output, call it _after_ fetching your other data.
567
567
  */
568
- parent: () => Promise<ParentData>;
568
+ parent(): Promise<ParentData>;
569
569
  /**
570
570
  * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](/docs/modules#$app-navigation-invalidate) to cause `load` to rerun.
571
571
  *
@@ -603,7 +603,7 @@ export interface ServerLoadEvent<
603
603
  * <button on:click={increase}>Increase Count</button>
604
604
  * ```
605
605
  */
606
- depends: (...deps: string[]) => void;
606
+ depends(...deps: string[]): void;
607
607
  }
608
608
 
609
609
  export interface Action<
@@ -83,7 +83,7 @@ export type CSRPageNodeLoader = () => Promise<CSRPageNode>;
83
83
  */
84
84
  export type CSRRoute = {
85
85
  id: string;
86
- exec: (path: string) => undefined | Record<string, string>;
86
+ exec(path: string): undefined | Record<string, string>;
87
87
  errors: Array<CSRPageNodeLoader | undefined>;
88
88
  layouts: Array<[boolean, CSRPageNodeLoader] | undefined>;
89
89
  leaf: [boolean, CSRPageNodeLoader];
@@ -169,6 +169,7 @@ export interface RouteData {
169
169
  pattern: RegExp;
170
170
  names: string[];
171
171
  types: string[];
172
+ optional: boolean[];
172
173
 
173
174
  layout: PageNode | null;
174
175
  error: PageNode | null;
@@ -260,7 +261,7 @@ export interface SSRNode {
260
261
  /** external CSS files */
261
262
  stylesheets: string[];
262
263
  /** inlined styles */
263
- inline_styles?: () => MaybePromise<Record<string, string>>;
264
+ inline_styles?(): MaybePromise<Record<string, string>>;
264
265
 
265
266
  shared: {
266
267
  load?: Load;
@@ -335,6 +336,7 @@ export interface SSRRoute {
335
336
  pattern: RegExp;
336
337
  names: string[];
337
338
  types: string[];
339
+ optional: boolean[];
338
340
 
339
341
  page: PageNodeIndexes | null;
340
342
 
@@ -343,7 +345,7 @@ export interface SSRRoute {
343
345
 
344
346
  export interface SSRState {
345
347
  fallback?: string;
346
- getClientAddress: () => string;
348
+ getClientAddress(): string;
347
349
  initiator?: SSRRoute | SSRErrorPage;
348
350
  platform?: any;
349
351
  prerendering?: PrerenderOptions;
@@ -15,15 +15,15 @@ export interface AdapterEntry {
15
15
  * if it should be treated as a fallback for the current route. For example, `/foo/[c]`
16
16
  * is a fallback for `/foo/a-[b]`, and `/[...catchall]` is a fallback for all routes
17
17
  */
18
- filter: (route: RouteDefinition) => boolean;
18
+ filter(route: RouteDefinition): boolean;
19
19
 
20
20
  /**
21
21
  * A function that is invoked once the entry has been created. This is where you
22
22
  * should write the function to the filesystem and generate redirect manifests.
23
23
  */
24
- complete: (entry: {
25
- generateManifest: (opts: { relativePath: string; format?: 'esm' | 'cjs' }) => string;
26
- }) => MaybePromise<void>;
24
+ complete(entry: {
25
+ generateManifest(opts: { relativePath: string; format?: 'esm' | 'cjs' }): string;
26
+ }): MaybePromise<void>;
27
27
  }
28
28
 
29
29
  // Based on https://github.com/josh-hemphill/csp-typed-directives/blob/latest/src/csp.types.ts
@@ -195,7 +195,7 @@ export type PrerenderOption = boolean | 'auto';
195
195
  export type PrerenderMap = Map<string, PrerenderOption>;
196
196
 
197
197
  export interface RequestOptions {
198
- getClientAddress: () => string;
198
+ getClientAddress(): string;
199
199
  platform?: App.Platform;
200
200
  }
201
201