canopycms 0.0.16 → 0.0.18

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 (219) hide show
  1. package/README.md +120 -34
  2. package/dist/ai/generate.js +3 -3
  3. package/dist/ai/handler.js +5 -5
  4. package/dist/ai/index.js +3 -3
  5. package/dist/ai/json-to-markdown.js +1 -1
  6. package/dist/ai/json-to-markdown.js.map +1 -1
  7. package/dist/ai/resolve-branch.js +2 -2
  8. package/dist/api/__test__/mock-client.js +1 -1
  9. package/dist/api/assets.js +1 -1
  10. package/dist/api/branch-merge.js +3 -3
  11. package/dist/api/branch-review.js +4 -4
  12. package/dist/api/branch-status.js +8 -8
  13. package/dist/api/branch-withdraw.js +5 -5
  14. package/dist/api/branch.js +9 -9
  15. package/dist/api/comments.js +4 -4
  16. package/dist/api/content.d.ts.map +1 -1
  17. package/dist/api/content.js +17 -16
  18. package/dist/api/content.js.map +1 -1
  19. package/dist/api/entries.js +8 -8
  20. package/dist/api/github-sync.js +3 -3
  21. package/dist/api/groups.js +4 -4
  22. package/dist/api/guards.js +1 -1
  23. package/dist/api/index.js +3 -3
  24. package/dist/api/permissions.js +4 -4
  25. package/dist/api/reference-options.js +5 -5
  26. package/dist/api/resolve-references.js +4 -4
  27. package/dist/api/route-builder.js +1 -1
  28. package/dist/api/schema.js +5 -5
  29. package/dist/api/settings-helpers.js +1 -1
  30. package/dist/api/user.js +1 -1
  31. package/dist/api/validators.js +3 -3
  32. package/dist/asset-store.js +1 -1
  33. package/dist/auth/cache.js +2 -2
  34. package/dist/auth/caching-auth-plugin.js +1 -1
  35. package/dist/auth/file-based-auth-cache.js +1 -1
  36. package/dist/auth/index.js +1 -1
  37. package/dist/authorization/branch.js +1 -1
  38. package/dist/authorization/content.js +3 -3
  39. package/dist/authorization/groups/index.js +2 -2
  40. package/dist/authorization/groups/loader.js +4 -4
  41. package/dist/authorization/index.js +8 -8
  42. package/dist/authorization/path.js +1 -1
  43. package/dist/authorization/permissions/index.js +2 -2
  44. package/dist/authorization/permissions/loader.js +3 -3
  45. package/dist/authorization/permissions/schema.js +1 -1
  46. package/dist/authorization/test-utils.js +1 -1
  47. package/dist/authorization/validation.js +1 -1
  48. package/dist/branch-metadata.js +3 -3
  49. package/dist/branch-registry.js +2 -2
  50. package/dist/branch-schema-cache.js +2 -2
  51. package/dist/branch-workspace.js +6 -6
  52. package/dist/build/generate-ai-content.js +4 -4
  53. package/dist/build/index.js +1 -1
  54. package/dist/cli/cli.js +5 -5
  55. package/dist/cli/generate-ai-content.js +40 -29
  56. package/dist/cli/init.d.ts +5 -0
  57. package/dist/cli/init.d.ts.map +1 -1
  58. package/dist/cli/init.js +68 -25
  59. package/dist/cli/init.js.map +1 -1
  60. package/dist/cli/sync.js +1 -1
  61. package/dist/cli/template-files/canopy.ts.template +10 -6
  62. package/dist/cli/template-files/edit-page-dev.tsx.template +16 -0
  63. package/dist/cli/template-files/edit-page.tsx.template +14 -21
  64. package/dist/cli/template-files/middleware-clerk.ts.template +13 -0
  65. package/dist/cli/template-files/middleware.ts.template +30 -0
  66. package/dist/cli/template-files/next.config-static.ts.template +13 -0
  67. package/dist/cli/template-files/next.config.ts.template +5 -0
  68. package/dist/cli/template-files/schemas.ts.template +4 -2
  69. package/dist/cli/templates.d.ts +8 -0
  70. package/dist/cli/templates.d.ts.map +1 -1
  71. package/dist/cli/templates.js +22 -2
  72. package/dist/cli/templates.js.map +1 -1
  73. package/dist/client.js +9 -9
  74. package/dist/config/flatten.js +2 -2
  75. package/dist/config/helpers.js +3 -3
  76. package/dist/config/index.js +9 -9
  77. package/dist/config/schemas/collection.js +1 -1
  78. package/dist/config/schemas/config.js +2 -2
  79. package/dist/config/schemas/field.d.ts +21 -0
  80. package/dist/config/schemas/field.d.ts.map +1 -1
  81. package/dist/config/schemas/field.js +2 -1
  82. package/dist/config/schemas/field.js.map +1 -1
  83. package/dist/config/types.d.ts +7 -0
  84. package/dist/config/types.d.ts.map +1 -1
  85. package/dist/config/validation.js +2 -2
  86. package/dist/config-test.js +2 -2
  87. package/dist/config.js +2 -2
  88. package/dist/content-id-index.js +2 -2
  89. package/dist/content-listing.d.ts +3 -2
  90. package/dist/content-listing.d.ts.map +1 -1
  91. package/dist/content-listing.js +15 -12
  92. package/dist/content-listing.js.map +1 -1
  93. package/dist/content-reader.d.ts.map +1 -1
  94. package/dist/content-reader.js +18 -14
  95. package/dist/content-reader.js.map +1 -1
  96. package/dist/content-store.d.ts +5 -0
  97. package/dist/content-store.d.ts.map +1 -1
  98. package/dist/content-store.js +34 -24
  99. package/dist/content-store.js.map +1 -1
  100. package/dist/content-tree.d.ts.map +1 -1
  101. package/dist/content-tree.js +8 -3
  102. package/dist/content-tree.js.map +1 -1
  103. package/dist/context.d.ts +38 -7
  104. package/dist/context.d.ts.map +1 -1
  105. package/dist/context.js +38 -6
  106. package/dist/context.js.map +1 -1
  107. package/dist/editor/BranchManager.js +4 -4
  108. package/dist/editor/CanopyEditor.js +3 -3
  109. package/dist/editor/CanopyEditorPage.js +1 -1
  110. package/dist/editor/CommentsPanel.js +1 -1
  111. package/dist/editor/Editor.js +18 -18
  112. package/dist/editor/EntryNavigator.js +1 -1
  113. package/dist/editor/FormRenderer.js +12 -12
  114. package/dist/editor/GroupManager.js +1 -1
  115. package/dist/editor/PermissionManager.js +1 -1
  116. package/dist/editor/client-reference-resolver.js +1 -1
  117. package/dist/editor/comments/BranchComments.js +1 -1
  118. package/dist/editor/comments/EntryComments.js +1 -1
  119. package/dist/editor/comments/FieldWrapper.js +1 -1
  120. package/dist/editor/comments/InlineCommentThread.js +1 -1
  121. package/dist/editor/comments/ThreadCarousel.js +1 -1
  122. package/dist/editor/components/EditorHeader.js +1 -1
  123. package/dist/editor/components/UserBadge.js +1 -1
  124. package/dist/editor/components/index.js +3 -3
  125. package/dist/editor/context/ApiClientContext.js +1 -1
  126. package/dist/editor/context/index.js +2 -2
  127. package/dist/editor/editor-config.js +2 -2
  128. package/dist/editor/editor-config.js.map +1 -1
  129. package/dist/editor/editor-utils.js +1 -1
  130. package/dist/editor/fields/BlockField.js +1 -1
  131. package/dist/editor/fields/ObjectField.js +1 -1
  132. package/dist/editor/fields/ReferenceField.js +1 -1
  133. package/dist/editor/group-manager/GroupCard.js +1 -1
  134. package/dist/editor/group-manager/InternalGroupsTab.js +1 -1
  135. package/dist/editor/group-manager/MemberList.js +1 -1
  136. package/dist/editor/group-manager/index.js +9 -9
  137. package/dist/editor/hooks/__test__/test-utils.js +3 -3
  138. package/dist/editor/hooks/index.js +11 -11
  139. package/dist/editor/hooks/useBranchActions.js +1 -1
  140. package/dist/editor/hooks/useBranchManager.js +1 -1
  141. package/dist/editor/hooks/useCommentSystem.js +2 -2
  142. package/dist/editor/hooks/useDraftManager.js +1 -1
  143. package/dist/editor/hooks/useEntryManager.js +3 -3
  144. package/dist/editor/hooks/useGroupManager.js +1 -1
  145. package/dist/editor/hooks/usePermissionManager.js +1 -1
  146. package/dist/editor/hooks/useReferenceResolution.js +1 -1
  147. package/dist/editor/hooks/useSchemaManager.js +1 -1
  148. package/dist/editor/hooks/useUserContext.js +1 -1
  149. package/dist/editor/permission-manager/PermissionEditor.js +4 -4
  150. package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
  151. package/dist/editor/permission-manager/PermissionTree.js +3 -3
  152. package/dist/editor/permission-manager/UserSelector.js +1 -1
  153. package/dist/editor/permission-manager/hooks/usePermissionTree.js +2 -2
  154. package/dist/editor/permission-manager/index.js +6 -6
  155. package/dist/editor/preview-bridge.js +1 -1
  156. package/dist/editor/schema-editor/CollectionEditor.js +2 -2
  157. package/dist/editor/schema-editor/index.js +2 -2
  158. package/dist/entry-schema-registry.d.ts.map +1 -1
  159. package/dist/entry-schema-registry.js +12 -3
  160. package/dist/entry-schema-registry.js.map +1 -1
  161. package/dist/entry-schema.d.ts +1 -0
  162. package/dist/entry-schema.d.ts.map +1 -1
  163. package/dist/entry-schema.js.map +1 -1
  164. package/dist/git-manager.js +4 -4
  165. package/dist/github-service.d.ts.map +1 -1
  166. package/dist/github-service.js +12 -8
  167. package/dist/github-service.js.map +1 -1
  168. package/dist/http/handler.js +7 -7
  169. package/dist/http/index.js +3 -3
  170. package/dist/http/router.js +12 -12
  171. package/dist/id.js +1 -1
  172. package/dist/index.d.ts +1 -0
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.js +7 -6
  175. package/dist/index.js.map +1 -1
  176. package/dist/operating-mode/client-unsafe-strategy.js +2 -2
  177. package/dist/operating-mode/client.js +1 -1
  178. package/dist/operating-mode/index.js +2 -2
  179. package/dist/paths/branch.js +1 -1
  180. package/dist/paths/index.d.ts +1 -1
  181. package/dist/paths/index.d.ts.map +1 -1
  182. package/dist/paths/index.js +6 -6
  183. package/dist/paths/index.js.map +1 -1
  184. package/dist/paths/normalize.d.ts +8 -0
  185. package/dist/paths/normalize.d.ts.map +1 -1
  186. package/dist/paths/normalize.js +17 -0
  187. package/dist/paths/normalize.js.map +1 -1
  188. package/dist/paths/test-utils.js +1 -1
  189. package/dist/paths/validation.js +1 -1
  190. package/dist/reference-resolver.js +1 -1
  191. package/dist/schema/index.js +2 -2
  192. package/dist/schema/meta-loader.js +1 -1
  193. package/dist/schema/resolver.js +1 -1
  194. package/dist/schema/schema-store.js +4 -4
  195. package/dist/server.js +13 -13
  196. package/dist/services.js +12 -12
  197. package/dist/settings-branch-utils.js +1 -1
  198. package/dist/settings-workspace.js +3 -3
  199. package/dist/task-queue/index.js +1 -1
  200. package/dist/task-queue/task-queue.js +1 -1
  201. package/dist/url-path-resolver.d.ts +16 -0
  202. package/dist/url-path-resolver.d.ts.map +1 -0
  203. package/dist/url-path-resolver.js +31 -0
  204. package/dist/url-path-resolver.js.map +1 -0
  205. package/dist/user.js +1 -1
  206. package/dist/utils/body-field.d.ts +18 -0
  207. package/dist/utils/body-field.d.ts.map +1 -0
  208. package/dist/utils/body-field.js +39 -0
  209. package/dist/utils/body-field.js.map +1 -0
  210. package/dist/utils/fs.js +1 -1
  211. package/dist/utils/sanitize-href.d.ts +19 -0
  212. package/dist/utils/sanitize-href.d.ts.map +1 -0
  213. package/dist/utils/sanitize-href.js +30 -0
  214. package/dist/utils/sanitize-href.js.map +1 -0
  215. package/dist/validation/reference-validator.js +2 -2
  216. package/dist/worker/cms-worker.js +5 -5
  217. package/dist/worker/task-queue-config.js +1 -1
  218. package/dist/worker/task-queue.js +2 -2
  219. package/package.json +1 -1
@@ -10,21 +10,21 @@
10
10
  *
11
11
  * Usage:
12
12
  * ```ts
13
- * import { normalizeFilesystemPath, createLogicalPath, parseSlug } from '../paths'
13
+ * import { normalizeFilesystemPath, createLogicalPath, parseSlug } from '../paths/index.js'
14
14
  * ```
15
15
  */
16
16
  // Normalization utilities (client-safe)
17
- export { normalizeFilesystemPath, normalizeCollectionPath, hasTraversalSequence, createLogicalPath, createPhysicalPath, joinPath, } from './normalize';
17
+ export { normalizeFilesystemPath, normalizeCollectionPath, hasTraversalSequence, createLogicalPath, createPhysicalPath, joinPath, trimSlashes, } from './normalize.js';
18
18
  // Normalization utilities (server-only, requires Node.js path module)
19
- export { validateAndNormalizePath } from './normalize-server';
19
+ export { validateAndNormalizePath } from './normalize-server.js';
20
20
  // Validation utilities
21
21
  export { validateContentPath, isValidCollectionPath, sanitizeForPath,
22
22
  // Path type detection and parsing
23
23
  hasEmbeddedContentId, looksLikePhysicalPath, looksLikeLogicalPath, parseLogicalPath, parsePhysicalPath, isValidContentId,
24
24
  // Branded type validation and parsing
25
- parseContentId, parseBranchName, parseSlug, } from './validation';
25
+ parseContentId, parseBranchName, parseSlug, } from './validation.js';
26
26
  // Path resolution utilities
27
- export { resolveLogicalPath } from './resolve';
27
+ export { resolveLogicalPath } from './resolve.js';
28
28
  // Branch path utilities
29
- export { resolveBranchPath, ensureBranchRoot, getDefaultBranchBase, resolveBranchPaths, sanitizeBranchName, BranchPathError, } from './branch';
29
+ export { resolveBranchPath, ensureBranchRoot, getDefaultBranchBase, resolveBranchPaths, sanitizeBranchName, BranchPathError, } from './branch.js';
30
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,wCAAwC;AACxC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,GACT,MAAM,aAAa,CAAA;AAEpB,sEAAsE;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAE7D,uBAAuB;AACvB,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,eAAe;AACf,kCAAkC;AAClC,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB;AAChB,sCAAsC;AACtC,cAAc,EACd,eAAe,EACf,SAAS,GACV,MAAM,cAAc,CAAA;AAErB,4BAA4B;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAE9C,wBAAwB;AACxB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,GAGhB,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,wCAAwC;AACxC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,WAAW,GACZ,MAAM,aAAa,CAAA;AAEpB,sEAAsE;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAE7D,uBAAuB;AACvB,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,eAAe;AACf,kCAAkC;AAClC,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB;AAChB,sCAAsC;AACtC,cAAc,EACd,eAAe,EACf,SAAS,GACV,MAAM,cAAc,CAAA;AAErB,4BAA4B;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAE9C,wBAAwB;AACxB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,GAGhB,MAAM,UAAU,CAAA"}
@@ -51,6 +51,14 @@ export declare function createLogicalPath(...segments: string[]): LogicalPath;
51
51
  * createPhysicalPath('content', 'posts', 'my-post.ABC123.mdx') // as PhysicalPath
52
52
  */
53
53
  export declare function createPhysicalPath(...segments: string[]): PhysicalPath;
54
+ /**
55
+ * Strip leading and trailing slashes from a path or URL segment.
56
+ *
57
+ * @example
58
+ * trimSlashes('/docs/guides/') // 'docs/guides'
59
+ * trimSlashes('///multi///') // 'multi'
60
+ */
61
+ export declare function trimSlashes(path: string): string;
54
62
  /**
55
63
  * Join path segments with forward slashes.
56
64
  * Does not validate - use createLogicalPath/createPhysicalPath for validation.
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/paths/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAExD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,SAAY,GAAG,MAAM,CAO/F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,CAWpE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,YAAY,CAWtE;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAKtD"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/paths/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAExD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,SAAY,GAAG,MAAM,CAO/F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,CAWpE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,YAAY,CAWtE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAKtD"}
@@ -83,6 +83,23 @@ export function createPhysicalPath(...segments) {
83
83
  }
84
84
  return normalized;
85
85
  }
86
+ /**
87
+ * Strip leading and trailing slashes from a path or URL segment.
88
+ *
89
+ * @example
90
+ * trimSlashes('/docs/guides/') // 'docs/guides'
91
+ * trimSlashes('///multi///') // 'multi'
92
+ */
93
+ export function trimSlashes(path) {
94
+ // Linear scan instead of regex to avoid polynomial ReDoS on repeated '/' chars
95
+ let start = 0;
96
+ let end = path.length;
97
+ while (start < end && path[start] === '/')
98
+ start++;
99
+ while (end > start && path[end - 1] === '/')
100
+ end--;
101
+ return path.slice(start, end);
102
+ }
86
103
  /**
87
104
  * Join path segments with forward slashes.
88
105
  * Does not validate - use createLogicalPath/createPhysicalPath for validation.
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/paths/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,IAAI;SACR,KAAK,CAAC,QAAQ,CAAC;SACf,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,cAAsB,EAAE,WAAW,GAAG,SAAS;IACrF,MAAM,UAAU,GAAG,uBAAuB,CAAC,cAAc,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,GAAG,WAAW,GAAG,CAAA;IAChC,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,OAAO,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,UAAU,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;IAChD,OAAO,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,QAAkB;IACrD,MAAM,UAAU,GAAG,QAAQ;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,IAAI,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,8CAA8C,UAAU,EAAE,CAAC,CAAA;IAC7E,CAAC;IAED,OAAO,UAAyB,CAAA;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAG,QAAkB;IACtD,MAAM,UAAU,GAAG,QAAQ;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,IAAI,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,8CAA8C,UAAU,EAAE,CAAC,CAAA;IAC7E,CAAC;IAED,OAAO,UAA0B,CAAA;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAG,QAAkB;IAC5C,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC"}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/paths/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,IAAI;SACR,KAAK,CAAC,QAAQ,CAAC;SACf,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,cAAsB,EAAE,WAAW,GAAG,SAAS;IACrF,MAAM,UAAU,GAAG,uBAAuB,CAAC,cAAc,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,GAAG,WAAW,GAAG,CAAA;IAChC,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,OAAO,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,UAAU,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;IAChD,OAAO,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,QAAkB;IACrD,MAAM,UAAU,GAAG,QAAQ;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,IAAI,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,8CAA8C,UAAU,EAAE,CAAC,CAAA;IAC7E,CAAC;IAED,OAAO,UAAyB,CAAA;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAG,QAAkB;IACtD,MAAM,UAAU,GAAG,QAAQ;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,IAAI,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,8CAA8C,UAAU,EAAE,CAAC,CAAA;IAC7E,CAAC;IAED,OAAO,UAA0B,CAAA;AACnC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,+EAA+E;IAC/E,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAA;IACrB,OAAO,KAAK,GAAG,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG;QAAE,KAAK,EAAE,CAAA;IAClD,OAAO,GAAG,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG;QAAE,GAAG,EAAE,CAAA;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAG,QAAkB;IAC5C,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;SACtC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC"}
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @example
8
8
  * // In test files only:
9
- * import { unsafeAsLogicalPath, unsafeAsSlug } from '../paths/test-utils'
9
+ * import { unsafeAsLogicalPath, unsafeAsSlug } from '../paths/test-utils.js'
10
10
  */
11
11
  /** Test-only: cast a string to LogicalPath without validation. */
12
12
  export const unsafeAsLogicalPath = (path) => path;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Security-focused validation for content paths and slugs.
5
5
  */
6
- import { normalizeFilesystemPath, hasTraversalSequence } from './normalize';
6
+ import { normalizeFilesystemPath, hasTraversalSequence } from './normalize.js';
7
7
  /**
8
8
  * Base58 alphabet used for content IDs (excludes ambiguous: 0, O, I, l)
9
9
  */
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { extractSlugFromFilename } from './content-id-index';
2
+ import { extractSlugFromFilename } from './content-id-index.js';
3
3
  /**
4
4
  * ReferenceResolver resolves content IDs to display values for reference fields.
5
5
  *
@@ -13,7 +13,7 @@
13
13
  * ```
14
14
  */
15
15
  // Meta loader (low-level API)
16
- export { loadCollectionMetaFiles, resolveCollectionReferences, watchCollectionMetaFiles, } from './meta-loader';
16
+ export { loadCollectionMetaFiles, resolveCollectionReferences, watchCollectionMetaFiles, } from './meta-loader.js';
17
17
  // Resolver (high-level API)
18
- export { resolveSchema, hasSchemaFiles, isValidSchema } from './resolver';
18
+ export { resolveSchema, hasSchemaFiles, isValidSchema } from './resolver.js';
19
19
  //# sourceMappingURL=index.js.map
@@ -2,7 +2,7 @@ import { promises as fs } from 'fs';
2
2
  import { join } from 'pathe';
3
3
  import { z } from 'zod';
4
4
  import chokidar from 'chokidar';
5
- import { extractSlugFromFilename, extractIdFromFilename } from '../content-id-index';
5
+ import { extractSlugFromFilename, extractIdFromFilename } from '../content-id-index.js';
6
6
  /**
7
7
  * Zod schema for entry type metadata in .collection.json files.
8
8
  * Each entry type has a name, format, and schema reference to the entry schema registry.
@@ -7,7 +7,7 @@
7
7
  * Field schemas are defined in the entry schema registry and referenced by name
8
8
  * in .collection.json files for reusability and type safety.
9
9
  */
10
- import { loadCollectionMetaFiles, resolveCollectionReferences } from './meta-loader';
10
+ import { loadCollectionMetaFiles, resolveCollectionReferences } from './meta-loader.js';
11
11
  /**
12
12
  * Resolve schema from .collection.json files.
13
13
  *
@@ -11,10 +11,10 @@
11
11
  import { promises as fs } from 'node:fs';
12
12
  import path from 'node:path';
13
13
  import { z } from 'zod';
14
- import { atomicWriteFile } from '../utils/atomic-write';
15
- import { resolveCollectionPath } from '../content-id-index';
16
- import { generateId, isValidId } from '../id';
17
- import { createLogicalPath, validateAndNormalizePath } from '../paths';
14
+ import { atomicWriteFile } from '../utils/atomic-write.js';
15
+ import { resolveCollectionPath } from '../content-id-index.js';
16
+ import { generateId, isValidId } from '../id.js';
17
+ import { createLogicalPath, validateAndNormalizePath } from '../paths/index.js';
18
18
  // ============================================================================
19
19
  // Zod Schemas for Validation
20
20
  // ============================================================================
package/dist/server.js CHANGED
@@ -1,14 +1,14 @@
1
- export * from './content-reader';
2
- export * from './services';
3
- export * from './build-mode';
4
- export * from './context';
5
- export { operatingStrategy } from './operating-mode';
6
- export * from './authorization/groups';
7
- export * from './branch-workspace';
8
- export * from './content-store';
9
- export { loadCollectionMetaFiles, resolveCollectionReferences, watchCollectionMetaFiles, resolveSchema, } from './schema';
10
- export { createEntrySchemaRegistry, validateEntrySchemaRegistry } from './entry-schema-registry';
11
- export { generateId, isValidId } from './id';
12
- export { buildContentTree } from './content-tree';
13
- export { listEntries } from './content-listing';
1
+ export * from './content-reader.js';
2
+ export * from './services.js';
3
+ export * from './build-mode.js';
4
+ export * from './context.js';
5
+ export { operatingStrategy } from './operating-mode/index.js';
6
+ export * from './authorization/groups/index.js';
7
+ export * from './branch-workspace.js';
8
+ export * from './content-store.js';
9
+ export { loadCollectionMetaFiles, resolveCollectionReferences, watchCollectionMetaFiles, resolveSchema, } from './schema/index.js';
10
+ export { createEntrySchemaRegistry, validateEntrySchemaRegistry } from './entry-schema-registry.js';
11
+ export { generateId, isValidId } from './id.js';
12
+ export { buildContentTree } from './content-tree.js';
13
+ export { listEntries } from './content-listing.js';
14
14
  //# sourceMappingURL=server.js.map
package/dist/services.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import path from 'node:path';
2
- import { getConfigDefaults } from './config';
3
- import { createCheckPathAccess, createCheckBranchAccess, createCheckContentAccess, loadPathPermissions, } from './authorization';
4
- import { GitManager } from './git-manager';
5
- import { BranchRegistry } from './branch-registry';
6
- import { SettingsWorkspaceManager } from './settings-workspace';
7
- import { getDefaultBranchBase } from './paths';
8
- import { createGitHubService } from './github-service';
9
- import { operatingStrategy } from './operating-mode';
10
- import { BranchSchemaCache } from './branch-schema-cache';
11
- import { enqueueTask } from './worker/task-queue';
12
- import { getTaskQueueDir } from './worker/task-queue-config';
13
- import { detectHeadBranch } from './utils/git';
2
+ import { getConfigDefaults } from './config/index.js';
3
+ import { createCheckPathAccess, createCheckBranchAccess, createCheckContentAccess, loadPathPermissions, } from './authorization/index.js';
4
+ import { GitManager } from './git-manager.js';
5
+ import { BranchRegistry } from './branch-registry.js';
6
+ import { SettingsWorkspaceManager } from './settings-workspace.js';
7
+ import { getDefaultBranchBase } from './paths/index.js';
8
+ import { createGitHubService } from './github-service.js';
9
+ import { operatingStrategy } from './operating-mode/index.js';
10
+ import { BranchSchemaCache } from './branch-schema-cache.js';
11
+ import { enqueueTask } from './worker/task-queue.js';
12
+ import { getTaskQueueDir } from './worker/task-queue-config.js';
13
+ import { detectHeadBranch } from './utils/git.js';
14
14
  /**
15
15
  * In dev mode, auto-detect the current HEAD branch if defaultBaseBranch is not set.
16
16
  * Eliminates the need to manually update defaultBaseBranch when working on a feature branch.
@@ -1,4 +1,4 @@
1
- import { operatingStrategy } from './operating-mode';
1
+ import { operatingStrategy } from './operating-mode/index.js';
2
2
  /**
3
3
  * Check if a branch name is the settings branch for the current configuration
4
4
  */
@@ -1,8 +1,8 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { GitManager } from './git-manager';
4
- import { createDebugLogger } from './utils/debug';
5
- import { isFileExistsError } from './utils/error';
3
+ import { GitManager } from './git-manager.js';
4
+ import { createDebugLogger } from './utils/debug.js';
5
+ import { isFileExistsError } from './utils/error.js';
6
6
  const log = createDebugLogger({ prefix: 'SettingsWorkspace' });
7
7
  // In-memory lock to prevent concurrent workspace initialization within the same process.
8
8
  // Settings only need one lock (not per-branch like content branches).
@@ -1,2 +1,2 @@
1
- export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, } from './task-queue';
1
+ export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, recoverOrphanedTasks, cleanupOldTasks, getTask, listTasks, getQueueStats, } from './task-queue.js';
2
2
  //# sourceMappingURL=index.js.map
@@ -21,7 +21,7 @@ import crypto from 'node:crypto';
21
21
  const DEFAULT_MAX_RETRIES = 3;
22
22
  // Silent no-op logger
23
23
  const nullLogger = { debug: () => { } };
24
- import { atomicWriteFile } from '../utils/atomic-write';
24
+ import { atomicWriteFile } from '../utils/atomic-write.js';
25
25
  // Local helper — only stdlib dependency, keeps task-queue easy to extract.
26
26
  function isNotFoundError(err) {
27
27
  return err instanceof Error && 'code' in err && err.code === 'ENOENT';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Resolves a URL path to candidate entryPath/slug pairs for content lookup.
3
+ *
4
+ * Returns an ordered list of attempts:
5
+ * 1. Direct entry: last segment is slug, rest is collection path
6
+ * 2. Index fallback: full path is collection, slug is 'index'
7
+ *
8
+ * @param urlPath - URL path like '/docs/guides/getting-started' or 'docs/guides'
9
+ * @param contentRoot - Content root directory name (default: 'content')
10
+ * @returns Array of { entryPath, slug } candidates to try in order
11
+ */
12
+ export declare function resolveUrlPathCandidates(urlPath: string, contentRoot: string): Array<{
13
+ entryPath: string;
14
+ slug: string;
15
+ }>;
16
+ //# sourceMappingURL=url-path-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-path-resolver.d.ts","sourceRoot":"","sources":["../src/url-path-resolver.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAsB5C"}
@@ -0,0 +1,31 @@
1
+ import { trimSlashes } from './paths/normalize.js';
2
+ /**
3
+ * Resolves a URL path to candidate entryPath/slug pairs for content lookup.
4
+ *
5
+ * Returns an ordered list of attempts:
6
+ * 1. Direct entry: last segment is slug, rest is collection path
7
+ * 2. Index fallback: full path is collection, slug is 'index'
8
+ *
9
+ * @param urlPath - URL path like '/docs/guides/getting-started' or 'docs/guides'
10
+ * @param contentRoot - Content root directory name (default: 'content')
11
+ * @returns Array of { entryPath, slug } candidates to try in order
12
+ */
13
+ export function resolveUrlPathCandidates(urlPath, contentRoot) {
14
+ const normalized = trimSlashes(urlPath);
15
+ const segments = normalized.split('/').filter(Boolean);
16
+ if (segments.length === 0)
17
+ return [];
18
+ const candidates = [];
19
+ // Try 1: last segment is the entry slug, rest is the collection path
20
+ const slug = segments[segments.length - 1];
21
+ const collectionSegments = segments.slice(0, -1);
22
+ const entryPath = collectionSegments.length > 0 ? `${contentRoot}/${collectionSegments.join('/')}` : contentRoot;
23
+ candidates.push({ entryPath, slug });
24
+ // Try 2: full path is a collection with an index entry
25
+ candidates.push({
26
+ entryPath: `${contentRoot}/${segments.join('/')}`,
27
+ slug: 'index',
28
+ });
29
+ return candidates;
30
+ }
31
+ //# sourceMappingURL=url-path-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-path-resolver.js","sourceRoot":"","sources":["../src/url-path-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAe,EACf,WAAmB;IAEnB,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACtD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAEpC,MAAM,UAAU,GAA+C,EAAE,CAAA;IAEjE,qEAAqE;IACrE,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC1C,MAAM,kBAAkB,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAChD,MAAM,SAAS,GACb,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAA;IAEhG,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEpC,uDAAuD;IACvD,UAAU,CAAC,IAAI,CAAC;QACd,SAAS,EAAE,GAAG,WAAW,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACjD,IAAI,EAAE,OAAO;KACd,CAAC,CAAA;IAEF,OAAO,UAAU,CAAA;AACnB,CAAC"}
package/dist/user.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Import from client-safe subpaths to avoid pulling in server-only loader code
2
- import { RESERVED_GROUPS } from './authorization/helpers';
2
+ import { RESERVED_GROUPS } from './authorization/helpers.js';
3
3
  /**
4
4
  * Branded ANONYMOUS_USER constant - use this for intentional anonymous access.
5
5
  * Callers must explicitly pass this to indicate anonymous access is intended.
@@ -0,0 +1,18 @@
1
+ import type { FieldConfig } from '../config';
2
+ /**
3
+ * Count the number of top-level fields marked `isBody: true` in a schema.
4
+ * Does NOT recurse into objects — isBody only makes sense at the top level
5
+ * because it maps to the file's markdown content.
6
+ */
7
+ export declare function countBodyFields(fields: readonly FieldConfig[]): number;
8
+ /**
9
+ * Find the name of the field marked `isBody: true`, or `'body'` as the default.
10
+ * Used at read time to map the markdown file's content to the correct data field.
11
+ */
12
+ export declare function findBodyFieldName(fields: readonly FieldConfig[]): string;
13
+ /**
14
+ * Find isBody fields that have an invalid type (not 'markdown' or 'mdx').
15
+ * Returns field names that fail validation.
16
+ */
17
+ export declare function findInvalidBodyFields(fields: readonly FieldConfig[]): string[];
18
+ //# sourceMappingURL=body-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-field.d.ts","sourceRoot":"","sources":["../../src/utils/body-field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAI5C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAMtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAKxE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,EAAE,CAQ9E"}
@@ -0,0 +1,39 @@
1
+ const BODY_FIELD_TYPES = new Set(['markdown', 'mdx']);
2
+ /**
3
+ * Count the number of top-level fields marked `isBody: true` in a schema.
4
+ * Does NOT recurse into objects — isBody only makes sense at the top level
5
+ * because it maps to the file's markdown content.
6
+ */
7
+ export function countBodyFields(fields) {
8
+ let count = 0;
9
+ for (const field of fields) {
10
+ if ('isBody' in field && field.isBody)
11
+ count++;
12
+ }
13
+ return count;
14
+ }
15
+ /**
16
+ * Find the name of the field marked `isBody: true`, or `'body'` as the default.
17
+ * Used at read time to map the markdown file's content to the correct data field.
18
+ */
19
+ export function findBodyFieldName(fields) {
20
+ for (const field of fields) {
21
+ if ('isBody' in field && field.isBody)
22
+ return field.name;
23
+ }
24
+ return 'body';
25
+ }
26
+ /**
27
+ * Find isBody fields that have an invalid type (not 'markdown' or 'mdx').
28
+ * Returns field names that fail validation.
29
+ */
30
+ export function findInvalidBodyFields(fields) {
31
+ const invalid = [];
32
+ for (const field of fields) {
33
+ if ('isBody' in field && field.isBody && !BODY_FIELD_TYPES.has(field.type)) {
34
+ invalid.push(field.name);
35
+ }
36
+ }
37
+ return invalid;
38
+ }
39
+ //# sourceMappingURL=body-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-field.js","sourceRoot":"","sources":["../../src/utils/body-field.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAA;AAErD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAA8B;IAC5D,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM;YAAE,KAAK,EAAE,CAAA;IAChD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA8B;IAC9D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC,IAAI,CAAA;IAC1D,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAA8B;IAClE,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3E,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC"}
package/dist/utils/fs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import fs from 'node:fs/promises';
2
- import { isNotFoundError } from './error';
2
+ import { isNotFoundError } from './error.js';
3
3
  /** Check if a path exists on disk. */
4
4
  export async function filePathExists(filePath) {
5
5
  try {
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Sanitize an untrusted URL for use in `href` attributes.
3
+ *
4
+ * Parses the input with `new URL()` and only allows `http:` and `https:` protocols,
5
+ * blocking `javascript:`, `data:`, `vbscript:`, and other dangerous schemes.
6
+ * Returns the fallback (default `'#'`) for invalid or disallowed URLs.
7
+ *
8
+ * This utility breaks CodeQL's taint chain by constructing a new string from
9
+ * the parsed URL rather than passing the original input through.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * import { sanitizeHref } from 'canopycms'
14
+ *
15
+ * <a href={sanitizeHref(cta.link)}>{cta.text}</a>
16
+ * ```
17
+ */
18
+ export declare function sanitizeHref(url: string, fallback?: string): string;
19
+ //# sourceMappingURL=sanitize-href.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-href.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize-href.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAUhE"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Sanitize an untrusted URL for use in `href` attributes.
3
+ *
4
+ * Parses the input with `new URL()` and only allows `http:` and `https:` protocols,
5
+ * blocking `javascript:`, `data:`, `vbscript:`, and other dangerous schemes.
6
+ * Returns the fallback (default `'#'`) for invalid or disallowed URLs.
7
+ *
8
+ * This utility breaks CodeQL's taint chain by constructing a new string from
9
+ * the parsed URL rather than passing the original input through.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * import { sanitizeHref } from 'canopycms'
14
+ *
15
+ * <a href={sanitizeHref(cta.link)}>{cta.text}</a>
16
+ * ```
17
+ */
18
+ export function sanitizeHref(url, fallback = '#') {
19
+ try {
20
+ const parsed = new URL(url);
21
+ if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
22
+ return parsed.href;
23
+ }
24
+ }
25
+ catch {
26
+ // invalid URL
27
+ }
28
+ return fallback;
29
+ }
30
+ //# sourceMappingURL=sanitize-href.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-href.js","sourceRoot":"","sources":["../../src/utils/sanitize-href.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,QAAQ,GAAG,GAAG;IACtD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QAC3B,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChE,OAAO,MAAM,CAAC,IAAI,CAAA;QACpB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -1,5 +1,5 @@
1
- import { isValidId } from '../id';
2
- import { findFieldsByType } from './field-traversal';
1
+ import { isValidId } from '../id.js';
2
+ import { findFieldsByType } from './field-traversal.js';
3
3
  /**
4
4
  * ReferenceValidator validates that referenced content IDs exist and match collection constraints.
5
5
  *
@@ -2,11 +2,11 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { simpleGit } from 'simple-git';
4
4
  import { Octokit } from '@octokit/rest';
5
- import { dequeueTask, completeTask, failTask, retryTask, recoverOrphanedTasks, cleanupOldTasks, cmsTaskQueueLogger, } from './task-queue';
6
- import { getBranchMetadataFileManager, BranchMetadataFileManager } from '../branch-metadata';
7
- import { extractIdFromFilename } from '../content-id-index';
8
- import { ROOT_COLLECTION_ID } from '../paths/types';
9
- import { isFileExistsError } from '../utils/error';
5
+ import { dequeueTask, completeTask, failTask, retryTask, recoverOrphanedTasks, cleanupOldTasks, cmsTaskQueueLogger, } from './task-queue.js';
6
+ import { getBranchMetadataFileManager, BranchMetadataFileManager } from '../branch-metadata.js';
7
+ import { extractIdFromFilename } from '../content-id-index.js';
8
+ import { ROOT_COLLECTION_ID } from '../paths/types.js';
9
+ import { isFileExistsError } from '../utils/error.js';
10
10
  const DEFAULT_TASK_TIMEOUT = 60_000;
11
11
  const DEFAULT_MAX_RETRIES = 3;
12
12
  // Payload validation helpers — fail fast with clear errors instead of silent `as` casts
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { DEFAULT_PROD_WORKSPACE } from '../config';
2
+ import { DEFAULT_PROD_WORKSPACE } from '../config/index.js';
3
3
  /**
4
4
  * Get the task queue directory for async worker operations.
5
5
  *
@@ -2,7 +2,7 @@
2
2
  * CanopyCMS task queue — re-exports from the generic task-queue module
3
3
  * with CMS-specific action types and a WorkerTask alias.
4
4
  */
5
- import { createDebugLogger } from '../utils/debug';
5
+ import { createDebugLogger } from '../utils/debug.js';
6
6
  // ============================================================================
7
7
  // Shared logger instance for CMS task queue operations
8
8
  // ============================================================================
@@ -16,5 +16,5 @@ export const cmsTaskQueueLogger = {
16
16
  // Re-exports from generic task-queue module
17
17
  // ============================================================================
18
18
  export { enqueueTask, dequeueTask, completeTask, failTask, retryTask, recoverOrphanedTasks, cleanupOldTasks, getTask, getTask as getTaskResult, // backward-compatible alias
19
- listTasks, getQueueStats, } from '../task-queue';
19
+ listTasks, getQueueStats, } from '../task-queue/index.js';
20
20
  //# sourceMappingURL=task-queue.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "@codemirror/language, @lezer/highlight: workaround — @mdxeditor/editor uses cm6-theme-basic-light which peer-requires these but mdxeditor doesn't declare them as dependencies",
3
3
  "name": "canopycms",
4
- "version": "0.0.16",
4
+ "version": "0.0.18",
5
5
  "description": "CanopyCMS core package: schema-driven content, branch-aware editing, and editor UI for Next.js.",
6
6
  "license": "MIT",
7
7
  "repository": {