@leadcms/sdk 3.2.0 → 3.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 (46) hide show
  1. package/README.md +15 -3
  2. package/dist/cli/bin/generate-env.d.ts +1 -1
  3. package/dist/cli/bin/generate-env.d.ts.map +1 -1
  4. package/dist/cli/bin/generate-env.js +2 -2
  5. package/dist/cli/bin/generate-env.js.map +1 -1
  6. package/dist/cli/bin/pull-comments.js +3 -1
  7. package/dist/cli/bin/pull-comments.js.map +1 -1
  8. package/dist/cli/bin/pull-content.js +2 -1
  9. package/dist/cli/bin/pull-content.js.map +1 -1
  10. package/dist/cli/bin/pull-media.js +3 -1
  11. package/dist/cli/bin/pull-media.js.map +1 -1
  12. package/dist/cli/index.js +7 -4
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/lib/content-merge.d.ts +80 -0
  19. package/dist/lib/content-merge.d.ts.map +1 -0
  20. package/dist/lib/content-merge.js +350 -0
  21. package/dist/lib/content-merge.js.map +1 -0
  22. package/dist/scripts/fetch-leadcms-content.d.ts +1 -0
  23. package/dist/scripts/fetch-leadcms-content.d.ts.map +1 -1
  24. package/dist/scripts/fetch-leadcms-content.js +106 -13
  25. package/dist/scripts/fetch-leadcms-content.js.map +1 -1
  26. package/dist/scripts/generate-env-js.d.ts +5 -0
  27. package/dist/scripts/generate-env-js.d.ts.map +1 -1
  28. package/dist/scripts/generate-env-js.js +12 -10
  29. package/dist/scripts/generate-env-js.js.map +1 -1
  30. package/dist/scripts/pull-all.d.ts +16 -1
  31. package/dist/scripts/pull-all.d.ts.map +1 -1
  32. package/dist/scripts/pull-all.js +49 -24
  33. package/dist/scripts/pull-all.js.map +1 -1
  34. package/dist/scripts/pull-comments.d.ts +5 -1
  35. package/dist/scripts/pull-comments.d.ts.map +1 -1
  36. package/dist/scripts/pull-comments.js +8 -1
  37. package/dist/scripts/pull-comments.js.map +1 -1
  38. package/dist/scripts/pull-content.d.ts +2 -0
  39. package/dist/scripts/pull-content.d.ts.map +1 -1
  40. package/dist/scripts/pull-content.js +7 -1
  41. package/dist/scripts/pull-content.js.map +1 -1
  42. package/dist/scripts/pull-media.d.ts +5 -1
  43. package/dist/scripts/pull-media.d.ts.map +1 -1
  44. package/dist/scripts/pull-media.js +8 -1
  45. package/dist/scripts/pull-media.js.map +1 -1
  46. package/package.json +3 -2
package/README.md CHANGED
@@ -152,14 +152,17 @@ npm run test:watch
152
152
 
153
153
  ### Test Coverage
154
154
 
155
- The SDK maintains high test coverage with comprehensive unit tests covering:
155
+ The SDK maintains high test coverage with **481 tests across 30 test suites**, covering:
156
156
 
157
- - 📄 Content retrieval and parsing
157
+ - 📄 Content retrieval, parsing, and transformation
158
158
  - 🌍 Multi-language support and translations
159
159
  - 📝 Draft content handling and user-specific overrides
160
160
  - 🏗️ Build-time optimizations and caching
161
161
  - 🔧 Configuration management and validation
162
162
  - 🔄 Push/Pull synchronization with conflict detection
163
+ - 🗂️ Content rename, type change, and deletion handling
164
+ - 🗑️ Media deletion sync and file cleanup
165
+ - 🔁 Sync token migration and edge cases
163
166
  - 🖥️ CLI command functionality with mocked API responses
164
167
 
165
168
  ### Testing with Mock Data
@@ -395,6 +398,9 @@ npx leadcms pull-media
395
398
 
396
399
  # Pull only comments
397
400
  npx leadcms pull-comments
401
+
402
+ # Reset and pull everything from scratch
403
+ npx leadcms pull --reset
398
404
  ```
399
405
 
400
406
  > **Note:** `npx leadcms fetch` is still supported as an alias for backward compatibility.
@@ -402,11 +408,17 @@ npx leadcms pull-comments
402
408
  What each command does:
403
409
 
404
410
  - `npx leadcms pull` - Syncs content, media and comments into your project using the configured directories. Updates incremental sync tokens so subsequent runs are faster.
411
+ - `npx leadcms pull --reset` - Deletes all local content, media, comments, and sync tokens, then performs a full pull from scratch. Useful when local state has become inconsistent or after configuration changes.
405
412
  - `npx leadcms pull-content` - Downloads only content entities (MDX/JSON files) and updates local metadata.
406
413
  - `npx leadcms pull-media` - Downloads media files to your `mediaDir` (e.g., `public/media`). Use this when you changed media or want to refresh assets separately from content.
407
414
  - `npx leadcms pull-comments` - Downloads comments to the comments directory (e.g., `.leadcms/comments/`). Useful when you only need comment updates.
408
415
 
409
- > **Note:** The CLI uses incremental sync tokens to avoid re-downloading unchanged items where supported by the LeadCMS API.
416
+ **Intelligent sync handling:**
417
+
418
+ - **Incremental sync** — Sync tokens avoid re-downloading unchanged items on subsequent pulls.
419
+ - **Rename & type-change cleanup** — When content is renamed (slug change), moved to a different type, or switched format (MDX ↔ JSON), the old file is automatically removed before the new version is written.
420
+ - **Deleted content removal** — Content and media deleted on the server are removed locally during the next pull.
421
+ - **Sync token migration** — When upgrading from SDK ≤ 3.1, legacy sync tokens are automatically migrated to their new location inside each data directory.
410
422
 
411
423
  ### Push local content to LeadCMS
412
424
 
@@ -2,5 +2,5 @@
2
2
  /**
3
3
  * LeadCMS Generate Env CLI Entry Point
4
4
  */
5
- import '../../scripts/generate-env-js.js';
5
+ export {};
6
6
  //# sourceMappingURL=generate-env.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-env.d.ts","sourceRoot":"","sources":["../../../src/cli/bin/generate-env.ts"],"names":[],"mappings":";AACA;;GAEG;AAGH,OAAO,kCAAkC,CAAC"}
1
+ {"version":3,"file":"generate-env.d.ts","sourceRoot":"","sources":["../../../src/cli/bin/generate-env.ts"],"names":[],"mappings":";AACA;;GAEG"}
@@ -2,6 +2,6 @@
2
2
  /**
3
3
  * LeadCMS Generate Env CLI Entry Point
4
4
  */
5
- // Import and run the generate-env script directly
6
- import '../../scripts/generate-env-js.js';
5
+ import { generateEnv } from '../../scripts/generate-env-js.js';
6
+ generateEnv();
7
7
  //# sourceMappingURL=generate-env.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-env.js","sourceRoot":"","sources":["../../../src/cli/bin/generate-env.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,kDAAkD;AAClD,OAAO,kCAAkC,CAAC"}
1
+ {"version":3,"file":"generate-env.js","sourceRoot":"","sources":["../../../src/cli/bin/generate-env.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAE/D,WAAW,EAAE,CAAC"}
@@ -3,7 +3,9 @@
3
3
  * LeadCMS Pull Comments CLI Entry Point
4
4
  */
5
5
  import { pullComments } from '../../scripts/pull-comments.js';
6
- pullComments().catch((error) => {
6
+ const args = process.argv.slice(2);
7
+ const reset = args.includes('--reset');
8
+ pullComments({ reset }).catch((error) => {
7
9
  console.error('Error running LeadCMS pull comments:', error.message);
8
10
  process.exit(1);
9
11
  });
@@ -1 +1 @@
1
- {"version":3,"file":"pull-comments.js","sourceRoot":"","sources":["../../../src/cli/bin/pull-comments.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAE9D,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;IAClC,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"pull-comments.js","sourceRoot":"","sources":["../../../src/cli/bin/pull-comments.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAE9D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEvC,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;IAC3C,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -15,7 +15,8 @@ const slugIndex = args.findIndex(arg => arg === '--slug');
15
15
  if (slugIndex !== -1 && args[slugIndex + 1]) {
16
16
  targetSlug = args[slugIndex + 1];
17
17
  }
18
- pullContent({ targetId, targetSlug }).catch((error) => {
18
+ const reset = args.includes('--reset');
19
+ pullContent({ targetId, targetSlug, reset }).catch((error) => {
19
20
  console.error('Error running LeadCMS pull content:', error.message);
20
21
  process.exit(1);
21
22
  });
@@ -1 +1 @@
1
- {"version":3,"file":"pull-content.js","sourceRoot":"","sources":["../../../src/cli/bin/pull-content.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,0BAA0B;AAC1B,IAAI,QAA4B,CAAC;AACjC,IAAI,UAA8B,CAAC;AAEnC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AACtD,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC;IACxC,QAAQ,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC;AAC1D,IAAI,SAAS,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC;IAC5C,UAAU,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,WAAW,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;IACzD,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"pull-content.js","sourceRoot":"","sources":["../../../src/cli/bin/pull-content.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,0BAA0B;AAC1B,IAAI,QAA4B,CAAC;AACjC,IAAI,UAA8B,CAAC;AAEnC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AACtD,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC;IACxC,QAAQ,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC;AAC1D,IAAI,SAAS,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC;IAC5C,UAAU,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEvC,WAAW,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;IAChE,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -3,7 +3,9 @@
3
3
  * LeadCMS Pull Media CLI Entry Point
4
4
  */
5
5
  import { pullMedia } from '../../scripts/pull-media.js';
6
- pullMedia().catch((error) => {
6
+ const args = process.argv.slice(2);
7
+ const reset = args.includes('--reset');
8
+ pullMedia({ reset }).catch((error) => {
7
9
  console.error('Error running LeadCMS pull media:', error.message);
8
10
  process.exit(1);
9
11
  });
@@ -1 +1 @@
1
- {"version":3,"file":"pull-media.js","sourceRoot":"","sources":["../../../src/cli/bin/pull-media.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;IAC/B,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"pull-media.js","sourceRoot":"","sources":["../../../src/cli/bin/pull-media.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEvC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;IACxC,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/cli/index.js CHANGED
@@ -69,10 +69,10 @@ switch (command) {
69
69
  runScript('pull-content.js', commandArgs);
70
70
  break;
71
71
  case 'pull-media':
72
- runScript('pull-media.js');
72
+ runScript('pull-media.js', commandArgs);
73
73
  break;
74
74
  case 'pull-comments':
75
- runScript('pull-comments.js');
75
+ runScript('pull-comments.js', commandArgs);
76
76
  break;
77
77
  case 'push':
78
78
  runScript('push-all.js', commandArgs);
@@ -127,8 +127,11 @@ Usage:
127
127
  leadcms pull-content [options] - Pull only content from LeadCMS
128
128
  --id <content-id> - Pull specific content by ID
129
129
  --slug <slug> - Pull specific content by slug
130
- leadcms pull-media - Pull only media files from LeadCMS
131
- leadcms pull-comments - Pull only comments from LeadCMS
130
+ --reset - Delete local content files and sync token, then pull fresh
131
+ leadcms pull-media [options] - Pull only media files from LeadCMS
132
+ --reset - Delete local media files and sync token, then pull fresh
133
+ leadcms pull-comments [options] - Pull only comments from LeadCMS
134
+ --reset - Delete local comment files and sync token, then pull fresh
132
135
  leadcms fetch - Alias for 'pull' (backward compatibility)
133
136
 
134
137
  Push commands:
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAChC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE1C,SAAS,SAAS,CAAC,UAAkB,EAAE,OAAiB,EAAE;IACxD,6DAA6D;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE;QAC9C,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAiB,EAAE,OAAiB,EAAE;IAC/D,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,SAAS,OAAO;QACd,IAAI,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE;YAC9C,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,YAAY,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;QACnE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QACtE,OAAO,WAAW,CAAC,OAAO,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,QAAQ,OAAO,EAAE,CAAC;IAChB,KAAK,SAAS,CAAC;IACf,KAAK,IAAI,CAAC;IACV,KAAK,WAAW;QACd,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,MAAM;IACR,KAAK,MAAM,CAAC;IACZ,KAAK,OAAO,EAAE,mCAAmC;QAC/C,SAAS,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QACtC,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,MAAM;IACR,KAAK,YAAY;QACf,SAAS,CAAC,eAAe,CAAC,CAAC;QAC3B,MAAM;IACR,KAAK,eAAe;QAClB,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC9B,MAAM;IACR,KAAK,MAAM;QACT,SAAS,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QACtC,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,MAAM;IACR,KAAK,YAAY;QACf,SAAS,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM;IACR,KAAK,QAAQ;QACX,SAAS,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM;IACR,KAAK,gBAAgB;QACnB,SAAS,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;QAC5C,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,MAAM;IACR,KAAK,OAAO;QACV,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC7B,MAAM;IACR,KAAK,MAAM,CAAC;IACZ,KAAK,QAAQ;QACX,SAAS,CAAC,SAAS,CAAC,CAAC;QACrB,MAAM;IACR,KAAK,OAAO;QACV,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,MAAM;IACR,KAAK,QAAQ,CAAC;IACd,KAAK,WAAW;QACd,uBAAuB,EAAE,CAAC;QAC1B,MAAM;IACR;QACE,OAAO,CAAC,GAAG,CAAC;mBACG,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+E9B,CAAC,CAAC;QACC,MAAM;AACV,CAAC;AAED,SAAS,uBAAuB;IAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE;QACpE,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAE/D,sCAAsC;QACtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;YAC3F,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAE5D,IAAI,CAAC;YACH,qBAAqB;YACrB,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;gBACjB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;oBACvC,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,GAAG,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,wBAAwB;YACxB,MAAM,eAAe,GAAG;gBACtB,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,YAAY,EAAE;gBAChD,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,YAAY,EAAE;gBAChD,EAAE,GAAG,EAAE,+BAA+B,EAAE,IAAI,EAAE,+BAA+B,EAAE;aAChF,CAAC;YAEF,qBAAqB;YACrB,MAAM,YAAY,GAAG;gBACnB,EAAE,GAAG,EAAE,2BAA2B,EAAE,IAAI,EAAE,oBAAoB,EAAE;gBAChE,EAAE,GAAG,EAAE,2BAA2B,EAAE,IAAI,EAAE,oBAAoB,EAAE;gBAChE,EAAE,GAAG,EAAE,iCAAiC,EAAE,IAAI,EAAE,0BAA0B,EAAE;aAC7E,CAAC;YAEF,CAAC,GAAG,eAAe,EAAE,GAAG,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE;gBAC9D,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;gBAClD,MAAM,QAAQ,GAAG,IAAI,CAAC;gBAEtB,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAClD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;oBAE7C,gCAAgC;oBAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;wBACzB,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;oBAChC,CAAC;oBAED,OAAO,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;gBACvC,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CAAC,2BAA2B,OAAO,EAAE,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,8EAA8E,CAAC,CAAC;YAC5F,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;YAClF,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;YAC7E,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;QAEhF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAChC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE1C,SAAS,SAAS,CAAC,UAAkB,EAAE,OAAiB,EAAE;IACxD,6DAA6D;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE;QAC9C,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAiB,EAAE,OAAiB,EAAE;IAC/D,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,SAAS,OAAO;QACd,IAAI,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE;YAC9C,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,YAAY,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;QACnE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QACtE,OAAO,WAAW,CAAC,OAAO,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,QAAQ,OAAO,EAAE,CAAC;IAChB,KAAK,SAAS,CAAC;IACf,KAAK,IAAI,CAAC;IACV,KAAK,WAAW;QACd,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,MAAM;IACR,KAAK,MAAM,CAAC;IACZ,KAAK,OAAO,EAAE,mCAAmC;QAC/C,SAAS,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QACtC,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,MAAM;IACR,KAAK,YAAY;QACf,SAAS,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM;IACR,KAAK,eAAe;QAClB,SAAS,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;QAC3C,MAAM;IACR,KAAK,MAAM;QACT,SAAS,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QACtC,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,MAAM;IACR,KAAK,YAAY;QACf,SAAS,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM;IACR,KAAK,QAAQ;QACX,SAAS,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM;IACR,KAAK,gBAAgB;QACnB,SAAS,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;QAC5C,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,MAAM;IACR,KAAK,OAAO;QACV,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,MAAM;IACR,KAAK,cAAc;QACjB,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC7B,MAAM;IACR,KAAK,MAAM,CAAC;IACZ,KAAK,QAAQ;QACX,SAAS,CAAC,SAAS,CAAC,CAAC;QACrB,MAAM;IACR,KAAK,OAAO;QACV,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,MAAM;IACR,KAAK,QAAQ,CAAC;IACd,KAAK,WAAW;QACd,uBAAuB,EAAE,CAAC;QAC1B,MAAM;IACR;QACE,OAAO,CAAC,GAAG,CAAC;mBACG,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkF9B,CAAC,CAAC;QACC,MAAM;AACV,CAAC;AAED,SAAS,uBAAuB;IAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE;QACpE,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAE/D,sCAAsC;QACtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;YAC3F,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAE5D,IAAI,CAAC;YACH,qBAAqB;YACrB,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;gBACjB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;oBACvC,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,GAAG,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,wBAAwB;YACxB,MAAM,eAAe,GAAG;gBACtB,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,YAAY,EAAE;gBAChD,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,YAAY,EAAE;gBAChD,EAAE,GAAG,EAAE,+BAA+B,EAAE,IAAI,EAAE,+BAA+B,EAAE;aAChF,CAAC;YAEF,qBAAqB;YACrB,MAAM,YAAY,GAAG;gBACnB,EAAE,GAAG,EAAE,2BAA2B,EAAE,IAAI,EAAE,oBAAoB,EAAE;gBAChE,EAAE,GAAG,EAAE,2BAA2B,EAAE,IAAI,EAAE,oBAAoB,EAAE;gBAChE,EAAE,GAAG,EAAE,iCAAiC,EAAE,IAAI,EAAE,0BAA0B,EAAE;aAC7E,CAAC;YAEF,CAAC,GAAG,eAAe,EAAE,GAAG,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE;gBAC9D,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;gBAClD,MAAM,QAAQ,GAAG,IAAI,CAAC;gBAEtB,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAClD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;oBAE7C,gCAAgC;oBAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;wBACzB,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;oBAChC,CAAC;oBAED,OAAO,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;gBACvC,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CAAC,2BAA2B,OAAO,EAAE,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,8EAA8E,CAAC,CAAC;YAC5F,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;YAClF,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;YAC7E,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;QAEhF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/index.d.ts CHANGED
@@ -3,5 +3,7 @@ export * from './lib/config.js';
3
3
  export * from './lib/locale-utils.js';
4
4
  export * from './lib/comment-types.js';
5
5
  export * from './lib/cms-config-types.js';
6
+ export { threeWayMerge, threeWayMergeJson, isLocallyModified } from './lib/content-merge.js';
7
+ export type { MergeResult } from './lib/content-merge.js';
6
8
  export type { CommentTreeNode, CommentTreeOptions, CommentStatistics, CommentSortOrder } from './lib/comment-utils.js';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAG1C,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAG1C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC7F,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -4,6 +4,8 @@ export * from './lib/config.js';
4
4
  export * from './lib/locale-utils.js';
5
5
  export * from './lib/comment-types.js';
6
6
  export * from './lib/cms-config-types.js';
7
+ // Content merge utilities for three-way merge support
8
+ export { threeWayMerge, threeWayMergeJson, isLocallyModified } from './lib/content-merge.js';
7
9
  // LeadCMS SDK - Framework-agnostic content management
8
10
  //
9
11
  // Core functions for accessing LeadCMS content:
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAK1C,sDAAsD;AACtD,EAAE;AACF,gDAAgD;AAChD,yDAAyD;AACzD,0DAA0D;AAC1D,wEAAwE;AACxE,iEAAiE;AACjE,sDAAsD;AACtD,EAAE;AACF,gBAAgB;AAChB,4DAA4D;AAC5D,uEAAuE;AACvE,kEAAkE;AAClE,wFAAwF;AACxF,iGAAiG;AACjG,sFAAsF;AACtF,EAAE;AACF,6FAA6F;AAC7F,4FAA4F;AAC5F,2DAA2D;AAC3D,EAAE;AACF,oBAAoB;AACpB,0DAA0D;AAC1D,EAAE;AACF,yBAAyB;AACzB,4CAA4C;AAC5C,sCAAsC;AACtC,kDAAkD;AAClD,EAAE;AACF,iBAAiB;AACjB,qFAAqF;AACrF,oFAAoF;AACpF,mEAAmE;AACnE,gEAAgE;AAChE,oEAAoE;AACpE,wDAAwD;AACxD,yDAAyD;AACzD,EAAE;AACF,mFAAmF;AACnF,qFAAqF"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAE1C,sDAAsD;AACtD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAM7F,sDAAsD;AACtD,EAAE;AACF,gDAAgD;AAChD,yDAAyD;AACzD,0DAA0D;AAC1D,wEAAwE;AACxE,iEAAiE;AACjE,sDAAsD;AACtD,EAAE;AACF,gBAAgB;AAChB,4DAA4D;AAC5D,uEAAuE;AACvE,kEAAkE;AAClE,wFAAwF;AACxF,iGAAiG;AACjG,sFAAsF;AACtF,EAAE;AACF,6FAA6F;AAC7F,4FAA4F;AAC5F,2DAA2D;AAC3D,EAAE;AACF,oBAAoB;AACpB,0DAA0D;AAC1D,EAAE;AACF,yBAAyB;AACzB,4CAA4C;AAC5C,sCAAsC;AACtC,kDAAkD;AAClD,EAAE;AACF,iBAAiB;AACjB,qFAAqF;AACrF,oFAAoF;AACpF,mEAAmE;AACnE,gEAAgE;AAChE,oEAAoE;AACpE,wDAAwD;AACxD,yDAAyD;AACzD,EAAE;AACF,mFAAmF;AACnF,qFAAqF"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Three-way merge utilities for LeadCMS content
3
+ *
4
+ * Uses the node-diff3 library to perform git-style three-way merges between
5
+ * a base version, a local version, and a remote version of content files.
6
+ *
7
+ * For JSON content, a structural (field-level) merge is used instead of
8
+ * line-based diff to avoid false conflicts from adjacent line changes.
9
+ *
10
+ * The base version comes from the server via the sync API (the state of the
11
+ * content at the time of the client's last sync token). This avoids needing
12
+ * any local storage of base snapshots.
13
+ */
14
+ /**
15
+ * Result of a three-way content merge
16
+ */
17
+ export interface MergeResult {
18
+ /** Whether the merge completed without conflicts */
19
+ success: boolean;
20
+ /** The merged content (may contain conflict markers if success is false) */
21
+ merged: string;
22
+ /** Whether there were conflicts that require manual resolution */
23
+ hasConflicts: boolean;
24
+ /** Number of conflict regions found */
25
+ conflictCount: number;
26
+ }
27
+ /**
28
+ * Perform a three-way merge between base, local, and remote content.
29
+ *
30
+ * This works like git merge:
31
+ * - Changes that don't overlap are merged automatically
32
+ * - Changes that modify the same lines produce conflict markers
33
+ * - Server-controlled fields (updatedAt, createdAt) in YAML frontmatter
34
+ * are auto-resolved to the remote value, never producing conflicts
35
+ *
36
+ * For JSON content, prefer threeWayMergeJson() which does structural merging
37
+ * and avoids false conflicts from adjacent line changes.
38
+ *
39
+ * @param base - The original content at the time of last sync (from server's baseItems)
40
+ * @param local - The current local file content (possibly user-modified)
41
+ * @param remote - The current remote content (fetched from server)
42
+ * @returns MergeResult with merged content and conflict information
43
+ */
44
+ export declare function threeWayMerge(base: string, local: string, remote: string): MergeResult;
45
+ /**
46
+ * Perform a structural three-way merge on JSON content.
47
+ *
48
+ * Instead of doing a line-based diff (which produces false conflicts for
49
+ * adjacent field changes), this parses the JSON and merges field-by-field:
50
+ *
51
+ * - Fields changed only locally → keep local value
52
+ * - Fields changed only remotely → take remote value
53
+ * - Fields changed identically on both sides → take either (same value)
54
+ * - Fields changed differently on both sides → conflict
55
+ * - Server-controlled fields (updatedAt, createdAt) → always take remote
56
+ *
57
+ * For nested objects, the merge recurses into each level.
58
+ *
59
+ * @param base - The base JSON content (from server's baseItems, transformed to local format)
60
+ * @param local - The current local JSON file content
61
+ * @param remote - The current remote JSON content (transformed to local format)
62
+ * @returns MergeResult with the merged JSON string
63
+ */
64
+ export declare function threeWayMergeJson(base: string, local: string, remote: string): MergeResult;
65
+ /**
66
+ * Determine whether a local file has been modified compared to the base version.
67
+ *
68
+ * This is used to decide whether three-way merge is needed:
69
+ * - If local === base → local is unmodified, safe to overwrite with remote
70
+ * - If local !== base → local was modified, need three-way merge
71
+ *
72
+ * Uses timestamp normalization to avoid false positives from precision differences
73
+ * (e.g. server returns 7 decimal places but local file has 6).
74
+ *
75
+ * @param base - The base content (from server's baseItems, transformed to local format)
76
+ * @param local - The current local file content
77
+ * @returns true if local content differs from base
78
+ */
79
+ export declare function isLocallyModified(base: string, local: string): boolean;
80
+ //# sourceMappingURL=content-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-merge.d.ts","sourceRoot":"","sources":["../../src/lib/content-merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,YAAY,EAAE,OAAO,CAAC;IACtB,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CA4CtF;AAsED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAwB1F;AAiJD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtE"}
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Three-way merge utilities for LeadCMS content
3
+ *
4
+ * Uses the node-diff3 library to perform git-style three-way merges between
5
+ * a base version, a local version, and a remote version of content files.
6
+ *
7
+ * For JSON content, a structural (field-level) merge is used instead of
8
+ * line-based diff to avoid false conflicts from adjacent line changes.
9
+ *
10
+ * The base version comes from the server via the sync API (the state of the
11
+ * content at the time of the client's last sync token). This avoids needing
12
+ * any local storage of base snapshots.
13
+ */
14
+ import { diff3Merge } from 'node-diff3';
15
+ /**
16
+ * Fields that are controlled by the server and should always take the remote
17
+ * value during merge, even if they differ between base and local.
18
+ * These fields are set/updated by the server automatically and should never
19
+ * be treated as meaningful local edits.
20
+ */
21
+ const SERVER_CONTROLLED_FIELDS = new Set([
22
+ 'updatedAt',
23
+ 'createdAt',
24
+ ]);
25
+ /**
26
+ * Regex to match a YAML frontmatter line for a server-controlled field.
27
+ * Matches lines like:
28
+ * updatedAt: "2026-02-01T00:00:00Z"
29
+ * createdAt: "2026-01-01T00:00:00Z"
30
+ * updatedAt: 2026-02-01T00:00:00Z
31
+ */
32
+ const SERVER_CONTROLLED_YAML_LINE = /^\s*(updatedAt|createdAt)\s*:/;
33
+ /**
34
+ * Perform a three-way merge between base, local, and remote content.
35
+ *
36
+ * This works like git merge:
37
+ * - Changes that don't overlap are merged automatically
38
+ * - Changes that modify the same lines produce conflict markers
39
+ * - Server-controlled fields (updatedAt, createdAt) in YAML frontmatter
40
+ * are auto-resolved to the remote value, never producing conflicts
41
+ *
42
+ * For JSON content, prefer threeWayMergeJson() which does structural merging
43
+ * and avoids false conflicts from adjacent line changes.
44
+ *
45
+ * @param base - The original content at the time of last sync (from server's baseItems)
46
+ * @param local - The current local file content (possibly user-modified)
47
+ * @param remote - The current remote content (fetched from server)
48
+ * @returns MergeResult with merged content and conflict information
49
+ */
50
+ export function threeWayMerge(base, local, remote) {
51
+ const baseLines = base.split('\n');
52
+ const localLines = local.split('\n');
53
+ const remoteLines = remote.split('\n');
54
+ const regions = diff3Merge(localLines, baseLines, remoteLines);
55
+ let conflictCount = 0;
56
+ const resultLines = [];
57
+ for (const region of regions) {
58
+ if ('ok' in region && region.ok) {
59
+ resultLines.push(...region.ok);
60
+ }
61
+ else if ('conflict' in region && region.conflict) {
62
+ const localConflictLines = region.conflict.a;
63
+ const remoteConflictLines = region.conflict.b;
64
+ // Try to auto-resolve server-controlled fields within the conflict
65
+ const resolved = resolveServerControlledConflict(localConflictLines, remoteConflictLines);
66
+ if (resolved.remainingConflict) {
67
+ // There are still real conflicts after extracting server-controlled fields
68
+ conflictCount++;
69
+ resultLines.push(...resolved.resolvedLines);
70
+ resultLines.push('<<<<<<< local');
71
+ resultLines.push(...resolved.remainingConflict.local);
72
+ resultLines.push('=======');
73
+ resultLines.push(...resolved.remainingConflict.remote);
74
+ resultLines.push('>>>>>>> remote');
75
+ }
76
+ else {
77
+ // All lines in this conflict were server-controlled → fully auto-resolved
78
+ resultLines.push(...resolved.resolvedLines);
79
+ }
80
+ }
81
+ }
82
+ const merged = resultLines.join('\n');
83
+ return {
84
+ success: conflictCount === 0,
85
+ merged,
86
+ hasConflicts: conflictCount > 0,
87
+ conflictCount,
88
+ };
89
+ }
90
+ /**
91
+ * Attempt to auto-resolve server-controlled fields within a conflict region.
92
+ *
93
+ * For each line in the conflict, if it's a server-controlled YAML field
94
+ * (updatedAt, createdAt), take the remote version. Non-server-controlled
95
+ * lines remain as conflicts.
96
+ *
97
+ * Returns:
98
+ * - resolvedLines: lines that were auto-resolved (server-controlled)
99
+ * - remainingConflict: null if fully resolved, or { local, remote } with
100
+ * the non-server-controlled lines that still conflict
101
+ */
102
+ function resolveServerControlledConflict(localLines, remoteLines) {
103
+ const resolvedLines = [];
104
+ const remainingLocal = [];
105
+ const remainingRemote = [];
106
+ // Separate server-controlled from non-server-controlled lines on each side
107
+ const localServerControlled = [];
108
+ const localOther = [];
109
+ for (const line of localLines) {
110
+ if (SERVER_CONTROLLED_YAML_LINE.test(line)) {
111
+ localServerControlled.push(line);
112
+ }
113
+ else {
114
+ localOther.push(line);
115
+ }
116
+ }
117
+ const remoteServerControlled = [];
118
+ const remoteOther = [];
119
+ for (const line of remoteLines) {
120
+ if (SERVER_CONTROLLED_YAML_LINE.test(line)) {
121
+ remoteServerControlled.push(line);
122
+ }
123
+ else {
124
+ remoteOther.push(line);
125
+ }
126
+ }
127
+ // Auto-resolve server-controlled fields: always take remote version
128
+ resolvedLines.push(...remoteServerControlled);
129
+ // Check if there are remaining non-server-controlled lines
130
+ if (localOther.length === 0 && remoteOther.length === 0) {
131
+ // Entire conflict was server-controlled → fully resolved
132
+ return { resolvedLines, remainingConflict: null };
133
+ }
134
+ // There are real conflicting lines remaining
135
+ return {
136
+ resolvedLines,
137
+ remainingConflict: { local: localOther, remote: remoteOther },
138
+ };
139
+ }
140
+ /**
141
+ * Perform a structural three-way merge on JSON content.
142
+ *
143
+ * Instead of doing a line-based diff (which produces false conflicts for
144
+ * adjacent field changes), this parses the JSON and merges field-by-field:
145
+ *
146
+ * - Fields changed only locally → keep local value
147
+ * - Fields changed only remotely → take remote value
148
+ * - Fields changed identically on both sides → take either (same value)
149
+ * - Fields changed differently on both sides → conflict
150
+ * - Server-controlled fields (updatedAt, createdAt) → always take remote
151
+ *
152
+ * For nested objects, the merge recurses into each level.
153
+ *
154
+ * @param base - The base JSON content (from server's baseItems, transformed to local format)
155
+ * @param local - The current local JSON file content
156
+ * @param remote - The current remote JSON content (transformed to local format)
157
+ * @returns MergeResult with the merged JSON string
158
+ */
159
+ export function threeWayMergeJson(base, local, remote) {
160
+ let baseObj;
161
+ let localObj;
162
+ let remoteObj;
163
+ try {
164
+ baseObj = JSON.parse(base);
165
+ localObj = JSON.parse(local);
166
+ remoteObj = JSON.parse(remote);
167
+ }
168
+ catch {
169
+ // If any version is not valid JSON, fall back to line-based merge
170
+ return threeWayMerge(base, local, remote);
171
+ }
172
+ const { value: mergedObj, conflicted, conflictCount } = mergeValues(baseObj, localObj, remoteObj);
173
+ const merged = JSON.stringify(mergedObj, null, 2);
174
+ return {
175
+ success: !conflicted,
176
+ merged,
177
+ hasConflicts: conflicted,
178
+ conflictCount,
179
+ };
180
+ }
181
+ /**
182
+ * Recursively merge three values (base, local, remote).
183
+ * Returns the merged value and whether any conflicts were found.
184
+ */
185
+ function mergeValues(base, local, remote) {
186
+ // If both local and remote are objects (not arrays), merge field by field
187
+ if (isPlainObject(base) && isPlainObject(local) && isPlainObject(remote)) {
188
+ return mergeObjects(base, local, remote);
189
+ }
190
+ // For non-object values (primitives, arrays, etc.): compare as JSON strings
191
+ const baseStr = JSON.stringify(base);
192
+ const localStr = JSON.stringify(local);
193
+ const remoteStr = JSON.stringify(remote);
194
+ if (baseStr === localStr && baseStr === remoteStr) {
195
+ // No changes
196
+ return { value: local, conflicted: false, conflictCount: 0 };
197
+ }
198
+ if (baseStr === localStr) {
199
+ // Only remote changed → take remote
200
+ return { value: remote, conflicted: false, conflictCount: 0 };
201
+ }
202
+ if (baseStr === remoteStr) {
203
+ // Only local changed → keep local
204
+ return { value: local, conflicted: false, conflictCount: 0 };
205
+ }
206
+ if (localStr === remoteStr) {
207
+ // Both changed identically → take either
208
+ return { value: local, conflicted: false, conflictCount: 0 };
209
+ }
210
+ // Both changed differently → conflict
211
+ // Use a special marker object that will be serialized with conflict info
212
+ return {
213
+ value: {
214
+ '<<<<<<< local': local,
215
+ '=======': '---',
216
+ '>>>>>>> remote': remote,
217
+ },
218
+ conflicted: true,
219
+ conflictCount: 1,
220
+ };
221
+ }
222
+ /**
223
+ * Merge three plain objects field by field.
224
+ */
225
+ function mergeObjects(base, local, remote) {
226
+ const allKeys = new Set([
227
+ ...Object.keys(base),
228
+ ...Object.keys(local),
229
+ ...Object.keys(remote),
230
+ ]);
231
+ const merged = {};
232
+ let hasConflict = false;
233
+ let totalConflicts = 0;
234
+ for (const key of allKeys) {
235
+ const inBase = key in base;
236
+ const inLocal = key in local;
237
+ const inRemote = key in remote;
238
+ // Server-controlled fields: always take remote value
239
+ if (SERVER_CONTROLLED_FIELDS.has(key)) {
240
+ if (inRemote) {
241
+ merged[key] = remote[key];
242
+ }
243
+ else if (inLocal) {
244
+ merged[key] = local[key];
245
+ }
246
+ // If only in base, it was deleted from both → omit
247
+ continue;
248
+ }
249
+ if (inBase && inLocal && inRemote) {
250
+ // Key exists in all three — merge the values
251
+ const result = mergeValues(base[key], local[key], remote[key]);
252
+ merged[key] = result.value;
253
+ if (result.conflicted) {
254
+ hasConflict = true;
255
+ totalConflicts += result.conflictCount;
256
+ }
257
+ }
258
+ else if (!inBase && inLocal && inRemote) {
259
+ // Key added by both sides
260
+ const result = mergeValues(undefined, local[key], remote[key]);
261
+ merged[key] = result.value;
262
+ if (result.conflicted) {
263
+ hasConflict = true;
264
+ totalConflicts += result.conflictCount;
265
+ }
266
+ }
267
+ else if (!inBase && inLocal && !inRemote) {
268
+ // Key added only locally → keep
269
+ merged[key] = local[key];
270
+ }
271
+ else if (!inBase && !inLocal && inRemote) {
272
+ // Key added only remotely → take
273
+ merged[key] = remote[key];
274
+ }
275
+ else if (inBase && !inLocal && inRemote) {
276
+ // Key deleted locally — check if remote also changed it
277
+ const baseStr = JSON.stringify(base[key]);
278
+ const remoteStr = JSON.stringify(remote[key]);
279
+ if (baseStr === remoteStr) {
280
+ // Remote didn't change it, local deleted it → keep deleted (omit)
281
+ }
282
+ else {
283
+ // Remote changed it but local deleted it → conflict, prefer remote
284
+ merged[key] = remote[key];
285
+ hasConflict = true;
286
+ totalConflicts++;
287
+ }
288
+ }
289
+ else if (inBase && inLocal && !inRemote) {
290
+ // Key deleted remotely — check if local also changed it
291
+ const baseStr = JSON.stringify(base[key]);
292
+ const localStr = JSON.stringify(local[key]);
293
+ if (baseStr === localStr) {
294
+ // Local didn't change it, remote deleted it → keep deleted (omit)
295
+ }
296
+ else {
297
+ // Local changed it but remote deleted it → conflict, prefer local
298
+ merged[key] = local[key];
299
+ hasConflict = true;
300
+ totalConflicts++;
301
+ }
302
+ }
303
+ else if (inBase && !inLocal && !inRemote) {
304
+ // Deleted by both sides → omit
305
+ }
306
+ }
307
+ return { value: merged, conflicted: hasConflict, conflictCount: totalConflicts };
308
+ }
309
+ /**
310
+ * Check if a value is a plain object (not array, null, Date, etc.)
311
+ */
312
+ function isPlainObject(value) {
313
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
314
+ }
315
+ /**
316
+ * Determine whether a local file has been modified compared to the base version.
317
+ *
318
+ * This is used to decide whether three-way merge is needed:
319
+ * - If local === base → local is unmodified, safe to overwrite with remote
320
+ * - If local !== base → local was modified, need three-way merge
321
+ *
322
+ * Uses timestamp normalization to avoid false positives from precision differences
323
+ * (e.g. server returns 7 decimal places but local file has 6).
324
+ *
325
+ * @param base - The base content (from server's baseItems, transformed to local format)
326
+ * @param local - The current local file content
327
+ * @returns true if local content differs from base
328
+ */
329
+ export function isLocallyModified(base, local) {
330
+ return normalizeForMergeComparison(base) !== normalizeForMergeComparison(local);
331
+ }
332
+ /**
333
+ * Normalize content for merge comparison.
334
+ * Handles trivial whitespace and timestamp precision differences that shouldn't
335
+ * trigger a merge.
336
+ */
337
+ function normalizeForMergeComparison(content) {
338
+ return content
339
+ .replace(/\r\n/g, '\n')
340
+ .replace(/\s+\n/g, '\n')
341
+ // Normalize ISO timestamp precision: truncate fractional seconds to 6 decimal
342
+ // places (microsecond precision) then strip trailing zeros.
343
+ // e.g. "2026-02-13T10:32:20.2939836Z" → "2026-02-13T10:32:20.293983Z"
344
+ // This prevents false diffs from servers returning 7-digit precision while
345
+ // local serializers use 6-digit precision.
346
+ .replace(/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{1,6})\d*Z/g, '$1Z')
347
+ .replace(/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+?)0+Z/g, '$1Z')
348
+ .trimEnd();
349
+ }
350
+ //# sourceMappingURL=content-merge.js.map