@sveltejs/kit 3.0.0-next.1 → 3.0.0-next.11

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 (144) hide show
  1. package/package.json +33 -21
  2. package/src/constants.js +2 -0
  3. package/src/core/adapt/builder.js +32 -49
  4. package/src/core/adapt/index.js +1 -4
  5. package/src/core/config/index.js +137 -71
  6. package/src/core/config/options.js +236 -244
  7. package/src/core/config/types.d.ts +1 -1
  8. package/src/core/env.js +121 -5
  9. package/src/core/generate_manifest/index.js +12 -15
  10. package/src/core/postbuild/analyse.js +7 -19
  11. package/src/core/postbuild/crawl.js +22 -6
  12. package/src/core/postbuild/fallback.js +2 -1
  13. package/src/core/postbuild/prerender.js +114 -48
  14. package/src/core/postbuild/queue.js +2 -1
  15. package/src/core/sync/create_manifest_data/index.js +53 -50
  16. package/src/core/sync/sync.js +0 -2
  17. package/src/core/sync/write_client_manifest.js +8 -15
  18. package/src/core/sync/write_env.js +2 -1
  19. package/src/core/sync/write_non_ambient.js +12 -9
  20. package/src/core/sync/write_server.js +14 -15
  21. package/src/core/sync/write_tsconfig.js +16 -8
  22. package/src/core/sync/write_tsconfig_test/package.json +7 -0
  23. package/src/core/sync/write_types/index.js +28 -24
  24. package/src/core/utils.js +30 -5
  25. package/src/exports/env/index.js +77 -0
  26. package/src/exports/hooks/index.js +3 -9
  27. package/src/exports/hooks/sequence.js +3 -2
  28. package/src/exports/index.js +35 -13
  29. package/src/exports/internal/client.js +5 -0
  30. package/src/exports/internal/env.js +8 -5
  31. package/src/exports/internal/index.js +1 -90
  32. package/src/exports/internal/{event.js → server/event.js} +1 -2
  33. package/src/exports/internal/server/index.js +33 -0
  34. package/src/exports/internal/shared.js +89 -0
  35. package/src/exports/node/index.js +62 -15
  36. package/src/exports/params.js +68 -0
  37. package/src/exports/public.d.ts +363 -189
  38. package/src/exports/url.js +86 -0
  39. package/src/exports/vite/build/build_server.js +53 -59
  40. package/src/exports/vite/build/remote.js +18 -11
  41. package/src/exports/vite/build/utils.js +0 -8
  42. package/src/exports/vite/dev/index.js +92 -50
  43. package/src/exports/vite/index.js +903 -681
  44. package/src/exports/vite/module_ids.js +0 -2
  45. package/src/exports/vite/preview/index.js +32 -24
  46. package/src/exports/vite/static_analysis/index.js +2 -4
  47. package/src/exports/vite/static_analysis/types.d.ts +14 -0
  48. package/src/exports/vite/utils.js +40 -35
  49. package/src/runtime/app/env/internal.js +4 -4
  50. package/src/runtime/app/env/types.d.ts +1 -1
  51. package/src/runtime/app/environment/index.js +3 -3
  52. package/src/runtime/app/forms.js +24 -7
  53. package/src/runtime/app/paths/client.js +4 -10
  54. package/src/runtime/app/paths/internal/client.js +4 -2
  55. package/src/runtime/app/paths/internal/server.js +2 -23
  56. package/src/runtime/app/paths/public.d.ts +0 -28
  57. package/src/runtime/app/paths/server.js +10 -6
  58. package/src/runtime/app/server/index.js +1 -1
  59. package/src/runtime/app/server/remote/command.js +0 -3
  60. package/src/runtime/app/server/remote/form.js +27 -15
  61. package/src/runtime/app/server/remote/prerender.js +29 -36
  62. package/src/runtime/app/server/remote/query.js +101 -99
  63. package/src/runtime/app/server/remote/requested.js +22 -14
  64. package/src/runtime/app/server/remote/shared.js +30 -26
  65. package/src/runtime/app/state/client.js +1 -2
  66. package/src/runtime/app/stores.js +13 -76
  67. package/src/runtime/client/bundle.js +1 -1
  68. package/src/runtime/client/client-entry.js +3 -0
  69. package/src/runtime/client/client.js +411 -318
  70. package/src/runtime/client/entry.js +24 -3
  71. package/src/runtime/client/fetcher.js +3 -2
  72. package/src/runtime/client/ndjson.js +6 -33
  73. package/src/runtime/client/payload.js +17 -0
  74. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  75. package/src/runtime/client/remote-functions/command.svelte.js +7 -32
  76. package/src/runtime/client/remote-functions/form.svelte.js +183 -112
  77. package/src/runtime/client/remote-functions/prerender.svelte.js +29 -8
  78. package/src/runtime/client/remote-functions/query/index.js +7 -14
  79. package/src/runtime/client/remote-functions/query/instance.svelte.js +63 -18
  80. package/src/runtime/client/remote-functions/query/proxy.js +3 -3
  81. package/src/runtime/client/remote-functions/query-batch.svelte.js +60 -68
  82. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +60 -18
  83. package/src/runtime/client/remote-functions/query-live/iterator.js +36 -55
  84. package/src/runtime/client/remote-functions/shared.svelte.js +88 -62
  85. package/src/runtime/client/sse.js +32 -0
  86. package/src/runtime/client/state.svelte.js +65 -49
  87. package/src/runtime/client/stream.js +39 -0
  88. package/src/runtime/client/types.d.ts +11 -7
  89. package/src/runtime/client/utils.js +0 -96
  90. package/src/runtime/components/root.svelte +66 -0
  91. package/src/runtime/env/dynamic/private.js +7 -0
  92. package/src/runtime/env/dynamic/public.js +7 -0
  93. package/src/runtime/env/static/private.js +6 -0
  94. package/src/runtime/env/static/public.js +6 -0
  95. package/src/runtime/form-utils.js +100 -22
  96. package/src/runtime/server/cookie.js +69 -52
  97. package/src/runtime/server/csrf.js +65 -0
  98. package/src/runtime/server/data/index.js +15 -19
  99. package/src/runtime/server/env_module.js +0 -5
  100. package/src/runtime/server/errors.js +135 -0
  101. package/src/runtime/server/fetch.js +1 -1
  102. package/src/runtime/server/index.js +22 -12
  103. package/src/runtime/server/internal.js +25 -0
  104. package/src/runtime/server/page/actions.js +43 -27
  105. package/src/runtime/server/page/data_serializer.js +10 -10
  106. package/src/runtime/server/page/index.js +12 -17
  107. package/src/runtime/server/page/load_data.js +2 -2
  108. package/src/runtime/server/page/render.js +114 -193
  109. package/src/runtime/server/page/respond_with_error.js +11 -11
  110. package/src/runtime/server/page/server_routing.js +27 -18
  111. package/src/runtime/server/remote-functions.js +596 -0
  112. package/src/runtime/server/respond.js +100 -68
  113. package/src/runtime/server/sourcemaps.js +183 -0
  114. package/src/runtime/server/utils.js +2 -134
  115. package/src/runtime/shared.js +83 -13
  116. package/src/runtime/telemetry/otel.js +1 -1
  117. package/src/runtime/types.d.ts +8 -0
  118. package/src/types/ambient-private.d.ts +2 -0
  119. package/src/types/ambient.d.ts +10 -5
  120. package/src/types/global-private.d.ts +13 -25
  121. package/src/types/internal.d.ts +95 -80
  122. package/src/types/private.d.ts +41 -1
  123. package/src/utils/error.js +24 -4
  124. package/src/utils/escape.js +9 -25
  125. package/src/utils/features.js +1 -1
  126. package/src/utils/fork.js +7 -2
  127. package/src/utils/import.js +6 -1
  128. package/src/utils/imports.js +83 -0
  129. package/src/utils/mime.js +9 -0
  130. package/src/utils/page_nodes.js +3 -5
  131. package/src/utils/params.js +66 -0
  132. package/src/utils/routing.js +90 -44
  133. package/src/utils/shared-iterator.js +5 -0
  134. package/src/utils/streaming.js +14 -4
  135. package/src/utils/url.js +20 -2
  136. package/src/version.js +1 -1
  137. package/types/index.d.ts +537 -557
  138. package/types/index.d.ts.map +24 -39
  139. package/src/core/sync/write_root.js +0 -148
  140. package/src/exports/internal/server.js +0 -22
  141. package/src/runtime/server/remote.js +0 -457
  142. package/src/runtime/shared-server.js +0 -7
  143. package/src/types/synthetic/$lib.md +0 -5
  144. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
package/src/core/env.js CHANGED
@@ -38,6 +38,7 @@ export async function load_explicit_env(kit, file, root, mode) {
38
38
  logLevel: 'silent',
39
39
  mode,
40
40
  define: {
41
+ __SVELTEKIT_PAYLOAD__: 'undefined', // coming in through static import in env/internal.js but will end up unused
41
42
  __SVELTEKIT_APP_VERSION__: JSON.stringify(kit.version.name) // needed by $app/env
42
43
  },
43
44
  resolve: {
@@ -51,6 +52,10 @@ export async function load_explicit_env(kit, file, root, mode) {
51
52
  /** @type {Record<string, EnvVarConfig<any>>} */
52
53
  let variables;
53
54
 
55
+ /** @type {import('../runtime/app/env/internal.js')} */ (
56
+ await server.ssrLoadModule(`${runtime_directory}/app/env/internal.js`)
57
+ ).set_building();
58
+
54
59
  try {
55
60
  ({ variables } = await server.ssrLoadModule(file));
56
61
 
@@ -87,11 +92,12 @@ export async function load_explicit_env(kit, file, root, mode) {
87
92
 
88
93
  /**
89
94
  * Creates the `__sveltekit/env` module
90
- * @param {Record<string, EnvVarConfig<any>> | null} variables
95
+ * @param {Record<string, EnvVarConfig<any> | undefined> | null} variables
91
96
  * @param {Record<string, string>} env
92
97
  * @param {string | null} entry
98
+ * @param {boolean} is_dev
93
99
  */
94
- export function create_sveltekit_env(variables, env, entry) {
100
+ export function create_sveltekit_env(variables, env, entry, is_dev) {
95
101
  const imports = entry
96
102
  ? [
97
103
  `import { variables } from ${JSON.stringify(entry)};`,
@@ -106,7 +112,7 @@ export function create_sveltekit_env(variables, env, entry) {
106
112
  const issues = {};
107
113
 
108
114
  for (const [name, config] of Object.entries(variables ?? {})) {
109
- if (config.static) {
115
+ if (config?.static) {
110
116
  if (config.public) {
111
117
  const value = validate(variables ?? {}, env[name], name, issues);
112
118
  declarations.push(`explicit_public_env.${name} = ${devalue.uneval(value)};`);
@@ -116,7 +122,7 @@ export function create_sveltekit_env(variables, env, entry) {
116
122
  `const ${name} = validate(variables, env.${name}, ${JSON.stringify(name)}, issues);`
117
123
  );
118
124
 
119
- if (config.public) {
125
+ if (config?.public) {
120
126
  setters.push(`explicit_public_env.${name} = ${name};`);
121
127
  setters.push(`rendered_env.${name} = ${name};`);
122
128
  } else {
@@ -145,6 +151,19 @@ export function create_sveltekit_env(variables, env, entry) {
145
151
  }`
146
152
  ];
147
153
 
154
+ // In dev, initialise the env immediately. Tools like `vite-node` load modules
155
+ // through the Vite config but don't run the SvelteKit dev server, which is what
156
+ // normally calls `set_env`. Without this, dynamic env vars imported from
157
+ // `$app/env/public` and `$app/env/private` would be `undefined` in such contexts.
158
+ if (is_dev) {
159
+ /** @type {Record<string, string>} */
160
+ const dev_env = {};
161
+ for (const name of Object.keys(variables ?? {})) {
162
+ if (name in env) dev_env[name] = env[name];
163
+ }
164
+ blocks.push(`set_env(${devalue.uneval(dev_env)});`);
165
+ }
166
+
148
167
  const module = blocks.join('\n\n');
149
168
 
150
169
  return module;
@@ -213,9 +232,36 @@ export function create_sveltekit_env_public(variables, env, prelude) {
213
232
  return `${prelude}\n\n${exports.join('')}`;
214
233
  }
215
234
 
235
+ /**
236
+ * Creates the `__sveltekit/env/service-worker` module used in production. When an app uses
237
+ * dynamic public env vars, they're loaded at runtime via an import of the prerendered
238
+ * `env.js`. If there are none, values are inlined.
239
+ * @param {Record<string, EnvVarConfig<any>> | null} variables
240
+ * @param {Record<string, string>} env
241
+ * @param {string} global
242
+ * @param {string} base
243
+ * @param {string} app_dir
244
+ */
245
+ export function create_sveltekit_env_service_worker(variables, env, global, base, app_dir) {
246
+ const has_dynamic_public_env = Object.values(variables ?? {}).some(
247
+ (config) => config.public && !config.static
248
+ );
249
+
250
+ if (!has_dynamic_public_env) {
251
+ return create_sveltekit_env_service_worker_dev(variables, env, global);
252
+ }
253
+
254
+ return dedent`
255
+ import { env } from '${base}/${app_dir}/env.js';
256
+
257
+ globalThis.__SVELTEKIT_EXPERIMENTAL_EXPLICIT_ENVIRONMENT_VARIABLES__ = true;
258
+
259
+ ${global} = { env };
260
+ `;
261
+ }
262
+
216
263
  /**
217
264
  * Creates the `__sveltekit/env/service-worker` module used in development
218
- * (but not in prod, which goes through build_service_worker instead)
219
265
  * @param {Record<string, EnvVarConfig<any>> | null} variables
220
266
  * @param {Record<string, string>} env
221
267
  * @param {string} global
@@ -330,3 +376,73 @@ export const reserved = new Set([
330
376
  ]);
331
377
 
332
378
  export const valid_identifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
379
+
380
+ /**
381
+ * Generates `export const` declarations (and, for reserved-word names that need
382
+ * aliasing, `const` + re-export specifiers) for a set of named exports.
383
+ *
384
+ * For regular names, emits a single efficient `export const name = expr;` statement.
385
+ * For reserved-word names (e.g. `delete`, `class`), emits `const alias = expr;` plus
386
+ * a re-export specifier (`alias as name`), since reserved words can't be `const`
387
+ * binding names but CAN appear in export specifiers.
388
+ *
389
+ * You can do evil things like `export { c as class }`. In order to import/re-export
390
+ * these, you need to alias the binding, then un-alias it when re-exporting:
391
+ *
392
+ * const _0 = ...; // safe binding name
393
+ * export { _0 as class }; // valid — `class` is allowed in export specifiers
394
+ *
395
+ * Aliases are chosen to avoid collisions with any of the supplied names. The
396
+ * namespace binding (used to hold the imported module) is likewise chosen to
397
+ * avoid collisions.
398
+ *
399
+ * @param {Iterable<string>} names — the export names
400
+ * @param {(name: string, namespace: string) => string} build_expression —
401
+ * called for each name to produce the right-hand side of the declaration;
402
+ * receives the chosen namespace binding so it can reference the imported module
403
+ * @param {string} namespace_prefix — the preferred binding name for the namespace
404
+ * (suffixed with a number if it collides with any export name)
405
+ * @returns {{ namespace: string, declarations: string[], reexports: string[] }}
406
+ */
407
+ export function create_exported_declarations(names, build_expression, namespace_prefix) {
408
+ /** @type {Set<string>} */
409
+ const set = new Set(names);
410
+
411
+ let namespace = namespace_prefix;
412
+ let namespace_index = 0;
413
+ while (set.has(namespace)) {
414
+ namespace = `${namespace_prefix}${namespace_index++}`;
415
+ }
416
+
417
+ let alias_index = 0;
418
+ /** @type {Map<string, string>} */
419
+ const aliases = new Map();
420
+
421
+ for (const name of set) {
422
+ if (!reserved.has(name)) continue;
423
+
424
+ let alias = `_${alias_index++}`;
425
+ while (set.has(alias)) {
426
+ alias = `_${alias_index++}`;
427
+ }
428
+ aliases.set(name, alias);
429
+ }
430
+
431
+ /** @type {string[]} */
432
+ const declarations = [];
433
+ /** @type {string[]} */
434
+ const reexports = [];
435
+
436
+ for (const name of set) {
437
+ const alias = aliases.get(name);
438
+ const expr = build_expression(name, namespace);
439
+ if (alias) {
440
+ declarations.push(`const ${alias} = ${expr};`);
441
+ reexports.push(`${alias} as ${name}`);
442
+ } else {
443
+ declarations.push(`export const ${name} = ${expr};`);
444
+ }
445
+ }
446
+
447
+ return { namespace, declarations, reexports };
448
+ }
@@ -1,7 +1,7 @@
1
1
  /** @import { RemoteChunk } from 'types' */
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import * as mime from 'mrmime';
4
+ import { lookup as mime_lookup } from '../../utils/mime.js';
5
5
  import { s } from '../../utils/misc.js';
6
6
  import { get_mime_lookup } from '../utils.js';
7
7
  import { resolve_symlinks } from '../../exports/vite/build/utils.js';
@@ -69,10 +69,8 @@ export function generate_manifest({
69
69
  assets.push(build_data.service_worker);
70
70
  }
71
71
 
72
- // In case of server-side route resolution, we need to include all matchers. Prerendered routes are not part
73
- // of the server manifest, and they could reference matchers that then would not be included.
74
- const matchers = new Set(
75
- build_data.client?.nodes ? Object.keys(build_data.manifest_data.matchers) : undefined
72
+ const uses_matchers = build_data.manifest_data.routes.some((route) =>
73
+ route.params.some((param) => param.matcher)
76
74
  );
77
75
 
78
76
  /** @param {Array<number | undefined>} indexes */
@@ -93,7 +91,7 @@ export function generate_manifest({
93
91
  files[file] = fs.statSync(path.resolve(build_data.out_dir, 'server', file)).size;
94
92
 
95
93
  const ext = path.extname(file);
96
- mime_types[ext] ??= mime.lookup(ext) || '';
94
+ mime_types[ext] ??= mime_lookup(ext) || '';
97
95
  }
98
96
 
99
97
  // prettier-ignore
@@ -117,10 +115,6 @@ export function generate_manifest({
117
115
  ${routes.map(route => {
118
116
  if (!route.page && !route.endpoint) return;
119
117
 
120
- route.params.forEach(param => {
121
- if (param.matcher) matchers.add(param.matcher);
122
- });
123
-
124
118
  return dedent`
125
119
  {
126
120
  id: ${s(route.id)},
@@ -134,11 +128,14 @@ export function generate_manifest({
134
128
  ],
135
129
  prerendered_routes: new Set(${s(prerendered)}),
136
130
  matchers: async () => {
137
- ${Array.from(
138
- matchers,
139
- type => `const { match: ${type} } = await import ('${(join_relative(relative_path, `/entries/matchers/${type}.js`))}')`
140
- ).join('\n')}
141
- return { ${Array.from(matchers).join(', ')} };
131
+ ${
132
+ uses_matchers && build_data.manifest_data.params
133
+ ? dedent`
134
+ const { params } = await import('${join_relative(relative_path, '/entries/params.js')}');
135
+ return params;
136
+ `
137
+ : 'return {};'
138
+ }
142
139
  },
143
140
  server_assets: ${s(files)}
144
141
  }
@@ -1,4 +1,3 @@
1
- /** @import { Adapter } from '@sveltejs/kit' */
2
1
  /** @import { RemoteChunk } from 'types' */
3
2
  import { join } from 'node:path';
4
3
  import { pathToFileURL } from 'node:url';
@@ -10,7 +9,6 @@ import { has_server_load, resolve_route } from '../../utils/routing.js';
10
9
  import { check_feature } from '../../utils/features.js';
11
10
  import { createReadableStream } from '@sveltejs/kit/node';
12
11
  import { PageNodes } from '../../utils/page_nodes.js';
13
- import { build_server_nodes } from '../../exports/vite/build/build_server.js';
14
12
 
15
13
  export default forked(import.meta.url, analyse);
16
14
 
@@ -22,9 +20,7 @@ export default forked(import.meta.url, analyse);
22
20
  * server_manifest: import('vite').Manifest;
23
21
  * tracked_features: Record<string, string[]>;
24
22
  * env: Record<string, string>;
25
- * out: string;
26
23
  * remotes: RemoteChunk[];
27
- * root: string;
28
24
  * vite_config_file: string | undefined;
29
25
  * }} opts
30
26
  */
@@ -35,24 +31,14 @@ async function analyse({
35
31
  server_manifest,
36
32
  tracked_features,
37
33
  env,
38
- out,
39
34
  remotes,
40
- root,
41
35
  vite_config_file
42
36
  }) {
43
37
  /** @type {import('@sveltejs/kit').SSRManifest} */
44
38
  const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
45
39
 
46
40
  const vite_config = await load_vite_config(vite_config_file);
47
-
48
41
  const config = extract_svelte_config(vite_config).kit;
49
-
50
- // TODO i think this can just be config.adapter?
51
- /** @type {Adapter | undefined} */
52
- const adapter = vite_config.plugins.find(
53
- (plugin) => plugin.name === 'vite-plugin-sveltekit-adapter'
54
- )?.api?.adapter;
55
-
56
42
  const server_root = join(config.outDir, 'output');
57
43
 
58
44
  /** @type {import('types').ServerInternalModule} */
@@ -62,13 +48,15 @@ async function analyse({
62
48
  // essential we do this before analysing the code
63
49
  internal.set_building();
64
50
 
65
- // set env, `read`, and `manifest`, in case they're used in initialisation
66
- internal.set_env(env);
51
+ // set `read` and `manifest`, in case they're used in initialisation
67
52
  internal.set_manifest(manifest);
68
53
  internal.set_read_implementation((file) => createReadableStream(`${server_root}/server/${file}`));
69
54
 
70
- // first, build server nodes without the client manifest so we can analyse it
71
- build_server_nodes(out, config, manifest_data, server_manifest, null, null, null, root);
55
+ // `set_env` lives in a separate module that imports the user's `src/env` config. We import it
56
+ // *after* `set_building()` so that `building`-dependent expressions resolve correctly
57
+ /** @type {import('__sveltekit/env')} */
58
+ const { set_env } = await import(pathToFileURL(`${server_root}/server/env.js`).href);
59
+ set_env(env);
72
60
 
73
61
  /** @type {import('types').ServerMetadata} */
74
62
  const metadata = {
@@ -134,7 +122,7 @@ async function analyse({
134
122
  server_manifest,
135
123
  tracked_features
136
124
  )) {
137
- check_feature(route.id, route_config, feature, adapter);
125
+ check_feature(route.id, route_config, feature, config.adapter);
138
126
  }
139
127
  }
140
128
 
@@ -38,6 +38,18 @@ export function crawl(html, base) {
38
38
  /** @type {string[]} */
39
39
  const hrefs = [];
40
40
 
41
+ /** @type {string[]} */
42
+ const invalid = [];
43
+
44
+ /** @param {string} url */
45
+ const push_href = (url) => {
46
+ try {
47
+ hrefs.push(resolve(base, url));
48
+ } catch {
49
+ invalid.push(url);
50
+ }
51
+ };
52
+
41
53
  let i = 0;
42
54
  main: while (i < html.length) {
43
55
  const char = html[i];
@@ -186,9 +198,13 @@ export function crawl(html, base) {
186
198
 
187
199
  if (href) {
188
200
  if (tag === 'BASE') {
189
- base = resolve(base, href);
201
+ try {
202
+ base = resolve(base, href);
203
+ } catch {
204
+ invalid.push(href);
205
+ }
190
206
  } else if (!rel || !/\bexternal\b/i.test(rel)) {
191
- hrefs.push(resolve(base, href));
207
+ push_href(href);
192
208
  }
193
209
  }
194
210
 
@@ -201,7 +217,7 @@ export function crawl(html, base) {
201
217
  }
202
218
 
203
219
  if (src) {
204
- hrefs.push(resolve(base, src));
220
+ push_href(src);
205
221
  }
206
222
 
207
223
  if (srcset) {
@@ -222,7 +238,7 @@ export function crawl(html, base) {
222
238
  candidates.push(value);
223
239
  for (const candidate of candidates) {
224
240
  const src = candidate.split(WHITESPACE)[0];
225
- if (src) hrefs.push(resolve(base, src));
241
+ if (src) push_href(src);
226
242
  }
227
243
  }
228
244
 
@@ -230,7 +246,7 @@ export function crawl(html, base) {
230
246
  const attr = name ?? property;
231
247
 
232
248
  if (attr && CRAWLABLE_META_NAME_ATTRS.has(attr)) {
233
- hrefs.push(resolve(base, content));
249
+ push_href(content);
234
250
  }
235
251
  }
236
252
  }
@@ -239,5 +255,5 @@ export function crawl(html, base) {
239
255
  i += 1;
240
256
  }
241
257
 
242
- return { ids, hrefs };
258
+ return { ids, hrefs, invalid };
243
259
  }
@@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import { forked } from '../../utils/fork.js';
5
+ import { stackless } from '../../utils/error.js';
5
6
 
6
7
  export default forked(import.meta.url, generate_fallback);
7
8
 
@@ -47,5 +48,5 @@ async function generate_fallback({ manifest_path, env, out_dir, origin, assets }
47
48
  return await response.text();
48
49
  }
49
50
 
50
- throw new Error(`Could not create a fallback page — failed with status ${response.status}`);
51
+ throw stackless('Could not create a fallback page');
51
52
  }