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
@@ -0,0 +1,57 @@
1
+ import type { FieldConfig } from '../config/index.js';
2
+ import type { CommentThread } from '../comment-store.js';
3
+ import { type CanopyPathSegment } from './canopy-path.js';
4
+ /**
5
+ * One list a removal sits inside (a block list, or an object list holding the removed item's
6
+ * list): the index of the item enclosing the removal, and every other item.
7
+ */
8
+ export interface RemovalAnchor {
9
+ index: number;
10
+ siblings: unknown[];
11
+ }
12
+ /**
13
+ * What a form's Remove took out, for Undo. Paths are canopy paths (`blocks[2].items`), which skip
14
+ * a block's `value` wrapper; `restoreRemoval` resolves them against the value it restores into.
15
+ */
16
+ export type FieldRemoval = ({
17
+ kind: 'list-item';
18
+ /** The list field's own path. */
19
+ listPath: CanopyPathSegment[];
20
+ index: number;
21
+ /** The removed item itself, so its list-item key comes back with it. */
22
+ item: unknown;
23
+ /** Names the item in the Undo toast. */
24
+ label: string;
25
+ } | {
26
+ kind: 'value';
27
+ path: CanopyPathSegment[];
28
+ value: unknown;
29
+ label: string;
30
+ }) & {
31
+ /**
32
+ * The enclosing lists as they were before the removal (`removalAnchors`). Undo puts nothing
33
+ * back once one has changed, so an item never lands in whichever block now holds its index.
34
+ */
35
+ anchors?: RemovalAnchor[];
36
+ /** `clear` for an optional object's Clear, which its toast calls clearing, not removing. */
37
+ action?: 'remove' | 'clear';
38
+ };
39
+ /**
40
+ * The canopy path `restoreRemoval` puts a removal back at: a list item returns to its old index,
41
+ * or to the list's end when the list is now shorter than that.
42
+ */
43
+ export declare function restoredFieldPath(fields: readonly FieldConfig[], value: Record<string, unknown>, removal: FieldRemoval): CanopyPathSegment[];
44
+ /** The enclosing lists of a removal in `value`, taken before the removal applies; see `anchors`. */
45
+ export declare function removalAnchors(fields: readonly FieldConfig[], value: Record<string, unknown>, removal: FieldRemoval): RemovalAnchor[] | undefined;
46
+ /**
47
+ * `value` with a removal put back, or undefined when it can't be: the list or field is gone, an
48
+ * enclosing list has changed, the item is already there, or the image field has been filled.
49
+ * Edits made after the removal are kept, because it changes only the one list or field, in the
50
+ * value as it is now.
51
+ */
52
+ export declare function restoreRemoval(fields: readonly FieldConfig[], value: Record<string, unknown>, removal: FieldRemoval): Record<string, unknown> | undefined;
53
+ /**
54
+ * How many open field threads a removal at `path` moves to the entry: those inside it keyed to an
55
+ * item at or below it. One keyed only above stays on its field, which a Clear leaves in place.
56
+ */
57
+ export declare function openThreadsWithin(threads: readonly CommentThread[], entryPath: string, path: readonly CanopyPathSegment[]): number;
@@ -0,0 +1,163 @@
1
+ import equal from 'fast-deep-equal';
2
+ import { isPlainRecord } from '../validation/field-traversal.js';
3
+ import { normalizeCanopyPath, parseCanopyPath } from './canopy-path.js';
4
+ const findField = (fields, name) => {
5
+ for (const field of fields) {
6
+ if (field.type === 'group') {
7
+ const inGroup = findField(field.fields, name);
8
+ if (inGroup)
9
+ return inGroup;
10
+ }
11
+ else if (field.name === name) {
12
+ return field;
13
+ }
14
+ }
15
+ return undefined;
16
+ };
17
+ /**
18
+ * The path into the stored value for a canopy path, with the enclosing lists it passes through,
19
+ * or undefined when the value no longer has it.
20
+ */
21
+ const resolvePath = (fields, value, path) => {
22
+ let scope = fields;
23
+ let node = value;
24
+ const out = [];
25
+ const anchors = [];
26
+ const anchor = (list, index) => anchors.push({ index, siblings: list.filter((_, i) => i !== index) });
27
+ let i = 0;
28
+ while (i < path.length) {
29
+ const name = path[i];
30
+ const field = typeof name === 'string' ? findField(scope, name) : undefined;
31
+ if (typeof name !== 'string' || !field)
32
+ return undefined;
33
+ out.push(name);
34
+ node = isPlainRecord(node) ? node[name] : undefined;
35
+ i += 1;
36
+ if (i === path.length)
37
+ return { path: out, anchors };
38
+ const index = path[i];
39
+ if (field.type === 'block') {
40
+ const block = typeof index === 'number' && Array.isArray(node) ? node[index] : undefined;
41
+ if (typeof index !== 'number' || !isPlainRecord(block))
42
+ return undefined;
43
+ const template = field.templates.find((t) => t.name === block.template);
44
+ if (!template || !Array.isArray(node))
45
+ return undefined;
46
+ anchor(node, index);
47
+ out.push(index, 'value');
48
+ node = block.value;
49
+ scope = template.fields;
50
+ i += 1;
51
+ }
52
+ else if (field.type === 'object') {
53
+ const objectField = field;
54
+ if (objectField.list) {
55
+ if (typeof index !== 'number' || !Array.isArray(node))
56
+ return undefined;
57
+ anchor(node, index);
58
+ out.push(index);
59
+ node = node[index];
60
+ i += 1;
61
+ }
62
+ scope = objectField.fields;
63
+ }
64
+ else {
65
+ return undefined;
66
+ }
67
+ }
68
+ return { path: out, anchors };
69
+ };
70
+ const getAt = (root, path) => path.reduce((node, segment) => {
71
+ if (typeof segment === 'number')
72
+ return Array.isArray(node) ? node[segment] : undefined;
73
+ return isPlainRecord(node) ? node[segment] : undefined;
74
+ }, root);
75
+ const setAt = (root, path, next) => {
76
+ if (path.length === 0)
77
+ return next;
78
+ const [head, ...rest] = path;
79
+ if (typeof head === 'number') {
80
+ const list = Array.isArray(root) ? [...root] : [];
81
+ list[head] = setAt(list[head], rest, next);
82
+ return list;
83
+ }
84
+ const record = isPlainRecord(root) ? root : {};
85
+ return { ...record, [head]: setAt(record[head], rest, next) };
86
+ };
87
+ /** Equal once stored: JSON drops `undefined` keys, as the server's copy of a draft does. */
88
+ const sameContent = (a, b) => equal(JSON.parse(JSON.stringify(a ?? null)), JSON.parse(JSON.stringify(b ?? null)));
89
+ const removalPath = (removal) => removal.kind === 'list-item' ? removal.listPath : removal.path;
90
+ const anchorsHold = (then, now) => then === undefined ||
91
+ (then.length === now.length &&
92
+ then.every((anchor, i) => anchor.index === now[i].index &&
93
+ // By content as stored, so the server's copy of the same items still holds.
94
+ sameContent(anchor.siblings, now[i].siblings)));
95
+ /**
96
+ * The canopy path `restoreRemoval` puts a removal back at: a list item returns to its old index,
97
+ * or to the list's end when the list is now shorter than that.
98
+ */
99
+ export function restoredFieldPath(fields, value, removal) {
100
+ if (removal.kind !== 'list-item')
101
+ return removal.path;
102
+ const resolved = resolvePath(fields, value, removal.listPath);
103
+ const list = resolved ? getAt(value, resolved.path) : undefined;
104
+ return [...removal.listPath, Math.min(removal.index, Array.isArray(list) ? list.length : 0)];
105
+ }
106
+ /** The enclosing lists of a removal in `value`, taken before the removal applies; see `anchors`. */
107
+ export function removalAnchors(fields, value, removal) {
108
+ return resolvePath(fields, value, removalPath(removal))?.anchors;
109
+ }
110
+ /**
111
+ * `value` with a removal put back, or undefined when it can't be: the list or field is gone, an
112
+ * enclosing list has changed, the item is already there, or the image field has been filled.
113
+ * Edits made after the removal are kept, because it changes only the one list or field, in the
114
+ * value as it is now.
115
+ */
116
+ export function restoreRemoval(fields, value, removal) {
117
+ const resolved = resolvePath(fields, value, removalPath(removal));
118
+ if (!resolved || !anchorsHold(removal.anchors, resolved.anchors))
119
+ return undefined;
120
+ const { path } = resolved;
121
+ // An enclosing object cleared since would come back holding only this.
122
+ if (!isPlainRecord(path.length > 1 ? getAt(value, path.slice(0, -1)) : value))
123
+ return undefined;
124
+ const current = getAt(value, path);
125
+ let next;
126
+ if (removal.kind === 'list-item') {
127
+ if (current !== undefined && current !== null && !Array.isArray(current))
128
+ return undefined;
129
+ // Already back (a Discard or Reload restored it, or an earlier Undo did).
130
+ if (Array.isArray(current) && current.some((item) => sameContent(item, removal.item))) {
131
+ return undefined;
132
+ }
133
+ const list = Array.isArray(current) ? [...current] : [];
134
+ list.splice(Math.min(removal.index, list.length), 0, removal.item);
135
+ next = list;
136
+ }
137
+ else {
138
+ if (current !== undefined && current !== null)
139
+ return undefined;
140
+ next = removal.value;
141
+ }
142
+ const restored = setAt(value, path, next);
143
+ return isPlainRecord(restored) ? restored : undefined;
144
+ }
145
+ /**
146
+ * How many open field threads a removal at `path` moves to the entry: those inside it keyed to an
147
+ * item at or below it. One keyed only above stays on its field, which a Clear leaves in place.
148
+ */
149
+ export function openThreadsWithin(threads, entryPath, path) {
150
+ const prefix = parseCanopyPath(normalizeCanopyPath(path));
151
+ const isIndex = (segment) => typeof segment === 'number';
152
+ const itemsAbove = prefix.filter(isIndex).length - (isIndex(prefix[prefix.length - 1]) ? 1 : 0);
153
+ return threads.filter((thread) => {
154
+ if (thread.type !== 'field' || thread.resolved || thread.onRemovedItem)
155
+ return false;
156
+ if (thread.entryPath !== entryPath || !thread.canopyPath)
157
+ return false;
158
+ if ((thread.itemKeys?.length ?? 0) <= itemsAbove)
159
+ return false;
160
+ const segments = parseCanopyPath(thread.canopyPath);
161
+ return prefix.length <= segments.length && prefix.every((s, i) => segments[i] === s);
162
+ }).length;
163
+ }
@@ -0,0 +1,4 @@
1
+ /** What the editor calls a user id CanopyCMS itself acts as (system-users.ts). */
2
+ export declare const SYSTEM_USER_LABEL = "CanopyCMS bot";
3
+ /** A user id as text where no name lookup is available: a bot by its label, anyone else by id. */
4
+ export declare const userIdLabel: (userId: string) => string;
@@ -0,0 +1,5 @@
1
+ import { isSystemUserId } from '../system-users.js';
2
+ /** What the editor calls a user id CanopyCMS itself acts as (system-users.ts). */
3
+ export const SYSTEM_USER_LABEL = 'CanopyCMS bot';
4
+ /** A user id as text where no name lookup is available: a bot by its label, anyone else by id. */
5
+ export const userIdLabel = (userId) => isSystemUserId(userId) ? SYSTEM_USER_LABEL : userId;
@@ -0,0 +1,8 @@
1
+ import { modals } from '@mantine/modals';
2
+ type ConfirmModalProps = Parameters<typeof modals.openConfirmModal>[0];
3
+ /**
4
+ * `modals.openConfirmModal` with `sm` actions: its own Buttons would otherwise take the theme's
5
+ * compact `xs` default. A `size` the caller sets replaces it.
6
+ */
7
+ export declare function openConfirm(props: ConfirmModalProps): string;
8
+ export {};
@@ -0,0 +1,12 @@
1
+ import { modals } from '@mantine/modals';
2
+ /**
3
+ * `modals.openConfirmModal` with `sm` actions: its own Buttons would otherwise take the theme's
4
+ * compact `xs` default. A `size` the caller sets replaces it.
5
+ */
6
+ export function openConfirm(props) {
7
+ return modals.openConfirmModal({
8
+ ...props,
9
+ confirmProps: Object.assign({ size: 'sm' }, props.confirmProps),
10
+ cancelProps: Object.assign({ size: 'sm' }, props.cancelProps),
11
+ });
12
+ }
@@ -0,0 +1,19 @@
1
+ /** Where in the editor an error was caught, for the log line and the copied details. */
2
+ export interface EditorErrorContext {
3
+ /** `editor` for the crash screen, `field` for a field boundary, `rich-text` for MDXEditor. */
4
+ boundary: 'editor' | 'field' | 'rich-text';
5
+ /** The field's canopy path, for a field or rich-text boundary. */
6
+ fieldPath?: string;
7
+ /** React's component stack, when React supplied one. */
8
+ componentStack?: string;
9
+ }
10
+ /**
11
+ * The single point every error an editor boundary catches passes through. Logs it, because a
12
+ * boundary must never hide a crash; an adopter-facing report hook belongs here too.
13
+ */
14
+ export declare function reportEditorError(error: unknown, context: EditorErrorContext): void;
15
+ /**
16
+ * The text "Copy error details" puts on the clipboard. Sanitised, because an author pastes it
17
+ * into a chat or a ticket: stack frames can name local paths, and a message can carry a token.
18
+ */
19
+ export declare function formatErrorDetails(error: unknown, context: EditorErrorContext): string;
@@ -0,0 +1,32 @@
1
+ import { getErrorMessage, sanitizeErrorMessage } from '../../utils/error.js';
2
+ /**
3
+ * The single point every error an editor boundary catches passes through. Logs it, because a
4
+ * boundary must never hide a crash; an adopter-facing report hook belongs here too.
5
+ */
6
+ export function reportEditorError(error, context) {
7
+ const where = context.fieldPath ? `${context.boundary} ${context.fieldPath}` : context.boundary;
8
+ console.error(`[canopycms] editor error caught (${where})`, error, context.componentStack ?? '');
9
+ }
10
+ const MAX_DETAILS_LENGTH = 8000;
11
+ /**
12
+ * The text "Copy error details" puts on the clipboard. Sanitised, because an author pastes it
13
+ * into a chat or a ticket: stack frames can name local paths, and a message can carry a token.
14
+ */
15
+ export function formatErrorDetails(error, context) {
16
+ const lines = [
17
+ 'CanopyCMS editor error',
18
+ `Time: ${new Date().toISOString()}`,
19
+ `Caught by: ${context.boundary}${context.fieldPath ? ` (${context.fieldPath})` : ''}`,
20
+ `Error: ${error instanceof Error ? `${error.name}: ${error.message}` : getErrorMessage(error)}`,
21
+ ];
22
+ if (typeof navigator !== 'undefined')
23
+ lines.push(`Browser: ${navigator.userAgent}`);
24
+ if (error instanceof Error && error.stack)
25
+ lines.push('', 'Stack:', error.stack);
26
+ if (context.componentStack)
27
+ lines.push('', 'Component stack:', context.componentStack.trim());
28
+ const details = sanitizeErrorMessage(lines.join('\n'));
29
+ return details.length > MAX_DETAILS_LENGTH
30
+ ? `${details.slice(0, MAX_DETAILS_LENGTH)}\n[truncated]`
31
+ : details;
32
+ }
@@ -0,0 +1,56 @@
1
+ import { type MouseEvent, type RefObject } from 'react';
2
+ /**
3
+ * Mantine's own `returnFocus` records the focused element at open, and a menu item has unmounted
4
+ * with its menu by close, so an overlay opened from one returns focus here instead.
5
+ * `FOCUS_RETURN_ATTR` marks an overlay whose exit callback does; `focusIfIdle` treats focus inside it as idle.
6
+ */
7
+ export declare const FOCUS_RETURN_ATTR = "data-focus-return";
8
+ /**
9
+ * Focuses `target` unless the user has moved focus on: nothing is focused, or focus is inside an
10
+ * overlay `FOCUS_RETURN_ATTR` marks, as a closing one is until after its exit callback.
11
+ */
12
+ export declare function focusIfIdle(target: HTMLElement | null): void;
13
+ /**
14
+ * Run by `useMenuItemFocusReturn` when its menu has closed after an item acted: focuses the menu's
15
+ * `target` trigger once the item has unmounted and dropped focus to the page. Mantine calls it just before
16
+ * unmounting the items, hence the frame's wait; `returnFocus` would instead steal focus from an
17
+ * overlay the item opened, which holds it by then.
18
+ * @internal Exported for tests.
19
+ */
20
+ export declare function focusIfDropped(target: HTMLElement | null): void;
21
+ /**
22
+ * Props for a Mantine `Menu` and its `Menu.Dropdown` that run `focusIfDropped` on `trigger` after an
23
+ * item acted. A menu dismissed by a press elsewhere keeps focus where that press left it.
24
+ */
25
+ export declare function useMenuItemFocusReturn(trigger: RefObject<HTMLElement | null>): {
26
+ menu: {
27
+ onExitTransitionEnd: () => void;
28
+ };
29
+ dropdown: {
30
+ onClickCapture: (event: MouseEvent) => void;
31
+ };
32
+ };
33
+ /** The focused control to hand focus back to, or null when it is a menu item (gone once it acts) or the page. */
34
+ export declare function rememberOpener(): HTMLElement | null;
35
+ /** The remembered opener while it is still on the page, else the menu trigger that stands in for it. */
36
+ export declare function returnTarget(opener: HTMLElement | null, standIn: () => HTMLElement | null): HTMLElement | null;
37
+ /**
38
+ * Props that make a Mantine `Modal`, `Drawer` or `modals.openConfirmModal` focus `returnFocusTo()`
39
+ * once it has closed; none, keeping Mantine's default, without one.
40
+ */
41
+ export declare function focusReturnProps(returnFocusTo?: () => HTMLElement | null): {
42
+ returnFocus?: false;
43
+ onExitTransitionEnd?: () => void;
44
+ [FOCUS_RETURN_ATTR]?: true;
45
+ };
46
+ /**
47
+ * Focus for a list of removable badges, each with a `Remove …` button. The button that removes an
48
+ * item is gone once it acts, so `focusAfterRemove(index, fallback)` moves focus, once the list has
49
+ * re-rendered without the item, to the Remove button now at that index (the next item's, else the
50
+ * previous one's), else to the `fallback` control: the section's "Add …" button, or whatever stands
51
+ * in for it while that is hidden or disabled. Put `listRef` on the element holding the badges.
52
+ */
53
+ export declare function useFocusAfterRemove<L extends HTMLElement = HTMLDivElement>(): {
54
+ listRef: RefObject<L>;
55
+ focusAfterRemove: (index: number, fallback: RefObject<HTMLElement | null>) => void;
56
+ };
@@ -0,0 +1,106 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ /**
3
+ * Mantine's own `returnFocus` records the focused element at open, and a menu item has unmounted
4
+ * with its menu by close, so an overlay opened from one returns focus here instead.
5
+ * `FOCUS_RETURN_ATTR` marks an overlay whose exit callback does; `focusIfIdle` treats focus inside it as idle.
6
+ */
7
+ export const FOCUS_RETURN_ATTR = 'data-focus-return';
8
+ /**
9
+ * Focuses `target` unless the user has moved focus on: nothing is focused, or focus is inside an
10
+ * overlay `FOCUS_RETURN_ATTR` marks, as a closing one is until after its exit callback.
11
+ */
12
+ export function focusIfIdle(target) {
13
+ const active = document.activeElement;
14
+ if (!active || active === document.body || active.closest(`[${FOCUS_RETURN_ATTR}]`)) {
15
+ target?.focus({ preventScroll: true });
16
+ }
17
+ }
18
+ /**
19
+ * Run by `useMenuItemFocusReturn` when its menu has closed after an item acted: focuses the menu's
20
+ * `target` trigger once the item has unmounted and dropped focus to the page. Mantine calls it just before
21
+ * unmounting the items, hence the frame's wait; `returnFocus` would instead steal focus from an
22
+ * overlay the item opened, which holds it by then.
23
+ * @internal Exported for tests.
24
+ */
25
+ export function focusIfDropped(target) {
26
+ requestAnimationFrame(() => {
27
+ const active = document.activeElement;
28
+ if (!active || active === document.body)
29
+ target?.focus({ preventScroll: true });
30
+ });
31
+ }
32
+ /**
33
+ * Props for a Mantine `Menu` and its `Menu.Dropdown` that run `focusIfDropped` on `trigger` after an
34
+ * item acted. A menu dismissed by a press elsewhere keeps focus where that press left it.
35
+ */
36
+ export function useMenuItemFocusReturn(trigger) {
37
+ const acted = useRef(false);
38
+ return {
39
+ menu: {
40
+ onExitTransitionEnd: () => {
41
+ if (acted.current)
42
+ focusIfDropped(trigger.current);
43
+ acted.current = false;
44
+ },
45
+ },
46
+ dropdown: {
47
+ onClickCapture: (event) => {
48
+ if (event.target instanceof Element &&
49
+ event.target.closest('[role="menuitem"]:not([aria-disabled="true"])')) {
50
+ acted.current = true;
51
+ }
52
+ },
53
+ },
54
+ };
55
+ }
56
+ /** The focused control to hand focus back to, or null when it is a menu item (gone once it acts) or the page. */
57
+ export function rememberOpener() {
58
+ const active = document.activeElement;
59
+ return active instanceof HTMLElement &&
60
+ active !== document.body &&
61
+ !active.closest('[role="menuitem"]')
62
+ ? active
63
+ : null;
64
+ }
65
+ /** The remembered opener while it is still on the page, else the menu trigger that stands in for it. */
66
+ export function returnTarget(opener, standIn) {
67
+ return opener?.isConnected ? opener : standIn();
68
+ }
69
+ /**
70
+ * Props that make a Mantine `Modal`, `Drawer` or `modals.openConfirmModal` focus `returnFocusTo()`
71
+ * once it has closed; none, keeping Mantine's default, without one.
72
+ */
73
+ export function focusReturnProps(returnFocusTo) {
74
+ if (!returnFocusTo)
75
+ return {};
76
+ return {
77
+ returnFocus: false,
78
+ onExitTransitionEnd: () => focusIfIdle(returnFocusTo()),
79
+ [FOCUS_RETURN_ATTR]: true,
80
+ };
81
+ }
82
+ /**
83
+ * Focus for a list of removable badges, each with a `Remove …` button. The button that removes an
84
+ * item is gone once it acts, so `focusAfterRemove(index, fallback)` moves focus, once the list has
85
+ * re-rendered without the item, to the Remove button now at that index (the next item's, else the
86
+ * previous one's), else to the `fallback` control: the section's "Add …" button, or whatever stands
87
+ * in for it while that is hidden or disabled. Put `listRef` on the element holding the badges.
88
+ */
89
+ export function useFocusAfterRemove() {
90
+ const listRef = useRef(null);
91
+ const [pending, setPending] = useState(null);
92
+ useEffect(() => {
93
+ if (!pending)
94
+ return;
95
+ const removeButtons = listRef.current?.querySelectorAll('button[aria-label^="Remove "]');
96
+ const target = removeButtons && removeButtons.length > 0
97
+ ? removeButtons[Math.min(pending.index, removeButtons.length - 1)]
98
+ : pending.fallback.current;
99
+ target?.focus();
100
+ setPending(null);
101
+ }, [pending]);
102
+ return {
103
+ listRef,
104
+ focusAfterRemove: (index, fallback) => setPending({ index, fallback }),
105
+ };
106
+ }
@@ -23,12 +23,22 @@ export type EntryLinkUrlResolver = (entry: {
23
23
  }) => string;
24
24
  /** URL path for an entry's location in the content tree; delegates to `computeEntryUrl`. */
25
25
  export declare function resolveEntryUrl(location: Pick<IdLocation, 'collection' | 'slug'>, contentRoot: string): string;
26
+ export interface ResolveEntryLinksOptions {
27
+ /**
28
+ * Whether a link to this content id may show its target. When set, a link to a target it
29
+ * refuses, or to a missing one, shows nothing of that target's URL or slug: an inline
30
+ * markdown link (`[text](entry:ID)`, or an image) becomes its bare text, and any other form
31
+ * becomes `#`.
32
+ */
33
+ isLinkable?: (id: string) => boolean;
34
+ }
26
35
  /**
27
36
  * Replace `entry:CONTENT_ID` tokens with resolved URL paths, skipping code blocks and
28
37
  * spans so examples mentioning the syntax survive. A missing ID becomes "#" (dead link)
29
38
  * plus a warning; an anchor fragment is preserved (`entry:ID#heading` => `/path#heading`).
39
+ * See {@link ResolveEntryLinksOptions.isLinkable} for links to a target the caller withholds.
30
40
  */
31
- export declare function resolveEntryLinksInText(text: string, idIndex: ContentIdIndex, contentRoot: string, customResolver?: EntryLinkUrlResolver): string;
41
+ export declare function resolveEntryLinksInText(text: string, idIndex: ContentIdIndex, contentRoot: string, customResolver?: EntryLinkUrlResolver, options?: ResolveEntryLinksOptions): string;
32
42
  /** Quick-check pattern for early bail-out (no `g` flag, safe for `.test()`). */
33
43
  export declare const ENTRY_LINK_QUICK_CHECK: RegExp;
34
44
  /**
@@ -27,19 +27,26 @@ export function resolveEntryUrl(location, contentRoot) {
27
27
  * Replace `entry:CONTENT_ID` tokens with resolved URL paths, skipping code blocks and
28
28
  * spans so examples mentioning the syntax survive. A missing ID becomes "#" (dead link)
29
29
  * plus a warning; an anchor fragment is preserved (`entry:ID#heading` => `/path#heading`).
30
+ * See {@link ResolveEntryLinksOptions.isLinkable} for links to a target the caller withholds.
30
31
  */
31
- export function resolveEntryLinksInText(text, idIndex, contentRoot, customResolver) {
32
+ export function resolveEntryLinksInText(text, idIndex, contentRoot, customResolver, options = {}) {
33
+ const { isLinkable } = options;
32
34
  const parts = splitByCodeRegions(text);
33
35
  return parts
34
36
  .map((part) => {
35
37
  if (part.isCode)
36
38
  return part.text;
37
- return part.text.replace(ENTRY_LINK_PATTERN, (_match, id, anchor) => {
38
- const location = idIndex.findById(id);
39
- if (!location || location.type !== 'entry' || !location.collection || !location.slug) {
39
+ const partText = isLinkable
40
+ ? unwrapInlineLinks(part.text, (id) => !isLinkable(id) || !findEntry(idIndex, id))
41
+ : part.text;
42
+ return partText.replace(ENTRY_LINK_PATTERN, (_match, id, anchor) => {
43
+ const location = findEntry(idIndex, id);
44
+ if (!location) {
40
45
  log.warn('resolve', `Entry link target not found: entry:${id}`);
41
- return anchor ?? '#';
46
+ return isLinkable ? '#' : (anchor ?? '#');
42
47
  }
48
+ if (isLinkable && !isLinkable(id))
49
+ return '#';
43
50
  let url;
44
51
  if (customResolver) {
45
52
  url = customResolver({
@@ -56,6 +63,59 @@ export function resolveEntryLinksInText(text, idIndex, contentRoot, customResolv
56
63
  })
57
64
  .join('');
58
65
  }
66
+ function findEntry(idIndex, id) {
67
+ const location = idIndex.findById(id);
68
+ if (!location || location.type !== 'entry' || !location.collection || !location.slug) {
69
+ return undefined;
70
+ }
71
+ return location;
72
+ }
73
+ /**
74
+ * `](entry:ID#anchor "title")`: the target half of an inline markdown link. A match starts only at
75
+ * a literal `](entry:`, its anchor stops at `]` and its title at the next `"`, so failed matches
76
+ * scan stretches that don't overlap, keeping the scan linear.
77
+ */
78
+ const INLINE_LINK_TARGET = new RegExp(`\\]\\(entry:(${BASE58_CHAR}{12})(?:#[^\\s)>"'\\]]*)?(?:[ \\t]+"[^"\\n]*")?\\)`, 'g');
79
+ /**
80
+ * Replace each inline markdown link (or image) whose `entry:` target `shouldUnwrap` names with
81
+ * its bracketed text. A link whose opening `[` can't be found is left alone, for the caller's
82
+ * token pass to neutralize.
83
+ */
84
+ function unwrapInlineLinks(text, shouldUnwrap) {
85
+ let out = '';
86
+ let cursor = 0;
87
+ // A failed search from `close` saw no `[` it could match before it, and a later `]` only adds
88
+ // depth, so later searches stop there: the bracket scans stay linear in the text.
89
+ let scanFloor = 0;
90
+ for (const match of text.matchAll(INLINE_LINK_TARGET)) {
91
+ const close = match.index;
92
+ if (close < cursor || !shouldUnwrap(match[1]))
93
+ continue;
94
+ const open = findOpeningBracket(text, close, Math.max(cursor, scanFloor));
95
+ if (open === -1) {
96
+ scanFloor = close;
97
+ continue;
98
+ }
99
+ const isImage = open > cursor && text[open - 1] === '!' && text[open - 2] !== '\\';
100
+ const start = isImage ? open - 1 : open;
101
+ out += text.slice(cursor, start) + text.slice(open + 1, close);
102
+ cursor = close + match[0].length;
103
+ }
104
+ return out + text.slice(cursor);
105
+ }
106
+ /** The `[` matching the `]` at `close`, searching back no further than `floor`; -1 if none. */
107
+ function findOpeningBracket(text, close, floor) {
108
+ let depth = 1;
109
+ for (let i = close - 1; i >= floor; i--) {
110
+ if (i > floor && text[i - 1] === '\\')
111
+ continue;
112
+ if (text[i] === ']')
113
+ depth++;
114
+ else if (text[i] === '[' && --depth === 0)
115
+ return i;
116
+ }
117
+ return -1;
118
+ }
59
119
  /** Quick-check pattern for early bail-out (no `g` flag, safe for `.test()`). */
60
120
  export const ENTRY_LINK_QUICK_CHECK = /entry:[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{12}/;
61
121
  /**
@@ -16,9 +16,9 @@ import type { EntrySchemaRegistry } from './schema/types.js';
16
16
  * array; more than one `isTitle` per schema, or one on a non-string field or inside a list;
17
17
  * more than one `isBody`, or one on a field that is not markdown/mdx or is named one of
18
18
  * `RESOLVED_REFERENCE_KEYS`; a top-level or inline-group field named `unavailable`. This is also the one
19
- * place the shared field-shape checks run: select fields must have options,
20
- * reference fields must have `collections` or `entryTypes`, no inline groups
21
- * inside object/block fields, no field-name collisions after group flattening.
19
+ * place the shared field-shape checks run: field names a path can spell, select fields must have options,
20
+ * reference fields must have `collections` or `entryTypes`, no inline groups inside object/block fields,
21
+ * no field-name collisions after group flattening, valid `mdxAllow`, `stampOnPublish` placement.
22
22
  *
23
23
  * @example
24
24
  * ```typescript
@@ -2,7 +2,7 @@ import { countTitleFields, findInvalidTitleFields, findTitleFieldsInLists, } fro
2
2
  import { countBodyFields, findInvalidBodyFields, findReservedBodyFieldName, } from './utils/body-field.js';
3
3
  import { RESOLVED_REFERENCE_KEYS, RESTRICTED_REFERENCE_MARKER } from './entry-schema.js';
4
4
  import { flattenGroupFields } from './utils/flatten-group-fields.js';
5
- import { ensureSelectFieldsHaveOptions, ensureReferenceFieldsHaveScope, ensureItemTitleFieldsExist, ensureNoFlattenedFieldNameCollisions, ensureNoGroupsInsideComplexFields, } from './config/validation.js';
5
+ import { ensureFieldNamesSpellInPaths, ensureSelectFieldsHaveOptions, ensureReferenceFieldsHaveScope, ensureItemTitleFieldsExist, ensureNoFlattenedFieldNameCollisions, ensureNoGroupsInsideComplexFields, ensureMarkdownFieldOptions, ensureStampOnPublishPlacement, } from './config/validation.js';
6
6
  /** Look up a field's type by dotted path (e.g., "meta.order").
7
7
  * Groups are transparent — their children are searched at the same path level. */
8
8
  function findFieldType(fields, dottedPath) {
@@ -39,9 +39,9 @@ function findFieldType(fields, dottedPath) {
39
39
  * array; more than one `isTitle` per schema, or one on a non-string field or inside a list;
40
40
  * more than one `isBody`, or one on a field that is not markdown/mdx or is named one of
41
41
  * `RESOLVED_REFERENCE_KEYS`; a top-level or inline-group field named `unavailable`. This is also the one
42
- * place the shared field-shape checks run: select fields must have options,
43
- * reference fields must have `collections` or `entryTypes`, no inline groups
44
- * inside object/block fields, no field-name collisions after group flattening.
42
+ * place the shared field-shape checks run: field names a path can spell, select fields must have options,
43
+ * reference fields must have `collections` or `entryTypes`, no inline groups inside object/block fields,
44
+ * no field-name collisions after group flattening, valid `mdxAllow`, `stampOnPublish` placement.
45
45
  *
46
46
  * @example
47
47
  * ```typescript
@@ -95,10 +95,13 @@ export function createEntrySchemaRegistry(registry) {
95
95
  if (flattenGroupFields(schema).some((f) => f.name === RESTRICTED_REFERENCE_MARKER)) {
96
96
  throw new Error(`Entry schema registry entry "${key}": field "${RESTRICTED_REFERENCE_MARKER}" is reserved — a resolved reference carries "${RESTRICTED_REFERENCE_MARKER}: true" only when the reader may not read its target, so a field with that name cannot be delivered on a reference to this entry type. Rename the field.`);
97
97
  }
98
+ ensureFieldNamesSpellInPaths(schema);
98
99
  ensureSelectFieldsHaveOptions(schema);
99
100
  ensureReferenceFieldsHaveScope(schema);
100
101
  ensureItemTitleFieldsExist(schema);
101
102
  ensureNoGroupsInsideComplexFields(schema);
103
+ ensureMarkdownFieldOptions(schema);
104
+ ensureStampOnPublishPlacement(schema, `Entry schema registry entry "${key}"`);
102
105
  ensureNoFlattenedFieldNameCollisions(schema, `entry schema "${key}"`);
103
106
  }
104
107
  return registry;