@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21

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 (195) hide show
  1. package/package.json +62 -36
  2. package/src/cli.js +15 -12
  3. package/src/constants.js +6 -1
  4. package/src/core/adapt/builder.js +66 -72
  5. package/src/core/adapt/index.js +17 -6
  6. package/src/core/config/index.js +134 -80
  7. package/src/core/config/options.js +295 -273
  8. package/src/core/config/types.d.ts +1 -1
  9. package/src/core/env.js +146 -16
  10. package/src/core/generate_manifest/index.js +18 -15
  11. package/src/core/postbuild/analyse.js +8 -20
  12. package/src/core/postbuild/crawl.js +22 -6
  13. package/src/core/postbuild/entities.js +8 -2
  14. package/src/core/postbuild/fallback.js +4 -2
  15. package/src/core/postbuild/prerender.js +222 -70
  16. package/src/core/postbuild/queue.js +2 -1
  17. package/src/core/sync/create_manifest_data/conflict.js +1 -1
  18. package/src/core/sync/create_manifest_data/index.js +82 -62
  19. package/src/core/sync/sync.js +40 -31
  20. package/src/core/sync/ts.js +1 -1
  21. package/src/core/sync/utils.js +22 -2
  22. package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
  23. package/src/core/sync/write_client_manifest.js +14 -29
  24. package/src/core/sync/write_env.js +7 -5
  25. package/src/core/sync/write_server.js +37 -45
  26. package/src/core/sync/write_tsconfig/index.js +274 -0
  27. package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
  28. package/src/core/sync/write_tsconfig/utils.js +77 -0
  29. package/src/core/sync/write_tsconfig/validate.js +128 -0
  30. package/src/core/sync/write_types/index.js +127 -123
  31. package/src/core/utils.js +30 -5
  32. package/src/exports/env/index.js +77 -0
  33. package/src/exports/env/public.d.ts +55 -0
  34. package/src/exports/hooks/index.js +3 -9
  35. package/src/exports/hooks/public.d.ts +195 -0
  36. package/src/exports/hooks/sequence.js +9 -6
  37. package/src/exports/index.js +52 -29
  38. package/src/exports/internal/client.js +5 -0
  39. package/src/exports/internal/env.js +8 -5
  40. package/src/exports/internal/index.js +1 -90
  41. package/src/exports/internal/{event.js → server/event.js} +2 -3
  42. package/src/exports/internal/server/index.js +37 -0
  43. package/src/exports/internal/server/telemetry.js +95 -0
  44. package/src/exports/internal/shared.js +90 -0
  45. package/src/exports/node/index.js +64 -22
  46. package/src/exports/params/index.js +70 -0
  47. package/src/exports/params/public.d.ts +63 -0
  48. package/src/exports/public.d.ts +50 -1733
  49. package/src/exports/remote/index.js +11 -0
  50. package/src/exports/remote/public.d.ts +519 -0
  51. package/src/exports/url.js +86 -0
  52. package/src/exports/vite/build/build_server.js +54 -65
  53. package/src/exports/vite/build/remote.js +24 -19
  54. package/src/exports/vite/build/utils.js +0 -8
  55. package/src/exports/vite/dev/index.js +218 -146
  56. package/src/exports/vite/index.js +1590 -858
  57. package/src/exports/vite/module_ids.js +2 -2
  58. package/src/exports/vite/preview/index.js +40 -32
  59. package/src/exports/vite/public.d.ts +588 -0
  60. package/src/exports/vite/utils.js +84 -46
  61. package/src/pathname.js +55 -0
  62. package/src/runner.js +15 -0
  63. package/src/runtime/app/env/internal.js +4 -4
  64. package/src/runtime/app/env/types.d.ts +1 -1
  65. package/src/runtime/app/environment/index.js +3 -3
  66. package/src/runtime/app/{forms.js → forms/index.js} +73 -42
  67. package/src/runtime/app/forms/public.d.ts +2 -0
  68. package/src/runtime/app/forms/types.d.ts +56 -0
  69. package/src/runtime/app/internal/transport.js +53 -0
  70. package/src/runtime/app/manifest/index.js +1 -0
  71. package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
  72. package/src/runtime/app/navigation/public.d.ts +237 -0
  73. package/src/runtime/app/paths/client.js +37 -37
  74. package/src/runtime/app/paths/index.js +1 -1
  75. package/src/runtime/app/paths/internal/client.js +34 -2
  76. package/src/runtime/app/paths/internal/server.js +6 -23
  77. package/src/runtime/app/paths/internal.d.ts +3 -0
  78. package/src/runtime/app/paths/public.d.ts +1 -29
  79. package/src/runtime/app/paths/server.js +36 -17
  80. package/src/runtime/app/paths/types.d.ts +11 -19
  81. package/src/runtime/app/server/index.js +2 -2
  82. package/src/runtime/app/server/public.d.ts +201 -0
  83. package/src/runtime/app/server/remote/command.js +13 -11
  84. package/src/runtime/app/server/remote/form.js +61 -39
  85. package/src/runtime/app/server/remote/prerender.js +45 -45
  86. package/src/runtime/app/server/remote/query.js +106 -108
  87. package/src/runtime/app/server/remote/requested.js +27 -19
  88. package/src/runtime/app/server/remote/shared.js +76 -76
  89. package/src/runtime/app/service-worker/index.js +24 -0
  90. package/src/runtime/app/state/client.js +4 -2
  91. package/src/runtime/app/state/index.js +7 -5
  92. package/src/runtime/app/state/public.d.ts +72 -0
  93. package/src/runtime/app/state/server.js +3 -0
  94. package/src/runtime/app/stores.js +15 -78
  95. package/src/runtime/client/bundle.js +1 -1
  96. package/src/runtime/client/client-entry.js +3 -0
  97. package/src/runtime/client/client.js +1336 -648
  98. package/src/runtime/client/constants.js +3 -6
  99. package/src/runtime/client/entry.js +24 -3
  100. package/src/runtime/client/fetcher.js +25 -25
  101. package/src/runtime/client/ndjson.js +1 -1
  102. package/src/runtime/client/parse.js +1 -1
  103. package/src/runtime/client/payload.js +17 -0
  104. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  105. package/src/runtime/client/remote-functions/command.svelte.js +37 -61
  106. package/src/runtime/client/remote-functions/form.svelte.js +267 -178
  107. package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
  108. package/src/runtime/client/remote-functions/query/index.js +10 -17
  109. package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
  110. package/src/runtime/client/remote-functions/query/proxy.js +5 -5
  111. package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
  112. package/src/runtime/client/remote-functions/query-live/index.js +1 -1
  113. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
  114. package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
  115. package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
  116. package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
  117. package/src/runtime/client/snapshots.js +147 -0
  118. package/src/runtime/client/state.svelte.js +94 -55
  119. package/src/runtime/client/stream.js +3 -2
  120. package/src/runtime/client/types.d.ts +13 -9
  121. package/src/runtime/client/utils.js +22 -110
  122. package/src/runtime/components/root.svelte +56 -0
  123. package/src/runtime/env/dynamic/private.js +7 -0
  124. package/src/runtime/env/dynamic/public.js +7 -0
  125. package/src/runtime/env/static/private.js +6 -0
  126. package/src/runtime/env/static/public.js +6 -0
  127. package/src/runtime/form-utils.js +172 -61
  128. package/src/runtime/pathname.js +20 -32
  129. package/src/runtime/props.svelte.js +72 -0
  130. package/src/runtime/server/constants.js +0 -3
  131. package/src/runtime/server/cookie.js +72 -55
  132. package/src/runtime/server/csrf.js +65 -0
  133. package/src/runtime/server/data/index.js +49 -53
  134. package/src/runtime/server/dev.js +22 -0
  135. package/src/runtime/server/endpoint.js +6 -7
  136. package/src/runtime/server/env_module.js +0 -5
  137. package/src/runtime/server/errors.js +160 -0
  138. package/src/runtime/server/fetch.js +32 -39
  139. package/src/runtime/server/index.js +90 -64
  140. package/src/runtime/server/internal.js +71 -0
  141. package/src/runtime/server/page/actions.js +85 -64
  142. package/src/runtime/server/page/crypto.js +2 -2
  143. package/src/runtime/server/page/csp.js +88 -104
  144. package/src/runtime/server/page/data_serializer.js +24 -25
  145. package/src/runtime/server/page/index.js +36 -53
  146. package/src/runtime/server/page/load_data.js +50 -57
  147. package/src/runtime/server/page/render.js +173 -239
  148. package/src/runtime/server/page/respond_with_error.js +17 -31
  149. package/src/runtime/server/page/serialize_data.js +2 -13
  150. package/src/runtime/server/page/server_routing.js +85 -26
  151. package/src/runtime/server/remote-functions.js +640 -0
  152. package/src/runtime/server/respond.js +190 -131
  153. package/src/runtime/server/sourcemaps.js +183 -0
  154. package/src/runtime/server/state.js +53 -0
  155. package/src/runtime/server/utils.js +13 -155
  156. package/src/runtime/shared.js +20 -40
  157. package/src/runtime/utils.js +3 -0
  158. package/src/types/ambient-private.d.ts +11 -1
  159. package/src/types/ambient.d.ts +87 -36
  160. package/src/types/global-private.d.ts +25 -25
  161. package/src/types/internal.d.ts +163 -157
  162. package/src/types/private.d.ts +41 -1
  163. package/src/utils/error.js +28 -4
  164. package/src/utils/escape.js +9 -25
  165. package/src/utils/features.js +1 -1
  166. package/src/utils/filesystem.js +1 -23
  167. package/src/utils/fork.js +7 -2
  168. package/src/utils/hash.js +21 -0
  169. package/src/utils/http.js +8 -7
  170. package/src/utils/import.js +9 -2
  171. package/src/utils/imports.js +83 -0
  172. package/src/utils/mime.js +9 -0
  173. package/src/utils/page_nodes.js +6 -7
  174. package/src/utils/params.js +67 -0
  175. package/src/utils/regex.js +9 -0
  176. package/src/utils/routing.js +145 -73
  177. package/src/utils/shared-iterator.js +5 -0
  178. package/src/utils/streaming.js +14 -4
  179. package/src/utils/url.js +33 -2
  180. package/src/version.js +1 -1
  181. package/types/index.d.ts +2616 -2433
  182. package/types/index.d.ts.map +120 -106
  183. package/src/core/sync/write_ambient.js +0 -18
  184. package/src/core/sync/write_root.js +0 -148
  185. package/src/core/sync/write_tsconfig.js +0 -250
  186. package/src/exports/internal/server.js +0 -22
  187. package/src/exports/node/polyfills.js +0 -30
  188. package/src/runtime/server/app.js +0 -9
  189. package/src/runtime/server/remote.js +0 -457
  190. package/src/runtime/shared-server.js +0 -7
  191. package/src/runtime/telemetry/otel.js +0 -21
  192. package/src/runtime/telemetry/record_span.js +0 -65
  193. package/src/types/synthetic/$lib.md +0 -5
  194. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
  195. /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
@@ -1,31 +1,24 @@
1
+ import fs from 'node:fs';
1
2
  import path from 'node:path';
2
3
  import { posixify } from '../../utils/os.js';
3
4
  import { negotiate } from '../../utils/http.js';
4
5
  import { escape_html } from '../../utils/escape.js';
6
+ import { escape_for_regexp } from '../../utils/regex.js';
5
7
  import { stackless } from '../../utils/error.js';
6
8
  import { dedent } from '../../core/sync/utils.js';
7
- import {
8
- app_server,
9
- app_env_private,
10
- service_worker,
11
- sveltekit_env_private
12
- } from './module_ids.js';
9
+ import { app_server, app_env_private, sveltekit_env_private } from './module_ids.js';
13
10
 
14
11
  /**
15
- * Transforms kit.alias to a valid vite.resolve.alias array.
12
+ * Transforms alias to a valid vite.resolve.alias array.
16
13
  *
17
14
  * Related to tsconfig path alias creation.
18
15
  *
19
- * @param {import('types').ValidatedKitConfig} config
16
+ * @param {import('types').ValidatedConfig} config
20
17
  * @param {string} root
21
- * */
18
+ */
22
19
  export function get_config_aliases(config, root) {
23
20
  /** @type {import('vite').Alias[]} */
24
- const alias = [
25
- // For now, we handle `$lib` specially here rather than make it a default value for
26
- // `config.kit.alias` since it has special meaning for packaging, etc.
27
- { find: '$lib', replacement: config.files.lib }
28
- ];
21
+ const alias = [];
29
22
 
30
23
  for (let [key, value] of Object.entries(config.alias)) {
31
24
  value = posixify(value);
@@ -36,29 +29,22 @@ export function get_config_aliases(config, root) {
36
29
  // Doing just `{ find: key.slice(0, -2) ,..}` would mean `import .. from "key"` would also be matched, which we don't want
37
30
  alias.push({
38
31
  find: new RegExp(`^${escape_for_regexp(key.slice(0, -2))}\\/(.+)$`),
39
- replacement: `${path.resolve(root, value)}/$1`
32
+ replacement: `${posixify(path.resolve(root, value))}/$1`
40
33
  });
41
34
  } else if (key + '/*' in config.alias) {
42
35
  // key and key/* both exist -> the replacement for key needs to happen _only_ on import .. from "key"
43
36
  alias.push({
44
37
  find: new RegExp(`^${escape_for_regexp(key)}$`),
45
- replacement: path.resolve(root, value)
38
+ replacement: posixify(path.resolve(root, value))
46
39
  });
47
40
  } else {
48
- alias.push({ find: key, replacement: path.resolve(root, value) });
41
+ alias.push({ find: key, replacement: posixify(path.resolve(root, value)) });
49
42
  }
50
43
  }
51
44
 
52
45
  return alias;
53
46
  }
54
47
 
55
- /**
56
- * @param {string} str
57
- */
58
- function escape_for_regexp(str) {
59
- return str.replace(/[.*+?^${}()|[\]\\]/g, (match) => '\\' + match);
60
- }
61
-
62
48
  /**
63
49
  * Silently respond with 404 for Chrome DevTools workspaces request.
64
50
  * Chrome always requests this at the root, regardless of base path.
@@ -118,22 +104,17 @@ export function not_found(req, res, base) {
118
104
  const query_pattern = /\?.*$/s;
119
105
 
120
106
  /**
121
- * Removes cwd/lib path from the start of the id
107
+ * Removes cwd path from the start of the id and replaces any `#`-prefixed
108
+ * import alias target paths with their alias names.
122
109
  * @param {string} id
123
- * @param {string} lib
110
+ * @param {Array<{ alias: string, path: string }>} aliases — sorted by path length descending
124
111
  * @param {string} cwd
125
112
  */
126
- export function normalize_id(id, lib, cwd) {
113
+ export function normalize_id(id, aliases, cwd) {
127
114
  id = id.replace(query_pattern, '');
128
115
 
129
- if (id.startsWith(lib)) {
130
- id = id.replace(lib, '$lib');
131
- }
132
-
133
- if (id.startsWith(cwd)) {
134
- id = path.relative(cwd, id);
135
- }
136
-
116
+ // check before the cwd is removed — in a user's app these modules live
117
+ // inside `node_modules`, i.e. within the cwd
137
118
  if (id === app_server) {
138
119
  return '$app/server';
139
120
  }
@@ -142,29 +123,86 @@ export function normalize_id(id, lib, cwd) {
142
123
  return '$app/env/private';
143
124
  }
144
125
 
145
- if (id === service_worker) {
146
- return '$service-worker';
126
+ for (const { alias, path } of aliases) {
127
+ if (id === path || id.startsWith(path + '/')) {
128
+ id = id.replace(path, alias);
129
+ break;
130
+ }
131
+ }
132
+
133
+ if (id.startsWith(cwd)) {
134
+ id = path.relative(cwd, id);
147
135
  }
148
136
 
149
137
  return posixify(id);
150
138
  }
151
139
 
140
+ export const remote_module_pattern = /[/.]remote\.[^/]+$/;
141
+
142
+ /**
143
+ * A cache of which directories can export remote modules
144
+ * @type {Map<string, boolean>}
145
+ */
146
+ const remote_module_cache = new Map();
147
+
148
+ /**
149
+ * Whether `id` is a remote module. Files in node_modules only count if the
150
+ * package they belong to has a peer dependency on `@sveltejs/kit`
151
+ * @param {string} id
152
+ * @returns {boolean}
153
+ */
154
+ export function is_remote_module(id) {
155
+ id = posixify(id);
156
+ if (!remote_module_pattern.test(id)) return false;
157
+ if (!id.includes('node_modules')) return true;
158
+
159
+ return can_export_remote_module(path.dirname(id));
160
+ }
161
+
162
+ /**
163
+ * @param {string} directory
164
+ * @returns {boolean}
165
+ */
166
+ function can_export_remote_module(directory) {
167
+ let cached = remote_module_cache.get(directory);
168
+ if (cached !== undefined) return cached;
169
+
170
+ let pkg;
171
+
172
+ try {
173
+ pkg = JSON.parse(fs.readFileSync(path.join(directory, 'package.json'), 'utf8'));
174
+ } catch {}
175
+
176
+ if (pkg?.peerDependencies?.['@sveltejs/kit']) {
177
+ cached = true;
178
+ } else {
179
+ const parent = path.dirname(directory);
180
+
181
+ cached =
182
+ path.basename(directory) === 'node_modules' || parent === directory
183
+ ? false // base case
184
+ : can_export_remote_module(parent); // recurse
185
+ }
186
+
187
+ remote_module_cache.set(directory, cached);
188
+ return cached;
189
+ }
190
+
191
+ export const server_only_module_pattern = /[/.]server\.[^/]+$/;
192
+ export const server_only_directory_pattern = /\/server\//;
193
+
152
194
  export const strip_virtual_prefix = /** @param {string} id */ (id) => id.replace('\0virtual:', '');
153
195
 
154
196
  /**
155
- * For `error_for_missing_config('instrumentation.server.js', 'kit.experimental.instrumentation.server', true)`,
197
+ * For `error_for_missing_config('remote functions', 'experimental.remoteFunctions', 'true')`,
156
198
  * returns:
157
199
  *
158
200
  * ```
159
- * To enable `instrumentation.server.js`, add the following to your `svelte.config.js`:
201
+ * To enable remote functions, add the following to the SvelteKit plugin in your `vite.config.js`:
160
202
  *
161
203
  *\`\`\`js
162
- * kit:
163
- * experimental:
164
- * instrumentation:
165
- * server: true
166
- * }
167
- * }
204
+ * experimental: {
205
+ * remoteFunctions: true
168
206
  * }
169
207
  *\`\`\`
170
208
  *```
@@ -185,7 +223,7 @@ export function error_for_missing_config(feature_name, path, value) {
185
223
 
186
224
  throw stackless(
187
225
  dedent`\
188
- To enable ${feature_name}, add the following to your \`svelte.config.js\`:
226
+ To enable ${feature_name}, add the following to your SvelteKit plugin in \`vite.config.js\`:
189
227
 
190
228
  ${result}
191
229
  `
@@ -0,0 +1,55 @@
1
+ const DATA_SUFFIX = '/__data.json';
2
+ const HTML_DATA_SUFFIX = '.html__data.json';
3
+
4
+ /** @param {string} pathname */
5
+ export function has_data_suffix(pathname) {
6
+ return pathname.endsWith(DATA_SUFFIX) || pathname.endsWith(HTML_DATA_SUFFIX);
7
+ }
8
+
9
+ /** @param {string} pathname */
10
+ export function add_data_suffix(pathname) {
11
+ if (pathname.endsWith('.html')) return pathname.replace(/\.html$/, HTML_DATA_SUFFIX);
12
+ return pathname.replace(/\/$/, '') + DATA_SUFFIX;
13
+ }
14
+
15
+ /** @param {string} pathname */
16
+ export function strip_data_suffix(pathname) {
17
+ if (pathname.endsWith(HTML_DATA_SUFFIX)) {
18
+ return pathname.slice(0, -HTML_DATA_SUFFIX.length) + '.html';
19
+ }
20
+
21
+ return pathname.slice(0, -DATA_SUFFIX.length);
22
+ }
23
+
24
+ const ROUTE_SUFFIX = '/__route.js';
25
+ const HTML_ROUTE_SUFFIX = '.html__route.js';
26
+
27
+ /**
28
+ * @param {string} pathname
29
+ * @returns {boolean}
30
+ */
31
+ export function has_resolution_suffix(pathname) {
32
+ return pathname.endsWith(ROUTE_SUFFIX) || pathname.endsWith(HTML_ROUTE_SUFFIX);
33
+ }
34
+
35
+ /**
36
+ * Convert a regular URL to a route to send to SvelteKit's server-side route resolution endpoint
37
+ * @param {string} pathname
38
+ * @returns {string}
39
+ */
40
+ export function add_resolution_suffix(pathname) {
41
+ if (pathname.endsWith('.html')) return pathname.replace(/\.html$/, HTML_ROUTE_SUFFIX);
42
+ return pathname.replace(/\/$/, '') + ROUTE_SUFFIX;
43
+ }
44
+
45
+ /**
46
+ * @param {string} pathname
47
+ * @returns {string}
48
+ */
49
+ export function strip_resolution_suffix(pathname) {
50
+ if (pathname.endsWith(HTML_ROUTE_SUFFIX)) {
51
+ return pathname.slice(0, -HTML_ROUTE_SUFFIX.length) + '.html';
52
+ }
53
+
54
+ return pathname.slice(0, -ROUTE_SUFFIX.length);
55
+ }
package/src/runner.js ADDED
@@ -0,0 +1,15 @@
1
+ /** @import { ViteDevServer } from 'vite' */
2
+
3
+ /**
4
+ * @param {typeof import('vite')} vite the peer resolved vite module
5
+ * @param {ViteDevServer} server
6
+ */
7
+ export function get_runner(vite, server) {
8
+ // `isRunnableDevEnvironment` does an `instanceof` check and will fail if
9
+ // we're using different instances of Vite
10
+ if (!vite.isRunnableDevEnvironment(server.environments.ssr)) {
11
+ throw new Error('The configured Vite SSR environment must be a RunnableDevEnvironment');
12
+ }
13
+
14
+ return server.environments.ssr.runner;
15
+ }
@@ -1,4 +1,7 @@
1
- export const version = __SVELTEKIT_APP_VERSION__;
1
+ import { BROWSER } from 'esm-env';
2
+ import { payload } from '../../client/payload.js';
3
+
4
+ export const version = BROWSER ? payload.version : __SVELTEKIT_APP_VERSION__;
2
5
  export let building = false;
3
6
  export let prerendering = false;
4
7
 
@@ -9,6 +12,3 @@ export function set_building() {
9
12
  export function set_prerendering() {
10
13
  prerendering = true;
11
14
  }
12
-
13
- // force /@vite/client to be injected
14
- import.meta.hot;
@@ -14,6 +14,6 @@ export const dev: boolean;
14
14
  export const building: boolean;
15
15
 
16
16
  /**
17
- * The value of `config.kit.version.name`.
17
+ * The value of `config.version.name`.
18
18
  */
19
19
  export const version: string;
@@ -1,6 +1,6 @@
1
- import { dev } from '../env/index.js';
1
+ import { DEV } from 'esm-env';
2
2
  export * from '../env/index.js';
3
3
 
4
- if (dev) {
5
- console.warn('`$app/environment` is now `$app/env`');
4
+ if (DEV) {
5
+ console.warn('`$app/environment` is deprecated, use `$app/env` instead');
6
6
  }
@@ -1,9 +1,15 @@
1
- import * as devalue from 'devalue';
2
- import { BROWSER, DEV } from 'esm-env';
3
- import { noop } from '../../utils/functions.js';
4
- import { invalidateAll } from './navigation.js';
5
- import { app as client_app, applyAction } from '../client/client.js';
6
- import { app as server_app } from '../server/app.js';
1
+ /** @import { ActionResult, SubmitFunction } from './types.js' */
2
+ import { DEV } from 'esm-env';
3
+ import { noop } from '../../../utils/functions.js';
4
+ import { refreshAll } from '../navigation/index.js';
5
+ import {
6
+ applyAction,
7
+ apply_action_navigation,
8
+ handle_error,
9
+ is_current_location
10
+ } from '../../client/client.js';
11
+ import { notify_version } from '../../client/state.svelte.js';
12
+ import { parse } from '#app/internal/transport';
7
13
 
8
14
  export { applyAction };
9
15
 
@@ -27,15 +33,13 @@ export { applyAction };
27
33
  * @template {Record<string, unknown> | undefined} Success
28
34
  * @template {Record<string, unknown> | undefined} Failure
29
35
  * @param {string} result
30
- * @returns {import('@sveltejs/kit').ActionResult<Success, Failure>}
36
+ * @returns {ActionResult<Success, Failure>}
31
37
  */
32
38
  export function deserialize(result) {
33
39
  const parsed = JSON.parse(result);
34
40
 
35
41
  if (parsed.data) {
36
- // the decoders should never be initialised at the top-level because `app`
37
- // will not be initialised yet if `kit.output.bundleStrategy` is 'single' or 'inline'
38
- parsed.data = devalue.parse(parsed.data, BROWSER ? client_app.decoders : server_app.decoders);
42
+ parsed.data = parse(parsed.data);
39
43
  }
40
44
 
41
45
  return parsed;
@@ -61,21 +65,22 @@ function clone(element) {
61
65
  * If a function is returned, that function is called with the response from the server.
62
66
  * If nothing is returned, the fallback will be used.
63
67
  *
64
- * If this function or its return value isn't set, it
65
- * - falls back to updating the `form` prop with the returned data if the action is on the same page as the form
66
- * - updates `page.status`
67
- * - resets the `<form>` element and invalidates all data in case of successful submission with no redirect response
68
+ * If this function or its return value isn't set, it emulates the browser-native behaviour, just without the full-page reload. It
69
+ * - resets the `<form>` element and refreshes all data in case of a successful submission with no redirect response
70
+ * - updates the `form` prop, `page.form` and `page.status` if the action is on the same page as the form
71
+ * - navigates to the page the submission lands on — populating that page's `form` prop and `page.status` on success and failure if that isn't the current page, just as a native form submission would, but with the `?/actionName` param stripped from the destination URL
68
72
  * - redirects in case of a redirect response
69
- * - redirects to the nearest error page in case of an unexpected error
73
+ * - renders the nearest error page in case of an unexpected error — the one nearest the action's route, if the action is on a different page
70
74
  *
71
75
  * If you provide a custom function with a callback and want to use the default behavior, invoke `update` in your callback.
72
76
  * It accepts an options object
73
77
  * - `reset: false` if you don't want the `<form>` values to be reset after a successful submission
74
- * - `invalidateAll: false` if you don't want the action to call `invalidateAll` after submission
78
+ * - `refreshAll` to control whether all data is refreshed after submission; it defaults to `true` for successes and `false` for failures
79
+ * - `navigate: false` to apply non-redirect results to the current page rather than navigating to `result.location`; redirects are always followed
75
80
  * @template {Record<string, unknown> | undefined} Success
76
81
  * @template {Record<string, unknown> | undefined} Failure
77
82
  * @param {HTMLFormElement} form_element The form element
78
- * @param {import('@sveltejs/kit').SubmitFunction<Success, Failure>} submit Submit callback
83
+ * @param {SubmitFunction<Success, Failure>} submit Submit callback
79
84
  */
80
85
  export function enhance(form_element, submit = noop) {
81
86
  if (DEV && clone(form_element).method !== 'post') {
@@ -84,37 +89,50 @@ export function enhance(form_element, submit = noop) {
84
89
 
85
90
  /**
86
91
  * @param {{
87
- * action: URL;
92
+ * result: ActionResult;
93
+ * reset?: boolean;
94
+ * refreshAll?: boolean;
88
95
  * invalidateAll?: boolean;
89
- * result: import('@sveltejs/kit').ActionResult;
90
- * reset?: boolean
96
+ * navigate?: boolean;
91
97
  * }} opts
92
98
  */
93
99
  const fallback_callback = async ({
94
- action,
95
100
  result,
96
101
  reset = true,
97
- invalidateAll: shouldInvalidateAll = true
102
+ refreshAll: should_refresh_all,
103
+ invalidateAll: deprecated_invalidate_all,
104
+ navigate = true
98
105
  }) => {
99
- if (result.type === 'success') {
100
- if (reset) {
101
- // We call reset from the prototype to avoid DOM clobbering
102
- HTMLFormElement.prototype.reset.call(form_element);
103
- }
104
- if (shouldInvalidateAll) {
105
- await invalidateAll();
106
- }
106
+ if (DEV && deprecated_invalidate_all !== undefined) {
107
+ console.warn(
108
+ 'The `update({ invalidateAll })` option has been deprecated in favour of `update({ refreshAll })`'
109
+ );
110
+ }
111
+
112
+ should_refresh_all ??= deprecated_invalidate_all ?? result.type === 'success';
113
+
114
+ if (result.type === 'success' && reset) {
115
+ // We call reset from the prototype to avoid DOM clobbering
116
+ HTMLFormElement.prototype.reset.call(form_element);
107
117
  }
108
118
 
109
- // For success/failure results, only apply action if it belongs to the
110
- // current page, otherwise `form` will be updated erroneously
111
- if (
112
- location.origin + location.pathname === action.origin + action.pathname ||
113
- result.type === 'redirect' ||
114
- result.type === 'error'
115
- ) {
119
+ const destination =
120
+ navigate && result.type !== 'redirect' && !is_current_location(result.location)
121
+ ? result.location
122
+ : undefined;
123
+
124
+ if (destination === undefined) {
125
+ if (should_refresh_all && result.type !== 'redirect') {
126
+ await refreshAll();
127
+ }
128
+
116
129
  await applyAction(result);
130
+ return;
117
131
  }
132
+
133
+ // emulate the browser: navigate to where the submission lands, rendering that
134
+ // page with this result
135
+ await apply_action_navigation(destination, result, should_refresh_all);
118
136
  };
119
137
 
120
138
  /** @param {SubmitEvent} event */
@@ -165,7 +183,7 @@ export function enhance(form_element, submit = noop) {
165
183
  })) ?? fallback_callback;
166
184
  if (cancelled) return;
167
185
 
168
- /** @type {import('@sveltejs/kit').ActionResult} */
186
+ /** @type {ActionResult} */
169
187
  let result;
170
188
 
171
189
  try {
@@ -197,11 +215,23 @@ export function enhance(form_element, submit = noop) {
197
215
  signal: controller.signal
198
216
  });
199
217
 
218
+ // detect new deployments from the response header
219
+ notify_version(response.headers.get('x-sveltekit-version'));
220
+
200
221
  result = deserialize(await response.text());
201
- if (result.type === 'error') result.status = response.status;
222
+ if (result.type === 'error' || result.type === 'failure') {
223
+ result.status = response.status;
224
+ }
202
225
  } catch (error) {
203
226
  if (/** @type {any} */ (error)?.name === 'AbortError') return;
204
- result = { type: 'error', error };
227
+ result = {
228
+ type: 'error',
229
+ error: await handle_error(error, {
230
+ params: {},
231
+ route: { id: null },
232
+ url: new URL(location.href)
233
+ })
234
+ };
205
235
  }
206
236
 
207
237
  await callback({
@@ -210,10 +240,11 @@ export function enhance(form_element, submit = noop) {
210
240
  formElement: form_element,
211
241
  update: (opts) =>
212
242
  fallback_callback({
213
- action,
214
243
  result,
215
244
  reset: opts?.reset,
216
- invalidateAll: opts?.invalidateAll
245
+ refreshAll: opts?.refreshAll,
246
+ invalidateAll: opts?.invalidateAll,
247
+ navigate: opts?.navigate
217
248
  }),
218
249
  // @ts-expect-error generic constraints stuff we don't care about
219
250
  result
@@ -0,0 +1,2 @@
1
+ export * from './index.js';
2
+ export type { ActionResult, SubmitFunction } from './types.js';
@@ -0,0 +1,56 @@
1
+ // kept separate from public.d.ts so generated $types can resolve these without pulling in the runtime graph
2
+ import type { MaybePromise } from '../../../types/private.js';
3
+ /**
4
+ * When calling a form action via fetch, the response will be one of these shapes.
5
+ * ```svelte
6
+ * <form method="post" use:enhance={() => {
7
+ * return ({ result }) => {
8
+ * // result is of type ActionResult
9
+ * };
10
+ * }}
11
+ * ```
12
+ *
13
+ * Success and failure results carry the root-relative `pathname + search` of the action URL, with
14
+ * the `?/actionName` parameter removed. Redirect results carry the redirect target. Server-generated
15
+ * error results also carry the action location, while client-generated errors such as network
16
+ * failures do not. `update` uses this location to emulate native form navigation.
17
+ */
18
+ export type ActionResult<
19
+ Success extends Record<string, unknown> | undefined = Record<string, any>,
20
+ Failure extends Record<string, unknown> | undefined = Record<string, any>
21
+ > =
22
+ | { type: 'success'; status: number; data?: Success; location: string }
23
+ | { type: 'failure'; status: number; data?: Failure; location: string }
24
+ | { type: 'redirect'; status: number; location: string }
25
+ | { type: 'error'; status?: number; error: App.Error; location?: string };
26
+
27
+ export type SubmitFunction<
28
+ Success extends Record<string, unknown> | undefined = Record<string, any>,
29
+ Failure extends Record<string, unknown> | undefined = Record<string, any>
30
+ > = (input: {
31
+ action: URL;
32
+ formData: FormData;
33
+ formElement: HTMLFormElement;
34
+ controller: AbortController;
35
+ submitter: HTMLElement | null;
36
+ cancel: () => void;
37
+ }) => MaybePromise<
38
+ | void
39
+ | ((opts: {
40
+ formData: FormData;
41
+ formElement: HTMLFormElement;
42
+ action: URL;
43
+ result: ActionResult<Success, Failure>;
44
+ /**
45
+ * Call this to get the default behavior of a form submission response.
46
+ * @param options Set `reset: false` if you don't want the `<form>` values to be reset after a successful submission. `refreshAll` defaults to `true` for successful results and `false` for failures. When the submission navigates, setting it to `false` still runs the destination's `load` functions but may reuse shared layout data. Set `navigate: false` to apply non-redirect results to the current page instead of navigating to `result.location`. Redirects are always followed.
47
+ */
48
+ update: (options?: {
49
+ reset?: boolean;
50
+ refreshAll?: boolean;
51
+ navigate?: boolean;
52
+ /** @deprecated Use `refreshAll` instead. */
53
+ invalidateAll?: boolean;
54
+ }) => Promise<void>;
55
+ }) => MaybePromise<void>)
56
+ >;
@@ -0,0 +1,53 @@
1
+ /** @import { Transport } from '@sveltejs/kit/hooks' */
2
+ import * as devalue from 'devalue';
3
+ import { DEV } from 'esm-env';
4
+
5
+ /** @type {(thing: any) => string} */
6
+ export let uneval = () => {
7
+ throw new Error(DEV ? 'called uneval before init_transport' : '');
8
+ };
9
+
10
+ /** @type {(data: any) => string} */
11
+ export let stringify = () => {
12
+ throw new Error(DEV ? 'called stringify before init_transport' : '');
13
+ };
14
+
15
+ /** @type {(data: string) => any} */
16
+ export let parse = () => {
17
+ throw new Error(DEV ? 'called parse before init_transport' : '');
18
+ };
19
+
20
+ /** @type {Record<string, (data: any) => any>} */
21
+ export let encoders = {};
22
+
23
+ /** @type {Record<string, (data: any) => any>} */
24
+ export let decoders = {};
25
+
26
+ export let has_custom_transporters = false;
27
+
28
+ /**
29
+ *
30
+ * @param {Transport} transport
31
+ */
32
+ export function init_transport(transport) {
33
+ const transporters = Object.entries(transport);
34
+
35
+ has_custom_transporters = transporters.length > 0;
36
+
37
+ /** @param {unknown} thing */
38
+ const replacer = (thing) => {
39
+ for (const key of Object.keys(transport)) {
40
+ const encoded = transport[key].encode(thing);
41
+ if (encoded) {
42
+ return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`;
43
+ }
44
+ }
45
+ };
46
+
47
+ encoders = Object.fromEntries(transporters.map(([k, v]) => [k, v.encode]));
48
+ decoders = Object.fromEntries(transporters.map(([k, v]) => [k, v.decode]));
49
+
50
+ uneval = (data) => devalue.uneval(data, replacer);
51
+ stringify = (data) => devalue.stringify(data, encoders);
52
+ parse = (data) => devalue.parse(data, decoders);
53
+ }
@@ -0,0 +1 @@
1
+ export * from '__sveltekit/manifest-data';
@@ -11,4 +11,5 @@ export {
11
11
  preloadData,
12
12
  pushState,
13
13
  replaceState
14
- } from '../client/client.js';
14
+ } from '../../client/client.js';
15
+ export { snapshot } from '../../client/snapshots.js';