@sveltejs/kit 3.0.0-next.11 → 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.
- package/package.json +10 -10
- package/src/cli.js +8 -8
- package/src/constants.js +1 -1
- package/src/core/config/options.js +43 -35
- package/src/core/env.js +25 -11
- package/src/core/postbuild/prerender.js +3 -3
- package/src/core/sync/sync.js +11 -14
- package/src/core/sync/utils.js +21 -1
- package/src/core/sync/{write_non_ambient.js → write_app_types.js} +24 -23
- package/src/core/sync/write_client_manifest.js +4 -12
- package/src/core/sync/write_env.js +6 -4
- package/src/core/sync/write_server.js +10 -15
- package/src/core/sync/write_tsconfig/index.js +257 -0
- package/src/core/sync/write_tsconfig/utils.js +162 -0
- package/src/core/sync/write_types/index.js +80 -88
- package/src/exports/index.js +23 -12
- package/src/exports/internal/server/index.js +3 -1
- package/src/exports/internal/shared.js +4 -12
- package/src/exports/public.d.ts +87 -62
- package/src/exports/vite/build/remote.js +10 -12
- package/src/exports/vite/dev/index.js +113 -88
- package/src/exports/vite/index.js +452 -237
- package/src/exports/vite/module_ids.js +3 -1
- package/src/exports/vite/utils.js +1 -10
- package/src/runner.js +13 -0
- package/src/runtime/app/forms.js +4 -0
- package/src/runtime/app/manifest/index.js +1 -0
- package/src/runtime/app/paths/client.js +30 -30
- package/src/runtime/app/paths/internal/client.js +26 -0
- package/src/runtime/app/paths/server.js +22 -9
- package/src/runtime/app/paths/types.d.ts +11 -19
- package/src/runtime/app/server/remote/command.js +12 -7
- package/src/runtime/app/server/remote/form.js +37 -26
- package/src/runtime/app/server/remote/prerender.js +22 -11
- package/src/runtime/app/server/remote/query.js +5 -4
- package/src/runtime/app/server/remote/requested.js +4 -4
- package/src/runtime/app/server/remote/shared.js +48 -30
- package/src/runtime/app/service-worker/index.js +24 -0
- package/src/runtime/app/state/client.js +3 -0
- package/src/runtime/app/state/index.js +3 -3
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/client/client.js +627 -311
- package/src/runtime/client/constants.js +2 -6
- package/src/runtime/client/fetcher.js +27 -17
- package/src/runtime/client/remote-functions/form.svelte.js +82 -58
- package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query/index.js +2 -2
- package/src/runtime/client/remote-functions/query/instance.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-batch.svelte.js +3 -4
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-live/iterator.js +15 -10
- package/src/runtime/client/remote-functions/shared.svelte.js +15 -11
- package/src/runtime/client/state.svelte.js +54 -33
- package/src/runtime/client/types.d.ts +1 -2
- package/src/runtime/client/utils.js +21 -14
- package/src/runtime/components/root.svelte +4 -14
- package/src/runtime/form-utils.js +89 -54
- package/src/runtime/props.svelte.js +71 -0
- package/src/runtime/server/cookie.js +1 -1
- package/src/runtime/server/data/index.js +31 -28
- package/src/runtime/server/errors.js +1 -1
- package/src/runtime/server/fetch.js +4 -6
- package/src/runtime/server/page/actions.js +3 -3
- package/src/runtime/server/page/csp.js +86 -103
- package/src/runtime/server/page/index.js +1 -2
- package/src/runtime/server/page/load_data.js +15 -5
- package/src/runtime/server/page/render.js +46 -52
- package/src/runtime/server/page/respond_with_error.js +1 -3
- package/src/runtime/server/remote-functions.js +66 -35
- package/src/runtime/server/respond.js +56 -16
- package/src/runtime/server/utils.js +10 -0
- package/src/types/ambient-private.d.ts +9 -1
- package/src/types/ambient.d.ts +23 -28
- package/src/types/global-private.d.ts +12 -0
- package/src/types/internal.d.ts +15 -10
- package/src/types/private.d.ts +3 -12
- package/src/utils/url.js +12 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +172 -155
- package/types/index.d.ts.map +5 -1
- package/src/core/sync/write_ambient.js +0 -18
- package/src/core/sync/write_tsconfig.js +0 -258
- package/src/runtime/types.d.ts +0 -8
- /package/src/core/sync/{write_tsconfig_test → write_tsconfig/test-app}/package.json +0 -0
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
export const SNAPSHOT_KEY = 'sveltekit:snapshot';
|
|
2
|
-
export const
|
|
3
|
-
export const
|
|
4
|
-
export const PAGE_URL_KEY = 'sveltekit:pageurl';
|
|
5
|
-
|
|
6
|
-
export const HISTORY_INDEX = 'sveltekit:history';
|
|
7
|
-
export const NAVIGATION_INDEX = 'sveltekit:navigation';
|
|
2
|
+
export const HISTORY_INFO_KEY = 'sveltekit:history-info';
|
|
3
|
+
export const HISTORY_METADATA_KEY = 'sveltekit:metadata';
|
|
8
4
|
|
|
9
5
|
export const PRELOAD_PRIORITIES = /** @type {const} */ ({
|
|
10
6
|
tap: 1,
|
|
@@ -89,22 +89,24 @@ const cache = new Map();
|
|
|
89
89
|
export function initial_fetch(resource, opts) {
|
|
90
90
|
const selector = build_selector(resource, opts);
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
script
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
if (selector) {
|
|
93
|
+
const script = document.querySelector(selector);
|
|
94
|
+
if (script?.textContent) {
|
|
95
|
+
script.remove(); // In case multiple script tags match the same selector
|
|
96
|
+
let { body, ...init } = JSON.parse(script.textContent);
|
|
97
|
+
|
|
98
|
+
const b64 = script.getAttribute('data-b64');
|
|
99
|
+
if (b64 !== null) {
|
|
100
|
+
// Can't use native_fetch('data:...;base64,${body}')
|
|
101
|
+
// csp can block the request
|
|
102
|
+
body = base64_decode(body);
|
|
103
|
+
}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
const ttl = script.getAttribute('data-ttl');
|
|
106
|
+
if (ttl) cache.set(selector, { body, init, ttl: 1000 * Number(ttl) });
|
|
106
107
|
|
|
107
|
-
|
|
108
|
+
return Promise.resolve(new Response(body, init));
|
|
109
|
+
}
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
return DEV ? dev_fetch(resource, opts) : window.fetch(resource, opts);
|
|
@@ -119,7 +121,7 @@ export function initial_fetch(resource, opts) {
|
|
|
119
121
|
export function subsequent_fetch(resource, resolved, opts) {
|
|
120
122
|
if (cache.size > 0) {
|
|
121
123
|
const selector = build_selector(resource, opts);
|
|
122
|
-
const cached = cache.get(selector);
|
|
124
|
+
const cached = selector && cache.get(selector);
|
|
123
125
|
if (cached) {
|
|
124
126
|
// https://developer.mozilla.org/en-US/docs/Web/API/Request/cache#value
|
|
125
127
|
if (
|
|
@@ -155,6 +157,7 @@ export function dev_fetch(resource, opts) {
|
|
|
155
157
|
* Build the cache key for a given request
|
|
156
158
|
* @param {URL | RequestInfo} resource
|
|
157
159
|
* @param {RequestInit} [opts]
|
|
160
|
+
* @returns {string | null} `null` for requests the server never serializes
|
|
158
161
|
*/
|
|
159
162
|
function build_selector(resource, opts) {
|
|
160
163
|
const url = JSON.stringify(resource instanceof Request ? resource.url : resource);
|
|
@@ -162,6 +165,13 @@ function build_selector(resource, opts) {
|
|
|
162
165
|
let selector = `script[data-sveltekit-fetched][data-url=${url}]`;
|
|
163
166
|
|
|
164
167
|
if (opts?.headers || opts?.body) {
|
|
168
|
+
const body = opts.body;
|
|
169
|
+
|
|
170
|
+
if (body && typeof body !== 'string' && !ArrayBuffer.isView(body)) {
|
|
171
|
+
// the server skips serializing these, so a matching script tag belongs to another request
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
|
|
165
175
|
/** @type {import('types').StrictBody[]} */
|
|
166
176
|
const values = [];
|
|
167
177
|
|
|
@@ -169,8 +179,8 @@ function build_selector(resource, opts) {
|
|
|
169
179
|
values.push([...new Headers(opts.headers)].join(','));
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
if (
|
|
173
|
-
values.push(
|
|
182
|
+
if (body) {
|
|
183
|
+
values.push(/** @type {import('types').StrictBody} */ (body));
|
|
174
184
|
}
|
|
175
185
|
|
|
176
186
|
selector += `[data-hash="${hash(...values)}"]`;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
handle_error,
|
|
12
12
|
refreshAll
|
|
13
13
|
} from '../client.js';
|
|
14
|
+
import { page } from '../state.svelte.js';
|
|
14
15
|
import { tick } from 'svelte';
|
|
15
16
|
import { categorize_updates, remote_request } from './shared.svelte.js';
|
|
16
17
|
import { createAttachmentKey } from 'svelte/attachments';
|
|
@@ -25,7 +26,9 @@ import {
|
|
|
25
26
|
serialize_binary_form,
|
|
26
27
|
deep_get,
|
|
27
28
|
DELETE_KEY,
|
|
28
|
-
BINARY_FORM_CONTENT_TYPE
|
|
29
|
+
BINARY_FORM_CONTENT_TYPE,
|
|
30
|
+
parse_form_key,
|
|
31
|
+
coerce_form_value
|
|
29
32
|
} from '../../form-utils.js';
|
|
30
33
|
|
|
31
34
|
/**
|
|
@@ -37,16 +40,22 @@ import {
|
|
|
37
40
|
* @returns {InternalRemoteFormIssue[]}
|
|
38
41
|
*/
|
|
39
42
|
function merge_with_server_issues(form_data, current_issues, client_issues) {
|
|
43
|
+
const client_names = new Set(client_issues.map((issue) => issue.name));
|
|
44
|
+
|
|
40
45
|
const merged = [
|
|
41
|
-
...current_issues.filter(
|
|
42
|
-
(issue) => issue.server && !client_issues.some((i) => i.name === issue.name)
|
|
43
|
-
),
|
|
46
|
+
...current_issues.filter((issue) => issue.server && !client_names.has(issue.name)),
|
|
44
47
|
...client_issues
|
|
45
48
|
];
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
/** @type {Map<string, number>} */
|
|
51
|
+
const positions = new Map();
|
|
52
|
+
let i = 0;
|
|
53
|
+
for (const key of form_data.keys()) {
|
|
54
|
+
if (!positions.has(key)) positions.set(key, i);
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
48
57
|
|
|
49
|
-
return merged.sort((a, b) =>
|
|
58
|
+
return merged.sort((a, b) => (positions.get(a.name) ?? -1) - (positions.get(b.name) ?? -1));
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
/**
|
|
@@ -67,7 +76,29 @@ export function form(id) {
|
|
|
67
76
|
function create_instance(key) {
|
|
68
77
|
const action_id_without_key = id;
|
|
69
78
|
const action_id = id + (key != undefined ? `/${JSON.stringify(key)}` : '');
|
|
70
|
-
const action = '
|
|
79
|
+
const action = '/remote=' + encodeURIComponent(action_id);
|
|
80
|
+
|
|
81
|
+
/** @type {string} */
|
|
82
|
+
let cached_search = '';
|
|
83
|
+
/** @type {string} */
|
|
84
|
+
let cached_query = '';
|
|
85
|
+
|
|
86
|
+
/** @returns {string} */
|
|
87
|
+
function get_action() {
|
|
88
|
+
if (page.url.search !== cached_search) {
|
|
89
|
+
cached_search = page.url.search;
|
|
90
|
+
|
|
91
|
+
if (page.url.search) {
|
|
92
|
+
const params = new URLSearchParams(page.url.search);
|
|
93
|
+
params.delete('/remote');
|
|
94
|
+
cached_query = params.toString();
|
|
95
|
+
} else {
|
|
96
|
+
cached_query = '';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return `?${cached_query && `${cached_query}&`}${action}`;
|
|
101
|
+
}
|
|
71
102
|
|
|
72
103
|
// the output of a non-enhanced submission that resulted in this page —
|
|
73
104
|
// consume it so the form's state survives hydration (form outputs are
|
|
@@ -123,8 +154,8 @@ export function form(id) {
|
|
|
123
154
|
/** @type {InternalRemoteFormIssue[] | null} */
|
|
124
155
|
let unread_issues = null;
|
|
125
156
|
|
|
126
|
-
/** @type {string | null} */
|
|
127
|
-
let
|
|
157
|
+
/** @type {{ name: string; type: 'number' | 'boolean' | null; is_array: boolean } | null} */
|
|
158
|
+
let previous_submitter = null;
|
|
128
159
|
|
|
129
160
|
/**
|
|
130
161
|
* In dev, warn if there are validation issues going unread
|
|
@@ -160,8 +191,8 @@ export function form(id) {
|
|
|
160
191
|
* @returns {Record<string, any>}
|
|
161
192
|
*/
|
|
162
193
|
function convert(form_data) {
|
|
163
|
-
const data = convert_formdata(form_data);
|
|
164
|
-
if (key !== undefined && !
|
|
194
|
+
const data = convert_formdata(action_id_without_key, form_data);
|
|
195
|
+
if (key !== undefined && !('id' in data)) {
|
|
165
196
|
data.id = key;
|
|
166
197
|
}
|
|
167
198
|
return data;
|
|
@@ -353,7 +384,10 @@ export function form(id) {
|
|
|
353
384
|
const instance = {};
|
|
354
385
|
|
|
355
386
|
instance.method = 'POST';
|
|
356
|
-
instance
|
|
387
|
+
Object.defineProperty(instance, 'action', {
|
|
388
|
+
get: get_action,
|
|
389
|
+
enumerable: true
|
|
390
|
+
});
|
|
357
391
|
|
|
358
392
|
instance[createAttachmentKey()] = (/** @type {HTMLFormElement} */ form) => {
|
|
359
393
|
if (element) {
|
|
@@ -405,26 +439,30 @@ export function form(id) {
|
|
|
405
439
|
const form_data = new FormData(form, event.submitter);
|
|
406
440
|
|
|
407
441
|
if (
|
|
408
|
-
|
|
409
|
-
!Array.from(form_data.keys())
|
|
442
|
+
previous_submitter !== null &&
|
|
443
|
+
!Array.from(form_data.keys())
|
|
444
|
+
.map((k) => parse_form_key(action_id_without_key, k).name)
|
|
445
|
+
.includes(previous_submitter.name)
|
|
410
446
|
) {
|
|
411
|
-
|
|
412
|
-
// `set_nested_value` would coerce `undefined` to `NaN`/`false`
|
|
413
|
-
// instead of clearing the previously-submitted value.
|
|
414
|
-
set_nested_value(input, previous_submitter_name, undefined);
|
|
447
|
+
set_nested_value(input, previous_submitter, undefined);
|
|
415
448
|
}
|
|
416
449
|
|
|
417
450
|
if (event.submitter) {
|
|
418
451
|
const name = event.submitter.getAttribute('name');
|
|
452
|
+
|
|
453
|
+
/** @type {null | ReturnType<typeof parse_form_key>} */
|
|
454
|
+
let submitter = null;
|
|
455
|
+
|
|
419
456
|
const value = /** @type {any} */ (event.submitter).value;
|
|
420
457
|
|
|
421
458
|
if (name !== null && value !== undefined) {
|
|
422
|
-
|
|
459
|
+
submitter = parse_form_key(action_id_without_key, name);
|
|
460
|
+
set_nested_value(input, submitter, coerce_form_value(submitter.type, value));
|
|
423
461
|
}
|
|
424
462
|
|
|
425
|
-
|
|
463
|
+
previous_submitter = submitter;
|
|
426
464
|
} else {
|
|
427
|
-
|
|
465
|
+
previous_submitter = null;
|
|
428
466
|
}
|
|
429
467
|
|
|
430
468
|
if (DEV) {
|
|
@@ -463,15 +501,14 @@ export function form(id) {
|
|
|
463
501
|
// but that makes the types unnecessarily awkward
|
|
464
502
|
const element = /** @type {HTMLInputElement} */ (e.target);
|
|
465
503
|
|
|
466
|
-
|
|
504
|
+
const name = element.name;
|
|
467
505
|
if (!name) return;
|
|
468
506
|
|
|
469
|
-
const
|
|
470
|
-
if (is_array) name = name.slice(0, -2);
|
|
507
|
+
const field = parse_form_key(action_id_without_key, name);
|
|
471
508
|
|
|
472
509
|
const is_file = element.type === 'file';
|
|
473
510
|
|
|
474
|
-
if (is_array) {
|
|
511
|
+
if (field.is_array) {
|
|
475
512
|
let value;
|
|
476
513
|
|
|
477
514
|
if (element.tagName === 'SELECT') {
|
|
@@ -481,7 +518,7 @@ export function form(id) {
|
|
|
481
518
|
);
|
|
482
519
|
} else {
|
|
483
520
|
const elements = /** @type {HTMLInputElement[]} */ (
|
|
484
|
-
Array.from(form.querySelectorAll(`[name="${name}
|
|
521
|
+
Array.from(form.querySelectorAll(`[name="${name}"]`))
|
|
485
522
|
);
|
|
486
523
|
|
|
487
524
|
if (DEV) {
|
|
@@ -502,7 +539,7 @@ export function form(id) {
|
|
|
502
539
|
}
|
|
503
540
|
}
|
|
504
541
|
|
|
505
|
-
set_nested_value(input,
|
|
542
|
+
set_nested_value(input, field, value);
|
|
506
543
|
} else if (is_file) {
|
|
507
544
|
if (DEV && element.multiple) {
|
|
508
545
|
throw new Error(
|
|
@@ -513,21 +550,19 @@ export function form(id) {
|
|
|
513
550
|
const file = /** @type {HTMLInputElement & { files: FileList }} */ (element).files[0];
|
|
514
551
|
|
|
515
552
|
if (file) {
|
|
516
|
-
set_nested_value(input,
|
|
553
|
+
set_nested_value(input, field, file);
|
|
517
554
|
} else {
|
|
518
|
-
set_nested_value(input,
|
|
555
|
+
set_nested_value(input, field, DELETE_KEY);
|
|
519
556
|
}
|
|
520
557
|
} else {
|
|
521
558
|
set_nested_value(
|
|
522
559
|
input,
|
|
523
|
-
|
|
560
|
+
field,
|
|
524
561
|
element.type === 'checkbox' && !element.checked ? null : element.value
|
|
525
562
|
);
|
|
526
563
|
}
|
|
527
564
|
|
|
528
|
-
name =
|
|
529
|
-
|
|
530
|
-
dirty[name] = true;
|
|
565
|
+
dirty[field.name] = true;
|
|
531
566
|
};
|
|
532
567
|
|
|
533
568
|
const handle_reset = async () => {
|
|
@@ -535,7 +570,7 @@ export function form(id) {
|
|
|
535
570
|
// the inputs are actually updated (so that it can be cancelled)
|
|
536
571
|
await tick();
|
|
537
572
|
|
|
538
|
-
input = convert_formdata(new FormData(form));
|
|
573
|
+
input = convert_formdata(action_id_without_key, new FormData(form));
|
|
539
574
|
raw_issues = [];
|
|
540
575
|
touched = {};
|
|
541
576
|
dirty = {};
|
|
@@ -545,15 +580,15 @@ export function form(id) {
|
|
|
545
580
|
|
|
546
581
|
/** @param {Event} e */
|
|
547
582
|
const handle_focusout = (e) => {
|
|
548
|
-
|
|
583
|
+
const name = /** @type {HTMLInputElement} */ (e.target).name;
|
|
549
584
|
if (!name) return;
|
|
550
585
|
|
|
551
|
-
|
|
586
|
+
const field = parse_form_key(action_id_without_key, name);
|
|
552
587
|
|
|
553
|
-
touched[name] = true;
|
|
588
|
+
touched[field.name] = true;
|
|
554
589
|
|
|
555
|
-
if (Object.hasOwn(dirty, name)) {
|
|
556
|
-
can_validate[name] = true;
|
|
590
|
+
if (Object.hasOwn(dirty, field.name)) {
|
|
591
|
+
can_validate[field.name] = true;
|
|
557
592
|
}
|
|
558
593
|
};
|
|
559
594
|
|
|
@@ -608,10 +643,10 @@ export function form(id) {
|
|
|
608
643
|
},
|
|
609
644
|
fields: {
|
|
610
645
|
get: () =>
|
|
611
|
-
create_field_proxy(
|
|
612
|
-
|
|
613
|
-
() => input,
|
|
614
|
-
(path, value) => {
|
|
646
|
+
create_field_proxy({
|
|
647
|
+
form_id: action_id_without_key,
|
|
648
|
+
get: () => input,
|
|
649
|
+
set: (path, value) => {
|
|
615
650
|
if (path.length === 0) {
|
|
616
651
|
input = value;
|
|
617
652
|
} else if (value !== deep_get(input, path)) {
|
|
@@ -626,7 +661,7 @@ export function form(id) {
|
|
|
626
661
|
}
|
|
627
662
|
}
|
|
628
663
|
},
|
|
629
|
-
(path, all) => {
|
|
664
|
+
get_issues: (path, all) => {
|
|
630
665
|
if (DEV && unread_issues !== null && path !== undefined) {
|
|
631
666
|
unread_issues = unread_issues.filter((issue) => {
|
|
632
667
|
return (
|
|
@@ -638,10 +673,9 @@ export function form(id) {
|
|
|
638
673
|
|
|
639
674
|
return issues;
|
|
640
675
|
},
|
|
641
|
-
() => touched,
|
|
642
|
-
() => dirty
|
|
643
|
-
|
|
644
|
-
)
|
|
676
|
+
get_touched: () => touched,
|
|
677
|
+
get_dirty: () => dirty
|
|
678
|
+
})
|
|
645
679
|
},
|
|
646
680
|
result: {
|
|
647
681
|
get: () => result
|
|
@@ -809,13 +843,3 @@ function validate_form_data(form_data, enctype) {
|
|
|
809
843
|
}
|
|
810
844
|
}
|
|
811
845
|
}
|
|
812
|
-
|
|
813
|
-
/**
|
|
814
|
-
* Remove the `n:` or `b:` prefix from a field name
|
|
815
|
-
* @template {string | null} T
|
|
816
|
-
* @param {T} name
|
|
817
|
-
* @returns {T}
|
|
818
|
-
*/
|
|
819
|
-
function strip_prefix(name) {
|
|
820
|
-
return /** @type {T} */ (name && name.replace(/^[nb]:/, ''));
|
|
821
|
-
}
|
|
@@ -172,7 +172,7 @@ class Prerender {
|
|
|
172
172
|
});
|
|
173
173
|
this.#loading = false;
|
|
174
174
|
this.#error = error;
|
|
175
|
-
throw new HttpError(error
|
|
175
|
+
throw new HttpError(error); // so that transformError doesn't transform it again
|
|
176
176
|
}
|
|
177
177
|
);
|
|
178
178
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { RemoteQueryFunction } from '@sveltejs/kit' */
|
|
2
2
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
3
3
|
import { _goto, query_map } from '../../client.js';
|
|
4
|
-
import {
|
|
4
|
+
import { QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
|
|
5
5
|
import { DEV } from 'esm-env';
|
|
6
6
|
import { QueryProxy } from './proxy.js';
|
|
7
7
|
|
|
@@ -26,7 +26,7 @@ export function query(id) {
|
|
|
26
26
|
return new QueryProxy(id, arg, async (payload) => {
|
|
27
27
|
const url = `${base}/${app_dir}/remote/${id}${payload ? `?payload=${payload}` : ''}`;
|
|
28
28
|
|
|
29
|
-
const result = await remote_request(url
|
|
29
|
+
const result = await remote_request(url);
|
|
30
30
|
|
|
31
31
|
if (result.redirect) {
|
|
32
32
|
// Use internal version to allow redirects to external URLs
|
|
@@ -70,7 +70,7 @@ export class Query {
|
|
|
70
70
|
delete query_responses[key];
|
|
71
71
|
|
|
72
72
|
if (node.e) {
|
|
73
|
-
this.fail(new HttpError(node.e
|
|
73
|
+
this.fail(new HttpError(node.e));
|
|
74
74
|
} else {
|
|
75
75
|
this.set(/** @type {T} */ (node.v));
|
|
76
76
|
}
|
|
@@ -152,7 +152,7 @@ export class Query {
|
|
|
152
152
|
this.#loading = false;
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
reject(new HttpError(error
|
|
155
|
+
reject(new HttpError(error)); // so that transformError doesn't transform it again
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
return promise;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { RemoteQueryFunction } from '@sveltejs/kit' */
|
|
2
2
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
3
3
|
import { _goto } from '../client.js';
|
|
4
|
-
import {
|
|
4
|
+
import { QUERY_FUNCTION_ID, remote_request } from './shared.svelte.js';
|
|
5
5
|
import { QueryProxy } from './query/proxy.js';
|
|
6
6
|
import { HttpError } from '@sveltejs/kit/internal';
|
|
7
7
|
|
|
@@ -30,8 +30,7 @@ export function query_batch(id) {
|
|
|
30
30
|
// but in different forks/async contexts and in the same macrotask?
|
|
31
31
|
// If so this would potentially be buggy
|
|
32
32
|
const headers = {
|
|
33
|
-
'Content-Type': 'application/json'
|
|
34
|
-
...get_remote_request_headers()
|
|
33
|
+
'Content-Type': 'application/json'
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
// Wait for the next macrotask - don't use microtask as Svelte runtime uses these to collect changes and flush them,
|
|
@@ -72,7 +71,7 @@ export function query_batch(id) {
|
|
|
72
71
|
|
|
73
72
|
for (const { resolve, reject } of resolvers) {
|
|
74
73
|
if (result.type === 'error') {
|
|
75
|
-
reject(new HttpError(result.error
|
|
74
|
+
reject(new HttpError(result.error));
|
|
76
75
|
} else {
|
|
77
76
|
resolve(result.data);
|
|
78
77
|
}
|
|
@@ -91,7 +91,7 @@ export class LiveQuery {
|
|
|
91
91
|
// the query failed during SSR — seed the failed state (mirroring `fail()`,
|
|
92
92
|
// minus its terminal `#done`), so the main loop still connects as usual
|
|
93
93
|
// and the query can recover
|
|
94
|
-
const error = new HttpError(node.e
|
|
94
|
+
const error = new HttpError(node.e);
|
|
95
95
|
this.#loading = false;
|
|
96
96
|
this.#error = error.body;
|
|
97
97
|
|
|
@@ -417,7 +417,7 @@ export class LiveQuery {
|
|
|
417
417
|
route: { id: null },
|
|
418
418
|
url: new URL(location.href)
|
|
419
419
|
});
|
|
420
|
-
this.fail(new HttpError(error
|
|
420
|
+
this.fail(new HttpError(error));
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
get [Symbol.toStringTag]() {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
/** @import { RemoteFunctionResponse } from 'types' */
|
|
1
2
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
2
3
|
import { app } from '../../client.js';
|
|
3
|
-
import {
|
|
4
|
+
import { notify_version } from '../../state.svelte.js';
|
|
5
|
+
import { handle_side_channel_response } from '../shared.svelte.js';
|
|
4
6
|
import * as devalue from 'devalue';
|
|
5
7
|
import { HttpError } from '@sveltejs/kit/internal';
|
|
6
8
|
import { noop } from '../../../../utils/functions.js';
|
|
@@ -23,25 +25,28 @@ export async function* create_live_iterator(
|
|
|
23
25
|
const url = `${base}/${app_dir}/remote/${id}${payload ? `?payload=${payload}` : ''}`;
|
|
24
26
|
|
|
25
27
|
const response = await fetch(url, {
|
|
26
|
-
headers: get_remote_request_headers(),
|
|
27
28
|
signal: controller.signal
|
|
28
29
|
});
|
|
29
30
|
|
|
31
|
+
// detect new deployments from the response header
|
|
32
|
+
notify_version(response.headers.get('x-sveltekit-version'));
|
|
33
|
+
|
|
30
34
|
if (!response.ok) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
status: response.status,
|
|
34
|
-
error: response.statusText
|
|
35
|
-
}));
|
|
35
|
+
/** @type {RemoteFunctionResponse | undefined} */
|
|
36
|
+
const result = await response.json().catch(() => undefined);
|
|
36
37
|
|
|
37
|
-
throw new HttpError(
|
|
38
|
+
throw new HttpError(
|
|
39
|
+
result?.type === 'error'
|
|
40
|
+
? result.error
|
|
41
|
+
: { status: response.status, message: response.statusText }
|
|
42
|
+
);
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
if (response.headers.get('content-type')?.includes('application/json')) {
|
|
41
46
|
// we can end up here if we e.g. redirect in `handle`
|
|
42
47
|
const result = await response.json();
|
|
43
48
|
await handle_side_channel_response(result);
|
|
44
|
-
throw new HttpError(500, 'Invalid query.live response');
|
|
49
|
+
throw new HttpError({ status: 500, message: 'Invalid query.live response' });
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
if (!response.body) {
|
|
@@ -60,7 +65,7 @@ export async function* create_live_iterator(
|
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
await handle_side_channel_response(node);
|
|
63
|
-
throw new HttpError(500, 'Invalid query.live response');
|
|
68
|
+
throw new HttpError({ status: 500, message: 'Invalid query.live response' });
|
|
64
69
|
}
|
|
65
70
|
} finally {
|
|
66
71
|
try {
|
|
@@ -6,7 +6,7 @@ import { app, _goto, live_query_map, query_map, query_responses } from '../clien
|
|
|
6
6
|
import { HttpError, Redirect } from '@sveltejs/kit/internal';
|
|
7
7
|
import { untrack } from 'svelte';
|
|
8
8
|
import { create_remote_key, split_remote_key } from '../../shared.js';
|
|
9
|
-
import { navigating, page } from '../state.svelte.js';
|
|
9
|
+
import { navigating, page, notify_version } from '../state.svelte.js';
|
|
10
10
|
|
|
11
11
|
/** Indicates a query function, as opposed to a query instance */
|
|
12
12
|
export const QUERY_FUNCTION_ID = Symbol('sveltekit.query_function_id');
|
|
@@ -86,7 +86,7 @@ export function pin_while_resolving(cache_map, cache, id, payload, then) {
|
|
|
86
86
|
*/
|
|
87
87
|
export function unwrap_node(node) {
|
|
88
88
|
if (node.e) {
|
|
89
|
-
throw new HttpError(node.e
|
|
89
|
+
throw new HttpError(node.e);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
return node.v;
|
|
@@ -112,24 +112,28 @@ export function get_remote_request_headers() {
|
|
|
112
112
|
*/
|
|
113
113
|
export async function remote_request(url, init) {
|
|
114
114
|
const response = await fetch(url, init);
|
|
115
|
+
const status = response.status;
|
|
116
|
+
|
|
117
|
+
// detect new deployments from the response header
|
|
118
|
+
notify_version(response.headers.get('x-sveltekit-version'));
|
|
115
119
|
|
|
116
120
|
if (!response.ok) {
|
|
117
121
|
const result = await response.json().catch(() => ({
|
|
118
122
|
type: 'error',
|
|
119
|
-
status
|
|
120
|
-
error:
|
|
123
|
+
status,
|
|
124
|
+
error: {
|
|
125
|
+
status,
|
|
126
|
+
message: response.statusText
|
|
127
|
+
}
|
|
121
128
|
}));
|
|
122
129
|
|
|
123
|
-
throw new HttpError(
|
|
124
|
-
result.error?.status ?? result.status ?? response.status ?? 500,
|
|
125
|
-
result.error
|
|
126
|
-
);
|
|
130
|
+
throw new HttpError({ status, ...result.error });
|
|
127
131
|
}
|
|
128
132
|
|
|
129
133
|
const result = /** @type {RemoteFunctionResponse} */ (await response.json());
|
|
130
134
|
|
|
131
135
|
if (result.type === 'error') {
|
|
132
|
-
throw new HttpError(result.error
|
|
136
|
+
throw new HttpError(result.error);
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
const data = /** @type {RemoteFunctionData} */ (
|
|
@@ -144,7 +148,7 @@ export async function remote_request(url, init) {
|
|
|
144
148
|
function refresh(key, entry, result) {
|
|
145
149
|
if (entry?.resource) {
|
|
146
150
|
if (result.e) {
|
|
147
|
-
entry.resource.fail(new HttpError(result.e
|
|
151
|
+
entry.resource.fail(new HttpError(result.e));
|
|
148
152
|
} else {
|
|
149
153
|
entry.resource.set(result.v);
|
|
150
154
|
}
|
|
@@ -198,7 +202,7 @@ export async function handle_side_channel_response(response) {
|
|
|
198
202
|
}
|
|
199
203
|
|
|
200
204
|
if (response.type === 'error') {
|
|
201
|
-
throw new HttpError(response.error
|
|
205
|
+
throw new HttpError(response.error);
|
|
202
206
|
}
|
|
203
207
|
|
|
204
208
|
return response;
|