@open-mercato/core 0.6.6 → 0.6.7-develop.6553.1.2ec7246e04

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 (271) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/gateway_session_initialization/index.js +23 -0
  3. package/dist/generated/entities/gateway_session_initialization/index.js.map +7 -0
  4. package/dist/generated/entities.ids.generated.js +1 -0
  5. package/dist/generated/entities.ids.generated.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +12 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/api_keys/api/keys/route.js +30 -13
  9. package/dist/modules/api_keys/api/keys/route.js.map +2 -2
  10. package/dist/modules/api_keys/cli.js +2 -1
  11. package/dist/modules/api_keys/cli.js.map +2 -2
  12. package/dist/modules/attachments/api/file/[id]/route.js +9 -7
  13. package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
  14. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +9 -7
  15. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
  16. package/dist/modules/attachments/api/route.js +21 -17
  17. package/dist/modules/attachments/api/route.js.map +2 -2
  18. package/dist/modules/attachments/components/AttachmentContentPreview.js +6 -35
  19. package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
  20. package/dist/modules/attachments/lib/reconcileOrganization.js +110 -0
  21. package/dist/modules/attachments/lib/reconcileOrganization.js.map +7 -0
  22. package/dist/modules/attachments/lib/requestScope.js +10 -0
  23. package/dist/modules/attachments/lib/requestScope.js.map +7 -0
  24. package/dist/modules/audit_logs/backend/audit-logs/page.js +14 -24
  25. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  26. package/dist/modules/auth/api/autologin.js +85 -0
  27. package/dist/modules/auth/api/autologin.js.map +7 -0
  28. package/dist/modules/auth/api/users/route.js +6 -2
  29. package/dist/modules/auth/api/users/route.js.map +2 -2
  30. package/dist/modules/auth/cli.js +3 -2
  31. package/dist/modules/auth/cli.js.map +2 -2
  32. package/dist/modules/auth/lib/autologin.js +19 -0
  33. package/dist/modules/auth/lib/autologin.js.map +7 -0
  34. package/dist/modules/configs/lib/upgrade-actions.js +22 -0
  35. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  36. package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +1 -0
  37. package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +2 -2
  38. package/dist/modules/customer_accounts/api/admin/roles/[id].js +17 -3
  39. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  40. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +6 -1
  41. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
  42. package/dist/modules/customer_accounts/api/portal/users-invite.js +6 -1
  43. package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
  44. package/dist/modules/customer_accounts/services/customerInvitationService.js +1 -0
  45. package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
  46. package/dist/modules/customer_accounts/services/customerRbacService.js +6 -1
  47. package/dist/modules/customer_accounts/services/customerRbacService.js.map +2 -2
  48. package/dist/modules/customer_accounts/widgets/injection-table.js +0 -2
  49. package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
  50. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +7 -1
  51. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  52. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js +2 -2
  53. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js.map +2 -2
  54. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +37 -43
  55. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
  56. package/dist/modules/customers/components/detail/DealDetailTabs.js +23 -35
  57. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
  58. package/dist/modules/customers/components/detail/DetailTabsLayout.js +6 -21
  59. package/dist/modules/customers/components/detail/DetailTabsLayout.js.map +2 -2
  60. package/dist/modules/customers/components/detail/MobilePersonDetail.js +26 -32
  61. package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +2 -2
  62. package/dist/modules/customers/components/detail/PersonDetailTabs.js +29 -39
  63. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  64. package/dist/modules/customers/components/detail/useDealsAccess.js +16 -0
  65. package/dist/modules/customers/components/detail/useDealsAccess.js.map +7 -0
  66. package/dist/modules/dashboards/api/roles/widgets/route.js +22 -3
  67. package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
  68. package/dist/modules/dashboards/api/users/widgets/route.js +22 -3
  69. package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
  70. package/dist/modules/dashboards/cli.js +4 -3
  71. package/dist/modules/dashboards/cli.js.map +2 -2
  72. package/dist/modules/dashboards/lib/widgetAssignmentScope.js +9 -1
  73. package/dist/modules/dashboards/lib/widgetAssignmentScope.js.map +2 -2
  74. package/dist/modules/dictionaries/commands/entries.js +7 -14
  75. package/dist/modules/dictionaries/commands/entries.js.map +2 -2
  76. package/dist/modules/dictionaries/commands/entry-operations.js +7 -16
  77. package/dist/modules/dictionaries/commands/entry-operations.js.map +2 -2
  78. package/dist/modules/dictionaries/commands/factory.js +9 -3
  79. package/dist/modules/dictionaries/commands/factory.js.map +2 -2
  80. package/dist/modules/dictionaries/fields/dictionary.js +56 -41
  81. package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
  82. package/dist/modules/directory/utils/organizationScope.js +10 -3
  83. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  84. package/dist/modules/entities/api/records.js +5 -4
  85. package/dist/modules/entities/api/records.js.map +2 -2
  86. package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js +1 -0
  87. package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js.map +2 -2
  88. package/dist/modules/entities/backend/entities/user/[entityId]/page.js +49 -49
  89. package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
  90. package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js +1 -0
  91. package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js.map +2 -2
  92. package/dist/modules/entities/cli.js +2 -1
  93. package/dist/modules/entities/cli.js.map +2 -2
  94. package/dist/modules/feature_toggles/api/check/boolean/route.js +0 -14
  95. package/dist/modules/feature_toggles/api/check/boolean/route.js.map +2 -2
  96. package/dist/modules/feature_toggles/defaults.json +8 -0
  97. package/dist/modules/integrations/backend/integrations/[id]/page.js +9 -80
  98. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  99. package/dist/modules/payment_gateways/data/entities.js +45 -0
  100. package/dist/modules/payment_gateways/data/entities.js.map +2 -2
  101. package/dist/modules/payment_gateways/lib/gateway-service.js +173 -38
  102. package/dist/modules/payment_gateways/lib/gateway-service.js.map +3 -3
  103. package/dist/modules/payment_gateways/lib/session-idempotency.js +104 -0
  104. package/dist/modules/payment_gateways/lib/session-idempotency.js.map +7 -0
  105. package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js +11 -0
  106. package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js.map +7 -0
  107. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +16 -14
  108. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +2 -2
  109. package/dist/modules/planner/components/AvailabilityRulesEditor.js +18 -30
  110. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  111. package/dist/modules/query_index/api/status.js +2 -8
  112. package/dist/modules/query_index/api/status.js.map +2 -2
  113. package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -24
  114. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  115. package/dist/modules/sales/backend/sales/channels/create/page.js +6 -0
  116. package/dist/modules/sales/backend/sales/channels/create/page.js.map +2 -2
  117. package/dist/modules/sales/backend/sales/channels/create/page.meta.js +2 -0
  118. package/dist/modules/sales/backend/sales/channels/create/page.meta.js.map +2 -2
  119. package/dist/modules/sales/backend/sales/channels/offers/page.js +6 -0
  120. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  121. package/dist/modules/sales/backend/sales/channels/offers/page.meta.js +2 -0
  122. package/dist/modules/sales/backend/sales/channels/offers/page.meta.js.map +2 -2
  123. package/dist/modules/sales/backend/sales/channels/page.js +6 -0
  124. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  125. package/dist/modules/sales/backend/sales/channels/page.meta.js +2 -0
  126. package/dist/modules/sales/backend/sales/channels/page.meta.js.map +2 -2
  127. package/dist/modules/sales/backend/sales/documents/[id]/page.js +6 -4
  128. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  129. package/dist/modules/sales/commands/documents.js +44 -0
  130. package/dist/modules/sales/commands/documents.js.map +2 -2
  131. package/dist/modules/sales/commands/returns.js +2 -27
  132. package/dist/modules/sales/commands/returns.js.map +2 -2
  133. package/dist/modules/sales/components/SalesChannelsDisabledNotice.js +15 -0
  134. package/dist/modules/sales/components/SalesChannelsDisabledNotice.js.map +7 -0
  135. package/dist/modules/sales/components/documents/AddressesSection.js +6 -2
  136. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  137. package/dist/modules/sales/components/documents/ItemsSection.js +1 -0
  138. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  139. package/dist/modules/sales/components/documents/LineItemDialog.js +9 -0
  140. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  141. package/dist/modules/sales/components/documents/SalesDocumentForm.js +51 -3
  142. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  143. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -8
  144. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  145. package/dist/modules/sales/components/documents/ShipmentDialog.js +59 -38
  146. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  147. package/dist/modules/sales/components/useSalesChannelsEnabled.js +44 -0
  148. package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +7 -0
  149. package/dist/modules/sales/lib/calculations.js +6 -0
  150. package/dist/modules/sales/lib/calculations.js.map +2 -2
  151. package/dist/modules/sales/lib/salesChannelsToggle.js +18 -0
  152. package/dist/modules/sales/lib/salesChannelsToggle.js.map +7 -0
  153. package/dist/modules/sales/lib/salesChannelsToggleId.js +5 -0
  154. package/dist/modules/sales/lib/salesChannelsToggleId.js.map +7 -0
  155. package/dist/modules/sales/lib/shipments/snapshots.js +27 -1
  156. package/dist/modules/sales/lib/shipments/snapshots.js.map +2 -2
  157. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +22 -25
  158. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  159. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -14
  160. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  161. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +10 -29
  162. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +2 -2
  163. package/dist/modules/sync_excel/lib/adapters/customers.js +19 -20
  164. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  165. package/dist/modules/sync_excel/lib/parser.js +185 -0
  166. package/dist/modules/sync_excel/lib/parser.js.map +2 -2
  167. package/dist/modules/sync_excel/lib/upload-storage.js +20 -1
  168. package/dist/modules/sync_excel/lib/upload-storage.js.map +2 -2
  169. package/generated/entities/gateway_session_initialization/index.ts +10 -0
  170. package/generated/entities.ids.generated.ts +1 -0
  171. package/generated/entity-fields-registry.ts +12 -0
  172. package/package.json +9 -8
  173. package/src/modules/api_keys/api/keys/route.ts +36 -13
  174. package/src/modules/api_keys/cli.ts +2 -3
  175. package/src/modules/attachments/api/file/[id]/route.ts +11 -7
  176. package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +11 -7
  177. package/src/modules/attachments/api/route.ts +26 -21
  178. package/src/modules/attachments/components/AttachmentContentPreview.tsx +9 -44
  179. package/src/modules/attachments/lib/reconcileOrganization.ts +188 -0
  180. package/src/modules/attachments/lib/requestScope.ts +27 -0
  181. package/src/modules/audit_logs/backend/audit-logs/page.tsx +12 -22
  182. package/src/modules/auth/api/autologin.ts +100 -0
  183. package/src/modules/auth/api/users/route.ts +11 -2
  184. package/src/modules/auth/cli.ts +3 -2
  185. package/src/modules/auth/lib/autologin.ts +36 -0
  186. package/src/modules/configs/i18n/de.json +5 -1
  187. package/src/modules/configs/i18n/en.json +5 -1
  188. package/src/modules/configs/i18n/es.json +5 -1
  189. package/src/modules/configs/i18n/pl.json +5 -1
  190. package/src/modules/configs/lib/upgrade-actions.ts +24 -0
  191. package/src/modules/customer_accounts/AGENTS.md +8 -6
  192. package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +1 -0
  193. package/src/modules/customer_accounts/api/admin/roles/[id].ts +17 -3
  194. package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +6 -1
  195. package/src/modules/customer_accounts/api/portal/users-invite.ts +6 -1
  196. package/src/modules/customer_accounts/services/customerInvitationService.ts +1 -0
  197. package/src/modules/customer_accounts/services/customerRbacService.ts +9 -2
  198. package/src/modules/customer_accounts/widgets/injection-table.ts +0 -2
  199. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +11 -1
  200. package/src/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.tsx +6 -2
  201. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +39 -55
  202. package/src/modules/customers/components/detail/DealDetailTabs.tsx +24 -49
  203. package/src/modules/customers/components/detail/DetailTabsLayout.tsx +13 -24
  204. package/src/modules/customers/components/detail/MobilePersonDetail.tsx +25 -31
  205. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +29 -50
  206. package/src/modules/customers/components/detail/useDealsAccess.ts +19 -0
  207. package/src/modules/dashboards/api/roles/widgets/route.ts +22 -3
  208. package/src/modules/dashboards/api/users/widgets/route.ts +22 -3
  209. package/src/modules/dashboards/cli.ts +4 -9
  210. package/src/modules/dashboards/lib/widgetAssignmentScope.ts +18 -0
  211. package/src/modules/dictionaries/commands/entries.ts +7 -16
  212. package/src/modules/dictionaries/commands/entry-operations.ts +8 -18
  213. package/src/modules/dictionaries/commands/factory.ts +8 -2
  214. package/src/modules/dictionaries/fields/dictionary.tsx +55 -32
  215. package/src/modules/dictionaries/i18n/de.json +2 -0
  216. package/src/modules/dictionaries/i18n/en.json +2 -0
  217. package/src/modules/dictionaries/i18n/es.json +2 -0
  218. package/src/modules/dictionaries/i18n/pl.json +2 -0
  219. package/src/modules/directory/utils/organizationScope.ts +36 -2
  220. package/src/modules/entities/api/records.ts +5 -7
  221. package/src/modules/entities/backend/entities/system/[entityId]/page.meta.ts +1 -0
  222. package/src/modules/entities/backend/entities/user/[entityId]/page.meta.ts +1 -0
  223. package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +51 -49
  224. package/src/modules/entities/cli.ts +2 -1
  225. package/src/modules/entities/i18n/de.json +34 -0
  226. package/src/modules/entities/i18n/en.json +34 -0
  227. package/src/modules/entities/i18n/es.json +34 -0
  228. package/src/modules/entities/i18n/pl.json +34 -0
  229. package/src/modules/feature_toggles/api/check/boolean/route.ts +0 -15
  230. package/src/modules/feature_toggles/defaults.json +8 -0
  231. package/src/modules/integrations/backend/integrations/[id]/page.tsx +16 -59
  232. package/src/modules/payment_gateways/data/entities.ts +39 -0
  233. package/src/modules/payment_gateways/lib/gateway-service.ts +211 -40
  234. package/src/modules/payment_gateways/lib/session-idempotency.ts +142 -0
  235. package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +236 -0
  236. package/src/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.ts +10 -0
  237. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +14 -20
  238. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +16 -34
  239. package/src/modules/query_index/api/status.ts +2 -8
  240. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +27 -37
  241. package/src/modules/sales/backend/sales/channels/create/page.meta.ts +3 -0
  242. package/src/modules/sales/backend/sales/channels/create/page.tsx +7 -0
  243. package/src/modules/sales/backend/sales/channels/offers/page.meta.ts +3 -0
  244. package/src/modules/sales/backend/sales/channels/offers/page.tsx +7 -0
  245. package/src/modules/sales/backend/sales/channels/page.meta.ts +4 -0
  246. package/src/modules/sales/backend/sales/channels/page.tsx +7 -0
  247. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +7 -5
  248. package/src/modules/sales/commands/documents.ts +65 -0
  249. package/src/modules/sales/commands/returns.ts +2 -32
  250. package/src/modules/sales/components/SalesChannelsDisabledNotice.tsx +21 -0
  251. package/src/modules/sales/components/documents/AddressesSection.tsx +6 -2
  252. package/src/modules/sales/components/documents/ItemsSection.tsx +5 -0
  253. package/src/modules/sales/components/documents/LineItemDialog.tsx +10 -0
  254. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +53 -3
  255. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +10 -8
  256. package/src/modules/sales/components/documents/ShipmentDialog.tsx +65 -40
  257. package/src/modules/sales/components/useSalesChannelsEnabled.ts +59 -0
  258. package/src/modules/sales/i18n/de.json +5 -0
  259. package/src/modules/sales/i18n/en.json +5 -0
  260. package/src/modules/sales/i18n/es.json +5 -0
  261. package/src/modules/sales/i18n/pl.json +5 -0
  262. package/src/modules/sales/lib/calculations.ts +15 -0
  263. package/src/modules/sales/lib/salesChannelsToggle.ts +26 -0
  264. package/src/modules/sales/lib/salesChannelsToggleId.ts +1 -0
  265. package/src/modules/sales/lib/shipments/snapshots.ts +30 -0
  266. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +25 -34
  267. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +11 -17
  268. package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +11 -28
  269. package/src/modules/sync_excel/lib/adapters/customers.ts +20 -22
  270. package/src/modules/sync_excel/lib/parser.ts +245 -0
  271. package/src/modules/sync_excel/lib/upload-storage.ts +23 -1
@@ -1199,84 +1199,41 @@ export default function IntegrationDetailPage({ params }: IntegrationDetailPageP
1199
1199
  </section>
1200
1200
  ) : null}
1201
1201
 
1202
- <Tabs value={activeTab} onValueChange={handleTabChange} className="space-y-5">
1203
- <TabsList className="h-auto w-full justify-start overflow-x-auto rounded-none border-b border-border bg-transparent p-0">
1202
+ <Tabs value={activeTab} onValueChange={handleTabChange} variant="underline" className="space-y-5">
1203
+ <TabsList className="w-full overflow-x-auto">
1204
1204
  {showCredentialsTab ? (
1205
- <TabsTrigger
1206
- value="credentials"
1207
- className="mr-8 h-auto rounded-none border-b-2 border-transparent bg-transparent px-0 py-2.5 text-sm font-medium text-muted-foreground shadow-none transition-colors hover:bg-transparent hover:text-foreground aria-selected:border-accent-indigo aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none last:mr-0"
1208
- >
1209
- <span className="inline-flex items-center gap-2">
1210
- <Key className="h-4 w-4" />
1211
- <span>{t('integrations.detail.tabs.credentials')}</span>
1212
- </span>
1205
+ <TabsTrigger value="credentials" leading={<Key className="h-4 w-4" />}>
1206
+ {t('integrations.detail.tabs.credentials')}
1213
1207
  </TabsTrigger>
1214
1208
  ) : null}
1215
1209
  {leadingInjectedTab ? (
1216
- <TabsTrigger
1217
- value={leadingInjectedTab.id}
1218
- className="mr-8 h-auto rounded-none border-b-2 border-transparent bg-transparent px-0 py-2.5 text-sm font-medium text-muted-foreground shadow-none transition-colors hover:bg-transparent hover:text-foreground aria-selected:border-accent-indigo aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none last:mr-0"
1219
- >
1220
- <span className="inline-flex items-center gap-2">
1221
- <Settings className="h-4 w-4" />
1222
- <span>{leadingInjectedTab.label}</span>
1223
- </span>
1210
+ <TabsTrigger value={leadingInjectedTab.id} leading={<Settings className="h-4 w-4" />}>
1211
+ {leadingInjectedTab.label}
1224
1212
  </TabsTrigger>
1225
1213
  ) : null}
1226
1214
  {showVersionTab ? (
1227
- <TabsTrigger
1228
- value="version"
1229
- className="mr-8 h-auto rounded-none border-b-2 border-transparent bg-transparent px-0 py-2.5 text-sm font-medium text-muted-foreground shadow-none transition-colors hover:bg-transparent hover:text-foreground aria-selected:border-accent-indigo aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none last:mr-0"
1230
- >
1231
- <span className="inline-flex items-center gap-2">
1232
- <RefreshCw className="h-4 w-4" />
1233
- <span>{t('integrations.detail.tabs.version')}</span>
1234
- </span>
1215
+ <TabsTrigger value="version" leading={<RefreshCw className="h-4 w-4" />}>
1216
+ {t('integrations.detail.tabs.version')}
1235
1217
  </TabsTrigger>
1236
1218
  ) : null}
1237
1219
  {showDataSyncScheduleTab ? (
1238
- <TabsTrigger
1239
- value="data-sync-schedule"
1240
- className="mr-8 h-auto rounded-none border-b-2 border-transparent bg-transparent px-0 py-2.5 text-sm font-medium text-muted-foreground shadow-none transition-colors hover:bg-transparent hover:text-foreground aria-selected:border-accent-indigo aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none last:mr-0"
1241
- >
1242
- <span className="inline-flex items-center gap-2">
1243
- <Calendar className="h-4 w-4" />
1244
- <span>{t('data_sync.integrationTab.title', 'Sync schedules')}</span>
1245
- </span>
1220
+ <TabsTrigger value="data-sync-schedule" leading={<Calendar className="h-4 w-4" />}>
1221
+ {t('data_sync.integrationTab.title', 'Sync schedules')}
1246
1222
  </TabsTrigger>
1247
1223
  ) : null}
1248
1224
  {showHealthTab ? (
1249
- <TabsTrigger
1250
- value="health"
1251
- className="mr-8 h-auto rounded-none border-b-2 border-transparent bg-transparent px-0 py-2.5 text-sm font-medium text-muted-foreground shadow-none transition-colors hover:bg-transparent hover:text-foreground aria-selected:border-accent-indigo aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none last:mr-0"
1252
- >
1253
- <span className="inline-flex items-center gap-2">
1254
- <Activity className="h-4 w-4" />
1255
- <span>{t('integrations.detail.tabs.health')}</span>
1256
- </span>
1225
+ <TabsTrigger value="health" leading={<Activity className="h-4 w-4" />}>
1226
+ {t('integrations.detail.tabs.health')}
1257
1227
  </TabsTrigger>
1258
1228
  ) : null}
1259
1229
  {showLogsTab ? (
1260
- <TabsTrigger
1261
- value="logs"
1262
- className="mr-8 h-auto rounded-none border-b-2 border-transparent bg-transparent px-0 py-2.5 text-sm font-medium text-muted-foreground shadow-none transition-colors hover:bg-transparent hover:text-foreground aria-selected:border-accent-indigo aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none last:mr-0"
1263
- >
1264
- <span className="inline-flex items-center gap-2">
1265
- <FileText className="h-4 w-4" />
1266
- <span>{t('integrations.detail.tabs.logs')}</span>
1267
- </span>
1230
+ <TabsTrigger value="logs" leading={<FileText className="h-4 w-4" />}>
1231
+ {t('integrations.detail.tabs.logs')}
1268
1232
  </TabsTrigger>
1269
1233
  ) : null}
1270
1234
  {trailingInjectedTabs.map((tab) => (
1271
- <TabsTrigger
1272
- key={tab.id}
1273
- value={tab.id}
1274
- className="mr-8 h-auto rounded-none border-b-2 border-transparent bg-transparent px-0 py-2.5 text-sm font-medium text-muted-foreground shadow-none transition-colors hover:bg-transparent hover:text-foreground aria-selected:border-accent-indigo aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none last:mr-0"
1275
- >
1276
- <span className="inline-flex items-center gap-2">
1277
- <Settings className="h-4 w-4" />
1278
- <span>{tab.label}</span>
1279
- </span>
1235
+ <TabsTrigger key={tab.id} value={tab.id} leading={<Settings className="h-4 w-4" />}>
1236
+ {tab.label}
1280
1237
  </TabsTrigger>
1281
1238
  ))}
1282
1239
  </TabsList>
@@ -75,6 +75,45 @@ export class GatewayTransaction {
75
75
  deletedAt?: Date | null
76
76
  }
77
77
 
78
+ @Entity({ tableName: 'gateway_session_initializations' })
79
+ @Unique({
80
+ name: 'gateway_session_initializations_scope_operation_unique',
81
+ properties: ['operationKey', 'providerKey', 'organizationId', 'tenantId'],
82
+ })
83
+ export class GatewaySessionInitialization {
84
+ [OptionalProps]?: 'claimToken' | 'claimedAt' | 'gatewayTransactionId' | 'createdAt' | 'updatedAt'
85
+
86
+ @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
87
+ id!: string
88
+
89
+ @Property({ name: 'operation_key', type: 'text' })
90
+ operationKey!: string
91
+
92
+ @Property({ name: 'provider_key', type: 'text' })
93
+ providerKey!: string
94
+
95
+ @Property({ name: 'claim_token', type: 'uuid', nullable: true })
96
+ claimToken?: string | null
97
+
98
+ @Property({ name: 'claimed_at', type: Date, nullable: true })
99
+ claimedAt?: Date | null
100
+
101
+ @Property({ name: 'gateway_transaction_id', type: 'uuid', nullable: true })
102
+ gatewayTransactionId?: string | null
103
+
104
+ @Property({ name: 'organization_id', type: 'uuid' })
105
+ organizationId!: string
106
+
107
+ @Property({ name: 'tenant_id', type: 'uuid' })
108
+ tenantId!: string
109
+
110
+ @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
111
+ createdAt: Date = new Date()
112
+
113
+ @Property({ name: 'updated_at', type: Date, onCreate: () => new Date(), onUpdate: () => new Date() })
114
+ updatedAt: Date = new Date()
115
+ }
116
+
78
117
  @Entity({ tableName: 'gateway_webhook_events' })
79
118
  @Unique({
80
119
  name: 'gateway_webhook_events_idempotency_unique',
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from 'node:crypto'
1
2
  import type { EntityManager } from '@mikro-orm/postgresql'
2
3
  import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
3
4
  import {
@@ -15,10 +16,21 @@ import type { CredentialsService } from '../../integrations/lib/credentials-serv
15
16
  import type { IntegrationStateService } from '../../integrations/lib/state-service'
16
17
  import type { IntegrationLogService } from '../../integrations/lib/log-service'
17
18
  import { conflict } from '@open-mercato/shared/lib/crud/errors'
18
- import { GatewayTransaction } from '../data/entities'
19
+ import { GatewaySessionInitialization, GatewayTransaction } from '../data/entities'
19
20
  import { canApplyManualAction, isValidTransition, type ManualGatewayAction } from './status-machine'
20
21
  import { emitPaymentGatewayEvent } from '../events'
21
22
  import { readGatewayMetadata, readWebhookLog } from './transaction-fields'
23
+ import {
24
+ buildPaymentSessionOperationKey,
25
+ claimPaymentSessionInitialization,
26
+ findPaymentSessionInitialization,
27
+ reclaimPaymentSessionInitialization,
28
+ refreshPaymentSessionInitialization,
29
+ releasePaymentSessionInitialization,
30
+ } from './session-idempotency'
31
+
32
+ const PAYMENT_SESSION_CLAIM_STALE_MS = 30_000
33
+ const PAYMENT_SESSION_WAIT_INTERVAL_MS = 25
22
34
 
23
35
  function assertManualActionAllowed(action: ManualGatewayAction, transaction: GatewayTransaction): void {
24
36
  const current = transaction.unifiedStatus as UnifiedPaymentStatus
@@ -48,11 +60,17 @@ export interface PaymentGatewayServiceDeps {
48
60
  integrationCredentialsService: CredentialsService
49
61
  integrationStateService?: IntegrationStateService
50
62
  integrationLogService?: IntegrationLogService
63
+ sessionClaimOptions?: {
64
+ staleAfterMs?: number
65
+ heartbeatIntervalMs?: number
66
+ pollIntervalMs?: number
67
+ }
51
68
  }
52
69
 
53
70
  export interface CreatePaymentSessionInput {
54
71
  providerKey: string
55
72
  paymentId: string
73
+ idempotencyKey?: string
56
74
  orderId?: string
57
75
  amount: number
58
76
  currencyCode: string
@@ -69,6 +87,12 @@ export interface CreatePaymentSessionInput {
69
87
 
70
88
  export function createPaymentGatewayService(deps: PaymentGatewayServiceDeps) {
71
89
  const { em, integrationCredentialsService, integrationLogService } = deps
90
+ const claimStaleAfterMs = Math.max(1, deps.sessionClaimOptions?.staleAfterMs ?? PAYMENT_SESSION_CLAIM_STALE_MS)
91
+ const claimHeartbeatIntervalMs = Math.max(
92
+ 1,
93
+ deps.sessionClaimOptions?.heartbeatIntervalMs ?? Math.floor(claimStaleAfterMs / 3),
94
+ )
95
+ const claimPollIntervalMs = Math.max(1, deps.sessionClaimOptions?.pollIntervalMs ?? PAYMENT_SESSION_WAIT_INTERVAL_MS)
72
96
 
73
97
  async function findTransactionOrThrow(
74
98
  transactionId: string,
@@ -152,6 +176,109 @@ export function createPaymentGatewayService(deps: PaymentGatewayServiceDeps) {
152
176
  return { adapter, credentials }
153
177
  }
154
178
 
179
+ function createGatewayTransaction(
180
+ manager: EntityManager,
181
+ input: CreatePaymentSessionInput,
182
+ session: CreateSessionResult,
183
+ id?: string,
184
+ ): GatewayTransaction {
185
+ const data = {
186
+ paymentId: input.paymentId,
187
+ providerKey: input.providerKey,
188
+ providerSessionId: session.sessionId,
189
+ unifiedStatus: session.status,
190
+ redirectUrl: session.redirectUrl
191
+ ?? (session.clientSession?.type === 'redirect' ? session.clientSession.redirectUrl : null),
192
+ clientSecret: session.clientSecret ?? null,
193
+ amount: String(input.amount),
194
+ currencyCode: input.currencyCode,
195
+ gatewayMetadata: {
196
+ ...(session.providerData ?? {}),
197
+ ...(session.clientSession ? { clientSession: session.clientSession } : {}),
198
+ },
199
+ organizationId: input.organizationId,
200
+ tenantId: input.tenantId,
201
+ deletedAt: null,
202
+ }
203
+ return id
204
+ ? manager.create(GatewayTransaction, { id, ...data })
205
+ : manager.create(GatewayTransaction, data)
206
+ }
207
+
208
+ function restoreSession(transaction: GatewayTransaction): CreateSessionResult {
209
+ const metadata = readGatewayMetadata(transaction.gatewayMetadata)
210
+ const { clientSession, ...providerData } = metadata
211
+ return {
212
+ sessionId: readProviderSessionId(transaction),
213
+ status: transaction.unifiedStatus as UnifiedPaymentStatus,
214
+ ...(transaction.clientSecret ? { clientSecret: transaction.clientSecret } : {}),
215
+ ...(transaction.redirectUrl ? { redirectUrl: transaction.redirectUrl } : {}),
216
+ ...(Object.keys(providerData).length > 0 ? { providerData } : {}),
217
+ ...(clientSession && typeof clientSession === 'object'
218
+ ? { clientSession: clientSession as CreateSessionResult['clientSession'] }
219
+ : {}),
220
+ }
221
+ }
222
+
223
+ async function recordCreatedSession(
224
+ transaction: GatewayTransaction,
225
+ input: CreatePaymentSessionInput,
226
+ scope: { organizationId: string; tenantId: string },
227
+ ): Promise<void> {
228
+ await emitPaymentGatewayEvent('payment_gateways.session.created', {
229
+ transactionId: transaction.id,
230
+ paymentId: transaction.paymentId,
231
+ providerKey: transaction.providerKey,
232
+ status: transaction.unifiedStatus,
233
+ organizationId: transaction.organizationId,
234
+ tenantId: transaction.tenantId,
235
+ })
236
+ await writeTransactionLog(
237
+ transaction.providerKey,
238
+ scope,
239
+ transaction.id,
240
+ 'info',
241
+ 'Payment session created',
242
+ {
243
+ paymentId: transaction.paymentId,
244
+ providerSessionId: transaction.providerSessionId,
245
+ status: transaction.unifiedStatus,
246
+ amount: input.amount,
247
+ currencyCode: input.currencyCode,
248
+ },
249
+ )
250
+ }
251
+
252
+ function startClaimHeartbeat(
253
+ ownership: { id: string; claimToken: string },
254
+ scope: { organizationId: string; tenantId: string },
255
+ ): () => Promise<void> {
256
+ let stopped = false
257
+ let timer: ReturnType<typeof setTimeout> | null = null
258
+ let pendingRefresh = Promise.resolve()
259
+
260
+ const schedule = () => {
261
+ timer = setTimeout(() => {
262
+ pendingRefresh = refreshPaymentSessionInitialization(em, ownership, scope, new Date())
263
+ .then(
264
+ (refreshed) => {
265
+ if (refreshed && !stopped) schedule()
266
+ },
267
+ () => {
268
+ if (!stopped) schedule()
269
+ },
270
+ )
271
+ }, claimHeartbeatIntervalMs)
272
+ }
273
+ schedule()
274
+
275
+ return async () => {
276
+ stopped = true
277
+ if (timer) clearTimeout(timer)
278
+ await pendingRefresh
279
+ }
280
+ }
281
+
155
282
  return {
156
283
  async createPaymentSession(input: CreatePaymentSessionInput): Promise<{ transaction: GatewayTransaction; session: CreateSessionResult }> {
157
284
  const scope = { organizationId: input.organizationId, tenantId: input.tenantId }
@@ -160,6 +287,7 @@ export function createPaymentGatewayService(deps: PaymentGatewayServiceDeps) {
160
287
  const sessionInput: CreateSessionInput = {
161
288
  paymentId: input.paymentId,
162
289
  orderId: input.orderId,
290
+ idempotencyKey: input.idempotencyKey,
163
291
  tenantId: input.tenantId,
164
292
  organizationId: input.organizationId,
165
293
  amount: input.amount,
@@ -174,50 +302,93 @@ export function createPaymentGatewayService(deps: PaymentGatewayServiceDeps) {
174
302
  credentials,
175
303
  }
176
304
 
177
- const session = await adapter.createSession(sessionInput)
305
+ if (!input.idempotencyKey) {
306
+ const session = await adapter.createSession(sessionInput)
307
+ const transaction = createGatewayTransaction(em, input, session)
308
+ await em.persist(transaction).flush()
309
+ await recordCreatedSession(transaction, input, scope)
310
+ return { transaction, session }
311
+ }
178
312
 
179
- const transaction = em.create(GatewayTransaction, {
313
+ const operationKey = buildPaymentSessionOperationKey({
314
+ idempotencyKey: input.idempotencyKey,
180
315
  paymentId: input.paymentId,
181
316
  providerKey: input.providerKey,
182
- providerSessionId: session.sessionId,
183
- unifiedStatus: session.status,
184
- redirectUrl: session.redirectUrl
185
- ?? (session.clientSession?.type === 'redirect' ? session.clientSession.redirectUrl : null),
186
- clientSecret: session.clientSecret ?? null,
187
- amount: String(input.amount),
188
- currencyCode: input.currencyCode,
189
- gatewayMetadata: {
190
- ...(session.providerData ?? {}),
191
- ...(session.clientSession ? { clientSession: session.clientSession } : {}),
192
- },
193
- organizationId: input.organizationId,
194
- tenantId: input.tenantId,
195
- })
196
- await em.persist(transaction).flush()
197
- await emitPaymentGatewayEvent('payment_gateways.session.created', {
198
- transactionId: transaction.id,
199
- paymentId: transaction.paymentId,
200
- providerKey: transaction.providerKey,
201
- status: transaction.unifiedStatus,
202
- organizationId: transaction.organizationId,
203
- tenantId: transaction.tenantId,
204
- })
205
- await writeTransactionLog(
206
- transaction.providerKey,
207
317
  scope,
208
- transaction.id,
209
- 'info',
210
- 'Payment session created',
211
- {
212
- paymentId: transaction.paymentId,
213
- providerSessionId: transaction.providerSessionId,
214
- status: transaction.unifiedStatus,
215
- amount: input.amount,
216
- currencyCode: input.currencyCode,
217
- },
218
- )
318
+ })
319
+ while (true) {
320
+ const existing = await findPaymentSessionInitialization(em, operationKey, input.providerKey, scope)
321
+ if (existing?.gatewayTransactionId) {
322
+ const transaction = await findOneWithDecryption(
323
+ em.fork(),
324
+ GatewayTransaction,
325
+ {
326
+ id: existing.gatewayTransactionId,
327
+ organizationId: scope.organizationId,
328
+ tenantId: scope.tenantId,
329
+ deletedAt: null,
330
+ },
331
+ undefined,
332
+ scope,
333
+ )
334
+ if (!transaction) {
335
+ throw new Error('Completed payment session is missing its gateway transaction')
336
+ }
337
+ return { transaction, session: restoreSession(transaction) }
338
+ }
339
+
340
+ const claimedAt = new Date()
341
+ const staleBefore = new Date(claimedAt.getTime() - claimStaleAfterMs)
342
+ const ownership = existing
343
+ ? await reclaimPaymentSessionInitialization(em, existing, scope, claimedAt, staleBefore)
344
+ : await claimPaymentSessionInitialization(em, operationKey, input.providerKey, scope, claimedAt)
345
+
346
+ if (!ownership) {
347
+ await new Promise((resolve) => setTimeout(resolve, claimPollIntervalMs))
348
+ continue
349
+ }
350
+
351
+ let session: CreateSessionResult
352
+ const stopHeartbeat = startClaimHeartbeat(ownership, scope)
353
+ try {
354
+ session = await adapter.createSession({ ...sessionInput, idempotencyKey: operationKey })
355
+ } catch (error) {
356
+ await releasePaymentSessionInitialization(em, ownership, scope).catch(() => undefined)
357
+ throw error
358
+ } finally {
359
+ await stopHeartbeat()
360
+ }
361
+
362
+ const transactionId = randomUUID()
363
+ const transaction = await em.fork().transactional(async (transactionEm) => {
364
+ const finalizedRows = await transactionEm.nativeUpdate(
365
+ GatewaySessionInitialization,
366
+ {
367
+ id: ownership.id,
368
+ claimToken: ownership.claimToken,
369
+ gatewayTransactionId: null,
370
+ organizationId: scope.organizationId,
371
+ tenantId: scope.tenantId,
372
+ },
373
+ {
374
+ gatewayTransactionId: transactionId,
375
+ claimToken: null,
376
+ claimedAt: null,
377
+ updatedAt: new Date(),
378
+ },
379
+ )
380
+ if (finalizedRows === 0) return null
381
+ const created = createGatewayTransaction(transactionEm, input, session, transactionId)
382
+ await transactionEm.persist(created).flush()
383
+ return created
384
+ })
219
385
 
220
- return { transaction, session }
386
+ if (!transaction) {
387
+ continue
388
+ }
389
+ await recordCreatedSession(transaction, input, scope)
390
+ return { transaction, session }
391
+ }
221
392
  },
222
393
 
223
394
  async capturePayment(transactionId: string, amount: number | undefined, scope: { organizationId: string; tenantId: string }): Promise<CaptureResult> {
@@ -0,0 +1,142 @@
1
+ import { createHash, randomUUID } from 'node:crypto'
2
+ import { UniqueConstraintViolationException } from '@mikro-orm/core'
3
+ import type { EntityManager } from '@mikro-orm/postgresql'
4
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
5
+ import { GatewaySessionInitialization } from '../data/entities'
6
+
7
+ type Scope = { organizationId: string; tenantId: string }
8
+
9
+ export type OwnedPaymentSessionInitialization = {
10
+ id: string
11
+ claimToken: string
12
+ }
13
+
14
+ export function buildPaymentSessionOperationKey(input: {
15
+ idempotencyKey: string
16
+ paymentId: string
17
+ providerKey: string
18
+ scope: Scope
19
+ }): string {
20
+ const digest = createHash('sha256')
21
+ .update(JSON.stringify([
22
+ input.scope.tenantId,
23
+ input.scope.organizationId,
24
+ input.providerKey,
25
+ input.paymentId,
26
+ input.idempotencyKey,
27
+ ]))
28
+ .digest('hex')
29
+ return `om-payment-session:${digest}`
30
+ }
31
+
32
+ export async function findPaymentSessionInitialization(
33
+ em: EntityManager,
34
+ operationKey: string,
35
+ providerKey: string,
36
+ scope: Scope,
37
+ ): Promise<GatewaySessionInitialization | null> {
38
+ return findOneWithDecryption(
39
+ em.fork(),
40
+ GatewaySessionInitialization,
41
+ {
42
+ operationKey,
43
+ providerKey,
44
+ organizationId: scope.organizationId,
45
+ tenantId: scope.tenantId,
46
+ },
47
+ undefined,
48
+ scope,
49
+ )
50
+ }
51
+
52
+ export async function claimPaymentSessionInitialization(
53
+ em: EntityManager,
54
+ operationKey: string,
55
+ providerKey: string,
56
+ scope: Scope,
57
+ claimedAt: Date,
58
+ ): Promise<OwnedPaymentSessionInitialization | null> {
59
+ const claimEm = em.fork()
60
+ const claimToken = randomUUID()
61
+ const record = claimEm.create(GatewaySessionInitialization, {
62
+ operationKey,
63
+ providerKey,
64
+ claimToken,
65
+ claimedAt,
66
+ gatewayTransactionId: null,
67
+ organizationId: scope.organizationId,
68
+ tenantId: scope.tenantId,
69
+ })
70
+ try {
71
+ await claimEm.persist(record).flush()
72
+ return { id: record.id, claimToken }
73
+ } catch (error: unknown) {
74
+ if (error instanceof UniqueConstraintViolationException) return null
75
+ throw error
76
+ }
77
+ }
78
+
79
+ export async function reclaimPaymentSessionInitialization(
80
+ em: EntityManager,
81
+ claim: GatewaySessionInitialization,
82
+ scope: Scope,
83
+ claimedAt: Date,
84
+ staleBefore: Date,
85
+ ): Promise<OwnedPaymentSessionInitialization | null> {
86
+ const claimToken = randomUUID()
87
+ const claimedRows = await em.fork().nativeUpdate(
88
+ GatewaySessionInitialization,
89
+ {
90
+ id: claim.id,
91
+ operationKey: claim.operationKey,
92
+ providerKey: claim.providerKey,
93
+ organizationId: scope.organizationId,
94
+ tenantId: scope.tenantId,
95
+ gatewayTransactionId: null,
96
+ $or: [
97
+ { claimToken: null },
98
+ { claimedAt: { $lt: staleBefore } },
99
+ ],
100
+ },
101
+ { claimToken, claimedAt, updatedAt: claimedAt },
102
+ )
103
+ return claimedRows > 0 ? { id: claim.id, claimToken } : null
104
+ }
105
+
106
+ export async function releasePaymentSessionInitialization(
107
+ em: EntityManager,
108
+ ownership: OwnedPaymentSessionInitialization,
109
+ scope: Scope,
110
+ ): Promise<void> {
111
+ await em.fork().nativeUpdate(
112
+ GatewaySessionInitialization,
113
+ {
114
+ id: ownership.id,
115
+ claimToken: ownership.claimToken,
116
+ organizationId: scope.organizationId,
117
+ tenantId: scope.tenantId,
118
+ gatewayTransactionId: null,
119
+ },
120
+ { claimToken: null, claimedAt: null, updatedAt: new Date() },
121
+ )
122
+ }
123
+
124
+ export async function refreshPaymentSessionInitialization(
125
+ em: EntityManager,
126
+ ownership: OwnedPaymentSessionInitialization,
127
+ scope: Scope,
128
+ claimedAt: Date,
129
+ ): Promise<boolean> {
130
+ const refreshedRows = await em.fork().nativeUpdate(
131
+ GatewaySessionInitialization,
132
+ {
133
+ id: ownership.id,
134
+ claimToken: ownership.claimToken,
135
+ organizationId: scope.organizationId,
136
+ tenantId: scope.tenantId,
137
+ gatewayTransactionId: null,
138
+ },
139
+ { claimedAt, updatedAt: claimedAt },
140
+ )
141
+ return refreshedRows > 0
142
+ }