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

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 (192) hide show
  1. package/package.json +58 -36
  2. package/src/cli.js +14 -11
  3. package/src/constants.js +6 -1
  4. package/src/core/adapt/builder.js +54 -60
  5. package/src/core/adapt/index.js +2 -5
  6. package/src/core/config/index.js +141 -76
  7. package/src/core/config/options.js +260 -260
  8. package/src/core/config/types.d.ts +1 -1
  9. package/src/core/env.js +143 -13
  10. package/src/core/generate_manifest/index.js +18 -15
  11. package/src/core/postbuild/analyse.js +7 -19
  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 +193 -69
  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 +72 -52
  19. package/src/core/sync/sync.js +35 -26
  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} +105 -56
  23. package/src/core/sync/write_client_manifest.js +13 -28
  24. package/src/core/sync/write_env.js +7 -5
  25. package/src/core/sync/write_server.js +25 -33
  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 +119 -116
  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 +194 -0
  36. package/src/exports/hooks/sequence.js +9 -6
  37. package/src/exports/index.js +53 -20
  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} +1 -2
  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 +219 -1118
  49. package/src/exports/url.js +86 -0
  50. package/src/exports/vite/build/build_server.js +53 -64
  51. package/src/exports/vite/build/remote.js +24 -19
  52. package/src/exports/vite/build/utils.js +0 -8
  53. package/src/exports/vite/dev/index.js +199 -125
  54. package/src/exports/vite/index.js +1514 -833
  55. package/src/exports/vite/module_ids.js +2 -2
  56. package/src/exports/vite/preview/index.js +32 -24
  57. package/src/exports/vite/utils.js +83 -45
  58. package/src/pathname.js +55 -0
  59. package/src/runner.js +15 -0
  60. package/src/runtime/app/env/internal.js +4 -4
  61. package/src/runtime/app/env/types.d.ts +1 -1
  62. package/src/runtime/app/environment/index.js +3 -3
  63. package/src/runtime/app/{forms.js → forms/index.js} +73 -42
  64. package/src/runtime/app/forms/public.d.ts +2 -0
  65. package/src/runtime/app/forms/types.d.ts +56 -0
  66. package/src/runtime/app/internal/transport.js +53 -0
  67. package/src/runtime/app/manifest/index.js +1 -0
  68. package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
  69. package/src/runtime/app/navigation/public.d.ts +237 -0
  70. package/src/runtime/app/paths/client.js +37 -37
  71. package/src/runtime/app/paths/index.js +1 -1
  72. package/src/runtime/app/paths/internal/client.js +34 -2
  73. package/src/runtime/app/paths/internal/server.js +6 -23
  74. package/src/runtime/app/paths/internal.d.ts +3 -0
  75. package/src/runtime/app/paths/public.d.ts +1 -29
  76. package/src/runtime/app/paths/server.js +36 -17
  77. package/src/runtime/app/paths/types.d.ts +11 -19
  78. package/src/runtime/app/server/index.js +2 -2
  79. package/src/runtime/app/server/public.d.ts +519 -0
  80. package/src/runtime/app/server/remote/command.js +13 -11
  81. package/src/runtime/app/server/remote/form.js +61 -39
  82. package/src/runtime/app/server/remote/prerender.js +45 -45
  83. package/src/runtime/app/server/remote/query.js +106 -108
  84. package/src/runtime/app/server/remote/requested.js +27 -19
  85. package/src/runtime/app/server/remote/shared.js +75 -75
  86. package/src/runtime/app/service-worker/index.js +24 -0
  87. package/src/runtime/app/state/client.js +4 -2
  88. package/src/runtime/app/state/index.js +7 -5
  89. package/src/runtime/app/state/public.d.ts +72 -0
  90. package/src/runtime/app/state/server.js +3 -0
  91. package/src/runtime/app/stores.js +15 -78
  92. package/src/runtime/client/bundle.js +1 -1
  93. package/src/runtime/client/client-entry.js +3 -0
  94. package/src/runtime/client/client.js +1336 -648
  95. package/src/runtime/client/constants.js +3 -6
  96. package/src/runtime/client/entry.js +24 -3
  97. package/src/runtime/client/fetcher.js +25 -25
  98. package/src/runtime/client/ndjson.js +1 -1
  99. package/src/runtime/client/parse.js +1 -1
  100. package/src/runtime/client/payload.js +17 -0
  101. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  102. package/src/runtime/client/remote-functions/command.svelte.js +37 -61
  103. package/src/runtime/client/remote-functions/form.svelte.js +267 -178
  104. package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
  105. package/src/runtime/client/remote-functions/query/index.js +10 -17
  106. package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
  107. package/src/runtime/client/remote-functions/query/proxy.js +5 -5
  108. package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
  109. package/src/runtime/client/remote-functions/query-live/index.js +1 -1
  110. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
  111. package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
  112. package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
  113. package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
  114. package/src/runtime/client/snapshots.js +147 -0
  115. package/src/runtime/client/state.svelte.js +94 -55
  116. package/src/runtime/client/stream.js +3 -2
  117. package/src/runtime/client/types.d.ts +13 -9
  118. package/src/runtime/client/utils.js +22 -110
  119. package/src/runtime/components/root.svelte +56 -0
  120. package/src/runtime/env/dynamic/private.js +7 -0
  121. package/src/runtime/env/dynamic/public.js +7 -0
  122. package/src/runtime/env/static/private.js +6 -0
  123. package/src/runtime/env/static/public.js +6 -0
  124. package/src/runtime/form-utils.js +172 -61
  125. package/src/runtime/pathname.js +20 -32
  126. package/src/runtime/props.svelte.js +72 -0
  127. package/src/runtime/server/constants.js +0 -3
  128. package/src/runtime/server/cookie.js +70 -53
  129. package/src/runtime/server/csrf.js +65 -0
  130. package/src/runtime/server/data/index.js +48 -52
  131. package/src/runtime/server/dev.js +22 -0
  132. package/src/runtime/server/endpoint.js +3 -4
  133. package/src/runtime/server/env_module.js +0 -5
  134. package/src/runtime/server/errors.js +160 -0
  135. package/src/runtime/server/fetch.js +31 -38
  136. package/src/runtime/server/index.js +90 -64
  137. package/src/runtime/server/internal.js +71 -0
  138. package/src/runtime/server/page/actions.js +84 -64
  139. package/src/runtime/server/page/crypto.js +2 -2
  140. package/src/runtime/server/page/csp.js +88 -104
  141. package/src/runtime/server/page/data_serializer.js +22 -23
  142. package/src/runtime/server/page/index.js +35 -53
  143. package/src/runtime/server/page/load_data.js +47 -54
  144. package/src/runtime/server/page/render.js +172 -238
  145. package/src/runtime/server/page/respond_with_error.js +16 -30
  146. package/src/runtime/server/page/serialize_data.js +2 -13
  147. package/src/runtime/server/page/server_routing.js +85 -26
  148. package/src/runtime/server/remote-functions.js +639 -0
  149. package/src/runtime/server/respond.js +188 -129
  150. package/src/runtime/server/sourcemaps.js +183 -0
  151. package/src/runtime/server/state.js +53 -0
  152. package/src/runtime/server/utils.js +12 -154
  153. package/src/runtime/shared.js +20 -40
  154. package/src/runtime/utils.js +3 -0
  155. package/src/types/ambient-private.d.ts +11 -1
  156. package/src/types/ambient.d.ts +87 -36
  157. package/src/types/global-private.d.ts +25 -25
  158. package/src/types/internal.d.ts +160 -150
  159. package/src/types/private.d.ts +41 -1
  160. package/src/utils/error.js +28 -4
  161. package/src/utils/escape.js +9 -25
  162. package/src/utils/features.js +1 -1
  163. package/src/utils/filesystem.js +1 -23
  164. package/src/utils/fork.js +7 -2
  165. package/src/utils/hash.js +21 -0
  166. package/src/utils/http.js +8 -7
  167. package/src/utils/import.js +9 -2
  168. package/src/utils/imports.js +83 -0
  169. package/src/utils/mime.js +9 -0
  170. package/src/utils/page_nodes.js +6 -7
  171. package/src/utils/params.js +67 -0
  172. package/src/utils/regex.js +9 -0
  173. package/src/utils/routing.js +145 -73
  174. package/src/utils/shared-iterator.js +5 -0
  175. package/src/utils/streaming.js +14 -4
  176. package/src/utils/url.js +33 -2
  177. package/src/version.js +1 -1
  178. package/types/index.d.ts +2291 -2135
  179. package/types/index.d.ts.map +116 -108
  180. package/src/core/sync/write_ambient.js +0 -18
  181. package/src/core/sync/write_root.js +0 -148
  182. package/src/core/sync/write_tsconfig.js +0 -250
  183. package/src/exports/internal/server.js +0 -22
  184. package/src/exports/node/polyfills.js +0 -30
  185. package/src/runtime/server/app.js +0 -9
  186. package/src/runtime/server/remote.js +0 -457
  187. package/src/runtime/shared-server.js +0 -7
  188. package/src/runtime/telemetry/otel.js +0 -21
  189. package/src/runtime/telemetry/record_span.js +0 -65
  190. package/src/types/synthetic/$lib.md +0 -5
  191. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
  192. /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
@@ -6,10 +6,10 @@ export const sveltekit_env_public_client = '\0virtual:__sveltekit/env/public/cli
6
6
  export const sveltekit_env_public_server = '\0virtual:__sveltekit/env/public/server';
7
7
  export const sveltekit_env_private = '\0virtual:__sveltekit/env/private';
8
8
  export const sveltekit_env_service_worker = '\0virtual:__sveltekit/env/service-worker';
9
-
9
+ export const sveltekit_server = '\0virtual:__sveltekit/server';
10
10
  export const service_worker = '\0virtual:service-worker';
11
11
 
12
- export const sveltekit_server = '\0virtual:__sveltekit/server';
12
+ export const sveltekit_manifest_data = '\0virtual:__sveltekit/manifest-data';
13
13
 
14
14
  export const app_server = posixify(
15
15
  fileURLToPath(new URL('../../runtime/app/server/index.js', import.meta.url))
@@ -1,24 +1,23 @@
1
+ /** @import { NextHandleFunction } from 'connect' */
2
+ /** @import { PreviewServer, ResolvedConfig } from 'vite' */
3
+ /** @import { ValidatedConfig, ServerInternalModule, ServerModule } from 'types' */
1
4
  import fs from 'node:fs';
2
5
  import { join } from 'node:path';
3
6
  import { pathToFileURL } from 'node:url';
4
- import { lookup } from 'mrmime';
7
+ import { lookup } from '../../../utils/mime.js';
5
8
  import sirv from 'sirv';
6
9
  import { loadEnv, normalizePath } from 'vite';
7
10
  import { createReadableStream, getRequest, setResponse } from '../../../exports/node/index.js';
8
11
  import { SVELTE_KIT_ASSETS } from '../../../constants.js';
9
12
  import { is_chrome_devtools_request, not_found } from '../utils.js';
10
-
11
- /** @typedef {import('http').IncomingMessage} Req */
12
- /** @typedef {import('http').ServerResponse} Res */
13
- /** @typedef {(req: Req, res: Res, next: () => void) => void} Handler */
13
+ import { stackless } from '../../../utils/error.js';
14
14
 
15
15
  /**
16
- * @param {import('vite').PreviewServer} vite
17
- * @param {import('vite').ResolvedConfig} vite_config
18
- * @param {import('types').ValidatedConfig} svelte_config
19
- * @param {import('@sveltejs/kit').Adapter | undefined} adapter
16
+ * @param {PreviewServer} vite
17
+ * @param {ResolvedConfig} vite_config
18
+ * @param {ValidatedConfig} svelte_config
20
19
  */
21
- export async function preview(vite, vite_config, svelte_config, adapter) {
20
+ export async function preview(vite, vite_config, svelte_config) {
22
21
  const { paths } = svelte_config.kit;
23
22
  const base = paths.base;
24
23
  const assets = paths.assets ? SVELTE_KIT_ASSETS : paths.base;
@@ -29,8 +28,8 @@ export async function preview(vite, vite_config, svelte_config, adapter) {
29
28
 
30
29
  const dir = join(svelte_config.kit.outDir, 'output/server');
31
30
 
32
- if (!fs.existsSync(dir)) {
33
- throw new Error(`Server files not found at ${dir}, did you run \`build\` first?`);
31
+ if (!fs.existsSync(`${dir}/manifest.js`)) {
32
+ throw stackless(`Server files not found at ${dir}, did you run \`build\` first?`);
34
33
  }
35
34
 
36
35
  const instrumentation = join(dir, 'instrumentation.server.js');
@@ -38,10 +37,10 @@ export async function preview(vite, vite_config, svelte_config, adapter) {
38
37
  await import(pathToFileURL(instrumentation).href);
39
38
  }
40
39
 
41
- /** @type {import('types').ServerInternalModule} */
40
+ /** @type {ServerInternalModule} */
42
41
  const { set_assets } = await import(pathToFileURL(join(dir, 'internal.js')).href);
43
42
 
44
- /** @type {import('types').ServerModule} */
43
+ /** @type {ServerModule} */
45
44
  const { Server } = await import(pathToFileURL(join(dir, 'index.js')).href);
46
45
 
47
46
  const { manifest } = await import(pathToFileURL(join(dir, 'manifest.js')).href);
@@ -49,12 +48,21 @@ export async function preview(vite, vite_config, svelte_config, adapter) {
49
48
  set_assets(assets);
50
49
 
51
50
  const server = new Server(manifest);
52
- await server.init({
53
- env: loadEnv(vite_config.mode, svelte_config.kit.env.dir, ''),
54
- read: (file) => createReadableStream(`${dir}/${file}`)
55
- });
56
51
 
57
- const emulator = await adapter?.emulate?.();
52
+ try {
53
+ await server.init({
54
+ env: loadEnv(vite_config.mode, svelte_config.kit.env.dir, ''),
55
+ read: (file) => createReadableStream(`${dir}/${file}`)
56
+ });
57
+ } catch (error) {
58
+ // Vite erases the error message when starting the preview server so we store
59
+ // it in the stack instead. This ensures errors thrown using `stackless`
60
+ // are still readable
61
+ if (error instanceof Error) error.stack = error.message;
62
+ throw error;
63
+ }
64
+
65
+ const emulator = await svelte_config.kit.adapter?.emulate?.();
58
66
 
59
67
  return () => {
60
68
  // Remove the base middleware. It screws with the URL.
@@ -196,12 +204,12 @@ export async function preview(vite, vite_config, svelte_config, adapter) {
196
204
  vite.middlewares.use(async (req, res) => {
197
205
  const host = req.headers[':authority'] || req.headers.host;
198
206
 
199
- const request = await getRequest({
207
+ const request = getRequest({
200
208
  base: `${protocol}://${host}`,
201
209
  request: req
202
210
  });
203
211
 
204
- await setResponse(
212
+ setResponse(
205
213
  res,
206
214
  await server.respond(request, {
207
215
  getClientAddress: () => {
@@ -225,7 +233,7 @@ export async function preview(vite, vite_config, svelte_config, adapter) {
225
233
 
226
234
  /**
227
235
  * @param {string} dir
228
- * @returns {Handler}
236
+ * @returns {NextHandleFunction}
229
237
  */
230
238
  const mutable = (dir) =>
231
239
  fs.existsSync(dir)
@@ -237,8 +245,8 @@ const mutable = (dir) =>
237
245
 
238
246
  /**
239
247
  * @param {string} scope
240
- * @param {Handler} handler
241
- * @returns {Handler}
248
+ * @param {NextHandleFunction} handler
249
+ * @returns {NextHandleFunction}
242
250
  */
243
251
  function scoped(scope, handler) {
244
252
  if (scope === '') return handler;
@@ -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
16
  * @param {import('types').ValidatedKitConfig} 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';