@sveltejs/kit 1.0.0-next.576 → 1.0.0-next.578
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/adapt/builder.js +42 -11
- package/src/core/config/options.js +2 -0
- package/src/core/prerender/fallback.js +43 -0
- package/src/core/prerender/prerender.js +0 -12
- package/src/exports/index.js +9 -4
- package/src/exports/vite/build/build_server.js +1 -0
- package/src/exports/vite/build/utils.js +2 -1
- package/src/exports/vite/dev/index.js +1 -0
- package/src/exports/vite/index.js +2 -1
- package/src/runtime/app/forms.js +1 -1
- package/src/runtime/client/client.js +25 -9
- package/src/runtime/client/fetcher.js +10 -10
- package/src/runtime/control.js +1 -1
- package/src/runtime/server/page/actions.js +11 -11
- package/src/runtime/server/page/index.js +1 -1
- package/src/runtime/server/page/render.js +31 -14
- package/types/index.d.ts +18 -14
- package/types/internal.d.ts +2 -0
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { existsSync, statSync, createReadStream, createWriteStream } from 'node:fs';
|
|
2
|
+
import { pipeline } from 'node:stream';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { fork } from 'node:child_process';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
1
6
|
import glob from 'tiny-glob';
|
|
2
7
|
import zlib from 'zlib';
|
|
3
|
-
import { existsSync, statSync, createReadStream, createWriteStream } from 'fs';
|
|
4
|
-
import { pipeline } from 'stream';
|
|
5
|
-
import { promisify } from 'util';
|
|
6
8
|
import { copy, rimraf, mkdirp } from '../../utils/filesystem.js';
|
|
7
9
|
import { generate_manifest } from '../generate_manifest/index.js';
|
|
8
10
|
import { get_route_segments } from '../../utils/routing.js';
|
|
11
|
+
import { get_env } from '../../exports/vite/utils.js';
|
|
9
12
|
|
|
10
13
|
const pipe = promisify(pipeline);
|
|
11
14
|
|
|
@@ -104,6 +107,33 @@ export function create_builder({ config, build_data, routes, prerendered, log })
|
|
|
104
107
|
}
|
|
105
108
|
},
|
|
106
109
|
|
|
110
|
+
generateFallback(dest) {
|
|
111
|
+
// do prerendering in a subprocess so any dangling stuff gets killed upon completion
|
|
112
|
+
const script = fileURLToPath(new URL('../prerender/fallback.js', import.meta.url));
|
|
113
|
+
|
|
114
|
+
const manifest_path = `${config.kit.outDir}/output/server/manifest-full.js`;
|
|
115
|
+
|
|
116
|
+
const env = get_env(config.kit.env, 'production');
|
|
117
|
+
|
|
118
|
+
return new Promise((fulfil, reject) => {
|
|
119
|
+
const child = fork(
|
|
120
|
+
script,
|
|
121
|
+
[dest, manifest_path, JSON.stringify({ ...env.private, ...env.public })],
|
|
122
|
+
{
|
|
123
|
+
stdio: 'inherit'
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
child.on('exit', (code) => {
|
|
128
|
+
if (code) {
|
|
129
|
+
reject(new Error(`Could not create a fallback page — failed with code ${code}`));
|
|
130
|
+
} else {
|
|
131
|
+
fulfil(undefined);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
|
|
107
137
|
generateManifest: ({ relativePath }) => {
|
|
108
138
|
return generate_manifest({
|
|
109
139
|
build_data,
|
|
@@ -132,16 +162,17 @@ export function create_builder({ config, build_data, routes, prerendered, log })
|
|
|
132
162
|
return [...copy(`${config.kit.outDir}/output/client`, dest)];
|
|
133
163
|
},
|
|
134
164
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
165
|
+
// @ts-expect-error
|
|
166
|
+
writePrerendered(dest, opts) {
|
|
167
|
+
// TODO remove for 1.0
|
|
168
|
+
if (opts?.fallback) {
|
|
169
|
+
throw new Error(
|
|
170
|
+
'The fallback option no longer exists — use builder.generateFallback(fallback) instead'
|
|
171
|
+
);
|
|
142
172
|
}
|
|
143
173
|
|
|
144
|
-
|
|
174
|
+
const source = `${config.kit.outDir}/output/prerendered`;
|
|
175
|
+
return [...copy(`${source}/pages`, dest), ...copy(`${source}/dependencies`, dest)];
|
|
145
176
|
},
|
|
146
177
|
|
|
147
178
|
writeServer(dest) {
|
|
@@ -129,6 +129,8 @@ const options = object(
|
|
|
129
129
|
checkOrigin: boolean(true)
|
|
130
130
|
}),
|
|
131
131
|
|
|
132
|
+
embedded: boolean(false),
|
|
133
|
+
|
|
132
134
|
// TODO: remove this for the 1.0 release
|
|
133
135
|
endpointExtensions: error(
|
|
134
136
|
(keypath) => `${keypath} has been renamed to config.kit.moduleExtensions`
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
4
|
+
import { mkdirp } from '../../utils/filesystem.js';
|
|
5
|
+
import { installPolyfills } from '../../exports/node/polyfills.js';
|
|
6
|
+
import { load_config } from '../config/index.js';
|
|
7
|
+
|
|
8
|
+
const [, , dest, manifest_path, env] = process.argv;
|
|
9
|
+
|
|
10
|
+
/** @type {import('types').ValidatedKitConfig} */
|
|
11
|
+
const config = (await load_config()).kit;
|
|
12
|
+
|
|
13
|
+
installPolyfills();
|
|
14
|
+
|
|
15
|
+
const server_root = join(config.outDir, 'output');
|
|
16
|
+
|
|
17
|
+
/** @type {import('types').ServerModule} */
|
|
18
|
+
const { Server, override } = await import(pathToFileURL(`${server_root}/server/index.js`).href);
|
|
19
|
+
|
|
20
|
+
/** @type {import('types').SSRManifest} */
|
|
21
|
+
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
|
|
22
|
+
|
|
23
|
+
override({
|
|
24
|
+
building: true,
|
|
25
|
+
paths: config.paths,
|
|
26
|
+
read: (file) => readFileSync(join(config.files.assets, file))
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const server = new Server(manifest);
|
|
30
|
+
await server.init({ env: JSON.parse(env) });
|
|
31
|
+
|
|
32
|
+
const rendered = await server.respond(new Request(config.prerender.origin + '/[fallback]'), {
|
|
33
|
+
getClientAddress: () => {
|
|
34
|
+
throw new Error('Cannot read clientAddress during prerendering');
|
|
35
|
+
},
|
|
36
|
+
prerendering: {
|
|
37
|
+
fallback: true,
|
|
38
|
+
dependencies: new Map()
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
mkdirp(dirname(dest));
|
|
43
|
+
writeFileSync(dest, await rendered.text());
|
|
@@ -453,18 +453,6 @@ export async function prerender() {
|
|
|
453
453
|
);
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
-
const rendered = await server.respond(new Request(config.prerender.origin + '/[fallback]'), {
|
|
457
|
-
getClientAddress,
|
|
458
|
-
prerendering: {
|
|
459
|
-
fallback: true,
|
|
460
|
-
dependencies: new Map()
|
|
461
|
-
}
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
const file = `${config.outDir}/output/prerendered/fallback.html`;
|
|
465
|
-
mkdirp(dirname(file));
|
|
466
|
-
writeFileSync(file, await rendered.text());
|
|
467
|
-
|
|
468
456
|
output_and_exit({ prerendered, prerender_map });
|
|
469
457
|
}
|
|
470
458
|
|
package/src/exports/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HttpError, Redirect,
|
|
1
|
+
import { HttpError, Redirect, ActionFailure } from '../runtime/control.js';
|
|
2
2
|
|
|
3
3
|
// For some reason we need to type the params as well here,
|
|
4
4
|
// JSdoc doesn't seem to like @type with function overloads
|
|
@@ -46,10 +46,15 @@ export function json(data, init) {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Generates
|
|
49
|
+
* Generates an `ActionFailure` object.
|
|
50
50
|
* @param {number} status
|
|
51
51
|
* @param {Record<string, any> | undefined} [data]
|
|
52
52
|
*/
|
|
53
|
-
export function
|
|
54
|
-
return new
|
|
53
|
+
export function fail(status, data) {
|
|
54
|
+
return new ActionFailure(status, data);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// TODO remove for 1.0
|
|
58
|
+
export function invalid() {
|
|
59
|
+
throw new Error('invalid(...) is now fail(...)');
|
|
55
60
|
}
|
|
@@ -147,7 +147,8 @@ export function get_default_build_config({ config, input, ssr, outDir }) {
|
|
|
147
147
|
__SVELTEKIT_APP_VERSION_FILE__: JSON.stringify(`${config.kit.appDir}/version.json`),
|
|
148
148
|
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: JSON.stringify(config.kit.version.pollInterval),
|
|
149
149
|
__SVELTEKIT_BROWSER__: ssr ? 'false' : 'true',
|
|
150
|
-
__SVELTEKIT_DEV__: 'false'
|
|
150
|
+
__SVELTEKIT_DEV__: 'false',
|
|
151
|
+
__SVELTEKIT_EMBEDDED__: config.kit.embedded ? 'true' : 'false'
|
|
151
152
|
},
|
|
152
153
|
publicDir: ssr ? false : config.kit.files.assets,
|
|
153
154
|
resolve: {
|
|
@@ -449,6 +449,7 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
449
449
|
check_origin: svelte_config.kit.csrf.checkOrigin
|
|
450
450
|
},
|
|
451
451
|
dev: true,
|
|
452
|
+
embedded: svelte_config.kit.embedded,
|
|
452
453
|
handle_error: async (error, event) => {
|
|
453
454
|
const error_object = await hooks.handleError({
|
|
454
455
|
error: new Proxy(error, {
|
|
@@ -262,7 +262,8 @@ function kit({ svelte_config }) {
|
|
|
262
262
|
define: {
|
|
263
263
|
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0',
|
|
264
264
|
__SVELTEKIT_BROWSER__: config_env.ssrBuild ? 'false' : 'true',
|
|
265
|
-
__SVELTEKIT_DEV__: 'true'
|
|
265
|
+
__SVELTEKIT_DEV__: 'true',
|
|
266
|
+
__SVELTEKIT_EMBEDDED__: svelte_config.kit.embedded ? 'true' : 'false'
|
|
266
267
|
},
|
|
267
268
|
publicDir: svelte_config.kit.files.assets,
|
|
268
269
|
resolve: {
|
package/src/runtime/app/forms.js
CHANGED
|
@@ -47,7 +47,7 @@ export function enhance(form, submit = () => {}) {
|
|
|
47
47
|
await invalidateAll();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
// For success/
|
|
50
|
+
// For success/failure results, only apply action if it belongs to the
|
|
51
51
|
// current page, otherwise `form` will be updated erroneously
|
|
52
52
|
if (
|
|
53
53
|
location.origin + location.pathname === action.origin + action.pathname ||
|
|
@@ -89,6 +89,7 @@ function check_for_removed_attributes() {
|
|
|
89
89
|
* @returns {import('./types').Client}
|
|
90
90
|
*/
|
|
91
91
|
export function create_client({ target, base }) {
|
|
92
|
+
const container = __SVELTEKIT_EMBEDDED__ ? target : document.documentElement;
|
|
92
93
|
/** @type {Array<((url: URL) => boolean)>} */
|
|
93
94
|
const invalidated = [];
|
|
94
95
|
|
|
@@ -591,6 +592,7 @@ export function create_client({ target, base }) {
|
|
|
591
592
|
uses.url = true;
|
|
592
593
|
}),
|
|
593
594
|
async fetch(resource, init) {
|
|
595
|
+
/** @type {URL | string} */
|
|
594
596
|
let requested;
|
|
595
597
|
|
|
596
598
|
if (resource instanceof Request) {
|
|
@@ -1199,7 +1201,7 @@ export function create_client({ target, base }) {
|
|
|
1199
1201
|
/** @type {NodeJS.Timeout} */
|
|
1200
1202
|
let mousemove_timeout;
|
|
1201
1203
|
|
|
1202
|
-
|
|
1204
|
+
container.addEventListener('mousemove', (event) => {
|
|
1203
1205
|
const target = /** @type {Element} */ (event.target);
|
|
1204
1206
|
|
|
1205
1207
|
clearTimeout(mousemove_timeout);
|
|
@@ -1213,8 +1215,8 @@ export function create_client({ target, base }) {
|
|
|
1213
1215
|
preload(/** @type {Element} */ (event.composedPath()[0]), 1);
|
|
1214
1216
|
}
|
|
1215
1217
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
+
container.addEventListener('mousedown', tap);
|
|
1219
|
+
container.addEventListener('touchstart', tap, { passive: true });
|
|
1218
1220
|
|
|
1219
1221
|
const observer = new IntersectionObserver(
|
|
1220
1222
|
(entries) => {
|
|
@@ -1233,7 +1235,7 @@ export function create_client({ target, base }) {
|
|
|
1233
1235
|
* @param {number} priority
|
|
1234
1236
|
*/
|
|
1235
1237
|
function preload(element, priority) {
|
|
1236
|
-
const a = find_anchor(element,
|
|
1238
|
+
const a = find_anchor(element, container);
|
|
1237
1239
|
if (!a) return;
|
|
1238
1240
|
|
|
1239
1241
|
const { url, external } = get_link_info(a, base);
|
|
@@ -1253,7 +1255,7 @@ export function create_client({ target, base }) {
|
|
|
1253
1255
|
function after_navigate() {
|
|
1254
1256
|
observer.disconnect();
|
|
1255
1257
|
|
|
1256
|
-
for (const a of
|
|
1258
|
+
for (const a of container.querySelectorAll('a')) {
|
|
1257
1259
|
const { url, external } = get_link_info(a, base);
|
|
1258
1260
|
if (external) continue;
|
|
1259
1261
|
|
|
@@ -1457,14 +1459,14 @@ export function create_client({ target, base }) {
|
|
|
1457
1459
|
}
|
|
1458
1460
|
|
|
1459
1461
|
/** @param {MouseEvent} event */
|
|
1460
|
-
|
|
1462
|
+
container.addEventListener('click', (event) => {
|
|
1461
1463
|
// Adapted from https://github.com/visionmedia/page.js
|
|
1462
1464
|
// MIT license https://github.com/visionmedia/page.js#license
|
|
1463
1465
|
if (event.button || event.which !== 1) return;
|
|
1464
1466
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
1465
1467
|
if (event.defaultPrevented) return;
|
|
1466
1468
|
|
|
1467
|
-
const a = find_anchor(/** @type {Element} */ (event.composedPath()[0]),
|
|
1469
|
+
const a = find_anchor(/** @type {Element} */ (event.composedPath()[0]), container);
|
|
1468
1470
|
if (!a) return;
|
|
1469
1471
|
|
|
1470
1472
|
const { url, external, has } = get_link_info(a, base);
|
|
@@ -1534,7 +1536,7 @@ export function create_client({ target, base }) {
|
|
|
1534
1536
|
});
|
|
1535
1537
|
});
|
|
1536
1538
|
|
|
1537
|
-
|
|
1539
|
+
container.addEventListener('submit', (event) => {
|
|
1538
1540
|
if (event.defaultPrevented) return;
|
|
1539
1541
|
|
|
1540
1542
|
const form = /** @type {HTMLFormElement} */ (
|
|
@@ -1639,11 +1641,25 @@ export function create_client({ target, base }) {
|
|
|
1639
1641
|
});
|
|
1640
1642
|
},
|
|
1641
1643
|
|
|
1642
|
-
_hydrate: async ({
|
|
1644
|
+
_hydrate: async ({
|
|
1645
|
+
status = 200,
|
|
1646
|
+
error,
|
|
1647
|
+
node_ids,
|
|
1648
|
+
params,
|
|
1649
|
+
route,
|
|
1650
|
+
data: server_data_nodes,
|
|
1651
|
+
form
|
|
1652
|
+
}) => {
|
|
1643
1653
|
hydrated = true;
|
|
1644
1654
|
|
|
1645
1655
|
const url = new URL(location.href);
|
|
1646
1656
|
|
|
1657
|
+
if (!__SVELTEKIT_EMBEDDED__) {
|
|
1658
|
+
// See https://github.com/sveltejs/kit/pull/4935#issuecomment-1328093358 for one motivation
|
|
1659
|
+
// of determining the params on the client side.
|
|
1660
|
+
({ params = {}, route = { id: null } } = get_navigation_intent(url, false) || {});
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1647
1663
|
/** @type {import('./types').NavigationFinished | undefined} */
|
|
1648
1664
|
let result;
|
|
1649
1665
|
|
|
@@ -41,9 +41,7 @@ if (import.meta.env.DEV) {
|
|
|
41
41
|
const method = input instanceof Request ? input.method : init?.method || 'GET';
|
|
42
42
|
|
|
43
43
|
if (method !== 'GET') {
|
|
44
|
-
|
|
45
|
-
.href;
|
|
46
|
-
cache.delete(url);
|
|
44
|
+
cache.delete(build_selector(input));
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
return native_fetch(input, init);
|
|
@@ -53,9 +51,7 @@ if (import.meta.env.DEV) {
|
|
|
53
51
|
const method = input instanceof Request ? input.method : init?.method || 'GET';
|
|
54
52
|
|
|
55
53
|
if (method !== 'GET') {
|
|
56
|
-
|
|
57
|
-
.href;
|
|
58
|
-
cache.delete(url);
|
|
54
|
+
cache.delete(build_selector(input));
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
return native_fetch(input, init);
|
|
@@ -67,7 +63,7 @@ const cache = new Map();
|
|
|
67
63
|
/**
|
|
68
64
|
* Should be called on the initial run of load functions that hydrate the page.
|
|
69
65
|
* Saves any requests with cache-control max-age to the cache.
|
|
70
|
-
* @param {
|
|
66
|
+
* @param {URL | string} resource
|
|
71
67
|
* @param {RequestInit} [opts]
|
|
72
68
|
*/
|
|
73
69
|
export function initial_fetch(resource, opts) {
|
|
@@ -88,7 +84,7 @@ export function initial_fetch(resource, opts) {
|
|
|
88
84
|
|
|
89
85
|
/**
|
|
90
86
|
* Tries to get the response from the cache, if max-age allows it, else does a fetch.
|
|
91
|
-
* @param {
|
|
87
|
+
* @param {URL | string} resource
|
|
92
88
|
* @param {string} resolved
|
|
93
89
|
* @param {RequestInit} [opts]
|
|
94
90
|
*/
|
|
@@ -97,7 +93,11 @@ export function subsequent_fetch(resource, resolved, opts) {
|
|
|
97
93
|
const selector = build_selector(resource, opts);
|
|
98
94
|
const cached = cache.get(selector);
|
|
99
95
|
if (cached) {
|
|
100
|
-
|
|
96
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Request/cache#value
|
|
97
|
+
if (
|
|
98
|
+
performance.now() < cached.ttl &&
|
|
99
|
+
['default', 'force-cache', 'only-if-cached', undefined].includes(opts?.cache)
|
|
100
|
+
) {
|
|
101
101
|
return new Response(cached.body, cached.init);
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -110,7 +110,7 @@ export function subsequent_fetch(resource, resolved, opts) {
|
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
112
|
* Build the cache key for a given request
|
|
113
|
-
* @param {
|
|
113
|
+
* @param {URL | RequestInfo} resource
|
|
114
114
|
* @param {RequestInit} [opts]
|
|
115
115
|
*/
|
|
116
116
|
function build_selector(resource, opts) {
|
package/src/runtime/control.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as devalue from 'devalue';
|
|
|
2
2
|
import { error, json } from '../../../exports/index.js';
|
|
3
3
|
import { normalize_error } from '../../../utils/error.js';
|
|
4
4
|
import { is_form_content_type, negotiate } from '../../../utils/http.js';
|
|
5
|
-
import { HttpError, Redirect,
|
|
5
|
+
import { HttpError, Redirect, ActionFailure } from '../../control.js';
|
|
6
6
|
import { handle_error_and_jsonify } from '../utils.js';
|
|
7
7
|
|
|
8
8
|
/** @param {import('types').RequestEvent} event */
|
|
@@ -50,9 +50,9 @@ export async function handle_action_json_request(event, options, server) {
|
|
|
50
50
|
try {
|
|
51
51
|
const data = await call_action(event, actions);
|
|
52
52
|
|
|
53
|
-
if (data instanceof
|
|
53
|
+
if (data instanceof ActionFailure) {
|
|
54
54
|
return action_json({
|
|
55
|
-
type: '
|
|
55
|
+
type: 'failure',
|
|
56
56
|
status: data.status,
|
|
57
57
|
// @ts-expect-error we assign a string to what is supposed to be an object. That's ok
|
|
58
58
|
// because we don't use the object outside, and this way we have better code navigation
|
|
@@ -81,7 +81,7 @@ export async function handle_action_json_request(event, options, server) {
|
|
|
81
81
|
return action_json(
|
|
82
82
|
{
|
|
83
83
|
type: 'error',
|
|
84
|
-
error: await handle_error_and_jsonify(event, options,
|
|
84
|
+
error: await handle_error_and_jsonify(event, options, check_incorrect_fail_use(error))
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
status: error instanceof HttpError ? error.status : 500
|
|
@@ -93,9 +93,9 @@ export async function handle_action_json_request(event, options, server) {
|
|
|
93
93
|
/**
|
|
94
94
|
* @param {HttpError | Error} error
|
|
95
95
|
*/
|
|
96
|
-
function
|
|
97
|
-
return error instanceof
|
|
98
|
-
? new Error(`Cannot "throw
|
|
96
|
+
function check_incorrect_fail_use(error) {
|
|
97
|
+
return error instanceof ActionFailure
|
|
98
|
+
? new Error(`Cannot "throw fail()". Use "return fail()"`)
|
|
99
99
|
: error;
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -142,8 +142,8 @@ export async function handle_action_request(event, server) {
|
|
|
142
142
|
try {
|
|
143
143
|
const data = await call_action(event, actions);
|
|
144
144
|
|
|
145
|
-
if (data instanceof
|
|
146
|
-
return { type: '
|
|
145
|
+
if (data instanceof ActionFailure) {
|
|
146
|
+
return { type: 'failure', status: data.status, data: data.data };
|
|
147
147
|
} else {
|
|
148
148
|
return {
|
|
149
149
|
type: 'success',
|
|
@@ -164,7 +164,7 @@ export async function handle_action_request(event, server) {
|
|
|
164
164
|
|
|
165
165
|
return {
|
|
166
166
|
type: 'error',
|
|
167
|
-
error:
|
|
167
|
+
error: check_incorrect_fail_use(error)
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
170
|
}
|
|
@@ -183,7 +183,7 @@ function check_named_default_separate(actions) {
|
|
|
183
183
|
/**
|
|
184
184
|
* @param {import('types').RequestEvent} event
|
|
185
185
|
* @param {NonNullable<import('types').SSRNode['server']['actions']>} actions
|
|
186
|
-
* @throws {Redirect |
|
|
186
|
+
* @throws {Redirect | ActionFailure | HttpError | Error}
|
|
187
187
|
*/
|
|
188
188
|
export async function call_action(event, actions) {
|
|
189
189
|
const url = new URL(event.request.url);
|
|
@@ -68,7 +68,7 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
68
68
|
const error = action_result.error;
|
|
69
69
|
status = error instanceof HttpError ? error.status : 500;
|
|
70
70
|
}
|
|
71
|
-
if (action_result?.type === '
|
|
71
|
+
if (action_result?.type === 'failure') {
|
|
72
72
|
status = action_result.status;
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -67,7 +67,7 @@ export async function render_response({
|
|
|
67
67
|
let rendered;
|
|
68
68
|
|
|
69
69
|
const form_value =
|
|
70
|
-
action_result?.type === 'success' || action_result?.type === '
|
|
70
|
+
action_result?.type === 'success' || action_result?.type === 'failure'
|
|
71
71
|
? action_result.data ?? null
|
|
72
72
|
: null;
|
|
73
73
|
|
|
@@ -266,24 +266,41 @@ export async function render_response({
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
if (page_config.csr) {
|
|
269
|
+
const opts = [
|
|
270
|
+
`env: ${s(options.public_env)}`,
|
|
271
|
+
`paths: ${s(options.paths)}`,
|
|
272
|
+
`target: document.querySelector('[data-sveltekit-hydrate="${target}"]').parentNode`,
|
|
273
|
+
`version: ${s(options.version)}`
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
if (page_config.ssr) {
|
|
277
|
+
const hydrate = [
|
|
278
|
+
`node_ids: [${branch.map(({ node }) => node.index).join(', ')}]`,
|
|
279
|
+
`data: ${serialized.data}`,
|
|
280
|
+
`form: ${serialized.form}`
|
|
281
|
+
];
|
|
282
|
+
|
|
283
|
+
if (status !== 200) {
|
|
284
|
+
hydrate.push(`status: ${status}`);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (error) {
|
|
288
|
+
hydrate.push(`error: ${devalue.uneval(error)}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (options.embedded) {
|
|
292
|
+
hydrate.push(`params: ${devalue.uneval(event.params)}`, `route: ${s(event.route)}`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
opts.push(`hydrate: {\n\t\t\t\t\t${hydrate.join(',\n\t\t\t\t\t')}\n\t\t\t\t}`);
|
|
296
|
+
}
|
|
297
|
+
|
|
269
298
|
// prettier-ignore
|
|
270
299
|
const init_app = `
|
|
271
300
|
import { start } from ${s(prefixed(entry.file))};
|
|
272
301
|
|
|
273
302
|
start({
|
|
274
|
-
|
|
275
|
-
hydrate: ${page_config.ssr ? `{
|
|
276
|
-
status: ${status},
|
|
277
|
-
error: ${devalue.uneval(error)},
|
|
278
|
-
node_ids: [${branch.map(({ node }) => node.index).join(', ')}],
|
|
279
|
-
params: ${devalue.uneval(event.params)},
|
|
280
|
-
route: ${s(event.route)},
|
|
281
|
-
data: ${serialized.data},
|
|
282
|
-
form: ${serialized.form}
|
|
283
|
-
}` : 'null'},
|
|
284
|
-
paths: ${s(options.paths)},
|
|
285
|
-
target: document.querySelector('[data-sveltekit-hydrate="${target}"]').parentNode,
|
|
286
|
-
version: ${s(options.version)}
|
|
303
|
+
${opts.join(',\n\t\t\t\t')}
|
|
287
304
|
});
|
|
288
305
|
`;
|
|
289
306
|
|
package/types/index.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ type OptionalUnion<
|
|
|
61
61
|
A extends keyof U = U extends U ? keyof U : never
|
|
62
62
|
> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;
|
|
63
63
|
|
|
64
|
-
type UnpackValidationError<T> = T extends
|
|
64
|
+
type UnpackValidationError<T> = T extends ActionFailure<infer X>
|
|
65
65
|
? X
|
|
66
66
|
: T extends void
|
|
67
67
|
? undefined // needs to be undefined, because void will corrupt union type
|
|
@@ -90,6 +90,11 @@ export interface Builder {
|
|
|
90
90
|
*/
|
|
91
91
|
createEntries(fn: (route: RouteDefinition) => AdapterEntry): Promise<void>;
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Generate a fallback page for a static webserver to use when no route is matched. Useful for single-page apps.
|
|
95
|
+
*/
|
|
96
|
+
generateFallback(dest: string): Promise<void>;
|
|
97
|
+
|
|
93
98
|
/**
|
|
94
99
|
* Generate a server-side manifest to initialise the SvelteKit [server](https://kit.svelte.dev/docs/types#public-types-server) with.
|
|
95
100
|
* @param opts a relative path to the base directory of the app and optionally in which format (esm or cjs) the manifest should be generated
|
|
@@ -117,15 +122,9 @@ export interface Builder {
|
|
|
117
122
|
/**
|
|
118
123
|
* Write prerendered files to `dest`.
|
|
119
124
|
* @param dest the destination folder
|
|
120
|
-
* @param opts.fallback the name of a file for fallback responses, like `200.html` or `404.html` depending on where the app is deployed
|
|
121
125
|
* @returns an array of files written to `dest`
|
|
122
126
|
*/
|
|
123
|
-
writePrerendered(
|
|
124
|
-
dest: string,
|
|
125
|
-
opts?: {
|
|
126
|
-
fallback?: string;
|
|
127
|
-
}
|
|
128
|
-
): string[];
|
|
127
|
+
writePrerendered(dest: string): string[];
|
|
129
128
|
/**
|
|
130
129
|
* Write server-side code to `dest`.
|
|
131
130
|
* @param dest the destination folder
|
|
@@ -325,6 +324,11 @@ export interface KitConfig {
|
|
|
325
324
|
*/
|
|
326
325
|
checkOrigin?: boolean;
|
|
327
326
|
};
|
|
327
|
+
/**
|
|
328
|
+
* Whether or not the app is embedded inside a larger app. If `true`, SvelteKit will add its event listeners related to navigation etc on the parent of `%sveltekit.body%` instead of `window`, and will pass `params` from the server rather than inferring them from `location.pathname`.
|
|
329
|
+
* @default false
|
|
330
|
+
*/
|
|
331
|
+
embedded?: boolean;
|
|
328
332
|
/**
|
|
329
333
|
* Environment variable configuration
|
|
330
334
|
*/
|
|
@@ -1069,7 +1073,7 @@ export type ActionResult<
|
|
|
1069
1073
|
Invalid extends Record<string, unknown> | undefined = Record<string, any>
|
|
1070
1074
|
> =
|
|
1071
1075
|
| { type: 'success'; status: number; data?: Success }
|
|
1072
|
-
| { type: '
|
|
1076
|
+
| { type: 'failure'; status: number; data?: Invalid }
|
|
1073
1077
|
| { type: 'redirect'; status: number; location: string }
|
|
1074
1078
|
| { type: 'error'; error: any };
|
|
1075
1079
|
|
|
@@ -1124,17 +1128,17 @@ export interface Redirect {
|
|
|
1124
1128
|
export function json(data: any, init?: ResponseInit): Response;
|
|
1125
1129
|
|
|
1126
1130
|
/**
|
|
1127
|
-
* Create
|
|
1131
|
+
* Create an `ActionFailure` object.
|
|
1128
1132
|
*/
|
|
1129
|
-
export function
|
|
1133
|
+
export function fail<T extends Record<string, unknown> | undefined>(
|
|
1130
1134
|
status: number,
|
|
1131
1135
|
data?: T
|
|
1132
|
-
):
|
|
1136
|
+
): ActionFailure<T>;
|
|
1133
1137
|
|
|
1134
1138
|
/**
|
|
1135
|
-
* The object returned by the [`
|
|
1139
|
+
* The object returned by the [`fail`](https://kit.svelte.dev/docs/modules#sveltejs-kit-fail) function
|
|
1136
1140
|
*/
|
|
1137
|
-
export interface
|
|
1141
|
+
export interface ActionFailure<T extends Record<string, unknown> | undefined = undefined>
|
|
1138
1142
|
extends UniqueInterface {
|
|
1139
1143
|
status: number;
|
|
1140
1144
|
data: T;
|
package/types/internal.d.ts
CHANGED
|
@@ -299,6 +299,7 @@ export interface SSROptions {
|
|
|
299
299
|
check_origin: boolean;
|
|
300
300
|
};
|
|
301
301
|
dev: boolean;
|
|
302
|
+
embedded: boolean;
|
|
302
303
|
handle_error(error: Error & { frame?: string }, event: RequestEvent): MaybePromise<App.Error>;
|
|
303
304
|
hooks: ServerHooks;
|
|
304
305
|
manifest: SSRManifest;
|
|
@@ -387,4 +388,5 @@ declare global {
|
|
|
387
388
|
const __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: number;
|
|
388
389
|
const __SVELTEKIT_BROWSER__: boolean;
|
|
389
390
|
const __SVELTEKIT_DEV__: boolean;
|
|
391
|
+
const __SVELTEKIT_EMBEDDED__: boolean;
|
|
390
392
|
}
|