@sveltejs/kit 2.64.0 → 2.65.1
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 +2 -2
- package/src/core/postbuild/analyse.js +0 -5
- package/src/core/postbuild/prerender.js +2 -0
- package/src/core/sync/write_client_manifest.js +5 -0
- package/src/exports/public.d.ts +1 -1
- package/src/exports/vite/build/build_server.js +43 -57
- package/src/exports/vite/build/build_service_worker.js +10 -0
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/index.js +237 -178
- package/src/runtime/app/server/remote/command.js +0 -3
- package/src/runtime/app/server/remote/form.js +18 -13
- package/src/runtime/app/server/remote/prerender.js +28 -34
- package/src/runtime/app/server/remote/query.js +105 -94
- package/src/runtime/app/server/remote/requested.js +14 -10
- package/src/runtime/app/server/remote/shared.js +25 -18
- package/src/runtime/client/client.js +25 -15
- package/src/runtime/client/remote-functions/command.svelte.js +5 -30
- package/src/runtime/client/remote-functions/form.svelte.js +62 -82
- package/src/runtime/client/remote-functions/prerender.svelte.js +14 -6
- package/src/runtime/client/remote-functions/query/index.js +6 -14
- package/src/runtime/client/remote-functions/query/instance.svelte.js +37 -8
- package/src/runtime/client/remote-functions/query/proxy.js +3 -3
- package/src/runtime/client/remote-functions/query-batch.svelte.js +59 -68
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +20 -6
- package/src/runtime/client/remote-functions/shared.svelte.js +76 -59
- package/src/runtime/server/page/render.js +20 -83
- package/src/runtime/server/page/server_routing.js +20 -15
- package/src/runtime/server/remote.js +296 -204
- package/src/runtime/server/respond.js +4 -2
- package/src/runtime/shared.js +0 -15
- package/src/types/global-private.d.ts +3 -3
- package/src/types/internal.d.ts +53 -34
- package/src/version.js +1 -1
- package/types/index.d.ts +4 -4
- package/types/index.d.ts.map +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import { ServerNodesResponse, ServerRedirectNode } from 'types' */
|
|
1
|
+
/** @import { RemoteFunctionDataNode, ServerNodesResponse, ServerRedirectNode } from 'types' */
|
|
2
2
|
/** @import { CacheEntry } from './remote-functions/cache.svelte.js' */
|
|
3
3
|
/** @import { Query } from './remote-functions/query/instance.svelte.js' */
|
|
4
4
|
/** @import { LiveQuery } from './remote-functions/query-live/instance.svelte.js' */
|
|
@@ -202,18 +202,20 @@ let target;
|
|
|
202
202
|
export let app;
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
* Data that was serialized during SSR for queries/forms/commands
|
|
206
|
-
*
|
|
207
|
-
*
|
|
205
|
+
* Data that was serialized during SSR for queries/forms/commands, stored as
|
|
206
|
+
* `{ v }` (value) or `{ e }` (error) nodes so that failed states survive hydration.
|
|
207
|
+
* Entries are deleted as they are consumed (when the corresponding resource is created).
|
|
208
|
+
* @type {Record<string, RemoteFunctionDataNode>}
|
|
208
209
|
*/
|
|
209
|
-
export
|
|
210
|
+
export const query_responses = {};
|
|
210
211
|
|
|
211
212
|
/**
|
|
212
|
-
* Data that was serialized during SSR for prerender functions
|
|
213
|
+
* Data that was serialized during SSR for prerender functions, stored as
|
|
214
|
+
* `{ v }` (value) or `{ e }` (error) nodes.
|
|
213
215
|
* This persists across client-side navigations.
|
|
214
|
-
* @type {Record<string,
|
|
216
|
+
* @type {Record<string, RemoteFunctionDataNode>}
|
|
215
217
|
*/
|
|
216
|
-
export
|
|
218
|
+
export const prerender_responses = {};
|
|
217
219
|
|
|
218
220
|
/** @type {Array<((url: URL) => boolean)>} */
|
|
219
221
|
const invalidated = [];
|
|
@@ -328,9 +330,15 @@ export async function start(_app, _target, hydrate) {
|
|
|
328
330
|
);
|
|
329
331
|
}
|
|
330
332
|
|
|
331
|
-
if (__SVELTEKIT_PAYLOAD__) {
|
|
332
|
-
|
|
333
|
-
|
|
333
|
+
if (__SVELTEKIT_PAYLOAD__.data) {
|
|
334
|
+
const { q = {}, p = {}, l = {}, f = {} } = __SVELTEKIT_PAYLOAD__.data;
|
|
335
|
+
|
|
336
|
+
// store the whole nodes — error records seed the corresponding
|
|
337
|
+
// resources in a failed state when they are created during hydration
|
|
338
|
+
for (const k in q) query_responses[k] = q[k];
|
|
339
|
+
for (const k in l) query_responses[k] = l[k];
|
|
340
|
+
for (const k in f) query_responses[k] = f[k];
|
|
341
|
+
for (const k in p) prerender_responses[k] = p[k];
|
|
334
342
|
}
|
|
335
343
|
|
|
336
344
|
// detect basic auth credentials in the current URL
|
|
@@ -546,7 +554,11 @@ export async function _goto(url, options, redirect_count, nav_token) {
|
|
|
546
554
|
force_invalidation = true;
|
|
547
555
|
query_keys = new Set();
|
|
548
556
|
for (const [id, entries] of query_map) {
|
|
549
|
-
for (const payload of entries
|
|
557
|
+
for (const [payload, entry] of entries) {
|
|
558
|
+
// don't refresh yet, as some queries will be unrendered,
|
|
559
|
+
// but clear caches so that newly rendered queries
|
|
560
|
+
// don't use stale data. TODO same for `live_query_map`
|
|
561
|
+
entry.resource?.reset();
|
|
550
562
|
query_keys.add(create_remote_key(id, payload));
|
|
551
563
|
}
|
|
552
564
|
}
|
|
@@ -574,7 +586,7 @@ export async function _goto(url, options, redirect_count, nav_token) {
|
|
|
574
586
|
for (const [id, entries] of query_map) {
|
|
575
587
|
for (const [payload, { resource }] of entries) {
|
|
576
588
|
if (query_keys?.has(create_remote_key(id, payload))) {
|
|
577
|
-
void resource.
|
|
589
|
+
void resource.start();
|
|
578
590
|
}
|
|
579
591
|
}
|
|
580
592
|
}
|
|
@@ -3028,8 +3040,6 @@ async function _hydrate(
|
|
|
3028
3040
|
|
|
3029
3041
|
target.textContent = '';
|
|
3030
3042
|
hydrate = false;
|
|
3031
|
-
} finally {
|
|
3032
|
-
query_responses = {};
|
|
3033
3043
|
}
|
|
3034
3044
|
|
|
3035
3045
|
if (result.props.page) {
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
/** @import { RemoteCommand, RemoteQueryUpdate } from '@sveltejs/kit' */
|
|
2
|
-
/** @import { RemoteFunctionResponse } from 'types' */
|
|
3
2
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
4
|
-
import * as devalue from 'devalue';
|
|
5
|
-
import { HttpError } from '@sveltejs/kit/internal';
|
|
6
3
|
import { app } from '../client.js';
|
|
7
4
|
import { stringify_command_arg } from '../../shared.js';
|
|
8
|
-
import {
|
|
9
|
-
get_remote_request_headers,
|
|
10
|
-
apply_refreshes,
|
|
11
|
-
categorize_updates,
|
|
12
|
-
apply_reconnections
|
|
13
|
-
} from './shared.svelte.js';
|
|
5
|
+
import { get_remote_request_headers, categorize_updates, remote_request } from './shared.svelte.js';
|
|
14
6
|
|
|
15
7
|
/**
|
|
16
8
|
* Client-version of the `command` function from `$app/server`.
|
|
@@ -53,7 +45,7 @@ export function command(id) {
|
|
|
53
45
|
throw updates_error;
|
|
54
46
|
}
|
|
55
47
|
|
|
56
|
-
const response = await
|
|
48
|
+
const response = await remote_request(`${base}/${app_dir}/remote/${id}`, {
|
|
57
49
|
method: 'POST',
|
|
58
50
|
body: JSON.stringify({
|
|
59
51
|
payload: await stringify_command_arg(arg, app.hooks.transport),
|
|
@@ -62,30 +54,13 @@ export function command(id) {
|
|
|
62
54
|
headers
|
|
63
55
|
});
|
|
64
56
|
|
|
65
|
-
if (
|
|
66
|
-
// We only end up here in case of a network error or if the server has an internal error
|
|
67
|
-
// (which shouldn't happen because we handle errors on the server and always send a 200 response)
|
|
68
|
-
throw new Error('Failed to execute remote function');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const result = /** @type {RemoteFunctionResponse} */ (await response.json());
|
|
72
|
-
if (result.type === 'redirect') {
|
|
57
|
+
if (response.redirect) {
|
|
73
58
|
throw new Error(
|
|
74
59
|
'Redirects are not allowed in commands. Return a result instead and use goto on the client'
|
|
75
60
|
);
|
|
76
|
-
} else if (result.type === 'error') {
|
|
77
|
-
throw new HttpError(result.status ?? 500, result.error);
|
|
78
|
-
} else {
|
|
79
|
-
if (result.refreshes) {
|
|
80
|
-
apply_refreshes(result.refreshes);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (result.reconnects) {
|
|
84
|
-
apply_reconnections(result.reconnects);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return devalue.parse(result.result, app.decoders);
|
|
88
61
|
}
|
|
62
|
+
|
|
63
|
+
return response._;
|
|
89
64
|
} finally {
|
|
90
65
|
overrides?.forEach((fn) => fn());
|
|
91
66
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
2
2
|
/** @import { RemoteFormInput, RemoteForm, RemoteQueryUpdate } from '@sveltejs/kit' */
|
|
3
|
-
/** @import { InternalRemoteFormIssue
|
|
3
|
+
/** @import { InternalRemoteFormIssue } from 'types' */
|
|
4
4
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
5
|
-
import * as devalue from 'devalue';
|
|
6
5
|
import { DEV } from 'esm-env';
|
|
7
6
|
import { HttpError } from '@sveltejs/kit/internal';
|
|
8
|
-
import {
|
|
7
|
+
import { query_responses, _goto, set_nearest_error_page, invalidateAll } from '../client.js';
|
|
9
8
|
import { tick } from 'svelte';
|
|
10
|
-
import {
|
|
9
|
+
import { categorize_updates, remote_request } from './shared.svelte.js';
|
|
11
10
|
import { createAttachmentKey } from 'svelte/attachments';
|
|
12
11
|
import {
|
|
13
12
|
convert_formdata,
|
|
@@ -60,18 +59,25 @@ export function form(id) {
|
|
|
60
59
|
const action_id = id + (key != undefined ? `/${JSON.stringify(key)}` : '');
|
|
61
60
|
const action = '?/remote=' + encodeURIComponent(action_id);
|
|
62
61
|
|
|
62
|
+
// the output of a non-enhanced submission that resulted in this page —
|
|
63
|
+
// consume it so the form's state survives hydration (form outputs are
|
|
64
|
+
// always value nodes; the server never serializes them as errors)
|
|
65
|
+
/** @type {{ input?: Record<string, any>, issues?: InternalRemoteFormIssue[], result?: any } | undefined} */
|
|
66
|
+
const initial = query_responses[action_id]?.v;
|
|
67
|
+
delete query_responses[action_id];
|
|
68
|
+
|
|
63
69
|
/**
|
|
64
70
|
* @type {Record<string, string | string[] | File | File[]>}
|
|
65
71
|
*/
|
|
66
|
-
let input = $state({});
|
|
72
|
+
let input = $state(initial?.input ?? {});
|
|
67
73
|
|
|
68
74
|
/** @type {InternalRemoteFormIssue[]} */
|
|
69
|
-
let raw_issues = $state.raw([]);
|
|
75
|
+
let raw_issues = $state.raw(initial?.issues ?? []);
|
|
70
76
|
|
|
71
77
|
const issues = $derived(flatten_issues(raw_issues));
|
|
72
78
|
|
|
73
79
|
/** @type {any} */
|
|
74
|
-
let result = $state.raw(
|
|
80
|
+
let result = $state.raw(initial?.result);
|
|
75
81
|
|
|
76
82
|
/** @type {number} */
|
|
77
83
|
let pending_count = $state(0);
|
|
@@ -182,77 +188,54 @@ export function form(id) {
|
|
|
182
188
|
remote_refreshes: Array.from(refreshes ?? [])
|
|
183
189
|
});
|
|
184
190
|
|
|
185
|
-
const response = await
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
'
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (!response.ok) {
|
|
197
|
-
// We only end up here in case of a network error or if the server has an internal error
|
|
198
|
-
// (which shouldn't happen because we handle errors on the server and always send a 200 response)
|
|
199
|
-
throw new Error('Failed to execute remote function');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const form_result = /** @type { RemoteFunctionResponse} */ (await response.json());
|
|
203
|
-
|
|
204
|
-
// reset issues in case it's a redirect or error (but issues passed in that case)
|
|
205
|
-
raw_issues = [];
|
|
206
|
-
result = undefined;
|
|
207
|
-
|
|
208
|
-
if (form_result.type === 'result') {
|
|
209
|
-
({ issues: raw_issues = [], result } = devalue.parse(form_result.result, app.decoders));
|
|
210
|
-
const succeeded = raw_issues.length === 0;
|
|
211
|
-
|
|
212
|
-
if (succeeded) {
|
|
213
|
-
if (refreshes === null && !form_result.refreshes && !form_result.reconnects) {
|
|
214
|
-
void invalidateAll();
|
|
215
|
-
} else {
|
|
216
|
-
if (form_result.refreshes) {
|
|
217
|
-
apply_refreshes(form_result.refreshes);
|
|
218
|
-
}
|
|
219
|
-
if (form_result.reconnects) {
|
|
220
|
-
apply_reconnections(form_result.reconnects);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
} else {
|
|
224
|
-
if (DEV) {
|
|
225
|
-
warn_on_missing_issue_reads();
|
|
226
|
-
}
|
|
191
|
+
const response = await remote_request(
|
|
192
|
+
`${base}/${app_dir}/remote/${action_id_without_key}`,
|
|
193
|
+
{
|
|
194
|
+
method: 'POST',
|
|
195
|
+
headers: {
|
|
196
|
+
'Content-Type': BINARY_FORM_CONTENT_TYPE,
|
|
197
|
+
// Forms cannot be called during rendering, so it's save to use location here
|
|
198
|
+
'x-sveltekit-pathname': location.pathname,
|
|
199
|
+
'x-sveltekit-search': location.search
|
|
200
|
+
},
|
|
201
|
+
body: blob
|
|
227
202
|
}
|
|
203
|
+
);
|
|
228
204
|
|
|
229
|
-
|
|
230
|
-
} else if (form_result.type === 'redirect') {
|
|
231
|
-
const stringified_refreshes = form_result.refreshes ?? '';
|
|
232
|
-
const stringified_reconnects = form_result.reconnects ?? '';
|
|
233
|
-
if (stringified_refreshes) {
|
|
234
|
-
apply_refreshes(stringified_refreshes);
|
|
235
|
-
}
|
|
205
|
+
({ issues: raw_issues = [], result } = response._ ?? {});
|
|
236
206
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
207
|
+
// if the developer took control of updates via `.updates(...)` (even with
|
|
208
|
+
// no arguments), or the server performed explicit refreshes, don't invalidateAll
|
|
209
|
+
const should_invalidate = refreshes === null && !response.r;
|
|
240
210
|
|
|
211
|
+
if (response.redirect) {
|
|
241
212
|
// Use internal version to allow redirects to external URLs
|
|
242
213
|
void _goto(
|
|
243
|
-
|
|
214
|
+
response.redirect,
|
|
244
215
|
{
|
|
245
|
-
invalidateAll:
|
|
246
|
-
refreshes === null && !stringified_refreshes && !stringified_reconnects
|
|
216
|
+
invalidateAll: should_invalidate
|
|
247
217
|
},
|
|
248
218
|
0
|
|
249
219
|
);
|
|
250
220
|
return true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const succeeded = raw_issues.length === 0;
|
|
224
|
+
|
|
225
|
+
if (succeeded) {
|
|
226
|
+
if (should_invalidate) {
|
|
227
|
+
void invalidateAll();
|
|
228
|
+
}
|
|
251
229
|
} else {
|
|
252
|
-
|
|
230
|
+
if (DEV) {
|
|
231
|
+
warn_on_missing_issue_reads();
|
|
232
|
+
}
|
|
253
233
|
}
|
|
234
|
+
|
|
235
|
+
return succeeded;
|
|
254
236
|
} catch (e) {
|
|
255
237
|
result = undefined;
|
|
238
|
+
raw_issues = [];
|
|
256
239
|
throw e;
|
|
257
240
|
} finally {
|
|
258
241
|
overrides?.forEach((fn) => fn());
|
|
@@ -661,30 +644,27 @@ export function form(id) {
|
|
|
661
644
|
if (validated?.issues) {
|
|
662
645
|
array = validated.issues.map((issue) => normalize_issue(issue, false));
|
|
663
646
|
} else if (!preflightOnly) {
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
'
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
647
|
+
const result = await remote_request(
|
|
648
|
+
`${base}/${app_dir}/remote/${action_id_without_key}`,
|
|
649
|
+
{
|
|
650
|
+
method: 'POST',
|
|
651
|
+
headers: {
|
|
652
|
+
'Content-Type': BINARY_FORM_CONTENT_TYPE,
|
|
653
|
+
// Validation should not be and will not be called during rendering, so it's save to use location here
|
|
654
|
+
'x-sveltekit-pathname': location.pathname,
|
|
655
|
+
'x-sveltekit-search': location.search
|
|
656
|
+
},
|
|
657
|
+
body: serialize_binary_form(data, {
|
|
658
|
+
validate_only: true
|
|
659
|
+
}).blob
|
|
660
|
+
}
|
|
661
|
+
);
|
|
678
662
|
|
|
679
663
|
if (validate_id !== id) {
|
|
680
664
|
return;
|
|
681
665
|
}
|
|
682
666
|
|
|
683
|
-
|
|
684
|
-
array = /** @type {InternalRemoteFormIssue[]} */ (
|
|
685
|
-
devalue.parse(result.result, app.decoders)
|
|
686
|
-
);
|
|
687
|
-
}
|
|
667
|
+
array = /** @type {InternalRemoteFormIssue[]} */ (result._);
|
|
688
668
|
}
|
|
689
669
|
|
|
690
670
|
if (!includeUntouched && !submitted) {
|
|
@@ -2,8 +2,8 @@
|
|
|
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, prerender_responses } from '../client.js';
|
|
6
|
-
import { get_remote_request_headers, remote_request } from './shared.svelte.js';
|
|
5
|
+
import { app, goto, prerender_responses } from '../client.js';
|
|
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
|
|
|
9
9
|
// Initialize Cache API for prerender functions
|
|
@@ -67,7 +67,7 @@ export function prerender(id) {
|
|
|
67
67
|
const url = `${base}/${app_dir}/remote/${id}${payload ? `/${payload}` : ''}`;
|
|
68
68
|
|
|
69
69
|
if (Object.hasOwn(prerender_responses, cache_key)) {
|
|
70
|
-
const data = prerender_responses[cache_key];
|
|
70
|
+
const data = unwrap_node(prerender_responses[cache_key]);
|
|
71
71
|
|
|
72
72
|
if (prerender_cache) {
|
|
73
73
|
void put(url, devalue.stringify(data, app.encoders));
|
|
@@ -77,6 +77,7 @@ export function prerender(id) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// Do this here, after await Svelte' reactivity context is gone.
|
|
80
|
+
// TODO we really don't want to be sending these specific headers here?
|
|
80
81
|
const headers = get_remote_request_headers();
|
|
81
82
|
|
|
82
83
|
// Check the Cache API first
|
|
@@ -93,14 +94,21 @@ export function prerender(id) {
|
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
const
|
|
97
|
+
const result = await remote_request(url, { headers });
|
|
98
|
+
|
|
99
|
+
if (result.redirect) {
|
|
100
|
+
void goto(result.redirect);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const data = result._;
|
|
97
105
|
|
|
98
106
|
// For successful prerender requests, save to cache
|
|
99
107
|
if (prerender_cache) {
|
|
100
|
-
void put(url,
|
|
108
|
+
void put(url, devalue.stringify(data, app.encoders));
|
|
101
109
|
}
|
|
102
110
|
|
|
103
|
-
return
|
|
111
|
+
return data;
|
|
104
112
|
});
|
|
105
113
|
|
|
106
114
|
prerender_resources.set(cache_key, new WeakRef(resource));
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/** @import { RemoteQueryFunction } from '@sveltejs/kit' */
|
|
2
2
|
import { app_dir, base } from '$app/paths/internal/client';
|
|
3
|
-
import {
|
|
3
|
+
import { goto, query_map } from '../../client.js';
|
|
4
4
|
import { get_remote_request_headers, QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
|
|
5
|
-
import * as devalue from 'devalue';
|
|
6
5
|
import { DEV } from 'esm-env';
|
|
7
|
-
import { unfriendly_hydratable } from '../../../shared.js';
|
|
8
6
|
import { QueryProxy } from './proxy.js';
|
|
9
7
|
|
|
10
8
|
/**
|
|
@@ -25,20 +23,14 @@ export function query(id) {
|
|
|
25
23
|
|
|
26
24
|
/** @type {RemoteQueryFunction<any, any>} */
|
|
27
25
|
const wrapper = (arg) => {
|
|
28
|
-
return new QueryProxy(id, arg, async (
|
|
29
|
-
if (Object.hasOwn(query_responses, key)) {
|
|
30
|
-
const value = query_responses[key];
|
|
31
|
-
delete query_responses[key];
|
|
32
|
-
return value;
|
|
33
|
-
}
|
|
34
|
-
|
|
26
|
+
return new QueryProxy(id, arg, async (payload) => {
|
|
35
27
|
const url = `${base}/${app_dir}/remote/${id}${payload ? `?payload=${payload}` : ''}`;
|
|
36
28
|
|
|
37
|
-
const
|
|
38
|
-
remote_request(url, get_remote_request_headers())
|
|
39
|
-
);
|
|
29
|
+
const result = await remote_request(url, { headers: get_remote_request_headers() });
|
|
40
30
|
|
|
41
|
-
|
|
31
|
+
if (result.redirect) {
|
|
32
|
+
await goto(result.redirect);
|
|
33
|
+
}
|
|
42
34
|
});
|
|
43
35
|
};
|
|
44
36
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { query_responses } from '../../client.js';
|
|
2
|
+
import { HttpError } from '@sveltejs/kit/internal';
|
|
2
3
|
import { QUERY_OVERRIDE_KEY } from '../shared.svelte.js';
|
|
3
4
|
import { noop } from '../../../../utils/functions.js';
|
|
4
5
|
import { with_resolvers } from '../../../../utils/promise.js';
|
|
@@ -64,6 +65,17 @@ export class Query {
|
|
|
64
65
|
constructor(key, fn) {
|
|
65
66
|
this.#key = key;
|
|
66
67
|
this.#fn = fn;
|
|
68
|
+
|
|
69
|
+
if (Object.hasOwn(query_responses, key)) {
|
|
70
|
+
const node = query_responses[key];
|
|
71
|
+
delete query_responses[key];
|
|
72
|
+
|
|
73
|
+
if (node.e) {
|
|
74
|
+
this.fail(new HttpError(node.e[0] ?? 500, node.e[1]));
|
|
75
|
+
} else {
|
|
76
|
+
this.set(/** @type {T} */ (node.v));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
#get_promise() {
|
|
@@ -71,7 +83,7 @@ export class Query {
|
|
|
71
83
|
return /** @type {Promise<T>} */ (this.#promise);
|
|
72
84
|
}
|
|
73
85
|
|
|
74
|
-
|
|
86
|
+
start() {
|
|
75
87
|
// there is a really weird bug with untrack and writes and initializations
|
|
76
88
|
// every time you see this comment, try removing the `tick.then` here and see
|
|
77
89
|
// if all the tests still pass with the latest svelte version
|
|
@@ -132,12 +144,12 @@ export class Query {
|
|
|
132
144
|
get then() {
|
|
133
145
|
// TODO this should be unnecessary but due to the bug described
|
|
134
146
|
// in #start, we need to do this in some circumstances
|
|
135
|
-
this
|
|
147
|
+
this.start();
|
|
136
148
|
return this.#then;
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
get catch() {
|
|
140
|
-
this
|
|
152
|
+
this.start();
|
|
141
153
|
this.#then;
|
|
142
154
|
return (/** @type {any} */ reject) => {
|
|
143
155
|
return this.#then(undefined, reject);
|
|
@@ -145,7 +157,7 @@ export class Query {
|
|
|
145
157
|
}
|
|
146
158
|
|
|
147
159
|
get finally() {
|
|
148
|
-
this
|
|
160
|
+
this.start();
|
|
149
161
|
this.#then;
|
|
150
162
|
return (/** @type {any} */ fn) => {
|
|
151
163
|
return this.#then(
|
|
@@ -162,12 +174,12 @@ export class Query {
|
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
get current() {
|
|
165
|
-
this
|
|
177
|
+
this.start();
|
|
166
178
|
return this.#current;
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
get error() {
|
|
170
|
-
this
|
|
182
|
+
this.start();
|
|
171
183
|
return this.#error;
|
|
172
184
|
}
|
|
173
185
|
|
|
@@ -175,7 +187,7 @@ export class Query {
|
|
|
175
187
|
* Returns true if the resource is loading or reloading.
|
|
176
188
|
*/
|
|
177
189
|
get loading() {
|
|
178
|
-
this
|
|
190
|
+
this.start();
|
|
179
191
|
return this.#loading;
|
|
180
192
|
}
|
|
181
193
|
|
|
@@ -183,7 +195,7 @@ export class Query {
|
|
|
183
195
|
* Returns true once the resource has been loaded for the first time.
|
|
184
196
|
*/
|
|
185
197
|
get ready() {
|
|
186
|
-
this
|
|
198
|
+
this.start();
|
|
187
199
|
return this.#ready;
|
|
188
200
|
}
|
|
189
201
|
|
|
@@ -199,6 +211,10 @@ export class Query {
|
|
|
199
211
|
* @param {T} value
|
|
200
212
|
*/
|
|
201
213
|
set(value) {
|
|
214
|
+
// normally consumed in the constructor, but make sure a leftover
|
|
215
|
+
// SSR record can never shadow the newly-set value
|
|
216
|
+
delete query_responses[this.#key];
|
|
217
|
+
|
|
202
218
|
this.#clear_pending();
|
|
203
219
|
this.#ready = true;
|
|
204
220
|
this.#loading = false;
|
|
@@ -211,6 +227,10 @@ export class Query {
|
|
|
211
227
|
* @param {unknown} error
|
|
212
228
|
*/
|
|
213
229
|
fail(error) {
|
|
230
|
+
// normally consumed in the constructor, but make sure a leftover
|
|
231
|
+
// SSR record can never shadow the newly-set error
|
|
232
|
+
delete query_responses[this.#key];
|
|
233
|
+
|
|
214
234
|
this.#clear_pending();
|
|
215
235
|
this.#loading = false;
|
|
216
236
|
this.#error = error;
|
|
@@ -243,6 +263,15 @@ export class Query {
|
|
|
243
263
|
return release;
|
|
244
264
|
}
|
|
245
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Reset ahead of a navigation that invalidates all, to force newly
|
|
268
|
+
* rendered queries to get fresh data
|
|
269
|
+
*/
|
|
270
|
+
reset() {
|
|
271
|
+
this.#promise = null;
|
|
272
|
+
delete query_responses[this.#key];
|
|
273
|
+
}
|
|
274
|
+
|
|
246
275
|
get [Symbol.toStringTag]() {
|
|
247
276
|
return 'Query';
|
|
248
277
|
}
|
|
@@ -25,7 +25,7 @@ export class QueryProxy {
|
|
|
25
25
|
/**
|
|
26
26
|
* @param {string} id
|
|
27
27
|
* @param {any} arg
|
|
28
|
-
* @param {(
|
|
28
|
+
* @param {(payload: string) => Promise<T>} fn
|
|
29
29
|
*/
|
|
30
30
|
constructor(id, arg, fn) {
|
|
31
31
|
this.#id = id;
|
|
@@ -41,7 +41,7 @@ export class QueryProxy {
|
|
|
41
41
|
this.#payload,
|
|
42
42
|
// IMPORTANT: This cannot close over `this` or it becomes impossible to
|
|
43
43
|
// garbage collect the QueryProxy and thus impossible to evict cache entries.
|
|
44
|
-
() => new Query(key, () => fn(
|
|
44
|
+
() => new Query(key, () => fn(payload))
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
cache.ref(this, entry, this.#id, this.#payload);
|
|
@@ -98,7 +98,7 @@ export class QueryProxy {
|
|
|
98
98
|
this.#payload,
|
|
99
99
|
// IMPORTANT: This cannot close over `this` or it becomes impossible to
|
|
100
100
|
// garbage collect the QueryProxy and thus impossible to evict cache entries.
|
|
101
|
-
() => new Query(key_ref, () => fn_ref(
|
|
101
|
+
() => new Query(key_ref, () => fn_ref(payload_ref))
|
|
102
102
|
);
|
|
103
103
|
|
|
104
104
|
const deref = cache.manual_ref(entry, this.#id, this.#payload);
|