@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.20
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 +58 -36
- package/src/cli.js +14 -11
- package/src/constants.js +6 -1
- package/src/core/adapt/builder.js +54 -60
- package/src/core/adapt/index.js +2 -5
- package/src/core/config/index.js +141 -76
- package/src/core/config/options.js +260 -260
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +143 -13
- package/src/core/generate_manifest/index.js +18 -15
- package/src/core/postbuild/analyse.js +7 -19
- 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 +193 -69
- 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 +72 -52
- package/src/core/sync/sync.js +35 -26
- 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} +105 -56
- package/src/core/sync/write_client_manifest.js +13 -28
- package/src/core/sync/write_env.js +7 -5
- package/src/core/sync/write_server.js +25 -33
- 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 +119 -116
- 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 +194 -0
- package/src/exports/hooks/sequence.js +9 -6
- package/src/exports/index.js +53 -20
- 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} +1 -2
- 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 +219 -1118
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +53 -64
- 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 +199 -125
- package/src/exports/vite/index.js +1514 -833
- package/src/exports/vite/module_ids.js +2 -2
- package/src/exports/vite/preview/index.js +32 -24
- package/src/exports/vite/utils.js +83 -45
- 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 +519 -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 +75 -75
- 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 +70 -53
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +48 -52
- package/src/runtime/server/dev.js +22 -0
- package/src/runtime/server/endpoint.js +3 -4
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/errors.js +160 -0
- package/src/runtime/server/fetch.js +31 -38
- package/src/runtime/server/index.js +90 -64
- package/src/runtime/server/internal.js +71 -0
- package/src/runtime/server/page/actions.js +84 -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 +22 -23
- package/src/runtime/server/page/index.js +35 -53
- package/src/runtime/server/page/load_data.js +47 -54
- package/src/runtime/server/page/render.js +172 -238
- package/src/runtime/server/page/respond_with_error.js +16 -30
- 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 +639 -0
- package/src/runtime/server/respond.js +188 -129
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/state.js +53 -0
- package/src/runtime/server/utils.js +12 -154
- 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 +160 -150
- 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 +2291 -2135
- package/types/index.d.ts.map +116 -108
- 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,15 @@
|
|
|
1
|
-
/** @import { RequestEvent,
|
|
2
|
-
/** @import {
|
|
3
|
-
import
|
|
1
|
+
/** @import { RequestEvent, Actions } from '@sveltejs/kit' */
|
|
2
|
+
/** @import { ActionResult } from '$app/forms' */
|
|
3
|
+
/** @import { SSROptions, SSRNode, ServerNode } from 'types' */
|
|
4
4
|
import { DEV } from 'esm-env';
|
|
5
5
|
import { json } from '@sveltejs/kit';
|
|
6
6
|
import { HttpError, Redirect, ActionFailure, SvelteKitError } from '@sveltejs/kit/internal';
|
|
7
|
-
import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server';
|
|
8
|
-
import {
|
|
7
|
+
import { with_request_store, merge_tracing, record_span } from '@sveltejs/kit/internal/server';
|
|
8
|
+
import { normalize_error } from '../../../utils/error.js';
|
|
9
9
|
import { is_form_content_type, negotiate } from '../../../utils/http.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { with_version_header } from '../utils.js';
|
|
11
|
+
import { handle_error_and_jsonify } from '../errors.js';
|
|
12
|
+
import { stringify, uneval } from '#app/internal/transport';
|
|
12
13
|
|
|
13
14
|
/** @param {RequestEvent} event */
|
|
14
15
|
export function is_action_json_request(event) {
|
|
@@ -22,12 +23,13 @@ export function is_action_json_request(event) {
|
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* @param {RequestEvent} event
|
|
25
|
-
* @param {import('types').RequestState}
|
|
26
|
+
* @param {import('types').RequestState} state
|
|
26
27
|
* @param {SSROptions} options
|
|
27
28
|
* @param {SSRNode['server'] | undefined} server
|
|
28
29
|
*/
|
|
29
|
-
export async function handle_action_json_request(event,
|
|
30
|
+
export async function handle_action_json_request(event, state, options, server) {
|
|
30
31
|
const actions = server?.actions;
|
|
32
|
+
const location = get_action_location(event.url);
|
|
31
33
|
|
|
32
34
|
if (!actions) {
|
|
33
35
|
const no_actions_error = new SvelteKitError(
|
|
@@ -36,13 +38,16 @@ export async function handle_action_json_request(event, event_state, options, se
|
|
|
36
38
|
`POST method not allowed. No form actions exist for ${DEV ? `the page at ${event.route.id}` : 'this page'}`
|
|
37
39
|
);
|
|
38
40
|
|
|
41
|
+
const error = await handle_error_and_jsonify(event, state, options, no_actions_error);
|
|
42
|
+
|
|
39
43
|
return action_json(
|
|
40
44
|
{
|
|
41
45
|
type: 'error',
|
|
42
|
-
error
|
|
46
|
+
error,
|
|
47
|
+
location
|
|
43
48
|
},
|
|
44
49
|
{
|
|
45
|
-
status:
|
|
50
|
+
status: error.status,
|
|
46
51
|
headers: {
|
|
47
52
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
|
|
48
53
|
// "The server must generate an Allow header field in a 405 status code response"
|
|
@@ -55,35 +60,40 @@ export async function handle_action_json_request(event, event_state, options, se
|
|
|
55
60
|
check_named_default_separate(actions);
|
|
56
61
|
|
|
57
62
|
try {
|
|
58
|
-
const data = await call_action(event,
|
|
63
|
+
const data = await call_action(event, state, actions);
|
|
59
64
|
|
|
60
65
|
if (DEV) {
|
|
61
66
|
validate_action_return(data);
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
if (data instanceof ActionFailure) {
|
|
70
|
+
return action_json(
|
|
71
|
+
{
|
|
72
|
+
type: 'failure',
|
|
73
|
+
status: data.status,
|
|
74
|
+
location,
|
|
75
|
+
// @ts-expect-error we assign a string to what is supposed to be an object. That's ok
|
|
76
|
+
// because we don't use the object outside, and this way we have better code navigation
|
|
77
|
+
// through knowing where the related interface is used.
|
|
78
|
+
data: try_serialize(data.data, stringify, /** @type {string} */ (event.route.id))
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
status: data.status
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
} else if (data) {
|
|
65
85
|
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
|
-
)
|
|
86
|
+
type: 'success',
|
|
87
|
+
status: 200,
|
|
88
|
+
location,
|
|
89
|
+
// @ts-expect-error see comment above
|
|
90
|
+
data: try_serialize(data, stringify, /** @type {string} */ (event.route.id))
|
|
76
91
|
});
|
|
77
92
|
} else {
|
|
78
93
|
return action_json({
|
|
79
94
|
type: 'success',
|
|
80
|
-
status:
|
|
81
|
-
|
|
82
|
-
data: stringify_action_response(
|
|
83
|
-
data,
|
|
84
|
-
/** @type {string} */ (event.route.id),
|
|
85
|
-
options.hooks.transport
|
|
86
|
-
)
|
|
95
|
+
status: 204,
|
|
96
|
+
location
|
|
87
97
|
});
|
|
88
98
|
}
|
|
89
99
|
} catch (e) {
|
|
@@ -93,23 +103,42 @@ export async function handle_action_json_request(event, event_state, options, se
|
|
|
93
103
|
return action_json_redirect(err);
|
|
94
104
|
}
|
|
95
105
|
|
|
106
|
+
const transformed = await handle_error_and_jsonify(
|
|
107
|
+
event,
|
|
108
|
+
state,
|
|
109
|
+
options,
|
|
110
|
+
check_incorrect_fail_use(err)
|
|
111
|
+
);
|
|
112
|
+
|
|
96
113
|
return action_json(
|
|
97
114
|
{
|
|
98
115
|
type: 'error',
|
|
99
|
-
error:
|
|
100
|
-
|
|
101
|
-
event_state,
|
|
102
|
-
options,
|
|
103
|
-
check_incorrect_fail_use(err)
|
|
104
|
-
)
|
|
116
|
+
error: transformed,
|
|
117
|
+
location
|
|
105
118
|
},
|
|
106
119
|
{
|
|
107
|
-
status:
|
|
120
|
+
status: transformed.status
|
|
108
121
|
}
|
|
109
122
|
);
|
|
110
123
|
}
|
|
111
124
|
}
|
|
112
125
|
|
|
126
|
+
/**
|
|
127
|
+
* @param {URL} url
|
|
128
|
+
*/
|
|
129
|
+
export function get_action_location(url) {
|
|
130
|
+
const location = new URL(url);
|
|
131
|
+
|
|
132
|
+
for (const key of location.searchParams.keys()) {
|
|
133
|
+
if (key.startsWith('/')) {
|
|
134
|
+
location.searchParams.delete(key);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return location.pathname + location.search;
|
|
140
|
+
}
|
|
141
|
+
|
|
113
142
|
/**
|
|
114
143
|
* @param {HttpError | Error} error
|
|
115
144
|
*/
|
|
@@ -135,7 +164,7 @@ export function action_json_redirect(redirect) {
|
|
|
135
164
|
* @param {ResponseInit} [init]
|
|
136
165
|
*/
|
|
137
166
|
function action_json(data, init) {
|
|
138
|
-
return json(data, init);
|
|
167
|
+
return with_version_header(json(data, init));
|
|
139
168
|
}
|
|
140
169
|
|
|
141
170
|
/**
|
|
@@ -147,12 +176,13 @@ export function is_action_request(event) {
|
|
|
147
176
|
|
|
148
177
|
/**
|
|
149
178
|
* @param {RequestEvent} event
|
|
150
|
-
* @param {import('types').RequestState}
|
|
179
|
+
* @param {import('types').RequestState} state
|
|
151
180
|
* @param {SSRNode['server'] | undefined} server
|
|
152
181
|
* @returns {Promise<ActionResult>}
|
|
153
182
|
*/
|
|
154
|
-
export async function handle_action_request(event,
|
|
183
|
+
export async function handle_action_request(event, state, server) {
|
|
155
184
|
const actions = server?.actions;
|
|
185
|
+
const location = get_action_location(event.url);
|
|
156
186
|
|
|
157
187
|
if (!actions) {
|
|
158
188
|
// TODO should this be a different error altogether?
|
|
@@ -163,6 +193,8 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
163
193
|
});
|
|
164
194
|
return {
|
|
165
195
|
type: 'error',
|
|
196
|
+
location,
|
|
197
|
+
// We're lying a bit with the types here; this will be transformed into a proper App.Error object later
|
|
166
198
|
error: new SvelteKitError(
|
|
167
199
|
405,
|
|
168
200
|
'Method Not Allowed',
|
|
@@ -174,7 +206,7 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
174
206
|
check_named_default_separate(actions);
|
|
175
207
|
|
|
176
208
|
try {
|
|
177
|
-
const data = await call_action(event,
|
|
209
|
+
const data = await call_action(event, state, actions);
|
|
178
210
|
|
|
179
211
|
if (DEV) {
|
|
180
212
|
validate_action_return(data);
|
|
@@ -184,12 +216,14 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
184
216
|
return {
|
|
185
217
|
type: 'failure',
|
|
186
218
|
status: data.status,
|
|
219
|
+
location,
|
|
187
220
|
data: data.data
|
|
188
221
|
};
|
|
189
222
|
} else {
|
|
190
223
|
return {
|
|
191
224
|
type: 'success',
|
|
192
225
|
status: 200,
|
|
226
|
+
location,
|
|
193
227
|
// @ts-expect-error this will be removed upon serialization, so `undefined` is the same as omission
|
|
194
228
|
data
|
|
195
229
|
};
|
|
@@ -207,6 +241,8 @@ export async function handle_action_request(event, event_state, server) {
|
|
|
207
241
|
|
|
208
242
|
return {
|
|
209
243
|
type: 'error',
|
|
244
|
+
location,
|
|
245
|
+
// @ts-expect-error We're lying a bit with the types here; this will be transformed into a proper App.Error object later
|
|
210
246
|
error: check_incorrect_fail_use(err)
|
|
211
247
|
};
|
|
212
248
|
}
|
|
@@ -225,11 +261,11 @@ function check_named_default_separate(actions) {
|
|
|
225
261
|
|
|
226
262
|
/**
|
|
227
263
|
* @param {RequestEvent} event
|
|
228
|
-
* @param {import('types').RequestState}
|
|
264
|
+
* @param {import('types').RequestState} state
|
|
229
265
|
* @param {NonNullable<ServerNode['actions']>} actions
|
|
230
266
|
* @throws {Redirect | HttpError | SvelteKitError | Error}
|
|
231
267
|
*/
|
|
232
|
-
async function call_action(event,
|
|
268
|
+
async function call_action(event, state, actions) {
|
|
233
269
|
const url = new URL(event.request.url);
|
|
234
270
|
|
|
235
271
|
let name = 'default';
|
|
@@ -243,11 +279,12 @@ async function call_action(event, event_state, actions) {
|
|
|
243
279
|
}
|
|
244
280
|
}
|
|
245
281
|
|
|
246
|
-
|
|
247
|
-
if (!action) {
|
|
282
|
+
if (!Object.hasOwn(actions, name)) {
|
|
248
283
|
throw new SvelteKitError(404, 'Not Found', `No action with name '${name}' found`);
|
|
249
284
|
}
|
|
250
285
|
|
|
286
|
+
const action = actions[name];
|
|
287
|
+
|
|
251
288
|
if (!is_form_content_type(event.request)) {
|
|
252
289
|
throw new SvelteKitError(
|
|
253
290
|
415,
|
|
@@ -267,7 +304,7 @@ async function call_action(event, event_state, actions) {
|
|
|
267
304
|
fn: async (current) => {
|
|
268
305
|
const traced_event = merge_tracing(event, current);
|
|
269
306
|
|
|
270
|
-
const result = await with_request_store({ event: traced_event, state
|
|
307
|
+
const result = await with_request_store({ event: traced_event, state }, () =>
|
|
271
308
|
action(traced_event)
|
|
272
309
|
);
|
|
273
310
|
|
|
@@ -298,26 +335,9 @@ function validate_action_return(data) {
|
|
|
298
335
|
* Try to `devalue.uneval` the data object, and if it fails, return a proper Error with context
|
|
299
336
|
* @param {any} data
|
|
300
337
|
* @param {string} route_id
|
|
301
|
-
* @param {ServerHooks['transport']} transport
|
|
302
338
|
*/
|
|
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);
|
|
339
|
+
export function uneval_action_response(data, route_id) {
|
|
340
|
+
return try_serialize(data, uneval, route_id);
|
|
321
341
|
}
|
|
322
342
|
|
|
323
343
|
/**
|
|
@@ -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
|
}
|