canopycms 0.0.67-int.90 → 0.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (539) hide show
  1. package/README.md +30 -3
  2. package/dist/ai/generate.js +1 -27
  3. package/dist/ai/handler.d.ts +0 -4
  4. package/dist/ai/handler.js +0 -11
  5. package/dist/ai/index.d.ts +1 -8
  6. package/dist/ai/index.js +1 -8
  7. package/dist/ai/json-to-markdown.js +15 -58
  8. package/dist/ai/resolve-branch.d.ts +2 -7
  9. package/dist/ai/resolve-branch.js +2 -8
  10. package/dist/ai/strip-mdx.d.ts +5 -13
  11. package/dist/ai/strip-mdx.js +5 -17
  12. package/dist/ai/to-plain-text.d.ts +10 -28
  13. package/dist/ai/to-plain-text.js +10 -28
  14. package/dist/ai/transform-components.d.ts +2 -4
  15. package/dist/ai/transform-components.js +8 -19
  16. package/dist/ai/types.d.ts +5 -10
  17. package/dist/api/admin-branch-health.d.ts +4 -12
  18. package/dist/api/admin-branch-health.js +26 -66
  19. package/dist/api/admin.d.ts +4 -12
  20. package/dist/api/admin.js +10 -26
  21. package/dist/api/assets.d.ts +0 -25
  22. package/dist/api/assets.js +50 -91
  23. package/dist/api/branch-merge.d.ts +1 -1
  24. package/dist/api/branch-merge.js +0 -2
  25. package/dist/api/branch-review.d.ts +0 -8
  26. package/dist/api/branch-review.js +0 -13
  27. package/dist/api/branch-status.d.ts +0 -3
  28. package/dist/api/branch-status.js +8 -33
  29. package/dist/api/branch-withdraw.d.ts +0 -1
  30. package/dist/api/branch-withdraw.js +6 -9
  31. package/dist/api/branch.d.ts +7 -12
  32. package/dist/api/branch.js +7 -44
  33. package/dist/api/client.d.ts +71 -224
  34. package/dist/api/client.js +82 -233
  35. package/dist/api/comments.d.ts +2 -4
  36. package/dist/api/comments.js +0 -17
  37. package/dist/api/content.d.ts +0 -6
  38. package/dist/api/content.js +66 -142
  39. package/dist/api/entries-constants.d.ts +5 -9
  40. package/dist/api/entries-constants.js +5 -9
  41. package/dist/api/entries.d.ts +8 -13
  42. package/dist/api/entries.js +20 -51
  43. package/dist/api/github-sync.d.ts +2 -4
  44. package/dist/api/github-sync.js +4 -8
  45. package/dist/api/groups.d.ts +3 -0
  46. package/dist/api/groups.js +8 -21
  47. package/dist/api/guards.d.ts +4 -16
  48. package/dist/api/guards.js +3 -22
  49. package/dist/api/index.d.ts +4 -4
  50. package/dist/api/permissions.d.ts +2 -0
  51. package/dist/api/permissions.js +18 -40
  52. package/dist/api/reference-options.d.ts +0 -1
  53. package/dist/api/reference-options.js +3 -11
  54. package/dist/api/request-body-hash.d.ts +12 -23
  55. package/dist/api/request-body-hash.js +12 -23
  56. package/dist/api/resolve-references.d.ts +0 -1
  57. package/dist/api/resolve-references.js +13 -28
  58. package/dist/api/route-builder.d.ts +3 -7
  59. package/dist/api/route-builder.js +1 -1
  60. package/dist/api/routes.d.ts +12 -0
  61. package/dist/api/routes.js +47 -0
  62. package/dist/api/schema.d.ts +23 -33
  63. package/dist/api/schema.js +20 -74
  64. package/dist/api/settings-helpers.js +4 -5
  65. package/dist/api/types.d.ts +0 -5
  66. package/dist/api/user.js +0 -5
  67. package/dist/api/validators.d.ts +14 -52
  68. package/dist/api/validators.js +14 -52
  69. package/dist/assets/asset-prefixes.d.ts +4 -8
  70. package/dist/assets/asset-prefixes.js +4 -8
  71. package/dist/assets/asset-src.d.ts +5 -22
  72. package/dist/assets/asset-src.js +5 -21
  73. package/dist/assets/factory.d.ts +1 -2
  74. package/dist/assets/factory.js +1 -2
  75. package/dist/assets/finalize.d.ts +3 -1
  76. package/dist/assets/finalize.js +3 -1
  77. package/dist/assets/index.d.ts +3 -3
  78. package/dist/assets/index.js +1 -1
  79. package/dist/assets/keys.d.ts +5 -3
  80. package/dist/assets/keys.js +6 -3
  81. package/dist/assets/pipeline.d.ts +3 -2
  82. package/dist/assets/pipeline.js +22 -56
  83. package/dist/assets/sharp-loader.d.ts +2 -10
  84. package/dist/assets/sharp-loader.js +2 -10
  85. package/dist/assets/store-local.d.ts +1 -2
  86. package/dist/assets/store-local.js +1 -2
  87. package/dist/assets/store-s3.d.ts +3 -4
  88. package/dist/assets/svg-sanitizer.d.ts +6 -14
  89. package/dist/assets/svg-sanitizer.js +6 -14
  90. package/dist/assets/transform-directives.d.ts +3 -4
  91. package/dist/assets/transform-directives.js +1 -1
  92. package/dist/assets/transform.d.ts +19 -30
  93. package/dist/assets/transform.js +18 -31
  94. package/dist/auth/cache.d.ts +2 -3
  95. package/dist/auth/cache.js +2 -3
  96. package/dist/auth/caching-auth-plugin.d.ts +11 -22
  97. package/dist/auth/caching-auth-plugin.js +12 -14
  98. package/dist/auth/context-helpers.d.ts +6 -20
  99. package/dist/auth/context-helpers.js +5 -17
  100. package/dist/auth/file-based-auth-cache.d.ts +10 -21
  101. package/dist/auth/file-based-auth-cache.js +23 -51
  102. package/dist/auth/plugin.d.ts +29 -61
  103. package/dist/auth/plugin.js +9 -13
  104. package/dist/auth/types.d.ts +11 -20
  105. package/dist/authorization/branch.d.ts +30 -49
  106. package/dist/authorization/branch.js +16 -42
  107. package/dist/authorization/content.d.ts +11 -40
  108. package/dist/authorization/content.js +13 -45
  109. package/dist/authorization/groups/index.d.ts +0 -3
  110. package/dist/authorization/groups/index.js +0 -3
  111. package/dist/authorization/groups/loader.d.ts +14 -28
  112. package/dist/authorization/groups/loader.js +14 -38
  113. package/dist/authorization/groups/schema.d.ts +0 -6
  114. package/dist/authorization/groups/schema.js +4 -7
  115. package/dist/authorization/helpers.d.ts +9 -28
  116. package/dist/authorization/helpers.js +9 -28
  117. package/dist/authorization/index.d.ts +3 -25
  118. package/dist/authorization/index.js +3 -35
  119. package/dist/authorization/path.d.ts +6 -13
  120. package/dist/authorization/path.js +8 -25
  121. package/dist/authorization/permissions/index.d.ts +0 -3
  122. package/dist/authorization/permissions/index.js +0 -3
  123. package/dist/authorization/permissions/loader.d.ts +14 -27
  124. package/dist/authorization/permissions/loader.js +14 -32
  125. package/dist/authorization/permissions/schema.d.ts +1 -6
  126. package/dist/authorization/permissions/schema.js +6 -13
  127. package/dist/authorization/protected-branch.d.ts +36 -65
  128. package/dist/authorization/protected-branch.js +29 -41
  129. package/dist/authorization/settings-file-store.d.ts +38 -81
  130. package/dist/authorization/settings-file-store.js +38 -79
  131. package/dist/authorization/types.d.ts +4 -26
  132. package/dist/authorization/types.js +0 -6
  133. package/dist/authorization/validation.d.ts +1 -23
  134. package/dist/authorization/validation.js +1 -24
  135. package/dist/branch-health.d.ts +39 -67
  136. package/dist/branch-health.js +27 -43
  137. package/dist/branch-metadata-file.d.ts +16 -32
  138. package/dist/branch-metadata-file.js +13 -26
  139. package/dist/branch-metadata.d.ts +49 -80
  140. package/dist/branch-metadata.js +57 -87
  141. package/dist/branch-registry.d.ts +26 -64
  142. package/dist/branch-registry.js +44 -93
  143. package/dist/branch-schema-cache.d.ts +34 -124
  144. package/dist/branch-schema-cache.js +49 -155
  145. package/dist/branch-workspace.d.ts +4 -4
  146. package/dist/branch-workspace.js +15 -19
  147. package/dist/build/generate-ai-content.d.ts +1 -0
  148. package/dist/build/generate-ai-content.js +12 -25
  149. package/dist/build-canopy.d.ts +17 -27
  150. package/dist/build-canopy.js +16 -23
  151. package/dist/build-mode.d.ts +25 -27
  152. package/dist/build-mode.js +25 -29
  153. package/dist/cli/cli.d.ts +15 -26
  154. package/dist/cli/cli.js +601 -978
  155. package/dist/cli/generate-ai-content.js +351 -628
  156. package/dist/cli/github-app-manifest.d.ts +84 -0
  157. package/dist/cli/github-app-manifest.js +161 -0
  158. package/dist/cli/init-github-app.d.ts +110 -444
  159. package/dist/cli/init-github-app.js +236 -773
  160. package/dist/cli/init.js +39 -80
  161. package/dist/cli/migrate.d.ts +13 -10
  162. package/dist/cli/migrate.js +22 -30
  163. package/dist/cli/project-detect.d.ts +17 -31
  164. package/dist/cli/project-detect.js +31 -42
  165. package/dist/cli/project-root.d.ts +4 -11
  166. package/dist/cli/project-root.js +4 -11
  167. package/dist/cli/prompt.d.ts +10 -0
  168. package/dist/cli/prompt.js +67 -0
  169. package/dist/cli/sync.d.ts +0 -8
  170. package/dist/cli/sync.js +8 -28
  171. package/dist/cli/template-files/middleware.ts.template +15 -29
  172. package/dist/cli/templates.d.ts +2 -12
  173. package/dist/cli/templates.js +4 -4
  174. package/dist/client.d.ts +1 -1
  175. package/dist/comment-store.d.ts +32 -53
  176. package/dist/comment-store.js +32 -52
  177. package/dist/config/flatten.d.ts +0 -3
  178. package/dist/config/flatten.js +2 -12
  179. package/dist/config/helpers.js +2 -2
  180. package/dist/config/index.d.ts +2 -2
  181. package/dist/config/index.js +1 -4
  182. package/dist/config/schemas/collection.d.ts +0 -8
  183. package/dist/config/schemas/collection.js +0 -10
  184. package/dist/config/schemas/config.d.ts +6 -78
  185. package/dist/config/schemas/config.js +38 -54
  186. package/dist/config/schemas/field.d.ts +2 -242
  187. package/dist/config/schemas/field.js +9 -20
  188. package/dist/config/schemas/media.js +1 -1
  189. package/dist/config/schemas/permissions.js +0 -2
  190. package/dist/config/schemas/url.d.ts +5 -6
  191. package/dist/config/schemas/url.js +5 -6
  192. package/dist/config/types.d.ts +45 -33
  193. package/dist/config/types.js +0 -1
  194. package/dist/config.d.ts +1 -8
  195. package/dist/config.js +1 -9
  196. package/dist/content-id-index.d.ts +76 -188
  197. package/dist/content-id-index.js +79 -230
  198. package/dist/content-index-generation.d.ts +27 -48
  199. package/dist/content-index-generation.js +35 -84
  200. package/dist/content-index-registry.d.ts +15 -24
  201. package/dist/content-index-registry.js +5 -9
  202. package/dist/content-listing.d.ts +64 -107
  203. package/dist/content-listing.js +68 -118
  204. package/dist/content-reader.d.ts +20 -29
  205. package/dist/content-reader.js +10 -18
  206. package/dist/content-store.d.ts +210 -336
  207. package/dist/content-store.js +413 -657
  208. package/dist/content-tree.d.ts +44 -86
  209. package/dist/content-tree.js +26 -54
  210. package/dist/context.d.ts +67 -94
  211. package/dist/context.js +53 -72
  212. package/dist/dev-content-watcher.d.ts +18 -18
  213. package/dist/dev-content-watcher.js +41 -44
  214. package/dist/editor/BranchManager.d.ts +3 -6
  215. package/dist/editor/BranchManager.js +24 -44
  216. package/dist/editor/CanopyEditor.js +5 -2
  217. package/dist/editor/CommentsPanel.js +0 -2
  218. package/dist/editor/Editor.js +19 -76
  219. package/dist/editor/EditorAuthGate.d.ts +27 -0
  220. package/dist/editor/EditorAuthGate.js +140 -0
  221. package/dist/editor/EntryNavigator.js +0 -20
  222. package/dist/editor/FormRenderer.d.ts +1 -2
  223. package/dist/editor/FormRenderer.js +8 -23
  224. package/dist/editor/admin/SystemHealthPanel.js +20 -37
  225. package/dist/editor/admin/useSystemHealth.d.ts +2 -3
  226. package/dist/editor/admin/useSystemHealth.js +10 -12
  227. package/dist/editor/client-reference-resolver.d.ts +2 -5
  228. package/dist/editor/client-reference-resolver.js +2 -19
  229. package/dist/editor/comments/BranchComments.js +0 -4
  230. package/dist/editor/comments/EntryComments.js +0 -4
  231. package/dist/editor/comments/FieldWrapper.js +0 -4
  232. package/dist/editor/comments/InlineCommentThread.js +0 -2
  233. package/dist/editor/comments/ThreadCarousel.d.ts +0 -58
  234. package/dist/editor/comments/ThreadCarousel.js +0 -12
  235. package/dist/editor/components/EditorFooter.d.ts +0 -8
  236. package/dist/editor/components/EditorFooter.js +0 -5
  237. package/dist/editor/components/EditorHeader.d.ts +0 -31
  238. package/dist/editor/components/EditorHeader.js +21 -71
  239. package/dist/editor/components/EditorSidebar.d.ts +0 -19
  240. package/dist/editor/components/EditorSidebar.js +0 -16
  241. package/dist/editor/components/EntryCreateModal.d.ts +4 -4
  242. package/dist/editor/components/EntryCreateModal.js +7 -22
  243. package/dist/editor/components/RenameEntryModal.js +0 -4
  244. package/dist/editor/components/UserBadge.js +0 -10
  245. package/dist/editor/components/index.js +0 -2
  246. package/dist/editor/context/ApiClientContext.d.ts +8 -7
  247. package/dist/editor/context/ApiClientContext.js +39 -11
  248. package/dist/editor/context/AssetContext.d.ts +7 -17
  249. package/dist/editor/context/AssetContext.js +7 -17
  250. package/dist/editor/context/EditorIdentityContext.d.ts +13 -0
  251. package/dist/editor/context/EditorIdentityContext.js +7 -0
  252. package/dist/editor/context/EditorStateContext.d.ts +10 -41
  253. package/dist/editor/context/EditorStateContext.js +7 -23
  254. package/dist/editor/context/SWRProvider.d.ts +3 -6
  255. package/dist/editor/context/index.d.ts +1 -20
  256. package/dist/editor/context/index.js +1 -20
  257. package/dist/editor/editor-utils.d.ts +8 -47
  258. package/dist/editor/editor-utils.js +19 -72
  259. package/dist/editor/fields/BlockField.d.ts +2 -2
  260. package/dist/editor/fields/BlockField.js +1 -2
  261. package/dist/editor/fields/CodeField.d.ts +0 -1
  262. package/dist/editor/fields/CodeField.js +0 -1
  263. package/dist/editor/fields/DateTimeField.d.ts +15 -22
  264. package/dist/editor/fields/DateTimeField.js +17 -26
  265. package/dist/editor/fields/ImageField.d.ts +2 -2
  266. package/dist/editor/fields/ImageField.js +8 -14
  267. package/dist/editor/fields/InlineGroupField.d.ts +0 -1
  268. package/dist/editor/fields/InlineGroupField.js +0 -1
  269. package/dist/editor/fields/MarkdownField.d.ts +0 -1
  270. package/dist/editor/fields/MarkdownField.js +6 -11
  271. package/dist/editor/fields/MdxImageDialog.d.ts +1 -1
  272. package/dist/editor/fields/MdxImageDialog.js +0 -1
  273. package/dist/editor/fields/NumberField.d.ts +9 -19
  274. package/dist/editor/fields/NumberField.js +11 -22
  275. package/dist/editor/fields/NumberListField.d.ts +7 -10
  276. package/dist/editor/fields/NumberListField.js +7 -10
  277. package/dist/editor/fields/ObjectField.d.ts +5 -8
  278. package/dist/editor/fields/ObjectField.js +0 -1
  279. package/dist/editor/fields/ReferenceField.d.ts +1 -1
  280. package/dist/editor/fields/ReferenceField.js +11 -16
  281. package/dist/editor/fields/SelectField.d.ts +2 -2
  282. package/dist/editor/fields/SelectField.js +0 -1
  283. package/dist/editor/fields/StringListField.d.ts +0 -4
  284. package/dist/editor/fields/StringListField.js +4 -9
  285. package/dist/editor/fields/TextField.d.ts +0 -1
  286. package/dist/editor/fields/TextField.js +0 -1
  287. package/dist/editor/fields/ToggleField.d.ts +0 -1
  288. package/dist/editor/fields/ToggleField.js +0 -1
  289. package/dist/editor/fields/entry-link/EntryLinkContext.js +2 -4
  290. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -3
  291. package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -4
  292. package/dist/editor/group-manager/ExternalGroupsTab.d.ts +0 -3
  293. package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
  294. package/dist/editor/group-manager/GroupCard.d.ts +0 -3
  295. package/dist/editor/group-manager/GroupForm.d.ts +0 -3
  296. package/dist/editor/group-manager/InternalGroupsTab.d.ts +0 -3
  297. package/dist/editor/group-manager/InternalGroupsTab.js +0 -2
  298. package/dist/editor/group-manager/MemberList.d.ts +0 -3
  299. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +0 -3
  300. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -3
  301. package/dist/editor/group-manager/hooks/useGroupState.d.ts +0 -3
  302. package/dist/editor/group-manager/hooks/useGroupState.js +0 -5
  303. package/dist/editor/group-manager/hooks/useUserSearch.d.ts +0 -3
  304. package/dist/editor/group-manager/hooks/useUserSearch.js +0 -3
  305. package/dist/editor/group-manager/index.d.ts +0 -6
  306. package/dist/editor/group-manager/index.js +0 -10
  307. package/dist/editor/group-manager/types.d.ts +2 -5
  308. package/dist/editor/group-manager/types.js +0 -3
  309. package/dist/editor/hooks/index.d.ts +6 -11
  310. package/dist/editor/hooks/index.js +6 -12
  311. package/dist/editor/hooks/useBranchActions.d.ts +0 -14
  312. package/dist/editor/hooks/useBranchActions.js +0 -22
  313. package/dist/editor/hooks/useBranchManager.d.ts +2 -48
  314. package/dist/editor/hooks/useBranchManager.js +4 -64
  315. package/dist/editor/hooks/useBranchesData.d.ts +7 -6
  316. package/dist/editor/hooks/useBranchesData.js +7 -6
  317. package/dist/editor/hooks/useCommentSystem.d.ts +0 -49
  318. package/dist/editor/hooks/useCommentSystem.js +1 -36
  319. package/dist/editor/hooks/useDraftManager.d.ts +2 -35
  320. package/dist/editor/hooks/useDraftManager.js +23 -64
  321. package/dist/editor/hooks/useEditorLayout.d.ts +0 -20
  322. package/dist/editor/hooks/useEditorLayout.js +0 -23
  323. package/dist/editor/hooks/useEntriesData.d.ts +1 -0
  324. package/dist/editor/hooks/useEntriesData.js +2 -3
  325. package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -2
  326. package/dist/editor/hooks/useEntryLinkResolution.js +2 -2
  327. package/dist/editor/hooks/useEntryManager.d.ts +2 -27
  328. package/dist/editor/hooks/useEntryManager.js +29 -78
  329. package/dist/editor/hooks/useGroupManager.d.ts +0 -21
  330. package/dist/editor/hooks/useGroupManager.js +0 -21
  331. package/dist/editor/hooks/usePermissionManager.d.ts +0 -20
  332. package/dist/editor/hooks/usePermissionManager.js +0 -20
  333. package/dist/editor/hooks/useReferenceResolution.d.ts +2 -33
  334. package/dist/editor/hooks/useReferenceResolution.js +1 -48
  335. package/dist/editor/hooks/useSchemaManager.d.ts +8 -27
  336. package/dist/editor/hooks/useSchemaManager.js +0 -19
  337. package/dist/editor/hooks/useUserContext.d.ts +2 -9
  338. package/dist/editor/hooks/useUserContext.js +10 -10
  339. package/dist/editor/hooks/useUserMetadata.d.ts +0 -2
  340. package/dist/editor/hooks/useUserMetadata.js +0 -3
  341. package/dist/editor/media/AssetCard.d.ts +0 -1
  342. package/dist/editor/media/AssetCard.js +1 -2
  343. package/dist/editor/media/CropStep.d.ts +0 -1
  344. package/dist/editor/media/CropStep.js +0 -1
  345. package/dist/editor/media/MediaLibrary.d.ts +1 -2
  346. package/dist/editor/media/MediaLibrary.js +1 -2
  347. package/dist/editor/media/MediaLibraryBody.d.ts +0 -1
  348. package/dist/editor/media/MediaLibraryBody.js +0 -1
  349. package/dist/editor/media/crop-math.d.ts +1 -1
  350. package/dist/editor/media/crop-math.js +1 -1
  351. package/dist/editor/permission-manager/GroupSelector.d.ts +0 -3
  352. package/dist/editor/permission-manager/PermissionEditor.d.ts +0 -4
  353. package/dist/editor/permission-manager/PermissionEditor.js +0 -1
  354. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +0 -7
  355. package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -4
  356. package/dist/editor/permission-manager/PermissionTree.d.ts +0 -4
  357. package/dist/editor/permission-manager/UserSelector.d.ts +0 -3
  358. package/dist/editor/permission-manager/constants.d.ts +0 -3
  359. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +0 -3
  360. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -10
  361. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +0 -14
  362. package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -11
  363. package/dist/editor/permission-manager/index.d.ts +0 -7
  364. package/dist/editor/permission-manager/index.js +0 -16
  365. package/dist/editor/permission-manager/types.d.ts +2 -12
  366. package/dist/editor/permission-manager/types.js +0 -3
  367. package/dist/editor/permission-manager/utils.d.ts +0 -28
  368. package/dist/editor/permission-manager/utils.js +9 -23
  369. package/dist/editor/preview-bridge.d.ts +5 -1
  370. package/dist/editor/preview-bridge.js +4 -4
  371. package/dist/editor/schema-editor/CollectionEditor.d.ts +0 -5
  372. package/dist/editor/schema-editor/CollectionEditor.js +9 -31
  373. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +0 -6
  374. package/dist/editor/schema-editor/EntryTypeEditor.js +3 -24
  375. package/dist/editor/schema-editor/index.d.ts +0 -7
  376. package/dist/editor/schema-editor/index.js +0 -7
  377. package/dist/editor/utils/env.d.ts +3 -18
  378. package/dist/editor/utils/env.js +6 -25
  379. package/dist/entry-link-resolver.d.ts +13 -35
  380. package/dist/entry-link-resolver.js +20 -53
  381. package/dist/entry-schema-registry.d.ts +20 -60
  382. package/dist/entry-schema-registry.js +20 -69
  383. package/dist/entry-schema.d.ts +118 -223
  384. package/dist/entry-schema.js +46 -91
  385. package/dist/git-manager.d.ts +101 -200
  386. package/dist/git-manager.js +211 -384
  387. package/dist/github-service.d.ts +34 -75
  388. package/dist/github-service.js +37 -91
  389. package/dist/http/handler.d.ts +6 -37
  390. package/dist/http/handler.js +65 -120
  391. package/dist/http/router.d.ts +15 -32
  392. package/dist/http/router.js +34 -99
  393. package/dist/http/types.d.ts +15 -40
  394. package/dist/http/types.js +3 -7
  395. package/dist/id.d.ts +4 -10
  396. package/dist/id.js +4 -10
  397. package/dist/index.js +6 -9
  398. package/dist/operating-mode/client-safe-strategy.d.ts +7 -14
  399. package/dist/operating-mode/client-safe-strategy.js +8 -28
  400. package/dist/operating-mode/client-unsafe-strategy.d.ts +6 -16
  401. package/dist/operating-mode/client-unsafe-strategy.js +9 -34
  402. package/dist/operating-mode/client.d.ts +3 -10
  403. package/dist/operating-mode/client.js +3 -8
  404. package/dist/operating-mode/deployment-name-fixtures.d.ts +14 -18
  405. package/dist/operating-mode/deployment-name-fixtures.js +14 -18
  406. package/dist/operating-mode/deployment-name.d.ts +19 -29
  407. package/dist/operating-mode/deployment-name.js +29 -47
  408. package/dist/operating-mode/index.d.ts +4 -25
  409. package/dist/operating-mode/index.js +9 -31
  410. package/dist/operating-mode/mode-env.d.ts +32 -54
  411. package/dist/operating-mode/mode-env.js +36 -58
  412. package/dist/operating-mode/types.d.ts +24 -72
  413. package/dist/operating-mode/types.js +1 -7
  414. package/dist/paths/branch-name.d.ts +30 -40
  415. package/dist/paths/branch-name.js +30 -40
  416. package/dist/paths/branch.d.ts +4 -18
  417. package/dist/paths/branch.js +6 -22
  418. package/dist/paths/index.d.ts +2 -13
  419. package/dist/paths/index.js +3 -23
  420. package/dist/paths/normalize-server.d.ts +3 -15
  421. package/dist/paths/normalize-server.js +3 -15
  422. package/dist/paths/normalize.d.ts +13 -33
  423. package/dist/paths/normalize.js +13 -33
  424. package/dist/paths/resolve.d.ts +4 -17
  425. package/dist/paths/resolve.js +4 -22
  426. package/dist/paths/types.d.ts +12 -34
  427. package/dist/paths/types.js +5 -7
  428. package/dist/paths/validation.d.ts +22 -119
  429. package/dist/paths/validation.js +30 -148
  430. package/dist/reference-resolver.d.ts +0 -13
  431. package/dist/reference-resolver.js +0 -18
  432. package/dist/resolve-canopy-user.d.ts +16 -18
  433. package/dist/resolve-canopy-user.js +17 -26
  434. package/dist/resource-generation.d.ts +16 -25
  435. package/dist/resource-generation.js +34 -97
  436. package/dist/schema/meta-loader.d.ts +2 -14
  437. package/dist/schema/meta-loader.js +15 -64
  438. package/dist/schema/resolver.d.ts +1 -4
  439. package/dist/schema/resolver.js +1 -6
  440. package/dist/schema/schema-store-types.d.ts +0 -12
  441. package/dist/schema/schema-store.d.ts +61 -138
  442. package/dist/schema/schema-store.js +85 -282
  443. package/dist/schema/types.d.ts +0 -4
  444. package/dist/server.d.ts +62 -93
  445. package/dist/server.js +63 -94
  446. package/dist/services.d.ts +23 -47
  447. package/dist/services.js +55 -98
  448. package/dist/settings-workspace.d.ts +17 -30
  449. package/dist/settings-workspace.js +51 -81
  450. package/dist/static/index.d.ts +26 -52
  451. package/dist/static/index.js +33 -67
  452. package/dist/{worker/task-queue.d.ts → task-queue/cms-task-queue.d.ts} +7 -9
  453. package/dist/task-queue/cms-task-queue.js +13 -0
  454. package/dist/task-queue/task-queue-config.d.ts +3 -0
  455. package/dist/{worker → task-queue}/task-queue-config.js +1 -6
  456. package/dist/task-queue/task-queue.d.ts +16 -22
  457. package/dist/task-queue/task-queue.js +20 -44
  458. package/dist/task-queue/types.d.ts +0 -1
  459. package/dist/task-queue/worker-status.d.ts +35 -0
  460. package/dist/task-queue/worker-status.js +40 -0
  461. package/dist/types.d.ts +40 -51
  462. package/dist/url-collision.d.ts +26 -40
  463. package/dist/url-collision.js +47 -63
  464. package/dist/url-exclusivity-fixtures.d.ts +15 -20
  465. package/dist/url-exclusivity-fixtures.js +14 -19
  466. package/dist/url-path-resolver.d.ts +8 -16
  467. package/dist/url-path-resolver.js +19 -29
  468. package/dist/user.d.ts +8 -21
  469. package/dist/user.js +10 -19
  470. package/dist/utils/async-mutex.js +4 -6
  471. package/dist/utils/atomic-write.d.ts +2 -11
  472. package/dist/utils/atomic-write.js +2 -11
  473. package/dist/utils/body-field.d.ts +8 -15
  474. package/dist/utils/body-field.js +8 -15
  475. package/dist/utils/content-serialize.d.ts +18 -24
  476. package/dist/utils/content-serialize.js +109 -160
  477. package/dist/utils/content-write-lock.d.ts +51 -106
  478. package/dist/utils/content-write-lock.js +66 -111
  479. package/dist/utils/debug.d.ts +7 -23
  480. package/dist/utils/debug.js +7 -23
  481. package/dist/utils/entry-url.d.ts +11 -23
  482. package/dist/utils/entry-url.js +11 -26
  483. package/dist/utils/error.d.ts +25 -90
  484. package/dist/utils/error.js +60 -147
  485. package/dist/utils/flatten-group-fields.d.ts +5 -7
  486. package/dist/utils/flatten-group-fields.js +5 -7
  487. package/dist/utils/format.d.ts +1 -5
  488. package/dist/utils/format.js +1 -5
  489. package/dist/utils/fs.d.ts +3 -4
  490. package/dist/utils/fs.js +3 -4
  491. package/dist/utils/git.d.ts +52 -83
  492. package/dist/utils/git.js +79 -125
  493. package/dist/utils/logger.d.ts +35 -50
  494. package/dist/utils/logger.js +35 -52
  495. package/dist/utils/provisioning-lock.d.ts +23 -35
  496. package/dist/utils/provisioning-lock.js +49 -69
  497. package/dist/utils/sanitize-href.d.ts +5 -10
  498. package/dist/utils/sanitize-href.js +8 -18
  499. package/dist/utils/title-field.d.ts +17 -20
  500. package/dist/utils/title-field.js +18 -27
  501. package/dist/utils/typed-filename.d.ts +20 -48
  502. package/dist/utils/typed-filename.js +25 -61
  503. package/dist/utils/url-prefix.d.ts +3 -3
  504. package/dist/utils/url-prefix.js +3 -3
  505. package/dist/validation/block-structural-keys.d.ts +16 -31
  506. package/dist/validation/block-structural-keys.js +19 -29
  507. package/dist/validation/deletion-checker.d.ts +0 -34
  508. package/dist/validation/deletion-checker.js +1 -43
  509. package/dist/validation/entry-link-validator.d.ts +6 -13
  510. package/dist/validation/entry-link-validator.js +4 -13
  511. package/dist/validation/entry-type-reference-validator.d.ts +13 -18
  512. package/dist/validation/entry-type-reference-validator.js +13 -18
  513. package/dist/validation/entry-validator.d.ts +13 -25
  514. package/dist/validation/entry-validator.js +15 -32
  515. package/dist/validation/field-traversal.d.ts +3 -30
  516. package/dist/validation/field-traversal.js +1 -32
  517. package/dist/validation/reference-validator.d.ts +5 -24
  518. package/dist/validation/reference-validator.js +5 -30
  519. package/dist/worker/cms-worker.d.ts +172 -232
  520. package/dist/worker/cms-worker.js +241 -333
  521. package/dist/worker/git-sync.d.ts +32 -133
  522. package/dist/worker/git-sync.js +129 -191
  523. package/dist/worker/github-auth.d.ts +13 -19
  524. package/dist/worker/github-auth.js +13 -19
  525. package/dist/worker/history-rewrite.d.ts +53 -66
  526. package/dist/worker/history-rewrite.js +54 -60
  527. package/dist/worker/log.d.ts +24 -41
  528. package/dist/worker/log.js +25 -42
  529. package/dist/worker/rebase.d.ts +20 -110
  530. package/dist/worker/rebase.js +279 -354
  531. package/dist/worker/task-runner.d.ts +32 -66
  532. package/dist/worker/task-runner.js +126 -162
  533. package/dist/worker/worker-context.d.ts +41 -81
  534. package/package.json +4 -4
  535. package/dist/cli/template-files/middleware-clerk.ts.template +0 -37
  536. package/dist/worker/task-queue-config.d.ts +0 -8
  537. package/dist/worker/task-queue.js +0 -19
  538. package/dist/worker/worker-status.d.ts +0 -47
  539. package/dist/worker/worker-status.js +0 -52
@@ -1,55 +1,38 @@
1
1
  /**
2
- * Content tree builder for adopters.
2
+ * Content tree builder for adopters: walks the schema + filesystem and returns a tree of
3
+ * content nodes for navigation, sitemaps, search indexes, breadcrumbs.
3
4
  *
4
- * Walks the schema + filesystem and returns a tree of content nodes that
5
- * adopters can use for navigation, sitemaps, search indexes, breadcrumbs, etc.
6
- *
7
- * Nodes carry Canopy's structural facts (logicalPath, contentId, collection
8
- * metadata, entry metadata). Display concerns like labels are left to the
9
- * adopter via the `extract` callback.
5
+ * Nodes carry Canopy's structural facts (logicalPath, contentId, collection metadata, entry
6
+ * metadata); display concerns like labels are left to the adopter's `extract` callback.
10
7
  */
11
8
  import type { FlatSchemaItem, ContentFormat } from './config/index.js';
12
9
  /**
13
- * Adopter-supplied registry mapping entry type names (as they appear in
14
- * filenames: `partner.index.yaml` → `'partner'`) to their data shapes.
10
+ * Adopter-supplied registry mapping entry type names (as they appear in filenames:
11
+ * `partner.index.yaml` → `'partner'`) to their data shapes.
15
12
  *
16
- * Pair with `TypeFromEntrySchema<typeof yourSchema>` to derive shapes from
17
- * schemas you've already defined — no redeclaration needed.
13
+ * Pair with `TypeFromEntrySchema<typeof yourSchema>` to derive shapes from schemas you have
14
+ * already defined — no redeclaration needed.
18
15
  *
19
16
  * @example
20
17
  * ```ts
21
- * import { defineEntrySchema, type TypeFromEntrySchema } from 'canopycms'
22
- *
23
- * const partnerSchema = defineEntrySchema([
24
- * { name: 'name', type: 'string', isTitle: true },
25
- * { name: 'tagline', type: 'string' },
26
- * ])
27
- * const docSchema = defineEntrySchema([
28
- * { name: 'title', type: 'string' },
29
- * ])
30
- *
18
+ * const partnerSchema = defineEntrySchema([{ name: 'name', type: 'string', isTitle: true }])
31
19
  * interface MyEntries {
32
20
  * partner: TypeFromEntrySchema<typeof partnerSchema>
33
- * doc: TypeFromEntrySchema<typeof docSchema>
34
21
  * }
35
22
  *
36
- * const canopy = await getCanopyForBuild()
37
23
  * await canopy.buildContentTree<NavFields, MyEntries>({
38
- * extract: (data, meta) => {
39
- * if (meta.kind === 'collection' && meta.indexEntry?.entryType === 'partner') {
40
- * // meta.indexEntry.data is narrowed to PartnerContent
41
- * return { name: meta.indexEntry.data.name }
42
- * }
43
- * return { name: '' }
44
- * },
24
+ * // meta.indexEntry.data is narrowed to the partner shape
25
+ * extract: (data, meta) =>
26
+ * meta.kind === 'collection' && meta.indexEntry?.entryType === 'partner'
27
+ * ? { name: meta.indexEntry.data.name }
28
+ * : { name: '' },
45
29
  * })
46
30
  * ```
47
31
  */
48
32
  export type EntryTypeMap = Record<string, object>;
49
33
  /**
50
- * Default TEntryTypes when an adopter hasn't supplied one.
51
- * The index signature preserves the loose shape — `meta.indexEntry.data`
52
- * stays `Record<string, unknown>`, useful for unstructured access without
34
+ * Default TEntryTypes when an adopter hasn't supplied one. The index signature keeps
35
+ * `meta.indexEntry.data` as `Record<string, unknown>`, useful for unstructured access without
53
36
  * opting in to the discriminated-union pattern. Exported so callers wrapping
54
37
  * `buildContentTree` (e.g. CanopyBuildContext) share the same default.
55
38
  */
@@ -68,15 +51,14 @@ export interface ContentTreeExtractMeta<TEntryTypes = DefaultEntryTypes> {
68
51
  /** Content format — present when kind is 'entry'. */
69
52
  format?: ContentFormat;
70
53
  /**
71
- * The entry with slug 'index' inside a collection, when present.
72
- * Represents the collection's "identity" under the directory-as-page pattern
73
- * (e.g., a partner's metadata for /data-catalog/<partner>/, a section landing
74
- * for /docs/<section>/). Only populated when kind === 'collection' AND the
75
- * collection contains an entry with slug 'index'. Undefined for collections
76
- * at the maxDepth cap (entries aren't loaded there).
54
+ * The entry with slug 'index' inside a collection, when present — the collection's
55
+ * "identity" under the directory-as-page pattern (a partner's metadata for
56
+ * /data-catalog/<partner>/, a section landing for /docs/<section>/). Populated only when
57
+ * kind === 'collection' AND such an entry exists; undefined for collections at the maxDepth
58
+ * cap, where entries are not loaded.
77
59
  *
78
- * When TEntryTypes is supplied, this becomes a discriminated union: narrow
79
- * on `indexEntry.entryType` and `data` is typed accordingly.
60
+ * With TEntryTypes supplied this is a discriminated union: narrow on `indexEntry.entryType`
61
+ * and `data` is typed accordingly.
80
62
  */
81
63
  indexEntry?: {
82
64
  [K in keyof TEntryTypes & string]: {
@@ -119,24 +101,18 @@ export interface BuildContentTreeOptions<T = unknown, TEntryTypes = DefaultEntry
119
101
  /** Starting collection path. Defaults to content root. */
120
102
  rootPath?: string;
121
103
  /**
122
- * Extract typed custom fields from each node's raw data.
123
- * For entries: data is frontmatter + body (md/mdx) or parsed JSON.
124
- * For collections: data is `{ name, label }` from the schema.
125
- *
126
- * Supply TEntryTypes to get narrowed access to `meta.indexEntry.data`
127
- * via discriminated-union narrowing on `meta.indexEntry.entryType`.
104
+ * Extract typed custom fields from each node's raw data. For entries, data is frontmatter +
105
+ * body (md/mdx) or the parsed object; for collections it is `{ name, label }` from the
106
+ * schema. Supply TEntryTypes for narrowed access to `meta.indexEntry.data`.
128
107
  *
129
- * Note: extract should be a pure mapping. It may be invoked on entry nodes
130
- * that `filter` later removes (the tree-walk extracts then filters), so any
131
- * side effects (logging, counters, populating an external index) will see
132
- * those rejected nodes too.
108
+ * Must be a pure mapping: it may be invoked on entry nodes that `filter` later removes (the
109
+ * tree-walk extracts, then filters), so side effects see those rejected nodes too.
133
110
  */
134
111
  extract?: (data: Record<string, unknown>, meta: ContentTreeExtractMeta<TEntryTypes>) => T;
135
112
  /**
136
- * Filter: return false to exclude a node and its descendants.
137
- * Runs after extract, so `fields` is available. Rejecting a collection
138
- * short-circuits descendant traversal (no recursion into child collections
139
- * or entry reads beneath the rejected node).
113
+ * Return false to exclude a node and its descendants. Runs after extract, so `fields` is
114
+ * available. Rejecting a collection short-circuits descendant traversal — no recursion into
115
+ * child collections, no entry reads beneath it.
140
116
  */
141
117
  filter?: (node: ContentTreeNode<T>) => boolean;
142
118
  /**
@@ -144,20 +120,11 @@ export interface BuildContentTreeOptions<T = unknown, TEntryTypes = DefaultEntry
144
120
  * with it. To extend rather than replace the default behavior, call the exported
145
121
  * `defaultBuildPath(logicalPath, contentRootName, kind)` from inside your
146
122
  * function and post-process its result (see `canopycms/server`).
147
- *
148
- * Default behavior (`defaultBuildPath`):
149
- * - Strips the `{contentRootName}/` prefix from `logicalPath`.
150
- * - For entries: collapses an `index` slug to its parent collection's path
151
- * (`content/guides/index` → `/guides`, not `/guides/index`); a collection
152
- * literally named `index` is unaffected (only entries collapse).
153
- * - Lowercases the entire result.
154
- * - Prepends `/`; the content root's own index collapses to `/`.
155
123
  */
156
124
  buildPath?: (logicalPath: LogicalPath, kind: 'collection' | 'entry') => string;
157
125
  /**
158
- * Custom sort for children at each level.
159
- * When provided, replaces the default sort (order array → alphabetical).
160
- * Runs after extract + filter, so `fields` is available.
126
+ * Custom sort for children at each level; replaces the default (order array → alphabetical)
127
+ * entirely. Runs after extract + filter, so `fields` is available.
161
128
  */
162
129
  sort?: (a: ContentTreeNode<T>, b: ContentTreeNode<T>) => number;
163
130
  /** Max depth to traverse. Default: unlimited. */
@@ -167,34 +134,25 @@ export interface BuildContentTreeOptions<T = unknown, TEntryTypes = DefaultEntry
167
134
  * `read()`/`readByUrlPath()` do. Applies to both entry nodes and the `meta.indexEntry`
168
135
  * handed to a collection's `extract`. Off leaves them as the bare id string, or `null`.
169
136
  *
170
- * Same flag, same default (`false`) and same reasoning as `listEntries`' option — see
171
- * `ListEntriesOptions.resolveReferences` in content-listing.ts for why the default is
172
- * opt-in rather than matching `read()`, what it costs, and why path ACLs are not applied
173
- * to the resolved targets.
137
+ * Same flag, same default (`false`) and same reasoning as
138
+ * `ListEntriesOptions.resolveReferences` in content-listing.ts — see it for why the default
139
+ * is opt-in, what it costs, and why path ACLs are not applied to the resolved targets.
174
140
  */
175
141
  resolveReferences?: boolean;
176
142
  }
177
143
  /**
178
- * Default path builder: strips the content root prefix, lowercases, and prepends /.
179
- * All URL paths are lowercased unconditionally for consistency with slug normalization.
180
- * Adopters with case-sensitive slugs (e.g., "API-Reference") will get lowercased URLs.
181
- *
182
- * Index entries (slug 'index', any case) are collapsed to their parent collection path,
183
- * matching the URL convention used by readByUrlPath and listEntries.
144
+ * Default path builder: strips the content root prefix, collapses index entries, lowercases,
145
+ * prepends `/`. Lowercasing is unconditional, for consistency with slug normalization, so an
146
+ * adopter with case-sensitive slugs ("API-Reference") gets lowercased URLs. Index entries
147
+ * (slug 'index', any case) collapse to their parent collection path, matching the convention
148
+ * readByUrlPath and listEntries use.
184
149
  *
185
- * Exported (also re-exported from `canopycms/server`) so adopters who want to
186
- * EXTEND this behavior rather than replace it can call it from inside their own
187
- * `buildPath` and post-process the result, instead of reimplementing the
188
- * content-root-strip / index-collapse / lowercase logic verbatim.
150
+ * Exported (and re-exported from `canopycms/server`) so adopters who want to EXTEND this
151
+ * rather than replace it can call it from inside their own `buildPath` and post-process the
152
+ * result, instead of reimplementing strip / collapse / lowercase verbatim.
189
153
  */
190
154
  export declare const defaultBuildPath: (logicalPath: LogicalPath, contentRootName: string, kind: "collection" | "entry") => string;
191
155
  /**
192
156
  * Build a content tree from a flattened schema and the filesystem.
193
- *
194
- * @param branchRoot - Absolute path to the branch workspace root
195
- * @param flatSchema - Flattened schema items (from flattenSchema)
196
- * @param contentRootName - The content root name (e.g. "content")
197
- * @param options - Tree-building options
198
- * @param visibility - Internal path-ACL predicate; see `ContentVisibilityOptions`
199
157
  */
200
158
  export declare function buildContentTree<T = unknown, TEntryTypes = DefaultEntryTypes>(branchRoot: string, flatSchema: FlatSchemaItem[], contentRootName: string, options?: BuildContentTreeOptions<T, TEntryTypes>, visibility?: ContentVisibilityOptions): Promise<ContentTreeNode<T>[]>;
@@ -1,18 +1,12 @@
1
1
  /**
2
- * Content tree builder for adopters.
2
+ * Content tree builder for adopters: walks the schema + filesystem and returns a tree of
3
+ * content nodes for navigation, sitemaps, search indexes, breadcrumbs.
3
4
  *
4
- * Walks the schema + filesystem and returns a tree of content nodes that
5
- * adopters can use for navigation, sitemaps, search indexes, breadcrumbs, etc.
6
- *
7
- * Nodes carry Canopy's structural facts (logicalPath, contentId, collection
8
- * metadata, entry metadata). Display concerns like labels are left to the
9
- * adopter via the `extract` callback.
5
+ * Nodes carry Canopy's structural facts (logicalPath, contentId, collection metadata, entry
6
+ * metadata); display concerns like labels are left to the adopter's `extract` callback.
10
7
  */
11
8
  import { isIndexSlug } from './utils/entry-url.js';
12
9
  import { createReferenceResolver, listCollectionEntries, resolveCollectionItemReferences, sortByOrder, } from './content-listing.js';
13
- // ---------------------------------------------------------------------------
14
- // Internal helpers
15
- // ---------------------------------------------------------------------------
16
10
  /** Group flat schema items by parentPath for O(1) child lookup. */
17
11
  const groupByParent = (flat) => {
18
12
  const map = new Map();
@@ -27,28 +21,24 @@ const groupByParent = (flat) => {
27
21
  return map;
28
22
  };
29
23
  /**
30
- * Default path builder: strips the content root prefix, lowercases, and prepends /.
31
- * All URL paths are lowercased unconditionally for consistency with slug normalization.
32
- * Adopters with case-sensitive slugs (e.g., "API-Reference") will get lowercased URLs.
33
- *
34
- * Index entries (slug 'index', any case) are collapsed to their parent collection path,
35
- * matching the URL convention used by readByUrlPath and listEntries.
24
+ * Default path builder: strips the content root prefix, collapses index entries, lowercases,
25
+ * prepends `/`. Lowercasing is unconditional, for consistency with slug normalization, so an
26
+ * adopter with case-sensitive slugs ("API-Reference") gets lowercased URLs. Index entries
27
+ * (slug 'index', any case) collapse to their parent collection path, matching the convention
28
+ * readByUrlPath and listEntries use.
36
29
  *
37
- * Exported (also re-exported from `canopycms/server`) so adopters who want to
38
- * EXTEND this behavior rather than replace it can call it from inside their own
39
- * `buildPath` and post-process the result, instead of reimplementing the
40
- * content-root-strip / index-collapse / lowercase logic verbatim.
30
+ * Exported (and re-exported from `canopycms/server`) so adopters who want to EXTEND this
31
+ * rather than replace it can call it from inside their own `buildPath` and post-process the
32
+ * result, instead of reimplementing strip / collapse / lowercase verbatim.
41
33
  */
42
34
  export const defaultBuildPath = (logicalPath, contentRootName, kind) => {
43
35
  const prefix = contentRootName ? `${contentRootName}/` : '';
44
36
  const stripped = prefix && logicalPath.startsWith(prefix) ? logicalPath.slice(prefix.length) : logicalPath;
45
- // Collapse index entries: content/guides/index → /guides (not /guides/index)
46
- // Only for entries — a collection named "index" should keep its path.
47
- //
48
- // The index test runs on the LAST SEGMENT through the shared `isIndexSlug`, so it is
49
- // case-insensitive and agrees with `computeEntryUrl`. A string `endsWith('/index')` test
50
- // did not: for an adopter-supplied `content/docs/Index` this said `/docs/index` while
51
- // `computeEntryUrl` said `/docs`, and `/docs/index` is the one that does NOT round-trip.
37
+ // Collapse index entries: content/guides/index → /guides. Entries only — a collection named
38
+ // "index" keeps its path. The test runs on the LAST SEGMENT through the shared
39
+ // `isIndexSlug`, so it is case-insensitive and agrees with `computeEntryUrl`; a string
40
+ // `endsWith('/index')` test disagreed for an adopter-supplied `content/docs/Index`, and
41
+ // `/docs/index` is the answer that does NOT round-trip.
52
42
  const lastSlash = stripped.lastIndexOf('/');
53
43
  const lastSegment = lastSlash === -1 ? stripped : stripped.slice(lastSlash + 1);
54
44
  const collapsed = kind === 'entry' && isIndexSlug(lastSegment)
@@ -59,17 +49,8 @@ export const defaultBuildPath = (logicalPath, contentRootName, kind) => {
59
49
  const urlPath = collapsed ? `/${collapsed}` : '/';
60
50
  return urlPath.toLowerCase();
61
51
  };
62
- // ---------------------------------------------------------------------------
63
- // Core builder
64
- // ---------------------------------------------------------------------------
65
52
  /**
66
53
  * Build a content tree from a flattened schema and the filesystem.
67
- *
68
- * @param branchRoot - Absolute path to the branch workspace root
69
- * @param flatSchema - Flattened schema items (from flattenSchema)
70
- * @param contentRootName - The content root name (e.g. "content")
71
- * @param options - Tree-building options
72
- * @param visibility - Internal path-ACL predicate; see `ContentVisibilityOptions`
73
54
  */
74
55
  export async function buildContentTree(branchRoot, flatSchema, contentRootName, options, visibility) {
75
56
  const childrenByParent = groupByParent(flatSchema);
@@ -98,7 +79,6 @@ export async function buildContentTree(branchRoot, flatSchema, contentRootName,
98
79
  // reason the ACL filter lives here. A denied entry is filtered above and never resolved.
99
80
  return resolver ? resolveCollectionItemReferences(visible, collection, resolver) : visible;
100
81
  };
101
- // Find the starting collection(s)
102
82
  const rootPath = options?.rootPath ?? contentRootName;
103
83
  const rootCollection = flatSchema.find((item) => item.type === 'collection' && item.logicalPath === rootPath);
104
84
  if (!rootCollection)
@@ -131,20 +111,16 @@ export async function buildContentTree(branchRoot, flatSchema, contentRootName,
131
111
  return null;
132
112
  return node;
133
113
  }
134
- // Load this collection's entries first (needed for indexEntry detection).
135
- // We deliberately do NOT parallelize the child-collection recursion here:
136
- // if `filter` rejects this collection, returning early short-circuits all
137
- // descendant I/O — preserving the pre-existing "filter prunes whole subtree"
138
- // optimization that the directory-as-page reorder would otherwise lose.
114
+ // Load this collection's entries first (needed for indexEntry detection). The
115
+ // child-collection recursion deliberately does NOT run in parallel with it: if `filter`
116
+ // rejects this collection, returning early short-circuits all descendant I/O.
139
117
  const entries = await listVisibleEntries(collection);
140
- // Surface the 'index' entry (when present) to extract via meta.
141
- // 'index' is the same magic slug Canopy uses in defaultBuildPath to collapse
142
- // /foo/index URLs to /foo/, keeping conventions consistent. If a collection
143
- // contains multiple slug==='index' entries (only possible via hand-edited or
144
- // merged content — the write path forbids it), the first by filename order
145
- // wins.
146
- // The cast bridges runtime string keys to the parametric discriminated union;
147
- // the adopter narrows on `indexEntry.entryType` to get the typed `data`.
118
+ // Surface the 'index' entry (when present) to extract via meta. 'index' is the same magic
119
+ // slug defaultBuildPath collapses /foo/index to /foo with. If a collection contains
120
+ // several slug==='index' entries (only reachable via hand-edited or merged content -- the
121
+ // write path forbids it), the first by filename order wins. The cast bridges runtime
122
+ // string keys to the parametric discriminated union; the adopter narrows on
123
+ // `indexEntry.entryType` to get the typed `data`.
148
124
  const idx = entries.find((e) => e.slug === 'index');
149
125
  const indexEntry = (idx ? { entryType: idx.entryType, format: idx.format, data: idx.data } : undefined);
150
126
  if (extract) {
@@ -156,10 +132,8 @@ export async function buildContentTree(branchRoot, flatSchema, contentRootName,
156
132
  }
157
133
  if (filter && !filter(node))
158
134
  return null;
159
- // Now recurse into child collections (after filter has had a chance to prune)
160
135
  const childCollections = childrenByParent.get(collection.logicalPath) ?? [];
161
136
  const childCollectionNodes = await Promise.all(childCollections.map((child) => buildNode(child, depth + 1)));
162
- // Build entry nodes
163
137
  const entryNodes = [];
164
138
  for (const entry of entries) {
165
139
  const entryNode = buildEntryNode(entry, buildPath, extract);
@@ -167,7 +141,6 @@ export async function buildContentTree(branchRoot, flatSchema, contentRootName,
167
141
  continue;
168
142
  entryNodes.push(entryNode);
169
143
  }
170
- // Combine and interleave by order array (or custom sort)
171
144
  const allChildren = interleaveChildren(childCollectionNodes.filter((n) => n !== null), entryNodes, collection.order, customSort);
172
145
  // Prune empty collections (no children after filtering)
173
146
  if (allChildren.length === 0)
@@ -177,7 +150,6 @@ export async function buildContentTree(branchRoot, flatSchema, contentRootName,
177
150
  };
178
151
  // Start from root's children (don't include the root collection itself)
179
152
  const topLevelCollections = childrenByParent.get(rootCollection.logicalPath) ?? [];
180
- // Also get entries directly in the root collection
181
153
  const [collectionNodes, rootEntries] = await Promise.all([
182
154
  Promise.all(topLevelCollections.map((child) => buildNode(child, 1))),
183
155
  listVisibleEntries(rootCollection),
package/dist/context.d.ts CHANGED
@@ -7,13 +7,13 @@
7
7
  * layer where authorization is applied, so a read that bypasses it bypasses
8
8
  * path ACLs.
9
9
  *
10
- * PHASE-AWARE: at build time (`isBuildMode`) or for a static deployment
11
- * (`isDeployedStatic`) it authorizes as `STATIC_DEPLOY_USER` instead of a real
12
- * user (WHO), and it reads the working tree at `process.cwd()` instead of a
13
- * branch workspace (WHERE: `readsFromCheckout`, applied inside
10
+ * PHASE-AWARE: at build time (`isBuildMode`) or on a static deployment
11
+ * (`isDeployedStatic`) it authorizes as `STATIC_DEPLOY_USER` rather than a real
12
+ * user (WHO) and reads the working tree at `process.cwd()` rather than a branch
13
+ * workspace (WHERE: `readsFromCheckout`, applied inside
14
14
  * `loadOrCreateBranchContext`), so a `branch` passed to a read selects nothing.
15
- * Only request-time reads on a server deployment resolve a branch workspace --
16
- * in dev mode, the clone under `.canopy-dev/content-branches/`.
15
+ * Only request-time reads on a server deployment resolve a branch workspace —
16
+ * in dev, the clone under `.canopy-dev/content-branches/`.
17
17
  *
18
18
  * The Next.js adapter wraps this in React `cache()` for per-request memoization
19
19
  * (`canopycms-next/src/context-wrapper.ts`).
@@ -28,60 +28,60 @@ import { type ListEntriesOptions, type ListEntriesItem } from './content-listing
28
28
  export interface CanopyContextOptions {
29
29
  services: CanopyServices;
30
30
  /**
31
- * Extract the current user from framework-specific context.
32
- * Should call authResultToCanopyUser() to apply bootstrap admin groups.
33
- *
34
- * Framework adapters provide this (e.g., from Next.js headers, Express req, etc.)
31
+ * Extract the current user from framework-specific context — supplied by the
32
+ * framework adapter, and must call authResultToCanopyUser() so bootstrap
33
+ * admin groups are applied.
35
34
  */
36
35
  extractUser: () => Promise<CanopyUser>;
37
36
  }
38
37
  /**
39
- * Build-time context.
40
- *
41
- * Obtained via getCanopyForBuild(); reads the filesystem directly as a synthetic admin
42
- * (STATIC_DEPLOY_USER) and bypasses all branch/path ACLs. Safe for static generation
43
- * (generateStaticParams, sitemap, build-time page rendering); it must NOT be used to serve
44
- * content at request time on a production `server` deployment. (Framework adapters throw on the
45
- * read helpers there; `services` remains a raw, unguarded escape hatch.) For request-scoped,
46
- * ACL-enforced access use getCanopy() (CanopyContext) instead.
38
+ * Build-time context, from getCanopyForBuild(): reads the filesystem directly
39
+ * as a synthetic admin (STATIC_DEPLOY_USER), bypassing all branch and path
40
+ * ACLs. Use it for static generation — generateStaticParams, sitemap,
41
+ * build-time page rendering — and never to serve content at request time on a
42
+ * production `server` deployment; request-time, ACL-enforced access is
43
+ * getCanopy() (CanopyContext). Framework adapters throw on the read helpers
44
+ * there, though `services` stays a raw, unguarded escape hatch.
47
45
  *
48
- * Includes read/readByUrlPath so build-time code can resolve a single entry by path/URL without
49
- * scanning the whole collection.
46
+ * It carries read/readByUrlPath so build-time code can resolve a single entry
47
+ * by path or URL without scanning the whole collection.
50
48
  */
51
49
  export interface CanopyBuildContext {
52
50
  /**
53
- * Build a content tree from the schema and filesystem entries.
51
+ * Build a content tree from the schema and filesystem entries. Supply
52
+ * TEntryTypes (entry type name → data shape, typically via
53
+ * `TypeFromEntrySchema<typeof yourSchema>`) for narrowed access to
54
+ * `meta.indexEntry.data` inside `extract`.
54
55
  *
55
- * Supply TEntryTypes (a map of entry type name → data shape, typically
56
- * derived via `TypeFromEntrySchema<typeof yourSchema>`) to get narrowed
57
- * access to `meta.indexEntry.data` inside the `extract` callback.
58
- *
59
- * Path ACLs: on the request-scoped context (`getCanopy()`), entries the current user
60
- * cannot `read` are omitted — from the emitted nodes AND from the `meta.indexEntry`
61
- * handed to `extract`. Collections whose children are all filtered out are pruned.
62
- * On the build context, and on static deployments, nothing is filtered (synthetic admin).
56
+ * Path ACLs: on the request-scoped context (`getCanopy()`), entries the user
57
+ * cannot `read` are omitted from the emitted nodes AND from the
58
+ * `meta.indexEntry` handed to `extract`, and a collection whose children are
59
+ * all filtered out is pruned. On the build context and on static deployments
60
+ * nothing is filtered — the synthetic admin sees everything.
63
61
  */
64
62
  buildContentTree: <T = unknown, TEntryTypes = DefaultEntryTypes>(options?: BuildContentTreeOptions<T, TEntryTypes>) => Promise<ContentTreeNode<T>[]>;
65
63
  /**
66
- * List all content entries as a flat array.
64
+ * Every content entry as a flat array.
67
65
  *
68
- * Path ACLs: on the request-scoped context (`getCanopy()`), entries the current user
69
- * cannot `read` are omitted before `extract` runs. On the build context, and on static
70
- * deployments, nothing is filtered (synthetic admin).
66
+ * Path ACLs: on the request-scoped context (`getCanopy()`), entries the user
67
+ * cannot `read` are omitted before `extract` runs; on the build context and
68
+ * static deployments nothing is filtered.
71
69
  *
72
- * Branch: unlike `read`/`readByUrlPath`, this takes no `branch` option — it always lists
73
- * `defaultActiveBranch ?? defaultBaseBranch ?? 'main'`. In `dev` that tracks the git HEAD
74
- * via `refreshActiveBranch()`; in `prod` that refresh is a no-op, so this always reads the
75
- * base branch. See `.claude/future-tasks/context-listing-branch-pinning.md`.
70
+ * Branch: unlike `read`/`readByUrlPath` this takes no `branch` option, always
71
+ * listing `defaultActiveBranch ?? defaultBaseBranch ?? 'main'`. In `dev` that
72
+ * tracks git HEAD via `refreshActiveBranch()`; in `prod` the refresh is a
73
+ * no-op, so it always reads the base branch. See
74
+ * `.claude/future-tasks/context-listing-branch-pinning.md`.
76
75
  */
77
76
  listEntries: <T = Record<string, unknown>>(options?: ListEntriesOptions<T>) => Promise<ListEntriesItem<T>[]>;
78
77
  /**
79
- * Content reader (auth context applied automatically — admin at build time).
78
+ * Content reader, with the auth context applied automatically (admin at build
79
+ * time).
80
80
  *
81
- * `meta.physicalPath` is the absolute filesystem path to the resolved entry file.
82
- * It is **server-only** — do not serialize it to the client or embed it in public
83
- * output, as it reveals the deployment's filesystem layout (home dir / EFS mount /
84
- * branch name). Intended for build-time reads of colocated artifacts, e.g.
81
+ * `meta.physicalPath` is the resolved entry file's absolute path, and is
82
+ * **server-only**: never serialize it to the client or embed it in public
83
+ * output, since it reveals the deployment's filesystem layout (home dir, EFS
84
+ * mount, branch name). It is for build-time reads of colocated artifacts, e.g.
85
85
  * `fs.readFile(path.join(path.dirname(result.meta.physicalPath), 'profile.json'))`.
86
86
  */
87
87
  read: <T = unknown>(input: {
@@ -95,56 +95,33 @@ export interface CanopyBuildContext {
95
95
  meta: ContentReadMeta;
96
96
  }>;
97
97
  /**
98
- * Read content by URL path, resolving the collection/entry split automatically.
99
- *
100
- * Tries direct entry match first (last segment = slug, rest = collection path),
101
- * then falls back to index entry (full path = collection, slug = 'index'). Both attempts
102
- * require the collection part to be a real collection — see below.
103
- * Root path '/' resolves to the content root's index entry.
98
+ * Read content by URL path, resolving the collection/entry split itself: a
99
+ * direct entry match first (last segment = slug, rest = collection path),
100
+ * then the index entry (full path = collection, slug = 'index'). Both need a
101
+ * real collection for the collection part; root '/' is the content root's
102
+ * index entry.
104
103
  *
105
- * Resolves ONLY what `listEntries` publishes — `readByUrlPath(item.urlPath)` reaches the entry,
106
- * and no other spelling does. Three shapes that used to resolve are therefore null now:
107
- * `/x/index` (the literal spelling of an index entry's collapsed URL, in any case),
108
- * `/<collection>/<entryTypeName>` and `/<collection>/<entryTypeName>/<slug>` (an entry-type
109
- * path is not a collection, so it is not part of any published URL), and an entry whose
110
- * on-disk type token its collection does not declare (`listEntries` skips those too). A
111
- * collection literally named `index` is unaffected — the index fallback resolves it.
104
+ * Resolves ONLY what `listEntries` publishes — `readByUrlPath(item.urlPath)`
105
+ * reaches the entry and no other spelling does; a collection literally named
106
+ * `index` still resolves, via the index fallback. `read({ entryPath })` is
107
+ * deliberately NOT narrowed this way: a schema path is a different question
108
+ * from a published URL, and reaches a singleton whose slug nobody knows.
112
109
  *
113
- * `read({ entryPath: 'content/home' })` is deliberately NOT narrowed: addressing an entry
114
- * structurally, by its schema path, is a different question from addressing it by its
115
- * published URL, and it is the only way to reach a singleton without knowing its slug.
110
+ * Null when nothing matches — a collection URL with no index entry (use
111
+ * buildContentTree), a non-entry path like `/favicon.ico` the slug validator
112
+ * rejects, or a path the user may not read, so a FORBIDDEN denial renders as
113
+ * a 404 via `notFound()` rather than a 500. Strict `read()` still throws.
116
114
  *
117
- * Returns null if no content matches the path — including collection URLs that have no
118
- * index entry (use buildContentTree for those) and non-entry/invalid paths such as
119
- * `/favicon.ico` or Next internals (the slug validator rejects them, treated as a miss).
120
- * Also returns null for paths the current user is not permitted to read (a FORBIDDEN
121
- * denial renders as a 404 via `notFound()` instead of a 500); the strict `read()` API
122
- * still throws on permission errors.
123
- *
124
- * The result's `meta.physicalPath` is the absolute filesystem path to the resolved
125
- * entry file. It is **server-only** — do not serialize it to the client or embed it
126
- * in public output, as it reveals the deployment's filesystem layout (home dir / EFS
127
- * mount / branch name). Intended for build-time reads of colocated artifacts.
128
- *
129
- * `meta.entryType` and `meta.entryId` are also resolved for free (path resolution
130
- * already derives them) — useful for entry-type-based dispatch in a single
131
- * catch-all route without a separate `listEntries` lookup or filename parse. See
132
- * `ContentReadMeta` (content-reader.ts) before branching on `entryType` for a legacy
133
- * file: `entryId === undefined` signals that `entryType` is a fallback, not a read.
115
+ * `meta.physicalPath` is **server-only**, for the reason given on `read`.
116
+ * `meta.entryType`/`entryId` come free with path resolution, so one catch-all
117
+ * route can dispatch on entry type with no extra lookup; check
118
+ * `ContentReadMeta` first — `entryId === undefined` marks `entryType` a
119
+ * fallback, not a read.
134
120
  *
135
121
  * @example
136
122
  * ```ts
137
- * // URL /docs/guides/getting-started → reads content/docs/guides + slug "getting-started"
138
- * // URL /docs/guides → reads content/docs/guides + slug "index"
139
- * // URL / → reads content root + slug "index"
140
- * const result = await canopy.readByUrlPath<DocContent>('/docs/guides/getting-started')
141
- * if (result) {
142
- * const { data, path } = result
143
- * switch (result.meta.entryType) {
144
- * case 'home': return <HomePage data={data} />
145
- * default: return <DocView data={data} />
146
- * }
147
- * }
123
+ * const result = await canopy.readByUrlPath<DocContent>('/docs/guides/intro')
124
+ * if (result?.meta.entryType === 'home') return <HomePage data={result.data} />
148
125
  * ```
149
126
  */
150
127
  readByUrlPath: <T = unknown>(urlPath: string, options?: {
@@ -163,15 +140,11 @@ export interface CanopyContext extends CanopyBuildContext {
163
140
  user: CanopyUser;
164
141
  }
165
142
  /**
166
- * Create a Canopy context that manages auth + content reading.
167
- * Framework-agnostic - the adapter provides the extractUser function.
168
- *
169
- * User extractor should apply bootstrap admin groups (via authResultToCanopyUser).
143
+ * Create a Canopy context managing auth + content reading. Framework-agnostic:
144
+ * the adapter supplies extractUser.
170
145
  *
171
- * NOTE: This function is synchronous because in practice, services are always
172
- * provided pre-created (async) by the framework adapter. The fallback path
173
- * that creates services from config cannot work correctly since createCanopyServices
174
- * is now async. Always pass services, not config.
146
+ * Synchronous, and takes pre-created `services` rather than config — building
147
+ * services is async, so there is no working fallback path from config here.
175
148
  */
176
149
  export declare function createCanopyContext(options: CanopyContextOptions): {
177
150
  getContext: () => Promise<CanopyContext>;