@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/api/deviceOps.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport type { UserDevice } from '../data/entities'\nimport type {\n RegisterDeviceCommandInput,\n UpdateDeviceCommandInput,\n DeactivateDeviceCommandInput,\n} from '../data/validators'\nimport { attachOperationMetadataHeader } from '../lib/operationMetadata'\n\nconst RESOURCE_KIND = 'devices.user_device'\n\n// push_token is a secret. The mutation guard forwards mutationPayload into record-lock conflict\n// details that are returned to clients, so strip the token before it reaches the guard.\nexport function redactMutationPayload(\n payload: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!payload || !('pushToken' in payload)) return payload\n const { pushToken: _pushToken, ...rest } = payload\n return rest\n}\n\ntype RequestContainer = Awaited<ReturnType<typeof createRequestContainer>>\ntype OrganizationScope = Awaited<ReturnType<typeof resolveOrganizationScopeForRequest>>\n\n// Shared mutation context for device write ops. `actorUserId` is the authenticated caller (used for\n// the mutation guard / audit), independent of which user *owns* the device being mutated.\nexport type DeviceMutationContext = {\n container: RequestContainer\n auth: NonNullable<AuthContext>\n scope: OrganizationScope\n organizationId: string | null\n actorUserId: string\n request: Request\n}\n\nfunction commandCtx(mctx: DeviceMutationContext) {\n return {\n container: mctx.container,\n auth: mctx.auth,\n organizationScope: mctx.scope ?? null,\n selectedOrganizationId: mctx.organizationId,\n organizationIds: mctx.scope?.filterIds ?? (mctx.auth.orgId ? [mctx.auth.orgId] : null),\n request: mctx.request,\n }\n}\n\nasync function runGuards(\n mctx: DeviceMutationContext,\n operation: 'create' | 'update' | 'delete',\n resourceId: string,\n mutationPayload?: Record<string, unknown>,\n) {\n return validateCrudMutationGuard(mctx.container, {\n tenantId: mctx.auth.tenantId!,\n organizationId: mctx.organizationId,\n userId: mctx.actorUserId,\n resourceKind: RESOURCE_KIND,\n resourceId,\n operation,\n requestMethod: mctx.request.method,\n requestHeaders: mctx.request.headers,\n mutationPayload,\n })\n}\n\nasync function runAfter(\n mctx: DeviceMutationContext,\n guardResult: Awaited<ReturnType<typeof validateCrudMutationGuard>>,\n operation: 'create' | 'update' | 'delete',\n resourceId: string,\n) {\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(mctx.container, {\n tenantId: mctx.auth.tenantId!,\n organizationId: mctx.organizationId,\n userId: mctx.actorUserId,\n resourceKind: RESOURCE_KIND,\n resourceId,\n operation,\n requestMethod: mctx.request.method,\n requestHeaders: mctx.request.headers,\n metadata: (guardResult.metadata as Record<string, unknown> | null | undefined) ?? null,\n })\n }\n}\n\nexport async function executeRegister(\n mctx: DeviceMutationContext,\n commandInput: RegisterDeviceCommandInput,\n): Promise<NextResponse> {\n // Register is an upsert, so the device row id isn't known until execution. Key the mutation guard\n // by the stable, tenant-unique upsert tuple so validate and after-success agree (record locks are\n // keyed by resourceId); deviceId alone is not unique across users.\n const guardResourceId = `${commandInput.userId}:${commandInput.deviceId}`\n const guardResult = await runGuards(mctx, 'create', guardResourceId, redactMutationPayload(commandInput))\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = mctx.container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<\n RegisterDeviceCommandInput,\n { id: string; deviceId: string; revived: boolean }\n >('devices.user_devices.register', { input: commandInput, ctx: commandCtx(mctx) })\n\n await runAfter(mctx, guardResult, 'create', guardResourceId)\n\n const response = NextResponse.json(\n { id: result.id, deviceId: result.deviceId, revived: result.revived },\n { status: 201 },\n )\n attachOperationMetadataHeader(response, logEntry, { resourceKind: RESOURCE_KIND, resourceId: result.id })\n return response\n}\n\nexport async function executeUpdate(\n mctx: DeviceMutationContext,\n device: UserDevice,\n body: Omit<UpdateDeviceCommandInput, 'id' | 'tenantId' | 'userId' | 'organizationId'>,\n): Promise<NextResponse> {\n // Device metadata edits carry lost-update risk (unlike the idempotent soft-delete deactivate), so\n // enforce OSS optimistic locking when the caller sends the expected-version header. No-ops when the\n // header is absent (e.g. mobile self-update clients), keeping the contract backward-compatible.\n enforceCommandOptimisticLock({\n resourceKind: RESOURCE_KIND,\n resourceId: device.id,\n current: device.updatedAt,\n request: mctx.request,\n })\n\n const guardResult = await runGuards(mctx, 'update', device.id, redactMutationPayload(body))\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = mctx.container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<UpdateDeviceCommandInput, { id: string }>('devices.user_devices.update', {\n input: {\n ...body,\n id: device.id,\n tenantId: device.tenantId,\n userId: device.userId,\n organizationId: device.organizationId ?? null,\n } satisfies UpdateDeviceCommandInput,\n ctx: commandCtx(mctx),\n })\n\n await runAfter(mctx, guardResult, 'update', device.id)\n\n const response = NextResponse.json({ ok: true, id: device.id })\n attachOperationMetadataHeader(response, logEntry, { resourceKind: RESOURCE_KIND, resourceId: device.id })\n return response\n}\n\nexport async function executeDeactivate(\n mctx: DeviceMutationContext,\n device: UserDevice,\n): Promise<NextResponse> {\n const guardResult = await runGuards(mctx, 'delete', device.id)\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = mctx.container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<DeactivateDeviceCommandInput, { id: string }>(\n 'devices.user_devices.deactivate',\n {\n input: {\n id: device.id,\n tenantId: device.tenantId,\n userId: device.userId,\n organizationId: device.organizationId ?? null,\n } satisfies DeactivateDeviceCommandInput,\n ctx: commandCtx(mctx),\n },\n )\n\n await runAfter(mctx, guardResult, 'delete', device.id)\n\n const response = NextResponse.json({ ok: true })\n attachOperationMetadataHeader(response, logEntry, { resourceKind: RESOURCE_KIND, resourceId: device.id })\n return response\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCrudOpenApiFactory,
|
|
3
|
+
createPagedListResponseSchema as createSharedPagedListResponseSchema
|
|
4
|
+
} from "@open-mercato/shared/lib/openapi/crud";
|
|
5
|
+
function createPagedListResponseSchema(itemSchema) {
|
|
6
|
+
return createSharedPagedListResponseSchema(itemSchema, { paginationMetaOptional: true });
|
|
7
|
+
}
|
|
8
|
+
const buildDevicesCrudOpenApi = createCrudOpenApiFactory({
|
|
9
|
+
defaultTag: "Devices",
|
|
10
|
+
makeListDescription: ({ pluralLower }) => `Returns the authenticated user's registered ${pluralLower} (admins may list across users).`
|
|
11
|
+
});
|
|
12
|
+
function createDevicesCrudOpenApi(options) {
|
|
13
|
+
return buildDevicesCrudOpenApi(options);
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
createDevicesCrudOpenApi,
|
|
17
|
+
createPagedListResponseSchema
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/api/openapi.ts"],
|
|
4
|
+
"sourcesContent": ["import { type ZodTypeAny } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n createCrudOpenApiFactory,\n createPagedListResponseSchema as createSharedPagedListResponseSchema,\n type CrudOpenApiOptions,\n} from '@open-mercato/shared/lib/openapi/crud'\n\nexport function createPagedListResponseSchema(itemSchema: ZodTypeAny) {\n return createSharedPagedListResponseSchema(itemSchema, { paginationMetaOptional: true })\n}\n\n// createCrudOpenApiFactory already falls back to the shared default create/ok response schemas\n// when omitted, so there is nothing module-specific to re-pass or re-export here.\nconst buildDevicesCrudOpenApi = createCrudOpenApiFactory({\n defaultTag: 'Devices',\n makeListDescription: ({ pluralLower }) =>\n `Returns the authenticated user's registered ${pluralLower} (admins may list across users).`,\n})\n\nexport function createDevicesCrudOpenApi(options: CrudOpenApiOptions): OpenApiRouteDoc {\n return buildDevicesCrudOpenApi(options)\n}\n"],
|
|
5
|
+
"mappings": "AAEA;AAAA,EACE;AAAA,EACA,iCAAiC;AAAA,OAE5B;AAEA,SAAS,8BAA8B,YAAwB;AACpE,SAAO,oCAAoC,YAAY,EAAE,wBAAwB,KAAK,CAAC;AACzF;AAIA,MAAM,0BAA0B,yBAAyB;AAAA,EACvD,YAAY;AAAA,EACZ,qBAAqB,CAAC,EAAE,YAAY,MAClC,+CAA+C,WAAW;AAC9D,CAAC;AAEM,SAAS,yBAAyB,SAA8C;AACrF,SAAO,wBAAwB,OAAO;AACxC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
|
|
4
|
+
import { consumeAdvancedFilterState, mergeAdvancedFilterTree } from "@open-mercato/shared/lib/crud/advanced-filter-integration";
|
|
5
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
6
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
7
|
+
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
8
|
+
import { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
9
|
+
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
10
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
11
|
+
import { resolveLocaleFromAcceptLanguage } from "@open-mercato/shared/lib/i18n/locale";
|
|
12
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
13
|
+
import { E } from "../../../generated/entities.ids.generated.js";
|
|
14
|
+
import { UserDevice } from "../data/entities.js";
|
|
15
|
+
import {
|
|
16
|
+
registerDeviceSchema,
|
|
17
|
+
registerDeviceCommandSchema
|
|
18
|
+
} from "../data/validators.js";
|
|
19
|
+
import { resolveDeviceActorUserId } from "./auth.js";
|
|
20
|
+
import { createDevicesCrudOpenApi, createPagedListResponseSchema } from "./openapi.js";
|
|
21
|
+
import { deviceListSchema, deviceListFields, deviceListSortFieldMap, deviceListItemSchema } from "./deviceList.js";
|
|
22
|
+
import { executeRegister } from "./deviceOps.js";
|
|
23
|
+
const logger = createLogger("devices");
|
|
24
|
+
const routeMetadata = {
|
|
25
|
+
GET: { requireAuth: true, requireFeatures: ["devices.view"] },
|
|
26
|
+
POST: { requireAuth: true, requireFeatures: ["devices.manage"] }
|
|
27
|
+
};
|
|
28
|
+
const metadata = routeMetadata;
|
|
29
|
+
const NO_MATCH_USER_ID = "00000000-0000-0000-0000-000000000000";
|
|
30
|
+
const crud = makeCrudRoute({
|
|
31
|
+
metadata: routeMetadata,
|
|
32
|
+
orm: {
|
|
33
|
+
entity: UserDevice,
|
|
34
|
+
idField: "id",
|
|
35
|
+
// organization_id stays nullable, but scoping follows the standard org-scoped pattern (like every
|
|
36
|
+
// other module): the factory auto-filters by the caller's organization scope. The query engine's
|
|
37
|
+
// org scope is null-aware — callers whose scope includes null (or who have no org restriction) also
|
|
38
|
+
// see null-org rows; a caller pinned to a specific org does not.
|
|
39
|
+
orgField: "organizationId",
|
|
40
|
+
tenantField: "tenantId",
|
|
41
|
+
softDeleteField: "deletedAt"
|
|
42
|
+
},
|
|
43
|
+
indexer: { entityType: E.devices.user_device },
|
|
44
|
+
// Align the CRUD cache resource tag with the command's resourceKind ('devices.user_device') so
|
|
45
|
+
// writes through the device commands invalidate this list cache. Without this, the factory falls
|
|
46
|
+
// back to the ORM entity name and the cache is never busted (stale list under ENABLE_CRUD_API_CACHE).
|
|
47
|
+
// The factory does not own the write methods here (custom POST + command bus), so no events are emitted.
|
|
48
|
+
events: { module: "devices", entity: "user_device" },
|
|
49
|
+
list: {
|
|
50
|
+
schema: deviceListSchema,
|
|
51
|
+
entityId: E.devices.user_device,
|
|
52
|
+
// push_token is a secret and is never exposed via the list API.
|
|
53
|
+
fields: deviceListFields,
|
|
54
|
+
sortFieldMap: deviceListSortFieldMap,
|
|
55
|
+
// Exports are off for the self-serve list. The factory enables them for every list that does not
|
|
56
|
+
// declare `export` (resolveAvailableExportFormats falls back to csv/json/xml/markdown), and its
|
|
57
|
+
// full-export branch replaces the filters with `{}` instead of calling `buildFilters`
|
|
58
|
+
// (`baseFilters = exportFullRequested ? {} : buildFilters(...)`). On this route `buildFilters` is
|
|
59
|
+
// the only user-level boundary — automatic scoping covers tenant and organization, not the acting
|
|
60
|
+
// user — so `?format=json&exportScope=full` would return every device in the caller's org scope.
|
|
61
|
+
// With no available formats, `exportRequested` is never true and that branch is unreachable. Bulk
|
|
62
|
+
// device data belongs to the admin tree (api/admin/devices), which gates cross-user listing.
|
|
63
|
+
export: { enabled: false },
|
|
64
|
+
// Self-serve: always scoped to the acting user. Cross-user listing lives in api/admin/devices.
|
|
65
|
+
buildFilters: async (query, ctx) => {
|
|
66
|
+
const advancedFilterTree = consumeAdvancedFilterState(query);
|
|
67
|
+
const filters = {};
|
|
68
|
+
const actorUserId = resolveDeviceActorUserId(ctx.auth);
|
|
69
|
+
filters.user_id = { $eq: actorUserId ?? NO_MATCH_USER_ID };
|
|
70
|
+
if (query.platform) filters.platform = { $eq: query.platform };
|
|
71
|
+
return mergeAdvancedFilterTree(filters, advancedFilterTree);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
const GET = crud.GET;
|
|
76
|
+
async function POST(req) {
|
|
77
|
+
const { translate } = await resolveTranslations();
|
|
78
|
+
try {
|
|
79
|
+
const container = await createRequestContainer();
|
|
80
|
+
const auth = await getAuthFromRequest(req);
|
|
81
|
+
const actorUserId = resolveDeviceActorUserId(auth);
|
|
82
|
+
if (!auth || !auth.tenantId || !actorUserId) {
|
|
83
|
+
return NextResponse.json({ error: translate("devices.errors.unauthorized", "Unauthorized") }, { status: 401 });
|
|
84
|
+
}
|
|
85
|
+
const body = registerDeviceSchema.parse(await readJsonSafe(req, {}));
|
|
86
|
+
const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
|
|
87
|
+
const organizationId = scope?.selectedId ?? auth.orgId ?? null;
|
|
88
|
+
const headerLocale = resolveLocaleFromAcceptLanguage(req.headers.get("accept-language"));
|
|
89
|
+
const commandInput = registerDeviceCommandSchema.parse({
|
|
90
|
+
...body,
|
|
91
|
+
locale: body.locale ?? headerLocale ?? void 0,
|
|
92
|
+
tenantId: auth.tenantId,
|
|
93
|
+
organizationId,
|
|
94
|
+
userId: actorUserId
|
|
95
|
+
});
|
|
96
|
+
const mctx = { container, auth, scope, organizationId, actorUserId, request: req };
|
|
97
|
+
return await executeRegister(mctx, commandInput);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
if (err instanceof z.ZodError) {
|
|
100
|
+
return NextResponse.json(
|
|
101
|
+
{ error: translate("devices.errors.invalid_payload", "Invalid device payload"), details: err.flatten() },
|
|
102
|
+
{ status: 400 }
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (isCrudHttpError(err) && err.body?.code === "device_already_registered") {
|
|
106
|
+
return NextResponse.json(
|
|
107
|
+
{ error: translate("devices.errors.already_registered", "This device is already registered") },
|
|
108
|
+
{ status: 409 }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
if (isCrudHttpError(err)) {
|
|
112
|
+
return NextResponse.json(err.body, { status: err.status });
|
|
113
|
+
}
|
|
114
|
+
logger.error("devices.POST failed", { err });
|
|
115
|
+
return NextResponse.json(
|
|
116
|
+
{ error: translate("devices.errors.register_failed", "Failed to register device") },
|
|
117
|
+
{ status: 500 }
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const registerResponseSchema = z.object({
|
|
122
|
+
id: z.string().uuid(),
|
|
123
|
+
deviceId: z.string(),
|
|
124
|
+
revived: z.boolean()
|
|
125
|
+
});
|
|
126
|
+
const openApi = createDevicesCrudOpenApi({
|
|
127
|
+
resourceName: "Device",
|
|
128
|
+
pluralName: "Devices",
|
|
129
|
+
querySchema: deviceListSchema,
|
|
130
|
+
listResponseSchema: createPagedListResponseSchema(deviceListItemSchema),
|
|
131
|
+
create: {
|
|
132
|
+
schema: registerDeviceSchema,
|
|
133
|
+
responseSchema: registerResponseSchema,
|
|
134
|
+
description: "Registers (or idempotently upserts) the current user's device for the given deviceId. May include an initial push token."
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
export {
|
|
138
|
+
GET,
|
|
139
|
+
POST,
|
|
140
|
+
metadata,
|
|
141
|
+
openApi
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/devices/api/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveLocaleFromAcceptLanguage } from '@open-mercato/shared/lib/i18n/locale'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { E } from '#generated/entities.ids.generated'\nimport { UserDevice } from '../data/entities'\nimport {\n registerDeviceSchema,\n registerDeviceCommandSchema,\n type RegisterDeviceCommandInput,\n} from '../data/validators'\nimport { resolveDeviceActorUserId } from './auth'\nimport { createDevicesCrudOpenApi, createPagedListResponseSchema } from './openapi'\nimport { deviceListSchema, deviceListFields, deviceListSortFieldMap, deviceListItemSchema } from './deviceList'\nimport { executeRegister, type DeviceMutationContext } from './deviceOps'\n\nconst logger = createLogger('devices')\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['devices.view'] },\n POST: { requireAuth: true, requireFeatures: ['devices.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst NO_MATCH_USER_ID = '00000000-0000-0000-0000-000000000000'\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: UserDevice,\n idField: 'id',\n // organization_id stays nullable, but scoping follows the standard org-scoped pattern (like every\n // other module): the factory auto-filters by the caller's organization scope. The query engine's\n // org scope is null-aware \u2014 callers whose scope includes null (or who have no org restriction) also\n // see null-org rows; a caller pinned to a specific org does not.\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.devices.user_device },\n // Align the CRUD cache resource tag with the command's resourceKind ('devices.user_device') so\n // writes through the device commands invalidate this list cache. Without this, the factory falls\n // back to the ORM entity name and the cache is never busted (stale list under ENABLE_CRUD_API_CACHE).\n // The factory does not own the write methods here (custom POST + command bus), so no events are emitted.\n events: { module: 'devices', entity: 'user_device' },\n list: {\n schema: deviceListSchema,\n entityId: E.devices.user_device,\n // push_token is a secret and is never exposed via the list API.\n fields: deviceListFields,\n sortFieldMap: deviceListSortFieldMap,\n // Exports are off for the self-serve list. The factory enables them for every list that does not\n // declare `export` (resolveAvailableExportFormats falls back to csv/json/xml/markdown), and its\n // full-export branch replaces the filters with `{}` instead of calling `buildFilters`\n // (`baseFilters = exportFullRequested ? {} : buildFilters(...)`). On this route `buildFilters` is\n // the only user-level boundary \u2014 automatic scoping covers tenant and organization, not the acting\n // user \u2014 so `?format=json&exportScope=full` would return every device in the caller's org scope.\n // With no available formats, `exportRequested` is never true and that branch is unreachable. Bulk\n // device data belongs to the admin tree (api/admin/devices), which gates cross-user listing.\n export: { enabled: false },\n // Self-serve: always scoped to the acting user. Cross-user listing lives in api/admin/devices.\n buildFilters: async (query, ctx) => {\n // Consume the client-supplied advanced filter here (this deletes every `filter[...]` key from\n // `query`) so the CRUD factory's own merge step becomes a no-op. That step is\n // `{ ...existingFilters, ...advancedWhere }` (advanced-filter-integration.ts), and condition\n // field names are never validated \u2014 `filter[conditions][0][field]=user_id` or `=$and` would\n // otherwise overwrite whatever key this route uses for its scope and widen the listing to other\n // users. `mergeAdvancedFilterTree` instead AND-combines under `$and: [routeFilters, treeWhere]`,\n // where the scope sits in its own array element and no client key can reach it. Same pattern as\n // customers/people, companies and deals.\n const advancedFilterTree = consumeAdvancedFilterState(query)\n const filters: Record<string, unknown> = {}\n const actorUserId = resolveDeviceActorUserId(ctx.auth)\n // Self-serve visibility is strictly the acting user's own devices; cross-user listing lives in\n // api/admin/devices. Fail closed when there is no resolvable acting user (e.g. API keys).\n filters.user_id = { $eq: actorUserId ?? NO_MATCH_USER_ID }\n if (query.platform) filters.platform = { $eq: query.platform }\n return mergeAdvancedFilterTree(filters, advancedFilterTree)\n },\n },\n})\n\nexport const GET = crud.GET\n\nexport async function POST(req: Request) {\n const { translate } = await resolveTranslations()\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const actorUserId = resolveDeviceActorUserId(auth)\n if (!auth || !auth.tenantId || !actorUserId) {\n return NextResponse.json({ error: translate('devices.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n }\n\n const body = registerDeviceSchema.parse(await readJsonSafe(req, {}))\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n\n // When the app doesn't send an explicit per-device locale, fall back to the request's\n // Accept-Language (the mobile client calls this with its own headers). Only on self-register \u2014\n // PUT stays tri-state, and admin register uses the admin's browser headers, not the device's.\n const headerLocale = resolveLocaleFromAcceptLanguage(req.headers.get('accept-language'))\n\n const commandInput = registerDeviceCommandSchema.parse({\n ...body,\n locale: body.locale ?? headerLocale ?? undefined,\n tenantId: auth.tenantId,\n organizationId,\n userId: actorUserId,\n } satisfies RegisterDeviceCommandInput)\n\n const mctx: DeviceMutationContext = { container, auth, scope, organizationId, actorUserId, request: req }\n return await executeRegister(mctx, commandInput)\n } catch (err) {\n if (err instanceof z.ZodError) {\n return NextResponse.json(\n { error: translate('devices.errors.invalid_payload', 'Invalid device payload'), details: err.flatten() },\n { status: 400 },\n )\n }\n if (isCrudHttpError(err) && (err.body as { code?: string } | undefined)?.code === 'device_already_registered') {\n return NextResponse.json(\n { error: translate('devices.errors.already_registered', 'This device is already registered') },\n { status: 409 },\n )\n }\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n logger.error('devices.POST failed', { err })\n return NextResponse.json(\n { error: translate('devices.errors.register_failed', 'Failed to register device') },\n { status: 500 },\n )\n }\n}\n\nconst registerResponseSchema = z.object({\n id: z.string().uuid(),\n deviceId: z.string(),\n revived: z.boolean(),\n})\n\nexport const openApi: OpenApiRouteDoc = createDevicesCrudOpenApi({\n resourceName: 'Device',\n pluralName: 'Devices',\n querySchema: deviceListSchema,\n listResponseSchema: createPagedListResponseSchema(deviceListItemSchema),\n create: {\n schema: registerDeviceSchema,\n responseSchema: registerResponseSchema,\n description:\n 'Registers (or idempotently upserts) the current user\\'s device for the given deviceId. May include an initial push token.',\n },\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { useRouter } from "next/navigation";
|
|
6
|
+
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
7
|
+
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
|
|
8
|
+
import { updateCrud } from "@open-mercato/ui/backend/utils/crud";
|
|
9
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
10
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
11
|
+
import { LoadingMessage, ErrorMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
|
|
12
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
13
|
+
function DeviceAdminEditPage({ params }) {
|
|
14
|
+
const router = useRouter();
|
|
15
|
+
const t = useT();
|
|
16
|
+
const id = typeof params?.id === "string" ? params.id : "";
|
|
17
|
+
const [device, setDevice] = React.useState(null);
|
|
18
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
19
|
+
const [error, setError] = React.useState(null);
|
|
20
|
+
const [notFound, setNotFound] = React.useState(false);
|
|
21
|
+
const [userLabel, setUserLabel] = React.useState(null);
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
let cancelled = false;
|
|
24
|
+
async function load() {
|
|
25
|
+
setIsLoading(true);
|
|
26
|
+
setError(null);
|
|
27
|
+
setNotFound(false);
|
|
28
|
+
const call = await apiCall(
|
|
29
|
+
`/api/devices/admin/devices/${encodeURIComponent(id)}`,
|
|
30
|
+
void 0,
|
|
31
|
+
{ fallback: null }
|
|
32
|
+
);
|
|
33
|
+
if (cancelled) return;
|
|
34
|
+
if (call.ok && call.result?.item) {
|
|
35
|
+
setDevice(call.result.item);
|
|
36
|
+
} else if (call.status === 404 || call.ok && !call.result?.item) {
|
|
37
|
+
setNotFound(true);
|
|
38
|
+
} else {
|
|
39
|
+
setError(t("devices.form.error.loadFailed"));
|
|
40
|
+
}
|
|
41
|
+
setIsLoading(false);
|
|
42
|
+
}
|
|
43
|
+
if (id) load();
|
|
44
|
+
return () => {
|
|
45
|
+
cancelled = true;
|
|
46
|
+
};
|
|
47
|
+
}, [id, t]);
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
const userId = device?.user_id;
|
|
50
|
+
if (!userId) return;
|
|
51
|
+
let cancelled = false;
|
|
52
|
+
void (async () => {
|
|
53
|
+
const call = await apiCall(
|
|
54
|
+
`/api/auth/users?id=${encodeURIComponent(userId)}`,
|
|
55
|
+
{ headers: { "x-om-forbidden-redirect": "0" } },
|
|
56
|
+
{ fallback: null }
|
|
57
|
+
).catch(() => null);
|
|
58
|
+
if (cancelled || !call || !call.ok) return;
|
|
59
|
+
const found = call.result?.items?.find((u) => u.id === userId);
|
|
60
|
+
const label = found?.name?.trim() || found?.email?.trim() || null;
|
|
61
|
+
if (label) setUserLabel(label);
|
|
62
|
+
})();
|
|
63
|
+
return () => {
|
|
64
|
+
cancelled = true;
|
|
65
|
+
};
|
|
66
|
+
}, [device?.user_id]);
|
|
67
|
+
const fields = React.useMemo(() => [
|
|
68
|
+
{ id: "clientAppVersion", label: t("devices.form.appVersion"), type: "text" },
|
|
69
|
+
{ id: "osVersion", label: t("devices.form.osVersion"), type: "text" },
|
|
70
|
+
{ id: "pushProvider", label: t("devices.form.pushProvider"), type: "text" }
|
|
71
|
+
], [t]);
|
|
72
|
+
const groups = React.useMemo(() => [
|
|
73
|
+
{ id: "details", title: t("devices.form.details"), column: 1, fields: ["clientAppVersion", "osVersion", "pushProvider"] }
|
|
74
|
+
], [t]);
|
|
75
|
+
if (isLoading) {
|
|
76
|
+
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(LoadingMessage, { label: t("common.loading") }) }) });
|
|
77
|
+
}
|
|
78
|
+
if (notFound) {
|
|
79
|
+
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
|
|
80
|
+
RecordNotFoundState,
|
|
81
|
+
{
|
|
82
|
+
label: t("devices.errors.not_found"),
|
|
83
|
+
backHref: "/backend/devices",
|
|
84
|
+
backLabel: t("devices.list.title")
|
|
85
|
+
}
|
|
86
|
+
) }) });
|
|
87
|
+
}
|
|
88
|
+
if (error || !device) {
|
|
89
|
+
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ErrorMessage, { label: error ?? t("devices.form.error.loadFailed") }) }) });
|
|
90
|
+
}
|
|
91
|
+
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
|
|
92
|
+
CrudForm,
|
|
93
|
+
{
|
|
94
|
+
title: t("devices.form.editTitle"),
|
|
95
|
+
backHref: "/backend/devices",
|
|
96
|
+
contentHeader: /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-1 gap-3 rounded-md border bg-muted p-4 text-sm sm:grid-cols-3", children: [
|
|
97
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
98
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs font-medium text-muted-foreground", children: t("devices.form.deviceId") }),
|
|
99
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-1", children: /* @__PURE__ */ jsx("code", { className: "text-xs", children: device.device_id }) })
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
102
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs font-medium text-muted-foreground", children: t("devices.form.platform") }),
|
|
103
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-1", children: device.platform })
|
|
104
|
+
] }),
|
|
105
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
106
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs font-medium text-muted-foreground", children: t("devices.form.userId") }),
|
|
107
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-1", children: userLabel ? /* @__PURE__ */ jsx(Link, { href: `/backend/users/${encodeURIComponent(device.user_id)}/edit`, className: "text-primary hover:underline", children: userLabel }) : /* @__PURE__ */ jsx("code", { className: "text-xs", children: device.user_id }) })
|
|
108
|
+
] })
|
|
109
|
+
] }),
|
|
110
|
+
fields,
|
|
111
|
+
groups,
|
|
112
|
+
optimisticLockUpdatedAt: device.updated_at,
|
|
113
|
+
initialValues: {
|
|
114
|
+
clientAppVersion: device.client_app_version ?? "",
|
|
115
|
+
osVersion: device.os_version ?? "",
|
|
116
|
+
pushProvider: device.push_provider ?? ""
|
|
117
|
+
},
|
|
118
|
+
submitLabel: t("common.save"),
|
|
119
|
+
cancelHref: "/backend/devices",
|
|
120
|
+
onSubmit: async (values) => {
|
|
121
|
+
await updateCrud(`devices/admin/devices/${encodeURIComponent(id)}`, {
|
|
122
|
+
clientAppVersion: values.clientAppVersion.trim() || null,
|
|
123
|
+
osVersion: values.osVersion.trim() || null,
|
|
124
|
+
pushProvider: values.pushProvider.trim() || null
|
|
125
|
+
});
|
|
126
|
+
flash(t("devices.form.success.updated"), "success");
|
|
127
|
+
router.push("/backend/devices");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
) }) });
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
DeviceAdminEditPage as default
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/devices/backend/devices/%5Bid%5D/page.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { LoadingMessage, ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype DeviceDetail = {\n id: string\n user_id: string\n device_id: string\n platform: string\n client_app_version: string | null\n os_version: string | null\n push_provider: string | null\n updated_at: string | null\n}\n\ntype FormValues = {\n clientAppVersion: string\n osVersion: string\n pushProvider: string\n}\n\nexport default function DeviceAdminEditPage({ params }: { params?: { id?: string } }) {\n const router = useRouter()\n const t = useT()\n const id = typeof params?.id === 'string' ? params.id : ''\n const [device, setDevice] = React.useState<DeviceDetail | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [notFound, setNotFound] = React.useState(false)\n const [userLabel, setUserLabel] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setError(null)\n setNotFound(false)\n const call = await apiCall<{ item?: DeviceDetail }>(\n `/api/devices/admin/devices/${encodeURIComponent(id)}`,\n undefined,\n { fallback: null },\n )\n if (cancelled) return\n if (call.ok && call.result?.item) {\n setDevice(call.result.item)\n } else if (call.status === 404 || (call.ok && !call.result?.item)) {\n setNotFound(true)\n } else {\n setError(t('devices.form.error.loadFailed'))\n }\n setIsLoading(false)\n }\n if (id) load()\n return () => { cancelled = true }\n }, [id, t])\n\n // Resolve the owner's display name for a link to their profile. Devices admins may not hold\n // auth.users.list, so fall back to the raw id (rendered without a link) instead of redirecting.\n React.useEffect(() => {\n const userId = device?.user_id\n if (!userId) return\n let cancelled = false\n void (async () => {\n const call = await apiCall<{ items?: { id: string; name?: string | null; email?: string | null }[] }>(\n `/api/auth/users?id=${encodeURIComponent(userId)}`,\n { headers: { 'x-om-forbidden-redirect': '0' } },\n { fallback: null },\n ).catch(() => null)\n if (cancelled || !call || !call.ok) return\n const found = call.result?.items?.find((u) => u.id === userId)\n const label = found?.name?.trim() || found?.email?.trim() || null\n if (label) setUserLabel(label)\n })()\n return () => { cancelled = true }\n }, [device?.user_id])\n\n const fields = React.useMemo<CrudField[]>(() => [\n { id: 'clientAppVersion', label: t('devices.form.appVersion'), type: 'text' },\n { id: 'osVersion', label: t('devices.form.osVersion'), type: 'text' },\n { id: 'pushProvider', label: t('devices.form.pushProvider'), type: 'text' },\n ], [t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => ([\n { id: 'details', title: t('devices.form.details'), column: 1, fields: ['clientAppVersion', 'osVersion', 'pushProvider'] },\n ]), [t])\n\n if (isLoading) {\n return <Page><PageBody><LoadingMessage label={t('common.loading')} /></PageBody></Page>\n }\n if (notFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('devices.errors.not_found')}\n backHref=\"/backend/devices\"\n backLabel={t('devices.list.title')}\n />\n </PageBody>\n </Page>\n )\n }\n if (error || !device) {\n return <Page><PageBody><ErrorMessage label={error ?? t('devices.form.error.loadFailed')} /></PageBody></Page>\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<FormValues>\n title={t('devices.form.editTitle')}\n backHref=\"/backend/devices\"\n contentHeader={(\n <dl className=\"grid grid-cols-1 gap-3 rounded-md border bg-muted p-4 text-sm sm:grid-cols-3\">\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">{t('devices.form.deviceId')}</dt>\n <dd className=\"mt-1\"><code className=\"text-xs\">{device.device_id}</code></dd>\n </div>\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">{t('devices.form.platform')}</dt>\n <dd className=\"mt-1\">{device.platform}</dd>\n </div>\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">{t('devices.form.userId')}</dt>\n <dd className=\"mt-1\">{userLabel ? (\n <Link href={`/backend/users/${encodeURIComponent(device.user_id)}/edit`} className=\"text-primary hover:underline\">{userLabel}</Link>\n ) : (\n <code className=\"text-xs\">{device.user_id}</code>\n )}</dd>\n </div>\n </dl>\n )}\n fields={fields}\n groups={groups}\n optimisticLockUpdatedAt={device.updated_at}\n initialValues={{\n clientAppVersion: device.client_app_version ?? '',\n osVersion: device.os_version ?? '',\n pushProvider: device.push_provider ?? '',\n }}\n submitLabel={t('common.save')}\n cancelHref=\"/backend/devices\"\n onSubmit={async (values) => {\n await updateCrud(`devices/admin/devices/${encodeURIComponent(id)}`, {\n clientAppVersion: values.clientAppVersion.trim() || null,\n osVersion: values.osVersion.trim() || null,\n pushProvider: values.pushProvider.trim() || null,\n })\n flash(t('devices.form.success.updated'), 'success')\n router.push('/backend/devices')\n }}\n />\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const metadata = {
|
|
2
|
+
requireAuth: true,
|
|
3
|
+
requireFeatures: ["devices.admin"],
|
|
4
|
+
pageTitle: "Edit device",
|
|
5
|
+
pageTitleKey: "devices.form.editTitle",
|
|
6
|
+
pageContext: "settings",
|
|
7
|
+
navHidden: true,
|
|
8
|
+
breadcrumb: [
|
|
9
|
+
{ label: "Devices", labelKey: "devices.nav.devices", href: "/backend/devices" },
|
|
10
|
+
{ label: "Edit device", labelKey: "devices.form.editTitle" }
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
metadata
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=page.meta.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/devices/backend/devices/%5Bid%5D/page.meta.ts"],
|
|
4
|
+
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['devices.admin'],\n pageTitle: 'Edit device',\n pageTitleKey: 'devices.form.editTitle',\n pageContext: 'settings' as const,\n navHidden: true,\n breadcrumb: [\n { label: 'Devices', labelKey: 'devices.nav.devices', href: '/backend/devices' },\n { label: 'Edit device', labelKey: 'devices.form.editTitle' },\n ],\n}\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,eAAe;AAAA,EACjC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,aAAa;AAAA,EACb,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,WAAW,UAAU,uBAAuB,MAAM,mBAAmB;AAAA,IAC9E,EAAE,OAAO,eAAe,UAAU,yBAAyB;AAAA,EAC7D;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useRouter } from "next/navigation";
|
|
5
|
+
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
6
|
+
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
|
|
7
|
+
import { createCrud } from "@open-mercato/ui/backend/utils/crud";
|
|
8
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
9
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
10
|
+
function trimmedOrUndefined(value) {
|
|
11
|
+
const trimmed = value.trim();
|
|
12
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
13
|
+
}
|
|
14
|
+
function DeviceAdminCreatePage() {
|
|
15
|
+
const router = useRouter();
|
|
16
|
+
const t = useT();
|
|
17
|
+
const fields = React.useMemo(() => [
|
|
18
|
+
{ id: "userId", label: t("devices.form.userId"), type: "text", required: true, description: t("devices.form.userIdHint") },
|
|
19
|
+
{ id: "deviceId", label: t("devices.form.deviceId"), type: "text", required: true },
|
|
20
|
+
{
|
|
21
|
+
id: "platform",
|
|
22
|
+
label: t("devices.form.platform"),
|
|
23
|
+
type: "select",
|
|
24
|
+
required: true,
|
|
25
|
+
options: [
|
|
26
|
+
{ value: "ios", label: "iOS" },
|
|
27
|
+
{ value: "android", label: "Android" },
|
|
28
|
+
{ value: "web", label: "Web" }
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{ id: "clientAppVersion", label: t("devices.form.appVersion"), type: "text" },
|
|
32
|
+
{ id: "osVersion", label: t("devices.form.osVersion"), type: "text" },
|
|
33
|
+
{ id: "pushToken", label: t("devices.form.pushToken"), type: "password", description: t("devices.form.pushTokenHint") },
|
|
34
|
+
{ id: "pushProvider", label: t("devices.form.pushProvider"), type: "text" }
|
|
35
|
+
], [t]);
|
|
36
|
+
const groups = React.useMemo(() => [
|
|
37
|
+
{ id: "details", title: t("devices.form.details"), column: 1, fields: ["userId", "deviceId", "platform", "clientAppVersion", "osVersion", "pushToken", "pushProvider"] }
|
|
38
|
+
], [t]);
|
|
39
|
+
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
|
|
40
|
+
CrudForm,
|
|
41
|
+
{
|
|
42
|
+
title: t("devices.form.createTitle"),
|
|
43
|
+
backHref: "/backend/devices",
|
|
44
|
+
fields,
|
|
45
|
+
groups,
|
|
46
|
+
initialValues: { userId: "", deviceId: "", platform: "ios", clientAppVersion: "", osVersion: "", pushToken: "", pushProvider: "" },
|
|
47
|
+
submitLabel: t("common.create"),
|
|
48
|
+
cancelHref: "/backend/devices",
|
|
49
|
+
onSubmit: async (values) => {
|
|
50
|
+
await createCrud("devices/admin/devices", {
|
|
51
|
+
userId: values.userId.trim(),
|
|
52
|
+
deviceId: values.deviceId.trim(),
|
|
53
|
+
platform: values.platform,
|
|
54
|
+
clientAppVersion: trimmedOrUndefined(values.clientAppVersion),
|
|
55
|
+
osVersion: trimmedOrUndefined(values.osVersion),
|
|
56
|
+
pushToken: trimmedOrUndefined(values.pushToken),
|
|
57
|
+
pushProvider: trimmedOrUndefined(values.pushProvider)
|
|
58
|
+
});
|
|
59
|
+
flash(t("devices.form.success.created"), "success");
|
|
60
|
+
router.push("/backend/devices");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
) }) });
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
DeviceAdminCreatePage as default
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/devices/backend/devices/create/page.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype FormValues = {\n userId: string\n deviceId: string\n platform: 'ios' | 'android' | 'web'\n clientAppVersion: string\n osVersion: string\n pushToken: string\n pushProvider: string\n}\n\nfunction trimmedOrUndefined(value: string): string | undefined {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nexport default function DeviceAdminCreatePage() {\n const router = useRouter()\n const t = useT()\n\n const fields = React.useMemo<CrudField[]>(() => [\n { id: 'userId', label: t('devices.form.userId'), type: 'text', required: true, description: t('devices.form.userIdHint') },\n { id: 'deviceId', label: t('devices.form.deviceId'), type: 'text', required: true },\n {\n id: 'platform',\n label: t('devices.form.platform'),\n type: 'select',\n required: true,\n options: [\n { value: 'ios', label: 'iOS' },\n { value: 'android', label: 'Android' },\n { value: 'web', label: 'Web' },\n ],\n },\n { id: 'clientAppVersion', label: t('devices.form.appVersion'), type: 'text' },\n { id: 'osVersion', label: t('devices.form.osVersion'), type: 'text' },\n { id: 'pushToken', label: t('devices.form.pushToken'), type: 'password', description: t('devices.form.pushTokenHint') },\n { id: 'pushProvider', label: t('devices.form.pushProvider'), type: 'text' },\n ], [t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => ([\n { id: 'details', title: t('devices.form.details'), column: 1, fields: ['userId', 'deviceId', 'platform', 'clientAppVersion', 'osVersion', 'pushToken', 'pushProvider'] },\n ]), [t])\n\n return (\n <Page>\n <PageBody>\n <CrudForm<FormValues>\n title={t('devices.form.createTitle')}\n backHref=\"/backend/devices\"\n fields={fields}\n groups={groups}\n initialValues={{ userId: '', deviceId: '', platform: 'ios', clientAppVersion: '', osVersion: '', pushToken: '', pushProvider: '' }}\n submitLabel={t('common.create')}\n cancelHref=\"/backend/devices\"\n onSubmit={async (values) => {\n await createCrud('devices/admin/devices', {\n userId: values.userId.trim(),\n deviceId: values.deviceId.trim(),\n platform: values.platform,\n clientAppVersion: trimmedOrUndefined(values.clientAppVersion),\n osVersion: trimmedOrUndefined(values.osVersion),\n pushToken: trimmedOrUndefined(values.pushToken),\n pushProvider: trimmedOrUndefined(values.pushProvider),\n })\n flash(t('devices.form.success.created'), 'success')\n router.push('/backend/devices')\n }}\n />\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAuDQ;AAtDR,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,MAAM,gBAAgB;AAC/B,SAAS,gBAAoD;AAC7D,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,YAAY;AAYrB,SAAS,mBAAmB,OAAmC;AAC7D,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AAEe,SAAR,wBAAyC;AAC9C,QAAM,SAAS,UAAU;AACzB,QAAM,IAAI,KAAK;AAEf,QAAM,SAAS,MAAM,QAAqB,MAAM;AAAA,IAC9C,EAAE,IAAI,UAAU,OAAO,EAAE,qBAAqB,GAAG,MAAM,QAAQ,UAAU,MAAM,aAAa,EAAE,yBAAyB,EAAE;AAAA,IACzH,EAAE,IAAI,YAAY,OAAO,EAAE,uBAAuB,GAAG,MAAM,QAAQ,UAAU,KAAK;AAAA,IAClF;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,uBAAuB;AAAA,MAChC,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS;AAAA,QACP,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,QAC7B,EAAE,OAAO,WAAW,OAAO,UAAU;AAAA,QACrC,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,EAAE,IAAI,oBAAoB,OAAO,EAAE,yBAAyB,GAAG,MAAM,OAAO;AAAA,IAC5E,EAAE,IAAI,aAAa,OAAO,EAAE,wBAAwB,GAAG,MAAM,OAAO;AAAA,IACpE,EAAE,IAAI,aAAa,OAAO,EAAE,wBAAwB,GAAG,MAAM,YAAY,aAAa,EAAE,4BAA4B,EAAE;AAAA,IACtH,EAAE,IAAI,gBAAgB,OAAO,EAAE,2BAA2B,GAAG,MAAM,OAAO;AAAA,EAC5E,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,SAAS,MAAM,QAAyB,MAAO;AAAA,IACnD,EAAE,IAAI,WAAW,OAAO,EAAE,sBAAsB,GAAG,QAAQ,GAAG,QAAQ,CAAC,UAAU,YAAY,YAAY,oBAAoB,aAAa,aAAa,cAAc,EAAE;AAAA,EACzK,GAAI,CAAC,CAAC,CAAC;AAEP,SACE,oBAAC,QACC,8BAAC,YACC;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,0BAA0B;AAAA,MACnC,UAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,eAAe,EAAE,QAAQ,IAAI,UAAU,IAAI,UAAU,OAAO,kBAAkB,IAAI,WAAW,IAAI,WAAW,IAAI,cAAc,GAAG;AAAA,MACjI,aAAa,EAAE,eAAe;AAAA,MAC9B,YAAW;AAAA,MACX,UAAU,OAAO,WAAW;AAC1B,cAAM,WAAW,yBAAyB;AAAA,UACxC,QAAQ,OAAO,OAAO,KAAK;AAAA,UAC3B,UAAU,OAAO,SAAS,KAAK;AAAA,UAC/B,UAAU,OAAO;AAAA,UACjB,kBAAkB,mBAAmB,OAAO,gBAAgB;AAAA,UAC5D,WAAW,mBAAmB,OAAO,SAAS;AAAA,UAC9C,WAAW,mBAAmB,OAAO,SAAS;AAAA,UAC9C,cAAc,mBAAmB,OAAO,YAAY;AAAA,QACtD,CAAC;AACD,cAAM,EAAE,8BAA8B,GAAG,SAAS;AAClD,eAAO,KAAK,kBAAkB;AAAA,MAChC;AAAA;AAAA,EACF,GACF,GACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const metadata = {
|
|
2
|
+
requireAuth: true,
|
|
3
|
+
requireFeatures: ["devices.admin"],
|
|
4
|
+
pageTitle: "Register device",
|
|
5
|
+
pageTitleKey: "devices.form.createTitle",
|
|
6
|
+
pageContext: "settings",
|
|
7
|
+
navHidden: true,
|
|
8
|
+
breadcrumb: [
|
|
9
|
+
{ label: "Devices", labelKey: "devices.nav.devices", href: "/backend/devices" },
|
|
10
|
+
{ label: "Register device", labelKey: "devices.form.createTitle" }
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
metadata
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=page.meta.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/devices/backend/devices/create/page.meta.ts"],
|
|
4
|
+
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['devices.admin'],\n pageTitle: 'Register device',\n pageTitleKey: 'devices.form.createTitle',\n pageContext: 'settings' as const,\n navHidden: true,\n breadcrumb: [\n { label: 'Devices', labelKey: 'devices.nav.devices', href: '/backend/devices' },\n { label: 'Register device', labelKey: 'devices.form.createTitle' },\n ],\n}\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,eAAe;AAAA,EACjC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,aAAa;AAAA,EACb,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,WAAW,UAAU,uBAAuB,MAAM,mBAAmB;AAAA,IAC9E,EAAE,OAAO,mBAAmB,UAAU,2BAA2B;AAAA,EACnE;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|