@sveltejs/kit 2.61.1 → 2.63.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 +14 -3
- package/src/cli.js +32 -6
- package/src/core/adapt/builder.js +31 -5
- package/src/core/adapt/index.js +5 -2
- package/src/core/config/index.js +100 -36
- package/src/core/config/options.js +1 -0
- package/src/core/env.js +313 -8
- package/src/core/postbuild/analyse.js +2 -1
- package/src/core/postbuild/fallback.js +7 -8
- package/src/core/postbuild/prerender.js +6 -2
- package/src/core/sync/sync.js +16 -0
- package/src/core/sync/write_ambient.js +12 -6
- package/src/core/sync/write_env.js +32 -0
- package/src/core/sync/write_root.js +1 -1
- package/src/core/sync/write_server.js +3 -2
- package/src/core/sync/write_tsconfig.js +1 -0
- package/src/exports/hooks/index.js +13 -0
- package/src/exports/internal/env.js +71 -0
- package/src/exports/internal/types.d.ts +3 -0
- package/src/exports/node/index.js +2 -10
- package/src/exports/public.d.ts +41 -1
- package/src/exports/vite/build/build_service_worker.js +20 -4
- package/src/exports/vite/dev/index.js +2 -2
- package/src/exports/vite/index.js +157 -33
- package/src/exports/vite/module_ids.js +10 -1
- package/src/exports/vite/utils.js +6 -0
- package/src/runtime/app/env/index.js +2 -0
- package/src/runtime/app/env/internal.js +11 -0
- package/src/runtime/app/env/private.js +1 -0
- package/src/runtime/app/env/public/client.js +7 -0
- package/src/runtime/app/env/public/index.js +1 -0
- package/src/runtime/app/env/public/server.js +7 -0
- package/src/runtime/app/env/standard-schema.d.ts +0 -0
- package/src/runtime/app/env/types.d.ts +19 -0
- package/src/runtime/app/environment/index.js +10 -2
- package/src/runtime/app/server/remote/query.js +1 -1
- package/src/runtime/app/state/client.js +10 -6
- package/src/runtime/client/client.js +68 -51
- package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
- package/src/runtime/client/utils.js +1 -1
- package/src/runtime/server/env_module.js +13 -3
- package/src/runtime/server/fetch.js +12 -14
- package/src/runtime/server/index.js +2 -0
- package/src/runtime/server/page/render.js +11 -3
- package/src/runtime/server/respond.js +8 -11
- package/src/types/ambient-private.d.ts +25 -9
- package/src/types/global-private.d.ts +2 -0
- package/src/types/internal.d.ts +1 -0
- package/src/utils/http.js +21 -0
- package/src/utils/import.js +2 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +76 -4
- package/types/index.d.ts.map +7 -1
package/src/core/env.js
CHANGED
|
@@ -1,19 +1,126 @@
|
|
|
1
|
+
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
2
|
+
/** @import { EnvVarConfig } from '@sveltejs/kit' */
|
|
3
|
+
/** @import { ValidatedKitConfig } from 'types' */
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import * as vite from 'vite';
|
|
7
|
+
import * as devalue from 'devalue';
|
|
1
8
|
import { GENERATED_COMMENT } from '../constants.js';
|
|
2
9
|
import { dedent } from './sync/utils.js';
|
|
3
|
-
import { runtime_base } from './utils.js';
|
|
10
|
+
import { runtime_base, runtime_directory } from './utils.js';
|
|
11
|
+
import { resolve_entry } from '../utils/filesystem.js';
|
|
12
|
+
import { handle_issues, validate } from '../exports/internal/env.js';
|
|
13
|
+
import { get_config_aliases } from '../exports/vite/utils.js';
|
|
4
14
|
|
|
5
15
|
/**
|
|
6
16
|
* @typedef {'public' | 'private'} EnvType
|
|
7
17
|
*/
|
|
8
18
|
|
|
19
|
+
let warned = false;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {import('types').ValidatedKitConfig} config
|
|
23
|
+
* @returns {string | null}
|
|
24
|
+
*/
|
|
25
|
+
export function resolve_explicit_env_entry(config) {
|
|
26
|
+
const resolved = resolve_entry(path.join(config.files.src, 'env'));
|
|
27
|
+
|
|
28
|
+
if (resolved) {
|
|
29
|
+
if (config.experimental.explicitEnvironmentVariables) {
|
|
30
|
+
return resolved;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!warned) {
|
|
34
|
+
console.warn(
|
|
35
|
+
`${path.relative(process.cwd(), resolved)} requires the \`experimental.explicitEnvironmentVariables\` flag to be set`
|
|
36
|
+
);
|
|
37
|
+
warned = true;
|
|
38
|
+
}
|
|
39
|
+
} else if (config.experimental.explicitEnvironmentVariables) {
|
|
40
|
+
console.warn(
|
|
41
|
+
'experimental.explicitEnvironmentVariables was set, but no src/env.ts or src/env.js file could be found'
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {ValidatedKitConfig} kit
|
|
50
|
+
* @param {string | null} file
|
|
51
|
+
* @param {string} mode
|
|
52
|
+
* @returns {Promise<Record<string, EnvVarConfig<any>> | null>}
|
|
53
|
+
*/
|
|
54
|
+
export async function load_explicit_env(kit, file, mode) {
|
|
55
|
+
if (!file) return null;
|
|
56
|
+
|
|
57
|
+
const server = await vite.createServer({
|
|
58
|
+
configFile: false,
|
|
59
|
+
logLevel: 'silent',
|
|
60
|
+
mode,
|
|
61
|
+
define: {
|
|
62
|
+
__SVELTEKIT_APP_VERSION__: JSON.stringify(kit.version.name) // needed by $app/env
|
|
63
|
+
},
|
|
64
|
+
resolve: {
|
|
65
|
+
alias: [
|
|
66
|
+
{ find: '$app/env', replacement: `${runtime_directory}/app/env` },
|
|
67
|
+
...get_config_aliases(kit)
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/** @type {Record<string, EnvVarConfig<any>>} */
|
|
73
|
+
let variables;
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
({ variables } = await server.ssrLoadModule(file));
|
|
77
|
+
|
|
78
|
+
if (!variables || typeof variables !== 'object') {
|
|
79
|
+
throw new Error(`${file} must export a variables object`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// validate
|
|
83
|
+
for (const name of Object.keys(variables)) {
|
|
84
|
+
if (!valid_identifier.test(name) || reserved.has(name)) {
|
|
85
|
+
throw new Error(`Invalid environment variable name ${JSON.stringify(name)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
const error = /** @type {any} */ (e || {});
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
error.code === 'ERR_MODULE_NOT_FOUND' &&
|
|
93
|
+
error.message?.includes(`Cannot find module '$app`)
|
|
94
|
+
) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Cannot import \`$app/*\` modules other than \`$app/env\` inside \`src/env\``,
|
|
97
|
+
{ cause: e }
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
throw error;
|
|
102
|
+
} finally {
|
|
103
|
+
await server.close();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return variables;
|
|
107
|
+
}
|
|
108
|
+
|
|
9
109
|
/**
|
|
10
110
|
* @param {string} id
|
|
11
111
|
* @param {Record<string, string>} env
|
|
112
|
+
* @param {boolean} disabled
|
|
12
113
|
* @returns {string}
|
|
13
114
|
*/
|
|
14
|
-
export function create_static_module(id, env) {
|
|
115
|
+
export function create_static_module(id, env, disabled) {
|
|
15
116
|
/** @type {string[]} */
|
|
16
|
-
const
|
|
117
|
+
const statements = [];
|
|
118
|
+
|
|
119
|
+
if (disabled) {
|
|
120
|
+
statements.push(
|
|
121
|
+
`throw new Error('Cannot import \`${id}\` when \`experimental.explicitEnvironmentVariables\` is enabled. Use \`${id.replace('$env/static', '$app/env')}\` instead.');`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
17
124
|
|
|
18
125
|
for (const key in env) {
|
|
19
126
|
if (!valid_identifier.test(key) || reserved.has(key)) {
|
|
@@ -23,24 +130,199 @@ export function create_static_module(id, env) {
|
|
|
23
130
|
const comment = `/** @type {import('${id}').${key}} */`;
|
|
24
131
|
const declaration = `export const ${key} = ${JSON.stringify(env[key])};`;
|
|
25
132
|
|
|
26
|
-
|
|
133
|
+
statements.push(`${comment}\n${declaration}`);
|
|
27
134
|
}
|
|
28
135
|
|
|
29
|
-
return GENERATED_COMMENT +
|
|
136
|
+
return GENERATED_COMMENT + statements.join('\n\n');
|
|
30
137
|
}
|
|
31
138
|
|
|
32
139
|
/**
|
|
33
140
|
* @param {EnvType} type
|
|
34
141
|
* @param {Record<string, string> | undefined} dev_values If in a development mode, values to pre-populate the module with.
|
|
142
|
+
* @param {boolean} disabled
|
|
35
143
|
*/
|
|
36
|
-
export function create_dynamic_module(type, dev_values) {
|
|
144
|
+
export function create_dynamic_module(type, dev_values, disabled) {
|
|
145
|
+
const prelude = disabled
|
|
146
|
+
? `throw new Error('Cannot import \`$env/dynamic/${type}\` when \`experimental.explicitEnvironmentVariables\` is enabled. Use \`$app/env/${type}\` instead.');\n\n`
|
|
147
|
+
: '';
|
|
148
|
+
|
|
37
149
|
if (dev_values) {
|
|
38
150
|
const keys = Object.entries(dev_values).map(
|
|
39
151
|
([k, v]) => `${JSON.stringify(k)}: ${JSON.stringify(v)}`
|
|
40
152
|
);
|
|
41
|
-
return
|
|
153
|
+
return `${prelude}export const env = {\n${keys.join(',\n')}\n}`;
|
|
154
|
+
}
|
|
155
|
+
return `${prelude}export { ${type}_env as env } from '${runtime_base}/shared-server.js';`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Creates the `__sveltekit/env` module
|
|
160
|
+
* @param {Record<string, EnvVarConfig<any>> | null} variables
|
|
161
|
+
* @param {Record<string, string>} env
|
|
162
|
+
* @param {string | null} entry
|
|
163
|
+
*/
|
|
164
|
+
export function create_sveltekit_env(variables, env, entry) {
|
|
165
|
+
const imports = entry
|
|
166
|
+
? [
|
|
167
|
+
`import { variables } from ${JSON.stringify(entry)};`,
|
|
168
|
+
`import { validate, handle_issues } from '@sveltejs/kit/internal/env';`
|
|
169
|
+
]
|
|
170
|
+
: [`const variables = {};`, `const handle_issues = () => {};`];
|
|
171
|
+
|
|
172
|
+
const declarations = [];
|
|
173
|
+
const setters = [];
|
|
174
|
+
|
|
175
|
+
/** @type {Record<string, StandardSchemaV1.Issue[]>} */
|
|
176
|
+
const issues = {};
|
|
177
|
+
|
|
178
|
+
for (const [name, config] of Object.entries(variables ?? {})) {
|
|
179
|
+
if (config.static) {
|
|
180
|
+
if (config.public) {
|
|
181
|
+
const value = validate(variables ?? {}, env[name], name, issues);
|
|
182
|
+
declarations.push(`explicit_public_env.${name} = ${devalue.uneval(value)};`);
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
setters.push(
|
|
186
|
+
`const ${name} = validate(variables, env.${name}, ${JSON.stringify(name)}, issues);`
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (config.public) {
|
|
190
|
+
setters.push(`explicit_public_env.${name} = ${name};`);
|
|
191
|
+
setters.push(`rendered_env.${name} = ${name};`);
|
|
192
|
+
} else {
|
|
193
|
+
setters.push(`dynamic_private_env.${name} = ${name};`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
handle_issues(issues);
|
|
199
|
+
|
|
200
|
+
const blocks = [
|
|
201
|
+
GENERATED_COMMENT,
|
|
202
|
+
imports.join('\n'),
|
|
203
|
+
`const issues = {};`,
|
|
204
|
+
'export { variables }',
|
|
205
|
+
'export const dynamic_private_env = {};',
|
|
206
|
+
'export const explicit_public_env = {};',
|
|
207
|
+
'export const rendered_env = {};',
|
|
208
|
+
...declarations,
|
|
209
|
+
`handle_issues(issues);`,
|
|
210
|
+
dedent`
|
|
211
|
+
export function set_env(env) {
|
|
212
|
+
const issues = {};
|
|
213
|
+
${setters.join('\n')}
|
|
214
|
+
handle_issues(issues);
|
|
215
|
+
}`
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
const module = blocks.join('\n\n');
|
|
219
|
+
|
|
220
|
+
return module;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Creates the `__sveltekit/env/private` module
|
|
225
|
+
* @param {Record<string, EnvVarConfig<any>> | null} variables
|
|
226
|
+
* @param {Record<string, string>} env
|
|
227
|
+
*/
|
|
228
|
+
export function create_sveltekit_env_private(variables, env) {
|
|
229
|
+
if (!variables) {
|
|
230
|
+
return '';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** @type {Record<string, StandardSchemaV1.Issue[]>} */
|
|
234
|
+
const issues = {};
|
|
235
|
+
|
|
236
|
+
/** @type {string[]} */
|
|
237
|
+
const exports = [];
|
|
238
|
+
|
|
239
|
+
for (const [name, config] of Object.entries(variables)) {
|
|
240
|
+
if (config.public) continue;
|
|
241
|
+
|
|
242
|
+
const value = config.static
|
|
243
|
+
? devalue.uneval(validate(variables, env[name], name, issues))
|
|
244
|
+
: `env.${name}`;
|
|
245
|
+
|
|
246
|
+
exports.push(`export const ${name} = ${value};\n`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
handle_issues(issues);
|
|
250
|
+
|
|
251
|
+
return `import { dynamic_private_env as env } from '__sveltekit/env';\n\n${exports.join('')}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Creates the `__sveltekit/env/public/*` modules
|
|
256
|
+
* @param {Record<string, EnvVarConfig<any>> | null} variables
|
|
257
|
+
* @param {Record<string, string>} env
|
|
258
|
+
* @param {string} prelude
|
|
259
|
+
*/
|
|
260
|
+
export function create_sveltekit_env_public(variables, env, prelude) {
|
|
261
|
+
if (!variables) {
|
|
262
|
+
return '';
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** @type {Record<string, StandardSchemaV1.Issue[]>} */
|
|
266
|
+
const issues = {};
|
|
267
|
+
|
|
268
|
+
/** @type {string[]} */
|
|
269
|
+
const exports = [];
|
|
270
|
+
|
|
271
|
+
for (const [name, config] of Object.entries(variables)) {
|
|
272
|
+
if (!config.public) continue;
|
|
273
|
+
|
|
274
|
+
const value = config.static
|
|
275
|
+
? devalue.uneval(validate(variables, env[name], name, issues))
|
|
276
|
+
: `env.${name}`;
|
|
277
|
+
|
|
278
|
+
exports.push(`export const ${name} = ${value};\n`);
|
|
42
279
|
}
|
|
43
|
-
|
|
280
|
+
|
|
281
|
+
handle_issues(issues);
|
|
282
|
+
|
|
283
|
+
return `${prelude}\n\n${exports.join('')}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Creates the `__sveltekit/env/service-worker` module used in development
|
|
288
|
+
* (but not in prod, which goes through build_service_worker instead)
|
|
289
|
+
* @param {Record<string, EnvVarConfig<any>> | null} variables
|
|
290
|
+
* @param {Record<string, string>} env
|
|
291
|
+
* @param {string} global
|
|
292
|
+
*/
|
|
293
|
+
export function create_sveltekit_env_service_worker_dev(variables, env, global) {
|
|
294
|
+
/** @type {string[]} */
|
|
295
|
+
const properties = [];
|
|
296
|
+
|
|
297
|
+
/** @type {Record<string, StandardSchemaV1.Issue[]>} */
|
|
298
|
+
const issues = {};
|
|
299
|
+
|
|
300
|
+
for (const [name, config] of Object.entries(variables ?? {})) {
|
|
301
|
+
if (!config.public) continue;
|
|
302
|
+
|
|
303
|
+
const value = validate(variables ?? {}, env[name], name, issues);
|
|
304
|
+
properties.push(`${name}: ${devalue.uneval(value)}`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
handle_issues(issues);
|
|
308
|
+
|
|
309
|
+
return dedent`
|
|
310
|
+
globalThis.__SVELTEKIT_EXPERIMENTAL_EXPLICIT_ENVIRONMENT_VARIABLES__ = true;
|
|
311
|
+
|
|
312
|
+
${global} = {
|
|
313
|
+
env: {
|
|
314
|
+
${properties.join(',\n\t\t') || '// empty'}
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** @param {string} description */
|
|
321
|
+
function create_jsdoc(description) {
|
|
322
|
+
return `/**\n${description
|
|
323
|
+
.split('\n')
|
|
324
|
+
.map((line) => ` * ${line.replaceAll('*/', '*\\/')}`)
|
|
325
|
+
.join('\n')}\n */`;
|
|
44
326
|
}
|
|
45
327
|
|
|
46
328
|
/**
|
|
@@ -98,6 +380,29 @@ export function create_dynamic_types(id, env, { public_prefix, private_prefix })
|
|
|
98
380
|
`;
|
|
99
381
|
}
|
|
100
382
|
|
|
383
|
+
/**
|
|
384
|
+
* @param {Record<string, EnvVarConfig<any>>} variables
|
|
385
|
+
* @param {string} relative
|
|
386
|
+
* @param {EnvType} type
|
|
387
|
+
*/
|
|
388
|
+
export function create_explicit_env_types(variables, relative, type) {
|
|
389
|
+
const declarations = Object.entries(variables)
|
|
390
|
+
.filter(([_, config]) => !!config.public === (type === 'public'))
|
|
391
|
+
.map(([name, config]) => {
|
|
392
|
+
const comment = config.description ? `${create_jsdoc(config.description)}\n` : '';
|
|
393
|
+
const type = config.schema
|
|
394
|
+
? `import('@sveltejs/kit/internal/types').StandardSchemaV1.InferOutput<typeof import('${relative}').variables.${name}.schema>`
|
|
395
|
+
: 'string';
|
|
396
|
+
return `${comment}export const ${name}: ${type};`;
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
return dedent`
|
|
400
|
+
declare module '$app/env/${type}' {
|
|
401
|
+
${declarations.join('\n') || `// no ${type} environment variables were defined`}
|
|
402
|
+
}
|
|
403
|
+
`;
|
|
404
|
+
}
|
|
405
|
+
|
|
101
406
|
export const reserved = new Set([
|
|
102
407
|
'do',
|
|
103
408
|
'if',
|
|
@@ -50,7 +50,7 @@ async function analyse({
|
|
|
50
50
|
|
|
51
51
|
installPolyfills();
|
|
52
52
|
|
|
53
|
-
// configure `import { building } from '$app/environment'` —
|
|
53
|
+
// configure `import { building } from '$app/environment'` and `$app/env` —
|
|
54
54
|
// essential we do this before analysing the code
|
|
55
55
|
internal.set_building();
|
|
56
56
|
|
|
@@ -60,6 +60,7 @@ async function analyse({
|
|
|
60
60
|
const public_env = filter_env(env, public_prefix, private_prefix);
|
|
61
61
|
internal.set_private_env(private_env);
|
|
62
62
|
internal.set_public_env(public_env);
|
|
63
|
+
internal.set_env(env);
|
|
63
64
|
internal.set_manifest(manifest);
|
|
64
65
|
internal.set_read_implementation((file) => createReadableStream(`${server_root}/server/${file}`));
|
|
65
66
|
|
|
@@ -2,7 +2,6 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { installPolyfills } from '../../exports/node/polyfills.js';
|
|
5
|
-
import { load_config } from '../config/index.js';
|
|
6
5
|
import { forked } from '../../utils/fork.js';
|
|
7
6
|
|
|
8
7
|
export default forked(import.meta.url, generate_fallback);
|
|
@@ -11,15 +10,15 @@ export default forked(import.meta.url, generate_fallback);
|
|
|
11
10
|
* @param {{
|
|
12
11
|
* manifest_path: string;
|
|
13
12
|
* env: Record<string, string>
|
|
13
|
+
* out_dir: string;
|
|
14
|
+
* origin: string;
|
|
15
|
+
* assets: string;
|
|
14
16
|
* }} opts
|
|
15
17
|
*/
|
|
16
|
-
async function generate_fallback({ manifest_path, env }) {
|
|
17
|
-
/** @type {import('types').ValidatedKitConfig} */
|
|
18
|
-
const config = (await load_config()).kit;
|
|
19
|
-
|
|
18
|
+
async function generate_fallback({ manifest_path, env, out_dir, origin, assets }) {
|
|
20
19
|
installPolyfills();
|
|
21
20
|
|
|
22
|
-
const server_root = join(
|
|
21
|
+
const server_root = join(out_dir, 'output');
|
|
23
22
|
|
|
24
23
|
/** @type {import('types').ServerInternalModule} */
|
|
25
24
|
const { set_building } = await import(pathToFileURL(`${server_root}/server/internal.js`).href);
|
|
@@ -35,7 +34,7 @@ async function generate_fallback({ manifest_path, env }) {
|
|
|
35
34
|
const server = new Server(manifest);
|
|
36
35
|
await server.init({ env });
|
|
37
36
|
|
|
38
|
-
const response = await server.respond(new Request(
|
|
37
|
+
const response = await server.respond(new Request(origin + '/[fallback]'), {
|
|
39
38
|
getClientAddress: () => {
|
|
40
39
|
throw new Error('Cannot read clientAddress during prerendering');
|
|
41
40
|
},
|
|
@@ -44,7 +43,7 @@ async function generate_fallback({ manifest_path, env }) {
|
|
|
44
43
|
dependencies: new Map(),
|
|
45
44
|
remote_responses: new Map()
|
|
46
45
|
},
|
|
47
|
-
read: (file) => readFileSync(join(
|
|
46
|
+
read: (file) => readFileSync(join(assets, file))
|
|
48
47
|
});
|
|
49
48
|
|
|
50
49
|
if (response.ok) {
|
|
@@ -46,7 +46,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
46
46
|
/** @type {import('types').ServerModule} */
|
|
47
47
|
const { Server } = await import(pathToFileURL(`${out}/server/index.js`).href);
|
|
48
48
|
|
|
49
|
-
// configure `import { building } from '$app/environment'` —
|
|
49
|
+
// configure `import { building } from '$app/environment'` and `$app/env` —
|
|
50
50
|
// essential we do this before analysing the code
|
|
51
51
|
internal.set_building();
|
|
52
52
|
internal.set_prerendering();
|
|
@@ -106,7 +106,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
106
106
|
if (hash) {
|
|
107
107
|
const fallback = await generate_fallback({
|
|
108
108
|
manifest_path,
|
|
109
|
-
env
|
|
109
|
+
env,
|
|
110
|
+
out_dir: config.outDir,
|
|
111
|
+
origin: config.prerender.origin,
|
|
112
|
+
assets: config.files.assets
|
|
110
113
|
});
|
|
111
114
|
|
|
112
115
|
const file = output_filename('/', true);
|
|
@@ -494,6 +497,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
494
497
|
const public_env = filter_env(env, public_prefix, private_prefix);
|
|
495
498
|
internal.set_private_env(private_env);
|
|
496
499
|
internal.set_public_env(public_env);
|
|
500
|
+
internal.set_env(env);
|
|
497
501
|
internal.set_manifest(manifest);
|
|
498
502
|
internal.set_read_implementation((file) => createReadableStream(`${out}/server/${file}`));
|
|
499
503
|
|
package/src/core/sync/sync.js
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
create_node_analyser,
|
|
12
12
|
get_page_options
|
|
13
13
|
} from '../../exports/vite/static_analysis/index.js';
|
|
14
|
+
import { load_explicit_env } from '../env.js';
|
|
15
|
+
import { write_env } from './write_env.js';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Initialize SvelteKit's generated files that only depend on the config and mode.
|
|
@@ -87,6 +89,20 @@ export function all_types(config, mode) {
|
|
|
87
89
|
write_non_ambient(config.kit, manifest_data);
|
|
88
90
|
}
|
|
89
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Generate modules and types for explicit env vars
|
|
94
|
+
* @param {import('types').ValidatedKitConfig} kit
|
|
95
|
+
* @param {string | null} entry
|
|
96
|
+
* @param {string} mode The Vite mode
|
|
97
|
+
*/
|
|
98
|
+
export async function env(kit, entry, mode) {
|
|
99
|
+
const env_config = await load_explicit_env(kit, entry, mode);
|
|
100
|
+
|
|
101
|
+
write_env(kit, entry, env_config);
|
|
102
|
+
|
|
103
|
+
return env_config;
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
/**
|
|
91
107
|
* Regenerate __SERVER__/internal.js in response to src/{app.html,error.html,service-worker.js} changing
|
|
92
108
|
* @param {import('types').ValidatedConfig} config
|
|
@@ -53,11 +53,17 @@ ${create_dynamic_types('public', env, prefixes)}
|
|
|
53
53
|
* @param {string} mode The Vite mode
|
|
54
54
|
*/
|
|
55
55
|
export function write_ambient(config, mode) {
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
/** @type {string} */
|
|
57
|
+
let content;
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
if (config.experimental.explicitEnvironmentVariables) {
|
|
60
|
+
content = `${GENERATED_COMMENT}\n/// <reference types="@sveltejs/kit" />`;
|
|
61
|
+
} else {
|
|
62
|
+
const env = get_env(config.env, mode);
|
|
63
|
+
const { publicPrefix: public_prefix, privatePrefix: private_prefix } = config.env;
|
|
64
|
+
|
|
65
|
+
content = template(env, { public_prefix, private_prefix });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
write_if_changed(path.join(config.outDir, 'ambient.d.ts'), content);
|
|
63
69
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** @import { EnvVarConfig } from '@sveltejs/kit' */
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { create_explicit_env_types } from '../env.js';
|
|
4
|
+
import { write_if_changed } from './utils.js';
|
|
5
|
+
|
|
6
|
+
const DOCS = '// See https://svelte.dev/docs/kit/environment-variables for more information';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Writes ambient declarations including types reference to @sveltejs/kit,
|
|
10
|
+
* and the existing environment variables in process.env to
|
|
11
|
+
* $env/static/private and $env/static/public
|
|
12
|
+
* @param {import('types').ValidatedKitConfig} kit
|
|
13
|
+
* @param {string | null} entry
|
|
14
|
+
* @param {Record<string, EnvVarConfig<any>> | null} env_config
|
|
15
|
+
*/
|
|
16
|
+
export function write_env(kit, entry, env_config) {
|
|
17
|
+
const content = [];
|
|
18
|
+
const out = path.join(kit.outDir, 'env.d.ts');
|
|
19
|
+
|
|
20
|
+
if (entry && env_config) {
|
|
21
|
+
const relative = path.relative(kit.outDir, entry);
|
|
22
|
+
content.push(
|
|
23
|
+
`// This file is generated from ${relative}.\n${DOCS}`,
|
|
24
|
+
create_explicit_env_types(env_config, relative, 'private'),
|
|
25
|
+
create_explicit_env_types(env_config, relative, 'public')
|
|
26
|
+
);
|
|
27
|
+
} else {
|
|
28
|
+
content.push(DOCS);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
write_if_changed(out, content.join('\n\n'));
|
|
32
|
+
}
|
|
@@ -100,7 +100,7 @@ export function write_root(manifest_data, config, output) {
|
|
|
100
100
|
${isSvelte5Plus() ? '<svelte:options runes={true} />' : ''}
|
|
101
101
|
<script>
|
|
102
102
|
import { setContext, ${isSvelte5Plus() ? '' : 'afterUpdate, '}onMount, tick } from 'svelte';
|
|
103
|
-
import { browser } from '$app/
|
|
103
|
+
import { browser } from '$app/env';
|
|
104
104
|
|
|
105
105
|
// stores
|
|
106
106
|
${
|
|
@@ -30,9 +30,10 @@ const server_template = ({
|
|
|
30
30
|
error_page
|
|
31
31
|
}) => `
|
|
32
32
|
import root from '../root.${isSvelte5Plus() ? 'js' : 'svelte'}';
|
|
33
|
-
import { set_building, set_prerendering } from '
|
|
33
|
+
import { set_building, set_prerendering } from '$app/env/internal';
|
|
34
34
|
import { set_assets } from '$app/paths/internal/server';
|
|
35
35
|
import { set_manifest, set_read_implementation } from '__sveltekit/server';
|
|
36
|
+
import { set_env } from '__sveltekit/env';
|
|
36
37
|
import { set_private_env, set_public_env } from '${runtime_directory}/shared-server.js';
|
|
37
38
|
|
|
38
39
|
export const options = {
|
|
@@ -92,7 +93,7 @@ export async function get_hooks() {
|
|
|
92
93
|
};
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
export { set_assets, set_building, set_manifest, set_prerendering, set_private_env, set_public_env, set_read_implementation };
|
|
96
|
+
export { set_assets, set_building, set_env, set_manifest, set_prerendering, set_private_env, set_public_env, set_read_implementation };
|
|
96
97
|
`;
|
|
97
98
|
|
|
98
99
|
// TODO need to re-run this whenever src/app.html or src/error.html are
|
|
@@ -57,6 +57,7 @@ export function get_tsconfig(kit) {
|
|
|
57
57
|
|
|
58
58
|
const include = new Set([
|
|
59
59
|
'ambient.d.ts', // careful: changing this name would be a breaking change, because it's referenced in the service-workers documentation
|
|
60
|
+
'env.d.ts',
|
|
60
61
|
'non-ambient.d.ts',
|
|
61
62
|
'./types/**/$types.d.ts',
|
|
62
63
|
config_relative('vite.config.js'),
|
|
@@ -1 +1,14 @@
|
|
|
1
|
+
/** @import { EnvVarConfig } from '@sveltejs/kit' */
|
|
2
|
+
|
|
1
3
|
export { sequence } from './sequence.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Utility for defining [environment variables](https://svelte.dev/docs/kit/environment-variables),
|
|
7
|
+
* which are made available via `$app/env/public` and `$app/env/private`.
|
|
8
|
+
* @template {Record<string, EnvVarConfig<any>>} T
|
|
9
|
+
* @param {T} variables
|
|
10
|
+
* @returns {T}
|
|
11
|
+
*/
|
|
12
|
+
export function defineEnvVars(variables) {
|
|
13
|
+
return variables;
|
|
14
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
2
|
+
/** @import { EnvVarConfig } from '@sveltejs/kit' */
|
|
3
|
+
|
|
4
|
+
import { stackless } from '../vite/utils.js';
|
|
5
|
+
|
|
6
|
+
const MISSING = {
|
|
7
|
+
message: `Value is missing. If it is optional, add a Standard Schema validator declaring it as such.`
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const BAD_VALIDATOR = {
|
|
11
|
+
message: 'Variable was configured with a validator that does not implement Standard Schema'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const ASYNC_VALIDATOR = {
|
|
15
|
+
message: 'Variable uses an async validator, which is not supported'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {Record<string, EnvVarConfig<any>>} variables
|
|
20
|
+
* @param {string | undefined} value
|
|
21
|
+
* @param {string} name
|
|
22
|
+
* @param {Record<string, StandardSchemaV1.Issue[]>} issues
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
export function validate(variables, value, name, issues) {
|
|
26
|
+
const config = variables[name] ?? {};
|
|
27
|
+
const validator = config.schema;
|
|
28
|
+
|
|
29
|
+
if (!validator) {
|
|
30
|
+
if (!value) issues[name] = [MISSING];
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!validator['~standard']) {
|
|
35
|
+
issues[name] = [BAD_VALIDATOR];
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const result = validator['~standard'].validate(value);
|
|
40
|
+
|
|
41
|
+
if (result instanceof Promise) {
|
|
42
|
+
issues[name] = [ASYNC_VALIDATOR];
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (result.issues) {
|
|
47
|
+
issues[name] = [...result.issues];
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result.value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {Record<string, StandardSchemaV1.Issue[]>} issues
|
|
56
|
+
*/
|
|
57
|
+
export function handle_issues(issues) {
|
|
58
|
+
const entries = Object.entries(issues);
|
|
59
|
+
|
|
60
|
+
if (entries.length === 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let message = 'Invalid environment variables\n';
|
|
65
|
+
|
|
66
|
+
for (const [name, issues] of entries) {
|
|
67
|
+
message += `\n${name}\n${issues.map((issue) => ` - ${issue.message}`).join('\n')}\n`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
throw stackless(message);
|
|
71
|
+
}
|