canopycms 0.0.68-int.98 → 0.1.0

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 (688) hide show
  1. package/CHANGELOG.md +2131 -0
  2. package/README.md +47 -63
  3. package/dist/ai/generate.d.ts +5 -0
  4. package/dist/ai/generate.js +244 -115
  5. package/dist/ai/index.d.ts +1 -1
  6. package/dist/ai/json-to-markdown.d.ts +21 -1
  7. package/dist/ai/json-to-markdown.js +120 -57
  8. package/dist/ai/references.d.ts +72 -0
  9. package/dist/ai/references.js +223 -0
  10. package/dist/ai/resolve-branch.js +9 -2
  11. package/dist/ai/to-plain-text.d.ts +17 -8
  12. package/dist/ai/to-plain-text.js +18 -15
  13. package/dist/ai/types.d.ts +84 -3
  14. package/dist/api/admin-branch-health.d.ts +24 -1
  15. package/dist/api/admin-branch-health.js +52 -20
  16. package/dist/api/admin.d.ts +23 -5
  17. package/dist/api/admin.js +36 -1
  18. package/dist/api/assets.js +88 -78
  19. package/dist/api/branch-create-window.d.ts +12 -0
  20. package/dist/api/branch-create-window.js +13 -0
  21. package/dist/api/branch-merge.d.ts +1 -1
  22. package/dist/api/branch-merge.js +1 -1
  23. package/dist/api/branch-review.d.ts +3 -3
  24. package/dist/api/branch-review.js +16 -7
  25. package/dist/api/branch-status.d.ts +16 -6
  26. package/dist/api/branch-status.js +57 -12
  27. package/dist/api/branch-withdraw.d.ts +2 -2
  28. package/dist/api/branch-withdraw.js +8 -3
  29. package/dist/api/branch.d.ts +25 -12
  30. package/dist/api/branch.js +164 -103
  31. package/dist/api/client.d.ts +78 -58
  32. package/dist/api/client.js +150 -117
  33. package/dist/api/comments.d.ts +12 -3
  34. package/dist/api/comments.js +118 -9
  35. package/dist/api/content.d.ts +9 -9
  36. package/dist/api/content.js +131 -22
  37. package/dist/api/entries-constants.d.ts +14 -3
  38. package/dist/api/entries-constants.js +14 -3
  39. package/dist/api/entries.d.ts +40 -2
  40. package/dist/api/entries.js +102 -6
  41. package/dist/api/github-sync.d.ts +19 -0
  42. package/dist/api/github-sync.js +50 -3
  43. package/dist/api/groups.d.ts +4 -4
  44. package/dist/api/groups.js +2 -1
  45. package/dist/api/guards.js +23 -3
  46. package/dist/api/index.d.ts +3 -1
  47. package/dist/api/index.js +1 -0
  48. package/dist/api/permissions.d.ts +21 -2
  49. package/dist/api/permissions.js +50 -3
  50. package/dist/api/request-deadline.d.ts +59 -0
  51. package/dist/api/request-deadline.js +73 -0
  52. package/dist/api/resolve-references.js +8 -7
  53. package/dist/api/route-builder.d.ts +14 -0
  54. package/dist/api/route-builder.js +14 -1
  55. package/dist/api/schema.d.ts +11 -9
  56. package/dist/api/schema.js +2 -0
  57. package/dist/api/settings-helpers.d.ts +5 -1
  58. package/dist/api/settings-helpers.js +10 -2
  59. package/dist/api/types.d.ts +18 -0
  60. package/dist/api/users-constants.d.ts +6 -0
  61. package/dist/api/users-constants.js +6 -0
  62. package/dist/assets/asset-url.d.ts +28 -16
  63. package/dist/assets/asset-url.js +51 -25
  64. package/dist/assets/finalize.js +3 -0
  65. package/dist/assets/index.d.ts +1 -1
  66. package/dist/assets/materialize.d.ts +153 -0
  67. package/dist/assets/materialize.js +402 -0
  68. package/dist/assets/store-local.d.ts +19 -5
  69. package/dist/assets/store-local.js +69 -10
  70. package/dist/assets/store-s3.d.ts +38 -7
  71. package/dist/assets/store-s3.js +128 -22
  72. package/dist/assets/transform-directives.d.ts +52 -13
  73. package/dist/assets/transform-directives.js +87 -27
  74. package/dist/assets/transform.d.ts +3 -3
  75. package/dist/assets/transform.js +13 -8
  76. package/dist/assets/types.d.ts +31 -4
  77. package/dist/auth/cache.d.ts +1 -1
  78. package/dist/auth/cache.js +1 -1
  79. package/dist/auth/caching-auth-plugin.d.ts +2 -0
  80. package/dist/auth/caching-auth-plugin.js +12 -2
  81. package/dist/auth/file-based-auth-cache.d.ts +8 -0
  82. package/dist/auth/file-based-auth-cache.js +18 -8
  83. package/dist/auth/person-name.d.ts +5 -0
  84. package/dist/auth/person-name.js +8 -0
  85. package/dist/auth/plugin.d.ts +10 -1
  86. package/dist/auth/types.d.ts +2 -0
  87. package/dist/auth/user-metadata-lookup.d.ts +21 -0
  88. package/dist/auth/user-metadata-lookup.js +116 -0
  89. package/dist/authorization/branch.d.ts +1 -1
  90. package/dist/authorization/branch.js +12 -13
  91. package/dist/authorization/groups/schema.d.ts +4 -4
  92. package/dist/authorization/helpers.d.ts +8 -0
  93. package/dist/authorization/helpers.js +8 -0
  94. package/dist/authorization/index.d.ts +1 -1
  95. package/dist/authorization/index.js +1 -1
  96. package/dist/authorization/protected-branch.d.ts +5 -4
  97. package/dist/authorization/protected-branch.js +7 -5
  98. package/dist/branch-health.d.ts +35 -8
  99. package/dist/branch-health.js +54 -18
  100. package/dist/branch-metadata-error.d.ts +27 -0
  101. package/dist/branch-metadata-error.js +23 -0
  102. package/dist/branch-metadata-file.d.ts +205 -24
  103. package/dist/branch-metadata-file.js +126 -25
  104. package/dist/branch-metadata.d.ts +45 -6
  105. package/dist/branch-metadata.js +142 -50
  106. package/dist/branch-provisioning.d.ts +167 -0
  107. package/dist/branch-provisioning.js +501 -0
  108. package/dist/branch-registry.d.ts +8 -0
  109. package/dist/branch-registry.js +61 -9
  110. package/dist/branch-schema-cache.d.ts +29 -12
  111. package/dist/branch-schema-cache.js +64 -21
  112. package/dist/branch-sparse.d.ts +23 -0
  113. package/dist/branch-sparse.js +118 -0
  114. package/dist/branch-workspace.d.ts +42 -3
  115. package/dist/branch-workspace.js +239 -100
  116. package/dist/build/asset-refs.d.ts +94 -0
  117. package/dist/build/asset-refs.js +267 -0
  118. package/dist/build/generate-ai-content.js +5 -0
  119. package/dist/build/inline-flight.d.ts +37 -0
  120. package/dist/build/inline-flight.js +142 -0
  121. package/dist/cli/asset-refs.d.ts +52 -0
  122. package/dist/cli/asset-refs.js +194 -0
  123. package/dist/cli/cli.d.ts +15 -1
  124. package/dist/cli/cli.js +8543 -3193
  125. package/dist/cli/configured-asset-store.d.ts +12 -0
  126. package/dist/cli/configured-asset-store.js +46 -0
  127. package/dist/cli/generate-ai-content.js +4244 -1072
  128. package/dist/cli/init.js +217 -126
  129. package/dist/cli/project-detect.d.ts +2 -0
  130. package/dist/cli/project-detect.js +2 -0
  131. package/dist/cli/template-files/Dockerfile.cms.template +13 -5
  132. package/dist/cli/template-files/cms-stack.ts.template +16 -13
  133. package/dist/client.d.ts +1 -2
  134. package/dist/client.js +1 -2
  135. package/dist/comment-store.d.ts +25 -0
  136. package/dist/comment-store.js +43 -8
  137. package/dist/config/flatten.js +2 -0
  138. package/dist/config/helpers.js +2 -2
  139. package/dist/config/index.d.ts +1 -1
  140. package/dist/config/schemas/config.d.ts +12 -29
  141. package/dist/config/schemas/config.js +9 -12
  142. package/dist/config/schemas/field.d.ts +3 -0
  143. package/dist/config/schemas/field.js +58 -4
  144. package/dist/config/schemas/media.d.ts +4 -13
  145. package/dist/config/schemas/media.js +5 -8
  146. package/dist/config/schemas/url.d.ts +2 -20
  147. package/dist/config/schemas/url.js +2 -25
  148. package/dist/config/types.d.ts +116 -22
  149. package/dist/config/types.js +3 -9
  150. package/dist/config/validation.d.ts +25 -4
  151. package/dist/config/validation.js +116 -3
  152. package/dist/content-id-index.js +2 -2
  153. package/dist/content-index-generation.d.ts +1 -1
  154. package/dist/content-index-generation.js +1 -1
  155. package/dist/content-listing.d.ts +10 -1
  156. package/dist/content-listing.js +22 -5
  157. package/dist/content-reader.d.ts +9 -0
  158. package/dist/content-reader.js +16 -11
  159. package/dist/content-store.d.ts +75 -12
  160. package/dist/content-store.js +249 -86
  161. package/dist/content-tree.js +2 -2
  162. package/dist/context.js +5 -2
  163. package/dist/dangling-reference-log.d.ts +17 -0
  164. package/dist/dangling-reference-log.js +29 -0
  165. package/dist/dev-content-watcher.d.ts +1 -1
  166. package/dist/dev-content-watcher.js +1 -1
  167. package/dist/editor/BranchManager.d.ts +23 -7
  168. package/dist/editor/BranchManager.js +119 -54
  169. package/dist/editor/CanopyEditor.d.ts +1 -1
  170. package/dist/editor/CanopyEditor.js +1 -2
  171. package/dist/editor/CommentsPanel.d.ts +14 -0
  172. package/dist/editor/CommentsPanel.js +68 -43
  173. package/dist/editor/Editor.d.ts +11 -5
  174. package/dist/editor/Editor.js +891 -218
  175. package/dist/editor/EditorAuthGate.d.ts +7 -1
  176. package/dist/editor/EditorAuthGate.js +41 -9
  177. package/dist/editor/EntryNavigator.d.ts +22 -0
  178. package/dist/editor/EntryNavigator.js +353 -105
  179. package/dist/editor/FormHeader.d.ts +25 -0
  180. package/dist/editor/FormHeader.js +82 -0
  181. package/dist/editor/FormRenderer.d.ts +27 -3
  182. package/dist/editor/FormRenderer.js +171 -76
  183. package/dist/editor/PreviewFrame.d.ts +40 -0
  184. package/dist/editor/PreviewFrame.js +215 -0
  185. package/dist/editor/PreviewPane.d.ts +47 -0
  186. package/dist/editor/PreviewPane.js +147 -0
  187. package/dist/editor/PreviewToolbarTools.d.ts +22 -0
  188. package/dist/editor/PreviewToolbarTools.js +73 -0
  189. package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
  190. package/dist/editor/admin/SystemHealthPanel.js +163 -33
  191. package/dist/editor/admin/useSystemHealth.d.ts +18 -0
  192. package/dist/editor/admin/useSystemHealth.js +70 -1
  193. package/dist/editor/branch-status.d.ts +17 -0
  194. package/dist/editor/branch-status.js +29 -0
  195. package/dist/editor/canopy-path.d.ts +9 -6
  196. package/dist/editor/canopy-path.js +8 -11
  197. package/dist/editor/client-reference-resolver.d.ts +43 -16
  198. package/dist/editor/client-reference-resolver.js +155 -64
  199. package/dist/editor/comments/BranchComments.d.ts +1 -1
  200. package/dist/editor/comments/BranchComments.js +2 -2
  201. package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
  202. package/dist/editor/comments/CloseRefusedNotice.js +7 -0
  203. package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
  204. package/dist/editor/comments/CommentThreadsPopover.js +274 -0
  205. package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
  206. package/dist/editor/comments/CommentWriteAlert.js +13 -0
  207. package/dist/editor/comments/EntryComments.d.ts +10 -4
  208. package/dist/editor/comments/EntryComments.js +14 -17
  209. package/dist/editor/comments/FieldWrapper.d.ts +18 -4
  210. package/dist/editor/comments/FieldWrapper.js +62 -28
  211. package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
  212. package/dist/editor/comments/InlineCommentThread.js +11 -47
  213. package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
  214. package/dist/editor/comments/ThreadCarousel.js +18 -21
  215. package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
  216. package/dist/editor/comments/ThreadReplyControls.js +92 -0
  217. package/dist/editor/comments/field-comment-context.d.ts +14 -0
  218. package/dist/editor/comments/field-comment-context.js +14 -0
  219. package/dist/editor/comments/form-comments.d.ts +48 -0
  220. package/dist/editor/comments/form-comments.js +178 -0
  221. package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
  222. package/dist/editor/comments/item-anchor-copy.js +6 -0
  223. package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
  224. package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
  225. package/dist/editor/comments/popover-placement.d.ts +18 -0
  226. package/dist/editor/comments/popover-placement.js +58 -0
  227. package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
  228. package/dist/editor/comments/use-tracked-writes.js +53 -0
  229. package/dist/editor/components/BranchAccessList.d.ts +15 -0
  230. package/dist/editor/components/BranchAccessList.js +52 -0
  231. package/dist/editor/components/BranchLockBanner.d.ts +22 -0
  232. package/dist/editor/components/BranchLockBanner.js +39 -0
  233. package/dist/editor/components/BranchPill.d.ts +32 -0
  234. package/dist/editor/components/BranchPill.js +33 -0
  235. package/dist/editor/components/BranchesDrawer.d.ts +11 -0
  236. package/dist/editor/components/BranchesDrawer.js +5 -0
  237. package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
  238. package/dist/editor/components/ConfirmDeleteModal.js +3 -2
  239. package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
  240. package/dist/editor/components/DestructiveMenuItem.js +8 -0
  241. package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
  242. package/dist/editor/components/EditorCrashScreen.js +22 -0
  243. package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
  244. package/dist/editor/components/EditorErrorBoundary.js +40 -0
  245. package/dist/editor/components/EditorHeader.d.ts +56 -106
  246. package/dist/editor/components/EditorHeader.js +130 -131
  247. package/dist/editor/components/EditorRail.d.ts +49 -0
  248. package/dist/editor/components/EditorRail.js +65 -0
  249. package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
  250. package/dist/editor/components/EntryBreadcrumb.js +56 -0
  251. package/dist/editor/components/EntryCreateModal.d.ts +12 -7
  252. package/dist/editor/components/EntryCreateModal.js +51 -57
  253. package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
  254. package/dist/editor/components/NoEditPermissionNotice.js +5 -4
  255. package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
  256. package/dist/editor/components/QuickOpenPalette.js +66 -0
  257. package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
  258. package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
  259. package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
  260. package/dist/editor/components/ReasonedMenuItem.js +15 -0
  261. package/dist/editor/components/ReferencedByList.d.ts +11 -0
  262. package/dist/editor/components/ReferencedByList.js +28 -0
  263. package/dist/editor/components/RelativeTime.d.ts +10 -0
  264. package/dist/editor/components/RelativeTime.js +10 -0
  265. package/dist/editor/components/RenameEntryModal.d.ts +9 -1
  266. package/dist/editor/components/RenameEntryModal.js +19 -31
  267. package/dist/editor/components/RetryToastMessage.d.ts +9 -0
  268. package/dist/editor/components/RetryToastMessage.js +6 -0
  269. package/dist/editor/components/SaveAllResult.d.ts +25 -0
  270. package/dist/editor/components/SaveAllResult.js +86 -0
  271. package/dist/editor/components/SaveSplitButton.d.ts +30 -0
  272. package/dist/editor/components/SaveSplitButton.js +108 -0
  273. package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
  274. package/dist/editor/components/StagedChangesDrawer.js +92 -0
  275. package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
  276. package/dist/editor/components/UnavailableEntryNotice.js +9 -0
  277. package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
  278. package/dist/editor/components/UnavailableTypeMessage.js +9 -0
  279. package/dist/editor/components/UndoToastMessage.d.ts +18 -0
  280. package/dist/editor/components/UndoToastMessage.js +10 -0
  281. package/dist/editor/components/UserBadge.d.ts +2 -5
  282. package/dist/editor/components/UserBadge.js +62 -33
  283. package/dist/editor/components/ValidationSummary.d.ts +14 -0
  284. package/dist/editor/components/ValidationSummary.js +24 -0
  285. package/dist/editor/components/index.d.ts +2 -2
  286. package/dist/editor/components/index.js +2 -2
  287. package/dist/editor/context/ApiClientContext.d.ts +8 -2
  288. package/dist/editor/context/ApiClientContext.js +19 -8
  289. package/dist/editor/context/AssetContext.d.ts +13 -35
  290. package/dist/editor/context/AssetContext.js +12 -31
  291. package/dist/editor/context/EditorStateContext.d.ts +4 -4
  292. package/dist/editor/context/EditorStateContext.js +4 -4
  293. package/dist/editor/context/SWRProvider.d.ts +3 -3
  294. package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
  295. package/dist/editor/context/SiteMdxAllowContext.js +7 -0
  296. package/dist/editor/context/index.d.ts +2 -1
  297. package/dist/editor/context/index.js +2 -1
  298. package/dist/editor/contrast.d.ts +19 -0
  299. package/dist/editor/contrast.js +41 -0
  300. package/dist/editor/copy.d.ts +18 -0
  301. package/dist/editor/copy.js +18 -0
  302. package/dist/editor/editor-config.js +16 -0
  303. package/dist/editor/editor-utils.d.ts +34 -8
  304. package/dist/editor/editor-utils.js +42 -20
  305. package/dist/editor/entry-search.d.ts +20 -0
  306. package/dist/editor/entry-search.js +34 -0
  307. package/dist/editor/field-breadcrumb.d.ts +12 -0
  308. package/dist/editor/field-breadcrumb.js +85 -0
  309. package/dist/editor/field-props.d.ts +86 -0
  310. package/dist/editor/field-props.js +27 -0
  311. package/dist/editor/field-target.d.ts +30 -0
  312. package/dist/editor/field-target.js +77 -0
  313. package/dist/editor/fields/BlockField.d.ts +12 -0
  314. package/dist/editor/fields/BlockField.js +89 -73
  315. package/dist/editor/fields/CodeField.d.ts +2 -0
  316. package/dist/editor/fields/CodeField.js +6 -2
  317. package/dist/editor/fields/DateTimeField.d.ts +4 -29
  318. package/dist/editor/fields/DateTimeField.js +79 -41
  319. package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
  320. package/dist/editor/fields/ExpandAllButton.js +4 -0
  321. package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
  322. package/dist/editor/fields/FieldCrashFallback.js +30 -0
  323. package/dist/editor/fields/FieldLabel.d.ts +37 -0
  324. package/dist/editor/fields/FieldLabel.js +19 -0
  325. package/dist/editor/fields/ImageField.d.ts +4 -0
  326. package/dist/editor/fields/ImageField.js +29 -14
  327. package/dist/editor/fields/InlineGroupField.js +4 -3
  328. package/dist/editor/fields/ItemList.d.ts +42 -0
  329. package/dist/editor/fields/ItemList.js +130 -0
  330. package/dist/editor/fields/MarkdownField.d.ts +32 -0
  331. package/dist/editor/fields/MarkdownField.js +223 -46
  332. package/dist/editor/fields/MdxImageDialog.js +1 -1
  333. package/dist/editor/fields/NumberField.d.ts +2 -0
  334. package/dist/editor/fields/NumberField.js +8 -5
  335. package/dist/editor/fields/NumberListField.d.ts +2 -0
  336. package/dist/editor/fields/NumberListField.js +19 -16
  337. package/dist/editor/fields/ObjectField.d.ts +2 -7
  338. package/dist/editor/fields/ObjectField.js +15 -5
  339. package/dist/editor/fields/ObjectListField.d.ts +29 -0
  340. package/dist/editor/fields/ObjectListField.js +57 -0
  341. package/dist/editor/fields/ReferenceField.d.ts +2 -0
  342. package/dist/editor/fields/ReferenceField.js +34 -9
  343. package/dist/editor/fields/SelectField.d.ts +2 -0
  344. package/dist/editor/fields/SelectField.js +11 -2
  345. package/dist/editor/fields/StringListField.d.ts +4 -1
  346. package/dist/editor/fields/StringListField.js +22 -8
  347. package/dist/editor/fields/TextField.d.ts +2 -0
  348. package/dist/editor/fields/TextField.js +6 -2
  349. package/dist/editor/fields/ToggleField.d.ts +2 -0
  350. package/dist/editor/fields/ToggleField.js +8 -3
  351. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
  352. package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
  353. package/dist/editor/fields/form-expansion.d.ts +9 -0
  354. package/dist/editor/fields/form-expansion.js +2 -0
  355. package/dist/editor/fields/item-expansion.d.ts +15 -0
  356. package/dist/editor/fields/item-expansion.js +60 -0
  357. package/dist/editor/fields/list-item-keys.d.ts +8 -0
  358. package/dist/editor/fields/list-item-keys.js +50 -0
  359. package/dist/editor/fields/list-item-title.d.ts +20 -0
  360. package/dist/editor/fields/list-item-title.js +85 -0
  361. package/dist/editor/fields/markdown-export-options.d.ts +2 -0
  362. package/dist/editor/fields/markdown-export-options.js +8 -0
  363. package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
  364. package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
  365. package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
  366. package/dist/editor/fields/mdx-jsx-support.js +157 -69
  367. package/dist/editor/fields/rich-text-failures.d.ts +5 -0
  368. package/dist/editor/fields/rich-text-failures.js +26 -0
  369. package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
  370. package/dist/editor/fields/toolbar-wrap.js +35 -0
  371. package/dist/editor/form-outline.d.ts +13 -0
  372. package/dist/editor/form-outline.js +70 -0
  373. package/dist/editor/group-manager/GroupCard.d.ts +4 -1
  374. package/dist/editor/group-manager/GroupCard.js +12 -3
  375. package/dist/editor/group-manager/GroupForm.js +1 -1
  376. package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
  377. package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
  378. package/dist/editor/group-manager/MemberList.d.ts +2 -1
  379. package/dist/editor/group-manager/MemberList.js +15 -4
  380. package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
  381. package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
  382. package/dist/editor/group-manager/index.js +34 -5
  383. package/dist/editor/group-manager/types.d.ts +5 -2
  384. package/dist/editor/hooks/create-branch-request.d.ts +20 -0
  385. package/dist/editor/hooks/create-branch-request.js +54 -0
  386. package/dist/editor/hooks/save-all.d.ts +68 -0
  387. package/dist/editor/hooks/save-all.js +61 -0
  388. package/dist/editor/hooks/useBranchActions.d.ts +11 -1
  389. package/dist/editor/hooks/useBranchActions.js +42 -19
  390. package/dist/editor/hooks/useBranchManager.d.ts +21 -0
  391. package/dist/editor/hooks/useBranchManager.js +321 -125
  392. package/dist/editor/hooks/useBranchesData.d.ts +8 -4
  393. package/dist/editor/hooks/useBranchesData.js +9 -5
  394. package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
  395. package/dist/editor/hooks/useCommentSystem.js +79 -55
  396. package/dist/editor/hooks/useCommentsData.d.ts +11 -7
  397. package/dist/editor/hooks/useCommentsData.js +20 -19
  398. package/dist/editor/hooks/useDraftManager.d.ts +77 -3
  399. package/dist/editor/hooks/useDraftManager.js +887 -94
  400. package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
  401. package/dist/editor/hooks/useEditorLayout.js +98 -20
  402. package/dist/editor/hooks/useEntriesData.d.ts +2 -1
  403. package/dist/editor/hooks/useEntriesData.js +18 -4
  404. package/dist/editor/hooks/useEntryManager.d.ts +41 -2
  405. package/dist/editor/hooks/useEntryManager.js +227 -41
  406. package/dist/editor/hooks/useGroupManager.js +13 -16
  407. package/dist/editor/hooks/usePermissionManager.js +14 -6
  408. package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
  409. package/dist/editor/hooks/usePreviewMarks.js +33 -0
  410. package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
  411. package/dist/editor/hooks/useReferenceResolution.js +34 -177
  412. package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
  413. package/dist/editor/hooks/useSchemaManager.js +97 -39
  414. package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
  415. package/dist/editor/hooks/useUserMetadata.js +76 -47
  416. package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
  417. package/dist/editor/hooks/user-metadata-batcher.js +33 -0
  418. package/dist/editor/media/AssetCard.d.ts +6 -7
  419. package/dist/editor/media/AssetCard.js +24 -31
  420. package/dist/editor/media/AssetListRow.d.ts +16 -0
  421. package/dist/editor/media/AssetListRow.js +41 -0
  422. package/dist/editor/media/CropStep.js +6 -1
  423. package/dist/editor/media/MediaLibrary.d.ts +4 -3
  424. package/dist/editor/media/MediaLibrary.js +11 -4
  425. package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
  426. package/dist/editor/media/MediaLibraryBody.js +195 -80
  427. package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
  428. package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
  429. package/dist/editor/media/crop-math.d.ts +3 -4
  430. package/dist/editor/media/crop-math.js +11 -22
  431. package/dist/editor/media/editor-image-src.d.ts +8 -0
  432. package/dist/editor/media/editor-image-src.js +10 -0
  433. package/dist/editor/media/format-bytes.d.ts +2 -0
  434. package/dist/editor/media/format-bytes.js +23 -0
  435. package/dist/editor/media/media-library-prefs.d.ts +23 -0
  436. package/dist/editor/media/media-library-prefs.js +49 -0
  437. package/dist/editor/media/media-library-view.d.ts +34 -0
  438. package/dist/editor/media/media-library-view.js +40 -0
  439. package/dist/editor/media/useAssetLibrary.d.ts +30 -0
  440. package/dist/editor/media/useAssetLibrary.js +126 -0
  441. package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
  442. package/dist/editor/media/useStableAssetOrder.js +37 -0
  443. package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
  444. package/dist/editor/media/useThumbnailFailure.js +16 -0
  445. package/dist/editor/permission-manager/GroupSelector.js +2 -2
  446. package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
  447. package/dist/editor/permission-manager/PermissionEditor.js +15 -4
  448. package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
  449. package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
  450. package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
  451. package/dist/editor/permission-manager/UserSelector.js +3 -3
  452. package/dist/editor/permission-manager/index.js +12 -3
  453. package/dist/editor/permission-manager/types.d.ts +5 -2
  454. package/dist/editor/platform.d.ts +3 -0
  455. package/dist/editor/platform.js +9 -0
  456. package/dist/editor/preview-asset-base.d.ts +9 -0
  457. package/dist/editor/preview-asset-base.js +17 -0
  458. package/dist/editor/preview-bridge.d.ts +51 -27
  459. package/dist/editor/preview-bridge.js +103 -144
  460. package/dist/editor/preview-marks.d.ts +15 -0
  461. package/dist/editor/preview-marks.js +74 -0
  462. package/dist/editor/preview-path.d.ts +12 -0
  463. package/dist/editor/preview-path.js +45 -1
  464. package/dist/editor/preview-scale.d.ts +27 -0
  465. package/dist/editor/preview-scale.js +34 -0
  466. package/dist/editor/raw-asset-base.d.ts +5 -0
  467. package/dist/editor/raw-asset-base.js +14 -0
  468. package/dist/editor/relative-time.d.ts +4 -4
  469. package/dist/editor/relative-time.js +16 -8
  470. package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
  471. package/dist/editor/schema-editor/CollectionEditor.js +361 -62
  472. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
  473. package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
  474. package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
  475. package/dist/editor/schema-editor/collection-draft.js +40 -0
  476. package/dist/editor/schema-editor/index.d.ts +1 -1
  477. package/dist/editor/schema-label.d.ts +10 -0
  478. package/dist/editor/schema-label.js +17 -0
  479. package/dist/editor/settings-conflict.d.ts +5 -0
  480. package/dist/editor/settings-conflict.js +8 -0
  481. package/dist/editor/shell/ActivityRail.d.ts +37 -0
  482. package/dist/editor/shell/ActivityRail.js +91 -0
  483. package/dist/editor/shell/EditorShell.d.ts +17 -0
  484. package/dist/editor/shell/EditorShell.js +31 -0
  485. package/dist/editor/shell/PaneLayout.d.ts +28 -0
  486. package/dist/editor/shell/PaneLayout.js +116 -0
  487. package/dist/editor/shell/SidePanelHost.d.ts +35 -0
  488. package/dist/editor/shell/SidePanelHost.js +184 -0
  489. package/dist/editor/shell/TopBar.d.ts +12 -0
  490. package/dist/editor/shell/TopBar.js +14 -0
  491. package/dist/editor/shell/host-chrome.d.ts +16 -0
  492. package/dist/editor/shell/host-chrome.js +69 -0
  493. package/dist/editor/slug.d.ts +16 -0
  494. package/dist/editor/slug.js +43 -0
  495. package/dist/editor/theme.d.ts +2 -1
  496. package/dist/editor/theme.js +314 -13
  497. package/dist/editor/unanswered.d.ts +17 -0
  498. package/dist/editor/unanswered.js +26 -0
  499. package/dist/editor/unavailable-entry-type.d.ts +20 -0
  500. package/dist/editor/unavailable-entry-type.js +28 -0
  501. package/dist/editor/undo-removal.d.ts +57 -0
  502. package/dist/editor/undo-removal.js +163 -0
  503. package/dist/editor/user-display.d.ts +4 -0
  504. package/dist/editor/user-display.js +5 -0
  505. package/dist/editor/utils/confirm-modal.d.ts +8 -0
  506. package/dist/editor/utils/confirm-modal.js +12 -0
  507. package/dist/editor/utils/editor-errors.d.ts +19 -0
  508. package/dist/editor/utils/editor-errors.js +32 -0
  509. package/dist/editor/utils/focus-return.d.ts +56 -0
  510. package/dist/editor/utils/focus-return.js +106 -0
  511. package/dist/entry-link-resolver.d.ts +11 -1
  512. package/dist/entry-link-resolver.js +65 -5
  513. package/dist/entry-schema-registry.d.ts +3 -3
  514. package/dist/entry-schema-registry.js +7 -4
  515. package/dist/entry-schema.d.ts +49 -3
  516. package/dist/entry-schema.js +18 -0
  517. package/dist/git-manager.d.ts +172 -10
  518. package/dist/git-manager.js +449 -107
  519. package/dist/github-service.d.ts +39 -2
  520. package/dist/github-service.js +101 -7
  521. package/dist/http/handler.js +74 -9
  522. package/dist/http/types.d.ts +2 -0
  523. package/dist/http/worker-not-ready.d.ts +9 -4
  524. package/dist/http/worker-not-ready.js +59 -6
  525. package/dist/index.d.ts +2 -0
  526. package/dist/index.js +3 -0
  527. package/dist/item-keys.d.ts +46 -0
  528. package/dist/item-keys.js +235 -0
  529. package/dist/operating-mode/editor-mode-check.d.ts +15 -0
  530. package/dist/operating-mode/editor-mode-check.js +24 -0
  531. package/dist/operating-mode/mode-env.d.ts +13 -14
  532. package/dist/operating-mode/mode-env.js +13 -14
  533. package/dist/operating-mode/types.d.ts +2 -2
  534. package/dist/paths/branch.d.ts +0 -1
  535. package/dist/paths/branch.js +1 -8
  536. package/dist/paths/index.d.ts +1 -1
  537. package/dist/paths/index.js +1 -1
  538. package/dist/paths/validation.js +0 -2
  539. package/dist/preview.d.ts +8 -0
  540. package/dist/preview.js +7 -0
  541. package/dist/reference-resolver.js +1 -0
  542. package/dist/resolve-canopy-user.d.ts +1 -1
  543. package/dist/resolve-canopy-user.js +1 -1
  544. package/dist/schema/meta-loader.d.ts +18 -8
  545. package/dist/schema/meta-loader.js +42 -9
  546. package/dist/schema/registry-fingerprint.d.ts +14 -0
  547. package/dist/schema/registry-fingerprint.js +63 -0
  548. package/dist/schema/resolver.d.ts +7 -4
  549. package/dist/schema/resolver.js +7 -6
  550. package/dist/schema/schema-store.d.ts +7 -10
  551. package/dist/schema/schema-store.js +13 -11
  552. package/dist/schema/schema-unavailable-error.d.ts +11 -0
  553. package/dist/schema/schema-unavailable-error.js +15 -0
  554. package/dist/schema/types.d.ts +22 -0
  555. package/dist/schema-registry-record.d.ts +35 -0
  556. package/dist/schema-registry-record.js +134 -0
  557. package/dist/server.d.ts +79 -9
  558. package/dist/server.js +62 -8
  559. package/dist/services.d.ts +33 -5
  560. package/dist/services.js +155 -37
  561. package/dist/settings-workspace.d.ts +23 -3
  562. package/dist/settings-workspace.js +159 -45
  563. package/dist/stamp-on-publish.d.ts +36 -0
  564. package/dist/stamp-on-publish.js +71 -0
  565. package/dist/static/index.d.ts +58 -5
  566. package/dist/static/index.js +133 -3
  567. package/dist/static/seo.d.ts +5 -5
  568. package/dist/static/seo.js +5 -5
  569. package/dist/submission-attribution.d.ts +8 -0
  570. package/dist/submission-attribution.js +22 -0
  571. package/dist/system-users.d.ts +12 -0
  572. package/dist/system-users.js +12 -0
  573. package/dist/task-queue/cms-task-queue.d.ts +1 -1
  574. package/dist/task-queue/cms-task-queue.js +1 -1
  575. package/dist/task-queue/index.d.ts +1 -1
  576. package/dist/task-queue/index.js +1 -1
  577. package/dist/task-queue/task-queue.d.ts +6 -0
  578. package/dist/task-queue/task-queue.js +29 -0
  579. package/dist/task-queue/worker-status.d.ts +35 -9
  580. package/dist/task-queue/worker-status.js +84 -17
  581. package/dist/types.d.ts +90 -9
  582. package/dist/url-collision.js +3 -3
  583. package/dist/url-exclusivity-fixtures.d.ts +8 -1
  584. package/dist/url-exclusivity-fixtures.js +11 -1
  585. package/dist/user.js +2 -1
  586. package/dist/utils/atomic-write.js +2 -1
  587. package/dist/utils/base-branch.d.ts +13 -0
  588. package/dist/utils/base-branch.js +23 -0
  589. package/dist/utils/content-serialize.d.ts +15 -7
  590. package/dist/utils/content-serialize.js +353 -51
  591. package/dist/utils/content-write-lock.d.ts +6 -1
  592. package/dist/utils/content-write-lock.js +21 -6
  593. package/dist/utils/debug.d.ts +1 -1
  594. package/dist/utils/debug.js +5 -3
  595. package/dist/utils/error.js +13 -2
  596. package/dist/utils/escape-text.d.ts +7 -0
  597. package/dist/utils/escape-text.js +27 -0
  598. package/dist/utils/fs.d.ts +12 -4
  599. package/dist/utils/fs.js +18 -5
  600. package/dist/utils/git.d.ts +21 -1
  601. package/dist/utils/git.js +63 -8
  602. package/dist/utils/json-source-splice.d.ts +14 -0
  603. package/dist/utils/json-source-splice.js +120 -0
  604. package/dist/utils/markdown-body-splice.d.ts +39 -0
  605. package/dist/utils/markdown-body-splice.js +421 -0
  606. package/dist/utils/occ-json-write.js +18 -12
  607. package/dist/utils/provision-log.d.ts +25 -0
  608. package/dist/utils/provision-log.js +49 -0
  609. package/dist/utils/provisioning-lock.d.ts +32 -1
  610. package/dist/utils/provisioning-lock.js +78 -32
  611. package/dist/utils/sanitize-href.d.ts +9 -23
  612. package/dist/utils/sanitize-href.js +14 -28
  613. package/dist/utils/title-field.d.ts +10 -0
  614. package/dist/utils/title-field.js +47 -0
  615. package/dist/utils/yaml-source-splice.d.ts +58 -0
  616. package/dist/utils/yaml-source-splice.js +515 -0
  617. package/dist/validation/block-structural-keys.d.ts +1 -1
  618. package/dist/validation/block-structural-keys.js +1 -1
  619. package/dist/validation/deletion-checker.d.ts +21 -29
  620. package/dist/validation/deletion-checker.js +41 -117
  621. package/dist/validation/entry-validator.d.ts +6 -10
  622. package/dist/validation/entry-validator.js +19 -26
  623. package/dist/validation/field-traversal.d.ts +22 -0
  624. package/dist/validation/field-traversal.js +39 -8
  625. package/dist/validation/markdown-safety.d.ts +68 -0
  626. package/dist/validation/markdown-safety.js +596 -0
  627. package/dist/validation/mdx-allowlist.d.ts +55 -0
  628. package/dist/validation/mdx-allowlist.js +183 -0
  629. package/dist/validation/reference-validator.d.ts +2 -0
  630. package/dist/validation/reference-validator.js +3 -0
  631. package/dist/version.d.ts +1 -1
  632. package/dist/version.js +1 -1
  633. package/dist/worker/branch-policy.d.ts +124 -0
  634. package/dist/worker/branch-policy.js +243 -0
  635. package/dist/worker/bundle-header.d.ts +117 -0
  636. package/dist/worker/bundle-header.js +253 -0
  637. package/dist/worker/cms-worker.d.ts +236 -142
  638. package/dist/worker/cms-worker.js +772 -285
  639. package/dist/worker/gateway-egress.d.ts +43 -0
  640. package/dist/worker/gateway-egress.js +209 -0
  641. package/dist/worker/gateway-instance.d.ts +42 -0
  642. package/dist/worker/gateway-instance.js +129 -0
  643. package/dist/worker/git-process.d.ts +81 -0
  644. package/dist/worker/git-process.js +234 -0
  645. package/dist/worker/git-sync.d.ts +34 -17
  646. package/dist/worker/git-sync.js +394 -131
  647. package/dist/worker/github-auth.d.ts +9 -9
  648. package/dist/worker/github-auth.js +13 -15
  649. package/dist/worker/github-gateway-http.d.ts +62 -0
  650. package/dist/worker/github-gateway-http.js +977 -0
  651. package/dist/worker/github-gateway-wire.d.ts +590 -0
  652. package/dist/worker/github-gateway-wire.js +488 -0
  653. package/dist/worker/github-gateway.d.ts +238 -0
  654. package/dist/worker/github-gateway.js +726 -0
  655. package/dist/worker/github-mirror-upkeep.d.ts +75 -0
  656. package/dist/worker/github-mirror-upkeep.js +266 -0
  657. package/dist/worker/github-mirror.d.ts +364 -0
  658. package/dist/worker/github-mirror.js +1030 -0
  659. package/dist/worker/github-transfer.d.ts +56 -0
  660. package/dist/worker/github-transfer.js +444 -0
  661. package/dist/worker/history-rewrite.d.ts +4 -5
  662. package/dist/worker/history-rewrite.js +12 -17
  663. package/dist/worker/provisioned-workspace.d.ts +5 -5
  664. package/dist/worker/provisioned-workspace.js +5 -5
  665. package/dist/worker/rebase.d.ts +1 -1
  666. package/dist/worker/rebase.js +58 -54
  667. package/dist/worker/remote-git-maintenance.d.ts +3 -0
  668. package/dist/worker/remote-git-maintenance.js +12 -0
  669. package/dist/worker/schema-gate.d.ts +49 -0
  670. package/dist/worker/schema-gate.js +226 -0
  671. package/dist/worker/self-checks.d.ts +107 -0
  672. package/dist/worker/self-checks.js +358 -0
  673. package/dist/worker/shared-repo-git.d.ts +96 -0
  674. package/dist/worker/shared-repo-git.js +459 -0
  675. package/dist/worker/sparse-cone.d.ts +20 -0
  676. package/dist/worker/sparse-cone.js +136 -0
  677. package/dist/worker/stale-mirror.d.ts +82 -0
  678. package/dist/worker/stale-mirror.js +130 -0
  679. package/dist/worker/task-runner.d.ts +5 -3
  680. package/dist/worker/task-runner.js +287 -186
  681. package/dist/worker/worker-context.d.ts +36 -37
  682. package/package.json +35 -7
  683. package/dist/editor/EditorPanes.d.ts +0 -10
  684. package/dist/editor/EditorPanes.js +0 -98
  685. package/dist/editor/components/EditorFooter.d.ts +0 -11
  686. package/dist/editor/components/EditorFooter.js +0 -9
  687. package/dist/editor/components/EditorSidebar.d.ts +0 -67
  688. package/dist/editor/components/EditorSidebar.js +0 -22
@@ -4,12 +4,19 @@ export interface UseReferenceResolutionOptions {
4
4
  value: FormValue;
5
5
  fields: EntrySchema;
6
6
  branch: string;
7
- onResolvedValueChange?: (resolved: FormValue) => void;
8
- onLoadingStateChange?: (loadingState: FormValue) => void;
7
+ /** Identifies the open entry; when it changes every cached target is fetched again. */
8
+ entryKey?: string;
9
9
  }
10
10
  export interface UseReferenceResolutionResult {
11
+ /** The draft with every reference replaced by its target, or `null` until it has one. */
11
12
  resolvedValue: FormValue;
13
+ /** `true` at each reference position still resolving; see `applyReferenceCache`. */
12
14
  loadingState: FormValue;
13
15
  }
14
- export declare function useReferenceResolution({ value, fields, branch, onResolvedValueChange, onLoadingStateChange, }: UseReferenceResolutionOptions): UseReferenceResolutionResult;
16
+ /**
17
+ * The draft as live preview shows it. Computed during render from the cache, so the first value
18
+ * for a new entry or edit already has no bare ids; a debounced effect then fetches the ids the
19
+ * cache lacks, in batched requests, and re-renders when they arrive.
20
+ */
21
+ export declare function useReferenceResolution({ value, fields, branch, entryKey, }: UseReferenceResolutionOptions): UseReferenceResolutionResult;
15
22
  export {};
@@ -1,189 +1,46 @@
1
1
  import { useEffect, useMemo, useRef, useState } from 'react';
2
- import { resolveChangedReferences } from '../client-reference-resolver.js';
3
- import { flattenGroupFields } from '../../utils/flatten-group-fields.js';
2
+ import { applyReferenceCache, expireReferences, fetchReferences, idsToFetch, storeReferences, } from '../client-reference-resolver.js';
4
3
  import { useOptionalApiClient } from '../context/index.js';
5
- export function useReferenceResolution({ value, fields, branch, onResolvedValueChange, onLoadingStateChange, }) {
6
- // Context-provided client (configured with the deployment's basePath) when this hook is
7
- // rendered inside an ApiClientProvider -- which it always is in the real Editor tree. `null`
8
- // outside one (e.g. FormRenderer.stories.tsx, or this hook's own unwrapped unit tests);
9
- // resolveChangedReferences falls back to a default-configured client in that case.
4
+ /**
5
+ * The draft as live preview shows it. Computed during render from the cache, so the first value
6
+ * for a new entry or edit already has no bare ids; a debounced effect then fetches the ids the
7
+ * cache lacks, in batched requests, and re-renders when they arrive.
8
+ */
9
+ export function useReferenceResolution({ value, fields, branch, entryKey, }) {
10
+ // The context client carries the deployment's basePath. `null` outside an ApiClientProvider
11
+ // (this hook's own unit tests); fetchReferences then falls back to a default client.
10
12
  const apiClient = useOptionalApiClient();
11
- const resolvedCache = useRef(new Map());
12
- const prevValueRef = useRef({}); // Track previous value for change detection
13
- const lastNotifiedValueRef = useRef(''); // Track last notified value to prevent infinite loops
14
- const [resolutionTrigger, setResolutionTrigger] = useState(0); // Trigger to force useMemo re-computation
15
- // Monotonic token identifying the current debounced-resolve attempt.
16
- // Clearing the setTimeout in the effect cleanup only cancels a resolve
17
- // that HASN'T fired yet; once the 300ms elapses and the async callback
18
- // below starts awaiting `resolveChangedReferences`, clearTimeout can no
19
- // longer stop it. The generation check after that await catches the case
20
- // clearTimeout can't: a newer value/branch superseding this attempt, or
21
- // the component unmounting, while the network call was in flight.
22
- const resolveGenerationRef = useRef(0);
23
- const referenceFieldNames = useMemo(() => {
24
- const names = new Set();
25
- for (const field of flattenGroupFields(fields)) {
26
- if (field.type === 'reference') {
27
- names.add(field.name);
28
- }
29
- }
30
- return names;
31
- }, [fields]);
32
- /**
33
- * PHASE 1: SYNCHRONOUS RESOLUTION
34
- *
35
- * Compute resolved value by applying cached reference data to form value.
36
- * This runs synchronously during render (useMemo), so there are no async gaps.
37
- *
38
- * For each reference field:
39
- * - If ID is in cache: substitute full object
40
- * - If ID not in cache: keep the ID (loading state)
41
- *
42
- * Dependencies include resolutionTrigger, which is incremented when cache updates,
43
- * forcing this to re-run and pick up newly-resolved data.
44
- */
45
- const resolvedValue = useMemo(() => {
46
- const result = { ...value };
47
- for (const fieldName of referenceFieldNames) {
48
- const fieldValue = value[fieldName];
49
- if (fieldValue) {
50
- if (Array.isArray(fieldValue)) {
51
- result[fieldName] = fieldValue.map((id) => {
52
- if (typeof id === 'string') {
53
- const cached = resolvedCache.current.get(`${branch}:${id}`);
54
- return cached || null;
55
- }
56
- return id;
57
- });
58
- }
59
- else if (typeof fieldValue === 'string') {
60
- const cached = resolvedCache.current.get(`${branch}:${fieldValue}`);
61
- result[fieldName] = cached || null;
62
- }
63
- }
64
- }
65
- return result;
66
- }, [value, branch, resolutionTrigger, referenceFieldNames]);
67
- /**
68
- * Compute loading state that mirrors the data structure.
69
- * For each reference field, track if it's currently loading (not in cache).
70
- */
71
- const loadingState = useMemo(() => {
72
- const result = {};
73
- for (const fieldName of referenceFieldNames) {
74
- const fieldValue = value[fieldName];
75
- if (fieldValue) {
76
- if (Array.isArray(fieldValue)) {
77
- result[fieldName] = fieldValue.map((id) => {
78
- if (typeof id === 'string') {
79
- return !resolvedCache.current.has(`${branch}:${id}`);
80
- }
81
- return false;
82
- });
83
- }
84
- else if (typeof fieldValue === 'string') {
85
- result[fieldName] = !resolvedCache.current.has(`${branch}:${fieldValue}`);
86
- }
87
- else {
88
- result[fieldName] = false;
89
- }
90
- }
91
- else {
92
- result[fieldName] = false;
93
- }
94
- }
95
- return result;
96
- }, [value, branch, resolutionTrigger, referenceFieldNames]);
97
- /**
98
- * PHASE 2: BACKGROUND ASYNC RESOLUTION
99
- *
100
- * Find reference IDs that aren't in cache yet and fetch them from the API.
101
- */
13
+ // One map per branch, so a request for a branch left behind stores into an orphaned map.
14
+ const cacheRef = useRef(new Map());
15
+ // The cache is a ref, so a fetch that fills it bumps this to recompute the memo below.
16
+ const [cacheVersion, setCacheVersion] = useState(0);
17
+ const { resolvedValue, loadingState } = useMemo(() => applyReferenceCache(fields, value, branch, cacheRef.current), [fields, value, branch, cacheVersion]);
18
+ // These two are declared before the fetch effect, so it sees their result in the same commit.
102
19
  useEffect(() => {
103
- const uncachedIds = new Set();
104
- for (const fieldName of referenceFieldNames) {
105
- const fieldValue = value[fieldName];
106
- if (fieldValue) {
107
- const ids = Array.isArray(fieldValue) ? fieldValue : [fieldValue];
108
- for (const id of ids) {
109
- if (typeof id === 'string' && !resolvedCache.current.has(`${branch}:${id}`)) {
110
- uncachedIds.add(id);
111
- }
112
- }
113
- }
114
- }
115
- if (uncachedIds.size === 0) {
116
- prevValueRef.current = value;
20
+ cacheRef.current = new Map();
21
+ setCacheVersion((prev) => prev + 1);
22
+ }, [branch]);
23
+ useEffect(() => {
24
+ expireReferences(cacheRef.current);
25
+ }, [entryKey]);
26
+ // Asks for all the cache lacks, even ids still in flight; the next edit retries a failure.
27
+ useEffect(() => {
28
+ const cache = cacheRef.current;
29
+ const ids = idsToFetch(fields, value, branch, cache, Date.now());
30
+ if (ids.length === 0)
117
31
  return;
118
- }
119
- // Claim a generation for this attempt before scheduling the debounce, so
120
- // the check below always compares against the token captured at the
121
- // moment THIS attempt was scheduled -- not whatever the ref happens to
122
- // hold when the callback resumes after its await.
123
- const generation = ++resolveGenerationRef.current;
124
32
  const timeout = setTimeout(async () => {
125
33
  try {
126
- const updates = await resolveChangedReferences(prevValueRef.current, value, fields, branch, resolvedCache.current, apiClient ?? undefined);
127
- // A newer value/branch superseded this attempt, or the component
128
- // unmounted, while the request above was in flight -- discard.
129
- if (generation !== resolveGenerationRef.current)
130
- return;
131
- for (const [fieldName, resolvedFieldValue] of Object.entries(updates)) {
132
- if (Array.isArray(resolvedFieldValue)) {
133
- resolvedFieldValue.forEach((obj, idx) => {
134
- const fieldValue = value[fieldName];
135
- if (Array.isArray(fieldValue)) {
136
- const id = fieldValue[idx];
137
- if (typeof obj === 'object' && obj !== null && typeof id === 'string') {
138
- resolvedCache.current.set(`${branch}:${id}`, obj);
139
- }
140
- }
141
- });
142
- }
143
- else if (typeof resolvedFieldValue === 'object' && resolvedFieldValue !== null) {
144
- const id = value[fieldName];
145
- if (typeof id === 'string') {
146
- resolvedCache.current.set(`${branch}:${id}`, resolvedFieldValue);
147
- }
148
- }
149
- }
150
- setResolutionTrigger((prev) => prev + 1);
151
- prevValueRef.current = value;
34
+ const found = await fetchReferences(ids, branch, apiClient ?? undefined);
35
+ // Keyed by branch and id, a result stays valid however the draft changed meanwhile.
36
+ storeReferences(cache, branch, found, Date.now());
37
+ setCacheVersion((prev) => prev + 1);
152
38
  }
153
39
  catch (error) {
154
40
  console.error('Reference resolution failed:', error);
155
41
  }
156
- }, 300); // 300ms debounce
157
- return () => {
158
- clearTimeout(timeout);
159
- // Invalidate this attempt's generation on cleanup too, not just when a
160
- // newer effect run claims the next one: cleanup is what fires on
161
- // unmount, where there IS no next run to bump the counter otherwise.
162
- ++resolveGenerationRef.current;
163
- };
164
- }, [value, fields, branch, referenceFieldNames, apiClient]);
165
- useEffect(() => {
166
- resolvedCache.current.clear();
167
- setResolutionTrigger((prev) => prev + 1);
168
- }, [branch]);
169
- // Notify parent of resolved value changes (with infinite loop prevention)
170
- useEffect(() => {
171
- const serialized = JSON.stringify(resolvedValue);
172
- if (serialized !== lastNotifiedValueRef.current) {
173
- lastNotifiedValueRef.current = serialized;
174
- onResolvedValueChange?.(resolvedValue);
175
- }
176
- }, [resolvedValue, onResolvedValueChange]);
177
- const lastNotifiedLoadingRef = useRef('');
178
- useEffect(() => {
179
- const serialized = JSON.stringify(loadingState);
180
- if (serialized !== lastNotifiedLoadingRef.current) {
181
- lastNotifiedLoadingRef.current = serialized;
182
- onLoadingStateChange?.(loadingState);
183
- }
184
- }, [loadingState, onLoadingStateChange]);
185
- return {
186
- resolvedValue,
187
- loadingState,
188
- };
42
+ }, 300);
43
+ return () => clearTimeout(timeout);
44
+ }, [value, fields, branch, entryKey, apiClient]);
45
+ return { resolvedValue, loadingState };
189
46
  }
@@ -1,4 +1,5 @@
1
1
  import type { CreateCollectionInput, UpdateCollectionInput, CreateEntryTypeInput, UpdateEntryTypeInput } from '../../api/index.js';
2
+ import type { EntryReferencedBy } from '../../api/entries.js';
2
3
  import type { LogicalPath, ContentId } from '../../paths/types.js';
3
4
  export interface UseSchemaManagerOptions {
4
5
  branchName: string;
@@ -15,9 +16,28 @@ export interface UseSchemaManagerOptions {
15
16
  */
16
17
  export type SchemaOpResult = {
17
18
  ok: true;
18
- } | {
19
+ } | SchemaOpFailure;
20
+ /**
21
+ * `unanswered`: the write timed out or got a gateway's 5xx page, so it may have landed
22
+ * (`editor/unanswered.ts`); `onSchemaChange` has been called so the content tree shows which.
23
+ */
24
+ type SchemaOpFailure = {
25
+ ok: false;
26
+ error: string;
27
+ unanswered?: true;
28
+ };
29
+ /** Takes down a collection create's or details save's unknown-outcome toast, once it landed. */
30
+ export declare const hideCollectionOutcomeUnknown: () => void;
31
+ /** @internal Exported for tests. */
32
+ export declare const schemaChangeOutcomeUnknown: (action: string, check: string) => string;
33
+ /**
34
+ * {@link SchemaOpResult}, or a refusal because other entries reference the one being deleted.
35
+ * That refusal shows no toast: the caller asks the user, then retries with `confirmReferenced`.
36
+ */
37
+ type DeleteEntryResult = SchemaOpResult | {
19
38
  ok: false;
20
39
  error: string;
40
+ referencedBy: EntryReferencedBy;
21
41
  };
22
42
  /** Same shape as {@link SchemaOpResult}, plus a payload on success. */
23
43
  type CreateCollectionResult = {
@@ -26,10 +46,7 @@ type CreateCollectionResult = {
26
46
  collectionPath: LogicalPath;
27
47
  contentId: ContentId;
28
48
  };
29
- } | {
30
- ok: false;
31
- error: string;
32
- };
49
+ } | SchemaOpFailure;
33
50
  export interface UseSchemaManagerReturn {
34
51
  createCollection: (input: CreateCollectionInput) => Promise<CreateCollectionResult>;
35
52
  updateCollection: (collectionPath: LogicalPath, updates: UpdateCollectionInput) => Promise<SchemaOpResult>;
@@ -38,7 +55,9 @@ export interface UseSchemaManagerReturn {
38
55
  updateEntryType: (collectionPath: LogicalPath, entryTypeName: string, updates: UpdateEntryTypeInput) => Promise<SchemaOpResult>;
39
56
  removeEntryType: (collectionPath: LogicalPath, entryTypeName: string) => Promise<SchemaOpResult>;
40
57
  updateOrder: (collectionPath: LogicalPath, order: string[]) => Promise<SchemaOpResult>;
41
- deleteEntry: (entryPath: LogicalPath) => Promise<SchemaOpResult>;
58
+ deleteEntry: (entryPath: LogicalPath, options?: {
59
+ confirmReferenced?: boolean;
60
+ }) => Promise<DeleteEntryResult>;
42
61
  isLoading: boolean;
43
62
  }
44
63
  /**
@@ -2,6 +2,17 @@ import { useState, useCallback } from 'react';
2
2
  import { notifications } from '@mantine/notifications';
3
3
  import { useApiClient } from '../context/index.js';
4
4
  import { getErrorMessage } from '../../utils/error.js';
5
+ import { isGatewayFailure, isUnanswered, UnansweredError } from '../unanswered.js';
6
+ const SCHEMA_OUTCOME_UNKNOWN_TOAST_ID = 'canopy-schema-outcome-unknown';
7
+ // A collection create or details save has its own, so settling one leaves another write's up.
8
+ const COLLECTION_OUTCOME_UNKNOWN_TOAST_ID = 'canopy-collection-outcome-unknown';
9
+ const CHECK_CONTENT_PANEL = 'Check the "Content" panel';
10
+ /** Takes down a collection create's or details save's unknown-outcome toast, once it landed. */
11
+ export const hideCollectionOutcomeUnknown = () => {
12
+ notifications.hide(COLLECTION_OUTCOME_UNKNOWN_TOAST_ID);
13
+ };
14
+ /** @internal Exported for tests. */
15
+ export const schemaChangeOutcomeUnknown = (action, check) => `${action} may have gone through even though the server didn't answer. ${check} before trying again.`;
5
16
  /**
6
17
  * Hook for managing schema operations (collections, entry types, ordering).
7
18
  *
@@ -10,23 +21,50 @@ import { getErrorMessage } from '../../utils/error.js';
10
21
  export function useSchemaManager(options) {
11
22
  const apiClient = useApiClient();
12
23
  const [isLoading, setIsLoading] = useState(false);
13
- // Toasts on every failure (relied on by fire-and-forget callers that ignore
14
- // the returned result) and returns the underlying message so callers that
15
- // do inspect the result can also surface it inline (e.g. in a modal).
16
- const handleError = useCallback((message, error) => {
24
+ // Collection, order and entry operations toast each failure that reaches here
25
+ // (relied on by fire-and-forget callers that ignore the returned result).
26
+ // Entry-type operations pass `toast: false`: their only caller,
27
+ // CollectionEditor, shows each result inline. Both return the underlying
28
+ // message for callers that surface it themselves.
29
+ const handleError = useCallback((message, error, { toast = true } = {}) => {
17
30
  console.error(message, error);
18
31
  const errorMessage = getErrorMessage(error);
19
- notifications.show({
20
- title: 'Error',
21
- message: `${message}: ${errorMessage}`,
22
- color: 'red',
23
- });
32
+ if (toast) {
33
+ notifications.show({
34
+ title: 'Error',
35
+ message: `${message}: ${errorMessage}`,
36
+ color: 'red',
37
+ });
38
+ }
24
39
  return errorMessage;
25
40
  }, []);
41
+ /**
42
+ * The failure result for a write. An unanswered one may have landed, so the content tree
43
+ * reloads, and its toast (only with `unknown`) says to check rather than that it failed.
44
+ */
45
+ const fail = useCallback((error, message, { toast = true, unknown, unknownId = SCHEMA_OUTCOME_UNKNOWN_TOAST_ID, } = {}) => {
46
+ if (!isUnanswered(error))
47
+ return { ok: false, error: handleError(message, error, { toast }) };
48
+ console.error(message, error);
49
+ void Promise.resolve(options.onSchemaChange?.()).catch(console.error);
50
+ if (unknown) {
51
+ notifications.hide(unknownId);
52
+ notifications.show({
53
+ id: unknownId,
54
+ message: unknown,
55
+ color: 'yellow',
56
+ autoClose: false,
57
+ withCloseButton: true,
58
+ });
59
+ }
60
+ return { ok: false, error: getErrorMessage(error), unanswered: true };
61
+ }, [options.onSchemaChange, handleError]);
26
62
  const createCollection = useCallback(async (input) => {
27
63
  setIsLoading(true);
28
64
  try {
29
65
  const result = await apiClient.schema.createCollection({ branch: options.branchName }, input);
66
+ if (isGatewayFailure(result))
67
+ throw new UnansweredError();
30
68
  if (!result.ok || !result.data) {
31
69
  throw new Error(result.error || 'Failed to create collection');
32
70
  }
@@ -38,16 +76,21 @@ export function useSchemaManager(options) {
38
76
  return { ok: true, data: result.data };
39
77
  }
40
78
  catch (error) {
41
- return { ok: false, error: handleError('Failed to create collection', error) };
79
+ return fail(error, 'Failed to create collection', {
80
+ unknown: schemaChangeOutcomeUnknown('Creating the collection', CHECK_CONTENT_PANEL),
81
+ unknownId: COLLECTION_OUTCOME_UNKNOWN_TOAST_ID,
82
+ });
42
83
  }
43
84
  finally {
44
85
  setIsLoading(false);
45
86
  }
46
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
87
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
47
88
  const updateCollection = useCallback(async (collectionPath, updates) => {
48
89
  setIsLoading(true);
49
90
  try {
50
91
  const result = await apiClient.schema.updateCollection({ branch: options.branchName, collectionPath }, updates);
92
+ if (isGatewayFailure(result))
93
+ throw new UnansweredError();
51
94
  if (!result.ok) {
52
95
  throw new Error(result.error || 'Failed to update collection');
53
96
  }
@@ -55,16 +98,20 @@ export function useSchemaManager(options) {
55
98
  message: 'Collection updated',
56
99
  color: 'green',
57
100
  });
58
- await options.onSchemaChange?.();
101
+ // The write landed, so a failed refresh is logged rather than reported as its failure.
102
+ await Promise.resolve(options.onSchemaChange?.()).catch(console.error);
59
103
  return { ok: true };
60
104
  }
61
105
  catch (error) {
62
- return { ok: false, error: handleError('Failed to update collection', error) };
106
+ return fail(error, 'Failed to update collection', {
107
+ unknown: schemaChangeOutcomeUnknown('Saving collection details', 'Reopen the collection to check'),
108
+ unknownId: COLLECTION_OUTCOME_UNKNOWN_TOAST_ID,
109
+ });
63
110
  }
64
111
  finally {
65
112
  setIsLoading(false);
66
113
  }
67
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
114
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
68
115
  const deleteCollection = useCallback(async (collectionPath) => {
69
116
  setIsLoading(true);
70
117
  try {
@@ -72,6 +119,8 @@ export function useSchemaManager(options) {
72
119
  branch: options.branchName,
73
120
  collectionPath,
74
121
  });
122
+ if (isGatewayFailure(result))
123
+ throw new UnansweredError();
75
124
  if (!result.ok) {
76
125
  throw new Error(result.error || 'Failed to delete collection');
77
126
  }
@@ -83,54 +132,52 @@ export function useSchemaManager(options) {
83
132
  return { ok: true };
84
133
  }
85
134
  catch (error) {
86
- return { ok: false, error: handleError('Failed to delete collection', error) };
135
+ return fail(error, 'Failed to delete collection', {
136
+ unknown: schemaChangeOutcomeUnknown('Deleting the collection', CHECK_CONTENT_PANEL),
137
+ });
87
138
  }
88
139
  finally {
89
140
  setIsLoading(false);
90
141
  }
91
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
142
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
92
143
  const addEntryType = useCallback(async (collectionPath, entryType) => {
93
144
  setIsLoading(true);
94
145
  try {
95
146
  const result = await apiClient.schema.addEntryType({ branch: options.branchName, collectionPath }, entryType);
147
+ if (isGatewayFailure(result))
148
+ throw new UnansweredError();
96
149
  if (!result.ok) {
97
150
  throw new Error(result.error || 'Failed to add entry type');
98
151
  }
99
- notifications.show({
100
- message: `Entry type "${entryType.name}" added`,
101
- color: 'green',
102
- });
103
152
  options.onSchemaChange?.();
104
153
  return { ok: true };
105
154
  }
106
155
  catch (error) {
107
- return { ok: false, error: handleError('Failed to add entry type', error) };
156
+ return fail(error, 'Failed to add entry type', { toast: false });
108
157
  }
109
158
  finally {
110
159
  setIsLoading(false);
111
160
  }
112
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
161
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
113
162
  const updateEntryType = useCallback(async (collectionPath, entryTypeName, updates) => {
114
163
  setIsLoading(true);
115
164
  try {
116
165
  const result = await apiClient.schema.updateEntryType({ branch: options.branchName, collectionPath, entryTypeName }, updates);
166
+ if (isGatewayFailure(result))
167
+ throw new UnansweredError();
117
168
  if (!result.ok) {
118
169
  throw new Error(result.error || 'Failed to update entry type');
119
170
  }
120
- notifications.show({
121
- message: 'Entry type updated',
122
- color: 'green',
123
- });
124
171
  options.onSchemaChange?.();
125
172
  return { ok: true };
126
173
  }
127
174
  catch (error) {
128
- return { ok: false, error: handleError('Failed to update entry type', error) };
175
+ return fail(error, 'Failed to update entry type', { toast: false });
129
176
  }
130
177
  finally {
131
178
  setIsLoading(false);
132
179
  }
133
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
180
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
134
181
  const removeEntryType = useCallback(async (collectionPath, entryTypeName) => {
135
182
  setIsLoading(true);
136
183
  try {
@@ -139,27 +186,27 @@ export function useSchemaManager(options) {
139
186
  collectionPath,
140
187
  entryTypeName,
141
188
  });
189
+ if (isGatewayFailure(result))
190
+ throw new UnansweredError();
142
191
  if (!result.ok) {
143
192
  throw new Error(result.error || 'Failed to remove entry type');
144
193
  }
145
- notifications.show({
146
- message: `Entry type "${entryTypeName}" removed`,
147
- color: 'green',
148
- });
149
194
  options.onSchemaChange?.();
150
195
  return { ok: true };
151
196
  }
152
197
  catch (error) {
153
- return { ok: false, error: handleError('Failed to remove entry type', error) };
198
+ return fail(error, 'Failed to remove entry type', { toast: false });
154
199
  }
155
200
  finally {
156
201
  setIsLoading(false);
157
202
  }
158
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
203
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
159
204
  const updateOrder = useCallback(async (collectionPath, order) => {
160
205
  setIsLoading(true);
161
206
  try {
162
207
  const result = await apiClient.schema.updateOrder({ branch: options.branchName, collectionPath }, { order });
208
+ if (isGatewayFailure(result))
209
+ throw new UnansweredError();
163
210
  if (!result.ok) {
164
211
  throw new Error(result.error || 'Failed to update order');
165
212
  }
@@ -168,19 +215,28 @@ export function useSchemaManager(options) {
168
215
  return { ok: true };
169
216
  }
170
217
  catch (error) {
171
- return { ok: false, error: handleError('Failed to update order', error) };
218
+ return fail(error, 'Failed to update order', {
219
+ unknown: schemaChangeOutcomeUnknown('Reordering entries', CHECK_CONTENT_PANEL),
220
+ });
172
221
  }
173
222
  finally {
174
223
  setIsLoading(false);
175
224
  }
176
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
177
- const deleteEntry = useCallback(async (entryPath) => {
225
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
226
+ const deleteEntry = useCallback(async (entryPath, deleteOptions) => {
178
227
  setIsLoading(true);
179
228
  try {
180
229
  const result = await apiClient.entries.delete({
181
230
  branch: options.branchName,
182
231
  entryPath,
232
+ ...(deleteOptions?.confirmReferenced ? { confirmReferenced: 'true' } : {}),
183
233
  });
234
+ const referencedBy = result.data?.referencedBy;
235
+ if (!result.ok && referencedBy) {
236
+ return { ok: false, error: result.error ?? 'Entry is referenced', referencedBy };
237
+ }
238
+ if (isGatewayFailure(result))
239
+ throw new UnansweredError();
184
240
  if (!result.ok) {
185
241
  throw new Error(result.error || 'Failed to delete entry');
186
242
  }
@@ -192,12 +248,14 @@ export function useSchemaManager(options) {
192
248
  return { ok: true };
193
249
  }
194
250
  catch (error) {
195
- return { ok: false, error: handleError('Failed to delete entry', error) };
251
+ return fail(error, 'Failed to delete entry', {
252
+ unknown: schemaChangeOutcomeUnknown('Deleting the entry', CHECK_CONTENT_PANEL),
253
+ });
196
254
  }
197
255
  finally {
198
256
  setIsLoading(false);
199
257
  }
200
- }, [apiClient, options.branchName, options.onSchemaChange, handleError]);
258
+ }, [apiClient, options.branchName, options.onSchemaChange, fail]);
201
259
  return {
202
260
  createCollection,
203
261
  updateCollection,
@@ -1,4 +1,5 @@
1
- import type { UserSearchResult } from '../../auth/types.js';
1
+ import { type Cache, type ScopedMutator } from 'swr';
2
+ import type { UserProfile, UserSearchResult } from '../../auth/types.js';
2
3
  import type { CanopyUserId } from '../../types.js';
3
4
  export interface UseUserMetadataResult {
4
5
  userMetadata: UserSearchResult | null;
@@ -6,8 +7,17 @@ export interface UseUserMetadataResult {
6
7
  error: Error | null;
7
8
  }
8
9
  /**
9
- * Fetches user metadata using the provided getter function.
10
- *
11
- * @param cachedUser - Optional: if provided, returns immediately without fetching
10
+ * Caches profiles a response carried, keeping a cached record's email. A profile matching the
11
+ * cached record is not written: any write makes SWR discard a lookup in flight, email included. A
12
+ * user with no record, or whose written record still has no email, is refetched once the writes
13
+ * settle, since the seed may have discarded a lookup; that refetch is detached, so the caller
14
+ * never waits on the directory.
12
15
  */
16
+ export declare function seedUserProfiles(swr: {
17
+ cache: Cache;
18
+ mutate: ScopedMutator;
19
+ }, users: readonly UserProfile[]): Promise<void>;
20
+ /** Answers from the cache with no request and no email, for a reader who may not look users up. */
21
+ export declare function useSeededUserResolver(): (userId: string) => Promise<UserSearchResult | null>;
22
+ /** One user's metadata under a per-user SWR key, so every badge for that user shares a fetch. */
13
23
  export declare function useUserMetadata(userId: CanopyUserId, getUserMetadata: (userId: string) => Promise<UserSearchResult | null>, cachedUser?: UserSearchResult): UseUserMetadataResult;