canopycms 0.0.62 → 0.0.64

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 (1204) hide show
  1. package/README.md +153 -19
  2. package/dist/ai/generate.d.ts +4 -5
  3. package/dist/ai/generate.js +0 -1
  4. package/dist/ai/handler.d.ts +3 -4
  5. package/dist/ai/handler.js +0 -1
  6. package/dist/ai/index.d.ts +15 -7
  7. package/dist/ai/index.js +9 -1
  8. package/dist/ai/json-to-markdown.d.ts +1 -2
  9. package/dist/ai/json-to-markdown.js +11 -2
  10. package/dist/ai/resolve-branch.d.ts +1 -2
  11. package/dist/ai/resolve-branch.js +0 -1
  12. package/dist/ai/strip-mdx.d.ts +0 -1
  13. package/dist/ai/strip-mdx.js +0 -1
  14. package/dist/ai/to-plain-text.d.ts +60 -0
  15. package/dist/ai/to-plain-text.js +301 -0
  16. package/dist/ai/transform-components.d.ts +1 -2
  17. package/dist/ai/transform-components.js +70 -6
  18. package/dist/ai/types.d.ts +1 -2
  19. package/dist/ai/types.js +0 -1
  20. package/dist/api/admin-branch-health.d.ts +7 -8
  21. package/dist/api/admin-branch-health.js +0 -1
  22. package/dist/api/admin.d.ts +16 -17
  23. package/dist/api/admin.js +0 -1
  24. package/dist/api/assets.d.ts +8 -9
  25. package/dist/api/assets.js +0 -1
  26. package/dist/api/branch-merge.d.ts +3 -4
  27. package/dist/api/branch-merge.js +0 -1
  28. package/dist/api/branch-review.d.ts +5 -6
  29. package/dist/api/branch-review.js +0 -1
  30. package/dist/api/branch-status.d.ts +15 -16
  31. package/dist/api/branch-status.js +0 -1
  32. package/dist/api/branch-withdraw.d.ts +3 -4
  33. package/dist/api/branch-withdraw.js +0 -1
  34. package/dist/api/branch.d.ts +13 -14
  35. package/dist/api/branch.js +0 -1
  36. package/dist/api/client.d.ts +14 -15
  37. package/dist/api/client.js +0 -1
  38. package/dist/api/comments.d.ts +11 -12
  39. package/dist/api/comments.js +0 -1
  40. package/dist/api/content.d.ts +22 -24
  41. package/dist/api/content.js +132 -18
  42. package/dist/api/entries-constants.d.ts +0 -1
  43. package/dist/api/entries-constants.js +0 -1
  44. package/dist/api/entries.d.ts +12 -13
  45. package/dist/api/entries.js +12 -2
  46. package/dist/api/github-sync.d.ts +2 -3
  47. package/dist/api/github-sync.js +0 -1
  48. package/dist/api/groups.d.ts +6 -7
  49. package/dist/api/groups.js +0 -1
  50. package/dist/api/guards.d.ts +2 -3
  51. package/dist/api/guards.js +0 -1
  52. package/dist/api/index.d.ts +18 -19
  53. package/dist/api/index.js +0 -1
  54. package/dist/api/permissions.d.ts +10 -11
  55. package/dist/api/permissions.js +0 -1
  56. package/dist/api/reference-options.d.ts +3 -4
  57. package/dist/api/reference-options.js +0 -1
  58. package/dist/api/request-body-hash.d.ts +0 -1
  59. package/dist/api/request-body-hash.js +0 -1
  60. package/dist/api/resolve-references.d.ts +6 -7
  61. package/dist/api/resolve-references.js +24 -6
  62. package/dist/api/route-builder.d.ts +2 -3
  63. package/dist/api/route-builder.js +0 -1
  64. package/dist/api/schema.d.ts +43 -44
  65. package/dist/api/schema.js +0 -1
  66. package/dist/api/settings-helpers.d.ts +2 -3
  67. package/dist/api/settings-helpers.js +0 -1
  68. package/dist/api/types.d.ts +6 -7
  69. package/dist/api/types.js +0 -1
  70. package/dist/api/user.d.ts +2 -3
  71. package/dist/api/user.js +0 -1
  72. package/dist/api/validators.d.ts +3 -4
  73. package/dist/api/validators.js +0 -1
  74. package/dist/assets/asset-prefixes.d.ts +1 -2
  75. package/dist/assets/asset-prefixes.js +0 -1
  76. package/dist/assets/asset-src.d.ts +17 -5
  77. package/dist/assets/asset-src.js +15 -3
  78. package/dist/assets/asset-url.d.ts +28 -7
  79. package/dist/assets/asset-url.js +20 -15
  80. package/dist/assets/factory.d.ts +2 -3
  81. package/dist/assets/factory.js +0 -2
  82. package/dist/assets/finalize.d.ts +2 -3
  83. package/dist/assets/finalize.js +0 -1
  84. package/dist/assets/index.d.ts +12 -13
  85. package/dist/assets/index.js +0 -1
  86. package/dist/assets/keys.d.ts +1 -2
  87. package/dist/assets/keys.js +0 -1
  88. package/dist/assets/pipeline.d.ts +1 -2
  89. package/dist/assets/pipeline.js +0 -1
  90. package/dist/assets/store-local.d.ts +1 -2
  91. package/dist/assets/store-local.js +0 -1
  92. package/dist/assets/store-s3.d.ts +2 -4
  93. package/dist/assets/store-s3.js +0 -1
  94. package/dist/assets/svg-sanitizer.d.ts +0 -1
  95. package/dist/assets/svg-sanitizer.js +0 -1
  96. package/dist/assets/transform-directives.d.ts +0 -1
  97. package/dist/assets/transform-directives.js +0 -1
  98. package/dist/assets/transform.d.ts +1 -2
  99. package/dist/assets/transform.js +0 -1
  100. package/dist/assets/types.d.ts +0 -1
  101. package/dist/assets/types.js +0 -1
  102. package/dist/auth/cache.d.ts +2 -3
  103. package/dist/auth/cache.js +0 -1
  104. package/dist/auth/caching-auth-plugin.d.ts +3 -4
  105. package/dist/auth/caching-auth-plugin.js +0 -1
  106. package/dist/auth/context-helpers.d.ts +1 -2
  107. package/dist/auth/context-helpers.js +0 -1
  108. package/dist/auth/file-based-auth-cache.d.ts +3 -4
  109. package/dist/auth/file-based-auth-cache.js +0 -1
  110. package/dist/auth/index.d.ts +6 -7
  111. package/dist/auth/index.js +0 -1
  112. package/dist/auth/plugin.d.ts +3 -4
  113. package/dist/auth/plugin.js +0 -1
  114. package/dist/auth/types.d.ts +1 -2
  115. package/dist/auth/types.js +0 -1
  116. package/dist/authorization/branch.d.ts +58 -7
  117. package/dist/authorization/branch.js +55 -10
  118. package/dist/authorization/content.d.ts +6 -7
  119. package/dist/authorization/content.js +0 -1
  120. package/dist/authorization/groups/index.d.ts +2 -3
  121. package/dist/authorization/groups/index.js +0 -1
  122. package/dist/authorization/groups/loader.d.ts +3 -4
  123. package/dist/authorization/groups/loader.js +0 -1
  124. package/dist/authorization/groups/schema.d.ts +1 -2
  125. package/dist/authorization/groups/schema.js +0 -1
  126. package/dist/authorization/helpers.d.ts +0 -1
  127. package/dist/authorization/helpers.js +0 -1
  128. package/dist/authorization/index.d.ts +11 -12
  129. package/dist/authorization/index.js +0 -1
  130. package/dist/authorization/path.d.ts +4 -5
  131. package/dist/authorization/path.js +0 -1
  132. package/dist/authorization/permissions/index.d.ts +2 -3
  133. package/dist/authorization/permissions/index.js +0 -1
  134. package/dist/authorization/permissions/loader.d.ts +4 -5
  135. package/dist/authorization/permissions/loader.js +0 -1
  136. package/dist/authorization/permissions/schema.d.ts +2 -3
  137. package/dist/authorization/permissions/schema.js +0 -1
  138. package/dist/authorization/protected-branch.d.ts +2 -3
  139. package/dist/authorization/protected-branch.js +0 -1
  140. package/dist/authorization/settings-file-store.d.ts +1 -2
  141. package/dist/authorization/settings-file-store.js +0 -1
  142. package/dist/authorization/types.d.ts +7 -8
  143. package/dist/authorization/types.js +0 -1
  144. package/dist/authorization/validation.d.ts +1 -2
  145. package/dist/authorization/validation.js +0 -1
  146. package/dist/branch-health.d.ts +2 -3
  147. package/dist/branch-health.js +0 -1
  148. package/dist/branch-metadata.d.ts +2 -3
  149. package/dist/branch-metadata.js +0 -1
  150. package/dist/branch-registry.d.ts +1 -2
  151. package/dist/branch-registry.js +0 -1
  152. package/dist/branch-schema-cache.d.ts +4 -5
  153. package/dist/branch-schema-cache.js +0 -1
  154. package/dist/branch-workspace.d.ts +4 -5
  155. package/dist/branch-workspace.js +0 -1
  156. package/dist/build/generate-ai-content.d.ts +21 -5
  157. package/dist/build/generate-ai-content.js +98 -6
  158. package/dist/build/index.d.ts +2 -3
  159. package/dist/build/index.js +0 -1
  160. package/dist/build-canopy.d.ts +48 -0
  161. package/dist/build-canopy.js +50 -0
  162. package/dist/build-mode.d.ts +1 -2
  163. package/dist/build-mode.js +0 -1
  164. package/dist/cli/cli.d.ts +1 -2
  165. package/dist/cli/cli.js +1192 -495
  166. package/dist/cli/generate-ai-content.d.ts +0 -1
  167. package/dist/cli/generate-ai-content.js +1062 -370
  168. package/dist/cli/init.d.ts +1 -2
  169. package/dist/cli/init.js +12 -2
  170. package/dist/cli/migrate.d.ts +5 -3
  171. package/dist/cli/migrate.js +5 -3
  172. package/dist/cli/project-detect.d.ts +5 -2
  173. package/dist/cli/project-detect.js +5 -1
  174. package/dist/cli/project-root.d.ts +0 -1
  175. package/dist/cli/project-root.js +0 -1
  176. package/dist/cli/sync.d.ts +0 -1
  177. package/dist/cli/sync.js +0 -1
  178. package/dist/cli/template-files/canopycms.config.ts.template +18 -1
  179. package/dist/cli/template-files/deploy-cms.yml.template +8 -6
  180. package/dist/cli/templates.d.ts +0 -1
  181. package/dist/cli/templates.js +0 -1
  182. package/dist/client.d.ts +13 -14
  183. package/dist/client.js +0 -1
  184. package/dist/comment-store.d.ts +0 -1
  185. package/dist/comment-store.js +0 -1
  186. package/dist/config/flatten.d.ts +1 -2
  187. package/dist/config/flatten.js +0 -1
  188. package/dist/config/helpers.d.ts +3 -4
  189. package/dist/config/helpers.js +2 -2
  190. package/dist/config/index.d.ts +10 -11
  191. package/dist/config/index.js +0 -1
  192. package/dist/config/schemas/collection.d.ts +0 -1
  193. package/dist/config/schemas/collection.js +0 -1
  194. package/dist/config/schemas/config.d.ts +7 -4
  195. package/dist/config/schemas/config.js +12 -1
  196. package/dist/config/schemas/field.d.ts +3 -1
  197. package/dist/config/schemas/field.js +5 -1
  198. package/dist/config/schemas/media.d.ts +0 -1
  199. package/dist/config/schemas/media.js +0 -1
  200. package/dist/config/schemas/permissions.d.ts +0 -1
  201. package/dist/config/schemas/permissions.js +0 -1
  202. package/dist/config/types.d.ts +55 -9
  203. package/dist/config/types.js +0 -1
  204. package/dist/config/validation.d.ts +1 -2
  205. package/dist/config/validation.js +0 -1
  206. package/dist/config.d.ts +2 -3
  207. package/dist/config.js +0 -1
  208. package/dist/content-id-index.d.ts +1 -2
  209. package/dist/content-id-index.js +0 -1
  210. package/dist/content-index-generation.d.ts +0 -1
  211. package/dist/content-index-generation.js +0 -1
  212. package/dist/content-index-registry.d.ts +0 -1
  213. package/dist/content-index-registry.js +0 -1
  214. package/dist/content-listing.d.ts +137 -16
  215. package/dist/content-listing.js +175 -41
  216. package/dist/content-reader.d.ts +44 -8
  217. package/dist/content-reader.js +39 -7
  218. package/dist/content-store.d.ts +147 -7
  219. package/dist/content-store.js +294 -22
  220. package/dist/content-tree.d.ts +44 -5
  221. package/dist/content-tree.js +47 -11
  222. package/dist/context.d.ts +38 -15
  223. package/dist/context.js +55 -5
  224. package/dist/dev-content-watcher.d.ts +2 -3
  225. package/dist/dev-content-watcher.js +0 -1
  226. package/dist/editor/BranchManager.d.ts +4 -5
  227. package/dist/editor/BranchManager.js +0 -1
  228. package/dist/editor/CanopyEditor.d.ts +2 -3
  229. package/dist/editor/CanopyEditor.js +1 -2
  230. package/dist/editor/CanopyEditorPage.d.ts +2 -3
  231. package/dist/editor/CanopyEditorPage.js +0 -1
  232. package/dist/editor/CommentsPanel.d.ts +2 -3
  233. package/dist/editor/CommentsPanel.js +0 -1
  234. package/dist/editor/Editor.d.ts +13 -8
  235. package/dist/editor/Editor.js +4 -5
  236. package/dist/editor/EditorPanes.d.ts +0 -1
  237. package/dist/editor/EditorPanes.js +0 -1
  238. package/dist/editor/EntryNavigator.d.ts +1 -2
  239. package/dist/editor/EntryNavigator.js +0 -1
  240. package/dist/editor/FormRenderer.d.ts +2 -3
  241. package/dist/editor/FormRenderer.js +22 -3
  242. package/dist/editor/GroupManager.d.ts +2 -3
  243. package/dist/editor/GroupManager.js +0 -1
  244. package/dist/editor/PermissionManager.d.ts +2 -3
  245. package/dist/editor/PermissionManager.js +0 -1
  246. package/dist/editor/admin/SystemHealthPanel.d.ts +0 -1
  247. package/dist/editor/admin/SystemHealthPanel.js +0 -1
  248. package/dist/editor/admin/useSystemHealth.d.ts +2 -3
  249. package/dist/editor/admin/useSystemHealth.js +0 -1
  250. package/dist/editor/canopy-path.d.ts +0 -1
  251. package/dist/editor/canopy-path.js +0 -1
  252. package/dist/editor/client-reference-resolver.d.ts +13 -4
  253. package/dist/editor/client-reference-resolver.js +18 -8
  254. package/dist/editor/comments/BranchComments.d.ts +2 -3
  255. package/dist/editor/comments/BranchComments.js +0 -1
  256. package/dist/editor/comments/EntryComments.d.ts +1 -2
  257. package/dist/editor/comments/EntryComments.js +0 -1
  258. package/dist/editor/comments/FieldWrapper.d.ts +1 -2
  259. package/dist/editor/comments/FieldWrapper.js +0 -1
  260. package/dist/editor/comments/InlineCommentThread.d.ts +2 -3
  261. package/dist/editor/comments/InlineCommentThread.js +0 -1
  262. package/dist/editor/comments/ThreadCarousel.d.ts +2 -3
  263. package/dist/editor/comments/ThreadCarousel.js +0 -1
  264. package/dist/editor/components/ConfirmDeleteModal.d.ts +0 -1
  265. package/dist/editor/components/ConfirmDeleteModal.js +0 -1
  266. package/dist/editor/components/EditorFooter.d.ts +0 -1
  267. package/dist/editor/components/EditorFooter.js +0 -1
  268. package/dist/editor/components/EditorHeader.d.ts +4 -5
  269. package/dist/editor/components/EditorHeader.js +0 -1
  270. package/dist/editor/components/EditorSidebar.d.ts +1 -2
  271. package/dist/editor/components/EditorSidebar.js +0 -1
  272. package/dist/editor/components/EntryCreateModal.d.ts +0 -1
  273. package/dist/editor/components/EntryCreateModal.js +21 -10
  274. package/dist/editor/components/RenameEntryModal.d.ts +0 -1
  275. package/dist/editor/components/RenameEntryModal.js +0 -1
  276. package/dist/editor/components/UserBadge.d.ts +2 -3
  277. package/dist/editor/components/UserBadge.js +0 -1
  278. package/dist/editor/components/index.d.ts +3 -4
  279. package/dist/editor/components/index.js +0 -1
  280. package/dist/editor/context/ApiClientContext.d.ts +9 -3
  281. package/dist/editor/context/ApiClientContext.js +8 -4
  282. package/dist/editor/context/AssetContext.d.ts +26 -2
  283. package/dist/editor/context/AssetContext.js +23 -3
  284. package/dist/editor/context/EditorStateContext.d.ts +1 -2
  285. package/dist/editor/context/EditorStateContext.js +0 -1
  286. package/dist/editor/context/SWRProvider.d.ts +0 -1
  287. package/dist/editor/context/SWRProvider.js +0 -1
  288. package/dist/editor/context/index.d.ts +4 -5
  289. package/dist/editor/context/index.js +0 -1
  290. package/dist/editor/editor-config.d.ts +2 -3
  291. package/dist/editor/editor-config.js +0 -1
  292. package/dist/editor/editor-utils.d.ts +22 -10
  293. package/dist/editor/editor-utils.js +41 -10
  294. package/dist/editor/fields/BlockField.d.ts +1 -2
  295. package/dist/editor/fields/BlockField.js +0 -1
  296. package/dist/editor/fields/CodeField.d.ts +0 -1
  297. package/dist/editor/fields/CodeField.js +0 -1
  298. package/dist/editor/fields/DateTimeField.d.ts +0 -1
  299. package/dist/editor/fields/DateTimeField.js +0 -1
  300. package/dist/editor/fields/ImageField.d.ts +1 -2
  301. package/dist/editor/fields/ImageField.js +0 -1
  302. package/dist/editor/fields/InlineGroupField.d.ts +2 -3
  303. package/dist/editor/fields/InlineGroupField.js +0 -1
  304. package/dist/editor/fields/MarkdownField.d.ts +0 -1
  305. package/dist/editor/fields/MarkdownField.js +0 -1
  306. package/dist/editor/fields/MdxImageDialog.d.ts +0 -1
  307. package/dist/editor/fields/MdxImageDialog.js +0 -1
  308. package/dist/editor/fields/NumberField.d.ts +0 -1
  309. package/dist/editor/fields/NumberField.js +0 -1
  310. package/dist/editor/fields/NumberListField.d.ts +0 -1
  311. package/dist/editor/fields/NumberListField.js +0 -1
  312. package/dist/editor/fields/ObjectField.d.ts +11 -2
  313. package/dist/editor/fields/ObjectField.js +3 -4
  314. package/dist/editor/fields/ReferenceField.d.ts +0 -1
  315. package/dist/editor/fields/ReferenceField.js +8 -3
  316. package/dist/editor/fields/SelectField.d.ts +0 -1
  317. package/dist/editor/fields/SelectField.js +0 -1
  318. package/dist/editor/fields/StringListField.d.ts +0 -1
  319. package/dist/editor/fields/StringListField.js +0 -1
  320. package/dist/editor/fields/TextField.d.ts +0 -1
  321. package/dist/editor/fields/TextField.js +0 -1
  322. package/dist/editor/fields/ToggleField.d.ts +0 -1
  323. package/dist/editor/fields/ToggleField.js +0 -1
  324. package/dist/editor/fields/entry-link/EntryLinkContext.d.ts +1 -2
  325. package/dist/editor/fields/entry-link/EntryLinkContext.js +0 -1
  326. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -1
  327. package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -1
  328. package/dist/editor/fields/entry-link/index.d.ts +2 -3
  329. package/dist/editor/fields/entry-link/index.js +0 -1
  330. package/dist/editor/group-manager/ExternalGroupsTab.d.ts +1 -2
  331. package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
  332. package/dist/editor/group-manager/GroupCard.d.ts +1 -2
  333. package/dist/editor/group-manager/GroupCard.js +0 -1
  334. package/dist/editor/group-manager/GroupForm.d.ts +1 -2
  335. package/dist/editor/group-manager/GroupForm.js +0 -1
  336. package/dist/editor/group-manager/InternalGroupsTab.d.ts +1 -2
  337. package/dist/editor/group-manager/InternalGroupsTab.js +0 -1
  338. package/dist/editor/group-manager/MemberList.d.ts +1 -2
  339. package/dist/editor/group-manager/MemberList.js +0 -1
  340. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +1 -2
  341. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -1
  342. package/dist/editor/group-manager/hooks/useGroupState.d.ts +1 -2
  343. package/dist/editor/group-manager/hooks/useGroupState.js +0 -1
  344. package/dist/editor/group-manager/hooks/useUserSearch.d.ts +1 -2
  345. package/dist/editor/group-manager/hooks/useUserSearch.js +0 -1
  346. package/dist/editor/group-manager/index.d.ts +5 -6
  347. package/dist/editor/group-manager/index.js +0 -1
  348. package/dist/editor/group-manager/types.d.ts +4 -5
  349. package/dist/editor/group-manager/types.js +0 -1
  350. package/dist/editor/hooks/index.d.ts +14 -15
  351. package/dist/editor/hooks/index.js +0 -1
  352. package/dist/editor/hooks/useBranchActions.d.ts +0 -1
  353. package/dist/editor/hooks/useBranchActions.js +0 -1
  354. package/dist/editor/hooks/useBranchManager.d.ts +4 -5
  355. package/dist/editor/hooks/useBranchManager.js +0 -1
  356. package/dist/editor/hooks/useBranchesData.d.ts +2 -3
  357. package/dist/editor/hooks/useBranchesData.js +0 -1
  358. package/dist/editor/hooks/useCommentSystem.d.ts +2 -3
  359. package/dist/editor/hooks/useCommentSystem.js +0 -1
  360. package/dist/editor/hooks/useCommentsData.d.ts +2 -3
  361. package/dist/editor/hooks/useCommentsData.js +0 -1
  362. package/dist/editor/hooks/useDraftManager.d.ts +3 -4
  363. package/dist/editor/hooks/useDraftManager.js +0 -1
  364. package/dist/editor/hooks/useEditorLayout.d.ts +1 -2
  365. package/dist/editor/hooks/useEditorLayout.js +0 -1
  366. package/dist/editor/hooks/useEntriesData.d.ts +3 -5
  367. package/dist/editor/hooks/useEntriesData.js +0 -3
  368. package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -3
  369. package/dist/editor/hooks/useEntryLinkResolution.js +0 -1
  370. package/dist/editor/hooks/useEntryManager.d.ts +5 -7
  371. package/dist/editor/hooks/useEntryManager.js +8 -3
  372. package/dist/editor/hooks/useGroupManager.d.ts +2 -3
  373. package/dist/editor/hooks/useGroupManager.js +0 -1
  374. package/dist/editor/hooks/usePermissionManager.d.ts +2 -3
  375. package/dist/editor/hooks/usePermissionManager.js +0 -1
  376. package/dist/editor/hooks/useReferenceResolution.d.ts +1 -2
  377. package/dist/editor/hooks/useReferenceResolution.js +8 -3
  378. package/dist/editor/hooks/useSchemaManager.d.ts +2 -3
  379. package/dist/editor/hooks/useSchemaManager.js +0 -1
  380. package/dist/editor/hooks/useUserContext.d.ts +1 -2
  381. package/dist/editor/hooks/useUserContext.js +8 -3
  382. package/dist/editor/hooks/useUserMetadata.d.ts +2 -3
  383. package/dist/editor/hooks/useUserMetadata.js +0 -1
  384. package/dist/editor/media/AssetCard.d.ts +1 -2
  385. package/dist/editor/media/AssetCard.js +0 -1
  386. package/dist/editor/media/CropStep.d.ts +1 -2
  387. package/dist/editor/media/CropStep.js +0 -1
  388. package/dist/editor/media/MediaLibrary.d.ts +1 -2
  389. package/dist/editor/media/MediaLibrary.js +0 -1
  390. package/dist/editor/media/MediaLibraryBody.d.ts +1 -2
  391. package/dist/editor/media/MediaLibraryBody.js +0 -1
  392. package/dist/editor/media/crop-math.d.ts +1 -2
  393. package/dist/editor/media/crop-math.js +0 -1
  394. package/dist/editor/media/upload-asset.d.ts +2 -3
  395. package/dist/editor/media/upload-asset.js +0 -1
  396. package/dist/editor/media/upload-constants.d.ts +0 -1
  397. package/dist/editor/media/upload-constants.js +0 -1
  398. package/dist/editor/media/useAssetUpload.d.ts +1 -2
  399. package/dist/editor/media/useAssetUpload.js +0 -1
  400. package/dist/editor/media/xhr-upload.d.ts +0 -1
  401. package/dist/editor/media/xhr-upload.js +0 -1
  402. package/dist/editor/permission-manager/GroupSelector.d.ts +1 -2
  403. package/dist/editor/permission-manager/GroupSelector.js +0 -1
  404. package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -2
  405. package/dist/editor/permission-manager/PermissionEditor.js +0 -1
  406. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +1 -2
  407. package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -1
  408. package/dist/editor/permission-manager/PermissionTree.d.ts +1 -2
  409. package/dist/editor/permission-manager/PermissionTree.js +0 -1
  410. package/dist/editor/permission-manager/UserSelector.d.ts +1 -2
  411. package/dist/editor/permission-manager/UserSelector.js +0 -1
  412. package/dist/editor/permission-manager/constants.d.ts +1 -2
  413. package/dist/editor/permission-manager/constants.js +0 -1
  414. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +1 -2
  415. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -1
  416. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +2 -3
  417. package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -1
  418. package/dist/editor/permission-manager/index.d.ts +4 -5
  419. package/dist/editor/permission-manager/index.js +0 -1
  420. package/dist/editor/permission-manager/types.d.ts +3 -4
  421. package/dist/editor/permission-manager/types.js +0 -1
  422. package/dist/editor/permission-manager/utils.d.ts +2 -3
  423. package/dist/editor/permission-manager/utils.js +0 -1
  424. package/dist/editor/preview-bridge.d.ts +1 -2
  425. package/dist/editor/preview-bridge.js +0 -1
  426. package/dist/editor/relative-time.d.ts +0 -1
  427. package/dist/editor/relative-time.js +0 -1
  428. package/dist/editor/schema-editor/CollectionEditor.d.ts +4 -5
  429. package/dist/editor/schema-editor/CollectionEditor.js +0 -1
  430. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +2 -3
  431. package/dist/editor/schema-editor/EntryTypeEditor.js +0 -1
  432. package/dist/editor/schema-editor/index.d.ts +2 -3
  433. package/dist/editor/schema-editor/index.js +0 -1
  434. package/dist/editor/theme.d.ts +0 -1
  435. package/dist/editor/theme.js +0 -1
  436. package/dist/editor/utils/env.d.ts +0 -1
  437. package/dist/editor/utils/env.js +0 -1
  438. package/dist/entry-link-resolver.d.ts +1 -2
  439. package/dist/entry-link-resolver.js +0 -1
  440. package/dist/entry-schema-registry.d.ts +3 -4
  441. package/dist/entry-schema-registry.js +6 -2
  442. package/dist/entry-schema.d.ts +342 -11
  443. package/dist/entry-schema.js +170 -1
  444. package/dist/git-manager.d.ts +1 -2
  445. package/dist/git-manager.js +0 -1
  446. package/dist/github-service.d.ts +1 -2
  447. package/dist/github-service.js +0 -1
  448. package/dist/http/handler.d.ts +6 -7
  449. package/dist/http/handler.js +0 -1
  450. package/dist/http/index.d.ts +6 -7
  451. package/dist/http/index.js +0 -1
  452. package/dist/http/router.d.ts +2 -3
  453. package/dist/http/router.js +0 -1
  454. package/dist/http/types.d.ts +0 -1
  455. package/dist/http/types.js +0 -1
  456. package/dist/id.d.ts +2 -3
  457. package/dist/id.js +0 -1
  458. package/dist/index.d.ts +17 -17
  459. package/dist/index.js +7 -1
  460. package/dist/operating-mode/client-safe-strategy.d.ts +1 -2
  461. package/dist/operating-mode/client-safe-strategy.js +0 -1
  462. package/dist/operating-mode/client-unsafe-strategy.d.ts +1 -2
  463. package/dist/operating-mode/client-unsafe-strategy.js +0 -1
  464. package/dist/operating-mode/client.d.ts +3 -4
  465. package/dist/operating-mode/client.js +0 -1
  466. package/dist/operating-mode/deployment-name-fixtures.d.ts +0 -1
  467. package/dist/operating-mode/deployment-name-fixtures.js +0 -1
  468. package/dist/operating-mode/deployment-name.d.ts +0 -1
  469. package/dist/operating-mode/deployment-name.js +0 -1
  470. package/dist/operating-mode/index.d.ts +5 -6
  471. package/dist/operating-mode/index.js +0 -1
  472. package/dist/operating-mode/mode-env.d.ts +1 -2
  473. package/dist/operating-mode/mode-env.js +0 -1
  474. package/dist/operating-mode/types.d.ts +2 -3
  475. package/dist/operating-mode/types.js +0 -1
  476. package/dist/paths/branch-name.d.ts +1 -2
  477. package/dist/paths/branch-name.js +0 -1
  478. package/dist/paths/branch.d.ts +3 -4
  479. package/dist/paths/branch.js +0 -1
  480. package/dist/paths/index.d.ts +8 -9
  481. package/dist/paths/index.js +0 -1
  482. package/dist/paths/normalize-server.d.ts +1 -2
  483. package/dist/paths/normalize-server.js +0 -1
  484. package/dist/paths/normalize.d.ts +1 -2
  485. package/dist/paths/normalize.js +0 -1
  486. package/dist/paths/resolve.d.ts +2 -3
  487. package/dist/paths/resolve.js +0 -1
  488. package/dist/paths/types.d.ts +0 -1
  489. package/dist/paths/types.js +0 -1
  490. package/dist/paths/validation.d.ts +1 -2
  491. package/dist/paths/validation.js +0 -1
  492. package/dist/reference-resolver.d.ts +3 -4
  493. package/dist/reference-resolver.js +0 -1
  494. package/dist/resolve-canopy-user.d.ts +3 -4
  495. package/dist/resolve-canopy-user.js +0 -1
  496. package/dist/resource-generation.d.ts +0 -1
  497. package/dist/resource-generation.js +0 -1
  498. package/dist/schema/index.d.ts +3 -4
  499. package/dist/schema/index.js +0 -1
  500. package/dist/schema/meta-loader.d.ts +3 -4
  501. package/dist/schema/meta-loader.js +3 -3
  502. package/dist/schema/resolver.d.ts +2 -3
  503. package/dist/schema/resolver.js +0 -1
  504. package/dist/schema/schema-store-types.d.ts +2 -3
  505. package/dist/schema/schema-store-types.js +0 -1
  506. package/dist/schema/schema-store.d.ts +6 -7
  507. package/dist/schema/schema-store.js +33 -1
  508. package/dist/schema/types.d.ts +1 -2
  509. package/dist/schema/types.js +0 -1
  510. package/dist/server.d.ts +97 -37
  511. package/dist/server.js +60 -3
  512. package/dist/services.d.ts +10 -12
  513. package/dist/services.js +2 -7
  514. package/dist/settings-workspace.d.ts +12 -15
  515. package/dist/settings-workspace.js +10 -13
  516. package/dist/static/index.d.ts +227 -9
  517. package/dist/static/index.js +302 -14
  518. package/dist/static/seo.d.ts +128 -0
  519. package/dist/static/seo.js +162 -0
  520. package/dist/sync-core.d.ts +0 -1
  521. package/dist/sync-core.js +0 -1
  522. package/dist/task-queue/index.d.ts +2 -3
  523. package/dist/task-queue/index.js +0 -1
  524. package/dist/task-queue/task-queue.d.ts +1 -2
  525. package/dist/task-queue/task-queue.js +0 -1
  526. package/dist/task-queue/types.d.ts +0 -1
  527. package/dist/task-queue/types.js +0 -1
  528. package/dist/types.d.ts +3 -4
  529. package/dist/types.js +0 -1
  530. package/dist/url-collision.d.ts +86 -0
  531. package/dist/url-collision.js +186 -0
  532. package/dist/url-path-resolver.d.ts +11 -2
  533. package/dist/url-path-resolver.js +37 -5
  534. package/dist/user.d.ts +3 -4
  535. package/dist/user.js +0 -1
  536. package/dist/utils/async-mutex.d.ts +0 -1
  537. package/dist/utils/async-mutex.js +0 -1
  538. package/dist/utils/atomic-write.d.ts +0 -1
  539. package/dist/utils/atomic-write.js +0 -1
  540. package/dist/utils/body-field.d.ts +12 -2
  541. package/dist/utils/body-field.js +17 -1
  542. package/dist/utils/content-serialize.d.ts +37 -0
  543. package/dist/utils/content-serialize.js +429 -0
  544. package/dist/utils/content-write-lock.d.ts +12 -16
  545. package/dist/utils/content-write-lock.js +38 -22
  546. package/dist/utils/debug.d.ts +0 -1
  547. package/dist/utils/debug.js +0 -1
  548. package/dist/utils/entry-url.d.ts +17 -1
  549. package/dist/utils/entry-url.js +21 -3
  550. package/dist/utils/error.d.ts +0 -1
  551. package/dist/utils/error.js +0 -1
  552. package/dist/utils/flatten-group-fields.d.ts +1 -2
  553. package/dist/utils/flatten-group-fields.js +0 -1
  554. package/dist/utils/format.d.ts +1 -2
  555. package/dist/utils/format.js +0 -1
  556. package/dist/utils/fs.d.ts +7 -1
  557. package/dist/utils/fs.js +16 -1
  558. package/dist/utils/git.d.ts +1 -2
  559. package/dist/utils/git.js +0 -1
  560. package/dist/utils/logger.d.ts +0 -1
  561. package/dist/utils/logger.js +0 -1
  562. package/dist/utils/occ-json-write.d.ts +0 -1
  563. package/dist/utils/occ-json-write.js +0 -1
  564. package/dist/utils/provisioning-lock.d.ts +17 -4
  565. package/dist/utils/provisioning-lock.js +94 -14
  566. package/dist/utils/sanitize-href.d.ts +46 -1
  567. package/dist/utils/sanitize-href.js +63 -3
  568. package/dist/utils/title-field.d.ts +1 -2
  569. package/dist/utils/title-field.js +0 -1
  570. package/dist/utils/typed-filename.d.ts +61 -0
  571. package/dist/utils/typed-filename.js +92 -0
  572. package/dist/utils/url-prefix.d.ts +121 -0
  573. package/dist/utils/url-prefix.js +158 -0
  574. package/dist/validation/block-structural-keys.d.ts +42 -0
  575. package/dist/validation/block-structural-keys.js +44 -0
  576. package/dist/validation/deletion-checker.d.ts +4 -5
  577. package/dist/validation/deletion-checker.js +0 -1
  578. package/dist/validation/entry-link-validator.d.ts +2 -3
  579. package/dist/validation/entry-link-validator.js +0 -1
  580. package/dist/validation/entry-type-reference-validator.d.ts +1 -2
  581. package/dist/validation/entry-type-reference-validator.js +0 -1
  582. package/dist/validation/entry-validator.d.ts +23 -2
  583. package/dist/validation/entry-validator.js +34 -2
  584. package/dist/validation/field-traversal.d.ts +28 -4
  585. package/dist/validation/field-traversal.js +24 -7
  586. package/dist/validation/reference-validator.d.ts +2 -3
  587. package/dist/validation/reference-validator.js +0 -1
  588. package/dist/worker/cms-worker.d.ts +9 -2
  589. package/dist/worker/cms-worker.js +59 -2
  590. package/dist/worker/log.d.ts +0 -1
  591. package/dist/worker/log.js +0 -1
  592. package/dist/worker/task-queue-config.d.ts +1 -2
  593. package/dist/worker/task-queue-config.js +0 -1
  594. package/dist/worker/task-queue.d.ts +3 -4
  595. package/dist/worker/task-queue.js +0 -1
  596. package/dist/worker/worker-status.d.ts +1 -2
  597. package/dist/worker/worker-status.js +0 -1
  598. package/package.json +2 -6
  599. package/dist/ai/generate.d.ts.map +0 -1
  600. package/dist/ai/generate.js.map +0 -1
  601. package/dist/ai/handler.d.ts.map +0 -1
  602. package/dist/ai/handler.js.map +0 -1
  603. package/dist/ai/index.d.ts.map +0 -1
  604. package/dist/ai/index.js.map +0 -1
  605. package/dist/ai/json-to-markdown.d.ts.map +0 -1
  606. package/dist/ai/json-to-markdown.js.map +0 -1
  607. package/dist/ai/resolve-branch.d.ts.map +0 -1
  608. package/dist/ai/resolve-branch.js.map +0 -1
  609. package/dist/ai/strip-mdx.d.ts.map +0 -1
  610. package/dist/ai/strip-mdx.js.map +0 -1
  611. package/dist/ai/transform-components.d.ts.map +0 -1
  612. package/dist/ai/transform-components.js.map +0 -1
  613. package/dist/ai/types.d.ts.map +0 -1
  614. package/dist/ai/types.js.map +0 -1
  615. package/dist/api/__test__/mock-client.d.ts +0 -231
  616. package/dist/api/__test__/mock-client.d.ts.map +0 -1
  617. package/dist/api/__test__/mock-client.js +0 -388
  618. package/dist/api/__test__/mock-client.js.map +0 -1
  619. package/dist/api/admin-branch-health.d.ts.map +0 -1
  620. package/dist/api/admin-branch-health.js.map +0 -1
  621. package/dist/api/admin.d.ts.map +0 -1
  622. package/dist/api/admin.js.map +0 -1
  623. package/dist/api/assets.d.ts.map +0 -1
  624. package/dist/api/assets.js.map +0 -1
  625. package/dist/api/branch-merge.d.ts.map +0 -1
  626. package/dist/api/branch-merge.js.map +0 -1
  627. package/dist/api/branch-review.d.ts.map +0 -1
  628. package/dist/api/branch-review.js.map +0 -1
  629. package/dist/api/branch-status.d.ts.map +0 -1
  630. package/dist/api/branch-status.js.map +0 -1
  631. package/dist/api/branch-withdraw.d.ts.map +0 -1
  632. package/dist/api/branch-withdraw.js.map +0 -1
  633. package/dist/api/branch.d.ts.map +0 -1
  634. package/dist/api/branch.js.map +0 -1
  635. package/dist/api/client.d.ts.map +0 -1
  636. package/dist/api/client.js.map +0 -1
  637. package/dist/api/comments.d.ts.map +0 -1
  638. package/dist/api/comments.js.map +0 -1
  639. package/dist/api/content.d.ts.map +0 -1
  640. package/dist/api/content.js.map +0 -1
  641. package/dist/api/entries-constants.d.ts.map +0 -1
  642. package/dist/api/entries-constants.js.map +0 -1
  643. package/dist/api/entries.d.ts.map +0 -1
  644. package/dist/api/entries.js.map +0 -1
  645. package/dist/api/github-sync.d.ts.map +0 -1
  646. package/dist/api/github-sync.js.map +0 -1
  647. package/dist/api/groups.d.ts.map +0 -1
  648. package/dist/api/groups.js.map +0 -1
  649. package/dist/api/guards.d.ts.map +0 -1
  650. package/dist/api/guards.js.map +0 -1
  651. package/dist/api/index.d.ts.map +0 -1
  652. package/dist/api/index.js.map +0 -1
  653. package/dist/api/permissions.d.ts.map +0 -1
  654. package/dist/api/permissions.js.map +0 -1
  655. package/dist/api/reference-options.d.ts.map +0 -1
  656. package/dist/api/reference-options.js.map +0 -1
  657. package/dist/api/request-body-hash.d.ts.map +0 -1
  658. package/dist/api/request-body-hash.js.map +0 -1
  659. package/dist/api/resolve-references.d.ts.map +0 -1
  660. package/dist/api/resolve-references.js.map +0 -1
  661. package/dist/api/route-builder.d.ts.map +0 -1
  662. package/dist/api/route-builder.js.map +0 -1
  663. package/dist/api/schema.d.ts.map +0 -1
  664. package/dist/api/schema.js.map +0 -1
  665. package/dist/api/settings-helpers.d.ts.map +0 -1
  666. package/dist/api/settings-helpers.js.map +0 -1
  667. package/dist/api/types.d.ts.map +0 -1
  668. package/dist/api/types.js.map +0 -1
  669. package/dist/api/user.d.ts.map +0 -1
  670. package/dist/api/user.js.map +0 -1
  671. package/dist/api/validators.d.ts.map +0 -1
  672. package/dist/api/validators.js.map +0 -1
  673. package/dist/assets/asset-prefixes.d.ts.map +0 -1
  674. package/dist/assets/asset-prefixes.js.map +0 -1
  675. package/dist/assets/asset-src.d.ts.map +0 -1
  676. package/dist/assets/asset-src.js.map +0 -1
  677. package/dist/assets/asset-url.d.ts.map +0 -1
  678. package/dist/assets/asset-url.js.map +0 -1
  679. package/dist/assets/factory.d.ts.map +0 -1
  680. package/dist/assets/factory.js.map +0 -1
  681. package/dist/assets/finalize.d.ts.map +0 -1
  682. package/dist/assets/finalize.js.map +0 -1
  683. package/dist/assets/index.d.ts.map +0 -1
  684. package/dist/assets/index.js.map +0 -1
  685. package/dist/assets/keys.d.ts.map +0 -1
  686. package/dist/assets/keys.js.map +0 -1
  687. package/dist/assets/pipeline.d.ts.map +0 -1
  688. package/dist/assets/pipeline.js.map +0 -1
  689. package/dist/assets/store-local.d.ts.map +0 -1
  690. package/dist/assets/store-local.js.map +0 -1
  691. package/dist/assets/store-s3.d.ts.map +0 -1
  692. package/dist/assets/store-s3.js.map +0 -1
  693. package/dist/assets/svg-sanitizer.d.ts.map +0 -1
  694. package/dist/assets/svg-sanitizer.js.map +0 -1
  695. package/dist/assets/transform-directives.d.ts.map +0 -1
  696. package/dist/assets/transform-directives.js.map +0 -1
  697. package/dist/assets/transform.d.ts.map +0 -1
  698. package/dist/assets/transform.js.map +0 -1
  699. package/dist/assets/types.d.ts.map +0 -1
  700. package/dist/assets/types.js.map +0 -1
  701. package/dist/auth/cache.d.ts.map +0 -1
  702. package/dist/auth/cache.js.map +0 -1
  703. package/dist/auth/caching-auth-plugin.d.ts.map +0 -1
  704. package/dist/auth/caching-auth-plugin.js.map +0 -1
  705. package/dist/auth/context-helpers.d.ts.map +0 -1
  706. package/dist/auth/context-helpers.js.map +0 -1
  707. package/dist/auth/file-based-auth-cache.d.ts.map +0 -1
  708. package/dist/auth/file-based-auth-cache.js.map +0 -1
  709. package/dist/auth/index.d.ts.map +0 -1
  710. package/dist/auth/index.js.map +0 -1
  711. package/dist/auth/plugin.d.ts.map +0 -1
  712. package/dist/auth/plugin.js.map +0 -1
  713. package/dist/auth/types.d.ts.map +0 -1
  714. package/dist/auth/types.js.map +0 -1
  715. package/dist/authorization/branch.d.ts.map +0 -1
  716. package/dist/authorization/branch.js.map +0 -1
  717. package/dist/authorization/content.d.ts.map +0 -1
  718. package/dist/authorization/content.js.map +0 -1
  719. package/dist/authorization/groups/index.d.ts.map +0 -1
  720. package/dist/authorization/groups/index.js.map +0 -1
  721. package/dist/authorization/groups/loader.d.ts.map +0 -1
  722. package/dist/authorization/groups/loader.js.map +0 -1
  723. package/dist/authorization/groups/schema.d.ts.map +0 -1
  724. package/dist/authorization/groups/schema.js.map +0 -1
  725. package/dist/authorization/helpers.d.ts.map +0 -1
  726. package/dist/authorization/helpers.js.map +0 -1
  727. package/dist/authorization/index.d.ts.map +0 -1
  728. package/dist/authorization/index.js.map +0 -1
  729. package/dist/authorization/path.d.ts.map +0 -1
  730. package/dist/authorization/path.js.map +0 -1
  731. package/dist/authorization/permissions/index.d.ts.map +0 -1
  732. package/dist/authorization/permissions/index.js.map +0 -1
  733. package/dist/authorization/permissions/loader.d.ts.map +0 -1
  734. package/dist/authorization/permissions/loader.js.map +0 -1
  735. package/dist/authorization/permissions/schema.d.ts.map +0 -1
  736. package/dist/authorization/permissions/schema.js.map +0 -1
  737. package/dist/authorization/protected-branch.d.ts.map +0 -1
  738. package/dist/authorization/protected-branch.js.map +0 -1
  739. package/dist/authorization/settings-file-store.d.ts.map +0 -1
  740. package/dist/authorization/settings-file-store.js.map +0 -1
  741. package/dist/authorization/test-utils.d.ts +0 -26
  742. package/dist/authorization/test-utils.d.ts.map +0 -1
  743. package/dist/authorization/test-utils.js +0 -23
  744. package/dist/authorization/test-utils.js.map +0 -1
  745. package/dist/authorization/types.d.ts.map +0 -1
  746. package/dist/authorization/types.js.map +0 -1
  747. package/dist/authorization/validation.d.ts.map +0 -1
  748. package/dist/authorization/validation.js.map +0 -1
  749. package/dist/branch-health.d.ts.map +0 -1
  750. package/dist/branch-health.js.map +0 -1
  751. package/dist/branch-metadata.d.ts.map +0 -1
  752. package/dist/branch-metadata.js.map +0 -1
  753. package/dist/branch-registry.d.ts.map +0 -1
  754. package/dist/branch-registry.js.map +0 -1
  755. package/dist/branch-schema-cache.d.ts.map +0 -1
  756. package/dist/branch-schema-cache.js.map +0 -1
  757. package/dist/branch-workspace.d.ts.map +0 -1
  758. package/dist/branch-workspace.js.map +0 -1
  759. package/dist/build/generate-ai-content.d.ts.map +0 -1
  760. package/dist/build/generate-ai-content.js.map +0 -1
  761. package/dist/build/index.d.ts.map +0 -1
  762. package/dist/build/index.js.map +0 -1
  763. package/dist/build-mode.d.ts.map +0 -1
  764. package/dist/build-mode.js.map +0 -1
  765. package/dist/cli/cli.d.ts.map +0 -1
  766. package/dist/cli/cli.js.map +0 -1
  767. package/dist/cli/generate-ai-content.d.ts.map +0 -1
  768. package/dist/cli/generate-ai-content.js.map +0 -1
  769. package/dist/cli/init.d.ts.map +0 -1
  770. package/dist/cli/init.js.map +0 -1
  771. package/dist/cli/migrate.d.ts.map +0 -1
  772. package/dist/cli/migrate.js.map +0 -1
  773. package/dist/cli/project-detect.d.ts.map +0 -1
  774. package/dist/cli/project-detect.js.map +0 -1
  775. package/dist/cli/project-root.d.ts.map +0 -1
  776. package/dist/cli/project-root.js.map +0 -1
  777. package/dist/cli/sync.d.ts.map +0 -1
  778. package/dist/cli/sync.js.map +0 -1
  779. package/dist/cli/templates.d.ts.map +0 -1
  780. package/dist/cli/templates.js.map +0 -1
  781. package/dist/client.d.ts.map +0 -1
  782. package/dist/client.js.map +0 -1
  783. package/dist/comment-store.d.ts.map +0 -1
  784. package/dist/comment-store.js.map +0 -1
  785. package/dist/config/flatten.d.ts.map +0 -1
  786. package/dist/config/flatten.js.map +0 -1
  787. package/dist/config/helpers.d.ts.map +0 -1
  788. package/dist/config/helpers.js.map +0 -1
  789. package/dist/config/index.d.ts.map +0 -1
  790. package/dist/config/index.js.map +0 -1
  791. package/dist/config/schemas/collection.d.ts.map +0 -1
  792. package/dist/config/schemas/collection.js.map +0 -1
  793. package/dist/config/schemas/config.d.ts.map +0 -1
  794. package/dist/config/schemas/config.js.map +0 -1
  795. package/dist/config/schemas/field.d.ts.map +0 -1
  796. package/dist/config/schemas/field.js.map +0 -1
  797. package/dist/config/schemas/media.d.ts.map +0 -1
  798. package/dist/config/schemas/media.js.map +0 -1
  799. package/dist/config/schemas/permissions.d.ts.map +0 -1
  800. package/dist/config/schemas/permissions.js.map +0 -1
  801. package/dist/config/types.d.ts.map +0 -1
  802. package/dist/config/types.js.map +0 -1
  803. package/dist/config/validation.d.ts.map +0 -1
  804. package/dist/config/validation.js.map +0 -1
  805. package/dist/config-test.d.ts +0 -20
  806. package/dist/config-test.d.ts.map +0 -1
  807. package/dist/config-test.js +0 -49
  808. package/dist/config-test.js.map +0 -1
  809. package/dist/config.d.ts.map +0 -1
  810. package/dist/config.js.map +0 -1
  811. package/dist/content-id-index.d.ts.map +0 -1
  812. package/dist/content-id-index.js.map +0 -1
  813. package/dist/content-index-generation.d.ts.map +0 -1
  814. package/dist/content-index-generation.js.map +0 -1
  815. package/dist/content-index-registry.d.ts.map +0 -1
  816. package/dist/content-index-registry.js.map +0 -1
  817. package/dist/content-listing.d.ts.map +0 -1
  818. package/dist/content-listing.js.map +0 -1
  819. package/dist/content-reader.d.ts.map +0 -1
  820. package/dist/content-reader.js.map +0 -1
  821. package/dist/content-store.d.ts.map +0 -1
  822. package/dist/content-store.js.map +0 -1
  823. package/dist/content-tree.d.ts.map +0 -1
  824. package/dist/content-tree.js.map +0 -1
  825. package/dist/context.d.ts.map +0 -1
  826. package/dist/context.js.map +0 -1
  827. package/dist/dev-content-watcher.d.ts.map +0 -1
  828. package/dist/dev-content-watcher.js.map +0 -1
  829. package/dist/editor/BranchManager.d.ts.map +0 -1
  830. package/dist/editor/BranchManager.js.map +0 -1
  831. package/dist/editor/CanopyEditor.d.ts.map +0 -1
  832. package/dist/editor/CanopyEditor.js.map +0 -1
  833. package/dist/editor/CanopyEditorPage.d.ts.map +0 -1
  834. package/dist/editor/CanopyEditorPage.js.map +0 -1
  835. package/dist/editor/CommentsPanel.d.ts.map +0 -1
  836. package/dist/editor/CommentsPanel.js.map +0 -1
  837. package/dist/editor/Editor.d.ts.map +0 -1
  838. package/dist/editor/Editor.js.map +0 -1
  839. package/dist/editor/EditorPanes.d.ts.map +0 -1
  840. package/dist/editor/EditorPanes.js.map +0 -1
  841. package/dist/editor/EntryNavigator.d.ts.map +0 -1
  842. package/dist/editor/EntryNavigator.js.map +0 -1
  843. package/dist/editor/FormRenderer.d.ts.map +0 -1
  844. package/dist/editor/FormRenderer.js.map +0 -1
  845. package/dist/editor/GroupManager.d.ts.map +0 -1
  846. package/dist/editor/GroupManager.js.map +0 -1
  847. package/dist/editor/PermissionManager.d.ts.map +0 -1
  848. package/dist/editor/PermissionManager.js.map +0 -1
  849. package/dist/editor/admin/SystemHealthPanel.d.ts.map +0 -1
  850. package/dist/editor/admin/SystemHealthPanel.js.map +0 -1
  851. package/dist/editor/admin/useSystemHealth.d.ts.map +0 -1
  852. package/dist/editor/admin/useSystemHealth.js.map +0 -1
  853. package/dist/editor/canopy-path.d.ts.map +0 -1
  854. package/dist/editor/canopy-path.js.map +0 -1
  855. package/dist/editor/client-reference-resolver.d.ts.map +0 -1
  856. package/dist/editor/client-reference-resolver.js.map +0 -1
  857. package/dist/editor/comments/BranchComments.d.ts.map +0 -1
  858. package/dist/editor/comments/BranchComments.js.map +0 -1
  859. package/dist/editor/comments/EntryComments.d.ts.map +0 -1
  860. package/dist/editor/comments/EntryComments.js.map +0 -1
  861. package/dist/editor/comments/FieldWrapper.d.ts.map +0 -1
  862. package/dist/editor/comments/FieldWrapper.js.map +0 -1
  863. package/dist/editor/comments/InlineCommentThread.d.ts.map +0 -1
  864. package/dist/editor/comments/InlineCommentThread.js.map +0 -1
  865. package/dist/editor/comments/ThreadCarousel.d.ts.map +0 -1
  866. package/dist/editor/comments/ThreadCarousel.js.map +0 -1
  867. package/dist/editor/components/ConfirmDeleteModal.d.ts.map +0 -1
  868. package/dist/editor/components/ConfirmDeleteModal.js.map +0 -1
  869. package/dist/editor/components/EditorFooter.d.ts.map +0 -1
  870. package/dist/editor/components/EditorFooter.js.map +0 -1
  871. package/dist/editor/components/EditorHeader.d.ts.map +0 -1
  872. package/dist/editor/components/EditorHeader.js.map +0 -1
  873. package/dist/editor/components/EditorSidebar.d.ts.map +0 -1
  874. package/dist/editor/components/EditorSidebar.js.map +0 -1
  875. package/dist/editor/components/EntryCreateModal.d.ts.map +0 -1
  876. package/dist/editor/components/EntryCreateModal.js.map +0 -1
  877. package/dist/editor/components/RenameEntryModal.d.ts.map +0 -1
  878. package/dist/editor/components/RenameEntryModal.js.map +0 -1
  879. package/dist/editor/components/UserBadge.d.ts.map +0 -1
  880. package/dist/editor/components/UserBadge.js.map +0 -1
  881. package/dist/editor/components/index.d.ts.map +0 -1
  882. package/dist/editor/components/index.js.map +0 -1
  883. package/dist/editor/context/ApiClientContext.d.ts.map +0 -1
  884. package/dist/editor/context/ApiClientContext.js.map +0 -1
  885. package/dist/editor/context/AssetContext.d.ts.map +0 -1
  886. package/dist/editor/context/AssetContext.js.map +0 -1
  887. package/dist/editor/context/EditorStateContext.d.ts.map +0 -1
  888. package/dist/editor/context/EditorStateContext.js.map +0 -1
  889. package/dist/editor/context/SWRProvider.d.ts.map +0 -1
  890. package/dist/editor/context/SWRProvider.js.map +0 -1
  891. package/dist/editor/context/index.d.ts.map +0 -1
  892. package/dist/editor/context/index.js.map +0 -1
  893. package/dist/editor/editor-config.d.ts.map +0 -1
  894. package/dist/editor/editor-config.js.map +0 -1
  895. package/dist/editor/editor-utils.d.ts.map +0 -1
  896. package/dist/editor/editor-utils.js.map +0 -1
  897. package/dist/editor/fields/BlockField.d.ts.map +0 -1
  898. package/dist/editor/fields/BlockField.js.map +0 -1
  899. package/dist/editor/fields/CodeField.d.ts.map +0 -1
  900. package/dist/editor/fields/CodeField.js.map +0 -1
  901. package/dist/editor/fields/DateTimeField.d.ts.map +0 -1
  902. package/dist/editor/fields/DateTimeField.js.map +0 -1
  903. package/dist/editor/fields/ImageField.d.ts.map +0 -1
  904. package/dist/editor/fields/ImageField.js.map +0 -1
  905. package/dist/editor/fields/InlineGroupField.d.ts.map +0 -1
  906. package/dist/editor/fields/InlineGroupField.js.map +0 -1
  907. package/dist/editor/fields/MarkdownField.d.ts.map +0 -1
  908. package/dist/editor/fields/MarkdownField.js.map +0 -1
  909. package/dist/editor/fields/MdxImageDialog.d.ts.map +0 -1
  910. package/dist/editor/fields/MdxImageDialog.js.map +0 -1
  911. package/dist/editor/fields/NumberField.d.ts.map +0 -1
  912. package/dist/editor/fields/NumberField.js.map +0 -1
  913. package/dist/editor/fields/NumberListField.d.ts.map +0 -1
  914. package/dist/editor/fields/NumberListField.js.map +0 -1
  915. package/dist/editor/fields/ObjectField.d.ts.map +0 -1
  916. package/dist/editor/fields/ObjectField.js.map +0 -1
  917. package/dist/editor/fields/ReferenceField.d.ts.map +0 -1
  918. package/dist/editor/fields/ReferenceField.js.map +0 -1
  919. package/dist/editor/fields/SelectField.d.ts.map +0 -1
  920. package/dist/editor/fields/SelectField.js.map +0 -1
  921. package/dist/editor/fields/StringListField.d.ts.map +0 -1
  922. package/dist/editor/fields/StringListField.js.map +0 -1
  923. package/dist/editor/fields/TextField.d.ts.map +0 -1
  924. package/dist/editor/fields/TextField.js.map +0 -1
  925. package/dist/editor/fields/ToggleField.d.ts.map +0 -1
  926. package/dist/editor/fields/ToggleField.js.map +0 -1
  927. package/dist/editor/fields/entry-link/EntryLinkContext.d.ts.map +0 -1
  928. package/dist/editor/fields/entry-link/EntryLinkContext.js.map +0 -1
  929. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts.map +0 -1
  930. package/dist/editor/fields/entry-link/InsertEntryLink.js.map +0 -1
  931. package/dist/editor/fields/entry-link/index.d.ts.map +0 -1
  932. package/dist/editor/fields/entry-link/index.js.map +0 -1
  933. package/dist/editor/group-manager/ExternalGroupsTab.d.ts.map +0 -1
  934. package/dist/editor/group-manager/ExternalGroupsTab.js.map +0 -1
  935. package/dist/editor/group-manager/GroupCard.d.ts.map +0 -1
  936. package/dist/editor/group-manager/GroupCard.js.map +0 -1
  937. package/dist/editor/group-manager/GroupForm.d.ts.map +0 -1
  938. package/dist/editor/group-manager/GroupForm.js.map +0 -1
  939. package/dist/editor/group-manager/InternalGroupsTab.d.ts.map +0 -1
  940. package/dist/editor/group-manager/InternalGroupsTab.js.map +0 -1
  941. package/dist/editor/group-manager/MemberList.d.ts.map +0 -1
  942. package/dist/editor/group-manager/MemberList.js.map +0 -1
  943. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts.map +0 -1
  944. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js.map +0 -1
  945. package/dist/editor/group-manager/hooks/useGroupState.d.ts.map +0 -1
  946. package/dist/editor/group-manager/hooks/useGroupState.js.map +0 -1
  947. package/dist/editor/group-manager/hooks/useUserSearch.d.ts.map +0 -1
  948. package/dist/editor/group-manager/hooks/useUserSearch.js.map +0 -1
  949. package/dist/editor/group-manager/index.d.ts.map +0 -1
  950. package/dist/editor/group-manager/index.js.map +0 -1
  951. package/dist/editor/group-manager/types.d.ts.map +0 -1
  952. package/dist/editor/group-manager/types.js.map +0 -1
  953. package/dist/editor/hooks/__test__/test-utils.d.ts +0 -164
  954. package/dist/editor/hooks/__test__/test-utils.d.ts.map +0 -1
  955. package/dist/editor/hooks/__test__/test-utils.js +0 -203
  956. package/dist/editor/hooks/__test__/test-utils.js.map +0 -1
  957. package/dist/editor/hooks/index.d.ts.map +0 -1
  958. package/dist/editor/hooks/index.js.map +0 -1
  959. package/dist/editor/hooks/useBranchActions.d.ts.map +0 -1
  960. package/dist/editor/hooks/useBranchActions.js.map +0 -1
  961. package/dist/editor/hooks/useBranchManager.d.ts.map +0 -1
  962. package/dist/editor/hooks/useBranchManager.js.map +0 -1
  963. package/dist/editor/hooks/useBranchesData.d.ts.map +0 -1
  964. package/dist/editor/hooks/useBranchesData.js.map +0 -1
  965. package/dist/editor/hooks/useCommentSystem.d.ts.map +0 -1
  966. package/dist/editor/hooks/useCommentSystem.js.map +0 -1
  967. package/dist/editor/hooks/useCommentsData.d.ts.map +0 -1
  968. package/dist/editor/hooks/useCommentsData.js.map +0 -1
  969. package/dist/editor/hooks/useDraftManager.d.ts.map +0 -1
  970. package/dist/editor/hooks/useDraftManager.js.map +0 -1
  971. package/dist/editor/hooks/useEditorLayout.d.ts.map +0 -1
  972. package/dist/editor/hooks/useEditorLayout.js.map +0 -1
  973. package/dist/editor/hooks/useEntriesData.d.ts.map +0 -1
  974. package/dist/editor/hooks/useEntriesData.js.map +0 -1
  975. package/dist/editor/hooks/useEntryLinkResolution.d.ts.map +0 -1
  976. package/dist/editor/hooks/useEntryLinkResolution.js.map +0 -1
  977. package/dist/editor/hooks/useEntryManager.d.ts.map +0 -1
  978. package/dist/editor/hooks/useEntryManager.js.map +0 -1
  979. package/dist/editor/hooks/useGroupManager.d.ts.map +0 -1
  980. package/dist/editor/hooks/useGroupManager.js.map +0 -1
  981. package/dist/editor/hooks/usePermissionManager.d.ts.map +0 -1
  982. package/dist/editor/hooks/usePermissionManager.js.map +0 -1
  983. package/dist/editor/hooks/useReferenceResolution.d.ts.map +0 -1
  984. package/dist/editor/hooks/useReferenceResolution.js.map +0 -1
  985. package/dist/editor/hooks/useSchemaManager.d.ts.map +0 -1
  986. package/dist/editor/hooks/useSchemaManager.js.map +0 -1
  987. package/dist/editor/hooks/useUserContext.d.ts.map +0 -1
  988. package/dist/editor/hooks/useUserContext.js.map +0 -1
  989. package/dist/editor/hooks/useUserMetadata.d.ts.map +0 -1
  990. package/dist/editor/hooks/useUserMetadata.js.map +0 -1
  991. package/dist/editor/media/AssetCard.d.ts.map +0 -1
  992. package/dist/editor/media/AssetCard.js.map +0 -1
  993. package/dist/editor/media/CropStep.d.ts.map +0 -1
  994. package/dist/editor/media/CropStep.js.map +0 -1
  995. package/dist/editor/media/MediaLibrary.d.ts.map +0 -1
  996. package/dist/editor/media/MediaLibrary.js.map +0 -1
  997. package/dist/editor/media/MediaLibraryBody.d.ts.map +0 -1
  998. package/dist/editor/media/MediaLibraryBody.js.map +0 -1
  999. package/dist/editor/media/crop-math.d.ts.map +0 -1
  1000. package/dist/editor/media/crop-math.js.map +0 -1
  1001. package/dist/editor/media/upload-asset.d.ts.map +0 -1
  1002. package/dist/editor/media/upload-asset.js.map +0 -1
  1003. package/dist/editor/media/upload-constants.d.ts.map +0 -1
  1004. package/dist/editor/media/upload-constants.js.map +0 -1
  1005. package/dist/editor/media/useAssetUpload.d.ts.map +0 -1
  1006. package/dist/editor/media/useAssetUpload.js.map +0 -1
  1007. package/dist/editor/media/xhr-upload.d.ts.map +0 -1
  1008. package/dist/editor/media/xhr-upload.js.map +0 -1
  1009. package/dist/editor/permission-manager/GroupSelector.d.ts.map +0 -1
  1010. package/dist/editor/permission-manager/GroupSelector.js.map +0 -1
  1011. package/dist/editor/permission-manager/PermissionEditor.d.ts.map +0 -1
  1012. package/dist/editor/permission-manager/PermissionEditor.js.map +0 -1
  1013. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts.map +0 -1
  1014. package/dist/editor/permission-manager/PermissionLevelBadge.js.map +0 -1
  1015. package/dist/editor/permission-manager/PermissionTree.d.ts.map +0 -1
  1016. package/dist/editor/permission-manager/PermissionTree.js.map +0 -1
  1017. package/dist/editor/permission-manager/UserSelector.d.ts.map +0 -1
  1018. package/dist/editor/permission-manager/UserSelector.js.map +0 -1
  1019. package/dist/editor/permission-manager/constants.d.ts.map +0 -1
  1020. package/dist/editor/permission-manager/constants.js.map +0 -1
  1021. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts.map +0 -1
  1022. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js.map +0 -1
  1023. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts.map +0 -1
  1024. package/dist/editor/permission-manager/hooks/usePermissionTree.js.map +0 -1
  1025. package/dist/editor/permission-manager/index.d.ts.map +0 -1
  1026. package/dist/editor/permission-manager/index.js.map +0 -1
  1027. package/dist/editor/permission-manager/types.d.ts.map +0 -1
  1028. package/dist/editor/permission-manager/types.js.map +0 -1
  1029. package/dist/editor/permission-manager/utils.d.ts.map +0 -1
  1030. package/dist/editor/permission-manager/utils.js.map +0 -1
  1031. package/dist/editor/preview-bridge.d.ts.map +0 -1
  1032. package/dist/editor/preview-bridge.js.map +0 -1
  1033. package/dist/editor/relative-time.d.ts.map +0 -1
  1034. package/dist/editor/relative-time.js.map +0 -1
  1035. package/dist/editor/schema-editor/CollectionEditor.d.ts.map +0 -1
  1036. package/dist/editor/schema-editor/CollectionEditor.js.map +0 -1
  1037. package/dist/editor/schema-editor/EntryTypeEditor.d.ts.map +0 -1
  1038. package/dist/editor/schema-editor/EntryTypeEditor.js.map +0 -1
  1039. package/dist/editor/schema-editor/index.d.ts.map +0 -1
  1040. package/dist/editor/schema-editor/index.js.map +0 -1
  1041. package/dist/editor/setup-test-dom.d.ts +0 -1
  1042. package/dist/editor/setup-test-dom.d.ts.map +0 -1
  1043. package/dist/editor/setup-test-dom.js +0 -12
  1044. package/dist/editor/setup-test-dom.js.map +0 -1
  1045. package/dist/editor/test-setup.d.ts +0 -6
  1046. package/dist/editor/test-setup.d.ts.map +0 -1
  1047. package/dist/editor/test-setup.js +0 -42
  1048. package/dist/editor/test-setup.js.map +0 -1
  1049. package/dist/editor/theme.d.ts.map +0 -1
  1050. package/dist/editor/theme.js.map +0 -1
  1051. package/dist/editor/utils/env.d.ts.map +0 -1
  1052. package/dist/editor/utils/env.js.map +0 -1
  1053. package/dist/entry-link-resolver.d.ts.map +0 -1
  1054. package/dist/entry-link-resolver.js.map +0 -1
  1055. package/dist/entry-schema-registry.d.ts.map +0 -1
  1056. package/dist/entry-schema-registry.js.map +0 -1
  1057. package/dist/entry-schema.d.ts.map +0 -1
  1058. package/dist/entry-schema.js.map +0 -1
  1059. package/dist/git-manager.d.ts.map +0 -1
  1060. package/dist/git-manager.js.map +0 -1
  1061. package/dist/github-service.d.ts.map +0 -1
  1062. package/dist/github-service.js.map +0 -1
  1063. package/dist/http/handler.d.ts.map +0 -1
  1064. package/dist/http/handler.js.map +0 -1
  1065. package/dist/http/index.d.ts.map +0 -1
  1066. package/dist/http/index.js.map +0 -1
  1067. package/dist/http/router.d.ts.map +0 -1
  1068. package/dist/http/router.js.map +0 -1
  1069. package/dist/http/types.d.ts.map +0 -1
  1070. package/dist/http/types.js.map +0 -1
  1071. package/dist/id.d.ts.map +0 -1
  1072. package/dist/id.js.map +0 -1
  1073. package/dist/index.d.ts.map +0 -1
  1074. package/dist/index.js.map +0 -1
  1075. package/dist/operating-mode/client-safe-strategy.d.ts.map +0 -1
  1076. package/dist/operating-mode/client-safe-strategy.js.map +0 -1
  1077. package/dist/operating-mode/client-unsafe-strategy.d.ts.map +0 -1
  1078. package/dist/operating-mode/client-unsafe-strategy.js.map +0 -1
  1079. package/dist/operating-mode/client.d.ts.map +0 -1
  1080. package/dist/operating-mode/client.js.map +0 -1
  1081. package/dist/operating-mode/deployment-name-fixtures.d.ts.map +0 -1
  1082. package/dist/operating-mode/deployment-name-fixtures.js.map +0 -1
  1083. package/dist/operating-mode/deployment-name.d.ts.map +0 -1
  1084. package/dist/operating-mode/deployment-name.js.map +0 -1
  1085. package/dist/operating-mode/index.d.ts.map +0 -1
  1086. package/dist/operating-mode/index.js.map +0 -1
  1087. package/dist/operating-mode/mode-env.d.ts.map +0 -1
  1088. package/dist/operating-mode/mode-env.js.map +0 -1
  1089. package/dist/operating-mode/types.d.ts.map +0 -1
  1090. package/dist/operating-mode/types.js.map +0 -1
  1091. package/dist/paths/branch-name.d.ts.map +0 -1
  1092. package/dist/paths/branch-name.js.map +0 -1
  1093. package/dist/paths/branch.d.ts.map +0 -1
  1094. package/dist/paths/branch.js.map +0 -1
  1095. package/dist/paths/index.d.ts.map +0 -1
  1096. package/dist/paths/index.js.map +0 -1
  1097. package/dist/paths/normalize-server.d.ts.map +0 -1
  1098. package/dist/paths/normalize-server.js.map +0 -1
  1099. package/dist/paths/normalize.d.ts.map +0 -1
  1100. package/dist/paths/normalize.js.map +0 -1
  1101. package/dist/paths/resolve.d.ts.map +0 -1
  1102. package/dist/paths/resolve.js.map +0 -1
  1103. package/dist/paths/test-utils.d.ts +0 -22
  1104. package/dist/paths/test-utils.d.ts.map +0 -1
  1105. package/dist/paths/test-utils.js +0 -21
  1106. package/dist/paths/test-utils.js.map +0 -1
  1107. package/dist/paths/types.d.ts.map +0 -1
  1108. package/dist/paths/types.js.map +0 -1
  1109. package/dist/paths/validation.d.ts.map +0 -1
  1110. package/dist/paths/validation.js.map +0 -1
  1111. package/dist/reference-resolver.d.ts.map +0 -1
  1112. package/dist/reference-resolver.js.map +0 -1
  1113. package/dist/resolve-canopy-user.d.ts.map +0 -1
  1114. package/dist/resolve-canopy-user.js.map +0 -1
  1115. package/dist/resource-generation.d.ts.map +0 -1
  1116. package/dist/resource-generation.js.map +0 -1
  1117. package/dist/schema/index.d.ts.map +0 -1
  1118. package/dist/schema/index.js.map +0 -1
  1119. package/dist/schema/meta-loader.d.ts.map +0 -1
  1120. package/dist/schema/meta-loader.js.map +0 -1
  1121. package/dist/schema/resolver.d.ts.map +0 -1
  1122. package/dist/schema/resolver.js.map +0 -1
  1123. package/dist/schema/schema-store-types.d.ts.map +0 -1
  1124. package/dist/schema/schema-store-types.js.map +0 -1
  1125. package/dist/schema/schema-store.d.ts.map +0 -1
  1126. package/dist/schema/schema-store.js.map +0 -1
  1127. package/dist/schema/types.d.ts.map +0 -1
  1128. package/dist/schema/types.js.map +0 -1
  1129. package/dist/server.d.ts.map +0 -1
  1130. package/dist/server.js.map +0 -1
  1131. package/dist/services.d.ts.map +0 -1
  1132. package/dist/services.js.map +0 -1
  1133. package/dist/settings-workspace.d.ts.map +0 -1
  1134. package/dist/settings-workspace.js.map +0 -1
  1135. package/dist/static/index.d.ts.map +0 -1
  1136. package/dist/static/index.js.map +0 -1
  1137. package/dist/sync-core.d.ts.map +0 -1
  1138. package/dist/sync-core.js.map +0 -1
  1139. package/dist/task-queue/index.d.ts.map +0 -1
  1140. package/dist/task-queue/index.js.map +0 -1
  1141. package/dist/task-queue/task-queue.d.ts.map +0 -1
  1142. package/dist/task-queue/task-queue.js.map +0 -1
  1143. package/dist/task-queue/types.d.ts.map +0 -1
  1144. package/dist/task-queue/types.js.map +0 -1
  1145. package/dist/types.d.ts.map +0 -1
  1146. package/dist/types.js.map +0 -1
  1147. package/dist/url-path-resolver.d.ts.map +0 -1
  1148. package/dist/url-path-resolver.js.map +0 -1
  1149. package/dist/user.d.ts.map +0 -1
  1150. package/dist/user.js.map +0 -1
  1151. package/dist/utils/async-mutex.d.ts.map +0 -1
  1152. package/dist/utils/async-mutex.js.map +0 -1
  1153. package/dist/utils/atomic-write.d.ts.map +0 -1
  1154. package/dist/utils/atomic-write.js.map +0 -1
  1155. package/dist/utils/body-field.d.ts.map +0 -1
  1156. package/dist/utils/body-field.js.map +0 -1
  1157. package/dist/utils/content-write-lock.d.ts.map +0 -1
  1158. package/dist/utils/content-write-lock.js.map +0 -1
  1159. package/dist/utils/debug.d.ts.map +0 -1
  1160. package/dist/utils/debug.js.map +0 -1
  1161. package/dist/utils/entry-url.d.ts.map +0 -1
  1162. package/dist/utils/entry-url.js.map +0 -1
  1163. package/dist/utils/error.d.ts.map +0 -1
  1164. package/dist/utils/error.js.map +0 -1
  1165. package/dist/utils/flatten-group-fields.d.ts.map +0 -1
  1166. package/dist/utils/flatten-group-fields.js.map +0 -1
  1167. package/dist/utils/format.d.ts.map +0 -1
  1168. package/dist/utils/format.js.map +0 -1
  1169. package/dist/utils/fs.d.ts.map +0 -1
  1170. package/dist/utils/fs.js.map +0 -1
  1171. package/dist/utils/git.d.ts.map +0 -1
  1172. package/dist/utils/git.js.map +0 -1
  1173. package/dist/utils/logger.d.ts.map +0 -1
  1174. package/dist/utils/logger.js.map +0 -1
  1175. package/dist/utils/occ-json-write.d.ts.map +0 -1
  1176. package/dist/utils/occ-json-write.js.map +0 -1
  1177. package/dist/utils/provisioning-lock.d.ts.map +0 -1
  1178. package/dist/utils/provisioning-lock.js.map +0 -1
  1179. package/dist/utils/sanitize-href.d.ts.map +0 -1
  1180. package/dist/utils/sanitize-href.js.map +0 -1
  1181. package/dist/utils/title-field.d.ts.map +0 -1
  1182. package/dist/utils/title-field.js.map +0 -1
  1183. package/dist/validation/deletion-checker.d.ts.map +0 -1
  1184. package/dist/validation/deletion-checker.js.map +0 -1
  1185. package/dist/validation/entry-link-validator.d.ts.map +0 -1
  1186. package/dist/validation/entry-link-validator.js.map +0 -1
  1187. package/dist/validation/entry-type-reference-validator.d.ts.map +0 -1
  1188. package/dist/validation/entry-type-reference-validator.js.map +0 -1
  1189. package/dist/validation/entry-validator.d.ts.map +0 -1
  1190. package/dist/validation/entry-validator.js.map +0 -1
  1191. package/dist/validation/field-traversal.d.ts.map +0 -1
  1192. package/dist/validation/field-traversal.js.map +0 -1
  1193. package/dist/validation/reference-validator.d.ts.map +0 -1
  1194. package/dist/validation/reference-validator.js.map +0 -1
  1195. package/dist/worker/cms-worker.d.ts.map +0 -1
  1196. package/dist/worker/cms-worker.js.map +0 -1
  1197. package/dist/worker/log.d.ts.map +0 -1
  1198. package/dist/worker/log.js.map +0 -1
  1199. package/dist/worker/task-queue-config.d.ts.map +0 -1
  1200. package/dist/worker/task-queue-config.js.map +0 -1
  1201. package/dist/worker/task-queue.d.ts.map +0 -1
  1202. package/dist/worker/task-queue.js.map +0 -1
  1203. package/dist/worker/worker-status.d.ts.map +0 -1
  1204. package/dist/worker/worker-status.js.map +0 -1
@@ -8,12 +8,27 @@ var __export = (target, all) => {
8
8
  __defProp(target, name, { get: all[name], enumerable: true });
9
9
  };
10
10
 
11
+ // dist/utils/logger.js
12
+ function canopyLogWarn(...args) {
13
+ active.warn(...args);
14
+ }
15
+ function canopyLogError(...args) {
16
+ active.error(...args);
17
+ }
18
+ var active;
19
+ var init_logger = __esm({
20
+ "dist/utils/logger.js"() {
21
+ "use strict";
22
+ active = console;
23
+ }
24
+ });
25
+
11
26
  // dist/paths/normalize.js
12
- function normalizeFilesystemPath(path20) {
13
- return path20.split(/[\\/]+/).filter(Boolean).join("/");
27
+ function normalizeFilesystemPath(path21) {
28
+ return path21.split(/[\\/]+/).filter(Boolean).join("/");
14
29
  }
15
- function hasTraversalSequence(path20) {
16
- const normalized = normalizeFilesystemPath(path20);
30
+ function hasTraversalSequence(path21) {
31
+ const normalized = normalizeFilesystemPath(path21);
17
32
  return normalized.includes("..");
18
33
  }
19
34
  function createLogicalPath(...segments) {
@@ -23,14 +38,14 @@ function createLogicalPath(...segments) {
23
38
  }
24
39
  return normalized;
25
40
  }
26
- function trimSlashes(path20) {
41
+ function trimSlashes(path21) {
27
42
  let start = 0;
28
- let end = path20.length;
29
- while (start < end && path20[start] === "/")
43
+ let end = path21.length;
44
+ while (start < end && path21[start] === "/")
30
45
  start++;
31
- while (end > start && path20[end - 1] === "/")
46
+ while (end > start && path21[end - 1] === "/")
32
47
  end--;
33
- return path20.slice(start, end);
48
+ return path21.slice(start, end);
34
49
  }
35
50
  var init_normalize = __esm({
36
51
  "dist/paths/normalize.js"() {
@@ -38,21 +53,6 @@ var init_normalize = __esm({
38
53
  }
39
54
  });
40
55
 
41
- // dist/utils/logger.js
42
- function canopyLogWarn(...args) {
43
- active.warn(...args);
44
- }
45
- function canopyLogError(...args) {
46
- active.error(...args);
47
- }
48
- var active;
49
- var init_logger = __esm({
50
- "dist/utils/logger.js"() {
51
- "use strict";
52
- active = console;
53
- }
54
- });
55
-
56
56
  // dist/paths/types.js
57
57
  var ROOT_COLLECTION_ID;
58
58
  var init_types = __esm({
@@ -239,7 +239,12 @@ var init_field = __esm({
239
239
  collections: z2.array(z2.string().min(1)).min(1).optional(),
240
240
  entryTypes: z2.array(z2.string().min(1)).min(1).optional(),
241
241
  displayField: z2.string().min(1).optional(),
242
- options: z2.array(referenceOptionSchema).optional()
242
+ options: z2.array(referenceOptionSchema).optional(),
243
+ // Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
244
+ // default, so a consumer that adopts this schema's parse output would silently delete a
245
+ // runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
246
+ // absent on purpose — it is type-inference-only and stripping it changes no behavior.)
247
+ includeBody: z2.boolean().optional()
243
248
  });
244
249
  fieldHolder = [z2.never()];
245
250
  blockSchema = z2.object({
@@ -349,7 +354,7 @@ var init_media = __esm({
349
354
 
350
355
  // dist/config/schemas/config.js
351
356
  import { z as z5 } from "zod";
352
- var defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE;
357
+ var defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, basePathSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE;
353
358
  var init_config = __esm({
354
359
  "dist/config/schemas/config.js"() {
355
360
  "use strict";
@@ -373,6 +378,9 @@ var init_config = __esm({
373
378
  deployedAsSchema = z5.enum(["static", "server"]).default("server");
374
379
  contentRootSchema = relativePathSchema.default("content");
375
380
  sourceRootSchema = z5.string().min(1).optional();
381
+ basePathSchema = z5.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
382
+ message: "basePath must not be empty or only whitespace"
383
+ }).optional();
376
384
  deploymentNameSchema = z5.string().default("prod");
377
385
  devContentSyncSchema = z5.enum(["off", "warn"]).default("warn");
378
386
  devConfigSchema = z5.object({
@@ -435,6 +443,7 @@ var init_config = __esm({
435
443
  deploymentName: deploymentNameSchema.optional(),
436
444
  contentRoot: contentRootSchema.default("content"),
437
445
  sourceRoot: sourceRootSchema.optional(),
446
+ basePath: basePathSchema,
438
447
  editor: editorConfigSchema.optional(),
439
448
  authPlugin: z5.custom().optional(),
440
449
  entryLinkUrl: z5.custom().optional(),
@@ -672,7 +681,7 @@ var init_config2 = __esm({
672
681
  });
673
682
 
674
683
  // dist/operating-mode/client-unsafe-strategy.js
675
- import path8 from "node:path";
684
+ import path9 from "node:path";
676
685
  function operatingStrategy(mode) {
677
686
  const cached = strategyCache.get(mode);
678
687
  if (cached)
@@ -710,32 +719,32 @@ var init_client_unsafe_strategy = __esm({
710
719
  // - shouldCommit(), shouldPush()
711
720
  // Add client-unsafe methods (use Node.js APIs)
712
721
  getWorkspaceRoot(_sourceRoot) {
713
- return path8.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE);
722
+ return path9.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE);
714
723
  }
715
724
  getContentRoot(contentRoot, sourceRoot) {
716
- return path8.resolve(sourceRoot ?? process.cwd(), contentRoot);
725
+ return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
717
726
  }
718
727
  getContentBranchesRoot(sourceRoot) {
719
- return path8.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
728
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
720
729
  }
721
730
  getContentBranchRoot(branchName, sourceRoot) {
722
- return path8.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
731
+ return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
723
732
  }
724
733
  getGitExcludePattern() {
725
734
  return ".canopy-meta/";
726
735
  }
727
736
  getPermissionsFilePath(root) {
728
- return path8.join(root, this.getPermissionsFileName());
737
+ return path9.join(root, this.getPermissionsFileName());
729
738
  }
730
739
  getGroupsFilePath(root) {
731
- return path8.join(root, this.getGroupsFileName());
740
+ return path9.join(root, this.getGroupsFileName());
732
741
  }
733
742
  getRemoteUrlConfig() {
734
743
  return {
735
744
  shouldAutoInitLocal: false,
736
745
  defaultRemotePath: "",
737
746
  envVarName: "CANOPYCMS_REMOTE_URL",
738
- autoDetectRemotePath: path8.join(this.getWorkspaceRoot(), "remote.git")
747
+ autoDetectRemotePath: path9.join(this.getWorkspaceRoot(), "remote.git")
739
748
  };
740
749
  }
741
750
  requiresExistingRepo() {
@@ -747,7 +756,7 @@ var init_client_unsafe_strategy = __esm({
747
756
  return `canopycms-settings-${resolveDeploymentName(config, "prod")}`;
748
757
  }
749
758
  getSettingsRoot(sourceRoot) {
750
- return path8.join(this.getWorkspaceRoot(sourceRoot), "settings");
759
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
751
760
  }
752
761
  usesSeparateSettingsBranch() {
753
762
  return true;
@@ -764,25 +773,25 @@ var init_client_unsafe_strategy = __esm({
764
773
  DevStrategy = class extends DevClientSafeStrategy {
765
774
  // Inherits client-safe methods from DevClientSafeStrategy
766
775
  getWorkspaceRoot(sourceRoot) {
767
- return path8.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
776
+ return path9.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
768
777
  }
769
778
  getContentRoot(contentRoot, sourceRoot) {
770
- return path8.resolve(sourceRoot ?? process.cwd(), contentRoot);
779
+ return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
771
780
  }
772
781
  getContentBranchesRoot(sourceRoot) {
773
- return path8.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
782
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
774
783
  }
775
784
  getContentBranchRoot(branchName, sourceRoot) {
776
- return path8.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
785
+ return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
777
786
  }
778
787
  getGitExcludePattern() {
779
788
  return ".canopy-meta/";
780
789
  }
781
790
  getPermissionsFilePath(root) {
782
- return path8.join(root, this.getPermissionsFileName());
791
+ return path9.join(root, this.getPermissionsFileName());
783
792
  }
784
793
  getGroupsFilePath(root) {
785
- return path8.join(root, this.getGroupsFileName());
794
+ return path9.join(root, this.getGroupsFileName());
786
795
  }
787
796
  getRemoteUrlConfig() {
788
797
  return {
@@ -800,7 +809,7 @@ var init_client_unsafe_strategy = __esm({
800
809
  return `canopycms-settings-${resolveDeploymentName(config, "local")}`;
801
810
  }
802
811
  getSettingsRoot(sourceRoot) {
803
- return path8.join(this.getWorkspaceRoot(sourceRoot), "settings");
812
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
804
813
  }
805
814
  usesSeparateSettingsBranch() {
806
815
  return true;
@@ -839,18 +848,38 @@ var init_operating_mode = __esm({
839
848
  });
840
849
 
841
850
  // dist/cli/generate-ai-content.js
842
- import path19 from "node:path";
851
+ import path20 from "node:path";
843
852
  import { createJiti } from "jiti";
844
853
 
845
854
  // dist/build/generate-ai-content.js
846
- import fs16 from "node:fs/promises";
847
- import path18 from "node:path";
855
+ import fs17 from "node:fs/promises";
856
+ import path19 from "node:path";
857
+
858
+ // dist/utils/error.js
859
+ function getErrorMessage(err) {
860
+ if (err instanceof Error) {
861
+ return err.message;
862
+ }
863
+ if (typeof err === "string") {
864
+ return err;
865
+ }
866
+ return String(err);
867
+ }
868
+ function isNodeError(err) {
869
+ return err instanceof Error && "code" in err;
870
+ }
871
+ function isNotFoundError(err) {
872
+ return isNodeError(err) && err.code === "ENOENT";
873
+ }
874
+ function isFileExistsError(err) {
875
+ return isNodeError(err) && err.code === "EEXIST";
876
+ }
848
877
 
849
878
  // dist/content-store.js
850
- import fs9 from "node:fs/promises";
851
- import path10 from "node:path";
852
- import matter from "gray-matter";
853
- import { parse as yamlParse, stringify as yamlStringify } from "yaml";
879
+ import fs10 from "node:fs/promises";
880
+ import path11 from "node:path";
881
+ import matter2 from "gray-matter";
882
+ import { parse as yamlParse } from "yaml";
854
883
 
855
884
  // dist/utils/atomic-write.js
856
885
  import fs from "node:fs/promises";
@@ -869,6 +898,207 @@ async function atomicWriteFile(filePath, content) {
869
898
  }
870
899
  }
871
900
 
901
+ // dist/utils/content-serialize.js
902
+ import matter from "gray-matter";
903
+ import { isCollection, isMap, isNode, isScalar, isSeq, parseDocument, stringify as yamlStringify } from "yaml";
904
+
905
+ // dist/validation/block-structural-keys.js
906
+ var BLOCK_DISCRIMINATOR_KEYS = ["template", "_type"];
907
+ var BLOCK_STRUCTURAL_KEYS = new Set(BLOCK_DISCRIMINATOR_KEYS);
908
+ function isBlockStructuralKey(key) {
909
+ return BLOCK_STRUCTURAL_KEYS.has(key);
910
+ }
911
+
912
+ // dist/utils/content-serialize.js
913
+ function isPlainRecord(value) {
914
+ if (typeof value !== "object" || value === null || Array.isArray(value))
915
+ return false;
916
+ const proto = Object.getPrototypeOf(value);
917
+ return proto === Object.prototype || proto === null;
918
+ }
919
+ function recordKeyOf(keyNode) {
920
+ if (!isScalar(keyNode))
921
+ return void 0;
922
+ const { value } = keyNode;
923
+ if (value === null || value === void 0)
924
+ return void 0;
925
+ if (typeof value === "object")
926
+ return void 0;
927
+ return String(value);
928
+ }
929
+ function carryComments(from, to) {
930
+ if (!isNode(from) || !isNode(to))
931
+ return;
932
+ const source = from;
933
+ const target = to;
934
+ if (source.commentBefore !== void 0)
935
+ target.commentBefore = source.commentBefore;
936
+ if (source.comment !== void 0)
937
+ target.comment = source.comment;
938
+ if (source.spaceBefore !== void 0)
939
+ target.spaceBefore = source.spaceBefore;
940
+ }
941
+ function identityKey(value) {
942
+ try {
943
+ return JSON.stringify(value) ?? "undefined";
944
+ } catch {
945
+ return void 0;
946
+ }
947
+ }
948
+ function nodePlainValue(node) {
949
+ if (!isNode(node))
950
+ return node;
951
+ try {
952
+ return node.toJSON();
953
+ } catch {
954
+ return void 0;
955
+ }
956
+ }
957
+ function nodeIdentityKey(node) {
958
+ const plain = nodePlainValue(node);
959
+ return plain === void 0 && isNode(node) ? void 0 : identityKey(plain);
960
+ }
961
+ var EVIDENCE_MAX_DEPTH = 6;
962
+ function sharesFieldEvidence(existing, value, depth) {
963
+ for (const key of Object.keys(value)) {
964
+ if (isBlockStructuralKey(key))
965
+ continue;
966
+ if (!Object.prototype.hasOwnProperty.call(existing, key))
967
+ continue;
968
+ const before = existing[key];
969
+ const after = value[key];
970
+ if (depth < EVIDENCE_MAX_DEPTH && isPlainRecord(before) && isPlainRecord(after) && sharesFieldEvidence(before, after, depth + 1)) {
971
+ return true;
972
+ }
973
+ const beforeKey = identityKey(before);
974
+ if (beforeKey !== void 0 && beforeKey === identityKey(after))
975
+ return true;
976
+ }
977
+ return false;
978
+ }
979
+ function looksLikeSameItem(node, value) {
980
+ const existing = nodePlainValue(node);
981
+ if (!isPlainRecord(existing) || !isPlainRecord(value))
982
+ return true;
983
+ return sharesFieldEvidence(existing, value, 0);
984
+ }
985
+ function reconcileNode(doc, existing, value) {
986
+ if (isMap(existing) && isPlainRecord(value)) {
987
+ reconcileMap(doc, existing, value);
988
+ return existing;
989
+ }
990
+ if (isSeq(existing) && Array.isArray(value)) {
991
+ reconcileSeq(doc, existing, value);
992
+ return existing;
993
+ }
994
+ if (isScalar(existing) && Object.is(existing.value, value))
995
+ return existing;
996
+ const fresh = doc.createNode(value);
997
+ if (!isCollection(existing))
998
+ carryComments(existing, fresh);
999
+ return fresh;
1000
+ }
1001
+ function reconcileMap(doc, map, value) {
1002
+ const wanted = new Set(Object.keys(value).filter((key) => value[key] !== void 0));
1003
+ const seen = /* @__PURE__ */ new Set();
1004
+ const retained = [];
1005
+ for (const pair of map.items) {
1006
+ const key = recordKeyOf(pair.key);
1007
+ if (key === void 0 || !wanted.has(key) || seen.has(key))
1008
+ continue;
1009
+ seen.add(key);
1010
+ pair.value = reconcileNode(doc, pair.value, value[key]);
1011
+ retained.push(pair);
1012
+ }
1013
+ map.items = retained;
1014
+ for (const key of Object.keys(value)) {
1015
+ if (seen.has(key) || !wanted.has(key))
1016
+ continue;
1017
+ map.set(doc.createNode(key), doc.createNode(value[key]));
1018
+ }
1019
+ }
1020
+ function reconcileSeq(doc, seq, value) {
1021
+ const oldItems = seq.items;
1022
+ const byIdentity = /* @__PURE__ */ new Map();
1023
+ oldItems.forEach((node, index) => {
1024
+ const key = nodeIdentityKey(node);
1025
+ if (key === void 0)
1026
+ return;
1027
+ const bucket = byIdentity.get(key);
1028
+ if (bucket)
1029
+ bucket.push(index);
1030
+ else
1031
+ byIdentity.set(key, [index]);
1032
+ });
1033
+ const consumed = /* @__PURE__ */ new Set();
1034
+ const matches = value.map((item) => {
1035
+ const key = identityKey(item);
1036
+ if (key === void 0)
1037
+ return void 0;
1038
+ const bucket = byIdentity.get(key);
1039
+ while (bucket && bucket.length > 0) {
1040
+ const index = bucket.shift();
1041
+ if (index !== void 0 && !consumed.has(index)) {
1042
+ consumed.add(index);
1043
+ return index;
1044
+ }
1045
+ }
1046
+ return void 0;
1047
+ });
1048
+ seq.items = value.map((item, index) => {
1049
+ const matched = matches[index];
1050
+ if (matched !== void 0)
1051
+ return oldItems[matched];
1052
+ const candidate = index < oldItems.length && !consumed.has(index) ? oldItems[index] : void 0;
1053
+ const sameItem = candidate !== void 0 && looksLikeSameItem(candidate, item) ? candidate : void 0;
1054
+ return reconcileNode(doc, sameItem, item);
1055
+ });
1056
+ }
1057
+ function applyDataToDocument(doc, data) {
1058
+ doc.contents = reconcileNode(doc, doc.contents, data);
1059
+ }
1060
+ function serializeYaml(data, existingRaw) {
1061
+ if (existingRaw === void 0)
1062
+ return yamlStringify(data);
1063
+ const doc = parseDocument(existingRaw);
1064
+ if (doc.errors.length > 0)
1065
+ return yamlStringify(data);
1066
+ applyDataToDocument(doc, data);
1067
+ return doc.toString();
1068
+ }
1069
+ function extractRawFrontmatter(raw) {
1070
+ let parsed;
1071
+ try {
1072
+ parsed = matter(raw, {});
1073
+ } catch {
1074
+ return void 0;
1075
+ }
1076
+ const frontmatter = parsed.matter;
1077
+ if (typeof frontmatter !== "string" || frontmatter.trim() === "")
1078
+ return void 0;
1079
+ return frontmatter;
1080
+ }
1081
+ function serializeFrontmatter(body, data, existingRaw) {
1082
+ if (existingRaw === void 0)
1083
+ return matter.stringify(body, data);
1084
+ const existingFrontmatter = extractRawFrontmatter(existingRaw);
1085
+ if (existingFrontmatter === void 0)
1086
+ return matter.stringify(body, data);
1087
+ const doc = parseDocument(existingFrontmatter);
1088
+ if (doc.errors.length > 0)
1089
+ return matter.stringify(body, data);
1090
+ applyDataToDocument(doc, data);
1091
+ const reconciled = doc.toString();
1092
+ return matter.stringify(body, data, {
1093
+ engines: {
1094
+ yaml: {
1095
+ parse: () => ({}),
1096
+ stringify: () => reconciled
1097
+ }
1098
+ }
1099
+ });
1100
+ }
1101
+
872
1102
  // dist/utils/async-mutex.js
873
1103
  var locks = /* @__PURE__ */ new Map();
874
1104
  async function withLock(key, fn) {
@@ -890,46 +1120,66 @@ async function withLock(key, fn) {
890
1120
 
891
1121
  // dist/utils/content-write-lock.js
892
1122
  import path3 from "node:path";
893
-
894
- // dist/utils/error.js
895
- function getErrorMessage(err) {
896
- if (err instanceof Error) {
897
- return err.message;
898
- }
899
- if (typeof err === "string") {
900
- return err;
901
- }
902
- return String(err);
903
- }
904
- function isNodeError(err) {
905
- return err instanceof Error && "code" in err;
906
- }
907
- function isNotFoundError(err) {
908
- return isNodeError(err) && err.code === "ENOENT";
909
- }
910
- function isFileExistsError(err) {
911
- return isNodeError(err) && err.code === "EEXIST";
912
- }
1123
+ init_logger();
913
1124
 
914
1125
  // dist/utils/provisioning-lock.js
915
1126
  import fs2 from "node:fs/promises";
916
1127
  import path2 from "node:path";
917
1128
  import lockfile from "proper-lockfile";
918
- async function acquireProvisioningLock(lockTargetDir2, lockName) {
1129
+ init_logger();
1130
+ function provisioningLockOptions(lockPath, retries, onCompromised) {
1131
+ return {
1132
+ lockfilePath: lockPath,
1133
+ realpath: false,
1134
+ retries,
1135
+ stale: 3e4,
1136
+ // proper-lockfile invokes this from inside its refresh timer, so ANY throw
1137
+ // escaping here is an uncaught exception that kills the process -- the very
1138
+ // failure the handler exists to prevent. Call sites are told not to throw
1139
+ // (see OnLockCompromised); this makes it structural rather than a
1140
+ // convention, and also covers the LOGGER throwing: under `CI=true`,
1141
+ // vitest's `onConsoleLog` turns any console write into a throw.
1142
+ onCompromised: (err) => {
1143
+ try {
1144
+ if (onCompromised) {
1145
+ onCompromised(err);
1146
+ return;
1147
+ }
1148
+ canopyLogWarn(`[canopy] Provisioning lock compromised mid-hold for ${lockPath}:`, getErrorMessage(err));
1149
+ } catch {
1150
+ try {
1151
+ process.stderr.write(`[canopy] lock compromised for ${lockPath}; its handler or logger threw
1152
+ `);
1153
+ } catch {
1154
+ }
1155
+ }
1156
+ }
1157
+ };
1158
+ }
1159
+ function releaseIgnoringAlreadyReleased(release, lockPath) {
1160
+ return async () => {
1161
+ try {
1162
+ await release();
1163
+ } catch (err) {
1164
+ if (isNodeError(err) && err.code === "ERELEASED") {
1165
+ canopyLogWarn(`[canopy] Lock at ${lockPath} was already released (compromised mid-hold, or released twice); nothing to release`);
1166
+ return;
1167
+ }
1168
+ throw err;
1169
+ }
1170
+ };
1171
+ }
1172
+ async function acquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
919
1173
  await fs2.mkdir(lockTargetDir2, { recursive: true });
920
- return lockfile.lock(lockTargetDir2, {
921
- lockfilePath: path2.join(lockTargetDir2, lockName),
922
- retries: { retries: 600, factor: 1, minTimeout: 300, maxTimeout: 800, randomize: true },
923
- stale: 3e4
924
- });
1174
+ const lockPath = path2.join(lockTargetDir2, lockName);
1175
+ const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, { retries: 600, factor: 1, minTimeout: 300, maxTimeout: 800, randomize: true }, onCompromised));
1176
+ return releaseIgnoringAlreadyReleased(release, lockPath);
925
1177
  }
926
- async function tryAcquireProvisioningLock(lockTargetDir2, lockName) {
1178
+ async function tryAcquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
927
1179
  await fs2.mkdir(lockTargetDir2, { recursive: true });
928
- return lockfile.lock(lockTargetDir2, {
929
- lockfilePath: path2.join(lockTargetDir2, lockName),
930
- retries: 0,
931
- stale: 3e4
932
- });
1180
+ const lockPath = path2.join(lockTargetDir2, lockName);
1181
+ const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, 0, onCompromised));
1182
+ return releaseIgnoringAlreadyReleased(release, lockPath);
933
1183
  }
934
1184
 
935
1185
  // dist/utils/content-write-lock.js
@@ -948,14 +1198,14 @@ function lockTargetDir(branchRoot) {
948
1198
  var sleep = (ms) => new Promise((resolve2) => {
949
1199
  setTimeout(resolve2, ms);
950
1200
  });
951
- function tryAcquireContentWriteLock(branchRoot) {
952
- return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME);
1201
+ function tryAcquireContentWriteLock(branchRoot, onCompromised) {
1202
+ return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME, onCompromised);
953
1203
  }
954
- async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
1204
+ async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, onCompromised) {
955
1205
  const startedAt = Date.now();
956
1206
  for (let attempt = 0; ; attempt++) {
957
1207
  try {
958
- return await tryAcquireContentWriteLock(branchRoot);
1208
+ return await tryAcquireContentWriteLock(branchRoot, onCompromised);
959
1209
  } catch (err) {
960
1210
  if (!isNodeError(err) || err.code !== "ELOCKED")
961
1211
  throw err;
@@ -968,12 +1218,21 @@ async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRIT
968
1218
  }
969
1219
  }
970
1220
  async function withContentWriteLock(branchRoot, fn, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
971
- const release = await acquireContentWriteLock(branchRoot, waitMs);
1221
+ let compromised = false;
1222
+ const release = await acquireContentWriteLock(branchRoot, waitMs, (err) => {
1223
+ compromised = true;
1224
+ canopyLogWarn(`[canopy] Content-write lock compromised mid-hold for ${branchRoot}:`, getErrorMessage(err));
1225
+ });
1226
+ let result;
972
1227
  try {
973
- return await fn();
1228
+ result = await fn();
974
1229
  } finally {
975
1230
  await release();
976
1231
  }
1232
+ if (compromised) {
1233
+ throw new ContentWriteLockBusyError("This branch was being synced while your change was written, so the change may or may not have been recorded. Reload the entry to see the current state before saving again.");
1234
+ }
1235
+ return result;
977
1236
  }
978
1237
 
979
1238
  // dist/utils/flatten-group-fields.js
@@ -998,6 +1257,105 @@ function findBodyFieldName(fields) {
998
1257
  return "body";
999
1258
  }
1000
1259
 
1260
+ // dist/static/seo.js
1261
+ var DEFAULT_SEO_FIELD_NAMES = {
1262
+ title: "metaTitle",
1263
+ description: "metaDescription",
1264
+ ogImage: "ogImage",
1265
+ ogType: "ogType",
1266
+ canonical: "canonical",
1267
+ noindex: "noindex",
1268
+ twitterCard: "twitterCard"
1269
+ };
1270
+
1271
+ // dist/entry-schema.js
1272
+ function buildResolvedReference(data, meta, body) {
1273
+ const resolved = { ...data };
1274
+ if (body && body.value)
1275
+ resolved[body.fieldName] = body.value;
1276
+ resolved.id = meta.id;
1277
+ resolved.slug = meta.slug;
1278
+ resolved.collection = meta.collection;
1279
+ resolved.urlPath = meta.urlPath;
1280
+ return resolved;
1281
+ }
1282
+ var SEO_GROUP_FIELDS = [
1283
+ {
1284
+ name: DEFAULT_SEO_FIELD_NAMES.title,
1285
+ type: "string",
1286
+ label: "Meta Title",
1287
+ description: "Overrides the page title in search results and social cards.",
1288
+ required: false
1289
+ },
1290
+ {
1291
+ name: DEFAULT_SEO_FIELD_NAMES.description,
1292
+ type: "string",
1293
+ label: "Meta Description",
1294
+ description: "Summary shown under the title in search results.",
1295
+ required: false
1296
+ },
1297
+ {
1298
+ name: DEFAULT_SEO_FIELD_NAMES.ogImage,
1299
+ type: "string",
1300
+ label: "Social Image URL",
1301
+ description: "Image for social cards. Site-relative or absolute.",
1302
+ required: false
1303
+ },
1304
+ {
1305
+ name: DEFAULT_SEO_FIELD_NAMES.ogType,
1306
+ type: "select",
1307
+ label: "OpenGraph Type",
1308
+ options: ["website", "article", "profile"],
1309
+ required: false
1310
+ },
1311
+ {
1312
+ name: DEFAULT_SEO_FIELD_NAMES.canonical,
1313
+ type: "string",
1314
+ label: "Canonical URL",
1315
+ description: "Set only to point at a different canonical copy of this page.",
1316
+ required: false
1317
+ },
1318
+ {
1319
+ name: DEFAULT_SEO_FIELD_NAMES.noindex,
1320
+ type: "boolean",
1321
+ label: "Hide from search engines",
1322
+ description: "Marks the page noindex AND drops it from the sitemap.",
1323
+ required: false
1324
+ },
1325
+ {
1326
+ name: DEFAULT_SEO_FIELD_NAMES.twitterCard,
1327
+ type: "select",
1328
+ label: "Twitter Card",
1329
+ options: ["summary", "summary_large_image"],
1330
+ required: false
1331
+ }
1332
+ ];
1333
+
1334
+ // dist/utils/entry-url.js
1335
+ init_normalize();
1336
+ function isIndexSlug(slug) {
1337
+ return slug?.toLowerCase() === "index";
1338
+ }
1339
+ function computeEntryUrl(collection, slug, contentRoot) {
1340
+ const root = trimSlashes(contentRoot);
1341
+ let stripped = collection;
1342
+ if (root && collection.startsWith(`${root}/`)) {
1343
+ stripped = collection.slice(root.length + 1);
1344
+ } else if (collection === root) {
1345
+ stripped = "";
1346
+ }
1347
+ const segments = stripped.split("/").filter(Boolean);
1348
+ if (slug && !isIndexSlug(slug)) {
1349
+ segments.push(slug);
1350
+ }
1351
+ const path21 = segments.length > 0 ? `/${segments.join("/")}` : "/";
1352
+ return path21.toLowerCase();
1353
+ }
1354
+
1355
+ // dist/url-collision.js
1356
+ import fs4 from "node:fs/promises";
1357
+ import path5 from "node:path";
1358
+
1001
1359
  // dist/content-id-index.js
1002
1360
  import fs3 from "node:fs/promises";
1003
1361
  import path4 from "node:path";
@@ -1013,6 +1371,37 @@ var PHYSICAL_SEGMENT_PATTERN = new RegExp(`\\.${BASE58_PATTERN}{12}(?:\\.[a-z]+)
1013
1371
  function isValidContentId(id) {
1014
1372
  return CONTENT_ID_PATTERN.test(id);
1015
1373
  }
1374
+ function parseSlug(slug) {
1375
+ if (!slug) {
1376
+ return {
1377
+ ok: false,
1378
+ error: "Slug is required"
1379
+ };
1380
+ }
1381
+ if (slug.length > 64) {
1382
+ return { ok: false, error: "Slug too long (max 64 characters)" };
1383
+ }
1384
+ if (slug.includes("/") || slug.includes("\\")) {
1385
+ return {
1386
+ ok: false,
1387
+ error: "Slug cannot contain path separators"
1388
+ };
1389
+ }
1390
+ if (slug === "." || slug === "..") {
1391
+ return {
1392
+ ok: false,
1393
+ error: "Slug cannot be a traversal sequence"
1394
+ };
1395
+ }
1396
+ const normalized = slug.toLowerCase();
1397
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
1398
+ return {
1399
+ ok: false,
1400
+ error: "Slug must start with a letter or number and contain only lowercase letters, numbers, and hyphens"
1401
+ };
1402
+ }
1403
+ return { ok: true, slug: normalized };
1404
+ }
1016
1405
 
1017
1406
  // dist/id.js
1018
1407
  function generateId() {
@@ -1357,13 +1746,13 @@ function extractIdFromFilename(filename) {
1357
1746
  return null;
1358
1747
  }
1359
1748
  async function resolveCollectionPath(root, logicalPath) {
1360
- const fs17 = await import("node:fs/promises");
1361
- const path20 = await import("node:path");
1749
+ const fs18 = await import("node:fs/promises");
1750
+ const path21 = await import("node:path");
1362
1751
  const segments = logicalPath.split("/").filter(Boolean);
1363
1752
  let currentPath = root;
1364
1753
  for (const segment of segments) {
1365
1754
  try {
1366
- const entries = await fs17.readdir(currentPath, { withFileTypes: true });
1755
+ const entries = await fs18.readdir(currentPath, { withFileTypes: true });
1367
1756
  const matchingDir = entries.find((entry) => {
1368
1757
  if (!entry.isDirectory())
1369
1758
  return false;
@@ -1371,7 +1760,7 @@ async function resolveCollectionPath(root, logicalPath) {
1371
1760
  return logicalName === segment.toLowerCase();
1372
1761
  });
1373
1762
  if (matchingDir) {
1374
- currentPath = path20.join(currentPath, matchingDir.name);
1763
+ currentPath = path21.join(currentPath, matchingDir.name);
1375
1764
  } else {
1376
1765
  return null;
1377
1766
  }
@@ -1421,8 +1810,99 @@ function extractSlugFromFilename(filename, entryTypeName) {
1421
1810
  return filename.toLowerCase();
1422
1811
  }
1423
1812
 
1813
+ // dist/utils/typed-filename.js
1814
+ var parseTypedFilename = (filename, entryTypes) => {
1815
+ if (filename.startsWith("."))
1816
+ return null;
1817
+ const lastDot = filename.lastIndexOf(".");
1818
+ if (lastDot === -1)
1819
+ return null;
1820
+ const nameWithoutExt = filename.slice(0, lastDot);
1821
+ const parts = nameWithoutExt.split(".");
1822
+ if (parts.length < 3)
1823
+ return null;
1824
+ const potentialType = parts[0];
1825
+ if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
1826
+ return null;
1827
+ }
1828
+ const id = parts[parts.length - 1];
1829
+ if (!isValidId(id))
1830
+ return null;
1831
+ const slug = parts.slice(1, -1).join(".").toLowerCase();
1832
+ return {
1833
+ type: potentialType,
1834
+ slug,
1835
+ id
1836
+ };
1837
+ };
1838
+
1839
+ // dist/url-collision.js
1840
+ var CONTENT_EXTENSIONS = [".md", ".mdx", ".json", ".yaml"];
1841
+ async function readDirSafe(dir) {
1842
+ try {
1843
+ return await fs4.readdir(dir, { withFileTypes: true });
1844
+ } catch (err) {
1845
+ if (isNotFoundError(err))
1846
+ return [];
1847
+ throw err;
1848
+ }
1849
+ }
1850
+ async function findChildCollectionDir(dir, name) {
1851
+ const wanted = name.toLowerCase();
1852
+ for (const entry of await readDirSafe(dir)) {
1853
+ if (!entry.isDirectory())
1854
+ continue;
1855
+ if (extractSlugFromFilename(entry.name) === wanted)
1856
+ return path5.join(dir, entry.name);
1857
+ }
1858
+ return null;
1859
+ }
1860
+ function entrySlugOf(filename) {
1861
+ if (!CONTENT_EXTENSIONS.some((ext) => filename.endsWith(ext)))
1862
+ return null;
1863
+ return parseTypedFilename(filename)?.slug ?? null;
1864
+ }
1865
+ async function findIndexEntryIn(dir) {
1866
+ for (const entry of await readDirSafe(dir)) {
1867
+ if (entry.isDirectory())
1868
+ continue;
1869
+ if (isIndexSlug(entrySlugOf(entry.name) ?? void 0))
1870
+ return path5.join(dir, entry.name);
1871
+ }
1872
+ return null;
1873
+ }
1874
+ async function findEntryBySlugIn(dir, slug) {
1875
+ const wanted = slug.toLowerCase();
1876
+ for (const entry of await readDirSafe(dir)) {
1877
+ if (entry.isDirectory())
1878
+ continue;
1879
+ if (entrySlugOf(entry.name) === wanted)
1880
+ return path5.join(dir, entry.name);
1881
+ }
1882
+ return null;
1883
+ }
1884
+ async function findUrlPathClaimant(opts) {
1885
+ const { collectionDir, slug, contentRoot } = opts;
1886
+ if (isIndexSlug(slug)) {
1887
+ const resolvedRoot = path5.resolve(contentRoot);
1888
+ if (path5.resolve(collectionDir) === resolvedRoot)
1889
+ return null;
1890
+ const parentDir = path5.dirname(collectionDir);
1891
+ const ownName = extractSlugFromFilename(path5.basename(collectionDir));
1892
+ if (isIndexSlug(ownName))
1893
+ return null;
1894
+ const claimant = await findEntryBySlugIn(parentDir, ownName);
1895
+ return claimant ? { kind: "parent-entry", physicalPath: claimant, name: ownName } : null;
1896
+ }
1897
+ const childDir = await findChildCollectionDir(collectionDir, slug);
1898
+ if (!childDir)
1899
+ return null;
1900
+ const indexEntry = await findIndexEntryIn(childDir);
1901
+ return indexEntry ? { kind: "sibling-collection-index", physicalPath: indexEntry, name: slug } : null;
1902
+ }
1903
+
1424
1904
  // dist/content-index-registry.js
1425
- import path5 from "node:path";
1905
+ import path6 from "node:path";
1426
1906
  var registry = /* @__PURE__ */ new Map();
1427
1907
  var finalization = new FinalizationRegistry(({ rootKey, ref }) => {
1428
1908
  const refs = registry.get(rootKey);
@@ -1433,7 +1913,7 @@ var finalization = new FinalizationRegistry(({ rootKey, ref }) => {
1433
1913
  registry.delete(rootKey);
1434
1914
  });
1435
1915
  function registerContentIndexForInvalidation(root, target) {
1436
- const rootKey = path5.resolve(root);
1916
+ const rootKey = path6.resolve(root);
1437
1917
  let refs = registry.get(rootKey);
1438
1918
  if (!refs) {
1439
1919
  refs = /* @__PURE__ */ new Set();
@@ -1444,8 +1924,8 @@ function registerContentIndexForInvalidation(root, target) {
1444
1924
  finalization.register(target, { rootKey, ref });
1445
1925
  }
1446
1926
  function invalidateContentIndexesForRoot(root) {
1447
- const rootKey = path5.resolve(root);
1448
- const prefix = rootKey + path5.sep;
1927
+ const rootKey = path6.resolve(root);
1928
+ const prefix = rootKey + path6.sep;
1449
1929
  for (const [storeRoot, refs] of registry) {
1450
1930
  if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
1451
1931
  continue;
@@ -1463,8 +1943,8 @@ function invalidateContentIndexesForRoot(root) {
1463
1943
  }
1464
1944
 
1465
1945
  // dist/resource-generation.js
1466
- import fs4 from "node:fs/promises";
1467
- import path6 from "node:path";
1946
+ import fs5 from "node:fs/promises";
1947
+ import path7 from "node:path";
1468
1948
  import { randomUUID } from "node:crypto";
1469
1949
 
1470
1950
  // dist/utils/debug.js
@@ -1573,7 +2053,7 @@ var testLogger = createDebugLogger({
1573
2053
  var log = createDebugLogger({ prefix: "ResourceGeneration" });
1574
2054
  var META_DIR2 = ".canopy-meta";
1575
2055
  function resourceGenerationPath(root, resource) {
1576
- return path6.resolve(root, META_DIR2, `${resource}.generation`);
2056
+ return path7.resolve(root, META_DIR2, `${resource}.generation`);
1577
2057
  }
1578
2058
  async function bumpResourceGeneration(root, resource, options) {
1579
2059
  const token = randomUUID();
@@ -1591,7 +2071,7 @@ async function bumpResourceGeneration(root, resource, options) {
1591
2071
  }
1592
2072
  async function readResourceGeneration(root, resource) {
1593
2073
  try {
1594
- const token = await fs4.readFile(resourceGenerationPath(root, resource), "utf-8");
2074
+ const token = await fs5.readFile(resourceGenerationPath(root, resource), "utf-8");
1595
2075
  return { ok: true, token };
1596
2076
  } catch (err) {
1597
2077
  if (isNodeError(err) && err.code === "ENOENT")
@@ -1607,11 +2087,11 @@ function isGenerationCurrent(snapshotToken, read) {
1607
2087
  }
1608
2088
 
1609
2089
  // dist/branch-schema-cache.js
1610
- import fs6 from "node:fs/promises";
1611
- import path7 from "node:path";
2090
+ import fs7 from "node:fs/promises";
2091
+ import path8 from "node:path";
1612
2092
 
1613
2093
  // dist/schema/meta-loader.js
1614
- import { promises as fs5 } from "fs";
2094
+ import { promises as fs6 } from "fs";
1615
2095
  import { join } from "pathe";
1616
2096
  import { z } from "zod";
1617
2097
  import chokidar from "chokidar";
@@ -1648,7 +2128,7 @@ function stripEmbeddedIdFromName(name) {
1648
2128
  async function scanForCollectionMeta(baseDir, relativePath = "") {
1649
2129
  const collections = [];
1650
2130
  try {
1651
- const entries = await fs5.readdir(baseDir, { withFileTypes: true });
2131
+ const entries = await fs6.readdir(baseDir, { withFileTypes: true });
1652
2132
  for (const entry of entries) {
1653
2133
  if (!entry.isDirectory())
1654
2134
  continue;
@@ -1659,8 +2139,8 @@ async function scanForCollectionMeta(baseDir, relativePath = "") {
1659
2139
  const absolutePath = join(baseDir, folderName);
1660
2140
  const metaPath = join(absolutePath, ".collection.json");
1661
2141
  try {
1662
- await fs5.access(metaPath);
1663
- const content = await fs5.readFile(metaPath, "utf-8");
2142
+ await fs6.access(metaPath);
2143
+ const content = await fs6.readFile(metaPath, "utf-8");
1664
2144
  const parsed = JSON.parse(content);
1665
2145
  const meta = collectionMetaSchema.parse(parsed);
1666
2146
  collections.push({
@@ -1692,7 +2172,7 @@ async function loadCollectionMetaFiles(contentRoot) {
1692
2172
  let root = null;
1693
2173
  const rootMetaPath = join(contentRoot, ".collection.json");
1694
2174
  try {
1695
- await fs5.access(rootMetaPath);
2175
+ await fs6.access(rootMetaPath);
1696
2176
  } catch (err) {
1697
2177
  if (err.code === "ENOENT") {
1698
2178
  } else {
@@ -1700,7 +2180,7 @@ async function loadCollectionMetaFiles(contentRoot) {
1700
2180
  }
1701
2181
  }
1702
2182
  try {
1703
- const content = await fs5.readFile(rootMetaPath, "utf-8");
2183
+ const content = await fs6.readFile(rootMetaPath, "utf-8");
1704
2184
  const parsed = JSON.parse(content);
1705
2185
  root = rootCollectionMetaSchema.parse(parsed);
1706
2186
  } catch (err) {
@@ -1887,16 +2367,16 @@ var SCHEMA_GENERATION_RESOURCE = "schema";
1887
2367
  async function isStaleByMtime(dir, cachedAt) {
1888
2368
  let entries;
1889
2369
  try {
1890
- entries = await fs6.readdir(dir, { recursive: true, encoding: "utf-8" });
2370
+ entries = await fs7.readdir(dir, { recursive: true, encoding: "utf-8" });
1891
2371
  } catch {
1892
2372
  return true;
1893
2373
  }
1894
2374
  for (const entry of entries) {
1895
2375
  if (!entry.endsWith(".collection.json"))
1896
2376
  continue;
1897
- const full = path7.join(dir, entry);
2377
+ const full = path8.join(dir, entry);
1898
2378
  try {
1899
- const stat = await fs6.stat(full);
2379
+ const stat = await fs7.stat(full);
1900
2380
  if (stat.mtimeMs > cachedAt.getTime())
1901
2381
  return true;
1902
2382
  } catch {
@@ -1920,7 +2400,7 @@ var BranchSchemaCache = class {
1920
2400
  * the project root, regardless of which entrypoint produced the cwd branchRoot.
1921
2401
  */
1922
2402
  skipDiskCache(branchRoot) {
1923
- return isBuildMode() || path7.resolve(branchRoot) === path7.resolve(process.cwd());
2403
+ return isBuildMode() || path8.resolve(branchRoot) === path8.resolve(process.cwd());
1924
2404
  }
1925
2405
  /**
1926
2406
  * Get schema for a branch (loads from cache or resolves fresh).
@@ -1946,14 +2426,14 @@ var BranchSchemaCache = class {
1946
2426
  * Load schema from cache or resolve fresh if cache is missing or stale.
1947
2427
  */
1948
2428
  async loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName) {
1949
- const contentRoot = path7.join(branchRoot, contentRootName);
2429
+ const contentRoot = path8.join(branchRoot, contentRootName);
1950
2430
  const skipDiskCache = this.skipDiskCache(branchRoot);
1951
2431
  if (!skipDiskCache) {
1952
- const cacheDir = path7.join(branchRoot, ".canopy-meta");
1953
- const cachePath = path7.join(cacheDir, "schema-cache.json");
2432
+ const cacheDir = path8.join(branchRoot, ".canopy-meta");
2433
+ const cachePath = path8.join(cacheDir, "schema-cache.json");
1954
2434
  let cacheData = null;
1955
2435
  try {
1956
- const cacheContent = await fs6.readFile(cachePath, "utf-8");
2436
+ const cacheContent = await fs7.readFile(cachePath, "utf-8");
1957
2437
  cacheData = JSON.parse(cacheContent);
1958
2438
  } catch {
1959
2439
  cacheData = null;
@@ -1990,7 +2470,7 @@ var BranchSchemaCache = class {
1990
2470
  */
1991
2471
  async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
1992
2472
  const { skipDiskCache } = options;
1993
- const contentRoot = path7.join(branchRoot, contentRootName);
2473
+ const contentRoot = path8.join(branchRoot, contentRootName);
1994
2474
  const read = skipDiskCache ? null : await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
1995
2475
  const result = await this.resolveFresh(contentRoot, entrySchemaRegistry);
1996
2476
  if (!isValidSchema(result.schema)) {
@@ -2003,9 +2483,9 @@ var BranchSchemaCache = class {
2003
2483
  }
2004
2484
  const flatSchema = flattenSchema(result.schema, contentRootName);
2005
2485
  if (!skipDiskCache) {
2006
- const cacheDir = path7.join(branchRoot, ".canopy-meta");
2007
- const cachePath = path7.join(cacheDir, "schema-cache.json");
2008
- await fs6.unlink(path7.join(cacheDir, "schema-cache.stale")).catch(() => {
2486
+ const cacheDir = path8.join(branchRoot, ".canopy-meta");
2487
+ const cachePath = path8.join(cacheDir, "schema-cache.json");
2488
+ await fs7.unlink(path8.join(cacheDir, "schema-cache.stale")).catch(() => {
2009
2489
  });
2010
2490
  if (read && read.ok) {
2011
2491
  const newCache = {
@@ -2015,13 +2495,13 @@ var BranchSchemaCache = class {
2015
2495
  cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
2016
2496
  generation: read.token
2017
2497
  };
2018
- await fs6.mkdir(cacheDir, { recursive: true });
2019
- const tmpPath = path7.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
2020
- await fs6.writeFile(tmpPath, JSON.stringify(newCache, null, 2), "utf-8");
2498
+ await fs7.mkdir(cacheDir, { recursive: true });
2499
+ const tmpPath = path8.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
2500
+ await fs7.writeFile(tmpPath, JSON.stringify(newCache, null, 2), "utf-8");
2021
2501
  try {
2022
- await fs6.rename(tmpPath, cachePath);
2502
+ await fs7.rename(tmpPath, cachePath);
2023
2503
  } catch (err) {
2024
- await fs6.unlink(tmpPath).catch(() => {
2504
+ await fs7.unlink(tmpPath).catch(() => {
2025
2505
  });
2026
2506
  throw err;
2027
2507
  }
@@ -2093,10 +2573,10 @@ async function invalidateBranchContentCaches(root) {
2093
2573
  }
2094
2574
 
2095
2575
  // dist/utils/fs.js
2096
- import fs7 from "node:fs/promises";
2576
+ import fs8 from "node:fs/promises";
2097
2577
  async function filePathExists(filePath) {
2098
2578
  try {
2099
- await fs7.stat(filePath);
2579
+ await fs8.stat(filePath);
2100
2580
  return true;
2101
2581
  } catch (err) {
2102
2582
  if (isNotFoundError(err))
@@ -2104,6 +2584,15 @@ async function filePathExists(filePath) {
2104
2584
  throw err;
2105
2585
  }
2106
2586
  }
2587
+ async function readFileIfExists(filePath) {
2588
+ try {
2589
+ return await fs8.readFile(filePath, "utf8");
2590
+ } catch (err) {
2591
+ if (isNotFoundError(err))
2592
+ return void 0;
2593
+ throw err;
2594
+ }
2595
+ }
2107
2596
 
2108
2597
  // dist/utils/format.js
2109
2598
  var getFormatExtension = (format) => {
@@ -2142,8 +2631,8 @@ function validateAndNormalizePath(root, target) {
2142
2631
 
2143
2632
  // dist/paths/branch.js
2144
2633
  init_operating_mode();
2145
- import fs8 from "node:fs/promises";
2146
- import path9 from "node:path";
2634
+ import fs9 from "node:fs/promises";
2635
+ import path10 from "node:path";
2147
2636
 
2148
2637
  // dist/paths/branch-name.js
2149
2638
  function sanitizeBranchName(branchName) {
@@ -2166,11 +2655,11 @@ function resolveBranchPath(options) {
2166
2655
  const safeBranch = sanitizeBranchName(options.branchName);
2167
2656
  const strategy = operatingStrategy(options.mode);
2168
2657
  const baseRoot = resolveContentBranchesRoot(options.mode, options.basePathOverride);
2169
- const normalizedBase = path9.resolve(baseRoot);
2170
- const baseWithSep = normalizedBase.endsWith(path9.sep) ? normalizedBase : `${normalizedBase}${path9.sep}`;
2658
+ const normalizedBase = path10.resolve(baseRoot);
2659
+ const baseWithSep = normalizedBase.endsWith(path10.sep) ? normalizedBase : `${normalizedBase}${path10.sep}`;
2171
2660
  const branchRoot = strategy.getContentBranchRoot(safeBranch, options.basePathOverride);
2172
2661
  const withinBase = (target) => {
2173
- const resolved = path9.resolve(target);
2662
+ const resolved = path10.resolve(target);
2174
2663
  return resolved === normalizedBase || resolved.startsWith(baseWithSep);
2175
2664
  };
2176
2665
  if (!withinBase(branchRoot)) {
@@ -2180,7 +2669,7 @@ function resolveBranchPath(options) {
2180
2669
  }
2181
2670
  async function ensureBranchRoot(options) {
2182
2671
  const result = resolveBranchPath(options);
2183
- await fs8.mkdir(result.branchRoot, { recursive: true });
2672
+ await fs9.mkdir(result.branchRoot, { recursive: true });
2184
2673
  return result;
2185
2674
  }
2186
2675
 
@@ -2226,6 +2715,13 @@ var DuplicateContentIdError = class extends ContentConflictError {
2226
2715
  this.paths = sorted;
2227
2716
  }
2228
2717
  };
2718
+ var UrlPathConflictError = class extends ContentConflictError {
2719
+ constructor(message, conflictingPath) {
2720
+ super(message);
2721
+ this.name = "UrlPathConflictError";
2722
+ this.conflictingPath = conflictingPath;
2723
+ }
2724
+ };
2229
2725
  function getDefaultEntryType(entries) {
2230
2726
  if (!entries || entries.length === 0)
2231
2727
  return void 0;
@@ -2242,6 +2738,7 @@ function validateSlug(slug) {
2242
2738
  var DEFAULT_INDEX_FRESHNESS_INTERVAL_MS = 1e3;
2243
2739
  var FORCED_REFRESH_MIN_INTERVAL_MS = 5e3;
2244
2740
  var STALE_LOOKUP = Symbol("stale-index-lookup");
2741
+ var createReferenceResolveCache = () => /* @__PURE__ */ new Map();
2245
2742
  var ContentStore = class {
2246
2743
  constructor(root, flatSchema, options = {}) {
2247
2744
  this.indexGeneration = 0;
@@ -2250,7 +2747,7 @@ var ContentStore = class {
2250
2747
  this.lastDiskProbeMs = 0;
2251
2748
  this.lastForcedRefreshMs = 0;
2252
2749
  this.indexBuild = null;
2253
- this.root = path10.resolve(root);
2750
+ this.root = path11.resolve(root);
2254
2751
  this.contentRootName = options.contentRootName || "content";
2255
2752
  this.indexFreshnessIntervalMs = options.indexFreshnessIntervalMs ?? DEFAULT_INDEX_FRESHNESS_INTERVAL_MS;
2256
2753
  this.contentWriteLockWaitMs = options.contentWriteLockWaitMs ?? DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS;
@@ -2398,7 +2895,7 @@ var ContentStore = class {
2398
2895
  async findEntryPathsById(dir, id) {
2399
2896
  let entries;
2400
2897
  try {
2401
- entries = await fs9.readdir(dir, { withFileTypes: true });
2898
+ entries = await fs10.readdir(dir, { withFileTypes: true });
2402
2899
  } catch (err) {
2403
2900
  if (isNodeError(err) && err.code === "ENOENT")
2404
2901
  return [];
@@ -2409,7 +2906,7 @@ var ContentStore = class {
2409
2906
  if (entry.isDirectory())
2410
2907
  continue;
2411
2908
  if (extractIdFromFilename(entry.name) === id) {
2412
- matches.push(path10.relative(this.root, path10.join(dir, entry.name)));
2909
+ matches.push(path11.relative(this.root, path11.join(dir, entry.name)));
2413
2910
  }
2414
2911
  }
2415
2912
  return matches.sort();
@@ -2421,11 +2918,11 @@ var ContentStore = class {
2421
2918
  getSchemaItems() {
2422
2919
  return this.schemaIndex.values();
2423
2920
  }
2424
- assertSchemaItem(path20) {
2425
- const normalized = normalizeFilesystemPath(path20);
2921
+ assertSchemaItem(path21) {
2922
+ const normalized = normalizeFilesystemPath(path21);
2426
2923
  const item = this.schemaIndex.get(normalized);
2427
2924
  if (!item) {
2428
- throw new ContentStoreError(`Unknown schema item: ${path20}`, "NO_SCHEMA_ITEM");
2925
+ throw new ContentStoreError(`Unknown schema item: ${path21}`, "NO_SCHEMA_ITEM");
2429
2926
  }
2430
2927
  return item;
2431
2928
  }
@@ -2492,6 +2989,26 @@ var ContentStore = class {
2492
2989
  return this.createLockKey(schemaItem, slug);
2493
2990
  return prePass.id ? this.idLockKey(prePass.id) : prePass.absolutePath;
2494
2991
  }
2992
+ /**
2993
+ * Refuse a create/rename that would give a second entry a `urlPath` another entry already
2994
+ * holds. See url-collision.ts for the two shapes that count, and the legitimate
2995
+ * landing-page-beside-a-collection shape that deliberately does not.
2996
+ *
2997
+ * @param collectionDir Absolute physical directory the entry will live in.
2998
+ * @param slug The entry's slug, as it will be written.
2999
+ */
3000
+ async assertUrlPathAvailable(collectionDir, slug) {
3001
+ const claimant = await findUrlPathClaimant({
3002
+ collectionDir,
3003
+ slug,
3004
+ contentRoot: path11.resolve(this.root, this.contentRootName)
3005
+ });
3006
+ if (!claimant)
3007
+ return;
3008
+ const relative2 = path11.relative(this.root, claimant.physicalPath);
3009
+ const message = claimant.kind === "sibling-collection-index" ? `An entry with slug "${slug}" would share a URL with the index entry of the "${claimant.name}" collection beside it ("${relative2}"), and only one of them could be served there. Rename this entry, or remove that collection's index entry.` : `An index entry here would share a URL with the "${claimant.name}" entry in the parent collection ("${relative2}"), and only one of them could be served there. Rename that entry, or give this collection's landing page a different slug.`;
3010
+ throw new UrlPathConflictError(message, claimant.physicalPath);
3011
+ }
2495
3012
  /**
2496
3013
  * Build absolute and relative paths with security validation.
2497
3014
  * All entries use the unified filename pattern: {type}.{slug}.{id}.{ext}
@@ -2508,7 +3025,7 @@ var ContentStore = class {
2508
3025
  * @param options.entryTypeName - For collections with multiple entry types, specify which one to use. Defaults to the default entry type.
2509
3026
  */
2510
3027
  async buildPaths(schemaItem, slug, options = {}) {
2511
- const rootWithSep = this.root.endsWith(path10.sep) ? this.root : `${this.root}${path10.sep}`;
3028
+ const rootWithSep = this.root.endsWith(path11.sep) ? this.root : `${this.root}${path11.sep}`;
2512
3029
  if (schemaItem.type === "entry-type") {
2513
3030
  const parentPath = schemaItem.parentPath || "";
2514
3031
  const parentCollection = this.schemaIndex.get(parentPath);
@@ -2541,7 +3058,7 @@ var ContentStore = class {
2541
3058
  const entryTypeName = entryTypeConfig?.name || "entry";
2542
3059
  let collectionRoot = await resolveCollectionPath(this.root, schemaItem.logicalPath);
2543
3060
  if (!collectionRoot) {
2544
- collectionRoot = path10.resolve(this.root, schemaItem.logicalPath);
3061
+ collectionRoot = path11.resolve(this.root, schemaItem.logicalPath);
2545
3062
  }
2546
3063
  if (!collectionRoot.startsWith(rootWithSep)) {
2547
3064
  throw new ContentStoreError("Path traversal detected", "VALIDATION");
@@ -2551,7 +3068,7 @@ var ContentStore = class {
2551
3068
  let existingEntryType;
2552
3069
  let foundExisting = false;
2553
3070
  if (!id) {
2554
- const entries = await fs9.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
3071
+ const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
2555
3072
  const existingFile = entries.find((entry) => {
2556
3073
  if (entry.isDirectory())
2557
3074
  return false;
@@ -2577,14 +3094,14 @@ var ContentStore = class {
2577
3094
  }
2578
3095
  filename = `${finalEntryTypeName}.${safeSlug}.${id}${ext}`;
2579
3096
  }
2580
- const resolved = path10.resolve(collectionRoot, filename);
2581
- const collectionRootWithSep = collectionRoot.endsWith(path10.sep) ? collectionRoot : `${collectionRoot}${path10.sep}`;
3097
+ const resolved = path11.resolve(collectionRoot, filename);
3098
+ const collectionRootWithSep = collectionRoot.endsWith(path11.sep) ? collectionRoot : `${collectionRoot}${path11.sep}`;
2582
3099
  if (!resolved.startsWith(collectionRootWithSep)) {
2583
3100
  throw new ContentStoreError("Path traversal detected", "VALIDATION");
2584
3101
  }
2585
3102
  return {
2586
3103
  absolutePath: resolved,
2587
- relativePath: path10.relative(this.root, resolved),
3104
+ relativePath: path11.relative(this.root, resolved),
2588
3105
  id,
2589
3106
  entryTypeName: finalEntryTypeName,
2590
3107
  existed
@@ -2620,8 +3137,8 @@ var ContentStore = class {
2620
3137
  async read(collectionPath, slug = "", options = {}) {
2621
3138
  const schemaItem = this.assertSchemaItem(collectionPath);
2622
3139
  const { absolutePath, relativePath, entryTypeName: resolvedEntryTypeName } = await this.buildPaths(schemaItem, slug);
2623
- const stat = await fs9.stat(absolutePath);
2624
- const raw = await fs9.readFile(absolutePath, "utf8");
3140
+ const stat = await fs10.stat(absolutePath);
3141
+ const raw = await fs10.readFile(absolutePath, "utf8");
2625
3142
  let doc;
2626
3143
  let format;
2627
3144
  let fields;
@@ -2660,7 +3177,7 @@ var ContentStore = class {
2660
3177
  absolutePath
2661
3178
  };
2662
3179
  } else {
2663
- const parsed = matter(raw);
3180
+ const parsed = matter2(raw);
2664
3181
  doc = {
2665
3182
  collection: schemaItem.logicalPath,
2666
3183
  collectionName: schemaItem.name,
@@ -2723,7 +3240,7 @@ var ContentStore = class {
2723
3240
  const indexedPath = guardIndex.findById(id)?.relativePath ?? null;
2724
3241
  if (indexedPath && indexedPath !== relativePath) {
2725
3242
  const quarantined = guardIndex.getDuplicateFor(id);
2726
- const bothOnDisk = await filePathExists(absolutePath) && await filePathExists(path10.join(this.root, indexedPath));
3243
+ const bothOnDisk = await filePathExists(absolutePath) && await filePathExists(path11.join(this.root, indexedPath));
2727
3244
  if (quarantined || bothOnDisk) {
2728
3245
  throw new DuplicateContentIdError(id, [
2729
3246
  indexedPath,
@@ -2734,10 +3251,18 @@ var ContentStore = class {
2734
3251
  }
2735
3252
  }
2736
3253
  }
2737
- await fs9.mkdir(path10.dirname(absolutePath), { recursive: true });
3254
+ if (!await filePathExists(absolutePath)) {
3255
+ const chosenSlug = extractSlugFromFilename(path11.basename(absolutePath));
3256
+ const routable = parseSlug(chosenSlug);
3257
+ if (!routable.ok) {
3258
+ throw new ContentStoreError(`Cannot create entry "${chosenSlug}": ${routable.error}. An entry whose slug is not addressable as a URL segment would build and then 404 on every visit.`, "VALIDATION");
3259
+ }
3260
+ await this.assertUrlPathAvailable(path11.dirname(absolutePath), chosenSlug);
3261
+ }
3262
+ await fs10.mkdir(path11.dirname(absolutePath), { recursive: true });
2738
3263
  if (input.expectedVersion !== void 0) {
2739
3264
  try {
2740
- const existing = await fs9.stat(absolutePath);
3265
+ const existing = await fs10.stat(absolutePath);
2741
3266
  if (input.expectedVersion === null) {
2742
3267
  throw new ContentConflictError("An entry with this slug already exists");
2743
3268
  }
@@ -2754,7 +3279,7 @@ var ContentStore = class {
2754
3279
  }
2755
3280
  }
2756
3281
  if (existingId && !await filePathExists(absolutePath)) {
2757
- const actualRelPaths = await this.findEntryPathsById(path10.dirname(absolutePath), existingId);
3282
+ const actualRelPaths = await this.findEntryPathsById(path11.dirname(absolutePath), existingId);
2758
3283
  if (actualRelPaths.length > 1) {
2759
3284
  throw new DuplicateContentIdError(existingId, actualRelPaths);
2760
3285
  }
@@ -2764,14 +3289,15 @@ var ContentStore = class {
2764
3289
  throw new ContentConflictError();
2765
3290
  }
2766
3291
  }
3292
+ const existingRaw = input.format === "json" ? void 0 : await readFileIfExists(absolutePath);
2767
3293
  let content;
2768
3294
  if (input.format === "json") {
2769
3295
  content = `${JSON.stringify(input.data ?? {}, null, 2)}
2770
3296
  `;
2771
3297
  } else if (input.format === "yaml") {
2772
- content = yamlStringify(input.data ?? {});
3298
+ content = serializeYaml(input.data ?? {}, existingRaw);
2773
3299
  } else {
2774
- content = matter.stringify(input.body, input.data ?? {});
3300
+ content = serializeFrontmatter(input.body, input.data ?? {}, existingRaw);
2775
3301
  }
2776
3302
  await atomicWriteFile(absolutePath, content);
2777
3303
  const liveIndex = this._idIndex;
@@ -2780,7 +3306,7 @@ var ContentStore = class {
2780
3306
  const existing = liveIndex.findById(id);
2781
3307
  if (existing) {
2782
3308
  if (existing.relativePath !== relativePath) {
2783
- staleOldAbsPath = path10.join(this.root, existing.relativePath);
3309
+ staleOldAbsPath = path11.join(this.root, existing.relativePath);
2784
3310
  liveIndex.updatePath(existing.id, relativePath);
2785
3311
  }
2786
3312
  } else {
@@ -2793,13 +3319,13 @@ var ContentStore = class {
2793
3319
  }
2794
3320
  }
2795
3321
  if (staleOldAbsPath) {
2796
- await fs9.unlink(staleOldAbsPath).catch((err) => {
3322
+ await fs10.unlink(staleOldAbsPath).catch((err) => {
2797
3323
  if (!isNodeError(err) || err.code !== "ENOENT")
2798
3324
  throw err;
2799
3325
  });
2800
3326
  }
2801
3327
  await this.recordOwnMutation(liveIndex);
2802
- const afterStat = await fs9.stat(absolutePath);
3328
+ const afterStat = await fs10.stat(absolutePath);
2803
3329
  const base = {
2804
3330
  collection: schemaItem.logicalPath,
2805
3331
  collectionName: schemaItem.name,
@@ -2877,7 +3403,7 @@ var ContentStore = class {
2877
3403
  const schemaItem = this.assertSchemaItem(collectionPath);
2878
3404
  const { absolutePath } = await this.buildPaths(schemaItem, slug);
2879
3405
  try {
2880
- await fs9.access(absolutePath);
3406
+ await fs10.access(absolutePath);
2881
3407
  return true;
2882
3408
  } catch (err) {
2883
3409
  if (isNodeError(err) && err.code === "ENOENT")
@@ -2916,7 +3442,7 @@ var ContentStore = class {
2916
3442
  const collectionRoot = await resolveCollectionPath(this.root, collectionPath);
2917
3443
  if (!collectionRoot)
2918
3444
  return 0;
2919
- const entries = await fs9.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
3445
+ const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
2920
3446
  return entries.filter((entry) => !entry.isDirectory() && extractEntryTypeFromFilename(entry.name) === entryTypeName).length;
2921
3447
  }
2922
3448
  /**
@@ -2940,7 +3466,7 @@ var ContentStore = class {
2940
3466
  const collection = this.assertCollection(collectionPath);
2941
3467
  const prePass = await this.buildPaths(collection, slug);
2942
3468
  if (!prePass.existed) {
2943
- await fs9.unlink(prePass.absolutePath);
3469
+ await fs10.unlink(prePass.absolutePath);
2944
3470
  return;
2945
3471
  }
2946
3472
  let lockKey = this.entryLockKey(collection, slug, prePass);
@@ -2956,7 +3482,7 @@ var ContentStore = class {
2956
3482
  return RETRY_KEY;
2957
3483
  }
2958
3484
  const { absolutePath, relativePath } = inLock;
2959
- await fs9.unlink(absolutePath);
3485
+ await fs10.unlink(absolutePath);
2960
3486
  const liveIndex = this._idIndex;
2961
3487
  const id = liveIndex.findByPath(relativePath);
2962
3488
  if (id) {
@@ -2992,6 +3518,10 @@ var ContentStore = class {
2992
3518
  if (currentSlug === safeNewSlug) {
2993
3519
  return { newPath: `${collectionPath}/${currentSlug}` };
2994
3520
  }
3521
+ const routable = parseSlug(safeNewSlug);
3522
+ if (!routable.ok) {
3523
+ throw new ContentStoreError(`Cannot rename to "${safeNewSlug}": ${routable.error}. An entry whose slug is not addressable as a URL segment would build and then 404 on every visit.`, "VALIDATION");
3524
+ }
2995
3525
  const prePass = await this.buildPaths(collection, currentSlug);
2996
3526
  if (!prePass.existed) {
2997
3527
  throw new ContentStoreError(`Entry not found: ${currentSlug}`, "NOT_FOUND");
@@ -3018,7 +3548,7 @@ var ContentStore = class {
3018
3548
  }
3019
3549
  destLockKey = currentDestKey;
3020
3550
  const { absolutePath: currentPath, relativePath: currentRelPath } = inLock;
3021
- const currentFilename = path10.basename(currentPath);
3551
+ const currentFilename = path11.basename(currentPath);
3022
3552
  const parts = currentFilename.split(".");
3023
3553
  if (parts.length < 4) {
3024
3554
  throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}`, "VALIDATION");
@@ -3027,10 +3557,10 @@ var ContentStore = class {
3027
3557
  const contentId = parts[parts.length - 2];
3028
3558
  const ext = `.${parts[parts.length - 1]}`;
3029
3559
  const newFilename = `${entryTypeName}.${safeNewSlug}.${contentId}${ext}`;
3030
- const parentDir = path10.dirname(currentPath);
3031
- const newPath = path10.join(parentDir, newFilename);
3560
+ const parentDir = path11.dirname(currentPath);
3561
+ const newPath = path11.join(parentDir, newFilename);
3032
3562
  try {
3033
- const entries = await fs9.readdir(parentDir, { withFileTypes: true });
3563
+ const entries = await fs10.readdir(parentDir, { withFileTypes: true });
3034
3564
  for (const entry of entries) {
3035
3565
  if (entry.isDirectory())
3036
3566
  continue;
@@ -3043,16 +3573,17 @@ var ContentStore = class {
3043
3573
  if (err instanceof ContentStoreError)
3044
3574
  throw err;
3045
3575
  }
3576
+ await this.assertUrlPathAvailable(parentDir, safeNewSlug);
3046
3577
  try {
3047
- await fs9.link(currentPath, newPath);
3578
+ await fs10.link(currentPath, newPath);
3048
3579
  } catch (err) {
3049
3580
  if (isNodeError(err) && err.code === "EEXIST") {
3050
3581
  throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"`, "VALIDATION");
3051
3582
  }
3052
3583
  throw err;
3053
3584
  }
3054
- await fs9.unlink(currentPath);
3055
- const newRelativePath = path10.relative(this.root, newPath);
3585
+ await fs10.unlink(currentPath);
3586
+ const newRelativePath = path11.relative(this.root, newPath);
3056
3587
  const liveIndex = this._idIndex;
3057
3588
  const entryId = liveIndex.findByPath(currentRelPath);
3058
3589
  if (entryId) {
@@ -3124,34 +3655,57 @@ var ContentStore = class {
3124
3655
  }
3125
3656
  return entries;
3126
3657
  }
3658
+ /**
3659
+ * Resolve every `reference` field in `data` against `fields`, returning a copy.
3660
+ *
3661
+ * This is what `read()` applies automatically (unless `resolveReferences: false`), exposed
3662
+ * so BATCH surfaces can opt into the same resolution without duplicating the walk: the
3663
+ * listing primitives in content-listing.ts and content-tree.ts read entry files straight
3664
+ * off disk and never touch this store, so before this existed a `reference` field reached
3665
+ * `listEntries()`/`buildContentTree()` callers as a bare id string or `null`.
3666
+ *
3667
+ * Pass one {@link ReferenceResolveCache} across a whole batch so a target referenced by
3668
+ * many entries is read once rather than once per referencing entry. Omit `cache` and the
3669
+ * behavior is exactly what `read()` has always done, unmemoized.
3670
+ *
3671
+ * **Path ACLs are not consulted for the targets.** Resolution goes through this store's
3672
+ * own `read()`, below the per-entry permission check in content-reader.ts — so a resolved
3673
+ * target may be an entry the caller could not `read()` directly. That is pre-existing
3674
+ * `read()` behavior, matched here on purpose so one rule covers both; see the
3675
+ * `resolveReferences` option in content-listing.ts for the note adopters see.
3676
+ */
3677
+ async resolveReferences(data, fields, cache) {
3678
+ return this.resolveReferencesInData(data, fields, cache);
3679
+ }
3127
3680
  /**
3128
3681
  * Recursively resolve reference fields in data.
3129
3682
  * This traverses objects, arrays, and blocks to find and resolve all reference fields.
3130
3683
  */
3131
- async resolveReferencesInData(data, fields) {
3684
+ async resolveReferencesInData(data, fields, cache) {
3132
3685
  const resolved = { ...data };
3133
3686
  const idIndex = await this.idIndex();
3134
3687
  for (const field of fields) {
3135
3688
  if (field.type === "group") {
3136
- const groupResolved = await this.resolveReferencesInData(resolved, field.fields);
3689
+ const groupResolved = await this.resolveReferencesInData(resolved, field.fields, cache);
3137
3690
  Object.assign(resolved, groupResolved);
3138
3691
  continue;
3139
3692
  }
3140
3693
  const value = data[field.name];
3141
3694
  if (field.type === "reference") {
3695
+ const includeBody = field.includeBody === true;
3142
3696
  if (typeof value === "string" && value) {
3143
- resolved[field.name] = await this.resolveSingleReference(value, idIndex);
3697
+ resolved[field.name] = await this.resolveSingleReference(value, idIndex, includeBody, cache);
3144
3698
  } else if (field.list && Array.isArray(value)) {
3145
- resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex) : null));
3699
+ resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex, includeBody, cache) : null));
3146
3700
  }
3147
3701
  } else if (field.type === "object" && value) {
3148
3702
  const objectField = field;
3149
3703
  if (!objectField.fields)
3150
3704
  continue;
3151
3705
  if (objectField.list && Array.isArray(value)) {
3152
- resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields) : item));
3706
+ resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields, cache) : item));
3153
3707
  } else if (typeof value === "object") {
3154
- resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields);
3708
+ resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields, cache);
3155
3709
  }
3156
3710
  } else if (field.type === "block" && Array.isArray(value)) {
3157
3711
  const blockField = field;
@@ -3164,7 +3718,7 @@ var ContentStore = class {
3164
3718
  return block;
3165
3719
  return {
3166
3720
  ...b,
3167
- value: await this.resolveReferencesInData(b.value, template.fields)
3721
+ value: await this.resolveReferencesInData(b.value, template.fields, cache)
3168
3722
  };
3169
3723
  }));
3170
3724
  }
@@ -3172,7 +3726,56 @@ var ContentStore = class {
3172
3726
  return resolved;
3173
3727
  }
3174
3728
  /**
3175
- * Resolve a single reference ID to full entry data.
3729
+ * Resolve a single reference ID to full entry data, memoized when a batch cache is
3730
+ * supplied. Without a cache this is a straight pass-through to the uncached path, so
3731
+ * `read()` behaves exactly as it always has.
3732
+ *
3733
+ * Every occurrence gets its OWN deep copy, even on a cache hit. Without that, the memo
3734
+ * would hand one shared object to all 40 entries referencing the same block — a mutation
3735
+ * in one caller's `extract` (truncating a body for a search index, deleting a field) would
3736
+ * silently rewrite it for every sibling, and both `list: true` elements of `[id, id]` would
3737
+ * be the same instance. The copy is what keeps the cache a pure performance optimization
3738
+ * instead of a semantic change.
3739
+ *
3740
+ * Note the uncached path is NOT the clean baseline it looks like. For a json/yaml target it
3741
+ * genuinely reparses fresh per occurrence, but for md/mdx gray-matter serves `data` from a
3742
+ * process-global content-keyed cache, so `resolveSingleReferenceOnce`'s top-level spread
3743
+ * severs exactly one level and NESTED frontmatter objects alias across occurrences, calls and
3744
+ * requests. That is pre-existing `read()` behavior and out of scope here — deliberately, since
3745
+ * touching it would change `read()` — but it means the cached path is the safer of the two,
3746
+ * not a relaxation of a guarantee the uncached one provides. See
3747
+ * `.claude/future-tasks/graymatter-cache-shared-frontmatter.md`.
3748
+ *
3749
+ * What the copy costs, measured rather than assumed (2000 occurrences of one target, local
3750
+ * disk, so every read hits the page cache — the friendliest possible case for NOT caching):
3751
+ * a snippet-sized target is ~63x cheaper to clone than to re-read-and-parse, while a 265KB
3752
+ * JSON target is ~0.8x, i.e. cloning is marginally SLOWER than reparsing it. So the win is
3753
+ * large in the case this exists for and roughly a wash at the pathological end, never a
3754
+ * blow-up. Two things keep the bad end narrow: an md/mdx target resolves to its FRONTMATTER
3755
+ * only *unless the field sets `includeBody`* (`read()` puts the body on `doc.body`, which
3756
+ * `resolveSingleReferenceOnce` spreads in only for an embedding field), so by default body
3757
+ * size is irrelevant no matter how long the document and only a genuinely huge JSON/YAML
3758
+ * target reaches the wash. **`includeBody: true` is the case that CAN reach it on markdown**:
3759
+ * the body then sits inside the memoized object and is cloned once per referencing entry, so
3760
+ * a long document embedded by many pages pays that repeatedly — the reason `includeBody`
3761
+ * exists as an opt-in per field rather than as resolution's default. And in the deployment this
3762
+ * targets, content lives on EFS/NFS where the syscall the memo removes dominates parse and
3763
+ * clone alike, which the local-disk numbers above understate badly. Correctness is the
3764
+ * reason for the copy regardless; the numbers are here so nobody has to re-derive them
3765
+ * before touching this.
3766
+ */
3767
+ resolveSingleReference(id, idIndex, includeBody, cache) {
3768
+ if (!cache)
3769
+ return this.resolveSingleReferenceUncached(id, idIndex, includeBody);
3770
+ const key = includeBody ? `${id}:body` : id;
3771
+ let pending = cache.get(key);
3772
+ if (!pending) {
3773
+ pending = this.resolveSingleReferenceUncached(id, idIndex, includeBody);
3774
+ cache.set(key, pending);
3775
+ }
3776
+ return pending.then((resolved) => resolved === null ? null : structuredClone(resolved));
3777
+ }
3778
+ /**
3176
3779
  * Returns null if the reference is invalid or missing.
3177
3780
  * Includes id, slug, and collection fields for debugging.
3178
3781
  *
@@ -3186,16 +3789,21 @@ var ContentStore = class {
3186
3789
  * idIndex() dedupes concurrent builds — so a sibling call that wins the
3187
3790
  * throttle and rebuilds heals every other miss in the same batch, not just
3188
3791
  * the first.
3792
+ *
3793
+ * A {@link ReferenceResolveCache} sits ABOVE this, never inside it, so every
3794
+ * distinct id still runs the full refresh-and-retry above. What a cache changes
3795
+ * is only that repeats of the SAME id in one batch share that one attempt's
3796
+ * outcome instead of each getting an independent throw of the dice.
3189
3797
  */
3190
- async resolveSingleReference(id, idIndex) {
3191
- const first = await this.resolveSingleReferenceOnce(id, idIndex);
3798
+ async resolveSingleReferenceUncached(id, idIndex, includeBody) {
3799
+ const first = await this.resolveSingleReferenceOnce(id, idIndex, includeBody);
3192
3800
  if (first !== STALE_LOOKUP)
3193
3801
  return first;
3194
3802
  await this.refreshIndexForSuspiciousLookup();
3195
- const second = await this.resolveSingleReferenceOnce(id, await this.idIndex());
3803
+ const second = await this.resolveSingleReferenceOnce(id, await this.idIndex(), includeBody);
3196
3804
  return second === STALE_LOOKUP ? null : second;
3197
3805
  }
3198
- async resolveSingleReferenceOnce(id, idIndex) {
3806
+ async resolveSingleReferenceOnce(id, idIndex, includeBody) {
3199
3807
  try {
3200
3808
  const location = idIndex.findById(id);
3201
3809
  if (!location)
@@ -3206,12 +3814,13 @@ var ContentStore = class {
3206
3814
  const doc = await this.read(location.collection, location.slug, {
3207
3815
  resolveReferences: false
3208
3816
  });
3209
- return {
3817
+ const bodyForEmbed = includeBody && "body" in doc ? { fieldName: doc.bodyFieldName, value: doc.body } : void 0;
3818
+ return buildResolvedReference(doc.data, {
3210
3819
  id,
3211
3820
  slug: location.slug,
3212
3821
  collection: location.collection,
3213
- ...doc.data
3214
- };
3822
+ urlPath: computeEntryUrl(location.collection, location.slug, this.contentRootName)
3823
+ }, bodyForEmbed);
3215
3824
  } catch (error) {
3216
3825
  if (isNodeError(error) && error.code === "ENOENT")
3217
3826
  return STALE_LOOKUP;
@@ -3222,8 +3831,8 @@ var ContentStore = class {
3222
3831
  };
3223
3832
 
3224
3833
  // dist/ai/generate.js
3225
- import path11 from "node:path";
3226
- import fs10 from "node:fs/promises";
3834
+ import path12 from "node:path";
3835
+ import fs11 from "node:fs/promises";
3227
3836
  import { minimatch } from "minimatch";
3228
3837
 
3229
3838
  // dist/ai/strip-mdx.js
@@ -3298,14 +3907,44 @@ var BLOCK_RESTORE_RE = /<<CODEBLOCK(\d+)>>/g;
3298
3907
  var INLINE_PREFIX = "<<INLINECODE";
3299
3908
  var INLINE_SUFFIX = ">>";
3300
3909
  var INLINE_RESTORE_RE = /<<INLINECODE(\d+)>>/g;
3910
+ function isFenceCloseLine(line, marker) {
3911
+ return line.startsWith(marker) && /^\s*$/.test(line.slice(marker.length));
3912
+ }
3913
+ function maskFencedCodeBlocks(body, blocks) {
3914
+ const lines = body.split("\n");
3915
+ const lineCount = lines.length;
3916
+ const nextCloseLine = {
3917
+ "```": new Array(lineCount + 1).fill(-1),
3918
+ "~~~": new Array(lineCount + 1).fill(-1)
3919
+ };
3920
+ for (let i2 = lineCount - 1; i2 >= 0; i2--) {
3921
+ nextCloseLine["```"][i2] = isFenceCloseLine(lines[i2], "```") ? i2 : nextCloseLine["```"][i2 + 1];
3922
+ nextCloseLine["~~~"][i2] = isFenceCloseLine(lines[i2], "~~~") ? i2 : nextCloseLine["~~~"][i2 + 1];
3923
+ }
3924
+ const outLines = [];
3925
+ let i = 0;
3926
+ while (i < lineCount) {
3927
+ const line = lines[i];
3928
+ const marker = line.startsWith("```") ? "```" : line.startsWith("~~~") ? "~~~" : null;
3929
+ const searchFrom = i + 2;
3930
+ const closeIndex = marker && searchFrom < lineCount ? nextCloseLine[marker][searchFrom] : -1;
3931
+ if (!marker || closeIndex === -1) {
3932
+ outLines.push(line);
3933
+ i++;
3934
+ continue;
3935
+ }
3936
+ const block = lines.slice(i, closeIndex + 1).join("\n");
3937
+ const idx = blocks.length;
3938
+ blocks.push(block);
3939
+ outLines.push(`${BLOCK_PREFIX}${idx}${BLOCK_SUFFIX}`);
3940
+ i = closeIndex + 1;
3941
+ }
3942
+ return outLines.join("\n");
3943
+ }
3301
3944
  function maskCodeBlocks(body) {
3302
3945
  const blocks = [];
3303
3946
  const inlines = [];
3304
- let masked = body.replace(/^(```|~~~).*\n[\s\S]*?\n\1\s*$/gm, (block) => {
3305
- const idx = blocks.length;
3306
- blocks.push(block);
3307
- return `${BLOCK_PREFIX}${idx}${BLOCK_SUFFIX}`;
3308
- });
3947
+ let masked = maskFencedCodeBlocks(body, blocks);
3309
3948
  masked = masked.replace(/``[^`]+``|`[^`]+`/g, (span) => {
3310
3949
  const idx = inlines.length;
3311
3950
  inlines.push(span);
@@ -3475,7 +4114,7 @@ function renderField(field, value, depth, entry, config) {
3475
4114
  const heading = "#".repeat(Math.min(depth, 6));
3476
4115
  const descriptionLine = "description" in field && field.description ? `
3477
4116
 
3478
- *${field.description}*` : "";
4117
+ _${field.description}_` : "";
3479
4118
  if ("list" in field && field.list && Array.isArray(value)) {
3480
4119
  return renderListField(field, value, depth, label, heading, descriptionLine, entry, config);
3481
4120
  }
@@ -3740,30 +4379,14 @@ function formatInlineValue(field, value) {
3740
4379
  return String(value);
3741
4380
  }
3742
4381
  function yamlValue(value) {
4382
+ if (value === "")
4383
+ return '""';
3743
4384
  if (/[:#{}[\],&*?|>!%@`]/.test(value) || value.includes("\n")) {
3744
4385
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
3745
4386
  }
3746
4387
  return value;
3747
4388
  }
3748
4389
 
3749
- // dist/utils/entry-url.js
3750
- init_normalize();
3751
- function computeEntryUrl(collection, slug, contentRoot) {
3752
- const root = trimSlashes(contentRoot);
3753
- let stripped = collection;
3754
- if (root && collection.startsWith(`${root}/`)) {
3755
- stripped = collection.slice(root.length + 1);
3756
- } else if (collection === root) {
3757
- stripped = "";
3758
- }
3759
- const segments = stripped.split("/").filter(Boolean);
3760
- if (slug && slug !== "index") {
3761
- segments.push(slug);
3762
- }
3763
- const path20 = segments.length > 0 ? `/${segments.join("/")}` : "/";
3764
- return path20.toLowerCase();
3765
- }
3766
-
3767
4390
  // dist/entry-link-resolver.js
3768
4391
  var log2 = createDebugLogger({ prefix: "EntryLinks" });
3769
4392
  var BASE58_CHAR = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
@@ -3936,7 +4559,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
3936
4559
  const listed = await store.getCollectionEntryPaths(collection.logicalPath);
3937
4560
  const directEntries = listed.filter((e) => e.collection === collection.logicalPath);
3938
4561
  for (const listEntry of directEntries) {
3939
- const entryTypeName = extractEntryTypeFromFilename(path11.basename(listEntry.relativePath));
4562
+ const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
3940
4563
  if (!entryTypeName)
3941
4564
  continue;
3942
4565
  if (config?.exclude?.entryTypes?.includes(entryTypeName))
@@ -3954,7 +4577,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
3954
4577
  }
3955
4578
  if (config?.exclude?.where?.(aiEntry))
3956
4579
  continue;
3957
- await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path11.basename(listEntry.relativePath)), config);
4580
+ await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
3958
4581
  entries.push(aiEntry);
3959
4582
  const entryFilePath = `${cleanPath}/${listEntry.slug}.md`;
3960
4583
  const entryMarkdown = entryToMarkdown(aiEntry, config);
@@ -4005,7 +4628,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
4005
4628
  const listed = await store.getCollectionEntryPaths(rootCollection.logicalPath);
4006
4629
  const directEntries = listed.filter((e) => e.collection === rootCollection.logicalPath);
4007
4630
  for (const listEntry of directEntries) {
4008
- const entryTypeName = extractEntryTypeFromFilename(path11.basename(listEntry.relativePath));
4631
+ const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
4009
4632
  if (!entryTypeName)
4010
4633
  continue;
4011
4634
  if (config?.exclude?.entryTypes?.includes(entryTypeName))
@@ -4023,7 +4646,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
4023
4646
  }
4024
4647
  if (config?.exclude?.where?.(aiEntry))
4025
4648
  continue;
4026
- await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path11.basename(listEntry.relativePath)), config);
4649
+ await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
4027
4650
  entries.push(aiEntry);
4028
4651
  const entryFilePath = `${listEntry.slug}.md`;
4029
4652
  const entryMarkdown = entryToMarkdown(aiEntry, config);
@@ -4071,19 +4694,19 @@ function docToAIEntry(doc, slug, entryTypeName, entryTypeConfig, cleanCollection
4071
4694
  };
4072
4695
  }
4073
4696
  function makeReadSibling(dir) {
4074
- const resolvedDir = path11.resolve(dir);
4697
+ const resolvedDir = path12.resolve(dir);
4075
4698
  return async (name) => {
4076
- if (!name || name.includes("/") || name.includes("\\") || path11.isAbsolute(name) || hasTraversalSequence(name)) {
4699
+ if (!name || name.includes("/") || name.includes("\\") || path12.isAbsolute(name) || hasTraversalSequence(name)) {
4077
4700
  return null;
4078
4701
  }
4079
- const abs = path11.resolve(resolvedDir, name);
4080
- if (path11.dirname(abs) !== resolvedDir)
4702
+ const abs = path12.resolve(resolvedDir, name);
4703
+ if (path12.dirname(abs) !== resolvedDir)
4081
4704
  return null;
4082
4705
  try {
4083
- const stats = await fs10.lstat(abs);
4706
+ const stats = await fs11.lstat(abs);
4084
4707
  if (!stats.isFile())
4085
4708
  return null;
4086
- return await fs10.readFile(abs, "utf8");
4709
+ return await fs11.readFile(abs, "utf8");
4087
4710
  } catch (err) {
4088
4711
  if (isNodeError(err) && (err.code === "ENOENT" || err.code === "ENOTDIR"))
4089
4712
  return null;
@@ -4097,7 +4720,7 @@ async function runEntryTransform(entry, absolutePath, contentId, config) {
4097
4720
  return;
4098
4721
  const ctx = {
4099
4722
  contentId: contentId ?? "",
4100
- readSibling: makeReadSibling(path11.dirname(absolutePath))
4723
+ readSibling: makeReadSibling(path12.dirname(absolutePath))
4101
4724
  };
4102
4725
  try {
4103
4726
  const appended = await transform(entry, ctx);
@@ -4134,15 +4757,15 @@ function matchesBundleFilter(entry, filter, contentRoot) {
4134
4757
  }
4135
4758
 
4136
4759
  // dist/branch-workspace.js
4137
- import path16 from "node:path";
4760
+ import path17 from "node:path";
4138
4761
 
4139
4762
  // dist/branch-metadata.js
4140
- import fs13 from "node:fs/promises";
4141
- import path14 from "node:path";
4763
+ import fs14 from "node:fs/promises";
4764
+ import path15 from "node:path";
4142
4765
 
4143
4766
  // dist/branch-registry.js
4144
- import fs11 from "node:fs/promises";
4145
- import path12 from "node:path";
4767
+ import fs12 from "node:fs/promises";
4768
+ import path13 from "node:path";
4146
4769
  init_logger();
4147
4770
  var log3 = createDebugLogger({ prefix: "BranchRegistry" });
4148
4771
  var REGISTRY_FILE = "branches.json";
@@ -4155,10 +4778,10 @@ var BranchRegistry = class {
4155
4778
  constructor(root) {
4156
4779
  this.regenInFlight = null;
4157
4780
  this.lastForcedRefreshMs = 0;
4158
- this.root = path12.resolve(root);
4159
- this.registryPath = path12.join(this.root, REGISTRY_FILE);
4160
- this.stalePath = path12.join(this.root, REGISTRY_STALE_FILE);
4161
- this.tempPath = path12.join(this.root, REGISTRY_TEMP_FILE);
4781
+ this.root = path13.resolve(root);
4782
+ this.registryPath = path13.join(this.root, REGISTRY_FILE);
4783
+ this.stalePath = path13.join(this.root, REGISTRY_STALE_FILE);
4784
+ this.tempPath = path13.join(this.root, REGISTRY_TEMP_FILE);
4162
4785
  }
4163
4786
  /**
4164
4787
  * Returns all branches. Uses the cached snapshot if its embedded generation
@@ -4167,7 +4790,7 @@ var BranchRegistry = class {
4167
4790
  async list() {
4168
4791
  let parsed;
4169
4792
  try {
4170
- const raw = await fs11.readFile(this.registryPath, "utf8");
4793
+ const raw = await fs12.readFile(this.registryPath, "utf8");
4171
4794
  parsed = JSON.parse(raw);
4172
4795
  } catch (err) {
4173
4796
  if (isNotFoundError(err)) {
@@ -4256,7 +4879,7 @@ var BranchRegistry = class {
4256
4879
  async performRegenerate() {
4257
4880
  const read = await readResourceGeneration(this.root, RESOURCE2);
4258
4881
  const branches = await this.scanBranchDirectories();
4259
- await fs11.unlink(this.stalePath).catch(() => {
4882
+ await fs12.unlink(this.stalePath).catch(() => {
4260
4883
  });
4261
4884
  if (!read.ok) {
4262
4885
  return branches;
@@ -4267,12 +4890,12 @@ var BranchRegistry = class {
4267
4890
  generation: read.token
4268
4891
  };
4269
4892
  const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
4270
- await fs11.mkdir(this.root, { recursive: true });
4271
- await fs11.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
4893
+ await fs12.mkdir(this.root, { recursive: true });
4894
+ await fs12.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
4272
4895
  try {
4273
- await fs11.rename(uniqueTempPath, this.registryPath);
4896
+ await fs12.rename(uniqueTempPath, this.registryPath);
4274
4897
  } catch (err) {
4275
- await fs11.unlink(uniqueTempPath).catch(() => {
4898
+ await fs12.unlink(uniqueTempPath).catch(() => {
4276
4899
  });
4277
4900
  throw err;
4278
4901
  }
@@ -4286,12 +4909,12 @@ var BranchRegistry = class {
4286
4909
  async scanBranchDirectories() {
4287
4910
  const branches = [];
4288
4911
  try {
4289
- const entries = await fs11.readdir(this.root, { withFileTypes: true });
4912
+ const entries = await fs12.readdir(this.root, { withFileTypes: true });
4290
4913
  for (const entry of entries) {
4291
4914
  if (!entry.isDirectory() || entry.name.startsWith(".")) {
4292
4915
  continue;
4293
4916
  }
4294
- const branchRoot = path12.join(this.root, entry.name);
4917
+ const branchRoot = path13.join(this.root, entry.name);
4295
4918
  let meta;
4296
4919
  try {
4297
4920
  meta = await BranchMetadataFileManager.loadOnly(branchRoot);
@@ -4318,8 +4941,8 @@ var BranchRegistry = class {
4318
4941
  };
4319
4942
 
4320
4943
  // dist/utils/occ-json-write.js
4321
- import fs12 from "node:fs/promises";
4322
- import path13 from "node:path";
4944
+ import fs13 from "node:fs/promises";
4945
+ import path14 from "node:path";
4323
4946
  import { randomUUID as randomUUID2 } from "node:crypto";
4324
4947
  import lockfile2 from "proper-lockfile";
4325
4948
  var log4 = createDebugLogger({ prefix: "OccJsonWrite" });
@@ -4335,29 +4958,29 @@ async function writeOccJsonFile(filePath, payload, options) {
4335
4958
  const writeId = randomUUID2();
4336
4959
  const data = { ...payload, version: newVersion, writeId };
4337
4960
  const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
4338
- const dir = path13.dirname(filePath);
4339
- await fs12.mkdir(dir, { recursive: true });
4961
+ const dir = path14.dirname(filePath);
4962
+ await fs13.mkdir(dir, { recursive: true });
4340
4963
  const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
4341
- await fs12.writeFile(tempPath, content, "utf-8");
4964
+ await fs13.writeFile(tempPath, content, "utf-8");
4342
4965
  if (expectedVersion === null) {
4343
4966
  try {
4344
- await fs12.link(tempPath, filePath);
4967
+ await fs13.link(tempPath, filePath);
4345
4968
  } catch (err) {
4346
- await fs12.unlink(tempPath).catch(() => {
4969
+ await fs13.unlink(tempPath).catch(() => {
4347
4970
  });
4348
4971
  if (isFileExistsError(err)) {
4349
4972
  throw new OccWriteConflictError();
4350
4973
  }
4351
4974
  throw err;
4352
4975
  }
4353
- await fs12.unlink(tempPath).catch(() => {
4976
+ await fs13.unlink(tempPath).catch(() => {
4354
4977
  });
4355
4978
  return { version: newVersion, writeId };
4356
4979
  }
4357
4980
  try {
4358
4981
  let currentVersion = null;
4359
4982
  try {
4360
- const current = JSON.parse(await fs12.readFile(filePath, "utf-8"));
4983
+ const current = JSON.parse(await fs13.readFile(filePath, "utf-8"));
4361
4984
  currentVersion = current.version ?? 0;
4362
4985
  } catch {
4363
4986
  currentVersion = null;
@@ -4365,16 +4988,16 @@ async function writeOccJsonFile(filePath, payload, options) {
4365
4988
  if (currentVersion !== expectedVersion) {
4366
4989
  throw new OccWriteConflictError();
4367
4990
  }
4368
- await fs12.rename(tempPath, filePath);
4991
+ await fs13.rename(tempPath, filePath);
4369
4992
  if (settleMs > 0) {
4370
4993
  await new Promise((resolve2) => setTimeout(resolve2, settleMs));
4371
4994
  }
4372
- const afterWrite = JSON.parse(await fs12.readFile(filePath, "utf-8"));
4995
+ const afterWrite = JSON.parse(await fs13.readFile(filePath, "utf-8"));
4373
4996
  if (afterWrite.writeId !== writeId) {
4374
4997
  throw new OccWriteConflictError();
4375
4998
  }
4376
4999
  } catch (err) {
4377
- await fs12.unlink(tempPath).catch(() => {
5000
+ await fs13.unlink(tempPath).catch(() => {
4378
5001
  });
4379
5002
  throw err;
4380
5003
  }
@@ -4400,8 +5023,8 @@ async function withOccRetry(operation, options) {
4400
5023
  throw new Error("Unreachable");
4401
5024
  }
4402
5025
  async function withOccFileLock(filePath, fn) {
4403
- const dir = path13.dirname(filePath);
4404
- await fs12.mkdir(dir, { recursive: true });
5026
+ const dir = path14.dirname(filePath);
5027
+ await fs13.mkdir(dir, { recursive: true });
4405
5028
  const MAX_ATTEMPTS = 14;
4406
5029
  let release = null;
4407
5030
  for (let attempt = 1; release === null; attempt++) {
@@ -4464,8 +5087,8 @@ var BranchMetadataCorruptError = class extends Error {
4464
5087
  };
4465
5088
  var BranchMetadataFileManager = class _BranchMetadataFileManager {
4466
5089
  constructor(branchRoot, baseRoot, options) {
4467
- this.branchRoot = path14.resolve(branchRoot);
4468
- this.filePath = path14.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
5090
+ this.branchRoot = path15.resolve(branchRoot);
5091
+ this.filePath = path15.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
4469
5092
  this.baseRoot = baseRoot;
4470
5093
  this.settleMs = options?.settleMs;
4471
5094
  }
@@ -4474,10 +5097,10 @@ var BranchMetadataFileManager = class _BranchMetadataFileManager {
4474
5097
  * Use this for read-only access (e.g., in registry scanning or loadBranchContext).
4475
5098
  */
4476
5099
  static async loadOnly(branchRoot) {
4477
- const resolvedRoot = path14.resolve(branchRoot);
4478
- const filePath = path14.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
5100
+ const resolvedRoot = path15.resolve(branchRoot);
5101
+ const filePath = path15.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
4479
5102
  try {
4480
- const raw = await fs13.readFile(filePath, "utf8");
5103
+ const raw = await fs14.readFile(filePath, "utf8");
4481
5104
  return JSON.parse(raw);
4482
5105
  } catch (err) {
4483
5106
  if (isNotFoundError(err)) {
@@ -4498,7 +5121,7 @@ var BranchMetadataFileManager = class _BranchMetadataFileManager {
4498
5121
  }
4499
5122
  async load() {
4500
5123
  try {
4501
- const raw = await fs13.readFile(this.filePath, "utf8");
5124
+ const raw = await fs14.readFile(this.filePath, "utf8");
4502
5125
  const parsed = JSON.parse(raw);
4503
5126
  const version = parsed.version ?? 0;
4504
5127
  return { meta: parsed, version };
@@ -4560,7 +5183,7 @@ var BranchMetadataFileManager = class _BranchMetadataFileManager {
4560
5183
  */
4561
5184
  async save(incoming) {
4562
5185
  try {
4563
- await fs13.stat(this.branchRoot);
5186
+ await fs14.stat(this.branchRoot);
4564
5187
  } catch (err) {
4565
5188
  if (isNotFoundError(err)) {
4566
5189
  throw new BranchMetadataConflictError("Branch no longer exists");
@@ -4648,8 +5271,8 @@ var loadBranchContext = async (options) => {
4648
5271
  init_operating_mode();
4649
5272
 
4650
5273
  // dist/git-manager.js
4651
- import fs14 from "node:fs/promises";
4652
- import path15 from "node:path";
5274
+ import fs15 from "node:fs/promises";
5275
+ import path16 from "node:path";
4653
5276
  import { simpleGit as simpleGit2 } from "simple-git";
4654
5277
 
4655
5278
  // dist/utils/git.js
@@ -4709,11 +5332,11 @@ function gitChildEnv(overrides) {
4709
5332
  var remoteInitLocks = /* @__PURE__ */ new Map();
4710
5333
  var GITHUB_TRACKING_REF_PREFIX = "refs/remotes/github/";
4711
5334
  async function ensureGitExcludePattern(repoPath, pattern) {
4712
- const excludePath = path15.join(repoPath, ".git", "info", "exclude");
4713
- await fs14.mkdir(path15.dirname(excludePath), { recursive: true });
5335
+ const excludePath = path16.join(repoPath, ".git", "info", "exclude");
5336
+ await fs15.mkdir(path16.dirname(excludePath), { recursive: true });
4714
5337
  let content = "";
4715
5338
  try {
4716
- content = await fs14.readFile(excludePath, "utf-8");
5339
+ content = await fs15.readFile(excludePath, "utf-8");
4717
5340
  } catch (err) {
4718
5341
  if (!isNotFoundError(err))
4719
5342
  throw err;
@@ -4725,7 +5348,7 @@ async function ensureGitExcludePattern(repoPath, pattern) {
4725
5348
  }
4726
5349
  const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
4727
5350
  const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
4728
- await fs14.writeFile(excludePath, newContent, "utf-8");
5351
+ await fs15.writeFile(excludePath, newContent, "utf-8");
4729
5352
  log5.debug("git", "Added pattern to .git/info/exclude", { pattern });
4730
5353
  }
4731
5354
  var GitConflictError = class extends Error {
@@ -4746,12 +5369,12 @@ var GitRemoteRefMissingError = class extends Error {
4746
5369
  };
4747
5370
  var GitManager = class _GitManager {
4748
5371
  constructor(options, gitOptions) {
4749
- this.repoPath = path15.resolve(options.repoPath);
5372
+ this.repoPath = path16.resolve(options.repoPath);
4750
5373
  this.baseBranch = options.baseBranch ?? "main";
4751
5374
  this.remote = options.remote ?? "origin";
4752
5375
  this.skipIndexMarker = options.skipIndexMarker ?? false;
4753
5376
  this.git = simpleGit2({ baseDir: this.repoPath, ...gitOptions });
4754
- this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path15.dirname(this.repoPath) }));
5377
+ this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(this.repoPath) }));
4755
5378
  }
4756
5379
  static async cloneRepo(remoteUrl, targetPath, baseBranch = "main") {
4757
5380
  log5.debug("git", "Cloning repository", {
@@ -4793,11 +5416,11 @@ var GitManager = class _GitManager {
4793
5416
  remotePath: options.remotePath,
4794
5417
  baseBranch: options.baseBranch
4795
5418
  });
4796
- const remoteParent = path15.dirname(options.remotePath);
5419
+ const remoteParent = path16.dirname(options.remotePath);
4797
5420
  releaseLock = await acquireProvisioningLock(remoteParent, ".remote-init.lock");
4798
5421
  let remoteExists = false;
4799
5422
  try {
4800
- const stat = await fs14.stat(options.remotePath);
5423
+ const stat = await fs15.stat(options.remotePath);
4801
5424
  remoteExists = stat.isDirectory();
4802
5425
  } catch (err) {
4803
5426
  if (!isNotFoundError(err))
@@ -5049,7 +5672,7 @@ var GitManager = class _GitManager {
5049
5672
  */
5050
5673
  static async validateGitRepoExists(repoPath) {
5051
5674
  try {
5052
- const stat = await fs14.stat(path15.join(repoPath, ".git"));
5675
+ const stat = await fs15.stat(path16.join(repoPath, ".git"));
5053
5676
  if (!stat.isDirectory()) {
5054
5677
  throw new Error(`Expected git repo at ${repoPath}`);
5055
5678
  }
@@ -5127,7 +5750,7 @@ var GitManager = class _GitManager {
5127
5750
  }
5128
5751
  if (config.autoDetectRemotePath) {
5129
5752
  try {
5130
- const stat = await fs14.stat(config.autoDetectRemotePath);
5753
+ const stat = await fs15.stat(config.autoDetectRemotePath);
5131
5754
  if (stat.isDirectory()) {
5132
5755
  log5.debug("git", "Auto-detected local remote", {
5133
5756
  path: config.autoDetectRemotePath
@@ -5140,8 +5763,8 @@ var GitManager = class _GitManager {
5140
5763
  if (config.shouldAutoInitLocal) {
5141
5764
  const gitRoot = await this.findGitRoot();
5142
5765
  const sourceRoot = options.sourceRoot;
5143
- const sourcePath = sourceRoot ? path15.resolve(gitRoot, sourceRoot) : gitRoot;
5144
- const localRemotePath = path15.join(sourcePath, config.defaultRemotePath);
5766
+ const sourcePath = sourceRoot ? path16.resolve(gitRoot, sourceRoot) : gitRoot;
5767
+ const localRemotePath = path16.join(sourcePath, config.defaultRemotePath);
5145
5768
  await this.ensureLocalSimulatedRemote({
5146
5769
  remotePath: localRemotePath,
5147
5770
  sourcePath: gitRoot,
@@ -5169,7 +5792,7 @@ var GitManager = class _GitManager {
5169
5792
  static async repoExistsAt(workspacePath) {
5170
5793
  try {
5171
5794
  const checkGit = simpleGit2({ baseDir: workspacePath });
5172
- checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path15.dirname(workspacePath) }));
5795
+ checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(workspacePath) }));
5173
5796
  await checkGit.raw(["rev-parse", "--git-dir"]);
5174
5797
  return true;
5175
5798
  } catch {
@@ -5191,19 +5814,19 @@ var GitManager = class _GitManager {
5191
5814
  const baseBranch = await resolveBaseBranch({
5192
5815
  defaultBaseBranch: options.baseBranch,
5193
5816
  mode: options.mode,
5194
- detectFrom: options.sourceRoot ? path15.resolve(process.cwd(), options.sourceRoot) : process.cwd()
5817
+ detectFrom: options.sourceRoot ? path16.resolve(process.cwd(), options.sourceRoot) : process.cwd()
5195
5818
  });
5196
5819
  const remoteName = options.remoteName ?? "origin";
5197
5820
  const repoExists = await _GitManager.repoExistsAt(options.workspacePath);
5198
5821
  if (!repoExists) {
5199
- const gitPath = path15.join(options.workspacePath, ".git");
5822
+ const gitPath = path16.join(options.workspacePath, ".git");
5200
5823
  try {
5201
- const stat = await fs14.stat(gitPath);
5824
+ const stat = await fs15.stat(gitPath);
5202
5825
  if (stat.isDirectory()) {
5203
5826
  log5.debug("git", "Removing corrupt .git directory", {
5204
5827
  workspacePath: options.workspacePath
5205
5828
  });
5206
- await fs14.rm(gitPath, { recursive: true });
5829
+ await fs15.rm(gitPath, { recursive: true });
5207
5830
  }
5208
5831
  } catch (cleanupErr) {
5209
5832
  if (!isNotFoundError(cleanupErr))
@@ -5230,7 +5853,7 @@ var GitManager = class _GitManager {
5230
5853
  }
5231
5854
  justCloned = true;
5232
5855
  const freshGit = simpleGit2({ baseDir: options.workspacePath });
5233
- freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path15.dirname(options.workspacePath) }));
5856
+ freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(options.workspacePath) }));
5234
5857
  await freshGit.addConfig("canopycms.managed", "true");
5235
5858
  await freshGit.addConfig("user.name", options.gitBotAuthorName);
5236
5859
  await freshGit.addConfig("user.email", options.gitBotAuthorEmail);
@@ -5581,9 +6204,9 @@ var GitManager = class _GitManager {
5581
6204
  } catch {
5582
6205
  }
5583
6206
  for (const [filePath, content] of Object.entries(initialFiles)) {
5584
- const absolutePath = path15.join(this.repoPath, filePath);
5585
- await fs14.mkdir(path15.dirname(absolutePath), { recursive: true });
5586
- await fs14.writeFile(absolutePath, content, "utf-8");
6207
+ const absolutePath = path16.join(this.repoPath, filePath);
6208
+ await fs15.mkdir(path16.dirname(absolutePath), { recursive: true });
6209
+ await fs15.writeFile(absolutePath, content, "utf-8");
5587
6210
  await this.git.add(filePath);
5588
6211
  }
5589
6212
  await this.git.commit("Initialize settings branch", ["--allow-empty"]);
@@ -5612,7 +6235,7 @@ var BranchWorkspaceManager = class {
5612
6235
  branchName: options.branchName,
5613
6236
  mode: options.mode
5614
6237
  });
5615
- releaseLock = await acquireProvisioningLock(path16.dirname(options.branchRoot), `.${path16.basename(options.branchRoot)}.init.lock`);
6238
+ releaseLock = await acquireProvisioningLock(path17.dirname(options.branchRoot), `.${path17.basename(options.branchRoot)}.init.lock`);
5616
6239
  await GitManager.initializeWorkspace({
5617
6240
  workspacePath: options.branchRoot,
5618
6241
  branchName: options.branchName,
@@ -5653,7 +6276,7 @@ var BranchWorkspaceManager = class {
5653
6276
  const baseBranch = await resolveBaseBranch({
5654
6277
  defaultBaseBranch: this.config.defaultBaseBranch,
5655
6278
  mode,
5656
- detectFrom: this.config.sourceRoot ? path16.resolve(process.cwd(), this.config.sourceRoot) : void 0
6279
+ detectFrom: this.config.sourceRoot ? path17.resolve(process.cwd(), this.config.sourceRoot) : void 0
5657
6280
  });
5658
6281
  await this.ensureGitWorkspace({
5659
6282
  branchRoot,
@@ -5737,9 +6360,9 @@ async function resolveBranchRoot(config) {
5737
6360
  }
5738
6361
 
5739
6362
  // dist/content-listing.js
5740
- import fs15 from "node:fs/promises";
5741
- import path17 from "node:path";
5742
- import matter2 from "gray-matter";
6363
+ import fs16 from "node:fs/promises";
6364
+ import path18 from "node:path";
6365
+ import matter3 from "gray-matter";
5743
6366
  import { parse as yamlParse2 } from "yaml";
5744
6367
  var log7 = createDebugLogger({ prefix: "ContentListing" });
5745
6368
  var normalizePath = (root, target) => {
@@ -5751,15 +6374,15 @@ var normalizePath = (root, target) => {
5751
6374
  };
5752
6375
  var readEntryData = async (filePath, format, bodyFieldName = "body") => {
5753
6376
  try {
5754
- const raw = await fs15.readFile(filePath, "utf8");
6377
+ const raw = await fs16.readFile(filePath, "utf8");
5755
6378
  if (format === "json") {
5756
6379
  return asRecord(JSON.parse(raw));
5757
6380
  }
5758
6381
  if (format === "yaml") {
5759
6382
  return asRecord(yamlParse2(raw));
5760
6383
  }
5761
- const parsed = matter2(raw);
5762
- const data = parsed.data ?? {};
6384
+ const parsed = matter3(raw);
6385
+ const data = { ...parsed.data ?? {} };
5763
6386
  if (parsed.content) {
5764
6387
  data[bodyFieldName] = parsed.content;
5765
6388
  }
@@ -5771,47 +6394,47 @@ var readEntryData = async (filePath, format, bodyFieldName = "body") => {
5771
6394
  return {};
5772
6395
  }
5773
6396
  };
5774
- var parseTypedFilename = (filename, entryTypes) => {
5775
- const lastDot = filename.lastIndexOf(".");
5776
- if (lastDot === -1)
5777
- return null;
5778
- const nameWithoutExt = filename.slice(0, lastDot);
5779
- const parts = nameWithoutExt.split(".");
5780
- if (parts.length >= 3) {
5781
- const potentialType = parts[0];
5782
- const matchingType = entryTypes.find((e) => e.name === potentialType);
5783
- if (matchingType) {
5784
- const id = parts[parts.length - 1];
5785
- if (!isValidId(id))
5786
- return null;
5787
- const slug = parts.slice(1, -1).join(".").toLowerCase();
5788
- return {
5789
- type: potentialType,
5790
- slug,
5791
- id
5792
- };
5793
- }
5794
- }
5795
- return null;
5796
- };
5797
- async function listEntries(branchRoot, flatSchema, contentRootName, options) {
6397
+ var createReferenceResolver = (branchRoot, flatSchema, contentRootName) => ({
6398
+ store: new ContentStore(branchRoot, flatSchema, { contentRootName }),
6399
+ cache: createReferenceResolveCache()
6400
+ });
6401
+ var resolveCollectionItemReferences = async (items, collection, resolver) => Promise.all(items.map(async (item) => {
6402
+ const fields = collection.entries?.find((e) => e.name === item.entryType)?.schema;
6403
+ if (!fields)
6404
+ return item;
6405
+ return {
6406
+ ...item,
6407
+ data: await resolver.store.resolveReferences(item.data, fields, resolver.cache)
6408
+ };
6409
+ }));
6410
+ async function listEntries(branchRoot, flatSchema, contentRootName, options, visibility) {
5798
6411
  const rootPath = options?.rootPath ?? contentRootName;
5799
6412
  const extract = options?.extract;
5800
6413
  const filter = options?.filter;
5801
6414
  const customSort = options?.sort;
5802
6415
  const collections = flatSchema.filter((item) => item.type === "collection" && item.entries !== void 0 && (item.logicalPath === rootPath || item.logicalPath.startsWith(`${rootPath}/`)));
6416
+ const shouldInclude = visibility?.shouldInclude;
6417
+ const skippedFiles = [];
6418
+ const resolver = options?.resolveReferences ? createReferenceResolver(branchRoot, flatSchema, contentRootName) : null;
5803
6419
  const collectionResults = await Promise.all(collections.map(async (collection) => {
5804
- const entries = await listCollectionEntries(branchRoot, collection);
5805
- return entries.map((entry) => ({ entry, collection }));
6420
+ const entries = await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file));
6421
+ const visible = shouldInclude ? entries.filter((e) => shouldInclude(e.physicalPath)) : entries;
6422
+ const resolved = resolver ? await resolveCollectionItemReferences(visible, collection, resolver) : visible;
6423
+ return resolved.map((entry) => ({ entry, collection }));
5806
6424
  }));
6425
+ if (isBuildMode() && skippedFiles.length > 0) {
6426
+ const lines = skippedFiles.map(({ filename, collectionPath }) => ` - ${collectionPath}/${filename}`);
6427
+ throw new Error(`CanopyCMS static build: found ${skippedFiles.length} file(s) that look like malformed content entries inside a content collection:
6428
+ ${lines.join("\n")}
6429
+ Expected {type}.{slug}.{id}.{ext} with a known entry type (a name declared in that collection's entries config) and a valid 12-char Base58 ID. This usually means a schema rename without a matching file rename, an entry type declared in one collection but not another, or a stray file placed directly in a collection directory. If this is meant to be a colocated sibling artifact (e.g. an entry's contentId-prefixed data file read via an entryTransforms readSibling call), keep its name to three or fewer dot-separated segments (id.suffix.ext) so it is never mistaken for an entry attempt. Otherwise rename or move the file, or fix the schema, then rebuild.`);
6430
+ }
5807
6431
  const contentPrefix = contentRootName ? `${contentRootName}/` : "";
5808
6432
  const items = [];
5809
6433
  for (const results of collectionResults) {
5810
6434
  for (const { entry, collection } of results) {
5811
6435
  const pathWithoutRoot = entry.logicalPath.startsWith(contentPrefix) ? entry.logicalPath.slice(contentPrefix.length) : entry.logicalPath;
5812
6436
  const pathSegments = pathWithoutRoot.split("/").filter(Boolean);
5813
- const urlSegments = entry.slug === "index" ? pathSegments.slice(0, -1) : pathSegments;
5814
- const urlPath = urlSegments.length > 0 ? `/${urlSegments.join("/")}`.toLowerCase() : "/";
6437
+ const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
5815
6438
  const raw = entry.data;
5816
6439
  const meta = {
5817
6440
  entryPath: entry.logicalPath,
@@ -5830,7 +6453,8 @@ async function listEntries(branchRoot, flatSchema, contentRootName, options) {
5830
6453
  entryType: entry.entryType,
5831
6454
  format: entry.format,
5832
6455
  data,
5833
- schema: collection.entries?.find((e) => e.name === entry.entryType)?.schema
6456
+ schema: collection.entries?.find((e) => e.name === entry.entryType)?.schema,
6457
+ updatedAt: entry.updatedAt
5834
6458
  };
5835
6459
  if (filter && !filter(item))
5836
6460
  continue;
@@ -5844,7 +6468,15 @@ async function listEntries(branchRoot, flatSchema, contentRootName, options) {
5844
6468
  }
5845
6469
  return items;
5846
6470
  }
5847
- var listCollectionEntries = async (root, collection) => {
6471
+ var looksLikeMalformedEntry = (filename, entryTypes) => {
6472
+ if (filename.startsWith(".") || filename.startsWith("_"))
6473
+ return false;
6474
+ const segments = filename.split(".");
6475
+ if (segments.length >= 4)
6476
+ return true;
6477
+ return segments.length === 3 && entryTypes.some((e) => e.name === segments[0]);
6478
+ };
6479
+ var listCollectionEntries = async (root, collection, onSkip) => {
5848
6480
  if (collection.type !== "collection" || !collection.entries) {
5849
6481
  return [];
5850
6482
  }
@@ -5864,7 +6496,7 @@ var listCollectionEntries = async (root, collection) => {
5864
6496
  normalizePath(root, collectionRoot);
5865
6497
  let dirents;
5866
6498
  try {
5867
- dirents = await fs15.readdir(collectionRoot, { withFileTypes: true });
6499
+ dirents = await fs16.readdir(collectionRoot, { withFileTypes: true });
5868
6500
  } catch (err) {
5869
6501
  if (isNotFoundError(err))
5870
6502
  return [];
@@ -5872,11 +6504,14 @@ var listCollectionEntries = async (root, collection) => {
5872
6504
  }
5873
6505
  const files = dirents.filter((d) => d.isFile() && validExts.some((ext) => d.name.endsWith(ext)) && d.name !== ".collection.json").sort((a, b) => a.name.localeCompare(b.name));
5874
6506
  const entries = await Promise.all(files.map(async (file) => {
5875
- const absolutePath = path17.join(collectionRoot, file.name);
6507
+ const absolutePath = path18.join(collectionRoot, file.name);
5876
6508
  const relativePath = normalizePath(root, absolutePath);
5877
6509
  const parsed = parseTypedFilename(file.name, entryTypes);
5878
6510
  if (!parsed) {
5879
6511
  log7.warn("listCollectionEntries", `Skipping file with unrecognized filename format: ${file.name} (expected {type}.{slug}.{id}.{ext} with a known entry type and valid 12-char Base58 ID)`);
6512
+ if (looksLikeMalformedEntry(file.name, entryTypes)) {
6513
+ onSkip?.({ filename: file.name, collectionPath: collection.logicalPath });
6514
+ }
5880
6515
  return null;
5881
6516
  }
5882
6517
  const { type: entryTypeName, slug, id: contentId } = parsed;
@@ -5884,7 +6519,7 @@ var listCollectionEntries = async (root, collection) => {
5884
6519
  const format = entryType?.format || "json";
5885
6520
  const bodyField = entryType?.schema ? findBodyFieldName(entryType.schema) : "body";
5886
6521
  const [stats, data] = await Promise.all([
5887
- fs15.stat(absolutePath),
6522
+ fs16.stat(absolutePath),
5888
6523
  readEntryData(absolutePath, format, bodyField)
5889
6524
  ]);
5890
6525
  const item = {
@@ -5922,7 +6557,7 @@ function isValidCropRect(x, y, w, h) {
5922
6557
  }
5923
6558
 
5924
6559
  // dist/validation/field-traversal.js
5925
- function isPlainRecord(value) {
6560
+ function isPlainRecord2(value) {
5926
6561
  return typeof value === "object" && value !== null && !Array.isArray(value);
5927
6562
  }
5928
6563
  function resolveBlockItem(blockField, item) {
@@ -5932,21 +6567,21 @@ function resolveBlockItem(blockField, item) {
5932
6567
  const template = blockField.templates?.find((t) => t.name === templateName);
5933
6568
  if (!template?.fields)
5934
6569
  return void 0;
5935
- const data = isPlainRecord(item.value) ? item.value : item;
6570
+ const data = isPlainRecord2(item.value) ? item.value : item;
5936
6571
  return { fields: template.fields, data };
5937
6572
  }
5938
6573
 
5939
6574
  // dist/validation/entry-validator.js
5940
6575
  var KNOWN_FIELD_TYPES = new Set(fieldTypes);
5941
6576
  var STRING_FIELD_TYPES = /* @__PURE__ */ new Set(["string", "markdown", "mdx", "code"]);
5942
- function isPlainRecord2(value) {
6577
+ function isPlainRecord3(value) {
5943
6578
  return typeof value === "object" && value !== null && !Array.isArray(value);
5944
6579
  }
5945
6580
  function isPositiveInt(value) {
5946
6581
  return typeof value === "number" && Number.isInteger(value) && value > 0;
5947
6582
  }
5948
6583
  function isValidImageCropValue(value) {
5949
- if (!isPlainRecord2(value))
6584
+ if (!isPlainRecord3(value))
5950
6585
  return false;
5951
6586
  const { x, y, w, h } = value;
5952
6587
  if (typeof x !== "number" || typeof y !== "number" || typeof w !== "number" || typeof h !== "number") {
@@ -5954,79 +6589,79 @@ function isValidImageCropValue(value) {
5954
6589
  }
5955
6590
  return isValidCropRect(x, y, w, h);
5956
6591
  }
5957
- function validateImageValue(field, value, path20) {
5958
- if (!isPlainRecord2(value)) {
5959
- return [{ fieldPath: path20, message: "Expected an image object with { src, alt }" }];
6592
+ function validateImageValue(field, value, path21) {
6593
+ if (!isPlainRecord3(value)) {
6594
+ return [{ fieldPath: path21, message: "Expected an image object with { src, alt }" }];
5960
6595
  }
5961
6596
  const errors = [];
5962
6597
  if (typeof value.src !== "string" || value.src.trim() === "") {
5963
- errors.push({ fieldPath: `${path20}.src`, message: "Image src is required" });
6598
+ errors.push({ fieldPath: `${path21}.src`, message: "Image src is required" });
5964
6599
  }
5965
6600
  if (typeof value.alt !== "string") {
5966
- errors.push({ fieldPath: `${path20}.alt`, message: "Image alt text is required" });
6601
+ errors.push({ fieldPath: `${path21}.alt`, message: "Image alt text is required" });
5967
6602
  } else if (value.alt.trim() === "" && field.altOptional !== true) {
5968
- errors.push({ fieldPath: `${path20}.alt`, message: "Image alt text is required" });
6603
+ errors.push({ fieldPath: `${path21}.alt`, message: "Image alt text is required" });
5969
6604
  }
5970
6605
  if (value.width !== void 0 && !isPositiveInt(value.width)) {
5971
- errors.push({ fieldPath: `${path20}.width`, message: "Image width must be a positive integer" });
6606
+ errors.push({ fieldPath: `${path21}.width`, message: "Image width must be a positive integer" });
5972
6607
  }
5973
6608
  if (value.height !== void 0 && !isPositiveInt(value.height)) {
5974
6609
  errors.push({
5975
- fieldPath: `${path20}.height`,
6610
+ fieldPath: `${path21}.height`,
5976
6611
  message: "Image height must be a positive integer"
5977
6612
  });
5978
6613
  }
5979
6614
  if (value.crop !== void 0 && !isValidImageCropValue(value.crop)) {
5980
- errors.push({ fieldPath: `${path20}.crop`, message: "Invalid image crop rect" });
6615
+ errors.push({ fieldPath: `${path21}.crop`, message: "Invalid image crop rect" });
5981
6616
  }
5982
6617
  return errors;
5983
6618
  }
5984
6619
  function referenceValueId(value) {
5985
6620
  if (typeof value === "string")
5986
6621
  return value;
5987
- if (isPlainRecord2(value) && typeof value.id === "string")
6622
+ if (isPlainRecord3(value) && typeof value.id === "string")
5988
6623
  return value.id;
5989
6624
  return void 0;
5990
6625
  }
5991
6626
  var selectOptionValues = (field) => (field.options ?? []).map((opt) => typeof opt === "string" ? opt : opt.value);
5992
- function validateScalar(field, value, path20) {
6627
+ function validateScalar(field, value, path21) {
5993
6628
  switch (field.type) {
5994
6629
  case "number":
5995
6630
  if (typeof value !== "number" || !Number.isFinite(value)) {
5996
- return [{ fieldPath: path20, message: "Expected a number" }];
6631
+ return [{ fieldPath: path21, message: "Expected a number" }];
5997
6632
  }
5998
6633
  return [];
5999
6634
  case "boolean":
6000
6635
  if (typeof value !== "boolean") {
6001
- return [{ fieldPath: path20, message: "Expected true or false" }];
6636
+ return [{ fieldPath: path21, message: "Expected true or false" }];
6002
6637
  }
6003
6638
  return [];
6004
6639
  case "datetime":
6005
6640
  if (typeof value !== "string" || value !== "" && Number.isNaN(Date.parse(value))) {
6006
- return [{ fieldPath: path20, message: "Expected a valid date/time string" }];
6641
+ return [{ fieldPath: path21, message: "Expected a valid date/time string" }];
6007
6642
  }
6008
6643
  return [];
6009
6644
  case "select": {
6010
6645
  if (typeof value !== "string") {
6011
- return [{ fieldPath: path20, message: "Expected a selection" }];
6646
+ return [{ fieldPath: path21, message: "Expected a selection" }];
6012
6647
  }
6013
6648
  const options = selectOptionValues(field);
6014
6649
  if (value !== "" && !options.includes(value)) {
6015
- return [{ fieldPath: path20, message: `Must be one of: ${options.join(", ")}` }];
6650
+ return [{ fieldPath: path21, message: `Must be one of: ${options.join(", ")}` }];
6016
6651
  }
6017
6652
  return [];
6018
6653
  }
6019
6654
  case "reference":
6020
6655
  if (referenceValueId(value) === void 0) {
6021
- return [{ fieldPath: path20, message: "Expected a reference id" }];
6656
+ return [{ fieldPath: path21, message: "Expected a reference id" }];
6022
6657
  }
6023
6658
  return [];
6024
6659
  case "image":
6025
- return validateImageValue(field, value, path20);
6660
+ return validateImageValue(field, value, path21);
6026
6661
  default:
6027
6662
  if (STRING_FIELD_TYPES.has(field.type)) {
6028
6663
  if (typeof value !== "string") {
6029
- return [{ fieldPath: path20, message: "Expected text" }];
6664
+ return [{ fieldPath: path21, message: "Expected text" }];
6030
6665
  }
6031
6666
  }
6032
6667
  return [];
@@ -6049,12 +6684,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
6049
6684
  errors.push(...validateEntryData(field.fields, data, pathPrefix));
6050
6685
  continue;
6051
6686
  }
6052
- const path20 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
6687
+ const path21 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
6053
6688
  const value = data[field.name];
6054
6689
  const isRequired = "required" in field && field.required === true;
6055
6690
  if (isRequired && isEmptyForRequired(field, value)) {
6056
6691
  const message = Array.isArray(value) ? "At least one item is required" : "This field is required";
6057
- errors.push({ fieldPath: path20, message });
6692
+ errors.push({ fieldPath: path21, message });
6058
6693
  continue;
6059
6694
  }
6060
6695
  if (value === void 0 || value === null)
@@ -6062,12 +6697,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
6062
6697
  if (field.type === "block") {
6063
6698
  const blockField = field;
6064
6699
  if (!Array.isArray(value)) {
6065
- errors.push({ fieldPath: path20, message: "Expected a list of blocks" });
6700
+ errors.push({ fieldPath: path21, message: "Expected a list of blocks" });
6066
6701
  continue;
6067
6702
  }
6068
6703
  value.forEach((item, index) => {
6069
- const itemPath = `${path20}[${index}]`;
6070
- if (!isPlainRecord2(item)) {
6704
+ const itemPath = `${path21}[${index}]`;
6705
+ if (!isPlainRecord3(item)) {
6071
6706
  errors.push({ fieldPath: itemPath, message: "Expected a block object" });
6072
6707
  return;
6073
6708
  }
@@ -6088,12 +6723,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
6088
6723
  const objectField = field;
6089
6724
  if (objectField.list) {
6090
6725
  if (!Array.isArray(value)) {
6091
- errors.push({ fieldPath: path20, message: "Expected a list of items" });
6726
+ errors.push({ fieldPath: path21, message: "Expected a list of items" });
6092
6727
  continue;
6093
6728
  }
6094
6729
  value.forEach((item, index) => {
6095
- const itemPath = `${path20}[${index}]`;
6096
- if (!isPlainRecord2(item)) {
6730
+ const itemPath = `${path21}[${index}]`;
6731
+ if (!isPlainRecord3(item)) {
6097
6732
  errors.push({ fieldPath: itemPath, message: "Expected an object" });
6098
6733
  return;
6099
6734
  }
@@ -6101,28 +6736,28 @@ function validateEntryData(fields, data, pathPrefix = "") {
6101
6736
  errors.push(...validateEntryData(objectField.fields, item, itemPath));
6102
6737
  }
6103
6738
  });
6104
- } else if (!isPlainRecord2(value)) {
6105
- errors.push({ fieldPath: path20, message: "Expected an object" });
6739
+ } else if (!isPlainRecord3(value)) {
6740
+ errors.push({ fieldPath: path21, message: "Expected an object" });
6106
6741
  } else if (objectField.fields) {
6107
- errors.push(...validateEntryData(objectField.fields, value, path20));
6742
+ errors.push(...validateEntryData(objectField.fields, value, path21));
6108
6743
  }
6109
6744
  continue;
6110
6745
  }
6111
6746
  if ("list" in field && field.list) {
6112
6747
  if (!Array.isArray(value)) {
6113
- errors.push({ fieldPath: path20, message: "Expected a list of values" });
6748
+ errors.push({ fieldPath: path21, message: "Expected a list of values" });
6114
6749
  continue;
6115
6750
  }
6116
6751
  value.forEach((item, index) => {
6117
- errors.push(...validateScalar(field, item, `${path20}[${index}]`));
6752
+ errors.push(...validateScalar(field, item, `${path21}[${index}]`));
6118
6753
  });
6119
6754
  continue;
6120
6755
  }
6121
6756
  if (Array.isArray(value) && KNOWN_FIELD_TYPES.has(field.type)) {
6122
- errors.push({ fieldPath: path20, message: "Expected a single value, not a list" });
6757
+ errors.push({ fieldPath: path21, message: "Expected a single value, not a list" });
6123
6758
  continue;
6124
6759
  }
6125
- errors.push(...validateScalar(field, value, path20));
6760
+ errors.push(...validateScalar(field, value, path21));
6126
6761
  }
6127
6762
  return errors;
6128
6763
  }
@@ -6170,6 +6805,38 @@ These are likely abandoned create-scaffolds (empty entries left behind when a cr
6170
6805
  }
6171
6806
 
6172
6807
  // dist/build/generate-ai-content.js
6808
+ var GENERATED_RECORD_FILENAME = ".canopy-generated.json";
6809
+ async function readGeneratedRecord(outputDir) {
6810
+ try {
6811
+ const raw = await fs17.readFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), "utf-8");
6812
+ const parsed = JSON.parse(raw);
6813
+ if (typeof parsed !== "object" || parsed === null || !("files" in parsed))
6814
+ return [];
6815
+ const { files } = parsed;
6816
+ if (!Array.isArray(files))
6817
+ return [];
6818
+ return files.filter((entry) => typeof entry === "string");
6819
+ } catch {
6820
+ return [];
6821
+ }
6822
+ }
6823
+ async function writeGeneratedRecord(outputDir, files) {
6824
+ const record = { files: [...files].sort() };
6825
+ await fs17.mkdir(outputDir, { recursive: true });
6826
+ await fs17.writeFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), `${JSON.stringify(record, null, 2)}
6827
+ `, "utf-8");
6828
+ }
6829
+ async function removeEmptyDirsUpward(startDir, stopAt) {
6830
+ let current = startDir;
6831
+ while (current.startsWith(stopAt) && current !== stopAt) {
6832
+ try {
6833
+ await fs17.rmdir(current);
6834
+ } catch {
6835
+ return;
6836
+ }
6837
+ current = path19.dirname(current);
6838
+ }
6839
+ }
6173
6840
  async function generateAIContentFiles(options) {
6174
6841
  const { config, entrySchemaRegistry, outputDir, aiConfig, _testFlatSchema } = options;
6175
6842
  const contentRootName = config.contentRoot || "content";
@@ -6192,18 +6859,40 @@ async function generateAIContentFiles(options) {
6192
6859
  config: aiConfig,
6193
6860
  entryLinkUrl: config.entryLinkUrl
6194
6861
  });
6195
- const absoluteOutputDir = path18.resolve(outputDir) + path18.sep;
6196
- let fileCount = 0;
6197
- for (const [filePath, content] of result.files) {
6198
- const absolutePath = path18.resolve(path18.join(absoluteOutputDir, filePath));
6862
+ const absoluteOutputDir = path19.resolve(outputDir) + path19.sep;
6863
+ const resolveOutputPath = (filePath) => {
6864
+ const absolutePath = path19.resolve(path19.join(absoluteOutputDir, filePath));
6199
6865
  if (!absolutePath.startsWith(absoluteOutputDir)) {
6200
6866
  throw new Error(`Path traversal detected in AI content output: ${filePath}`);
6201
6867
  }
6202
- await fs16.mkdir(path18.dirname(absolutePath), { recursive: true });
6203
- await fs16.writeFile(absolutePath, content, "utf-8");
6868
+ return absolutePath;
6869
+ };
6870
+ const previousFiles = await readGeneratedRecord(absoluteOutputDir);
6871
+ const currentFiles = [...result.files.keys()];
6872
+ await writeGeneratedRecord(absoluteOutputDir, [.../* @__PURE__ */ new Set([...previousFiles, ...currentFiles])]);
6873
+ let fileCount = 0;
6874
+ for (const [filePath, content] of result.files) {
6875
+ const absolutePath = resolveOutputPath(filePath);
6876
+ await fs17.mkdir(path19.dirname(absolutePath), { recursive: true });
6877
+ await fs17.writeFile(absolutePath, content, "utf-8");
6204
6878
  fileCount++;
6205
6879
  }
6206
- return { fileCount, outputDir: absoluteOutputDir };
6880
+ const currentSet = new Set(currentFiles);
6881
+ const stale = previousFiles.filter((filePath) => !currentSet.has(filePath));
6882
+ let removedCount = 0;
6883
+ for (const filePath of stale) {
6884
+ const absolutePath = resolveOutputPath(filePath);
6885
+ try {
6886
+ await fs17.unlink(absolutePath);
6887
+ removedCount++;
6888
+ } catch (err) {
6889
+ if (!isNodeError(err) || err.code !== "ENOENT")
6890
+ throw err;
6891
+ }
6892
+ await removeEmptyDirsUpward(path19.dirname(absolutePath), absoluteOutputDir);
6893
+ }
6894
+ await writeGeneratedRecord(absoluteOutputDir, currentFiles);
6895
+ return { fileCount, removedCount, outputDir: absoluteOutputDir };
6207
6896
  }
6208
6897
 
6209
6898
  // dist/cli/generate-ai-content.js
@@ -6211,7 +6900,7 @@ var jiti = createJiti(import.meta.url);
6211
6900
  async function generateAIContentCLI(options) {
6212
6901
  const { projectDir, outputDir = "public/ai", configPath, appDir = "app" } = options;
6213
6902
  console.log("\nCanopyCMS generate-ai-content\n");
6214
- const canopyConfigPath = path19.join(projectDir, "canopycms.config.ts");
6903
+ const canopyConfigPath = path20.join(projectDir, "canopycms.config.ts");
6215
6904
  let canopyConfigModule;
6216
6905
  try {
6217
6906
  canopyConfigModule = await jiti.import(canopyConfigPath);
@@ -6222,7 +6911,7 @@ async function generateAIContentCLI(options) {
6222
6911
  }
6223
6912
  const configExport = canopyConfigModule.default ?? canopyConfigModule.config ?? canopyConfigModule;
6224
6913
  const serverConfig = typeof configExport === "object" && configExport !== null && "server" in configExport ? configExport.server : configExport;
6225
- const schemasPath = path19.join(projectDir, appDir, "schemas.ts");
6914
+ const schemasPath = path20.join(projectDir, appDir, "schemas.ts");
6226
6915
  let entrySchemaRegistry = {};
6227
6916
  try {
6228
6917
  const schemasModule = await jiti.import(schemasPath);
@@ -6233,7 +6922,7 @@ async function generateAIContentCLI(options) {
6233
6922
  let aiConfig;
6234
6923
  if (configPath) {
6235
6924
  try {
6236
- const aiConfigModule = await jiti.import(path19.resolve(configPath));
6925
+ const aiConfigModule = await jiti.import(path20.resolve(configPath));
6237
6926
  aiConfig = aiConfigModule.aiContentConfig ?? aiConfigModule.default ?? aiConfigModule.config;
6238
6927
  } catch (err) {
6239
6928
  console.error(`Could not load AI config from ${configPath}`);
@@ -6250,7 +6939,7 @@ async function generateAIContentCLI(options) {
6250
6939
  console.error("Make sure canopycms.config.ts uses defineCanopyConfig().");
6251
6940
  process.exit(1);
6252
6941
  }
6253
- const resolvedOutput = path19.resolve(projectDir, outputDir);
6942
+ const resolvedOutput = path20.resolve(projectDir, outputDir);
6254
6943
  console.log(` Output: ${resolvedOutput}`);
6255
6944
  console.log(` Mode: ${serverConfig.mode ?? "dev"}`);
6256
6945
  const result = await generateAIContentFiles({
@@ -6261,6 +6950,9 @@ async function generateAIContentCLI(options) {
6261
6950
  });
6262
6951
  console.log(`
6263
6952
  Generated ${result.fileCount} files`);
6953
+ if (result.removedCount > 0) {
6954
+ console.log(` Removed ${result.removedCount} stale files from the previous run`);
6955
+ }
6264
6956
  console.log(` Output: ${result.outputDir}
6265
6957
  `);
6266
6958
  }