@sveltejs/kit 1.0.0-next.480 → 1.0.0-next.482
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/scripts/special-types/$env+dynamic+private.md +2 -2
- package/scripts/special-types/$env+dynamic+public.md +1 -1
- package/scripts/special-types/$env+static+private.md +1 -1
- package/scripts/special-types/$env+static+public.md +1 -1
- package/scripts/special-types/$lib.md +4 -0
- package/src/exports/node/index.js +14 -9
- package/src/exports/vite/build/utils.js +1 -1
- package/src/exports/vite/dev/index.js +1 -1
- package/src/exports/vite/graph_analysis/index.js +277 -0
- package/src/exports/vite/graph_analysis/types.d.ts +5 -0
- package/src/exports/vite/graph_analysis/utils.js +30 -0
- package/src/exports/vite/index.js +2 -1
- package/src/exports/vite/utils.js +1 -282
- package/src/runtime/client/client.js +27 -19
- package/src/utils/unit_test.js +11 -0
- package/types/index.d.ts +8 -2
- package/types/internal.d.ts +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#
|
|
1
|
+
This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env).
|
|
2
2
|
|
|
3
|
-
This module cannot be imported into
|
|
3
|
+
This module cannot be imported into public-facing code.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { env } from '$env/dynamic/private';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Similar to [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#
|
|
1
|
+
Similar to [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
|
|
2
2
|
|
|
3
3
|
Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead.
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), this module cannot be imported into
|
|
1
|
+
Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), this module cannot be imported into public-facing code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env).
|
|
2
2
|
|
|
3
3
|
_Unlike_ [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), the values exported from this module are statically injected into your bundle at build time, enabling optimisations like dead code elimination.
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Similar to [`$env/static/private`](https://kit.svelte.dev/docs/modules#$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#
|
|
1
|
+
Similar to [`$env/static/private`](https://kit.svelte.dev/docs/modules#$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
|
|
2
2
|
|
|
3
3
|
Values are replaced statically at build time.
|
|
4
4
|
|
|
@@ -1 +1,5 @@
|
|
|
1
1
|
This is a simple alias to `src/lib`, or whatever directory is specified as [`config.kit.files.lib`](https://kit.svelte.dev/docs/configuration#files). It allows you to access common components and utility modules without `../../../../` nonsense.
|
|
2
|
+
|
|
3
|
+
#### `$lib/server`
|
|
4
|
+
|
|
5
|
+
A subdirectory of `$lib`. SvelteKit will prevent you from importing any modules in `$lib/server` into public-facing code. See [server-only modules](/docs/server-only-modules).
|
|
@@ -11,23 +11,22 @@ function get_raw_body(req, body_size_limit) {
|
|
|
11
11
|
return null;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const content_length = Number(h['content-length']);
|
|
15
15
|
|
|
16
16
|
// check if no request body
|
|
17
17
|
if (
|
|
18
|
-
(req.httpVersionMajor === 1 && isNaN(
|
|
19
|
-
|
|
18
|
+
(req.httpVersionMajor === 1 && isNaN(content_length) && h['transfer-encoding'] == null) ||
|
|
19
|
+
content_length === 0
|
|
20
20
|
) {
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
let length = content_length;
|
|
25
|
+
|
|
24
26
|
if (body_size_limit) {
|
|
25
27
|
if (!length) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
if (length > body_size_limit) {
|
|
28
|
+
length = body_size_limit;
|
|
29
|
+
} else if (length > body_size_limit) {
|
|
31
30
|
throw new Error(
|
|
32
31
|
`Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`
|
|
33
32
|
);
|
|
@@ -59,7 +58,13 @@ function get_raw_body(req, body_size_limit) {
|
|
|
59
58
|
|
|
60
59
|
size += chunk.length;
|
|
61
60
|
if (size > length) {
|
|
62
|
-
|
|
61
|
+
req.destroy(
|
|
62
|
+
new Error(
|
|
63
|
+
`request body size exceeded ${
|
|
64
|
+
content_length ? "'content-length'" : 'BODY_SIZE_LIMIT'
|
|
65
|
+
} of ${length}`
|
|
66
|
+
)
|
|
67
|
+
);
|
|
63
68
|
return;
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -147,7 +147,7 @@ export function get_default_build_config({ config, input, ssr, outDir }) {
|
|
|
147
147
|
* @returns {string}
|
|
148
148
|
*/
|
|
149
149
|
export function assets_base(config) {
|
|
150
|
-
return config.paths.assets
|
|
150
|
+
return (config.paths.assets || config.paths.base || '.') + '/';
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
const method_names = new Set(['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH']);
|
|
@@ -11,7 +11,7 @@ import { load_error_page, load_template } from '../../../core/config/index.js';
|
|
|
11
11
|
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
12
12
|
import * as sync from '../../../core/sync/sync.js';
|
|
13
13
|
import { get_mime_lookup, runtime_base, runtime_prefix } from '../../../core/utils.js';
|
|
14
|
-
import { prevent_illegal_vite_imports } from '../
|
|
14
|
+
import { prevent_illegal_vite_imports } from '../graph_analysis/index.js';
|
|
15
15
|
import { compact } from '../../../utils/array.js';
|
|
16
16
|
import { normalizePath } from 'vite';
|
|
17
17
|
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { normalizePath } from 'vite';
|
|
3
|
+
import { remove_query_from_id, get_module_types } from './utils.js';
|
|
4
|
+
|
|
5
|
+
/** @typedef {import('./types').ImportGraph} ImportGraph */
|
|
6
|
+
|
|
7
|
+
const CWD_ID = normalizePath(process.cwd());
|
|
8
|
+
const NODE_MODULES_ID = normalizePath(path.resolve(process.cwd(), 'node_modules'));
|
|
9
|
+
const ILLEGAL_IMPORTS = new Set([
|
|
10
|
+
'/@id/__x00__$env/dynamic/private', //dev
|
|
11
|
+
'\0$env/dynamic/private', // prod
|
|
12
|
+
'/@id/__x00__$env/static/private', // dev
|
|
13
|
+
'\0$env/static/private' // prod
|
|
14
|
+
]);
|
|
15
|
+
const ILLEGAL_MODULE_NAME_PATTERN = /.*\.server\..+/;
|
|
16
|
+
|
|
17
|
+
export class IllegalModuleGuard {
|
|
18
|
+
/** @type {string} */
|
|
19
|
+
#lib_dir;
|
|
20
|
+
|
|
21
|
+
/** @type {string} */
|
|
22
|
+
#server_dir;
|
|
23
|
+
|
|
24
|
+
/** @type {Array<ImportGraph>} */
|
|
25
|
+
#chain = [];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} lib_dir
|
|
29
|
+
*/
|
|
30
|
+
constructor(lib_dir) {
|
|
31
|
+
this.#lib_dir = normalizePath(lib_dir);
|
|
32
|
+
this.#server_dir = normalizePath(path.resolve(lib_dir, 'server'));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Assert that a node imports no illegal modules.
|
|
37
|
+
* @param {ImportGraph} node
|
|
38
|
+
* @returns {void}
|
|
39
|
+
*/
|
|
40
|
+
assert_legal(node) {
|
|
41
|
+
this.#chain.push(node);
|
|
42
|
+
for (const child of node.children) {
|
|
43
|
+
if (this.#is_illegal(child.id)) {
|
|
44
|
+
this.#chain.push(child);
|
|
45
|
+
const error = this.#format_illegal_import_chain(this.#chain);
|
|
46
|
+
this.#chain = []; // Reset the chain in case we want to reuse this guard
|
|
47
|
+
throw new Error(error);
|
|
48
|
+
}
|
|
49
|
+
this.assert_legal(child);
|
|
50
|
+
}
|
|
51
|
+
this.#chain.pop();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `true` if the provided ID represents a server-only module, else `false`.
|
|
56
|
+
* @param {string} module_id
|
|
57
|
+
* @returns {boolean}
|
|
58
|
+
*/
|
|
59
|
+
#is_illegal(module_id) {
|
|
60
|
+
if (this.#is_kit_illegal(module_id) || this.#is_user_illegal(module_id)) return true;
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* `true` if the provided ID represents a Kit-defined server-only module, else `false`.
|
|
66
|
+
* @param {string} module_id
|
|
67
|
+
* @returns {boolean}
|
|
68
|
+
*/
|
|
69
|
+
#is_kit_illegal(module_id) {
|
|
70
|
+
return ILLEGAL_IMPORTS.has(module_id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* `true` if the provided ID represents a user-defined server-only module, else `false`.
|
|
75
|
+
* @param {string} module_id
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
78
|
+
#is_user_illegal(module_id) {
|
|
79
|
+
if (module_id.startsWith(this.#server_dir)) return true;
|
|
80
|
+
|
|
81
|
+
// files outside the project root are ignored
|
|
82
|
+
if (!module_id.startsWith(CWD_ID)) return false;
|
|
83
|
+
|
|
84
|
+
// so are files inside node_modules
|
|
85
|
+
if (module_id.startsWith(NODE_MODULES_ID)) return false;
|
|
86
|
+
|
|
87
|
+
return ILLEGAL_MODULE_NAME_PATTERN.test(path.basename(module_id));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {string} str
|
|
92
|
+
* @param {number} times
|
|
93
|
+
*/
|
|
94
|
+
#repeat(str, times) {
|
|
95
|
+
return new Array(times + 1).join(str);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create a formatted error for an illegal import.
|
|
100
|
+
* @param {Array<ImportGraph>} stack
|
|
101
|
+
*/
|
|
102
|
+
#format_illegal_import_chain(stack) {
|
|
103
|
+
const dev_virtual_prefix = '/@id/__x00__';
|
|
104
|
+
const prod_virtual_prefix = '\0';
|
|
105
|
+
|
|
106
|
+
stack = stack.map((graph) => {
|
|
107
|
+
if (graph.id.startsWith(dev_virtual_prefix)) {
|
|
108
|
+
return { ...graph, id: graph.id.replace(dev_virtual_prefix, '') };
|
|
109
|
+
}
|
|
110
|
+
if (graph.id.startsWith(prod_virtual_prefix)) {
|
|
111
|
+
return { ...graph, id: graph.id.replace(prod_virtual_prefix, '') };
|
|
112
|
+
}
|
|
113
|
+
if (graph.id.startsWith(this.#lib_dir)) {
|
|
114
|
+
return { ...graph, id: graph.id.replace(this.#lib_dir, '$lib') };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { ...graph, id: path.relative(process.cwd(), graph.id) };
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const pyramid = stack
|
|
121
|
+
.map(
|
|
122
|
+
(file, i) =>
|
|
123
|
+
`${this.#repeat(' ', i * 2)}- ${file.id} ${
|
|
124
|
+
file.dynamic ? '(imported by parent dynamically)' : ''
|
|
125
|
+
}`
|
|
126
|
+
)
|
|
127
|
+
.join('\n');
|
|
128
|
+
|
|
129
|
+
return `Cannot import ${stack.at(-1)?.id} into public-facing code:\n${pyramid}`;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** @implements {ImportGraph} */
|
|
134
|
+
export class RollupImportGraph {
|
|
135
|
+
/** @type {(id: string) => import('rollup').ModuleInfo | null} */
|
|
136
|
+
#node_getter;
|
|
137
|
+
|
|
138
|
+
/** @type {import('rollup').ModuleInfo} */
|
|
139
|
+
#module_info;
|
|
140
|
+
|
|
141
|
+
/** @type {string} */
|
|
142
|
+
id;
|
|
143
|
+
|
|
144
|
+
/** @type {boolean} */
|
|
145
|
+
dynamic;
|
|
146
|
+
|
|
147
|
+
/** @type {Set<string>} */
|
|
148
|
+
#seen;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
152
|
+
* @param {import('rollup').ModuleInfo} node
|
|
153
|
+
*/
|
|
154
|
+
constructor(node_getter, node) {
|
|
155
|
+
this.#node_getter = node_getter;
|
|
156
|
+
this.#module_info = node;
|
|
157
|
+
this.id = remove_query_from_id(normalizePath(node.id));
|
|
158
|
+
this.dynamic = false;
|
|
159
|
+
this.#seen = new Set();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
164
|
+
* @param {import('rollup').ModuleInfo} node
|
|
165
|
+
* @param {boolean} dynamic
|
|
166
|
+
* @param {Set<string>} seen;
|
|
167
|
+
* @returns {RollupImportGraph}
|
|
168
|
+
*/
|
|
169
|
+
static #new_internal(node_getter, node, dynamic, seen) {
|
|
170
|
+
const instance = new RollupImportGraph(node_getter, node);
|
|
171
|
+
instance.dynamic = dynamic;
|
|
172
|
+
instance.#seen = seen;
|
|
173
|
+
return instance;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
get children() {
|
|
177
|
+
return this.#children();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
*#children() {
|
|
181
|
+
if (this.#seen.has(this.id)) return;
|
|
182
|
+
this.#seen.add(this.id);
|
|
183
|
+
for (const id of this.#module_info.importedIds) {
|
|
184
|
+
const child = this.#node_getter(id);
|
|
185
|
+
if (child === null) return;
|
|
186
|
+
yield RollupImportGraph.#new_internal(this.#node_getter, child, false, this.#seen);
|
|
187
|
+
}
|
|
188
|
+
for (const id of this.#module_info.dynamicallyImportedIds) {
|
|
189
|
+
const child = this.#node_getter(id);
|
|
190
|
+
if (child === null) return;
|
|
191
|
+
yield RollupImportGraph.#new_internal(this.#node_getter, child, true, this.#seen);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** @implements {ImportGraph} */
|
|
197
|
+
export class ViteImportGraph {
|
|
198
|
+
/** @type {Set<string>} */
|
|
199
|
+
#module_types;
|
|
200
|
+
|
|
201
|
+
/** @type {import('vite').ModuleNode} */
|
|
202
|
+
#module_info;
|
|
203
|
+
|
|
204
|
+
/** @type {string} */
|
|
205
|
+
id;
|
|
206
|
+
|
|
207
|
+
/** @type {Set<string>} */
|
|
208
|
+
#seen;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
|
|
212
|
+
* @param {import('vite').ModuleNode} node
|
|
213
|
+
*/
|
|
214
|
+
constructor(module_types, node) {
|
|
215
|
+
this.#module_types = module_types;
|
|
216
|
+
this.#module_info = node;
|
|
217
|
+
this.id = remove_query_from_id(normalizePath(node.id ?? ''));
|
|
218
|
+
this.#seen = new Set();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
|
|
223
|
+
* @param {import('vite').ModuleNode} node
|
|
224
|
+
* @param {Set<string>} seen
|
|
225
|
+
* @returns {ViteImportGraph}
|
|
226
|
+
*/
|
|
227
|
+
static #new_internal(module_types, node, seen) {
|
|
228
|
+
const instance = new ViteImportGraph(module_types, node);
|
|
229
|
+
instance.#seen = seen;
|
|
230
|
+
return instance;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
get dynamic() {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
get children() {
|
|
238
|
+
return this.#children();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
*#children() {
|
|
242
|
+
if (this.#seen.has(this.id)) return;
|
|
243
|
+
this.#seen.add(this.id);
|
|
244
|
+
for (const child of this.#module_info.importedModules) {
|
|
245
|
+
if (!this.#module_types.has(path.extname(this.id))) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
yield ViteImportGraph.#new_internal(this.#module_types, child, this.#seen);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Throw an error if a private module is imported from a client-side node.
|
|
255
|
+
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
256
|
+
* @param {import('rollup').ModuleInfo} node
|
|
257
|
+
* @param {string} lib_dir
|
|
258
|
+
* @returns {void}
|
|
259
|
+
*/
|
|
260
|
+
export function prevent_illegal_rollup_imports(node_getter, node, lib_dir) {
|
|
261
|
+
const graph = new RollupImportGraph(node_getter, node);
|
|
262
|
+
const guard = new IllegalModuleGuard(lib_dir);
|
|
263
|
+
guard.assert_legal(graph);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Throw an error if a private module is imported from a client-side node.
|
|
268
|
+
* @param {import('vite').ModuleNode} node
|
|
269
|
+
* @param {string} lib_dir
|
|
270
|
+
* @param {Iterable<string>} module_types File extensions to analyze in addition to the defaults: `.ts`, `.js`, etc.
|
|
271
|
+
* @returns {void}
|
|
272
|
+
*/
|
|
273
|
+
export function prevent_illegal_vite_imports(node, lib_dir, module_types) {
|
|
274
|
+
const graph = new ViteImportGraph(get_module_types(module_types), node);
|
|
275
|
+
const guard = new IllegalModuleGuard(lib_dir);
|
|
276
|
+
guard.assert_legal(graph);
|
|
277
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const query_pattern = /\?.*$/s;
|
|
2
|
+
|
|
3
|
+
/** @param {string} path */
|
|
4
|
+
export function remove_query_from_id(path) {
|
|
5
|
+
return path.replace(query_pattern, '');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Vite does some weird things with import trees in dev
|
|
10
|
+
* for example, a Tailwind app.css will appear to import
|
|
11
|
+
* every file in the project. This isn't a problem for
|
|
12
|
+
* Rollup during build.
|
|
13
|
+
* @param {Iterable<string>} config_module_types
|
|
14
|
+
*/
|
|
15
|
+
export const get_module_types = (config_module_types) => {
|
|
16
|
+
return new Set([
|
|
17
|
+
'',
|
|
18
|
+
'.ts',
|
|
19
|
+
'.js',
|
|
20
|
+
'.svelte',
|
|
21
|
+
'.mts',
|
|
22
|
+
'.mjs',
|
|
23
|
+
'.cts',
|
|
24
|
+
'.cjs',
|
|
25
|
+
'.svelte.md',
|
|
26
|
+
'.svx',
|
|
27
|
+
'.md',
|
|
28
|
+
...config_module_types
|
|
29
|
+
]);
|
|
30
|
+
};
|
|
@@ -14,7 +14,8 @@ import { generate_manifest } from '../../core/generate_manifest/index.js';
|
|
|
14
14
|
import { runtime_directory, logger } from '../../core/utils.js';
|
|
15
15
|
import { find_deps, get_default_build_config } from './build/utils.js';
|
|
16
16
|
import { preview } from './preview/index.js';
|
|
17
|
-
import { get_aliases,
|
|
17
|
+
import { get_aliases, get_env } from './utils.js';
|
|
18
|
+
import { prevent_illegal_rollup_imports } from './graph_analysis/index.js';
|
|
18
19
|
import { fileURLToPath } from 'node:url';
|
|
19
20
|
import { create_static_module, create_dynamic_module } from '../../core/env.js';
|
|
20
21
|
|
|
@@ -1,232 +1,8 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import { loadConfigFromFile, loadEnv
|
|
2
|
+
import { loadConfigFromFile, loadEnv } from 'vite';
|
|
3
3
|
import { runtime_directory } from '../../core/utils.js';
|
|
4
4
|
import { posixify } from '../../utils/filesystem.js';
|
|
5
5
|
|
|
6
|
-
class IllegalModuleGuard {
|
|
7
|
-
/** @type {string} */
|
|
8
|
-
#lib_dir;
|
|
9
|
-
|
|
10
|
-
/** @type {string} */
|
|
11
|
-
#server_dir;
|
|
12
|
-
|
|
13
|
-
/** @type {string} */
|
|
14
|
-
#node_modules_dir = normalizePath(path.resolve(process.cwd(), 'node_modules'));
|
|
15
|
-
|
|
16
|
-
/** @type {string} */
|
|
17
|
-
#cwd = normalizePath(process.cwd());
|
|
18
|
-
|
|
19
|
-
/** @type {Set<string>} */
|
|
20
|
-
#illegal_imports = new Set([
|
|
21
|
-
'/@id/__x00__$env/dynamic/private', //dev
|
|
22
|
-
'\0$env/dynamic/private', // prod
|
|
23
|
-
'/@id/__x00__$env/static/private', // dev
|
|
24
|
-
'\0$env/static/private' // prod
|
|
25
|
-
]);
|
|
26
|
-
|
|
27
|
-
/** @type {Array<import('types').ImportNode>} */
|
|
28
|
-
#chain = [];
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @param {string} lib_dir
|
|
32
|
-
*/
|
|
33
|
-
constructor(lib_dir) {
|
|
34
|
-
this.#lib_dir = normalizePath(lib_dir);
|
|
35
|
-
this.#server_dir = normalizePath(path.resolve(lib_dir, 'server'));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @param {import('types').ImportNode} node
|
|
40
|
-
* @returns {void}
|
|
41
|
-
*/
|
|
42
|
-
assert_legal(node) {
|
|
43
|
-
this.#chain.push(node);
|
|
44
|
-
for (const child of node.children) {
|
|
45
|
-
if (this.#is_illegal(child.name)) {
|
|
46
|
-
this.#chain.push(child);
|
|
47
|
-
throw new Error(this.#format_illegal_import_chain(this.#chain));
|
|
48
|
-
}
|
|
49
|
-
this.assert_legal(child);
|
|
50
|
-
}
|
|
51
|
-
this.#chain.pop();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* `true` if the provided ID represents a server-only module, else `false`.
|
|
56
|
-
* @param {string} module_id
|
|
57
|
-
* @returns {boolean}
|
|
58
|
-
*/
|
|
59
|
-
#is_illegal(module_id) {
|
|
60
|
-
if (this.#is_kit_illegal(module_id) || this.#is_user_illegal(module_id)) return true;
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* `true` if the provided ID represents a Kit-defined server-only module, else `false`.
|
|
66
|
-
* @param {string} module_id
|
|
67
|
-
* @returns {boolean}
|
|
68
|
-
*/
|
|
69
|
-
#is_kit_illegal(module_id) {
|
|
70
|
-
return this.#illegal_imports.has(module_id);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* `true` if the provided ID represents a user-defined server-only module, else `false`.
|
|
75
|
-
* @param {string} module_id
|
|
76
|
-
* @returns {boolean}
|
|
77
|
-
*/
|
|
78
|
-
#is_user_illegal(module_id) {
|
|
79
|
-
if (module_id.startsWith(this.#server_dir)) return true;
|
|
80
|
-
|
|
81
|
-
// files outside the project root are ignored
|
|
82
|
-
if (!module_id.startsWith(this.#cwd)) return false;
|
|
83
|
-
|
|
84
|
-
// so are files inside node_modules
|
|
85
|
-
if (module_id.startsWith(this.#node_modules_dir)) return false;
|
|
86
|
-
|
|
87
|
-
return /.*\.server\..+/.test(path.basename(module_id));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* @param {string} str
|
|
92
|
-
* @param {number} times
|
|
93
|
-
*/
|
|
94
|
-
#repeat(str, times) {
|
|
95
|
-
return new Array(times + 1).join(str);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Create a formatted error for an illegal import.
|
|
100
|
-
* @param {Array<{name: string, dynamic: boolean}>} stack
|
|
101
|
-
*/
|
|
102
|
-
#format_illegal_import_chain(stack) {
|
|
103
|
-
const dev_virtual_prefix = '/@id/__x00__';
|
|
104
|
-
const prod_virtual_prefix = '\0';
|
|
105
|
-
|
|
106
|
-
stack = stack.map((file) => {
|
|
107
|
-
if (file.name.startsWith(dev_virtual_prefix)) {
|
|
108
|
-
return { ...file, name: file.name.replace(dev_virtual_prefix, '') };
|
|
109
|
-
}
|
|
110
|
-
if (file.name.startsWith(prod_virtual_prefix)) {
|
|
111
|
-
return { ...file, name: file.name.replace(prod_virtual_prefix, '') };
|
|
112
|
-
}
|
|
113
|
-
if (file.name.startsWith(this.#lib_dir)) {
|
|
114
|
-
return { ...file, name: file.name.replace(this.#lib_dir, '$lib') };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return { ...file, name: path.relative(process.cwd(), file.name) };
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const pyramid = stack
|
|
121
|
-
.map(
|
|
122
|
-
(file, i) =>
|
|
123
|
-
`${this.#repeat(' ', i * 2)}- ${file.name} ${
|
|
124
|
-
file.dynamic ? '(imported by parent dynamically)' : ''
|
|
125
|
-
}`
|
|
126
|
-
)
|
|
127
|
-
.join('\n');
|
|
128
|
-
|
|
129
|
-
return `Cannot import ${stack.at(-1)?.name} into client-side code:\n${pyramid}`;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
class RollupImportGraph {
|
|
134
|
-
/** @type {(id: string) => import('rollup').ModuleInfo | null} */
|
|
135
|
-
#node_getter;
|
|
136
|
-
|
|
137
|
-
/** @type {import('rollup').ModuleInfo} */
|
|
138
|
-
#module_info;
|
|
139
|
-
|
|
140
|
-
/** @type {string} */
|
|
141
|
-
name;
|
|
142
|
-
|
|
143
|
-
/** @type {boolean} */
|
|
144
|
-
dynamic;
|
|
145
|
-
|
|
146
|
-
/** @type {Set<string>} */
|
|
147
|
-
#seen;
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
151
|
-
* @param {import('rollup').ModuleInfo} node
|
|
152
|
-
* @param {boolean} dynamic
|
|
153
|
-
* @param {Set<string>} seen
|
|
154
|
-
*/
|
|
155
|
-
constructor(node_getter, node, dynamic = false, seen = new Set()) {
|
|
156
|
-
this.#node_getter = node_getter;
|
|
157
|
-
this.#module_info = node;
|
|
158
|
-
this.name = remove_query_from_path(normalizePath(node.id));
|
|
159
|
-
this.dynamic = dynamic;
|
|
160
|
-
this.#seen = seen;
|
|
161
|
-
void (/** @type {import('types').ImportNode} */ (this));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
get children() {
|
|
165
|
-
return this.#children();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
*#children() {
|
|
169
|
-
if (this.#seen.has(this.name)) return;
|
|
170
|
-
this.#seen.add(this.name);
|
|
171
|
-
for (const id of this.#module_info.importedIds) {
|
|
172
|
-
const child = this.#node_getter(id);
|
|
173
|
-
if (child === null) return;
|
|
174
|
-
yield new RollupImportGraph(this.#node_getter, child, false, this.#seen);
|
|
175
|
-
}
|
|
176
|
-
for (const id of this.#module_info.dynamicallyImportedIds) {
|
|
177
|
-
const child = this.#node_getter(id);
|
|
178
|
-
if (child === null) return;
|
|
179
|
-
yield new RollupImportGraph(this.#node_getter, child, true, this.#seen);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
class ViteImportGraph {
|
|
185
|
-
/** @type {Set<string>} */
|
|
186
|
-
#module_types;
|
|
187
|
-
|
|
188
|
-
/** @type {import('vite').ModuleNode} */
|
|
189
|
-
#module_info;
|
|
190
|
-
|
|
191
|
-
/** @type {string} */
|
|
192
|
-
name;
|
|
193
|
-
|
|
194
|
-
/** @type {Set<string>} */
|
|
195
|
-
#seen;
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
|
|
199
|
-
* @param {import('vite').ModuleNode} node
|
|
200
|
-
* @param {Set<string>} seen
|
|
201
|
-
*/
|
|
202
|
-
constructor(module_types, node, seen = new Set()) {
|
|
203
|
-
this.#module_types = module_types;
|
|
204
|
-
this.#module_info = node;
|
|
205
|
-
this.name = remove_query_from_path(normalizePath(node.id ?? ''));
|
|
206
|
-
this.#seen = seen;
|
|
207
|
-
void (/** @type {import('types').ImportNode} */ (this));
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
get dynamic() {
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
get children() {
|
|
215
|
-
return this.#children();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
*#children() {
|
|
219
|
-
if (this.#seen.has(this.name)) return;
|
|
220
|
-
this.#seen.add(this.name);
|
|
221
|
-
for (const child of this.#module_info.importedModules) {
|
|
222
|
-
if (!this.#module_types.has(path.extname(this.name))) {
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
yield new ViteImportGraph(this.#module_types, child, this.#seen);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
6
|
/**
|
|
231
7
|
* @param {import('vite').ResolvedConfig} config
|
|
232
8
|
* @param {import('vite').ConfigEnv} config_env
|
|
@@ -379,60 +155,3 @@ export function get_env(env_config, mode) {
|
|
|
379
155
|
private: Object.fromEntries(entries.filter(([k]) => !k.startsWith(env_config.publicPrefix)))
|
|
380
156
|
};
|
|
381
157
|
}
|
|
382
|
-
|
|
383
|
-
const query_pattern = /\?.*$/s;
|
|
384
|
-
|
|
385
|
-
/** @param {string} path */
|
|
386
|
-
function remove_query_from_path(path) {
|
|
387
|
-
return path.replace(query_pattern, '');
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Vite does some weird things with import trees in dev
|
|
392
|
-
* for example, a Tailwind app.css will appear to import
|
|
393
|
-
* every file in the project. This isn't a problem for
|
|
394
|
-
* Rollup during build.
|
|
395
|
-
* @param {Iterable<string>} config_module_types
|
|
396
|
-
*/
|
|
397
|
-
const get_module_types = (config_module_types) => {
|
|
398
|
-
return new Set([
|
|
399
|
-
'',
|
|
400
|
-
'.ts',
|
|
401
|
-
'.js',
|
|
402
|
-
'.svelte',
|
|
403
|
-
'.mts',
|
|
404
|
-
'.mjs',
|
|
405
|
-
'.cts',
|
|
406
|
-
'.cjs',
|
|
407
|
-
'.svelte.md',
|
|
408
|
-
'.svx',
|
|
409
|
-
'.md',
|
|
410
|
-
...config_module_types
|
|
411
|
-
]);
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Throw an error if a private module is imported from a client-side node.
|
|
416
|
-
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
417
|
-
* @param {import('rollup').ModuleInfo} node
|
|
418
|
-
* @param {string} lib_dir
|
|
419
|
-
* @returns {void}
|
|
420
|
-
*/
|
|
421
|
-
export function prevent_illegal_rollup_imports(node_getter, node, lib_dir) {
|
|
422
|
-
const graph = new RollupImportGraph(node_getter, node);
|
|
423
|
-
const guard = new IllegalModuleGuard(lib_dir);
|
|
424
|
-
guard.assert_legal(graph);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Throw an error if a private module is imported from a client-side node.
|
|
429
|
-
* @param {import('vite').ModuleNode} node
|
|
430
|
-
* @param {string} lib_dir
|
|
431
|
-
* @param {Iterable<string>} module_types File extensions to analyze in addition to the defaults: `.ts`, `.js`, etc.
|
|
432
|
-
* @returns {void}
|
|
433
|
-
*/
|
|
434
|
-
export function prevent_illegal_vite_imports(node, lib_dir, module_types) {
|
|
435
|
-
const graph = new ViteImportGraph(get_module_types(module_types), node);
|
|
436
|
-
const guard = new IllegalModuleGuard(lib_dir);
|
|
437
|
-
guard.assert_legal(graph);
|
|
438
|
-
}
|
|
@@ -43,6 +43,7 @@ function update_scroll_positions(index) {
|
|
|
43
43
|
scroll_positions[index] = scroll_state();
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// TODO remove for 1.0
|
|
46
47
|
/** @type {Record<string, true>} */
|
|
47
48
|
let warned_about_attributes = {};
|
|
48
49
|
|
|
@@ -742,12 +743,11 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
742
743
|
/** @type {import('./types').BranchNode | undefined} */
|
|
743
744
|
const previous = current.branch[i];
|
|
744
745
|
|
|
745
|
-
const server_data_node = server_data_nodes?.[i]
|
|
746
|
+
const server_data_node = server_data_nodes?.[i];
|
|
746
747
|
|
|
747
|
-
const can_reuse_server_data = !server_data_node || server_data_node.type === 'skip';
|
|
748
748
|
// re-use data from previous load if it's still valid
|
|
749
749
|
const valid =
|
|
750
|
-
|
|
750
|
+
(!server_data_node || server_data_node.type === 'skip') &&
|
|
751
751
|
loader[1] === previous?.loader &&
|
|
752
752
|
!has_changed(changed, parent_changed, previous.shared?.uses);
|
|
753
753
|
if (valid) return previous;
|
|
@@ -771,7 +771,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
771
771
|
}
|
|
772
772
|
return data;
|
|
773
773
|
},
|
|
774
|
-
server_data_node: create_data_node(
|
|
774
|
+
server_data_node: create_data_node(
|
|
775
|
+
// server_data_node is undefined if it wasn't reloaded from the server;
|
|
776
|
+
// and if current loader uses server data, we want to reuse previous data.
|
|
777
|
+
server_data_node === undefined && loader[0] ? { type: 'skip' } : server_data_node ?? null,
|
|
778
|
+
previous?.server
|
|
779
|
+
)
|
|
775
780
|
});
|
|
776
781
|
});
|
|
777
782
|
|
|
@@ -1321,10 +1326,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1321
1326
|
if (hash !== undefined && base === location.href.split('#')[0]) {
|
|
1322
1327
|
// set this flag to distinguish between navigations triggered by
|
|
1323
1328
|
// clicking a hash link and those triggered by popstate
|
|
1329
|
+
// TODO why not update history here directly?
|
|
1324
1330
|
hash_navigating = true;
|
|
1325
1331
|
|
|
1326
1332
|
update_scroll_positions(current_history_index);
|
|
1327
1333
|
|
|
1334
|
+
current.url = url;
|
|
1328
1335
|
stores.page.set({ ...page, url });
|
|
1329
1336
|
stores.page.notify();
|
|
1330
1337
|
|
|
@@ -1545,25 +1552,26 @@ function add_url_properties(type, target) {
|
|
|
1545
1552
|
|
|
1546
1553
|
function pre_update() {
|
|
1547
1554
|
if (__SVELTEKIT_DEV__) {
|
|
1548
|
-
// Nasty hack to silence harmless warnings the user can do nothing about
|
|
1549
|
-
const warn = console.warn;
|
|
1550
|
-
console.warn = (...args) => {
|
|
1551
|
-
if (
|
|
1552
|
-
args.length === 1 &&
|
|
1553
|
-
/<(Layout|Page)(_[\w$]+)?> was created (with unknown|without expected) prop '(data|form)'/.test(
|
|
1554
|
-
args[0]
|
|
1555
|
-
)
|
|
1556
|
-
) {
|
|
1557
|
-
return;
|
|
1558
|
-
}
|
|
1559
|
-
warn(...args);
|
|
1560
|
-
};
|
|
1561
|
-
|
|
1562
1555
|
return () => {
|
|
1563
|
-
tick().then(() => (console.warn = warn));
|
|
1564
1556
|
check_for_removed_attributes();
|
|
1565
1557
|
};
|
|
1566
1558
|
}
|
|
1567
1559
|
|
|
1568
1560
|
return () => {};
|
|
1569
1561
|
}
|
|
1562
|
+
|
|
1563
|
+
if (__SVELTEKIT_DEV__) {
|
|
1564
|
+
// Nasty hack to silence harmless warnings the user can do nothing about
|
|
1565
|
+
const warn = console.warn;
|
|
1566
|
+
console.warn = (...args) => {
|
|
1567
|
+
if (
|
|
1568
|
+
args.length === 1 &&
|
|
1569
|
+
/<(Layout|Page)(_[\w$]+)?> was created (with unknown|without expected) prop '(data|form)'/.test(
|
|
1570
|
+
args[0]
|
|
1571
|
+
)
|
|
1572
|
+
) {
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
warn(...args);
|
|
1576
|
+
};
|
|
1577
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
TrailingSlash
|
|
17
17
|
} from './private.js';
|
|
18
18
|
import { SSRNodeLoader, SSRRoute, ValidatedConfig } from './internal.js';
|
|
19
|
-
import { HttpError, Redirect
|
|
19
|
+
import { HttpError, Redirect } from '../src/runtime/control.js';
|
|
20
20
|
|
|
21
21
|
export { PrerenderOption } from './private.js';
|
|
22
22
|
|
|
@@ -39,6 +39,12 @@ export type AwaitedActions<T extends Record<string, (...args: any) => any>> = {
|
|
|
39
39
|
[Key in keyof T]: UnpackValidationError<Awaited<ReturnType<T[Key]>>>;
|
|
40
40
|
}[keyof T];
|
|
41
41
|
|
|
42
|
+
// Needs to be here, else ActionData will be resolved to unknown - probably because of "d.ts file imports .js file" in combination with allowJs
|
|
43
|
+
interface ValidationError<T extends Record<string, unknown> | undefined = undefined> {
|
|
44
|
+
status: number;
|
|
45
|
+
data: T;
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
type UnpackValidationError<T> = T extends ValidationError<infer X> ? X : T;
|
|
43
49
|
|
|
44
50
|
export interface Builder {
|
|
@@ -292,7 +298,7 @@ export interface RequestEvent<
|
|
|
292
298
|
/**
|
|
293
299
|
* A `(event: RequestEvent) => Response` function exported from a `+server.js` file that corresponds to an HTTP verb (`GET`, `PUT`, `PATCH`, etc) and handles requests with that method.
|
|
294
300
|
*
|
|
295
|
-
* It receives `Params` as the first generic argument, which you can skip by using [generated types](/docs/types#generated-types) instead.
|
|
301
|
+
* It receives `Params` as the first generic argument, which you can skip by using [generated types](https://kit.svelte.dev/docs/types#generated-types) instead.
|
|
296
302
|
*/
|
|
297
303
|
export interface RequestHandler<
|
|
298
304
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>
|
package/types/internal.d.ts
CHANGED
|
@@ -100,12 +100,6 @@ export interface ClientHooks {
|
|
|
100
100
|
handleError: HandleClientError;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
export interface ImportNode {
|
|
104
|
-
readonly name: string;
|
|
105
|
-
readonly dynamic: boolean;
|
|
106
|
-
readonly children: Generator<ImportNode>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
103
|
export class InternalServer extends Server {
|
|
110
104
|
init(options: ServerInitOptions): Promise<void>;
|
|
111
105
|
respond(
|