@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,71 @@
|
|
|
1
|
+
import { LockMode } from "@mikro-orm/core";
|
|
2
|
+
import { detectLocale, loadDictionary } from "@open-mercato/shared/lib/i18n/server";
|
|
3
|
+
import { createFallbackTranslator } from "@open-mercato/shared/lib/i18n/translate";
|
|
4
|
+
import { resolveSupportedLocale } from "@open-mercato/shared/lib/i18n/locale";
|
|
5
|
+
import { resolveLocaleFromRequest } from "../../translations/lib/locale.js";
|
|
6
|
+
import { NotificationTypeOverride } from "../data/entities.js";
|
|
7
|
+
import { getNotificationDeliveryStrategies } from "./deliveryStrategies.js";
|
|
8
|
+
import { getNotificationType } from "./notification-type-registry.js";
|
|
9
|
+
const CATEGORY_LABEL_KEY_PREFIX = "notifications.categories.";
|
|
10
|
+
async function resolveCatalogueTranslate(req) {
|
|
11
|
+
const requested = resolveSupportedLocale(resolveLocaleFromRequest(req));
|
|
12
|
+
const locale = requested ?? await detectLocale();
|
|
13
|
+
return createFallbackTranslator(await loadDictionary(locale));
|
|
14
|
+
}
|
|
15
|
+
const typeItem = (row, override, translate) => ({
|
|
16
|
+
id: row.id,
|
|
17
|
+
labelKey: row.labelKey,
|
|
18
|
+
descriptionKey: row.descriptionKey ?? null,
|
|
19
|
+
category: row.category ?? null,
|
|
20
|
+
categoryLabel: row.category ? translate(`${CATEGORY_LABEL_KEY_PREFIX}${row.category}`, row.category) : null,
|
|
21
|
+
label: row.labelKey ? translate(row.labelKey, row.id) : null,
|
|
22
|
+
description: row.descriptionKey ? translate(row.descriptionKey, "") : null,
|
|
23
|
+
silent: row.silent === true,
|
|
24
|
+
nonOptOut: (override?.nonOptOut ?? row.nonOptOut) === true,
|
|
25
|
+
channels: override?.channels ?? getNotificationType(row.id)?.channels ?? null,
|
|
26
|
+
storedChannels: override?.channels ?? null,
|
|
27
|
+
storedNonOptOut: override?.nonOptOut ?? null,
|
|
28
|
+
updatedAt: override?.updatedAt ? override.updatedAt.toISOString() : null
|
|
29
|
+
});
|
|
30
|
+
function resolveRegisteredChannelIds() {
|
|
31
|
+
return getNotificationDeliveryStrategies().map((strategy) => strategy.id);
|
|
32
|
+
}
|
|
33
|
+
function resolveEffectiveChannels(typeId, storedChannels, registeredChannelIds) {
|
|
34
|
+
return storedChannels ?? getNotificationType(typeId)?.channels ?? registeredChannelIds;
|
|
35
|
+
}
|
|
36
|
+
function loadTypeOverrideForUpdate(em, tenantId, notificationTypeId) {
|
|
37
|
+
return em.findOne(
|
|
38
|
+
NotificationTypeOverride,
|
|
39
|
+
{ tenantId, notificationTypeId },
|
|
40
|
+
{ lockMode: LockMode.PESSIMISTIC_WRITE }
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
function applyTypeOverride(em, input) {
|
|
44
|
+
const { tenantId, notificationTypeId, existing, nextChannels, nextNonOptOut } = input;
|
|
45
|
+
if (nextChannels === null && nextNonOptOut === null) {
|
|
46
|
+
if (existing) em.remove(existing);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
if (existing) {
|
|
50
|
+
existing.channels = nextChannels;
|
|
51
|
+
existing.nonOptOut = nextNonOptOut;
|
|
52
|
+
return existing;
|
|
53
|
+
}
|
|
54
|
+
const created = em.create(NotificationTypeOverride, {
|
|
55
|
+
tenantId,
|
|
56
|
+
notificationTypeId,
|
|
57
|
+
channels: nextChannels,
|
|
58
|
+
nonOptOut: nextNonOptOut
|
|
59
|
+
});
|
|
60
|
+
em.persist(created);
|
|
61
|
+
return created;
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
applyTypeOverride,
|
|
65
|
+
loadTypeOverrideForUpdate,
|
|
66
|
+
resolveCatalogueTranslate,
|
|
67
|
+
resolveEffectiveChannels,
|
|
68
|
+
resolveRegisteredChannelIds,
|
|
69
|
+
typeItem
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=typeCatalogue.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/lib/typeCatalogue.ts"],
|
|
4
|
+
"sourcesContent": ["import { LockMode } from '@mikro-orm/core'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { detectLocale, loadDictionary } from '@open-mercato/shared/lib/i18n/server'\nimport { createFallbackTranslator } from '@open-mercato/shared/lib/i18n/translate'\nimport { resolveSupportedLocale } from '@open-mercato/shared/lib/i18n/locale'\nimport { resolveLocaleFromRequest } from '../../translations/lib/locale'\nimport { NotificationType, NotificationTypeOverride } from '../data/entities'\nimport { getNotificationDeliveryStrategies } from './deliveryStrategies'\nimport { getNotificationType } from './notification-type-registry'\n\nconst CATEGORY_LABEL_KEY_PREFIX = 'notifications.categories.'\n\nexport type CatalogueTranslate = (key: string, fallback: string) => string\n\n/**\n * Locale for the display strings, following the repo-wide request-locale convention\n * (`resolveLocaleFromRequest`: `?locale=` \u2192 `x-locale` \u2192 cookie \u2192 `Accept-Language`).\n * Only the `Accept-Language` branch of that helper validates its input, so the result is\n * re-checked against the supported set here \u2014 an unsupported `?locale=zz` would otherwise\n * load an empty dictionary instead of degrading. Falls back to ambient detection, which\n * also honours `OM_FORCE_LOCALE`.\n */\nexport async function resolveCatalogueTranslate(req: Request): Promise<CatalogueTranslate> {\n const requested = resolveSupportedLocale(resolveLocaleFromRequest(req))\n const locale = requested ?? (await detectLocale())\n return createFallbackTranslator(await loadDictionary(locale))\n}\n\n/**\n * Catalogue item with the caller tenant's stored overrides merged in \u2014 matching\n * `resolveEligibleChannels` in the delivery gate, so preference UIs lock exactly the cells\n * delivery would reject. `channels: null` = no restriction (every registered channel).\n * `updatedAt` is the override row's version token for optimistic locking (`null` when the\n * tenant stores no override yet).\n *\n * `label` / `description` / `categoryLabel` are resolved server-side so clients without the\n * Open Mercato dictionary (the mobile app) can render the screen directly. Group on\n * `category` \u2014 the raw key, stable across locales \u2014 and display `categoryLabel`; grouping on\n * the localized string re-partitions the list whenever the language changes.\n *\n * A category whose owning module ships no `notifications.categories.<key>` entry falls back\n * to the raw key, so `categoryLabel === category` signals to a client that no server-side\n * translation exists and it may apply its own presentation.\n */\nexport const typeItem = (\n row: NotificationType,\n override: NotificationTypeOverride | null | undefined,\n translate: CatalogueTranslate,\n) => ({\n id: row.id,\n labelKey: row.labelKey,\n descriptionKey: row.descriptionKey ?? null,\n category: row.category ?? null,\n categoryLabel: row.category\n ? translate(`${CATEGORY_LABEL_KEY_PREFIX}${row.category}`, row.category)\n : null,\n label: row.labelKey ? translate(row.labelKey, row.id) : null,\n description: row.descriptionKey ? translate(row.descriptionKey, '') : null,\n silent: row.silent === true,\n nonOptOut: (override?.nonOptOut ?? row.nonOptOut) === true,\n channels: override?.channels ?? getNotificationType(row.id)?.channels ?? null,\n storedChannels: override?.channels ?? null,\n storedNonOptOut: override?.nonOptOut ?? null,\n updatedAt: override?.updatedAt ? override.updatedAt.toISOString() : null,\n})\n\n/** Ids of every registered delivery channel (`in_app`, `email`, `push`, \u2026). */\nexport function resolveRegisteredChannelIds(): string[] {\n return getNotificationDeliveryStrategies().map((strategy) => strategy.id)\n}\n\n/**\n * The channel set a per-channel toggle applies to, resolved server-side so a client never\n * has to send a whole replacing array. Mirrors what the catalogue exposes as the effective\n * set \u2014 stored override, else the code declaration, else every registered channel (the\n * `channels: null` \"no restriction\" case, which a toggle has to materialize before it can\n * remove one entry from it).\n */\nexport function resolveEffectiveChannels(\n typeId: string,\n storedChannels: string[] | null | undefined,\n registeredChannelIds: string[],\n): string[] {\n return storedChannels ?? getNotificationType(typeId)?.channels ?? registeredChannelIds\n}\n\n/**\n * Load the tenant's override row for a type under a row lock, so a read-modify-write of the\n * `channels` array serializes against a concurrent one instead of last-write-wins. Returns\n * `null` when no override is stored yet (nothing exists to lock \u2014 that first-write race is\n * caught by the partial unique index instead).\n */\nexport function loadTypeOverrideForUpdate(\n em: EntityManager,\n tenantId: string,\n notificationTypeId: string,\n): Promise<NotificationTypeOverride | null> {\n return em.findOne(\n NotificationTypeOverride,\n { tenantId, notificationTypeId },\n { lockMode: LockMode.PESSIMISTIC_WRITE },\n )\n}\n\n/**\n * Apply the resolved override values to the tenant's row, creating, updating or dropping it.\n * Shared by the full-array `PATCH` and the per-channel add/remove sub-resource so both agree\n * on the \"all overrides cleared \u21D2 remove the row\" rule. Does NOT flush \u2014 the caller owns the\n * transaction boundary and the unique-violation handling.\n */\nexport function applyTypeOverride(\n em: EntityManager,\n input: {\n tenantId: string\n notificationTypeId: string\n existing: NotificationTypeOverride | null\n nextChannels: string[] | null\n nextNonOptOut: boolean | null\n },\n): NotificationTypeOverride | null {\n const { tenantId, notificationTypeId, existing, nextChannels, nextNonOptOut } = input\n if (nextChannels === null && nextNonOptOut === null) {\n // Both overrides cleared \u21D2 the code declarations apply again; drop the row\n // instead of keeping an all-null husk.\n if (existing) em.remove(existing)\n return null\n }\n if (existing) {\n existing.channels = nextChannels\n existing.nonOptOut = nextNonOptOut\n return existing\n }\n const created = em.create(NotificationTypeOverride, {\n tenantId,\n notificationTypeId,\n channels: nextChannels,\n nonOptOut: nextNonOptOut,\n })\n em.persist(created)\n return created\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,gBAAgB;AAEzB,SAAS,cAAc,sBAAsB;AAC7C,SAAS,gCAAgC;AACzC,SAAS,8BAA8B;AACvC,SAAS,gCAAgC;AACzC,SAA2B,gCAAgC;AAC3D,SAAS,yCAAyC;AAClD,SAAS,2BAA2B;AAEpC,MAAM,4BAA4B;AAYlC,eAAsB,0BAA0B,KAA2C;AACzF,QAAM,YAAY,uBAAuB,yBAAyB,GAAG,CAAC;AACtE,QAAM,SAAS,aAAc,MAAM,aAAa;AAChD,SAAO,yBAAyB,MAAM,eAAe,MAAM,CAAC;AAC9D;AAkBO,MAAM,WAAW,CACtB,KACA,UACA,eACI;AAAA,EACJ,IAAI,IAAI;AAAA,EACR,UAAU,IAAI;AAAA,EACd,gBAAgB,IAAI,kBAAkB;AAAA,EACtC,UAAU,IAAI,YAAY;AAAA,EAC1B,eAAe,IAAI,WACf,UAAU,GAAG,yBAAyB,GAAG,IAAI,QAAQ,IAAI,IAAI,QAAQ,IACrE;AAAA,EACJ,OAAO,IAAI,WAAW,UAAU,IAAI,UAAU,IAAI,EAAE,IAAI;AAAA,EACxD,aAAa,IAAI,iBAAiB,UAAU,IAAI,gBAAgB,EAAE,IAAI;AAAA,EACtE,QAAQ,IAAI,WAAW;AAAA,EACvB,YAAY,UAAU,aAAa,IAAI,eAAe;AAAA,EACtD,UAAU,UAAU,YAAY,oBAAoB,IAAI,EAAE,GAAG,YAAY;AAAA,EACzE,gBAAgB,UAAU,YAAY;AAAA,EACtC,iBAAiB,UAAU,aAAa;AAAA,EACxC,WAAW,UAAU,YAAY,SAAS,UAAU,YAAY,IAAI;AACtE;AAGO,SAAS,8BAAwC;AACtD,SAAO,kCAAkC,EAAE,IAAI,CAAC,aAAa,SAAS,EAAE;AAC1E;AASO,SAAS,yBACd,QACA,gBACA,sBACU;AACV,SAAO,kBAAkB,oBAAoB,MAAM,GAAG,YAAY;AACpE;AAQO,SAAS,0BACd,IACA,UACA,oBAC0C;AAC1C,SAAO,GAAG;AAAA,IACR;AAAA,IACA,EAAE,UAAU,mBAAmB;AAAA,IAC/B,EAAE,UAAU,SAAS,kBAAkB;AAAA,EACzC;AACF;AAQO,SAAS,kBACd,IACA,OAOiC;AACjC,QAAM,EAAE,UAAU,oBAAoB,UAAU,cAAc,cAAc,IAAI;AAChF,MAAI,iBAAiB,QAAQ,kBAAkB,MAAM;AAGnD,QAAI,SAAU,IAAG,OAAO,QAAQ;AAChC,WAAO;AAAA,EACT;AACA,MAAI,UAAU;AACZ,aAAS,WAAW;AACpB,aAAS,YAAY;AACrB,WAAO;AAAA,EACT;AACA,QAAM,UAAU,GAAG,OAAO,0BAA0B;AAAA,IAClD;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACD,KAAG,QAAQ,OAAO;AAClB,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
function computeNextChannels(effective, channelId, enabled) {
|
|
2
|
+
return enabled ? Array.from(/* @__PURE__ */ new Set([...effective, channelId])) : effective.filter((channel) => channel !== channelId);
|
|
3
|
+
}
|
|
4
|
+
function computeChannelsPatch(effective, channelId, enabled) {
|
|
5
|
+
const next = computeNextChannels(effective, channelId, enabled);
|
|
6
|
+
return next.length > 0 ? next : null;
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
computeChannelsPatch,
|
|
10
|
+
computeNextChannels
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=typeChannelSettings.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/lib/typeChannelSettings.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Next eligibility set after toggling one channel in the admin type-catalogue\n * table, based on the EFFECTIVE set (tenant override ?? code ?? all registered\n * channels) \u2014 the stored array replaces the code-declared set wholesale.\n */\nexport function computeNextChannels(\n effective: string[],\n channelId: string,\n enabled: boolean,\n): string[] {\n return enabled\n ? Array.from(new Set([...effective, channelId]))\n : effective.filter((channel) => channel !== channelId)\n}\n\n/**\n * The `channels` value to PATCH after one toggle: the next eligibility set, or `null` when the\n * toggle empties it (unchecking the last channel). Persisting `[]` would black-hole the type\n * (invisible + undelivered) and is rejected by the API \u2014 `null` clears the override so the\n * code-declared default reapplies.\n */\nexport function computeChannelsPatch(\n effective: string[],\n channelId: string,\n enabled: boolean,\n): string[] | null {\n const next = computeNextChannels(effective, channelId, enabled)\n return next.length > 0 ? next : null\n}\n"],
|
|
5
|
+
"mappings": "AAKO,SAAS,oBACd,WACA,WACA,SACU;AACV,SAAO,UACH,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAG,WAAW,SAAS,CAAC,CAAC,IAC7C,UAAU,OAAO,CAAC,YAAY,YAAY,SAAS;AACzD;AAQO,SAAS,qBACd,WACA,WACA,SACiB;AACjB,QAAM,OAAO,oBAAoB,WAAW,WAAW,OAAO;AAC9D,SAAO,KAAK,SAAS,IAAI,OAAO;AAClC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
async function getNotificationTypeOverrides(em, tenantId, typeIds) {
|
|
2
|
+
const result = /* @__PURE__ */ new Map();
|
|
3
|
+
const uniqueIds = Array.from(new Set(typeIds)).filter((id) => id.length > 0);
|
|
4
|
+
if (!uniqueIds.length || !tenantId) return result;
|
|
5
|
+
const db = em.getKysely();
|
|
6
|
+
const rows = await db.selectFrom("notification_type_overrides").select(["notification_type_id", "channels", "non_opt_out"]).where("tenant_id", "=", tenantId).where("notification_type_id", "in", uniqueIds).execute();
|
|
7
|
+
for (const row of rows) {
|
|
8
|
+
const channels = Array.isArray(row.channels) ? row.channels : null;
|
|
9
|
+
const nonOptOut = typeof row.non_opt_out === "boolean" ? row.non_opt_out : null;
|
|
10
|
+
if (channels !== null || nonOptOut !== null) {
|
|
11
|
+
result.set(row.notification_type_id, { channels, nonOptOut });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
getNotificationTypeOverrides
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=typeOverrides.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/lib/typeOverrides.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { Kysely } from 'kysely'\n\n/**\n * Tenant-scoped operator overrides of a notification type's delivery contract,\n * read from `notification_type_overrides`. Types without a row (or whose row\n * stores neither field) are absent from the map \u2014 the code declarations apply.\n * Used by the create-time gate, the deliver-subscriber recompute, and the\n * preference write path so `shouldDeliver` applies the same effective\n * eligibility + opt-out governance the types API reports.\n */\nexport type NotificationTypeOverrides = {\n /** Stored eligibility override; `null` \u21D2 inherit the code-declared `type.channels`. */\n channels: string[] | null\n /** Stored `nonOptOut` override; `null` \u21D2 inherit the code-declared flag. */\n nonOptOut: boolean | null\n}\n\nexport async function getNotificationTypeOverrides(\n em: EntityManager,\n tenantId: string,\n typeIds: string[],\n): Promise<Map<string, NotificationTypeOverrides>> {\n const result = new Map<string, NotificationTypeOverrides>()\n const uniqueIds = Array.from(new Set(typeIds)).filter((id) => id.length > 0)\n if (!uniqueIds.length || !tenantId) return result\n const db = em.getKysely<any>() as Kysely<any>\n const rows = (await db\n .selectFrom('notification_type_overrides')\n .select(['notification_type_id', 'channels', 'non_opt_out'])\n .where('tenant_id', '=', tenantId)\n .where('notification_type_id', 'in', uniqueIds)\n .execute()) as Array<{\n notification_type_id: string\n channels: string[] | null\n non_opt_out: boolean | null\n }>\n for (const row of rows) {\n const channels = Array.isArray(row.channels) ? row.channels : null\n const nonOptOut = typeof row.non_opt_out === 'boolean' ? row.non_opt_out : null\n if (channels !== null || nonOptOut !== null) {\n result.set(row.notification_type_id, { channels, nonOptOut })\n }\n }\n return result\n}\n"],
|
|
5
|
+
"mappings": "AAkBA,eAAsB,6BACpB,IACA,UACA,SACiD;AACjD,QAAM,SAAS,oBAAI,IAAuC;AAC1D,QAAM,YAAY,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;AAC3E,MAAI,CAAC,UAAU,UAAU,CAAC,SAAU,QAAO;AAC3C,QAAM,KAAK,GAAG,UAAe;AAC7B,QAAM,OAAQ,MAAM,GACjB,WAAW,6BAA6B,EACxC,OAAO,CAAC,wBAAwB,YAAY,aAAa,CAAC,EAC1D,MAAM,aAAa,KAAK,QAAQ,EAChC,MAAM,wBAAwB,MAAM,SAAS,EAC7C,QAAQ;AAKX,aAAW,OAAO,MAAM;AACtB,UAAM,WAAW,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW;AAC9D,UAAM,YAAY,OAAO,IAAI,gBAAgB,YAAY,IAAI,cAAc;AAC3E,QAAI,aAAa,QAAQ,cAAc,MAAM;AAC3C,aAAO,IAAI,IAAI,sBAAsB,EAAE,UAAU,UAAU,CAAC;AAAA,IAC9D;AAAA,EACF;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260625122947_notifications extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`create table "notification_preferences" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "user_id" uuid not null, "notification_type_id" text not null, "channel" text not null, "enabled" boolean not null default true, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
|
|
5
|
+
this.addSql(`create unique index "notification_preferences_unique" on "notification_preferences" ("tenant_id", "user_id", "notification_type_id", "channel");`);
|
|
6
|
+
this.addSql(`create index "notification_preferences_tenant_user_idx" on "notification_preferences" ("tenant_id", "user_id");`);
|
|
7
|
+
this.addSql(`create table "notification_types" ("id" text not null, "tenant_id" uuid null, "label_key" text not null, "description_key" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
|
|
8
|
+
this.addSql(`create index "notification_types_tenant_idx" on "notification_types" ("tenant_id");`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
Migration20260625122947_notifications
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=Migration20260625122947_notifications.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260625122947_notifications.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260625122947_notifications extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"notification_preferences\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"user_id\" uuid not null, \"notification_type_id\" text not null, \"channel\" text not null, \"enabled\" boolean not null default true, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create unique index \"notification_preferences_unique\" on \"notification_preferences\" (\"tenant_id\", \"user_id\", \"notification_type_id\", \"channel\");`);\n this.addSql(`create index \"notification_preferences_tenant_user_idx\" on \"notification_preferences\" (\"tenant_id\", \"user_id\");`);\n\n this.addSql(`create table \"notification_types\" (\"id\" text not null, \"tenant_id\" uuid null, \"label_key\" text not null, \"description_key\" text null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"notification_types_tenant_idx\" on \"notification_types\" (\"tenant_id\");`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,8CAA8C,UAAU;AAAA,EAE1D,KAA2B;AAClC,SAAK,OAAO,+UAA+U;AAC3V,SAAK,OAAO,kJAAkJ;AAC9J,SAAK,OAAO,iHAAiH;AAE7H,SAAK,OAAO,kOAAkO;AAC9O,SAAK,OAAO,qFAAqF;AAAA,EACnG;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260626120500_notifications_push_payload extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "notifications" add column "data" jsonb null;`);
|
|
5
|
+
this.addSql(`alter table "notifications" add column "push_options" jsonb null;`);
|
|
6
|
+
}
|
|
7
|
+
down() {
|
|
8
|
+
this.addSql(`alter table "notifications" drop column "push_options";`);
|
|
9
|
+
this.addSql(`alter table "notifications" drop column "data";`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
Migration20260626120500_notifications_push_payload
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=Migration20260626120500_notifications_push_payload.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260626120500_notifications_push_payload extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"notifications\" add column \"data\" jsonb null;`);\n this.addSql(`alter table \"notifications\" add column \"push_options\" jsonb null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"notifications\" drop column \"push_options\";`);\n this.addSql(`alter table \"notifications\" drop column \"data\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,2DAA2D,UAAU;AAAA,EAEvE,KAA2B;AAClC,SAAK,OAAO,2DAA2D;AACvE,SAAK,OAAO,mEAAmE;AAAA,EACjF;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,yDAAyD;AACrE,SAAK,OAAO,iDAAiD;AAAA,EAC/D;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260626130000_notifications_non_opt_out extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "notification_types" add column "non_opt_out" boolean not null default false;`);
|
|
5
|
+
}
|
|
6
|
+
down() {
|
|
7
|
+
this.addSql(`alter table "notification_types" drop column "non_opt_out";`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
Migration20260626130000_notifications_non_opt_out
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=Migration20260626130000_notifications_non_opt_out.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260626130000_notifications_non_opt_out extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"notification_types\" add column \"non_opt_out\" boolean not null default false;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"notification_types\" drop column \"non_opt_out\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,0DAA0D,UAAU;AAAA,EAEtE,KAA2B;AAClC,SAAK,OAAO,2FAA2F;AAAA,EACzG;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,6DAA6D;AAAA,EAC3E;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260626140000_notifications_type_category_silent extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "notification_types" add column "category" text null;`);
|
|
5
|
+
this.addSql(`alter table "notification_types" add column "silent" boolean not null default false;`);
|
|
6
|
+
}
|
|
7
|
+
down() {
|
|
8
|
+
this.addSql(`alter table "notification_types" drop column "silent";`);
|
|
9
|
+
this.addSql(`alter table "notification_types" drop column "category";`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
Migration20260626140000_notifications_type_category_silent
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=Migration20260626140000_notifications_type_category_silent.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260626140000_notifications_type_category_silent.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260626140000_notifications_type_category_silent extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"notification_types\" add column \"category\" text null;`);\n this.addSql(`alter table \"notification_types\" add column \"silent\" boolean not null default false;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"notification_types\" drop column \"silent\";`);\n this.addSql(`alter table \"notification_types\" drop column \"category\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,mEAAmE,UAAU;AAAA,EAE/E,KAA2B;AAClC,SAAK,OAAO,mEAAmE;AAC/E,SAAK,OAAO,sFAAsF;AAAA,EACpG;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,wDAAwD;AACpE,SAAK,OAAO,0DAA0D;AAAA,EACxE;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/modules/notifications/migrations/Migration20260706120000_notifications_channels.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260706120000_notifications_channels extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "notifications" add column "channels" jsonb null;`);
|
|
5
|
+
}
|
|
6
|
+
down() {
|
|
7
|
+
this.addSql(`alter table "notifications" drop column "channels";`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
Migration20260706120000_notifications_channels
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=Migration20260706120000_notifications_channels.js.map
|
package/dist/modules/notifications/migrations/Migration20260706120000_notifications_channels.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260706120000_notifications_channels.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260706120000_notifications_channels extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"notifications\" add column \"channels\" jsonb null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"notifications\" drop column \"channels\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,uDAAuD,UAAU;AAAA,EAEnE,KAA2B;AAClC,SAAK,OAAO,+DAA+D;AAAA,EAC7E;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,qDAAqD;AAAA,EACnE;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260716123121_notifications extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`create table "notification_type_overrides" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "notification_type_id" text not null, "channels" jsonb null, "non_opt_out" boolean null, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
|
|
5
|
+
this.addSql(`create unique index "notification_type_overrides_unique" on "notification_type_overrides" ("tenant_id", "notification_type_id");`);
|
|
6
|
+
}
|
|
7
|
+
down() {
|
|
8
|
+
this.addSql(`drop table if exists "notification_type_overrides" cascade;`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
Migration20260716123121_notifications
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=Migration20260716123121_notifications.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260716123121_notifications.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260716123121_notifications extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"notification_type_overrides\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"notification_type_id\" text not null, \"channels\" jsonb null, \"non_opt_out\" boolean null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create unique index \"notification_type_overrides_unique\" on \"notification_type_overrides\" (\"tenant_id\", \"notification_type_id\");`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"notification_type_overrides\" cascade;`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,8CAA8C,UAAU;AAAA,EAE1D,KAA2B;AAClC,SAAK,OAAO,0SAA0S;AACtT,SAAK,OAAO,kIAAkI;AAAA,EAChJ;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,6DAA6D;AAAA,EAC3E;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const notificationChannels = [
|
|
2
|
+
{
|
|
3
|
+
id: "in_app",
|
|
4
|
+
labelKey: "notifications.preferences.channels.inApp",
|
|
5
|
+
descriptionKey: "notifications.preferences.channels.inAppHint",
|
|
6
|
+
order: 10
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
id: "email",
|
|
10
|
+
labelKey: "notifications.preferences.channels.email",
|
|
11
|
+
descriptionKey: "notifications.preferences.channels.emailHint",
|
|
12
|
+
order: 20
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "push",
|
|
16
|
+
labelKey: "notifications.preferences.channels.push",
|
|
17
|
+
descriptionKey: "notifications.preferences.channels.pushHint",
|
|
18
|
+
order: 30
|
|
19
|
+
}
|
|
20
|
+
];
|
|
21
|
+
var notification_channels_default = notificationChannels;
|
|
22
|
+
export {
|
|
23
|
+
notification_channels_default as default,
|
|
24
|
+
notificationChannels
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=notification-channels.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/notifications/notification-channels.ts"],
|
|
4
|
+
"sourcesContent": ["import type { NotificationChannelDefinition } from '@open-mercato/shared/modules/notifications/types'\n\n/**\n * Core-owned delivery channels. `notifications` is the channel-metadata authority (labels shown in the\n * preferences UI + the `/api/notifications/channels` catalogue); the delivery *behavior* for each lives\n * in its own strategy (`in_app`/`email` here, `push` in `push_notifications`). Third-party modules add\n * further channels by shipping their own generator-discovered `notification-channels.ts`.\n */\nexport const notificationChannels: NotificationChannelDefinition[] = [\n {\n id: 'in_app',\n labelKey: 'notifications.preferences.channels.inApp',\n descriptionKey: 'notifications.preferences.channels.inAppHint',\n order: 10,\n },\n {\n id: 'email',\n labelKey: 'notifications.preferences.channels.email',\n descriptionKey: 'notifications.preferences.channels.emailHint',\n order: 20,\n },\n {\n id: 'push',\n labelKey: 'notifications.preferences.channels.push',\n descriptionKey: 'notifications.preferences.channels.pushHint',\n order: 30,\n },\n]\n\nexport default notificationChannels\n"],
|
|
5
|
+
"mappings": "AAQO,MAAM,uBAAwD;AAAA,EACnE;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AACF;AAEA,IAAO,gCAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { inAppDeliveryStrategy } from "./lib/strategies/in-app-delivery-strategy.js";
|
|
2
|
+
import { emailDeliveryStrategy } from "./lib/strategies/email-delivery-strategy.js";
|
|
3
|
+
const deliveryStrategies = [
|
|
4
|
+
inAppDeliveryStrategy,
|
|
5
|
+
emailDeliveryStrategy
|
|
6
|
+
];
|
|
7
|
+
var notifications_delivery_strategies_default = deliveryStrategies;
|
|
8
|
+
export {
|
|
9
|
+
notifications_delivery_strategies_default as default,
|
|
10
|
+
deliveryStrategies
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=notifications.delivery-strategies.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/notifications/notifications.delivery-strategies.ts"],
|
|
4
|
+
"sourcesContent": ["import type { NotificationDeliveryStrategy } from './lib/deliveryStrategies'\nimport { inAppDeliveryStrategy } from './lib/strategies/in-app-delivery-strategy'\nimport { emailDeliveryStrategy } from './lib/strategies/email-delivery-strategy'\n\n/**\n * Core-owned delivery strategies, discovered by the notifications `delivery-strategies` generator\n * plugin (see `generators.ts`) and registered at bootstrap. `push` is contributed separately by the\n * `push_notifications` module through its own `notifications.delivery-strategies.ts`.\n */\nexport const deliveryStrategies: NotificationDeliveryStrategy[] = [\n inAppDeliveryStrategy,\n emailDeliveryStrategy,\n]\n\nexport default deliveryStrategies\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,6BAA6B;AACtC,SAAS,6BAA6B;AAO/B,MAAM,qBAAqD;AAAA,EAChE;AAAA,EACA;AACF;AAEA,IAAO,4CAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
2
|
+
import { TYPE_REGISTRY_SYNC_EVENT } from "./events.js";
|
|
3
|
+
const logger = createLogger("notifications");
|
|
1
4
|
const setup = {
|
|
2
5
|
defaultRoleFeatures: {
|
|
3
6
|
superadmin: ["notifications.*"],
|
|
4
7
|
admin: ["notifications.*"],
|
|
5
|
-
employee: ["notifications.view"]
|
|
8
|
+
employee: ["notifications.view", "notifications.manage_preferences"]
|
|
9
|
+
},
|
|
10
|
+
async seedDefaults({ container, tenantId, organizationId }) {
|
|
11
|
+
try {
|
|
12
|
+
const eventBus = container.resolve("eventBus");
|
|
13
|
+
await eventBus.emit(
|
|
14
|
+
TYPE_REGISTRY_SYNC_EVENT,
|
|
15
|
+
{ tenantId, organizationId },
|
|
16
|
+
{ tenantId, organizationId, persistent: true }
|
|
17
|
+
);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
logger.warn("type_registry.sync emit skipped during seedDefaults", { err });
|
|
20
|
+
}
|
|
6
21
|
}
|
|
7
22
|
};
|
|
8
23
|
var setup_default = setup;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/notifications/setup.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n superadmin: ['notifications.*'],\n admin: ['notifications.*'],\n employee: ['notifications.view'],\n },\n}\n\nexport default setup\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { TYPE_REGISTRY_SYNC_EVENT } from './events'\n\nconst logger = createLogger('notifications')\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n superadmin: ['notifications.*'],\n admin: ['notifications.*'],\n employee: ['notifications.view', 'notifications.manage_preferences'],\n },\n\n async seedDefaults({ container, tenantId, organizationId }) {\n // Best-effort: nudge the type catalogue into the DB at init time. The\n // `GET /api/notifications/types` lazy reconcile is the reliable fallback, so\n // a failure here must never break tenant initialization.\n try {\n const eventBus = container.resolve('eventBus') as {\n emit: (event: string, payload: unknown, options?: unknown) => Promise<void>\n }\n await eventBus.emit(\n TYPE_REGISTRY_SYNC_EVENT,\n { tenantId, organizationId },\n { tenantId, organizationId, persistent: true },\n )\n } catch (err) {\n logger.warn('type_registry.sync emit skipped during seedDefaults', { err })\n }\n },\n}\n\nexport default setup\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAAS,gCAAgC;AAEzC,MAAM,SAAS,aAAa,eAAe;AAEpC,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,YAAY,CAAC,iBAAiB;AAAA,IAC9B,OAAO,CAAC,iBAAiB;AAAA,IACzB,UAAU,CAAC,sBAAsB,kCAAkC;AAAA,EACrE;AAAA,EAEA,MAAM,aAAa,EAAE,WAAW,UAAU,eAAe,GAAG;AAI1D,QAAI;AACF,YAAM,WAAW,UAAU,QAAQ,UAAU;AAG7C,YAAM,SAAS;AAAA,QACb;AAAA,QACA,EAAE,UAAU,eAAe;AAAA,QAC3B,EAAE,UAAU,gBAAgB,YAAY,KAAK;AAAA,MAC/C;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,KAAK,uDAAuD,EAAE,IAAI,CAAC;AAAA,IAC5E;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,11 +2,11 @@ import { Notification } from "../data/entities.js";
|
|
|
2
2
|
import { NOTIFICATION_EVENTS } from "../lib/events.js";
|
|
3
3
|
import { DEFAULT_NOTIFICATION_DELIVERY_CONFIG, resolveNotificationDeliveryConfig, resolveNotificationPanelUrl } from "../lib/deliveryConfig.js";
|
|
4
4
|
import { getNotificationDeliveryStrategies } from "../lib/deliveryStrategies.js";
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import { resolveEffectiveChannels } from "../lib/shouldDeliver.js";
|
|
6
|
+
import { getNotificationType } from "../lib/notification-type-registry.js";
|
|
7
|
+
import { getNotificationTypeOverrides } from "../lib/typeOverrides.js";
|
|
8
|
+
import { resolveNotificationPreferenceService } from "../lib/notificationPreferenceService.js";
|
|
9
|
+
import { resolveNotificationCopy } from "../lib/notificationCopy.js";
|
|
10
10
|
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
11
11
|
import { User } from "../../auth/data/entities.js";
|
|
12
12
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
@@ -28,13 +28,6 @@ const buildPanelLink = (panelUrl, notificationId) => {
|
|
|
28
28
|
const separator = panelUrl.includes("?") ? "&" : "?";
|
|
29
29
|
return `${panelUrl}${separator}notificationId=${encodeURIComponent(notificationId)}`;
|
|
30
30
|
};
|
|
31
|
-
const resolveNotificationCopy = async (notification) => {
|
|
32
|
-
const dict = await loadDictionary(defaultLocale);
|
|
33
|
-
const t = createFallbackTranslator(dict);
|
|
34
|
-
const title = notification.titleKey ? t(notification.titleKey, notification.title ?? notification.titleKey, notification.titleVariables ?? void 0) : notification.title;
|
|
35
|
-
const body = notification.bodyKey ? t(notification.bodyKey, notification.body ?? notification.bodyKey ?? "", notification.bodyVariables ?? void 0) : notification.body ?? null;
|
|
36
|
-
return { title, body, t };
|
|
37
|
-
};
|
|
38
31
|
const resolveRecipient = async (em, notification, encryptionService) => {
|
|
39
32
|
const where = {
|
|
40
33
|
id: notification.recipientUserId,
|
|
@@ -64,9 +57,6 @@ const resolveRecipient = async (em, notification, encryptionService) => {
|
|
|
64
57
|
async function handle(payload, ctx) {
|
|
65
58
|
debug("deliver notification event", payload);
|
|
66
59
|
const deliveryConfig = await resolveNotificationDeliveryConfig(ctx, { defaultValue: DEFAULT_NOTIFICATION_DELIVERY_CONFIG });
|
|
67
|
-
if (!deliveryConfig.strategies.email.enabled) {
|
|
68
|
-
debug("email delivery disabled");
|
|
69
|
-
}
|
|
70
60
|
const em = ctx.resolve("em");
|
|
71
61
|
const notification = await findOneWithDecryption(
|
|
72
62
|
em,
|
|
@@ -118,59 +108,78 @@ async function handle(payload, ctx) {
|
|
|
118
108
|
href: fullHref
|
|
119
109
|
};
|
|
120
110
|
}).filter((action) => action !== null);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
bodyIntro: t("notifications.delivery.email.bodyIntro", "Review the notification details and take any required actions."),
|
|
128
|
-
actionNotice: t("notifications.delivery.email.actionNotice", "Actions are available in Open Mercato and are read-only in this email."),
|
|
129
|
-
openCta: t("notifications.delivery.email.openCta", "Open notification center"),
|
|
130
|
-
footer: t("notifications.delivery.email.footer", "Open Mercato notifications")
|
|
131
|
-
};
|
|
111
|
+
const strategyConfigs = deliveryConfig.strategies.custom ?? {};
|
|
112
|
+
const strategies = getNotificationDeliveryStrategies();
|
|
113
|
+
const persistedChannels = notification.channels;
|
|
114
|
+
const registeredStrategyIds = strategies.map((strategy) => strategy.id);
|
|
115
|
+
let targetChannels = persistedChannels ?? null;
|
|
116
|
+
if (persistedChannels == null && registeredStrategyIds.length > 0) {
|
|
132
117
|
try {
|
|
133
|
-
|
|
134
|
-
await
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
panelUrl: panelLink,
|
|
144
|
-
copy
|
|
145
|
-
})
|
|
118
|
+
const typeOverrides = (await getNotificationTypeOverrides(em, notification.tenantId, [notification.type])).get(notification.type);
|
|
119
|
+
targetChannels = await resolveEffectiveChannels({
|
|
120
|
+
typeId: notification.type,
|
|
121
|
+
type: getNotificationType(notification.type),
|
|
122
|
+
scope: { tenantId: notification.tenantId, userId: notification.recipientUserId },
|
|
123
|
+
targetChannels: null,
|
|
124
|
+
registeredChannels: registeredStrategyIds,
|
|
125
|
+
preferences: resolveNotificationPreferenceService({ resolve: ctx.resolve }),
|
|
126
|
+
channelsOverride: typeOverrides?.channels ?? null,
|
|
127
|
+
nonOptOutOverride: typeOverrides?.nonOptOut ?? null
|
|
146
128
|
});
|
|
147
|
-
} catch (
|
|
148
|
-
logger.error("
|
|
129
|
+
} catch (err) {
|
|
130
|
+
logger.error("failed to recompute delivery channels; retrying via persistent subscriber", {
|
|
131
|
+
notificationId: notification.id,
|
|
132
|
+
type: notification.type,
|
|
133
|
+
err
|
|
134
|
+
});
|
|
135
|
+
throw err;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (persistedChannels == null && targetChannels != null) {
|
|
139
|
+
try {
|
|
140
|
+
await em.fork().nativeUpdate(
|
|
141
|
+
Notification,
|
|
142
|
+
{ id: notification.id, tenantId: notification.tenantId },
|
|
143
|
+
{ channels: targetChannels }
|
|
144
|
+
);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
debug("failed to persist recomputed channels", err);
|
|
149
147
|
}
|
|
150
148
|
}
|
|
151
|
-
const strategyConfigs = deliveryConfig.strategies.custom ?? {};
|
|
152
|
-
const strategies = getNotificationDeliveryStrategies();
|
|
153
149
|
for (const strategy of strategies) {
|
|
150
|
+
if (targetChannels && !targetChannels.includes(strategy.id)) {
|
|
151
|
+
debug("channel not targeted", strategy.id);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
154
|
const strategyConfig = strategyConfigs[strategy.id];
|
|
155
155
|
const enabled = strategyConfig?.enabled ?? strategy.defaultEnabled ?? false;
|
|
156
156
|
if (!enabled) {
|
|
157
|
-
debug("
|
|
157
|
+
debug("delivery disabled", strategy.id);
|
|
158
158
|
continue;
|
|
159
159
|
}
|
|
160
|
+
if (strategy.supports && !strategy.supports(notification)) {
|
|
161
|
+
debug("strategy does not support notification", strategy.id);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const context = {
|
|
165
|
+
notification,
|
|
166
|
+
recipient,
|
|
167
|
+
title,
|
|
168
|
+
body,
|
|
169
|
+
panelUrl,
|
|
170
|
+
panelLink,
|
|
171
|
+
actionLinks,
|
|
172
|
+
deliveryConfig,
|
|
173
|
+
config: strategyConfig ?? {},
|
|
174
|
+
resolve: ctx.resolve,
|
|
175
|
+
t
|
|
176
|
+
};
|
|
160
177
|
try {
|
|
161
|
-
await strategy.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
panelUrl,
|
|
167
|
-
panelLink,
|
|
168
|
-
actionLinks,
|
|
169
|
-
deliveryConfig,
|
|
170
|
-
config: strategyConfig ?? {},
|
|
171
|
-
resolve: ctx.resolve,
|
|
172
|
-
t
|
|
173
|
-
});
|
|
178
|
+
if (strategy.isConfigured && !await strategy.isConfigured(context)) {
|
|
179
|
+
debug("strategy not configured", strategy.id);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
await strategy.deliver(context);
|
|
174
183
|
} catch (error) {
|
|
175
184
|
logger.error("Delivery strategy failed", { strategyId: strategy.id, err: error });
|
|
176
185
|
}
|