@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.
- package/README.md +88 -0
- package/build.mjs +23 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/modules/documents/acl.js +15 -0
- package/dist/modules/documents/acl.js.map +7 -0
- package/dist/modules/documents/api/[id]/archive/route.js +116 -0
- package/dist/modules/documents/api/[id]/archive/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/attachments/[attachmentId]/route.js +155 -0
- package/dist/modules/documents/api/[id]/attachments/[attachmentId]/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/attachments/route.js +153 -0
- package/dist/modules/documents/api/[id]/attachments/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/collab-token/route.js +180 -0
- package/dist/modules/documents/api/[id]/collab-token/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/comments/access-check/route.js +86 -0
- package/dist/modules/documents/api/[id]/comments/access-check/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/comments/route.js +387 -0
- package/dist/modules/documents/api/[id]/comments/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/content/route.js +143 -0
- package/dist/modules/documents/api/[id]/content/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/duplicate/route.js +200 -0
- package/dist/modules/documents/api/[id]/duplicate/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/export/route.js +421 -0
- package/dist/modules/documents/api/[id]/export/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/favorite/route.js +96 -0
- package/dist/modules/documents/api/[id]/favorite/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/links/[linkId]/route.js +85 -0
- package/dist/modules/documents/api/[id]/links/[linkId]/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/links/route.js +257 -0
- package/dist/modules/documents/api/[id]/links/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/principals/route.js +299 -0
- package/dist/modules/documents/api/[id]/principals/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/route.js +246 -0
- package/dist/modules/documents/api/[id]/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/shares/route.js +335 -0
- package/dist/modules/documents/api/[id]/shares/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/unarchive/route.js +39 -0
- package/dist/modules/documents/api/[id]/unarchive/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/versions/[versionId]/restore/route.js +133 -0
- package/dist/modules/documents/api/[id]/versions/[versionId]/restore/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/versions/[versionId]/route.js +93 -0
- package/dist/modules/documents/api/[id]/versions/[versionId]/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/versions/route.js +193 -0
- package/dist/modules/documents/api/[id]/versions/route.js.map +7 -0
- package/dist/modules/documents/api/[id]/watch/route.js +97 -0
- package/dist/modules/documents/api/[id]/watch/route.js.map +7 -0
- package/dist/modules/documents/api/_commands.js +34 -0
- package/dist/modules/documents/api/_commands.js.map +7 -0
- package/dist/modules/documents/api/_shared.js +490 -0
- package/dist/modules/documents/api/_shared.js.map +7 -0
- package/dist/modules/documents/api/folders/route.js +256 -0
- package/dist/modules/documents/api/folders/route.js.map +7 -0
- package/dist/modules/documents/api/instantiate/route.js +108 -0
- package/dist/modules/documents/api/instantiate/route.js.map +7 -0
- package/dist/modules/documents/api/route.js +322 -0
- package/dist/modules/documents/api/route.js.map +7 -0
- package/dist/modules/documents/api/templates/[templateId]/preview/route.js +94 -0
- package/dist/modules/documents/api/templates/[templateId]/preview/route.js.map +7 -0
- package/dist/modules/documents/api/templates/[templateId]/route.js +82 -0
- package/dist/modules/documents/api/templates/[templateId]/route.js.map +7 -0
- package/dist/modules/documents/api/templates/route.js +344 -0
- package/dist/modules/documents/api/templates/route.js.map +7 -0
- package/dist/modules/documents/backend/documents/DocumentsPageClient.js +160 -0
- package/dist/modules/documents/backend/documents/DocumentsPageClient.js.map +7 -0
- package/dist/modules/documents/backend/documents/DocumentsTable.js +143 -0
- package/dist/modules/documents/backend/documents/DocumentsTable.js.map +7 -0
- package/dist/modules/documents/backend/documents/FolderDialog.js +55 -0
- package/dist/modules/documents/backend/documents/FolderDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/FolderTree.js +40 -0
- package/dist/modules/documents/backend/documents/FolderTree.js.map +7 -0
- package/dist/modules/documents/backend/documents/MoveDocumentDialog.js +64 -0
- package/dist/modules/documents/backend/documents/MoveDocumentDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/CommentAnchorNavigation.js +77 -0
- package/dist/modules/documents/backend/documents/[id]/CommentAnchorNavigation.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/CommentComposer.js +126 -0
- package/dist/modules/documents/backend/documents/[id]/CommentComposer.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/CommentThreadList.js +88 -0
- package/dist/modules/documents/backend/documents/[id]/CommentThreadList.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/CommentsRail.js +123 -0
- package/dist/modules/documents/backend/documents/[id]/CommentsRail.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentCanvas.js +91 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentCanvas.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentEditorErrorBoundary.js +27 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentEditorErrorBoundary.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentEditorIsland.js +50 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentEditorIsland.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentEditorSurface.js +168 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentEditorSurface.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentNavigator.js +129 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentNavigator.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentPageClient.js +429 -0
- package/dist/modules/documents/backend/documents/[id]/DocumentPageClient.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/EditorColorTools.js +68 -0
- package/dist/modules/documents/backend/documents/[id]/EditorColorTools.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/EditorStatusPresence.js +69 -0
- package/dist/modules/documents/backend/documents/[id]/EditorStatusPresence.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/EditorToolbar.js +151 -0
- package/dist/modules/documents/backend/documents/[id]/EditorToolbar.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/ExportMenu.js +121 -0
- package/dist/modules/documents/backend/documents/[id]/ExportMenu.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/MentionPicker.js +114 -0
- package/dist/modules/documents/backend/documents/[id]/MentionPicker.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/OutlinePane.js +70 -0
- package/dist/modules/documents/backend/documents/[id]/OutlinePane.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/RecordFieldsDialog.js +157 -0
- package/dist/modules/documents/backend/documents/[id]/RecordFieldsDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/RelatedRecordsPanel.js +266 -0
- package/dist/modules/documents/backend/documents/[id]/RelatedRecordsPanel.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/VersionHistoryPanel.js +227 -0
- package/dist/modules/documents/backend/documents/[id]/VersionHistoryPanel.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/VersionPreviewDialog.js +157 -0
- package/dist/modules/documents/backend/documents/[id]/VersionPreviewDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/commentTypes.js +150 -0
- package/dist/modules/documents/backend/documents/[id]/commentTypes.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/componentCapabilities.js +13 -0
- package/dist/modules/documents/backend/documents/[id]/componentCapabilities.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/documentPagination.js +295 -0
- package/dist/modules/documents/backend/documents/[id]/documentPagination.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/editorPresenceStyles.js +81 -0
- package/dist/modules/documents/backend/documents/[id]/editorPresenceStyles.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/editorTypes.js +52 -0
- package/dist/modules/documents/backend/documents/[id]/editorTypes.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/page.js +10 -0
- package/dist/modules/documents/backend/documents/[id]/page.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/page.meta.js +16 -0
- package/dist/modules/documents/backend/documents/[id]/page.meta.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/relatedRecordModel.js +38 -0
- package/dist/modules/documents/backend/documents/[id]/relatedRecordModel.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/restoreVersion.js +33 -0
- package/dist/modules/documents/backend/documents/[id]/restoreVersion.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentCollaboration.js +392 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentCollaboration.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentComments.js +253 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentComments.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentEditor.js +149 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentEditor.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentTitle.js +82 -0
- package/dist/modules/documents/backend/documents/[id]/useDocumentTitle.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/useEditorInsertions.js +144 -0
- package/dist/modules/documents/backend/documents/[id]/useEditorInsertions.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/useFallbackContentPersistence.js +237 -0
- package/dist/modules/documents/backend/documents/[id]/useFallbackContentPersistence.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/useMentionPicker.js +216 -0
- package/dist/modules/documents/backend/documents/[id]/useMentionPicker.js.map +7 -0
- package/dist/modules/documents/backend/documents/[id]/versionHistoryModel.js +25 -0
- package/dist/modules/documents/backend/documents/[id]/versionHistoryModel.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/EntityPicker.js +156 -0
- package/dist/modules/documents/backend/documents/components/EntityPicker.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/EntityPickerResults.js +46 -0
- package/dist/modules/documents/backend/documents/components/EntityPickerResults.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/NewFromTemplateDialog.js +127 -0
- package/dist/modules/documents/backend/documents/components/NewFromTemplateDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/PrincipalPicker.js +84 -0
- package/dist/modules/documents/backend/documents/components/PrincipalPicker.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/ShareDialog.js +77 -0
- package/dist/modules/documents/backend/documents/components/ShareDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/ShareDialogAddForm.js +93 -0
- package/dist/modules/documents/backend/documents/components/ShareDialogAddForm.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/ShareDialogList.js +82 -0
- package/dist/modules/documents/backend/documents/components/ShareDialogList.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/TemplateBodyEditor.js +96 -0
- package/dist/modules/documents/backend/documents/components/TemplateBodyEditor.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/TemplateEditorDialog.js +169 -0
- package/dist/modules/documents/backend/documents/components/TemplateEditorDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/TemplatePreview.js +38 -0
- package/dist/modules/documents/backend/documents/components/TemplatePreview.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/TemplateSlotFields.js +69 -0
- package/dist/modules/documents/backend/documents/components/TemplateSlotFields.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/TemplateSlotsEditor.js +71 -0
- package/dist/modules/documents/backend/documents/components/TemplateSlotsEditor.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/principalPickerModel.js +63 -0
- package/dist/modules/documents/backend/documents/components/principalPickerModel.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/shareDialogModel.js +68 -0
- package/dist/modules/documents/backend/documents/components/shareDialogModel.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/templateUi.js +89 -0
- package/dist/modules/documents/backend/documents/components/templateUi.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/useAvailableEntityRegistry.js +30 -0
- package/dist/modules/documents/backend/documents/components/useAvailableEntityRegistry.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/useEntitySearch.js +191 -0
- package/dist/modules/documents/backend/documents/components/useEntitySearch.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/usePrincipalPicker.js +221 -0
- package/dist/modules/documents/backend/documents/components/usePrincipalPicker.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/useShareDialog.js +236 -0
- package/dist/modules/documents/backend/documents/components/useShareDialog.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/useTemplateDetail.js +49 -0
- package/dist/modules/documents/backend/documents/components/useTemplateDetail.js.map +7 -0
- package/dist/modules/documents/backend/documents/components/useTemplateInstantiation.js +234 -0
- package/dist/modules/documents/backend/documents/components/useTemplateInstantiation.js.map +7 -0
- package/dist/modules/documents/backend/documents/documentUi.js +106 -0
- package/dist/modules/documents/backend/documents/documentUi.js.map +7 -0
- package/dist/modules/documents/backend/documents/documentsListTypes.js +132 -0
- package/dist/modules/documents/backend/documents/documentsListTypes.js.map +7 -0
- package/dist/modules/documents/backend/documents/page.js +9 -0
- package/dist/modules/documents/backend/documents/page.js.map +7 -0
- package/dist/modules/documents/backend/documents/page.meta.js +26 -0
- package/dist/modules/documents/backend/documents/page.meta.js.map +7 -0
- package/dist/modules/documents/backend/documents/templates/TemplatesPageClient.js +91 -0
- package/dist/modules/documents/backend/documents/templates/TemplatesPageClient.js.map +7 -0
- package/dist/modules/documents/backend/documents/templates/TemplatesTable.js +58 -0
- package/dist/modules/documents/backend/documents/templates/TemplatesTable.js.map +7 -0
- package/dist/modules/documents/backend/documents/templates/page.js +9 -0
- package/dist/modules/documents/backend/documents/templates/page.js.map +7 -0
- package/dist/modules/documents/backend/documents/templates/page.meta.js +34 -0
- package/dist/modules/documents/backend/documents/templates/page.meta.js.map +7 -0
- package/dist/modules/documents/backend/documents/templates/useTemplatesPage.js +139 -0
- package/dist/modules/documents/backend/documents/templates/useTemplatesPage.js.map +7 -0
- package/dist/modules/documents/backend/documents/useDocumentsList.js +314 -0
- package/dist/modules/documents/backend/documents/useDocumentsList.js.map +7 -0
- package/dist/modules/documents/ce.js +8 -0
- package/dist/modules/documents/ce.js.map +7 -0
- package/dist/modules/documents/commands/aggregate.js +99 -0
- package/dist/modules/documents/commands/aggregate.js.map +7 -0
- package/dist/modules/documents/commands/attachments.js +252 -0
- package/dist/modules/documents/commands/attachments.js.map +7 -0
- package/dist/modules/documents/commands/comments.js +782 -0
- package/dist/modules/documents/commands/comments.js.map +7 -0
- package/dist/modules/documents/commands/content.js +238 -0
- package/dist/modules/documents/commands/content.js.map +7 -0
- package/dist/modules/documents/commands/document-crud.js +505 -0
- package/dist/modules/documents/commands/document-crud.js.map +7 -0
- package/dist/modules/documents/commands/documents.js +473 -0
- package/dist/modules/documents/commands/documents.js.map +7 -0
- package/dist/modules/documents/commands/duplicate.js +640 -0
- package/dist/modules/documents/commands/duplicate.js.map +7 -0
- package/dist/modules/documents/commands/favorites.js +150 -0
- package/dist/modules/documents/commands/favorites.js.map +7 -0
- package/dist/modules/documents/commands/folders.js +420 -0
- package/dist/modules/documents/commands/folders.js.map +7 -0
- package/dist/modules/documents/commands/index.js +64 -0
- package/dist/modules/documents/commands/index.js.map +7 -0
- package/dist/modules/documents/commands/interceptors.js +300 -0
- package/dist/modules/documents/commands/interceptors.js.map +7 -0
- package/dist/modules/documents/commands/lifecycle.js +249 -0
- package/dist/modules/documents/commands/lifecycle.js.map +7 -0
- package/dist/modules/documents/commands/links.js +410 -0
- package/dist/modules/documents/commands/links.js.map +7 -0
- package/dist/modules/documents/commands/mutation-helpers.js +42 -0
- package/dist/modules/documents/commands/mutation-helpers.js.map +7 -0
- package/dist/modules/documents/commands/projection-types.js +1 -0
- package/dist/modules/documents/commands/projection-types.js.map +7 -0
- package/dist/modules/documents/commands/shared.js +143 -0
- package/dist/modules/documents/commands/shared.js.map +7 -0
- package/dist/modules/documents/commands/shares.js +527 -0
- package/dist/modules/documents/commands/shares.js.map +7 -0
- package/dist/modules/documents/commands/side-effects.js +103 -0
- package/dist/modules/documents/commands/side-effects.js.map +7 -0
- package/dist/modules/documents/commands/templates.js +461 -0
- package/dist/modules/documents/commands/templates.js.map +7 -0
- package/dist/modules/documents/commands/versions.js +432 -0
- package/dist/modules/documents/commands/versions.js.map +7 -0
- package/dist/modules/documents/commands/watchers.js +164 -0
- package/dist/modules/documents/commands/watchers.js.map +7 -0
- package/dist/modules/documents/data/entities.js +653 -0
- package/dist/modules/documents/data/entities.js.map +7 -0
- package/dist/modules/documents/data/extensions.js +44 -0
- package/dist/modules/documents/data/extensions.js.map +7 -0
- package/dist/modules/documents/data/validators.js +219 -0
- package/dist/modules/documents/data/validators.js.map +7 -0
- package/dist/modules/documents/di.js +35 -0
- package/dist/modules/documents/di.js.map +7 -0
- package/dist/modules/documents/encryption.js +12 -0
- package/dist/modules/documents/encryption.js.map +7 -0
- package/dist/modules/documents/events.js +27 -0
- package/dist/modules/documents/events.js.map +7 -0
- package/dist/modules/documents/index.js +19 -0
- package/dist/modules/documents/index.js.map +7 -0
- package/dist/modules/documents/lib/attachmentServicePort.js +30 -0
- package/dist/modules/documents/lib/attachmentServicePort.js.map +7 -0
- package/dist/modules/documents/lib/capabilities.js +32 -0
- package/dist/modules/documents/lib/capabilities.js.map +7 -0
- package/dist/modules/documents/lib/collabCloseEvents.js +17 -0
- package/dist/modules/documents/lib/collabCloseEvents.js.map +7 -0
- package/dist/modules/documents/lib/collabEndpoint.js +22 -0
- package/dist/modules/documents/lib/collabEndpoint.js.map +7 -0
- package/dist/modules/documents/lib/collabMaterializer.js +107 -0
- package/dist/modules/documents/lib/collabMaterializer.js.map +7 -0
- package/dist/modules/documents/lib/collabToken.js +120 -0
- package/dist/modules/documents/lib/collabToken.js.map +7 -0
- package/dist/modules/documents/lib/collaborationAwareness.js +68 -0
- package/dist/modules/documents/lib/collaborationAwareness.js.map +7 -0
- package/dist/modules/documents/lib/commentAnchors.js +15 -0
- package/dist/modules/documents/lib/commentAnchors.js.map +7 -0
- package/dist/modules/documents/lib/constants.js +25 -0
- package/dist/modules/documents/lib/constants.js.map +7 -0
- package/dist/modules/documents/lib/contentService.js +248 -0
- package/dist/modules/documents/lib/contentService.js.map +7 -0
- package/dist/modules/documents/lib/displayLabels.js +23 -0
- package/dist/modules/documents/lib/displayLabels.js.map +7 -0
- package/dist/modules/documents/lib/docxRenderer.js +601 -0
- package/dist/modules/documents/lib/docxRenderer.js.map +7 -0
- package/dist/modules/documents/lib/duplicateContent.js +22 -0
- package/dist/modules/documents/lib/duplicateContent.js.map +7 -0
- package/dist/modules/documents/lib/editorConfig.js +287 -0
- package/dist/modules/documents/lib/editorConfig.js.map +7 -0
- package/dist/modules/documents/lib/entityLinks.js +148 -0
- package/dist/modules/documents/lib/entityLinks.js.map +7 -0
- package/dist/modules/documents/lib/entityRegistry.js +258 -0
- package/dist/modules/documents/lib/entityRegistry.js.map +7 -0
- package/dist/modules/documents/lib/entityRegistry.server.js +189 -0
- package/dist/modules/documents/lib/entityRegistry.server.js.map +7 -0
- package/dist/modules/documents/lib/entityRegistryAvailability.server.js +9 -0
- package/dist/modules/documents/lib/entityRegistryAvailability.server.js.map +7 -0
- package/dist/modules/documents/lib/entitySuggestion.js +50 -0
- package/dist/modules/documents/lib/entitySuggestion.js.map +7 -0
- package/dist/modules/documents/lib/favorites.js +22 -0
- package/dist/modules/documents/lib/favorites.js.map +7 -0
- package/dist/modules/documents/lib/folderHierarchySerialization.js +19 -0
- package/dist/modules/documents/lib/folderHierarchySerialization.js.map +7 -0
- package/dist/modules/documents/lib/historyLimits.js +100 -0
- package/dist/modules/documents/lib/historyLimits.js.map +7 -0
- package/dist/modules/documents/lib/historyPolicy.js +14 -0
- package/dist/modules/documents/lib/historyPolicy.js.map +7 -0
- package/dist/modules/documents/lib/organizationAccess.js +17 -0
- package/dist/modules/documents/lib/organizationAccess.js.map +7 -0
- package/dist/modules/documents/lib/pdfHtml.js +62 -0
- package/dist/modules/documents/lib/pdfHtml.js.map +7 -0
- package/dist/modules/documents/lib/pdfRenderer.js +284 -0
- package/dist/modules/documents/lib/pdfRenderer.js.map +7 -0
- package/dist/modules/documents/lib/permissions.js +222 -0
- package/dist/modules/documents/lib/permissions.js.map +7 -0
- package/dist/modules/documents/lib/platformServices.js +35 -0
- package/dist/modules/documents/lib/platformServices.js.map +7 -0
- package/dist/modules/documents/lib/recordFieldInsertion.js +58 -0
- package/dist/modules/documents/lib/recordFieldInsertion.js.map +7 -0
- package/dist/modules/documents/lib/requestBody.js +80 -0
- package/dist/modules/documents/lib/requestBody.js.map +7 -0
- package/dist/modules/documents/lib/resourceLimits.js +62 -0
- package/dist/modules/documents/lib/resourceLimits.js.map +7 -0
- package/dist/modules/documents/lib/shareCounts.js +25 -0
- package/dist/modules/documents/lib/shareCounts.js.map +7 -0
- package/dist/modules/documents/lib/templateFill.js +84 -0
- package/dist/modules/documents/lib/templateFill.js.map +7 -0
- package/dist/modules/documents/lib/templateInstantiation.js +147 -0
- package/dist/modules/documents/lib/templateInstantiation.js.map +7 -0
- package/dist/modules/documents/lib/templatePreviewDigest.js +82 -0
- package/dist/modules/documents/lib/templatePreviewDigest.js.map +7 -0
- package/dist/modules/documents/lib/templateSeeds.js +201 -0
- package/dist/modules/documents/lib/templateSeeds.js.map +7 -0
- package/dist/modules/documents/lib/userLabels.js +37 -0
- package/dist/modules/documents/lib/userLabels.js.map +7 -0
- package/dist/modules/documents/lib/versionContent.js +131 -0
- package/dist/modules/documents/lib/versionContent.js.map +7 -0
- package/dist/modules/documents/lib/versionLabels.js +12 -0
- package/dist/modules/documents/lib/versionLabels.js.map +7 -0
- package/dist/modules/documents/lib/versioning.js +14 -0
- package/dist/modules/documents/lib/versioning.js.map +7 -0
- package/dist/modules/documents/lib/visibility.js +422 -0
- package/dist/modules/documents/lib/visibility.js.map +7 -0
- package/dist/modules/documents/lib/watchers.js +106 -0
- package/dist/modules/documents/lib/watchers.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260708163836_documents.js +44 -0
- package/dist/modules/documents/migrations/Migration20260708163836_documents.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260709164720_documents.js +17 -0
- package/dist/modules/documents/migrations/Migration20260709164720_documents.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260710002318_documents.js +32 -0
- package/dist/modules/documents/migrations/Migration20260710002318_documents.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260710071003_documents.js +13 -0
- package/dist/modules/documents/migrations/Migration20260710071003_documents.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260712120000_documents.js +13 -0
- package/dist/modules/documents/migrations/Migration20260712120000_documents.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260712183000_documents.js +14 -0
- package/dist/modules/documents/migrations/Migration20260712183000_documents.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260713092156_documents.js +29 -0
- package/dist/modules/documents/migrations/Migration20260713092156_documents.js.map +7 -0
- package/dist/modules/documents/migrations/Migration20260717000000_documents.js +37 -0
- package/dist/modules/documents/migrations/Migration20260717000000_documents.js.map +7 -0
- package/dist/modules/documents/notifications.js +47 -0
- package/dist/modules/documents/notifications.js.map +7 -0
- package/dist/modules/documents/search.js +101 -0
- package/dist/modules/documents/search.js.map +7 -0
- package/dist/modules/documents/setup.js +19 -0
- package/dist/modules/documents/setup.js.map +7 -0
- package/dist/modules/documents/widgets/injection/related-documents/LinkDocumentDialog.js +214 -0
- package/dist/modules/documents/widgets/injection/related-documents/LinkDocumentDialog.js.map +7 -0
- package/dist/modules/documents/widgets/injection/related-documents/context.js +84 -0
- package/dist/modules/documents/widgets/injection/related-documents/context.js.map +7 -0
- package/dist/modules/documents/widgets/injection/related-documents/useRelatedDocuments.js +98 -0
- package/dist/modules/documents/widgets/injection/related-documents/useRelatedDocuments.js.map +7 -0
- package/dist/modules/documents/widgets/injection/related-documents/widget.client.js +83 -0
- package/dist/modules/documents/widgets/injection/related-documents/widget.client.js.map +7 -0
- package/dist/modules/documents/widgets/injection/related-documents/widget.js +19 -0
- package/dist/modules/documents/widgets/injection/related-documents/widget.js.map +7 -0
- package/dist/modules/documents/widgets/injection-table.js +21 -0
- package/dist/modules/documents/widgets/injection-table.js.map +7 -0
- package/dist/server/documents-collab-server.js +2260 -0
- package/dist/server/documents-collab-server.js.map +7 -0
- package/generated/entities/document/index.ts +12 -0
- package/generated/entities/document_attachment/index.ts +9 -0
- package/generated/entities/document_comment/index.ts +14 -0
- package/generated/entities/document_content/index.ts +11 -0
- package/generated/entities/document_entity_link/index.ts +19 -0
- package/generated/entities/document_favorite/index.ts +7 -0
- package/generated/entities/document_folder/index.ts +9 -0
- package/generated/entities/document_share/index.ts +11 -0
- package/generated/entities/document_template/index.ts +13 -0
- package/generated/entities/document_version/index.ts +9 -0
- package/generated/entities/document_watcher/index.ts +7 -0
- package/generated/entities.ids.generated.ts +21 -0
- package/generated/entity-fields-registry.ts +151 -0
- package/jest.config.cjs +34 -0
- package/package.json +149 -0
- package/server/documents-collab-server.ts +3416 -0
- package/src/index.ts +1 -0
- package/src/modules/documents/acl.ts +11 -0
- package/src/modules/documents/api/[id]/archive/route.ts +132 -0
- package/src/modules/documents/api/[id]/attachments/[attachmentId]/route.ts +166 -0
- package/src/modules/documents/api/[id]/attachments/route.ts +173 -0
- package/src/modules/documents/api/[id]/collab-token/route.ts +203 -0
- package/src/modules/documents/api/[id]/comments/access-check/route.ts +96 -0
- package/src/modules/documents/api/[id]/comments/route.ts +442 -0
- package/src/modules/documents/api/[id]/content/route.ts +156 -0
- package/src/modules/documents/api/[id]/duplicate/route.ts +231 -0
- package/src/modules/documents/api/[id]/export/route.ts +535 -0
- package/src/modules/documents/api/[id]/favorite/route.ts +110 -0
- package/src/modules/documents/api/[id]/links/[linkId]/route.ts +92 -0
- package/src/modules/documents/api/[id]/links/route.ts +301 -0
- package/src/modules/documents/api/[id]/principals/route.ts +375 -0
- package/src/modules/documents/api/[id]/route.ts +267 -0
- package/src/modules/documents/api/[id]/shares/route.ts +372 -0
- package/src/modules/documents/api/[id]/unarchive/route.ts +42 -0
- package/src/modules/documents/api/[id]/versions/[versionId]/restore/route.ts +152 -0
- package/src/modules/documents/api/[id]/versions/[versionId]/route.ts +100 -0
- package/src/modules/documents/api/[id]/versions/route.ts +207 -0
- package/src/modules/documents/api/[id]/watch/route.ts +111 -0
- package/src/modules/documents/api/_commands.ts +53 -0
- package/src/modules/documents/api/_shared.ts +676 -0
- package/src/modules/documents/api/folders/route.ts +287 -0
- package/src/modules/documents/api/instantiate/route.ts +114 -0
- package/src/modules/documents/api/route.ts +362 -0
- package/src/modules/documents/api/templates/[templateId]/preview/route.ts +97 -0
- package/src/modules/documents/api/templates/[templateId]/route.ts +92 -0
- package/src/modules/documents/api/templates/route.ts +370 -0
- package/src/modules/documents/backend/documents/DocumentsPageClient.tsx +150 -0
- package/src/modules/documents/backend/documents/DocumentsTable.tsx +168 -0
- package/src/modules/documents/backend/documents/FolderDialog.tsx +62 -0
- package/src/modules/documents/backend/documents/FolderTree.tsx +72 -0
- package/src/modules/documents/backend/documents/MoveDocumentDialog.tsx +70 -0
- package/src/modules/documents/backend/documents/[id]/CommentAnchorNavigation.ts +88 -0
- package/src/modules/documents/backend/documents/[id]/CommentComposer.tsx +136 -0
- package/src/modules/documents/backend/documents/[id]/CommentThreadList.tsx +131 -0
- package/src/modules/documents/backend/documents/[id]/CommentsRail.tsx +138 -0
- package/src/modules/documents/backend/documents/[id]/DocumentCanvas.tsx +111 -0
- package/src/modules/documents/backend/documents/[id]/DocumentEditorErrorBoundary.tsx +39 -0
- package/src/modules/documents/backend/documents/[id]/DocumentEditorIsland.tsx +50 -0
- package/src/modules/documents/backend/documents/[id]/DocumentEditorSurface.tsx +162 -0
- package/src/modules/documents/backend/documents/[id]/DocumentNavigator.tsx +129 -0
- package/src/modules/documents/backend/documents/[id]/DocumentPageClient.tsx +463 -0
- package/src/modules/documents/backend/documents/[id]/EditorColorTools.tsx +71 -0
- package/src/modules/documents/backend/documents/[id]/EditorStatusPresence.tsx +78 -0
- package/src/modules/documents/backend/documents/[id]/EditorToolbar.tsx +108 -0
- package/src/modules/documents/backend/documents/[id]/ExportMenu.tsx +144 -0
- package/src/modules/documents/backend/documents/[id]/MentionPicker.tsx +137 -0
- package/src/modules/documents/backend/documents/[id]/OutlinePane.tsx +98 -0
- package/src/modules/documents/backend/documents/[id]/RecordFieldsDialog.tsx +185 -0
- package/src/modules/documents/backend/documents/[id]/RelatedRecordsPanel.tsx +320 -0
- package/src/modules/documents/backend/documents/[id]/VersionHistoryPanel.tsx +244 -0
- package/src/modules/documents/backend/documents/[id]/VersionPreviewDialog.tsx +197 -0
- package/src/modules/documents/backend/documents/[id]/commentTypes.ts +192 -0
- package/src/modules/documents/backend/documents/[id]/componentCapabilities.ts +17 -0
- package/src/modules/documents/backend/documents/[id]/documentPagination.ts +352 -0
- package/src/modules/documents/backend/documents/[id]/editorPresenceStyles.ts +77 -0
- package/src/modules/documents/backend/documents/[id]/editorTypes.ts +84 -0
- package/src/modules/documents/backend/documents/[id]/page.meta.ts +12 -0
- package/src/modules/documents/backend/documents/[id]/page.tsx +6 -0
- package/src/modules/documents/backend/documents/[id]/relatedRecordModel.ts +49 -0
- package/src/modules/documents/backend/documents/[id]/restoreVersion.ts +49 -0
- package/src/modules/documents/backend/documents/[id]/useDocumentCollaboration.ts +458 -0
- package/src/modules/documents/backend/documents/[id]/useDocumentComments.ts +286 -0
- package/src/modules/documents/backend/documents/[id]/useDocumentEditor.ts +157 -0
- package/src/modules/documents/backend/documents/[id]/useDocumentTitle.ts +77 -0
- package/src/modules/documents/backend/documents/[id]/useEditorInsertions.ts +147 -0
- package/src/modules/documents/backend/documents/[id]/useFallbackContentPersistence.ts +277 -0
- package/src/modules/documents/backend/documents/[id]/useMentionPicker.ts +259 -0
- package/src/modules/documents/backend/documents/[id]/versionHistoryModel.ts +29 -0
- package/src/modules/documents/backend/documents/components/EntityPicker.tsx +171 -0
- package/src/modules/documents/backend/documents/components/EntityPickerResults.tsx +64 -0
- package/src/modules/documents/backend/documents/components/NewFromTemplateDialog.tsx +136 -0
- package/src/modules/documents/backend/documents/components/PrincipalPicker.tsx +90 -0
- package/src/modules/documents/backend/documents/components/ShareDialog.tsx +88 -0
- package/src/modules/documents/backend/documents/components/ShareDialogAddForm.tsx +113 -0
- package/src/modules/documents/backend/documents/components/ShareDialogList.tsx +117 -0
- package/src/modules/documents/backend/documents/components/TemplateBodyEditor.tsx +96 -0
- package/src/modules/documents/backend/documents/components/TemplateEditorDialog.tsx +171 -0
- package/src/modules/documents/backend/documents/components/TemplatePreview.tsx +43 -0
- package/src/modules/documents/backend/documents/components/TemplateSlotFields.tsx +72 -0
- package/src/modules/documents/backend/documents/components/TemplateSlotsEditor.tsx +72 -0
- package/src/modules/documents/backend/documents/components/principalPickerModel.ts +86 -0
- package/src/modules/documents/backend/documents/components/shareDialogModel.ts +94 -0
- package/src/modules/documents/backend/documents/components/templateUi.ts +128 -0
- package/src/modules/documents/backend/documents/components/useAvailableEntityRegistry.ts +43 -0
- package/src/modules/documents/backend/documents/components/useEntitySearch.ts +197 -0
- package/src/modules/documents/backend/documents/components/usePrincipalPicker.ts +165 -0
- package/src/modules/documents/backend/documents/components/useShareDialog.ts +267 -0
- package/src/modules/documents/backend/documents/components/useTemplateDetail.ts +54 -0
- package/src/modules/documents/backend/documents/components/useTemplateInstantiation.ts +252 -0
- package/src/modules/documents/backend/documents/documentUi.ts +134 -0
- package/src/modules/documents/backend/documents/documentsListTypes.ts +163 -0
- package/src/modules/documents/backend/documents/page.meta.ts +24 -0
- package/src/modules/documents/backend/documents/page.tsx +5 -0
- package/src/modules/documents/backend/documents/templates/TemplatesPageClient.tsx +93 -0
- package/src/modules/documents/backend/documents/templates/TemplatesTable.tsx +71 -0
- package/src/modules/documents/backend/documents/templates/page.meta.ts +32 -0
- package/src/modules/documents/backend/documents/templates/page.tsx +5 -0
- package/src/modules/documents/backend/documents/templates/useTemplatesPage.tsx +148 -0
- package/src/modules/documents/backend/documents/useDocumentsList.tsx +305 -0
- package/src/modules/documents/ce.ts +6 -0
- package/src/modules/documents/commands/aggregate.ts +128 -0
- package/src/modules/documents/commands/attachments.ts +309 -0
- package/src/modules/documents/commands/comments.ts +966 -0
- package/src/modules/documents/commands/content.ts +294 -0
- package/src/modules/documents/commands/document-crud.ts +609 -0
- package/src/modules/documents/commands/documents.ts +581 -0
- package/src/modules/documents/commands/duplicate.ts +772 -0
- package/src/modules/documents/commands/favorites.ts +171 -0
- package/src/modules/documents/commands/folders.ts +506 -0
- package/src/modules/documents/commands/index.ts +33 -0
- package/src/modules/documents/commands/interceptors.ts +402 -0
- package/src/modules/documents/commands/lifecycle.ts +333 -0
- package/src/modules/documents/commands/links.ts +486 -0
- package/src/modules/documents/commands/mutation-helpers.ts +48 -0
- package/src/modules/documents/commands/projection-types.ts +77 -0
- package/src/modules/documents/commands/shared.ts +219 -0
- package/src/modules/documents/commands/shares.ts +612 -0
- package/src/modules/documents/commands/side-effects.ts +130 -0
- package/src/modules/documents/commands/templates.ts +522 -0
- package/src/modules/documents/commands/versions.ts +537 -0
- package/src/modules/documents/commands/watchers.ts +181 -0
- package/src/modules/documents/data/entities.ts +631 -0
- package/src/modules/documents/data/extensions.ts +42 -0
- package/src/modules/documents/data/validators.ts +248 -0
- package/src/modules/documents/di.ts +33 -0
- package/src/modules/documents/encryption.ts +14 -0
- package/src/modules/documents/events.ts +23 -0
- package/src/modules/documents/i18n/.hardcoded-allowlist.json +9 -0
- package/src/modules/documents/i18n/de.json +522 -0
- package/src/modules/documents/i18n/en.json +522 -0
- package/src/modules/documents/i18n/es.json +522 -0
- package/src/modules/documents/i18n/ko.json +522 -0
- package/src/modules/documents/i18n/pl.json +522 -0
- package/src/modules/documents/index.ts +17 -0
- package/src/modules/documents/lib/attachmentServicePort.ts +94 -0
- package/src/modules/documents/lib/capabilities.ts +57 -0
- package/src/modules/documents/lib/collabCloseEvents.ts +26 -0
- package/src/modules/documents/lib/collabEndpoint.ts +43 -0
- package/src/modules/documents/lib/collabMaterializer.ts +140 -0
- package/src/modules/documents/lib/collabToken.ts +170 -0
- package/src/modules/documents/lib/collaborationAwareness.ts +102 -0
- package/src/modules/documents/lib/commentAnchors.ts +19 -0
- package/src/modules/documents/lib/constants.ts +39 -0
- package/src/modules/documents/lib/contentService.ts +340 -0
- package/src/modules/documents/lib/displayLabels.ts +31 -0
- package/src/modules/documents/lib/docxRenderer.ts +685 -0
- package/src/modules/documents/lib/duplicateContent.ts +32 -0
- package/src/modules/documents/lib/editorConfig.ts +371 -0
- package/src/modules/documents/lib/entityLinks.ts +250 -0
- package/src/modules/documents/lib/entityRegistry.server.ts +267 -0
- package/src/modules/documents/lib/entityRegistry.ts +345 -0
- package/src/modules/documents/lib/entityRegistryAvailability.server.ts +19 -0
- package/src/modules/documents/lib/entitySuggestion.ts +61 -0
- package/src/modules/documents/lib/favorites.ts +35 -0
- package/src/modules/documents/lib/folderHierarchySerialization.ts +34 -0
- package/src/modules/documents/lib/historyLimits.ts +154 -0
- package/src/modules/documents/lib/historyPolicy.ts +7 -0
- package/src/modules/documents/lib/organizationAccess.ts +44 -0
- package/src/modules/documents/lib/pdfHtml.ts +65 -0
- package/src/modules/documents/lib/pdfRenderer.ts +367 -0
- package/src/modules/documents/lib/permissions.ts +299 -0
- package/src/modules/documents/lib/platformServices.ts +70 -0
- package/src/modules/documents/lib/recordFieldInsertion.ts +72 -0
- package/src/modules/documents/lib/requestBody.ts +97 -0
- package/src/modules/documents/lib/resourceLimits.ts +94 -0
- package/src/modules/documents/lib/shareCounts.ts +44 -0
- package/src/modules/documents/lib/templateFill.ts +138 -0
- package/src/modules/documents/lib/templateInstantiation.ts +206 -0
- package/src/modules/documents/lib/templatePreviewDigest.ts +122 -0
- package/src/modules/documents/lib/templateSeeds.ts +248 -0
- package/src/modules/documents/lib/userLabels.ts +58 -0
- package/src/modules/documents/lib/versionContent.ts +163 -0
- package/src/modules/documents/lib/versionLabels.ts +9 -0
- package/src/modules/documents/lib/versioning.ts +29 -0
- package/src/modules/documents/lib/visibility.ts +610 -0
- package/src/modules/documents/lib/watchers.ts +129 -0
- package/src/modules/documents/migrations/.snapshot-open-mercato.json +2892 -0
- package/src/modules/documents/migrations/Migration20260708163836_documents.ts +50 -0
- package/src/modules/documents/migrations/Migration20260709164720_documents.ts +19 -0
- package/src/modules/documents/migrations/Migration20260710002318_documents.ts +35 -0
- package/src/modules/documents/migrations/Migration20260710071003_documents.ts +13 -0
- package/src/modules/documents/migrations/Migration20260712120000_documents.ts +13 -0
- package/src/modules/documents/migrations/Migration20260712183000_documents.ts +12 -0
- package/src/modules/documents/migrations/Migration20260713092156_documents.ts +43 -0
- package/src/modules/documents/migrations/Migration20260717000000_documents.ts +40 -0
- package/src/modules/documents/notifications.ts +45 -0
- package/src/modules/documents/search.ts +118 -0
- package/src/modules/documents/setup.ts +19 -0
- package/src/modules/documents/widgets/injection/related-documents/LinkDocumentDialog.tsx +224 -0
- package/src/modules/documents/widgets/injection/related-documents/context.ts +101 -0
- package/src/modules/documents/widgets/injection/related-documents/useRelatedDocuments.ts +112 -0
- package/src/modules/documents/widgets/injection/related-documents/widget.client.tsx +76 -0
- package/src/modules/documents/widgets/injection/related-documents/widget.ts +19 -0
- package/src/modules/documents/widgets/injection-table.ts +20 -0
- package/tsconfig.json +9 -0
- package/watch.mjs +6 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/documents/lib/entityLinks.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { DocumentEntityLink } from '../data/entities'\nimport type {\n DocumentEntityLinkCreateInput,\n DocumentEntityType,\n} from '../data/validators'\nimport { sanitizeDocumentsDisplayLabel } from './displayLabels'\nimport { getEntityTokenFieldNames } from './entityRegistry'\nimport { DOCUMENTS_MAX_ENTITY_LINKS_PER_DOCUMENT } from './resourceLimits'\n\nexport type DocumentEntityLinkScope = {\n tenantId: string\n organizationId: string\n}\n\nexport type DocumentEntityLinkCanonicalTarget = {\n id: string\n label: string\n href: string\n values?: Record<string, string | null>\n}\n\ntype LinkTargetFields = Pick<\n DocumentEntityLink,\n | 'customerEntityId'\n | 'customerKind'\n | 'dealId'\n | 'productId'\n | 'catalogOfferId'\n | 'quoteId'\n | 'salesOrderId'\n | 'linkedDocumentId'\n>\n\nexport type DocumentEntityLinkCreateData = LinkTargetFields & {\n id: string\n documentId: string\n tenantId: string\n organizationId: string\n labelSnapshot: string\n hrefSnapshot: string\n source: DocumentEntityLinkCreateInput['source']\n createdByUserId: string\n}\n\nconst EMPTY_TARGET: LinkTargetFields = {\n customerEntityId: null,\n customerKind: null,\n dealId: null,\n productId: null,\n catalogOfferId: null,\n quoteId: null,\n salesOrderId: null,\n linkedDocumentId: null,\n}\n\nfunction sanitizeDocumentEntityValue(value: unknown): string | null {\n const label = sanitizeDocumentsDisplayLabel(value)\n return label && label.length <= 10_000 ? label : null\n}\n\nexport function buildDocumentEntityLinkTarget(\n entityType: DocumentEntityType,\n entityId: string,\n): LinkTargetFields {\n const target = { ...EMPTY_TARGET }\n if (entityType === 'customer-person' || entityType === 'customer-company') {\n target.customerEntityId = entityId\n target.customerKind = entityType === 'customer-person' ? 'person' : 'company'\n } else if (entityType === 'deal') {\n target.dealId = entityId\n } else if (entityType === 'product') {\n target.productId = entityId\n } else if (entityType === 'catalog-offer') {\n target.catalogOfferId = entityId\n } else if (entityType === 'quote') {\n target.quoteId = entityId\n } else if (entityType === 'document') {\n target.linkedDocumentId = entityId\n } else {\n target.salesOrderId = entityId\n }\n return target\n}\n\nexport function buildDocumentEntityLinkTargetWhere(\n entityType: DocumentEntityType,\n entityId: string,\n): LinkTargetFields {\n return buildDocumentEntityLinkTarget(entityType, entityId)\n}\n\nexport function getDocumentEntityLinkType(link: DocumentEntityLink): DocumentEntityType {\n if (link.customerEntityId) {\n return link.customerKind === 'company' ? 'customer-company' : 'customer-person'\n }\n if (link.dealId) return 'deal'\n if (link.productId) return 'product'\n if (link.catalogOfferId) return 'catalog-offer'\n if (link.quoteId) return 'quote'\n if (link.linkedDocumentId) return 'document'\n return 'sales-order'\n}\n\nexport function getDocumentEntityLinkEntityId(link: DocumentEntityLink): string {\n return link.customerEntityId\n ?? link.dealId\n ?? link.productId\n ?? link.catalogOfferId\n ?? link.quoteId\n ?? link.linkedDocumentId\n ?? link.salesOrderId\n ?? ''\n}\n\nexport function createDocumentEntityLinkData(input: {\n id: string\n documentId: string\n scope: DocumentEntityLinkScope\n actorUserId: string\n link: DocumentEntityLinkCreateInput\n}): DocumentEntityLinkCreateData {\n const labelSnapshot = sanitizeDocumentsDisplayLabel(input.link.label)\n if (!labelSnapshot) {\n throw new Error('[internal] document entity link label crossed persistence without a readable label')\n }\n return {\n id: input.id,\n documentId: input.documentId,\n tenantId: input.scope.tenantId,\n organizationId: input.scope.organizationId,\n labelSnapshot,\n hrefSnapshot: input.link.href,\n source: input.link.source,\n createdByUserId: input.actorUserId,\n ...buildDocumentEntityLinkTarget(input.link.entityType, input.link.entityId),\n }\n}\n\nexport async function findDocumentEntityLinks(\n em: EntityManager,\n documentId: string,\n scope: DocumentEntityLinkScope,\n options: { withDeleted?: boolean } = {},\n): Promise<DocumentEntityLink[]> {\n const links = await findWithDecryption(\n em,\n DocumentEntityLink,\n {\n documentId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n ...(options.withDeleted ? {} : { deletedAt: null }),\n },\n options.withDeleted\n ? { orderBy: { createdAt: 'ASC' } }\n : {\n orderBy: { createdAt: 'ASC' },\n limit: DOCUMENTS_MAX_ENTITY_LINKS_PER_DOCUMENT + 1,\n },\n scope,\n )\n if (!options.withDeleted) assertDocumentEntityLinkListWithinLimit(links)\n return links\n}\n\nexport function assertDocumentEntityLinkListWithinLimit(\n links: readonly DocumentEntityLink[],\n): void {\n if (links.length <= DOCUMENTS_MAX_ENTITY_LINKS_PER_DOCUMENT) return\n throw new CrudHttpError(413, { error: 'documents.links.limitExceeded' })\n}\n\n/** Call only while holding the document aggregate lock. */\nexport async function assertDocumentEntityLinkCapacity(\n em: EntityManager,\n documentId: string,\n scope: DocumentEntityLinkScope,\n): Promise<void> {\n const activeCount = await em.count(DocumentEntityLink, {\n documentId,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n })\n if (activeCount < DOCUMENTS_MAX_ENTITY_LINKS_PER_DOCUMENT) return\n throw new CrudHttpError(413, { error: 'documents.links.limitExceeded' })\n}\n\nexport function serializeDocumentEntityLink(\n link: DocumentEntityLink,\n options: {\n canOpen: boolean\n restrictedLabel: string\n canonicalTarget?: DocumentEntityLinkCanonicalTarget\n },\n): {\n id: string\n entityType: DocumentEntityType\n entityId: string | null\n label: string\n href: string | null\n canOpen: boolean\n source: string\n createdAt: string\n updatedAt: string\n values?: Record<string, string | null>\n} {\n const entityType = getDocumentEntityLinkType(link)\n const restrictedLabel = sanitizeDocumentsDisplayLabel(options.restrictedLabel)\n const canonicalLabel = options.canonicalTarget\n ? sanitizeDocumentsDisplayLabel(options.canonicalTarget.label)\n : null\n const snapshotLabel = sanitizeDocumentsDisplayLabel(link.labelSnapshot)\n const canOpen = options.canOpen && (\n options.canonicalTarget ? Boolean(canonicalLabel) : Boolean(snapshotLabel)\n )\n const readableLabel = canOpen ? canonicalLabel ?? snapshotLabel : restrictedLabel\n if (!readableLabel) {\n throw new Error('[internal] document entity link serialization requires a readable fallback label')\n }\n const allowedValueFields = getEntityTokenFieldNames(entityType)\n const values = options.canonicalTarget?.values\n ? Object.fromEntries(Array.from(allowedValueFields, (field) => [\n field,\n sanitizeDocumentEntityValue(options.canonicalTarget?.values?.[field]),\n ]))\n : null\n const hasReadableValues = values\n ? Object.values(values).some((value) => value !== null)\n : false\n return {\n id: link.id,\n entityType,\n entityId: canOpen\n ? options.canonicalTarget?.id ?? getDocumentEntityLinkEntityId(link)\n : null,\n label: canOpen ? readableLabel : restrictedLabel ?? readableLabel,\n href: canOpen\n ? options.canonicalTarget?.href ?? link.hrefSnapshot\n : null,\n canOpen,\n source: link.source,\n createdAt: link.createdAt.toISOString(),\n updatedAt: link.updatedAt.toISOString(),\n ...(canOpen && hasReadableValues && values ? { values } : {}),\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import {
|
|
2
|
+
firstSafeDocumentsDisplayLabel,
|
|
3
|
+
sanitizeDocumentsDisplayLabel
|
|
4
|
+
} from "./displayLabels.js";
|
|
5
|
+
function readRecord(value) {
|
|
6
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7
|
+
}
|
|
8
|
+
function readString(item, ...keys) {
|
|
9
|
+
for (const key of keys) {
|
|
10
|
+
const value = item[key];
|
|
11
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
function readDisplayString(item, ...keys) {
|
|
16
|
+
return firstSafeDocumentsDisplayLabel(...keys.map((key) => item[key]));
|
|
17
|
+
}
|
|
18
|
+
function readNestedString(item, parentKey, ...keys) {
|
|
19
|
+
const parent = readRecord(item[parentKey]);
|
|
20
|
+
return parent ? readString(parent, ...keys) : null;
|
|
21
|
+
}
|
|
22
|
+
function readNestedDisplayString(item, parentKey, ...keys) {
|
|
23
|
+
const parent = readRecord(item[parentKey]);
|
|
24
|
+
return parent ? readDisplayString(parent, ...keys) : null;
|
|
25
|
+
}
|
|
26
|
+
function readDisplayTextValue(item, ...keys) {
|
|
27
|
+
for (const key of keys) {
|
|
28
|
+
const value = item[key];
|
|
29
|
+
const safe = typeof value === "number" && Number.isFinite(value) ? sanitizeDocumentsDisplayLabel(String(value)) : sanitizeDocumentsDisplayLabel(value);
|
|
30
|
+
if (safe) return safe;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function optionalSubtitle(value) {
|
|
35
|
+
return value ?? void 0;
|
|
36
|
+
}
|
|
37
|
+
function mapCustomerItem(item) {
|
|
38
|
+
const id = readString(item, "id");
|
|
39
|
+
const email = readDisplayString(item, "email", "primaryEmail", "primary_email");
|
|
40
|
+
const label = readDisplayString(item, "name", "displayName", "display_name") ?? email;
|
|
41
|
+
if (!id || !label) return null;
|
|
42
|
+
return { id, label, subtitle: optionalSubtitle(email) };
|
|
43
|
+
}
|
|
44
|
+
function mapDealItem(item) {
|
|
45
|
+
const id = readString(item, "id");
|
|
46
|
+
const label = readDisplayString(item, "title");
|
|
47
|
+
if (!id || !label) return null;
|
|
48
|
+
return { id, label, subtitle: optionalSubtitle(readDisplayString(item, "status")) };
|
|
49
|
+
}
|
|
50
|
+
function mapProductItem(item) {
|
|
51
|
+
const id = readString(item, "id");
|
|
52
|
+
const label = readDisplayString(item, "title");
|
|
53
|
+
if (!id || !label) return null;
|
|
54
|
+
return { id, label, subtitle: optionalSubtitle(readDisplayString(item, "sku")) };
|
|
55
|
+
}
|
|
56
|
+
function mapCatalogOfferItem(item) {
|
|
57
|
+
const id = readString(item, "id");
|
|
58
|
+
const productId = readString(item, "productId", "product_id") ?? readNestedString(item, "product", "id");
|
|
59
|
+
const productTitle = readNestedDisplayString(item, "product", "title", "name");
|
|
60
|
+
const label = readDisplayString(item, "title", "name") ?? productTitle;
|
|
61
|
+
if (!id || !productId || !label) return null;
|
|
62
|
+
const productSku = readNestedDisplayString(item, "product", "sku");
|
|
63
|
+
return {
|
|
64
|
+
id,
|
|
65
|
+
label,
|
|
66
|
+
subtitle: optionalSubtitle(productTitle ?? productSku),
|
|
67
|
+
href: `/backend/catalog/products/${productId}`
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function mapSalesDocumentItem(item, numberKeys) {
|
|
71
|
+
const id = readString(item, "id");
|
|
72
|
+
const label = readDisplayString(item, ...numberKeys, "number", "title");
|
|
73
|
+
if (!id || !label) return null;
|
|
74
|
+
return { id, label, subtitle: optionalSubtitle(readDisplayString(item, "status")) };
|
|
75
|
+
}
|
|
76
|
+
function mapDocumentItem(item) {
|
|
77
|
+
const id = readString(item, "id");
|
|
78
|
+
const label = readDisplayString(item, "title");
|
|
79
|
+
if (!id || !label) return null;
|
|
80
|
+
const archivedAt = item.archivedAt ?? item.archived_at;
|
|
81
|
+
return {
|
|
82
|
+
id,
|
|
83
|
+
label,
|
|
84
|
+
archivedAt: typeof archivedAt === "string" && archivedAt.length > 0 ? archivedAt : null
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function field(fieldName, labelKey, keys) {
|
|
88
|
+
return {
|
|
89
|
+
field: fieldName,
|
|
90
|
+
labelKey,
|
|
91
|
+
extract: (item) => readDisplayTextValue(item, ...keys)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function exactIdPath(pathPrefix, id) {
|
|
95
|
+
return `${pathPrefix}/${id}`;
|
|
96
|
+
}
|
|
97
|
+
const CATALOG_PRODUCT_HREF_PATTERN = /^\/backend\/catalog\/products\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
98
|
+
function buildIdAddressableEntry(input) {
|
|
99
|
+
return {
|
|
100
|
+
...input,
|
|
101
|
+
resolveHref: (item) => input.href(item.id),
|
|
102
|
+
isCanonicalHref: (item, href) => href === input.href(item.id)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function readItemsArray(response) {
|
|
106
|
+
if (Array.isArray(response)) {
|
|
107
|
+
return response.map(readRecord).filter((item) => item !== null);
|
|
108
|
+
}
|
|
109
|
+
const record = readRecord(response);
|
|
110
|
+
const candidates = [record?.items, record?.data];
|
|
111
|
+
for (const candidate of candidates) {
|
|
112
|
+
if (Array.isArray(candidate)) {
|
|
113
|
+
return candidate.map(readRecord).filter((item) => item !== null);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const DOCUMENT_ENTITY_REGISTRY = [
|
|
119
|
+
buildIdAddressableEntry({
|
|
120
|
+
type: "customer-person",
|
|
121
|
+
labelKey: "documents.entities.customerPerson",
|
|
122
|
+
searchPath: "/api/customers/people",
|
|
123
|
+
mapItem: mapCustomerItem,
|
|
124
|
+
href: (id) => exactIdPath("/backend/customers/people", id),
|
|
125
|
+
requiredModule: "customers",
|
|
126
|
+
requiredFeatureModule: "customers",
|
|
127
|
+
requiredFeature: "customers.people.view",
|
|
128
|
+
tokenFields: [
|
|
129
|
+
field("name", "documents.entityFields.name", ["name", "displayName", "display_name"]),
|
|
130
|
+
field("email", "documents.entityFields.email", ["email", "primaryEmail", "primary_email"]),
|
|
131
|
+
field("phone", "documents.entityFields.phone", ["phone", "primaryPhone", "primary_phone"])
|
|
132
|
+
]
|
|
133
|
+
}),
|
|
134
|
+
buildIdAddressableEntry({
|
|
135
|
+
type: "customer-company",
|
|
136
|
+
labelKey: "documents.entities.customerCompany",
|
|
137
|
+
searchPath: "/api/customers/companies",
|
|
138
|
+
mapItem: mapCustomerItem,
|
|
139
|
+
href: (id) => exactIdPath("/backend/customers/companies", id),
|
|
140
|
+
requiredModule: "customers",
|
|
141
|
+
requiredFeatureModule: "customers",
|
|
142
|
+
requiredFeature: "customers.companies.view",
|
|
143
|
+
tokenFields: [
|
|
144
|
+
field("name", "documents.entityFields.name", ["name", "displayName", "display_name"]),
|
|
145
|
+
field("email", "documents.entityFields.email", ["email", "primaryEmail", "primary_email"]),
|
|
146
|
+
field("phone", "documents.entityFields.phone", ["phone", "primaryPhone", "primary_phone"])
|
|
147
|
+
]
|
|
148
|
+
}),
|
|
149
|
+
buildIdAddressableEntry({
|
|
150
|
+
type: "deal",
|
|
151
|
+
labelKey: "documents.entities.deal",
|
|
152
|
+
searchPath: "/api/customers/deals",
|
|
153
|
+
mapItem: mapDealItem,
|
|
154
|
+
href: (id) => exactIdPath("/backend/customers/deals", id),
|
|
155
|
+
requiredModule: "customers",
|
|
156
|
+
requiredFeatureModule: "customers",
|
|
157
|
+
requiredFeature: "customers.deals.view",
|
|
158
|
+
tokenFields: [
|
|
159
|
+
field("title", "documents.entityFields.title", ["title"]),
|
|
160
|
+
field("status", "documents.entityFields.status", ["status"]),
|
|
161
|
+
field("value", "documents.entityFields.value", ["value", "valueAmount", "value_amount"]),
|
|
162
|
+
field("valueCurrency", "documents.entityFields.valueCurrency", ["valueCurrency", "value_currency"])
|
|
163
|
+
]
|
|
164
|
+
}),
|
|
165
|
+
buildIdAddressableEntry({
|
|
166
|
+
type: "product",
|
|
167
|
+
labelKey: "documents.entities.product",
|
|
168
|
+
searchPath: "/api/catalog/products",
|
|
169
|
+
mapItem: mapProductItem,
|
|
170
|
+
href: (id) => exactIdPath("/backend/catalog/products", id),
|
|
171
|
+
requiredModule: "catalog",
|
|
172
|
+
requiredFeatureModule: "catalog",
|
|
173
|
+
requiredFeature: "catalog.products.view",
|
|
174
|
+
tokenFields: [
|
|
175
|
+
field("title", "documents.entityFields.title", ["title"]),
|
|
176
|
+
field("subtitle", "documents.entityFields.subtitle", ["subtitle"]),
|
|
177
|
+
field("sku", "documents.entityFields.sku", ["sku"])
|
|
178
|
+
]
|
|
179
|
+
}),
|
|
180
|
+
{
|
|
181
|
+
type: "catalog-offer",
|
|
182
|
+
labelKey: "documents.entities.catalogOffer",
|
|
183
|
+
searchPath: "/api/catalog/offers",
|
|
184
|
+
mapItem: mapCatalogOfferItem,
|
|
185
|
+
href: () => "",
|
|
186
|
+
resolveHref: (item) => {
|
|
187
|
+
const href = item.href ?? null;
|
|
188
|
+
return href && CATALOG_PRODUCT_HREF_PATTERN.test(href) ? href : null;
|
|
189
|
+
},
|
|
190
|
+
isCanonicalHref: (item, href) => Boolean(item.href && href === item.href && CATALOG_PRODUCT_HREF_PATTERN.test(href)),
|
|
191
|
+
requiredModule: "catalog",
|
|
192
|
+
requiredFeatureModule: "sales",
|
|
193
|
+
requiredFeature: "sales.channels.manage",
|
|
194
|
+
tokenFields: [
|
|
195
|
+
field("title", "documents.entityFields.title", ["title", "name"]),
|
|
196
|
+
field("description", "documents.entityFields.description", ["description"])
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
buildIdAddressableEntry({
|
|
200
|
+
type: "quote",
|
|
201
|
+
labelKey: "documents.entities.quote",
|
|
202
|
+
searchPath: "/api/sales/quotes",
|
|
203
|
+
mapItem: (item) => mapSalesDocumentItem(item, ["quoteNumber", "quote_number"]),
|
|
204
|
+
href: (id) => exactIdPath("/backend/sales/quotes", id),
|
|
205
|
+
requiredModule: "sales",
|
|
206
|
+
requiredFeatureModule: "sales",
|
|
207
|
+
requiredFeature: "sales.quotes.view",
|
|
208
|
+
tokenFields: [
|
|
209
|
+
field("number", "documents.entityFields.number", ["quoteNumber", "quote_number", "number"]),
|
|
210
|
+
field("status", "documents.entityFields.status", ["status"]),
|
|
211
|
+
field("total", "documents.entityFields.total", ["grandTotalGross", "grand_total_gross", "total"]),
|
|
212
|
+
field("currency", "documents.entityFields.currency", ["currencyCode", "currency_code"])
|
|
213
|
+
]
|
|
214
|
+
}),
|
|
215
|
+
buildIdAddressableEntry({
|
|
216
|
+
type: "sales-order",
|
|
217
|
+
labelKey: "documents.entities.salesOrder",
|
|
218
|
+
searchPath: "/api/sales/orders",
|
|
219
|
+
mapItem: (item) => mapSalesDocumentItem(item, ["orderNumber", "order_number"]),
|
|
220
|
+
href: (id) => exactIdPath("/backend/sales/orders", id),
|
|
221
|
+
requiredModule: "sales",
|
|
222
|
+
requiredFeatureModule: "sales",
|
|
223
|
+
requiredFeature: "sales.orders.view",
|
|
224
|
+
tokenFields: [
|
|
225
|
+
field("number", "documents.entityFields.number", ["orderNumber", "order_number", "number"]),
|
|
226
|
+
field("status", "documents.entityFields.status", ["status"]),
|
|
227
|
+
field("total", "documents.entityFields.total", ["grandTotalGross", "grand_total_gross", "total"]),
|
|
228
|
+
field("currency", "documents.entityFields.currency", ["currencyCode", "currency_code"])
|
|
229
|
+
]
|
|
230
|
+
}),
|
|
231
|
+
buildIdAddressableEntry({
|
|
232
|
+
type: "document",
|
|
233
|
+
labelKey: "documents.entities.document",
|
|
234
|
+
searchPath: "/api/documents",
|
|
235
|
+
mapItem: mapDocumentItem,
|
|
236
|
+
href: (id) => exactIdPath("/backend/documents", id),
|
|
237
|
+
requiredModule: "documents",
|
|
238
|
+
requiredFeatureModule: "documents",
|
|
239
|
+
requiredFeature: "documents.view",
|
|
240
|
+
tokenFields: [
|
|
241
|
+
field("title", "documents.entityFields.title", ["title"])
|
|
242
|
+
]
|
|
243
|
+
})
|
|
244
|
+
];
|
|
245
|
+
function getEntityRegistryEntry(type) {
|
|
246
|
+
return DOCUMENT_ENTITY_REGISTRY.find((entry) => entry.type === type) ?? null;
|
|
247
|
+
}
|
|
248
|
+
function getEntityTokenFieldNames(type) {
|
|
249
|
+
const entry = getEntityRegistryEntry(type);
|
|
250
|
+
return new Set(entry?.tokenFields.map((tokenField) => tokenField.field) ?? []);
|
|
251
|
+
}
|
|
252
|
+
export {
|
|
253
|
+
DOCUMENT_ENTITY_REGISTRY,
|
|
254
|
+
getEntityRegistryEntry,
|
|
255
|
+
getEntityTokenFieldNames,
|
|
256
|
+
readItemsArray
|
|
257
|
+
};
|
|
258
|
+
//# sourceMappingURL=entityRegistry.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/documents/lib/entityRegistry.ts"],
|
|
4
|
+
"sourcesContent": ["import type { DocumentEntityType } from '../data/validators'\nimport {\n firstSafeDocumentsDisplayLabel,\n sanitizeDocumentsDisplayLabel,\n} from './displayLabels'\n\nexport type { DocumentEntityType } from '../data/validators'\n\nexport type EntityPickerItem = {\n id: string\n label: string\n subtitle?: string\n href?: string\n archivedAt?: string | null\n}\n\nexport type EntityTokenField = {\n field: string\n labelKey: string\n extract: (item: Record<string, unknown>) => string | null\n}\n\nexport type EntityRegistryEntry = {\n type: DocumentEntityType\n labelKey: string\n searchPath: string\n mapItem: (item: Record<string, unknown>) => EntityPickerItem | null\n href: (id: string) => string\n tokenFields: EntityTokenField[]\n}\n\n/**\n * Internal registry contract used by Documents integrations. Keep the\n * long-standing EntityRegistryEntry shape above assignable for deep-import\n * consumers while requiring every built-in entry to declare its capability\n * and canonical-link policy.\n */\nexport type DocumentEntityRegistryEntry = EntityRegistryEntry & {\n resolveHref: (item: EntityPickerItem) => string | null\n isCanonicalHref: (item: Pick<EntityPickerItem, 'id' | 'href'>, href: string) => boolean\n requiredModule: string\n /**\n * Module that owns `requiredFeature`. This is usually the same as\n * `requiredModule`, but catalog offers are rendered by Catalog while their\n * channel-access feature is owned by Sales. Keeping it explicit lets the\n * server and ClientBootstrap-backed picker make the same fail-closed choice.\n */\n requiredFeatureModule: string\n requiredFeature: string\n}\n\nfunction readRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? value as Record<string, unknown>\n : null\n}\n\nfunction readString(item: Record<string, unknown>, ...keys: string[]): string | null {\n for (const key of keys) {\n const value = item[key]\n if (typeof value === 'string' && value.trim().length > 0) return value.trim()\n }\n return null\n}\n\n/**\n * Cross-module records are an untrusted display boundary. Their identifiers\n * remain available to the registry for canonical routing, but a name, status,\n * SKU, or other rendered value must never fall back to an identifier-shaped\n * string. Continue through aliases so a malformed preferred field does not\n * hide a later readable value.\n */\nfunction readDisplayString(item: Record<string, unknown>, ...keys: string[]): string | null {\n return firstSafeDocumentsDisplayLabel(...keys.map((key) => item[key]))\n}\n\nfunction readNestedString(\n item: Record<string, unknown>,\n parentKey: string,\n ...keys: string[]\n): string | null {\n const parent = readRecord(item[parentKey])\n return parent ? readString(parent, ...keys) : null\n}\n\nfunction readNestedDisplayString(\n item: Record<string, unknown>,\n parentKey: string,\n ...keys: string[]\n): string | null {\n const parent = readRecord(item[parentKey])\n return parent ? readDisplayString(parent, ...keys) : null\n}\n\nfunction readDisplayTextValue(item: Record<string, unknown>, ...keys: string[]): string | null {\n for (const key of keys) {\n const value = item[key]\n const safe = typeof value === 'number' && Number.isFinite(value)\n ? sanitizeDocumentsDisplayLabel(String(value))\n : sanitizeDocumentsDisplayLabel(value)\n if (safe) return safe\n }\n return null\n}\n\nfunction optionalSubtitle(value: string | null): string | undefined {\n return value ?? undefined\n}\n\nfunction mapCustomerItem(item: Record<string, unknown>): EntityPickerItem | null {\n const id = readString(item, 'id')\n const email = readDisplayString(item, 'email', 'primaryEmail', 'primary_email')\n const label = readDisplayString(item, 'name', 'displayName', 'display_name') ?? email\n if (!id || !label) return null\n return { id, label, subtitle: optionalSubtitle(email) }\n}\n\nfunction mapDealItem(item: Record<string, unknown>): EntityPickerItem | null {\n const id = readString(item, 'id')\n const label = readDisplayString(item, 'title')\n if (!id || !label) return null\n return { id, label, subtitle: optionalSubtitle(readDisplayString(item, 'status')) }\n}\n\nfunction mapProductItem(item: Record<string, unknown>): EntityPickerItem | null {\n const id = readString(item, 'id')\n const label = readDisplayString(item, 'title')\n if (!id || !label) return null\n return { id, label, subtitle: optionalSubtitle(readDisplayString(item, 'sku')) }\n}\n\nfunction mapCatalogOfferItem(item: Record<string, unknown>): EntityPickerItem | null {\n const id = readString(item, 'id')\n const productId = readString(item, 'productId', 'product_id')\n ?? readNestedString(item, 'product', 'id')\n const productTitle = readNestedDisplayString(item, 'product', 'title', 'name')\n const label = readDisplayString(item, 'title', 'name') ?? productTitle\n if (!id || !productId || !label) return null\n const productSku = readNestedDisplayString(item, 'product', 'sku')\n return {\n id,\n label,\n subtitle: optionalSubtitle(productTitle ?? productSku),\n href: `/backend/catalog/products/${productId}`,\n }\n}\n\nfunction mapSalesDocumentItem(\n item: Record<string, unknown>,\n numberKeys: string[],\n): EntityPickerItem | null {\n const id = readString(item, 'id')\n const label = readDisplayString(item, ...numberKeys, 'number', 'title')\n if (!id || !label) return null\n return { id, label, subtitle: optionalSubtitle(readDisplayString(item, 'status')) }\n}\n\nfunction mapDocumentItem(item: Record<string, unknown>): EntityPickerItem | null {\n const id = readString(item, 'id')\n const label = readDisplayString(item, 'title')\n if (!id || !label) return null\n const archivedAt = item.archivedAt ?? item.archived_at\n return {\n id,\n label,\n archivedAt: typeof archivedAt === 'string' && archivedAt.length > 0 ? archivedAt : null,\n }\n}\n\nfunction field(fieldName: string, labelKey: string, keys: string[]): EntityTokenField {\n return {\n field: fieldName,\n labelKey,\n extract: (item) => readDisplayTextValue(item, ...keys),\n }\n}\n\nfunction exactIdPath(pathPrefix: string, id: string): string {\n return `${pathPrefix}/${id}`\n}\n\nconst CATALOG_PRODUCT_HREF_PATTERN =\n /^\\/backend\\/catalog\\/products\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nfunction buildIdAddressableEntry(\n input: Omit<DocumentEntityRegistryEntry, 'resolveHref' | 'isCanonicalHref'>,\n): DocumentEntityRegistryEntry {\n return {\n ...input,\n resolveHref: (item) => input.href(item.id),\n isCanonicalHref: (item, href) => href === input.href(item.id),\n }\n}\n\nexport function readItemsArray(response: unknown): Record<string, unknown>[] {\n if (Array.isArray(response)) {\n return response.map(readRecord).filter((item): item is Record<string, unknown> => item !== null)\n }\n\n const record = readRecord(response)\n const candidates = [record?.items, record?.data]\n for (const candidate of candidates) {\n if (Array.isArray(candidate)) {\n return candidate.map(readRecord).filter((item): item is Record<string, unknown> => item !== null)\n }\n }\n return []\n}\n\nexport const DOCUMENT_ENTITY_REGISTRY: DocumentEntityRegistryEntry[] = [\n buildIdAddressableEntry({\n type: 'customer-person',\n labelKey: 'documents.entities.customerPerson',\n searchPath: '/api/customers/people',\n mapItem: mapCustomerItem,\n href: (id) => exactIdPath('/backend/customers/people', id),\n requiredModule: 'customers',\n requiredFeatureModule: 'customers',\n requiredFeature: 'customers.people.view',\n tokenFields: [\n field('name', 'documents.entityFields.name', ['name', 'displayName', 'display_name']),\n field('email', 'documents.entityFields.email', ['email', 'primaryEmail', 'primary_email']),\n field('phone', 'documents.entityFields.phone', ['phone', 'primaryPhone', 'primary_phone']),\n ],\n }),\n buildIdAddressableEntry({\n type: 'customer-company',\n labelKey: 'documents.entities.customerCompany',\n searchPath: '/api/customers/companies',\n mapItem: mapCustomerItem,\n href: (id) => exactIdPath('/backend/customers/companies', id),\n requiredModule: 'customers',\n requiredFeatureModule: 'customers',\n requiredFeature: 'customers.companies.view',\n tokenFields: [\n field('name', 'documents.entityFields.name', ['name', 'displayName', 'display_name']),\n field('email', 'documents.entityFields.email', ['email', 'primaryEmail', 'primary_email']),\n field('phone', 'documents.entityFields.phone', ['phone', 'primaryPhone', 'primary_phone']),\n ],\n }),\n buildIdAddressableEntry({\n type: 'deal',\n labelKey: 'documents.entities.deal',\n searchPath: '/api/customers/deals',\n mapItem: mapDealItem,\n href: (id) => exactIdPath('/backend/customers/deals', id),\n requiredModule: 'customers',\n requiredFeatureModule: 'customers',\n requiredFeature: 'customers.deals.view',\n tokenFields: [\n field('title', 'documents.entityFields.title', ['title']),\n field('status', 'documents.entityFields.status', ['status']),\n field('value', 'documents.entityFields.value', ['value', 'valueAmount', 'value_amount']),\n field('valueCurrency', 'documents.entityFields.valueCurrency', ['valueCurrency', 'value_currency']),\n ],\n }),\n buildIdAddressableEntry({\n type: 'product',\n labelKey: 'documents.entities.product',\n searchPath: '/api/catalog/products',\n mapItem: mapProductItem,\n href: (id) => exactIdPath('/backend/catalog/products', id),\n requiredModule: 'catalog',\n requiredFeatureModule: 'catalog',\n requiredFeature: 'catalog.products.view',\n tokenFields: [\n field('title', 'documents.entityFields.title', ['title']),\n field('subtitle', 'documents.entityFields.subtitle', ['subtitle']),\n field('sku', 'documents.entityFields.sku', ['sku']),\n ],\n }),\n {\n type: 'catalog-offer',\n labelKey: 'documents.entities.catalogOffer',\n searchPath: '/api/catalog/offers',\n mapItem: mapCatalogOfferItem,\n href: () => '',\n resolveHref: (item) => {\n const href = item.href ?? null\n return href && CATALOG_PRODUCT_HREF_PATTERN.test(href) ? href : null\n },\n isCanonicalHref: (item, href) => Boolean(item.href && href === item.href && CATALOG_PRODUCT_HREF_PATTERN.test(href)),\n requiredModule: 'catalog',\n requiredFeatureModule: 'sales',\n requiredFeature: 'sales.channels.manage',\n tokenFields: [\n field('title', 'documents.entityFields.title', ['title', 'name']),\n field('description', 'documents.entityFields.description', ['description']),\n ],\n },\n buildIdAddressableEntry({\n type: 'quote',\n labelKey: 'documents.entities.quote',\n searchPath: '/api/sales/quotes',\n mapItem: (item) => mapSalesDocumentItem(item, ['quoteNumber', 'quote_number']),\n href: (id) => exactIdPath('/backend/sales/quotes', id),\n requiredModule: 'sales',\n requiredFeatureModule: 'sales',\n requiredFeature: 'sales.quotes.view',\n tokenFields: [\n field('number', 'documents.entityFields.number', ['quoteNumber', 'quote_number', 'number']),\n field('status', 'documents.entityFields.status', ['status']),\n field('total', 'documents.entityFields.total', ['grandTotalGross', 'grand_total_gross', 'total']),\n field('currency', 'documents.entityFields.currency', ['currencyCode', 'currency_code']),\n ],\n }),\n buildIdAddressableEntry({\n type: 'sales-order',\n labelKey: 'documents.entities.salesOrder',\n searchPath: '/api/sales/orders',\n mapItem: (item) => mapSalesDocumentItem(item, ['orderNumber', 'order_number']),\n href: (id) => exactIdPath('/backend/sales/orders', id),\n requiredModule: 'sales',\n requiredFeatureModule: 'sales',\n requiredFeature: 'sales.orders.view',\n tokenFields: [\n field('number', 'documents.entityFields.number', ['orderNumber', 'order_number', 'number']),\n field('status', 'documents.entityFields.status', ['status']),\n field('total', 'documents.entityFields.total', ['grandTotalGross', 'grand_total_gross', 'total']),\n field('currency', 'documents.entityFields.currency', ['currencyCode', 'currency_code']),\n ],\n }),\n buildIdAddressableEntry({\n type: 'document',\n labelKey: 'documents.entities.document',\n searchPath: '/api/documents',\n mapItem: mapDocumentItem,\n href: (id) => exactIdPath('/backend/documents', id),\n requiredModule: 'documents',\n requiredFeatureModule: 'documents',\n requiredFeature: 'documents.view',\n tokenFields: [\n field('title', 'documents.entityFields.title', ['title']),\n ],\n }),\n]\n\nexport function getEntityRegistryEntry(type: string): DocumentEntityRegistryEntry | null {\n return DOCUMENT_ENTITY_REGISTRY.find((entry) => entry.type === type) ?? null\n}\n\nexport function getEntityTokenFieldNames(type: DocumentEntityType): Set<string> {\n const entry = getEntityRegistryEntry(type)\n return new Set(entry?.tokenFields.map((tokenField) => tokenField.field) ?? [])\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
2
|
+
import {
|
|
3
|
+
fetchWithTimeout,
|
|
4
|
+
resolveTimeoutMs,
|
|
5
|
+
withTimeout
|
|
6
|
+
} from "@open-mercato/shared/lib/http/fetchWithTimeout";
|
|
7
|
+
import { getSecurityEmailBaseUrl } from "@open-mercato/shared/lib/url";
|
|
8
|
+
import {
|
|
9
|
+
getEntityRegistryEntry,
|
|
10
|
+
readItemsArray
|
|
11
|
+
} from "./entityRegistry.js";
|
|
12
|
+
import { isDocumentEntityRegistryModuleEnabled } from "./entityRegistryAvailability.server.js";
|
|
13
|
+
const DEFAULT_REGISTRY_LOOKUP_TIMEOUT_MS = 3e3;
|
|
14
|
+
const MAX_REGISTRY_RESPONSE_BYTES = 1e6;
|
|
15
|
+
async function readRegistryJsonBody(response, callerSignal, timeoutMs) {
|
|
16
|
+
return withTimeout(async (timeoutSignal) => {
|
|
17
|
+
const signals = [callerSignal, timeoutSignal];
|
|
18
|
+
for (const signal of signals) {
|
|
19
|
+
if (signal.aborted) {
|
|
20
|
+
throw signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const reader = response.body?.getReader();
|
|
24
|
+
if (!reader) return null;
|
|
25
|
+
let aborted = null;
|
|
26
|
+
const listeners = signals.map((signal) => {
|
|
27
|
+
let handled = false;
|
|
28
|
+
const listener = () => {
|
|
29
|
+
if (handled) return;
|
|
30
|
+
handled = true;
|
|
31
|
+
aborted = signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
32
|
+
void reader.cancel(aborted).catch(() => void 0);
|
|
33
|
+
};
|
|
34
|
+
signal.addEventListener("abort", listener, { once: true });
|
|
35
|
+
if (signal.aborted) listener();
|
|
36
|
+
return { signal, listener };
|
|
37
|
+
});
|
|
38
|
+
const decoder = new TextDecoder();
|
|
39
|
+
let decoded = "";
|
|
40
|
+
let totalBytes = 0;
|
|
41
|
+
try {
|
|
42
|
+
while (true) {
|
|
43
|
+
const { done, value } = await reader.read();
|
|
44
|
+
if (done) break;
|
|
45
|
+
totalBytes += value.byteLength;
|
|
46
|
+
if (totalBytes > MAX_REGISTRY_RESPONSE_BYTES) {
|
|
47
|
+
await reader.cancel().catch(() => void 0);
|
|
48
|
+
throw new Error("[internal] Entity registry response exceeded the size limit");
|
|
49
|
+
}
|
|
50
|
+
decoded += decoder.decode(value, { stream: true });
|
|
51
|
+
}
|
|
52
|
+
if (aborted) throw aborted;
|
|
53
|
+
decoded += decoder.decode();
|
|
54
|
+
} finally {
|
|
55
|
+
for (const { signal, listener } of listeners) {
|
|
56
|
+
signal.removeEventListener("abort", listener);
|
|
57
|
+
}
|
|
58
|
+
reader.releaseLock();
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
return JSON.parse(decoded);
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}, timeoutMs, "documents entity-registry response");
|
|
66
|
+
}
|
|
67
|
+
function buildForwardedHeaders(request) {
|
|
68
|
+
const headers = new Headers();
|
|
69
|
+
const cookie = request.headers.get("cookie");
|
|
70
|
+
const authorization = request.headers.get("authorization");
|
|
71
|
+
const apiKey = request.headers.get("x-api-key");
|
|
72
|
+
if (cookie) headers.set("cookie", cookie);
|
|
73
|
+
if (authorization) headers.set("authorization", authorization);
|
|
74
|
+
if (apiKey) headers.set("x-api-key", apiKey);
|
|
75
|
+
return headers;
|
|
76
|
+
}
|
|
77
|
+
async function verifyEntityRegistryTarget(request, input, options = {}) {
|
|
78
|
+
const entry = getEntityRegistryEntry(input.entityType);
|
|
79
|
+
if (!entry) {
|
|
80
|
+
throw new CrudHttpError(400, { error: "documents.links.invalidEntityType" });
|
|
81
|
+
}
|
|
82
|
+
if (!isDocumentEntityRegistryModuleEnabled(entry)) {
|
|
83
|
+
throw new CrudHttpError(503, { error: "documents.links.targetUnavailable" });
|
|
84
|
+
}
|
|
85
|
+
const timeoutMs = Math.min(
|
|
86
|
+
resolveTimeoutMs(options.timeoutMs, DEFAULT_REGISTRY_LOOKUP_TIMEOUT_MS),
|
|
87
|
+
DEFAULT_REGISTRY_LOOKUP_TIMEOUT_MS
|
|
88
|
+
);
|
|
89
|
+
const deadline = Date.now() + timeoutMs;
|
|
90
|
+
let response;
|
|
91
|
+
try {
|
|
92
|
+
const lookupUrl = new URL(entry.searchPath, getSecurityEmailBaseUrl());
|
|
93
|
+
lookupUrl.searchParams.set("id", input.entityId);
|
|
94
|
+
lookupUrl.searchParams.set("pageSize", "1");
|
|
95
|
+
const fetchImpl = options.fetchImpl ?? fetchWithTimeout;
|
|
96
|
+
response = await fetchImpl(lookupUrl, {
|
|
97
|
+
method: "GET",
|
|
98
|
+
headers: buildForwardedHeaders(request),
|
|
99
|
+
cache: "no-store",
|
|
100
|
+
redirect: "manual",
|
|
101
|
+
signal: request.signal,
|
|
102
|
+
timeoutMs
|
|
103
|
+
});
|
|
104
|
+
} catch {
|
|
105
|
+
throw new CrudHttpError(503, { error: "documents.links.targetUnavailable" });
|
|
106
|
+
}
|
|
107
|
+
if (response.status === 404) {
|
|
108
|
+
throw new CrudHttpError(options.maskTargetAbsence ? 403 : 503, {
|
|
109
|
+
error: options.maskTargetAbsence ? "documents.links.targetRestricted" : "documents.links.targetUnavailable"
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (response.status >= 500) {
|
|
113
|
+
throw new CrudHttpError(503, { error: "documents.links.targetUnavailable" });
|
|
114
|
+
}
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
throw new CrudHttpError(response.status === 401 ? 401 : 403, {
|
|
117
|
+
error: "documents.links.targetRestricted"
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
let payload;
|
|
121
|
+
try {
|
|
122
|
+
payload = await readRegistryJsonBody(
|
|
123
|
+
response,
|
|
124
|
+
request.signal,
|
|
125
|
+
Math.max(1, deadline - Date.now())
|
|
126
|
+
);
|
|
127
|
+
} catch {
|
|
128
|
+
throw new CrudHttpError(503, { error: "documents.links.targetUnavailable" });
|
|
129
|
+
}
|
|
130
|
+
const rawItem = readItemsArray(payload).find((candidate) => entry.mapItem(candidate)?.id === input.entityId) ?? null;
|
|
131
|
+
const mapped = rawItem ? entry.mapItem(rawItem) : null;
|
|
132
|
+
const resolvedHref = mapped ? entry.resolveHref(mapped) : null;
|
|
133
|
+
if (!mapped || !rawItem || !resolvedHref || !entry.isCanonicalHref(mapped, resolvedHref)) {
|
|
134
|
+
throw new CrudHttpError(options.maskTargetAbsence ? 403 : 400, {
|
|
135
|
+
error: options.maskTargetAbsence ? "documents.links.targetRestricted" : "documents.links.targetMismatch"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
...mapped,
|
|
140
|
+
href: resolvedHref,
|
|
141
|
+
values: Object.fromEntries(entry.tokenFields.map((field) => [field.field, field.extract(rawItem)]))
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function verifyEntityRegistrySelection(request, input, options = {}) {
|
|
145
|
+
return verifyEntityRegistryTarget(request, input, options);
|
|
146
|
+
}
|
|
147
|
+
async function verifyEntityRegistryTargetAccess(request, input, options = {}) {
|
|
148
|
+
try {
|
|
149
|
+
return await verifyEntityRegistryTarget(request, input, {
|
|
150
|
+
...options,
|
|
151
|
+
maskTargetAbsence: true
|
|
152
|
+
});
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (isCrudHttpError(error) && error.status >= 400 && error.status < 500) {
|
|
155
|
+
throw new CrudHttpError(403, { error: "documents.links.targetRestricted" });
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function verifyEntityRegistrySelections(request, inputs, options = {}) {
|
|
161
|
+
const deduped = Array.from(
|
|
162
|
+
new Map(inputs.map((input) => [`${input.entityType}:${input.entityId}`, input])).values()
|
|
163
|
+
);
|
|
164
|
+
if (deduped.length > 20) {
|
|
165
|
+
throw new CrudHttpError(400, { error: "documents.templates.tooManySlots" });
|
|
166
|
+
}
|
|
167
|
+
const concurrency = Math.max(1, Math.min(4, options.concurrency ?? 4));
|
|
168
|
+
const verified = /* @__PURE__ */ new Map();
|
|
169
|
+
let nextIndex = 0;
|
|
170
|
+
const workers = Array.from({ length: Math.min(concurrency, deduped.length) }, async () => {
|
|
171
|
+
while (nextIndex < deduped.length) {
|
|
172
|
+
const index = nextIndex;
|
|
173
|
+
nextIndex += 1;
|
|
174
|
+
const input = deduped[index];
|
|
175
|
+
verified.set(
|
|
176
|
+
`${input.entityType}:${input.entityId}`,
|
|
177
|
+
await verifyEntityRegistrySelection(request, input, options)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
await Promise.all(workers);
|
|
182
|
+
return verified;
|
|
183
|
+
}
|
|
184
|
+
export {
|
|
185
|
+
verifyEntityRegistrySelection,
|
|
186
|
+
verifyEntityRegistrySelections,
|
|
187
|
+
verifyEntityRegistryTargetAccess
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=entityRegistry.server.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/documents/lib/entityRegistry.server.ts"],
|
|
4
|
+
"sourcesContent": ["import { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n fetchWithTimeout,\n type FetchWithTimeoutInit,\n resolveTimeoutMs,\n withTimeout,\n} from '@open-mercato/shared/lib/http/fetchWithTimeout'\nimport { getSecurityEmailBaseUrl } from '@open-mercato/shared/lib/url'\nimport type { DocumentEntityType } from '../data/validators'\nimport {\n getEntityRegistryEntry,\n readItemsArray,\n type EntityPickerItem,\n} from './entityRegistry'\nimport { isDocumentEntityRegistryModuleEnabled } from './entityRegistryAvailability.server'\n\nexport type VerifyEntityRegistrySelectionInput = {\n entityType: DocumentEntityType\n entityId: string\n label: string\n href: string\n}\n\nexport type VerifyEntityRegistryTargetAccessInput = Pick<\n VerifyEntityRegistrySelectionInput,\n 'entityType' | 'entityId'\n>\n\nexport type VerifiedEntityRegistrySelection = EntityPickerItem & {\n href: string\n values: Record<string, string | null>\n}\n\ntype RegistryFetch = (\n input: RequestInfo | URL,\n init?: FetchWithTimeoutInit,\n) => Promise<Response>\n\nconst DEFAULT_REGISTRY_LOOKUP_TIMEOUT_MS = 3_000\nconst MAX_REGISTRY_RESPONSE_BYTES = 1_000_000\n\nasync function readRegistryJsonBody(\n response: Response,\n callerSignal: AbortSignal,\n timeoutMs: number,\n): Promise<unknown> {\n return withTimeout(async (timeoutSignal) => {\n const signals = [callerSignal, timeoutSignal]\n for (const signal of signals) {\n if (signal.aborted) {\n throw signal.reason instanceof Error\n ? signal.reason\n : new DOMException('Aborted', 'AbortError')\n }\n }\n\n const reader = response.body?.getReader()\n if (!reader) return null\n let aborted: unknown = null\n const listeners = signals.map((signal) => {\n let handled = false\n const listener = () => {\n if (handled) return\n handled = true\n aborted = signal.reason instanceof Error\n ? signal.reason\n : new DOMException('Aborted', 'AbortError')\n void reader.cancel(aborted).catch(() => undefined)\n }\n signal.addEventListener('abort', listener, { once: true })\n if (signal.aborted) listener()\n return { signal, listener }\n })\n\n const decoder = new TextDecoder()\n let decoded = ''\n let totalBytes = 0\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n totalBytes += value.byteLength\n if (totalBytes > MAX_REGISTRY_RESPONSE_BYTES) {\n await reader.cancel().catch(() => undefined)\n throw new Error('[internal] Entity registry response exceeded the size limit')\n }\n decoded += decoder.decode(value, { stream: true })\n }\n if (aborted) throw aborted\n decoded += decoder.decode()\n } finally {\n for (const { signal, listener } of listeners) {\n signal.removeEventListener('abort', listener)\n }\n reader.releaseLock()\n }\n\n try {\n return JSON.parse(decoded) as unknown\n } catch {\n return null\n }\n }, timeoutMs, 'documents entity-registry response')\n}\n\nfunction buildForwardedHeaders(request: Request): Headers {\n const headers = new Headers()\n const cookie = request.headers.get('cookie')\n const authorization = request.headers.get('authorization')\n const apiKey = request.headers.get('x-api-key')\n if (cookie) headers.set('cookie', cookie)\n if (authorization) headers.set('authorization', authorization)\n if (apiKey) headers.set('x-api-key', apiKey)\n return headers\n}\n\ntype RegistryVerificationOptions = {\n fetchImpl?: RegistryFetch\n timeoutMs?: number\n maskTargetAbsence?: boolean\n}\n\nasync function verifyEntityRegistryTarget(\n request: Request,\n input: VerifyEntityRegistryTargetAccessInput,\n options: RegistryVerificationOptions = {},\n): Promise<VerifiedEntityRegistrySelection> {\n const entry = getEntityRegistryEntry(input.entityType)\n if (!entry) {\n throw new CrudHttpError(400, { error: 'documents.links.invalidEntityType' })\n }\n if (!isDocumentEntityRegistryModuleEnabled(entry)) {\n throw new CrudHttpError(503, { error: 'documents.links.targetUnavailable' })\n }\n\n const timeoutMs = Math.min(\n resolveTimeoutMs(options.timeoutMs, DEFAULT_REGISTRY_LOOKUP_TIMEOUT_MS),\n DEFAULT_REGISTRY_LOOKUP_TIMEOUT_MS,\n )\n const deadline = Date.now() + timeoutMs\n let response: Response\n try {\n // This request carries the caller's credentials, so its destination must\n // come from the configured application URL rather than request.url/Host.\n // getSecurityEmailBaseUrl intentionally has a fixed loopback development\n // fallback and requires APP_URL in production.\n const lookupUrl = new URL(entry.searchPath, getSecurityEmailBaseUrl())\n lookupUrl.searchParams.set('id', input.entityId)\n lookupUrl.searchParams.set('pageSize', '1')\n const fetchImpl = options.fetchImpl ?? fetchWithTimeout\n response = await fetchImpl(lookupUrl, {\n method: 'GET',\n headers: buildForwardedHeaders(request),\n cache: 'no-store',\n redirect: 'manual',\n signal: request.signal,\n timeoutMs,\n })\n } catch {\n throw new CrudHttpError(503, { error: 'documents.links.targetUnavailable' })\n }\n\n if (response.status === 404) {\n throw new CrudHttpError(options.maskTargetAbsence ? 403 : 503, {\n error: options.maskTargetAbsence\n ? 'documents.links.targetRestricted'\n : 'documents.links.targetUnavailable',\n })\n }\n if (response.status >= 500) {\n throw new CrudHttpError(503, { error: 'documents.links.targetUnavailable' })\n }\n if (!response.ok) {\n throw new CrudHttpError(response.status === 401 ? 401 : 403, {\n error: 'documents.links.targetRestricted',\n })\n }\n\n let payload: unknown\n try {\n payload = await readRegistryJsonBody(\n response,\n request.signal,\n Math.max(1, deadline - Date.now()),\n )\n } catch {\n throw new CrudHttpError(503, { error: 'documents.links.targetUnavailable' })\n }\n const rawItem = readItemsArray(payload).find((candidate) => (\n entry.mapItem(candidate)?.id === input.entityId\n )) ?? null\n const mapped = rawItem ? entry.mapItem(rawItem) : null\n const resolvedHref = mapped ? entry.resolveHref(mapped) : null\n if (!mapped || !rawItem || !resolvedHref || !entry.isCanonicalHref(mapped, resolvedHref)) {\n throw new CrudHttpError(options.maskTargetAbsence ? 403 : 400, {\n error: options.maskTargetAbsence\n ? 'documents.links.targetRestricted'\n : 'documents.links.targetMismatch',\n })\n }\n return {\n ...mapped,\n href: resolvedHref,\n values: Object.fromEntries(entry.tokenFields.map((field) => [field.field, field.extract(rawItem)])),\n }\n}\n\nexport async function verifyEntityRegistrySelection(\n request: Request,\n input: VerifyEntityRegistrySelectionInput,\n options: { fetchImpl?: RegistryFetch; timeoutMs?: number } = {},\n): Promise<VerifiedEntityRegistrySelection> {\n return verifyEntityRegistryTarget(request, input, options)\n}\n\n/**\n * Verify access to one exact peer record before using its UUID as a reverse\n * relation filter. Missing and restricted targets intentionally share the same\n * denial so the Documents collection cannot become a peer-record oracle.\n */\nexport async function verifyEntityRegistryTargetAccess(\n request: Request,\n input: VerifyEntityRegistryTargetAccessInput,\n options: { fetchImpl?: RegistryFetch; timeoutMs?: number } = {},\n): Promise<VerifiedEntityRegistrySelection> {\n try {\n return await verifyEntityRegistryTarget(request, input, {\n ...options,\n maskTargetAbsence: true,\n })\n } catch (error) {\n if (isCrudHttpError(error) && error.status >= 400 && error.status < 500) {\n throw new CrudHttpError(403, { error: 'documents.links.targetRestricted' })\n }\n throw error\n }\n}\n\nexport async function verifyEntityRegistrySelections(\n request: Request,\n inputs: VerifyEntityRegistrySelectionInput[],\n options: { fetchImpl?: RegistryFetch; concurrency?: number; timeoutMs?: number } = {},\n): Promise<Map<string, VerifiedEntityRegistrySelection>> {\n const deduped = Array.from(\n new Map(inputs.map((input) => [`${input.entityType}:${input.entityId}`, input])).values(),\n )\n if (deduped.length > 20) {\n throw new CrudHttpError(400, { error: 'documents.templates.tooManySlots' })\n }\n\n const concurrency = Math.max(1, Math.min(4, options.concurrency ?? 4))\n const verified = new Map<string, VerifiedEntityRegistrySelection>()\n let nextIndex = 0\n const workers = Array.from({ length: Math.min(concurrency, deduped.length) }, async () => {\n while (nextIndex < deduped.length) {\n const index = nextIndex\n nextIndex += 1\n const input = deduped[index]!\n verified.set(\n `${input.entityType}:${input.entityId}`,\n await verifyEntityRegistrySelection(request, input, options),\n )\n }\n })\n await Promise.all(workers)\n return verified\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getEnabledModuleIds } from "@open-mercato/shared/security/enabledModulesRegistry";
|
|
2
|
+
function isDocumentEntityRegistryModuleEnabled(entry) {
|
|
3
|
+
const enabledModuleIds = new Set(getEnabledModuleIds());
|
|
4
|
+
return enabledModuleIds.has(entry.requiredModule) && enabledModuleIds.has(entry.requiredFeatureModule);
|
|
5
|
+
}
|
|
6
|
+
export {
|
|
7
|
+
isDocumentEntityRegistryModuleEnabled
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=entityRegistryAvailability.server.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/documents/lib/entityRegistryAvailability.server.ts"],
|
|
4
|
+
"sourcesContent": ["import { getEnabledModuleIds } from '@open-mercato/shared/security/enabledModulesRegistry'\nimport type { DocumentEntityRegistryEntry } from './entityRegistry'\n\n/**\n * Returns whether the peer module backing a Documents entity-registry entry\n * is enabled in the running application.\n *\n * The bootstrapped module registry is the canonical server-side source. An\n * empty/unavailable registry therefore fails closed for peer-backed entries;\n * stale ACL grants (including superadmin wildcards) must never make a disabled\n * module addressable through Documents.\n */\nexport function isDocumentEntityRegistryModuleEnabled(\n entry: Pick<DocumentEntityRegistryEntry, 'requiredModule' | 'requiredFeatureModule'>,\n): boolean {\n const enabledModuleIds = new Set(getEnabledModuleIds())\n return enabledModuleIds.has(entry.requiredModule)\n && enabledModuleIds.has(entry.requiredFeatureModule)\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2BAA2B;AAY7B,SAAS,sCACd,OACS;AACT,QAAM,mBAAmB,IAAI,IAAI,oBAAoB,CAAC;AACtD,SAAO,iBAAiB,IAAI,MAAM,cAAc,KAC3C,iBAAiB,IAAI,MAAM,qBAAqB;AACvD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Extension } from "@tiptap/core";
|
|
2
|
+
import { Suggestion } from "@tiptap/suggestion";
|
|
3
|
+
function notifyTrigger(handlers, props) {
|
|
4
|
+
handlers.onTrigger({
|
|
5
|
+
query: props.query,
|
|
6
|
+
range: {
|
|
7
|
+
from: props.range.from,
|
|
8
|
+
to: props.range.to
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function createEntitySuggestionExtension(handlers) {
|
|
13
|
+
return Extension.create({
|
|
14
|
+
name: "entitySuggestion",
|
|
15
|
+
addProseMirrorPlugins() {
|
|
16
|
+
return [
|
|
17
|
+
Suggestion({
|
|
18
|
+
editor: this.editor,
|
|
19
|
+
char: "@",
|
|
20
|
+
allowSpaces: false,
|
|
21
|
+
startOfLine: false,
|
|
22
|
+
items: () => [],
|
|
23
|
+
command: () => void 0,
|
|
24
|
+
render: () => ({
|
|
25
|
+
onStart: (props) => notifyTrigger(handlers, props),
|
|
26
|
+
onUpdate: (props) => notifyTrigger(handlers, props),
|
|
27
|
+
onExit: () => handlers.onClose()
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function insertEntityRef(editor, attrs) {
|
|
35
|
+
return editor.chain().focus().insertContent([
|
|
36
|
+
{
|
|
37
|
+
type: "entityRef",
|
|
38
|
+
attrs
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: " "
|
|
43
|
+
}
|
|
44
|
+
]).run();
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
createEntitySuggestionExtension,
|
|
48
|
+
insertEntityRef
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=entitySuggestion.js.map
|