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.
- package/dist/@types/astro.d.ts +12 -12
- package/dist/assets/endpoint/node.js +1 -1
- package/dist/cli/check/index.js +1 -1
- package/dist/cli/db/index.d.ts +3 -4
- package/dist/cli/db/index.js +3 -7
- package/dist/cli/flags.d.ts +2 -3
- package/dist/cli/flags.js +1 -1
- package/dist/cli/index.js +12 -25
- package/dist/content/content-layer.d.ts +2 -2
- package/dist/content/data-store.d.ts +5 -65
- package/dist/content/data-store.js +10 -261
- package/dist/content/loaders/types.d.ts +1 -1
- package/dist/content/mutable-data-store.d.ts +77 -0
- package/dist/content/mutable-data-store.js +269 -0
- package/dist/content/types-generator.js +3 -5
- package/dist/content/utils.d.ts +1 -0
- package/dist/content/utils.js +8 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +5 -7
- package/dist/core/logger/vite.js +1 -1
- package/dist/core/messages.js +2 -2
- package/dist/core/preview/static-preview-server.js +1 -1
- package/dist/core/routing/manifest/create.js +1 -1
- package/dist/core/sync/index.js +5 -6
- package/dist/runtime/server/render/server-islands.js +4 -3
- package/dist/vite-plugin-astro-server/response.js +1 -1
- package/package.json +4 -2
package/dist/@types/astro.d.ts
CHANGED
|
@@ -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
|
-
* ```
|
|
2203
|
+
* ```ts ins={3,8} del={7}
|
|
2204
2204
|
* // src/content/config.ts
|
|
2205
2205
|
* import { defineCollection, z } from 'astro:content';
|
|
2206
|
-
*
|
|
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
|
-
*
|
|
2211
|
-
*
|
|
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
|
-
* ```
|
|
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
|
-
*
|
|
2230
|
-
*
|
|
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
|
-
* ```
|
|
2239
|
+
* ```astro ins={4,9} del={3,8}
|
|
2240
2240
|
* // src/pages/index.astro
|
|
2241
2241
|
* ---
|
|
2242
|
-
*
|
|
2243
|
-
*
|
|
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
|
-
*
|
|
2248
|
-
*
|
|
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";
|
package/dist/cli/check/index.js
CHANGED
|
@@ -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:
|
|
10
|
+
cwd: flags.root
|
|
11
11
|
};
|
|
12
12
|
const checkPackage = await getPackage(
|
|
13
13
|
"@astrojs/check",
|
package/dist/cli/db/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function db({
|
|
3
|
-
|
|
4
|
-
flags: Flags;
|
|
1
|
+
import type { Arguments } from 'yargs-parser';
|
|
2
|
+
export declare function db({ flags }: {
|
|
3
|
+
flags: Arguments;
|
|
5
4
|
}): Promise<void>;
|
package/dist/cli/db/index.js
CHANGED
|
@@ -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({
|
|
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:
|
|
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
|
-
|
|
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
|
package/dist/cli/flags.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type {
|
|
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
|
|
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 === "
|
|
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(
|
|
47
|
-
const cmd =
|
|
48
|
-
if (
|
|
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,
|
|
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 =
|
|
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] =
|
|
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 =
|
|
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({
|
|
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
|
|
167
|
-
|
|
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,
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
5
|
+
this._collections = /* @__PURE__ */ new Map();
|
|
22
6
|
}
|
|
23
7
|
get(collectionName, key) {
|
|
24
|
-
return this
|
|
8
|
+
return this._collections.get(collectionName)?.get(String(key));
|
|
25
9
|
}
|
|
26
10
|
entries(collectionName) {
|
|
27
|
-
const collection = this
|
|
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
|
|
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
|
|
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
|
|
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
|
|
30
|
+
return this._collections.has(collectionName);
|
|
68
31
|
}
|
|
69
32
|
collections() {
|
|
70
|
-
return this
|
|
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
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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,
|
package/dist/content/utils.d.ts
CHANGED
|
@@ -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 {};
|
package/dist/content/utils.js
CHANGED
|
@@ -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,
|
package/dist/core/constants.js
CHANGED
package/dist/core/dev/dev.js
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
83
|
-
globalDataStore.set(store);
|
|
81
|
+
store = new MutableDataStore();
|
|
84
82
|
}
|
|
85
83
|
const config = globalContentConfigObserver.get();
|
|
86
84
|
if (config.status === "error") {
|
package/dist/core/logger/vite.js
CHANGED
package/dist/core/messages.js
CHANGED
|
@@ -38,7 +38,7 @@ function serverStart({
|
|
|
38
38
|
host,
|
|
39
39
|
base
|
|
40
40
|
}) {
|
|
41
|
-
const version = "4.14.
|
|
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.
|
|
273
|
+
`v${"4.14.2"}`
|
|
274
274
|
)} ${headline}`
|
|
275
275
|
);
|
|
276
276
|
}
|
package/dist/core/sync/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
65
|
-
script.previousSibling
|
|
66
|
-
script.previousSibling
|
|
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
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro",
|
|
3
|
-
"version": "4.14.
|
|
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",
|