@sveltejs/kit 3.0.0-next.23 → 3.0.0-next.24
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 +40 -5
- package/src/cli.js +3 -3
- package/src/constants.js +13 -1
- package/src/core/adapt/builder.js +2 -3
- package/src/core/env.js +139 -181
- package/src/core/postbuild/analyse.js +9 -4
- package/src/core/postbuild/prerender.js +3 -4
- package/src/core/sync/create_manifest_data/index.js +29 -33
- package/src/core/sync/sync.js +23 -40
- package/src/core/sync/write_app_manifest.js +83 -0
- package/src/core/sync/write_client_manifest.js +6 -4
- package/src/core/sync/write_server.js +10 -6
- package/src/core/sync/write_types/index.js +2 -2
- package/src/core/utils.js +0 -28
- package/src/exports/hooks/public.d.ts +9 -1
- package/src/exports/node/index.js +77 -5
- package/src/exports/vite/build/build_server.js +3 -3
- package/src/exports/vite/build/utils.js +48 -4
- package/src/exports/vite/dev/index.js +11 -22
- package/src/exports/vite/index.js +62 -345
- package/src/exports/vite/module_ids.js +1 -11
- package/src/exports/vite/plugins/env-vars.js +117 -0
- package/src/exports/vite/preview/index.js +6 -4
- package/src/exports/vite/utils.js +2 -4
- package/src/runtime/app/env/{types.d.ts → client.js} +9 -4
- package/src/runtime/app/env/index.js +1 -2
- package/src/runtime/app/env/private/index.js +1 -0
- package/src/runtime/app/env/public/client.js +1 -1
- package/src/runtime/app/env/public/server.js +1 -1
- package/src/runtime/app/env/{internal.js → server.js} +4 -4
- package/src/runtime/app/forms/client.js +263 -0
- package/src/runtime/app/forms/index.js +1 -263
- package/src/runtime/app/forms/public.d.ts +1 -1
- package/src/runtime/app/forms/server.js +6 -0
- package/src/runtime/app/forms/shared.js +34 -0
- package/src/runtime/app/manifest/index.js +1 -1
- package/src/runtime/app/navigation/client.js +15 -0
- package/src/runtime/app/navigation/index.js +1 -15
- package/src/runtime/app/navigation/public.d.ts +1 -1
- package/src/runtime/app/navigation/server.js +15 -0
- package/src/runtime/app/paths/server.js +1 -1
- package/src/runtime/app/server/remote/form.js +11 -1
- package/src/runtime/app/server/remote/prerender.js +1 -2
- package/src/runtime/app/server/remote/query.js +1 -1
- package/src/runtime/app/state/client.svelte.js +207 -0
- package/src/runtime/app/state/index.js +1 -66
- package/src/runtime/app/state/public.d.ts +1 -1
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client.js +206 -274
- package/src/runtime/client/fetcher.js +18 -8
- package/src/runtime/client/remote-functions/form.svelte.js +9 -6
- package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query-live/iterator.js +1 -1
- package/src/runtime/client/remote-functions/shared.svelte.js +2 -2
- package/src/runtime/client/snapshots.js +1 -3
- package/src/runtime/client/stream.js +27 -20
- package/src/runtime/client/utils.js +7 -3
- package/src/runtime/components/root.svelte +5 -5
- package/src/runtime/env/dynamic/private.js +1 -1
- package/src/runtime/env/static/private.js +1 -1
- package/src/runtime/error-chain.js +54 -0
- package/src/runtime/form-utils.js +53 -77
- package/src/runtime/invalid-import.js +1 -0
- package/src/runtime/props.svelte.js +1 -1
- package/src/runtime/server/data/index.js +1 -1
- package/src/runtime/server/endpoint.js +8 -3
- package/src/runtime/server/env_module.js +1 -1
- package/src/runtime/server/errors.js +2 -2
- package/src/runtime/server/index.js +2 -2
- package/src/runtime/server/page/actions.js +77 -122
- package/src/runtime/server/page/index.js +37 -69
- package/src/runtime/server/page/render.js +18 -23
- package/src/runtime/server/remote-functions.js +14 -42
- package/src/runtime/server/respond.js +23 -3
- package/src/telemetry.js +1 -33
- package/src/types/ambient-private.d.ts +9 -17
- package/src/types/internal.d.ts +20 -4
- package/src/types/private.d.ts +1 -1
- package/src/utils/exports.js +1 -0
- package/src/utils/filesystem.js +9 -21
- package/src/utils/functions.js +10 -0
- package/src/utils/routing.js +0 -11
- package/src/utils/url.js +0 -11
- package/src/version.js +1 -1
- package/types/index.d.ts +34 -28
- package/types/index.d.ts.map +7 -5
- package/src/runtime/app/env/private.js +0 -1
- package/src/runtime/app/env/standard-schema.d.ts +0 -0
- package/src/runtime/app/state/client.js +0 -63
- package/src/runtime/client/state.svelte.js +0 -98
- package/src/runtime/server/ambient.d.ts +0 -4
- package/src/utils/path.js +0 -23
|
@@ -1,263 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { DEV } from 'esm-env';
|
|
3
|
-
import { noop } from '../../../utils/functions.js';
|
|
4
|
-
import { refreshAll } from '../navigation/index.js';
|
|
5
|
-
import {
|
|
6
|
-
applyAction,
|
|
7
|
-
apply_action_navigation,
|
|
8
|
-
handle_error,
|
|
9
|
-
is_current_location
|
|
10
|
-
} from '../../client/client.js';
|
|
11
|
-
import { notify_version } from '../../client/state.svelte.js';
|
|
12
|
-
import { parse } from '#app/internal/transport';
|
|
13
|
-
|
|
14
|
-
export { applyAction };
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Use this function to deserialize the response from a form submission.
|
|
18
|
-
* Usage:
|
|
19
|
-
*
|
|
20
|
-
* ```js
|
|
21
|
-
* import { deserialize } from '$app/forms';
|
|
22
|
-
*
|
|
23
|
-
* async function handleSubmit(event) {
|
|
24
|
-
* const response = await fetch('/form?/action', {
|
|
25
|
-
* method: 'POST',
|
|
26
|
-
* body: new FormData(event.target)
|
|
27
|
-
* });
|
|
28
|
-
*
|
|
29
|
-
* const result = deserialize(await response.text());
|
|
30
|
-
* // ...
|
|
31
|
-
* }
|
|
32
|
-
* ```
|
|
33
|
-
* @template {Record<string, unknown> | undefined} Success
|
|
34
|
-
* @template {Record<string, unknown> | undefined} Failure
|
|
35
|
-
* @param {string} result
|
|
36
|
-
* @returns {ActionResult<Success, Failure>}
|
|
37
|
-
*/
|
|
38
|
-
export function deserialize(result) {
|
|
39
|
-
const parsed = JSON.parse(result);
|
|
40
|
-
|
|
41
|
-
if (parsed.data) {
|
|
42
|
-
parsed.data = parse(parsed.data);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return parsed;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Shallow clone an element, so that we can access e.g. `form.action` without worrying
|
|
50
|
-
* that someone has added an `<input name="action">` (https://github.com/sveltejs/kit/issues/7593)
|
|
51
|
-
* @template {HTMLElement} T
|
|
52
|
-
* @param {T} element
|
|
53
|
-
* @returns {T}
|
|
54
|
-
*/
|
|
55
|
-
function clone(element) {
|
|
56
|
-
return /** @type {T} */ (HTMLElement.prototype.cloneNode.call(element));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* This action enhances a `<form>` element that otherwise would work without JavaScript.
|
|
61
|
-
*
|
|
62
|
-
* The `submit` function is called upon submission with the given FormData and the `action` that should be triggered.
|
|
63
|
-
* If `cancel` is called, the form will not be submitted.
|
|
64
|
-
* You can use the abort `controller` to cancel the submission in case another one starts.
|
|
65
|
-
* If a function is returned, that function is called with the response from the server.
|
|
66
|
-
* If nothing is returned, the fallback will be used.
|
|
67
|
-
*
|
|
68
|
-
* If this function or its return value isn't set, it emulates the browser-native behaviour, just without the full-page reload. It
|
|
69
|
-
* - resets the `<form>` element and refreshes all data in case of a successful submission with no redirect response
|
|
70
|
-
* - updates the `form` prop, `page.form` and `page.status` if the action is on the same page as the form
|
|
71
|
-
* - navigates to the page the submission lands on — populating that page's `form` prop and `page.status` — on success and failure if that isn't the current page, just as a native form submission would, but with the `?/actionName` param stripped from the destination URL
|
|
72
|
-
* - redirects in case of a redirect response
|
|
73
|
-
* - renders the nearest error page in case of an unexpected error — the one nearest the action's route, if the action is on a different page
|
|
74
|
-
*
|
|
75
|
-
* If you provide a custom function with a callback and want to use the default behavior, invoke `update` in your callback.
|
|
76
|
-
* It accepts an options object
|
|
77
|
-
* - `reset: false` if you don't want the `<form>` values to be reset after a successful submission
|
|
78
|
-
* - `refreshAll` to control whether all data is refreshed after submission; it defaults to `true` for successes and `false` for failures
|
|
79
|
-
* - `navigate: false` to apply non-redirect results to the current page rather than navigating to `result.location`; redirects are always followed
|
|
80
|
-
* @template {Record<string, unknown> | undefined} Success
|
|
81
|
-
* @template {Record<string, unknown> | undefined} Failure
|
|
82
|
-
* @param {HTMLFormElement} form_element The form element
|
|
83
|
-
* @param {SubmitFunction<Success, Failure>} submit Submit callback
|
|
84
|
-
*/
|
|
85
|
-
export function enhance(form_element, submit = noop) {
|
|
86
|
-
if (DEV && clone(form_element).method !== 'post') {
|
|
87
|
-
throw new Error('use:enhance can only be used on <form> fields with method="POST"');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* @param {{
|
|
92
|
-
* result: ActionResult;
|
|
93
|
-
* reset?: boolean;
|
|
94
|
-
* refreshAll?: boolean;
|
|
95
|
-
* invalidateAll?: boolean;
|
|
96
|
-
* navigate?: boolean;
|
|
97
|
-
* }} opts
|
|
98
|
-
*/
|
|
99
|
-
const fallback_callback = async ({
|
|
100
|
-
result,
|
|
101
|
-
reset = true,
|
|
102
|
-
refreshAll: should_refresh_all,
|
|
103
|
-
invalidateAll: deprecated_invalidate_all,
|
|
104
|
-
navigate = true
|
|
105
|
-
}) => {
|
|
106
|
-
if (DEV && deprecated_invalidate_all !== undefined) {
|
|
107
|
-
console.warn(
|
|
108
|
-
'The `update({ invalidateAll })` option has been deprecated in favour of `update({ refreshAll })`'
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
should_refresh_all ??= deprecated_invalidate_all ?? result.type === 'success';
|
|
113
|
-
|
|
114
|
-
if (result.type === 'success' && reset) {
|
|
115
|
-
// We call reset from the prototype to avoid DOM clobbering
|
|
116
|
-
HTMLFormElement.prototype.reset.call(form_element);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const destination =
|
|
120
|
-
navigate && result.type !== 'redirect' && !is_current_location(result.location)
|
|
121
|
-
? result.location
|
|
122
|
-
: undefined;
|
|
123
|
-
|
|
124
|
-
if (destination === undefined) {
|
|
125
|
-
if (should_refresh_all && result.type !== 'redirect') {
|
|
126
|
-
await refreshAll();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
await applyAction(result);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// emulate the browser: navigate to where the submission lands, rendering that
|
|
134
|
-
// page with this result
|
|
135
|
-
await apply_action_navigation(destination, result, should_refresh_all);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
/** @param {SubmitEvent} event */
|
|
139
|
-
async function handle_submit(event) {
|
|
140
|
-
const method = event.submitter?.hasAttribute('formmethod')
|
|
141
|
-
? /** @type {HTMLButtonElement | HTMLInputElement} */ (event.submitter).formMethod
|
|
142
|
-
: clone(form_element).method;
|
|
143
|
-
if (method !== 'post') return;
|
|
144
|
-
|
|
145
|
-
event.preventDefault();
|
|
146
|
-
|
|
147
|
-
const action = new URL(
|
|
148
|
-
// We can't do submitter.formAction directly because that property is always set
|
|
149
|
-
event.submitter?.hasAttribute('formaction')
|
|
150
|
-
? /** @type {HTMLButtonElement | HTMLInputElement} */ (event.submitter).formAction
|
|
151
|
-
: clone(form_element).action
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
const enctype = event.submitter?.hasAttribute('formenctype')
|
|
155
|
-
? /** @type {HTMLButtonElement | HTMLInputElement} */ (event.submitter).formEnctype
|
|
156
|
-
: clone(form_element).enctype;
|
|
157
|
-
|
|
158
|
-
const form_data = new FormData(form_element, event.submitter);
|
|
159
|
-
|
|
160
|
-
if (DEV && enctype !== 'multipart/form-data') {
|
|
161
|
-
for (const value of form_data.values()) {
|
|
162
|
-
if (value instanceof File) {
|
|
163
|
-
throw new Error(
|
|
164
|
-
'Your form contains <input type="file"> fields, but is missing the necessary `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819.'
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const controller = new AbortController();
|
|
171
|
-
|
|
172
|
-
let cancelled = false;
|
|
173
|
-
const cancel = () => (cancelled = true);
|
|
174
|
-
|
|
175
|
-
const callback =
|
|
176
|
-
(await submit({
|
|
177
|
-
action,
|
|
178
|
-
cancel,
|
|
179
|
-
controller,
|
|
180
|
-
formData: form_data,
|
|
181
|
-
formElement: form_element,
|
|
182
|
-
submitter: event.submitter
|
|
183
|
-
})) ?? fallback_callback;
|
|
184
|
-
if (cancelled) return;
|
|
185
|
-
|
|
186
|
-
/** @type {ActionResult} */
|
|
187
|
-
let result;
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
const headers = new Headers({
|
|
191
|
-
accept: 'application/json',
|
|
192
|
-
'x-sveltekit-action': 'true'
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// do not explicitly set the `Content-Type` header when sending `FormData`
|
|
196
|
-
// or else it will interfere with the browser's header setting
|
|
197
|
-
// see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects#sect4
|
|
198
|
-
if (enctype !== 'multipart/form-data') {
|
|
199
|
-
headers.set(
|
|
200
|
-
'Content-Type',
|
|
201
|
-
/^(:?application\/x-www-form-urlencoded|text\/plain)$/.test(enctype)
|
|
202
|
-
? enctype
|
|
203
|
-
: 'application/x-www-form-urlencoded'
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// @ts-expect-error `URLSearchParams(form_data)` is kosher, but typescript doesn't know that
|
|
208
|
-
const body = enctype === 'multipart/form-data' ? form_data : new URLSearchParams(form_data);
|
|
209
|
-
|
|
210
|
-
const response = await fetch(action, {
|
|
211
|
-
method: 'POST',
|
|
212
|
-
headers,
|
|
213
|
-
cache: 'no-store',
|
|
214
|
-
body,
|
|
215
|
-
signal: controller.signal
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// detect new deployments from the response header
|
|
219
|
-
notify_version(response.headers.get('x-sveltekit-version'));
|
|
220
|
-
|
|
221
|
-
result = deserialize(await response.text());
|
|
222
|
-
if (result.type === 'error' || result.type === 'failure') {
|
|
223
|
-
result.status = response.status;
|
|
224
|
-
}
|
|
225
|
-
} catch (error) {
|
|
226
|
-
if (/** @type {any} */ (error)?.name === 'AbortError') return;
|
|
227
|
-
result = {
|
|
228
|
-
type: 'error',
|
|
229
|
-
error: await handle_error(error, {
|
|
230
|
-
params: {},
|
|
231
|
-
route: { id: null },
|
|
232
|
-
url: new URL(location.href)
|
|
233
|
-
})
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
await callback({
|
|
238
|
-
action,
|
|
239
|
-
formData: form_data,
|
|
240
|
-
formElement: form_element,
|
|
241
|
-
update: (opts) =>
|
|
242
|
-
fallback_callback({
|
|
243
|
-
result,
|
|
244
|
-
reset: opts?.reset,
|
|
245
|
-
refreshAll: opts?.refreshAll,
|
|
246
|
-
invalidateAll: opts?.invalidateAll,
|
|
247
|
-
navigate: opts?.navigate
|
|
248
|
-
}),
|
|
249
|
-
// @ts-expect-error generic constraints stuff we don't care about
|
|
250
|
-
result
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// @ts-expect-error
|
|
255
|
-
HTMLFormElement.prototype.addEventListener.call(form_element, 'submit', handle_submit);
|
|
256
|
-
|
|
257
|
-
return {
|
|
258
|
-
destroy() {
|
|
259
|
-
// @ts-expect-error
|
|
260
|
-
HTMLFormElement.prototype.removeEventListener.call(form_element, 'submit', handle_submit);
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
}
|
|
1
|
+
export { applyAction, deserialize, enhance } from '#app/forms';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './client.js';
|
|
2
2
|
export type { ActionResult, SubmitFunction } from './types.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** @import { ActionResult } from './types.js' */
|
|
2
|
+
import { parse } from '#app/internal/transport';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Use this function to deserialize the response from a form submission.
|
|
6
|
+
* Usage:
|
|
7
|
+
*
|
|
8
|
+
* ```js
|
|
9
|
+
* import { deserialize } from '$app/forms';
|
|
10
|
+
*
|
|
11
|
+
* async function handleSubmit(event) {
|
|
12
|
+
* const response = await fetch('/form?/action', {
|
|
13
|
+
* method: 'POST',
|
|
14
|
+
* body: new FormData(event.target)
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* const result = deserialize(await response.text());
|
|
18
|
+
* // ...
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
* @template {Record<string, unknown> | undefined} Success
|
|
22
|
+
* @template {Record<string, unknown> | undefined} Failure
|
|
23
|
+
* @param {string} result
|
|
24
|
+
* @returns {ActionResult<Success, Failure>}
|
|
25
|
+
*/
|
|
26
|
+
export function deserialize(result) {
|
|
27
|
+
const parsed = JSON.parse(result);
|
|
28
|
+
|
|
29
|
+
if (parsed.data) {
|
|
30
|
+
parsed.data = parse(parsed.data);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return parsed;
|
|
34
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from '
|
|
1
|
+
export * from '<sveltekit:generated>/app-manifest.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
afterNavigate,
|
|
3
|
+
beforeNavigate,
|
|
4
|
+
disableScrollHandling,
|
|
5
|
+
goto,
|
|
6
|
+
invalidate,
|
|
7
|
+
invalidateAll,
|
|
8
|
+
refreshAll,
|
|
9
|
+
onNavigate,
|
|
10
|
+
preloadCode,
|
|
11
|
+
preloadData,
|
|
12
|
+
pushState,
|
|
13
|
+
replaceState
|
|
14
|
+
} from '../../client/client.js';
|
|
15
|
+
export { snapshot } from '../../client/snapshots.js';
|
|
@@ -1,15 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
afterNavigate,
|
|
3
|
-
beforeNavigate,
|
|
4
|
-
disableScrollHandling,
|
|
5
|
-
goto,
|
|
6
|
-
invalidate,
|
|
7
|
-
invalidateAll,
|
|
8
|
-
refreshAll,
|
|
9
|
-
onNavigate,
|
|
10
|
-
preloadCode,
|
|
11
|
-
preloadData,
|
|
12
|
-
pushState,
|
|
13
|
-
replaceState
|
|
14
|
-
} from '../../client/client.js';
|
|
15
|
-
export { snapshot } from '../../client/snapshots.js';
|
|
1
|
+
export * from '#app/navigation';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { noop, disallow_on_server } from '../../../utils/functions.js';
|
|
2
|
+
|
|
3
|
+
export const afterNavigate = noop;
|
|
4
|
+
export const beforeNavigate = noop;
|
|
5
|
+
export const disableScrollHandling = disallow_on_server('disableScrollHandling', '()');
|
|
6
|
+
export const goto = disallow_on_server('goto');
|
|
7
|
+
export const invalidate = disallow_on_server('invalidate');
|
|
8
|
+
export const invalidateAll = disallow_on_server('invalidateAll', '()');
|
|
9
|
+
export const onNavigate = noop;
|
|
10
|
+
export const refreshAll = disallow_on_server('refreshAll', '()');
|
|
11
|
+
export const preloadCode = disallow_on_server('preloadCode');
|
|
12
|
+
export const preloadData = disallow_on_server('preloadData');
|
|
13
|
+
export const pushState = disallow_on_server('pushState');
|
|
14
|
+
export const replaceState = disallow_on_server('replaceState');
|
|
15
|
+
export const snapshot = noop;
|
|
@@ -4,7 +4,7 @@ import { decode_pathname } from '../../../utils/url.js';
|
|
|
4
4
|
import { add_data_suffix } from '../../../pathname.js';
|
|
5
5
|
import { try_get_request_store } from '@sveltejs/kit/internal/server';
|
|
6
6
|
import { manifest } from '../../server/internal.js';
|
|
7
|
-
import { get_hooks } from '
|
|
7
|
+
import { get_hooks } from '<sveltekit:generated>/server.js';
|
|
8
8
|
import { DEV } from 'esm-env';
|
|
9
9
|
|
|
10
10
|
export { base, assets, app_dir } from './internal/server.js';
|
|
@@ -11,7 +11,11 @@ import {
|
|
|
11
11
|
parse_form_key
|
|
12
12
|
} from '../../../form-utils.js';
|
|
13
13
|
import { get_cache, get_implicit_lookup, run_remote_function } from './shared.js';
|
|
14
|
-
import { ValidationError } from '@sveltejs/kit/internal';
|
|
14
|
+
import { ActionFailure, ValidationError } from '@sveltejs/kit/internal';
|
|
15
|
+
import { DEV } from 'esm-env';
|
|
16
|
+
|
|
17
|
+
const incorrect_fail_message =
|
|
18
|
+
'`fail(...)` is for form actions. A remote `form` handler should call `invalid(...)` instead. See https://svelte.dev/docs/kit/remote-functions#form-Programmatic-validation';
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* Creates a form object that can be spread onto a `<form>` element.
|
|
@@ -118,9 +122,15 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
118
122
|
() => data,
|
|
119
123
|
(data) => (!maybe_fn ? fn() : fn(data, issue))
|
|
120
124
|
);
|
|
125
|
+
|
|
126
|
+
if (DEV && output.result instanceof ActionFailure) {
|
|
127
|
+
throw new Error(incorrect_fail_message);
|
|
128
|
+
}
|
|
121
129
|
} catch (e) {
|
|
122
130
|
if (e instanceof ValidationError) {
|
|
123
131
|
handle_issues(output, e.issues, form_data, __.id);
|
|
132
|
+
} else if (DEV && e instanceof ActionFailure) {
|
|
133
|
+
throw new Error(incorrect_fail_message, { cause: e });
|
|
124
134
|
} else {
|
|
125
135
|
throw e;
|
|
126
136
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/** @import { RemoteResource, RemotePrerenderFunction } from '$app/server' */
|
|
2
2
|
/** @import { RemoteFunctionResponse, RemotePrerenderInputsGenerator, RemotePrerenderInternals, MaybePromise } from 'types' */
|
|
3
3
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
4
|
-
import { json } from '@sveltejs/kit';
|
|
5
4
|
import { HandledHttpError } from '@sveltejs/kit/internal';
|
|
6
5
|
import { get_request_store } from '@sveltejs/kit/internal/server';
|
|
7
6
|
import { stringify_remote_arg } from '../../../shared.js';
|
|
@@ -145,7 +144,7 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) {
|
|
|
145
144
|
const body = { type: 'result', data: stringify({ _: result }) };
|
|
146
145
|
state.prerendering.dependencies.set(url, {
|
|
147
146
|
body: JSON.stringify(body),
|
|
148
|
-
response: json(body)
|
|
147
|
+
response: Response.json(body)
|
|
149
148
|
});
|
|
150
149
|
}
|
|
151
150
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
5
5
|
import { get_request_store } from '@sveltejs/kit/internal/server';
|
|
6
6
|
import { create_remote_key, stringify_remote_arg } from '../../../shared.js';
|
|
7
|
-
import { prerendering } from '
|
|
7
|
+
import { prerendering } from '#app/env/server';
|
|
8
8
|
import {
|
|
9
9
|
create_validator,
|
|
10
10
|
get_cache,
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/** @import { Navigation } from '$app/navigation' */
|
|
2
|
+
/** @import { Page } from '$app/state' */
|
|
3
|
+
import { DEV } from 'esm-env';
|
|
4
|
+
import { assets } from '#app/paths';
|
|
5
|
+
import { version } from '$app/env';
|
|
6
|
+
|
|
7
|
+
/** @type {Page} */
|
|
8
|
+
export const internal_page = new (class Page {
|
|
9
|
+
data = $state.raw({});
|
|
10
|
+
form = $state.raw(null);
|
|
11
|
+
error = $state.raw(null);
|
|
12
|
+
params = $state.raw({});
|
|
13
|
+
route = $state.raw({ id: null });
|
|
14
|
+
shallow = $state.raw(null);
|
|
15
|
+
state = $state.raw({});
|
|
16
|
+
status = $state.raw(-1);
|
|
17
|
+
url = $state.raw(new URL('a:'));
|
|
18
|
+
})();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {Partial<Page>} new_page
|
|
22
|
+
*/
|
|
23
|
+
export function update_page(new_page) {
|
|
24
|
+
Object.assign(internal_page, new_page);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A read-only reactive object with information about the current page, serving several use cases:
|
|
29
|
+
* - retrieving the combined `data` of all pages/layouts anywhere in your component tree (also see [loading data](https://svelte.dev/docs/kit/load))
|
|
30
|
+
* - retrieving the current value of the `form` prop anywhere in your component tree (also see [form actions](https://svelte.dev/docs/kit/form-actions))
|
|
31
|
+
* - retrieving the page state that was set through `goto` (also see [goto](https://svelte.dev/docs/kit/$app-navigation#goto) and [shallow routing](https://svelte.dev/docs/kit/shallow-routing))
|
|
32
|
+
* - retrieving metadata such as the URL you're on, the current route and its parameters, the target of a shallow navigation, and whether or not there was an error
|
|
33
|
+
*
|
|
34
|
+
* ```svelte
|
|
35
|
+
* <!--- file: +layout.svelte --->
|
|
36
|
+
* <script>
|
|
37
|
+
* import { page } from '$app/state';
|
|
38
|
+
* </script>
|
|
39
|
+
*
|
|
40
|
+
* <p>Currently at {page.url.pathname}</p>
|
|
41
|
+
*
|
|
42
|
+
* {#if page.error}
|
|
43
|
+
* <span class="red">Problem detected</span>
|
|
44
|
+
* {:else}
|
|
45
|
+
* <span class="small">All systems operational</span>
|
|
46
|
+
* {/if}
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* Changes to `page` are available exclusively with runes. (The legacy reactivity syntax will not reflect any changes)
|
|
50
|
+
*
|
|
51
|
+
* ```svelte
|
|
52
|
+
* <!--- file: +page.svelte --->
|
|
53
|
+
* <script>
|
|
54
|
+
* import { page } from '$app/state';
|
|
55
|
+
* const id = $derived(page.params.id); // This will correctly update id for usage on this page
|
|
56
|
+
* $: badId = page.params.id; // Do not use; will never update after initial load
|
|
57
|
+
* </script>
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* On the server, values can only be read during rendering (in other words _not_ in e.g. `load` functions). In the browser, the values can be read at any time.
|
|
61
|
+
*
|
|
62
|
+
* @type {Page}
|
|
63
|
+
*/
|
|
64
|
+
export const page = {
|
|
65
|
+
get data() {
|
|
66
|
+
return internal_page.data;
|
|
67
|
+
},
|
|
68
|
+
get error() {
|
|
69
|
+
return internal_page.error;
|
|
70
|
+
},
|
|
71
|
+
get form() {
|
|
72
|
+
return internal_page.form;
|
|
73
|
+
},
|
|
74
|
+
get params() {
|
|
75
|
+
return internal_page.params;
|
|
76
|
+
},
|
|
77
|
+
get route() {
|
|
78
|
+
return internal_page.route;
|
|
79
|
+
},
|
|
80
|
+
get shallow() {
|
|
81
|
+
return internal_page.shallow;
|
|
82
|
+
},
|
|
83
|
+
get state() {
|
|
84
|
+
return internal_page.state;
|
|
85
|
+
},
|
|
86
|
+
get status() {
|
|
87
|
+
return internal_page.status;
|
|
88
|
+
},
|
|
89
|
+
get url() {
|
|
90
|
+
return internal_page.url;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** @type {Navigation | null} */
|
|
95
|
+
let navigation = $state.raw(null);
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param {Navigation | null} value
|
|
99
|
+
*/
|
|
100
|
+
export function set_navigation(value) {
|
|
101
|
+
navigation = value;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* A read-only object representing an in-progress navigation, with `from`, `to`, `type` and (if `type === 'popstate'`) `delta` properties.
|
|
106
|
+
* Values are `null` when no navigation is occurring, or during server rendering.
|
|
107
|
+
* @type {Navigation | { from: null, to: null, type: null, willUnload: null, delta: null, complete: null }}
|
|
108
|
+
*/
|
|
109
|
+
export const navigating = {
|
|
110
|
+
get from() {
|
|
111
|
+
return navigation ? navigation.from : null;
|
|
112
|
+
},
|
|
113
|
+
get to() {
|
|
114
|
+
return navigation ? navigation.to : null;
|
|
115
|
+
},
|
|
116
|
+
get type() {
|
|
117
|
+
return navigation ? navigation.type : null;
|
|
118
|
+
},
|
|
119
|
+
get willUnload() {
|
|
120
|
+
return navigation ? navigation.willUnload : null;
|
|
121
|
+
},
|
|
122
|
+
// @ts-expect-error TODO not entirely sure what's going on here
|
|
123
|
+
get delta() {
|
|
124
|
+
return navigation?.type === 'popstate' ? navigation.delta : null;
|
|
125
|
+
},
|
|
126
|
+
get complete() {
|
|
127
|
+
return navigation ? navigation.complete : null;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const interval = __SVELTEKIT_APP_VERSION_POLL_INTERVAL__;
|
|
132
|
+
|
|
133
|
+
/** @type {number | undefined} */
|
|
134
|
+
let timeout;
|
|
135
|
+
|
|
136
|
+
/** @type {Promise<boolean> | undefined} */
|
|
137
|
+
let checking;
|
|
138
|
+
|
|
139
|
+
let _updated = $state(false);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A read-only reactive value that's initially `false`. SvelteKit checks for new versions on data, remote, and form action responses (via the `x-sveltekit-version` header), when the tab regains focus or becomes visible, and on a poll interval (see [`version.pollInterval`](https://svelte.dev/docs/kit/configuration#version)). `updated.current` is set to `true` when a new version is detected. `updated.check()` will force an immediate check, regardless of polling.
|
|
143
|
+
* @type {{ get current(): boolean; check(): Promise<boolean>; }}
|
|
144
|
+
*/
|
|
145
|
+
export const updated = {
|
|
146
|
+
get current() {
|
|
147
|
+
return _updated;
|
|
148
|
+
},
|
|
149
|
+
async check() {
|
|
150
|
+
if (DEV) return false;
|
|
151
|
+
|
|
152
|
+
window.clearTimeout(timeout);
|
|
153
|
+
|
|
154
|
+
if (_updated) {
|
|
155
|
+
return Promise.resolve(true);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return (checking ??= (async () => {
|
|
159
|
+
try {
|
|
160
|
+
const res = await fetch(`${assets}/${__SVELTEKIT_APP_VERSION_FILE__}`, {
|
|
161
|
+
headers: {
|
|
162
|
+
'cache-control': 'no-cache'
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (!res.ok) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const data = await res.json();
|
|
171
|
+
return (_updated ||= data.version !== version);
|
|
172
|
+
} catch {
|
|
173
|
+
return false;
|
|
174
|
+
} finally {
|
|
175
|
+
checking = undefined;
|
|
176
|
+
if (interval && !_updated) timeout = window.setTimeout(updated.check, interval);
|
|
177
|
+
}
|
|
178
|
+
})());
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
if (!DEV && interval) {
|
|
183
|
+
timeout = window.setTimeout(updated.check, interval);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Mark `updated.current` as `true` if the given version differs from the one
|
|
188
|
+
* the app was hydrated with. Called from the server response header path.
|
|
189
|
+
* Does NOT reset the poll timer — unlike `check()`, this is a passive observation
|
|
190
|
+
* from a single server instance's response, not an explicit version check. The
|
|
191
|
+
* poll timer continues on its original schedule as a backstop. This is important
|
|
192
|
+
* for platforms that implement skew protection, where `x-sveltekit-version`
|
|
193
|
+
* may be out of date — in this case we still need to poll for `version.json`.
|
|
194
|
+
* @param {string | null} new_version
|
|
195
|
+
*/
|
|
196
|
+
export function notify_version(new_version) {
|
|
197
|
+
if (__SVELTEKIT_APP_VERSION_CHECKS_ENABLED__ && new_version) {
|
|
198
|
+
_updated ||= new_version !== version;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Used for testing
|
|
204
|
+
*/
|
|
205
|
+
export function reset_updated() {
|
|
206
|
+
_updated = false;
|
|
207
|
+
}
|