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,20 +1,18 @@
1
- import type { Task } from './task-queue.js';
1
+ import type { Task } from '../task-queue/cms-task-queue.js';
2
2
  import type { WorkerContext } from './worker-context.js';
3
3
  /**
4
- * The task-queue cluster: everything reachable from `CmsWorker.processTaskQueue()`,
5
- * the loop that drains tasks Lambda enqueued because it has no internet.
4
+ * The task-queue cluster: everything reachable from
5
+ * `CmsWorker.processTaskQueue()`, the loop that drains tasks Lambda enqueued
6
+ * because it has no internet. It owns the GitHub-facing side of the worker --
7
+ * pushing branches, creating and updating PRs, recording the outcome on branch
8
+ * metadata -- plus the permanent-vs-transient classification that decides
9
+ * whether a failed task is retried or fails fast.
6
10
  *
7
- * One of the four disjoint call trees that used to share cms-worker.ts. It owns
8
- * the GitHub-facing side of the worker -- pushing branches, creating and
9
- * updating PRs, and recording the outcome on branch metadata -- plus the
10
- * permanent-vs-transient failure classification that decides whether a failed
11
- * task is retried or fails fast.
12
- *
13
- * Shares nothing with the git-sync cluster but the four resolved paths, the
14
- * Octokit client and the history-rewrite marker (history-rewrite.ts). Note the
11
+ * It shares nothing with the git-sync cluster but the four resolved paths, the
12
+ * Octokit client and the history-rewrite marker (history-rewrite.ts), and the
15
13
  * two loops run CONCURRENTLY: `scheduleLoop` drives this on `taskPollInterval`
16
- * (default 5s) and syncGit on `gitSyncInterval` (default 5min), so anything
17
- * here that reads branch metadata written by the rebase loop must re-read it
14
+ * (default 5s) and syncGit on `gitSyncInterval` (default 5min). So anything
15
+ * here that reads branch metadata written by the rebase loop MUST re-read it
18
16
  * rather than trust a snapshot.
19
17
  */
20
18
  export type TaskRunnerContext = Pick<WorkerContext, 'githubOwner' | 'githubRepo' | 'baseBranch' | 'sanitizedBaseBranch' | 'taskDir' | 'remoteGitPath' | 'contentBranchesPath' | 'taskTimeoutMs' | 'maxTasksPerCycle' | 'maxRetries' | 'log' | 'octokit' | 'buildGitHubUrl' | 'refreshGitHubCredential' | 'branchWorkspacePath' | 'executeTask' | 'pushBranchToGitHub' | 'isRunning' | 'ensureStatusReport'>;
@@ -29,72 +27,40 @@ export declare class PermanentTaskError extends Error {
29
27
  * Classify a task failure as permanent (fail fast) or transient (retry).
30
28
  *
31
29
  * Transient — worth retrying with backoff:
32
- * - network errors / anything without an HTTP status (git failures included:
33
- * most push/fetch failures are connectivity or contention and the retry
34
- * budget bounds the pathological cases)
35
- * - HTTP 408 (request timeout) and 429 (rate limited)
36
- * - HTTP 403 that carries a rate-limit signal (see `isRateLimitSignal403`):
37
- * GitHub returns 403, not 429, for both primary and secondary/abuse rate
38
- * limits. The throttling plugin (see github-service.ts createCanopyOctokit)
39
- * proactively retries short waits, but this carve-out remains the safety
40
- * net for waits the plugin gives up on (`shouldRetryRateLimit`/
41
- * `shouldRetrySecondaryRateLimit`) and for errors it never sees — without
42
- * it a rate-limited push-and-create-or-update-pr task would fail
43
- * permanently and wedge the branch (`sync-failed`, no retry).
44
- * - HTTP 5xx (server-side, usually recovers)
30
+ * - network errors / anything without an HTTP status, git failures included:
31
+ * most push/fetch failures are connectivity or contention, and the retry
32
+ * budget bounds the pathological cases;
33
+ * - HTTP 408 and 429;
34
+ * - HTTP 403 carrying a rate-limit signal (`isRateLimitSignal403`): GitHub
35
+ * returns 403, not 429, for both primary and secondary rate limits. The
36
+ * throttling plugin (github-service.ts's createCanopyOctokit) retries short
37
+ * waits, and this carve-out is the safety net for waits it gives up on and
38
+ * errors it never sees — without it a rate-limited
39
+ * push-and-create-or-update-pr task fails permanently and wedges the branch;
40
+ * - HTTP 5xx.
45
41
  *
46
42
  * Permanent — retrying the identical request cannot succeed:
47
- * - PermanentTaskError (malformed payload, unknown action)
48
- * - other HTTP 4xx (e.g. 401/404/422): the request itself is bad
49
- * - plain HTTP 403 with no rate-limit signal: a real permission denial
43
+ * - PermanentTaskError (malformed payload, unknown action);
44
+ * - other HTTP 4xx (401/404/422): the request itself is bad;
45
+ * - plain HTTP 403 with no rate-limit signal: a real permission denial.
50
46
  */
51
47
  export declare function isPermanentTaskFailure(err: unknown): boolean;
52
48
  /**
53
- * Staleness threshold for recoverOrphanedTasks, derived from the
54
- * configured task timeout rather than fixed: the safety argument for
55
- * running recovery on every poll cycle is "no legitimately in-flight task
56
- * can be this old, because executeTaskWithTimeout bounds every attempt by
57
- * taskTimeoutMs" -- which is only true if this threshold scales with
58
- * taskTimeoutMs. 2x leaves the same comfortable margin the defaults have
59
- * (60s timeout vs 5min threshold); the 5-minute floor preserves the
60
- * long-standing default for a replacement instance's boot window.
49
+ * Staleness threshold for recoverOrphanedTasks, derived from the configured
50
+ * task timeout rather than fixed. The safety argument for running recovery on
51
+ * every poll cycle is "no legitimately in-flight task can be this old, because
52
+ * executeTaskWithTimeout bounds every attempt by taskTimeoutMs" -- true only
53
+ * while this threshold scales with taskTimeoutMs. The 5-minute floor covers a
54
+ * replacement instance's boot window.
61
55
  */
62
56
  export declare function orphanRecoveryMaxAgeMs(ctx: Pick<TaskRunnerContext, 'taskTimeoutMs'>): number;
63
57
  /**
64
- * Process queued tasks from Lambda.
65
- * Polls .tasks/pending/ directory and executes each task.
66
- * Processes up to maxTasksPerCycle tasks per invocation.
67
- * Retries transient failures with exponential backoff.
58
+ * Process queued tasks from Lambda, up to maxTasksPerCycle per invocation.
68
59
  */
69
60
  export declare function processTaskQueue(ctx: TaskRunnerContext): Promise<void>;
70
- /**
71
- * Execute a task bounded by taskTimeoutMs (DEP-H1). Two layers:
72
- * - An AbortSignal cancels Octokit HTTP calls promptly.
73
- * - A Promise.race rejects when the timeout fires, so work that cannot
74
- * observe the signal (git subprocesses via simple-git) still fails the
75
- * attempt and the worker moves on instead of stalling forever.
76
- * That second layer also stops a hung `ctx.buildGitHubUrl()` in
77
- * pushBranchToGitHub from stalling the worker: resolving the tokenized URL is
78
- * async and does not observe the signal, so the attempt fails at taskTimeoutMs —
79
- * but the resolution is not cancelled, and if it later settles the abandoned
80
- * push continues. (On the App path the mint is separately bounded by
81
- * gitTokenMintTimeoutMs. git-sync.ts's two resolutions run on the sync loop,
82
- * not through here, and are not bounded by taskTimeoutMs.)
83
- * pushBranchToGitHub additionally kills stalled git processes via
84
- * simple-git's block timeout, so a hung push doesn't leak a process.
85
- */
86
- export declare function executeTaskWithTimeout(ctx: TaskRunnerContext, task: Task): Promise<Record<string, unknown>>;
87
61
  export declare function executeTask(ctx: TaskRunnerContext, task: Task, signal: AbortSignal): Promise<Record<string, unknown>>;
88
62
  /**
89
63
  * Update branch metadata after successful task completion.
90
- * Writes PR URL/number and sets syncStatus to 'synced'.
91
64
  */
92
65
  export declare function updateBranchMetadata(ctx: TaskRunnerContext, task: Task, result: Record<string, unknown>): Promise<void>;
93
- /**
94
- * Update branch metadata after permanent task failure.
95
- * Sets syncStatus to 'sync-failed' and records `error` (already redacted
96
- * by the caller, processTaskQueue -- see [REDACT] there) as
97
- * syncFailureReason, so the editor can show WHY, not just that it failed.
98
- */
99
- export declare function updateBranchMetadataOnFailure(ctx: TaskRunnerContext, task: Task, error: string): Promise<void>;
100
66
  export declare function pushBranchToGitHub(ctx: TaskRunnerContext, branch: string): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import { simpleGit } from 'simple-git';
3
- import { completeTask, dequeueTask, failTask, recoverOrphanedTasks, retryTask } from './task-queue.js';
3
+ import { completeTask, dequeueTask, failTask, recoverOrphanedTasks, retryTask, } from '../task-queue/cms-task-queue.js';
4
4
  import { createOrUpdatePullRequest } from '../github-service.js';
5
5
  import { BranchMetadataFileManager, getBranchMetadataFileManager } from '../branch-metadata.js';
6
6
  import { sanitizeBranchName } from '../paths/branch-name.js';
@@ -8,7 +8,7 @@ import { gitNetworkChildEnv } from '../git-manager.js';
8
8
  import { getErrorMessage, redactCredentials } from '../utils/error.js';
9
9
  import { isNonFastForwardRejection, isStaleLeaseRejection } from '../utils/git.js';
10
10
  import { clearHistoryRewrittenMarker, readPublishedSha } from './history-rewrite.js';
11
- import { writeWorkerStatus } from './worker-status.js';
11
+ import { writeWorkerStatus } from '../task-queue/worker-status.js';
12
12
  import { workerLog, workerLogError } from './log.js';
13
13
  /**
14
14
  * An error inherent to the task itself (malformed payload, unknown action):
@@ -21,24 +21,22 @@ export class PermanentTaskError extends Error {
21
21
  * Classify a task failure as permanent (fail fast) or transient (retry).
22
22
  *
23
23
  * Transient — worth retrying with backoff:
24
- * - network errors / anything without an HTTP status (git failures included:
25
- * most push/fetch failures are connectivity or contention and the retry
26
- * budget bounds the pathological cases)
27
- * - HTTP 408 (request timeout) and 429 (rate limited)
28
- * - HTTP 403 that carries a rate-limit signal (see `isRateLimitSignal403`):
29
- * GitHub returns 403, not 429, for both primary and secondary/abuse rate
30
- * limits. The throttling plugin (see github-service.ts createCanopyOctokit)
31
- * proactively retries short waits, but this carve-out remains the safety
32
- * net for waits the plugin gives up on (`shouldRetryRateLimit`/
33
- * `shouldRetrySecondaryRateLimit`) and for errors it never sees — without
34
- * it a rate-limited push-and-create-or-update-pr task would fail
35
- * permanently and wedge the branch (`sync-failed`, no retry).
36
- * - HTTP 5xx (server-side, usually recovers)
24
+ * - network errors / anything without an HTTP status, git failures included:
25
+ * most push/fetch failures are connectivity or contention, and the retry
26
+ * budget bounds the pathological cases;
27
+ * - HTTP 408 and 429;
28
+ * - HTTP 403 carrying a rate-limit signal (`isRateLimitSignal403`): GitHub
29
+ * returns 403, not 429, for both primary and secondary rate limits. The
30
+ * throttling plugin (github-service.ts's createCanopyOctokit) retries short
31
+ * waits, and this carve-out is the safety net for waits it gives up on and
32
+ * errors it never sees — without it a rate-limited
33
+ * push-and-create-or-update-pr task fails permanently and wedges the branch;
34
+ * - HTTP 5xx.
37
35
  *
38
36
  * Permanent — retrying the identical request cannot succeed:
39
- * - PermanentTaskError (malformed payload, unknown action)
40
- * - other HTTP 4xx (e.g. 401/404/422): the request itself is bad
41
- * - plain HTTP 403 with no rate-limit signal: a real permission denial
37
+ * - PermanentTaskError (malformed payload, unknown action);
38
+ * - other HTTP 4xx (401/404/422): the request itself is bad;
39
+ * - plain HTTP 403 with no rate-limit signal: a real permission denial.
42
40
  */
43
41
  export function isPermanentTaskFailure(err) {
44
42
  if (err instanceof PermanentTaskError)
@@ -74,11 +72,10 @@ function getResponseHeaders(err) {
74
72
  return headers;
75
73
  }
76
74
  /**
77
- * Detect whether a 403 is a GitHub rate-limit response rather than a plain
78
- * permission denial. GitHub signals rate limiting on 403s three ways: the
79
- * primary limit zeroes out `x-ratelimit-remaining`, secondary/abuse limits
80
- * often include a `retry-after` header, and both cases produce a message
81
- * containing "rate limit" (e.g. "You have exceeded a secondary rate limit").
75
+ * Whether a 403 is a GitHub rate-limit response rather than a plain permission
76
+ * denial. GitHub signals rate limiting on 403s three ways: the primary limit
77
+ * zeroes `x-ratelimit-remaining`, secondary limits often carry `retry-after`,
78
+ * and both produce a message containing "rate limit".
82
79
  */
83
80
  function isRateLimitSignal403(err) {
84
81
  const headers = getResponseHeaders(err);
@@ -110,49 +107,35 @@ function optionalString(payload, key, fallback) {
110
107
  return typeof val === 'string' ? val : fallback;
111
108
  }
112
109
  /**
113
- * Staleness threshold for recoverOrphanedTasks, derived from the
114
- * configured task timeout rather than fixed: the safety argument for
115
- * running recovery on every poll cycle is "no legitimately in-flight task
116
- * can be this old, because executeTaskWithTimeout bounds every attempt by
117
- * taskTimeoutMs" -- which is only true if this threshold scales with
118
- * taskTimeoutMs. 2x leaves the same comfortable margin the defaults have
119
- * (60s timeout vs 5min threshold); the 5-minute floor preserves the
120
- * long-standing default for a replacement instance's boot window.
110
+ * Staleness threshold for recoverOrphanedTasks, derived from the configured
111
+ * task timeout rather than fixed. The safety argument for running recovery on
112
+ * every poll cycle is "no legitimately in-flight task can be this old, because
113
+ * executeTaskWithTimeout bounds every attempt by taskTimeoutMs" -- true only
114
+ * while this threshold scales with taskTimeoutMs. The 5-minute floor covers a
115
+ * replacement instance's boot window.
121
116
  */
122
117
  export function orphanRecoveryMaxAgeMs(ctx) {
123
118
  return Math.max(5 * 60_000, ctx.taskTimeoutMs * 2);
124
119
  }
125
120
  /**
126
- * Process queued tasks from Lambda.
127
- * Polls .tasks/pending/ directory and executes each task.
128
- * Processes up to maxTasksPerCycle tasks per invocation.
129
- * Retries transient failures with exponential backoff.
121
+ * Process queued tasks from Lambda, up to maxTasksPerCycle per invocation.
130
122
  */
131
123
  export async function processTaskQueue(ctx) {
132
124
  if (!ctx.isRunning())
133
125
  return;
134
126
  // Recover tasks orphaned in processing/ on EVERY cycle, not only at boot
135
- // (start()'s call above). Before this fix, recoverOrphanedTasks() ran
136
- // exactly once, at start() - fine when an instance was replaced rarely
137
- // (a spot interruption), but CanopyCmsService's worker ASG now rolls on
138
- // every `cdk deploy` (see its UpdatePolicy), making replacement routine.
139
- // A replacement instance's user-data (yum install git/unzip/nodejs/
140
- // efs-utils, mount EFS) takes roughly 2-4 minutes, well under
141
- // recoverOrphanedTasks()'s 5-minute default staleness threshold - so
142
- // THAT ONE boot-time call would see the just-orphaned file as "too
143
- // fresh" and skip it, and nothing rescanned afterward: the task (and its
144
- // branch's syncStatus) would be wedged forever. Re-checking every poll
145
- // means the file's age eventually crosses the threshold and it gets
146
- // recovered without operator intervention.
127
+ // (start()'s call). Instance replacement is routine -- CanopyCmsService's
128
+ // worker ASG rolls on every `cdk deploy` -- and a replacement's user-data
129
+ // takes roughly 2-4 minutes, well under the staleness threshold, so a
130
+ // boot-only call sees the just-orphaned file as "too fresh", skips it, and
131
+ // nothing rescans: the task and its branch's syncStatus wedge forever.
147
132
  //
148
- // Safe to run this often: executeTaskWithTimeout() guarantees every task
149
- // THIS process dequeues is completed, failed, or retried (all three
150
- // remove the processing/ file) within taskTimeoutMs - and the staleness
151
- // threshold is derived from taskTimeoutMs (orphanRecoveryMaxAgeMs below)
152
- // precisely so that guarantee holds for ANY configured timeout, not just
153
- // the 60s default: a fixed 5-minute threshold would have this call steal
154
- // the worker's own still-in-flight task back to pending whenever an
155
- // adopter configured taskTimeoutMs above ~5 minutes.
133
+ // Safe to run this often because executeTaskWithTimeout() guarantees every
134
+ // task THIS process dequeues is completed, failed or retried (all three
135
+ // remove the processing/ file) within taskTimeoutMs -- which is why the
136
+ // threshold is derived from taskTimeoutMs (orphanRecoveryMaxAgeMs) rather
137
+ // than fixed. A fixed 5 minutes would steal the worker's own in-flight task
138
+ // back to pending whenever an adopter configured a longer timeout.
156
139
  const recovered = await recoverOrphanedTasks(ctx.taskDir, orphanRecoveryMaxAgeMs(ctx), ctx.log);
157
140
  if (recovered > 0) {
158
141
  workerLog(`Recovered ${recovered} orphaned task(s)`);
@@ -169,14 +152,13 @@ export async function processTaskQueue(ctx) {
169
152
  catch (err) {
170
153
  const message = getErrorMessage(err);
171
154
  workerLogError(`Task ${task.id} (${task.action}) failed:`, message);
172
- // [REDACT] task.error is persisted (pending/failed task JSON) and
173
- // served to the browser by the admin panel's Tasks tab -- a push
174
- // failure's message can embed the bot token via buildGitHubUrl().
175
- // Console output above stays raw (journald/CloudWatch is trusted).
155
+ // [REDACT] task.error is persisted (pending/failed task JSON) and served
156
+ // to the browser by the admin panel's Tasks tab -- a push failure's
157
+ // message can embed the bot token via buildGitHubUrl(). Console output
158
+ // above stays raw (journald/CloudWatch is trusted).
176
159
  const persistedMessage = redactCredentials(message);
177
- // DEP-L1: only transient failures (network, 429/5xx, timeouts) are
178
- // worth retrying; permanent ones (malformed payload, other 4xx) would
179
- // just burn the retry budget on an identical doomed request.
160
+ // DEP-L1: only transient failures are worth retrying; a permanent one
161
+ // would burn the retry budget on an identical doomed request.
180
162
  const permanent = isPermanentTaskFailure(err);
181
163
  const retryCount = task.retryCount ?? 0;
182
164
  const maxRetries = task.maxRetries ?? ctx.maxRetries;
@@ -191,26 +173,23 @@ export async function processTaskQueue(ctx) {
191
173
  ? ' Permanently failed (non-retryable error)'
192
174
  : ` Permanently failed after ${maxRetries} retries`);
193
175
  }
194
- // The credential may have rotated. Without this, a push meeting a revoked
195
- // token spent its whole retry budget (5s/10s/20s backoff) waiting on the
196
- // git-sync loop's refresh, up to 5 minutes away, and failed permanently
197
- // while the working token sat in the secret store. With it, the retry
198
- // resolves buildGitHubUrl() afresh and picks the new token up — unless
199
- // another failure used the re-read within the floor (60s in core, five
200
- // minutes for the AWS provider), in which case a publish that exhausts
201
- // its retries first still fails.
176
+ // The credential may have rotated, and the next retry resolves
177
+ // buildGitHubUrl() afresh to pick a new token up. Without this a push
178
+ // meeting a revoked token spends its whole retry budget (5s/10s/20s
179
+ // backoff) waiting on the git-sync loop's refresh up to 5 minutes away,
180
+ // and fails permanently while the working token sits in the secret store.
202
181
  //
203
- // Ungated, and after the outcome is recorded rather than before: the task
182
+ // Ungated, and AFTER the outcome is recorded rather than before: the task
204
183
  // is safely in pending/ or failed/ while a network read runs, and that
205
184
  // read is bounded and never throws. See CmsWorker.refreshGitHubCredential.
206
185
  await ctx.refreshGitHubCredential();
207
186
  }
208
187
  processed++;
209
188
  }
210
- // PR-W1: only stamp/write when work actually happened this poll --
211
- // otherwise every idle 5s poll would hit worker-status.json, an EFS
212
- // write treadmill for no signal (liveness is already covered by the
213
- // lock heartbeat; see api/admin.ts's classifyWorkerLiveness).
189
+ // Only stamp/write when work actually happened this poll: otherwise every
190
+ // idle 5s poll would hit worker-status.json, an EFS write treadmill for no
191
+ // signal, since liveness is already covered by the lock heartbeat (see
192
+ // api/admin.ts's classifyWorkerLiveness).
214
193
  if (processed > 0) {
215
194
  const report = ctx.ensureStatusReport();
216
195
  report.lastTaskCycleAt = new Date().toISOString();
@@ -219,21 +198,19 @@ export async function processTaskQueue(ctx) {
219
198
  }
220
199
  /**
221
200
  * Execute a task bounded by taskTimeoutMs (DEP-H1). Two layers:
222
- * - An AbortSignal cancels Octokit HTTP calls promptly.
223
- * - A Promise.race rejects when the timeout fires, so work that cannot
224
- * observe the signal (git subprocesses via simple-git) still fails the
225
- * attempt and the worker moves on instead of stalling forever.
226
- * That second layer also stops a hung `ctx.buildGitHubUrl()` in
227
- * pushBranchToGitHub from stalling the worker: resolving the tokenized URL is
228
- * async and does not observe the signal, so the attempt fails at taskTimeoutMs —
229
- * but the resolution is not cancelled, and if it later settles the abandoned
230
- * push continues. (On the App path the mint is separately bounded by
231
- * gitTokenMintTimeoutMs. git-sync.ts's two resolutions run on the sync loop,
232
- * not through here, and are not bounded by taskTimeoutMs.)
233
- * pushBranchToGitHub additionally kills stalled git processes via
234
- * simple-git's block timeout, so a hung push doesn't leak a process.
201
+ * - an AbortSignal cancels Octokit HTTP calls promptly;
202
+ * - a Promise.race rejects when the timeout fires, so work that cannot observe
203
+ * the signal (git subprocesses via simple-git, and a hung
204
+ * `ctx.buildGitHubUrl()` in pushBranchToGitHub) still fails the attempt and
205
+ * the worker moves on instead of stalling forever.
206
+ *
207
+ * A raced-out resolution is not CANCELLED: if it later settles, the abandoned
208
+ * push continues. On the App path the mint is separately bounded by
209
+ * gitTokenMintTimeoutMs, and git-sync.ts's two resolutions run on the sync loop
210
+ * and are not bounded by taskTimeoutMs at all. pushBranchToGitHub additionally
211
+ * kills stalled git processes via simple-git's block timeout.
235
212
  */
236
- export async function executeTaskWithTimeout(ctx, task) {
213
+ async function executeTaskWithTimeout(ctx, task) {
237
214
  const controller = new AbortController();
238
215
  const timer = setTimeout(() => controller.abort(), ctx.taskTimeoutMs);
239
216
  try {
@@ -289,22 +266,19 @@ export async function executeTask(ctx, task, signal) {
289
266
  return { prNumber };
290
267
  }
291
268
  case 'push-and-create-or-update-pr': {
292
- // GIT-H1: idempotent create-or-update. Used for both content-branch
293
- // submits and settings-branch syncs so a retry after a crash (task
294
- // completed on GitHub but branch metadata never recorded the PR
295
- // number) recovers the existing PR instead of hitting the 422 that
296
- // a blind `pulls.create` would throw on a duplicate head+base.
297
- // Delegates to the shared helper (also used by GitHubService's
298
- // direct-API path) so the list->tiebreak->update/create logic and
299
- // the draft->ready conversion live in one place.
269
+ // GIT-H1: idempotent create-or-update, so a retry after a crash (the task
270
+ // completed on GitHub but branch metadata never recorded the PR number)
271
+ // recovers the existing PR instead of hitting the 422 a blind
272
+ // `pulls.create` throws on a duplicate head+base. Delegates to the shared
273
+ // helper GitHubService's direct-API path also uses, so the
274
+ // list->tiebreak->update/create logic and the draft->ready conversion
275
+ // live in one place.
300
276
  const branch = requireString(payload, 'branch');
301
277
  const base = optionalString(payload, 'baseBranch', ctx.baseBranch);
302
278
  // Defense-in-depth: refuse head===base even if the 'submittableBranch'
303
- // API guard and the syncSubmitPr backstop were both somehow bypassed
304
- // (e.g. a task queued before this check shipped). PermanentTaskError
305
- // (not a plain Error) so this fails immediately instead of burning
306
- // the retry budget on an identical doomed request -- retrying can
307
- // never make the branch not be the base branch.
279
+ // API guard and the syncSubmitPr backstop were both bypassed.
280
+ // PermanentTaskError, not a plain Error, so it fails immediately --
281
+ // retrying can never make the branch not be the base branch.
308
282
  if (sanitizeBranchName(branch) === ctx.sanitizedBaseBranch) {
309
283
  throw new PermanentTaskError(`Refusing to push-and-create-or-update-pr for "${branch}": it is the base branch -- submitting the base branch is never valid`);
310
284
  }
@@ -370,7 +344,6 @@ export async function executeTask(ctx, task, signal) {
370
344
  }
371
345
  /**
372
346
  * Update branch metadata after successful task completion.
373
- * Writes PR URL/number and sets syncStatus to 'synced'.
374
347
  */
375
348
  export async function updateBranchMetadata(ctx, task, result) {
376
349
  const branch = typeof task.payload.branch === 'string' ? task.payload.branch : null;
@@ -388,22 +361,20 @@ export async function updateBranchMetadata(ctx, task, result) {
388
361
  const updates = {
389
362
  name: branch,
390
363
  syncStatus: 'synced',
391
- // save()'s merge only overwrites keys present in this update (see
392
- // BranchMetadataFileManager.save()'s spread order) -- a prior
393
- // syncFailureReason from an earlier failed attempt would otherwise
394
- // survive forever past this successful sync. Explicitly clear it,
395
- // same pattern as rebaseFailure's PR-W2 M2 clearing elsewhere.
364
+ // save()'s merge only overwrites keys present in this update, so a prior
365
+ // syncFailureReason would survive this successful sync forever unless
366
+ // cleared explicitly (same pattern as rebaseFailure elsewhere).
396
367
  syncFailureReason: undefined,
397
368
  };
398
369
  if (result.prUrl)
399
370
  updates.pullRequestUrl = result.prUrl;
400
371
  if (result.prNumber) {
401
372
  updates.pullRequestNumber = result.prNumber;
402
- // As soon as the PR exists the field should read 'open' -- without
403
- // this it would stay absent until the next poll cycle observes it.
404
- // Exception: the git-sync loop may have archived this branch (PR
405
- // merged/closed) while this task was in flight; a late task
406
- // completion must not downgrade that terminal state back to 'open'.
373
+ // As soon as the PR exists the field reads 'open', rather than staying
374
+ // absent until the next poll cycle observes it. Exception: the git-sync
375
+ // loop may have archived this branch (PR merged/closed) while the task
376
+ // was in flight, and a late completion must not downgrade that terminal
377
+ // state back to 'open'.
407
378
  const current = await BranchMetadataFileManager.loadOnly(branchPath);
408
379
  const terminal = current?.branch.status === 'archived' ||
409
380
  current?.branch.pullRequestState === 'merged' ||
@@ -419,12 +390,11 @@ export async function updateBranchMetadata(ctx, task, result) {
419
390
  }
420
391
  }
421
392
  /**
422
- * Update branch metadata after permanent task failure.
423
- * Sets syncStatus to 'sync-failed' and records `error` (already redacted
424
- * by the caller, processTaskQueue -- see [REDACT] there) as
425
- * syncFailureReason, so the editor can show WHY, not just that it failed.
393
+ * Update branch metadata after permanent task failure. `error` is already
394
+ * redacted by the caller (see [REDACT] in processTaskQueue) and is recorded as
395
+ * syncFailureReason so the editor can show WHY, not just that it failed.
426
396
  */
427
- export async function updateBranchMetadataOnFailure(ctx, task, error) {
397
+ async function updateBranchMetadataOnFailure(ctx, task, error) {
428
398
  const branch = typeof task.payload.branch === 'string' ? task.payload.branch : null;
429
399
  if (!branch)
430
400
  return;
@@ -448,36 +418,33 @@ export async function updateBranchMetadataOnFailure(ctx, task, error) {
448
418
  export async function pushBranchToGitHub(ctx, branch) {
449
419
  const git = simpleGit({
450
420
  baseDir: ctx.remoteGitPath,
451
- // DEP-H1: kill the git process if it produces no output for
452
- // taskTimeoutMs (network stall, credential prompt) instead of letting
453
- // it hang past the task timeout.
421
+ // DEP-H1: kill the git process if it produces no output for taskTimeoutMs
422
+ // (network stall, credential prompt) instead of letting it hang past the
423
+ // task timeout.
454
424
  timeout: { block: ctx.taskTimeoutMs },
455
425
  });
456
- // Force stable (English) git output so isNonFastForwardRejection below
457
- // can reliably match it -- git's rejection text is gettext-translated, so
458
- // a non-English host would silently turn that classifier into a no-op.
459
- // gitNetworkChildEnv (NOT gitChildEnv) because this call talks to GitHub:
460
- // it keeps ambient HTTPS_PROXY/GIT_SSL_*/GIT_SSH_COMMAND, which
461
- // gitChildEnv's local-ops allowlist deliberately drops.
426
+ // Force stable (English) git output so isNonFastForwardRejection below can
427
+ // match it -- git's rejection text is gettext-translated, so a non-English
428
+ // host would silently turn that classifier into a no-op. gitNetworkChildEnv
429
+ // (NOT gitChildEnv) because this call talks to GitHub: it keeps ambient
430
+ // HTTPS_PROXY/GIT_SSL_*/GIT_SSH_COMMAND, which gitChildEnv's local-ops
431
+ // allowlist deliberately drops.
462
432
  git.env(gitNetworkChildEnv());
463
- // Resolve the tokenized URL ONCE, here, before anything below runs. All
464
- // three pushes in this function use this const; none of them calls
465
- // ctx.buildGitHubUrl() again. That is a correctness requirement, not tidiness
466
- // -- resolution is async, and doing it per-push breaks two things:
433
+ // Resolve the tokenized URL ONCE, here: all three pushes below use this
434
+ // const and none calls ctx.buildGitHubUrl() again. A correctness
435
+ // requirement, not tidiness, since resolution is async:
467
436
  //
468
- // - The retry push below sits INSIDE the stale-lease catch. A resolution
469
- // that threw there would replace the push error being classified, so
470
- // neither isStaleLeaseRejection nor isNonFastForwardRejection would ever
471
- // run and a genuinely diverged branch would be retried instead of raising
472
- // PermanentTaskError -- re-introducing exactly the retry-budget burn that
473
- // carve-out exists to prevent.
437
+ // - the retry push sits INSIDE the stale-lease catch, and a resolution that
438
+ // threw there would replace the push error being classified, so neither
439
+ // isStaleLeaseRejection nor isNonFastForwardRejection would run and a
440
+ // genuinely diverged branch would be retried instead of raising
441
+ // PermanentTaskError;
474
442
  // - readPublishedSha below captures remote.git's tip BEFORE the push, and
475
- // that value decides whether the [SYNC-H1] marker gets cleared at the end.
476
- // An awaited resolution between the read and the push widens the window in
477
- // which remote.git's tip can move underneath that decision.
443
+ // that value decides whether the [SYNC-H1] marker is cleared at the end.
444
+ // An awaited resolution in between widens the window in which the tip can
445
+ // move underneath that decision.
478
446
  //
479
- // It also means all three pushes provably carry the same credential, rather
480
- // than one per push with an expiry boundary somewhere in between.
447
+ // It also means all three pushes provably carry the same credential.
481
448
  const githubUrl = await ctx.buildGitHubUrl();
482
449
  // [SYNC-H1] If the rebase loop rewrote this branch's already-published
483
450
  // history, GitHub still holds the commit it replaced, so an ordinary
@@ -507,23 +474,20 @@ export async function pushBranchToGitHub(ctx, branch) {
507
474
  catch (err) {
508
475
  const message = getErrorMessage(err);
509
476
  // A refused lease means GitHub is not at the commit we rewrote, so the
510
- // marker is stale -- which is routine, not exceptional: tasks are
511
- // re-run after a crash (recoverOrphanedTasks), and the marker survives
512
- // any failure to clear it. Two benign shapes reach here, and both are
513
- // ordinary fast-forwards that a lease has no business blocking:
514
- // GitHub already holds the rewritten history from an earlier attempt,
515
- // or the branch has since moved past it.
477
+ // marker is stale -- routine, not exceptional: tasks are re-run after a
478
+ // crash (recoverOrphanedTasks) and the marker survives any failure to
479
+ // clear it. The two benign shapes that reach here (GitHub already holds
480
+ // the rewritten history, or the branch moved past it) are ordinary
481
+ // fast-forwards a lease has no business blocking.
516
482
  //
517
- // Retry PLAIN, and let git adjudicate. A non-forced push succeeds if
518
- // and only if it fast-forwards, so it can never destroy anything --
519
- // there is no ancestry check to get wrong here, and no extra network
520
- // round trip to read GitHub's tip. Only if THAT is also rejected has
521
- // the branch genuinely diverged.
483
+ // So retry PLAIN and let git adjudicate: a non-forced push succeeds if and
484
+ // only if it fast-forwards, so it can never destroy anything, with no
485
+ // ancestry check to get wrong and no extra round trip to read GitHub's
486
+ // tip. Only if THAT is also rejected has the branch genuinely diverged.
522
487
  //
523
- // (Verified: git evaluates the lease only when it actually has an
524
- // update to apply. An up-to-date ref with a stale lease prints
525
- // "Everything up-to-date" and exits 0, so the already-landed case is
526
- // usually absorbed above and never even reaches this branch.)
488
+ // (git evaluates the lease only when it actually has an update to apply,
489
+ // so an up-to-date ref with a stale lease prints "Everything up-to-date",
490
+ // exits 0, and is absorbed above without reaching here.)
527
491
  if (marker && isStaleLeaseRejection(message)) {
528
492
  try {
529
493
  await git.push(githubUrl, branch);
@@ -545,11 +509,11 @@ export async function pushBranchToGitHub(ctx, branch) {
545
509
  return;
546
510
  }
547
511
  // An ordinary non-fast-forward rejection: GitHub has commits this
548
- // deployment never published. Retrying the identical push can never
549
- // succeed (DEP-L1's git-failure-is-transient carve-out does NOT apply
550
- // here), so fail fast instead of burning the task's retry budget.
551
- // Deliberately does NOT advise renaming the branch: a branch reaching
552
- // this point usually has an open PR, and renaming would orphan it.
512
+ // deployment never published, so retrying the identical push can never
513
+ // succeed (DEP-L1's git-failure-is-transient carve-out does NOT apply) and
514
+ // it fails fast instead of burning the retry budget. Deliberately does NOT
515
+ // advise renaming the branch: one reaching this point usually has an open
516
+ // PR, which renaming would orphan.
553
517
  if (isNonFastForwardRejection(message)) {
554
518
  throw new PermanentTaskError(`Push rejected for branch "${branch}": GitHub's tip is not what this deployment last ` +
555
519
  `published, so the branch has diverged and needs reconciling. Something else moved it ` +