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
@@ -6,11 +6,15 @@
6
6
  * the same checks. Exported so the test suite can exercise them directly.
7
7
  */
8
8
  import { CanopyConfigSchema } from './schemas/config.js';
9
+ import { mdxAllowlistSchema } from './schemas/field.js';
10
+ import { isMarkdownField, markdownFieldOptionsError } from '../validation/mdx-allowlist.js';
9
11
  import { normalizePathValue } from './flatten.js';
10
12
  // Leaf module, NOT the `operating-mode` barrel: the barrel re-exports the
11
13
  // client-unsafe strategy (node:fs/node:path) and this file is reachable from
12
14
  // `canopycms/client` (the generated editor page imports the adopter's config).
13
15
  import { resolveOperatingMode } from '../operating-mode/mode-env.js';
16
+ import { isPathFieldName } from '../editor/canopy-path.js';
17
+ import { ITEM_KEY } from '../item-keys.js';
14
18
  /**
15
19
  * Recursively check that all select fields have options defined.
16
20
  * Throws an error if a select field is missing options.
@@ -37,6 +41,33 @@ export const ensureSelectFieldsHaveOptions = (fields) => {
37
41
  }
38
42
  }
39
43
  };
44
+ /**
45
+ * Check that every data field's name can be spelled as a field path segment (`isPathFieldName`):
46
+ * the form, the preview's marks, validation errors and comment threads all name a field by its
47
+ * path. An inline group's own name is not part of any path, so only its children are checked.
48
+ * `ITEM_KEY` is reserved too, since every list item and block carries it.
49
+ */
50
+ export const ensureFieldNamesSpellInPaths = (fields) => {
51
+ if (!Array.isArray(fields))
52
+ return;
53
+ for (const field of fields) {
54
+ const f = field;
55
+ if (f?.type !== 'group' && typeof f?.name === 'string' && !isPathFieldName(f.name)) {
56
+ throw new Error(`Field "${f.name}": field names can't be empty, all digits, or contain '.', '[' or ']'; they're used in field paths`);
57
+ }
58
+ if (f?.type !== 'group' && f?.name === ITEM_KEY) {
59
+ throw new Error(`Field "${ITEM_KEY}": the name is reserved for the key CanopyCMS gives each list item and block. Rename the field, and the key in your content files with it.`);
60
+ }
61
+ if (f?.type === 'group' || f?.type === 'object') {
62
+ ensureFieldNamesSpellInPaths(f.fields);
63
+ }
64
+ if (f?.type === 'block' && Array.isArray(f.templates)) {
65
+ for (const template of f.templates) {
66
+ ensureFieldNamesSpellInPaths(template.fields);
67
+ }
68
+ }
69
+ }
70
+ };
40
71
  /**
41
72
  * Recursively check that all reference fields have at least one of `collections` or `entryTypes`.
42
73
  * Throws an error if a reference field has neither.
@@ -78,9 +109,11 @@ export const forEachReferenceField = (fields, visit) => {
78
109
  }
79
110
  };
80
111
  /**
81
- * Check that every `itemTitleField` sits on a `list: true` object and names a direct child
82
- * of type `string` or `number`, the only values the card heading shows as typed (a reference
83
- * would show its raw id, a select its stored value). Throws an error when it does not.
112
+ * Check that every `itemLabel` is non-blank text and, like every `itemTitleField`, sits on a
113
+ * `list: true` object, and that every `itemTitleField` names a direct child of type `string` or
114
+ * `number`, the only values the card heading shows as typed (a reference would show its raw id, a
115
+ * select its stored value). Throws an error when it does not. Entry schemas reach the editor
116
+ * through these checks, not the zod field schema.
84
117
  */
85
118
  export const ensureItemTitleFieldsExist = (fields) => {
86
119
  if (!Array.isArray(fields))
@@ -89,6 +122,15 @@ export const ensureItemTitleFieldsExist = (fields) => {
89
122
  const f = field;
90
123
  if (f?.type === 'object') {
91
124
  const children = Array.isArray(f.fields) ? f.fields : [];
125
+ if (f.itemLabel !== undefined) {
126
+ const label = `Object field "${f.name ?? 'unknown'}" has itemLabel`;
127
+ if (f.list !== true) {
128
+ throw new Error(`${label}, but itemLabel applies only to list: true objects`);
129
+ }
130
+ if (typeof f.itemLabel !== 'string' || f.itemLabel.trim() === '') {
131
+ throw new Error(`${label}, which must be non-blank text`);
132
+ }
133
+ }
92
134
  if (f.itemTitleField !== undefined) {
93
135
  const label = `Object field "${f.name ?? 'unknown'}" has itemTitleField "${String(f.itemTitleField)}"`;
94
136
  if (f.list !== true) {
@@ -210,6 +252,77 @@ export const ensureNoGroupsInsideComplexFields = (fields) => {
210
252
  };
211
253
  checkFields(Array.isArray(fields) ? fields : undefined);
212
254
  };
255
+ /**
256
+ * Check that `stampOnPublish` sits only on an entry's own top-level `datetime` field (an inline
257
+ * group's members count, since groups carry no data) that is neither `list: true` nor
258
+ * `required: true`. The submit that stamps sets one top-level value, and a required field can
259
+ * never be saved empty, so it would never be stamped. Throws on the first problem.
260
+ */
261
+ export const ensureStampOnPublishPlacement = (fields, scopeLabel = 'entry schema') => {
262
+ const refuse = (f, why) => {
263
+ throw new Error(`${scopeLabel}: field "${f.name ?? 'unknown'}" has stampOnPublish, ${why}`);
264
+ };
265
+ const check = (scopeFields, nestedIn) => {
266
+ if (!Array.isArray(scopeFields))
267
+ return;
268
+ for (const field of scopeFields) {
269
+ const f = field;
270
+ if (f?.stampOnPublish !== undefined && typeof f.stampOnPublish !== 'boolean') {
271
+ refuse(f, 'which must be true or false');
272
+ }
273
+ if (f?.stampOnPublish === true) {
274
+ if (nestedIn)
275
+ refuse(f, `but it is inside ${nestedIn}; only a top-level field is stamped`);
276
+ if (f.type !== 'datetime')
277
+ refuse(f, `but it is type "${String(f.type)}", not "datetime"`);
278
+ if (f.list === true)
279
+ refuse(f, 'but it is list: true; only a single date is stamped');
280
+ if (f.required === true) {
281
+ refuse(f, 'but it is required: true, so it can never be saved empty to be stamped');
282
+ }
283
+ }
284
+ if (f?.type === 'group')
285
+ check(f.fields, nestedIn);
286
+ if (f?.type === 'object')
287
+ check(f.fields, `object field "${String(f.name)}"`);
288
+ if (f?.type === 'block' && Array.isArray(f.templates)) {
289
+ for (const template of f.templates) {
290
+ check(template.fields, `block field "${String(f.name)}"`);
291
+ }
292
+ }
293
+ }
294
+ };
295
+ check(fields, undefined);
296
+ };
297
+ /**
298
+ * Check every markdown and mdx field's `mdxAllow` against its schema and its `renderAs`,
299
+ * `mdxAllow` and `executable` against each other. Throws on the first problem.
300
+ */
301
+ export const ensureMarkdownFieldOptions = (fields) => {
302
+ for (const field of fields) {
303
+ if (isMarkdownField(field)) {
304
+ if (field.mdxAllow !== undefined) {
305
+ const parsed = mdxAllowlistSchema.safeParse(field.mdxAllow);
306
+ if (!parsed.success) {
307
+ const [first] = parsed.error.issues;
308
+ const where = first?.path.join('.') ?? '';
309
+ throw new Error(`Field "${field.name}": mdxAllow${where === '' ? '' : `.${where}`} ${first?.message ?? 'is invalid'}`);
310
+ }
311
+ }
312
+ const message = markdownFieldOptionsError(field);
313
+ if (message !== undefined)
314
+ throw new Error(message);
315
+ }
316
+ if (field.type === 'group' || field.type === 'object') {
317
+ if ('fields' in field && Array.isArray(field.fields))
318
+ ensureMarkdownFieldOptions(field.fields);
319
+ }
320
+ if (field.type === 'block' && 'templates' in field && Array.isArray(field.templates)) {
321
+ for (const template of field.templates)
322
+ ensureMarkdownFieldOptions(template.fields);
323
+ }
324
+ }
325
+ };
213
326
  /**
214
327
  * Validate and normalize a CanopyConfig object.
215
328
  * Performs Zod validation and normalizes paths. Field-shape validation for
@@ -165,8 +165,8 @@ export class ContentIdIndex {
165
165
  `embed this ID. Keeping "${kept}" for ID-based lookups (reads, references, ` +
166
166
  `listings); "${dropped}" is excluded from those lookups for now but has NOT ` +
167
167
  `been deleted -- it is still on disk at that path, and saves addressed to it are ` +
168
- `refused until this is resolved. An admin can resolve this via ` +
169
- `the repair-content-duplicates admin action for this branch, which archives ` +
168
+ `refused until this is resolved. An admin can resolve this in System health ` +
169
+ `(Branches tab), whose repair-content-duplicates action archives ` +
170
170
  `"${dropped}" with a dot-prefixed name so future scans stop flagging it. ` +
171
171
  `Root: ${this.root}`);
172
172
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Absolute path of the generation marker for a branch-clone root.
3
- * @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md.
3
+ * @internal No importer; deletion candidate in safeinsights/canopycms#725.
4
4
  */
5
5
  export declare function contentIndexGenerationPath(root: string): string;
6
6
  /**
@@ -20,7 +20,7 @@ import { SCHEMA_GENERATION_RESOURCE } from './branch-schema-cache.js';
20
20
  const RESOURCE = 'content-index';
21
21
  /**
22
22
  * Absolute path of the generation marker for a branch-clone root.
23
- * @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md.
23
+ * @internal No importer; deletion candidate in safeinsights/canopycms#725.
24
24
  */
25
25
  export function contentIndexGenerationPath(root) {
26
26
  return resourceGenerationPath(root, RESOURCE);
@@ -152,6 +152,12 @@ export interface ListingReferenceResolver {
152
152
  cache: ReferenceResolveCache;
153
153
  access: ReferenceTargetAccess | undefined;
154
154
  }
155
+ /**
156
+ * A collection's listed entries minus those of an `unavailable` entry type, for the listings
157
+ * adopter pages render: data whose shape the running code does not know renders wrong rather
158
+ * than failing. The editor's own listing keeps them, so it can say why they cannot be opened.
159
+ */
160
+ export declare const withoutUnavailableEntries: (items: CollectionListItem[], collection: CollectionSchemaItem) => CollectionListItem[];
155
161
  /**
156
162
  * Resolve `reference` fields in a collection's listed entries, in place of their raw data.
157
163
  *
@@ -203,5 +209,8 @@ export interface SkippedListingFile {
203
209
  * -- a `README.md`, a colocated sibling artifact -- is always dropped with a debug-gated
204
210
  * `log.warn` and never passed to `onSkip`. Optional and purely diagnostic: `listEntries` uses
205
211
  * it to turn the skip into a hard build-time failure instead of a silent one.
212
+ *
213
+ * `readsId`, when given, leaves out every entry whose ContentId it rejects before its file is
214
+ * read, so a caller wanting a few entries does not pay for the rest.
206
215
  */
207
- export declare const listCollectionEntries: (root: string, collection: FlatSchemaItem, onSkip?: (file: SkippedListingFile) => void) => Promise<CollectionListItem[]>;
216
+ export declare const listCollectionEntries: (root: string, collection: FlatSchemaItem, onSkip?: (file: SkippedListingFile) => void, readsId?: (id: ContentId) => boolean) => Promise<CollectionListItem[]>;
@@ -14,6 +14,7 @@ import { isNotFoundError, getErrorMessage } from './utils/error.js';
14
14
  import { createDebugLogger } from './utils/debug.js';
15
15
  import { ContentStore, ContentStoreError, createReferenceResolveCache, } from './content-store.js';
16
16
  import { isBuildMode } from './build-mode.js';
17
+ import { withItemKeys } from './item-keys.js';
17
18
  const log = createDebugLogger({ prefix: 'ContentListing' });
18
19
  /** Validate and normalize `target` under `root`; throws ContentStoreError on a traversal. */
19
20
  const normalizePath = (root, target) => {
@@ -89,6 +90,15 @@ export const createReferenceResolver = (branchRoot, flatSchema, contentRootName,
89
90
  // row would have hidden.
90
91
  access: visibility?.shouldInclude,
91
92
  });
93
+ /**
94
+ * A collection's listed entries minus those of an `unavailable` entry type, for the listings
95
+ * adopter pages render: data whose shape the running code does not know renders wrong rather
96
+ * than failing. The editor's own listing keeps them, so it can say why they cannot be opened.
97
+ */
98
+ export const withoutUnavailableEntries = (items, collection) => {
99
+ const unavailable = new Set(collection.entries?.filter((e) => e.unavailable).map((e) => e.name) ?? []);
100
+ return unavailable.size > 0 ? items.filter((item) => !unavailable.has(item.entryType)) : items;
101
+ };
92
102
  /**
93
103
  * Resolve `reference` fields in a collection's listed entries, in place of their raw data.
94
104
  *
@@ -103,7 +113,7 @@ export const resolveCollectionItemReferences = async (items, collection, resolve
103
113
  return item;
104
114
  return {
105
115
  ...item,
106
- data: await resolver.store.resolveReferences(item.data, fields, resolver.cache, resolver.access),
116
+ data: await resolver.store.resolveReferences(item.data, fields, resolver.cache, resolver.access, item.logicalPath),
107
117
  };
108
118
  }));
109
119
  /**
@@ -142,7 +152,7 @@ export async function listEntries(branchRoot, flatSchema, contentRootName, optio
142
152
  ? createReferenceResolver(branchRoot, flatSchema, contentRootName, visibility)
143
153
  : null;
144
154
  const collectionResults = await Promise.all(collections.map(async (collection) => {
145
- const entries = await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file));
155
+ const entries = withoutUnavailableEntries(await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file)), collection);
146
156
  const visible = shouldInclude ? entries.filter((e) => shouldInclude(e.logicalPath)) : entries;
147
157
  // Resolve AFTER the visibility filter (a denied entry is never resolved, so its
148
158
  // references cost nothing and leak nothing) and BEFORE the mapping below, so
@@ -183,7 +193,7 @@ export async function listEntries(branchRoot, flatSchema, contentRootName, optio
183
193
  // One deliberate copy of the rule remains: `content-tree.ts`'s `defaultBuildPath`,
184
194
  // exported for adopters to extend and also handling the collection case
185
195
  // `computeEntryUrl` does not model. Folding it in is tracked in
186
- // `.claude/future-tasks/default-build-path-url-rule-copy.md`.
196
+ // safeinsights/canopycms#646.
187
197
  const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
188
198
  const raw = entry.data;
189
199
  const meta = {
@@ -281,8 +291,11 @@ const looksLikeMalformedEntry = (filename, entryTypes) => {
281
291
  * -- a `README.md`, a colocated sibling artifact -- is always dropped with a debug-gated
282
292
  * `log.warn` and never passed to `onSkip`. Optional and purely diagnostic: `listEntries` uses
283
293
  * it to turn the skip into a hard build-time failure instead of a silent one.
294
+ *
295
+ * `readsId`, when given, leaves out every entry whose ContentId it rejects before its file is
296
+ * read, so a caller wanting a few entries does not pay for the rest.
284
297
  */
285
- export const listCollectionEntries = async (root, collection, onSkip) => {
298
+ export const listCollectionEntries = async (root, collection, onSkip, readsId) => {
286
299
  if (collection.type !== 'collection' || !collection.entries) {
287
300
  return [];
288
301
  }
@@ -326,13 +339,17 @@ export const listCollectionEntries = async (root, collection, onSkip) => {
326
339
  return null;
327
340
  }
328
341
  const { type: entryTypeName, slug, id: contentId } = parsed;
342
+ if (readsId && !readsId(contentId))
343
+ return null;
329
344
  const entryType = entryTypes.find((e) => e.name === entryTypeName);
330
345
  const format = entryType?.format || 'json';
331
346
  const bodyField = entryType?.schema ? findBodyFieldName(entryType.schema) : 'body';
332
- const [stats, data] = await Promise.all([
347
+ const [stats, rawData] = await Promise.all([
333
348
  fs.stat(absolutePath),
334
349
  readEntryData(absolutePath, format, bodyField),
335
350
  ]);
351
+ // Keyed as `ContentStore.read` keys it, so every reader names an item alike.
352
+ const data = withItemKeys(entryType?.schema ?? [], rawData, 'content');
336
353
  const item = {
337
354
  logicalPath: entryLogicalPath(collection.logicalPath, slug),
338
355
  contentId,
@@ -84,10 +84,19 @@ export interface ContentReadMeta {
84
84
  * `{type}.{slug}.{id}.{ext}`) -- see the `entryType` caveat above for what that implies.
85
85
  */
86
86
  entryId?: ContentId;
87
+ /** The entry's slug within its collection, by the rule `listEntries` uses. */
88
+ slug: Slug;
89
+ /** The entry's URL path with no query, by the rule `listEntries` uses. */
90
+ urlPath: string;
87
91
  }
88
92
  export interface ContentReader {
89
93
  read: <T = unknown>(input: ReadContentInput, message?: string) => Promise<{
90
94
  data: T;
95
+ /**
96
+ * The requested `entryPath` and slug as a percent-encoded URL path, plus `?branch=<name>`.
97
+ * Through an entry-type `entryPath` it is not the entry's URL. Compare entries by
98
+ * `meta.urlPath`.
99
+ */
91
100
  path: string;
92
101
  meta: ContentReadMeta;
93
102
  }>;
@@ -1,11 +1,14 @@
1
1
  import { loadBranchContext, loadOrCreateBranchContext } from './branch-workspace.js';
2
+ import { SchemaUnavailableError } from './schema/schema-unavailable-error.js';
2
3
  import { ContentStore, ContentStoreError } from './content-store.js';
3
4
  import { namesNoWorkspace, resolveBranchPaths, } from './paths/index.js';
4
5
  import { trimSlashes } from './paths/normalize.js';
5
- import { isIndexSlug } from './utils/entry-url.js';
6
+ import { computeEntryUrl, isIndexSlug } from './utils/entry-url.js';
6
7
  import { isDeployedStatic, isBuildMode, readsFromCheckout } from './build-mode.js';
7
8
  import { isNotFoundError } from './utils/error.js';
8
9
  import { resolveEntryLinksInData } from './entry-link-resolver.js';
10
+ import { baseBranchOf } from './utils/base-branch.js';
11
+ import { CONTENT_READER_USER_ID } from './system-users.js';
9
12
  /**
10
13
  * Server-side helper to read content directly from a branch workspace. A branch with no workspace
11
14
  * reads as NOT_FOUND unless `allowCreateBranch` or a `getBranchContext` resolver says otherwise.
@@ -14,12 +17,9 @@ export const createContentReader = (options) => {
14
17
  const services = options.services;
15
18
  const operatingMode = services.config.mode;
16
19
  const basePathOverride = options.basePathOverride;
17
- const defaultBranch = options.defaultBranch ??
18
- services.config.defaultActiveBranch ??
19
- services.config.defaultBaseBranch ??
20
- 'main';
20
+ const defaultBranch = options.defaultBranch ?? services.config.defaultActiveBranch ?? baseBranchOf(services.config);
21
21
  const allowCreateBranch = options.allowCreateBranch ?? false;
22
- const createdBy = options.createdBy ?? 'canopycms-content-reader';
22
+ const createdBy = options.createdBy ?? CONTENT_READER_USER_ID;
23
23
  const resolveBranchContext = async (branchName) => {
24
24
  // Static deployments and builds read from the checkout: loadOrCreateBranchContext
25
25
  // returns a synthetic cwd context without git ops, regardless of allowCreateBranch
@@ -115,7 +115,7 @@ export const createContentReader = (options) => {
115
115
  // deliberately does not resolve the former, so a caller linking `path` linked to a 404.
116
116
  // Same index decision as computeEntryUrl/listEntries/buildPreviewSrc, through the same
117
117
  // predicate. NOTE this builder still keeps its own content-root strip and its own encoding
118
- // rather than delegating wholesale -- see .claude/future-tasks/default-build-path-url-rule-copy.md.
118
+ // rather than delegating wholesale -- see safeinsights/canopycms#646.
119
119
  const encodedSlug = isIndexSlug(opts.slug) ? '' : encodeSlug(opts.slug);
120
120
  const url = encodedSlug ? `${trimmed}/${encodedSlug}` : trimmed || '/';
121
121
  return appendBranch(url);
@@ -141,6 +141,8 @@ export const createContentReader = (options) => {
141
141
  // key by them without a separate listEntries lookup or filename parse.
142
142
  let entryType;
143
143
  let entryId;
144
+ let urlPath;
145
+ let resolvedSlug;
144
146
  try {
145
147
  const resolved = await store.resolveDocumentPath(entryPath, slug ?? '');
146
148
  logicalPath = resolved.logicalPath;
@@ -150,6 +152,8 @@ export const createContentReader = (options) => {
150
152
  // absent, for legacy entry files without an embedded ID (see ContentReadMeta).
151
153
  entryType = resolved.entryTypeName;
152
154
  entryId = resolved.id;
155
+ resolvedSlug = resolved.slug;
156
+ urlPath = computeEntryUrl(resolved.collectionPath, resolved.slug, contentRoot);
153
157
  }
154
158
  catch (err) {
155
159
  const message = err instanceof ContentStoreError ? err.message : 'Invalid content request';
@@ -196,10 +200,11 @@ export const createContentReader = (options) => {
196
200
  resolveReferences: input.resolveReferences ?? true,
197
201
  referenceAccess,
198
202
  });
199
- return { doc, store, physicalPath, entryType, entryId };
203
+ return { doc, store, physicalPath, entryType, entryId, slug: resolvedSlug, urlPath };
200
204
  }
201
205
  catch (err) {
202
- if (isNotFoundError(err))
206
+ // An entry of an unavailable type reads as absent, as adopter listings leave it out.
207
+ if (isNotFoundError(err) || err instanceof SchemaUnavailableError)
203
208
  return null;
204
209
  throw err;
205
210
  }
@@ -211,7 +216,7 @@ export const createContentReader = (options) => {
211
216
  const defaultMessage = `Content not found for ${entryPath}${slug ? `/${slug}` : ''} on branch ${branchName}`;
212
217
  throw new ContentStoreError(message ?? defaultMessage, 'NOT_FOUND');
213
218
  }
214
- const { doc, store, physicalPath, entryType, entryId } = result;
219
+ const { doc, store, physicalPath, entryType, entryId, slug: entrySlug, urlPath } = result;
215
220
  // For md/mdx format, merge the body into the data so callers get a complete object.
216
221
  // The field name comes from the schema's isBody flag (defaults to 'body').
217
222
  const docRecord = doc;
@@ -228,7 +233,7 @@ export const createContentReader = (options) => {
228
233
  slug,
229
234
  branch: branchName,
230
235
  });
231
- return { data, path, meta: { physicalPath, entryType, entryId } };
236
+ return { data, path, meta: { physicalPath, entryType, entryId, slug: entrySlug, urlPath } };
232
237
  };
233
238
  return { read };
234
239
  };
@@ -1,4 +1,4 @@
1
- import type { EntrySchema, FlatSchemaItem, EntryTypeConfig } from './config/index.js';
1
+ import type { ContentFormat, EntrySchema, FlatSchemaItem, EntryTypeConfig } from './config/index.js';
2
2
  import { ContentIdIndex } from './content-id-index.js';
3
3
  import { type LogicalPath, type PhysicalPath, type Slug, type ContentId } from './paths/index.js';
4
4
  export type MarkdownDocument = {
@@ -50,6 +50,19 @@ export declare class ContentStoreError extends Error {
50
50
  export declare class ContentConflictError extends Error {
51
51
  constructor(message?: string);
52
52
  }
53
+ /**
54
+ * Thrown when a write carrying a numeric `expectedVersion` finds no file: the entry was deleted
55
+ * or moved since that version was read. A missing file is a change since the read, so the write
56
+ * is refused rather than re-creating the entry; re-creating it is a create (`expectedVersion:
57
+ * null`) the caller makes deliberately.
58
+ *
59
+ * A `ContentConflictError` subclass so every 409 mapping keeps working; the distinct type lets
60
+ * the API tell the editor the entry is gone, where "reload to see the latest version" has
61
+ * nothing to reload.
62
+ */
63
+ export declare class EntryGoneError extends ContentConflictError {
64
+ constructor();
65
+ }
53
66
  /**
54
67
  * [SYNC-C1] Thrown when a mutation could not take the branch's cross-host
55
68
  * content-write lock within its bounded wait (utils/content-write-lock.ts) --
@@ -61,7 +74,11 @@ export declare class ContentConflictError extends Error {
61
74
  * instead of the misleading generic "modified by another editor".
62
75
  */
63
76
  export declare class BranchSyncingError extends ContentConflictError {
64
- constructor(message: string);
77
+ /** As on `ContentWriteLockBusyError`: `'unknown'` means the write ran and may have landed. */
78
+ readonly outcome: 'not-run' | 'unknown';
79
+ constructor(message: string,
80
+ /** As on `ContentWriteLockBusyError`: `'unknown'` means the write ran and may have landed. */
81
+ outcome?: 'not-run' | 'unknown');
65
82
  }
66
83
  /**
67
84
  * [F1] Thrown when a save's content ID is carried by MORE THAN ONE file in the branch's
@@ -152,10 +169,11 @@ export interface ContentStoreOptions {
152
169
  * cache must never be shared by two readers.
153
170
  *
154
171
  * Misses are memoized alongside hits so one batch stays internally coherent: a shared block
155
- * resolving to data on page 1 and `null` on page 40 of one sitemap is worse than either
156
- * consistent answer. Each DISTINCT id still gets its full self-healing retry, inside the memo.
172
+ * resolving to data on page 1 and a `MissingReference` on page 40 of one sitemap is worse than
173
+ * either consistent answer. Each DISTINCT id still gets its full self-healing retry, inside the
174
+ * memo.
157
175
  */
158
- export type ReferenceResolveCache = Map<string, Promise<Record<string, unknown> | null>>;
176
+ export type ReferenceResolveCache = Map<string, Promise<Record<string, unknown>>>;
159
177
  /** Create a cache for one batch of reference resolution. See {@link ReferenceResolveCache}. */
160
178
  export declare const createReferenceResolveCache: () => ReferenceResolveCache;
161
179
  /**
@@ -172,6 +190,13 @@ export interface ReadOptions {
172
190
  resolveReferences?: boolean;
173
191
  /** See {@link ReferenceTargetAccess}. */
174
192
  referenceAccess?: ReferenceTargetAccess;
193
+ /**
194
+ * Read an entry of an `unavailable` entry type as raw data instead of throwing
195
+ * {@link SchemaUnavailableError}: for reads of it as another entry's reference target
196
+ * (resolution embeds that raw data; the picker takes a label from it), never for one an
197
+ * author edits.
198
+ */
199
+ allowUnavailableEntryType?: boolean;
175
200
  }
176
201
  export declare class ContentStore {
177
202
  private readonly root;
@@ -365,6 +390,10 @@ export declare class ContentStore {
365
390
  relativePath: PhysicalPath;
366
391
  /** The entry's logical path, the form path-permission rules match (`entryLogicalPath`). */
367
392
  logicalPath: LogicalPath;
393
+ /** The collection the entry file lives in: the parent, when an entry-type item delegated. */
394
+ collectionPath: LogicalPath;
395
+ /** The entry's slug within that collection, lowercased as listings report it. */
396
+ slug: Slug;
368
397
  id?: string;
369
398
  /**
370
399
  * Always populated for a valid schema item: the collection branch below resolves a name
@@ -387,6 +416,21 @@ export declare class ContentStore {
387
416
  */
388
417
  read(collectionPath: LogicalPath, slug?: Slug | '', options?: ReadOptions): Promise<ContentDocument>;
389
418
  write(collectionPath: LogicalPath, slug: (Slug | "") | undefined, input: WriteInput, entryTypeName?: string, existingId?: ContentId): Promise<ContentDocument>;
419
+ /**
420
+ * Set top-level `field` of the entry file at `physicalPath` to the string `value` when the
421
+ * file holds it empty (absent, null or ''), keeping every other byte. Resolves to the file's
422
+ * version (the mtime `read()` reports) before and after the write, or undefined when it left
423
+ * the file alone.
424
+ *
425
+ * PRECONDITION: the caller already holds this branch's content-write lock, which makes the
426
+ * read and the write one critical section; a call outside it throws. This takes no lock
427
+ * itself, since a nested acquisition fails busy and is why nothing holding that lock may call
428
+ * `write()` (docs/concurrency.md, "Lock acquisition order").
429
+ */
430
+ fillEmptyFieldWhileHoldingWriteLock(physicalPath: PhysicalPath, format: ContentFormat, field: string, value: string): Promise<{
431
+ previousVersion: number;
432
+ version: number;
433
+ } | undefined>;
390
434
  /**
391
435
  * Read an entry by its ID (UUID).
392
436
  * Returns null if the ID doesn't exist or points to a collection.
@@ -478,14 +522,21 @@ export declare class ContentStore {
478
522
  * unmemoized behavior.
479
523
  *
480
524
  * `access` applies to every target exactly as in `read()`; see {@link ReferenceTargetAccess}.
525
+ * `origin`, the referring entry's logical path, names it in the dangling-reference warning.
526
+ */
527
+ resolveReferences(data: Record<string, unknown>, fields: EntrySchema, cache?: ReferenceResolveCache, access?: ReferenceTargetAccess, origin?: string): Promise<Record<string, unknown>>;
528
+ /**
529
+ * Resolve one reference id the way a reference field resolves it, for callers with ids but no
530
+ * field to walk: the editor's live-preview endpoint (api/resolve-references.ts) and the AI
531
+ * export (ai/references.ts). An id
532
+ * naming no readable entry resolves to a `MissingReference`, as in `read()`. No body is
533
+ * embedded, since there is no field to ask for one.
481
534
  */
482
- resolveReferences(data: Record<string, unknown>, fields: EntrySchema, cache?: ReferenceResolveCache, access?: ReferenceTargetAccess): Promise<Record<string, unknown>>;
535
+ resolveReferenceTarget(id: string, access?: ReferenceTargetAccess): Promise<Record<string, unknown>>;
483
536
  /**
484
- * Resolve one reference id the way a reference field resolves it, for the editor's
485
- * live-preview endpoint (api/resolve-references.ts), which has ids but no field to walk. Null
486
- * when the id names no entry. No body is embedded, since there is no field to ask for one.
537
+ * `trail` names where `data` sits, for the dangling-reference warning: the referring entry and
538
+ * the field path so far, in `traverseFields`' format (`blocks[2].author`, `reviewers[1]`).
487
539
  */
488
- resolveReferenceTarget(id: string, access?: ReferenceTargetAccess): Promise<Record<string, unknown> | null>;
489
540
  private resolveReferencesInData;
490
541
  /**
491
542
  * Resolve a single reference ID to full entry data, memoized when a batch cache is supplied.
@@ -501,7 +552,7 @@ export declare class ContentStore {
501
552
  * `data` from a process-global content-keyed cache, so `resolveSingleReferenceOnce`'s
502
553
  * top-level spread severs exactly one level and NESTED frontmatter objects alias across
503
554
  * occurrences, calls and requests. Pre-existing `read()` behavior, deliberately out of scope
504
- * here; see `.claude/future-tasks/graymatter-cache-shared-frontmatter.md`.
555
+ * here; see safeinsights/canopycms#708.
505
556
  *
506
557
  * Measured (2000 occurrences of one target, local disk, the friendliest case for NOT
507
558
  * caching): cloning a snippet-sized target is ~63x cheaper than re-reading and parsing it, a
@@ -513,7 +564,8 @@ export declare class ContentStore {
513
564
  */
514
565
  private resolveSingleReference;
515
566
  /**
516
- * Returns null if the reference is invalid or missing. Includes id, slug and collection.
567
+ * The target's data with its reference metadata, a `RestrictedReference` for a denied target,
568
+ * or a `MissingReference` when the id names no readable entry.
517
569
  *
518
570
  * A suspicious result (ID missing from the index, or an index hit whose file is gone)
519
571
  * triggers one forced index refresh and a retry — self-healing for mutations by other
@@ -526,6 +578,17 @@ export declare class ContentStore {
526
578
  * still runs the full refresh-and-retry; a cache only makes repeats of the SAME id share it.
527
579
  */
528
580
  private resolveSingleReferenceUncached;
581
+ /**
582
+ * Throw {@link SchemaUnavailableError} when an entry exists at `slug` and is of an
583
+ * `unavailable` entry type, for a handler to refuse before any other check answers first.
584
+ */
585
+ assertEntryAvailable(collectionPath: LogicalPath, slug?: Slug | ''): Promise<void>;
586
+ /**
587
+ * Throw {@link SchemaUnavailableError} when the entry type an entry is read or written as --
588
+ * `entryTypeName`, else the collection's default -- is `unavailable`. A name the collection
589
+ * does not declare is never charged to the default type, which it was not written as.
590
+ */
591
+ private assertEntryTypeAvailable;
529
592
  /**
530
593
  * The entry type an entry file was written as, by its filename's type token, falling back to
531
594
  * the collection's default the way `read()` does for a legacy untyped file.