@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21
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 +62 -36
- package/src/cli.js +15 -12
- package/src/constants.js +6 -1
- package/src/core/adapt/builder.js +66 -72
- package/src/core/adapt/index.js +17 -6
- package/src/core/config/index.js +134 -80
- package/src/core/config/options.js +295 -273
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +146 -16
- package/src/core/generate_manifest/index.js +18 -15
- package/src/core/postbuild/analyse.js +8 -20
- package/src/core/postbuild/crawl.js +22 -6
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +4 -2
- package/src/core/postbuild/prerender.js +222 -70
- package/src/core/postbuild/queue.js +2 -1
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +82 -62
- package/src/core/sync/sync.js +40 -31
- package/src/core/sync/ts.js +1 -1
- package/src/core/sync/utils.js +22 -2
- package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
- package/src/core/sync/write_client_manifest.js +14 -29
- package/src/core/sync/write_env.js +7 -5
- package/src/core/sync/write_server.js +37 -45
- package/src/core/sync/write_tsconfig/index.js +274 -0
- package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
- package/src/core/sync/write_tsconfig/utils.js +77 -0
- package/src/core/sync/write_tsconfig/validate.js +128 -0
- package/src/core/sync/write_types/index.js +127 -123
- package/src/core/utils.js +30 -5
- package/src/exports/env/index.js +77 -0
- package/src/exports/env/public.d.ts +55 -0
- package/src/exports/hooks/index.js +3 -9
- package/src/exports/hooks/public.d.ts +195 -0
- package/src/exports/hooks/sequence.js +9 -6
- package/src/exports/index.js +52 -29
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/env.js +8 -5
- package/src/exports/internal/index.js +1 -90
- package/src/exports/internal/{event.js → server/event.js} +2 -3
- package/src/exports/internal/server/index.js +37 -0
- package/src/exports/internal/server/telemetry.js +95 -0
- package/src/exports/internal/shared.js +90 -0
- package/src/exports/node/index.js +64 -22
- package/src/exports/params/index.js +70 -0
- package/src/exports/params/public.d.ts +63 -0
- package/src/exports/public.d.ts +50 -1733
- package/src/exports/remote/index.js +11 -0
- package/src/exports/remote/public.d.ts +519 -0
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +54 -65
- package/src/exports/vite/build/remote.js +24 -19
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/dev/index.js +218 -146
- package/src/exports/vite/index.js +1590 -858
- package/src/exports/vite/module_ids.js +2 -2
- package/src/exports/vite/preview/index.js +40 -32
- package/src/exports/vite/public.d.ts +588 -0
- package/src/exports/vite/utils.js +84 -46
- package/src/pathname.js +55 -0
- package/src/runner.js +15 -0
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/env/types.d.ts +1 -1
- package/src/runtime/app/environment/index.js +3 -3
- package/src/runtime/app/{forms.js → forms/index.js} +73 -42
- package/src/runtime/app/forms/public.d.ts +2 -0
- package/src/runtime/app/forms/types.d.ts +56 -0
- package/src/runtime/app/internal/transport.js +53 -0
- package/src/runtime/app/manifest/index.js +1 -0
- package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
- package/src/runtime/app/navigation/public.d.ts +237 -0
- package/src/runtime/app/paths/client.js +37 -37
- package/src/runtime/app/paths/index.js +1 -1
- package/src/runtime/app/paths/internal/client.js +34 -2
- package/src/runtime/app/paths/internal/server.js +6 -23
- package/src/runtime/app/paths/internal.d.ts +3 -0
- package/src/runtime/app/paths/public.d.ts +1 -29
- package/src/runtime/app/paths/server.js +36 -17
- package/src/runtime/app/paths/types.d.ts +11 -19
- package/src/runtime/app/server/index.js +2 -2
- package/src/runtime/app/server/public.d.ts +201 -0
- package/src/runtime/app/server/remote/command.js +13 -11
- package/src/runtime/app/server/remote/form.js +61 -39
- package/src/runtime/app/server/remote/prerender.js +45 -45
- package/src/runtime/app/server/remote/query.js +106 -108
- package/src/runtime/app/server/remote/requested.js +27 -19
- package/src/runtime/app/server/remote/shared.js +76 -76
- package/src/runtime/app/service-worker/index.js +24 -0
- package/src/runtime/app/state/client.js +4 -2
- package/src/runtime/app/state/index.js +7 -5
- package/src/runtime/app/state/public.d.ts +72 -0
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/app/stores.js +15 -78
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +1336 -648
- package/src/runtime/client/constants.js +3 -6
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/fetcher.js +25 -25
- package/src/runtime/client/ndjson.js +1 -1
- package/src/runtime/client/parse.js +1 -1
- package/src/runtime/client/payload.js +17 -0
- package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
- package/src/runtime/client/remote-functions/command.svelte.js +37 -61
- package/src/runtime/client/remote-functions/form.svelte.js +267 -178
- package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
- package/src/runtime/client/remote-functions/query/index.js +10 -17
- package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
- package/src/runtime/client/remote-functions/query/proxy.js +5 -5
- package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
- package/src/runtime/client/remote-functions/query-live/index.js +1 -1
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
- package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
- package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
- package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
- package/src/runtime/client/snapshots.js +147 -0
- package/src/runtime/client/state.svelte.js +94 -55
- package/src/runtime/client/stream.js +3 -2
- package/src/runtime/client/types.d.ts +13 -9
- package/src/runtime/client/utils.js +22 -110
- package/src/runtime/components/root.svelte +56 -0
- package/src/runtime/env/dynamic/private.js +7 -0
- package/src/runtime/env/dynamic/public.js +7 -0
- package/src/runtime/env/static/private.js +6 -0
- package/src/runtime/env/static/public.js +6 -0
- package/src/runtime/form-utils.js +172 -61
- package/src/runtime/pathname.js +20 -32
- package/src/runtime/props.svelte.js +72 -0
- package/src/runtime/server/constants.js +0 -3
- package/src/runtime/server/cookie.js +72 -55
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +49 -53
- package/src/runtime/server/dev.js +22 -0
- package/src/runtime/server/endpoint.js +6 -7
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/errors.js +160 -0
- package/src/runtime/server/fetch.js +32 -39
- package/src/runtime/server/index.js +90 -64
- package/src/runtime/server/internal.js +71 -0
- package/src/runtime/server/page/actions.js +85 -64
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +88 -104
- package/src/runtime/server/page/data_serializer.js +24 -25
- package/src/runtime/server/page/index.js +36 -53
- package/src/runtime/server/page/load_data.js +50 -57
- package/src/runtime/server/page/render.js +173 -239
- package/src/runtime/server/page/respond_with_error.js +17 -31
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +85 -26
- package/src/runtime/server/remote-functions.js +640 -0
- package/src/runtime/server/respond.js +190 -131
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/state.js +53 -0
- package/src/runtime/server/utils.js +13 -155
- package/src/runtime/shared.js +20 -40
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +11 -1
- package/src/types/ambient.d.ts +87 -36
- package/src/types/global-private.d.ts +25 -25
- package/src/types/internal.d.ts +163 -157
- package/src/types/private.d.ts +41 -1
- package/src/utils/error.js +28 -4
- package/src/utils/escape.js +9 -25
- package/src/utils/features.js +1 -1
- package/src/utils/filesystem.js +1 -23
- package/src/utils/fork.js +7 -2
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +9 -2
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- package/src/utils/page_nodes.js +6 -7
- package/src/utils/params.js +67 -0
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +145 -73
- package/src/utils/shared-iterator.js +5 -0
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +33 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +2616 -2433
- package/types/index.d.ts.map +120 -106
- package/src/core/sync/write_ambient.js +0 -18
- package/src/core/sync/write_root.js +0 -148
- package/src/core/sync/write_tsconfig.js +0 -250
- package/src/exports/internal/server.js +0 -22
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/server/app.js +0 -9
- package/src/runtime/server/remote.js +0 -457
- package/src/runtime/shared-server.js +0 -7
- package/src/runtime/telemetry/otel.js +0 -21
- package/src/runtime/telemetry/record_span.js +0 -65
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
- /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
/** @import {
|
|
2
|
-
/** @import {
|
|
3
|
-
import
|
|
1
|
+
/** @import { Actions } from '@sveltejs/kit' */
|
|
2
|
+
/** @import { RequestEvent } from '$app/server' */
|
|
3
|
+
/** @import { ActionResult } from '$app/forms' */
|
|
4
|
+
/** @import { SSROptions, SSRNode, ServerNode } from 'types' */
|
|
4
5
|
import { DEV } from 'esm-env';
|
|
5
6
|
import { json } from '@sveltejs/kit';
|
|
6
7
|
import { HttpError, Redirect, ActionFailure, SvelteKitError } from '@sveltejs/kit/internal';
|
|
7
|
-
import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server';
|
|
8
|
-
import {
|
|
8
|
+
import { with_request_store, merge_tracing, record_span } from '@sveltejs/kit/internal/server';
|
|
9
|
+
import { normalize_error } from '../../../utils/error.js';
|
|
9
10
|
import { is_form_content_type, negotiate } from '../../../utils/http.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
11
|
+
import { with_version_header } from '../utils.js';
|
|
12
|
+
import { handle_error_and_jsonify } from '../errors.js';
|
|
13
|
+
import { stringify, uneval } from '#app/internal/transport';
|
|
12
14
|
|
|
13
15
|
/** @param {RequestEvent} event */
|
|
14
16
|
export function is_action_json_request(event) {
|
|
@@ -22,12 +24,13 @@ export function is_action_json_request(event) {
|
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* @param {RequestEvent} event
|
|
25
|
-
* @param {import('types').RequestState}
|
|
27
|
+
* @param {import('types').RequestState} state
|
|
26
28
|
* @param {SSROptions} options
|
|
27
29
|
* @param {SSRNode['server'] | undefined} server
|
|
28
30
|
*/
|
|
29
|
-
export async function handle_action_json_request(event,
|
|
31
|
+
export async function handle_action_json_request(event, state, options, server) {
|
|
30
32
|
const actions = server?.actions;
|
|
33
|
+
const location = get_action_location(event.url);
|
|
31
34
|
|
|
32
35
|
if (!actions) {
|
|
33
36
|
const no_actions_error = new SvelteKitError(
|
|
@@ -36,13 +39,16 @@ export async function handle_action_json_request(event, event_state, options, se
|
|
|
36
39
|
`POST method not allowed. No form actions exist for ${DEV ? `the page at ${event.route.id}` : 'this page'}`
|
|
37
40
|
);
|
|
38
41
|
|
|
42
|
+
const error = await handle_error_and_jsonify(event, state, options, no_actions_error);
|
|
43
|
+
|
|
39
44
|
return action_json(
|
|
40
45
|
{
|
|
41
46
|
type: 'error',
|
|
42
|
-
error
|
|
47
|
+
error,
|
|
48
|
+
location
|
|
43
49
|
},
|
|
44
50
|
{
|
|
45
|
-
status:
|
|
51
|
+
status: error.status,
|
|
46
52
|
headers: {
|
|
47
53
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
|
|
48
54
|
// "The server must generate an Allow header field in a 405 status code response"
|
|
@@ -55,35 +61,40 @@ export async function handle_action_json_request(event, event_state, options, se
|
|
|
55
61
|
check_named_default_separate(actions);
|
|
56
62
|
|
|
57
63
|
try {
|
|
58
|
-
const data = await call_action(event,
|
|
64
|
+
const data = await call_action(event, state, actions);
|
|
59
65
|
|
|
60
66
|
if (DEV) {
|
|
61
67
|
validate_action_return(data);
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
if (data instanceof ActionFailure) {
|
|
71
|
+
return action_json(
|
|
72
|
+
{
|
|
73
|
+
type: 'failure',
|
|
74
|
+
status: data.status,
|
|
75
|
+
location,
|
|
76
|
+
// @ts-expect-error we assign a string to what is supposed to be an object. That's ok
|
|
77
|
+
// because we don't use the object outside, and this way we have better code navigation
|
|
78
|
+
// through knowing where the related interface is used.
|
|
79
|
+
data: try_serialize(data.data, stringify, /** @type {string} */ (event.route.id))
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
status: data.status
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
} else if (data) {
|
|
65
86
|
return action_json({
|
|
66
|
-
type: '
|
|
67
|
-
status:
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
data: stringify_action_response(
|
|
72
|
-
data.data,
|
|
73
|
-
/** @type {string} */ (event.route.id),
|
|
74
|
-
options.hooks.transport
|
|
75
|
-
)
|
|
87
|
+
type: 'success',
|
|
88
|
+
status: 200,
|
|
89
|
+
location,
|
|
90
|
+
// @ts-expect-error see comment above
|
|
91
|
+
data: try_serialize(data, stringify, /** @type {string} */ (event.route.id))
|
|
76
92
|
});
|
|
77
93
|
} else {
|
|
78
94
|
return action_json({
|
|
79
95
|
type: 'success',
|
|
80
|
-
status:
|
|
81
|
-
|
|
82
|
-
data: stringify_action_response(
|
|
83
|
-
data,
|
|
84
|
-
/** @type {string} */ (event.route.id),
|
|
85
|
-
options.hooks.transport
|
|
86
|
-
)
|
|
96
|
+
status: 204,
|
|
97
|
+
location
|
|
87
98
|
});
|
|
88
99
|
}
|
|
89
100
|
} catch (e) {
|
|
@@ -93,23 +104,42 @@ export async function handle_action_json_request(event, event_state, options, se
|
|
|
93
104
|
return action_json_redirect(err);
|
|
94
105
|
}
|
|
95
106
|
|
|
107
|
+
const transformed = await handle_error_and_jsonify(
|
|
108
|
+
event,
|
|
109
|
+
state,
|
|
110
|
+
options,
|
|
111
|
+
check_incorrect_fail_use(err)
|
|
112
|
+
);
|
|
113
|
+
|
|
96
114
|
return action_json(
|
|
97
115
|
{
|
|
98
116
|
type: 'error',
|
|
99
|
-
error:
|
|
100
|
-
|
|
101
|
-
event_state,
|
|
102
|
-
options,
|
|
103
|
-
check_incorrect_fail_use(err)
|
|
104
|
-
)
|
|
117
|
+
error: transformed,
|
|
118
|
+
location
|
|
105
119
|
},
|
|
106
120
|
{
|
|
107
|
-
status:
|
|
121
|
+
status: transformed.status
|
|
108
122
|
}
|
|
109
123
|
);
|
|
110
124
|
}
|
|
111
125
|
}
|
|
112
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @param {URL} url
|
|
129
|
+
*/
|
|
130
|
+
export function get_action_location(url) {
|
|
131
|
+
const location = new URL(url);
|
|
132
|
+
|
|
133
|
+
for (const key of location.searchParams.keys()) {
|
|
134
|
+
if (key.startsWith('/')) {
|
|
135
|
+
location.searchParams.delete(key);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return location.pathname + location.search;
|
|
141
|
+
}
|
|
142
|
+
|
|
113
143
|
/**
|
|
114
144
|
* @param {HttpError | Error} error
|
|
115
145
|
*/
|
|
@@ -135,7 +165,7 @@ export function action_json_redirect(redirect) {
|
|
|
135
165
|
* @param {ResponseInit} [init]
|
|
136
166
|
*/
|
|
137
167
|
function action_json(data, init) {
|
|
138
|
-
return json(data, init);
|
|
168
|
+
return with_version_header(json(data, init));
|
|
139
169
|
}
|
|
140
170
|
|
|
141
171
|
/**
|
|
@@ -147,12 +177,13 @@ export function is_action_request(event) {
|
|
|
147
177
|
|
|
148
178
|
/**
|
|
149
179
|
* @param {RequestEvent} event
|
|
150
|
-
* @param {import('types').RequestState}
|
|
180
|
+
* @param {import('types').RequestState} state
|
|
151
181
|
* @param {SSRNode['server'] | undefined} server
|
|
152
182
|
* @returns {Promise<ActionResult>}
|
|
153
183
|
*/
|
|
154
|
-
export async function handle_action_request(event,
|
|
184
|
+
export async function handle_action_request(event, state, server) {
|
|
155
185
|
const actions = server?.actions;
|
|
186
|
+
const location = get_action_location(event.url);
|
|
156
187
|
|
|
157
188
|
if (!actions) {
|
|
158
189
|
// TODO should this be a different error altogether?
|
|
@@ -163,6 +194,8 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
163
194
|
});
|
|
164
195
|
return {
|
|
165
196
|
type: 'error',
|
|
197
|
+
location,
|
|
198
|
+
// We're lying a bit with the types here; this will be transformed into a proper App.Error object later
|
|
166
199
|
error: new SvelteKitError(
|
|
167
200
|
405,
|
|
168
201
|
'Method Not Allowed',
|
|
@@ -174,7 +207,7 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
174
207
|
check_named_default_separate(actions);
|
|
175
208
|
|
|
176
209
|
try {
|
|
177
|
-
const data = await call_action(event,
|
|
210
|
+
const data = await call_action(event, state, actions);
|
|
178
211
|
|
|
179
212
|
if (DEV) {
|
|
180
213
|
validate_action_return(data);
|
|
@@ -184,12 +217,14 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
184
217
|
return {
|
|
185
218
|
type: 'failure',
|
|
186
219
|
status: data.status,
|
|
220
|
+
location,
|
|
187
221
|
data: data.data
|
|
188
222
|
};
|
|
189
223
|
} else {
|
|
190
224
|
return {
|
|
191
225
|
type: 'success',
|
|
192
226
|
status: 200,
|
|
227
|
+
location,
|
|
193
228
|
// @ts-expect-error this will be removed upon serialization, so `undefined` is the same as omission
|
|
194
229
|
data
|
|
195
230
|
};
|
|
@@ -207,6 +242,8 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
207
242
|
|
|
208
243
|
return {
|
|
209
244
|
type: 'error',
|
|
245
|
+
location,
|
|
246
|
+
// @ts-expect-error We're lying a bit with the types here; this will be transformed into a proper App.Error object later
|
|
210
247
|
error: check_incorrect_fail_use(err)
|
|
211
248
|
};
|
|
212
249
|
}
|
|
@@ -225,11 +262,11 @@ function check_named_default_separate(actions) {
|
|
|
225
262
|
|
|
226
263
|
/**
|
|
227
264
|
* @param {RequestEvent} event
|
|
228
|
-
* @param {import('types').RequestState}
|
|
265
|
+
* @param {import('types').RequestState} state
|
|
229
266
|
* @param {NonNullable<ServerNode['actions']>} actions
|
|
230
267
|
* @throws {Redirect | HttpError | SvelteKitError | Error}
|
|
231
268
|
*/
|
|
232
|
-
async function call_action(event,
|
|
269
|
+
async function call_action(event, state, actions) {
|
|
233
270
|
const url = new URL(event.request.url);
|
|
234
271
|
|
|
235
272
|
let name = 'default';
|
|
@@ -243,11 +280,12 @@ async function call_action(event, event_state, actions) {
|
|
|
243
280
|
}
|
|
244
281
|
}
|
|
245
282
|
|
|
246
|
-
|
|
247
|
-
if (!action) {
|
|
283
|
+
if (!Object.hasOwn(actions, name)) {
|
|
248
284
|
throw new SvelteKitError(404, 'Not Found', `No action with name '${name}' found`);
|
|
249
285
|
}
|
|
250
286
|
|
|
287
|
+
const action = actions[name];
|
|
288
|
+
|
|
251
289
|
if (!is_form_content_type(event.request)) {
|
|
252
290
|
throw new SvelteKitError(
|
|
253
291
|
415,
|
|
@@ -267,7 +305,7 @@ async function call_action(event, event_state, actions) {
|
|
|
267
305
|
fn: async (current) => {
|
|
268
306
|
const traced_event = merge_tracing(event, current);
|
|
269
307
|
|
|
270
|
-
const result = await with_request_store({ event: traced_event, state
|
|
308
|
+
const result = await with_request_store({ event: traced_event, state }, () =>
|
|
271
309
|
action(traced_event)
|
|
272
310
|
);
|
|
273
311
|
|
|
@@ -298,26 +336,9 @@ function validate_action_return(data) {
|
|
|
298
336
|
* Try to `devalue.uneval` the data object, and if it fails, return a proper Error with context
|
|
299
337
|
* @param {any} data
|
|
300
338
|
* @param {string} route_id
|
|
301
|
-
* @param {ServerHooks['transport']} transport
|
|
302
339
|
*/
|
|
303
|
-
export function uneval_action_response(data, route_id
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return try_serialize(data, (value) => devalue.uneval(value, replacer), route_id);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Try to `devalue.stringify` the data object, and if it fails, return a proper Error with context
|
|
311
|
-
* @param {any} data
|
|
312
|
-
* @param {string} route_id
|
|
313
|
-
* @param {ServerHooks['transport']} transport
|
|
314
|
-
*/
|
|
315
|
-
function stringify_action_response(data, route_id, transport) {
|
|
316
|
-
const encoders = Object.fromEntries(
|
|
317
|
-
Object.entries(transport).map(([key, value]) => [key, value.encode])
|
|
318
|
-
);
|
|
319
|
-
|
|
320
|
-
return try_serialize(data, (value) => devalue.stringify(value, encoders), route_id);
|
|
340
|
+
export function uneval_action_response(data, route_id) {
|
|
341
|
+
return try_serialize(data, uneval, route_id);
|
|
321
342
|
}
|
|
322
343
|
|
|
323
344
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { text_encoder } from '../../utils.js';
|
|
1
|
+
import { base64_encode, text_encoder } from '../../utils.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* SHA-256 hashing function adapted from https://bitwiseshiftleft.github.io/sjcl
|
|
@@ -102,7 +102,7 @@ export function sha256(data) {
|
|
|
102
102
|
const bytes = new Uint8Array(out.buffer);
|
|
103
103
|
reverse_endianness(bytes);
|
|
104
104
|
|
|
105
|
-
return
|
|
105
|
+
return base64_encode(bytes);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/** The SHA-256 initialization vector */
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { escape_html } from '../../../utils/escape.js';
|
|
2
|
+
import { base64_encode } from '../../utils.js';
|
|
2
3
|
import { sha256 } from './crypto.js';
|
|
3
4
|
|
|
4
5
|
const array = new Uint8Array(16);
|
|
5
6
|
|
|
6
7
|
function generate_nonce() {
|
|
7
8
|
crypto.getRandomValues(array);
|
|
8
|
-
return
|
|
9
|
+
return base64_encode(array);
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
const quoted = new Set([
|
|
@@ -53,19 +54,19 @@ class BaseProvider {
|
|
|
53
54
|
#directives;
|
|
54
55
|
|
|
55
56
|
/** @type {Set<import('types').Csp.Source>} */
|
|
56
|
-
#script_src;
|
|
57
|
+
#script_src = new Set();
|
|
57
58
|
|
|
58
59
|
/** @type {Set<import('types').Csp.Source>} */
|
|
59
|
-
#script_src_elem;
|
|
60
|
+
#script_src_elem = new Set();
|
|
60
61
|
|
|
61
62
|
/** @type {Set<import('types').Csp.Source>} */
|
|
62
|
-
#style_src;
|
|
63
|
+
#style_src = new Set();
|
|
63
64
|
|
|
64
65
|
/** @type {Set<import('types').Csp.Source>} */
|
|
65
|
-
#style_src_attr;
|
|
66
|
+
#style_src_attr = new Set();
|
|
66
67
|
|
|
67
68
|
/** @type {Set<import('types').Csp.Source>} */
|
|
68
|
-
#style_src_elem;
|
|
69
|
+
#style_src_elem = new Set();
|
|
69
70
|
|
|
70
71
|
/** @type {boolean} */
|
|
71
72
|
script_needs_nonce;
|
|
@@ -90,12 +91,6 @@ class BaseProvider {
|
|
|
90
91
|
|
|
91
92
|
const d = this.#directives;
|
|
92
93
|
|
|
93
|
-
this.#script_src = new Set();
|
|
94
|
-
this.#script_src_elem = new Set();
|
|
95
|
-
this.#style_src = new Set();
|
|
96
|
-
this.#style_src_attr = new Set();
|
|
97
|
-
this.#style_src_elem = new Set();
|
|
98
|
-
|
|
99
94
|
const effective_script_src = d['script-src'] || d['default-src'];
|
|
100
95
|
const script_src_elem = d['script-src-elem'];
|
|
101
96
|
const effective_style_src = d['style-src'] || d['default-src'];
|
|
@@ -117,32 +112,25 @@ class BaseProvider {
|
|
|
117
112
|
|
|
118
113
|
// ...and add unsafe-inline so we can inject <style> elements
|
|
119
114
|
// Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list, so we remove those during dev when injecting unsafe-inline
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
d['style-src-elem'] = [
|
|
140
|
-
...style_src_elem.filter(
|
|
141
|
-
(value) => !(value.startsWith('sha256-') || value.startsWith('nonce-'))
|
|
142
|
-
),
|
|
143
|
-
'unsafe-inline'
|
|
144
|
-
];
|
|
145
|
-
}
|
|
115
|
+
/**
|
|
116
|
+
* @template {'style-src' | 'style-src-attr' | 'style-src-elem'} K
|
|
117
|
+
* @param {K} key
|
|
118
|
+
* @param {import('types').CspDirectives[K]} directive
|
|
119
|
+
*/
|
|
120
|
+
const add_unsafe_inline = (key, directive) => {
|
|
121
|
+
if (directive && !directive.includes('unsafe-inline')) {
|
|
122
|
+
d[key] = /** @type {import('types').CspDirectives[K]} */ ([
|
|
123
|
+
...directive.filter(
|
|
124
|
+
(value) => !(value.startsWith('sha256-') || value.startsWith('nonce-'))
|
|
125
|
+
),
|
|
126
|
+
'unsafe-inline'
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
add_unsafe_inline('style-src', effective_style_src);
|
|
132
|
+
add_unsafe_inline('style-src-attr', style_src_attr);
|
|
133
|
+
add_unsafe_inline('style-src-elem', style_src_elem);
|
|
146
134
|
}
|
|
147
135
|
|
|
148
136
|
/** @param {(import('types').Csp.Source | import('types').Csp.ActionSource)[] | undefined} directive */
|
|
@@ -175,13 +163,16 @@ class BaseProvider {
|
|
|
175
163
|
this.#nonce = nonce;
|
|
176
164
|
}
|
|
177
165
|
|
|
178
|
-
/**
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
166
|
+
/**
|
|
167
|
+
* @param {string} content
|
|
168
|
+
* @returns {`nonce-${string}` | `sha256-${string}`}
|
|
169
|
+
*/
|
|
170
|
+
#get_source(content) {
|
|
171
|
+
return this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
|
|
172
|
+
}
|
|
184
173
|
|
|
174
|
+
/** @param {`nonce-${string}` | `sha256-${string}`} source */
|
|
175
|
+
#add_script_source(source) {
|
|
185
176
|
if (this.#script_src_needs_csp) {
|
|
186
177
|
this.#script_src.add(source);
|
|
187
178
|
}
|
|
@@ -191,15 +182,17 @@ class BaseProvider {
|
|
|
191
182
|
}
|
|
192
183
|
}
|
|
193
184
|
|
|
185
|
+
/** @param {string} content */
|
|
186
|
+
add_script(content) {
|
|
187
|
+
if (!this.#script_needs_csp) return;
|
|
188
|
+
|
|
189
|
+
this.#add_script_source(this.#get_source(content));
|
|
190
|
+
}
|
|
191
|
+
|
|
194
192
|
/** @param {`sha256-${string}`[]} hashes */
|
|
195
193
|
add_script_hashes(hashes) {
|
|
196
194
|
for (const hash of hashes) {
|
|
197
|
-
|
|
198
|
-
this.#script_src.add(hash);
|
|
199
|
-
}
|
|
200
|
-
if (this.#script_src_elem_needs_csp) {
|
|
201
|
-
this.#script_src_elem.add(hash);
|
|
202
|
-
}
|
|
195
|
+
this.#add_script_source(hash);
|
|
203
196
|
}
|
|
204
197
|
}
|
|
205
198
|
|
|
@@ -207,8 +200,7 @@ class BaseProvider {
|
|
|
207
200
|
add_style(content) {
|
|
208
201
|
if (!this.#style_needs_csp) return;
|
|
209
202
|
|
|
210
|
-
|
|
211
|
-
const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
|
|
203
|
+
const source = this.#get_source(content);
|
|
212
204
|
|
|
213
205
|
if (this.#style_src_needs_csp) {
|
|
214
206
|
this.#style_src.add(source);
|
|
@@ -251,40 +243,34 @@ class BaseProvider {
|
|
|
251
243
|
|
|
252
244
|
const directives = { ...this.#directives };
|
|
253
245
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
]
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
]
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (this.#script_src_elem.size > 0) {
|
|
283
|
-
directives['script-src-elem'] = [
|
|
284
|
-
...(directives['script-src-elem'] || []),
|
|
285
|
-
...this.#script_src_elem
|
|
286
|
-
];
|
|
287
|
-
}
|
|
246
|
+
/**
|
|
247
|
+
* @template {'style-src' | 'style-src-attr' | 'style-src-elem' | 'script-src' | 'script-src-elem'} K
|
|
248
|
+
* @param {K} key
|
|
249
|
+
* @param {Set<import('types').Csp.Source>} sources
|
|
250
|
+
* @param {import('types').CspDirectives[K]} [base]
|
|
251
|
+
*/
|
|
252
|
+
const merge_sources = (key, sources, base) => {
|
|
253
|
+
if (sources.size > 0) {
|
|
254
|
+
directives[key] = /** @type {import('types').CspDirectives[K]} */ ([
|
|
255
|
+
...(base || []),
|
|
256
|
+
...sources
|
|
257
|
+
]);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
merge_sources(
|
|
262
|
+
'style-src',
|
|
263
|
+
this.#style_src,
|
|
264
|
+
directives['style-src'] || directives['default-src']
|
|
265
|
+
);
|
|
266
|
+
merge_sources('style-src-attr', this.#style_src_attr, directives['style-src-attr']);
|
|
267
|
+
merge_sources('style-src-elem', this.#style_src_elem, directives['style-src-elem']);
|
|
268
|
+
merge_sources(
|
|
269
|
+
'script-src',
|
|
270
|
+
this.#script_src,
|
|
271
|
+
directives['script-src'] || directives['default-src']
|
|
272
|
+
);
|
|
273
|
+
merge_sources('script-src-elem', this.#script_src_elem, directives['script-src-elem']);
|
|
288
274
|
|
|
289
275
|
for (const key in directives) {
|
|
290
276
|
if (is_meta && (key === 'frame-ancestors' || key === 'report-uri' || key === 'sandbox')) {
|
|
@@ -300,13 +286,11 @@ class BaseProvider {
|
|
|
300
286
|
|
|
301
287
|
const directive = [key];
|
|
302
288
|
if (Array.isArray(value)) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
});
|
|
289
|
+
for (const source of value) {
|
|
290
|
+
directive.push(
|
|
291
|
+
quoted.has(source) || crypto_pattern.test(source) ? `'${source}'` : source
|
|
292
|
+
);
|
|
293
|
+
}
|
|
310
294
|
}
|
|
311
295
|
|
|
312
296
|
header.push(directive.join(' '));
|
|
@@ -337,17 +321,17 @@ class CspReportOnlyProvider extends BaseProvider {
|
|
|
337
321
|
constructor(use_hashes, directives, nonce) {
|
|
338
322
|
super(use_hashes, directives, nonce);
|
|
339
323
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
324
|
+
// If we're generating content-security-policy-report-only,
|
|
325
|
+
// if there are any directives, we need a report-uri or report-to (or both)
|
|
326
|
+
// else it's just an expensive noop.
|
|
327
|
+
if (
|
|
328
|
+
Object.values(directives).some((v) => !!v) &&
|
|
329
|
+
!directives['report-to']?.length &&
|
|
330
|
+
!directives['report-uri']?.length
|
|
331
|
+
) {
|
|
332
|
+
throw Error(
|
|
333
|
+
'`content-security-policy-report-only` must be specified with either the `report-to` or `report-uri` directives, or both'
|
|
334
|
+
);
|
|
351
335
|
}
|
|
352
336
|
}
|
|
353
337
|
}
|