astro 4.14.0 → 4.14.2

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.
@@ -2200,15 +2200,15 @@ export interface AstroUserConfig {
2200
2200
  *
2201
2201
  * 2. **Edit the collection definition**. Your updated collection requires a `loader`, and the option to select a collection `type` is no longer available.
2202
2202
  *
2203
- * ```diff
2203
+ * ```ts ins={3,8} del={7}
2204
2204
  * // src/content/config.ts
2205
2205
  * import { defineCollection, z } from 'astro:content';
2206
- * + import { glob } from 'astro/loaders';
2206
+ * import { glob } from 'astro/loaders';
2207
2207
  *
2208
2208
  * const blog = defineCollection({
2209
2209
  * // For content layer you no longer define a `type`
2210
- * - type: 'content',
2211
- * + loader: glob({ pattern: "**\/*.md", base: "./src/data/blog" }),
2210
+ * type: 'content',
2211
+ * loader: glob({ pattern: "**\/*.md", base: "./src/data/blog" }),
2212
2212
  * schema: z.object({
2213
2213
  * title: z.string(),
2214
2214
  * description: z.string(),
@@ -2220,14 +2220,14 @@ export interface AstroUserConfig {
2220
2220
  *
2221
2221
  * 3. **Change references from `slug` to `id`**. Content layer collections do not have a `slug` field. Instead, all updated collections will have an `id`.
2222
2222
  *
2223
- * ```diff
2223
+ * ```astro ins={7} del={6}
2224
2224
  * // src/pages/index.astro
2225
2225
  * ---
2226
2226
  * export async function getStaticPaths() {
2227
2227
  * const posts = await getCollection('blog');
2228
2228
  * return posts.map((post) => ({
2229
- * - params: { slug: post.slug },
2230
- * + params: { slug: post.id },
2229
+ * params: { slug: post.slug },
2230
+ * params: { slug: post.id },
2231
2231
  * props: post,
2232
2232
  * }));
2233
2233
  * }
@@ -2236,16 +2236,16 @@ export interface AstroUserConfig {
2236
2236
  *
2237
2237
  * 4. **Switch to the new `render()` function**. Entries no longer have a `render()` method, as they are now serializable plain objects. Instead, import the `render()` function from `astro:content`.
2238
2238
  *
2239
- * ```diff
2239
+ * ```astro ins={4,9} del={3,8}
2240
2240
  * // src/pages/index.astro
2241
2241
  * ---
2242
- * - import { getEntry } from 'astro:content';
2243
- * + import { getEntry, render } from 'astro:content';
2242
+ * import { getEntry } from 'astro:content';
2243
+ * import { getEntry, render } from 'astro:content';
2244
2244
  *
2245
2245
  * const post = await getEntry('blog', params.slug);
2246
2246
  *
2247
- * - const { Content, headings } = await post.render();
2248
- * + const { Content, headings } = await render(post);
2247
+ * const { Content, headings } = await post.render();
2248
+ * const { Content, headings } = await render(post);
2249
2249
  * ---
2250
2250
  *
2251
2251
  * <Content />
@@ -1,9 +1,9 @@
1
+ import { readFile } from "node:fs/promises";
1
2
  import os from "node:os";
2
3
  import { isAbsolute } from "node:path";
3
4
  import { fileURLToPath, pathToFileURL } from "node:url";
4
5
  import { assetsDir, imageConfig, outDir } from "astro:assets";
5
6
  import { isRemotePath, removeQueryString } from "@astrojs/internal-helpers/path";
6
- import { readFile } from "fs/promises";
7
7
  import * as mime from "mrmime";
8
8
  import { getConfiguredImageService } from "../internal.js";
9
9
  import { etag } from "../utils/etag.js";
@@ -7,7 +7,7 @@ async function check(flags) {
7
7
  const logger = createLoggerFromFlags(flags);
8
8
  const getPackageOpts = {
9
9
  skipAsk: !!flags.yes || !!flags.y,
10
- cwd: typeof flags.root == "string" ? flags.root : void 0
10
+ cwd: flags.root
11
11
  };
12
12
  const checkPackage = await getPackage(
13
13
  "@astrojs/check",
@@ -1,5 +1,4 @@
1
- import { type Flags } from '../flags.js';
2
- export declare function db({ positionals, flags }: {
3
- positionals: string[];
4
- flags: Flags;
1
+ import type { Arguments } from 'yargs-parser';
2
+ export declare function db({ flags }: {
3
+ flags: Arguments;
5
4
  }): Promise<void>;
@@ -2,12 +2,12 @@ import { resolveConfig } from "../../core/config/config.js";
2
2
  import { apply as applyPolyfill } from "../../core/polyfill.js";
3
3
  import { createLoggerFromFlags, flagsToAstroInlineConfig } from "../flags.js";
4
4
  import { getPackage } from "../install-package.js";
5
- async function db({ positionals, flags }) {
5
+ async function db({ flags }) {
6
6
  applyPolyfill();
7
7
  const logger = createLoggerFromFlags(flags);
8
8
  const getPackageOpts = {
9
9
  skipAsk: !!flags.yes || !!flags.y,
10
- cwd: typeof flags.root == "string" ? flags.root : void 0
10
+ cwd: flags.root
11
11
  };
12
12
  const dbPackage = await getPackage("@astrojs/db", logger, getPackageOpts, []);
13
13
  if (!dbPackage) {
@@ -20,11 +20,7 @@ async function db({ positionals, flags }) {
20
20
  const { cli } = dbPackage;
21
21
  const inlineConfig = flagsToAstroInlineConfig(flags);
22
22
  const { astroConfig } = await resolveConfig(inlineConfig, "build");
23
- const yargsArgs = {
24
- _: positionals,
25
- ...flags
26
- };
27
- await cli({ flags: yargsArgs, config: astroConfig });
23
+ await cli({ flags, config: astroConfig });
28
24
  }
29
25
  export {
30
26
  db
@@ -1,8 +1,7 @@
1
- import type { parseArgs } from 'node:util';
1
+ import type { Arguments } from 'yargs-parser';
2
2
  import type { AstroInlineConfig } from '../@types/astro.js';
3
3
  import { Logger } from '../core/logger/core.js';
4
- export type ParsedArgsResult = ReturnType<typeof parseArgs>;
5
- export type Flags = ParsedArgsResult['values'];
4
+ export type Flags = Arguments;
6
5
  export declare function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig;
7
6
  /**
8
7
  * The `logging` is usually created from an `AstroInlineConfig`, but some flows like `add`
package/dist/cli/flags.js CHANGED
@@ -13,7 +13,7 @@ function flagsToAstroInlineConfig(flags) {
13
13
  base: typeof flags.base === "string" ? flags.base : void 0,
14
14
  outDir: typeof flags.outDir === "string" ? flags.outDir : void 0,
15
15
  server: {
16
- port: typeof flags.port === "string" ? Number(flags.port) : void 0,
16
+ port: typeof flags.port === "number" ? flags.port : void 0,
17
17
  host: typeof flags.host === "string" || typeof flags.host === "boolean" ? flags.host : void 0,
18
18
  open: typeof flags.open === "string" || typeof flags.open === "boolean" ? flags.open : void 0
19
19
  }
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { parseArgs } from "node:util";
2
1
  import * as colors from "kleur/colors";
2
+ import yargs from "yargs-parser";
3
3
  import { ASTRO_VERSION } from "../core/constants.js";
4
4
  async function printAstroHelp() {
5
5
  const { printHelp } = await import("../core/messages.js");
@@ -43,9 +43,9 @@ function printVersion() {
43
43
  console.log();
44
44
  console.log(` ${colors.bgGreen(colors.black(` astro `))} ${colors.green(`v${ASTRO_VERSION}`)}`);
45
45
  }
46
- function resolveCommand(args) {
47
- const cmd = args.positionals[2];
48
- if (args.values.version) return "version";
46
+ function resolveCommand(flags) {
47
+ const cmd = flags._[2];
48
+ if (flags.version) return "version";
49
49
  const supportedCommands = /* @__PURE__ */ new Set([
50
50
  "add",
51
51
  "sync",
@@ -68,8 +68,7 @@ function resolveCommand(args) {
68
68
  }
69
69
  return "help";
70
70
  }
71
- async function runCommand(cmd, args) {
72
- const flags = args.values;
71
+ async function runCommand(cmd, flags) {
73
72
  switch (cmd) {
74
73
  case "help":
75
74
  await printAstroHelp();
@@ -89,7 +88,7 @@ async function runCommand(cmd, args) {
89
88
  }
90
89
  case "telemetry": {
91
90
  const { update } = await import("./telemetry/index.js");
92
- const subcommand = args.positionals[3];
91
+ const subcommand = flags._[3]?.toString();
93
92
  await update(subcommand, { flags });
94
93
  return;
95
94
  }
@@ -100,7 +99,7 @@ async function runCommand(cmd, args) {
100
99
  }
101
100
  case "preferences": {
102
101
  const { preferences } = await import("./preferences/index.js");
103
- const [subcommand, key, value] = args.positionals.slice(3);
102
+ const [subcommand, key, value] = flags._.slice(3).map((v) => v.toString());
104
103
  const exitCode = await preferences(subcommand, key, value, { flags });
105
104
  return process.exit(exitCode);
106
105
  }
@@ -114,7 +113,7 @@ async function runCommand(cmd, args) {
114
113
  switch (cmd) {
115
114
  case "add": {
116
115
  const { add } = await import("./add/index.js");
117
- const packages = args.positionals.slice(3);
116
+ const packages = flags._.slice(3);
118
117
  await add(packages, { flags });
119
118
  return;
120
119
  }
@@ -124,7 +123,7 @@ async function runCommand(cmd, args) {
124
123
  case "link":
125
124
  case "init": {
126
125
  const { db } = await import("./db/index.js");
127
- await db({ positionals: args.positionals, flags });
126
+ await db({ flags });
128
127
  return;
129
128
  }
130
129
  case "dev": {
@@ -163,22 +162,10 @@ async function runCommand(cmd, args) {
163
162
  throw new Error(`Error running ${cmd} -- no command found.`);
164
163
  }
165
164
  async function cli(argv) {
166
- const args = parseArgs({
167
- args: argv,
168
- allowPositionals: true,
169
- strict: false,
170
- options: {
171
- global: { type: "boolean", short: "g" },
172
- host: { type: "string" },
173
- // Can be boolean too, which is covered by `strict: false`
174
- open: { type: "string" }
175
- // Can be boolean too, which is covered by `strict: false`
176
- // TODO: Add more flags here
177
- }
178
- });
179
- const cmd = resolveCommand(args);
165
+ const flags = yargs(argv, { boolean: ["global"], alias: { g: "global" } });
166
+ const cmd = resolveCommand(flags);
180
167
  try {
181
- await runCommand(cmd, args);
168
+ await runCommand(cmd, flags);
182
169
  } catch (err) {
183
170
  const { throwAndExit } = await import("./throw-and-exit.js");
184
171
  await throwAndExit(cmd, err);
@@ -1,10 +1,10 @@
1
1
  import type { FSWatcher } from 'vite';
2
2
  import type { AstroSettings } from '../@types/astro.js';
3
3
  import type { Logger } from '../core/logger/core.js';
4
- import type { DataStore } from './data-store.js';
5
4
  import type { LoaderContext } from './loaders/types.js';
5
+ import type { MutableDataStore } from './mutable-data-store.js';
6
6
  export interface ContentLayerOptions {
7
- store: DataStore;
7
+ store: MutableDataStore;
8
8
  settings: AstroSettings;
9
9
  logger: Logger;
10
10
  watcher?: FSWatcher;
@@ -1,4 +1,3 @@
1
- import { type PathLike } from 'fs';
2
1
  import type { MarkdownHeading } from '@astrojs/markdown-remark';
3
2
  export interface RenderedContent {
4
3
  /** Rendered HTML string. If present then `render(entry)` will return a component that renders this HTML. */
@@ -32,83 +31,24 @@ export interface DataEntry<TData extends Record<string, unknown> = Record<string
32
31
  */
33
32
  deferredRender?: boolean;
34
33
  }
34
+ /**
35
+ * A read-only data store for content collections. This is used to retrieve data from the content layer at runtime.
36
+ * To add or modify data, use {@link MutableDataStore} instead.
37
+ */
35
38
  export declare class DataStore {
36
- #private;
39
+ protected _collections: Map<string, Map<string, any>>;
37
40
  constructor();
38
41
  get<T = DataEntry>(collectionName: string, key: string): T | undefined;
39
42
  entries<T = DataEntry>(collectionName: string): Array<[id: string, T]>;
40
43
  values<T = DataEntry>(collectionName: string): Array<T>;
41
44
  keys(collectionName: string): Array<string>;
42
- set(collectionName: string, key: string, value: unknown): void;
43
- delete(collectionName: string, key: string): void;
44
- clear(collectionName: string): void;
45
- clearAll(): void;
46
45
  has(collectionName: string, key: string): boolean;
47
46
  hasCollection(collectionName: string): boolean;
48
47
  collections(): Map<string, Map<string, any>>;
49
- addAssetImport(assetImport: string, filePath: string): void;
50
- addAssetImports(assets: Array<string>, filePath: string): void;
51
- addModuleImport(fileName: string): void;
52
- writeAssetImports(filePath: PathLike): Promise<void>;
53
- writeModuleImports(filePath: PathLike): Promise<void>;
54
- scopedStore(collectionName: string): ScopedDataStore;
55
- /**
56
- * Returns a MetaStore for a given collection, or if no collection is provided, the default meta collection.
57
- */
58
- metaStore(collectionName?: string): MetaStore;
59
- toString(): string;
60
- writeToDisk(filePath: PathLike): Promise<void>;
61
48
  /**
62
49
  * Attempts to load a DataStore from the virtual module.
63
50
  * This only works in Vite.
64
51
  */
65
52
  static fromModule(): Promise<DataStore>;
66
53
  static fromMap(data: Map<string, Map<string, any>>): Promise<DataStore>;
67
- static fromString(data: string): Promise<DataStore>;
68
- static fromFile(filePath: string | URL): Promise<DataStore>;
69
- }
70
- export interface ScopedDataStore {
71
- get: <TData extends Record<string, unknown> = Record<string, unknown>>(key: string) => DataEntry<TData> | undefined;
72
- entries: () => Array<[id: string, DataEntry]>;
73
- set: <TData extends Record<string, unknown>>(opts: {
74
- /** The ID of the entry. Must be unique per collection. */
75
- id: string;
76
- /** The data to store. */
77
- data: TData;
78
- /** The raw body of the content, if applicable. */
79
- body?: string;
80
- /** The file path of the content, if applicable. Relative to the site root. */
81
- filePath?: string;
82
- /** A content digest, to check if the content has changed. */
83
- digest?: number | string;
84
- /** The rendered content, if applicable. */
85
- rendered?: RenderedContent;
86
- /**
87
- * If an entry is a deferred, its rendering phase is delegated to a virtual module during the runtime phase.
88
- */
89
- deferredRender?: boolean;
90
- }) => boolean;
91
- values: () => Array<DataEntry>;
92
- keys: () => Array<string>;
93
- delete: (key: string) => void;
94
- clear: () => void;
95
- has: (key: string) => boolean;
96
- /**
97
- * Adds a single asset to the store. This asset will be transformed
98
- * by Vite, and the URL will be available in the final build.
99
- * @param fileName
100
- * @param specifier
101
- * @returns
102
- */
103
- addModuleImport: (fileName: string) => void;
104
- }
105
- /**
106
- * A key-value store for metadata strings. Useful for storing things like sync tokens.
107
- */
108
- export interface MetaStore {
109
- get: (key: string) => string | undefined;
110
- set: (key: string, value: string) => void;
111
- has: (key: string) => boolean;
112
- delete: (key: string) => void;
113
54
  }
114
- export declare function contentModuleToId(fileName: string): string;
@@ -1,266 +1,36 @@
1
- import { promises as fs, existsSync } from "fs";
2
1
  import * as devalue from "devalue";
3
- import { imageSrcToImportId, importIdToSymbolName } from "../assets/utils/resolveImports.js";
4
- import { AstroError, AstroErrorData } from "../core/errors/index.js";
5
- import { CONTENT_MODULE_FLAG, DEFERRED_MODULE } from "./consts.js";
6
- const SAVE_DEBOUNCE_MS = 500;
7
2
  class DataStore {
8
- #collections = /* @__PURE__ */ new Map();
9
- #file;
10
- #assetsFile;
11
- #modulesFile;
12
- #saveTimeout;
13
- #assetsSaveTimeout;
14
- #modulesSaveTimeout;
15
- #dirty = false;
16
- #assetsDirty = false;
17
- #modulesDirty = false;
18
- #assetImports = /* @__PURE__ */ new Set();
19
- #moduleImports = /* @__PURE__ */ new Map();
3
+ _collections = /* @__PURE__ */ new Map();
20
4
  constructor() {
21
- this.#collections = /* @__PURE__ */ new Map();
5
+ this._collections = /* @__PURE__ */ new Map();
22
6
  }
23
7
  get(collectionName, key) {
24
- return this.#collections.get(collectionName)?.get(String(key));
8
+ return this._collections.get(collectionName)?.get(String(key));
25
9
  }
26
10
  entries(collectionName) {
27
- const collection = this.#collections.get(collectionName) ?? /* @__PURE__ */ new Map();
11
+ const collection = this._collections.get(collectionName) ?? /* @__PURE__ */ new Map();
28
12
  return [...collection.entries()];
29
13
  }
30
14
  values(collectionName) {
31
- const collection = this.#collections.get(collectionName) ?? /* @__PURE__ */ new Map();
15
+ const collection = this._collections.get(collectionName) ?? /* @__PURE__ */ new Map();
32
16
  return [...collection.values()];
33
17
  }
34
18
  keys(collectionName) {
35
- const collection = this.#collections.get(collectionName) ?? /* @__PURE__ */ new Map();
19
+ const collection = this._collections.get(collectionName) ?? /* @__PURE__ */ new Map();
36
20
  return [...collection.keys()];
37
21
  }
38
- set(collectionName, key, value) {
39
- const collection = this.#collections.get(collectionName) ?? /* @__PURE__ */ new Map();
40
- collection.set(String(key), value);
41
- this.#collections.set(collectionName, collection);
42
- this.#saveToDiskDebounced();
43
- }
44
- delete(collectionName, key) {
45
- const collection = this.#collections.get(collectionName);
46
- if (collection) {
47
- collection.delete(String(key));
48
- this.#saveToDiskDebounced();
49
- }
50
- }
51
- clear(collectionName) {
52
- this.#collections.delete(collectionName);
53
- this.#saveToDiskDebounced();
54
- }
55
- clearAll() {
56
- this.#collections.clear();
57
- this.#saveToDiskDebounced();
58
- }
59
22
  has(collectionName, key) {
60
- const collection = this.#collections.get(collectionName);
23
+ const collection = this._collections.get(collectionName);
61
24
  if (collection) {
62
25
  return collection.has(String(key));
63
26
  }
64
27
  return false;
65
28
  }
66
29
  hasCollection(collectionName) {
67
- return this.#collections.has(collectionName);
30
+ return this._collections.has(collectionName);
68
31
  }
69
32
  collections() {
70
- return this.#collections;
71
- }
72
- addAssetImport(assetImport, filePath) {
73
- const id = imageSrcToImportId(assetImport, filePath);
74
- if (id) {
75
- this.#assetImports.add(id);
76
- this.#writeAssetsImportsDebounced();
77
- }
78
- }
79
- addAssetImports(assets, filePath) {
80
- assets.forEach((asset) => this.addAssetImport(asset, filePath));
81
- }
82
- addModuleImport(fileName) {
83
- const id = contentModuleToId(fileName);
84
- if (id) {
85
- this.#moduleImports.set(fileName, id);
86
- this.#writeModulesImportsDebounced();
87
- }
88
- }
89
- async writeAssetImports(filePath) {
90
- this.#assetsFile = filePath;
91
- if (this.#assetImports.size === 0) {
92
- try {
93
- await fs.writeFile(filePath, "export default new Map();");
94
- } catch (err) {
95
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
96
- }
97
- }
98
- if (!this.#assetsDirty && existsSync(filePath)) {
99
- return;
100
- }
101
- const imports = [];
102
- const exports = [];
103
- this.#assetImports.forEach((id) => {
104
- const symbol = importIdToSymbolName(id);
105
- imports.push(`import ${symbol} from '${id}';`);
106
- exports.push(`[${JSON.stringify(id)}, ${symbol}]`);
107
- });
108
- const code = (
109
- /* js */
110
- `
111
- ${imports.join("\n")}
112
- export default new Map([${exports.join(", ")}]);
113
- `
114
- );
115
- try {
116
- await fs.writeFile(filePath, code);
117
- } catch (err) {
118
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
119
- }
120
- this.#assetsDirty = false;
121
- }
122
- async writeModuleImports(filePath) {
123
- this.#modulesFile = filePath;
124
- if (this.#moduleImports.size === 0) {
125
- try {
126
- await fs.writeFile(filePath, "export default new Map();");
127
- } catch (err) {
128
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
129
- }
130
- }
131
- if (!this.#modulesDirty && existsSync(filePath)) {
132
- return;
133
- }
134
- const lines = [];
135
- for (const [fileName, specifier] of this.#moduleImports) {
136
- lines.push(`['${fileName}', () => import('${specifier}')]`);
137
- }
138
- const code = `
139
- export default new Map([
140
- ${lines.join(",\n")}]);
141
- `;
142
- try {
143
- await fs.writeFile(filePath, code);
144
- } catch (err) {
145
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
146
- }
147
- this.#modulesDirty = false;
148
- }
149
- #writeAssetsImportsDebounced() {
150
- this.#assetsDirty = true;
151
- if (this.#assetsFile) {
152
- if (this.#assetsSaveTimeout) {
153
- clearTimeout(this.#assetsSaveTimeout);
154
- }
155
- this.#assetsSaveTimeout = setTimeout(() => {
156
- this.#assetsSaveTimeout = void 0;
157
- this.writeAssetImports(this.#assetsFile);
158
- }, SAVE_DEBOUNCE_MS);
159
- }
160
- }
161
- #writeModulesImportsDebounced() {
162
- this.#modulesDirty = true;
163
- if (this.#modulesFile) {
164
- if (this.#modulesSaveTimeout) {
165
- clearTimeout(this.#modulesSaveTimeout);
166
- }
167
- this.#modulesSaveTimeout = setTimeout(() => {
168
- this.#modulesSaveTimeout = void 0;
169
- this.writeModuleImports(this.#modulesFile);
170
- }, SAVE_DEBOUNCE_MS);
171
- }
172
- }
173
- #saveToDiskDebounced() {
174
- this.#dirty = true;
175
- if (this.#file) {
176
- if (this.#saveTimeout) {
177
- clearTimeout(this.#saveTimeout);
178
- }
179
- this.#saveTimeout = setTimeout(() => {
180
- this.#saveTimeout = void 0;
181
- this.writeToDisk(this.#file);
182
- }, SAVE_DEBOUNCE_MS);
183
- }
184
- }
185
- scopedStore(collectionName) {
186
- return {
187
- get: (key) => this.get(collectionName, key),
188
- entries: () => this.entries(collectionName),
189
- values: () => this.values(collectionName),
190
- keys: () => this.keys(collectionName),
191
- set: ({ id: key, data, body, filePath, deferredRender, digest, rendered }) => {
192
- if (!key) {
193
- throw new Error(`ID must be a non-empty string`);
194
- }
195
- const id = String(key);
196
- if (digest) {
197
- const existing = this.get(collectionName, id);
198
- if (existing && existing.digest === digest) {
199
- return false;
200
- }
201
- }
202
- const entry = {
203
- id,
204
- data
205
- };
206
- if (body) {
207
- entry.body = body;
208
- }
209
- if (filePath) {
210
- if (filePath.startsWith("/")) {
211
- throw new Error(`File path must be relative to the site root. Got: ${filePath}`);
212
- }
213
- entry.filePath = filePath;
214
- }
215
- if (digest) {
216
- entry.digest = digest;
217
- }
218
- if (rendered) {
219
- entry.rendered = rendered;
220
- }
221
- if (deferredRender) {
222
- entry.deferredRender = deferredRender;
223
- if (filePath) {
224
- this.addModuleImport(filePath);
225
- }
226
- }
227
- this.set(collectionName, id, entry);
228
- return true;
229
- },
230
- delete: (key) => this.delete(collectionName, key),
231
- clear: () => this.clear(collectionName),
232
- has: (key) => this.has(collectionName, key),
233
- addAssetImport: (assetImport, fileName) => this.addAssetImport(assetImport, fileName),
234
- addAssetImports: (assets, fileName) => this.addAssetImports(assets, fileName),
235
- addModuleImport: (fileName) => this.addModuleImport(fileName)
236
- };
237
- }
238
- /**
239
- * Returns a MetaStore for a given collection, or if no collection is provided, the default meta collection.
240
- */
241
- metaStore(collectionName = ":meta") {
242
- const collectionKey = `meta:${collectionName}`;
243
- return {
244
- get: (key) => this.get(collectionKey, key),
245
- set: (key, data) => this.set(collectionKey, key, data),
246
- delete: (key) => this.delete(collectionKey, key),
247
- has: (key) => this.has(collectionKey, key)
248
- };
249
- }
250
- toString() {
251
- return devalue.stringify(this.#collections);
252
- }
253
- async writeToDisk(filePath) {
254
- if (!this.#dirty) {
255
- return;
256
- }
257
- try {
258
- await fs.writeFile(filePath, this.toString());
259
- this.#file = filePath;
260
- this.#dirty = false;
261
- } catch (err) {
262
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
263
- }
33
+ return this._collections;
264
34
  }
265
35
  /**
266
36
  * Attempts to load a DataStore from the virtual module.
@@ -277,23 +47,9 @@ ${lines.join(",\n")}]);
277
47
  }
278
48
  static async fromMap(data) {
279
49
  const store = new DataStore();
280
- store.#collections = data;
50
+ store._collections = data;
281
51
  return store;
282
52
  }
283
- static async fromString(data) {
284
- const map = devalue.parse(data);
285
- return DataStore.fromMap(map);
286
- }
287
- static async fromFile(filePath) {
288
- try {
289
- if (existsSync(filePath)) {
290
- const data = await fs.readFile(filePath, "utf-8");
291
- return DataStore.fromString(data);
292
- }
293
- } catch {
294
- }
295
- return new DataStore();
296
- }
297
53
  }
298
54
  function dataStoreSingleton() {
299
55
  let instance = void 0;
@@ -309,15 +65,8 @@ function dataStoreSingleton() {
309
65
  }
310
66
  };
311
67
  }
312
- function contentModuleToId(fileName) {
313
- const params = new URLSearchParams(DEFERRED_MODULE);
314
- params.set("fileName", fileName);
315
- params.set(CONTENT_MODULE_FLAG, "true");
316
- return `${DEFERRED_MODULE}?${params.toString()}`;
317
- }
318
68
  const globalDataStore = dataStoreSingleton();
319
69
  export {
320
70
  DataStore,
321
- contentModuleToId,
322
71
  globalDataStore
323
72
  };
@@ -1,7 +1,7 @@
1
1
  import type { FSWatcher } from 'vite';
2
2
  import type { ZodSchema } from 'zod';
3
3
  import type { AstroIntegrationLogger, AstroSettings } from '../../@types/astro.js';
4
- import type { MetaStore, ScopedDataStore } from '../data-store.js';
4
+ import type { MetaStore, ScopedDataStore } from '../mutable-data-store.js';
5
5
  export interface ParseDataOptions<TData extends Record<string, unknown>> {
6
6
  /** The ID of the entry. Unique per collection */
7
7
  id: string;
@@ -0,0 +1,77 @@
1
+ import { type PathLike } from 'node:fs';
2
+ import { type DataEntry, DataStore, type RenderedContent } from './data-store.js';
3
+ /**
4
+ * Extends the DataStore with the ability to change entries and write them to disk.
5
+ * This is kept as a separate class to avoid needing node builtins at runtime, when read-only access is all that is needed.
6
+ */
7
+ export declare class MutableDataStore extends DataStore {
8
+ #private;
9
+ set(collectionName: string, key: string, value: unknown): void;
10
+ delete(collectionName: string, key: string): void;
11
+ clear(collectionName: string): void;
12
+ clearAll(): void;
13
+ addAssetImport(assetImport: string, filePath: string): void;
14
+ addAssetImports(assets: Array<string>, filePath: string): void;
15
+ addModuleImport(fileName: string): void;
16
+ writeAssetImports(filePath: PathLike): Promise<void>;
17
+ writeModuleImports(filePath: PathLike): Promise<void>;
18
+ scopedStore(collectionName: string): ScopedDataStore;
19
+ /**
20
+ * Returns a MetaStore for a given collection, or if no collection is provided, the default meta collection.
21
+ */
22
+ metaStore(collectionName?: string): MetaStore;
23
+ toString(): string;
24
+ writeToDisk(filePath: PathLike): Promise<void>;
25
+ /**
26
+ * Attempts to load a MutableDataStore from the virtual module.
27
+ * This only works in Vite.
28
+ */
29
+ static fromModule(): Promise<MutableDataStore>;
30
+ static fromMap(data: Map<string, Map<string, any>>): Promise<MutableDataStore>;
31
+ static fromString(data: string): Promise<MutableDataStore>;
32
+ static fromFile(filePath: string | URL): Promise<MutableDataStore>;
33
+ }
34
+ export interface ScopedDataStore {
35
+ get: <TData extends Record<string, unknown> = Record<string, unknown>>(key: string) => DataEntry<TData> | undefined;
36
+ entries: () => Array<[id: string, DataEntry]>;
37
+ set: <TData extends Record<string, unknown>>(opts: {
38
+ /** The ID of the entry. Must be unique per collection. */
39
+ id: string;
40
+ /** The data to store. */
41
+ data: TData;
42
+ /** The raw body of the content, if applicable. */
43
+ body?: string;
44
+ /** The file path of the content, if applicable. Relative to the site root. */
45
+ filePath?: string;
46
+ /** A content digest, to check if the content has changed. */
47
+ digest?: number | string;
48
+ /** The rendered content, if applicable. */
49
+ rendered?: RenderedContent;
50
+ /**
51
+ * If an entry is a deferred, its rendering phase is delegated to a virtual module during the runtime phase.
52
+ */
53
+ deferredRender?: boolean;
54
+ }) => boolean;
55
+ values: () => Array<DataEntry>;
56
+ keys: () => Array<string>;
57
+ delete: (key: string) => void;
58
+ clear: () => void;
59
+ has: (key: string) => boolean;
60
+ /**
61
+ * Adds a single asset to the store. This asset will be transformed
62
+ * by Vite, and the URL will be available in the final build.
63
+ * @param fileName
64
+ * @param specifier
65
+ * @returns
66
+ */
67
+ addModuleImport: (fileName: string) => void;
68
+ }
69
+ /**
70
+ * A key-value store for metadata strings. Useful for storing things like sync tokens.
71
+ */
72
+ export interface MetaStore {
73
+ get: (key: string) => string | undefined;
74
+ set: (key: string, value: string) => void;
75
+ has: (key: string) => boolean;
76
+ delete: (key: string) => void;
77
+ }
@@ -0,0 +1,269 @@
1
+ import { promises as fs, existsSync } from "node:fs";
2
+ import * as devalue from "devalue";
3
+ import { imageSrcToImportId, importIdToSymbolName } from "../assets/utils/resolveImports.js";
4
+ import { AstroError, AstroErrorData } from "../core/errors/index.js";
5
+ import { DataStore } from "./data-store.js";
6
+ import { contentModuleToId } from "./utils.js";
7
+ const SAVE_DEBOUNCE_MS = 500;
8
+ class MutableDataStore extends DataStore {
9
+ #file;
10
+ #assetsFile;
11
+ #modulesFile;
12
+ #saveTimeout;
13
+ #assetsSaveTimeout;
14
+ #modulesSaveTimeout;
15
+ #dirty = false;
16
+ #assetsDirty = false;
17
+ #modulesDirty = false;
18
+ #assetImports = /* @__PURE__ */ new Set();
19
+ #moduleImports = /* @__PURE__ */ new Map();
20
+ set(collectionName, key, value) {
21
+ const collection = this._collections.get(collectionName) ?? /* @__PURE__ */ new Map();
22
+ collection.set(String(key), value);
23
+ this._collections.set(collectionName, collection);
24
+ this.#saveToDiskDebounced();
25
+ }
26
+ delete(collectionName, key) {
27
+ const collection = this._collections.get(collectionName);
28
+ if (collection) {
29
+ collection.delete(String(key));
30
+ this.#saveToDiskDebounced();
31
+ }
32
+ }
33
+ clear(collectionName) {
34
+ this._collections.delete(collectionName);
35
+ this.#saveToDiskDebounced();
36
+ }
37
+ clearAll() {
38
+ this._collections.clear();
39
+ this.#saveToDiskDebounced();
40
+ }
41
+ addAssetImport(assetImport, filePath) {
42
+ const id = imageSrcToImportId(assetImport, filePath);
43
+ if (id) {
44
+ this.#assetImports.add(id);
45
+ this.#writeAssetsImportsDebounced();
46
+ }
47
+ }
48
+ addAssetImports(assets, filePath) {
49
+ assets.forEach((asset) => this.addAssetImport(asset, filePath));
50
+ }
51
+ addModuleImport(fileName) {
52
+ const id = contentModuleToId(fileName);
53
+ if (id) {
54
+ this.#moduleImports.set(fileName, id);
55
+ this.#writeModulesImportsDebounced();
56
+ }
57
+ }
58
+ async writeAssetImports(filePath) {
59
+ this.#assetsFile = filePath;
60
+ if (this.#assetImports.size === 0) {
61
+ try {
62
+ await fs.writeFile(filePath, "export default new Map();");
63
+ } catch (err) {
64
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
65
+ }
66
+ }
67
+ if (!this.#assetsDirty && existsSync(filePath)) {
68
+ return;
69
+ }
70
+ const imports = [];
71
+ const exports = [];
72
+ this.#assetImports.forEach((id) => {
73
+ const symbol = importIdToSymbolName(id);
74
+ imports.push(`import ${symbol} from '${id}';`);
75
+ exports.push(`[${JSON.stringify(id)}, ${symbol}]`);
76
+ });
77
+ const code = (
78
+ /* js */
79
+ `
80
+ ${imports.join("\n")}
81
+ export default new Map([${exports.join(", ")}]);
82
+ `
83
+ );
84
+ try {
85
+ await fs.writeFile(filePath, code);
86
+ } catch (err) {
87
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
88
+ }
89
+ this.#assetsDirty = false;
90
+ }
91
+ async writeModuleImports(filePath) {
92
+ this.#modulesFile = filePath;
93
+ if (this.#moduleImports.size === 0) {
94
+ try {
95
+ await fs.writeFile(filePath, "export default new Map();");
96
+ } catch (err) {
97
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
98
+ }
99
+ }
100
+ if (!this.#modulesDirty && existsSync(filePath)) {
101
+ return;
102
+ }
103
+ const lines = [];
104
+ for (const [fileName, specifier] of this.#moduleImports) {
105
+ lines.push(`['${fileName}', () => import('${specifier}')]`);
106
+ }
107
+ const code = `
108
+ export default new Map([
109
+ ${lines.join(",\n")}]);
110
+ `;
111
+ try {
112
+ await fs.writeFile(filePath, code);
113
+ } catch (err) {
114
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
115
+ }
116
+ this.#modulesDirty = false;
117
+ }
118
+ #writeAssetsImportsDebounced() {
119
+ this.#assetsDirty = true;
120
+ if (this.#assetsFile) {
121
+ if (this.#assetsSaveTimeout) {
122
+ clearTimeout(this.#assetsSaveTimeout);
123
+ }
124
+ this.#assetsSaveTimeout = setTimeout(() => {
125
+ this.#assetsSaveTimeout = void 0;
126
+ this.writeAssetImports(this.#assetsFile);
127
+ }, SAVE_DEBOUNCE_MS);
128
+ }
129
+ }
130
+ #writeModulesImportsDebounced() {
131
+ this.#modulesDirty = true;
132
+ if (this.#modulesFile) {
133
+ if (this.#modulesSaveTimeout) {
134
+ clearTimeout(this.#modulesSaveTimeout);
135
+ }
136
+ this.#modulesSaveTimeout = setTimeout(() => {
137
+ this.#modulesSaveTimeout = void 0;
138
+ this.writeModuleImports(this.#modulesFile);
139
+ }, SAVE_DEBOUNCE_MS);
140
+ }
141
+ }
142
+ #saveToDiskDebounced() {
143
+ this.#dirty = true;
144
+ if (this.#file) {
145
+ if (this.#saveTimeout) {
146
+ clearTimeout(this.#saveTimeout);
147
+ }
148
+ this.#saveTimeout = setTimeout(() => {
149
+ this.#saveTimeout = void 0;
150
+ this.writeToDisk(this.#file);
151
+ }, SAVE_DEBOUNCE_MS);
152
+ }
153
+ }
154
+ scopedStore(collectionName) {
155
+ return {
156
+ get: (key) => this.get(collectionName, key),
157
+ entries: () => this.entries(collectionName),
158
+ values: () => this.values(collectionName),
159
+ keys: () => this.keys(collectionName),
160
+ set: ({ id: key, data, body, filePath, deferredRender, digest, rendered }) => {
161
+ if (!key) {
162
+ throw new Error(`ID must be a non-empty string`);
163
+ }
164
+ const id = String(key);
165
+ if (digest) {
166
+ const existing = this.get(collectionName, id);
167
+ if (existing && existing.digest === digest) {
168
+ return false;
169
+ }
170
+ }
171
+ const entry = {
172
+ id,
173
+ data
174
+ };
175
+ if (body) {
176
+ entry.body = body;
177
+ }
178
+ if (filePath) {
179
+ if (filePath.startsWith("/")) {
180
+ throw new Error(`File path must be relative to the site root. Got: ${filePath}`);
181
+ }
182
+ entry.filePath = filePath;
183
+ }
184
+ if (digest) {
185
+ entry.digest = digest;
186
+ }
187
+ if (rendered) {
188
+ entry.rendered = rendered;
189
+ }
190
+ if (deferredRender) {
191
+ entry.deferredRender = deferredRender;
192
+ if (filePath) {
193
+ this.addModuleImport(filePath);
194
+ }
195
+ }
196
+ this.set(collectionName, id, entry);
197
+ return true;
198
+ },
199
+ delete: (key) => this.delete(collectionName, key),
200
+ clear: () => this.clear(collectionName),
201
+ has: (key) => this.has(collectionName, key),
202
+ addAssetImport: (assetImport, fileName) => this.addAssetImport(assetImport, fileName),
203
+ addAssetImports: (assets, fileName) => this.addAssetImports(assets, fileName),
204
+ addModuleImport: (fileName) => this.addModuleImport(fileName)
205
+ };
206
+ }
207
+ /**
208
+ * Returns a MetaStore for a given collection, or if no collection is provided, the default meta collection.
209
+ */
210
+ metaStore(collectionName = ":meta") {
211
+ const collectionKey = `meta:${collectionName}`;
212
+ return {
213
+ get: (key) => this.get(collectionKey, key),
214
+ set: (key, data) => this.set(collectionKey, key, data),
215
+ delete: (key) => this.delete(collectionKey, key),
216
+ has: (key) => this.has(collectionKey, key)
217
+ };
218
+ }
219
+ toString() {
220
+ return devalue.stringify(this._collections);
221
+ }
222
+ async writeToDisk(filePath) {
223
+ if (!this.#dirty) {
224
+ return;
225
+ }
226
+ try {
227
+ await fs.writeFile(filePath, this.toString());
228
+ this.#file = filePath;
229
+ this.#dirty = false;
230
+ } catch (err) {
231
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
232
+ }
233
+ }
234
+ /**
235
+ * Attempts to load a MutableDataStore from the virtual module.
236
+ * This only works in Vite.
237
+ */
238
+ static async fromModule() {
239
+ try {
240
+ const data = await import("astro:data-layer-content");
241
+ const map = devalue.unflatten(data.default);
242
+ return MutableDataStore.fromMap(map);
243
+ } catch {
244
+ }
245
+ return new MutableDataStore();
246
+ }
247
+ static async fromMap(data) {
248
+ const store = new MutableDataStore();
249
+ store._collections = data;
250
+ return store;
251
+ }
252
+ static async fromString(data) {
253
+ const map = devalue.parse(data);
254
+ return MutableDataStore.fromMap(map);
255
+ }
256
+ static async fromFile(filePath) {
257
+ try {
258
+ if (existsSync(filePath)) {
259
+ const data = await fs.readFile(filePath, "utf-8");
260
+ return MutableDataStore.fromString(data);
261
+ }
262
+ } catch {
263
+ }
264
+ return new MutableDataStore();
265
+ }
266
+ }
267
+ export {
268
+ MutableDataStore
269
+ };
@@ -477,11 +477,9 @@ async function writeContentFiles({
477
477
  contentConfig ? `typeof import(${configPathRelativeToCacheDir})` : "never"
478
478
  );
479
479
  if (settings.injectedTypes.some((t) => t.filename === CONTENT_TYPES_FILE)) {
480
- fs.promises.writeFile(
481
- new URL(CONTENT_TYPES_FILE, settings.dotAstroDir),
482
- typeTemplateContent,
483
- "utf-8"
484
- );
480
+ const filePath = fileURLToPath(new URL(CONTENT_TYPES_FILE, settings.dotAstroDir));
481
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
482
+ await fs.promises.writeFile(filePath, typeTemplateContent, "utf-8");
485
483
  } else {
486
484
  settings.injectedTypes.push({
487
485
  filename: CONTENT_TYPES_FILE,
@@ -485,4 +485,5 @@ export declare function posixifyPath(filePath: string): string;
485
485
  * Unlike `path.posix.relative`, this function will accept a platform path and return a posix path.
486
486
  */
487
487
  export declare function posixRelative(from: string, to: string): string;
488
+ export declare function contentModuleToId(fileName: string): string;
488
489
  export {};
@@ -12,6 +12,7 @@ import {
12
12
  CONTENT_FLAGS,
13
13
  CONTENT_LAYER_TYPE,
14
14
  CONTENT_MODULE_FLAG,
15
+ DEFERRED_MODULE,
15
16
  IMAGE_IMPORT_PREFIX,
16
17
  PROPAGATED_ASSET_FLAG
17
18
  } from "./consts.js";
@@ -465,7 +466,14 @@ function posixifyPath(filePath) {
465
466
  function posixRelative(from, to) {
466
467
  return posixifyPath(path.relative(from, to));
467
468
  }
469
+ function contentModuleToId(fileName) {
470
+ const params = new URLSearchParams(DEFERRED_MODULE);
471
+ params.set("fileName", fileName);
472
+ params.set(CONTENT_MODULE_FLAG, "true");
473
+ return `${DEFERRED_MODULE}?${params.toString()}`;
474
+ }
468
475
  export {
476
+ contentModuleToId,
469
477
  contentObservable,
470
478
  getContentEntryExts,
471
479
  getContentEntryIdAndSlug,
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "4.14.0";
1
+ const ASTRO_VERSION = "4.14.2";
2
2
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
3
3
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
4
4
  const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
@@ -1,11 +1,11 @@
1
1
  import fs, { existsSync } from "node:fs";
2
+ import { performance } from "node:perf_hooks";
2
3
  import { green } from "kleur/colors";
3
- import { performance } from "perf_hooks";
4
4
  import { gt, major, minor, patch } from "semver";
5
5
  import { DATA_STORE_FILE } from "../../content/consts.js";
6
6
  import { globalContentLayer } from "../../content/content-layer.js";
7
- import { DataStore, globalDataStore } from "../../content/data-store.js";
8
7
  import { attachContentServerListeners } from "../../content/index.js";
8
+ import { MutableDataStore } from "../../content/mutable-data-store.js";
9
9
  import { globalContentConfigObserver } from "../../content/utils.js";
10
10
  import { telemetry } from "../../events/index.js";
11
11
  import * as msg from "../messages.js";
@@ -23,7 +23,7 @@ async function dev(inlineConfig) {
23
23
  await telemetry.record([]);
24
24
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
25
25
  const logger = restart.container.logger;
26
- const currentVersion = "4.14.0";
26
+ const currentVersion = "4.14.2";
27
27
  const isPrerelease = currentVersion.includes("-");
28
28
  if (!isPrerelease) {
29
29
  try {
@@ -72,15 +72,13 @@ async function dev(inlineConfig) {
72
72
  try {
73
73
  const dataStoreFile = new URL(DATA_STORE_FILE, restart.container.settings.config.cacheDir);
74
74
  if (existsSync(dataStoreFile)) {
75
- store = await DataStore.fromFile(dataStoreFile);
76
- globalDataStore.set(store);
75
+ store = await MutableDataStore.fromFile(dataStoreFile);
77
76
  }
78
77
  } catch (err) {
79
78
  logger.error("content", err.message);
80
79
  }
81
80
  if (!store) {
82
- store = new DataStore();
83
- globalDataStore.set(store);
81
+ store = new MutableDataStore();
84
82
  }
85
83
  const config = globalContentConfigObserver.get();
86
84
  if (config.status === "error") {
@@ -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.14.0";
41
+ const version = "4.14.2";
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.14.0"}`
273
+ `v${"4.14.2"}`
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";
@@ -1,11 +1,12 @@
1
1
  import fsMod, { existsSync } from "node:fs";
2
2
  import { performance } from "node:perf_hooks";
3
+ import { fileURLToPath } from "node:url";
3
4
  import { dim } from "kleur/colors";
4
5
  import { createServer } from "vite";
5
6
  import { CONTENT_TYPES_FILE, DATA_STORE_FILE } from "../../content/consts.js";
6
7
  import { globalContentLayer } from "../../content/content-layer.js";
7
- import { DataStore, globalDataStore } from "../../content/data-store.js";
8
8
  import { createContentTypesGenerator } from "../../content/index.js";
9
+ import { MutableDataStore } from "../../content/mutable-data-store.js";
9
10
  import { getContentPaths, globalContentConfigObserver } from "../../content/utils.js";
10
11
  import { syncAstroEnv } from "../../env/sync.js";
11
12
  import { telemetry } from "../../events/index.js";
@@ -74,15 +75,13 @@ async function syncInternal({
74
75
  try {
75
76
  const dataStoreFile = new URL(DATA_STORE_FILE, settings.config.cacheDir);
76
77
  if (existsSync(dataStoreFile)) {
77
- store = await DataStore.fromFile(dataStoreFile);
78
- globalDataStore.set(store);
78
+ store = await MutableDataStore.fromFile(dataStoreFile);
79
79
  }
80
80
  } catch (err) {
81
81
  logger.error("content", err.message);
82
82
  }
83
83
  if (!store) {
84
- store = new DataStore();
85
- globalDataStore.set(store);
84
+ store = new MutableDataStore();
86
85
  }
87
86
  const contentLayer = globalContentLayer.init({
88
87
  settings,
@@ -91,7 +90,7 @@ async function syncInternal({
91
90
  });
92
91
  await contentLayer.sync();
93
92
  settings.timer.end("Sync content layer");
94
- } else if (fs.existsSync(getContentPaths(settings.config, fs).contentDir.href)) {
93
+ } else if (fs.existsSync(fileURLToPath(getContentPaths(settings.config, fs).contentDir))) {
95
94
  settings.injectedTypes.push({
96
95
  filename: CONTENT_TYPES_FILE,
97
96
  content: ""
@@ -61,9 +61,10 @@ if(response.status === 200 && response.headers.get('content-type') === 'text/htm
61
61
  let html = await response.text();
62
62
 
63
63
  // Swap!
64
- while(script.previousSibling?.nodeType !== 8 &&
65
- script.previousSibling?.data !== 'server-island-start') {
66
- script.previousSibling?.remove();
64
+ while(script.previousSibling &&
65
+ script.previousSibling.nodeType !== 8 &&
66
+ script.previousSibling.data !== 'server-island-start') {
67
+ script.previousSibling.remove();
67
68
  }
68
69
  script.previousSibling?.remove();
69
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "4.14.0",
3
+ "version": "4.14.2",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -115,8 +115,8 @@
115
115
  "@babel/plugin-transform-react-jsx": "^7.25.2",
116
116
  "@babel/traverse": "^7.25.3",
117
117
  "@babel/types": "^7.25.2",
118
- "@rollup/pluginutils": "^5.1.0",
119
118
  "@oslojs/encoding": "^0.4.1",
119
+ "@rollup/pluginutils": "^5.1.0",
120
120
  "@types/babel__core": "^7.20.5",
121
121
  "@types/cookie": "^0.6.0",
122
122
  "acorn": "^8.12.1",
@@ -168,6 +168,7 @@
168
168
  "vitefu": "^0.2.5",
169
169
  "which-pm": "^3.0.0",
170
170
  "xxhash-wasm": "^1.0.2",
171
+ "yargs-parser": "^21.1.1",
171
172
  "zod": "^3.23.8",
172
173
  "zod-to-json-schema": "^3.23.2",
173
174
  "zod-to-ts": "^1.2.0",
@@ -197,6 +198,7 @@
197
198
  "@types/micromatch": "^4.0.9",
198
199
  "@types/prompts": "^2.4.9",
199
200
  "@types/semver": "^7.5.8",
201
+ "@types/yargs-parser": "^21.0.3",
200
202
  "cheerio": "1.0.0",
201
203
  "eol": "^0.9.1",
202
204
  "expect-type": "^0.19.0",