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
@@ -12,11 +12,7 @@ import { SchemaOps, SchemaStoreBusyError } from '../schema/schema-store.js';
12
12
  import { listCollectionEntries as listCollectionEntriesShared, sortByOrder, } from '../content-listing.js';
13
13
  // Re-export pagination constants from the dependency-free module so they remain
14
14
  // part of the entries API surface without pulling server deps into client bundles.
15
- export { MAX_ENTRIES_PER_PAGE, DEFAULT_ENTRIES_LIMIT } from './entries-constants.js';
16
15
  const log = createDebugLogger({ prefix: 'EntriesAPI' });
17
- // ============================================================================
18
- // Zod Schemas for Validation
19
- // ============================================================================
20
16
  const listEntriesParamsSchema = z.object({
21
17
  branch: branchNameSchema,
22
18
  collection: logicalPathSchema.optional(),
@@ -54,14 +50,11 @@ const toCollectionItem = (entry, collection) => {
54
50
  /**
55
51
  * List entries in a single collection, mapped to API CollectionItem type.
56
52
  *
57
- * Deliberately does NOT resolve `reference` fields, unlike the `resolveReferences` option
58
- * that `listEntries`/`buildContentTree` grew for the same underlying primitive. This is a
59
- * paginated admin table rendering slug/title/canEdit — it never reads inside a reference —
60
- * and resolution here would land in the worst possible place: it runs BEFORE pagination
61
- * (`filterWithAccessControl` walks the full collection, `slice` happens at the end), on a
62
- * request path, so every keystroke in the admin search box would pay a full ContentId index
63
- * scan plus one read per distinct referenced entry. Revisit only if a column ever needs to
64
- * display a reference's content.
53
+ * Deliberately does NOT resolve `reference` fields (unlike the `resolveReferences` option
54
+ * elsewhere on the same primitive): this runs BEFORE pagination (`slice` happens at the end) on
55
+ * a search request path, so resolving would cost a full ContentId scan plus one read per
56
+ * referenced entry on every keystroke. Revisit only if a column needs to display a reference's
57
+ * content.
65
58
  */
66
59
  const listCollectionEntries = async (root, collection) => {
67
60
  const entries = await listCollectionEntriesShared(root, collection);
@@ -179,12 +172,10 @@ const listEntriesHandler = async (gc, ctx, req, params) => {
179
172
  },
180
173
  };
181
174
  };
182
- // ============================================================================
183
- // Route Definitions with defineEndpoint
184
- // ============================================================================
185
175
  /**
186
176
  * List entries for a branch
187
177
  * GET /:branch/entries
178
+ * @internal Exported for tests.
188
179
  */
189
180
  export const listEntries = defineEndpoint({
190
181
  namespace: 'entries',
@@ -215,14 +206,10 @@ const deleteEntryParamsSchema = z.object({
215
206
  */
216
207
  const deleteEntryHandler = async (gc, ctx, req, params) => {
217
208
  const { branchContext } = gc;
218
- // Parse entryPath to get collection and slug
219
209
  // Format: collectionPath/slug (e.g., "posts/hello-world" or "docs/api/getting-started")
220
210
  // params.entryPath is already decoded exactly once, uniformly with every
221
- // other route param, by http/router.ts's matchRoute (C5) - re-decoding it
222
- // here was the redundant second decode that made this route inconsistent
223
- // with content.ts's (undecoded) catch-all and vulnerable to a malformed
224
- // `%` escape throwing past this handler's try/catch. Still re-validate the
225
- // final decoded value for traversal, same as before.
211
+ // other route param, by http/router.ts's matchRoute (C5). Still re-validate the
212
+ // final decoded value for traversal.
226
213
  const entryPathResult = parseLogicalPath(params.entryPath);
227
214
  if (!entryPathResult.ok) {
228
215
  return {
@@ -250,8 +237,6 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
250
237
  };
251
238
  }
252
239
  const flatSchema = branchContext.flatSchema;
253
- // Check edit permission on the entry
254
- // Build the physical path for permission check
255
240
  const collection = flatSchema.find((item) => item.type === 'collection' && item.logicalPath === collectionPath);
256
241
  if (!collection) {
257
242
  return { ok: false, status: 404, error: 'Collection not found' };
@@ -280,16 +265,13 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
280
265
  if (isNotFoundError(err)) {
281
266
  return { ok: false, status: 404, error: 'Entry not found' };
282
267
  }
283
- // C2: only a recognized ContentStoreError is the client's fault (bad
284
- // slug/path shape); anything else - a real fs error, a bug - is a
285
- // server fault and must surface as a 500, not get mislabeled as
286
- // "Invalid entry path".
268
+ // C2: same rule as content.ts's writeContentHandler catch (ContentStoreError -> 400,
269
+ // everything else -> 500).
287
270
  if (err instanceof ContentStoreError) {
288
271
  return { ok: false, status: 400, error: 'Invalid entry path' };
289
272
  }
290
273
  throw err;
291
274
  }
292
- // Check edit access using the real physical path
293
275
  const editAccess = await ctx.services.checkContentAccess(branchContext, branchContext.branchRoot, physicalPath, req.user, 'edit');
294
276
  if (!editAccess.allowed) {
295
277
  return {
@@ -302,15 +284,11 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
302
284
  try {
303
285
  // Get the entry's content ID before deleting (for order update)
304
286
  const contentId = await contentStore.getIdForEntry(collectionLogicalPath, entrySlug);
305
- // Delete the entry
306
287
  await contentStore.delete(collectionLogicalPath, entrySlug);
307
- // Update the collection's order array to remove the deleted item.
308
- // Construct exactly like api/schema.ts's getSchemaOps: the configured
309
- // content root as the first argument, the branch root passed explicitly as
310
- // the fourth, and with services, so updateOrder's .collection.json write
311
- // bumps the schema generation marker. Without the bump, every host durably
312
- // serves the stale cached order (still containing the deleted entry) until
313
- // the next unrelated schema mutation — prod has no mtime backstop.
288
+ // Construct exactly like api/schema.ts's getSchemaOps (content root, registry, services,
289
+ // branch root) so updateOrder's write bumps the schema generation marker — without it, every
290
+ // host keeps serving the stale cached order (still containing the deleted entry) until the
291
+ // next unrelated schema mutation, since prod has no mtime backstop.
314
292
  if (contentId && collection.type === 'collection' && collection.order) {
315
293
  const contentRootName = ctx.services.config.contentRoot || 'content';
316
294
  const schemaStore = new SchemaOps(path.join(branchContext.branchRoot, contentRootName), ctx.services.entrySchemaRegistry, ctx.services, branchContext.branchRoot);
@@ -320,13 +298,9 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
320
298
  await schemaStore.updateOrder(collectionPath, newOrder);
321
299
  }
322
300
  catch (err) {
323
- // C6: order cleanup is best-effort hygiene that runs AFTER the
324
- // entry is already deleted, so no failure here - busy schema lock,
325
- // ENOSPC, a bug, anything - is allowed to turn an otherwise-
326
- // successful delete into an error response (the entry is gone; a
327
- // client that sees an error and retries the delete would just get
328
- // a confusing 404). Surface it as a warning on the success
329
- // response instead (mirrors content.ts's write-path `validationWarnings`).
301
+ // C6: order cleanup is best-effort hygiene after the entry is already deleted, so no
302
+ // failure here may turn an otherwise-successful delete into an error (a retry would
303
+ // just 404). Surface it as a warning instead (mirrors content.ts's `validationWarnings`).
330
304
  const reason = err instanceof SchemaStoreBusyError ? 'schema is busy' : getErrorMessage(err);
331
305
  log.warn('delete-entry', 'Skipped order cleanup', {
332
306
  collectionPath,
@@ -347,9 +321,8 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
347
321
  if (isNotFoundError(err)) {
348
322
  return { ok: false, status: 404, error: 'Entry not found' };
349
323
  }
350
- // [SYNC-C1] Contention with the worker's rebase (or another editor) is a
351
- // retriable conflict, not a server fault -- 409, with the syncing
352
- // variant's own "try again" message when that is what happened.
324
+ // [SYNC-C1] Contention with the worker's rebase (or another editor) is a retriable conflict,
325
+ // not a server fault — 409, with the syncing variant's own "try again" message.
353
326
  if (err instanceof ContentConflictError) {
354
327
  return {
355
328
  ok: false,
@@ -366,11 +339,7 @@ const deleteEntryHandler = async (gc, ctx, req, params) => {
366
339
  };
367
340
  }
368
341
  };
369
- /**
370
- * Delete an entry
371
- * DELETE /:branch/entries/...entryPath
372
- * Note: Uses catch-all to support paths with slashes (e.g., content/posts/hello-world)
373
- */
342
+ /** @internal Exported for tests. */
374
343
  export const deleteEntry = defineEndpoint({
375
344
  namespace: 'entries',
376
345
  name: 'delete',
@@ -1,7 +1,6 @@
1
1
  import type { ApiContext } from './types.js';
2
2
  import type { BranchContext, SyncStatus } from '../types.js';
3
3
  /**
4
- * Result of a GitHub sync operation.
5
4
  * The caller uses this to update branch metadata.
6
5
  */
7
6
  export interface GitHubSyncResult {
@@ -10,12 +9,11 @@ export interface GitHubSyncResult {
10
9
  syncStatus?: SyncStatus;
11
10
  }
12
11
  /**
13
- * Submit a branch: create or update a PR.
14
12
  * Uses githubService directly if available, otherwise queues a task for the worker.
15
13
  */
16
14
  export declare function syncSubmitPr(ctx: ApiContext, context: BranchContext): Promise<GitHubSyncResult>;
17
15
  /**
18
- * Convert a PR to draft (used by withdraw and request-changes).
19
- * Uses githubService directly if available, otherwise queues a task.
16
+ * Used by withdraw and request-changes. Uses githubService directly if
17
+ * available, otherwise queues a task.
20
18
  */
21
19
  export declare function syncConvertToDraft(ctx: ApiContext, context: BranchContext): Promise<void>;
@@ -1,10 +1,9 @@
1
- import { enqueueTask } from '../worker/task-queue.js';
2
- import { getTaskQueueDir } from '../worker/task-queue-config.js';
1
+ import { enqueueTask } from '../task-queue/cms-task-queue.js';
2
+ import { getTaskQueueDir } from '../task-queue/task-queue-config.js';
3
3
  import { clientOperatingStrategy } from '../operating-mode/index.js';
4
4
  import { getErrorMessage } from '../utils/error.js';
5
5
  import { sanitizeBranchName } from '../paths/branch-name.js';
6
6
  /**
7
- * Submit a branch: create or update a PR.
8
7
  * Uses githubService directly if available, otherwise queues a task for the worker.
9
8
  */
10
9
  export async function syncSubmitPr(ctx, context) {
@@ -118,8 +117,8 @@ export async function syncSubmitPr(ctx, context) {
118
117
  });
119
118
  }
120
119
  /**
121
- * Convert a PR to draft (used by withdraw and request-changes).
122
- * Uses githubService directly if available, otherwise queues a task.
120
+ * Used by withdraw and request-changes. Uses githubService directly if
121
+ * available, otherwise queues a task.
123
122
  */
124
123
  export async function syncConvertToDraft(ctx, context) {
125
124
  if (!context.branch.pullRequestNumber)
@@ -147,9 +146,6 @@ export async function syncConvertToDraft(ctx, context) {
147
146
  });
148
147
  }
149
148
  }
150
- /**
151
- * Enqueue a GitHub task for the EC2 worker.
152
- */
153
149
  async function enqueueGitHubTask(ctx, context, task) {
154
150
  const taskDir = getTaskQueueDir(ctx.services.config);
155
151
  try {
@@ -16,6 +16,7 @@ export type ExternalGroupsResponse = ApiResponse<{
16
16
  /**
17
17
  * Validate that an update to internal groups doesn't remove the last admin.
18
18
  * Considers both internal Admins group members and bootstrap admins.
19
+ * @internal Exported for tests.
19
20
  */
20
21
  export declare const validateAdminGroupUpdate: (newGroups: InternalGroup[], bootstrapAdminIds: Set<string>) => {
21
22
  valid: boolean;
@@ -23,6 +24,7 @@ export declare const validateAdminGroupUpdate: (newGroups: InternalGroup[], boot
23
24
  };
24
25
  /**
25
26
  * Validate that reserved groups are not deleted or renamed.
27
+ * @internal Exported for tests.
26
28
  */
27
29
  export declare const validateReservedGroups: (newGroups: InternalGroup[]) => {
28
30
  valid: boolean;
@@ -35,6 +37,7 @@ export interface UpdateInternalGroupsBody {
35
37
  }
36
38
  /**
37
39
  * Search external groups (for group UI)
40
+ * @internal Exported for tests.
38
41
  */
39
42
  export interface SearchExternalGroupsParams {
40
43
  query: string;
@@ -4,9 +4,6 @@ import { defineEndpoint } from './route-builder.js';
4
4
  import { getSettingsBranchContext, commitSettings } from './settings-helpers.js';
5
5
  import { generateId } from '../id.js';
6
6
  import { getErrorMessage, sanitizeErrorMessage } from '../utils/error.js';
7
- // ============================================================================
8
- // Zod Schemas for Validation
9
- // ============================================================================
10
7
  const internalGroupSchema = z.object({
11
8
  id: z.string(),
12
9
  name: z.string(),
@@ -37,15 +34,14 @@ class GroupsValidationError extends Error {
37
34
  /**
38
35
  * Validate that an update to internal groups doesn't remove the last admin.
39
36
  * Considers both internal Admins group members and bootstrap admins.
37
+ * @internal Exported for tests.
40
38
  */
41
39
  export const validateAdminGroupUpdate = (newGroups, bootstrapAdminIds) => {
42
- // Find the Admins group in the new groups
43
40
  const adminsGroup = newGroups.find((g) => g.id === RESERVED_GROUPS.ADMINS);
44
41
  const adminMembersCount = adminsGroup?.members?.length ?? 0;
45
42
  // Total admins = internal Admins group members + bootstrap admins (excluding overlap)
46
43
  const internalAdmins = new Set(adminsGroup?.members ?? []);
47
44
  let totalAdmins = adminMembersCount;
48
- // Add bootstrap admins that aren't already in the internal group
49
45
  for (const bootstrapId of bootstrapAdminIds) {
50
46
  if (!internalAdmins.has(bootstrapId)) {
51
47
  totalAdmins++;
@@ -61,12 +57,11 @@ export const validateAdminGroupUpdate = (newGroups, bootstrapAdminIds) => {
61
57
  };
62
58
  /**
63
59
  * Validate that reserved groups are not deleted or renamed.
60
+ * @internal Exported for tests.
64
61
  */
65
62
  export const validateReservedGroups = (newGroups) => {
66
- // Check if any reserved group IDs have been altered
67
63
  for (const group of newGroups) {
68
64
  if (isReservedGroup(group.id)) {
69
- // Reserved group exists - make sure the name matches the ID
70
65
  if (group.name !== group.id) {
71
66
  return {
72
67
  valid: false,
@@ -122,11 +117,10 @@ const updateInternalGroupsHandler = async (_gc, ctx, req, body) => {
122
117
  return { ok: false, status: result.status, error: result.error };
123
118
  }
124
119
  const { context, mode } = result;
125
- // Load -> compare -> reconcile -> validate -> write all happen atomically
126
- // under the cross-host layered lock (see
127
- // authorization/settings-file-store.ts), against the mutator's own
128
- // freshly-reloaded file — no separate pre-read here, so there's no
129
- // TOCTOU window between the version/reconciliation checks and the write.
120
+ // Load -> compare -> reconcile -> validate -> write all happen atomically under the
121
+ // cross-host layered lock (see authorization/settings-file-store.ts), against the mutator's
122
+ // own freshly-reloaded file — no separate pre-read, so no TOCTOU window between the
123
+ // version/reconciliation checks and the write.
130
124
  await mutateGroupsFile(context.branchRoot, mode, (currentFile, version) => {
131
125
  if (body.expectedContentVersion !== undefined && body.expectedContentVersion !== version) {
132
126
  throw new SettingsVersionConflictError('Groups were modified by another user. Please reload and try again.');
@@ -137,16 +131,13 @@ const updateInternalGroupsHandler = async (_gc, ctx, req, body) => {
137
131
  const existingById = new Set(existingGroups.map((g) => g.id));
138
132
  // Process groups: generate IDs for new groups, keep IDs for existing groups
139
133
  const processedGroups = body.groups.map((group) => {
140
- // Existing group with valid ID - keep ID
141
134
  if (group.id && group.id.trim() !== '' && existingById.has(group.id)) {
142
135
  return group;
143
136
  }
144
- // Check if this is a reserved group (by ID or name)
145
137
  if (isReservedGroup(group.id) || isReservedGroup(group.name)) {
146
138
  // Reserved groups: ID = name (e.g., "Admins", "Reviewers")
147
139
  return { ...group, id: group.name };
148
140
  }
149
- // New regular group (empty ID or not in existing set) - generate ID
150
141
  return { ...group, id: generateId() };
151
142
  });
152
143
  // Validate no duplicate IDs
@@ -182,9 +173,8 @@ const updateInternalGroupsHandler = async (_gc, ctx, req, body) => {
182
173
  groups: processedGroups,
183
174
  };
184
175
  });
185
- // Commit and push (mode-aware). A push failure means the change is saved
186
- // to the branch working tree but NOT durably persisted (API-H1) - surface
187
- // that to the client instead of reporting a bare 200.
176
+ // A failed push is returned to the client as an error, never a bare 200 (see
177
+ // CommitSettingsResult in settings-helpers.ts).
188
178
  const commitResult = await commitSettings(ctx, {
189
179
  context,
190
180
  branchRoot: context.branchRoot,
@@ -239,9 +229,6 @@ const searchExternalGroupsHandler = async (_gc, ctx, req, params) => {
239
229
  };
240
230
  }
241
231
  };
242
- // ============================================================================
243
- // Route Definitions with defineEndpoint
244
- // ============================================================================
245
232
  /**
246
233
  * Get internal groups
247
234
  * GET /groups/internal
@@ -1,26 +1,14 @@
1
1
  /**
2
- * Declarative guard system for API endpoints.
3
- *
4
- * Guards run before the handler and either:
5
- * - Return an error response (404, 403, 500) to short-circuit
6
- * - Produce a guard context (e.g., branch context with schema) for the handler
7
- *
8
- * Usage in defineEndpoint:
9
- * ```ts
10
- * defineEndpoint({
11
- * guards: ['branchAccessWithSchema'] as const,
12
- * handler: async (gc, ctx, req, params) => {
13
- * // gc.branchContext is guaranteed non-null with flatSchema
14
- * }
15
- * })
16
- * ```
2
+ * Declarative guard system for API endpoints: guards run before the handler and either return an
3
+ * error response (404/403/500) to short-circuit, or produce a guard context (e.g. branch context
4
+ * with schema) for the handler. See api/AGENTS.md for the full guard reference.
17
5
  */
18
6
  import type { BranchContext, BranchContextWithSchema } from '../types.js';
19
7
  import type { ApiContext, ApiRequest, ApiResponse } from './types.js';
20
8
  /** All available guard identifiers */
21
9
  export type GuardId = 'branch' | 'branchAccess' | 'schema' | 'branchAccessWithSchema' | 'admin' | 'reviewer' | 'privileged' | 'writableBranch' | 'submittableBranch';
22
10
  /** Maps each guard ID to the context it contributes */
23
- export interface GuardContextMap {
11
+ interface GuardContextMap {
24
12
  branch: {
25
13
  branchContext: BranchContext;
26
14
  };
@@ -1,26 +1,10 @@
1
1
  /**
2
- * Declarative guard system for API endpoints.
3
- *
4
- * Guards run before the handler and either:
5
- * - Return an error response (404, 403, 500) to short-circuit
6
- * - Produce a guard context (e.g., branch context with schema) for the handler
7
- *
8
- * Usage in defineEndpoint:
9
- * ```ts
10
- * defineEndpoint({
11
- * guards: ['branchAccessWithSchema'] as const,
12
- * handler: async (gc, ctx, req, params) => {
13
- * // gc.branchContext is guaranteed non-null with flatSchema
14
- * }
15
- * })
16
- * ```
2
+ * Declarative guard system for API endpoints: guards run before the handler and either return an
3
+ * error response (404/403/500) to short-circuit, or produce a guard context (e.g. branch context
4
+ * with schema) for the handler. See api/AGENTS.md for the full guard reference.
17
5
  */
18
6
  import { isAdmin, isReviewer, isPrivileged } from '../authorization/helpers.js';
19
7
  import { getBranchProtection, getBranchWriteProtection } from '../authorization/protected-branch.js';
20
- // ============================================================================
21
- // Guard runner implementations
22
- // ============================================================================
23
- /** Extracts branch name from params, returning error response if missing */
24
8
  function extractBranchName(params) {
25
9
  const branch = params.branch;
26
10
  if (typeof branch !== 'string' || !branch) {
@@ -193,9 +177,6 @@ const runPrivilegedGuard = async (_ctx, req) => {
193
177
  }
194
178
  return { ok: true, context: {} };
195
179
  };
196
- // ============================================================================
197
- // Guard registry
198
- // ============================================================================
199
180
  const GUARD_RUNNERS = {
200
181
  branch: runBranchGuard,
201
182
  branchAccess: runBranchAccessGuard,
@@ -1,18 +1,18 @@
1
1
  export type { ApiResponse, ApiRequest, ApiContext } from './types.js';
2
2
  export type { BranchResponse, BranchListResponse, BranchDeleteResponse, CreateBranchBody, UpdateBranchAccessBody, } from './branch.js';
3
3
  export type { BranchMergeResponse } from './branch-merge.js';
4
- export type { CommentsResponse, AddCommentResponse, ResolveCommentResponse, ListCommentsResponse, } from './comments.js';
4
+ export type { CommentsResponse, AddCommentResponse, ResolveCommentResponse } from './comments.js';
5
5
  export type { EntriesResponse, ListEntriesResponse, CollectionItem, ListEntriesParams, DeleteEntryResponse, } from './entries.js';
6
6
  export type { PermissionsResponse, UpdatePermissionsBody, SearchUsersParams, GetUserMetadataResponse, GetUserMetadataParams, } from './permissions.js';
7
7
  export type { UserInfoResponse } from './user.js';
8
- export type { AssetRecord, AssetsListResponse, PresignAssetResponse, PresignAssetBody, FinalizeAssetResponse, FinalizeAssetBody, AssetDeleteResponse, ListAssetsParams, DeleteAssetParams, } from './assets.js';
8
+ export type { AssetRecord, AssetsListResponse, PresignAssetResponse, PresignAssetBody, FinalizeAssetResponse, FinalizeAssetBody, AssetDeleteResponse, } from './assets.js';
9
9
  export type { InternalGroupsResponse, ExternalGroupsResponse, UpdateInternalGroupsBody, SearchExternalGroupsParams, ExternalGroup, } from './groups.js';
10
10
  export type { ReferenceOptionsResponse } from './reference-options.js';
11
11
  export type { ResolveReferencesResponse } from './resolve-references.js';
12
- export type { SchemaResponse, WireEntryType, WireCollectionConfig, WireFlatSchemaItem, CollectionResponse, CreateCollectionResponse, UpdateCollectionResponse, DeleteCollectionResponse, AddEntryTypeResponse, UpdateEntryTypeResponse, RemoveEntryTypeResponse, UpdateOrderResponse, GetSchemaApiResponse, GetCollectionApiResponse, CreateCollectionApiResponse, UpdateCollectionApiResponse, DeleteCollectionApiResponse, AddEntryTypeApiResponse, UpdateEntryTypeApiResponse, RemoveEntryTypeApiResponse, UpdateOrderApiResponse, } from './schema.js';
12
+ export type { GetSchemaApiResponse, GetCollectionApiResponse, CreateCollectionApiResponse, UpdateCollectionApiResponse, DeleteCollectionApiResponse, AddEntryTypeApiResponse, UpdateEntryTypeApiResponse, RemoveEntryTypeApiResponse, UpdateOrderApiResponse, } from './schema.js';
13
13
  export type { CreateCollectionInput, UpdateCollectionInput, CreateEntryTypeInput, UpdateEntryTypeInput, } from '../schema/schema-store-types.js';
14
14
  export type { EntryTypeSummary } from './entries.js';
15
- export type { AdminStatusResponse, AdminStatusData, AdminTasksResponse, AdminTasksData, ListAdminTasksParams, AdminRetryTaskResponse, AdminRetryTaskData, RetryTaskParams, AdminDeleteTaskResponse, AdminDeleteTaskData, DeleteTaskParams, WorkerLiveness, WorkerLivenessState, } from './admin.js';
15
+ export type { AdminStatusResponse, AdminStatusData, AdminTasksResponse, AdminTasksData, ListAdminTasksParams, AdminRetryTaskResponse, AdminDeleteTaskResponse, DeleteTaskParams, WorkerLiveness, } from './admin.js';
16
16
  export { USER_ROUTES } from './user.js';
17
17
  export { CanopyApiClient, createApiClient } from './client.js';
18
18
  export type { ApiClientOptions } from './client.js';
@@ -143,7 +143,9 @@ declare const getUserMetadataParamsSchema: z.ZodObject<{
143
143
  userId: string;
144
144
  }>;
145
145
  export type UpdatePermissionsBody = z.infer<typeof updatePermissionsBodySchema>;
146
+ /** @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md. */
146
147
  export type SearchUsersParams = z.infer<typeof searchUsersParamsSchema>;
148
+ /** @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md. */
147
149
  export type GetUserMetadataParams = z.infer<typeof getUserMetadataParamsSchema>;
148
150
  /**
149
151
  * Exported routes for router registration
@@ -5,9 +5,6 @@ import { MAX_ENTRIES_PER_PAGE } from './entries-constants.js';
5
5
  import { defineEndpoint } from './route-builder.js';
6
6
  import { getSettingsBranchContext, commitSettings } from './settings-helpers.js';
7
7
  import { getErrorMessage, sanitizeErrorMessage } from '../utils/error.js';
8
- // ============================================================================
9
- // Zod Schemas for Validation
10
- // ============================================================================
11
8
  const permissionTargetSchema = z.object({
12
9
  allowedUsers: z.array(z.string()).optional(),
13
10
  allowedGroups: z.array(z.string()).optional(),
@@ -24,18 +21,14 @@ const updatePermissionsBodySchema = z.object({
24
21
  });
25
22
  const searchUsersParamsSchema = z.object({
26
23
  q: z.string(),
27
- // Coerced + range-checked (consistent with api/entries.ts's listEntriesParamsSchema)
28
- // rather than z.string() + an unchecked parseInt(), which silently produced NaN
29
- // for a non-numeric limit (API-M2). Capped like listEntries so a caller cannot
30
- // request an unbounded page from the auth provider.
24
+ // Coerced + range-checked, not z.string() + an unchecked parseInt() (which silently produced
25
+ // NaN for a non-numeric limit): capped like entries.ts's listEntriesParamsSchema so a caller
26
+ // can't request an unbounded page from the auth provider.
31
27
  limit: z.coerce.number().int().min(1).max(MAX_ENTRIES_PER_PAGE).optional(),
32
28
  });
33
29
  const getUserMetadataParamsSchema = z.object({
34
30
  userId: z.string(),
35
31
  });
36
- /**
37
- * Get current permissions (admin only)
38
- */
39
32
  const getPermissionsHandler = async (_gc, ctx, _req) => {
40
33
  try {
41
34
  const result = await getSettingsBranchContext(ctx);
@@ -58,9 +51,6 @@ const getPermissionsHandler = async (_gc, ctx, _req) => {
58
51
  };
59
52
  }
60
53
  };
61
- /**
62
- * Update permissions (admin only)
63
- */
64
54
  const updatePermissionsHandler = async (_gc, ctx, req, body) => {
65
55
  if (!body?.permissions) {
66
56
  return { ok: false, status: 400, error: 'permissions array required' };
@@ -85,9 +75,8 @@ const updatePermissionsHandler = async (_gc, ctx, req, body) => {
85
75
  pathPermissions: body.permissions,
86
76
  };
87
77
  });
88
- // Commit and push (mode-aware). A push failure means the change is saved
89
- // to the branch working tree but NOT durably persisted (API-H1) - surface
90
- // that to the client instead of reporting a bare 200.
78
+ // Commit and push (mode-aware): a push failure means the change is saved to the branch
79
+ // working tree but NOT durably persisted — surface that to the client, not a bare 200.
91
80
  const commitResult = await commitSettings(ctx, {
92
81
  context,
93
82
  branchRoot: context.branchRoot,
@@ -141,18 +130,13 @@ const searchUsersHandler = async (_gc, ctx, req, params) => {
141
130
  }
142
131
  };
143
132
  /**
144
- * List groups (for permission UI)
145
- *
146
- * Merges BOTH group universes, because both are valid `allowedGroups` targets:
147
- * the auth provider's groups and Canopy's own internal groups from groups.json
148
- * (see PermissionGroupOption in auth/types.ts). Feeding this endpoint from the
149
- * auth plugin alone made internally-created groups unreachable from the
150
- * Permission Manager's picker -- they could only be granted a path permission
151
- * by hand-editing permissions.json.
133
+ * List groups (for permission UI). Merges BOTH group universes — the auth provider's and
134
+ * Canopy's own internal groups from groups.json (see PermissionGroupOption in auth/types.ts) —
135
+ * since both are valid `allowedGroups` targets.
152
136
  *
153
- * Internal entries are name-only (no members, no memberCount): this endpoint is
154
- * `privileged` (admin or reviewer) whereas `groups.getInternal` is admin-only,
155
- * so member identities and counts must not leak through here.
137
+ * Internal entries are name-only (no members, no memberCount): this endpoint is `privileged`
138
+ * (admin or reviewer) whereas `groups.getInternal` is admin-only, so member identities and
139
+ * counts must not leak through here.
156
140
  */
157
141
  const listGroupsHandler = async (_gc, ctx, _req) => {
158
142
  const authPlugin = ctx.authPlugin;
@@ -168,13 +152,11 @@ const listGroupsHandler = async (_gc, ctx, _req) => {
168
152
  const { context, mode } = result;
169
153
  const file = await loadGroupsFile(context.branchRoot, mode);
170
154
  const internalGroups = deriveInternalGroups(file?.groups ?? [], ctx.services.bootstrapAdminIds);
171
- // Deduplicate by ID, internal first so it wins a collision. The two ID
172
- // spaces are not namespaced against each other, but `checkPathPermission`
173
- // matches `allowedGroups` by ID string against one flattened `user.groups`
174
- // list -- so two same-ID groups ARE a single permission target, and
175
- // emitting both would misrepresent what enforcement actually does.
176
- // (Reserved IDs can never arrive from the provider: stripReservedGroups in
177
- // user.ts removes them before they reach `user.groups`.)
155
+ // Deduplicate by ID, internal first so it wins a collision: the two ID spaces aren't
156
+ // namespaced against each other, but `checkPathPermission` matches `allowedGroups` by ID
157
+ // string against one flattened `user.groups` list, so two same-ID groups ARE a single
158
+ // permission target — emitting both would misrepresent enforcement. (Reserved IDs never
159
+ // arrive from the provider: stripReservedGroups in user.ts removes them first.)
178
160
  const byId = new Map();
179
161
  for (const group of internalGroups) {
180
162
  byId.set(group.id, {
@@ -187,9 +169,8 @@ const listGroupsHandler = async (_gc, ctx, _req) => {
187
169
  for (const group of externalGroups) {
188
170
  const collision = byId.get(group.id);
189
171
  if (collision) {
190
- // Keep the internal entry, but record that granting this ID ALSO
191
- // reaches the provider group's membership -- the picker surfaces that
192
- // so an admin isn't shown a name-and-members set narrower than the
172
+ // Keep the internal entry, but record that granting this ID ALSO reaches the provider
173
+ // group's membership, so the picker doesn't show an admin a narrower set than the
193
174
  // grant's real reach.
194
175
  collision.source = 'both';
195
176
  continue;
@@ -228,9 +209,6 @@ const getUserMetadataHandler = async (_gc, ctx, req, params) => {
228
209
  };
229
210
  }
230
211
  };
231
- // ============================================================================
232
- // Route Definitions with defineEndpoint
233
- // ============================================================================
234
212
  /**
235
213
  * Get current permissions (admin only)
236
214
  * GET /permissions
@@ -1,6 +1,5 @@
1
1
  import { z } from 'zod';
2
2
  import type { ApiResponse } from './types.js';
3
- /** Response type for reference options */
4
3
  export type ReferenceOptionsResponse = ApiResponse<{
5
4
  options: Array<{
6
5
  id: string;
@@ -4,9 +4,6 @@ import { defineEndpoint } from './route-builder.js';
4
4
  import { ReferenceResolver } from '../reference-resolver.js';
5
5
  import { parseLogicalPath } from '../paths/index.js';
6
6
  import { branchNameSchema } from './validators.js';
7
- // ============================================================================
8
- // Zod Schemas for Validation
9
- // ============================================================================
10
7
  const getReferenceOptionsParamsSchema = z.object({
11
8
  branch: branchNameSchema,
12
9
  });
@@ -68,11 +65,9 @@ const getReferenceOptionsHandler = async (gc, ctx, req, _params) => {
68
65
  .map((t) => t.trim())
69
66
  .filter(Boolean)
70
67
  : undefined;
71
- // Build the access checker once (permissions loaded a single time, reused for
72
- // every candidate) and pass it into loadReferenceOptions as a filter *before*
73
- // loading: a denied path is skipped outright, so it never triggers the
74
- // store.read() that loadReferenceOptions would otherwise do just to compute a
75
- // label for an option the caller isn't allowed to see.
68
+ // Build the access checker once and pass it in as a filter *before* loading: a denied path is
69
+ // skipped outright, so it never triggers the store.read() that would otherwise compute a label
70
+ // for an option the caller isn't allowed to see.
76
71
  const checkAccess = await ctx.services.createContentAccessChecker(branchContext, branchContext.branchRoot, req.user);
77
72
  const resolver = new ReferenceResolver(store, idIndex);
78
73
  const options = await resolver.loadReferenceOptions(collections, displayField, search, entryTypes, (relativePath) => checkAccess(relativePath, 'read').allowed);
@@ -82,9 +77,6 @@ const getReferenceOptionsHandler = async (gc, ctx, req, _params) => {
82
77
  data: { options },
83
78
  };
84
79
  };
85
- // ============================================================================
86
- // Route Definitions
87
- // ============================================================================
88
80
  /**
89
81
  * Get reference options for a field
90
82
  * GET /:branch/reference-options