@open-mercato/documents 0.6.8-develop.7016.1.4ed7b1e49d

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 (602) hide show
  1. package/README.md +88 -0
  2. package/build.mjs +23 -0
  3. package/dist/index.js +5 -0
  4. package/dist/index.js.map +7 -0
  5. package/dist/modules/documents/acl.js +15 -0
  6. package/dist/modules/documents/acl.js.map +7 -0
  7. package/dist/modules/documents/api/[id]/archive/route.js +116 -0
  8. package/dist/modules/documents/api/[id]/archive/route.js.map +7 -0
  9. package/dist/modules/documents/api/[id]/attachments/[attachmentId]/route.js +155 -0
  10. package/dist/modules/documents/api/[id]/attachments/[attachmentId]/route.js.map +7 -0
  11. package/dist/modules/documents/api/[id]/attachments/route.js +153 -0
  12. package/dist/modules/documents/api/[id]/attachments/route.js.map +7 -0
  13. package/dist/modules/documents/api/[id]/collab-token/route.js +180 -0
  14. package/dist/modules/documents/api/[id]/collab-token/route.js.map +7 -0
  15. package/dist/modules/documents/api/[id]/comments/access-check/route.js +86 -0
  16. package/dist/modules/documents/api/[id]/comments/access-check/route.js.map +7 -0
  17. package/dist/modules/documents/api/[id]/comments/route.js +387 -0
  18. package/dist/modules/documents/api/[id]/comments/route.js.map +7 -0
  19. package/dist/modules/documents/api/[id]/content/route.js +143 -0
  20. package/dist/modules/documents/api/[id]/content/route.js.map +7 -0
  21. package/dist/modules/documents/api/[id]/duplicate/route.js +200 -0
  22. package/dist/modules/documents/api/[id]/duplicate/route.js.map +7 -0
  23. package/dist/modules/documents/api/[id]/export/route.js +421 -0
  24. package/dist/modules/documents/api/[id]/export/route.js.map +7 -0
  25. package/dist/modules/documents/api/[id]/favorite/route.js +96 -0
  26. package/dist/modules/documents/api/[id]/favorite/route.js.map +7 -0
  27. package/dist/modules/documents/api/[id]/links/[linkId]/route.js +85 -0
  28. package/dist/modules/documents/api/[id]/links/[linkId]/route.js.map +7 -0
  29. package/dist/modules/documents/api/[id]/links/route.js +257 -0
  30. package/dist/modules/documents/api/[id]/links/route.js.map +7 -0
  31. package/dist/modules/documents/api/[id]/principals/route.js +299 -0
  32. package/dist/modules/documents/api/[id]/principals/route.js.map +7 -0
  33. package/dist/modules/documents/api/[id]/route.js +246 -0
  34. package/dist/modules/documents/api/[id]/route.js.map +7 -0
  35. package/dist/modules/documents/api/[id]/shares/route.js +335 -0
  36. package/dist/modules/documents/api/[id]/shares/route.js.map +7 -0
  37. package/dist/modules/documents/api/[id]/unarchive/route.js +39 -0
  38. package/dist/modules/documents/api/[id]/unarchive/route.js.map +7 -0
  39. package/dist/modules/documents/api/[id]/versions/[versionId]/restore/route.js +133 -0
  40. package/dist/modules/documents/api/[id]/versions/[versionId]/restore/route.js.map +7 -0
  41. package/dist/modules/documents/api/[id]/versions/[versionId]/route.js +93 -0
  42. package/dist/modules/documents/api/[id]/versions/[versionId]/route.js.map +7 -0
  43. package/dist/modules/documents/api/[id]/versions/route.js +193 -0
  44. package/dist/modules/documents/api/[id]/versions/route.js.map +7 -0
  45. package/dist/modules/documents/api/[id]/watch/route.js +97 -0
  46. package/dist/modules/documents/api/[id]/watch/route.js.map +7 -0
  47. package/dist/modules/documents/api/_commands.js +34 -0
  48. package/dist/modules/documents/api/_commands.js.map +7 -0
  49. package/dist/modules/documents/api/_shared.js +490 -0
  50. package/dist/modules/documents/api/_shared.js.map +7 -0
  51. package/dist/modules/documents/api/folders/route.js +256 -0
  52. package/dist/modules/documents/api/folders/route.js.map +7 -0
  53. package/dist/modules/documents/api/instantiate/route.js +108 -0
  54. package/dist/modules/documents/api/instantiate/route.js.map +7 -0
  55. package/dist/modules/documents/api/route.js +322 -0
  56. package/dist/modules/documents/api/route.js.map +7 -0
  57. package/dist/modules/documents/api/templates/[templateId]/preview/route.js +94 -0
  58. package/dist/modules/documents/api/templates/[templateId]/preview/route.js.map +7 -0
  59. package/dist/modules/documents/api/templates/[templateId]/route.js +82 -0
  60. package/dist/modules/documents/api/templates/[templateId]/route.js.map +7 -0
  61. package/dist/modules/documents/api/templates/route.js +344 -0
  62. package/dist/modules/documents/api/templates/route.js.map +7 -0
  63. package/dist/modules/documents/backend/documents/DocumentsPageClient.js +160 -0
  64. package/dist/modules/documents/backend/documents/DocumentsPageClient.js.map +7 -0
  65. package/dist/modules/documents/backend/documents/DocumentsTable.js +143 -0
  66. package/dist/modules/documents/backend/documents/DocumentsTable.js.map +7 -0
  67. package/dist/modules/documents/backend/documents/FolderDialog.js +55 -0
  68. package/dist/modules/documents/backend/documents/FolderDialog.js.map +7 -0
  69. package/dist/modules/documents/backend/documents/FolderTree.js +40 -0
  70. package/dist/modules/documents/backend/documents/FolderTree.js.map +7 -0
  71. package/dist/modules/documents/backend/documents/MoveDocumentDialog.js +64 -0
  72. package/dist/modules/documents/backend/documents/MoveDocumentDialog.js.map +7 -0
  73. package/dist/modules/documents/backend/documents/[id]/CommentAnchorNavigation.js +77 -0
  74. package/dist/modules/documents/backend/documents/[id]/CommentAnchorNavigation.js.map +7 -0
  75. package/dist/modules/documents/backend/documents/[id]/CommentComposer.js +126 -0
  76. package/dist/modules/documents/backend/documents/[id]/CommentComposer.js.map +7 -0
  77. package/dist/modules/documents/backend/documents/[id]/CommentThreadList.js +88 -0
  78. package/dist/modules/documents/backend/documents/[id]/CommentThreadList.js.map +7 -0
  79. package/dist/modules/documents/backend/documents/[id]/CommentsRail.js +123 -0
  80. package/dist/modules/documents/backend/documents/[id]/CommentsRail.js.map +7 -0
  81. package/dist/modules/documents/backend/documents/[id]/DocumentCanvas.js +91 -0
  82. package/dist/modules/documents/backend/documents/[id]/DocumentCanvas.js.map +7 -0
  83. package/dist/modules/documents/backend/documents/[id]/DocumentEditorErrorBoundary.js +27 -0
  84. package/dist/modules/documents/backend/documents/[id]/DocumentEditorErrorBoundary.js.map +7 -0
  85. package/dist/modules/documents/backend/documents/[id]/DocumentEditorIsland.js +50 -0
  86. package/dist/modules/documents/backend/documents/[id]/DocumentEditorIsland.js.map +7 -0
  87. package/dist/modules/documents/backend/documents/[id]/DocumentEditorSurface.js +168 -0
  88. package/dist/modules/documents/backend/documents/[id]/DocumentEditorSurface.js.map +7 -0
  89. package/dist/modules/documents/backend/documents/[id]/DocumentNavigator.js +129 -0
  90. package/dist/modules/documents/backend/documents/[id]/DocumentNavigator.js.map +7 -0
  91. package/dist/modules/documents/backend/documents/[id]/DocumentPageClient.js +429 -0
  92. package/dist/modules/documents/backend/documents/[id]/DocumentPageClient.js.map +7 -0
  93. package/dist/modules/documents/backend/documents/[id]/EditorColorTools.js +68 -0
  94. package/dist/modules/documents/backend/documents/[id]/EditorColorTools.js.map +7 -0
  95. package/dist/modules/documents/backend/documents/[id]/EditorStatusPresence.js +69 -0
  96. package/dist/modules/documents/backend/documents/[id]/EditorStatusPresence.js.map +7 -0
  97. package/dist/modules/documents/backend/documents/[id]/EditorToolbar.js +151 -0
  98. package/dist/modules/documents/backend/documents/[id]/EditorToolbar.js.map +7 -0
  99. package/dist/modules/documents/backend/documents/[id]/ExportMenu.js +121 -0
  100. package/dist/modules/documents/backend/documents/[id]/ExportMenu.js.map +7 -0
  101. package/dist/modules/documents/backend/documents/[id]/MentionPicker.js +114 -0
  102. package/dist/modules/documents/backend/documents/[id]/MentionPicker.js.map +7 -0
  103. package/dist/modules/documents/backend/documents/[id]/OutlinePane.js +70 -0
  104. package/dist/modules/documents/backend/documents/[id]/OutlinePane.js.map +7 -0
  105. package/dist/modules/documents/backend/documents/[id]/RecordFieldsDialog.js +157 -0
  106. package/dist/modules/documents/backend/documents/[id]/RecordFieldsDialog.js.map +7 -0
  107. package/dist/modules/documents/backend/documents/[id]/RelatedRecordsPanel.js +266 -0
  108. package/dist/modules/documents/backend/documents/[id]/RelatedRecordsPanel.js.map +7 -0
  109. package/dist/modules/documents/backend/documents/[id]/VersionHistoryPanel.js +227 -0
  110. package/dist/modules/documents/backend/documents/[id]/VersionHistoryPanel.js.map +7 -0
  111. package/dist/modules/documents/backend/documents/[id]/VersionPreviewDialog.js +157 -0
  112. package/dist/modules/documents/backend/documents/[id]/VersionPreviewDialog.js.map +7 -0
  113. package/dist/modules/documents/backend/documents/[id]/commentTypes.js +150 -0
  114. package/dist/modules/documents/backend/documents/[id]/commentTypes.js.map +7 -0
  115. package/dist/modules/documents/backend/documents/[id]/componentCapabilities.js +13 -0
  116. package/dist/modules/documents/backend/documents/[id]/componentCapabilities.js.map +7 -0
  117. package/dist/modules/documents/backend/documents/[id]/documentPagination.js +295 -0
  118. package/dist/modules/documents/backend/documents/[id]/documentPagination.js.map +7 -0
  119. package/dist/modules/documents/backend/documents/[id]/editorPresenceStyles.js +81 -0
  120. package/dist/modules/documents/backend/documents/[id]/editorPresenceStyles.js.map +7 -0
  121. package/dist/modules/documents/backend/documents/[id]/editorTypes.js +52 -0
  122. package/dist/modules/documents/backend/documents/[id]/editorTypes.js.map +7 -0
  123. package/dist/modules/documents/backend/documents/[id]/page.js +10 -0
  124. package/dist/modules/documents/backend/documents/[id]/page.js.map +7 -0
  125. package/dist/modules/documents/backend/documents/[id]/page.meta.js +16 -0
  126. package/dist/modules/documents/backend/documents/[id]/page.meta.js.map +7 -0
  127. package/dist/modules/documents/backend/documents/[id]/relatedRecordModel.js +38 -0
  128. package/dist/modules/documents/backend/documents/[id]/relatedRecordModel.js.map +7 -0
  129. package/dist/modules/documents/backend/documents/[id]/restoreVersion.js +33 -0
  130. package/dist/modules/documents/backend/documents/[id]/restoreVersion.js.map +7 -0
  131. package/dist/modules/documents/backend/documents/[id]/useDocumentCollaboration.js +392 -0
  132. package/dist/modules/documents/backend/documents/[id]/useDocumentCollaboration.js.map +7 -0
  133. package/dist/modules/documents/backend/documents/[id]/useDocumentComments.js +253 -0
  134. package/dist/modules/documents/backend/documents/[id]/useDocumentComments.js.map +7 -0
  135. package/dist/modules/documents/backend/documents/[id]/useDocumentEditor.js +149 -0
  136. package/dist/modules/documents/backend/documents/[id]/useDocumentEditor.js.map +7 -0
  137. package/dist/modules/documents/backend/documents/[id]/useDocumentTitle.js +82 -0
  138. package/dist/modules/documents/backend/documents/[id]/useDocumentTitle.js.map +7 -0
  139. package/dist/modules/documents/backend/documents/[id]/useEditorInsertions.js +144 -0
  140. package/dist/modules/documents/backend/documents/[id]/useEditorInsertions.js.map +7 -0
  141. package/dist/modules/documents/backend/documents/[id]/useFallbackContentPersistence.js +237 -0
  142. package/dist/modules/documents/backend/documents/[id]/useFallbackContentPersistence.js.map +7 -0
  143. package/dist/modules/documents/backend/documents/[id]/useMentionPicker.js +216 -0
  144. package/dist/modules/documents/backend/documents/[id]/useMentionPicker.js.map +7 -0
  145. package/dist/modules/documents/backend/documents/[id]/versionHistoryModel.js +25 -0
  146. package/dist/modules/documents/backend/documents/[id]/versionHistoryModel.js.map +7 -0
  147. package/dist/modules/documents/backend/documents/components/EntityPicker.js +156 -0
  148. package/dist/modules/documents/backend/documents/components/EntityPicker.js.map +7 -0
  149. package/dist/modules/documents/backend/documents/components/EntityPickerResults.js +46 -0
  150. package/dist/modules/documents/backend/documents/components/EntityPickerResults.js.map +7 -0
  151. package/dist/modules/documents/backend/documents/components/NewFromTemplateDialog.js +127 -0
  152. package/dist/modules/documents/backend/documents/components/NewFromTemplateDialog.js.map +7 -0
  153. package/dist/modules/documents/backend/documents/components/PrincipalPicker.js +84 -0
  154. package/dist/modules/documents/backend/documents/components/PrincipalPicker.js.map +7 -0
  155. package/dist/modules/documents/backend/documents/components/ShareDialog.js +77 -0
  156. package/dist/modules/documents/backend/documents/components/ShareDialog.js.map +7 -0
  157. package/dist/modules/documents/backend/documents/components/ShareDialogAddForm.js +93 -0
  158. package/dist/modules/documents/backend/documents/components/ShareDialogAddForm.js.map +7 -0
  159. package/dist/modules/documents/backend/documents/components/ShareDialogList.js +82 -0
  160. package/dist/modules/documents/backend/documents/components/ShareDialogList.js.map +7 -0
  161. package/dist/modules/documents/backend/documents/components/TemplateBodyEditor.js +96 -0
  162. package/dist/modules/documents/backend/documents/components/TemplateBodyEditor.js.map +7 -0
  163. package/dist/modules/documents/backend/documents/components/TemplateEditorDialog.js +169 -0
  164. package/dist/modules/documents/backend/documents/components/TemplateEditorDialog.js.map +7 -0
  165. package/dist/modules/documents/backend/documents/components/TemplatePreview.js +38 -0
  166. package/dist/modules/documents/backend/documents/components/TemplatePreview.js.map +7 -0
  167. package/dist/modules/documents/backend/documents/components/TemplateSlotFields.js +69 -0
  168. package/dist/modules/documents/backend/documents/components/TemplateSlotFields.js.map +7 -0
  169. package/dist/modules/documents/backend/documents/components/TemplateSlotsEditor.js +71 -0
  170. package/dist/modules/documents/backend/documents/components/TemplateSlotsEditor.js.map +7 -0
  171. package/dist/modules/documents/backend/documents/components/principalPickerModel.js +63 -0
  172. package/dist/modules/documents/backend/documents/components/principalPickerModel.js.map +7 -0
  173. package/dist/modules/documents/backend/documents/components/shareDialogModel.js +68 -0
  174. package/dist/modules/documents/backend/documents/components/shareDialogModel.js.map +7 -0
  175. package/dist/modules/documents/backend/documents/components/templateUi.js +89 -0
  176. package/dist/modules/documents/backend/documents/components/templateUi.js.map +7 -0
  177. package/dist/modules/documents/backend/documents/components/useAvailableEntityRegistry.js +30 -0
  178. package/dist/modules/documents/backend/documents/components/useAvailableEntityRegistry.js.map +7 -0
  179. package/dist/modules/documents/backend/documents/components/useEntitySearch.js +191 -0
  180. package/dist/modules/documents/backend/documents/components/useEntitySearch.js.map +7 -0
  181. package/dist/modules/documents/backend/documents/components/usePrincipalPicker.js +221 -0
  182. package/dist/modules/documents/backend/documents/components/usePrincipalPicker.js.map +7 -0
  183. package/dist/modules/documents/backend/documents/components/useShareDialog.js +236 -0
  184. package/dist/modules/documents/backend/documents/components/useShareDialog.js.map +7 -0
  185. package/dist/modules/documents/backend/documents/components/useTemplateDetail.js +49 -0
  186. package/dist/modules/documents/backend/documents/components/useTemplateDetail.js.map +7 -0
  187. package/dist/modules/documents/backend/documents/components/useTemplateInstantiation.js +234 -0
  188. package/dist/modules/documents/backend/documents/components/useTemplateInstantiation.js.map +7 -0
  189. package/dist/modules/documents/backend/documents/documentUi.js +106 -0
  190. package/dist/modules/documents/backend/documents/documentUi.js.map +7 -0
  191. package/dist/modules/documents/backend/documents/documentsListTypes.js +132 -0
  192. package/dist/modules/documents/backend/documents/documentsListTypes.js.map +7 -0
  193. package/dist/modules/documents/backend/documents/page.js +9 -0
  194. package/dist/modules/documents/backend/documents/page.js.map +7 -0
  195. package/dist/modules/documents/backend/documents/page.meta.js +26 -0
  196. package/dist/modules/documents/backend/documents/page.meta.js.map +7 -0
  197. package/dist/modules/documents/backend/documents/templates/TemplatesPageClient.js +91 -0
  198. package/dist/modules/documents/backend/documents/templates/TemplatesPageClient.js.map +7 -0
  199. package/dist/modules/documents/backend/documents/templates/TemplatesTable.js +58 -0
  200. package/dist/modules/documents/backend/documents/templates/TemplatesTable.js.map +7 -0
  201. package/dist/modules/documents/backend/documents/templates/page.js +9 -0
  202. package/dist/modules/documents/backend/documents/templates/page.js.map +7 -0
  203. package/dist/modules/documents/backend/documents/templates/page.meta.js +34 -0
  204. package/dist/modules/documents/backend/documents/templates/page.meta.js.map +7 -0
  205. package/dist/modules/documents/backend/documents/templates/useTemplatesPage.js +139 -0
  206. package/dist/modules/documents/backend/documents/templates/useTemplatesPage.js.map +7 -0
  207. package/dist/modules/documents/backend/documents/useDocumentsList.js +314 -0
  208. package/dist/modules/documents/backend/documents/useDocumentsList.js.map +7 -0
  209. package/dist/modules/documents/ce.js +8 -0
  210. package/dist/modules/documents/ce.js.map +7 -0
  211. package/dist/modules/documents/commands/aggregate.js +99 -0
  212. package/dist/modules/documents/commands/aggregate.js.map +7 -0
  213. package/dist/modules/documents/commands/attachments.js +252 -0
  214. package/dist/modules/documents/commands/attachments.js.map +7 -0
  215. package/dist/modules/documents/commands/comments.js +782 -0
  216. package/dist/modules/documents/commands/comments.js.map +7 -0
  217. package/dist/modules/documents/commands/content.js +238 -0
  218. package/dist/modules/documents/commands/content.js.map +7 -0
  219. package/dist/modules/documents/commands/document-crud.js +505 -0
  220. package/dist/modules/documents/commands/document-crud.js.map +7 -0
  221. package/dist/modules/documents/commands/documents.js +473 -0
  222. package/dist/modules/documents/commands/documents.js.map +7 -0
  223. package/dist/modules/documents/commands/duplicate.js +640 -0
  224. package/dist/modules/documents/commands/duplicate.js.map +7 -0
  225. package/dist/modules/documents/commands/favorites.js +150 -0
  226. package/dist/modules/documents/commands/favorites.js.map +7 -0
  227. package/dist/modules/documents/commands/folders.js +420 -0
  228. package/dist/modules/documents/commands/folders.js.map +7 -0
  229. package/dist/modules/documents/commands/index.js +64 -0
  230. package/dist/modules/documents/commands/index.js.map +7 -0
  231. package/dist/modules/documents/commands/interceptors.js +300 -0
  232. package/dist/modules/documents/commands/interceptors.js.map +7 -0
  233. package/dist/modules/documents/commands/lifecycle.js +249 -0
  234. package/dist/modules/documents/commands/lifecycle.js.map +7 -0
  235. package/dist/modules/documents/commands/links.js +410 -0
  236. package/dist/modules/documents/commands/links.js.map +7 -0
  237. package/dist/modules/documents/commands/mutation-helpers.js +42 -0
  238. package/dist/modules/documents/commands/mutation-helpers.js.map +7 -0
  239. package/dist/modules/documents/commands/projection-types.js +1 -0
  240. package/dist/modules/documents/commands/projection-types.js.map +7 -0
  241. package/dist/modules/documents/commands/shared.js +143 -0
  242. package/dist/modules/documents/commands/shared.js.map +7 -0
  243. package/dist/modules/documents/commands/shares.js +527 -0
  244. package/dist/modules/documents/commands/shares.js.map +7 -0
  245. package/dist/modules/documents/commands/side-effects.js +103 -0
  246. package/dist/modules/documents/commands/side-effects.js.map +7 -0
  247. package/dist/modules/documents/commands/templates.js +461 -0
  248. package/dist/modules/documents/commands/templates.js.map +7 -0
  249. package/dist/modules/documents/commands/versions.js +432 -0
  250. package/dist/modules/documents/commands/versions.js.map +7 -0
  251. package/dist/modules/documents/commands/watchers.js +164 -0
  252. package/dist/modules/documents/commands/watchers.js.map +7 -0
  253. package/dist/modules/documents/data/entities.js +653 -0
  254. package/dist/modules/documents/data/entities.js.map +7 -0
  255. package/dist/modules/documents/data/extensions.js +44 -0
  256. package/dist/modules/documents/data/extensions.js.map +7 -0
  257. package/dist/modules/documents/data/validators.js +219 -0
  258. package/dist/modules/documents/data/validators.js.map +7 -0
  259. package/dist/modules/documents/di.js +35 -0
  260. package/dist/modules/documents/di.js.map +7 -0
  261. package/dist/modules/documents/encryption.js +12 -0
  262. package/dist/modules/documents/encryption.js.map +7 -0
  263. package/dist/modules/documents/events.js +27 -0
  264. package/dist/modules/documents/events.js.map +7 -0
  265. package/dist/modules/documents/index.js +19 -0
  266. package/dist/modules/documents/index.js.map +7 -0
  267. package/dist/modules/documents/lib/attachmentServicePort.js +30 -0
  268. package/dist/modules/documents/lib/attachmentServicePort.js.map +7 -0
  269. package/dist/modules/documents/lib/capabilities.js +32 -0
  270. package/dist/modules/documents/lib/capabilities.js.map +7 -0
  271. package/dist/modules/documents/lib/collabCloseEvents.js +17 -0
  272. package/dist/modules/documents/lib/collabCloseEvents.js.map +7 -0
  273. package/dist/modules/documents/lib/collabEndpoint.js +22 -0
  274. package/dist/modules/documents/lib/collabEndpoint.js.map +7 -0
  275. package/dist/modules/documents/lib/collabMaterializer.js +107 -0
  276. package/dist/modules/documents/lib/collabMaterializer.js.map +7 -0
  277. package/dist/modules/documents/lib/collabToken.js +120 -0
  278. package/dist/modules/documents/lib/collabToken.js.map +7 -0
  279. package/dist/modules/documents/lib/collaborationAwareness.js +68 -0
  280. package/dist/modules/documents/lib/collaborationAwareness.js.map +7 -0
  281. package/dist/modules/documents/lib/commentAnchors.js +15 -0
  282. package/dist/modules/documents/lib/commentAnchors.js.map +7 -0
  283. package/dist/modules/documents/lib/constants.js +25 -0
  284. package/dist/modules/documents/lib/constants.js.map +7 -0
  285. package/dist/modules/documents/lib/contentService.js +248 -0
  286. package/dist/modules/documents/lib/contentService.js.map +7 -0
  287. package/dist/modules/documents/lib/displayLabels.js +23 -0
  288. package/dist/modules/documents/lib/displayLabels.js.map +7 -0
  289. package/dist/modules/documents/lib/docxRenderer.js +601 -0
  290. package/dist/modules/documents/lib/docxRenderer.js.map +7 -0
  291. package/dist/modules/documents/lib/duplicateContent.js +22 -0
  292. package/dist/modules/documents/lib/duplicateContent.js.map +7 -0
  293. package/dist/modules/documents/lib/editorConfig.js +287 -0
  294. package/dist/modules/documents/lib/editorConfig.js.map +7 -0
  295. package/dist/modules/documents/lib/entityLinks.js +148 -0
  296. package/dist/modules/documents/lib/entityLinks.js.map +7 -0
  297. package/dist/modules/documents/lib/entityRegistry.js +258 -0
  298. package/dist/modules/documents/lib/entityRegistry.js.map +7 -0
  299. package/dist/modules/documents/lib/entityRegistry.server.js +189 -0
  300. package/dist/modules/documents/lib/entityRegistry.server.js.map +7 -0
  301. package/dist/modules/documents/lib/entityRegistryAvailability.server.js +9 -0
  302. package/dist/modules/documents/lib/entityRegistryAvailability.server.js.map +7 -0
  303. package/dist/modules/documents/lib/entitySuggestion.js +50 -0
  304. package/dist/modules/documents/lib/entitySuggestion.js.map +7 -0
  305. package/dist/modules/documents/lib/favorites.js +22 -0
  306. package/dist/modules/documents/lib/favorites.js.map +7 -0
  307. package/dist/modules/documents/lib/folderHierarchySerialization.js +19 -0
  308. package/dist/modules/documents/lib/folderHierarchySerialization.js.map +7 -0
  309. package/dist/modules/documents/lib/historyLimits.js +100 -0
  310. package/dist/modules/documents/lib/historyLimits.js.map +7 -0
  311. package/dist/modules/documents/lib/historyPolicy.js +14 -0
  312. package/dist/modules/documents/lib/historyPolicy.js.map +7 -0
  313. package/dist/modules/documents/lib/organizationAccess.js +17 -0
  314. package/dist/modules/documents/lib/organizationAccess.js.map +7 -0
  315. package/dist/modules/documents/lib/pdfHtml.js +62 -0
  316. package/dist/modules/documents/lib/pdfHtml.js.map +7 -0
  317. package/dist/modules/documents/lib/pdfRenderer.js +284 -0
  318. package/dist/modules/documents/lib/pdfRenderer.js.map +7 -0
  319. package/dist/modules/documents/lib/permissions.js +222 -0
  320. package/dist/modules/documents/lib/permissions.js.map +7 -0
  321. package/dist/modules/documents/lib/platformServices.js +35 -0
  322. package/dist/modules/documents/lib/platformServices.js.map +7 -0
  323. package/dist/modules/documents/lib/recordFieldInsertion.js +58 -0
  324. package/dist/modules/documents/lib/recordFieldInsertion.js.map +7 -0
  325. package/dist/modules/documents/lib/requestBody.js +80 -0
  326. package/dist/modules/documents/lib/requestBody.js.map +7 -0
  327. package/dist/modules/documents/lib/resourceLimits.js +62 -0
  328. package/dist/modules/documents/lib/resourceLimits.js.map +7 -0
  329. package/dist/modules/documents/lib/shareCounts.js +25 -0
  330. package/dist/modules/documents/lib/shareCounts.js.map +7 -0
  331. package/dist/modules/documents/lib/templateFill.js +84 -0
  332. package/dist/modules/documents/lib/templateFill.js.map +7 -0
  333. package/dist/modules/documents/lib/templateInstantiation.js +147 -0
  334. package/dist/modules/documents/lib/templateInstantiation.js.map +7 -0
  335. package/dist/modules/documents/lib/templatePreviewDigest.js +82 -0
  336. package/dist/modules/documents/lib/templatePreviewDigest.js.map +7 -0
  337. package/dist/modules/documents/lib/templateSeeds.js +201 -0
  338. package/dist/modules/documents/lib/templateSeeds.js.map +7 -0
  339. package/dist/modules/documents/lib/userLabels.js +37 -0
  340. package/dist/modules/documents/lib/userLabels.js.map +7 -0
  341. package/dist/modules/documents/lib/versionContent.js +131 -0
  342. package/dist/modules/documents/lib/versionContent.js.map +7 -0
  343. package/dist/modules/documents/lib/versionLabels.js +12 -0
  344. package/dist/modules/documents/lib/versionLabels.js.map +7 -0
  345. package/dist/modules/documents/lib/versioning.js +14 -0
  346. package/dist/modules/documents/lib/versioning.js.map +7 -0
  347. package/dist/modules/documents/lib/visibility.js +422 -0
  348. package/dist/modules/documents/lib/visibility.js.map +7 -0
  349. package/dist/modules/documents/lib/watchers.js +106 -0
  350. package/dist/modules/documents/lib/watchers.js.map +7 -0
  351. package/dist/modules/documents/migrations/Migration20260708163836_documents.js +44 -0
  352. package/dist/modules/documents/migrations/Migration20260708163836_documents.js.map +7 -0
  353. package/dist/modules/documents/migrations/Migration20260709164720_documents.js +17 -0
  354. package/dist/modules/documents/migrations/Migration20260709164720_documents.js.map +7 -0
  355. package/dist/modules/documents/migrations/Migration20260710002318_documents.js +32 -0
  356. package/dist/modules/documents/migrations/Migration20260710002318_documents.js.map +7 -0
  357. package/dist/modules/documents/migrations/Migration20260710071003_documents.js +13 -0
  358. package/dist/modules/documents/migrations/Migration20260710071003_documents.js.map +7 -0
  359. package/dist/modules/documents/migrations/Migration20260712120000_documents.js +13 -0
  360. package/dist/modules/documents/migrations/Migration20260712120000_documents.js.map +7 -0
  361. package/dist/modules/documents/migrations/Migration20260712183000_documents.js +14 -0
  362. package/dist/modules/documents/migrations/Migration20260712183000_documents.js.map +7 -0
  363. package/dist/modules/documents/migrations/Migration20260713092156_documents.js +29 -0
  364. package/dist/modules/documents/migrations/Migration20260713092156_documents.js.map +7 -0
  365. package/dist/modules/documents/migrations/Migration20260717000000_documents.js +37 -0
  366. package/dist/modules/documents/migrations/Migration20260717000000_documents.js.map +7 -0
  367. package/dist/modules/documents/notifications.js +47 -0
  368. package/dist/modules/documents/notifications.js.map +7 -0
  369. package/dist/modules/documents/search.js +101 -0
  370. package/dist/modules/documents/search.js.map +7 -0
  371. package/dist/modules/documents/setup.js +19 -0
  372. package/dist/modules/documents/setup.js.map +7 -0
  373. package/dist/modules/documents/widgets/injection/related-documents/LinkDocumentDialog.js +214 -0
  374. package/dist/modules/documents/widgets/injection/related-documents/LinkDocumentDialog.js.map +7 -0
  375. package/dist/modules/documents/widgets/injection/related-documents/context.js +84 -0
  376. package/dist/modules/documents/widgets/injection/related-documents/context.js.map +7 -0
  377. package/dist/modules/documents/widgets/injection/related-documents/useRelatedDocuments.js +98 -0
  378. package/dist/modules/documents/widgets/injection/related-documents/useRelatedDocuments.js.map +7 -0
  379. package/dist/modules/documents/widgets/injection/related-documents/widget.client.js +83 -0
  380. package/dist/modules/documents/widgets/injection/related-documents/widget.client.js.map +7 -0
  381. package/dist/modules/documents/widgets/injection/related-documents/widget.js +19 -0
  382. package/dist/modules/documents/widgets/injection/related-documents/widget.js.map +7 -0
  383. package/dist/modules/documents/widgets/injection-table.js +21 -0
  384. package/dist/modules/documents/widgets/injection-table.js.map +7 -0
  385. package/dist/server/documents-collab-server.js +2260 -0
  386. package/dist/server/documents-collab-server.js.map +7 -0
  387. package/generated/entities/document/index.ts +12 -0
  388. package/generated/entities/document_attachment/index.ts +9 -0
  389. package/generated/entities/document_comment/index.ts +14 -0
  390. package/generated/entities/document_content/index.ts +11 -0
  391. package/generated/entities/document_entity_link/index.ts +19 -0
  392. package/generated/entities/document_favorite/index.ts +7 -0
  393. package/generated/entities/document_folder/index.ts +9 -0
  394. package/generated/entities/document_share/index.ts +11 -0
  395. package/generated/entities/document_template/index.ts +13 -0
  396. package/generated/entities/document_version/index.ts +9 -0
  397. package/generated/entities/document_watcher/index.ts +7 -0
  398. package/generated/entities.ids.generated.ts +21 -0
  399. package/generated/entity-fields-registry.ts +151 -0
  400. package/jest.config.cjs +34 -0
  401. package/package.json +149 -0
  402. package/server/documents-collab-server.ts +3416 -0
  403. package/src/index.ts +1 -0
  404. package/src/modules/documents/acl.ts +11 -0
  405. package/src/modules/documents/api/[id]/archive/route.ts +132 -0
  406. package/src/modules/documents/api/[id]/attachments/[attachmentId]/route.ts +166 -0
  407. package/src/modules/documents/api/[id]/attachments/route.ts +173 -0
  408. package/src/modules/documents/api/[id]/collab-token/route.ts +203 -0
  409. package/src/modules/documents/api/[id]/comments/access-check/route.ts +96 -0
  410. package/src/modules/documents/api/[id]/comments/route.ts +442 -0
  411. package/src/modules/documents/api/[id]/content/route.ts +156 -0
  412. package/src/modules/documents/api/[id]/duplicate/route.ts +231 -0
  413. package/src/modules/documents/api/[id]/export/route.ts +535 -0
  414. package/src/modules/documents/api/[id]/favorite/route.ts +110 -0
  415. package/src/modules/documents/api/[id]/links/[linkId]/route.ts +92 -0
  416. package/src/modules/documents/api/[id]/links/route.ts +301 -0
  417. package/src/modules/documents/api/[id]/principals/route.ts +375 -0
  418. package/src/modules/documents/api/[id]/route.ts +267 -0
  419. package/src/modules/documents/api/[id]/shares/route.ts +372 -0
  420. package/src/modules/documents/api/[id]/unarchive/route.ts +42 -0
  421. package/src/modules/documents/api/[id]/versions/[versionId]/restore/route.ts +152 -0
  422. package/src/modules/documents/api/[id]/versions/[versionId]/route.ts +100 -0
  423. package/src/modules/documents/api/[id]/versions/route.ts +207 -0
  424. package/src/modules/documents/api/[id]/watch/route.ts +111 -0
  425. package/src/modules/documents/api/_commands.ts +53 -0
  426. package/src/modules/documents/api/_shared.ts +676 -0
  427. package/src/modules/documents/api/folders/route.ts +287 -0
  428. package/src/modules/documents/api/instantiate/route.ts +114 -0
  429. package/src/modules/documents/api/route.ts +362 -0
  430. package/src/modules/documents/api/templates/[templateId]/preview/route.ts +97 -0
  431. package/src/modules/documents/api/templates/[templateId]/route.ts +92 -0
  432. package/src/modules/documents/api/templates/route.ts +370 -0
  433. package/src/modules/documents/backend/documents/DocumentsPageClient.tsx +150 -0
  434. package/src/modules/documents/backend/documents/DocumentsTable.tsx +168 -0
  435. package/src/modules/documents/backend/documents/FolderDialog.tsx +62 -0
  436. package/src/modules/documents/backend/documents/FolderTree.tsx +72 -0
  437. package/src/modules/documents/backend/documents/MoveDocumentDialog.tsx +70 -0
  438. package/src/modules/documents/backend/documents/[id]/CommentAnchorNavigation.ts +88 -0
  439. package/src/modules/documents/backend/documents/[id]/CommentComposer.tsx +136 -0
  440. package/src/modules/documents/backend/documents/[id]/CommentThreadList.tsx +131 -0
  441. package/src/modules/documents/backend/documents/[id]/CommentsRail.tsx +138 -0
  442. package/src/modules/documents/backend/documents/[id]/DocumentCanvas.tsx +111 -0
  443. package/src/modules/documents/backend/documents/[id]/DocumentEditorErrorBoundary.tsx +39 -0
  444. package/src/modules/documents/backend/documents/[id]/DocumentEditorIsland.tsx +50 -0
  445. package/src/modules/documents/backend/documents/[id]/DocumentEditorSurface.tsx +162 -0
  446. package/src/modules/documents/backend/documents/[id]/DocumentNavigator.tsx +129 -0
  447. package/src/modules/documents/backend/documents/[id]/DocumentPageClient.tsx +463 -0
  448. package/src/modules/documents/backend/documents/[id]/EditorColorTools.tsx +71 -0
  449. package/src/modules/documents/backend/documents/[id]/EditorStatusPresence.tsx +78 -0
  450. package/src/modules/documents/backend/documents/[id]/EditorToolbar.tsx +108 -0
  451. package/src/modules/documents/backend/documents/[id]/ExportMenu.tsx +144 -0
  452. package/src/modules/documents/backend/documents/[id]/MentionPicker.tsx +137 -0
  453. package/src/modules/documents/backend/documents/[id]/OutlinePane.tsx +98 -0
  454. package/src/modules/documents/backend/documents/[id]/RecordFieldsDialog.tsx +185 -0
  455. package/src/modules/documents/backend/documents/[id]/RelatedRecordsPanel.tsx +320 -0
  456. package/src/modules/documents/backend/documents/[id]/VersionHistoryPanel.tsx +244 -0
  457. package/src/modules/documents/backend/documents/[id]/VersionPreviewDialog.tsx +197 -0
  458. package/src/modules/documents/backend/documents/[id]/commentTypes.ts +192 -0
  459. package/src/modules/documents/backend/documents/[id]/componentCapabilities.ts +17 -0
  460. package/src/modules/documents/backend/documents/[id]/documentPagination.ts +352 -0
  461. package/src/modules/documents/backend/documents/[id]/editorPresenceStyles.ts +77 -0
  462. package/src/modules/documents/backend/documents/[id]/editorTypes.ts +84 -0
  463. package/src/modules/documents/backend/documents/[id]/page.meta.ts +12 -0
  464. package/src/modules/documents/backend/documents/[id]/page.tsx +6 -0
  465. package/src/modules/documents/backend/documents/[id]/relatedRecordModel.ts +49 -0
  466. package/src/modules/documents/backend/documents/[id]/restoreVersion.ts +49 -0
  467. package/src/modules/documents/backend/documents/[id]/useDocumentCollaboration.ts +458 -0
  468. package/src/modules/documents/backend/documents/[id]/useDocumentComments.ts +286 -0
  469. package/src/modules/documents/backend/documents/[id]/useDocumentEditor.ts +157 -0
  470. package/src/modules/documents/backend/documents/[id]/useDocumentTitle.ts +77 -0
  471. package/src/modules/documents/backend/documents/[id]/useEditorInsertions.ts +147 -0
  472. package/src/modules/documents/backend/documents/[id]/useFallbackContentPersistence.ts +277 -0
  473. package/src/modules/documents/backend/documents/[id]/useMentionPicker.ts +259 -0
  474. package/src/modules/documents/backend/documents/[id]/versionHistoryModel.ts +29 -0
  475. package/src/modules/documents/backend/documents/components/EntityPicker.tsx +171 -0
  476. package/src/modules/documents/backend/documents/components/EntityPickerResults.tsx +64 -0
  477. package/src/modules/documents/backend/documents/components/NewFromTemplateDialog.tsx +136 -0
  478. package/src/modules/documents/backend/documents/components/PrincipalPicker.tsx +90 -0
  479. package/src/modules/documents/backend/documents/components/ShareDialog.tsx +88 -0
  480. package/src/modules/documents/backend/documents/components/ShareDialogAddForm.tsx +113 -0
  481. package/src/modules/documents/backend/documents/components/ShareDialogList.tsx +117 -0
  482. package/src/modules/documents/backend/documents/components/TemplateBodyEditor.tsx +96 -0
  483. package/src/modules/documents/backend/documents/components/TemplateEditorDialog.tsx +171 -0
  484. package/src/modules/documents/backend/documents/components/TemplatePreview.tsx +43 -0
  485. package/src/modules/documents/backend/documents/components/TemplateSlotFields.tsx +72 -0
  486. package/src/modules/documents/backend/documents/components/TemplateSlotsEditor.tsx +72 -0
  487. package/src/modules/documents/backend/documents/components/principalPickerModel.ts +86 -0
  488. package/src/modules/documents/backend/documents/components/shareDialogModel.ts +94 -0
  489. package/src/modules/documents/backend/documents/components/templateUi.ts +128 -0
  490. package/src/modules/documents/backend/documents/components/useAvailableEntityRegistry.ts +43 -0
  491. package/src/modules/documents/backend/documents/components/useEntitySearch.ts +197 -0
  492. package/src/modules/documents/backend/documents/components/usePrincipalPicker.ts +165 -0
  493. package/src/modules/documents/backend/documents/components/useShareDialog.ts +267 -0
  494. package/src/modules/documents/backend/documents/components/useTemplateDetail.ts +54 -0
  495. package/src/modules/documents/backend/documents/components/useTemplateInstantiation.ts +252 -0
  496. package/src/modules/documents/backend/documents/documentUi.ts +134 -0
  497. package/src/modules/documents/backend/documents/documentsListTypes.ts +163 -0
  498. package/src/modules/documents/backend/documents/page.meta.ts +24 -0
  499. package/src/modules/documents/backend/documents/page.tsx +5 -0
  500. package/src/modules/documents/backend/documents/templates/TemplatesPageClient.tsx +93 -0
  501. package/src/modules/documents/backend/documents/templates/TemplatesTable.tsx +71 -0
  502. package/src/modules/documents/backend/documents/templates/page.meta.ts +32 -0
  503. package/src/modules/documents/backend/documents/templates/page.tsx +5 -0
  504. package/src/modules/documents/backend/documents/templates/useTemplatesPage.tsx +148 -0
  505. package/src/modules/documents/backend/documents/useDocumentsList.tsx +305 -0
  506. package/src/modules/documents/ce.ts +6 -0
  507. package/src/modules/documents/commands/aggregate.ts +128 -0
  508. package/src/modules/documents/commands/attachments.ts +309 -0
  509. package/src/modules/documents/commands/comments.ts +966 -0
  510. package/src/modules/documents/commands/content.ts +294 -0
  511. package/src/modules/documents/commands/document-crud.ts +609 -0
  512. package/src/modules/documents/commands/documents.ts +581 -0
  513. package/src/modules/documents/commands/duplicate.ts +772 -0
  514. package/src/modules/documents/commands/favorites.ts +171 -0
  515. package/src/modules/documents/commands/folders.ts +506 -0
  516. package/src/modules/documents/commands/index.ts +33 -0
  517. package/src/modules/documents/commands/interceptors.ts +402 -0
  518. package/src/modules/documents/commands/lifecycle.ts +333 -0
  519. package/src/modules/documents/commands/links.ts +486 -0
  520. package/src/modules/documents/commands/mutation-helpers.ts +48 -0
  521. package/src/modules/documents/commands/projection-types.ts +77 -0
  522. package/src/modules/documents/commands/shared.ts +219 -0
  523. package/src/modules/documents/commands/shares.ts +612 -0
  524. package/src/modules/documents/commands/side-effects.ts +130 -0
  525. package/src/modules/documents/commands/templates.ts +522 -0
  526. package/src/modules/documents/commands/versions.ts +537 -0
  527. package/src/modules/documents/commands/watchers.ts +181 -0
  528. package/src/modules/documents/data/entities.ts +631 -0
  529. package/src/modules/documents/data/extensions.ts +42 -0
  530. package/src/modules/documents/data/validators.ts +248 -0
  531. package/src/modules/documents/di.ts +33 -0
  532. package/src/modules/documents/encryption.ts +14 -0
  533. package/src/modules/documents/events.ts +23 -0
  534. package/src/modules/documents/i18n/.hardcoded-allowlist.json +9 -0
  535. package/src/modules/documents/i18n/de.json +522 -0
  536. package/src/modules/documents/i18n/en.json +522 -0
  537. package/src/modules/documents/i18n/es.json +522 -0
  538. package/src/modules/documents/i18n/ko.json +522 -0
  539. package/src/modules/documents/i18n/pl.json +522 -0
  540. package/src/modules/documents/index.ts +17 -0
  541. package/src/modules/documents/lib/attachmentServicePort.ts +94 -0
  542. package/src/modules/documents/lib/capabilities.ts +57 -0
  543. package/src/modules/documents/lib/collabCloseEvents.ts +26 -0
  544. package/src/modules/documents/lib/collabEndpoint.ts +43 -0
  545. package/src/modules/documents/lib/collabMaterializer.ts +140 -0
  546. package/src/modules/documents/lib/collabToken.ts +170 -0
  547. package/src/modules/documents/lib/collaborationAwareness.ts +102 -0
  548. package/src/modules/documents/lib/commentAnchors.ts +19 -0
  549. package/src/modules/documents/lib/constants.ts +39 -0
  550. package/src/modules/documents/lib/contentService.ts +340 -0
  551. package/src/modules/documents/lib/displayLabels.ts +31 -0
  552. package/src/modules/documents/lib/docxRenderer.ts +685 -0
  553. package/src/modules/documents/lib/duplicateContent.ts +32 -0
  554. package/src/modules/documents/lib/editorConfig.ts +371 -0
  555. package/src/modules/documents/lib/entityLinks.ts +250 -0
  556. package/src/modules/documents/lib/entityRegistry.server.ts +267 -0
  557. package/src/modules/documents/lib/entityRegistry.ts +345 -0
  558. package/src/modules/documents/lib/entityRegistryAvailability.server.ts +19 -0
  559. package/src/modules/documents/lib/entitySuggestion.ts +61 -0
  560. package/src/modules/documents/lib/favorites.ts +35 -0
  561. package/src/modules/documents/lib/folderHierarchySerialization.ts +34 -0
  562. package/src/modules/documents/lib/historyLimits.ts +154 -0
  563. package/src/modules/documents/lib/historyPolicy.ts +7 -0
  564. package/src/modules/documents/lib/organizationAccess.ts +44 -0
  565. package/src/modules/documents/lib/pdfHtml.ts +65 -0
  566. package/src/modules/documents/lib/pdfRenderer.ts +367 -0
  567. package/src/modules/documents/lib/permissions.ts +299 -0
  568. package/src/modules/documents/lib/platformServices.ts +70 -0
  569. package/src/modules/documents/lib/recordFieldInsertion.ts +72 -0
  570. package/src/modules/documents/lib/requestBody.ts +97 -0
  571. package/src/modules/documents/lib/resourceLimits.ts +94 -0
  572. package/src/modules/documents/lib/shareCounts.ts +44 -0
  573. package/src/modules/documents/lib/templateFill.ts +138 -0
  574. package/src/modules/documents/lib/templateInstantiation.ts +206 -0
  575. package/src/modules/documents/lib/templatePreviewDigest.ts +122 -0
  576. package/src/modules/documents/lib/templateSeeds.ts +248 -0
  577. package/src/modules/documents/lib/userLabels.ts +58 -0
  578. package/src/modules/documents/lib/versionContent.ts +163 -0
  579. package/src/modules/documents/lib/versionLabels.ts +9 -0
  580. package/src/modules/documents/lib/versioning.ts +29 -0
  581. package/src/modules/documents/lib/visibility.ts +610 -0
  582. package/src/modules/documents/lib/watchers.ts +129 -0
  583. package/src/modules/documents/migrations/.snapshot-open-mercato.json +2892 -0
  584. package/src/modules/documents/migrations/Migration20260708163836_documents.ts +50 -0
  585. package/src/modules/documents/migrations/Migration20260709164720_documents.ts +19 -0
  586. package/src/modules/documents/migrations/Migration20260710002318_documents.ts +35 -0
  587. package/src/modules/documents/migrations/Migration20260710071003_documents.ts +13 -0
  588. package/src/modules/documents/migrations/Migration20260712120000_documents.ts +13 -0
  589. package/src/modules/documents/migrations/Migration20260712183000_documents.ts +12 -0
  590. package/src/modules/documents/migrations/Migration20260713092156_documents.ts +43 -0
  591. package/src/modules/documents/migrations/Migration20260717000000_documents.ts +40 -0
  592. package/src/modules/documents/notifications.ts +45 -0
  593. package/src/modules/documents/search.ts +118 -0
  594. package/src/modules/documents/setup.ts +19 -0
  595. package/src/modules/documents/widgets/injection/related-documents/LinkDocumentDialog.tsx +224 -0
  596. package/src/modules/documents/widgets/injection/related-documents/context.ts +101 -0
  597. package/src/modules/documents/widgets/injection/related-documents/useRelatedDocuments.ts +112 -0
  598. package/src/modules/documents/widgets/injection/related-documents/widget.client.tsx +76 -0
  599. package/src/modules/documents/widgets/injection/related-documents/widget.ts +19 -0
  600. package/src/modules/documents/widgets/injection-table.ts +20 -0
  601. package/tsconfig.json +9 -0
  602. package/watch.mjs +6 -0
@@ -0,0 +1,676 @@
1
+ import { NextResponse } from 'next/server'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import type { AwilixContainer } from 'awilix'
4
+ import { z } from 'zod'
5
+ import { getAuthFromRequest, type AuthContext } from '@open-mercato/shared/lib/auth/server'
6
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
7
+ import { hasAllFeatures } from '@open-mercato/shared/lib/auth/featureMatch'
8
+ import {
9
+ ORGANIZATION_SCOPE_REQUIRED_ERROR_CODE,
10
+ resolveActiveOrganizationId,
11
+ } from '@open-mercato/shared/lib/auth/organizationScope'
12
+ import { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
13
+ import {
14
+ runRouteMutationGuards,
15
+ type RouteMutationGuardPassed,
16
+ } from '@open-mercato/shared/lib/crud/route-mutation-guard'
17
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
18
+ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
19
+ import { createLogger } from '@open-mercato/shared/lib/logger'
20
+ import type { OpenApiHttpMethod, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
21
+ import {
22
+ Document,
23
+ DocumentContent,
24
+ DocumentFolder,
25
+ DocumentShare,
26
+ } from '../data/entities'
27
+ import {
28
+ deriveDocumentCapabilities,
29
+ type DocumentCapabilities,
30
+ } from '../lib/capabilities'
31
+ import {
32
+ resolveActiveSubjectRoleIds,
33
+ resolvePermission,
34
+ type DocumentTier,
35
+ } from '../lib/permissions'
36
+ import { hasResolvedDocumentsOrganizationAccess } from '../lib/organizationAccess'
37
+ import { containsCanonicalUuid } from '../lib/displayLabels'
38
+ import {
39
+ DOCUMENTS_JSON_BODY_LIMITS,
40
+ readBoundedJsonBody,
41
+ } from '../lib/requestBody'
42
+ import { resolveOrganizationScopeService } from '../lib/platformServices'
43
+
44
+ const logger = createLogger('documents').child({ component: 'api' })
45
+
46
+ export type DocumentsAuthContext = NonNullable<AuthContext> & {
47
+ features: string[]
48
+ roleIds: string[]
49
+ resolvedRoleIds: string[]
50
+ organizationId: string
51
+ }
52
+
53
+ export type DocumentsRouteContext = {
54
+ container: AwilixContainer
55
+ em: EntityManager
56
+ auth: DocumentsAuthContext
57
+ tenantId: string
58
+ organizationId: string
59
+ request: Request
60
+ }
61
+
62
+ type RbacServiceLike = {
63
+ loadAcl: (
64
+ userId: string,
65
+ scope: { tenantId: string | null; organizationId: string | null },
66
+ ) => Promise<{
67
+ isSuperAdmin: boolean
68
+ features: string[]
69
+ organizations: string[] | null
70
+ }>
71
+ }
72
+
73
+ export type MutationGuardResult = RouteMutationGuardPassed
74
+
75
+ export type DocumentCapabilityProjection = {
76
+ relationshipTier: DocumentTier | null
77
+ capabilities: DocumentCapabilities
78
+ }
79
+
80
+ /**
81
+ * Every documents error body carries a translated `error` message. Some also
82
+ * carry a machine-readable `code` discriminator: without it a client cannot
83
+ * tell an unresolved organization scope (recoverable — pick an organization)
84
+ * apart from an ordinary validation rejection, since both are a 400.
85
+ */
86
+ export const routeErrorSchema = z.object({ error: z.string(), code: z.string().optional() })
87
+
88
+ export const ORGANIZATION_SCOPE_REQUIRED_DESCRIPTION =
89
+ `Organization scope could not be resolved (\`code: ${ORGANIZATION_SCOPE_REQUIRED_ERROR_CODE}\`)`
90
+
91
+ export const ORGANIZATION_SELECTION_INVALID_ERROR_CODE = 'organization_selection_invalid'
92
+
93
+ export const ORGANIZATION_SELECTION_INVALID_DESCRIPTION =
94
+ `The selected organization no longer resolves (\`code: ${ORGANIZATION_SELECTION_INVALID_ERROR_CODE}\`)`
95
+
96
+ /**
97
+ * `resolveDocumentsContext` answers 400 with the
98
+ * `organization_scope_required` discriminator whenever an unrestricted caller
99
+ * (a super-admin viewing a foreign tenant with "all organizations" selected)
100
+ * has no resolvable organization. Every route that resolves a documents
101
+ * context can therefore return it, including methods whose own contract
102
+ * declares no 400 at all — so the contract has to say so, or generated clients
103
+ * and the API reference cannot model the recovery path.
104
+ *
105
+ * Responses are keyed by status when the document is built, so a route that
106
+ * already documents a 400 must merge rather than append a second entry.
107
+ */
108
+ export function withDocumentsContextErrors(doc: OpenApiRouteDoc): OpenApiRouteDoc {
109
+ const methods: OpenApiRouteDoc['methods'] = {}
110
+ for (const method of Object.keys(doc.methods) as OpenApiHttpMethod[]) {
111
+ const methodDoc = doc.methods[method]
112
+ if (!methodDoc) continue
113
+ const merge = (
114
+ errors: NonNullable<typeof methodDoc.errors>,
115
+ status: number,
116
+ description: string,
117
+ ): NonNullable<typeof methodDoc.errors> => (
118
+ errors.some((error) => error.status === status)
119
+ ? errors.map((error) => (error.status === status
120
+ ? {
121
+ ...error,
122
+ description: error.description
123
+ ? `${error.description}, or ${description}`
124
+ : description,
125
+ schema: error.schema ?? routeErrorSchema,
126
+ }
127
+ : error))
128
+ : [...errors, { status, description, schema: routeErrorSchema }]
129
+ )
130
+ // `resolveDocumentsContext` answers 400 `organization_scope_required` and
131
+ // 422 `organization_selection_invalid` from the same call, so both ride on
132
+ // every route that resolves a documents context.
133
+ let errors = merge(methodDoc.errors ?? [], 400, ORGANIZATION_SCOPE_REQUIRED_DESCRIPTION)
134
+ errors = merge(errors, 422, ORGANIZATION_SELECTION_INVALID_DESCRIPTION)
135
+ methods[method] = { ...methodDoc, errors }
136
+ }
137
+ return { ...doc, methods }
138
+ }
139
+
140
+ const actorUuidSchema = z.string().uuid()
141
+
142
+ export const ROUTE_ERROR_TRANSLATIONS: Record<string, { key: string; fallback: string }> = {
143
+ Unauthorized: { key: 'api.errors.unauthorized', fallback: 'Unauthorized' },
144
+ Forbidden: { key: 'api.errors.forbidden', fallback: 'Forbidden' },
145
+ 'Organization context is required': {
146
+ key: 'documents.errors.organizationRequired',
147
+ fallback: 'Organization context is required',
148
+ },
149
+ 'Validation failed': { key: 'api.errors.invalidPayload', fallback: 'Invalid payload.' },
150
+ 'Internal server error': { key: 'api.errors.internal', fallback: 'Internal server error' },
151
+ 'Record changed by another user': {
152
+ key: 'documents.errors.recordChanged',
153
+ fallback: 'Record changed by another user',
154
+ },
155
+ 'Document not found': { key: 'documents.documents.notFound', fallback: 'Document not found.' },
156
+ 'documents.content.notFound': {
157
+ key: 'documents.content.notFound',
158
+ fallback: 'Document content not found.',
159
+ },
160
+ 'documents.versions.notFound': {
161
+ key: 'documents.versions.notFound',
162
+ fallback: 'Version not found.',
163
+ },
164
+ 'documents.folders.error.invalidPlacement': {
165
+ key: 'documents.folders.error.invalidPlacement',
166
+ fallback: 'This folder cannot be placed there.',
167
+ },
168
+ 'Folder not found': { key: 'documents.folders.notFound', fallback: 'Folder not found.' },
169
+ 'Share not found': { key: 'documents.share.notFound', fallback: 'Share not found.' },
170
+ 'Comment not found': { key: 'documents.comments.notFound', fallback: 'Comment not found.' },
171
+ 'Document comment limit reached': {
172
+ key: 'documents.comments.limitExceeded',
173
+ fallback: 'This document has reached its comment limit.',
174
+ },
175
+ 'Document version history storage limit exceeded': {
176
+ key: 'documents.versions.quotaExceeded',
177
+ fallback: 'Version history could not retain this snapshot within the document storage limit.',
178
+ },
179
+ 'documents.errors.requestBodyTooLarge': {
180
+ key: 'documents.errors.requestBodyTooLarge',
181
+ fallback: 'Request body is too large.',
182
+ },
183
+ 'Share principal not found in this organization': {
184
+ key: 'documents.share.principalNotFound',
185
+ fallback: 'Share principal not found in this organization',
186
+ },
187
+ 'Private attachment partition is not configured': {
188
+ key: 'documents.attachments.partitionUnavailable',
189
+ fallback: 'Private attachment partition is not configured',
190
+ },
191
+ 'Expected multipart/form-data': {
192
+ key: 'documents.attachments.multipartRequired',
193
+ fallback: 'Expected multipart/form-data',
194
+ },
195
+ 'File is required': { key: 'documents.attachments.fileRequired', fallback: 'File is required' },
196
+ 'Attachment exceeds the maximum upload size.': {
197
+ key: 'documents.attachments.tooLarge',
198
+ fallback: 'Attachment exceeds the maximum upload size.',
199
+ },
200
+ 'Executable file types are not allowed as attachments.': {
201
+ key: 'documents.attachments.executableBlocked',
202
+ fallback: 'Executable file types are not allowed as attachments.',
203
+ },
204
+ 'Active content uploads are not allowed.': {
205
+ key: 'documents.attachments.activeContentBlocked',
206
+ fallback: 'Active content uploads are not allowed.',
207
+ },
208
+ 'Attachment storage quota exceeded for this tenant.': {
209
+ key: 'documents.attachments.quotaExceeded',
210
+ fallback: 'Attachment storage quota exceeded for this tenant.',
211
+ },
212
+ 'Attachment not found': { key: 'documents.attachments.notFound', fallback: 'Attachment not found' },
213
+ 'Partition misconfigured': {
214
+ key: 'documents.attachments.partitionMisconfigured',
215
+ fallback: 'Attachment partition is misconfigured',
216
+ },
217
+ 'File not available': {
218
+ key: 'documents.attachments.fileUnavailable',
219
+ fallback: 'File not available',
220
+ },
221
+ 'Unsupported format': { key: 'documents.export.unsupportedFormat', fallback: 'Unsupported format' },
222
+ 'documents.export.runtimeUnavailable': {
223
+ key: 'documents.export.runtimeUnavailable',
224
+ fallback: 'PDF export is temporarily unavailable.',
225
+ },
226
+ 'documents.errors.organizationSelectionInvalid': {
227
+ key: 'documents.errors.organizationSelectionInvalid',
228
+ fallback: 'Your selected organization is no longer available. Please re-select an organization and try again.',
229
+ },
230
+ }
231
+
232
+ const ROUTE_ERROR_KEY_FALLBACKS = Object.fromEntries(
233
+ Object.values(ROUTE_ERROR_TRANSLATIONS).map(({ key, fallback }) => [key, fallback]),
234
+ ) as Record<string, string>
235
+
236
+ function normalizeStrings(values: unknown): string[] {
237
+ if (!Array.isArray(values)) return []
238
+ return Array.from(
239
+ new Set(
240
+ values
241
+ .map((value) => (typeof value === 'string' ? value.trim() : ''))
242
+ .filter((value) => value.length > 0),
243
+ ),
244
+ )
245
+ }
246
+
247
+ function resolveSelectedOrganization(
248
+ auth: NonNullable<AuthContext>,
249
+ scope: { selectedId?: string | null; filterIds?: string[] | null; allowedIds?: string[] | null; tenantId?: string | null } | null,
250
+ ): string | null {
251
+ // Every document row carries one organization, so there is no "all
252
+ // organizations" view of this module. When the super-admin switcher clears
253
+ // `auth.orgId`, keep the operator on their own organization (the shared
254
+ // helper refuses the fallback once the tenant override moved them elsewhere)
255
+ // instead of failing every request.
256
+ const activeOrganizationId = resolveActiveOrganizationId(auth)
257
+ const allowed = scope?.filterIds ?? scope?.allowedIds ?? (activeOrganizationId ? [activeOrganizationId] : null)
258
+ const candidates = [
259
+ scope?.selectedId ?? null,
260
+ activeOrganizationId,
261
+ Array.isArray(allowed) && allowed.length > 0 ? allowed[0] : null,
262
+ ]
263
+ for (const candidate of candidates) {
264
+ if (!candidate) continue
265
+ if (!Array.isArray(allowed) || allowed.includes(candidate)) return candidate
266
+ }
267
+ return null
268
+ }
269
+
270
+ function readAuthScopeId(auth: NonNullable<AuthContext>, key: 'actorTenantId' | 'actorOrgId'): string | null {
271
+ const value = auth[key]
272
+ if (typeof value === 'string' && value.trim().length > 0) return value.trim()
273
+ return null
274
+ }
275
+
276
+ function normalizeActorUuid(value: unknown): string | null {
277
+ if (typeof value !== 'string') return null
278
+ const normalized = value.trim()
279
+ return actorUuidSchema.safeParse(normalized).success ? normalized : null
280
+ }
281
+
282
+ function isApiKeyAuth(auth: NonNullable<AuthContext>): boolean {
283
+ return auth.isApiKey === true || auth.sub.trim().startsWith('api_key:')
284
+ }
285
+
286
+ export function hasDocumentsFeature(auth: DocumentsAuthContext, feature: string): boolean {
287
+ if (auth.isSuperAdmin === true) return true
288
+ return hasAllFeatures([feature], auth.features)
289
+ }
290
+
291
+ export function hasAnyDocumentsFeature(auth: DocumentsAuthContext, features: string[]): boolean {
292
+ if (auth.isSuperAdmin === true) return true
293
+ return features.some((feature) => hasAllFeatures([feature], auth.features))
294
+ }
295
+
296
+ export function deriveCapabilitiesForContext(
297
+ ctx: DocumentsRouteContext,
298
+ relationshipTier: DocumentTier | null,
299
+ options: { archived?: boolean } = {},
300
+ ): DocumentCapabilities {
301
+ return deriveDocumentCapabilities({
302
+ relationshipTier,
303
+ managerOverride: hasDocumentsFeature(ctx.auth, 'documents.manage'),
304
+ archived: options.archived === true,
305
+ userFeatures: ctx.auth.features,
306
+ })
307
+ }
308
+
309
+ export async function resolveDocumentCapabilityProjection(
310
+ ctx: DocumentsRouteContext,
311
+ documentId: string,
312
+ options: { archived?: boolean } = {},
313
+ ): Promise<DocumentCapabilityProjection> {
314
+ const relationshipTier = await resolvePermission(ctx.em, documentId, ctx.auth)
315
+ return {
316
+ relationshipTier,
317
+ capabilities: deriveCapabilitiesForContext(ctx, relationshipTier, options),
318
+ }
319
+ }
320
+
321
+ export async function loadDocumentArchivedState(
322
+ ctx: DocumentsRouteContext,
323
+ documentId: string,
324
+ ): Promise<{ archivedAt: Date | null }> {
325
+ const document = await findOneWithDecryption(
326
+ ctx.em,
327
+ Document,
328
+ {
329
+ id: documentId,
330
+ tenantId: ctx.tenantId,
331
+ organizationId: ctx.organizationId,
332
+ deletedAt: null,
333
+ },
334
+ { fields: ['id', 'archivedAt'] },
335
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId },
336
+ )
337
+ if (!document) throw new CrudHttpError(404, { error: 'documents.documents.notFound' })
338
+ return { archivedAt: document.archivedAt ?? null }
339
+ }
340
+
341
+ export async function assertDocumentNotArchived(
342
+ ctx: DocumentsRouteContext,
343
+ documentId: string,
344
+ ): Promise<void> {
345
+ const state = await loadDocumentArchivedState(ctx, documentId)
346
+ if (state.archivedAt !== null) {
347
+ throw new CrudHttpError(403, { error: 'documents.errors.documentArchived' })
348
+ }
349
+ }
350
+
351
+ export async function resolveDocumentsContext(
352
+ request: Request,
353
+ requiredFeatures: string[],
354
+ ): Promise<DocumentsRouteContext> {
355
+ const container = await createRequestContainer()
356
+ const em = container.resolve('em') as EntityManager
357
+ const auth = await getAuthFromRequest(request)
358
+ if (!auth || !auth.tenantId) {
359
+ throw new CrudHttpError(401, { error: 'api.errors.unauthorized' })
360
+ }
361
+
362
+ const authenticatedActorUserId = resolveActorUserId(auth)
363
+ const actorTenantId = readAuthScopeId(auth, 'actorTenantId') ?? auth.tenantId
364
+ const actorOrganizationId = readAuthScopeId(auth, 'actorOrgId') ?? auth.orgId
365
+ const rbacService = container.resolve('rbacService') as RbacServiceLike
366
+ const actorAcl = await rbacService.loadAcl(auth.sub, {
367
+ tenantId: actorTenantId,
368
+ organizationId: actorOrganizationId,
369
+ })
370
+ // Organization scope resolution historically accepts the authenticated
371
+ // superadmin bit to support tenant/org switching. Replace that potentially
372
+ // stale token bit with the live RBAC decision before asking the shared scope
373
+ // resolver to expand parent grants into descendant organizations.
374
+ const scopeAuth = {
375
+ ...auth,
376
+ // API-key authentication validates both keyId and any backing user. Keep
377
+ // the prefixed subject for ACL while projecting its UUID domain actor for
378
+ // ownership/share/audit helpers. An unbound key uses its own key UUID.
379
+ userId: authenticatedActorUserId,
380
+ isSuperAdmin: actorAcl.isSuperAdmin === true,
381
+ }
382
+ const organizationScopeService = resolveOrganizationScopeService(container)
383
+ if (!organizationScopeService) {
384
+ throw new CrudHttpError(403, { error: 'api.errors.forbidden' })
385
+ }
386
+ const scope = await organizationScopeService.resolveForRequest({ auth: scopeAuth, request })
387
+ // The caller explicitly selected an organization that no longer resolves to a
388
+ // real, accessible org (stale selected-org cookie after a delete or an access
389
+ // loss). The scope resolver falls back to another allowed org, so continuing
390
+ // would silently read and write against an organization the caller never
391
+ // chose. Fail loud on every documents operation instead — the same contract
392
+ // `makeCrudRoute` enforces via `rejectInvalidOrgSelection` (#3936).
393
+ if (scope?.selectionRejected) {
394
+ throw new CrudHttpError(422, {
395
+ error: 'documents.errors.organizationSelectionInvalid',
396
+ code: ORGANIZATION_SELECTION_INVALID_ERROR_CODE,
397
+ })
398
+ }
399
+ const tenantId = scope?.tenantId ?? auth.tenantId
400
+ const organizationId = resolveSelectedOrganization(scopeAuth, scope)
401
+ if (!tenantId) {
402
+ throw new CrudHttpError(400, { error: 'documents.errors.organizationRequired' })
403
+ }
404
+ if (!organizationId) {
405
+ // An unrestricted caller with no resolvable organization (a super-admin
406
+ // viewing a foreign tenant with "all organizations" selected) is a 400, not
407
+ // a 401 (which `apiFetch` would turn into a refresh loop) and not a 403 (the
408
+ // caller is allowed in; they only need to pick an organization). A caller
409
+ // whose grants expand to no organization at all stays a 403.
410
+ const unrestricted = (scope?.filterIds ?? scope?.allowedIds ?? null) === null
411
+ if (unrestricted) {
412
+ throw new CrudHttpError(400, {
413
+ error: 'documents.errors.organizationRequired',
414
+ code: ORGANIZATION_SCOPE_REQUIRED_ERROR_CODE,
415
+ })
416
+ }
417
+ throw new CrudHttpError(403, { error: 'api.errors.forbidden' })
418
+ }
419
+
420
+ const acl = await rbacService.loadAcl(auth.sub, { tenantId, organizationId })
421
+ if (!hasResolvedDocumentsOrganizationAccess(acl, organizationId, scope)) {
422
+ throw new CrudHttpError(403, { error: 'api.errors.forbidden' })
423
+ }
424
+ const roleIds = await resolveActiveSubjectRoleIds(
425
+ container,
426
+ { tenantId, organizationId },
427
+ auth.sub,
428
+ )
429
+ const documentsAuth: DocumentsAuthContext = {
430
+ ...scopeAuth,
431
+ tenantId,
432
+ orgId: organizationId,
433
+ organizationId,
434
+ roleIds,
435
+ resolvedRoleIds: roleIds,
436
+ // JWT/trusted-request claims are only authentication hints. The current
437
+ // RBAC projection is authoritative for features and superadmin status so
438
+ // a revoked grant cannot survive in a long-lived token.
439
+ features: acl.isSuperAdmin === true ? ['*'] : normalizeStrings(acl.features),
440
+ isSuperAdmin: acl.isSuperAdmin === true,
441
+ }
442
+
443
+ if (!hasAnyDocumentsFeature(documentsAuth, requiredFeatures)) {
444
+ throw new CrudHttpError(403, { error: 'api.errors.forbidden' })
445
+ }
446
+
447
+ return {
448
+ container,
449
+ em,
450
+ auth: documentsAuth,
451
+ tenantId,
452
+ organizationId,
453
+ request,
454
+ }
455
+ }
456
+
457
+ export function resolveActorUserId(auth: NonNullable<AuthContext>): string {
458
+ const subject = auth.sub.trim()
459
+ if (isApiKeyAuth(auth)) {
460
+ // `keyId` is populated only by successful API-key authentication. Do not
461
+ // recover an actor by parsing an arbitrary prefixed subject when that
462
+ // validated field is absent, malformed, or disagrees with the subject.
463
+ const keyId = normalizeActorUuid(auth.keyId)
464
+ if (!keyId || subject !== `api_key:${keyId}`) {
465
+ throw new CrudHttpError(403, { error: 'api.errors.forbidden' })
466
+ }
467
+ if (auth.userId === undefined || auth.userId === null) return keyId
468
+ const backingUserId = normalizeActorUuid(auth.userId)
469
+ if (backingUserId) return backingUserId
470
+ throw new CrudHttpError(403, { error: 'api.errors.forbidden' })
471
+ }
472
+
473
+ const actorUserId = normalizeActorUuid(subject)
474
+ const claimedUserId = auth.userId === undefined || auth.userId === null
475
+ ? actorUserId
476
+ : normalizeActorUuid(auth.userId)
477
+ if (actorUserId && claimedUserId === actorUserId) return actorUserId
478
+ throw new CrudHttpError(403, { error: 'api.errors.forbidden' })
479
+ }
480
+
481
+ export async function readBody(
482
+ request: Request,
483
+ maxBytes = DOCUMENTS_JSON_BODY_LIMITS.standard,
484
+ ): Promise<Record<string, unknown>> {
485
+ return (await readBoundedJsonBody<Record<string, unknown>>(request, maxBytes, {})) ?? {}
486
+ }
487
+
488
+ async function localizeRouteErrorBody(body: Record<string, unknown>): Promise<Record<string, unknown>> {
489
+ const rawError = typeof body.error === 'string' ? body.error : null
490
+ if (!rawError) return body
491
+
492
+ if (containsCanonicalUuid(rawError)) {
493
+ const { key, fallback } = ROUTE_ERROR_TRANSLATIONS['Internal server error']!
494
+ try {
495
+ const { translate } = await resolveTranslations()
496
+ return { ...body, error: translate(key, fallback) }
497
+ } catch {
498
+ return { ...body, error: fallback }
499
+ }
500
+ }
501
+
502
+ const literal = ROUTE_ERROR_TRANSLATIONS[rawError]
503
+ const key = literal?.key ?? rawError
504
+ const fallback = literal?.fallback ?? ROUTE_ERROR_KEY_FALLBACKS[key]
505
+ // Attachment failures reach these routes as the attachments module's own
506
+ // catalogued keys. The locale dictionary is merged across modules, so they
507
+ // resolve here; without this prefix the raw key would reach the client.
508
+ if (
509
+ !key.startsWith('documents.')
510
+ && !key.startsWith('api.')
511
+ && !key.startsWith('attachments.')
512
+ ) return body
513
+
514
+ try {
515
+ const { translate } = await resolveTranslations()
516
+ return { ...body, error: translate(key, fallback) }
517
+ } catch {
518
+ return { ...body, error: fallback ?? key }
519
+ }
520
+ }
521
+
522
+ export async function handleDocumentsRouteError(error: unknown, label: string): Promise<Response> {
523
+ if (isCrudHttpError(error)) {
524
+ const body = error.body && typeof error.body === 'object' && !Array.isArray(error.body)
525
+ ? error.body as Record<string, unknown>
526
+ : { error: 'api.errors.internal' }
527
+ return NextResponse.json(await localizeRouteErrorBody(body), { status: error.status })
528
+ }
529
+ if (error instanceof z.ZodError) {
530
+ return NextResponse.json(
531
+ await localizeRouteErrorBody({ error: 'api.errors.invalidPayload', details: error.issues }),
532
+ { status: 400 },
533
+ )
534
+ }
535
+ logger.error(`${label} failed`, { err: error })
536
+ return NextResponse.json(
537
+ await localizeRouteErrorBody({ error: 'api.errors.internal' }),
538
+ { status: 500 },
539
+ )
540
+ }
541
+
542
+ export async function loadScopedDocument(ctx: DocumentsRouteContext, id: string): Promise<Document> {
543
+ const document = await findOneWithDecryption(ctx.em, Document, {
544
+ id,
545
+ tenantId: ctx.tenantId,
546
+ organizationId: ctx.organizationId,
547
+ deletedAt: null,
548
+ }, undefined, { tenantId: ctx.tenantId, organizationId: ctx.organizationId })
549
+ if (!document) throw new CrudHttpError(404, { error: 'documents.documents.notFound' })
550
+ return document
551
+ }
552
+
553
+ export async function loadScopedShare(
554
+ ctx: DocumentsRouteContext,
555
+ documentId: string,
556
+ shareId: string,
557
+ ): Promise<DocumentShare> {
558
+ const share = await findOneWithDecryption(ctx.em, DocumentShare, {
559
+ id: shareId,
560
+ documentId,
561
+ tenantId: ctx.tenantId,
562
+ organizationId: ctx.organizationId,
563
+ deletedAt: null,
564
+ }, undefined, { tenantId: ctx.tenantId, organizationId: ctx.organizationId })
565
+ if (!share) throw new CrudHttpError(404, { error: 'documents.share.notFound' })
566
+ return share
567
+ }
568
+
569
+ export function serializeDocument(document: Document): Record<string, unknown> {
570
+ return {
571
+ id: document.id,
572
+ title: document.title,
573
+ folderId: document.folderId ?? null,
574
+ ownerUserId: document.ownerUserId,
575
+ createdByUserId: document.createdByUserId,
576
+ isActive: document.isActive,
577
+ createdAt: document.createdAt.toISOString(),
578
+ updatedAt: document.updatedAt.toISOString(),
579
+ }
580
+ }
581
+
582
+ export function serializeContent(content: DocumentContent | null): Record<string, unknown> {
583
+ return {
584
+ contentHtml: content?.contentHtml ?? '',
585
+ contentText: content?.contentText ?? '',
586
+ updatedAt: content?.updatedAt ? content.updatedAt.toISOString() : null,
587
+ }
588
+ }
589
+
590
+ export function serializeFolder(folder: DocumentFolder): Record<string, unknown> {
591
+ return {
592
+ id: folder.id,
593
+ name: folder.name,
594
+ parentFolderId: folder.parentFolderId ?? null,
595
+ ownerUserId: folder.ownerUserId,
596
+ createdAt: folder.createdAt.toISOString(),
597
+ updatedAt: folder.updatedAt.toISOString(),
598
+ }
599
+ }
600
+
601
+ export function serializeShare(share: DocumentShare): Record<string, unknown> {
602
+ return {
603
+ id: share.id,
604
+ documentId: share.documentId,
605
+ principalType: share.principalType,
606
+ principalId: share.principalId,
607
+ permission: share.permission,
608
+ createdByUserId: share.createdByUserId,
609
+ createdAt: share.createdAt.toISOString(),
610
+ updatedAt: share.updatedAt.toISOString(),
611
+ }
612
+ }
613
+
614
+ export async function validateMutationGuard(
615
+ ctx: DocumentsRouteContext,
616
+ input: {
617
+ resourceKind: string
618
+ resourceId: string
619
+ operation: 'create' | 'update' | 'delete' | 'custom'
620
+ mutationPayload?: Record<string, unknown> | null
621
+ /**
622
+ * Re-parses a guard's `modifiedPayload` before it reaches the command. A
623
+ * registry guard may rewrite the payload, and the route's own schema is the
624
+ * only thing that still guarantees the command receives a shape it can trust.
625
+ */
626
+ mutationPayloadSchema?: { parse: (value: unknown) => Record<string, unknown> }
627
+ },
628
+ ): Promise<MutationGuardResult> {
629
+ // `runRouteMutationGuards` runs EVERY registered guard plus the bridged legacy
630
+ // DI service. The deprecated `validateCrudMutationGuard` /
631
+ // `runCrudMutationGuardAfterSuccess` pair used here before resolved only the
632
+ // single DI-registered guard service, so every guard a module contributed
633
+ // through the registry — along with its payload transformation and its
634
+ // after-success callback — was silently skipped on Documents writes.
635
+ const guardResult = await runRouteMutationGuards({
636
+ container: ctx.container,
637
+ req: ctx.request,
638
+ auth: {
639
+ tenantId: ctx.tenantId,
640
+ organizationId: ctx.organizationId,
641
+ userId: resolveActorUserId(ctx.auth),
642
+ userFeatures: ctx.auth.features,
643
+ },
644
+ input: {
645
+ resourceKind: input.resourceKind,
646
+ resourceId: input.resourceId,
647
+ operation: input.operation,
648
+ mutationPayload: input.mutationPayload ?? null,
649
+ },
650
+ })
651
+ if (!guardResult.ok) {
652
+ throw new CrudHttpError(guardResult.errorStatus, guardResult.errorBody)
653
+ }
654
+ if (guardResult.modifiedPayload && input.mutationPayload) {
655
+ const transformed = input.mutationPayloadSchema
656
+ ? input.mutationPayloadSchema.parse(guardResult.modifiedPayload)
657
+ : guardResult.modifiedPayload
658
+ // Routes read the object they handed in, so the transformation has to land
659
+ // there rather than only on the guard result.
660
+ for (const key of Object.keys(input.mutationPayload)) delete input.mutationPayload[key]
661
+ Object.assign(input.mutationPayload, transformed)
662
+ }
663
+ return guardResult
664
+ }
665
+
666
+ export async function runMutationGuardAfterSuccess(
667
+ _ctx: DocumentsRouteContext,
668
+ guardResult: MutationGuardResult,
669
+ _input: {
670
+ resourceKind: string
671
+ resourceId: string
672
+ operation: 'create' | 'update' | 'delete' | 'custom'
673
+ },
674
+ ): Promise<void> {
675
+ await guardResult.runAfterSuccess()
676
+ }