canopycms 0.0.67-int.90 → 0.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (539) hide show
  1. package/README.md +30 -3
  2. package/dist/ai/generate.js +1 -27
  3. package/dist/ai/handler.d.ts +0 -4
  4. package/dist/ai/handler.js +0 -11
  5. package/dist/ai/index.d.ts +1 -8
  6. package/dist/ai/index.js +1 -8
  7. package/dist/ai/json-to-markdown.js +15 -58
  8. package/dist/ai/resolve-branch.d.ts +2 -7
  9. package/dist/ai/resolve-branch.js +2 -8
  10. package/dist/ai/strip-mdx.d.ts +5 -13
  11. package/dist/ai/strip-mdx.js +5 -17
  12. package/dist/ai/to-plain-text.d.ts +10 -28
  13. package/dist/ai/to-plain-text.js +10 -28
  14. package/dist/ai/transform-components.d.ts +2 -4
  15. package/dist/ai/transform-components.js +8 -19
  16. package/dist/ai/types.d.ts +5 -10
  17. package/dist/api/admin-branch-health.d.ts +4 -12
  18. package/dist/api/admin-branch-health.js +26 -66
  19. package/dist/api/admin.d.ts +4 -12
  20. package/dist/api/admin.js +10 -26
  21. package/dist/api/assets.d.ts +0 -25
  22. package/dist/api/assets.js +50 -91
  23. package/dist/api/branch-merge.d.ts +1 -1
  24. package/dist/api/branch-merge.js +0 -2
  25. package/dist/api/branch-review.d.ts +0 -8
  26. package/dist/api/branch-review.js +0 -13
  27. package/dist/api/branch-status.d.ts +0 -3
  28. package/dist/api/branch-status.js +8 -33
  29. package/dist/api/branch-withdraw.d.ts +0 -1
  30. package/dist/api/branch-withdraw.js +6 -9
  31. package/dist/api/branch.d.ts +7 -12
  32. package/dist/api/branch.js +7 -44
  33. package/dist/api/client.d.ts +71 -224
  34. package/dist/api/client.js +82 -233
  35. package/dist/api/comments.d.ts +2 -4
  36. package/dist/api/comments.js +0 -17
  37. package/dist/api/content.d.ts +0 -6
  38. package/dist/api/content.js +66 -142
  39. package/dist/api/entries-constants.d.ts +5 -9
  40. package/dist/api/entries-constants.js +5 -9
  41. package/dist/api/entries.d.ts +8 -13
  42. package/dist/api/entries.js +20 -51
  43. package/dist/api/github-sync.d.ts +2 -4
  44. package/dist/api/github-sync.js +4 -8
  45. package/dist/api/groups.d.ts +3 -0
  46. package/dist/api/groups.js +8 -21
  47. package/dist/api/guards.d.ts +4 -16
  48. package/dist/api/guards.js +3 -22
  49. package/dist/api/index.d.ts +4 -4
  50. package/dist/api/permissions.d.ts +2 -0
  51. package/dist/api/permissions.js +18 -40
  52. package/dist/api/reference-options.d.ts +0 -1
  53. package/dist/api/reference-options.js +3 -11
  54. package/dist/api/request-body-hash.d.ts +12 -23
  55. package/dist/api/request-body-hash.js +12 -23
  56. package/dist/api/resolve-references.d.ts +0 -1
  57. package/dist/api/resolve-references.js +13 -28
  58. package/dist/api/route-builder.d.ts +3 -7
  59. package/dist/api/route-builder.js +1 -1
  60. package/dist/api/routes.d.ts +12 -0
  61. package/dist/api/routes.js +47 -0
  62. package/dist/api/schema.d.ts +23 -33
  63. package/dist/api/schema.js +20 -74
  64. package/dist/api/settings-helpers.js +4 -5
  65. package/dist/api/types.d.ts +0 -5
  66. package/dist/api/user.js +0 -5
  67. package/dist/api/validators.d.ts +14 -52
  68. package/dist/api/validators.js +14 -52
  69. package/dist/assets/asset-prefixes.d.ts +4 -8
  70. package/dist/assets/asset-prefixes.js +4 -8
  71. package/dist/assets/asset-src.d.ts +5 -22
  72. package/dist/assets/asset-src.js +5 -21
  73. package/dist/assets/factory.d.ts +1 -2
  74. package/dist/assets/factory.js +1 -2
  75. package/dist/assets/finalize.d.ts +3 -1
  76. package/dist/assets/finalize.js +3 -1
  77. package/dist/assets/index.d.ts +3 -3
  78. package/dist/assets/index.js +1 -1
  79. package/dist/assets/keys.d.ts +5 -3
  80. package/dist/assets/keys.js +6 -3
  81. package/dist/assets/pipeline.d.ts +3 -2
  82. package/dist/assets/pipeline.js +22 -56
  83. package/dist/assets/sharp-loader.d.ts +2 -10
  84. package/dist/assets/sharp-loader.js +2 -10
  85. package/dist/assets/store-local.d.ts +1 -2
  86. package/dist/assets/store-local.js +1 -2
  87. package/dist/assets/store-s3.d.ts +3 -4
  88. package/dist/assets/svg-sanitizer.d.ts +6 -14
  89. package/dist/assets/svg-sanitizer.js +6 -14
  90. package/dist/assets/transform-directives.d.ts +3 -4
  91. package/dist/assets/transform-directives.js +1 -1
  92. package/dist/assets/transform.d.ts +19 -30
  93. package/dist/assets/transform.js +18 -31
  94. package/dist/auth/cache.d.ts +2 -3
  95. package/dist/auth/cache.js +2 -3
  96. package/dist/auth/caching-auth-plugin.d.ts +11 -22
  97. package/dist/auth/caching-auth-plugin.js +12 -14
  98. package/dist/auth/context-helpers.d.ts +6 -20
  99. package/dist/auth/context-helpers.js +5 -17
  100. package/dist/auth/file-based-auth-cache.d.ts +10 -21
  101. package/dist/auth/file-based-auth-cache.js +23 -51
  102. package/dist/auth/plugin.d.ts +29 -61
  103. package/dist/auth/plugin.js +9 -13
  104. package/dist/auth/types.d.ts +11 -20
  105. package/dist/authorization/branch.d.ts +30 -49
  106. package/dist/authorization/branch.js +16 -42
  107. package/dist/authorization/content.d.ts +11 -40
  108. package/dist/authorization/content.js +13 -45
  109. package/dist/authorization/groups/index.d.ts +0 -3
  110. package/dist/authorization/groups/index.js +0 -3
  111. package/dist/authorization/groups/loader.d.ts +14 -28
  112. package/dist/authorization/groups/loader.js +14 -38
  113. package/dist/authorization/groups/schema.d.ts +0 -6
  114. package/dist/authorization/groups/schema.js +4 -7
  115. package/dist/authorization/helpers.d.ts +9 -28
  116. package/dist/authorization/helpers.js +9 -28
  117. package/dist/authorization/index.d.ts +3 -25
  118. package/dist/authorization/index.js +3 -35
  119. package/dist/authorization/path.d.ts +6 -13
  120. package/dist/authorization/path.js +8 -25
  121. package/dist/authorization/permissions/index.d.ts +0 -3
  122. package/dist/authorization/permissions/index.js +0 -3
  123. package/dist/authorization/permissions/loader.d.ts +14 -27
  124. package/dist/authorization/permissions/loader.js +14 -32
  125. package/dist/authorization/permissions/schema.d.ts +1 -6
  126. package/dist/authorization/permissions/schema.js +6 -13
  127. package/dist/authorization/protected-branch.d.ts +36 -65
  128. package/dist/authorization/protected-branch.js +29 -41
  129. package/dist/authorization/settings-file-store.d.ts +38 -81
  130. package/dist/authorization/settings-file-store.js +38 -79
  131. package/dist/authorization/types.d.ts +4 -26
  132. package/dist/authorization/types.js +0 -6
  133. package/dist/authorization/validation.d.ts +1 -23
  134. package/dist/authorization/validation.js +1 -24
  135. package/dist/branch-health.d.ts +39 -67
  136. package/dist/branch-health.js +27 -43
  137. package/dist/branch-metadata-file.d.ts +16 -32
  138. package/dist/branch-metadata-file.js +13 -26
  139. package/dist/branch-metadata.d.ts +49 -80
  140. package/dist/branch-metadata.js +57 -87
  141. package/dist/branch-registry.d.ts +26 -64
  142. package/dist/branch-registry.js +44 -93
  143. package/dist/branch-schema-cache.d.ts +34 -124
  144. package/dist/branch-schema-cache.js +49 -155
  145. package/dist/branch-workspace.d.ts +4 -4
  146. package/dist/branch-workspace.js +15 -19
  147. package/dist/build/generate-ai-content.d.ts +1 -0
  148. package/dist/build/generate-ai-content.js +12 -25
  149. package/dist/build-canopy.d.ts +17 -27
  150. package/dist/build-canopy.js +16 -23
  151. package/dist/build-mode.d.ts +25 -27
  152. package/dist/build-mode.js +25 -29
  153. package/dist/cli/cli.d.ts +15 -26
  154. package/dist/cli/cli.js +601 -978
  155. package/dist/cli/generate-ai-content.js +351 -628
  156. package/dist/cli/github-app-manifest.d.ts +84 -0
  157. package/dist/cli/github-app-manifest.js +161 -0
  158. package/dist/cli/init-github-app.d.ts +110 -444
  159. package/dist/cli/init-github-app.js +236 -773
  160. package/dist/cli/init.js +39 -80
  161. package/dist/cli/migrate.d.ts +13 -10
  162. package/dist/cli/migrate.js +22 -30
  163. package/dist/cli/project-detect.d.ts +17 -31
  164. package/dist/cli/project-detect.js +31 -42
  165. package/dist/cli/project-root.d.ts +4 -11
  166. package/dist/cli/project-root.js +4 -11
  167. package/dist/cli/prompt.d.ts +10 -0
  168. package/dist/cli/prompt.js +67 -0
  169. package/dist/cli/sync.d.ts +0 -8
  170. package/dist/cli/sync.js +8 -28
  171. package/dist/cli/template-files/middleware.ts.template +15 -29
  172. package/dist/cli/templates.d.ts +2 -12
  173. package/dist/cli/templates.js +4 -4
  174. package/dist/client.d.ts +1 -1
  175. package/dist/comment-store.d.ts +32 -53
  176. package/dist/comment-store.js +32 -52
  177. package/dist/config/flatten.d.ts +0 -3
  178. package/dist/config/flatten.js +2 -12
  179. package/dist/config/helpers.js +2 -2
  180. package/dist/config/index.d.ts +2 -2
  181. package/dist/config/index.js +1 -4
  182. package/dist/config/schemas/collection.d.ts +0 -8
  183. package/dist/config/schemas/collection.js +0 -10
  184. package/dist/config/schemas/config.d.ts +6 -78
  185. package/dist/config/schemas/config.js +38 -54
  186. package/dist/config/schemas/field.d.ts +2 -242
  187. package/dist/config/schemas/field.js +9 -20
  188. package/dist/config/schemas/media.js +1 -1
  189. package/dist/config/schemas/permissions.js +0 -2
  190. package/dist/config/schemas/url.d.ts +5 -6
  191. package/dist/config/schemas/url.js +5 -6
  192. package/dist/config/types.d.ts +45 -33
  193. package/dist/config/types.js +0 -1
  194. package/dist/config.d.ts +1 -8
  195. package/dist/config.js +1 -9
  196. package/dist/content-id-index.d.ts +76 -188
  197. package/dist/content-id-index.js +79 -230
  198. package/dist/content-index-generation.d.ts +27 -48
  199. package/dist/content-index-generation.js +35 -84
  200. package/dist/content-index-registry.d.ts +15 -24
  201. package/dist/content-index-registry.js +5 -9
  202. package/dist/content-listing.d.ts +64 -107
  203. package/dist/content-listing.js +68 -118
  204. package/dist/content-reader.d.ts +20 -29
  205. package/dist/content-reader.js +10 -18
  206. package/dist/content-store.d.ts +210 -336
  207. package/dist/content-store.js +413 -657
  208. package/dist/content-tree.d.ts +44 -86
  209. package/dist/content-tree.js +26 -54
  210. package/dist/context.d.ts +67 -94
  211. package/dist/context.js +53 -72
  212. package/dist/dev-content-watcher.d.ts +18 -18
  213. package/dist/dev-content-watcher.js +41 -44
  214. package/dist/editor/BranchManager.d.ts +3 -6
  215. package/dist/editor/BranchManager.js +24 -44
  216. package/dist/editor/CanopyEditor.js +5 -2
  217. package/dist/editor/CommentsPanel.js +0 -2
  218. package/dist/editor/Editor.js +19 -76
  219. package/dist/editor/EditorAuthGate.d.ts +27 -0
  220. package/dist/editor/EditorAuthGate.js +140 -0
  221. package/dist/editor/EntryNavigator.js +0 -20
  222. package/dist/editor/FormRenderer.d.ts +1 -2
  223. package/dist/editor/FormRenderer.js +8 -23
  224. package/dist/editor/admin/SystemHealthPanel.js +20 -37
  225. package/dist/editor/admin/useSystemHealth.d.ts +2 -3
  226. package/dist/editor/admin/useSystemHealth.js +10 -12
  227. package/dist/editor/client-reference-resolver.d.ts +2 -5
  228. package/dist/editor/client-reference-resolver.js +2 -19
  229. package/dist/editor/comments/BranchComments.js +0 -4
  230. package/dist/editor/comments/EntryComments.js +0 -4
  231. package/dist/editor/comments/FieldWrapper.js +0 -4
  232. package/dist/editor/comments/InlineCommentThread.js +0 -2
  233. package/dist/editor/comments/ThreadCarousel.d.ts +0 -58
  234. package/dist/editor/comments/ThreadCarousel.js +0 -12
  235. package/dist/editor/components/EditorFooter.d.ts +0 -8
  236. package/dist/editor/components/EditorFooter.js +0 -5
  237. package/dist/editor/components/EditorHeader.d.ts +0 -31
  238. package/dist/editor/components/EditorHeader.js +21 -71
  239. package/dist/editor/components/EditorSidebar.d.ts +0 -19
  240. package/dist/editor/components/EditorSidebar.js +0 -16
  241. package/dist/editor/components/EntryCreateModal.d.ts +4 -4
  242. package/dist/editor/components/EntryCreateModal.js +7 -22
  243. package/dist/editor/components/RenameEntryModal.js +0 -4
  244. package/dist/editor/components/UserBadge.js +0 -10
  245. package/dist/editor/components/index.js +0 -2
  246. package/dist/editor/context/ApiClientContext.d.ts +8 -7
  247. package/dist/editor/context/ApiClientContext.js +39 -11
  248. package/dist/editor/context/AssetContext.d.ts +7 -17
  249. package/dist/editor/context/AssetContext.js +7 -17
  250. package/dist/editor/context/EditorIdentityContext.d.ts +13 -0
  251. package/dist/editor/context/EditorIdentityContext.js +7 -0
  252. package/dist/editor/context/EditorStateContext.d.ts +10 -41
  253. package/dist/editor/context/EditorStateContext.js +7 -23
  254. package/dist/editor/context/SWRProvider.d.ts +3 -6
  255. package/dist/editor/context/index.d.ts +1 -20
  256. package/dist/editor/context/index.js +1 -20
  257. package/dist/editor/editor-utils.d.ts +8 -47
  258. package/dist/editor/editor-utils.js +19 -72
  259. package/dist/editor/fields/BlockField.d.ts +2 -2
  260. package/dist/editor/fields/BlockField.js +1 -2
  261. package/dist/editor/fields/CodeField.d.ts +0 -1
  262. package/dist/editor/fields/CodeField.js +0 -1
  263. package/dist/editor/fields/DateTimeField.d.ts +15 -22
  264. package/dist/editor/fields/DateTimeField.js +17 -26
  265. package/dist/editor/fields/ImageField.d.ts +2 -2
  266. package/dist/editor/fields/ImageField.js +8 -14
  267. package/dist/editor/fields/InlineGroupField.d.ts +0 -1
  268. package/dist/editor/fields/InlineGroupField.js +0 -1
  269. package/dist/editor/fields/MarkdownField.d.ts +0 -1
  270. package/dist/editor/fields/MarkdownField.js +6 -11
  271. package/dist/editor/fields/MdxImageDialog.d.ts +1 -1
  272. package/dist/editor/fields/MdxImageDialog.js +0 -1
  273. package/dist/editor/fields/NumberField.d.ts +9 -19
  274. package/dist/editor/fields/NumberField.js +11 -22
  275. package/dist/editor/fields/NumberListField.d.ts +7 -10
  276. package/dist/editor/fields/NumberListField.js +7 -10
  277. package/dist/editor/fields/ObjectField.d.ts +5 -8
  278. package/dist/editor/fields/ObjectField.js +0 -1
  279. package/dist/editor/fields/ReferenceField.d.ts +1 -1
  280. package/dist/editor/fields/ReferenceField.js +11 -16
  281. package/dist/editor/fields/SelectField.d.ts +2 -2
  282. package/dist/editor/fields/SelectField.js +0 -1
  283. package/dist/editor/fields/StringListField.d.ts +0 -4
  284. package/dist/editor/fields/StringListField.js +4 -9
  285. package/dist/editor/fields/TextField.d.ts +0 -1
  286. package/dist/editor/fields/TextField.js +0 -1
  287. package/dist/editor/fields/ToggleField.d.ts +0 -1
  288. package/dist/editor/fields/ToggleField.js +0 -1
  289. package/dist/editor/fields/entry-link/EntryLinkContext.js +2 -4
  290. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -3
  291. package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -4
  292. package/dist/editor/group-manager/ExternalGroupsTab.d.ts +0 -3
  293. package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
  294. package/dist/editor/group-manager/GroupCard.d.ts +0 -3
  295. package/dist/editor/group-manager/GroupForm.d.ts +0 -3
  296. package/dist/editor/group-manager/InternalGroupsTab.d.ts +0 -3
  297. package/dist/editor/group-manager/InternalGroupsTab.js +0 -2
  298. package/dist/editor/group-manager/MemberList.d.ts +0 -3
  299. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +0 -3
  300. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -3
  301. package/dist/editor/group-manager/hooks/useGroupState.d.ts +0 -3
  302. package/dist/editor/group-manager/hooks/useGroupState.js +0 -5
  303. package/dist/editor/group-manager/hooks/useUserSearch.d.ts +0 -3
  304. package/dist/editor/group-manager/hooks/useUserSearch.js +0 -3
  305. package/dist/editor/group-manager/index.d.ts +0 -6
  306. package/dist/editor/group-manager/index.js +0 -10
  307. package/dist/editor/group-manager/types.d.ts +2 -5
  308. package/dist/editor/group-manager/types.js +0 -3
  309. package/dist/editor/hooks/index.d.ts +6 -11
  310. package/dist/editor/hooks/index.js +6 -12
  311. package/dist/editor/hooks/useBranchActions.d.ts +0 -14
  312. package/dist/editor/hooks/useBranchActions.js +0 -22
  313. package/dist/editor/hooks/useBranchManager.d.ts +2 -48
  314. package/dist/editor/hooks/useBranchManager.js +4 -64
  315. package/dist/editor/hooks/useBranchesData.d.ts +7 -6
  316. package/dist/editor/hooks/useBranchesData.js +7 -6
  317. package/dist/editor/hooks/useCommentSystem.d.ts +0 -49
  318. package/dist/editor/hooks/useCommentSystem.js +1 -36
  319. package/dist/editor/hooks/useDraftManager.d.ts +2 -35
  320. package/dist/editor/hooks/useDraftManager.js +23 -64
  321. package/dist/editor/hooks/useEditorLayout.d.ts +0 -20
  322. package/dist/editor/hooks/useEditorLayout.js +0 -23
  323. package/dist/editor/hooks/useEntriesData.d.ts +1 -0
  324. package/dist/editor/hooks/useEntriesData.js +2 -3
  325. package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -2
  326. package/dist/editor/hooks/useEntryLinkResolution.js +2 -2
  327. package/dist/editor/hooks/useEntryManager.d.ts +2 -27
  328. package/dist/editor/hooks/useEntryManager.js +29 -78
  329. package/dist/editor/hooks/useGroupManager.d.ts +0 -21
  330. package/dist/editor/hooks/useGroupManager.js +0 -21
  331. package/dist/editor/hooks/usePermissionManager.d.ts +0 -20
  332. package/dist/editor/hooks/usePermissionManager.js +0 -20
  333. package/dist/editor/hooks/useReferenceResolution.d.ts +2 -33
  334. package/dist/editor/hooks/useReferenceResolution.js +1 -48
  335. package/dist/editor/hooks/useSchemaManager.d.ts +8 -27
  336. package/dist/editor/hooks/useSchemaManager.js +0 -19
  337. package/dist/editor/hooks/useUserContext.d.ts +2 -9
  338. package/dist/editor/hooks/useUserContext.js +10 -10
  339. package/dist/editor/hooks/useUserMetadata.d.ts +0 -2
  340. package/dist/editor/hooks/useUserMetadata.js +0 -3
  341. package/dist/editor/media/AssetCard.d.ts +0 -1
  342. package/dist/editor/media/AssetCard.js +1 -2
  343. package/dist/editor/media/CropStep.d.ts +0 -1
  344. package/dist/editor/media/CropStep.js +0 -1
  345. package/dist/editor/media/MediaLibrary.d.ts +1 -2
  346. package/dist/editor/media/MediaLibrary.js +1 -2
  347. package/dist/editor/media/MediaLibraryBody.d.ts +0 -1
  348. package/dist/editor/media/MediaLibraryBody.js +0 -1
  349. package/dist/editor/media/crop-math.d.ts +1 -1
  350. package/dist/editor/media/crop-math.js +1 -1
  351. package/dist/editor/permission-manager/GroupSelector.d.ts +0 -3
  352. package/dist/editor/permission-manager/PermissionEditor.d.ts +0 -4
  353. package/dist/editor/permission-manager/PermissionEditor.js +0 -1
  354. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +0 -7
  355. package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -4
  356. package/dist/editor/permission-manager/PermissionTree.d.ts +0 -4
  357. package/dist/editor/permission-manager/UserSelector.d.ts +0 -3
  358. package/dist/editor/permission-manager/constants.d.ts +0 -3
  359. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +0 -3
  360. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -10
  361. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +0 -14
  362. package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -11
  363. package/dist/editor/permission-manager/index.d.ts +0 -7
  364. package/dist/editor/permission-manager/index.js +0 -16
  365. package/dist/editor/permission-manager/types.d.ts +2 -12
  366. package/dist/editor/permission-manager/types.js +0 -3
  367. package/dist/editor/permission-manager/utils.d.ts +0 -28
  368. package/dist/editor/permission-manager/utils.js +9 -23
  369. package/dist/editor/preview-bridge.d.ts +5 -1
  370. package/dist/editor/preview-bridge.js +4 -4
  371. package/dist/editor/schema-editor/CollectionEditor.d.ts +0 -5
  372. package/dist/editor/schema-editor/CollectionEditor.js +9 -31
  373. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +0 -6
  374. package/dist/editor/schema-editor/EntryTypeEditor.js +3 -24
  375. package/dist/editor/schema-editor/index.d.ts +0 -7
  376. package/dist/editor/schema-editor/index.js +0 -7
  377. package/dist/editor/utils/env.d.ts +3 -18
  378. package/dist/editor/utils/env.js +6 -25
  379. package/dist/entry-link-resolver.d.ts +13 -35
  380. package/dist/entry-link-resolver.js +20 -53
  381. package/dist/entry-schema-registry.d.ts +20 -60
  382. package/dist/entry-schema-registry.js +20 -69
  383. package/dist/entry-schema.d.ts +118 -223
  384. package/dist/entry-schema.js +46 -91
  385. package/dist/git-manager.d.ts +101 -200
  386. package/dist/git-manager.js +211 -384
  387. package/dist/github-service.d.ts +34 -75
  388. package/dist/github-service.js +37 -91
  389. package/dist/http/handler.d.ts +6 -37
  390. package/dist/http/handler.js +65 -120
  391. package/dist/http/router.d.ts +15 -32
  392. package/dist/http/router.js +34 -99
  393. package/dist/http/types.d.ts +15 -40
  394. package/dist/http/types.js +3 -7
  395. package/dist/id.d.ts +4 -10
  396. package/dist/id.js +4 -10
  397. package/dist/index.js +6 -9
  398. package/dist/operating-mode/client-safe-strategy.d.ts +7 -14
  399. package/dist/operating-mode/client-safe-strategy.js +8 -28
  400. package/dist/operating-mode/client-unsafe-strategy.d.ts +6 -16
  401. package/dist/operating-mode/client-unsafe-strategy.js +9 -34
  402. package/dist/operating-mode/client.d.ts +3 -10
  403. package/dist/operating-mode/client.js +3 -8
  404. package/dist/operating-mode/deployment-name-fixtures.d.ts +14 -18
  405. package/dist/operating-mode/deployment-name-fixtures.js +14 -18
  406. package/dist/operating-mode/deployment-name.d.ts +19 -29
  407. package/dist/operating-mode/deployment-name.js +29 -47
  408. package/dist/operating-mode/index.d.ts +4 -25
  409. package/dist/operating-mode/index.js +9 -31
  410. package/dist/operating-mode/mode-env.d.ts +32 -54
  411. package/dist/operating-mode/mode-env.js +36 -58
  412. package/dist/operating-mode/types.d.ts +24 -72
  413. package/dist/operating-mode/types.js +1 -7
  414. package/dist/paths/branch-name.d.ts +30 -40
  415. package/dist/paths/branch-name.js +30 -40
  416. package/dist/paths/branch.d.ts +4 -18
  417. package/dist/paths/branch.js +6 -22
  418. package/dist/paths/index.d.ts +2 -13
  419. package/dist/paths/index.js +3 -23
  420. package/dist/paths/normalize-server.d.ts +3 -15
  421. package/dist/paths/normalize-server.js +3 -15
  422. package/dist/paths/normalize.d.ts +13 -33
  423. package/dist/paths/normalize.js +13 -33
  424. package/dist/paths/resolve.d.ts +4 -17
  425. package/dist/paths/resolve.js +4 -22
  426. package/dist/paths/types.d.ts +12 -34
  427. package/dist/paths/types.js +5 -7
  428. package/dist/paths/validation.d.ts +22 -119
  429. package/dist/paths/validation.js +30 -148
  430. package/dist/reference-resolver.d.ts +0 -13
  431. package/dist/reference-resolver.js +0 -18
  432. package/dist/resolve-canopy-user.d.ts +16 -18
  433. package/dist/resolve-canopy-user.js +17 -26
  434. package/dist/resource-generation.d.ts +16 -25
  435. package/dist/resource-generation.js +34 -97
  436. package/dist/schema/meta-loader.d.ts +2 -14
  437. package/dist/schema/meta-loader.js +15 -64
  438. package/dist/schema/resolver.d.ts +1 -4
  439. package/dist/schema/resolver.js +1 -6
  440. package/dist/schema/schema-store-types.d.ts +0 -12
  441. package/dist/schema/schema-store.d.ts +61 -138
  442. package/dist/schema/schema-store.js +85 -282
  443. package/dist/schema/types.d.ts +0 -4
  444. package/dist/server.d.ts +62 -93
  445. package/dist/server.js +63 -94
  446. package/dist/services.d.ts +23 -47
  447. package/dist/services.js +55 -98
  448. package/dist/settings-workspace.d.ts +17 -30
  449. package/dist/settings-workspace.js +51 -81
  450. package/dist/static/index.d.ts +26 -52
  451. package/dist/static/index.js +33 -67
  452. package/dist/{worker/task-queue.d.ts → task-queue/cms-task-queue.d.ts} +7 -9
  453. package/dist/task-queue/cms-task-queue.js +13 -0
  454. package/dist/task-queue/task-queue-config.d.ts +3 -0
  455. package/dist/{worker → task-queue}/task-queue-config.js +1 -6
  456. package/dist/task-queue/task-queue.d.ts +16 -22
  457. package/dist/task-queue/task-queue.js +20 -44
  458. package/dist/task-queue/types.d.ts +0 -1
  459. package/dist/task-queue/worker-status.d.ts +35 -0
  460. package/dist/task-queue/worker-status.js +40 -0
  461. package/dist/types.d.ts +40 -51
  462. package/dist/url-collision.d.ts +26 -40
  463. package/dist/url-collision.js +47 -63
  464. package/dist/url-exclusivity-fixtures.d.ts +15 -20
  465. package/dist/url-exclusivity-fixtures.js +14 -19
  466. package/dist/url-path-resolver.d.ts +8 -16
  467. package/dist/url-path-resolver.js +19 -29
  468. package/dist/user.d.ts +8 -21
  469. package/dist/user.js +10 -19
  470. package/dist/utils/async-mutex.js +4 -6
  471. package/dist/utils/atomic-write.d.ts +2 -11
  472. package/dist/utils/atomic-write.js +2 -11
  473. package/dist/utils/body-field.d.ts +8 -15
  474. package/dist/utils/body-field.js +8 -15
  475. package/dist/utils/content-serialize.d.ts +18 -24
  476. package/dist/utils/content-serialize.js +109 -160
  477. package/dist/utils/content-write-lock.d.ts +51 -106
  478. package/dist/utils/content-write-lock.js +66 -111
  479. package/dist/utils/debug.d.ts +7 -23
  480. package/dist/utils/debug.js +7 -23
  481. package/dist/utils/entry-url.d.ts +11 -23
  482. package/dist/utils/entry-url.js +11 -26
  483. package/dist/utils/error.d.ts +25 -90
  484. package/dist/utils/error.js +60 -147
  485. package/dist/utils/flatten-group-fields.d.ts +5 -7
  486. package/dist/utils/flatten-group-fields.js +5 -7
  487. package/dist/utils/format.d.ts +1 -5
  488. package/dist/utils/format.js +1 -5
  489. package/dist/utils/fs.d.ts +3 -4
  490. package/dist/utils/fs.js +3 -4
  491. package/dist/utils/git.d.ts +52 -83
  492. package/dist/utils/git.js +79 -125
  493. package/dist/utils/logger.d.ts +35 -50
  494. package/dist/utils/logger.js +35 -52
  495. package/dist/utils/provisioning-lock.d.ts +23 -35
  496. package/dist/utils/provisioning-lock.js +49 -69
  497. package/dist/utils/sanitize-href.d.ts +5 -10
  498. package/dist/utils/sanitize-href.js +8 -18
  499. package/dist/utils/title-field.d.ts +17 -20
  500. package/dist/utils/title-field.js +18 -27
  501. package/dist/utils/typed-filename.d.ts +20 -48
  502. package/dist/utils/typed-filename.js +25 -61
  503. package/dist/utils/url-prefix.d.ts +3 -3
  504. package/dist/utils/url-prefix.js +3 -3
  505. package/dist/validation/block-structural-keys.d.ts +16 -31
  506. package/dist/validation/block-structural-keys.js +19 -29
  507. package/dist/validation/deletion-checker.d.ts +0 -34
  508. package/dist/validation/deletion-checker.js +1 -43
  509. package/dist/validation/entry-link-validator.d.ts +6 -13
  510. package/dist/validation/entry-link-validator.js +4 -13
  511. package/dist/validation/entry-type-reference-validator.d.ts +13 -18
  512. package/dist/validation/entry-type-reference-validator.js +13 -18
  513. package/dist/validation/entry-validator.d.ts +13 -25
  514. package/dist/validation/entry-validator.js +15 -32
  515. package/dist/validation/field-traversal.d.ts +3 -30
  516. package/dist/validation/field-traversal.js +1 -32
  517. package/dist/validation/reference-validator.d.ts +5 -24
  518. package/dist/validation/reference-validator.js +5 -30
  519. package/dist/worker/cms-worker.d.ts +172 -232
  520. package/dist/worker/cms-worker.js +241 -333
  521. package/dist/worker/git-sync.d.ts +32 -133
  522. package/dist/worker/git-sync.js +129 -191
  523. package/dist/worker/github-auth.d.ts +13 -19
  524. package/dist/worker/github-auth.js +13 -19
  525. package/dist/worker/history-rewrite.d.ts +53 -66
  526. package/dist/worker/history-rewrite.js +54 -60
  527. package/dist/worker/log.d.ts +24 -41
  528. package/dist/worker/log.js +25 -42
  529. package/dist/worker/rebase.d.ts +20 -110
  530. package/dist/worker/rebase.js +279 -354
  531. package/dist/worker/task-runner.d.ts +32 -66
  532. package/dist/worker/task-runner.js +126 -162
  533. package/dist/worker/worker-context.d.ts +41 -81
  534. package/package.json +4 -4
  535. package/dist/cli/template-files/middleware-clerk.ts.template +0 -37
  536. package/dist/worker/task-queue-config.d.ts +0 -8
  537. package/dist/worker/task-queue.js +0 -19
  538. package/dist/worker/worker-status.d.ts +0 -47
  539. package/dist/worker/worker-status.js +0 -52
@@ -1,47 +1,32 @@
1
1
  /**
2
2
  * Schema Store - handles reading and writing .collection.json files.
3
- *
4
- * This module provides CRUD operations for collection schema metadata:
5
- * - Create/update/delete collections
6
- * - Add/update/remove entry types
7
- * - Update ordering of items within collections
8
- *
9
3
  * All mutations are branch-specific (like content edits).
10
4
  *
11
5
  * ## Concurrency
12
6
  *
13
- * `.collection.json` is read-modify-written by every mutator below, and is
14
- * mutated cross-host: two warm Lambda containers (or a Lambda + the EC2
15
- * worker) on EFS can both read the same pre-mutation file and have the
16
- * second write silently clobber the first. This deviates from the standard
17
- * 3-layer recipe in docs/concurrency.md in one deliberate way: NO OCC
18
- * `version`/`writeId` fields go into `.collection.json` itself, and no
19
- * lockfile lives in the content tree. Two reasons:
7
+ * `.collection.json` is read-modify-written by every mutator below and
8
+ * mutated cross-host — two warm Lambdas, or a Lambda + the EC2 worker, on
9
+ * EFS can both read the same pre-mutation file and clobber each other's
10
+ * write. This deviates from the standard 3-layer recipe in
11
+ * docs/concurrency.md: no OCC `version`/`writeId` field goes into
12
+ * `.collection.json` itself, and no lockfile lives in the content tree —
13
+ * both are adopter-visible, git-committed files, so a rebase would make a
14
+ * version counter meaningless and a crash-leftover lockfile would land in a
15
+ * commit an adopter reviews.
20
16
  *
21
- * - `.collection.json` is an adopter-visible, git-committed content file.
22
- * Rebases rewrite it wholesale from upstream, so a `version` counter would
23
- * be meaningless (and actively misleading) the moment a rebase lands.
24
- * - A lockfile crash-leftover inside the content tree would be swept into
25
- * `git add .` at publish time — a `.lock` or `.tmp` file has no business
26
- * ending up in a commit an adopter reviews.
17
+ * Protection is instead layer 1 ({@link withLock}) + layer 3
18
+ * ({@link withOccFileLock}) on one COARSE per-branch SURROGATE lock path
19
+ * OUTSIDE the content tree (`{branchRoot}/.canopy-meta/schema`, see
20
+ * `withSchemaLock`), covering every schema mutation on the branch including
21
+ * multi-file ones. Layer 2 (OCC read-back) is skipped, since there's no
22
+ * version field to check; layer 4 (generation marker) guards the schema
23
+ * CACHE separately, not this write path.
27
24
  *
28
- * Protection is instead: layer 1 ({@link withLock}) + layer 3
29
- * ({@link withOccFileLock}) on a single COARSE per-branch SURROGATE lock
30
- * path OUTSIDE the content tree — `{branchRoot}/.canopy-meta/schema` (see
31
- * `withSchemaLock`). One lock covers every schema mutation on the branch,
32
- * including multi-file mutations (`createCollection` writes the new child's
33
- * meta AND the parent's). Layer 2 (OCC read-back) is skipped entirely since
34
- * there is no version field to check; layer 4 (generation marker) is used
35
- * separately, for the schema CACHE, not for this write path.
36
- *
37
- * Accepted residual: `deleteBranch` does NOT take this lock before its
38
- * recursive `rm` — an in-flight schema write can race a concurrent branch
39
- * deletion (the write's `rm`/rename can hit ENOTEMPTY or land in a
40
- * half-deleted tree). This mirrors the same residual documented on
41
- * `BranchMetadataFileManager.save()` in branch-metadata.ts and is not closed
42
- * here either; see `withSchemaLock`'s doc comment for the phantom-guard that
43
- * IS in place for the common ordering (branch already gone before this call
44
- * ever starts).
25
+ * Accepted residual: `deleteBranch` does not take this lock before its
26
+ * recursive `rm`, so an in-flight write can race a concurrent branch
27
+ * deletion (mirrors the residual on `BranchMetadataFileManager.save()` in
28
+ * branch-metadata.ts) — see `withSchemaLock`'s doc for the phantom-guard
29
+ * covering the common ordering instead.
45
30
  */
46
31
  import { promises as fs } from 'node:fs';
47
32
  import path from 'node:path';
@@ -57,12 +42,8 @@ import { isIndexSlug } from '../utils/entry-url.js';
57
42
  import { invalidateBranchContentCaches } from '../content-index-generation.js';
58
43
  import { generateId, isValidId } from '../id.js';
59
44
  import { createLogicalPath, normalizeCollectionPath as stripContentRootPrefix, validateAndNormalizePath, } from '../paths/index.js';
60
- // ============================================================================
61
- // Zod Schemas for Validation
62
- // ============================================================================
63
45
  /** Max length for names and slugs (filesystem path safety) */
64
46
  const MAX_NAME_LENGTH = 64;
65
- /** Max length for labels */
66
47
  const MAX_LABEL_LENGTH = 128;
67
48
  /**
68
49
  * Safe pattern for names and slugs that become filesystem path segments.
@@ -117,9 +98,6 @@ const updateEntryTypeInputSchema = z.object({
117
98
  default: z.boolean().optional(),
118
99
  maxItems: z.number().int().positive().optional(),
119
100
  });
120
- // ============================================================================
121
- // SchemaOps Class
122
- // ============================================================================
123
101
  const log = createDebugLogger({ prefix: 'SchemaOps' });
124
102
  /**
125
103
  * Thrown when a schema mutation cannot proceed because the per-branch
@@ -154,43 +132,31 @@ export class SchemaOps {
154
132
  .join('/');
155
133
  this.schemaLockPath = path.join(this.branchRoot, '.canopy-meta', 'schema');
156
134
  }
157
- // --------------------------------------------------------------------------
158
- // Schema Lock
159
- // --------------------------------------------------------------------------
160
135
  /**
161
136
  * Serialize an entire read-modify-write schema mutation behind the coarse
162
- * per-branch surrogate lock described in the module doc comment. Layers,
163
- * outermost to innermost (same structure as
164
- * `BranchMetadataFileManager.save()` — see branch-metadata.ts):
165
- *
166
- * 1. {@link withLock} — in-process FIFO mutex, deterministic same-process
167
- * serialization.
168
- * 2. {@link withOccFileLock} — server-enforced, cross-process/cross-host
169
- * mutual exclusion (proper-lockfile, mkdir-based), immune to NFS client
170
- * dentry/attribute caching.
137
+ * per-branch surrogate lock described in the module doc comment: layer 1
138
+ * ({@link withLock}, in-process FIFO mutex) wraps layer 3
139
+ * ({@link withOccFileLock}, cross-process/cross-host mkdir-based mutual
140
+ * exclusion, immune to NFS attribute caching), same structure as
141
+ * `BranchMetadataFileManager.save()` in branch-metadata.ts.
171
142
  *
172
- * NOT re-entrant: callers must never invoke this (directly or via a public
173
- * mutator) from inside a callback already running under it — `withLock`
174
- * would deadlock waiting on itself. This is why `updateOrderInner` calls
175
- * `updateCollectionInner` directly instead of the public `updateCollection`.
143
+ * NOT re-entrant — callers must never invoke this from inside a callback
144
+ * already running under it, or `withLock` deadlocks waiting on itself;
145
+ * that's why `updateOrderInner` calls `updateCollectionInner` directly
146
+ * instead of the public `updateCollection`.
176
147
  *
177
148
  * Phantom-resurrection guard: `branchRoot` can be removed by a concurrent
178
149
  * `deleteBranch` between the caller resolving its BranchContext and this
179
- * call reaching its own lock acquisition. `withOccFileLock`'s own
180
- * `mkdir({recursive:true})` on the lock directory would otherwise silently
181
- * recreate `.canopy-meta/` inside a directory tree that no longer exists
182
- * anywhere else. Checking BEFORE the lock (not after) fails fast without
183
- * paying for an acquisition on a doomed mutation.
184
- *
185
- * Residual window (accepted, same shape as branch-metadata.ts's): a call
186
- * that passes this check can still race a `deleteBranch` `rm` that starts
187
- * moments later and is still mid-flight when this call's write lands,
188
- * resurrecting the tree. `deleteBranch` does not take this lock at all
189
- * (see the module doc comment), so that race is not closed here either.
150
+ * call's own lock acquisition, which would otherwise let
151
+ * `withOccFileLock`'s `mkdir({recursive:true})` silently recreate
152
+ * `.canopy-meta/` in an otherwise-deleted tree. Checking BEFORE the lock
153
+ * fails fast instead. Residual (accepted, same shape as
154
+ * branch-metadata.ts's): a call that passes this check can still race a
155
+ * `deleteBranch` `rm` starting moments later — not closed here either,
156
+ * since `deleteBranch` never takes this lock (see the module doc comment).
190
157
  *
191
158
  * Translation happens ONLY at this boundary: inner code always sees the
192
- * raw {@link OccWriteConflictError} bubble up to here (never catches or
193
- * re-translates it itself).
159
+ * raw {@link OccWriteConflictError} bubble up here untranslated.
194
160
  */
195
161
  async withSchemaLock(fn) {
196
162
  try {
@@ -212,12 +178,10 @@ export class SchemaOps {
212
178
  throw err;
213
179
  }
214
180
  }
215
- // --------------------------------------------------------------------------
216
- // Cache Invalidation
217
- // --------------------------------------------------------------------------
218
181
  /**
219
182
  * Invalidate schema cache for this branch after mutations, then eagerly
220
- * re-resolve on THIS host.
183
+ * re-resolve on THIS host. Every mutator calls this after `withSchemaLock`
184
+ * has returned, never inside the critical section.
221
185
  *
222
186
  * The eager re-resolve is the durable-snapshot window-E mitigation (see
223
187
  * BranchSchemaCache's class docs): the mutating host's own scan is
@@ -271,68 +235,38 @@ export class SchemaOps {
271
235
  async invalidateContentIdIndexes() {
272
236
  await invalidateBranchContentCaches(this.branchRoot);
273
237
  }
274
- // --------------------------------------------------------------------------
275
- // Path Normalization
276
- // --------------------------------------------------------------------------
277
238
  /**
278
239
  * The single normalisation boundary for logical collection paths entering
279
- * this class. Every public method that accepts a logical collection path
280
- * (or, for `createCollection`, `input.parentPath`) calls this exactly once
281
- * before doing anything else with the path — that is the whole fix for the
282
- * "Collection not found" bug: `flattenSchema` (branch-schema-cache.ts)
283
- * produces content-root-prefixed logical paths (e.g. "content/posts", or
284
- * "cms/content/posts" for a multi-segment `contentRoot: 'cms/content'`),
285
- * the editor round-trips those straight back into every mutator
286
- * (`CollectionEditor.tsx` passes `editingCollection.logicalPath` as-is),
287
- * but `resolveCollectionPath(this.contentRoot, ...)` treats its second
288
- * argument as relative to `this.contentRoot` — which already embeds the
289
- * content-root segment(s). A prefixed path therefore resolved one level
290
- * too deep and was reported as not found. `updateCollectionInner` used to
291
- * strip the prefix itself (the only mutator that did); that bespoke strip
292
- * is gone now that every entry point normalises here instead.
240
+ * this class. Every public method that accepts one calls this exactly
241
+ * once, before touching the path: `flattenSchema` (branch-schema-cache.ts)
242
+ * produces content-root-prefixed logical paths (e.g. "content/posts") that
243
+ * the editor round-trips straight back into every mutator, but
244
+ * `resolveCollectionPath` treats its path argument as already relative to
245
+ * `this.contentRoot` — without stripping, a prefixed path resolves one
246
+ * level too deep and is reported as not found.
293
247
  *
294
- * Prefix-only: strips ONE leading `"{contentRootName}/"` if present (exact
295
- * string match against the full, possibly multi-segment, `contentRootName`
296
- * — never `path.basename()`, which would break a multi-segment root like
297
- * "cms/content"), otherwise returns the path unchanged. So both prefixed
298
- * (production/editor) and unprefixed (existing store tests, adopters
299
- * calling SchemaOps directly) input work. Deliberately does NOT touch the
300
- * bare root-collection sentinel (`collectionPath === this.contentRootName`,
301
- * no trailing segment): that has no trailing "/" to match, so it passes
302
- * through unchanged and the `=== this.contentRootName` checks in
248
+ * Strips ONE leading `"{contentRootName}/"` if present — exact string
249
+ * match against the full, possibly multi-segment, `contentRootName`, never
250
+ * `path.basename()` (which would break a root like "cms/content") —
251
+ * otherwise returns the path unchanged, so both prefixed and unprefixed
252
+ * callers work. Leaves the bare root-collection sentinel
253
+ * (`collectionPath === this.contentRootName`) untouched: it has no
254
+ * trailing "/" to strip, so the `=== this.contentRootName` checks in
303
255
  * `updateCollectionInner`/`updateOrderInner` keep working.
304
256
  *
305
- * CALL EXACTLY ONCE PER ENTRY POINT — it is NOT idempotent, and an earlier
306
- * version of this comment claimed it was. A sub-collection literally named
307
- * after the content root defeats the "already normalised" reasoning: with
308
- * `contentRoot: 'content'`, "content/content/x" normalises to "content/x"
309
- * and again to "x", and "content/content" normalises to "content", which
310
- * the `=== this.contentRootName` checks above then treat as the ROOT
311
- * collection — so a second call mutates a DIFFERENT collection rather than
312
- * reporting not-found. Every entry point calls this exactly once today, so
313
- * the ambiguity is unreachable; removing it needs the editor to send an
314
- * unambiguously-scoped path, tracked in
315
- * .claude/future-tasks/collection-path-content-root-ambiguity.md.
316
- *
317
- * A future public method that accepts a logical collection path must call
318
- * this first, and only once, the same way every existing one does — that is
319
- * the "safe by construction" contract this boundary is meant to provide.
257
+ * NOT idempotent — a sub-collection literally named after the content
258
+ * root can re-normalise to the ROOT collection on a second call, mutating
259
+ * the wrong one instead of reporting not-found. Every entry point calls
260
+ * this exactly once today, so the ambiguity is unreachable; see
261
+ * .claude/future-tasks/collection-path-content-root-ambiguity.md. A future
262
+ * method that accepts a logical collection path must do the same.
320
263
  */
321
264
  normalizeCollectionPath(collectionPath) {
322
265
  return createLogicalPath(stripContentRootPrefix(collectionPath, this.contentRootName));
323
266
  }
324
- // --------------------------------------------------------------------------
325
- // Validation Helpers
326
- // --------------------------------------------------------------------------
327
- /**
328
- * Validate that a schema reference exists in the registry
329
- */
330
267
  validateSchemaReference(schemaKey) {
331
268
  return schemaKey in this.entrySchemaRegistry;
332
269
  }
333
- /**
334
- * Validate all schema references in entry types
335
- */
336
270
  validateEntryTypeSchemas(entryTypes) {
337
271
  for (const entryType of entryTypes) {
338
272
  if (!this.validateSchemaReference(entryType.schema)) {
@@ -355,15 +289,8 @@ export class SchemaOps {
355
289
  }
356
290
  return { valid: true, normalizedPath: result.normalizedPath };
357
291
  }
358
- // --------------------------------------------------------------------------
359
- // Read Operations
360
- // --------------------------------------------------------------------------
361
- /**
362
- * Read a collection's .collection.json file
363
- */
364
292
  async readCollectionMeta(collectionPath) {
365
293
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
366
- // Resolve logical path to physical path with embedded IDs
367
294
  const physicalPath = await resolveCollectionPath(this.contentRoot, normalizedPath);
368
295
  if (!physicalPath) {
369
296
  return null;
@@ -380,9 +307,6 @@ export class SchemaOps {
380
307
  throw err;
381
308
  }
382
309
  }
383
- /**
384
- * Read root collection meta (content/.collection.json)
385
- */
386
310
  async readRootCollectionMeta() {
387
311
  const metaPath = path.join(this.contentRoot, '.collection.json');
388
312
  try {
@@ -409,11 +333,9 @@ export class SchemaOps {
409
333
  try {
410
334
  const entries = await fs.readdir(physicalPath, { withFileTypes: true });
411
335
  for (const entry of entries) {
412
- // Content files mean not empty
413
336
  if (entry.isFile() && entry.name !== '.collection.json') {
414
337
  return false;
415
338
  }
416
- // Child collection directories mean not empty
417
339
  if (entry.isDirectory()) {
418
340
  try {
419
341
  await fs.access(path.join(physicalPath, entry.name, '.collection.json'));
@@ -433,45 +355,27 @@ export class SchemaOps {
433
355
  throw err;
434
356
  }
435
357
  }
436
- // --------------------------------------------------------------------------
437
- // Write Operations
438
- //
439
358
  // These are plain atomic writes with NO locking of their own: every caller
440
359
  // reaches them from inside a public mutator's `withSchemaLock` critical
441
360
  // section (see the module doc comment), which is what actually protects
442
361
  // against concurrent writers. Locking here too would be redundant and
443
362
  // would mislead a reader into thinking THIS is where the safety comes
444
363
  // from.
445
- // --------------------------------------------------------------------------
446
- /**
447
- * Write a collection's .collection.json file
448
- */
449
364
  async writeCollectionMeta(physicalPath, meta) {
450
365
  const metaPath = path.join(physicalPath, '.collection.json');
451
366
  const content = JSON.stringify(meta, null, 2) + '\n';
452
367
  await atomicWriteFile(metaPath, content);
453
368
  }
454
- /**
455
- * Write root collection meta
456
- */
457
369
  async writeRootCollectionMeta(meta) {
458
370
  const metaPath = path.join(this.contentRoot, '.collection.json');
459
371
  const content = JSON.stringify(meta, null, 2) + '\n';
460
372
  await atomicWriteFile(metaPath, content);
461
373
  }
462
- // --------------------------------------------------------------------------
463
- // Collection Operations
464
- // --------------------------------------------------------------------------
465
- /**
466
- * Create a new collection
467
- */
468
374
  async createCollection(input) {
469
- // Validate input
470
375
  const parseResult = createCollectionInputSchema.safeParse(input);
471
376
  if (!parseResult.success) {
472
377
  throw new Error(`Invalid input: ${parseResult.error.message}`);
473
378
  }
474
- // Validate schema references
475
379
  const schemaValidation = this.validateEntryTypeSchemas(input.entries);
476
380
  if (!schemaValidation.valid) {
477
381
  throw new Error(schemaValidation.error);
@@ -485,12 +389,11 @@ export class SchemaOps {
485
389
  ? { ...input, parentPath: this.normalizeCollectionPath(input.parentPath) }
486
390
  : input;
487
391
  const result = await this.withSchemaLock(() => this.createCollectionInner(normalizedInput));
488
- // Invalidate schema cache after mutation (outside the lock — see withSchemaLock's doc comment)
392
+ // Outside the lock -- see invalidateSchemaCache.
489
393
  await this.invalidateSchemaCache();
490
394
  return result;
491
395
  }
492
396
  async createCollectionInner(input) {
493
- // Determine parent directory
494
397
  let parentPhysicalPath;
495
398
  if (input.parentPath) {
496
399
  const resolved = await resolveCollectionPath(this.contentRoot, input.parentPath);
@@ -502,18 +405,16 @@ export class SchemaOps {
502
405
  else {
503
406
  parentPhysicalPath = this.contentRoot;
504
407
  }
505
- // Generate embedded ID for new collection
506
408
  const contentId = generateId();
507
409
  const dirName = `${input.name}.${contentId}`;
508
410
  const physicalPath = path.join(parentPhysicalPath, dirName);
509
- // Defense-in-depth (SCH-C1): the name pattern above already prevents
411
+ // Defense-in-depth: the name pattern above already prevents
510
412
  // traversal, but independently assert the resolved path stays within the
511
413
  // content root before any filesystem write.
512
414
  const containment = this.validatePath(physicalPath);
513
415
  if (!containment.valid) {
514
416
  throw new Error(`Invalid collection path: ${containment.error}`);
515
417
  }
516
- // Create directory
517
418
  await fs.mkdir(physicalPath, { recursive: true });
518
419
  await this.invalidateContentIdIndexes();
519
420
  // Build collection meta with empty order array (required for ordering support)
@@ -528,40 +429,32 @@ export class SchemaOps {
528
429
  default: et.default,
529
430
  maxItems: et.maxItems,
530
431
  })),
531
- order: [], // Initialize with empty order array
432
+ order: [],
532
433
  };
533
- // Write .collection.json
534
434
  await this.writeCollectionMeta(physicalPath, meta);
535
- // Add new collection's contentId to parent's order array
536
435
  // For root-level collections (empty parentPath), we don't update parent order
537
436
  const parentLogicalPath = input.parentPath
538
437
  ? createLogicalPath(input.parentPath)
539
438
  : createLogicalPath('');
540
439
  const parentMeta = input.parentPath ? await this.readCollectionMeta(parentLogicalPath) : null;
541
440
  if (parentMeta) {
542
- // Initialize parent's order array if it doesn't exist
543
441
  const existingOrder = parentMeta.order ?? [];
544
442
  parentMeta.order = [...existingOrder, contentId];
545
443
  await this.writeCollectionMeta(parentPhysicalPath, parentMeta);
546
444
  }
547
- // Build logical path
548
445
  const logicalPath = input.parentPath
549
446
  ? createLogicalPath(`${input.parentPath}/${input.name}`)
550
447
  : createLogicalPath(input.name);
551
448
  return { collectionPath: logicalPath, contentId };
552
449
  }
553
- /**
554
- * Update a collection's metadata
555
- */
556
450
  async updateCollection(collectionPath, updates) {
557
- // Validate input
558
451
  const parseResult = updateCollectionInputSchema.safeParse(updates);
559
452
  if (!parseResult.success) {
560
453
  throw new Error(`Invalid input: ${parseResult.error.message}`);
561
454
  }
562
455
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
563
456
  await this.withSchemaLock(() => this.updateCollectionInner(normalizedPath, updates));
564
- // Invalidate schema cache after mutation (outside the lock — see withSchemaLock's doc comment)
457
+ // Outside the lock -- see invalidateSchemaCache.
565
458
  await this.invalidateSchemaCache();
566
459
  }
567
460
  /**
@@ -577,10 +470,7 @@ export class SchemaOps {
577
470
  * comment for the single boundary that owns that now.
578
471
  */
579
472
  async updateCollectionInner(collectionPath, updates) {
580
- // Check if this is the root collection (path equals the configured content
581
- // root, e.g. "content" or "cms/content")
582
473
  if (collectionPath === this.contentRootName) {
583
- // Update root collection meta
584
474
  let meta = await this.readRootCollectionMeta();
585
475
  if (!meta) {
586
476
  meta = {};
@@ -595,22 +485,16 @@ export class SchemaOps {
595
485
  await this.writeRootCollectionMeta(meta);
596
486
  return;
597
487
  }
598
- // Resolve path for regular collection. collectionPath is already
599
- // normalized (no content-root prefix) by the caller — see this method's
600
- // doc comment.
601
488
  const physicalPath = await resolveCollectionPath(this.contentRoot, collectionPath);
602
489
  if (!physicalPath) {
603
490
  throw new Error(`Collection not found: ${collectionPath}`);
604
491
  }
605
- // Read existing meta
606
492
  const meta = await this.readCollectionMeta(collectionPath);
607
493
  if (!meta) {
608
494
  throw new Error(`Collection meta not found: ${collectionPath}`);
609
495
  }
610
- // Handle slug change (directory rename) if provided
611
496
  let finalPhysicalPath = physicalPath;
612
497
  if (updates.slug !== undefined) {
613
- // Extract current slug and ID from physical path
614
498
  // Format: /path/to/{slug}.{12-char-id}
615
499
  const dirName = path.basename(physicalPath);
616
500
  const parts = dirName.split('.');
@@ -619,17 +503,13 @@ export class SchemaOps {
619
503
  }
620
504
  const currentSlug = parts[0];
621
505
  const contentId = parts[1];
622
- // Only rename if slug is actually different
623
506
  if (updates.slug !== currentSlug) {
624
- // Validate new slug (alphanumeric + hyphens, lowercase)
625
507
  if (!SAFE_NAME_PATTERN.test(updates.slug)) {
626
508
  throw new Error(`Slug ${SAFE_NAME_MESSAGE}`);
627
509
  }
628
- // Build new path with new slug + same ID
629
510
  const parentDir = path.dirname(physicalPath);
630
511
  const newDirName = `${updates.slug}.${contentId}`;
631
512
  const newPhysicalPath = path.join(parentDir, newDirName);
632
- // Check if any collection with this slug already exists
633
513
  // Need to check for any directory matching {slug}.{any-id}
634
514
  try {
635
515
  const entries = await fs.readdir(parentDir, { withFileTypes: true });
@@ -643,34 +523,22 @@ export class SchemaOps {
643
523
  }
644
524
  }
645
525
  catch (err) {
646
- // Re-throw "already exists" errors
647
526
  if (err.message.includes('already exists')) {
648
527
  throw err;
649
528
  }
650
529
  // Ignore other errors (e.g., ENOENT if parent dir doesn't exist somehow)
651
530
  }
652
- // [URL] Contested-URL guard. Renaming a collection re-paths every entry beneath it, so
653
- // its index entry -- the one whose URL is the collection's own path -- lands on the new
654
- // name. If an entry with that slug already sits in the parent, the two would contest one
655
- // URL and only one could be served. See url-collision.ts.
656
- //
657
- // Only the index entry can collide: the sibling-name check above has already established
658
- // that no `{slug}.{id}` directory exists at the destination, so no descendant DEEPER than
659
- // the index entry has anything to collide with.
660
- //
661
- // That holds only as far as the check above does, and it is narrower than it looks: it
662
- // compares case-SENSITIVELY (so `guides` beside an existing `Guides.{id}` passes it) and
663
- // it requires `parts.length === 2 && isValidId(parts[1])` (so a plain, ID-less `docs/`
664
- // directory at the destination passes it too). Descendants CAN then contest.
665
- // See .claude/future-tasks/collection-sibling-name-uniqueness.md, which tracks both the
666
- // missing create-side check and this case hole.
531
+ // Contested-URL guard: renaming re-paths every entry beneath this collection, so its own
532
+ // index entry can end up sharing a URL with a same-slugged entry already in the parent
533
+ // (see url-collision.ts). Only the index entry is at risk — the sibling-name check above
534
+ // already rules out a `{slug}.{id}` directory at the destination — but that check is
535
+ // case-SENSITIVE and lets an ID-less `docs/`-style directory through, so a case or
536
+ // ID-less collision can still slip past it for entries deeper than the index; see
537
+ // .claude/future-tasks/collection-sibling-name-uniqueness.md.
667
538
  if (await findIndexEntryIn(physicalPath)) {
668
- // Renaming TO "index" collapses this collection onto ITS OWN new path
669
- // (`<parentPath>/index`), not onto `<parentPath>` -- see `computeEntryUrl`. An entry in
670
- // the parent whose slug is the literal string "index" is the PARENT's own index/landing
671
- // entry, which collapses onto `<parentPath>` itself -- a different URL, not a collision.
672
- // Skip the lookup in that case; see url-collision.ts's `findUrlPathClaimant` for the
673
- // create-time version of this same false positive.
539
+ // Renaming TO "index" collapses this collection onto its OWN new path, not the
540
+ // parent's — see url-collision.ts's findUrlPathClaimant for the equivalent create-time
541
+ // check, which skips this same false positive the same way.
674
542
  const conflicting = isIndexSlug(updates.slug)
675
543
  ? null
676
544
  : await findEntryBySlugIn(parentDir, updates.slug);
@@ -688,7 +556,6 @@ export class SchemaOps {
688
556
  await this.invalidateContentIdIndexes();
689
557
  }
690
558
  }
691
- // Apply metadata updates
692
559
  if (updates.name !== undefined) {
693
560
  meta.name = updates.name;
694
561
  }
@@ -707,7 +574,7 @@ export class SchemaOps {
707
574
  async deleteCollection(collectionPath) {
708
575
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
709
576
  await this.withSchemaLock(() => this.deleteCollectionInner(normalizedPath));
710
- // Invalidate schema cache after mutation (outside the lock — see withSchemaLock's doc comment)
577
+ // Outside the lock -- see invalidateSchemaCache.
711
578
  await this.invalidateSchemaCache();
712
579
  }
713
580
  async deleteCollectionInner(collectionPath) {
@@ -717,53 +584,39 @@ export class SchemaOps {
717
584
  if (!isEmpty) {
718
585
  throw new Error('Collection must be empty before deletion. Delete all entries first.');
719
586
  }
720
- // Resolve path
721
587
  const physicalPath = await resolveCollectionPath(this.contentRoot, collectionPath);
722
588
  if (!physicalPath) {
723
589
  throw new Error(`Collection not found: ${collectionPath}`);
724
590
  }
725
- // Delete the directory (including .collection.json)
726
591
  await fs.rm(physicalPath, { recursive: true });
727
592
  await this.invalidateContentIdIndexes();
728
593
  }
729
- // --------------------------------------------------------------------------
730
- // Entry Type Operations
731
- // --------------------------------------------------------------------------
732
- /**
733
- * Add an entry type to a collection
734
- */
735
594
  async addEntryType(collectionPath, entryType) {
736
- // Validate input
737
595
  const parseResult = entryTypeInputSchema.safeParse(entryType);
738
596
  if (!parseResult.success) {
739
597
  throw new Error(`Invalid input: ${parseResult.error.message}`);
740
598
  }
741
- // Validate schema reference
742
599
  if (!this.validateSchemaReference(entryType.schema)) {
743
600
  const available = Object.keys(this.entrySchemaRegistry).join(', ');
744
601
  throw new Error(`Schema reference "${entryType.schema}" not found. Available: ${available}`);
745
602
  }
746
603
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
747
604
  await this.withSchemaLock(() => this.addEntryTypeInner(normalizedPath, entryType));
748
- // Invalidate schema cache after mutation (outside the lock — see withSchemaLock's doc comment)
605
+ // Outside the lock -- see invalidateSchemaCache.
749
606
  await this.invalidateSchemaCache();
750
607
  }
751
608
  async addEntryTypeInner(collectionPath, entryType) {
752
- // Resolve path
753
609
  const physicalPath = await resolveCollectionPath(this.contentRoot, collectionPath);
754
610
  if (!physicalPath) {
755
611
  throw new Error(`Collection not found: ${collectionPath}`);
756
612
  }
757
- // Read existing meta
758
613
  const meta = await this.readCollectionMeta(collectionPath);
759
614
  if (!meta) {
760
615
  throw new Error(`Collection meta not found: ${collectionPath}`);
761
616
  }
762
- // Check for duplicate name
763
617
  if (meta.entries?.some((et) => et.name === entryType.name)) {
764
618
  throw new Error(`Entry type "${entryType.name}" already exists in this collection`);
765
619
  }
766
- // Add entry type
767
620
  meta.entries = meta.entries || [];
768
621
  meta.entries.push({
769
622
  name: entryType.name,
@@ -773,35 +626,27 @@ export class SchemaOps {
773
626
  default: entryType.default,
774
627
  maxItems: entryType.maxItems,
775
628
  });
776
- // Write back
777
629
  await this.writeCollectionMeta(physicalPath, meta);
778
630
  }
779
- /**
780
- * Update an entry type in a collection
781
- */
782
631
  async updateEntryType(collectionPath, entryTypeName, updates) {
783
- // Validate input
784
632
  const parseResult = updateEntryTypeInputSchema.safeParse(updates);
785
633
  if (!parseResult.success) {
786
634
  throw new Error(`Invalid input: ${parseResult.error.message}`);
787
635
  }
788
- // Validate schema reference if provided
789
636
  if (updates.schema && !this.validateSchemaReference(updates.schema)) {
790
637
  const available = Object.keys(this.entrySchemaRegistry).join(', ');
791
638
  throw new Error(`Schema reference "${updates.schema}" not found. Available: ${available}`);
792
639
  }
793
640
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
794
641
  await this.withSchemaLock(() => this.updateEntryTypeInner(normalizedPath, entryTypeName, updates));
795
- // Invalidate schema cache after mutation (outside the lock — see withSchemaLock's doc comment)
642
+ // Outside the lock -- see invalidateSchemaCache.
796
643
  await this.invalidateSchemaCache();
797
644
  }
798
645
  async updateEntryTypeInner(collectionPath, entryTypeName, updates) {
799
- // Breaking-change usage guard — moved here from api/schema.ts's
800
- // updateEntryTypeHandler, which used to count usages BEFORE calling this
801
- // method: a concurrent write could land an entry between that count and
802
- // this write (TOCTOU). Running the count under the same lock that guards
803
- // the write closes that window. Error message preserved exactly — the
804
- // handler's catch surfaces it verbatim as a 400.
646
+ // Breaking-change usage guard: the usage count runs under the same lock
647
+ // as the write; counted outside it, a concurrent write could land an
648
+ // entry between the count and this write (TOCTOU). Error message
649
+ // preserved exactly — the handler's catch surfaces it verbatim as a 400.
805
650
  const isBreakingChange = updates.format !== undefined || updates.schema !== undefined;
806
651
  if (isBreakingChange) {
807
652
  const usageCount = await this.countEntriesUsingType(collectionPath, entryTypeName);
@@ -810,22 +655,18 @@ export class SchemaOps {
810
655
  throw new Error(`Cannot modify schema or format for entry type with existing ${entryWord}. ${usageCount} ${entryWord} currently use this type.`);
811
656
  }
812
657
  }
813
- // Resolve path
814
658
  const physicalPath = await resolveCollectionPath(this.contentRoot, collectionPath);
815
659
  if (!physicalPath) {
816
660
  throw new Error(`Collection not found: ${collectionPath}`);
817
661
  }
818
- // Read existing meta
819
662
  const meta = await this.readCollectionMeta(collectionPath);
820
663
  if (!meta) {
821
664
  throw new Error(`Collection meta not found: ${collectionPath}`);
822
665
  }
823
- // Find entry type
824
666
  const entryType = meta.entries?.find((et) => et.name === entryTypeName);
825
667
  if (!entryType) {
826
668
  throw new Error(`Entry type "${entryTypeName}" not found in collection`);
827
669
  }
828
- // Apply updates
829
670
  if (updates.label !== undefined) {
830
671
  entryType.label = updates.label;
831
672
  }
@@ -841,55 +682,41 @@ export class SchemaOps {
841
682
  if (updates.maxItems !== undefined) {
842
683
  entryType.maxItems = updates.maxItems;
843
684
  }
844
- // Write back
845
685
  await this.writeCollectionMeta(physicalPath, meta);
846
686
  }
847
- /**
848
- * Remove an entry type from a collection
849
- */
850
687
  async removeEntryType(collectionPath, entryTypeName) {
851
688
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
852
689
  await this.withSchemaLock(() => this.removeEntryTypeInner(normalizedPath, entryTypeName));
853
- // Invalidate schema cache after mutation (outside the lock — see withSchemaLock's doc comment)
690
+ // Outside the lock -- see invalidateSchemaCache.
854
691
  await this.invalidateSchemaCache();
855
692
  }
856
693
  async removeEntryTypeInner(collectionPath, entryTypeName) {
857
- // Resolve path
858
694
  const physicalPath = await resolveCollectionPath(this.contentRoot, collectionPath);
859
695
  if (!physicalPath) {
860
696
  throw new Error(`Collection not found: ${collectionPath}`);
861
697
  }
862
- // Read existing meta
863
698
  const meta = await this.readCollectionMeta(collectionPath);
864
699
  if (!meta) {
865
700
  throw new Error(`Collection meta not found: ${collectionPath}`);
866
701
  }
867
- // Check entry type exists
868
702
  const index = meta.entries?.findIndex((et) => et.name === entryTypeName) ?? -1;
869
703
  if (index === -1) {
870
704
  throw new Error(`Entry type "${entryTypeName}" not found in collection`);
871
705
  }
872
- // Ensure at least one entry type remains
873
706
  if (meta.entries.length === 1) {
874
707
  throw new Error('Cannot remove last entry type. Collection must have at least one entry type.');
875
708
  }
876
- // Check for entries still using this type
877
709
  const usageCount = await this.countEntriesUsingType(collectionPath, entryTypeName);
878
710
  if (usageCount > 0) {
879
711
  throw new Error(`Cannot remove entry type "${entryTypeName}": ${usageCount} ${usageCount === 1 ? 'entry still uses' : 'entries still use'} it. ` +
880
712
  'Delete or migrate those entries first.');
881
713
  }
882
- // Remove entry type
883
714
  meta.entries.splice(index, 1);
884
- // Write back
885
715
  await this.writeCollectionMeta(physicalPath, meta);
886
716
  }
887
- // --------------------------------------------------------------------------
888
- // Usage Counting
889
- // --------------------------------------------------------------------------
890
717
  /**
891
718
  * Count the number of entries using a specific entry type in a collection.
892
- * This is used to prevent breaking changes to entry types that have existing content.
719
+ * Prevents breaking changes to entry types that have existing content.
893
720
  *
894
721
  * @param collectionPath - Logical path to the collection (e.g., "content/posts")
895
722
  * @param entryTypeName - Name of the entry type to count
@@ -905,29 +732,22 @@ export class SchemaOps {
905
732
  */
906
733
  async countEntriesUsingType(collectionPath, entryTypeName) {
907
734
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
908
- // Resolve collection physical path
909
735
  const physicalPath = await resolveCollectionPath(this.contentRoot, normalizedPath);
910
736
  if (!physicalPath) {
911
- // Collection doesn't exist yet - return 0
912
737
  return 0;
913
738
  }
914
739
  try {
915
- // Read directory entries
916
740
  const entries = await fs.readdir(physicalPath, { withFileTypes: true });
917
741
  // Count files matching pattern: {entryTypeName}.{slug}.{id}.{ext}
918
742
  let count = 0;
919
743
  for (const entry of entries) {
920
- // Skip directories and hidden files
921
744
  if (entry.isDirectory() || entry.name.startsWith('.')) {
922
745
  continue;
923
746
  }
924
- // Parse filename: type.slug.id.ext
925
747
  const parts = entry.name.split('.');
926
- // Need at least 4 parts: type, slug, id, ext
927
748
  if (parts.length < 4) {
928
749
  continue;
929
750
  }
930
- // Check if first part matches entry type name
931
751
  if (parts[0] !== entryTypeName) {
932
752
  continue;
933
753
  }
@@ -947,23 +767,14 @@ export class SchemaOps {
947
767
  throw err;
948
768
  }
949
769
  }
950
- // --------------------------------------------------------------------------
951
- // Order Operations
952
- // --------------------------------------------------------------------------
953
- /**
954
- * Update the order of items in a collection
955
- */
956
770
  async updateOrder(collectionPath, order) {
957
771
  const normalizedPath = this.normalizeCollectionPath(collectionPath);
958
772
  await this.withSchemaLock(() => this.updateOrderInner(normalizedPath, order));
959
- // Invalidate schema cache after mutation (outside the lock — see withSchemaLock's doc comment)
773
+ // Outside the lock -- see invalidateSchemaCache.
960
774
  await this.invalidateSchemaCache();
961
775
  }
962
776
  async updateOrderInner(collectionPath, order) {
963
- // Check if this is the root collection (path equals the configured content
964
- // root, e.g. "content" or "cms/content")
965
777
  if (collectionPath === this.contentRootName) {
966
- // Update root collection meta
967
778
  let meta = await this.readRootCollectionMeta();
968
779
  if (!meta) {
969
780
  meta = {};
@@ -972,16 +783,8 @@ export class SchemaOps {
972
783
  await this.writeRootCollectionMeta(meta);
973
784
  return;
974
785
  }
975
- // Update regular collection. collectionPath is already normalized (no
976
- // content-root prefix) by the public updateOrder above. Calls
977
- // updateCollectionInner DIRECTLY, never the public updateCollection:
978
- // we're already inside withSchemaLock's critical section here, and
979
- // withLock is not re-entrant — going through updateCollection would call
980
- // withSchemaLock again and deadlock waiting on the lock it itself holds.
786
+ // Inner, not updateCollection: withSchemaLock is not re-entrant (see its doc).
981
787
  await this.updateCollectionInner(collectionPath, { order });
982
788
  }
983
789
  }
984
- // ============================================================================
985
- // Exports
986
- // ============================================================================
987
790
  export { createCollectionInputSchema, updateCollectionInputSchema, entryTypeInputSchema, updateEntryTypeInputSchema, };