@openora/core 0.4.1-canary.66 → 0.4.1-canary.68

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 (213) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/audit/__tests__/audit.service.int.test.js +202 -2
  3. package/dist/audit/__tests__/audit.service.int.test.js.map +1 -1
  4. package/dist/audit/plugin.d.ts +2 -0
  5. package/dist/audit/plugin.d.ts.map +1 -1
  6. package/dist/audit/plugin.js +76 -34
  7. package/dist/audit/plugin.js.map +1 -1
  8. package/dist/casino/gaming/__tests__/gaming.service.int.test.js +4 -3
  9. package/dist/casino/gaming/__tests__/gaming.service.int.test.js.map +1 -1
  10. package/dist/casino/gaming/plugin.d.ts +1 -1
  11. package/dist/casino/gaming/plugin.d.ts.map +1 -1
  12. package/dist/casino/gaming/plugin.js +3 -3
  13. package/dist/casino/gaming/plugin.js.map +1 -1
  14. package/dist/casino/gaming/service/gaming.service.d.ts +3 -2
  15. package/dist/casino/gaming/service/gaming.service.d.ts.map +1 -1
  16. package/dist/casino/gaming/service/gaming.service.js +9 -2
  17. package/dist/casino/gaming/service/gaming.service.js.map +1 -1
  18. package/dist/compliance/__tests__/compliance.service.int.test.js +4 -3
  19. package/dist/compliance/__tests__/compliance.service.int.test.js.map +1 -1
  20. package/dist/compliance/__tests__/kyc-admin.router.int.test.js +2 -1
  21. package/dist/compliance/__tests__/kyc-admin.router.int.test.js.map +1 -1
  22. package/dist/compliance/__tests__/kyc.service.int.test.js +2 -1
  23. package/dist/compliance/__tests__/kyc.service.int.test.js.map +1 -1
  24. package/dist/compliance/__tests__/rg.router.int.test.js +4 -2
  25. package/dist/compliance/__tests__/rg.router.int.test.js.map +1 -1
  26. package/dist/compliance/__tests__/rg.service.int.test.js +4 -2
  27. package/dist/compliance/__tests__/rg.service.int.test.js.map +1 -1
  28. package/dist/compliance/plugin.d.ts.map +1 -1
  29. package/dist/compliance/plugin.js +4 -2
  30. package/dist/compliance/plugin.js.map +1 -1
  31. package/dist/compliance/service/compliance.service.d.ts +3 -2
  32. package/dist/compliance/service/compliance.service.d.ts.map +1 -1
  33. package/dist/compliance/service/compliance.service.js +5 -1
  34. package/dist/compliance/service/compliance.service.js.map +1 -1
  35. package/dist/compliance/service/kyc.service.d.ts +3 -1
  36. package/dist/compliance/service/kyc.service.d.ts.map +1 -1
  37. package/dist/compliance/service/kyc.service.js +6 -2
  38. package/dist/compliance/service/kyc.service.js.map +1 -1
  39. package/dist/compliance/service/rg.service.d.ts +3 -1
  40. package/dist/compliance/service/rg.service.d.ts.map +1 -1
  41. package/dist/compliance/service/rg.service.js +7 -0
  42. package/dist/compliance/service/rg.service.js.map +1 -1
  43. package/dist/contracts/adapters/identity-reader.d.ts +2 -0
  44. package/dist/contracts/adapters/identity-reader.d.ts.map +1 -1
  45. package/dist/contracts/adapters/identity-reader.js.map +1 -1
  46. package/dist/contracts/schemas/events.d.ts +63 -0
  47. package/dist/contracts/schemas/events.d.ts.map +1 -1
  48. package/dist/contracts/schemas/events.js +140 -24
  49. package/dist/contracts/schemas/events.js.map +1 -1
  50. package/dist/engagement/chat/__tests__/chat.service.int.test.js +8 -3
  51. package/dist/engagement/chat/__tests__/chat.service.int.test.js.map +1 -1
  52. package/dist/engagement/chat/plugin.d.ts.map +1 -1
  53. package/dist/engagement/chat/plugin.js +2 -2
  54. package/dist/engagement/chat/plugin.js.map +1 -1
  55. package/dist/engagement/chat/service/chat.service.d.ts +3 -2
  56. package/dist/engagement/chat/service/chat.service.d.ts.map +1 -1
  57. package/dist/engagement/chat/service/chat.service.js +18 -1
  58. package/dist/engagement/chat/service/chat.service.js.map +1 -1
  59. package/dist/engagement/contracts.d.ts +1 -0
  60. package/dist/engagement/contracts.d.ts.map +1 -1
  61. package/dist/engagement/contracts.js +1 -0
  62. package/dist/engagement/contracts.js.map +1 -1
  63. package/dist/engagement/index.d.ts +1 -0
  64. package/dist/engagement/index.d.ts.map +1 -1
  65. package/dist/engagement/index.js +1 -0
  66. package/dist/engagement/index.js.map +1 -1
  67. package/dist/engagement/notifications/__tests__/notifications.service.int.test.js +34 -0
  68. package/dist/engagement/notifications/__tests__/notifications.service.int.test.js.map +1 -1
  69. package/dist/engagement/notifications/contract/index.d.ts +9 -1
  70. package/dist/engagement/notifications/contract/index.d.ts.map +1 -1
  71. package/dist/engagement/notifications/contract/index.js +2 -0
  72. package/dist/engagement/notifications/contract/index.js.map +1 -1
  73. package/dist/engagement/notifications/plugin.d.ts.map +1 -1
  74. package/dist/engagement/notifications/plugin.js +24 -0
  75. package/dist/engagement/notifications/plugin.js.map +1 -1
  76. package/dist/engagement/notifications/router/index.d.ts +2 -0
  77. package/dist/engagement/notifications/router/index.d.ts.map +1 -1
  78. package/dist/engagement/server.d.ts +1 -0
  79. package/dist/engagement/server.d.ts.map +1 -1
  80. package/dist/engagement/server.js +1 -0
  81. package/dist/engagement/server.js.map +1 -1
  82. package/dist/engagement/social/__tests__/social.router.int.test.d.ts +2 -0
  83. package/dist/engagement/social/__tests__/social.router.int.test.d.ts.map +1 -0
  84. package/dist/engagement/social/__tests__/social.router.int.test.js +97 -0
  85. package/dist/engagement/social/__tests__/social.router.int.test.js.map +1 -0
  86. package/dist/engagement/social/__tests__/social.service.int.test.d.ts +2 -0
  87. package/dist/engagement/social/__tests__/social.service.int.test.d.ts.map +1 -0
  88. package/dist/engagement/social/__tests__/social.service.int.test.js +233 -0
  89. package/dist/engagement/social/__tests__/social.service.int.test.js.map +1 -0
  90. package/dist/engagement/social/contract/index.d.ts +73 -0
  91. package/dist/engagement/social/contract/index.d.ts.map +1 -0
  92. package/dist/engagement/social/contract/index.js +54 -0
  93. package/dist/engagement/social/contract/index.js.map +1 -0
  94. package/dist/engagement/social/drizzle/migrations/0000_fine_jamie_braddock.sql +24 -0
  95. package/dist/engagement/social/drizzle/migrations/0001_lame_eddie_brock.sql +10 -0
  96. package/dist/engagement/social/drizzle/migrations/0002_foamy_saracen.sql +1 -0
  97. package/dist/engagement/social/drizzle/migrations/meta/0000_snapshot.json +232 -0
  98. package/dist/engagement/social/drizzle/migrations/meta/0001_snapshot.json +129 -0
  99. package/dist/engagement/social/drizzle/migrations/meta/0002_snapshot.json +134 -0
  100. package/dist/engagement/social/drizzle/migrations/meta/_journal.json +27 -0
  101. package/dist/engagement/social/drizzle.config.d.ts +4 -0
  102. package/dist/engagement/social/drizzle.config.d.ts.map +1 -0
  103. package/dist/engagement/social/drizzle.config.js +21 -0
  104. package/dist/engagement/social/drizzle.config.js.map +1 -0
  105. package/dist/engagement/social/index.d.ts +3 -0
  106. package/dist/engagement/social/index.d.ts.map +1 -0
  107. package/dist/engagement/social/index.js +6 -0
  108. package/dist/engagement/social/index.js.map +1 -0
  109. package/dist/engagement/social/migrate.d.ts +5 -0
  110. package/dist/engagement/social/migrate.d.ts.map +1 -0
  111. package/dist/engagement/social/migrate.js +17 -0
  112. package/dist/engagement/social/migrate.js.map +1 -0
  113. package/dist/engagement/social/plugin.d.ts +111 -0
  114. package/dist/engagement/social/plugin.d.ts.map +1 -0
  115. package/dist/engagement/social/plugin.js +16 -0
  116. package/dist/engagement/social/plugin.js.map +1 -0
  117. package/dist/engagement/social/router/index.d.ts +31 -0
  118. package/dist/engagement/social/router/index.d.ts.map +1 -0
  119. package/dist/engagement/social/router/index.js +31 -0
  120. package/dist/engagement/social/router/index.js.map +1 -0
  121. package/dist/engagement/social/schema/index.d.ts +128 -0
  122. package/dist/engagement/social/schema/index.d.ts.map +1 -0
  123. package/dist/engagement/social/schema/index.js +36 -0
  124. package/dist/engagement/social/schema/index.js.map +1 -0
  125. package/dist/engagement/social/service/social.service.d.ts +39 -0
  126. package/dist/engagement/social/service/social.service.d.ts.map +1 -0
  127. package/dist/engagement/social/service/social.service.js +251 -0
  128. package/dist/engagement/social/service/social.service.js.map +1 -0
  129. package/dist/iam/__tests__/iam.service.int.test.js +42 -38
  130. package/dist/iam/__tests__/iam.service.int.test.js.map +1 -1
  131. package/dist/iam/plugin.d.ts.map +1 -1
  132. package/dist/iam/plugin.js +2 -2
  133. package/dist/iam/plugin.js.map +1 -1
  134. package/dist/iam/service/iam.service.d.ts +3 -2
  135. package/dist/iam/service/iam.service.d.ts.map +1 -1
  136. package/dist/iam/service/iam.service.js +24 -10
  137. package/dist/iam/service/iam.service.js.map +1 -1
  138. package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js +6 -2
  139. package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js.map +1 -1
  140. package/dist/pam/identity/__tests__/identity.service.int.test.js +3 -2
  141. package/dist/pam/identity/__tests__/identity.service.int.test.js.map +1 -1
  142. package/dist/pam/identity/__tests__/login-enforcement.service.int.test.js +8 -3
  143. package/dist/pam/identity/__tests__/login-enforcement.service.int.test.js.map +1 -1
  144. package/dist/pam/identity/adapters/identity-reader.service.d.ts +1 -0
  145. package/dist/pam/identity/adapters/identity-reader.service.d.ts.map +1 -1
  146. package/dist/pam/identity/adapters/identity-reader.service.js +11 -0
  147. package/dist/pam/identity/adapters/identity-reader.service.js.map +1 -1
  148. package/dist/pam/identity/plugin.d.ts.map +1 -1
  149. package/dist/pam/identity/plugin.js +16 -3
  150. package/dist/pam/identity/plugin.js.map +1 -1
  151. package/dist/pam/identity/service/identity.service.d.ts +4 -2
  152. package/dist/pam/identity/service/identity.service.d.ts.map +1 -1
  153. package/dist/pam/identity/service/identity.service.js +81 -31
  154. package/dist/pam/identity/service/identity.service.js.map +1 -1
  155. package/dist/pam/identity/service/phone-login.service.d.ts.map +1 -1
  156. package/dist/pam/identity/service/phone-login.service.js +16 -6
  157. package/dist/pam/identity/service/phone-login.service.js.map +1 -1
  158. package/dist/pam/identity/service/session.service.d.ts +4 -2
  159. package/dist/pam/identity/service/session.service.d.ts.map +1 -1
  160. package/dist/pam/identity/service/session.service.js +5 -1
  161. package/dist/pam/identity/service/session.service.js.map +1 -1
  162. package/dist/pam/player-management/__tests__/kyc-status-writer.int.test.js +2 -1
  163. package/dist/pam/player-management/__tests__/kyc-status-writer.int.test.js.map +1 -1
  164. package/dist/pam/player-management/__tests__/player.service.int.test.js +1 -0
  165. package/dist/pam/player-management/__tests__/player.service.int.test.js.map +1 -1
  166. package/dist/pam/player-management/service/kyc-status-writer.d.ts.map +1 -1
  167. package/dist/pam/player-management/service/kyc-status-writer.js +2 -1
  168. package/dist/pam/player-management/service/kyc-status-writer.js.map +1 -1
  169. package/dist/pam/player-management/service/player.service.d.ts.map +1 -1
  170. package/dist/pam/player-management/service/player.service.js +1 -0
  171. package/dist/pam/player-management/service/player.service.js.map +1 -1
  172. package/dist/pam/tag/__tests__/tag-evaluation.service.int.test.js +57 -13
  173. package/dist/pam/tag/__tests__/tag-evaluation.service.int.test.js.map +1 -1
  174. package/dist/pam/tag/service/tag.service.d.ts.map +1 -1
  175. package/dist/pam/tag/service/tag.service.js +25 -0
  176. package/dist/pam/tag/service/tag.service.js.map +1 -1
  177. package/dist/server/auth/admin-guard.d.ts +3 -2
  178. package/dist/server/auth/admin-guard.d.ts.map +1 -1
  179. package/dist/server/auth/admin-guard.js +28 -9
  180. package/dist/server/auth/admin-guard.js.map +1 -1
  181. package/dist/server/kernel/__tests__/event-bus.int.test.js +9 -5
  182. package/dist/server/kernel/__tests__/event-bus.int.test.js.map +1 -1
  183. package/dist/server/runtime/create-app.d.ts.map +1 -1
  184. package/dist/server/runtime/create-app.js +4 -2
  185. package/dist/server/runtime/create-app.js.map +1 -1
  186. package/dist/testing/mock.d.ts +2 -1
  187. package/dist/testing/mock.d.ts.map +1 -1
  188. package/dist/testing/mock.js +8 -0
  189. package/dist/testing/mock.js.map +1 -1
  190. package/dist/wallet/__tests__/wallet-auto-rule.router.int.test.js +2 -1
  191. package/dist/wallet/__tests__/wallet-auto-rule.router.int.test.js.map +1 -1
  192. package/dist/wallet/__tests__/wallet-auto-withdrawal-config.router.int.test.js +4 -2
  193. package/dist/wallet/__tests__/wallet-auto-withdrawal-config.router.int.test.js.map +1 -1
  194. package/dist/wallet/__tests__/wallet-auto-withdrawal.int.test.js +5 -2
  195. package/dist/wallet/__tests__/wallet-auto-withdrawal.int.test.js.map +1 -1
  196. package/dist/wallet/__tests__/wallet-kyc-gate.int.test.js +4 -2
  197. package/dist/wallet/__tests__/wallet-kyc-gate.int.test.js.map +1 -1
  198. package/dist/wallet/__tests__/wallet-webhook.router.int.test.js +4 -2
  199. package/dist/wallet/__tests__/wallet-webhook.router.int.test.js.map +1 -1
  200. package/dist/wallet/__tests__/wallet.rate-limit.int.test.js +4 -2
  201. package/dist/wallet/__tests__/wallet.rate-limit.int.test.js.map +1 -1
  202. package/dist/wallet/__tests__/wallet.router.int.test.js +2 -1
  203. package/dist/wallet/__tests__/wallet.router.int.test.js.map +1 -1
  204. package/dist/wallet/__tests__/wallet.service.int.test.js +4 -2
  205. package/dist/wallet/__tests__/wallet.service.int.test.js.map +1 -1
  206. package/dist/wallet/plugin.d.ts.map +1 -1
  207. package/dist/wallet/plugin.js +2 -1
  208. package/dist/wallet/plugin.js.map +1 -1
  209. package/dist/wallet/service/wallet.service.d.ts +4 -2
  210. package/dist/wallet/service/wallet.service.d.ts.map +1 -1
  211. package/dist/wallet/service/wallet.service.js +8 -1
  212. package/dist/wallet/service/wallet.service.js.map +1 -1
  213. package/package.json +21 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social.service.int.test.d.ts","sourceRoot":"","sources":["../../../../src/engagement/social/__tests__/social.service.int.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,233 @@
1
+ import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { sql } from 'drizzle-orm';
4
+ import { createTestDb } from '@openora/core/testing';
5
+ import { migrate as migrateChat } from '@openora/core/engagement/migrate/chat';
6
+ import { chatUserBlock } from '@openora/core/engagement/schema/chat';
7
+ import { player } from '@openora/core/pam/schema/profile';
8
+ import { migrate as migrateProfile } from '@openora/core/pam/migrate/profile';
9
+ import { makeEventBus } from '../../../testing/mock.js';
10
+ import { migrate } from '../migrate.js';
11
+ import { friendship } from '../schema/index.js';
12
+ import { SocialService, SelfFriendRequestError, FriendRequestTargetNotFoundError, FriendRequestUnavailableError, AlreadyFriendsError, RequestAlreadyPendingError, FriendRequestRefusedError, BlockedBySelfError, } from '../service/social.service.js';
13
+ let db;
14
+ function makeService() {
15
+ const events = makeEventBus();
16
+ return { svc: new SocialService(db.drizzle, events), events };
17
+ }
18
+ async function seedPlayer(overrides = {}) {
19
+ const [row] = await db.drizzle.db
20
+ .insert(player)
21
+ .values({ userId: randomUUID(), displayName: 'Player', ...overrides })
22
+ .returning();
23
+ return row;
24
+ }
25
+ async function seedBlock(blockerId, blockedId) {
26
+ await db.drizzle.db.insert(chatUserBlock).values({ blockerId, blockedId });
27
+ }
28
+ beforeAll(async () => {
29
+ db = await createTestDb([migrate, migrateProfile, migrateChat]);
30
+ });
31
+ afterAll(async () => {
32
+ await db.drop();
33
+ });
34
+ beforeEach(async () => {
35
+ await db.drizzle.db.execute(sql `TRUNCATE ${friendship}, ${chatUserBlock}, ${player} RESTART IDENTITY CASCADE`);
36
+ });
37
+ describe('SocialService.sendFriendRequest (real PG)', () => {
38
+ it('inserts a pending row and emits social.friend_request.sent', async () => {
39
+ const { svc, events } = makeService();
40
+ const requester = await seedPlayer({ displayName: 'Alice' });
41
+ const addressee = await seedPlayer({ displayName: 'Bob' });
42
+ const result = await svc.sendFriendRequest(requester.userId, addressee.userId);
43
+ expect(result).toMatchObject({
44
+ requesterId: requester.userId,
45
+ addresseeId: addressee.userId,
46
+ acceptedAt: null,
47
+ refusedAt: null,
48
+ });
49
+ expect(typeof result.createdAt).toBe('string');
50
+ expect(await db.drizzle.db.select().from(friendship)).toHaveLength(1);
51
+ expect(events.emit).toHaveBeenCalledWith('social.friend_request.sent', {
52
+ friendshipId: result.id,
53
+ requesterId: requester.userId,
54
+ addresseeId: addressee.userId,
55
+ requesterDisplayName: 'Alice',
56
+ });
57
+ });
58
+ it('throws SelfFriendRequestError when targeting self and does not emit', async () => {
59
+ const { svc, events } = makeService();
60
+ const p = await seedPlayer();
61
+ await expect(svc.sendFriendRequest(p.userId, p.userId)).rejects.toBeInstanceOf(SelfFriendRequestError);
62
+ expect(events.emit).not.toHaveBeenCalled();
63
+ });
64
+ it('throws FriendRequestTargetNotFoundError when the target does not exist', async () => {
65
+ const { svc } = makeService();
66
+ const requester = await seedPlayer();
67
+ await expect(svc.sendFriendRequest(requester.userId, randomUUID())).rejects.toBeInstanceOf(FriendRequestTargetNotFoundError);
68
+ });
69
+ it.each(['suspended', 'closed'])('throws FriendRequestUnavailableError when the target is %s', async (status) => {
70
+ const { svc } = makeService();
71
+ const requester = await seedPlayer();
72
+ const target = await seedPlayer({ status });
73
+ await expect(svc.sendFriendRequest(requester.userId, target.userId)).rejects.toBeInstanceOf(FriendRequestUnavailableError);
74
+ });
75
+ it('throws FriendRequestUnavailableError (never leaking the block, same as suspended) when the target has blocked the caller', async () => {
76
+ const { svc, events } = makeService();
77
+ const requester = await seedPlayer();
78
+ const target = await seedPlayer();
79
+ await seedBlock(target.userId, requester.userId);
80
+ await expect(svc.sendFriendRequest(requester.userId, target.userId)).rejects.toBeInstanceOf(FriendRequestUnavailableError);
81
+ expect(events.emit).not.toHaveBeenCalled();
82
+ });
83
+ it('throws BlockedBySelfError when the caller has blocked the target', async () => {
84
+ const { svc, events } = makeService();
85
+ const requester = await seedPlayer();
86
+ const target = await seedPlayer();
87
+ await seedBlock(requester.userId, target.userId);
88
+ await expect(svc.sendFriendRequest(requester.userId, target.userId)).rejects.toBeInstanceOf(BlockedBySelfError);
89
+ expect(events.emit).not.toHaveBeenCalled();
90
+ });
91
+ it('throws RequestAlreadyPendingError on a same-direction duplicate and does not double-insert or re-emit', async () => {
92
+ const { svc, events } = makeService();
93
+ const requester = await seedPlayer();
94
+ const target = await seedPlayer();
95
+ await svc.sendFriendRequest(requester.userId, target.userId);
96
+ events.emit.mockClear();
97
+ await expect(svc.sendFriendRequest(requester.userId, target.userId)).rejects.toBeInstanceOf(RequestAlreadyPendingError);
98
+ expect(events.emit).not.toHaveBeenCalled();
99
+ expect(await db.drizzle.db.select().from(friendship)).toHaveLength(1);
100
+ });
101
+ it('throws AlreadyFriendsError once the pair is already friends', async () => {
102
+ const { svc, events } = makeService();
103
+ const requester = await seedPlayer();
104
+ const target = await seedPlayer();
105
+ await svc.sendFriendRequest(requester.userId, target.userId);
106
+ await svc.sendFriendRequest(target.userId, requester.userId); // mutual auto-accept
107
+ events.emit.mockClear();
108
+ await expect(svc.sendFriendRequest(requester.userId, target.userId)).rejects.toBeInstanceOf(AlreadyFriendsError);
109
+ expect(events.emit).not.toHaveBeenCalled();
110
+ });
111
+ it('auto-accepts a mutual/simultaneous request, updates the SAME row, and emits social.friend_request.accepted', async () => {
112
+ const { svc, events } = makeService();
113
+ const alice = await seedPlayer({ displayName: 'Alice' });
114
+ const bob = await seedPlayer({ displayName: 'Bob' });
115
+ const first = await svc.sendFriendRequest(alice.userId, bob.userId);
116
+ events.emit.mockClear();
117
+ const result = await svc.sendFriendRequest(bob.userId, alice.userId);
118
+ expect(result).toMatchObject({
119
+ id: first.id,
120
+ requesterId: alice.userId,
121
+ addresseeId: bob.userId,
122
+ refusedAt: null,
123
+ });
124
+ expect(result.acceptedAt).toEqual(expect.any(String));
125
+ expect(events.emit).toHaveBeenCalledWith('social.friend_request.accepted', {
126
+ friendshipId: first.id,
127
+ requesterId: alice.userId,
128
+ addresseeId: bob.userId,
129
+ accepterId: bob.userId,
130
+ accepterDisplayName: 'Bob',
131
+ });
132
+ const rows = await db.drizzle.db.select().from(friendship);
133
+ expect(rows).toHaveLength(1);
134
+ expect(rows[0]?.acceptedAt).toBeInstanceOf(Date);
135
+ expect(rows[0]?.refusedAt).toBeNull();
136
+ });
137
+ it('keeps a refused request refused and does not auto-accept a new request for the pair', async () => {
138
+ const { svc, events } = makeService();
139
+ const requester = await seedPlayer();
140
+ const addressee = await seedPlayer();
141
+ const [refused] = await db.drizzle.db
142
+ .insert(friendship)
143
+ .values({
144
+ requesterId: requester.userId,
145
+ addresseeId: addressee.userId,
146
+ refusedAt: new Date(),
147
+ })
148
+ .returning();
149
+ const relationship = await svc.getRelationships(requester.userId, [addressee.userId]);
150
+ expect(relationship).toEqual([
151
+ {
152
+ userId: addressee.userId,
153
+ status: 'refused',
154
+ friendshipId: refused?.id,
155
+ canSendRequest: false,
156
+ },
157
+ ]);
158
+ await expect(svc.sendFriendRequest(requester.userId, addressee.userId)).rejects.toBeInstanceOf(FriendRequestRefusedError);
159
+ expect(events.emit).not.toHaveBeenCalled();
160
+ });
161
+ });
162
+ describe('SocialService.getRelationships (real PG)', () => {
163
+ it('returns none + canSendRequest true for an unrelated active player', async () => {
164
+ const { svc } = makeService();
165
+ const caller = await seedPlayer();
166
+ const other = await seedPlayer();
167
+ const result = await svc.getRelationships(caller.userId, [other.userId]);
168
+ expect(result).toEqual([
169
+ { userId: other.userId, status: 'none', friendshipId: null, canSendRequest: true },
170
+ ]);
171
+ });
172
+ it('returns unavailable for a nonexistent user', async () => {
173
+ const { svc } = makeService();
174
+ const caller = await seedPlayer();
175
+ const result = await svc.getRelationships(caller.userId, [randomUUID()]);
176
+ expect(result[0]).toMatchObject({ status: 'unavailable', canSendRequest: false });
177
+ });
178
+ it.each(['suspended', 'closed'])('returns unavailable for a %s target', async (status) => {
179
+ const { svc } = makeService();
180
+ const caller = await seedPlayer();
181
+ const target = await seedPlayer({ status });
182
+ const result = await svc.getRelationships(caller.userId, [target.userId]);
183
+ expect(result[0]).toMatchObject({ status: 'unavailable', canSendRequest: false });
184
+ });
185
+ it('returns unavailable when the target has blocked the caller', async () => {
186
+ const { svc } = makeService();
187
+ const caller = await seedPlayer();
188
+ const target = await seedPlayer();
189
+ await seedBlock(target.userId, caller.userId);
190
+ const result = await svc.getRelationships(caller.userId, [target.userId]);
191
+ expect(result[0]).toMatchObject({ status: 'unavailable', canSendRequest: false });
192
+ });
193
+ it('returns blocked_by_me when the caller has blocked the target', async () => {
194
+ const { svc } = makeService();
195
+ const caller = await seedPlayer();
196
+ const target = await seedPlayer();
197
+ await seedBlock(caller.userId, target.userId);
198
+ const result = await svc.getRelationships(caller.userId, [target.userId]);
199
+ expect(result[0]).toMatchObject({
200
+ status: 'blocked_by_me',
201
+ friendshipId: null,
202
+ canSendRequest: false,
203
+ });
204
+ });
205
+ it('returns pending_outgoing / pending_incoming from each side of a pending request', async () => {
206
+ const { svc } = makeService();
207
+ const caller = await seedPlayer();
208
+ const target = await seedPlayer();
209
+ const sent = await svc.sendFriendRequest(caller.userId, target.userId);
210
+ const fromCaller = await svc.getRelationships(caller.userId, [target.userId]);
211
+ const fromTarget = await svc.getRelationships(target.userId, [caller.userId]);
212
+ expect(fromCaller[0]).toMatchObject({ status: 'pending_outgoing', friendshipId: sent.id });
213
+ expect(fromTarget[0]).toMatchObject({ status: 'pending_incoming', friendshipId: sent.id });
214
+ });
215
+ it('returns friends for an accepted pair', async () => {
216
+ const { svc } = makeService();
217
+ const alice = await seedPlayer();
218
+ const bob = await seedPlayer();
219
+ await svc.sendFriendRequest(alice.userId, bob.userId);
220
+ await svc.sendFriendRequest(bob.userId, alice.userId);
221
+ const result = await svc.getRelationships(alice.userId, [bob.userId]);
222
+ expect(result[0]).toMatchObject({ status: 'friends', canSendRequest: false });
223
+ });
224
+ it('preserves input order and duplicates, and batches reads (no N+1)', async () => {
225
+ const { svc } = makeService();
226
+ const caller = await seedPlayer();
227
+ const a = await seedPlayer();
228
+ const b = await seedPlayer();
229
+ const result = await svc.getRelationships(caller.userId, [b.userId, a.userId, b.userId]);
230
+ expect(result.map((r) => r.userId)).toEqual([b.userId, a.userId, b.userId]);
231
+ });
232
+ });
233
+ //# sourceMappingURL=social.service.int.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social.service.int.test.js","sourceRoot":"","sources":["../../../../src/engagement/social/__tests__/social.service.int.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import * as z from 'zod';
2
+ export declare const SendFriendRequestInputSchema: z.ZodObject<{
3
+ targetUserId: z.ZodUUID;
4
+ }, z.core.$strip>;
5
+ export type SendFriendRequestInput = z.infer<typeof SendFriendRequestInputSchema>;
6
+ export declare const FriendshipSchema: z.ZodObject<{
7
+ id: z.ZodUUID;
8
+ requesterId: z.ZodUUID;
9
+ addresseeId: z.ZodUUID;
10
+ createdAt: z.ZodISODateTime;
11
+ acceptedAt: z.ZodNullable<z.ZodISODateTime>;
12
+ refusedAt: z.ZodNullable<z.ZodISODateTime>;
13
+ }, z.core.$strip>;
14
+ export type Friendship = z.infer<typeof FriendshipSchema>;
15
+ export declare const RELATIONSHIP_STATUSES: readonly ["none", "pending_outgoing", "pending_incoming", "friends", "refused", "blocked_by_me", "unavailable"];
16
+ export declare const RelationshipStatusSchema: z.ZodEnum<{
17
+ none: "none";
18
+ pending_outgoing: "pending_outgoing";
19
+ pending_incoming: "pending_incoming";
20
+ friends: "friends";
21
+ refused: "refused";
22
+ blocked_by_me: "blocked_by_me";
23
+ unavailable: "unavailable";
24
+ }>;
25
+ export type RelationshipStatus = z.infer<typeof RelationshipStatusSchema>;
26
+ export declare const GetRelationshipsInputSchema: z.ZodObject<{
27
+ userIds: z.ZodArray<z.ZodUUID>;
28
+ }, z.core.$strip>;
29
+ export type GetRelationshipsInput = z.infer<typeof GetRelationshipsInputSchema>;
30
+ export declare const RelationshipSchema: z.ZodObject<{
31
+ userId: z.ZodUUID;
32
+ status: z.ZodEnum<{
33
+ none: "none";
34
+ pending_outgoing: "pending_outgoing";
35
+ pending_incoming: "pending_incoming";
36
+ friends: "friends";
37
+ refused: "refused";
38
+ blocked_by_me: "blocked_by_me";
39
+ unavailable: "unavailable";
40
+ }>;
41
+ friendshipId: z.ZodNullable<z.ZodUUID>;
42
+ canSendRequest: z.ZodBoolean;
43
+ }, z.core.$strip>;
44
+ export type Relationship = z.infer<typeof RelationshipSchema>;
45
+ export declare const socialContract: {
46
+ sendFriendRequest: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
47
+ targetUserId: z.ZodUUID;
48
+ }, z.core.$strip>, z.ZodObject<{
49
+ id: z.ZodUUID;
50
+ requesterId: z.ZodUUID;
51
+ addresseeId: z.ZodUUID;
52
+ createdAt: z.ZodISODateTime;
53
+ acceptedAt: z.ZodNullable<z.ZodISODateTime>;
54
+ refusedAt: z.ZodNullable<z.ZodISODateTime>;
55
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
56
+ getRelationships: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
57
+ userIds: z.ZodArray<z.ZodUUID>;
58
+ }, z.core.$strip>, z.ZodArray<z.ZodObject<{
59
+ userId: z.ZodUUID;
60
+ status: z.ZodEnum<{
61
+ none: "none";
62
+ pending_outgoing: "pending_outgoing";
63
+ pending_incoming: "pending_incoming";
64
+ friends: "friends";
65
+ refused: "refused";
66
+ blocked_by_me: "blocked_by_me";
67
+ unavailable: "unavailable";
68
+ }>;
69
+ friendshipId: z.ZodNullable<z.ZodUUID>;
70
+ canSendRequest: z.ZodBoolean;
71
+ }, z.core.$strip>>, Record<never, never>, Record<never, never>>;
72
+ };
73
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/engagement/social/contract/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AASzB,eAAO,MAAM,4BAA4B;;iBAEvC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF,eAAO,MAAM,gBAAgB;;;;;;;iBAO3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAM1D,eAAO,MAAM,qBAAqB,iHAQxB,CAAC;AACX,eAAO,MAAM,wBAAwB;;;;;;;;EAAgC,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,2BAA2B;;iBAEtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;iBAK7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;CAW1B,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { oc } from '@orpc/contract';
2
+ import * as z from 'zod';
3
+ import { TimestampSchema, UuidSchema } from '@openora/core/contracts';
4
+ // Canonical request/response shapes for the Social module. This is the
5
+ // single source of truth - the router validates against it, live OpenAPI + the typed
6
+ // client are emitted from it. Derive related shapes with .pick()/.omit()/.extend()
7
+ // rather than re-typing fields. Promote anything shared across domains to
8
+ // @openora/core/contracts. This dir is isomorphic: Zod + @openora/core/contracts only.
9
+ export const SendFriendRequestInputSchema = z.object({
10
+ targetUserId: UuidSchema,
11
+ });
12
+ export const FriendshipSchema = z.object({
13
+ id: UuidSchema,
14
+ requesterId: UuidSchema,
15
+ addresseeId: UuidSchema,
16
+ createdAt: TimestampSchema,
17
+ acceptedAt: TimestampSchema.nullable(),
18
+ refusedAt: TimestampSchema.nullable(),
19
+ });
20
+ // Per-target relationship state for a batch lookup (eg rendering a friends-list /
21
+ // player-search page without one request per row). `unavailable` covers every case
22
+ // the caller must never be able to distinguish from "target doesn't exist" - a
23
+ // missing/suspended/closed player, or a target who has blocked the caller.
24
+ export const RELATIONSHIP_STATUSES = [
25
+ 'none',
26
+ 'pending_outgoing',
27
+ 'pending_incoming',
28
+ 'friends',
29
+ 'refused',
30
+ 'blocked_by_me',
31
+ 'unavailable',
32
+ ];
33
+ export const RelationshipStatusSchema = z.enum(RELATIONSHIP_STATUSES);
34
+ export const GetRelationshipsInputSchema = z.object({
35
+ userIds: z.array(UuidSchema).min(1).max(100),
36
+ });
37
+ export const RelationshipSchema = z.object({
38
+ userId: UuidSchema,
39
+ status: RelationshipStatusSchema,
40
+ friendshipId: UuidSchema.nullable(),
41
+ canSendRequest: z.boolean(),
42
+ });
43
+ export const socialContract = {
44
+ sendFriendRequest: oc
45
+ .route({ method: 'POST', path: '/social/friend-requests' })
46
+ .input(SendFriendRequestInputSchema)
47
+ .output(FriendshipSchema),
48
+ // POST is deliberate - this is a batch lookup, not a single-resource GET.
49
+ getRelationships: oc
50
+ .route({ method: 'POST', path: '/social/relationships' })
51
+ .input(GetRelationshipsInputSchema)
52
+ .output(z.array(RelationshipSchema)),
53
+ };
54
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/engagement/social/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEtE,uEAAuE;AACvE,qFAAqF;AACrF,mFAAmF;AACnF,0EAA0E;AAC1E,uFAAuF;AAEvF,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,YAAY,EAAE,UAAU;CACzB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,UAAU;IACd,WAAW,EAAE,UAAU;IACvB,WAAW,EAAE,UAAU;IACvB,SAAS,EAAE,eAAe;IAC1B,UAAU,EAAE,eAAe,CAAC,QAAQ,EAAE;IACtC,SAAS,EAAE,eAAe,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC;AAGH,kFAAkF;AAClF,mFAAmF;AACnF,+EAA+E;AAC/E,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,MAAM;IACN,kBAAkB;IAClB,kBAAkB;IAClB,SAAS;IACT,SAAS;IACT,eAAe;IACf,aAAa;CACL,CAAC;AACX,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AAGtE,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;CAC7C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,wBAAwB;IAChC,YAAY,EAAE,UAAU,CAAC,QAAQ,EAAE;IACnC,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;CAC5B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,iBAAiB,EAAE,EAAE;SAClB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC;SAC1D,KAAK,CAAC,4BAA4B,CAAC;SACnC,MAAM,CAAC,gBAAgB,CAAC;IAE3B,0EAA0E;IAC1E,gBAAgB,EAAE,EAAE;SACjB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC;SACxD,KAAK,CAAC,2BAA2B,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;CACvC,CAAC"}
@@ -0,0 +1,24 @@
1
+ CREATE TYPE "public"."friendship_status" AS ENUM('pending', 'accepted');--> statement-breakpoint
2
+ CREATE TABLE "friendship" (
3
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
4
+ "requester_id" uuid NOT NULL,
5
+ "addressee_id" uuid NOT NULL,
6
+ "status" "friendship_status" DEFAULT 'pending' NOT NULL,
7
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
8
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
9
+ "responded_at" timestamp with time zone
10
+ );
11
+ --> statement-breakpoint
12
+ CREATE TABLE "social_user_block" (
13
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
14
+ "blocker_id" uuid NOT NULL,
15
+ "blocked_id" uuid NOT NULL,
16
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
17
+ "removed_at" timestamp with time zone
18
+ );
19
+ --> statement-breakpoint
20
+ CREATE UNIQUE INDEX "friendship_pair_key" ON "friendship" USING btree (LEAST("requester_id", "addressee_id"),GREATEST("requester_id", "addressee_id"));--> statement-breakpoint
21
+ CREATE INDEX "friendship_addressee_status_idx" ON "friendship" USING btree ("addressee_id","status");--> statement-breakpoint
22
+ CREATE INDEX "friendship_requester_status_idx" ON "friendship" USING btree ("requester_id","status");--> statement-breakpoint
23
+ CREATE UNIQUE INDEX "social_user_block_pair_key" ON "social_user_block" USING btree ("blocker_id","blocked_id") WHERE "social_user_block"."removed_at" IS NULL;--> statement-breakpoint
24
+ CREATE INDEX "social_user_block_blocked_idx" ON "social_user_block" USING btree ("blocked_id");
@@ -0,0 +1,10 @@
1
+ ALTER TABLE "social_user_block" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint
2
+ DROP TABLE "social_user_block" CASCADE;--> statement-breakpoint
3
+ ALTER TABLE "friendship" RENAME COLUMN "responded_at" TO "accepted_at";--> statement-breakpoint
4
+ DROP INDEX "friendship_addressee_status_idx";--> statement-breakpoint
5
+ DROP INDEX "friendship_requester_status_idx";--> statement-breakpoint
6
+ ALTER TABLE "friendship" ADD COLUMN "refused_at" timestamp with time zone;--> statement-breakpoint
7
+ CREATE INDEX "friendship_addressee_idx" ON "friendship" USING btree ("addressee_id");--> statement-breakpoint
8
+ CREATE INDEX "friendship_requester_idx" ON "friendship" USING btree ("requester_id");--> statement-breakpoint
9
+ ALTER TABLE "friendship" DROP COLUMN "status";--> statement-breakpoint
10
+ DROP TYPE "public"."friendship_status";
@@ -0,0 +1 @@
1
+ ALTER TABLE "friendship" ADD CONSTRAINT "friendship_one_decision_key" CHECK (NOT ("friendship"."accepted_at" IS NOT NULL AND "friendship"."refused_at" IS NOT NULL));