@openora/core 0.4.1-canary.151 → 0.4.1-canary.153

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 (243) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/admin-console/__tests__/backoffice.service.int.test.js +20 -3
  3. package/dist/admin-console/__tests__/backoffice.service.int.test.js.map +1 -1
  4. package/dist/admin-console/plugin.d.ts +2 -1
  5. package/dist/admin-console/plugin.d.ts.map +1 -1
  6. package/dist/analytics/plugin.d.ts +2 -1
  7. package/dist/analytics/plugin.d.ts.map +1 -1
  8. package/dist/audit/__tests__/map-event.test.js +46 -0
  9. package/dist/audit/__tests__/map-event.test.js.map +1 -1
  10. package/dist/audit/plugin.d.ts +2 -1
  11. package/dist/audit/plugin.d.ts.map +1 -1
  12. package/dist/audit/plugin.js +88 -0
  13. package/dist/audit/plugin.js.map +1 -1
  14. package/dist/audit/service/audit.service.d.ts.map +1 -1
  15. package/dist/audit/service/audit.service.js +1 -6
  16. package/dist/audit/service/audit.service.js.map +1 -1
  17. package/dist/casino/gaming/__tests__/admin-reporting.int.test.js +20 -3
  18. package/dist/casino/gaming/__tests__/admin-reporting.int.test.js.map +1 -1
  19. package/dist/casino/gaming/__tests__/game-category.service.int.test.d.ts +2 -0
  20. package/dist/casino/gaming/__tests__/game-category.service.int.test.d.ts.map +1 -0
  21. package/dist/casino/gaming/__tests__/game-category.service.int.test.js +134 -0
  22. package/dist/casino/gaming/__tests__/game-category.service.int.test.js.map +1 -0
  23. package/dist/casino/gaming/__tests__/game-provider.service.int.test.d.ts +2 -0
  24. package/dist/casino/gaming/__tests__/game-provider.service.int.test.d.ts.map +1 -0
  25. package/dist/casino/gaming/__tests__/game-provider.service.int.test.js +274 -0
  26. package/dist/casino/gaming/__tests__/game-provider.service.int.test.js.map +1 -0
  27. package/dist/casino/gaming/__tests__/gaming-catalog-admin.router.int.test.d.ts +2 -0
  28. package/dist/casino/gaming/__tests__/gaming-catalog-admin.router.int.test.d.ts.map +1 -0
  29. package/dist/casino/gaming/__tests__/gaming-catalog-admin.router.int.test.js +174 -0
  30. package/dist/casino/gaming/__tests__/gaming-catalog-admin.router.int.test.js.map +1 -0
  31. package/dist/casino/gaming/__tests__/gaming-migration.int.test.d.ts +2 -0
  32. package/dist/casino/gaming/__tests__/gaming-migration.int.test.d.ts.map +1 -0
  33. package/dist/casino/gaming/__tests__/gaming-migration.int.test.js +171 -0
  34. package/dist/casino/gaming/__tests__/gaming-migration.int.test.js.map +1 -0
  35. package/dist/casino/gaming/__tests__/gaming.service.int.test.js +274 -13
  36. package/dist/casino/gaming/__tests__/gaming.service.int.test.js.map +1 -1
  37. package/dist/casino/gaming/contract/index.d.ts +520 -18
  38. package/dist/casino/gaming/contract/index.d.ts.map +1 -1
  39. package/dist/casino/gaming/contract/index.js +167 -4
  40. package/dist/casino/gaming/contract/index.js.map +1 -1
  41. package/dist/casino/gaming/drizzle/migrations/0005_natural_thunderbolt_ross.sql +223 -0
  42. package/dist/casino/gaming/drizzle/migrations/meta/0005_snapshot.json +680 -0
  43. package/dist/casino/gaming/drizzle/migrations/meta/_journal.json +7 -0
  44. package/dist/casino/gaming/plugin.d.ts +2 -1
  45. package/dist/casino/gaming/plugin.d.ts.map +1 -1
  46. package/dist/casino/gaming/plugin.js +9 -2
  47. package/dist/casino/gaming/plugin.js.map +1 -1
  48. package/dist/casino/gaming/router/index.d.ts +372 -18
  49. package/dist/casino/gaming/router/index.d.ts.map +1 -1
  50. package/dist/casino/gaming/router/index.js +62 -6
  51. package/dist/casino/gaming/router/index.js.map +1 -1
  52. package/dist/casino/gaming/schema/index.d.ts +499 -4
  53. package/dist/casino/gaming/schema/index.d.ts.map +1 -1
  54. package/dist/casino/gaming/schema/index.js +72 -6
  55. package/dist/casino/gaming/schema/index.js.map +1 -1
  56. package/dist/casino/gaming/service/game-category.service.d.ts +109 -0
  57. package/dist/casino/gaming/service/game-category.service.d.ts.map +1 -0
  58. package/dist/casino/gaming/service/game-category.service.js +176 -0
  59. package/dist/casino/gaming/service/game-category.service.js.map +1 -0
  60. package/dist/casino/gaming/service/game-provider.service.d.ts +118 -0
  61. package/dist/casino/gaming/service/game-provider.service.d.ts.map +1 -0
  62. package/dist/casino/gaming/service/game-provider.service.js +251 -0
  63. package/dist/casino/gaming/service/game-provider.service.js.map +1 -0
  64. package/dist/casino/gaming/service/gaming.service.d.ts +122 -14
  65. package/dist/casino/gaming/service/gaming.service.d.ts.map +1 -1
  66. package/dist/casino/gaming/service/gaming.service.js +189 -23
  67. package/dist/casino/gaming/service/gaming.service.js.map +1 -1
  68. package/dist/casino/lobby/__tests__/lobby.cache.int.test.js +137 -4
  69. package/dist/casino/lobby/__tests__/lobby.cache.int.test.js.map +1 -1
  70. package/dist/casino/lobby/contract/index.d.ts +68 -8
  71. package/dist/casino/lobby/contract/index.d.ts.map +1 -1
  72. package/dist/casino/lobby/contract/index.js +4 -3
  73. package/dist/casino/lobby/contract/index.js.map +1 -1
  74. package/dist/casino/lobby/plugin.d.ts +2 -1
  75. package/dist/casino/lobby/plugin.d.ts.map +1 -1
  76. package/dist/casino/lobby/router/index.d.ts +34 -4
  77. package/dist/casino/lobby/router/index.d.ts.map +1 -1
  78. package/dist/casino/lobby/service/lobby.service.d.ts +34 -4
  79. package/dist/casino/lobby/service/lobby.service.d.ts.map +1 -1
  80. package/dist/casino/lobby/service/lobby.service.js +60 -26
  81. package/dist/casino/lobby/service/lobby.service.js.map +1 -1
  82. package/dist/casino/shared/game-catalog.d.ts +32 -0
  83. package/dist/casino/shared/game-catalog.d.ts.map +1 -0
  84. package/dist/casino/shared/game-catalog.js +67 -0
  85. package/dist/casino/shared/game-catalog.js.map +1 -0
  86. package/dist/cms/plugin.d.ts +2 -1
  87. package/dist/cms/plugin.d.ts.map +1 -1
  88. package/dist/compliance/__tests__/rg-monitoring.service.int.test.js +17 -3
  89. package/dist/compliance/__tests__/rg-monitoring.service.int.test.js.map +1 -1
  90. package/dist/compliance/__tests__/rg-self-service.int.test.js +2 -2
  91. package/dist/compliance/__tests__/rg-self-service.int.test.js.map +1 -1
  92. package/dist/compliance/plugin.d.ts +2 -1
  93. package/dist/compliance/plugin.d.ts.map +1 -1
  94. package/dist/contracts/__tests__/kit.test.js +21 -1
  95. package/dist/contracts/__tests__/kit.test.js.map +1 -1
  96. package/dist/contracts/adapters/email-template.d.ts +1 -1
  97. package/dist/contracts/adapters/email-template.d.ts.map +1 -1
  98. package/dist/contracts/adapters/email-template.js.map +1 -1
  99. package/dist/contracts/adapters/index.d.ts +2 -0
  100. package/dist/contracts/adapters/index.d.ts.map +1 -1
  101. package/dist/contracts/adapters/index.js +1 -0
  102. package/dist/contracts/adapters/index.js.map +1 -1
  103. package/dist/contracts/adapters/mail-recipient-directory.d.ts +17 -0
  104. package/dist/contracts/adapters/mail-recipient-directory.d.ts.map +1 -0
  105. package/dist/contracts/adapters/mail-recipient-directory.js +3 -0
  106. package/dist/contracts/adapters/mail-recipient-directory.js.map +1 -0
  107. package/dist/contracts/adapters/rate-limit.d.ts +1 -0
  108. package/dist/contracts/adapters/rate-limit.d.ts.map +1 -1
  109. package/dist/contracts/adapters/rate-limit.js +1 -0
  110. package/dist/contracts/adapters/rate-limit.js.map +1 -1
  111. package/dist/contracts/kit.d.ts +3 -0
  112. package/dist/contracts/kit.d.ts.map +1 -1
  113. package/dist/contracts/kit.js +8 -0
  114. package/dist/contracts/kit.js.map +1 -1
  115. package/dist/contracts/schemas/__tests__/events.test.js +7 -0
  116. package/dist/contracts/schemas/__tests__/events.test.js.map +1 -1
  117. package/dist/contracts/schemas/__tests__/game-schemas.test.d.ts +2 -0
  118. package/dist/contracts/schemas/__tests__/game-schemas.test.d.ts.map +1 -0
  119. package/dist/contracts/schemas/__tests__/game-schemas.test.js +43 -0
  120. package/dist/contracts/schemas/__tests__/game-schemas.test.js.map +1 -0
  121. package/dist/contracts/schemas/events.d.ts +116 -0
  122. package/dist/contracts/schemas/events.d.ts.map +1 -1
  123. package/dist/contracts/schemas/events.js +93 -0
  124. package/dist/contracts/schemas/events.js.map +1 -1
  125. package/dist/contracts/schemas/game.d.ts +39 -0
  126. package/dist/contracts/schemas/game.d.ts.map +1 -1
  127. package/dist/contracts/schemas/game.js +32 -0
  128. package/dist/contracts/schemas/game.js.map +1 -1
  129. package/dist/contracts/schemas/iam.d.ts +1 -1
  130. package/dist/contracts/schemas/iam.js +1 -1
  131. package/dist/contracts/schemas/iam.js.map +1 -1
  132. package/dist/contracts/schemas/identity.d.ts +5 -0
  133. package/dist/contracts/schemas/identity.d.ts.map +1 -1
  134. package/dist/contracts/schemas/identity.js +7 -0
  135. package/dist/contracts/schemas/identity.js.map +1 -1
  136. package/dist/contracts/schemas/mail.d.ts +9 -1
  137. package/dist/contracts/schemas/mail.d.ts.map +1 -1
  138. package/dist/contracts/schemas/mail.js +3 -0
  139. package/dist/contracts/schemas/mail.js.map +1 -1
  140. package/dist/engagement/chat/plugin.d.ts +2 -1
  141. package/dist/engagement/chat/plugin.d.ts.map +1 -1
  142. package/dist/engagement/chat-commands/plugin.d.ts +2 -1
  143. package/dist/engagement/chat-commands/plugin.d.ts.map +1 -1
  144. package/dist/engagement/notifications/plugin.d.ts +2 -1
  145. package/dist/engagement/notifications/plugin.d.ts.map +1 -1
  146. package/dist/engagement/social/plugin.d.ts +2 -1
  147. package/dist/engagement/social/plugin.d.ts.map +1 -1
  148. package/dist/fx/exchange-rate/plugin.d.ts +2 -1
  149. package/dist/fx/exchange-rate/plugin.d.ts.map +1 -1
  150. package/dist/iam/plugin.d.ts +2 -1
  151. package/dist/iam/plugin.d.ts.map +1 -1
  152. package/dist/mail/__tests__/default-email-template-renderer.test.js +12 -0
  153. package/dist/mail/__tests__/default-email-template-renderer.test.js.map +1 -1
  154. package/dist/mail/__tests__/mail.service.test.js +45 -12
  155. package/dist/mail/__tests__/mail.service.test.js.map +1 -1
  156. package/dist/mail/adapters/default-email-template-renderer.d.ts +1 -1
  157. package/dist/mail/adapters/default-email-template-renderer.d.ts.map +1 -1
  158. package/dist/mail/adapters/default-email-template-renderer.js +11 -4
  159. package/dist/mail/adapters/default-email-template-renderer.js.map +1 -1
  160. package/dist/mail/contract/index.d.ts +5 -0
  161. package/dist/mail/contract/index.d.ts.map +1 -1
  162. package/dist/mail/plugin.d.ts +2 -1
  163. package/dist/mail/plugin.d.ts.map +1 -1
  164. package/dist/mail/plugin.js +2 -2
  165. package/dist/mail/plugin.js.map +1 -1
  166. package/dist/mail/service/mail.service.d.ts +2 -2
  167. package/dist/mail/service/mail.service.d.ts.map +1 -1
  168. package/dist/mail/service/mail.service.js +12 -4
  169. package/dist/mail/service/mail.service.js.map +1 -1
  170. package/dist/pam/identity/__tests__/identity.service.int.test.js +81 -0
  171. package/dist/pam/identity/__tests__/identity.service.int.test.js.map +1 -1
  172. package/dist/pam/identity/admin-user-directory.d.ts +11 -1
  173. package/dist/pam/identity/admin-user-directory.d.ts.map +1 -1
  174. package/dist/pam/identity/admin-user-directory.js +19 -0
  175. package/dist/pam/identity/admin-user-directory.js.map +1 -1
  176. package/dist/pam/identity/contract/index.d.ts +17 -0
  177. package/dist/pam/identity/contract/index.d.ts.map +1 -1
  178. package/dist/pam/identity/contract/index.js +7 -1
  179. package/dist/pam/identity/contract/index.js.map +1 -1
  180. package/dist/pam/identity/drizzle/migrations/0014_spicy_mephistopheles.sql +1 -0
  181. package/dist/pam/identity/drizzle/migrations/meta/0014_snapshot.json +1096 -0
  182. package/dist/pam/identity/drizzle/migrations/meta/_journal.json +7 -0
  183. package/dist/pam/identity/plugin.d.ts +2 -1
  184. package/dist/pam/identity/plugin.d.ts.map +1 -1
  185. package/dist/pam/identity/plugin.js +3 -2
  186. package/dist/pam/identity/plugin.js.map +1 -1
  187. package/dist/pam/identity/react/account.d.ts +4 -1
  188. package/dist/pam/identity/react/account.d.ts.map +1 -1
  189. package/dist/pam/identity/react/account.js +8 -0
  190. package/dist/pam/identity/react/account.js.map +1 -1
  191. package/dist/pam/identity/router/index.d.ts +17 -0
  192. package/dist/pam/identity/router/index.d.ts.map +1 -1
  193. package/dist/pam/identity/router/index.js +1 -0
  194. package/dist/pam/identity/router/index.js.map +1 -1
  195. package/dist/pam/identity/schema/index.d.ts +17 -0
  196. package/dist/pam/identity/schema/index.d.ts.map +1 -1
  197. package/dist/pam/identity/schema/index.js +4 -0
  198. package/dist/pam/identity/schema/index.js.map +1 -1
  199. package/dist/pam/identity/service/identity.service.d.ts +9 -1
  200. package/dist/pam/identity/service/identity.service.d.ts.map +1 -1
  201. package/dist/pam/identity/service/identity.service.js +77 -0
  202. package/dist/pam/identity/service/identity.service.js.map +1 -1
  203. package/dist/pam/identity/service/security-controls.service.d.ts.map +1 -1
  204. package/dist/pam/identity/service/security-controls.service.js +1 -0
  205. package/dist/pam/identity/service/security-controls.service.js.map +1 -1
  206. package/dist/pam/player-management/plugin.d.ts +2 -1
  207. package/dist/pam/player-management/plugin.d.ts.map +1 -1
  208. package/dist/pam/player-note/plugin.d.ts +2 -1
  209. package/dist/pam/player-note/plugin.d.ts.map +1 -1
  210. package/dist/pam/profile/plugin.d.ts +2 -1
  211. package/dist/pam/profile/plugin.d.ts.map +1 -1
  212. package/dist/pam/react.d.ts +1 -1
  213. package/dist/pam/react.d.ts.map +1 -1
  214. package/dist/pam/react.js +1 -1
  215. package/dist/pam/react.js.map +1 -1
  216. package/dist/pam/tag/plugin.d.ts +2 -1
  217. package/dist/pam/tag/plugin.d.ts.map +1 -1
  218. package/dist/react/client.d.ts +2 -1
  219. package/dist/react/client.d.ts.map +1 -1
  220. package/dist/react/client.js +2 -1
  221. package/dist/react/client.js.map +1 -1
  222. package/dist/server/auth/permissions.d.ts +12 -12
  223. package/dist/server/auth/permissions.js +1 -1
  224. package/dist/server/auth/permissions.js.map +1 -1
  225. package/dist/server/db/__tests__/query-helpers.test.js +47 -1
  226. package/dist/server/db/__tests__/query-helpers.test.js.map +1 -1
  227. package/dist/server/db/index.d.ts +1 -1
  228. package/dist/server/db/index.d.ts.map +1 -1
  229. package/dist/server/db/index.js +1 -1
  230. package/dist/server/db/index.js.map +1 -1
  231. package/dist/server/db/query-helpers.d.ts +5 -0
  232. package/dist/server/db/query-helpers.d.ts.map +1 -1
  233. package/dist/server/db/query-helpers.js +37 -0
  234. package/dist/server/db/query-helpers.js.map +1 -1
  235. package/dist/server/runtime/core-token-catalog.d.ts +2 -1
  236. package/dist/server/runtime/core-token-catalog.d.ts.map +1 -1
  237. package/dist/server/runtime/core-token-catalog.js +2 -1
  238. package/dist/server/runtime/core-token-catalog.js.map +1 -1
  239. package/dist/testing/seed-player.d.ts +2 -0
  240. package/dist/testing/seed-player.d.ts.map +1 -1
  241. package/dist/wallet/plugin.d.ts +2 -1
  242. package/dist/wallet/plugin.d.ts.map +1 -1
  243. package/package.json +1 -1
@@ -0,0 +1,109 @@
1
+ import { type EventBus, DrizzleService } from '@openora/core/server';
2
+ import type { ClientMeta, User } from '@openora/core/contracts';
3
+ import type { CreateCategoryInput, UpdateCategoryInput } from '../contract/index.js';
4
+ export declare const GameCategoryNotFoundError: new (id: string) => Error & {
5
+ data?: Record<string, string>;
6
+ };
7
+ export declare const GameCategorySlugTakenError: new () => Error & {
8
+ data?: Record<string, string>;
9
+ };
10
+ type Actor = {
11
+ actorId: User['id'];
12
+ } & ClientMeta;
13
+ export declare class GameCategoryService {
14
+ private readonly drizzle;
15
+ private readonly events;
16
+ constructor(drizzle: DrizzleService, events: EventBus);
17
+ listActiveCategories({ page, limit }: {
18
+ page: number;
19
+ limit: number;
20
+ }): Promise<{
21
+ items: {
22
+ translations: Record<string, {
23
+ name: string;
24
+ }>;
25
+ id: string;
26
+ slug: string;
27
+ name: string;
28
+ icon: string | null;
29
+ sortOrder: number;
30
+ }[];
31
+ total: number;
32
+ page: number;
33
+ limit: number;
34
+ }>;
35
+ listCategoriesAdmin({ page, limit, q, isActive, }: {
36
+ page: number;
37
+ limit: number;
38
+ q?: string;
39
+ isActive?: boolean;
40
+ }): Promise<{
41
+ items: {
42
+ isActive: boolean;
43
+ createdAt: string;
44
+ updatedAt: string;
45
+ id: string;
46
+ slug: string;
47
+ name: string;
48
+ translations: Record<string, {
49
+ name: string;
50
+ }>;
51
+ icon: string | null;
52
+ sortOrder: number;
53
+ }[];
54
+ total: number;
55
+ page: number;
56
+ limit: number;
57
+ }>;
58
+ getCategory(id: string): Promise<{
59
+ isActive: boolean;
60
+ createdAt: string;
61
+ updatedAt: string;
62
+ id: string;
63
+ slug: string;
64
+ name: string;
65
+ translations: Record<string, {
66
+ name: string;
67
+ }>;
68
+ icon: string | null;
69
+ sortOrder: number;
70
+ }>;
71
+ getActiveCategoryBySlug(slug: string): Promise<{
72
+ id: string;
73
+ slug: string;
74
+ name: string;
75
+ translations: Record<string, {
76
+ name: string;
77
+ }>;
78
+ icon: string | null;
79
+ sortOrder: number;
80
+ }>;
81
+ createCategory({ slug, name, translations, icon, sortOrder, actorId, ip, userAgent, }: CreateCategoryInput & Actor): Promise<{
82
+ isActive: boolean;
83
+ createdAt: string;
84
+ updatedAt: string;
85
+ id: string;
86
+ slug: string;
87
+ name: string;
88
+ translations: Record<string, {
89
+ name: string;
90
+ }>;
91
+ icon: string | null;
92
+ sortOrder: number;
93
+ }>;
94
+ updateCategory({ id, actorId, ip, userAgent, ...patchInput }: UpdateCategoryInput & Actor): Promise<{
95
+ isActive: boolean;
96
+ createdAt: string;
97
+ updatedAt: string;
98
+ id: string;
99
+ slug: string;
100
+ name: string;
101
+ translations: Record<string, {
102
+ name: string;
103
+ }>;
104
+ icon: string | null;
105
+ sortOrder: number;
106
+ }>;
107
+ }
108
+ export {};
109
+ //# sourceMappingURL=game-category.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-category.service.d.ts","sourceRoot":"","sources":["../../../../src/casino/gaming/service/game-category.service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAGb,cAAc,EAMf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGrF,eAAO,MAAM,yBAAyB;QAPtC,CAAA;CAO0E,CAAC;AAC3E,eAAO,MAAM,0BAA0B;QARvC,CAAA;CAWC,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;CACrB,GAAG,UAAU,CAAC;AAuBf,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,QAAQ;IAG7B,oBAAoB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;IA2BrE,mBAAmB,CAAC,EACxB,IAAI,EACJ,KAAK,EACL,CAAC,EACD,QAAQ,GACT,EAAE;QACD,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,CAAC,CAAC,EAAE,MAAM,CAAC;QACX,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;;;;;;;;;;;;;;;;;;IAoBK,WAAW,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;IAQtB,uBAAuB,CAAC,IAAI,EAAE,MAAM;;;;;;;;;;IAYpC,cAAc,CAAC,EACnB,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,OAAO,EACP,EAAE,EACF,SAAS,GACV,EAAE,mBAAmB,GAAG,KAAK;;;;;;;;;;;;;IAwCxB,cAAc,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,EAAE,mBAAmB,GAAG,KAAK;;;;;;;;;;;;;CAsDhG"}
@@ -0,0 +1,176 @@
1
+ import { makeNotFoundError, makeConflictError, findOneOrThrow, isUniqueConstraintViolation, likeContains, serializeRow, pageToOffset, } from '@openora/core/server';
2
+ import { eq, and, asc, count, ilike, ne, or } from 'drizzle-orm';
3
+ import { gameCategory } from '../schema/index.js';
4
+ import { toCategorySummary } from '../../shared/game-catalog.js';
5
+ export const GameCategoryNotFoundError = makeNotFoundError('GameCategory');
6
+ export const GameCategorySlugTakenError = makeConflictError('GameCategorySlugTakenError', 'A category with this slug already exists');
7
+ function categorySnapshot(record) {
8
+ return {
9
+ slug: record.slug,
10
+ name: record.name,
11
+ translations: record.translations ?? {},
12
+ icon: record.icon,
13
+ sortOrder: record.sortOrder,
14
+ isActive: record.isActive,
15
+ };
16
+ }
17
+ function toCategoryDetail(record) {
18
+ const dates = serializeRow(record, { dateFields: ['createdAt', 'updatedAt'] });
19
+ return {
20
+ ...toCategorySummary(record),
21
+ isActive: record.isActive,
22
+ createdAt: dates.createdAt,
23
+ updatedAt: dates.updatedAt,
24
+ };
25
+ }
26
+ export class GameCategoryService {
27
+ drizzle;
28
+ events;
29
+ constructor(drizzle, events) {
30
+ this.drizzle = drizzle;
31
+ this.events = events;
32
+ }
33
+ async listActiveCategories({ page, limit }) {
34
+ const where = eq(gameCategory.isActive, true);
35
+ const [rows, [{ n }]] = await Promise.all([
36
+ this.drizzle.db
37
+ .select({
38
+ id: gameCategory.id,
39
+ slug: gameCategory.slug,
40
+ name: gameCategory.name,
41
+ translations: gameCategory.translations,
42
+ icon: gameCategory.icon,
43
+ sortOrder: gameCategory.sortOrder,
44
+ })
45
+ .from(gameCategory)
46
+ .where(where)
47
+ .orderBy(asc(gameCategory.sortOrder), asc(gameCategory.name), asc(gameCategory.slug))
48
+ .limit(limit)
49
+ .offset(pageToOffset(page, limit)),
50
+ this.drizzle.db.select({ n: count() }).from(gameCategory).where(where),
51
+ ]);
52
+ return {
53
+ items: rows.map((row) => ({ ...row, translations: row.translations ?? {} })),
54
+ total: Number(n),
55
+ page,
56
+ limit,
57
+ };
58
+ }
59
+ async listCategoriesAdmin({ page, limit, q, isActive, }) {
60
+ const where = and(q
61
+ ? or(ilike(gameCategory.name, likeContains(q)), ilike(gameCategory.slug, likeContains(q)))
62
+ : undefined, isActive === undefined ? undefined : eq(gameCategory.isActive, isActive));
63
+ const [rows, [{ n }]] = await Promise.all([
64
+ this.drizzle.db
65
+ .select()
66
+ .from(gameCategory)
67
+ .where(where)
68
+ .orderBy(asc(gameCategory.sortOrder), asc(gameCategory.name))
69
+ .limit(limit)
70
+ .offset(pageToOffset(page, limit)),
71
+ this.drizzle.db.select({ n: count() }).from(gameCategory).where(where),
72
+ ]);
73
+ return { items: rows.map(toCategoryDetail), total: Number(n), page, limit };
74
+ }
75
+ async getCategory(id) {
76
+ const record = findOneOrThrow(await this.drizzle.db.select().from(gameCategory).where(eq(gameCategory.id, id)).limit(1), new GameCategoryNotFoundError(id));
77
+ return toCategoryDetail(record);
78
+ }
79
+ async getActiveCategoryBySlug(slug) {
80
+ const record = findOneOrThrow(await this.drizzle.db
81
+ .select()
82
+ .from(gameCategory)
83
+ .where(and(eq(gameCategory.slug, slug), eq(gameCategory.isActive, true)))
84
+ .limit(1), new GameCategoryNotFoundError(slug));
85
+ return toCategorySummary(record);
86
+ }
87
+ async createCategory({ slug, name, translations, icon, sortOrder, actorId, ip, userAgent, }) {
88
+ let record;
89
+ try {
90
+ record = await this.drizzle.db.transaction(async (tx) => {
91
+ const [existing] = await tx
92
+ .select({ id: gameCategory.id })
93
+ .from(gameCategory)
94
+ .where(eq(gameCategory.slug, slug))
95
+ .limit(1);
96
+ if (existing) {
97
+ throw new GameCategorySlugTakenError();
98
+ }
99
+ const [created] = await tx
100
+ .insert(gameCategory)
101
+ .values({
102
+ slug,
103
+ name,
104
+ translations: translations ?? {},
105
+ icon: icon ?? null,
106
+ sortOrder: sortOrder ?? 0,
107
+ })
108
+ .returning();
109
+ return created;
110
+ });
111
+ }
112
+ catch (error) {
113
+ if (isUniqueConstraintViolation(error)) {
114
+ throw new GameCategorySlugTakenError();
115
+ }
116
+ throw error;
117
+ }
118
+ this.events.emit('gaming.category.created', {
119
+ categoryId: record.id,
120
+ ...categorySnapshot(record),
121
+ actorId,
122
+ ip: ip ?? null,
123
+ userAgent: userAgent ?? null,
124
+ });
125
+ return toCategoryDetail(record);
126
+ }
127
+ async updateCategory({ id, actorId, ip, userAgent, ...patchInput }) {
128
+ const patch = { ...patchInput };
129
+ const hasChanges = Object.values(patch).some((value) => value !== undefined);
130
+ const outcome = await this.drizzle.db
131
+ .transaction(async (tx) => {
132
+ // The row lock serializes concurrent PATCHes, so the audited `before` is the
133
+ // state this write replaced, never a snapshot another request already changed.
134
+ const existing = findOneOrThrow(await tx
135
+ .select()
136
+ .from(gameCategory)
137
+ .where(eq(gameCategory.id, id))
138
+ .limit(1)
139
+ .for('update'), new GameCategoryNotFoundError(id));
140
+ if (patchInput.slug !== undefined && patchInput.slug !== existing.slug) {
141
+ const [clash] = await tx
142
+ .select({ id: gameCategory.id })
143
+ .from(gameCategory)
144
+ .where(and(eq(gameCategory.slug, patchInput.slug), ne(gameCategory.id, id)))
145
+ .limit(1);
146
+ if (clash) {
147
+ throw new GameCategorySlugTakenError();
148
+ }
149
+ }
150
+ if (!hasChanges) {
151
+ return { changed: false, before: existing, after: existing };
152
+ }
153
+ const updated = findOneOrThrow(await tx.update(gameCategory).set(patch).where(eq(gameCategory.id, id)).returning(), new GameCategoryNotFoundError(id));
154
+ return { changed: true, before: existing, after: updated };
155
+ })
156
+ .catch((error) => {
157
+ if (isUniqueConstraintViolation(error)) {
158
+ throw new GameCategorySlugTakenError();
159
+ }
160
+ throw error;
161
+ });
162
+ if (!outcome.changed) {
163
+ return toCategoryDetail(outcome.after);
164
+ }
165
+ this.events.emit('gaming.category.updated', {
166
+ categoryId: id,
167
+ actorId,
168
+ before: categorySnapshot(outcome.before),
169
+ after: categorySnapshot(outcome.after),
170
+ ip: ip ?? null,
171
+ userAgent: userAgent ?? null,
172
+ });
173
+ return toCategoryDetail(outcome.after);
174
+ }
175
+ }
176
+ //# sourceMappingURL=game-category.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-category.service.js","sourceRoot":"","sources":["../../../../src/casino/gaming/service/game-category.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ import { type EventBus, DrizzleService } from '@openora/core/server';
2
+ import type { ClientMeta, User } from '@openora/core/contracts';
3
+ import { gameProvider } from '../schema/index.js';
4
+ import type { CreateProviderInput, UpdateProviderInput } from '../contract/index.js';
5
+ export declare const GameProviderNotFoundError: new (id: string) => Error & {
6
+ data?: Record<string, string>;
7
+ };
8
+ export declare const GameProviderSlugTakenError: new () => Error & {
9
+ data?: Record<string, string>;
10
+ };
11
+ export declare const GameProviderVendorIdTakenError: new () => Error & {
12
+ data?: Record<string, string>;
13
+ };
14
+ export declare const GameProviderMappingInUseError: new (providerId: string, aggregator: string) => Error & {
15
+ data?: Record<string, string>;
16
+ };
17
+ type Actor = {
18
+ actorId: User['id'];
19
+ } & ClientMeta;
20
+ export declare function toProviderSummary(record: typeof gameProvider.$inferSelect): {
21
+ id: string;
22
+ slug: string;
23
+ name: string;
24
+ logoUrl: string | null;
25
+ };
26
+ export declare class GameProviderService {
27
+ private readonly drizzle;
28
+ private readonly events;
29
+ constructor(drizzle: DrizzleService, events: EventBus);
30
+ listActiveProviders({ page, limit }: {
31
+ page: number;
32
+ limit: number;
33
+ }): Promise<{
34
+ items: {
35
+ id: string;
36
+ slug: string;
37
+ name: string;
38
+ logoUrl: string | null;
39
+ }[];
40
+ total: number;
41
+ page: number;
42
+ limit: number;
43
+ }>;
44
+ listProvidersAdmin({ page, limit, q, isActive, }: {
45
+ page: number;
46
+ limit: number;
47
+ q?: string;
48
+ isActive?: boolean;
49
+ }): Promise<{
50
+ items: {
51
+ aggregatorMappings: {
52
+ aggregator: string;
53
+ vendorId: string;
54
+ }[];
55
+ metadata: {} | null;
56
+ isActive: boolean;
57
+ createdAt: string;
58
+ updatedAt: string;
59
+ id: string;
60
+ slug: string;
61
+ name: string;
62
+ logoUrl: string | null;
63
+ }[];
64
+ total: number;
65
+ page: number;
66
+ limit: number;
67
+ }>;
68
+ getProvider(id: string): Promise<{
69
+ aggregatorMappings: {
70
+ aggregator: string;
71
+ vendorId: string;
72
+ }[];
73
+ metadata: {} | null;
74
+ isActive: boolean;
75
+ createdAt: string;
76
+ updatedAt: string;
77
+ id: string;
78
+ slug: string;
79
+ name: string;
80
+ logoUrl: string | null;
81
+ }>;
82
+ getActiveProviderBySlug(slug: string): Promise<{
83
+ id: string;
84
+ slug: string;
85
+ name: string;
86
+ logoUrl: string | null;
87
+ }>;
88
+ createProvider({ slug, name, aggregatorMappings, logoUrl, metadata, actorId, ip, userAgent, }: CreateProviderInput & Actor): Promise<{
89
+ aggregatorMappings: {
90
+ aggregator: string;
91
+ vendorId: string;
92
+ }[];
93
+ metadata: {} | null;
94
+ isActive: boolean;
95
+ createdAt: string;
96
+ updatedAt: string;
97
+ id: string;
98
+ slug: string;
99
+ name: string;
100
+ logoUrl: string | null;
101
+ }>;
102
+ updateProvider({ id, actorId, ip, userAgent, aggregatorMappings, ...patchInput }: UpdateProviderInput & Actor): Promise<{
103
+ aggregatorMappings: {
104
+ aggregator: string;
105
+ vendorId: string;
106
+ }[];
107
+ metadata: {} | null;
108
+ isActive: boolean;
109
+ createdAt: string;
110
+ updatedAt: string;
111
+ id: string;
112
+ slug: string;
113
+ name: string;
114
+ logoUrl: string | null;
115
+ }>;
116
+ }
117
+ export {};
118
+ //# sourceMappingURL=game-provider.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-provider.service.d.ts","sourceRoot":"","sources":["../../../../src/casino/gaming/service/game-provider.service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAIb,cAAc,EAMf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,UAAU,EAAiC,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC/F,OAAO,EAAQ,YAAY,EAAiC,MAAM,oBAAoB,CAAC;AACvF,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGrF,eAAO,MAAM,yBAAyB;QAR7B,CAAC;CAQgE,CAAC;AAC3E,eAAO,MAAM,0BAA0B;QAT9B,CAAC;CAYT,CAAC;AACF,eAAO,MAAM,8BAA8B;QAblC,CAAC;CAgBT,CAAC;AACF,eAAO,MAAM,6BAA6B;QAjBjC,CAAC;CAuBT,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;CACrB,GAAG,UAAU,CAAC;AAEf,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,YAAY,CAAC,YAAY;;;;;EAOzE;AAsCD,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,QAAQ;IAG7B,mBAAmB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;IAoBpE,kBAAkB,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,CAAC,EACD,QAAQ,GACT,EAAE;QACD,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,CAAC,CAAC,EAAE,MAAM,CAAC;QACX,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;;;;;;;;;;;;;;;;;;;IA6BK,WAAW,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;IAStB,uBAAuB,CAAC,IAAI,EAAE,MAAM;;;;;;IAYpC,cAAc,CAAC,EACnB,IAAI,EACJ,IAAI,EACJ,kBAAuB,EACvB,OAAO,EACP,QAAQ,EACR,OAAO,EACP,EAAE,EACF,SAAS,GACV,EAAE,mBAAmB,GAAG,KAAK;;;;;;;;;;;;;;IAsDxB,cAAc,CAAC,EACnB,EAAE,EACF,OAAO,EACP,EAAE,EACF,SAAS,EACT,kBAAkB,EAClB,GAAG,UAAU,EACd,EAAE,mBAAmB,GAAG,KAAK;;;;;;;;;;;;;;CA6G/B"}
@@ -0,0 +1,251 @@
1
+ import { createDomainError, makeNotFoundError, makeConflictError, findOneOrThrow, likeContains, serializeRow, pageToOffset, uniqueConstraintName, } from '@openora/core/server';
2
+ import { eq, and, asc, count, ilike, inArray, ne, or } from 'drizzle-orm';
3
+ import { game, gameProvider, gameProviderAggregatorMapping } from '../schema/index.js';
4
+ import { mappingsByProviderIds } from '../../shared/game-catalog.js';
5
+ export const GameProviderNotFoundError = makeNotFoundError('GameProvider');
6
+ export const GameProviderSlugTakenError = makeConflictError('GameProviderSlugTakenError', 'A provider with this slug already exists');
7
+ export const GameProviderVendorIdTakenError = makeConflictError('GameProviderVendorIdTakenError', 'A provider with this vendor ID already exists for the aggregator');
8
+ export const GameProviderMappingInUseError = createDomainError('GameProviderMappingInUseError', (providerId, aggregator) => `Provider ${providerId} still has games on aggregator ${aggregator}; move them before removing the mapping`);
9
+ export function toProviderSummary(record) {
10
+ return {
11
+ id: record.id,
12
+ slug: record.slug,
13
+ name: record.name,
14
+ logoUrl: record.logoUrl,
15
+ };
16
+ }
17
+ function providerSnapshot(record, aggregatorMappings) {
18
+ return {
19
+ slug: record.slug,
20
+ name: record.name,
21
+ aggregatorMappings: [...aggregatorMappings],
22
+ logoUrl: record.logoUrl,
23
+ metadata: record.metadata ?? null,
24
+ isActive: record.isActive,
25
+ };
26
+ }
27
+ function toProviderDetail(record, aggregatorMappings) {
28
+ const dates = serializeRow(record, { dateFields: ['createdAt', 'updatedAt'] });
29
+ return {
30
+ ...toProviderSummary(record),
31
+ aggregatorMappings: [...aggregatorMappings],
32
+ metadata: record.metadata ?? null,
33
+ isActive: record.isActive,
34
+ createdAt: dates.createdAt,
35
+ updatedAt: dates.updatedAt,
36
+ };
37
+ }
38
+ function isMappingConstraint(name) {
39
+ return (name === 'game_provider_aggregator_mapping_provider_aggregator_key' ||
40
+ name === 'game_provider_aggregator_mapping_aggregator_vendor_id_key');
41
+ }
42
+ export class GameProviderService {
43
+ drizzle;
44
+ events;
45
+ constructor(drizzle, events) {
46
+ this.drizzle = drizzle;
47
+ this.events = events;
48
+ }
49
+ async listActiveProviders({ page, limit }) {
50
+ const where = eq(gameProvider.isActive, true);
51
+ const [items, [{ n }]] = await Promise.all([
52
+ this.drizzle.db
53
+ .select({
54
+ id: gameProvider.id,
55
+ slug: gameProvider.slug,
56
+ name: gameProvider.name,
57
+ logoUrl: gameProvider.logoUrl,
58
+ })
59
+ .from(gameProvider)
60
+ .where(where)
61
+ .orderBy(asc(gameProvider.name), asc(gameProvider.slug))
62
+ .limit(limit)
63
+ .offset(pageToOffset(page, limit)),
64
+ this.drizzle.db.select({ n: count() }).from(gameProvider).where(where),
65
+ ]);
66
+ return { items, total: Number(n), page, limit };
67
+ }
68
+ async listProvidersAdmin({ page, limit, q, isActive, }) {
69
+ const where = and(q
70
+ ? or(ilike(gameProvider.name, likeContains(q)), ilike(gameProvider.slug, likeContains(q)))
71
+ : undefined, isActive === undefined ? undefined : eq(gameProvider.isActive, isActive));
72
+ const [rows, [{ n }]] = await Promise.all([
73
+ this.drizzle.db
74
+ .select()
75
+ .from(gameProvider)
76
+ .where(where)
77
+ .orderBy(asc(gameProvider.name))
78
+ .limit(limit)
79
+ .offset(pageToOffset(page, limit)),
80
+ this.drizzle.db.select({ n: count() }).from(gameProvider).where(where),
81
+ ]);
82
+ const mappings = await mappingsByProviderIds(this.drizzle.db, rows.map((row) => row.id));
83
+ return {
84
+ items: rows.map((row) => toProviderDetail(row, mappings.get(row.id) ?? [])),
85
+ total: Number(n),
86
+ page,
87
+ limit,
88
+ };
89
+ }
90
+ async getProvider(id) {
91
+ const record = findOneOrThrow(await this.drizzle.db.select().from(gameProvider).where(eq(gameProvider.id, id)).limit(1), new GameProviderNotFoundError(id));
92
+ const mappings = await mappingsByProviderIds(this.drizzle.db, [record.id]);
93
+ return toProviderDetail(record, mappings.get(record.id) ?? []);
94
+ }
95
+ async getActiveProviderBySlug(slug) {
96
+ const record = findOneOrThrow(await this.drizzle.db
97
+ .select()
98
+ .from(gameProvider)
99
+ .where(and(eq(gameProvider.slug, slug), eq(gameProvider.isActive, true)))
100
+ .limit(1), new GameProviderNotFoundError(slug));
101
+ return toProviderSummary(record);
102
+ }
103
+ async createProvider({ slug, name, aggregatorMappings = [], logoUrl, metadata, actorId, ip, userAgent, }) {
104
+ let outcome;
105
+ try {
106
+ outcome = await this.drizzle.db.transaction(async (tx) => {
107
+ const [existing] = await tx
108
+ .select({ id: gameProvider.id })
109
+ .from(gameProvider)
110
+ .where(eq(gameProvider.slug, slug))
111
+ .limit(1);
112
+ if (existing) {
113
+ throw new GameProviderSlugTakenError();
114
+ }
115
+ const created = findOneOrThrow(await tx
116
+ .insert(gameProvider)
117
+ .values({ slug, name, logoUrl: logoUrl ?? null, metadata: metadata ?? null })
118
+ .returning(), new GameProviderNotFoundError(slug));
119
+ if (aggregatorMappings.length > 0) {
120
+ await tx.insert(gameProviderAggregatorMapping).values(aggregatorMappings.map((mapping) => ({
121
+ providerId: created.id,
122
+ ...mapping,
123
+ })));
124
+ }
125
+ const mappings = (await mappingsByProviderIds(tx, [created.id])).get(created.id) ?? [];
126
+ return { record: created, mappings };
127
+ });
128
+ }
129
+ catch (error) {
130
+ const constraint = uniqueConstraintName(error);
131
+ if (constraint === 'game_provider_slug_key') {
132
+ throw new GameProviderSlugTakenError();
133
+ }
134
+ if (isMappingConstraint(constraint)) {
135
+ throw new GameProviderVendorIdTakenError();
136
+ }
137
+ throw error;
138
+ }
139
+ const snapshot = providerSnapshot(outcome.record, outcome.mappings);
140
+ this.events.emit('gaming.provider.created', {
141
+ providerId: outcome.record.id,
142
+ ...snapshot,
143
+ actorId,
144
+ ip: ip ?? null,
145
+ userAgent: userAgent ?? null,
146
+ });
147
+ return toProviderDetail(outcome.record, outcome.mappings);
148
+ }
149
+ async updateProvider({ id, actorId, ip, userAgent, aggregatorMappings, ...patchInput }) {
150
+ const outcome = await this.drizzle.db
151
+ .transaction(async (tx) => {
152
+ const existing = findOneOrThrow(await tx
153
+ .select()
154
+ .from(gameProvider)
155
+ .where(eq(gameProvider.id, id))
156
+ .limit(1)
157
+ .for('update'), new GameProviderNotFoundError(id));
158
+ const existingMappings = (await mappingsByProviderIds(tx, [id])).get(existing.id) ?? [];
159
+ if (patchInput.slug !== undefined && patchInput.slug !== existing.slug) {
160
+ const [clash] = await tx
161
+ .select({ id: gameProvider.id })
162
+ .from(gameProvider)
163
+ .where(and(eq(gameProvider.slug, patchInput.slug), ne(gameProvider.id, id)))
164
+ .limit(1);
165
+ if (clash) {
166
+ throw new GameProviderSlugTakenError();
167
+ }
168
+ }
169
+ const patch = { ...patchInput };
170
+ const hasProviderChanges = Object.values(patch).some((value) => value !== undefined);
171
+ const replaceMappings = aggregatorMappings !== undefined;
172
+ if (!hasProviderChanges && !replaceMappings) {
173
+ const snapshot = providerSnapshot(existing, existingMappings);
174
+ return {
175
+ changed: false,
176
+ before: snapshot,
177
+ after: snapshot,
178
+ result: toProviderDetail(existing, existingMappings),
179
+ };
180
+ }
181
+ if (replaceMappings) {
182
+ // A game on a dropped aggregator would stay playable yet sit in the unmapped
183
+ // state updateGame rejects. The provider row lock above conflicts with the
184
+ // FOR SHARE updateGame takes, so no game can move onto the pair mid-check.
185
+ const retained = new Set(aggregatorMappings.map((mapping) => mapping.aggregator));
186
+ const removed = existingMappings
187
+ .map((mapping) => mapping.aggregator)
188
+ .filter((aggregator) => !retained.has(aggregator));
189
+ if (removed.length > 0) {
190
+ const [inUse] = await tx
191
+ .select({ aggregator: game.aggregator })
192
+ .from(game)
193
+ .where(and(eq(game.providerId, id), inArray(game.aggregator, removed)))
194
+ .limit(1);
195
+ if (inUse) {
196
+ throw new GameProviderMappingInUseError(id, inUse.aggregator);
197
+ }
198
+ }
199
+ }
200
+ const next = findOneOrThrow(await tx
201
+ .update(gameProvider)
202
+ .set(replaceMappings ? { ...patch, updatedAt: new Date() } : patch)
203
+ .where(eq(gameProvider.id, id))
204
+ .returning(), new GameProviderNotFoundError(id));
205
+ if (replaceMappings) {
206
+ await tx
207
+ .delete(gameProviderAggregatorMapping)
208
+ .where(eq(gameProviderAggregatorMapping.providerId, id));
209
+ if (aggregatorMappings.length > 0) {
210
+ await tx.insert(gameProviderAggregatorMapping).values(aggregatorMappings.map((mapping) => ({
211
+ providerId: id,
212
+ ...mapping,
213
+ })));
214
+ }
215
+ }
216
+ const persistedMappings = replaceMappings
217
+ ? ((await mappingsByProviderIds(tx, [id])).get(id) ?? [])
218
+ : existingMappings;
219
+ return {
220
+ changed: true,
221
+ before: providerSnapshot(existing, existingMappings),
222
+ after: providerSnapshot(next, persistedMappings),
223
+ result: toProviderDetail(next, persistedMappings),
224
+ };
225
+ })
226
+ .catch((error) => {
227
+ // Translate only the index that actually fired: a vendor-id collision must
228
+ // never surface as a slug conflict, and an unknown 23505 must not lie at all.
229
+ if (isMappingConstraint(uniqueConstraintName(error))) {
230
+ throw new GameProviderVendorIdTakenError();
231
+ }
232
+ if (uniqueConstraintName(error) === 'game_provider_slug_key') {
233
+ throw new GameProviderSlugTakenError();
234
+ }
235
+ throw error;
236
+ });
237
+ if (!outcome.changed) {
238
+ return outcome.result;
239
+ }
240
+ this.events.emit('gaming.provider.updated', {
241
+ providerId: id,
242
+ actorId,
243
+ before: outcome.before,
244
+ after: outcome.after,
245
+ ip: ip ?? null,
246
+ userAgent: userAgent ?? null,
247
+ });
248
+ return outcome.result;
249
+ }
250
+ }
251
+ //# sourceMappingURL=game-provider.service.js.map