@sveltejs/kit 2.50.1 → 2.51.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 +4 -4
- package/src/core/postbuild/crawl.js +3 -3
- package/src/core/sync/write_tsconfig.js +7 -5
- package/src/exports/public.d.ts +14 -1
- package/src/exports/vite/build/build_server.js +116 -80
- package/src/exports/vite/index.js +4 -6
- package/src/exports/vite/static_analysis/utils.js +17 -0
- package/src/runtime/app/environment/index.js +1 -5
- package/src/runtime/app/server/remote/command.js +3 -1
- package/src/runtime/app/server/remote/form.js +1 -2
- package/src/runtime/app/server/remote/prerender.js +1 -1
- package/src/runtime/app/server/remote/query.js +39 -18
- package/src/runtime/app/server/remote/shared.js +4 -5
- package/src/runtime/client/client.js +22 -19
- package/src/runtime/server/fetch.js +6 -2
- package/src/runtime/server/page/csp.js +66 -28
- package/src/runtime/server/page/index.js +7 -2
- package/src/runtime/server/page/render.js +112 -44
- package/src/runtime/server/remote.js +4 -15
- package/src/types/internal.d.ts +13 -7
- package/src/utils/css.js +210 -0
- package/src/utils/routing.js +6 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +22 -3
- package/types/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/kit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.51.0",
|
|
4
4
|
"description": "SvelteKit is the fastest way to build Svelte apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -29,19 +29,19 @@
|
|
|
29
29
|
"magic-string": "^0.30.5",
|
|
30
30
|
"mrmime": "^2.0.0",
|
|
31
31
|
"sade": "^1.8.1",
|
|
32
|
-
"set-cookie-parser": "^
|
|
32
|
+
"set-cookie-parser": "^3.0.0",
|
|
33
33
|
"sirv": "^3.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@opentelemetry/api": "^1.0.0",
|
|
37
|
-
"@playwright/test": "1.
|
|
37
|
+
"@playwright/test": "1.58.2",
|
|
38
38
|
"@sveltejs/vite-plugin-svelte": "^6.0.0-next.3",
|
|
39
39
|
"@types/connect": "^3.4.38",
|
|
40
40
|
"@types/node": "^18.19.119",
|
|
41
41
|
"@types/set-cookie-parser": "^2.4.7",
|
|
42
42
|
"dts-buddy": "^0.6.2",
|
|
43
43
|
"rollup": "^4.14.2",
|
|
44
|
-
"svelte": "^5.
|
|
44
|
+
"svelte": "^5.48.4",
|
|
45
45
|
"svelte-preprocess": "^6.0.0",
|
|
46
46
|
"typescript": "^5.3.3",
|
|
47
47
|
"vite": "^6.3.5",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolve } from '../../utils/url.js';
|
|
1
|
+
import { resolve, decode_uri } from '../../utils/url.js';
|
|
2
2
|
import { decode } from './entities.js';
|
|
3
3
|
|
|
4
4
|
const DOCTYPE = 'DOCTYPE';
|
|
@@ -193,11 +193,11 @@ export function crawl(html, base) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
if (id) {
|
|
196
|
-
ids.push(id);
|
|
196
|
+
ids.push(decode_uri(id));
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
if (name && tag === 'A') {
|
|
200
|
-
ids.push(name);
|
|
200
|
+
ids.push(decode_uri(name));
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
if (src) {
|
|
@@ -62,10 +62,8 @@ export function get_tsconfig(kit) {
|
|
|
62
62
|
config_relative('vite.config.js'),
|
|
63
63
|
config_relative('vite.config.ts')
|
|
64
64
|
]);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const src_includes = [kit.files.routes, kit.files.lib, path.resolve('src')].filter((dir) => {
|
|
68
|
-
const relative = path.relative(path.resolve('src'), dir);
|
|
65
|
+
const src_includes = [kit.files.routes, kit.files.lib, kit.files.src].filter((dir) => {
|
|
66
|
+
const relative = path.relative(kit.files.src, dir);
|
|
69
67
|
return !relative || relative.startsWith('..');
|
|
70
68
|
});
|
|
71
69
|
for (const dir of src_includes) {
|
|
@@ -76,10 +74,14 @@ export function get_tsconfig(kit) {
|
|
|
76
74
|
|
|
77
75
|
// Test folder is a special case - we advocate putting tests in a top-level test folder
|
|
78
76
|
// and it's not configurable (should we make it?)
|
|
79
|
-
const test_folder = project_relative('
|
|
77
|
+
const test_folder = project_relative('test');
|
|
80
78
|
include.add(config_relative(`${test_folder}/**/*.js`));
|
|
81
79
|
include.add(config_relative(`${test_folder}/**/*.ts`));
|
|
82
80
|
include.add(config_relative(`${test_folder}/**/*.svelte`));
|
|
81
|
+
const tests_folder = project_relative('tests');
|
|
82
|
+
include.add(config_relative(`${tests_folder}/**/*.js`));
|
|
83
|
+
include.add(config_relative(`${tests_folder}/**/*.ts`));
|
|
84
|
+
include.add(config_relative(`${tests_folder}/**/*.svelte`));
|
|
83
85
|
|
|
84
86
|
const exclude = [config_relative('node_modules/**')];
|
|
85
87
|
// Add service worker to exclude list so that worker types references in it don't spill over into the rest of the app
|
package/src/exports/public.d.ts
CHANGED
|
@@ -1200,6 +1200,19 @@ export interface NavigationTarget<
|
|
|
1200
1200
|
* The URL that is navigated to
|
|
1201
1201
|
*/
|
|
1202
1202
|
url: URL;
|
|
1203
|
+
/**
|
|
1204
|
+
* The scroll position associated with this navigation.
|
|
1205
|
+
*
|
|
1206
|
+
* For the `from` target, this is the scroll position at the moment of navigation.
|
|
1207
|
+
*
|
|
1208
|
+
* For the `to` target, this represents the scroll position that will be or was restored:
|
|
1209
|
+
* - In `beforeNavigate` and `onNavigate`, this is only available for `popstate` navigations (back/forward button)
|
|
1210
|
+
* and will be `null` for other navigation types, since the final scroll position isn't known
|
|
1211
|
+
* ahead of time.
|
|
1212
|
+
* - In `afterNavigate`, this is always the scroll position that was applied after the navigation
|
|
1213
|
+
* completed.
|
|
1214
|
+
*/
|
|
1215
|
+
scroll: { x: number; y: number } | null;
|
|
1203
1216
|
}
|
|
1204
1217
|
|
|
1205
1218
|
/**
|
|
@@ -1249,7 +1262,7 @@ export interface NavigationEnter extends NavigationBase {
|
|
|
1249
1262
|
delta?: undefined;
|
|
1250
1263
|
|
|
1251
1264
|
/**
|
|
1252
|
-
* Dispatched `Event` object when navigation
|
|
1265
|
+
* Dispatched `Event` object when navigation occurred by `popstate` or `link`.
|
|
1253
1266
|
*/
|
|
1254
1267
|
event?: undefined;
|
|
1255
1268
|
}
|
|
@@ -5,14 +5,43 @@ import { s } from '../../../utils/misc.js';
|
|
|
5
5
|
import { normalizePath } from 'vite';
|
|
6
6
|
import { basename, join } from 'node:path';
|
|
7
7
|
import { create_node_analyser } from '../static_analysis/index.js';
|
|
8
|
+
import { fix_css_urls } from '../../../utils/css.js';
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Regenerate server nodes after acquiring client manifest
|
|
12
|
+
* @overload
|
|
13
|
+
* @param {string} out
|
|
14
|
+
* @param {import('types').ValidatedKitConfig} kit
|
|
15
|
+
* @param {import('types').ManifestData} manifest_data
|
|
16
|
+
* @param {import('vite').Manifest} server_manifest
|
|
17
|
+
* @param {import('vite').Manifest} client_manifest
|
|
18
|
+
* @param {string} assets_path
|
|
19
|
+
* @param {import('vite').Rollup.RollupOutput['output']} client_chunks
|
|
20
|
+
* @param {import('types').RecursiveRequired<import('types').ValidatedConfig['kit']['output']>} output_config
|
|
21
|
+
* @param {Map<string, { page_options: Record<string, any> | null, children: string[] }>} static_exports
|
|
22
|
+
* @returns {Promise<void>}
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Build server nodes without client manifest for analysis phase
|
|
26
|
+
* @overload
|
|
27
|
+
* @param {string} out
|
|
28
|
+
* @param {import('types').ValidatedKitConfig} kit
|
|
29
|
+
* @param {import('types').ManifestData} manifest_data
|
|
30
|
+
* @param {import('vite').Manifest} server_manifest
|
|
31
|
+
* @param {null} client_manifest
|
|
32
|
+
* @param {null} assets_path
|
|
33
|
+
* @param {null} client_chunks
|
|
34
|
+
* @param {import('types').RecursiveRequired<import('types').ValidatedConfig['kit']['output']>} output_config
|
|
35
|
+
* @param {Map<string, { page_options: Record<string, any> | null, children: string[] }>} static_exports
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
*/
|
|
9
38
|
/**
|
|
10
39
|
* @param {string} out
|
|
11
40
|
* @param {import('types').ValidatedKitConfig} kit
|
|
12
41
|
* @param {import('types').ManifestData} manifest_data
|
|
13
42
|
* @param {import('vite').Manifest} server_manifest
|
|
14
43
|
* @param {import('vite').Manifest | null} client_manifest
|
|
15
|
-
* @param {
|
|
44
|
+
* @param {string | null} assets_path
|
|
16
45
|
* @param {import('vite').Rollup.RollupOutput['output'] | null} client_chunks
|
|
17
46
|
* @param {import('types').RecursiveRequired<import('types').ValidatedConfig['kit']['output']>} output_config
|
|
18
47
|
* @param {Map<string, { page_options: Record<string, any> | null, children: string[] }>} static_exports
|
|
@@ -23,7 +52,7 @@ export async function build_server_nodes(
|
|
|
23
52
|
manifest_data,
|
|
24
53
|
server_manifest,
|
|
25
54
|
client_manifest,
|
|
26
|
-
|
|
55
|
+
assets_path,
|
|
27
56
|
client_chunks,
|
|
28
57
|
output_config,
|
|
29
58
|
static_exports
|
|
@@ -31,38 +60,59 @@ export async function build_server_nodes(
|
|
|
31
60
|
mkdirp(`${out}/server/nodes`);
|
|
32
61
|
mkdirp(`${out}/server/stylesheets`);
|
|
33
62
|
|
|
34
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Stylesheet names and their contents which are below the inline threshold
|
|
65
|
+
* @type {Map<string, string>}
|
|
66
|
+
*/
|
|
35
67
|
const stylesheets_to_inline = new Map();
|
|
36
68
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
69
|
+
/**
|
|
70
|
+
* For CSS inlining, we either store a string or a function that returns the
|
|
71
|
+
* styles with the correct relative URLs
|
|
72
|
+
* @type {(css: string, eager_assets: Set<string>) => string}
|
|
73
|
+
*/
|
|
74
|
+
let prepare_css_for_inlining = (css) => s(css);
|
|
40
75
|
|
|
41
|
-
|
|
42
|
-
for (const
|
|
43
|
-
|
|
44
|
-
if (!server_stylesheet) {
|
|
76
|
+
if (client_chunks && kit.inlineStyleThreshold > 0 && output_config.bundleStrategy === 'split') {
|
|
77
|
+
for (const chunk of client_chunks) {
|
|
78
|
+
if (chunk.type !== 'asset' || !chunk.fileName.endsWith('.css')) {
|
|
45
79
|
continue;
|
|
46
80
|
}
|
|
47
|
-
client_stylesheet.forEach((file, i) => {
|
|
48
|
-
stylesheets_to_inline.set(file, server_stylesheet[i]);
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
81
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
stylesheets_to_inline.delete(fileName);
|
|
82
|
+
const source = chunk.source.toString();
|
|
83
|
+
if (source.length < kit.inlineStyleThreshold) {
|
|
84
|
+
stylesheets_to_inline.set(chunk.fileName, source);
|
|
56
85
|
}
|
|
57
86
|
}
|
|
58
87
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
88
|
+
// If the client CSS has URL references to assets, we need to adjust the
|
|
89
|
+
// relative path so that they are correct when inlined into the document.
|
|
90
|
+
// Although `paths.assets` is static, we need to pass in a fake path
|
|
91
|
+
// `/_svelte_kit_assets` at runtime when running `vite preview`
|
|
92
|
+
if (kit.paths.assets || kit.paths.relative) {
|
|
93
|
+
const static_assets = new Set(
|
|
94
|
+
manifest_data.assets.map((asset) => decodeURIComponent(asset.file))
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const segments = /** @type {string} */ (assets_path).split('/');
|
|
98
|
+
const static_asset_prefix = segments.map(() => '..').join('/') + '/';
|
|
99
|
+
|
|
100
|
+
prepare_css_for_inlining = (css, eager_assets) => {
|
|
101
|
+
const transformed_css = fix_css_urls({
|
|
102
|
+
css,
|
|
103
|
+
vite_assets: eager_assets,
|
|
104
|
+
static_assets,
|
|
105
|
+
paths_assets: '${assets}',
|
|
106
|
+
base: '${base}',
|
|
107
|
+
static_asset_prefix
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// only convert to a function if we have adjusted any URLs
|
|
111
|
+
if (css !== transformed_css) {
|
|
112
|
+
return `function css(assets, base) { return \`${s(transformed_css).slice(1, -1)}\`; }`;
|
|
113
|
+
}
|
|
114
|
+
return s(css);
|
|
115
|
+
};
|
|
66
116
|
}
|
|
67
117
|
}
|
|
68
118
|
|
|
@@ -96,6 +146,9 @@ export async function build_server_nodes(
|
|
|
96
146
|
/** @type {string[]} */
|
|
97
147
|
let fonts = [];
|
|
98
148
|
|
|
149
|
+
/** @type {Set<string>} */
|
|
150
|
+
let eager_assets = new Set();
|
|
151
|
+
|
|
99
152
|
if (node.component && client_manifest) {
|
|
100
153
|
exports.push(
|
|
101
154
|
'let component_cache;',
|
|
@@ -135,7 +188,7 @@ export async function build_server_nodes(
|
|
|
135
188
|
const entry_path = `${normalizePath(kit.outDir)}/generated/client-optimized/nodes/${i}.js`;
|
|
136
189
|
const entry = find_deps(client_manifest, entry_path, true);
|
|
137
190
|
|
|
138
|
-
//
|
|
191
|
+
// Eagerly load client stylesheets and fonts imported by the SSR-ed page to avoid FOUC.
|
|
139
192
|
// However, if it is not used during SSR (not present in the server manifest),
|
|
140
193
|
// then it can be lazily loaded in the browser.
|
|
141
194
|
|
|
@@ -153,8 +206,6 @@ export async function build_server_nodes(
|
|
|
153
206
|
|
|
154
207
|
/** @type {Set<string>} */
|
|
155
208
|
const eager_css = new Set();
|
|
156
|
-
/** @type {Set<string>} */
|
|
157
|
-
const eager_assets = new Set();
|
|
158
209
|
|
|
159
210
|
entry.stylesheet_map.forEach((value, filepath) => {
|
|
160
211
|
// pages and layouts are renamed to node indexes when optimised for the client
|
|
@@ -180,27 +231,46 @@ export async function build_server_nodes(
|
|
|
180
231
|
`export const fonts = ${s(fonts)};`
|
|
181
232
|
);
|
|
182
233
|
|
|
183
|
-
/**
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Assets that have been processed by Vite (decoded and with the asset path stripped)
|
|
236
|
+
* @type {Set<string>}
|
|
237
|
+
*/
|
|
238
|
+
let vite_assets = new Set();
|
|
239
|
+
|
|
240
|
+
// Keep track of Vite asset filenames so that we avoid touching unrelated ones
|
|
241
|
+
// when adjusting the inlined CSS
|
|
242
|
+
if (stylesheets_to_inline.size && assets_path && eager_assets.size) {
|
|
243
|
+
vite_assets = new Set(
|
|
244
|
+
Array.from(eager_assets).map((asset) => {
|
|
245
|
+
return decodeURIComponent(asset.replace(`${assets_path}/`, ''));
|
|
246
|
+
})
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (stylesheets_to_inline.size) {
|
|
251
|
+
/** @type {string[]} */
|
|
252
|
+
const inline_styles = [];
|
|
253
|
+
|
|
254
|
+
stylesheets.forEach((file, i) => {
|
|
255
|
+
if (stylesheets_to_inline.has(file)) {
|
|
256
|
+
const filename = basename(file);
|
|
257
|
+
const dest = `${out}/server/stylesheets/${filename}.js`;
|
|
258
|
+
|
|
259
|
+
let css = /** @type {string} */ (stylesheets_to_inline.get(file));
|
|
260
|
+
|
|
261
|
+
fs.writeFileSync(
|
|
262
|
+
dest,
|
|
263
|
+
`// ${filename}\nexport default ${prepare_css_for_inlining(css, vite_assets)};`
|
|
264
|
+
);
|
|
265
|
+
const name = `stylesheet_${i}`;
|
|
266
|
+
imports.push(`import ${name} from '../stylesheets/${filename}.js';`);
|
|
267
|
+
inline_styles.push(`\t${s(file)}: ${name}`);
|
|
193
268
|
}
|
|
194
|
-
|
|
269
|
+
});
|
|
195
270
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
inline_styles.push(`\t${s(file)}: ${name}`);
|
|
271
|
+
if (inline_styles.length > 0) {
|
|
272
|
+
exports.push(`export const inline_styles = () => ({\n${inline_styles.join(',\n')}\n});`);
|
|
199
273
|
}
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
if (inline_styles.length > 0) {
|
|
203
|
-
exports.push(`export const inline_styles = () => ({\n${inline_styles.join(',\n')}\n});`);
|
|
204
274
|
}
|
|
205
275
|
|
|
206
276
|
fs.writeFileSync(
|
|
@@ -209,37 +279,3 @@ export async function build_server_nodes(
|
|
|
209
279
|
);
|
|
210
280
|
}
|
|
211
281
|
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* @param {(import('vite').Rollup.OutputAsset | import('vite').Rollup.OutputChunk)[]} chunks
|
|
215
|
-
*/
|
|
216
|
-
function get_stylesheets(chunks) {
|
|
217
|
-
/**
|
|
218
|
-
* A map of module IDs and the stylesheets they use.
|
|
219
|
-
* @type {Map<string, string[]>}
|
|
220
|
-
*/
|
|
221
|
-
const stylesheets_used = new Map();
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* A map of stylesheet names and their content.
|
|
225
|
-
* @type {Map<string, string>}
|
|
226
|
-
*/
|
|
227
|
-
const stylesheet_content = new Map();
|
|
228
|
-
|
|
229
|
-
for (const chunk of chunks) {
|
|
230
|
-
if (chunk.type === 'asset') {
|
|
231
|
-
if (chunk.fileName.endsWith('.css')) {
|
|
232
|
-
stylesheet_content.set(chunk.fileName, chunk.source.toString());
|
|
233
|
-
}
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (chunk.viteMetadata?.importedCss.size) {
|
|
238
|
-
const css = Array.from(chunk.viteMetadata.importedCss);
|
|
239
|
-
for (const id of chunk.moduleIds) {
|
|
240
|
-
stylesheets_used.set(id, css);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return { stylesheets_used, stylesheet_content };
|
|
245
|
-
}
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
} from './module_ids.js';
|
|
41
41
|
import { import_peer } from '../../utils/import.js';
|
|
42
42
|
import { compact } from '../../utils/array.js';
|
|
43
|
-
import { should_ignore } from './static_analysis/utils.js';
|
|
43
|
+
import { should_ignore, has_children } from './static_analysis/utils.js';
|
|
44
44
|
|
|
45
45
|
const cwd = posixify(process.cwd());
|
|
46
46
|
|
|
@@ -112,10 +112,8 @@ const warning_preprocessor = {
|
|
|
112
112
|
if (!filename) return;
|
|
113
113
|
|
|
114
114
|
const basename = path.basename(filename);
|
|
115
|
-
const has_children =
|
|
116
|
-
content.includes('<slot') || (isSvelte5Plus() && content.includes('{@render'));
|
|
117
115
|
|
|
118
|
-
if (basename.startsWith('+layout.') && !has_children) {
|
|
116
|
+
if (basename.startsWith('+layout.') && !has_children(content, isSvelte5Plus())) {
|
|
119
117
|
const message =
|
|
120
118
|
`\n${colors.bold().red(path.relative('.', filename))}\n` +
|
|
121
119
|
`\`<slot />\`${isSvelte5Plus() ? ' or `{@render ...}` tag' : ''}` +
|
|
@@ -1031,7 +1029,7 @@ async function kit({ svelte_config }) {
|
|
|
1031
1029
|
*/
|
|
1032
1030
|
writeBundle: {
|
|
1033
1031
|
sequential: true,
|
|
1034
|
-
async handler(_options
|
|
1032
|
+
async handler(_options) {
|
|
1035
1033
|
if (secondary_build_started) return; // only run this once
|
|
1036
1034
|
|
|
1037
1035
|
const verbose = vite_config.logLevel === 'info';
|
|
@@ -1271,7 +1269,7 @@ async function kit({ svelte_config }) {
|
|
|
1271
1269
|
manifest_data,
|
|
1272
1270
|
server_manifest,
|
|
1273
1271
|
client_manifest,
|
|
1274
|
-
|
|
1272
|
+
assets_path,
|
|
1275
1273
|
client_chunks,
|
|
1276
1274
|
svelte_config.kit.output,
|
|
1277
1275
|
static_exports
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if content has children rendering (slot, @render, or children prop forwarding)
|
|
3
|
+
* @param {string} content - The markup content
|
|
4
|
+
* @param {boolean} is_svelte_5_plus - Whether the project uses Svelte 5+
|
|
5
|
+
* @returns {boolean}
|
|
6
|
+
*/
|
|
7
|
+
export function has_children(content, is_svelte_5_plus) {
|
|
8
|
+
return (
|
|
9
|
+
content.includes('<slot') ||
|
|
10
|
+
(is_svelte_5_plus &&
|
|
11
|
+
(content.includes('{@render') ||
|
|
12
|
+
// children may be forwarded to a child component as a prop
|
|
13
|
+
content.includes('{children}') ||
|
|
14
|
+
content.includes('children={')))
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
/**
|
|
2
19
|
* Check if a match position is within a comment or a string
|
|
3
20
|
* @param {string} content - The full content
|
|
@@ -78,7 +78,9 @@ export function command(validate_or_fn, maybe_fn) {
|
|
|
78
78
|
|
|
79
79
|
state.refreshes ??= {};
|
|
80
80
|
|
|
81
|
-
const promise = Promise.resolve(
|
|
81
|
+
const promise = Promise.resolve(
|
|
82
|
+
run_remote_function(event, state, true, () => validate(arg), fn)
|
|
83
|
+
);
|
|
82
84
|
|
|
83
85
|
// @ts-expect-error
|
|
84
86
|
promise.updates = () => {
|
|
@@ -131,7 +131,7 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
const promise = get_response(__, arg, state, () =>
|
|
134
|
-
run_remote_function(event, state, false,
|
|
134
|
+
run_remote_function(event, state, false, () => validate(arg), fn)
|
|
135
135
|
);
|
|
136
136
|
|
|
137
137
|
if (state.prerendering) {
|
|
@@ -5,6 +5,8 @@ import { get_request_store } from '@sveltejs/kit/internal/server';
|
|
|
5
5
|
import { create_remote_key, stringify_remote_arg } from '../../../shared.js';
|
|
6
6
|
import { prerendering } from '__sveltekit/environment';
|
|
7
7
|
import { create_validator, get_cache, get_response, run_remote_function } from './shared.js';
|
|
8
|
+
import { handle_error_and_jsonify } from '../../../server/utils.js';
|
|
9
|
+
import { HttpError, SvelteKitError } from '@sveltejs/kit/internal';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Creates a remote query. When called from the browser, the function will be invoked on the server via a `fetch` call.
|
|
@@ -73,7 +75,7 @@ export function query(validate_or_fn, maybe_fn) {
|
|
|
73
75
|
const { event, state } = get_request_store();
|
|
74
76
|
|
|
75
77
|
const get_remote_function_result = () =>
|
|
76
|
-
run_remote_function(event, state, false,
|
|
78
|
+
run_remote_function(event, state, false, () => validate(arg), fn);
|
|
77
79
|
|
|
78
80
|
/** @type {Promise<any> & Partial<RemoteQuery<any>>} */
|
|
79
81
|
const promise = get_response(__, arg, state, get_remote_function_result);
|
|
@@ -137,7 +139,7 @@ export function query(validate_or_fn, maybe_fn) {
|
|
|
137
139
|
*/
|
|
138
140
|
/*@__NO_SIDE_EFFECTS__*/
|
|
139
141
|
function batch(validate_or_fn, maybe_fn) {
|
|
140
|
-
/** @type {(args?: Input[]) => (arg: Input, idx: number) => Output} */
|
|
142
|
+
/** @type {(args?: Input[]) => MaybePromise<(arg: Input, idx: number) => Output>} */
|
|
141
143
|
const fn = maybe_fn ?? validate_or_fn;
|
|
142
144
|
|
|
143
145
|
/** @type {(arg?: any) => MaybePromise<Input>} */
|
|
@@ -148,16 +150,34 @@ function batch(validate_or_fn, maybe_fn) {
|
|
|
148
150
|
type: 'query_batch',
|
|
149
151
|
id: '',
|
|
150
152
|
name: '',
|
|
151
|
-
run: (args) => {
|
|
153
|
+
run: async (args, options) => {
|
|
152
154
|
const { event, state } = get_request_store();
|
|
153
155
|
|
|
154
156
|
return run_remote_function(
|
|
155
157
|
event,
|
|
156
158
|
state,
|
|
157
159
|
false,
|
|
158
|
-
args,
|
|
159
|
-
(
|
|
160
|
-
|
|
160
|
+
async () => Promise.all(args.map(validate)),
|
|
161
|
+
async (/** @type {any[]} */ input) => {
|
|
162
|
+
const get_result = await fn(input);
|
|
163
|
+
|
|
164
|
+
return Promise.all(
|
|
165
|
+
input.map(async (arg, i) => {
|
|
166
|
+
try {
|
|
167
|
+
return { type: 'result', data: get_result(arg, i) };
|
|
168
|
+
} catch (error) {
|
|
169
|
+
return {
|
|
170
|
+
type: 'error',
|
|
171
|
+
error: await handle_error_and_jsonify(event, state, options, error),
|
|
172
|
+
status:
|
|
173
|
+
error instanceof HttpError || error instanceof SvelteKitError
|
|
174
|
+
? error.status
|
|
175
|
+
: 500
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
);
|
|
180
|
+
}
|
|
161
181
|
);
|
|
162
182
|
}
|
|
163
183
|
};
|
|
@@ -190,22 +210,23 @@ function batch(validate_or_fn, maybe_fn) {
|
|
|
190
210
|
batching = { args: [], resolvers: [] };
|
|
191
211
|
|
|
192
212
|
try {
|
|
193
|
-
|
|
213
|
+
return await run_remote_function(
|
|
194
214
|
event,
|
|
195
215
|
state,
|
|
196
216
|
false,
|
|
197
|
-
batched.args,
|
|
198
|
-
(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
217
|
+
async () => Promise.all(batched.args.map(validate)),
|
|
218
|
+
async (input) => {
|
|
219
|
+
const get_result = await fn(input);
|
|
220
|
+
|
|
221
|
+
for (let i = 0; i < batched.resolvers.length; i++) {
|
|
222
|
+
try {
|
|
223
|
+
batched.resolvers[i].resolve(get_result(input[i], i));
|
|
224
|
+
} catch (error) {
|
|
225
|
+
batched.resolvers[i].reject(error);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
207
228
|
}
|
|
208
|
-
|
|
229
|
+
);
|
|
209
230
|
} catch (error) {
|
|
210
231
|
for (const resolver of batched.resolvers) {
|
|
211
232
|
resolver.reject(error);
|
|
@@ -97,11 +97,10 @@ export function parse_remote_response(data, transport) {
|
|
|
97
97
|
* @param {RequestEvent} event
|
|
98
98
|
* @param {RequestState} state
|
|
99
99
|
* @param {boolean} allow_cookies
|
|
100
|
-
* @param {any}
|
|
101
|
-
* @param {(arg: any) => any} validate
|
|
100
|
+
* @param {() => any} get_input
|
|
102
101
|
* @param {(arg?: any) => T} fn
|
|
103
102
|
*/
|
|
104
|
-
export async function run_remote_function(event, state, allow_cookies,
|
|
103
|
+
export async function run_remote_function(event, state, allow_cookies, get_input, fn) {
|
|
105
104
|
/** @type {RequestStore} */
|
|
106
105
|
const store = {
|
|
107
106
|
event: {
|
|
@@ -142,8 +141,8 @@ export async function run_remote_function(event, state, allow_cookies, arg, vali
|
|
|
142
141
|
};
|
|
143
142
|
|
|
144
143
|
// In two parts, each with_event, so that runtimes without async local storage can still get the event at the start of the function
|
|
145
|
-
const
|
|
146
|
-
return with_request_store(store, () => fn(
|
|
144
|
+
const input = await with_request_store(store, get_input);
|
|
145
|
+
return with_request_store(store, () => fn(input));
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
/**
|