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
@@ -2,9 +2,6 @@ import type { OperatingMode } from '../../operating-mode/index.js';
2
2
  import type { BranchStatus } from '../../types.js';
3
3
  import type { EditorEntry } from '../Editor.js';
4
4
  import type { LogicalPath } from '../../paths/types.js';
5
- /**
6
- * Props for the EditorHeader component.
7
- */
8
5
  export interface EditorHeaderProps {
9
6
  /**
10
7
  * Site title displayed in the top-left.
@@ -150,33 +147,5 @@ export interface EditorHeaderProps {
150
147
  /**
151
148
  * Header component for the Editor.
152
149
  * Contains site info, file navigation, breadcrumbs, branch selector, comments button, and action buttons.
153
- *
154
- * @example
155
- * ```tsx
156
- * <EditorHeader
157
- * siteTitle="My Site"
158
- * siteSubtitle="CMS"
159
- * headerTitle="Edit Content"
160
- * currentEntry={currentEntry}
161
- * branchName="main"
162
- * operatingMode="collaboration"
163
- * busy={false}
164
- * breadcrumbSegments={['Posts', 'My Post']}
165
- * editedFiles={[]}
166
- * modifiedCount={0}
167
- * unresolvedCommentCount={0}
168
- * comments={[]}
169
- * onNavigatorOpen={() => setNavigatorOpen(true)}
170
- * onFileReload={handleReload}
171
- * onFileDiscardDraft={handleDiscardFileDraft}
172
- * onEntrySelect={setSelectedId}
173
- * onBranchReloadData={handleReloadBranchData}
174
- * onBranchDiscardDrafts={handleDiscardDrafts}
175
- * onBranchManagerOpen={() => setBranchManagerOpen(true)}
176
- * onCommentsPanelOpen={() => setCommentsPanelOpen(true)}
177
- * onSave={handleSave}
178
- * onSubmit={() => handleSubmit(branchName)}
179
- * />
180
- * ```
181
150
  */
182
151
  export declare const EditorHeader: import("react").ForwardRefExoticComponent<EditorHeaderProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -20,60 +20,20 @@ const getStatusColor = (status) => {
20
20
  /**
21
21
  * Header component for the Editor.
22
22
  * Contains site info, file navigation, breadcrumbs, branch selector, comments button, and action buttons.
23
- *
24
- * @example
25
- * ```tsx
26
- * <EditorHeader
27
- * siteTitle="My Site"
28
- * siteSubtitle="CMS"
29
- * headerTitle="Edit Content"
30
- * currentEntry={currentEntry}
31
- * branchName="main"
32
- * operatingMode="collaboration"
33
- * busy={false}
34
- * breadcrumbSegments={['Posts', 'My Post']}
35
- * editedFiles={[]}
36
- * modifiedCount={0}
37
- * unresolvedCommentCount={0}
38
- * comments={[]}
39
- * onNavigatorOpen={() => setNavigatorOpen(true)}
40
- * onFileReload={handleReload}
41
- * onFileDiscardDraft={handleDiscardFileDraft}
42
- * onEntrySelect={setSelectedId}
43
- * onBranchReloadData={handleReloadBranchData}
44
- * onBranchDiscardDrafts={handleDiscardDrafts}
45
- * onBranchManagerOpen={() => setBranchManagerOpen(true)}
46
- * onCommentsPanelOpen={() => setCommentsPanelOpen(true)}
47
- * onSave={handleSave}
48
- * onSubmit={() => handleSubmit(branchName)}
49
- * />
50
- * ```
51
23
  */
52
24
  export const EditorHeader = forwardRef(function EditorHeader({ siteTitle, siteSubtitle, headerTitle, currentEntry, branchName, operatingMode, busy, breadcrumbSegments, editedFiles, modifiedCount, unresolvedCommentCount: _, comments, onNavigatorOpen, onFileReload, onFileDiscardDraft, onEntrySelect, onBranchReloadData, onBranchDiscardDrafts, onBranchManagerOpen, onCommentsPanelOpen, onSave, onSubmit, hasUnsavedChanges, branchStatus, onWithdraw, userContext, branchCreatedBy, branchAccess, branchIsProtected = false, branchReadOnly = false, branchWriteBlocked = false, }, ref) {
53
- // `branchWriteBlocked` is the server's own answer (getBranchProtection, the
54
- // same call the writableBranch guard makes), so Save can never be enabled for
55
- // a write the API would reject. `branchReadOnly` only picks WHICH banner: the
56
- // base branch's is a structural property and takes precedence over a workflow
57
- // status lock.
25
+ // `branchWriteBlocked` is the server's own answer (getBranchProtection), so
26
+ // Save is never enabled for a write the API would reject; a client-side
27
+ // derivation could drift from it. `branchReadOnly` only picks which banner
28
+ // to show -- base-branch read-only takes precedence over a workflow status
29
+ // lock.
58
30
  const statusLocked = branchWriteBlocked && !branchReadOnly;
59
- // The lock now fails CLOSED while the branch list is unresolved (Editor.tsx's
60
- // `branchContentLocked` is `?? true`), which is right -- but `branchStatus` is
61
- // `currentBranch?.status`, i.e. undefined in that same window. Without this
62
- // distinction every banner and tooltip below interpolated it directly and read
63
- // `Branch "main" is undefined - content is read-only`, on ordinary initial load
64
- // and permanently after a failed branches fetch. Worse under version skew,
65
- // where the status IS known ('editing') and the copy would assert a status
66
- // lock the status plainly contradicts. So: locked, but say why honestly.
67
- //
68
- // Provably behavior-neutral for supported deployments: writeBlocked =
69
- // readOnly || status !== 'editing', so when status === 'editing' that
70
- // reduces to writeBlocked === readOnly. statusLocked = branchWriteBlocked
71
- // && !branchReadOnly, so the new 'editing' arm below would require
72
- // readOnly && !readOnly -- impossible. It is unreachable against any
73
- // current server and only changes what renders under version skew (an old
74
- // server that omits writeBlocked while still sending status: 'editing'),
75
- // where it replaces the self-contradicting "Branch is editing — content is
76
- // read-only" with the honest data-unavailable copy.
31
+ // Covers two cases where `branchStatus` can't be trusted to describe the lock
32
+ // honestly: branch data still loading (`branchStatus` is undefined, so the
33
+ // banner would otherwise interpolate "Branch is undefined...") and version
34
+ // skew (an old server omits `branchWriteBlocked` while still reporting
35
+ // status: 'editing', which would otherwise assert a lock the status
36
+ // contradicts). In both cases the banner says data is unavailable instead.
77
37
  const branchDataUnavailable = statusLocked && (branchStatus === undefined || branchStatus === 'editing');
78
38
  return (_jsx(Paper, { ref: ref, shadow: "md", withBorder: true, radius: 0, px: 0, py: 0, style: {
79
39
  position: 'fixed',
@@ -134,11 +94,11 @@ export const EditorHeader = forwardRef(function EditorHeader({ siteTitle, siteSu
134
94
  // wrongly stuck in 'submitted'.
135
95
  if (branchIsProtected && !isWithdrawable)
136
96
  return null;
137
- // Check if user can perform workflow actions (creator OR ACL access OR system
138
- // branch OR privileged). Admins/Reviewers must be able to withdraw a protected
139
- // base branch wrongly stuck in 'submitted' -- the documented recovery flow --
140
- // even when they're neither its creator nor in its ACL; this mirrors the
141
- // server's canPerformWorkflowAction and BranchManager.tsx.
97
+ // Who may submit/withdraw: creator, ACL access, the system branch, or an
98
+ // admin/reviewer -- Admins/Reviewers must be able to withdraw a protected
99
+ // base branch stuck in 'submitted' even without ACL access. Mirrors the
100
+ // server's canPerformWorkflowAction (BranchManager.tsx), which is the
101
+ // actual enforcer; this only decides whether to show the control disabled.
142
102
  const userIsCreator = userContext?.userId === branchCreatedBy;
143
103
  const isSystemBranch = branchCreatedBy === 'canopycms-system' && !branchIsProtected;
144
104
  const userInACL = userContext &&
@@ -154,21 +114,11 @@ export const EditorHeader = forwardRef(function EditorHeader({ siteTitle, siteSu
154
114
  const statusHasAction = isEditing || isWithdrawable;
155
115
  const canPerformAction = userHasPermission && statusHasAction;
156
116
  return (_jsx(Tooltip, { label:
157
- // The unknown-status arm mirrors the banner's: with no
158
- // branch data, `statusHasAction` is false (undefined is
159
- // neither 'editing' nor withdrawable) and this label used
160
- // to interpolate it as "This branch is undefined and has
161
- // no submit or withdraw action available".
162
- //
163
- // Latent rather than live TODAY, and only by accident:
164
- // Editor.tsx passes `branchIsProtected={... ?? true}` since
165
- // the fail-closed change, so in that same window the early
166
- // return above (`branchIsProtected && !isWithdrawable`)
167
- // unmounts this button before the tooltip can render. That
168
- // is one guard away from being user-visible -- relax the
169
- // `?? true`, or pass `branchIsProtected={false}` from
170
- // anywhere, and the copy is live. Guarding it here rather
171
- // than relying on an unrelated condition to keep hiding it.
117
+ // No branch data (`branchStatus === undefined`) must not be
118
+ // interpolated raw into this label. Guarded explicitly here rather
119
+ // than left to the early return above, which hides this button
120
+ // today only as a side effect of `branchIsProtected`'s `?? true`
121
+ // default -- not a guarantee this arm stays unreachable.
172
122
  branchStatus === undefined
173
123
  ? 'Branch data could not be loaded, so no submit or withdraw action is available'
174
124
  : !statusHasAction
@@ -1,7 +1,4 @@
1
1
  import type { PaneLayout } from '../EditorPanes.js';
2
- /**
3
- * Props for the EditorSidebar component.
4
- */
5
2
  export interface EditorSidebarProps {
6
3
  /**
7
4
  * Current layout mode (side or stacked).
@@ -66,21 +63,5 @@ export interface EditorSidebarProps {
66
63
  /**
67
64
  * Sidebar component for the Editor.
68
65
  * Contains layout toggle, highlight toggle, settings menu, account button, and logout button.
69
- *
70
- * @example
71
- * ```tsx
72
- * <EditorSidebar
73
- * layout={layout}
74
- * highlightEnabled={highlightEnabled}
75
- * sidebarWidth={60}
76
- * headerHeight={60}
77
- * footerHeight={40}
78
- * onLayoutChange={setLayout}
79
- * onHighlightToggle={() => setHighlightEnabled(!highlightEnabled)}
80
- * onPermissionManagerOpen={() => setPermissionManagerOpen(true)}
81
- * onGroupManagerOpen={() => setGroupManagerOpen(true)}
82
- * onMediaLibraryOpen={() => setMediaLibraryOpen(true)}
83
- * />
84
- * ```
85
66
  */
86
67
  export declare function EditorSidebar({ layout, highlightEnabled, sidebarWidth, headerHeight, footerHeight, onLayoutChange, onHighlightToggle, onPermissionManagerOpen, onGroupManagerOpen, onMediaLibraryOpen, onSystemHealthOpen, AccountComponent, onAccountClick, onLogoutClick, }: EditorSidebarProps): import("react/jsx-runtime").JSX.Element;
@@ -4,22 +4,6 @@ import { IconUserCircle, IconLogout, IconPhoto, IconSettings, IconLayoutColumns,
4
4
  /**
5
5
  * Sidebar component for the Editor.
6
6
  * Contains layout toggle, highlight toggle, settings menu, account button, and logout button.
7
- *
8
- * @example
9
- * ```tsx
10
- * <EditorSidebar
11
- * layout={layout}
12
- * highlightEnabled={highlightEnabled}
13
- * sidebarWidth={60}
14
- * headerHeight={60}
15
- * footerHeight={40}
16
- * onLayoutChange={setLayout}
17
- * onHighlightToggle={() => setHighlightEnabled(!highlightEnabled)}
18
- * onPermissionManagerOpen={() => setPermissionManagerOpen(true)}
19
- * onGroupManagerOpen={() => setGroupManagerOpen(true)}
20
- * onMediaLibraryOpen={() => setMediaLibraryOpen(true)}
21
- * />
22
- * ```
23
7
  */
24
8
  export function EditorSidebar({ layout, highlightEnabled, sidebarWidth, headerHeight, footerHeight, onLayoutChange, onHighlightToggle, onPermissionManagerOpen, onGroupManagerOpen, onMediaLibraryOpen, onSystemHealthOpen, AccountComponent, onAccountClick, onLogoutClick, }) {
25
9
  return (_jsxs(Paper, { withBorder: true, shadow: "sm", radius: 0, style: {
@@ -24,10 +24,10 @@ export interface EntryCreateModalProps {
24
24
  error?: string | null;
25
25
  /**
26
26
  * Slugs already taken in the target collection (from the already-loaded
27
- * entries list). Used to reject an obvious collision client-side with a
28
- * clear message, instead of the server returning a 409 (or, for entry
29
- * types with no required fields, silently succeeding via an update path
30
- * that never mentions the real problem).
27
+ * entries list). Lets the client flag an obvious collision early with a
28
+ * clear message; the server is still the authority, and without this
29
+ * check an entry type with no required fields would silently succeed via
30
+ * an update path instead of erroring.
31
31
  */
32
32
  existingSlugs?: Set<string>;
33
33
  }
@@ -1,13 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- /**
4
- * EntryCreateModal - Modal for creating new entries.
5
- *
6
- * Replaces window.prompt with a proper UI for:
7
- * - Selecting entry type (if multiple types available)
8
- * - Entering slug for new entry
9
- * - Validation and error handling
10
- */
3
+ /** Modal for creating a new entry: replaces window.prompt with entry-type selection, slug entry, and validation. */
11
4
  import { useState, useEffect, useRef } from 'react';
12
5
  import { Modal, Stack, TextInput, Group, Button, Alert, Text, Select } from '@mantine/core';
13
6
  import { IconAlertCircle } from '@tabler/icons-react';
@@ -15,31 +8,23 @@ import { parseSlug } from '../../paths/validation.js';
15
8
  /** Slug the form is seeded with each time the modal opens. */
16
9
  const DEFAULT_SLUG = 'untitled';
17
10
  export function EntryCreateModal({ isOpen, collectionLabel, entryTypes, selectedEntryTypeName, onCreate, onClose, isCreating = false, error = null, existingSlugs, }) {
18
- // Helper to get default or first entry type
19
11
  const getDefaultEntryTypeName = () => {
20
12
  if (selectedEntryTypeName)
21
13
  return selectedEntryTypeName;
22
14
  if (entryTypes.length === 1)
23
15
  return entryTypes[0].name;
24
- // Find entry type marked as default
25
16
  const defaultType = entryTypes.find((et) => et.default);
26
17
  return defaultType?.name || entryTypes[0]?.name || '';
27
18
  };
28
19
  const [slug, setSlug] = useState(DEFAULT_SLUG);
29
20
  const [entryTypeName, setEntryTypeName] = useState(getDefaultEntryTypeName());
30
21
  const [validationError, setValidationError] = useState(null);
31
- // Seed the form once per open, on the closed -> open transition.
32
- //
33
- // This deliberately keys on `isOpen` alone. It used to key on the prop
34
- // *values* (`[isOpen, selectedEntryTypeName, entryTypes]`), but `entryTypes`
35
- // is an array that callers build inline - a fresh identity on every parent
36
- // render - so any re-render while the modal was open re-ran this block and
37
- // silently discarded what the user had typed or selected. The entry was then
38
- // written to disk under the default slug with no error surfaced.
39
- //
40
- // Seeding is a lifecycle event, not a derivation of the current props, so the
41
- // narrow dep array is the point. Do not "fix" it by adding the props read
42
- // below (`entryTypes`, `selectedEntryTypeName`) back in.
22
+ // Seeds the form once per open, on the closed -> open transition. Keys on
23
+ // `isOpen` alone, not on `entryTypes`/`selectedEntryTypeName`: `entryTypes`
24
+ // is an array callers build inline, a fresh identity on every parent
25
+ // render, so keying on it would silently reset the form on every
26
+ // re-render while the modal is open. Do not add those props back to the
27
+ // dep array below.
43
28
  const wasOpenRef = useRef(false);
44
29
  useEffect(() => {
45
30
  if (isOpen && !wasOpenRef.current) {
@@ -1,8 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  /**
4
- * RenameEntryModal - Modal for renaming entry slugs.
5
- *
6
4
  * Allows changing the slug (middle segment) of an entry filename.
7
5
  * The content ID is preserved, so drafts and references remain intact.
8
6
  */
@@ -23,7 +21,6 @@ export function RenameEntryModal({ isOpen, entryLabel, currentSlug, onSave, onCl
23
21
  setValidationError(null);
24
22
  }
25
23
  }
26
- // Validate slug format
27
24
  const validateSlug = (slug) => {
28
25
  if (!slug.trim()) {
29
26
  return 'Slug cannot be empty';
@@ -31,7 +28,6 @@ export function RenameEntryModal({ isOpen, entryLabel, currentSlug, onSave, onCl
31
28
  if (slug.includes('/')) {
32
29
  return 'Slug cannot contain slashes';
33
30
  }
34
- // Simple validation - lowercase, alphanumeric + hyphens
35
31
  if (!/^[a-z0-9][-a-z0-9]*$/.test(slug)) {
36
32
  return 'Slug must start with letter/number and contain only lowercase letters, numbers, and hyphens';
37
33
  }
@@ -5,39 +5,32 @@ import { useUserMetadata } from '../hooks/useUserMetadata.js';
5
5
  export const UserBadge = ({ userId, getUserMetadata, variant = 'avatar-name', showEmailTooltip = true, onRemove, color, size = 'sm', badgeVariant = 'filled', showBadge = false, loading: loadingOverride, cachedUser, }) => {
6
6
  const { userMetadata, isLoading, error } = useUserMetadata(userId, getUserMetadata, cachedUser);
7
7
  const loading = loadingOverride ?? isLoading;
8
- // Avatar size mapping
9
8
  const avatarSize = {
10
9
  xs: 16,
11
10
  sm: 20,
12
11
  md: 24,
13
12
  lg: 32,
14
13
  }[size];
15
- // Text size mapping
16
14
  const textSize = {
17
15
  xs: 'xs',
18
16
  sm: 'sm',
19
17
  md: 'sm',
20
18
  lg: 'md',
21
19
  }[size];
22
- // Loading state
23
20
  if (loading) {
24
21
  return (_jsxs(Group, { gap: 4, children: [_jsx(Skeleton, { circle: true, height: avatarSize, width: avatarSize }), variant !== 'avatar-only' && _jsx(Skeleton, { height: 12, width: 60 })] }));
25
22
  }
26
- // Error or missing user - fallback to userId
27
23
  if (error || !userMetadata) {
28
24
  const content = (_jsxs(Group, { gap: 4, children: [_jsx(Avatar, { size: avatarSize, color: "gray" }), variant !== 'avatar-only' && (_jsx(Text, { size: textSize, c: "dimmed", children: userId }))] }));
29
25
  return showEmailTooltip ? (_jsx(Tooltip, { label: error ? 'Error loading user' : 'User not found', children: content })) : (content);
30
26
  }
31
- // Generate initials from name
32
27
  const getInitials = (name) => {
33
28
  const parts = name.trim().split(/\s+/);
34
29
  if (parts.length === 1)
35
30
  return parts[0].charAt(0).toUpperCase();
36
31
  return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
37
32
  };
38
- // Render avatar
39
33
  const renderAvatar = () => {
40
- // Special case: anonymous user
41
34
  if (userId === 'anonymous') {
42
35
  return (_jsx(Avatar, { size: avatarSize, color: "orange", children: _jsx(IconUserOff, { size: avatarSize * 0.6 }) }));
43
36
  }
@@ -61,7 +54,6 @@ export const UserBadge = ({ userId, getUserMetadata, variant = 'avatar-name', sh
61
54
  }
62
55
  return (_jsx(Avatar, { src: userMetadata.avatarUrl, size: avatarSize, color: avatarColor, style: avatarStyles, children: !userMetadata.avatarUrl && getInitials(userMetadata.name) }));
63
56
  };
64
- // Render content based on variant
65
57
  const renderContent = () => {
66
58
  const avatar = renderAvatar();
67
59
  switch (variant) {
@@ -75,7 +67,6 @@ export const UserBadge = ({ userId, getUserMetadata, variant = 'avatar-name', sh
75
67
  }
76
68
  };
77
69
  const content = renderContent();
78
- // If onRemove or showBadge, wrap the content in a Badge
79
70
  if (onRemove || showBadge) {
80
71
  const badgeContent = (_jsx(Badge, { variant: badgeVariant, color: color, pr: onRemove ? 3 : 8, pl: 4, rightSection: onRemove ? (_jsx(ActionIcon, { size: "xs", radius: "xl", variant: "transparent", onClick: () => onRemove(userId), "aria-label": "Remove user", style: { color: 'white' }, children: _jsx(IconX, { size: 12, stroke: 2.5 }) })) : undefined, styles: {
81
72
  label: {
@@ -87,6 +78,5 @@ export const UserBadge = ({ userId, getUserMetadata, variant = 'avatar-name', sh
87
78
  }, children: content }));
88
79
  return showEmailTooltip && variant !== 'full' ? (_jsx(Tooltip, { label: userMetadata.email, children: badgeContent })) : (badgeContent);
89
80
  }
90
- // No badge wrapper - just wrap with tooltip if needed
91
81
  return showEmailTooltip && variant !== 'full' ? (_jsx(Tooltip, { label: userMetadata.email, children: content })) : (content);
92
82
  };
@@ -1,5 +1,3 @@
1
- // Barrel export for all Editor UI components
2
- // Export components as they are created
3
1
  export * from './EditorFooter.js';
4
2
  export * from './EditorHeader.js';
5
3
  export * from './EditorSidebar.js';
@@ -1,11 +1,7 @@
1
1
  /**
2
- * API Client Context
3
- *
4
- * Provides dependency injection for the API client via context-based pattern
5
- * pattern that was duplicated across 6 hooks. This enables:
6
- * - Clean testing via provider (no more resetApiClient() hacks)
7
- * - Explicit dependency
8
- * - No global mutable state
2
+ * Provides the API client via context-based dependency injection rather than
3
+ * a module-global singleton, so tests can inject a mock client through the
4
+ * provider instead of resetting global state between tests.
9
5
  */
10
6
  import React from 'react';
11
7
  import { createApiClient } from '../../api/index.js';
@@ -27,6 +23,11 @@ export interface ApiClientProviderProps {
27
23
  * Use the client prop to inject a mock client for testing.
28
24
  */
29
25
  export declare function ApiClientProvider({ children, client, basePath }: ApiClientProviderProps): import("react/jsx-runtime").JSX.Element;
26
+ /**
27
+ * Subscribe to every 401 the provider's client receives, from any request. `listener` should be
28
+ * stable (e.g. from `useCallback`): a new function re-subscribes. No-op outside a provider.
29
+ */
30
+ export declare function useOnUnauthorized(listener: () => void): void;
30
31
  /**
31
32
  * Hook to access the API client.
32
33
  * Must be used within an ApiClientProvider.
@@ -1,31 +1,59 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  /**
4
- * API Client Context
5
- *
6
- * Provides dependency injection for the API client via context-based pattern
7
- * pattern that was duplicated across 6 hooks. This enables:
8
- * - Clean testing via provider (no more resetApiClient() hacks)
9
- * - Explicit dependency
10
- * - No global mutable state
4
+ * Provides the API client via context-based dependency injection rather than
5
+ * a module-global singleton, so tests can inject a mock client through the
6
+ * provider instead of resetting global state between tests.
11
7
  */
12
- import { createContext, useContext, useMemo } from 'react';
8
+ import { createContext, useContext, useEffect, useMemo, useState } from 'react';
13
9
  import { createApiClient } from '../../api/index.js';
14
10
  import { joinUrlPrefix } from '../../utils/url-prefix.js';
15
11
  const ApiClientContext = createContext(null);
12
+ function createUnauthorizedSignal() {
13
+ const listeners = new Set();
14
+ return {
15
+ emit: () => {
16
+ for (const listener of [...listeners])
17
+ listener();
18
+ },
19
+ subscribe: (listener) => {
20
+ listeners.add(listener);
21
+ return () => {
22
+ listeners.delete(listener);
23
+ };
24
+ },
25
+ };
26
+ }
27
+ const UnauthorizedSignalContext = createContext(null);
16
28
  /**
17
29
  * Provider that creates and provides the API client.
18
30
  * Use the client prop to inject a mock client for testing.
19
31
  */
20
32
  export function ApiClientProvider({ children, client, basePath }) {
33
+ const [unauthorized] = useState(createUnauthorizedSignal);
21
34
  // Memoized on identity, not just for cost: several consumers now list the client in their
22
35
  // effect deps (useUserContext, useReferenceResolution, ReferenceField), so a fresh client each
23
36
  // render would turn those one-shot fetches into a loop. A caller injecting an inline
24
37
  // `client={createApiClient()}` would reintroduce exactly that.
38
+ //
39
+ // Only a client built HERE reports 401s to `useOnUnauthorized`; an injected `client` is used
40
+ // as-is, so its 401s reach the auth gate only through the gate's own whoami result.
25
41
  const apiClient = useMemo(() => {
26
- return client ?? createApiClient({ baseUrl: joinUrlPrefix(basePath, '/api/canopycms') });
27
- }, [client, basePath]);
28
- return _jsx(ApiClientContext.Provider, { value: apiClient, children: children });
42
+ return (client ??
43
+ createApiClient({
44
+ baseUrl: joinUrlPrefix(basePath, '/api/canopycms'),
45
+ onUnauthorized: unauthorized.emit,
46
+ }));
47
+ }, [client, basePath, unauthorized]);
48
+ return (_jsx(UnauthorizedSignalContext.Provider, { value: unauthorized, children: _jsx(ApiClientContext.Provider, { value: apiClient, children: children }) }));
49
+ }
50
+ /**
51
+ * Subscribe to every 401 the provider's client receives, from any request. `listener` should be
52
+ * stable (e.g. from `useCallback`): a new function re-subscribes. No-op outside a provider.
53
+ */
54
+ export function useOnUnauthorized(listener) {
55
+ const signal = useContext(UnauthorizedSignalContext);
56
+ useEffect(() => signal?.subscribe(listener), [signal, listener]);
29
57
  }
30
58
  /**
31
59
  * Hook to access the API client.
@@ -1,6 +1,4 @@
1
1
  /**
2
- * Asset Context
3
- *
4
2
  * Carries `media.publicBaseUrl` (see CanopyClientConfig.assetBaseUrl) down to
5
3
  * every asset-URL-building component - MediaLibrary, ImageField, and the MDX
6
4
  * image dialog. A context (rather than a prop) because the MDX dialog is
@@ -31,23 +29,15 @@ export interface AssetContextProviderProps extends AssetContextValue {
31
29
  * full, and a deployment `basePath` cannot apply on top of it. Where the two differ is topology,
32
30
  * not precedence - see the asset-mount table in the README.
33
31
  *
34
- * WHY THE FALLBACK EXISTS, AND WHY THAT REASON IS NOW GONE. It was added because
35
- * `publicBaseUrl` was validated absolute-only (`z.string().url()`) and so could not express a
36
- * bare path, leaving the editor's thumbnails, previews and crop images root-relative — and 404 —
37
- * on a basePath deployment where Next serves `/assets`. That constraint was lifted when
38
- * `publicBaseUrl` moved to `assetMountUrlSchema`, which accepts a site-relative path: an adopter
39
- * can now simply set `publicBaseUrl: '/preview-123'`. The fallback is kept only so that existing
40
- * basePath deployments do not break on upgrade, which makes removing it a deliberate decision
41
- * rather than a cleanup - it is option 1 of
32
+ * The fallback is kept only so that existing basePath deployments do not break on upgrade,
33
+ * which makes removing it a deliberate decision rather than a cleanup - it is option 1 of
42
34
  * `.claude/future-tasks/editor-asset-mount-topology.md`, still open.
43
35
  *
44
- * KNOWN LIMITATION: the fallback assumes that topology, and consults none. On a CloudFront/CDK
45
- * deployment a basePath does NOT move the asset space (behaviors are anchored at the distribution
46
- * root), so prefixing is wrong there — the requests still resolve, because `withCanopy`'s
47
- * auto-prefixed `/assets/:path*` rewrite catches them and serves through the CMS Lambda, but they
48
- * bypass the CDN cache and the dedicated transform Lambda. The workaround is real though not
49
- * obvious: set `media.publicBaseUrl` to the distribution origin, which takes precedence here.
50
- * Tracked in `.claude/future-tasks/editor-asset-mount-topology.md`.
36
+ * KNOWN LIMITATION: on a CloudFront/CDK deployment, a basePath does NOT move the asset
37
+ * space (behaviors are anchored at the distribution root), so this fallback prefixes
38
+ * wrongly — requests still resolve, via `withCanopy`'s auto-prefixed `/assets/:path*`
39
+ * rewrite, but bypass the CDN cache and the dedicated transform Lambda. Workaround: set
40
+ * `media.publicBaseUrl` to the distribution origin instead, which takes precedence here.
51
41
  */
52
42
  export declare function AssetContextProvider({ baseUrl, basePath, children }: AssetContextProviderProps): import("react/jsx-runtime").JSX.Element;
53
43
  /** Safe to call outside a provider - returns `{ baseUrl: undefined }` (root-relative URLs). */
@@ -1,8 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  /**
4
- * Asset Context
5
- *
6
4
  * Carries `media.publicBaseUrl` (see CanopyClientConfig.assetBaseUrl) down to
7
5
  * every asset-URL-building component - MediaLibrary, ImageField, and the MDX
8
6
  * image dialog. A context (rather than a prop) because the MDX dialog is
@@ -22,23 +20,15 @@ const AssetContext = createContext({});
22
20
  * full, and a deployment `basePath` cannot apply on top of it. Where the two differ is topology,
23
21
  * not precedence - see the asset-mount table in the README.
24
22
  *
25
- * WHY THE FALLBACK EXISTS, AND WHY THAT REASON IS NOW GONE. It was added because
26
- * `publicBaseUrl` was validated absolute-only (`z.string().url()`) and so could not express a
27
- * bare path, leaving the editor's thumbnails, previews and crop images root-relative — and 404 —
28
- * on a basePath deployment where Next serves `/assets`. That constraint was lifted when
29
- * `publicBaseUrl` moved to `assetMountUrlSchema`, which accepts a site-relative path: an adopter
30
- * can now simply set `publicBaseUrl: '/preview-123'`. The fallback is kept only so that existing
31
- * basePath deployments do not break on upgrade, which makes removing it a deliberate decision
32
- * rather than a cleanup - it is option 1 of
23
+ * The fallback is kept only so that existing basePath deployments do not break on upgrade,
24
+ * which makes removing it a deliberate decision rather than a cleanup - it is option 1 of
33
25
  * `.claude/future-tasks/editor-asset-mount-topology.md`, still open.
34
26
  *
35
- * KNOWN LIMITATION: the fallback assumes that topology, and consults none. On a CloudFront/CDK
36
- * deployment a basePath does NOT move the asset space (behaviors are anchored at the distribution
37
- * root), so prefixing is wrong there — the requests still resolve, because `withCanopy`'s
38
- * auto-prefixed `/assets/:path*` rewrite catches them and serves through the CMS Lambda, but they
39
- * bypass the CDN cache and the dedicated transform Lambda. The workaround is real though not
40
- * obvious: set `media.publicBaseUrl` to the distribution origin, which takes precedence here.
41
- * Tracked in `.claude/future-tasks/editor-asset-mount-topology.md`.
27
+ * KNOWN LIMITATION: on a CloudFront/CDK deployment, a basePath does NOT move the asset
28
+ * space (behaviors are anchored at the distribution root), so this fallback prefixes
29
+ * wrongly — requests still resolve, via `withCanopy`'s auto-prefixed `/assets/:path*`
30
+ * rewrite, but bypass the CDN cache and the dedicated transform Lambda. Workaround: set
31
+ * `media.publicBaseUrl` to the distribution origin instead, which takes precedence here.
42
32
  */
43
33
  export function AssetContextProvider({ baseUrl, basePath, children }) {
44
34
  const resolved = baseUrl ?? basePath;
@@ -0,0 +1,13 @@
1
+ import type { UserContext } from '../BranchManager.js';
2
+ /**
3
+ * The identity `EditorAuthGate` resolved for the editor below it. Present only inside the gate;
4
+ * `useUserContext` reads it so the editor shares the gate's one `whoami` instead of issuing its
5
+ * own.
6
+ */
7
+ export interface EditorIdentity {
8
+ /** The server-accepted identity; the gate mounts the editor only once it has one. */
9
+ user: UserContext;
10
+ }
11
+ export declare const EditorIdentityContext: import("react").Context<EditorIdentity | null>;
12
+ /** The gate's resolved identity, or null outside an `EditorAuthGate`. */
13
+ export declare function useEditorIdentity(): EditorIdentity | null;
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { createContext, useContext } from 'react';
3
+ export const EditorIdentityContext = createContext(null);
4
+ /** The gate's resolved identity, or null outside an `EditorAuthGate`. */
5
+ export function useEditorIdentity() {
6
+ return useContext(EditorIdentityContext);
7
+ }