canopycms 0.0.67-int.90 → 0.0.67

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 (539) hide show
  1. package/README.md +30 -3
  2. package/dist/ai/generate.js +1 -27
  3. package/dist/ai/handler.d.ts +0 -4
  4. package/dist/ai/handler.js +0 -11
  5. package/dist/ai/index.d.ts +1 -8
  6. package/dist/ai/index.js +1 -8
  7. package/dist/ai/json-to-markdown.js +15 -58
  8. package/dist/ai/resolve-branch.d.ts +2 -7
  9. package/dist/ai/resolve-branch.js +2 -8
  10. package/dist/ai/strip-mdx.d.ts +5 -13
  11. package/dist/ai/strip-mdx.js +5 -17
  12. package/dist/ai/to-plain-text.d.ts +10 -28
  13. package/dist/ai/to-plain-text.js +10 -28
  14. package/dist/ai/transform-components.d.ts +2 -4
  15. package/dist/ai/transform-components.js +8 -19
  16. package/dist/ai/types.d.ts +5 -10
  17. package/dist/api/admin-branch-health.d.ts +4 -12
  18. package/dist/api/admin-branch-health.js +26 -66
  19. package/dist/api/admin.d.ts +4 -12
  20. package/dist/api/admin.js +10 -26
  21. package/dist/api/assets.d.ts +0 -25
  22. package/dist/api/assets.js +50 -91
  23. package/dist/api/branch-merge.d.ts +1 -1
  24. package/dist/api/branch-merge.js +0 -2
  25. package/dist/api/branch-review.d.ts +0 -8
  26. package/dist/api/branch-review.js +0 -13
  27. package/dist/api/branch-status.d.ts +0 -3
  28. package/dist/api/branch-status.js +8 -33
  29. package/dist/api/branch-withdraw.d.ts +0 -1
  30. package/dist/api/branch-withdraw.js +6 -9
  31. package/dist/api/branch.d.ts +7 -12
  32. package/dist/api/branch.js +7 -44
  33. package/dist/api/client.d.ts +71 -224
  34. package/dist/api/client.js +82 -233
  35. package/dist/api/comments.d.ts +2 -4
  36. package/dist/api/comments.js +0 -17
  37. package/dist/api/content.d.ts +0 -6
  38. package/dist/api/content.js +66 -142
  39. package/dist/api/entries-constants.d.ts +5 -9
  40. package/dist/api/entries-constants.js +5 -9
  41. package/dist/api/entries.d.ts +8 -13
  42. package/dist/api/entries.js +20 -51
  43. package/dist/api/github-sync.d.ts +2 -4
  44. package/dist/api/github-sync.js +4 -8
  45. package/dist/api/groups.d.ts +3 -0
  46. package/dist/api/groups.js +8 -21
  47. package/dist/api/guards.d.ts +4 -16
  48. package/dist/api/guards.js +3 -22
  49. package/dist/api/index.d.ts +4 -4
  50. package/dist/api/permissions.d.ts +2 -0
  51. package/dist/api/permissions.js +18 -40
  52. package/dist/api/reference-options.d.ts +0 -1
  53. package/dist/api/reference-options.js +3 -11
  54. package/dist/api/request-body-hash.d.ts +12 -23
  55. package/dist/api/request-body-hash.js +12 -23
  56. package/dist/api/resolve-references.d.ts +0 -1
  57. package/dist/api/resolve-references.js +13 -28
  58. package/dist/api/route-builder.d.ts +3 -7
  59. package/dist/api/route-builder.js +1 -1
  60. package/dist/api/routes.d.ts +12 -0
  61. package/dist/api/routes.js +47 -0
  62. package/dist/api/schema.d.ts +23 -33
  63. package/dist/api/schema.js +20 -74
  64. package/dist/api/settings-helpers.js +4 -5
  65. package/dist/api/types.d.ts +0 -5
  66. package/dist/api/user.js +0 -5
  67. package/dist/api/validators.d.ts +14 -52
  68. package/dist/api/validators.js +14 -52
  69. package/dist/assets/asset-prefixes.d.ts +4 -8
  70. package/dist/assets/asset-prefixes.js +4 -8
  71. package/dist/assets/asset-src.d.ts +5 -22
  72. package/dist/assets/asset-src.js +5 -21
  73. package/dist/assets/factory.d.ts +1 -2
  74. package/dist/assets/factory.js +1 -2
  75. package/dist/assets/finalize.d.ts +3 -1
  76. package/dist/assets/finalize.js +3 -1
  77. package/dist/assets/index.d.ts +3 -3
  78. package/dist/assets/index.js +1 -1
  79. package/dist/assets/keys.d.ts +5 -3
  80. package/dist/assets/keys.js +6 -3
  81. package/dist/assets/pipeline.d.ts +3 -2
  82. package/dist/assets/pipeline.js +22 -56
  83. package/dist/assets/sharp-loader.d.ts +2 -10
  84. package/dist/assets/sharp-loader.js +2 -10
  85. package/dist/assets/store-local.d.ts +1 -2
  86. package/dist/assets/store-local.js +1 -2
  87. package/dist/assets/store-s3.d.ts +3 -4
  88. package/dist/assets/svg-sanitizer.d.ts +6 -14
  89. package/dist/assets/svg-sanitizer.js +6 -14
  90. package/dist/assets/transform-directives.d.ts +3 -4
  91. package/dist/assets/transform-directives.js +1 -1
  92. package/dist/assets/transform.d.ts +19 -30
  93. package/dist/assets/transform.js +18 -31
  94. package/dist/auth/cache.d.ts +2 -3
  95. package/dist/auth/cache.js +2 -3
  96. package/dist/auth/caching-auth-plugin.d.ts +11 -22
  97. package/dist/auth/caching-auth-plugin.js +12 -14
  98. package/dist/auth/context-helpers.d.ts +6 -20
  99. package/dist/auth/context-helpers.js +5 -17
  100. package/dist/auth/file-based-auth-cache.d.ts +10 -21
  101. package/dist/auth/file-based-auth-cache.js +23 -51
  102. package/dist/auth/plugin.d.ts +29 -61
  103. package/dist/auth/plugin.js +9 -13
  104. package/dist/auth/types.d.ts +11 -20
  105. package/dist/authorization/branch.d.ts +30 -49
  106. package/dist/authorization/branch.js +16 -42
  107. package/dist/authorization/content.d.ts +11 -40
  108. package/dist/authorization/content.js +13 -45
  109. package/dist/authorization/groups/index.d.ts +0 -3
  110. package/dist/authorization/groups/index.js +0 -3
  111. package/dist/authorization/groups/loader.d.ts +14 -28
  112. package/dist/authorization/groups/loader.js +14 -38
  113. package/dist/authorization/groups/schema.d.ts +0 -6
  114. package/dist/authorization/groups/schema.js +4 -7
  115. package/dist/authorization/helpers.d.ts +9 -28
  116. package/dist/authorization/helpers.js +9 -28
  117. package/dist/authorization/index.d.ts +3 -25
  118. package/dist/authorization/index.js +3 -35
  119. package/dist/authorization/path.d.ts +6 -13
  120. package/dist/authorization/path.js +8 -25
  121. package/dist/authorization/permissions/index.d.ts +0 -3
  122. package/dist/authorization/permissions/index.js +0 -3
  123. package/dist/authorization/permissions/loader.d.ts +14 -27
  124. package/dist/authorization/permissions/loader.js +14 -32
  125. package/dist/authorization/permissions/schema.d.ts +1 -6
  126. package/dist/authorization/permissions/schema.js +6 -13
  127. package/dist/authorization/protected-branch.d.ts +36 -65
  128. package/dist/authorization/protected-branch.js +29 -41
  129. package/dist/authorization/settings-file-store.d.ts +38 -81
  130. package/dist/authorization/settings-file-store.js +38 -79
  131. package/dist/authorization/types.d.ts +4 -26
  132. package/dist/authorization/types.js +0 -6
  133. package/dist/authorization/validation.d.ts +1 -23
  134. package/dist/authorization/validation.js +1 -24
  135. package/dist/branch-health.d.ts +39 -67
  136. package/dist/branch-health.js +27 -43
  137. package/dist/branch-metadata-file.d.ts +16 -32
  138. package/dist/branch-metadata-file.js +13 -26
  139. package/dist/branch-metadata.d.ts +49 -80
  140. package/dist/branch-metadata.js +57 -87
  141. package/dist/branch-registry.d.ts +26 -64
  142. package/dist/branch-registry.js +44 -93
  143. package/dist/branch-schema-cache.d.ts +34 -124
  144. package/dist/branch-schema-cache.js +49 -155
  145. package/dist/branch-workspace.d.ts +4 -4
  146. package/dist/branch-workspace.js +15 -19
  147. package/dist/build/generate-ai-content.d.ts +1 -0
  148. package/dist/build/generate-ai-content.js +12 -25
  149. package/dist/build-canopy.d.ts +17 -27
  150. package/dist/build-canopy.js +16 -23
  151. package/dist/build-mode.d.ts +25 -27
  152. package/dist/build-mode.js +25 -29
  153. package/dist/cli/cli.d.ts +15 -26
  154. package/dist/cli/cli.js +601 -978
  155. package/dist/cli/generate-ai-content.js +351 -628
  156. package/dist/cli/github-app-manifest.d.ts +84 -0
  157. package/dist/cli/github-app-manifest.js +161 -0
  158. package/dist/cli/init-github-app.d.ts +110 -444
  159. package/dist/cli/init-github-app.js +236 -773
  160. package/dist/cli/init.js +39 -80
  161. package/dist/cli/migrate.d.ts +13 -10
  162. package/dist/cli/migrate.js +22 -30
  163. package/dist/cli/project-detect.d.ts +17 -31
  164. package/dist/cli/project-detect.js +31 -42
  165. package/dist/cli/project-root.d.ts +4 -11
  166. package/dist/cli/project-root.js +4 -11
  167. package/dist/cli/prompt.d.ts +10 -0
  168. package/dist/cli/prompt.js +67 -0
  169. package/dist/cli/sync.d.ts +0 -8
  170. package/dist/cli/sync.js +8 -28
  171. package/dist/cli/template-files/middleware.ts.template +15 -29
  172. package/dist/cli/templates.d.ts +2 -12
  173. package/dist/cli/templates.js +4 -4
  174. package/dist/client.d.ts +1 -1
  175. package/dist/comment-store.d.ts +32 -53
  176. package/dist/comment-store.js +32 -52
  177. package/dist/config/flatten.d.ts +0 -3
  178. package/dist/config/flatten.js +2 -12
  179. package/dist/config/helpers.js +2 -2
  180. package/dist/config/index.d.ts +2 -2
  181. package/dist/config/index.js +1 -4
  182. package/dist/config/schemas/collection.d.ts +0 -8
  183. package/dist/config/schemas/collection.js +0 -10
  184. package/dist/config/schemas/config.d.ts +6 -78
  185. package/dist/config/schemas/config.js +38 -54
  186. package/dist/config/schemas/field.d.ts +2 -242
  187. package/dist/config/schemas/field.js +9 -20
  188. package/dist/config/schemas/media.js +1 -1
  189. package/dist/config/schemas/permissions.js +0 -2
  190. package/dist/config/schemas/url.d.ts +5 -6
  191. package/dist/config/schemas/url.js +5 -6
  192. package/dist/config/types.d.ts +45 -33
  193. package/dist/config/types.js +0 -1
  194. package/dist/config.d.ts +1 -8
  195. package/dist/config.js +1 -9
  196. package/dist/content-id-index.d.ts +76 -188
  197. package/dist/content-id-index.js +79 -230
  198. package/dist/content-index-generation.d.ts +27 -48
  199. package/dist/content-index-generation.js +35 -84
  200. package/dist/content-index-registry.d.ts +15 -24
  201. package/dist/content-index-registry.js +5 -9
  202. package/dist/content-listing.d.ts +64 -107
  203. package/dist/content-listing.js +68 -118
  204. package/dist/content-reader.d.ts +20 -29
  205. package/dist/content-reader.js +10 -18
  206. package/dist/content-store.d.ts +210 -336
  207. package/dist/content-store.js +413 -657
  208. package/dist/content-tree.d.ts +44 -86
  209. package/dist/content-tree.js +26 -54
  210. package/dist/context.d.ts +67 -94
  211. package/dist/context.js +53 -72
  212. package/dist/dev-content-watcher.d.ts +18 -18
  213. package/dist/dev-content-watcher.js +41 -44
  214. package/dist/editor/BranchManager.d.ts +3 -6
  215. package/dist/editor/BranchManager.js +24 -44
  216. package/dist/editor/CanopyEditor.js +5 -2
  217. package/dist/editor/CommentsPanel.js +0 -2
  218. package/dist/editor/Editor.js +19 -76
  219. package/dist/editor/EditorAuthGate.d.ts +27 -0
  220. package/dist/editor/EditorAuthGate.js +140 -0
  221. package/dist/editor/EntryNavigator.js +0 -20
  222. package/dist/editor/FormRenderer.d.ts +1 -2
  223. package/dist/editor/FormRenderer.js +8 -23
  224. package/dist/editor/admin/SystemHealthPanel.js +20 -37
  225. package/dist/editor/admin/useSystemHealth.d.ts +2 -3
  226. package/dist/editor/admin/useSystemHealth.js +10 -12
  227. package/dist/editor/client-reference-resolver.d.ts +2 -5
  228. package/dist/editor/client-reference-resolver.js +2 -19
  229. package/dist/editor/comments/BranchComments.js +0 -4
  230. package/dist/editor/comments/EntryComments.js +0 -4
  231. package/dist/editor/comments/FieldWrapper.js +0 -4
  232. package/dist/editor/comments/InlineCommentThread.js +0 -2
  233. package/dist/editor/comments/ThreadCarousel.d.ts +0 -58
  234. package/dist/editor/comments/ThreadCarousel.js +0 -12
  235. package/dist/editor/components/EditorFooter.d.ts +0 -8
  236. package/dist/editor/components/EditorFooter.js +0 -5
  237. package/dist/editor/components/EditorHeader.d.ts +0 -31
  238. package/dist/editor/components/EditorHeader.js +21 -71
  239. package/dist/editor/components/EditorSidebar.d.ts +0 -19
  240. package/dist/editor/components/EditorSidebar.js +0 -16
  241. package/dist/editor/components/EntryCreateModal.d.ts +4 -4
  242. package/dist/editor/components/EntryCreateModal.js +7 -22
  243. package/dist/editor/components/RenameEntryModal.js +0 -4
  244. package/dist/editor/components/UserBadge.js +0 -10
  245. package/dist/editor/components/index.js +0 -2
  246. package/dist/editor/context/ApiClientContext.d.ts +8 -7
  247. package/dist/editor/context/ApiClientContext.js +39 -11
  248. package/dist/editor/context/AssetContext.d.ts +7 -17
  249. package/dist/editor/context/AssetContext.js +7 -17
  250. package/dist/editor/context/EditorIdentityContext.d.ts +13 -0
  251. package/dist/editor/context/EditorIdentityContext.js +7 -0
  252. package/dist/editor/context/EditorStateContext.d.ts +10 -41
  253. package/dist/editor/context/EditorStateContext.js +7 -23
  254. package/dist/editor/context/SWRProvider.d.ts +3 -6
  255. package/dist/editor/context/index.d.ts +1 -20
  256. package/dist/editor/context/index.js +1 -20
  257. package/dist/editor/editor-utils.d.ts +8 -47
  258. package/dist/editor/editor-utils.js +19 -72
  259. package/dist/editor/fields/BlockField.d.ts +2 -2
  260. package/dist/editor/fields/BlockField.js +1 -2
  261. package/dist/editor/fields/CodeField.d.ts +0 -1
  262. package/dist/editor/fields/CodeField.js +0 -1
  263. package/dist/editor/fields/DateTimeField.d.ts +15 -22
  264. package/dist/editor/fields/DateTimeField.js +17 -26
  265. package/dist/editor/fields/ImageField.d.ts +2 -2
  266. package/dist/editor/fields/ImageField.js +8 -14
  267. package/dist/editor/fields/InlineGroupField.d.ts +0 -1
  268. package/dist/editor/fields/InlineGroupField.js +0 -1
  269. package/dist/editor/fields/MarkdownField.d.ts +0 -1
  270. package/dist/editor/fields/MarkdownField.js +6 -11
  271. package/dist/editor/fields/MdxImageDialog.d.ts +1 -1
  272. package/dist/editor/fields/MdxImageDialog.js +0 -1
  273. package/dist/editor/fields/NumberField.d.ts +9 -19
  274. package/dist/editor/fields/NumberField.js +11 -22
  275. package/dist/editor/fields/NumberListField.d.ts +7 -10
  276. package/dist/editor/fields/NumberListField.js +7 -10
  277. package/dist/editor/fields/ObjectField.d.ts +5 -8
  278. package/dist/editor/fields/ObjectField.js +0 -1
  279. package/dist/editor/fields/ReferenceField.d.ts +1 -1
  280. package/dist/editor/fields/ReferenceField.js +11 -16
  281. package/dist/editor/fields/SelectField.d.ts +2 -2
  282. package/dist/editor/fields/SelectField.js +0 -1
  283. package/dist/editor/fields/StringListField.d.ts +0 -4
  284. package/dist/editor/fields/StringListField.js +4 -9
  285. package/dist/editor/fields/TextField.d.ts +0 -1
  286. package/dist/editor/fields/TextField.js +0 -1
  287. package/dist/editor/fields/ToggleField.d.ts +0 -1
  288. package/dist/editor/fields/ToggleField.js +0 -1
  289. package/dist/editor/fields/entry-link/EntryLinkContext.js +2 -4
  290. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -3
  291. package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -4
  292. package/dist/editor/group-manager/ExternalGroupsTab.d.ts +0 -3
  293. package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
  294. package/dist/editor/group-manager/GroupCard.d.ts +0 -3
  295. package/dist/editor/group-manager/GroupForm.d.ts +0 -3
  296. package/dist/editor/group-manager/InternalGroupsTab.d.ts +0 -3
  297. package/dist/editor/group-manager/InternalGroupsTab.js +0 -2
  298. package/dist/editor/group-manager/MemberList.d.ts +0 -3
  299. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +0 -3
  300. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -3
  301. package/dist/editor/group-manager/hooks/useGroupState.d.ts +0 -3
  302. package/dist/editor/group-manager/hooks/useGroupState.js +0 -5
  303. package/dist/editor/group-manager/hooks/useUserSearch.d.ts +0 -3
  304. package/dist/editor/group-manager/hooks/useUserSearch.js +0 -3
  305. package/dist/editor/group-manager/index.d.ts +0 -6
  306. package/dist/editor/group-manager/index.js +0 -10
  307. package/dist/editor/group-manager/types.d.ts +2 -5
  308. package/dist/editor/group-manager/types.js +0 -3
  309. package/dist/editor/hooks/index.d.ts +6 -11
  310. package/dist/editor/hooks/index.js +6 -12
  311. package/dist/editor/hooks/useBranchActions.d.ts +0 -14
  312. package/dist/editor/hooks/useBranchActions.js +0 -22
  313. package/dist/editor/hooks/useBranchManager.d.ts +2 -48
  314. package/dist/editor/hooks/useBranchManager.js +4 -64
  315. package/dist/editor/hooks/useBranchesData.d.ts +7 -6
  316. package/dist/editor/hooks/useBranchesData.js +7 -6
  317. package/dist/editor/hooks/useCommentSystem.d.ts +0 -49
  318. package/dist/editor/hooks/useCommentSystem.js +1 -36
  319. package/dist/editor/hooks/useDraftManager.d.ts +2 -35
  320. package/dist/editor/hooks/useDraftManager.js +23 -64
  321. package/dist/editor/hooks/useEditorLayout.d.ts +0 -20
  322. package/dist/editor/hooks/useEditorLayout.js +0 -23
  323. package/dist/editor/hooks/useEntriesData.d.ts +1 -0
  324. package/dist/editor/hooks/useEntriesData.js +2 -3
  325. package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -2
  326. package/dist/editor/hooks/useEntryLinkResolution.js +2 -2
  327. package/dist/editor/hooks/useEntryManager.d.ts +2 -27
  328. package/dist/editor/hooks/useEntryManager.js +29 -78
  329. package/dist/editor/hooks/useGroupManager.d.ts +0 -21
  330. package/dist/editor/hooks/useGroupManager.js +0 -21
  331. package/dist/editor/hooks/usePermissionManager.d.ts +0 -20
  332. package/dist/editor/hooks/usePermissionManager.js +0 -20
  333. package/dist/editor/hooks/useReferenceResolution.d.ts +2 -33
  334. package/dist/editor/hooks/useReferenceResolution.js +1 -48
  335. package/dist/editor/hooks/useSchemaManager.d.ts +8 -27
  336. package/dist/editor/hooks/useSchemaManager.js +0 -19
  337. package/dist/editor/hooks/useUserContext.d.ts +2 -9
  338. package/dist/editor/hooks/useUserContext.js +10 -10
  339. package/dist/editor/hooks/useUserMetadata.d.ts +0 -2
  340. package/dist/editor/hooks/useUserMetadata.js +0 -3
  341. package/dist/editor/media/AssetCard.d.ts +0 -1
  342. package/dist/editor/media/AssetCard.js +1 -2
  343. package/dist/editor/media/CropStep.d.ts +0 -1
  344. package/dist/editor/media/CropStep.js +0 -1
  345. package/dist/editor/media/MediaLibrary.d.ts +1 -2
  346. package/dist/editor/media/MediaLibrary.js +1 -2
  347. package/dist/editor/media/MediaLibraryBody.d.ts +0 -1
  348. package/dist/editor/media/MediaLibraryBody.js +0 -1
  349. package/dist/editor/media/crop-math.d.ts +1 -1
  350. package/dist/editor/media/crop-math.js +1 -1
  351. package/dist/editor/permission-manager/GroupSelector.d.ts +0 -3
  352. package/dist/editor/permission-manager/PermissionEditor.d.ts +0 -4
  353. package/dist/editor/permission-manager/PermissionEditor.js +0 -1
  354. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +0 -7
  355. package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -4
  356. package/dist/editor/permission-manager/PermissionTree.d.ts +0 -4
  357. package/dist/editor/permission-manager/UserSelector.d.ts +0 -3
  358. package/dist/editor/permission-manager/constants.d.ts +0 -3
  359. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +0 -3
  360. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -10
  361. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +0 -14
  362. package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -11
  363. package/dist/editor/permission-manager/index.d.ts +0 -7
  364. package/dist/editor/permission-manager/index.js +0 -16
  365. package/dist/editor/permission-manager/types.d.ts +2 -12
  366. package/dist/editor/permission-manager/types.js +0 -3
  367. package/dist/editor/permission-manager/utils.d.ts +0 -28
  368. package/dist/editor/permission-manager/utils.js +9 -23
  369. package/dist/editor/preview-bridge.d.ts +5 -1
  370. package/dist/editor/preview-bridge.js +4 -4
  371. package/dist/editor/schema-editor/CollectionEditor.d.ts +0 -5
  372. package/dist/editor/schema-editor/CollectionEditor.js +9 -31
  373. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +0 -6
  374. package/dist/editor/schema-editor/EntryTypeEditor.js +3 -24
  375. package/dist/editor/schema-editor/index.d.ts +0 -7
  376. package/dist/editor/schema-editor/index.js +0 -7
  377. package/dist/editor/utils/env.d.ts +3 -18
  378. package/dist/editor/utils/env.js +6 -25
  379. package/dist/entry-link-resolver.d.ts +13 -35
  380. package/dist/entry-link-resolver.js +20 -53
  381. package/dist/entry-schema-registry.d.ts +20 -60
  382. package/dist/entry-schema-registry.js +20 -69
  383. package/dist/entry-schema.d.ts +118 -223
  384. package/dist/entry-schema.js +46 -91
  385. package/dist/git-manager.d.ts +101 -200
  386. package/dist/git-manager.js +211 -384
  387. package/dist/github-service.d.ts +34 -75
  388. package/dist/github-service.js +37 -91
  389. package/dist/http/handler.d.ts +6 -37
  390. package/dist/http/handler.js +65 -120
  391. package/dist/http/router.d.ts +15 -32
  392. package/dist/http/router.js +34 -99
  393. package/dist/http/types.d.ts +15 -40
  394. package/dist/http/types.js +3 -7
  395. package/dist/id.d.ts +4 -10
  396. package/dist/id.js +4 -10
  397. package/dist/index.js +6 -9
  398. package/dist/operating-mode/client-safe-strategy.d.ts +7 -14
  399. package/dist/operating-mode/client-safe-strategy.js +8 -28
  400. package/dist/operating-mode/client-unsafe-strategy.d.ts +6 -16
  401. package/dist/operating-mode/client-unsafe-strategy.js +9 -34
  402. package/dist/operating-mode/client.d.ts +3 -10
  403. package/dist/operating-mode/client.js +3 -8
  404. package/dist/operating-mode/deployment-name-fixtures.d.ts +14 -18
  405. package/dist/operating-mode/deployment-name-fixtures.js +14 -18
  406. package/dist/operating-mode/deployment-name.d.ts +19 -29
  407. package/dist/operating-mode/deployment-name.js +29 -47
  408. package/dist/operating-mode/index.d.ts +4 -25
  409. package/dist/operating-mode/index.js +9 -31
  410. package/dist/operating-mode/mode-env.d.ts +32 -54
  411. package/dist/operating-mode/mode-env.js +36 -58
  412. package/dist/operating-mode/types.d.ts +24 -72
  413. package/dist/operating-mode/types.js +1 -7
  414. package/dist/paths/branch-name.d.ts +30 -40
  415. package/dist/paths/branch-name.js +30 -40
  416. package/dist/paths/branch.d.ts +4 -18
  417. package/dist/paths/branch.js +6 -22
  418. package/dist/paths/index.d.ts +2 -13
  419. package/dist/paths/index.js +3 -23
  420. package/dist/paths/normalize-server.d.ts +3 -15
  421. package/dist/paths/normalize-server.js +3 -15
  422. package/dist/paths/normalize.d.ts +13 -33
  423. package/dist/paths/normalize.js +13 -33
  424. package/dist/paths/resolve.d.ts +4 -17
  425. package/dist/paths/resolve.js +4 -22
  426. package/dist/paths/types.d.ts +12 -34
  427. package/dist/paths/types.js +5 -7
  428. package/dist/paths/validation.d.ts +22 -119
  429. package/dist/paths/validation.js +30 -148
  430. package/dist/reference-resolver.d.ts +0 -13
  431. package/dist/reference-resolver.js +0 -18
  432. package/dist/resolve-canopy-user.d.ts +16 -18
  433. package/dist/resolve-canopy-user.js +17 -26
  434. package/dist/resource-generation.d.ts +16 -25
  435. package/dist/resource-generation.js +34 -97
  436. package/dist/schema/meta-loader.d.ts +2 -14
  437. package/dist/schema/meta-loader.js +15 -64
  438. package/dist/schema/resolver.d.ts +1 -4
  439. package/dist/schema/resolver.js +1 -6
  440. package/dist/schema/schema-store-types.d.ts +0 -12
  441. package/dist/schema/schema-store.d.ts +61 -138
  442. package/dist/schema/schema-store.js +85 -282
  443. package/dist/schema/types.d.ts +0 -4
  444. package/dist/server.d.ts +62 -93
  445. package/dist/server.js +63 -94
  446. package/dist/services.d.ts +23 -47
  447. package/dist/services.js +55 -98
  448. package/dist/settings-workspace.d.ts +17 -30
  449. package/dist/settings-workspace.js +51 -81
  450. package/dist/static/index.d.ts +26 -52
  451. package/dist/static/index.js +33 -67
  452. package/dist/{worker/task-queue.d.ts → task-queue/cms-task-queue.d.ts} +7 -9
  453. package/dist/task-queue/cms-task-queue.js +13 -0
  454. package/dist/task-queue/task-queue-config.d.ts +3 -0
  455. package/dist/{worker → task-queue}/task-queue-config.js +1 -6
  456. package/dist/task-queue/task-queue.d.ts +16 -22
  457. package/dist/task-queue/task-queue.js +20 -44
  458. package/dist/task-queue/types.d.ts +0 -1
  459. package/dist/task-queue/worker-status.d.ts +35 -0
  460. package/dist/task-queue/worker-status.js +40 -0
  461. package/dist/types.d.ts +40 -51
  462. package/dist/url-collision.d.ts +26 -40
  463. package/dist/url-collision.js +47 -63
  464. package/dist/url-exclusivity-fixtures.d.ts +15 -20
  465. package/dist/url-exclusivity-fixtures.js +14 -19
  466. package/dist/url-path-resolver.d.ts +8 -16
  467. package/dist/url-path-resolver.js +19 -29
  468. package/dist/user.d.ts +8 -21
  469. package/dist/user.js +10 -19
  470. package/dist/utils/async-mutex.js +4 -6
  471. package/dist/utils/atomic-write.d.ts +2 -11
  472. package/dist/utils/atomic-write.js +2 -11
  473. package/dist/utils/body-field.d.ts +8 -15
  474. package/dist/utils/body-field.js +8 -15
  475. package/dist/utils/content-serialize.d.ts +18 -24
  476. package/dist/utils/content-serialize.js +109 -160
  477. package/dist/utils/content-write-lock.d.ts +51 -106
  478. package/dist/utils/content-write-lock.js +66 -111
  479. package/dist/utils/debug.d.ts +7 -23
  480. package/dist/utils/debug.js +7 -23
  481. package/dist/utils/entry-url.d.ts +11 -23
  482. package/dist/utils/entry-url.js +11 -26
  483. package/dist/utils/error.d.ts +25 -90
  484. package/dist/utils/error.js +60 -147
  485. package/dist/utils/flatten-group-fields.d.ts +5 -7
  486. package/dist/utils/flatten-group-fields.js +5 -7
  487. package/dist/utils/format.d.ts +1 -5
  488. package/dist/utils/format.js +1 -5
  489. package/dist/utils/fs.d.ts +3 -4
  490. package/dist/utils/fs.js +3 -4
  491. package/dist/utils/git.d.ts +52 -83
  492. package/dist/utils/git.js +79 -125
  493. package/dist/utils/logger.d.ts +35 -50
  494. package/dist/utils/logger.js +35 -52
  495. package/dist/utils/provisioning-lock.d.ts +23 -35
  496. package/dist/utils/provisioning-lock.js +49 -69
  497. package/dist/utils/sanitize-href.d.ts +5 -10
  498. package/dist/utils/sanitize-href.js +8 -18
  499. package/dist/utils/title-field.d.ts +17 -20
  500. package/dist/utils/title-field.js +18 -27
  501. package/dist/utils/typed-filename.d.ts +20 -48
  502. package/dist/utils/typed-filename.js +25 -61
  503. package/dist/utils/url-prefix.d.ts +3 -3
  504. package/dist/utils/url-prefix.js +3 -3
  505. package/dist/validation/block-structural-keys.d.ts +16 -31
  506. package/dist/validation/block-structural-keys.js +19 -29
  507. package/dist/validation/deletion-checker.d.ts +0 -34
  508. package/dist/validation/deletion-checker.js +1 -43
  509. package/dist/validation/entry-link-validator.d.ts +6 -13
  510. package/dist/validation/entry-link-validator.js +4 -13
  511. package/dist/validation/entry-type-reference-validator.d.ts +13 -18
  512. package/dist/validation/entry-type-reference-validator.js +13 -18
  513. package/dist/validation/entry-validator.d.ts +13 -25
  514. package/dist/validation/entry-validator.js +15 -32
  515. package/dist/validation/field-traversal.d.ts +3 -30
  516. package/dist/validation/field-traversal.js +1 -32
  517. package/dist/validation/reference-validator.d.ts +5 -24
  518. package/dist/validation/reference-validator.js +5 -30
  519. package/dist/worker/cms-worker.d.ts +172 -232
  520. package/dist/worker/cms-worker.js +241 -333
  521. package/dist/worker/git-sync.d.ts +32 -133
  522. package/dist/worker/git-sync.js +129 -191
  523. package/dist/worker/github-auth.d.ts +13 -19
  524. package/dist/worker/github-auth.js +13 -19
  525. package/dist/worker/history-rewrite.d.ts +53 -66
  526. package/dist/worker/history-rewrite.js +54 -60
  527. package/dist/worker/log.d.ts +24 -41
  528. package/dist/worker/log.js +25 -42
  529. package/dist/worker/rebase.d.ts +20 -110
  530. package/dist/worker/rebase.js +279 -354
  531. package/dist/worker/task-runner.d.ts +32 -66
  532. package/dist/worker/task-runner.js +126 -162
  533. package/dist/worker/worker-context.d.ts +41 -81
  534. package/package.json +4 -4
  535. package/dist/cli/template-files/middleware-clerk.ts.template +0 -37
  536. package/dist/worker/task-queue-config.d.ts +0 -8
  537. package/dist/worker/task-queue.js +0 -19
  538. package/dist/worker/worker-status.d.ts +0 -47
  539. package/dist/worker/worker-status.js +0 -52
@@ -2,40 +2,23 @@
2
2
  * Path resolution utilities for converting between physical and logical paths.
3
3
  */
4
4
  /**
5
- * Resolve a physical collection path to its logical path.
6
- *
7
- * Physical paths contain embedded IDs (e.g., "content/authors.q52DCVPuH4ga"),
8
- * while logical paths are schema-defined (e.g., "content/authors").
9
- *
10
- * This function matches physical path segments to logical path segments,
11
- * accounting for ID suffixes in physical paths.
12
- *
13
- * @param physicalPath - The physical filesystem path with embedded IDs
14
- * @param schemaItems - Iterable of schema items to search
15
- * @returns The matching logical path, or the physical path if no match found
16
- *
17
- * @example
18
- * // Match physical to logical
19
- * resolveLogicalPath("content/authors.q52DCVPuH4ga", schemaItems)
20
- * // Returns: "content/authors"
5
+ * Resolve a physical collection path (segments carry embedded IDs, e.g.
6
+ * "content/authors.q52DCVPuH4ga") to its schema-defined logical path
7
+ * ("content/authors"), or back to the physical path when nothing matches.
21
8
  *
22
9
  * @example
23
- * // Nested collections
24
10
  * resolveLogicalPath("content/docs.ABC/api.DEF", schemaItems)
25
11
  * // Returns: "content/docs/api"
12
+ * @internal Exported for tests.
26
13
  */
27
14
  export function resolveLogicalPath(physicalPath, schemaItems) {
28
15
  const pathSegments = physicalPath.split('/');
29
16
  for (const schemaItem of schemaItems) {
30
17
  if (schemaItem.type === 'collection') {
31
18
  const logicalSegments = schemaItem.logicalPath.split('/');
32
- // Check if all logical segments match the corresponding physical segments
33
- // (ignoring the ID part after the dot in directory names)
34
19
  if (pathSegments.length === logicalSegments.length) {
35
20
  const matches = logicalSegments.every((logicalSeg, i) => {
36
21
  const physicalSeg = pathSegments[i];
37
- // Physical segment might have ID: "authors.q52DCVPuH4ga"
38
- // Logical segment: "authors"
39
22
  // Match if identical OR if physical starts with logical + '.'
40
23
  return physicalSeg === logicalSeg || physicalSeg.startsWith(logicalSeg + '.');
41
24
  });
@@ -45,6 +28,5 @@ export function resolveLogicalPath(physicalPath, schemaItems) {
45
28
  }
46
29
  }
47
30
  }
48
- // Fallback: return the physical path if we can't find a match
49
31
  return physicalPath;
50
32
  }
@@ -1,62 +1,40 @@
1
1
  /**
2
- * Path type definitions for CanopyCMS
3
- *
4
- * These branded types provide compile-time safety to prevent accidentally
5
- * mixing logical paths (content/posts/my-post) with physical filesystem
6
- * paths (content/posts/my-post.ABC123.mdx).
7
- */
8
- /**
9
- * A logical content path without embedded IDs.
10
- * Used in APIs, URLs, and user-facing contexts.
11
- * Example: "content/posts/my-post"
2
+ * Branded path types. The brands exist to stop logical paths
3
+ * (content/posts/my-post) being passed where physical filesystem paths
4
+ * (content/posts/my-post.ABC123.mdx) are expected, and vice versa.
12
5
  */
6
+ /** A content path with no embedded IDs, as APIs and URLs carry it. */
13
7
  export type LogicalPath = string & {
14
8
  readonly __brand: 'LogicalPath';
15
9
  };
16
- /**
17
- * A physical filesystem path that may contain embedded IDs.
18
- * Used for actual file operations.
19
- * Example: "content/posts/my-post.ABC123.mdx"
20
- */
10
+ /** A filesystem path, which may carry embedded IDs, as file operations need. */
21
11
  export type PhysicalPath = string & {
22
12
  readonly __brand: 'PhysicalPath';
23
13
  };
24
- /**
25
- * A branch name that has been sanitized for filesystem use.
26
- */
14
+ /** A branch name already sanitized for filesystem use. */
27
15
  export type SanitizedBranchName = string & {
28
16
  readonly __brand: 'SanitizedBranchName';
29
17
  };
30
- /**
31
- * A git branch name (before sanitization for filesystem use).
32
- * Example: "feature/add-dark-mode" or "main"
33
- */
18
+ /** A git branch name, not yet sanitized: "feature/add-dark-mode", "main". */
34
19
  export type BranchName = string & {
35
20
  readonly __brand: 'BranchName';
36
21
  };
37
22
  /**
38
- * A 12-character Base58-encoded content ID.
39
- * Used to uniquely identify entries and collections in filenames.
40
- * Example: "bChqT78gcaLd"
23
+ * A 12-character Base58 content ID ("bChqT78gcaLd"), which uniquely identifies
24
+ * an entry or collection within a filename.
41
25
  */
42
26
  export type ContentId = string & {
43
27
  readonly __brand: 'ContentId';
44
28
  };
45
29
  /**
46
- * Sentinel ContentId for the root content directory (which has no embedded ID in its name).
47
- * Uses underscores — can never collide with real 12-char Base58 IDs (which exclude `_`).
30
+ * Sentinel ContentId for the root content directory, whose name carries no
31
+ * embedded ID. Underscores cannot collide with Base58 IDs, which exclude `_`.
48
32
  */
49
33
  export declare const ROOT_COLLECTION_ID: ContentId;
50
- /**
51
- * A validated, lowercase slug used for collections and entries.
52
- * Example: "posts", "my-first-post", "getting-started"
53
- */
34
+ /** A validated, lowercase collection or entry slug: "my-first-post". */
54
35
  export type Slug = string & {
55
36
  readonly __brand: 'Slug';
56
37
  };
57
- /**
58
- * Path validation result.
59
- */
60
38
  export interface PathValidationResult {
61
39
  valid: boolean;
62
40
  error?: string;
@@ -1,12 +1,10 @@
1
1
  /**
2
- * Path type definitions for CanopyCMS
3
- *
4
- * These branded types provide compile-time safety to prevent accidentally
5
- * mixing logical paths (content/posts/my-post) with physical filesystem
6
- * paths (content/posts/my-post.ABC123.mdx).
2
+ * Branded path types. The brands exist to stop logical paths
3
+ * (content/posts/my-post) being passed where physical filesystem paths
4
+ * (content/posts/my-post.ABC123.mdx) are expected, and vice versa.
7
5
  */
8
6
  /**
9
- * Sentinel ContentId for the root content directory (which has no embedded ID in its name).
10
- * Uses underscores — can never collide with real 12-char Base58 IDs (which exclude `_`).
7
+ * Sentinel ContentId for the root content directory, whose name carries no
8
+ * embedded ID. Underscores cannot collide with Base58 IDs, which exclude `_`.
11
9
  */
12
10
  export const ROOT_COLLECTION_ID = '__rootcoll__';
@@ -1,82 +1,40 @@
1
- /**
2
- * Path validation utilities.
3
- *
4
- * Security-focused validation for content paths and slugs.
5
- */
1
+ /** Security-focused validation for content paths, IDs, branch names and slugs. */
6
2
  import type { LogicalPath, PhysicalPath, ContentId, BranchName, Slug } from './types.js';
7
3
  /**
8
- * Validate a content path for security.
9
- *
10
- * @param path - The path to validate
11
- * @param rootPath - The root directory (for traversal check)
12
- * @returns Validation result
4
+ * Reject a content path that traverses, or that escapes `rootPath`.
5
+ * @internal Exported for tests.
13
6
  */
14
7
  export declare function validateContentPath(path: string, rootPath: string): {
15
8
  valid: boolean;
16
9
  error?: string;
17
10
  };
18
11
  /**
19
- * Validate a collection path.
20
- *
21
- * @param collectionPath - The collection path to validate
22
- * @returns true if valid, false otherwise
12
+ * A collection path must be non-empty, traversal-free, and `[A-Za-z0-9_/-]+`.
13
+ * @internal Exported for tests.
23
14
  */
24
15
  export declare function isValidCollectionPath(collectionPath: string): boolean;
25
16
  /**
26
- * Sanitize a string for use in paths by removing dangerous characters.
27
- *
28
- * @param input - The string to sanitize
29
- * @returns Sanitized string safe for path use
17
+ * Strip the characters that make a string unsafe as a path component.
18
+ * @internal Exported for tests.
30
19
  */
31
20
  export declare function sanitizeForPath(input: string): string;
32
21
  /**
33
- * Check if a path segment contains an embedded content ID.
34
- *
35
- * Physical paths have segments with embedded 12-char IDs:
36
- * - `post.my-slug.abc123def456.json` (entry file)
37
- * - `posts.abc123def456` (collection directory)
38
- *
39
- * @param segment - A single path segment (no slashes)
40
- * @returns true if segment contains embedded ID pattern
22
+ * Whether a single path segment (no slashes) carries an embedded content ID.
23
+ * @internal Exported for tests.
41
24
  */
42
25
  export declare function hasEmbeddedContentId(segment: string): boolean;
43
26
  /**
44
- * Check if a path appears to be a physical path (contains embedded content IDs).
45
- *
46
- * Physical paths have the format:
47
- * - `content/posts.abc123/post.hello.def456.json`
48
- *
49
- * Logical paths do not have embedded IDs:
50
- * - `content/posts/hello` or `posts/hello`
51
- *
52
- * @param path - The path to check
53
- * @returns true if any segment contains an embedded content ID
27
+ * Whether any segment carries an embedded content ID:
28
+ * `content/posts.abc123/post.hello.def456.json` does, `content/posts/hello`
29
+ * does not.
30
+ * @internal Exported for tests.
54
31
  */
55
32
  export declare function looksLikePhysicalPath(path: string): boolean;
56
- /**
57
- * Check if a path appears to be a logical path (no embedded content IDs).
58
- *
59
- * @param path - The path to check
60
- * @returns true if no segments contain embedded content IDs
61
- */
33
+ /** @internal Exported for tests. */
62
34
  export declare function looksLikeLogicalPath(path: string): boolean;
63
35
  /**
64
- * Validate and cast a string to LogicalPath.
65
- *
66
- * Use this at API boundaries to validate incoming path strings
67
- * and cast them to the branded LogicalPath type.
68
- *
69
- * @param path - The path string to validate
70
- * @returns Object with success flag and either the typed path or an error
71
- *
72
- * @example
73
- * ```ts
74
- * const result = parseLogicalPath(params.collectionPath)
75
- * if (!result.ok) {
76
- * return { ok: false, status: 400, error: result.error }
77
- * }
78
- * const collectionPath: LogicalPath = result.path
79
- * ```
36
+ * Validate an incoming path string at an API boundary and cast it to the
37
+ * branded LogicalPath type.
80
38
  */
81
39
  export declare function parseLogicalPath(path: string): {
82
40
  ok: true;
@@ -86,13 +44,9 @@ export declare function parseLogicalPath(path: string): {
86
44
  error: string;
87
45
  };
88
46
  /**
89
- * Validate and cast a string to PhysicalPath.
90
- *
91
- * Use this at API boundaries to validate incoming path strings
92
- * and cast them to the branded PhysicalPath type.
93
- *
94
- * @param path - The path string to validate
95
- * @returns Object with success flag and either the typed path or an error
47
+ * Validate an incoming path string at an API boundary and cast it to the
48
+ * branded PhysicalPath type.
49
+ * @internal Exported for tests.
96
50
  */
97
51
  export declare function parsePhysicalPath(path: string): {
98
52
  ok: true;
@@ -101,29 +55,8 @@ export declare function parsePhysicalPath(path: string): {
101
55
  ok: false;
102
56
  error: string;
103
57
  };
104
- /**
105
- * Check if a string is a valid 12-character content ID.
106
- *
107
- * @param id - The string to check
108
- * @returns true if valid Base58 12-char ID
109
- */
110
58
  export declare function isValidContentId(id: string): boolean;
111
- /**
112
- * Parse and validate a ContentId from a string.
113
- * Validates Base58 format and 12-character length.
114
- *
115
- * @param id - The string to validate
116
- * @returns Object with success flag and either the typed ID or an error
117
- *
118
- * @example
119
- * ```ts
120
- * const result = parseContentId(fileId)
121
- * if (!result.ok) {
122
- * throw new Error(result.error)
123
- * }
124
- * const contentId: ContentId = result.id
125
- * ```
126
- */
59
+ /** Validate a string as a 12-character Base58 ContentId and cast it. */
127
60
  export declare function parseContentId(id: string): {
128
61
  ok: true;
129
62
  id: ContentId;
@@ -131,22 +64,7 @@ export declare function parseContentId(id: string): {
131
64
  ok: false;
132
65
  error: string;
133
66
  };
134
- /**
135
- * Parse and validate a BranchName.
136
- * Checks git branch naming rules.
137
- *
138
- * @param name - The branch name to validate
139
- * @returns Object with success flag and either the typed name or an error
140
- *
141
- * @example
142
- * ```ts
143
- * const result = parseBranchName(params.branch)
144
- * if (!result.ok) {
145
- * return { ok: false, status: 400, error: result.error }
146
- * }
147
- * const branchName: BranchName = result.name
148
- * ```
149
- */
67
+ /** Validate a branch name against git's ref rules and cast it to BranchName. */
150
68
  export declare function parseBranchName(name: string): {
151
69
  ok: true;
152
70
  name: BranchName;
@@ -154,22 +72,7 @@ export declare function parseBranchName(name: string): {
154
72
  ok: false;
155
73
  error: string;
156
74
  };
157
- /**
158
- * Parse and validate a slug (collection or entry).
159
- * Validates format and length constraints.
160
- *
161
- * @param slug - The slug to validate
162
- * @returns Object with success flag and either the typed slug or an error
163
- *
164
- * @example
165
- * ```ts
166
- * const result = parseSlug(params.slug)
167
- * if (!result.ok) {
168
- * return { ok: false, status: 400, error: result.error }
169
- * }
170
- * const slug: Slug = result.slug
171
- * ```
172
- */
75
+ /** Validate a collection or entry slug and cast it to Slug. */
173
76
  export declare function parseSlug(slug: string): {
174
77
  ok: true;
175
78
  slug: Slug;
@@ -1,41 +1,25 @@
1
- /**
2
- * Path validation utilities.
3
- *
4
- * Security-focused validation for content paths and slugs.
5
- */
1
+ /** Security-focused validation for content paths, IDs, branch names and slugs. */
6
2
  import { normalizeFilesystemPath, hasTraversalSequence } from './normalize.js';
7
- /**
8
- * Base58 alphabet used for content IDs (excludes ambiguous: 0, O, I, l)
9
- */
3
+ /** Base58 alphabet for content IDs: excludes the ambiguous 0, O, I and l. */
10
4
  const BASE58_PATTERN = '[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]';
11
- /**
12
- * Pattern matching exactly a 12-character content ID
13
- */
14
5
  const CONTENT_ID_PATTERN = new RegExp(`^${BASE58_PATTERN}{12}$`);
15
6
  /**
16
- * Pattern matching a physical path segment with embedded ID.
17
- * Matches patterns like:
18
- * - `post.my-slug.abc123def456.json` (entry)
19
- * - `posts.abc123def456` (collection directory)
7
+ * A physical path segment carries an embedded ID: `posts.abc123def456` for a
8
+ * collection directory, `post.my-slug.abc123def456.json` for an entry file.
20
9
  */
21
10
  const PHYSICAL_SEGMENT_PATTERN = new RegExp(`\\.${BASE58_PATTERN}{12}(?:\\.[a-z]+)?$`);
22
11
  /**
23
- * Validate a content path for security.
24
- *
25
- * @param path - The path to validate
26
- * @param rootPath - The root directory (for traversal check)
27
- * @returns Validation result
12
+ * Reject a content path that traverses, or that escapes `rootPath`.
13
+ * @internal Exported for tests.
28
14
  */
29
15
  export function validateContentPath(path, rootPath) {
30
16
  const normalized = normalizeFilesystemPath(path);
31
- // Check for traversal sequences
32
17
  if (hasTraversalSequence(normalized)) {
33
18
  return { valid: false, error: 'Path contains traversal sequence' };
34
19
  }
35
- // Check path doesn't escape root
36
20
  const normalizedRoot = normalizeFilesystemPath(rootPath);
37
21
  if (!normalized.startsWith(normalizedRoot) && normalized !== normalizedRoot) {
38
- // Allow paths that are relative within the root
22
+ // Not already rooted: re-check as a path relative to the root.
39
23
  const normalizedPath = `${normalizedRoot}/${normalized}`;
40
24
  if (hasTraversalSequence(normalizedPath)) {
41
25
  return { valid: false, error: 'Path escapes root directory' };
@@ -44,29 +28,23 @@ export function validateContentPath(path, rootPath) {
44
28
  return { valid: true };
45
29
  }
46
30
  /**
47
- * Validate a collection path.
48
- *
49
- * @param collectionPath - The collection path to validate
50
- * @returns true if valid, false otherwise
31
+ * A collection path must be non-empty, traversal-free, and `[A-Za-z0-9_/-]+`.
32
+ * @internal Exported for tests.
51
33
  */
52
34
  export function isValidCollectionPath(collectionPath) {
53
35
  if (!collectionPath || collectionPath.length === 0) {
54
36
  return false;
55
37
  }
56
- // Normalize and check for traversal
57
38
  const normalized = normalizeFilesystemPath(collectionPath);
58
39
  if (hasTraversalSequence(normalized)) {
59
40
  return false;
60
41
  }
61
- // Collection paths should only contain alphanumeric, hyphens, underscores, and forward slashes
62
42
  const validPattern = /^[a-zA-Z0-9_/-]+$/;
63
43
  return validPattern.test(normalized);
64
44
  }
65
45
  /**
66
- * Sanitize a string for use in paths by removing dangerous characters.
67
- *
68
- * @param input - The string to sanitize
69
- * @returns Sanitized string safe for path use
46
+ * Strip the characters that make a string unsafe as a path component.
47
+ * @internal Exported for tests.
70
48
  */
71
49
  export function sanitizeForPath(input) {
72
50
  return input
@@ -76,73 +54,39 @@ export function sanitizeForPath(input) {
76
54
  .trim();
77
55
  }
78
56
  /**
79
- * Check if a path segment contains an embedded content ID.
80
- *
81
- * Physical paths have segments with embedded 12-char IDs:
82
- * - `post.my-slug.abc123def456.json` (entry file)
83
- * - `posts.abc123def456` (collection directory)
84
- *
85
- * @param segment - A single path segment (no slashes)
86
- * @returns true if segment contains embedded ID pattern
57
+ * Whether a single path segment (no slashes) carries an embedded content ID.
58
+ * @internal Exported for tests.
87
59
  */
88
60
  export function hasEmbeddedContentId(segment) {
89
61
  return PHYSICAL_SEGMENT_PATTERN.test(segment);
90
62
  }
91
63
  /**
92
- * Check if a path appears to be a physical path (contains embedded content IDs).
93
- *
94
- * Physical paths have the format:
95
- * - `content/posts.abc123/post.hello.def456.json`
96
- *
97
- * Logical paths do not have embedded IDs:
98
- * - `content/posts/hello` or `posts/hello`
99
- *
100
- * @param path - The path to check
101
- * @returns true if any segment contains an embedded content ID
64
+ * Whether any segment carries an embedded content ID:
65
+ * `content/posts.abc123/post.hello.def456.json` does, `content/posts/hello`
66
+ * does not.
67
+ * @internal Exported for tests.
102
68
  */
103
69
  export function looksLikePhysicalPath(path) {
104
70
  const segments = path.split('/');
105
71
  return segments.some(hasEmbeddedContentId);
106
72
  }
107
- /**
108
- * Check if a path appears to be a logical path (no embedded content IDs).
109
- *
110
- * @param path - The path to check
111
- * @returns true if no segments contain embedded content IDs
112
- */
73
+ /** @internal Exported for tests. */
113
74
  export function looksLikeLogicalPath(path) {
114
75
  return !looksLikePhysicalPath(path);
115
76
  }
116
77
  /**
117
- * Validate and cast a string to LogicalPath.
118
- *
119
- * Use this at API boundaries to validate incoming path strings
120
- * and cast them to the branded LogicalPath type.
121
- *
122
- * @param path - The path string to validate
123
- * @returns Object with success flag and either the typed path or an error
124
- *
125
- * @example
126
- * ```ts
127
- * const result = parseLogicalPath(params.collectionPath)
128
- * if (!result.ok) {
129
- * return { ok: false, status: 400, error: result.error }
130
- * }
131
- * const collectionPath: LogicalPath = result.path
132
- * ```
78
+ * Validate an incoming path string at an API boundary and cast it to the
79
+ * branded LogicalPath type.
133
80
  */
134
81
  export function parseLogicalPath(path) {
135
- // Basic validation
136
82
  if (!path || typeof path !== 'string') {
137
83
  return { ok: false, error: 'Path is required' };
138
84
  }
139
- // Normalize backslashes to forward slashes (consistent with parsePermissionPath)
85
+ // One separator in the branded value, as in parsePermissionPath.
140
86
  const normalized = path.replace(/\\/g, '/');
141
- // Security check
142
87
  if (hasTraversalSequence(normalized)) {
143
88
  return { ok: false, error: 'Path contains traversal sequence' };
144
89
  }
145
- // Check it's not a physical path
146
90
  if (looksLikePhysicalPath(normalized)) {
147
91
  return {
148
92
  ok: false,
@@ -152,26 +96,19 @@ export function parseLogicalPath(path) {
152
96
  return { ok: true, path: normalized };
153
97
  }
154
98
  /**
155
- * Validate and cast a string to PhysicalPath.
156
- *
157
- * Use this at API boundaries to validate incoming path strings
158
- * and cast them to the branded PhysicalPath type.
159
- *
160
- * @param path - The path string to validate
161
- * @returns Object with success flag and either the typed path or an error
99
+ * Validate an incoming path string at an API boundary and cast it to the
100
+ * branded PhysicalPath type.
101
+ * @internal Exported for tests.
162
102
  */
163
103
  export function parsePhysicalPath(path) {
164
- // Basic validation
165
104
  if (!path || typeof path !== 'string') {
166
105
  return { ok: false, error: 'Path is required' };
167
106
  }
168
- // Normalize backslashes to forward slashes (consistent with parseLogicalPath)
107
+ // One separator in the branded value, as in parseLogicalPath.
169
108
  const normalized = path.replace(/\\/g, '/');
170
- // Security check
171
109
  if (hasTraversalSequence(normalized)) {
172
110
  return { ok: false, error: 'Path contains traversal sequence' };
173
111
  }
174
- // Check it looks like a physical path
175
112
  if (!looksLikePhysicalPath(normalized)) {
176
113
  return {
177
114
  ok: false,
@@ -180,31 +117,10 @@ export function parsePhysicalPath(path) {
180
117
  }
181
118
  return { ok: true, path: normalized };
182
119
  }
183
- /**
184
- * Check if a string is a valid 12-character content ID.
185
- *
186
- * @param id - The string to check
187
- * @returns true if valid Base58 12-char ID
188
- */
189
120
  export function isValidContentId(id) {
190
121
  return CONTENT_ID_PATTERN.test(id);
191
122
  }
192
- /**
193
- * Parse and validate a ContentId from a string.
194
- * Validates Base58 format and 12-character length.
195
- *
196
- * @param id - The string to validate
197
- * @returns Object with success flag and either the typed ID or an error
198
- *
199
- * @example
200
- * ```ts
201
- * const result = parseContentId(fileId)
202
- * if (!result.ok) {
203
- * throw new Error(result.error)
204
- * }
205
- * const contentId: ContentId = result.id
206
- * ```
207
- */
123
+ /** Validate a string as a 12-character Base58 ContentId and cast it. */
208
124
  export function parseContentId(id) {
209
125
  if (!id || typeof id !== 'string') {
210
126
  return { ok: false, error: 'Content ID is required' };
@@ -217,22 +133,7 @@ export function parseContentId(id) {
217
133
  }
218
134
  return { ok: true, id: id };
219
135
  }
220
- /**
221
- * Parse and validate a BranchName.
222
- * Checks git branch naming rules.
223
- *
224
- * @param name - The branch name to validate
225
- * @returns Object with success flag and either the typed name or an error
226
- *
227
- * @example
228
- * ```ts
229
- * const result = parseBranchName(params.branch)
230
- * if (!result.ok) {
231
- * return { ok: false, status: 400, error: result.error }
232
- * }
233
- * const branchName: BranchName = result.name
234
- * ```
235
- */
136
+ /** Validate a branch name against git's ref rules and cast it to BranchName. */
236
137
  export function parseBranchName(name) {
237
138
  if (!name || typeof name !== 'string') {
238
139
  return { ok: false, error: 'Branch name is required' };
@@ -241,7 +142,6 @@ export function parseBranchName(name) {
241
142
  if (name.length > 250) {
242
143
  return { ok: false, error: 'Branch name too long (max 250 characters)' };
243
144
  }
244
- // Git branch name rules
245
145
  if (name.includes('..')) {
246
146
  return { ok: false, error: 'Branch name cannot contain ".."' };
247
147
  }
@@ -257,16 +157,14 @@ export function parseBranchName(name) {
257
157
  if (name.startsWith('-')) {
258
158
  return { ok: false, error: 'Branch name cannot start with "-"' };
259
159
  }
260
- // Additional git restrictions
261
160
  if (name.startsWith('.') || name.endsWith('.')) {
262
161
  return { ok: false, error: 'Branch name cannot start or end with a dot' };
263
162
  }
264
163
  if (name.includes('@{')) {
265
164
  return { ok: false, error: 'Branch name cannot contain "@{"' };
266
165
  }
267
- // Bare reserved refs: "HEAD" and "@" are ambiguous shorthand for the
268
- // current ref, not real branch names (still allow names that merely
269
- // contain these as a substring, e.g. "release-HEAD" or "HEADer").
166
+ // Bare "HEAD" and "@" are ambiguous shorthand for the current ref, not real
167
+ // branch names. Names merely containing them ("release-HEAD") stay legal.
270
168
  if (name === 'HEAD' || name === '@') {
271
169
  return { ok: false, error: 'Branch name cannot be the reserved ref "HEAD" or "@"' };
272
170
  }
@@ -280,22 +178,7 @@ export function parseBranchName(name) {
280
178
  }
281
179
  return { ok: true, name: name };
282
180
  }
283
- /**
284
- * Parse and validate a slug (collection or entry).
285
- * Validates format and length constraints.
286
- *
287
- * @param slug - The slug to validate
288
- * @returns Object with success flag and either the typed slug or an error
289
- *
290
- * @example
291
- * ```ts
292
- * const result = parseSlug(params.slug)
293
- * if (!result.ok) {
294
- * return { ok: false, status: 400, error: result.error }
295
- * }
296
- * const slug: Slug = result.slug
297
- * ```
298
- */
181
+ /** Validate a collection or entry slug and cast it to Slug. */
299
182
  export function parseSlug(slug) {
300
183
  if (!slug) {
301
184
  return {
@@ -307,7 +190,6 @@ export function parseSlug(slug) {
307
190
  if (slug.length > 64) {
308
191
  return { ok: false, error: 'Slug too long (max 64 characters)' };
309
192
  }
310
- // Check for path separators and traversal
311
193
  if (slug.includes('/') || slug.includes('\\')) {
312
194
  return {
313
195
  ok: false,