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
@@ -1,37 +1,28 @@
1
- /**
2
- * Branch-level authorization
3
- *
4
- * Handles checking if a user can access a branch based on ACLs.
5
- */
6
1
  import type { BranchContext } from '../types.js';
7
2
  import type { CanopyConfig, DefaultBranchAccess } from '../config/index.js';
8
3
  import type { CanopyUser } from '../user.js';
9
4
  import type { BranchAccessResult } from './types.js';
10
5
  /** Options narrowing {@link checkBranchAccessWithDefault} to a specific branch's nature. */
11
- export interface BranchAccessOptions {
6
+ interface BranchAccessOptions {
12
7
  /**
13
8
  * Whether this is the protected base branch -- pass
14
- * `getBranchProtection(...).isProtected`. When true, the branch passes this
15
- * layer wherever no explicit ACL decided the question, and the PATH layer alone
16
- * decides what is readable. Explicit ACL verdicts still win in both directions
17
- * (see the comment at the fallback site).
9
+ * `getBranchProtection(...).isProtected`. When true the branch passes this
10
+ * layer wherever no explicit ACL decided the question, leaving the PATH layer
11
+ * to decide what is readable; explicit ACL verdicts still win in both
12
+ * directions (see the fallback site below).
18
13
  *
19
- * This grant is load-bearing, not a convenience. The base branch takes no ACL
20
- * (`updateBranchAccessHandler` rejects one outright, because an entry there
21
- * would feed `allowed_by_acl` and confer Withdraw rights) and its `createdBy`
22
- * is `canopycms-system`, so nobody is its creator. Without this, the branch
23
- * every user lands on is unreachable under `defaultBranchAccess: 'deny'` with
24
- * no way to configure around it -- which is what made 'deny' unusable for any
25
- * site with non-admin editors.
26
- *
27
- * It cannot widen anything dangerous: workflow actions stay blocked because
28
- * {@link canPerformWorkflowAction} disables its system-branch grant on the
29
- * same flag, prod writes stay blocked by `getBranchWriteProtection().readOnly`,
30
- * and the editor API 401s anonymous callers before authorization runs. What it
31
- * buys is that a public-read `deployedAs: 'server'` site can run 'deny' with
14
+ * The grant is load-bearing: the base branch takes no ACL
15
+ * (`updateBranchAccessHandler` rejects one, since an entry there would feed
16
+ * `allowed_by_acl` and confer Withdraw rights) and its `createdBy` is
17
+ * `canopycms-system`, so nobody is its creator -- without this it is
18
+ * unreachable under `defaultBranchAccess: 'deny'` with no way to configure
19
+ * around it. It widens nothing dangerous: {@link canPerformWorkflowAction}
20
+ * disables its system-branch grant on the same flag, prod writes stay blocked
21
+ * by `getBranchWriteProtection().readOnly`, and the editor API 401s anonymous
22
+ * callers before authorization runs. What it buys: a public-read
23
+ * `deployedAs: 'server'` site can run 'deny' with
32
24
  * `defaultPathAccess: { read: 'allow' }` and still keep un-ACL'd work branches
33
- * private -- previously that required the blunt `defaultBranchAccess: 'allow'`,
34
- * which opened every work branch too.
25
+ * private.
35
26
  */
36
27
  isProtectedBranch?: boolean;
37
28
  }
@@ -46,14 +37,13 @@ export interface BranchAccessOptions {
46
37
  * 4. With no ACL: the branch creator, then `defaultAccess`, and only where that
47
38
  * would deny, the protected base branch grant
48
39
  * (see {@link BranchAccessOptions.isProtectedBranch})
40
+ * @internal Exported for tests.
49
41
  */
50
42
  export declare function checkBranchAccessWithDefault(context: BranchContext, user: CanopyUser, defaultAccess?: DefaultBranchAccess, options?: BranchAccessOptions): BranchAccessResult;
51
43
  /**
52
- * Create a branch access checker with bound default access.
53
- *
54
- * `config` is needed to resolve whether a branch is the protected base branch;
55
- * it routes through `getBranchProtection`, the single source of truth for that
56
- * question, rather than repeating the base-branch test here.
44
+ * Bind a default access level. `config` is needed only to resolve the
45
+ * protected-base-branch question, which routes through `getBranchProtection`,
46
+ * its single source of truth, rather than repeating the comparison here.
57
47
  */
58
48
  export declare function createCheckBranchAccess(defaultAccess?: DefaultBranchAccess, config?: Pick<CanopyConfig, 'mode' | 'defaultBaseBranch'>): (context: BranchContext, user: CanopyUser) => BranchAccessResult;
59
49
  /** Options tightening {@link canPerformWorkflowAction} beyond the default hybrid model. */
@@ -65,29 +55,20 @@ export interface WorkflowActionOptions {
65
55
  * -- pass `getBranchProtection(...).isProtected` here so only
66
56
  * admins/reviewers/explicit-ACL users retain workflow rights on it.
67
57
  *
68
- * It is also forwarded to {@link checkBranchAccessWithDefault}, where the same
69
- * flag GRANTS access (see {@link BranchAccessOptions.isProtectedBranch}). The
70
- * two pull in opposite directions on purpose, and that is exactly the intended
71
- * base-branch posture: readable by anyone the path layer permits, submittable
72
- * by no one. The access layer says yes, then `isSystemBranch` below is false,
73
- * so a non-creator/non-ACL/non-privileged user still gets `false` here.
58
+ * The same flag GRANTS access in {@link checkBranchAccessWithDefault} (see
59
+ * {@link BranchAccessOptions.isProtectedBranch}); pulling in opposite
60
+ * directions is the intended base-branch posture -- readable by anyone the
61
+ * path layer permits, submittable by no one.
74
62
  */
75
63
  isProtectedBranch?: boolean;
76
64
  }
77
65
  /**
78
- * Check if user can perform workflow actions (submit/withdraw) on a branch.
79
- * Allowed if: user is creator OR user has ACL access OR (system branch AND user has general access).
80
- *
81
- * This implements a hybrid permission model:
82
- * - Branch creators can always submit/withdraw their branches
83
- * - Users explicitly listed in branch ACLs can also submit/withdraw
84
- * - For system branches (createdBy: 'canopycms-system'), anyone with general access can submit/withdraw
85
- * - Admins and Reviewers always have access (via checkBranchAccess)
86
- * - Unless `options.isProtectedBranch` is set, in which case the system-branch
87
- * grant above is disabled (see {@link WorkflowActionOptions})
66
+ * Whether a user may submit/withdraw a branch: creator, OR ACL access, OR a
67
+ * system branch plus general access.
88
68
  *
89
- * The creator grant is enforced twice over: `checkBranchAccessWithDefault` now
90
- * admits the creator (so the gate below no longer swallows them under
91
- * `defaultBranchAccess: 'deny'`), and `userIsCreator` still decides the result.
69
+ * The creator grant is enforced twice: `checkBranchAccessWithDefault` admits
70
+ * the creator, so the gate below cannot swallow them under
71
+ * `defaultBranchAccess: 'deny'`, and `userIsCreator` decides the result.
92
72
  */
93
73
  export declare function canPerformWorkflowAction(context: BranchContext, user: CanopyUser, defaultAccess?: DefaultBranchAccess, options?: WorkflowActionOptions): boolean;
74
+ export {};
@@ -1,8 +1,3 @@
1
- /**
2
- * Branch-level authorization
3
- *
4
- * Handles checking if a user can access a branch based on ACLs.
5
- */
6
1
  import { isAdmin, isReviewer } from './helpers.js';
7
2
  import { getBranchProtection } from './protected-branch.js';
8
3
  /**
@@ -16,9 +11,9 @@ import { getBranchProtection } from './protected-branch.js';
16
11
  * 4. With no ACL: the branch creator, then `defaultAccess`, and only where that
17
12
  * would deny, the protected base branch grant
18
13
  * (see {@link BranchAccessOptions.isProtectedBranch})
14
+ * @internal Exported for tests.
19
15
  */
20
16
  export function checkBranchAccessWithDefault(context, user, defaultAccess = 'deny', options) {
21
- // Admins and Reviewers have full branch access
22
17
  if (isAdmin(user.groups) || isReviewer(user.groups)) {
23
18
  return { allowed: true, reason: 'privileged' };
24
19
  }
@@ -30,16 +25,13 @@ export function checkBranchAccessWithDefault(context, user, defaultAccess = 'den
30
25
  return { allowed: false, reason: 'denied_by_acl' };
31
26
  }
32
27
  if (!hasUserConstraint && !hasGroupConstraint) {
33
- // The branch creator owns their own un-ACL'd branch. This matches the three
34
- // places the server already grants on creator-ownership independently of
35
- // branch access (listBranchesHandler, canDeleteBranch, canModifyBranchAccess)
36
- // -- without it, under 'deny' a creator could delete their branch and rewrite
37
- // its ACL but not read a single file on it.
38
- //
39
- // Deliberately scoped to the no-ACL case: an EXPLICIT allowlist that omits
40
- // the creator still denies them, because that is how an admin locks down a
41
- // branch someone else created. Granting creator ahead of the ACL would make
42
- // that lockdown silently ineffective.
28
+ // The branch creator owns their own un-ACL'd branch, matching the three
29
+ // places that already grant on creator-ownership independently of branch
30
+ // access (listBranchesHandler, canDeleteBranch, canModifyBranchAccess):
31
+ // without it, under 'deny' a creator could delete their branch and rewrite
32
+ // its ACL but not read a file on it. Scoped to the no-ACL case on purpose --
33
+ // an EXPLICIT allowlist omitting the creator still denies them, which is how
34
+ // an admin locks down a branch someone else created.
43
35
  if (context.branch.createdBy === user.userId) {
44
36
  return { allowed: true, reason: 'creator' };
45
37
  }
@@ -61,11 +53,9 @@ export function checkBranchAccessWithDefault(context, user, defaultAccess = 'den
61
53
  return { allowed, reason: allowed ? 'allowed_by_acl' : 'denied_by_acl' };
62
54
  }
63
55
  /**
64
- * Create a branch access checker with bound default access.
65
- *
66
- * `config` is needed to resolve whether a branch is the protected base branch;
67
- * it routes through `getBranchProtection`, the single source of truth for that
68
- * question, rather than repeating the base-branch test here.
56
+ * Bind a default access level. `config` is needed only to resolve the
57
+ * protected-base-branch question, which routes through `getBranchProtection`,
58
+ * its single source of truth, rather than repeating the comparison here.
69
59
  */
70
60
  export function createCheckBranchAccess(defaultAccess = 'deny', config) {
71
61
  return (context, user) => checkBranchAccessWithDefault(context, user, defaultAccess, {
@@ -75,38 +65,22 @@ export function createCheckBranchAccess(defaultAccess = 'deny', config) {
75
65
  });
76
66
  }
77
67
  /**
78
- * Check if user can perform workflow actions (submit/withdraw) on a branch.
79
- * Allowed if: user is creator OR user has ACL access OR (system branch AND user has general access).
80
- *
81
- * This implements a hybrid permission model:
82
- * - Branch creators can always submit/withdraw their branches
83
- * - Users explicitly listed in branch ACLs can also submit/withdraw
84
- * - For system branches (createdBy: 'canopycms-system'), anyone with general access can submit/withdraw
85
- * - Admins and Reviewers always have access (via checkBranchAccess)
86
- * - Unless `options.isProtectedBranch` is set, in which case the system-branch
87
- * grant above is disabled (see {@link WorkflowActionOptions})
68
+ * Whether a user may submit/withdraw a branch: creator, OR ACL access, OR a
69
+ * system branch plus general access.
88
70
  *
89
- * The creator grant is enforced twice over: `checkBranchAccessWithDefault` now
90
- * admits the creator (so the gate below no longer swallows them under
91
- * `defaultBranchAccess: 'deny'`), and `userIsCreator` still decides the result.
71
+ * The creator grant is enforced twice: `checkBranchAccessWithDefault` admits
72
+ * the creator, so the gate below cannot swallow them under
73
+ * `defaultBranchAccess: 'deny'`, and `userIsCreator` decides the result.
92
74
  */
93
75
  export function canPerformWorkflowAction(context, user, defaultAccess = 'deny', options) {
94
- // Check if user has general branch access (handles admins, reviewers, creator, ACLs)
95
76
  const accessResult = checkBranchAccessWithDefault(context, user, defaultAccess, {
96
77
  isProtectedBranch: options?.isProtectedBranch,
97
78
  });
98
- // If user doesn't have basic branch access, deny immediately
99
79
  if (!accessResult.allowed) {
100
80
  return false;
101
81
  }
102
- // Check if user is the branch creator
103
82
  const userIsCreator = context.branch.createdBy === user.userId;
104
- // Check if this is a system-created branch (grant disabled on protected branches)
105
83
  const isSystemBranch = !options?.isProtectedBranch && context.branch.createdBy === 'canopycms-system';
106
- // Allow if:
107
- // 1. User is the creator, OR
108
- // 2. User has ACL access (reason: 'privileged' or 'allowed_by_acl'), OR
109
- // 3. System branch with general access
110
84
  return (userIsCreator ||
111
85
  accessResult.reason === 'privileged' ||
112
86
  accessResult.reason === 'allowed_by_acl' ||
@@ -1,18 +1,6 @@
1
1
  /**
2
- * Content access authorization
3
- *
4
- * This is the main entry point for authorization checks. It combines
5
- * branch-level and path-level access checks into a single API.
6
- *
7
- * Usage:
8
- * ```ts
9
- * import { checkContentAccess } from './authorization.js'
10
- *
11
- * const result = await checkContentAccess(deps, context, branchRoot, 'content/posts/my-post.mdx', user, 'edit')
12
- * if (result.allowed) {
13
- * // User can edit the file
14
- * }
15
- * ```
2
+ * Main entry point for authorization checks: combines branch-level and
3
+ * path-level access into a single API.
16
4
  */
17
5
  import type { BranchContext } from '../types.js';
18
6
  import type { PermissionLevel } from '../config/index.js';
@@ -25,35 +13,18 @@ import type { PhysicalPath } from '../paths/types.js';
25
13
  */
26
14
  export type ContentAccessChecker = (relativePath: PhysicalPath, level: PermissionLevel) => ContentAccessResult;
27
15
  /**
28
- * Create a content-access checker that resolves the request-constant work once
29
- * (branch access, the settings/permissions root, and the path-permission rules)
30
- * and returns a synchronous per-path checker.
31
- *
32
- * Branch access, the resolved permissions root, and the loaded rules are identical
33
- * for a fixed `(context, branchRoot, user)`, so hoisting them out of the per-path
34
- * check avoids re-reading the permissions file (and, in modes with a separate
35
- * settings branch, re-ensuring the settings workspace) for every entry. This is
36
- * the batch primitive used by listing endpoints that check many paths per request.
37
- *
38
- * @param deps - Dependencies including branch access checker and path permissions loader
39
- * @param context - Branch context containing branch metadata
40
- * @param branchRoot - Root directory of the branch
41
- * @param user - User to check access for
16
+ * Resolve the request-constant work once -- branch access, the
17
+ * settings/permissions root and the path-permission rules, all identical for a
18
+ * fixed `(context, branchRoot, user)` -- and return a synchronous per-path
19
+ * checker. Hoisting it avoids re-reading the permissions file (and, in modes
20
+ * with a separate settings branch, re-ensuring the settings workspace) for
21
+ * every entry. This is the batch primitive for listing endpoints that check
22
+ * many paths per request.
42
23
  */
43
24
  export declare function createContentAccessChecker(deps: ContentAccessDeps, context: BranchContext, branchRoot: string, user: CanopyUser): Promise<ContentAccessChecker>;
44
25
  /**
45
- * Check content access by evaluating both branch and path permissions.
46
- * Path permissions are loaded dynamically from the branch root.
47
- *
48
- * @param deps - Dependencies including branch access checker and path permissions loader
49
- * @param context - Branch context containing branch metadata
50
- * @param branchRoot - Root directory of the branch
51
- * @param relativePath - Physical path relative to branch root (with embedded IDs)
52
- * @param user - User to check access for
53
- * @param level - Permission level to check ('read', 'edit', or 'review')
26
+ * Single-path check; loads the path permissions from the branch root per call.
27
+ * @internal Exported for tests.
54
28
  */
55
29
  export declare function checkContentAccess(deps: ContentAccessDeps, context: BranchContext, branchRoot: string, relativePath: PhysicalPath, user: CanopyUser, level: PermissionLevel): Promise<ContentAccessResult>;
56
- /**
57
- * Create a content access checker with bound dependencies.
58
- */
59
30
  export declare function createCheckContentAccess(deps: ContentAccessDeps): (context: BranchContext, branchRoot: string, relativePath: PhysicalPath, user: CanopyUser, level: PermissionLevel) => Promise<ContentAccessResult>;
@@ -1,42 +1,20 @@
1
1
  /**
2
- * Content access authorization
3
- *
4
- * This is the main entry point for authorization checks. It combines
5
- * branch-level and path-level access checks into a single API.
6
- *
7
- * Usage:
8
- * ```ts
9
- * import { checkContentAccess } from './authorization.js'
10
- *
11
- * const result = await checkContentAccess(deps, context, branchRoot, 'content/posts/my-post.mdx', user, 'edit')
12
- * if (result.allowed) {
13
- * // User can edit the file
14
- * }
15
- * ```
2
+ * Main entry point for authorization checks: combines branch-level and
3
+ * path-level access into a single API.
16
4
  */
17
5
  import { operatingStrategy } from '../operating-mode/index.js';
18
6
  import { createCheckPathAccess } from './path.js';
19
7
  /**
20
- * Create a content-access checker that resolves the request-constant work once
21
- * (branch access, the settings/permissions root, and the path-permission rules)
22
- * and returns a synchronous per-path checker.
23
- *
24
- * Branch access, the resolved permissions root, and the loaded rules are identical
25
- * for a fixed `(context, branchRoot, user)`, so hoisting them out of the per-path
26
- * check avoids re-reading the permissions file (and, in modes with a separate
27
- * settings branch, re-ensuring the settings workspace) for every entry. This is
28
- * the batch primitive used by listing endpoints that check many paths per request.
29
- *
30
- * @param deps - Dependencies including branch access checker and path permissions loader
31
- * @param context - Branch context containing branch metadata
32
- * @param branchRoot - Root directory of the branch
33
- * @param user - User to check access for
8
+ * Resolve the request-constant work once -- branch access, the
9
+ * settings/permissions root and the path-permission rules, all identical for a
10
+ * fixed `(context, branchRoot, user)` -- and return a synchronous per-path
11
+ * checker. Hoisting it avoids re-reading the permissions file (and, in modes
12
+ * with a separate settings branch, re-ensuring the settings workspace) for
13
+ * every entry. This is the batch primitive for listing endpoints that check
14
+ * many paths per request.
34
15
  */
35
16
  export async function createContentAccessChecker(deps, context, branchRoot, user) {
36
17
  const branch = deps.checkBranchAccess(context, user);
37
- // Load permissions from appropriate location based on operating mode
38
- // Modes with separate settings branch: load from settings branch
39
- // Other modes: load from the current branch
40
18
  let permissionsRoot = branchRoot;
41
19
  const mode = deps.mode;
42
20
  const strategy = operatingStrategy(mode);
@@ -44,8 +22,8 @@ export async function createContentAccessChecker(deps, context, branchRoot, user
44
22
  if (!deps.getSettingsBranchRoot) {
45
23
  throw new Error('getSettingsBranchRoot is required for modes that use separate settings branch');
46
24
  }
47
- // getSettingsBranchRoot must throw if it cannot load the settings branch
48
- // This ensures we never fall back to reading permissions from the current branch
25
+ // getSettingsBranchRoot must throw if it cannot load the settings branch:
26
+ // falling back would read permissions from the branch being edited.
49
27
  permissionsRoot = await deps.getSettingsBranchRoot();
50
28
  }
51
29
  const rules = await deps.loadPathPermissions(permissionsRoot, deps.mode);
@@ -64,23 +42,13 @@ export async function createContentAccessChecker(deps, context, branchRoot, user
64
42
  };
65
43
  }
66
44
  /**
67
- * Check content access by evaluating both branch and path permissions.
68
- * Path permissions are loaded dynamically from the branch root.
69
- *
70
- * @param deps - Dependencies including branch access checker and path permissions loader
71
- * @param context - Branch context containing branch metadata
72
- * @param branchRoot - Root directory of the branch
73
- * @param relativePath - Physical path relative to branch root (with embedded IDs)
74
- * @param user - User to check access for
75
- * @param level - Permission level to check ('read', 'edit', or 'review')
45
+ * Single-path check; loads the path permissions from the branch root per call.
46
+ * @internal Exported for tests.
76
47
  */
77
48
  export async function checkContentAccess(deps, context, branchRoot, relativePath, user, level) {
78
49
  const check = await createContentAccessChecker(deps, context, branchRoot, user);
79
50
  return check(relativePath, level);
80
51
  }
81
- /**
82
- * Create a content access checker with bound dependencies.
83
- */
84
52
  export function createCheckContentAccess(deps) {
85
53
  return (context, branchRoot, relativePath, user, level) => checkContentAccess(deps, context, branchRoot, relativePath, user, level);
86
54
  }
@@ -1,5 +1,2 @@
1
- /**
2
- * Groups module exports
3
- */
4
1
  export { GroupsFileSchema, createDefaultGroupsFile, type GroupsFile, type InternalGroup, } from './schema.js';
5
2
  export { loadGroupsFile, loadInternalGroups, deriveInternalGroups, mutateGroupsFile, } from './loader.js';
@@ -1,5 +1,2 @@
1
- /**
2
- * Groups module exports
3
- */
4
1
  export { GroupsFileSchema, createDefaultGroupsFile, } from './schema.js';
5
2
  export { loadGroupsFile, loadInternalGroups, deriveInternalGroups, mutateGroupsFile, } from './loader.js';
@@ -1,42 +1,28 @@
1
1
  /**
2
- * Groups file loader
3
- *
4
- * Handles loading internal groups from the filesystem and mutating
5
- * groups.json under the cross-host layered lock in
6
- * authorization/settings-file-store.ts.
2
+ * Loads internal groups, and mutates groups.json under the cross-host layered
3
+ * lock in authorization/settings-file-store.ts.
7
4
  */
8
5
  import { type InternalGroup, type GroupsFile } from './schema.js';
9
6
  import type { OperatingMode } from '../../operating-mode/index.js';
10
7
  import type { OccWriteResult } from '../../utils/occ-json-write.js';
11
- /**
12
- * Load full groups file (for version checking)
13
- * Returns null if file doesn't exist.
14
- */
8
+ /** Returns null when the file doesn't exist. */
15
9
  export declare function loadGroupsFile(branchRoot: string, mode: OperatingMode): Promise<GroupsFile | null>;
16
10
  /**
17
- * Derive the effective internal groups list from the raw groups array
18
- * stored on disk: ensures the reserved Admins/Reviewers groups always exist
19
- * (synthesizing defaults when absent) and merges bootstrap admin IDs into
20
- * Admins. Pure — no disk I/O — so a caller that already holds a freshly
21
- * loaded file (e.g. a settings-file mutator, which reloads on every retry
22
- * attempt) can reconcile against it without a second read.
11
+ * The effective internal groups for a raw on-disk groups array: the reserved
12
+ * Admins/Reviewers groups always exist (synthesized when absent) and bootstrap
13
+ * admin IDs merge into Admins. Pure — no disk I/O — so a caller holding a
14
+ * freshly loaded file (e.g. a settings-file mutator, which reloads on every
15
+ * retry attempt) can reconcile against it without a second read.
23
16
  */
24
17
  export declare function deriveInternalGroups(fileGroups: InternalGroup[], bootstrapAdminIds?: Set<string>): InternalGroup[];
25
- /**
26
- * Load internal groups from .canopycms/groups.json (or .local.json in dev mode)
27
- * Ensures Admins and Reviewers groups always exist, adding them dynamically if not present.
28
- * If Admins group exists in file, merges with bootstrap admin IDs.
29
- */
18
+ /** Loads .canopycms/groups.json (groups.local.json in dev mode). */
30
19
  export declare function loadInternalGroups(branchRoot: string, mode: OperatingMode, bootstrapAdminIds?: Set<string>): Promise<InternalGroup[]>;
31
20
  /**
32
- * Mutate groups.json (or .local.json in dev mode) under the full cross-host
33
- * lock + OCC-retry stack (see authorization/settings-file-store.ts).
34
- * `mutate` is called with the current parsed file (`null` if it doesn't
35
- * exist yet) and the version to write under; it returns the next raw
36
- * payload, or `null` for a deliberate no-op. The returned payload is
37
- * validated against {@link GroupsFileSchema} before being written,
38
- * preserving the previous validate-before-write behavior of the old
39
- * `saveInternalGroups`.
21
+ * Mutate groups.json (groups.local.json in dev mode) under the full cross-host
22
+ * lock + OCC-retry stack (see authorization/settings-file-store.ts). `mutate`
23
+ * receives the current parsed file (`null` if absent) and the version to write
24
+ * under, and returns the next raw payload or `null` for a deliberate no-op.
25
+ * The payload is validated against {@link GroupsFileSchema} before writing.
40
26
  */
41
27
  export declare function mutateGroupsFile(branchRoot: string, mode: OperatingMode, mutate: (current: GroupsFile | null, version: number) => Record<string, unknown> | null, options?: {
42
28
  settleMs?: number;
@@ -1,25 +1,16 @@
1
1
  /**
2
- * Groups file loader
3
- *
4
- * Handles loading internal groups from the filesystem and mutating
5
- * groups.json under the cross-host layered lock in
6
- * authorization/settings-file-store.ts.
2
+ * Loads internal groups, and mutates groups.json under the cross-host layered
3
+ * lock in authorization/settings-file-store.ts.
7
4
  */
8
5
  import { promises as fs } from 'node:fs';
9
6
  import { GroupsFileSchema } from './schema.js';
10
7
  import { operatingStrategy } from '../../operating-mode/index.js';
11
8
  import { RESERVED_GROUPS } from '../helpers.js';
12
9
  import { mutateSettingsJsonFile } from '../settings-file-store.js';
13
- /**
14
- * Get the appropriate groups file path based on mode
15
- */
16
10
  function getGroupsFilePath(branchRoot, mode) {
17
11
  return operatingStrategy(mode).getGroupsFilePath(branchRoot);
18
12
  }
19
- /**
20
- * Load full groups file (for version checking)
21
- * Returns null if file doesn't exist.
22
- */
13
+ /** Returns null when the file doesn't exist. */
23
14
  export async function loadGroupsFile(branchRoot, mode) {
24
15
  const groupsPath = getGroupsFilePath(branchRoot, mode);
25
16
  try {
@@ -29,7 +20,6 @@ export async function loadGroupsFile(branchRoot, mode) {
29
20
  return validated;
30
21
  }
31
22
  catch (error) {
32
- // File doesn't exist
33
23
  if (error.code === 'ENOENT') {
34
24
  return null;
35
25
  }
@@ -37,20 +27,16 @@ export async function loadGroupsFile(branchRoot, mode) {
37
27
  }
38
28
  }
39
29
  /**
40
- * Derive the effective internal groups list from the raw groups array
41
- * stored on disk: ensures the reserved Admins/Reviewers groups always exist
42
- * (synthesizing defaults when absent) and merges bootstrap admin IDs into
43
- * Admins. Pure — no disk I/O — so a caller that already holds a freshly
44
- * loaded file (e.g. a settings-file mutator, which reloads on every retry
45
- * attempt) can reconcile against it without a second read.
30
+ * The effective internal groups for a raw on-disk groups array: the reserved
31
+ * Admins/Reviewers groups always exist (synthesized when absent) and bootstrap
32
+ * admin IDs merge into Admins. Pure — no disk I/O — so a caller holding a
33
+ * freshly loaded file (e.g. a settings-file mutator, which reloads on every
34
+ * retry attempt) can reconcile against it without a second read.
46
35
  */
47
36
  export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set()) {
48
- // Find existing Admins and Reviewers groups
49
37
  let adminsGroup = fileGroups.find((g) => g.id === RESERVED_GROUPS.ADMINS);
50
38
  let reviewersGroup = fileGroups.find((g) => g.id === RESERVED_GROUPS.REVIEWERS);
51
- // Ensure Admins group exists and includes bootstrap admins
52
39
  if (adminsGroup) {
53
- // Merge bootstrap admin IDs with existing members
54
40
  const allAdmins = new Set([...adminsGroup.members, ...bootstrapAdminIds]);
55
41
  adminsGroup = {
56
42
  ...adminsGroup,
@@ -58,7 +44,6 @@ export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set())
58
44
  };
59
45
  }
60
46
  else {
61
- // Create Admins group with bootstrap admins
62
47
  adminsGroup = {
63
48
  id: RESERVED_GROUPS.ADMINS,
64
49
  name: RESERVED_GROUPS.ADMINS,
@@ -66,7 +51,6 @@ export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set())
66
51
  members: Array.from(bootstrapAdminIds),
67
52
  };
68
53
  }
69
- // Ensure Reviewers group exists
70
54
  if (!reviewersGroup) {
71
55
  reviewersGroup = {
72
56
  id: RESERVED_GROUPS.REVIEWERS,
@@ -75,28 +59,20 @@ export function deriveInternalGroups(fileGroups, bootstrapAdminIds = new Set())
75
59
  members: [],
76
60
  };
77
61
  }
78
- // Return all groups: reserved groups first, then other groups
79
62
  const otherGroups = fileGroups.filter((g) => g.id !== RESERVED_GROUPS.ADMINS && g.id !== RESERVED_GROUPS.REVIEWERS);
80
63
  return [adminsGroup, reviewersGroup, ...otherGroups];
81
64
  }
82
- /**
83
- * Load internal groups from .canopycms/groups.json (or .local.json in dev mode)
84
- * Ensures Admins and Reviewers groups always exist, adding them dynamically if not present.
85
- * If Admins group exists in file, merges with bootstrap admin IDs.
86
- */
65
+ /** Loads .canopycms/groups.json (groups.local.json in dev mode). */
87
66
  export async function loadInternalGroups(branchRoot, mode, bootstrapAdminIds = new Set()) {
88
67
  const file = await loadGroupsFile(branchRoot, mode);
89
68
  return deriveInternalGroups(file?.groups ?? [], bootstrapAdminIds);
90
69
  }
91
70
  /**
92
- * Mutate groups.json (or .local.json in dev mode) under the full cross-host
93
- * lock + OCC-retry stack (see authorization/settings-file-store.ts).
94
- * `mutate` is called with the current parsed file (`null` if it doesn't
95
- * exist yet) and the version to write under; it returns the next raw
96
- * payload, or `null` for a deliberate no-op. The returned payload is
97
- * validated against {@link GroupsFileSchema} before being written,
98
- * preserving the previous validate-before-write behavior of the old
99
- * `saveInternalGroups`.
71
+ * Mutate groups.json (groups.local.json in dev mode) under the full cross-host
72
+ * lock + OCC-retry stack (see authorization/settings-file-store.ts). `mutate`
73
+ * receives the current parsed file (`null` if absent) and the version to write
74
+ * under, and returns the next raw payload or `null` for a deliberate no-op.
75
+ * The payload is validated against {@link GroupsFileSchema} before writing.
100
76
  */
101
77
  export async function mutateGroupsFile(branchRoot, mode, mutate, options) {
102
78
  const groupsPath = getGroupsFilePath(branchRoot, mode);
@@ -1,6 +1,3 @@
1
- /**
2
- * Schema for groups.json file
3
- */
4
1
  import { z } from 'zod';
5
2
  import type { CanopyUserId, CanopyGroupId } from '../../types.js';
6
3
  /**
@@ -51,9 +48,6 @@ export declare const GroupsFileSchema: z.ZodObject<{
51
48
  writeId?: string | undefined;
52
49
  }>;
53
50
  export type GroupsFile = z.infer<typeof GroupsFileSchema>;
54
- /**
55
- * Internal group representation
56
- */
57
51
  export interface InternalGroup {
58
52
  id: CanopyGroupId;
59
53
  name: string;
@@ -1,15 +1,12 @@
1
- /**
2
- * Schema for groups.json file
3
- */
4
1
  import { z } from 'zod';
5
2
  /**
6
3
  * Schema for .canopycms/groups.json
7
4
  */
8
5
  export const GroupsFileSchema = z.object({
9
- // Managed by writeOccJsonFile (see authorization/settings-file-store.ts) —
10
- // the single OCC counter for this file. Optional so a hand-written file
11
- // with no version field parses as version 0. A legacy `contentVersion`
12
- // field (if present) is silently stripped by this non-strict zod parse.
6
+ // Managed by writeOccJsonFile (see authorization/settings-file-store.ts):
7
+ // the single OCC counter for this file. Optional so a hand-written file with
8
+ // no version field parses as version 0; a stray `contentVersion` key is
9
+ // silently stripped by this non-strict zod parse.
13
10
  version: z.number().int().nonnegative().optional(),
14
11
  writeId: z.string().optional(),
15
12
  updatedAt: z.string().datetime(),