@open-mercato/core 0.6.6-develop.6551.1.1511bfa890 → 0.6.6
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/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities.ids.generated.js +0 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +0 -12
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +13 -30
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/cli.js +1 -2
- package/dist/modules/api_keys/cli.js.map +2 -2
- package/dist/modules/attachments/api/file/[id]/route.js +7 -9
- package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +7 -9
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +17 -21
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentContentPreview.js +35 -6
- package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +24 -14
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +2 -6
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/cli.js +2 -3
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +0 -22
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +0 -1
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -17
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +1 -6
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users-invite.js +1 -6
- package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerInvitationService.js +0 -1
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerRbacService.js +1 -6
- package/dist/modules/customer_accounts/services/customerRbacService.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection-table.js +2 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -7
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js +43 -37
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DealDetailTabs.js +35 -23
- package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DetailTabsLayout.js +21 -6
- package/dist/modules/customers/components/detail/DetailTabsLayout.js.map +2 -2
- package/dist/modules/customers/components/detail/MobilePersonDetail.js +32 -26
- package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailTabs.js +39 -29
- package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
- package/dist/modules/dashboards/api/roles/widgets/route.js +3 -22
- package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/api/users/widgets/route.js +3 -22
- package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/cli.js +3 -4
- package/dist/modules/dashboards/cli.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetAssignmentScope.js +1 -9
- package/dist/modules/dashboards/lib/widgetAssignmentScope.js.map +2 -2
- package/dist/modules/dictionaries/commands/entries.js +14 -7
- package/dist/modules/dictionaries/commands/entries.js.map +2 -2
- package/dist/modules/dictionaries/commands/entry-operations.js +16 -7
- package/dist/modules/dictionaries/commands/entry-operations.js.map +2 -2
- package/dist/modules/dictionaries/commands/factory.js +3 -9
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/dictionaries/fields/dictionary.js +41 -56
- package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js +3 -10
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -5
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js +0 -1
- package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js +49 -49
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js +0 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js.map +2 -2
- package/dist/modules/entities/cli.js +1 -2
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/feature_toggles/api/check/boolean/route.js +14 -0
- package/dist/modules/feature_toggles/api/check/boolean/route.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +0 -8
- package/dist/modules/integrations/backend/integrations/[id]/page.js +80 -9
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/payment_gateways/data/entities.js +0 -45
- package/dist/modules/payment_gateways/data/entities.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +38 -173
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +14 -16
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +30 -18
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/query_index/api/status.js +8 -2
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -24
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/create/page.js +0 -6
- package/dist/modules/sales/backend/sales/channels/create/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/create/page.meta.js +0 -2
- package/dist/modules/sales/backend/sales/channels/create/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +0 -6
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.meta.js +0 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +0 -6
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.meta.js +0 -2
- package/dist/modules/sales/backend/sales/channels/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +4 -6
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +0 -44
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +27 -2
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +2 -6
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +0 -1
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +0 -9
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +3 -51
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +8 -10
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +38 -59
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/lib/shipments/snapshots.js +1 -27
- package/dist/modules/sales/lib/shipments/snapshots.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +25 -22
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -12
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +29 -10
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +20 -19
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/sync_excel/lib/parser.js +0 -185
- package/dist/modules/sync_excel/lib/parser.js.map +2 -2
- package/dist/modules/sync_excel/lib/upload-storage.js +1 -20
- package/dist/modules/sync_excel/lib/upload-storage.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +8 -1
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +1 -1
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/find-definition.js +18 -2
- package/dist/modules/workflows/lib/find-definition.js.map +2 -2
- package/dist/modules/workflows/lib/signal-handler.js +3 -2
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +4 -8
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +3 -5
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/timer-handler.js +2 -1
- package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +5 -13
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +11 -9
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260715120000.js +68 -0
- package/dist/modules/workflows/migrations/Migration20260715120000.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260716120000.js +24 -0
- package/dist/modules/workflows/migrations/Migration20260716120000.js.map +7 -0
- package/dist/modules/workflows/workflows.js +2 -0
- package/dist/modules/workflows/workflows.js.map +2 -2
- package/generated/entities.ids.generated.ts +0 -1
- package/generated/entity-fields-registry.ts +0 -12
- package/package.json +8 -9
- package/src/modules/api_keys/api/keys/route.ts +13 -36
- package/src/modules/api_keys/cli.ts +3 -2
- package/src/modules/attachments/api/file/[id]/route.ts +7 -11
- package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +7 -11
- package/src/modules/attachments/api/route.ts +21 -26
- package/src/modules/attachments/components/AttachmentContentPreview.tsx +44 -9
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +22 -12
- package/src/modules/auth/api/users/route.ts +2 -11
- package/src/modules/auth/cli.ts +2 -3
- package/src/modules/configs/i18n/de.json +1 -5
- package/src/modules/configs/i18n/en.json +1 -5
- package/src/modules/configs/i18n/es.json +1 -5
- package/src/modules/configs/i18n/pl.json +1 -5
- package/src/modules/configs/lib/upgrade-actions.ts +0 -24
- package/src/modules/customer_accounts/AGENTS.md +6 -8
- package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +0 -1
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -17
- package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +1 -6
- package/src/modules/customer_accounts/api/portal/users-invite.ts +1 -6
- package/src/modules/customer_accounts/services/customerInvitationService.ts +0 -1
- package/src/modules/customer_accounts/services/customerRbacService.ts +2 -9
- package/src/modules/customer_accounts/widgets/injection-table.ts +2 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -11
- package/src/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.tsx +2 -6
- package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +55 -39
- package/src/modules/customers/components/detail/DealDetailTabs.tsx +49 -24
- package/src/modules/customers/components/detail/DetailTabsLayout.tsx +24 -13
- package/src/modules/customers/components/detail/MobilePersonDetail.tsx +31 -25
- package/src/modules/customers/components/detail/PersonDetailTabs.tsx +50 -29
- package/src/modules/dashboards/api/roles/widgets/route.ts +3 -22
- package/src/modules/dashboards/api/users/widgets/route.ts +3 -22
- package/src/modules/dashboards/cli.ts +9 -4
- package/src/modules/dashboards/lib/widgetAssignmentScope.ts +0 -18
- package/src/modules/dictionaries/commands/entries.ts +16 -7
- package/src/modules/dictionaries/commands/entry-operations.ts +18 -8
- package/src/modules/dictionaries/commands/factory.ts +2 -8
- package/src/modules/dictionaries/fields/dictionary.tsx +32 -55
- package/src/modules/dictionaries/i18n/de.json +0 -2
- package/src/modules/dictionaries/i18n/en.json +0 -2
- package/src/modules/dictionaries/i18n/es.json +0 -2
- package/src/modules/dictionaries/i18n/pl.json +0 -2
- package/src/modules/directory/utils/organizationScope.ts +2 -36
- package/src/modules/entities/api/records.ts +7 -5
- package/src/modules/entities/backend/entities/system/[entityId]/page.meta.ts +0 -1
- package/src/modules/entities/backend/entities/user/[entityId]/page.meta.ts +0 -1
- package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +49 -51
- package/src/modules/entities/cli.ts +1 -2
- package/src/modules/entities/i18n/de.json +0 -34
- package/src/modules/entities/i18n/en.json +0 -34
- package/src/modules/entities/i18n/es.json +0 -34
- package/src/modules/entities/i18n/pl.json +0 -34
- package/src/modules/feature_toggles/api/check/boolean/route.ts +15 -0
- package/src/modules/feature_toggles/defaults.json +0 -8
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +59 -16
- package/src/modules/payment_gateways/data/entities.ts +0 -39
- package/src/modules/payment_gateways/lib/gateway-service.ts +40 -211
- package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +0 -236
- package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +20 -14
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +34 -16
- package/src/modules/query_index/api/status.ts +8 -2
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +37 -27
- package/src/modules/sales/backend/sales/channels/create/page.meta.ts +0 -3
- package/src/modules/sales/backend/sales/channels/create/page.tsx +0 -7
- package/src/modules/sales/backend/sales/channels/offers/page.meta.ts +0 -3
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +0 -7
- package/src/modules/sales/backend/sales/channels/page.meta.ts +0 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +0 -7
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +5 -7
- package/src/modules/sales/commands/documents.ts +0 -65
- package/src/modules/sales/commands/returns.ts +32 -2
- package/src/modules/sales/components/documents/AddressesSection.tsx +2 -6
- package/src/modules/sales/components/documents/ItemsSection.tsx +0 -5
- package/src/modules/sales/components/documents/LineItemDialog.tsx +0 -10
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +3 -53
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +8 -10
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +40 -65
- package/src/modules/sales/i18n/de.json +0 -5
- package/src/modules/sales/i18n/en.json +0 -5
- package/src/modules/sales/i18n/es.json +0 -5
- package/src/modules/sales/i18n/pl.json +0 -5
- package/src/modules/sales/lib/shipments/snapshots.ts +0 -30
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +34 -25
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -11
- package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +28 -11
- package/src/modules/sync_excel/lib/adapters/customers.ts +22 -20
- package/src/modules/sync_excel/lib/parser.ts +0 -245
- package/src/modules/sync_excel/lib/upload-storage.ts +1 -23
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +12 -1
- package/src/modules/workflows/lib/activity-executor.ts +22 -2
- package/src/modules/workflows/lib/find-definition.ts +53 -1
- package/src/modules/workflows/lib/signal-handler.ts +5 -4
- package/src/modules/workflows/lib/step-handler.ts +4 -8
- package/src/modules/workflows/lib/task-handler.ts +2 -4
- package/src/modules/workflows/lib/timer-handler.ts +3 -2
- package/src/modules/workflows/lib/transition-handler.ts +5 -13
- package/src/modules/workflows/lib/workflow-executor.ts +11 -8
- package/src/modules/workflows/migrations/Migration20260715120000.ts +114 -0
- package/src/modules/workflows/migrations/Migration20260716120000.ts +57 -0
- package/src/modules/workflows/workflows.ts +2 -0
- package/dist/generated/entities/gateway_session_initialization/index.js +0 -23
- package/dist/generated/entities/gateway_session_initialization/index.js.map +0 -7
- package/dist/modules/attachments/lib/reconcileOrganization.js +0 -110
- package/dist/modules/attachments/lib/reconcileOrganization.js.map +0 -7
- package/dist/modules/attachments/lib/requestScope.js +0 -10
- package/dist/modules/attachments/lib/requestScope.js.map +0 -7
- package/dist/modules/auth/api/autologin.js +0 -85
- package/dist/modules/auth/api/autologin.js.map +0 -7
- package/dist/modules/auth/lib/autologin.js +0 -19
- package/dist/modules/auth/lib/autologin.js.map +0 -7
- package/dist/modules/customers/components/detail/useDealsAccess.js +0 -16
- package/dist/modules/customers/components/detail/useDealsAccess.js.map +0 -7
- package/dist/modules/payment_gateways/lib/session-idempotency.js +0 -104
- package/dist/modules/payment_gateways/lib/session-idempotency.js.map +0 -7
- package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js +0 -11
- package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js.map +0 -7
- package/dist/modules/sales/components/SalesChannelsDisabledNotice.js +0 -15
- package/dist/modules/sales/components/SalesChannelsDisabledNotice.js.map +0 -7
- package/dist/modules/sales/components/useSalesChannelsEnabled.js +0 -44
- package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +0 -7
- package/dist/modules/sales/lib/salesChannelsToggle.js +0 -18
- package/dist/modules/sales/lib/salesChannelsToggle.js.map +0 -7
- package/dist/modules/sales/lib/salesChannelsToggleId.js +0 -5
- package/dist/modules/sales/lib/salesChannelsToggleId.js.map +0 -7
- package/generated/entities/gateway_session_initialization/index.ts +0 -10
- package/src/modules/attachments/lib/reconcileOrganization.ts +0 -188
- package/src/modules/attachments/lib/requestScope.ts +0 -27
- package/src/modules/auth/api/autologin.ts +0 -100
- package/src/modules/auth/lib/autologin.ts +0 -36
- package/src/modules/customers/components/detail/useDealsAccess.ts +0 -19
- package/src/modules/payment_gateways/lib/session-idempotency.ts +0 -142
- package/src/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.ts +0 -10
- package/src/modules/sales/components/SalesChannelsDisabledNotice.tsx +0 -21
- package/src/modules/sales/components/useSalesChannelsEnabled.ts +0 -59
- package/src/modules/sales/lib/salesChannelsToggle.ts +0 -26
- package/src/modules/sales/lib/salesChannelsToggleId.ts +0 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations'
|
|
2
|
+
|
|
3
|
+
const LEGACY_WORKFLOW_ID = 'workflows.checkout-demo'
|
|
4
|
+
const LEGACY_WORKFLOW_NAME = 'Checkout with Payment Webhook'
|
|
5
|
+
const LEGACY_ACTIVITY_ID = 'reserve_inventory'
|
|
6
|
+
const LEGACY_ACTIVITY_URL = '{{env.INVENTORY_SERVICE_URL}}/api/inventory/reserve'
|
|
7
|
+
const TRANSITIONS_REPLACED_BY_CODE_DEFINITION = [
|
|
8
|
+
'cart_to_customer_info',
|
|
9
|
+
'customer_info_to_payment',
|
|
10
|
+
'confirmation_to_order',
|
|
11
|
+
] as const
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* SQL fragment (for the UPDATE `where` clause) that matches ONLY the exact
|
|
15
|
+
* legacy checkout seed: workflow id, name, version, and the presence of the
|
|
16
|
+
* obsolete `reserve_inventory` `CALL_WEBHOOK` activity with its exact env-based
|
|
17
|
+
* URL. The match is intentionally strict so the repair never touches a row that
|
|
18
|
+
* is not the known-broken seed. A tenant whose persisted row diverges from this
|
|
19
|
+
* fingerprint (renamed, re-versioned, or a different webhook URL) is left
|
|
20
|
+
* untouched — the trade-off is safety over coverage for an unknown variant.
|
|
21
|
+
*/
|
|
22
|
+
export function legacyCheckoutPredicate(): string {
|
|
23
|
+
return `
|
|
24
|
+
"wf"."workflow_id" = '${LEGACY_WORKFLOW_ID}'
|
|
25
|
+
and "wf"."workflow_name" = '${LEGACY_WORKFLOW_NAME}'
|
|
26
|
+
and "wf"."version" = 1
|
|
27
|
+
and exists (
|
|
28
|
+
select 1
|
|
29
|
+
from jsonb_array_elements(coalesce("wf"."definition"->'transitions', '[]'::jsonb)) as "transition"("value")
|
|
30
|
+
cross join lateral jsonb_array_elements(coalesce("transition"."value"->'activities', '[]'::jsonb)) as "activity"("value")
|
|
31
|
+
where "activity"."value"->>'activityId' = '${LEGACY_ACTIVITY_ID}'
|
|
32
|
+
and "activity"."value"->>'activityType' = 'CALL_WEBHOOK'
|
|
33
|
+
and "activity"."value"#>>'{config,url}' = '${LEGACY_ACTIVITY_URL}'
|
|
34
|
+
)
|
|
35
|
+
`.trim()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The exact UPDATE the migration runs. Exported so the DB-level regression test
|
|
40
|
+
* (`__integration__/TC-WF-031`) executes the identical SQL against Postgres,
|
|
41
|
+
* making the jsonb transformation itself — not just its rendered string —
|
|
42
|
+
* the thing under test.
|
|
43
|
+
*
|
|
44
|
+
* It rebuilds the `transitions` array in original order, dropping the
|
|
45
|
+
* `activities` key from exactly the three transitions the maintained code
|
|
46
|
+
* definition made side-effect-free. All other keys (e.g. `preConditions`) and
|
|
47
|
+
* all other transitions — including `confirmation_to_end`, whose remaining
|
|
48
|
+
* activities are internal (`CALL_API`/`SEND_EMAIL`/`EMIT_EVENT`) and never trip
|
|
49
|
+
* the outbound URL guard — are preserved verbatim.
|
|
50
|
+
*/
|
|
51
|
+
export function buildLegacyCheckoutRepairSql(): string {
|
|
52
|
+
const strippedTransitionList = TRANSITIONS_REPLACED_BY_CODE_DEFINITION
|
|
53
|
+
.map((id) => `'${id}'`)
|
|
54
|
+
.join(', ')
|
|
55
|
+
return `
|
|
56
|
+
update "workflow_definitions" as "wf"
|
|
57
|
+
set "definition" = jsonb_set(
|
|
58
|
+
"wf"."definition",
|
|
59
|
+
'{transitions}',
|
|
60
|
+
coalesce(
|
|
61
|
+
(
|
|
62
|
+
select jsonb_agg(
|
|
63
|
+
case
|
|
64
|
+
when "transition"."value"->>'transitionId' in (${strippedTransitionList})
|
|
65
|
+
then "transition"."value" - 'activities'
|
|
66
|
+
else "transition"."value"
|
|
67
|
+
end
|
|
68
|
+
order by "transition"."ordinality"
|
|
69
|
+
)
|
|
70
|
+
from jsonb_array_elements(
|
|
71
|
+
coalesce("wf"."definition"->'transitions', '[]'::jsonb)
|
|
72
|
+
) with ordinality as "transition"("value", "ordinality")
|
|
73
|
+
),
|
|
74
|
+
'[]'::jsonb
|
|
75
|
+
)
|
|
76
|
+
),
|
|
77
|
+
"updated_at" = current_timestamp
|
|
78
|
+
where "wf"."code_workflow_id" is null
|
|
79
|
+
and "wf"."deleted_at" is null
|
|
80
|
+
and ${legacyCheckoutPredicate()};
|
|
81
|
+
`.trim()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Repairs the former seeded checkout demo after it was renamed to the same ID
|
|
86
|
+
* as the code-defined workflow. The DB-first lookup shadows the current code
|
|
87
|
+
* definition, including its obsolete external inventory webhook.
|
|
88
|
+
*
|
|
89
|
+
* The persisted row must remain active because historical and in-flight
|
|
90
|
+
* workflow instances reference it by definition_id — a random UUID the
|
|
91
|
+
* code-registry fallback in find-definition.ts deliberately never substitutes.
|
|
92
|
+
* The migration removes the activity arrays from the three transitions that
|
|
93
|
+
* the maintained code definition intentionally made side-effect-free,
|
|
94
|
+
* preserving the row and all instance references while keeping the demo
|
|
95
|
+
* self-contained. (Fresh installs never had this row; they execute the virtual
|
|
96
|
+
* code definition directly via findDefinitionForInstance.)
|
|
97
|
+
*
|
|
98
|
+
* `confirmation_to_end` is deliberately NOT rebuilt: unlike the three stripped
|
|
99
|
+
* transitions it still holds activities in the maintained code definition, and
|
|
100
|
+
* its legacy-only extra (`emit_order_completed`, an internal `EMIT_EVENT`) is
|
|
101
|
+
* harmless — it emits no external request, so leaving it costs nothing and
|
|
102
|
+
* avoids fragile per-activity surgery that could re-introduce a failure.
|
|
103
|
+
*/
|
|
104
|
+
export class Migration20260715120000 extends Migration {
|
|
105
|
+
override async up(): Promise<void> {
|
|
106
|
+
this.addSql(buildLegacyCheckoutRepairSql())
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
override async down(): Promise<void> {
|
|
110
|
+
// Forward-only data repair. The removed demo-only activity payloads cannot
|
|
111
|
+
// be reconstructed safely, and restoring obsolete external webhooks would
|
|
112
|
+
// re-open issue #4179.
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations'
|
|
2
|
+
|
|
3
|
+
const CODE_WORKFLOW_ID = 'workflows.checkout-demo'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Retires the persisted checkout-demo seed rows so runtime resolves the
|
|
7
|
+
* maintained CODE definition instead (issue #4211).
|
|
8
|
+
*
|
|
9
|
+
* Background: `workflows.checkout-demo` is now code-defined
|
|
10
|
+
* (`packages/core/src/modules/workflows/workflows.ts`), and only the code
|
|
11
|
+
* definition forwards the cart's line items + shipping/tax adjustments to
|
|
12
|
+
* `POST /api/sales/orders`. But existing tenants still carry a persisted
|
|
13
|
+
* `workflow_definitions` row from the old seed — originally seeded under ids
|
|
14
|
+
* like `checkout_simple_v1` / names like `Simple Checkout Flow` and later
|
|
15
|
+
* `Checkout with Payment Webhook`, then renamed to `workflows.checkout-demo`
|
|
16
|
+
* by Migration20260428102318. Its `create_order` body never sent `lines`, and
|
|
17
|
+
* because `findWorkflowDefinition` resolves the DB row first, that stale row
|
|
18
|
+
* SHADOWS the code definition — so orders come out with zero line items and
|
|
19
|
+
* $0.00 totals. Patching the persisted body is unreliable: the seed's name and
|
|
20
|
+
* body shape vary across historical versions, so a fingerprint on either misses
|
|
21
|
+
* whole cohorts of tenants (the defect QA hit).
|
|
22
|
+
*
|
|
23
|
+
* Instead, soft-delete the seeded rows. This is body/name-agnostic, so it fixes
|
|
24
|
+
* every historical seed variant:
|
|
25
|
+
* - New instances: `findWorkflowDefinition` filters `deleted_at IS NULL`, so
|
|
26
|
+
* the retired row is skipped and the code definition is used (correct body).
|
|
27
|
+
* - In-flight instances: `findDefinitionForInstance` loads the definition by
|
|
28
|
+
* `id` with no soft-delete filter (WorkflowDefinition has no global filter),
|
|
29
|
+
* so instances that reference the row keep resolving and advancing.
|
|
30
|
+
*
|
|
31
|
+
* Scope is limited to `code_workflow_id IS NULL` rows — user customizations of
|
|
32
|
+
* the code definition set `code_workflow_id` and MUST NOT be retired. The
|
|
33
|
+
* `deleted_at IS NULL` guard makes the migration idempotent.
|
|
34
|
+
*/
|
|
35
|
+
export function buildRetireSeededCheckoutDemoSql(): string {
|
|
36
|
+
return `
|
|
37
|
+
update "workflow_definitions" as "wf"
|
|
38
|
+
set "deleted_at" = current_timestamp,
|
|
39
|
+
"updated_at" = current_timestamp
|
|
40
|
+
where "wf"."workflow_id" = '${CODE_WORKFLOW_ID}'
|
|
41
|
+
and "wf"."code_workflow_id" is null
|
|
42
|
+
and "wf"."deleted_at" is null;
|
|
43
|
+
`.trim()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class Migration20260716120000 extends Migration {
|
|
47
|
+
override async up(): Promise<void> {
|
|
48
|
+
this.addSql(buildRetireSeededCheckoutDemoSql())
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override async down(): Promise<void> {
|
|
52
|
+
// Forward-only. Restoring `deleted_at = null` would re-shadow the maintained
|
|
53
|
+
// code definition with the stale seed body and re-introduce zero-line orders
|
|
54
|
+
// (#4211). The code definition supersedes the seed, so there is nothing to
|
|
55
|
+
// restore.
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -239,6 +239,8 @@ const checkoutDemo = defineWorkflow({
|
|
|
239
239
|
customerEntityId: '{{context.customer.id}}',
|
|
240
240
|
currencyCode: '{{context.cart.currency}}',
|
|
241
241
|
placedAt: '{{now}}',
|
|
242
|
+
lines: '{{context.cart.orderLines}}',
|
|
243
|
+
adjustments: '{{context.cart.orderAdjustments}}',
|
|
242
244
|
grandTotalGrossAmount: '{{context.cart.total}}',
|
|
243
245
|
},
|
|
244
246
|
validateTenantMatch: true,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const id = "id";
|
|
2
|
-
const operation_key = "operation_key";
|
|
3
|
-
const provider_key = "provider_key";
|
|
4
|
-
const claim_token = "claim_token";
|
|
5
|
-
const claimed_at = "claimed_at";
|
|
6
|
-
const gateway_transaction_id = "gateway_transaction_id";
|
|
7
|
-
const organization_id = "organization_id";
|
|
8
|
-
const tenant_id = "tenant_id";
|
|
9
|
-
const created_at = "created_at";
|
|
10
|
-
const updated_at = "updated_at";
|
|
11
|
-
export {
|
|
12
|
-
claim_token,
|
|
13
|
-
claimed_at,
|
|
14
|
-
created_at,
|
|
15
|
-
gateway_transaction_id,
|
|
16
|
-
id,
|
|
17
|
-
operation_key,
|
|
18
|
-
organization_id,
|
|
19
|
-
provider_key,
|
|
20
|
-
tenant_id,
|
|
21
|
-
updated_at
|
|
22
|
-
};
|
|
23
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../generated/entities/gateway_session_initialization/index.ts"],
|
|
4
|
-
"sourcesContent": ["export const id = \"id\";\nexport const operation_key = \"operation_key\";\nexport const provider_key = \"provider_key\";\nexport const claim_token = \"claim_token\";\nexport const claimed_at = \"claimed_at\";\nexport const gateway_transaction_id = \"gateway_transaction_id\";\nexport const organization_id = \"organization_id\";\nexport const tenant_id = \"tenant_id\";\nexport const created_at = \"created_at\";\nexport const updated_at = \"updated_at\";\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,KAAK;AACX,MAAM,gBAAgB;AACtB,MAAM,eAAe;AACrB,MAAM,cAAc;AACpB,MAAM,aAAa;AACnB,MAAM,yBAAyB;AAC/B,MAAM,kBAAkB;AACxB,MAAM,YAAY;AAClB,MAAM,aAAa;AACnB,MAAM,aAAa;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
2
|
-
import { Attachment } from "../data/entities.js";
|
|
3
|
-
const logger = createLogger("attachments").child({ component: "reconcileOrganization" });
|
|
4
|
-
const LIBRARY_ENTITY_ID = "attachments:library";
|
|
5
|
-
const DEFAULT_BATCH_SIZE = 500;
|
|
6
|
-
function readParentOrganizationId(record) {
|
|
7
|
-
const raw = record["organization_id"] ?? record["organizationId"];
|
|
8
|
-
if (typeof raw === "string" && raw.trim().length) return raw.trim();
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
function ensureBucket(report, entityId) {
|
|
12
|
-
const existing = report.byEntity[entityId];
|
|
13
|
-
if (existing) return existing;
|
|
14
|
-
const bucket = { scanned: 0, updated: 0, unresolved: 0 };
|
|
15
|
-
report.byEntity[entityId] = bucket;
|
|
16
|
-
return bucket;
|
|
17
|
-
}
|
|
18
|
-
async function reconcileAttachmentOrganizations(opts) {
|
|
19
|
-
const { em, queryEngine, tenantId } = opts;
|
|
20
|
-
const batchSize = opts.batchSize && opts.batchSize > 0 ? opts.batchSize : DEFAULT_BATCH_SIZE;
|
|
21
|
-
const report = {
|
|
22
|
-
scanned: 0,
|
|
23
|
-
updated: 0,
|
|
24
|
-
unresolved: 0,
|
|
25
|
-
skippedVirtual: 0,
|
|
26
|
-
byEntity: {}
|
|
27
|
-
};
|
|
28
|
-
const rows = await em.getConnection().execute(
|
|
29
|
-
"select id, entity_id, record_id, organization_id from attachments where tenant_id = ?",
|
|
30
|
-
[tenantId]
|
|
31
|
-
);
|
|
32
|
-
report.scanned = rows.length;
|
|
33
|
-
if (!rows.length) return report;
|
|
34
|
-
const groups = /* @__PURE__ */ new Map();
|
|
35
|
-
for (const row of rows) {
|
|
36
|
-
if (!row.id || !row.entity_id || !row.record_id) continue;
|
|
37
|
-
const list = groups.get(row.entity_id) ?? [];
|
|
38
|
-
list.push(row);
|
|
39
|
-
groups.set(row.entity_id, list);
|
|
40
|
-
}
|
|
41
|
-
const pendingUpdates = [];
|
|
42
|
-
for (const [entityId, group] of groups) {
|
|
43
|
-
const bucket = ensureBucket(report, entityId);
|
|
44
|
-
bucket.scanned += group.length;
|
|
45
|
-
if (entityId === LIBRARY_ENTITY_ID) {
|
|
46
|
-
report.skippedVirtual += group.length;
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
const recordIds = Array.from(
|
|
50
|
-
new Set(group.map((row) => row.record_id).filter((value) => !!value))
|
|
51
|
-
);
|
|
52
|
-
const parentOrgByRecordId = /* @__PURE__ */ new Map();
|
|
53
|
-
let resolvable = true;
|
|
54
|
-
for (let index = 0; index < recordIds.length; index += batchSize) {
|
|
55
|
-
const chunk = recordIds.slice(index, index + batchSize);
|
|
56
|
-
try {
|
|
57
|
-
const result = await queryEngine.query(entityId, {
|
|
58
|
-
fields: ["id", "organization_id"],
|
|
59
|
-
filters: { id: chunk.length === 1 ? { $eq: chunk[0] } : { $in: chunk } },
|
|
60
|
-
tenantId,
|
|
61
|
-
withDeleted: true,
|
|
62
|
-
page: { pageSize: Math.max(chunk.length, 1) }
|
|
63
|
-
});
|
|
64
|
-
for (const item of result.items ?? []) {
|
|
65
|
-
const record = item;
|
|
66
|
-
const recordId = record.id != null ? String(record.id) : null;
|
|
67
|
-
if (!recordId) continue;
|
|
68
|
-
parentOrgByRecordId.set(recordId, readParentOrganizationId(record));
|
|
69
|
-
}
|
|
70
|
-
} catch (error) {
|
|
71
|
-
resolvable = false;
|
|
72
|
-
logger.warn("org reconcile: cannot resolve parent organization for entity", {
|
|
73
|
-
entityId,
|
|
74
|
-
error
|
|
75
|
-
});
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (!resolvable) {
|
|
80
|
-
bucket.unresolved += group.length;
|
|
81
|
-
report.unresolved += group.length;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
for (const row of group) {
|
|
85
|
-
const target = row.record_id ? parentOrgByRecordId.get(row.record_id) : null;
|
|
86
|
-
if (!target) {
|
|
87
|
-
bucket.unresolved += 1;
|
|
88
|
-
report.unresolved += 1;
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if ((row.organization_id ?? null) === target) continue;
|
|
92
|
-
pendingUpdates.push({ id: row.id, organizationId: target });
|
|
93
|
-
bucket.updated += 1;
|
|
94
|
-
report.updated += 1;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
for (let index = 0; index < pendingUpdates.length; index += batchSize) {
|
|
98
|
-
const chunk = pendingUpdates.slice(index, index + batchSize);
|
|
99
|
-
for (const update of chunk) {
|
|
100
|
-
const reference = em.getReference(Attachment, update.id);
|
|
101
|
-
reference.organizationId = update.organizationId;
|
|
102
|
-
}
|
|
103
|
-
await em.flush();
|
|
104
|
-
}
|
|
105
|
-
return report;
|
|
106
|
-
}
|
|
107
|
-
export {
|
|
108
|
-
reconcileAttachmentOrganizations
|
|
109
|
-
};
|
|
110
|
-
//# sourceMappingURL=reconcileOrganization.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/attachments/lib/reconcileOrganization.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport { Attachment } from '../data/entities'\n\nconst logger = createLogger('attachments').child({ component: 'reconcileOrganization' })\n\n/**\n * Virtual entity id for library attachments \u2014 these are not attached to a\n * parent record that owns an organization, so there is nothing to reconcile\n * against. They are counted as skipped rather than unresolved.\n */\nconst LIBRARY_ENTITY_ID = 'attachments:library'\n\nconst DEFAULT_BATCH_SIZE = 500\n\nexport type AttachmentOrgReconcileEntityStat = {\n scanned: number\n updated: number\n unresolved: number\n}\n\nexport type AttachmentOrgReconcileReport = {\n scanned: number\n updated: number\n unresolved: number\n skippedVirtual: number\n byEntity: Record<string, AttachmentOrgReconcileEntityStat>\n}\n\ntype AttachmentScanRow = {\n id: string\n entity_id: string | null\n record_id: string | null\n organization_id: string | null\n}\n\nfunction readParentOrganizationId(record: Record<string, unknown>): string | null {\n const raw = record['organization_id'] ?? record['organizationId']\n if (typeof raw === 'string' && raw.trim().length) return raw.trim()\n return null\n}\n\nfunction ensureBucket(\n report: AttachmentOrgReconcileReport,\n entityId: string,\n): AttachmentOrgReconcileEntityStat {\n const existing = report.byEntity[entityId]\n if (existing) return existing\n const bucket: AttachmentOrgReconcileEntityStat = { scanned: 0, updated: 0, unresolved: 0 }\n report.byEntity[entityId] = bucket\n return bucket\n}\n\n/**\n * Reconcile the `organization_id` of existing attachments to the organization\n * of the record they are attached to.\n *\n * Background (#3765): before the upload route became selected-organization\n * aware, a multi-org admin who switched the header organization uploaded files\n * that were silently stored under their *home* organization instead of the\n * selected one (the organization of the parent record). Those rows are now\n * invisible to org-scoped reads and stay orphaned. This heals them forward.\n *\n * The parent record's organization is the ground truth: an attachment is not\n * distinguishable from a legitimately home-org one by looking at the attachment\n * alone. Parent organizations are resolved generically through the Query Engine\n * by `entityId` (works for both base and custom entities, tenant-scoped and\n * organization-agnostic so the parent's real org is returned regardless of\n * which org the caller sits in) \u2014 the same mechanism the attachments module\n * already uses to enrich assignment details.\n *\n * The reconciliation is:\n * - idempotent \u2014 rows already matching their parent are left untouched;\n * - conservative \u2014 when the parent org cannot be resolved (unregistered\n * entity id, hard-deleted parent, parent without an org column) the row is\n * counted as `unresolved` and left as-is rather than guessed at;\n * - tenant-scoped \u2014 it reconciles every attachment in the tenant across all\n * organizations (the whole point is moving rows between orgs).\n *\n * Writes go through the passed `EntityManager` (which the caller runs inside a\n * transaction) so the whole reconciliation commits atomically.\n */\nexport async function reconcileAttachmentOrganizations(opts: {\n em: EntityManager\n queryEngine: QueryEngine\n tenantId: string\n batchSize?: number\n}): Promise<AttachmentOrgReconcileReport> {\n const { em, queryEngine, tenantId } = opts\n const batchSize = opts.batchSize && opts.batchSize > 0 ? opts.batchSize : DEFAULT_BATCH_SIZE\n const report: AttachmentOrgReconcileReport = {\n scanned: 0,\n updated: 0,\n unresolved: 0,\n skippedVirtual: 0,\n byEntity: {},\n }\n\n const rows = (await em.getConnection().execute(\n 'select id, entity_id, record_id, organization_id from attachments where tenant_id = ?',\n [tenantId],\n )) as AttachmentScanRow[]\n report.scanned = rows.length\n if (!rows.length) return report\n\n const groups = new Map<string, AttachmentScanRow[]>()\n for (const row of rows) {\n if (!row.id || !row.entity_id || !row.record_id) continue\n const list = groups.get(row.entity_id) ?? []\n list.push(row)\n groups.set(row.entity_id, list)\n }\n\n const pendingUpdates: Array<{ id: string; organizationId: string }> = []\n\n for (const [entityId, group] of groups) {\n const bucket = ensureBucket(report, entityId)\n bucket.scanned += group.length\n\n if (entityId === LIBRARY_ENTITY_ID) {\n report.skippedVirtual += group.length\n continue\n }\n\n const recordIds = Array.from(\n new Set(group.map((row) => row.record_id).filter((value): value is string => !!value)),\n )\n const parentOrgByRecordId = new Map<string, string | null>()\n let resolvable = true\n\n for (let index = 0; index < recordIds.length; index += batchSize) {\n const chunk = recordIds.slice(index, index + batchSize)\n try {\n const result = await queryEngine.query(entityId as any, {\n fields: ['id', 'organization_id'],\n filters: { id: chunk.length === 1 ? { $eq: chunk[0] } : { $in: chunk } },\n tenantId,\n withDeleted: true,\n page: { pageSize: Math.max(chunk.length, 1) },\n })\n for (const item of result.items ?? []) {\n const record = item as Record<string, unknown>\n const recordId = record.id != null ? String(record.id) : null\n if (!recordId) continue\n parentOrgByRecordId.set(recordId, readParentOrganizationId(record))\n }\n } catch (error) {\n resolvable = false\n logger.warn('org reconcile: cannot resolve parent organization for entity', {\n entityId,\n error,\n })\n break\n }\n }\n\n if (!resolvable) {\n bucket.unresolved += group.length\n report.unresolved += group.length\n continue\n }\n\n for (const row of group) {\n const target = row.record_id ? parentOrgByRecordId.get(row.record_id) : null\n if (!target) {\n bucket.unresolved += 1\n report.unresolved += 1\n continue\n }\n if ((row.organization_id ?? null) === target) continue\n pendingUpdates.push({ id: row.id, organizationId: target })\n bucket.updated += 1\n report.updated += 1\n }\n }\n\n for (let index = 0; index < pendingUpdates.length; index += batchSize) {\n const chunk = pendingUpdates.slice(index, index + batchSize)\n for (const update of chunk) {\n const reference = em.getReference(Attachment, update.id)\n reference.organizationId = update.organizationId\n }\n await em.flush()\n }\n\n return report\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,oBAAoB;AAE7B,SAAS,kBAAkB;AAE3B,MAAM,SAAS,aAAa,aAAa,EAAE,MAAM,EAAE,WAAW,wBAAwB,CAAC;AAOvF,MAAM,oBAAoB;AAE1B,MAAM,qBAAqB;AAuB3B,SAAS,yBAAyB,QAAgD;AAChF,QAAM,MAAM,OAAO,iBAAiB,KAAK,OAAO,gBAAgB;AAChE,MAAI,OAAO,QAAQ,YAAY,IAAI,KAAK,EAAE,OAAQ,QAAO,IAAI,KAAK;AAClE,SAAO;AACT;AAEA,SAAS,aACP,QACA,UACkC;AAClC,QAAM,WAAW,OAAO,SAAS,QAAQ;AACzC,MAAI,SAAU,QAAO;AACrB,QAAM,SAA2C,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,EAAE;AACzF,SAAO,SAAS,QAAQ,IAAI;AAC5B,SAAO;AACT;AA+BA,eAAsB,iCAAiC,MAKb;AACxC,QAAM,EAAE,IAAI,aAAa,SAAS,IAAI;AACtC,QAAM,YAAY,KAAK,aAAa,KAAK,YAAY,IAAI,KAAK,YAAY;AAC1E,QAAM,SAAuC;AAAA,IAC3C,SAAS;AAAA,IACT,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,UAAU,CAAC;AAAA,EACb;AAEA,QAAM,OAAQ,MAAM,GAAG,cAAc,EAAE;AAAA,IACrC;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AACA,SAAO,UAAU,KAAK;AACtB,MAAI,CAAC,KAAK,OAAQ,QAAO;AAEzB,QAAM,SAAS,oBAAI,IAAiC;AACpD,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,IAAI,MAAM,CAAC,IAAI,aAAa,CAAC,IAAI,UAAW;AACjD,UAAM,OAAO,OAAO,IAAI,IAAI,SAAS,KAAK,CAAC;AAC3C,SAAK,KAAK,GAAG;AACb,WAAO,IAAI,IAAI,WAAW,IAAI;AAAA,EAChC;AAEA,QAAM,iBAAgE,CAAC;AAEvE,aAAW,CAAC,UAAU,KAAK,KAAK,QAAQ;AACtC,UAAM,SAAS,aAAa,QAAQ,QAAQ;AAC5C,WAAO,WAAW,MAAM;AAExB,QAAI,aAAa,mBAAmB;AAClC,aAAO,kBAAkB,MAAM;AAC/B;AAAA,IACF;AAEA,UAAM,YAAY,MAAM;AAAA,MACtB,IAAI,IAAI,MAAM,IAAI,CAAC,QAAQ,IAAI,SAAS,EAAE,OAAO,CAAC,UAA2B,CAAC,CAAC,KAAK,CAAC;AAAA,IACvF;AACA,UAAM,sBAAsB,oBAAI,IAA2B;AAC3D,QAAI,aAAa;AAEjB,aAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,SAAS,WAAW;AAChE,YAAM,QAAQ,UAAU,MAAM,OAAO,QAAQ,SAAS;AACtD,UAAI;AACF,cAAM,SAAS,MAAM,YAAY,MAAM,UAAiB;AAAA,UACtD,QAAQ,CAAC,MAAM,iBAAiB;AAAA,UAChC,SAAS,EAAE,IAAI,MAAM,WAAW,IAAI,EAAE,KAAK,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE;AAAA,UACvE;AAAA,UACA,aAAa;AAAA,UACb,MAAM,EAAE,UAAU,KAAK,IAAI,MAAM,QAAQ,CAAC,EAAE;AAAA,QAC9C,CAAC;AACD,mBAAW,QAAQ,OAAO,SAAS,CAAC,GAAG;AACrC,gBAAM,SAAS;AACf,gBAAM,WAAW,OAAO,MAAM,OAAO,OAAO,OAAO,EAAE,IAAI;AACzD,cAAI,CAAC,SAAU;AACf,8BAAoB,IAAI,UAAU,yBAAyB,MAAM,CAAC;AAAA,QACpE;AAAA,MACF,SAAS,OAAO;AACd,qBAAa;AACb,eAAO,KAAK,gEAAgE;AAAA,UAC1E;AAAA,UACA;AAAA,QACF,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,YAAY;AACf,aAAO,cAAc,MAAM;AAC3B,aAAO,cAAc,MAAM;AAC3B;AAAA,IACF;AAEA,eAAW,OAAO,OAAO;AACvB,YAAM,SAAS,IAAI,YAAY,oBAAoB,IAAI,IAAI,SAAS,IAAI;AACxE,UAAI,CAAC,QAAQ;AACX,eAAO,cAAc;AACrB,eAAO,cAAc;AACrB;AAAA,MACF;AACA,WAAK,IAAI,mBAAmB,UAAU,OAAQ;AAC9C,qBAAe,KAAK,EAAE,IAAI,IAAI,IAAI,gBAAgB,OAAO,CAAC;AAC1D,aAAO,WAAW;AAClB,aAAO,WAAW;AAAA,IACpB;AAAA,EACF;AAEA,WAAS,QAAQ,GAAG,QAAQ,eAAe,QAAQ,SAAS,WAAW;AACrE,UAAM,QAAQ,eAAe,MAAM,OAAO,QAAQ,SAAS;AAC3D,eAAW,UAAU,OAAO;AAC1B,YAAM,YAAY,GAAG,aAAa,YAAY,OAAO,EAAE;AACvD,gBAAU,iBAAiB,OAAO;AAAA,IACpC;AACA,UAAM,GAAG,MAAM;AAAA,EACjB;AAEA,SAAO;AACT;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
2
|
-
async function resolveAttachmentOrganizationId(container, auth, request) {
|
|
3
|
-
if (!auth) return null;
|
|
4
|
-
const scope = await resolveOrganizationScopeForRequest({ container, auth, request });
|
|
5
|
-
return scope?.selectedId ?? auth.orgId ?? null;
|
|
6
|
-
}
|
|
7
|
-
export {
|
|
8
|
-
resolveAttachmentOrganizationId
|
|
9
|
-
};
|
|
10
|
-
//# sourceMappingURL=requestScope.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/attachments/lib/requestScope.ts"],
|
|
4
|
-
"sourcesContent": ["import type { AwilixContainer } from 'awilix'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\n\n/**\n * Resolve the organization an attachment request should act within.\n *\n * `auth.orgId` alone is NOT selected-organization aware for non-superadmin\n * principals: `applySuperAdminScope` only rewrites `orgId` from the\n * `om_selected_org` cookie for superadmins, so a regular multi-org admin who\n * switches the header organization keeps `auth.orgId` pinned to their own home\n * organization. The CRUD factory and other org-scoped routes derive the active\n * organization via `resolveOrganizationScopeForRequest` (cookie-driven and\n * RBAC-validated for ALL users, falling back to the home org when the selection\n * is absent or inaccessible). Attachments must do the same so uploaded files\n * land under \u2014 and are read back from \u2014 the currently selected organization\n * rather than the uploader's home organization (#3765).\n */\nexport async function resolveAttachmentOrganizationId(\n container: AwilixContainer,\n auth: AuthContext,\n request: Request,\n): Promise<string | null> {\n if (!auth) return null\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n return scope?.selectedId ?? auth.orgId ?? null\n}\n"],
|
|
5
|
-
"mappings": "AAEA,SAAS,0CAA0C;AAgBnD,eAAsB,gCACpB,WACA,MACA,SACwB;AACxB,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC;AACnF,SAAO,OAAO,cAAc,KAAK,SAAS;AAC5C;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
-
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
3
|
-
import { signJwt } from "@open-mercato/shared/lib/auth/jwt";
|
|
4
|
-
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
5
|
-
import { buildSafeRedirectResponse, resolveTrustedRedirectBase } from "@open-mercato/core/modules/auth/lib/requestRedirect";
|
|
6
|
-
import { sanitizeRedirectPath } from "@open-mercato/core/modules/auth/lib/safeRedirect";
|
|
7
|
-
import { resolveAutoLoginCredentials } from "@open-mercato/core/modules/auth/lib/autologin";
|
|
8
|
-
import { emitAuthEvent } from "@open-mercato/core/modules/auth/events";
|
|
9
|
-
const metadata = { requireAuth: false };
|
|
10
|
-
const accessTokenMaxAgeSeconds = 60 * 60 * 8;
|
|
11
|
-
const logger = createLogger("auth").child({ component: "autologin" });
|
|
12
|
-
async function GET(req) {
|
|
13
|
-
const url = new URL(req.url);
|
|
14
|
-
const baseUrl = resolveTrustedRedirectBase(req) ?? url.origin;
|
|
15
|
-
const redirectTo = sanitizeRedirectPath(url.searchParams.get("redirect"), baseUrl, "/backend");
|
|
16
|
-
const credentials = resolveAutoLoginCredentials();
|
|
17
|
-
if (!credentials) {
|
|
18
|
-
return buildSafeRedirectResponse(req, "/login");
|
|
19
|
-
}
|
|
20
|
-
const existing = await getAuthFromRequest(req);
|
|
21
|
-
if (existing) {
|
|
22
|
-
return buildSafeRedirectResponse(req, redirectTo);
|
|
23
|
-
}
|
|
24
|
-
const container = await createRequestContainer();
|
|
25
|
-
const auth = container.resolve("authService");
|
|
26
|
-
let user = null;
|
|
27
|
-
if (credentials.tenantId) {
|
|
28
|
-
user = await auth.findUserByEmailAndTenant(credentials.email, credentials.tenantId);
|
|
29
|
-
} else {
|
|
30
|
-
const users = await auth.findUsersByEmail(credentials.email);
|
|
31
|
-
user = users.length === 1 ? users[0] : null;
|
|
32
|
-
}
|
|
33
|
-
const ok = await auth.verifyPassword(user, credentials.password);
|
|
34
|
-
if (!user || !ok) {
|
|
35
|
-
logger.warn("OM_AUTOLOGIN credentials did not resolve to a single valid user; falling back to login");
|
|
36
|
-
return buildSafeRedirectResponse(req, "/login");
|
|
37
|
-
}
|
|
38
|
-
const resolvedTenantId = credentials.tenantId ?? (user.tenantId ? String(user.tenantId) : null);
|
|
39
|
-
const roles = await auth.getUserRoles(user, resolvedTenantId);
|
|
40
|
-
await auth.updateLastLoginAt(user);
|
|
41
|
-
const expiresAt = new Date(Date.now() + accessTokenMaxAgeSeconds * 1e3);
|
|
42
|
-
const { session } = await auth.createSession(user, expiresAt);
|
|
43
|
-
const token = signJwt({
|
|
44
|
-
sub: String(user.id),
|
|
45
|
-
sid: String(session.id),
|
|
46
|
-
tenantId: resolvedTenantId,
|
|
47
|
-
orgId: user.organizationId ? String(user.organizationId) : null,
|
|
48
|
-
email: user.email,
|
|
49
|
-
roles
|
|
50
|
-
});
|
|
51
|
-
void emitAuthEvent("auth.login.success", {
|
|
52
|
-
id: String(user.id),
|
|
53
|
-
email: user.email,
|
|
54
|
-
tenantId: resolvedTenantId,
|
|
55
|
-
organizationId: user.organizationId ? String(user.organizationId) : null
|
|
56
|
-
}).catch(() => void 0);
|
|
57
|
-
const res = buildSafeRedirectResponse(req, redirectTo);
|
|
58
|
-
res.cookies.set("auth_token", token, {
|
|
59
|
-
httpOnly: true,
|
|
60
|
-
path: "/",
|
|
61
|
-
sameSite: "lax",
|
|
62
|
-
secure: process.env.NODE_ENV === "production",
|
|
63
|
-
maxAge: accessTokenMaxAgeSeconds
|
|
64
|
-
});
|
|
65
|
-
return res;
|
|
66
|
-
}
|
|
67
|
-
const openApi = {
|
|
68
|
-
tag: "Authentication & Accounts",
|
|
69
|
-
summary: "Demo autologin",
|
|
70
|
-
methods: {
|
|
71
|
-
GET: {
|
|
72
|
-
summary: "Auto sign-in using env-configured demo credentials",
|
|
73
|
-
description: "When OM_AUTOLOGIN_EMAIL / OM_AUTOLOGIN_PASSWORD are configured, signs the visitor in with those credentials and redirects into the app. Intended for single-tenant demo instances only. Falls back to the login page when disabled or misconfigured.",
|
|
74
|
-
responses: [
|
|
75
|
-
{ status: 307, description: "Redirect into the app (or to /login on failure)", mediaType: "text/html" }
|
|
76
|
-
]
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
export {
|
|
81
|
-
GET,
|
|
82
|
-
metadata,
|
|
83
|
-
openApi
|
|
84
|
-
};
|
|
85
|
-
//# sourceMappingURL=autologin.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/auth/api/autologin.ts"],
|
|
4
|
-
"sourcesContent": ["import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { signJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { buildSafeRedirectResponse, resolveTrustedRedirectBase } from '@open-mercato/core/modules/auth/lib/requestRedirect'\nimport { sanitizeRedirectPath } from '@open-mercato/core/modules/auth/lib/safeRedirect'\nimport { resolveAutoLoginCredentials } from '@open-mercato/core/modules/auth/lib/autologin'\nimport { emitAuthEvent } from '@open-mercato/core/modules/auth/events'\n\nexport const metadata = { requireAuth: false }\n\nconst accessTokenMaxAgeSeconds = 60 * 60 * 8\nconst logger = createLogger('auth').child({ component: 'autologin' })\n\n// Demo-only convenience: when OM_AUTOLOGIN_* credentials are configured, sign the\n// visitor in with those credentials and redirect into the app. Gated entirely\n// behind env vars \u2014 the homepage only routes here when they are set. On any\n// failure (feature off, bad credentials) it falls back to the manual login form\n// so a misconfigured demo can never loop.\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const baseUrl = resolveTrustedRedirectBase(req) ?? url.origin\n const redirectTo = sanitizeRedirectPath(url.searchParams.get('redirect'), baseUrl, '/backend')\n\n const credentials = resolveAutoLoginCredentials()\n if (!credentials) {\n return buildSafeRedirectResponse(req, '/login')\n }\n\n // Already signed in \u2014 go straight to the app instead of re-issuing a session.\n const existing = await getAuthFromRequest(req)\n if (existing) {\n return buildSafeRedirectResponse(req, redirectTo)\n }\n\n const container = await createRequestContainer()\n const auth = container.resolve<AuthService>('authService')\n\n let user = null\n if (credentials.tenantId) {\n user = await auth.findUserByEmailAndTenant(credentials.email, credentials.tenantId)\n } else {\n const users = await auth.findUsersByEmail(credentials.email)\n user = users.length === 1 ? users[0] : null\n }\n\n const ok = await auth.verifyPassword(user, credentials.password)\n if (!user || !ok) {\n // Misconfigured demo credentials \u2014 never loop; drop to the manual form.\n logger.warn('OM_AUTOLOGIN credentials did not resolve to a single valid user; falling back to login')\n return buildSafeRedirectResponse(req, '/login')\n }\n\n const resolvedTenantId = credentials.tenantId ?? (user.tenantId ? String(user.tenantId) : null)\n const roles = await auth.getUserRoles(user, resolvedTenantId)\n await auth.updateLastLoginAt(user)\n const expiresAt = new Date(Date.now() + accessTokenMaxAgeSeconds * 1000)\n const { session } = await auth.createSession(user, expiresAt)\n const token = signJwt({\n sub: String(user.id),\n sid: String(session.id),\n tenantId: resolvedTenantId,\n orgId: user.organizationId ? String(user.organizationId) : null,\n email: user.email,\n roles,\n })\n void emitAuthEvent('auth.login.success', {\n id: String(user.id),\n email: user.email,\n tenantId: resolvedTenantId,\n organizationId: user.organizationId ? String(user.organizationId) : null,\n }).catch(() => undefined)\n\n const res = buildSafeRedirectResponse(req, redirectTo)\n res.cookies.set('auth_token', token, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge: accessTokenMaxAgeSeconds,\n })\n return res\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'Demo autologin',\n methods: {\n GET: {\n summary: 'Auto sign-in using env-configured demo credentials',\n description:\n 'When OM_AUTOLOGIN_EMAIL / OM_AUTOLOGIN_PASSWORD are configured, signs the visitor in with those credentials and redirects into the app. Intended for single-tenant demo instances only. Falls back to the login page when disabled or misconfigured.',\n responses: [\n { status: 307, description: 'Redirect into the app (or to /login on failure)', mediaType: 'text/html' },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,oBAAoB;AAE7B,SAAS,eAAe;AACxB,SAAS,0BAA0B;AACnC,SAAS,2BAA2B,kCAAkC;AACtE,SAAS,4BAA4B;AACrC,SAAS,mCAAmC;AAC5C,SAAS,qBAAqB;AAEvB,MAAM,WAAW,EAAE,aAAa,MAAM;AAE7C,MAAM,2BAA2B,KAAK,KAAK;AAC3C,MAAM,SAAS,aAAa,MAAM,EAAE,MAAM,EAAE,WAAW,YAAY,CAAC;AAOpE,eAAsB,IAAI,KAAc;AACtC,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,QAAM,UAAU,2BAA2B,GAAG,KAAK,IAAI;AACvD,QAAM,aAAa,qBAAqB,IAAI,aAAa,IAAI,UAAU,GAAG,SAAS,UAAU;AAE7F,QAAM,cAAc,4BAA4B;AAChD,MAAI,CAAC,aAAa;AAChB,WAAO,0BAA0B,KAAK,QAAQ;AAAA,EAChD;AAGA,QAAM,WAAW,MAAM,mBAAmB,GAAG;AAC7C,MAAI,UAAU;AACZ,WAAO,0BAA0B,KAAK,UAAU;AAAA,EAClD;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,OAAO,UAAU,QAAqB,aAAa;AAEzD,MAAI,OAAO;AACX,MAAI,YAAY,UAAU;AACxB,WAAO,MAAM,KAAK,yBAAyB,YAAY,OAAO,YAAY,QAAQ;AAAA,EACpF,OAAO;AACL,UAAM,QAAQ,MAAM,KAAK,iBAAiB,YAAY,KAAK;AAC3D,WAAO,MAAM,WAAW,IAAI,MAAM,CAAC,IAAI;AAAA,EACzC;AAEA,QAAM,KAAK,MAAM,KAAK,eAAe,MAAM,YAAY,QAAQ;AAC/D,MAAI,CAAC,QAAQ,CAAC,IAAI;AAEhB,WAAO,KAAK,wFAAwF;AACpG,WAAO,0BAA0B,KAAK,QAAQ;AAAA,EAChD;AAEA,QAAM,mBAAmB,YAAY,aAAa,KAAK,WAAW,OAAO,KAAK,QAAQ,IAAI;AAC1F,QAAM,QAAQ,MAAM,KAAK,aAAa,MAAM,gBAAgB;AAC5D,QAAM,KAAK,kBAAkB,IAAI;AACjC,QAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,2BAA2B,GAAI;AACvE,QAAM,EAAE,QAAQ,IAAI,MAAM,KAAK,cAAc,MAAM,SAAS;AAC5D,QAAM,QAAQ,QAAQ;AAAA,IACpB,KAAK,OAAO,KAAK,EAAE;AAAA,IACnB,KAAK,OAAO,QAAQ,EAAE;AAAA,IACtB,UAAU;AAAA,IACV,OAAO,KAAK,iBAAiB,OAAO,KAAK,cAAc,IAAI;AAAA,IAC3D,OAAO,KAAK;AAAA,IACZ;AAAA,EACF,CAAC;AACD,OAAK,cAAc,sBAAsB;AAAA,IACvC,IAAI,OAAO,KAAK,EAAE;AAAA,IAClB,OAAO,KAAK;AAAA,IACZ,UAAU;AAAA,IACV,gBAAgB,KAAK,iBAAiB,OAAO,KAAK,cAAc,IAAI;AAAA,EACtE,CAAC,EAAE,MAAM,MAAM,MAAS;AAExB,QAAM,MAAM,0BAA0B,KAAK,UAAU;AACrD,MAAI,QAAQ,IAAI,cAAc,OAAO;AAAA,IACnC,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,IACjC,QAAQ;AAAA,EACV,CAAC;AACD,SAAO;AACT;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aACE;AAAA,MACF,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,mDAAmD,WAAW,YAAY;AAAA,MACxG;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
function readEnvValue(env, key) {
|
|
2
|
-
const value = env[key];
|
|
3
|
-
return typeof value === "string" ? value.trim() : "";
|
|
4
|
-
}
|
|
5
|
-
function resolveAutoLoginCredentials(env = process.env) {
|
|
6
|
-
const email = readEnvValue(env, "OM_AUTOLOGIN_EMAIL");
|
|
7
|
-
const password = env.OM_AUTOLOGIN_PASSWORD ?? "";
|
|
8
|
-
if (!email || !password) return null;
|
|
9
|
-
const tenantId = readEnvValue(env, "OM_AUTOLOGIN_TENANT");
|
|
10
|
-
return { email, password, tenantId: tenantId || null };
|
|
11
|
-
}
|
|
12
|
-
function isAutoLoginEnabled(env = process.env) {
|
|
13
|
-
return resolveAutoLoginCredentials(env) !== null;
|
|
14
|
-
}
|
|
15
|
-
export {
|
|
16
|
-
isAutoLoginEnabled,
|
|
17
|
-
resolveAutoLoginCredentials
|
|
18
|
-
};
|
|
19
|
-
//# sourceMappingURL=autologin.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/auth/lib/autologin.ts"],
|
|
4
|
-
"sourcesContent": ["export type AutoLoginCredentials = {\n email: string\n password: string\n tenantId: string | null\n}\n\nfunction readEnvValue(env: Record<string, string | undefined>, key: string): string {\n const value = env[key]\n return typeof value === 'string' ? value.trim() : ''\n}\n\n/**\n * Reads the optional demo-autologin credentials from env. When both\n * `OM_AUTOLOGIN_EMAIL` and `OM_AUTOLOGIN_PASSWORD` are set, the homepage hands\n * unauthenticated visitors to the autologin route which signs them in and drops\n * them into the app. Unset (the default) \u2192 `null` \u2192 normal login flow.\n *\n * `OM_AUTOLOGIN_TENANT` is optional and only needed when the same email exists\n * across multiple tenants. Pure: pass the env bag so it stays testable.\n */\nexport function resolveAutoLoginCredentials(\n env: Record<string, string | undefined> = process.env,\n): AutoLoginCredentials | null {\n const email = readEnvValue(env, 'OM_AUTOLOGIN_EMAIL')\n const password = env.OM_AUTOLOGIN_PASSWORD ?? ''\n if (!email || !password) return null\n const tenantId = readEnvValue(env, 'OM_AUTOLOGIN_TENANT')\n return { email, password, tenantId: tenantId || null }\n}\n\n/** True when demo autologin credentials are configured via env. */\nexport function isAutoLoginEnabled(\n env: Record<string, string | undefined> = process.env,\n): boolean {\n return resolveAutoLoginCredentials(env) !== null\n}\n"],
|
|
5
|
-
"mappings": "AAMA,SAAS,aAAa,KAAyC,KAAqB;AAClF,QAAM,QAAQ,IAAI,GAAG;AACrB,SAAO,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;AACpD;AAWO,SAAS,4BACd,MAA0C,QAAQ,KACrB;AAC7B,QAAM,QAAQ,aAAa,KAAK,oBAAoB;AACpD,QAAM,WAAW,IAAI,yBAAyB;AAC9C,MAAI,CAAC,SAAS,CAAC,SAAU,QAAO;AAChC,QAAM,WAAW,aAAa,KAAK,qBAAqB;AACxD,SAAO,EAAE,OAAO,UAAU,UAAU,YAAY,KAAK;AACvD;AAGO,SAAS,mBACd,MAA0C,QAAQ,KACzC;AACT,SAAO,4BAA4B,GAAG,MAAM;AAC9C;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import { useBackendChrome } from "@open-mercato/ui/backend/BackendChromeProvider";
|
|
4
|
-
import { hasFeature } from "@open-mercato/shared/security/features";
|
|
5
|
-
function useDealsAccess() {
|
|
6
|
-
const { payload, isReady } = useBackendChrome();
|
|
7
|
-
const canViewDeals = React.useMemo(
|
|
8
|
-
() => hasFeature(payload?.grantedFeatures ?? [], "customers.deals.view"),
|
|
9
|
-
[payload?.grantedFeatures]
|
|
10
|
-
);
|
|
11
|
-
return { canViewDeals, isReady };
|
|
12
|
-
}
|
|
13
|
-
export {
|
|
14
|
-
useDealsAccess
|
|
15
|
-
};
|
|
16
|
-
//# sourceMappingURL=useDealsAccess.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/modules/customers/components/detail/useDealsAccess.ts"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useBackendChrome } from '@open-mercato/ui/backend/BackendChromeProvider'\nimport { hasFeature } from '@open-mercato/shared/security/features'\n\nexport type DealsAccess = {\n canViewDeals: boolean\n isReady: boolean\n}\n\nexport function useDealsAccess(): DealsAccess {\n const { payload, isReady } = useBackendChrome()\n const canViewDeals = React.useMemo(\n () => hasFeature(payload?.grantedFeatures ?? [], 'customers.deals.view'),\n [payload?.grantedFeatures],\n )\n return { canViewDeals, isReady }\n}\n"],
|
|
5
|
-
"mappings": ";AAEA,YAAY,WAAW;AACvB,SAAS,wBAAwB;AACjC,SAAS,kBAAkB;AAOpB,SAAS,iBAA8B;AAC5C,QAAM,EAAE,SAAS,QAAQ,IAAI,iBAAiB;AAC9C,QAAM,eAAe,MAAM;AAAA,IACzB,MAAM,WAAW,SAAS,mBAAmB,CAAC,GAAG,sBAAsB;AAAA,IACvE,CAAC,SAAS,eAAe;AAAA,EAC3B;AACA,SAAO,EAAE,cAAc,QAAQ;AACjC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { UniqueConstraintViolationException } from "@mikro-orm/core";
|
|
3
|
-
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
4
|
-
import { GatewaySessionInitialization } from "../data/entities.js";
|
|
5
|
-
function buildPaymentSessionOperationKey(input) {
|
|
6
|
-
const digest = createHash("sha256").update(JSON.stringify([
|
|
7
|
-
input.scope.tenantId,
|
|
8
|
-
input.scope.organizationId,
|
|
9
|
-
input.providerKey,
|
|
10
|
-
input.paymentId,
|
|
11
|
-
input.idempotencyKey
|
|
12
|
-
])).digest("hex");
|
|
13
|
-
return `om-payment-session:${digest}`;
|
|
14
|
-
}
|
|
15
|
-
async function findPaymentSessionInitialization(em, operationKey, providerKey, scope) {
|
|
16
|
-
return findOneWithDecryption(
|
|
17
|
-
em.fork(),
|
|
18
|
-
GatewaySessionInitialization,
|
|
19
|
-
{
|
|
20
|
-
operationKey,
|
|
21
|
-
providerKey,
|
|
22
|
-
organizationId: scope.organizationId,
|
|
23
|
-
tenantId: scope.tenantId
|
|
24
|
-
},
|
|
25
|
-
void 0,
|
|
26
|
-
scope
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
async function claimPaymentSessionInitialization(em, operationKey, providerKey, scope, claimedAt) {
|
|
30
|
-
const claimEm = em.fork();
|
|
31
|
-
const claimToken = randomUUID();
|
|
32
|
-
const record = claimEm.create(GatewaySessionInitialization, {
|
|
33
|
-
operationKey,
|
|
34
|
-
providerKey,
|
|
35
|
-
claimToken,
|
|
36
|
-
claimedAt,
|
|
37
|
-
gatewayTransactionId: null,
|
|
38
|
-
organizationId: scope.organizationId,
|
|
39
|
-
tenantId: scope.tenantId
|
|
40
|
-
});
|
|
41
|
-
try {
|
|
42
|
-
await claimEm.persist(record).flush();
|
|
43
|
-
return { id: record.id, claimToken };
|
|
44
|
-
} catch (error) {
|
|
45
|
-
if (error instanceof UniqueConstraintViolationException) return null;
|
|
46
|
-
throw error;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async function reclaimPaymentSessionInitialization(em, claim, scope, claimedAt, staleBefore) {
|
|
50
|
-
const claimToken = randomUUID();
|
|
51
|
-
const claimedRows = await em.fork().nativeUpdate(
|
|
52
|
-
GatewaySessionInitialization,
|
|
53
|
-
{
|
|
54
|
-
id: claim.id,
|
|
55
|
-
operationKey: claim.operationKey,
|
|
56
|
-
providerKey: claim.providerKey,
|
|
57
|
-
organizationId: scope.organizationId,
|
|
58
|
-
tenantId: scope.tenantId,
|
|
59
|
-
gatewayTransactionId: null,
|
|
60
|
-
$or: [
|
|
61
|
-
{ claimToken: null },
|
|
62
|
-
{ claimedAt: { $lt: staleBefore } }
|
|
63
|
-
]
|
|
64
|
-
},
|
|
65
|
-
{ claimToken, claimedAt, updatedAt: claimedAt }
|
|
66
|
-
);
|
|
67
|
-
return claimedRows > 0 ? { id: claim.id, claimToken } : null;
|
|
68
|
-
}
|
|
69
|
-
async function releasePaymentSessionInitialization(em, ownership, scope) {
|
|
70
|
-
await em.fork().nativeUpdate(
|
|
71
|
-
GatewaySessionInitialization,
|
|
72
|
-
{
|
|
73
|
-
id: ownership.id,
|
|
74
|
-
claimToken: ownership.claimToken,
|
|
75
|
-
organizationId: scope.organizationId,
|
|
76
|
-
tenantId: scope.tenantId,
|
|
77
|
-
gatewayTransactionId: null
|
|
78
|
-
},
|
|
79
|
-
{ claimToken: null, claimedAt: null, updatedAt: /* @__PURE__ */ new Date() }
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
async function refreshPaymentSessionInitialization(em, ownership, scope, claimedAt) {
|
|
83
|
-
const refreshedRows = await em.fork().nativeUpdate(
|
|
84
|
-
GatewaySessionInitialization,
|
|
85
|
-
{
|
|
86
|
-
id: ownership.id,
|
|
87
|
-
claimToken: ownership.claimToken,
|
|
88
|
-
organizationId: scope.organizationId,
|
|
89
|
-
tenantId: scope.tenantId,
|
|
90
|
-
gatewayTransactionId: null
|
|
91
|
-
},
|
|
92
|
-
{ claimedAt, updatedAt: claimedAt }
|
|
93
|
-
);
|
|
94
|
-
return refreshedRows > 0;
|
|
95
|
-
}
|
|
96
|
-
export {
|
|
97
|
-
buildPaymentSessionOperationKey,
|
|
98
|
-
claimPaymentSessionInitialization,
|
|
99
|
-
findPaymentSessionInitialization,
|
|
100
|
-
reclaimPaymentSessionInitialization,
|
|
101
|
-
refreshPaymentSessionInitialization,
|
|
102
|
-
releasePaymentSessionInitialization
|
|
103
|
-
};
|
|
104
|
-
//# sourceMappingURL=session-idempotency.js.map
|