@wopr-network/platform-core 0.1.0

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 (694) hide show
  1. package/biome.json +61 -0
  2. package/dist/admin/admin-audit-log-repository.d.ts +33 -0
  3. package/dist/admin/admin-audit-log-repository.js +102 -0
  4. package/dist/admin/audit-log.d.ts +49 -0
  5. package/dist/admin/audit-log.js +63 -0
  6. package/dist/admin/index.d.ts +6 -0
  7. package/dist/admin/index.js +3 -0
  8. package/dist/admin/role-store.d.ts +37 -0
  9. package/dist/admin/role-store.js +106 -0
  10. package/dist/auth/api-key-repository.d.ts +11 -0
  11. package/dist/auth/api-key-repository.js +33 -0
  12. package/dist/auth/api-key-repository.test.d.ts +1 -0
  13. package/dist/auth/api-key-repository.test.js +46 -0
  14. package/dist/auth/auth.test.d.ts +1 -0
  15. package/dist/auth/auth.test.js +140 -0
  16. package/dist/auth/better-auth.d.ts +42 -0
  17. package/dist/auth/better-auth.js +196 -0
  18. package/dist/auth/index.d.ts +186 -0
  19. package/dist/auth/index.js +422 -0
  20. package/dist/auth/login-history-repository.d.ts +14 -0
  21. package/dist/auth/login-history-repository.js +15 -0
  22. package/dist/auth/login-history-repository.test.d.ts +1 -0
  23. package/dist/auth/login-history-repository.test.js +47 -0
  24. package/dist/auth/middleware.d.ts +55 -0
  25. package/dist/auth/middleware.js +101 -0
  26. package/dist/auth/middleware.test.d.ts +1 -0
  27. package/dist/auth/middleware.test.js +213 -0
  28. package/dist/auth/scoped-tokens.test.d.ts +1 -0
  29. package/dist/auth/scoped-tokens.test.js +306 -0
  30. package/dist/auth/tenant-access.test.d.ts +1 -0
  31. package/dist/auth/tenant-access.test.js +62 -0
  32. package/dist/auth/user-creator.d.ts +9 -0
  33. package/dist/auth/user-creator.js +47 -0
  34. package/dist/auth/user-creator.test.d.ts +1 -0
  35. package/dist/auth/user-creator.test.js +78 -0
  36. package/dist/auth/user-role-repository.d.ts +31 -0
  37. package/dist/auth/user-role-repository.js +53 -0
  38. package/dist/auth/user-role-repository.test.d.ts +1 -0
  39. package/dist/auth/user-role-repository.test.js +122 -0
  40. package/dist/billing/drizzle-webhook-seen-repository.d.ts +10 -0
  41. package/dist/billing/drizzle-webhook-seen-repository.js +28 -0
  42. package/dist/billing/index.d.ts +7 -0
  43. package/dist/billing/index.js +7 -0
  44. package/dist/billing/payment-processor.d.ts +127 -0
  45. package/dist/billing/payment-processor.js +8 -0
  46. package/dist/billing/payment-processor.test.d.ts +1 -0
  47. package/dist/billing/payment-processor.test.js +71 -0
  48. package/dist/billing/payram/cents-credits-boundary.test.d.ts +1 -0
  49. package/dist/billing/payram/cents-credits-boundary.test.js +75 -0
  50. package/dist/billing/payram/charge-store.d.ts +41 -0
  51. package/dist/billing/payram/charge-store.js +72 -0
  52. package/dist/billing/payram/charge-store.test.d.ts +1 -0
  53. package/dist/billing/payram/charge-store.test.js +64 -0
  54. package/dist/billing/payram/checkout.d.ts +15 -0
  55. package/dist/billing/payram/checkout.js +24 -0
  56. package/dist/billing/payram/checkout.test.d.ts +1 -0
  57. package/dist/billing/payram/checkout.test.js +74 -0
  58. package/dist/billing/payram/client.d.ts +7 -0
  59. package/dist/billing/payram/client.js +15 -0
  60. package/dist/billing/payram/client.test.d.ts +1 -0
  61. package/dist/billing/payram/client.test.js +52 -0
  62. package/dist/billing/payram/index.d.ts +8 -0
  63. package/dist/billing/payram/index.js +4 -0
  64. package/dist/billing/payram/types.d.ts +40 -0
  65. package/dist/billing/payram/types.js +1 -0
  66. package/dist/billing/payram/webhook.d.ts +19 -0
  67. package/dist/billing/payram/webhook.js +67 -0
  68. package/dist/billing/payram/webhook.test.d.ts +7 -0
  69. package/dist/billing/payram/webhook.test.js +248 -0
  70. package/dist/billing/stripe/cents-credits-boundary.test.d.ts +1 -0
  71. package/dist/billing/stripe/cents-credits-boundary.test.js +62 -0
  72. package/dist/billing/stripe/checkout.d.ts +20 -0
  73. package/dist/billing/stripe/checkout.js +63 -0
  74. package/dist/billing/stripe/checkout.test.d.ts +1 -0
  75. package/dist/billing/stripe/checkout.test.js +148 -0
  76. package/dist/billing/stripe/client.d.ts +14 -0
  77. package/dist/billing/stripe/client.js +33 -0
  78. package/dist/billing/stripe/client.test.d.ts +1 -0
  79. package/dist/billing/stripe/client.test.js +58 -0
  80. package/dist/billing/stripe/credit-prices.d.ts +63 -0
  81. package/dist/billing/stripe/credit-prices.js +81 -0
  82. package/dist/billing/stripe/credit-prices.test.d.ts +1 -0
  83. package/dist/billing/stripe/credit-prices.test.js +87 -0
  84. package/dist/billing/stripe/index.d.ts +14 -0
  85. package/dist/billing/stripe/index.js +8 -0
  86. package/dist/billing/stripe/payment-methods-detach-all.test.d.ts +1 -0
  87. package/dist/billing/stripe/payment-methods-detach-all.test.js +40 -0
  88. package/dist/billing/stripe/payment-methods.d.ts +25 -0
  89. package/dist/billing/stripe/payment-methods.js +53 -0
  90. package/dist/billing/stripe/payment-methods.test.d.ts +1 -0
  91. package/dist/billing/stripe/payment-methods.test.js +122 -0
  92. package/dist/billing/stripe/portal.d.ts +10 -0
  93. package/dist/billing/stripe/portal.js +16 -0
  94. package/dist/billing/stripe/portal.test.d.ts +1 -0
  95. package/dist/billing/stripe/portal.test.js +48 -0
  96. package/dist/billing/stripe/setup-intent.d.ts +16 -0
  97. package/dist/billing/stripe/setup-intent.js +22 -0
  98. package/dist/billing/stripe/setup-intent.test.d.ts +1 -0
  99. package/dist/billing/stripe/setup-intent.test.js +58 -0
  100. package/dist/billing/stripe/stripe-payment-processor.d.ts +49 -0
  101. package/dist/billing/stripe/stripe-payment-processor.js +166 -0
  102. package/dist/billing/stripe/stripe-payment-processor.test.d.ts +1 -0
  103. package/dist/billing/stripe/stripe-payment-processor.test.js +413 -0
  104. package/dist/billing/stripe/tenant-store.d.ts +56 -0
  105. package/dist/billing/stripe/tenant-store.js +119 -0
  106. package/dist/billing/stripe/tenant-store.test.d.ts +1 -0
  107. package/dist/billing/stripe/tenant-store.test.js +97 -0
  108. package/dist/billing/stripe/types.d.ts +49 -0
  109. package/dist/billing/stripe/types.js +1 -0
  110. package/dist/billing/webhook-seen-repository.d.ts +14 -0
  111. package/dist/billing/webhook-seen-repository.js +13 -0
  112. package/dist/config/billing-env.test.d.ts +1 -0
  113. package/dist/config/billing-env.test.js +48 -0
  114. package/dist/config/index.d.ts +46 -0
  115. package/dist/config/index.js +38 -0
  116. package/dist/config/logger.d.ts +2 -0
  117. package/dist/config/logger.js +11 -0
  118. package/dist/config/provider-endpoints.d.ts +6 -0
  119. package/dist/config/provider-endpoints.js +12 -0
  120. package/dist/credits/auto-topup-charge.d.ts +27 -0
  121. package/dist/credits/auto-topup-charge.js +139 -0
  122. package/dist/credits/auto-topup-charge.test.d.ts +1 -0
  123. package/dist/credits/auto-topup-charge.test.js +242 -0
  124. package/dist/credits/auto-topup-event-log-repository.d.ts +16 -0
  125. package/dist/credits/auto-topup-event-log-repository.js +18 -0
  126. package/dist/credits/auto-topup-event-log-repository.test.d.ts +1 -0
  127. package/dist/credits/auto-topup-event-log-repository.test.js +83 -0
  128. package/dist/credits/auto-topup-schedule.d.ts +27 -0
  129. package/dist/credits/auto-topup-schedule.js +66 -0
  130. package/dist/credits/auto-topup-schedule.test.d.ts +1 -0
  131. package/dist/credits/auto-topup-schedule.test.js +145 -0
  132. package/dist/credits/auto-topup-settings-repository.d.ts +54 -0
  133. package/dist/credits/auto-topup-settings-repository.js +184 -0
  134. package/dist/credits/auto-topup-settings-repository.test.d.ts +1 -0
  135. package/dist/credits/auto-topup-settings-repository.test.js +104 -0
  136. package/dist/credits/auto-topup-usage.d.ts +22 -0
  137. package/dist/credits/auto-topup-usage.js +56 -0
  138. package/dist/credits/auto-topup-usage.test.d.ts +1 -0
  139. package/dist/credits/auto-topup-usage.test.js +181 -0
  140. package/dist/credits/credit-expiry-cron.d.ts +19 -0
  141. package/dist/credits/credit-expiry-cron.js +50 -0
  142. package/dist/credits/credit-expiry-cron.test.d.ts +1 -0
  143. package/dist/credits/credit-expiry-cron.test.js +67 -0
  144. package/dist/credits/credit-ledger-extra.test.d.ts +1 -0
  145. package/dist/credits/credit-ledger-extra.test.js +40 -0
  146. package/dist/credits/credit-ledger.bench.d.ts +1 -0
  147. package/dist/credits/credit-ledger.bench.js +33 -0
  148. package/dist/credits/credit-ledger.d.ts +130 -0
  149. package/dist/credits/credit-ledger.js +293 -0
  150. package/dist/credits/credit-ledger.test.d.ts +4 -0
  151. package/dist/credits/credit-ledger.test.js +203 -0
  152. package/dist/credits/credit-transaction-repository.d.ts +17 -0
  153. package/dist/credits/credit-transaction-repository.js +35 -0
  154. package/dist/credits/credit-transaction-repository.test.d.ts +1 -0
  155. package/dist/credits/credit-transaction-repository.test.js +232 -0
  156. package/dist/credits/credit.d.ts +75 -0
  157. package/dist/credits/credit.js +139 -0
  158. package/dist/credits/credit.test.d.ts +1 -0
  159. package/dist/credits/credit.test.js +196 -0
  160. package/dist/credits/dividend-cron.d.ts +29 -0
  161. package/dist/credits/dividend-cron.js +88 -0
  162. package/dist/credits/dividend-cron.test.d.ts +1 -0
  163. package/dist/credits/dividend-cron.test.js +128 -0
  164. package/dist/credits/dividend-repository.d.ts +29 -0
  165. package/dist/credits/dividend-repository.js +126 -0
  166. package/dist/credits/dividend-repository.test.d.ts +1 -0
  167. package/dist/credits/dividend-repository.test.js +176 -0
  168. package/dist/credits/index.d.ts +9 -0
  169. package/dist/credits/index.js +5 -0
  170. package/dist/credits/repository-types.d.ts +29 -0
  171. package/dist/credits/repository-types.js +1 -0
  172. package/dist/credits/signup-grant.d.ts +12 -0
  173. package/dist/credits/signup-grant.js +35 -0
  174. package/dist/credits/signup-grant.test.d.ts +1 -0
  175. package/dist/credits/signup-grant.test.js +51 -0
  176. package/dist/credits/tenant-customer-repository.d.ts +30 -0
  177. package/dist/credits/tenant-customer-repository.js +5 -0
  178. package/dist/db/auth-user-repository.d.ts +46 -0
  179. package/dist/db/auth-user-repository.js +90 -0
  180. package/dist/db/credit-column.d.ts +27 -0
  181. package/dist/db/credit-column.js +13 -0
  182. package/dist/db/index.d.ts +14 -0
  183. package/dist/db/index.js +8 -0
  184. package/dist/db/schema/account-deletion-requests.d.ts +203 -0
  185. package/dist/db/schema/account-deletion-requests.js +36 -0
  186. package/dist/db/schema/account-export-requests.d.ts +148 -0
  187. package/dist/db/schema/account-export-requests.js +19 -0
  188. package/dist/db/schema/admin-audit.d.ts +194 -0
  189. package/dist/db/schema/admin-audit.js +21 -0
  190. package/dist/db/schema/admin-users.d.ts +177 -0
  191. package/dist/db/schema/admin-users.js +23 -0
  192. package/dist/db/schema/affiliate-fraud.d.ts +160 -0
  193. package/dist/db/schema/affiliate-fraud.js +18 -0
  194. package/dist/db/schema/affiliate.d.ts +277 -0
  195. package/dist/db/schema/affiliate.js +32 -0
  196. package/dist/db/schema/coupon-codes.d.ts +143 -0
  197. package/dist/db/schema/coupon-codes.js +17 -0
  198. package/dist/db/schema/credit-auto-topup-settings.d.ts +232 -0
  199. package/dist/db/schema/credit-auto-topup-settings.js +27 -0
  200. package/dist/db/schema/credit-auto-topup.d.ts +130 -0
  201. package/dist/db/schema/credit-auto-topup.js +21 -0
  202. package/dist/db/schema/credits.d.ts +283 -0
  203. package/dist/db/schema/credits.js +38 -0
  204. package/dist/db/schema/dividend-distributions.d.ts +130 -0
  205. package/dist/db/schema/dividend-distributions.js +19 -0
  206. package/dist/db/schema/email-notifications.d.ts +99 -0
  207. package/dist/db/schema/email-notifications.js +21 -0
  208. package/dist/db/schema/index.d.ts +33 -0
  209. package/dist/db/schema/index.js +33 -0
  210. package/dist/db/schema/meter-events.d.ts +599 -0
  211. package/dist/db/schema/meter-events.js +55 -0
  212. package/dist/db/schema/notification-preferences.d.ts +165 -0
  213. package/dist/db/schema/notification-preferences.js +18 -0
  214. package/dist/db/schema/notification-queue.d.ts +236 -0
  215. package/dist/db/schema/notification-queue.js +40 -0
  216. package/dist/db/schema/org-memberships.d.ts +63 -0
  217. package/dist/db/schema/org-memberships.js +15 -0
  218. package/dist/db/schema/organization-members.d.ts +235 -0
  219. package/dist/db/schema/organization-members.js +27 -0
  220. package/dist/db/schema/payram.d.ts +164 -0
  221. package/dist/db/schema/payram.js +21 -0
  222. package/dist/db/schema/platform-api-keys.d.ts +143 -0
  223. package/dist/db/schema/platform-api-keys.js +20 -0
  224. package/dist/db/schema/promotion-redemptions.d.ts +143 -0
  225. package/dist/db/schema/promotion-redemptions.js +18 -0
  226. package/dist/db/schema/promotions.d.ts +445 -0
  227. package/dist/db/schema/promotions.js +48 -0
  228. package/dist/db/schema/provider-credentials.d.ts +201 -0
  229. package/dist/db/schema/provider-credentials.js +36 -0
  230. package/dist/db/schema/rate-limit-entries.d.ts +75 -0
  231. package/dist/db/schema/rate-limit-entries.js +7 -0
  232. package/dist/db/schema/secret-audit-log.d.ts +109 -0
  233. package/dist/db/schema/secret-audit-log.js +15 -0
  234. package/dist/db/schema/session-usage.d.ts +194 -0
  235. package/dist/db/schema/session-usage.js +19 -0
  236. package/dist/db/schema/spending-limits.d.ts +92 -0
  237. package/dist/db/schema/spending-limits.js +8 -0
  238. package/dist/db/schema/tenant-addons.d.ts +58 -0
  239. package/dist/db/schema/tenant-addons.js +9 -0
  240. package/dist/db/schema/tenant-api-keys.d.ts +131 -0
  241. package/dist/db/schema/tenant-api-keys.js +21 -0
  242. package/dist/db/schema/tenant-capability-settings.d.ts +79 -0
  243. package/dist/db/schema/tenant-capability-settings.js +12 -0
  244. package/dist/db/schema/tenant-customers.d.ts +303 -0
  245. package/dist/db/schema/tenant-customers.js +25 -0
  246. package/dist/db/schema/tenants.d.ts +126 -0
  247. package/dist/db/schema/tenants.js +18 -0
  248. package/dist/db/schema/user-roles.d.ts +98 -0
  249. package/dist/db/schema/user-roles.js +18 -0
  250. package/dist/db/schema/webhook-seen-events.d.ts +58 -0
  251. package/dist/db/schema/webhook-seen-events.js +9 -0
  252. package/dist/email/billing-emails.d.ts +51 -0
  253. package/dist/email/billing-emails.js +163 -0
  254. package/dist/email/billing-emails.test.d.ts +1 -0
  255. package/dist/email/billing-emails.test.js +162 -0
  256. package/dist/email/client.d.ts +51 -0
  257. package/dist/email/client.js +102 -0
  258. package/dist/email/client.test.d.ts +1 -0
  259. package/dist/email/client.test.js +120 -0
  260. package/dist/email/drizzle-billing-email-repository.d.ts +21 -0
  261. package/dist/email/drizzle-billing-email-repository.js +36 -0
  262. package/dist/email/drizzle-billing-email-repository.test.d.ts +1 -0
  263. package/dist/email/drizzle-billing-email-repository.test.js +42 -0
  264. package/dist/email/index.d.ts +33 -0
  265. package/dist/email/index.js +22 -0
  266. package/dist/email/notification-preferences-store.d.ts +12 -0
  267. package/dist/email/notification-preferences-store.js +82 -0
  268. package/dist/email/notification-preferences-store.test.d.ts +1 -0
  269. package/dist/email/notification-preferences-store.test.js +86 -0
  270. package/dist/email/notification-queue-store.d.ts +25 -0
  271. package/dist/email/notification-queue-store.js +97 -0
  272. package/dist/email/notification-queue-store.test.d.ts +1 -0
  273. package/dist/email/notification-queue-store.test.js +177 -0
  274. package/dist/email/notification-repository-types.d.ts +70 -0
  275. package/dist/email/notification-repository-types.js +6 -0
  276. package/dist/email/notification-service.d.ts +41 -0
  277. package/dist/email/notification-service.js +196 -0
  278. package/dist/email/notification-service.test.d.ts +1 -0
  279. package/dist/email/notification-service.test.js +160 -0
  280. package/dist/email/notification-templates.d.ts +18 -0
  281. package/dist/email/notification-templates.js +574 -0
  282. package/dist/email/notification-templates.test.d.ts +1 -0
  283. package/dist/email/notification-templates.test.js +238 -0
  284. package/dist/email/notification-worker.d.ts +24 -0
  285. package/dist/email/notification-worker.js +109 -0
  286. package/dist/email/notification-worker.test.d.ts +1 -0
  287. package/dist/email/notification-worker.test.js +153 -0
  288. package/dist/email/require-verified.d.ts +25 -0
  289. package/dist/email/require-verified.js +52 -0
  290. package/dist/email/require-verified.test.d.ts +1 -0
  291. package/dist/email/require-verified.test.js +62 -0
  292. package/dist/email/resend-adapter.d.ts +47 -0
  293. package/dist/email/resend-adapter.js +137 -0
  294. package/dist/email/resend-adapter.test.d.ts +1 -0
  295. package/dist/email/resend-adapter.test.js +190 -0
  296. package/dist/email/templates.d.ts +22 -0
  297. package/dist/email/templates.js +359 -0
  298. package/dist/email/templates.test.d.ts +1 -0
  299. package/dist/email/templates.test.js +170 -0
  300. package/dist/email/verification.d.ts +42 -0
  301. package/dist/email/verification.js +83 -0
  302. package/dist/email/verification.test.d.ts +1 -0
  303. package/dist/email/verification.test.js +141 -0
  304. package/dist/index.d.ts +13 -0
  305. package/dist/index.js +23 -0
  306. package/dist/metering/aggregator.d.ts +54 -0
  307. package/dist/metering/aggregator.js +123 -0
  308. package/dist/metering/aggregator.test.d.ts +1 -0
  309. package/dist/metering/aggregator.test.js +179 -0
  310. package/dist/metering/dlq.d.ts +31 -0
  311. package/dist/metering/dlq.js +82 -0
  312. package/dist/metering/dlq.test.d.ts +1 -0
  313. package/dist/metering/dlq.test.js +117 -0
  314. package/dist/metering/drizzle-usage-summary-repository.d.ts +67 -0
  315. package/dist/metering/drizzle-usage-summary-repository.js +98 -0
  316. package/dist/metering/emitter.d.ts +66 -0
  317. package/dist/metering/emitter.js +185 -0
  318. package/dist/metering/emitter.test.d.ts +1 -0
  319. package/dist/metering/emitter.test.js +171 -0
  320. package/dist/metering/index.d.ts +11 -0
  321. package/dist/metering/index.js +5 -0
  322. package/dist/metering/load-test.bench.d.ts +1 -0
  323. package/dist/metering/load-test.bench.js +103 -0
  324. package/dist/metering/meter-event-repository.d.ts +33 -0
  325. package/dist/metering/meter-event-repository.js +58 -0
  326. package/dist/metering/meter-repositories.test.d.ts +1 -0
  327. package/dist/metering/meter-repositories.test.js +419 -0
  328. package/dist/metering/metering.test.d.ts +1 -0
  329. package/dist/metering/metering.test.js +1046 -0
  330. package/dist/metering/reconciliation-cron.d.ts +37 -0
  331. package/dist/metering/reconciliation-cron.js +85 -0
  332. package/dist/metering/reconciliation-cron.test.d.ts +1 -0
  333. package/dist/metering/reconciliation-cron.test.js +162 -0
  334. package/dist/metering/reconciliation-repository.d.ts +27 -0
  335. package/dist/metering/reconciliation-repository.js +43 -0
  336. package/dist/metering/reconciliation-repository.test.d.ts +1 -0
  337. package/dist/metering/reconciliation-repository.test.js +160 -0
  338. package/dist/metering/types.d.ts +88 -0
  339. package/dist/metering/types.js +1 -0
  340. package/dist/metering/wal.d.ts +49 -0
  341. package/dist/metering/wal.js +124 -0
  342. package/dist/metering/wal.test.d.ts +1 -0
  343. package/dist/metering/wal.test.js +175 -0
  344. package/dist/middleware/csrf.d.ts +24 -0
  345. package/dist/middleware/csrf.js +80 -0
  346. package/dist/middleware/csrf.test.d.ts +1 -0
  347. package/dist/middleware/csrf.test.js +152 -0
  348. package/dist/middleware/drizzle-rate-limit-repository.d.ts +9 -0
  349. package/dist/middleware/drizzle-rate-limit-repository.js +52 -0
  350. package/dist/middleware/drizzle-rate-limit-repository.test.d.ts +1 -0
  351. package/dist/middleware/drizzle-rate-limit-repository.test.js +74 -0
  352. package/dist/middleware/get-client-ip.d.ts +22 -0
  353. package/dist/middleware/get-client-ip.js +51 -0
  354. package/dist/middleware/get-client-ip.test.d.ts +1 -0
  355. package/dist/middleware/get-client-ip.test.js +40 -0
  356. package/dist/middleware/index.d.ts +5 -0
  357. package/dist/middleware/index.js +4 -0
  358. package/dist/middleware/rate-limit-repository.d.ts +19 -0
  359. package/dist/middleware/rate-limit-repository.js +1 -0
  360. package/dist/middleware/rate-limit.d.ts +57 -0
  361. package/dist/middleware/rate-limit.js +109 -0
  362. package/dist/middleware/rate-limit.test.d.ts +1 -0
  363. package/dist/middleware/rate-limit.test.js +247 -0
  364. package/dist/security/credential-vault/audit-repository.d.ts +27 -0
  365. package/dist/security/credential-vault/audit-repository.js +42 -0
  366. package/dist/security/credential-vault/audit-repository.test.d.ts +1 -0
  367. package/dist/security/credential-vault/audit-repository.test.js +78 -0
  368. package/dist/security/credential-vault/credential-repository.d.ts +94 -0
  369. package/dist/security/credential-vault/credential-repository.js +145 -0
  370. package/dist/security/credential-vault/credential-repository.test.d.ts +1 -0
  371. package/dist/security/credential-vault/credential-repository.test.js +206 -0
  372. package/dist/security/credential-vault/index.d.ts +12 -0
  373. package/dist/security/credential-vault/index.js +6 -0
  374. package/dist/security/credential-vault/key-rotation.d.ts +18 -0
  375. package/dist/security/credential-vault/key-rotation.js +52 -0
  376. package/dist/security/credential-vault/key-rotation.test.d.ts +1 -0
  377. package/dist/security/credential-vault/key-rotation.test.js +95 -0
  378. package/dist/security/credential-vault/migrate-plaintext.d.ts +15 -0
  379. package/dist/security/credential-vault/migrate-plaintext.js +80 -0
  380. package/dist/security/credential-vault/migrate-plaintext.test.d.ts +1 -0
  381. package/dist/security/credential-vault/migrate-plaintext.test.js +111 -0
  382. package/dist/security/credential-vault/migration-check.d.ts +15 -0
  383. package/dist/security/credential-vault/migration-check.js +71 -0
  384. package/dist/security/credential-vault/migration-check.test.d.ts +1 -0
  385. package/dist/security/credential-vault/migration-check.test.js +457 -0
  386. package/dist/security/credential-vault/store.d.ts +106 -0
  387. package/dist/security/credential-vault/store.js +181 -0
  388. package/dist/security/credential-vault/store.test.d.ts +1 -0
  389. package/dist/security/credential-vault/store.test.js +482 -0
  390. package/dist/security/encryption.d.ts +22 -0
  391. package/dist/security/encryption.js +53 -0
  392. package/dist/security/encryption.test.d.ts +1 -0
  393. package/dist/security/encryption.test.js +95 -0
  394. package/dist/security/host-validation.d.ts +11 -0
  395. package/dist/security/host-validation.js +108 -0
  396. package/dist/security/host-validation.test.d.ts +1 -0
  397. package/dist/security/host-validation.test.js +106 -0
  398. package/dist/security/index.d.ts +11 -0
  399. package/dist/security/index.js +11 -0
  400. package/dist/security/key-audit.d.ts +16 -0
  401. package/dist/security/key-audit.js +35 -0
  402. package/dist/security/key-audit.test.d.ts +1 -0
  403. package/dist/security/key-audit.test.js +50 -0
  404. package/dist/security/key-injection.d.ts +28 -0
  405. package/dist/security/key-injection.js +57 -0
  406. package/dist/security/key-injection.test.d.ts +1 -0
  407. package/dist/security/key-injection.test.js +97 -0
  408. package/dist/security/key-validation.d.ts +16 -0
  409. package/dist/security/key-validation.js +78 -0
  410. package/dist/security/key-validation.test.d.ts +1 -0
  411. package/dist/security/key-validation.test.js +87 -0
  412. package/dist/security/redirect-allowlist.d.ts +6 -0
  413. package/dist/security/redirect-allowlist.js +36 -0
  414. package/dist/security/redirect-allowlist.test.d.ts +1 -0
  415. package/dist/security/redirect-allowlist.test.js +55 -0
  416. package/dist/security/tenant-keys/capability-settings-store.d.ts +22 -0
  417. package/dist/security/tenant-keys/capability-settings-store.js +33 -0
  418. package/dist/security/tenant-keys/capability-settings-store.test.d.ts +1 -0
  419. package/dist/security/tenant-keys/capability-settings-store.test.js +77 -0
  420. package/dist/security/tenant-keys/index.d.ts +10 -0
  421. package/dist/security/tenant-keys/index.js +5 -0
  422. package/dist/security/tenant-keys/key-resolution-repository.d.ts +15 -0
  423. package/dist/security/tenant-keys/key-resolution-repository.js +18 -0
  424. package/dist/security/tenant-keys/key-resolution-repository.test.d.ts +1 -0
  425. package/dist/security/tenant-keys/key-resolution-repository.test.js +72 -0
  426. package/dist/security/tenant-keys/key-resolution.d.ts +39 -0
  427. package/dist/security/tenant-keys/key-resolution.js +59 -0
  428. package/dist/security/tenant-keys/key-resolution.test.d.ts +1 -0
  429. package/dist/security/tenant-keys/key-resolution.test.js +97 -0
  430. package/dist/security/tenant-keys/org-key-resolution.d.ts +30 -0
  431. package/dist/security/tenant-keys/org-key-resolution.js +50 -0
  432. package/dist/security/tenant-keys/org-key-resolution.test.d.ts +1 -0
  433. package/dist/security/tenant-keys/org-key-resolution.test.js +103 -0
  434. package/dist/security/tenant-keys/tenant-key-repository.d.ts +36 -0
  435. package/dist/security/tenant-keys/tenant-key-repository.js +96 -0
  436. package/dist/security/tenant-keys/tenant-key-repository.test.d.ts +1 -0
  437. package/dist/security/tenant-keys/tenant-key-repository.test.js +114 -0
  438. package/dist/security/types.d.ts +35 -0
  439. package/dist/security/types.js +15 -0
  440. package/dist/tenancy/drizzle-org-repository.d.ts +40 -0
  441. package/dist/tenancy/drizzle-org-repository.js +126 -0
  442. package/dist/tenancy/index.d.ts +6 -0
  443. package/dist/tenancy/index.js +3 -0
  444. package/dist/tenancy/org-member-repository.d.ts +57 -0
  445. package/dist/tenancy/org-member-repository.js +99 -0
  446. package/dist/tenancy/org-repository.test.d.ts +1 -0
  447. package/dist/tenancy/org-repository.test.js +143 -0
  448. package/dist/tenancy/org-service.d.ts +70 -0
  449. package/dist/tenancy/org-service.js +223 -0
  450. package/dist/tenancy/org-service.test.d.ts +1 -0
  451. package/dist/tenancy/org-service.test.js +550 -0
  452. package/dist/test/db.d.ts +33 -0
  453. package/dist/test/db.js +65 -0
  454. package/dist/trpc/index.d.ts +1 -0
  455. package/dist/trpc/index.js +1 -0
  456. package/dist/trpc/init.d.ts +49 -0
  457. package/dist/trpc/init.js +108 -0
  458. package/dist/trpc/init.test.d.ts +1 -0
  459. package/dist/trpc/init.test.js +154 -0
  460. package/drizzle/migrations/0000_slippery_mandrill.sql +559 -0
  461. package/drizzle/migrations/meta/0000_snapshot.json +4374 -0
  462. package/drizzle/migrations/meta/_journal.json +13 -0
  463. package/drizzle.config.ts +41 -0
  464. package/package.json +64 -0
  465. package/src/admin/admin-audit-log-repository.ts +135 -0
  466. package/src/admin/audit-log.ts +111 -0
  467. package/src/admin/index.ts +6 -0
  468. package/src/admin/role-store.ts +134 -0
  469. package/src/auth/api-key-repository.test.ts +63 -0
  470. package/src/auth/api-key-repository.ts +46 -0
  471. package/src/auth/auth.test.ts +166 -0
  472. package/src/auth/better-auth.ts +216 -0
  473. package/src/auth/index.ts +520 -0
  474. package/src/auth/login-history-repository.test.ts +54 -0
  475. package/src/auth/login-history-repository.ts +28 -0
  476. package/src/auth/middleware.test.ts +264 -0
  477. package/src/auth/middleware.ts +117 -0
  478. package/src/auth/scoped-tokens.test.ts +362 -0
  479. package/src/auth/tenant-access.test.ts +69 -0
  480. package/src/auth/user-creator.test.ts +98 -0
  481. package/src/auth/user-creator.ts +54 -0
  482. package/src/auth/user-role-repository.test.ts +149 -0
  483. package/src/auth/user-role-repository.ts +67 -0
  484. package/src/billing/drizzle-webhook-seen-repository.ts +34 -0
  485. package/src/billing/index.ts +22 -0
  486. package/src/billing/payment-processor.test.ts +93 -0
  487. package/src/billing/payment-processor.ts +150 -0
  488. package/src/billing/payram/cents-credits-boundary.test.ts +84 -0
  489. package/src/billing/payram/charge-store.test.ts +84 -0
  490. package/src/billing/payram/charge-store.ts +109 -0
  491. package/src/billing/payram/checkout.test.ts +99 -0
  492. package/src/billing/payram/checkout.ts +40 -0
  493. package/src/billing/payram/client.test.ts +62 -0
  494. package/src/billing/payram/client.ts +21 -0
  495. package/src/billing/payram/index.ts +14 -0
  496. package/src/billing/payram/types.ts +44 -0
  497. package/src/billing/payram/webhook.test.ts +318 -0
  498. package/src/billing/payram/webhook.ts +97 -0
  499. package/src/billing/stripe/cents-credits-boundary.test.ts +70 -0
  500. package/src/billing/stripe/checkout.test.ts +186 -0
  501. package/src/billing/stripe/checkout.ts +82 -0
  502. package/src/billing/stripe/client.test.ts +64 -0
  503. package/src/billing/stripe/client.ts +39 -0
  504. package/src/billing/stripe/credit-prices.test.ts +114 -0
  505. package/src/billing/stripe/credit-prices.ts +113 -0
  506. package/src/billing/stripe/index.ts +14 -0
  507. package/src/billing/stripe/payment-methods-detach-all.test.ts +53 -0
  508. package/src/billing/stripe/payment-methods.test.ts +157 -0
  509. package/src/billing/stripe/payment-methods.ts +76 -0
  510. package/src/billing/stripe/portal.test.ts +63 -0
  511. package/src/billing/stripe/portal.ts +25 -0
  512. package/src/billing/stripe/setup-intent.test.ts +78 -0
  513. package/src/billing/stripe/setup-intent.ts +34 -0
  514. package/src/billing/stripe/stripe-payment-processor.test.ts +517 -0
  515. package/src/billing/stripe/stripe-payment-processor.ts +255 -0
  516. package/src/billing/stripe/tenant-store.test.ts +124 -0
  517. package/src/billing/stripe/tenant-store.ts +151 -0
  518. package/src/billing/stripe/types.ts +53 -0
  519. package/src/billing/webhook-seen-repository.ts +24 -0
  520. package/src/config/billing-env.test.ts +54 -0
  521. package/src/config/index.ts +44 -0
  522. package/src/config/logger.ts +12 -0
  523. package/src/config/provider-endpoints.ts +14 -0
  524. package/src/credits/auto-topup-charge.test.ts +292 -0
  525. package/src/credits/auto-topup-charge.ts +171 -0
  526. package/src/credits/auto-topup-event-log-repository.test.ts +99 -0
  527. package/src/credits/auto-topup-event-log-repository.ts +30 -0
  528. package/src/credits/auto-topup-schedule.test.ts +179 -0
  529. package/src/credits/auto-topup-schedule.ts +93 -0
  530. package/src/credits/auto-topup-settings-repository.test.ts +123 -0
  531. package/src/credits/auto-topup-settings-repository.ts +245 -0
  532. package/src/credits/auto-topup-usage.test.ts +220 -0
  533. package/src/credits/auto-topup-usage.ts +68 -0
  534. package/src/credits/credit-expiry-cron.test.ts +125 -0
  535. package/src/credits/credit-expiry-cron.ts +76 -0
  536. package/src/credits/credit-ledger-extra.test.ts +57 -0
  537. package/src/credits/credit-ledger.bench.ts +56 -0
  538. package/src/credits/credit-ledger.test.ts +276 -0
  539. package/src/credits/credit-ledger.ts +450 -0
  540. package/src/credits/credit-transaction-repository.test.ts +274 -0
  541. package/src/credits/credit-transaction-repository.ts +62 -0
  542. package/src/credits/credit.test.ts +234 -0
  543. package/src/credits/credit.ts +160 -0
  544. package/src/credits/dividend-cron.test.ts +158 -0
  545. package/src/credits/dividend-cron.ts +127 -0
  546. package/src/credits/dividend-repository.test.ts +223 -0
  547. package/src/credits/dividend-repository.ts +182 -0
  548. package/src/credits/index.ts +25 -0
  549. package/src/credits/repository-types.ts +33 -0
  550. package/src/credits/signup-grant.test.ts +63 -0
  551. package/src/credits/signup-grant.ts +44 -0
  552. package/src/credits/tenant-customer-repository.ts +28 -0
  553. package/src/db/auth-user-repository.ts +124 -0
  554. package/src/db/credit-column.ts +17 -0
  555. package/src/db/index.ts +21 -0
  556. package/src/db/schema/account-deletion-requests.ts +41 -0
  557. package/src/db/schema/account-export-requests.ts +24 -0
  558. package/src/db/schema/admin-audit.ts +26 -0
  559. package/src/db/schema/admin-users.ts +31 -0
  560. package/src/db/schema/affiliate-fraud.ts +23 -0
  561. package/src/db/schema/affiliate.ts +38 -0
  562. package/src/db/schema/coupon-codes.ts +22 -0
  563. package/src/db/schema/credit-auto-topup-settings.ts +32 -0
  564. package/src/db/schema/credit-auto-topup.ts +26 -0
  565. package/src/db/schema/credits.ts +44 -0
  566. package/src/db/schema/dividend-distributions.ts +24 -0
  567. package/src/db/schema/email-notifications.ts +26 -0
  568. package/src/db/schema/index.ts +33 -0
  569. package/src/db/schema/meter-events.ts +70 -0
  570. package/src/db/schema/notification-preferences.ts +19 -0
  571. package/src/db/schema/notification-queue.ts +45 -0
  572. package/src/db/schema/org-memberships.ts +20 -0
  573. package/src/db/schema/organization-members.ts +37 -0
  574. package/src/db/schema/payram.ts +26 -0
  575. package/src/db/schema/platform-api-keys.ts +25 -0
  576. package/src/db/schema/promotion-redemptions.ts +23 -0
  577. package/src/db/schema/promotions.ts +57 -0
  578. package/src/db/schema/provider-credentials.ts +41 -0
  579. package/src/db/schema/rate-limit-entries.ts +12 -0
  580. package/src/db/schema/secret-audit-log.ts +20 -0
  581. package/src/db/schema/session-usage.ts +24 -0
  582. package/src/db/schema/spending-limits.ts +9 -0
  583. package/src/db/schema/tenant-addons.ts +14 -0
  584. package/src/db/schema/tenant-api-keys.ts +26 -0
  585. package/src/db/schema/tenant-capability-settings.ts +17 -0
  586. package/src/db/schema/tenant-customers.ts +35 -0
  587. package/src/db/schema/tenants.ts +23 -0
  588. package/src/db/schema/user-roles.ts +23 -0
  589. package/src/db/schema/webhook-seen-events.ts +14 -0
  590. package/src/email/billing-emails.test.ts +198 -0
  591. package/src/email/billing-emails.ts +211 -0
  592. package/src/email/client.test.ts +149 -0
  593. package/src/email/client.ts +137 -0
  594. package/src/email/drizzle-billing-email-repository.test.ts +52 -0
  595. package/src/email/drizzle-billing-email-repository.ts +59 -0
  596. package/src/email/index.ts +57 -0
  597. package/src/email/notification-preferences-store.test.ts +102 -0
  598. package/src/email/notification-preferences-store.ts +90 -0
  599. package/src/email/notification-queue-store.test.ts +215 -0
  600. package/src/email/notification-queue-store.ts +127 -0
  601. package/src/email/notification-repository-types.ts +101 -0
  602. package/src/email/notification-service.test.ts +178 -0
  603. package/src/email/notification-service.ts +265 -0
  604. package/src/email/notification-templates.test.ts +261 -0
  605. package/src/email/notification-templates.ts +727 -0
  606. package/src/email/notification-worker.test.ts +189 -0
  607. package/src/email/notification-worker.ts +133 -0
  608. package/src/email/require-verified.ts +65 -0
  609. package/src/email/resend-adapter.test.ts +253 -0
  610. package/src/email/resend-adapter.ts +157 -0
  611. package/src/email/templates.test.ts +217 -0
  612. package/src/email/templates.ts +469 -0
  613. package/src/email/verification.test.ts +185 -0
  614. package/src/email/verification.ts +110 -0
  615. package/src/index.ts +51 -0
  616. package/src/metering/aggregator.test.ts +239 -0
  617. package/src/metering/aggregator.ts +160 -0
  618. package/src/metering/dlq.test.ts +134 -0
  619. package/src/metering/dlq.ts +102 -0
  620. package/src/metering/drizzle-usage-summary-repository.ts +167 -0
  621. package/src/metering/emitter.test.ts +202 -0
  622. package/src/metering/emitter.ts +227 -0
  623. package/src/metering/index.ts +21 -0
  624. package/src/metering/load-test.bench.ts +130 -0
  625. package/src/metering/meter-event-repository.ts +87 -0
  626. package/src/metering/meter-repositories.test.ts +491 -0
  627. package/src/metering/metering.test.ts +1317 -0
  628. package/src/metering/reconciliation-cron.test.ts +202 -0
  629. package/src/metering/reconciliation-cron.ts +134 -0
  630. package/src/metering/reconciliation-repository.test.ts +196 -0
  631. package/src/metering/reconciliation-repository.ts +83 -0
  632. package/src/metering/types.ts +93 -0
  633. package/src/metering/wal.test.ts +222 -0
  634. package/src/metering/wal.ts +139 -0
  635. package/src/middleware/csrf.test.ts +178 -0
  636. package/src/middleware/csrf.ts +101 -0
  637. package/src/middleware/drizzle-rate-limit-repository.test.ts +97 -0
  638. package/src/middleware/drizzle-rate-limit-repository.ts +57 -0
  639. package/src/middleware/get-client-ip.test.ts +49 -0
  640. package/src/middleware/get-client-ip.ts +62 -0
  641. package/src/middleware/index.ts +12 -0
  642. package/src/middleware/rate-limit-repository.ts +22 -0
  643. package/src/middleware/rate-limit.test.ts +338 -0
  644. package/src/middleware/rate-limit.ts +169 -0
  645. package/src/security/credential-vault/audit-repository.test.ts +91 -0
  646. package/src/security/credential-vault/audit-repository.ts +64 -0
  647. package/src/security/credential-vault/credential-repository.test.ts +264 -0
  648. package/src/security/credential-vault/credential-repository.ts +233 -0
  649. package/src/security/credential-vault/index.ts +26 -0
  650. package/src/security/credential-vault/key-rotation.test.ts +139 -0
  651. package/src/security/credential-vault/key-rotation.ts +70 -0
  652. package/src/security/credential-vault/migrate-plaintext.test.ts +138 -0
  653. package/src/security/credential-vault/migrate-plaintext.ts +101 -0
  654. package/src/security/credential-vault/migration-check.test.ts +533 -0
  655. package/src/security/credential-vault/migration-check.ts +88 -0
  656. package/src/security/credential-vault/store.test.ts +569 -0
  657. package/src/security/credential-vault/store.ts +284 -0
  658. package/src/security/encryption.test.ts +114 -0
  659. package/src/security/encryption.ts +65 -0
  660. package/src/security/host-validation.test.ts +136 -0
  661. package/src/security/host-validation.ts +116 -0
  662. package/src/security/index.ts +59 -0
  663. package/src/security/key-audit.test.ts +57 -0
  664. package/src/security/key-audit.ts +45 -0
  665. package/src/security/key-injection.test.ts +131 -0
  666. package/src/security/key-injection.ts +71 -0
  667. package/src/security/key-validation.test.ts +111 -0
  668. package/src/security/key-validation.ts +84 -0
  669. package/src/security/redirect-allowlist.test.ts +70 -0
  670. package/src/security/redirect-allowlist.ts +35 -0
  671. package/src/security/tenant-keys/capability-settings-store.test.ts +98 -0
  672. package/src/security/tenant-keys/capability-settings-store.ts +53 -0
  673. package/src/security/tenant-keys/index.ts +10 -0
  674. package/src/security/tenant-keys/key-resolution-repository.test.ts +95 -0
  675. package/src/security/tenant-keys/key-resolution-repository.ts +31 -0
  676. package/src/security/tenant-keys/key-resolution.test.ts +173 -0
  677. package/src/security/tenant-keys/key-resolution.ts +87 -0
  678. package/src/security/tenant-keys/org-key-resolution.test.ts +217 -0
  679. package/src/security/tenant-keys/org-key-resolution.ts +76 -0
  680. package/src/security/tenant-keys/tenant-key-repository.test.ts +143 -0
  681. package/src/security/tenant-keys/tenant-key-repository.ts +130 -0
  682. package/src/security/types.ts +43 -0
  683. package/src/tenancy/drizzle-org-repository.ts +169 -0
  684. package/src/tenancy/index.ts +6 -0
  685. package/src/tenancy/org-member-repository.ts +159 -0
  686. package/src/tenancy/org-repository.test.ts +172 -0
  687. package/src/tenancy/org-service.test.ts +634 -0
  688. package/src/tenancy/org-service.ts +290 -0
  689. package/src/test/db.ts +97 -0
  690. package/src/trpc/index.ts +11 -0
  691. package/src/trpc/init.test.ts +196 -0
  692. package/src/trpc/init.ts +138 -0
  693. package/tsconfig.json +20 -0
  694. package/vitest.config.ts +8 -0
@@ -0,0 +1,149 @@
1
+ import type { PGlite } from "@electric-sql/pglite";
2
+ import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
3
+ import type { PlatformDb } from "../db/index.js";
4
+ import { beginTestTransaction, createTestDb, endTestTransaction, rollbackTestTransaction } from "../test/db.js";
5
+ import { DrizzleUserRoleRepository } from "./user-role-repository.js";
6
+
7
+ describe("DrizzleUserRoleRepository", () => {
8
+ let db: PlatformDb;
9
+ let pool: PGlite;
10
+ let repo: DrizzleUserRoleRepository;
11
+
12
+ beforeAll(async () => {
13
+ ({ db, pool } = await createTestDb());
14
+ await beginTestTransaction(pool);
15
+ });
16
+
17
+ afterAll(async () => {
18
+ await endTestTransaction(pool);
19
+ await pool.close();
20
+ });
21
+
22
+ beforeEach(async () => {
23
+ await rollbackTestTransaction(pool);
24
+ repo = new DrizzleUserRoleRepository(db);
25
+ });
26
+
27
+ describe("grantRole", () => {
28
+ it("assigns a role and subsequent lookup returns it", async () => {
29
+ await repo.grantRole("user-1", "tenant-1", "user", "admin-1");
30
+ const roles = await repo.listRolesByUser("user-1");
31
+ expect(roles).toHaveLength(1);
32
+ expect(roles[0]).toEqual({ tenantId: "tenant-1", role: "user" });
33
+ });
34
+ });
35
+
36
+ describe("revokeRole", () => {
37
+ it("removes a granted role so it is no longer returned", async () => {
38
+ await repo.grantRole("user-1", "tenant-1", "user", "admin-1");
39
+ const removed = await repo.revokeRole("user-1", "tenant-1");
40
+ expect(removed).toBe(true);
41
+ const roles = await repo.listRolesByUser("user-1");
42
+ expect(roles).toHaveLength(0);
43
+ });
44
+
45
+ it("returns false when revoking a non-existent role", async () => {
46
+ const removed = await repo.revokeRole("user-1", "tenant-1");
47
+ expect(removed).toBe(false);
48
+ });
49
+ });
50
+
51
+ describe("listRolesByUser", () => {
52
+ it("returns only the specified user's roles across tenants", async () => {
53
+ await repo.grantRole("user-1", "tenant-1", "user", null);
54
+ await repo.grantRole("user-1", "tenant-2", "tenant_admin", null);
55
+ await repo.grantRole("user-2", "tenant-1", "user", null);
56
+
57
+ const roles = await repo.listRolesByUser("user-1");
58
+ expect(roles).toHaveLength(2);
59
+ const tenantIds = roles.map((r) => r.tenantId).sort();
60
+ expect(tenantIds).toEqual(["tenant-1", "tenant-2"]);
61
+ });
62
+
63
+ it("returns empty array for user with no roles", async () => {
64
+ const roles = await repo.listRolesByUser("nobody");
65
+ expect(roles).toEqual([]);
66
+ });
67
+ });
68
+
69
+ describe("listUsersByRole", () => {
70
+ it("returns all users with a given role in a tenant", async () => {
71
+ await repo.grantRole("user-1", "tenant-1", "user", null);
72
+ await repo.grantRole("user-2", "tenant-1", "user", null);
73
+ await repo.grantRole("user-3", "tenant-1", "tenant_admin", null);
74
+
75
+ const users = await repo.listUsersByRole("user", "tenant-1");
76
+ expect(users).toHaveLength(2);
77
+ const userIds = users.map((u) => u.userId).sort();
78
+ expect(userIds).toEqual(["user-1", "user-2"]);
79
+ });
80
+
81
+ it("does not return users from other tenants", async () => {
82
+ await repo.grantRole("user-1", "tenant-1", "user", null);
83
+ await repo.grantRole("user-2", "tenant-2", "user", null);
84
+
85
+ const users = await repo.listUsersByRole("user", "tenant-1");
86
+ expect(users).toHaveLength(1);
87
+ expect(users[0].userId).toBe("user-1");
88
+ });
89
+ });
90
+
91
+ describe("isPlatformAdmin", () => {
92
+ it("returns true for a user with platform_admin role in sentinel tenant", async () => {
93
+ await repo.grantRole("admin-1", "*", "platform_admin", null);
94
+ expect(await repo.isPlatformAdmin("admin-1")).toBe(true);
95
+ });
96
+
97
+ it("returns false for a user with no roles", async () => {
98
+ expect(await repo.isPlatformAdmin("nobody")).toBe(false);
99
+ });
100
+
101
+ it("returns false for a tenant_admin in the sentinel tenant", async () => {
102
+ await repo.grantRole("user-1", "*", "tenant_admin", null);
103
+ expect(await repo.isPlatformAdmin("user-1")).toBe(false);
104
+ });
105
+
106
+ it("returns false for a platform_admin in a regular tenant", async () => {
107
+ await repo.grantRole("user-1", "tenant-1", "platform_admin", null);
108
+ expect(await repo.isPlatformAdmin("user-1")).toBe(false);
109
+ });
110
+ });
111
+
112
+ describe("idempotent grant", () => {
113
+ it("granting the same role twice does not error or duplicate", async () => {
114
+ await repo.grantRole("user-1", "tenant-1", "user", "admin-1");
115
+ await repo.grantRole("user-1", "tenant-1", "user", "admin-1");
116
+
117
+ const roles = await repo.listRolesByUser("user-1");
118
+ expect(roles).toHaveLength(1);
119
+ });
120
+
121
+ it("granting a different role to same user+tenant upserts", async () => {
122
+ await repo.grantRole("user-1", "tenant-1", "user", "admin-1");
123
+ await repo.grantRole("user-1", "tenant-1", "tenant_admin", "admin-2");
124
+
125
+ const roles = await repo.listRolesByUser("user-1");
126
+ expect(roles).toHaveLength(1);
127
+ expect(roles[0].role).toBe("tenant_admin");
128
+ });
129
+ });
130
+
131
+ describe("getTenantIdByUserId", () => {
132
+ it("returns the tenant ID for a user with a role", async () => {
133
+ await repo.grantRole("user-1", "tenant-1", "user", null);
134
+ const tenantId = await repo.getTenantIdByUserId("user-1");
135
+ expect(tenantId).toBe("tenant-1");
136
+ });
137
+
138
+ it("returns null for a user with no roles", async () => {
139
+ const tenantId = await repo.getTenantIdByUserId("nobody");
140
+ expect(tenantId).toBeNull();
141
+ });
142
+
143
+ it("excludes platform admin sentinel tenant", async () => {
144
+ await repo.grantRole("admin-1", "*", "platform_admin", null);
145
+ const tenantId = await repo.getTenantIdByUserId("admin-1");
146
+ expect(tenantId).toBeNull();
147
+ });
148
+ });
149
+ });
@@ -0,0 +1,67 @@
1
+ import { and, eq } from "drizzle-orm";
2
+ import type { PlatformDb } from "../db/index.js";
3
+ import { userRoles } from "../db/schema/user-roles.js";
4
+
5
+ export interface IUserRoleRepository {
6
+ getTenantIdByUserId(userId: string): Promise<string | null>;
7
+ grantRole(userId: string, tenantId: string, role: string, grantedBy: string | null): Promise<void>;
8
+ revokeRole(userId: string, tenantId: string): Promise<boolean>;
9
+ listRolesByUser(userId: string): Promise<Array<{ tenantId: string; role: string }>>;
10
+ listUsersByRole(role: string, tenantId: string): Promise<Array<{ userId: string; role: string }>>;
11
+ isPlatformAdmin(userId: string): Promise<boolean>;
12
+ }
13
+
14
+ export class DrizzleUserRoleRepository implements IUserRoleRepository {
15
+ constructor(private readonly db: PlatformDb) {}
16
+
17
+ async getTenantIdByUserId(userId: string): Promise<string | null> {
18
+ const rows = await this.db
19
+ .select({ tenantId: userRoles.tenantId })
20
+ .from(userRoles)
21
+ .where(eq(userRoles.userId, userId))
22
+ .limit(1);
23
+ const tenantId = rows[0]?.tenantId ?? null;
24
+ // Exclude platform-admin sentinel value
25
+ return tenantId === "*" ? null : tenantId;
26
+ }
27
+
28
+ async grantRole(userId: string, tenantId: string, role: string, grantedBy: string | null): Promise<void> {
29
+ await this.db
30
+ .insert(userRoles)
31
+ .values({ userId, tenantId, role, grantedBy, grantedAt: Date.now() })
32
+ .onConflictDoUpdate({
33
+ target: [userRoles.userId, userRoles.tenantId],
34
+ set: { role, grantedBy, grantedAt: Date.now() },
35
+ });
36
+ }
37
+
38
+ async revokeRole(userId: string, tenantId: string): Promise<boolean> {
39
+ const result = await this.db
40
+ .delete(userRoles)
41
+ .where(and(eq(userRoles.userId, userId), eq(userRoles.tenantId, tenantId)))
42
+ .returning({ userId: userRoles.userId });
43
+ return result.length > 0;
44
+ }
45
+
46
+ async listRolesByUser(userId: string): Promise<Array<{ tenantId: string; role: string }>> {
47
+ return this.db
48
+ .select({ tenantId: userRoles.tenantId, role: userRoles.role })
49
+ .from(userRoles)
50
+ .where(eq(userRoles.userId, userId));
51
+ }
52
+
53
+ async listUsersByRole(role: string, tenantId: string): Promise<Array<{ userId: string; role: string }>> {
54
+ return this.db
55
+ .select({ userId: userRoles.userId, role: userRoles.role })
56
+ .from(userRoles)
57
+ .where(and(eq(userRoles.role, role), eq(userRoles.tenantId, tenantId)));
58
+ }
59
+
60
+ async isPlatformAdmin(userId: string): Promise<boolean> {
61
+ const rows = await this.db
62
+ .select({ userId: userRoles.userId })
63
+ .from(userRoles)
64
+ .where(and(eq(userRoles.userId, userId), eq(userRoles.tenantId, "*"), eq(userRoles.role, "platform_admin")));
65
+ return rows.length > 0;
66
+ }
67
+ }
@@ -0,0 +1,34 @@
1
+ import { and, eq, lt } from "drizzle-orm";
2
+ import type { PlatformDb } from "../db/index.js";
3
+ import { webhookSeenEvents } from "../db/schema/index.js";
4
+ import type { WebhookSeenEvent } from "../credits/repository-types.js";
5
+ import type { IWebhookSeenRepository } from "./webhook-seen-repository.js";
6
+
7
+ export class DrizzleWebhookSeenRepository implements IWebhookSeenRepository {
8
+ constructor(private readonly db: PlatformDb) {}
9
+
10
+ async isDuplicate(eventId: string, source: string): Promise<boolean> {
11
+ const row = (
12
+ await this.db
13
+ .select()
14
+ .from(webhookSeenEvents)
15
+ .where(and(eq(webhookSeenEvents.eventId, eventId), eq(webhookSeenEvents.source, source)))
16
+ )[0];
17
+ return row !== undefined;
18
+ }
19
+
20
+ async markSeen(eventId: string, source: string): Promise<WebhookSeenEvent> {
21
+ const seenAt = Date.now();
22
+ await this.db.insert(webhookSeenEvents).values({ eventId, source, seenAt }).onConflictDoNothing();
23
+ return { eventId, source, seenAt };
24
+ }
25
+
26
+ async purgeExpired(ttlMs: number): Promise<number> {
27
+ const cutoff = Date.now() - ttlMs;
28
+ const result = await this.db
29
+ .delete(webhookSeenEvents)
30
+ .where(lt(webhookSeenEvents.seenAt, cutoff))
31
+ .returning({ id: webhookSeenEvents.eventId });
32
+ return result.length;
33
+ }
34
+ }
@@ -0,0 +1,22 @@
1
+ export type {
2
+ SavedPaymentMethod,
3
+ CheckoutOpts,
4
+ CheckoutSession,
5
+ ChargeOpts,
6
+ ChargeResult,
7
+ SetupResult,
8
+ PortalOpts,
9
+ WebhookResult,
10
+ IPaymentProcessor,
11
+ Invoice,
12
+ } from "./payment-processor.js";
13
+ export { PaymentMethodOwnershipError } from "./payment-processor.js";
14
+ export type { IWebhookSeenRepository } from "./webhook-seen-repository.js";
15
+ export { noOpReplayGuard } from "./webhook-seen-repository.js";
16
+ export { DrizzleWebhookSeenRepository } from "./drizzle-webhook-seen-repository.js";
17
+
18
+ // Stripe
19
+ export * from "./stripe/index.js";
20
+
21
+ // PayRam
22
+ export * from "./payram/index.js";
@@ -0,0 +1,93 @@
1
+ import { describe, expectTypeOf, it } from "vitest";
2
+ import type {
3
+ ChargeOpts,
4
+ ChargeResult,
5
+ CheckoutOpts,
6
+ CheckoutSession,
7
+ IPaymentProcessor,
8
+ PortalOpts,
9
+ SavedPaymentMethod,
10
+ SetupResult,
11
+ WebhookResult,
12
+ } from "./payment-processor.js";
13
+
14
+ describe("IPaymentProcessor types", () => {
15
+ it("CheckoutOpts has required fields", () => {
16
+ expectTypeOf<CheckoutOpts>().toHaveProperty("tenant");
17
+ expectTypeOf<CheckoutOpts>().toHaveProperty("amount");
18
+ expectTypeOf<CheckoutOpts>().toHaveProperty("successUrl");
19
+ expectTypeOf<CheckoutOpts>().toHaveProperty("cancelUrl");
20
+ });
21
+
22
+ it("CheckoutSession has id and url", () => {
23
+ expectTypeOf<CheckoutSession>().toHaveProperty("id");
24
+ expectTypeOf<CheckoutSession>().toHaveProperty("url");
25
+ });
26
+
27
+ it("ChargeResult has success field", () => {
28
+ expectTypeOf<ChargeResult>().toHaveProperty("success");
29
+ });
30
+
31
+ it("WebhookResult uses Credit for credited field", () => {
32
+ expectTypeOf<WebhookResult>().toHaveProperty("handled");
33
+ expectTypeOf<WebhookResult>().toHaveProperty("eventType");
34
+ });
35
+
36
+ it("SavedPaymentMethod has id, label, isDefault", () => {
37
+ expectTypeOf<SavedPaymentMethod>().toHaveProperty("id");
38
+ expectTypeOf<SavedPaymentMethod>().toHaveProperty("label");
39
+ expectTypeOf<SavedPaymentMethod>().toHaveProperty("isDefault");
40
+ });
41
+
42
+ it("IPaymentProcessor has all required methods", () => {
43
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("name");
44
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("createCheckoutSession");
45
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("handleWebhook");
46
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("supportsPortal");
47
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("setupPaymentMethod");
48
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("listPaymentMethods");
49
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("detachPaymentMethod");
50
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("charge");
51
+ });
52
+
53
+ it("createPortalSession is required on IPaymentProcessor", () => {
54
+ // Implementations that don't support portal must still implement createPortalSession (and throw)
55
+ const processor: IPaymentProcessor = {
56
+ name: "test",
57
+ createCheckoutSession: async () => ({ id: "s", url: "u" }),
58
+ handleWebhook: async () => ({ handled: true, eventType: "test" }),
59
+ supportsPortal: () => false,
60
+ createPortalSession: async () => {
61
+ throw new Error("Billing portal not supported");
62
+ },
63
+ setupPaymentMethod: async () => ({ clientSecret: "cs" }),
64
+ listPaymentMethods: async () => [],
65
+ detachPaymentMethod: async () => undefined,
66
+ charge: async () => ({ success: true }),
67
+ getCustomerEmail: async () => "",
68
+ updateCustomerEmail: async () => undefined,
69
+ listInvoices: async () => [],
70
+ };
71
+ expectTypeOf(processor).toMatchTypeOf<IPaymentProcessor>();
72
+ });
73
+
74
+ it("PortalOpts has tenant and returnUrl", () => {
75
+ expectTypeOf<PortalOpts>().toHaveProperty("tenant");
76
+ expectTypeOf<PortalOpts>().toHaveProperty("returnUrl");
77
+ });
78
+
79
+ it("SetupResult has clientSecret", () => {
80
+ expectTypeOf<SetupResult>().toHaveProperty("clientSecret");
81
+ });
82
+
83
+ it("ChargeOpts has tenant, amount, source", () => {
84
+ expectTypeOf<ChargeOpts>().toHaveProperty("tenant");
85
+ expectTypeOf<ChargeOpts>().toHaveProperty("amount");
86
+ expectTypeOf<ChargeOpts>().toHaveProperty("source");
87
+ });
88
+
89
+ it("IPaymentProcessor has getCustomerEmail and updateCustomerEmail", () => {
90
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("getCustomerEmail");
91
+ expectTypeOf<IPaymentProcessor>().toHaveProperty("updateCustomerEmail");
92
+ });
93
+ });
@@ -0,0 +1,150 @@
1
+ import type { Credit } from "../credits/credit.js";
2
+
3
+ /** Thrown when a tenant tries to detach a payment method they don't own. */
4
+ export class PaymentMethodOwnershipError extends Error {
5
+ readonly code = "PAYMENT_METHOD_NOT_OWNED" as const;
6
+ constructor() {
7
+ super("Payment method does not belong to this tenant");
8
+ this.name = "PaymentMethodOwnershipError";
9
+ }
10
+ }
11
+
12
+ /** A saved payment method on file for a tenant (processor-agnostic). */
13
+ export interface SavedPaymentMethod {
14
+ /** Processor-specific payment method ID (e.g. Stripe pm_xxx, PayRam wallet address). */
15
+ id: string;
16
+ /** Human-readable label (e.g. "Visa ending 4242", "ETH wallet"). */
17
+ label: string;
18
+ /** Whether this is the tenant's default payment method. */
19
+ isDefault: boolean;
20
+ }
21
+
22
+ /** Options for creating a checkout session. */
23
+ export interface CheckoutOpts {
24
+ /** Internal tenant ID. */
25
+ tenant: string;
26
+ /** Amount to charge. Required when no priceId is provided; may be omitted when priceId resolves the amount. */
27
+ amount?: Credit;
28
+ /** URL to redirect to after successful checkout. */
29
+ successUrl: string;
30
+ /** URL to redirect to if the user cancels checkout. */
31
+ cancelUrl: string;
32
+ /** Processor-specific price ID (e.g. Stripe price_xxx). Processors that don't use price IDs may ignore this. */
33
+ priceId?: string;
34
+ }
35
+
36
+ /** Returned after creating a checkout session. */
37
+ export interface CheckoutSession {
38
+ /** Processor-specific session ID (for idempotency / correlation). */
39
+ id: string;
40
+ /** URL to redirect the user to for payment. */
41
+ url: string;
42
+ }
43
+
44
+ /** Options for charging a saved payment method off-session. */
45
+ export interface ChargeOpts {
46
+ /** Internal tenant ID. */
47
+ tenant: string;
48
+ /** Amount to charge. */
49
+ amount: Credit;
50
+ /** Descriptive source tag for ledger entries (e.g. "auto_topup_usage"). */
51
+ source: string;
52
+ }
53
+
54
+ /** Result of an off-session charge attempt. */
55
+ export interface ChargeResult {
56
+ success: boolean;
57
+ /** Processor-specific payment reference (e.g. Stripe PaymentIntent ID). */
58
+ paymentReference?: string;
59
+ error?: string;
60
+ }
61
+
62
+ /** Result of setting up a payment method for future use. */
63
+ export interface SetupResult {
64
+ /** Processor-specific client secret for frontend completion (e.g. Stripe SetupIntent). */
65
+ clientSecret: string;
66
+ }
67
+
68
+ /** Options for creating a billing portal session. */
69
+ export interface PortalOpts {
70
+ /** Internal tenant ID. */
71
+ tenant: string;
72
+ /** URL to redirect to when the user is done managing billing. */
73
+ returnUrl: string;
74
+ }
75
+
76
+ /** Result of processing an incoming webhook from a payment processor. */
77
+ export interface WebhookResult {
78
+ handled: boolean;
79
+ /** Processor-specific event type or status string. */
80
+ eventType: string;
81
+ tenant?: string;
82
+ /** Credits to grant to the tenant's ledger. */
83
+ credited?: Credit;
84
+ /** Bot IDs reactivated after credit purchase (WOP-447). */
85
+ reactivatedBots?: string[];
86
+ /** True when this event was a duplicate / replay. */
87
+ duplicate?: boolean;
88
+ }
89
+
90
+ /**
91
+ * Processor-agnostic payment interface.
92
+ *
93
+ * Each payment processor (Stripe, PayRam, future processors) implements
94
+ * this interface. The platform layer programs against IPaymentProcessor
95
+ * and never imports processor-specific types.
96
+ */
97
+ export interface IPaymentProcessor {
98
+ /** Human-readable processor name (e.g. "stripe", "payram"). */
99
+ readonly name: string;
100
+
101
+ /** Create a checkout session for a one-time credit purchase. */
102
+ createCheckoutSession(opts: CheckoutOpts): Promise<CheckoutSession>;
103
+
104
+ /** Process an incoming webhook payload. */
105
+ handleWebhook(payload: Buffer, signature: string): Promise<WebhookResult>;
106
+
107
+ /** Whether this processor supports a self-service billing portal. */
108
+ supportsPortal(): boolean;
109
+
110
+ /**
111
+ * Create a billing portal session (only if supportsPortal() is true).
112
+ * Implementations that return false from supportsPortal() must throw rather than leaving this undefined.
113
+ */
114
+ createPortalSession(opts: PortalOpts): Promise<{ url: string }>;
115
+
116
+ /** Save a payment method for future off-session charges. */
117
+ setupPaymentMethod(tenant: string): Promise<SetupResult>;
118
+
119
+ /** List saved payment methods for a tenant. */
120
+ listPaymentMethods(tenant: string): Promise<SavedPaymentMethod[]>;
121
+
122
+ /** Charge a saved payment method off-session. */
123
+ charge(opts: ChargeOpts): Promise<ChargeResult>;
124
+
125
+ /** Detach a payment method from the tenant's account. */
126
+ detachPaymentMethod(tenant: string, paymentMethodId: string): Promise<void>;
127
+
128
+ /** Get the billing email for a tenant's customer account. Returns "" if no customer exists. */
129
+ getCustomerEmail(tenantId: string): Promise<string>;
130
+
131
+ /** Update the billing email for a tenant's customer account. */
132
+ updateCustomerEmail(tenantId: string, email: string): Promise<void>;
133
+
134
+ /** List invoices for a tenant. Returns an empty array if no customer exists. */
135
+ listInvoices(tenantId: string): Promise<Invoice[]>;
136
+ }
137
+
138
+ /** A past invoice for a tenant (processor-agnostic). */
139
+ export interface Invoice {
140
+ /** Processor-specific invoice ID (e.g. Stripe in_xxx). */
141
+ id: string;
142
+ /** ISO 8601 date string for when the invoice was created. */
143
+ date: string;
144
+ /** Invoice total in cents. */
145
+ amountCents: number;
146
+ /** Invoice status (e.g. "paid", "open", "void", "uncollectible"). */
147
+ status: string;
148
+ /** URL to download the invoice PDF. Empty string if unavailable. */
149
+ downloadUrl: string;
150
+ }
@@ -0,0 +1,84 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ /**
4
+ * Regression tests for PayRam cents/credits boundary (WOP-1058).
5
+ *
6
+ * Verifies that the USD-to-cents conversion in checkout and
7
+ * the cents-to-credits flow in the webhook maintain correct units.
8
+ *
9
+ * If any of these tests fail after a rename/refactor, a _cents field was
10
+ * incorrectly changed to store Credit raw units (nanodollars) instead of
11
+ * USD cents. See src/monetization/credits/credit-ledger.ts for naming convention.
12
+ */
13
+ describe("WOP-1058: PayRam cents/credits boundary", () => {
14
+ it("USD to cents conversion is correct (mirrors checkout.ts pattern)", () => {
15
+ // This mirrors the conversion in payram/checkout.ts: Math.round(opts.amountUsd * 100)
16
+ const amountUsd = 25;
17
+ const amountUsdCents = Math.round(amountUsd * 100);
18
+ expect(amountUsdCents).toBe(2500);
19
+ // Must NOT be nanodollar scale
20
+ expect(amountUsdCents).toBeLessThan(1_000_000);
21
+ });
22
+
23
+ it("minimum payment amount converts to valid cents", () => {
24
+ const MIN_PAYMENT_USD = 10;
25
+ const cents = Math.round(MIN_PAYMENT_USD * 100);
26
+ expect(cents).toBe(1000);
27
+ expect(Number.isInteger(cents)).toBe(true);
28
+ // Sanity: $10 is 1000 cents, NOT 10_000_000_000 nanodollars
29
+ expect(cents).toBeLessThan(1_000_000);
30
+ });
31
+
32
+ it("fractional USD amounts round correctly to cents", () => {
33
+ // Edge case: floating point conversion
34
+ const amountUsd = 10.99;
35
+ const cents = Math.round(amountUsd * 100);
36
+ expect(cents).toBe(1099);
37
+ expect(cents).toBeLessThan(1_000_000);
38
+ });
39
+
40
+ it("amountUsdCents stored in charge record equals USD * 100 (not nanodollars)", () => {
41
+ // The core invariant: payram/checkout.ts stores Math.round(amountUsd * 100)
42
+ // as amountUsdCents. This test proves the conversion stays at cent scale.
43
+ const testCases: Array<{ usd: number; expectedCents: number }> = [
44
+ { usd: 10, expectedCents: 1000 },
45
+ { usd: 25, expectedCents: 2500 },
46
+ { usd: 50, expectedCents: 5000 },
47
+ { usd: 100, expectedCents: 10000 },
48
+ ];
49
+
50
+ for (const { usd, expectedCents } of testCases) {
51
+ const amountUsdCents = Math.round(usd * 100);
52
+ expect(amountUsdCents).toBe(expectedCents);
53
+ // CREDIT SCALE = 1_000_000_000. If this value approaches that, unit confusion occurred.
54
+ expect(amountUsdCents).toBeLessThan(1_000_000);
55
+ }
56
+ });
57
+
58
+ it("creditedCents in webhook equals amountUsdCents from charge store (1:1 for PayRam)", () => {
59
+ // payram/webhook.ts: const creditCents = charge.amountUsdCents;
60
+ // The credited amount always equals the stored USD cents — no bonus tiers for PayRam.
61
+ const chargeAmountUsdCents = 2500; // $25.00
62
+ const creditCents = chargeAmountUsdCents; // 1:1 for PayRam
63
+ expect(creditCents).toBe(2500);
64
+ // creditedCents must be 2500 (cents), not 25_000_000_000 (nanodollars)
65
+ expect(creditCents).toBeLessThan(1_000_000);
66
+ });
67
+
68
+ it("cents-to-nanodollar scale difference is preserved as a sanity constant", () => {
69
+ // Credit.SCALE = 1_000_000_000 nanodollars per dollar
70
+ // 1 USD cent = 10_000_000 nanodollars (SCALE / 100)
71
+ // This test documents the relationship so future developers understand the gap.
72
+ const CREDIT_SCALE = 1_000_000_000;
73
+ const CENTS_PER_DOLLAR = 100;
74
+ const NANODOLLARS_PER_CENT = CREDIT_SCALE / CENTS_PER_DOLLAR;
75
+
76
+ expect(NANODOLLARS_PER_CENT).toBe(10_000_000);
77
+
78
+ // $25 in cents = 2500. $25 in nanodollars = 25_000_000_000.
79
+ // These are 10_000_000x apart — confirming that mixing the two is catastrophic.
80
+ const twentyFiveDollarsInCents = 2500;
81
+ const twentyFiveDollarsInNanodollars = 25 * CREDIT_SCALE;
82
+ expect(twentyFiveDollarsInNanodollars / twentyFiveDollarsInCents).toBe(NANODOLLARS_PER_CENT);
83
+ });
84
+ });