canopycms 0.0.68-int.98 → 0.1.0

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 (688) hide show
  1. package/CHANGELOG.md +2131 -0
  2. package/README.md +47 -63
  3. package/dist/ai/generate.d.ts +5 -0
  4. package/dist/ai/generate.js +244 -115
  5. package/dist/ai/index.d.ts +1 -1
  6. package/dist/ai/json-to-markdown.d.ts +21 -1
  7. package/dist/ai/json-to-markdown.js +120 -57
  8. package/dist/ai/references.d.ts +72 -0
  9. package/dist/ai/references.js +223 -0
  10. package/dist/ai/resolve-branch.js +9 -2
  11. package/dist/ai/to-plain-text.d.ts +17 -8
  12. package/dist/ai/to-plain-text.js +18 -15
  13. package/dist/ai/types.d.ts +84 -3
  14. package/dist/api/admin-branch-health.d.ts +24 -1
  15. package/dist/api/admin-branch-health.js +52 -20
  16. package/dist/api/admin.d.ts +23 -5
  17. package/dist/api/admin.js +36 -1
  18. package/dist/api/assets.js +88 -78
  19. package/dist/api/branch-create-window.d.ts +12 -0
  20. package/dist/api/branch-create-window.js +13 -0
  21. package/dist/api/branch-merge.d.ts +1 -1
  22. package/dist/api/branch-merge.js +1 -1
  23. package/dist/api/branch-review.d.ts +3 -3
  24. package/dist/api/branch-review.js +16 -7
  25. package/dist/api/branch-status.d.ts +16 -6
  26. package/dist/api/branch-status.js +57 -12
  27. package/dist/api/branch-withdraw.d.ts +2 -2
  28. package/dist/api/branch-withdraw.js +8 -3
  29. package/dist/api/branch.d.ts +25 -12
  30. package/dist/api/branch.js +164 -103
  31. package/dist/api/client.d.ts +78 -58
  32. package/dist/api/client.js +150 -117
  33. package/dist/api/comments.d.ts +12 -3
  34. package/dist/api/comments.js +118 -9
  35. package/dist/api/content.d.ts +9 -9
  36. package/dist/api/content.js +131 -22
  37. package/dist/api/entries-constants.d.ts +14 -3
  38. package/dist/api/entries-constants.js +14 -3
  39. package/dist/api/entries.d.ts +40 -2
  40. package/dist/api/entries.js +102 -6
  41. package/dist/api/github-sync.d.ts +19 -0
  42. package/dist/api/github-sync.js +50 -3
  43. package/dist/api/groups.d.ts +4 -4
  44. package/dist/api/groups.js +2 -1
  45. package/dist/api/guards.js +23 -3
  46. package/dist/api/index.d.ts +3 -1
  47. package/dist/api/index.js +1 -0
  48. package/dist/api/permissions.d.ts +21 -2
  49. package/dist/api/permissions.js +50 -3
  50. package/dist/api/request-deadline.d.ts +59 -0
  51. package/dist/api/request-deadline.js +73 -0
  52. package/dist/api/resolve-references.js +8 -7
  53. package/dist/api/route-builder.d.ts +14 -0
  54. package/dist/api/route-builder.js +14 -1
  55. package/dist/api/schema.d.ts +11 -9
  56. package/dist/api/schema.js +2 -0
  57. package/dist/api/settings-helpers.d.ts +5 -1
  58. package/dist/api/settings-helpers.js +10 -2
  59. package/dist/api/types.d.ts +18 -0
  60. package/dist/api/users-constants.d.ts +6 -0
  61. package/dist/api/users-constants.js +6 -0
  62. package/dist/assets/asset-url.d.ts +28 -16
  63. package/dist/assets/asset-url.js +51 -25
  64. package/dist/assets/finalize.js +3 -0
  65. package/dist/assets/index.d.ts +1 -1
  66. package/dist/assets/materialize.d.ts +153 -0
  67. package/dist/assets/materialize.js +402 -0
  68. package/dist/assets/store-local.d.ts +19 -5
  69. package/dist/assets/store-local.js +69 -10
  70. package/dist/assets/store-s3.d.ts +38 -7
  71. package/dist/assets/store-s3.js +128 -22
  72. package/dist/assets/transform-directives.d.ts +52 -13
  73. package/dist/assets/transform-directives.js +87 -27
  74. package/dist/assets/transform.d.ts +3 -3
  75. package/dist/assets/transform.js +13 -8
  76. package/dist/assets/types.d.ts +31 -4
  77. package/dist/auth/cache.d.ts +1 -1
  78. package/dist/auth/cache.js +1 -1
  79. package/dist/auth/caching-auth-plugin.d.ts +2 -0
  80. package/dist/auth/caching-auth-plugin.js +12 -2
  81. package/dist/auth/file-based-auth-cache.d.ts +8 -0
  82. package/dist/auth/file-based-auth-cache.js +18 -8
  83. package/dist/auth/person-name.d.ts +5 -0
  84. package/dist/auth/person-name.js +8 -0
  85. package/dist/auth/plugin.d.ts +10 -1
  86. package/dist/auth/types.d.ts +2 -0
  87. package/dist/auth/user-metadata-lookup.d.ts +21 -0
  88. package/dist/auth/user-metadata-lookup.js +116 -0
  89. package/dist/authorization/branch.d.ts +1 -1
  90. package/dist/authorization/branch.js +12 -13
  91. package/dist/authorization/groups/schema.d.ts +4 -4
  92. package/dist/authorization/helpers.d.ts +8 -0
  93. package/dist/authorization/helpers.js +8 -0
  94. package/dist/authorization/index.d.ts +1 -1
  95. package/dist/authorization/index.js +1 -1
  96. package/dist/authorization/protected-branch.d.ts +5 -4
  97. package/dist/authorization/protected-branch.js +7 -5
  98. package/dist/branch-health.d.ts +35 -8
  99. package/dist/branch-health.js +54 -18
  100. package/dist/branch-metadata-error.d.ts +27 -0
  101. package/dist/branch-metadata-error.js +23 -0
  102. package/dist/branch-metadata-file.d.ts +205 -24
  103. package/dist/branch-metadata-file.js +126 -25
  104. package/dist/branch-metadata.d.ts +45 -6
  105. package/dist/branch-metadata.js +142 -50
  106. package/dist/branch-provisioning.d.ts +167 -0
  107. package/dist/branch-provisioning.js +501 -0
  108. package/dist/branch-registry.d.ts +8 -0
  109. package/dist/branch-registry.js +61 -9
  110. package/dist/branch-schema-cache.d.ts +29 -12
  111. package/dist/branch-schema-cache.js +64 -21
  112. package/dist/branch-sparse.d.ts +23 -0
  113. package/dist/branch-sparse.js +118 -0
  114. package/dist/branch-workspace.d.ts +42 -3
  115. package/dist/branch-workspace.js +239 -100
  116. package/dist/build/asset-refs.d.ts +94 -0
  117. package/dist/build/asset-refs.js +267 -0
  118. package/dist/build/generate-ai-content.js +5 -0
  119. package/dist/build/inline-flight.d.ts +37 -0
  120. package/dist/build/inline-flight.js +142 -0
  121. package/dist/cli/asset-refs.d.ts +52 -0
  122. package/dist/cli/asset-refs.js +194 -0
  123. package/dist/cli/cli.d.ts +15 -1
  124. package/dist/cli/cli.js +8543 -3193
  125. package/dist/cli/configured-asset-store.d.ts +12 -0
  126. package/dist/cli/configured-asset-store.js +46 -0
  127. package/dist/cli/generate-ai-content.js +4244 -1072
  128. package/dist/cli/init.js +217 -126
  129. package/dist/cli/project-detect.d.ts +2 -0
  130. package/dist/cli/project-detect.js +2 -0
  131. package/dist/cli/template-files/Dockerfile.cms.template +13 -5
  132. package/dist/cli/template-files/cms-stack.ts.template +16 -13
  133. package/dist/client.d.ts +1 -2
  134. package/dist/client.js +1 -2
  135. package/dist/comment-store.d.ts +25 -0
  136. package/dist/comment-store.js +43 -8
  137. package/dist/config/flatten.js +2 -0
  138. package/dist/config/helpers.js +2 -2
  139. package/dist/config/index.d.ts +1 -1
  140. package/dist/config/schemas/config.d.ts +12 -29
  141. package/dist/config/schemas/config.js +9 -12
  142. package/dist/config/schemas/field.d.ts +3 -0
  143. package/dist/config/schemas/field.js +58 -4
  144. package/dist/config/schemas/media.d.ts +4 -13
  145. package/dist/config/schemas/media.js +5 -8
  146. package/dist/config/schemas/url.d.ts +2 -20
  147. package/dist/config/schemas/url.js +2 -25
  148. package/dist/config/types.d.ts +116 -22
  149. package/dist/config/types.js +3 -9
  150. package/dist/config/validation.d.ts +25 -4
  151. package/dist/config/validation.js +116 -3
  152. package/dist/content-id-index.js +2 -2
  153. package/dist/content-index-generation.d.ts +1 -1
  154. package/dist/content-index-generation.js +1 -1
  155. package/dist/content-listing.d.ts +10 -1
  156. package/dist/content-listing.js +22 -5
  157. package/dist/content-reader.d.ts +9 -0
  158. package/dist/content-reader.js +16 -11
  159. package/dist/content-store.d.ts +75 -12
  160. package/dist/content-store.js +249 -86
  161. package/dist/content-tree.js +2 -2
  162. package/dist/context.js +5 -2
  163. package/dist/dangling-reference-log.d.ts +17 -0
  164. package/dist/dangling-reference-log.js +29 -0
  165. package/dist/dev-content-watcher.d.ts +1 -1
  166. package/dist/dev-content-watcher.js +1 -1
  167. package/dist/editor/BranchManager.d.ts +23 -7
  168. package/dist/editor/BranchManager.js +119 -54
  169. package/dist/editor/CanopyEditor.d.ts +1 -1
  170. package/dist/editor/CanopyEditor.js +1 -2
  171. package/dist/editor/CommentsPanel.d.ts +14 -0
  172. package/dist/editor/CommentsPanel.js +68 -43
  173. package/dist/editor/Editor.d.ts +11 -5
  174. package/dist/editor/Editor.js +891 -218
  175. package/dist/editor/EditorAuthGate.d.ts +7 -1
  176. package/dist/editor/EditorAuthGate.js +41 -9
  177. package/dist/editor/EntryNavigator.d.ts +22 -0
  178. package/dist/editor/EntryNavigator.js +353 -105
  179. package/dist/editor/FormHeader.d.ts +25 -0
  180. package/dist/editor/FormHeader.js +82 -0
  181. package/dist/editor/FormRenderer.d.ts +27 -3
  182. package/dist/editor/FormRenderer.js +171 -76
  183. package/dist/editor/PreviewFrame.d.ts +40 -0
  184. package/dist/editor/PreviewFrame.js +215 -0
  185. package/dist/editor/PreviewPane.d.ts +47 -0
  186. package/dist/editor/PreviewPane.js +147 -0
  187. package/dist/editor/PreviewToolbarTools.d.ts +22 -0
  188. package/dist/editor/PreviewToolbarTools.js +73 -0
  189. package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
  190. package/dist/editor/admin/SystemHealthPanel.js +163 -33
  191. package/dist/editor/admin/useSystemHealth.d.ts +18 -0
  192. package/dist/editor/admin/useSystemHealth.js +70 -1
  193. package/dist/editor/branch-status.d.ts +17 -0
  194. package/dist/editor/branch-status.js +29 -0
  195. package/dist/editor/canopy-path.d.ts +9 -6
  196. package/dist/editor/canopy-path.js +8 -11
  197. package/dist/editor/client-reference-resolver.d.ts +43 -16
  198. package/dist/editor/client-reference-resolver.js +155 -64
  199. package/dist/editor/comments/BranchComments.d.ts +1 -1
  200. package/dist/editor/comments/BranchComments.js +2 -2
  201. package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
  202. package/dist/editor/comments/CloseRefusedNotice.js +7 -0
  203. package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
  204. package/dist/editor/comments/CommentThreadsPopover.js +274 -0
  205. package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
  206. package/dist/editor/comments/CommentWriteAlert.js +13 -0
  207. package/dist/editor/comments/EntryComments.d.ts +10 -4
  208. package/dist/editor/comments/EntryComments.js +14 -17
  209. package/dist/editor/comments/FieldWrapper.d.ts +18 -4
  210. package/dist/editor/comments/FieldWrapper.js +62 -28
  211. package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
  212. package/dist/editor/comments/InlineCommentThread.js +11 -47
  213. package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
  214. package/dist/editor/comments/ThreadCarousel.js +18 -21
  215. package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
  216. package/dist/editor/comments/ThreadReplyControls.js +92 -0
  217. package/dist/editor/comments/field-comment-context.d.ts +14 -0
  218. package/dist/editor/comments/field-comment-context.js +14 -0
  219. package/dist/editor/comments/form-comments.d.ts +48 -0
  220. package/dist/editor/comments/form-comments.js +178 -0
  221. package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
  222. package/dist/editor/comments/item-anchor-copy.js +6 -0
  223. package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
  224. package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
  225. package/dist/editor/comments/popover-placement.d.ts +18 -0
  226. package/dist/editor/comments/popover-placement.js +58 -0
  227. package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
  228. package/dist/editor/comments/use-tracked-writes.js +53 -0
  229. package/dist/editor/components/BranchAccessList.d.ts +15 -0
  230. package/dist/editor/components/BranchAccessList.js +52 -0
  231. package/dist/editor/components/BranchLockBanner.d.ts +22 -0
  232. package/dist/editor/components/BranchLockBanner.js +39 -0
  233. package/dist/editor/components/BranchPill.d.ts +32 -0
  234. package/dist/editor/components/BranchPill.js +33 -0
  235. package/dist/editor/components/BranchesDrawer.d.ts +11 -0
  236. package/dist/editor/components/BranchesDrawer.js +5 -0
  237. package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
  238. package/dist/editor/components/ConfirmDeleteModal.js +3 -2
  239. package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
  240. package/dist/editor/components/DestructiveMenuItem.js +8 -0
  241. package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
  242. package/dist/editor/components/EditorCrashScreen.js +22 -0
  243. package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
  244. package/dist/editor/components/EditorErrorBoundary.js +40 -0
  245. package/dist/editor/components/EditorHeader.d.ts +56 -106
  246. package/dist/editor/components/EditorHeader.js +130 -131
  247. package/dist/editor/components/EditorRail.d.ts +49 -0
  248. package/dist/editor/components/EditorRail.js +65 -0
  249. package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
  250. package/dist/editor/components/EntryBreadcrumb.js +56 -0
  251. package/dist/editor/components/EntryCreateModal.d.ts +12 -7
  252. package/dist/editor/components/EntryCreateModal.js +51 -57
  253. package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
  254. package/dist/editor/components/NoEditPermissionNotice.js +5 -4
  255. package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
  256. package/dist/editor/components/QuickOpenPalette.js +66 -0
  257. package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
  258. package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
  259. package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
  260. package/dist/editor/components/ReasonedMenuItem.js +15 -0
  261. package/dist/editor/components/ReferencedByList.d.ts +11 -0
  262. package/dist/editor/components/ReferencedByList.js +28 -0
  263. package/dist/editor/components/RelativeTime.d.ts +10 -0
  264. package/dist/editor/components/RelativeTime.js +10 -0
  265. package/dist/editor/components/RenameEntryModal.d.ts +9 -1
  266. package/dist/editor/components/RenameEntryModal.js +19 -31
  267. package/dist/editor/components/RetryToastMessage.d.ts +9 -0
  268. package/dist/editor/components/RetryToastMessage.js +6 -0
  269. package/dist/editor/components/SaveAllResult.d.ts +25 -0
  270. package/dist/editor/components/SaveAllResult.js +86 -0
  271. package/dist/editor/components/SaveSplitButton.d.ts +30 -0
  272. package/dist/editor/components/SaveSplitButton.js +108 -0
  273. package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
  274. package/dist/editor/components/StagedChangesDrawer.js +92 -0
  275. package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
  276. package/dist/editor/components/UnavailableEntryNotice.js +9 -0
  277. package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
  278. package/dist/editor/components/UnavailableTypeMessage.js +9 -0
  279. package/dist/editor/components/UndoToastMessage.d.ts +18 -0
  280. package/dist/editor/components/UndoToastMessage.js +10 -0
  281. package/dist/editor/components/UserBadge.d.ts +2 -5
  282. package/dist/editor/components/UserBadge.js +62 -33
  283. package/dist/editor/components/ValidationSummary.d.ts +14 -0
  284. package/dist/editor/components/ValidationSummary.js +24 -0
  285. package/dist/editor/components/index.d.ts +2 -2
  286. package/dist/editor/components/index.js +2 -2
  287. package/dist/editor/context/ApiClientContext.d.ts +8 -2
  288. package/dist/editor/context/ApiClientContext.js +19 -8
  289. package/dist/editor/context/AssetContext.d.ts +13 -35
  290. package/dist/editor/context/AssetContext.js +12 -31
  291. package/dist/editor/context/EditorStateContext.d.ts +4 -4
  292. package/dist/editor/context/EditorStateContext.js +4 -4
  293. package/dist/editor/context/SWRProvider.d.ts +3 -3
  294. package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
  295. package/dist/editor/context/SiteMdxAllowContext.js +7 -0
  296. package/dist/editor/context/index.d.ts +2 -1
  297. package/dist/editor/context/index.js +2 -1
  298. package/dist/editor/contrast.d.ts +19 -0
  299. package/dist/editor/contrast.js +41 -0
  300. package/dist/editor/copy.d.ts +18 -0
  301. package/dist/editor/copy.js +18 -0
  302. package/dist/editor/editor-config.js +16 -0
  303. package/dist/editor/editor-utils.d.ts +34 -8
  304. package/dist/editor/editor-utils.js +42 -20
  305. package/dist/editor/entry-search.d.ts +20 -0
  306. package/dist/editor/entry-search.js +34 -0
  307. package/dist/editor/field-breadcrumb.d.ts +12 -0
  308. package/dist/editor/field-breadcrumb.js +85 -0
  309. package/dist/editor/field-props.d.ts +86 -0
  310. package/dist/editor/field-props.js +27 -0
  311. package/dist/editor/field-target.d.ts +30 -0
  312. package/dist/editor/field-target.js +77 -0
  313. package/dist/editor/fields/BlockField.d.ts +12 -0
  314. package/dist/editor/fields/BlockField.js +89 -73
  315. package/dist/editor/fields/CodeField.d.ts +2 -0
  316. package/dist/editor/fields/CodeField.js +6 -2
  317. package/dist/editor/fields/DateTimeField.d.ts +4 -29
  318. package/dist/editor/fields/DateTimeField.js +79 -41
  319. package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
  320. package/dist/editor/fields/ExpandAllButton.js +4 -0
  321. package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
  322. package/dist/editor/fields/FieldCrashFallback.js +30 -0
  323. package/dist/editor/fields/FieldLabel.d.ts +37 -0
  324. package/dist/editor/fields/FieldLabel.js +19 -0
  325. package/dist/editor/fields/ImageField.d.ts +4 -0
  326. package/dist/editor/fields/ImageField.js +29 -14
  327. package/dist/editor/fields/InlineGroupField.js +4 -3
  328. package/dist/editor/fields/ItemList.d.ts +42 -0
  329. package/dist/editor/fields/ItemList.js +130 -0
  330. package/dist/editor/fields/MarkdownField.d.ts +32 -0
  331. package/dist/editor/fields/MarkdownField.js +223 -46
  332. package/dist/editor/fields/MdxImageDialog.js +1 -1
  333. package/dist/editor/fields/NumberField.d.ts +2 -0
  334. package/dist/editor/fields/NumberField.js +8 -5
  335. package/dist/editor/fields/NumberListField.d.ts +2 -0
  336. package/dist/editor/fields/NumberListField.js +19 -16
  337. package/dist/editor/fields/ObjectField.d.ts +2 -7
  338. package/dist/editor/fields/ObjectField.js +15 -5
  339. package/dist/editor/fields/ObjectListField.d.ts +29 -0
  340. package/dist/editor/fields/ObjectListField.js +57 -0
  341. package/dist/editor/fields/ReferenceField.d.ts +2 -0
  342. package/dist/editor/fields/ReferenceField.js +34 -9
  343. package/dist/editor/fields/SelectField.d.ts +2 -0
  344. package/dist/editor/fields/SelectField.js +11 -2
  345. package/dist/editor/fields/StringListField.d.ts +4 -1
  346. package/dist/editor/fields/StringListField.js +22 -8
  347. package/dist/editor/fields/TextField.d.ts +2 -0
  348. package/dist/editor/fields/TextField.js +6 -2
  349. package/dist/editor/fields/ToggleField.d.ts +2 -0
  350. package/dist/editor/fields/ToggleField.js +8 -3
  351. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
  352. package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
  353. package/dist/editor/fields/form-expansion.d.ts +9 -0
  354. package/dist/editor/fields/form-expansion.js +2 -0
  355. package/dist/editor/fields/item-expansion.d.ts +15 -0
  356. package/dist/editor/fields/item-expansion.js +60 -0
  357. package/dist/editor/fields/list-item-keys.d.ts +8 -0
  358. package/dist/editor/fields/list-item-keys.js +50 -0
  359. package/dist/editor/fields/list-item-title.d.ts +20 -0
  360. package/dist/editor/fields/list-item-title.js +85 -0
  361. package/dist/editor/fields/markdown-export-options.d.ts +2 -0
  362. package/dist/editor/fields/markdown-export-options.js +8 -0
  363. package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
  364. package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
  365. package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
  366. package/dist/editor/fields/mdx-jsx-support.js +157 -69
  367. package/dist/editor/fields/rich-text-failures.d.ts +5 -0
  368. package/dist/editor/fields/rich-text-failures.js +26 -0
  369. package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
  370. package/dist/editor/fields/toolbar-wrap.js +35 -0
  371. package/dist/editor/form-outline.d.ts +13 -0
  372. package/dist/editor/form-outline.js +70 -0
  373. package/dist/editor/group-manager/GroupCard.d.ts +4 -1
  374. package/dist/editor/group-manager/GroupCard.js +12 -3
  375. package/dist/editor/group-manager/GroupForm.js +1 -1
  376. package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
  377. package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
  378. package/dist/editor/group-manager/MemberList.d.ts +2 -1
  379. package/dist/editor/group-manager/MemberList.js +15 -4
  380. package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
  381. package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
  382. package/dist/editor/group-manager/index.js +34 -5
  383. package/dist/editor/group-manager/types.d.ts +5 -2
  384. package/dist/editor/hooks/create-branch-request.d.ts +20 -0
  385. package/dist/editor/hooks/create-branch-request.js +54 -0
  386. package/dist/editor/hooks/save-all.d.ts +68 -0
  387. package/dist/editor/hooks/save-all.js +61 -0
  388. package/dist/editor/hooks/useBranchActions.d.ts +11 -1
  389. package/dist/editor/hooks/useBranchActions.js +42 -19
  390. package/dist/editor/hooks/useBranchManager.d.ts +21 -0
  391. package/dist/editor/hooks/useBranchManager.js +321 -125
  392. package/dist/editor/hooks/useBranchesData.d.ts +8 -4
  393. package/dist/editor/hooks/useBranchesData.js +9 -5
  394. package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
  395. package/dist/editor/hooks/useCommentSystem.js +79 -55
  396. package/dist/editor/hooks/useCommentsData.d.ts +11 -7
  397. package/dist/editor/hooks/useCommentsData.js +20 -19
  398. package/dist/editor/hooks/useDraftManager.d.ts +77 -3
  399. package/dist/editor/hooks/useDraftManager.js +887 -94
  400. package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
  401. package/dist/editor/hooks/useEditorLayout.js +98 -20
  402. package/dist/editor/hooks/useEntriesData.d.ts +2 -1
  403. package/dist/editor/hooks/useEntriesData.js +18 -4
  404. package/dist/editor/hooks/useEntryManager.d.ts +41 -2
  405. package/dist/editor/hooks/useEntryManager.js +227 -41
  406. package/dist/editor/hooks/useGroupManager.js +13 -16
  407. package/dist/editor/hooks/usePermissionManager.js +14 -6
  408. package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
  409. package/dist/editor/hooks/usePreviewMarks.js +33 -0
  410. package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
  411. package/dist/editor/hooks/useReferenceResolution.js +34 -177
  412. package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
  413. package/dist/editor/hooks/useSchemaManager.js +97 -39
  414. package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
  415. package/dist/editor/hooks/useUserMetadata.js +76 -47
  416. package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
  417. package/dist/editor/hooks/user-metadata-batcher.js +33 -0
  418. package/dist/editor/media/AssetCard.d.ts +6 -7
  419. package/dist/editor/media/AssetCard.js +24 -31
  420. package/dist/editor/media/AssetListRow.d.ts +16 -0
  421. package/dist/editor/media/AssetListRow.js +41 -0
  422. package/dist/editor/media/CropStep.js +6 -1
  423. package/dist/editor/media/MediaLibrary.d.ts +4 -3
  424. package/dist/editor/media/MediaLibrary.js +11 -4
  425. package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
  426. package/dist/editor/media/MediaLibraryBody.js +195 -80
  427. package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
  428. package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
  429. package/dist/editor/media/crop-math.d.ts +3 -4
  430. package/dist/editor/media/crop-math.js +11 -22
  431. package/dist/editor/media/editor-image-src.d.ts +8 -0
  432. package/dist/editor/media/editor-image-src.js +10 -0
  433. package/dist/editor/media/format-bytes.d.ts +2 -0
  434. package/dist/editor/media/format-bytes.js +23 -0
  435. package/dist/editor/media/media-library-prefs.d.ts +23 -0
  436. package/dist/editor/media/media-library-prefs.js +49 -0
  437. package/dist/editor/media/media-library-view.d.ts +34 -0
  438. package/dist/editor/media/media-library-view.js +40 -0
  439. package/dist/editor/media/useAssetLibrary.d.ts +30 -0
  440. package/dist/editor/media/useAssetLibrary.js +126 -0
  441. package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
  442. package/dist/editor/media/useStableAssetOrder.js +37 -0
  443. package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
  444. package/dist/editor/media/useThumbnailFailure.js +16 -0
  445. package/dist/editor/permission-manager/GroupSelector.js +2 -2
  446. package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
  447. package/dist/editor/permission-manager/PermissionEditor.js +15 -4
  448. package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
  449. package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
  450. package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
  451. package/dist/editor/permission-manager/UserSelector.js +3 -3
  452. package/dist/editor/permission-manager/index.js +12 -3
  453. package/dist/editor/permission-manager/types.d.ts +5 -2
  454. package/dist/editor/platform.d.ts +3 -0
  455. package/dist/editor/platform.js +9 -0
  456. package/dist/editor/preview-asset-base.d.ts +9 -0
  457. package/dist/editor/preview-asset-base.js +17 -0
  458. package/dist/editor/preview-bridge.d.ts +51 -27
  459. package/dist/editor/preview-bridge.js +103 -144
  460. package/dist/editor/preview-marks.d.ts +15 -0
  461. package/dist/editor/preview-marks.js +74 -0
  462. package/dist/editor/preview-path.d.ts +12 -0
  463. package/dist/editor/preview-path.js +45 -1
  464. package/dist/editor/preview-scale.d.ts +27 -0
  465. package/dist/editor/preview-scale.js +34 -0
  466. package/dist/editor/raw-asset-base.d.ts +5 -0
  467. package/dist/editor/raw-asset-base.js +14 -0
  468. package/dist/editor/relative-time.d.ts +4 -4
  469. package/dist/editor/relative-time.js +16 -8
  470. package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
  471. package/dist/editor/schema-editor/CollectionEditor.js +361 -62
  472. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
  473. package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
  474. package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
  475. package/dist/editor/schema-editor/collection-draft.js +40 -0
  476. package/dist/editor/schema-editor/index.d.ts +1 -1
  477. package/dist/editor/schema-label.d.ts +10 -0
  478. package/dist/editor/schema-label.js +17 -0
  479. package/dist/editor/settings-conflict.d.ts +5 -0
  480. package/dist/editor/settings-conflict.js +8 -0
  481. package/dist/editor/shell/ActivityRail.d.ts +37 -0
  482. package/dist/editor/shell/ActivityRail.js +91 -0
  483. package/dist/editor/shell/EditorShell.d.ts +17 -0
  484. package/dist/editor/shell/EditorShell.js +31 -0
  485. package/dist/editor/shell/PaneLayout.d.ts +28 -0
  486. package/dist/editor/shell/PaneLayout.js +116 -0
  487. package/dist/editor/shell/SidePanelHost.d.ts +35 -0
  488. package/dist/editor/shell/SidePanelHost.js +184 -0
  489. package/dist/editor/shell/TopBar.d.ts +12 -0
  490. package/dist/editor/shell/TopBar.js +14 -0
  491. package/dist/editor/shell/host-chrome.d.ts +16 -0
  492. package/dist/editor/shell/host-chrome.js +69 -0
  493. package/dist/editor/slug.d.ts +16 -0
  494. package/dist/editor/slug.js +43 -0
  495. package/dist/editor/theme.d.ts +2 -1
  496. package/dist/editor/theme.js +314 -13
  497. package/dist/editor/unanswered.d.ts +17 -0
  498. package/dist/editor/unanswered.js +26 -0
  499. package/dist/editor/unavailable-entry-type.d.ts +20 -0
  500. package/dist/editor/unavailable-entry-type.js +28 -0
  501. package/dist/editor/undo-removal.d.ts +57 -0
  502. package/dist/editor/undo-removal.js +163 -0
  503. package/dist/editor/user-display.d.ts +4 -0
  504. package/dist/editor/user-display.js +5 -0
  505. package/dist/editor/utils/confirm-modal.d.ts +8 -0
  506. package/dist/editor/utils/confirm-modal.js +12 -0
  507. package/dist/editor/utils/editor-errors.d.ts +19 -0
  508. package/dist/editor/utils/editor-errors.js +32 -0
  509. package/dist/editor/utils/focus-return.d.ts +56 -0
  510. package/dist/editor/utils/focus-return.js +106 -0
  511. package/dist/entry-link-resolver.d.ts +11 -1
  512. package/dist/entry-link-resolver.js +65 -5
  513. package/dist/entry-schema-registry.d.ts +3 -3
  514. package/dist/entry-schema-registry.js +7 -4
  515. package/dist/entry-schema.d.ts +49 -3
  516. package/dist/entry-schema.js +18 -0
  517. package/dist/git-manager.d.ts +172 -10
  518. package/dist/git-manager.js +449 -107
  519. package/dist/github-service.d.ts +39 -2
  520. package/dist/github-service.js +101 -7
  521. package/dist/http/handler.js +74 -9
  522. package/dist/http/types.d.ts +2 -0
  523. package/dist/http/worker-not-ready.d.ts +9 -4
  524. package/dist/http/worker-not-ready.js +59 -6
  525. package/dist/index.d.ts +2 -0
  526. package/dist/index.js +3 -0
  527. package/dist/item-keys.d.ts +46 -0
  528. package/dist/item-keys.js +235 -0
  529. package/dist/operating-mode/editor-mode-check.d.ts +15 -0
  530. package/dist/operating-mode/editor-mode-check.js +24 -0
  531. package/dist/operating-mode/mode-env.d.ts +13 -14
  532. package/dist/operating-mode/mode-env.js +13 -14
  533. package/dist/operating-mode/types.d.ts +2 -2
  534. package/dist/paths/branch.d.ts +0 -1
  535. package/dist/paths/branch.js +1 -8
  536. package/dist/paths/index.d.ts +1 -1
  537. package/dist/paths/index.js +1 -1
  538. package/dist/paths/validation.js +0 -2
  539. package/dist/preview.d.ts +8 -0
  540. package/dist/preview.js +7 -0
  541. package/dist/reference-resolver.js +1 -0
  542. package/dist/resolve-canopy-user.d.ts +1 -1
  543. package/dist/resolve-canopy-user.js +1 -1
  544. package/dist/schema/meta-loader.d.ts +18 -8
  545. package/dist/schema/meta-loader.js +42 -9
  546. package/dist/schema/registry-fingerprint.d.ts +14 -0
  547. package/dist/schema/registry-fingerprint.js +63 -0
  548. package/dist/schema/resolver.d.ts +7 -4
  549. package/dist/schema/resolver.js +7 -6
  550. package/dist/schema/schema-store.d.ts +7 -10
  551. package/dist/schema/schema-store.js +13 -11
  552. package/dist/schema/schema-unavailable-error.d.ts +11 -0
  553. package/dist/schema/schema-unavailable-error.js +15 -0
  554. package/dist/schema/types.d.ts +22 -0
  555. package/dist/schema-registry-record.d.ts +35 -0
  556. package/dist/schema-registry-record.js +134 -0
  557. package/dist/server.d.ts +79 -9
  558. package/dist/server.js +62 -8
  559. package/dist/services.d.ts +33 -5
  560. package/dist/services.js +155 -37
  561. package/dist/settings-workspace.d.ts +23 -3
  562. package/dist/settings-workspace.js +159 -45
  563. package/dist/stamp-on-publish.d.ts +36 -0
  564. package/dist/stamp-on-publish.js +71 -0
  565. package/dist/static/index.d.ts +58 -5
  566. package/dist/static/index.js +133 -3
  567. package/dist/static/seo.d.ts +5 -5
  568. package/dist/static/seo.js +5 -5
  569. package/dist/submission-attribution.d.ts +8 -0
  570. package/dist/submission-attribution.js +22 -0
  571. package/dist/system-users.d.ts +12 -0
  572. package/dist/system-users.js +12 -0
  573. package/dist/task-queue/cms-task-queue.d.ts +1 -1
  574. package/dist/task-queue/cms-task-queue.js +1 -1
  575. package/dist/task-queue/index.d.ts +1 -1
  576. package/dist/task-queue/index.js +1 -1
  577. package/dist/task-queue/task-queue.d.ts +6 -0
  578. package/dist/task-queue/task-queue.js +29 -0
  579. package/dist/task-queue/worker-status.d.ts +35 -9
  580. package/dist/task-queue/worker-status.js +84 -17
  581. package/dist/types.d.ts +90 -9
  582. package/dist/url-collision.js +3 -3
  583. package/dist/url-exclusivity-fixtures.d.ts +8 -1
  584. package/dist/url-exclusivity-fixtures.js +11 -1
  585. package/dist/user.js +2 -1
  586. package/dist/utils/atomic-write.js +2 -1
  587. package/dist/utils/base-branch.d.ts +13 -0
  588. package/dist/utils/base-branch.js +23 -0
  589. package/dist/utils/content-serialize.d.ts +15 -7
  590. package/dist/utils/content-serialize.js +353 -51
  591. package/dist/utils/content-write-lock.d.ts +6 -1
  592. package/dist/utils/content-write-lock.js +21 -6
  593. package/dist/utils/debug.d.ts +1 -1
  594. package/dist/utils/debug.js +5 -3
  595. package/dist/utils/error.js +13 -2
  596. package/dist/utils/escape-text.d.ts +7 -0
  597. package/dist/utils/escape-text.js +27 -0
  598. package/dist/utils/fs.d.ts +12 -4
  599. package/dist/utils/fs.js +18 -5
  600. package/dist/utils/git.d.ts +21 -1
  601. package/dist/utils/git.js +63 -8
  602. package/dist/utils/json-source-splice.d.ts +14 -0
  603. package/dist/utils/json-source-splice.js +120 -0
  604. package/dist/utils/markdown-body-splice.d.ts +39 -0
  605. package/dist/utils/markdown-body-splice.js +421 -0
  606. package/dist/utils/occ-json-write.js +18 -12
  607. package/dist/utils/provision-log.d.ts +25 -0
  608. package/dist/utils/provision-log.js +49 -0
  609. package/dist/utils/provisioning-lock.d.ts +32 -1
  610. package/dist/utils/provisioning-lock.js +78 -32
  611. package/dist/utils/sanitize-href.d.ts +9 -23
  612. package/dist/utils/sanitize-href.js +14 -28
  613. package/dist/utils/title-field.d.ts +10 -0
  614. package/dist/utils/title-field.js +47 -0
  615. package/dist/utils/yaml-source-splice.d.ts +58 -0
  616. package/dist/utils/yaml-source-splice.js +515 -0
  617. package/dist/validation/block-structural-keys.d.ts +1 -1
  618. package/dist/validation/block-structural-keys.js +1 -1
  619. package/dist/validation/deletion-checker.d.ts +21 -29
  620. package/dist/validation/deletion-checker.js +41 -117
  621. package/dist/validation/entry-validator.d.ts +6 -10
  622. package/dist/validation/entry-validator.js +19 -26
  623. package/dist/validation/field-traversal.d.ts +22 -0
  624. package/dist/validation/field-traversal.js +39 -8
  625. package/dist/validation/markdown-safety.d.ts +68 -0
  626. package/dist/validation/markdown-safety.js +596 -0
  627. package/dist/validation/mdx-allowlist.d.ts +55 -0
  628. package/dist/validation/mdx-allowlist.js +183 -0
  629. package/dist/validation/reference-validator.d.ts +2 -0
  630. package/dist/validation/reference-validator.js +3 -0
  631. package/dist/version.d.ts +1 -1
  632. package/dist/version.js +1 -1
  633. package/dist/worker/branch-policy.d.ts +124 -0
  634. package/dist/worker/branch-policy.js +243 -0
  635. package/dist/worker/bundle-header.d.ts +117 -0
  636. package/dist/worker/bundle-header.js +253 -0
  637. package/dist/worker/cms-worker.d.ts +236 -142
  638. package/dist/worker/cms-worker.js +772 -285
  639. package/dist/worker/gateway-egress.d.ts +43 -0
  640. package/dist/worker/gateway-egress.js +209 -0
  641. package/dist/worker/gateway-instance.d.ts +42 -0
  642. package/dist/worker/gateway-instance.js +129 -0
  643. package/dist/worker/git-process.d.ts +81 -0
  644. package/dist/worker/git-process.js +234 -0
  645. package/dist/worker/git-sync.d.ts +34 -17
  646. package/dist/worker/git-sync.js +394 -131
  647. package/dist/worker/github-auth.d.ts +9 -9
  648. package/dist/worker/github-auth.js +13 -15
  649. package/dist/worker/github-gateway-http.d.ts +62 -0
  650. package/dist/worker/github-gateway-http.js +977 -0
  651. package/dist/worker/github-gateway-wire.d.ts +590 -0
  652. package/dist/worker/github-gateway-wire.js +488 -0
  653. package/dist/worker/github-gateway.d.ts +238 -0
  654. package/dist/worker/github-gateway.js +726 -0
  655. package/dist/worker/github-mirror-upkeep.d.ts +75 -0
  656. package/dist/worker/github-mirror-upkeep.js +266 -0
  657. package/dist/worker/github-mirror.d.ts +364 -0
  658. package/dist/worker/github-mirror.js +1030 -0
  659. package/dist/worker/github-transfer.d.ts +56 -0
  660. package/dist/worker/github-transfer.js +444 -0
  661. package/dist/worker/history-rewrite.d.ts +4 -5
  662. package/dist/worker/history-rewrite.js +12 -17
  663. package/dist/worker/provisioned-workspace.d.ts +5 -5
  664. package/dist/worker/provisioned-workspace.js +5 -5
  665. package/dist/worker/rebase.d.ts +1 -1
  666. package/dist/worker/rebase.js +58 -54
  667. package/dist/worker/remote-git-maintenance.d.ts +3 -0
  668. package/dist/worker/remote-git-maintenance.js +12 -0
  669. package/dist/worker/schema-gate.d.ts +49 -0
  670. package/dist/worker/schema-gate.js +226 -0
  671. package/dist/worker/self-checks.d.ts +107 -0
  672. package/dist/worker/self-checks.js +358 -0
  673. package/dist/worker/shared-repo-git.d.ts +96 -0
  674. package/dist/worker/shared-repo-git.js +459 -0
  675. package/dist/worker/sparse-cone.d.ts +20 -0
  676. package/dist/worker/sparse-cone.js +136 -0
  677. package/dist/worker/stale-mirror.d.ts +82 -0
  678. package/dist/worker/stale-mirror.js +130 -0
  679. package/dist/worker/task-runner.d.ts +5 -3
  680. package/dist/worker/task-runner.js +287 -186
  681. package/dist/worker/worker-context.d.ts +36 -37
  682. package/package.json +35 -7
  683. package/dist/editor/EditorPanes.d.ts +0 -10
  684. package/dist/editor/EditorPanes.js +0 -98
  685. package/dist/editor/components/EditorFooter.d.ts +0 -11
  686. package/dist/editor/components/EditorFooter.js +0 -9
  687. package/dist/editor/components/EditorSidebar.d.ts +0 -67
  688. package/dist/editor/components/EditorSidebar.js +0 -22
@@ -4,6 +4,8 @@
4
4
  */
5
5
  import { loadOrCreateBranchContext } from '../branch-workspace.js';
6
6
  import { readsFromCheckout } from '../build-mode.js';
7
+ import { GitManager } from '../git-manager.js';
8
+ import { baseBranchOf } from '../utils/base-branch.js';
7
9
  import { detectHeadBranch } from '../utils/git.js';
8
10
  /**
9
11
  * Resolve the branch root directory for reading content.
@@ -15,6 +17,11 @@ export async function resolveBranchRoot(config) {
15
17
  if (readsFromCheckout(config)) {
16
18
  return process.cwd();
17
19
  }
20
+ // Prod reads an unset base branch from the remote's HEAD, as services does; provisioning
21
+ // needs it even when the active branch is configured.
22
+ const resolved = config.mode === 'prod' && !config.defaultBaseBranch
23
+ ? { ...config, defaultBaseBranch: await GitManager.detectBaseBranch(config, 'throw') }
24
+ : config;
18
25
  let activeBranch;
19
26
  if (config.defaultActiveBranch) {
20
27
  activeBranch = config.defaultActiveBranch;
@@ -23,10 +30,10 @@ export async function resolveBranchRoot(config) {
23
30
  activeBranch = await detectHeadBranch(process.cwd(), config.defaultBaseBranch ?? 'main');
24
31
  }
25
32
  else {
26
- activeBranch = config.defaultBaseBranch ?? 'main';
33
+ activeBranch = baseBranchOf(resolved);
27
34
  }
28
35
  const context = await loadOrCreateBranchContext({
29
- config,
36
+ config: resolved,
30
37
  branchName: activeBranch,
31
38
  mode: config.mode,
32
39
  createdBy: 'canopycms-ai',
@@ -10,22 +10,31 @@
10
10
  * their children's text**: deleting a `<Callout>...</Callout>` wholesale
11
11
  * would silently drop every word inside it from the search index.
12
12
  *
13
+ * The input is an entry body, with its front matter already split off, as
14
+ * the content store returns it. There is no front-matter step: a body may
15
+ * open with a `---` thematic break, which a front-matter parser would read as
16
+ * the start of a block and swallow the prose after it.
17
+ *
13
18
  * Pipeline (each step operates on the previous step's output):
14
- * 1. Strip YAML frontmatter (via `gray-matter`, the same parser
15
- * `content-store.ts` uses for `.md`/`.mdx` bodies).
16
- * 2. Strip `import`/`export` statements (via `stripMdxImports`), which also
19
+ * 1. Strip `import`/`export` statements (via `stripMdxImports`), which also
17
20
  * protects fenced code blocks from every later step.
18
- * 3. Mask fenced code blocks and inline code spans, capturing their content.
21
+ * 2. Mask fenced code blocks and inline code spans, capturing their content.
22
+ * 3. Strip HTML/MDX comments (see `stripHtmlComments` below).
19
23
  * 4. Strip JSX/HTML tags via a single global replace (see `TAG_RE` below).
20
24
  * 5. Strip JSX expressions (`{...}`, including nested braces) — these are
21
25
  * code, not prose.
22
26
  * 6. Strip common Markdown syntax (see `stripMarkdownSyntax` below).
23
- * 7. Restore the masked code from step 3 as plain text.
27
+ * 7. Restore the masked code from step 2 as plain text.
24
28
  * 8. Collapse whitespace: trim each line, collapse runs of blank lines,
25
29
  * trim the result. Paragraph breaks (single blank lines) are preserved.
26
30
  */
27
31
  /**
28
- * Convert MDX/Markdown body content to plain prose text.
32
+ * Convert an MDX/Markdown entry body to plain prose text.
33
+ *
34
+ * Pass the body only: the value of the entry's body field, such as
35
+ * `entry.data.body` when the schema names that field `body`. Front matter
36
+ * in the input is treated as prose, so a caller holding a whole file splits
37
+ * it first, for example with `matter(file, {}).content`.
29
38
  *
30
39
  * See the module doc above for the full pipeline and why this exists as a
31
40
  * distinct transform from `stripMdxImports`.
@@ -37,6 +46,6 @@
37
46
  * Output preserves paragraph breaks (blank lines) but is not further
38
47
  * chunked, weighted, or field-selected — composing that into a search
39
48
  * document is left to the caller, since that logic is where adopter search
40
- * indexes genuinely diverge (see docs/adopter-migration.md).
49
+ * indexes genuinely diverge (see CHANGELOG.md).
41
50
  */
42
- export declare function toPlainText(markdown: string): string;
51
+ export declare function toPlainText(body: string): string;
@@ -10,21 +10,24 @@
10
10
  * their children's text**: deleting a `<Callout>...</Callout>` wholesale
11
11
  * would silently drop every word inside it from the search index.
12
12
  *
13
+ * The input is an entry body, with its front matter already split off, as
14
+ * the content store returns it. There is no front-matter step: a body may
15
+ * open with a `---` thematic break, which a front-matter parser would read as
16
+ * the start of a block and swallow the prose after it.
17
+ *
13
18
  * Pipeline (each step operates on the previous step's output):
14
- * 1. Strip YAML frontmatter (via `gray-matter`, the same parser
15
- * `content-store.ts` uses for `.md`/`.mdx` bodies).
16
- * 2. Strip `import`/`export` statements (via `stripMdxImports`), which also
19
+ * 1. Strip `import`/`export` statements (via `stripMdxImports`), which also
17
20
  * protects fenced code blocks from every later step.
18
- * 3. Mask fenced code blocks and inline code spans, capturing their content.
21
+ * 2. Mask fenced code blocks and inline code spans, capturing their content.
22
+ * 3. Strip HTML/MDX comments (see `stripHtmlComments` below).
19
23
  * 4. Strip JSX/HTML tags via a single global replace (see `TAG_RE` below).
20
24
  * 5. Strip JSX expressions (`{...}`, including nested braces) — these are
21
25
  * code, not prose.
22
26
  * 6. Strip common Markdown syntax (see `stripMarkdownSyntax` below).
23
- * 7. Restore the masked code from step 3 as plain text.
27
+ * 7. Restore the masked code from step 2 as plain text.
24
28
  * 8. Collapse whitespace: trim each line, collapse runs of blank lines,
25
29
  * trim the result. Paragraph breaks (single blank lines) are preserved.
26
30
  */
27
- import matter from 'gray-matter';
28
31
  import { stripMdxImports } from './strip-mdx.js';
29
32
  /**
30
33
  * Masking markers use `@` right after `<` (and before the closing `>`),
@@ -254,7 +257,12 @@ function collapseWhitespace(text) {
254
257
  .trim();
255
258
  }
256
259
  /**
257
- * Convert MDX/Markdown body content to plain prose text.
260
+ * Convert an MDX/Markdown entry body to plain prose text.
261
+ *
262
+ * Pass the body only: the value of the entry's body field, such as
263
+ * `entry.data.body` when the schema names that field `body`. Front matter
264
+ * in the input is treated as prose, so a caller holding a whole file splits
265
+ * it first, for example with `matter(file, {}).content`.
258
266
  *
259
267
  * See the module doc above for the full pipeline and why this exists as a
260
268
  * distinct transform from `stripMdxImports`.
@@ -266,15 +274,10 @@ function collapseWhitespace(text) {
266
274
  * Output preserves paragraph breaks (blank lines) but is not further
267
275
  * chunked, weighted, or field-selected — composing that into a search
268
276
  * document is left to the caller, since that logic is where adopter search
269
- * indexes genuinely diverge (see docs/adopter-migration.md).
277
+ * indexes genuinely diverge (see CHANGELOG.md).
270
278
  */
271
- export function toPlainText(markdown) {
272
- // Destructures `content` only: never touches `.data` (so the shared-instance
273
- // hazard cannot apply) and never needs `.matter` (so the cache-hit hazard
274
- // cannot apply either).
275
- // eslint-disable-next-line no-restricted-syntax
276
- const { content } = matter(markdown);
277
- const withoutImports = stripMdxImports(content);
279
+ export function toPlainText(body) {
280
+ const withoutImports = stripMdxImports(body);
278
281
  const { masked, restore } = maskCode(withoutImports);
279
282
  let result = masked;
280
283
  result = stripHtmlComments(result);
@@ -5,6 +5,33 @@
5
5
  * from CanopyCMS content, and the output manifest/metadata structures.
6
6
  */
7
7
  import type { FieldConfig } from '../config/index.js';
8
+ import type { MissingReference, ResolvedReferenceMeta } from '../entry-schema.js';
9
+ import type { SeoFieldLocation } from '../static/seo.js';
10
+ /** A reference whose target this export shows: the target's own data plus where it lives. */
11
+ export type AIResolvedReference = Record<string, unknown> & ResolvedReferenceMeta & {
12
+ unavailable?: undefined;
13
+ };
14
+ /**
15
+ * A reference whose target exists but is not in this export (left out by `exclude`, or its own
16
+ * markdown failed to render). Carries the id and nothing of the target, so no title of it can
17
+ * reach the output.
18
+ */
19
+ export type AIExcludedReference = {
20
+ id: string;
21
+ unavailable: true;
22
+ reason: 'excluded';
23
+ };
24
+ /**
25
+ * A reference whose target this export does not show: a `MissingReference` when the id names no
26
+ * readable entry, an {@link AIExcludedReference} when the export leaves the target out.
27
+ */
28
+ export type AIUnavailableReference = MissingReference | AIExcludedReference;
29
+ /**
30
+ * What a `reference` field holds in {@link AIEntryMeta.data} (an array of these for
31
+ * `list: true`), at any depth, in place of the stored id; a cleared reference stays `''`. Branch
32
+ * on `unavailable` before reading anything but `id`.
33
+ */
34
+ export type AIReferenceValue = AIResolvedReference | AIUnavailableReference;
8
35
  /**
9
36
  * Metadata about an entry, provided to filter/predicate functions.
10
37
  * Does not include the full data payload — use `where` predicates for
@@ -17,7 +44,11 @@ export interface AIEntryMeta {
17
44
  collectionName: string;
18
45
  entryType: string;
19
46
  format: string;
20
- /** The entry's parsed data (frontmatter for MD/MDX, full data for JSON) */
47
+ /**
48
+ * The entry's parsed data (frontmatter for MD/MDX, full data for JSON), with every `reference`
49
+ * field holding an {@link AIReferenceValue} rather than the stored id. `exclude.where` sees a
50
+ * target the export leaves out in full; everything after it sees that target as unavailable.
51
+ */
21
52
  data: Record<string, unknown>;
22
53
  }
23
54
  /**
@@ -30,6 +61,12 @@ export interface ExcludeConfig {
30
61
  entryTypes?: string[];
31
62
  /** Custom predicate — return true to exclude the entry */
32
63
  where?: (entry: AIEntryMeta) => boolean;
64
+ /**
65
+ * Leave out entries marked `noindex`, read through `isNoindexEntry` at
66
+ * {@link AIContentConfig.seo}, the predicate the sitemap and robots metadata use. Default
67
+ * `true`; `false` exports them.
68
+ */
69
+ noindex?: boolean;
33
70
  }
34
71
  /**
35
72
  * Filter criteria for bundles. Filters are AND'd when combined.
@@ -57,7 +94,8 @@ export interface BundleConfig {
57
94
  }
58
95
  /**
59
96
  * Per-field markdown override function.
60
- * Return a markdown string to replace the default conversion for this field.
97
+ * Return a markdown string to replace the default conversion for this field. A `reference`
98
+ * field's value is an {@link AIReferenceValue}, or an array of them.
61
99
  */
62
100
  export type FieldTransformFn = (value: unknown, fieldConfig: FieldConfig) => string;
63
101
  /**
@@ -143,7 +181,8 @@ export interface EntryTransformContext {
143
181
  readSibling: (name: string) => Promise<string | null>;
144
182
  }
145
183
  /**
146
- * Per-entry-type transform. Runs once per entry at generation time (may be async). Return a
184
+ * Per-entry-type transform. Runs once per entry at generation time (may be async), and again if
185
+ * an entry it references fails to render and is masked out of its data. Return a
147
186
  * markdown string to APPEND after the entry's body/fields, or `undefined` to append nothing.
148
187
  * Append-only by design — `entryToMarkdown` remains the sole owner of base serialization.
149
188
  *
@@ -166,12 +205,52 @@ export type EntryTransformFn = (entry: AIEntry, ctx: EntryTransformContext) => P
166
205
  * Entry transform overrides, keyed by entry type name.
167
206
  */
168
207
  export type EntryTransforms = Record<string, EntryTransformFn>;
208
+ /** What {@link AIReferenceLinkFn} knows about a target beyond its data. */
209
+ export interface AIReferenceLinkContext {
210
+ /**
211
+ * The target's MD/MDX body as stored, `undefined` for a data-only entry. It only informs this
212
+ * decision: none of it reaches the entries that link to the target.
213
+ */
214
+ body: string | undefined;
215
+ /**
216
+ * The URL the export links by default: `entryLinkUrl`'s result when the site sets one, else
217
+ * the target's `urlPath`; `undefined` when neither gives one.
218
+ */
219
+ defaultUrl: string | undefined;
220
+ }
221
+ /**
222
+ * Where a link to an exported entry points, for every reference to it and every body `entry:`
223
+ * link to it. Return a URL to link there instead of `context.defaultUrl`, `false` when the target
224
+ * has no page (the title renders as plain text, with no page or markdown-version link), or
225
+ * `undefined` to keep the default. Called once per target per run, never for a missing target or
226
+ * one the exclusions leave out; a throw or any other return is logged and treated as `false`.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * // A person has a page only when their bio (the body) has prose
231
+ * referenceLink: (target, { body }) =>
232
+ * target.collection === 'content/people' && !body?.trim() ? false : undefined
233
+ * ```
234
+ */
235
+ export type AIReferenceLinkFn = (target: AIResolvedReference, context: AIReferenceLinkContext) => Promise<string | false | undefined> | string | false | undefined;
169
236
  /**
170
237
  * Main AI content configuration. Shared by route handler and build utility.
171
238
  */
172
239
  export interface AIContentConfig {
240
+ /**
241
+ * Site-relative URL path the generated files are served under, without the deployment
242
+ * `basePath`, as page links are. A reference links its target's markdown copy beneath it.
243
+ * Default `/ai`: where `canopycms init` mounts the route, and where `generate-ai-content`'s
244
+ * default `--output public/ai` is served. Set it when you serve the files elsewhere.
245
+ */
246
+ mountPath?: string;
173
247
  /** Opt-out exclusions — content to skip */
174
248
  exclude?: ExcludeConfig;
249
+ /**
250
+ * Where entries keep their SEO fields, when not the flat defaults. Drives the `noindex` read,
251
+ * so pass the same object as `createNextCanopyContext({ seo })`, or the two can disagree.
252
+ */
253
+ seo?: SeoFieldLocation;
175
254
  /** Custom bundles — filtered content subsets */
176
255
  bundles?: BundleConfig[];
177
256
  /** Per-entry-type, per-field markdown overrides */
@@ -182,6 +261,8 @@ export interface AIContentConfig {
182
261
  bodyTransforms?: BodyTransforms;
183
262
  /** Per-entry-type transforms that append markdown (e.g. folding in a colocated sibling artifact) */
184
263
  entryTransforms?: EntryTransforms;
264
+ /** Override or suppress the page link of a referenced or `entry:`-linked target */
265
+ referenceLink?: AIReferenceLinkFn;
185
266
  }
186
267
  /**
187
268
  * Identity function for type-checking AI content config.
@@ -13,9 +13,26 @@ import { z } from 'zod';
13
13
  import type { BranchAccessControl, BranchMetadata, BranchStatus } from '../types.js';
14
14
  import { type BranchHealthEntry } from '../branch-health.js';
15
15
  import type { ApiResponse } from './types.js';
16
+ /**
17
+ * Wall-clock budget the opt-in duplicate-ID scan shares across every healthy
18
+ * branch: well inside the CMS Lambda's default 60 s timeout
19
+ * (`DEFAULT_CMS_LAMBDA_TIMEOUT` in canopycms-cdk), leaving the rest of the
20
+ * request its headroom.
21
+ * @internal Exported for tests.
22
+ */
23
+ export declare const DUPLICATE_ID_SCAN_BUDGET_MS = 20000;
16
24
  export interface BranchHealthData {
17
25
  entries: BranchHealthEntry[];
18
26
  generatedAt: string;
27
+ /**
28
+ * Present only when the request asked for the duplicate-ID scan. `truncated`
29
+ * is true when the budget ran out before every healthy branch was scanned;
30
+ * those branches report `duplicateIdScan.state === 'unknown'`.
31
+ */
32
+ duplicateIdScan?: {
33
+ budgetMs: number;
34
+ truncated: boolean;
35
+ };
19
36
  }
20
37
  /** Response type for GET /admin/branch-health */
21
38
  export type BranchHealthResponse = ApiResponse<BranchHealthData>;
@@ -65,7 +82,13 @@ export type RepairContentDuplicatesResponse = ApiResponse<RepairContentDuplicate
65
82
  * router/generate-client import.
66
83
  */
67
84
  export declare const ADMIN_BRANCH_HEALTH_ROUTES: {
68
- readonly branchHealth: import("./route-builder.js").RouteDefinition<undefined, undefined, BranchHealthResponse>;
85
+ readonly branchHealth: import("./route-builder.js").RouteDefinition<z.ZodObject<{
86
+ duplicates: z.ZodOptional<z.ZodLiteral<"1">>;
87
+ }, "strip", z.ZodTypeAny, {
88
+ duplicates?: "1" | undefined;
89
+ }, {
90
+ duplicates?: "1" | undefined;
91
+ }>, undefined, BranchHealthResponse>;
69
92
  readonly purgeBranchDir: import("./route-builder.js").RouteDefinition<z.ZodObject<{
70
93
  dirName: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
71
94
  }, "strip", z.ZodTypeAny, {
@@ -17,7 +17,8 @@ import { BranchMetadataFileManager, getBranchMetadataFileManager } from '../bran
17
17
  // Same constants the reader uses, rather than a second copy of the two string
18
18
  // literals.
19
19
  import { BRANCH_META_DIR, BRANCH_META_FILE } from '../branch-metadata-file.js';
20
- import { scanBranchHealth } from '../branch-health.js';
20
+ import { ORPHAN_YOUTH_THRESHOLD_MS, scanBranchHealth, } from '../branch-health.js';
21
+ import { formatDirStamp } from '../branch-provisioning.js';
21
22
  import { ContentIdIndex } from '../content-id-index.js';
22
23
  import { invalidateContentIndexesDurable } from '../content-index-generation.js';
23
24
  import { getDefaultBranchBase, sanitizeBranchName } from '../paths/index.js';
@@ -26,10 +27,17 @@ import { branchProvisioningLockName, tryAcquireProvisioningLock } from '../utils
26
27
  import { withContentWriteLock, ContentWriteLockBusyError, DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, } from '../utils/content-write-lock.js';
27
28
  import { getErrorMessage, isNodeError, isNotFoundError } from '../utils/error.js';
28
29
  import { defineEndpoint } from './route-builder.js';
30
+ import { baseBranchOf } from '../utils/base-branch.js';
29
31
  /** [H1] A fresh (< 5 min old) init lock blocks purge -- provisioning may be running. */
30
32
  const PROVISIONING_LOCK_FRESH_MS = 5 * 60_000;
31
- /** An orphan dir younger than this may still be a clone in progress; corrupt dirs are exempt. */
32
- const ORPHAN_YOUTH_THRESHOLD_MS = 15 * 60_000;
33
+ /**
34
+ * Wall-clock budget the opt-in duplicate-ID scan shares across every healthy
35
+ * branch: well inside the CMS Lambda's default 60 s timeout
36
+ * (`DEFAULT_CMS_LAMBDA_TIMEOUT` in canopycms-cdk), leaving the rest of the
37
+ * request its headroom.
38
+ * @internal Exported for tests.
39
+ */
40
+ export const DUPLICATE_ID_SCAN_BUDGET_MS = 20_000;
33
41
  // Mirrors deleteTaskHandler's fileName pattern in admin.ts: conservative
34
42
  // charset plus explicit traversal/dot-prefix refinements (the regex alone
35
43
  // technically excludes '/' already, but the refinements keep intent explicit
@@ -40,13 +48,11 @@ const dirNameSchema = z
40
48
  .refine((v) => !v.includes('..'), { message: 'dirName must not contain ..' })
41
49
  .refine((v) => !v.startsWith('.'), { message: 'dirName must not be dot-prefixed' });
42
50
  const branchDirParamsSchema = z.object({ dirName: dirNameSchema });
43
- /** Compact UTC stamp for trash/archive names: `YYYYMMDDTHHMMSSZ` (no colons -- portability). */
44
- function formatTrashStamp(date) {
45
- return date
46
- .toISOString()
47
- .replace(/[-:]/g, '')
48
- .replace(/\.\d{3}Z$/, 'Z');
49
- }
51
+ /**
52
+ * `duplicates=1` opts in to the duplicate-ID scan, a full content-tree readdir
53
+ * per healthy branch. The panel's 30 s poll leaves it off.
54
+ */
55
+ const branchHealthParamsSchema = z.object({ duplicates: z.literal('1').optional() });
50
56
  /**
51
57
  * Re-resolve dirName under baseRoot and enforce containment (belt-and-
52
58
  * suspenders on top of the zod regex, matching deleteTaskHandler's pattern
@@ -68,19 +74,31 @@ class RepairPreconditionError extends Error {
68
74
  this.status = status;
69
75
  }
70
76
  }
71
- const getBranchHealthHandler = async (_gc, ctx, _req) => {
77
+ const getBranchHealthHandler = async (_gc, ctx, _req, params) => {
72
78
  // Same derivation services.ts uses to construct the BranchRegistry --
73
79
  // admin handlers must agree with it or the scan silently looks at the
74
80
  // wrong directory.
75
81
  const baseRoot = getDefaultBranchBase(ctx.services.config.mode);
76
- const baseBranchName = ctx.services.config.defaultBaseBranch ?? 'main';
82
+ const baseBranchName = baseBranchOf(ctx.services.config);
77
83
  const contentRootName = ctx.services.config.contentRoot || 'content';
84
+ const scanDuplicates = params.duplicates === '1';
78
85
  try {
79
- const entries = await scanBranchHealth(baseRoot, { baseBranchName, contentRootName });
86
+ const entries = await scanBranchHealth(baseRoot, {
87
+ baseBranchName,
88
+ contentRootName,
89
+ ...(scanDuplicates ? { duplicateIdScan: { budgetMs: DUPLICATE_ID_SCAN_BUDGET_MS } } : {}),
90
+ });
91
+ const truncated = entries.some((e) => e.duplicateIdScan?.state === 'unknown' && e.duplicateIdScan.reason === 'out-of-time');
80
92
  return {
81
93
  ok: true,
82
94
  status: 200,
83
- data: { entries, generatedAt: new Date().toISOString() },
95
+ data: {
96
+ entries,
97
+ generatedAt: new Date().toISOString(),
98
+ ...(scanDuplicates
99
+ ? { duplicateIdScan: { budgetMs: DUPLICATE_ID_SCAN_BUDGET_MS, truncated } }
100
+ : {}),
101
+ },
84
102
  };
85
103
  }
86
104
  catch (err) {
@@ -110,7 +128,7 @@ const getBranchHealthHandler = async (_gc, ctx, _req) => {
110
128
  */
111
129
  const purgeBranchDirHandler = async (_gc, ctx, _req, params) => {
112
130
  const baseRoot = getDefaultBranchBase(ctx.services.config.mode);
113
- const baseBranchName = ctx.services.config.defaultBaseBranch ?? 'main';
131
+ const baseBranchName = baseBranchOf(ctx.services.config);
114
132
  const sanitizedBaseBranchName = sanitizeBranchName(baseBranchName);
115
133
  if (params.dirName === sanitizedBaseBranchName) {
116
134
  return { ok: false, status: 400, error: 'The base branch directory can never be purged' };
@@ -202,7 +220,7 @@ const purgeBranchDirHandler = async (_gc, ctx, _req, params) => {
202
220
  // [C1] The timestamp lives in the NAME, not the dir's mtime: rename()
203
221
  // preserves the original mtime, so mtime-based retention would delete
204
222
  // a months-stale orphan's trash on the very first cleanup pass.
205
- const trashName = `.trash-${params.dirName}-${formatTrashStamp(new Date())}`;
223
+ const trashName = `.trash-${params.dirName}-${formatDirStamp(new Date())}`;
206
224
  const trashPath = path.join(baseRoot, trashName);
207
225
  try {
208
226
  await fs.rename(dirPath, trashPath);
@@ -306,7 +324,7 @@ const repairBranchDirHandler = async (_gc, ctx, req, params) => {
306
324
  if (recheck === 'missing') {
307
325
  throw new RepairPreconditionError('No metadata file -- use purge for orphans', 409);
308
326
  }
309
- const archivedName = `${BRANCH_META_FILE}.corrupt-${formatTrashStamp(new Date())}`;
327
+ const archivedName = `${BRANCH_META_FILE}.corrupt-${formatDirStamp(new Date())}`;
310
328
  await fs.rename(branchJsonPath, path.join(dirPath, BRANCH_META_DIR, archivedName));
311
329
  return archivedName;
312
330
  });
@@ -420,7 +438,7 @@ async function checkStillCorrupt(dirPath) {
420
438
  * rebuild) and invalidates any ContentStore already registered in THIS
421
439
  * process for the same root.
422
440
  */
423
- const repairContentDuplicatesHandler = async (_gc, ctx, _req, params) => {
441
+ const repairContentDuplicatesHandler = async (_gc, ctx, req, params) => {
424
442
  const baseRoot = getDefaultBranchBase(ctx.services.config.mode);
425
443
  const dirPath = resolveDirWithinBase(baseRoot, params.dirName);
426
444
  if (!dirPath) {
@@ -449,7 +467,7 @@ const repairContentDuplicatesHandler = async (_gc, ctx, _req, params) => {
449
467
  if (duplicates.length === 0) {
450
468
  return { ok: false, status: 409, error: 'No duplicate content IDs found' };
451
469
  }
452
- const stamp = formatTrashStamp(new Date());
470
+ const stamp = formatDirStamp(new Date());
453
471
  try {
454
472
  for (const dup of duplicates) {
455
473
  const archivedAs = [];
@@ -493,15 +511,26 @@ const repairContentDuplicatesHandler = async (_gc, ctx, _req, params) => {
493
511
  : getErrorMessage(err),
494
512
  };
495
513
  }
514
+ finally {
515
+ // Archived files leave the branch at its next submit, a partial repair's included, so the
516
+ // admin is one of its editors. No `writableBranch` guard can say so: this route names a
517
+ // directory, not a branch.
518
+ if (resolved.length > 0) {
519
+ await ctx.services.recordBranchEditor({ branchRoot: dirPath, baseRoot }, req.user);
520
+ }
521
+ }
496
522
  };
497
523
  /**
498
- * Branch directory health scan (healthy/corrupt-metadata/orphan)
524
+ * Branch directory health scan (healthy/corrupt-metadata/orphan); `duplicates=1`
525
+ * adds the bounded duplicate-ID scan
499
526
  */
500
527
  const getBranchHealth = defineEndpoint({
501
528
  namespace: 'admin',
502
529
  name: 'branchHealth',
530
+ clientTimeout: 'long',
503
531
  method: 'GET',
504
532
  path: '/admin/branch-health',
533
+ params: branchHealthParamsSchema,
505
534
  responseType: 'BranchHealthResponse',
506
535
  response: {},
507
536
  defaultMockData: { entries: [], generatedAt: '2024-01-01T00:00:00.000Z' },
@@ -514,6 +543,7 @@ const getBranchHealth = defineEndpoint({
514
543
  const purgeBranchDir = defineEndpoint({
515
544
  namespace: 'admin',
516
545
  name: 'purgeBranchDir',
546
+ clientTimeout: 'long',
517
547
  method: 'POST',
518
548
  path: '/admin/branch-dirs/:dirName/purge',
519
549
  params: branchDirParamsSchema,
@@ -529,6 +559,7 @@ const purgeBranchDir = defineEndpoint({
529
559
  const repairBranchDir = defineEndpoint({
530
560
  namespace: 'admin',
531
561
  name: 'repairBranchDir',
562
+ clientTimeout: 'long',
532
563
  method: 'POST',
533
564
  path: '/admin/branch-dirs/:dirName/repair-metadata',
534
565
  params: branchDirParamsSchema,
@@ -558,6 +589,7 @@ const repairBranchDir = defineEndpoint({
558
589
  const repairContentDuplicates = defineEndpoint({
559
590
  namespace: 'admin',
560
591
  name: 'repairContentDuplicates',
592
+ clientTimeout: 'long',
561
593
  method: 'POST',
562
594
  path: '/admin/branch-dirs/:dirName/repair-content-duplicates',
563
595
  params: branchDirParamsSchema,
@@ -10,6 +10,7 @@ import type { ApiResponse } from './types.js';
10
10
  import type { Task, QueueStats, CorruptTaskFile } from '../task-queue/cms-task-queue.js';
11
11
  import type { BuildIdentity, WorkerStatusReport } from '../types.js';
12
12
  import type { OperatingMode } from '../operating-mode/index.js';
13
+ import type { SchemaIssue } from '../schema/types.js';
13
14
  export type { BranchHealthResponse, PurgeBranchDirResponse, RepairBranchDirResponse, RepairContentDuplicatesResponse, } from './admin-branch-health.js';
14
15
  type WorkerLivenessState = 'alive' | 'stale' | 'absent';
15
16
  export interface WorkerLiveness {
@@ -37,12 +38,23 @@ export interface AdminStatusData {
37
38
  * /admin.
38
39
  */
39
40
  settingsWorkspaceError?: string;
41
+ /** What the base branch's schema leaves out under this process's code; absent when nothing. */
42
+ schemaIssues?: SchemaIssue[];
40
43
  /** Build of the API process answering this request. */
41
44
  build: BuildIdentity;
42
45
  /** Whether `media` is configured; without it every upload returns 501. */
43
46
  assetStore: {
44
47
  configured: boolean;
45
48
  };
49
+ /**
50
+ * Whether THIS API process can load sharp. When false, any editor image not yet stored (a new
51
+ * crop, thumbnail or preview size, transformed on demand here) fails, and raster uploads are
52
+ * accepted without decode validation. Speaks only for the process that answers the request.
53
+ */
54
+ imageProcessing: {
55
+ available: boolean;
56
+ error?: string;
57
+ };
46
58
  }
47
59
  /** Response type for GET /admin/status */
48
60
  export type AdminStatusResponse = ApiResponse<AdminStatusData>;
@@ -66,10 +78,10 @@ declare const listAdminTasksParamsSchema: z.ZodObject<{
66
78
  status: z.ZodEnum<["pending", "processing", "completed", "failed", "corrupt"]>;
67
79
  limit: z.ZodOptional<z.ZodNumber>;
68
80
  }, "strip", z.ZodTypeAny, {
69
- status: "failed" | "pending" | "processing" | "completed" | "corrupt";
81
+ status: "failed" | "pending" | "corrupt" | "processing" | "completed";
70
82
  limit?: number | undefined;
71
83
  }, {
72
- status: "failed" | "pending" | "processing" | "completed" | "corrupt";
84
+ status: "failed" | "pending" | "corrupt" | "processing" | "completed";
73
85
  limit?: number | undefined;
74
86
  }>;
75
87
  export type ListAdminTasksParams = z.infer<typeof listAdminTasksParamsSchema>;
@@ -93,7 +105,13 @@ export type DeleteTaskParams = z.infer<typeof deleteTaskParamsSchema>;
93
105
  * `ADMIN_ROUTES` import.
94
106
  */
95
107
  export declare const ADMIN_ROUTES: {
96
- readonly branchHealth: import("./route-builder.js").RouteDefinition<undefined, undefined, import("./admin-branch-health.js").BranchHealthResponse>;
108
+ readonly branchHealth: import("./route-builder.js").RouteDefinition<z.ZodObject<{
109
+ duplicates: z.ZodOptional<z.ZodLiteral<"1">>;
110
+ }, "strip", z.ZodTypeAny, {
111
+ duplicates?: "1" | undefined;
112
+ }, {
113
+ duplicates?: "1" | undefined;
114
+ }>, undefined, import("./admin-branch-health.js").BranchHealthResponse>;
97
115
  readonly purgeBranchDir: import("./route-builder.js").RouteDefinition<z.ZodObject<{
98
116
  dirName: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
99
117
  }, "strip", z.ZodTypeAny, {
@@ -120,10 +138,10 @@ export declare const ADMIN_ROUTES: {
120
138
  status: z.ZodEnum<["pending", "processing", "completed", "failed", "corrupt"]>;
121
139
  limit: z.ZodOptional<z.ZodNumber>;
122
140
  }, "strip", z.ZodTypeAny, {
123
- status: "failed" | "pending" | "processing" | "completed" | "corrupt";
141
+ status: "failed" | "pending" | "corrupt" | "processing" | "completed";
124
142
  limit?: number | undefined;
125
143
  }, {
126
- status: "failed" | "pending" | "processing" | "completed" | "corrupt";
144
+ status: "failed" | "pending" | "corrupt" | "processing" | "completed";
127
145
  limit?: number | undefined;
128
146
  }>, undefined, AdminTasksResponse>;
129
147
  readonly retryTask: import("./route-builder.js").RouteDefinition<z.ZodObject<{
package/dist/api/admin.js CHANGED
@@ -14,7 +14,9 @@ import { WORKER_STATUS_FILE } from '../task-queue/worker-status.js';
14
14
  import { defineEndpoint } from './route-builder.js';
15
15
  import { getErrorMessage, isNotFoundError, redactCredentials } from '../utils/error.js';
16
16
  import { getBuildIdentity } from '../build-identity.js';
17
+ import { loadSharp } from '../assets/sharp-loader.js';
17
18
  import { ADMIN_BRANCH_HEALTH_ROUTES } from './admin-branch-health.js';
19
+ import { baseBranchOf } from '../utils/base-branch.js';
18
20
  /**
19
21
  * 60_000 = DEFAULT_LOCK_STALE_MS in worker/cms-worker.ts, hardcoded rather
20
22
  * than threaded through config: an adopter who overrides `lockStaleMs` skews
@@ -82,6 +84,24 @@ async function readSettingsWorkspaceError(ctx) {
82
84
  return redactCredentials(getErrorMessage(err));
83
85
  }
84
86
  }
87
+ /**
88
+ * What the base branch's schema leaves out under this process's registry (see
89
+ * `BranchSchemaCache`). Empty when the probe cannot resolve it: that failure reaches the
90
+ * editor through every schema-guarded route anyway.
91
+ */
92
+ async function readBaseSchemaIssues(ctx) {
93
+ try {
94
+ const { config, branchSchemaCache, entrySchemaRegistry } = ctx.services;
95
+ const base = await ctx.getBranchContext(baseBranchOf(config));
96
+ if (!base)
97
+ return [];
98
+ const { issues } = await branchSchemaCache.getSchema(base.branchRoot, entrySchemaRegistry, config.contentRoot || 'content');
99
+ return issues;
100
+ }
101
+ catch {
102
+ return [];
103
+ }
104
+ }
85
105
  /** Age (ms) of the oldest file in pending/, or undefined if empty/missing. */
86
106
  async function getOldestPendingAgeMs(taskDir) {
87
107
  const pendingDir = path.join(taskDir, 'pending');
@@ -133,15 +153,27 @@ const deleteTaskParamsSchema = z.object({
133
153
  .regex(/^[A-Za-z0-9._-]{1,120}\.json$/)
134
154
  .refine((v) => !v.includes('..'), { message: 'fileName must not contain ..' }),
135
155
  });
156
+ /** Loads sharp in this process; a failure is reported, never thrown. */
157
+ async function probeImageProcessing() {
158
+ try {
159
+ await loadSharp();
160
+ return { available: true };
161
+ }
162
+ catch (err) {
163
+ return { available: false, error: getErrorMessage(err) };
164
+ }
165
+ }
136
166
  const getAdminStatusHandler = async (_gc, ctx, _req) => {
137
167
  const taskDir = getTaskQueueDir(ctx.services.config);
138
168
  try {
139
- const [queueStats, oldestPendingAgeMs, worker, { workerStatus, statusReadError }, settingsWorkspaceError,] = await Promise.all([
169
+ const [queueStats, oldestPendingAgeMs, worker, { workerStatus, statusReadError }, settingsWorkspaceError, imageProcessing, schemaIssues,] = await Promise.all([
140
170
  getQueueStats(taskDir),
141
171
  getOldestPendingAgeMs(taskDir),
142
172
  classifyWorkerLiveness(taskDir),
143
173
  readWorkerStatus(taskDir),
144
174
  readSettingsWorkspaceError(ctx),
175
+ probeImageProcessing(),
176
+ readBaseSchemaIssues(ctx),
145
177
  ]);
146
178
  return {
147
179
  ok: true,
@@ -157,8 +189,10 @@ const getAdminStatusHandler = async (_gc, ctx, _req) => {
157
189
  workerStatus,
158
190
  ...(statusReadError ? { statusReadError } : {}),
159
191
  ...(settingsWorkspaceError ? { settingsWorkspaceError } : {}),
192
+ ...(schemaIssues.length > 0 ? { schemaIssues } : {}),
160
193
  build: getBuildIdentity(),
161
194
  assetStore: { configured: !!ctx.assetStore },
195
+ imageProcessing,
162
196
  },
163
197
  };
164
198
  }
@@ -271,6 +305,7 @@ const getAdminStatus = defineEndpoint({
271
305
  workerStatus: null,
272
306
  build: { canopycmsVersion: '0.0.0' },
273
307
  assetStore: { configured: false },
308
+ imageProcessing: { available: true },
274
309
  },
275
310
  guards: ['admin'],
276
311
  handler: getAdminStatusHandler,