@imjp/writenex-astro 0.1.0 → 1.3.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.
Files changed (99) hide show
  1. package/README.md +13 -13
  2. package/dist/{chunk-CYLDJ3HZ.js → chunk-GIS7XEJF.js} +4 -4
  3. package/dist/{chunk-CYLDJ3HZ.js.map → chunk-GIS7XEJF.js.map} +1 -1
  4. package/dist/{chunk-7XU5X6CW.js → chunk-GUUSVFBP.js} +12 -12
  5. package/dist/chunk-GUUSVFBP.js.map +1 -0
  6. package/dist/{chunk-XNTQTTJU.js → chunk-JFQQJPDF.js} +2 -2
  7. package/dist/{chunk-XNTQTTJU.js.map → chunk-JFQQJPDF.js.map} +1 -1
  8. package/dist/{chunk-CF2XXJFF.js → chunk-OWYFIQFK.js} +436 -436
  9. package/dist/chunk-OWYFIQFK.js.map +1 -0
  10. package/dist/{chunk-5PM6EQE5.js → chunk-S2OUQLMK.js} +7 -5
  11. package/dist/chunk-S2OUQLMK.js.map +1 -0
  12. package/dist/{chunk-AAOQHQPU.js → chunk-TQAYIZOA.js} +5 -5
  13. package/dist/{chunk-AAOQHQPU.js.map → chunk-TQAYIZOA.js.map} +1 -1
  14. package/dist/{chunk-CRPZUUDU.js → chunk-YBCPOLMY.js} +1 -1
  15. package/dist/{chunk-CRPZUUDU.js.map → chunk-YBCPOLMY.js.map} +1 -1
  16. package/dist/client/index.css +1 -1
  17. package/dist/client/index.css.map +1 -1
  18. package/dist/client/index.d.ts +19 -0
  19. package/dist/client/index.js +159 -147
  20. package/dist/client/index.js.map +1 -1
  21. package/dist/client/styles.css +2 -8
  22. package/dist/config/index.d.ts +2 -2
  23. package/dist/config/index.js +2 -2
  24. package/dist/{config-BmEdBDo_.d.ts → config-CliL0CoN.d.ts} +1 -1
  25. package/dist/{content-BWR52vD-.d.ts → content-TuL3GT66.d.ts} +1 -1
  26. package/dist/discovery/index.d.ts +2 -2
  27. package/dist/discovery/index.js +3 -3
  28. package/dist/filesystem/index.d.ts +703 -703
  29. package/dist/filesystem/index.js +4 -4
  30. package/dist/filesystem/index.js.map +1 -1
  31. package/dist/index.d.ts +4 -4
  32. package/dist/index.js +7 -7
  33. package/dist/index.js.map +1 -1
  34. package/dist/{loader-55LWCXHA.js → loader-VGNXC2XJ.js} +3 -3
  35. package/dist/schema-DDJyoVkj.d.ts +189 -0
  36. package/dist/server/index.d.ts +37 -37
  37. package/dist/server/index.js +5 -5
  38. package/package.json +17 -18
  39. package/src/client/App.tsx +18 -18
  40. package/src/client/components/ConfigPanel/ConfigPanel.tsx +14 -13
  41. package/src/client/components/CreateContentModal/CreateContentModal.tsx +1 -1
  42. package/src/client/components/Editor/Editor.tsx +27 -27
  43. package/src/client/components/Editor/ImageDialog.tsx +4 -3
  44. package/src/client/components/Editor/LinkDialog.tsx +7 -6
  45. package/src/client/components/Editor/index.ts +1 -1
  46. package/src/client/components/FrontmatterForm/FrontmatterForm.css +1 -1
  47. package/src/client/components/FrontmatterForm/FrontmatterForm.tsx +1 -1
  48. package/src/client/components/Header/Header.tsx +8 -8
  49. package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.tsx +1 -1
  50. package/src/client/components/LazyEditor.tsx +1 -1
  51. package/src/client/components/LiveRegion/index.ts +1 -1
  52. package/src/client/components/SearchReplace/SearchReplacePanel.tsx +5 -5
  53. package/src/client/components/SearchReplace/index.ts +1 -1
  54. package/src/client/components/SelectCollectionModal/SelectCollectionModal.tsx +2 -2
  55. package/src/client/components/Sidebar/Sidebar.tsx +6 -6
  56. package/src/client/components/SkipLink/index.ts +1 -1
  57. package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.tsx +1 -1
  58. package/src/client/components/VersionHistory/DiffViewer.tsx +18 -11
  59. package/src/client/components/VersionHistory/VersionActions.tsx +6 -6
  60. package/src/client/components/VersionHistory/VersionHistoryPanel.tsx +10 -10
  61. package/src/client/components/VersionHistory/index.ts +2 -2
  62. package/src/client/context/ApiContext.tsx +2 -2
  63. package/src/client/context/ThemeContext.tsx +2 -2
  64. package/src/client/hooks/useApi.ts +1 -1
  65. package/src/client/hooks/useFocusTrap.ts +1 -1
  66. package/src/client/hooks/useSearch.ts +1 -1
  67. package/src/client/hooks/useVersionHistory.ts +2 -2
  68. package/src/client/index.tsx +1 -1
  69. package/src/client/styles.css +2 -8
  70. package/src/config/defaults.ts +4 -4
  71. package/src/config/index.ts +14 -16
  72. package/src/config/loader.ts +6 -4
  73. package/src/config/schema.ts +8 -4
  74. package/src/core/index.ts +1 -1
  75. package/src/discovery/collections.ts +3 -3
  76. package/src/discovery/index.ts +9 -11
  77. package/src/discovery/patterns.ts +2 -2
  78. package/src/discovery/schema.ts +1 -1
  79. package/src/filesystem/images.ts +3 -3
  80. package/src/filesystem/index.ts +74 -79
  81. package/src/filesystem/reader.ts +2 -2
  82. package/src/filesystem/version-config.ts +10 -10
  83. package/src/filesystem/versions.ts +9 -9
  84. package/src/filesystem/watcher.ts +1 -1
  85. package/src/filesystem/writer.ts +6 -6
  86. package/src/global.d.ts +39 -0
  87. package/src/index.ts +10 -10
  88. package/src/integration.ts +2 -2
  89. package/src/server/assets.ts +3 -3
  90. package/src/server/cache.ts +1 -1
  91. package/src/server/index.ts +12 -15
  92. package/src/server/middleware.ts +3 -3
  93. package/src/server/routes.ts +28 -28
  94. package/src/types/index.ts +24 -28
  95. package/dist/chunk-5PM6EQE5.js.map +0 -1
  96. package/dist/chunk-7XU5X6CW.js.map +0 -1
  97. package/dist/chunk-CF2XXJFF.js.map +0 -1
  98. package/dist/loader-CrdnaAWR.d.ts +0 -327
  99. /package/dist/{loader-55LWCXHA.js.map → loader-VGNXC2XJ.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  isValidPattern,
5
5
  readContentFile,
6
6
  resolvePatternTokens
7
- } from "./chunk-AAOQHQPU.js";
7
+ } from "./chunk-TQAYIZOA.js";
8
8
 
9
9
  // src/core/errors.ts
10
10
  var WritenexErrorCode = /* @__PURE__ */ ((WritenexErrorCode2) => {
@@ -260,17 +260,330 @@ function wrapError(error, defaultCode = "UNKNOWN_ERROR" /* UNKNOWN_ERROR */) {
260
260
  return new WritenexError(defaultCode, message, { cause });
261
261
  }
262
262
 
263
+ // src/filesystem/images.ts
264
+ import { existsSync } from "fs";
265
+ import { mkdir, readdir, stat, writeFile } from "fs/promises";
266
+ import { basename, dirname, extname, join, relative } from "path";
267
+ var DEFAULT_IMAGE_CONFIG = {
268
+ strategy: "colocated",
269
+ publicPath: "/images",
270
+ storagePath: "public/images"
271
+ };
272
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
273
+ ".jpg",
274
+ ".jpeg",
275
+ ".png",
276
+ ".gif",
277
+ ".webp",
278
+ ".avif",
279
+ ".svg"
280
+ ]);
281
+ function isValidImageFile(filename) {
282
+ const ext = extname(filename).toLowerCase();
283
+ return SUPPORTED_EXTENSIONS.has(ext);
284
+ }
285
+ function generateUniqueFilename(originalName, _contentId) {
286
+ const ext = extname(originalName).toLowerCase();
287
+ const baseName = basename(originalName, ext).toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").substring(0, 50);
288
+ const timestamp = Date.now().toString(36);
289
+ return `${baseName}-${timestamp}${ext}`;
290
+ }
291
+ function getColocatedPath(projectRoot, collection, contentId, filename) {
292
+ const collectionPath = join(projectRoot, "src/content", collection);
293
+ const imageDir = join(collectionPath, contentId);
294
+ const storagePath = join(imageDir, filename);
295
+ const indexMdPath = join(collectionPath, contentId, "index.md");
296
+ const indexMdxPath = join(collectionPath, contentId, "index.mdx");
297
+ const isFolderBased = existsSync(indexMdPath) || existsSync(indexMdxPath);
298
+ const markdownPath = isFolderBased ? `./${filename}` : `./${contentId}/${filename}`;
299
+ return { storagePath, markdownPath };
300
+ }
301
+ function getPublicPath(projectRoot, collection, filename, config) {
302
+ const storagePath = join(
303
+ projectRoot,
304
+ config.storagePath ?? "public/images",
305
+ collection,
306
+ filename
307
+ );
308
+ const publicPath = config.publicPath ?? "/images";
309
+ const url = `${publicPath}/${collection}/${filename}`;
310
+ return { storagePath, markdownPath: url, url };
311
+ }
312
+ async function uploadImage(options) {
313
+ const {
314
+ filename,
315
+ data,
316
+ collection,
317
+ contentId,
318
+ projectRoot,
319
+ config = DEFAULT_IMAGE_CONFIG
320
+ } = options;
321
+ if (!isValidImageFile(filename)) {
322
+ return {
323
+ success: false,
324
+ error: `Invalid image file type. Supported: ${[...SUPPORTED_EXTENSIONS].join(", ")}`
325
+ };
326
+ }
327
+ const uniqueFilename = generateUniqueFilename(filename, contentId);
328
+ try {
329
+ let storagePath;
330
+ let markdownPath;
331
+ let url;
332
+ switch (config.strategy) {
333
+ case "public": {
334
+ const paths = getPublicPath(
335
+ projectRoot,
336
+ collection,
337
+ uniqueFilename,
338
+ config
339
+ );
340
+ storagePath = paths.storagePath;
341
+ markdownPath = paths.markdownPath;
342
+ url = paths.url;
343
+ break;
344
+ }
345
+ case "colocated":
346
+ default: {
347
+ const paths = getColocatedPath(
348
+ projectRoot,
349
+ collection,
350
+ contentId,
351
+ uniqueFilename
352
+ );
353
+ storagePath = paths.storagePath;
354
+ markdownPath = paths.markdownPath;
355
+ break;
356
+ }
357
+ }
358
+ const dir = dirname(storagePath);
359
+ if (!existsSync(dir)) {
360
+ await mkdir(dir, { recursive: true });
361
+ }
362
+ await writeFile(storagePath, data);
363
+ return {
364
+ success: true,
365
+ path: markdownPath,
366
+ url: url ?? markdownPath
367
+ };
368
+ } catch (error) {
369
+ const message = error instanceof Error ? error.message : "Unknown error";
370
+ return {
371
+ success: false,
372
+ error: `Failed to upload image: ${message}`
373
+ };
374
+ }
375
+ }
376
+ function parseMultipartFormData(body, contentType) {
377
+ const result = { fields: {} };
378
+ const boundaryMatch = contentType.match(/boundary=(?:"([^"]+)"|([^;]+))/);
379
+ if (!boundaryMatch) {
380
+ return result;
381
+ }
382
+ const boundary = boundaryMatch[1] ?? boundaryMatch[2];
383
+ if (!boundary) {
384
+ return result;
385
+ }
386
+ const boundaryBuffer = Buffer.from(`--${boundary}`);
387
+ const parts = splitBuffer(body, boundaryBuffer);
388
+ for (const part of parts) {
389
+ if (part.length < 10) continue;
390
+ const separatorIndex = part.indexOf("\r\n\r\n");
391
+ if (separatorIndex === -1) continue;
392
+ const headerSection = part.slice(0, separatorIndex).toString("utf-8");
393
+ const bodySection = part.slice(separatorIndex + 4);
394
+ const bodyEnd = bodySection.length - 2;
395
+ const cleanBody = bodyEnd > 0 ? bodySection.slice(0, bodyEnd) : bodySection;
396
+ const headers = parseHeaders(headerSection);
397
+ const disposition = headers["content-disposition"];
398
+ if (!disposition) continue;
399
+ const nameMatch = disposition.match(/name="([^"]+)"/);
400
+ const filenameMatch = disposition.match(/filename="([^"]+)"/);
401
+ if (filenameMatch) {
402
+ result.file = {
403
+ filename: filenameMatch[1] ?? "unknown",
404
+ data: cleanBody,
405
+ contentType: headers["content-type"] ?? "application/octet-stream"
406
+ };
407
+ } else if (nameMatch) {
408
+ result.fields[nameMatch[1] ?? ""] = cleanBody.toString("utf-8");
409
+ }
410
+ }
411
+ return result;
412
+ }
413
+ function splitBuffer(buffer, delimiter) {
414
+ const parts = [];
415
+ let start = 0;
416
+ let index;
417
+ while ((index = buffer.indexOf(delimiter, start)) !== -1) {
418
+ if (index > start) {
419
+ parts.push(buffer.slice(start, index));
420
+ }
421
+ start = index + delimiter.length;
422
+ }
423
+ if (start < buffer.length) {
424
+ parts.push(buffer.slice(start));
425
+ }
426
+ return parts;
427
+ }
428
+ function parseHeaders(headerSection) {
429
+ const headers = {};
430
+ const lines = headerSection.split("\r\n");
431
+ for (const line of lines) {
432
+ const colonIndex = line.indexOf(":");
433
+ if (colonIndex > 0) {
434
+ const key = line.slice(0, colonIndex).trim().toLowerCase();
435
+ const value = line.slice(colonIndex + 1).trim();
436
+ headers[key] = value;
437
+ }
438
+ }
439
+ return headers;
440
+ }
441
+ var DATE_PREFIX_PATTERN = /^\d{4}-\d{2}-\d{2}-/;
442
+ function getContentImageFolder(collectionPath, contentId, contentFilePath) {
443
+ const filename = basename(contentFilePath);
444
+ const contentDir = dirname(contentFilePath);
445
+ if (filename === "index.md" || filename === "index.mdx") {
446
+ return contentDir;
447
+ }
448
+ const siblingFolderPath = join(collectionPath, contentId);
449
+ if (existsSync(siblingFolderPath)) {
450
+ return siblingFolderPath;
451
+ }
452
+ return null;
453
+ }
454
+ function detectContentStructure(contentFilePath) {
455
+ const filename = basename(contentFilePath);
456
+ if (filename === "index.md" || filename === "index.mdx") {
457
+ return "folder-based";
458
+ }
459
+ const nameWithoutExt = filename.replace(/\.(md|mdx)$/, "");
460
+ if (DATE_PREFIX_PATTERN.test(nameWithoutExt)) {
461
+ return "date-prefixed";
462
+ }
463
+ return "flat";
464
+ }
465
+ function shouldSkipDirectory(dirName) {
466
+ return dirName.startsWith(".") || dirName.startsWith("_");
467
+ }
468
+ async function scanDirectoryForImages(dirPath, basePath, options) {
469
+ const { maxDepth, currentDepth } = options;
470
+ if (currentDepth >= maxDepth) {
471
+ return [];
472
+ }
473
+ if (!existsSync(dirPath)) {
474
+ return [];
475
+ }
476
+ const images = [];
477
+ try {
478
+ const entries = await readdir(dirPath, { withFileTypes: true });
479
+ for (const entry of entries) {
480
+ const entryPath = join(dirPath, entry.name);
481
+ if (entry.isDirectory()) {
482
+ if (shouldSkipDirectory(entry.name)) {
483
+ continue;
484
+ }
485
+ const subImages = await scanDirectoryForImages(entryPath, basePath, {
486
+ maxDepth,
487
+ currentDepth: currentDepth + 1,
488
+ basePath
489
+ });
490
+ images.push(...subImages);
491
+ } else if (entry.isFile()) {
492
+ if (isValidImageFile(entry.name)) {
493
+ const fileStat = await stat(entryPath);
494
+ const extension = extname(entry.name).toLowerCase();
495
+ const relativePath = calculateRelativePathFromBase(
496
+ basePath,
497
+ entryPath
498
+ );
499
+ images.push({
500
+ filename: entry.name,
501
+ relativePath,
502
+ absolutePath: entryPath,
503
+ size: fileStat.size,
504
+ extension
505
+ });
506
+ }
507
+ }
508
+ }
509
+ } catch {
510
+ return [];
511
+ }
512
+ return images;
513
+ }
514
+ function calculateRelativePathFromBase(basePath, targetPath) {
515
+ const relPath = relative(basePath, targetPath);
516
+ return `./${relPath}`;
517
+ }
518
+ function calculateRelativePath(contentFilePath, imagePath) {
519
+ const contentDir = dirname(contentFilePath);
520
+ const relPath = relative(contentDir, imagePath);
521
+ if (relPath.startsWith("..")) {
522
+ return relPath;
523
+ }
524
+ return `./${relPath}`;
525
+ }
526
+ var DEFAULT_MAX_DEPTH = 5;
527
+ async function discoverContentImages(collectionPath, contentId, options) {
528
+ const maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH;
529
+ try {
530
+ const contentFilePath = getContentFilePath(collectionPath, contentId);
531
+ if (!contentFilePath) {
532
+ return {
533
+ success: false,
534
+ images: [],
535
+ error: `Content '${contentId}' not found in collection`
536
+ };
537
+ }
538
+ const imageFolderPath = getContentImageFolder(
539
+ collectionPath,
540
+ contentId,
541
+ contentFilePath
542
+ );
543
+ if (!imageFolderPath) {
544
+ return {
545
+ success: true,
546
+ images: []
547
+ };
548
+ }
549
+ const scannedImages = await scanDirectoryForImages(
550
+ imageFolderPath,
551
+ imageFolderPath,
552
+ {
553
+ maxDepth,
554
+ currentDepth: 0,
555
+ basePath: imageFolderPath
556
+ }
557
+ );
558
+ const images = scannedImages.map((img) => ({
559
+ ...img,
560
+ relativePath: calculateRelativePath(contentFilePath, img.absolutePath)
561
+ }));
562
+ return {
563
+ success: true,
564
+ images
565
+ };
566
+ } catch (error) {
567
+ const message = error instanceof Error ? error.message : "Unknown error";
568
+ return {
569
+ success: false,
570
+ images: [],
571
+ error: `Failed to discover images: ${message}`
572
+ };
573
+ }
574
+ }
575
+
263
576
  // src/filesystem/versions.ts
577
+ import { existsSync as existsSync2 } from "fs";
264
578
  import {
579
+ mkdir as mkdir2,
580
+ readdir as readdir2,
265
581
  readFile,
266
- writeFile,
267
- mkdir,
268
- readdir,
269
- stat,
270
- unlink
582
+ stat as stat2,
583
+ unlink,
584
+ writeFile as writeFile2
271
585
  } from "fs/promises";
272
- import { existsSync } from "fs";
273
- import { join, basename } from "path";
586
+ import { basename as basename2, join as join2 } from "path";
274
587
  import matter from "gray-matter";
275
588
  var PREVIEW_MAX_LENGTH = 100;
276
589
  var GITIGNORE_CONTENT = "*\n";
@@ -338,13 +651,13 @@ function parseVersionId(versionId) {
338
651
  return isNaN(date.getTime()) ? null : date;
339
652
  }
340
653
  function getVersionStoragePath(projectRoot, collection, contentId, config) {
341
- return join(projectRoot, config.storagePath, collection, contentId);
654
+ return join2(projectRoot, config.storagePath, collection, contentId);
342
655
  }
343
656
  function getVersionFilePath(storagePath, versionId) {
344
- return join(storagePath, `${versionId}.md`);
657
+ return join2(storagePath, `${versionId}.md`);
345
658
  }
346
659
  function getManifestPath(storagePath) {
347
- return join(storagePath, "manifest.json");
660
+ return join2(storagePath, "manifest.json");
348
661
  }
349
662
  function generatePreview(content) {
350
663
  try {
@@ -397,23 +710,23 @@ function stripLabelFromContent(content) {
397
710
  }
398
711
  }
399
712
  async function ensureGitignore(projectRoot, config) {
400
- const storageRoot = join(projectRoot, config.storagePath);
401
- const gitignorePath = join(storageRoot, ".gitignore");
402
- if (!existsSync(storageRoot)) {
403
- await mkdir(storageRoot, { recursive: true });
713
+ const storageRoot = join2(projectRoot, config.storagePath);
714
+ const gitignorePath = join2(storageRoot, ".gitignore");
715
+ if (!existsSync2(storageRoot)) {
716
+ await mkdir2(storageRoot, { recursive: true });
404
717
  }
405
- if (!existsSync(gitignorePath)) {
406
- await writeFile(gitignorePath, GITIGNORE_CONTENT, "utf-8");
718
+ if (!existsSync2(gitignorePath)) {
719
+ await writeFile2(gitignorePath, GITIGNORE_CONTENT, "utf-8");
407
720
  }
408
721
  }
409
722
  async function ensureStorageDirectory(storagePath) {
410
- if (!existsSync(storagePath)) {
411
- await mkdir(storagePath, { recursive: true });
723
+ if (!existsSync2(storagePath)) {
724
+ await mkdir2(storagePath, { recursive: true });
412
725
  }
413
726
  }
414
727
  async function readManifest(storagePath) {
415
728
  const manifestPath = getManifestPath(storagePath);
416
- if (!existsSync(manifestPath)) {
729
+ if (!existsSync2(manifestPath)) {
417
730
  return null;
418
731
  }
419
732
  try {
@@ -436,7 +749,7 @@ async function writeManifest(storagePath, manifest) {
436
749
  await ensureStorageDirectory(storagePath);
437
750
  const manifestPath = getManifestPath(storagePath);
438
751
  const content = JSON.stringify(manifest, null, 2);
439
- await writeFile(manifestPath, content, "utf-8");
752
+ await writeFile2(manifestPath, content, "utf-8");
440
753
  }
441
754
  function createEmptyManifest(collection, contentId) {
442
755
  return {
@@ -448,20 +761,20 @@ function createEmptyManifest(collection, contentId) {
448
761
  }
449
762
  async function recoverManifest(storagePath, collection, contentId) {
450
763
  const manifest = createEmptyManifest(collection, contentId);
451
- if (!existsSync(storagePath)) {
764
+ if (!existsSync2(storagePath)) {
452
765
  return manifest;
453
766
  }
454
767
  try {
455
- const files = await readdir(storagePath);
768
+ const files = await readdir2(storagePath);
456
769
  const versionFiles = files.filter(
457
770
  (f) => f.endsWith(".md") && f !== "manifest.json"
458
771
  );
459
772
  for (const file of versionFiles) {
460
- const versionId = basename(file, ".md");
461
- const filePath = join(storagePath, file);
773
+ const versionId = basename2(file, ".md");
774
+ const filePath = join2(storagePath, file);
462
775
  try {
463
776
  const content = await readFile(filePath, "utf-8");
464
- const stats = await stat(filePath);
777
+ const stats = await stat2(filePath);
465
778
  const timestamp = parseVersionId(versionId);
466
779
  if (timestamp) {
467
780
  const label = extractLabelFromContent(content);
@@ -523,7 +836,7 @@ async function saveVersion(projectRoot, collection, contentId, content, config,
523
836
  storagePath,
524
837
  lastVersion.id
525
838
  );
526
- if (existsSync(lastVersionPath)) {
839
+ if (existsSync2(lastVersionPath)) {
527
840
  try {
528
841
  const lastContent = await readFile(lastVersionPath, "utf-8");
529
842
  if (lastContent === content) {
@@ -538,8 +851,8 @@ async function saveVersion(projectRoot, collection, contentId, content, config,
538
851
  const versionId = now.toISOString().replace(/:/g, "-");
539
852
  const versionPath = getVersionFilePath(storagePath, versionId);
540
853
  const contentToSave = label ? injectLabelIntoContent(content, label) : content;
541
- await writeFile(versionPath, contentToSave, "utf-8");
542
- const stats = await stat(versionPath);
854
+ await writeFile2(versionPath, contentToSave, "utf-8");
855
+ const stats = await stat2(versionPath);
543
856
  const entry = {
544
857
  id: versionId,
545
858
  timestamp: now.toISOString(),
@@ -570,7 +883,7 @@ async function getVersions(projectRoot, collection, contentId, config) {
570
883
  contentId,
571
884
  config
572
885
  );
573
- if (!existsSync(storagePath)) {
886
+ if (!existsSync2(storagePath)) {
574
887
  return [];
575
888
  }
576
889
  const manifest = await getOrRecoverManifest(
@@ -598,11 +911,11 @@ async function getVersion(projectRoot, collection, contentId, versionId, config)
598
911
  config
599
912
  );
600
913
  const versionPath = getVersionFilePath(storagePath, versionId);
601
- if (!existsSync(versionPath)) {
914
+ if (!existsSync2(versionPath)) {
602
915
  return null;
603
916
  }
604
917
  const rawContent = await readFile(versionPath, "utf-8");
605
- const stats = await stat(versionPath);
918
+ const stats = await stat2(versionPath);
606
919
  const labelFromContent = extractLabelFromContent(rawContent);
607
920
  const content = stripLabelFromContent(rawContent);
608
921
  const { data: frontmatter, content: body } = matter(content);
@@ -638,7 +951,7 @@ async function deleteVersion(projectRoot, collection, contentId, versionId, conf
638
951
  return withLock(storagePath, async () => {
639
952
  try {
640
953
  const versionPath = getVersionFilePath(storagePath, versionId);
641
- if (!existsSync(versionPath)) {
954
+ if (!existsSync2(versionPath)) {
642
955
  return { success: false, error: `Version not found: ${versionId}` };
643
956
  }
644
957
  const manifest = await getOrRecoverManifest(
@@ -669,17 +982,17 @@ async function clearVersions(projectRoot, collection, contentId, config) {
669
982
  contentId,
670
983
  config
671
984
  );
672
- if (!existsSync(storagePath)) {
985
+ if (!existsSync2(storagePath)) {
673
986
  return { success: true };
674
987
  }
675
988
  return withLock(storagePath, async () => {
676
989
  try {
677
- const files = await readdir(storagePath);
990
+ const files = await readdir2(storagePath);
678
991
  const versionFiles = files.filter(
679
992
  (f) => f.endsWith(".md") && f !== "manifest.json"
680
993
  );
681
994
  for (const file of versionFiles) {
682
- const filePath = join(storagePath, file);
995
+ const filePath = join2(storagePath, file);
683
996
  try {
684
997
  await unlink(filePath);
685
998
  } catch {
@@ -697,7 +1010,7 @@ async function clearVersions(projectRoot, collection, contentId, config) {
697
1010
  }
698
1011
  async function pruneVersionsInternal(storagePath, config) {
699
1012
  try {
700
- if (!existsSync(storagePath)) {
1013
+ if (!existsSync2(storagePath)) {
701
1014
  return { success: true };
702
1015
  }
703
1016
  const manifest = await readManifest(storagePath);
@@ -719,7 +1032,7 @@ async function pruneVersionsInternal(storagePath, config) {
719
1032
  for (const version of toDelete) {
720
1033
  const versionPath = getVersionFilePath(storagePath, version.id);
721
1034
  try {
722
- if (existsSync(versionPath)) {
1035
+ if (existsSync2(versionPath)) {
723
1036
  await unlink(versionPath);
724
1037
  }
725
1038
  } catch {
@@ -747,7 +1060,7 @@ async function pruneVersions(projectRoot, collection, contentId, config) {
747
1060
  contentId,
748
1061
  config
749
1062
  );
750
- if (!existsSync(storagePath)) {
1063
+ if (!existsSync2(storagePath)) {
751
1064
  return { success: true };
752
1065
  }
753
1066
  return withLock(
@@ -772,7 +1085,7 @@ async function restoreVersion(projectRoot, collection, contentId, versionId, con
772
1085
  };
773
1086
  }
774
1087
  let safetySnapshot;
775
- if (!skipSafetySnapshot && existsSync(contentFilePath)) {
1088
+ if (!skipSafetySnapshot && existsSync2(contentFilePath)) {
776
1089
  try {
777
1090
  const currentContent = await readFile(contentFilePath, "utf-8");
778
1091
  const snapshotResult = await saveVersion(
@@ -793,7 +1106,7 @@ async function restoreVersion(projectRoot, collection, contentId, versionId, con
793
1106
  );
794
1107
  }
795
1108
  }
796
- await writeFile(contentFilePath, versionToRestore.content, "utf-8");
1109
+ await writeFile2(contentFilePath, versionToRestore.content, "utf-8");
797
1110
  return {
798
1111
  success: true,
799
1112
  version: {
@@ -817,9 +1130,9 @@ async function restoreVersion(projectRoot, collection, contentId, versionId, con
817
1130
  }
818
1131
 
819
1132
  // src/filesystem/writer.ts
820
- import { writeFile as writeFile2, unlink as unlink2, mkdir as mkdir2, readFile as readFile2, stat as stat2 } from "fs/promises";
821
- import { existsSync as existsSync2 } from "fs";
822
- import { join as join2, dirname, basename as basename2 } from "path";
1133
+ import { existsSync as existsSync3 } from "fs";
1134
+ import { mkdir as mkdir3, readFile as readFile2, stat as stat3, unlink as unlink2, writeFile as writeFile3 } from "fs/promises";
1135
+ import { basename as basename3, dirname as dirname2, join as join3 } from "path";
823
1136
  import slugify from "slugify";
824
1137
  function generateSlug(text) {
825
1138
  return slugify(text, {
@@ -830,12 +1143,12 @@ function generateSlug(text) {
830
1143
  }
831
1144
  function contentExists(slug, collectionPath, filePattern) {
832
1145
  const relativePath = generatePathFromPattern(filePattern, { slug });
833
- const fullPath = join2(collectionPath, relativePath);
1146
+ const fullPath = join3(collectionPath, relativePath);
834
1147
  if (filePattern.includes("/index.")) {
835
- const folderPath = join2(collectionPath, slug);
836
- return existsSync2(folderPath);
1148
+ const folderPath = join3(collectionPath, slug);
1149
+ return existsSync3(folderPath);
837
1150
  }
838
- return existsSync2(fullPath);
1151
+ return existsSync3(fullPath);
839
1152
  }
840
1153
  async function generateUniqueSlug(baseSlug, collectionPath, filePattern = "{slug}.md") {
841
1154
  let slug = baseSlug;
@@ -917,13 +1230,13 @@ async function createContent(collectionPath, options) {
917
1230
  customTokens
918
1231
  });
919
1232
  const relativePath = generatePathFromPattern(filePattern, tokens);
920
- const filePath = join2(collectionPath, relativePath);
921
- const parentDir = dirname(filePath);
922
- if (!existsSync2(parentDir)) {
923
- await mkdir2(parentDir, { recursive: true });
1233
+ const filePath = join3(collectionPath, relativePath);
1234
+ const parentDir = dirname2(filePath);
1235
+ if (!existsSync3(parentDir)) {
1236
+ await mkdir3(parentDir, { recursive: true });
924
1237
  }
925
1238
  const content = createFileContent(frontmatter, body);
926
- await writeFile2(filePath, content, "utf-8");
1239
+ await writeFile3(filePath, content, "utf-8");
927
1240
  return {
928
1241
  success: true,
929
1242
  id: slug,
@@ -955,405 +1268,92 @@ async function updateContent(filePath, collectionPath, options) {
955
1268
  existing.content.id,
956
1269
  existing.content.raw,
957
1270
  existing.content.mtime,
958
- expectedMtime
959
- );
960
- return {
961
- success: false,
962
- error: conflictError.message,
963
- conflict: conflictError
964
- };
965
- }
966
- }
967
- const frontmatter = options.frontmatter ? { ...existing.content.frontmatter, ...options.frontmatter } : existing.content.frontmatter;
968
- const body = options.body ?? existing.content.body;
969
- const newContent = createFileContent(frontmatter, body);
970
- const currentContent = existsSync2(filePath) ? await readFile2(filePath, "utf-8") : "";
971
- if (newContent === currentContent) {
972
- return {
973
- success: true,
974
- id: existing.content.id,
975
- path: filePath,
976
- mtime: existing.content.mtime
977
- };
978
- }
979
- if (projectRoot && collection && versionHistoryConfig && versionHistoryConfig.enabled && currentContent) {
980
- try {
981
- const fileName = basename2(filePath);
982
- const contentId = fileName === "index.md" || fileName === "index.mdx" ? basename2(dirname(filePath)) : fileName.replace(/\.(md|mdx)$/, "");
983
- const versionResult = await saveVersion(
984
- projectRoot,
985
- collection,
986
- contentId,
987
- currentContent,
988
- versionHistoryConfig,
989
- { skipIfIdentical: true }
990
- );
991
- if (!versionResult.success) {
992
- console.warn(
993
- `[writenex] Failed to create version snapshot: ${versionResult.error}`
994
- );
995
- }
996
- } catch (versionError) {
997
- console.warn(
998
- `[writenex] Version creation error (save will continue):`,
999
- versionError
1000
- );
1001
- }
1002
- }
1003
- await writeFile2(filePath, newContent, "utf-8");
1004
- const newStats = await stat2(filePath);
1005
- return {
1006
- success: true,
1007
- id: existing.content.id,
1008
- path: filePath,
1009
- mtime: newStats.mtimeMs
1010
- };
1011
- } catch (error) {
1012
- if (error instanceof ContentConflictError) {
1013
- return {
1014
- success: false,
1015
- error: error.message,
1016
- conflict: error
1017
- };
1018
- }
1019
- const message = error instanceof Error ? error.message : String(error);
1020
- return {
1021
- success: false,
1022
- error: `Failed to update content: ${message}`
1023
- };
1024
- }
1025
- }
1026
- async function deleteContent(filePath) {
1027
- try {
1028
- if (!existsSync2(filePath)) {
1029
- return {
1030
- success: false,
1031
- error: "Content file not found"
1032
- };
1033
- }
1034
- await unlink2(filePath);
1035
- return {
1036
- success: true,
1037
- path: filePath
1038
- };
1039
- } catch (error) {
1040
- const message = error instanceof Error ? error.message : String(error);
1041
- return {
1042
- success: false,
1043
- error: `Failed to delete content: ${message}`
1044
- };
1045
- }
1046
- }
1047
-
1048
- // src/filesystem/images.ts
1049
- import { writeFile as writeFile3, mkdir as mkdir3, readdir as readdir2, stat as stat3 } from "fs/promises";
1050
- import { existsSync as existsSync3 } from "fs";
1051
- import { join as join3, dirname as dirname2, basename as basename3, extname, relative } from "path";
1052
- var DEFAULT_IMAGE_CONFIG = {
1053
- strategy: "colocated",
1054
- publicPath: "/images",
1055
- storagePath: "public/images"
1056
- };
1057
- var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
1058
- ".jpg",
1059
- ".jpeg",
1060
- ".png",
1061
- ".gif",
1062
- ".webp",
1063
- ".avif",
1064
- ".svg"
1065
- ]);
1066
- function isValidImageFile(filename) {
1067
- const ext = extname(filename).toLowerCase();
1068
- return SUPPORTED_EXTENSIONS.has(ext);
1069
- }
1070
- function generateUniqueFilename(originalName, _contentId) {
1071
- const ext = extname(originalName).toLowerCase();
1072
- const baseName = basename3(originalName, ext).toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").substring(0, 50);
1073
- const timestamp = Date.now().toString(36);
1074
- return `${baseName}-${timestamp}${ext}`;
1075
- }
1076
- function getColocatedPath(projectRoot, collection, contentId, filename) {
1077
- const collectionPath = join3(projectRoot, "src/content", collection);
1078
- const imageDir = join3(collectionPath, contentId);
1079
- const storagePath = join3(imageDir, filename);
1080
- const indexMdPath = join3(collectionPath, contentId, "index.md");
1081
- const indexMdxPath = join3(collectionPath, contentId, "index.mdx");
1082
- const isFolderBased = existsSync3(indexMdPath) || existsSync3(indexMdxPath);
1083
- const markdownPath = isFolderBased ? `./${filename}` : `./${contentId}/${filename}`;
1084
- return { storagePath, markdownPath };
1085
- }
1086
- function getPublicPath(projectRoot, collection, filename, config) {
1087
- const storagePath = join3(
1088
- projectRoot,
1089
- config.storagePath ?? "public/images",
1090
- collection,
1091
- filename
1092
- );
1093
- const publicPath = config.publicPath ?? "/images";
1094
- const url = `${publicPath}/${collection}/${filename}`;
1095
- return { storagePath, markdownPath: url, url };
1096
- }
1097
- async function uploadImage(options) {
1098
- const {
1099
- filename,
1100
- data,
1101
- collection,
1102
- contentId,
1103
- projectRoot,
1104
- config = DEFAULT_IMAGE_CONFIG
1105
- } = options;
1106
- if (!isValidImageFile(filename)) {
1107
- return {
1108
- success: false,
1109
- error: `Invalid image file type. Supported: ${[...SUPPORTED_EXTENSIONS].join(", ")}`
1110
- };
1111
- }
1112
- const uniqueFilename = generateUniqueFilename(filename, contentId);
1113
- try {
1114
- let storagePath;
1115
- let markdownPath;
1116
- let url;
1117
- switch (config.strategy) {
1118
- case "public": {
1119
- const paths = getPublicPath(
1120
- projectRoot,
1121
- collection,
1122
- uniqueFilename,
1123
- config
1124
- );
1125
- storagePath = paths.storagePath;
1126
- markdownPath = paths.markdownPath;
1127
- url = paths.url;
1128
- break;
1271
+ expectedMtime
1272
+ );
1273
+ return {
1274
+ success: false,
1275
+ error: conflictError.message,
1276
+ conflict: conflictError
1277
+ };
1129
1278
  }
1130
- case "colocated":
1131
- default: {
1132
- const paths = getColocatedPath(
1279
+ }
1280
+ const frontmatter = options.frontmatter ? { ...existing.content.frontmatter, ...options.frontmatter } : existing.content.frontmatter;
1281
+ const body = options.body ?? existing.content.body;
1282
+ const newContent = createFileContent(frontmatter, body);
1283
+ const currentContent = existsSync3(filePath) ? await readFile2(filePath, "utf-8") : "";
1284
+ if (newContent === currentContent) {
1285
+ return {
1286
+ success: true,
1287
+ id: existing.content.id,
1288
+ path: filePath,
1289
+ mtime: existing.content.mtime
1290
+ };
1291
+ }
1292
+ if (projectRoot && collection && versionHistoryConfig && versionHistoryConfig.enabled && currentContent) {
1293
+ try {
1294
+ const fileName = basename3(filePath);
1295
+ const contentId = fileName === "index.md" || fileName === "index.mdx" ? basename3(dirname2(filePath)) : fileName.replace(/\.(md|mdx)$/, "");
1296
+ const versionResult = await saveVersion(
1133
1297
  projectRoot,
1134
1298
  collection,
1135
1299
  contentId,
1136
- uniqueFilename
1300
+ currentContent,
1301
+ versionHistoryConfig,
1302
+ { skipIfIdentical: true }
1303
+ );
1304
+ if (!versionResult.success) {
1305
+ console.warn(
1306
+ `[writenex] Failed to create version snapshot: ${versionResult.error}`
1307
+ );
1308
+ }
1309
+ } catch (versionError) {
1310
+ console.warn(
1311
+ `[writenex] Version creation error (save will continue):`,
1312
+ versionError
1137
1313
  );
1138
- storagePath = paths.storagePath;
1139
- markdownPath = paths.markdownPath;
1140
- break;
1141
1314
  }
1142
1315
  }
1143
- const dir = dirname2(storagePath);
1144
- if (!existsSync3(dir)) {
1145
- await mkdir3(dir, { recursive: true });
1146
- }
1147
- await writeFile3(storagePath, data);
1316
+ await writeFile3(filePath, newContent, "utf-8");
1317
+ const newStats = await stat3(filePath);
1148
1318
  return {
1149
1319
  success: true,
1150
- path: markdownPath,
1151
- url: url ?? markdownPath
1320
+ id: existing.content.id,
1321
+ path: filePath,
1322
+ mtime: newStats.mtimeMs
1152
1323
  };
1153
1324
  } catch (error) {
1154
- const message = error instanceof Error ? error.message : "Unknown error";
1325
+ if (error instanceof ContentConflictError) {
1326
+ return {
1327
+ success: false,
1328
+ error: error.message,
1329
+ conflict: error
1330
+ };
1331
+ }
1332
+ const message = error instanceof Error ? error.message : String(error);
1155
1333
  return {
1156
1334
  success: false,
1157
- error: `Failed to upload image: ${message}`
1335
+ error: `Failed to update content: ${message}`
1158
1336
  };
1159
1337
  }
1160
1338
  }
1161
- function parseMultipartFormData(body, contentType) {
1162
- const result = { fields: {} };
1163
- const boundaryMatch = contentType.match(/boundary=(?:"([^"]+)"|([^;]+))/);
1164
- if (!boundaryMatch) {
1165
- return result;
1166
- }
1167
- const boundary = boundaryMatch[1] ?? boundaryMatch[2];
1168
- if (!boundary) {
1169
- return result;
1170
- }
1171
- const boundaryBuffer = Buffer.from(`--${boundary}`);
1172
- const parts = splitBuffer(body, boundaryBuffer);
1173
- for (const part of parts) {
1174
- if (part.length < 10) continue;
1175
- const separatorIndex = part.indexOf("\r\n\r\n");
1176
- if (separatorIndex === -1) continue;
1177
- const headerSection = part.slice(0, separatorIndex).toString("utf-8");
1178
- const bodySection = part.slice(separatorIndex + 4);
1179
- const bodyEnd = bodySection.length - 2;
1180
- const cleanBody = bodyEnd > 0 ? bodySection.slice(0, bodyEnd) : bodySection;
1181
- const headers = parseHeaders(headerSection);
1182
- const disposition = headers["content-disposition"];
1183
- if (!disposition) continue;
1184
- const nameMatch = disposition.match(/name="([^"]+)"/);
1185
- const filenameMatch = disposition.match(/filename="([^"]+)"/);
1186
- if (filenameMatch) {
1187
- result.file = {
1188
- filename: filenameMatch[1] ?? "unknown",
1189
- data: cleanBody,
1190
- contentType: headers["content-type"] ?? "application/octet-stream"
1191
- };
1192
- } else if (nameMatch) {
1193
- result.fields[nameMatch[1] ?? ""] = cleanBody.toString("utf-8");
1194
- }
1195
- }
1196
- return result;
1197
- }
1198
- function splitBuffer(buffer, delimiter) {
1199
- const parts = [];
1200
- let start = 0;
1201
- let index;
1202
- while ((index = buffer.indexOf(delimiter, start)) !== -1) {
1203
- if (index > start) {
1204
- parts.push(buffer.slice(start, index));
1205
- }
1206
- start = index + delimiter.length;
1207
- }
1208
- if (start < buffer.length) {
1209
- parts.push(buffer.slice(start));
1210
- }
1211
- return parts;
1212
- }
1213
- function parseHeaders(headerSection) {
1214
- const headers = {};
1215
- const lines = headerSection.split("\r\n");
1216
- for (const line of lines) {
1217
- const colonIndex = line.indexOf(":");
1218
- if (colonIndex > 0) {
1219
- const key = line.slice(0, colonIndex).trim().toLowerCase();
1220
- const value = line.slice(colonIndex + 1).trim();
1221
- headers[key] = value;
1222
- }
1223
- }
1224
- return headers;
1225
- }
1226
- var DATE_PREFIX_PATTERN = /^\d{4}-\d{2}-\d{2}-/;
1227
- function getContentImageFolder(collectionPath, contentId, contentFilePath) {
1228
- const filename = basename3(contentFilePath);
1229
- const contentDir = dirname2(contentFilePath);
1230
- if (filename === "index.md" || filename === "index.mdx") {
1231
- return contentDir;
1232
- }
1233
- const siblingFolderPath = join3(collectionPath, contentId);
1234
- if (existsSync3(siblingFolderPath)) {
1235
- return siblingFolderPath;
1236
- }
1237
- return null;
1238
- }
1239
- function detectContentStructure(contentFilePath) {
1240
- const filename = basename3(contentFilePath);
1241
- if (filename === "index.md" || filename === "index.mdx") {
1242
- return "folder-based";
1243
- }
1244
- const nameWithoutExt = filename.replace(/\.(md|mdx)$/, "");
1245
- if (DATE_PREFIX_PATTERN.test(nameWithoutExt)) {
1246
- return "date-prefixed";
1247
- }
1248
- return "flat";
1249
- }
1250
- function shouldSkipDirectory(dirName) {
1251
- return dirName.startsWith(".") || dirName.startsWith("_");
1252
- }
1253
- async function scanDirectoryForImages(dirPath, basePath, options) {
1254
- const { maxDepth, currentDepth } = options;
1255
- if (currentDepth >= maxDepth) {
1256
- return [];
1257
- }
1258
- if (!existsSync3(dirPath)) {
1259
- return [];
1260
- }
1261
- const images = [];
1262
- try {
1263
- const entries = await readdir2(dirPath, { withFileTypes: true });
1264
- for (const entry of entries) {
1265
- const entryPath = join3(dirPath, entry.name);
1266
- if (entry.isDirectory()) {
1267
- if (shouldSkipDirectory(entry.name)) {
1268
- continue;
1269
- }
1270
- const subImages = await scanDirectoryForImages(entryPath, basePath, {
1271
- maxDepth,
1272
- currentDepth: currentDepth + 1,
1273
- basePath
1274
- });
1275
- images.push(...subImages);
1276
- } else if (entry.isFile()) {
1277
- if (isValidImageFile(entry.name)) {
1278
- const fileStat = await stat3(entryPath);
1279
- const extension = extname(entry.name).toLowerCase();
1280
- const relativePath = calculateRelativePathFromBase(
1281
- basePath,
1282
- entryPath
1283
- );
1284
- images.push({
1285
- filename: entry.name,
1286
- relativePath,
1287
- absolutePath: entryPath,
1288
- size: fileStat.size,
1289
- extension
1290
- });
1291
- }
1292
- }
1293
- }
1294
- } catch {
1295
- return [];
1296
- }
1297
- return images;
1298
- }
1299
- function calculateRelativePathFromBase(basePath, targetPath) {
1300
- const relPath = relative(basePath, targetPath);
1301
- return `./${relPath}`;
1302
- }
1303
- function calculateRelativePath(contentFilePath, imagePath) {
1304
- const contentDir = dirname2(contentFilePath);
1305
- const relPath = relative(contentDir, imagePath);
1306
- if (relPath.startsWith("..")) {
1307
- return relPath;
1308
- }
1309
- return `./${relPath}`;
1310
- }
1311
- var DEFAULT_MAX_DEPTH = 5;
1312
- async function discoverContentImages(collectionPath, contentId, options) {
1313
- const maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH;
1339
+ async function deleteContent(filePath) {
1314
1340
  try {
1315
- const contentFilePath = getContentFilePath(collectionPath, contentId);
1316
- if (!contentFilePath) {
1341
+ if (!existsSync3(filePath)) {
1317
1342
  return {
1318
1343
  success: false,
1319
- images: [],
1320
- error: `Content '${contentId}' not found in collection`
1321
- };
1322
- }
1323
- const imageFolderPath = getContentImageFolder(
1324
- collectionPath,
1325
- contentId,
1326
- contentFilePath
1327
- );
1328
- if (!imageFolderPath) {
1329
- return {
1330
- success: true,
1331
- images: []
1344
+ error: "Content file not found"
1332
1345
  };
1333
1346
  }
1334
- const scannedImages = await scanDirectoryForImages(
1335
- imageFolderPath,
1336
- imageFolderPath,
1337
- {
1338
- maxDepth,
1339
- currentDepth: 0,
1340
- basePath: imageFolderPath
1341
- }
1342
- );
1343
- const images = scannedImages.map((img) => ({
1344
- ...img,
1345
- relativePath: calculateRelativePath(contentFilePath, img.absolutePath)
1346
- }));
1347
+ await unlink2(filePath);
1347
1348
  return {
1348
1349
  success: true,
1349
- images
1350
+ path: filePath
1350
1351
  };
1351
1352
  } catch (error) {
1352
- const message = error instanceof Error ? error.message : "Unknown error";
1353
+ const message = error instanceof Error ? error.message : String(error);
1353
1354
  return {
1354
1355
  success: false,
1355
- images: [],
1356
- error: `Failed to discover images: ${message}`
1356
+ error: `Failed to delete content: ${message}`
1357
1357
  };
1358
1358
  }
1359
1359
  }
@@ -1372,6 +1372,15 @@ export {
1372
1372
  VersionNotFoundError,
1373
1373
  isWritenexError,
1374
1374
  wrapError,
1375
+ DEFAULT_IMAGE_CONFIG,
1376
+ isValidImageFile,
1377
+ uploadImage,
1378
+ parseMultipartFormData,
1379
+ getContentImageFolder,
1380
+ detectContentStructure,
1381
+ scanDirectoryForImages,
1382
+ calculateRelativePath,
1383
+ discoverContentImages,
1375
1384
  generateVersionId,
1376
1385
  parseVersionId,
1377
1386
  getVersionStoragePath,
@@ -1396,15 +1405,6 @@ export {
1396
1405
  generateUniqueSlug,
1397
1406
  createContent,
1398
1407
  updateContent,
1399
- deleteContent,
1400
- DEFAULT_IMAGE_CONFIG,
1401
- isValidImageFile,
1402
- uploadImage,
1403
- parseMultipartFormData,
1404
- getContentImageFolder,
1405
- detectContentStructure,
1406
- scanDirectoryForImages,
1407
- calculateRelativePath,
1408
- discoverContentImages
1408
+ deleteContent
1409
1409
  };
1410
- //# sourceMappingURL=chunk-CF2XXJFF.js.map
1410
+ //# sourceMappingURL=chunk-OWYFIQFK.js.map