@imjp/writenex-astro 0.1.0
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/README.md +539 -0
- package/dist/chunk-5PM6EQE5.js +151 -0
- package/dist/chunk-5PM6EQE5.js.map +1 -0
- package/dist/chunk-7XU5X6CW.js +1331 -0
- package/dist/chunk-7XU5X6CW.js.map +1 -0
- package/dist/chunk-AAOQHQPU.js +574 -0
- package/dist/chunk-AAOQHQPU.js.map +1 -0
- package/dist/chunk-CF2XXJFF.js +1410 -0
- package/dist/chunk-CF2XXJFF.js.map +1 -0
- package/dist/chunk-CRPZUUDU.js +52 -0
- package/dist/chunk-CRPZUUDU.js.map +1 -0
- package/dist/chunk-CYLDJ3HZ.js +310 -0
- package/dist/chunk-CYLDJ3HZ.js.map +1 -0
- package/dist/chunk-KIKIPIFA.js +1 -0
- package/dist/chunk-KIKIPIFA.js.map +1 -0
- package/dist/chunk-XNTQTTJU.js +145 -0
- package/dist/chunk-XNTQTTJU.js.map +1 -0
- package/dist/client/index.css +2 -0
- package/dist/client/index.css.map +1 -0
- package/dist/client/index.js +375 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/styles.css +584 -0
- package/dist/client/variables.css +304 -0
- package/dist/config/index.d.ts +54 -0
- package/dist/config/index.js +38 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config-BmEdBDo_.d.ts +220 -0
- package/dist/content-BWR52vD-.d.ts +64 -0
- package/dist/discovery/index.d.ts +310 -0
- package/dist/discovery/index.js +38 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/errors-C0iYiDTv.d.ts +107 -0
- package/dist/filesystem/index.d.ts +1292 -0
- package/dist/filesystem/index.js +203 -0
- package/dist/filesystem/index.js.map +1 -0
- package/dist/image-FP7w5ZIs.d.ts +47 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +151 -0
- package/dist/index.js.map +1 -0
- package/dist/loader-55LWCXHA.js +12 -0
- package/dist/loader-55LWCXHA.js.map +1 -0
- package/dist/loader-CrdnaAWR.d.ts +327 -0
- package/dist/server/index.d.ts +357 -0
- package/dist/server/index.js +37 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +94 -0
- package/src/client/App.tsx +900 -0
- package/src/client/components/ConfigPanel/ConfigPanel.css +553 -0
- package/src/client/components/ConfigPanel/ConfigPanel.tsx +396 -0
- package/src/client/components/ConfigPanel/index.ts +6 -0
- package/src/client/components/CreateContentModal/CreateContentModal.css +327 -0
- package/src/client/components/CreateContentModal/CreateContentModal.tsx +216 -0
- package/src/client/components/CreateContentModal/index.ts +7 -0
- package/src/client/components/Editor/Editor.css +885 -0
- package/src/client/components/Editor/Editor.tsx +484 -0
- package/src/client/components/Editor/ImageDialog.css +344 -0
- package/src/client/components/Editor/ImageDialog.tsx +367 -0
- package/src/client/components/Editor/LinkDialog.css +326 -0
- package/src/client/components/Editor/LinkDialog.tsx +332 -0
- package/src/client/components/Editor/index.ts +6 -0
- package/src/client/components/FrontmatterForm/FrontmatterForm.css +468 -0
- package/src/client/components/FrontmatterForm/FrontmatterForm.tsx +914 -0
- package/src/client/components/FrontmatterForm/index.ts +7 -0
- package/src/client/components/Header/Header.css +300 -0
- package/src/client/components/Header/Header.tsx +300 -0
- package/src/client/components/Header/index.ts +7 -0
- package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.css +239 -0
- package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.tsx +151 -0
- package/src/client/components/KeyboardShortcuts/index.ts +6 -0
- package/src/client/components/LazyEditor.tsx +75 -0
- package/src/client/components/LiveRegion/LiveRegion.css +19 -0
- package/src/client/components/LiveRegion/LiveRegion.tsx +60 -0
- package/src/client/components/LiveRegion/index.ts +7 -0
- package/src/client/components/SearchReplace/SearchReplacePanel.css +300 -0
- package/src/client/components/SearchReplace/SearchReplacePanel.tsx +332 -0
- package/src/client/components/SearchReplace/index.ts +7 -0
- package/src/client/components/SelectCollectionModal/SelectCollectionModal.css +308 -0
- package/src/client/components/SelectCollectionModal/SelectCollectionModal.tsx +223 -0
- package/src/client/components/SelectCollectionModal/index.ts +7 -0
- package/src/client/components/Sidebar/Sidebar.css +570 -0
- package/src/client/components/Sidebar/Sidebar.tsx +617 -0
- package/src/client/components/Sidebar/index.ts +7 -0
- package/src/client/components/SkipLink/SkipLink.css +51 -0
- package/src/client/components/SkipLink/SkipLink.tsx +67 -0
- package/src/client/components/SkipLink/index.ts +7 -0
- package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.css +233 -0
- package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.tsx +160 -0
- package/src/client/components/UnsavedChangesModal/index.ts +1 -0
- package/src/client/components/VersionHistory/DiffViewer.css +430 -0
- package/src/client/components/VersionHistory/DiffViewer.tsx +383 -0
- package/src/client/components/VersionHistory/VersionActions.css +318 -0
- package/src/client/components/VersionHistory/VersionActions.tsx +277 -0
- package/src/client/components/VersionHistory/VersionHistoryPanel.css +369 -0
- package/src/client/components/VersionHistory/VersionHistoryPanel.tsx +469 -0
- package/src/client/components/VersionHistory/index.ts +9 -0
- package/src/client/context/ApiContext.tsx +154 -0
- package/src/client/context/ThemeContext.tsx +172 -0
- package/src/client/hooks/useAnnounce.ts +201 -0
- package/src/client/hooks/useApi.ts +374 -0
- package/src/client/hooks/useArrowNavigation.ts +286 -0
- package/src/client/hooks/useAutosave.ts +241 -0
- package/src/client/hooks/useFocusTrap.ts +178 -0
- package/src/client/hooks/useKeyboardShortcuts.ts +203 -0
- package/src/client/hooks/useSearch.ts +206 -0
- package/src/client/hooks/useVersionHistory.ts +451 -0
- package/src/client/index.tsx +70 -0
- package/src/client/styles.css +584 -0
- package/src/client/utils/focus.ts +57 -0
- package/src/client/utils/openInEditor.ts +130 -0
- package/src/client/variables.css +304 -0
- package/src/config/defaults.ts +109 -0
- package/src/config/index.ts +32 -0
- package/src/config/loader.ts +174 -0
- package/src/config/schema.ts +161 -0
- package/src/core/constants.ts +39 -0
- package/src/core/errors.ts +739 -0
- package/src/core/index.ts +11 -0
- package/src/discovery/collections.ts +216 -0
- package/src/discovery/index.ts +33 -0
- package/src/discovery/patterns.ts +702 -0
- package/src/discovery/schema.ts +453 -0
- package/src/filesystem/images.ts +798 -0
- package/src/filesystem/index.ts +107 -0
- package/src/filesystem/reader.ts +452 -0
- package/src/filesystem/version-config.ts +390 -0
- package/src/filesystem/versions.ts +1339 -0
- package/src/filesystem/watcher.ts +226 -0
- package/src/filesystem/writer.ts +540 -0
- package/src/index.ts +61 -0
- package/src/integration.ts +228 -0
- package/src/server/assets.ts +254 -0
- package/src/server/cache.ts +355 -0
- package/src/server/index.ts +33 -0
- package/src/server/middleware.ts +209 -0
- package/src/server/routes.ts +1428 -0
- package/src/types/api.ts +61 -0
- package/src/types/config.ts +134 -0
- package/src/types/content.ts +64 -0
- package/src/types/image.ts +48 -0
- package/src/types/index.ts +58 -0
- package/src/types/version.ts +117 -0
|
@@ -0,0 +1,1292 @@
|
|
|
1
|
+
import { C as ContentItem, a as ContentSummary } from '../content-BWR52vD-.js';
|
|
2
|
+
import { V as VersionHistoryConfig, d as SaveVersionOptions, e as VersionResult, f as VersionEntry, g as Version, R as RestoreVersionOptions, h as RestoreResult, i as VersionManifest, I as ImageConfig } from '../config-BmEdBDo_.js';
|
|
3
|
+
import { C as ContentConflictError } from '../errors-C0iYiDTv.js';
|
|
4
|
+
import { I as ImageDiscoveryOptions, a as ImageDiscoveryResult, D as DiscoveredImage } from '../image-FP7w5ZIs.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Filesystem reader for content collections
|
|
8
|
+
*
|
|
9
|
+
* This module provides functions for reading content files from the filesystem,
|
|
10
|
+
* parsing frontmatter, and extracting content metadata.
|
|
11
|
+
*
|
|
12
|
+
* ## Features:
|
|
13
|
+
* - Read individual content files with frontmatter parsing
|
|
14
|
+
* - List all content files in a collection
|
|
15
|
+
* - Generate content summaries for listing
|
|
16
|
+
* - Support for .md and .mdx files
|
|
17
|
+
*
|
|
18
|
+
* @module @writenex/astro/filesystem/reader
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Options for reading content
|
|
23
|
+
*/
|
|
24
|
+
interface ReadContentOptions {
|
|
25
|
+
/** Include draft content in listings */
|
|
26
|
+
includeDrafts?: boolean;
|
|
27
|
+
/** Sort field for listings */
|
|
28
|
+
sortBy?: string;
|
|
29
|
+
/** Sort order */
|
|
30
|
+
sortOrder?: "asc" | "desc";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of reading a content file
|
|
34
|
+
*/
|
|
35
|
+
interface ReadFileResult {
|
|
36
|
+
/** Whether the read was successful */
|
|
37
|
+
success: boolean;
|
|
38
|
+
/** The content item (if successful) */
|
|
39
|
+
content?: ContentItem;
|
|
40
|
+
/** Error message (if failed) */
|
|
41
|
+
error?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if a file is a content file based on extension
|
|
45
|
+
*
|
|
46
|
+
* @param filename - The filename to check
|
|
47
|
+
* @returns True if the file is a content file
|
|
48
|
+
*/
|
|
49
|
+
declare function isContentFile(filename: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Extract slug from a content file path
|
|
52
|
+
*
|
|
53
|
+
* Handles various file patterns:
|
|
54
|
+
* - `my-post.md` -> `my-post`
|
|
55
|
+
* - `2024-01-15-my-post.md` -> `2024-01-15-my-post`
|
|
56
|
+
* - `my-post/index.md` -> `my-post`
|
|
57
|
+
*
|
|
58
|
+
* @param filePath - Path to the content file
|
|
59
|
+
* @param collectionPath - Path to the collection directory
|
|
60
|
+
* @returns The extracted slug
|
|
61
|
+
*/
|
|
62
|
+
declare function extractSlug(filePath: string, collectionPath: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Generate an excerpt from markdown content
|
|
65
|
+
*
|
|
66
|
+
* @param body - The markdown body content
|
|
67
|
+
* @param maxLength - Maximum excerpt length
|
|
68
|
+
* @returns The generated excerpt
|
|
69
|
+
*/
|
|
70
|
+
declare function generateExcerpt(body: string, maxLength?: number): string;
|
|
71
|
+
/**
|
|
72
|
+
* Read and parse a single content file
|
|
73
|
+
*
|
|
74
|
+
* @param filePath - Absolute path to the content file
|
|
75
|
+
* @param collectionPath - Path to the collection directory
|
|
76
|
+
* @returns ReadFileResult with the parsed content or error
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const result = await readContentFile(
|
|
81
|
+
* '/project/src/content/blog/my-post.md',
|
|
82
|
+
* '/project/src/content/blog'
|
|
83
|
+
* );
|
|
84
|
+
*
|
|
85
|
+
* if (result.success) {
|
|
86
|
+
* console.log(result.content.frontmatter.title);
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function readContentFile(filePath: string, collectionPath: string): Promise<ReadFileResult>;
|
|
91
|
+
/**
|
|
92
|
+
* Read all content files in a collection
|
|
93
|
+
*
|
|
94
|
+
* @param collectionPath - Absolute path to the collection directory
|
|
95
|
+
* @param options - Read options
|
|
96
|
+
* @returns Array of content items
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const items = await readCollection('/project/src/content/blog', {
|
|
101
|
+
* includeDrafts: false,
|
|
102
|
+
* sortBy: 'pubDate',
|
|
103
|
+
* sortOrder: 'desc',
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function readCollection(collectionPath: string, options?: ReadContentOptions): Promise<ContentItem[]>;
|
|
108
|
+
/**
|
|
109
|
+
* Convert a content item to a summary for listing
|
|
110
|
+
*
|
|
111
|
+
* @param item - The full content item
|
|
112
|
+
* @returns Content summary with essential fields
|
|
113
|
+
*/
|
|
114
|
+
declare function toContentSummary(item: ContentItem): ContentSummary;
|
|
115
|
+
/**
|
|
116
|
+
* Get content summaries for a collection
|
|
117
|
+
*
|
|
118
|
+
* @param collectionPath - Absolute path to the collection directory
|
|
119
|
+
* @param options - Read options
|
|
120
|
+
* @returns Array of content summaries
|
|
121
|
+
*/
|
|
122
|
+
declare function getCollectionSummaries(collectionPath: string, options?: ReadContentOptions): Promise<ContentSummary[]>;
|
|
123
|
+
/**
|
|
124
|
+
* Get the count of content files in a collection
|
|
125
|
+
*
|
|
126
|
+
* @param collectionPath - Absolute path to the collection directory
|
|
127
|
+
* @returns Number of content files
|
|
128
|
+
*/
|
|
129
|
+
declare function getCollectionCount(collectionPath: string): Promise<number>;
|
|
130
|
+
/**
|
|
131
|
+
* Check if a collection directory exists and contains content
|
|
132
|
+
*
|
|
133
|
+
* @param collectionPath - Absolute path to the collection directory
|
|
134
|
+
* @returns Object with exists and hasContent flags
|
|
135
|
+
*/
|
|
136
|
+
declare function checkCollection(collectionPath: string): Promise<{
|
|
137
|
+
exists: boolean;
|
|
138
|
+
hasContent: boolean;
|
|
139
|
+
count: number;
|
|
140
|
+
}>;
|
|
141
|
+
/**
|
|
142
|
+
* Get file stats for a content file
|
|
143
|
+
*
|
|
144
|
+
* @param filePath - Path to the content file
|
|
145
|
+
* @returns File stats or null if file doesn't exist
|
|
146
|
+
*/
|
|
147
|
+
declare function getFileStats(filePath: string): Promise<{
|
|
148
|
+
size: number;
|
|
149
|
+
mtime: Date;
|
|
150
|
+
ctime: Date;
|
|
151
|
+
} | null>;
|
|
152
|
+
/**
|
|
153
|
+
* Get the file path for a content item by ID
|
|
154
|
+
*
|
|
155
|
+
* Searches for the content file in the collection directory,
|
|
156
|
+
* handling different content structures:
|
|
157
|
+
* - Folder-based: `slug/index.md` or `slug/index.mdx`
|
|
158
|
+
* - Flat file: `slug.md` or `slug.mdx`
|
|
159
|
+
*
|
|
160
|
+
* @param collectionPath - Path to the collection directory
|
|
161
|
+
* @param contentId - Content ID (slug)
|
|
162
|
+
* @returns File path if found, null otherwise
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* const filePath = getContentFilePath('/project/src/content/blog', 'my-post');
|
|
167
|
+
* // Returns: '/project/src/content/blog/my-post.md' or
|
|
168
|
+
* // '/project/src/content/blog/my-post/index.md'
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
declare function getContentFilePath(collectionPath: string, contentId: string): string | null;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @fileoverview Filesystem writer for content operations
|
|
175
|
+
*
|
|
176
|
+
* This module provides functions for creating, updating, and deleting
|
|
177
|
+
* content files in Astro content collections.
|
|
178
|
+
*
|
|
179
|
+
* ## Features:
|
|
180
|
+
* - Create new content files with frontmatter
|
|
181
|
+
* - Update existing content files
|
|
182
|
+
* - Delete content files
|
|
183
|
+
* - Generate unique slugs to avoid collisions
|
|
184
|
+
* - Support for different file patterns (flat, folder-based, date-prefixed)
|
|
185
|
+
* - Automatic version history creation before updates
|
|
186
|
+
*
|
|
187
|
+
* @module @writenex/astro/filesystem/writer
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Options for creating content
|
|
192
|
+
*/
|
|
193
|
+
interface CreateContentOptions {
|
|
194
|
+
/** Frontmatter data */
|
|
195
|
+
frontmatter: Record<string, unknown>;
|
|
196
|
+
/** Markdown body content */
|
|
197
|
+
body: string;
|
|
198
|
+
/** Custom slug (optional, generated from title if not provided) */
|
|
199
|
+
slug?: string;
|
|
200
|
+
/** File pattern for the collection (e.g., "{slug}/index.md", "{date}-{slug}.md") */
|
|
201
|
+
filePattern?: string;
|
|
202
|
+
/** Custom token values to override automatic resolution */
|
|
203
|
+
customTokens?: Record<string, string>;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Options for updating content
|
|
207
|
+
*/
|
|
208
|
+
interface UpdateContentOptions {
|
|
209
|
+
/** Updated frontmatter data */
|
|
210
|
+
frontmatter?: Record<string, unknown>;
|
|
211
|
+
/** Updated markdown body content */
|
|
212
|
+
body?: string;
|
|
213
|
+
/** Project root for version history (required for version creation) */
|
|
214
|
+
projectRoot?: string;
|
|
215
|
+
/** Collection name for version history */
|
|
216
|
+
collection?: string;
|
|
217
|
+
/** Version history configuration */
|
|
218
|
+
versionHistoryConfig?: Required<VersionHistoryConfig>;
|
|
219
|
+
/**
|
|
220
|
+
* Expected modification time for conflict detection.
|
|
221
|
+
* If provided and the file's mtime differs, the update will fail with a conflict error.
|
|
222
|
+
*/
|
|
223
|
+
expectedMtime?: number;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Result of a write operation
|
|
227
|
+
*/
|
|
228
|
+
interface WriteResult {
|
|
229
|
+
/** Whether the operation was successful */
|
|
230
|
+
success: boolean;
|
|
231
|
+
/** The content ID (slug) */
|
|
232
|
+
id?: string;
|
|
233
|
+
/** The file path */
|
|
234
|
+
path?: string;
|
|
235
|
+
/** Error message if failed */
|
|
236
|
+
error?: string;
|
|
237
|
+
/** New modification time after write (for conflict detection) */
|
|
238
|
+
mtime?: number;
|
|
239
|
+
/** Conflict error if update failed due to external modification */
|
|
240
|
+
conflict?: ContentConflictError;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Generate a URL-safe slug from a string
|
|
244
|
+
*
|
|
245
|
+
* @param text - Text to slugify
|
|
246
|
+
* @returns URL-safe slug
|
|
247
|
+
*/
|
|
248
|
+
declare function generateSlug(text: string): string;
|
|
249
|
+
/**
|
|
250
|
+
* Generate a unique slug that doesn't conflict with existing files
|
|
251
|
+
*
|
|
252
|
+
* @param baseSlug - The base slug to start with
|
|
253
|
+
* @param collectionPath - Path to the collection directory
|
|
254
|
+
* @param filePattern - File pattern (default: "{slug}.md")
|
|
255
|
+
* @returns A unique slug
|
|
256
|
+
*/
|
|
257
|
+
declare function generateUniqueSlug(baseSlug: string, collectionPath: string, filePattern?: string): Promise<string>;
|
|
258
|
+
/**
|
|
259
|
+
* Create a new content file in a collection
|
|
260
|
+
*
|
|
261
|
+
* Supports various file patterns with automatic token resolution:
|
|
262
|
+
* - `{slug}.md` - Simple flat structure (default)
|
|
263
|
+
* - `{slug}/index.md` - Folder-based content
|
|
264
|
+
* - `{date}-{slug}.md` - Date-prefixed naming
|
|
265
|
+
* - `{year}/{slug}.md` - Year folder structure
|
|
266
|
+
* - `{year}/{month}/{slug}.md` - Year/month folder structure
|
|
267
|
+
* - `{year}/{month}/{day}/{slug}.md` - Full date folder structure
|
|
268
|
+
* - `{lang}/{slug}.md` - Language-prefixed (i18n)
|
|
269
|
+
* - `{category}/{slug}.md` - Category folder structure
|
|
270
|
+
* - `{author}/{slug}.md` - Author folder structure
|
|
271
|
+
* - Any custom pattern with tokens from frontmatter
|
|
272
|
+
*
|
|
273
|
+
* Token resolution priority:
|
|
274
|
+
* 1. Custom tokens (explicitly provided via customTokens)
|
|
275
|
+
* 2. Known token resolvers (date, year, month, lang, category, etc.)
|
|
276
|
+
* 3. Frontmatter values (for custom tokens)
|
|
277
|
+
* 4. Default values
|
|
278
|
+
*
|
|
279
|
+
* @param collectionPath - Absolute path to the collection directory
|
|
280
|
+
* @param options - Content creation options
|
|
281
|
+
* @returns WriteResult with success status and file info
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```typescript
|
|
285
|
+
* // Flat structure
|
|
286
|
+
* const result = await createContent('/project/src/content/blog', {
|
|
287
|
+
* frontmatter: { title: 'My New Post', pubDate: new Date() },
|
|
288
|
+
* body: '# Hello World',
|
|
289
|
+
* });
|
|
290
|
+
*
|
|
291
|
+
* // Folder-based structure
|
|
292
|
+
* const result = await createContent('/project/src/content/blog', {
|
|
293
|
+
* frontmatter: { title: 'My New Post', pubDate: new Date() },
|
|
294
|
+
* body: '# Hello World',
|
|
295
|
+
* filePattern: '{slug}/index.md',
|
|
296
|
+
* });
|
|
297
|
+
*
|
|
298
|
+
* // i18n structure with custom token
|
|
299
|
+
* const result = await createContent('/project/src/content/blog', {
|
|
300
|
+
* frontmatter: { title: 'My New Post', lang: 'id' },
|
|
301
|
+
* body: '# Hello World',
|
|
302
|
+
* filePattern: '{lang}/{slug}.md',
|
|
303
|
+
* });
|
|
304
|
+
*
|
|
305
|
+
* // Custom pattern with explicit token
|
|
306
|
+
* const result = await createContent('/project/src/content/blog', {
|
|
307
|
+
* frontmatter: { title: 'My New Post' },
|
|
308
|
+
* body: '# Hello World',
|
|
309
|
+
* filePattern: '{category}/{slug}.md',
|
|
310
|
+
* customTokens: { category: 'tutorials' },
|
|
311
|
+
* });
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
declare function createContent(collectionPath: string, options: CreateContentOptions): Promise<WriteResult>;
|
|
315
|
+
/**
|
|
316
|
+
* Update an existing content file
|
|
317
|
+
*
|
|
318
|
+
* Creates a version snapshot of the current content before updating
|
|
319
|
+
* when version history is configured. Skips both version creation and
|
|
320
|
+
* file write if the new content is identical to the current file content.
|
|
321
|
+
* Version creation errors are logged but do not fail the save operation.
|
|
322
|
+
*
|
|
323
|
+
* @param filePath - Absolute path to the content file
|
|
324
|
+
* @param collectionPath - Path to the collection directory
|
|
325
|
+
* @param options - Update options including version history config
|
|
326
|
+
* @returns WriteResult with success status
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* ```typescript
|
|
330
|
+
* const result = await updateContent(
|
|
331
|
+
* '/project/src/content/blog/my-post.md',
|
|
332
|
+
* '/project/src/content/blog',
|
|
333
|
+
* {
|
|
334
|
+
* frontmatter: { title: 'Updated Title' },
|
|
335
|
+
* body: '# Updated Content',
|
|
336
|
+
* projectRoot: '/project',
|
|
337
|
+
* collection: 'blog',
|
|
338
|
+
* versionHistoryConfig: { enabled: true, maxVersions: 20, storagePath: '.writenex/versions' },
|
|
339
|
+
* }
|
|
340
|
+
* );
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
declare function updateContent(filePath: string, collectionPath: string, options: UpdateContentOptions): Promise<WriteResult>;
|
|
344
|
+
/**
|
|
345
|
+
* Delete a content file
|
|
346
|
+
*
|
|
347
|
+
* @param filePath - Absolute path to the content file
|
|
348
|
+
* @returns WriteResult with success status
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* const result = await deleteContent('/project/src/content/blog/my-post.md');
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
declare function deleteContent(filePath: string): Promise<WriteResult>;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* @fileoverview File watcher for detecting external changes
|
|
359
|
+
*
|
|
360
|
+
* This module provides file watching capabilities to detect when
|
|
361
|
+
* content files are modified outside of the Writenex editor
|
|
362
|
+
* (e.g., in VS Code or another editor).
|
|
363
|
+
*
|
|
364
|
+
* @module @writenex/astro/filesystem/watcher
|
|
365
|
+
*/
|
|
366
|
+
/**
|
|
367
|
+
* File change event types
|
|
368
|
+
*/
|
|
369
|
+
type FileChangeType = "add" | "change" | "unlink";
|
|
370
|
+
/**
|
|
371
|
+
* File change event
|
|
372
|
+
*/
|
|
373
|
+
interface FileChangeEvent {
|
|
374
|
+
type: FileChangeType;
|
|
375
|
+
path: string;
|
|
376
|
+
collection: string;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Watcher options
|
|
380
|
+
*/
|
|
381
|
+
interface WatcherOptions {
|
|
382
|
+
/** Callback when a file changes */
|
|
383
|
+
onChange?: (event: FileChangeEvent) => void;
|
|
384
|
+
/** Debounce delay in milliseconds */
|
|
385
|
+
debounceMs?: number;
|
|
386
|
+
/** Patterns to ignore */
|
|
387
|
+
ignored?: string[];
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Content file watcher
|
|
391
|
+
*
|
|
392
|
+
* Watches the src/content directory for changes and emits events
|
|
393
|
+
* when files are added, modified, or deleted.
|
|
394
|
+
*/
|
|
395
|
+
declare class ContentWatcher {
|
|
396
|
+
private watcher;
|
|
397
|
+
private projectRoot;
|
|
398
|
+
private contentDir;
|
|
399
|
+
private options;
|
|
400
|
+
private debounceTimers;
|
|
401
|
+
constructor(projectRoot: string, contentDir?: string, options?: WatcherOptions);
|
|
402
|
+
/**
|
|
403
|
+
* Start watching for file changes
|
|
404
|
+
*/
|
|
405
|
+
start(): void;
|
|
406
|
+
/**
|
|
407
|
+
* Stop watching for file changes
|
|
408
|
+
*/
|
|
409
|
+
stop(): Promise<void>;
|
|
410
|
+
/**
|
|
411
|
+
* Handle a file change event
|
|
412
|
+
*/
|
|
413
|
+
private handleChange;
|
|
414
|
+
/**
|
|
415
|
+
* Emit a file change event
|
|
416
|
+
*/
|
|
417
|
+
private emitChange;
|
|
418
|
+
/**
|
|
419
|
+
* Check if the watcher is running
|
|
420
|
+
*/
|
|
421
|
+
isWatching(): boolean;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Track file modification times for conflict detection
|
|
425
|
+
*/
|
|
426
|
+
declare class FileModificationTracker {
|
|
427
|
+
private mtimes;
|
|
428
|
+
/**
|
|
429
|
+
* Record the current modification time of a file
|
|
430
|
+
*/
|
|
431
|
+
track(filePath: string): Promise<void>;
|
|
432
|
+
/**
|
|
433
|
+
* Check if a file has been modified externally
|
|
434
|
+
*/
|
|
435
|
+
hasExternalChanges(filePath: string): Promise<boolean>;
|
|
436
|
+
/**
|
|
437
|
+
* Clear tracking for a file
|
|
438
|
+
*/
|
|
439
|
+
untrack(filePath: string): void;
|
|
440
|
+
/**
|
|
441
|
+
* Clear all tracking
|
|
442
|
+
*/
|
|
443
|
+
clear(): void;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Create a content watcher instance
|
|
447
|
+
*/
|
|
448
|
+
declare function createContentWatcher(projectRoot: string, options?: WatcherOptions): ContentWatcher;
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* @fileoverview Version history management for content files
|
|
452
|
+
*
|
|
453
|
+
* This module provides functions for creating, reading, and managing
|
|
454
|
+
* version history (shadow copies) of content files. Versions are stored
|
|
455
|
+
* as markdown files in a hidden directory structure with a JSON manifest
|
|
456
|
+
* tracking metadata.
|
|
457
|
+
*
|
|
458
|
+
* ## Storage Structure:
|
|
459
|
+
* ```
|
|
460
|
+
* .writenex/versions/
|
|
461
|
+
* ├── .gitignore # Contains "*" to exclude from Git
|
|
462
|
+
* └── {collection}/
|
|
463
|
+
* └── {contentId}/
|
|
464
|
+
* ├── manifest.json # Version metadata
|
|
465
|
+
* └── {timestamp}.md # Version files
|
|
466
|
+
* ```
|
|
467
|
+
*
|
|
468
|
+
* @module @writenex/astro/filesystem/versions
|
|
469
|
+
* @see {@link VersionEntry} - Version metadata type
|
|
470
|
+
* @see {@link VersionManifest} - Manifest structure type
|
|
471
|
+
*/
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Generate a unique version ID based on current timestamp with random suffix.
|
|
475
|
+
*
|
|
476
|
+
* The ID is an ISO-8601 timestamp with colons replaced by hyphens,
|
|
477
|
+
* plus a 4-character random suffix to ensure uniqueness even when
|
|
478
|
+
* multiple versions are created within the same millisecond.
|
|
479
|
+
*
|
|
480
|
+
* Format: YYYY-MM-DDTHH-MM-SS.mmmZ-xxxx
|
|
481
|
+
* Where xxxx is a random alphanumeric suffix.
|
|
482
|
+
*
|
|
483
|
+
* @returns Version ID string (e.g., "2024-12-11T10-30-00.000Z-a1b2")
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* ```typescript
|
|
487
|
+
* const id = generateVersionId();
|
|
488
|
+
* // Returns: "2024-12-11T10-30-00.000Z-a1b2"
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
declare function generateVersionId(): string;
|
|
492
|
+
/**
|
|
493
|
+
* Parse a version ID back to a Date object.
|
|
494
|
+
*
|
|
495
|
+
* Handles both old format (without suffix) and new format (with random suffix).
|
|
496
|
+
*
|
|
497
|
+
* @param versionId - Version ID string
|
|
498
|
+
* @returns Date object or null if invalid
|
|
499
|
+
*/
|
|
500
|
+
declare function parseVersionId(versionId: string): Date | null;
|
|
501
|
+
/**
|
|
502
|
+
* Get the storage path for version files of a content item.
|
|
503
|
+
*
|
|
504
|
+
* @param projectRoot - Absolute path to project root
|
|
505
|
+
* @param collection - Collection name
|
|
506
|
+
* @param contentId - Content item ID (slug)
|
|
507
|
+
* @param config - Version history configuration
|
|
508
|
+
* @returns Absolute path to version storage directory
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```typescript
|
|
512
|
+
* const path = getVersionStoragePath(
|
|
513
|
+
* '/project',
|
|
514
|
+
* 'blog',
|
|
515
|
+
* 'my-post',
|
|
516
|
+
* { storagePath: '.writenex/versions' }
|
|
517
|
+
* );
|
|
518
|
+
* // Returns: "/project/.writenex/versions/blog/my-post"
|
|
519
|
+
* ```
|
|
520
|
+
*/
|
|
521
|
+
declare function getVersionStoragePath(projectRoot: string, collection: string, contentId: string, config: Required<VersionHistoryConfig>): string;
|
|
522
|
+
/**
|
|
523
|
+
* Get the path to a specific version file.
|
|
524
|
+
*
|
|
525
|
+
* @param storagePath - Version storage directory path
|
|
526
|
+
* @param versionId - Version ID
|
|
527
|
+
* @returns Absolute path to version file
|
|
528
|
+
*/
|
|
529
|
+
declare function getVersionFilePath(storagePath: string, versionId: string): string;
|
|
530
|
+
/**
|
|
531
|
+
* Get the path to the manifest file for a content item.
|
|
532
|
+
*
|
|
533
|
+
* @param storagePath - Version storage directory path
|
|
534
|
+
* @returns Absolute path to manifest file
|
|
535
|
+
*/
|
|
536
|
+
declare function getManifestPath(storagePath: string): string;
|
|
537
|
+
/**
|
|
538
|
+
* Generate a preview string from content.
|
|
539
|
+
*
|
|
540
|
+
* Extracts the first 100 characters of the content body,
|
|
541
|
+
* stripping frontmatter if present.
|
|
542
|
+
*
|
|
543
|
+
* @param content - Full markdown content
|
|
544
|
+
* @returns Preview string (max 100 characters)
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```typescript
|
|
548
|
+
* const preview = generatePreview("---\ntitle: Test\n---\n\n# Hello World\n\nThis is content.");
|
|
549
|
+
* // Returns: "# Hello World\n\nThis is content."
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
declare function generatePreview(content: string): string;
|
|
553
|
+
/**
|
|
554
|
+
* Ensure the .gitignore file exists in the version storage root.
|
|
555
|
+
*
|
|
556
|
+
* Creates a .gitignore file with "*" pattern to exclude all version
|
|
557
|
+
* files from Git tracking.
|
|
558
|
+
*
|
|
559
|
+
* @param projectRoot - Absolute path to project root
|
|
560
|
+
* @param config - Version history configuration
|
|
561
|
+
*
|
|
562
|
+
* @example
|
|
563
|
+
* ```typescript
|
|
564
|
+
* await ensureGitignore('/project', { storagePath: '.writenex/versions' });
|
|
565
|
+
* // Creates: /project/.writenex/versions/.gitignore with content "*"
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
declare function ensureGitignore(projectRoot: string, config: Required<VersionHistoryConfig>): Promise<void>;
|
|
569
|
+
/**
|
|
570
|
+
* Ensure the version storage directory exists for a content item.
|
|
571
|
+
*
|
|
572
|
+
* @param storagePath - Version storage directory path
|
|
573
|
+
*/
|
|
574
|
+
declare function ensureStorageDirectory(storagePath: string): Promise<void>;
|
|
575
|
+
/**
|
|
576
|
+
* Read the version manifest for a content item.
|
|
577
|
+
*
|
|
578
|
+
* @param storagePath - Version storage directory path
|
|
579
|
+
* @returns Version manifest or null if not found/corrupted
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```typescript
|
|
583
|
+
* const manifest = await readManifest('/project/.writenex/versions/blog/my-post');
|
|
584
|
+
* if (manifest) {
|
|
585
|
+
* console.log(`Found ${manifest.versions.length} versions`);
|
|
586
|
+
* }
|
|
587
|
+
* ```
|
|
588
|
+
*/
|
|
589
|
+
declare function readManifest(storagePath: string): Promise<VersionManifest | null>;
|
|
590
|
+
/**
|
|
591
|
+
* Write the version manifest for a content item.
|
|
592
|
+
*
|
|
593
|
+
* @param storagePath - Version storage directory path
|
|
594
|
+
* @param manifest - Version manifest to write
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* ```typescript
|
|
598
|
+
* await writeManifest('/project/.writenex/versions/blog/my-post', {
|
|
599
|
+
* contentId: 'my-post',
|
|
600
|
+
* collection: 'blog',
|
|
601
|
+
* versions: [],
|
|
602
|
+
* updatedAt: new Date().toISOString(),
|
|
603
|
+
* });
|
|
604
|
+
* ```
|
|
605
|
+
*/
|
|
606
|
+
declare function writeManifest(storagePath: string, manifest: VersionManifest): Promise<void>;
|
|
607
|
+
/**
|
|
608
|
+
* Create an empty manifest for a content item.
|
|
609
|
+
*
|
|
610
|
+
* @param collection - Collection name
|
|
611
|
+
* @param contentId - Content item ID
|
|
612
|
+
* @returns New empty manifest
|
|
613
|
+
*/
|
|
614
|
+
declare function createEmptyManifest(collection: string, contentId: string): VersionManifest;
|
|
615
|
+
/**
|
|
616
|
+
* Recover manifest by scanning version files in the storage directory.
|
|
617
|
+
*
|
|
618
|
+
* This function rebuilds the manifest from existing version files
|
|
619
|
+
* when the manifest is corrupted or missing.
|
|
620
|
+
*
|
|
621
|
+
* @param storagePath - Version storage directory path
|
|
622
|
+
* @param collection - Collection name
|
|
623
|
+
* @param contentId - Content item ID
|
|
624
|
+
* @returns Recovered manifest
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* ```typescript
|
|
628
|
+
* const manifest = await recoverManifest(
|
|
629
|
+
* '/project/.writenex/versions/blog/my-post',
|
|
630
|
+
* 'blog',
|
|
631
|
+
* 'my-post'
|
|
632
|
+
* );
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
declare function recoverManifest(storagePath: string, collection: string, contentId: string): Promise<VersionManifest>;
|
|
636
|
+
/**
|
|
637
|
+
* Get or recover manifest for a content item.
|
|
638
|
+
*
|
|
639
|
+
* Attempts to read existing manifest, falls back to recovery if corrupted.
|
|
640
|
+
*
|
|
641
|
+
* @param storagePath - Version storage directory path
|
|
642
|
+
* @param collection - Collection name
|
|
643
|
+
* @param contentId - Content item ID
|
|
644
|
+
* @returns Version manifest
|
|
645
|
+
*/
|
|
646
|
+
declare function getOrRecoverManifest(storagePath: string, collection: string, contentId: string): Promise<VersionManifest>;
|
|
647
|
+
/**
|
|
648
|
+
* Save a version snapshot of content.
|
|
649
|
+
*
|
|
650
|
+
* Creates a new version file with the provided content and updates
|
|
651
|
+
* the manifest. Automatically prunes old versions if the limit is exceeded.
|
|
652
|
+
*
|
|
653
|
+
* @param projectRoot - Absolute path to project root
|
|
654
|
+
* @param collection - Collection name
|
|
655
|
+
* @param contentId - Content item ID (slug)
|
|
656
|
+
* @param content - Full markdown content to save
|
|
657
|
+
* @param config - Version history configuration
|
|
658
|
+
* @param options - Save options
|
|
659
|
+
* @returns Result of the save operation
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```typescript
|
|
663
|
+
* const result = await saveVersion(
|
|
664
|
+
* '/project',
|
|
665
|
+
* 'blog',
|
|
666
|
+
* 'my-post',
|
|
667
|
+
* '---\ntitle: My Post\n---\n\nContent here...',
|
|
668
|
+
* { enabled: true, maxVersions: 20, storagePath: '.writenex/versions' }
|
|
669
|
+
* );
|
|
670
|
+
*
|
|
671
|
+
* if (result.success) {
|
|
672
|
+
* console.log(`Created version: ${result.version?.id}`);
|
|
673
|
+
* }
|
|
674
|
+
* ```
|
|
675
|
+
*/
|
|
676
|
+
declare function saveVersion(projectRoot: string, collection: string, contentId: string, content: string, config: Required<VersionHistoryConfig>, options?: SaveVersionOptions): Promise<VersionResult>;
|
|
677
|
+
/**
|
|
678
|
+
* Get all versions for a content item.
|
|
679
|
+
*
|
|
680
|
+
* Returns versions sorted by timestamp in descending order (newest first).
|
|
681
|
+
* Handles missing or corrupted manifests gracefully.
|
|
682
|
+
*
|
|
683
|
+
* @param projectRoot - Absolute path to project root
|
|
684
|
+
* @param collection - Collection name
|
|
685
|
+
* @param contentId - Content item ID (slug)
|
|
686
|
+
* @param config - Version history configuration
|
|
687
|
+
* @returns Array of version entries
|
|
688
|
+
*
|
|
689
|
+
* @example
|
|
690
|
+
* ```typescript
|
|
691
|
+
* const versions = await getVersions(
|
|
692
|
+
* '/project',
|
|
693
|
+
* 'blog',
|
|
694
|
+
* 'my-post',
|
|
695
|
+
* { enabled: true, maxVersions: 20, storagePath: '.writenex/versions' }
|
|
696
|
+
* );
|
|
697
|
+
*
|
|
698
|
+
* console.log(`Found ${versions.length} versions`);
|
|
699
|
+
* ```
|
|
700
|
+
*/
|
|
701
|
+
declare function getVersions(projectRoot: string, collection: string, contentId: string, config: Required<VersionHistoryConfig>): Promise<VersionEntry[]>;
|
|
702
|
+
/**
|
|
703
|
+
* Get a specific version with full content.
|
|
704
|
+
*
|
|
705
|
+
* Reads the version file and parses it to return structured data
|
|
706
|
+
* with frontmatter and body separated.
|
|
707
|
+
*
|
|
708
|
+
* @param projectRoot - Absolute path to project root
|
|
709
|
+
* @param collection - Collection name
|
|
710
|
+
* @param contentId - Content item ID (slug)
|
|
711
|
+
* @param versionId - Version ID to retrieve
|
|
712
|
+
* @param config - Version history configuration
|
|
713
|
+
* @returns Full version data or null if not found
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* ```typescript
|
|
717
|
+
* const version = await getVersion(
|
|
718
|
+
* '/project',
|
|
719
|
+
* 'blog',
|
|
720
|
+
* 'my-post',
|
|
721
|
+
* '2024-12-11T10-30-00-000Z',
|
|
722
|
+
* { enabled: true, maxVersions: 20, storagePath: '.writenex/versions' }
|
|
723
|
+
* );
|
|
724
|
+
*
|
|
725
|
+
* if (version) {
|
|
726
|
+
* console.log(`Title: ${version.frontmatter.title}`);
|
|
727
|
+
* console.log(`Body: ${version.body}`);
|
|
728
|
+
* }
|
|
729
|
+
* ```
|
|
730
|
+
*/
|
|
731
|
+
declare function getVersion(projectRoot: string, collection: string, contentId: string, versionId: string, config: Required<VersionHistoryConfig>): Promise<Version | null>;
|
|
732
|
+
/**
|
|
733
|
+
* Delete a specific version.
|
|
734
|
+
*
|
|
735
|
+
* Removes the version file from the filesystem and updates the manifest.
|
|
736
|
+
*
|
|
737
|
+
* @param projectRoot - Absolute path to project root
|
|
738
|
+
* @param collection - Collection name
|
|
739
|
+
* @param contentId - Content item ID (slug)
|
|
740
|
+
* @param versionId - Version ID to delete
|
|
741
|
+
* @param config - Version history configuration
|
|
742
|
+
* @returns Result of the delete operation
|
|
743
|
+
*
|
|
744
|
+
* @example
|
|
745
|
+
* ```typescript
|
|
746
|
+
* const result = await deleteVersion(
|
|
747
|
+
* '/project',
|
|
748
|
+
* 'blog',
|
|
749
|
+
* 'my-post',
|
|
750
|
+
* '2024-12-11T10-30-00-000Z',
|
|
751
|
+
* { enabled: true, maxVersions: 20, storagePath: '.writenex/versions' }
|
|
752
|
+
* );
|
|
753
|
+
*
|
|
754
|
+
* if (result.success) {
|
|
755
|
+
* console.log('Version deleted');
|
|
756
|
+
* }
|
|
757
|
+
* ```
|
|
758
|
+
*/
|
|
759
|
+
declare function deleteVersion(projectRoot: string, collection: string, contentId: string, versionId: string, config: Required<VersionHistoryConfig>): Promise<VersionResult>;
|
|
760
|
+
/**
|
|
761
|
+
* Clear all versions for a content item.
|
|
762
|
+
*
|
|
763
|
+
* Deletes all version files and resets the manifest to empty state.
|
|
764
|
+
*
|
|
765
|
+
* @param projectRoot - Absolute path to project root
|
|
766
|
+
* @param collection - Collection name
|
|
767
|
+
* @param contentId - Content item ID (slug)
|
|
768
|
+
* @param config - Version history configuration
|
|
769
|
+
* @returns Result of the clear operation
|
|
770
|
+
*
|
|
771
|
+
* @example
|
|
772
|
+
* ```typescript
|
|
773
|
+
* const result = await clearVersions(
|
|
774
|
+
* '/project',
|
|
775
|
+
* 'blog',
|
|
776
|
+
* 'my-post',
|
|
777
|
+
* { enabled: true, maxVersions: 20, storagePath: '.writenex/versions' }
|
|
778
|
+
* );
|
|
779
|
+
*
|
|
780
|
+
* if (result.success) {
|
|
781
|
+
* console.log('All versions cleared');
|
|
782
|
+
* }
|
|
783
|
+
* ```
|
|
784
|
+
*/
|
|
785
|
+
declare function clearVersions(projectRoot: string, collection: string, contentId: string, config: Required<VersionHistoryConfig>): Promise<VersionResult>;
|
|
786
|
+
declare function pruneVersions(projectRoot: string, collection: string, contentId: string, config: Required<VersionHistoryConfig>): Promise<VersionResult>;
|
|
787
|
+
/**
|
|
788
|
+
* Restore a version to current content.
|
|
789
|
+
*
|
|
790
|
+
* This function:
|
|
791
|
+
* 1. Creates a safety snapshot of the current content before restoring
|
|
792
|
+
* 2. Reads the version content to restore
|
|
793
|
+
* 3. Overwrites the current content file with the version content
|
|
794
|
+
*
|
|
795
|
+
* Note: Cache invalidation should be handled by the caller (API route)
|
|
796
|
+
* since the cache is managed at the server level.
|
|
797
|
+
*
|
|
798
|
+
* @param projectRoot - Absolute path to project root
|
|
799
|
+
* @param collection - Collection name
|
|
800
|
+
* @param contentId - Content item ID (slug)
|
|
801
|
+
* @param versionId - Version ID to restore
|
|
802
|
+
* @param contentFilePath - Absolute path to the current content file
|
|
803
|
+
* @param config - Version history configuration
|
|
804
|
+
* @param options - Restore options
|
|
805
|
+
* @returns Result of the restore operation
|
|
806
|
+
*
|
|
807
|
+
* @example
|
|
808
|
+
* ```typescript
|
|
809
|
+
* const result = await restoreVersion(
|
|
810
|
+
* '/project',
|
|
811
|
+
* 'blog',
|
|
812
|
+
* 'my-post',
|
|
813
|
+
* '2024-12-11T10-30-00-000Z',
|
|
814
|
+
* '/project/src/content/blog/my-post.md',
|
|
815
|
+
* { enabled: true, maxVersions: 20, storagePath: '.writenex/versions' }
|
|
816
|
+
* );
|
|
817
|
+
*
|
|
818
|
+
* if (result.success) {
|
|
819
|
+
* console.log('Restored content:', result.content);
|
|
820
|
+
* if (result.safetySnapshot) {
|
|
821
|
+
* console.log('Safety snapshot created:', result.safetySnapshot.id);
|
|
822
|
+
* }
|
|
823
|
+
* }
|
|
824
|
+
* ```
|
|
825
|
+
*/
|
|
826
|
+
declare function restoreVersion(projectRoot: string, collection: string, contentId: string, versionId: string, contentFilePath: string, config: Required<VersionHistoryConfig>, options?: RestoreVersionOptions): Promise<RestoreResult>;
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* @fileoverview Config-aware wrappers for version history operations
|
|
830
|
+
*
|
|
831
|
+
* This module provides wrapper functions that automatically apply configuration
|
|
832
|
+
* defaults and check the enabled flag before performing version operations.
|
|
833
|
+
* These wrappers simplify usage by accepting partial configuration and handling
|
|
834
|
+
* all the configuration resolution internally.
|
|
835
|
+
*
|
|
836
|
+
* @module @writenex/astro/filesystem/version-config
|
|
837
|
+
* @see {@link saveVersion} - Core save function
|
|
838
|
+
* @see {@link getVersions} - Core list function
|
|
839
|
+
*/
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Resolve version history configuration with defaults applied.
|
|
843
|
+
*
|
|
844
|
+
* Takes a partial configuration and merges it with defaults to produce
|
|
845
|
+
* a complete configuration object.
|
|
846
|
+
*
|
|
847
|
+
* @param config - Partial version history configuration
|
|
848
|
+
* @returns Complete configuration with all defaults applied
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```typescript
|
|
852
|
+
* const resolved = resolveVersionConfig({ maxVersions: 50 });
|
|
853
|
+
* // Returns: { enabled: true, maxVersions: 50, storagePath: '.writenex/versions' }
|
|
854
|
+
* ```
|
|
855
|
+
*/
|
|
856
|
+
declare function resolveVersionConfig(config?: VersionHistoryConfig): Required<VersionHistoryConfig>;
|
|
857
|
+
/**
|
|
858
|
+
* Check if version history is enabled in the configuration.
|
|
859
|
+
*
|
|
860
|
+
* @param config - Version history configuration (partial or full)
|
|
861
|
+
* @returns True if version history is enabled
|
|
862
|
+
*
|
|
863
|
+
* @example
|
|
864
|
+
* ```typescript
|
|
865
|
+
* if (isVersionHistoryEnabled({ enabled: false })) {
|
|
866
|
+
* // This won't execute
|
|
867
|
+
* }
|
|
868
|
+
* ```
|
|
869
|
+
*/
|
|
870
|
+
declare function isVersionHistoryEnabled(config?: VersionHistoryConfig): boolean;
|
|
871
|
+
/**
|
|
872
|
+
* Save a version with automatic configuration resolution.
|
|
873
|
+
*
|
|
874
|
+
* This wrapper automatically applies configuration defaults and checks
|
|
875
|
+
* the enabled flag before delegating to the core saveVersion function.
|
|
876
|
+
*
|
|
877
|
+
* @param projectRoot - Absolute path to project root
|
|
878
|
+
* @param collection - Collection name
|
|
879
|
+
* @param contentId - Content item ID (slug)
|
|
880
|
+
* @param content - Full markdown content to save
|
|
881
|
+
* @param config - Partial version history configuration
|
|
882
|
+
* @param options - Save options
|
|
883
|
+
* @returns Result of the save operation
|
|
884
|
+
*
|
|
885
|
+
* @example
|
|
886
|
+
* ```typescript
|
|
887
|
+
* // With partial config - defaults are applied automatically
|
|
888
|
+
* const result = await saveVersionWithConfig(
|
|
889
|
+
* '/project',
|
|
890
|
+
* 'blog',
|
|
891
|
+
* 'my-post',
|
|
892
|
+
* '---\ntitle: My Post\n---\n\nContent...',
|
|
893
|
+
* { maxVersions: 50 } // enabled and storagePath use defaults
|
|
894
|
+
* );
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
declare function saveVersionWithConfig(projectRoot: string, collection: string, contentId: string, content: string, config?: VersionHistoryConfig, options?: SaveVersionOptions): Promise<VersionResult>;
|
|
898
|
+
/**
|
|
899
|
+
* Get all versions with automatic configuration resolution.
|
|
900
|
+
*
|
|
901
|
+
* This wrapper automatically applies configuration defaults and checks
|
|
902
|
+
* the enabled flag before delegating to the core getVersions function.
|
|
903
|
+
*
|
|
904
|
+
* @param projectRoot - Absolute path to project root
|
|
905
|
+
* @param collection - Collection name
|
|
906
|
+
* @param contentId - Content item ID (slug)
|
|
907
|
+
* @param config - Partial version history configuration
|
|
908
|
+
* @returns Array of version entries (empty if disabled)
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* ```typescript
|
|
912
|
+
* const versions = await getVersionsWithConfig(
|
|
913
|
+
* '/project',
|
|
914
|
+
* 'blog',
|
|
915
|
+
* 'my-post',
|
|
916
|
+
* { storagePath: 'custom/versions' }
|
|
917
|
+
* );
|
|
918
|
+
* ```
|
|
919
|
+
*/
|
|
920
|
+
declare function getVersionsWithConfig(projectRoot: string, collection: string, contentId: string, config?: VersionHistoryConfig): Promise<VersionEntry[]>;
|
|
921
|
+
/**
|
|
922
|
+
* Get a specific version with automatic configuration resolution.
|
|
923
|
+
*
|
|
924
|
+
* This wrapper automatically applies configuration defaults and checks
|
|
925
|
+
* the enabled flag before delegating to the core getVersion function.
|
|
926
|
+
*
|
|
927
|
+
* @param projectRoot - Absolute path to project root
|
|
928
|
+
* @param collection - Collection name
|
|
929
|
+
* @param contentId - Content item ID (slug)
|
|
930
|
+
* @param versionId - Version ID to retrieve
|
|
931
|
+
* @param config - Partial version history configuration
|
|
932
|
+
* @returns Full version data or null if not found/disabled
|
|
933
|
+
*
|
|
934
|
+
* @example
|
|
935
|
+
* ```typescript
|
|
936
|
+
* const version = await getVersionWithConfig(
|
|
937
|
+
* '/project',
|
|
938
|
+
* 'blog',
|
|
939
|
+
* 'my-post',
|
|
940
|
+
* '2024-12-11T10-30-00-000Z'
|
|
941
|
+
* );
|
|
942
|
+
* ```
|
|
943
|
+
*/
|
|
944
|
+
declare function getVersionWithConfig(projectRoot: string, collection: string, contentId: string, versionId: string, config?: VersionHistoryConfig): Promise<Version | null>;
|
|
945
|
+
/**
|
|
946
|
+
* Delete a version with automatic configuration resolution.
|
|
947
|
+
*
|
|
948
|
+
* This wrapper automatically applies configuration defaults before
|
|
949
|
+
* delegating to the core deleteVersion function.
|
|
950
|
+
*
|
|
951
|
+
* @param projectRoot - Absolute path to project root
|
|
952
|
+
* @param collection - Collection name
|
|
953
|
+
* @param contentId - Content item ID (slug)
|
|
954
|
+
* @param versionId - Version ID to delete
|
|
955
|
+
* @param config - Partial version history configuration
|
|
956
|
+
* @returns Result of the delete operation
|
|
957
|
+
*
|
|
958
|
+
* @example
|
|
959
|
+
* ```typescript
|
|
960
|
+
* const result = await deleteVersionWithConfig(
|
|
961
|
+
* '/project',
|
|
962
|
+
* 'blog',
|
|
963
|
+
* 'my-post',
|
|
964
|
+
* '2024-12-11T10-30-00-000Z'
|
|
965
|
+
* );
|
|
966
|
+
* ```
|
|
967
|
+
*/
|
|
968
|
+
declare function deleteVersionWithConfig(projectRoot: string, collection: string, contentId: string, versionId: string, config?: VersionHistoryConfig): Promise<VersionResult>;
|
|
969
|
+
/**
|
|
970
|
+
* Clear all versions with automatic configuration resolution.
|
|
971
|
+
*
|
|
972
|
+
* This wrapper automatically applies configuration defaults before
|
|
973
|
+
* delegating to the core clearVersions function.
|
|
974
|
+
*
|
|
975
|
+
* @param projectRoot - Absolute path to project root
|
|
976
|
+
* @param collection - Collection name
|
|
977
|
+
* @param contentId - Content item ID (slug)
|
|
978
|
+
* @param config - Partial version history configuration
|
|
979
|
+
* @returns Result of the clear operation
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* ```typescript
|
|
983
|
+
* const result = await clearVersionsWithConfig(
|
|
984
|
+
* '/project',
|
|
985
|
+
* 'blog',
|
|
986
|
+
* 'my-post'
|
|
987
|
+
* );
|
|
988
|
+
* ```
|
|
989
|
+
*/
|
|
990
|
+
declare function clearVersionsWithConfig(projectRoot: string, collection: string, contentId: string, config?: VersionHistoryConfig): Promise<VersionResult>;
|
|
991
|
+
/**
|
|
992
|
+
* Prune old versions with automatic configuration resolution.
|
|
993
|
+
*
|
|
994
|
+
* This wrapper automatically applies configuration defaults before
|
|
995
|
+
* delegating to the core pruneVersions function. Uses the configured
|
|
996
|
+
* maxVersions value for determining how many versions to keep.
|
|
997
|
+
*
|
|
998
|
+
* @param projectRoot - Absolute path to project root
|
|
999
|
+
* @param collection - Collection name
|
|
1000
|
+
* @param contentId - Content item ID (slug)
|
|
1001
|
+
* @param config - Partial version history configuration
|
|
1002
|
+
* @returns Result of the prune operation
|
|
1003
|
+
*
|
|
1004
|
+
* @example
|
|
1005
|
+
* ```typescript
|
|
1006
|
+
* // Uses custom maxVersions
|
|
1007
|
+
* const result = await pruneVersionsWithConfig(
|
|
1008
|
+
* '/project',
|
|
1009
|
+
* 'blog',
|
|
1010
|
+
* 'my-post',
|
|
1011
|
+
* { maxVersions: 10 }
|
|
1012
|
+
* );
|
|
1013
|
+
* ```
|
|
1014
|
+
*/
|
|
1015
|
+
declare function pruneVersionsWithConfig(projectRoot: string, collection: string, contentId: string, config?: VersionHistoryConfig): Promise<VersionResult>;
|
|
1016
|
+
/**
|
|
1017
|
+
* Restore a version with automatic configuration resolution.
|
|
1018
|
+
*
|
|
1019
|
+
* This wrapper automatically applies configuration defaults and checks
|
|
1020
|
+
* the enabled flag before delegating to the core restoreVersion function.
|
|
1021
|
+
*
|
|
1022
|
+
* @param projectRoot - Absolute path to project root
|
|
1023
|
+
* @param collection - Collection name
|
|
1024
|
+
* @param contentId - Content item ID (slug)
|
|
1025
|
+
* @param versionId - Version ID to restore
|
|
1026
|
+
* @param contentFilePath - Absolute path to the current content file
|
|
1027
|
+
* @param config - Partial version history configuration
|
|
1028
|
+
* @param options - Restore options
|
|
1029
|
+
* @returns Result of the restore operation
|
|
1030
|
+
*
|
|
1031
|
+
* @example
|
|
1032
|
+
* ```typescript
|
|
1033
|
+
* const result = await restoreVersionWithConfig(
|
|
1034
|
+
* '/project',
|
|
1035
|
+
* 'blog',
|
|
1036
|
+
* 'my-post',
|
|
1037
|
+
* '2024-12-11T10-30-00-000Z',
|
|
1038
|
+
* '/project/src/content/blog/my-post.md'
|
|
1039
|
+
* );
|
|
1040
|
+
* ```
|
|
1041
|
+
*/
|
|
1042
|
+
declare function restoreVersionWithConfig(projectRoot: string, collection: string, contentId: string, versionId: string, contentFilePath: string, config?: VersionHistoryConfig, options?: RestoreVersionOptions): Promise<RestoreResult>;
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* @fileoverview Image handling for content collections
|
|
1046
|
+
*
|
|
1047
|
+
* This module provides functions for uploading and managing images
|
|
1048
|
+
* in content collections with support for different storage strategies.
|
|
1049
|
+
*
|
|
1050
|
+
* ## Strategies:
|
|
1051
|
+
* - colocated: Images stored alongside content files
|
|
1052
|
+
* - public: Images stored in public directory
|
|
1053
|
+
* - custom: User-defined storage paths
|
|
1054
|
+
*
|
|
1055
|
+
* @module @writenex/astro/filesystem/images
|
|
1056
|
+
*/
|
|
1057
|
+
|
|
1058
|
+
/**
|
|
1059
|
+
* Default image configuration
|
|
1060
|
+
*/
|
|
1061
|
+
declare const DEFAULT_IMAGE_CONFIG: ImageConfig;
|
|
1062
|
+
/**
|
|
1063
|
+
* Result of image upload operation
|
|
1064
|
+
*/
|
|
1065
|
+
interface ImageUploadResult {
|
|
1066
|
+
success: boolean;
|
|
1067
|
+
/** Markdown-compatible path for the image */
|
|
1068
|
+
path?: string;
|
|
1069
|
+
/** Public URL for the image */
|
|
1070
|
+
url?: string;
|
|
1071
|
+
/** Error message if failed */
|
|
1072
|
+
error?: string;
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Options for image upload
|
|
1076
|
+
*/
|
|
1077
|
+
interface ImageUploadOptions {
|
|
1078
|
+
/** Original filename */
|
|
1079
|
+
filename: string;
|
|
1080
|
+
/** Image binary data */
|
|
1081
|
+
data: Buffer;
|
|
1082
|
+
/** Collection name */
|
|
1083
|
+
collection: string;
|
|
1084
|
+
/** Content ID (slug) */
|
|
1085
|
+
contentId: string;
|
|
1086
|
+
/** Project root path */
|
|
1087
|
+
projectRoot: string;
|
|
1088
|
+
/** Image configuration */
|
|
1089
|
+
config?: ImageConfig;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Validate image file
|
|
1093
|
+
*
|
|
1094
|
+
* @param filename - Original filename
|
|
1095
|
+
* @returns True if valid image file
|
|
1096
|
+
*/
|
|
1097
|
+
declare function isValidImageFile(filename: string): boolean;
|
|
1098
|
+
/**
|
|
1099
|
+
* Upload an image file
|
|
1100
|
+
*
|
|
1101
|
+
* @param options - Upload options
|
|
1102
|
+
* @returns Upload result with paths
|
|
1103
|
+
*
|
|
1104
|
+
* @example
|
|
1105
|
+
* ```typescript
|
|
1106
|
+
* const result = await uploadImage({
|
|
1107
|
+
* filename: "hero.jpg",
|
|
1108
|
+
* data: imageBuffer,
|
|
1109
|
+
* collection: "blog",
|
|
1110
|
+
* contentId: "my-post",
|
|
1111
|
+
* projectRoot: "/path/to/project",
|
|
1112
|
+
* });
|
|
1113
|
+
*
|
|
1114
|
+
* if (result.success) {
|
|
1115
|
+
* console.log(result.path); // "./my-post/hero-abc123.jpg"
|
|
1116
|
+
* }
|
|
1117
|
+
* ```
|
|
1118
|
+
*/
|
|
1119
|
+
declare function uploadImage(options: ImageUploadOptions): Promise<ImageUploadResult>;
|
|
1120
|
+
/**
|
|
1121
|
+
* Parse multipart form data for image upload
|
|
1122
|
+
*
|
|
1123
|
+
* Simple parser for multipart/form-data with single file upload.
|
|
1124
|
+
* For production, consider using a proper multipart parser library.
|
|
1125
|
+
*
|
|
1126
|
+
* @param body - Raw request body
|
|
1127
|
+
* @param contentType - Content-Type header
|
|
1128
|
+
* @returns Parsed file data and fields
|
|
1129
|
+
*/
|
|
1130
|
+
declare function parseMultipartFormData(body: Buffer, contentType: string): {
|
|
1131
|
+
file?: {
|
|
1132
|
+
filename: string;
|
|
1133
|
+
data: Buffer;
|
|
1134
|
+
contentType: string;
|
|
1135
|
+
};
|
|
1136
|
+
fields: Record<string, string>;
|
|
1137
|
+
};
|
|
1138
|
+
/**
|
|
1139
|
+
* Content structure type detected from file path
|
|
1140
|
+
*/
|
|
1141
|
+
type ContentStructure = "flat" | "folder-based" | "date-prefixed";
|
|
1142
|
+
/**
|
|
1143
|
+
* Result of content structure detection
|
|
1144
|
+
*/
|
|
1145
|
+
interface ContentStructureResult {
|
|
1146
|
+
/** Detected structure type */
|
|
1147
|
+
structure: ContentStructure;
|
|
1148
|
+
/** Path to the image folder (null if doesn't exist) */
|
|
1149
|
+
imageFolderPath: string | null;
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Detect content structure and get the image folder path
|
|
1153
|
+
*
|
|
1154
|
+
* Handles three content structures:
|
|
1155
|
+
* - Flat file: `my-post.md` -> looks for `my-post/` sibling folder
|
|
1156
|
+
* - Folder-based: `slug/index.md` -> uses `slug/` parent folder
|
|
1157
|
+
* - Date-prefixed: `2024-01-15-my-post.md` -> looks for `2024-01-15-my-post/` sibling folder
|
|
1158
|
+
*
|
|
1159
|
+
* @param collectionPath - Absolute path to the collection directory
|
|
1160
|
+
* @param contentId - Content ID (slug)
|
|
1161
|
+
* @param contentFilePath - Absolute path to the content file
|
|
1162
|
+
* @returns Path to the image folder, or null if no image folder exists
|
|
1163
|
+
*
|
|
1164
|
+
* @example
|
|
1165
|
+
* ```typescript
|
|
1166
|
+
* // Flat file structure
|
|
1167
|
+
* const folder = getContentImageFolder(
|
|
1168
|
+
* '/project/src/content/blog',
|
|
1169
|
+
* 'my-post',
|
|
1170
|
+
* '/project/src/content/blog/my-post.md'
|
|
1171
|
+
* );
|
|
1172
|
+
* // Returns: '/project/src/content/blog/my-post' (if exists)
|
|
1173
|
+
*
|
|
1174
|
+
* // Folder-based structure
|
|
1175
|
+
* const folder = getContentImageFolder(
|
|
1176
|
+
* '/project/src/content/blog',
|
|
1177
|
+
* 'my-post',
|
|
1178
|
+
* '/project/src/content/blog/my-post/index.md'
|
|
1179
|
+
* );
|
|
1180
|
+
* // Returns: '/project/src/content/blog/my-post'
|
|
1181
|
+
* ```
|
|
1182
|
+
*/
|
|
1183
|
+
declare function getContentImageFolder(collectionPath: string, contentId: string, contentFilePath: string): string | null;
|
|
1184
|
+
/**
|
|
1185
|
+
* Detect the content structure type from a content file path
|
|
1186
|
+
*
|
|
1187
|
+
* @param contentFilePath - Absolute path to the content file
|
|
1188
|
+
* @returns The detected content structure type
|
|
1189
|
+
*/
|
|
1190
|
+
declare function detectContentStructure(contentFilePath: string): ContentStructure;
|
|
1191
|
+
/**
|
|
1192
|
+
* Options for recursive directory scanning
|
|
1193
|
+
*/
|
|
1194
|
+
interface ScanOptions {
|
|
1195
|
+
/** Maximum recursion depth */
|
|
1196
|
+
maxDepth: number;
|
|
1197
|
+
/** Current recursion depth */
|
|
1198
|
+
currentDepth: number;
|
|
1199
|
+
/** Base path for calculating relative paths */
|
|
1200
|
+
basePath: string;
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Scan a directory recursively for image files
|
|
1204
|
+
*
|
|
1205
|
+
* Recursively scans the given directory for image files with supported extensions.
|
|
1206
|
+
* Skips hidden folders (starting with .) and special folders (starting with _).
|
|
1207
|
+
* Limits recursion to the specified maxDepth.
|
|
1208
|
+
*
|
|
1209
|
+
* @param dirPath - Absolute path to the directory to scan
|
|
1210
|
+
* @param basePath - Base path for calculating relative paths
|
|
1211
|
+
* @param options - Scan options including maxDepth and currentDepth
|
|
1212
|
+
* @returns Array of discovered images
|
|
1213
|
+
*
|
|
1214
|
+
* @example
|
|
1215
|
+
* ```typescript
|
|
1216
|
+
* const images = await scanDirectoryForImages(
|
|
1217
|
+
* '/project/src/content/blog/my-post',
|
|
1218
|
+
* '/project/src/content/blog/my-post',
|
|
1219
|
+
* { maxDepth: 5, currentDepth: 0, basePath: '/project/src/content/blog/my-post' }
|
|
1220
|
+
* );
|
|
1221
|
+
* ```
|
|
1222
|
+
*/
|
|
1223
|
+
declare function scanDirectoryForImages(dirPath: string, basePath: string, options: ScanOptions): Promise<DiscoveredImage[]>;
|
|
1224
|
+
/**
|
|
1225
|
+
* Calculate relative path from content file to image file
|
|
1226
|
+
*
|
|
1227
|
+
* Calculates the path that can be used in markdown to reference an image
|
|
1228
|
+
* relative to the content file's location. The path always starts with ./
|
|
1229
|
+
* to ensure it's treated as a relative reference.
|
|
1230
|
+
*
|
|
1231
|
+
* @param contentFilePath - Absolute path to the content file (e.g., /project/src/content/blog/my-post.md)
|
|
1232
|
+
* @param imagePath - Absolute path to the image file (e.g., /project/src/content/blog/my-post/images/hero.jpg)
|
|
1233
|
+
* @returns Relative path starting with ./ (e.g., ./my-post/images/hero.jpg)
|
|
1234
|
+
*
|
|
1235
|
+
* @example
|
|
1236
|
+
* ```typescript
|
|
1237
|
+
* // Flat file structure
|
|
1238
|
+
* const relPath = calculateRelativePath(
|
|
1239
|
+
* '/project/src/content/blog/my-post.md',
|
|
1240
|
+
* '/project/src/content/blog/my-post/hero.jpg'
|
|
1241
|
+
* );
|
|
1242
|
+
* // Returns: './my-post/hero.jpg'
|
|
1243
|
+
*
|
|
1244
|
+
* // Folder-based structure
|
|
1245
|
+
* const relPath = calculateRelativePath(
|
|
1246
|
+
* '/project/src/content/blog/my-post/index.md',
|
|
1247
|
+
* '/project/src/content/blog/my-post/images/hero.jpg'
|
|
1248
|
+
* );
|
|
1249
|
+
* // Returns: './images/hero.jpg'
|
|
1250
|
+
*
|
|
1251
|
+
* // Nested subfolder
|
|
1252
|
+
* const relPath = calculateRelativePath(
|
|
1253
|
+
* '/project/src/content/blog/my-post/index.md',
|
|
1254
|
+
* '/project/src/content/blog/my-post/assets/photos/hero.jpg'
|
|
1255
|
+
* );
|
|
1256
|
+
* // Returns: './assets/photos/hero.jpg'
|
|
1257
|
+
* ```
|
|
1258
|
+
*/
|
|
1259
|
+
declare function calculateRelativePath(contentFilePath: string, imagePath: string): string;
|
|
1260
|
+
/**
|
|
1261
|
+
* Discover all images associated with a content item
|
|
1262
|
+
*
|
|
1263
|
+
* This is the main entry point for image discovery. It:
|
|
1264
|
+
* 1. Locates the content file using getContentFilePath
|
|
1265
|
+
* 2. Determines the image folder using getContentImageFolder
|
|
1266
|
+
* 3. Scans the folder recursively using scanDirectoryForImages
|
|
1267
|
+
* 4. Calculates relative paths for all discovered images
|
|
1268
|
+
*
|
|
1269
|
+
* @param collectionPath - Absolute path to the collection directory
|
|
1270
|
+
* @param contentId - Content ID (slug)
|
|
1271
|
+
* @param options - Optional discovery options
|
|
1272
|
+
* @returns ImageDiscoveryResult with discovered images or error
|
|
1273
|
+
*
|
|
1274
|
+
* @example
|
|
1275
|
+
* ```typescript
|
|
1276
|
+
* const result = await discoverContentImages(
|
|
1277
|
+
* '/project/src/content/blog',
|
|
1278
|
+
* 'my-post',
|
|
1279
|
+
* { maxDepth: 3 }
|
|
1280
|
+
* );
|
|
1281
|
+
*
|
|
1282
|
+
* if (result.success) {
|
|
1283
|
+
* console.log(`Found ${result.images.length} images`);
|
|
1284
|
+
* for (const img of result.images) {
|
|
1285
|
+
* console.log(`- ${img.relativePath}`);
|
|
1286
|
+
* }
|
|
1287
|
+
* }
|
|
1288
|
+
* ```
|
|
1289
|
+
*/
|
|
1290
|
+
declare function discoverContentImages(collectionPath: string, contentId: string, options?: ImageDiscoveryOptions): Promise<ImageDiscoveryResult>;
|
|
1291
|
+
|
|
1292
|
+
export { type ContentStructure, type ContentStructureResult, ContentWatcher, type CreateContentOptions, DEFAULT_IMAGE_CONFIG, type FileChangeEvent, type FileChangeType, FileModificationTracker, type ImageUploadOptions, type ImageUploadResult, type ReadContentOptions, type ReadFileResult, type UpdateContentOptions, type WatcherOptions, type WriteResult, calculateRelativePath, checkCollection, clearVersions, clearVersionsWithConfig, createContent, createContentWatcher, createEmptyManifest, deleteContent, deleteVersion, deleteVersionWithConfig, detectContentStructure, discoverContentImages, ensureGitignore, ensureStorageDirectory, extractSlug, generateExcerpt, generatePreview, generateSlug, generateUniqueSlug, generateVersionId, getCollectionCount, getCollectionSummaries, getContentFilePath, getContentImageFolder, getFileStats, getManifestPath, getOrRecoverManifest, getVersion, getVersionFilePath, getVersionStoragePath, getVersionWithConfig, getVersions, getVersionsWithConfig, isContentFile, isValidImageFile, isVersionHistoryEnabled, parseMultipartFormData, parseVersionId, pruneVersions, pruneVersionsWithConfig, readCollection, readContentFile, readManifest, recoverManifest, resolveVersionConfig, restoreVersion, restoreVersionWithConfig, saveVersion, saveVersionWithConfig, scanDirectoryForImages, toContentSummary, updateContent, uploadImage, writeManifest };
|