canopycms 0.0.63 → 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 (1209) 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 +7 -8
  7. package/dist/ai/index.js +0 -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 +4 -1
  15. package/dist/ai/to-plain-text.js +47 -1
  16. package/dist/ai/transform-components.d.ts +1 -2
  17. package/dist/ai/transform-components.js +0 -1
  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 +4 -5
  117. package/dist/authorization/branch.js +0 -1
  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 +6 -7
  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 +5 -6
  161. package/dist/build-canopy.js +0 -1
  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 +1131 -486
  166. package/dist/cli/generate-ai-content.d.ts +0 -1
  167. package/dist/cli/generate-ai-content.js +1000 -360
  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/deploy-cms.yml.template +8 -6
  179. package/dist/cli/templates.d.ts +0 -1
  180. package/dist/cli/templates.js +0 -1
  181. package/dist/client.d.ts +13 -14
  182. package/dist/client.js +0 -1
  183. package/dist/comment-store.d.ts +0 -1
  184. package/dist/comment-store.js +0 -1
  185. package/dist/config/flatten.d.ts +1 -2
  186. package/dist/config/flatten.js +0 -1
  187. package/dist/config/helpers.d.ts +3 -4
  188. package/dist/config/helpers.js +2 -2
  189. package/dist/config/index.d.ts +10 -11
  190. package/dist/config/index.js +0 -1
  191. package/dist/config/schemas/collection.d.ts +0 -1
  192. package/dist/config/schemas/collection.js +0 -1
  193. package/dist/config/schemas/config.d.ts +7 -4
  194. package/dist/config/schemas/config.js +12 -1
  195. package/dist/config/schemas/field.d.ts +3 -1
  196. package/dist/config/schemas/field.js +5 -1
  197. package/dist/config/schemas/media.d.ts +0 -1
  198. package/dist/config/schemas/media.js +0 -1
  199. package/dist/config/schemas/permissions.d.ts +0 -1
  200. package/dist/config/schemas/permissions.js +0 -1
  201. package/dist/config/types.d.ts +55 -9
  202. package/dist/config/types.js +0 -1
  203. package/dist/config/validation.d.ts +1 -2
  204. package/dist/config/validation.js +0 -1
  205. package/dist/config.d.ts +2 -3
  206. package/dist/config.js +0 -1
  207. package/dist/content-id-index.d.ts +1 -2
  208. package/dist/content-id-index.js +0 -1
  209. package/dist/content-index-generation.d.ts +0 -1
  210. package/dist/content-index-generation.js +0 -1
  211. package/dist/content-index-registry.d.ts +0 -1
  212. package/dist/content-index-registry.js +0 -1
  213. package/dist/content-listing.d.ts +75 -59
  214. package/dist/content-listing.js +76 -83
  215. package/dist/content-reader.d.ts +4 -5
  216. package/dist/content-reader.js +22 -3
  217. package/dist/content-store.d.ts +137 -6
  218. package/dist/content-store.js +294 -22
  219. package/dist/content-tree.d.ts +15 -5
  220. package/dist/content-tree.js +27 -8
  221. package/dist/context.d.ts +9 -6
  222. package/dist/context.js +0 -1
  223. package/dist/dev-content-watcher.d.ts +2 -3
  224. package/dist/dev-content-watcher.js +0 -1
  225. package/dist/editor/BranchManager.d.ts +4 -5
  226. package/dist/editor/BranchManager.js +0 -1
  227. package/dist/editor/CanopyEditor.d.ts +2 -3
  228. package/dist/editor/CanopyEditor.js +1 -2
  229. package/dist/editor/CanopyEditorPage.d.ts +2 -3
  230. package/dist/editor/CanopyEditorPage.js +0 -1
  231. package/dist/editor/CommentsPanel.d.ts +2 -3
  232. package/dist/editor/CommentsPanel.js +0 -1
  233. package/dist/editor/Editor.d.ts +13 -8
  234. package/dist/editor/Editor.js +4 -5
  235. package/dist/editor/EditorPanes.d.ts +0 -1
  236. package/dist/editor/EditorPanes.js +0 -1
  237. package/dist/editor/EntryNavigator.d.ts +1 -2
  238. package/dist/editor/EntryNavigator.js +0 -1
  239. package/dist/editor/FormRenderer.d.ts +2 -3
  240. package/dist/editor/FormRenderer.js +22 -3
  241. package/dist/editor/GroupManager.d.ts +2 -3
  242. package/dist/editor/GroupManager.js +0 -1
  243. package/dist/editor/PermissionManager.d.ts +2 -3
  244. package/dist/editor/PermissionManager.js +0 -1
  245. package/dist/editor/admin/SystemHealthPanel.d.ts +0 -1
  246. package/dist/editor/admin/SystemHealthPanel.js +0 -1
  247. package/dist/editor/admin/useSystemHealth.d.ts +2 -3
  248. package/dist/editor/admin/useSystemHealth.js +0 -1
  249. package/dist/editor/canopy-path.d.ts +0 -1
  250. package/dist/editor/canopy-path.js +0 -1
  251. package/dist/editor/client-reference-resolver.d.ts +13 -4
  252. package/dist/editor/client-reference-resolver.js +18 -8
  253. package/dist/editor/comments/BranchComments.d.ts +2 -3
  254. package/dist/editor/comments/BranchComments.js +0 -1
  255. package/dist/editor/comments/EntryComments.d.ts +1 -2
  256. package/dist/editor/comments/EntryComments.js +0 -1
  257. package/dist/editor/comments/FieldWrapper.d.ts +1 -2
  258. package/dist/editor/comments/FieldWrapper.js +0 -1
  259. package/dist/editor/comments/InlineCommentThread.d.ts +2 -3
  260. package/dist/editor/comments/InlineCommentThread.js +0 -1
  261. package/dist/editor/comments/ThreadCarousel.d.ts +2 -3
  262. package/dist/editor/comments/ThreadCarousel.js +0 -1
  263. package/dist/editor/components/ConfirmDeleteModal.d.ts +0 -1
  264. package/dist/editor/components/ConfirmDeleteModal.js +0 -1
  265. package/dist/editor/components/EditorFooter.d.ts +0 -1
  266. package/dist/editor/components/EditorFooter.js +0 -1
  267. package/dist/editor/components/EditorHeader.d.ts +4 -5
  268. package/dist/editor/components/EditorHeader.js +0 -1
  269. package/dist/editor/components/EditorSidebar.d.ts +1 -2
  270. package/dist/editor/components/EditorSidebar.js +0 -1
  271. package/dist/editor/components/EntryCreateModal.d.ts +0 -1
  272. package/dist/editor/components/EntryCreateModal.js +21 -10
  273. package/dist/editor/components/RenameEntryModal.d.ts +0 -1
  274. package/dist/editor/components/RenameEntryModal.js +0 -1
  275. package/dist/editor/components/UserBadge.d.ts +2 -3
  276. package/dist/editor/components/UserBadge.js +0 -1
  277. package/dist/editor/components/index.d.ts +3 -4
  278. package/dist/editor/components/index.js +0 -1
  279. package/dist/editor/context/ApiClientContext.d.ts +9 -3
  280. package/dist/editor/context/ApiClientContext.js +8 -4
  281. package/dist/editor/context/AssetContext.d.ts +26 -2
  282. package/dist/editor/context/AssetContext.js +23 -3
  283. package/dist/editor/context/EditorStateContext.d.ts +1 -2
  284. package/dist/editor/context/EditorStateContext.js +0 -1
  285. package/dist/editor/context/SWRProvider.d.ts +0 -1
  286. package/dist/editor/context/SWRProvider.js +0 -1
  287. package/dist/editor/context/index.d.ts +4 -5
  288. package/dist/editor/context/index.js +0 -1
  289. package/dist/editor/editor-config.d.ts +2 -3
  290. package/dist/editor/editor-config.js +0 -1
  291. package/dist/editor/editor-utils.d.ts +22 -10
  292. package/dist/editor/editor-utils.js +41 -10
  293. package/dist/editor/fields/BlockField.d.ts +1 -2
  294. package/dist/editor/fields/BlockField.js +0 -1
  295. package/dist/editor/fields/CodeField.d.ts +0 -1
  296. package/dist/editor/fields/CodeField.js +0 -1
  297. package/dist/editor/fields/DateTimeField.d.ts +0 -1
  298. package/dist/editor/fields/DateTimeField.js +0 -1
  299. package/dist/editor/fields/ImageField.d.ts +1 -2
  300. package/dist/editor/fields/ImageField.js +0 -1
  301. package/dist/editor/fields/InlineGroupField.d.ts +2 -3
  302. package/dist/editor/fields/InlineGroupField.js +0 -1
  303. package/dist/editor/fields/MarkdownField.d.ts +0 -1
  304. package/dist/editor/fields/MarkdownField.js +0 -1
  305. package/dist/editor/fields/MdxImageDialog.d.ts +0 -1
  306. package/dist/editor/fields/MdxImageDialog.js +0 -1
  307. package/dist/editor/fields/NumberField.d.ts +0 -1
  308. package/dist/editor/fields/NumberField.js +0 -1
  309. package/dist/editor/fields/NumberListField.d.ts +0 -1
  310. package/dist/editor/fields/NumberListField.js +0 -1
  311. package/dist/editor/fields/ObjectField.d.ts +11 -2
  312. package/dist/editor/fields/ObjectField.js +3 -4
  313. package/dist/editor/fields/ReferenceField.d.ts +0 -1
  314. package/dist/editor/fields/ReferenceField.js +8 -3
  315. package/dist/editor/fields/SelectField.d.ts +0 -1
  316. package/dist/editor/fields/SelectField.js +0 -1
  317. package/dist/editor/fields/StringListField.d.ts +0 -1
  318. package/dist/editor/fields/StringListField.js +0 -1
  319. package/dist/editor/fields/TextField.d.ts +0 -1
  320. package/dist/editor/fields/TextField.js +0 -1
  321. package/dist/editor/fields/ToggleField.d.ts +0 -1
  322. package/dist/editor/fields/ToggleField.js +0 -1
  323. package/dist/editor/fields/entry-link/EntryLinkContext.d.ts +1 -2
  324. package/dist/editor/fields/entry-link/EntryLinkContext.js +0 -1
  325. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -1
  326. package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -1
  327. package/dist/editor/fields/entry-link/index.d.ts +2 -3
  328. package/dist/editor/fields/entry-link/index.js +0 -1
  329. package/dist/editor/group-manager/ExternalGroupsTab.d.ts +1 -2
  330. package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
  331. package/dist/editor/group-manager/GroupCard.d.ts +1 -2
  332. package/dist/editor/group-manager/GroupCard.js +0 -1
  333. package/dist/editor/group-manager/GroupForm.d.ts +1 -2
  334. package/dist/editor/group-manager/GroupForm.js +0 -1
  335. package/dist/editor/group-manager/InternalGroupsTab.d.ts +1 -2
  336. package/dist/editor/group-manager/InternalGroupsTab.js +0 -1
  337. package/dist/editor/group-manager/MemberList.d.ts +1 -2
  338. package/dist/editor/group-manager/MemberList.js +0 -1
  339. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +1 -2
  340. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -1
  341. package/dist/editor/group-manager/hooks/useGroupState.d.ts +1 -2
  342. package/dist/editor/group-manager/hooks/useGroupState.js +0 -1
  343. package/dist/editor/group-manager/hooks/useUserSearch.d.ts +1 -2
  344. package/dist/editor/group-manager/hooks/useUserSearch.js +0 -1
  345. package/dist/editor/group-manager/index.d.ts +5 -6
  346. package/dist/editor/group-manager/index.js +0 -1
  347. package/dist/editor/group-manager/types.d.ts +4 -5
  348. package/dist/editor/group-manager/types.js +0 -1
  349. package/dist/editor/hooks/index.d.ts +14 -15
  350. package/dist/editor/hooks/index.js +0 -1
  351. package/dist/editor/hooks/useBranchActions.d.ts +0 -1
  352. package/dist/editor/hooks/useBranchActions.js +0 -1
  353. package/dist/editor/hooks/useBranchManager.d.ts +4 -5
  354. package/dist/editor/hooks/useBranchManager.js +0 -1
  355. package/dist/editor/hooks/useBranchesData.d.ts +2 -3
  356. package/dist/editor/hooks/useBranchesData.js +0 -1
  357. package/dist/editor/hooks/useCommentSystem.d.ts +2 -3
  358. package/dist/editor/hooks/useCommentSystem.js +0 -1
  359. package/dist/editor/hooks/useCommentsData.d.ts +2 -3
  360. package/dist/editor/hooks/useCommentsData.js +0 -1
  361. package/dist/editor/hooks/useDraftManager.d.ts +3 -4
  362. package/dist/editor/hooks/useDraftManager.js +0 -1
  363. package/dist/editor/hooks/useEditorLayout.d.ts +1 -2
  364. package/dist/editor/hooks/useEditorLayout.js +0 -1
  365. package/dist/editor/hooks/useEntriesData.d.ts +3 -5
  366. package/dist/editor/hooks/useEntriesData.js +0 -3
  367. package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -3
  368. package/dist/editor/hooks/useEntryLinkResolution.js +0 -1
  369. package/dist/editor/hooks/useEntryManager.d.ts +5 -7
  370. package/dist/editor/hooks/useEntryManager.js +8 -3
  371. package/dist/editor/hooks/useGroupManager.d.ts +2 -3
  372. package/dist/editor/hooks/useGroupManager.js +0 -1
  373. package/dist/editor/hooks/usePermissionManager.d.ts +2 -3
  374. package/dist/editor/hooks/usePermissionManager.js +0 -1
  375. package/dist/editor/hooks/useReferenceResolution.d.ts +1 -2
  376. package/dist/editor/hooks/useReferenceResolution.js +8 -3
  377. package/dist/editor/hooks/useSchemaManager.d.ts +2 -3
  378. package/dist/editor/hooks/useSchemaManager.js +0 -1
  379. package/dist/editor/hooks/useUserContext.d.ts +1 -2
  380. package/dist/editor/hooks/useUserContext.js +8 -3
  381. package/dist/editor/hooks/useUserMetadata.d.ts +2 -3
  382. package/dist/editor/hooks/useUserMetadata.js +0 -1
  383. package/dist/editor/media/AssetCard.d.ts +1 -2
  384. package/dist/editor/media/AssetCard.js +0 -1
  385. package/dist/editor/media/CropStep.d.ts +1 -2
  386. package/dist/editor/media/CropStep.js +0 -1
  387. package/dist/editor/media/MediaLibrary.d.ts +1 -2
  388. package/dist/editor/media/MediaLibrary.js +0 -1
  389. package/dist/editor/media/MediaLibraryBody.d.ts +1 -2
  390. package/dist/editor/media/MediaLibraryBody.js +0 -1
  391. package/dist/editor/media/crop-math.d.ts +1 -2
  392. package/dist/editor/media/crop-math.js +0 -1
  393. package/dist/editor/media/upload-asset.d.ts +2 -3
  394. package/dist/editor/media/upload-asset.js +0 -1
  395. package/dist/editor/media/upload-constants.d.ts +0 -1
  396. package/dist/editor/media/upload-constants.js +0 -1
  397. package/dist/editor/media/useAssetUpload.d.ts +1 -2
  398. package/dist/editor/media/useAssetUpload.js +0 -1
  399. package/dist/editor/media/xhr-upload.d.ts +0 -1
  400. package/dist/editor/media/xhr-upload.js +0 -1
  401. package/dist/editor/permission-manager/GroupSelector.d.ts +1 -2
  402. package/dist/editor/permission-manager/GroupSelector.js +0 -1
  403. package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -2
  404. package/dist/editor/permission-manager/PermissionEditor.js +0 -1
  405. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +1 -2
  406. package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -1
  407. package/dist/editor/permission-manager/PermissionTree.d.ts +1 -2
  408. package/dist/editor/permission-manager/PermissionTree.js +0 -1
  409. package/dist/editor/permission-manager/UserSelector.d.ts +1 -2
  410. package/dist/editor/permission-manager/UserSelector.js +0 -1
  411. package/dist/editor/permission-manager/constants.d.ts +1 -2
  412. package/dist/editor/permission-manager/constants.js +0 -1
  413. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +1 -2
  414. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -1
  415. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +2 -3
  416. package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -1
  417. package/dist/editor/permission-manager/index.d.ts +4 -5
  418. package/dist/editor/permission-manager/index.js +0 -1
  419. package/dist/editor/permission-manager/types.d.ts +3 -4
  420. package/dist/editor/permission-manager/types.js +0 -1
  421. package/dist/editor/permission-manager/utils.d.ts +2 -3
  422. package/dist/editor/permission-manager/utils.js +0 -1
  423. package/dist/editor/preview-bridge.d.ts +1 -2
  424. package/dist/editor/preview-bridge.js +0 -1
  425. package/dist/editor/relative-time.d.ts +0 -1
  426. package/dist/editor/relative-time.js +0 -1
  427. package/dist/editor/schema-editor/CollectionEditor.d.ts +4 -5
  428. package/dist/editor/schema-editor/CollectionEditor.js +0 -1
  429. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +2 -3
  430. package/dist/editor/schema-editor/EntryTypeEditor.js +0 -1
  431. package/dist/editor/schema-editor/index.d.ts +2 -3
  432. package/dist/editor/schema-editor/index.js +0 -1
  433. package/dist/editor/theme.d.ts +0 -1
  434. package/dist/editor/theme.js +0 -1
  435. package/dist/editor/utils/env.d.ts +0 -1
  436. package/dist/editor/utils/env.js +0 -1
  437. package/dist/entry-link-resolver.d.ts +1 -2
  438. package/dist/entry-link-resolver.js +0 -1
  439. package/dist/entry-schema-registry.d.ts +3 -4
  440. package/dist/entry-schema-registry.js +6 -2
  441. package/dist/entry-schema.d.ts +114 -3
  442. package/dist/entry-schema.js +46 -1
  443. package/dist/git-manager.d.ts +1 -2
  444. package/dist/git-manager.js +0 -1
  445. package/dist/github-service.d.ts +1 -2
  446. package/dist/github-service.js +0 -1
  447. package/dist/http/handler.d.ts +6 -7
  448. package/dist/http/handler.js +0 -1
  449. package/dist/http/index.d.ts +6 -7
  450. package/dist/http/index.js +0 -1
  451. package/dist/http/router.d.ts +2 -3
  452. package/dist/http/router.js +0 -1
  453. package/dist/http/types.d.ts +0 -1
  454. package/dist/http/types.js +0 -1
  455. package/dist/id.d.ts +2 -3
  456. package/dist/id.js +0 -1
  457. package/dist/index.d.ts +17 -18
  458. package/dist/index.js +0 -1
  459. package/dist/operating-mode/client-safe-strategy.d.ts +1 -2
  460. package/dist/operating-mode/client-safe-strategy.js +0 -1
  461. package/dist/operating-mode/client-unsafe-strategy.d.ts +1 -2
  462. package/dist/operating-mode/client-unsafe-strategy.js +0 -1
  463. package/dist/operating-mode/client.d.ts +3 -4
  464. package/dist/operating-mode/client.js +0 -1
  465. package/dist/operating-mode/deployment-name-fixtures.d.ts +0 -1
  466. package/dist/operating-mode/deployment-name-fixtures.js +0 -1
  467. package/dist/operating-mode/deployment-name.d.ts +0 -1
  468. package/dist/operating-mode/deployment-name.js +0 -1
  469. package/dist/operating-mode/index.d.ts +5 -6
  470. package/dist/operating-mode/index.js +0 -1
  471. package/dist/operating-mode/mode-env.d.ts +1 -2
  472. package/dist/operating-mode/mode-env.js +0 -1
  473. package/dist/operating-mode/types.d.ts +2 -3
  474. package/dist/operating-mode/types.js +0 -1
  475. package/dist/paths/branch-name.d.ts +1 -2
  476. package/dist/paths/branch-name.js +0 -1
  477. package/dist/paths/branch.d.ts +3 -4
  478. package/dist/paths/branch.js +0 -1
  479. package/dist/paths/index.d.ts +8 -9
  480. package/dist/paths/index.js +0 -1
  481. package/dist/paths/normalize-server.d.ts +1 -2
  482. package/dist/paths/normalize-server.js +0 -1
  483. package/dist/paths/normalize.d.ts +1 -2
  484. package/dist/paths/normalize.js +0 -1
  485. package/dist/paths/resolve.d.ts +2 -3
  486. package/dist/paths/resolve.js +0 -1
  487. package/dist/paths/types.d.ts +0 -1
  488. package/dist/paths/types.js +0 -1
  489. package/dist/paths/validation.d.ts +1 -2
  490. package/dist/paths/validation.js +0 -1
  491. package/dist/reference-resolver.d.ts +3 -4
  492. package/dist/reference-resolver.js +0 -1
  493. package/dist/resolve-canopy-user.d.ts +3 -4
  494. package/dist/resolve-canopy-user.js +0 -1
  495. package/dist/resource-generation.d.ts +0 -1
  496. package/dist/resource-generation.js +0 -1
  497. package/dist/schema/index.d.ts +3 -4
  498. package/dist/schema/index.js +0 -1
  499. package/dist/schema/meta-loader.d.ts +3 -4
  500. package/dist/schema/meta-loader.js +3 -3
  501. package/dist/schema/resolver.d.ts +2 -3
  502. package/dist/schema/resolver.js +0 -1
  503. package/dist/schema/schema-store-types.d.ts +2 -3
  504. package/dist/schema/schema-store-types.js +0 -1
  505. package/dist/schema/schema-store.d.ts +6 -7
  506. package/dist/schema/schema-store.js +33 -1
  507. package/dist/schema/types.d.ts +1 -2
  508. package/dist/schema/types.js +0 -1
  509. package/dist/server.d.ts +54 -45
  510. package/dist/server.js +11 -3
  511. package/dist/services.d.ts +10 -11
  512. package/dist/services.js +0 -1
  513. package/dist/settings-workspace.d.ts +12 -15
  514. package/dist/settings-workspace.js +10 -13
  515. package/dist/static/index.d.ts +164 -6
  516. package/dist/static/index.js +242 -7
  517. package/dist/static/seo.d.ts +8 -30
  518. package/dist/static/seo.js +19 -46
  519. package/dist/sync-core.d.ts +0 -1
  520. package/dist/sync-core.js +0 -1
  521. package/dist/task-queue/index.d.ts +2 -3
  522. package/dist/task-queue/index.js +0 -1
  523. package/dist/task-queue/task-queue.d.ts +1 -2
  524. package/dist/task-queue/task-queue.js +0 -1
  525. package/dist/task-queue/types.d.ts +0 -1
  526. package/dist/task-queue/types.js +0 -1
  527. package/dist/types.d.ts +3 -4
  528. package/dist/types.js +0 -1
  529. package/dist/url-collision.d.ts +86 -0
  530. package/dist/url-collision.js +186 -0
  531. package/dist/url-path-resolver.d.ts +11 -2
  532. package/dist/url-path-resolver.js +37 -5
  533. package/dist/user.d.ts +3 -4
  534. package/dist/user.js +0 -1
  535. package/dist/utils/async-mutex.d.ts +0 -1
  536. package/dist/utils/async-mutex.js +0 -1
  537. package/dist/utils/atomic-write.d.ts +0 -1
  538. package/dist/utils/atomic-write.js +0 -1
  539. package/dist/utils/body-field.d.ts +12 -2
  540. package/dist/utils/body-field.js +17 -1
  541. package/dist/utils/content-serialize.d.ts +37 -0
  542. package/dist/utils/content-serialize.js +429 -0
  543. package/dist/utils/content-write-lock.d.ts +12 -16
  544. package/dist/utils/content-write-lock.js +38 -22
  545. package/dist/utils/debug.d.ts +0 -1
  546. package/dist/utils/debug.js +0 -1
  547. package/dist/utils/entry-url.d.ts +17 -1
  548. package/dist/utils/entry-url.js +21 -3
  549. package/dist/utils/error.d.ts +0 -1
  550. package/dist/utils/error.js +0 -1
  551. package/dist/utils/flatten-group-fields.d.ts +1 -2
  552. package/dist/utils/flatten-group-fields.js +0 -1
  553. package/dist/utils/format.d.ts +1 -2
  554. package/dist/utils/format.js +0 -1
  555. package/dist/utils/fs.d.ts +7 -1
  556. package/dist/utils/fs.js +16 -1
  557. package/dist/utils/git.d.ts +1 -2
  558. package/dist/utils/git.js +0 -1
  559. package/dist/utils/logger.d.ts +0 -1
  560. package/dist/utils/logger.js +0 -1
  561. package/dist/utils/occ-json-write.d.ts +0 -1
  562. package/dist/utils/occ-json-write.js +0 -1
  563. package/dist/utils/provisioning-lock.d.ts +17 -4
  564. package/dist/utils/provisioning-lock.js +94 -14
  565. package/dist/utils/sanitize-href.d.ts +2 -3
  566. package/dist/utils/sanitize-href.js +2 -3
  567. package/dist/utils/title-field.d.ts +1 -2
  568. package/dist/utils/title-field.js +0 -1
  569. package/dist/utils/typed-filename.d.ts +61 -0
  570. package/dist/utils/typed-filename.js +92 -0
  571. package/dist/utils/url-prefix.d.ts +121 -0
  572. package/dist/utils/url-prefix.js +158 -0
  573. package/dist/validation/block-structural-keys.d.ts +42 -0
  574. package/dist/validation/block-structural-keys.js +44 -0
  575. package/dist/validation/deletion-checker.d.ts +4 -5
  576. package/dist/validation/deletion-checker.js +0 -1
  577. package/dist/validation/entry-link-validator.d.ts +2 -3
  578. package/dist/validation/entry-link-validator.js +0 -1
  579. package/dist/validation/entry-type-reference-validator.d.ts +1 -2
  580. package/dist/validation/entry-type-reference-validator.js +0 -1
  581. package/dist/validation/entry-validator.d.ts +23 -2
  582. package/dist/validation/entry-validator.js +34 -2
  583. package/dist/validation/field-traversal.d.ts +28 -4
  584. package/dist/validation/field-traversal.js +24 -7
  585. package/dist/validation/reference-validator.d.ts +2 -3
  586. package/dist/validation/reference-validator.js +0 -1
  587. package/dist/worker/cms-worker.d.ts +9 -2
  588. package/dist/worker/cms-worker.js +59 -2
  589. package/dist/worker/log.d.ts +0 -1
  590. package/dist/worker/log.js +0 -1
  591. package/dist/worker/task-queue-config.d.ts +1 -2
  592. package/dist/worker/task-queue-config.js +0 -1
  593. package/dist/worker/task-queue.d.ts +3 -4
  594. package/dist/worker/task-queue.js +0 -1
  595. package/dist/worker/worker-status.d.ts +1 -2
  596. package/dist/worker/worker-status.js +0 -1
  597. package/package.json +2 -6
  598. package/dist/ai/generate.d.ts.map +0 -1
  599. package/dist/ai/generate.js.map +0 -1
  600. package/dist/ai/handler.d.ts.map +0 -1
  601. package/dist/ai/handler.js.map +0 -1
  602. package/dist/ai/index.d.ts.map +0 -1
  603. package/dist/ai/index.js.map +0 -1
  604. package/dist/ai/json-to-markdown.d.ts.map +0 -1
  605. package/dist/ai/json-to-markdown.js.map +0 -1
  606. package/dist/ai/resolve-branch.d.ts.map +0 -1
  607. package/dist/ai/resolve-branch.js.map +0 -1
  608. package/dist/ai/strip-mdx.d.ts.map +0 -1
  609. package/dist/ai/strip-mdx.js.map +0 -1
  610. package/dist/ai/to-plain-text.d.ts.map +0 -1
  611. package/dist/ai/to-plain-text.js.map +0 -1
  612. package/dist/ai/transform-components.d.ts.map +0 -1
  613. package/dist/ai/transform-components.js.map +0 -1
  614. package/dist/ai/types.d.ts.map +0 -1
  615. package/dist/ai/types.js.map +0 -1
  616. package/dist/api/__test__/mock-client.d.ts +0 -231
  617. package/dist/api/__test__/mock-client.d.ts.map +0 -1
  618. package/dist/api/__test__/mock-client.js +0 -388
  619. package/dist/api/__test__/mock-client.js.map +0 -1
  620. package/dist/api/admin-branch-health.d.ts.map +0 -1
  621. package/dist/api/admin-branch-health.js.map +0 -1
  622. package/dist/api/admin.d.ts.map +0 -1
  623. package/dist/api/admin.js.map +0 -1
  624. package/dist/api/assets.d.ts.map +0 -1
  625. package/dist/api/assets.js.map +0 -1
  626. package/dist/api/branch-merge.d.ts.map +0 -1
  627. package/dist/api/branch-merge.js.map +0 -1
  628. package/dist/api/branch-review.d.ts.map +0 -1
  629. package/dist/api/branch-review.js.map +0 -1
  630. package/dist/api/branch-status.d.ts.map +0 -1
  631. package/dist/api/branch-status.js.map +0 -1
  632. package/dist/api/branch-withdraw.d.ts.map +0 -1
  633. package/dist/api/branch-withdraw.js.map +0 -1
  634. package/dist/api/branch.d.ts.map +0 -1
  635. package/dist/api/branch.js.map +0 -1
  636. package/dist/api/client.d.ts.map +0 -1
  637. package/dist/api/client.js.map +0 -1
  638. package/dist/api/comments.d.ts.map +0 -1
  639. package/dist/api/comments.js.map +0 -1
  640. package/dist/api/content.d.ts.map +0 -1
  641. package/dist/api/content.js.map +0 -1
  642. package/dist/api/entries-constants.d.ts.map +0 -1
  643. package/dist/api/entries-constants.js.map +0 -1
  644. package/dist/api/entries.d.ts.map +0 -1
  645. package/dist/api/entries.js.map +0 -1
  646. package/dist/api/github-sync.d.ts.map +0 -1
  647. package/dist/api/github-sync.js.map +0 -1
  648. package/dist/api/groups.d.ts.map +0 -1
  649. package/dist/api/groups.js.map +0 -1
  650. package/dist/api/guards.d.ts.map +0 -1
  651. package/dist/api/guards.js.map +0 -1
  652. package/dist/api/index.d.ts.map +0 -1
  653. package/dist/api/index.js.map +0 -1
  654. package/dist/api/permissions.d.ts.map +0 -1
  655. package/dist/api/permissions.js.map +0 -1
  656. package/dist/api/reference-options.d.ts.map +0 -1
  657. package/dist/api/reference-options.js.map +0 -1
  658. package/dist/api/request-body-hash.d.ts.map +0 -1
  659. package/dist/api/request-body-hash.js.map +0 -1
  660. package/dist/api/resolve-references.d.ts.map +0 -1
  661. package/dist/api/resolve-references.js.map +0 -1
  662. package/dist/api/route-builder.d.ts.map +0 -1
  663. package/dist/api/route-builder.js.map +0 -1
  664. package/dist/api/schema.d.ts.map +0 -1
  665. package/dist/api/schema.js.map +0 -1
  666. package/dist/api/settings-helpers.d.ts.map +0 -1
  667. package/dist/api/settings-helpers.js.map +0 -1
  668. package/dist/api/types.d.ts.map +0 -1
  669. package/dist/api/types.js.map +0 -1
  670. package/dist/api/user.d.ts.map +0 -1
  671. package/dist/api/user.js.map +0 -1
  672. package/dist/api/validators.d.ts.map +0 -1
  673. package/dist/api/validators.js.map +0 -1
  674. package/dist/assets/asset-prefixes.d.ts.map +0 -1
  675. package/dist/assets/asset-prefixes.js.map +0 -1
  676. package/dist/assets/asset-src.d.ts.map +0 -1
  677. package/dist/assets/asset-src.js.map +0 -1
  678. package/dist/assets/asset-url.d.ts.map +0 -1
  679. package/dist/assets/asset-url.js.map +0 -1
  680. package/dist/assets/factory.d.ts.map +0 -1
  681. package/dist/assets/factory.js.map +0 -1
  682. package/dist/assets/finalize.d.ts.map +0 -1
  683. package/dist/assets/finalize.js.map +0 -1
  684. package/dist/assets/index.d.ts.map +0 -1
  685. package/dist/assets/index.js.map +0 -1
  686. package/dist/assets/keys.d.ts.map +0 -1
  687. package/dist/assets/keys.js.map +0 -1
  688. package/dist/assets/pipeline.d.ts.map +0 -1
  689. package/dist/assets/pipeline.js.map +0 -1
  690. package/dist/assets/store-local.d.ts.map +0 -1
  691. package/dist/assets/store-local.js.map +0 -1
  692. package/dist/assets/store-s3.d.ts.map +0 -1
  693. package/dist/assets/store-s3.js.map +0 -1
  694. package/dist/assets/svg-sanitizer.d.ts.map +0 -1
  695. package/dist/assets/svg-sanitizer.js.map +0 -1
  696. package/dist/assets/transform-directives.d.ts.map +0 -1
  697. package/dist/assets/transform-directives.js.map +0 -1
  698. package/dist/assets/transform.d.ts.map +0 -1
  699. package/dist/assets/transform.js.map +0 -1
  700. package/dist/assets/types.d.ts.map +0 -1
  701. package/dist/assets/types.js.map +0 -1
  702. package/dist/auth/cache.d.ts.map +0 -1
  703. package/dist/auth/cache.js.map +0 -1
  704. package/dist/auth/caching-auth-plugin.d.ts.map +0 -1
  705. package/dist/auth/caching-auth-plugin.js.map +0 -1
  706. package/dist/auth/context-helpers.d.ts.map +0 -1
  707. package/dist/auth/context-helpers.js.map +0 -1
  708. package/dist/auth/file-based-auth-cache.d.ts.map +0 -1
  709. package/dist/auth/file-based-auth-cache.js.map +0 -1
  710. package/dist/auth/index.d.ts.map +0 -1
  711. package/dist/auth/index.js.map +0 -1
  712. package/dist/auth/plugin.d.ts.map +0 -1
  713. package/dist/auth/plugin.js.map +0 -1
  714. package/dist/auth/types.d.ts.map +0 -1
  715. package/dist/auth/types.js.map +0 -1
  716. package/dist/authorization/branch.d.ts.map +0 -1
  717. package/dist/authorization/branch.js.map +0 -1
  718. package/dist/authorization/content.d.ts.map +0 -1
  719. package/dist/authorization/content.js.map +0 -1
  720. package/dist/authorization/groups/index.d.ts.map +0 -1
  721. package/dist/authorization/groups/index.js.map +0 -1
  722. package/dist/authorization/groups/loader.d.ts.map +0 -1
  723. package/dist/authorization/groups/loader.js.map +0 -1
  724. package/dist/authorization/groups/schema.d.ts.map +0 -1
  725. package/dist/authorization/groups/schema.js.map +0 -1
  726. package/dist/authorization/helpers.d.ts.map +0 -1
  727. package/dist/authorization/helpers.js.map +0 -1
  728. package/dist/authorization/index.d.ts.map +0 -1
  729. package/dist/authorization/index.js.map +0 -1
  730. package/dist/authorization/path.d.ts.map +0 -1
  731. package/dist/authorization/path.js.map +0 -1
  732. package/dist/authorization/permissions/index.d.ts.map +0 -1
  733. package/dist/authorization/permissions/index.js.map +0 -1
  734. package/dist/authorization/permissions/loader.d.ts.map +0 -1
  735. package/dist/authorization/permissions/loader.js.map +0 -1
  736. package/dist/authorization/permissions/schema.d.ts.map +0 -1
  737. package/dist/authorization/permissions/schema.js.map +0 -1
  738. package/dist/authorization/protected-branch.d.ts.map +0 -1
  739. package/dist/authorization/protected-branch.js.map +0 -1
  740. package/dist/authorization/settings-file-store.d.ts.map +0 -1
  741. package/dist/authorization/settings-file-store.js.map +0 -1
  742. package/dist/authorization/test-utils.d.ts +0 -26
  743. package/dist/authorization/test-utils.d.ts.map +0 -1
  744. package/dist/authorization/test-utils.js +0 -23
  745. package/dist/authorization/test-utils.js.map +0 -1
  746. package/dist/authorization/types.d.ts.map +0 -1
  747. package/dist/authorization/types.js.map +0 -1
  748. package/dist/authorization/validation.d.ts.map +0 -1
  749. package/dist/authorization/validation.js.map +0 -1
  750. package/dist/branch-health.d.ts.map +0 -1
  751. package/dist/branch-health.js.map +0 -1
  752. package/dist/branch-metadata.d.ts.map +0 -1
  753. package/dist/branch-metadata.js.map +0 -1
  754. package/dist/branch-registry.d.ts.map +0 -1
  755. package/dist/branch-registry.js.map +0 -1
  756. package/dist/branch-schema-cache.d.ts.map +0 -1
  757. package/dist/branch-schema-cache.js.map +0 -1
  758. package/dist/branch-workspace.d.ts.map +0 -1
  759. package/dist/branch-workspace.js.map +0 -1
  760. package/dist/build/generate-ai-content.d.ts.map +0 -1
  761. package/dist/build/generate-ai-content.js.map +0 -1
  762. package/dist/build/index.d.ts.map +0 -1
  763. package/dist/build/index.js.map +0 -1
  764. package/dist/build-canopy.d.ts.map +0 -1
  765. package/dist/build-canopy.js.map +0 -1
  766. package/dist/build-mode.d.ts.map +0 -1
  767. package/dist/build-mode.js.map +0 -1
  768. package/dist/cli/cli.d.ts.map +0 -1
  769. package/dist/cli/cli.js.map +0 -1
  770. package/dist/cli/generate-ai-content.d.ts.map +0 -1
  771. package/dist/cli/generate-ai-content.js.map +0 -1
  772. package/dist/cli/init.d.ts.map +0 -1
  773. package/dist/cli/init.js.map +0 -1
  774. package/dist/cli/migrate.d.ts.map +0 -1
  775. package/dist/cli/migrate.js.map +0 -1
  776. package/dist/cli/project-detect.d.ts.map +0 -1
  777. package/dist/cli/project-detect.js.map +0 -1
  778. package/dist/cli/project-root.d.ts.map +0 -1
  779. package/dist/cli/project-root.js.map +0 -1
  780. package/dist/cli/sync.d.ts.map +0 -1
  781. package/dist/cli/sync.js.map +0 -1
  782. package/dist/cli/templates.d.ts.map +0 -1
  783. package/dist/cli/templates.js.map +0 -1
  784. package/dist/client.d.ts.map +0 -1
  785. package/dist/client.js.map +0 -1
  786. package/dist/comment-store.d.ts.map +0 -1
  787. package/dist/comment-store.js.map +0 -1
  788. package/dist/config/flatten.d.ts.map +0 -1
  789. package/dist/config/flatten.js.map +0 -1
  790. package/dist/config/helpers.d.ts.map +0 -1
  791. package/dist/config/helpers.js.map +0 -1
  792. package/dist/config/index.d.ts.map +0 -1
  793. package/dist/config/index.js.map +0 -1
  794. package/dist/config/schemas/collection.d.ts.map +0 -1
  795. package/dist/config/schemas/collection.js.map +0 -1
  796. package/dist/config/schemas/config.d.ts.map +0 -1
  797. package/dist/config/schemas/config.js.map +0 -1
  798. package/dist/config/schemas/field.d.ts.map +0 -1
  799. package/dist/config/schemas/field.js.map +0 -1
  800. package/dist/config/schemas/media.d.ts.map +0 -1
  801. package/dist/config/schemas/media.js.map +0 -1
  802. package/dist/config/schemas/permissions.d.ts.map +0 -1
  803. package/dist/config/schemas/permissions.js.map +0 -1
  804. package/dist/config/types.d.ts.map +0 -1
  805. package/dist/config/types.js.map +0 -1
  806. package/dist/config/validation.d.ts.map +0 -1
  807. package/dist/config/validation.js.map +0 -1
  808. package/dist/config-test.d.ts +0 -20
  809. package/dist/config-test.d.ts.map +0 -1
  810. package/dist/config-test.js +0 -49
  811. package/dist/config-test.js.map +0 -1
  812. package/dist/config.d.ts.map +0 -1
  813. package/dist/config.js.map +0 -1
  814. package/dist/content-id-index.d.ts.map +0 -1
  815. package/dist/content-id-index.js.map +0 -1
  816. package/dist/content-index-generation.d.ts.map +0 -1
  817. package/dist/content-index-generation.js.map +0 -1
  818. package/dist/content-index-registry.d.ts.map +0 -1
  819. package/dist/content-index-registry.js.map +0 -1
  820. package/dist/content-listing.d.ts.map +0 -1
  821. package/dist/content-listing.js.map +0 -1
  822. package/dist/content-reader.d.ts.map +0 -1
  823. package/dist/content-reader.js.map +0 -1
  824. package/dist/content-store.d.ts.map +0 -1
  825. package/dist/content-store.js.map +0 -1
  826. package/dist/content-tree.d.ts.map +0 -1
  827. package/dist/content-tree.js.map +0 -1
  828. package/dist/context.d.ts.map +0 -1
  829. package/dist/context.js.map +0 -1
  830. package/dist/dev-content-watcher.d.ts.map +0 -1
  831. package/dist/dev-content-watcher.js.map +0 -1
  832. package/dist/editor/BranchManager.d.ts.map +0 -1
  833. package/dist/editor/BranchManager.js.map +0 -1
  834. package/dist/editor/CanopyEditor.d.ts.map +0 -1
  835. package/dist/editor/CanopyEditor.js.map +0 -1
  836. package/dist/editor/CanopyEditorPage.d.ts.map +0 -1
  837. package/dist/editor/CanopyEditorPage.js.map +0 -1
  838. package/dist/editor/CommentsPanel.d.ts.map +0 -1
  839. package/dist/editor/CommentsPanel.js.map +0 -1
  840. package/dist/editor/Editor.d.ts.map +0 -1
  841. package/dist/editor/Editor.js.map +0 -1
  842. package/dist/editor/EditorPanes.d.ts.map +0 -1
  843. package/dist/editor/EditorPanes.js.map +0 -1
  844. package/dist/editor/EntryNavigator.d.ts.map +0 -1
  845. package/dist/editor/EntryNavigator.js.map +0 -1
  846. package/dist/editor/FormRenderer.d.ts.map +0 -1
  847. package/dist/editor/FormRenderer.js.map +0 -1
  848. package/dist/editor/GroupManager.d.ts.map +0 -1
  849. package/dist/editor/GroupManager.js.map +0 -1
  850. package/dist/editor/PermissionManager.d.ts.map +0 -1
  851. package/dist/editor/PermissionManager.js.map +0 -1
  852. package/dist/editor/admin/SystemHealthPanel.d.ts.map +0 -1
  853. package/dist/editor/admin/SystemHealthPanel.js.map +0 -1
  854. package/dist/editor/admin/useSystemHealth.d.ts.map +0 -1
  855. package/dist/editor/admin/useSystemHealth.js.map +0 -1
  856. package/dist/editor/canopy-path.d.ts.map +0 -1
  857. package/dist/editor/canopy-path.js.map +0 -1
  858. package/dist/editor/client-reference-resolver.d.ts.map +0 -1
  859. package/dist/editor/client-reference-resolver.js.map +0 -1
  860. package/dist/editor/comments/BranchComments.d.ts.map +0 -1
  861. package/dist/editor/comments/BranchComments.js.map +0 -1
  862. package/dist/editor/comments/EntryComments.d.ts.map +0 -1
  863. package/dist/editor/comments/EntryComments.js.map +0 -1
  864. package/dist/editor/comments/FieldWrapper.d.ts.map +0 -1
  865. package/dist/editor/comments/FieldWrapper.js.map +0 -1
  866. package/dist/editor/comments/InlineCommentThread.d.ts.map +0 -1
  867. package/dist/editor/comments/InlineCommentThread.js.map +0 -1
  868. package/dist/editor/comments/ThreadCarousel.d.ts.map +0 -1
  869. package/dist/editor/comments/ThreadCarousel.js.map +0 -1
  870. package/dist/editor/components/ConfirmDeleteModal.d.ts.map +0 -1
  871. package/dist/editor/components/ConfirmDeleteModal.js.map +0 -1
  872. package/dist/editor/components/EditorFooter.d.ts.map +0 -1
  873. package/dist/editor/components/EditorFooter.js.map +0 -1
  874. package/dist/editor/components/EditorHeader.d.ts.map +0 -1
  875. package/dist/editor/components/EditorHeader.js.map +0 -1
  876. package/dist/editor/components/EditorSidebar.d.ts.map +0 -1
  877. package/dist/editor/components/EditorSidebar.js.map +0 -1
  878. package/dist/editor/components/EntryCreateModal.d.ts.map +0 -1
  879. package/dist/editor/components/EntryCreateModal.js.map +0 -1
  880. package/dist/editor/components/RenameEntryModal.d.ts.map +0 -1
  881. package/dist/editor/components/RenameEntryModal.js.map +0 -1
  882. package/dist/editor/components/UserBadge.d.ts.map +0 -1
  883. package/dist/editor/components/UserBadge.js.map +0 -1
  884. package/dist/editor/components/index.d.ts.map +0 -1
  885. package/dist/editor/components/index.js.map +0 -1
  886. package/dist/editor/context/ApiClientContext.d.ts.map +0 -1
  887. package/dist/editor/context/ApiClientContext.js.map +0 -1
  888. package/dist/editor/context/AssetContext.d.ts.map +0 -1
  889. package/dist/editor/context/AssetContext.js.map +0 -1
  890. package/dist/editor/context/EditorStateContext.d.ts.map +0 -1
  891. package/dist/editor/context/EditorStateContext.js.map +0 -1
  892. package/dist/editor/context/SWRProvider.d.ts.map +0 -1
  893. package/dist/editor/context/SWRProvider.js.map +0 -1
  894. package/dist/editor/context/index.d.ts.map +0 -1
  895. package/dist/editor/context/index.js.map +0 -1
  896. package/dist/editor/editor-config.d.ts.map +0 -1
  897. package/dist/editor/editor-config.js.map +0 -1
  898. package/dist/editor/editor-utils.d.ts.map +0 -1
  899. package/dist/editor/editor-utils.js.map +0 -1
  900. package/dist/editor/fields/BlockField.d.ts.map +0 -1
  901. package/dist/editor/fields/BlockField.js.map +0 -1
  902. package/dist/editor/fields/CodeField.d.ts.map +0 -1
  903. package/dist/editor/fields/CodeField.js.map +0 -1
  904. package/dist/editor/fields/DateTimeField.d.ts.map +0 -1
  905. package/dist/editor/fields/DateTimeField.js.map +0 -1
  906. package/dist/editor/fields/ImageField.d.ts.map +0 -1
  907. package/dist/editor/fields/ImageField.js.map +0 -1
  908. package/dist/editor/fields/InlineGroupField.d.ts.map +0 -1
  909. package/dist/editor/fields/InlineGroupField.js.map +0 -1
  910. package/dist/editor/fields/MarkdownField.d.ts.map +0 -1
  911. package/dist/editor/fields/MarkdownField.js.map +0 -1
  912. package/dist/editor/fields/MdxImageDialog.d.ts.map +0 -1
  913. package/dist/editor/fields/MdxImageDialog.js.map +0 -1
  914. package/dist/editor/fields/NumberField.d.ts.map +0 -1
  915. package/dist/editor/fields/NumberField.js.map +0 -1
  916. package/dist/editor/fields/NumberListField.d.ts.map +0 -1
  917. package/dist/editor/fields/NumberListField.js.map +0 -1
  918. package/dist/editor/fields/ObjectField.d.ts.map +0 -1
  919. package/dist/editor/fields/ObjectField.js.map +0 -1
  920. package/dist/editor/fields/ReferenceField.d.ts.map +0 -1
  921. package/dist/editor/fields/ReferenceField.js.map +0 -1
  922. package/dist/editor/fields/SelectField.d.ts.map +0 -1
  923. package/dist/editor/fields/SelectField.js.map +0 -1
  924. package/dist/editor/fields/StringListField.d.ts.map +0 -1
  925. package/dist/editor/fields/StringListField.js.map +0 -1
  926. package/dist/editor/fields/TextField.d.ts.map +0 -1
  927. package/dist/editor/fields/TextField.js.map +0 -1
  928. package/dist/editor/fields/ToggleField.d.ts.map +0 -1
  929. package/dist/editor/fields/ToggleField.js.map +0 -1
  930. package/dist/editor/fields/entry-link/EntryLinkContext.d.ts.map +0 -1
  931. package/dist/editor/fields/entry-link/EntryLinkContext.js.map +0 -1
  932. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts.map +0 -1
  933. package/dist/editor/fields/entry-link/InsertEntryLink.js.map +0 -1
  934. package/dist/editor/fields/entry-link/index.d.ts.map +0 -1
  935. package/dist/editor/fields/entry-link/index.js.map +0 -1
  936. package/dist/editor/group-manager/ExternalGroupsTab.d.ts.map +0 -1
  937. package/dist/editor/group-manager/ExternalGroupsTab.js.map +0 -1
  938. package/dist/editor/group-manager/GroupCard.d.ts.map +0 -1
  939. package/dist/editor/group-manager/GroupCard.js.map +0 -1
  940. package/dist/editor/group-manager/GroupForm.d.ts.map +0 -1
  941. package/dist/editor/group-manager/GroupForm.js.map +0 -1
  942. package/dist/editor/group-manager/InternalGroupsTab.d.ts.map +0 -1
  943. package/dist/editor/group-manager/InternalGroupsTab.js.map +0 -1
  944. package/dist/editor/group-manager/MemberList.d.ts.map +0 -1
  945. package/dist/editor/group-manager/MemberList.js.map +0 -1
  946. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts.map +0 -1
  947. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js.map +0 -1
  948. package/dist/editor/group-manager/hooks/useGroupState.d.ts.map +0 -1
  949. package/dist/editor/group-manager/hooks/useGroupState.js.map +0 -1
  950. package/dist/editor/group-manager/hooks/useUserSearch.d.ts.map +0 -1
  951. package/dist/editor/group-manager/hooks/useUserSearch.js.map +0 -1
  952. package/dist/editor/group-manager/index.d.ts.map +0 -1
  953. package/dist/editor/group-manager/index.js.map +0 -1
  954. package/dist/editor/group-manager/types.d.ts.map +0 -1
  955. package/dist/editor/group-manager/types.js.map +0 -1
  956. package/dist/editor/hooks/__test__/test-utils.d.ts +0 -164
  957. package/dist/editor/hooks/__test__/test-utils.d.ts.map +0 -1
  958. package/dist/editor/hooks/__test__/test-utils.js +0 -203
  959. package/dist/editor/hooks/__test__/test-utils.js.map +0 -1
  960. package/dist/editor/hooks/index.d.ts.map +0 -1
  961. package/dist/editor/hooks/index.js.map +0 -1
  962. package/dist/editor/hooks/useBranchActions.d.ts.map +0 -1
  963. package/dist/editor/hooks/useBranchActions.js.map +0 -1
  964. package/dist/editor/hooks/useBranchManager.d.ts.map +0 -1
  965. package/dist/editor/hooks/useBranchManager.js.map +0 -1
  966. package/dist/editor/hooks/useBranchesData.d.ts.map +0 -1
  967. package/dist/editor/hooks/useBranchesData.js.map +0 -1
  968. package/dist/editor/hooks/useCommentSystem.d.ts.map +0 -1
  969. package/dist/editor/hooks/useCommentSystem.js.map +0 -1
  970. package/dist/editor/hooks/useCommentsData.d.ts.map +0 -1
  971. package/dist/editor/hooks/useCommentsData.js.map +0 -1
  972. package/dist/editor/hooks/useDraftManager.d.ts.map +0 -1
  973. package/dist/editor/hooks/useDraftManager.js.map +0 -1
  974. package/dist/editor/hooks/useEditorLayout.d.ts.map +0 -1
  975. package/dist/editor/hooks/useEditorLayout.js.map +0 -1
  976. package/dist/editor/hooks/useEntriesData.d.ts.map +0 -1
  977. package/dist/editor/hooks/useEntriesData.js.map +0 -1
  978. package/dist/editor/hooks/useEntryLinkResolution.d.ts.map +0 -1
  979. package/dist/editor/hooks/useEntryLinkResolution.js.map +0 -1
  980. package/dist/editor/hooks/useEntryManager.d.ts.map +0 -1
  981. package/dist/editor/hooks/useEntryManager.js.map +0 -1
  982. package/dist/editor/hooks/useGroupManager.d.ts.map +0 -1
  983. package/dist/editor/hooks/useGroupManager.js.map +0 -1
  984. package/dist/editor/hooks/usePermissionManager.d.ts.map +0 -1
  985. package/dist/editor/hooks/usePermissionManager.js.map +0 -1
  986. package/dist/editor/hooks/useReferenceResolution.d.ts.map +0 -1
  987. package/dist/editor/hooks/useReferenceResolution.js.map +0 -1
  988. package/dist/editor/hooks/useSchemaManager.d.ts.map +0 -1
  989. package/dist/editor/hooks/useSchemaManager.js.map +0 -1
  990. package/dist/editor/hooks/useUserContext.d.ts.map +0 -1
  991. package/dist/editor/hooks/useUserContext.js.map +0 -1
  992. package/dist/editor/hooks/useUserMetadata.d.ts.map +0 -1
  993. package/dist/editor/hooks/useUserMetadata.js.map +0 -1
  994. package/dist/editor/media/AssetCard.d.ts.map +0 -1
  995. package/dist/editor/media/AssetCard.js.map +0 -1
  996. package/dist/editor/media/CropStep.d.ts.map +0 -1
  997. package/dist/editor/media/CropStep.js.map +0 -1
  998. package/dist/editor/media/MediaLibrary.d.ts.map +0 -1
  999. package/dist/editor/media/MediaLibrary.js.map +0 -1
  1000. package/dist/editor/media/MediaLibraryBody.d.ts.map +0 -1
  1001. package/dist/editor/media/MediaLibraryBody.js.map +0 -1
  1002. package/dist/editor/media/crop-math.d.ts.map +0 -1
  1003. package/dist/editor/media/crop-math.js.map +0 -1
  1004. package/dist/editor/media/upload-asset.d.ts.map +0 -1
  1005. package/dist/editor/media/upload-asset.js.map +0 -1
  1006. package/dist/editor/media/upload-constants.d.ts.map +0 -1
  1007. package/dist/editor/media/upload-constants.js.map +0 -1
  1008. package/dist/editor/media/useAssetUpload.d.ts.map +0 -1
  1009. package/dist/editor/media/useAssetUpload.js.map +0 -1
  1010. package/dist/editor/media/xhr-upload.d.ts.map +0 -1
  1011. package/dist/editor/media/xhr-upload.js.map +0 -1
  1012. package/dist/editor/permission-manager/GroupSelector.d.ts.map +0 -1
  1013. package/dist/editor/permission-manager/GroupSelector.js.map +0 -1
  1014. package/dist/editor/permission-manager/PermissionEditor.d.ts.map +0 -1
  1015. package/dist/editor/permission-manager/PermissionEditor.js.map +0 -1
  1016. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts.map +0 -1
  1017. package/dist/editor/permission-manager/PermissionLevelBadge.js.map +0 -1
  1018. package/dist/editor/permission-manager/PermissionTree.d.ts.map +0 -1
  1019. package/dist/editor/permission-manager/PermissionTree.js.map +0 -1
  1020. package/dist/editor/permission-manager/UserSelector.d.ts.map +0 -1
  1021. package/dist/editor/permission-manager/UserSelector.js.map +0 -1
  1022. package/dist/editor/permission-manager/constants.d.ts.map +0 -1
  1023. package/dist/editor/permission-manager/constants.js.map +0 -1
  1024. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts.map +0 -1
  1025. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js.map +0 -1
  1026. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts.map +0 -1
  1027. package/dist/editor/permission-manager/hooks/usePermissionTree.js.map +0 -1
  1028. package/dist/editor/permission-manager/index.d.ts.map +0 -1
  1029. package/dist/editor/permission-manager/index.js.map +0 -1
  1030. package/dist/editor/permission-manager/types.d.ts.map +0 -1
  1031. package/dist/editor/permission-manager/types.js.map +0 -1
  1032. package/dist/editor/permission-manager/utils.d.ts.map +0 -1
  1033. package/dist/editor/permission-manager/utils.js.map +0 -1
  1034. package/dist/editor/preview-bridge.d.ts.map +0 -1
  1035. package/dist/editor/preview-bridge.js.map +0 -1
  1036. package/dist/editor/relative-time.d.ts.map +0 -1
  1037. package/dist/editor/relative-time.js.map +0 -1
  1038. package/dist/editor/schema-editor/CollectionEditor.d.ts.map +0 -1
  1039. package/dist/editor/schema-editor/CollectionEditor.js.map +0 -1
  1040. package/dist/editor/schema-editor/EntryTypeEditor.d.ts.map +0 -1
  1041. package/dist/editor/schema-editor/EntryTypeEditor.js.map +0 -1
  1042. package/dist/editor/schema-editor/index.d.ts.map +0 -1
  1043. package/dist/editor/schema-editor/index.js.map +0 -1
  1044. package/dist/editor/setup-test-dom.d.ts +0 -1
  1045. package/dist/editor/setup-test-dom.d.ts.map +0 -1
  1046. package/dist/editor/setup-test-dom.js +0 -12
  1047. package/dist/editor/setup-test-dom.js.map +0 -1
  1048. package/dist/editor/test-setup.d.ts +0 -6
  1049. package/dist/editor/test-setup.d.ts.map +0 -1
  1050. package/dist/editor/test-setup.js +0 -42
  1051. package/dist/editor/test-setup.js.map +0 -1
  1052. package/dist/editor/theme.d.ts.map +0 -1
  1053. package/dist/editor/theme.js.map +0 -1
  1054. package/dist/editor/utils/env.d.ts.map +0 -1
  1055. package/dist/editor/utils/env.js.map +0 -1
  1056. package/dist/entry-link-resolver.d.ts.map +0 -1
  1057. package/dist/entry-link-resolver.js.map +0 -1
  1058. package/dist/entry-schema-registry.d.ts.map +0 -1
  1059. package/dist/entry-schema-registry.js.map +0 -1
  1060. package/dist/entry-schema.d.ts.map +0 -1
  1061. package/dist/entry-schema.js.map +0 -1
  1062. package/dist/git-manager.d.ts.map +0 -1
  1063. package/dist/git-manager.js.map +0 -1
  1064. package/dist/github-service.d.ts.map +0 -1
  1065. package/dist/github-service.js.map +0 -1
  1066. package/dist/http/handler.d.ts.map +0 -1
  1067. package/dist/http/handler.js.map +0 -1
  1068. package/dist/http/index.d.ts.map +0 -1
  1069. package/dist/http/index.js.map +0 -1
  1070. package/dist/http/router.d.ts.map +0 -1
  1071. package/dist/http/router.js.map +0 -1
  1072. package/dist/http/types.d.ts.map +0 -1
  1073. package/dist/http/types.js.map +0 -1
  1074. package/dist/id.d.ts.map +0 -1
  1075. package/dist/id.js.map +0 -1
  1076. package/dist/index.d.ts.map +0 -1
  1077. package/dist/index.js.map +0 -1
  1078. package/dist/operating-mode/client-safe-strategy.d.ts.map +0 -1
  1079. package/dist/operating-mode/client-safe-strategy.js.map +0 -1
  1080. package/dist/operating-mode/client-unsafe-strategy.d.ts.map +0 -1
  1081. package/dist/operating-mode/client-unsafe-strategy.js.map +0 -1
  1082. package/dist/operating-mode/client.d.ts.map +0 -1
  1083. package/dist/operating-mode/client.js.map +0 -1
  1084. package/dist/operating-mode/deployment-name-fixtures.d.ts.map +0 -1
  1085. package/dist/operating-mode/deployment-name-fixtures.js.map +0 -1
  1086. package/dist/operating-mode/deployment-name.d.ts.map +0 -1
  1087. package/dist/operating-mode/deployment-name.js.map +0 -1
  1088. package/dist/operating-mode/index.d.ts.map +0 -1
  1089. package/dist/operating-mode/index.js.map +0 -1
  1090. package/dist/operating-mode/mode-env.d.ts.map +0 -1
  1091. package/dist/operating-mode/mode-env.js.map +0 -1
  1092. package/dist/operating-mode/types.d.ts.map +0 -1
  1093. package/dist/operating-mode/types.js.map +0 -1
  1094. package/dist/paths/branch-name.d.ts.map +0 -1
  1095. package/dist/paths/branch-name.js.map +0 -1
  1096. package/dist/paths/branch.d.ts.map +0 -1
  1097. package/dist/paths/branch.js.map +0 -1
  1098. package/dist/paths/index.d.ts.map +0 -1
  1099. package/dist/paths/index.js.map +0 -1
  1100. package/dist/paths/normalize-server.d.ts.map +0 -1
  1101. package/dist/paths/normalize-server.js.map +0 -1
  1102. package/dist/paths/normalize.d.ts.map +0 -1
  1103. package/dist/paths/normalize.js.map +0 -1
  1104. package/dist/paths/resolve.d.ts.map +0 -1
  1105. package/dist/paths/resolve.js.map +0 -1
  1106. package/dist/paths/test-utils.d.ts +0 -22
  1107. package/dist/paths/test-utils.d.ts.map +0 -1
  1108. package/dist/paths/test-utils.js +0 -21
  1109. package/dist/paths/test-utils.js.map +0 -1
  1110. package/dist/paths/types.d.ts.map +0 -1
  1111. package/dist/paths/types.js.map +0 -1
  1112. package/dist/paths/validation.d.ts.map +0 -1
  1113. package/dist/paths/validation.js.map +0 -1
  1114. package/dist/reference-resolver.d.ts.map +0 -1
  1115. package/dist/reference-resolver.js.map +0 -1
  1116. package/dist/resolve-canopy-user.d.ts.map +0 -1
  1117. package/dist/resolve-canopy-user.js.map +0 -1
  1118. package/dist/resource-generation.d.ts.map +0 -1
  1119. package/dist/resource-generation.js.map +0 -1
  1120. package/dist/schema/index.d.ts.map +0 -1
  1121. package/dist/schema/index.js.map +0 -1
  1122. package/dist/schema/meta-loader.d.ts.map +0 -1
  1123. package/dist/schema/meta-loader.js.map +0 -1
  1124. package/dist/schema/resolver.d.ts.map +0 -1
  1125. package/dist/schema/resolver.js.map +0 -1
  1126. package/dist/schema/schema-store-types.d.ts.map +0 -1
  1127. package/dist/schema/schema-store-types.js.map +0 -1
  1128. package/dist/schema/schema-store.d.ts.map +0 -1
  1129. package/dist/schema/schema-store.js.map +0 -1
  1130. package/dist/schema/types.d.ts.map +0 -1
  1131. package/dist/schema/types.js.map +0 -1
  1132. package/dist/server.d.ts.map +0 -1
  1133. package/dist/server.js.map +0 -1
  1134. package/dist/services.d.ts.map +0 -1
  1135. package/dist/services.js.map +0 -1
  1136. package/dist/settings-workspace.d.ts.map +0 -1
  1137. package/dist/settings-workspace.js.map +0 -1
  1138. package/dist/static/index.d.ts.map +0 -1
  1139. package/dist/static/index.js.map +0 -1
  1140. package/dist/static/seo.d.ts.map +0 -1
  1141. package/dist/static/seo.js.map +0 -1
  1142. package/dist/sync-core.d.ts.map +0 -1
  1143. package/dist/sync-core.js.map +0 -1
  1144. package/dist/task-queue/index.d.ts.map +0 -1
  1145. package/dist/task-queue/index.js.map +0 -1
  1146. package/dist/task-queue/task-queue.d.ts.map +0 -1
  1147. package/dist/task-queue/task-queue.js.map +0 -1
  1148. package/dist/task-queue/types.d.ts.map +0 -1
  1149. package/dist/task-queue/types.js.map +0 -1
  1150. package/dist/types.d.ts.map +0 -1
  1151. package/dist/types.js.map +0 -1
  1152. package/dist/url-path-resolver.d.ts.map +0 -1
  1153. package/dist/url-path-resolver.js.map +0 -1
  1154. package/dist/user.d.ts.map +0 -1
  1155. package/dist/user.js.map +0 -1
  1156. package/dist/utils/async-mutex.d.ts.map +0 -1
  1157. package/dist/utils/async-mutex.js.map +0 -1
  1158. package/dist/utils/atomic-write.d.ts.map +0 -1
  1159. package/dist/utils/atomic-write.js.map +0 -1
  1160. package/dist/utils/body-field.d.ts.map +0 -1
  1161. package/dist/utils/body-field.js.map +0 -1
  1162. package/dist/utils/content-write-lock.d.ts.map +0 -1
  1163. package/dist/utils/content-write-lock.js.map +0 -1
  1164. package/dist/utils/debug.d.ts.map +0 -1
  1165. package/dist/utils/debug.js.map +0 -1
  1166. package/dist/utils/entry-url.d.ts.map +0 -1
  1167. package/dist/utils/entry-url.js.map +0 -1
  1168. package/dist/utils/error.d.ts.map +0 -1
  1169. package/dist/utils/error.js.map +0 -1
  1170. package/dist/utils/flatten-group-fields.d.ts.map +0 -1
  1171. package/dist/utils/flatten-group-fields.js.map +0 -1
  1172. package/dist/utils/format.d.ts.map +0 -1
  1173. package/dist/utils/format.js.map +0 -1
  1174. package/dist/utils/fs.d.ts.map +0 -1
  1175. package/dist/utils/fs.js.map +0 -1
  1176. package/dist/utils/git.d.ts.map +0 -1
  1177. package/dist/utils/git.js.map +0 -1
  1178. package/dist/utils/logger.d.ts.map +0 -1
  1179. package/dist/utils/logger.js.map +0 -1
  1180. package/dist/utils/occ-json-write.d.ts.map +0 -1
  1181. package/dist/utils/occ-json-write.js.map +0 -1
  1182. package/dist/utils/provisioning-lock.d.ts.map +0 -1
  1183. package/dist/utils/provisioning-lock.js.map +0 -1
  1184. package/dist/utils/sanitize-href.d.ts.map +0 -1
  1185. package/dist/utils/sanitize-href.js.map +0 -1
  1186. package/dist/utils/title-field.d.ts.map +0 -1
  1187. package/dist/utils/title-field.js.map +0 -1
  1188. package/dist/validation/deletion-checker.d.ts.map +0 -1
  1189. package/dist/validation/deletion-checker.js.map +0 -1
  1190. package/dist/validation/entry-link-validator.d.ts.map +0 -1
  1191. package/dist/validation/entry-link-validator.js.map +0 -1
  1192. package/dist/validation/entry-type-reference-validator.d.ts.map +0 -1
  1193. package/dist/validation/entry-type-reference-validator.js.map +0 -1
  1194. package/dist/validation/entry-validator.d.ts.map +0 -1
  1195. package/dist/validation/entry-validator.js.map +0 -1
  1196. package/dist/validation/field-traversal.d.ts.map +0 -1
  1197. package/dist/validation/field-traversal.js.map +0 -1
  1198. package/dist/validation/reference-validator.d.ts.map +0 -1
  1199. package/dist/validation/reference-validator.js.map +0 -1
  1200. package/dist/worker/cms-worker.d.ts.map +0 -1
  1201. package/dist/worker/cms-worker.js.map +0 -1
  1202. package/dist/worker/log.d.ts.map +0 -1
  1203. package/dist/worker/log.js.map +0 -1
  1204. package/dist/worker/task-queue-config.d.ts.map +0 -1
  1205. package/dist/worker/task-queue-config.js.map +0 -1
  1206. package/dist/worker/task-queue.d.ts.map +0 -1
  1207. package/dist/worker/task-queue.js.map +0 -1
  1208. package/dist/worker/worker-status.d.ts.map +0 -1
  1209. package/dist/worker/worker-status.js.map +0 -1
package/dist/cli/cli.js CHANGED
@@ -1047,7 +1047,7 @@ CanopyCMS worker run-once (mode: ${mode}, auth: ${authMode})
1047
1047
  }
1048
1048
  console.log("\nDone");
1049
1049
  }
1050
- var __defProp2, __getOwnPropNames2, __esm2, __export2, active, init_logger, primitiveFieldTypes, fieldTypes, init_types, fieldBaseSchema, selectOptionSchema, referenceOptionSchema, primitiveFieldSchema, ASPECT_RATIO_RE, imageFieldSchema, selectFieldSchema, referenceFieldSchema, fieldHolder, blockSchema, blockFieldSchema, objectFieldSchema, inlineGroupFieldSchema, customFieldSchema, knownFieldSchema, fieldSchema, init_field, relativePathSchema, entryTypeSchema, collectionSchema, init_collection, mediaSchema, init_media, defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE, init_config, permissionTargetSchema, pathPermissionSchema, init_permissions, init_normalize, init_types2, init_flatten, init_mode_env, init_validation, init_helpers, init_config2, init_error2, init_fs2, templates_exports, __dirname, TEMPLATES_DIR, SCAFFOLD_STACK_NAME, init_templates, project_detect_exports, COMMANDS, MAX_WORKSPACE_DEPTH, CDK_DEPENDENCIES, init_project_detect, task_queue_config_exports, init_task_queue_config, LOG_LEVELS, DebugLogger, testLogger, init_debug, init_atomic_write, DEFAULT_MAX_RETRIES, nullLogger, init_task_queue, init_task_queue2, task_queue_exports, debugLogger, cmsTaskQueueLogger, init_task_queue3, ProdClientSafeStrategy, DevClientSafeStrategy, warned, VALID_DEPLOYMENT_NAME, isValidDeploymentName, ProdStrategy, DevStrategy, strategyCache;
1050
+ var __defProp2, __getOwnPropNames2, __esm2, __export2, active, init_logger, primitiveFieldTypes, fieldTypes, init_types, fieldBaseSchema, selectOptionSchema, referenceOptionSchema, primitiveFieldSchema, ASPECT_RATIO_RE, imageFieldSchema, selectFieldSchema, referenceFieldSchema, fieldHolder, blockSchema, blockFieldSchema, objectFieldSchema, inlineGroupFieldSchema, customFieldSchema, knownFieldSchema, fieldSchema, init_field, relativePathSchema, entryTypeSchema, collectionSchema, init_collection, mediaSchema, init_media, defaultBranchAccessSchema, defaultPathAccessLevelSchema, defaultPathAccessLevelsSchema, defaultPathAccessSchema, defaultBaseBranchSchema, defaultRemoteNameSchema, defaultRemoteUrlSchema, gitBotAuthorNameSchema, gitBotAuthorEmailSchema, githubTokenEnvVarSchema, operatingModeSchema, deployedAsSchema, contentRootSchema, sourceRootSchema, basePathSchema, deploymentNameSchema, devContentSyncSchema, devConfigSchema, editorConfigSchema, CanopyConfigSchema, DEFAULT_PROD_WORKSPACE, init_config, permissionTargetSchema, pathPermissionSchema, init_permissions, init_normalize, init_types2, init_flatten, init_mode_env, init_validation, init_helpers, init_config2, init_error2, init_fs2, templates_exports, __dirname, TEMPLATES_DIR, SCAFFOLD_STACK_NAME, init_templates, project_detect_exports, COMMANDS, MAX_WORKSPACE_DEPTH, CDK_DEPENDENCIES, init_project_detect, task_queue_config_exports, init_task_queue_config, LOG_LEVELS, DebugLogger, testLogger, init_debug, init_atomic_write, DEFAULT_MAX_RETRIES, nullLogger, init_task_queue, init_task_queue2, task_queue_exports, debugLogger, cmsTaskQueueLogger, init_task_queue3, ProdClientSafeStrategy, DevClientSafeStrategy, warned, VALID_DEPLOYMENT_NAME, isValidDeploymentName, ProdStrategy, DevStrategy, strategyCache;
1051
1051
  var init_init = __esm({
1052
1052
  "dist/cli/init.js"() {
1053
1053
  "use strict";
@@ -1134,7 +1134,12 @@ var init_init = __esm({
1134
1134
  collections: z.array(z.string().min(1)).min(1).optional(),
1135
1135
  entryTypes: z.array(z.string().min(1)).min(1).optional(),
1136
1136
  displayField: z.string().min(1).optional(),
1137
- options: z.array(referenceOptionSchema).optional()
1137
+ options: z.array(referenceOptionSchema).optional(),
1138
+ // Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
1139
+ // default, so a consumer that adopts this schema's parse output would silently delete a
1140
+ // runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
1141
+ // absent on purpose — it is type-inference-only and stripping it changes no behavior.)
1142
+ includeBody: z.boolean().optional()
1138
1143
  });
1139
1144
  fieldHolder = [z.never()];
1140
1145
  blockSchema = z.object({
@@ -1255,6 +1260,9 @@ var init_init = __esm({
1255
1260
  deployedAsSchema = z4.enum(["static", "server"]).default("server");
1256
1261
  contentRootSchema = relativePathSchema.default("content");
1257
1262
  sourceRootSchema = z4.string().min(1).optional();
1263
+ basePathSchema = z4.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
1264
+ message: "basePath must not be empty or only whitespace"
1265
+ }).optional();
1258
1266
  deploymentNameSchema = z4.string().default("prod");
1259
1267
  devContentSyncSchema = z4.enum(["off", "warn"]).default("warn");
1260
1268
  devConfigSchema = z4.object({
@@ -1317,6 +1325,7 @@ var init_init = __esm({
1317
1325
  deploymentName: deploymentNameSchema.optional(),
1318
1326
  contentRoot: contentRootSchema.default("content"),
1319
1327
  sourceRoot: sourceRootSchema.optional(),
1328
+ basePath: basePathSchema,
1320
1329
  editor: editorConfigSchema.optional(),
1321
1330
  authPlugin: z4.custom().optional(),
1322
1331
  entryLinkUrl: z4.custom().optional(),
@@ -1480,6 +1489,7 @@ var init_init = __esm({
1480
1489
  };
1481
1490
  MAX_WORKSPACE_DEPTH = 8;
1482
1491
  CDK_DEPENDENCIES = [
1492
+ "canopycms",
1483
1493
  "canopycms-cdk",
1484
1494
  "aws-cdk-lib",
1485
1495
  "constructs",
@@ -1844,63 +1854,73 @@ import { isAbsolute as isAbsolute2 } from "pathe";
1844
1854
  import { z as z42 } from "zod";
1845
1855
  import { z as z52 } from "zod";
1846
1856
  import { z as z6 } from "zod";
1847
- import path82 from "node:path";
1848
- import path19 from "node:path";
1857
+ import path9 from "node:path";
1858
+ import path20 from "node:path";
1849
1859
  import { createJiti as createJiti2 } from "jiti";
1850
- import fs16 from "node:fs/promises";
1851
- import path18 from "node:path";
1852
- import fs9 from "node:fs/promises";
1860
+ import fs17 from "node:fs/promises";
1861
+ import path19 from "node:path";
1862
+ import fs10 from "node:fs/promises";
1863
+ import path11 from "node:path";
1864
+ import matter2 from "gray-matter";
1865
+ import { parse as yamlParse } from "yaml";
1866
+ import fs7 from "node:fs/promises";
1853
1867
  import path10 from "node:path";
1854
1868
  import matter from "gray-matter";
1855
- import { parse as yamlParse, stringify as yamlStringify } from "yaml";
1856
- import fs7 from "node:fs/promises";
1857
- import path9 from "node:path";
1869
+ import { isCollection, isMap, isNode, isScalar, isSeq, parseDocument, stringify as yamlStringify } from "yaml";
1858
1870
  import path32 from "node:path";
1859
1871
  import fs23 from "node:fs/promises";
1860
1872
  import path22 from "node:path";
1861
1873
  import lockfile from "proper-lockfile";
1874
+ import fs42 from "node:fs/promises";
1875
+ import path52 from "node:path";
1862
1876
  import fs32 from "node:fs/promises";
1863
1877
  import path42 from "node:path";
1864
1878
  import { generate } from "short-uuid";
1865
- import path52 from "node:path";
1866
- import fs42 from "node:fs/promises";
1867
1879
  import path62 from "node:path";
1868
- import { randomUUID } from "node:crypto";
1869
- import fs62 from "node:fs/promises";
1880
+ import fs52 from "node:fs/promises";
1870
1881
  import path72 from "node:path";
1871
- import { promises as fs52 } from "fs";
1882
+ import { randomUUID } from "node:crypto";
1883
+ import fs72 from "node:fs/promises";
1884
+ import path82 from "node:path";
1885
+ import { promises as fs62 } from "fs";
1872
1886
  import { join as join3 } from "pathe";
1873
1887
  import { z as z7 } from "zod";
1874
1888
  import chokidar from "chokidar";
1875
- import fs72 from "node:fs/promises";
1876
- import { sep, resolve, relative } from "node:path";
1877
1889
  import fs8 from "node:fs/promises";
1878
- import path92 from "node:path";
1879
- import path11 from "node:path";
1880
- import fs10 from "node:fs/promises";
1881
- import { minimatch } from "minimatch";
1882
- import path16 from "node:path";
1883
- import fs13 from "node:fs/promises";
1884
- import path14 from "node:path";
1885
- import fs11 from "node:fs/promises";
1890
+ import { sep, resolve, relative } from "node:path";
1891
+ import fs9 from "node:fs/promises";
1892
+ import path102 from "node:path";
1886
1893
  import path12 from "node:path";
1894
+ import fs11 from "node:fs/promises";
1895
+ import { minimatch } from "minimatch";
1896
+ import path17 from "node:path";
1897
+ import fs14 from "node:fs/promises";
1898
+ import path15 from "node:path";
1887
1899
  import fs12 from "node:fs/promises";
1888
1900
  import path13 from "node:path";
1901
+ import fs13 from "node:fs/promises";
1902
+ import path14 from "node:path";
1889
1903
  import { randomUUID as randomUUID2 } from "node:crypto";
1890
1904
  import lockfile2 from "proper-lockfile";
1891
- import fs14 from "node:fs/promises";
1892
- import path15 from "node:path";
1905
+ import fs15 from "node:fs/promises";
1906
+ import path16 from "node:path";
1893
1907
  import { simpleGit as simpleGit2 } from "simple-git";
1894
1908
  import { simpleGit as simpleGit3 } from "simple-git";
1895
- import fs15 from "node:fs/promises";
1896
- import path17 from "node:path";
1897
- import matter2 from "gray-matter";
1909
+ import fs16 from "node:fs/promises";
1910
+ import path18 from "node:path";
1911
+ import matter3 from "gray-matter";
1898
1912
  import { parse as yamlParse2 } from "yaml";
1899
- function normalizeFilesystemPath(path202) {
1900
- return path202.split(/[\\/]+/).filter(Boolean).join("/");
1913
+ function canopyLogWarn2(...args) {
1914
+ active2.warn(...args);
1915
+ }
1916
+ function canopyLogError(...args) {
1917
+ active2.error(...args);
1901
1918
  }
1902
- function hasTraversalSequence(path202) {
1903
- const normalized = normalizeFilesystemPath(path202);
1919
+ function normalizeFilesystemPath(path212) {
1920
+ return path212.split(/[\\/]+/).filter(Boolean).join("/");
1921
+ }
1922
+ function hasTraversalSequence(path212) {
1923
+ const normalized = normalizeFilesystemPath(path212);
1904
1924
  return normalized.includes("..");
1905
1925
  }
1906
1926
  function createLogicalPath(...segments) {
@@ -1910,20 +1930,14 @@ function createLogicalPath(...segments) {
1910
1930
  }
1911
1931
  return normalized;
1912
1932
  }
1913
- function trimSlashes(path202) {
1933
+ function trimSlashes(path212) {
1914
1934
  let start = 0;
1915
- let end = path202.length;
1916
- while (start < end && path202[start] === "/")
1935
+ let end = path212.length;
1936
+ while (start < end && path212[start] === "/")
1917
1937
  start++;
1918
- while (end > start && path202[end - 1] === "/")
1938
+ while (end > start && path212[end - 1] === "/")
1919
1939
  end--;
1920
- return path202.slice(start, end);
1921
- }
1922
- function canopyLogWarn2(...args) {
1923
- active2.warn(...args);
1924
- }
1925
- function canopyLogError(...args) {
1926
- active2.error(...args);
1940
+ return path212.slice(start, end);
1927
1941
  }
1928
1942
  function readModeEnv() {
1929
1943
  if (typeof process === "undefined" || typeof process.env === "undefined")
@@ -2007,8 +2021,26 @@ function operatingStrategy2(mode) {
2007
2021
  function clearStrategyCache() {
2008
2022
  strategyCache2.clear();
2009
2023
  }
2024
+ function getErrorMessage3(err) {
2025
+ if (err instanceof Error) {
2026
+ return err.message;
2027
+ }
2028
+ if (typeof err === "string") {
2029
+ return err;
2030
+ }
2031
+ return String(err);
2032
+ }
2033
+ function isNodeError3(err) {
2034
+ return err instanceof Error && "code" in err;
2035
+ }
2036
+ function isNotFoundError3(err) {
2037
+ return isNodeError3(err) && err.code === "ENOENT";
2038
+ }
2039
+ function isFileExistsError2(err) {
2040
+ return isNodeError3(err) && err.code === "EEXIST";
2041
+ }
2010
2042
  async function atomicWriteFile2(filePath, content) {
2011
- const dir = path9.dirname(filePath);
2043
+ const dir = path10.dirname(filePath);
2012
2044
  await fs7.mkdir(dir, { recursive: true });
2013
2045
  const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
2014
2046
  await fs7.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
@@ -2020,6 +2052,196 @@ async function atomicWriteFile2(filePath, content) {
2020
2052
  throw err;
2021
2053
  }
2022
2054
  }
2055
+ function isBlockStructuralKey(key) {
2056
+ return BLOCK_STRUCTURAL_KEYS.has(key);
2057
+ }
2058
+ function isPlainRecord(value) {
2059
+ if (typeof value !== "object" || value === null || Array.isArray(value))
2060
+ return false;
2061
+ const proto = Object.getPrototypeOf(value);
2062
+ return proto === Object.prototype || proto === null;
2063
+ }
2064
+ function recordKeyOf(keyNode) {
2065
+ if (!isScalar(keyNode))
2066
+ return void 0;
2067
+ const { value } = keyNode;
2068
+ if (value === null || value === void 0)
2069
+ return void 0;
2070
+ if (typeof value === "object")
2071
+ return void 0;
2072
+ return String(value);
2073
+ }
2074
+ function carryComments(from, to) {
2075
+ if (!isNode(from) || !isNode(to))
2076
+ return;
2077
+ const source = from;
2078
+ const target = to;
2079
+ if (source.commentBefore !== void 0)
2080
+ target.commentBefore = source.commentBefore;
2081
+ if (source.comment !== void 0)
2082
+ target.comment = source.comment;
2083
+ if (source.spaceBefore !== void 0)
2084
+ target.spaceBefore = source.spaceBefore;
2085
+ }
2086
+ function identityKey(value) {
2087
+ try {
2088
+ return JSON.stringify(value) ?? "undefined";
2089
+ } catch {
2090
+ return void 0;
2091
+ }
2092
+ }
2093
+ function nodePlainValue(node) {
2094
+ if (!isNode(node))
2095
+ return node;
2096
+ try {
2097
+ return node.toJSON();
2098
+ } catch {
2099
+ return void 0;
2100
+ }
2101
+ }
2102
+ function nodeIdentityKey(node) {
2103
+ const plain = nodePlainValue(node);
2104
+ return plain === void 0 && isNode(node) ? void 0 : identityKey(plain);
2105
+ }
2106
+ function sharesFieldEvidence(existing, value, depth) {
2107
+ for (const key of Object.keys(value)) {
2108
+ if (isBlockStructuralKey(key))
2109
+ continue;
2110
+ if (!Object.prototype.hasOwnProperty.call(existing, key))
2111
+ continue;
2112
+ const before = existing[key];
2113
+ const after = value[key];
2114
+ if (depth < EVIDENCE_MAX_DEPTH && isPlainRecord(before) && isPlainRecord(after) && sharesFieldEvidence(before, after, depth + 1)) {
2115
+ return true;
2116
+ }
2117
+ const beforeKey = identityKey(before);
2118
+ if (beforeKey !== void 0 && beforeKey === identityKey(after))
2119
+ return true;
2120
+ }
2121
+ return false;
2122
+ }
2123
+ function looksLikeSameItem(node, value) {
2124
+ const existing = nodePlainValue(node);
2125
+ if (!isPlainRecord(existing) || !isPlainRecord(value))
2126
+ return true;
2127
+ return sharesFieldEvidence(existing, value, 0);
2128
+ }
2129
+ function reconcileNode(doc, existing, value) {
2130
+ if (isMap(existing) && isPlainRecord(value)) {
2131
+ reconcileMap(doc, existing, value);
2132
+ return existing;
2133
+ }
2134
+ if (isSeq(existing) && Array.isArray(value)) {
2135
+ reconcileSeq(doc, existing, value);
2136
+ return existing;
2137
+ }
2138
+ if (isScalar(existing) && Object.is(existing.value, value))
2139
+ return existing;
2140
+ const fresh = doc.createNode(value);
2141
+ if (!isCollection(existing))
2142
+ carryComments(existing, fresh);
2143
+ return fresh;
2144
+ }
2145
+ function reconcileMap(doc, map, value) {
2146
+ const wanted = new Set(Object.keys(value).filter((key) => value[key] !== void 0));
2147
+ const seen = /* @__PURE__ */ new Set();
2148
+ const retained = [];
2149
+ for (const pair of map.items) {
2150
+ const key = recordKeyOf(pair.key);
2151
+ if (key === void 0 || !wanted.has(key) || seen.has(key))
2152
+ continue;
2153
+ seen.add(key);
2154
+ pair.value = reconcileNode(doc, pair.value, value[key]);
2155
+ retained.push(pair);
2156
+ }
2157
+ map.items = retained;
2158
+ for (const key of Object.keys(value)) {
2159
+ if (seen.has(key) || !wanted.has(key))
2160
+ continue;
2161
+ map.set(doc.createNode(key), doc.createNode(value[key]));
2162
+ }
2163
+ }
2164
+ function reconcileSeq(doc, seq, value) {
2165
+ const oldItems = seq.items;
2166
+ const byIdentity = /* @__PURE__ */ new Map();
2167
+ oldItems.forEach((node, index) => {
2168
+ const key = nodeIdentityKey(node);
2169
+ if (key === void 0)
2170
+ return;
2171
+ const bucket = byIdentity.get(key);
2172
+ if (bucket)
2173
+ bucket.push(index);
2174
+ else
2175
+ byIdentity.set(key, [index]);
2176
+ });
2177
+ const consumed = /* @__PURE__ */ new Set();
2178
+ const matches = value.map((item) => {
2179
+ const key = identityKey(item);
2180
+ if (key === void 0)
2181
+ return void 0;
2182
+ const bucket = byIdentity.get(key);
2183
+ while (bucket && bucket.length > 0) {
2184
+ const index = bucket.shift();
2185
+ if (index !== void 0 && !consumed.has(index)) {
2186
+ consumed.add(index);
2187
+ return index;
2188
+ }
2189
+ }
2190
+ return void 0;
2191
+ });
2192
+ seq.items = value.map((item, index) => {
2193
+ const matched = matches[index];
2194
+ if (matched !== void 0)
2195
+ return oldItems[matched];
2196
+ const candidate = index < oldItems.length && !consumed.has(index) ? oldItems[index] : void 0;
2197
+ const sameItem = candidate !== void 0 && looksLikeSameItem(candidate, item) ? candidate : void 0;
2198
+ return reconcileNode(doc, sameItem, item);
2199
+ });
2200
+ }
2201
+ function applyDataToDocument(doc, data) {
2202
+ doc.contents = reconcileNode(doc, doc.contents, data);
2203
+ }
2204
+ function serializeYaml(data, existingRaw) {
2205
+ if (existingRaw === void 0)
2206
+ return yamlStringify(data);
2207
+ const doc = parseDocument(existingRaw);
2208
+ if (doc.errors.length > 0)
2209
+ return yamlStringify(data);
2210
+ applyDataToDocument(doc, data);
2211
+ return doc.toString();
2212
+ }
2213
+ function extractRawFrontmatter(raw) {
2214
+ let parsed;
2215
+ try {
2216
+ parsed = matter(raw, {});
2217
+ } catch {
2218
+ return void 0;
2219
+ }
2220
+ const frontmatter = parsed.matter;
2221
+ if (typeof frontmatter !== "string" || frontmatter.trim() === "")
2222
+ return void 0;
2223
+ return frontmatter;
2224
+ }
2225
+ function serializeFrontmatter(body, data, existingRaw) {
2226
+ if (existingRaw === void 0)
2227
+ return matter.stringify(body, data);
2228
+ const existingFrontmatter = extractRawFrontmatter(existingRaw);
2229
+ if (existingFrontmatter === void 0)
2230
+ return matter.stringify(body, data);
2231
+ const doc = parseDocument(existingFrontmatter);
2232
+ if (doc.errors.length > 0)
2233
+ return matter.stringify(body, data);
2234
+ applyDataToDocument(doc, data);
2235
+ const reconciled = doc.toString();
2236
+ return matter.stringify(body, data, {
2237
+ engines: {
2238
+ yaml: {
2239
+ parse: () => ({}),
2240
+ stringify: () => reconciled
2241
+ }
2242
+ }
2243
+ });
2244
+ }
2023
2245
  async function withLock(key, fn) {
2024
2246
  const prev = locks.get(key) ?? Promise.resolve();
2025
2247
  let resolve2;
@@ -2036,51 +2258,71 @@ async function withLock(key, fn) {
2036
2258
  locks.delete(key);
2037
2259
  }
2038
2260
  }
2039
- function getErrorMessage3(err) {
2040
- if (err instanceof Error) {
2041
- return err.message;
2042
- }
2043
- if (typeof err === "string") {
2044
- return err;
2045
- }
2046
- return String(err);
2047
- }
2048
- function isNodeError3(err) {
2049
- return err instanceof Error && "code" in err;
2050
- }
2051
- function isNotFoundError3(err) {
2052
- return isNodeError3(err) && err.code === "ENOENT";
2261
+ function provisioningLockOptions(lockPath, retries, onCompromised) {
2262
+ return {
2263
+ lockfilePath: lockPath,
2264
+ realpath: false,
2265
+ retries,
2266
+ stale: 3e4,
2267
+ // proper-lockfile invokes this from inside its refresh timer, so ANY throw
2268
+ // escaping here is an uncaught exception that kills the process -- the very
2269
+ // failure the handler exists to prevent. Call sites are told not to throw
2270
+ // (see OnLockCompromised); this makes it structural rather than a
2271
+ // convention, and also covers the LOGGER throwing: under `CI=true`,
2272
+ // vitest's `onConsoleLog` turns any console write into a throw.
2273
+ onCompromised: (err) => {
2274
+ try {
2275
+ if (onCompromised) {
2276
+ onCompromised(err);
2277
+ return;
2278
+ }
2279
+ canopyLogWarn2(`[canopy] Provisioning lock compromised mid-hold for ${lockPath}:`, getErrorMessage3(err));
2280
+ } catch {
2281
+ try {
2282
+ process.stderr.write(`[canopy] lock compromised for ${lockPath}; its handler or logger threw
2283
+ `);
2284
+ } catch {
2285
+ }
2286
+ }
2287
+ }
2288
+ };
2053
2289
  }
2054
- function isFileExistsError2(err) {
2055
- return isNodeError3(err) && err.code === "EEXIST";
2290
+ function releaseIgnoringAlreadyReleased(release, lockPath) {
2291
+ return async () => {
2292
+ try {
2293
+ await release();
2294
+ } catch (err) {
2295
+ if (isNodeError3(err) && err.code === "ERELEASED") {
2296
+ canopyLogWarn2(`[canopy] Lock at ${lockPath} was already released (compromised mid-hold, or released twice); nothing to release`);
2297
+ return;
2298
+ }
2299
+ throw err;
2300
+ }
2301
+ };
2056
2302
  }
2057
- async function acquireProvisioningLock(lockTargetDir2, lockName) {
2303
+ async function acquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
2058
2304
  await fs23.mkdir(lockTargetDir2, { recursive: true });
2059
- return lockfile.lock(lockTargetDir2, {
2060
- lockfilePath: path22.join(lockTargetDir2, lockName),
2061
- retries: { retries: 600, factor: 1, minTimeout: 300, maxTimeout: 800, randomize: true },
2062
- stale: 3e4
2063
- });
2305
+ const lockPath = path22.join(lockTargetDir2, lockName);
2306
+ const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, { retries: 600, factor: 1, minTimeout: 300, maxTimeout: 800, randomize: true }, onCompromised));
2307
+ return releaseIgnoringAlreadyReleased(release, lockPath);
2064
2308
  }
2065
- async function tryAcquireProvisioningLock(lockTargetDir2, lockName) {
2309
+ async function tryAcquireProvisioningLock(lockTargetDir2, lockName, onCompromised) {
2066
2310
  await fs23.mkdir(lockTargetDir2, { recursive: true });
2067
- return lockfile.lock(lockTargetDir2, {
2068
- lockfilePath: path22.join(lockTargetDir2, lockName),
2069
- retries: 0,
2070
- stale: 3e4
2071
- });
2311
+ const lockPath = path22.join(lockTargetDir2, lockName);
2312
+ const release = await lockfile.lock(lockPath, provisioningLockOptions(lockPath, 0, onCompromised));
2313
+ return releaseIgnoringAlreadyReleased(release, lockPath);
2072
2314
  }
2073
2315
  function lockTargetDir(branchRoot) {
2074
2316
  return path32.join(path32.resolve(branchRoot), META_DIR);
2075
2317
  }
2076
- function tryAcquireContentWriteLock(branchRoot) {
2077
- return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME);
2318
+ function tryAcquireContentWriteLock(branchRoot, onCompromised) {
2319
+ return tryAcquireProvisioningLock(lockTargetDir(branchRoot), CONTENT_WRITE_LOCK_NAME, onCompromised);
2078
2320
  }
2079
- async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
2321
+ async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, onCompromised) {
2080
2322
  const startedAt = Date.now();
2081
2323
  for (let attempt = 0; ; attempt++) {
2082
2324
  try {
2083
- return await tryAcquireContentWriteLock(branchRoot);
2325
+ return await tryAcquireContentWriteLock(branchRoot, onCompromised);
2084
2326
  } catch (err) {
2085
2327
  if (!isNodeError3(err) || err.code !== "ELOCKED")
2086
2328
  throw err;
@@ -2093,12 +2335,21 @@ async function acquireContentWriteLock(branchRoot, waitMs = DEFAULT_CONTENT_WRIT
2093
2335
  }
2094
2336
  }
2095
2337
  async function withContentWriteLock(branchRoot, fn, waitMs = DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS) {
2096
- const release = await acquireContentWriteLock(branchRoot, waitMs);
2338
+ let compromised = false;
2339
+ const release = await acquireContentWriteLock(branchRoot, waitMs, (err) => {
2340
+ compromised = true;
2341
+ canopyLogWarn2(`[canopy] Content-write lock compromised mid-hold for ${branchRoot}:`, getErrorMessage3(err));
2342
+ });
2343
+ let result;
2097
2344
  try {
2098
- return await fn();
2345
+ result = await fn();
2099
2346
  } finally {
2100
2347
  await release();
2101
2348
  }
2349
+ if (compromised) {
2350
+ 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.");
2351
+ }
2352
+ return result;
2102
2353
  }
2103
2354
  function flattenGroupFields(fields) {
2104
2355
  const result = [];
@@ -2118,9 +2369,68 @@ function findBodyFieldName(fields) {
2118
2369
  }
2119
2370
  return "body";
2120
2371
  }
2372
+ function buildResolvedReference(data, meta, body) {
2373
+ const resolved = { ...data };
2374
+ if (body && body.value)
2375
+ resolved[body.fieldName] = body.value;
2376
+ resolved.id = meta.id;
2377
+ resolved.slug = meta.slug;
2378
+ resolved.collection = meta.collection;
2379
+ resolved.urlPath = meta.urlPath;
2380
+ return resolved;
2381
+ }
2382
+ function isIndexSlug(slug) {
2383
+ return slug?.toLowerCase() === "index";
2384
+ }
2385
+ function computeEntryUrl(collection, slug, contentRoot) {
2386
+ const root = trimSlashes(contentRoot);
2387
+ let stripped = collection;
2388
+ if (root && collection.startsWith(`${root}/`)) {
2389
+ stripped = collection.slice(root.length + 1);
2390
+ } else if (collection === root) {
2391
+ stripped = "";
2392
+ }
2393
+ const segments = stripped.split("/").filter(Boolean);
2394
+ if (slug && !isIndexSlug(slug)) {
2395
+ segments.push(slug);
2396
+ }
2397
+ const path212 = segments.length > 0 ? `/${segments.join("/")}` : "/";
2398
+ return path212.toLowerCase();
2399
+ }
2121
2400
  function isValidContentId(id) {
2122
2401
  return CONTENT_ID_PATTERN.test(id);
2123
2402
  }
2403
+ function parseSlug(slug) {
2404
+ if (!slug) {
2405
+ return {
2406
+ ok: false,
2407
+ error: "Slug is required"
2408
+ };
2409
+ }
2410
+ if (slug.length > 64) {
2411
+ return { ok: false, error: "Slug too long (max 64 characters)" };
2412
+ }
2413
+ if (slug.includes("/") || slug.includes("\\")) {
2414
+ return {
2415
+ ok: false,
2416
+ error: "Slug cannot contain path separators"
2417
+ };
2418
+ }
2419
+ if (slug === "." || slug === "..") {
2420
+ return {
2421
+ ok: false,
2422
+ error: "Slug cannot be a traversal sequence"
2423
+ };
2424
+ }
2425
+ const normalized = slug.toLowerCase();
2426
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
2427
+ return {
2428
+ ok: false,
2429
+ error: "Slug must start with a letter or number and contain only lowercase letters, numbers, and hyphens"
2430
+ };
2431
+ }
2432
+ return { ok: true, slug: normalized };
2433
+ }
2124
2434
  function generateId() {
2125
2435
  const full = generate();
2126
2436
  return full.substring(0, 12);
@@ -2148,13 +2458,13 @@ function extractIdFromFilename(filename) {
2148
2458
  return null;
2149
2459
  }
2150
2460
  async function resolveCollectionPath(root, logicalPath) {
2151
- const fs172 = await import("node:fs/promises");
2152
- const path202 = await import("node:path");
2461
+ const fs182 = await import("node:fs/promises");
2462
+ const path212 = await import("node:path");
2153
2463
  const segments = logicalPath.split("/").filter(Boolean);
2154
2464
  let currentPath = root;
2155
2465
  for (const segment of segments) {
2156
2466
  try {
2157
- const entries = await fs172.readdir(currentPath, { withFileTypes: true });
2467
+ const entries = await fs182.readdir(currentPath, { withFileTypes: true });
2158
2468
  const matchingDir = entries.find((entry) => {
2159
2469
  if (!entry.isDirectory())
2160
2470
  return false;
@@ -2162,7 +2472,7 @@ async function resolveCollectionPath(root, logicalPath) {
2162
2472
  return logicalName === segment.toLowerCase();
2163
2473
  });
2164
2474
  if (matchingDir) {
2165
- currentPath = path202.join(currentPath, matchingDir.name);
2475
+ currentPath = path212.join(currentPath, matchingDir.name);
2166
2476
  } else {
2167
2477
  return null;
2168
2478
  }
@@ -2211,8 +2521,70 @@ function extractSlugFromFilename(filename, entryTypeName) {
2211
2521
  }
2212
2522
  return filename.toLowerCase();
2213
2523
  }
2524
+ async function readDirSafe(dir) {
2525
+ try {
2526
+ return await fs42.readdir(dir, { withFileTypes: true });
2527
+ } catch (err) {
2528
+ if (isNotFoundError3(err))
2529
+ return [];
2530
+ throw err;
2531
+ }
2532
+ }
2533
+ async function findChildCollectionDir(dir, name) {
2534
+ const wanted = name.toLowerCase();
2535
+ for (const entry of await readDirSafe(dir)) {
2536
+ if (!entry.isDirectory())
2537
+ continue;
2538
+ if (extractSlugFromFilename(entry.name) === wanted)
2539
+ return path52.join(dir, entry.name);
2540
+ }
2541
+ return null;
2542
+ }
2543
+ function entrySlugOf(filename) {
2544
+ if (!CONTENT_EXTENSIONS.some((ext) => filename.endsWith(ext)))
2545
+ return null;
2546
+ return parseTypedFilename(filename)?.slug ?? null;
2547
+ }
2548
+ async function findIndexEntryIn(dir) {
2549
+ for (const entry of await readDirSafe(dir)) {
2550
+ if (entry.isDirectory())
2551
+ continue;
2552
+ if (isIndexSlug(entrySlugOf(entry.name) ?? void 0))
2553
+ return path52.join(dir, entry.name);
2554
+ }
2555
+ return null;
2556
+ }
2557
+ async function findEntryBySlugIn(dir, slug) {
2558
+ const wanted = slug.toLowerCase();
2559
+ for (const entry of await readDirSafe(dir)) {
2560
+ if (entry.isDirectory())
2561
+ continue;
2562
+ if (entrySlugOf(entry.name) === wanted)
2563
+ return path52.join(dir, entry.name);
2564
+ }
2565
+ return null;
2566
+ }
2567
+ async function findUrlPathClaimant(opts) {
2568
+ const { collectionDir, slug, contentRoot } = opts;
2569
+ if (isIndexSlug(slug)) {
2570
+ const resolvedRoot = path52.resolve(contentRoot);
2571
+ if (path52.resolve(collectionDir) === resolvedRoot)
2572
+ return null;
2573
+ const parentDir = path52.dirname(collectionDir);
2574
+ const ownName = extractSlugFromFilename(path52.basename(collectionDir));
2575
+ if (isIndexSlug(ownName))
2576
+ return null;
2577
+ const claimant = await findEntryBySlugIn(parentDir, ownName);
2578
+ return claimant ? { kind: "parent-entry", physicalPath: claimant, name: ownName } : null;
2579
+ }
2580
+ const childDir = await findChildCollectionDir(collectionDir, slug);
2581
+ if (!childDir)
2582
+ return null;
2583
+ const indexEntry = await findIndexEntryIn(childDir);
2584
+ return indexEntry ? { kind: "sibling-collection-index", physicalPath: indexEntry, name: slug } : null;
2585
+ }
2214
2586
  function registerContentIndexForInvalidation(root, target) {
2215
- const rootKey = path52.resolve(root);
2587
+ const rootKey = path62.resolve(root);
2216
2588
  let refs = registry.get(rootKey);
2217
2589
  if (!refs) {
2218
2590
  refs = /* @__PURE__ */ new Set();
@@ -2223,8 +2595,8 @@ function registerContentIndexForInvalidation(root, target) {
2223
2595
  finalization.register(target, { rootKey, ref });
2224
2596
  }
2225
2597
  function invalidateContentIndexesForRoot(root) {
2226
- const rootKey = path52.resolve(root);
2227
- const prefix = rootKey + path52.sep;
2598
+ const rootKey = path62.resolve(root);
2599
+ const prefix = rootKey + path62.sep;
2228
2600
  for (const [storeRoot, refs] of registry) {
2229
2601
  if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
2230
2602
  continue;
@@ -2244,7 +2616,7 @@ function createDebugLogger2(options) {
2244
2616
  return new DebugLogger2(options);
2245
2617
  }
2246
2618
  function resourceGenerationPath(root, resource) {
2247
- return path62.resolve(root, META_DIR2, `${resource}.generation`);
2619
+ return path72.resolve(root, META_DIR2, `${resource}.generation`);
2248
2620
  }
2249
2621
  async function bumpResourceGeneration(root, resource, options) {
2250
2622
  const token = randomUUID();
@@ -2262,7 +2634,7 @@ async function bumpResourceGeneration(root, resource, options) {
2262
2634
  }
2263
2635
  async function readResourceGeneration(root, resource) {
2264
2636
  try {
2265
- const token = await fs42.readFile(resourceGenerationPath(root, resource), "utf-8");
2637
+ const token = await fs52.readFile(resourceGenerationPath(root, resource), "utf-8");
2266
2638
  return { ok: true, token };
2267
2639
  } catch (err) {
2268
2640
  if (isNodeError3(err) && err.code === "ENOENT")
@@ -2282,7 +2654,7 @@ function stripEmbeddedIdFromName(name) {
2282
2654
  async function scanForCollectionMeta(baseDir, relativePath = "") {
2283
2655
  const collections = [];
2284
2656
  try {
2285
- const entries = await fs52.readdir(baseDir, { withFileTypes: true });
2657
+ const entries = await fs62.readdir(baseDir, { withFileTypes: true });
2286
2658
  for (const entry of entries) {
2287
2659
  if (!entry.isDirectory())
2288
2660
  continue;
@@ -2293,8 +2665,8 @@ async function scanForCollectionMeta(baseDir, relativePath = "") {
2293
2665
  const absolutePath = join3(baseDir, folderName);
2294
2666
  const metaPath = join3(absolutePath, ".collection.json");
2295
2667
  try {
2296
- await fs52.access(metaPath);
2297
- const content = await fs52.readFile(metaPath, "utf-8");
2668
+ await fs62.access(metaPath);
2669
+ const content = await fs62.readFile(metaPath, "utf-8");
2298
2670
  const parsed = JSON.parse(content);
2299
2671
  const meta = collectionMetaSchema.parse(parsed);
2300
2672
  collections.push({
@@ -2326,7 +2698,7 @@ async function loadCollectionMetaFiles(contentRoot) {
2326
2698
  let root = null;
2327
2699
  const rootMetaPath = join3(contentRoot, ".collection.json");
2328
2700
  try {
2329
- await fs52.access(rootMetaPath);
2701
+ await fs62.access(rootMetaPath);
2330
2702
  } catch (err) {
2331
2703
  if (err.code === "ENOENT") {
2332
2704
  } else {
@@ -2334,7 +2706,7 @@ async function loadCollectionMetaFiles(contentRoot) {
2334
2706
  }
2335
2707
  }
2336
2708
  try {
2337
- const content = await fs52.readFile(rootMetaPath, "utf-8");
2709
+ const content = await fs62.readFile(rootMetaPath, "utf-8");
2338
2710
  const parsed = JSON.parse(content);
2339
2711
  root = rootCollectionMetaSchema.parse(parsed);
2340
2712
  } catch (err) {
@@ -2424,16 +2796,16 @@ function isValidSchema(schema) {
2424
2796
  async function isStaleByMtime(dir, cachedAt) {
2425
2797
  let entries;
2426
2798
  try {
2427
- entries = await fs62.readdir(dir, { recursive: true, encoding: "utf-8" });
2799
+ entries = await fs72.readdir(dir, { recursive: true, encoding: "utf-8" });
2428
2800
  } catch {
2429
2801
  return true;
2430
2802
  }
2431
2803
  for (const entry of entries) {
2432
2804
  if (!entry.endsWith(".collection.json"))
2433
2805
  continue;
2434
- const full = path72.join(dir, entry);
2806
+ const full = path82.join(dir, entry);
2435
2807
  try {
2436
- const stat = await fs62.stat(full);
2808
+ const stat = await fs72.stat(full);
2437
2809
  if (stat.mtimeMs > cachedAt.getTime())
2438
2810
  return true;
2439
2811
  } catch {
@@ -2456,7 +2828,7 @@ async function invalidateBranchContentCaches(root) {
2456
2828
  }
2457
2829
  async function filePathExists3(filePath) {
2458
2830
  try {
2459
- await fs72.stat(filePath);
2831
+ await fs8.stat(filePath);
2460
2832
  return true;
2461
2833
  } catch (err) {
2462
2834
  if (isNotFoundError3(err))
@@ -2464,6 +2836,15 @@ async function filePathExists3(filePath) {
2464
2836
  throw err;
2465
2837
  }
2466
2838
  }
2839
+ async function readFileIfExists(filePath) {
2840
+ try {
2841
+ return await fs8.readFile(filePath, "utf8");
2842
+ } catch (err) {
2843
+ if (isNotFoundError3(err))
2844
+ return void 0;
2845
+ throw err;
2846
+ }
2847
+ }
2467
2848
  function validateAndNormalizePath(root, target) {
2468
2849
  const resolvedRoot = resolve(root);
2469
2850
  const withSep = resolvedRoot.endsWith(sep) ? resolvedRoot : `${resolvedRoot}${sep}`;
@@ -2493,11 +2874,11 @@ function resolveBranchPath(options) {
2493
2874
  const safeBranch = sanitizeBranchName(options.branchName);
2494
2875
  const strategy = operatingStrategy2(options.mode);
2495
2876
  const baseRoot = resolveContentBranchesRoot(options.mode, options.basePathOverride);
2496
- const normalizedBase = path92.resolve(baseRoot);
2497
- const baseWithSep = normalizedBase.endsWith(path92.sep) ? normalizedBase : `${normalizedBase}${path92.sep}`;
2877
+ const normalizedBase = path102.resolve(baseRoot);
2878
+ const baseWithSep = normalizedBase.endsWith(path102.sep) ? normalizedBase : `${normalizedBase}${path102.sep}`;
2498
2879
  const branchRoot = strategy.getContentBranchRoot(safeBranch, options.basePathOverride);
2499
2880
  const withinBase = (target) => {
2500
- const resolved = path92.resolve(target);
2881
+ const resolved = path102.resolve(target);
2501
2882
  return resolved === normalizedBase || resolved.startsWith(baseWithSep);
2502
2883
  };
2503
2884
  if (!withinBase(branchRoot)) {
@@ -2507,7 +2888,7 @@ function resolveBranchPath(options) {
2507
2888
  }
2508
2889
  async function ensureBranchRoot(options) {
2509
2890
  const result = resolveBranchPath(options);
2510
- await fs8.mkdir(result.branchRoot, { recursive: true });
2891
+ await fs9.mkdir(result.branchRoot, { recursive: true });
2511
2892
  return result;
2512
2893
  }
2513
2894
  async function withLocks(keys, fn) {
@@ -2795,7 +3176,7 @@ function renderField(field, value, depth, entry, config) {
2795
3176
  const heading = "#".repeat(Math.min(depth, 6));
2796
3177
  const descriptionLine = "description" in field && field.description ? `
2797
3178
 
2798
- *${field.description}*` : "";
3179
+ _${field.description}_` : "";
2799
3180
  if ("list" in field && field.list && Array.isArray(value)) {
2800
3181
  return renderListField(field, value, depth, label, heading, descriptionLine, entry, config);
2801
3182
  }
@@ -3051,26 +3432,13 @@ function formatInlineValue(field, value) {
3051
3432
  return String(value);
3052
3433
  }
3053
3434
  function yamlValue(value) {
3435
+ if (value === "")
3436
+ return '""';
3054
3437
  if (/[:#{}[\],&*?|>!%@`]/.test(value) || value.includes("\n")) {
3055
3438
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
3056
3439
  }
3057
3440
  return value;
3058
3441
  }
3059
- function computeEntryUrl(collection, slug, contentRoot) {
3060
- const root = trimSlashes(contentRoot);
3061
- let stripped = collection;
3062
- if (root && collection.startsWith(`${root}/`)) {
3063
- stripped = collection.slice(root.length + 1);
3064
- } else if (collection === root) {
3065
- stripped = "";
3066
- }
3067
- const segments = stripped.split("/").filter(Boolean);
3068
- if (slug && slug !== "index") {
3069
- segments.push(slug);
3070
- }
3071
- const path202 = segments.length > 0 ? `/${segments.join("/")}` : "/";
3072
- return path202.toLowerCase();
3073
- }
3074
3442
  function resolveEntryUrl(location, contentRoot) {
3075
3443
  return computeEntryUrl(location.collection ?? "", location.slug ?? "", contentRoot);
3076
3444
  }
@@ -3237,7 +3605,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
3237
3605
  const listed = await store.getCollectionEntryPaths(collection.logicalPath);
3238
3606
  const directEntries = listed.filter((e) => e.collection === collection.logicalPath);
3239
3607
  for (const listEntry of directEntries) {
3240
- const entryTypeName = extractEntryTypeFromFilename(path11.basename(listEntry.relativePath));
3608
+ const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
3241
3609
  if (!entryTypeName)
3242
3610
  continue;
3243
3611
  if (config?.exclude?.entryTypes?.includes(entryTypeName))
@@ -3255,7 +3623,7 @@ async function processCollection(store, collection, flatSchema, contentRoot, con
3255
3623
  }
3256
3624
  if (config?.exclude?.where?.(aiEntry))
3257
3625
  continue;
3258
- await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path11.basename(listEntry.relativePath)), config);
3626
+ await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
3259
3627
  entries.push(aiEntry);
3260
3628
  const entryFilePath = `${cleanPath}/${listEntry.slug}.md`;
3261
3629
  const entryMarkdown = entryToMarkdown(aiEntry, config);
@@ -3306,7 +3674,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
3306
3674
  const listed = await store.getCollectionEntryPaths(rootCollection.logicalPath);
3307
3675
  const directEntries = listed.filter((e) => e.collection === rootCollection.logicalPath);
3308
3676
  for (const listEntry of directEntries) {
3309
- const entryTypeName = extractEntryTypeFromFilename(path11.basename(listEntry.relativePath));
3677
+ const entryTypeName = extractEntryTypeFromFilename(path12.basename(listEntry.relativePath));
3310
3678
  if (!entryTypeName)
3311
3679
  continue;
3312
3680
  if (config?.exclude?.entryTypes?.includes(entryTypeName))
@@ -3324,7 +3692,7 @@ async function processRootEntries(store, rootCollection, contentRoot, config, id
3324
3692
  }
3325
3693
  if (config?.exclude?.where?.(aiEntry))
3326
3694
  continue;
3327
- await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path11.basename(listEntry.relativePath)), config);
3695
+ await runEntryTransform(aiEntry, doc.absolutePath, extractIdFromFilename(path12.basename(listEntry.relativePath)), config);
3328
3696
  entries.push(aiEntry);
3329
3697
  const entryFilePath = `${listEntry.slug}.md`;
3330
3698
  const entryMarkdown = entryToMarkdown(aiEntry, config);
@@ -3372,19 +3740,19 @@ function docToAIEntry(doc, slug, entryTypeName, entryTypeConfig, cleanCollection
3372
3740
  };
3373
3741
  }
3374
3742
  function makeReadSibling(dir) {
3375
- const resolvedDir = path11.resolve(dir);
3743
+ const resolvedDir = path12.resolve(dir);
3376
3744
  return async (name) => {
3377
- if (!name || name.includes("/") || name.includes("\\") || path11.isAbsolute(name) || hasTraversalSequence(name)) {
3745
+ if (!name || name.includes("/") || name.includes("\\") || path12.isAbsolute(name) || hasTraversalSequence(name)) {
3378
3746
  return null;
3379
3747
  }
3380
- const abs = path11.resolve(resolvedDir, name);
3381
- if (path11.dirname(abs) !== resolvedDir)
3748
+ const abs = path12.resolve(resolvedDir, name);
3749
+ if (path12.dirname(abs) !== resolvedDir)
3382
3750
  return null;
3383
3751
  try {
3384
- const stats = await fs10.lstat(abs);
3752
+ const stats = await fs11.lstat(abs);
3385
3753
  if (!stats.isFile())
3386
3754
  return null;
3387
- return await fs10.readFile(abs, "utf8");
3755
+ return await fs11.readFile(abs, "utf8");
3388
3756
  } catch (err) {
3389
3757
  if (isNodeError3(err) && (err.code === "ENOENT" || err.code === "ENOTDIR"))
3390
3758
  return null;
@@ -3398,7 +3766,7 @@ async function runEntryTransform(entry, absolutePath, contentId, config) {
3398
3766
  return;
3399
3767
  const ctx = {
3400
3768
  contentId: contentId ?? "",
3401
- readSibling: makeReadSibling(path11.dirname(absolutePath))
3769
+ readSibling: makeReadSibling(path12.dirname(absolutePath))
3402
3770
  };
3403
3771
  try {
3404
3772
  const appended = await transform(entry, ctx);
@@ -3439,29 +3807,29 @@ async function writeOccJsonFile(filePath, payload, options) {
3439
3807
  const writeId = randomUUID2();
3440
3808
  const data = { ...payload, version: newVersion, writeId };
3441
3809
  const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
3442
- const dir = path13.dirname(filePath);
3443
- await fs12.mkdir(dir, { recursive: true });
3810
+ const dir = path14.dirname(filePath);
3811
+ await fs13.mkdir(dir, { recursive: true });
3444
3812
  const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
3445
- await fs12.writeFile(tempPath, content, "utf-8");
3813
+ await fs13.writeFile(tempPath, content, "utf-8");
3446
3814
  if (expectedVersion === null) {
3447
3815
  try {
3448
- await fs12.link(tempPath, filePath);
3816
+ await fs13.link(tempPath, filePath);
3449
3817
  } catch (err) {
3450
- await fs12.unlink(tempPath).catch(() => {
3818
+ await fs13.unlink(tempPath).catch(() => {
3451
3819
  });
3452
3820
  if (isFileExistsError2(err)) {
3453
3821
  throw new OccWriteConflictError();
3454
3822
  }
3455
3823
  throw err;
3456
3824
  }
3457
- await fs12.unlink(tempPath).catch(() => {
3825
+ await fs13.unlink(tempPath).catch(() => {
3458
3826
  });
3459
3827
  return { version: newVersion, writeId };
3460
3828
  }
3461
3829
  try {
3462
3830
  let currentVersion = null;
3463
3831
  try {
3464
- const current = JSON.parse(await fs12.readFile(filePath, "utf-8"));
3832
+ const current = JSON.parse(await fs13.readFile(filePath, "utf-8"));
3465
3833
  currentVersion = current.version ?? 0;
3466
3834
  } catch {
3467
3835
  currentVersion = null;
@@ -3469,16 +3837,16 @@ async function writeOccJsonFile(filePath, payload, options) {
3469
3837
  if (currentVersion !== expectedVersion) {
3470
3838
  throw new OccWriteConflictError();
3471
3839
  }
3472
- await fs12.rename(tempPath, filePath);
3840
+ await fs13.rename(tempPath, filePath);
3473
3841
  if (settleMs > 0) {
3474
3842
  await new Promise((resolve2) => setTimeout(resolve2, settleMs));
3475
3843
  }
3476
- const afterWrite = JSON.parse(await fs12.readFile(filePath, "utf-8"));
3844
+ const afterWrite = JSON.parse(await fs13.readFile(filePath, "utf-8"));
3477
3845
  if (afterWrite.writeId !== writeId) {
3478
3846
  throw new OccWriteConflictError();
3479
3847
  }
3480
3848
  } catch (err) {
3481
- await fs12.unlink(tempPath).catch(() => {
3849
+ await fs13.unlink(tempPath).catch(() => {
3482
3850
  });
3483
3851
  throw err;
3484
3852
  }
@@ -3504,8 +3872,8 @@ async function withOccRetry(operation, options) {
3504
3872
  throw new Error("Unreachable");
3505
3873
  }
3506
3874
  async function withOccFileLock(filePath, fn) {
3507
- const dir = path13.dirname(filePath);
3508
- await fs12.mkdir(dir, { recursive: true });
3875
+ const dir = path14.dirname(filePath);
3876
+ await fs13.mkdir(dir, { recursive: true });
3509
3877
  const MAX_ATTEMPTS = 14;
3510
3878
  let release = null;
3511
3879
  for (let attempt = 1; release === null; attempt++) {
@@ -3589,11 +3957,11 @@ function gitChildEnv(overrides) {
3589
3957
  return { ...env, ...FORCE_C_LOCALE, ...overrides };
3590
3958
  }
3591
3959
  async function ensureGitExcludePattern(repoPath, pattern) {
3592
- const excludePath = path15.join(repoPath, ".git", "info", "exclude");
3593
- await fs14.mkdir(path15.dirname(excludePath), { recursive: true });
3960
+ const excludePath = path16.join(repoPath, ".git", "info", "exclude");
3961
+ await fs15.mkdir(path16.dirname(excludePath), { recursive: true });
3594
3962
  let content = "";
3595
3963
  try {
3596
- content = await fs14.readFile(excludePath, "utf-8");
3964
+ content = await fs15.readFile(excludePath, "utf-8");
3597
3965
  } catch (err) {
3598
3966
  if (!isNotFoundError3(err))
3599
3967
  throw err;
@@ -3605,7 +3973,7 @@ async function ensureGitExcludePattern(repoPath, pattern) {
3605
3973
  }
3606
3974
  const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
3607
3975
  const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
3608
- await fs14.writeFile(excludePath, newContent, "utf-8");
3976
+ await fs15.writeFile(excludePath, newContent, "utf-8");
3609
3977
  log5.debug("git", "Added pattern to .git/info/exclude", { pattern });
3610
3978
  }
3611
3979
  async function loadOrCreateBranchContext(options) {
@@ -3669,10 +4037,12 @@ async function listEntries(branchRoot, flatSchema, contentRootName, options, vis
3669
4037
  const collections = flatSchema.filter((item) => item.type === "collection" && item.entries !== void 0 && (item.logicalPath === rootPath || item.logicalPath.startsWith(`${rootPath}/`)));
3670
4038
  const shouldInclude = visibility?.shouldInclude;
3671
4039
  const skippedFiles = [];
4040
+ const resolver = options?.resolveReferences ? createReferenceResolver(branchRoot, flatSchema, contentRootName) : null;
3672
4041
  const collectionResults = await Promise.all(collections.map(async (collection) => {
3673
4042
  const entries = await listCollectionEntries(branchRoot, collection, (file) => skippedFiles.push(file));
3674
4043
  const visible = shouldInclude ? entries.filter((e) => shouldInclude(e.physicalPath)) : entries;
3675
- return visible.map((entry) => ({ entry, collection }));
4044
+ const resolved = resolver ? await resolveCollectionItemReferences(visible, collection, resolver) : visible;
4045
+ return resolved.map((entry) => ({ entry, collection }));
3676
4046
  }));
3677
4047
  if (isBuildMode() && skippedFiles.length > 0) {
3678
4048
  const lines = skippedFiles.map(({ filename, collectionPath }) => ` - ${collectionPath}/${filename}`);
@@ -3686,8 +4056,7 @@ Expected {type}.{slug}.{id}.{ext} with a known entry type (a name declared in th
3686
4056
  for (const { entry, collection } of results) {
3687
4057
  const pathWithoutRoot = entry.logicalPath.startsWith(contentPrefix) ? entry.logicalPath.slice(contentPrefix.length) : entry.logicalPath;
3688
4058
  const pathSegments = pathWithoutRoot.split("/").filter(Boolean);
3689
- const urlSegments = entry.slug === "index" ? pathSegments.slice(0, -1) : pathSegments;
3690
- const urlPath = urlSegments.length > 0 ? `/${urlSegments.join("/")}`.toLowerCase() : "/";
4059
+ const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
3691
4060
  const raw = entry.data;
3692
4061
  const meta = {
3693
4062
  entryPath: entry.logicalPath,
@@ -3732,7 +4101,7 @@ function isValidCropRect(x, y, w, h) {
3732
4101
  return false;
3733
4102
  return true;
3734
4103
  }
3735
- function isPlainRecord(value) {
4104
+ function isPlainRecord2(value) {
3736
4105
  return typeof value === "object" && value !== null && !Array.isArray(value);
3737
4106
  }
3738
4107
  function resolveBlockItem(blockField, item) {
@@ -3742,17 +4111,17 @@ function resolveBlockItem(blockField, item) {
3742
4111
  const template = blockField.templates?.find((t) => t.name === templateName);
3743
4112
  if (!template?.fields)
3744
4113
  return void 0;
3745
- const data = isPlainRecord(item.value) ? item.value : item;
4114
+ const data = isPlainRecord2(item.value) ? item.value : item;
3746
4115
  return { fields: template.fields, data };
3747
4116
  }
3748
- function isPlainRecord2(value) {
4117
+ function isPlainRecord3(value) {
3749
4118
  return typeof value === "object" && value !== null && !Array.isArray(value);
3750
4119
  }
3751
4120
  function isPositiveInt(value) {
3752
4121
  return typeof value === "number" && Number.isInteger(value) && value > 0;
3753
4122
  }
3754
4123
  function isValidImageCropValue(value) {
3755
- if (!isPlainRecord2(value))
4124
+ if (!isPlainRecord3(value))
3756
4125
  return false;
3757
4126
  const { x, y, w, h } = value;
3758
4127
  if (typeof x !== "number" || typeof y !== "number" || typeof w !== "number" || typeof h !== "number") {
@@ -3760,78 +4129,78 @@ function isValidImageCropValue(value) {
3760
4129
  }
3761
4130
  return isValidCropRect(x, y, w, h);
3762
4131
  }
3763
- function validateImageValue(field, value, path202) {
3764
- if (!isPlainRecord2(value)) {
3765
- return [{ fieldPath: path202, message: "Expected an image object with { src, alt }" }];
4132
+ function validateImageValue(field, value, path212) {
4133
+ if (!isPlainRecord3(value)) {
4134
+ return [{ fieldPath: path212, message: "Expected an image object with { src, alt }" }];
3766
4135
  }
3767
4136
  const errors = [];
3768
4137
  if (typeof value.src !== "string" || value.src.trim() === "") {
3769
- errors.push({ fieldPath: `${path202}.src`, message: "Image src is required" });
4138
+ errors.push({ fieldPath: `${path212}.src`, message: "Image src is required" });
3770
4139
  }
3771
4140
  if (typeof value.alt !== "string") {
3772
- errors.push({ fieldPath: `${path202}.alt`, message: "Image alt text is required" });
4141
+ errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
3773
4142
  } else if (value.alt.trim() === "" && field.altOptional !== true) {
3774
- errors.push({ fieldPath: `${path202}.alt`, message: "Image alt text is required" });
4143
+ errors.push({ fieldPath: `${path212}.alt`, message: "Image alt text is required" });
3775
4144
  }
3776
4145
  if (value.width !== void 0 && !isPositiveInt(value.width)) {
3777
- errors.push({ fieldPath: `${path202}.width`, message: "Image width must be a positive integer" });
4146
+ errors.push({ fieldPath: `${path212}.width`, message: "Image width must be a positive integer" });
3778
4147
  }
3779
4148
  if (value.height !== void 0 && !isPositiveInt(value.height)) {
3780
4149
  errors.push({
3781
- fieldPath: `${path202}.height`,
4150
+ fieldPath: `${path212}.height`,
3782
4151
  message: "Image height must be a positive integer"
3783
4152
  });
3784
4153
  }
3785
4154
  if (value.crop !== void 0 && !isValidImageCropValue(value.crop)) {
3786
- errors.push({ fieldPath: `${path202}.crop`, message: "Invalid image crop rect" });
4155
+ errors.push({ fieldPath: `${path212}.crop`, message: "Invalid image crop rect" });
3787
4156
  }
3788
4157
  return errors;
3789
4158
  }
3790
4159
  function referenceValueId(value) {
3791
4160
  if (typeof value === "string")
3792
4161
  return value;
3793
- if (isPlainRecord2(value) && typeof value.id === "string")
4162
+ if (isPlainRecord3(value) && typeof value.id === "string")
3794
4163
  return value.id;
3795
4164
  return void 0;
3796
4165
  }
3797
- function validateScalar(field, value, path202) {
4166
+ function validateScalar(field, value, path212) {
3798
4167
  switch (field.type) {
3799
4168
  case "number":
3800
4169
  if (typeof value !== "number" || !Number.isFinite(value)) {
3801
- return [{ fieldPath: path202, message: "Expected a number" }];
4170
+ return [{ fieldPath: path212, message: "Expected a number" }];
3802
4171
  }
3803
4172
  return [];
3804
4173
  case "boolean":
3805
4174
  if (typeof value !== "boolean") {
3806
- return [{ fieldPath: path202, message: "Expected true or false" }];
4175
+ return [{ fieldPath: path212, message: "Expected true or false" }];
3807
4176
  }
3808
4177
  return [];
3809
4178
  case "datetime":
3810
4179
  if (typeof value !== "string" || value !== "" && Number.isNaN(Date.parse(value))) {
3811
- return [{ fieldPath: path202, message: "Expected a valid date/time string" }];
4180
+ return [{ fieldPath: path212, message: "Expected a valid date/time string" }];
3812
4181
  }
3813
4182
  return [];
3814
4183
  case "select": {
3815
4184
  if (typeof value !== "string") {
3816
- return [{ fieldPath: path202, message: "Expected a selection" }];
4185
+ return [{ fieldPath: path212, message: "Expected a selection" }];
3817
4186
  }
3818
4187
  const options = selectOptionValues(field);
3819
4188
  if (value !== "" && !options.includes(value)) {
3820
- return [{ fieldPath: path202, message: `Must be one of: ${options.join(", ")}` }];
4189
+ return [{ fieldPath: path212, message: `Must be one of: ${options.join(", ")}` }];
3821
4190
  }
3822
4191
  return [];
3823
4192
  }
3824
4193
  case "reference":
3825
4194
  if (referenceValueId(value) === void 0) {
3826
- return [{ fieldPath: path202, message: "Expected a reference id" }];
4195
+ return [{ fieldPath: path212, message: "Expected a reference id" }];
3827
4196
  }
3828
4197
  return [];
3829
4198
  case "image":
3830
- return validateImageValue(field, value, path202);
4199
+ return validateImageValue(field, value, path212);
3831
4200
  default:
3832
4201
  if (STRING_FIELD_TYPES.has(field.type)) {
3833
4202
  if (typeof value !== "string") {
3834
- return [{ fieldPath: path202, message: "Expected text" }];
4203
+ return [{ fieldPath: path212, message: "Expected text" }];
3835
4204
  }
3836
4205
  }
3837
4206
  return [];
@@ -3854,12 +4223,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
3854
4223
  errors.push(...validateEntryData(field.fields, data, pathPrefix));
3855
4224
  continue;
3856
4225
  }
3857
- const path202 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
4226
+ const path212 = pathPrefix ? `${pathPrefix}.${field.name}` : field.name;
3858
4227
  const value = data[field.name];
3859
4228
  const isRequired = "required" in field && field.required === true;
3860
4229
  if (isRequired && isEmptyForRequired(field, value)) {
3861
4230
  const message = Array.isArray(value) ? "At least one item is required" : "This field is required";
3862
- errors.push({ fieldPath: path202, message });
4231
+ errors.push({ fieldPath: path212, message });
3863
4232
  continue;
3864
4233
  }
3865
4234
  if (value === void 0 || value === null)
@@ -3867,12 +4236,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
3867
4236
  if (field.type === "block") {
3868
4237
  const blockField = field;
3869
4238
  if (!Array.isArray(value)) {
3870
- errors.push({ fieldPath: path202, message: "Expected a list of blocks" });
4239
+ errors.push({ fieldPath: path212, message: "Expected a list of blocks" });
3871
4240
  continue;
3872
4241
  }
3873
4242
  value.forEach((item, index) => {
3874
- const itemPath = `${path202}[${index}]`;
3875
- if (!isPlainRecord2(item)) {
4243
+ const itemPath = `${path212}[${index}]`;
4244
+ if (!isPlainRecord3(item)) {
3876
4245
  errors.push({ fieldPath: itemPath, message: "Expected a block object" });
3877
4246
  return;
3878
4247
  }
@@ -3893,12 +4262,12 @@ function validateEntryData(fields, data, pathPrefix = "") {
3893
4262
  const objectField = field;
3894
4263
  if (objectField.list) {
3895
4264
  if (!Array.isArray(value)) {
3896
- errors.push({ fieldPath: path202, message: "Expected a list of items" });
4265
+ errors.push({ fieldPath: path212, message: "Expected a list of items" });
3897
4266
  continue;
3898
4267
  }
3899
4268
  value.forEach((item, index) => {
3900
- const itemPath = `${path202}[${index}]`;
3901
- if (!isPlainRecord2(item)) {
4269
+ const itemPath = `${path212}[${index}]`;
4270
+ if (!isPlainRecord3(item)) {
3902
4271
  errors.push({ fieldPath: itemPath, message: "Expected an object" });
3903
4272
  return;
3904
4273
  }
@@ -3906,28 +4275,28 @@ function validateEntryData(fields, data, pathPrefix = "") {
3906
4275
  errors.push(...validateEntryData(objectField.fields, item, itemPath));
3907
4276
  }
3908
4277
  });
3909
- } else if (!isPlainRecord2(value)) {
3910
- errors.push({ fieldPath: path202, message: "Expected an object" });
4278
+ } else if (!isPlainRecord3(value)) {
4279
+ errors.push({ fieldPath: path212, message: "Expected an object" });
3911
4280
  } else if (objectField.fields) {
3912
- errors.push(...validateEntryData(objectField.fields, value, path202));
4281
+ errors.push(...validateEntryData(objectField.fields, value, path212));
3913
4282
  }
3914
4283
  continue;
3915
4284
  }
3916
4285
  if ("list" in field && field.list) {
3917
4286
  if (!Array.isArray(value)) {
3918
- errors.push({ fieldPath: path202, message: "Expected a list of values" });
4287
+ errors.push({ fieldPath: path212, message: "Expected a list of values" });
3919
4288
  continue;
3920
4289
  }
3921
4290
  value.forEach((item, index) => {
3922
- errors.push(...validateScalar(field, item, `${path202}[${index}]`));
4291
+ errors.push(...validateScalar(field, item, `${path212}[${index}]`));
3923
4292
  });
3924
4293
  continue;
3925
4294
  }
3926
4295
  if (Array.isArray(value) && KNOWN_FIELD_TYPES.has(field.type)) {
3927
- errors.push({ fieldPath: path202, message: "Expected a single value, not a list" });
4296
+ errors.push({ fieldPath: path212, message: "Expected a single value, not a list" });
3928
4297
  continue;
3929
4298
  }
3930
- errors.push(...validateScalar(field, value, path202));
4299
+ errors.push(...validateScalar(field, value, path212));
3931
4300
  }
3932
4301
  return errors;
3933
4302
  }
@@ -3971,6 +4340,37 @@ function assertBuildEntriesValid(items, phaseLabel) {
3971
4340
  ${lines.join("\n")}
3972
4341
  These are likely abandoned create-scaffolds (empty entries left behind when a create was started but never finished). Finish editing the entry (fill in its required fields) or delete the abandoned draft, then rebuild.`);
3973
4342
  }
4343
+ async function readGeneratedRecord(outputDir) {
4344
+ try {
4345
+ const raw = await fs17.readFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), "utf-8");
4346
+ const parsed = JSON.parse(raw);
4347
+ if (typeof parsed !== "object" || parsed === null || !("files" in parsed))
4348
+ return [];
4349
+ const { files } = parsed;
4350
+ if (!Array.isArray(files))
4351
+ return [];
4352
+ return files.filter((entry) => typeof entry === "string");
4353
+ } catch {
4354
+ return [];
4355
+ }
4356
+ }
4357
+ async function writeGeneratedRecord(outputDir, files) {
4358
+ const record = { files: [...files].sort() };
4359
+ await fs17.mkdir(outputDir, { recursive: true });
4360
+ await fs17.writeFile(path19.join(outputDir, GENERATED_RECORD_FILENAME), `${JSON.stringify(record, null, 2)}
4361
+ `, "utf-8");
4362
+ }
4363
+ async function removeEmptyDirsUpward(startDir, stopAt) {
4364
+ let current = startDir;
4365
+ while (current.startsWith(stopAt) && current !== stopAt) {
4366
+ try {
4367
+ await fs17.rmdir(current);
4368
+ } catch {
4369
+ return;
4370
+ }
4371
+ current = path19.dirname(current);
4372
+ }
4373
+ }
3974
4374
  async function generateAIContentFiles(options) {
3975
4375
  const { config, entrySchemaRegistry, outputDir, aiConfig: aiConfig2, _testFlatSchema } = options;
3976
4376
  const contentRootName = config.contentRoot || "content";
@@ -3993,23 +4393,45 @@ async function generateAIContentFiles(options) {
3993
4393
  config: aiConfig2,
3994
4394
  entryLinkUrl: config.entryLinkUrl
3995
4395
  });
3996
- const absoluteOutputDir = path18.resolve(outputDir) + path18.sep;
3997
- let fileCount = 0;
3998
- for (const [filePath, content] of result.files) {
3999
- const absolutePath = path18.resolve(path18.join(absoluteOutputDir, filePath));
4396
+ const absoluteOutputDir = path19.resolve(outputDir) + path19.sep;
4397
+ const resolveOutputPath = (filePath) => {
4398
+ const absolutePath = path19.resolve(path19.join(absoluteOutputDir, filePath));
4000
4399
  if (!absolutePath.startsWith(absoluteOutputDir)) {
4001
4400
  throw new Error(`Path traversal detected in AI content output: ${filePath}`);
4002
4401
  }
4003
- await fs16.mkdir(path18.dirname(absolutePath), { recursive: true });
4004
- await fs16.writeFile(absolutePath, content, "utf-8");
4402
+ return absolutePath;
4403
+ };
4404
+ const previousFiles = await readGeneratedRecord(absoluteOutputDir);
4405
+ const currentFiles = [...result.files.keys()];
4406
+ await writeGeneratedRecord(absoluteOutputDir, [.../* @__PURE__ */ new Set([...previousFiles, ...currentFiles])]);
4407
+ let fileCount = 0;
4408
+ for (const [filePath, content] of result.files) {
4409
+ const absolutePath = resolveOutputPath(filePath);
4410
+ await fs17.mkdir(path19.dirname(absolutePath), { recursive: true });
4411
+ await fs17.writeFile(absolutePath, content, "utf-8");
4005
4412
  fileCount++;
4006
4413
  }
4007
- return { fileCount, outputDir: absoluteOutputDir };
4414
+ const currentSet = new Set(currentFiles);
4415
+ const stale = previousFiles.filter((filePath) => !currentSet.has(filePath));
4416
+ let removedCount = 0;
4417
+ for (const filePath of stale) {
4418
+ const absolutePath = resolveOutputPath(filePath);
4419
+ try {
4420
+ await fs17.unlink(absolutePath);
4421
+ removedCount++;
4422
+ } catch (err) {
4423
+ if (!isNodeError3(err) || err.code !== "ENOENT")
4424
+ throw err;
4425
+ }
4426
+ await removeEmptyDirsUpward(path19.dirname(absolutePath), absoluteOutputDir);
4427
+ }
4428
+ await writeGeneratedRecord(absoluteOutputDir, currentFiles);
4429
+ return { fileCount, removedCount, outputDir: absoluteOutputDir };
4008
4430
  }
4009
4431
  async function generateAIContentCLI(options) {
4010
4432
  const { projectDir, outputDir = "public/ai", configPath, appDir = "app" } = options;
4011
4433
  console.log("\nCanopyCMS generate-ai-content\n");
4012
- const canopyConfigPath = path19.join(projectDir, "canopycms.config.ts");
4434
+ const canopyConfigPath = path20.join(projectDir, "canopycms.config.ts");
4013
4435
  let canopyConfigModule;
4014
4436
  try {
4015
4437
  canopyConfigModule = await jiti.import(canopyConfigPath);
@@ -4020,7 +4442,7 @@ async function generateAIContentCLI(options) {
4020
4442
  }
4021
4443
  const configExport = canopyConfigModule.default ?? canopyConfigModule.config ?? canopyConfigModule;
4022
4444
  const serverConfig = typeof configExport === "object" && configExport !== null && "server" in configExport ? configExport.server : configExport;
4023
- const schemasPath = path19.join(projectDir, appDir, "schemas.ts");
4445
+ const schemasPath = path20.join(projectDir, appDir, "schemas.ts");
4024
4446
  let entrySchemaRegistry = {};
4025
4447
  try {
4026
4448
  const schemasModule = await jiti.import(schemasPath);
@@ -4031,7 +4453,7 @@ async function generateAIContentCLI(options) {
4031
4453
  let aiConfig2;
4032
4454
  if (configPath) {
4033
4455
  try {
4034
- const aiConfigModule = await jiti.import(path19.resolve(configPath));
4456
+ const aiConfigModule = await jiti.import(path20.resolve(configPath));
4035
4457
  aiConfig2 = aiConfigModule.aiContentConfig ?? aiConfigModule.default ?? aiConfigModule.config;
4036
4458
  } catch (err) {
4037
4459
  console.error(`Could not load AI config from ${configPath}`);
@@ -4048,7 +4470,7 @@ async function generateAIContentCLI(options) {
4048
4470
  console.error("Make sure canopycms.config.ts uses defineCanopyConfig().");
4049
4471
  process.exit(1);
4050
4472
  }
4051
- const resolvedOutput = path19.resolve(projectDir, outputDir);
4473
+ const resolvedOutput = path20.resolve(projectDir, outputDir);
4052
4474
  console.log(` Output: ${resolvedOutput}`);
4053
4475
  console.log(` Mode: ${serverConfig.mode ?? "dev"}`);
4054
4476
  const result = await generateAIContentFiles({
@@ -4059,10 +4481,13 @@ async function generateAIContentCLI(options) {
4059
4481
  });
4060
4482
  console.log(`
4061
4483
  Generated ${result.fileCount} files`);
4484
+ if (result.removedCount > 0) {
4485
+ console.log(` Removed ${result.removedCount} stale files from the previous run`);
4486
+ }
4062
4487
  console.log(` Output: ${result.outputDir}
4063
4488
  `);
4064
4489
  }
4065
- var __defProp3, __getOwnPropNames3, __esm3, __export3, init_normalize2, active2, init_logger2, ROOT_COLLECTION_ID, init_types3, normalizePathValue, flattenSchema, init_flatten2, primitiveFieldTypes2, fieldTypes2, init_types22, fieldBaseSchema2, selectOptionSchema2, referenceOptionSchema2, primitiveFieldSchema2, ASPECT_RATIO_RE2, imageFieldSchema2, selectFieldSchema2, referenceFieldSchema2, fieldHolder2, blockSchema2, blockFieldSchema2, objectFieldSchema2, inlineGroupFieldSchema2, customFieldSchema2, knownFieldSchema2, fieldSchema2, init_field2, relativePathSchema2, entryTypeSchema2, collectionSchema2, init_collection2, mediaSchema2, init_media2, defaultBranchAccessSchema2, defaultPathAccessLevelSchema2, defaultPathAccessLevelsSchema2, defaultPathAccessSchema2, defaultBaseBranchSchema2, defaultRemoteNameSchema2, defaultRemoteUrlSchema2, gitBotAuthorNameSchema2, gitBotAuthorEmailSchema2, githubTokenEnvVarSchema2, operatingModeSchema2, deployedAsSchema2, contentRootSchema2, sourceRootSchema2, deploymentNameSchema2, devContentSyncSchema2, devConfigSchema2, editorConfigSchema2, CanopyConfigSchema2, DEFAULT_PROD_WORKSPACE2, init_config3, SERVER_MODE_ENV_VAR, BROWSER_MODE_ENV_VAR, warned2, init_mode_env2, forEachReferenceField, init_validation2, ProdClientSafeStrategy2, DevClientSafeStrategy2, clientStrategyCache, init_client_safe_strategy, warned22, VALID_DEPLOYMENT_NAME2, isValidDeploymentName2, init_deployment_name, permissionTargetSchema2, pathPermissionSchema2, init_permissions2, init_helpers2, init_config22, ProdStrategy2, DevStrategy2, strategyCache2, init_client_unsafe_strategy, operating_mode_exports, init_operating_mode, locks, META_DIR, CONTENT_WRITE_LOCK_NAME, DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, ContentWriteLockBusyError, sleep, BASE58_PATTERN, CONTENT_ID_PATTERN, PHYSICAL_SEGMENT_PATTERN, isValidId, EMPTY_LOGICAL_PATH, ContentIdIndex, registry, finalization, LOG_LEVELS2, DebugLogger2, testLogger2, log2, META_DIR2, entryTypeMetaSchema, collectionMetaSchema, rootCollectionMetaSchema, editDistance, closestName, forEachEntryType, collectEntryTypeNames, validateReferenceEntryTypes, isDeployedStatic, isBuildMode, STATIC_DEPLOY_USER, SCHEMA_CACHE_VERSION, MTIME_CHECK_DEBOUNCE_MS, SCHEMA_GENERATION_RESOURCE, BranchSchemaCache, RESOURCE, getFormatExtension, isDataOnlyFormat, asRecord, BranchPathError, resolveContentBranchesRoot, ContentStoreError, ContentConflictError, BranchSyncingError, DuplicateContentIdError, DEFAULT_INDEX_FRESHNESS_INTERVAL_MS, FORCED_REFRESH_MIN_INTERVAL_MS, STALE_LOOKUP, ContentStore, ATTR_CONTENT, BLOCK_PREFIX, BLOCK_SUFFIX, BLOCK_RESTORE_RE, INLINE_PREFIX, INLINE_SUFFIX, INLINE_RESTORE_RE, FLAT_CELL_TYPES, log22, BASE58_CHAR, ENTRY_LINK_PATTERN, log3, REGISTRY_FILE, REGISTRY_STALE_FILE, REGISTRY_TEMP_FILE, REGISTRY_VERSION, RESOURCE2, GET_MISS_REFRESH_MIN_INTERVAL_MS, BranchRegistry, log4, OccWriteConflictError, BRANCH_META_DIR, BRANCH_META_FILE, CURRENT_SCHEMA_VERSION, BranchMetadataConflictError, BranchMetadataCorruptError, BranchMetadataFileManager, getBranchMetadataFileManager, loadBranchContext, NETWORK_SCHEME_PATTERN, TRANSPORT_HELPER_PATTERN, LEADING_OPTION_PATTERN, WINDOWS_DRIVE_PATTERN, COLON_BEFORE_SLASH_PATTERN, MISSING_REMOTE_REF_REASONS, log5, GIT_ENV_PASSTHROUGH, FORCE_C_LOCALE, remoteInitLocks, GITHUB_TRACKING_REF_PREFIX, GitConflictError, GitRemoteRefMissingError, GitManager, log6, workspaceInitLocks, BranchWorkspaceManager, log7, normalizePath, readEntryData, parseTypedFilename, looksLikeMalformedEntry, listCollectionEntries, MAX_INPUT_PIXELS, KNOWN_FIELD_TYPES, STRING_FIELD_TYPES, selectOptionValues, jiti;
4490
+ var __defProp3, __getOwnPropNames3, __esm3, __export3, active2, init_logger2, init_normalize2, ROOT_COLLECTION_ID, init_types3, normalizePathValue, flattenSchema, init_flatten2, primitiveFieldTypes2, fieldTypes2, init_types22, fieldBaseSchema2, selectOptionSchema2, referenceOptionSchema2, primitiveFieldSchema2, ASPECT_RATIO_RE2, imageFieldSchema2, selectFieldSchema2, referenceFieldSchema2, fieldHolder2, blockSchema2, blockFieldSchema2, objectFieldSchema2, inlineGroupFieldSchema2, customFieldSchema2, knownFieldSchema2, fieldSchema2, init_field2, relativePathSchema2, entryTypeSchema2, collectionSchema2, init_collection2, mediaSchema2, init_media2, defaultBranchAccessSchema2, defaultPathAccessLevelSchema2, defaultPathAccessLevelsSchema2, defaultPathAccessSchema2, defaultBaseBranchSchema2, defaultRemoteNameSchema2, defaultRemoteUrlSchema2, gitBotAuthorNameSchema2, gitBotAuthorEmailSchema2, githubTokenEnvVarSchema2, operatingModeSchema2, deployedAsSchema2, contentRootSchema2, sourceRootSchema2, basePathSchema2, deploymentNameSchema2, devContentSyncSchema2, devConfigSchema2, editorConfigSchema2, CanopyConfigSchema2, DEFAULT_PROD_WORKSPACE2, init_config3, SERVER_MODE_ENV_VAR, BROWSER_MODE_ENV_VAR, warned2, init_mode_env2, forEachReferenceField, init_validation2, ProdClientSafeStrategy2, DevClientSafeStrategy2, clientStrategyCache, init_client_safe_strategy, warned22, VALID_DEPLOYMENT_NAME2, isValidDeploymentName2, init_deployment_name, permissionTargetSchema2, pathPermissionSchema2, init_permissions2, init_helpers2, init_config22, ProdStrategy2, DevStrategy2, strategyCache2, init_client_unsafe_strategy, operating_mode_exports, init_operating_mode, BLOCK_DISCRIMINATOR_KEYS, BLOCK_STRUCTURAL_KEYS, EVIDENCE_MAX_DEPTH, locks, META_DIR, CONTENT_WRITE_LOCK_NAME, DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS, ContentWriteLockBusyError, sleep, DEFAULT_SEO_FIELD_NAMES, SEO_GROUP_FIELDS, BASE58_PATTERN, CONTENT_ID_PATTERN, PHYSICAL_SEGMENT_PATTERN, isValidId, EMPTY_LOGICAL_PATH, ContentIdIndex, parseTypedFilename, CONTENT_EXTENSIONS, registry, finalization, LOG_LEVELS2, DebugLogger2, testLogger2, log2, META_DIR2, entryTypeMetaSchema, collectionMetaSchema, rootCollectionMetaSchema, editDistance, closestName, forEachEntryType, collectEntryTypeNames, validateReferenceEntryTypes, isDeployedStatic, isBuildMode, STATIC_DEPLOY_USER, SCHEMA_CACHE_VERSION, MTIME_CHECK_DEBOUNCE_MS, SCHEMA_GENERATION_RESOURCE, BranchSchemaCache, RESOURCE, getFormatExtension, isDataOnlyFormat, asRecord, BranchPathError, resolveContentBranchesRoot, ContentStoreError, ContentConflictError, BranchSyncingError, DuplicateContentIdError, UrlPathConflictError, DEFAULT_INDEX_FRESHNESS_INTERVAL_MS, FORCED_REFRESH_MIN_INTERVAL_MS, STALE_LOOKUP, createReferenceResolveCache, ContentStore, ATTR_CONTENT, BLOCK_PREFIX, BLOCK_SUFFIX, BLOCK_RESTORE_RE, INLINE_PREFIX, INLINE_SUFFIX, INLINE_RESTORE_RE, FLAT_CELL_TYPES, log22, BASE58_CHAR, ENTRY_LINK_PATTERN, log3, REGISTRY_FILE, REGISTRY_STALE_FILE, REGISTRY_TEMP_FILE, REGISTRY_VERSION, RESOURCE2, GET_MISS_REFRESH_MIN_INTERVAL_MS, BranchRegistry, log4, OccWriteConflictError, BRANCH_META_DIR, BRANCH_META_FILE, CURRENT_SCHEMA_VERSION, BranchMetadataConflictError, BranchMetadataCorruptError, BranchMetadataFileManager, getBranchMetadataFileManager, loadBranchContext, NETWORK_SCHEME_PATTERN, TRANSPORT_HELPER_PATTERN, LEADING_OPTION_PATTERN, WINDOWS_DRIVE_PATTERN, COLON_BEFORE_SLASH_PATTERN, MISSING_REMOTE_REF_REASONS, log5, GIT_ENV_PASSTHROUGH, FORCE_C_LOCALE, remoteInitLocks, GITHUB_TRACKING_REF_PREFIX, GitConflictError, GitRemoteRefMissingError, GitManager, log6, workspaceInitLocks, BranchWorkspaceManager, log7, normalizePath, readEntryData, createReferenceResolver, resolveCollectionItemReferences, looksLikeMalformedEntry, listCollectionEntries, MAX_INPUT_PIXELS, KNOWN_FIELD_TYPES, STRING_FIELD_TYPES, selectOptionValues, GENERATED_RECORD_FILENAME, jiti;
4066
4491
  var init_generate_ai_content = __esm({
4067
4492
  "dist/cli/generate-ai-content.js"() {
4068
4493
  "use strict";
@@ -4075,17 +4500,17 @@ var init_generate_ai_content = __esm({
4075
4500
  for (var name in all)
4076
4501
  __defProp3(target, name, { get: all[name], enumerable: true });
4077
4502
  };
4078
- init_normalize2 = __esm3({
4079
- "dist/paths/normalize.js"() {
4080
- "use strict";
4081
- }
4082
- });
4083
4503
  init_logger2 = __esm3({
4084
4504
  "dist/utils/logger.js"() {
4085
4505
  "use strict";
4086
4506
  active2 = console;
4087
4507
  }
4088
4508
  });
4509
+ init_normalize2 = __esm3({
4510
+ "dist/paths/normalize.js"() {
4511
+ "use strict";
4512
+ }
4513
+ });
4089
4514
  init_types3 = __esm3({
4090
4515
  "dist/paths/types.js"() {
4091
4516
  "use strict";
@@ -4259,7 +4684,12 @@ var init_generate_ai_content = __esm({
4259
4684
  collections: z22.array(z22.string().min(1)).min(1).optional(),
4260
4685
  entryTypes: z22.array(z22.string().min(1)).min(1).optional(),
4261
4686
  displayField: z22.string().min(1).optional(),
4262
- options: z22.array(referenceOptionSchema2).optional()
4687
+ options: z22.array(referenceOptionSchema2).optional(),
4688
+ // Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
4689
+ // default, so a consumer that adopts this schema's parse output would silently delete a
4690
+ // runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
4691
+ // absent on purpose — it is type-inference-only and stripping it changes no behavior.)
4692
+ includeBody: z22.boolean().optional()
4263
4693
  });
4264
4694
  fieldHolder2 = [z22.never()];
4265
4695
  blockSchema2 = z22.object({
@@ -4380,6 +4810,9 @@ var init_generate_ai_content = __esm({
4380
4810
  deployedAsSchema2 = z52.enum(["static", "server"]).default("server");
4381
4811
  contentRootSchema2 = relativePathSchema2.default("content");
4382
4812
  sourceRootSchema2 = z52.string().min(1).optional();
4813
+ basePathSchema2 = z52.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
4814
+ message: "basePath must not be empty or only whitespace"
4815
+ }).optional();
4383
4816
  deploymentNameSchema2 = z52.string().default("prod");
4384
4817
  devContentSyncSchema2 = z52.enum(["off", "warn"]).default("warn");
4385
4818
  devConfigSchema2 = z52.object({
@@ -4442,6 +4875,7 @@ var init_generate_ai_content = __esm({
4442
4875
  deploymentName: deploymentNameSchema2.optional(),
4443
4876
  contentRoot: contentRootSchema2.default("content"),
4444
4877
  sourceRoot: sourceRootSchema2.optional(),
4878
+ basePath: basePathSchema2,
4445
4879
  editor: editorConfigSchema2.optional(),
4446
4880
  authPlugin: z52.custom().optional(),
4447
4881
  entryLinkUrl: z52.custom().optional(),
@@ -4611,32 +5045,32 @@ var init_generate_ai_content = __esm({
4611
5045
  // - shouldCommit(), shouldPush()
4612
5046
  // Add client-unsafe methods (use Node.js APIs)
4613
5047
  getWorkspaceRoot(_sourceRoot) {
4614
- return path82.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE2);
5048
+ return path9.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE2);
4615
5049
  }
4616
5050
  getContentRoot(contentRoot, sourceRoot) {
4617
- return path82.resolve(sourceRoot ?? process.cwd(), contentRoot);
5051
+ return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
4618
5052
  }
4619
5053
  getContentBranchesRoot(sourceRoot) {
4620
- return path82.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
5054
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
4621
5055
  }
4622
5056
  getContentBranchRoot(branchName, sourceRoot) {
4623
- return path82.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
5057
+ return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
4624
5058
  }
4625
5059
  getGitExcludePattern() {
4626
5060
  return ".canopy-meta/";
4627
5061
  }
4628
5062
  getPermissionsFilePath(root) {
4629
- return path82.join(root, this.getPermissionsFileName());
5063
+ return path9.join(root, this.getPermissionsFileName());
4630
5064
  }
4631
5065
  getGroupsFilePath(root) {
4632
- return path82.join(root, this.getGroupsFileName());
5066
+ return path9.join(root, this.getGroupsFileName());
4633
5067
  }
4634
5068
  getRemoteUrlConfig() {
4635
5069
  return {
4636
5070
  shouldAutoInitLocal: false,
4637
5071
  defaultRemotePath: "",
4638
5072
  envVarName: "CANOPYCMS_REMOTE_URL",
4639
- autoDetectRemotePath: path82.join(this.getWorkspaceRoot(), "remote.git")
5073
+ autoDetectRemotePath: path9.join(this.getWorkspaceRoot(), "remote.git")
4640
5074
  };
4641
5075
  }
4642
5076
  requiresExistingRepo() {
@@ -4648,7 +5082,7 @@ var init_generate_ai_content = __esm({
4648
5082
  return `canopycms-settings-${resolveDeploymentName2(config, "prod")}`;
4649
5083
  }
4650
5084
  getSettingsRoot(sourceRoot) {
4651
- return path82.join(this.getWorkspaceRoot(sourceRoot), "settings");
5085
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
4652
5086
  }
4653
5087
  usesSeparateSettingsBranch() {
4654
5088
  return true;
@@ -4665,25 +5099,25 @@ var init_generate_ai_content = __esm({
4665
5099
  DevStrategy2 = class extends DevClientSafeStrategy2 {
4666
5100
  // Inherits client-safe methods from DevClientSafeStrategy
4667
5101
  getWorkspaceRoot(sourceRoot) {
4668
- return path82.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
5102
+ return path9.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
4669
5103
  }
4670
5104
  getContentRoot(contentRoot, sourceRoot) {
4671
- return path82.resolve(sourceRoot ?? process.cwd(), contentRoot);
5105
+ return path9.resolve(sourceRoot ?? process.cwd(), contentRoot);
4672
5106
  }
4673
5107
  getContentBranchesRoot(sourceRoot) {
4674
- return path82.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
5108
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
4675
5109
  }
4676
5110
  getContentBranchRoot(branchName, sourceRoot) {
4677
- return path82.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
5111
+ return path9.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
4678
5112
  }
4679
5113
  getGitExcludePattern() {
4680
5114
  return ".canopy-meta/";
4681
5115
  }
4682
5116
  getPermissionsFilePath(root) {
4683
- return path82.join(root, this.getPermissionsFileName());
5117
+ return path9.join(root, this.getPermissionsFileName());
4684
5118
  }
4685
5119
  getGroupsFilePath(root) {
4686
- return path82.join(root, this.getGroupsFileName());
5120
+ return path9.join(root, this.getGroupsFileName());
4687
5121
  }
4688
5122
  getRemoteUrlConfig() {
4689
5123
  return {
@@ -4701,7 +5135,7 @@ var init_generate_ai_content = __esm({
4701
5135
  return `canopycms-settings-${resolveDeploymentName2(config, "local")}`;
4702
5136
  }
4703
5137
  getSettingsRoot(sourceRoot) {
4704
- return path82.join(this.getWorkspaceRoot(sourceRoot), "settings");
5138
+ return path9.join(this.getWorkspaceRoot(sourceRoot), "settings");
4705
5139
  }
4706
5140
  usesSeparateSettingsBranch() {
4707
5141
  return true;
@@ -4736,7 +5170,12 @@ var init_generate_ai_content = __esm({
4736
5170
  init_mode_env2();
4737
5171
  }
4738
5172
  });
5173
+ BLOCK_DISCRIMINATOR_KEYS = ["template", "_type"];
5174
+ BLOCK_STRUCTURAL_KEYS = new Set(BLOCK_DISCRIMINATOR_KEYS);
5175
+ EVIDENCE_MAX_DEPTH = 6;
4739
5176
  locks = /* @__PURE__ */ new Map();
5177
+ init_logger2();
5178
+ init_logger2();
4740
5179
  META_DIR = ".canopy-meta";
4741
5180
  CONTENT_WRITE_LOCK_NAME = "content-write.lock";
4742
5181
  DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS = 2e3;
@@ -4749,6 +5188,67 @@ var init_generate_ai_content = __esm({
4749
5188
  sleep = (ms) => new Promise((resolve2) => {
4750
5189
  setTimeout(resolve2, ms);
4751
5190
  });
5191
+ DEFAULT_SEO_FIELD_NAMES = {
5192
+ title: "metaTitle",
5193
+ description: "metaDescription",
5194
+ ogImage: "ogImage",
5195
+ ogType: "ogType",
5196
+ canonical: "canonical",
5197
+ noindex: "noindex",
5198
+ twitterCard: "twitterCard"
5199
+ };
5200
+ SEO_GROUP_FIELDS = [
5201
+ {
5202
+ name: DEFAULT_SEO_FIELD_NAMES.title,
5203
+ type: "string",
5204
+ label: "Meta Title",
5205
+ description: "Overrides the page title in search results and social cards.",
5206
+ required: false
5207
+ },
5208
+ {
5209
+ name: DEFAULT_SEO_FIELD_NAMES.description,
5210
+ type: "string",
5211
+ label: "Meta Description",
5212
+ description: "Summary shown under the title in search results.",
5213
+ required: false
5214
+ },
5215
+ {
5216
+ name: DEFAULT_SEO_FIELD_NAMES.ogImage,
5217
+ type: "string",
5218
+ label: "Social Image URL",
5219
+ description: "Image for social cards. Site-relative or absolute.",
5220
+ required: false
5221
+ },
5222
+ {
5223
+ name: DEFAULT_SEO_FIELD_NAMES.ogType,
5224
+ type: "select",
5225
+ label: "OpenGraph Type",
5226
+ options: ["website", "article", "profile"],
5227
+ required: false
5228
+ },
5229
+ {
5230
+ name: DEFAULT_SEO_FIELD_NAMES.canonical,
5231
+ type: "string",
5232
+ label: "Canonical URL",
5233
+ description: "Set only to point at a different canonical copy of this page.",
5234
+ required: false
5235
+ },
5236
+ {
5237
+ name: DEFAULT_SEO_FIELD_NAMES.noindex,
5238
+ type: "boolean",
5239
+ label: "Hide from search engines",
5240
+ description: "Marks the page noindex AND drops it from the sitemap.",
5241
+ required: false
5242
+ },
5243
+ {
5244
+ name: DEFAULT_SEO_FIELD_NAMES.twitterCard,
5245
+ type: "select",
5246
+ label: "Twitter Card",
5247
+ options: ["summary", "summary_large_image"],
5248
+ required: false
5249
+ }
5250
+ ];
5251
+ init_normalize2();
4752
5252
  init_normalize2();
4753
5253
  BASE58_PATTERN = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
4754
5254
  CONTENT_ID_PATTERN = new RegExp(`^${BASE58_PATTERN}{12}$`);
@@ -5066,6 +5566,31 @@ var init_generate_ai_content = __esm({
5066
5566
  this.pathToId.set(newRelativePath, id);
5067
5567
  }
5068
5568
  };
5569
+ parseTypedFilename = (filename, entryTypes) => {
5570
+ if (filename.startsWith("."))
5571
+ return null;
5572
+ const lastDot = filename.lastIndexOf(".");
5573
+ if (lastDot === -1)
5574
+ return null;
5575
+ const nameWithoutExt = filename.slice(0, lastDot);
5576
+ const parts = nameWithoutExt.split(".");
5577
+ if (parts.length < 3)
5578
+ return null;
5579
+ const potentialType = parts[0];
5580
+ if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
5581
+ return null;
5582
+ }
5583
+ const id = parts[parts.length - 1];
5584
+ if (!isValidId(id))
5585
+ return null;
5586
+ const slug = parts.slice(1, -1).join(".").toLowerCase();
5587
+ return {
5588
+ type: potentialType,
5589
+ slug,
5590
+ id
5591
+ };
5592
+ };
5593
+ CONTENT_EXTENSIONS = [".md", ".mdx", ".json", ".yaml"];
5069
5594
  registry = /* @__PURE__ */ new Map();
5070
5595
  finalization = new FinalizationRegistry(({ rootKey, ref }) => {
5071
5596
  const refs = registry.get(rootKey);
@@ -5303,7 +5828,7 @@ var init_generate_ai_content = __esm({
5303
5828
  * the project root, regardless of which entrypoint produced the cwd branchRoot.
5304
5829
  */
5305
5830
  skipDiskCache(branchRoot) {
5306
- return isBuildMode() || path72.resolve(branchRoot) === path72.resolve(process.cwd());
5831
+ return isBuildMode() || path82.resolve(branchRoot) === path82.resolve(process.cwd());
5307
5832
  }
5308
5833
  /**
5309
5834
  * Get schema for a branch (loads from cache or resolves fresh).
@@ -5329,14 +5854,14 @@ var init_generate_ai_content = __esm({
5329
5854
  * Load schema from cache or resolve fresh if cache is missing or stale.
5330
5855
  */
5331
5856
  async loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName) {
5332
- const contentRoot = path72.join(branchRoot, contentRootName);
5857
+ const contentRoot = path82.join(branchRoot, contentRootName);
5333
5858
  const skipDiskCache = this.skipDiskCache(branchRoot);
5334
5859
  if (!skipDiskCache) {
5335
- const cacheDir = path72.join(branchRoot, ".canopy-meta");
5336
- const cachePath = path72.join(cacheDir, "schema-cache.json");
5860
+ const cacheDir = path82.join(branchRoot, ".canopy-meta");
5861
+ const cachePath = path82.join(cacheDir, "schema-cache.json");
5337
5862
  let cacheData = null;
5338
5863
  try {
5339
- const cacheContent = await fs62.readFile(cachePath, "utf-8");
5864
+ const cacheContent = await fs72.readFile(cachePath, "utf-8");
5340
5865
  cacheData = JSON.parse(cacheContent);
5341
5866
  } catch {
5342
5867
  cacheData = null;
@@ -5373,7 +5898,7 @@ var init_generate_ai_content = __esm({
5373
5898
  */
5374
5899
  async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
5375
5900
  const { skipDiskCache } = options;
5376
- const contentRoot = path72.join(branchRoot, contentRootName);
5901
+ const contentRoot = path82.join(branchRoot, contentRootName);
5377
5902
  const read = skipDiskCache ? null : await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
5378
5903
  const result = await this.resolveFresh(contentRoot, entrySchemaRegistry);
5379
5904
  if (!isValidSchema(result.schema)) {
@@ -5386,9 +5911,9 @@ var init_generate_ai_content = __esm({
5386
5911
  }
5387
5912
  const flatSchema = flattenSchema(result.schema, contentRootName);
5388
5913
  if (!skipDiskCache) {
5389
- const cacheDir = path72.join(branchRoot, ".canopy-meta");
5390
- const cachePath = path72.join(cacheDir, "schema-cache.json");
5391
- await fs62.unlink(path72.join(cacheDir, "schema-cache.stale")).catch(() => {
5914
+ const cacheDir = path82.join(branchRoot, ".canopy-meta");
5915
+ const cachePath = path82.join(cacheDir, "schema-cache.json");
5916
+ await fs72.unlink(path82.join(cacheDir, "schema-cache.stale")).catch(() => {
5392
5917
  });
5393
5918
  if (read && read.ok) {
5394
5919
  const newCache = {
@@ -5398,13 +5923,13 @@ var init_generate_ai_content = __esm({
5398
5923
  cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
5399
5924
  generation: read.token
5400
5925
  };
5401
- await fs62.mkdir(cacheDir, { recursive: true });
5402
- const tmpPath = path72.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
5403
- await fs62.writeFile(tmpPath, JSON.stringify(newCache, null, 2), "utf-8");
5926
+ await fs72.mkdir(cacheDir, { recursive: true });
5927
+ const tmpPath = path82.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
5928
+ await fs72.writeFile(tmpPath, JSON.stringify(newCache, null, 2), "utf-8");
5404
5929
  try {
5405
- await fs62.rename(tmpPath, cachePath);
5930
+ await fs72.rename(tmpPath, cachePath);
5406
5931
  } catch (err) {
5407
- await fs62.unlink(tmpPath).catch(() => {
5932
+ await fs72.unlink(tmpPath).catch(() => {
5408
5933
  });
5409
5934
  throw err;
5410
5935
  }
@@ -5514,9 +6039,17 @@ var init_generate_ai_content = __esm({
5514
6039
  this.paths = sorted;
5515
6040
  }
5516
6041
  };
6042
+ UrlPathConflictError = class extends ContentConflictError {
6043
+ constructor(message, conflictingPath) {
6044
+ super(message);
6045
+ this.name = "UrlPathConflictError";
6046
+ this.conflictingPath = conflictingPath;
6047
+ }
6048
+ };
5517
6049
  DEFAULT_INDEX_FRESHNESS_INTERVAL_MS = 1e3;
5518
6050
  FORCED_REFRESH_MIN_INTERVAL_MS = 5e3;
5519
6051
  STALE_LOOKUP = Symbol("stale-index-lookup");
6052
+ createReferenceResolveCache = () => /* @__PURE__ */ new Map();
5520
6053
  ContentStore = class {
5521
6054
  constructor(root, flatSchema, options = {}) {
5522
6055
  this.indexGeneration = 0;
@@ -5525,7 +6058,7 @@ var init_generate_ai_content = __esm({
5525
6058
  this.lastDiskProbeMs = 0;
5526
6059
  this.lastForcedRefreshMs = 0;
5527
6060
  this.indexBuild = null;
5528
- this.root = path10.resolve(root);
6061
+ this.root = path11.resolve(root);
5529
6062
  this.contentRootName = options.contentRootName || "content";
5530
6063
  this.indexFreshnessIntervalMs = options.indexFreshnessIntervalMs ?? DEFAULT_INDEX_FRESHNESS_INTERVAL_MS;
5531
6064
  this.contentWriteLockWaitMs = options.contentWriteLockWaitMs ?? DEFAULT_CONTENT_WRITE_LOCK_WAIT_MS;
@@ -5673,7 +6206,7 @@ var init_generate_ai_content = __esm({
5673
6206
  async findEntryPathsById(dir, id) {
5674
6207
  let entries;
5675
6208
  try {
5676
- entries = await fs9.readdir(dir, { withFileTypes: true });
6209
+ entries = await fs10.readdir(dir, { withFileTypes: true });
5677
6210
  } catch (err) {
5678
6211
  if (isNodeError3(err) && err.code === "ENOENT")
5679
6212
  return [];
@@ -5684,7 +6217,7 @@ var init_generate_ai_content = __esm({
5684
6217
  if (entry.isDirectory())
5685
6218
  continue;
5686
6219
  if (extractIdFromFilename(entry.name) === id) {
5687
- matches.push(path10.relative(this.root, path10.join(dir, entry.name)));
6220
+ matches.push(path11.relative(this.root, path11.join(dir, entry.name)));
5688
6221
  }
5689
6222
  }
5690
6223
  return matches.sort();
@@ -5696,11 +6229,11 @@ var init_generate_ai_content = __esm({
5696
6229
  getSchemaItems() {
5697
6230
  return this.schemaIndex.values();
5698
6231
  }
5699
- assertSchemaItem(path202) {
5700
- const normalized = normalizeFilesystemPath(path202);
6232
+ assertSchemaItem(path212) {
6233
+ const normalized = normalizeFilesystemPath(path212);
5701
6234
  const item = this.schemaIndex.get(normalized);
5702
6235
  if (!item) {
5703
- throw new ContentStoreError(`Unknown schema item: ${path202}`, "NO_SCHEMA_ITEM");
6236
+ throw new ContentStoreError(`Unknown schema item: ${path212}`, "NO_SCHEMA_ITEM");
5704
6237
  }
5705
6238
  return item;
5706
6239
  }
@@ -5767,6 +6300,26 @@ var init_generate_ai_content = __esm({
5767
6300
  return this.createLockKey(schemaItem, slug);
5768
6301
  return prePass.id ? this.idLockKey(prePass.id) : prePass.absolutePath;
5769
6302
  }
6303
+ /**
6304
+ * Refuse a create/rename that would give a second entry a `urlPath` another entry already
6305
+ * holds. See url-collision.ts for the two shapes that count, and the legitimate
6306
+ * landing-page-beside-a-collection shape that deliberately does not.
6307
+ *
6308
+ * @param collectionDir Absolute physical directory the entry will live in.
6309
+ * @param slug The entry's slug, as it will be written.
6310
+ */
6311
+ async assertUrlPathAvailable(collectionDir, slug) {
6312
+ const claimant = await findUrlPathClaimant({
6313
+ collectionDir,
6314
+ slug,
6315
+ contentRoot: path11.resolve(this.root, this.contentRootName)
6316
+ });
6317
+ if (!claimant)
6318
+ return;
6319
+ const relative2 = path11.relative(this.root, claimant.physicalPath);
6320
+ 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.`;
6321
+ throw new UrlPathConflictError(message, claimant.physicalPath);
6322
+ }
5770
6323
  /**
5771
6324
  * Build absolute and relative paths with security validation.
5772
6325
  * All entries use the unified filename pattern: {type}.{slug}.{id}.{ext}
@@ -5783,7 +6336,7 @@ var init_generate_ai_content = __esm({
5783
6336
  * @param options.entryTypeName - For collections with multiple entry types, specify which one to use. Defaults to the default entry type.
5784
6337
  */
5785
6338
  async buildPaths(schemaItem, slug, options = {}) {
5786
- const rootWithSep = this.root.endsWith(path10.sep) ? this.root : `${this.root}${path10.sep}`;
6339
+ const rootWithSep = this.root.endsWith(path11.sep) ? this.root : `${this.root}${path11.sep}`;
5787
6340
  if (schemaItem.type === "entry-type") {
5788
6341
  const parentPath = schemaItem.parentPath || "";
5789
6342
  const parentCollection = this.schemaIndex.get(parentPath);
@@ -5816,7 +6369,7 @@ var init_generate_ai_content = __esm({
5816
6369
  const entryTypeName = entryTypeConfig?.name || "entry";
5817
6370
  let collectionRoot = await resolveCollectionPath(this.root, schemaItem.logicalPath);
5818
6371
  if (!collectionRoot) {
5819
- collectionRoot = path10.resolve(this.root, schemaItem.logicalPath);
6372
+ collectionRoot = path11.resolve(this.root, schemaItem.logicalPath);
5820
6373
  }
5821
6374
  if (!collectionRoot.startsWith(rootWithSep)) {
5822
6375
  throw new ContentStoreError("Path traversal detected", "VALIDATION");
@@ -5826,7 +6379,7 @@ var init_generate_ai_content = __esm({
5826
6379
  let existingEntryType;
5827
6380
  let foundExisting = false;
5828
6381
  if (!id) {
5829
- const entries = await fs9.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
6382
+ const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
5830
6383
  const existingFile = entries.find((entry) => {
5831
6384
  if (entry.isDirectory())
5832
6385
  return false;
@@ -5852,14 +6405,14 @@ var init_generate_ai_content = __esm({
5852
6405
  }
5853
6406
  filename = `${finalEntryTypeName}.${safeSlug}.${id}${ext}`;
5854
6407
  }
5855
- const resolved = path10.resolve(collectionRoot, filename);
5856
- const collectionRootWithSep = collectionRoot.endsWith(path10.sep) ? collectionRoot : `${collectionRoot}${path10.sep}`;
6408
+ const resolved = path11.resolve(collectionRoot, filename);
6409
+ const collectionRootWithSep = collectionRoot.endsWith(path11.sep) ? collectionRoot : `${collectionRoot}${path11.sep}`;
5857
6410
  if (!resolved.startsWith(collectionRootWithSep)) {
5858
6411
  throw new ContentStoreError("Path traversal detected", "VALIDATION");
5859
6412
  }
5860
6413
  return {
5861
6414
  absolutePath: resolved,
5862
- relativePath: path10.relative(this.root, resolved),
6415
+ relativePath: path11.relative(this.root, resolved),
5863
6416
  id,
5864
6417
  entryTypeName: finalEntryTypeName,
5865
6418
  existed
@@ -5895,8 +6448,8 @@ var init_generate_ai_content = __esm({
5895
6448
  async read(collectionPath, slug = "", options = {}) {
5896
6449
  const schemaItem = this.assertSchemaItem(collectionPath);
5897
6450
  const { absolutePath, relativePath, entryTypeName: resolvedEntryTypeName } = await this.buildPaths(schemaItem, slug);
5898
- const stat = await fs9.stat(absolutePath);
5899
- const raw = await fs9.readFile(absolutePath, "utf8");
6451
+ const stat = await fs10.stat(absolutePath);
6452
+ const raw = await fs10.readFile(absolutePath, "utf8");
5900
6453
  let doc;
5901
6454
  let format;
5902
6455
  let fields;
@@ -5935,7 +6488,7 @@ var init_generate_ai_content = __esm({
5935
6488
  absolutePath
5936
6489
  };
5937
6490
  } else {
5938
- const parsed = matter(raw);
6491
+ const parsed = matter2(raw);
5939
6492
  doc = {
5940
6493
  collection: schemaItem.logicalPath,
5941
6494
  collectionName: schemaItem.name,
@@ -5998,7 +6551,7 @@ var init_generate_ai_content = __esm({
5998
6551
  const indexedPath = guardIndex.findById(id)?.relativePath ?? null;
5999
6552
  if (indexedPath && indexedPath !== relativePath) {
6000
6553
  const quarantined = guardIndex.getDuplicateFor(id);
6001
- const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(path10.join(this.root, indexedPath));
6554
+ const bothOnDisk = await filePathExists3(absolutePath) && await filePathExists3(path11.join(this.root, indexedPath));
6002
6555
  if (quarantined || bothOnDisk) {
6003
6556
  throw new DuplicateContentIdError(id, [
6004
6557
  indexedPath,
@@ -6009,10 +6562,18 @@ var init_generate_ai_content = __esm({
6009
6562
  }
6010
6563
  }
6011
6564
  }
6012
- await fs9.mkdir(path10.dirname(absolutePath), { recursive: true });
6565
+ if (!await filePathExists3(absolutePath)) {
6566
+ const chosenSlug = extractSlugFromFilename(path11.basename(absolutePath));
6567
+ const routable = parseSlug(chosenSlug);
6568
+ if (!routable.ok) {
6569
+ 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");
6570
+ }
6571
+ await this.assertUrlPathAvailable(path11.dirname(absolutePath), chosenSlug);
6572
+ }
6573
+ await fs10.mkdir(path11.dirname(absolutePath), { recursive: true });
6013
6574
  if (input.expectedVersion !== void 0) {
6014
6575
  try {
6015
- const existing = await fs9.stat(absolutePath);
6576
+ const existing = await fs10.stat(absolutePath);
6016
6577
  if (input.expectedVersion === null) {
6017
6578
  throw new ContentConflictError("An entry with this slug already exists");
6018
6579
  }
@@ -6029,7 +6590,7 @@ var init_generate_ai_content = __esm({
6029
6590
  }
6030
6591
  }
6031
6592
  if (existingId && !await filePathExists3(absolutePath)) {
6032
- const actualRelPaths = await this.findEntryPathsById(path10.dirname(absolutePath), existingId);
6593
+ const actualRelPaths = await this.findEntryPathsById(path11.dirname(absolutePath), existingId);
6033
6594
  if (actualRelPaths.length > 1) {
6034
6595
  throw new DuplicateContentIdError(existingId, actualRelPaths);
6035
6596
  }
@@ -6039,14 +6600,15 @@ var init_generate_ai_content = __esm({
6039
6600
  throw new ContentConflictError();
6040
6601
  }
6041
6602
  }
6603
+ const existingRaw = input.format === "json" ? void 0 : await readFileIfExists(absolutePath);
6042
6604
  let content;
6043
6605
  if (input.format === "json") {
6044
6606
  content = `${JSON.stringify(input.data ?? {}, null, 2)}
6045
6607
  `;
6046
6608
  } else if (input.format === "yaml") {
6047
- content = yamlStringify(input.data ?? {});
6609
+ content = serializeYaml(input.data ?? {}, existingRaw);
6048
6610
  } else {
6049
- content = matter.stringify(input.body, input.data ?? {});
6611
+ content = serializeFrontmatter(input.body, input.data ?? {}, existingRaw);
6050
6612
  }
6051
6613
  await atomicWriteFile2(absolutePath, content);
6052
6614
  const liveIndex = this._idIndex;
@@ -6055,7 +6617,7 @@ var init_generate_ai_content = __esm({
6055
6617
  const existing = liveIndex.findById(id);
6056
6618
  if (existing) {
6057
6619
  if (existing.relativePath !== relativePath) {
6058
- staleOldAbsPath = path10.join(this.root, existing.relativePath);
6620
+ staleOldAbsPath = path11.join(this.root, existing.relativePath);
6059
6621
  liveIndex.updatePath(existing.id, relativePath);
6060
6622
  }
6061
6623
  } else {
@@ -6068,13 +6630,13 @@ var init_generate_ai_content = __esm({
6068
6630
  }
6069
6631
  }
6070
6632
  if (staleOldAbsPath) {
6071
- await fs9.unlink(staleOldAbsPath).catch((err) => {
6633
+ await fs10.unlink(staleOldAbsPath).catch((err) => {
6072
6634
  if (!isNodeError3(err) || err.code !== "ENOENT")
6073
6635
  throw err;
6074
6636
  });
6075
6637
  }
6076
6638
  await this.recordOwnMutation(liveIndex);
6077
- const afterStat = await fs9.stat(absolutePath);
6639
+ const afterStat = await fs10.stat(absolutePath);
6078
6640
  const base = {
6079
6641
  collection: schemaItem.logicalPath,
6080
6642
  collectionName: schemaItem.name,
@@ -6152,7 +6714,7 @@ var init_generate_ai_content = __esm({
6152
6714
  const schemaItem = this.assertSchemaItem(collectionPath);
6153
6715
  const { absolutePath } = await this.buildPaths(schemaItem, slug);
6154
6716
  try {
6155
- await fs9.access(absolutePath);
6717
+ await fs10.access(absolutePath);
6156
6718
  return true;
6157
6719
  } catch (err) {
6158
6720
  if (isNodeError3(err) && err.code === "ENOENT")
@@ -6191,7 +6753,7 @@ var init_generate_ai_content = __esm({
6191
6753
  const collectionRoot = await resolveCollectionPath(this.root, collectionPath);
6192
6754
  if (!collectionRoot)
6193
6755
  return 0;
6194
- const entries = await fs9.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
6756
+ const entries = await fs10.readdir(collectionRoot, { withFileTypes: true }).catch(() => []);
6195
6757
  return entries.filter((entry) => !entry.isDirectory() && extractEntryTypeFromFilename(entry.name) === entryTypeName).length;
6196
6758
  }
6197
6759
  /**
@@ -6215,7 +6777,7 @@ var init_generate_ai_content = __esm({
6215
6777
  const collection = this.assertCollection(collectionPath);
6216
6778
  const prePass = await this.buildPaths(collection, slug);
6217
6779
  if (!prePass.existed) {
6218
- await fs9.unlink(prePass.absolutePath);
6780
+ await fs10.unlink(prePass.absolutePath);
6219
6781
  return;
6220
6782
  }
6221
6783
  let lockKey = this.entryLockKey(collection, slug, prePass);
@@ -6231,7 +6793,7 @@ var init_generate_ai_content = __esm({
6231
6793
  return RETRY_KEY;
6232
6794
  }
6233
6795
  const { absolutePath, relativePath } = inLock;
6234
- await fs9.unlink(absolutePath);
6796
+ await fs10.unlink(absolutePath);
6235
6797
  const liveIndex = this._idIndex;
6236
6798
  const id = liveIndex.findByPath(relativePath);
6237
6799
  if (id) {
@@ -6267,6 +6829,10 @@ var init_generate_ai_content = __esm({
6267
6829
  if (currentSlug === safeNewSlug) {
6268
6830
  return { newPath: `${collectionPath}/${currentSlug}` };
6269
6831
  }
6832
+ const routable = parseSlug(safeNewSlug);
6833
+ if (!routable.ok) {
6834
+ 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");
6835
+ }
6270
6836
  const prePass = await this.buildPaths(collection, currentSlug);
6271
6837
  if (!prePass.existed) {
6272
6838
  throw new ContentStoreError(`Entry not found: ${currentSlug}`, "NOT_FOUND");
@@ -6293,7 +6859,7 @@ var init_generate_ai_content = __esm({
6293
6859
  }
6294
6860
  destLockKey = currentDestKey;
6295
6861
  const { absolutePath: currentPath, relativePath: currentRelPath } = inLock;
6296
- const currentFilename = path10.basename(currentPath);
6862
+ const currentFilename = path11.basename(currentPath);
6297
6863
  const parts = currentFilename.split(".");
6298
6864
  if (parts.length < 4) {
6299
6865
  throw new ContentStoreError(`Invalid entry filename format: ${currentFilename}`, "VALIDATION");
@@ -6302,10 +6868,10 @@ var init_generate_ai_content = __esm({
6302
6868
  const contentId = parts[parts.length - 2];
6303
6869
  const ext = `.${parts[parts.length - 1]}`;
6304
6870
  const newFilename = `${entryTypeName}.${safeNewSlug}.${contentId}${ext}`;
6305
- const parentDir = path10.dirname(currentPath);
6306
- const newPath = path10.join(parentDir, newFilename);
6871
+ const parentDir = path11.dirname(currentPath);
6872
+ const newPath = path11.join(parentDir, newFilename);
6307
6873
  try {
6308
- const entries = await fs9.readdir(parentDir, { withFileTypes: true });
6874
+ const entries = await fs10.readdir(parentDir, { withFileTypes: true });
6309
6875
  for (const entry of entries) {
6310
6876
  if (entry.isDirectory())
6311
6877
  continue;
@@ -6318,16 +6884,17 @@ var init_generate_ai_content = __esm({
6318
6884
  if (err instanceof ContentStoreError)
6319
6885
  throw err;
6320
6886
  }
6887
+ await this.assertUrlPathAvailable(parentDir, safeNewSlug);
6321
6888
  try {
6322
- await fs9.link(currentPath, newPath);
6889
+ await fs10.link(currentPath, newPath);
6323
6890
  } catch (err) {
6324
6891
  if (isNodeError3(err) && err.code === "EEXIST") {
6325
6892
  throw new ContentStoreError(`Entry with slug "${safeNewSlug}" already exists in collection "${collectionPath}"`, "VALIDATION");
6326
6893
  }
6327
6894
  throw err;
6328
6895
  }
6329
- await fs9.unlink(currentPath);
6330
- const newRelativePath = path10.relative(this.root, newPath);
6896
+ await fs10.unlink(currentPath);
6897
+ const newRelativePath = path11.relative(this.root, newPath);
6331
6898
  const liveIndex = this._idIndex;
6332
6899
  const entryId = liveIndex.findByPath(currentRelPath);
6333
6900
  if (entryId) {
@@ -6399,34 +6966,57 @@ var init_generate_ai_content = __esm({
6399
6966
  }
6400
6967
  return entries;
6401
6968
  }
6969
+ /**
6970
+ * Resolve every `reference` field in `data` against `fields`, returning a copy.
6971
+ *
6972
+ * This is what `read()` applies automatically (unless `resolveReferences: false`), exposed
6973
+ * so BATCH surfaces can opt into the same resolution without duplicating the walk: the
6974
+ * listing primitives in content-listing.ts and content-tree.ts read entry files straight
6975
+ * off disk and never touch this store, so before this existed a `reference` field reached
6976
+ * `listEntries()`/`buildContentTree()` callers as a bare id string or `null`.
6977
+ *
6978
+ * Pass one {@link ReferenceResolveCache} across a whole batch so a target referenced by
6979
+ * many entries is read once rather than once per referencing entry. Omit `cache` and the
6980
+ * behavior is exactly what `read()` has always done, unmemoized.
6981
+ *
6982
+ * **Path ACLs are not consulted for the targets.** Resolution goes through this store's
6983
+ * own `read()`, below the per-entry permission check in content-reader.ts — so a resolved
6984
+ * target may be an entry the caller could not `read()` directly. That is pre-existing
6985
+ * `read()` behavior, matched here on purpose so one rule covers both; see the
6986
+ * `resolveReferences` option in content-listing.ts for the note adopters see.
6987
+ */
6988
+ async resolveReferences(data, fields, cache) {
6989
+ return this.resolveReferencesInData(data, fields, cache);
6990
+ }
6402
6991
  /**
6403
6992
  * Recursively resolve reference fields in data.
6404
6993
  * This traverses objects, arrays, and blocks to find and resolve all reference fields.
6405
6994
  */
6406
- async resolveReferencesInData(data, fields) {
6995
+ async resolveReferencesInData(data, fields, cache) {
6407
6996
  const resolved = { ...data };
6408
6997
  const idIndex = await this.idIndex();
6409
6998
  for (const field of fields) {
6410
6999
  if (field.type === "group") {
6411
- const groupResolved = await this.resolveReferencesInData(resolved, field.fields);
7000
+ const groupResolved = await this.resolveReferencesInData(resolved, field.fields, cache);
6412
7001
  Object.assign(resolved, groupResolved);
6413
7002
  continue;
6414
7003
  }
6415
7004
  const value = data[field.name];
6416
7005
  if (field.type === "reference") {
7006
+ const includeBody = field.includeBody === true;
6417
7007
  if (typeof value === "string" && value) {
6418
- resolved[field.name] = await this.resolveSingleReference(value, idIndex);
7008
+ resolved[field.name] = await this.resolveSingleReference(value, idIndex, includeBody, cache);
6419
7009
  } else if (field.list && Array.isArray(value)) {
6420
- resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex) : null));
7010
+ resolved[field.name] = await Promise.all(value.map((id) => typeof id === "string" ? this.resolveSingleReference(id, idIndex, includeBody, cache) : null));
6421
7011
  }
6422
7012
  } else if (field.type === "object" && value) {
6423
7013
  const objectField = field;
6424
7014
  if (!objectField.fields)
6425
7015
  continue;
6426
7016
  if (objectField.list && Array.isArray(value)) {
6427
- resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields) : item));
7017
+ resolved[field.name] = await Promise.all(value.map((item) => typeof item === "object" && item !== null ? this.resolveReferencesInData(item, objectField.fields, cache) : item));
6428
7018
  } else if (typeof value === "object") {
6429
- resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields);
7019
+ resolved[field.name] = await this.resolveReferencesInData(value, objectField.fields, cache);
6430
7020
  }
6431
7021
  } else if (field.type === "block" && Array.isArray(value)) {
6432
7022
  const blockField = field;
@@ -6439,7 +7029,7 @@ var init_generate_ai_content = __esm({
6439
7029
  return block;
6440
7030
  return {
6441
7031
  ...b,
6442
- value: await this.resolveReferencesInData(b.value, template.fields)
7032
+ value: await this.resolveReferencesInData(b.value, template.fields, cache)
6443
7033
  };
6444
7034
  }));
6445
7035
  }
@@ -6447,7 +7037,56 @@ var init_generate_ai_content = __esm({
6447
7037
  return resolved;
6448
7038
  }
6449
7039
  /**
6450
- * Resolve a single reference ID to full entry data.
7040
+ * Resolve a single reference ID to full entry data, memoized when a batch cache is
7041
+ * supplied. Without a cache this is a straight pass-through to the uncached path, so
7042
+ * `read()` behaves exactly as it always has.
7043
+ *
7044
+ * Every occurrence gets its OWN deep copy, even on a cache hit. Without that, the memo
7045
+ * would hand one shared object to all 40 entries referencing the same block — a mutation
7046
+ * in one caller's `extract` (truncating a body for a search index, deleting a field) would
7047
+ * silently rewrite it for every sibling, and both `list: true` elements of `[id, id]` would
7048
+ * be the same instance. The copy is what keeps the cache a pure performance optimization
7049
+ * instead of a semantic change.
7050
+ *
7051
+ * Note the uncached path is NOT the clean baseline it looks like. For a json/yaml target it
7052
+ * genuinely reparses fresh per occurrence, but for md/mdx gray-matter serves `data` from a
7053
+ * process-global content-keyed cache, so `resolveSingleReferenceOnce`'s top-level spread
7054
+ * severs exactly one level and NESTED frontmatter objects alias across occurrences, calls and
7055
+ * requests. That is pre-existing `read()` behavior and out of scope here — deliberately, since
7056
+ * touching it would change `read()` — but it means the cached path is the safer of the two,
7057
+ * not a relaxation of a guarantee the uncached one provides. See
7058
+ * `.claude/future-tasks/graymatter-cache-shared-frontmatter.md`.
7059
+ *
7060
+ * What the copy costs, measured rather than assumed (2000 occurrences of one target, local
7061
+ * disk, so every read hits the page cache — the friendliest possible case for NOT caching):
7062
+ * a snippet-sized target is ~63x cheaper to clone than to re-read-and-parse, while a 265KB
7063
+ * JSON target is ~0.8x, i.e. cloning is marginally SLOWER than reparsing it. So the win is
7064
+ * large in the case this exists for and roughly a wash at the pathological end, never a
7065
+ * blow-up. Two things keep the bad end narrow: an md/mdx target resolves to its FRONTMATTER
7066
+ * only *unless the field sets `includeBody`* (`read()` puts the body on `doc.body`, which
7067
+ * `resolveSingleReferenceOnce` spreads in only for an embedding field), so by default body
7068
+ * size is irrelevant no matter how long the document and only a genuinely huge JSON/YAML
7069
+ * target reaches the wash. **`includeBody: true` is the case that CAN reach it on markdown**:
7070
+ * the body then sits inside the memoized object and is cloned once per referencing entry, so
7071
+ * a long document embedded by many pages pays that repeatedly — the reason `includeBody`
7072
+ * exists as an opt-in per field rather than as resolution's default. And in the deployment this
7073
+ * targets, content lives on EFS/NFS where the syscall the memo removes dominates parse and
7074
+ * clone alike, which the local-disk numbers above understate badly. Correctness is the
7075
+ * reason for the copy regardless; the numbers are here so nobody has to re-derive them
7076
+ * before touching this.
7077
+ */
7078
+ resolveSingleReference(id, idIndex, includeBody, cache) {
7079
+ if (!cache)
7080
+ return this.resolveSingleReferenceUncached(id, idIndex, includeBody);
7081
+ const key = includeBody ? `${id}:body` : id;
7082
+ let pending = cache.get(key);
7083
+ if (!pending) {
7084
+ pending = this.resolveSingleReferenceUncached(id, idIndex, includeBody);
7085
+ cache.set(key, pending);
7086
+ }
7087
+ return pending.then((resolved) => resolved === null ? null : structuredClone(resolved));
7088
+ }
7089
+ /**
6451
7090
  * Returns null if the reference is invalid or missing.
6452
7091
  * Includes id, slug, and collection fields for debugging.
6453
7092
  *
@@ -6461,16 +7100,21 @@ var init_generate_ai_content = __esm({
6461
7100
  * idIndex() dedupes concurrent builds — so a sibling call that wins the
6462
7101
  * throttle and rebuilds heals every other miss in the same batch, not just
6463
7102
  * the first.
7103
+ *
7104
+ * A {@link ReferenceResolveCache} sits ABOVE this, never inside it, so every
7105
+ * distinct id still runs the full refresh-and-retry above. What a cache changes
7106
+ * is only that repeats of the SAME id in one batch share that one attempt's
7107
+ * outcome instead of each getting an independent throw of the dice.
6464
7108
  */
6465
- async resolveSingleReference(id, idIndex) {
6466
- const first = await this.resolveSingleReferenceOnce(id, idIndex);
7109
+ async resolveSingleReferenceUncached(id, idIndex, includeBody) {
7110
+ const first = await this.resolveSingleReferenceOnce(id, idIndex, includeBody);
6467
7111
  if (first !== STALE_LOOKUP)
6468
7112
  return first;
6469
7113
  await this.refreshIndexForSuspiciousLookup();
6470
- const second = await this.resolveSingleReferenceOnce(id, await this.idIndex());
7114
+ const second = await this.resolveSingleReferenceOnce(id, await this.idIndex(), includeBody);
6471
7115
  return second === STALE_LOOKUP ? null : second;
6472
7116
  }
6473
- async resolveSingleReferenceOnce(id, idIndex) {
7117
+ async resolveSingleReferenceOnce(id, idIndex, includeBody) {
6474
7118
  try {
6475
7119
  const location = idIndex.findById(id);
6476
7120
  if (!location)
@@ -6481,12 +7125,13 @@ var init_generate_ai_content = __esm({
6481
7125
  const doc = await this.read(location.collection, location.slug, {
6482
7126
  resolveReferences: false
6483
7127
  });
6484
- return {
7128
+ const bodyForEmbed = includeBody && "body" in doc ? { fieldName: doc.bodyFieldName, value: doc.body } : void 0;
7129
+ return buildResolvedReference(doc.data, {
6485
7130
  id,
6486
7131
  slug: location.slug,
6487
7132
  collection: location.collection,
6488
- ...doc.data
6489
- };
7133
+ urlPath: computeEntryUrl(location.collection, location.slug, this.contentRootName)
7134
+ }, bodyForEmbed);
6490
7135
  } catch (error) {
6491
7136
  if (isNodeError3(error) && error.code === "ENOENT")
6492
7137
  return STALE_LOOKUP;
@@ -6511,7 +7156,6 @@ var init_generate_ai_content = __esm({
6511
7156
  "reference",
6512
7157
  "image"
6513
7158
  ]);
6514
- init_normalize2();
6515
7159
  log22 = createDebugLogger2({ prefix: "EntryLinks" });
6516
7160
  BASE58_CHAR = "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]";
6517
7161
  ENTRY_LINK_PATTERN = new RegExp(`entry:(${BASE58_CHAR}{12})(#[^\\s)>"']*)?`, "g");
@@ -6527,10 +7171,10 @@ var init_generate_ai_content = __esm({
6527
7171
  constructor(root) {
6528
7172
  this.regenInFlight = null;
6529
7173
  this.lastForcedRefreshMs = 0;
6530
- this.root = path12.resolve(root);
6531
- this.registryPath = path12.join(this.root, REGISTRY_FILE);
6532
- this.stalePath = path12.join(this.root, REGISTRY_STALE_FILE);
6533
- this.tempPath = path12.join(this.root, REGISTRY_TEMP_FILE);
7174
+ this.root = path13.resolve(root);
7175
+ this.registryPath = path13.join(this.root, REGISTRY_FILE);
7176
+ this.stalePath = path13.join(this.root, REGISTRY_STALE_FILE);
7177
+ this.tempPath = path13.join(this.root, REGISTRY_TEMP_FILE);
6534
7178
  }
6535
7179
  /**
6536
7180
  * Returns all branches. Uses the cached snapshot if its embedded generation
@@ -6539,7 +7183,7 @@ var init_generate_ai_content = __esm({
6539
7183
  async list() {
6540
7184
  let parsed;
6541
7185
  try {
6542
- const raw = await fs11.readFile(this.registryPath, "utf8");
7186
+ const raw = await fs12.readFile(this.registryPath, "utf8");
6543
7187
  parsed = JSON.parse(raw);
6544
7188
  } catch (err) {
6545
7189
  if (isNotFoundError3(err)) {
@@ -6628,7 +7272,7 @@ var init_generate_ai_content = __esm({
6628
7272
  async performRegenerate() {
6629
7273
  const read = await readResourceGeneration(this.root, RESOURCE2);
6630
7274
  const branches = await this.scanBranchDirectories();
6631
- await fs11.unlink(this.stalePath).catch(() => {
7275
+ await fs12.unlink(this.stalePath).catch(() => {
6632
7276
  });
6633
7277
  if (!read.ok) {
6634
7278
  return branches;
@@ -6639,12 +7283,12 @@ var init_generate_ai_content = __esm({
6639
7283
  generation: read.token
6640
7284
  };
6641
7285
  const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
6642
- await fs11.mkdir(this.root, { recursive: true });
6643
- await fs11.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
7286
+ await fs12.mkdir(this.root, { recursive: true });
7287
+ await fs12.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
6644
7288
  try {
6645
- await fs11.rename(uniqueTempPath, this.registryPath);
7289
+ await fs12.rename(uniqueTempPath, this.registryPath);
6646
7290
  } catch (err) {
6647
- await fs11.unlink(uniqueTempPath).catch(() => {
7291
+ await fs12.unlink(uniqueTempPath).catch(() => {
6648
7292
  });
6649
7293
  throw err;
6650
7294
  }
@@ -6658,12 +7302,12 @@ var init_generate_ai_content = __esm({
6658
7302
  async scanBranchDirectories() {
6659
7303
  const branches = [];
6660
7304
  try {
6661
- const entries = await fs11.readdir(this.root, { withFileTypes: true });
7305
+ const entries = await fs12.readdir(this.root, { withFileTypes: true });
6662
7306
  for (const entry of entries) {
6663
7307
  if (!entry.isDirectory() || entry.name.startsWith(".")) {
6664
7308
  continue;
6665
7309
  }
6666
- const branchRoot = path12.join(this.root, entry.name);
7310
+ const branchRoot = path13.join(this.root, entry.name);
6667
7311
  let meta;
6668
7312
  try {
6669
7313
  meta = await BranchMetadataFileManager.loadOnly(branchRoot);
@@ -6714,8 +7358,8 @@ var init_generate_ai_content = __esm({
6714
7358
  };
6715
7359
  BranchMetadataFileManager = class _BranchMetadataFileManager {
6716
7360
  constructor(branchRoot, baseRoot, options) {
6717
- this.branchRoot = path14.resolve(branchRoot);
6718
- this.filePath = path14.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
7361
+ this.branchRoot = path15.resolve(branchRoot);
7362
+ this.filePath = path15.join(this.branchRoot, BRANCH_META_DIR, BRANCH_META_FILE);
6719
7363
  this.baseRoot = baseRoot;
6720
7364
  this.settleMs = options?.settleMs;
6721
7365
  }
@@ -6724,10 +7368,10 @@ var init_generate_ai_content = __esm({
6724
7368
  * Use this for read-only access (e.g., in registry scanning or loadBranchContext).
6725
7369
  */
6726
7370
  static async loadOnly(branchRoot) {
6727
- const resolvedRoot = path14.resolve(branchRoot);
6728
- const filePath = path14.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
7371
+ const resolvedRoot = path15.resolve(branchRoot);
7372
+ const filePath = path15.join(resolvedRoot, BRANCH_META_DIR, BRANCH_META_FILE);
6729
7373
  try {
6730
- const raw = await fs13.readFile(filePath, "utf8");
7374
+ const raw = await fs14.readFile(filePath, "utf8");
6731
7375
  return JSON.parse(raw);
6732
7376
  } catch (err) {
6733
7377
  if (isNotFoundError3(err)) {
@@ -6748,7 +7392,7 @@ var init_generate_ai_content = __esm({
6748
7392
  }
6749
7393
  async load() {
6750
7394
  try {
6751
- const raw = await fs13.readFile(this.filePath, "utf8");
7395
+ const raw = await fs14.readFile(this.filePath, "utf8");
6752
7396
  const parsed = JSON.parse(raw);
6753
7397
  const version = parsed.version ?? 0;
6754
7398
  return { meta: parsed, version };
@@ -6810,7 +7454,7 @@ var init_generate_ai_content = __esm({
6810
7454
  */
6811
7455
  async save(incoming) {
6812
7456
  try {
6813
- await fs13.stat(this.branchRoot);
7457
+ await fs14.stat(this.branchRoot);
6814
7458
  } catch (err) {
6815
7459
  if (isNotFoundError3(err)) {
6816
7460
  throw new BranchMetadataConflictError("Branch no longer exists");
@@ -6923,12 +7567,12 @@ var init_generate_ai_content = __esm({
6923
7567
  };
6924
7568
  GitManager = class _GitManager {
6925
7569
  constructor(options, gitOptions) {
6926
- this.repoPath = path15.resolve(options.repoPath);
7570
+ this.repoPath = path16.resolve(options.repoPath);
6927
7571
  this.baseBranch = options.baseBranch ?? "main";
6928
7572
  this.remote = options.remote ?? "origin";
6929
7573
  this.skipIndexMarker = options.skipIndexMarker ?? false;
6930
7574
  this.git = simpleGit2({ baseDir: this.repoPath, ...gitOptions });
6931
- this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path15.dirname(this.repoPath) }));
7575
+ this.git.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(this.repoPath) }));
6932
7576
  }
6933
7577
  static async cloneRepo(remoteUrl, targetPath, baseBranch = "main") {
6934
7578
  log5.debug("git", "Cloning repository", {
@@ -6970,11 +7614,11 @@ var init_generate_ai_content = __esm({
6970
7614
  remotePath: options.remotePath,
6971
7615
  baseBranch: options.baseBranch
6972
7616
  });
6973
- const remoteParent = path15.dirname(options.remotePath);
7617
+ const remoteParent = path16.dirname(options.remotePath);
6974
7618
  releaseLock = await acquireProvisioningLock(remoteParent, ".remote-init.lock");
6975
7619
  let remoteExists = false;
6976
7620
  try {
6977
- const stat = await fs14.stat(options.remotePath);
7621
+ const stat = await fs15.stat(options.remotePath);
6978
7622
  remoteExists = stat.isDirectory();
6979
7623
  } catch (err) {
6980
7624
  if (!isNotFoundError3(err))
@@ -7226,7 +7870,7 @@ var init_generate_ai_content = __esm({
7226
7870
  */
7227
7871
  static async validateGitRepoExists(repoPath) {
7228
7872
  try {
7229
- const stat = await fs14.stat(path15.join(repoPath, ".git"));
7873
+ const stat = await fs15.stat(path16.join(repoPath, ".git"));
7230
7874
  if (!stat.isDirectory()) {
7231
7875
  throw new Error(`Expected git repo at ${repoPath}`);
7232
7876
  }
@@ -7304,7 +7948,7 @@ var init_generate_ai_content = __esm({
7304
7948
  }
7305
7949
  if (config.autoDetectRemotePath) {
7306
7950
  try {
7307
- const stat = await fs14.stat(config.autoDetectRemotePath);
7951
+ const stat = await fs15.stat(config.autoDetectRemotePath);
7308
7952
  if (stat.isDirectory()) {
7309
7953
  log5.debug("git", "Auto-detected local remote", {
7310
7954
  path: config.autoDetectRemotePath
@@ -7317,8 +7961,8 @@ var init_generate_ai_content = __esm({
7317
7961
  if (config.shouldAutoInitLocal) {
7318
7962
  const gitRoot = await this.findGitRoot();
7319
7963
  const sourceRoot = options.sourceRoot;
7320
- const sourcePath = sourceRoot ? path15.resolve(gitRoot, sourceRoot) : gitRoot;
7321
- const localRemotePath = path15.join(sourcePath, config.defaultRemotePath);
7964
+ const sourcePath = sourceRoot ? path16.resolve(gitRoot, sourceRoot) : gitRoot;
7965
+ const localRemotePath = path16.join(sourcePath, config.defaultRemotePath);
7322
7966
  await this.ensureLocalSimulatedRemote({
7323
7967
  remotePath: localRemotePath,
7324
7968
  sourcePath: gitRoot,
@@ -7346,7 +7990,7 @@ var init_generate_ai_content = __esm({
7346
7990
  static async repoExistsAt(workspacePath) {
7347
7991
  try {
7348
7992
  const checkGit = simpleGit2({ baseDir: workspacePath });
7349
- checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path15.dirname(workspacePath) }));
7993
+ checkGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(workspacePath) }));
7350
7994
  await checkGit.raw(["rev-parse", "--git-dir"]);
7351
7995
  return true;
7352
7996
  } catch {
@@ -7368,19 +8012,19 @@ var init_generate_ai_content = __esm({
7368
8012
  const baseBranch = await resolveBaseBranch({
7369
8013
  defaultBaseBranch: options.baseBranch,
7370
8014
  mode: options.mode,
7371
- detectFrom: options.sourceRoot ? path15.resolve(process.cwd(), options.sourceRoot) : process.cwd()
8015
+ detectFrom: options.sourceRoot ? path16.resolve(process.cwd(), options.sourceRoot) : process.cwd()
7372
8016
  });
7373
8017
  const remoteName = options.remoteName ?? "origin";
7374
8018
  const repoExists = await _GitManager.repoExistsAt(options.workspacePath);
7375
8019
  if (!repoExists) {
7376
- const gitPath = path15.join(options.workspacePath, ".git");
8020
+ const gitPath = path16.join(options.workspacePath, ".git");
7377
8021
  try {
7378
- const stat = await fs14.stat(gitPath);
8022
+ const stat = await fs15.stat(gitPath);
7379
8023
  if (stat.isDirectory()) {
7380
8024
  log5.debug("git", "Removing corrupt .git directory", {
7381
8025
  workspacePath: options.workspacePath
7382
8026
  });
7383
- await fs14.rm(gitPath, { recursive: true });
8027
+ await fs15.rm(gitPath, { recursive: true });
7384
8028
  }
7385
8029
  } catch (cleanupErr) {
7386
8030
  if (!isNotFoundError3(cleanupErr))
@@ -7407,7 +8051,7 @@ var init_generate_ai_content = __esm({
7407
8051
  }
7408
8052
  justCloned = true;
7409
8053
  const freshGit = simpleGit2({ baseDir: options.workspacePath });
7410
- freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path15.dirname(options.workspacePath) }));
8054
+ freshGit.env(gitChildEnv({ GIT_CEILING_DIRECTORIES: path16.dirname(options.workspacePath) }));
7411
8055
  await freshGit.addConfig("canopycms.managed", "true");
7412
8056
  await freshGit.addConfig("user.name", options.gitBotAuthorName);
7413
8057
  await freshGit.addConfig("user.email", options.gitBotAuthorEmail);
@@ -7758,9 +8402,9 @@ var init_generate_ai_content = __esm({
7758
8402
  } catch {
7759
8403
  }
7760
8404
  for (const [filePath, content] of Object.entries(initialFiles)) {
7761
- const absolutePath = path15.join(this.repoPath, filePath);
7762
- await fs14.mkdir(path15.dirname(absolutePath), { recursive: true });
7763
- await fs14.writeFile(absolutePath, content, "utf-8");
8405
+ const absolutePath = path16.join(this.repoPath, filePath);
8406
+ await fs15.mkdir(path16.dirname(absolutePath), { recursive: true });
8407
+ await fs15.writeFile(absolutePath, content, "utf-8");
7764
8408
  await this.git.add(filePath);
7765
8409
  }
7766
8410
  await this.git.commit("Initialize settings branch", ["--allow-empty"]);
@@ -7787,7 +8431,7 @@ var init_generate_ai_content = __esm({
7787
8431
  branchName: options.branchName,
7788
8432
  mode: options.mode
7789
8433
  });
7790
- releaseLock = await acquireProvisioningLock(path16.dirname(options.branchRoot), `.${path16.basename(options.branchRoot)}.init.lock`);
8434
+ releaseLock = await acquireProvisioningLock(path17.dirname(options.branchRoot), `.${path17.basename(options.branchRoot)}.init.lock`);
7791
8435
  await GitManager.initializeWorkspace({
7792
8436
  workspacePath: options.branchRoot,
7793
8437
  branchName: options.branchName,
@@ -7828,7 +8472,7 @@ var init_generate_ai_content = __esm({
7828
8472
  const baseBranch = await resolveBaseBranch({
7829
8473
  defaultBaseBranch: this.config.defaultBaseBranch,
7830
8474
  mode,
7831
- detectFrom: this.config.sourceRoot ? path16.resolve(process.cwd(), this.config.sourceRoot) : void 0
8475
+ detectFrom: this.config.sourceRoot ? path17.resolve(process.cwd(), this.config.sourceRoot) : void 0
7832
8476
  });
7833
8477
  await this.ensureGitWorkspace({
7834
8478
  branchRoot,
@@ -7865,15 +8509,15 @@ var init_generate_ai_content = __esm({
7865
8509
  };
7866
8510
  readEntryData = async (filePath, format, bodyFieldName = "body") => {
7867
8511
  try {
7868
- const raw = await fs15.readFile(filePath, "utf8");
8512
+ const raw = await fs16.readFile(filePath, "utf8");
7869
8513
  if (format === "json") {
7870
8514
  return asRecord(JSON.parse(raw));
7871
8515
  }
7872
8516
  if (format === "yaml") {
7873
8517
  return asRecord(yamlParse2(raw));
7874
8518
  }
7875
- const parsed = matter2(raw);
7876
- const data = parsed.data ?? {};
8519
+ const parsed = matter3(raw);
8520
+ const data = { ...parsed.data ?? {} };
7877
8521
  if (parsed.content) {
7878
8522
  data[bodyFieldName] = parsed.content;
7879
8523
  }
@@ -7885,30 +8529,19 @@ var init_generate_ai_content = __esm({
7885
8529
  return {};
7886
8530
  }
7887
8531
  };
7888
- parseTypedFilename = (filename, entryTypes) => {
7889
- if (filename.startsWith("."))
7890
- return null;
7891
- const lastDot = filename.lastIndexOf(".");
7892
- if (lastDot === -1)
7893
- return null;
7894
- const nameWithoutExt = filename.slice(0, lastDot);
7895
- const parts = nameWithoutExt.split(".");
7896
- if (parts.length < 3)
7897
- return null;
7898
- const potentialType = parts[0];
7899
- if (entryTypes && !entryTypes.some((e) => e.name === potentialType)) {
7900
- return null;
7901
- }
7902
- const id = parts[parts.length - 1];
7903
- if (!isValidId(id))
7904
- return null;
7905
- const slug = parts.slice(1, -1).join(".").toLowerCase();
8532
+ createReferenceResolver = (branchRoot, flatSchema, contentRootName) => ({
8533
+ store: new ContentStore(branchRoot, flatSchema, { contentRootName }),
8534
+ cache: createReferenceResolveCache()
8535
+ });
8536
+ resolveCollectionItemReferences = async (items, collection, resolver) => Promise.all(items.map(async (item) => {
8537
+ const fields = collection.entries?.find((e) => e.name === item.entryType)?.schema;
8538
+ if (!fields)
8539
+ return item;
7906
8540
  return {
7907
- type: potentialType,
7908
- slug,
7909
- id
8541
+ ...item,
8542
+ data: await resolver.store.resolveReferences(item.data, fields, resolver.cache)
7910
8543
  };
7911
- };
8544
+ }));
7912
8545
  looksLikeMalformedEntry = (filename, entryTypes) => {
7913
8546
  if (filename.startsWith(".") || filename.startsWith("_"))
7914
8547
  return false;
@@ -7937,7 +8570,7 @@ var init_generate_ai_content = __esm({
7937
8570
  normalizePath(root, collectionRoot);
7938
8571
  let dirents;
7939
8572
  try {
7940
- dirents = await fs15.readdir(collectionRoot, { withFileTypes: true });
8573
+ dirents = await fs16.readdir(collectionRoot, { withFileTypes: true });
7941
8574
  } catch (err) {
7942
8575
  if (isNotFoundError3(err))
7943
8576
  return [];
@@ -7945,7 +8578,7 @@ var init_generate_ai_content = __esm({
7945
8578
  }
7946
8579
  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));
7947
8580
  const entries = await Promise.all(files.map(async (file) => {
7948
- const absolutePath = path17.join(collectionRoot, file.name);
8581
+ const absolutePath = path18.join(collectionRoot, file.name);
7949
8582
  const relativePath = normalizePath(root, absolutePath);
7950
8583
  const parsed = parseTypedFilename(file.name, entryTypes);
7951
8584
  if (!parsed) {
@@ -7960,7 +8593,7 @@ var init_generate_ai_content = __esm({
7960
8593
  const format = entryType?.format || "json";
7961
8594
  const bodyField = entryType?.schema ? findBodyFieldName(entryType.schema) : "body";
7962
8595
  const [stats, data] = await Promise.all([
7963
- fs15.stat(absolutePath),
8596
+ fs16.stat(absolutePath),
7964
8597
  readEntryData(absolutePath, format, bodyField)
7965
8598
  ]);
7966
8599
  const item = {
@@ -7984,22 +8617,23 @@ var init_generate_ai_content = __esm({
7984
8617
  KNOWN_FIELD_TYPES = new Set(fieldTypes2);
7985
8618
  STRING_FIELD_TYPES = /* @__PURE__ */ new Set(["string", "markdown", "mdx", "code"]);
7986
8619
  selectOptionValues = (field) => (field.options ?? []).map((opt) => typeof opt === "string" ? opt : opt.value);
8620
+ GENERATED_RECORD_FILENAME = ".canopy-generated.json";
7987
8621
  jiti = createJiti2(import.meta.url);
7988
8622
  }
7989
8623
  });
7990
8624
 
7991
8625
  // dist/utils/atomic-write.js
7992
- import fs17 from "node:fs/promises";
7993
- import path20 from "node:path";
8626
+ import fs18 from "node:fs/promises";
8627
+ import path21 from "node:path";
7994
8628
  async function atomicWriteFile3(filePath, content) {
7995
- const dir = path20.dirname(filePath);
7996
- await fs17.mkdir(dir, { recursive: true });
8629
+ const dir = path21.dirname(filePath);
8630
+ await fs18.mkdir(dir, { recursive: true });
7997
8631
  const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
7998
- await fs17.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
8632
+ await fs18.writeFile(tempPath, content, typeof content === "string" ? "utf-8" : void 0);
7999
8633
  try {
8000
- await fs17.rename(tempPath, filePath);
8634
+ await fs18.rename(tempPath, filePath);
8001
8635
  } catch (err) {
8002
- await fs17.unlink(tempPath).catch(() => {
8636
+ await fs18.unlink(tempPath).catch(() => {
8003
8637
  });
8004
8638
  throw err;
8005
8639
  }
@@ -8119,11 +8753,11 @@ var init_debug2 = __esm({
8119
8753
  });
8120
8754
 
8121
8755
  // dist/resource-generation.js
8122
- import fs18 from "node:fs/promises";
8123
- import path21 from "node:path";
8756
+ import fs19 from "node:fs/promises";
8757
+ import path23 from "node:path";
8124
8758
  import { randomUUID as randomUUID3 } from "node:crypto";
8125
8759
  function resourceGenerationPath2(root, resource) {
8126
- return path21.resolve(root, META_DIR3, `${resource}.generation`);
8760
+ return path23.resolve(root, META_DIR3, `${resource}.generation`);
8127
8761
  }
8128
8762
  async function bumpResourceGeneration2(root, resource, options) {
8129
8763
  const token = randomUUID3();
@@ -8141,7 +8775,7 @@ async function bumpResourceGeneration2(root, resource, options) {
8141
8775
  }
8142
8776
  async function readResourceGeneration2(root, resource) {
8143
8777
  try {
8144
- const token = await fs18.readFile(resourceGenerationPath2(root, resource), "utf-8");
8778
+ const token = await fs19.readFile(resourceGenerationPath2(root, resource), "utf-8");
8145
8779
  return { ok: true, token };
8146
8780
  } catch (err) {
8147
8781
  if (isNodeError(err) && err.code === "ENOENT")
@@ -8168,10 +8802,10 @@ var init_resource_generation = __esm({
8168
8802
  });
8169
8803
 
8170
8804
  // dist/content-index-registry.js
8171
- import path23 from "node:path";
8805
+ import path24 from "node:path";
8172
8806
  function invalidateContentIndexesForRoot2(root) {
8173
- const rootKey = path23.resolve(root);
8174
- const prefix = rootKey + path23.sep;
8807
+ const rootKey = path24.resolve(root);
8808
+ const prefix = rootKey + path24.sep;
8175
8809
  for (const [storeRoot, refs] of registry2) {
8176
8810
  if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
8177
8811
  continue;
@@ -8229,7 +8863,7 @@ var init_normalize3 = __esm({
8229
8863
  function isValidContentId2(id) {
8230
8864
  return CONTENT_ID_PATTERN2.test(id);
8231
8865
  }
8232
- function parseSlug(slug) {
8866
+ function parseSlug2(slug) {
8233
8867
  if (!slug) {
8234
8868
  return {
8235
8869
  ok: false,
@@ -8339,7 +8973,7 @@ var init_content_id_index = __esm({
8339
8973
  });
8340
8974
 
8341
8975
  // dist/schema/meta-loader.js
8342
- import { promises as fs19 } from "fs";
8976
+ import { promises as fs20 } from "fs";
8343
8977
  import { join as join4 } from "pathe";
8344
8978
  import { z as z8 } from "zod";
8345
8979
  import chokidar2 from "chokidar";
@@ -8349,7 +8983,7 @@ function stripEmbeddedIdFromName2(name) {
8349
8983
  async function scanForCollectionMeta2(baseDir, relativePath = "") {
8350
8984
  const collections = [];
8351
8985
  try {
8352
- const entries = await fs19.readdir(baseDir, { withFileTypes: true });
8986
+ const entries = await fs20.readdir(baseDir, { withFileTypes: true });
8353
8987
  for (const entry of entries) {
8354
8988
  if (!entry.isDirectory())
8355
8989
  continue;
@@ -8360,8 +8994,8 @@ async function scanForCollectionMeta2(baseDir, relativePath = "") {
8360
8994
  const absolutePath = join4(baseDir, folderName);
8361
8995
  const metaPath = join4(absolutePath, ".collection.json");
8362
8996
  try {
8363
- await fs19.access(metaPath);
8364
- const content = await fs19.readFile(metaPath, "utf-8");
8997
+ await fs20.access(metaPath);
8998
+ const content = await fs20.readFile(metaPath, "utf-8");
8365
8999
  const parsed = JSON.parse(content);
8366
9000
  const meta = collectionMetaSchema2.parse(parsed);
8367
9001
  collections.push({
@@ -8393,7 +9027,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
8393
9027
  let root = null;
8394
9028
  const rootMetaPath = join4(contentRoot, ".collection.json");
8395
9029
  try {
8396
- await fs19.access(rootMetaPath);
9030
+ await fs20.access(rootMetaPath);
8397
9031
  } catch (err) {
8398
9032
  if (err.code === "ENOENT") {
8399
9033
  } else {
@@ -8401,7 +9035,7 @@ async function loadCollectionMetaFiles2(contentRoot) {
8401
9035
  }
8402
9036
  }
8403
9037
  try {
8404
- const content = await fs19.readFile(rootMetaPath, "utf-8");
9038
+ const content = await fs20.readFile(rootMetaPath, "utf-8");
8405
9039
  const parsed = JSON.parse(content);
8406
9040
  root = rootCollectionMetaSchema2.parse(parsed);
8407
9041
  } catch (err) {
@@ -8548,7 +9182,12 @@ var init_field3 = __esm({
8548
9182
  collections: z9.array(z9.string().min(1)).min(1).optional(),
8549
9183
  entryTypes: z9.array(z9.string().min(1)).min(1).optional(),
8550
9184
  displayField: z9.string().min(1).optional(),
8551
- options: z9.array(referenceOptionSchema3).optional()
9185
+ options: z9.array(referenceOptionSchema3).optional(),
9186
+ // Must be listed here, not just on ReferenceFieldConfig: zod strips unknown keys by
9187
+ // default, so a consumer that adopts this schema's parse output would silently delete a
9188
+ // runtime-consumed flag and the feature would no-op with no error. (`resolvedSchema` is
9189
+ // absent on purpose — it is type-inference-only and stripping it changes no behavior.)
9190
+ includeBody: z9.boolean().optional()
8552
9191
  });
8553
9192
  fieldHolder3 = [z9.never()];
8554
9193
  blockSchema3 = z9.object({
@@ -8658,7 +9297,7 @@ var init_media3 = __esm({
8658
9297
 
8659
9298
  // dist/config/schemas/config.js
8660
9299
  import { z as z12 } from "zod";
8661
- var defaultBranchAccessSchema3, defaultPathAccessLevelSchema3, defaultPathAccessLevelsSchema3, defaultPathAccessSchema3, defaultBaseBranchSchema3, defaultRemoteNameSchema3, defaultRemoteUrlSchema3, gitBotAuthorNameSchema3, gitBotAuthorEmailSchema3, githubTokenEnvVarSchema3, operatingModeSchema3, deployedAsSchema3, contentRootSchema3, sourceRootSchema3, deploymentNameSchema3, devContentSyncSchema3, devConfigSchema3, editorConfigSchema3, CanopyConfigSchema3, DEFAULT_PROD_WORKSPACE3;
9300
+ var defaultBranchAccessSchema3, defaultPathAccessLevelSchema3, defaultPathAccessLevelsSchema3, defaultPathAccessSchema3, defaultBaseBranchSchema3, defaultRemoteNameSchema3, defaultRemoteUrlSchema3, gitBotAuthorNameSchema3, gitBotAuthorEmailSchema3, githubTokenEnvVarSchema3, operatingModeSchema3, deployedAsSchema3, contentRootSchema3, sourceRootSchema3, basePathSchema3, deploymentNameSchema3, devContentSyncSchema3, devConfigSchema3, editorConfigSchema3, CanopyConfigSchema3, DEFAULT_PROD_WORKSPACE3;
8662
9301
  var init_config4 = __esm({
8663
9302
  "dist/config/schemas/config.js"() {
8664
9303
  "use strict";
@@ -8682,6 +9321,9 @@ var init_config4 = __esm({
8682
9321
  deployedAsSchema3 = z12.enum(["static", "server"]).default("server");
8683
9322
  contentRootSchema3 = relativePathSchema3.default("content");
8684
9323
  sourceRootSchema3 = z12.string().min(1).optional();
9324
+ basePathSchema3 = z12.string().transform((value) => value.trim()).refine((value) => value.length > 0, {
9325
+ message: "basePath must not be empty or only whitespace"
9326
+ }).optional();
8685
9327
  deploymentNameSchema3 = z12.string().default("prod");
8686
9328
  devContentSyncSchema3 = z12.enum(["off", "warn"]).default("warn");
8687
9329
  devConfigSchema3 = z12.object({
@@ -8744,6 +9386,7 @@ var init_config4 = __esm({
8744
9386
  deploymentName: deploymentNameSchema3.optional(),
8745
9387
  contentRoot: contentRootSchema3.default("content"),
8746
9388
  sourceRoot: sourceRootSchema3.optional(),
9389
+ basePath: basePathSchema3,
8747
9390
  editor: editorConfigSchema3.optional(),
8748
9391
  authPlugin: z12.custom().optional(),
8749
9392
  entryLinkUrl: z12.custom().optional(),
@@ -8830,13 +9473,13 @@ var init_content_index_generation = __esm({
8830
9473
  });
8831
9474
 
8832
9475
  // dist/sync-core.js
8833
- import fs20 from "node:fs/promises";
8834
- import path24 from "node:path";
9476
+ import fs21 from "node:fs/promises";
9477
+ import path25 from "node:path";
8835
9478
  import { simpleGit as simpleGit4 } from "simple-git";
8836
9479
  function assertWithinDir(resolved, parent, label) {
8837
- const normalizedResolved = path24.resolve(resolved);
8838
- const normalizedParent = path24.resolve(parent);
8839
- if (!normalizedResolved.startsWith(normalizedParent + path24.sep) && normalizedResolved !== normalizedParent) {
9480
+ const normalizedResolved = path25.resolve(resolved);
9481
+ const normalizedParent = path25.resolve(parent);
9482
+ if (!normalizedResolved.startsWith(normalizedParent + path25.sep) && normalizedResolved !== normalizedParent) {
8840
9483
  throw new Error(`${label} escapes the expected directory: ${resolved}`);
8841
9484
  }
8842
9485
  }
@@ -8844,19 +9487,19 @@ async function safeReplaceDir(oldDir, newDir) {
8844
9487
  const backupDir = `${oldDir}.sync-backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
8845
9488
  const oldExists = await filePathExists(oldDir);
8846
9489
  if (oldExists) {
8847
- await fs20.rename(oldDir, backupDir);
9490
+ await fs21.rename(oldDir, backupDir);
8848
9491
  }
8849
9492
  try {
8850
- await fs20.rename(newDir, oldDir);
9493
+ await fs21.rename(newDir, oldDir);
8851
9494
  } catch (err) {
8852
9495
  if (oldExists) {
8853
- await fs20.rename(backupDir, oldDir).catch(() => {
9496
+ await fs21.rename(backupDir, oldDir).catch(() => {
8854
9497
  });
8855
9498
  }
8856
9499
  throw err;
8857
9500
  }
8858
9501
  if (oldExists) {
8859
- await fs20.rm(backupDir, { recursive: true, force: true }).catch(() => {
9502
+ await fs21.rm(backupDir, { recursive: true, force: true }).catch(() => {
8860
9503
  });
8861
9504
  }
8862
9505
  }
@@ -8864,7 +9507,7 @@ async function listFilesRecursive(dir, prefix = "") {
8864
9507
  const results = [];
8865
9508
  let entries;
8866
9509
  try {
8867
- entries = await fs20.readdir(dir, { withFileTypes: true });
9510
+ entries = await fs21.readdir(dir, { withFileTypes: true });
8868
9511
  } catch {
8869
9512
  return results;
8870
9513
  }
@@ -8875,7 +9518,7 @@ async function listFilesRecursive(dir, prefix = "") {
8875
9518
  continue;
8876
9519
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
8877
9520
  if (entry.isDirectory()) {
8878
- results.push(...await listFilesRecursive(path24.join(dir, entry.name), rel));
9521
+ results.push(...await listFilesRecursive(path25.join(dir, entry.name), rel));
8879
9522
  } else {
8880
9523
  results.push(rel);
8881
9524
  }
@@ -8883,19 +9526,19 @@ async function listFilesRecursive(dir, prefix = "") {
8883
9526
  return results;
8884
9527
  }
8885
9528
  async function copyDir(src, dest) {
8886
- await fs20.mkdir(dest, { recursive: true });
8887
- const entries = await fs20.readdir(src, { withFileTypes: true });
9529
+ await fs21.mkdir(dest, { recursive: true });
9530
+ const entries = await fs21.readdir(src, { withFileTypes: true });
8888
9531
  for (const entry of entries) {
8889
9532
  if (entry.name === ".git")
8890
9533
  continue;
8891
9534
  if (entry.isSymbolicLink())
8892
9535
  continue;
8893
- const srcPath = path24.join(src, entry.name);
8894
- const destPath = path24.join(dest, entry.name);
9536
+ const srcPath = path25.join(src, entry.name);
9537
+ const destPath = path25.join(dest, entry.name);
8895
9538
  if (entry.isDirectory()) {
8896
9539
  await copyDir(srcPath, destPath);
8897
9540
  } else {
8898
- await fs20.copyFile(srcPath, destPath);
9541
+ await fs21.copyFile(srcPath, destPath);
8899
9542
  }
8900
9543
  }
8901
9544
  }
@@ -8904,14 +9547,14 @@ async function pushContentToWorkspace(options) {
8904
9547
  if (!await filePathExists(srcContentDir)) {
8905
9548
  return { fileCount: 0 };
8906
9549
  }
8907
- const wsContentDir = path24.join(branchPath, contentRoot);
9550
+ const wsContentDir = path25.join(branchPath, contentRoot);
8908
9551
  assertWithinDir(wsContentDir, branchPath, "content-root");
8909
9552
  const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
8910
9553
  try {
8911
9554
  await copyDir(srcContentDir, tmpDir);
8912
9555
  await safeReplaceDir(wsContentDir, tmpDir);
8913
9556
  } catch (err) {
8914
- await fs20.rm(tmpDir, { recursive: true, force: true }).catch(() => {
9557
+ await fs21.rm(tmpDir, { recursive: true, force: true }).catch(() => {
8915
9558
  });
8916
9559
  throw err;
8917
9560
  }
@@ -8955,19 +9598,21 @@ import lockfile3 from "proper-lockfile";
8955
9598
  var init_provisioning_lock = __esm({
8956
9599
  "dist/utils/provisioning-lock.js"() {
8957
9600
  "use strict";
9601
+ init_error();
9602
+ init_logger3();
8958
9603
  }
8959
9604
  });
8960
9605
 
8961
9606
  // dist/git-manager.js
8962
- import fs21 from "node:fs/promises";
8963
- import path25 from "node:path";
9607
+ import fs24 from "node:fs/promises";
9608
+ import path26 from "node:path";
8964
9609
  import { simpleGit as simpleGit6 } from "simple-git";
8965
9610
  async function ensureGitExcludePattern2(repoPath, pattern) {
8966
- const excludePath = path25.join(repoPath, ".git", "info", "exclude");
8967
- await fs21.mkdir(path25.dirname(excludePath), { recursive: true });
9611
+ const excludePath = path26.join(repoPath, ".git", "info", "exclude");
9612
+ await fs24.mkdir(path26.dirname(excludePath), { recursive: true });
8968
9613
  let content = "";
8969
9614
  try {
8970
- content = await fs21.readFile(excludePath, "utf-8");
9615
+ content = await fs24.readFile(excludePath, "utf-8");
8971
9616
  } catch (err) {
8972
9617
  if (!isNotFoundError(err))
8973
9618
  throw err;
@@ -8979,7 +9624,7 @@ async function ensureGitExcludePattern2(repoPath, pattern) {
8979
9624
  }
8980
9625
  const needsLeadingNewline = content.length > 0 && !content.endsWith("\n");
8981
9626
  const newContent = content + (needsLeadingNewline ? "\n" : "") + pattern + "\n";
8982
- await fs21.writeFile(excludePath, newContent, "utf-8");
9627
+ await fs24.writeFile(excludePath, newContent, "utf-8");
8983
9628
  log9.debug("git", "Added pattern to .git/info/exclude", { pattern });
8984
9629
  }
8985
9630
  var log9;
@@ -9136,7 +9781,7 @@ var init_config5 = __esm({
9136
9781
  });
9137
9782
 
9138
9783
  // dist/operating-mode/client-unsafe-strategy.js
9139
- import path26 from "node:path";
9784
+ import path27 from "node:path";
9140
9785
  function operatingStrategy3(mode) {
9141
9786
  const cached = strategyCache3.get(mode);
9142
9787
  if (cached)
@@ -9171,32 +9816,32 @@ var init_client_unsafe_strategy2 = __esm({
9171
9816
  // - shouldCommit(), shouldPush()
9172
9817
  // Add client-unsafe methods (use Node.js APIs)
9173
9818
  getWorkspaceRoot(_sourceRoot) {
9174
- return path26.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE3);
9819
+ return path27.resolve(process.env.CANOPYCMS_WORKSPACE_ROOT ?? DEFAULT_PROD_WORKSPACE3);
9175
9820
  }
9176
9821
  getContentRoot(contentRoot, sourceRoot) {
9177
- return path26.resolve(sourceRoot ?? process.cwd(), contentRoot);
9822
+ return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
9178
9823
  }
9179
9824
  getContentBranchesRoot(sourceRoot) {
9180
- return path26.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
9825
+ return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
9181
9826
  }
9182
9827
  getContentBranchRoot(branchName, sourceRoot) {
9183
- return path26.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
9828
+ return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
9184
9829
  }
9185
9830
  getGitExcludePattern() {
9186
9831
  return ".canopy-meta/";
9187
9832
  }
9188
9833
  getPermissionsFilePath(root) {
9189
- return path26.join(root, this.getPermissionsFileName());
9834
+ return path27.join(root, this.getPermissionsFileName());
9190
9835
  }
9191
9836
  getGroupsFilePath(root) {
9192
- return path26.join(root, this.getGroupsFileName());
9837
+ return path27.join(root, this.getGroupsFileName());
9193
9838
  }
9194
9839
  getRemoteUrlConfig() {
9195
9840
  return {
9196
9841
  shouldAutoInitLocal: false,
9197
9842
  defaultRemotePath: "",
9198
9843
  envVarName: "CANOPYCMS_REMOTE_URL",
9199
- autoDetectRemotePath: path26.join(this.getWorkspaceRoot(), "remote.git")
9844
+ autoDetectRemotePath: path27.join(this.getWorkspaceRoot(), "remote.git")
9200
9845
  };
9201
9846
  }
9202
9847
  requiresExistingRepo() {
@@ -9208,7 +9853,7 @@ var init_client_unsafe_strategy2 = __esm({
9208
9853
  return `canopycms-settings-${resolveDeploymentName3(config, "prod")}`;
9209
9854
  }
9210
9855
  getSettingsRoot(sourceRoot) {
9211
- return path26.join(this.getWorkspaceRoot(sourceRoot), "settings");
9856
+ return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
9212
9857
  }
9213
9858
  usesSeparateSettingsBranch() {
9214
9859
  return true;
@@ -9225,25 +9870,25 @@ var init_client_unsafe_strategy2 = __esm({
9225
9870
  DevStrategy3 = class extends DevClientSafeStrategy3 {
9226
9871
  // Inherits client-safe methods from DevClientSafeStrategy
9227
9872
  getWorkspaceRoot(sourceRoot) {
9228
- return path26.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
9873
+ return path27.resolve(sourceRoot ?? process.cwd(), ".canopy-dev");
9229
9874
  }
9230
9875
  getContentRoot(contentRoot, sourceRoot) {
9231
- return path26.resolve(sourceRoot ?? process.cwd(), contentRoot);
9876
+ return path27.resolve(sourceRoot ?? process.cwd(), contentRoot);
9232
9877
  }
9233
9878
  getContentBranchesRoot(sourceRoot) {
9234
- return path26.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
9879
+ return path27.join(this.getWorkspaceRoot(sourceRoot), "content-branches");
9235
9880
  }
9236
9881
  getContentBranchRoot(branchName, sourceRoot) {
9237
- return path26.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
9882
+ return path27.resolve(this.getContentBranchesRoot(sourceRoot), branchName);
9238
9883
  }
9239
9884
  getGitExcludePattern() {
9240
9885
  return ".canopy-meta/";
9241
9886
  }
9242
9887
  getPermissionsFilePath(root) {
9243
- return path26.join(root, this.getPermissionsFileName());
9888
+ return path27.join(root, this.getPermissionsFileName());
9244
9889
  }
9245
9890
  getGroupsFilePath(root) {
9246
- return path26.join(root, this.getGroupsFileName());
9891
+ return path27.join(root, this.getGroupsFileName());
9247
9892
  }
9248
9893
  getRemoteUrlConfig() {
9249
9894
  return {
@@ -9261,7 +9906,7 @@ var init_client_unsafe_strategy2 = __esm({
9261
9906
  return `canopycms-settings-${resolveDeploymentName3(config, "local")}`;
9262
9907
  }
9263
9908
  getSettingsRoot(sourceRoot) {
9264
- return path26.join(this.getWorkspaceRoot(sourceRoot), "settings");
9909
+ return path27.join(this.getWorkspaceRoot(sourceRoot), "settings");
9265
9910
  }
9266
9911
  usesSeparateSettingsBranch() {
9267
9912
  return true;
@@ -9293,8 +9938,8 @@ __export(sync_exports, {
9293
9938
  SyncError: () => SyncError,
9294
9939
  sync: () => sync
9295
9940
  });
9296
- import fs24 from "node:fs/promises";
9297
- import path27 from "node:path";
9941
+ import fs25 from "node:fs/promises";
9942
+ import path28 from "node:path";
9298
9943
  import { simpleGit as simpleGit7 } from "simple-git";
9299
9944
  import * as p2 from "@clack/prompts";
9300
9945
  async function detectCurrentBranch(projectDir) {
@@ -9307,7 +9952,7 @@ async function detectCurrentBranch(projectDir) {
9307
9952
  async function selectBranch(options, branchesDir) {
9308
9953
  let branches = [];
9309
9954
  if (await filePathExists(branchesDir)) {
9310
- const entries = await fs24.readdir(branchesDir, { withFileTypes: true });
9955
+ const entries = await fs25.readdir(branchesDir, { withFileTypes: true });
9311
9956
  branches = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
9312
9957
  }
9313
9958
  let branchName = options.branch;
@@ -9335,11 +9980,11 @@ async function selectBranch(options, branchesDir) {
9335
9980
  branchName = result;
9336
9981
  }
9337
9982
  }
9338
- const branchPath = path27.join(branchesDir, branchName);
9983
+ const branchPath = path28.join(branchesDir, branchName);
9339
9984
  assertWithinDir(branchPath, branchesDir, "--branch");
9340
9985
  if (!branches.includes(branchName)) {
9341
9986
  if (options.autoCreate) {
9342
- await fs24.mkdir(branchPath, { recursive: true });
9987
+ await fs25.mkdir(branchPath, { recursive: true });
9343
9988
  const wsGit = simpleGit7({ baseDir: branchPath });
9344
9989
  await wsGit.init();
9345
9990
  await wsGit.checkoutLocalBranch(branchName);
@@ -9356,8 +10001,8 @@ async function selectBranch(options, branchesDir) {
9356
10001
  async function syncPush(options) {
9357
10002
  const { projectDir } = options;
9358
10003
  const contentRoot = options.contentRoot || "content";
9359
- const branchesDir = path27.join(projectDir, ".canopy-dev", "content-branches");
9360
- const srcContentDir = path27.join(projectDir, contentRoot);
10004
+ const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
10005
+ const srcContentDir = path28.join(projectDir, contentRoot);
9361
10006
  assertWithinDir(srcContentDir, projectDir, "--content-root");
9362
10007
  if (!await filePathExists(srcContentDir)) {
9363
10008
  throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
@@ -9365,7 +10010,7 @@ async function syncPush(options) {
9365
10010
  const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
9366
10011
  if (!branchName)
9367
10012
  return { fileCount: 0 };
9368
- const branchPath = path27.join(branchesDir, branchName);
10013
+ const branchPath = path28.join(branchesDir, branchName);
9369
10014
  assertWithinDir(branchPath, branchesDir, "--branch");
9370
10015
  const wsGit = simpleGit7({ baseDir: branchPath });
9371
10016
  const status = await wsGit.status();
@@ -9423,19 +10068,19 @@ async function syncPush(options) {
9423
10068
  async function syncPull(options) {
9424
10069
  const { projectDir } = options;
9425
10070
  const contentRoot = options.contentRoot || "content";
9426
- const branchesDir = path27.join(projectDir, ".canopy-dev", "content-branches");
10071
+ const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
9427
10072
  const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
9428
10073
  if (!branchName)
9429
10074
  return { fileCount: 0 };
9430
- const branchPath = path27.join(branchesDir, branchName);
10075
+ const branchPath = path28.join(branchesDir, branchName);
9431
10076
  assertWithinDir(branchPath, branchesDir, "--branch");
9432
- const branchContentDir = path27.join(branchPath, contentRoot);
10077
+ const branchContentDir = path28.join(branchPath, contentRoot);
9433
10078
  assertWithinDir(branchContentDir, branchPath, "--content-root");
9434
10079
  if (!await filePathExists(branchContentDir)) {
9435
10080
  throw new SyncError(`Content directory not found in branch workspace: ${branchName}/${contentRoot}`);
9436
10081
  }
9437
10082
  p2.log.step(`Pulling content from branch: ${branchName}`);
9438
- const destContentDir = path27.join(projectDir, contentRoot);
10083
+ const destContentDir = path28.join(projectDir, contentRoot);
9439
10084
  assertWithinDir(destContentDir, projectDir, "--content-root");
9440
10085
  const sourceGit = simpleGit7({ baseDir: projectDir });
9441
10086
  const status = await sourceGit.status();
@@ -9487,7 +10132,7 @@ async function syncPull(options) {
9487
10132
  await copyDir(branchContentDir, tmpDestDir);
9488
10133
  await safeReplaceDir(destContentDir, tmpDestDir);
9489
10134
  } catch (err) {
9490
- await fs24.rm(tmpDestDir, { recursive: true, force: true }).catch(() => {
10135
+ await fs25.rm(tmpDestDir, { recursive: true, force: true }).catch(() => {
9491
10136
  });
9492
10137
  throw err;
9493
10138
  }
@@ -9511,8 +10156,8 @@ async function syncPull(options) {
9511
10156
  async function syncBoth(options) {
9512
10157
  const { projectDir } = options;
9513
10158
  const contentRoot = options.contentRoot || "content";
9514
- const branchesDir = path27.join(projectDir, ".canopy-dev", "content-branches");
9515
- const srcContentDir = path27.join(projectDir, contentRoot);
10159
+ const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
10160
+ const srcContentDir = path28.join(projectDir, contentRoot);
9516
10161
  assertWithinDir(srcContentDir, projectDir, "--content-root");
9517
10162
  if (!await filePathExists(srcContentDir)) {
9518
10163
  throw new SyncError(`Content directory not found: ${contentRoot}/ (expected at ${srcContentDir})`);
@@ -9520,7 +10165,7 @@ async function syncBoth(options) {
9520
10165
  const branchName = await selectBranch({ ...options, projectDir, autoCreate: true }, branchesDir);
9521
10166
  if (!branchName)
9522
10167
  return { pushed: 0, pulled: 0 };
9523
- const branchPath = path27.join(branchesDir, branchName);
10168
+ const branchPath = path28.join(branchesDir, branchName);
9524
10169
  assertWithinDir(branchPath, branchesDir, "--branch");
9525
10170
  const wsGit = simpleGit7({ baseDir: branchPath });
9526
10171
  const status = await wsGit.status();
@@ -9555,14 +10200,14 @@ async function syncBoth(options) {
9555
10200
  try {
9556
10201
  const incomingBranch = `sync-incoming-${Date.now()}`;
9557
10202
  await wsGit.raw(["checkout", "-b", incomingBranch, baseRef]);
9558
- const wsContentDir = path27.join(branchPath, contentRoot);
10203
+ const wsContentDir = path28.join(branchPath, contentRoot);
9559
10204
  assertWithinDir(wsContentDir, branchPath, "--content-root");
9560
10205
  const tmpDir = `${wsContentDir}.sync-tmp-${Date.now()}`;
9561
10206
  try {
9562
10207
  await copyDir(srcContentDir, tmpDir);
9563
10208
  await safeReplaceDir(wsContentDir, tmpDir);
9564
10209
  } catch (err) {
9565
- await fs24.rm(tmpDir, { recursive: true, force: true }).catch(() => {
10210
+ await fs25.rm(tmpDir, { recursive: true, force: true }).catch(() => {
9566
10211
  });
9567
10212
  await wsGit.checkout(currentBranch);
9568
10213
  await wsGit.raw(["branch", "-D", incomingBranch]).catch(() => {
@@ -9619,11 +10264,11 @@ async function syncBoth(options) {
9619
10264
  }
9620
10265
  async function syncAbort(options) {
9621
10266
  const { projectDir } = options;
9622
- const branchesDir = path27.join(projectDir, ".canopy-dev", "content-branches");
10267
+ const branchesDir = path28.join(projectDir, ".canopy-dev", "content-branches");
9623
10268
  const branchName = await selectBranch({ ...options, projectDir }, branchesDir);
9624
10269
  if (!branchName)
9625
10270
  return;
9626
- const branchPath = path27.join(branchesDir, branchName);
10271
+ const branchPath = path28.join(branchesDir, branchName);
9627
10272
  assertWithinDir(branchPath, branchesDir, "--branch");
9628
10273
  const wsGit = simpleGit7({ baseDir: branchPath });
9629
10274
  const status = await wsGit.status();
@@ -9751,8 +10396,8 @@ var init_async_mutex = __esm({
9751
10396
  });
9752
10397
 
9753
10398
  // dist/utils/occ-json-write.js
9754
- import fs25 from "node:fs/promises";
9755
- import path28 from "node:path";
10399
+ import fs26 from "node:fs/promises";
10400
+ import path29 from "node:path";
9756
10401
  import { randomUUID as randomUUID4 } from "node:crypto";
9757
10402
  import lockfile4 from "proper-lockfile";
9758
10403
  async function writeOccJsonFile2(filePath, payload, options) {
@@ -9761,29 +10406,29 @@ async function writeOccJsonFile2(filePath, payload, options) {
9761
10406
  const writeId = randomUUID4();
9762
10407
  const data = { ...payload, version: newVersion, writeId };
9763
10408
  const content = JSON.stringify(data, null, 2) + (trailingNewline ? "\n" : "");
9764
- const dir = path28.dirname(filePath);
9765
- await fs25.mkdir(dir, { recursive: true });
10409
+ const dir = path29.dirname(filePath);
10410
+ await fs26.mkdir(dir, { recursive: true });
9766
10411
  const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
9767
- await fs25.writeFile(tempPath, content, "utf-8");
10412
+ await fs26.writeFile(tempPath, content, "utf-8");
9768
10413
  if (expectedVersion === null) {
9769
10414
  try {
9770
- await fs25.link(tempPath, filePath);
10415
+ await fs26.link(tempPath, filePath);
9771
10416
  } catch (err) {
9772
- await fs25.unlink(tempPath).catch(() => {
10417
+ await fs26.unlink(tempPath).catch(() => {
9773
10418
  });
9774
10419
  if (isFileExistsError(err)) {
9775
10420
  throw new OccWriteConflictError2();
9776
10421
  }
9777
10422
  throw err;
9778
10423
  }
9779
- await fs25.unlink(tempPath).catch(() => {
10424
+ await fs26.unlink(tempPath).catch(() => {
9780
10425
  });
9781
10426
  return { version: newVersion, writeId };
9782
10427
  }
9783
10428
  try {
9784
10429
  let currentVersion = null;
9785
10430
  try {
9786
- const current = JSON.parse(await fs25.readFile(filePath, "utf-8"));
10431
+ const current = JSON.parse(await fs26.readFile(filePath, "utf-8"));
9787
10432
  currentVersion = current.version ?? 0;
9788
10433
  } catch {
9789
10434
  currentVersion = null;
@@ -9791,16 +10436,16 @@ async function writeOccJsonFile2(filePath, payload, options) {
9791
10436
  if (currentVersion !== expectedVersion) {
9792
10437
  throw new OccWriteConflictError2();
9793
10438
  }
9794
- await fs25.rename(tempPath, filePath);
10439
+ await fs26.rename(tempPath, filePath);
9795
10440
  if (settleMs > 0) {
9796
10441
  await new Promise((resolve2) => setTimeout(resolve2, settleMs));
9797
10442
  }
9798
- const afterWrite = JSON.parse(await fs25.readFile(filePath, "utf-8"));
10443
+ const afterWrite = JSON.parse(await fs26.readFile(filePath, "utf-8"));
9799
10444
  if (afterWrite.writeId !== writeId) {
9800
10445
  throw new OccWriteConflictError2();
9801
10446
  }
9802
10447
  } catch (err) {
9803
- await fs25.unlink(tempPath).catch(() => {
10448
+ await fs26.unlink(tempPath).catch(() => {
9804
10449
  });
9805
10450
  throw err;
9806
10451
  }
@@ -9826,8 +10471,8 @@ async function withOccRetry2(operation, options) {
9826
10471
  throw new Error("Unreachable");
9827
10472
  }
9828
10473
  async function withOccFileLock2(filePath, fn) {
9829
- const dir = path28.dirname(filePath);
9830
- await fs25.mkdir(dir, { recursive: true });
10474
+ const dir = path29.dirname(filePath);
10475
+ await fs26.mkdir(dir, { recursive: true });
9831
10476
  const MAX_ATTEMPTS = 14;
9832
10477
  let release = null;
9833
10478
  for (let attempt = 1; release === null; attempt++) {
@@ -9886,8 +10531,8 @@ var init_occ_json_write = __esm({
9886
10531
  });
9887
10532
 
9888
10533
  // dist/branch-registry.js
9889
- import fs26 from "node:fs/promises";
9890
- import path29 from "node:path";
10534
+ import fs27 from "node:fs/promises";
10535
+ import path30 from "node:path";
9891
10536
  var log12, REGISTRY_FILE2, REGISTRY_STALE_FILE2, REGISTRY_TEMP_FILE2, REGISTRY_VERSION2, RESOURCE4, GET_MISS_REFRESH_MIN_INTERVAL_MS2, BranchRegistry2;
9892
10537
  var init_branch_registry = __esm({
9893
10538
  "dist/branch-registry.js"() {
@@ -9908,10 +10553,10 @@ var init_branch_registry = __esm({
9908
10553
  constructor(root) {
9909
10554
  this.regenInFlight = null;
9910
10555
  this.lastForcedRefreshMs = 0;
9911
- this.root = path29.resolve(root);
9912
- this.registryPath = path29.join(this.root, REGISTRY_FILE2);
9913
- this.stalePath = path29.join(this.root, REGISTRY_STALE_FILE2);
9914
- this.tempPath = path29.join(this.root, REGISTRY_TEMP_FILE2);
10556
+ this.root = path30.resolve(root);
10557
+ this.registryPath = path30.join(this.root, REGISTRY_FILE2);
10558
+ this.stalePath = path30.join(this.root, REGISTRY_STALE_FILE2);
10559
+ this.tempPath = path30.join(this.root, REGISTRY_TEMP_FILE2);
9915
10560
  }
9916
10561
  /**
9917
10562
  * Returns all branches. Uses the cached snapshot if its embedded generation
@@ -9920,7 +10565,7 @@ var init_branch_registry = __esm({
9920
10565
  async list() {
9921
10566
  let parsed;
9922
10567
  try {
9923
- const raw = await fs26.readFile(this.registryPath, "utf8");
10568
+ const raw = await fs27.readFile(this.registryPath, "utf8");
9924
10569
  parsed = JSON.parse(raw);
9925
10570
  } catch (err) {
9926
10571
  if (isNotFoundError(err)) {
@@ -10009,7 +10654,7 @@ var init_branch_registry = __esm({
10009
10654
  async performRegenerate() {
10010
10655
  const read = await readResourceGeneration2(this.root, RESOURCE4);
10011
10656
  const branches = await this.scanBranchDirectories();
10012
- await fs26.unlink(this.stalePath).catch(() => {
10657
+ await fs27.unlink(this.stalePath).catch(() => {
10013
10658
  });
10014
10659
  if (!read.ok) {
10015
10660
  return branches;
@@ -10020,12 +10665,12 @@ var init_branch_registry = __esm({
10020
10665
  generation: read.token
10021
10666
  };
10022
10667
  const uniqueTempPath = `${this.tempPath}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
10023
- await fs26.mkdir(this.root, { recursive: true });
10024
- await fs26.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
10668
+ await fs27.mkdir(this.root, { recursive: true });
10669
+ await fs27.writeFile(uniqueTempPath, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
10025
10670
  try {
10026
- await fs26.rename(uniqueTempPath, this.registryPath);
10671
+ await fs27.rename(uniqueTempPath, this.registryPath);
10027
10672
  } catch (err) {
10028
- await fs26.unlink(uniqueTempPath).catch(() => {
10673
+ await fs27.unlink(uniqueTempPath).catch(() => {
10029
10674
  });
10030
10675
  throw err;
10031
10676
  }
@@ -10039,12 +10684,12 @@ var init_branch_registry = __esm({
10039
10684
  async scanBranchDirectories() {
10040
10685
  const branches = [];
10041
10686
  try {
10042
- const entries = await fs26.readdir(this.root, { withFileTypes: true });
10687
+ const entries = await fs27.readdir(this.root, { withFileTypes: true });
10043
10688
  for (const entry of entries) {
10044
10689
  if (!entry.isDirectory() || entry.name.startsWith(".")) {
10045
10690
  continue;
10046
10691
  }
10047
- const branchRoot = path29.join(this.root, entry.name);
10692
+ const branchRoot = path30.join(this.root, entry.name);
10048
10693
  let meta;
10049
10694
  try {
10050
10695
  meta = await BranchMetadataFileManager2.loadOnly(branchRoot);
@@ -10073,8 +10718,8 @@ var init_branch_registry = __esm({
10073
10718
  });
10074
10719
 
10075
10720
  // dist/branch-metadata.js
10076
- import fs27 from "node:fs/promises";
10077
- import path30 from "node:path";
10721
+ import fs28 from "node:fs/promises";
10722
+ import path31 from "node:path";
10078
10723
  var BRANCH_META_DIR2, BRANCH_META_FILE2, CURRENT_SCHEMA_VERSION2, BranchMetadataConflictError2, BranchMetadataCorruptError2, BranchMetadataFileManager2;
10079
10724
  var init_branch_metadata = __esm({
10080
10725
  "dist/branch-metadata.js"() {
@@ -10103,8 +10748,8 @@ var init_branch_metadata = __esm({
10103
10748
  };
10104
10749
  BranchMetadataFileManager2 = class _BranchMetadataFileManager2 {
10105
10750
  constructor(branchRoot, baseRoot, options) {
10106
- this.branchRoot = path30.resolve(branchRoot);
10107
- this.filePath = path30.join(this.branchRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
10751
+ this.branchRoot = path31.resolve(branchRoot);
10752
+ this.filePath = path31.join(this.branchRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
10108
10753
  this.baseRoot = baseRoot;
10109
10754
  this.settleMs = options?.settleMs;
10110
10755
  }
@@ -10113,10 +10758,10 @@ var init_branch_metadata = __esm({
10113
10758
  * Use this for read-only access (e.g., in registry scanning or loadBranchContext).
10114
10759
  */
10115
10760
  static async loadOnly(branchRoot) {
10116
- const resolvedRoot = path30.resolve(branchRoot);
10117
- const filePath = path30.join(resolvedRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
10761
+ const resolvedRoot = path31.resolve(branchRoot);
10762
+ const filePath = path31.join(resolvedRoot, BRANCH_META_DIR2, BRANCH_META_FILE2);
10118
10763
  try {
10119
- const raw = await fs27.readFile(filePath, "utf8");
10764
+ const raw = await fs28.readFile(filePath, "utf8");
10120
10765
  return JSON.parse(raw);
10121
10766
  } catch (err) {
10122
10767
  if (isNotFoundError(err)) {
@@ -10137,7 +10782,7 @@ var init_branch_metadata = __esm({
10137
10782
  }
10138
10783
  async load() {
10139
10784
  try {
10140
- const raw = await fs27.readFile(this.filePath, "utf8");
10785
+ const raw = await fs28.readFile(this.filePath, "utf8");
10141
10786
  const parsed = JSON.parse(raw);
10142
10787
  const version = parsed.version ?? 0;
10143
10788
  return { meta: parsed, version };
@@ -10199,7 +10844,7 @@ var init_branch_metadata = __esm({
10199
10844
  */
10200
10845
  async save(incoming) {
10201
10846
  try {
10202
- await fs27.stat(this.branchRoot);
10847
+ await fs28.stat(this.branchRoot);
10203
10848
  } catch (err) {
10204
10849
  if (isNotFoundError(err)) {
10205
10850
  throw new BranchMetadataConflictError2("Branch no longer exists");
@@ -10274,8 +10919,8 @@ __export(migrate_exports, {
10274
10919
  migrate: () => migrate,
10275
10920
  slugifyName: () => slugifyName
10276
10921
  });
10277
- import fs28 from "node:fs/promises";
10278
- import path31 from "node:path";
10922
+ import fs29 from "node:fs/promises";
10923
+ import path33 from "node:path";
10279
10924
  import * as p3 from "@clack/prompts";
10280
10925
  function slugifyName(name) {
10281
10926
  const slug = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
@@ -10283,7 +10928,7 @@ function slugifyName(name) {
10283
10928
  }
10284
10929
  function toValidSlug(name) {
10285
10930
  const slug = slugifyName(name);
10286
- const parsed = parseSlug(slug);
10931
+ const parsed = parseSlug2(slug);
10287
10932
  if (!parsed.ok) {
10288
10933
  throw new MigrateError(`Cannot derive a valid slug from "${name}" (got "${slug}"): ${parsed.error}`);
10289
10934
  }
@@ -10300,7 +10945,7 @@ function stripDirIdSuffix(dirName) {
10300
10945
  return dirName;
10301
10946
  }
10302
10947
  async function planDirectory(dirPath, isRoot, ctx) {
10303
- const entries = await fs28.readdir(dirPath, { withFileTypes: true });
10948
+ const entries = await fs29.readdir(dirPath, { withFileTypes: true });
10304
10949
  entries.sort((a, b) => a.name.localeCompare(b.name));
10305
10950
  const ops = [];
10306
10951
  let hasOwnFiles = false;
@@ -10309,7 +10954,7 @@ async function planDirectory(dirPath, isRoot, ctx) {
10309
10954
  if (entry.name.startsWith("."))
10310
10955
  continue;
10311
10956
  if (entry.isDirectory()) {
10312
- const subPath = path31.join(dirPath, entry.name);
10957
+ const subPath = path33.join(dirPath, entry.name);
10313
10958
  const sub = await planDirectory(subPath, false, ctx);
10314
10959
  if (!sub.hasContent)
10315
10960
  continue;
@@ -10317,10 +10962,10 @@ async function planDirectory(dirPath, isRoot, ctx) {
10317
10962
  ops.push(...sub.ops);
10318
10963
  if (!extractIdFromFilename2(entry.name)) {
10319
10964
  const newName = `${toValidSlug(entry.name)}.${generateId2()}`;
10320
- ops.push({ kind: "rename", from: subPath, to: path31.join(dirPath, newName) });
10965
+ ops.push({ kind: "rename", from: subPath, to: path33.join(dirPath, newName) });
10321
10966
  }
10322
10967
  } else if (entry.isFile()) {
10323
- const ext = path31.extname(entry.name).slice(1);
10968
+ const ext = path33.extname(entry.name).slice(1);
10324
10969
  const matchesFormat = ext === ctx.format || ctx.format === "yaml" && ext === "yml";
10325
10970
  if (!matchesFormat)
10326
10971
  continue;
@@ -10331,17 +10976,17 @@ async function planDirectory(dirPath, isRoot, ctx) {
10331
10976
  const newName = `${ctx.entryType}.${toValidSlug(base)}.${generateId2()}.${ext}`;
10332
10977
  ops.push({
10333
10978
  kind: "rename",
10334
- from: path31.join(dirPath, entry.name),
10335
- to: path31.join(dirPath, newName)
10979
+ from: path33.join(dirPath, entry.name),
10980
+ to: path33.join(dirPath, newName)
10336
10981
  });
10337
10982
  }
10338
10983
  }
10339
10984
  }
10340
10985
  const needsMeta = isRoot ? hasOwnFiles : hasContent;
10341
- const metaPath = path31.join(dirPath, ".collection.json");
10986
+ const metaPath = path33.join(dirPath, ".collection.json");
10342
10987
  if (needsMeta && !await filePathExists(metaPath)) {
10343
10988
  const entryTypeMeta = { name: ctx.entryType, format: ctx.format, schema: ctx.schema };
10344
- const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(path31.basename(dirPath))), entries: [entryTypeMeta] };
10989
+ const meta = isRoot ? { entries: [entryTypeMeta] } : { name: toValidSlug(stripDirIdSuffix(path33.basename(dirPath))), entries: [entryTypeMeta] };
10345
10990
  ops.push({ kind: "write", filePath: metaPath, content: JSON.stringify(meta, null, 2) + "\n" });
10346
10991
  }
10347
10992
  return { ops, hasContent };
@@ -10350,7 +10995,7 @@ async function migrate(options) {
10350
10995
  const { projectDir } = options;
10351
10996
  const contentRoot = options.contentRoot || "content";
10352
10997
  p3.intro("CanopyCMS migrate");
10353
- const contentDir = path31.join(projectDir, contentRoot);
10998
+ const contentDir = path33.join(projectDir, contentRoot);
10354
10999
  if (!await filePathExists(contentDir)) {
10355
11000
  throw new MigrateError(`Content directory not found: ${contentRoot}/ (expected at ${contentDir})`);
10356
11001
  }
@@ -10427,14 +11072,14 @@ async function migrate(options) {
10427
11072
  const applyOps = async () => {
10428
11073
  for (const op of ops) {
10429
11074
  if (op.kind === "rename") {
10430
- await fs28.rename(op.from, op.to);
11075
+ await fs29.rename(op.from, op.to);
10431
11076
  } else {
10432
- await fs28.writeFile(op.filePath, op.content, "utf-8");
11077
+ await fs29.writeFile(op.filePath, op.content, "utf-8");
10433
11078
  }
10434
11079
  }
10435
11080
  };
10436
11081
  if (isBranchClone) {
10437
- const lockPath = path31.join(projectDir, ".canopy-meta", "schema");
11082
+ const lockPath = path33.join(projectDir, ".canopy-meta", "schema");
10438
11083
  try {
10439
11084
  await withLock2(lockPath, () => withOccFileLock2(lockPath, applyOps));
10440
11085
  } catch (err) {
@@ -10482,7 +11127,7 @@ var init_migrate = __esm({
10482
11127
  this.name = "MigrateError";
10483
11128
  }
10484
11129
  };
10485
- describeOp = (op, baseDir) => op.kind === "rename" ? `rename ${path31.relative(baseDir, op.from)} \u2192 ${path31.basename(op.to)}` : `create ${path31.relative(baseDir, op.filePath)}`;
11130
+ describeOp = (op, baseDir) => op.kind === "rename" ? `rename ${path33.relative(baseDir, op.from)} \u2192 ${path33.basename(op.to)}` : `create ${path33.relative(baseDir, op.filePath)}`;
10486
11131
  }
10487
11132
  });
10488
11133