@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.
Files changed (597) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/notification/index.js +6 -0
  3. package/dist/generated/entities/notification/index.js.map +2 -2
  4. package/dist/generated/entities/notification_preference/index.js +19 -0
  5. package/dist/generated/entities/notification_preference/index.js.map +7 -0
  6. package/dist/generated/entities/notification_type/index.js +21 -0
  7. package/dist/generated/entities/notification_type/index.js.map +7 -0
  8. package/dist/generated/entities/notification_type_override/index.js +17 -0
  9. package/dist/generated/entities/notification_type_override/index.js.map +7 -0
  10. package/dist/generated/entities/push_notification_delivery/index.js +41 -0
  11. package/dist/generated/entities/push_notification_delivery/index.js.map +7 -0
  12. package/dist/generated/entities/user_device/index.js +35 -0
  13. package/dist/generated/entities/user_device/index.js.map +7 -0
  14. package/dist/generated/entities.ids.generated.js +12 -1
  15. package/dist/generated/entities.ids.generated.js.map +2 -2
  16. package/dist/generated/entity-fields-registry.js +72 -0
  17. package/dist/generated/entity-fields-registry.js.map +2 -2
  18. package/dist/helpers/integration/api.js +2 -1
  19. package/dist/helpers/integration/api.js.map +2 -2
  20. package/dist/helpers/integration/appRoot.js +9 -0
  21. package/dist/helpers/integration/appRoot.js.map +7 -0
  22. package/dist/helpers/integration/dbFixtures.js +1 -4
  23. package/dist/helpers/integration/dbFixtures.js.map +2 -2
  24. package/dist/helpers/integration/pushFake.js +126 -0
  25. package/dist/helpers/integration/pushFake.js.map +7 -0
  26. package/dist/modules/auth/notifications.js +16 -0
  27. package/dist/modules/auth/notifications.js.map +2 -2
  28. package/dist/modules/business_rules/notifications.js +2 -0
  29. package/dist/modules/business_rules/notifications.js.map +2 -2
  30. package/dist/modules/catalog/notifications.js +2 -0
  31. package/dist/modules/catalog/notifications.js.map +2 -2
  32. package/dist/modules/communication_channels/acl.js +9 -0
  33. package/dist/modules/communication_channels/acl.js.map +2 -2
  34. package/dist/modules/communication_channels/api/delete/admin/channels/[id]/route.js +133 -0
  35. package/dist/modules/communication_channels/api/delete/admin/channels/[id]/route.js.map +7 -0
  36. package/dist/modules/communication_channels/api/get/channels/[id]/health/route.js +6 -2
  37. package/dist/modules/communication_channels/api/get/channels/[id]/health/route.js.map +2 -2
  38. package/dist/modules/communication_channels/api/get/channels/[id]/route.js +6 -2
  39. package/dist/modules/communication_channels/api/get/channels/[id]/route.js.map +2 -2
  40. package/dist/modules/communication_channels/api/get/channels/route.js +2 -1
  41. package/dist/modules/communication_channels/api/get/channels/route.js.map +2 -2
  42. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +10 -5
  43. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
  44. package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js +29 -1
  45. package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js.map +2 -2
  46. package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js +157 -0
  47. package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js.map +7 -0
  48. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +8 -1
  49. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  50. package/dist/modules/communication_channels/commands/admin-delete-channel.js +141 -0
  51. package/dist/modules/communication_channels/commands/admin-delete-channel.js.map +7 -0
  52. package/dist/modules/communication_channels/commands/connect-credential-channel.js +25 -8
  53. package/dist/modules/communication_channels/commands/connect-credential-channel.js.map +2 -2
  54. package/dist/modules/communication_channels/commands/deliver-outbound-message.js +2 -2
  55. package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +2 -2
  56. package/dist/modules/communication_channels/commands/push-register.js +1 -1
  57. package/dist/modules/communication_channels/commands/push-register.js.map +2 -2
  58. package/dist/modules/communication_channels/commands/push-unregister.js +4 -3
  59. package/dist/modules/communication_channels/commands/push-unregister.js.map +2 -2
  60. package/dist/modules/communication_channels/data/entities.js +4 -0
  61. package/dist/modules/communication_channels/data/entities.js.map +2 -2
  62. package/dist/modules/communication_channels/data/validators.js +2 -1
  63. package/dist/modules/communication_channels/data/validators.js.map +2 -2
  64. package/dist/modules/communication_channels/lib/access-control.js +11 -1
  65. package/dist/modules/communication_channels/lib/access-control.js.map +2 -2
  66. package/dist/modules/communication_channels/lib/connect-channel.js +20 -12
  67. package/dist/modules/communication_channels/lib/connect-channel.js.map +2 -2
  68. package/dist/modules/communication_channels/lib/push-adapter.js +68 -0
  69. package/dist/modules/communication_channels/lib/push-adapter.js.map +7 -0
  70. package/dist/modules/communication_channels/lib/push-capabilities.js +31 -0
  71. package/dist/modules/communication_channels/lib/push-capabilities.js.map +7 -0
  72. package/dist/modules/communication_channels/lib/push-connect-error.js +20 -0
  73. package/dist/modules/communication_channels/lib/push-connect-error.js.map +7 -0
  74. package/dist/modules/communication_channels/lib/push-credential-errors.js +41 -0
  75. package/dist/modules/communication_channels/lib/push-credential-errors.js.map +7 -0
  76. package/dist/modules/communication_channels/lib/push-envelope.js +46 -0
  77. package/dist/modules/communication_channels/lib/push-envelope.js.map +7 -0
  78. package/dist/modules/communication_channels/lib/refcounted-client-cache.js +64 -0
  79. package/dist/modules/communication_channels/lib/refcounted-client-cache.js.map +7 -0
  80. package/dist/modules/communication_channels/migrations/Migration20260703123630_communication_channels.js +13 -0
  81. package/dist/modules/communication_channels/migrations/Migration20260703123630_communication_channels.js.map +7 -0
  82. package/dist/modules/communication_channels/notifications.js +4 -0
  83. package/dist/modules/communication_channels/notifications.js.map +2 -2
  84. package/dist/modules/communication_channels/setup.js +2 -0
  85. package/dist/modules/communication_channels/setup.js.map +2 -2
  86. package/dist/modules/configs/lib/upgrade-actions.js +21 -0
  87. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  88. package/dist/modules/customer_accounts/notifications.js +12 -0
  89. package/dist/modules/customer_accounts/notifications.js.map +2 -2
  90. package/dist/modules/customers/notifications.js +4 -0
  91. package/dist/modules/customers/notifications.js.map +2 -2
  92. package/dist/modules/devices/acl.js +11 -0
  93. package/dist/modules/devices/acl.js.map +7 -0
  94. package/dist/modules/devices/api/[id]/route.js +167 -0
  95. package/dist/modules/devices/api/[id]/route.js.map +7 -0
  96. package/dist/modules/devices/api/admin/devices/[id]/route.js +219 -0
  97. package/dist/modules/devices/api/admin/devices/[id]/route.js.map +7 -0
  98. package/dist/modules/devices/api/admin/devices/route.js +140 -0
  99. package/dist/modules/devices/api/admin/devices/route.js.map +7 -0
  100. package/dist/modules/devices/api/auth.js +9 -0
  101. package/dist/modules/devices/api/auth.js.map +7 -0
  102. package/dist/modules/devices/api/deviceList.js +53 -0
  103. package/dist/modules/devices/api/deviceList.js.map +7 -0
  104. package/dist/modules/devices/api/deviceOps.js +118 -0
  105. package/dist/modules/devices/api/deviceOps.js.map +7 -0
  106. package/dist/modules/devices/api/openapi.js +19 -0
  107. package/dist/modules/devices/api/openapi.js.map +7 -0
  108. package/dist/modules/devices/api/route.js +143 -0
  109. package/dist/modules/devices/api/route.js.map +7 -0
  110. package/dist/modules/devices/backend/devices/[id]/page.js +135 -0
  111. package/dist/modules/devices/backend/devices/[id]/page.js.map +7 -0
  112. package/dist/modules/devices/backend/devices/[id]/page.meta.js +16 -0
  113. package/dist/modules/devices/backend/devices/[id]/page.meta.js.map +7 -0
  114. package/dist/modules/devices/backend/devices/create/page.js +68 -0
  115. package/dist/modules/devices/backend/devices/create/page.js.map +7 -0
  116. package/dist/modules/devices/backend/devices/create/page.meta.js +16 -0
  117. package/dist/modules/devices/backend/devices/create/page.meta.js.map +7 -0
  118. package/dist/modules/devices/backend/devices/page.js +235 -0
  119. package/dist/modules/devices/backend/devices/page.js.map +7 -0
  120. package/dist/modules/devices/backend/devices/page.meta.js +23 -0
  121. package/dist/modules/devices/backend/devices/page.meta.js.map +7 -0
  122. package/dist/modules/devices/commands/deactivate.js +107 -0
  123. package/dist/modules/devices/commands/deactivate.js.map +7 -0
  124. package/dist/modules/devices/commands/index.js +4 -0
  125. package/dist/modules/devices/commands/index.js.map +7 -0
  126. package/dist/modules/devices/commands/register.js +183 -0
  127. package/dist/modules/devices/commands/register.js.map +7 -0
  128. package/dist/modules/devices/commands/shared.js +74 -0
  129. package/dist/modules/devices/commands/shared.js.map +7 -0
  130. package/dist/modules/devices/commands/update.js +126 -0
  131. package/dist/modules/devices/commands/update.js.map +7 -0
  132. package/dist/modules/devices/data/entities.js +83 -0
  133. package/dist/modules/devices/data/entities.js.map +7 -0
  134. package/dist/modules/devices/data/validators.js +49 -0
  135. package/dist/modules/devices/data/validators.js.map +7 -0
  136. package/dist/modules/devices/di.js +11 -0
  137. package/dist/modules/devices/di.js.map +7 -0
  138. package/dist/modules/devices/encryption.js +12 -0
  139. package/dist/modules/devices/encryption.js.map +7 -0
  140. package/dist/modules/devices/events.js +19 -0
  141. package/dist/modules/devices/events.js.map +7 -0
  142. package/dist/modules/devices/index.js +17 -0
  143. package/dist/modules/devices/index.js.map +7 -0
  144. package/dist/modules/devices/lib/operationMetadata.js +20 -0
  145. package/dist/modules/devices/lib/operationMetadata.js.map +7 -0
  146. package/dist/modules/devices/migrations/Migration20260602120000.js +15 -0
  147. package/dist/modules/devices/migrations/Migration20260602120000.js.map +7 -0
  148. package/dist/modules/devices/migrations/Migration20260630120000.js +15 -0
  149. package/dist/modules/devices/migrations/Migration20260630120000.js.map +7 -0
  150. package/dist/modules/devices/migrations/Migration20260701120000.js +13 -0
  151. package/dist/modules/devices/migrations/Migration20260701120000.js.map +7 -0
  152. package/dist/modules/devices/migrations/Migration20260721120000.js +15 -0
  153. package/dist/modules/devices/migrations/Migration20260721120000.js.map +7 -0
  154. package/dist/modules/devices/setup.js +13 -0
  155. package/dist/modules/devices/setup.js.map +7 -0
  156. package/dist/modules/entities/cli.js +8 -3
  157. package/dist/modules/entities/cli.js.map +2 -2
  158. package/dist/modules/entities/migrations/Migration20260722120000.js +28 -0
  159. package/dist/modules/entities/migrations/Migration20260722120000.js.map +7 -0
  160. package/dist/modules/inbox_ops/notifications.js +2 -0
  161. package/dist/modules/inbox_ops/notifications.js.map +2 -2
  162. package/dist/modules/messages/notifications.js +2 -0
  163. package/dist/modules/messages/notifications.js.map +2 -2
  164. package/dist/modules/notifications/acl.js +3 -1
  165. package/dist/modules/notifications/acl.js.map +2 -2
  166. package/dist/modules/notifications/api/admin/preferences/route.js +167 -0
  167. package/dist/modules/notifications/api/admin/preferences/route.js.map +7 -0
  168. package/dist/modules/notifications/api/channels/route.js +54 -0
  169. package/dist/modules/notifications/api/channels/route.js.map +7 -0
  170. package/dist/modules/notifications/api/preferences/route.js +126 -0
  171. package/dist/modules/notifications/api/preferences/route.js.map +7 -0
  172. package/dist/modules/notifications/api/route.js +8 -1
  173. package/dist/modules/notifications/api/route.js.map +2 -2
  174. package/dist/modules/notifications/api/types/[id]/channels/[channel]/route.js +187 -0
  175. package/dist/modules/notifications/api/types/[id]/channels/[channel]/route.js.map +7 -0
  176. package/dist/modules/notifications/api/types/route.js +225 -0
  177. package/dist/modules/notifications/api/types/route.js.map +7 -0
  178. package/dist/modules/notifications/api/unread-count/route.js +5 -1
  179. package/dist/modules/notifications/api/unread-count/route.js.map +2 -2
  180. package/dist/modules/notifications/backend/notifications/user-preferences/page.js +10 -0
  181. package/dist/modules/notifications/backend/notifications/user-preferences/page.js.map +7 -0
  182. package/dist/modules/notifications/backend/notifications/user-preferences/page.meta.js +28 -0
  183. package/dist/modules/notifications/backend/notifications/user-preferences/page.meta.js.map +7 -0
  184. package/dist/modules/notifications/backend/profile/notification-preferences/page.js +10 -0
  185. package/dist/modules/notifications/backend/profile/notification-preferences/page.js.map +7 -0
  186. package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js +33 -0
  187. package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js.map +7 -0
  188. package/dist/modules/notifications/data/entities.js +128 -1
  189. package/dist/modules/notifications/data/entities.js.map +2 -2
  190. package/dist/modules/notifications/data/validators.js +95 -2
  191. package/dist/modules/notifications/data/validators.js.map +2 -2
  192. package/dist/modules/notifications/di.js +7 -0
  193. package/dist/modules/notifications/di.js.map +2 -2
  194. package/dist/modules/notifications/events.js +17 -0
  195. package/dist/modules/notifications/events.js.map +2 -2
  196. package/dist/modules/notifications/frontend/NotificationPreferenceMatrix.js +190 -0
  197. package/dist/modules/notifications/frontend/NotificationPreferenceMatrix.js.map +7 -0
  198. package/dist/modules/notifications/frontend/NotificationPreferencesPageClient.js +124 -0
  199. package/dist/modules/notifications/frontend/NotificationPreferencesPageClient.js.map +7 -0
  200. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +166 -1
  201. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +2 -2
  202. package/dist/modules/notifications/frontend/NotificationUserPreferencesAdminPageClient.js +172 -0
  203. package/dist/modules/notifications/frontend/NotificationUserPreferencesAdminPageClient.js.map +7 -0
  204. package/dist/modules/notifications/generators.js +63 -0
  205. package/dist/modules/notifications/generators.js.map +7 -0
  206. package/dist/modules/notifications/lib/delivery-strategies-registry.js +19 -0
  207. package/dist/modules/notifications/lib/delivery-strategies-registry.js.map +7 -0
  208. package/dist/modules/notifications/lib/deliveryStrategies.js.map +2 -2
  209. package/dist/modules/notifications/lib/derive-category.js +8 -0
  210. package/dist/modules/notifications/lib/derive-category.js.map +7 -0
  211. package/dist/modules/notifications/lib/notification-channel-registry.js +35 -0
  212. package/dist/modules/notifications/lib/notification-channel-registry.js.map +7 -0
  213. package/dist/modules/notifications/lib/notification-type-registry.js +87 -0
  214. package/dist/modules/notifications/lib/notification-type-registry.js.map +7 -0
  215. package/dist/modules/notifications/lib/notificationCopy.js +14 -0
  216. package/dist/modules/notifications/lib/notificationCopy.js.map +7 -0
  217. package/dist/modules/notifications/lib/notificationFactory.js +4 -1
  218. package/dist/modules/notifications/lib/notificationFactory.js.map +2 -2
  219. package/dist/modules/notifications/lib/notificationMapper.js +2 -0
  220. package/dist/modules/notifications/lib/notificationMapper.js.map +2 -2
  221. package/dist/modules/notifications/lib/notificationPreferenceService.js +83 -0
  222. package/dist/modules/notifications/lib/notificationPreferenceService.js.map +7 -0
  223. package/dist/modules/notifications/lib/notificationService.js +83 -28
  224. package/dist/modules/notifications/lib/notificationService.js.map +2 -2
  225. package/dist/modules/notifications/lib/notificationVisibility.js +24 -0
  226. package/dist/modules/notifications/lib/notificationVisibility.js.map +7 -0
  227. package/dist/modules/notifications/lib/routeHelpers.js +11 -1
  228. package/dist/modules/notifications/lib/routeHelpers.js.map +2 -2
  229. package/dist/modules/notifications/lib/shouldDeliver.js +46 -0
  230. package/dist/modules/notifications/lib/shouldDeliver.js.map +7 -0
  231. package/dist/modules/notifications/lib/strategies/email-delivery-strategy.js +54 -0
  232. package/dist/modules/notifications/lib/strategies/email-delivery-strategy.js.map +7 -0
  233. package/dist/modules/notifications/lib/strategies/in-app-delivery-strategy.js +12 -0
  234. package/dist/modules/notifications/lib/strategies/in-app-delivery-strategy.js.map +7 -0
  235. package/dist/modules/notifications/lib/typeCatalogue.js +71 -0
  236. package/dist/modules/notifications/lib/typeCatalogue.js.map +7 -0
  237. package/dist/modules/notifications/lib/typeChannelSettings.js +12 -0
  238. package/dist/modules/notifications/lib/typeChannelSettings.js.map +7 -0
  239. package/dist/modules/notifications/lib/typeOverrides.js +19 -0
  240. package/dist/modules/notifications/lib/typeOverrides.js.map +7 -0
  241. package/dist/modules/notifications/migrations/Migration20260625122947_notifications.js +14 -0
  242. package/dist/modules/notifications/migrations/Migration20260625122947_notifications.js.map +7 -0
  243. package/dist/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.js +15 -0
  244. package/dist/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.js.map +7 -0
  245. package/dist/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.js +13 -0
  246. package/dist/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.js.map +7 -0
  247. package/dist/modules/notifications/migrations/Migration20260626140000_notifications_type_category_silent.js +15 -0
  248. package/dist/modules/notifications/migrations/Migration20260626140000_notifications_type_category_silent.js.map +7 -0
  249. package/dist/modules/notifications/migrations/Migration20260706120000_notifications_channels.js +13 -0
  250. package/dist/modules/notifications/migrations/Migration20260706120000_notifications_channels.js.map +7 -0
  251. package/dist/modules/notifications/migrations/Migration20260716123121_notifications.js +14 -0
  252. package/dist/modules/notifications/migrations/Migration20260716123121_notifications.js.map +7 -0
  253. package/dist/modules/notifications/notification-channels.js +26 -0
  254. package/dist/modules/notifications/notification-channels.js.map +7 -0
  255. package/dist/modules/notifications/notifications.delivery-strategies.js +12 -0
  256. package/dist/modules/notifications/notifications.delivery-strategies.js.map +7 -0
  257. package/dist/modules/notifications/setup.js +16 -1
  258. package/dist/modules/notifications/setup.js.map +2 -2
  259. package/dist/modules/notifications/subscribers/deliver-notification.js +66 -57
  260. package/dist/modules/notifications/subscribers/deliver-notification.js.map +2 -2
  261. package/dist/modules/notifications/subscribers/sync-notification-types.js +16 -0
  262. package/dist/modules/notifications/subscribers/sync-notification-types.js.map +7 -0
  263. package/dist/modules/notifications/widgets/injection/profile-preferences-menu/widget.js +23 -0
  264. package/dist/modules/notifications/widgets/injection/profile-preferences-menu/widget.js.map +7 -0
  265. package/dist/modules/notifications/widgets/injection-table.js +14 -0
  266. package/dist/modules/notifications/widgets/injection-table.js.map +7 -0
  267. package/dist/modules/push_notifications/acl.js +13 -0
  268. package/dist/modules/push_notifications/acl.js.map +7 -0
  269. package/dist/modules/push_notifications/api/custom-send/route.js +141 -0
  270. package/dist/modules/push_notifications/api/custom-send/route.js.map +7 -0
  271. package/dist/modules/push_notifications/api/deliveries/[id]/route.js +110 -0
  272. package/dist/modules/push_notifications/api/deliveries/[id]/route.js.map +7 -0
  273. package/dist/modules/push_notifications/api/deliveries/route.js +56 -0
  274. package/dist/modules/push_notifications/api/deliveries/route.js.map +7 -0
  275. package/dist/modules/push_notifications/api/openapi.js +19 -0
  276. package/dist/modules/push_notifications/api/openapi.js.map +7 -0
  277. package/dist/modules/push_notifications/backend/push_notifications/[id]/page.js +103 -0
  278. package/dist/modules/push_notifications/backend/push_notifications/[id]/page.js.map +7 -0
  279. package/dist/modules/push_notifications/backend/push_notifications/[id]/page.meta.js +13 -0
  280. package/dist/modules/push_notifications/backend/push_notifications/[id]/page.meta.js.map +7 -0
  281. package/dist/modules/push_notifications/backend/push_notifications/page.js +213 -0
  282. package/dist/modules/push_notifications/backend/push_notifications/page.js.map +7 -0
  283. package/dist/modules/push_notifications/backend/push_notifications/page.meta.js +23 -0
  284. package/dist/modules/push_notifications/backend/push_notifications/page.meta.js.map +7 -0
  285. package/dist/modules/push_notifications/backend/push_notifications/send/page.js +245 -0
  286. package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +7 -0
  287. package/dist/modules/push_notifications/backend/push_notifications/send/page.meta.js +26 -0
  288. package/dist/modules/push_notifications/backend/push_notifications/send/page.meta.js.map +7 -0
  289. package/dist/modules/push_notifications/data/entities.js +92 -0
  290. package/dist/modules/push_notifications/data/entities.js.map +7 -0
  291. package/dist/modules/push_notifications/data/extensions.js +23 -0
  292. package/dist/modules/push_notifications/data/extensions.js.map +7 -0
  293. package/dist/modules/push_notifications/data/validators.js +89 -0
  294. package/dist/modules/push_notifications/data/validators.js.map +7 -0
  295. package/dist/modules/push_notifications/di.js +17 -0
  296. package/dist/modules/push_notifications/di.js.map +7 -0
  297. package/dist/modules/push_notifications/events.js +24 -0
  298. package/dist/modules/push_notifications/events.js.map +7 -0
  299. package/dist/modules/push_notifications/index.js +16 -0
  300. package/dist/modules/push_notifications/index.js.map +7 -0
  301. package/dist/modules/push_notifications/lib/fake-provider-recorder.js +80 -0
  302. package/dist/modules/push_notifications/lib/fake-provider-recorder.js.map +7 -0
  303. package/dist/modules/push_notifications/lib/push-delivery-strategy.js +54 -0
  304. package/dist/modules/push_notifications/lib/push-delivery-strategy.js.map +7 -0
  305. package/dist/modules/push_notifications/lib/push-delivery.js +297 -0
  306. package/dist/modules/push_notifications/lib/push-delivery.js.map +7 -0
  307. package/dist/modules/push_notifications/lib/push-fanout.js +138 -0
  308. package/dist/modules/push_notifications/lib/push-fanout.js.map +7 -0
  309. package/dist/modules/push_notifications/lib/push-health.js +32 -0
  310. package/dist/modules/push_notifications/lib/push-health.js.map +7 -0
  311. package/dist/modules/push_notifications/lib/push-reaper.js +87 -0
  312. package/dist/modules/push_notifications/lib/push-reaper.js.map +7 -0
  313. package/dist/modules/push_notifications/lib/push-receipt-reaper.js +136 -0
  314. package/dist/modules/push_notifications/lib/push-receipt-reaper.js.map +7 -0
  315. package/dist/modules/push_notifications/lib/push-stub-adapter.js +63 -0
  316. package/dist/modules/push_notifications/lib/push-stub-adapter.js.map +7 -0
  317. package/dist/modules/push_notifications/lib/queue.js +53 -0
  318. package/dist/modules/push_notifications/lib/queue.js.map +7 -0
  319. package/dist/modules/push_notifications/lib/reclaim-window.js +13 -0
  320. package/dist/modules/push_notifications/lib/reclaim-window.js.map +7 -0
  321. package/dist/modules/push_notifications/lib/send-custom-push.js +48 -0
  322. package/dist/modules/push_notifications/lib/send-custom-push.js.map +7 -0
  323. package/dist/modules/push_notifications/migrations/Migration20260625150049_push_notifications.js +16 -0
  324. package/dist/modules/push_notifications/migrations/Migration20260625150049_push_notifications.js.map +7 -0
  325. package/dist/modules/push_notifications/migrations/Migration20260626120000_push_notifications_silent.js +13 -0
  326. package/dist/modules/push_notifications/migrations/Migration20260626120000_push_notifications_silent.js.map +7 -0
  327. package/dist/modules/push_notifications/notifications.delivery-strategies.js +8 -0
  328. package/dist/modules/push_notifications/notifications.delivery-strategies.js.map +7 -0
  329. package/dist/modules/push_notifications/notifications.js +40 -0
  330. package/dist/modules/push_notifications/notifications.js.map +7 -0
  331. package/dist/modules/push_notifications/setup.js +52 -0
  332. package/dist/modules/push_notifications/setup.js.map +7 -0
  333. package/dist/modules/push_notifications/workers/reclaim-stuck.worker.js +57 -0
  334. package/dist/modules/push_notifications/workers/reclaim-stuck.worker.js.map +7 -0
  335. package/dist/modules/push_notifications/workers/send-push.worker.js +27 -0
  336. package/dist/modules/push_notifications/workers/send-push.worker.js.map +7 -0
  337. package/dist/modules/sales/notifications.js +8 -0
  338. package/dist/modules/sales/notifications.js.map +2 -2
  339. package/dist/modules/staff/notifications.js +6 -0
  340. package/dist/modules/staff/notifications.js.map +2 -2
  341. package/dist/modules/workflows/notifications.js +2 -0
  342. package/dist/modules/workflows/notifications.js.map +2 -2
  343. package/generated/entities/notification/index.ts +3 -0
  344. package/generated/entities/notification_preference/index.ts +8 -0
  345. package/generated/entities/notification_type/index.ts +9 -0
  346. package/generated/entities/notification_type_override/index.ts +7 -0
  347. package/generated/entities/push_notification_delivery/index.ts +19 -0
  348. package/generated/entities/user_device/index.ts +16 -0
  349. package/generated/entities.ids.generated.ts +12 -1
  350. package/generated/entity-fields-registry.ts +72 -0
  351. package/package.json +7 -7
  352. package/src/helpers/integration/api.ts +2 -1
  353. package/src/helpers/integration/appRoot.ts +13 -0
  354. package/src/helpers/integration/dbFixtures.ts +1 -5
  355. package/src/helpers/integration/pushFake.ts +219 -0
  356. package/src/modules/auth/i18n/de.json +1 -0
  357. package/src/modules/auth/i18n/en.json +1 -0
  358. package/src/modules/auth/i18n/es.json +1 -0
  359. package/src/modules/auth/i18n/ko.json +1 -0
  360. package/src/modules/auth/i18n/pl.json +1 -0
  361. package/src/modules/auth/notifications.ts +16 -0
  362. package/src/modules/business_rules/i18n/de.json +2 -1
  363. package/src/modules/business_rules/i18n/en.json +2 -1
  364. package/src/modules/business_rules/i18n/es.json +2 -1
  365. package/src/modules/business_rules/i18n/ko.json +2 -1
  366. package/src/modules/business_rules/i18n/pl.json +2 -1
  367. package/src/modules/business_rules/notifications.ts +2 -0
  368. package/src/modules/catalog/i18n/de.json +2 -1
  369. package/src/modules/catalog/i18n/en.json +2 -1
  370. package/src/modules/catalog/i18n/es.json +2 -1
  371. package/src/modules/catalog/i18n/ko.json +2 -1
  372. package/src/modules/catalog/i18n/pl.json +2 -1
  373. package/src/modules/catalog/notifications.ts +2 -0
  374. package/src/modules/communication_channels/acl.ts +9 -0
  375. package/src/modules/communication_channels/api/delete/admin/channels/[id]/route.ts +168 -0
  376. package/src/modules/communication_channels/api/get/channels/[id]/health/route.ts +6 -2
  377. package/src/modules/communication_channels/api/get/channels/[id]/route.ts +6 -2
  378. package/src/modules/communication_channels/api/get/channels/route.ts +2 -1
  379. package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +16 -5
  380. package/src/modules/communication_channels/api/post/channels/connect/credentials/route.ts +37 -1
  381. package/src/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.ts +175 -0
  382. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +11 -1
  383. package/src/modules/communication_channels/commands/admin-delete-channel.ts +203 -0
  384. package/src/modules/communication_channels/commands/connect-credential-channel.ts +63 -15
  385. package/src/modules/communication_channels/commands/deliver-outbound-message.ts +10 -2
  386. package/src/modules/communication_channels/commands/push-register.ts +7 -1
  387. package/src/modules/communication_channels/commands/push-unregister.ts +14 -3
  388. package/src/modules/communication_channels/data/entities.ts +10 -0
  389. package/src/modules/communication_channels/data/validators.ts +1 -0
  390. package/src/modules/communication_channels/i18n/de.json +35 -1
  391. package/src/modules/communication_channels/i18n/en.json +35 -1
  392. package/src/modules/communication_channels/i18n/es.json +35 -1
  393. package/src/modules/communication_channels/i18n/ko.json +35 -1
  394. package/src/modules/communication_channels/i18n/pl.json +35 -1
  395. package/src/modules/communication_channels/lib/access-control.ts +42 -0
  396. package/src/modules/communication_channels/lib/adapter.ts +25 -0
  397. package/src/modules/communication_channels/lib/connect-channel.ts +61 -26
  398. package/src/modules/communication_channels/lib/push-adapter.ts +139 -0
  399. package/src/modules/communication_channels/lib/push-capabilities.ts +42 -0
  400. package/src/modules/communication_channels/lib/push-connect-error.ts +52 -0
  401. package/src/modules/communication_channels/lib/push-credential-errors.ts +58 -0
  402. package/src/modules/communication_channels/lib/push-envelope.ts +104 -0
  403. package/src/modules/communication_channels/lib/refcounted-client-cache.ts +123 -0
  404. package/src/modules/communication_channels/migrations/.snapshot-open-mercato.json +9 -0
  405. package/src/modules/communication_channels/migrations/Migration20260703123630_communication_channels.ts +20 -0
  406. package/src/modules/communication_channels/notifications.ts +4 -0
  407. package/src/modules/communication_channels/setup.ts +2 -0
  408. package/src/modules/configs/i18n/de.json +5 -1
  409. package/src/modules/configs/i18n/en.json +5 -1
  410. package/src/modules/configs/i18n/es.json +5 -1
  411. package/src/modules/configs/i18n/ko.json +5 -1
  412. package/src/modules/configs/i18n/pl.json +5 -1
  413. package/src/modules/configs/lib/upgrade-actions.ts +21 -0
  414. package/src/modules/customer_accounts/i18n/de.json +2 -1
  415. package/src/modules/customer_accounts/i18n/en.json +2 -1
  416. package/src/modules/customer_accounts/i18n/es.json +2 -1
  417. package/src/modules/customer_accounts/i18n/ko.json +2 -1
  418. package/src/modules/customer_accounts/i18n/pl.json +2 -1
  419. package/src/modules/customer_accounts/notifications.ts +12 -0
  420. package/src/modules/customers/i18n/de.json +2 -1
  421. package/src/modules/customers/i18n/en.json +2 -1
  422. package/src/modules/customers/i18n/es.json +2 -1
  423. package/src/modules/customers/i18n/ko.json +2 -1
  424. package/src/modules/customers/i18n/pl.json +2 -1
  425. package/src/modules/customers/notifications.ts +4 -0
  426. package/src/modules/devices/AGENTS.md +101 -0
  427. package/src/modules/devices/acl.ts +7 -0
  428. package/src/modules/devices/api/[id]/route.ts +180 -0
  429. package/src/modules/devices/api/admin/devices/[id]/route.ts +235 -0
  430. package/src/modules/devices/api/admin/devices/route.ts +160 -0
  431. package/src/modules/devices/api/auth.ts +13 -0
  432. package/src/modules/devices/api/deviceList.ts +54 -0
  433. package/src/modules/devices/api/deviceOps.ts +186 -0
  434. package/src/modules/devices/api/openapi.ts +23 -0
  435. package/src/modules/devices/api/route.ts +165 -0
  436. package/src/modules/devices/backend/devices/[id]/page.meta.ts +12 -0
  437. package/src/modules/devices/backend/devices/[id]/page.tsx +164 -0
  438. package/src/modules/devices/backend/devices/create/page.meta.ts +12 -0
  439. package/src/modules/devices/backend/devices/create/page.tsx +81 -0
  440. package/src/modules/devices/backend/devices/page.meta.ts +21 -0
  441. package/src/modules/devices/backend/devices/page.tsx +259 -0
  442. package/src/modules/devices/commands/deactivate.ts +126 -0
  443. package/src/modules/devices/commands/index.ts +3 -0
  444. package/src/modules/devices/commands/register.ts +199 -0
  445. package/src/modules/devices/commands/shared.ts +119 -0
  446. package/src/modules/devices/commands/update.ts +142 -0
  447. package/src/modules/devices/data/entities.ts +79 -0
  448. package/src/modules/devices/data/validators.ts +65 -0
  449. package/src/modules/devices/di.ts +9 -0
  450. package/src/modules/devices/encryption.ts +15 -0
  451. package/src/modules/devices/events.ts +16 -0
  452. package/src/modules/devices/i18n/de.json +45 -0
  453. package/src/modules/devices/i18n/en.json +45 -0
  454. package/src/modules/devices/i18n/es.json +45 -0
  455. package/src/modules/devices/i18n/ko.json +45 -0
  456. package/src/modules/devices/i18n/pl.json +45 -0
  457. package/src/modules/devices/index.ts +15 -0
  458. package/src/modules/devices/lib/operationMetadata.ts +35 -0
  459. package/src/modules/devices/migrations/.snapshot-open-mercato.json +200 -0
  460. package/src/modules/devices/migrations/Migration20260602120000.ts +15 -0
  461. package/src/modules/devices/migrations/Migration20260630120000.ts +20 -0
  462. package/src/modules/devices/migrations/Migration20260701120000.ts +13 -0
  463. package/src/modules/devices/migrations/Migration20260721120000.ts +18 -0
  464. package/src/modules/devices/setup.ts +11 -0
  465. package/src/modules/entities/cli.ts +16 -2
  466. package/src/modules/entities/migrations/Migration20260722120000.ts +38 -0
  467. package/src/modules/inbox_ops/i18n/de.json +2 -1
  468. package/src/modules/inbox_ops/i18n/en.json +2 -1
  469. package/src/modules/inbox_ops/i18n/es.json +2 -1
  470. package/src/modules/inbox_ops/i18n/ko.json +2 -1
  471. package/src/modules/inbox_ops/i18n/pl.json +2 -1
  472. package/src/modules/inbox_ops/notifications.ts +2 -0
  473. package/src/modules/messages/i18n/de.json +2 -1
  474. package/src/modules/messages/i18n/en.json +2 -1
  475. package/src/modules/messages/i18n/es.json +2 -1
  476. package/src/modules/messages/i18n/ko.json +2 -1
  477. package/src/modules/messages/i18n/pl.json +2 -1
  478. package/src/modules/messages/notifications.ts +2 -0
  479. package/src/modules/notifications/AGENTS.md +54 -0
  480. package/src/modules/notifications/acl.ts +2 -0
  481. package/src/modules/notifications/api/admin/preferences/route.ts +193 -0
  482. package/src/modules/notifications/api/channels/route.ts +54 -0
  483. package/src/modules/notifications/api/preferences/route.ts +131 -0
  484. package/src/modules/notifications/api/route.ts +8 -1
  485. package/src/modules/notifications/api/types/[id]/channels/[channel]/route.ts +226 -0
  486. package/src/modules/notifications/api/types/route.ts +239 -0
  487. package/src/modules/notifications/api/unread-count/route.ts +5 -1
  488. package/src/modules/notifications/backend/notifications/user-preferences/page.meta.ts +26 -0
  489. package/src/modules/notifications/backend/notifications/user-preferences/page.tsx +12 -0
  490. package/src/modules/notifications/backend/profile/notification-preferences/page.meta.ts +31 -0
  491. package/src/modules/notifications/backend/profile/notification-preferences/page.tsx +12 -0
  492. package/src/modules/notifications/data/entities.ts +144 -0
  493. package/src/modules/notifications/data/validators.ts +116 -0
  494. package/src/modules/notifications/di.ts +7 -0
  495. package/src/modules/notifications/events.ts +23 -0
  496. package/src/modules/notifications/frontend/NotificationPreferenceMatrix.tsx +287 -0
  497. package/src/modules/notifications/frontend/NotificationPreferencesPageClient.tsx +155 -0
  498. package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +273 -2
  499. package/src/modules/notifications/frontend/NotificationUserPreferencesAdminPageClient.tsx +214 -0
  500. package/src/modules/notifications/generators.ts +82 -0
  501. package/src/modules/notifications/i18n/de.json +43 -0
  502. package/src/modules/notifications/i18n/en.json +43 -0
  503. package/src/modules/notifications/i18n/es.json +43 -0
  504. package/src/modules/notifications/i18n/ko.json +43 -0
  505. package/src/modules/notifications/i18n/pl.json +44 -1
  506. package/src/modules/notifications/lib/delivery-strategies-registry.ts +30 -0
  507. package/src/modules/notifications/lib/deliveryStrategies.ts +40 -4
  508. package/src/modules/notifications/lib/derive-category.ts +15 -0
  509. package/src/modules/notifications/lib/notification-channel-registry.ts +59 -0
  510. package/src/modules/notifications/lib/notification-type-registry.ts +182 -0
  511. package/src/modules/notifications/lib/notificationCopy.ts +34 -0
  512. package/src/modules/notifications/lib/notificationFactory.ts +5 -1
  513. package/src/modules/notifications/lib/notificationMapper.ts +2 -0
  514. package/src/modules/notifications/lib/notificationPreferenceService.ts +138 -0
  515. package/src/modules/notifications/lib/notificationService.ts +129 -25
  516. package/src/modules/notifications/lib/notificationVisibility.ts +48 -0
  517. package/src/modules/notifications/lib/routeHelpers.ts +14 -1
  518. package/src/modules/notifications/lib/shouldDeliver.ts +112 -0
  519. package/src/modules/notifications/lib/strategies/email-delivery-strategy.ts +63 -0
  520. package/src/modules/notifications/lib/strategies/in-app-delivery-strategy.ts +21 -0
  521. package/src/modules/notifications/lib/typeCatalogue.ts +141 -0
  522. package/src/modules/notifications/lib/typeChannelSettings.ts +29 -0
  523. package/src/modules/notifications/lib/typeOverrides.ts +46 -0
  524. package/src/modules/notifications/migrations/.snapshot-open-mercato.json +874 -100
  525. package/src/modules/notifications/migrations/Migration20260625122947_notifications.ts +14 -0
  526. package/src/modules/notifications/migrations/Migration20260626120500_notifications_push_payload.ts +15 -0
  527. package/src/modules/notifications/migrations/Migration20260626130000_notifications_non_opt_out.ts +13 -0
  528. package/src/modules/notifications/migrations/Migration20260626140000_notifications_type_category_silent.ts +15 -0
  529. package/src/modules/notifications/migrations/Migration20260706120000_notifications_channels.ts +13 -0
  530. package/src/modules/notifications/migrations/Migration20260716123121_notifications.ts +14 -0
  531. package/src/modules/notifications/notification-channels.ts +30 -0
  532. package/src/modules/notifications/notifications.delivery-strategies.ts +15 -0
  533. package/src/modules/notifications/setup.ts +23 -1
  534. package/src/modules/notifications/subscribers/deliver-notification.ts +105 -71
  535. package/src/modules/notifications/subscribers/sync-notification-types.ts +18 -0
  536. package/src/modules/notifications/widgets/injection/profile-preferences-menu/widget.ts +35 -0
  537. package/src/modules/notifications/widgets/injection-table.ts +18 -0
  538. package/src/modules/push_notifications/AGENTS.md +92 -0
  539. package/src/modules/push_notifications/acl.ts +9 -0
  540. package/src/modules/push_notifications/api/custom-send/route.ts +175 -0
  541. package/src/modules/push_notifications/api/deliveries/[id]/route.ts +122 -0
  542. package/src/modules/push_notifications/api/deliveries/route.ts +58 -0
  543. package/src/modules/push_notifications/api/openapi.ts +22 -0
  544. package/src/modules/push_notifications/backend/push_notifications/[id]/page.meta.ts +9 -0
  545. package/src/modules/push_notifications/backend/push_notifications/[id]/page.tsx +149 -0
  546. package/src/modules/push_notifications/backend/push_notifications/page.meta.ts +21 -0
  547. package/src/modules/push_notifications/backend/push_notifications/page.tsx +239 -0
  548. package/src/modules/push_notifications/backend/push_notifications/send/page.meta.ts +24 -0
  549. package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +327 -0
  550. package/src/modules/push_notifications/data/entities.ts +111 -0
  551. package/src/modules/push_notifications/data/extensions.ts +29 -0
  552. package/src/modules/push_notifications/data/validators.ts +102 -0
  553. package/src/modules/push_notifications/di.ts +20 -0
  554. package/src/modules/push_notifications/events.ts +21 -0
  555. package/src/modules/push_notifications/i18n/de.json +79 -0
  556. package/src/modules/push_notifications/i18n/en.json +79 -0
  557. package/src/modules/push_notifications/i18n/es.json +79 -0
  558. package/src/modules/push_notifications/i18n/ko.json +79 -0
  559. package/src/modules/push_notifications/i18n/pl.json +79 -0
  560. package/src/modules/push_notifications/index.ts +15 -0
  561. package/src/modules/push_notifications/lib/fake-provider-recorder.ts +154 -0
  562. package/src/modules/push_notifications/lib/push-delivery-strategy.ts +90 -0
  563. package/src/modules/push_notifications/lib/push-delivery.ts +455 -0
  564. package/src/modules/push_notifications/lib/push-fanout.ts +237 -0
  565. package/src/modules/push_notifications/lib/push-health.ts +47 -0
  566. package/src/modules/push_notifications/lib/push-reaper.ts +140 -0
  567. package/src/modules/push_notifications/lib/push-receipt-reaper.ts +210 -0
  568. package/src/modules/push_notifications/lib/push-stub-adapter.ts +80 -0
  569. package/src/modules/push_notifications/lib/queue.ts +74 -0
  570. package/src/modules/push_notifications/lib/reclaim-window.ts +16 -0
  571. package/src/modules/push_notifications/lib/send-custom-push.ts +100 -0
  572. package/src/modules/push_notifications/migrations/.snapshot-open-mercato.json +386 -0
  573. package/src/modules/push_notifications/migrations/Migration20260625150049_push_notifications.ts +16 -0
  574. package/src/modules/push_notifications/migrations/Migration20260626120000_push_notifications_silent.ts +13 -0
  575. package/src/modules/push_notifications/notifications.delivery-strategies.ts +8 -0
  576. package/src/modules/push_notifications/notifications.ts +50 -0
  577. package/src/modules/push_notifications/setup.ts +92 -0
  578. package/src/modules/push_notifications/workers/reclaim-stuck.worker.ts +78 -0
  579. package/src/modules/push_notifications/workers/send-push.worker.ts +34 -0
  580. package/src/modules/sales/i18n/de.json +1 -0
  581. package/src/modules/sales/i18n/en.json +1 -0
  582. package/src/modules/sales/i18n/es.json +1 -0
  583. package/src/modules/sales/i18n/ko.json +1 -0
  584. package/src/modules/sales/i18n/pl.json +1 -0
  585. package/src/modules/sales/notifications.ts +8 -0
  586. package/src/modules/staff/i18n/de.json +1 -0
  587. package/src/modules/staff/i18n/en.json +1 -0
  588. package/src/modules/staff/i18n/es.json +1 -0
  589. package/src/modules/staff/i18n/ko.json +1 -0
  590. package/src/modules/staff/i18n/pl.json +1 -0
  591. package/src/modules/staff/notifications.ts +6 -0
  592. package/src/modules/workflows/i18n/de.json +1 -0
  593. package/src/modules/workflows/i18n/en.json +1 -0
  594. package/src/modules/workflows/i18n/es.json +1 -0
  595. package/src/modules/workflows/i18n/ko.json +1 -0
  596. package/src/modules/workflows/i18n/pl.json +1 -0
  597. 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
+ }