@sveltejs/kit 2.27.3 → 2.29.0
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/config/index.js +11 -0
- package/src/core/config/options.js +30 -11
- package/src/core/postbuild/prerender.js +5 -0
- package/src/exports/index.js +3 -4
- package/src/exports/public.d.ts +40 -11
- package/src/exports/vite/build/build_remote.js +4 -4
- package/src/exports/vite/index.js +121 -70
- package/src/exports/vite/static_analysis/utils.js +101 -0
- package/src/exports/vite/utils.js +16 -0
- package/src/runtime/app/server/event.js +1 -0
- package/src/runtime/app/server/index.js +3 -2
- package/src/runtime/app/server/remote/command.js +5 -0
- package/src/runtime/app/server/remote/form.js +10 -0
- package/src/runtime/client/client.js +2 -2
- package/src/runtime/client/fetcher.js +3 -2
- package/src/runtime/client/remote-functions/command.svelte.js +91 -0
- package/src/runtime/client/remote-functions/form.svelte.js +29 -2
- package/src/runtime/client/remote-functions/index.js +1 -1
- package/src/runtime/client/remote-functions/shared.svelte.js +11 -14
- package/src/runtime/server/cookie.js +2 -1
- package/src/runtime/server/data/index.js +3 -4
- package/src/runtime/server/page/crypto.js +3 -58
- package/src/runtime/server/page/csp.js +2 -2
- package/src/runtime/server/page/load_data.js +6 -5
- package/src/runtime/server/page/render.js +3 -4
- package/src/runtime/server/remote.js +29 -33
- package/src/runtime/shared.js +8 -12
- package/src/runtime/utils.js +43 -33
- package/src/types/internal.d.ts +1 -1
- package/src/version.js +1 -1
- package/types/index.d.ts +42 -15
- package/types/index.d.ts.map +1 -1
- package/src/exports/vite/graph_analysis/index.js +0 -87
- package/src/exports/vite/graph_analysis/types.d.ts +0 -5
- package/src/exports/vite/graph_analysis/utils.js +0 -6
- package/src/runtime/client/remote-functions/command.js +0 -71
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a match position is within a comment or a string
|
|
3
|
+
* @param {string} content - The full content
|
|
4
|
+
* @param {number} match_index - The index where the match starts
|
|
5
|
+
* @returns {boolean} - True if the match is within a comment
|
|
6
|
+
*/
|
|
7
|
+
export function should_ignore(content, match_index) {
|
|
8
|
+
// Track if we're inside different types of quotes and comments
|
|
9
|
+
let in_single_quote = false;
|
|
10
|
+
let in_double_quote = false;
|
|
11
|
+
let in_template_literal = false;
|
|
12
|
+
let in_single_line_comment = false;
|
|
13
|
+
let in_multi_line_comment = false;
|
|
14
|
+
let in_html_comment = false;
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < match_index; i++) {
|
|
17
|
+
const char = content[i];
|
|
18
|
+
const next_two = content.slice(i, i + 2);
|
|
19
|
+
const next_four = content.slice(i, i + 4);
|
|
20
|
+
|
|
21
|
+
// Handle end of single line comment
|
|
22
|
+
if (in_single_line_comment && char === '\n') {
|
|
23
|
+
in_single_line_comment = false;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Handle end of multi-line comment
|
|
28
|
+
if (in_multi_line_comment && next_two === '*/') {
|
|
29
|
+
in_multi_line_comment = false;
|
|
30
|
+
i++; // Skip the '/' part
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Handle end of HTML comment
|
|
35
|
+
if (in_html_comment && content.slice(i, i + 3) === '-->') {
|
|
36
|
+
in_html_comment = false;
|
|
37
|
+
i += 2; // Skip the '-->' part
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// If we're in any comment, skip processing
|
|
42
|
+
if (in_single_line_comment || in_multi_line_comment || in_html_comment) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Handle escape sequences in strings
|
|
47
|
+
if ((in_single_quote || in_double_quote || in_template_literal) && char === '\\') {
|
|
48
|
+
i++; // Skip the escaped character
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Handle string boundaries
|
|
53
|
+
if (!in_double_quote && !in_template_literal && char === "'") {
|
|
54
|
+
in_single_quote = !in_single_quote;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!in_single_quote && !in_template_literal && char === '"') {
|
|
59
|
+
in_double_quote = !in_double_quote;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!in_single_quote && !in_double_quote && char === '`') {
|
|
64
|
+
in_template_literal = !in_template_literal;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// If we're inside any string, don't process comment delimiters
|
|
69
|
+
if (in_single_quote || in_double_quote || in_template_literal) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Check for comment starts
|
|
74
|
+
if (next_two === '//') {
|
|
75
|
+
in_single_line_comment = true;
|
|
76
|
+
i++; // Skip the second '/'
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (next_two === '/*') {
|
|
81
|
+
in_multi_line_comment = true;
|
|
82
|
+
i++; // Skip the '*'
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (next_four === '<!--') {
|
|
87
|
+
in_html_comment = true;
|
|
88
|
+
i += 3; // Skip the '<!--'
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
in_single_line_comment ||
|
|
95
|
+
in_multi_line_comment ||
|
|
96
|
+
in_html_comment ||
|
|
97
|
+
in_single_quote ||
|
|
98
|
+
in_double_quote ||
|
|
99
|
+
in_template_literal
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -113,6 +113,8 @@ export function not_found(req, res, base) {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
const query_pattern = /\?.*$/s;
|
|
117
|
+
|
|
116
118
|
/**
|
|
117
119
|
* Removes cwd/lib path from the start of the id
|
|
118
120
|
* @param {string} id
|
|
@@ -120,6 +122,8 @@ export function not_found(req, res, base) {
|
|
|
120
122
|
* @param {string} cwd
|
|
121
123
|
*/
|
|
122
124
|
export function normalize_id(id, lib, cwd) {
|
|
125
|
+
id = id.replace(query_pattern, '');
|
|
126
|
+
|
|
123
127
|
if (id.startsWith(lib)) {
|
|
124
128
|
id = id.replace(lib, '$lib');
|
|
125
129
|
}
|
|
@@ -155,4 +159,16 @@ export function normalize_id(id, lib, cwd) {
|
|
|
155
159
|
return posixify(id);
|
|
156
160
|
}
|
|
157
161
|
|
|
162
|
+
/**
|
|
163
|
+
* For times when you need to throw an error, but without
|
|
164
|
+
* displaying a useless stack trace (since the developer
|
|
165
|
+
* can't do anything useful with it)
|
|
166
|
+
* @param {string} message
|
|
167
|
+
*/
|
|
168
|
+
export function stackless(message) {
|
|
169
|
+
const error = new Error(message);
|
|
170
|
+
error.stack = '';
|
|
171
|
+
return error;
|
|
172
|
+
}
|
|
173
|
+
|
|
158
174
|
export const strip_virtual_prefix = /** @param {string} id */ (id) => id.replace('\0virtual:', '');
|
|
@@ -19,6 +19,7 @@ import('node:async_hooks')
|
|
|
19
19
|
*
|
|
20
20
|
* In environments without [`AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage), this must be called synchronously (i.e. not after an `await`).
|
|
21
21
|
* @since 2.20.0
|
|
22
|
+
* @returns {RequestEvent}
|
|
22
23
|
*/
|
|
23
24
|
export function getRequestEvent() {
|
|
24
25
|
const event = request_event ?? als?.getStore();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { read_implementation, manifest } from '__sveltekit/server';
|
|
2
2
|
import { base } from '__sveltekit/paths';
|
|
3
3
|
import { DEV } from 'esm-env';
|
|
4
|
-
import {
|
|
4
|
+
import { base64_decode } from '../../utils.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Read the contents of an imported asset from the filesystem
|
|
@@ -33,8 +33,9 @@ export function read(asset) {
|
|
|
33
33
|
const data = asset.slice(match[0].length);
|
|
34
34
|
|
|
35
35
|
if (match[2] !== undefined) {
|
|
36
|
-
const decoded =
|
|
36
|
+
const decoded = base64_decode(data);
|
|
37
37
|
|
|
38
|
+
// @ts-ignore passing a Uint8Array to `new Response(...)` is fine
|
|
38
39
|
return new Response(decoded, {
|
|
39
40
|
headers: {
|
|
40
41
|
'Content-Length': decoded.byteLength.toString(),
|
|
@@ -97,6 +97,16 @@ export function form(fn) {
|
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
+
// On the server, pending is always 0
|
|
101
|
+
Object.defineProperty(instance, 'pending', {
|
|
102
|
+
get: () => 0
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// On the server, buttonProps.pending is always 0
|
|
106
|
+
Object.defineProperty(button_props, 'pending', {
|
|
107
|
+
get: () => 0
|
|
108
|
+
});
|
|
109
|
+
|
|
100
110
|
if (key == undefined) {
|
|
101
111
|
Object.defineProperty(instance, 'for', {
|
|
102
112
|
/** @type {RemoteForm<any>['for']} */
|
|
@@ -44,6 +44,7 @@ import { get_message, get_status } from '../../utils/error.js';
|
|
|
44
44
|
import { writable } from 'svelte/store';
|
|
45
45
|
import { page, update, navigating } from './state.svelte.js';
|
|
46
46
|
import { add_data_suffix, add_resolution_suffix } from '../pathname.js';
|
|
47
|
+
import { text_decoder } from '../utils.js';
|
|
47
48
|
|
|
48
49
|
export { load_css };
|
|
49
50
|
const ICON_REL_ATTRIBUTES = new Set(['icon', 'shortcut icon', 'apple-touch-icon']);
|
|
@@ -2781,7 +2782,6 @@ async function load_data(url, invalid) {
|
|
|
2781
2782
|
*/
|
|
2782
2783
|
const deferreds = new Map();
|
|
2783
2784
|
const reader = /** @type {ReadableStream<Uint8Array>} */ (res.body).getReader();
|
|
2784
|
-
const decoder = new TextDecoder();
|
|
2785
2785
|
|
|
2786
2786
|
/**
|
|
2787
2787
|
* @param {any} data
|
|
@@ -2804,7 +2804,7 @@ async function load_data(url, invalid) {
|
|
|
2804
2804
|
const { done, value } = await reader.read();
|
|
2805
2805
|
if (done && !text) break;
|
|
2806
2806
|
|
|
2807
|
-
text += !value && text ? '\n' :
|
|
2807
|
+
text += !value && text ? '\n' : text_decoder.decode(value, { stream: true }); // no value -> final chunk -> add a new line to trigger the last parse
|
|
2808
2808
|
|
|
2809
2809
|
while (true) {
|
|
2810
2810
|
const split = text.indexOf('\n');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BROWSER, DEV } from 'esm-env';
|
|
2
2
|
import { hash } from '../../utils/hash.js';
|
|
3
|
-
import {
|
|
3
|
+
import { base64_decode } from '../utils.js';
|
|
4
4
|
|
|
5
5
|
let loading = 0;
|
|
6
6
|
|
|
@@ -90,6 +90,7 @@ export function initial_fetch(resource, opts) {
|
|
|
90
90
|
|
|
91
91
|
const script = document.querySelector(selector);
|
|
92
92
|
if (script?.textContent) {
|
|
93
|
+
script.remove(); // In case multiple script tags match the same selector
|
|
93
94
|
let { body, ...init } = JSON.parse(script.textContent);
|
|
94
95
|
|
|
95
96
|
const ttl = script.getAttribute('data-ttl');
|
|
@@ -98,7 +99,7 @@ export function initial_fetch(resource, opts) {
|
|
|
98
99
|
if (b64 !== null) {
|
|
99
100
|
// Can't use native_fetch('data:...;base64,${body}')
|
|
100
101
|
// csp can block the request
|
|
101
|
-
body =
|
|
102
|
+
body = base64_decode(body);
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
return Promise.resolve(new Response(body, init));
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** @import { RemoteCommand, RemoteQueryOverride } from '@sveltejs/kit' */
|
|
2
|
+
/** @import { RemoteFunctionResponse } from 'types' */
|
|
3
|
+
/** @import { Query } from './query.svelte.js' */
|
|
4
|
+
import { app_dir, base } from '__sveltekit/paths';
|
|
5
|
+
import * as devalue from 'devalue';
|
|
6
|
+
import { HttpError } from '@sveltejs/kit/internal';
|
|
7
|
+
import { app } from '../client.js';
|
|
8
|
+
import { stringify_remote_arg } from '../../shared.js';
|
|
9
|
+
import { refresh_queries, release_overrides } from './shared.svelte.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Client-version of the `command` function from `$app/server`.
|
|
13
|
+
* @param {string} id
|
|
14
|
+
* @returns {RemoteCommand<any, any>}
|
|
15
|
+
*/
|
|
16
|
+
export function command(id) {
|
|
17
|
+
/** @type {number} */
|
|
18
|
+
let pending_count = $state(0);
|
|
19
|
+
|
|
20
|
+
// Careful: This function MUST be synchronous (can't use the async keyword) because the return type has to be a promise with an updates() method.
|
|
21
|
+
// If we make it async, the return type will be a promise that resolves to a promise with an updates() method, which is not what we want.
|
|
22
|
+
/** @type {RemoteCommand<any, any>} */
|
|
23
|
+
const command_function = (arg) => {
|
|
24
|
+
/** @type {Array<Query<any> | RemoteQueryOverride>} */
|
|
25
|
+
let updates = [];
|
|
26
|
+
|
|
27
|
+
// Increment pending count when command starts
|
|
28
|
+
pending_count++;
|
|
29
|
+
|
|
30
|
+
/** @type {Promise<any> & { updates: (...args: any[]) => any }} */
|
|
31
|
+
const promise = (async () => {
|
|
32
|
+
try {
|
|
33
|
+
// Wait a tick to give room for the `updates` method to be called
|
|
34
|
+
await Promise.resolve();
|
|
35
|
+
|
|
36
|
+
const response = await fetch(`${base}/${app_dir}/remote/${id}`, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
payload: stringify_remote_arg(arg, app.hooks.transport),
|
|
40
|
+
refreshes: updates.map((u) => u._key)
|
|
41
|
+
}),
|
|
42
|
+
headers: {
|
|
43
|
+
'Content-Type': 'application/json'
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
release_overrides(updates);
|
|
49
|
+
// We only end up here in case of a network error or if the server has an internal error
|
|
50
|
+
// (which shouldn't happen because we handle errors on the server and always send a 200 response)
|
|
51
|
+
throw new Error('Failed to execute remote function');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const result = /** @type {RemoteFunctionResponse} */ (await response.json());
|
|
55
|
+
if (result.type === 'redirect') {
|
|
56
|
+
release_overrides(updates);
|
|
57
|
+
throw new Error(
|
|
58
|
+
'Redirects are not allowed in commands. Return a result instead and use goto on the client'
|
|
59
|
+
);
|
|
60
|
+
} else if (result.type === 'error') {
|
|
61
|
+
release_overrides(updates);
|
|
62
|
+
throw new HttpError(result.status ?? 500, result.error);
|
|
63
|
+
} else {
|
|
64
|
+
if (result.refreshes) {
|
|
65
|
+
refresh_queries(result.refreshes, updates);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return devalue.parse(result.result, app.decoders);
|
|
69
|
+
}
|
|
70
|
+
} finally {
|
|
71
|
+
// Decrement pending count when command completes
|
|
72
|
+
pending_count--;
|
|
73
|
+
}
|
|
74
|
+
})();
|
|
75
|
+
|
|
76
|
+
promise.updates = (/** @type {any} */ ...args) => {
|
|
77
|
+
updates = args;
|
|
78
|
+
// @ts-expect-error Don't allow updates to be called multiple times
|
|
79
|
+
delete promise.updates;
|
|
80
|
+
return promise;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return promise;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
Object.defineProperty(command_function, 'pending', {
|
|
87
|
+
get: () => pending_count
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return command_function;
|
|
91
|
+
}
|
|
@@ -5,7 +5,14 @@ import { app_dir, base } from '__sveltekit/paths';
|
|
|
5
5
|
import * as devalue from 'devalue';
|
|
6
6
|
import { DEV } from 'esm-env';
|
|
7
7
|
import { HttpError } from '@sveltejs/kit/internal';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
app,
|
|
10
|
+
remote_responses,
|
|
11
|
+
started,
|
|
12
|
+
goto,
|
|
13
|
+
set_nearest_error_page,
|
|
14
|
+
invalidateAll
|
|
15
|
+
} from '../client.js';
|
|
9
16
|
import { tick } from 'svelte';
|
|
10
17
|
import { refresh_queries, release_overrides } from './shared.svelte.js';
|
|
11
18
|
|
|
@@ -27,6 +34,9 @@ export function form(id) {
|
|
|
27
34
|
/** @type {any} */
|
|
28
35
|
let result = $state(started ? undefined : remote_responses[action_id]);
|
|
29
36
|
|
|
37
|
+
/** @type {number} */
|
|
38
|
+
let pending_count = $state(0);
|
|
39
|
+
|
|
30
40
|
/**
|
|
31
41
|
* @param {FormData} data
|
|
32
42
|
* @returns {Promise<any> & { updates: (...args: any[]) => any }}
|
|
@@ -42,6 +52,9 @@ export function form(id) {
|
|
|
42
52
|
entry.count++;
|
|
43
53
|
}
|
|
44
54
|
|
|
55
|
+
// Increment pending count when submission starts
|
|
56
|
+
pending_count++;
|
|
57
|
+
|
|
45
58
|
/** @type {Array<Query<any> | RemoteQueryOverride>} */
|
|
46
59
|
let updates = [];
|
|
47
60
|
|
|
@@ -78,7 +91,11 @@ export function form(id) {
|
|
|
78
91
|
if (form_result.type === 'result') {
|
|
79
92
|
result = devalue.parse(form_result.result, app.decoders);
|
|
80
93
|
|
|
81
|
-
|
|
94
|
+
if (form_result.refreshes) {
|
|
95
|
+
refresh_queries(form_result.refreshes, updates);
|
|
96
|
+
} else {
|
|
97
|
+
void invalidateAll();
|
|
98
|
+
}
|
|
82
99
|
} else if (form_result.type === 'redirect') {
|
|
83
100
|
const refreshes = form_result.refreshes ?? '';
|
|
84
101
|
const invalidateAll = !refreshes && updates.length === 0;
|
|
@@ -94,6 +111,9 @@ export function form(id) {
|
|
|
94
111
|
release_overrides(updates);
|
|
95
112
|
throw e;
|
|
96
113
|
} finally {
|
|
114
|
+
// Decrement pending count when submission completes
|
|
115
|
+
pending_count--;
|
|
116
|
+
|
|
97
117
|
void tick().then(() => {
|
|
98
118
|
if (entry) {
|
|
99
119
|
entry.count--;
|
|
@@ -242,6 +262,10 @@ export function form(id) {
|
|
|
242
262
|
}
|
|
243
263
|
});
|
|
244
264
|
|
|
265
|
+
Object.defineProperty(button_props, 'pending', {
|
|
266
|
+
get: () => pending_count
|
|
267
|
+
});
|
|
268
|
+
|
|
245
269
|
Object.defineProperties(instance, {
|
|
246
270
|
buttonProps: {
|
|
247
271
|
value: button_props
|
|
@@ -249,6 +273,9 @@ export function form(id) {
|
|
|
249
273
|
result: {
|
|
250
274
|
get: () => result
|
|
251
275
|
},
|
|
276
|
+
pending: {
|
|
277
|
+
get: () => pending_count
|
|
278
|
+
},
|
|
252
279
|
enhance: {
|
|
253
280
|
/** @type {RemoteForm<any>['enhance']} */
|
|
254
281
|
value: (callback) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** @import { RemoteFunctionResponse } from 'types' */
|
|
3
3
|
/** @import { Query } from './query.svelte.js' */
|
|
4
4
|
import * as devalue from 'devalue';
|
|
5
|
-
import { app, goto,
|
|
5
|
+
import { app, goto, query_map } from '../client.js';
|
|
6
6
|
import { HttpError, Redirect } from '@sveltejs/kit/internal';
|
|
7
7
|
import { tick } from 'svelte';
|
|
8
8
|
import { create_remote_cache_key, stringify_remote_arg } from '../../shared.js';
|
|
@@ -125,19 +125,16 @@ export function release_overrides(updates) {
|
|
|
125
125
|
*/
|
|
126
126
|
export function refresh_queries(stringified_refreshes, updates = []) {
|
|
127
127
|
const refreshes = Object.entries(devalue.parse(stringified_refreshes, app.decoders));
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
// Update the query with the new value
|
|
137
|
-
const entry = query_map.get(key);
|
|
138
|
-
entry?.resource.set(value);
|
|
128
|
+
|
|
129
|
+
// `refreshes` is a superset of `updates`
|
|
130
|
+
for (const [key, value] of refreshes) {
|
|
131
|
+
// If there was an optimistic update, release it right before we update the query
|
|
132
|
+
const update = updates.find((u) => u._key === key);
|
|
133
|
+
if (update && 'release' in update) {
|
|
134
|
+
update.release();
|
|
139
135
|
}
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
// Update the query with the new value
|
|
137
|
+
const entry = query_map.get(key);
|
|
138
|
+
entry?.resource.set(value);
|
|
142
139
|
}
|
|
143
140
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parse, serialize } from 'cookie';
|
|
2
2
|
import { normalize_path, resolve } from '../../utils/url.js';
|
|
3
3
|
import { add_data_suffix } from '../pathname.js';
|
|
4
|
+
import { text_encoder } from '../utils.js';
|
|
4
5
|
|
|
5
6
|
// eslint-disable-next-line no-control-regex -- control characters are invalid in cookie names
|
|
6
7
|
const INVALID_COOKIE_CHARACTER_REGEX = /[\x00-\x1F\x7F()<>@,;:"/[\]?={} \t]/;
|
|
@@ -217,7 +218,7 @@ export function get_cookies(request, url) {
|
|
|
217
218
|
|
|
218
219
|
if (__SVELTEKIT_DEV__) {
|
|
219
220
|
const serialized = serialize(name, value, new_cookies[name].options);
|
|
220
|
-
if (
|
|
221
|
+
if (text_encoder.encode(serialized).byteLength > MAX_COOKIE_SIZE) {
|
|
221
222
|
throw new Error(`Cookie "${name}" is too large, and will be discarded by the browser`);
|
|
222
223
|
}
|
|
223
224
|
|
|
@@ -7,8 +7,7 @@ import { clarify_devalue_error, handle_error_and_jsonify, serialize_uses } from
|
|
|
7
7
|
import { normalize_path } from '../../../utils/url.js';
|
|
8
8
|
import * as devalue from 'devalue';
|
|
9
9
|
import { create_async_iterator } from '../../../utils/streaming.js';
|
|
10
|
-
|
|
11
|
-
const encoder = new TextEncoder();
|
|
10
|
+
import { text_encoder } from '../../utils.js';
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* @param {import('@sveltejs/kit').RequestEvent} event
|
|
@@ -129,9 +128,9 @@ export async function render_data(
|
|
|
129
128
|
return new Response(
|
|
130
129
|
new ReadableStream({
|
|
131
130
|
async start(controller) {
|
|
132
|
-
controller.enqueue(
|
|
131
|
+
controller.enqueue(text_encoder.encode(data));
|
|
133
132
|
for await (const chunk of chunks) {
|
|
134
|
-
controller.enqueue(
|
|
133
|
+
controller.enqueue(text_encoder.encode(chunk));
|
|
135
134
|
}
|
|
136
135
|
controller.close();
|
|
137
136
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { 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 btoa(String.fromCharCode(...bytes));
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/** The SHA-256 initialization vector */
|
|
@@ -160,7 +160,7 @@ function reverse_endianness(bytes) {
|
|
|
160
160
|
|
|
161
161
|
/** @param {string} str */
|
|
162
162
|
function encode(str) {
|
|
163
|
-
const encoded =
|
|
163
|
+
const encoded = text_encoder.encode(str);
|
|
164
164
|
const length = encoded.length * 8;
|
|
165
165
|
|
|
166
166
|
// result should be a multiple of 512 bits in length,
|
|
@@ -182,58 +182,3 @@ function encode(str) {
|
|
|
182
182
|
|
|
183
183
|
return words;
|
|
184
184
|
}
|
|
185
|
-
|
|
186
|
-
/*
|
|
187
|
-
Based on https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
|
|
188
|
-
|
|
189
|
-
MIT License
|
|
190
|
-
Copyright (c) 2020 Egor Nepomnyaschih
|
|
191
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
192
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
193
|
-
in the Software without restriction, including without limitation the rights
|
|
194
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
195
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
196
|
-
furnished to do so, subject to the following conditions:
|
|
197
|
-
The above copyright notice and this permission notice shall be included in all
|
|
198
|
-
copies or substantial portions of the Software.
|
|
199
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
200
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
201
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
202
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
203
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
204
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
205
|
-
SOFTWARE.
|
|
206
|
-
*/
|
|
207
|
-
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
|
|
208
|
-
|
|
209
|
-
/** @param {Uint8Array} bytes */
|
|
210
|
-
export function base64(bytes) {
|
|
211
|
-
const l = bytes.length;
|
|
212
|
-
|
|
213
|
-
let result = '';
|
|
214
|
-
let i;
|
|
215
|
-
|
|
216
|
-
for (i = 2; i < l; i += 3) {
|
|
217
|
-
result += chars[bytes[i - 2] >> 2];
|
|
218
|
-
result += chars[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
|
|
219
|
-
result += chars[((bytes[i - 1] & 0x0f) << 2) | (bytes[i] >> 6)];
|
|
220
|
-
result += chars[bytes[i] & 0x3f];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (i === l + 1) {
|
|
224
|
-
// 1 octet yet to write
|
|
225
|
-
result += chars[bytes[i - 2] >> 2];
|
|
226
|
-
result += chars[(bytes[i - 2] & 0x03) << 4];
|
|
227
|
-
result += '==';
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (i === l) {
|
|
231
|
-
// 2 octets yet to write
|
|
232
|
-
result += chars[bytes[i - 2] >> 2];
|
|
233
|
-
result += chars[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
|
|
234
|
-
result += chars[(bytes[i - 1] & 0x0f) << 2];
|
|
235
|
-
result += '=';
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return result;
|
|
239
|
-
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { escape_html } from '../../../utils/escape.js';
|
|
2
|
-
import {
|
|
2
|
+
import { sha256 } from './crypto.js';
|
|
3
3
|
|
|
4
4
|
const array = new Uint8Array(16);
|
|
5
5
|
|
|
6
6
|
function generate_nonce() {
|
|
7
7
|
crypto.getRandomValues(array);
|
|
8
|
-
return
|
|
8
|
+
return btoa(String.fromCharCode(...array));
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const quoted = new Set([
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEV } from 'esm-env';
|
|
2
2
|
import { disable_search, make_trackable } from '../../../utils/url.js';
|
|
3
3
|
import { validate_depends } from '../../shared.js';
|
|
4
|
-
import {
|
|
4
|
+
import { base64_encode, text_decoder } from '../../utils.js';
|
|
5
5
|
import { with_event } from '../../app/server/event.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -316,12 +316,14 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
|
|
|
316
316
|
return async () => {
|
|
317
317
|
const buffer = await response.arrayBuffer();
|
|
318
318
|
|
|
319
|
+
const bytes = new Uint8Array(buffer);
|
|
320
|
+
|
|
319
321
|
if (dependency) {
|
|
320
|
-
dependency.body =
|
|
322
|
+
dependency.body = bytes;
|
|
321
323
|
}
|
|
322
324
|
|
|
323
325
|
if (buffer instanceof ArrayBuffer) {
|
|
324
|
-
await push_fetched(
|
|
326
|
+
await push_fetched(base64_encode(bytes), true);
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
return buffer;
|
|
@@ -394,13 +396,12 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
|
|
|
394
396
|
async function stream_to_string(stream) {
|
|
395
397
|
let result = '';
|
|
396
398
|
const reader = stream.getReader();
|
|
397
|
-
const decoder = new TextDecoder();
|
|
398
399
|
while (true) {
|
|
399
400
|
const { done, value } = await reader.read();
|
|
400
401
|
if (done) {
|
|
401
402
|
break;
|
|
402
403
|
}
|
|
403
|
-
result +=
|
|
404
|
+
result += text_decoder.decode(value);
|
|
404
405
|
}
|
|
405
406
|
return result;
|
|
406
407
|
}
|
|
@@ -17,6 +17,7 @@ import { create_server_routing_response, generate_route_object } from './server_
|
|
|
17
17
|
import { add_resolution_suffix } from '../../pathname.js';
|
|
18
18
|
import { with_event } from '../../app/server/event.js';
|
|
19
19
|
import { get_event_state } from '../event-state.js';
|
|
20
|
+
import { text_encoder } from '../../utils.js';
|
|
20
21
|
|
|
21
22
|
// TODO rename this function/module
|
|
22
23
|
|
|
@@ -25,8 +26,6 @@ const updated = {
|
|
|
25
26
|
check: () => false
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
const encoder = new TextEncoder();
|
|
29
|
-
|
|
30
29
|
/**
|
|
31
30
|
* Creates the HTML response.
|
|
32
31
|
* @param {{
|
|
@@ -586,9 +585,9 @@ export async function render_response({
|
|
|
586
585
|
: new Response(
|
|
587
586
|
new ReadableStream({
|
|
588
587
|
async start(controller) {
|
|
589
|
-
controller.enqueue(
|
|
588
|
+
controller.enqueue(text_encoder.encode(transformed + '\n'));
|
|
590
589
|
for await (const chunk of chunks) {
|
|
591
|
-
controller.enqueue(
|
|
590
|
+
controller.enqueue(text_encoder.encode(chunk));
|
|
592
591
|
}
|
|
593
592
|
controller.close();
|
|
594
593
|
},
|