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,7 +1,5 @@
1
1
  /**
2
2
  * Shared content-listing utilities used by both the entries API and the content tree builder.
3
- *
4
- * Extracted from api/entries.ts to avoid duplication.
5
3
  */
6
4
  import fs from 'node:fs/promises';
7
5
  import path from 'node:path';
@@ -17,10 +15,7 @@ import { createDebugLogger } from './utils/debug.js';
17
15
  import { ContentStore, ContentStoreError, createReferenceResolveCache, } from './content-store.js';
18
16
  import { isBuildMode } from './build-mode.js';
19
17
  const log = createDebugLogger({ prefix: 'ContentListing' });
20
- /**
21
- * Validate and normalize a path relative to root.
22
- * Throws ContentStoreError on traversal attempt.
23
- */
18
+ /** Validate and normalize `target` under `root`; throws ContentStoreError on a traversal. */
24
19
  const normalizePath = (root, target) => {
25
20
  const result = validateAndNormalizePath(root, target);
26
21
  if (!result.valid) {
@@ -29,13 +24,11 @@ const normalizePath = (root, target) => {
29
24
  return result.normalizedPath;
30
25
  };
31
26
  /**
32
- * Read entry data from a file.
33
- * For md/mdx: returns frontmatter fields plus the body content (mapped to the
34
- * field name specified by `bodyFieldName`, which defaults to `'body'`).
35
- * For json: returns the parsed JSON object.
36
- * Returns an empty object on read/parse failure.
27
+ * Read entry data from a file. For md/mdx: frontmatter fields plus the body content under
28
+ * `bodyFieldName` (defaults to `'body'`); for json/yaml, the parsed object. Returns an empty
29
+ * object on read/parse failure.
37
30
  */
38
- export const readEntryData = async (filePath, format, bodyFieldName = 'body') => {
31
+ const readEntryData = async (filePath, format, bodyFieldName = 'body') => {
39
32
  try {
40
33
  const raw = await fs.readFile(filePath, 'utf8');
41
34
  if (format === 'json') {
@@ -51,13 +44,10 @@ export const readEntryData = async (filePath, format, bodyFieldName = 'body') =>
51
44
  // Copy before writing the body in. gray-matter keeps a PROCESS-GLOBAL cache keyed by file
52
45
  // content and hands every caller the same `data` object instance, so mutating it in place
53
46
  // wrote the body into a shared object that later, unrelated `matter()` calls then saw as
54
- // frontmatter. Concretely, before this copy: listing a collection that contains an md entry
55
- // poisoned the cache, and a subsequent reference resolution to that same entry — which goes
56
- // through `ContentStore.read()`, whose md branch calls `matter()` again — returned the body
57
- // as a frontmatter field. So a resolved md snippet came back WITH `body` on a whole-site
58
- // listing and WITHOUT it on one scoped past its own collection: the same entry, two shapes,
59
- // decided by unrelated scoping. Regression coverage lives with the reference-resolution
60
- // tests in content-listing.test.ts.
47
+ // frontmatter: listing a collection containing an md entry poisoned the cache, and a
48
+ // reference resolution to that same entry (through `ContentStore.read()`, whose md branch
49
+ // calls `matter()` again) returned the body as a frontmatter field -- one entry with two
50
+ // shapes, decided by unrelated listing scope.
61
51
  const data = { ...(parsed.data ?? {}) };
62
52
  if (parsed.content) {
63
53
  data[bodyFieldName] = parsed.content;
@@ -71,30 +61,25 @@ export const readEntryData = async (filePath, format, bodyFieldName = 'body') =>
71
61
  return {};
72
62
  }
73
63
  };
74
- // `parseTypedFilename` now lives in utils/typed-filename.ts so dependency-light modules can
75
- // use it without importing this one (which pulls in ContentStore). Re-exported here because
76
- // this is where callers -- and `canopycms/server` -- have always imported it from.
64
+ // `parseTypedFilename` lives in utils/typed-filename.ts so dependency-light modules can use it
65
+ // without importing this one (which pulls in ContentStore). Re-exported here because callers --
66
+ // and `canopycms/server` -- import it from here.
77
67
  export { parseTypedFilename } from './utils/typed-filename.js';
78
68
  import { parseTypedFilename } from './utils/typed-filename.js';
79
- // ---------------------------------------------------------------------------
80
- // Reference resolution for batch listings
81
- // ---------------------------------------------------------------------------
82
69
  /**
83
70
  * Build the `ContentStore` + shared cache that a batch listing resolves references through.
84
71
  *
85
72
  * Unrelated to the `ReferenceResolver` class in reference-resolver.ts despite the adjacent
86
- * name — that one resolves an id to a human-readable *display label* for the editor UI. This
87
- * resolves a reference to the referenced entry's *data* for server-side listings.
73
+ * name — that one resolves an id to a human-readable display label for the editor UI.
88
74
  *
89
- * Constructed lazily by each listing surface, and ONLY when the caller opted in — a store
75
+ * Constructed lazily by each listing surface, and ONLY when the caller opted in: a store
90
76
  * builds a ContentId index on first use, which is a full scan of the content tree, and the
91
77
  * default (`resolveReferences` off) must stay a pure filesystem walk with no index at all.
92
78
  *
93
- * One store and one cache per listing call, not per collection: the cache is the reason a
79
+ * One store and one cache per listing CALL, not per collection: the cache is the reason a
94
80
  * shared block referenced from 40 pages costs one read instead of 40, so it has to span the
95
- * whole batch. Per-call construction is the established shape here — content-reader.ts's
96
- * `resolveStore` builds a store per read, and content-index-registry.ts holds stores through
97
- * `WeakRef` + a `FinalizationRegistry` precisely so short-lived instances stay collectable.
81
+ * whole batch. content-index-registry.ts holds stores through `WeakRef` + a
82
+ * `FinalizationRegistry`, so these short-lived instances stay collectable.
98
83
  */
99
84
  export const createReferenceResolver = (branchRoot, flatSchema, contentRootName) => ({
100
85
  store: new ContentStore(branchRoot, flatSchema, { contentRootName }),
@@ -118,46 +103,33 @@ export const resolveCollectionItemReferences = async (items, collection, resolve
118
103
  };
119
104
  }));
120
105
  /**
121
- * List all content entries as a flat array.
106
+ * List all content entries as a flat array: walks the schema to discover collections, reads
107
+ * entries from each, and returns a flat list suitable for generateStaticParams, search
108
+ * indexing, sitemaps, etc.
122
109
  *
123
- * Walks the schema to discover collections, reads entries from each,
124
- * and returns a flat list suitable for generateStaticParams, search indexing, sitemaps, etc.
110
+ * Build-time-only failure: a file with a recognized content extension sitting in a collection
111
+ * directory that *looks like an attempted entry* (see `looksLikeMalformedEntry`) but does not
112
+ * match `{type}.{slug}.{id}.{ext}` is silently dropped by default. That is exactly the
113
+ * silent-page-loss static generation must not have -- a schema rename without a matching file
114
+ * rename, or an entry type declared in one collection but not another, would vanish a page with
115
+ * zero build output -- so when `isBuildMode()` is true any such file throws instead
116
+ * (`static/index.ts`'s `assertBuildEntriesValid` is the sibling schema-validity guard).
117
+ * Outside build mode (admin UI, content tree, `next dev`) it is still skipped, since a fresh
118
+ * scaffold or mid-rename file legitimately exists there.
125
119
  *
126
- * Build-time-only failure: a file with a recognized content extension (`.md`/`.mdx`/`.json`/
127
- * `.yaml`) sitting in a collection directory that *looks like an attempted entry* (see
128
- * `looksLikeMalformedEntry` below) but doesn't match `{type}.{slug}.{id}.{ext}` is, by default,
129
- * silently dropped (see `listCollectionEntries`'s debug-gated warning). That is exactly the
130
- * silent-page-loss failure mode static generation must not have — a schema rename without a
131
- * matching file rename, or an entry type declared in one collection but not another, would
132
- * otherwise vanish a page with zero build output. So when `isBuildMode()` is true, any such file
133
- * turns the listing into a thrown error instead (see `findInvalidEntries`/`assertBuildEntriesValid`
134
- * in `static/index.ts` for the sibling schema-validity guard this mirrors). Outside build mode
135
- * (admin UI, content tree, `next dev`) the file is still just skipped, since a fresh scaffold or
136
- * mid-rename file legitimately exists there.
137
- *
138
- * A file that was never entry-shaped to begin with — a `README.md`, or a colocated sibling
139
- * artifact named `{contentId}.suffix.ext` per the `entryTransforms`/`readSibling` convention
140
- * documented in the README — is not this guard's failure mode and never throws, in or out of
141
- * build mode. See `looksLikeMalformedEntry` for the exact shape test.
142
- *
143
- * @param branchRoot - Absolute path to the branch workspace root
144
- * @param flatSchema - Flattened schema items (from flattenSchema)
145
- * @param contentRootName - The content root name (e.g. "content")
146
- * @param options - Listing options (extract, filter, rootPath, sort, resolveReferences)
147
- * @param visibility - Internal path-ACL predicate; see `ContentVisibilityOptions`
120
+ * A file that was never entry-shaped -- a `README.md`, or a colocated sibling artifact named
121
+ * `{contentId}.suffix.ext` per the `entryTransforms`/`readSibling` convention -- never throws.
148
122
  */
149
123
  export async function listEntries(branchRoot, flatSchema, contentRootName, options, visibility) {
150
124
  const rootPath = options?.rootPath ?? contentRootName;
151
125
  const extract = options?.extract;
152
126
  const filter = options?.filter;
153
127
  const customSort = options?.sort;
154
- // Find all collections under rootPath
155
128
  const collections = flatSchema.filter((item) => item.type === 'collection' &&
156
129
  item.entries !== undefined &&
157
130
  (item.logicalPath === rootPath || item.logicalPath.startsWith(`${rootPath}/`)));
158
- // List entries from all collections in parallel.
159
- // The visibility predicate is applied here, before the map below, so a denied entry's
160
- // data never reaches `extract` (let alone the returned items).
131
+ // List entries from all collections in parallel. The visibility predicate is applied here,
132
+ // before the map below, so a denied entry's data never reaches `extract`.
161
133
  const shouldInclude = visibility?.shouldInclude;
162
134
  const skippedFiles = [];
163
135
  // One store + cache for the whole call, or nothing at all when the caller did not opt in.
@@ -176,10 +148,9 @@ export async function listEntries(branchRoot, flatSchema, contentRootName, optio
176
148
  : visible;
177
149
  return resolved.map((entry) => ({ entry, collection }));
178
150
  }));
179
- // Build-time only: fail loudly rather than silently shipping a build with a page missing. See
180
- // the build-time-only-failure note in this function's own doc comment above. Only files that
181
- // structurally look like a malformed entry reach `skippedFiles` at all -- see
182
- // `looksLikeMalformedEntry` and `listCollectionEntries`.
151
+ // Build-time only: fail loudly rather than silently shipping a build with a page missing --
152
+ // see this function's doc comment. Only files that structurally look like a malformed entry
153
+ // reach `skippedFiles` (see `looksLikeMalformedEntry`).
183
154
  if (isBuildMode() && skippedFiles.length > 0) {
184
155
  const lines = skippedFiles.map(({ filename, collectionPath }) => ` - ${collectionPath}/${filename}`);
185
156
  throw new Error(`CanopyCMS static build: found ${skippedFiles.length} file(s) that look like malformed ` +
@@ -193,26 +164,22 @@ export async function listEntries(branchRoot, flatSchema, contentRootName, optio
193
164
  'segments (id.suffix.ext) so it is never mistaken for an entry attempt. Otherwise rename ' +
194
165
  'or move the file, or fix the schema, then rebuild.');
195
166
  }
196
- // Flatten and map to ListEntriesItem
197
167
  const contentPrefix = contentRootName ? `${contentRootName}/` : '';
198
168
  const items = [];
199
169
  for (const results of collectionResults) {
200
170
  for (const { entry, collection } of results) {
201
- // Compute pathSegments: strip content root prefix, split on /
202
171
  const pathWithoutRoot = entry.logicalPath.startsWith(contentPrefix)
203
172
  ? entry.logicalPath.slice(contentPrefix.length)
204
173
  : entry.logicalPath;
205
174
  const pathSegments = pathWithoutRoot.split('/').filter(Boolean);
206
- // Compute urlPath (collapses an `index` entry to its parent collection path) through
207
- // the SHARED rule rather than a local copy of it. A resolved reference now carries a
208
- // `urlPath` too, and the whole point of that field is that it addresses the same entry
209
- // this listing does, so the two must not be free to drift apart.
175
+ // Compute urlPath (collapsing an `index` entry to its parent collection path) through
176
+ // the SHARED rule rather than a local copy: a resolved reference carries a `urlPath`
177
+ // that must address the same entry this listing does, so the two must not drift apart.
210
178
  //
211
- // One deliberate copy of this rule remains: `content-tree.ts`'s `defaultBuildPath`,
212
- // which is exported for adopters to extend and also handles the collection case
213
- // `computeEntryUrl` does not model. It agrees today; folding it in is tracked in
179
+ // One deliberate copy of the rule remains: `content-tree.ts`'s `defaultBuildPath`,
180
+ // exported for adopters to extend and also handling the collection case
181
+ // `computeEntryUrl` does not model. Folding it in is tracked in
214
182
  // `.claude/future-tasks/default-build-path-url-rule-copy.md`.
215
- // `content-listing.test.ts` pins the listing-vs-resolved-reference agreement.
216
183
  const urlPath = computeEntryUrl(entry.collectionPath, entry.slug, contentRootName);
217
184
  const raw = entry.data;
218
185
  const meta = {
@@ -249,15 +216,9 @@ export async function listEntries(branchRoot, flatSchema, contentRootName, optio
249
216
  }
250
217
  return items;
251
218
  }
252
- // ---------------------------------------------------------------------------
253
- // Shared utilities
254
- // ---------------------------------------------------------------------------
255
219
  /**
256
- * Sort items by a content ID order array.
257
- * Items in the order array come first (in order), items not in the array come at the end
258
- * sorted by the provided fallback key.
259
- *
260
- * Note: sorts the array in-place and returns it.
220
+ * Sort items by a content ID order array: items in `order` come first, in that order, then
221
+ * the rest sorted by `fallbackKey`. Sorts the array in place and returns it.
261
222
  */
262
223
  export const sortByOrder = (items, order, fallbackKey) => {
263
224
  if (!order || order.length === 0) {
@@ -278,32 +239,26 @@ export const sortByOrder = (items, order, fallbackKey) => {
278
239
  });
279
240
  };
280
241
  /**
281
- * True when a content-extension filename structurally resembles an attempted entry — as opposed
282
- * to a file that was never entry-shaped to begin with.
242
+ * True when a content-extension filename structurally resembles an attempted entry — as
243
+ * opposed to a file that was never entry-shaped to begin with.
283
244
  *
284
- * A successfully-parsed entry always has at least 4 dot-separated segments: `type` (1+),
285
- * `slug` (1+, since `parseTypedFilename` always takes at least the one segment between type and
286
- * id), `id` (1), `ext` (1). So a file with 4+ segments that still failed to parse is malformed
287
- * on its face — a wrong-length or invalid-Base58 ID, most often (`post.hello-world.BADID.md`).
245
+ * A successfully-parsed entry always has at least 4 dot-separated segments (type, slug, id,
246
+ * ext), so a 4+-segment file that still failed to parse is malformed on its face -- usually a
247
+ * wrong-length or invalid-Base58 ID (`post.hello-world.BADID.md`).
288
248
  *
289
- * That segment-count test alone missed the MORE common accident: losing the ID segment
290
- * entirely. `post.hello-world.md` (3 segments) fails `parseTypedFilename` exactly like the
291
- * 4-segment case does, but a bare 3-or-fewer-segment cutoff would treat it as never having been
292
- * entry-shaped and drop it silently — the page just vanishes with a green build. So a 3-segment
293
- * file whose FIRST segment matches a real entry type name in this collection is ALSO treated as
294
- * malformed: `parseTypedFilename` requires type+slug+id (3 segments) after stripping the
295
- * extension, so a 3-total-segment filename already has only 2 left over — it could only have
296
- * been attempting `type.slug` with no id, or `type.id` with no slug, either way a lost segment,
297
- * not a coincidence. This still leaves the two motivating "was never an entry" cases alone: a
298
- * bare `README.md` (2 segments, and "README" is essentially never a configured entry type name)
299
- * and an entry's colocated sibling artifact named `{contentId}.suffix.ext` per the
300
- * `entryTransforms`/`readSibling` convention documented in the README (3 segments, e.g.
301
- * `5NVkkrB1MJUv.profile.json` — a content ID is never itself an entry type name, so the same
302
- * "first segment matches a known type" test correctly leaves it unflagged).
249
+ * A 3-segment file whose FIRST segment matches a real entry type name in this collection
250
+ * counts too, which catches the more common accident of losing the ID segment entirely
251
+ * (`post.hello-world.md`): `parseTypedFilename` needs type+slug+id after the extension, so 3
252
+ * total segments leave only 2 -- `type.slug` with no id, or `type.id` with no slug, a lost
253
+ * segment rather than a coincidence. That leaves the two "never an entry" cases alone: a bare
254
+ * `README.md` (2 segments, and "README" is essentially never a configured entry type name) and
255
+ * an entry's colocated sibling artifact `{contentId}.suffix.ext` per the
256
+ * `entryTransforms`/`readSibling` convention (3 segments, but a content ID is never a type
257
+ * name).
303
258
  *
304
- * Dot-prefixed (hidden files, editor swap/backup files) and underscore-prefixed (a common
305
- * adopter convention for "not an entry") names are excluded outright regardless of segment
306
- * count, matching `parseTypedFilename`'s own dotfile rejection.
259
+ * Dot-prefixed (hidden files, editor swap/backup files) and underscore-prefixed (an adopter
260
+ * convention for "not an entry") names are excluded outright at any segment count, matching
261
+ * `parseTypedFilename`'s own dotfile rejection.
307
262
  */
308
263
  const looksLikeMalformedEntry = (filename, entryTypes) => {
309
264
  if (filename.startsWith('.') || filename.startsWith('_'))
@@ -314,24 +269,20 @@ const looksLikeMalformedEntry = (filename, entryTypes) => {
314
269
  return segments.length === 3 && entryTypes.some((e) => e.name === segments[0]);
315
270
  };
316
271
  /**
317
- * List all entries in a collection directory.
318
- * Reads each entry's data (frontmatter or JSON).
272
+ * List all entries in a collection directory, reading each entry's data.
319
273
  *
320
- * @param onSkip - Called for every file that has a recognized content extension, doesn't match
321
- * the `{type}.{slug}.{id}.{ext}` grammar (see `parseTypedFilename`), AND structurally looks
322
- * like an attempted entry (see `looksLikeMalformedEntry`). A file that was never entry-shaped
323
- * (too few dot-separated segments to ever be a valid entry — a `README.md`, a colocated
324
- * sibling artifact) is always silently dropped with a debug-gated `log.warn`, never passed to
325
- * `onSkip`. Optional and purely a diagnostic hook — existing callers that omit it keep the
326
- * exact prior behavior. `listEntries` below uses this to turn the skip into a hard build-time
327
- * failure instead of a silent one.
274
+ * `onSkip` is called for every file that has a recognized content extension, does NOT match
275
+ * the `{type}.{slug}.{id}.{ext}` grammar (see `parseTypedFilename`), AND structurally looks
276
+ * like an attempted entry (see `looksLikeMalformedEntry`). A file that was never entry-shaped
277
+ * -- a `README.md`, a colocated sibling artifact -- is always dropped with a debug-gated
278
+ * `log.warn` and never passed to `onSkip`. Optional and purely diagnostic: `listEntries` uses
279
+ * it to turn the skip into a hard build-time failure instead of a silent one.
328
280
  */
329
281
  export const listCollectionEntries = async (root, collection, onSkip) => {
330
282
  if (collection.type !== 'collection' || !collection.entries) {
331
283
  return [];
332
284
  }
333
285
  const entryTypes = collection.entries;
334
- // Build a map of extension to entry types for efficient lookup
335
286
  const extToTypes = new Map();
336
287
  for (const entryType of entryTypes) {
337
288
  const ext = getFormatExtension(entryType.format);
@@ -340,7 +291,6 @@ export const listCollectionEntries = async (root, collection, onSkip) => {
340
291
  extToTypes.set(ext, existing);
341
292
  }
342
293
  const validExts = Array.from(extToTypes.keys());
343
- // Resolve the full collection path with embedded IDs
344
294
  const collectionRoot = await resolveCollectionPath(root, collection.logicalPath);
345
295
  if (!collectionRoot) {
346
296
  return [];
@@ -31,18 +31,16 @@ export interface ReadContentInput {
31
31
  *
32
32
  * 1. `entryPath` must be a COLLECTION. A published URL is `/<collectionSegments>/<slug>` (or
33
33
  * the collapsed collection path, for an index entry), so its non-slug segments are always
34
- * collection names. An `entryPath` that resolves to an entry-TYPE item instead would be
35
- * delegated by `ContentStore.buildPaths` to the parent collection -- answering at
36
- * `/<collection>/<typeName>` and `/<collection>/<typeName>/<slug>`, neither of which any
37
- * forward surface emits.
34
+ * collection names. An `entryPath` resolving to an entry-TYPE item would be delegated by
35
+ * `ContentStore.buildPaths` to the parent collection, answering at URLs no forward surface
36
+ * emits.
38
37
  * 2. The resolved entry's type must be one its collection declares, matching the
39
38
  * `parseTypedFilename(filename, collection.entries)` check `listEntries` applies. A legacy
40
39
  * untyped file has no type token to fail on -- see `declaresEntryType`.
41
40
  *
42
- * Set by `readByUrlPath` and nothing else. Note what it does NOT do: `read({ entryPath:
43
- * 'content/home' })` and direct `ContentStore` use keep the entry-type delegation, which is a
44
- * supported API and the only way to address a singleton structurally. Misusing this flag can
45
- * only make a read stricter, never looser.
41
+ * Set by `readByUrlPath` and nothing else: `read({ entryPath: 'content/home' })` and direct
42
+ * `ContentStore` use keep the entry-type delegation, a supported API and the only way to
43
+ * address a singleton structurally. Misusing this flag can only make a read stricter.
46
44
  */
47
45
  urlAddressableOnly?: boolean;
48
46
  }
@@ -53,35 +51,28 @@ export interface ReadContentInput {
53
51
  */
54
52
  export interface ContentReadMeta {
55
53
  /**
56
- * Absolute filesystem path to the resolved entry file. It is **server-only**
57
- * -- do not serialize it to the client or embed it in public output, as it
58
- * reveals the deployment's filesystem layout (home dir / EFS mount / branch
59
- * name).
54
+ * Absolute filesystem path to the resolved entry file. **Server-only**: do not serialize it
55
+ * to the client or embed it in public output, as it reveals the deployment's filesystem
56
+ * layout (home dir / EFS mount / branch name).
60
57
  */
61
58
  physicalPath: PhysicalPath;
62
59
  /**
63
60
  * The resolved entry type name, read from the entry's own filename
64
- * (`{type}.{slug}.{id}.{ext}`) -- immutable once the file is created, and
65
- * NOT re-validated against the collection's current `entries` config on
66
- * every read. It is therefore usually, but not guaranteed to be, a key in
67
- * the collection's `entries` config: it can diverge if an entry type was
68
- * renamed or removed from the schema after files using the old name were
69
- * created, or if the file was hand-authored with an unrecognized type
70
- * token.
61
+ * (`{type}.{slug}.{id}.{ext}`) -- immutable once the file is created, and NOT re-validated
62
+ * against the collection's current `entries` config on every read. So it is usually, but not
63
+ * guaranteed to be, a key in that config: it diverges when an entry type was renamed or
64
+ * removed from the schema after files using the old name were created, or when the file was
65
+ * hand-authored with an unrecognized type token.
71
66
  *
72
- * For a legacy entry file predating embedded-type filenames (`{slug}.{ext}`),
73
- * there is no type recorded on disk at all -- `entryType` silently falls
74
- * back to the collection's DEFAULT entry type, which may or may not be what
75
- * the file actually is. `entryId` being `undefined` (below) is the signal
76
- * that this happened: when `entryId` is `undefined`, `entryType` is
77
- * inferred rather than read.
67
+ * A legacy entry file (`{slug}.{ext}`) records no type at all, so this falls back to the
68
+ * collection's DEFAULT entry type, which may not be what the file is. `entryId` being
69
+ * `undefined` is the signal that this happened.
78
70
  */
79
71
  entryType: string;
80
72
  /**
81
- * The entry's 12-char Base58 content ID, when the resolved file carries one.
82
- * Undefined only for legacy entry files predating embedded-ID filenames
83
- * (`{slug}.{ext}` rather than `{type}.{slug}.{id}.{ext}`) -- see the
84
- * `entryType` caveat above for what that implies about it.
73
+ * The entry's 12-char Base58 content ID, when the resolved file carries one. Undefined only
74
+ * for legacy entry files predating embedded-ID filenames (`{slug}.{ext}` rather than
75
+ * `{type}.{slug}.{id}.{ext}`) -- see the `entryType` caveat above for what that implies.
85
76
  */
86
77
  entryId?: ContentId;
87
78
  }
@@ -63,7 +63,6 @@ export const createContentReader = (options) => {
63
63
  const resolveStore = async (branchName) => {
64
64
  const context = await resolveBranchContext(branchName);
65
65
  const { branchRoot } = resolveBranchPaths(context, operatingMode, basePathOverride);
66
- // Load per-branch schema dynamically
67
66
  const branchSchemaCache = services.branchSchemaCache;
68
67
  const contentRootName = services.config.contentRoot || 'content';
69
68
  const { flatSchema: branchFlatSchema } = await branchSchemaCache.getSchema(branchRoot, services.entrySchemaRegistry, contentRootName);
@@ -86,24 +85,22 @@ export const createContentReader = (options) => {
86
85
  .filter(Boolean)
87
86
  .map((segment) => encodeURIComponent(segment))
88
87
  .join('/');
89
- // Build preview paths using simple path construction
90
88
  const contentRoot = trimSlashes(services.config.contentRoot ?? 'content');
91
89
  // The `val === contentRoot` branch matters as much as the prefix one: a root-level entry's
92
- // collectionPath IS the content root, which does not start with `${contentRoot}/`, so without
93
- // it the root index reported `path: '/content'` (and a root entry `/content/about`) -- paths
94
- // that resolve to nothing. `computeEntryUrl` has always had both branches; this had one.
90
+ // collectionPath IS the content root, which does not start with `${contentRoot}/`, so
91
+ // without it the root index reports `path: '/content'` (and a root entry `/content/about`)
92
+ // -- paths that resolve to nothing.
95
93
  //
96
94
  // Both branches stay guarded on `contentRoot` so an empty one passes the value through
97
95
  // unchanged, exactly as `computeEntryUrl` does. Unreachable today (`contentRootSchema` is
98
96
  // `relativePathSchema.default('content')` with `.min(1)`), but a blanket short-circuit would
99
- // be the WRONG answer if it ever were reachable -- it would flatten every entry to root.
97
+ // be the WRONG answer if it ever were reachable: it would flatten every entry to root.
100
98
  const stripRoot = (val) => contentRoot && val === contentRoot
101
99
  ? ''
102
100
  : contentRoot && val.startsWith(`${contentRoot}/`)
103
101
  ? val.slice(contentRoot.length + 1)
104
102
  : val;
105
103
  const buildEntryPath = (opts) => {
106
- // Construct preview path from collectionPath
107
104
  const stripped = stripRoot(opts.collectionPath);
108
105
  const base = stripped ? `/${stripped}` : '/';
109
106
  const appendBranch = (url) => opts.branch
@@ -136,21 +133,18 @@ export const createContentReader = (options) => {
136
133
  // for server-side colocated-artifact reads (e.g. a sibling profile.json). Already
137
134
  // computed here for permission checks; just carried through.
138
135
  let physicalPath;
139
- // Entry type + content ID are already resolved as part of path resolution
140
- // (buildPaths() derives both from the schema item / filename) — surfaced on
141
- // read() / readByUrlPath() so callers can route or key by them without a
142
- // separate listEntries lookup or filename parse.
136
+ // Entry type + content ID come out of path resolution (buildPaths() derives both from the
137
+ // schema item / filename), surfaced on read() / readByUrlPath() so callers can route or
138
+ // key by them without a separate listEntries lookup or filename parse.
143
139
  let entryType;
144
140
  let entryId;
145
141
  try {
146
142
  const resolved = await store.resolveDocumentPath(entryPath, slug ?? '');
147
143
  relativePath = resolved.relativePath;
148
144
  physicalPath = resolved.absolutePath;
149
- // resolveDocumentPath() always sets entryTypeName for a valid schema item
150
- // (collection entries fall back to 'entry'; entry-type items delegate to
151
- // their parent collection with their own name), so no further fallback
152
- // is needed here — id is the one field that can be legitimately absent,
153
- // for legacy entry files without an embedded ID (see ContentReadMeta).
145
+ // resolveDocumentPath() always sets entryTypeName for a valid schema item, so no
146
+ // further fallback is needed here; `id` is the one field that can be legitimately
147
+ // absent, for legacy entry files without an embedded ID (see ContentReadMeta).
154
148
  entryType = resolved.entryTypeName;
155
149
  entryId = resolved.id;
156
150
  }
@@ -216,9 +210,7 @@ export const createContentReader = (options) => {
216
210
  const rawData = docRecord.data;
217
211
  const body = docRecord.body;
218
212
  const bodyFieldName = docRecord.bodyFieldName ?? 'body';
219
- // Merge body into data first, then resolve entry links across all fields
220
213
  let data = (body != null ? { ...rawData, [bodyFieldName]: body } : rawData);
221
- // Resolve entry:ID links in all string values (body + nested markdown fields)
222
214
  if (input.resolveEntryLinks ?? true) {
223
215
  const idIndex = await store.idIndex();
224
216
  data = resolveEntryLinksInData(data, idIndex, contentRoot, services.config.entryLinkUrl);