@sveltejs/kit 1.0.0-next.471 → 1.0.0-next.474
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/options.js +4 -14
- package/src/core/sync/write_root.js +4 -4
- package/src/core/sync/write_types/index.js +104 -26
- package/src/exports/index.js +10 -1
- package/src/exports/node/polyfills.js +3 -2
- package/src/exports/vite/build/build_server.js +0 -1
- package/src/exports/vite/dev/index.js +0 -1
- package/src/runtime/app/forms.js +65 -0
- package/src/runtime/client/client.js +122 -58
- package/src/runtime/client/start.js +1 -9
- package/src/runtime/client/types.d.ts +9 -13
- package/src/runtime/control.js +67 -0
- package/src/runtime/server/cookie.js +76 -0
- package/src/runtime/server/endpoint.js +4 -1
- package/src/runtime/server/index.js +21 -40
- package/src/runtime/server/page/actions.js +243 -0
- package/src/runtime/server/page/fetch.js +1 -1
- package/src/runtime/server/page/index.js +35 -132
- package/src/runtime/server/page/render.js +14 -18
- package/src/runtime/server/page/respond_with_error.js +1 -2
- package/src/runtime/server/utils.js +11 -0
- package/types/ambient.d.ts +48 -0
- package/types/index.d.ts +58 -19
- package/types/internal.d.ts +3 -12
- package/types/private.d.ts +0 -3
- package/src/runtime/server/page/cookie.js +0 -25
package/package.json
CHANGED
|
@@ -171,20 +171,10 @@ const options = object(
|
|
|
171
171
|
|
|
172
172
|
inlineStyleThreshold: number(0),
|
|
173
173
|
|
|
174
|
-
methodOverride:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
throw new Error(`${keypath} must be an array of strings`);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (input.map((i) => i.toUpperCase()).includes('GET')) {
|
|
182
|
-
throw new Error(`${keypath} cannot contain "GET"`);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return input;
|
|
186
|
-
})
|
|
187
|
-
}),
|
|
174
|
+
methodOverride: error(
|
|
175
|
+
() =>
|
|
176
|
+
'Method overrides have been removed in favor of actions. See the PR for more information: https://github.com/sveltejs/kit/pull/6469'
|
|
177
|
+
),
|
|
188
178
|
|
|
189
179
|
moduleExtensions: string_array(['.js', '.ts']),
|
|
190
180
|
|
|
@@ -21,16 +21,16 @@ export function write_root(manifest_data, output) {
|
|
|
21
21
|
|
|
22
22
|
let l = max_depth;
|
|
23
23
|
|
|
24
|
-
let pyramid = `<svelte:component this={components[${l}]} data={data_${l}} {
|
|
24
|
+
let pyramid = `<svelte:component this={components[${l}]} data={data_${l}} {form} />`;
|
|
25
25
|
|
|
26
26
|
while (l--) {
|
|
27
27
|
pyramid = `
|
|
28
28
|
{#if components[${l + 1}]}
|
|
29
|
-
<svelte:component this={components[${l}]} data={data_${l}}
|
|
29
|
+
<svelte:component this={components[${l}]} data={data_${l}}>
|
|
30
30
|
${pyramid.replace(/\n/g, '\n\t\t\t\t\t')}
|
|
31
31
|
</svelte:component>
|
|
32
32
|
{:else}
|
|
33
|
-
<svelte:component this={components[${l}]} data={data_${l}} {
|
|
33
|
+
<svelte:component this={components[${l}]} data={data_${l}} {form} />
|
|
34
34
|
{/if}
|
|
35
35
|
`
|
|
36
36
|
.replace(/^\t\t\t/gm, '')
|
|
@@ -50,8 +50,8 @@ export function write_root(manifest_data, output) {
|
|
|
50
50
|
export let page;
|
|
51
51
|
|
|
52
52
|
export let components;
|
|
53
|
+
export let form;
|
|
53
54
|
${levels.map((l) => `export let data_${l} = null;`).join('\n\t\t\t\t')}
|
|
54
|
-
export let errors;
|
|
55
55
|
|
|
56
56
|
if (!browser) {
|
|
57
57
|
setContext('__svelte__', stores);
|
|
@@ -21,9 +21,6 @@ try {
|
|
|
21
21
|
|
|
22
22
|
const cwd = process.cwd();
|
|
23
23
|
|
|
24
|
-
const shared_names = new Set(['load']);
|
|
25
|
-
const server_names = new Set(['load', 'POST', 'PUT', 'PATCH', 'DELETE']); // TODO replace with a single `action`
|
|
26
|
-
|
|
27
24
|
/**
|
|
28
25
|
* Creates types for the whole manifest
|
|
29
26
|
* @param {import('types').ValidatedConfig} config
|
|
@@ -193,6 +190,7 @@ function update_types(config, routes, route) {
|
|
|
193
190
|
|
|
194
191
|
if (route.leaf.server) {
|
|
195
192
|
exports.push(`export type Action = Kit.Action<RouteParams>`);
|
|
193
|
+
exports.push(`export type Actions = Kit.Actions<RouteParams>`);
|
|
196
194
|
}
|
|
197
195
|
}
|
|
198
196
|
|
|
@@ -231,6 +229,9 @@ function update_types(config, routes, route) {
|
|
|
231
229
|
|
|
232
230
|
if (route.endpoint) {
|
|
233
231
|
exports.push(`export type RequestHandler = Kit.RequestHandler<RouteParams>;`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (route.leaf?.server || route.endpoint) {
|
|
234
235
|
exports.push(`export type RequestEvent = Kit.RequestEvent<RouteParams>;`);
|
|
235
236
|
}
|
|
236
237
|
|
|
@@ -270,7 +271,7 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
|
|
|
270
271
|
|
|
271
272
|
if (node.server) {
|
|
272
273
|
const content = fs.readFileSync(node.server, 'utf8');
|
|
273
|
-
const proxy = tweak_types(content,
|
|
274
|
+
const proxy = tweak_types(content, true);
|
|
274
275
|
const basename = path.basename(node.server);
|
|
275
276
|
if (proxy?.modified) {
|
|
276
277
|
fs.writeFileSync(`${outdir}/proxy${basename}`, proxy.code);
|
|
@@ -295,23 +296,19 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
|
|
|
295
296
|
exports.push(`export type ${prefix}ServerLoadEvent = Parameters<${prefix}ServerLoad>[0];`);
|
|
296
297
|
|
|
297
298
|
if (is_page) {
|
|
298
|
-
let
|
|
299
|
+
let type = 'unknown';
|
|
299
300
|
if (proxy) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
types.push(`Kit.AwaitedErrors<typeof import('${from}').${method}>`);
|
|
310
|
-
}
|
|
301
|
+
if (proxy.exports.includes('actions')) {
|
|
302
|
+
// If the file wasn't tweaked, we can use the return type of the original file.
|
|
303
|
+
// The advantage is that type updates are reflected without saving.
|
|
304
|
+
const from = proxy.modified
|
|
305
|
+
? `./proxy${replace_ext_with_js(basename)}`
|
|
306
|
+
: path_to_original(outdir, node.server);
|
|
307
|
+
|
|
308
|
+
type = `Kit.AwaitedActions<typeof import('${from}').actions>`;
|
|
311
309
|
}
|
|
312
|
-
errors = types.length ? types.join(' | ') : 'null';
|
|
313
310
|
}
|
|
314
|
-
exports.push(`export type
|
|
311
|
+
exports.push(`export type ActionData = ${type};`);
|
|
315
312
|
}
|
|
316
313
|
} else {
|
|
317
314
|
server_data = 'null';
|
|
@@ -323,7 +320,7 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
|
|
|
323
320
|
|
|
324
321
|
if (node.shared) {
|
|
325
322
|
const content = fs.readFileSync(node.shared, 'utf8');
|
|
326
|
-
const proxy = tweak_types(content,
|
|
323
|
+
const proxy = tweak_types(content, false);
|
|
327
324
|
if (proxy?.modified) {
|
|
328
325
|
fs.writeFileSync(`${outdir}/proxy${path.basename(node.shared)}`, proxy.code);
|
|
329
326
|
written_proxies.push(`proxy${path.basename(node.shared)}`);
|
|
@@ -426,10 +423,12 @@ function replace_ext_with_js(file_path) {
|
|
|
426
423
|
|
|
427
424
|
/**
|
|
428
425
|
* @param {string} content
|
|
429
|
-
* @param {
|
|
426
|
+
* @param {boolean} is_server
|
|
430
427
|
* @returns {Proxy}
|
|
431
428
|
*/
|
|
432
|
-
export function tweak_types(content,
|
|
429
|
+
export function tweak_types(content, is_server) {
|
|
430
|
+
const names = new Set(is_server ? ['load', 'actions'] : ['load']);
|
|
431
|
+
|
|
433
432
|
try {
|
|
434
433
|
let modified = false;
|
|
435
434
|
|
|
@@ -480,6 +479,7 @@ export function tweak_types(content, names) {
|
|
|
480
479
|
* @param {import('typescript').Node} value
|
|
481
480
|
*/
|
|
482
481
|
function replace_jsdoc_type_tags(node, value) {
|
|
482
|
+
let _modified = false;
|
|
483
483
|
// @ts-ignore
|
|
484
484
|
if (node.jsDoc) {
|
|
485
485
|
// @ts-ignore
|
|
@@ -492,22 +492,27 @@ export function tweak_types(content, names) {
|
|
|
492
492
|
ts.isArrowFunction(value);
|
|
493
493
|
|
|
494
494
|
if (is_fn && value.parameters?.length > 0) {
|
|
495
|
+
const name = ts.isIdentifier(value.parameters[0].name)
|
|
496
|
+
? value.parameters[0].name.text
|
|
497
|
+
: 'event';
|
|
495
498
|
code.overwrite(tag.tagName.pos, tag.tagName.end, 'param');
|
|
496
499
|
code.prependRight(tag.typeExpression.pos + 1, 'Parameters<');
|
|
497
500
|
code.appendLeft(tag.typeExpression.end - 1, '>[0]');
|
|
498
|
-
code.appendLeft(tag.typeExpression.end,
|
|
501
|
+
code.appendLeft(tag.typeExpression.end, ` ${name}`);
|
|
499
502
|
} else {
|
|
500
503
|
code.overwrite(tag.pos, tag.end, '');
|
|
501
504
|
}
|
|
502
|
-
|
|
505
|
+
_modified = true;
|
|
503
506
|
}
|
|
504
507
|
}
|
|
505
508
|
}
|
|
506
509
|
}
|
|
510
|
+
modified ||= _modified;
|
|
511
|
+
return _modified;
|
|
507
512
|
}
|
|
508
513
|
|
|
509
514
|
ast.forEachChild((node) => {
|
|
510
|
-
if (ts.isFunctionDeclaration(node) && node.name?.text &&
|
|
515
|
+
if (ts.isFunctionDeclaration(node) && node.name?.text && node.name?.text === 'load') {
|
|
511
516
|
// remove JSDoc comment above `export function load ...`
|
|
512
517
|
replace_jsdoc_type_tags(node, node);
|
|
513
518
|
}
|
|
@@ -525,7 +530,7 @@ export function tweak_types(content, names) {
|
|
|
525
530
|
for (const declaration of node.declarationList.declarations) {
|
|
526
531
|
if (
|
|
527
532
|
ts.isIdentifier(declaration.name) &&
|
|
528
|
-
|
|
533
|
+
declaration.name.text === 'load' &&
|
|
529
534
|
declaration.initializer
|
|
530
535
|
) {
|
|
531
536
|
// edge case — remove JSDoc comment above individual export
|
|
@@ -548,7 +553,6 @@ export function tweak_types(content, names) {
|
|
|
548
553
|
rhs.parameters.length
|
|
549
554
|
) {
|
|
550
555
|
const arg = rhs.parameters[0];
|
|
551
|
-
|
|
552
556
|
const add_parens = content[arg.pos - 1] !== '(';
|
|
553
557
|
|
|
554
558
|
if (add_parens) code.prependRight(arg.pos, '(');
|
|
@@ -569,6 +573,80 @@ export function tweak_types(content, names) {
|
|
|
569
573
|
|
|
570
574
|
modified = true;
|
|
571
575
|
}
|
|
576
|
+
} else if (
|
|
577
|
+
is_server &&
|
|
578
|
+
ts.isIdentifier(declaration.name) &&
|
|
579
|
+
declaration.name?.text === 'actions' &&
|
|
580
|
+
declaration.initializer
|
|
581
|
+
) {
|
|
582
|
+
// remove JSDoc comment from `export const actions = ..`
|
|
583
|
+
const removed = replace_jsdoc_type_tags(node, declaration.initializer);
|
|
584
|
+
// ... and move type to each individual action
|
|
585
|
+
if (removed) {
|
|
586
|
+
const rhs = declaration.initializer;
|
|
587
|
+
if (ts.isObjectLiteralExpression(rhs)) {
|
|
588
|
+
for (const prop of rhs.properties) {
|
|
589
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
590
|
+
const rhs = prop.initializer;
|
|
591
|
+
const replaced = replace_jsdoc_type_tags(prop, rhs);
|
|
592
|
+
if (
|
|
593
|
+
!replaced &&
|
|
594
|
+
rhs &&
|
|
595
|
+
(ts.isArrowFunction(rhs) || ts.isFunctionExpression(rhs)) &&
|
|
596
|
+
rhs.parameters?.[0]
|
|
597
|
+
) {
|
|
598
|
+
const name = ts.isIdentifier(rhs.parameters[0].name)
|
|
599
|
+
? rhs.parameters[0].name.text
|
|
600
|
+
: 'event';
|
|
601
|
+
code.prependRight(
|
|
602
|
+
rhs.pos,
|
|
603
|
+
`/** @param {import('./$types').RequestEvent} ${name} */ `
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// remove type from `export const actions: Actions ...`
|
|
612
|
+
if (declaration.type) {
|
|
613
|
+
let a = declaration.type.pos;
|
|
614
|
+
let b = declaration.type.end;
|
|
615
|
+
while (/\s/.test(content[a])) a += 1;
|
|
616
|
+
|
|
617
|
+
const type = content.slice(a, b);
|
|
618
|
+
code.remove(declaration.name.end, declaration.type.end);
|
|
619
|
+
code.append(`;null as any as ${type};`);
|
|
620
|
+
modified = true;
|
|
621
|
+
|
|
622
|
+
// ... and move type to each individual action
|
|
623
|
+
const rhs = declaration.initializer;
|
|
624
|
+
if (ts.isObjectLiteralExpression(rhs)) {
|
|
625
|
+
for (const prop of rhs.properties) {
|
|
626
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
627
|
+
const rhs = prop.initializer;
|
|
628
|
+
|
|
629
|
+
if (
|
|
630
|
+
rhs &&
|
|
631
|
+
(ts.isArrowFunction(rhs) || ts.isFunctionExpression(rhs)) &&
|
|
632
|
+
rhs.parameters.length
|
|
633
|
+
) {
|
|
634
|
+
const arg = rhs.parameters[0];
|
|
635
|
+
const add_parens = content[arg.pos - 1] !== '(';
|
|
636
|
+
|
|
637
|
+
if (add_parens) code.prependRight(arg.pos, '(');
|
|
638
|
+
|
|
639
|
+
if (arg && !arg.type) {
|
|
640
|
+
code.appendLeft(
|
|
641
|
+
arg.name.end,
|
|
642
|
+
`: import('./$types').RequestEvent` + (add_parens ? ')' : '')
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
572
650
|
}
|
|
573
651
|
}
|
|
574
652
|
}
|
package/src/exports/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HttpError, Redirect } from '../runtime/control.js';
|
|
1
|
+
import { HttpError, Redirect, ValidationError } from '../runtime/control.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Creates an `HttpError` object with an HTTP status code and an optional message.
|
|
@@ -43,3 +43,12 @@ export function json(data, init) {
|
|
|
43
43
|
headers
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Generates a `ValidationError` object.
|
|
49
|
+
* @param {number} status
|
|
50
|
+
* @param {Record<string, any> | undefined} [data]
|
|
51
|
+
*/
|
|
52
|
+
export function invalid(status, data) {
|
|
53
|
+
return new ValidationError(status, data);
|
|
54
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fetch, Response, Request, Headers } from 'undici';
|
|
2
2
|
import { ReadableStream, TransformStream, WritableStream } from 'stream/web';
|
|
3
3
|
import { Readable } from 'stream';
|
|
4
|
-
import { Request as NodeFetchRequest } from 'node-fetch';
|
|
4
|
+
import { Request as NodeFetchRequest, FormData } from 'node-fetch';
|
|
5
5
|
import { webcrypto as crypto } from 'crypto';
|
|
6
6
|
|
|
7
7
|
/** @type {Record<string, any>} */
|
|
@@ -24,7 +24,8 @@ const globals = {
|
|
|
24
24
|
Headers,
|
|
25
25
|
ReadableStream,
|
|
26
26
|
TransformStream,
|
|
27
|
-
WritableStream
|
|
27
|
+
WritableStream,
|
|
28
|
+
FormData
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
// exported for dev/preview and node environments
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { invalidateAll } from './navigation.js';
|
|
2
|
+
import { client } from '../client/singletons.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} name
|
|
6
|
+
*/
|
|
7
|
+
function guard(name) {
|
|
8
|
+
return () => {
|
|
9
|
+
throw new Error(`Cannot call ${name}(...) on the server`);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ssr = import.meta.env.SSR;
|
|
14
|
+
|
|
15
|
+
/** @type {import('$app/forms').applyAction} */
|
|
16
|
+
export const applyAction = ssr ? guard('applyAction') : client.apply_action;
|
|
17
|
+
|
|
18
|
+
/** @type {import('$app/forms').enhance} */
|
|
19
|
+
export function enhance(form, submit = () => {}) {
|
|
20
|
+
/** @param {import('types').ActionResult} result */
|
|
21
|
+
const fallback_callback = async (result) => {
|
|
22
|
+
if (result.type === 'success') {
|
|
23
|
+
await invalidateAll();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (location.origin + location.pathname === form.action.split('?')[0]) {
|
|
27
|
+
applyAction(result);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** @param {SubmitEvent} event */
|
|
32
|
+
async function handle_submit(event) {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
|
|
35
|
+
const data = new FormData(form);
|
|
36
|
+
|
|
37
|
+
let cancelled = false;
|
|
38
|
+
const cancel = () => (cancelled = true);
|
|
39
|
+
|
|
40
|
+
const callback = submit({ form, data, cancel }) ?? fallback_callback;
|
|
41
|
+
if (cancelled) return;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const response = await fetch(form.action, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: {
|
|
47
|
+
accept: 'application/json'
|
|
48
|
+
},
|
|
49
|
+
body: data
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
callback(await response.json());
|
|
53
|
+
} catch (error) {
|
|
54
|
+
callback({ type: 'error', error });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
form.addEventListener('submit', handle_submit);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
destroy() {
|
|
62
|
+
form.removeEventListener('submit', handle_submit);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|