@openora/core 0.4.1-canary.126 → 0.4.1-canary.128

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 (145) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/admin-console/plugin.d.ts +3 -0
  3. package/dist/admin-console/plugin.d.ts.map +1 -1
  4. package/dist/analytics/plugin.d.ts +3 -0
  5. package/dist/analytics/plugin.d.ts.map +1 -1
  6. package/dist/audit/plugin.d.ts +3 -0
  7. package/dist/audit/plugin.d.ts.map +1 -1
  8. package/dist/casino/gaming/plugin.d.ts +3 -0
  9. package/dist/casino/gaming/plugin.d.ts.map +1 -1
  10. package/dist/casino/lobby/plugin.d.ts +3 -0
  11. package/dist/casino/lobby/plugin.d.ts.map +1 -1
  12. package/dist/cms/plugin.d.ts +3 -0
  13. package/dist/cms/plugin.d.ts.map +1 -1
  14. package/dist/compliance/plugin.d.ts +3 -0
  15. package/dist/compliance/plugin.d.ts.map +1 -1
  16. package/dist/contracts/adapters/audit.d.ts +1 -1
  17. package/dist/contracts/adapters/audit.d.ts.map +1 -1
  18. package/dist/contracts/adapters/audit.js.map +1 -1
  19. package/dist/contracts/adapters/player-provisioning.d.ts +8 -0
  20. package/dist/contracts/adapters/player-provisioning.d.ts.map +1 -1
  21. package/dist/contracts/adapters/player-provisioning.js.map +1 -1
  22. package/dist/contracts/schemas/__tests__/common-schemas.test.js +26 -1
  23. package/dist/contracts/schemas/__tests__/common-schemas.test.js.map +1 -1
  24. package/dist/contracts/schemas/common.d.ts +14 -0
  25. package/dist/contracts/schemas/common.d.ts.map +1 -1
  26. package/dist/contracts/schemas/common.js +22 -0
  27. package/dist/contracts/schemas/common.js.map +1 -1
  28. package/dist/contracts/schemas/identity.d.ts +5 -0
  29. package/dist/contracts/schemas/identity.d.ts.map +1 -1
  30. package/dist/contracts/schemas/identity.js +8 -1
  31. package/dist/contracts/schemas/identity.js.map +1 -1
  32. package/dist/contracts/schemas/platform-config.d.ts +24 -0
  33. package/dist/contracts/schemas/platform-config.d.ts.map +1 -1
  34. package/dist/contracts/schemas/platform-config.js +29 -0
  35. package/dist/contracts/schemas/platform-config.js.map +1 -1
  36. package/dist/contracts/schemas/player.d.ts +6 -0
  37. package/dist/contracts/schemas/player.d.ts.map +1 -1
  38. package/dist/contracts/schemas/player.js +9 -1
  39. package/dist/contracts/schemas/player.js.map +1 -1
  40. package/dist/engagement/chat/__tests__/chat-moderation-expiry.int.test.d.ts +2 -0
  41. package/dist/engagement/chat/__tests__/chat-moderation-expiry.int.test.d.ts.map +1 -0
  42. package/dist/engagement/chat/__tests__/chat-moderation-expiry.int.test.js +155 -0
  43. package/dist/engagement/chat/__tests__/chat-moderation-expiry.int.test.js.map +1 -0
  44. package/dist/engagement/chat/__tests__/chat-mute-listing.int.test.d.ts +2 -0
  45. package/dist/engagement/chat/__tests__/chat-mute-listing.int.test.d.ts.map +1 -0
  46. package/dist/engagement/chat/__tests__/chat-mute-listing.int.test.js +81 -0
  47. package/dist/engagement/chat/__tests__/chat-mute-listing.int.test.js.map +1 -0
  48. package/dist/engagement/chat/drizzle/migrations/0014_chat_moderation_expiry_recorded.sql +19 -0
  49. package/dist/engagement/chat/drizzle/migrations/meta/0014_snapshot.json +1544 -0
  50. package/dist/engagement/chat/drizzle/migrations/meta/_journal.json +7 -0
  51. package/dist/engagement/chat/plugin.d.ts +3 -0
  52. package/dist/engagement/chat/plugin.d.ts.map +1 -1
  53. package/dist/engagement/chat/plugin.js +31 -1
  54. package/dist/engagement/chat/plugin.js.map +1 -1
  55. package/dist/engagement/chat/schema/index.d.ts +34 -0
  56. package/dist/engagement/chat/schema/index.d.ts.map +1 -1
  57. package/dist/engagement/chat/schema/index.js +3 -0
  58. package/dist/engagement/chat/schema/index.js.map +1 -1
  59. package/dist/engagement/chat/service/chat-ban.service.d.ts.map +1 -1
  60. package/dist/engagement/chat/service/chat-ban.service.js +7 -2
  61. package/dist/engagement/chat/service/chat-ban.service.js.map +1 -1
  62. package/dist/engagement/chat/service/chat-moderation-expiry.service.d.ts +22 -0
  63. package/dist/engagement/chat/service/chat-moderation-expiry.service.d.ts.map +1 -0
  64. package/dist/engagement/chat/service/chat-moderation-expiry.service.js +80 -0
  65. package/dist/engagement/chat/service/chat-moderation-expiry.service.js.map +1 -0
  66. package/dist/engagement/chat/service/chat-mute.service.d.ts.map +1 -1
  67. package/dist/engagement/chat/service/chat-mute.service.js +10 -2
  68. package/dist/engagement/chat/service/chat-mute.service.js.map +1 -1
  69. package/dist/engagement/chat-commands/plugin.d.ts +3 -0
  70. package/dist/engagement/chat-commands/plugin.d.ts.map +1 -1
  71. package/dist/engagement/notifications/plugin.d.ts +3 -0
  72. package/dist/engagement/notifications/plugin.d.ts.map +1 -1
  73. package/dist/engagement/social/plugin.d.ts +3 -0
  74. package/dist/engagement/social/plugin.d.ts.map +1 -1
  75. package/dist/fx/exchange-rate/plugin.d.ts +3 -0
  76. package/dist/fx/exchange-rate/plugin.d.ts.map +1 -1
  77. package/dist/iam/plugin.d.ts +3 -0
  78. package/dist/iam/plugin.d.ts.map +1 -1
  79. package/dist/pam/identity/contract/index.d.ts +5 -0
  80. package/dist/pam/identity/contract/index.d.ts.map +1 -1
  81. package/dist/pam/identity/plugin.d.ts +3 -0
  82. package/dist/pam/identity/plugin.d.ts.map +1 -1
  83. package/dist/pam/identity/plugin.js +1 -0
  84. package/dist/pam/identity/plugin.js.map +1 -1
  85. package/dist/pam/identity/react/account.d.ts +2 -0
  86. package/dist/pam/identity/react/account.d.ts.map +1 -1
  87. package/dist/pam/identity/react/auth.d.ts +2 -0
  88. package/dist/pam/identity/react/auth.d.ts.map +1 -1
  89. package/dist/pam/identity/router/index.d.ts +5 -0
  90. package/dist/pam/identity/router/index.d.ts.map +1 -1
  91. package/dist/pam/identity/service/capture-timezone.service.d.ts +10 -0
  92. package/dist/pam/identity/service/capture-timezone.service.d.ts.map +1 -0
  93. package/dist/pam/identity/service/capture-timezone.service.js +21 -0
  94. package/dist/pam/identity/service/capture-timezone.service.js.map +1 -0
  95. package/dist/pam/identity/service/identity.service.d.ts.map +1 -1
  96. package/dist/pam/identity/service/identity.service.js +9 -0
  97. package/dist/pam/identity/service/identity.service.js.map +1 -1
  98. package/dist/pam/identity/service/phone-login.service.d.ts +4 -2
  99. package/dist/pam/identity/service/phone-login.service.d.ts.map +1 -1
  100. package/dist/pam/identity/service/phone-login.service.js +7 -2
  101. package/dist/pam/identity/service/phone-login.service.js.map +1 -1
  102. package/dist/pam/player-management/contract/index.d.ts +10 -0
  103. package/dist/pam/player-management/contract/index.d.ts.map +1 -1
  104. package/dist/pam/player-management/plugin.d.ts +3 -0
  105. package/dist/pam/player-management/plugin.d.ts.map +1 -1
  106. package/dist/pam/player-management/router/index.d.ts +8 -0
  107. package/dist/pam/player-management/router/index.d.ts.map +1 -1
  108. package/dist/pam/player-management/service/player.service.d.ts +10 -0
  109. package/dist/pam/player-management/service/player.service.d.ts.map +1 -1
  110. package/dist/pam/player-note/plugin.d.ts +3 -0
  111. package/dist/pam/player-note/plugin.d.ts.map +1 -1
  112. package/dist/pam/profile/__tests__/profile.service.int.test.js +75 -0
  113. package/dist/pam/profile/__tests__/profile.service.int.test.js.map +1 -1
  114. package/dist/pam/profile/contract/index.d.ts +5 -0
  115. package/dist/pam/profile/contract/index.d.ts.map +1 -1
  116. package/dist/pam/profile/drizzle/migrations/0005_moaning_rachel_grey.sql +2 -0
  117. package/dist/pam/profile/drizzle/migrations/meta/0005_snapshot.json +242 -0
  118. package/dist/pam/profile/drizzle/migrations/meta/_journal.json +7 -0
  119. package/dist/pam/profile/plugin.d.ts +3 -0
  120. package/dist/pam/profile/plugin.d.ts.map +1 -1
  121. package/dist/pam/profile/react/profile.d.ts +5 -0
  122. package/dist/pam/profile/react/profile.d.ts.map +1 -1
  123. package/dist/pam/profile/router/index.d.ts +5 -0
  124. package/dist/pam/profile/router/index.d.ts.map +1 -1
  125. package/dist/pam/profile/schema/index.d.ts +34 -0
  126. package/dist/pam/profile/schema/index.d.ts.map +1 -1
  127. package/dist/pam/profile/schema/index.js +5 -0
  128. package/dist/pam/profile/schema/index.js.map +1 -1
  129. package/dist/pam/profile/service/profile.service.d.ts +11 -0
  130. package/dist/pam/profile/service/profile.service.d.ts.map +1 -1
  131. package/dist/pam/profile/service/profile.service.js +30 -5
  132. package/dist/pam/profile/service/profile.service.js.map +1 -1
  133. package/dist/pam/shared/player-mapper.d.ts +2 -0
  134. package/dist/pam/shared/player-mapper.d.ts.map +1 -1
  135. package/dist/pam/shared/player-mapper.js +2 -0
  136. package/dist/pam/shared/player-mapper.js.map +1 -1
  137. package/dist/pam/tag/plugin.d.ts +3 -0
  138. package/dist/pam/tag/plugin.d.ts.map +1 -1
  139. package/dist/server/runtime/core-token-catalog.d.ts +3 -0
  140. package/dist/server/runtime/core-token-catalog.d.ts.map +1 -1
  141. package/dist/testing/seed-player.d.ts +2 -0
  142. package/dist/testing/seed-player.d.ts.map +1 -1
  143. package/dist/wallet/plugin.d.ts +3 -0
  144. package/dist/wallet/plugin.d.ts.map +1 -1
  145. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../../src/contracts/schemas/player.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAOzB,eAAO,MAAM,eAAe,wEAMlB,CAAC;AACX,eAAO,MAAM,kBAAkB;;;;;;EAA0B,CAAC;AAE1D,eAAO,MAAM,YAAY,0HAQf,CAAC;AACX,eAAO,MAAM,eAAe;;;;;;;;EAAuB,CAAC;AAEpD,eAAO,MAAM,SAAS,gCAAiC,CAAC;AACxD,eAAO,MAAM,aAAa;;;EAAoB,CAAC;AAC/C,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,kBAAkB,sDAAuD,CAAC;AACvF,eAAO,MAAM,qBAAqB;;;;;EAA6B,CAAC;AAChE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAE/D;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBvB,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKjC,CAAC;AAEH,eAAO,MAAM,qBAAqB,mHASxB,CAAC;AACX,eAAO,MAAM,kBAAkB;;;;;;;;;GAAqD,CAAC;AACrF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAK1C,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAE5F,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAa,GAAG,OAAO,CAMjF;AAED;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B;;;;;;;iBAiBvC,CAAC;AAEL,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC"}
1
+ {"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../../src/contracts/schemas/player.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAOzB,eAAO,MAAM,eAAe,wEAMlB,CAAC;AACX,eAAO,MAAM,kBAAkB;;;;;;EAA0B,CAAC;AAE1D,eAAO,MAAM,YAAY,0HAQf,CAAC;AACX,eAAO,MAAM,eAAe;;;;;;;;EAAuB,CAAC;AAEpD,eAAO,MAAM,SAAS,gCAAiC,CAAC;AACxD,eAAO,MAAM,aAAa;;;EAAoB,CAAC;AAC/C,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,kBAAkB,sDAAuD,CAAC;AACvF,eAAO,MAAM,qBAAqB;;;;;EAA6B,CAAC;AAChE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAE/D;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuBvB,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKjC,CAAC;AAEH,eAAO,MAAM,qBAAqB,mHASxB,CAAC;AACX,eAAO,MAAM,kBAAkB;;;;;;;;;GAAqD,CAAC;AACrF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAK1C,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAE5F,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAa,GAAG,OAAO,CAMjF;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;iBAkBvC,CAAC;AAEL,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import * as z from 'zod';
2
- import { MoneyAmountSchema, TimestampSchema, UuidSchema } from './common.js';
2
+ import { MoneyAmountSchema, TimestampSchema, TimezoneSchema, UuidSchema } from './common.js';
3
3
  import { CountryCodeSchema, CurrencyCodeSchema } from './igaming-config.js';
4
4
  import { E164PhoneSchema } from './identity.js';
5
5
  import { TagKeySchema } from './tag.js';
@@ -54,6 +54,10 @@ export const PlayerSchema = z.object({
54
54
  totalWagered: MoneyAmountSchema,
55
55
  totalDeposits: MoneyAmountSchema,
56
56
  lastSeenAt: z.string().nullable(),
57
+ // The IANA zone the player's browser last reported; null until a device reports one.
58
+ timezone: TimezoneSchema.nullable(),
59
+ // Last confirmed by a device, not last changed: it moves on every accepted capture.
60
+ timezoneUpdatedAt: TimestampSchema.nullable(),
57
61
  createdAt: TimestampSchema,
58
62
  updatedAt: TimestampSchema,
59
63
  });
@@ -98,6 +102,9 @@ export function isAdultDateOfBirth(dateOfBirth, now = new Date()) {
98
102
  * phones. `null` clears a field; omitting it leaves the stored value alone. `phone` is the
99
103
  * player's self-declared contact number - the verified login credential lives on the
100
104
  * identity module's `user.phoneNumber` and is never written from here.
105
+ *
106
+ * `timezone` is the odd one out: not nullable (worth capturing, never worth clearing) and
107
+ * written by `recordTimezone` rather than by the field update.
101
108
  */
102
109
  export const UpdatePlayerProfileInputSchema = z
103
110
  .object({
@@ -112,6 +119,7 @@ export const UpdatePlayerProfileInputSchema = z
112
119
  phone: E164PhoneSchema.nullable(),
113
120
  country: CountryCodeSchema.nullable(),
114
121
  currency: CurrencyCodeSchema,
122
+ timezone: TimezoneSchema,
115
123
  })
116
124
  .partial()
117
125
  .refine((v) => Object.values(v).some((x) => x !== undefined), {
@@ -1 +1 @@
1
- {"version":3,"file":"player.js","sourceRoot":"","sources":["../../../src/contracts/schemas/player.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"player.js","sourceRoot":"","sources":["../../../src/contracts/schemas/player.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE7D,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,QAAQ;IACR,SAAS;IACT,eAAe;IACf,WAAW;IACX,QAAQ;CACA,CAAC;AACX,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAE1D,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,aAAa;IACb,SAAS;IACT,UAAU;IACV,UAAU;IACV,UAAU;IACV,wBAAwB;IACxB,qBAAqB;CACb,CAAC;AACX,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,UAAU,CAAU,CAAC;AACxD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAG/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAU,CAAC;AACvF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;AAGhE;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,EAAE,EAAE,UAAU;IACd,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACpC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,kBAAkB;IAC1B,SAAS,EAAE,eAAe;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACvB,YAAY,EAAE,iBAAiB;IAC/B,aAAa,EAAE,iBAAiB;IAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,qFAAqF;IACrF,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE;IACnC,oFAAoF;IACpF,iBAAiB,EAAE,eAAe,CAAC,QAAQ,EAAE;IAC7C,SAAS,EAAE,eAAe;IAC1B,SAAS,EAAE,eAAe;CAC3B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,MAAM,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACrC,SAAS,EAAE,eAAe,CAAC,QAAQ,EAAE;IACrC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,WAAW;IACX,UAAU;IACV,QAAQ;IACR,WAAW;IACX,cAAc;IACd,eAAe;IACf,YAAY;IACZ,OAAO;CACC,CAAC;AACX,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAGrF,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC;IACtD,GAAG,sBAAsB,CAAC,KAAK;IAC/B,GAAG,eAAe,CAAC,KAAK;IACxB,MAAM,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACrC,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;CACtD,CAAC,CAAC;AAQH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;IACtE,MAAM,MAAM,GACV,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,oBAAoB,CAAC,GAAG,MAAM;QACtD,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG;QAC7B,GAAG,CAAC,UAAU,EAAE,CAAC;IACnB,OAAO,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC;KAC5C,MAAM,CAAC;IACN,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAChD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC/C,WAAW,EAAE,CAAC,CAAC,GAAG;SACf,IAAI,EAAE;SACN,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QAC5C,OAAO,EAAE,2BAA2B,oBAAoB,YAAY;KACrE,CAAC;SACD,QAAQ,EAAE;IACb,KAAK,EAAE,eAAe,CAAC,QAAQ,EAAE;IACjC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACrC,QAAQ,EAAE,kBAAkB;IAC5B,QAAQ,EAAE,cAAc;CACzB,CAAC;KACD,OAAO,EAAE;KACT,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,EAAE;IAC5D,OAAO,EAAE,sCAAsC;CAChD,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chat-moderation-expiry.int.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-moderation-expiry.int.test.d.ts","sourceRoot":"","sources":["../../../../src/engagement/chat/__tests__/chat-moderation-expiry.int.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,155 @@
1
+ import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { eq, sql } from 'drizzle-orm';
4
+ import { createTestDb } from '@openora/core/testing';
5
+ import { auditLog } from '@openora/core/audit/schema';
6
+ import { migrate as migrateAudit } from '@openora/core/audit/migrate';
7
+ import { AuditService } from '@openora/core/audit/server';
8
+ import { makeEventBus, makeIdentityReader, mock, NO_CLIENT_META } from '../../../testing/mock.js';
9
+ import { migrate } from '../migrate.js';
10
+ import { chatMute, chatPlatformBan } from '../schema/index.js';
11
+ import { ChatModerationExpiryService } from '../service/chat-moderation-expiry.service.js';
12
+ import { ChatModerationService } from '../service/chat-moderation.service.js';
13
+ let db;
14
+ let audit;
15
+ const ADMIN_ID = randomUUID();
16
+ const secondsFromNow = (seconds) => new Date(Date.now() + seconds * 1000);
17
+ async function seedMute(overrides = {}) {
18
+ const [row] = await db.drizzle.db
19
+ .insert(chatMute)
20
+ .values({
21
+ userId: randomUUID(),
22
+ roomId: null,
23
+ scope: '__global',
24
+ mutedBy: ADMIN_ID,
25
+ reason: 'spam',
26
+ ...overrides,
27
+ })
28
+ .returning();
29
+ return row;
30
+ }
31
+ async function seedBan(overrides = {}) {
32
+ const [row] = await db.drizzle.db
33
+ .insert(chatPlatformBan)
34
+ .values({
35
+ userId: randomUUID(),
36
+ bannedBy: ADMIN_ID,
37
+ roomId: null,
38
+ scope: '__all_public',
39
+ reason: 'abuse',
40
+ ...overrides,
41
+ })
42
+ .returning();
43
+ return row;
44
+ }
45
+ const auditRowsFor = (resourceId) => db.drizzle.db.select().from(auditLog).where(eq(auditLog.resourceId, resourceId));
46
+ beforeAll(async () => {
47
+ db = await createTestDb([migrate, migrateAudit]);
48
+ // The real audit writer, so "exactly one audit entry" is a row count in audit_log
49
+ // rather than a call count on a spy - the hash chain has to accept these writes too.
50
+ const svc = new AuditService(db.drizzle, makeEventBus(), makeIdentityReader());
51
+ audit = {
52
+ record: (entry) => svc.record(entry).then(() => undefined),
53
+ recordInTransaction: (tx, entry) => svc.recordInTransaction(tx, entry).then(() => undefined),
54
+ };
55
+ });
56
+ afterAll(async () => {
57
+ await db.drop();
58
+ });
59
+ beforeEach(async () => {
60
+ await db.drizzle.db.execute(sql `TRUNCATE ${chatMute}, ${chatPlatformBan}, ${auditLog} RESTART IDENTITY CASCADE`);
61
+ });
62
+ describe('ChatModerationExpiryService.sweep', () => {
63
+ const makeSweep = () => new ChatModerationExpiryService(db.drizzle, audit);
64
+ const makeModeration = () => new ChatModerationService(db.drizzle, mock({}), audit);
65
+ it('records exactly one audit entry for a lapsed mute, dated from its own expiresAt', async () => {
66
+ const expiresAt = secondsFromNow(-30);
67
+ const mute = await seedMute({ expiresAt });
68
+ expect(await makeSweep().sweep()).toEqual({ mutes: 1, bans: 0 });
69
+ const rows = await auditRowsFor(mute.id);
70
+ expect(rows).toHaveLength(1);
71
+ expect(rows[0]).toMatchObject({
72
+ action: 'chat.mute.expired',
73
+ actorType: 'system',
74
+ actorId: null,
75
+ resourceType: 'chat_mute',
76
+ });
77
+ // The instant the player could post again, not the instant the cron noticed.
78
+ expect(rows[0].before['expiresAt']).toBe(expiresAt.toISOString());
79
+ expect(rows[0].before['userId']).toBe(mute.userId);
80
+ });
81
+ it('records exactly one audit entry for a lapsed platform ban', async () => {
82
+ const expiresAt = secondsFromNow(-30);
83
+ const ban = await seedBan({ expiresAt });
84
+ expect(await makeSweep().sweep()).toEqual({ mutes: 0, bans: 1 });
85
+ const rows = await auditRowsFor(ban.id);
86
+ expect(rows).toHaveLength(1);
87
+ expect(rows[0]).toMatchObject({
88
+ action: 'chat.platform_ban.expired',
89
+ actorType: 'system',
90
+ actorId: null,
91
+ resourceType: 'chat_platform_ban',
92
+ });
93
+ expect(rows[0].before['expiresAt']).toBe(expiresAt.toISOString());
94
+ });
95
+ it('is idempotent - a second sweep records nothing more', async () => {
96
+ const mute = await seedMute({ expiresAt: secondsFromNow(-30) });
97
+ const ban = await seedBan({ expiresAt: secondsFromNow(-30) });
98
+ await makeSweep().sweep();
99
+ expect(await makeSweep().sweep()).toEqual({ mutes: 0, bans: 0 });
100
+ expect(await auditRowsFor(mute.id)).toHaveLength(1);
101
+ expect(await auditRowsFor(ban.id)).toHaveLength(1);
102
+ });
103
+ it('leaves permanent, still-running and already-lifted entries alone', async () => {
104
+ await seedMute({ expiresAt: null });
105
+ await seedBan({ expiresAt: null });
106
+ await seedMute({ expiresAt: secondsFromNow(3600) });
107
+ await seedBan({ expiresAt: secondsFromNow(3600) });
108
+ // A lapsed entry an admin had already lifted: its end is on the trail as
109
+ // `chat.mute.lifted`, so a second entry would double-report the same ending.
110
+ await seedMute({ expiresAt: secondsFromNow(-30), liftedAt: new Date(), liftedBy: ADMIN_ID });
111
+ await seedBan({ expiresAt: secondsFromNow(-30), liftedAt: new Date(), liftedBy: ADMIN_ID });
112
+ expect(await makeSweep().sweep()).toEqual({ mutes: 0, bans: 0 });
113
+ expect(await db.drizzle.db.select().from(auditLog)).toEqual([]);
114
+ });
115
+ it('writes one entry per lapse when two sweeps run concurrently over the same rows', async () => {
116
+ const mute = await seedMute({ expiresAt: secondsFromNow(-30) });
117
+ const ban = await seedBan({ expiresAt: secondsFromNow(-30) });
118
+ const [a, b] = await Promise.all([makeSweep().sweep(), makeSweep().sweep()]);
119
+ expect(a.mutes + b.mutes).toBe(1);
120
+ expect(a.bans + b.bans).toBe(1);
121
+ expect(await auditRowsFor(mute.id)).toHaveLength(1);
122
+ expect(await auditRowsFor(ban.id)).toHaveLength(1);
123
+ });
124
+ it('stamps expiryRecordedAt so the row stops matching the scan', async () => {
125
+ const mute = await seedMute({ expiresAt: secondsFromNow(-30) });
126
+ await makeSweep().sweep();
127
+ const [row] = await db.drizzle.db.select().from(chatMute).where(eq(chatMute.id, mute.id));
128
+ expect(row.expiryRecordedAt).toBeInstanceOf(Date);
129
+ // The bookmark is not an enforcement input: the mute is still lapsed, still unlifted.
130
+ expect(row.liftedAt).toBeNull();
131
+ });
132
+ // A lapsed row is not active, so lifting it is a no-op in both directions: the trail
133
+ // carries `expired` or `lifted` for a given row, never both.
134
+ it('leaves an admin lift after the sweep off the trail', async () => {
135
+ const userId = randomUUID();
136
+ const mute = await seedMute({ userId, expiresAt: secondsFromNow(-30) });
137
+ const ban = await seedBan({ userId, expiresAt: secondsFromNow(-30) });
138
+ await makeSweep().sweep();
139
+ const moderation = makeModeration();
140
+ await moderation.unmute({ userId, roomId: '__global', actorId: ADMIN_ID, ...NO_CLIENT_META });
141
+ await moderation.unban({
142
+ userId,
143
+ roomId: '__all_public',
144
+ actorId: ADMIN_ID,
145
+ ...NO_CLIENT_META,
146
+ });
147
+ expect((await auditRowsFor(mute.id)).map((r) => r.action)).toEqual(['chat.mute.expired']);
148
+ expect((await auditRowsFor(ban.id)).map((r) => r.action)).toEqual([
149
+ 'chat.platform_ban.expired',
150
+ ]);
151
+ const [muteRow] = await db.drizzle.db.select().from(chatMute).where(eq(chatMute.id, mute.id));
152
+ expect(muteRow.liftedAt).toBeNull();
153
+ });
154
+ });
155
+ //# sourceMappingURL=chat-moderation-expiry.int.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-moderation-expiry.int.test.js","sourceRoot":"","sources":["../../../../src/engagement/chat/__tests__/chat-moderation-expiry.int.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chat-mute-listing.int.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-mute-listing.int.test.d.ts","sourceRoot":"","sources":["../../../../src/engagement/chat/__tests__/chat-mute-listing.int.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,81 @@
1
+ import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { eq, sql } from 'drizzle-orm';
4
+ import { createTestDb } from '@openora/core/testing';
5
+ import { mock, NO_CLIENT_META } from '../../../testing/mock.js';
6
+ import { migrate } from '../migrate.js';
7
+ import { chatMute } from '../schema/index.js';
8
+ import { ChatModerationService } from '../service/chat-moderation.service.js';
9
+ let db;
10
+ const ADMIN_ID = randomUUID();
11
+ const secondsFromNow = (seconds) => new Date(Date.now() + seconds * 1000);
12
+ const makeModeration = () => new ChatModerationService(db.drizzle, mock({}), mock({
13
+ record: vi.fn().mockResolvedValue(undefined),
14
+ recordInTransaction: vi.fn().mockResolvedValue(undefined),
15
+ }));
16
+ async function seedMute(overrides = {}) {
17
+ const [row] = await db.drizzle.db
18
+ .insert(chatMute)
19
+ .values({
20
+ userId: randomUUID(),
21
+ roomId: null,
22
+ scope: '__global',
23
+ mutedBy: ADMIN_ID,
24
+ reason: 'spam',
25
+ ...overrides,
26
+ })
27
+ .returning();
28
+ return row;
29
+ }
30
+ beforeAll(async () => {
31
+ db = await createTestDb([migrate]);
32
+ });
33
+ afterAll(async () => {
34
+ await db.drop();
35
+ });
36
+ beforeEach(async () => {
37
+ await db.drizzle.db.execute(sql `TRUNCATE ${chatMute} RESTART IDENTITY CASCADE`);
38
+ });
39
+ describe('ChatMuteService.listMutes expiry', () => {
40
+ it('omits a mute whose duration has run out but keeps permanent and running ones', async () => {
41
+ const permanent = await seedMute({ expiresAt: null });
42
+ const running = await seedMute({ expiresAt: secondsFromNow(3600) });
43
+ const expired = await seedMute({ expiresAt: secondsFromNow(-1) });
44
+ const ids = (await makeModeration().listMutes()).map((m) => m.id);
45
+ expect(ids).toContain(permanent.id);
46
+ expect(ids).toContain(running.id);
47
+ // The bug: enforcement already lets this player post again (assertCanSend applies the
48
+ // same predicate), so the listing saying "muted" is the only thing disagreeing.
49
+ expect(ids).not.toContain(expired.id);
50
+ });
51
+ it('omits an expired mute for the single-player listing the backoffice reads', async () => {
52
+ const userId = randomUUID();
53
+ await seedMute({ userId, expiresAt: secondsFromNow(-60) });
54
+ expect(await makeModeration().listMutes(userId)).toEqual([]);
55
+ });
56
+ it('still omits a lifted mute that has not yet expired', async () => {
57
+ const userId = randomUUID();
58
+ await seedMute({ userId, expiresAt: secondsFromNow(3600), liftedAt: new Date() });
59
+ expect(await makeModeration().listMutes(userId)).toEqual([]);
60
+ });
61
+ it('agrees with assertCanSend once a timed mute has lapsed', async () => {
62
+ const moderation = makeModeration();
63
+ const userId = randomUUID();
64
+ await moderation.mute({
65
+ userId,
66
+ roomId: '__global',
67
+ durationSeconds: 1,
68
+ reason: 'spam',
69
+ actorId: ADMIN_ID,
70
+ ...NO_CLIENT_META,
71
+ });
72
+ expect(await moderation.listMutes(userId)).toHaveLength(1);
73
+ await db.drizzle.db
74
+ .update(chatMute)
75
+ .set({ expiresAt: secondsFromNow(-1) })
76
+ .where(eq(chatMute.userId, userId));
77
+ await expect(moderation.assertCanSend(userId, null)).resolves.not.toThrow();
78
+ expect(await moderation.listMutes(userId)).toEqual([]);
79
+ });
80
+ });
81
+ //# sourceMappingURL=chat-mute-listing.int.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-mute-listing.int.test.js","sourceRoot":"","sources":["../../../../src/engagement/chat/__tests__/chat-mute-listing.int.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ ALTER TABLE "chat_mute" ADD COLUMN "expiry_recorded_at" timestamp with time zone;--> statement-breakpoint
2
+ ALTER TABLE "chat_platform_ban" ADD COLUMN "expiry_recorded_at" timestamp with time zone;--> statement-breakpoint
3
+ CREATE INDEX "chat_platform_ban_expires_at_idx" ON "chat_platform_ban" USING btree ("expires_at");--> statement-breakpoint
4
+ -- Backfill: every mute/ban that had already lapsed before this release is stamped as
5
+ -- recorded without an audit entry being written for it. The sweep only ever writes an
6
+ -- entry it can date from the row's own expires_at, and for these rows that date is in
7
+ -- the past of a deployment that had no expiry trail at all - so the alternative is a
8
+ -- first cron tick emitting one entry per lapse the operator has ever issued. The trail
9
+ -- starts at this release instead; nothing that was traceable before becomes less so.
10
+ UPDATE "chat_mute"
11
+ SET "expiry_recorded_at" = "expires_at"
12
+ WHERE "lifted_at" IS NULL
13
+ AND "expires_at" IS NOT NULL
14
+ AND "expires_at" <= now();--> statement-breakpoint
15
+ UPDATE "chat_platform_ban"
16
+ SET "expiry_recorded_at" = "expires_at"
17
+ WHERE "lifted_at" IS NULL
18
+ AND "expires_at" IS NOT NULL
19
+ AND "expires_at" <= now();