@sveltejs/kit 3.0.0-next.12 → 3.0.0-next.14
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 +11 -11
- package/src/cli.js +2 -2
- package/src/core/adapt/builder.js +8 -5
- package/src/core/generate_manifest/index.js +6 -0
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +2 -1
- package/src/core/postbuild/prerender.js +15 -6
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +33 -2
- package/src/core/sync/write_app_types.js +73 -29
- package/src/core/sync/write_tsconfig/index.js +15 -2
- package/src/core/sync/write_types/index.js +5 -2
- package/src/exports/index.js +23 -12
- package/src/exports/internal/shared.js +4 -12
- package/src/exports/node/index.js +2 -7
- package/src/exports/public.d.ts +61 -12
- package/src/exports/vite/build/remote.js +10 -12
- package/src/exports/vite/dev/index.js +32 -19
- package/src/exports/vite/index.js +162 -133
- package/src/exports/vite/utils.js +1 -7
- package/src/runtime/app/server/remote/form.js +9 -1
- package/src/runtime/app/server/remote/prerender.js +13 -9
- package/src/runtime/app/server/remote/query.js +0 -6
- package/src/runtime/app/server/remote/requested.js +4 -4
- package/src/runtime/app/state/client.js +3 -0
- package/src/runtime/app/state/index.js +2 -2
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/client/client.js +731 -342
- package/src/runtime/client/constants.js +2 -6
- package/src/runtime/client/fetcher.js +24 -25
- package/src/runtime/client/remote-functions/form.svelte.js +42 -14
- package/src/runtime/client/remote-functions/prerender.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query/index.js +1 -1
- package/src/runtime/client/remote-functions/query/instance.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-batch.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-live/iterator.js +10 -8
- package/src/runtime/client/remote-functions/query-live/proxy.js +0 -10
- package/src/runtime/client/remote-functions/shared.svelte.js +12 -11
- package/src/runtime/client/state.svelte.js +10 -22
- package/src/runtime/client/types.d.ts +1 -2
- package/src/runtime/client/utils.js +22 -14
- package/src/runtime/components/root.svelte +4 -14
- package/src/runtime/form-utils.js +4 -6
- package/src/runtime/pathname.js +37 -0
- package/src/runtime/props.svelte.js +71 -0
- package/src/runtime/server/fetch.js +9 -14
- package/src/runtime/server/index.js +10 -24
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +88 -104
- package/src/runtime/server/page/index.js +1 -2
- package/src/runtime/server/page/load_data.js +16 -33
- package/src/runtime/server/page/render.js +46 -25
- package/src/runtime/server/page/respond_with_error.js +1 -3
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +58 -9
- package/src/runtime/server/respond.js +20 -29
- package/src/runtime/server/state.js +43 -0
- package/src/runtime/shared.js +4 -2
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +2 -2
- package/src/types/ambient.d.ts +59 -8
- package/src/types/global-private.d.ts +1 -1
- package/src/types/internal.d.ts +4 -8
- package/src/types/private.d.ts +3 -12
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +2 -1
- package/src/utils/params.js +1 -1
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +52 -27
- package/src/utils/url.js +1 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +165 -66
- package/types/index.d.ts.map +2 -1
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/types.d.ts +0 -8
|
@@ -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,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BROWSER, DEV } from 'esm-env';
|
|
2
2
|
import { noop } from '../../utils/functions.js';
|
|
3
|
-
import {
|
|
3
|
+
import { hash_request } from '../../utils/hash.js';
|
|
4
4
|
import { base64_decode } from '../utils.js';
|
|
5
5
|
|
|
6
6
|
let loading = 0;
|
|
@@ -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,18 +165,14 @@ 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) {
|
|
165
|
-
|
|
166
|
-
const values = [];
|
|
167
|
-
|
|
168
|
-
if (opts.headers) {
|
|
169
|
-
values.push([...new Headers(opts.headers)].join(','));
|
|
170
|
-
}
|
|
168
|
+
const body = opts.body;
|
|
171
169
|
|
|
172
|
-
if (
|
|
173
|
-
|
|
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;
|
|
174
173
|
}
|
|
175
174
|
|
|
176
|
-
selector += `[data-hash="${
|
|
175
|
+
selector += `[data-hash="${hash_request(opts.headers, body)}"]`;
|
|
177
176
|
}
|
|
178
177
|
|
|
179
178
|
return selector;
|
|
@@ -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';
|
|
@@ -39,16 +40,22 @@ import {
|
|
|
39
40
|
* @returns {InternalRemoteFormIssue[]}
|
|
40
41
|
*/
|
|
41
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
|
+
|
|
42
45
|
const merged = [
|
|
43
|
-
...current_issues.filter(
|
|
44
|
-
(issue) => issue.server && !client_issues.some((i) => i.name === issue.name)
|
|
45
|
-
),
|
|
46
|
+
...current_issues.filter((issue) => issue.server && !client_names.has(issue.name)),
|
|
46
47
|
...client_issues
|
|
47
48
|
];
|
|
48
49
|
|
|
49
|
-
|
|
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
|
+
}
|
|
50
57
|
|
|
51
|
-
return merged.sort((a, b) =>
|
|
58
|
+
return merged.sort((a, b) => (positions.get(a.name) ?? -1) - (positions.get(b.name) ?? -1));
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
/**
|
|
@@ -69,7 +76,29 @@ export function form(id) {
|
|
|
69
76
|
function create_instance(key) {
|
|
70
77
|
const action_id_without_key = id;
|
|
71
78
|
const action_id = id + (key != undefined ? `/${JSON.stringify(key)}` : '');
|
|
72
|
-
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
|
+
}
|
|
73
102
|
|
|
74
103
|
// the output of a non-enhanced submission that resulted in this page —
|
|
75
104
|
// consume it so the form's state survives hydration (form outputs are
|
|
@@ -233,13 +262,9 @@ export function form(id) {
|
|
|
233
262
|
|
|
234
263
|
if (response.redirect) {
|
|
235
264
|
// Use internal version to allow redirects to external URLs
|
|
236
|
-
void _goto(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
refreshAll: should_refresh
|
|
240
|
-
},
|
|
241
|
-
0
|
|
242
|
-
);
|
|
265
|
+
void _goto(response.redirect, {
|
|
266
|
+
refreshAll: should_refresh
|
|
267
|
+
});
|
|
243
268
|
return true;
|
|
244
269
|
}
|
|
245
270
|
|
|
@@ -355,7 +380,10 @@ export function form(id) {
|
|
|
355
380
|
const instance = {};
|
|
356
381
|
|
|
357
382
|
instance.method = 'POST';
|
|
358
|
-
instance
|
|
383
|
+
Object.defineProperty(instance, 'action', {
|
|
384
|
+
get: get_action,
|
|
385
|
+
enumerable: true
|
|
386
|
+
});
|
|
359
387
|
|
|
360
388
|
instance[createAttachmentKey()] = (/** @type {HTMLFormElement} */ form) => {
|
|
361
389
|
if (element) {
|
|
@@ -100,7 +100,7 @@ export function prerender(id) {
|
|
|
100
100
|
|
|
101
101
|
if (result.redirect) {
|
|
102
102
|
// Use internal version to allow redirects to external URLs
|
|
103
|
-
void _goto(result.redirect
|
|
103
|
+
void _goto(result.redirect);
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -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
|
|
|
@@ -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;
|
|
@@ -50,7 +50,7 @@ export function query_batch(id) {
|
|
|
50
50
|
|
|
51
51
|
if (response.redirect) {
|
|
52
52
|
// Use internal version to allow redirects to external URLs
|
|
53
|
-
await _goto(response.redirect
|
|
53
|
+
await _goto(response.redirect);
|
|
54
54
|
|
|
55
55
|
// settle all batched promises (with `undefined`, like a redirect
|
|
56
56
|
// from a non-batched query) so that callers don't hang forever
|
|
@@ -71,7 +71,7 @@ export function query_batch(id) {
|
|
|
71
71
|
|
|
72
72
|
for (const { resolve, reject } of resolvers) {
|
|
73
73
|
if (result.type === 'error') {
|
|
74
|
-
reject(new HttpError(result.error
|
|
74
|
+
reject(new HttpError(result.error));
|
|
75
75
|
} else {
|
|
76
76
|
resolve(result.data);
|
|
77
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,3 +1,4 @@
|
|
|
1
|
+
/** @import { RemoteFunctionResponse } from 'types' */
|
|
1
2
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
2
3
|
import { app } from '../../client.js';
|
|
3
4
|
import { notify_version } from '../../state.svelte.js';
|
|
@@ -31,20 +32,21 @@ export async function* create_live_iterator(
|
|
|
31
32
|
notify_version(response.headers.get('x-sveltekit-version'));
|
|
32
33
|
|
|
33
34
|
if (!response.ok) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
status: response.status,
|
|
37
|
-
error: response.statusText
|
|
38
|
-
}));
|
|
35
|
+
/** @type {RemoteFunctionResponse | undefined} */
|
|
36
|
+
const result = await response.json().catch(() => undefined);
|
|
39
37
|
|
|
40
|
-
throw new HttpError(
|
|
38
|
+
throw new HttpError(
|
|
39
|
+
result?.type === 'error'
|
|
40
|
+
? result.error
|
|
41
|
+
: { status: response.status, message: response.statusText }
|
|
42
|
+
);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
if (response.headers.get('content-type')?.includes('application/json')) {
|
|
44
46
|
// we can end up here if we e.g. redirect in `handle`
|
|
45
47
|
const result = await response.json();
|
|
46
48
|
await handle_side_channel_response(result);
|
|
47
|
-
throw new HttpError(500, 'Invalid query.live response');
|
|
49
|
+
throw new HttpError({ status: 500, message: 'Invalid query.live response' });
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
if (!response.body) {
|
|
@@ -63,7 +65,7 @@ export async function* create_live_iterator(
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
await handle_side_channel_response(node);
|
|
66
|
-
throw new HttpError(500, 'Invalid query.live response');
|
|
68
|
+
throw new HttpError({ status: 500, message: 'Invalid query.live response' });
|
|
67
69
|
}
|
|
68
70
|
} finally {
|
|
69
71
|
try {
|
|
@@ -74,16 +74,6 @@ export class LiveQueryProxy {
|
|
|
74
74
|
return this.#get_cached_query().done;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
/**
|
|
78
|
-
* @deprecated Use `for await (const value of liveQuery())` instead.
|
|
79
|
-
* @returns {AsyncGenerator<T>}
|
|
80
|
-
*/
|
|
81
|
-
run() {
|
|
82
|
-
throw new Error(
|
|
83
|
-
'`.run()` has been removed from live queries. Use `for await (const value of liveQuery())` instead.'
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
77
|
reconnect() {
|
|
88
78
|
return this.#get_cached_query().reconnect();
|
|
89
79
|
}
|
|
@@ -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,6 +112,7 @@ 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;
|
|
115
116
|
|
|
116
117
|
// detect new deployments from the response header
|
|
117
118
|
notify_version(response.headers.get('x-sveltekit-version'));
|
|
@@ -119,20 +120,20 @@ export async function remote_request(url, init) {
|
|
|
119
120
|
if (!response.ok) {
|
|
120
121
|
const result = await response.json().catch(() => ({
|
|
121
122
|
type: 'error',
|
|
122
|
-
status
|
|
123
|
-
error:
|
|
123
|
+
status,
|
|
124
|
+
error: {
|
|
125
|
+
status,
|
|
126
|
+
message: response.statusText
|
|
127
|
+
}
|
|
124
128
|
}));
|
|
125
129
|
|
|
126
|
-
throw new HttpError(
|
|
127
|
-
result.error?.status ?? result.status ?? response.status ?? 500,
|
|
128
|
-
result.error
|
|
129
|
-
);
|
|
130
|
+
throw new HttpError({ status, ...result.error });
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
const result = /** @type {RemoteFunctionResponse} */ (await response.json());
|
|
133
134
|
|
|
134
135
|
if (result.type === 'error') {
|
|
135
|
-
throw new HttpError(result.error
|
|
136
|
+
throw new HttpError(result.error);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
const data = /** @type {RemoteFunctionData} */ (
|
|
@@ -147,7 +148,7 @@ export async function remote_request(url, init) {
|
|
|
147
148
|
function refresh(key, entry, result) {
|
|
148
149
|
if (entry?.resource) {
|
|
149
150
|
if (result.e) {
|
|
150
|
-
entry.resource.fail(new HttpError(result.e
|
|
151
|
+
entry.resource.fail(new HttpError(result.e));
|
|
151
152
|
} else {
|
|
152
153
|
entry.resource.set(result.v);
|
|
153
154
|
}
|
|
@@ -196,12 +197,12 @@ export async function remote_request(url, init) {
|
|
|
196
197
|
export async function handle_side_channel_response(response) {
|
|
197
198
|
if (response.type === 'redirect') {
|
|
198
199
|
// Use internal version to allow redirects to external URLs
|
|
199
|
-
await _goto(response.location
|
|
200
|
+
await _goto(response.location);
|
|
200
201
|
throw new Redirect(307, response.location);
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
if (response.type === 'error') {
|
|
204
|
-
throw new HttpError(response.error
|
|
205
|
+
throw new HttpError(response.error);
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
return response;
|
|
@@ -9,6 +9,7 @@ export const page = new (class Page {
|
|
|
9
9
|
error = $state.raw(null);
|
|
10
10
|
params = $state.raw({});
|
|
11
11
|
route = $state.raw({ id: null });
|
|
12
|
+
shallow = $state.raw(null);
|
|
12
13
|
state = $state.raw({});
|
|
13
14
|
status = $state.raw(-1);
|
|
14
15
|
url = $state.raw(new URL('a:'));
|
|
@@ -61,12 +62,14 @@ if (!DEV && BROWSER) {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
/** @type {() => Promise<boolean>} */
|
|
64
|
-
function check() {
|
|
65
|
-
if (checking) return checking;
|
|
66
|
-
|
|
65
|
+
updated.check = function check() {
|
|
67
66
|
window.clearTimeout(timeout);
|
|
68
67
|
|
|
69
|
-
|
|
68
|
+
if (updated.current) {
|
|
69
|
+
return Promise.resolve(true);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (checking ??= (async () => {
|
|
70
73
|
try {
|
|
71
74
|
const res = await fetch(`${assets}/${__SVELTEKIT_APP_VERSION_FILE__}`, {
|
|
72
75
|
headers: {
|
|
@@ -79,13 +82,7 @@ if (!DEV && BROWSER) {
|
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
const data = await res.json();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (new_update) {
|
|
85
|
-
updated.current = true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return new_update;
|
|
85
|
+
return (updated.current ||= data.version !== version);
|
|
89
86
|
} catch {
|
|
90
87
|
return false;
|
|
91
88
|
} finally {
|
|
@@ -93,16 +90,7 @@ if (!DEV && BROWSER) {
|
|
|
93
90
|
if (interval && !updated.current) timeout = window.setTimeout(check, interval);
|
|
94
91
|
}
|
|
95
92
|
})());
|
|
96
|
-
}
|
|
93
|
+
};
|
|
97
94
|
|
|
98
|
-
if (interval) timeout = window.setTimeout(check, interval);
|
|
99
|
-
|
|
100
|
-
updated.check = check;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* @param {import('@sveltejs/kit').Page} new_page
|
|
105
|
-
*/
|
|
106
|
-
export function update(new_page) {
|
|
107
|
-
Object.assign(page, new_page);
|
|
95
|
+
if (interval) timeout = window.setTimeout(updated.check, interval);
|
|
108
96
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { SvelteComponent } from 'svelte';
|
|
2
1
|
import {
|
|
3
2
|
ClientHooks,
|
|
4
3
|
CSRPageNode,
|
|
@@ -10,7 +9,7 @@ import {
|
|
|
10
9
|
Uses
|
|
11
10
|
} from 'types';
|
|
12
11
|
import { Page, ParamMatcher } from '@sveltejs/kit';
|
|
13
|
-
import { RenderNode } from '../
|
|
12
|
+
import { RenderNode } from '../props.svelte.js';
|
|
14
13
|
|
|
15
14
|
export interface SvelteKitApp {
|
|
16
15
|
/**
|
|
@@ -31,10 +31,9 @@ const warned = new WeakSet();
|
|
|
31
31
|
const valid_link_options = /** @type {const} */ ({
|
|
32
32
|
'preload-code': ['', 'false', 'tap', 'hover', 'viewport', 'eager'],
|
|
33
33
|
'preload-data': ['', 'false', 'tap', 'hover'],
|
|
34
|
-
keepfocus: ['', 'true', 'false'],
|
|
35
|
-
noscroll: ['', 'true', 'false'],
|
|
36
34
|
reload: ['', 'true', 'false'],
|
|
37
|
-
replacestate: ['', 'true', 'false']
|
|
35
|
+
replacestate: ['', 'true', 'false'],
|
|
36
|
+
reset: ['', 'true', 'false']
|
|
38
37
|
});
|
|
39
38
|
|
|
40
39
|
/**
|
|
@@ -123,6 +122,7 @@ export function get_link_info(a, base, uses_hash_router) {
|
|
|
123
122
|
/** @type {URL | undefined} */
|
|
124
123
|
let url;
|
|
125
124
|
|
|
125
|
+
// TODO replace the try/catch with `URL.parse` when browser support allows (Chrome 126, Firefox 126, Safari 18)
|
|
126
126
|
try {
|
|
127
127
|
url = new URL(a instanceof SVGAElement ? a.href.baseVal : a.href, document.baseURI);
|
|
128
128
|
|
|
@@ -150,12 +150,6 @@ export function get_link_info(a, base, uses_hash_router) {
|
|
|
150
150
|
* @param {HTMLFormElement | HTMLAnchorElement | SVGAElement} element
|
|
151
151
|
*/
|
|
152
152
|
export function get_router_options(element) {
|
|
153
|
-
/** @type {ValidLinkOptions<'keepfocus'> | null} */
|
|
154
|
-
let keepfocus = null;
|
|
155
|
-
|
|
156
|
-
/** @type {ValidLinkOptions<'noscroll'> | null} */
|
|
157
|
-
let noscroll = null;
|
|
158
|
-
|
|
159
153
|
/** @type {ValidLinkOptions<'preload-code'> | null} */
|
|
160
154
|
let preload_code = null;
|
|
161
155
|
|
|
@@ -168,16 +162,31 @@ export function get_router_options(element) {
|
|
|
168
162
|
/** @type {ValidLinkOptions<'replacestate'> | null} */
|
|
169
163
|
let replace_state = null;
|
|
170
164
|
|
|
165
|
+
/** @type {ValidLinkOptions<'reset'> | null} */
|
|
166
|
+
let reset = null;
|
|
167
|
+
|
|
171
168
|
/** @type {Element} */
|
|
172
169
|
let el = element;
|
|
173
170
|
|
|
174
171
|
while (el && el !== document.documentElement) {
|
|
172
|
+
if (DEV) {
|
|
173
|
+
for (const name of ['keepfocus', 'noscroll']) {
|
|
174
|
+
const value = el.getAttribute(`data-sveltekit-${name}`);
|
|
175
|
+
if (value !== null && !warned.has(el)) {
|
|
176
|
+
warned.add(el);
|
|
177
|
+
console.warn(
|
|
178
|
+
`\`data-sveltekit-${name}="true"\` has been replaced with \`data-sveltekit-reset="false"\``
|
|
179
|
+
);
|
|
180
|
+
console.log(el);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
175
185
|
if (preload_code === null) preload_code = link_option(el, 'preload-code');
|
|
176
186
|
if (preload_data === null) preload_data = link_option(el, 'preload-data');
|
|
177
|
-
if (keepfocus === null) keepfocus = link_option(el, 'keepfocus');
|
|
178
|
-
if (noscroll === null) noscroll = link_option(el, 'noscroll');
|
|
179
187
|
if (reload === null) reload = link_option(el, 'reload');
|
|
180
188
|
if (replace_state === null) replace_state = link_option(el, 'replacestate');
|
|
189
|
+
if (reset === null) reset = link_option(el, 'reset');
|
|
181
190
|
|
|
182
191
|
el = /** @type {Element} */ (parent_element(el));
|
|
183
192
|
}
|
|
@@ -198,10 +207,9 @@ export function get_router_options(element) {
|
|
|
198
207
|
return {
|
|
199
208
|
preload_code: levels[preload_code ?? 'false'],
|
|
200
209
|
preload_data: levels[preload_data ?? 'false'],
|
|
201
|
-
keepfocus: get_option_state(keepfocus),
|
|
202
|
-
noscroll: get_option_state(noscroll),
|
|
203
210
|
reload: get_option_state(reload),
|
|
204
|
-
replace_state: get_option_state(replace_state)
|
|
211
|
+
replace_state: get_option_state(replace_state),
|
|
212
|
+
reset: get_option_state(reset) ?? true
|
|
205
213
|
};
|
|
206
214
|
}
|
|
207
215
|
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { afterNavigate } from '$app/navigation';
|
|
3
|
-
import type {
|
|
4
|
-
import type { RenderNode } from '../types.js';
|
|
3
|
+
import type { Props, RenderNode } from '../props.svelte.js';
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
page: Page;
|
|
8
|
-
tree: RenderNode;
|
|
9
|
-
components: any[];
|
|
10
|
-
resetters: Array<(() => void) | undefined>;
|
|
11
|
-
form?: any;
|
|
12
|
-
error?: App.Error;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const { page, components, resetters, tree, form, error }: Props = $props();
|
|
5
|
+
const { page, components, onerror, tree, form, error }: Props = $props();
|
|
16
6
|
|
|
17
7
|
let mounted = $state(false);
|
|
18
8
|
let navigated = $state(false);
|
|
@@ -33,7 +23,7 @@
|
|
|
33
23
|
{const Error = $derived(n.error)}
|
|
34
24
|
{const data = $derived(n.data)}
|
|
35
25
|
|
|
36
|
-
<svelte:boundary onerror
|
|
26
|
+
<svelte:boundary {onerror}>
|
|
37
27
|
{#if n.child}
|
|
38
28
|
<!-- svelte-ignore binding_property_non_reactive -->
|
|
39
29
|
<Component bind:this={components[depth]} {data} {form} params={page.params}>
|
|
@@ -44,7 +34,7 @@
|
|
|
44
34
|
<Component bind:this={components[depth]} {data} {form} params={page.params} {error} />
|
|
45
35
|
{/if}
|
|
46
36
|
|
|
47
|
-
{#snippet failed(error)}
|
|
37
|
+
{#snippet failed(error: unknown)}
|
|
48
38
|
<Error {error} />
|
|
49
39
|
{/snippet}
|
|
50
40
|
</svelte:boundary>
|
|
@@ -3,12 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
import { DEV } from 'esm-env';
|
|
5
5
|
import * as devalue from 'devalue';
|
|
6
|
-
import { text_encoder } from './utils.js';
|
|
6
|
+
import { text_decoder, text_encoder } from './utils.js';
|
|
7
7
|
import { noop } from '../utils/functions.js';
|
|
8
8
|
import { SvelteKitError } from '@sveltejs/kit/internal';
|
|
9
9
|
|
|
10
|
-
const decoder = new TextDecoder();
|
|
11
|
-
|
|
12
10
|
/**
|
|
13
11
|
* Sets a parsed form field value in a nested object, mutating the original object.
|
|
14
12
|
* @param {Record<string, any>} object
|
|
@@ -283,7 +281,7 @@ export async function deserialize_binary_form(request, form_id) {
|
|
|
283
281
|
const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length);
|
|
284
282
|
if (!file_offsets_buffer) throw deserialize_error('file offset table too short');
|
|
285
283
|
|
|
286
|
-
const parsed_offsets = JSON.parse(
|
|
284
|
+
const parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer));
|
|
287
285
|
|
|
288
286
|
if (
|
|
289
287
|
!Array.isArray(parsed_offsets) ||
|
|
@@ -298,7 +296,7 @@ export async function deserialize_binary_form(request, form_id) {
|
|
|
298
296
|
|
|
299
297
|
/** @type {Array<{ offset: number, size: number }>} */
|
|
300
298
|
const file_spans = [];
|
|
301
|
-
const [data, meta] = devalue.parse(
|
|
299
|
+
const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {
|
|
302
300
|
File: ([name, type, size, last_modified, index]) => {
|
|
303
301
|
if (
|
|
304
302
|
typeof name !== 'string' ||
|
|
@@ -488,7 +486,7 @@ class LazyFile {
|
|
|
488
486
|
});
|
|
489
487
|
}
|
|
490
488
|
async text() {
|
|
491
|
-
return
|
|
489
|
+
return text_decoder.decode(await this.arrayBuffer());
|
|
492
490
|
}
|
|
493
491
|
}
|
|
494
492
|
|