@sveltejs/kit 3.0.0-next.16 → 3.0.0-next.17
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_types/index.js +1 -0
- package/src/exports/hooks/sequence.js +2 -1
- package/src/exports/internal/server/index.js +2 -0
- package/src/exports/internal/server/telemetry.js +95 -0
- package/src/exports/public.d.ts +17 -6
- package/src/runtime/app/forms.js +51 -39
- package/src/runtime/app/navigation.js +1 -0
- package/src/runtime/client/client.js +203 -49
- package/src/runtime/client/constants.js +1 -0
- package/src/runtime/client/snapshots.js +147 -0
- package/src/runtime/props.svelte.js +1 -0
- package/src/runtime/server/index.js +3 -0
- package/src/runtime/server/page/actions.js +34 -6
- package/src/runtime/server/page/load_data.js +1 -2
- package/src/runtime/server/remote-functions.js +7 -4
- package/src/runtime/server/respond.js +6 -3
- package/src/runtime/server/state.js +0 -4
- package/src/types/internal.d.ts +0 -3
- package/src/utils/import.js +1 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +42 -14
- package/types/index.d.ts.map +4 -1
- package/src/runtime/telemetry/otel.js +0 -21
- package/src/runtime/telemetry/record_span.js +0 -65
package/package.json
CHANGED
|
@@ -232,6 +232,7 @@ function update_types(config, routes, route, root, to_delete = new Set()) {
|
|
|
232
232
|
'type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;',
|
|
233
233
|
|
|
234
234
|
// Re-export `Snapshot` from @sveltejs/kit — in future we could use this to infer <T> from the return type of `snapshot.capture`
|
|
235
|
+
'/** @deprecated Use the `snapshot` helper from `$app/navigation` instead. */',
|
|
235
236
|
'export type Snapshot<T = any> = Kit.Snapshot<T>;',
|
|
236
237
|
|
|
237
238
|
'export type ErrorProps = { error: App.Error };'
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
merge_tracing,
|
|
4
4
|
get_request_store,
|
|
5
|
+
record_span,
|
|
5
6
|
with_request_store
|
|
6
7
|
} from '@sveltejs/kit/internal/server';
|
|
7
8
|
|
|
@@ -95,7 +96,7 @@ export function sequence(...handlers) {
|
|
|
95
96
|
function apply_handle(i, event, parent_options) {
|
|
96
97
|
const handle = handlers[i];
|
|
97
98
|
|
|
98
|
-
return
|
|
99
|
+
return record_span({
|
|
99
100
|
name: `sveltekit.handle.sequenced.${handle.name ? handle.name : i}`,
|
|
100
101
|
attributes: {},
|
|
101
102
|
fn: async (current) => {
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** @import { Tracer, SpanStatusCode, PropagationAPI, ContextAPI } from '@opentelemetry/api' */
|
|
2
|
+
/** @import { RecordSpan } from 'types' */
|
|
3
|
+
import { HttpError, Redirect } from '../shared.js';
|
|
4
|
+
import { noop_span } from '../../../runtime/telemetry/noop.js';
|
|
5
|
+
|
|
6
|
+
// Import this module by its bare specifier so bundled and external code share its state.
|
|
7
|
+
|
|
8
|
+
/** @type {Promise<{ tracer: Tracer, SpanStatusCode: typeof SpanStatusCode, propagation: PropagationAPI, context: ContextAPI }> | null} */
|
|
9
|
+
export let otel = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The caller passes in `import('@opentelemetry/api')` so the import lives behind
|
|
13
|
+
* `__SVELTEKIT_SERVER_TRACING_ENABLED__` in the bundled runtime and is eliminated
|
|
14
|
+
* from builds with tracing disabled, where the package may not be installed.
|
|
15
|
+
* @param {Promise<typeof import('@opentelemetry/api')>} api
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
export function init_tracing(api) {
|
|
19
|
+
otel ??= api
|
|
20
|
+
.then((module) => {
|
|
21
|
+
return {
|
|
22
|
+
tracer: module.trace.getTracer('sveltekit'),
|
|
23
|
+
propagation: module.propagation,
|
|
24
|
+
context: module.context,
|
|
25
|
+
SpanStatusCode: module.SpanStatusCode
|
|
26
|
+
};
|
|
27
|
+
})
|
|
28
|
+
.catch(() => {
|
|
29
|
+
throw new Error(
|
|
30
|
+
'Tracing is enabled (see the SvelteKit plugin `tracing.server` option in your vite.config.js), but `@opentelemetry/api` is not available. This error will likely resolve itself when you set up your tracing instrumentation in `instrumentation.server.js`. For more information, see https://svelte.dev/docs/kit/observability#opentelemetry-api'
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @type {RecordSpan} */
|
|
36
|
+
export async function record_span({ name, attributes, fn }) {
|
|
37
|
+
if (otel === null) {
|
|
38
|
+
return fn(noop_span);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { SpanStatusCode, tracer } = await otel;
|
|
42
|
+
|
|
43
|
+
return tracer.startActiveSpan(name, { attributes }, async (span) => {
|
|
44
|
+
try {
|
|
45
|
+
return await fn(span);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error instanceof HttpError) {
|
|
48
|
+
span.setAttributes({
|
|
49
|
+
[`${name}.result.type`]: 'known_error',
|
|
50
|
+
[`${name}.result.status`]: error.status,
|
|
51
|
+
[`${name}.result.message`]: error.body.message
|
|
52
|
+
});
|
|
53
|
+
if (error.status >= 500) {
|
|
54
|
+
span.recordException({
|
|
55
|
+
name: 'HttpError',
|
|
56
|
+
message: error.body.message
|
|
57
|
+
});
|
|
58
|
+
span.setStatus({
|
|
59
|
+
code: SpanStatusCode.ERROR,
|
|
60
|
+
message: error.body.message
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} else if (error instanceof Redirect) {
|
|
64
|
+
span.setAttributes({
|
|
65
|
+
[`${name}.result.type`]: 'redirect',
|
|
66
|
+
[`${name}.result.status`]: error.status,
|
|
67
|
+
[`${name}.result.location`]: error.location
|
|
68
|
+
});
|
|
69
|
+
} else if (error instanceof Error) {
|
|
70
|
+
span.setAttributes({
|
|
71
|
+
[`${name}.result.type`]: 'unknown_error'
|
|
72
|
+
});
|
|
73
|
+
span.recordException({
|
|
74
|
+
name: error.name,
|
|
75
|
+
message: error.message,
|
|
76
|
+
// conditional so this compiles under consumers' `exactOptionalPropertyTypes`
|
|
77
|
+
...(error.stack !== undefined && { stack: error.stack })
|
|
78
|
+
});
|
|
79
|
+
span.setStatus({
|
|
80
|
+
code: SpanStatusCode.ERROR,
|
|
81
|
+
message: error.message
|
|
82
|
+
});
|
|
83
|
+
} else {
|
|
84
|
+
span.setAttributes({
|
|
85
|
+
[`${name}.result.type`]: 'unknown_error'
|
|
86
|
+
});
|
|
87
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
throw error;
|
|
91
|
+
} finally {
|
|
92
|
+
span.end();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
package/src/exports/public.d.ts
CHANGED
|
@@ -1941,15 +1941,20 @@ export type Actions<
|
|
|
1941
1941
|
* };
|
|
1942
1942
|
* }}
|
|
1943
1943
|
* ```
|
|
1944
|
+
*
|
|
1945
|
+
* Success and failure results carry the root-relative `pathname + search` of the action URL, with
|
|
1946
|
+
* the `?/actionName` parameter removed. Redirect results carry the redirect target. Server-generated
|
|
1947
|
+
* error results also carry the action location, while client-generated errors such as network
|
|
1948
|
+
* failures do not. `update` uses this location to emulate native form navigation.
|
|
1944
1949
|
*/
|
|
1945
1950
|
export type ActionResult<
|
|
1946
1951
|
Success extends Record<string, unknown> | undefined = Record<string, any>,
|
|
1947
1952
|
Failure extends Record<string, unknown> | undefined = Record<string, any>
|
|
1948
1953
|
> =
|
|
1949
|
-
| { type: 'success'; status: number; data?: Success }
|
|
1950
|
-
| { type: 'failure'; status: number; data?: Failure }
|
|
1954
|
+
| { type: 'success'; status: number; data?: Success; location: string }
|
|
1955
|
+
| { type: 'failure'; status: number; data?: Failure; location: string }
|
|
1951
1956
|
| { type: 'redirect'; status: number; location: string }
|
|
1952
|
-
| { type: 'error'; status?: number; error: App.Error };
|
|
1957
|
+
| { type: 'error'; status?: number; error: App.Error; location?: string };
|
|
1953
1958
|
|
|
1954
1959
|
/**
|
|
1955
1960
|
* The object returned by the [`error`](https://svelte.dev/docs/kit/@sveltejs-kit#error) function.
|
|
@@ -1990,15 +1995,21 @@ export type SubmitFunction<
|
|
|
1990
1995
|
result: ActionResult<Success, Failure>;
|
|
1991
1996
|
/**
|
|
1992
1997
|
* Call this to get the default behavior of a form submission response.
|
|
1993
|
-
* @param options Set `reset: false` if you don't want the `<form>` values to be reset after a successful submission.
|
|
1994
|
-
* @param invalidateAll Set `invalidateAll: false` if you don't want the action to call `invalidateAll` after submission.
|
|
1998
|
+
* @param options Set `reset: false` if you don't want the `<form>` values to be reset after a successful submission. `refreshAll` defaults to `true` for successful results and `false` for failures. When the submission navigates, setting it to `false` still runs the destination's `load` functions but may reuse shared layout data. Set `navigate: false` to apply non-redirect results to the current page instead of navigating to `result.location`. Redirects are always followed.
|
|
1995
1999
|
*/
|
|
1996
|
-
update: (options?: {
|
|
2000
|
+
update: (options?: {
|
|
2001
|
+
reset?: boolean;
|
|
2002
|
+
refreshAll?: boolean;
|
|
2003
|
+
navigate?: boolean;
|
|
2004
|
+
/** @deprecated Use `refreshAll` instead. */
|
|
2005
|
+
invalidateAll?: boolean;
|
|
2006
|
+
}) => Promise<void>;
|
|
1997
2007
|
}) => MaybePromise<void>)
|
|
1998
2008
|
>;
|
|
1999
2009
|
|
|
2000
2010
|
/**
|
|
2001
2011
|
* The type of `export const snapshot` exported from a page or layout component.
|
|
2012
|
+
* @deprecated Use the [`snapshot`](https://svelte.dev/docs/kit/$app-navigation#snapshot) helper from `$app/navigation` instead.
|
|
2002
2013
|
*/
|
|
2003
2014
|
export interface Snapshot<T = any> {
|
|
2004
2015
|
capture: () => T;
|
package/src/runtime/app/forms.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { DEV } from 'esm-env';
|
|
2
2
|
import { noop } from '../../utils/functions.js';
|
|
3
3
|
import { refreshAll } from './navigation.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
applyAction,
|
|
6
|
+
apply_action_navigation,
|
|
7
|
+
handle_error,
|
|
8
|
+
is_current_location
|
|
9
|
+
} from '../client/client.js';
|
|
5
10
|
import { notify_version } from '../client/state.svelte.js';
|
|
6
11
|
import { parse } from '#app/internal/transport';
|
|
7
12
|
|
|
@@ -30,10 +35,6 @@ export { applyAction };
|
|
|
30
35
|
* @returns {import('@sveltejs/kit').ActionResult<Success, Failure>}
|
|
31
36
|
*/
|
|
32
37
|
export function deserialize(result) {
|
|
33
|
-
if (result === '') {
|
|
34
|
-
return { type: 'success', status: 204, data: undefined };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
38
|
const parsed = JSON.parse(result);
|
|
38
39
|
|
|
39
40
|
if (parsed.data) {
|
|
@@ -63,17 +64,18 @@ function clone(element) {
|
|
|
63
64
|
* If a function is returned, that function is called with the response from the server.
|
|
64
65
|
* If nothing is returned, the fallback will be used.
|
|
65
66
|
*
|
|
66
|
-
* If this function or its return value isn't set, it
|
|
67
|
-
* -
|
|
68
|
-
* - updates `page.status`
|
|
69
|
-
* -
|
|
67
|
+
* If this function or its return value isn't set, it emulates the browser-native behaviour, just without the full-page reload. It
|
|
68
|
+
* - resets the `<form>` element and refreshes all data in case of a successful submission with no redirect response
|
|
69
|
+
* - updates the `form` prop, `page.form` and `page.status` if the action is on the same page as the form
|
|
70
|
+
* - 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
|
|
70
71
|
* - redirects in case of a redirect response
|
|
71
|
-
* -
|
|
72
|
+
* - 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
|
|
72
73
|
*
|
|
73
74
|
* If you provide a custom function with a callback and want to use the default behavior, invoke `update` in your callback.
|
|
74
75
|
* It accepts an options object
|
|
75
76
|
* - `reset: false` if you don't want the `<form>` values to be reset after a successful submission
|
|
76
|
-
* - `
|
|
77
|
+
* - `refreshAll` to control whether all data is refreshed after submission; it defaults to `true` for successes and `false` for failures
|
|
78
|
+
* - `navigate: false` to apply non-redirect results to the current page rather than navigating to `result.location`; redirects are always followed
|
|
77
79
|
* @template {Record<string, unknown> | undefined} Success
|
|
78
80
|
* @template {Record<string, unknown> | undefined} Failure
|
|
79
81
|
* @param {HTMLFormElement} form_element The form element
|
|
@@ -86,37 +88,50 @@ export function enhance(form_element, submit = noop) {
|
|
|
86
88
|
|
|
87
89
|
/**
|
|
88
90
|
* @param {{
|
|
89
|
-
* action: URL;
|
|
90
|
-
* invalidateAll?: boolean;
|
|
91
91
|
* result: import('@sveltejs/kit').ActionResult;
|
|
92
|
-
* reset?: boolean
|
|
92
|
+
* reset?: boolean;
|
|
93
|
+
* refreshAll?: boolean;
|
|
94
|
+
* invalidateAll?: boolean;
|
|
95
|
+
* navigate?: boolean;
|
|
93
96
|
* }} opts
|
|
94
97
|
*/
|
|
95
98
|
const fallback_callback = async ({
|
|
96
|
-
action,
|
|
97
99
|
result,
|
|
98
100
|
reset = true,
|
|
99
|
-
|
|
101
|
+
refreshAll: should_refresh_all,
|
|
102
|
+
invalidateAll: deprecated_invalidate_all,
|
|
103
|
+
navigate = true
|
|
100
104
|
}) => {
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
if (DEV && deprecated_invalidate_all !== undefined) {
|
|
106
|
+
console.warn(
|
|
107
|
+
'The `update({ invalidateAll })` option has been deprecated in favour of `update({ refreshAll })`'
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
should_refresh_all ??= deprecated_invalidate_all ?? result.type === 'success';
|
|
112
|
+
|
|
113
|
+
if (result.type === 'success' && reset) {
|
|
114
|
+
// We call reset from the prototype to avoid DOM clobbering
|
|
115
|
+
HTMLFormElement.prototype.reset.call(form_element);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const destination =
|
|
119
|
+
navigate && result.type !== 'redirect' && !is_current_location(result.location)
|
|
120
|
+
? result.location
|
|
121
|
+
: undefined;
|
|
122
|
+
|
|
123
|
+
if (destination === undefined) {
|
|
124
|
+
if (should_refresh_all && result.type !== 'redirect') {
|
|
107
125
|
await refreshAll();
|
|
108
126
|
}
|
|
109
|
-
}
|
|
110
127
|
|
|
111
|
-
// For success/failure results, only apply action if it belongs to the
|
|
112
|
-
// current page, otherwise `form` will be updated erroneously
|
|
113
|
-
if (
|
|
114
|
-
location.origin + location.pathname === action.origin + action.pathname ||
|
|
115
|
-
result.type === 'redirect' ||
|
|
116
|
-
result.type === 'error'
|
|
117
|
-
) {
|
|
118
128
|
await applyAction(result);
|
|
129
|
+
return;
|
|
119
130
|
}
|
|
131
|
+
|
|
132
|
+
// emulate the browser: navigate to where the submission lands, rendering that
|
|
133
|
+
// page with this result
|
|
134
|
+
await apply_action_navigation(destination, result, should_refresh_all);
|
|
120
135
|
};
|
|
121
136
|
|
|
122
137
|
/** @param {SubmitEvent} event */
|
|
@@ -202,13 +217,9 @@ export function enhance(form_element, submit = noop) {
|
|
|
202
217
|
// detect new deployments from the response header
|
|
203
218
|
notify_version(response.headers.get('x-sveltekit-version'));
|
|
204
219
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
result = deserialize(await response.text());
|
|
209
|
-
if (result.type === 'error' || result.type === 'failure') {
|
|
210
|
-
result.status = response.status;
|
|
211
|
-
}
|
|
220
|
+
result = deserialize(await response.text());
|
|
221
|
+
if (result.type === 'error' || result.type === 'failure') {
|
|
222
|
+
result.status = response.status;
|
|
212
223
|
}
|
|
213
224
|
} catch (error) {
|
|
214
225
|
if (/** @type {any} */ (error)?.name === 'AbortError') return;
|
|
@@ -228,10 +239,11 @@ export function enhance(form_element, submit = noop) {
|
|
|
228
239
|
formElement: form_element,
|
|
229
240
|
update: (opts) =>
|
|
230
241
|
fallback_callback({
|
|
231
|
-
action,
|
|
232
242
|
result,
|
|
233
243
|
reset: opts?.reset,
|
|
234
|
-
|
|
244
|
+
refreshAll: opts?.refreshAll,
|
|
245
|
+
invalidateAll: opts?.invalidateAll,
|
|
246
|
+
navigate: opts?.navigate
|
|
235
247
|
}),
|
|
236
248
|
// @ts-expect-error generic constraints stuff we don't care about
|
|
237
249
|
result
|