@open-mercato/core 0.6.8-develop.6983.1.e4f794099e → 0.6.8-develop.6985.1.fb93574faa
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/notification/index.js +6 -0
- package/dist/generated/entities/notification/index.js.map +2 -2
- package/dist/generated/entities/notification_preference/index.js +19 -0
- package/dist/generated/entities/notification_preference/index.js.map +7 -0
- package/dist/generated/entities/notification_type/index.js +21 -0
- package/dist/generated/entities/notification_type/index.js.map +7 -0
- package/dist/generated/entities/notification_type_override/index.js +17 -0
- package/dist/generated/entities/notification_type_override/index.js.map +7 -0
- package/dist/generated/entities/push_notification_delivery/index.js +41 -0
- package/dist/generated/entities/push_notification_delivery/index.js.map +7 -0
- package/dist/generated/entities/user_device/index.js +35 -0
- package/dist/generated/entities/user_device/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +12 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +72 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/api.js +2 -1
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/appRoot.js +9 -0
- package/dist/helpers/integration/appRoot.js.map +7 -0
- package/dist/helpers/integration/dbFixtures.js +1 -4
- package/dist/helpers/integration/dbFixtures.js.map +2 -2
- package/dist/helpers/integration/pushFake.js +126 -0
- package/dist/helpers/integration/pushFake.js.map +7 -0
- package/dist/modules/auth/notifications.js +16 -0
- package/dist/modules/auth/notifications.js.map +2 -2
- package/dist/modules/business_rules/notifications.js +2 -0
- package/dist/modules/business_rules/notifications.js.map +2 -2
- package/dist/modules/catalog/notifications.js +2 -0
- package/dist/modules/catalog/notifications.js.map +2 -2
- package/dist/modules/communication_channels/acl.js +9 -0
- package/dist/modules/communication_channels/acl.js.map +2 -2
- package/dist/modules/communication_channels/api/delete/admin/channels/[id]/route.js +133 -0
- package/dist/modules/communication_channels/api/delete/admin/channels/[id]/route.js.map +7 -0
- package/dist/modules/communication_channels/api/get/channels/[id]/health/route.js +6 -2
- package/dist/modules/communication_channels/api/get/channels/[id]/health/route.js.map +2 -2
- package/dist/modules/communication_channels/api/get/channels/[id]/route.js +6 -2
- package/dist/modules/communication_channels/api/get/channels/[id]/route.js.map +2 -2
- package/dist/modules/communication_channels/api/get/channels/route.js +2 -1
- package/dist/modules/communication_channels/api/get/channels/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +10 -5
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js +29 -1
- package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js +157 -0
- package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js.map +7 -0
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +8 -1
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/communication_channels/commands/admin-delete-channel.js +141 -0
- package/dist/modules/communication_channels/commands/admin-delete-channel.js.map +7 -0
- package/dist/modules/communication_channels/commands/connect-credential-channel.js +25 -8
- package/dist/modules/communication_channels/commands/connect-credential-channel.js.map +2 -2
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js +2 -2
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +2 -2
- package/dist/modules/communication_channels/commands/push-register.js +1 -1
- package/dist/modules/communication_channels/commands/push-register.js.map +2 -2
- package/dist/modules/communication_channels/commands/push-unregister.js +4 -3
- package/dist/modules/communication_channels/commands/push-unregister.js.map +2 -2
- package/dist/modules/communication_channels/data/entities.js +4 -0
- package/dist/modules/communication_channels/data/entities.js.map +2 -2
- package/dist/modules/communication_channels/data/validators.js +2 -1
- package/dist/modules/communication_channels/data/validators.js.map +2 -2
- package/dist/modules/communication_channels/lib/access-control.js +11 -1
- package/dist/modules/communication_channels/lib/access-control.js.map +2 -2
- package/dist/modules/communication_channels/lib/connect-channel.js +20 -12
- package/dist/modules/communication_channels/lib/connect-channel.js.map +2 -2
- package/dist/modules/communication_channels/lib/push-adapter.js +68 -0
- package/dist/modules/communication_channels/lib/push-adapter.js.map +7 -0
- package/dist/modules/communication_channels/lib/push-capabilities.js +31 -0
- package/dist/modules/communication_channels/lib/push-capabilities.js.map +7 -0
- package/dist/modules/communication_channels/lib/push-connect-error.js +20 -0
- package/dist/modules/communication_channels/lib/push-connect-error.js.map +7 -0
- package/dist/modules/communication_channels/lib/push-credential-errors.js +41 -0
- package/dist/modules/communication_channels/lib/push-credential-errors.js.map +7 -0
- package/dist/modules/communication_channels/lib/push-envelope.js +46 -0
- package/dist/modules/communication_channels/lib/push-envelope.js.map +7 -0
- package/dist/modules/communication_channels/lib/refcounted-client-cache.js +64 -0
- package/dist/modules/communication_channels/lib/refcounted-client-cache.js.map +7 -0
- package/dist/modules/communication_channels/migrations/Migration20260703123630_communication_channels.js +13 -0
- package/dist/modules/communication_channels/migrations/Migration20260703123630_communication_channels.js.map +7 -0
- package/dist/modules/communication_channels/notifications.js +4 -0
- package/dist/modules/communication_channels/notifications.js.map +2 -2
- package/dist/modules/communication_channels/setup.js +2 -0
- package/dist/modules/communication_channels/setup.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +21 -0
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customer_accounts/notifications.js +12 -0
- package/dist/modules/customer_accounts/notifications.js.map +2 -2
- package/dist/modules/customers/notifications.js +4 -0
- package/dist/modules/customers/notifications.js.map +2 -2
- package/dist/modules/devices/acl.js +11 -0
- package/dist/modules/devices/acl.js.map +7 -0
- package/dist/modules/devices/api/[id]/route.js +167 -0
- package/dist/modules/devices/api/[id]/route.js.map +7 -0
- package/dist/modules/devices/api/admin/devices/[id]/route.js +219 -0
- package/dist/modules/devices/api/admin/devices/[id]/route.js.map +7 -0
- package/dist/modules/devices/api/admin/devices/route.js +140 -0
- package/dist/modules/devices/api/admin/devices/route.js.map +7 -0
- package/dist/modules/devices/api/auth.js +9 -0
- package/dist/modules/devices/api/auth.js.map +7 -0
- package/dist/modules/devices/api/deviceList.js +53 -0
- package/dist/modules/devices/api/deviceList.js.map +7 -0
- package/dist/modules/devices/api/deviceOps.js +118 -0
- package/dist/modules/devices/api/deviceOps.js.map +7 -0
- package/dist/modules/devices/api/openapi.js +19 -0
- package/dist/modules/devices/api/openapi.js.map +7 -0
- package/dist/modules/devices/api/route.js +143 -0
- package/dist/modules/devices/api/route.js.map +7 -0
- package/dist/modules/devices/backend/devices/[id]/page.js +135 -0
- package/dist/modules/devices/backend/devices/[id]/page.js.map +7 -0
- package/dist/modules/devices/backend/devices/[id]/page.meta.js +16 -0
- package/dist/modules/devices/backend/devices/[id]/page.meta.js.map +7 -0
- package/dist/modules/devices/backend/devices/create/page.js +68 -0
- package/dist/modules/devices/backend/devices/create/page.js.map +7 -0
- package/dist/modules/devices/backend/devices/create/page.meta.js +16 -0
- package/dist/modules/devices/backend/devices/create/page.meta.js.map +7 -0
- package/dist/modules/devices/backend/devices/page.js +235 -0
- package/dist/modules/devices/backend/devices/page.js.map +7 -0
- package/dist/modules/devices/backend/devices/page.meta.js +23 -0
- package/dist/modules/devices/backend/devices/page.meta.js.map +7 -0
- package/dist/modules/devices/commands/deactivate.js +107 -0
- package/dist/modules/devices/commands/deactivate.js.map +7 -0
- package/dist/modules/devices/commands/index.js +4 -0
- package/dist/modules/devices/commands/index.js.map +7 -0
- package/dist/modules/devices/commands/register.js +183 -0
- package/dist/modules/devices/commands/register.js.map +7 -0
- package/dist/modules/devices/commands/shared.js +74 -0
- package/dist/modules/devices/commands/shared.js.map +7 -0
- package/dist/modules/devices/commands/update.js +126 -0
- package/dist/modules/devices/commands/update.js.map +7 -0
- package/dist/modules/devices/data/entities.js +83 -0
- package/dist/modules/devices/data/entities.js.map +7 -0
- package/dist/modules/devices/data/validators.js +49 -0
- package/dist/modules/devices/data/validators.js.map +7 -0
- package/dist/modules/devices/di.js +11 -0
- package/dist/modules/devices/di.js.map +7 -0
- package/dist/modules/devices/encryption.js +12 -0
- package/dist/modules/devices/encryption.js.map +7 -0
- package/dist/modules/devices/events.js +19 -0
- package/dist/modules/devices/events.js.map +7 -0
- package/dist/modules/devices/index.js +17 -0
- package/dist/modules/devices/index.js.map +7 -0
- package/dist/modules/devices/lib/operationMetadata.js +20 -0
- package/dist/modules/devices/lib/operationMetadata.js.map +7 -0
- package/dist/modules/devices/migrations/Migration20260602120000.js +15 -0
- package/dist/modules/devices/migrations/Migration20260602120000.js.map +7 -0
- package/dist/modules/devices/migrations/Migration20260630120000.js +15 -0
- package/dist/modules/devices/migrations/Migration20260630120000.js.map +7 -0
- package/dist/modules/devices/migrations/Migration20260701120000.js +13 -0
- package/dist/modules/devices/migrations/Migration20260701120000.js.map +7 -0
- package/dist/modules/devices/migrations/Migration20260721120000.js +15 -0
- package/dist/modules/devices/migrations/Migration20260721120000.js.map +7 -0
- package/dist/modules/devices/setup.js +13 -0
- package/dist/modules/devices/setup.js.map +7 -0
- package/dist/modules/entities/cli.js +8 -3
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/migrations/Migration20260722120000.js +28 -0
- package/dist/modules/entities/migrations/Migration20260722120000.js.map +7 -0
- package/dist/modules/inbox_ops/notifications.js +2 -0
- package/dist/modules/inbox_ops/notifications.js.map +2 -2
- package/dist/modules/messages/notifications.js +2 -0
- package/dist/modules/messages/notifications.js.map +2 -2
- package/dist/modules/notifications/acl.js +3 -1
- package/dist/modules/notifications/acl.js.map +2 -2
- package/dist/modules/notifications/api/admin/preferences/route.js +167 -0
- package/dist/modules/notifications/api/admin/preferences/route.js.map +7 -0
- package/dist/modules/notifications/api/channels/route.js +54 -0
- package/dist/modules/notifications/api/channels/route.js.map +7 -0
- package/dist/modules/notifications/api/preferences/route.js +126 -0
- package/dist/modules/notifications/api/preferences/route.js.map +7 -0
- package/dist/modules/notifications/api/route.js +8 -1
- package/dist/modules/notifications/api/route.js.map +2 -2
- package/dist/modules/notifications/api/types/[id]/channels/[channel]/route.js +187 -0
- package/dist/modules/notifications/api/types/[id]/channels/[channel]/route.js.map +7 -0
- package/dist/modules/notifications/api/types/route.js +225 -0
- package/dist/modules/notifications/api/types/route.js.map +7 -0
- package/dist/modules/notifications/api/unread-count/route.js +5 -1
- package/dist/modules/notifications/api/unread-count/route.js.map +2 -2
- package/dist/modules/notifications/backend/notifications/user-preferences/page.js +10 -0
- package/dist/modules/notifications/backend/notifications/user-preferences/page.js.map +7 -0
- package/dist/modules/notifications/backend/notifications/user-preferences/page.meta.js +28 -0
- package/dist/modules/notifications/backend/notifications/user-preferences/page.meta.js.map +7 -0
- package/dist/modules/notifications/backend/profile/notification-preferences/page.js +10 -0
- package/dist/modules/notifications/backend/profile/notification-preferences/page.js.map +7 -0
- package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js +33 -0
- package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js.map +7 -0
- package/dist/modules/notifications/data/entities.js +128 -1
- package/dist/modules/notifications/data/entities.js.map +2 -2
- package/dist/modules/notifications/data/validators.js +95 -2
- package/dist/modules/notifications/data/validators.js.map +2 -2
- package/dist/modules/notifications/di.js +7 -0
- package/dist/modules/notifications/di.js.map +2 -2
- package/dist/modules/notifications/events.js +17 -0
- package/dist/modules/notifications/events.js.map +2 -2
- package/dist/modules/notifications/frontend/NotificationPreferenceMatrix.js +190 -0
- package/dist/modules/notifications/frontend/NotificationPreferenceMatrix.js.map +7 -0
- package/dist/modules/notifications/frontend/NotificationPreferencesPageClient.js +124 -0
- package/dist/modules/notifications/frontend/NotificationPreferencesPageClient.js.map +7 -0
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +166 -1
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +2 -2
- package/dist/modules/notifications/frontend/NotificationUserPreferencesAdminPageClient.js +172 -0
- package/dist/modules/notifications/frontend/NotificationUserPreferencesAdminPageClient.js.map +7 -0
- package/dist/modules/notifications/generators.js +63 -0
- package/dist/modules/notifications/generators.js.map +7 -0
- package/dist/modules/notifications/lib/delivery-strategies-registry.js +19 -0
- package/dist/modules/notifications/lib/delivery-strategies-registry.js.map +7 -0
- package/dist/modules/notifications/lib/deliveryStrategies.js.map +2 -2
- package/dist/modules/notifications/lib/derive-category.js +8 -0
- package/dist/modules/notifications/lib/derive-category.js.map +7 -0
- package/dist/modules/notifications/lib/notification-channel-registry.js +35 -0
- package/dist/modules/notifications/lib/notification-channel-registry.js.map +7 -0
- package/dist/modules/notifications/lib/notification-type-registry.js +87 -0
- package/dist/modules/notifications/lib/notification-type-registry.js.map +7 -0
- package/dist/modules/notifications/lib/notificationCopy.js +14 -0
- package/dist/modules/notifications/lib/notificationCopy.js.map +7 -0
- package/dist/modules/notifications/lib/notificationFactory.js +4 -1
- package/dist/modules/notifications/lib/notificationFactory.js.map +2 -2
- package/dist/modules/notifications/lib/notificationMapper.js +2 -0
- package/dist/modules/notifications/lib/notificationMapper.js.map +2 -2
- package/dist/modules/notifications/lib/notificationPreferenceService.js +83 -0
- package/dist/modules/notifications/lib/notificationPreferenceService.js.map +7 -0
- package/dist/modules/notifications/lib/notificationService.js +83 -28
- package/dist/modules/notifications/lib/notificationService.js.map +2 -2
- package/dist/modules/notifications/lib/notificationVisibility.js +24 -0
- package/dist/modules/notifications/lib/notificationVisibility.js.map +7 -0
- package/dist/modules/notifications/lib/routeHelpers.js +11 -1
- package/dist/modules/notifications/lib/routeHelpers.js.map +2 -2
- package/dist/modules/notifications/lib/shouldDeliver.js +46 -0
- package/dist/modules/notifications/lib/shouldDeliver.js.map +7 -0
- package/dist/modules/notifications/lib/strategies/email-delivery-strategy.js +54 -0
- package/dist/modules/notifications/lib/strategies/email-delivery-strategy.js.map +7 -0
- package/dist/modules/notifications/lib/strategies/in-app-delivery-strategy.js +12 -0
- package/dist/modules/notifications/lib/strategies/in-app-delivery-strategy.js.map +7 -0
- package/dist/modules/notifications/lib/typeCatalogue.js +71 -0
- package/dist/modules/notifications/lib/typeCatalogue.js.map +7 -0
- package/dist/modules/notifications/lib/typeChannelSettings.js +12 -0
- package/dist/modules/notifications/lib/typeChannelSettings.js.map +7 -0
- package/dist/modules/notifications/lib/typeOverrides.js +19 -0
- package/dist/modules/notifications/lib/typeOverrides.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260625122947_notifications.js +14 -0
- package/dist/modules/notifications/migrations/Migration20260625122947_notifications.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.js +15 -0
- package/dist/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.js +13 -0
- package/dist/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260626140000_notifications_type_category_silent.js +15 -0
- package/dist/modules/notifications/migrations/Migration20260626140000_notifications_type_category_silent.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260706120000_notifications_channels.js +13 -0
- package/dist/modules/notifications/migrations/Migration20260706120000_notifications_channels.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260716123121_notifications.js +14 -0
- package/dist/modules/notifications/migrations/Migration20260716123121_notifications.js.map +7 -0
- package/dist/modules/notifications/notification-channels.js +26 -0
- package/dist/modules/notifications/notification-channels.js.map +7 -0
- package/dist/modules/notifications/notifications.delivery-strategies.js +12 -0
- package/dist/modules/notifications/notifications.delivery-strategies.js.map +7 -0
- package/dist/modules/notifications/setup.js +16 -1
- package/dist/modules/notifications/setup.js.map +2 -2
- package/dist/modules/notifications/subscribers/deliver-notification.js +66 -57
- package/dist/modules/notifications/subscribers/deliver-notification.js.map +2 -2
- package/dist/modules/notifications/subscribers/sync-notification-types.js +16 -0
- package/dist/modules/notifications/subscribers/sync-notification-types.js.map +7 -0
- package/dist/modules/notifications/widgets/injection/profile-preferences-menu/widget.js +23 -0
- package/dist/modules/notifications/widgets/injection/profile-preferences-menu/widget.js.map +7 -0
- package/dist/modules/notifications/widgets/injection-table.js +14 -0
- package/dist/modules/notifications/widgets/injection-table.js.map +7 -0
- package/dist/modules/push_notifications/acl.js +13 -0
- package/dist/modules/push_notifications/acl.js.map +7 -0
- package/dist/modules/push_notifications/api/custom-send/route.js +141 -0
- package/dist/modules/push_notifications/api/custom-send/route.js.map +7 -0
- package/dist/modules/push_notifications/api/deliveries/[id]/route.js +110 -0
- package/dist/modules/push_notifications/api/deliveries/[id]/route.js.map +7 -0
- package/dist/modules/push_notifications/api/deliveries/route.js +56 -0
- package/dist/modules/push_notifications/api/deliveries/route.js.map +7 -0
- package/dist/modules/push_notifications/api/openapi.js +19 -0
- package/dist/modules/push_notifications/api/openapi.js.map +7 -0
- package/dist/modules/push_notifications/backend/push_notifications/[id]/page.js +103 -0
- package/dist/modules/push_notifications/backend/push_notifications/[id]/page.js.map +7 -0
- package/dist/modules/push_notifications/backend/push_notifications/[id]/page.meta.js +13 -0
- package/dist/modules/push_notifications/backend/push_notifications/[id]/page.meta.js.map +7 -0
- package/dist/modules/push_notifications/backend/push_notifications/page.js +213 -0
- package/dist/modules/push_notifications/backend/push_notifications/page.js.map +7 -0
- package/dist/modules/push_notifications/backend/push_notifications/page.meta.js +23 -0
- package/dist/modules/push_notifications/backend/push_notifications/page.meta.js.map +7 -0
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js +245 -0
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +7 -0
- package/dist/modules/push_notifications/backend/push_notifications/send/page.meta.js +26 -0
- package/dist/modules/push_notifications/backend/push_notifications/send/page.meta.js.map +7 -0
- package/dist/modules/push_notifications/data/entities.js +92 -0
- package/dist/modules/push_notifications/data/entities.js.map +7 -0
- package/dist/modules/push_notifications/data/extensions.js +23 -0
- package/dist/modules/push_notifications/data/extensions.js.map +7 -0
- package/dist/modules/push_notifications/data/validators.js +89 -0
- package/dist/modules/push_notifications/data/validators.js.map +7 -0
- package/dist/modules/push_notifications/di.js +17 -0
- package/dist/modules/push_notifications/di.js.map +7 -0
- package/dist/modules/push_notifications/events.js +24 -0
- package/dist/modules/push_notifications/events.js.map +7 -0
- package/dist/modules/push_notifications/index.js +16 -0
- package/dist/modules/push_notifications/index.js.map +7 -0
- package/dist/modules/push_notifications/lib/fake-provider-recorder.js +80 -0
- package/dist/modules/push_notifications/lib/fake-provider-recorder.js.map +7 -0
- package/dist/modules/push_notifications/lib/push-delivery-strategy.js +54 -0
- package/dist/modules/push_notifications/lib/push-delivery-strategy.js.map +7 -0
- package/dist/modules/push_notifications/lib/push-delivery.js +297 -0
- package/dist/modules/push_notifications/lib/push-delivery.js.map +7 -0
- package/dist/modules/push_notifications/lib/push-fanout.js +138 -0
- package/dist/modules/push_notifications/lib/push-fanout.js.map +7 -0
- package/dist/modules/push_notifications/lib/push-health.js +32 -0
- package/dist/modules/push_notifications/lib/push-health.js.map +7 -0
- package/dist/modules/push_notifications/lib/push-reaper.js +87 -0
- package/dist/modules/push_notifications/lib/push-reaper.js.map +7 -0
- package/dist/modules/push_notifications/lib/push-receipt-reaper.js +136 -0
- package/dist/modules/push_notifications/lib/push-receipt-reaper.js.map +7 -0
- package/dist/modules/push_notifications/lib/push-stub-adapter.js +63 -0
- package/dist/modules/push_notifications/lib/push-stub-adapter.js.map +7 -0
- package/dist/modules/push_notifications/lib/queue.js +53 -0
- package/dist/modules/push_notifications/lib/queue.js.map +7 -0
- package/dist/modules/push_notifications/lib/reclaim-window.js +13 -0
- package/dist/modules/push_notifications/lib/reclaim-window.js.map +7 -0
- package/dist/modules/push_notifications/lib/send-custom-push.js +48 -0
- package/dist/modules/push_notifications/lib/send-custom-push.js.map +7 -0
- package/dist/modules/push_notifications/migrations/Migration20260625150049_push_notifications.js +16 -0
- package/dist/modules/push_notifications/migrations/Migration20260625150049_push_notifications.js.map +7 -0
- package/dist/modules/push_notifications/migrations/Migration20260626120000_push_notifications_silent.js +13 -0
- package/dist/modules/push_notifications/migrations/Migration20260626120000_push_notifications_silent.js.map +7 -0
- package/dist/modules/push_notifications/notifications.delivery-strategies.js +8 -0
- package/dist/modules/push_notifications/notifications.delivery-strategies.js.map +7 -0
- package/dist/modules/push_notifications/notifications.js +40 -0
- package/dist/modules/push_notifications/notifications.js.map +7 -0
- package/dist/modules/push_notifications/setup.js +52 -0
- package/dist/modules/push_notifications/setup.js.map +7 -0
- package/dist/modules/push_notifications/workers/reclaim-stuck.worker.js +57 -0
- package/dist/modules/push_notifications/workers/reclaim-stuck.worker.js.map +7 -0
- package/dist/modules/push_notifications/workers/send-push.worker.js +27 -0
- package/dist/modules/push_notifications/workers/send-push.worker.js.map +7 -0
- package/dist/modules/sales/notifications.js +8 -0
- package/dist/modules/sales/notifications.js.map +2 -2
- package/dist/modules/staff/notifications.js +6 -0
- package/dist/modules/staff/notifications.js.map +2 -2
- package/dist/modules/workflows/notifications.js +2 -0
- package/dist/modules/workflows/notifications.js.map +2 -2
- package/generated/entities/notification/index.ts +3 -0
- package/generated/entities/notification_preference/index.ts +8 -0
- package/generated/entities/notification_type/index.ts +9 -0
- package/generated/entities/notification_type_override/index.ts +7 -0
- package/generated/entities/push_notification_delivery/index.ts +19 -0
- package/generated/entities/user_device/index.ts +16 -0
- package/generated/entities.ids.generated.ts +12 -1
- package/generated/entity-fields-registry.ts +72 -0
- package/package.json +7 -7
- package/src/helpers/integration/api.ts +2 -1
- package/src/helpers/integration/appRoot.ts +13 -0
- package/src/helpers/integration/dbFixtures.ts +1 -5
- package/src/helpers/integration/pushFake.ts +219 -0
- package/src/modules/auth/i18n/de.json +1 -0
- package/src/modules/auth/i18n/en.json +1 -0
- package/src/modules/auth/i18n/es.json +1 -0
- package/src/modules/auth/i18n/ko.json +1 -0
- package/src/modules/auth/i18n/pl.json +1 -0
- package/src/modules/auth/notifications.ts +16 -0
- package/src/modules/business_rules/i18n/de.json +2 -1
- package/src/modules/business_rules/i18n/en.json +2 -1
- package/src/modules/business_rules/i18n/es.json +2 -1
- package/src/modules/business_rules/i18n/ko.json +2 -1
- package/src/modules/business_rules/i18n/pl.json +2 -1
- package/src/modules/business_rules/notifications.ts +2 -0
- package/src/modules/catalog/i18n/de.json +2 -1
- package/src/modules/catalog/i18n/en.json +2 -1
- package/src/modules/catalog/i18n/es.json +2 -1
- package/src/modules/catalog/i18n/ko.json +2 -1
- package/src/modules/catalog/i18n/pl.json +2 -1
- package/src/modules/catalog/notifications.ts +2 -0
- package/src/modules/communication_channels/acl.ts +9 -0
- package/src/modules/communication_channels/api/delete/admin/channels/[id]/route.ts +168 -0
- package/src/modules/communication_channels/api/get/channels/[id]/health/route.ts +6 -2
- package/src/modules/communication_channels/api/get/channels/[id]/route.ts +6 -2
- package/src/modules/communication_channels/api/get/channels/route.ts +2 -1
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +16 -5
- package/src/modules/communication_channels/api/post/channels/connect/credentials/route.ts +37 -1
- package/src/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.ts +175 -0
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +11 -1
- package/src/modules/communication_channels/commands/admin-delete-channel.ts +203 -0
- package/src/modules/communication_channels/commands/connect-credential-channel.ts +63 -15
- package/src/modules/communication_channels/commands/deliver-outbound-message.ts +10 -2
- package/src/modules/communication_channels/commands/push-register.ts +7 -1
- package/src/modules/communication_channels/commands/push-unregister.ts +14 -3
- package/src/modules/communication_channels/data/entities.ts +10 -0
- package/src/modules/communication_channels/data/validators.ts +1 -0
- package/src/modules/communication_channels/i18n/de.json +35 -1
- package/src/modules/communication_channels/i18n/en.json +35 -1
- package/src/modules/communication_channels/i18n/es.json +35 -1
- package/src/modules/communication_channels/i18n/ko.json +35 -1
- package/src/modules/communication_channels/i18n/pl.json +35 -1
- package/src/modules/communication_channels/lib/access-control.ts +42 -0
- package/src/modules/communication_channels/lib/adapter.ts +25 -0
- package/src/modules/communication_channels/lib/connect-channel.ts +61 -26
- package/src/modules/communication_channels/lib/push-adapter.ts +139 -0
- package/src/modules/communication_channels/lib/push-capabilities.ts +42 -0
- package/src/modules/communication_channels/lib/push-connect-error.ts +52 -0
- package/src/modules/communication_channels/lib/push-credential-errors.ts +58 -0
- package/src/modules/communication_channels/lib/push-envelope.ts +104 -0
- package/src/modules/communication_channels/lib/refcounted-client-cache.ts +123 -0
- package/src/modules/communication_channels/migrations/.snapshot-open-mercato.json +9 -0
- package/src/modules/communication_channels/migrations/Migration20260703123630_communication_channels.ts +20 -0
- package/src/modules/communication_channels/notifications.ts +4 -0
- package/src/modules/communication_channels/setup.ts +2 -0
- package/src/modules/configs/i18n/de.json +5 -1
- package/src/modules/configs/i18n/en.json +5 -1
- package/src/modules/configs/i18n/es.json +5 -1
- package/src/modules/configs/i18n/ko.json +5 -1
- package/src/modules/configs/i18n/pl.json +5 -1
- package/src/modules/configs/lib/upgrade-actions.ts +21 -0
- package/src/modules/customer_accounts/i18n/de.json +2 -1
- package/src/modules/customer_accounts/i18n/en.json +2 -1
- package/src/modules/customer_accounts/i18n/es.json +2 -1
- package/src/modules/customer_accounts/i18n/ko.json +2 -1
- package/src/modules/customer_accounts/i18n/pl.json +2 -1
- package/src/modules/customer_accounts/notifications.ts +12 -0
- package/src/modules/customers/i18n/de.json +2 -1
- package/src/modules/customers/i18n/en.json +2 -1
- package/src/modules/customers/i18n/es.json +2 -1
- package/src/modules/customers/i18n/ko.json +2 -1
- package/src/modules/customers/i18n/pl.json +2 -1
- package/src/modules/customers/notifications.ts +4 -0
- package/src/modules/devices/AGENTS.md +101 -0
- package/src/modules/devices/acl.ts +7 -0
- package/src/modules/devices/api/[id]/route.ts +180 -0
- package/src/modules/devices/api/admin/devices/[id]/route.ts +235 -0
- package/src/modules/devices/api/admin/devices/route.ts +160 -0
- package/src/modules/devices/api/auth.ts +13 -0
- package/src/modules/devices/api/deviceList.ts +54 -0
- package/src/modules/devices/api/deviceOps.ts +186 -0
- package/src/modules/devices/api/openapi.ts +23 -0
- package/src/modules/devices/api/route.ts +165 -0
- package/src/modules/devices/backend/devices/[id]/page.meta.ts +12 -0
- package/src/modules/devices/backend/devices/[id]/page.tsx +164 -0
- package/src/modules/devices/backend/devices/create/page.meta.ts +12 -0
- package/src/modules/devices/backend/devices/create/page.tsx +81 -0
- package/src/modules/devices/backend/devices/page.meta.ts +21 -0
- package/src/modules/devices/backend/devices/page.tsx +259 -0
- package/src/modules/devices/commands/deactivate.ts +126 -0
- package/src/modules/devices/commands/index.ts +3 -0
- package/src/modules/devices/commands/register.ts +199 -0
- package/src/modules/devices/commands/shared.ts +119 -0
- package/src/modules/devices/commands/update.ts +142 -0
- package/src/modules/devices/data/entities.ts +79 -0
- package/src/modules/devices/data/validators.ts +65 -0
- package/src/modules/devices/di.ts +9 -0
- package/src/modules/devices/encryption.ts +15 -0
- package/src/modules/devices/events.ts +16 -0
- package/src/modules/devices/i18n/de.json +45 -0
- package/src/modules/devices/i18n/en.json +45 -0
- package/src/modules/devices/i18n/es.json +45 -0
- package/src/modules/devices/i18n/ko.json +45 -0
- package/src/modules/devices/i18n/pl.json +45 -0
- package/src/modules/devices/index.ts +15 -0
- package/src/modules/devices/lib/operationMetadata.ts +35 -0
- package/src/modules/devices/migrations/.snapshot-open-mercato.json +200 -0
- package/src/modules/devices/migrations/Migration20260602120000.ts +15 -0
- package/src/modules/devices/migrations/Migration20260630120000.ts +20 -0
- package/src/modules/devices/migrations/Migration20260701120000.ts +13 -0
- package/src/modules/devices/migrations/Migration20260721120000.ts +18 -0
- package/src/modules/devices/setup.ts +11 -0
- package/src/modules/entities/cli.ts +16 -2
- package/src/modules/entities/migrations/Migration20260722120000.ts +38 -0
- package/src/modules/inbox_ops/i18n/de.json +2 -1
- package/src/modules/inbox_ops/i18n/en.json +2 -1
- package/src/modules/inbox_ops/i18n/es.json +2 -1
- package/src/modules/inbox_ops/i18n/ko.json +2 -1
- package/src/modules/inbox_ops/i18n/pl.json +2 -1
- package/src/modules/inbox_ops/notifications.ts +2 -0
- package/src/modules/messages/i18n/de.json +2 -1
- package/src/modules/messages/i18n/en.json +2 -1
- package/src/modules/messages/i18n/es.json +2 -1
- package/src/modules/messages/i18n/ko.json +2 -1
- package/src/modules/messages/i18n/pl.json +2 -1
- package/src/modules/messages/notifications.ts +2 -0
- package/src/modules/notifications/AGENTS.md +54 -0
- package/src/modules/notifications/acl.ts +2 -0
- package/src/modules/notifications/api/admin/preferences/route.ts +193 -0
- package/src/modules/notifications/api/channels/route.ts +54 -0
- package/src/modules/notifications/api/preferences/route.ts +131 -0
- package/src/modules/notifications/api/route.ts +8 -1
- package/src/modules/notifications/api/types/[id]/channels/[channel]/route.ts +226 -0
- package/src/modules/notifications/api/types/route.ts +239 -0
- package/src/modules/notifications/api/unread-count/route.ts +5 -1
- package/src/modules/notifications/backend/notifications/user-preferences/page.meta.ts +26 -0
- package/src/modules/notifications/backend/notifications/user-preferences/page.tsx +12 -0
- package/src/modules/notifications/backend/profile/notification-preferences/page.meta.ts +31 -0
- package/src/modules/notifications/backend/profile/notification-preferences/page.tsx +12 -0
- package/src/modules/notifications/data/entities.ts +144 -0
- package/src/modules/notifications/data/validators.ts +116 -0
- package/src/modules/notifications/di.ts +7 -0
- package/src/modules/notifications/events.ts +23 -0
- package/src/modules/notifications/frontend/NotificationPreferenceMatrix.tsx +287 -0
- package/src/modules/notifications/frontend/NotificationPreferencesPageClient.tsx +155 -0
- package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +273 -2
- package/src/modules/notifications/frontend/NotificationUserPreferencesAdminPageClient.tsx +214 -0
- package/src/modules/notifications/generators.ts +82 -0
- package/src/modules/notifications/i18n/de.json +43 -0
- package/src/modules/notifications/i18n/en.json +43 -0
- package/src/modules/notifications/i18n/es.json +43 -0
- package/src/modules/notifications/i18n/ko.json +43 -0
- package/src/modules/notifications/i18n/pl.json +44 -1
- package/src/modules/notifications/lib/delivery-strategies-registry.ts +30 -0
- package/src/modules/notifications/lib/deliveryStrategies.ts +40 -4
- package/src/modules/notifications/lib/derive-category.ts +15 -0
- package/src/modules/notifications/lib/notification-channel-registry.ts +59 -0
- package/src/modules/notifications/lib/notification-type-registry.ts +182 -0
- package/src/modules/notifications/lib/notificationCopy.ts +34 -0
- package/src/modules/notifications/lib/notificationFactory.ts +5 -1
- package/src/modules/notifications/lib/notificationMapper.ts +2 -0
- package/src/modules/notifications/lib/notificationPreferenceService.ts +138 -0
- package/src/modules/notifications/lib/notificationService.ts +129 -25
- package/src/modules/notifications/lib/notificationVisibility.ts +48 -0
- package/src/modules/notifications/lib/routeHelpers.ts +14 -1
- package/src/modules/notifications/lib/shouldDeliver.ts +112 -0
- package/src/modules/notifications/lib/strategies/email-delivery-strategy.ts +63 -0
- package/src/modules/notifications/lib/strategies/in-app-delivery-strategy.ts +21 -0
- package/src/modules/notifications/lib/typeCatalogue.ts +141 -0
- package/src/modules/notifications/lib/typeChannelSettings.ts +29 -0
- package/src/modules/notifications/lib/typeOverrides.ts +46 -0
- package/src/modules/notifications/migrations/.snapshot-open-mercato.json +874 -100
- package/src/modules/notifications/migrations/Migration20260625122947_notifications.ts +14 -0
- package/src/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.ts +15 -0
- package/src/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.ts +13 -0
- package/src/modules/notifications/migrations/Migration20260626140000_notifications_type_category_silent.ts +15 -0
- package/src/modules/notifications/migrations/Migration20260706120000_notifications_channels.ts +13 -0
- package/src/modules/notifications/migrations/Migration20260716123121_notifications.ts +14 -0
- package/src/modules/notifications/notification-channels.ts +30 -0
- package/src/modules/notifications/notifications.delivery-strategies.ts +15 -0
- package/src/modules/notifications/setup.ts +23 -1
- package/src/modules/notifications/subscribers/deliver-notification.ts +105 -71
- package/src/modules/notifications/subscribers/sync-notification-types.ts +18 -0
- package/src/modules/notifications/widgets/injection/profile-preferences-menu/widget.ts +35 -0
- package/src/modules/notifications/widgets/injection-table.ts +18 -0
- package/src/modules/push_notifications/AGENTS.md +92 -0
- package/src/modules/push_notifications/acl.ts +9 -0
- package/src/modules/push_notifications/api/custom-send/route.ts +175 -0
- package/src/modules/push_notifications/api/deliveries/[id]/route.ts +122 -0
- package/src/modules/push_notifications/api/deliveries/route.ts +58 -0
- package/src/modules/push_notifications/api/openapi.ts +22 -0
- package/src/modules/push_notifications/backend/push_notifications/[id]/page.meta.ts +9 -0
- package/src/modules/push_notifications/backend/push_notifications/[id]/page.tsx +149 -0
- package/src/modules/push_notifications/backend/push_notifications/page.meta.ts +21 -0
- package/src/modules/push_notifications/backend/push_notifications/page.tsx +239 -0
- package/src/modules/push_notifications/backend/push_notifications/send/page.meta.ts +24 -0
- package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +327 -0
- package/src/modules/push_notifications/data/entities.ts +111 -0
- package/src/modules/push_notifications/data/extensions.ts +29 -0
- package/src/modules/push_notifications/data/validators.ts +102 -0
- package/src/modules/push_notifications/di.ts +20 -0
- package/src/modules/push_notifications/events.ts +21 -0
- package/src/modules/push_notifications/i18n/de.json +79 -0
- package/src/modules/push_notifications/i18n/en.json +79 -0
- package/src/modules/push_notifications/i18n/es.json +79 -0
- package/src/modules/push_notifications/i18n/ko.json +79 -0
- package/src/modules/push_notifications/i18n/pl.json +79 -0
- package/src/modules/push_notifications/index.ts +15 -0
- package/src/modules/push_notifications/lib/fake-provider-recorder.ts +154 -0
- package/src/modules/push_notifications/lib/push-delivery-strategy.ts +90 -0
- package/src/modules/push_notifications/lib/push-delivery.ts +455 -0
- package/src/modules/push_notifications/lib/push-fanout.ts +237 -0
- package/src/modules/push_notifications/lib/push-health.ts +47 -0
- package/src/modules/push_notifications/lib/push-reaper.ts +140 -0
- package/src/modules/push_notifications/lib/push-receipt-reaper.ts +210 -0
- package/src/modules/push_notifications/lib/push-stub-adapter.ts +80 -0
- package/src/modules/push_notifications/lib/queue.ts +74 -0
- package/src/modules/push_notifications/lib/reclaim-window.ts +16 -0
- package/src/modules/push_notifications/lib/send-custom-push.ts +100 -0
- package/src/modules/push_notifications/migrations/.snapshot-open-mercato.json +386 -0
- package/src/modules/push_notifications/migrations/Migration20260625150049_push_notifications.ts +16 -0
- package/src/modules/push_notifications/migrations/Migration20260626120000_push_notifications_silent.ts +13 -0
- package/src/modules/push_notifications/notifications.delivery-strategies.ts +8 -0
- package/src/modules/push_notifications/notifications.ts +50 -0
- package/src/modules/push_notifications/setup.ts +92 -0
- package/src/modules/push_notifications/workers/reclaim-stuck.worker.ts +78 -0
- package/src/modules/push_notifications/workers/send-push.worker.ts +34 -0
- package/src/modules/sales/i18n/de.json +1 -0
- package/src/modules/sales/i18n/en.json +1 -0
- package/src/modules/sales/i18n/es.json +1 -0
- package/src/modules/sales/i18n/ko.json +1 -0
- package/src/modules/sales/i18n/pl.json +1 -0
- package/src/modules/sales/notifications.ts +8 -0
- package/src/modules/staff/i18n/de.json +1 -0
- package/src/modules/staff/i18n/en.json +1 -0
- package/src/modules/staff/i18n/es.json +1 -0
- package/src/modules/staff/i18n/ko.json +1 -0
- package/src/modules/staff/i18n/pl.json +1 -0
- package/src/modules/staff/notifications.ts +6 -0
- package/src/modules/workflows/i18n/de.json +1 -0
- package/src/modules/workflows/i18n/en.json +1 -0
- package/src/modules/workflows/i18n/es.json +1 -0
- package/src/modules/workflows/i18n/ko.json +1 -0
- package/src/modules/workflows/i18n/pl.json +1 -0
- package/src/modules/workflows/notifications.ts +2 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/commands/register.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { UserDevice } from '../data/entities'\nimport { registerDeviceCommandSchema, type RegisterDeviceCommandInput } from '../data/validators'\nimport { emitDevicesEvent } from '../events'\nimport {\n applySnapshot,\n deviceEvents,\n deviceIndexer,\n isDeviceUniqueViolation,\n loadExistingDevice,\n serializeDevice,\n type DeviceSnapshot,\n type DeviceUndoPayload,\n} from './shared'\n\nconst registerDeviceCommand: CommandHandler<RegisterDeviceCommandInput, { id: string; deviceId: string; revived: boolean }> = {\n id: 'devices.user_devices.register',\n async prepare(rawInput, ctx) {\n const parsed = registerDeviceCommandSchema.parse(rawInput)\n // Enforce tenant scope before any DB access so prepare() can't probe across tenants.\n ensureTenantScope(ctx, parsed.tenantId)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await loadExistingDevice(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId ?? null,\n userId: parsed.userId,\n deviceId: parsed.deviceId,\n })\n return existing ? { before: serializeDevice(existing) } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = registerDeviceCommandSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await loadExistingDevice(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId ?? null,\n userId: parsed.userId,\n deviceId: parsed.deviceId,\n })\n const now = new Date()\n const hasPushToken = parsed.pushToken !== undefined && parsed.pushToken !== null\n const wasActive = existing ? existing.deletedAt == null : false\n\n let device!: UserDevice\n try {\n await withAtomicFlush(\n em,\n [\n () => {\n if (existing) {\n device = existing\n device.platform = parsed.platform\n device.organizationId = parsed.organizationId ?? device.organizationId ?? null\n if (parsed.clientAppVersion !== undefined) device.clientAppVersion = parsed.clientAppVersion ?? null\n if (parsed.osVersion !== undefined) device.osVersion = parsed.osVersion ?? null\n if (parsed.locale !== undefined) device.locale = parsed.locale ?? null\n if (hasPushToken) {\n device.pushToken = parsed.pushToken ?? null\n device.pushProvider = parsed.pushProvider ?? device.pushProvider ?? null\n device.pushTokenUpdatedAt = now\n }\n device.lastSeenAt = now\n device.deletedAt = null\n } else {\n device = em.create(UserDevice, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId ?? null,\n userId: parsed.userId,\n deviceId: parsed.deviceId,\n platform: parsed.platform,\n clientAppVersion: parsed.clientAppVersion ?? null,\n osVersion: parsed.osVersion ?? null,\n locale: parsed.locale ?? null,\n pushToken: hasPushToken ? parsed.pushToken ?? null : null,\n pushProvider: hasPushToken ? parsed.pushProvider ?? null : null,\n pushTokenUpdatedAt: hasPushToken ? now : null,\n lastSeenAt: now,\n })\n em.persist(device)\n }\n },\n ],\n { transaction: true },\n )\n } catch (err) {\n if (isDeviceUniqueViolation(err)) {\n // Default English message is a fallback; device routes translate by `code` (see route POST\n // handlers), matching the customers dictionaries conflict pattern.\n throw new CrudHttpError(409, {\n code: 'device_already_registered',\n error: 'This device is already registered',\n })\n }\n throw err\n }\n\n const revived = Boolean(existing) && !wasActive\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: existing ? 'updated' : 'created',\n entity: device,\n identifiers: {\n id: device.id,\n tenantId: device.tenantId,\n organizationId: device.organizationId ?? null,\n },\n indexer: deviceIndexer,\n events: deviceEvents,\n })\n await emitDevicesEvent(\n 'devices.user_device.registered',\n {\n id: device.id,\n tenantId: device.tenantId,\n organizationId: device.organizationId ?? null,\n userId: device.userId,\n deviceId: device.deviceId,\n platform: device.platform,\n revived,\n },\n { persistent: true },\n )\n\n return { id: device.id, deviceId: device.deviceId, revived }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const device = await findOneWithDecryption(em, UserDevice, { id: result.id })\n return device ? serializeDevice(device) : null\n },\n buildLog: async ({ result, snapshots }) => {\n const before = (snapshots.before as DeviceSnapshot | undefined) ?? null\n const after = (snapshots.after as DeviceSnapshot | undefined) ?? null\n return {\n actionLabel: before ? 'Update device' : 'Register device',\n resourceKind: 'devices.user_device',\n resourceId: result.id,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before,\n snapshotAfter: after,\n payload: {\n undo: { before, after } satisfies DeviceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<DeviceUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const before = payload?.before ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const device = await findOneWithDecryption(em, UserDevice, { id: after.id })\n if (!device) return\n\n await withAtomicFlush(\n em,\n [\n () => {\n if (before) {\n // Upsert/revive: restore the prior row state.\n applySnapshot(device, before)\n } else {\n // Fresh registration: undo by soft-deleting the created row.\n device.deletedAt = new Date()\n }\n },\n ],\n { transaction: true },\n )\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: before ? 'updated' : 'deleted',\n entity: device,\n identifiers: {\n id: device.id,\n tenantId: device.tenantId,\n organizationId: device.organizationId ?? null,\n },\n indexer: deviceIndexer,\n events: deviceEvents,\n })\n },\n}\n\nregisterCommand(registerDeviceCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { UniqueConstraintViolationException } from "@mikro-orm/core";
|
|
2
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
3
|
+
import { E } from "../../../generated/entities.ids.generated.js";
|
|
4
|
+
import { UserDevice } from "../data/entities.js";
|
|
5
|
+
const deviceIndexer = {
|
|
6
|
+
entityType: E.devices.user_device
|
|
7
|
+
};
|
|
8
|
+
const deviceEvents = {
|
|
9
|
+
module: "devices",
|
|
10
|
+
entity: "user_device",
|
|
11
|
+
persistent: true,
|
|
12
|
+
buildPayload: (ctx) => ({
|
|
13
|
+
id: ctx.identifiers.id,
|
|
14
|
+
tenantId: ctx.identifiers.tenantId,
|
|
15
|
+
organizationId: ctx.identifiers.organizationId
|
|
16
|
+
})
|
|
17
|
+
};
|
|
18
|
+
function toDate(value) {
|
|
19
|
+
if (!value) return null;
|
|
20
|
+
const date = new Date(value);
|
|
21
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
22
|
+
}
|
|
23
|
+
function fingerprintPushToken(token) {
|
|
24
|
+
return token ? token.slice(-8) : null;
|
|
25
|
+
}
|
|
26
|
+
function serializeDevice(device) {
|
|
27
|
+
return {
|
|
28
|
+
id: device.id,
|
|
29
|
+
tenantId: device.tenantId,
|
|
30
|
+
organizationId: device.organizationId ?? null,
|
|
31
|
+
userId: device.userId,
|
|
32
|
+
deviceId: device.deviceId,
|
|
33
|
+
platform: device.platform,
|
|
34
|
+
clientAppVersion: device.clientAppVersion ?? null,
|
|
35
|
+
osVersion: device.osVersion ?? null,
|
|
36
|
+
locale: device.locale ?? null,
|
|
37
|
+
pushTokenFingerprint: fingerprintPushToken(device.pushToken ?? null),
|
|
38
|
+
pushProvider: device.pushProvider ?? null,
|
|
39
|
+
pushTokenUpdatedAt: device.pushTokenUpdatedAt ? device.pushTokenUpdatedAt.toISOString() : null,
|
|
40
|
+
lastSeenAt: device.lastSeenAt.toISOString(),
|
|
41
|
+
deletedAt: device.deletedAt ? device.deletedAt.toISOString() : null
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function applySnapshot(device, snapshot) {
|
|
45
|
+
device.platform = snapshot.platform;
|
|
46
|
+
device.clientAppVersion = snapshot.clientAppVersion;
|
|
47
|
+
device.osVersion = snapshot.osVersion;
|
|
48
|
+
device.locale = snapshot.locale;
|
|
49
|
+
device.lastSeenAt = toDate(snapshot.lastSeenAt) ?? /* @__PURE__ */ new Date();
|
|
50
|
+
device.deletedAt = toDate(snapshot.deletedAt);
|
|
51
|
+
}
|
|
52
|
+
async function loadExistingDevice(em, scope) {
|
|
53
|
+
const dscope = { tenantId: scope.tenantId, organizationId: scope.organizationId };
|
|
54
|
+
const active = await findOneWithDecryption(em, UserDevice, { ...scope, deletedAt: null }, void 0, dscope);
|
|
55
|
+
if (active) return active;
|
|
56
|
+
return findOneWithDecryption(em, UserDevice, scope, { orderBy: { createdAt: "desc" } }, dscope);
|
|
57
|
+
}
|
|
58
|
+
const PG_UNIQUE_VIOLATION = "23505";
|
|
59
|
+
function isDeviceUniqueViolation(error) {
|
|
60
|
+
if (error instanceof UniqueConstraintViolationException) return true;
|
|
61
|
+
if (!error || typeof error !== "object") return false;
|
|
62
|
+
if (error.code === PG_UNIQUE_VIOLATION) return true;
|
|
63
|
+
const message = error.message;
|
|
64
|
+
return typeof message === "string" && message.toLowerCase().includes("duplicate key");
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
applySnapshot,
|
|
68
|
+
deviceEvents,
|
|
69
|
+
deviceIndexer,
|
|
70
|
+
isDeviceUniqueViolation,
|
|
71
|
+
loadExistingDevice,
|
|
72
|
+
serializeDevice
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/commands/shared.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { UniqueConstraintViolationException } from '@mikro-orm/core'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { CrudEventsConfig, CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\nimport { UserDevice } from '../data/entities'\n\nexport type DeviceSnapshot = {\n id: string\n tenantId: string\n organizationId: string | null\n userId: string\n deviceId: string\n platform: string\n clientAppVersion: string | null\n osVersion: string | null\n locale: string | null\n // Last-8 fingerprint of the push token \u2014 NEVER the plaintext. Audit snapshots and the undo payload\n // both persist to `action_logs` (no TTL, never purged, and `persistLog` permits a null tenantId the\n // encryption subscriber skips), so storing the real token there would leak a device credential\n // forever. The live encrypted column is the single source of truth; undo re-reads it (see applySnapshot).\n pushTokenFingerprint: string | null\n pushProvider: string | null\n pushTokenUpdatedAt: string | null\n lastSeenAt: string\n deletedAt: string | null\n}\n\nexport type DeviceUndoPayload = {\n before?: DeviceSnapshot | null\n after?: DeviceSnapshot | null\n}\n\nexport const deviceIndexer: CrudIndexerConfig<UserDevice> = {\n entityType: E.devices.user_device,\n}\n\nexport const deviceEvents: CrudEventsConfig<UserDevice> = {\n module: 'devices',\n entity: 'user_device',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n}\n\nfunction toDate(value: string | null | undefined): Date | null {\n if (!value) return null\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? null : date\n}\n\n// Persist at most the last 8 chars of the (long) provider token \u2014 never the full secret. Mirrors the\n// delivery log's `token_snapshot` (push-fanout.ts) so audit/undo carry a stable, non-sensitive fingerprint.\nfunction fingerprintPushToken(token: string | null): string | null {\n return token ? token.slice(-8) : null\n}\n\nexport function serializeDevice(device: UserDevice): DeviceSnapshot {\n return {\n id: device.id,\n tenantId: device.tenantId,\n organizationId: device.organizationId ?? null,\n userId: device.userId,\n deviceId: device.deviceId,\n platform: device.platform,\n clientAppVersion: device.clientAppVersion ?? null,\n osVersion: device.osVersion ?? null,\n locale: device.locale ?? null,\n pushTokenFingerprint: fingerprintPushToken(device.pushToken ?? null),\n pushProvider: device.pushProvider ?? null,\n pushTokenUpdatedAt: device.pushTokenUpdatedAt ? device.pushTokenUpdatedAt.toISOString() : null,\n lastSeenAt: device.lastSeenAt.toISOString(),\n deletedAt: device.deletedAt ? device.deletedAt.toISOString() : null,\n }\n}\n\nexport function applySnapshot(device: UserDevice, snapshot: DeviceSnapshot): void {\n device.platform = snapshot.platform as UserDevice['platform']\n device.clientAppVersion = snapshot.clientAppVersion\n device.osVersion = snapshot.osVersion\n device.locale = snapshot.locale\n // The push credential triple (token, provider, token_updated_at) is deliberately NOT restored from a\n // snapshot. The snapshot carries only a fingerprint, and the token is a device-issued credential whose\n // live encrypted column is authoritative \u2014 undo preserves whatever token the device currently holds.\n // Restoring a stale token, or the redacted/undecryptable placeholder a snapshot could otherwise carry,\n // would unrecoverably brick delivery. Reverting metadata is safe; reverting the secret is not.\n device.lastSeenAt = toDate(snapshot.lastSeenAt) ?? new Date()\n device.deletedAt = toDate(snapshot.deletedAt)\n}\n\nexport async function loadExistingDevice(\n em: EntityManager,\n // organizationId is part of the device identity (a null value matches IS NULL, mirroring the\n // coalesce(...) bucket in the unique index), so a device is looked up per (tenant, org, user, device).\n scope: { tenantId: string; organizationId: string | null; userId: string; deviceId: string },\n): Promise<UserDevice | null> {\n // push_token is encrypted at rest; decrypt on read so snapshots/undo payloads keep the plaintext.\n const dscope = { tenantId: scope.tenantId, organizationId: scope.organizationId }\n const active = await findOneWithDecryption(em, UserDevice, { ...scope, deletedAt: null }, undefined, dscope)\n if (active) return active\n return findOneWithDecryption(em, UserDevice, scope, { orderBy: { createdAt: 'desc' } }, dscope)\n}\n\n// Postgres SQLSTATE for unique_violation. MikroORM doesn't re-export pg error codes, so name it here.\nconst PG_UNIQUE_VIOLATION = '23505'\n\n// A concurrent first-registration of the same (tenant, org, user, device_id) loses the race against the\n// partial unique index. Surface it as a 409 conflict instead of a raw 500 \u2014 the endpoint is an\n// idempotent upsert, so the caller can simply re-issue the request to land on the existing row.\nexport function isDeviceUniqueViolation(error: unknown): boolean {\n if (error instanceof UniqueConstraintViolationException) return true\n if (!error || typeof error !== 'object') return false\n if ((error as { code?: string }).code === PG_UNIQUE_VIOLATION) return true\n const message = (error as { message?: string }).message\n return typeof message === 'string' && message.toLowerCase().includes('duplicate key')\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,0CAA0C;AACnD,SAAS,6BAA6B;AAEtC,SAAS,SAAS;AAClB,SAAS,kBAAkB;AA4BpB,MAAM,gBAA+C;AAAA,EAC1D,YAAY,EAAE,QAAQ;AACxB;AAEO,MAAM,eAA6C;AAAA,EACxD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc,CAAC,SAAS;AAAA,IACtB,IAAI,IAAI,YAAY;AAAA,IACpB,UAAU,IAAI,YAAY;AAAA,IAC1B,gBAAgB,IAAI,YAAY;AAAA,EAClC;AACF;AAEA,SAAS,OAAO,OAA+C;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,SAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;AAC/C;AAIA,SAAS,qBAAqB,OAAqC;AACjE,SAAO,QAAQ,MAAM,MAAM,EAAE,IAAI;AACnC;AAEO,SAAS,gBAAgB,QAAoC;AAClE,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX,UAAU,OAAO;AAAA,IACjB,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,UAAU,OAAO;AAAA,IACjB,kBAAkB,OAAO,oBAAoB;AAAA,IAC7C,WAAW,OAAO,aAAa;AAAA,IAC/B,QAAQ,OAAO,UAAU;AAAA,IACzB,sBAAsB,qBAAqB,OAAO,aAAa,IAAI;AAAA,IACnE,cAAc,OAAO,gBAAgB;AAAA,IACrC,oBAAoB,OAAO,qBAAqB,OAAO,mBAAmB,YAAY,IAAI;AAAA,IAC1F,YAAY,OAAO,WAAW,YAAY;AAAA,IAC1C,WAAW,OAAO,YAAY,OAAO,UAAU,YAAY,IAAI;AAAA,EACjE;AACF;AAEO,SAAS,cAAc,QAAoB,UAAgC;AAChF,SAAO,WAAW,SAAS;AAC3B,SAAO,mBAAmB,SAAS;AACnC,SAAO,YAAY,SAAS;AAC5B,SAAO,SAAS,SAAS;AAMzB,SAAO,aAAa,OAAO,SAAS,UAAU,KAAK,oBAAI,KAAK;AAC5D,SAAO,YAAY,OAAO,SAAS,SAAS;AAC9C;AAEA,eAAsB,mBACpB,IAGA,OAC4B;AAE5B,QAAM,SAAS,EAAE,UAAU,MAAM,UAAU,gBAAgB,MAAM,eAAe;AAChF,QAAM,SAAS,MAAM,sBAAsB,IAAI,YAAY,EAAE,GAAG,OAAO,WAAW,KAAK,GAAG,QAAW,MAAM;AAC3G,MAAI,OAAQ,QAAO;AACnB,SAAO,sBAAsB,IAAI,YAAY,OAAO,EAAE,SAAS,EAAE,WAAW,OAAO,EAAE,GAAG,MAAM;AAChG;AAGA,MAAM,sBAAsB;AAKrB,SAAS,wBAAwB,OAAyB;AAC/D,MAAI,iBAAiB,mCAAoC,QAAO;AAChE,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,MAAK,MAA4B,SAAS,oBAAqB,QAAO;AACtE,QAAM,UAAW,MAA+B;AAChD,SAAO,OAAO,YAAY,YAAY,QAAQ,YAAY,EAAE,SAAS,eAAe;AACtF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { registerCommand } from "@open-mercato/shared/lib/commands";
|
|
2
|
+
import { ensureTenantScope } from "@open-mercato/shared/lib/commands/scope";
|
|
3
|
+
import { extractUndoPayload } from "@open-mercato/shared/lib/commands/undo";
|
|
4
|
+
import { emitCrudSideEffects, emitCrudUndoSideEffects } from "@open-mercato/shared/lib/commands/helpers";
|
|
5
|
+
import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
|
|
6
|
+
import { assertFound } from "@open-mercato/shared/lib/crud/errors";
|
|
7
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
8
|
+
import { UserDevice } from "../data/entities.js";
|
|
9
|
+
import { updateDeviceCommandSchema } from "../data/validators.js";
|
|
10
|
+
import {
|
|
11
|
+
applySnapshot,
|
|
12
|
+
deviceEvents,
|
|
13
|
+
deviceIndexer,
|
|
14
|
+
serializeDevice
|
|
15
|
+
} from "./shared.js";
|
|
16
|
+
const updateDeviceCommand = {
|
|
17
|
+
id: "devices.user_devices.update",
|
|
18
|
+
async prepare(rawInput, ctx) {
|
|
19
|
+
const parsed = updateDeviceCommandSchema.parse(rawInput);
|
|
20
|
+
ensureTenantScope(ctx, parsed.tenantId);
|
|
21
|
+
const em = ctx.container.resolve("em").fork();
|
|
22
|
+
const device = await findOneWithDecryption(
|
|
23
|
+
em,
|
|
24
|
+
UserDevice,
|
|
25
|
+
{ id: parsed.id, tenantId: parsed.tenantId, deletedAt: null }
|
|
26
|
+
);
|
|
27
|
+
return device ? { before: serializeDevice(device) } : {};
|
|
28
|
+
},
|
|
29
|
+
async execute(rawInput, ctx) {
|
|
30
|
+
const parsed = updateDeviceCommandSchema.parse(rawInput);
|
|
31
|
+
const em = ctx.container.resolve("em").fork();
|
|
32
|
+
const device = assertFound(
|
|
33
|
+
await findOneWithDecryption(em, UserDevice, { id: parsed.id, deletedAt: null }),
|
|
34
|
+
"Device not found"
|
|
35
|
+
);
|
|
36
|
+
ensureTenantScope(ctx, device.tenantId);
|
|
37
|
+
const now = /* @__PURE__ */ new Date();
|
|
38
|
+
await withAtomicFlush(
|
|
39
|
+
em,
|
|
40
|
+
[
|
|
41
|
+
() => {
|
|
42
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "clientAppVersion")) {
|
|
43
|
+
device.clientAppVersion = parsed.clientAppVersion ?? null;
|
|
44
|
+
}
|
|
45
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "osVersion")) {
|
|
46
|
+
device.osVersion = parsed.osVersion ?? null;
|
|
47
|
+
}
|
|
48
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "locale")) {
|
|
49
|
+
device.locale = parsed.locale ?? null;
|
|
50
|
+
}
|
|
51
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "pushToken")) {
|
|
52
|
+
device.pushToken = parsed.pushToken ?? null;
|
|
53
|
+
device.pushTokenUpdatedAt = now;
|
|
54
|
+
}
|
|
55
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "pushProvider")) {
|
|
56
|
+
device.pushProvider = parsed.pushProvider ?? null;
|
|
57
|
+
}
|
|
58
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "lastSeenAt") && parsed.lastSeenAt) {
|
|
59
|
+
device.lastSeenAt = parsed.lastSeenAt;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
{ transaction: true }
|
|
64
|
+
);
|
|
65
|
+
const de = ctx.container.resolve("dataEngine");
|
|
66
|
+
await emitCrudSideEffects({
|
|
67
|
+
dataEngine: de,
|
|
68
|
+
action: "updated",
|
|
69
|
+
entity: device,
|
|
70
|
+
identifiers: {
|
|
71
|
+
id: device.id,
|
|
72
|
+
tenantId: device.tenantId,
|
|
73
|
+
organizationId: device.organizationId ?? null
|
|
74
|
+
},
|
|
75
|
+
indexer: deviceIndexer,
|
|
76
|
+
events: deviceEvents
|
|
77
|
+
});
|
|
78
|
+
return { id: device.id };
|
|
79
|
+
},
|
|
80
|
+
captureAfter: async (_input, result, ctx) => {
|
|
81
|
+
const em = ctx.container.resolve("em").fork();
|
|
82
|
+
const device = await findOneWithDecryption(em, UserDevice, { id: result.id });
|
|
83
|
+
return device ? serializeDevice(device) : null;
|
|
84
|
+
},
|
|
85
|
+
buildLog: async ({ snapshots }) => {
|
|
86
|
+
const before = snapshots.before ?? null;
|
|
87
|
+
if (!before) return null;
|
|
88
|
+
const after = snapshots.after ?? null;
|
|
89
|
+
return {
|
|
90
|
+
actionLabel: "Update device",
|
|
91
|
+
resourceKind: "devices.user_device",
|
|
92
|
+
resourceId: before.id,
|
|
93
|
+
tenantId: before.tenantId,
|
|
94
|
+
organizationId: before.organizationId,
|
|
95
|
+
snapshotBefore: before,
|
|
96
|
+
snapshotAfter: after,
|
|
97
|
+
payload: {
|
|
98
|
+
undo: { before, after }
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
undo: async ({ logEntry, ctx }) => {
|
|
103
|
+
const payload = extractUndoPayload(logEntry);
|
|
104
|
+
const before = payload?.before;
|
|
105
|
+
if (!before) return;
|
|
106
|
+
const em = ctx.container.resolve("em").fork();
|
|
107
|
+
const device = await findOneWithDecryption(em, UserDevice, { id: before.id });
|
|
108
|
+
if (!device) return;
|
|
109
|
+
await withAtomicFlush(em, [() => applySnapshot(device, before)], { transaction: true });
|
|
110
|
+
const de = ctx.container.resolve("dataEngine");
|
|
111
|
+
await emitCrudUndoSideEffects({
|
|
112
|
+
dataEngine: de,
|
|
113
|
+
action: "updated",
|
|
114
|
+
entity: device,
|
|
115
|
+
identifiers: {
|
|
116
|
+
id: device.id,
|
|
117
|
+
tenantId: device.tenantId,
|
|
118
|
+
organizationId: device.organizationId ?? null
|
|
119
|
+
},
|
|
120
|
+
indexer: deviceIndexer,
|
|
121
|
+
events: deviceEvents
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
registerCommand(updateDeviceCommand);
|
|
126
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/commands/update.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { assertFound } from '@open-mercato/shared/lib/crud/errors'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { UserDevice } from '../data/entities'\nimport { updateDeviceCommandSchema, type UpdateDeviceCommandInput } from '../data/validators'\nimport {\n applySnapshot,\n deviceEvents,\n deviceIndexer,\n serializeDevice,\n type DeviceSnapshot,\n type DeviceUndoPayload,\n} from './shared'\n\nconst updateDeviceCommand: CommandHandler<UpdateDeviceCommandInput, { id: string }> = {\n id: 'devices.user_devices.update',\n async prepare(rawInput, ctx) {\n const parsed = updateDeviceCommandSchema.parse(rawInput)\n // Enforce tenant scope and constrain the snapshot lookup to the caller's tenant.\n ensureTenantScope(ctx, parsed.tenantId)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n // No fallback decryption scope: `UserDevice` always carries its own organization_id, which\n // `decryptEntitiesWithFallbackScope` resolves first \u2014 matching the scope-less lookup in execute().\n const device = await findOneWithDecryption(\n em,\n UserDevice,\n { id: parsed.id, tenantId: parsed.tenantId, deletedAt: null },\n )\n return device ? { before: serializeDevice(device) } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = updateDeviceCommandSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const device = assertFound(\n await findOneWithDecryption(em, UserDevice, { id: parsed.id, deletedAt: null }),\n 'Device not found',\n )\n ensureTenantScope(ctx, device.tenantId)\n\n const now = new Date()\n await withAtomicFlush(\n em,\n [\n () => {\n if (Object.prototype.hasOwnProperty.call(parsed, 'clientAppVersion')) {\n device.clientAppVersion = parsed.clientAppVersion ?? null\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'osVersion')) {\n device.osVersion = parsed.osVersion ?? null\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'locale')) {\n device.locale = parsed.locale ?? null\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'pushToken')) {\n device.pushToken = parsed.pushToken ?? null\n device.pushTokenUpdatedAt = now\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'pushProvider')) {\n device.pushProvider = parsed.pushProvider ?? null\n }\n // Only a client-supplied lastSeenAt advances presence. Metadata-only edits (e.g. an admin\n // changing push_provider) must NOT bump last_seen_at \u2014 device presence is maintained by the\n // register heartbeat, not by edits.\n if (Object.prototype.hasOwnProperty.call(parsed, 'lastSeenAt') && parsed.lastSeenAt) {\n device.lastSeenAt = parsed.lastSeenAt\n }\n },\n ],\n { transaction: true },\n )\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: device,\n identifiers: {\n id: device.id,\n tenantId: device.tenantId,\n organizationId: device.organizationId ?? null,\n },\n indexer: deviceIndexer,\n events: deviceEvents,\n })\n\n return { id: device.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const device = await findOneWithDecryption(em, UserDevice, { id: result.id })\n return device ? serializeDevice(device) : null\n },\n buildLog: async ({ snapshots }) => {\n const before = (snapshots.before as DeviceSnapshot | undefined) ?? null\n if (!before) return null\n const after = (snapshots.after as DeviceSnapshot | undefined) ?? null\n return {\n actionLabel: 'Update device',\n resourceKind: 'devices.user_device',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after,\n payload: {\n undo: { before, after } satisfies DeviceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<DeviceUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const device = await findOneWithDecryption(em, UserDevice, { id: before.id })\n if (!device) return\n\n await withAtomicFlush(em, [() => applySnapshot(device, before)], { transaction: true })\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: device,\n identifiers: {\n id: device.id,\n tenantId: device.tenantId,\n organizationId: device.organizationId ?? null,\n },\n indexer: deviceIndexer,\n events: deviceEvents,\n })\n },\n}\n\nregisterCommand(updateDeviceCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
import { OptionalProps } from "@mikro-orm/core";
|
|
12
|
+
import { Entity, Index, PrimaryKey, Property } from "@mikro-orm/decorators/legacy";
|
|
13
|
+
OptionalProps;
|
|
14
|
+
let UserDevice = class {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.lastSeenAt = /* @__PURE__ */ new Date();
|
|
17
|
+
this.createdAt = /* @__PURE__ */ new Date();
|
|
18
|
+
this.updatedAt = /* @__PURE__ */ new Date();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
__decorateClass([
|
|
22
|
+
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
23
|
+
], UserDevice.prototype, "id", 2);
|
|
24
|
+
__decorateClass([
|
|
25
|
+
Property({ name: "tenant_id", type: "uuid" })
|
|
26
|
+
], UserDevice.prototype, "tenantId", 2);
|
|
27
|
+
__decorateClass([
|
|
28
|
+
Property({ name: "organization_id", type: "uuid", nullable: true })
|
|
29
|
+
], UserDevice.prototype, "organizationId", 2);
|
|
30
|
+
__decorateClass([
|
|
31
|
+
Property({ name: "user_id", type: "uuid" })
|
|
32
|
+
], UserDevice.prototype, "userId", 2);
|
|
33
|
+
__decorateClass([
|
|
34
|
+
Property({ name: "device_id", type: "text" })
|
|
35
|
+
], UserDevice.prototype, "deviceId", 2);
|
|
36
|
+
__decorateClass([
|
|
37
|
+
Property({ name: "platform", type: "text" })
|
|
38
|
+
], UserDevice.prototype, "platform", 2);
|
|
39
|
+
__decorateClass([
|
|
40
|
+
Property({ name: "client_app_version", type: "text", nullable: true })
|
|
41
|
+
], UserDevice.prototype, "clientAppVersion", 2);
|
|
42
|
+
__decorateClass([
|
|
43
|
+
Property({ name: "os_version", type: "text", nullable: true })
|
|
44
|
+
], UserDevice.prototype, "osVersion", 2);
|
|
45
|
+
__decorateClass([
|
|
46
|
+
Property({ name: "locale", type: "text", nullable: true })
|
|
47
|
+
], UserDevice.prototype, "locale", 2);
|
|
48
|
+
__decorateClass([
|
|
49
|
+
Property({ name: "push_token", type: "text", nullable: true })
|
|
50
|
+
], UserDevice.prototype, "pushToken", 2);
|
|
51
|
+
__decorateClass([
|
|
52
|
+
Property({ name: "push_provider", type: "text", nullable: true })
|
|
53
|
+
], UserDevice.prototype, "pushProvider", 2);
|
|
54
|
+
__decorateClass([
|
|
55
|
+
Property({ name: "push_token_updated_at", type: Date, nullable: true })
|
|
56
|
+
], UserDevice.prototype, "pushTokenUpdatedAt", 2);
|
|
57
|
+
__decorateClass([
|
|
58
|
+
Property({ name: "last_seen_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
59
|
+
], UserDevice.prototype, "lastSeenAt", 2);
|
|
60
|
+
__decorateClass([
|
|
61
|
+
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
62
|
+
], UserDevice.prototype, "createdAt", 2);
|
|
63
|
+
__decorateClass([
|
|
64
|
+
Property({ name: "updated_at", type: Date, onCreate: () => /* @__PURE__ */ new Date(), onUpdate: () => /* @__PURE__ */ new Date() })
|
|
65
|
+
], UserDevice.prototype, "updatedAt", 2);
|
|
66
|
+
__decorateClass([
|
|
67
|
+
Property({ name: "deleted_at", type: Date, nullable: true })
|
|
68
|
+
], UserDevice.prototype, "deletedAt", 2);
|
|
69
|
+
UserDevice = __decorateClass([
|
|
70
|
+
Entity({ tableName: "user_devices" }),
|
|
71
|
+
Index({ name: "user_devices_tenant_user_idx", properties: ["tenantId", "userId"] }),
|
|
72
|
+
Index({
|
|
73
|
+
// Device identity is scoped per organization: (tenant, org, user, device). organization_id is
|
|
74
|
+
// nullable, so the index is declared NULLS NOT DISTINCT — otherwise Postgres treats NULLs as
|
|
75
|
+
// distinct and would allow duplicate null-org rows for the same (tenant, user, device).
|
|
76
|
+
name: "user_devices_tenant_org_user_device_active_unique",
|
|
77
|
+
expression: 'create unique index "user_devices_tenant_org_user_device_active_unique" on "user_devices" ("tenant_id", "organization_id", "user_id", "device_id") nulls not distinct where deleted_at is null'
|
|
78
|
+
})
|
|
79
|
+
], UserDevice);
|
|
80
|
+
export {
|
|
81
|
+
UserDevice
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=entities.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/data/entities.ts"],
|
|
4
|
+
"sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport { Entity, Index, PrimaryKey, Property } from '@mikro-orm/decorators/legacy'\n\nexport type DevicePlatform = 'ios' | 'android' | 'web'\n\n@Entity({ tableName: 'user_devices' })\n@Index({ name: 'user_devices_tenant_user_idx', properties: ['tenantId', 'userId'] })\n@Index({\n // Device identity is scoped per organization: (tenant, org, user, device). organization_id is\n // nullable, so the index is declared NULLS NOT DISTINCT \u2014 otherwise Postgres treats NULLs as\n // distinct and would allow duplicate null-org rows for the same (tenant, user, device).\n name: 'user_devices_tenant_org_user_device_active_unique',\n expression:\n 'create unique index \"user_devices_tenant_org_user_device_active_unique\" on \"user_devices\" (\"tenant_id\", \"organization_id\", \"user_id\", \"device_id\") nulls not distinct where deleted_at is null',\n})\nexport class UserDevice {\n [OptionalProps]?:\n | 'organizationId'\n | 'clientAppVersion'\n | 'osVersion'\n | 'locale'\n | 'pushToken'\n | 'pushProvider'\n | 'pushTokenUpdatedAt'\n | 'lastSeenAt'\n | 'createdAt'\n | 'updatedAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'device_id', type: 'text' })\n deviceId!: string\n\n @Property({ name: 'platform', type: 'text' })\n platform!: DevicePlatform\n\n @Property({ name: 'client_app_version', type: 'text', nullable: true })\n clientAppVersion?: string | null\n\n @Property({ name: 'os_version', type: 'text', nullable: true })\n osVersion?: string | null\n\n // Per-device language the client app picked (BCP-47, e.g. `en` / `en-US`). Normalized to a\n // supported locale at push send time to translate the notification copy; null \u21D2 default locale.\n @Property({ name: 'locale', type: 'text', nullable: true })\n locale?: string | null\n\n @Property({ name: 'push_token', type: 'text', nullable: true })\n pushToken?: string | null\n\n @Property({ name: 'push_provider', type: 'text', nullable: true })\n pushProvider?: string | null\n\n @Property({ name: 'push_token_updated_at', type: Date, nullable: true })\n pushTokenUpdatedAt?: Date | null\n\n @Property({ name: 'last_seen_at', type: Date, onCreate: () => new Date() })\n lastSeenAt: Date = new Date()\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;AAAA,SAAS,qBAAqB;AAC9B,SAAS,QAAQ,OAAO,YAAY,gBAAgB;AAejD;AADI,IAAM,aAAN,MAAiB;AAAA,EAAjB;AAqDL,sBAAmB,oBAAI,KAAK;AAG5B,qBAAkB,oBAAI,KAAK;AAG3B,qBAAkB,oBAAI,KAAK;AAAA;AAI7B;AAhDE;AAAA,EADC,WAAW,EAAE,MAAM,QAAQ,YAAY,oBAAoB,CAAC;AAAA,GAdlD,WAeX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,aAAa,MAAM,OAAO,CAAC;AAAA,GAjBlC,WAkBX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,mBAAmB,MAAM,QAAQ,UAAU,KAAK,CAAC;AAAA,GApBxD,WAqBX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,WAAW,MAAM,OAAO,CAAC;AAAA,GAvBhC,WAwBX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,aAAa,MAAM,OAAO,CAAC;AAAA,GA1BlC,WA2BX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,YAAY,MAAM,OAAO,CAAC;AAAA,GA7BjC,WA8BX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,sBAAsB,MAAM,QAAQ,UAAU,KAAK,CAAC;AAAA,GAhC3D,WAiCX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK,CAAC;AAAA,GAnCnD,WAoCX;AAKA;AAAA,EADC,SAAS,EAAE,MAAM,UAAU,MAAM,QAAQ,UAAU,KAAK,CAAC;AAAA,GAxC/C,WAyCX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,QAAQ,UAAU,KAAK,CAAC;AAAA,GA3CnD,WA4CX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,iBAAiB,MAAM,QAAQ,UAAU,KAAK,CAAC;AAAA,GA9CtD,WA+CX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,yBAAyB,MAAM,MAAM,UAAU,KAAK,CAAC;AAAA,GAjD5D,WAkDX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,gBAAgB,MAAM,MAAM,UAAU,MAAM,oBAAI,KAAK,EAAE,CAAC;AAAA,GApD/D,WAqDX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,MAAM,UAAU,MAAM,oBAAI,KAAK,EAAE,CAAC;AAAA,GAvD7D,WAwDX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,MAAM,UAAU,MAAM,oBAAI,KAAK,GAAG,UAAU,MAAM,oBAAI,KAAK,EAAE,CAAC;AAAA,GA1DzF,WA2DX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,MAAM,UAAU,KAAK,CAAC;AAAA,GA7DjD,WA8DX;AA9DW,aAAN;AAAA,EAVN,OAAO,EAAE,WAAW,eAAe,CAAC;AAAA,EACpC,MAAM,EAAE,MAAM,gCAAgC,YAAY,CAAC,YAAY,QAAQ,EAAE,CAAC;AAAA,EAClF,MAAM;AAAA;AAAA;AAAA;AAAA,IAIL,MAAM;AAAA,IACN,YACE;AAAA,EACJ,CAAC;AAAA,GACY;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const devicePlatformSchema = z.enum(["ios", "android", "web"]);
|
|
3
|
+
const registerDeviceSchema = z.object({
|
|
4
|
+
deviceId: z.string().trim().min(1).max(255),
|
|
5
|
+
platform: devicePlatformSchema,
|
|
6
|
+
clientAppVersion: z.string().trim().max(64).nullish(),
|
|
7
|
+
osVersion: z.string().trim().max(64).nullish(),
|
|
8
|
+
locale: z.string().trim().min(2).max(35).nullish(),
|
|
9
|
+
pushToken: z.string().trim().min(1).max(4096).nullish(),
|
|
10
|
+
pushProvider: z.string().trim().min(1).max(32).nullish()
|
|
11
|
+
}).strict();
|
|
12
|
+
const registerDeviceAdminSchema = registerDeviceSchema.extend({
|
|
13
|
+
userId: z.string().uuid()
|
|
14
|
+
});
|
|
15
|
+
const updateDeviceSchema = z.object({
|
|
16
|
+
clientAppVersion: z.string().trim().max(64).nullable().optional(),
|
|
17
|
+
osVersion: z.string().trim().max(64).nullable().optional(),
|
|
18
|
+
locale: z.string().trim().min(2).max(35).nullable().optional(),
|
|
19
|
+
pushToken: z.string().trim().min(1).max(4096).nullable().optional(),
|
|
20
|
+
pushProvider: z.string().trim().min(1).max(32).nullable().optional(),
|
|
21
|
+
lastSeenAt: z.coerce.date().optional()
|
|
22
|
+
}).strict();
|
|
23
|
+
const registerDeviceCommandSchema = registerDeviceSchema.extend({
|
|
24
|
+
tenantId: z.string().uuid(),
|
|
25
|
+
organizationId: z.string().uuid().nullable().optional(),
|
|
26
|
+
userId: z.string().uuid()
|
|
27
|
+
});
|
|
28
|
+
const updateDeviceCommandSchema = updateDeviceSchema.extend({
|
|
29
|
+
id: z.string().uuid(),
|
|
30
|
+
tenantId: z.string().uuid(),
|
|
31
|
+
userId: z.string().uuid(),
|
|
32
|
+
organizationId: z.string().uuid().nullable().optional()
|
|
33
|
+
});
|
|
34
|
+
const deactivateDeviceCommandSchema = z.object({
|
|
35
|
+
id: z.string().uuid(),
|
|
36
|
+
tenantId: z.string().uuid(),
|
|
37
|
+
userId: z.string().uuid(),
|
|
38
|
+
organizationId: z.string().uuid().nullable().optional()
|
|
39
|
+
});
|
|
40
|
+
export {
|
|
41
|
+
deactivateDeviceCommandSchema,
|
|
42
|
+
devicePlatformSchema,
|
|
43
|
+
registerDeviceAdminSchema,
|
|
44
|
+
registerDeviceCommandSchema,
|
|
45
|
+
registerDeviceSchema,
|
|
46
|
+
updateDeviceCommandSchema,
|
|
47
|
+
updateDeviceSchema
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/data/validators.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\n\nexport const devicePlatformSchema = z.enum(['ios', 'android', 'web'])\nexport type DevicePlatformInput = z.infer<typeof devicePlatformSchema>\n\n// POST /api/devices \u2014 register/upsert. pushToken/pushProvider optional on first register.\nexport const registerDeviceSchema = z\n .object({\n deviceId: z.string().trim().min(1).max(255),\n platform: devicePlatformSchema,\n clientAppVersion: z.string().trim().max(64).nullish(),\n osVersion: z.string().trim().max(64).nullish(),\n locale: z.string().trim().min(2).max(35).nullish(),\n pushToken: z.string().trim().min(1).max(4096).nullish(),\n pushProvider: z.string().trim().min(1).max(32).nullish(),\n })\n .strict()\nexport type RegisterDeviceInput = z.infer<typeof registerDeviceSchema>\n\n// POST /api/devices/admin/devices \u2014 admin registers a device on behalf of any user in the tenant.\n// Same shape as self-register plus an explicit target userId (self-register derives it from auth).\nexport const registerDeviceAdminSchema = registerDeviceSchema.extend({\n userId: z.string().uuid(),\n})\nexport type RegisterDeviceAdminInput = z.infer<typeof registerDeviceAdminSchema>\n\n// PUT /api/devices/:id \u2014 partial update.\n// pushToken/pushProvider are tri-state: absent (leave unchanged) vs explicit null (clear).\n// `.nullable().optional()` distinguishes `undefined` from `null`; the command relies on\n// own-property presence to decide whether to touch the column.\nexport const updateDeviceSchema = z\n .object({\n clientAppVersion: z.string().trim().max(64).nullable().optional(),\n osVersion: z.string().trim().max(64).nullable().optional(),\n locale: z.string().trim().min(2).max(35).nullable().optional(),\n pushToken: z.string().trim().min(1).max(4096).nullable().optional(),\n pushProvider: z.string().trim().min(1).max(32).nullable().optional(),\n lastSeenAt: z.coerce.date().optional(),\n })\n .strict()\nexport type UpdateDeviceInput = z.infer<typeof updateDeviceSchema>\n\n// Command-side schemas append the resolved scope. Scope fields are never accepted from the client body.\nexport const registerDeviceCommandSchema = registerDeviceSchema.extend({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable().optional(),\n userId: z.string().uuid(),\n})\nexport type RegisterDeviceCommandInput = z.infer<typeof registerDeviceCommandSchema>\n\nexport const updateDeviceCommandSchema = updateDeviceSchema.extend({\n id: z.string().uuid(),\n tenantId: z.string().uuid(),\n userId: z.string().uuid(),\n organizationId: z.string().uuid().nullable().optional(),\n})\nexport type UpdateDeviceCommandInput = z.infer<typeof updateDeviceCommandSchema>\n\nexport const deactivateDeviceCommandSchema = z.object({\n id: z.string().uuid(),\n tenantId: z.string().uuid(),\n userId: z.string().uuid(),\n organizationId: z.string().uuid().nullable().optional(),\n})\nexport type DeactivateDeviceCommandInput = z.infer<typeof deactivateDeviceCommandSchema>\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAEX,MAAM,uBAAuB,EAAE,KAAK,CAAC,OAAO,WAAW,KAAK,CAAC;AAI7D,MAAM,uBAAuB,EACjC,OAAO;AAAA,EACN,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC1C,UAAU;AAAA,EACV,kBAAkB,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ;AAAA,EACpD,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ;AAAA,EAC7C,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ;AAAA,EACjD,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,QAAQ;AAAA,EACtD,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ;AACzD,CAAC,EACA,OAAO;AAKH,MAAM,4BAA4B,qBAAqB,OAAO;AAAA,EACnE,QAAQ,EAAE,OAAO,EAAE,KAAK;AAC1B,CAAC;AAOM,MAAM,qBAAqB,EAC/B,OAAO;AAAA,EACN,kBAAkB,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS;AAAA,EAChE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS;AAAA,EACzD,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS;AAAA,EAC7D,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAClE,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS;AAAA,EACnE,YAAY,EAAE,OAAO,KAAK,EAAE,SAAS;AACvC,CAAC,EACA,OAAO;AAIH,MAAM,8BAA8B,qBAAqB,OAAO;AAAA,EACrE,UAAU,EAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,EACtD,QAAQ,EAAE,OAAO,EAAE,KAAK;AAC1B,CAAC;AAGM,MAAM,4BAA4B,mBAAmB,OAAO;AAAA,EACjE,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,UAAU,EAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,EACxB,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AACxD,CAAC;AAGM,MAAM,gCAAgC,EAAE,OAAO;AAAA,EACpD,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,UAAU,EAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,EACxB,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AACxD,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/devices/di.ts"],
|
|
4
|
+
"sourcesContent": ["import { asValue } from 'awilix'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport { UserDevice } from './data/entities'\n\nexport function register(container: AppContainer) {\n container.register({\n UserDevice: asValue(UserDevice),\n })\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,eAAe;AAExB,SAAS,kBAAkB;AAEpB,SAAS,SAAS,WAAyB;AAChD,YAAU,SAAS;AAAA,IACjB,YAAY,QAAQ,UAAU;AAAA,EAChC,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const defaultEncryptionMaps = [
|
|
2
|
+
{
|
|
3
|
+
entityId: "devices:user_device",
|
|
4
|
+
fields: [{ field: "push_token" }]
|
|
5
|
+
}
|
|
6
|
+
];
|
|
7
|
+
var encryption_default = defaultEncryptionMaps;
|
|
8
|
+
export {
|
|
9
|
+
encryption_default as default,
|
|
10
|
+
defaultEncryptionMaps
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=encryption.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/devices/encryption.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleEncryptionMap } from '@open-mercato/shared/modules/encryption'\n\n// `push_token` is a long-lived provider secret. It is never exposed via the API (only a last-8\n// snapshot is persisted on delivery rows) and is redacted from audit-log snapshots, so it is\n// encrypted at rest. Reads route through `findWithDecryption`/`findOneWithDecryption` per the\n// `packages/core/AGENTS.md` Encryption section. No blind-index column is needed: the push delivery\n// path looks devices up by id/user, never by token value.\nexport const defaultEncryptionMaps: ModuleEncryptionMap[] = [\n {\n entityId: 'devices:user_device',\n fields: [{ field: 'push_token' }],\n },\n]\n\nexport default defaultEncryptionMaps\n"],
|
|
5
|
+
"mappings": "AAOO,MAAM,wBAA+C;AAAA,EAC1D;AAAA,IACE,UAAU;AAAA,IACV,QAAQ,CAAC,EAAE,OAAO,aAAa,CAAC;AAAA,EAClC;AACF;AAEA,IAAO,qBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createModuleEvents } from "@open-mercato/shared/modules/events";
|
|
2
|
+
const events = [
|
|
3
|
+
// Domain events (spec contract): emitted explicitly from commands.
|
|
4
|
+
{ id: "devices.user_device.registered", label: "User Device Registered", entity: "user_device", category: "crud" },
|
|
5
|
+
{ id: "devices.user_device.deactivated", label: "User Device Deactivated", entity: "user_device", category: "crud" },
|
|
6
|
+
// CRUD lifecycle events emitted by emitCrudSideEffects (keep declared to avoid undeclared-event warnings).
|
|
7
|
+
{ id: "devices.user_device.created", label: "User Device Created", entity: "user_device", category: "crud" },
|
|
8
|
+
{ id: "devices.user_device.updated", label: "User Device Updated", entity: "user_device", category: "crud" },
|
|
9
|
+
{ id: "devices.user_device.deleted", label: "User Device Deleted", entity: "user_device", category: "crud" }
|
|
10
|
+
];
|
|
11
|
+
const eventsConfig = createModuleEvents({ moduleId: "devices", events });
|
|
12
|
+
const emitDevicesEvent = eventsConfig.emit;
|
|
13
|
+
var events_default = eventsConfig;
|
|
14
|
+
export {
|
|
15
|
+
events_default as default,
|
|
16
|
+
emitDevicesEvent,
|
|
17
|
+
eventsConfig
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/devices/events.ts"],
|
|
4
|
+
"sourcesContent": ["import { createModuleEvents } from '@open-mercato/shared/modules/events'\n\nconst events = [\n // Domain events (spec contract): emitted explicitly from commands.\n { id: 'devices.user_device.registered', label: 'User Device Registered', entity: 'user_device', category: 'crud' },\n { id: 'devices.user_device.deactivated', label: 'User Device Deactivated', entity: 'user_device', category: 'crud' },\n // CRUD lifecycle events emitted by emitCrudSideEffects (keep declared to avoid undeclared-event warnings).\n { id: 'devices.user_device.created', label: 'User Device Created', entity: 'user_device', category: 'crud' },\n { id: 'devices.user_device.updated', label: 'User Device Updated', entity: 'user_device', category: 'crud' },\n { id: 'devices.user_device.deleted', label: 'User Device Deleted', entity: 'user_device', category: 'crud' },\n] as const\n\nexport const eventsConfig = createModuleEvents({ moduleId: 'devices', events })\nexport const emitDevicesEvent = eventsConfig.emit\nexport type DevicesEventId = typeof events[number]['id']\nexport default eventsConfig\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,0BAA0B;AAEnC,MAAM,SAAS;AAAA;AAAA,EAEb,EAAE,IAAI,kCAAkC,OAAO,0BAA0B,QAAQ,eAAe,UAAU,OAAO;AAAA,EACjH,EAAE,IAAI,mCAAmC,OAAO,2BAA2B,QAAQ,eAAe,UAAU,OAAO;AAAA;AAAA,EAEnH,EAAE,IAAI,+BAA+B,OAAO,uBAAuB,QAAQ,eAAe,UAAU,OAAO;AAAA,EAC3G,EAAE,IAAI,+BAA+B,OAAO,uBAAuB,QAAQ,eAAe,UAAU,OAAO;AAAA,EAC3G,EAAE,IAAI,+BAA+B,OAAO,uBAAuB,QAAQ,eAAe,UAAU,OAAO;AAC7G;AAEO,MAAM,eAAe,mBAAmB,EAAE,UAAU,WAAW,OAAO,CAAC;AACvE,MAAM,mBAAmB,aAAa;AAE7C,IAAO,iBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "./commands/index.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
name: "devices",
|
|
4
|
+
title: "Devices",
|
|
5
|
+
version: "0.1.0",
|
|
6
|
+
description: "Per-tenant user device registry (platform, app/OS metadata, push token storage).",
|
|
7
|
+
author: "Open Mercato Team",
|
|
8
|
+
license: "MIT",
|
|
9
|
+
requires: ["auth"],
|
|
10
|
+
ejectable: true
|
|
11
|
+
};
|
|
12
|
+
import { features } from "./acl.js";
|
|
13
|
+
export {
|
|
14
|
+
features,
|
|
15
|
+
metadata
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/devices/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleInfo } from '@open-mercato/shared/modules/registry'\nimport './commands'\n\nexport const metadata: ModuleInfo = {\n name: 'devices',\n title: 'Devices',\n version: '0.1.0',\n description: 'Per-tenant user device registry (platform, app/OS metadata, push token storage).',\n author: 'Open Mercato Team',\n license: 'MIT',\n requires: ['auth'],\n ejectable: true,\n}\n\nexport { features } from './acl'\n"],
|
|
5
|
+
"mappings": "AACA,OAAO;AAEA,MAAM,WAAuB;AAAA,EAClC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU,CAAC,MAAM;AAAA,EACjB,WAAW;AACb;AAEA,SAAS,gBAAgB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { serializeOperationMetadata } from "@open-mercato/shared/lib/commands/operationMetadata";
|
|
2
|
+
function attachOperationMetadataHeader(response, logEntry, fallback) {
|
|
3
|
+
if (!logEntry?.undoToken || !logEntry.id || !logEntry.commandId) return;
|
|
4
|
+
response.headers.set(
|
|
5
|
+
"x-om-operation",
|
|
6
|
+
serializeOperationMetadata({
|
|
7
|
+
id: logEntry.id,
|
|
8
|
+
undoToken: logEntry.undoToken,
|
|
9
|
+
commandId: logEntry.commandId,
|
|
10
|
+
actionLabel: logEntry.actionLabel ?? null,
|
|
11
|
+
resourceKind: logEntry.resourceKind ?? fallback.resourceKind,
|
|
12
|
+
resourceId: logEntry.resourceId ?? fallback.resourceId,
|
|
13
|
+
executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
attachOperationMetadataHeader
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=operationMetadata.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/lib/operationMetadata.ts"],
|
|
4
|
+
"sourcesContent": ["import { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\n\ntype OperationLogEntry = {\n id?: string | null\n undoToken?: string | null\n commandId?: string | null\n actionLabel?: string | null\n resourceKind?: string | null\n resourceId?: string | null\n createdAt?: Date | null\n}\n\n/**\n * Attaches the `x-om-operation` undo header to a response when the command produced an\n * undoable log entry. No-op otherwise.\n */\nexport function attachOperationMetadataHeader(\n response: Response,\n logEntry: OperationLogEntry | null | undefined,\n fallback: { resourceKind: string; resourceId: string },\n): void {\n if (!logEntry?.undoToken || !logEntry.id || !logEntry.commandId) return\n response.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? fallback.resourceKind,\n resourceId: logEntry.resourceId ?? fallback.resourceId,\n executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : new Date().toISOString(),\n }),\n )\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,kCAAkC;AAgBpC,SAAS,8BACd,UACA,UACA,UACM;AACN,MAAI,CAAC,UAAU,aAAa,CAAC,SAAS,MAAM,CAAC,SAAS,UAAW;AACjE,WAAS,QAAQ;AAAA,IACf;AAAA,IACA,2BAA2B;AAAA,MACzB,IAAI,SAAS;AAAA,MACb,WAAW,SAAS;AAAA,MACpB,WAAW,SAAS;AAAA,MACpB,aAAa,SAAS,eAAe;AAAA,MACrC,cAAc,SAAS,gBAAgB,SAAS;AAAA,MAChD,YAAY,SAAS,cAAc,SAAS;AAAA,MAC5C,YAAY,SAAS,qBAAqB,OAAO,SAAS,UAAU,YAAY,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC7G,CAAC;AAAA,EACH;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260602120000 extends Migration {
|
|
3
|
+
async up() {
|
|
4
|
+
this.addSql(`create table "user_devices" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid null, "user_id" uuid not null, "device_id" text not null, "platform" text not null, "client_app_version" text null, "os_version" text null, "push_token" text null, "push_provider" text null, "push_token_updated_at" timestamptz null, "last_seen_at" timestamptz not null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "user_devices_pkey" primary key ("id"));`);
|
|
5
|
+
this.addSql(`create index "user_devices_tenant_user_idx" on "user_devices" ("tenant_id", "user_id");`);
|
|
6
|
+
this.addSql(`create unique index "user_devices_tenant_user_device_active_unique" on "user_devices" ("tenant_id", "user_id", "device_id") where deleted_at is null;`);
|
|
7
|
+
}
|
|
8
|
+
async down() {
|
|
9
|
+
this.addSql(`drop table if exists "user_devices" cascade;`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
Migration20260602120000
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=Migration20260602120000.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/migrations/Migration20260602120000.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260602120000 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`create table \"user_devices\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid null, \"user_id\" uuid not null, \"device_id\" text not null, \"platform\" text not null, \"client_app_version\" text null, \"os_version\" text null, \"push_token\" text null, \"push_provider\" text null, \"push_token_updated_at\" timestamptz null, \"last_seen_at\" timestamptz not null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, constraint \"user_devices_pkey\" primary key (\"id\"));`);\n this.addSql(`create index \"user_devices_tenant_user_idx\" on \"user_devices\" (\"tenant_id\", \"user_id\");`);\n this.addSql(`create unique index \"user_devices_tenant_user_device_active_unique\" on \"user_devices\" (\"tenant_id\", \"user_id\", \"device_id\") where deleted_at is null;`);\n }\n\n override async down(): Promise<void> {\n this.addSql(`drop table if exists \"user_devices\" cascade;`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,qiBAAqiB;AACjjB,SAAK,OAAO,yFAAyF;AACrG,SAAK,OAAO,uJAAuJ;AAAA,EACrK;AAAA,EAEA,MAAe,OAAsB;AACnC,SAAK,OAAO,8CAA8C;AAAA,EAC5D;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|