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,7 +1,8 @@
1
1
  import type { BranchContext, BranchMetadata } from './types.js';
2
- import { BRANCH_META_DIR, BRANCH_META_FILE, BranchMetadataCorruptError, readBranchMetadataFile, type BranchMetadataFile } from './branch-metadata-file.js';
2
+ import { BranchMetadataCorruptError, type BranchMetadataFile } from './branch-metadata-file.js';
3
3
  import { type OperatingMode } from './operating-mode/index.js';
4
- export { BRANCH_META_DIR, BRANCH_META_FILE, BranchMetadataCorruptError, readBranchMetadataFile, type BranchMetadataFile, };
4
+ export { BranchMetadataCorruptError, type BranchMetadataFile };
5
+ /** @internal Exported for tests. */
5
6
  export declare class BranchMetadataConflictError extends Error {
6
7
  constructor(message?: string);
7
8
  }
@@ -9,28 +10,17 @@ export declare class BranchMetadataConflictError extends Error {
9
10
  * Manages branch.json — branch status and access ACLs, both security-adjacent
10
11
  * state — under `.canopy-meta/` in a branch workspace.
11
12
  *
12
- * save() is protected by three layers, outermost to innermost (identical
13
- * structure to {@link CommentStore}'s withMutation, see comment-store.ts):
13
+ * save() runs under the same three-layer stack as {@link CommentStore}'s
14
+ * withMutation — see comment-store.ts, and `utils/occ-json-write.ts` for the
15
+ * guarantees of layers 2-3.
14
16
  *
15
- * 1. {@link withLock} - an in-process FIFO mutex keyed by the resolved file
16
- * path. Serializes concurrent mutators on the SAME process/host
17
- * deterministically.
18
- * 2. {@link withOccFileLock} - a server-enforced, cross-process/cross-host
19
- * lock (proper-lockfile, mkdir-based). This is the actual fix for lost
20
- * branch-status/ACL updates across two warm Lambda containers (or a
21
- * Lambda + the EC2 worker) on EFS: rename-based OCC verification alone
22
- * relies on a read-back that can be served from the writer's own local
23
- * NFS dentry/attribute cache, so a foreign writer's rename can stay
24
- * invisible for that cache's window (commonly 3-60s) and both writers
25
- * conclude they won. A settle delay does not help — the cache window
26
- * dwarfs any sleep worth paying — only server-enforced mutual exclusion
27
- * does. Given branch.json carries status + ACLs, silently losing an
28
- * update here is a correctness/security issue, not just a UX glitch.
29
- * 3. {@link withOccRetry} around {@link writeOccJsonFile} - version/writeId
30
- * based optimistic concurrency control. With layers 1-2 in place this is
31
- * now a defense-in-depth backstop only, not the primary safety mechanism.
32
- *
33
- * See `utils/occ-json-write.ts` for full guarantee documentation of layers 2-3.
17
+ * Layer 2's server-enforced lock is the load-bearing one here. Rename-based OCC
18
+ * alone verifies by a read-back that can come from the writer's own NFS
19
+ * attribute cache, so for that cache's window (docs/concurrency.md) a foreign
20
+ * writer's rename stays invisible and both writers conclude they won; no settle
21
+ * delay closes it, since the window dwarfs any sleep worth paying. And because
22
+ * branch.json carries status and ACLs, a silently lost update is a
23
+ * correctness/security issue, not a UX glitch.
34
24
  */
35
25
  export declare class BranchMetadataFileManager {
36
26
  private readonly branchRoot;
@@ -38,94 +28,73 @@ export declare class BranchMetadataFileManager {
38
28
  private readonly baseRoot;
39
29
  private readonly settleMs;
40
30
  private constructor();
41
- /**
42
- * Load branch metadata without requiring baseRoot.
43
- * Use this for read-only access (e.g., in registry scanning or loadBranchContext).
44
- */
31
+ /** Read-only load, needing no baseRoot: registry scanning, loadBranchContext. */
45
32
  static loadOnly(branchRoot: string): Promise<BranchMetadataFile | null>;
46
33
  /**
47
- * Get a BranchMetadataFileManager instance configured for registry invalidation.
48
- * Use this in API handlers to ensure registry cache is invalidated on updates.
34
+ * An instance wired for registry invalidation. API handlers use this, so the
35
+ * registry cache is invalidated on update.
49
36
  */
50
37
  static get(branchRoot: string, baseRoot: string, options?: {
51
38
  settleMs?: number;
52
39
  }): BranchMetadataFileManager;
53
40
  private load;
54
41
  /**
55
- * Write branch.json via the shared OCC helper, with the schemaVersion
56
- * default applied here (payload shaping stays branch-metadata's concern).
42
+ * Write branch.json via the shared OCC helper, applying the schemaVersion
43
+ * default here since payload shaping is branch-metadata's concern.
57
44
  *
58
- * Throws the helper's raw {@link OccWriteConflictError} so the surrounding
59
- * {@link withOccRetry} in save() recognizes and retries it; translation to
60
- * the public `BranchMetadataConflictError` contract happens at the save()
61
- * boundary, after retries are exhausted (translating earlier would make
62
- * withOccRetry's default predicate miss it, since it only recognizes the
63
- * raw error type).
45
+ * Throws the helper's raw {@link OccWriteConflictError}, which is what the
46
+ * surrounding {@link withOccRetry} in save() recognizes and retries;
47
+ * translating to the public `BranchMetadataConflictError` earlier than the
48
+ * save() boundary would make withOccRetry's predicate miss it.
64
49
  *
65
- * branch-metadata historically writes WITH a trailing newline, unlike
66
- * comment-store; `trailingNewline: true` preserves that.
50
+ * branch.json is written WITH a trailing newline (`trailingNewline: true`),
51
+ * unlike comments.json.
67
52
  */
68
53
  private write;
69
54
  /**
70
- * Run a save cycle under the full lock + OCC-retry stack described in the
71
- * class doc comment. A conflict that survives every retry surfaces as the
72
- * public `BranchMetadataConflictError`.
55
+ * Run a save cycle under the full lock + OCC-retry stack (class doc). A
56
+ * conflict surviving every retry surfaces as `BranchMetadataConflictError`.
73
57
  *
74
- * Guards against a phantom-resurrection race with branch deletion: a
75
- * caller's branchContext can be resolved BEFORE a concurrent
76
- * deleteBranchHandler removes the branch directory, but this save() call
77
- * only reaches here (and its own mkdir({recursive:true}) inside write())
78
- * AFTER the removal. Without this check, that mkdir would silently
79
- * recreate `.canopy-meta/` (and this save would recreate branch.json from
80
- * defaults) inside a directory tree that no longer exists anywhere else --
81
- * a registry entry with no clone behind it. Checking BEFORE the lock stack
82
- * (rather than after) fails fast without paying for a lock acquisition on
83
- * a doomed save.
58
+ * The stat guards a phantom-resurrection race with branch deletion: a
59
+ * caller's branchContext can resolve BEFORE a concurrent deleteBranchHandler
60
+ * removes the branch directory, while the save reaches here after it, and
61
+ * write()'s `mkdir({recursive:true})` would then recreate `.canopy-meta/` and
62
+ * branch.json from defaults inside a tree nothing else refers to — a registry
63
+ * entry with no clone behind it. It runs BEFORE the lock stack so a doomed
64
+ * save fails fast instead of paying for a lock.
84
65
  *
85
- * Residual window (accepted): a save that passes this check can still
86
- * race a `rm` that starts moments later and is still mid-flight when this
87
- * save's write lands, resurrecting the tree. Closing that fully would
88
- * need a tombstone OUTSIDE the tree being removed -- the lockfile
89
- * (`withOccFileLock`) this save takes next lives INSIDE `branchRoot`, so
90
- * it cannot itself provide a wider guarantee than "the directory existed
91
- * a moment ago."
66
+ * Accepted residual window: a save that passes the check can still race a
67
+ * `rm` that starts moments later and is mid-flight when the write lands.
68
+ * Closing that needs a tombstone OUTSIDE the tree being removed, and the
69
+ * lockfile taken next lives INSIDE `branchRoot`, so it can promise no more
70
+ * than "the directory existed a moment ago".
92
71
  */
93
72
  save(incoming: BranchMetadataUpdate): Promise<BranchMetadataFile>;
94
- /**
95
- * Invalidates the registry cache so next list() call regenerates from branch.json files.
96
- */
73
+ /** Invalidate the registry cache so the next list() regenerates. */
97
74
  private invalidateRegistry;
98
75
  }
99
76
  /**
100
- * Fields that can be set via save().
101
- * - createdBy: Only used on initial creation; ignored if metadata already exists
102
- * - createdAt/updatedAt: Managed automatically
77
+ * Fields save() accepts. `createdBy` applies on creation only and is ignored
78
+ * once metadata exists; createdAt/updatedAt are managed here, not by callers.
103
79
  */
104
80
  export interface BranchMetadataUpdate {
105
81
  branch?: Partial<Omit<BranchMetadata, 'createdAt' | 'updatedAt'>>;
106
82
  }
107
83
  /**
108
- * Build the metadata update for archiving a branch because its PR merged.
109
- * Shared by the worker's merge-poll (CmsWorker.pollMergeState) and the
110
- * manual markAsMerged API (api/branch-merge.ts) so both paths produce
111
- * identical archived-branch metadata.
84
+ * The metadata update for archiving a branch whose PR merged. Shared by the
85
+ * worker's merge-poll (CmsWorker.pollMergeState) and the manual markAsMerged
86
+ * API (api/branch-merge.ts), so both produce identical metadata.
112
87
  *
113
- * Deliberately omits pullRequestNumber/pullRequestUrl: save()'s merge keeps
114
- * whatever the existing metadata already has for fields not present in the
115
- * incoming update, so the PR number/URL recorded earlier survive untouched.
88
+ * Deliberately omits pullRequestNumber/pullRequestUrl: save() keeps existing
89
+ * values for fields the incoming update omits, so the recorded PR number and
90
+ * URL survive untouched.
116
91
  */
117
92
  export declare function buildMergedBranchUpdate(branchName: string, now?: Date): NonNullable<BranchMetadataUpdate['branch']>;
118
- /**
119
- * Get a BranchMetadataFileManager instance configured for registry invalidation.
120
- * Use this in API handlers to ensure registry cache is invalidated on updates.
121
- */
93
+ /** {@link BranchMetadataFileManager.get} as a function. */
122
94
  export declare const getBranchMetadataFileManager: (branchRoot: string, baseRoot: string, options?: {
123
95
  settleMs?: number;
124
96
  }) => BranchMetadataFileManager;
125
- /**
126
- * Load branch context from metadata file (source of truth).
127
- * Returns null if the branch doesn't exist.
128
- */
97
+ /** Branch context from the metadata file, the source of truth. Null if absent. */
129
98
  export declare const loadBranchContext: (options: {
130
99
  branchName: string;
131
100
  mode: OperatingMode;
@@ -6,11 +6,12 @@ import { resolveBranchPath } from './paths/index.js';
6
6
  import { isNotFoundError } from './utils/error.js';
7
7
  import { withLock } from './utils/async-mutex.js';
8
8
  import { writeOccJsonFile, withOccRetry, withOccFileLock, OccWriteConflictError, } from './utils/occ-json-write.js';
9
- // The file format itself lives in the leaf so branch-registry.ts can read
10
- // branch.json without importing this module (which imports it back). Re-exported
11
- // here so the existing importers of these names do not have to move.
12
- export { BRANCH_META_DIR, BRANCH_META_FILE, BranchMetadataCorruptError, readBranchMetadataFile, };
9
+ // The file format lives in the leaf so branch-registry.ts can read branch.json
10
+ // without importing this module, which imports it back. Re-exported here so
11
+ // importers of these names do not have to move.
12
+ export { BranchMetadataCorruptError };
13
13
  const CURRENT_SCHEMA_VERSION = 1;
14
+ /** @internal Exported for tests. */
14
15
  export class BranchMetadataConflictError extends Error {
15
16
  constructor(message = 'Concurrent modification detected in branch metadata') {
16
17
  super(message);
@@ -21,28 +22,17 @@ export class BranchMetadataConflictError extends Error {
21
22
  * Manages branch.json — branch status and access ACLs, both security-adjacent
22
23
  * state — under `.canopy-meta/` in a branch workspace.
23
24
  *
24
- * save() is protected by three layers, outermost to innermost (identical
25
- * structure to {@link CommentStore}'s withMutation, see comment-store.ts):
25
+ * save() runs under the same three-layer stack as {@link CommentStore}'s
26
+ * withMutation — see comment-store.ts, and `utils/occ-json-write.ts` for the
27
+ * guarantees of layers 2-3.
26
28
  *
27
- * 1. {@link withLock} - an in-process FIFO mutex keyed by the resolved file
28
- * path. Serializes concurrent mutators on the SAME process/host
29
- * deterministically.
30
- * 2. {@link withOccFileLock} - a server-enforced, cross-process/cross-host
31
- * lock (proper-lockfile, mkdir-based). This is the actual fix for lost
32
- * branch-status/ACL updates across two warm Lambda containers (or a
33
- * Lambda + the EC2 worker) on EFS: rename-based OCC verification alone
34
- * relies on a read-back that can be served from the writer's own local
35
- * NFS dentry/attribute cache, so a foreign writer's rename can stay
36
- * invisible for that cache's window (commonly 3-60s) and both writers
37
- * conclude they won. A settle delay does not help — the cache window
38
- * dwarfs any sleep worth paying — only server-enforced mutual exclusion
39
- * does. Given branch.json carries status + ACLs, silently losing an
40
- * update here is a correctness/security issue, not just a UX glitch.
41
- * 3. {@link withOccRetry} around {@link writeOccJsonFile} - version/writeId
42
- * based optimistic concurrency control. With layers 1-2 in place this is
43
- * now a defense-in-depth backstop only, not the primary safety mechanism.
44
- *
45
- * See `utils/occ-json-write.ts` for full guarantee documentation of layers 2-3.
29
+ * Layer 2's server-enforced lock is the load-bearing one here. Rename-based OCC
30
+ * alone verifies by a read-back that can come from the writer's own NFS
31
+ * attribute cache, so for that cache's window (docs/concurrency.md) a foreign
32
+ * writer's rename stays invisible and both writers conclude they won; no settle
33
+ * delay closes it, since the window dwarfs any sleep worth paying. And because
34
+ * branch.json carries status and ACLs, a silently lost update is a
35
+ * correctness/security issue, not a UX glitch.
46
36
  */
47
37
  export class BranchMetadataFileManager {
48
38
  constructor(branchRoot, baseRoot, options) {
@@ -51,16 +41,13 @@ export class BranchMetadataFileManager {
51
41
  this.baseRoot = baseRoot;
52
42
  this.settleMs = options?.settleMs;
53
43
  }
54
- /**
55
- * Load branch metadata without requiring baseRoot.
56
- * Use this for read-only access (e.g., in registry scanning or loadBranchContext).
57
- */
44
+ /** Read-only load, needing no baseRoot: registry scanning, loadBranchContext. */
58
45
  static async loadOnly(branchRoot) {
59
46
  return readBranchMetadataFile(branchRoot);
60
47
  }
61
48
  /**
62
- * Get a BranchMetadataFileManager instance configured for registry invalidation.
63
- * Use this in API handlers to ensure registry cache is invalidated on updates.
49
+ * An instance wired for registry invalidation. API handlers use this, so the
50
+ * registry cache is invalidated on update.
64
51
  */
65
52
  static get(branchRoot, baseRoot, options) {
66
53
  return new BranchMetadataFileManager(branchRoot, baseRoot, options);
@@ -80,18 +67,16 @@ export class BranchMetadataFileManager {
80
67
  }
81
68
  }
82
69
  /**
83
- * Write branch.json via the shared OCC helper, with the schemaVersion
84
- * default applied here (payload shaping stays branch-metadata's concern).
70
+ * Write branch.json via the shared OCC helper, applying the schemaVersion
71
+ * default here since payload shaping is branch-metadata's concern.
85
72
  *
86
- * Throws the helper's raw {@link OccWriteConflictError} so the surrounding
87
- * {@link withOccRetry} in save() recognizes and retries it; translation to
88
- * the public `BranchMetadataConflictError` contract happens at the save()
89
- * boundary, after retries are exhausted (translating earlier would make
90
- * withOccRetry's default predicate miss it, since it only recognizes the
91
- * raw error type).
73
+ * Throws the helper's raw {@link OccWriteConflictError}, which is what the
74
+ * surrounding {@link withOccRetry} in save() recognizes and retries;
75
+ * translating to the public `BranchMetadataConflictError` earlier than the
76
+ * save() boundary would make withOccRetry's predicate miss it.
92
77
  *
93
- * branch-metadata historically writes WITH a trailing newline, unlike
94
- * comment-store; `trailingNewline: true` preserves that.
78
+ * branch.json is written WITH a trailing newline (`trailingNewline: true`),
79
+ * unlike comments.json.
95
80
  */
96
81
  async write(meta, expectedVersion) {
97
82
  const payload = {
@@ -105,28 +90,22 @@ export class BranchMetadataFileManager {
105
90
  });
106
91
  }
107
92
  /**
108
- * Run a save cycle under the full lock + OCC-retry stack described in the
109
- * class doc comment. A conflict that survives every retry surfaces as the
110
- * public `BranchMetadataConflictError`.
93
+ * Run a save cycle under the full lock + OCC-retry stack (class doc). A
94
+ * conflict surviving every retry surfaces as `BranchMetadataConflictError`.
111
95
  *
112
- * Guards against a phantom-resurrection race with branch deletion: a
113
- * caller's branchContext can be resolved BEFORE a concurrent
114
- * deleteBranchHandler removes the branch directory, but this save() call
115
- * only reaches here (and its own mkdir({recursive:true}) inside write())
116
- * AFTER the removal. Without this check, that mkdir would silently
117
- * recreate `.canopy-meta/` (and this save would recreate branch.json from
118
- * defaults) inside a directory tree that no longer exists anywhere else --
119
- * a registry entry with no clone behind it. Checking BEFORE the lock stack
120
- * (rather than after) fails fast without paying for a lock acquisition on
121
- * a doomed save.
96
+ * The stat guards a phantom-resurrection race with branch deletion: a
97
+ * caller's branchContext can resolve BEFORE a concurrent deleteBranchHandler
98
+ * removes the branch directory, while the save reaches here after it, and
99
+ * write()'s `mkdir({recursive:true})` would then recreate `.canopy-meta/` and
100
+ * branch.json from defaults inside a tree nothing else refers to — a registry
101
+ * entry with no clone behind it. It runs BEFORE the lock stack so a doomed
102
+ * save fails fast instead of paying for a lock.
122
103
  *
123
- * Residual window (accepted): a save that passes this check can still
124
- * race a `rm` that starts moments later and is still mid-flight when this
125
- * save's write lands, resurrecting the tree. Closing that fully would
126
- * need a tombstone OUTSIDE the tree being removed -- the lockfile
127
- * (`withOccFileLock`) this save takes next lives INSIDE `branchRoot`, so
128
- * it cannot itself provide a wider guarantee than "the directory existed
129
- * a moment ago."
104
+ * Accepted residual window: a save that passes the check can still race a
105
+ * `rm` that starts moments later and is mid-flight when the write lands.
106
+ * Closing that needs a tombstone OUTSIDE the tree being removed, and the
107
+ * lockfile taken next lives INSIDE `branchRoot`, so it can promise no more
108
+ * than "the directory existed a moment ago".
130
109
  */
131
110
  async save(incoming) {
132
111
  try {
@@ -167,9 +146,9 @@ export class BranchMetadataFileManager {
167
146
  createdAt: existing?.branch.createdAt ?? defaults.createdAt,
168
147
  // Fork point is recorded once at creation; later saves must not move it
169
148
  baseBranch: existing?.branch.baseBranch ?? incoming.branch?.baseBranch,
170
- // Always stamped fresh — the spreads above would otherwise let
171
- // the existing (creation-time) value win forever, freezing the
172
- // timestamp the editor's Branches panel sorts and displays by
149
+ // Always stamped fresh; the spreads above would otherwise let
150
+ // the creation-time value win forever, freezing the timestamp
151
+ // the editor's Branches panel sorts and displays by
173
152
  updatedAt: now,
174
153
  },
175
154
  };
@@ -185,31 +164,28 @@ export class BranchMetadataFileManager {
185
164
  }
186
165
  throw err;
187
166
  }
188
- // Registry invalidation AFTER releasing the lockfile: the protocol only
189
- // requires the bump to land strictly after the branch.json write (it
190
- // does), and the registry's eager regeneration is O(branch count) fs
191
- // reads on EFS — holding the server-enforced lock through it would
192
- // extend every save's critical section for no correctness gain.
167
+ // Registry invalidation AFTER releasing the lockfile. The protocol only
168
+ // requires the bump to land strictly after the branch.json write, which it
169
+ // does, and the registry's eager regeneration is O(branch count) fs reads
170
+ // on EFS — holding the lock through it would stretch every save's critical
171
+ // section for no correctness gain.
193
172
  await this.invalidateRegistry();
194
173
  return saved;
195
174
  }
196
- /**
197
- * Invalidates the registry cache so next list() call regenerates from branch.json files.
198
- */
175
+ /** Invalidate the registry cache so the next list() regenerates. */
199
176
  async invalidateRegistry() {
200
177
  const registry = new BranchRegistry(this.baseRoot);
201
178
  await registry.invalidate();
202
179
  }
203
180
  }
204
181
  /**
205
- * Build the metadata update for archiving a branch because its PR merged.
206
- * Shared by the worker's merge-poll (CmsWorker.pollMergeState) and the
207
- * manual markAsMerged API (api/branch-merge.ts) so both paths produce
208
- * identical archived-branch metadata.
182
+ * The metadata update for archiving a branch whose PR merged. Shared by the
183
+ * worker's merge-poll (CmsWorker.pollMergeState) and the manual markAsMerged
184
+ * API (api/branch-merge.ts), so both produce identical metadata.
209
185
  *
210
- * Deliberately omits pullRequestNumber/pullRequestUrl: save()'s merge keeps
211
- * whatever the existing metadata already has for fields not present in the
212
- * incoming update, so the PR number/URL recorded earlier survive untouched.
186
+ * Deliberately omits pullRequestNumber/pullRequestUrl: save() keeps existing
187
+ * values for fields the incoming update omits, so the recorded PR number and
188
+ * URL survive untouched.
213
189
  */
214
190
  export function buildMergedBranchUpdate(branchName, now = new Date()) {
215
191
  return {
@@ -219,17 +195,11 @@ export function buildMergedBranchUpdate(branchName, now = new Date()) {
219
195
  mergedAt: now.toISOString(),
220
196
  };
221
197
  }
222
- /**
223
- * Get a BranchMetadataFileManager instance configured for registry invalidation.
224
- * Use this in API handlers to ensure registry cache is invalidated on updates.
225
- */
198
+ /** {@link BranchMetadataFileManager.get} as a function. */
226
199
  export const getBranchMetadataFileManager = (branchRoot, baseRoot, options) => {
227
200
  return BranchMetadataFileManager.get(branchRoot, baseRoot, options);
228
201
  };
229
- /**
230
- * Load branch context from metadata file (source of truth).
231
- * Returns null if the branch doesn't exist.
232
- */
202
+ /** Branch context from the metadata file, the source of truth. Null if absent. */
233
203
  export const loadBranchContext = async (options) => {
234
204
  const { branchRoot, baseRoot } = resolveBranchPath({
235
205
  branchName: options.branchName,
@@ -1,59 +1,28 @@
1
1
  import type { BranchContext } from './types.js';
2
+ /** @internal Exported for tests. */
2
3
  export interface BranchRegistrySnapshot {
3
4
  version: number;
4
5
  branches: BranchContext[];
5
6
  /**
6
- * The resource-generation.ts marker token this snapshot was built against, or
7
- * null if it was built before any bump ever occurred on this root. Compared
8
- * against the live marker (via isGenerationCurrent) to decide freshness.
7
+ * The marker token this snapshot was built against, or null when it was built
8
+ * before any bump on this root. Compared against the live marker (via
9
+ * isGenerationCurrent) to decide freshness.
9
10
  */
10
11
  generation: string | null;
11
12
  }
12
13
  /**
13
- * BranchRegistry is a read-only cache for fast branch listing.
14
- * Individual branch.json files are the source of truth.
14
+ * A read-only `branches.json` cache for fast branch listing; the individual
15
+ * branch.json files are the source of truth.
15
16
  *
16
- * ## Cross-process freshness (resource-generation.ts marker protocol)
17
+ * Freshness follows the generation-marker protocol owned by
18
+ * resource-generation.ts. This is that protocol's durable-snapshot consumer, so
19
+ * it carries both mitigations: invalidate() eager-regenerates on the mutating
20
+ * host right after its own bump, and get() has a throttled suspicious-miss
21
+ * backstop bounding how long a bad snapshot can hide a real branch.
17
22
  *
18
- * Several warm Lambda containers plus the EC2 worker can share one branch-clone
19
- * root over EFS, each with its own in-process cache of `branches.json`. There is
20
- * no shared memory and no cross-host file watching, so freshness is coordinated
21
- * via the generic on-disk generation marker in resource-generation.ts: every
22
- * snapshot embeds the marker token it was built against, and every read
23
- * cheaply re-checks the live marker before trusting the cached snapshot. See
24
- * that module's doc comment for the full protocol and residual staleness
25
- * windows (A/B/C/E).
26
- *
27
- * BranchRegistry is exactly the "durable snapshot consumer" case called out
28
- * there: a regeneration whose scan is served from stale NFS dentry/attribute
29
- * caches can record a FRESH token over STALE data (window E), and because the
30
- * result is written to `branches.json`, that staleness becomes durable and
31
- * shared with every other host that reads the marker - not just one process's
32
- * memory. Two mitigations close the practical gap:
33
- *
34
- * - invalidate() eager-regenerates immediately after its own bump. The
35
- * mutating host's own scan is necessarily coherent with the mutation it just
36
- * made (no NFS round trip was needed to observe its own write), so this
37
- * closes window (E) for the common case without waiting for some other host
38
- * to lazily pull the change.
39
- * - get() implements a suspicious-miss backstop: a branch that "should" exist
40
- * but is absent from the cached snapshot forces one fresh regeneration
41
- * (throttled), bounding how long a bad snapshot can hide a real branch.
42
- *
43
- * regenerate() also skips persisting a snapshot when the marker read itself
44
- * fails (`{ ok: false }`, e.g. unreadable for a non-ENOENT reason): a snapshot
45
- * embedding a token we cannot attribute to "matches this scan" would be
46
- * indistinguishable from a correctly-attributed one to every future reader, so
47
- * the safer behavior is to serve the fresh scan without writing it durably and
48
- * let the next read retry the marker.
49
- *
50
- * Design:
51
- * - list() returns the cached snapshot if its embedded generation token still
52
- * matches the live marker, regenerates from branch.json files otherwise
53
- * - invalidate() bumps the marker (durable, cross-process) and eager-regenerates
54
- * - Concurrent regeneration within one process is deduped to a single scan
55
- * (regenInFlight); across processes, regeneration is still safe since all
56
- * processes produce identical output from the same branch.json files
23
+ * Concurrent regeneration within one process is deduped to a single scan
24
+ * (regenInFlight); across processes it needs no coordination, since every
25
+ * process produces identical output from the same branch.json files.
57
26
  */
58
27
  export declare class BranchRegistry {
59
28
  private readonly root;
@@ -71,35 +40,28 @@ export declare class BranchRegistry {
71
40
  */
72
41
  list(): Promise<BranchContext[]>;
73
42
  /**
74
- * Returns a single branch by name. Uses cache if available.
43
+ * Returns a single branch by name, from the cached snapshot when it is fresh.
75
44
  *
76
- * Suspicious-miss backstop: if `name` isn't in the (possibly cached) list,
77
- * that's a signal the snapshot may be stale in the specific direction where
78
- * a branch that now exists is missing from it - force one fresh
79
- * regeneration and re-search before giving up, throttled per instance so a
80
- * genuinely-absent branch costs at most one extra scan per throttle window.
81
- * This bounds durable window-E staleness for the "branch exists but
82
- * snapshot predates it" direction; see the class doc comment.
45
+ * Suspicious-miss backstop: a `name` missing from the list is the signal that
46
+ * the snapshot may predate a branch that now exists, so force one fresh
47
+ * regeneration and re-search before giving up. Throttled per instance, so a
48
+ * genuinely-absent branch costs at most one extra scan per window.
83
49
  */
84
50
  get(name: string): Promise<BranchContext | undefined>;
85
51
  private shouldForceRefresh;
86
52
  /**
87
- * Marks the cache as stale for every process sharing this root by bumping
88
- * the cross-process generation marker, then eager-regenerates on this host
89
- * (see class doc comment for why). The bump must succeed: a swallowed
90
- * failure here would leave the registry stale indefinitely with no
91
- * bounding backstop, unlike a failed eager regen below, which only forgoes
92
- * closing window (E) early - the bump alone already restored correctness
93
- * for every future reader. A failed eager regen therefore must not fail the
94
- * caller's save/delete.
53
+ * Marks the cache stale for every process sharing this root by bumping the
54
+ * marker, then eager-regenerates on this host. The bump must succeed —
55
+ * swallowing that failure leaves the registry stale indefinitely with no
56
+ * backstop. A failed eager regen must NOT fail the caller's save/delete: the
57
+ * bump alone already restored correctness for every future reader.
95
58
  */
96
59
  invalidate(): Promise<void>;
97
60
  /**
98
61
  * Scans branch directories and rebuilds the cache, deduping concurrent
99
62
  * callers on this instance to a single underlying scan. Never loops waiting
100
- * for the snapshot's embedded token to match the marker - under a bump
101
- * storm that could livelock; a caller that wants the very latest state
102
- * after a concurrent bump should call list() again after this resolves.
63
+ * for the embedded token to match the marker — that livelocks under a bump
64
+ * storm; a caller wanting the very latest state calls list() again.
103
65
  */
104
66
  private regenerate;
105
67
  private performRegenerate;