@sveltejs/kit 3.0.0-next.6 → 3.0.0-next.7
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 +7 -2
- package/src/core/adapt/builder.js +11 -39
- package/src/core/config/index.js +76 -71
- package/src/core/config/options.js +280 -285
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +85 -1
- package/src/core/generate_manifest/index.js +12 -15
- package/src/core/sync/create_manifest_data/index.js +6 -44
- package/src/core/sync/write_client_manifest.js +7 -14
- package/src/core/sync/write_non_ambient.js +10 -7
- package/src/core/sync/write_root.js +9 -30
- package/src/core/sync/write_server.js +0 -1
- package/src/core/sync/write_types/index.js +11 -10
- package/src/exports/index.js +3 -3
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/index.js +1 -91
- package/src/exports/internal/{event.js → server/event.js} +1 -2
- package/src/exports/internal/server/index.js +33 -0
- package/src/exports/internal/shared.js +89 -0
- package/src/exports/node/index.js +1 -1
- package/src/exports/params.js +63 -0
- package/src/exports/public.d.ts +82 -32
- package/src/exports/url.js +84 -0
- package/src/exports/vite/dev/index.js +28 -17
- package/src/exports/vite/index.js +217 -156
- package/src/exports/vite/preview/index.js +1 -1
- package/src/exports/vite/utils.js +3 -5
- package/src/runtime/app/paths/client.js +3 -7
- package/src/runtime/app/paths/server.js +1 -1
- package/src/runtime/app/server/remote/query.js +6 -12
- package/src/runtime/app/state/client.js +1 -2
- package/src/runtime/app/stores.js +13 -76
- package/src/runtime/client/client.js +26 -79
- package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
- package/src/runtime/client/remote-functions/form.svelte.js +5 -24
- package/src/runtime/client/remote-functions/prerender.svelte.js +10 -3
- package/src/runtime/client/remote-functions/query/instance.svelte.js +18 -9
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +16 -6
- package/src/runtime/client/remote-functions/shared.svelte.js +1 -2
- package/src/runtime/client/state.svelte.js +66 -49
- package/src/runtime/client/types.d.ts +1 -1
- package/src/runtime/client/utils.js +0 -96
- package/src/runtime/form-utils.js +15 -2
- package/src/runtime/server/index.js +1 -1
- package/src/runtime/server/page/load_data.js +1 -1
- package/src/runtime/server/page/render.js +15 -24
- package/src/runtime/server/page/server_routing.js +13 -9
- package/src/runtime/server/remote.js +21 -12
- package/src/runtime/server/respond.js +11 -8
- package/src/runtime/telemetry/otel.js +1 -1
- package/src/types/ambient.d.ts +5 -1
- package/src/types/global-private.d.ts +1 -1
- package/src/types/internal.d.ts +9 -10
- package/src/utils/error.js +1 -1
- package/src/utils/mime.js +9 -0
- package/src/utils/params.js +66 -0
- package/src/utils/routing.js +84 -38
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +0 -79
- package/src/version.js +1 -1
- package/types/index.d.ts +98 -87
- package/types/index.d.ts.map +10 -7
- package/src/exports/internal/server.js +0 -22
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
|
@@ -411,20 +411,14 @@ export function refresh(event, state, internals, payload, fn) {
|
|
|
411
411
|
|
|
412
412
|
const key = create_remote_key(internals.id, payload);
|
|
413
413
|
|
|
414
|
-
// `fn
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
//
|
|
419
|
-
// unhandled promise rejection (which crashes the process on modern Node).
|
|
420
|
-
// We still store the original promise so `collect_remote_data` can serialize
|
|
421
|
-
// either its value or its error as before.
|
|
422
|
-
const promise = fn();
|
|
423
|
-
promise.catch(() => {});
|
|
424
|
-
|
|
414
|
+
// `fn` is stored rather than invoked eagerly. The query is run at the end of
|
|
415
|
+
// the command/form (in `collect_remote_data`), so that it observes any state
|
|
416
|
+
// mutations that happen after `refresh()` is called. If the developer re-awaits
|
|
417
|
+
// the query before the command finishes, the cache entry created by that await
|
|
418
|
+
// is reused instead of re-running the query.
|
|
425
419
|
(state.remote.explicit ??= new Map()).set(key, {
|
|
426
420
|
internals,
|
|
427
|
-
|
|
421
|
+
fn
|
|
428
422
|
});
|
|
429
423
|
}
|
|
430
424
|
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
navigating as _navigating,
|
|
4
4
|
updated as _updated
|
|
5
5
|
} from '../../client/state.svelte.js';
|
|
6
|
-
import { stores } from '../../client/client.js';
|
|
7
6
|
|
|
8
7
|
export const page = {
|
|
9
8
|
get data() {
|
|
@@ -57,5 +56,5 @@ export const updated = {
|
|
|
57
56
|
get current() {
|
|
58
57
|
return _updated.current;
|
|
59
58
|
},
|
|
60
|
-
check:
|
|
59
|
+
check: _updated.check
|
|
61
60
|
};
|
|
@@ -1,101 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// TODO: remove this file when enough people have migrated to Kit 3
|
|
2
|
+
|
|
3
|
+
/** @returns {never} */
|
|
4
|
+
function removed() {
|
|
5
|
+
throw new Error(
|
|
6
|
+
'`$app/stores` has been removed in favour of `$app/state`. See https://svelte.dev/docs/kit/migrating-to-sveltekit-2#SvelteKit-2.12:-$app-stores-deprecated'
|
|
7
|
+
);
|
|
8
|
+
}
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
|
-
* A function that returns all of the contextual stores. On the server, this must be called during component initialization.
|
|
7
|
-
* Only use this if you need to defer store subscription until after the component has mounted, for some reason.
|
|
8
|
-
*
|
|
9
11
|
* @deprecated Use `$app/state` instead (requires Svelte 5, [see docs for more info](https://svelte.dev/docs/kit/migrating-to-sveltekit-2#SvelteKit-2.12:-$app-stores-deprecated))
|
|
10
12
|
*/
|
|
11
|
-
export const getStores =
|
|
12
|
-
const stores = BROWSER ? browser_stores : getContext('__svelte__');
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
/** @type {typeof page} */
|
|
16
|
-
page: {
|
|
17
|
-
subscribe: stores.page.subscribe
|
|
18
|
-
},
|
|
19
|
-
/** @type {typeof navigating} */
|
|
20
|
-
navigating: {
|
|
21
|
-
subscribe: stores.navigating.subscribe
|
|
22
|
-
},
|
|
23
|
-
/** @type {typeof updated} */
|
|
24
|
-
updated: stores.updated
|
|
25
|
-
};
|
|
26
|
-
};
|
|
13
|
+
export const getStores = removed;
|
|
27
14
|
|
|
28
15
|
/**
|
|
29
|
-
* A readable store whose value contains page data.
|
|
30
|
-
*
|
|
31
|
-
* On the server, this store can only be subscribed to during component initialization. In the browser, it can be subscribed to at any time.
|
|
32
|
-
*
|
|
33
16
|
* @deprecated Use `page` from `$app/state` instead (requires Svelte 5, [see docs for more info](https://svelte.dev/docs/kit/migrating-to-sveltekit-2#SvelteKit-2.12:-$app-stores-deprecated))
|
|
34
17
|
* @type {import('svelte/store').Readable<import('@sveltejs/kit').Page>}
|
|
35
18
|
*/
|
|
36
19
|
export const page = {
|
|
37
|
-
subscribe
|
|
38
|
-
const store = DEV ? get_store('page') : getStores().page;
|
|
39
|
-
return store.subscribe(fn);
|
|
40
|
-
}
|
|
20
|
+
subscribe: removed
|
|
41
21
|
};
|
|
42
22
|
|
|
43
23
|
/**
|
|
44
|
-
* A readable store.
|
|
45
|
-
* When navigating starts, its value is a `Navigation` object with `from`, `to`, `type` and (if `type === 'popstate'`) `delta` properties.
|
|
46
|
-
* When navigating finishes, its value reverts to `null`.
|
|
47
|
-
*
|
|
48
|
-
* On the server, this store can only be subscribed to during component initialization. In the browser, it can be subscribed to at any time.
|
|
49
|
-
*
|
|
50
24
|
* @deprecated Use `navigating` from `$app/state` instead (requires Svelte 5, [see docs for more info](https://svelte.dev/docs/kit/migrating-to-sveltekit-2#SvelteKit-2.12:-$app-stores-deprecated))
|
|
51
25
|
* @type {import('svelte/store').Readable<import('@sveltejs/kit').Navigation | null>}
|
|
52
26
|
*/
|
|
53
27
|
export const navigating = {
|
|
54
|
-
subscribe
|
|
55
|
-
const store = DEV ? get_store('navigating') : getStores().navigating;
|
|
56
|
-
return store.subscribe(fn);
|
|
57
|
-
}
|
|
28
|
+
subscribe: removed
|
|
58
29
|
};
|
|
59
30
|
|
|
60
31
|
/**
|
|
61
|
-
* A readable store whose initial value is `false`. If [`version.pollInterval`](https://svelte.dev/docs/kit/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.
|
|
62
|
-
*
|
|
63
|
-
* On the server, this store can only be subscribed to during component initialization. In the browser, it can be subscribed to at any time.
|
|
64
|
-
*
|
|
65
32
|
* @deprecated Use `updated` from `$app/state` instead (requires Svelte 5, [see docs for more info](https://svelte.dev/docs/kit/migrating-to-sveltekit-2#SvelteKit-2.12:-$app-stores-deprecated))
|
|
66
33
|
* @type {import('svelte/store').Readable<boolean> & { check(): Promise<boolean> }}
|
|
67
34
|
*/
|
|
68
35
|
export const updated = {
|
|
69
|
-
subscribe
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (BROWSER) {
|
|
73
|
-
updated.check = store.check;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return store.subscribe(fn);
|
|
77
|
-
},
|
|
78
|
-
check: () => {
|
|
79
|
-
throw new Error(
|
|
80
|
-
BROWSER
|
|
81
|
-
? 'Cannot check updated store before subscribing'
|
|
82
|
-
: 'Can only check updated store in browser'
|
|
83
|
-
);
|
|
84
|
-
}
|
|
36
|
+
subscribe: removed,
|
|
37
|
+
check: removed
|
|
85
38
|
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* @template {keyof ReturnType<typeof getStores>} Name
|
|
89
|
-
* @param {Name} name
|
|
90
|
-
* @returns {ReturnType<typeof getStores>[Name]}
|
|
91
|
-
*/
|
|
92
|
-
function get_store(name) {
|
|
93
|
-
try {
|
|
94
|
-
return getStores()[name];
|
|
95
|
-
} catch {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`Cannot subscribe to '${name}' store on the server outside of a Svelte component, as it is bound to the current request via component context. This prevents state from leaking between users.` +
|
|
98
|
-
'For more information, see https://svelte.dev/docs/kit/state-management#avoid-shared-state-on-the-server'
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
@@ -6,16 +6,7 @@
|
|
|
6
6
|
import { BROWSER, DEV } from 'esm-env';
|
|
7
7
|
import * as svelte from 'svelte';
|
|
8
8
|
import { HttpError, Redirect, SvelteKitError } from '@sveltejs/kit/internal';
|
|
9
|
-
|
|
10
|
-
// Svelte 4 and under don't have `untrack`, so we have to fallback if `untrack` is not exported
|
|
11
|
-
const untrack = svelte.untrack ?? ((value) => value());
|
|
12
|
-
import {
|
|
13
|
-
decode_params,
|
|
14
|
-
decode_pathname,
|
|
15
|
-
strip_hash,
|
|
16
|
-
make_trackable,
|
|
17
|
-
normalize_path
|
|
18
|
-
} from '../../utils/url.js';
|
|
9
|
+
import { decode_pathname, strip_hash, make_trackable, normalize_path } from '../../utils/url.js';
|
|
19
10
|
import { dev_fetch, initial_fetch, lock_fetch, subsequent_fetch, unlock_fetch } from './fetcher.js';
|
|
20
11
|
import { parse, parse_server_route } from './parse.js';
|
|
21
12
|
import * as storage from './session-storage.js';
|
|
@@ -27,8 +18,6 @@ import {
|
|
|
27
18
|
is_external_url,
|
|
28
19
|
origin,
|
|
29
20
|
scroll_state,
|
|
30
|
-
notifiable_store,
|
|
31
|
-
create_updated_store,
|
|
32
21
|
load_css
|
|
33
22
|
} from './utils.js';
|
|
34
23
|
import { base } from '$app/paths/internal/client';
|
|
@@ -53,8 +42,7 @@ import {
|
|
|
53
42
|
validate_load_response
|
|
54
43
|
} from '../shared.js';
|
|
55
44
|
import { get_message, get_status } from '../../utils/error.js';
|
|
56
|
-
import {
|
|
57
|
-
import { page, update, navigating } from './state.svelte.js';
|
|
45
|
+
import { page, update, navigating, updated } from './state.svelte.js';
|
|
58
46
|
import { add_data_suffix, add_resolution_suffix } from '../pathname.js';
|
|
59
47
|
import { noop_span } from '../telemetry/noop.js';
|
|
60
48
|
import { read_ndjson } from './ndjson.js';
|
|
@@ -127,15 +115,6 @@ if (DEV && BROWSER) {
|
|
|
127
115
|
};
|
|
128
116
|
}
|
|
129
117
|
|
|
130
|
-
export const stores = {
|
|
131
|
-
url: /* @__PURE__ */ notifiable_store({}),
|
|
132
|
-
page: /* @__PURE__ */ notifiable_store({}),
|
|
133
|
-
navigating: /* @__PURE__ */ writable(
|
|
134
|
-
/** @type {import('@sveltejs/kit').Navigation | null} */ (null)
|
|
135
|
-
),
|
|
136
|
-
updated: /* @__PURE__ */ create_updated_store()
|
|
137
|
-
};
|
|
138
|
-
|
|
139
118
|
/** @param {number} index */
|
|
140
119
|
function update_scroll_positions(index) {
|
|
141
120
|
scroll_positions[index] = scroll_state();
|
|
@@ -723,13 +702,14 @@ async function initialize(result, target, hydrate) {
|
|
|
723
702
|
|
|
724
703
|
update(/** @type {import('@sveltejs/kit').Page} */ (result.props.page));
|
|
725
704
|
|
|
705
|
+
// TODO: use mount()
|
|
726
706
|
root = new app.root({
|
|
727
707
|
target,
|
|
728
|
-
props: { ...result.props,
|
|
708
|
+
props: { ...result.props, components },
|
|
729
709
|
hydrate,
|
|
730
|
-
//
|
|
710
|
+
// Svelte 5 specific: asynchronously instantiate the component, i.e. don't call flushSync
|
|
731
711
|
sync: false,
|
|
732
|
-
//
|
|
712
|
+
// Svelte 5 specific: transformError allows to transform errors before they are passed to boundaries
|
|
733
713
|
transformError: __SVELTEKIT_EXPERIMENTAL_USE_TRANSFORM_ERROR__
|
|
734
714
|
? /** @param {unknown} e */ async (e) => {
|
|
735
715
|
const error = await handle_error(e, current.nav);
|
|
@@ -817,9 +797,8 @@ async function get_navigation_result_from_branch({
|
|
|
817
797
|
route
|
|
818
798
|
},
|
|
819
799
|
props: {
|
|
820
|
-
// @ts-ignore Somehow it's getting SvelteComponent and SvelteComponentDev mixed up
|
|
821
800
|
constructors: compact(branch).map((branch_node) => branch_node.node.component),
|
|
822
|
-
page
|
|
801
|
+
page
|
|
823
802
|
}
|
|
824
803
|
};
|
|
825
804
|
|
|
@@ -1177,10 +1156,6 @@ function diff_search_params(old_url, new_url) {
|
|
|
1177
1156
|
* @returns {import('./types.js').NavigationFinished}
|
|
1178
1157
|
*/
|
|
1179
1158
|
function preload_error({ error, url, route, params }) {
|
|
1180
|
-
// we skipped loading the error page, so we need to use the current page
|
|
1181
|
-
// store, but we still pass the updated status to the preloadData function
|
|
1182
|
-
const new_page = clone_page(page);
|
|
1183
|
-
new_page.status = error.status;
|
|
1184
1159
|
return {
|
|
1185
1160
|
type: 'loaded',
|
|
1186
1161
|
state: {
|
|
@@ -1191,7 +1166,12 @@ function preload_error({ error, url, route, params }) {
|
|
|
1191
1166
|
branch: []
|
|
1192
1167
|
},
|
|
1193
1168
|
props: {
|
|
1194
|
-
page:
|
|
1169
|
+
page: {
|
|
1170
|
+
// we skipped loading the error page, so we have to use the current page
|
|
1171
|
+
// store, but update the status received while preloading
|
|
1172
|
+
...page,
|
|
1173
|
+
status: error.status
|
|
1174
|
+
},
|
|
1195
1175
|
constructors: []
|
|
1196
1176
|
}
|
|
1197
1177
|
};
|
|
@@ -1377,8 +1357,7 @@ async function load_route({ id, invalidating, url, params, route, preload }) {
|
|
|
1377
1357
|
error = err.body;
|
|
1378
1358
|
} else {
|
|
1379
1359
|
// Referenced node could have been removed due to redeploy, check
|
|
1380
|
-
|
|
1381
|
-
if (updated) {
|
|
1360
|
+
if (await updated.check()) {
|
|
1382
1361
|
// Before reloading, try to update the service worker if it exists
|
|
1383
1362
|
await update_service_worker();
|
|
1384
1363
|
return await native_navigation(url);
|
|
@@ -1631,7 +1610,7 @@ export async function get_navigation_intent(url, invalidating) {
|
|
|
1631
1610
|
id: get_page_key(url),
|
|
1632
1611
|
invalidating,
|
|
1633
1612
|
route,
|
|
1634
|
-
params
|
|
1613
|
+
params,
|
|
1635
1614
|
url
|
|
1636
1615
|
};
|
|
1637
1616
|
}
|
|
@@ -1780,7 +1759,7 @@ async function navigate({
|
|
|
1780
1759
|
is_navigating = true;
|
|
1781
1760
|
|
|
1782
1761
|
if (started && nav.navigation.type !== 'enter') {
|
|
1783
|
-
|
|
1762
|
+
navigating.current = nav.navigation;
|
|
1784
1763
|
}
|
|
1785
1764
|
|
|
1786
1765
|
let navigation_result = intent && (await load_route(intent));
|
|
@@ -1867,8 +1846,7 @@ async function navigate({
|
|
|
1867
1846
|
|
|
1868
1847
|
if (!navigation_result) return;
|
|
1869
1848
|
} else if (/** @type {number} */ (navigation_result.props.page.status) >= 400) {
|
|
1870
|
-
|
|
1871
|
-
if (updated) {
|
|
1849
|
+
if (await updated.check()) {
|
|
1872
1850
|
// Before reloading, try to update the service worker if it exists
|
|
1873
1851
|
await update_service_worker();
|
|
1874
1852
|
return await native_navigation(url, replace_state);
|
|
@@ -1999,13 +1977,7 @@ async function navigate({
|
|
|
1999
1977
|
|
|
2000
1978
|
const { activeElement } = document;
|
|
2001
1979
|
|
|
2002
|
-
await commit_promise;
|
|
2003
|
-
|
|
2004
|
-
// TODO 3.0 remote — the double tick is probably necessary because
|
|
2005
|
-
// of some store shenanigans. `settled()` and `f.commit()`
|
|
2006
|
-
// should resolve after DOM updates in newer versions
|
|
2007
|
-
await svelte.tick();
|
|
2008
|
-
await svelte.tick();
|
|
1980
|
+
await (commit_promise ?? svelte.tick());
|
|
2009
1981
|
|
|
2010
1982
|
if (navigation_token !== nav_token) {
|
|
2011
1983
|
// a new navigation happened while we were waiting for the DOM to update, so abort
|
|
@@ -2069,7 +2041,7 @@ async function navigate({
|
|
|
2069
2041
|
restore_snapshot(current_navigation_index);
|
|
2070
2042
|
}
|
|
2071
2043
|
|
|
2072
|
-
|
|
2044
|
+
navigating.current = null;
|
|
2073
2045
|
|
|
2074
2046
|
updating = false;
|
|
2075
2047
|
}
|
|
@@ -2257,7 +2229,7 @@ export async function handle_error(error, event) {
|
|
|
2257
2229
|
* @param {T} callback
|
|
2258
2230
|
*/
|
|
2259
2231
|
function add_navigation_callback(callbacks, callback) {
|
|
2260
|
-
onMount(() => {
|
|
2232
|
+
svelte.onMount(() => {
|
|
2261
2233
|
callbacks.add(callback);
|
|
2262
2234
|
|
|
2263
2235
|
return () => {
|
|
@@ -2573,8 +2545,7 @@ export function pushState(url, state) {
|
|
|
2573
2545
|
|
|
2574
2546
|
page.state = state;
|
|
2575
2547
|
root.$set({
|
|
2576
|
-
|
|
2577
|
-
page: untrack(() => clone_page(page))
|
|
2548
|
+
page
|
|
2578
2549
|
});
|
|
2579
2550
|
|
|
2580
2551
|
clear_onward_history(current_history_index, current_navigation_index);
|
|
@@ -2617,7 +2588,7 @@ export function replaceState(url, state) {
|
|
|
2617
2588
|
|
|
2618
2589
|
page.state = state;
|
|
2619
2590
|
root.$set({
|
|
2620
|
-
page
|
|
2591
|
+
page
|
|
2621
2592
|
});
|
|
2622
2593
|
}
|
|
2623
2594
|
|
|
@@ -2647,11 +2618,11 @@ export async function applyAction(result) {
|
|
|
2647
2618
|
// this brings Svelte's view of the world in line with SvelteKit's
|
|
2648
2619
|
// after use:enhance reset the form....
|
|
2649
2620
|
form: null,
|
|
2650
|
-
page
|
|
2621
|
+
page
|
|
2651
2622
|
});
|
|
2652
2623
|
|
|
2653
2624
|
// ...so that setting the `form` prop takes effect and isn't ignored
|
|
2654
|
-
await tick();
|
|
2625
|
+
await svelte.tick();
|
|
2655
2626
|
root.$set({ form: result.data });
|
|
2656
2627
|
|
|
2657
2628
|
if (result.type === 'success') {
|
|
@@ -2685,7 +2656,7 @@ export async function set_nearest_error_page(error) {
|
|
|
2685
2656
|
root.$set(navigation_result.props);
|
|
2686
2657
|
update(navigation_result.props.page);
|
|
2687
2658
|
|
|
2688
|
-
void tick().then(() => reset_focus(current.url));
|
|
2659
|
+
void svelte.tick().then(() => reset_focus(current.url));
|
|
2689
2660
|
}
|
|
2690
2661
|
}
|
|
2691
2662
|
|
|
@@ -3010,7 +2981,7 @@ function _start_router() {
|
|
|
3010
2981
|
// the navigation away from it was successful.
|
|
3011
2982
|
// Info about bfcache here: https://web.dev/bfcache
|
|
3012
2983
|
if (event.persisted) {
|
|
3013
|
-
|
|
2984
|
+
navigating.current = null;
|
|
3014
2985
|
}
|
|
3015
2986
|
});
|
|
3016
2987
|
|
|
@@ -3019,8 +2990,6 @@ function _start_router() {
|
|
|
3019
2990
|
*/
|
|
3020
2991
|
function update_url(url) {
|
|
3021
2992
|
current.url = page.url = url;
|
|
3022
|
-
stores.page.set(clone_page(page));
|
|
3023
|
-
stores.page.notify();
|
|
3024
2993
|
}
|
|
3025
2994
|
}
|
|
3026
2995
|
|
|
@@ -3414,28 +3383,6 @@ function create_navigation(current, intent, url, type, target_scroll = null) {
|
|
|
3414
3383
|
};
|
|
3415
3384
|
}
|
|
3416
3385
|
|
|
3417
|
-
/**
|
|
3418
|
-
* TODO: remove this in 3.0 when the page store is also removed
|
|
3419
|
-
*
|
|
3420
|
-
* We need to assign a new page object so that subscribers are correctly notified.
|
|
3421
|
-
* However, spreading `{ ...page }` returns an empty object so we manually
|
|
3422
|
-
* assign to each property instead.
|
|
3423
|
-
*
|
|
3424
|
-
* @param {import('@sveltejs/kit').Page} page
|
|
3425
|
-
*/
|
|
3426
|
-
function clone_page(page) {
|
|
3427
|
-
return {
|
|
3428
|
-
data: page.data,
|
|
3429
|
-
error: page.error,
|
|
3430
|
-
form: page.form,
|
|
3431
|
-
params: page.params,
|
|
3432
|
-
route: page.route,
|
|
3433
|
-
state: page.state,
|
|
3434
|
-
status: page.status,
|
|
3435
|
-
url: page.url
|
|
3436
|
-
};
|
|
3437
|
-
}
|
|
3438
|
-
|
|
3439
3386
|
/**
|
|
3440
3387
|
* @param {URL} url
|
|
3441
3388
|
* @returns {URL}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
/** @import { Query } from './query/instance.svelte.js' */
|
|
2
|
+
/** @import { LiveQuery } from './query-live/instance.svelte.js' */
|
|
1
3
|
import { tick } from 'svelte';
|
|
2
4
|
import { once } from '../../../utils/functions.js';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
|
-
* @template R
|
|
7
|
+
* @template [R=Query<any> | LiveQuery<any>]
|
|
6
8
|
* @typedef {object} CacheEntry
|
|
7
9
|
* @property {number} proxy_count The number of live proxy instances referencing this
|
|
8
10
|
* entry. The entry is eligible for eviction when this hits zero.
|
|
@@ -23,8 +23,9 @@ import {
|
|
|
23
23
|
build_path_string,
|
|
24
24
|
normalize_issue,
|
|
25
25
|
serialize_binary_form,
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
deep_get,
|
|
27
|
+
DELETE_KEY,
|
|
28
|
+
BINARY_FORM_CONTENT_TYPE
|
|
28
29
|
} from '../../form-utils.js';
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -514,14 +515,7 @@ export function form(id) {
|
|
|
514
515
|
if (file) {
|
|
515
516
|
set_nested_value(input, name, file);
|
|
516
517
|
} else {
|
|
517
|
-
|
|
518
|
-
const path_parts = name.split(/\.|\[|\]/).filter(Boolean);
|
|
519
|
-
let current = /** @type {any} */ (input);
|
|
520
|
-
for (let i = 0; i < path_parts.length - 1; i++) {
|
|
521
|
-
if (current[path_parts[i]] == null) return;
|
|
522
|
-
current = current[path_parts[i]];
|
|
523
|
-
}
|
|
524
|
-
delete current[path_parts[path_parts.length - 1]];
|
|
518
|
+
set_nested_value(input, name, DELETE_KEY);
|
|
525
519
|
}
|
|
526
520
|
} else {
|
|
527
521
|
set_nested_value(
|
|
@@ -672,12 +666,7 @@ export function form(id) {
|
|
|
672
666
|
},
|
|
673
667
|
validate: {
|
|
674
668
|
/** @type {RemoteForm<any, any>['validate']} */
|
|
675
|
-
value: async ({
|
|
676
|
-
all = false,
|
|
677
|
-
preflightOnly = false,
|
|
678
|
-
// @ts-expect-error TODO remove this in 3.0
|
|
679
|
-
includeUntouched
|
|
680
|
-
} = {}) => {
|
|
669
|
+
value: async ({ all = false, preflightOnly = false } = {}) => {
|
|
681
670
|
if (!element) return;
|
|
682
671
|
|
|
683
672
|
const id = ++validate_id;
|
|
@@ -728,14 +717,6 @@ export function form(id) {
|
|
|
728
717
|
array = /** @type {InternalRemoteFormIssue[]} */ (result._);
|
|
729
718
|
}
|
|
730
719
|
|
|
731
|
-
if (includeUntouched !== undefined) {
|
|
732
|
-
console.warn(
|
|
733
|
-
`\`{ includeUntouched: ${includeUntouched} }\` has been replaced with \`{ all: ${includeUntouched} }\``
|
|
734
|
-
);
|
|
735
|
-
|
|
736
|
-
all = includeUntouched;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
720
|
if (!all && !submitted) {
|
|
740
721
|
array = array.filter((issue) => can_validate[issue.name]);
|
|
741
722
|
}
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
3
3
|
import { version } from '$app/env';
|
|
4
4
|
import * as devalue from 'devalue';
|
|
5
|
-
import { app, _goto, prerender_responses } from '../client.js';
|
|
5
|
+
import { app, _goto, handle_error, prerender_responses } from '../client.js';
|
|
6
6
|
import { get_remote_request_headers, remote_request, unwrap_node } from './shared.svelte.js';
|
|
7
7
|
import { create_remote_key, stringify_remote_arg } from '../../shared.js';
|
|
8
8
|
import { noop } from '../../../utils/functions.js';
|
|
9
|
+
import { HttpError } from '@sveltejs/kit/internal';
|
|
9
10
|
|
|
10
11
|
// Initialize Cache API for prerender functions
|
|
11
12
|
const CACHE_NAME = __SVELTEKIT_DEV__ ? `sveltekit:${Date.now()}` : `sveltekit:${version}`;
|
|
@@ -148,6 +149,7 @@ class Prerender {
|
|
|
148
149
|
/** @type {T | undefined} */
|
|
149
150
|
#current = $state.raw();
|
|
150
151
|
|
|
152
|
+
/** @type {App.Error | undefined} */
|
|
151
153
|
#error = $state.raw(undefined);
|
|
152
154
|
|
|
153
155
|
/**
|
|
@@ -162,10 +164,15 @@ class Prerender {
|
|
|
162
164
|
this.#error = undefined;
|
|
163
165
|
return value;
|
|
164
166
|
},
|
|
165
|
-
(
|
|
167
|
+
async (e) => {
|
|
168
|
+
const error = await handle_error(e, {
|
|
169
|
+
params: {},
|
|
170
|
+
route: { id: null },
|
|
171
|
+
url: new URL(location.href)
|
|
172
|
+
});
|
|
166
173
|
this.#loading = false;
|
|
167
174
|
this.#error = error;
|
|
168
|
-
throw error;
|
|
175
|
+
throw new HttpError(error.status, error); // so that transformError doesn't transform it again
|
|
169
176
|
}
|
|
170
177
|
);
|
|
171
178
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { query_responses } from '../../client.js';
|
|
1
|
+
import { query_responses, handle_error } from '../../client.js';
|
|
2
2
|
import { HttpError } from '@sveltejs/kit/internal';
|
|
3
3
|
import { QUERY_OVERRIDE_KEY } from '../shared.svelte.js';
|
|
4
4
|
import { noop } from '../../../../utils/functions.js';
|
|
@@ -37,7 +37,7 @@ export class Query {
|
|
|
37
37
|
return this.#overrides.reduce((v, r) => r(v), /** @type {T} */ (this.#raw));
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
/** @type {
|
|
40
|
+
/** @type {App.Error | undefined} */
|
|
41
41
|
#error = $state.raw(undefined);
|
|
42
42
|
|
|
43
43
|
/** @type {Promise<T>['then']} */
|
|
@@ -126,22 +126,33 @@ export class Query {
|
|
|
126
126
|
|
|
127
127
|
resolve(undefined);
|
|
128
128
|
})
|
|
129
|
-
.catch((e) => {
|
|
129
|
+
.catch(async (e) => {
|
|
130
130
|
// TODO: Our behavior here could be better:
|
|
131
131
|
// - We should not reject on redirects, but should hook into the router
|
|
132
132
|
// to ensure the query is properly refreshed before the navigation completes
|
|
133
133
|
// - Instead of failing on transport-level errors, we should probably do what
|
|
134
134
|
// LiveQuery does and preserve the last known good value and retry the connection
|
|
135
|
+
if (this.#latest.indexOf(resolve) === -1) return;
|
|
136
|
+
|
|
137
|
+
const error = await handle_error(e, {
|
|
138
|
+
params: {},
|
|
139
|
+
route: { id: null },
|
|
140
|
+
url: new URL(location.href)
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Re-check after the async `handle_error` gap: a later request may have
|
|
144
|
+
// resolved/rejected while we were awaiting and superseded this one, so
|
|
145
|
+
// recompute the index and bail out if this request is no longer current
|
|
135
146
|
const idx = this.#latest.indexOf(resolve);
|
|
136
147
|
if (idx === -1) return;
|
|
137
148
|
|
|
138
149
|
untrack(() => {
|
|
139
150
|
this.#latest.splice(0, idx).forEach((r) => r(undefined));
|
|
140
|
-
this.#error =
|
|
151
|
+
this.#error = error;
|
|
141
152
|
this.#loading = false;
|
|
142
153
|
});
|
|
143
154
|
|
|
144
|
-
reject(
|
|
155
|
+
reject(new HttpError(error.status, error)); // so that transformError doesn't transform it again
|
|
145
156
|
});
|
|
146
157
|
|
|
147
158
|
return promise;
|
|
@@ -229,9 +240,7 @@ export class Query {
|
|
|
229
240
|
this.#promise = Promise.resolve();
|
|
230
241
|
}
|
|
231
242
|
|
|
232
|
-
/**
|
|
233
|
-
* @param {unknown} error
|
|
234
|
-
*/
|
|
243
|
+
/** @param {HttpError} error */
|
|
235
244
|
fail(error) {
|
|
236
245
|
// normally consumed in the constructor, but make sure a leftover
|
|
237
246
|
// SSR record can never shadow the newly-set error
|
|
@@ -239,7 +248,7 @@ export class Query {
|
|
|
239
248
|
|
|
240
249
|
this.#clear_pending();
|
|
241
250
|
this.#loading = false;
|
|
242
|
-
this.#error = error;
|
|
251
|
+
this.#error = error.body;
|
|
243
252
|
|
|
244
253
|
const promise = Promise.reject(error);
|
|
245
254
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { query_responses } from '../../client.js';
|
|
1
|
+
import { query_responses, handle_error } from '../../client.js';
|
|
2
2
|
import { HttpError, Redirect } from '@sveltejs/kit/internal';
|
|
3
3
|
import { noop, once } from '../../../../utils/functions.js';
|
|
4
4
|
import { SharedIterator } from '../../../../utils/shared-iterator.js';
|
|
@@ -24,7 +24,7 @@ export class LiveQuery {
|
|
|
24
24
|
#done = $state(false);
|
|
25
25
|
/** @type {T | undefined} */
|
|
26
26
|
#raw = $state.raw();
|
|
27
|
-
/** @type {
|
|
27
|
+
/** @type {App.Error | undefined} */
|
|
28
28
|
#error = $state.raw(undefined);
|
|
29
29
|
/** @type {Promise<void>} */
|
|
30
30
|
#promise;
|
|
@@ -93,7 +93,7 @@ export class LiveQuery {
|
|
|
93
93
|
// and the query can recover
|
|
94
94
|
const error = new HttpError(node.e.status, node.e);
|
|
95
95
|
this.#loading = false;
|
|
96
|
-
this.#error = error;
|
|
96
|
+
this.#error = error.body;
|
|
97
97
|
|
|
98
98
|
promise.catch(noop);
|
|
99
99
|
this.#reject_first?.(error);
|
|
@@ -175,7 +175,7 @@ export class LiveQuery {
|
|
|
175
175
|
|
|
176
176
|
if (!this.#ready) {
|
|
177
177
|
// If we haven't successfully connected and received a value yet, surface the error
|
|
178
|
-
this
|
|
178
|
+
await this.#fail(error);
|
|
179
179
|
on_connect_failed(error);
|
|
180
180
|
break;
|
|
181
181
|
}
|
|
@@ -385,10 +385,10 @@ export class LiveQuery {
|
|
|
385
385
|
this.#fan_out.push(value);
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
-
/** @param {
|
|
388
|
+
/** @param {HttpError} error */
|
|
389
389
|
fail(error) {
|
|
390
390
|
this.#loading = false;
|
|
391
|
-
this.#error = error;
|
|
391
|
+
this.#error = error.body;
|
|
392
392
|
// `fail` is terminal — once a live query has hard-failed, the only way to start
|
|
393
393
|
// streaming again is via `reconnect()`. Mark it done and abort any in-flight
|
|
394
394
|
// request so that callers from outside the main loop (e.g. `apply_reconnections`)
|
|
@@ -410,6 +410,16 @@ export class LiveQuery {
|
|
|
410
410
|
this.#fan_out.fail(error);
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
+
/** @param {unknown} e */
|
|
414
|
+
async #fail(e) {
|
|
415
|
+
const error = await handle_error(e, {
|
|
416
|
+
params: {},
|
|
417
|
+
route: { id: null },
|
|
418
|
+
url: new URL(location.href)
|
|
419
|
+
});
|
|
420
|
+
this.fail(new HttpError(error.status, error));
|
|
421
|
+
}
|
|
422
|
+
|
|
413
423
|
get [Symbol.toStringTag]() {
|
|
414
424
|
return 'LiveQuery';
|
|
415
425
|
}
|
|
@@ -137,9 +137,8 @@ export async function remote_request(url, init) {
|
|
|
137
137
|
);
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
|
-
*
|
|
141
140
|
* @param {string} key
|
|
142
|
-
* @param {CacheEntry
|
|
141
|
+
* @param {CacheEntry | undefined} entry
|
|
143
142
|
* @param {any} result
|
|
144
143
|
*/
|
|
145
144
|
function refresh(key, entry, result) {
|