@sveltejs/kit 1.16.3 → 1.17.1
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 +5 -5
- package/src/core/postbuild/crawl.js +68 -43
- package/src/core/postbuild/prerender.js +6 -1
- package/src/exports/vite/dev/index.js +7 -8
- package/src/runtime/app/forms.js +67 -18
- package/src/runtime/client/client.js +1 -1
- package/src/runtime/server/cookie.js +35 -27
- package/src/runtime/server/fetch.js +3 -2
- package/src/runtime/server/respond.js +9 -2
- package/src/utils/fork.js +16 -20
- package/types/ambient.d.ts +22 -1
- package/types/index.d.ts +3 -0
- package/src/utils/unit_test.js +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.1",
|
|
4
4
|
"description": "The fastest way to build Svelte apps",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
|
15
15
|
"@types/cookie": "^0.5.1",
|
|
16
16
|
"cookie": "^0.5.0",
|
|
17
|
-
"devalue": "^4.3.
|
|
17
|
+
"devalue": "^4.3.1",
|
|
18
18
|
"esm-env": "^1.0.0",
|
|
19
19
|
"kleur": "^4.1.5",
|
|
20
20
|
"magic-string": "^0.30.0",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"svelte": "^3.56.0",
|
|
39
39
|
"svelte-preprocess": "^5.0.3",
|
|
40
40
|
"typescript": "^4.9.4",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
41
|
+
"vite": "^4.3.6",
|
|
42
|
+
"vitest": "^0.31.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"svelte": "^3.54.0",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"test:integration": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test",
|
|
90
90
|
"test:cross-platform:dev": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:cross-platform:dev",
|
|
91
91
|
"test:cross-platform:build": "pnpm test:unit && pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:cross-platform:build",
|
|
92
|
-
"test:unit": "
|
|
92
|
+
"test:unit": "vitest --config kit.vitest.config.js run",
|
|
93
93
|
"postinstall": "node postinstall.js"
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -13,6 +13,20 @@ const ATTRIBUTE_NAME = /[^\t\n\f />"'=]/;
|
|
|
13
13
|
|
|
14
14
|
const WHITESPACE = /[\s\n\r]/;
|
|
15
15
|
|
|
16
|
+
const CRAWLABLE_META_NAME_ATTRS = new Set([
|
|
17
|
+
'og:url',
|
|
18
|
+
'og:image',
|
|
19
|
+
'og:image:url',
|
|
20
|
+
'og:image:secure_url',
|
|
21
|
+
'og:video',
|
|
22
|
+
'og:video:url',
|
|
23
|
+
'og:video:secure_url',
|
|
24
|
+
'og:audio',
|
|
25
|
+
'og:audio:url',
|
|
26
|
+
'og:audio:secure_url',
|
|
27
|
+
'twitter:image'
|
|
28
|
+
]);
|
|
29
|
+
|
|
16
30
|
/**
|
|
17
31
|
* @param {string} html
|
|
18
32
|
* @param {string} base
|
|
@@ -81,6 +95,9 @@ export function crawl(html, base) {
|
|
|
81
95
|
|
|
82
96
|
const tag = html.slice(start, i).toUpperCase();
|
|
83
97
|
|
|
98
|
+
/** @type {Record<string, string>} */
|
|
99
|
+
const attributes = {};
|
|
100
|
+
|
|
84
101
|
if (tag === 'SCRIPT' || tag === 'STYLE') {
|
|
85
102
|
while (i < html.length) {
|
|
86
103
|
if (
|
|
@@ -95,9 +112,6 @@ export function crawl(html, base) {
|
|
|
95
112
|
}
|
|
96
113
|
}
|
|
97
114
|
|
|
98
|
-
let href = '';
|
|
99
|
-
let rel = '';
|
|
100
|
-
|
|
101
115
|
while (i < html.length) {
|
|
102
116
|
const start = i;
|
|
103
117
|
|
|
@@ -159,44 +173,7 @@ export function crawl(html, base) {
|
|
|
159
173
|
}
|
|
160
174
|
|
|
161
175
|
value = decode(value);
|
|
162
|
-
|
|
163
|
-
if (name === 'href') {
|
|
164
|
-
if (tag === 'BASE') {
|
|
165
|
-
base = resolve(base, value);
|
|
166
|
-
} else {
|
|
167
|
-
href = resolve(base, value);
|
|
168
|
-
}
|
|
169
|
-
} else if (name === 'id') {
|
|
170
|
-
ids.push(value);
|
|
171
|
-
} else if (name === 'name') {
|
|
172
|
-
if (tag === 'A') ids.push(value);
|
|
173
|
-
} else if (name === 'rel') {
|
|
174
|
-
rel = value;
|
|
175
|
-
} else if (name === 'src') {
|
|
176
|
-
if (value) hrefs.push(resolve(base, value));
|
|
177
|
-
} else if (name === 'srcset') {
|
|
178
|
-
const candidates = [];
|
|
179
|
-
let insideURL = true;
|
|
180
|
-
value = value.trim();
|
|
181
|
-
for (let i = 0; i < value.length; i++) {
|
|
182
|
-
if (
|
|
183
|
-
value[i] === ',' &&
|
|
184
|
-
(!insideURL || (insideURL && WHITESPACE.test(value[i + 1])))
|
|
185
|
-
) {
|
|
186
|
-
candidates.push(value.slice(0, i));
|
|
187
|
-
value = value.substring(i + 1).trim();
|
|
188
|
-
i = 0;
|
|
189
|
-
insideURL = true;
|
|
190
|
-
} else if (WHITESPACE.test(value[i])) {
|
|
191
|
-
insideURL = false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
candidates.push(value);
|
|
195
|
-
for (const candidate of candidates) {
|
|
196
|
-
const src = candidate.split(WHITESPACE)[0];
|
|
197
|
-
if (src) hrefs.push(resolve(base, src));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
176
|
+
attributes[name] = value;
|
|
200
177
|
} else {
|
|
201
178
|
i -= 1;
|
|
202
179
|
}
|
|
@@ -205,8 +182,56 @@ export function crawl(html, base) {
|
|
|
205
182
|
i += 1;
|
|
206
183
|
}
|
|
207
184
|
|
|
208
|
-
|
|
209
|
-
|
|
185
|
+
const { href, id, name, property, rel, src, srcset, content } = attributes;
|
|
186
|
+
|
|
187
|
+
if (href) {
|
|
188
|
+
if (tag === 'BASE') {
|
|
189
|
+
base = resolve(base, href);
|
|
190
|
+
} else if (!rel || !/\bexternal\b/i.test(rel)) {
|
|
191
|
+
hrefs.push(resolve(base, href));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (id) {
|
|
196
|
+
ids.push(id);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (name && tag === 'A') {
|
|
200
|
+
ids.push(name);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (src) {
|
|
204
|
+
hrefs.push(resolve(base, src));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (srcset) {
|
|
208
|
+
let value = srcset;
|
|
209
|
+
const candidates = [];
|
|
210
|
+
let insideURL = true;
|
|
211
|
+
value = value.trim();
|
|
212
|
+
for (let i = 0; i < value.length; i++) {
|
|
213
|
+
if (value[i] === ',' && (!insideURL || (insideURL && WHITESPACE.test(value[i + 1])))) {
|
|
214
|
+
candidates.push(value.slice(0, i));
|
|
215
|
+
value = value.substring(i + 1).trim();
|
|
216
|
+
i = 0;
|
|
217
|
+
insideURL = true;
|
|
218
|
+
} else if (WHITESPACE.test(value[i])) {
|
|
219
|
+
insideURL = false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
candidates.push(value);
|
|
223
|
+
for (const candidate of candidates) {
|
|
224
|
+
const src = candidate.split(WHITESPACE)[0];
|
|
225
|
+
if (src) hrefs.push(resolve(base, src));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (tag === 'META' && content) {
|
|
230
|
+
const attr = name ?? property;
|
|
231
|
+
|
|
232
|
+
if (attr && CRAWLABLE_META_NAME_ATTRS.has(attr)) {
|
|
233
|
+
hrefs.push(resolve(base, content));
|
|
234
|
+
}
|
|
210
235
|
}
|
|
211
236
|
}
|
|
212
237
|
}
|
|
@@ -12,6 +12,7 @@ import { get_route_segments } from '../../utils/routing.js';
|
|
|
12
12
|
import { queue } from './queue.js';
|
|
13
13
|
import { crawl } from './crawl.js';
|
|
14
14
|
import { forked } from '../../utils/fork.js';
|
|
15
|
+
import * as devalue from 'devalue';
|
|
15
16
|
|
|
16
17
|
export default forked(import.meta.url, prerender);
|
|
17
18
|
|
|
@@ -340,7 +341,11 @@ async function prerender({ out, manifest_path, metadata, verbose, env }) {
|
|
|
340
341
|
|
|
341
342
|
writeFileSync(
|
|
342
343
|
dest,
|
|
343
|
-
`<
|
|
344
|
+
`<script>location.href=${devalue.uneval(
|
|
345
|
+
location
|
|
346
|
+
)};</script><meta http-equiv="refresh" content=${escape_html_attr(
|
|
347
|
+
`0;url=${location}`
|
|
348
|
+
)}>`
|
|
344
349
|
);
|
|
345
350
|
|
|
346
351
|
written.add(file);
|
|
@@ -176,19 +176,18 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
176
176
|
const styles = {};
|
|
177
177
|
|
|
178
178
|
for (const dep of deps) {
|
|
179
|
-
const url = new URL(dep.url, '
|
|
179
|
+
const url = new URL(dep.url, 'dummy:/');
|
|
180
180
|
const query = url.searchParams;
|
|
181
181
|
|
|
182
182
|
if (
|
|
183
|
-
isCSSRequest(dep.file) ||
|
|
184
|
-
|
|
183
|
+
(isCSSRequest(dep.file) ||
|
|
184
|
+
(query.has('svelte') && query.get('type') === 'style')) &&
|
|
185
|
+
!(query.has('raw') || query.has('url') || query.has('inline'))
|
|
185
186
|
) {
|
|
186
|
-
// setting `?inline` to load CSS modules as css string
|
|
187
|
-
query.set('inline', '');
|
|
188
|
-
|
|
189
187
|
try {
|
|
190
|
-
|
|
191
|
-
|
|
188
|
+
query.set('inline', '');
|
|
189
|
+
const mod = await vite.ssrLoadModule(
|
|
190
|
+
`${decodeURI(url.pathname)}${url.search}${url.hash}`
|
|
192
191
|
);
|
|
193
192
|
styles[dep.url] = mod.default;
|
|
194
193
|
} catch {
|
package/src/runtime/app/forms.js
CHANGED
|
@@ -14,13 +14,34 @@ export function deserialize(result) {
|
|
|
14
14
|
return parsed;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} old_name
|
|
19
|
+
* @param {string} new_name
|
|
20
|
+
* @param {string} call_location
|
|
21
|
+
* @returns void
|
|
22
|
+
*/
|
|
23
|
+
function warn_on_access(old_name, new_name, call_location) {
|
|
24
|
+
if (!DEV) return;
|
|
25
|
+
// TODO 2.0: Remove this code
|
|
26
|
+
console.warn(
|
|
27
|
+
`\`${old_name}\` has been deprecated in favor of \`${new_name}\`. \`${old_name}\` will be removed in a future version. (Called from ${call_location})`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Shallow clone an element, so that we can access e.g. `form.action` without worrying
|
|
33
|
+
* that someone has added an `<input name="action">` (https://github.com/sveltejs/kit/issues/7593)
|
|
34
|
+
* @template {HTMLElement} T
|
|
35
|
+
* @param {T} element
|
|
36
|
+
* @returns {T}
|
|
37
|
+
*/
|
|
38
|
+
function clone(element) {
|
|
39
|
+
return /** @type {T} */ (HTMLElement.prototype.cloneNode.call(element));
|
|
40
|
+
}
|
|
41
|
+
|
|
17
42
|
/** @type {import('$app/forms').enhance} */
|
|
18
|
-
export function enhance(
|
|
19
|
-
if (
|
|
20
|
-
DEV &&
|
|
21
|
-
/** @type {HTMLFormElement} */ (HTMLFormElement.prototype.cloneNode.call(form)).method !==
|
|
22
|
-
'post'
|
|
23
|
-
) {
|
|
43
|
+
export function enhance(form_element, submit = () => {}) {
|
|
44
|
+
if (DEV && clone(form_element).method !== 'post') {
|
|
24
45
|
throw new Error('use:enhance can only be used on <form> fields with method="POST"');
|
|
25
46
|
}
|
|
26
47
|
|
|
@@ -35,7 +56,7 @@ export function enhance(form, submit = () => {}) {
|
|
|
35
56
|
if (result.type === 'success') {
|
|
36
57
|
if (reset !== false) {
|
|
37
58
|
// We call reset from the prototype to avoid DOM clobbering
|
|
38
|
-
HTMLFormElement.prototype.reset.call(
|
|
59
|
+
HTMLFormElement.prototype.reset.call(form_element);
|
|
39
60
|
}
|
|
40
61
|
await invalidateAll();
|
|
41
62
|
}
|
|
@@ -57,17 +78,28 @@ export function enhance(form, submit = () => {}) {
|
|
|
57
78
|
|
|
58
79
|
const action = new URL(
|
|
59
80
|
// We can't do submitter.formAction directly because that property is always set
|
|
60
|
-
// We do cloneNode for avoid DOM clobbering - https://github.com/sveltejs/kit/issues/7593
|
|
61
81
|
event.submitter?.hasAttribute('formaction')
|
|
62
82
|
? /** @type {HTMLButtonElement | HTMLInputElement} */ (event.submitter).formAction
|
|
63
|
-
:
|
|
83
|
+
: clone(form_element).action
|
|
64
84
|
);
|
|
65
85
|
|
|
66
|
-
const
|
|
86
|
+
const form_data = new FormData(form_element);
|
|
87
|
+
|
|
88
|
+
if (DEV && clone(form_element).enctype !== 'multipart/form-data') {
|
|
89
|
+
for (const value of form_data.values()) {
|
|
90
|
+
if (value instanceof File) {
|
|
91
|
+
// TODO 2.0: Upgrade to `throw Error`
|
|
92
|
+
console.warn(
|
|
93
|
+
'Your form contains <input type="file"> fields, but is missing the `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819. This will be upgraded to an error in v2.0.'
|
|
94
|
+
);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
67
99
|
|
|
68
100
|
const submitter_name = event.submitter?.getAttribute('name');
|
|
69
101
|
if (submitter_name) {
|
|
70
|
-
|
|
102
|
+
form_data.append(submitter_name, event.submitter?.getAttribute('value') ?? '');
|
|
71
103
|
}
|
|
72
104
|
|
|
73
105
|
const controller = new AbortController();
|
|
@@ -75,13 +107,22 @@ export function enhance(form, submit = () => {}) {
|
|
|
75
107
|
let cancelled = false;
|
|
76
108
|
const cancel = () => (cancelled = true);
|
|
77
109
|
|
|
110
|
+
// TODO 2.0: Remove `data` and `form`
|
|
78
111
|
const callback =
|
|
79
112
|
(await submit({
|
|
80
113
|
action,
|
|
81
114
|
cancel,
|
|
82
115
|
controller,
|
|
83
|
-
data
|
|
84
|
-
|
|
116
|
+
get data() {
|
|
117
|
+
warn_on_access('data', 'formData', 'use:enhance submit function');
|
|
118
|
+
return form_data;
|
|
119
|
+
},
|
|
120
|
+
formData: form_data,
|
|
121
|
+
get form() {
|
|
122
|
+
warn_on_access('form', 'formElement', 'use:enhance submit function');
|
|
123
|
+
return form_element;
|
|
124
|
+
},
|
|
125
|
+
formElement: form_element,
|
|
85
126
|
submitter: event.submitter
|
|
86
127
|
})) ?? fallback_callback;
|
|
87
128
|
if (cancelled) return;
|
|
@@ -97,7 +138,7 @@ export function enhance(form, submit = () => {}) {
|
|
|
97
138
|
'x-sveltekit-action': 'true'
|
|
98
139
|
},
|
|
99
140
|
cache: 'no-store',
|
|
100
|
-
body:
|
|
141
|
+
body: form_data,
|
|
101
142
|
signal: controller.signal
|
|
102
143
|
});
|
|
103
144
|
|
|
@@ -110,8 +151,16 @@ export function enhance(form, submit = () => {}) {
|
|
|
110
151
|
|
|
111
152
|
callback({
|
|
112
153
|
action,
|
|
113
|
-
data
|
|
114
|
-
|
|
154
|
+
get data() {
|
|
155
|
+
warn_on_access('data', 'formData', 'callback returned from use:enhance submit function');
|
|
156
|
+
return form_data;
|
|
157
|
+
},
|
|
158
|
+
formData: form_data,
|
|
159
|
+
get form() {
|
|
160
|
+
warn_on_access('form', 'formElement', 'callback returned from use:enhance submit function');
|
|
161
|
+
return form_element;
|
|
162
|
+
},
|
|
163
|
+
formElement: form_element,
|
|
115
164
|
update: (opts) => fallback_callback({ action, result, reset: opts?.reset }),
|
|
116
165
|
// @ts-expect-error generic constraints stuff we don't care about
|
|
117
166
|
result
|
|
@@ -119,12 +168,12 @@ export function enhance(form, submit = () => {}) {
|
|
|
119
168
|
}
|
|
120
169
|
|
|
121
170
|
// @ts-expect-error
|
|
122
|
-
HTMLFormElement.prototype.addEventListener.call(
|
|
171
|
+
HTMLFormElement.prototype.addEventListener.call(form_element, 'submit', handle_submit);
|
|
123
172
|
|
|
124
173
|
return {
|
|
125
174
|
destroy() {
|
|
126
175
|
// @ts-expect-error
|
|
127
|
-
HTMLFormElement.prototype.removeEventListener.call(
|
|
176
|
+
HTMLFormElement.prototype.removeEventListener.call(form_element, 'submit', handle_submit);
|
|
128
177
|
}
|
|
129
178
|
};
|
|
130
179
|
}
|
|
@@ -272,7 +272,7 @@ export function create_client(app, target) {
|
|
|
272
272
|
|
|
273
273
|
/** @param {import('./types').NavigationFinished} result */
|
|
274
274
|
function initialize(result) {
|
|
275
|
-
if (DEV && document.querySelector('vite-error-overlay')) return;
|
|
275
|
+
if (DEV && result.state.error && document.querySelector('vite-error-overlay')) return;
|
|
276
276
|
|
|
277
277
|
current = result.state;
|
|
278
278
|
|
|
@@ -107,32 +107,7 @@ export function get_cookies(request, url, trailing_slash) {
|
|
|
107
107
|
* @param {import('cookie').CookieSerializeOptions} opts
|
|
108
108
|
*/
|
|
109
109
|
set(name, value, opts = {}) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
new_cookies[name] = {
|
|
113
|
-
name,
|
|
114
|
-
value,
|
|
115
|
-
options: {
|
|
116
|
-
...defaults,
|
|
117
|
-
...opts,
|
|
118
|
-
path
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
if (__SVELTEKIT_DEV__) {
|
|
123
|
-
const serialized = serialize(name, value, new_cookies[name].options);
|
|
124
|
-
if (new TextEncoder().encode(serialized).byteLength > MAX_COOKIE_SIZE) {
|
|
125
|
-
throw new Error(`Cookie "${name}" is too large, and will be discarded by the browser`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
cookie_paths[name] ??= new Set();
|
|
129
|
-
|
|
130
|
-
if (!value) {
|
|
131
|
-
cookie_paths[name].delete(path);
|
|
132
|
-
} else {
|
|
133
|
-
cookie_paths[name].add(path);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
110
|
+
set_internal(name, value, { ...defaults, ...opts });
|
|
136
111
|
},
|
|
137
112
|
|
|
138
113
|
/**
|
|
@@ -193,7 +168,40 @@ export function get_cookies(request, url, trailing_slash) {
|
|
|
193
168
|
.join('; ');
|
|
194
169
|
}
|
|
195
170
|
|
|
196
|
-
|
|
171
|
+
/**
|
|
172
|
+
* @param {string} name
|
|
173
|
+
* @param {string} value
|
|
174
|
+
* @param {import('cookie').CookieSerializeOptions} opts
|
|
175
|
+
*/
|
|
176
|
+
function set_internal(name, value, opts) {
|
|
177
|
+
let path = opts.path ?? default_path;
|
|
178
|
+
|
|
179
|
+
new_cookies[name] = {
|
|
180
|
+
name,
|
|
181
|
+
value,
|
|
182
|
+
options: {
|
|
183
|
+
...opts,
|
|
184
|
+
path
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
if (__SVELTEKIT_DEV__) {
|
|
189
|
+
const serialized = serialize(name, value, new_cookies[name].options);
|
|
190
|
+
if (new TextEncoder().encode(serialized).byteLength > MAX_COOKIE_SIZE) {
|
|
191
|
+
throw new Error(`Cookie "${name}" is too large, and will be discarded by the browser`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
cookie_paths[name] ??= new Set();
|
|
195
|
+
|
|
196
|
+
if (!value) {
|
|
197
|
+
cookie_paths[name].delete(path);
|
|
198
|
+
} else {
|
|
199
|
+
cookie_paths[name].add(path);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return { cookies, new_cookies, get_cookie_header, set_internal };
|
|
197
205
|
}
|
|
198
206
|
|
|
199
207
|
/**
|
|
@@ -9,10 +9,11 @@ import * as paths from '__sveltekit/paths';
|
|
|
9
9
|
* manifest: import('types').SSRManifest;
|
|
10
10
|
* state: import('types').SSRState;
|
|
11
11
|
* get_cookie_header: (url: URL, header: string | null) => string;
|
|
12
|
+
* set_internal: (name: string, value: string, opts: import('cookie').CookieSerializeOptions) => void;
|
|
12
13
|
* }} opts
|
|
13
14
|
* @returns {typeof fetch}
|
|
14
15
|
*/
|
|
15
|
-
export function create_fetch({ event, options, manifest, state, get_cookie_header }) {
|
|
16
|
+
export function create_fetch({ event, options, manifest, state, get_cookie_header, set_internal }) {
|
|
16
17
|
return async (info, init) => {
|
|
17
18
|
const original_request = normalize_fetch_input(info, init, event.url);
|
|
18
19
|
|
|
@@ -131,7 +132,7 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
|
|
|
131
132
|
const { name, value, ...options } = set_cookie_parser.parseString(str);
|
|
132
133
|
|
|
133
134
|
// options.sameSite is string, something more specific is required - type cast is safe
|
|
134
|
-
|
|
135
|
+
set_internal(
|
|
135
136
|
name,
|
|
136
137
|
value,
|
|
137
138
|
/** @type {import('cookie').CookieSerializeOptions} */ (options)
|
|
@@ -244,7 +244,7 @@ export async function respond(request, options, manifest, state) {
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
const { cookies, new_cookies, get_cookie_header } = get_cookies(
|
|
247
|
+
const { cookies, new_cookies, get_cookie_header, set_internal } = get_cookies(
|
|
248
248
|
request,
|
|
249
249
|
url,
|
|
250
250
|
trailing_slash ?? 'never'
|
|
@@ -252,7 +252,14 @@ export async function respond(request, options, manifest, state) {
|
|
|
252
252
|
|
|
253
253
|
cookies_to_add = new_cookies;
|
|
254
254
|
event.cookies = cookies;
|
|
255
|
-
event.fetch = create_fetch({
|
|
255
|
+
event.fetch = create_fetch({
|
|
256
|
+
event,
|
|
257
|
+
options,
|
|
258
|
+
manifest,
|
|
259
|
+
state,
|
|
260
|
+
get_cookie_header,
|
|
261
|
+
set_internal
|
|
262
|
+
});
|
|
256
263
|
|
|
257
264
|
if (state.prerendering && !state.prerendering.fallback) disable_search(url);
|
|
258
265
|
|
package/src/utils/fork.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fileURLToPath } from 'node:url';
|
|
2
|
-
import
|
|
2
|
+
import { Worker, parentPort } from 'node:worker_threads';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Runs a task in a subprocess so any dangling stuff gets killed upon completion.
|
|
@@ -11,23 +11,21 @@ import child_process from 'node:child_process';
|
|
|
11
11
|
* @returns {(opts: T) => Promise<U>} A function that when called starts the subprocess
|
|
12
12
|
*/
|
|
13
13
|
export function forked(module, callback) {
|
|
14
|
-
if (process.env.SVELTEKIT_FORK &&
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
process.on(
|
|
14
|
+
if (process.env.SVELTEKIT_FORK && parentPort) {
|
|
15
|
+
parentPort.on(
|
|
18
16
|
'message',
|
|
19
17
|
/** @param {any} data */ async (data) => {
|
|
20
18
|
if (data?.type === 'args' && data.module === module) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
27
|
-
}
|
|
19
|
+
parentPort?.postMessage({
|
|
20
|
+
type: 'result',
|
|
21
|
+
module,
|
|
22
|
+
payload: await callback(data.payload)
|
|
23
|
+
});
|
|
28
24
|
}
|
|
29
25
|
}
|
|
30
26
|
);
|
|
27
|
+
|
|
28
|
+
parentPort.postMessage({ type: 'ready', module });
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
/**
|
|
@@ -36,20 +34,18 @@ export function forked(module, callback) {
|
|
|
36
34
|
*/
|
|
37
35
|
const fn = function (opts) {
|
|
38
36
|
return new Promise((fulfil, reject) => {
|
|
39
|
-
const
|
|
40
|
-
stdio: 'inherit',
|
|
37
|
+
const worker = new Worker(fileURLToPath(module), {
|
|
41
38
|
env: {
|
|
42
39
|
...process.env,
|
|
43
40
|
SVELTEKIT_FORK: 'true'
|
|
44
|
-
}
|
|
45
|
-
serialization: 'advanced'
|
|
41
|
+
}
|
|
46
42
|
});
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
worker.on(
|
|
49
45
|
'message',
|
|
50
46
|
/** @param {any} data */ (data) => {
|
|
51
47
|
if (data?.type === 'ready' && data.module === module) {
|
|
52
|
-
|
|
48
|
+
worker.postMessage({
|
|
53
49
|
type: 'args',
|
|
54
50
|
module,
|
|
55
51
|
payload: opts
|
|
@@ -57,13 +53,13 @@ export function forked(module, callback) {
|
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
if (data?.type === 'result' && data.module === module) {
|
|
60
|
-
|
|
56
|
+
worker.terminate();
|
|
61
57
|
fulfil(data.payload);
|
|
62
58
|
}
|
|
63
59
|
}
|
|
64
60
|
);
|
|
65
61
|
|
|
66
|
-
|
|
62
|
+
worker.on('exit', (code) => {
|
|
67
63
|
if (code) {
|
|
68
64
|
reject(new Error(`Failed with code ${code}`));
|
|
69
65
|
}
|
package/types/ambient.d.ts
CHANGED
|
@@ -80,15 +80,36 @@ declare module '$app/forms' {
|
|
|
80
80
|
Invalid extends Record<string, unknown> | undefined = Record<string, any>
|
|
81
81
|
> = (input: {
|
|
82
82
|
action: URL;
|
|
83
|
+
/**
|
|
84
|
+
* use `formData` instead of `data`
|
|
85
|
+
* @deprecated
|
|
86
|
+
*/
|
|
83
87
|
data: FormData;
|
|
88
|
+
formData: FormData;
|
|
89
|
+
/**
|
|
90
|
+
* use `formElement` instead of `form`
|
|
91
|
+
* @deprecated
|
|
92
|
+
*/
|
|
84
93
|
form: HTMLFormElement;
|
|
94
|
+
formElement: HTMLFormElement;
|
|
85
95
|
controller: AbortController;
|
|
86
96
|
cancel(): void;
|
|
87
97
|
submitter: HTMLElement | null;
|
|
88
98
|
}) => MaybePromise<
|
|
89
99
|
| void
|
|
90
100
|
| ((opts: {
|
|
101
|
+
/**
|
|
102
|
+
* use `formData` instead of `data`
|
|
103
|
+
* @deprecated
|
|
104
|
+
*/
|
|
105
|
+
data: FormData;
|
|
106
|
+
formData: FormData;
|
|
107
|
+
/**
|
|
108
|
+
* use `formElement` instead of `form`
|
|
109
|
+
* @deprecated
|
|
110
|
+
*/
|
|
91
111
|
form: HTMLFormElement;
|
|
112
|
+
formElement: HTMLFormElement;
|
|
92
113
|
action: URL;
|
|
93
114
|
result: ActionResult<Success, Invalid>;
|
|
94
115
|
/**
|
|
@@ -108,7 +129,7 @@ declare module '$app/forms' {
|
|
|
108
129
|
Success extends Record<string, unknown> | undefined = Record<string, any>,
|
|
109
130
|
Invalid extends Record<string, unknown> | undefined = Record<string, any>
|
|
110
131
|
>(
|
|
111
|
-
|
|
132
|
+
formElement: HTMLFormElement,
|
|
112
133
|
/**
|
|
113
134
|
* Called upon submission with the given FormData and the `action` that should be triggered.
|
|
114
135
|
* If `cancel` is called, the form will not be submitted.
|
package/types/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
UniqueInterface
|
|
21
21
|
} from './private.js';
|
|
22
22
|
import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from './internal.js';
|
|
23
|
+
import type { PluginOptions } from '@sveltejs/vite-plugin-svelte';
|
|
23
24
|
|
|
24
25
|
export { PrerenderOption } from './private.js';
|
|
25
26
|
|
|
@@ -186,6 +187,8 @@ export interface Config {
|
|
|
186
187
|
};
|
|
187
188
|
/** Preprocessor options, if any. Preprocessing can alternatively also be done through Vite's preprocessor capabilities. */
|
|
188
189
|
preprocess?: any;
|
|
190
|
+
/** `vite-plugin-svelte` plugin options. */
|
|
191
|
+
vitePlugin?: PluginOptions;
|
|
189
192
|
/** Any additional options required by tooling that integrates with Svelte. */
|
|
190
193
|
[key: string]: any;
|
|
191
194
|
}
|
package/src/utils/unit_test.js
DELETED