canopycms 0.0.0 → 0.0.1

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 (430) hide show
  1. package/package.json +2 -3
  2. package/dist/__integration__/fixtures/content-seeds.d.ts +0 -43
  3. package/dist/__integration__/fixtures/content-seeds.d.ts.map +0 -1
  4. package/dist/__integration__/fixtures/content-seeds.js +0 -99
  5. package/dist/__integration__/fixtures/content-seeds.js.map +0 -1
  6. package/dist/__integration__/fixtures/schemas.d.ts +0 -12
  7. package/dist/__integration__/fixtures/schemas.d.ts.map +0 -1
  8. package/dist/__integration__/fixtures/schemas.js +0 -65
  9. package/dist/__integration__/fixtures/schemas.js.map +0 -1
  10. package/dist/__integration__/test-utils/api-client.d.ts +0 -123
  11. package/dist/__integration__/test-utils/api-client.d.ts.map +0 -1
  12. package/dist/__integration__/test-utils/api-client.js +0 -118
  13. package/dist/__integration__/test-utils/api-client.js.map +0 -1
  14. package/dist/__integration__/test-utils/multi-user.d.ts +0 -25
  15. package/dist/__integration__/test-utils/multi-user.d.ts.map +0 -1
  16. package/dist/__integration__/test-utils/multi-user.js +0 -105
  17. package/dist/__integration__/test-utils/multi-user.js.map +0 -1
  18. package/dist/__integration__/test-utils/test-workspace.d.ts +0 -25
  19. package/dist/__integration__/test-utils/test-workspace.d.ts.map +0 -1
  20. package/dist/__integration__/test-utils/test-workspace.js +0 -102
  21. package/dist/__integration__/test-utils/test-workspace.js.map +0 -1
  22. package/dist/editor/BranchManager.stories.d.ts +0 -8
  23. package/dist/editor/BranchManager.stories.d.ts.map +0 -1
  24. package/dist/editor/BranchManager.stories.js +0 -74
  25. package/dist/editor/BranchManager.stories.js.map +0 -1
  26. package/dist/editor/CanopyEditor.stories.d.ts +0 -7
  27. package/dist/editor/CanopyEditor.stories.d.ts.map +0 -1
  28. package/dist/editor/CanopyEditor.stories.js +0 -99
  29. package/dist/editor/CanopyEditor.stories.js.map +0 -1
  30. package/dist/editor/CommentsPanel.stories.d.ts +0 -10
  31. package/dist/editor/CommentsPanel.stories.d.ts.map +0 -1
  32. package/dist/editor/CommentsPanel.stories.js +0 -175
  33. package/dist/editor/CommentsPanel.stories.js.map +0 -1
  34. package/dist/editor/Editor.stories.d.ts +0 -7
  35. package/dist/editor/Editor.stories.d.ts.map +0 -1
  36. package/dist/editor/Editor.stories.js +0 -95
  37. package/dist/editor/Editor.stories.js.map +0 -1
  38. package/dist/editor/EditorPanes.stories.d.ts +0 -7
  39. package/dist/editor/EditorPanes.stories.d.ts.map +0 -1
  40. package/dist/editor/EditorPanes.stories.js +0 -116
  41. package/dist/editor/EditorPanes.stories.js.map +0 -1
  42. package/dist/editor/EntryNavigator.stories.d.ts +0 -8
  43. package/dist/editor/EntryNavigator.stories.d.ts.map +0 -1
  44. package/dist/editor/EntryNavigator.stories.js +0 -42
  45. package/dist/editor/EntryNavigator.stories.js.map +0 -1
  46. package/dist/editor/FormRenderer.stories.d.ts +0 -7
  47. package/dist/editor/FormRenderer.stories.d.ts.map +0 -1
  48. package/dist/editor/FormRenderer.stories.js +0 -115
  49. package/dist/editor/FormRenderer.stories.js.map +0 -1
  50. package/dist/editor/GroupManager.stories.d.ts +0 -19
  51. package/dist/editor/GroupManager.stories.d.ts.map +0 -1
  52. package/dist/editor/GroupManager.stories.js +0 -265
  53. package/dist/editor/GroupManager.stories.js.map +0 -1
  54. package/dist/editor/PermissionManager.stories.d.ts +0 -20
  55. package/dist/editor/PermissionManager.stories.d.ts.map +0 -1
  56. package/dist/editor/PermissionManager.stories.js +0 -506
  57. package/dist/editor/PermissionManager.stories.js.map +0 -1
  58. package/dist/editor/comments/FieldWrapper.stories.d.ts +0 -10
  59. package/dist/editor/comments/FieldWrapper.stories.d.ts.map +0 -1
  60. package/dist/editor/comments/FieldWrapper.stories.js +0 -173
  61. package/dist/editor/comments/FieldWrapper.stories.js.map +0 -1
  62. package/dist/editor/fields/BlockField.stories.d.ts +0 -7
  63. package/dist/editor/fields/BlockField.stories.d.ts.map +0 -1
  64. package/dist/editor/fields/BlockField.stories.js +0 -50
  65. package/dist/editor/fields/BlockField.stories.js.map +0 -1
  66. package/dist/editor/fields/fields.stories.d.ts +0 -8
  67. package/dist/editor/fields/fields.stories.d.ts.map +0 -1
  68. package/dist/editor/fields/fields.stories.js +0 -34
  69. package/dist/editor/fields/fields.stories.js.map +0 -1
  70. package/dist/test-utils/api-test-helpers.d.ts +0 -238
  71. package/dist/test-utils/api-test-helpers.d.ts.map +0 -1
  72. package/dist/test-utils/api-test-helpers.js +0 -347
  73. package/dist/test-utils/api-test-helpers.js.map +0 -1
  74. package/dist/test-utils/console-spy.d.ts +0 -56
  75. package/dist/test-utils/console-spy.d.ts.map +0 -1
  76. package/dist/test-utils/console-spy.js +0 -81
  77. package/dist/test-utils/console-spy.js.map +0 -1
  78. package/dist/test-utils/git-helpers.d.ts +0 -21
  79. package/dist/test-utils/git-helpers.d.ts.map +0 -1
  80. package/dist/test-utils/git-helpers.js +0 -23
  81. package/dist/test-utils/git-helpers.js.map +0 -1
  82. package/dist/test-utils/index.d.ts +0 -5
  83. package/dist/test-utils/index.d.ts.map +0 -1
  84. package/dist/test-utils/index.js +0 -4
  85. package/dist/test-utils/index.js.map +0 -1
  86. package/src/__integration__/errors/invalid-content.test.ts +0 -238
  87. package/src/__integration__/errors/permission-denied.test.ts +0 -220
  88. package/src/__integration__/fixtures/content-seeds.ts +0 -105
  89. package/src/__integration__/fixtures/schemas.ts +0 -67
  90. package/src/__integration__/initialization/prod-sim-init.test.ts +0 -139
  91. package/src/__integration__/permissions/path-permissions.test.ts +0 -314
  92. package/src/__integration__/permissions/role-permissions.test.ts +0 -354
  93. package/src/__integration__/permissions/settings-branch-isolation.test.ts +0 -317
  94. package/src/__integration__/settings/groups-api.test.ts +0 -403
  95. package/src/__integration__/test-utils/api-client.ts +0 -167
  96. package/src/__integration__/test-utils/multi-user.ts +0 -129
  97. package/src/__integration__/test-utils/test-workspace.ts +0 -130
  98. package/src/__integration__/user/user-context.test.ts +0 -174
  99. package/src/__integration__/validation/input-validation.test.ts +0 -166
  100. package/src/__integration__/workflows/api-editing-workflow.test.ts +0 -244
  101. package/src/__integration__/workflows/conflict-resolution.test.ts +0 -259
  102. package/src/__integration__/workflows/editing-workflow.test.ts +0 -205
  103. package/src/__integration__/workflows/review-workflow.test.ts +0 -260
  104. package/src/ai/__tests__/build.integration.test.ts +0 -224
  105. package/src/ai/__tests__/generate.integration.test.ts +0 -495
  106. package/src/ai/__tests__/handler.integration.test.ts +0 -212
  107. package/src/ai/__tests__/json-to-markdown.test.ts +0 -553
  108. package/src/ai/generate.ts +0 -410
  109. package/src/ai/handler.ts +0 -123
  110. package/src/ai/index.ts +0 -26
  111. package/src/ai/json-to-markdown.ts +0 -424
  112. package/src/ai/resolve-branch.ts +0 -34
  113. package/src/ai/types.ts +0 -160
  114. package/src/api/AGENTS.md +0 -81
  115. package/src/api/__test__/mock-client.ts +0 -404
  116. package/src/api/assets.test.ts +0 -140
  117. package/src/api/assets.ts +0 -154
  118. package/src/api/branch-merge.test.ts +0 -163
  119. package/src/api/branch-merge.ts +0 -113
  120. package/src/api/branch-review.test.ts +0 -297
  121. package/src/api/branch-review.ts +0 -136
  122. package/src/api/branch-status.test.ts +0 -85
  123. package/src/api/branch-status.ts +0 -153
  124. package/src/api/branch-withdraw.test.ts +0 -146
  125. package/src/api/branch-withdraw.ts +0 -81
  126. package/src/api/branch-workflow.integration.test.ts +0 -578
  127. package/src/api/branch.test.ts +0 -620
  128. package/src/api/branch.ts +0 -492
  129. package/src/api/client.test.ts +0 -349
  130. package/src/api/client.ts +0 -506
  131. package/src/api/comments.test.ts +0 -285
  132. package/src/api/comments.ts +0 -210
  133. package/src/api/content.test.ts +0 -345
  134. package/src/api/content.ts +0 -454
  135. package/src/api/entries.test.ts +0 -1339
  136. package/src/api/entries.ts +0 -650
  137. package/src/api/github-sync.ts +0 -144
  138. package/src/api/groups.test.ts +0 -1013
  139. package/src/api/groups.ts +0 -375
  140. package/src/api/guards.test.ts +0 -533
  141. package/src/api/guards.ts +0 -271
  142. package/src/api/index.ts +0 -87
  143. package/src/api/permissions.test.ts +0 -766
  144. package/src/api/permissions.ts +0 -334
  145. package/src/api/reference-options.ts +0 -118
  146. package/src/api/resolve-references.ts +0 -107
  147. package/src/api/route-builder.ts +0 -289
  148. package/src/api/schema.test.ts +0 -840
  149. package/src/api/schema.ts +0 -936
  150. package/src/api/security.test.ts +0 -233
  151. package/src/api/settings-helpers.ts +0 -84
  152. package/src/api/types.ts +0 -40
  153. package/src/api/user.test.ts +0 -127
  154. package/src/api/user.ts +0 -42
  155. package/src/api/validators.test.ts +0 -275
  156. package/src/api/validators.ts +0 -176
  157. package/src/asset-store.test.ts +0 -37
  158. package/src/asset-store.ts +0 -110
  159. package/src/auth/cache.ts +0 -7
  160. package/src/auth/caching-auth-plugin.test.ts +0 -154
  161. package/src/auth/caching-auth-plugin.ts +0 -109
  162. package/src/auth/context-helpers.ts +0 -75
  163. package/src/auth/file-based-auth-cache.test.ts +0 -257
  164. package/src/auth/file-based-auth-cache.ts +0 -279
  165. package/src/auth/index.ts +0 -12
  166. package/src/auth/plugin.ts +0 -51
  167. package/src/auth/types.ts +0 -38
  168. package/src/authorization/__tests__/branch.test.ts +0 -260
  169. package/src/authorization/__tests__/content.test.ts +0 -142
  170. package/src/authorization/__tests__/path.test.ts +0 -133
  171. package/src/authorization/__tests__/permissions-loader.test.ts +0 -200
  172. package/src/authorization/branch.ts +0 -94
  173. package/src/authorization/content.ts +0 -93
  174. package/src/authorization/groups/index.ts +0 -11
  175. package/src/authorization/groups/loader.ts +0 -127
  176. package/src/authorization/groups/schema.ts +0 -48
  177. package/src/authorization/helpers.ts +0 -48
  178. package/src/authorization/index.ts +0 -84
  179. package/src/authorization/path.ts +0 -112
  180. package/src/authorization/permissions/index.ts +0 -11
  181. package/src/authorization/permissions/loader.ts +0 -116
  182. package/src/authorization/permissions/schema.ts +0 -66
  183. package/src/authorization/test-utils.ts +0 -15
  184. package/src/authorization/types.ts +0 -66
  185. package/src/authorization/validation.test.ts +0 -100
  186. package/src/authorization/validation.ts +0 -62
  187. package/src/branch-metadata.test.ts +0 -168
  188. package/src/branch-metadata.ts +0 -166
  189. package/src/branch-registry.test.ts +0 -248
  190. package/src/branch-registry.ts +0 -152
  191. package/src/branch-schema-cache.test.ts +0 -275
  192. package/src/branch-schema-cache.ts +0 -189
  193. package/src/branch-workspace.test.ts +0 -183
  194. package/src/branch-workspace.ts +0 -124
  195. package/src/build/generate-ai-content.ts +0 -78
  196. package/src/build/index.ts +0 -8
  197. package/src/build-mode.ts +0 -27
  198. package/src/cli/generate-ai-content.ts +0 -100
  199. package/src/cli/init.test.ts +0 -240
  200. package/src/cli/templates/Dockerfile.cms.template +0 -19
  201. package/src/cli/templates/canopy.ts.template +0 -55
  202. package/src/cli/templates/canopycms.config.ts.template +0 -11
  203. package/src/cli/templates/deploy-cms.yml.template +0 -27
  204. package/src/cli/templates/edit-page.tsx.template +0 -32
  205. package/src/cli/templates/route.ts.template +0 -12
  206. package/src/cli/templates/schemas.ts.template +0 -16
  207. package/src/cli/templates.ts +0 -47
  208. package/src/client.ts +0 -12
  209. package/src/comment-store.test.ts +0 -442
  210. package/src/comment-store.ts +0 -301
  211. package/src/config/__tests__/config.test.ts +0 -513
  212. package/src/config/flatten.ts +0 -174
  213. package/src/config/helpers.ts +0 -167
  214. package/src/config/index.ts +0 -86
  215. package/src/config/schemas/collection.ts +0 -67
  216. package/src/config/schemas/config.ts +0 -77
  217. package/src/config/schemas/field.ts +0 -108
  218. package/src/config/schemas/media.ts +0 -27
  219. package/src/config/schemas/permissions.ts +0 -21
  220. package/src/config/types.ts +0 -321
  221. package/src/config/validation.ts +0 -70
  222. package/src/config-test.ts +0 -65
  223. package/src/config.ts +0 -11
  224. package/src/content-id-index.test.ts +0 -512
  225. package/src/content-id-index.ts +0 -479
  226. package/src/content-reader.test.ts +0 -478
  227. package/src/content-reader.ts +0 -214
  228. package/src/content-store.test.ts +0 -1126
  229. package/src/content-store.ts +0 -793
  230. package/src/context.ts +0 -111
  231. package/src/editor/BranchManager.stories.tsx +0 -80
  232. package/src/editor/BranchManager.test.tsx +0 -324
  233. package/src/editor/BranchManager.tsx +0 -461
  234. package/src/editor/CanopyEditor.stories.tsx +0 -128
  235. package/src/editor/CanopyEditor.test.tsx +0 -81
  236. package/src/editor/CanopyEditor.tsx +0 -73
  237. package/src/editor/CanopyEditorPage.test.tsx +0 -59
  238. package/src/editor/CanopyEditorPage.tsx +0 -25
  239. package/src/editor/CommentsPanel.stories.tsx +0 -184
  240. package/src/editor/CommentsPanel.tsx +0 -338
  241. package/src/editor/Editor.integration.test.tsx +0 -227
  242. package/src/editor/Editor.stories.tsx +0 -119
  243. package/src/editor/Editor.tsx +0 -1221
  244. package/src/editor/EditorPanes.stories.tsx +0 -256
  245. package/src/editor/EditorPanes.test.tsx +0 -77
  246. package/src/editor/EditorPanes.tsx +0 -180
  247. package/src/editor/EntryNavigator.stories.tsx +0 -65
  248. package/src/editor/EntryNavigator.test.tsx +0 -598
  249. package/src/editor/EntryNavigator.tsx +0 -665
  250. package/src/editor/FormRenderer.stories.tsx +0 -212
  251. package/src/editor/FormRenderer.test.tsx +0 -194
  252. package/src/editor/FormRenderer.tsx +0 -432
  253. package/src/editor/GroupManager.stories.tsx +0 -301
  254. package/src/editor/GroupManager.test.tsx +0 -682
  255. package/src/editor/GroupManager.tsx +0 -9
  256. package/src/editor/PermissionManager.stories.tsx +0 -539
  257. package/src/editor/PermissionManager.test.tsx +0 -864
  258. package/src/editor/PermissionManager.tsx +0 -12
  259. package/src/editor/canopy-path.test.ts +0 -23
  260. package/src/editor/canopy-path.ts +0 -52
  261. package/src/editor/client-reference-resolver.ts +0 -118
  262. package/src/editor/comments/BranchComments.tsx +0 -93
  263. package/src/editor/comments/EntryComments.tsx +0 -94
  264. package/src/editor/comments/FieldWrapper.stories.tsx +0 -210
  265. package/src/editor/comments/FieldWrapper.tsx +0 -129
  266. package/src/editor/comments/InlineCommentThread.test.tsx +0 -384
  267. package/src/editor/comments/InlineCommentThread.tsx +0 -246
  268. package/src/editor/comments/ThreadCarousel.test.tsx +0 -393
  269. package/src/editor/comments/ThreadCarousel.tsx +0 -525
  270. package/src/editor/components/ConfirmDeleteModal.tsx +0 -49
  271. package/src/editor/components/EditorContext.tsx +0 -49
  272. package/src/editor/components/EditorFooter.tsx +0 -47
  273. package/src/editor/components/EditorHeader.tsx +0 -492
  274. package/src/editor/components/EditorSidebar.tsx +0 -193
  275. package/src/editor/components/EntryCreateModal.tsx +0 -193
  276. package/src/editor/components/RenameEntryModal.tsx +0 -152
  277. package/src/editor/components/UserBadge.test.tsx +0 -274
  278. package/src/editor/components/UserBadge.tsx +0 -240
  279. package/src/editor/components/index.ts +0 -6
  280. package/src/editor/context/ApiClientContext.tsx +0 -56
  281. package/src/editor/context/EditorStateContext.tsx +0 -221
  282. package/src/editor/context/index.ts +0 -40
  283. package/src/editor/editor-config.test.ts +0 -385
  284. package/src/editor/editor-config.ts +0 -94
  285. package/src/editor/editor-utils.test.ts +0 -772
  286. package/src/editor/editor-utils.ts +0 -303
  287. package/src/editor/env.ts +0 -4
  288. package/src/editor/fields/BlockField.stories.tsx +0 -79
  289. package/src/editor/fields/BlockField.tsx +0 -267
  290. package/src/editor/fields/CodeField.tsx +0 -41
  291. package/src/editor/fields/MarkdownField.tsx +0 -205
  292. package/src/editor/fields/ObjectField.tsx +0 -71
  293. package/src/editor/fields/ReferenceField.tsx +0 -138
  294. package/src/editor/fields/SelectField.tsx +0 -76
  295. package/src/editor/fields/TextField.tsx +0 -35
  296. package/src/editor/fields/ToggleField.tsx +0 -37
  297. package/src/editor/fields/fields.stories.tsx +0 -40
  298. package/src/editor/group-manager/ExternalGroupsTab.tsx +0 -114
  299. package/src/editor/group-manager/GroupCard.tsx +0 -102
  300. package/src/editor/group-manager/GroupForm.tsx +0 -66
  301. package/src/editor/group-manager/InternalGroupsTab.tsx +0 -147
  302. package/src/editor/group-manager/MemberList.tsx +0 -184
  303. package/src/editor/group-manager/hooks/useExternalGroupSearch.ts +0 -63
  304. package/src/editor/group-manager/hooks/useGroupState.ts +0 -134
  305. package/src/editor/group-manager/hooks/useUserSearch.ts +0 -84
  306. package/src/editor/group-manager/index.tsx +0 -210
  307. package/src/editor/group-manager/types.ts +0 -28
  308. package/src/editor/hooks/README.md +0 -26
  309. package/src/editor/hooks/__test__/test-utils.tsx +0 -183
  310. package/src/editor/hooks/index.ts +0 -23
  311. package/src/editor/hooks/useBranchActions.test.tsx +0 -267
  312. package/src/editor/hooks/useBranchActions.tsx +0 -121
  313. package/src/editor/hooks/useBranchManager.test.tsx +0 -391
  314. package/src/editor/hooks/useBranchManager.tsx +0 -326
  315. package/src/editor/hooks/useCommentSystem.test.ts +0 -615
  316. package/src/editor/hooks/useCommentSystem.ts +0 -347
  317. package/src/editor/hooks/useDraftManager.test.ts +0 -375
  318. package/src/editor/hooks/useDraftManager.ts +0 -259
  319. package/src/editor/hooks/useEditorLayout.test.ts +0 -147
  320. package/src/editor/hooks/useEditorLayout.ts +0 -67
  321. package/src/editor/hooks/useEntryManager.test.ts +0 -588
  322. package/src/editor/hooks/useEntryManager.ts +0 -387
  323. package/src/editor/hooks/useGroupManager.test.ts +0 -277
  324. package/src/editor/hooks/useGroupManager.ts +0 -139
  325. package/src/editor/hooks/usePermissionManager.test.ts +0 -211
  326. package/src/editor/hooks/usePermissionManager.ts +0 -113
  327. package/src/editor/hooks/useReferenceResolution.ts +0 -248
  328. package/src/editor/hooks/useSchemaManager.test.ts +0 -370
  329. package/src/editor/hooks/useSchemaManager.ts +0 -310
  330. package/src/editor/hooks/useUserContext.tsx +0 -57
  331. package/src/editor/hooks/useUserMetadata.test.ts +0 -191
  332. package/src/editor/hooks/useUserMetadata.ts +0 -71
  333. package/src/editor/permission-manager/GroupSelector.tsx +0 -73
  334. package/src/editor/permission-manager/PermissionEditor.tsx +0 -321
  335. package/src/editor/permission-manager/PermissionLevelBadge.tsx +0 -53
  336. package/src/editor/permission-manager/PermissionTree.tsx +0 -237
  337. package/src/editor/permission-manager/UserSelector.tsx +0 -95
  338. package/src/editor/permission-manager/constants.tsx +0 -18
  339. package/src/editor/permission-manager/hooks/useGroupsAndUsers.ts +0 -153
  340. package/src/editor/permission-manager/hooks/usePermissionTree.ts +0 -200
  341. package/src/editor/permission-manager/index.tsx +0 -294
  342. package/src/editor/permission-manager/types.ts +0 -58
  343. package/src/editor/permission-manager/utils.ts +0 -179
  344. package/src/editor/preview-bridge.test.tsx +0 -50
  345. package/src/editor/preview-bridge.tsx +0 -294
  346. package/src/editor/schema-editor/CollectionEditor.test.tsx +0 -238
  347. package/src/editor/schema-editor/CollectionEditor.tsx +0 -520
  348. package/src/editor/schema-editor/EntryTypeEditor.test.tsx +0 -215
  349. package/src/editor/schema-editor/EntryTypeEditor.tsx +0 -367
  350. package/src/editor/schema-editor/index.ts +0 -19
  351. package/src/editor/setup-test-dom.ts +0 -10
  352. package/src/editor/test-setup.ts +0 -33
  353. package/src/editor/theme.tsx +0 -119
  354. package/src/editor/utils/env.ts +0 -39
  355. package/src/entry-schema-registry.test.ts +0 -281
  356. package/src/entry-schema-registry.ts +0 -121
  357. package/src/entry-schema.ts +0 -84
  358. package/src/git-manager.test.ts +0 -552
  359. package/src/git-manager.ts +0 -667
  360. package/src/github-service.test.ts +0 -312
  361. package/src/github-service.ts +0 -295
  362. package/src/http/handler.test.ts +0 -275
  363. package/src/http/handler.ts +0 -280
  364. package/src/http/index.ts +0 -11
  365. package/src/http/router.ts +0 -164
  366. package/src/http/types.ts +0 -44
  367. package/src/id.test.ts +0 -48
  368. package/src/id.ts +0 -22
  369. package/src/index.ts +0 -26
  370. package/src/operating-mode/__tests__/strategies.test.ts +0 -511
  371. package/src/operating-mode/client-safe-strategy.ts +0 -184
  372. package/src/operating-mode/client-unsafe-strategy.ts +0 -303
  373. package/src/operating-mode/client.ts +0 -13
  374. package/src/operating-mode/index.ts +0 -34
  375. package/src/operating-mode/types.ts +0 -186
  376. package/src/paths/__tests__/branch.test.ts +0 -53
  377. package/src/paths/__tests__/normalize.test.ts +0 -141
  378. package/src/paths/__tests__/resolve.test.ts +0 -207
  379. package/src/paths/__tests__/validation.test.ts +0 -61
  380. package/src/paths/branch.ts +0 -115
  381. package/src/paths/index.ts +0 -73
  382. package/src/paths/normalize-server.ts +0 -40
  383. package/src/paths/normalize.ts +0 -107
  384. package/src/paths/resolve.ts +0 -61
  385. package/src/paths/test-utils.ts +0 -37
  386. package/src/paths/types.ts +0 -68
  387. package/src/paths/validation.test.ts +0 -480
  388. package/src/paths/validation.ts +0 -391
  389. package/src/reference-resolver.test.ts +0 -107
  390. package/src/reference-resolver.ts +0 -157
  391. package/src/schema/index.ts +0 -29
  392. package/src/schema/meta-loader.ts +0 -366
  393. package/src/schema/resolver.ts +0 -83
  394. package/src/schema/schema-store-types.ts +0 -56
  395. package/src/schema/schema-store.test.ts +0 -816
  396. package/src/schema/schema-store.ts +0 -795
  397. package/src/schema/types.ts +0 -33
  398. package/src/schema-meta-loader.test.ts +0 -447
  399. package/src/server.ts +0 -15
  400. package/src/services.test.ts +0 -559
  401. package/src/services.ts +0 -373
  402. package/src/settings-branch-utils.ts +0 -53
  403. package/src/settings-workspace.ts +0 -156
  404. package/src/task-queue/README.md +0 -144
  405. package/src/task-queue/index.ts +0 -14
  406. package/src/task-queue/task-queue.test.ts +0 -524
  407. package/src/task-queue/task-queue.ts +0 -514
  408. package/src/task-queue/types.ts +0 -41
  409. package/src/test-utils/api-test-helpers.ts +0 -445
  410. package/src/test-utils/console-spy.test.ts +0 -14
  411. package/src/test-utils/console-spy.ts +0 -125
  412. package/src/test-utils/git-helpers.ts +0 -31
  413. package/src/test-utils/index.ts +0 -4
  414. package/src/types.ts +0 -54
  415. package/src/user.ts +0 -118
  416. package/src/utils/debug.test.ts +0 -114
  417. package/src/utils/debug.ts +0 -127
  418. package/src/utils/error.test.ts +0 -92
  419. package/src/utils/error.ts +0 -83
  420. package/src/utils/format.ts +0 -12
  421. package/src/validation/__tests__/field-traversal.test.ts +0 -263
  422. package/src/validation/deletion-checker.ts +0 -234
  423. package/src/validation/field-traversal.ts +0 -146
  424. package/src/validation/reference-validator.ts +0 -168
  425. package/src/worker/cms-worker-rebase.test.ts +0 -473
  426. package/src/worker/cms-worker.ts +0 -777
  427. package/src/worker/integration.test.ts +0 -289
  428. package/src/worker/task-queue-config.ts +0 -25
  429. package/src/worker/task-queue.test.ts +0 -452
  430. package/src/worker/task-queue.ts +0 -58
@@ -1,650 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import type { Dirent } from 'node:fs'
3
- import path from 'node:path'
4
- import { z } from 'zod'
5
-
6
- import matter from 'gray-matter'
7
-
8
- import type { ContentFormat, FlatSchemaItem, EntryTypeConfig } from '../config'
9
- import { ContentStore, ContentStoreError } from '../content-store'
10
- import type { ApiContext, ApiRequest, ApiResponse } from './types'
11
- import type { BranchContextWithSchema } from '../types'
12
- import { defineEndpoint } from './route-builder'
13
- import { getFormatExtension } from '../utils/format'
14
- import { resolveCollectionPath } from '../content-id-index'
15
- import {
16
- validateAndNormalizePath,
17
- normalizeFilesystemPath,
18
- parseSlug,
19
- parseLogicalPath,
20
- } from '../paths'
21
- import { isNotFoundError } from '../utils/error'
22
- import { isValidId } from '../id'
23
- import type { LogicalPath, PhysicalPath, EntrySlug, ContentId } from '../paths/types'
24
- import { branchNameSchema, logicalPathSchema } from './validators'
25
- import { SchemaOps } from '../schema/schema-store'
26
-
27
- /**
28
- * Summary of an entry type for client display.
29
- * Simplified from EntryTypeConfig - doesn't include full field definitions.
30
- */
31
- export interface EntryTypeSummary {
32
- name: string
33
- label?: string
34
- format: ContentFormat
35
- default?: boolean
36
- maxItems?: number
37
- }
38
-
39
- export interface CollectionItem {
40
- logicalPath: LogicalPath
41
- contentId: ContentId // 12-char content ID
42
- slug: EntrySlug
43
- collectionPath: LogicalPath
44
- collectionName: string
45
- format: ContentFormat
46
- entryType: string // The entry type name (from typed entries)
47
- physicalPath: PhysicalPath
48
- title?: string
49
- updatedAt?: string
50
- exists?: boolean
51
- canEdit?: boolean
52
- }
53
-
54
- export interface ListEntriesParams {
55
- branch: string
56
- collection?: LogicalPath
57
- limit?: number
58
- cursor?: string
59
- q?: string
60
- recursive?: boolean
61
- }
62
-
63
- export interface ListEntriesResponse {
64
- entries: CollectionItem[]
65
- pagination: {
66
- cursor?: string
67
- hasMore: boolean
68
- limit: number
69
- }
70
- }
71
-
72
- /** Response type for listing entries */
73
- export type EntriesResponse = ApiResponse<ListEntriesResponse>
74
-
75
- // ============================================================================
76
- // Zod Schemas for Validation
77
- // ============================================================================
78
-
79
- const listEntriesParamsSchema = z.object({
80
- branch: branchNameSchema,
81
- collection: logicalPathSchema.optional(),
82
- limit: z.number().optional(),
83
- cursor: z.string().optional(),
84
- q: z.string().optional(),
85
- recursive: z.boolean().optional(),
86
- })
87
-
88
- /**
89
- * Validate and normalize a path relative to root.
90
- * Throws ContentStoreError on traversal attempt.
91
- */
92
- const normalizePath = (root: string, target: string): string => {
93
- const result = validateAndNormalizePath(root, target)
94
- if (!result.valid) {
95
- throw new ContentStoreError(result.error || 'Path traversal detected')
96
- }
97
- return result.normalizedPath!
98
- }
99
-
100
- const readTitle = async (filePath: string, format: ContentFormat): Promise<string | undefined> => {
101
- try {
102
- const raw = await fs.readFile(filePath, 'utf8')
103
- if (format === 'json') {
104
- const parsed = JSON.parse(raw) as Record<string, unknown>
105
- const title = parsed.title ?? parsed.name
106
- return typeof title === 'string' ? title : undefined
107
- }
108
- const parsed = matter(raw)
109
- const frontmatterTitle =
110
- (parsed.data as Record<string, unknown>)?.title ??
111
- (parsed.data as Record<string, unknown>)?.name
112
- return typeof frontmatterTitle === 'string' ? frontmatterTitle : undefined
113
- } catch {
114
- return undefined
115
- }
116
- }
117
-
118
- /**
119
- * Sort entries by the collection's order array.
120
- * Items in the order array come first (in order), items not in the array come at the end alphabetically by slug.
121
- * @param entries - The entries to sort
122
- * @param order - The order array (embedded IDs)
123
- * @returns Sorted entries
124
- */
125
- const sortEntriesByOrder = (
126
- entries: CollectionItem[],
127
- order?: readonly string[],
128
- ): CollectionItem[] => {
129
- if (!order || order.length === 0) {
130
- // No order defined, sort alphabetically by slug
131
- return entries.sort((a, b) => a.slug.localeCompare(b.slug))
132
- }
133
-
134
- // Create a map of contentId to order index
135
- const orderMap = new Map<string, number>()
136
- order.forEach((id, index) => orderMap.set(id, index))
137
-
138
- return entries.sort((a, b) => {
139
- const aIndex = orderMap.get(a.contentId)
140
- const bIndex = orderMap.get(b.contentId)
141
-
142
- // Both in order array: sort by order index
143
- if (aIndex !== undefined && bIndex !== undefined) {
144
- return aIndex - bIndex
145
- }
146
-
147
- // Only a is in order: a comes first
148
- if (aIndex !== undefined) return -1
149
-
150
- // Only b is in order: b comes first
151
- if (bIndex !== undefined) return 1
152
-
153
- // Neither in order: sort alphabetically by slug
154
- return a.slug.localeCompare(b.slug)
155
- })
156
- }
157
-
158
- /**
159
- * Parse a filename: {type}.{slug}.{id}.{ext}
160
- * Returns { type, slug, id } or null if the filename doesn't match the pattern.
161
- */
162
- const parseTypedFilename = (
163
- filename: string,
164
- entryTypes: readonly EntryTypeConfig[],
165
- ): { type: string; slug: EntrySlug; id: ContentId } | null => {
166
- // Remove extension
167
- const lastDot = filename.lastIndexOf('.')
168
- if (lastDot === -1) return null
169
- const nameWithoutExt = filename.slice(0, lastDot)
170
-
171
- // Parse: {type}.{slug}.{id}
172
- const parts = nameWithoutExt.split('.')
173
- if (parts.length >= 3) {
174
- // Check if first part matches a known entry type
175
- const potentialType = parts[0]
176
- const matchingType = entryTypes.find((e) => e.name === potentialType)
177
- if (matchingType) {
178
- const id = parts[parts.length - 1]
179
- if (!isValidId(id)) return null
180
- const slug = parts.slice(1, -1).join('.')
181
- return {
182
- type: potentialType,
183
- slug: slug as EntrySlug,
184
- id: id as ContentId,
185
- }
186
- }
187
- }
188
-
189
- return null
190
- }
191
-
192
- const listCollectionEntries = async (
193
- root: string,
194
- collection: FlatSchemaItem,
195
- ): Promise<CollectionItem[]> => {
196
- // Only collections with entries can be listed
197
- if (collection.type !== 'collection' || !collection.entries) {
198
- return []
199
- }
200
-
201
- const entryTypes = collection.entries as readonly EntryTypeConfig[]
202
-
203
- // Build a map of extension to entry types for efficient lookup
204
- const extToTypes = new Map<string, EntryTypeConfig[]>()
205
- for (const entryType of entryTypes) {
206
- const ext = getFormatExtension(entryType.format)
207
- const existing = extToTypes.get(ext) || []
208
- existing.push(entryType)
209
- extToTypes.set(ext, existing)
210
- }
211
-
212
- // Get all valid extensions for this collection
213
- const validExts = Array.from(extToTypes.keys())
214
-
215
- // Resolve the full collection path with embedded IDs
216
- // e.g., "content/docs/api" → "content/docs.bChqT78gcaLd/api.meiuwxTSo7UN"
217
- const collectionRoot = await resolveCollectionPath(root, collection.logicalPath)
218
-
219
- if (!collectionRoot) {
220
- // Collection directory doesn't exist yet
221
- return []
222
- }
223
-
224
- normalizePath(root, collectionRoot)
225
- let dirents: Dirent[]
226
- try {
227
- dirents = await fs.readdir(collectionRoot, { withFileTypes: true })
228
- } catch (err: unknown) {
229
- if (isNotFoundError(err)) return []
230
- throw err
231
- }
232
-
233
- // Filter to files with valid extensions
234
- const files = dirents
235
- .filter(
236
- (d) =>
237
- d.isFile() &&
238
- validExts.some((ext) => d.name.endsWith(ext)) &&
239
- d.name !== '.collection.json',
240
- )
241
- .sort((a, b) => a.name.localeCompare(b.name))
242
-
243
- // Parallelize file stats and title reads for better performance
244
- const entries = await Promise.all(
245
- files.map(async (file) => {
246
- const absolutePath = path.join(collectionRoot, file.name)
247
- const relativePath = normalizePath(root, absolutePath)
248
-
249
- // Parse the filename to extract type, slug, and id
250
- const parsed = parseTypedFilename(file.name, entryTypes)
251
- if (!parsed) {
252
- console.warn(
253
- `Skipping file with unrecognized filename format: ${file.name} (expected {type}.{slug}.{id}.{ext} with a known entry type and valid 12-char Base58 ID)`,
254
- )
255
- return null
256
- }
257
-
258
- const { type: entryTypeName, slug, id: contentId } = parsed
259
-
260
- // Determine the entry type and format
261
- // Type is always in filename now
262
- const entryType = entryTypes.find((e) => e.name === entryTypeName)
263
- const format: ContentFormat = entryType?.format || 'json'
264
-
265
- const [stats, title] = await Promise.all([
266
- fs.stat(absolutePath),
267
- readTitle(absolutePath, format),
268
- ])
269
-
270
- const item: CollectionItem = {
271
- // Safe: both collection.logicalPath (LogicalPath) and slug (EntrySlug) are branded
272
- logicalPath: `${collection.logicalPath}/${slug}` as LogicalPath,
273
- contentId, // 12-char content ID extracted from filename
274
- slug,
275
- collectionPath: collection.logicalPath,
276
- collectionName: collection.name,
277
- format,
278
- entryType: entryTypeName || 'default',
279
- physicalPath: relativePath as PhysicalPath,
280
- title: title ?? entryType?.label, // Fall back to entry type label if no title in content
281
- updatedAt: stats.mtime.toISOString(),
282
- exists: true,
283
- }
284
- return item
285
- }),
286
- )
287
-
288
- // Filter out nulls from failed parses
289
- return entries.filter((e): e is CollectionItem => e !== null)
290
- }
291
-
292
- /**
293
- * List entries from a collection and all its nested child collections
294
- */
295
- const listCollectionEntriesRecursive = async (
296
- root: string,
297
- targetPath: string,
298
- flatCollections: FlatSchemaItem[],
299
- ): Promise<CollectionItem[]> => {
300
- // Find all collections that are descendants of the target path
301
- const descendants = flatCollections.filter((item) => {
302
- return item.logicalPath === targetPath || item.logicalPath.startsWith(`${targetPath}/`)
303
- })
304
-
305
- // Parallelize listing entries from all descendant collections
306
- const collectionsWithEntries = descendants.filter(
307
- (item) => item.type === 'collection' && item.entries,
308
- )
309
- const results = await Promise.all(
310
- collectionsWithEntries.map((item) => listCollectionEntries(root, item)),
311
- )
312
-
313
- return results.flat()
314
- }
315
-
316
- const listEntriesHandler = async (
317
- gc: { branchContext: BranchContextWithSchema },
318
- ctx: ApiContext,
319
- req: ApiRequest,
320
- params: z.infer<typeof listEntriesParamsSchema>,
321
- ): Promise<EntriesResponse> => {
322
- if (!params.branch) {
323
- return { ok: false, status: 400, error: 'branch is required' }
324
- }
325
-
326
- const { branchContext } = gc
327
- const root = branchContext.branchRoot
328
- const flatSchema = branchContext.flatSchema
329
- const flatCollections = flatSchema
330
-
331
- const targetPath = params.collection ? normalizeFilesystemPath(params.collection) : undefined
332
- let targetCollections = flatCollections
333
-
334
- if (targetPath) {
335
- const match = flatCollections.find((c) => c.logicalPath === targetPath)
336
- if (!match) {
337
- return { ok: false, status: 404, error: 'Collection not found' }
338
- }
339
- targetCollections = [match]
340
- }
341
-
342
- const maxLimit = 200
343
- const limit = Math.min(Math.max(params.limit ?? 50, 1), maxLimit)
344
- const offset = Number.isFinite(Number(params.cursor)) ? Number(params.cursor) : 0
345
- const search = params.q?.toLowerCase()
346
- const recursive = params.recursive ?? false
347
-
348
- const entries: CollectionItem[] = []
349
-
350
- if (recursive && targetPath) {
351
- // Recursive mode: list entries from target collection and all its children
352
- try {
353
- const items = await listCollectionEntriesRecursive(root, targetPath, flatCollections)
354
- // For recursive mode, we can't easily apply per-collection ordering
355
- // Sort alphabetically for now (ordering is collection-specific)
356
- items.sort((a, b) => a.slug.localeCompare(b.slug))
357
- for (const item of items) {
358
- // Use the physicalPath for access control
359
- const readAccess = await ctx.services.checkContentAccess(
360
- branchContext,
361
- root,
362
- item.physicalPath,
363
- req.user,
364
- 'read',
365
- )
366
- if (!readAccess.allowed) continue
367
- const editAccess = await ctx.services.checkContentAccess(
368
- branchContext,
369
- root,
370
- item.physicalPath,
371
- req.user,
372
- 'edit',
373
- )
374
- if (search) {
375
- const haystack =
376
- `${item.slug} ${item.title ?? ''} ${item.collectionName ?? ''}`.toLowerCase()
377
- if (!haystack.includes(search)) {
378
- continue
379
- }
380
- }
381
- entries.push({ ...item, canEdit: editAccess.allowed })
382
- }
383
- } catch (err) {
384
- if (err instanceof ContentStoreError) {
385
- return { ok: false, status: 400, error: err.message }
386
- }
387
- throw err
388
- }
389
- } else {
390
- // Non-recursive mode: list entries from target collections
391
- for (const item of targetCollections) {
392
- // Only process collections (skip entry-types as they are metadata, not navigable nodes)
393
- if (item.type !== 'collection') continue
394
-
395
- try {
396
- const items = await listCollectionEntries(root, item)
397
- // Sort by collection's order array (items in order first, then alphabetically)
398
- sortEntriesByOrder(items, item.order)
399
- for (const entry of items) {
400
- // Use the physicalPath for access control
401
- const readAccess = await ctx.services.checkContentAccess(
402
- branchContext,
403
- root,
404
- entry.physicalPath,
405
- req.user,
406
- 'read',
407
- )
408
- if (!readAccess.allowed) continue
409
- const editAccess = await ctx.services.checkContentAccess(
410
- branchContext,
411
- root,
412
- entry.physicalPath,
413
- req.user,
414
- 'edit',
415
- )
416
- if (search) {
417
- const haystack =
418
- `${entry.slug} ${entry.title ?? ''} ${entry.collectionName ?? ''}`.toLowerCase()
419
- if (!haystack.includes(search)) {
420
- continue
421
- }
422
- }
423
- entries.push({ ...entry, canEdit: editAccess.allowed })
424
- }
425
- } catch (err) {
426
- if (err instanceof ContentStoreError) {
427
- return { ok: false, status: 400, error: err.message }
428
- }
429
- throw err
430
- }
431
- }
432
- }
433
-
434
- const paged = entries.slice(offset, offset + limit)
435
- const nextCursor = offset + limit < entries.length ? String(offset + limit) : undefined
436
-
437
- return {
438
- ok: true,
439
- status: 200,
440
- data: {
441
- entries: paged,
442
- pagination: {
443
- cursor: nextCursor,
444
- hasMore: Boolean(nextCursor),
445
- limit,
446
- },
447
- },
448
- }
449
- }
450
-
451
- // ============================================================================
452
- // Route Definitions with defineEndpoint
453
- // ============================================================================
454
-
455
- /**
456
- * List entries for a branch
457
- * GET /:branch/entries
458
- */
459
- export const listEntries = defineEndpoint({
460
- namespace: 'entries',
461
- name: 'list',
462
- method: 'GET',
463
- path: '/:branch/entries',
464
- params: listEntriesParamsSchema,
465
- responseType: 'EntriesResponse',
466
- response: {} as EntriesResponse,
467
- defaultMockData: {
468
- collections: [],
469
- entries: [],
470
- pagination: {
471
- hasMore: false,
472
- limit: 50,
473
- },
474
- },
475
- guards: ['schema'] as const,
476
- handler: listEntriesHandler,
477
- })
478
-
479
- // ============================================================================
480
- // Delete Entry
481
- // ============================================================================
482
-
483
- /** Response type for deleting an entry */
484
- export type DeleteEntryResponse = ApiResponse<{
485
- deleted: boolean
486
- contentId?: string
487
- }>
488
-
489
- const deleteEntryParamsSchema = z.object({
490
- branch: branchNameSchema,
491
- entryPath: logicalPathSchema, // Format: collectionPath/slug
492
- })
493
-
494
- /**
495
- * Delete an entry and update the collection's order array.
496
- * DELETE /:branch/entries/...entryPath
497
- * Note: Uses catch-all to support paths with slashes (e.g., content/posts/hello-world)
498
- */
499
- const deleteEntryHandler = async (
500
- gc: { branchContext: BranchContextWithSchema },
501
- ctx: ApiContext,
502
- req: ApiRequest,
503
- params: z.infer<typeof deleteEntryParamsSchema>,
504
- ): Promise<DeleteEntryResponse> => {
505
- const { branchContext } = gc
506
-
507
- // Parse entryPath to get collection and slug
508
- // Format: collectionPath/slug (e.g., "posts/hello-world" or "docs/api/getting-started")
509
- // Re-validate after decoding to prevent double-encoding path traversal attacks
510
- const decoded = decodeURIComponent(params.entryPath)
511
- const entryPathResult = parseLogicalPath(decoded)
512
- if (!entryPathResult.ok) {
513
- return {
514
- ok: false,
515
- status: 400,
516
- error: `Invalid entry path: ${entryPathResult.error}`,
517
- }
518
- }
519
- const entryPath = entryPathResult.path
520
-
521
- const lastSlash = entryPath.lastIndexOf('/')
522
- if (lastSlash === -1) {
523
- return {
524
- ok: false,
525
- status: 400,
526
- error: 'Invalid entry path format. Expected: collectionPath/slug',
527
- }
528
- }
529
-
530
- const collectionPath = entryPath.slice(0, lastSlash)
531
- const slug = entryPath.slice(lastSlash + 1)
532
-
533
- if (!collectionPath || !slug) {
534
- return {
535
- ok: false,
536
- status: 400,
537
- error: 'Invalid entry path format. Expected: collectionPath/slug',
538
- }
539
- }
540
-
541
- const flatSchema = branchContext.flatSchema
542
-
543
- // Check edit permission on the entry
544
- // Build the physical path for permission check
545
- const collection = flatSchema.find(
546
- (item) => item.type === 'collection' && item.logicalPath === collectionPath,
547
- )
548
- if (!collection) {
549
- return { ok: false, status: 404, error: 'Collection not found' }
550
- }
551
-
552
- const contentStore = new ContentStore(branchContext.branchRoot, flatSchema)
553
- const collectionLogicalPath = collectionPath as LogicalPath
554
- // Validate slug extracted from the path
555
- const slugResult = parseSlug(slug, 'entry')
556
- if (!slugResult.ok) {
557
- return {
558
- ok: false,
559
- status: 400,
560
- error: `Invalid entry slug: ${slugResult.error}`,
561
- }
562
- }
563
- const entrySlug = slugResult.slug as EntrySlug
564
-
565
- // Resolve the real physical path before checking permissions
566
- let physicalPath: PhysicalPath
567
- try {
568
- const resolved = await contentStore.resolveDocumentPath(collectionLogicalPath, entrySlug)
569
- physicalPath = resolved.relativePath
570
- } catch (err) {
571
- if (isNotFoundError(err)) {
572
- return { ok: false, status: 404, error: 'Entry not found' }
573
- }
574
- return { ok: false, status: 400, error: 'Invalid entry path' }
575
- }
576
-
577
- // Check edit access using the real physical path
578
- const editAccess = await ctx.services.checkContentAccess(
579
- branchContext,
580
- branchContext.branchRoot,
581
- physicalPath,
582
- req.user,
583
- 'edit',
584
- )
585
- if (!editAccess.allowed) {
586
- return {
587
- ok: false,
588
- status: 403,
589
- error: 'Edit permission required to delete entry',
590
- }
591
- }
592
-
593
- try {
594
- // Get the entry's content ID before deleting (for order update)
595
- const contentId = await contentStore.getIdForEntry(collectionLogicalPath, entrySlug)
596
-
597
- // Delete the entry
598
- await contentStore.delete(collectionLogicalPath, entrySlug)
599
-
600
- // Update the collection's order array to remove the deleted item
601
- if (contentId && collection.type === 'collection' && collection.order) {
602
- const schemaStore = new SchemaOps(branchContext.branchRoot, ctx.services.entrySchemaRegistry)
603
- const newOrder = collection.order.filter((id) => id !== contentId)
604
- if (newOrder.length !== collection.order.length) {
605
- await schemaStore.updateOrder(collectionPath as LogicalPath, newOrder as string[])
606
- }
607
- }
608
-
609
- return {
610
- ok: true,
611
- status: 200,
612
- data: { deleted: true, contentId: contentId || undefined },
613
- }
614
- } catch (err) {
615
- if (isNotFoundError(err)) {
616
- return { ok: false, status: 404, error: 'Entry not found' }
617
- }
618
- return {
619
- ok: false,
620
- status: 500,
621
- error: err instanceof Error ? err.message : 'Failed to delete entry',
622
- }
623
- }
624
- }
625
-
626
- /**
627
- * Delete an entry
628
- * DELETE /:branch/entries/...entryPath
629
- * Note: Uses catch-all to support paths with slashes (e.g., content/posts/hello-world)
630
- */
631
- export const deleteEntry = defineEndpoint({
632
- namespace: 'entries',
633
- name: 'delete',
634
- method: 'DELETE',
635
- path: '/:branch/entries/...entryPath',
636
- params: deleteEntryParamsSchema,
637
- responseType: 'DeleteEntryResponse',
638
- response: {} as DeleteEntryResponse,
639
- defaultMockData: { deleted: true },
640
- guards: ['schema'] as const,
641
- handler: deleteEntryHandler,
642
- })
643
-
644
- /**
645
- * Exported routes for router registration
646
- */
647
- export const ENTRY_ROUTES = {
648
- list: listEntries,
649
- delete: deleteEntry,
650
- } as const