@endora-commerce/mod-catalog 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/admin/components/PackagingUnitsEditor.d.ts +12 -0
- package/dist/admin/components/PackagingUnitsEditor.d.ts.map +1 -0
- package/dist/admin/components/PackagingUnitsEditor.js +99 -0
- package/dist/admin/components/PackagingUnitsEditor.js.map +1 -0
- package/dist/admin/components/ProductAttributesTab.d.ts +13 -0
- package/dist/admin/components/ProductAttributesTab.d.ts.map +1 -0
- package/dist/admin/components/ProductAttributesTab.js +140 -0
- package/dist/admin/components/ProductAttributesTab.js.map +1 -0
- package/dist/admin/components/ProductInventoryTab.d.ts +14 -0
- package/dist/admin/components/ProductInventoryTab.d.ts.map +1 -0
- package/dist/admin/components/ProductInventoryTab.js +284 -0
- package/dist/admin/components/ProductInventoryTab.js.map +1 -0
- package/dist/admin/components/ProductScopeEditor.d.ts +94 -0
- package/dist/admin/components/ProductScopeEditor.d.ts.map +1 -0
- package/dist/admin/components/ProductScopeEditor.js +395 -0
- package/dist/admin/components/ProductScopeEditor.js.map +1 -0
- package/dist/admin/components/ProductsBulkEditDialog.d.ts +11 -0
- package/dist/admin/components/ProductsBulkEditDialog.d.ts.map +1 -0
- package/dist/admin/components/ProductsBulkEditDialog.js +304 -0
- package/dist/admin/components/ProductsBulkEditDialog.js.map +1 -0
- package/dist/admin/index.d.ts +45 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +184 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/lib/resolve-product-selection.d.ts +21 -0
- package/dist/admin/lib/resolve-product-selection.d.ts.map +1 -0
- package/dist/admin/lib/resolve-product-selection.js +25 -0
- package/dist/admin/lib/resolve-product-selection.js.map +1 -0
- package/dist/admin/pages/AttachmentTypesPage.d.ts +18 -0
- package/dist/admin/pages/AttachmentTypesPage.d.ts.map +1 -0
- package/dist/admin/pages/AttachmentTypesPage.js +92 -0
- package/dist/admin/pages/AttachmentTypesPage.js.map +1 -0
- package/dist/admin/pages/AttributeSetsPage.d.ts +21 -0
- package/dist/admin/pages/AttributeSetsPage.d.ts.map +1 -0
- package/dist/admin/pages/AttributeSetsPage.js +158 -0
- package/dist/admin/pages/AttributeSetsPage.js.map +1 -0
- package/dist/admin/pages/AttributesManager.d.ts +9 -0
- package/dist/admin/pages/AttributesManager.d.ts.map +1 -0
- package/dist/admin/pages/AttributesManager.js +305 -0
- package/dist/admin/pages/AttributesManager.js.map +1 -0
- package/dist/admin/pages/BulkOperationDetailPage.d.ts +9 -0
- package/dist/admin/pages/BulkOperationDetailPage.d.ts.map +1 -0
- package/dist/admin/pages/BulkOperationDetailPage.js +187 -0
- package/dist/admin/pages/BulkOperationDetailPage.js.map +1 -0
- package/dist/admin/pages/BulkOperationsPage.d.ts +9 -0
- package/dist/admin/pages/BulkOperationsPage.d.ts.map +1 -0
- package/dist/admin/pages/BulkOperationsPage.js +98 -0
- package/dist/admin/pages/BulkOperationsPage.js.map +1 -0
- package/dist/admin/pages/CategoriesTree.d.ts +9 -0
- package/dist/admin/pages/CategoriesTree.d.ts.map +1 -0
- package/dist/admin/pages/CategoriesTree.js +176 -0
- package/dist/admin/pages/CategoriesTree.js.map +1 -0
- package/dist/admin/pages/ProductEditor.d.ts +13 -0
- package/dist/admin/pages/ProductEditor.d.ts.map +1 -0
- package/dist/admin/pages/ProductEditor.js +1050 -0
- package/dist/admin/pages/ProductEditor.js.map +1 -0
- package/dist/admin/pages/ProductsList.d.ts +9 -0
- package/dist/admin/pages/ProductsList.d.ts.map +1 -0
- package/dist/admin/pages/ProductsList.js +399 -0
- package/dist/admin/pages/ProductsList.js.map +1 -0
- package/dist/backend/commands/attribute-commands.d.ts +111 -0
- package/dist/backend/commands/attribute-commands.d.ts.map +1 -0
- package/dist/backend/commands/attribute-commands.js +482 -0
- package/dist/backend/commands/attribute-commands.js.map +1 -0
- package/dist/backend/demo/reset.d.ts +23 -0
- package/dist/backend/demo/reset.d.ts.map +1 -0
- package/dist/backend/demo/reset.js +41 -0
- package/dist/backend/demo/reset.js.map +1 -0
- package/dist/backend/demo/rows.d.ts +103 -0
- package/dist/backend/demo/rows.d.ts.map +1 -0
- package/dist/backend/demo/rows.js +162 -0
- package/dist/backend/demo/rows.js.map +1 -0
- package/dist/backend/demo/seed.d.ts +35 -0
- package/dist/backend/demo/seed.d.ts.map +1 -0
- package/dist/backend/demo/seed.js +177 -0
- package/dist/backend/demo/seed.js.map +1 -0
- package/dist/backend/entities/attachment-type.entity.d.ts +16 -0
- package/dist/backend/entities/attachment-type.entity.d.ts.map +1 -0
- package/dist/backend/entities/attachment-type.entity.js +57 -0
- package/dist/backend/entities/attachment-type.entity.js.map +1 -0
- package/dist/backend/entities/attribute-set-attribute.entity.d.ts +26 -0
- package/dist/backend/entities/attribute-set-attribute.entity.d.ts.map +1 -0
- package/dist/backend/entities/attribute-set-attribute.entity.js +55 -0
- package/dist/backend/entities/attribute-set-attribute.entity.js.map +1 -0
- package/dist/backend/entities/attribute-set.entity.d.ts +22 -0
- package/dist/backend/entities/attribute-set.entity.d.ts.map +1 -0
- package/dist/backend/entities/attribute-set.entity.js +67 -0
- package/dist/backend/entities/attribute-set.entity.js.map +1 -0
- package/dist/backend/entities/bulk-operation.entity.d.ts +78 -0
- package/dist/backend/entities/bulk-operation.entity.d.ts.map +1 -0
- package/dist/backend/entities/bulk-operation.entity.js +138 -0
- package/dist/backend/entities/bulk-operation.entity.js.map +1 -0
- package/dist/backend/entities/bundle-slot-option.entity.d.ts +23 -0
- package/dist/backend/entities/bundle-slot-option.entity.d.ts.map +1 -0
- package/dist/backend/entities/bundle-slot-option.entity.js +68 -0
- package/dist/backend/entities/bundle-slot-option.entity.js.map +1 -0
- package/dist/backend/entities/bundle-slot.entity.d.ts +25 -0
- package/dist/backend/entities/bundle-slot.entity.d.ts.map +1 -0
- package/dist/backend/entities/bundle-slot.entity.js +74 -0
- package/dist/backend/entities/bundle-slot.entity.js.map +1 -0
- package/dist/backend/entities/category.entity.d.ts +26 -0
- package/dist/backend/entities/category.entity.d.ts.map +1 -0
- package/dist/backend/entities/category.entity.js +119 -0
- package/dist/backend/entities/category.entity.js.map +1 -0
- package/dist/backend/entities/gallery-item-label.entity.d.ts +22 -0
- package/dist/backend/entities/gallery-item-label.entity.d.ts.map +1 -0
- package/dist/backend/entities/gallery-item-label.entity.js +50 -0
- package/dist/backend/entities/gallery-item-label.entity.js.map +1 -0
- package/dist/backend/entities/gallery-item.entity.d.ts +17 -0
- package/dist/backend/entities/gallery-item.entity.d.ts.map +1 -0
- package/dist/backend/entities/gallery-item.entity.js +58 -0
- package/dist/backend/entities/gallery-item.entity.js.map +1 -0
- package/dist/backend/entities/grouped-item.entity.d.ts +23 -0
- package/dist/backend/entities/grouped-item.entity.d.ts.map +1 -0
- package/dist/backend/entities/grouped-item.entity.js +68 -0
- package/dist/backend/entities/grouped-item.entity.js.map +1 -0
- package/dist/backend/entities/product-attachment.entity.d.ts +23 -0
- package/dist/backend/entities/product-attachment.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-attachment.entity.js +77 -0
- package/dist/backend/entities/product-attachment.entity.js.map +1 -0
- package/dist/backend/entities/product-attribute.entity.d.ts +72 -0
- package/dist/backend/entities/product-attribute.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-attribute.entity.js +161 -0
- package/dist/backend/entities/product-attribute.entity.js.map +1 -0
- package/dist/backend/entities/product-editor-preference.entity.d.ts +28 -0
- package/dist/backend/entities/product-editor-preference.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-editor-preference.entity.js +63 -0
- package/dist/backend/entities/product-editor-preference.entity.js.map +1 -0
- package/dist/backend/entities/product-link.entity.d.ts +25 -0
- package/dist/backend/entities/product-link.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-link.entity.js +70 -0
- package/dist/backend/entities/product-link.entity.js.map +1 -0
- package/dist/backend/entities/product-packaging-unit.entity.d.ts +26 -0
- package/dist/backend/entities/product-packaging-unit.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-packaging-unit.entity.js +76 -0
- package/dist/backend/entities/product-packaging-unit.entity.js.map +1 -0
- package/dist/backend/entities/product-value-override.entity.d.ts +43 -0
- package/dist/backend/entities/product-value-override.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-value-override.entity.js +90 -0
- package/dist/backend/entities/product-value-override.entity.js.map +1 -0
- package/dist/backend/entities/product-variant.entity.d.ts +18 -0
- package/dist/backend/entities/product-variant.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-variant.entity.js +68 -0
- package/dist/backend/entities/product-variant.entity.js.map +1 -0
- package/dist/backend/entities/product.entity.d.ts +108 -0
- package/dist/backend/entities/product.entity.d.ts.map +1 -0
- package/dist/backend/entities/product.entity.js +230 -0
- package/dist/backend/entities/product.entity.js.map +1 -0
- package/dist/backend/index.d.ts +262 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +642 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +216 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +223 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/prompt-tools.d.ts +47 -0
- package/dist/backend/prompt-tools.d.ts.map +1 -0
- package/dist/backend/prompt-tools.js +284 -0
- package/dist/backend/prompt-tools.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +105 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +1162 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.api-key.d.ts +33 -0
- package/dist/backend/routes.api-key.d.ts.map +1 -0
- package/dist/backend/routes.api-key.js +43 -0
- package/dist/backend/routes.api-key.js.map +1 -0
- package/dist/backend/routes.external.d.ts +32 -0
- package/dist/backend/routes.external.d.ts.map +1 -0
- package/dist/backend/routes.external.js +115 -0
- package/dist/backend/routes.external.js.map +1 -0
- package/dist/backend/routes.public.d.ts +46 -0
- package/dist/backend/routes.public.d.ts.map +1 -0
- package/dist/backend/routes.public.js +318 -0
- package/dist/backend/routes.public.js.map +1 -0
- package/dist/backend/services/asset-references.d.ts +4 -0
- package/dist/backend/services/asset-references.d.ts.map +1 -0
- package/dist/backend/services/asset-references.js +104 -0
- package/dist/backend/services/asset-references.js.map +1 -0
- package/dist/backend/services/attachment.service.d.ts +45 -0
- package/dist/backend/services/attachment.service.d.ts.map +1 -0
- package/dist/backend/services/attachment.service.js +268 -0
- package/dist/backend/services/attachment.service.js.map +1 -0
- package/dist/backend/services/attribute-option-validator.d.ts +47 -0
- package/dist/backend/services/attribute-option-validator.d.ts.map +1 -0
- package/dist/backend/services/attribute-option-validator.js +69 -0
- package/dist/backend/services/attribute-option-validator.js.map +1 -0
- package/dist/backend/services/attribute-set-validations.d.ts +65 -0
- package/dist/backend/services/attribute-set-validations.d.ts.map +1 -0
- package/dist/backend/services/attribute-set-validations.js +89 -0
- package/dist/backend/services/attribute-set-validations.js.map +1 -0
- package/dist/backend/services/attribute-set.service.d.ts +50 -0
- package/dist/backend/services/attribute-set.service.d.ts.map +1 -0
- package/dist/backend/services/attribute-set.service.js +401 -0
- package/dist/backend/services/attribute-set.service.js.map +1 -0
- package/dist/backend/services/attribute-type-mapping.d.ts +66 -0
- package/dist/backend/services/attribute-type-mapping.d.ts.map +1 -0
- package/dist/backend/services/attribute-type-mapping.js +121 -0
- package/dist/backend/services/attribute-type-mapping.js.map +1 -0
- package/dist/backend/services/attribute-value-key.service.d.ts +48 -0
- package/dist/backend/services/attribute-value-key.service.d.ts.map +1 -0
- package/dist/backend/services/attribute-value-key.service.js +118 -0
- package/dist/backend/services/attribute-value-key.service.js.map +1 -0
- package/dist/backend/services/audit-references.d.ts +13 -0
- package/dist/backend/services/audit-references.d.ts.map +1 -0
- package/dist/backend/services/audit-references.js +51 -0
- package/dist/backend/services/audit-references.js.map +1 -0
- package/dist/backend/services/bulk-operation-queue.d.ts +26 -0
- package/dist/backend/services/bulk-operation-queue.d.ts.map +1 -0
- package/dist/backend/services/bulk-operation-queue.js +34 -0
- package/dist/backend/services/bulk-operation-queue.js.map +1 -0
- package/dist/backend/services/bulk-operation.service.d.ts +195 -0
- package/dist/backend/services/bulk-operation.service.d.ts.map +1 -0
- package/dist/backend/services/bulk-operation.service.js +510 -0
- package/dist/backend/services/bulk-operation.service.js.map +1 -0
- package/dist/backend/services/bundle.service.d.ts +87 -0
- package/dist/backend/services/bundle.service.d.ts.map +1 -0
- package/dist/backend/services/bundle.service.js +286 -0
- package/dist/backend/services/bundle.service.js.map +1 -0
- package/dist/backend/services/catalog-admin.service.d.ts +398 -0
- package/dist/backend/services/catalog-admin.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-admin.service.js +1516 -0
- package/dist/backend/services/catalog-admin.service.js.map +1 -0
- package/dist/backend/services/catalog-attribute-read.service.d.ts +78 -0
- package/dist/backend/services/catalog-attribute-read.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-attribute-read.service.js +216 -0
- package/dist/backend/services/catalog-attribute-read.service.js.map +1 -0
- package/dist/backend/services/catalog-bulk-import.service.d.ts +30 -0
- package/dist/backend/services/catalog-bulk-import.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-bulk-import.service.js +136 -0
- package/dist/backend/services/catalog-bulk-import.service.js.map +1 -0
- package/dist/backend/services/catalog-bulk-update.service.d.ts +91 -0
- package/dist/backend/services/catalog-bulk-update.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-bulk-update.service.js +330 -0
- package/dist/backend/services/catalog-bulk-update.service.js.map +1 -0
- package/dist/backend/services/catalog-category-read.service.d.ts +66 -0
- package/dist/backend/services/catalog-category-read.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-category-read.service.js +248 -0
- package/dist/backend/services/catalog-category-read.service.js.map +1 -0
- package/dist/backend/services/catalog-org-price-decorator.d.ts +90 -0
- package/dist/backend/services/catalog-org-price-decorator.d.ts.map +1 -0
- package/dist/backend/services/catalog-org-price-decorator.js +184 -0
- package/dist/backend/services/catalog-org-price-decorator.js.map +1 -0
- package/dist/backend/services/catalog-product-filter.service.d.ts +82 -0
- package/dist/backend/services/catalog-product-filter.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-product-filter.service.js +275 -0
- package/dist/backend/services/catalog-product-filter.service.js.map +1 -0
- package/dist/backend/services/catalog-product-read.service.d.ts +46 -0
- package/dist/backend/services/catalog-product-read.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-product-read.service.js +197 -0
- package/dist/backend/services/catalog-product-read.service.js.map +1 -0
- package/dist/backend/services/catalog-query.service.d.ts +444 -0
- package/dist/backend/services/catalog-query.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-query.service.js +1633 -0
- package/dist/backend/services/catalog-query.service.js.map +1 -0
- package/dist/backend/services/catalog-quick-search.service.d.ts +78 -0
- package/dist/backend/services/catalog-quick-search.service.d.ts.map +1 -0
- package/dist/backend/services/catalog-quick-search.service.js +159 -0
- package/dist/backend/services/catalog-quick-search.service.js.map +1 -0
- package/dist/backend/services/catalog-write-ports.d.ts +25 -0
- package/dist/backend/services/catalog-write-ports.d.ts.map +1 -0
- package/dist/backend/services/catalog-write-ports.js +63 -0
- package/dist/backend/services/catalog-write-ports.js.map +1 -0
- package/dist/backend/services/category-admin.service.d.ts +102 -0
- package/dist/backend/services/category-admin.service.d.ts.map +1 -0
- package/dist/backend/services/category-admin.service.js +271 -0
- package/dist/backend/services/category-admin.service.js.map +1 -0
- package/dist/backend/services/gallery.service.d.ts +85 -0
- package/dist/backend/services/gallery.service.d.ts.map +1 -0
- package/dist/backend/services/gallery.service.js +326 -0
- package/dist/backend/services/gallery.service.js.map +1 -0
- package/dist/backend/services/grouped.service.d.ts +39 -0
- package/dist/backend/services/grouped.service.d.ts.map +1 -0
- package/dist/backend/services/grouped.service.js +136 -0
- package/dist/backend/services/grouped.service.js.map +1 -0
- package/dist/backend/services/label-resolver.d.ts +16 -0
- package/dist/backend/services/label-resolver.d.ts.map +1 -0
- package/dist/backend/services/label-resolver.js +43 -0
- package/dist/backend/services/label-resolver.js.map +1 -0
- package/dist/backend/services/packaging-unit.service.d.ts +28 -0
- package/dist/backend/services/packaging-unit.service.d.ts.map +1 -0
- package/dist/backend/services/packaging-unit.service.js +197 -0
- package/dist/backend/services/packaging-unit.service.js.map +1 -0
- package/dist/backend/services/primary-asset-url.d.ts +4 -0
- package/dist/backend/services/primary-asset-url.d.ts.map +1 -0
- package/dist/backend/services/primary-asset-url.js +55 -0
- package/dist/backend/services/primary-asset-url.js.map +1 -0
- package/dist/backend/services/product-editor-preferences.service.d.ts +20 -0
- package/dist/backend/services/product-editor-preferences.service.d.ts.map +1 -0
- package/dist/backend/services/product-editor-preferences.service.js +44 -0
- package/dist/backend/services/product-editor-preferences.service.js.map +1 -0
- package/dist/backend/services/product-link.service.d.ts +169 -0
- package/dist/backend/services/product-link.service.d.ts.map +1 -0
- package/dist/backend/services/product-link.service.js +297 -0
- package/dist/backend/services/product-link.service.js.map +1 -0
- package/dist/backend/services/product-overrides.service.d.ts +77 -0
- package/dist/backend/services/product-overrides.service.d.ts.map +1 -0
- package/dist/backend/services/product-overrides.service.js +204 -0
- package/dist/backend/services/product-overrides.service.js.map +1 -0
- package/dist/backend/services/product-scope-context.service.d.ts +36 -0
- package/dist/backend/services/product-scope-context.service.d.ts.map +1 -0
- package/dist/backend/services/product-scope-context.service.js +106 -0
- package/dist/backend/services/product-scope-context.service.js.map +1 -0
- package/dist/backend/services/product-type-validations.d.ts +42 -0
- package/dist/backend/services/product-type-validations.d.ts.map +1 -0
- package/dist/backend/services/product-type-validations.js +55 -0
- package/dist/backend/services/product-type-validations.js.map +1 -0
- package/dist/backend/services/product-value-resolver.service.d.ts +59 -0
- package/dist/backend/services/product-value-resolver.service.d.ts.map +1 -0
- package/dist/backend/services/product-value-resolver.service.js +111 -0
- package/dist/backend/services/product-value-resolver.service.js.map +1 -0
- package/dist/backend/services/system-attribute-scopes.d.ts +18 -0
- package/dist/backend/services/system-attribute-scopes.d.ts.map +1 -0
- package/dist/backend/services/system-attribute-scopes.js +18 -0
- package/dist/backend/services/system-attribute-scopes.js.map +1 -0
- package/dist/backend/services/viewer-organization.d.ts +25 -0
- package/dist/backend/services/viewer-organization.d.ts.map +1 -0
- package/dist/backend/services/viewer-organization.js +31 -0
- package/dist/backend/services/viewer-organization.js.map +1 -0
- package/dist/manifest.d.ts +204 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +686 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts +33 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts.map +1 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js +118 -0
- package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js.map +1 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts +24 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts.map +1 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js +31 -0
- package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js.map +1 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts +32 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts.map +1 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js +58 -0
- package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js.map +1 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts +22 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts.map +1 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js +66 -0
- package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js.map +1 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts +18 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts.map +1 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.js +73 -0
- package/dist/migrations/20260429T112543_catalog_product_attachments.js.map +1 -0
- package/dist/migrations/20260429T123726_catalog_product_links.d.ts +21 -0
- package/dist/migrations/20260429T123726_catalog_product_links.d.ts.map +1 -0
- package/dist/migrations/20260429T123726_catalog_product_links.js +48 -0
- package/dist/migrations/20260429T123726_catalog_product_links.js.map +1 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts +23 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts.map +1 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js +94 -0
- package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js.map +1 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts +24 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts.map +1 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js +31 -0
- package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js.map +1 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts +31 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts.map +1 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js +133 -0
- package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js.map +1 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts +16 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts.map +1 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js +23 -0
- package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js.map +1 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts +10 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts.map +1 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.js +22 -0
- package/dist/migrations/20260526T124736_catalog_product_status_inactive.js.map +1 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts +38 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts.map +1 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js +98 -0
- package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js.map +1 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts +13 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts.map +1 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js +17 -0
- package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js.map +1 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts +16 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts.map +1 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.js +42 -0
- package/dist/migrations/20260611T140407_catalog_bulk_operations.js.map +1 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts +14 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts.map +1 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js +18 -0
- package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js.map +1 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts +11 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts.map +1 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.js +29 -0
- package/dist/migrations/20260611T140412_catalog_product_packaging_units.js.map +1 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts +23 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts.map +1 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js +35 -0
- package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js.map +1 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts +12 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts.map +1 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js +16 -0
- package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js.map +1 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts +32 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts.map +1 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js +286 -0
- package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js.map +1 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts +36 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts.map +1 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.js +63 -0
- package/dist/migrations/20260804T152604_catalog_widen_product_sku.js.map +1 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.d.ts +18 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.d.ts.map +1 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.js +22 -0
- package/dist/migrations/20260804T160244_catalog_category_activation.js.map +1 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts +27 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts.map +1 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.js +44 -0
- package/dist/migrations/20260912T094557_catalog_sales_channel_products.js.map +1 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts +27 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts.map +1 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js +44 -0
- package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js.map +1 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts +36 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts.map +1 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.js +87 -0
- package/dist/migrations/20260925T125527_catalog_inventory_columns.js.map +1 -0
- package/dist/migrations/index.d.ts +55 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +80 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/ports/index.d.ts +96 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +2 -0
- package/dist/ports/index.js.map +1 -0
- package/docs/catalog/attachments.md +69 -0
- package/docs/catalog/attribute-sets.md +63 -0
- package/docs/catalog/attributes.md +244 -0
- package/docs/catalog/composite-products.md +115 -0
- package/docs/catalog/gallery-and-labels.md +73 -0
- package/docs/catalog/packaging-units.md +67 -0
- package/docs/catalog/per-channel-per-language-overrides.md +234 -0
- package/docs/catalog/product-links.md +79 -0
- package/docs/catalog.md +207 -0
- package/i18n/en.json +649 -0
- package/i18n/pl.json +649 -0
- package/package.json +109 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { CatalogAttributeValueKeyApi, CatalogAttributeValueKeyMove, CatalogAttributeValueKeyRenameOptions } from '../../ports/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* A value-key rename `catalog` refused before writing anything.
|
|
5
|
+
*
|
|
6
|
+
* `system_attribute` — `name` and `description` are product columns, not
|
|
7
|
+
* attribute values, and an override row carrying one of them is a slot of the
|
|
8
|
+
* product's own field; neither can be the source or the target of a key move.
|
|
9
|
+
* `invalid_key` — outside the grammar every product attribute key satisfies.
|
|
10
|
+
* `target_occupied` — the caller asked to `refuse` and data is already stored
|
|
11
|
+
* under the destination.
|
|
12
|
+
*/
|
|
13
|
+
export declare class AttributeValueKeyError extends Error {
|
|
14
|
+
readonly code: 'system_attribute' | 'invalid_key' | 'target_occupied';
|
|
15
|
+
constructor(code: 'system_attribute' | 'invalid_key' | 'target_occupied', message: string);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Renames an attribute's **value key** everywhere `catalog` stores it as a
|
|
19
|
+
* string (`specs/134-paid-module-extraction/research.md` D12, *Ergonode
|
|
20
|
+
* fallback boundary* and *what a rename does to data already under its
|
|
21
|
+
* destination*).
|
|
22
|
+
*
|
|
23
|
+
* Two places, and only two: `products.attribute_values`, a JSONB map keyed by
|
|
24
|
+
* the attribute key, and `product_value_overrides.attribute_key`. Everything
|
|
25
|
+
* else in the catalogue points at an attribute by id. The definition's own key
|
|
26
|
+
* is `custom_fields`' row and is renamed through its `applyRenameKey`, in the
|
|
27
|
+
* same transaction as this call — which is why this takes the caller's
|
|
28
|
+
* `EntityManager` and runs every statement on its transaction context rather
|
|
29
|
+
* than on a connection of its own.
|
|
30
|
+
*
|
|
31
|
+
* In order, all on that transaction:
|
|
32
|
+
*
|
|
33
|
+
* 1. the destination's baseline values and override rows are read and
|
|
34
|
+
* locked (`for update`);
|
|
35
|
+
* 2. if there are any, `refuse` throws `target_occupied` — nothing has been
|
|
36
|
+
* written — and `displace` strips the key from those products and deletes
|
|
37
|
+
* those override rows, keeping what it removed to return;
|
|
38
|
+
* 3. the two moves run. The destination is empty by now, so the `jsonb ||`
|
|
39
|
+
* in the first one only adds a key and the second can meet no unique
|
|
40
|
+
* index — the result does not depend on which products held what.
|
|
41
|
+
*
|
|
42
|
+
* No command, no audit, no cache publish: the caller's composite operation owns
|
|
43
|
+
* those, exactly as for `custom_fields`' apply seam.
|
|
44
|
+
*/
|
|
45
|
+
export declare class AttributeValueKeyService implements CatalogAttributeValueKeyApi {
|
|
46
|
+
renameValueKey(em: EntityManager, fromKey: string, toKey: string, options: CatalogAttributeValueKeyRenameOptions): Promise<CatalogAttributeValueKeyMove>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=attribute-value-key.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribute-value-key.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/attribute-value-key.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EACV,2BAA2B,EAC3B,4BAA4B,EAC5B,qCAAqC,EAGtC,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;GASG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAE7C,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa,GAAG,iBAAiB;gBAA5D,IAAI,EAAE,kBAAkB,GAAG,aAAa,GAAG,iBAAiB,EACrE,OAAO,EAAE,MAAM;CAKlB;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,wBAAyB,YAAW,2BAA2B;IACpE,cAAc,CAClB,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,4BAA4B,CAAC;CAwGzC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { customFieldDefinitionSchema, isSystemAttributeKey } from '@endora-commerce/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* A value-key rename `catalog` refused before writing anything.
|
|
4
|
+
*
|
|
5
|
+
* `system_attribute` — `name` and `description` are product columns, not
|
|
6
|
+
* attribute values, and an override row carrying one of them is a slot of the
|
|
7
|
+
* product's own field; neither can be the source or the target of a key move.
|
|
8
|
+
* `invalid_key` — outside the grammar every product attribute key satisfies.
|
|
9
|
+
* `target_occupied` — the caller asked to `refuse` and data is already stored
|
|
10
|
+
* under the destination.
|
|
11
|
+
*/
|
|
12
|
+
export class AttributeValueKeyError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(code, message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.name = 'AttributeValueKeyError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Renames an attribute's **value key** everywhere `catalog` stores it as a
|
|
22
|
+
* string (`specs/134-paid-module-extraction/research.md` D12, *Ergonode
|
|
23
|
+
* fallback boundary* and *what a rename does to data already under its
|
|
24
|
+
* destination*).
|
|
25
|
+
*
|
|
26
|
+
* Two places, and only two: `products.attribute_values`, a JSONB map keyed by
|
|
27
|
+
* the attribute key, and `product_value_overrides.attribute_key`. Everything
|
|
28
|
+
* else in the catalogue points at an attribute by id. The definition's own key
|
|
29
|
+
* is `custom_fields`' row and is renamed through its `applyRenameKey`, in the
|
|
30
|
+
* same transaction as this call — which is why this takes the caller's
|
|
31
|
+
* `EntityManager` and runs every statement on its transaction context rather
|
|
32
|
+
* than on a connection of its own.
|
|
33
|
+
*
|
|
34
|
+
* In order, all on that transaction:
|
|
35
|
+
*
|
|
36
|
+
* 1. the destination's baseline values and override rows are read and
|
|
37
|
+
* locked (`for update`);
|
|
38
|
+
* 2. if there are any, `refuse` throws `target_occupied` — nothing has been
|
|
39
|
+
* written — and `displace` strips the key from those products and deletes
|
|
40
|
+
* those override rows, keeping what it removed to return;
|
|
41
|
+
* 3. the two moves run. The destination is empty by now, so the `jsonb ||`
|
|
42
|
+
* in the first one only adds a key and the second can meet no unique
|
|
43
|
+
* index — the result does not depend on which products held what.
|
|
44
|
+
*
|
|
45
|
+
* No command, no audit, no cache publish: the caller's composite operation owns
|
|
46
|
+
* those, exactly as for `custom_fields`' apply seam.
|
|
47
|
+
*/
|
|
48
|
+
export class AttributeValueKeyService {
|
|
49
|
+
async renameValueKey(em, fromKey, toKey, options) {
|
|
50
|
+
for (const key of [fromKey, toKey]) {
|
|
51
|
+
if (isSystemAttributeKey(key)) {
|
|
52
|
+
throw new AttributeValueKeyError('system_attribute', `"${key}" is a product field, not an attribute value key; nothing was renamed.`);
|
|
53
|
+
}
|
|
54
|
+
if (!customFieldDefinitionSchema.shape.key.safeParse(key).success) {
|
|
55
|
+
throw new AttributeValueKeyError('invalid_key', `"${key}" is not a valid attribute key.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (fromKey === toKey) {
|
|
59
|
+
return { products: 0, overrides: 0, displaced: { values: [], overrides: [] } };
|
|
60
|
+
}
|
|
61
|
+
// command-coverage-ignore: owner-published rename seam — runs on the caller's
|
|
62
|
+
// transactional EM. Its one caller is a system-invariant repair with no
|
|
63
|
+
// operator and no actor (a connector re-keying the attributes it derived,
|
|
64
|
+
// committed atomically with `custom_fields`' definition rename and the
|
|
65
|
+
// connector's own repair checkpoint); an audit entry for it would have
|
|
66
|
+
// nobody to attribute. Contract: specs/134-paid-module-extraction/research.md D12.
|
|
67
|
+
const connection = em.getConnection();
|
|
68
|
+
const ctx = em.getTransactionContext();
|
|
69
|
+
const occupiedValues = (await connection.execute(`select "id" as product_id, "attribute_values" -> ?::text as value
|
|
70
|
+
from "products"
|
|
71
|
+
where jsonb_exists("attribute_values", ?::text)
|
|
72
|
+
for update`, [toKey, toKey], 'all', ctx));
|
|
73
|
+
const occupiedOverrides = (await connection.execute(`select "product_id", "channel_id", "language_code", "value"
|
|
74
|
+
from "product_value_overrides"
|
|
75
|
+
where "attribute_key" = ?
|
|
76
|
+
for update`, [toKey], 'all', ctx));
|
|
77
|
+
let displacedValues = [];
|
|
78
|
+
let displacedOverrides = [];
|
|
79
|
+
if (occupiedValues.length > 0 || occupiedOverrides.length > 0) {
|
|
80
|
+
if (options.occupied === 'refuse') {
|
|
81
|
+
throw new AttributeValueKeyError('target_occupied', `"${toKey}" already holds ${occupiedValues.length} product value(s) and ` +
|
|
82
|
+
`${occupiedOverrides.length} override row(s); nothing was renamed.`);
|
|
83
|
+
}
|
|
84
|
+
if (occupiedValues.length > 0) {
|
|
85
|
+
await connection.execute(`update "products" set "attribute_values" = "attribute_values" - ?::text
|
|
86
|
+
where jsonb_exists("attribute_values", ?::text)`, [toKey, toKey], 'run', ctx);
|
|
87
|
+
displacedValues = occupiedValues.map((row) => ({
|
|
88
|
+
productId: row.product_id,
|
|
89
|
+
value: row.value,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
if (occupiedOverrides.length > 0) {
|
|
93
|
+
const removed = (await connection.execute(`delete from "product_value_overrides" where "attribute_key" = ?
|
|
94
|
+
returning "product_id", "channel_id", "language_code", "value"`, [toKey], 'all', ctx));
|
|
95
|
+
displacedOverrides = removed.map((row) => ({
|
|
96
|
+
productId: row.product_id,
|
|
97
|
+
channelId: row.channel_id,
|
|
98
|
+
languageCode: row.language_code,
|
|
99
|
+
value: row.value,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const products = await connection.execute(`update "products"
|
|
104
|
+
set "attribute_values" = ("attribute_values" - ?::text) || jsonb_build_object(?::text, "attribute_values" -> ?::text)
|
|
105
|
+
where jsonb_exists("attribute_values", ?::text)`, [fromKey, toKey, fromKey, fromKey], 'run', ctx);
|
|
106
|
+
const overrides = await connection.execute(`update "product_value_overrides" set "attribute_key" = ? where "attribute_key" = ?`, [toKey, fromKey], 'run', ctx);
|
|
107
|
+
return {
|
|
108
|
+
products: affectedRowsOf(products),
|
|
109
|
+
overrides: affectedRowsOf(overrides),
|
|
110
|
+
displaced: { values: displacedValues, overrides: displacedOverrides },
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function affectedRowsOf(result) {
|
|
115
|
+
const affected = result?.affectedRows;
|
|
116
|
+
return typeof affected === 'number' ? affected : 0;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=attribute-value-key.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribute-value-key.service.js","sourceRoot":"","sources":["../../../src/backend/services/attribute-value-key.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuditReferenceRegistryPort } from '@endora-commerce/contracts';
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
3
|
+
/**
|
|
4
|
+
* What a `product` audit row is called, and where the admin app shows it
|
|
5
|
+
* (feature 075, D-87 drain).
|
|
6
|
+
*
|
|
7
|
+
* `audit_logs` used to run `select id, sku, name from products` for its
|
|
8
|
+
* dashboard card and spell `/catalog/products/{id}` into its own switch
|
|
9
|
+
* statement — a reader naming this module's table and this module's admin route.
|
|
10
|
+
* Both are answered here now, over this module's own entity.
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerCatalogAuditReferences(registry: AuditReferenceRegistryPort, emFactory: () => EntityManager): void;
|
|
13
|
+
//# sourceMappingURL=audit-references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-references.d.ts","sourceRoot":"","sources":["../../../src/backend/services/audit-references.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,0BAA0B,EACpC,SAAS,EAAE,MAAM,aAAa,GAC7B,IAAI,CAoBN"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Product } from '../entities/product.entity.js';
|
|
2
|
+
/**
|
|
3
|
+
* What a `product` audit row is called, and where the admin app shows it
|
|
4
|
+
* (feature 075, D-87 drain).
|
|
5
|
+
*
|
|
6
|
+
* `audit_logs` used to run `select id, sku, name from products` for its
|
|
7
|
+
* dashboard card and spell `/catalog/products/{id}` into its own switch
|
|
8
|
+
* statement — a reader naming this module's table and this module's admin route.
|
|
9
|
+
* Both are answered here now, over this module's own entity.
|
|
10
|
+
*/
|
|
11
|
+
export function registerCatalogAuditReferences(registry, emFactory) {
|
|
12
|
+
registry.register({
|
|
13
|
+
ownerModuleId: 'catalog',
|
|
14
|
+
referenceType: 'product',
|
|
15
|
+
resolve: async (ids) => {
|
|
16
|
+
const rows = await emFactory().find(Product, { id: { $in: [...ids] } }, { fields: ['id', 'sku', 'name'] });
|
|
17
|
+
return rows.map((row) => ({
|
|
18
|
+
id: row.id,
|
|
19
|
+
// The SKU is the fallback rather than a second field: a product with no
|
|
20
|
+
// translated name still has to render as something an operator
|
|
21
|
+
// recognises, and the audit card has one line to do it in.
|
|
22
|
+
label: pickTranslation(row.name) ?? row.sku,
|
|
23
|
+
url: `/catalog/products/${row.id}`,
|
|
24
|
+
}));
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The language fallback chain the audit card has always used. Kept in that order
|
|
30
|
+
* deliberately — moving `en-US` ahead of `en` would silently re-label existing
|
|
31
|
+
* rows on a deployment that stores both.
|
|
32
|
+
*/
|
|
33
|
+
function pickTranslation(value) {
|
|
34
|
+
if (!value)
|
|
35
|
+
return null;
|
|
36
|
+
// Pre-multilingual rows stored a bare string. `Object.values` over one yields
|
|
37
|
+
// its characters, so the guard is what stops a name rendering as `E`.
|
|
38
|
+
if (typeof value === 'string')
|
|
39
|
+
return value.length > 0 ? value : null;
|
|
40
|
+
for (const key of ['en', 'en-US', 'pl', 'pl-PL']) {
|
|
41
|
+
const v = value[key];
|
|
42
|
+
if (typeof v === 'string' && v.length > 0)
|
|
43
|
+
return v;
|
|
44
|
+
}
|
|
45
|
+
for (const v of Object.values(value)) {
|
|
46
|
+
if (typeof v === 'string' && v.length > 0)
|
|
47
|
+
return v;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=audit-references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-references.js","sourceRoot":"","sources":["../../../src/backend/services/audit-references.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAExD;;;;;;;;GAQG;AACH,MAAM,UAAU,8BAA8B,CAC5C,QAAoC,EACpC,SAA8B;IAE9B,QAAQ,CAAC,QAAQ,CAAC;QAChB,aAAa,EAAE,SAAS;QACxB,aAAa,EAAE,SAAS;QACxB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACrB,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CACjC,OAAO,EACP,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE,EACzB,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAClC,CAAC;YACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACxB,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,wEAAwE;gBACxE,+DAA+D;gBAC/D,2DAA2D;gBAC3D,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG;gBAC3C,GAAG,EAAE,qBAAqB,GAAG,CAAC,EAAE,EAAE;aACnC,CAAC,CAAC,CAAC;QACN,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CACtB,KAAyD;IAEzD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,8EAA8E;IAC9E,sEAAsE;IACtE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Queue, Worker, type Processor, type QueueOptions, type WorkerOptions } from 'bullmq';
|
|
2
|
+
import type { Redis } from 'ioredis';
|
|
3
|
+
/**
|
|
4
|
+
* BullMQ queue manager for catalog bulk operations (product bulk-edit and
|
|
5
|
+
* `search_reindex`), per Constitution Principle X (Scalable Queue Consumers).
|
|
6
|
+
*
|
|
7
|
+
* - The producer ({@link BulkOperationService.create}) persists a `pending`
|
|
8
|
+
* row and enqueues `{ operationId }` here — it never inline-executes the job.
|
|
9
|
+
* - The consumer is a BullMQ {@link Worker} that claims the operation
|
|
10
|
+
* atomically (BullMQ job lock + the row's conditional `pending → running`
|
|
11
|
+
* UPDATE) and runs the idempotent handler, so N ≥ 2 worker instances never
|
|
12
|
+
* double-process a job.
|
|
13
|
+
* - The worker is a **separable entrypoint**: co-located in the API process by
|
|
14
|
+
* default (single-VPS posture) but startable as its own process via
|
|
15
|
+
* `pnpm --filter backend run worker` without code changes.
|
|
16
|
+
*/
|
|
17
|
+
export interface BulkOperationJobData {
|
|
18
|
+
/** Primary key of the {@link BulkOperation} row to process. */
|
|
19
|
+
operationId: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const BULK_OPERATION_QUEUE_NAME = "catalog.bulk-operation";
|
|
22
|
+
/** Stable job name; the row is the source of truth, so a single name suffices. */
|
|
23
|
+
export declare const BULK_OPERATION_JOB_NAME = "process";
|
|
24
|
+
export declare function createBulkOperationQueue(redis: Redis, overrides?: Partial<QueueOptions>): Queue<BulkOperationJobData>;
|
|
25
|
+
export declare function createBulkOperationWorker(redis: Redis, processor: Processor<BulkOperationJobData>, overrides?: Partial<WorkerOptions>): Worker<BulkOperationJobData>;
|
|
26
|
+
//# sourceMappingURL=bulk-operation-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulk-operation-queue.d.ts","sourceRoot":"","sources":["../../../src/backend/services/bulk-operation-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE9F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAElE,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,YAAY,CAAC;AAKjD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,KAAK,EACZ,SAAS,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAChC,KAAK,CAAC,oBAAoB,CAAC,CAY7B;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,oBAAoB,CAAC,EAC1C,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GACjC,MAAM,CAAC,oBAAoB,CAAC,CAgB9B"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Queue, Worker } from 'bullmq';
|
|
2
|
+
import { enterSystemScope } from '@endora-commerce/platform/kernel';
|
|
3
|
+
export const BULK_OPERATION_QUEUE_NAME = 'catalog.bulk-operation';
|
|
4
|
+
/** Stable job name; the row is the source of truth, so a single name suffices. */
|
|
5
|
+
export const BULK_OPERATION_JOB_NAME = 'process';
|
|
6
|
+
const DEFAULT_ATTEMPTS = 3;
|
|
7
|
+
const DEFAULT_BACKOFF = { type: 'exponential', delay: 2_000 };
|
|
8
|
+
export function createBulkOperationQueue(redis, overrides) {
|
|
9
|
+
const options = {
|
|
10
|
+
connection: redis,
|
|
11
|
+
defaultJobOptions: {
|
|
12
|
+
attempts: DEFAULT_ATTEMPTS,
|
|
13
|
+
backoff: DEFAULT_BACKOFF,
|
|
14
|
+
removeOnComplete: { count: 500 },
|
|
15
|
+
removeOnFail: { count: 5_000 },
|
|
16
|
+
},
|
|
17
|
+
...overrides,
|
|
18
|
+
};
|
|
19
|
+
return new Queue(BULK_OPERATION_QUEUE_NAME, options);
|
|
20
|
+
}
|
|
21
|
+
export function createBulkOperationWorker(redis, processor, overrides) {
|
|
22
|
+
const options = {
|
|
23
|
+
connection: redis,
|
|
24
|
+
// Bulk operations are heavy (one drains a whole selection); keep a small
|
|
25
|
+
// concurrency per instance and scale out by adding worker processes.
|
|
26
|
+
concurrency: 2,
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
// Feature 072 (T033) — the job establishes its own scope. A bulk operation
|
|
30
|
+
// writes through the Command Bus, which derives its actor from the ambient
|
|
31
|
+
// context, so "no context" was never a safe state here.
|
|
32
|
+
return new Worker(BULK_OPERATION_QUEUE_NAME, (job) => enterSystemScope('catalog: bulk operation', () => processor(job)), options);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=bulk-operation-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulk-operation-queue.js","sourceRoot":"","sources":["../../../src/backend/services/bulk-operation-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAyD,MAAM,QAAQ,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAuBpE,MAAM,CAAC,MAAM,yBAAyB,GAAG,wBAAwB,CAAC;AAElE,kFAAkF;AAClF,MAAM,CAAC,MAAM,uBAAuB,GAAG,SAAS,CAAC;AAEjD,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,eAAe,GAAG,EAAE,IAAI,EAAE,aAAsB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAEvE,MAAM,UAAU,wBAAwB,CACtC,KAAY,EACZ,SAAiC;IAEjC,MAAM,OAAO,GAAiB;QAC5B,UAAU,EAAE,KAAK;QACjB,iBAAiB,EAAE;YACjB,QAAQ,EAAE,gBAAgB;YAC1B,OAAO,EAAE,eAAe;YACxB,gBAAgB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;YAChC,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SAC/B;QACD,GAAG,SAAS;KACb,CAAC;IACF,OAAO,IAAI,KAAK,CAAuB,yBAAyB,EAAE,OAAO,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,KAAY,EACZ,SAA0C,EAC1C,SAAkC;IAElC,MAAM,OAAO,GAAkB;QAC7B,UAAU,EAAE,KAAK;QACjB,yEAAyE;QACzE,qEAAqE;QACrE,WAAW,EAAE,CAAC;QACd,GAAG,SAAS;KACb,CAAC;IACF,2EAA2E;IAC3E,2EAA2E;IAC3E,wDAAwD;IACxD,OAAO,IAAI,MAAM,CACf,yBAAyB,EACzB,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,yBAAyB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAC1E,OAAO,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type AdminUserReadPort, type EmailMailerPort } from '@endora-commerce/contracts';
|
|
3
|
+
import type { CommandBus } from '@endora-commerce/platform/commands';
|
|
4
|
+
import { type BulkOperationLogEntry, type BulkOperationPayload, type BulkOperationStatus } from '../entities/bulk-operation.entity.js';
|
|
5
|
+
import type { CatalogBulkUpdateService, BulkUpdateOutcome } from './catalog-bulk-update.service.js';
|
|
6
|
+
/** The bell entry a finished bulk operation writes for the admin who asked. */
|
|
7
|
+
export interface BulkNotificationInput {
|
|
8
|
+
audience: 'admin_user';
|
|
9
|
+
targetAdminUserId: string;
|
|
10
|
+
kind: string;
|
|
11
|
+
subjectType?: string | null;
|
|
12
|
+
subjectId?: string | null;
|
|
13
|
+
title: string;
|
|
14
|
+
body?: string | null;
|
|
15
|
+
linkPath?: string | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `admin_notifications`' port, as this module reaches it.
|
|
19
|
+
*
|
|
20
|
+
* Resolving it asks a gate, so it either records or throws — it cannot answer
|
|
21
|
+
* "the operator switched the bell off", which is why the degrade lives in the
|
|
22
|
+
* recorder below rather than here (D-61's rejected alternative).
|
|
23
|
+
*/
|
|
24
|
+
export interface BulkNotificationPort {
|
|
25
|
+
record(input: BulkNotificationInput): Promise<unknown>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* What this module actually holds — the degrade in the return type (D-60).
|
|
29
|
+
*
|
|
30
|
+
* `not-present` is the operator having switched `admin_notifications` off. It
|
|
31
|
+
* is composed before the port is reached, so the `catch` around the write is
|
|
32
|
+
* left with what a `catch` should be left with: a failed write.
|
|
33
|
+
*/
|
|
34
|
+
export type BulkNotificationOutcome = 'recorded' | 'not-present';
|
|
35
|
+
export interface BulkNotificationRecorder {
|
|
36
|
+
record(input: BulkNotificationInput): Promise<BulkNotificationOutcome>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Wraps the gated port in the presence decision, so absence is *decided* rather
|
|
40
|
+
* than caught (D-60; Constitution XVII).
|
|
41
|
+
*
|
|
42
|
+
* A function rather than an object literal at the composition site on purpose:
|
|
43
|
+
* `check-port-catches.ts` follows the port **through the value**, and an object
|
|
44
|
+
* literal is where that trail deliberately stops.
|
|
45
|
+
*/
|
|
46
|
+
export declare function presenceAwareBulkRecorder(adminNotifications: BulkNotificationPort): BulkNotificationRecorder;
|
|
47
|
+
export interface CreateBulkOperationInput {
|
|
48
|
+
requestedByAdminUserId: string;
|
|
49
|
+
payload: BulkOperationPayload;
|
|
50
|
+
type?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface SerializedBulkOperation {
|
|
53
|
+
id: string;
|
|
54
|
+
type: string;
|
|
55
|
+
status: BulkOperationStatus;
|
|
56
|
+
requestedByAdminUserId: string;
|
|
57
|
+
total: number;
|
|
58
|
+
processed: number;
|
|
59
|
+
succeeded: number;
|
|
60
|
+
skipped: number;
|
|
61
|
+
failed: number;
|
|
62
|
+
touchedFields: string[];
|
|
63
|
+
results: BulkUpdateOutcome[] | null;
|
|
64
|
+
logs: BulkOperationLogEntry[] | null;
|
|
65
|
+
error: string | null;
|
|
66
|
+
createdAt: string;
|
|
67
|
+
startedAt: string | null;
|
|
68
|
+
finishedAt: string | null;
|
|
69
|
+
reversible: boolean;
|
|
70
|
+
undoStatus: 'none' | 'reverted' | 'partially_reverted';
|
|
71
|
+
undoneAt: string | null;
|
|
72
|
+
}
|
|
73
|
+
export interface ListBulkOperationsInput {
|
|
74
|
+
status?: BulkOperationStatus[];
|
|
75
|
+
limit?: number;
|
|
76
|
+
offset?: number;
|
|
77
|
+
}
|
|
78
|
+
export interface ListBulkOperationsResult {
|
|
79
|
+
items: SerializedBulkOperation[];
|
|
80
|
+
total: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Runs a full Meilisearch reindex (the `search:reindex` CLI equivalent) and
|
|
84
|
+
* reports how many documents landed. Wired from the composition root so the
|
|
85
|
+
* catalog module stays decoupled from the search module's indexer.
|
|
86
|
+
*/
|
|
87
|
+
export type SearchReindexRunner = () => Promise<{
|
|
88
|
+
/** Total documents pushed across every channel index. */
|
|
89
|
+
documentCount: number;
|
|
90
|
+
}>;
|
|
91
|
+
export declare class BulkOperationService {
|
|
92
|
+
#private;
|
|
93
|
+
private readonly emFactory;
|
|
94
|
+
private readonly bulkUpdateService;
|
|
95
|
+
private readonly deps;
|
|
96
|
+
/**
|
|
97
|
+
* Feature 054 — when injected, product bulk edits capture per-product revert
|
|
98
|
+
* state and expose an audited, conflict-aware undo (US2). Optional so bus-less
|
|
99
|
+
* constructions (some tests) keep the pre-054 behavior.
|
|
100
|
+
*/
|
|
101
|
+
private readonly commandBus?;
|
|
102
|
+
/** Single-flight guard so overlapping sweep ticks don't double-process. */
|
|
103
|
+
private draining;
|
|
104
|
+
constructor(emFactory: () => EntityManager, bulkUpdateService: CatalogBulkUpdateService, deps?: {
|
|
105
|
+
notificationService?: BulkNotificationRecorder;
|
|
106
|
+
mailer?: EmailMailerPort;
|
|
107
|
+
/**
|
|
108
|
+
* Feature 075 — who requested the operation, read through `admin_users`'
|
|
109
|
+
* port instead of `em.findOne(AdminUser, …)` against its table. Only the
|
|
110
|
+
* e-mail address is used, to tell the requester their run finished.
|
|
111
|
+
*
|
|
112
|
+
* Optional in the shape, like the two above, because a composition that
|
|
113
|
+
* neither notifies nor mails never reaches it.
|
|
114
|
+
*/
|
|
115
|
+
adminUsers?: AdminUserReadPort;
|
|
116
|
+
/**
|
|
117
|
+
* Producer hook: hands the new operation's id to the durable queue.
|
|
118
|
+
* Called once per `create()` with the persisted row's id. Failures are
|
|
119
|
+
* swallowed by the caller — the `pending` row is the source of truth and
|
|
120
|
+
* the worker's boot reconciliation re-enqueues anything left behind.
|
|
121
|
+
*/
|
|
122
|
+
onEnqueued?: (operationId: string) => void | Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Runs a full Meilisearch reindex for `search_reindex` operations.
|
|
125
|
+
* When omitted, such operations fail with a clear "not configured"
|
|
126
|
+
* message rather than silently no-op'ing.
|
|
127
|
+
*/
|
|
128
|
+
reindexRunner?: SearchReindexRunner;
|
|
129
|
+
},
|
|
130
|
+
/**
|
|
131
|
+
* Feature 054 — when injected, product bulk edits capture per-product revert
|
|
132
|
+
* state and expose an audited, conflict-aware undo (US2). Optional so bus-less
|
|
133
|
+
* constructions (some tests) keep the pre-054 behavior.
|
|
134
|
+
*/
|
|
135
|
+
commandBus?: CommandBus | undefined);
|
|
136
|
+
create(input: CreateBulkOperationInput): Promise<SerializedBulkOperation>;
|
|
137
|
+
/**
|
|
138
|
+
* Consumer entry point invoked by the BullMQ worker for one queued
|
|
139
|
+
* operation. Atomically claims the row (`pending → running`); if the claim
|
|
140
|
+
* affects no row the operation was already taken or finished, so this is a
|
|
141
|
+
* no-op — making the handler idempotent under redelivery/retries and safe at
|
|
142
|
+
* N ≥ 2 worker instances.
|
|
143
|
+
*/
|
|
144
|
+
processById(operationId: string): Promise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* Ids of every operation still `pending`. Used by the worker at boot to
|
|
147
|
+
* re-enqueue rows that were created while no producer/queue was reachable
|
|
148
|
+
* (e.g. an enqueue failure, or a row predating this deployment).
|
|
149
|
+
*/
|
|
150
|
+
findPendingIds(): Promise<string[]>;
|
|
151
|
+
list(input?: ListBulkOperationsInput): Promise<ListBulkOperationsResult>;
|
|
152
|
+
get(id: string): Promise<SerializedBulkOperation | null>;
|
|
153
|
+
/**
|
|
154
|
+
* Drain every `pending` operation. Safe to call repeatedly and
|
|
155
|
+
* concurrently — the single-flight guard ensures one drain at a time.
|
|
156
|
+
*/
|
|
157
|
+
processPending(): Promise<{
|
|
158
|
+
processed: number;
|
|
159
|
+
}>;
|
|
160
|
+
/**
|
|
161
|
+
* Atomically flip the oldest `pending` row to `running` and return its
|
|
162
|
+
* id. The conditional UPDATE means even if two drains race past the
|
|
163
|
+
* in-process guard (e.g. across worker restarts) only one wins a row.
|
|
164
|
+
*/
|
|
165
|
+
private claimNextPending;
|
|
166
|
+
private processOne;
|
|
167
|
+
/**
|
|
168
|
+
* Runs a `search_reindex` operation: a full Meilisearch reindex (the
|
|
169
|
+
* `search:reindex` CLI equivalent). Counts every reindexed document as
|
|
170
|
+
* both processed and succeeded; failure surfaces on the row + notifications.
|
|
171
|
+
*/
|
|
172
|
+
private processReindex;
|
|
173
|
+
private notify;
|
|
174
|
+
/**
|
|
175
|
+
* Undo a reversible bulk edit: restore every affected product whose current
|
|
176
|
+
* state still matches the operation's captured after-state; refuse (report,
|
|
177
|
+
* never clobber) any product changed since. Runs as an audited `bulk.undo`
|
|
178
|
+
* Command and is idempotent-safe on re-invocation (FR-006/FR-007/FR-014).
|
|
179
|
+
*/
|
|
180
|
+
undo(operationId: string): Promise<UndoOutcome>;
|
|
181
|
+
}
|
|
182
|
+
/** Undo result surfaced to the route (mapped to 200/404/409). */
|
|
183
|
+
export type UndoOutcome = {
|
|
184
|
+
ok: true;
|
|
185
|
+
reverted: string[];
|
|
186
|
+
conflicts: {
|
|
187
|
+
recordId: string;
|
|
188
|
+
reason: string;
|
|
189
|
+
}[];
|
|
190
|
+
undoStatus: 'reverted' | 'partially_reverted' | 'none';
|
|
191
|
+
} | {
|
|
192
|
+
ok: false;
|
|
193
|
+
code: 'NOT_FOUND' | 'NOT_REVERSIBLE' | 'ALREADY_REVERTED';
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=bulk-operation.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulk-operation.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/bulk-operation.service.ts"],"names":[],"mappings":"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"}
|