@sveltejs/kit 3.0.0-next.24 → 3.0.0-next.27

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.
Files changed (71) hide show
  1. package/package.json +16 -10
  2. package/src/constants.js +6 -0
  3. package/src/core/adapt/builder.js +128 -33
  4. package/src/core/adapt/index.js +3 -0
  5. package/src/core/config/index.js +4 -7
  6. package/src/core/env.js +39 -14
  7. package/src/core/generate_manifest/index.js +42 -43
  8. package/src/core/postbuild/analyse.js +4 -4
  9. package/src/core/postbuild/fallback.js +1 -1
  10. package/src/core/postbuild/prerender.js +4 -4
  11. package/src/core/sync/create_manifest_data/index.js +0 -1
  12. package/src/core/sync/write_app_manifest.js +3 -2
  13. package/src/core/sync/write_server.js +3 -17
  14. package/src/core/utils.js +10 -0
  15. package/src/exports/adapter.js +22 -0
  16. package/src/exports/public.d.ts +101 -49
  17. package/src/exports/vite/build/index.js +1173 -0
  18. package/src/exports/vite/build/remote.js +4 -4
  19. package/src/exports/vite/build/service-worker.js +98 -0
  20. package/src/exports/vite/dev/generate_manifest.js +308 -0
  21. package/src/exports/vite/dev/index.js +40 -282
  22. package/src/exports/vite/index.js +156 -1717
  23. package/src/exports/vite/plugins/env-vars.js +53 -34
  24. package/src/exports/vite/plugins/guard.js +217 -0
  25. package/src/exports/vite/plugins/remote.js +237 -0
  26. package/src/exports/vite/preview/index.js +8 -8
  27. package/src/exports/vite/static_analysis/index.js +15 -15
  28. package/src/exports/vite/utils.js +98 -1
  29. package/src/runner.js +4 -3
  30. package/src/runtime/app/paths/server.js +2 -2
  31. package/src/runtime/app/server/index.js +3 -3
  32. package/src/runtime/app/server/public.d.ts +114 -57
  33. package/src/runtime/app/server/remote/query.js +2 -2
  34. package/src/runtime/app/server/remote/requested.js +31 -15
  35. package/src/runtime/app/state/client.svelte.js +3 -1
  36. package/src/runtime/client/client.js +43 -198
  37. package/src/runtime/client/fetcher.js +6 -6
  38. package/src/runtime/client/focus.js +120 -0
  39. package/src/runtime/client/remote-functions/command.svelte.js +20 -9
  40. package/src/runtime/client/remote-functions/form.svelte.js +12 -7
  41. package/src/runtime/client/remote-functions/query/instance.svelte.js +19 -5
  42. package/src/runtime/client/remote-functions/shared.svelte.js +22 -1
  43. package/src/runtime/client/scroll.js +39 -0
  44. package/src/runtime/client/utils.js +28 -0
  45. package/src/runtime/form-utils.js +254 -264
  46. package/src/runtime/server/data/index.js +14 -36
  47. package/src/runtime/server/errors.js +7 -10
  48. package/src/runtime/server/fetch.js +21 -25
  49. package/src/runtime/server/index.js +35 -31
  50. package/src/runtime/server/internal.js +34 -5
  51. package/src/runtime/server/page/actions.js +6 -8
  52. package/src/runtime/server/page/data_serializer.js +6 -10
  53. package/src/runtime/server/page/index.js +18 -28
  54. package/src/runtime/server/page/load_data.js +2 -2
  55. package/src/runtime/server/page/render.js +22 -40
  56. package/src/runtime/server/page/respond_with_error.js +10 -13
  57. package/src/runtime/server/page/server_routing.js +21 -27
  58. package/src/runtime/server/remote-functions.js +136 -136
  59. package/src/runtime/server/respond.js +66 -64
  60. package/src/runtime/server/state.js +2 -0
  61. package/src/runtime/server/utils.js +4 -11
  62. package/src/runtime/shared.js +9 -0
  63. package/src/runtime/utils.js +41 -0
  64. package/src/types/ambient-private.d.ts +1 -2
  65. package/src/types/global-private.d.ts +8 -0
  66. package/src/types/internal.d.ts +56 -17
  67. package/src/utils/filesystem.js +44 -28
  68. package/src/utils/streaming.js +5 -15
  69. package/src/version.js +1 -1
  70. package/types/index.d.ts +235 -93
  71. package/types/index.d.ts.map +9 -2
@@ -2,6 +2,7 @@
2
2
  /** @import { EnvVarConfig } from '@sveltejs/kit/env' */
3
3
  /** @import { ValidatedConfig } from 'types' */
4
4
  import path from 'node:path';
5
+ import { exactRegex } from '@rolldown/pluginutils';
5
6
  import * as sync from '../../../core/sync/sync.js';
6
7
  import { create_env_modules, resolve_env_entry } from '../../../core/env.js';
7
8
  import { import_peer } from '../../../utils/import.js';
@@ -26,9 +27,6 @@ export function plugin_env_vars(config, callback) {
26
27
  /** @type {ResolvedConfig} */
27
28
  let resolved_config;
28
29
 
29
- /** @type {string | null} */
30
- let resolved_entry = null;
31
-
32
30
  /** @type {Set<string>} */
33
31
  let deps = new Set();
34
32
 
@@ -38,12 +36,8 @@ export function plugin_env_vars(config, callback) {
38
36
  let generated;
39
37
 
40
38
  async function generate() {
41
- const synced = await sync.env(
42
- config,
43
- resolved_entry,
44
- resolved_config.root,
45
- resolved_config.mode
46
- );
39
+ const entry = resolve_env_entry(config, resolved_config.root);
40
+ const synced = await sync.env(config, entry, resolved_config.root, resolved_config.mode);
47
41
 
48
42
  deps = synced.deps;
49
43
 
@@ -55,7 +49,7 @@ export function plugin_env_vars(config, callback) {
55
49
  vars,
56
50
  env,
57
51
  dir,
58
- resolved_entry && posixify(path.relative(dir, resolved_entry)),
52
+ entry && posixify(path.relative(dir, entry)),
59
53
  !is_build
60
54
  );
61
55
 
@@ -84,34 +78,59 @@ export function plugin_env_vars(config, callback) {
84
78
  // runs once via the memo — per-process, whichever environment starts first
85
79
  // (environment names vary by adapter), and never in the postbuild forks,
86
80
  // which resolve the config without building
87
- await (generated ??= (async () => {
88
- resolved_entry = resolve_env_entry(config, resolved_config.root);
89
- await generate();
90
- })());
81
+ await (generated ??= generate());
91
82
  },
92
83
 
93
- configureServer(server) {
94
- // `handleHotUpdate` only fires for `change` events on files Vite already knows about,
95
- // so it doesn't cover the env entry being created or deleted while the dev server is
96
- // running. Watch for those events explicitly, re-resolve the entry, regenerate the
97
- // modules and trigger a full reload (mirroring the previous behaviour).
98
- const on_entry_add_unlink = async (/** @type {string} */ file) => {
99
- const resolved = resolve_env_entry(config, resolved_config.root);
100
-
101
- if (file === resolved_entry || file === resolved) {
102
- resolved_entry = resolved;
103
- await generate();
104
- server.hot.send({ type: 'full-reload' });
105
- }
106
- };
107
-
108
- server.watcher.on('add', on_entry_add_unlink);
109
- server.watcher.on('unlink', on_entry_add_unlink);
110
- },
84
+ async hotUpdate({ type, file }) {
85
+ // runs for every environment; the generated modules are shared, so do the work once
86
+ if (this.environment.name !== 'client') return;
87
+
88
+ const created = type === 'create' && file === resolve_env_entry(config, resolved_config.root);
89
+ if (!deps.has(file) && !created) return;
111
90
 
112
- async handleHotUpdate(update) {
113
- if (!deps.has(update.file)) return;
114
91
  await generate();
92
+ if (type !== 'update') this.environment.hot.send({ type: 'full-reload' });
115
93
  }
116
94
  };
117
95
  }
96
+
97
+ /**
98
+ * @param {() => string | null} get_service_worker_entry_file
99
+ * @returns {Plugin}
100
+ */
101
+ export function plugin_service_worker_env_vars(get_service_worker_entry_file) {
102
+ /** @type {string | null} */
103
+ let service_worker_entry_file;
104
+
105
+ /** @satisfies {Plugin} */
106
+ const plugin = {
107
+ name: 'vite-plugin-sveltekit-service-worker-env',
108
+ configResolved() {
109
+ service_worker_entry_file = get_service_worker_entry_file();
110
+
111
+ if (service_worker_entry_file) {
112
+ plugin.transform.filter = {
113
+ id: exactRegex(service_worker_entry_file)
114
+ };
115
+ }
116
+ },
117
+ applyToEnvironment(environment) {
118
+ return !!service_worker_entry_file && environment.config.consumer === 'client';
119
+ },
120
+ transform: {
121
+ filter: {},
122
+ handler(code) {
123
+ // prepend the service worker with an import that configures
124
+ // `env`, in case `$app/env/public` is imported. In production
125
+ // this is required: dynamic public env vars aren't known at
126
+ // build time, so `env.js` is loaded at runtime. In dev, the
127
+ // imported module just inlines the current values instead.
128
+ return {
129
+ code: `import '<sveltekit:generated>/env/service-worker.js';\n${code}`
130
+ };
131
+ }
132
+ }
133
+ };
134
+
135
+ return plugin;
136
+ }
@@ -0,0 +1,217 @@
1
+ /** @import { TopLevelFilterExpression } from '@rolldown/pluginutils' */
2
+ /** @import { ManifestData, ValidatedConfig } from 'types' */
3
+ /** @import { Plugin } from 'vite' */
4
+ import path from 'node:path';
5
+ import { and, exactRegex, importerId, include, not } from '@rolldown/pluginutils';
6
+ import { app_env_private, app_server } from '../module_ids.js';
7
+ import {
8
+ error_for_missing_config,
9
+ normalize_id,
10
+ remote_module_pattern,
11
+ server_only_directory_pattern,
12
+ server_only_module_pattern
13
+ } from '../utils.js';
14
+ import { stackless } from '../../../utils/error.js';
15
+ import { posixify } from '../../../utils/os.js';
16
+
17
+ /**
18
+ * Ensures that client-side code can't accidentally import server-side code,
19
+ * whether in `*.server.js` files, `$app/server`, any `/server/` directory, or `$app/env/private`
20
+ * @param {ValidatedConfig} kit
21
+ * @param {() => { vite: typeof import('vite'); root: string; normalized_aliases: Array<{ alias: string, path: string }>; service_worker_entry_file: string | null; }} get_config
22
+ * @param {() => ManifestData} get_manifest_data
23
+ * @returns {Plugin}
24
+ */
25
+ export function plugin_guard(kit, get_config, get_manifest_data) {
26
+ /** @type {string} */
27
+ let root;
28
+
29
+ /** @type {string} */
30
+ let normalized_cwd;
31
+ /** @type {Array<{ alias: string, path: string }>} */
32
+ let normalized_aliases;
33
+ /** @type {string} */
34
+ let normalized_node_modules;
35
+ /** @type {string} */
36
+ let normalized_routes;
37
+ /** @type {string} */
38
+ let normalized_assets;
39
+
40
+ /** @type {string | null} */
41
+ let service_worker_entry_file;
42
+
43
+ /** @type {Map<string, Set<string>>} */
44
+ const import_map = new Map();
45
+
46
+ return {
47
+ name: 'vite-plugin-sveltekit-guard',
48
+
49
+ // Run this plugin before built-in resolution, so that relative imports
50
+ // are added to the module graph
51
+ enforce: 'pre',
52
+
53
+ configResolved() {
54
+ /** @type {typeof import('vite')} */
55
+ let vite;
56
+ ({ vite, root, normalized_aliases, service_worker_entry_file } = get_config());
57
+
58
+ normalized_cwd = vite.normalizePath(root);
59
+ normalized_node_modules = vite.normalizePath(path.resolve(root, 'node_modules'));
60
+ normalized_routes = vite.normalizePath(path.resolve(root, kit.files.routes));
61
+ normalized_assets = vite.normalizePath(path.resolve(root, kit.files.assets));
62
+ },
63
+
64
+ applyToEnvironment(environment) {
65
+ // the import map is only read for client-side violations in `load`, so skip other environments
66
+ return environment.config.consumer === 'client';
67
+ },
68
+
69
+ resolveId: {
70
+ // composable filters are not accepted type-wise but still work during build
71
+ // see https://github.com/vitejs/rolldown-vite/issues/605
72
+ filter: /** @type {any} */ (
73
+ /** @satisfies {TopLevelFilterExpression[]} */ ([
74
+ include(and(importerId(/.+/), not(importerId(/index\.html$/))))
75
+ ])
76
+ ),
77
+ async handler(id, importer, options) {
78
+ // composable filters only work during build so we still need this guard for dev
79
+ // see https://github.com/vitejs/rolldown-vite/issues/605
80
+ if (importer && !importer.endsWith('index.html')) {
81
+ const resolved = await this.resolve(id, importer, options);
82
+
83
+ if (resolved) {
84
+ const normalized = normalize_id(resolved.id, normalized_aliases, normalized_cwd);
85
+
86
+ let importers = import_map.get(normalized);
87
+
88
+ if (!importers) {
89
+ importers = new Set();
90
+ import_map.set(normalized, importers);
91
+ }
92
+
93
+ importers.add(normalize_id(importer, normalized_aliases, normalized_cwd));
94
+ }
95
+ }
96
+ }
97
+ },
98
+
99
+ load: {
100
+ filter: {
101
+ id: [
102
+ exactRegex(app_server),
103
+ exactRegex(app_env_private),
104
+ server_only_module_pattern,
105
+ server_only_directory_pattern
106
+ ]
107
+ },
108
+ handler(id) {
109
+ const normalized = normalize_id(id, normalized_aliases, normalized_cwd);
110
+
111
+ let is_server_only = normalized === '$app/env/private' || normalized === '$app/server';
112
+
113
+ // skip .server.js files outside the cwd or in node_modules, as the filename might not mean 'server-only module' in this context
114
+ if (id.startsWith(normalized_cwd + '/') && !id.startsWith(normalized_node_modules + '/')) {
115
+ // e.g. `server.ts` or `foo.server.ts`
116
+ is_server_only ||= server_only_module_pattern.test(id);
117
+
118
+ // e.g. `server/foo.ts`, unless in `src/routes` or `static`
119
+ is_server_only ||=
120
+ server_only_directory_pattern.test(id) &&
121
+ !id.startsWith(normalized_routes + '/') &&
122
+ !id.startsWith(normalized_assets + '/');
123
+ }
124
+
125
+ if (!is_server_only) return;
126
+
127
+ const manifest_data = get_manifest_data();
128
+
129
+ /** @type {Set<string>} */
130
+ const entrypoints = new Set();
131
+
132
+ /**
133
+ * Entrypoints must be normalized like the import map keys, or files
134
+ * outside the project root (e.g. hooks) would never match an importer
135
+ * @param {string} file - absolute, or relative to the project root
136
+ */
137
+ const add_entrypoint = (file) => {
138
+ entrypoints.add(
139
+ normalize_id(posixify(path.resolve(root, file)), normalized_aliases, normalized_cwd)
140
+ );
141
+ };
142
+
143
+ for (const node of manifest_data.nodes) {
144
+ if (node.component) add_entrypoint(node.component);
145
+ if (node.universal) add_entrypoint(node.universal);
146
+ }
147
+
148
+ if (manifest_data.hooks.client) add_entrypoint(manifest_data.hooks.client);
149
+ if (manifest_data.hooks.universal) add_entrypoint(manifest_data.hooks.universal);
150
+
151
+ if (service_worker_entry_file) {
152
+ add_entrypoint(service_worker_entry_file);
153
+ }
154
+
155
+ // Walk up the import graph from the server-only module, looking for a chain
156
+ // that leads back to a client entrypoint. We search all candidates (not just
157
+ // the first) because a module can be imported by both server and client code,
158
+ // and a greedy first-match could follow a server-only branch that never
159
+ // reaches an entrypoint — see https://github.com/sveltejs/kit/issues/16232
160
+ /** @type {Set<string>} */
161
+ const visited = new Set([normalized]);
162
+
163
+ /**
164
+ * @param {string} current
165
+ * @param {string[]} chain
166
+ * @returns {string[] | null}
167
+ */
168
+ function find_chain(current, chain) {
169
+ const importers = import_map.get(current);
170
+ if (!importers) return null;
171
+
172
+ for (const importer of importers) {
173
+ if (visited.has(importer)) continue;
174
+ visited.add(importer);
175
+
176
+ const next_chain = [...chain, importer];
177
+ if (entrypoints.has(importer)) {
178
+ return next_chain;
179
+ }
180
+ const result = find_chain(importer, next_chain);
181
+ if (result) return result;
182
+ }
183
+ return null;
184
+ }
185
+
186
+ const chain = find_chain(normalized, [normalized]);
187
+
188
+ if (chain) {
189
+ if (chain.some((id) => remote_module_pattern.test(id))) {
190
+ error_for_missing_config('remote functions', 'experimental.remoteFunctions', 'true');
191
+ }
192
+
193
+ const pyramid = chain
194
+ .reverse()
195
+ .map((id, i) => {
196
+ return `${' '.repeat(i + 1)}${id}`;
197
+ })
198
+ .join(' imports\n');
199
+
200
+ let message = `Cannot import ${normalized} into code that runs in the browser, as this could leak sensitive information.`;
201
+ message += `\n\n${pyramid}`;
202
+ message += `\n\nIf you're only using the import as a type, change it to \`import type\`.`;
203
+
204
+ throw stackless(message);
205
+ }
206
+
207
+ // No chain from this server-only module to a client entrypoint was found —
208
+ // the module is only imported from server code, which is valid.
209
+ }
210
+ },
211
+
212
+ // avoid watch mode rebuilds using stale import map data
213
+ buildEnd() {
214
+ import_map.clear();
215
+ }
216
+ };
217
+ }
@@ -0,0 +1,237 @@
1
+ /** @import { RemoteChunk, RemoteInternals, ServerMetadata, ValidatedConfig } from 'types' */
2
+ /** @import { Plugin, ViteDevServer } from 'vite' */
3
+ import path from 'node:path';
4
+ import { prefixRegex } from '@rolldown/pluginutils';
5
+ import MagicString from 'magic-string';
6
+ import { error_for_missing_config, is_remote_module, remote_module_pattern } from '../utils.js';
7
+ import { create_exported_declarations } from '../../../core/env.js';
8
+ import { dedent } from '../../../core/sync/utils.js';
9
+ import { runtime_directory } from '../../../core/utils.js';
10
+ import { get_runner } from '../../../runner.js';
11
+ import { hash } from '../../../utils/hash.js';
12
+ import { s } from '../../../utils/misc.js';
13
+ import { posixify } from '../../../utils/os.js';
14
+
15
+ /**
16
+ * @param {ValidatedConfig} svelte_config
17
+ * @param {() => { root: string; vite: typeof import('vite'); }} get_config
18
+ * @param {() => ServerMetadata | null} get_build_metadata
19
+ * @param {(remote_metadata: {remotes: RemoteChunk[]; remote_original_by_hash: Map<string, string>}) => void} set_remote_metadata
20
+ * @returns {Plugin}
21
+ */
22
+ export function plugin_remote(svelte_config, get_config, get_build_metadata, set_remote_metadata) {
23
+ /** @type {string} */
24
+ let root;
25
+ /** @type {typeof import('vite')} */
26
+ let vite;
27
+
28
+ /** @type {ViteDevServer} */
29
+ let dev_server;
30
+
31
+ /** @type {ServerMetadata | null} */
32
+ let build_metadata;
33
+
34
+ /** @type {RemoteChunk[]} */
35
+ let remotes = [];
36
+
37
+ /** @type {Map<string, string>} Maps remote hash -> original module id */
38
+ const remote_original_by_hash = new Map();
39
+ /** @type {Set<string>} Track which remote hashes have already been emitted */
40
+ const emitted_remote_hashes = new Set();
41
+
42
+ return {
43
+ name: 'vite-plugin-sveltekit-remote',
44
+
45
+ configResolved() {
46
+ ({ root, vite } = get_config());
47
+ },
48
+
49
+ configureServer(_dev_server) {
50
+ dev_server = _dev_server;
51
+ },
52
+
53
+ applyToEnvironment(environment) {
54
+ return svelte_config.experimental.remoteFunctions && environment.name !== 'serviceWorker';
55
+ },
56
+
57
+ perEnvironmentStartEndDuringDev: true,
58
+
59
+ buildStart() {
60
+ // avoid stale data when building with watch mode
61
+ if (this.meta.watchMode && this.environment.config.consumer === 'server') {
62
+ remotes = [];
63
+ remote_original_by_hash.clear();
64
+ emitted_remote_hashes.clear();
65
+ }
66
+
67
+ build_metadata = get_build_metadata();
68
+ set_remote_metadata({ remotes, remote_original_by_hash });
69
+ },
70
+
71
+ // prevent other plugins from resolving our remote virtual module
72
+ resolveId: {
73
+ filter: {
74
+ id: prefixRegex('\0sveltekit-remote:')
75
+ },
76
+ handler(id) {
77
+ return id;
78
+ }
79
+ },
80
+
81
+ load: {
82
+ filter: {
83
+ id: prefixRegex('\0sveltekit-remote:')
84
+ },
85
+ handler(id) {
86
+ // On-the-fly generated entry point for remote file just forwards the original module
87
+ // We're not using manualChunks because it can cause problems with circular dependencies
88
+ // (e.g. https://github.com/sveltejs/kit/issues/14679) and module ordering in general
89
+ // (e.g. https://github.com/sveltejs/kit/issues/14590).
90
+ const hash_id = id.slice('\0sveltekit-remote:'.length);
91
+ const original = remote_original_by_hash.get(hash_id);
92
+ if (!original) throw new Error(`Expected to find metadata for remote file ${id}`);
93
+ return `import * as m from ${s(original)};\nexport default m;`;
94
+ }
95
+ },
96
+
97
+ transform: {
98
+ filter: {
99
+ id: remote_module_pattern
100
+ },
101
+ async handler(code, id) {
102
+ if (!is_remote_module(id)) return;
103
+
104
+ const file = posixify(path.relative(root, id));
105
+ const remote = {
106
+ hash: hash(file),
107
+ file
108
+ };
109
+
110
+ if (this.environment.config.consumer === 'server') {
111
+ remotes.push(remote);
112
+
113
+ // we need to add an `await Promise.resolve()` because if the user imports this function
114
+ // on the client AND in a load function when loading the client module we will trigger
115
+ // an import during dev. During a link preload, the module can be mistakenly
116
+ // loaded and transformed twice and the first time all its exports would be undefined
117
+ // triggering a dev server error. By adding a microtask we ensure that the module is fully loaded
118
+ const ms = new MagicString(code);
119
+
120
+ // Extra newlines to prevent syntax errors around missing semicolons or comments
121
+ ms.append(
122
+ '\n\n' +
123
+ dedent`
124
+ import * as $$_self_$$ from './${path.basename(id)}';
125
+ import { init_remote_functions as $$_init_$$ } from '@sveltejs/kit/internal/server';
126
+
127
+ ${dev_server ? 'await Promise.resolve()' : ''}
128
+
129
+ $$_init_$$($$_self_$$, ${s(file)}, ${s(remote.hash)});
130
+
131
+ for (const [name, fn] of Object.entries($$_self_$$)) {
132
+ fn.__.id = ${s(remote.hash)} + '/' + name;
133
+ fn.__.name = name;
134
+ }
135
+ `
136
+ );
137
+
138
+ // Emit a dedicated entry chunk for this remote in SSR builds (prod only)
139
+ if (!dev_server) {
140
+ remote_original_by_hash.set(remote.hash, id);
141
+
142
+ if (!emitted_remote_hashes.has(remote.hash)) {
143
+ this.emitFile({
144
+ type: 'chunk',
145
+ id: `\0sveltekit-remote:${remote.hash}`,
146
+ name: `remote-${remote.hash}`
147
+ });
148
+ emitted_remote_hashes.add(remote.hash);
149
+ }
150
+ }
151
+
152
+ return {
153
+ code: ms.toString(),
154
+ map: ms.generateMap({ hires: 'boundary' })
155
+ };
156
+ }
157
+
158
+ // For the client, read the exports and create a new module that only contains fetch functions with the correct metadata
159
+
160
+ /** @type {Map<string, RemoteInternals['type']>} */
161
+ const map = new Map();
162
+
163
+ // in dev, load the server module here (which will result in this hook
164
+ // being called again with `opts.ssr === true` if the module isn't
165
+ // already loaded) so we can determine what it exports
166
+ if (dev_server) {
167
+ const module = await get_runner(vite, dev_server).import(id);
168
+
169
+ for (const [name, value] of Object.entries(module)) {
170
+ const type = value?.__?.type;
171
+ if (type) map.set(name, type);
172
+ }
173
+ }
174
+ // in prod, we already built and analysed the server code before
175
+ // building the client code, so `remotes` is populated
176
+ else if (build_metadata?.remotes) {
177
+ const exports = build_metadata.remotes.get(remote.hash);
178
+ if (!exports) throw new Error('Expected to find metadata for remote file ' + id);
179
+
180
+ for (const [name, value] of exports) {
181
+ map.set(name, value.type);
182
+ }
183
+ }
184
+
185
+ const { namespace, declarations, reexports } = create_exported_declarations(
186
+ map.keys(),
187
+ (name, ns) => `${ns}.${map.get(name)}('${remote.hash}/${name}')`,
188
+ '__remote'
189
+ );
190
+
191
+ const relative = posixify(
192
+ path.relative(path.dirname(id), `${runtime_directory}/client/remote-functions/index.js`)
193
+ );
194
+
195
+ let result = `import * as ${namespace} from '${relative}';\n\n${declarations.join('\n')}`;
196
+ if (reexports.length > 0) {
197
+ result += `\nexport { ${reexports.join(', ')} };`;
198
+ }
199
+ result += '\n';
200
+
201
+ if (dev_server) {
202
+ result += `\nimport.meta.hot?.accept();\n`;
203
+ }
204
+
205
+ return {
206
+ code: result,
207
+ map: null
208
+ };
209
+ }
210
+ }
211
+ };
212
+ }
213
+
214
+ /**
215
+ * @param {ValidatedConfig} svelte_config
216
+ * @returns {Plugin}
217
+ */
218
+ export function plugin_remote_guard(svelte_config) {
219
+ return {
220
+ name: 'vite-plugin-sveltekit-remote-guard',
221
+
222
+ applyToEnvironment() {
223
+ return !svelte_config.experimental.remoteFunctions;
224
+ },
225
+
226
+ transform: {
227
+ filter: {
228
+ id: new RegExp(
229
+ `.remote(${svelte_config.moduleExtensions.join('|')})$`.replaceAll('.', '\\.')
230
+ )
231
+ },
232
+ handler() {
233
+ error_for_missing_config('remote functions', 'experimental.remoteFunctions', 'true');
234
+ }
235
+ }
236
+ };
237
+ }
@@ -1,5 +1,5 @@
1
1
  /** @import { NextHandleFunction } from 'connect' */
2
- /** @import { PreviewServer, ResolvedConfig } from 'vite' */
2
+ /** @import { PreviewServer } from 'vite' */
3
3
  /** @import { ValidatedConfig, ServerInternalModule, ServerModule } from 'types' */
4
4
  import fs from 'node:fs';
5
5
  import { join } from 'node:path';
@@ -15,15 +15,14 @@ import { stackless } from '../../../utils/error.js';
15
15
 
16
16
  /**
17
17
  * @param {PreviewServer} vite
18
- * @param {ResolvedConfig} vite_config
19
18
  * @param {ValidatedConfig} svelte_config
20
19
  */
21
- export async function preview(vite, vite_config, svelte_config) {
20
+ export async function preview(vite, svelte_config) {
22
21
  const { paths } = svelte_config;
23
22
  const base = paths.base;
24
23
  const assets = paths.assets ? SVELTE_KIT_ASSETS : paths.base;
25
24
 
26
- const protocol = vite_config.preview.https ? 'https' : 'http';
25
+ const protocol = vite.config.preview.https ? 'https' : 'http';
27
26
 
28
27
  const etag = `"${Date.now()}"`;
29
28
 
@@ -44,6 +43,7 @@ export async function preview(vite, vite_config, svelte_config) {
44
43
  /** @type {ServerModule} */
45
44
  const { Server } = await import(pathToFileURL(join(dir, 'index.js')).href);
46
45
 
46
+ /** @type {{ manifest: import('types').SSRManifest }} */
47
47
  const { manifest } = await import(pathToFileURL(join(dir, 'manifest.js')).href);
48
48
 
49
49
  set_assets(assets);
@@ -52,7 +52,7 @@ export async function preview(vite, vite_config, svelte_config) {
52
52
 
53
53
  try {
54
54
  await server.init({
55
- env: loadEnv(vite_config.mode, svelte_config.env.dir, ''),
55
+ env: loadEnv(vite.config.mode, svelte_config.env.dir, ''),
56
56
  read: (file) => createReadableStream(`${dir}/${file}`)
57
57
  });
58
58
  } catch (error) {
@@ -205,13 +205,13 @@ export async function preview(vite, vite_config, svelte_config) {
205
205
  vite.middlewares.use(async (req, res) => {
206
206
  const host = req.headers[':authority'] || req.headers.host;
207
207
 
208
- const request = getRequest({
208
+ const request = (svelte_config.adapter?.vite?.getRequest ?? getRequest)({
209
209
  base: `${protocol}://${host}`,
210
210
  request: req,
211
211
  response: res
212
212
  });
213
213
 
214
- setResponse(
214
+ (svelte_config.adapter?.vite?.setResponse ?? setResponse)(
215
215
  res,
216
216
  await server.respond(request, {
217
217
  getClientAddress: () => {
@@ -220,7 +220,7 @@ export async function preview(vite, vite_config, svelte_config) {
220
220
  throw new Error('Could not determine clientAddress');
221
221
  },
222
222
  read: (file) => {
223
- if (file in manifest._.server_assets) {
223
+ if (file in manifest.server_assets) {
224
224
  return fs.readFileSync(join(dir, file));
225
225
  }
226
226