@openora/core 0.4.1-canary.37 → 0.4.1-canary.39

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 (259) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/admin-console/__tests__/backoffice.router.test.js +67 -51
  3. package/dist/admin-console/__tests__/backoffice.router.test.js.map +1 -1
  4. package/dist/admin-console/__tests__/backoffice.service.test.js +1 -13
  5. package/dist/admin-console/__tests__/backoffice.service.test.js.map +1 -1
  6. package/dist/analytics/__tests__/analytics.contract.test.js +12 -0
  7. package/dist/analytics/__tests__/analytics.contract.test.js.map +1 -1
  8. package/dist/analytics/__tests__/financial-analytics.service.test.js +3 -3
  9. package/dist/analytics/__tests__/financial-analytics.service.test.js.map +1 -1
  10. package/dist/analytics/service/financial-analytics.service.d.ts.map +1 -1
  11. package/dist/analytics/service/financial-analytics.service.js +14 -17
  12. package/dist/analytics/service/financial-analytics.service.js.map +1 -1
  13. package/dist/analytics/service/funnel-analytics.service.d.ts.map +1 -1
  14. package/dist/analytics/service/funnel-analytics.service.js +8 -11
  15. package/dist/analytics/service/funnel-analytics.service.js.map +1 -1
  16. package/dist/audit/__tests__/audit.service.test.js +128 -251
  17. package/dist/audit/__tests__/audit.service.test.js.map +1 -1
  18. package/dist/casino/gaming/__tests__/gaming.service.test.js +83 -89
  19. package/dist/casino/gaming/__tests__/gaming.service.test.js.map +1 -1
  20. package/dist/casino/lobby/__tests__/lobby.cache.test.js +42 -33
  21. package/dist/casino/lobby/__tests__/lobby.cache.test.js.map +1 -1
  22. package/dist/cms/__tests__/cms.reads.test.js +59 -80
  23. package/dist/cms/__tests__/cms.reads.test.js.map +1 -1
  24. package/dist/cms/__tests__/cms.router.test.js +62 -20
  25. package/dist/cms/__tests__/cms.router.test.js.map +1 -1
  26. package/dist/cms/__tests__/cms.service.test.js +116 -14
  27. package/dist/cms/__tests__/cms.service.test.js.map +1 -1
  28. package/dist/common/errors/__tests__/errors.mapper.test.d.ts +2 -0
  29. package/dist/common/errors/__tests__/errors.mapper.test.d.ts.map +1 -0
  30. package/dist/common/errors/__tests__/errors.mapper.test.js +59 -0
  31. package/dist/common/errors/__tests__/errors.mapper.test.js.map +1 -0
  32. package/dist/compliance/__tests__/assert.test.d.ts +2 -0
  33. package/dist/compliance/__tests__/assert.test.d.ts.map +1 -0
  34. package/dist/compliance/__tests__/assert.test.js +34 -0
  35. package/dist/compliance/__tests__/assert.test.js.map +1 -0
  36. package/dist/compliance/__tests__/compliance.service.test.js +149 -84
  37. package/dist/compliance/__tests__/compliance.service.test.js.map +1 -1
  38. package/dist/compliance/__tests__/kyc.service.test.js +247 -155
  39. package/dist/compliance/__tests__/kyc.service.test.js.map +1 -1
  40. package/dist/compliance/__tests__/limits.contract.test.d.ts +2 -0
  41. package/dist/compliance/__tests__/limits.contract.test.d.ts.map +1 -0
  42. package/dist/compliance/__tests__/limits.contract.test.js +43 -0
  43. package/dist/compliance/__tests__/limits.contract.test.js.map +1 -0
  44. package/dist/compliance/__tests__/rg-monitoring.service.test.js +256 -101
  45. package/dist/compliance/__tests__/rg-monitoring.service.test.js.map +1 -1
  46. package/dist/compliance/__tests__/rg.contract.test.js +1 -20
  47. package/dist/compliance/__tests__/rg.contract.test.js.map +1 -1
  48. package/dist/compliance/__tests__/rg.router.test.js +113 -65
  49. package/dist/compliance/__tests__/rg.router.test.js.map +1 -1
  50. package/dist/compliance/__tests__/rg.service.test.js +277 -235
  51. package/dist/compliance/__tests__/rg.service.test.js.map +1 -1
  52. package/dist/compliance/service/rg-monitoring.service.d.ts.map +1 -1
  53. package/dist/compliance/service/rg-monitoring.service.js +11 -8
  54. package/dist/compliance/service/rg-monitoring.service.js.map +1 -1
  55. package/dist/contracts/__tests__/compose-contract.test.d.ts +2 -0
  56. package/dist/contracts/__tests__/compose-contract.test.d.ts.map +1 -0
  57. package/dist/contracts/__tests__/compose-contract.test.js +27 -0
  58. package/dist/contracts/__tests__/compose-contract.test.js.map +1 -0
  59. package/dist/contracts/adapters/__tests__/token.test.d.ts +2 -0
  60. package/dist/contracts/adapters/__tests__/token.test.d.ts.map +1 -0
  61. package/dist/contracts/adapters/__tests__/token.test.js +14 -0
  62. package/dist/contracts/adapters/__tests__/token.test.js.map +1 -0
  63. package/dist/contracts/schemas/__tests__/events.test.d.ts +2 -0
  64. package/dist/contracts/schemas/__tests__/events.test.d.ts.map +1 -0
  65. package/dist/contracts/schemas/__tests__/events.test.js +51 -0
  66. package/dist/contracts/schemas/__tests__/events.test.js.map +1 -0
  67. package/dist/contracts/schemas/__tests__/igaming-config.test.d.ts +2 -0
  68. package/dist/contracts/schemas/__tests__/igaming-config.test.d.ts.map +1 -0
  69. package/dist/contracts/schemas/__tests__/igaming-config.test.js +38 -0
  70. package/dist/contracts/schemas/__tests__/igaming-config.test.js.map +1 -0
  71. package/dist/contracts/schemas/reporting.d.ts +7 -2
  72. package/dist/contracts/schemas/reporting.d.ts.map +1 -1
  73. package/dist/contracts/schemas/reporting.js +2 -1
  74. package/dist/contracts/schemas/reporting.js.map +1 -1
  75. package/dist/engagement/chat/__tests__/chat.service.test.js +524 -364
  76. package/dist/engagement/chat/__tests__/chat.service.test.js.map +1 -1
  77. package/dist/engagement/notifications/__tests__/notifications.service.test.js +125 -68
  78. package/dist/engagement/notifications/__tests__/notifications.service.test.js.map +1 -1
  79. package/dist/iam/__tests__/iam.service.test.js +367 -596
  80. package/dist/iam/__tests__/iam.service.test.js.map +1 -1
  81. package/dist/pam/identity/__tests__/admin-user-directory.test.js +144 -68
  82. package/dist/pam/identity/__tests__/admin-user-directory.test.js.map +1 -1
  83. package/dist/pam/identity/__tests__/identity.rate-limit.test.js +33 -22
  84. package/dist/pam/identity/__tests__/identity.rate-limit.test.js.map +1 -1
  85. package/dist/pam/identity/__tests__/identity.service.test.js +217 -298
  86. package/dist/pam/identity/__tests__/identity.service.test.js.map +1 -1
  87. package/dist/pam/identity/__tests__/login-enforcement.service.test.js +97 -32
  88. package/dist/pam/identity/__tests__/login-enforcement.service.test.js.map +1 -1
  89. package/dist/pam/identity/__tests__/phone-login.service.test.js +163 -134
  90. package/dist/pam/identity/__tests__/phone-login.service.test.js.map +1 -1
  91. package/dist/pam/identity/__tests__/rg-guard.test.d.ts +2 -0
  92. package/dist/pam/identity/__tests__/rg-guard.test.d.ts.map +1 -0
  93. package/dist/pam/identity/__tests__/rg-guard.test.js +21 -0
  94. package/dist/pam/identity/__tests__/rg-guard.test.js.map +1 -0
  95. package/dist/pam/player-management/__tests__/kyc-status-writer.test.js +73 -26
  96. package/dist/pam/player-management/__tests__/kyc-status-writer.test.js.map +1 -1
  97. package/dist/pam/player-management/__tests__/player.router.test.js +63 -46
  98. package/dist/pam/player-management/__tests__/player.router.test.js.map +1 -1
  99. package/dist/pam/player-management/__tests__/player.service.test.js +207 -111
  100. package/dist/pam/player-management/__tests__/player.service.test.js.map +1 -1
  101. package/dist/pam/profile/__tests__/profile.service.test.js +89 -41
  102. package/dist/pam/profile/__tests__/profile.service.test.js.map +1 -1
  103. package/dist/pam/shared/__tests__/shared-mappers.test.d.ts +2 -0
  104. package/dist/pam/shared/__tests__/shared-mappers.test.d.ts.map +1 -0
  105. package/dist/pam/shared/__tests__/shared-mappers.test.js +55 -0
  106. package/dist/pam/shared/__tests__/shared-mappers.test.js.map +1 -0
  107. package/dist/pam/tag/__tests__/get-active-tag-keys.test.js +72 -30
  108. package/dist/pam/tag/__tests__/get-active-tag-keys.test.js.map +1 -1
  109. package/dist/pam/tag/__tests__/tag-evaluation.service.test.js +308 -235
  110. package/dist/pam/tag/__tests__/tag-evaluation.service.test.js.map +1 -1
  111. package/dist/pam/tag/__tests__/tag-rule.service.test.js +136 -140
  112. package/dist/pam/tag/__tests__/tag-rule.service.test.js.map +1 -1
  113. package/dist/pam/tag/__tests__/tag.router.test.js +76 -25
  114. package/dist/pam/tag/__tests__/tag.router.test.js.map +1 -1
  115. package/dist/pam/tag/__tests__/tag.service.test.js +224 -247
  116. package/dist/pam/tag/__tests__/tag.service.test.js.map +1 -1
  117. package/dist/server/auth/__tests__/admin-guard.test.js +107 -117
  118. package/dist/server/auth/__tests__/admin-guard.test.js.map +1 -1
  119. package/dist/server/auth/__tests__/permission-levels.test.d.ts +2 -0
  120. package/dist/server/auth/__tests__/permission-levels.test.d.ts.map +1 -0
  121. package/dist/server/auth/__tests__/permission-levels.test.js +89 -0
  122. package/dist/server/auth/__tests__/permission-levels.test.js.map +1 -0
  123. package/dist/server/auth/__tests__/session-resolver.test.js +45 -13
  124. package/dist/server/auth/__tests__/session-resolver.test.js.map +1 -1
  125. package/dist/server/db/__tests__/query-helpers.test.js +72 -1
  126. package/dist/server/db/__tests__/query-helpers.test.js.map +1 -1
  127. package/dist/server/db/outbox/__tests__/relay.test.js +74 -81
  128. package/dist/server/db/outbox/__tests__/relay.test.js.map +1 -1
  129. package/dist/server/kernel/__tests__/bullmq-job-queue.test.js +204 -154
  130. package/dist/server/kernel/__tests__/bullmq-job-queue.test.js.map +1 -1
  131. package/dist/server/kernel/__tests__/cache.test.js +26 -13
  132. package/dist/server/kernel/__tests__/cache.test.js.map +1 -1
  133. package/dist/server/kernel/__tests__/domain-error.test.d.ts +2 -0
  134. package/dist/server/kernel/__tests__/domain-error.test.d.ts.map +1 -0
  135. package/dist/server/kernel/__tests__/domain-error.test.js +35 -0
  136. package/dist/server/kernel/__tests__/domain-error.test.js.map +1 -0
  137. package/dist/server/kernel/__tests__/error-reporter.test.d.ts +2 -0
  138. package/dist/server/kernel/__tests__/error-reporter.test.d.ts.map +1 -0
  139. package/dist/server/kernel/__tests__/error-reporter.test.js +52 -0
  140. package/dist/server/kernel/__tests__/error-reporter.test.js.map +1 -0
  141. package/dist/server/kernel/__tests__/event-bus.test.js +60 -20
  142. package/dist/server/kernel/__tests__/event-bus.test.js.map +1 -1
  143. package/dist/server/kernel/__tests__/orpc-error-map.test.d.ts +2 -0
  144. package/dist/server/kernel/__tests__/orpc-error-map.test.d.ts.map +1 -0
  145. package/dist/server/kernel/__tests__/orpc-error-map.test.js +54 -0
  146. package/dist/server/kernel/__tests__/orpc-error-map.test.js.map +1 -0
  147. package/dist/server/kernel/__tests__/platform-config-loader.test.d.ts +2 -0
  148. package/dist/server/kernel/__tests__/platform-config-loader.test.d.ts.map +1 -0
  149. package/dist/server/kernel/__tests__/platform-config-loader.test.js +112 -0
  150. package/dist/server/kernel/__tests__/platform-config-loader.test.js.map +1 -0
  151. package/dist/server/kernel/__tests__/rate-limiter.test.js +22 -13
  152. package/dist/server/kernel/__tests__/rate-limiter.test.js.map +1 -1
  153. package/dist/server/kernel/__tests__/realtime-transport.test.d.ts.map +1 -0
  154. package/dist/{testing/fakes → server/kernel}/__tests__/realtime-transport.test.js.map +1 -1
  155. package/dist/server/kernel/__tests__/redis-cache.test.js +34 -34
  156. package/dist/server/kernel/__tests__/redis-cache.test.js.map +1 -1
  157. package/dist/server/kernel/__tests__/redis-rate-limiter.test.js +49 -44
  158. package/dist/server/kernel/__tests__/redis-rate-limiter.test.js.map +1 -1
  159. package/dist/server/kernel/__tests__/redis-streams-broker.test.js +141 -262
  160. package/dist/server/kernel/__tests__/redis-streams-broker.test.js.map +1 -1
  161. package/dist/server/kernel/__tests__/request-context.test.d.ts +2 -0
  162. package/dist/server/kernel/__tests__/request-context.test.d.ts.map +1 -0
  163. package/dist/server/kernel/__tests__/request-context.test.js +64 -0
  164. package/dist/server/kernel/__tests__/request-context.test.js.map +1 -0
  165. package/dist/server/kernel/__tests__/router-utils.test.d.ts +2 -0
  166. package/dist/server/kernel/__tests__/router-utils.test.d.ts.map +1 -0
  167. package/dist/server/kernel/__tests__/router-utils.test.js +80 -0
  168. package/dist/server/kernel/__tests__/router-utils.test.js.map +1 -0
  169. package/dist/server/kernel/bullmq-job-queue.d.ts.map +1 -1
  170. package/dist/server/kernel/bullmq-job-queue.js +8 -2
  171. package/dist/server/kernel/bullmq-job-queue.js.map +1 -1
  172. package/dist/server/runtime/__tests__/create-app.test.js +26 -18
  173. package/dist/server/runtime/__tests__/create-app.test.js.map +1 -1
  174. package/dist/testing/index.d.ts +2 -6
  175. package/dist/testing/index.d.ts.map +1 -1
  176. package/dist/testing/index.js +2 -10
  177. package/dist/testing/index.js.map +1 -1
  178. package/dist/testing/mock.d.ts +28 -16
  179. package/dist/testing/mock.d.ts.map +1 -1
  180. package/dist/testing/mock.js +58 -37
  181. package/dist/testing/mock.js.map +1 -1
  182. package/dist/testing/real-infra.d.ts +47 -0
  183. package/dist/testing/real-infra.d.ts.map +1 -0
  184. package/dist/testing/real-infra.js +122 -0
  185. package/dist/testing/real-infra.js.map +1 -0
  186. package/dist/wallet/__tests__/admin-reporting.test.js +201 -90
  187. package/dist/wallet/__tests__/admin-reporting.test.js.map +1 -1
  188. package/dist/wallet/__tests__/rail-for.test.d.ts +2 -0
  189. package/dist/wallet/__tests__/rail-for.test.d.ts.map +1 -0
  190. package/dist/wallet/__tests__/rail-for.test.js +22 -0
  191. package/dist/wallet/__tests__/rail-for.test.js.map +1 -0
  192. package/dist/wallet/__tests__/wallet-auto-rule.router.test.js +82 -63
  193. package/dist/wallet/__tests__/wallet-auto-rule.router.test.js.map +1 -1
  194. package/dist/wallet/__tests__/wallet-auto-withdrawal.test.js +414 -437
  195. package/dist/wallet/__tests__/wallet-auto-withdrawal.test.js.map +1 -1
  196. package/dist/wallet/__tests__/wallet-commands.service.test.js +116 -155
  197. package/dist/wallet/__tests__/wallet-commands.service.test.js.map +1 -1
  198. package/dist/wallet/__tests__/wallet-kyc-gate.test.js +63 -42
  199. package/dist/wallet/__tests__/wallet-kyc-gate.test.js.map +1 -1
  200. package/dist/wallet/__tests__/wallet-webhook.router.test.js +129 -51
  201. package/dist/wallet/__tests__/wallet-webhook.router.test.js.map +1 -1
  202. package/dist/wallet/__tests__/wallet.rate-limit.test.js +74 -21
  203. package/dist/wallet/__tests__/wallet.rate-limit.test.js.map +1 -1
  204. package/dist/wallet/__tests__/wallet.router.test.js +56 -36
  205. package/dist/wallet/__tests__/wallet.router.test.js.map +1 -1
  206. package/dist/wallet/__tests__/wallet.service.test.js +623 -887
  207. package/dist/wallet/__tests__/wallet.service.test.js.map +1 -1
  208. package/package.json +1 -2
  209. package/dist/casino/lobby/__tests__/lobby.service.test.d.ts +0 -2
  210. package/dist/casino/lobby/__tests__/lobby.service.test.d.ts.map +0 -1
  211. package/dist/casino/lobby/__tests__/lobby.service.test.js +0 -11
  212. package/dist/casino/lobby/__tests__/lobby.service.test.js.map +0 -1
  213. package/dist/contracts/schemas/__tests__/identity-schemas.test.d.ts +0 -2
  214. package/dist/contracts/schemas/__tests__/identity-schemas.test.d.ts.map +0 -1
  215. package/dist/contracts/schemas/__tests__/identity-schemas.test.js +0 -43
  216. package/dist/contracts/schemas/__tests__/identity-schemas.test.js.map +0 -1
  217. package/dist/testing/fakes/__tests__/cache.test.d.ts +0 -2
  218. package/dist/testing/fakes/__tests__/cache.test.d.ts.map +0 -1
  219. package/dist/testing/fakes/__tests__/cache.test.js +0 -89
  220. package/dist/testing/fakes/__tests__/cache.test.js.map +0 -1
  221. package/dist/testing/fakes/__tests__/job-queue.test.d.ts +0 -2
  222. package/dist/testing/fakes/__tests__/job-queue.test.d.ts.map +0 -1
  223. package/dist/testing/fakes/__tests__/job-queue.test.js +0 -135
  224. package/dist/testing/fakes/__tests__/job-queue.test.js.map +0 -1
  225. package/dist/testing/fakes/__tests__/rate-limiter.test.d.ts +0 -2
  226. package/dist/testing/fakes/__tests__/rate-limiter.test.d.ts.map +0 -1
  227. package/dist/testing/fakes/__tests__/rate-limiter.test.js +0 -83
  228. package/dist/testing/fakes/__tests__/rate-limiter.test.js.map +0 -1
  229. package/dist/testing/fakes/__tests__/realtime-authorizer.test.d.ts +0 -2
  230. package/dist/testing/fakes/__tests__/realtime-authorizer.test.d.ts.map +0 -1
  231. package/dist/testing/fakes/__tests__/realtime-authorizer.test.js +0 -19
  232. package/dist/testing/fakes/__tests__/realtime-authorizer.test.js.map +0 -1
  233. package/dist/testing/fakes/__tests__/realtime-transport.test.d.ts.map +0 -1
  234. package/dist/testing/fakes/cache.d.ts +0 -14
  235. package/dist/testing/fakes/cache.d.ts.map +0 -1
  236. package/dist/testing/fakes/cache.js +0 -56
  237. package/dist/testing/fakes/cache.js.map +0 -1
  238. package/dist/testing/fakes/event-bus.d.ts +0 -17
  239. package/dist/testing/fakes/event-bus.d.ts.map +0 -1
  240. package/dist/testing/fakes/event-bus.js +0 -30
  241. package/dist/testing/fakes/event-bus.js.map +0 -1
  242. package/dist/testing/fakes/job-queue.d.ts +0 -40
  243. package/dist/testing/fakes/job-queue.d.ts.map +0 -1
  244. package/dist/testing/fakes/job-queue.js +0 -200
  245. package/dist/testing/fakes/job-queue.js.map +0 -1
  246. package/dist/testing/fakes/rate-limiter.d.ts +0 -11
  247. package/dist/testing/fakes/rate-limiter.d.ts.map +0 -1
  248. package/dist/testing/fakes/rate-limiter.js +0 -39
  249. package/dist/testing/fakes/rate-limiter.js.map +0 -1
  250. package/dist/testing/fakes/realtime-authorizer.d.ts +0 -10
  251. package/dist/testing/fakes/realtime-authorizer.d.ts.map +0 -1
  252. package/dist/testing/fakes/realtime-authorizer.js +0 -10
  253. package/dist/testing/fakes/realtime-authorizer.js.map +0 -1
  254. package/dist/testing/fakes/realtime-transport.d.ts +0 -2
  255. package/dist/testing/fakes/realtime-transport.d.ts.map +0 -1
  256. package/dist/testing/fakes/realtime-transport.js +0 -2
  257. package/dist/testing/fakes/realtime-transport.js.map +0 -1
  258. /package/dist/{testing/fakes → server/kernel}/__tests__/realtime-transport.test.d.ts +0 -0
  259. /package/dist/{testing/fakes → server/kernel}/__tests__/realtime-transport.test.js +0 -0
@@ -1,133 +1,123 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { mock, mockDb } from '../../../testing/mock.js';
1
+ import { describe, it, expect, vi, 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 { mock, makeEventBus } from '../../../testing/mock.js';
3
6
  import { AdminGuard } from '../admin-guard.js';
4
- describe('AdminGuard - unauthorized access logging', () => {
5
- it('emits identity.user.unauthorized_access when dynamic permission check fails', async () => {
6
- const drizzle = mockDb({
7
- execute: vi.fn().mockResolvedValue({
8
- rows: [{ id: 'u1', role: 'admin' }],
9
- }),
10
- });
11
- const sessions = mock({
12
- resolveUserId: vi.fn().mockResolvedValue('u1'),
13
- });
14
- const permissionResolver = mock({
15
- getGrants: vi.fn().mockResolvedValue([]),
16
- });
17
- const events = mock({
18
- emit: vi.fn(),
19
- });
20
- const guard = new AdminGuard(drizzle, sessions, permissionResolver, events);
21
- const context = {
22
- request: {
23
- headers: {
24
- 'x-real-ip': '127.0.0.1',
25
- 'user-agent': 'Mozilla/5.0',
26
- },
27
- },
28
- };
29
- await expect(guard.assert(context, 'admin', 'delete')).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
30
- expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({
31
- userId: 'u1',
32
- resource: 'admin',
33
- action: 'delete',
7
+ let db;
8
+ const requestContext = (headers) => ({ request: { headers } });
9
+ const ADMIN_HEADERS = { 'x-real-ip': '127.0.0.1', 'user-agent': 'Mozilla/5.0' };
10
+ function makeGuard({ userId, grants, } = {}) {
11
+ const events = makeEventBus();
12
+ const sessions = mock({ resolveUserId: vi.fn(async () => userId) });
13
+ const permissionResolver = grants
14
+ ? mock({ getGrants: vi.fn(async () => grants) })
15
+ : undefined;
16
+ const guard = new AdminGuard(db.drizzle, sessions, permissionResolver, events);
17
+ return { guard, events };
18
+ }
19
+ async function seedUser(role) {
20
+ const id = randomUUID();
21
+ await db.drizzle.db.execute(sql `INSERT INTO "user" (id, role) VALUES (${id}, ${role})`);
22
+ return id;
23
+ }
24
+ beforeAll(async () => {
25
+ db = await createTestDb([
26
+ async (databaseUrl) => {
27
+ process.env['DATABASE_URL'] = databaseUrl;
28
+ },
29
+ ]);
30
+ await db.drizzle.db.execute(sql `CREATE TABLE "user" (id uuid PRIMARY KEY, role text NOT NULL)`);
31
+ });
32
+ afterAll(async () => {
33
+ await db.drop();
34
+ });
35
+ beforeEach(async () => {
36
+ await db.drizzle.db.execute(sql `TRUNCATE "user"`);
37
+ });
38
+ describe('AdminGuard.assert - authentication (real PG)', () => {
39
+ it('throws UNAUTHORIZED when the context carries no request', async () => {
40
+ const { guard } = makeGuard();
41
+ await expect(guard.assert({})).rejects.toThrow(expect.objectContaining({ code: 'UNAUTHORIZED' }));
42
+ });
43
+ it('throws UNAUTHORIZED when no session resolves', async () => {
44
+ const { guard, events } = makeGuard();
45
+ await expect(guard.assert(requestContext(ADMIN_HEADERS))).rejects.toThrow(expect.objectContaining({ code: 'UNAUTHORIZED' }));
46
+ expect(events.emit).not.toHaveBeenCalled();
47
+ });
48
+ it('throws FORBIDDEN and emits when the session points at a missing user row', async () => {
49
+ const userId = randomUUID();
50
+ const { guard, events } = makeGuard({ userId });
51
+ await expect(guard.assert(requestContext(ADMIN_HEADERS))).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
52
+ expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({ userId, resource: 'admin', action: 'access', role: undefined }));
53
+ });
54
+ });
55
+ describe('AdminGuard.assert - static role fallback (real PG)', () => {
56
+ it('returns the caller for an admin with a granted permission', async () => {
57
+ const userId = await seedUser('admin');
58
+ const { guard, events } = makeGuard({ userId });
59
+ const caller = await guard.assert(requestContext(ADMIN_HEADERS), 'admin', 'delete');
60
+ expect(caller).toMatchObject({
61
+ userId,
62
+ role: 'admin',
34
63
  ip: '127.0.0.1',
35
64
  userAgent: 'Mozilla/5.0',
36
- role: 'admin',
37
- }));
38
- });
39
- it('emits identity.user.unauthorized_access when static role permission check fails', async () => {
40
- const drizzle = mockDb({
41
- execute: vi.fn().mockResolvedValue({
42
- rows: [{ id: 'u1', role: 'support' }],
43
- }),
44
65
  });
45
- const sessions = mock({
46
- resolveUserId: vi.fn().mockResolvedValue('u1'),
47
- });
48
- const events = mock({
49
- emit: vi.fn(),
66
+ expect(events.emit).not.toHaveBeenCalled();
67
+ });
68
+ it('passes the coarse check for an admin with no resource requested', async () => {
69
+ const userId = await seedUser('admin');
70
+ const { guard } = makeGuard({ userId });
71
+ await expect(guard.assert(requestContext(ADMIN_HEADERS))).resolves.toMatchObject({
72
+ role: 'admin',
50
73
  });
51
- const guard = new AdminGuard(drizzle, sessions, undefined, events);
52
- const context = {
53
- request: {
54
- headers: {
55
- 'x-forwarded-for': '192.168.1.1, 10.0.0.1',
56
- 'user-agent': 'Mozilla/5.0',
57
- },
58
- },
59
- };
60
- await expect(guard.assert(context, 'admin', 'delete')).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
74
+ });
75
+ it('denies a support role a permission its static role lacks', async () => {
76
+ const userId = await seedUser('support');
77
+ const { guard, events } = makeGuard({ userId });
78
+ await expect(guard.assert(requestContext({ 'x-forwarded-for': '192.168.1.1, 10.0.0.1', 'user-agent': 'Mozilla/5.0' }), 'admin', 'delete')).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
61
79
  expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({
62
- userId: 'u1',
80
+ userId,
63
81
  resource: 'admin',
64
82
  action: 'delete',
65
83
  ip: '192.168.1.1',
66
- userAgent: 'Mozilla/5.0',
67
84
  role: 'support',
68
85
  }));
69
86
  });
70
- it('emits identity.user.unauthorized_access when user has no static role (e.g. player role)', async () => {
71
- const drizzle = mockDb({
72
- execute: vi.fn().mockResolvedValue({
73
- rows: [{ id: 'u1', role: 'player' }],
74
- }),
75
- });
76
- const sessions = mock({
77
- resolveUserId: vi.fn().mockResolvedValue('u1'),
78
- });
79
- const events = mock({
80
- emit: vi.fn(),
81
- });
82
- const guard = new AdminGuard(drizzle, sessions, undefined, events);
83
- const context = {
84
- request: {
85
- headers: {
86
- 'x-real-ip': '127.0.0.1',
87
- 'user-agent': 'Mozilla/5.0',
88
- },
89
- },
90
- };
91
- await expect(guard.assert(context, 'admin', 'delete')).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
92
- expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({
93
- userId: 'u1',
94
- resource: 'admin',
95
- action: 'delete',
96
- ip: '127.0.0.1',
97
- userAgent: 'Mozilla/5.0',
98
- role: 'player',
99
- }));
87
+ it('allows a support role the permissions it does hold', async () => {
88
+ const userId = await seedUser('support');
89
+ const { guard } = makeGuard({ userId });
90
+ await expect(guard.assert(requestContext(ADMIN_HEADERS), 'player', 'view')).resolves.toMatchObject({ role: 'support' });
100
91
  });
101
- it('emits identity.user.unauthorized_access with default admin:access when coarse check fails for player role', async () => {
102
- const drizzle = mockDb({
103
- execute: vi.fn().mockResolvedValue({
104
- rows: [{ id: 'u1', role: 'player' }],
105
- }),
106
- });
107
- const sessions = mock({
108
- resolveUserId: vi.fn().mockResolvedValue('u1'),
109
- });
110
- const events = mock({
111
- emit: vi.fn(),
112
- });
113
- const guard = new AdminGuard(drizzle, sessions, undefined, events);
114
- const context = {
115
- request: {
116
- headers: {
117
- 'x-real-ip': '127.0.0.1',
118
- 'user-agent': 'Mozilla/5.0',
119
- },
120
- },
121
- };
122
- await expect(guard.assert(context)).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
123
- expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({
124
- userId: 'u1',
125
- resource: 'admin',
126
- action: 'access',
127
- ip: '127.0.0.1',
128
- userAgent: 'Mozilla/5.0',
129
- role: 'player',
130
- }));
92
+ it('denies a role with no entry in the static table', async () => {
93
+ const userId = await seedUser('player');
94
+ const { guard, events } = makeGuard({ userId });
95
+ await expect(guard.assert(requestContext(ADMIN_HEADERS), 'admin', 'delete')).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
96
+ expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({ userId, role: 'player', action: 'delete' }));
97
+ });
98
+ it('denies the coarse check for a non-admin role with the default admin:access pair', async () => {
99
+ const userId = await seedUser('player');
100
+ const { guard, events } = makeGuard({ userId });
101
+ await expect(guard.assert(requestContext(ADMIN_HEADERS))).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
102
+ expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({ resource: 'admin', action: 'access', role: 'player' }));
103
+ });
104
+ });
105
+ describe('AdminGuard.assert - DB grants (real PG)', () => {
106
+ it('allows a permission the resolver grants', async () => {
107
+ const userId = await seedUser('admin');
108
+ const { guard } = makeGuard({ userId, grants: [{ resource: 'admin', action: 'delete' }] });
109
+ await expect(guard.assert(requestContext(ADMIN_HEADERS), 'admin', 'delete')).resolves.toMatchObject({ userId });
110
+ });
111
+ it('denies and emits when the resolver returns no matching grant', async () => {
112
+ const userId = await seedUser('admin');
113
+ const { guard, events } = makeGuard({ userId, grants: [] });
114
+ await expect(guard.assert(requestContext(ADMIN_HEADERS), 'admin', 'delete')).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
115
+ expect(events.emit).toHaveBeenCalledWith('identity.user.unauthorized_access', expect.objectContaining({ userId, resource: 'admin', action: 'delete', role: 'admin' }));
116
+ });
117
+ it('lets DB grants override what the static role would have allowed', async () => {
118
+ const userId = await seedUser('admin');
119
+ const { guard } = makeGuard({ userId, grants: [{ resource: 'player', action: 'view' }] });
120
+ await expect(guard.assert(requestContext(ADMIN_HEADERS), 'admin', 'delete')).rejects.toThrow(expect.objectContaining({ code: 'FORBIDDEN' }));
131
121
  });
132
122
  });
133
123
  //# sourceMappingURL=admin-guard.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin-guard.test.js","sourceRoot":"","sources":["../../../../src/server/auth/__tests__/admin-guard.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"admin-guard.test.js","sourceRoot":"","sources":["../../../../src/server/auth/__tests__/admin-guard.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=permission-levels.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-levels.test.d.ts","sourceRoot":"","sources":["../../../../src/server/auth/__tests__/permission-levels.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { levelRank, isLevelSufficient, levelToActions, actionsToLevel, PERMISSION_LEVELS, } from '../permission-levels.js';
3
+ import { statement } from '../permissions.js';
4
+ describe('levelRank', () => {
5
+ it('orders the levels from no_access up to read_write', () => {
6
+ expect(PERMISSION_LEVELS.map(levelRank)).toEqual([0, 1, 2]);
7
+ });
8
+ it('ranks an unknown level below every real one so it can never satisfy a check', () => {
9
+ expect(levelRank('owner')).toBe(-1);
10
+ });
11
+ });
12
+ describe('isLevelSufficient', () => {
13
+ it.each([
14
+ ['no_access', 'no_access', true],
15
+ ['no_access', 'read', false],
16
+ ['no_access', 'read_write', false],
17
+ ['read', 'no_access', true],
18
+ ['read', 'read', true],
19
+ ['read', 'read_write', false],
20
+ ['read_write', 'no_access', true],
21
+ ['read_write', 'read', true],
22
+ ['read_write', 'read_write', true],
23
+ ])('%s covering %s is %s', (have, required, expected) => {
24
+ expect(isLevelSufficient(have, required)).toBe(expected);
25
+ });
26
+ it('refuses to escalate an unknown level', () => {
27
+ expect(isLevelSufficient('owner', 'read')).toBe(false);
28
+ });
29
+ });
30
+ describe('levelToActions', () => {
31
+ it('grants nothing at no_access, whatever the resource', () => {
32
+ for (const resource of Object.keys(statement)) {
33
+ expect(levelToActions(resource, 'no_access')).toEqual([]);
34
+ }
35
+ });
36
+ it('grants every declared action at read_write', () => {
37
+ for (const [resource, actions] of Object.entries(statement)) {
38
+ expect(levelToActions(resource, 'read_write')).toEqual(actions);
39
+ }
40
+ });
41
+ it('grants only view at read', () => {
42
+ expect(levelToActions('player', 'read')).toEqual(['view']);
43
+ expect(levelToActions('withdrawal', 'read')).toEqual(['view']);
44
+ });
45
+ it('grants nothing at read for a resource that declares no view action', () => {
46
+ expect(statement.content).not.toContain('view');
47
+ expect(levelToActions('content', 'read')).toEqual([]);
48
+ });
49
+ it.each(PERMISSION_LEVELS)('grants nothing on an unknown resource at %s', (level) => {
50
+ expect(levelToActions('tournaments', level)).toEqual([]);
51
+ });
52
+ it('never returns an action the resource does not declare', () => {
53
+ for (const [resource, actions] of Object.entries(statement)) {
54
+ for (const level of PERMISSION_LEVELS) {
55
+ expect(actions).toEqual(expect.arrayContaining([...levelToActions(resource, level)]));
56
+ }
57
+ }
58
+ });
59
+ });
60
+ describe('actionsToLevel', () => {
61
+ it('round-trips every level for every resource that can express it', () => {
62
+ for (const [resource, actions] of Object.entries(statement)) {
63
+ const viewOnlyResource = actions.length === 1 && actions[0] === 'view';
64
+ for (const level of PERMISSION_LEVELS) {
65
+ const granted = levelToActions(resource, level);
66
+ const expected = granted.length === 0 ? 'no_access' : viewOnlyResource ? 'read_write' : level;
67
+ expect(actionsToLevel(resource, granted)).toBe(expected);
68
+ }
69
+ }
70
+ });
71
+ it('cannot tell read from read_write on a resource whose only action is view', () => {
72
+ expect(statement.report).toEqual(['view']);
73
+ expect(actionsToLevel('report', ['view'])).toBe('read_write');
74
+ });
75
+ it('collapses a partial action set down, never up', () => {
76
+ expect(actionsToLevel('player', ['view', 'update'])).toBe('read');
77
+ expect(actionsToLevel('player', ['update', 'ban'])).toBe('no_access');
78
+ });
79
+ it('reports no_access for an unknown resource', () => {
80
+ expect(actionsToLevel('tournaments', ['view'])).toBe('no_access');
81
+ });
82
+ it('reports no_access for an empty action set', () => {
83
+ expect(actionsToLevel('player', [])).toBe('no_access');
84
+ });
85
+ it('ignores actions the resource does not declare', () => {
86
+ expect(actionsToLevel('report', ['view', 'delete-everything'])).toBe('read_write');
87
+ });
88
+ });
89
+ //# sourceMappingURL=permission-levels.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-levels.test.js","sourceRoot":"","sources":["../../../../src/server/auth/__tests__/permission-levels.test.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,59 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { mockDb } from '../../../testing/mock.js';
1
+ import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from 'vitest';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { createTestDb } from '@openora/core/testing';
3
4
  import { SessionResolver } from '../session-resolver.js';
4
- const { getSessionMock } = vi.hoisted(() => ({
5
- getSessionMock: vi.fn().mockResolvedValue(null),
5
+ const { createAuthMock, getSessionMock } = vi.hoisted(() => ({
6
+ createAuthMock: vi.fn(),
7
+ getSessionMock: vi.fn(),
6
8
  }));
7
9
  vi.mock('../auth.js', () => ({
8
- createAuth: vi.fn(() => ({ api: { getSession: getSessionMock } })),
10
+ createAuth: createAuthMock.mockImplementation(() => ({
11
+ api: { getSession: getSessionMock },
12
+ })),
9
13
  }));
14
+ let db;
15
+ beforeAll(async () => {
16
+ db = await createTestDb([]);
17
+ });
18
+ afterAll(async () => {
19
+ await db.drop();
20
+ });
10
21
  beforeEach(() => {
22
+ createAuthMock.mockClear();
11
23
  getSessionMock.mockClear();
12
24
  getSessionMock.mockResolvedValue(null);
13
25
  });
14
- describe('SessionResolver.resolveUserId', () => {
26
+ describe('SessionResolver (real PG-backed drizzle)', () => {
27
+ it('hands the drizzle db and the injected schema to better-auth exactly once', () => {
28
+ const schema = { session: {} };
29
+ new SessionResolver(db.drizzle, schema);
30
+ expect(createAuthMock).toHaveBeenCalledTimes(1);
31
+ expect(createAuthMock).toHaveBeenCalledWith({ db: db.drizzle.db, schema });
32
+ });
33
+ it('omits the schema key when none is injected', () => {
34
+ new SessionResolver(db.drizzle);
35
+ expect(createAuthMock).toHaveBeenCalledWith({ db: db.drizzle.db });
36
+ });
15
37
  it('returns undefined when there is no session', async () => {
16
- const resolver = new SessionResolver(mockDb({}));
17
- const userId = await resolver.resolveUserId(new Headers());
18
- expect(userId).toBeUndefined();
38
+ const resolver = new SessionResolver(db.drizzle);
39
+ expect(await resolver.resolveUserId(new Headers())).toBeUndefined();
19
40
  });
20
41
  it('returns the user id when a session resolves', async () => {
21
- getSessionMock.mockResolvedValueOnce({ user: { id: 'u1' } });
22
- const resolver = new SessionResolver(mockDb({}));
23
- const userId = await resolver.resolveUserId(new Headers());
24
- expect(userId).toBe('u1');
42
+ const userId = randomUUID();
43
+ getSessionMock.mockResolvedValueOnce({ user: { id: userId } });
44
+ const resolver = new SessionResolver(db.drizzle);
45
+ expect(await resolver.resolveUserId(new Headers())).toBe(userId);
46
+ });
47
+ it('forwards the caller headers to better-auth', async () => {
48
+ const resolver = new SessionResolver(db.drizzle);
49
+ const headers = new Headers({ cookie: 'session=abc' });
50
+ await resolver.resolveUserId(headers);
51
+ expect(getSessionMock).toHaveBeenCalledWith({ headers });
52
+ });
53
+ it('returns undefined for a session without a user', async () => {
54
+ getSessionMock.mockResolvedValueOnce({});
55
+ const resolver = new SessionResolver(db.drizzle);
56
+ expect(await resolver.resolveUserId(new Headers())).toBeUndefined();
25
57
  });
26
58
  });
27
59
  //# sourceMappingURL=session-resolver.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-resolver.test.js","sourceRoot":"","sources":["../../../../src/server/auth/__tests__/session-resolver.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC;CAChD,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3B,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;CACnE,CAAC,CAAC,CAAC;AAEJ,UAAU,CAAC,GAAG,EAAE;IACd,cAAc,CAAC,SAAS,EAAE,CAAC;IAC3B,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAEjD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;QAE3D,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,cAAc,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAEjD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;QAE3D,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"session-resolver.test.js","sourceRoot":"","sources":["../../../../src/server/auth/__tests__/session-resolver.test.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { findOneOrThrow, pageToOffset } from '../query-helpers.js';
2
+ import { findOneOrThrow, pageToOffset, moneyToNumber, mapConcurrent } from '../query-helpers.js';
3
3
  describe('findOneOrThrow', () => {
4
4
  it('returns the first row when present', () => {
5
5
  expect(findOneOrThrow([{ id: '1' }, { id: '2' }], new Error('nope'))).toEqual({ id: '1' });
@@ -15,4 +15,75 @@ describe('pageToOffset', () => {
15
15
  expect(pageToOffset(3, 20)).toBe(40);
16
16
  });
17
17
  });
18
+ describe('moneyToNumber', () => {
19
+ it('reads a decimal money string', () => {
20
+ expect(moneyToNumber('100.50')).toBe(100.5);
21
+ });
22
+ it('reads a whole amount', () => {
23
+ expect(moneyToNumber('100')).toBe(100);
24
+ });
25
+ it('reads a zero amount', () => {
26
+ expect(moneyToNumber('0')).toBe(0);
27
+ expect(moneyToNumber('0.00')).toBe(0);
28
+ });
29
+ it('reads a negative amount', () => {
30
+ expect(moneyToNumber('-25.75')).toBe(-25.75);
31
+ });
32
+ it('keeps the ordering of two amounts that differ lexicographically', () => {
33
+ expect(moneyToNumber('9.00')).toBeLessThan(moneyToNumber('10.00'));
34
+ });
35
+ it('returns NaN for a non-numeric string rather than silently zeroing it', () => {
36
+ expect(moneyToNumber('abc')).toBeNaN();
37
+ });
38
+ });
39
+ describe('mapConcurrent', () => {
40
+ const identity = async (n) => n * 2;
41
+ it('returns results in input order, not completion order', async () => {
42
+ const delays = [30, 5, 20, 1];
43
+ const result = await mapConcurrent(delays, 2, async (ms, index) => {
44
+ await new Promise((resolve) => setTimeout(resolve, ms));
45
+ return index;
46
+ });
47
+ expect(result).toEqual([0, 1, 2, 3]);
48
+ });
49
+ it('passes the index alongside each item', async () => {
50
+ const seen = [];
51
+ await mapConcurrent(['a', 'b', 'c'], 2, async (item, index) => {
52
+ seen.push([item, index]);
53
+ });
54
+ expect(seen).toEqual([
55
+ ['a', 0],
56
+ ['b', 1],
57
+ ['c', 2],
58
+ ]);
59
+ });
60
+ it('never runs more than `concurrency` calls at once', async () => {
61
+ let inFlight = 0;
62
+ let peak = 0;
63
+ await mapConcurrent(Array.from({ length: 20 }, (_, i) => i), 3, async () => {
64
+ inFlight += 1;
65
+ peak = Math.max(peak, inFlight);
66
+ await new Promise((resolve) => setTimeout(resolve, 1));
67
+ inFlight -= 1;
68
+ });
69
+ expect(peak).toBe(3);
70
+ });
71
+ it('handles an empty list without spawning a worker', async () => {
72
+ expect(await mapConcurrent([], 5, identity)).toEqual([]);
73
+ });
74
+ it('caps the worker count at the item count', async () => {
75
+ expect(await mapConcurrent([1, 2], 100, identity)).toEqual([2, 4]);
76
+ });
77
+ it('runs serially when concurrency is below 1', async () => {
78
+ expect(await mapConcurrent([1, 2, 3], 0, identity)).toEqual([2, 4, 6]);
79
+ });
80
+ it('rejects when any item rejects', async () => {
81
+ await expect(mapConcurrent([1, 2, 3], 2, async (n) => {
82
+ if (n === 2) {
83
+ throw new Error('item 2 failed');
84
+ }
85
+ return n;
86
+ })).rejects.toThrow('item 2 failed');
87
+ });
88
+ });
18
89
  //# sourceMappingURL=query-helpers.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-helpers.test.js","sourceRoot":"","sources":["../../../../src/server/db/__tests__/query-helpers.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnE,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"query-helpers.test.js","sourceRoot":"","sources":["../../../../src/server/db/__tests__/query-helpers.test.ts"],"names":[],"mappings":"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"}