astro 4.13.4 → 4.14.1

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 (98) hide show
  1. package/components/Code.astro +9 -0
  2. package/dist/@types/astro.d.ts +249 -1
  3. package/dist/actions/consts.d.ts +1 -1
  4. package/dist/actions/consts.js +1 -1
  5. package/dist/actions/index.js +12 -21
  6. package/dist/assets/endpoint/node.js +1 -1
  7. package/dist/assets/utils/resolveImports.d.ts +9 -0
  8. package/dist/assets/utils/resolveImports.js +22 -0
  9. package/dist/cli/add/index.d.ts +2 -2
  10. package/dist/cli/add/index.js +2 -2
  11. package/dist/cli/build/index.d.ts +2 -2
  12. package/dist/cli/build/index.js +5 -1
  13. package/dist/cli/check/index.d.ts +2 -2
  14. package/dist/cli/check/index.js +5 -2
  15. package/dist/cli/db/index.d.ts +4 -3
  16. package/dist/cli/db/index.js +10 -3
  17. package/dist/cli/dev/index.d.ts +2 -2
  18. package/dist/cli/dev/index.js +1 -0
  19. package/dist/cli/docs/index.d.ts +2 -2
  20. package/dist/cli/flags.d.ts +3 -1
  21. package/dist/cli/flags.js +2 -1
  22. package/dist/cli/index.d.ts +1 -1
  23. package/dist/cli/index.js +26 -13
  24. package/dist/cli/info/index.d.ts +2 -2
  25. package/dist/cli/preferences/index.d.ts +2 -2
  26. package/dist/cli/preferences/index.js +1 -1
  27. package/dist/cli/preview/index.d.ts +2 -2
  28. package/dist/cli/sync/index.d.ts +2 -2
  29. package/dist/cli/sync/index.js +5 -2
  30. package/dist/cli/telemetry/index.d.ts +2 -2
  31. package/dist/content/consts.d.ts +16 -2
  32. package/dist/content/consts.js +32 -2
  33. package/dist/content/content-layer.d.ts +40 -0
  34. package/dist/content/content-layer.js +253 -0
  35. package/dist/content/data-store.d.ts +54 -0
  36. package/dist/content/data-store.js +72 -0
  37. package/dist/content/loaders/file.d.ts +7 -0
  38. package/dist/content/loaders/file.js +72 -0
  39. package/dist/content/loaders/glob.d.ts +25 -0
  40. package/dist/content/loaders/glob.js +218 -0
  41. package/dist/content/loaders/index.d.ts +3 -0
  42. package/dist/content/loaders/index.js +7 -0
  43. package/dist/content/loaders/types.d.ts +36 -0
  44. package/dist/content/loaders/types.js +0 -0
  45. package/dist/content/mutable-data-store.d.ts +77 -0
  46. package/dist/content/mutable-data-store.js +269 -0
  47. package/dist/content/runtime.d.ts +46 -8
  48. package/dist/content/runtime.js +225 -31
  49. package/dist/content/types-generator.js +123 -35
  50. package/dist/content/utils.d.ts +307 -2
  51. package/dist/content/utils.js +101 -7
  52. package/dist/content/vite-plugin-content-assets.js +9 -1
  53. package/dist/content/vite-plugin-content-virtual-mod.js +94 -2
  54. package/dist/core/build/index.js +14 -7
  55. package/dist/core/build/plugins/plugin-ssr.js +32 -4
  56. package/dist/core/config/config.d.ts +2 -5
  57. package/dist/core/config/config.js +0 -12
  58. package/dist/core/config/index.d.ts +1 -1
  59. package/dist/core/config/index.js +0 -2
  60. package/dist/core/config/schema.d.ts +34 -0
  61. package/dist/core/config/schema.js +6 -2
  62. package/dist/core/config/settings.js +5 -3
  63. package/dist/core/constants.js +1 -1
  64. package/dist/core/create-vite.js +1 -1
  65. package/dist/core/dev/container.js +2 -1
  66. package/dist/core/dev/dev.js +33 -3
  67. package/dist/core/dev/restart.js +25 -10
  68. package/dist/core/errors/errors-data.d.ts +21 -0
  69. package/dist/core/errors/errors-data.js +13 -0
  70. package/dist/core/index.js +1 -1
  71. package/dist/core/logger/vite.js +1 -1
  72. package/dist/core/messages.js +2 -2
  73. package/dist/core/preview/static-preview-server.js +1 -1
  74. package/dist/core/routing/manifest/create.js +1 -1
  75. package/dist/core/sync/constants.d.ts +1 -0
  76. package/dist/core/sync/constants.js +4 -0
  77. package/dist/core/sync/index.d.ts +12 -4
  78. package/dist/core/sync/index.js +54 -24
  79. package/dist/core/sync/write-files.d.ts +4 -0
  80. package/dist/core/sync/write-files.js +69 -0
  81. package/dist/core/util.js +1 -1
  82. package/dist/env/sync.js +6 -4
  83. package/dist/integrations/hooks.d.ts +7 -1
  84. package/dist/integrations/hooks.js +54 -0
  85. package/dist/preferences/index.d.ts +1 -1
  86. package/dist/preferences/index.js +2 -2
  87. package/dist/runtime/server/render/server-islands.js +6 -4
  88. package/dist/vite-plugin-astro-server/response.js +1 -1
  89. package/dist/vite-plugin-env/index.d.ts +3 -1
  90. package/dist/vite-plugin-env/index.js +11 -1
  91. package/dist/vite-plugin-markdown/content-entry-type.js +25 -2
  92. package/dist/vite-plugin-scanner/index.js +15 -5
  93. package/package.json +10 -5
  94. package/templates/content/module.mjs +6 -1
  95. package/templates/content/types.d.ts +18 -5
  96. package/types/content.d.ts +34 -1
  97. package/dist/core/sync/setup-env-ts.d.ts +0 -8
  98. package/dist/core/sync/setup-env-ts.js +0 -79
@@ -1,5 +1,6 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import * as vite from "vite";
3
+ import { globalContentLayer } from "../../content/content-layer.js";
3
4
  import { eventCliSession, telemetry } from "../../events/index.js";
4
5
  import { createNodeLogger, createSettings, resolveConfig } from "../config/index.js";
5
6
  import { collectErrorMetadata } from "../errors/dev/utils.js";
@@ -20,16 +21,18 @@ async function createRestartedContainer(container, settings) {
20
21
  return newContainer;
21
22
  }
22
23
  const configRE = /.*astro.config.(?:mjs|cjs|js|ts)$/;
23
- const preferencesRE = /.*\.astro\/settings.json$/;
24
24
  function shouldRestartContainer({ settings, inlineConfig, restartInFlight }, changedFile) {
25
25
  if (restartInFlight) return false;
26
26
  let shouldRestart = false;
27
+ const normalizedChangedFile = vite.normalizePath(changedFile);
27
28
  if (inlineConfig.configFile) {
28
- shouldRestart = vite.normalizePath(inlineConfig.configFile) === vite.normalizePath(changedFile);
29
+ shouldRestart = vite.normalizePath(inlineConfig.configFile) === normalizedChangedFile;
29
30
  } else {
30
- const normalizedChangedFile = vite.normalizePath(changedFile);
31
31
  shouldRestart = configRE.test(normalizedChangedFile);
32
- if (preferencesRE.test(normalizedChangedFile)) {
32
+ const settingsPath = vite.normalizePath(
33
+ fileURLToPath(new URL("settings.json", settings.dotAstroDir))
34
+ );
35
+ if (settingsPath.endsWith(normalizedChangedFile)) {
33
36
  shouldRestart = settings.preferences.ignoreNextPreferenceReload ? false : true;
34
37
  settings.preferences.ignoreNextPreferenceReload = false;
35
38
  }
@@ -116,13 +119,25 @@ async function createContainerWithAutomaticRestart({
116
119
  watcher.on("unlink", handleChangeRestart("Configuration file removed."));
117
120
  watcher.on("add", handleChangeRestart("Configuration file added."));
118
121
  restart.container.viteServer.restart = () => handleServerRestart();
122
+ const customShortcuts = [
123
+ // Disable default Vite shortcuts that don't work well with Astro
124
+ { key: "r", description: "" },
125
+ { key: "u", description: "" },
126
+ { key: "c", description: "" }
127
+ ];
128
+ if (restart.container.settings.config.experimental.contentLayer) {
129
+ customShortcuts.push({
130
+ key: "s",
131
+ description: "sync content layer",
132
+ action: () => {
133
+ if (globalContentLayer.initialized()) {
134
+ globalContentLayer.get().sync();
135
+ }
136
+ }
137
+ });
138
+ }
119
139
  restart.container.viteServer.bindCLIShortcuts({
120
- customShortcuts: [
121
- // Disable Vite's builtin "r" (restart server), "u" (print server urls) and "c" (clear console) shortcuts
122
- { key: "r", description: "" },
123
- { key: "u", description: "" },
124
- { key: "c", description: "" }
125
- ]
140
+ customShortcuts
126
141
  });
127
142
  }
128
143
  setupContainer();
@@ -1151,6 +1151,16 @@ export declare const RewriteWithBodyUsed: {
1151
1151
  title: string;
1152
1152
  message: string;
1153
1153
  };
1154
+ /**
1155
+ * @docs
1156
+ * @description
1157
+ * An unknown error occurred while reading or writing files to disk. It can be caused by many things, eg. missing permissions or a file not existing we attempt to read.
1158
+ */
1159
+ export declare const UnknownFilesystemError: {
1160
+ name: string;
1161
+ title: string;
1162
+ hint: string;
1163
+ };
1154
1164
  /**
1155
1165
  * @docs
1156
1166
  * @kind heading
@@ -1320,6 +1330,17 @@ export declare const UnknownContentCollectionError: {
1320
1330
  name: string;
1321
1331
  title: string;
1322
1332
  };
1333
+ /**
1334
+ * @docs
1335
+ * @description
1336
+ * The `getDataEntryById` and `getEntryBySlug` functions are deprecated and cannot be used with content layer collections. Use the `getEntry` function instead.
1337
+ */
1338
+ export declare const GetEntryDeprecationError: {
1339
+ name: string;
1340
+ title: string;
1341
+ message: (collection: string, method: string) => string;
1342
+ hint: string;
1343
+ };
1323
1344
  /**
1324
1345
  * @docs
1325
1346
  * @message
@@ -419,6 +419,11 @@ const RewriteWithBodyUsed = {
419
419
  title: "Cannot use Astro.rewrite after the request body has been read",
420
420
  message: "Astro.rewrite() cannot be used if the request body has already been read. If you need to read the body, first clone the request."
421
421
  };
422
+ const UnknownFilesystemError = {
423
+ name: "UnknownFilesystemError",
424
+ title: "An unknown error occurred while reading or writing files to disk.",
425
+ hint: "It can be caused by many things, eg. missing permissions or a file not existing we attempt to read. Check the error cause for more details."
426
+ };
422
427
  const UnknownCSSError = {
423
428
  name: "UnknownCSSError",
424
429
  title: "Unknown CSS Error."
@@ -476,6 +481,12 @@ const UnknownContentCollectionError = {
476
481
  name: "UnknownContentCollectionError",
477
482
  title: "Unknown Content Collection Error."
478
483
  };
484
+ const GetEntryDeprecationError = {
485
+ name: "GetEntryDeprecationError",
486
+ title: "Invalid use of `getDataEntryById` or `getEntryBySlug` function.",
487
+ message: (collection, method) => `The \`${method}\` function is deprecated and cannot be used to query the "${collection}" collection. Use \`getEntry\` instead.`,
488
+ hint: "Use the `getEntry` or `getCollection` functions to query content layer collections."
489
+ };
479
490
  const InvalidContentEntryFrontmatterError = {
480
491
  name: "InvalidContentEntryFrontmatterError",
481
492
  title: "Content entry frontmatter does not match schema.",
@@ -602,6 +613,7 @@ export {
602
613
  FailedToFindPageMapSSR,
603
614
  FailedToLoadModuleSSR,
604
615
  GenerateContentTypesError,
616
+ GetEntryDeprecationError,
605
617
  GetStaticPathsExpectedParams,
606
618
  GetStaticPathsInvalidRouteParam,
607
619
  GetStaticPathsRemovedRSSHelper,
@@ -664,6 +676,7 @@ export {
664
676
  UnknownConfigError,
665
677
  UnknownContentCollectionError,
666
678
  UnknownError,
679
+ UnknownFilesystemError,
667
680
  UnknownMarkdownError,
668
681
  UnknownViteError,
669
682
  UnsupportedConfigTransformError,
@@ -3,7 +3,7 @@ import { default as _sync } from "./sync/index.js";
3
3
  import { default as default2 } from "./dev/index.js";
4
4
  import { default as default3 } from "./preview/index.js";
5
5
  const build = (inlineConfig) => _build(inlineConfig);
6
- const sync = (inlineConfig) => _sync({ inlineConfig });
6
+ const sync = (inlineConfig) => _sync(inlineConfig);
7
7
  export {
8
8
  build,
9
9
  default2 as dev,
@@ -1,4 +1,4 @@
1
- import { fileURLToPath } from "url";
1
+ import { fileURLToPath } from "node:url";
2
2
  import stripAnsi from "strip-ansi";
3
3
  import { isAstroError } from "../errors/errors.js";
4
4
  import { serverShortcuts as formatServerShortcuts } from "../messages.js";
@@ -38,7 +38,7 @@ function serverStart({
38
38
  host,
39
39
  base
40
40
  }) {
41
- const version = "4.13.4";
41
+ const version = "4.14.1";
42
42
  const localPrefix = `${dim("\u2503")} Local `;
43
43
  const networkPrefix = `${dim("\u2503")} Network `;
44
44
  const emptyPrefix = " ".repeat(11);
@@ -270,7 +270,7 @@ function printHelp({
270
270
  message.push(
271
271
  linebreak(),
272
272
  ` ${bgGreen(black(` ${commandName} `))} ${green(
273
- `v${"4.13.4"}`
273
+ `v${"4.14.1"}`
274
274
  )} ${headline}`
275
275
  );
276
276
  }
@@ -1,5 +1,5 @@
1
+ import { performance } from "node:perf_hooks";
1
2
  import { fileURLToPath } from "node:url";
2
- import { performance } from "perf_hooks";
3
3
  import { preview } from "vite";
4
4
  import * as msg from "../messages.js";
5
5
  import { getResolvedHostForHttpServer } from "./util.js";
@@ -1,5 +1,5 @@
1
- import { createRequire } from "module";
2
1
  import nodeFs from "node:fs";
2
+ import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { bold } from "kleur/colors";
@@ -0,0 +1 @@
1
+ export declare const REFERENCE_FILE = "./types.d.ts";
@@ -0,0 +1,4 @@
1
+ const REFERENCE_FILE = "./types.d.ts";
2
+ export {
3
+ REFERENCE_FILE
4
+ };
@@ -1,22 +1,30 @@
1
1
  import fsMod from 'node:fs';
2
- import type { AstroInlineConfig, AstroSettings } from '../../@types/astro.js';
2
+ import type { AstroConfig, AstroInlineConfig, AstroSettings } from '../../@types/astro.js';
3
3
  import type { Logger } from '../logger/core.js';
4
4
  export type SyncOptions = {
5
5
  logger: Logger;
6
6
  settings: AstroSettings;
7
+ force?: boolean;
7
8
  skip?: {
8
9
  content?: boolean;
9
10
  };
10
11
  };
11
- export default function sync({ inlineConfig, fs, telemetry: _telemetry, }: {
12
- inlineConfig: AstroInlineConfig;
12
+ export default function sync(inlineConfig: AstroInlineConfig, { fs, telemetry: _telemetry }?: {
13
13
  fs?: typeof fsMod;
14
14
  telemetry?: boolean;
15
15
  }): Promise<void>;
16
+ /**
17
+ * Clears the content layer and content collection cache, forcing a full rebuild.
18
+ */
19
+ export declare function clearContentLayerCache({ astroConfig, logger, fs, }: {
20
+ astroConfig: AstroConfig;
21
+ logger: Logger;
22
+ fs?: typeof fsMod;
23
+ }): Promise<void>;
16
24
  /**
17
25
  * Generates TypeScript types for all Astro modules. This sets up a `src/env.d.ts` file for type inferencing,
18
26
  * and defines the `astro:content` module for the Content Collections API.
19
27
  *
20
28
  * @experimental The JavaScript API is experimental
21
29
  */
22
- export declare function syncInternal({ logger, fs, settings, skip, }: SyncOptions): Promise<void>;
30
+ export declare function syncInternal({ logger, fs, settings, skip, force, }: SyncOptions): Promise<void>;
@@ -1,15 +1,17 @@
1
- import fsMod from "node:fs";
1
+ import fsMod, { existsSync } from "node:fs";
2
2
  import { performance } from "node:perf_hooks";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { dim } from "kleur/colors";
5
5
  import { createServer } from "vite";
6
- import { getPackage } from "../../cli/install-package.js";
6
+ import { CONTENT_TYPES_FILE, DATA_STORE_FILE } from "../../content/consts.js";
7
+ import { globalContentLayer } from "../../content/content-layer.js";
7
8
  import { createContentTypesGenerator } from "../../content/index.js";
8
- import { globalContentConfigObserver } from "../../content/utils.js";
9
+ import { MutableDataStore } from "../../content/mutable-data-store.js";
10
+ import { getContentPaths, globalContentConfigObserver } from "../../content/utils.js";
9
11
  import { syncAstroEnv } from "../../env/sync.js";
10
12
  import { telemetry } from "../../events/index.js";
11
13
  import { eventCliSession } from "../../events/session.js";
12
- import { runHookConfigSetup } from "../../integrations/hooks.js";
14
+ import { runHookConfigDone, runHookConfigSetup } from "../../integrations/hooks.js";
13
15
  import { getTimeStat } from "../build/util.js";
14
16
  import { resolveConfig } from "../config/config.js";
15
17
  import { createNodeLogger } from "../config/logging.js";
@@ -25,12 +27,8 @@ import {
25
27
  } from "../errors/index.js";
26
28
  import { formatErrorMessage } from "../messages.js";
27
29
  import { ensureProcessNodeEnv } from "../util.js";
28
- import { setUpEnvTs } from "./setup-env-ts.js";
29
- async function sync({
30
- inlineConfig,
31
- fs,
32
- telemetry: _telemetry = false
33
- }) {
30
+ import { writeFiles } from "./write-files.js";
31
+ async function sync(inlineConfig, { fs, telemetry: _telemetry = false } = {}) {
34
32
  ensureProcessNodeEnv("production");
35
33
  const logger = createNodeLogger(inlineConfig);
36
34
  const { astroConfig, userConfig } = await resolveConfig(inlineConfig ?? {}, "sync");
@@ -43,32 +41,63 @@ async function sync({
43
41
  settings,
44
42
  logger
45
43
  });
46
- return await syncInternal({ settings, logger, fs });
44
+ await runHookConfigDone({ settings, logger });
45
+ return await syncInternal({ settings, logger, fs, force: inlineConfig.force });
46
+ }
47
+ async function clearContentLayerCache({
48
+ astroConfig,
49
+ logger,
50
+ fs = fsMod
51
+ }) {
52
+ const dataStore = new URL(DATA_STORE_FILE, astroConfig.cacheDir);
53
+ if (fs.existsSync(dataStore)) {
54
+ logger.debug("content", "clearing data store");
55
+ await fs.promises.rm(dataStore, { force: true });
56
+ logger.warn("content", "data store cleared (force)");
57
+ }
47
58
  }
48
59
  async function syncInternal({
49
60
  logger,
50
61
  fs = fsMod,
51
62
  settings,
52
- skip
63
+ skip,
64
+ force
53
65
  }) {
54
- const cwd = fileURLToPath(settings.config.root);
66
+ if (force) {
67
+ await clearContentLayerCache({ astroConfig: settings.config, logger, fs });
68
+ }
55
69
  const timerStart = performance.now();
56
- const dbPackage = await getPackage(
57
- "@astrojs/db",
58
- logger,
59
- {
60
- optional: true,
61
- cwd
62
- },
63
- []
64
- );
65
70
  try {
66
- await dbPackage?.typegen?.(settings.config);
67
71
  if (!skip?.content) {
68
72
  await syncContentCollections(settings, { fs, logger });
73
+ settings.timer.start("Sync content layer");
74
+ let store;
75
+ try {
76
+ const dataStoreFile = new URL(DATA_STORE_FILE, settings.config.cacheDir);
77
+ if (existsSync(dataStoreFile)) {
78
+ store = await MutableDataStore.fromFile(dataStoreFile);
79
+ }
80
+ } catch (err) {
81
+ logger.error("content", err.message);
82
+ }
83
+ if (!store) {
84
+ store = new MutableDataStore();
85
+ }
86
+ const contentLayer = globalContentLayer.init({
87
+ settings,
88
+ logger,
89
+ store
90
+ });
91
+ await contentLayer.sync();
92
+ settings.timer.end("Sync content layer");
93
+ } else if (fs.existsSync(fileURLToPath(getContentPaths(settings.config, fs).contentDir))) {
94
+ settings.injectedTypes.push({
95
+ filename: CONTENT_TYPES_FILE,
96
+ content: ""
97
+ });
69
98
  }
70
99
  syncAstroEnv(settings, fs);
71
- await setUpEnvTs({ settings, logger, fs });
100
+ await writeFiles(settings, fs, logger);
72
101
  logger.info("types", `Generated ${dim(getTimeStat(timerStart, performance.now()))}`);
73
102
  } catch (err) {
74
103
  const error = createSafeError(err);
@@ -137,6 +166,7 @@ async function syncContentCollections(settings, { logger, fs }) {
137
166
  }
138
167
  }
139
168
  export {
169
+ clearContentLayerCache,
140
170
  sync as default,
141
171
  syncInternal
142
172
  };
@@ -0,0 +1,4 @@
1
+ import type fsMod from 'node:fs';
2
+ import type { AstroSettings } from '../../@types/astro.js';
3
+ import type { Logger } from '../logger/core.js';
4
+ export declare function writeFiles(settings: AstroSettings, fs: typeof fsMod, logger: Logger): Promise<void>;
@@ -0,0 +1,69 @@
1
+ import { dirname, relative } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { bold } from "kleur/colors";
4
+ import { normalizePath } from "vite";
5
+ import { AstroError, AstroErrorData } from "../errors/index.js";
6
+ import { REFERENCE_FILE } from "./constants.js";
7
+ async function writeFiles(settings, fs, logger) {
8
+ try {
9
+ writeInjectedTypes(settings, fs);
10
+ await setUpEnvTs(settings, fs, logger);
11
+ } catch (e) {
12
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: e });
13
+ }
14
+ }
15
+ function getTsReference(type, value) {
16
+ return `/// <reference ${type}=${JSON.stringify(value)} />`;
17
+ }
18
+ const CLIENT_TYPES_REFERENCE = getTsReference("types", "astro/client");
19
+ function writeInjectedTypes(settings, fs) {
20
+ const references = [];
21
+ for (const { filename, content } of settings.injectedTypes) {
22
+ const filepath = normalizePath(fileURLToPath(new URL(filename, settings.dotAstroDir)));
23
+ fs.mkdirSync(dirname(filepath), { recursive: true });
24
+ fs.writeFileSync(filepath, content, "utf-8");
25
+ references.push(normalizePath(relative(fileURLToPath(settings.dotAstroDir), filepath)));
26
+ }
27
+ const astroDtsContent = `${CLIENT_TYPES_REFERENCE}
28
+ ${references.map((reference) => getTsReference("path", reference)).join("\n")}`;
29
+ if (references.length === 0) {
30
+ fs.mkdirSync(settings.dotAstroDir, { recursive: true });
31
+ }
32
+ fs.writeFileSync(
33
+ normalizePath(fileURLToPath(new URL(REFERENCE_FILE, settings.dotAstroDir))),
34
+ astroDtsContent,
35
+ "utf-8"
36
+ );
37
+ }
38
+ async function setUpEnvTs(settings, fs, logger) {
39
+ const envTsPath = normalizePath(fileURLToPath(new URL("env.d.ts", settings.config.srcDir)));
40
+ const envTsPathRelativetoRoot = normalizePath(
41
+ relative(fileURLToPath(settings.config.root), envTsPath)
42
+ );
43
+ const relativePath = normalizePath(
44
+ relative(
45
+ fileURLToPath(settings.config.srcDir),
46
+ fileURLToPath(new URL(REFERENCE_FILE, settings.dotAstroDir))
47
+ )
48
+ );
49
+ const expectedTypeReference = getTsReference("path", relativePath);
50
+ if (fs.existsSync(envTsPath)) {
51
+ const initialEnvContents = await fs.promises.readFile(envTsPath, "utf-8");
52
+ let typesEnvContents = initialEnvContents;
53
+ if (!typesEnvContents.includes(expectedTypeReference)) {
54
+ typesEnvContents = `${expectedTypeReference}
55
+ ${typesEnvContents}`;
56
+ }
57
+ if (initialEnvContents !== typesEnvContents) {
58
+ logger.info("types", `Updated ${bold(envTsPathRelativetoRoot)} type declarations.`);
59
+ await fs.promises.writeFile(envTsPath, typesEnvContents, "utf-8");
60
+ }
61
+ } else {
62
+ await fs.promises.mkdir(settings.config.srcDir, { recursive: true });
63
+ await fs.promises.writeFile(envTsPath, expectedTypeReference, "utf-8");
64
+ logger.info("types", `Added ${bold(envTsPathRelativetoRoot)} type declarations`);
65
+ }
66
+ }
67
+ export {
68
+ writeFiles
69
+ };
package/dist/core/util.js CHANGED
@@ -101,7 +101,7 @@ function isPage(file, settings) {
101
101
  function isEndpoint(file, settings) {
102
102
  if (!isInPagesDir(file, settings.config)) return false;
103
103
  if (!isPublicRoute(file, settings.config)) return false;
104
- return !endsWithPageExt(file, settings);
104
+ return !endsWithPageExt(file, settings) && !file.toString().includes("?astro");
105
105
  }
106
106
  function isServerLikeOutput(config) {
107
107
  return config.output === "server" || config.output === "hybrid";
package/dist/env/sync.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import fsMod from "node:fs";
2
- import { ENV_TYPES_FILE, TYPES_TEMPLATE_URL } from "./constants.js";
2
+ import { TYPES_TEMPLATE_URL } from "./constants.js";
3
3
  import { getEnvFieldType } from "./validators.js";
4
4
  function syncAstroEnv(settings, fs = fsMod) {
5
5
  if (!settings.config.experimental.env) {
@@ -18,9 +18,11 @@ function syncAstroEnv(settings, fs = fsMod) {
18
18
  }
19
19
  }
20
20
  const template = fs.readFileSync(TYPES_TEMPLATE_URL, "utf-8");
21
- const dts = template.replace("// @@CLIENT@@", client).replace("// @@SERVER@@", server);
22
- fs.mkdirSync(settings.dotAstroDir, { recursive: true });
23
- fs.writeFileSync(new URL(ENV_TYPES_FILE, settings.dotAstroDir), dts, "utf-8");
21
+ const content = template.replace("// @@CLIENT@@", client).replace("// @@SERVER@@", server);
22
+ settings.injectedTypes.push({
23
+ filename: "astro/env.d.ts",
24
+ content
25
+ });
24
26
  }
25
27
  export {
26
28
  syncAstroEnv
@@ -1,7 +1,7 @@
1
1
  import fsMod from 'node:fs';
2
2
  import type { AddressInfo } from 'node:net';
3
3
  import type { InlineConfig, ViteDevServer } from 'vite';
4
- import type { AstroAdapter, AstroConfig, AstroSettings, RouteData } from '../@types/astro.js';
4
+ import type { AstroAdapter, AstroConfig, AstroSettings, RouteData, RouteOptions } from '../@types/astro.js';
5
5
  import type { SerializedSSRManifest } from '../core/app/types.js';
6
6
  import type { PageBuildData } from '../core/build/types.js';
7
7
  import type { Logger } from '../core/logger/core.js';
@@ -33,6 +33,7 @@ export declare function getToolbarServerCommunicationHelpers(server: ViteDevServ
33
33
  state: boolean;
34
34
  }) => void) => void;
35
35
  };
36
+ export declare function normalizeInjectedTypeFilename(filename: string, integrationName: string): string;
36
37
  export declare function runHookConfigSetup({ settings, command, logger, isRestart, fs, }: {
37
38
  settings: AstroSettings;
38
39
  command: 'dev' | 'build' | 'preview';
@@ -89,5 +90,10 @@ type RunHookBuildDone = {
89
90
  cacheManifest: boolean;
90
91
  };
91
92
  export declare function runHookBuildDone({ config, pages, routes, logging, cacheManifest, }: RunHookBuildDone): Promise<void>;
93
+ export declare function runHookRouteSetup({ route, settings, logger, }: {
94
+ route: RouteOptions;
95
+ settings: AstroSettings;
96
+ logger: Logger;
97
+ }): Promise<void>;
92
98
  export declare function isFunctionPerRouteEnabled(adapter: AstroAdapter | undefined): boolean;
93
99
  export {};
@@ -70,6 +70,15 @@ function getToolbarServerCommunicationHelpers(server) {
70
70
  }
71
71
  };
72
72
  }
73
+ const SAFE_CHARS_RE = /[^\w.-]/g;
74
+ function normalizeInjectedTypeFilename(filename, integrationName) {
75
+ if (!filename.endsWith(".d.ts")) {
76
+ throw new Error(
77
+ `Integration ${bold(integrationName)} is injecting a type that does not end with "${bold(".d.ts")}"`
78
+ );
79
+ }
80
+ return `./integrations/${integrationName.replace(SAFE_CHARS_RE, "_")}/${filename.replace(SAFE_CHARS_RE, "_")}`;
81
+ }
73
82
  async function runHookConfigSetup({
74
83
  settings,
75
84
  command,
@@ -242,6 +251,17 @@ async function runHookConfigDone({
242
251
  }
243
252
  settings.adapter = adapter;
244
253
  },
254
+ injectTypes(injectedType) {
255
+ const normalizedFilename = normalizeInjectedTypeFilename(
256
+ injectedType.filename,
257
+ integration.name
258
+ );
259
+ settings.injectedTypes.push({
260
+ filename: normalizedFilename,
261
+ content: injectedType.content
262
+ });
263
+ return new URL(normalizedFilename, settings.config.root);
264
+ },
245
265
  logger: getLogger(integration, logger)
246
266
  }),
247
267
  logger
@@ -419,6 +439,38 @@ async function runHookBuildDone({
419
439
  }
420
440
  }
421
441
  }
442
+ async function runHookRouteSetup({
443
+ route,
444
+ settings,
445
+ logger
446
+ }) {
447
+ const prerenderChangeLogs = [];
448
+ for (const integration of settings.config.integrations) {
449
+ if (integration?.hooks?.["astro:route:setup"]) {
450
+ const originalRoute = { ...route };
451
+ const integrationLogger = getLogger(integration, logger);
452
+ await withTakingALongTimeMsg({
453
+ name: integration.name,
454
+ hookName: "astro:route:setup",
455
+ hookResult: integration.hooks["astro:route:setup"]({
456
+ route,
457
+ logger: integrationLogger
458
+ }),
459
+ logger
460
+ });
461
+ if (route.prerender !== originalRoute.prerender) {
462
+ prerenderChangeLogs.push({ integrationName: integration.name, value: route.prerender });
463
+ }
464
+ }
465
+ }
466
+ if (prerenderChangeLogs.length > 1) {
467
+ logger.debug(
468
+ "router",
469
+ `The ${route.component} route's prerender option has been changed multiple times by integrations:
470
+ ` + prerenderChangeLogs.map((log) => `- ${log.integrationName}: ${log.value}`).join("\n")
471
+ );
472
+ }
473
+ }
422
474
  function isFunctionPerRouteEnabled(adapter) {
423
475
  if (adapter?.adapterFeatures?.functionPerRoute === true) {
424
476
  return true;
@@ -429,6 +481,7 @@ function isFunctionPerRouteEnabled(adapter) {
429
481
  export {
430
482
  getToolbarServerCommunicationHelpers,
431
483
  isFunctionPerRouteEnabled,
484
+ normalizeInjectedTypeFilename,
432
485
  runHookBuildDone,
433
486
  runHookBuildGenerated,
434
487
  runHookBuildSetup,
@@ -436,6 +489,7 @@ export {
436
489
  runHookBuildStart,
437
490
  runHookConfigDone,
438
491
  runHookConfigSetup,
492
+ runHookRouteSetup,
439
493
  runHookServerDone,
440
494
  runHookServerSetup,
441
495
  runHookServerStart
@@ -32,5 +32,5 @@ export interface AstroPreferences {
32
32
  }
33
33
  export declare function isValidKey(key: string): key is PreferenceKey;
34
34
  export declare function coerce(key: string, value: unknown): any;
35
- export default function createPreferences(config: AstroConfig): AstroPreferences;
35
+ export default function createPreferences(config: AstroConfig, dotAstroDir: URL): AstroPreferences;
36
36
  export {};
@@ -25,9 +25,9 @@ function coerce(key, value) {
25
25
  }
26
26
  return value;
27
27
  }
28
- function createPreferences(config) {
28
+ function createPreferences(config, dotAstroDir) {
29
29
  const global = new PreferenceStore(getGlobalPreferenceDir());
30
- const project = new PreferenceStore(fileURLToPath(new URL("./.astro/", config.root)));
30
+ const project = new PreferenceStore(fileURLToPath(dotAstroDir));
31
31
  const stores = { global, project };
32
32
  return {
33
33
  async get(key, { location } = {}) {
@@ -40,7 +40,8 @@ function renderServerIsland(result, _displayName, props, slots) {
40
40
  const key = await result.key;
41
41
  const propsEncrypted = await encryptString(key, JSON.stringify(props));
42
42
  const hostId = crypto.randomUUID();
43
- const serverIslandUrl = `${result.base}_server-islands/${componentId}${result.trailingSlash === "always" ? "/" : ""}`;
43
+ const slash = result.base.endsWith("/") ? "" : "/";
44
+ const serverIslandUrl = `${result.base}${slash}_server-islands/${componentId}${result.trailingSlash === "always" ? "/" : ""}`;
44
45
  destination.write(`<script async type="module" data-island-id="${hostId}">
45
46
  let componentId = ${safeJsonStringify(componentId)};
46
47
  let componentExport = ${safeJsonStringify(componentExport)};
@@ -60,9 +61,10 @@ if(response.status === 200 && response.headers.get('content-type') === 'text/htm
60
61
  let html = await response.text();
61
62
 
62
63
  // Swap!
63
- while(script.previousSibling?.nodeType !== 8 &&
64
- script.previousSibling?.data !== 'server-island-start') {
65
- script.previousSibling?.remove();
64
+ while(script.previousSibling &&
65
+ script.previousSibling.nodeType !== 8 &&
66
+ script.previousSibling.data !== 'server-island-start') {
67
+ script.previousSibling.remove();
66
68
  }
67
69
  script.previousSibling?.remove();
68
70
 
@@ -1,4 +1,4 @@
1
- import { Readable } from "stream";
1
+ import { Readable } from "node:stream";
2
2
  import { getSetCookiesFromResponse } from "../core/cookies/index.js";
3
3
  import { getViteErrorPayload } from "../core/errors/dev/index.js";
4
4
  import notFoundTemplate from "../template/4xx.js";
@@ -1,7 +1,9 @@
1
1
  import type * as vite from 'vite';
2
2
  import type { AstroSettings } from '../@types/astro.js';
3
+ import type { Logger } from '../core/logger/core.js';
3
4
  interface EnvPluginOptions {
4
5
  settings: AstroSettings;
6
+ logger: Logger;
5
7
  }
6
- export default function envVitePlugin({ settings }: EnvPluginOptions): vite.Plugin;
8
+ export default function envVitePlugin({ settings, logger }: EnvPluginOptions): vite.Plugin;
7
9
  export {};