@sveltejs/kit 2.3.4 → 2.4.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/adapt/builder.js +20 -1
- package/src/core/generate_manifest/find_server_assets.js +52 -0
- package/src/core/generate_manifest/index.js +22 -4
- package/src/core/postbuild/analyse.js +68 -17
- package/src/core/postbuild/prerender.js +5 -1
- package/src/core/sync/create_manifest_data/index.js +19 -1
- package/src/core/sync/write_server.js +2 -1
- package/src/exports/node/index.js +12 -0
- package/src/exports/public.d.ts +21 -0
- package/src/exports/vite/build/utils.js +7 -5
- package/src/exports/vite/dev/index.js +27 -3
- package/src/exports/vite/graph_analysis/index.js +6 -2
- package/src/exports/vite/index.js +43 -2
- package/src/exports/vite/module_ids.js +10 -1
- package/src/exports/vite/preview/index.js +3 -2
- package/src/runtime/app/server/index.js +58 -0
- package/src/runtime/server/index.js +10 -2
- package/src/runtime/server/page/index.js +2 -5
- package/src/runtime/server/page/load_page_nodes.js +11 -0
- package/src/runtime/server/respond.js +22 -5
- package/src/types/ambient-private.d.ts +10 -0
- package/src/types/global-private.d.ts +15 -0
- package/src/types/internal.d.ts +15 -1
- package/src/utils/features.js +24 -0
- package/src/utils/route_config.js +20 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +48 -0
- package/types/index.d.ts.map +5 -1
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import colors from 'kleur';
|
|
2
|
+
import { createReadStream, createWriteStream, existsSync, statSync } from 'node:fs';
|
|
2
3
|
import { extname, resolve } from 'node:path';
|
|
3
4
|
import { pipeline } from 'node:stream';
|
|
4
5
|
import { promisify } from 'node:util';
|
|
@@ -10,6 +11,7 @@ import { get_env } from '../../exports/vite/utils.js';
|
|
|
10
11
|
import generate_fallback from '../postbuild/fallback.js';
|
|
11
12
|
import { write } from '../sync/utils.js';
|
|
12
13
|
import { list_files } from '../utils.js';
|
|
14
|
+
import { find_server_assets } from '../generate_manifest/find_server_assets.js';
|
|
13
15
|
|
|
14
16
|
const pipe = promisify(pipeline);
|
|
15
17
|
const extensions = ['.html', '.js', '.mjs', '.json', '.css', '.svg', '.xml', '.wasm'];
|
|
@@ -144,6 +146,13 @@ export function create_builder({
|
|
|
144
146
|
}
|
|
145
147
|
},
|
|
146
148
|
|
|
149
|
+
findServerAssets(route_data) {
|
|
150
|
+
return find_server_assets(
|
|
151
|
+
build_data,
|
|
152
|
+
route_data.map((route) => /** @type {import('types').RouteData} */ (lookup.get(route)))
|
|
153
|
+
);
|
|
154
|
+
},
|
|
155
|
+
|
|
147
156
|
async generateFallback(dest) {
|
|
148
157
|
const manifest_path = `${config.kit.outDir}/output/server/manifest-full.js`;
|
|
149
158
|
const env = get_env(config.kit.env, vite_config.mode);
|
|
@@ -153,6 +162,16 @@ export function create_builder({
|
|
|
153
162
|
env: { ...env.private, ...env.public }
|
|
154
163
|
});
|
|
155
164
|
|
|
165
|
+
if (existsSync(dest)) {
|
|
166
|
+
console.log(
|
|
167
|
+
colors
|
|
168
|
+
.bold()
|
|
169
|
+
.yellow(
|
|
170
|
+
`Overwriting ${dest} with fallback page. Consider using a different name for the fallback.`
|
|
171
|
+
)
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
156
175
|
write(dest, fallback);
|
|
157
176
|
},
|
|
158
177
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { find_deps } from '../../exports/vite/build/utils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Finds all the assets that are imported by server files associated with `routes`
|
|
5
|
+
* @param {import('types').BuildData} build_data
|
|
6
|
+
* @param {import('types').RouteData[]} routes
|
|
7
|
+
*/
|
|
8
|
+
export function find_server_assets(build_data, routes) {
|
|
9
|
+
/**
|
|
10
|
+
* All nodes actually used in the routes definition (prerendered routes are omitted).
|
|
11
|
+
* Root layout/error is always included as they are needed for 404 and root errors.
|
|
12
|
+
* @type {Set<any>}
|
|
13
|
+
*/
|
|
14
|
+
const used_nodes = new Set([0, 1]);
|
|
15
|
+
|
|
16
|
+
// TODO add hooks.server.js asset imports
|
|
17
|
+
/** @type {Set<string>} */
|
|
18
|
+
const server_assets = new Set();
|
|
19
|
+
|
|
20
|
+
/** @param {string} id */
|
|
21
|
+
function add_assets(id) {
|
|
22
|
+
if (id in build_data.server_manifest) {
|
|
23
|
+
const deps = find_deps(build_data.server_manifest, id, false);
|
|
24
|
+
for (const asset of deps.assets) {
|
|
25
|
+
server_assets.add(asset);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const route of routes) {
|
|
31
|
+
if (route.page) {
|
|
32
|
+
for (const i of route.page.layouts) used_nodes.add(i);
|
|
33
|
+
for (const i of route.page.errors) used_nodes.add(i);
|
|
34
|
+
used_nodes.add(route.page.leaf);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (route.endpoint) {
|
|
38
|
+
add_assets(route.endpoint.file);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const n of used_nodes) {
|
|
43
|
+
const node = build_data.manifest_data.nodes[n];
|
|
44
|
+
if (node?.server) add_assets(node.server);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (build_data.manifest_data.hooks.server) {
|
|
48
|
+
add_assets(build_data.manifest_data.hooks.server);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return Array.from(server_assets);
|
|
52
|
+
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import * as mime from 'mrmime';
|
|
1
4
|
import { s } from '../../utils/misc.js';
|
|
2
5
|
import { get_mime_lookup } from '../utils.js';
|
|
3
6
|
import { resolve_symlinks } from '../../exports/vite/build/utils.js';
|
|
4
7
|
import { compact } from '../../utils/array.js';
|
|
5
8
|
import { join_relative } from '../../utils/filesystem.js';
|
|
6
9
|
import { dedent } from '../sync/utils.js';
|
|
10
|
+
import { find_server_assets } from './find_server_assets.js';
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* Generates the data used to write the server-side manifest.js file. This data is used in the Vite
|
|
@@ -26,6 +30,8 @@ export function generate_manifest({ build_data, relative_path, routes }) {
|
|
|
26
30
|
*/
|
|
27
31
|
const used_nodes = new Set([0, 1]);
|
|
28
32
|
|
|
33
|
+
const server_assets = find_server_assets(build_data, routes);
|
|
34
|
+
|
|
29
35
|
for (const route of routes) {
|
|
30
36
|
if (route.page) {
|
|
31
37
|
for (const i of route.page.layouts) used_nodes.add(i);
|
|
@@ -63,6 +69,17 @@ export function generate_manifest({ build_data, relative_path, routes }) {
|
|
|
63
69
|
return `[${string},]`;
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
const mime_types = get_mime_lookup(build_data.manifest_data);
|
|
73
|
+
|
|
74
|
+
/** @type {Record<string, number>} */
|
|
75
|
+
const files = {};
|
|
76
|
+
for (const file of server_assets) {
|
|
77
|
+
files[file] = fs.statSync(path.resolve(build_data.out_dir, 'server', file)).size;
|
|
78
|
+
|
|
79
|
+
const ext = path.extname(file);
|
|
80
|
+
mime_types[ext] ??= mime.lookup(ext) || '';
|
|
81
|
+
}
|
|
82
|
+
|
|
66
83
|
// prettier-ignore
|
|
67
84
|
// String representation of
|
|
68
85
|
/** @template {import('@sveltejs/kit').SSRManifest} T */
|
|
@@ -71,7 +88,7 @@ export function generate_manifest({ build_data, relative_path, routes }) {
|
|
|
71
88
|
appDir: ${s(build_data.app_dir)},
|
|
72
89
|
appPath: ${s(build_data.app_path)},
|
|
73
90
|
assets: new Set(${s(assets)}),
|
|
74
|
-
mimeTypes: ${s(
|
|
91
|
+
mimeTypes: ${s(mime_types)},
|
|
75
92
|
_: {
|
|
76
93
|
client: ${s(build_data.client)},
|
|
77
94
|
nodes: [
|
|
@@ -80,7 +97,7 @@ export function generate_manifest({ build_data, relative_path, routes }) {
|
|
|
80
97
|
routes: [
|
|
81
98
|
${routes.map(route => {
|
|
82
99
|
if (!route.page && !route.endpoint) return;
|
|
83
|
-
|
|
100
|
+
|
|
84
101
|
route.params.forEach(param => {
|
|
85
102
|
if (param.matcher) matchers.add(param.matcher);
|
|
86
103
|
});
|
|
@@ -98,11 +115,12 @@ export function generate_manifest({ build_data, relative_path, routes }) {
|
|
|
98
115
|
],
|
|
99
116
|
matchers: async () => {
|
|
100
117
|
${Array.from(
|
|
101
|
-
matchers,
|
|
118
|
+
matchers,
|
|
102
119
|
type => `const { match: ${type} } = await import ('${(join_relative(relative_path, `/entries/matchers/${type}.js`))}')`
|
|
103
120
|
).join('\n')}
|
|
104
121
|
return { ${Array.from(matchers).join(', ')} };
|
|
105
|
-
}
|
|
122
|
+
},
|
|
123
|
+
server_assets: ${s(files)}
|
|
106
124
|
}
|
|
107
125
|
}
|
|
108
126
|
`;
|
|
@@ -14,16 +14,22 @@ import { installPolyfills } from '../../exports/node/polyfills.js';
|
|
|
14
14
|
import { ENDPOINT_METHODS } from '../../constants.js';
|
|
15
15
|
import { filter_private_env, filter_public_env } from '../../utils/env.js';
|
|
16
16
|
import { resolve_route } from '../../utils/routing.js';
|
|
17
|
+
import { get_page_config } from '../../utils/route_config.js';
|
|
18
|
+
import { check_feature } from '../../utils/features.js';
|
|
19
|
+
import { createReadableStream } from '@sveltejs/kit/node';
|
|
17
20
|
|
|
18
21
|
export default forked(import.meta.url, analyse);
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* @param {{
|
|
22
25
|
* manifest_path: string;
|
|
26
|
+
* manifest_data: import('types').ManifestData;
|
|
27
|
+
* server_manifest: import('vite').Manifest;
|
|
28
|
+
* tracked_features: Record<string, string[]>;
|
|
23
29
|
* env: Record<string, string>
|
|
24
30
|
* }} opts
|
|
25
31
|
*/
|
|
26
|
-
async function analyse({ manifest_path, env }) {
|
|
32
|
+
async function analyse({ manifest_path, manifest_data, server_manifest, tracked_features, env }) {
|
|
27
33
|
/** @type {import('@sveltejs/kit').SSRManifest} */
|
|
28
34
|
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
|
|
29
35
|
|
|
@@ -48,6 +54,8 @@ async function analyse({ manifest_path, env }) {
|
|
|
48
54
|
internal.set_private_env(private_env);
|
|
49
55
|
internal.set_public_env(public_env);
|
|
50
56
|
internal.set_safe_public_env(public_env);
|
|
57
|
+
internal.set_manifest(manifest);
|
|
58
|
+
internal.set_read_implementation((file) => createReadableStream(`${server_root}/server/${file}`));
|
|
51
59
|
|
|
52
60
|
/** @type {import('types').ServerMetadata} */
|
|
53
61
|
const metadata = {
|
|
@@ -89,12 +97,26 @@ async function analyse({ manifest_path, env }) {
|
|
|
89
97
|
}
|
|
90
98
|
}
|
|
91
99
|
|
|
100
|
+
const route_config = page?.config ?? endpoint?.config;
|
|
101
|
+
const prerender = page?.prerender ?? endpoint?.prerender;
|
|
102
|
+
|
|
103
|
+
if (prerender !== true) {
|
|
104
|
+
for (const feature of list_features(
|
|
105
|
+
route,
|
|
106
|
+
manifest_data,
|
|
107
|
+
server_manifest,
|
|
108
|
+
tracked_features
|
|
109
|
+
)) {
|
|
110
|
+
check_feature(route.id, route_config, feature, config.adapter);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
92
114
|
const page_methods = page?.methods ?? [];
|
|
93
115
|
const api_methods = endpoint?.methods ?? [];
|
|
94
116
|
const entries = page?.entries ?? endpoint?.entries;
|
|
95
117
|
|
|
96
118
|
metadata.routes.set(route.id, {
|
|
97
|
-
config:
|
|
119
|
+
config: route_config,
|
|
98
120
|
methods: Array.from(new Set([...page_methods, ...api_methods])),
|
|
99
121
|
page: {
|
|
100
122
|
methods: page_methods
|
|
@@ -102,7 +124,7 @@ async function analyse({ manifest_path, env }) {
|
|
|
102
124
|
api: {
|
|
103
125
|
methods: api_methods
|
|
104
126
|
},
|
|
105
|
-
prerender
|
|
127
|
+
prerender,
|
|
106
128
|
entries:
|
|
107
129
|
entries && (await entries()).map((entry_object) => resolve_route(route.id, entry_object))
|
|
108
130
|
});
|
|
@@ -163,7 +185,7 @@ function analyse_page(layouts, leaf) {
|
|
|
163
185
|
validate_page_exports(leaf.universal, leaf.universal_id);
|
|
164
186
|
|
|
165
187
|
return {
|
|
166
|
-
config:
|
|
188
|
+
config: get_page_config([...layouts, leaf]),
|
|
167
189
|
entries: leaf.universal?.entries ?? leaf.server?.entries,
|
|
168
190
|
methods,
|
|
169
191
|
prerender: get_option([...layouts, leaf], 'prerender') ?? false
|
|
@@ -171,22 +193,51 @@ function analyse_page(layouts, leaf) {
|
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
/**
|
|
174
|
-
*
|
|
175
|
-
* @param {
|
|
196
|
+
* @param {import('types').SSRRoute} route
|
|
197
|
+
* @param {import('types').ManifestData} manifest_data
|
|
198
|
+
* @param {import('vite').Manifest} server_manifest
|
|
199
|
+
* @param {Record<string, string[]>} tracked_features
|
|
176
200
|
*/
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
let current = {};
|
|
201
|
+
function list_features(route, manifest_data, server_manifest, tracked_features) {
|
|
202
|
+
const features = new Set();
|
|
180
203
|
|
|
181
|
-
|
|
182
|
-
|
|
204
|
+
const route_data = /** @type {import('types').RouteData} */ (
|
|
205
|
+
manifest_data.routes.find((r) => r.id === route.id)
|
|
206
|
+
);
|
|
183
207
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
208
|
+
/** @param {string} id */
|
|
209
|
+
function visit(id) {
|
|
210
|
+
const chunk = server_manifest[id];
|
|
211
|
+
if (!chunk) return;
|
|
212
|
+
|
|
213
|
+
if (chunk.file in tracked_features) {
|
|
214
|
+
for (const feature of tracked_features[chunk.file]) {
|
|
215
|
+
features.add(feature);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (chunk.imports) {
|
|
220
|
+
for (const id of chunk.imports) {
|
|
221
|
+
visit(id);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let page_node = route_data?.leaf;
|
|
227
|
+
while (page_node) {
|
|
228
|
+
if (page_node.server) visit(page_node.server);
|
|
229
|
+
page_node = page_node.parent ?? null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (route_data.endpoint) {
|
|
233
|
+
visit(route_data.endpoint.file);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (manifest_data.hooks.server) {
|
|
237
|
+
// TODO if hooks.server.js imports `read`, it will be in the entry chunk
|
|
238
|
+
// we don't currently account for that case
|
|
239
|
+
visit(manifest_data.hooks.server);
|
|
189
240
|
}
|
|
190
241
|
|
|
191
|
-
return
|
|
242
|
+
return Array.from(features);
|
|
192
243
|
}
|
|
@@ -12,6 +12,7 @@ import { queue } from './queue.js';
|
|
|
12
12
|
import { crawl } from './crawl.js';
|
|
13
13
|
import { forked } from '../../utils/fork.js';
|
|
14
14
|
import * as devalue from 'devalue';
|
|
15
|
+
import { createReadableStream } from '@sveltejs/kit/node';
|
|
15
16
|
|
|
16
17
|
export default forked(import.meta.url, prerender);
|
|
17
18
|
|
|
@@ -430,7 +431,10 @@ async function prerender({ out, manifest_path, metadata, verbose, env }) {
|
|
|
430
431
|
log.info('Prerendering');
|
|
431
432
|
|
|
432
433
|
const server = new Server(manifest);
|
|
433
|
-
await server.init({
|
|
434
|
+
await server.init({
|
|
435
|
+
env,
|
|
436
|
+
read: (file) => createReadableStream(`${config.outDir}/output/server/${file}`)
|
|
437
|
+
});
|
|
434
438
|
|
|
435
439
|
for (const entry of config.prerender.entries) {
|
|
436
440
|
if (entry === '*') {
|
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import colors from 'kleur';
|
|
4
4
|
import { lookup } from 'mrmime';
|
|
5
5
|
import { list_files, runtime_directory } from '../../utils.js';
|
|
6
|
-
import { posixify } from '../../../utils/filesystem.js';
|
|
6
|
+
import { posixify, resolve_entry } from '../../../utils/filesystem.js';
|
|
7
7
|
import { parse_route_id } from '../../../utils/routing.js';
|
|
8
8
|
import { sort_routes } from './sort.js';
|
|
9
9
|
|
|
@@ -22,6 +22,7 @@ export default function create_manifest_data({
|
|
|
22
22
|
cwd = process.cwd()
|
|
23
23
|
}) {
|
|
24
24
|
const assets = create_assets(config);
|
|
25
|
+
const hooks = create_hooks(config, cwd);
|
|
25
26
|
const matchers = create_matchers(config, cwd);
|
|
26
27
|
const { nodes, routes } = create_routes_and_nodes(cwd, config, fallback);
|
|
27
28
|
|
|
@@ -35,6 +36,7 @@ export default function create_manifest_data({
|
|
|
35
36
|
|
|
36
37
|
return {
|
|
37
38
|
assets,
|
|
39
|
+
hooks,
|
|
38
40
|
matchers,
|
|
39
41
|
nodes,
|
|
40
42
|
routes
|
|
@@ -52,6 +54,22 @@ export function create_assets(config) {
|
|
|
52
54
|
}));
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @param {import('types').ValidatedConfig} config
|
|
59
|
+
* @param {string} cwd
|
|
60
|
+
*/
|
|
61
|
+
function create_hooks(config, cwd) {
|
|
62
|
+
const client = resolve_entry(config.kit.files.hooks.client);
|
|
63
|
+
const server = resolve_entry(config.kit.files.hooks.server);
|
|
64
|
+
const universal = resolve_entry(config.kit.files.hooks.universal);
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
client: client && posixify(path.relative(cwd, client)),
|
|
68
|
+
server: server && posixify(path.relative(cwd, server)),
|
|
69
|
+
universal: universal && posixify(path.relative(cwd, universal))
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
55
73
|
/**
|
|
56
74
|
* @param {import('types').ValidatedConfig} config
|
|
57
75
|
* @param {string} cwd
|
|
@@ -30,6 +30,7 @@ const server_template = ({
|
|
|
30
30
|
import root from '../root.${isSvelte5Plus() ? 'js' : 'svelte'}';
|
|
31
31
|
import { set_building, set_prerendering } from '__sveltekit/environment';
|
|
32
32
|
import { set_assets } from '__sveltekit/paths';
|
|
33
|
+
import { set_manifest, set_read_implementation } from '__sveltekit/server';
|
|
33
34
|
import { set_private_env, set_public_env, set_safe_public_env } from '${runtime_directory}/shared-server.js';
|
|
34
35
|
|
|
35
36
|
export const options = {
|
|
@@ -68,7 +69,7 @@ export async function get_hooks() {
|
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
export { set_assets, set_building, set_prerendering, set_private_env, set_public_env, set_safe_public_env };
|
|
72
|
+
export { set_assets, set_building, set_manifest, set_prerendering, set_private_env, set_public_env, set_read_implementation, set_safe_public_env };
|
|
72
73
|
`;
|
|
73
74
|
|
|
74
75
|
// TODO need to re-run this whenever src/app.html or src/error.html are
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { Readable } from 'node:stream';
|
|
1
3
|
import * as set_cookie_parser from 'set-cookie-parser';
|
|
2
4
|
import { SvelteKitError } from '../../runtime/control.js';
|
|
3
5
|
|
|
@@ -189,3 +191,13 @@ export async function setResponse(res, response) {
|
|
|
189
191
|
}
|
|
190
192
|
}
|
|
191
193
|
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Converts a file on disk to a readable stream
|
|
197
|
+
* @param {string} file
|
|
198
|
+
* @returns {ReadableStream}
|
|
199
|
+
* @since 2.4.0
|
|
200
|
+
*/
|
|
201
|
+
export function createReadableStream(file) {
|
|
202
|
+
return /** @type {ReadableStream} */ (Readable.toWeb(createReadStream(file)));
|
|
203
|
+
}
|
package/src/exports/public.d.ts
CHANGED
|
@@ -35,6 +35,16 @@ export interface Adapter {
|
|
|
35
35
|
* @param builder An object provided by SvelteKit that contains methods for adapting the app
|
|
36
36
|
*/
|
|
37
37
|
adapt(builder: Builder): MaybePromise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Checks called during dev and build to determine whether specific features will work in production with this adapter
|
|
40
|
+
*/
|
|
41
|
+
supports?: {
|
|
42
|
+
/**
|
|
43
|
+
* Test support for `read` from `$app/server`
|
|
44
|
+
* @param config The merged route config
|
|
45
|
+
*/
|
|
46
|
+
read?: (details: { config: any; route: { id: string } }) => boolean;
|
|
47
|
+
};
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
export type LoadProperties<input extends Record<string, any> | void> = input extends void
|
|
@@ -89,6 +99,7 @@ export interface Builder {
|
|
|
89
99
|
/** An array of all routes (including prerendered) */
|
|
90
100
|
routes: RouteDefinition[];
|
|
91
101
|
|
|
102
|
+
// TODO 3.0 remove this method
|
|
92
103
|
/**
|
|
93
104
|
* Create separate functions that map to one or more routes of your app.
|
|
94
105
|
* @param fn A function that groups a set of routes into an entry point
|
|
@@ -96,6 +107,11 @@ export interface Builder {
|
|
|
96
107
|
*/
|
|
97
108
|
createEntries(fn: (route: RouteDefinition) => AdapterEntry): Promise<void>;
|
|
98
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Find all the assets imported by server files belonging to `routes`
|
|
112
|
+
*/
|
|
113
|
+
findServerAssets(routes: RouteDefinition[]): string[];
|
|
114
|
+
|
|
99
115
|
/**
|
|
100
116
|
* Generate a fallback page for a static webserver to use when no route is matched. Useful for single-page apps.
|
|
101
117
|
*/
|
|
@@ -1144,7 +1160,10 @@ export class Server {
|
|
|
1144
1160
|
}
|
|
1145
1161
|
|
|
1146
1162
|
export interface ServerInitOptions {
|
|
1163
|
+
/** A map of environment variables */
|
|
1147
1164
|
env: Record<string, string>;
|
|
1165
|
+
/** A function that turns an asset filename into a `ReadableStream`. Required for the `read` export from `$app/server` to work */
|
|
1166
|
+
read?: (file: string) => ReadableStream;
|
|
1148
1167
|
}
|
|
1149
1168
|
|
|
1150
1169
|
export interface SSRManifest {
|
|
@@ -1159,6 +1178,8 @@ export interface SSRManifest {
|
|
|
1159
1178
|
nodes: SSRNodeLoader[];
|
|
1160
1179
|
routes: SSRRoute[];
|
|
1161
1180
|
matchers(): Promise<Record<string, ParamMatcher>>;
|
|
1181
|
+
/** A `[file]: size` map of all assets imported by server code */
|
|
1182
|
+
server_assets: Record<string, number>;
|
|
1162
1183
|
};
|
|
1163
1184
|
}
|
|
1164
1185
|
|
|
@@ -20,7 +20,7 @@ export function find_deps(manifest, entry, add_dynamic_css) {
|
|
|
20
20
|
const stylesheets = new Set();
|
|
21
21
|
|
|
22
22
|
/** @type {Set<string>} */
|
|
23
|
-
const
|
|
23
|
+
const imported_assets = new Set();
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* @param {string} current
|
|
@@ -36,9 +36,7 @@ export function find_deps(manifest, entry, add_dynamic_css) {
|
|
|
36
36
|
|
|
37
37
|
if (chunk.assets) {
|
|
38
38
|
for (const asset of chunk.assets) {
|
|
39
|
-
|
|
40
|
-
fonts.add(asset);
|
|
41
|
-
}
|
|
39
|
+
imported_assets.add(asset);
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
|
|
@@ -59,11 +57,15 @@ export function find_deps(manifest, entry, add_dynamic_css) {
|
|
|
59
57
|
|
|
60
58
|
traverse(file, true);
|
|
61
59
|
|
|
60
|
+
const assets = Array.from(imported_assets);
|
|
61
|
+
|
|
62
62
|
return {
|
|
63
|
+
assets,
|
|
63
64
|
file: chunk.file,
|
|
64
65
|
imports: Array.from(imports),
|
|
65
66
|
stylesheets: Array.from(stylesheets),
|
|
66
|
-
|
|
67
|
+
// TODO do we need this separately?
|
|
68
|
+
fonts: assets.filter((asset) => /\.(woff2?|ttf|otf)$/.test(asset))
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { URL } from 'node:url';
|
|
4
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
4
5
|
import colors from 'kleur';
|
|
5
6
|
import sirv from 'sirv';
|
|
6
7
|
import { isCSSRequest, loadEnv, buildErrorMessage } from 'vite';
|
|
7
|
-
import { getRequest, setResponse } from '../../../exports/node/index.js';
|
|
8
|
+
import { createReadableStream, getRequest, setResponse } from '../../../exports/node/index.js';
|
|
8
9
|
import { installPolyfills } from '../../../exports/node/polyfills.js';
|
|
9
10
|
import { coalesce_to_error } from '../../../utils/error.js';
|
|
10
11
|
import { posixify, resolve_entry, to_fs } from '../../../utils/filesystem.js';
|
|
@@ -15,6 +16,7 @@ import { get_mime_lookup, runtime_base } from '../../../core/utils.js';
|
|
|
15
16
|
import { compact } from '../../../utils/array.js';
|
|
16
17
|
import { not_found } from '../utils.js';
|
|
17
18
|
import { SCHEME } from '../../../utils/url.js';
|
|
19
|
+
import { check_feature } from '../../../utils/features.js';
|
|
18
20
|
|
|
19
21
|
const cwd = process.cwd();
|
|
20
22
|
|
|
@@ -27,6 +29,15 @@ const cwd = process.cwd();
|
|
|
27
29
|
export async function dev(vite, vite_config, svelte_config) {
|
|
28
30
|
installPolyfills();
|
|
29
31
|
|
|
32
|
+
const async_local_storage = new AsyncLocalStorage();
|
|
33
|
+
|
|
34
|
+
globalThis.__SVELTEKIT_TRACK__ = (label) => {
|
|
35
|
+
const context = async_local_storage.getStore();
|
|
36
|
+
if (!context || context.prerender === true) return;
|
|
37
|
+
|
|
38
|
+
check_feature(context.event.route.id, context.config, label, svelte_config.kit.adapter);
|
|
39
|
+
};
|
|
40
|
+
|
|
30
41
|
const fetch = globalThis.fetch;
|
|
31
42
|
globalThis.fetch = (info, init) => {
|
|
32
43
|
if (typeof info === 'string' && !SCHEME.test(info)) {
|
|
@@ -123,6 +134,13 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
123
134
|
fonts: [],
|
|
124
135
|
uses_env_dynamic_public: true
|
|
125
136
|
},
|
|
137
|
+
server_assets: new Proxy(
|
|
138
|
+
{},
|
|
139
|
+
{
|
|
140
|
+
has: (_, /** @type {string} */ file) => fs.existsSync(file.replace(/^\/@fs/, '')),
|
|
141
|
+
get: (_, /** @type {string} */ file) => fs.statSync(file.replace(/^\/@fs/, '')).size
|
|
142
|
+
}
|
|
143
|
+
),
|
|
126
144
|
nodes: manifest_data.nodes.map((node, index) => {
|
|
127
145
|
return async () => {
|
|
128
146
|
/** @type {import('types').SSRNode} */
|
|
@@ -470,7 +488,10 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
470
488
|
|
|
471
489
|
const server = new Server(manifest);
|
|
472
490
|
|
|
473
|
-
await server.init({
|
|
491
|
+
await server.init({
|
|
492
|
+
env,
|
|
493
|
+
read: (file) => createReadableStream(file.replace(/^\/@fs/, ''))
|
|
494
|
+
});
|
|
474
495
|
|
|
475
496
|
const request = await getRequest({
|
|
476
497
|
base,
|
|
@@ -505,7 +526,10 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
505
526
|
if (remoteAddress) return remoteAddress;
|
|
506
527
|
throw new Error('Could not determine clientAddress');
|
|
507
528
|
},
|
|
508
|
-
read: (file) => fs.readFileSync(path.join(svelte_config.kit.files.assets, file))
|
|
529
|
+
read: (file) => fs.readFileSync(path.join(svelte_config.kit.files.assets, file)),
|
|
530
|
+
before_handle: (event, config, prerender) => {
|
|
531
|
+
async_local_storage.enterWith({ event, config, prerender });
|
|
532
|
+
}
|
|
509
533
|
});
|
|
510
534
|
|
|
511
535
|
if (rendered.status === 404) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { posixify } from '../../../utils/filesystem.js';
|
|
3
3
|
import { strip_virtual_prefix } from '../utils.js';
|
|
4
|
-
import { env_dynamic_private, env_static_private } from '../module_ids.js';
|
|
4
|
+
import { app_server, env_dynamic_private, env_static_private } from '../module_ids.js';
|
|
5
5
|
|
|
6
|
-
const ILLEGAL_IMPORTS = new Set([env_dynamic_private, env_static_private]);
|
|
6
|
+
const ILLEGAL_IMPORTS = new Set([env_dynamic_private, env_static_private, app_server]);
|
|
7
7
|
const ILLEGAL_MODULE_NAME_PATTERN = /.*\.server\..+/;
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -101,5 +101,9 @@ export function normalize_id(id, lib, cwd) {
|
|
|
101
101
|
id = path.relative(cwd, id);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
if (id === app_server) {
|
|
105
|
+
return '$app/server';
|
|
106
|
+
}
|
|
107
|
+
|
|
104
108
|
return posixify(id);
|
|
105
109
|
}
|
|
@@ -31,7 +31,8 @@ import {
|
|
|
31
31
|
env_static_public,
|
|
32
32
|
service_worker,
|
|
33
33
|
sveltekit_environment,
|
|
34
|
-
sveltekit_paths
|
|
34
|
+
sveltekit_paths,
|
|
35
|
+
sveltekit_server
|
|
35
36
|
} from './module_ids.js';
|
|
36
37
|
import { pathToFileURL } from 'node:url';
|
|
37
38
|
|
|
@@ -224,6 +225,13 @@ async function kit({ svelte_config }) {
|
|
|
224
225
|
const service_worker_entry_file = resolve_entry(kit.files.serviceWorker);
|
|
225
226
|
const parsed_service_worker = path.parse(kit.files.serviceWorker);
|
|
226
227
|
|
|
228
|
+
/**
|
|
229
|
+
* A map showing which features (such as `$app/server:read`) are defined
|
|
230
|
+
* in which chunks, so that we can later determine which routes use which features
|
|
231
|
+
* @type {Record<string, string[]>}
|
|
232
|
+
*/
|
|
233
|
+
const tracked_features = {};
|
|
234
|
+
|
|
227
235
|
const sourcemapIgnoreList = /** @param {string} relative_path */ (relative_path) =>
|
|
228
236
|
relative_path.includes('node_modules') || relative_path.includes(kit.outDir);
|
|
229
237
|
|
|
@@ -492,13 +500,29 @@ async function kit({ svelte_config }) {
|
|
|
492
500
|
}
|
|
493
501
|
`;
|
|
494
502
|
}
|
|
503
|
+
|
|
504
|
+
case sveltekit_server: {
|
|
505
|
+
return dedent`
|
|
506
|
+
export let read_implementation = null;
|
|
507
|
+
|
|
508
|
+
export let manifest = null;
|
|
509
|
+
|
|
510
|
+
export function set_read_implementation(fn) {
|
|
511
|
+
read_implementation = fn;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export function set_manifest(_) {
|
|
515
|
+
manifest = _;
|
|
516
|
+
}
|
|
517
|
+
`;
|
|
518
|
+
}
|
|
495
519
|
}
|
|
496
520
|
}
|
|
497
521
|
};
|
|
498
522
|
|
|
499
523
|
/**
|
|
500
524
|
* Ensures that client-side code can't accidentally import server-side code,
|
|
501
|
-
* whether in `*.server.js` files, `$lib/server`, or `$env/[static|dynamic]/private`
|
|
525
|
+
* whether in `*.server.js` files, `$app/server`, `$lib/server`, or `$env/[static|dynamic]/private`
|
|
502
526
|
* @type {import('vite').Plugin}
|
|
503
527
|
*/
|
|
504
528
|
const plugin_guard = {
|
|
@@ -685,6 +709,19 @@ async function kit({ svelte_config }) {
|
|
|
685
709
|
}
|
|
686
710
|
},
|
|
687
711
|
|
|
712
|
+
renderChunk(code, chunk) {
|
|
713
|
+
if (code.includes('__SVELTEKIT_TRACK__')) {
|
|
714
|
+
return {
|
|
715
|
+
code: code.replace(/__SVELTEKIT_TRACK__\('(.+?)'\)/g, (_, label) => {
|
|
716
|
+
(tracked_features[chunk.name + '.js'] ??= []).push(label);
|
|
717
|
+
// put extra whitespace at the end of the comment to preserve the source size and avoid interfering with source maps
|
|
718
|
+
return `/* track ${label} */`;
|
|
719
|
+
}),
|
|
720
|
+
map: null // TODO we may need to generate a sourcemap in future
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
|
|
688
725
|
generateBundle() {
|
|
689
726
|
if (vite_config.build.ssr) return;
|
|
690
727
|
|
|
@@ -716,6 +753,7 @@ async function kit({ svelte_config }) {
|
|
|
716
753
|
app_dir: kit.appDir,
|
|
717
754
|
app_path: `${kit.paths.base.slice(1)}${kit.paths.base ? '/' : ''}${kit.appDir}`,
|
|
718
755
|
manifest_data,
|
|
756
|
+
out_dir: out,
|
|
719
757
|
service_worker: service_worker_entry_file ? 'service-worker.js' : null, // TODO make file configurable?
|
|
720
758
|
client: null,
|
|
721
759
|
server_manifest
|
|
@@ -738,6 +776,9 @@ async function kit({ svelte_config }) {
|
|
|
738
776
|
|
|
739
777
|
const metadata = await analyse({
|
|
740
778
|
manifest_path,
|
|
779
|
+
manifest_data,
|
|
780
|
+
server_manifest,
|
|
781
|
+
tracked_features,
|
|
741
782
|
env: { ...env.private, ...env.public }
|
|
742
783
|
});
|
|
743
784
|
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
|
|
1
3
|
export const env_static_private = '\0virtual:$env/static/private';
|
|
2
4
|
export const env_static_public = '\0virtual:$env/static/public';
|
|
3
5
|
export const env_dynamic_private = '\0virtual:$env/dynamic/private';
|
|
4
6
|
export const env_dynamic_public = '\0virtual:$env/dynamic/public';
|
|
7
|
+
|
|
5
8
|
export const service_worker = '\0virtual:$service-worker';
|
|
6
|
-
|
|
9
|
+
|
|
7
10
|
export const sveltekit_environment = '\0virtual:__sveltekit/environment';
|
|
11
|
+
export const sveltekit_paths = '\0virtual:__sveltekit/paths';
|
|
12
|
+
export const sveltekit_server = '\0virtual:__sveltekit/server';
|
|
13
|
+
|
|
14
|
+
export const app_server = fileURLToPath(
|
|
15
|
+
new URL('../../runtime/app/server/index.js', import.meta.url)
|
|
16
|
+
);
|
|
@@ -4,7 +4,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
4
4
|
import { lookup } from 'mrmime';
|
|
5
5
|
import sirv from 'sirv';
|
|
6
6
|
import { loadEnv, normalizePath } from 'vite';
|
|
7
|
-
import { getRequest, setResponse } from '../../../exports/node/index.js';
|
|
7
|
+
import { createReadableStream, getRequest, setResponse } from '../../../exports/node/index.js';
|
|
8
8
|
import { installPolyfills } from '../../../exports/node/polyfills.js';
|
|
9
9
|
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
10
10
|
import { not_found } from '../utils.js';
|
|
@@ -47,7 +47,8 @@ export async function preview(vite, vite_config, svelte_config) {
|
|
|
47
47
|
|
|
48
48
|
const server = new Server(manifest);
|
|
49
49
|
await server.init({
|
|
50
|
-
env: loadEnv(vite_config.mode, svelte_config.kit.env.dir, '')
|
|
50
|
+
env: loadEnv(vite_config.mode, svelte_config.kit.env.dir, ''),
|
|
51
|
+
read: (file) => createReadableStream(`${dir}/${file}`)
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
return () => {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { read_implementation, manifest } from '__sveltekit/server';
|
|
2
|
+
import { base } from '__sveltekit/paths';
|
|
3
|
+
import { DEV } from 'esm-env';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Read the contents of an imported asset from the filesystem
|
|
7
|
+
* @example
|
|
8
|
+
* ```js
|
|
9
|
+
* import { read } from '$app/server';
|
|
10
|
+
* import somefile from './somefile.txt';
|
|
11
|
+
*
|
|
12
|
+
* const asset = read(somefile);
|
|
13
|
+
* const text = await asset.text();
|
|
14
|
+
* ```
|
|
15
|
+
* @param {string} asset
|
|
16
|
+
* @returns {Response}
|
|
17
|
+
* @since 2.4.0
|
|
18
|
+
*/
|
|
19
|
+
export function read(asset) {
|
|
20
|
+
__SVELTEKIT_TRACK__('$app/server:read');
|
|
21
|
+
|
|
22
|
+
if (!read_implementation) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
'No `read` implementation was provided. Please ensure that your adapter is up to date and supports this feature'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// handle inline assets internally
|
|
29
|
+
if (asset.startsWith('data:')) {
|
|
30
|
+
const [prelude, data] = asset.split(';');
|
|
31
|
+
const type = prelude.slice(5) || 'application/octet-stream';
|
|
32
|
+
|
|
33
|
+
const decoded = data.startsWith('base64,') ? atob(data.slice(7)) : decodeURIComponent(data);
|
|
34
|
+
|
|
35
|
+
return new Response(decoded, {
|
|
36
|
+
headers: {
|
|
37
|
+
'Content-Length': decoded.length.toString(),
|
|
38
|
+
'Content-Type': type
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const file = DEV && asset.startsWith('/@fs') ? asset : asset.slice(base.length + 1);
|
|
44
|
+
|
|
45
|
+
if (file in manifest._.server_assets) {
|
|
46
|
+
const length = manifest._.server_assets[file];
|
|
47
|
+
const type = manifest.mimeTypes[file.slice(file.lastIndexOf('.'))];
|
|
48
|
+
|
|
49
|
+
return new Response(read_implementation(file), {
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Length': '' + length,
|
|
52
|
+
'Content-Type': type
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
throw new Error(`Asset does not exist: ${file}`);
|
|
58
|
+
}
|
|
@@ -4,6 +4,7 @@ import { options, get_hooks } from '__SERVER__/internal.js';
|
|
|
4
4
|
import { DEV } from 'esm-env';
|
|
5
5
|
import { filter_private_env, filter_public_env } from '../../utils/env.js';
|
|
6
6
|
import { prerendering } from '__sveltekit/environment';
|
|
7
|
+
import { set_read_implementation, set_manifest } from '__sveltekit/server';
|
|
7
8
|
|
|
8
9
|
/** @type {ProxyHandler<{ type: 'public' | 'private' }>} */
|
|
9
10
|
const prerender_env_handler = {
|
|
@@ -26,14 +27,17 @@ export class Server {
|
|
|
26
27
|
/** @type {import('types').SSROptions} */
|
|
27
28
|
this.#options = options;
|
|
28
29
|
this.#manifest = manifest;
|
|
30
|
+
|
|
31
|
+
set_manifest(manifest);
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
35
|
* @param {{
|
|
33
|
-
* env: Record<string, string
|
|
36
|
+
* env: Record<string, string>;
|
|
37
|
+
* read?: (file: string) => ReadableStream;
|
|
34
38
|
* }} opts
|
|
35
39
|
*/
|
|
36
|
-
async init({ env }) {
|
|
40
|
+
async init({ env, read }) {
|
|
37
41
|
// Take care: Some adapters may have to call `Server.init` per-request to set env vars,
|
|
38
42
|
// so anything that shouldn't be rerun should be wrapped in an `if` block to make sure it hasn't
|
|
39
43
|
// been done already.
|
|
@@ -55,6 +59,10 @@ export class Server {
|
|
|
55
59
|
);
|
|
56
60
|
set_safe_public_env(public_env);
|
|
57
61
|
|
|
62
|
+
if (read) {
|
|
63
|
+
set_read_implementation(read);
|
|
64
|
+
}
|
|
65
|
+
|
|
58
66
|
if (!this.#options.hooks) {
|
|
59
67
|
try {
|
|
60
68
|
const module = await get_hooks();
|
|
@@ -15,6 +15,7 @@ import { render_response } from './render.js';
|
|
|
15
15
|
import { respond_with_error } from './respond_with_error.js';
|
|
16
16
|
import { get_option } from '../../../utils/options.js';
|
|
17
17
|
import { get_data_json } from '../data/index.js';
|
|
18
|
+
import { load_page_nodes } from './load_page_nodes.js';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* The maximum request depth permitted before assuming we're stuck in an infinite loop
|
|
@@ -44,11 +45,7 @@ export async function render_page(event, page, options, manifest, state, resolve
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
try {
|
|
47
|
-
const nodes = await
|
|
48
|
-
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
49
|
-
...page.layouts.map((n) => (n == undefined ? n : manifest._.nodes[n]())),
|
|
50
|
-
manifest._.nodes[page.leaf]()
|
|
51
|
-
]);
|
|
48
|
+
const nodes = await load_page_nodes(page, manifest);
|
|
52
49
|
|
|
53
50
|
const leaf_node = /** @type {import('types').SSRNode} */ (nodes.at(-1));
|
|
54
51
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('types').PageNodeIndexes} page
|
|
3
|
+
* @param {import('@sveltejs/kit').SSRManifest} manifest
|
|
4
|
+
*/
|
|
5
|
+
export function load_page_nodes(page, manifest) {
|
|
6
|
+
return Promise.all([
|
|
7
|
+
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
8
|
+
...page.layouts.map((n) => (n == undefined ? n : manifest._.nodes[n]())),
|
|
9
|
+
manifest._.nodes[page.leaf]()
|
|
10
|
+
]);
|
|
11
|
+
}
|
|
@@ -31,6 +31,8 @@ import { json, text } from '../../exports/index.js';
|
|
|
31
31
|
import { action_json_redirect, is_action_json_request } from './page/actions.js';
|
|
32
32
|
import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js';
|
|
33
33
|
import { get_public_env } from './env_module.js';
|
|
34
|
+
import { load_page_nodes } from './page/load_page_nodes.js';
|
|
35
|
+
import { get_page_config } from '../../utils/route_config.js';
|
|
34
36
|
|
|
35
37
|
/* global __SVELTEKIT_ADAPTER_NAME__ */
|
|
36
38
|
|
|
@@ -217,11 +219,7 @@ export async function respond(request, options, manifest, state) {
|
|
|
217
219
|
if (url.pathname === base || url.pathname === base + '/') {
|
|
218
220
|
trailing_slash = 'always';
|
|
219
221
|
} else if (route.page) {
|
|
220
|
-
const nodes = await
|
|
221
|
-
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
222
|
-
...route.page.layouts.map((n) => (n == undefined ? n : manifest._.nodes[n]())),
|
|
223
|
-
manifest._.nodes[route.page.leaf]()
|
|
224
|
-
]);
|
|
222
|
+
const nodes = await load_page_nodes(route.page, manifest);
|
|
225
223
|
|
|
226
224
|
if (DEV) {
|
|
227
225
|
const layouts = nodes.slice(0, -1);
|
|
@@ -272,6 +270,25 @@ export async function respond(request, options, manifest, state) {
|
|
|
272
270
|
});
|
|
273
271
|
}
|
|
274
272
|
}
|
|
273
|
+
|
|
274
|
+
if (DEV && state.before_handle) {
|
|
275
|
+
let config = {};
|
|
276
|
+
|
|
277
|
+
/** @type {import('types').PrerenderOption} */
|
|
278
|
+
let prerender = false;
|
|
279
|
+
|
|
280
|
+
if (route.endpoint) {
|
|
281
|
+
const node = await route.endpoint();
|
|
282
|
+
config = node.config ?? config;
|
|
283
|
+
prerender = node.prerender ?? prerender;
|
|
284
|
+
} else if (route.page) {
|
|
285
|
+
const nodes = await load_page_nodes(route.page, manifest);
|
|
286
|
+
config = get_page_config(nodes);
|
|
287
|
+
prerender = get_option(nodes, 'prerender') ?? false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
state.before_handle(event, config, prerender);
|
|
291
|
+
}
|
|
275
292
|
}
|
|
276
293
|
|
|
277
294
|
const { cookies, new_cookies, get_cookie_header, set_internal } = get_cookies(
|
|
@@ -16,3 +16,13 @@ declare module '__sveltekit/paths' {
|
|
|
16
16
|
export function override(paths: { base: string; assets: string }): void;
|
|
17
17
|
export function set_assets(path: string): void;
|
|
18
18
|
}
|
|
19
|
+
|
|
20
|
+
/** Internal version of $app/server */
|
|
21
|
+
declare module '__sveltekit/server' {
|
|
22
|
+
import { SSRManifest } from '@sveltejs/kit';
|
|
23
|
+
|
|
24
|
+
export let manifest: SSRManifest;
|
|
25
|
+
export function read_implementation(path: string): ReadableStream;
|
|
26
|
+
export function set_manifest(manifest: SSRManifest): void;
|
|
27
|
+
export function set_read_implementation(fn: (path: string) => ReadableStream): void;
|
|
28
|
+
}
|
|
@@ -4,6 +4,21 @@ declare global {
|
|
|
4
4
|
const __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: number;
|
|
5
5
|
const __SVELTEKIT_DEV__: boolean;
|
|
6
6
|
const __SVELTEKIT_EMBEDDED__: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* This makes the use of specific features visible at both dev and build time, in such a
|
|
9
|
+
* way that we can error when they are not supported by the target platform.
|
|
10
|
+
*
|
|
11
|
+
* During dev, `globalThis.__SVELTEKIT_TRACK__` is a function that grabs the current `event`
|
|
12
|
+
* and route `config` (from an AsyncLocalStorage instance) and calls the relevant `supports`
|
|
13
|
+
* function on the adapter (e.g. `adapter.supports.read(...)`).
|
|
14
|
+
*
|
|
15
|
+
* At build time, if the function containing the `__SVELTEKIT_TRACK__` call is untreeshaken,
|
|
16
|
+
* we locate it in the `renderChunk` build hook and a) make a note of the chunk that contains
|
|
17
|
+
* it and b) replace it with a comment. Later, we can use this information to establish
|
|
18
|
+
* which routes use which feature, and use the same `adapter.supports.read(...)` function
|
|
19
|
+
* to throw an error if the feature would fail in production.
|
|
20
|
+
*/
|
|
21
|
+
var __SVELTEKIT_TRACK__: (label: string) => void;
|
|
7
22
|
var Bun: object;
|
|
8
23
|
var Deno: object;
|
|
9
24
|
}
|
package/src/types/internal.d.ts
CHANGED
|
@@ -13,7 +13,9 @@ import {
|
|
|
13
13
|
HandleFetch,
|
|
14
14
|
Actions,
|
|
15
15
|
HandleClientError,
|
|
16
|
-
Reroute
|
|
16
|
+
Reroute,
|
|
17
|
+
RequestEvent,
|
|
18
|
+
SSRManifest
|
|
17
19
|
} from '@sveltejs/kit';
|
|
18
20
|
import {
|
|
19
21
|
HttpMethod,
|
|
@@ -30,9 +32,11 @@ export interface ServerModule {
|
|
|
30
32
|
export interface ServerInternalModule {
|
|
31
33
|
set_assets(path: string): void;
|
|
32
34
|
set_building(): void;
|
|
35
|
+
set_manifest(manifest: SSRManifest): void;
|
|
33
36
|
set_prerendering(): void;
|
|
34
37
|
set_private_env(environment: Record<string, string>): void;
|
|
35
38
|
set_public_env(environment: Record<string, string>): void;
|
|
39
|
+
set_read_implementation(implementation: (path: string) => ReadableStream): void;
|
|
36
40
|
set_safe_public_env(environment: Record<string, string>): void;
|
|
37
41
|
set_version(version: string): void;
|
|
38
42
|
set_fix_stack_trace(fix_stack_trace: (error: unknown) => string): void;
|
|
@@ -45,6 +49,7 @@ export interface Asset {
|
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
export interface AssetDependencies {
|
|
52
|
+
assets: string[];
|
|
48
53
|
file: string;
|
|
49
54
|
imports: string[];
|
|
50
55
|
stylesheets: string[];
|
|
@@ -55,6 +60,7 @@ export interface BuildData {
|
|
|
55
60
|
app_dir: string;
|
|
56
61
|
app_path: string;
|
|
57
62
|
manifest_data: ManifestData;
|
|
63
|
+
out_dir: string;
|
|
58
64
|
service_worker: string | null;
|
|
59
65
|
client: {
|
|
60
66
|
start: string;
|
|
@@ -120,12 +126,19 @@ export class InternalServer extends Server {
|
|
|
120
126
|
options: RequestOptions & {
|
|
121
127
|
prerendering?: PrerenderOptions;
|
|
122
128
|
read: (file: string) => Buffer;
|
|
129
|
+
/** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated */
|
|
130
|
+
before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
|
|
123
131
|
}
|
|
124
132
|
): Promise<Response>;
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
export interface ManifestData {
|
|
128
136
|
assets: Asset[];
|
|
137
|
+
hooks: {
|
|
138
|
+
client: string | null;
|
|
139
|
+
server: string | null;
|
|
140
|
+
universal: string | null;
|
|
141
|
+
};
|
|
129
142
|
nodes: PageNode[];
|
|
130
143
|
routes: RouteData[];
|
|
131
144
|
matchers: Record<string, string>;
|
|
@@ -404,6 +417,7 @@ export interface SSRState {
|
|
|
404
417
|
*/
|
|
405
418
|
prerender_default?: PrerenderOption;
|
|
406
419
|
read?: (file: string) => Buffer;
|
|
420
|
+
before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
|
|
407
421
|
}
|
|
408
422
|
|
|
409
423
|
export type StrictBody = string | ArrayBufferView;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} route_id
|
|
3
|
+
* @param {any} config
|
|
4
|
+
* @param {string} feature
|
|
5
|
+
* @param {import('@sveltejs/kit').Adapter | undefined} adapter
|
|
6
|
+
*/
|
|
7
|
+
export function check_feature(route_id, config, feature, adapter) {
|
|
8
|
+
if (!adapter) return;
|
|
9
|
+
|
|
10
|
+
switch (feature) {
|
|
11
|
+
case '$app/server:read': {
|
|
12
|
+
const supported = adapter.supports?.read?.({
|
|
13
|
+
route: { id: route_id },
|
|
14
|
+
config
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (!supported) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Cannot use \`read\` from \`$app/server\` in ${route_id} when using ${adapter.name}. Please ensure that your adapter is up to date and supports this feature.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Do a shallow merge (first level) of the config object
|
|
3
|
+
* @param {Array<import('types').SSRNode | undefined>} nodes
|
|
4
|
+
*/
|
|
5
|
+
export function get_page_config(nodes) {
|
|
6
|
+
/** @type {any} */
|
|
7
|
+
let current = {};
|
|
8
|
+
|
|
9
|
+
for (const node of nodes) {
|
|
10
|
+
if (!node?.universal?.config && !node?.server?.config) continue;
|
|
11
|
+
|
|
12
|
+
current = {
|
|
13
|
+
...current,
|
|
14
|
+
...node?.universal?.config,
|
|
15
|
+
...node?.server?.config
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return Object.keys(current).length ? current : undefined;
|
|
20
|
+
}
|
package/src/version.js
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -17,6 +17,16 @@ declare module '@sveltejs/kit' {
|
|
|
17
17
|
* @param builder An object provided by SvelteKit that contains methods for adapting the app
|
|
18
18
|
*/
|
|
19
19
|
adapt(builder: Builder): MaybePromise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Checks called during dev and build to determine whether specific features will work in production with this adapter
|
|
22
|
+
*/
|
|
23
|
+
supports?: {
|
|
24
|
+
/**
|
|
25
|
+
* Test support for `read` from `$app/server`
|
|
26
|
+
* @param config The merged route config
|
|
27
|
+
*/
|
|
28
|
+
read?: (details: { config: any; route: { id: string } }) => boolean;
|
|
29
|
+
};
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
export type LoadProperties<input extends Record<string, any> | void> = input extends void
|
|
@@ -71,6 +81,7 @@ declare module '@sveltejs/kit' {
|
|
|
71
81
|
/** An array of all routes (including prerendered) */
|
|
72
82
|
routes: RouteDefinition[];
|
|
73
83
|
|
|
84
|
+
// TODO 3.0 remove this method
|
|
74
85
|
/**
|
|
75
86
|
* Create separate functions that map to one or more routes of your app.
|
|
76
87
|
* @param fn A function that groups a set of routes into an entry point
|
|
@@ -78,6 +89,11 @@ declare module '@sveltejs/kit' {
|
|
|
78
89
|
*/
|
|
79
90
|
createEntries(fn: (route: RouteDefinition) => AdapterEntry): Promise<void>;
|
|
80
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Find all the assets imported by server files belonging to `routes`
|
|
94
|
+
*/
|
|
95
|
+
findServerAssets(routes: RouteDefinition[]): string[];
|
|
96
|
+
|
|
81
97
|
/**
|
|
82
98
|
* Generate a fallback page for a static webserver to use when no route is matched. Useful for single-page apps.
|
|
83
99
|
*/
|
|
@@ -1126,7 +1142,10 @@ declare module '@sveltejs/kit' {
|
|
|
1126
1142
|
}
|
|
1127
1143
|
|
|
1128
1144
|
export interface ServerInitOptions {
|
|
1145
|
+
/** A map of environment variables */
|
|
1129
1146
|
env: Record<string, string>;
|
|
1147
|
+
/** A function that turns an asset filename into a `ReadableStream`. Required for the `read` export from `$app/server` to work */
|
|
1148
|
+
read?: (file: string) => ReadableStream;
|
|
1130
1149
|
}
|
|
1131
1150
|
|
|
1132
1151
|
export interface SSRManifest {
|
|
@@ -1141,6 +1160,8 @@ declare module '@sveltejs/kit' {
|
|
|
1141
1160
|
nodes: SSRNodeLoader[];
|
|
1142
1161
|
routes: SSRRoute[];
|
|
1143
1162
|
matchers(): Promise<Record<string, ParamMatcher>>;
|
|
1163
|
+
/** A `[file]: size` map of all assets imported by server code */
|
|
1164
|
+
server_assets: Record<string, number>;
|
|
1144
1165
|
};
|
|
1145
1166
|
}
|
|
1146
1167
|
|
|
@@ -1549,6 +1570,7 @@ declare module '@sveltejs/kit' {
|
|
|
1549
1570
|
app_dir: string;
|
|
1550
1571
|
app_path: string;
|
|
1551
1572
|
manifest_data: ManifestData;
|
|
1573
|
+
out_dir: string;
|
|
1552
1574
|
service_worker: string | null;
|
|
1553
1575
|
client: {
|
|
1554
1576
|
start: string;
|
|
@@ -1563,6 +1585,11 @@ declare module '@sveltejs/kit' {
|
|
|
1563
1585
|
|
|
1564
1586
|
interface ManifestData {
|
|
1565
1587
|
assets: Asset[];
|
|
1588
|
+
hooks: {
|
|
1589
|
+
client: string | null;
|
|
1590
|
+
server: string | null;
|
|
1591
|
+
universal: string | null;
|
|
1592
|
+
};
|
|
1566
1593
|
nodes: PageNode[];
|
|
1567
1594
|
routes: RouteData[];
|
|
1568
1595
|
matchers: Record<string, string>;
|
|
@@ -1873,6 +1900,11 @@ declare module '@sveltejs/kit/node' {
|
|
|
1873
1900
|
}): Promise<Request>;
|
|
1874
1901
|
|
|
1875
1902
|
export function setResponse(res: import('http').ServerResponse, response: Response): Promise<void>;
|
|
1903
|
+
/**
|
|
1904
|
+
* Converts a file on disk to a readable stream
|
|
1905
|
+
* @since 2.4.0
|
|
1906
|
+
*/
|
|
1907
|
+
export function createReadableStream(file: string): ReadableStream;
|
|
1876
1908
|
}
|
|
1877
1909
|
|
|
1878
1910
|
declare module '@sveltejs/kit/node/polyfills' {
|
|
@@ -2107,6 +2139,22 @@ declare module '$app/paths' {
|
|
|
2107
2139
|
export function resolveRoute(id: string, params: Record<string, string | undefined>): string;
|
|
2108
2140
|
}
|
|
2109
2141
|
|
|
2142
|
+
declare module '$app/server' {
|
|
2143
|
+
/**
|
|
2144
|
+
* Read the contents of an imported asset from the filesystem
|
|
2145
|
+
* @example
|
|
2146
|
+
* ```js
|
|
2147
|
+
* import { read } from '$app/server';
|
|
2148
|
+
* import somefile from './somefile.txt';
|
|
2149
|
+
*
|
|
2150
|
+
* const asset = read(somefile);
|
|
2151
|
+
* const text = await asset.text();
|
|
2152
|
+
* ```
|
|
2153
|
+
* @since 2.4.0
|
|
2154
|
+
*/
|
|
2155
|
+
export function read(asset: string): Response;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2110
2158
|
declare module '$app/stores' {
|
|
2111
2159
|
export function getStores(): {
|
|
2112
2160
|
|
package/types/index.d.ts.map
CHANGED
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
"sequence",
|
|
87
87
|
"getRequest",
|
|
88
88
|
"setResponse",
|
|
89
|
+
"createReadableStream",
|
|
89
90
|
"installPolyfills",
|
|
90
91
|
"sveltekit",
|
|
91
92
|
"browser",
|
|
@@ -109,6 +110,7 @@
|
|
|
109
110
|
"base",
|
|
110
111
|
"assets",
|
|
111
112
|
"resolveRoute",
|
|
113
|
+
"read",
|
|
112
114
|
"getStores",
|
|
113
115
|
"page",
|
|
114
116
|
"navigating",
|
|
@@ -129,6 +131,7 @@
|
|
|
129
131
|
"../src/runtime/app/forms.js",
|
|
130
132
|
"../src/runtime/client/client.js",
|
|
131
133
|
"../src/runtime/app/paths/types.d.ts",
|
|
134
|
+
"../src/runtime/app/server/index.js",
|
|
132
135
|
"../src/runtime/app/stores.js"
|
|
133
136
|
],
|
|
134
137
|
"sourcesContent": [
|
|
@@ -146,7 +149,8 @@
|
|
|
146
149
|
null,
|
|
147
150
|
null,
|
|
148
151
|
null,
|
|
152
|
+
null,
|
|
149
153
|
null
|
|
150
154
|
],
|
|
151
|
-
"mappings": ";;;;;;;;;kBA2BiBA,OAAOA
|
|
155
|
+
"mappings": ";;;;;;;;;kBA2BiBA,OAAOA;;;;;;;;;;;;;;;;;;;;;;aAsBZC,cAAcA;;;;;;aAMdC,cAAcA;;;;;;;;;;;;;;;kBAeTC,aAAaA;;;;;;;;;;;;;;;;kBAgBbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAkGPC,MAAMA;;;;;;;;;;;;;;;;;;;;;kBAqBNC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAyDPC,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAqZdC,MAAMA;;;;;;;;;;;aAWNC,iBAAiBA;;;;;;;;;;;;;aAajBC,iBAAiBA;;;;;;;;;;aAUjBC,WAAWA;;;;;;;;;;aAUXC,OAAOA;;;;;;aAMPC,IAAIA;;;;;;;;;;;;kBAYCC,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4GTC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0BfC,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;aAwBrBC,cAAcA;;kBAETC,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAoCVC,cAAcA;;;;;;;;;;kBAUdC,UAAUA;;;;;;;;;;;;;;;;;;kBAkBVC,aAAaA;;;;;;;;;;;;;;;;;;;kBAmBbC,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA8CTC,YAAYA;;kBAEPC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA4FjBC,cAAcA;;;;;kBAKTC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;kBAuBdC,eAAeA;;;;;;;;;;;;;;;cAenBC,MAAMA;;;;;;kBAMFC,iBAAiBA;;;;;;;kBAOjBC,WAAWA;;;;;;;;;;;;;;;;;;;;;aAqBhBC,UAAUA;;;;;;;kBAOLC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAqEpBC,MAAMA;;;;;;;;;;aAUNC,OAAOA;;;;;;;;;;;;;;;;aAgBPC,YAAYA;;;;;;;;;;;;kBC3wCXC,SAASA;;;;;;;;;;kBAqBTC,QAAQA;;;;;;;aDmxCTC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6BTC,QAAQA;;;;WE/zCRC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAkDZC,GAAGA;;;;;;;;;;;;;;;;;;;;;;WAsBHC,aAAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAmElBC,UAAUA;;WAELC,MAAMA;;;;;;;;;MASXC,YAAYA;;WAEPC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAmCXC,yBAAyBA;;;;;;;;;;WAUzBC,yBAAyBA;;;;WAIzBC,sCAAsCA;;;;MAI3CC,8BAA8BA;MAC9BC,8BAA8BA;MAC9BC,2CAA2CA;;;;;;aAM3CC,eAAeA;;WAIVC,cAAcA;;;;;WAKdC,YAAYA;;;;;;MAMjBC,aAAaA;WC9LRC,KAAKA;;;;;;WAcLC,SAASA;;;;;;;;;;;;;;;;;WA4ETC,YAAYA;;;;;;;;;;;;WAYZC,QAAQA;;;;;;;;;;;;;MAwBbC,iBAAiBA;;;;;;;;WAUZC,UAAUA;;;;;;;;;;;;;WAaVC,SAASA;;;;;;;;;;;;;;;;;;;;;;;WAsGTC,YAAYA;;;;;;;;;;;;;MAajBC,kBAAkBA;;WAEbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAsCZC,aAAaA;;WA2BRC,eAAeA;;;;;;MAMpBC,uBAAuBA;;MAEvBC,WAAWA;;;;;;;;WAQNC,QAAQA;;;;;;;;;MA0CbC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCvWXC,WAAWA;;;;;;;;;;;iBAcXC,QAAQA;;;;;iBAaRC,UAAUA;;;;;;iBASVC,IAAIA;;;;;;iBA8BJC,IAAIA;;;;;;;;;;;;aApI6CC,QAAQA;aAMVC,YAAYA;cCX9DC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCiEJC,QAAQA;;;;iBCqCFC,UAAUA;;;;;;iBAeVC,WAAWA;;;;;iBAgFjBC,oBAAoBA;;;;;;;;;iBCtLpBC,gBAAgBA;;;;;;;iBCgIVC,SAASA;;;;;;;cC/IlBC,OAAOA;;;;;cAKPC,GAAGA;;;;;cAKHC,QAAQA;;;;;cAKRC,OAAOA;;;;;;;;;;;;;;;;;;;;;;iBCWJC,WAAWA;;;;;;;;;;;;;;;;;;;;;iBAyCXC,OAAOA;;;;;;;iBC0wDDC,WAAWA;;;;;;;;;iBA5RjBC,aAAaA;;;;;;;;;;;;iBAiBbC,cAAcA;;;;;;;;;;iBAedC,UAAUA;;;;;iBASVC,qBAAqBA;;;;;;;;iBA2BrBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;iBAsCJC,UAAUA;;;;iBAmBVC,aAAaA;;;;;;;;;;;;iBAqBPC,WAAWA;;;;;;;;;;;;;;;;;;iBAoCjBC,WAAWA;;;;;iBA2BXC,SAASA;;;;;iBAuCTC,YAAYA;MVhpDhB3D,YAAYA;;;;;;;;;YWvJb4D,IAAIA;;;;;;;YAOJC,MAAMA;;;;;;;;;;;;;;;iBAeDC,YAAYA;;;;;;;;;;;;;;;;iBCTZC,IAAIA;;;;iBCVPC,SAASA;;;;;;;;;;;;;;cAwBTC,IAAIA;;;;;;;;cAeJC,UAAUA;;;;;;cAaVC,OAAOA"
|
|
152
156
|
}
|