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,235 @@
1
+ import { isPlainRecord, resolveBlockItem } from './validation/field-traversal.js';
2
+ import { formatCanopyPath, parseCanopyPath } from './editor/canopy-path.js';
3
+ /**
4
+ * The key each object-list item and block carries in content, naming that item among its list's
5
+ * items for as long as it exists: a move or an edit keeps it, a copy gets a new one. Field comment
6
+ * threads name the items on their path by it (`CommentThread.itemKeys`). Beside `template` on a
7
+ * block, never inside its `value`; a schema may not define a field of this name.
8
+ *
9
+ * Dependency-free: the editor and the server both use this module.
10
+ */
11
+ export const ITEM_KEY = '_key';
12
+ const ITEM_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
13
+ /** A usable item key: 1-64 letters, digits, `_` or `-`, starting with a letter or digit. */
14
+ export const isItemKey = (value) => typeof value === 'string' && ITEM_KEY_PATTERN.test(value);
15
+ const BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
16
+ /** A new random item key: 12 Base58 characters. */
17
+ export function mintItemKey() {
18
+ return Array.from(crypto.getRandomValues(new Uint8Array(12)), (b) => BASE58[b % 58]).join('');
19
+ }
20
+ /** cyrb53: a fast, well-mixed 53-bit string hash. Not cryptographic, and needn't be. */
21
+ function hash53(text) {
22
+ let h1 = 0xdeadbeef;
23
+ let h2 = 0x41c6ce57;
24
+ for (let i = 0; i < text.length; i++) {
25
+ const c = text.charCodeAt(i);
26
+ h1 = Math.imul(h1 ^ c, 2654435761);
27
+ h2 = Math.imul(h2 ^ c, 1597334677);
28
+ }
29
+ h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
30
+ h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
31
+ return 4294967296 * (2097151 & h2) + (h1 >>> 0);
32
+ }
33
+ /** `h` and the Base58 hash of an item as it was read, before any key was added inside it. */
34
+ function contentKey(item) {
35
+ let n = hash53(JSON.stringify(item));
36
+ let out = '';
37
+ do {
38
+ out = BASE58[n % 58] + out;
39
+ n = Math.floor(n / 58);
40
+ } while (n > 0);
41
+ return `h${out}`;
42
+ }
43
+ const isListField = (field) => field.type === 'block' || (field.type === 'object' && !!field.list);
44
+ /**
45
+ * `data` with every object-list item and block keyed, each unique in its list, nested lists
46
+ * included; the same object when nothing needed a key. A usable key is kept unless `fill` is
47
+ * `fresh`.
48
+ */
49
+ export function withItemKeys(fields, data, fill) {
50
+ let out = data;
51
+ for (const field of fields) {
52
+ if (field.type === 'group') {
53
+ out = withItemKeys(field.fields, out, fill);
54
+ continue;
55
+ }
56
+ const value = out[field.name];
57
+ let next = value;
58
+ if (isListField(field)) {
59
+ if (Array.isArray(value))
60
+ next = keyList(field, value, fill);
61
+ }
62
+ else if (field.type === 'object' && isPlainRecord(value)) {
63
+ next = withItemKeys(field.fields ?? [], value, fill);
64
+ }
65
+ if (next !== value)
66
+ out = { ...out, [field.name]: next };
67
+ }
68
+ return out;
69
+ }
70
+ /** `item`, a copy about to join `field`'s list, with fresh keys for it and every item inside it. */
71
+ export function withFreshItemKeys(field, item) {
72
+ return keyList(field, [item], 'fresh')[0];
73
+ }
74
+ function keyList(field, items, fill) {
75
+ const held = new Set();
76
+ if (fill !== 'fresh') {
77
+ for (const item of items) {
78
+ if (isPlainRecord(item) && isItemKey(item[ITEM_KEY]))
79
+ held.add(item[ITEM_KEY]);
80
+ }
81
+ }
82
+ const kept = new Set();
83
+ let changed = false;
84
+ const out = items.map((item) => {
85
+ if (!isPlainRecord(item))
86
+ return item;
87
+ let next = keyInside(field, item, fill);
88
+ const own = item[ITEM_KEY];
89
+ if (fill !== 'fresh' && isItemKey(own) && !kept.has(own)) {
90
+ kept.add(own);
91
+ }
92
+ else {
93
+ const key = fill === 'content' ? unheld(contentKey(item), held) : mintItemKey();
94
+ held.add(key);
95
+ kept.add(key);
96
+ next = { ...next, [ITEM_KEY]: key };
97
+ }
98
+ if (next !== item)
99
+ changed = true;
100
+ return next;
101
+ });
102
+ return changed ? out : items;
103
+ }
104
+ /** `key`, or with a suffix when another item of the list already holds it (identical items). */
105
+ function unheld(key, held) {
106
+ let out = key;
107
+ for (let n = 2; held.has(out); n++)
108
+ out = `${key}-${n}`;
109
+ return out;
110
+ }
111
+ /** The item with the lists inside it keyed. */
112
+ function keyInside(field, item, fill) {
113
+ if (field.type !== 'block') {
114
+ return withItemKeys(field.fields ?? [], item, fill);
115
+ }
116
+ const resolved = resolveBlockItem(field, item);
117
+ if (!resolved)
118
+ return item;
119
+ const data = withItemKeys(resolved.fields, resolved.data, fill);
120
+ if (data === resolved.data)
121
+ return item;
122
+ return resolved.data === item ? data : { ...item, value: data };
123
+ }
124
+ const findField = (fields, name) => {
125
+ for (const field of fields) {
126
+ if (field.type === 'group') {
127
+ const inGroup = findField(field.fields, name);
128
+ if (inGroup)
129
+ return inGroup;
130
+ }
131
+ else if (field.name === name) {
132
+ return field;
133
+ }
134
+ }
135
+ return undefined;
136
+ };
137
+ /**
138
+ * Walks `canopyPath` through `value` by schema, calling `atIndex` with each list index on the path
139
+ * and that list's items; it returns the index to continue with, or undefined to stop. Returns the
140
+ * path walked, or undefined when the walk stopped or the value has no such path.
141
+ */
142
+ function walkPath(fields, value, canopyPath, atIndex) {
143
+ const segments = parseCanopyPath(canopyPath);
144
+ const out = [];
145
+ let scope = fields;
146
+ let record = value;
147
+ let depth = 0;
148
+ for (let i = 0; i < segments.length; i++) {
149
+ const name = segments[i];
150
+ if (typeof name !== 'string')
151
+ return undefined;
152
+ const field = findField(scope, name);
153
+ out.push(name);
154
+ if (!field || i === segments.length - 1) {
155
+ if (!field)
156
+ return undefined;
157
+ continue;
158
+ }
159
+ const node = record?.[name];
160
+ if (isListField(field)) {
161
+ const index = segments[i + 1];
162
+ if (typeof index !== 'number' || !Array.isArray(node))
163
+ return undefined;
164
+ const at = atIndex(index, node, depth);
165
+ if (at === undefined)
166
+ return undefined;
167
+ depth += 1;
168
+ out.push(at);
169
+ i += 1;
170
+ const item = node[at];
171
+ if (!isPlainRecord(item))
172
+ return undefined;
173
+ if (field.type === 'block') {
174
+ const resolved = resolveBlockItem(field, item);
175
+ if (!resolved)
176
+ return undefined;
177
+ scope = resolved.fields;
178
+ record = resolved.data;
179
+ }
180
+ else {
181
+ scope = field.fields ?? [];
182
+ record = item;
183
+ }
184
+ }
185
+ else if (field.type === 'object') {
186
+ scope = field.fields ?? [];
187
+ record = isPlainRecord(node) ? node : undefined;
188
+ }
189
+ else {
190
+ return undefined;
191
+ }
192
+ }
193
+ return out;
194
+ }
195
+ /**
196
+ * The keys of the list items on `canopyPath` in `value`, outermost first: what a new field thread
197
+ * stores to name them. Undefined when an item on the path has no usable key or the path isn't
198
+ * there.
199
+ */
200
+ export function itemKeysOnPath(fields, value, canopyPath) {
201
+ const keys = [];
202
+ const walked = walkPath(fields, value, canopyPath, (index, items) => {
203
+ const item = items[index];
204
+ const key = isPlainRecord(item) ? item[ITEM_KEY] : undefined;
205
+ if (!isItemKey(key))
206
+ return undefined;
207
+ keys.push(key);
208
+ return index;
209
+ });
210
+ return walked ? keys : undefined;
211
+ }
212
+ /**
213
+ * Where a field thread made at `canopyPath` on the items named by `itemKeys` is in `value` now:
214
+ * its path with each index replaced by that item's current one, or `null` when one of the items
215
+ * is gone. A path with no keys (one through no list) is returned as it is.
216
+ */
217
+ export function resolveThreadPath(fields, value, canopyPath, itemKeys) {
218
+ if (!itemKeys || itemKeys.length === 0)
219
+ return canopyPath;
220
+ let missing = false;
221
+ const walked = walkPath(fields, value, canopyPath, (_index, items, depth) => {
222
+ const key = itemKeys[depth];
223
+ const at = items.findIndex((item) => isPlainRecord(item) && item[ITEM_KEY] === key);
224
+ if (key === undefined || at === -1) {
225
+ missing = true;
226
+ return undefined;
227
+ }
228
+ return at;
229
+ });
230
+ // A walk that can't reach an item, its enclosing object cleared or its block's template gone,
231
+ // has lost it just as surely as a removal.
232
+ if (missing || !walked)
233
+ return null;
234
+ return formatCanopyPath(walked);
235
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The run-time check that the editor bundle and its server agree on `mode` (see mode-env.ts).
3
+ * Without it, a dev bundle against a prod server fails only as a sign-in that never succeeds. The
4
+ * generated client sends its mode in `EDITOR_MODE_HEADER`, and the request handler refuses a
5
+ * mismatch with `EDITOR_MODE_MISMATCH_STATUS` before auth, naming only the editor's value (with
6
+ * two modes, that still tells the editor the server's). A request without the header is not
7
+ * checked; only the editor's client sends it. Dependency-free: it reaches the browser bundle.
8
+ */
9
+ import type { OperatingMode } from './types.js';
10
+ export declare const EDITOR_MODE_HEADER = "x-canopy-editor-mode";
11
+ /** Not 409, which the editor reads as a save conflict to reload past. */
12
+ export declare const EDITOR_MODE_MISMATCH_STATUS = 412;
13
+ /** The header's value, or undefined for an absent or unrecognized one, which is not checked. */
14
+ export declare function parseEditorModeHeader(value: string | null): OperatingMode | undefined;
15
+ export declare function editorModeMismatchMessage(editorMode: OperatingMode): string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The run-time check that the editor bundle and its server agree on `mode` (see mode-env.ts).
3
+ * Without it, a dev bundle against a prod server fails only as a sign-in that never succeeds. The
4
+ * generated client sends its mode in `EDITOR_MODE_HEADER`, and the request handler refuses a
5
+ * mismatch with `EDITOR_MODE_MISMATCH_STATUS` before auth, naming only the editor's value (with
6
+ * two modes, that still tells the editor the server's). A request without the header is not
7
+ * checked; only the editor's client sends it. Dependency-free: it reaches the browser bundle.
8
+ */
9
+ export const EDITOR_MODE_HEADER = 'x-canopy-editor-mode';
10
+ /** Not 409, which the editor reads as a save conflict to reload past. */
11
+ export const EDITOR_MODE_MISMATCH_STATUS = 412;
12
+ function otherOperatingMode(mode) {
13
+ return mode === 'prod' ? 'dev' : 'prod';
14
+ }
15
+ /** The header's value, or undefined for an absent or unrecognized one, which is not checked. */
16
+ export function parseEditorModeHeader(value) {
17
+ return value === 'prod' || value === 'dev' ? value : undefined;
18
+ }
19
+ export function editorModeMismatchMessage(editorMode) {
20
+ const serverMode = otherOperatingMode(editorMode);
21
+ return (`This editor was built for "${editorMode}" mode, but the CMS server runs in "${serverMode}" ` +
22
+ `mode, so signing in cannot work. Whoever deploys this site needs to rebuild the editor with ` +
23
+ `NEXT_PUBLIC_CANOPY_MODE=${serverMode} set at build time. Reloading this page will not help.`);
24
+ }
@@ -8,24 +8,23 @@
8
8
  * - `next dev` and `next build` are both `dev`. Build-time reads come from
9
9
  * the working tree in either mode (`readsFromCheckout` in build-mode.ts),
10
10
  * while prod would hold the image builder to checks it has no reason to
11
- * meet: `gitBotAuthorName`/`gitBotAuthorEmail` (the prod strategy's
12
- * `validateConfig`) and a credential-verifying auth plugin
13
- * (`assertAuthPluginAllowedForMode`). See Dockerfile.cms.template.
11
+ * meet: the prod strategy's `validateConfig` (`gitBotAuthorName`, `gitBotAuthorEmail`)
12
+ * and `assertAuthPluginAllowedForMode`. See Dockerfile.cms.template.
14
13
  * - The Lambda is `prod`: dev resolves the workspace to `<cwd>/.canopy-dev`,
15
- * and Lambda's filesystem is read-only outside /tmp, so the first write
16
- * fails with EROFS.
14
+ * and Lambda's filesystem is read-only outside /tmp (EROFS).
17
15
  *
18
16
  * Two variable names, on purpose. Server code reads `CANOPY_MODE`, stamped on
19
- * the Lambda by `CanopyCmsService` and deliberately NOT set during
20
- * `next build`. Browser code has no runtime environment — the editor page
21
- * imports the config directly (`config.client()`), so its `mode` is whatever
22
- * was inlined at build time, and Next inlines only `NEXT_PUBLIC_*`. Both names
23
- * MUST appear as literal `process.env.X` member expressions here or the
24
- * bundler cannot substitute them.
17
+ * the Lambda by `CanopyCmsService` and NOT set during `next build`. The editor
18
+ * page imports the config directly, so the browser's `mode` is inlined at
19
+ * build, and Next inlines only `NEXT_PUBLIC_*`. Both names MUST appear as
20
+ * literal `process.env.X` member expressions here or the bundler cannot
21
+ * substitute them. The two MUST agree at run time: editor-mode-check.ts refuses
22
+ * editor requests where they do not. A prerendered `/edit` resolves the
23
+ * build's mode on the server, which is harmless: NextCanopyEditorPage's
24
+ * `<Suspense>` makes that prerender bail out to client rendering.
25
25
  *
26
- * An unrecognized value throws rather than falling back: falling back would
27
- * turn a typo (`CANOPY_MODE=production`) into a silent dev-mode deployment
28
- * running header-trusting dev auth semantics.
26
+ * An unrecognized value throws rather than falling back: a typo
27
+ * (`CANOPY_MODE=production`) would otherwise deploy dev auth semantics silently.
29
28
  */
30
29
  import type { OperatingMode } from './types.js';
31
30
  /**
@@ -8,24 +8,23 @@
8
8
  * - `next dev` and `next build` are both `dev`. Build-time reads come from
9
9
  * the working tree in either mode (`readsFromCheckout` in build-mode.ts),
10
10
  * while prod would hold the image builder to checks it has no reason to
11
- * meet: `gitBotAuthorName`/`gitBotAuthorEmail` (the prod strategy's
12
- * `validateConfig`) and a credential-verifying auth plugin
13
- * (`assertAuthPluginAllowedForMode`). See Dockerfile.cms.template.
11
+ * meet: the prod strategy's `validateConfig` (`gitBotAuthorName`, `gitBotAuthorEmail`)
12
+ * and `assertAuthPluginAllowedForMode`. See Dockerfile.cms.template.
14
13
  * - The Lambda is `prod`: dev resolves the workspace to `<cwd>/.canopy-dev`,
15
- * and Lambda's filesystem is read-only outside /tmp, so the first write
16
- * fails with EROFS.
14
+ * and Lambda's filesystem is read-only outside /tmp (EROFS).
17
15
  *
18
16
  * Two variable names, on purpose. Server code reads `CANOPY_MODE`, stamped on
19
- * the Lambda by `CanopyCmsService` and deliberately NOT set during
20
- * `next build`. Browser code has no runtime environment — the editor page
21
- * imports the config directly (`config.client()`), so its `mode` is whatever
22
- * was inlined at build time, and Next inlines only `NEXT_PUBLIC_*`. Both names
23
- * MUST appear as literal `process.env.X` member expressions here or the
24
- * bundler cannot substitute them.
17
+ * the Lambda by `CanopyCmsService` and NOT set during `next build`. The editor
18
+ * page imports the config directly, so the browser's `mode` is inlined at
19
+ * build, and Next inlines only `NEXT_PUBLIC_*`. Both names MUST appear as
20
+ * literal `process.env.X` member expressions here or the bundler cannot
21
+ * substitute them. The two MUST agree at run time: editor-mode-check.ts refuses
22
+ * editor requests where they do not. A prerendered `/edit` resolves the
23
+ * build's mode on the server, which is harmless: NextCanopyEditorPage's
24
+ * `<Suspense>` makes that prerender bail out to client rendering.
25
25
  *
26
- * An unrecognized value throws rather than falling back: falling back would
27
- * turn a typo (`CANOPY_MODE=production`) into a silent dev-mode deployment
28
- * running header-trusting dev auth semantics.
26
+ * An unrecognized value throws rather than falling back: a typo
27
+ * (`CANOPY_MODE=production`) would otherwise deploy dev auth semantics silently.
29
28
  */
30
29
  import { canopyLogWarn } from '../utils/logger.js';
31
30
  const SERVER_MODE_ENV_VAR = 'CANOPY_MODE';
@@ -2,7 +2,7 @@
2
2
  import type { OperatingMode as OM } from './index.js';
3
3
  import type { CanopyConfig } from '../config/index.js';
4
4
  export type OperatingMode = OM;
5
- /** @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md. */
5
+ /** @internal No importer; deletion candidate in safeinsights/canopycms#725. */
6
6
  export interface ResolveRemoteUrlOptions {
7
7
  mode: OperatingMode;
8
8
  remoteUrl?: string;
@@ -47,7 +47,7 @@ export interface ClientSafeStrategy {
47
47
  export interface ClientUnsafeStrategy extends ClientSafeStrategy {
48
48
  /**
49
49
  * The mode's workspace root; content-branches, settings and .cache all live
50
- * under it. prod: CANOPYCMS_WORKSPACE_ROOT ?? /mnt/efs/workspace.
50
+ * under it. prod: CANOPYCMS_WORKSPACE_ROOT ?? /mnt/efs.
51
51
  * dev: {sourceRoot ?? cwd}/.canopy-dev.
52
52
  */
53
53
  getWorkspaceRoot(sourceRoot?: string): string;
@@ -24,6 +24,5 @@ import { sanitizeBranchName } from './branch-name.js';
24
24
  export { sanitizeBranchName };
25
25
  /** Resolve a branch name to workspace paths, rejecting traversal and settings-branch names. */
26
26
  export declare function resolveBranchPath(options: BranchPathOptions): BranchPathResult;
27
- export declare function ensureBranchRoot(options: BranchPathOptions): Promise<BranchPathResult>;
28
27
  export declare function getDefaultBranchBase(mode: OperatingMode, override?: string): string;
29
28
  export declare function resolveBranchPaths(branchContext: BranchContext, mode: OperatingMode, basePathOverride?: string): BranchPathResult;
@@ -1,5 +1,4 @@
1
1
  /** Branch path resolution utilities. */
2
- import fs from 'node:fs/promises';
3
2
  import path from 'node:path';
4
3
  import { operatingStrategy } from '../operating-mode/index.js';
5
4
  import { isNodeError } from '../utils/error.js';
@@ -15,8 +14,7 @@ export function namesNoWorkspace(err) {
15
14
  return true;
16
15
  return isNodeError(err) && (err.code === 'ENAMETOOLONG' || err.code === 'ENOTDIR');
17
16
  }
18
- // Lives in ./branch-name (dependency-free); re-exported here for server-side
19
- // importers, who may safely reach this module's node:fs imports.
17
+ // Lives in ./branch-name (dependency-free); re-exported for server-side importers.
20
18
  import { sanitizeBranchName, isSettingsBranchName } from './branch-name.js';
21
19
  /** @internal Exported for tests. */
22
20
  export { sanitizeBranchName };
@@ -48,11 +46,6 @@ export function resolveBranchPath(options) {
48
46
  }
49
47
  return { branchRoot, baseRoot: normalizedBase, branchName: safeBranch };
50
48
  }
51
- export async function ensureBranchRoot(options) {
52
- const result = resolveBranchPath(options);
53
- await fs.mkdir(result.branchRoot, { recursive: true });
54
- return result;
55
- }
56
49
  export function getDefaultBranchBase(mode, override) {
57
50
  return resolveContentBranchesRoot(mode, override);
58
51
  }
@@ -7,5 +7,5 @@ export { normalizeFilesystemPath, normalizeCollectionPath, hasTraversalSequence,
7
7
  export { validateAndNormalizePath } from './normalize-server.js';
8
8
  export { validateContentPath, isValidCollectionPath, sanitizeForPath, hasEmbeddedContentId, looksLikePhysicalPath, looksLikeLogicalPath, parseLogicalPath, parsePhysicalPath, isValidContentId, parseContentId, parseBranchName, parseSlug, } from './validation.js';
9
9
  export { resolveLogicalPath } from './resolve.js';
10
- export { resolveBranchPath, ensureBranchRoot, getDefaultBranchBase, resolveBranchPaths, BranchPathError, namesNoWorkspace, type BranchPathOptions, type BranchPathResult, } from './branch.js';
10
+ export { resolveBranchPath, getDefaultBranchBase, resolveBranchPaths, BranchPathError, namesNoWorkspace, type BranchPathOptions, type BranchPathResult, } from './branch.js';
11
11
  export { sanitizeBranchName, RESERVED_SETTINGS_BRANCH_PREFIX, RESERVED_ROUTE_BRANCH_NAMES, isSettingsBranchName, } from './branch-name.js';
@@ -8,5 +8,5 @@ export { normalizeFilesystemPath, normalizeCollectionPath, hasTraversalSequence,
8
8
  export { validateAndNormalizePath } from './normalize-server.js';
9
9
  export { validateContentPath, isValidCollectionPath, sanitizeForPath, hasEmbeddedContentId, looksLikePhysicalPath, looksLikeLogicalPath, parseLogicalPath, parsePhysicalPath, isValidContentId, parseContentId, parseBranchName, parseSlug, } from './validation.js';
10
10
  export { resolveLogicalPath } from './resolve.js';
11
- export { resolveBranchPath, ensureBranchRoot, getDefaultBranchBase, resolveBranchPaths, BranchPathError, namesNoWorkspace, } from './branch.js';
11
+ export { resolveBranchPath, getDefaultBranchBase, resolveBranchPaths, BranchPathError, namesNoWorkspace, } from './branch.js';
12
12
  export { sanitizeBranchName, RESERVED_SETTINGS_BRANCH_PREFIX, RESERVED_ROUTE_BRANCH_NAMES, isSettingsBranchName, } from './branch-name.js';
@@ -186,7 +186,6 @@ export function parseSlug(slug) {
186
186
  error: 'Slug is required',
187
187
  };
188
188
  }
189
- // Check length (filesystem path safety)
190
189
  if (slug.length > 64) {
191
190
  return { ok: false, error: 'Slug too long (max 64 characters)' };
192
191
  }
@@ -202,7 +201,6 @@ export function parseSlug(slug) {
202
201
  error: 'Slug cannot be a traversal sequence',
203
202
  };
204
203
  }
205
- // Normalize to lowercase for case-insensitive matching
206
204
  const normalized = slug.toLowerCase();
207
205
  if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
208
206
  return {
@@ -0,0 +1,8 @@
1
+ /**
2
+ * What a host page needs from the preview bridge. Everything reachable from here stays free of
3
+ * CSS, `@mantine/*` and editor UI (`pnpm lint:bundle`): a page that imports it renders in the
4
+ * adopter's own styles inside the editor's preview, and ships no editor code to the public.
5
+ */
6
+ export { CANOPY_PREVIEW_ERROR, CANOPY_PREVIEW_FOCUS, CANOPY_PREVIEW_HIGHLIGHT, CANOPY_PREVIEW_MESSAGE, CANOPY_PREVIEW_READY, isTrustedEditorMessage, resolveMessageOrigin, useCanopyPreview, usePreviewAssetBaseGate, usePreviewData, usePreviewFocusEmitter, usePreviewHighlight, } from './editor/preview-bridge.js';
7
+ export type { DraftUpdateMessage, HighlightMessage, PreviewErrorMessage, PreviewFocusMessage, PreviewLoadingState, } from './editor/preview-bridge.js';
8
+ export type { CanopyPathSegment } from './editor/canopy-path.js';
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ /**
3
+ * What a host page needs from the preview bridge. Everything reachable from here stays free of
4
+ * CSS, `@mantine/*` and editor UI (`pnpm lint:bundle`): a page that imports it renders in the
5
+ * adopter's own styles inside the editor's preview, and ships no editor code to the public.
6
+ */
7
+ export { CANOPY_PREVIEW_ERROR, CANOPY_PREVIEW_FOCUS, CANOPY_PREVIEW_HIGHLIGHT, CANOPY_PREVIEW_MESSAGE, CANOPY_PREVIEW_READY, isTrustedEditorMessage, resolveMessageOrigin, useCanopyPreview, usePreviewAssetBaseGate, usePreviewData, usePreviewFocusEmitter, usePreviewHighlight, } from './editor/preview-bridge.js';
@@ -54,6 +54,7 @@ export class ReferenceResolver {
54
54
  // Only the label is read, so the candidate's own references stay unresolved.
55
55
  const doc = await this.store.read(location.collection, normalizedSlug, {
56
56
  resolveReferences: false,
57
+ allowUnavailableEntryType: true,
57
58
  });
58
59
  const label = String(doc.data[displayField] || doc.data.title || normalizedSlug);
59
60
  if (search && !label.toLowerCase().includes(search.toLowerCase())) {
@@ -3,7 +3,7 @@ import type { CanopyUser } from './user.js';
3
3
  import type { OperatingMode } from './operating-mode/index.js';
4
4
  /**
5
5
  * Test-only: reset the once-per-process "no admins configured" warning latch.
6
- * @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md.
6
+ * @internal No importer; deletion candidate in safeinsights/canopycms#725.
7
7
  */
8
8
  export declare function resetResolveCanopyUserWarningForTests(): void;
9
9
  export interface ResolveCanopyUserDeps {
@@ -17,7 +17,7 @@ import { timeRequestPhase } from './utils/request-timing.js';
17
17
  let warnedNoAdmins = false;
18
18
  /**
19
19
  * Test-only: reset the once-per-process "no admins configured" warning latch.
20
- * @internal No importer; deletion candidate in knip-no-importer-deletion-candidates.md.
20
+ * @internal No importer; deletion candidate in safeinsights/canopycms#725.
21
21
  */
22
22
  export function resetResolveCanopyUserWarningForTests() {
23
23
  warnedNoAdmins = false;
@@ -1,6 +1,6 @@
1
1
  import type { RootCollectionConfig } from '../config/index.js';
2
2
  import type { ContentId } from '../paths/types.js';
3
- import type { EntrySchemaRegistry } from './types.js';
3
+ import type { EntrySchemaRegistry, SchemaIssue, UnknownSchemaPolicy } from './types.js';
4
4
  type EntryTypeMeta = {
5
5
  name: string;
6
6
  format: 'md' | 'mdx' | 'json' | 'yaml';
@@ -38,6 +38,13 @@ export declare function loadCollectionMetaFiles(contentRoot: string): Promise<{
38
38
  contentId?: ContentId;
39
39
  }>;
40
40
  }>;
41
+ type LoadedMetaFiles = {
42
+ root: RootCollectionMeta | null;
43
+ collections: Array<CollectionMeta & {
44
+ path: string;
45
+ contentId?: ContentId;
46
+ }>;
47
+ };
41
48
  /**
42
49
  * Resolve schema references for root collection and all collections.
43
50
  *
@@ -49,12 +56,15 @@ export declare function loadCollectionMetaFiles(contentRoot: string): Promise<{
49
56
  * @returns Fully resolved root collection config ready for use by CanopyCMS
50
57
  * @throws Error if any schema reference doesn't exist in registry (with helpful suggestions)
51
58
  */
52
- export declare function resolveCollectionReferences(metaFiles: {
53
- root: RootCollectionMeta | null;
54
- collections: Array<CollectionMeta & {
55
- path: string;
56
- contentId?: ContentId;
57
- }>;
58
- }, entrySchemaRegistry: EntrySchemaRegistry): RootCollectionConfig;
59
+ export declare function resolveCollectionReferences(metaFiles: LoadedMetaFiles, entrySchemaRegistry: EntrySchemaRegistry): RootCollectionConfig;
60
+ /**
61
+ * {@link resolveCollectionReferences} under an explicit {@link UnknownSchemaPolicy}: 'degrade'
62
+ * marks an entry type naming an unregistered schema `unavailable` and reports it in `issues`
63
+ * instead of throwing, so the rest of the schema still resolves.
64
+ */
65
+ export declare function resolveCollectionMetaFiles(metaFiles: LoadedMetaFiles, entrySchemaRegistry: EntrySchemaRegistry, policy: UnknownSchemaPolicy): {
66
+ schema: RootCollectionConfig;
67
+ issues: SchemaIssue[];
68
+ };
59
69
  export declare function watchCollectionMetaFiles(contentRoot: string, onChange: () => void): () => void;
60
70
  export {};
@@ -154,12 +154,36 @@ export async function loadCollectionMetaFiles(contentRoot) {
154
154
  const collections = await scanForCollectionMeta(contentRoot);
155
155
  return { root, collections };
156
156
  }
157
- function resolveEntryTypes(entryTypes, entrySchemaRegistry, contextName) {
157
+ function resolveEntryTypes(entryTypes, entrySchemaRegistry, contextName, location, resolution) {
158
158
  return entryTypes.map((entryType) => {
159
159
  const resolvedSchema = entrySchemaRegistry[entryType.schema];
160
160
  if (!resolvedSchema) {
161
- throw new Error(`Schema reference "${entryType.schema}" in entry type "${entryType.name}" (${contextName}) not found in registry. ` +
162
- `Available schemas: ${Object.keys(entrySchemaRegistry).join(', ')}`);
161
+ const message = `Schema reference "${entryType.schema}" in entry type "${entryType.name}" (${contextName}) not found in registry.`;
162
+ if (resolution.policy === 'throw') {
163
+ throw new Error(`${message} Available schemas: ${Object.keys(entrySchemaRegistry).join(', ')}`);
164
+ }
165
+ resolution.issues.push({
166
+ kind: 'unknown-schema',
167
+ collectionPath: location.collectionPath,
168
+ entryType: entryType.name,
169
+ schemaRef: entryType.schema,
170
+ metaFile: location.metaFile,
171
+ message,
172
+ });
173
+ return {
174
+ name: entryType.name,
175
+ label: entryType.label,
176
+ format: entryType.format,
177
+ schema: [],
178
+ schemaRef: entryType.schema,
179
+ default: entryType.default,
180
+ maxItems: entryType.maxItems,
181
+ unavailable: {
182
+ reason: 'unknown-schema',
183
+ schemaRef: entryType.schema,
184
+ metaFile: location.metaFile,
185
+ },
186
+ };
163
187
  }
164
188
  // Note: "body" field name validation for md/mdx formats is handled by the
165
189
  // entry schema registry (isBody constraints). Not checked here because
@@ -175,9 +199,9 @@ function resolveEntryTypes(entryTypes, entrySchemaRegistry, contextName) {
175
199
  };
176
200
  });
177
201
  }
178
- function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections) {
202
+ function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections, resolution) {
179
203
  const entries = meta.entries && meta.entries.length > 0
180
- ? resolveEntryTypes(meta.entries, entrySchemaRegistry, `collection "${meta.name}"`)
204
+ ? resolveEntryTypes(meta.entries, entrySchemaRegistry, `collection "${meta.name}"`, { collectionPath: meta.path, metaFile: `${meta.path}/.collection.json` }, resolution)
181
205
  : undefined;
182
206
  // Find nested collections (subfolders with .collection.json)
183
207
  const nestedCollections = allCollections.filter((col) => {
@@ -185,7 +209,7 @@ function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections) {
185
209
  col.path.split('/').length === meta.path.split('/').length + 1);
186
210
  });
187
211
  const collections = nestedCollections.length > 0
188
- ? nestedCollections.map((nestedMeta) => resolveCollectionMeta(nestedMeta, entrySchemaRegistry, allCollections))
212
+ ? nestedCollections.map((nestedMeta) => resolveCollectionMeta(nestedMeta, entrySchemaRegistry, allCollections, resolution))
189
213
  : undefined;
190
214
  return {
191
215
  name: meta.name,
@@ -209,13 +233,22 @@ function resolveCollectionMeta(meta, entrySchemaRegistry, allCollections) {
209
233
  * @throws Error if any schema reference doesn't exist in registry (with helpful suggestions)
210
234
  */
211
235
  export function resolveCollectionReferences(metaFiles, entrySchemaRegistry) {
236
+ return resolveCollectionMetaFiles(metaFiles, entrySchemaRegistry, 'throw').schema;
237
+ }
238
+ /**
239
+ * {@link resolveCollectionReferences} under an explicit {@link UnknownSchemaPolicy}: 'degrade'
240
+ * marks an entry type naming an unregistered schema `unavailable` and reports it in `issues`
241
+ * instead of throwing, so the rest of the schema still resolves.
242
+ */
243
+ export function resolveCollectionMetaFiles(metaFiles, entrySchemaRegistry, policy) {
244
+ const resolution = { policy, issues: [] };
212
245
  // Build result object dynamically to avoid readonly conflicts
213
246
  const result = {};
214
247
  if (metaFiles.root?.label) {
215
248
  result.label = metaFiles.root.label;
216
249
  }
217
250
  if (metaFiles.root?.entries && metaFiles.root.entries.length > 0) {
218
- result.entries = resolveEntryTypes(metaFiles.root.entries, entrySchemaRegistry, 'root collection');
251
+ result.entries = resolveEntryTypes(metaFiles.root.entries, entrySchemaRegistry, 'root collection', { collectionPath: '', metaFile: '.collection.json' }, resolution);
219
252
  }
220
253
  if (metaFiles.root?.order) {
221
254
  result.order = metaFiles.root.order;
@@ -223,9 +256,9 @@ export function resolveCollectionReferences(metaFiles, entrySchemaRegistry) {
223
256
  // Resolve top-level collections (no slashes in path)
224
257
  const topLevelCollections = metaFiles.collections.filter((meta) => !meta.path.includes('/'));
225
258
  if (topLevelCollections.length > 0) {
226
- result.collections = topLevelCollections.map((meta) => resolveCollectionMeta(meta, entrySchemaRegistry, metaFiles.collections));
259
+ result.collections = topLevelCollections.map((meta) => resolveCollectionMeta(meta, entrySchemaRegistry, metaFiles.collections, resolution));
227
260
  }
228
- return result;
261
+ return { schema: result, issues: resolution.issues };
229
262
  }
230
263
  export function watchCollectionMetaFiles(contentRoot, onChange) {
231
264
  const watcher = chokidar.watch(`${contentRoot}/**/.collection.json`, {