@sveltejs/kit 2.40.0 → 2.42.0
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 +1 -1
- package/src/core/sync/write_server.js +2 -0
- package/src/exports/public.d.ts +103 -10
- package/src/runtime/app/server/remote/form.js +146 -15
- package/src/runtime/client/client.js +12 -7
- package/src/runtime/client/remote-functions/form.svelte.js +321 -79
- package/src/runtime/server/page/render.js +28 -26
- package/src/runtime/server/remote.js +4 -3
- package/src/runtime/utils.js +122 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +121 -12
- package/types/index.d.ts.map +8 -4
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import { load_error_page, load_template } from '../config/index.js';
|
|
|
7
7
|
import { runtime_directory } from '../utils.js';
|
|
8
8
|
import { isSvelte5Plus, write_if_changed } from './utils.js';
|
|
9
9
|
import colors from 'kleur';
|
|
10
|
+
import { escape_html } from '../../utils/escape.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* @param {{
|
|
@@ -54,6 +55,7 @@ export const options = {
|
|
|
54
55
|
.replace('%sveltekit.body%', '" + body + "')
|
|
55
56
|
.replace(/%sveltekit\.assets%/g, '" + assets + "')
|
|
56
57
|
.replace(/%sveltekit\.nonce%/g, '" + nonce + "')
|
|
58
|
+
.replace(/%sveltekit\.version%/g, escape_html(config.kit.version.name))
|
|
57
59
|
.replace(
|
|
58
60
|
/%sveltekit\.env\.([^%]+)%/g,
|
|
59
61
|
(_match, capture) => `" + (env[${s(capture)}] ?? "") + "`
|
package/src/exports/public.d.ts
CHANGED
|
@@ -1810,28 +1810,105 @@ export interface Snapshot<T = any> {
|
|
|
1810
1810
|
restore: (snapshot: T) => void;
|
|
1811
1811
|
}
|
|
1812
1812
|
|
|
1813
|
+
// If T is unknown or RemoteFormInput, the types below will recurse indefinitely and create giant unions that TS can't handle
|
|
1814
|
+
type WillRecurseIndefinitely<T> = unknown extends T
|
|
1815
|
+
? true
|
|
1816
|
+
: RemoteFormInput extends T
|
|
1817
|
+
? true
|
|
1818
|
+
: false;
|
|
1819
|
+
|
|
1820
|
+
// Helper type to convert union to intersection
|
|
1821
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
|
|
1822
|
+
? I
|
|
1823
|
+
: never;
|
|
1824
|
+
|
|
1825
|
+
type FlattenInput<T, Prefix extends string> =
|
|
1826
|
+
WillRecurseIndefinitely<T> extends true
|
|
1827
|
+
? { [key: string]: string }
|
|
1828
|
+
: T extends Array<infer U>
|
|
1829
|
+
? U extends string | File
|
|
1830
|
+
? { [P in Prefix]: string[] }
|
|
1831
|
+
: FlattenInput<U, `${Prefix}[${number}]`>
|
|
1832
|
+
: T extends File
|
|
1833
|
+
? { [P in Prefix]: string }
|
|
1834
|
+
: T extends object
|
|
1835
|
+
? {
|
|
1836
|
+
[K in keyof T]: FlattenInput<
|
|
1837
|
+
T[K],
|
|
1838
|
+
Prefix extends '' ? K & string : `${Prefix}.${K & string}`
|
|
1839
|
+
>;
|
|
1840
|
+
}[keyof T]
|
|
1841
|
+
: { [P in Prefix]: string };
|
|
1842
|
+
|
|
1843
|
+
type FlattenIssues<T, Prefix extends string> =
|
|
1844
|
+
WillRecurseIndefinitely<T> extends true
|
|
1845
|
+
? { [key: string]: RemoteFormIssue[] }
|
|
1846
|
+
: T extends Array<infer U>
|
|
1847
|
+
? { [P in Prefix | `${Prefix}[${number}]`]: RemoteFormIssue[] } & FlattenIssues<
|
|
1848
|
+
U,
|
|
1849
|
+
`${Prefix}[${number}]`
|
|
1850
|
+
>
|
|
1851
|
+
: T extends File
|
|
1852
|
+
? { [P in Prefix]: RemoteFormIssue[] }
|
|
1853
|
+
: T extends object
|
|
1854
|
+
? {
|
|
1855
|
+
[K in keyof T]: FlattenIssues<
|
|
1856
|
+
T[K],
|
|
1857
|
+
Prefix extends '' ? K & string : `${Prefix}.${K & string}`
|
|
1858
|
+
>;
|
|
1859
|
+
}[keyof T]
|
|
1860
|
+
: { [P in Prefix]: RemoteFormIssue[] };
|
|
1861
|
+
|
|
1862
|
+
type FlattenKeys<T, Prefix extends string> =
|
|
1863
|
+
WillRecurseIndefinitely<T> extends true
|
|
1864
|
+
? { [key: string]: string }
|
|
1865
|
+
: T extends Array<infer U>
|
|
1866
|
+
? U extends string | File
|
|
1867
|
+
? { [P in `${Prefix}[]`]: string[] }
|
|
1868
|
+
: FlattenKeys<U, `${Prefix}[${number}]`>
|
|
1869
|
+
: T extends File
|
|
1870
|
+
? { [P in Prefix]: string }
|
|
1871
|
+
: T extends object
|
|
1872
|
+
? {
|
|
1873
|
+
[K in keyof T]: FlattenKeys<
|
|
1874
|
+
T[K],
|
|
1875
|
+
Prefix extends '' ? K & string : `${Prefix}.${K & string}`
|
|
1876
|
+
>;
|
|
1877
|
+
}[keyof T]
|
|
1878
|
+
: { [P in Prefix]: string };
|
|
1879
|
+
|
|
1880
|
+
export interface RemoteFormInput {
|
|
1881
|
+
[key: string]: FormDataEntryValue | FormDataEntryValue[] | RemoteFormInput | RemoteFormInput[];
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
export interface RemoteFormIssue {
|
|
1885
|
+
name: string;
|
|
1886
|
+
path: Array<string | number>;
|
|
1887
|
+
message: string;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1813
1890
|
/**
|
|
1814
1891
|
* The return value of a remote `form` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
|
|
1815
1892
|
*/
|
|
1816
|
-
export type RemoteForm<
|
|
1893
|
+
export type RemoteForm<Input extends RemoteFormInput | void, Output> = {
|
|
1894
|
+
/** Attachment that sets up an event handler that intercepts the form submission on the client to prevent a full page reload */
|
|
1895
|
+
[attachment: symbol]: (node: HTMLFormElement) => void;
|
|
1817
1896
|
method: 'POST';
|
|
1818
1897
|
/** The URL to send the form to. */
|
|
1819
1898
|
action: string;
|
|
1820
|
-
/** Event handler that intercepts the form submission on the client to prevent a full page reload */
|
|
1821
|
-
onsubmit: (event: SubmitEvent) => void;
|
|
1822
1899
|
/** Use the `enhance` method to influence what happens when the form is submitted. */
|
|
1823
1900
|
enhance(
|
|
1824
1901
|
callback: (opts: {
|
|
1825
1902
|
form: HTMLFormElement;
|
|
1826
|
-
data:
|
|
1903
|
+
data: Input;
|
|
1827
1904
|
submit: () => Promise<void> & {
|
|
1828
1905
|
updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => Promise<void>;
|
|
1829
1906
|
};
|
|
1830
|
-
}) => void
|
|
1907
|
+
}) => void | Promise<void>
|
|
1831
1908
|
): {
|
|
1832
1909
|
method: 'POST';
|
|
1833
1910
|
action: string;
|
|
1834
|
-
|
|
1911
|
+
[attachment: symbol]: (node: HTMLFormElement) => void;
|
|
1835
1912
|
};
|
|
1836
1913
|
/**
|
|
1837
1914
|
* Create an instance of the form for the given key.
|
|
@@ -1847,11 +1924,27 @@ export type RemoteForm<Result> = {
|
|
|
1847
1924
|
* {/each}
|
|
1848
1925
|
* ```
|
|
1849
1926
|
*/
|
|
1850
|
-
for(key: string | number | boolean): Omit<RemoteForm<
|
|
1927
|
+
for(key: string | number | boolean): Omit<RemoteForm<Input, Output>, 'for'>;
|
|
1928
|
+
/**
|
|
1929
|
+
* This method exists to allow you to typecheck `name` attributes. It returns its argument
|
|
1930
|
+
* @example
|
|
1931
|
+
* ```svelte
|
|
1932
|
+
* <input name={login.field('username')} />
|
|
1933
|
+
* ```
|
|
1934
|
+
**/
|
|
1935
|
+
field<Name extends keyof UnionToIntersection<FlattenKeys<Input, ''>>>(string: Name): Name;
|
|
1936
|
+
/** Preflight checks */
|
|
1937
|
+
preflight(schema: StandardSchemaV1<Input, any>): RemoteForm<Input, Output>;
|
|
1938
|
+
/** Validate the form contents programmatically */
|
|
1939
|
+
validate(options?: { includeUntouched?: boolean }): Promise<void>;
|
|
1851
1940
|
/** The result of the form submission */
|
|
1852
|
-
get result():
|
|
1941
|
+
get result(): Output | undefined;
|
|
1853
1942
|
/** The number of pending submissions */
|
|
1854
1943
|
get pending(): number;
|
|
1944
|
+
/** The submitted values */
|
|
1945
|
+
input: null | UnionToIntersection<FlattenInput<Input, ''>>;
|
|
1946
|
+
/** Validation issues */
|
|
1947
|
+
issues: null | UnionToIntersection<FlattenIssues<Input, ''>>;
|
|
1855
1948
|
/** Spread this onto a `<button>` or `<input type="submit">` */
|
|
1856
1949
|
buttonProps: {
|
|
1857
1950
|
type: 'submit';
|
|
@@ -1862,11 +1955,11 @@ export type RemoteForm<Result> = {
|
|
|
1862
1955
|
enhance(
|
|
1863
1956
|
callback: (opts: {
|
|
1864
1957
|
form: HTMLFormElement;
|
|
1865
|
-
data:
|
|
1958
|
+
data: Input;
|
|
1866
1959
|
submit: () => Promise<void> & {
|
|
1867
1960
|
updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => Promise<void>;
|
|
1868
1961
|
};
|
|
1869
|
-
}) => void
|
|
1962
|
+
}) => void | Promise<void>
|
|
1870
1963
|
): {
|
|
1871
1964
|
type: 'submit';
|
|
1872
1965
|
formmethod: 'POST';
|
|
@@ -1,34 +1,77 @@
|
|
|
1
|
-
/** @import { RemoteForm } from '@sveltejs/kit' */
|
|
2
|
-
/** @import {
|
|
1
|
+
/** @import { RemoteFormInput, RemoteForm } from '@sveltejs/kit' */
|
|
2
|
+
/** @import { MaybePromise, RemoteInfo } from 'types' */
|
|
3
|
+
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
3
4
|
import { get_request_store } from '@sveltejs/kit/internal/server';
|
|
5
|
+
import { DEV } from 'esm-env';
|
|
4
6
|
import { run_remote_function } from './shared.js';
|
|
7
|
+
import { convert_formdata, flatten_issues } from '../../../utils.js';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Creates a form object that can be spread onto a `<form>` element.
|
|
8
11
|
*
|
|
9
12
|
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
|
|
10
13
|
*
|
|
11
|
-
* @template
|
|
12
|
-
* @
|
|
13
|
-
* @
|
|
14
|
+
* @template Output
|
|
15
|
+
* @overload
|
|
16
|
+
* @param {() => Output} fn
|
|
17
|
+
* @returns {RemoteForm<void, Output>}
|
|
18
|
+
* @since 2.27
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Creates a form object that can be spread onto a `<form>` element.
|
|
22
|
+
*
|
|
23
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
|
|
24
|
+
*
|
|
25
|
+
* @template {RemoteFormInput} Input
|
|
26
|
+
* @template Output
|
|
27
|
+
* @overload
|
|
28
|
+
* @param {'unchecked'} validate
|
|
29
|
+
* @param {(data: Input) => MaybePromise<Output>} fn
|
|
30
|
+
* @returns {RemoteForm<Input, Output>}
|
|
31
|
+
* @since 2.27
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Creates a form object that can be spread onto a `<form>` element.
|
|
35
|
+
*
|
|
36
|
+
* See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
|
|
37
|
+
*
|
|
38
|
+
* @template {StandardSchemaV1<RemoteFormInput, Record<string, any>>} Schema
|
|
39
|
+
* @template Output
|
|
40
|
+
* @overload
|
|
41
|
+
* @param {Schema} validate
|
|
42
|
+
* @param {(data: StandardSchemaV1.InferOutput<Schema>) => MaybePromise<Output>} fn
|
|
43
|
+
* @returns {RemoteForm<StandardSchemaV1.InferInput<Schema>, Output>}
|
|
44
|
+
* @since 2.27
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* @template {RemoteFormInput} Input
|
|
48
|
+
* @template Output
|
|
49
|
+
* @param {any} validate_or_fn
|
|
50
|
+
* @param {(data?: Input) => MaybePromise<Output>} [maybe_fn]
|
|
51
|
+
* @returns {RemoteForm<Input, Output>}
|
|
14
52
|
* @since 2.27
|
|
15
53
|
*/
|
|
16
54
|
/*@__NO_SIDE_EFFECTS__*/
|
|
17
55
|
// @ts-ignore we don't want to prefix `fn` with an underscore, as that will be user-visible
|
|
18
|
-
export function form(
|
|
56
|
+
export function form(validate_or_fn, maybe_fn) {
|
|
57
|
+
/** @type {(data?: Input) => Output} */
|
|
58
|
+
const fn = maybe_fn ?? validate_or_fn;
|
|
59
|
+
|
|
60
|
+
/** @type {StandardSchemaV1 | null} */
|
|
61
|
+
const schema = !maybe_fn || validate_or_fn === 'unchecked' ? null : validate_or_fn;
|
|
62
|
+
|
|
19
63
|
/**
|
|
20
64
|
* @param {string | number | boolean} [key]
|
|
21
65
|
*/
|
|
22
66
|
function create_instance(key) {
|
|
23
|
-
/** @type {RemoteForm<
|
|
67
|
+
/** @type {RemoteForm<Input, Output>} */
|
|
24
68
|
const instance = {};
|
|
25
69
|
|
|
26
70
|
instance.method = 'POST';
|
|
27
|
-
instance.onsubmit = () => {};
|
|
28
71
|
|
|
29
72
|
Object.defineProperty(instance, 'enhance', {
|
|
30
73
|
value: () => {
|
|
31
|
-
return { action: instance.action, method: instance.method
|
|
74
|
+
return { action: instance.action, method: instance.method };
|
|
32
75
|
}
|
|
33
76
|
});
|
|
34
77
|
|
|
@@ -54,19 +97,79 @@ export function form(fn) {
|
|
|
54
97
|
id: '',
|
|
55
98
|
/** @param {FormData} form_data */
|
|
56
99
|
fn: async (form_data) => {
|
|
100
|
+
const validate_only = form_data.get('sveltekit:validate_only') === 'true';
|
|
101
|
+
form_data.delete('sveltekit:validate_only');
|
|
102
|
+
|
|
103
|
+
let data = maybe_fn ? convert_formdata(form_data) : undefined;
|
|
104
|
+
|
|
105
|
+
// TODO 3.0 remove this warning
|
|
106
|
+
if (DEV && !data) {
|
|
107
|
+
const error = () => {
|
|
108
|
+
throw new Error(
|
|
109
|
+
'Remote form functions no longer get passed a FormData object. ' +
|
|
110
|
+
"`form` now has the same signature as `query` or `command`, i.e. it expects to be invoked like `form(schema, callback)` or `form('unchecked', callback)`. " +
|
|
111
|
+
'The payload of the callback function is now a POJO instead of a FormData object. See https://kit.svelte.dev/docs/remote-functions#form for details.'
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
data = {};
|
|
115
|
+
for (const key of [
|
|
116
|
+
'append',
|
|
117
|
+
'delete',
|
|
118
|
+
'entries',
|
|
119
|
+
'forEach',
|
|
120
|
+
'get',
|
|
121
|
+
'getAll',
|
|
122
|
+
'has',
|
|
123
|
+
'keys',
|
|
124
|
+
'set',
|
|
125
|
+
'values'
|
|
126
|
+
]) {
|
|
127
|
+
Object.defineProperty(data, key, { get: error });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** @type {{ input?: Record<string, string | string[]>, issues?: Record<string, StandardSchemaV1.Issue[]>, result: Output }} */
|
|
132
|
+
const output = {};
|
|
133
|
+
|
|
57
134
|
const { event, state } = get_request_store();
|
|
135
|
+
const validated = await schema?.['~standard'].validate(data);
|
|
136
|
+
|
|
137
|
+
if (validate_only) {
|
|
138
|
+
return validated?.issues ?? [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (validated?.issues !== undefined) {
|
|
142
|
+
output.issues = flatten_issues(validated.issues);
|
|
143
|
+
output.input = {};
|
|
144
|
+
|
|
145
|
+
for (let key of form_data.keys()) {
|
|
146
|
+
// redact sensitive fields
|
|
147
|
+
if (/^[.\]]?_/.test(key)) continue;
|
|
148
|
+
|
|
149
|
+
const is_array = key.endsWith('[]');
|
|
150
|
+
const values = form_data.getAll(key).filter((value) => typeof value === 'string');
|
|
58
151
|
|
|
59
|
-
|
|
152
|
+
if (is_array) key = key.slice(0, -2);
|
|
60
153
|
|
|
61
|
-
|
|
154
|
+
output.input[key] = is_array ? values : values[0];
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
if (validated !== undefined) {
|
|
158
|
+
data = validated.value;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
state.refreshes ??= {};
|
|
162
|
+
|
|
163
|
+
output.result = await run_remote_function(event, state, true, data, (d) => d, fn);
|
|
164
|
+
}
|
|
62
165
|
|
|
63
166
|
// We don't need to care about args or deduplicating calls, because uneval results are only relevant in full page reloads
|
|
64
167
|
// where only one form submission is active at the same time
|
|
65
168
|
if (!event.isRemoteRequest) {
|
|
66
|
-
(state.remote_data ??= {})[__.id] =
|
|
169
|
+
(state.remote_data ??= {})[__.id] = output;
|
|
67
170
|
}
|
|
68
171
|
|
|
69
|
-
return
|
|
172
|
+
return output;
|
|
70
173
|
}
|
|
71
174
|
};
|
|
72
175
|
|
|
@@ -82,11 +185,24 @@ export function form(fn) {
|
|
|
82
185
|
enumerable: true
|
|
83
186
|
});
|
|
84
187
|
|
|
188
|
+
for (const property of ['input', 'issues']) {
|
|
189
|
+
Object.defineProperty(instance, property, {
|
|
190
|
+
get() {
|
|
191
|
+
try {
|
|
192
|
+
const { remote_data } = get_request_store().state;
|
|
193
|
+
return remote_data?.[__.id]?.[property] ?? {};
|
|
194
|
+
} catch {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
85
201
|
Object.defineProperty(instance, 'result', {
|
|
86
202
|
get() {
|
|
87
203
|
try {
|
|
88
204
|
const { remote_data } = get_request_store().state;
|
|
89
|
-
return remote_data?.[__.id];
|
|
205
|
+
return remote_data?.[__.id]?.result;
|
|
90
206
|
} catch {
|
|
91
207
|
return undefined;
|
|
92
208
|
}
|
|
@@ -103,9 +219,24 @@ export function form(fn) {
|
|
|
103
219
|
get: () => 0
|
|
104
220
|
});
|
|
105
221
|
|
|
222
|
+
Object.defineProperty(instance, 'field', {
|
|
223
|
+
value: (/** @type {string} */ name) => name
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
Object.defineProperty(instance, 'preflight', {
|
|
227
|
+
// preflight is a noop on the server
|
|
228
|
+
value: () => instance
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
Object.defineProperty(instance, 'validate', {
|
|
232
|
+
value: () => {
|
|
233
|
+
throw new Error('Cannot call validate() on the server');
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
106
237
|
if (key == undefined) {
|
|
107
238
|
Object.defineProperty(instance, 'for', {
|
|
108
|
-
/** @type {RemoteForm<any>['for']} */
|
|
239
|
+
/** @type {RemoteForm<any, any>['for']} */
|
|
109
240
|
value: (key) => {
|
|
110
241
|
const { state } = get_request_store();
|
|
111
242
|
const cache_key = __.id + '|' + JSON.stringify(key);
|
|
@@ -190,10 +190,7 @@ let target;
|
|
|
190
190
|
export let app;
|
|
191
191
|
|
|
192
192
|
/** @type {Record<string, any>} */
|
|
193
|
-
|
|
194
|
-
// because it will be `undefined` when users import the exports from this module.
|
|
195
|
-
// It's only defined when the server renders a page.
|
|
196
|
-
export const remote_responses = __SVELTEKIT_PAYLOAD__?.data ?? {};
|
|
193
|
+
export let remote_responses = {};
|
|
197
194
|
|
|
198
195
|
/** @type {Array<((url: URL) => boolean)>} */
|
|
199
196
|
const invalidated = [];
|
|
@@ -294,6 +291,10 @@ export async function start(_app, _target, hydrate) {
|
|
|
294
291
|
);
|
|
295
292
|
}
|
|
296
293
|
|
|
294
|
+
if (__SVELTEKIT_PAYLOAD__.data) {
|
|
295
|
+
remote_responses = __SVELTEKIT_PAYLOAD__?.data;
|
|
296
|
+
}
|
|
297
|
+
|
|
297
298
|
// detect basic auth credentials in the current URL
|
|
298
299
|
// https://github.com/sveltejs/kit/pull/11179
|
|
299
300
|
// if so, refresh the page without credentials
|
|
@@ -460,7 +461,7 @@ export async function _goto(url, options, redirect_count, nav_token) {
|
|
|
460
461
|
load_cache = null;
|
|
461
462
|
}
|
|
462
463
|
|
|
463
|
-
|
|
464
|
+
await navigate({
|
|
464
465
|
type: 'goto',
|
|
465
466
|
url: resolve_url(url),
|
|
466
467
|
keepfocus: options.keepFocus,
|
|
@@ -480,6 +481,7 @@ export async function _goto(url, options, redirect_count, nav_token) {
|
|
|
480
481
|
}
|
|
481
482
|
}
|
|
482
483
|
});
|
|
484
|
+
|
|
483
485
|
if (options.invalidateAll) {
|
|
484
486
|
// TODO the ticks shouldn't be necessary, something inside Svelte itself is buggy
|
|
485
487
|
// when a query in a layout that still exists after page change is refreshed earlier than this
|
|
@@ -495,7 +497,6 @@ export async function _goto(url, options, redirect_count, nav_token) {
|
|
|
495
497
|
});
|
|
496
498
|
});
|
|
497
499
|
}
|
|
498
|
-
return result;
|
|
499
500
|
}
|
|
500
501
|
|
|
501
502
|
/** @param {import('./types.js').NavigationIntent} intent */
|
|
@@ -1282,6 +1283,7 @@ async function load_root_error_page({ status, error, url, route }) {
|
|
|
1282
1283
|
});
|
|
1283
1284
|
} catch (error) {
|
|
1284
1285
|
if (error instanceof Redirect) {
|
|
1286
|
+
// @ts-expect-error TODO investigate this
|
|
1285
1287
|
return _goto(new URL(error.location, location.href), {}, 0);
|
|
1286
1288
|
}
|
|
1287
1289
|
|
|
@@ -1576,7 +1578,7 @@ async function navigate({
|
|
|
1576
1578
|
if (navigation_result.type === 'redirect') {
|
|
1577
1579
|
// whatwg fetch spec https://fetch.spec.whatwg.org/#http-redirect-fetch says to error after 20 redirects
|
|
1578
1580
|
if (redirect_count < 20) {
|
|
1579
|
-
|
|
1581
|
+
await navigate({
|
|
1580
1582
|
type,
|
|
1581
1583
|
url: new URL(navigation_result.location, url),
|
|
1582
1584
|
popped,
|
|
@@ -1587,6 +1589,9 @@ async function navigate({
|
|
|
1587
1589
|
redirect_count: redirect_count + 1,
|
|
1588
1590
|
nav_token
|
|
1589
1591
|
});
|
|
1592
|
+
|
|
1593
|
+
nav.fulfil(undefined);
|
|
1594
|
+
return;
|
|
1590
1595
|
}
|
|
1591
1596
|
|
|
1592
1597
|
navigation_result = await load_root_error_page({
|