@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,52 @@
1
+ import { createHmac } from "node:crypto";
2
+ import { decrypt, encrypt } from "../encryption.js";
3
+ import { getVaultEncryptionKey } from "./store.js";
4
+ /** Derive a per-tenant encryption key (duplicated from tenant-keys route to avoid circular deps). */
5
+ function deriveTenantKey(tenantId, platformSecret) {
6
+ return createHmac("sha256", platformSecret).update(`tenant:${tenantId}`).digest();
7
+ }
8
+ /**
9
+ * Re-encrypt all credentials from oldSecret to newSecret.
10
+ *
11
+ * MUST be run inside a transaction by the caller.
12
+ * Back up the database before running this.
13
+ */
14
+ export async function reEncryptAllCredentials(credentialAccess, tenantKeyAccess, oldSecret, newSecret) {
15
+ const result = {
16
+ providerCredentials: { migrated: 0, errors: [] },
17
+ tenantKeys: { migrated: 0, errors: [] },
18
+ };
19
+ const oldVaultKey = getVaultEncryptionKey(oldSecret);
20
+ const newVaultKey = getVaultEncryptionKey(newSecret);
21
+ // --- provider_credentials ---
22
+ const provRows = await credentialAccess.listAllWithEncryptedValue();
23
+ for (const row of provRows) {
24
+ try {
25
+ const payload = JSON.parse(row.encryptedValue);
26
+ const plaintext = decrypt(payload, oldVaultKey);
27
+ const reEncrypted = encrypt(plaintext, newVaultKey);
28
+ await credentialAccess.updateEncryptedValueOnly(row.id, JSON.stringify(reEncrypted));
29
+ result.providerCredentials.migrated++;
30
+ }
31
+ catch (err) {
32
+ result.providerCredentials.errors.push(`Row ${row.id}: ${err instanceof Error ? err.message : String(err)}`);
33
+ }
34
+ }
35
+ // --- tenant_api_keys ---
36
+ const tenantRows = await tenantKeyAccess.listAll();
37
+ for (const row of tenantRows) {
38
+ try {
39
+ const payload = JSON.parse(row.encryptedKey);
40
+ const oldTenantKey = deriveTenantKey(row.tenantId, oldSecret);
41
+ const plaintext = decrypt(payload, oldTenantKey);
42
+ const newTenantKey = deriveTenantKey(row.tenantId, newSecret);
43
+ const reEncrypted = encrypt(plaintext, newTenantKey);
44
+ await tenantKeyAccess.updateEncryptedKey(row.id, JSON.stringify(reEncrypted));
45
+ result.tenantKeys.migrated++;
46
+ }
47
+ catch (err) {
48
+ result.tenantKeys.errors.push(`Row ${row.id}: ${err instanceof Error ? err.message : String(err)}`);
49
+ }
50
+ }
51
+ return result;
52
+ }
@@ -0,0 +1,95 @@
1
+ import { createHmac } from "node:crypto";
2
+ import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
3
+ import { createTestDb, truncateAllTables } from "../../test/db.js";
4
+ import { decrypt, encrypt } from "../encryption.js";
5
+ import { DrizzleCredentialRepository, DrizzleMigrationTenantKeyAccess } from "./credential-repository.js";
6
+ import { reEncryptAllCredentials } from "./key-rotation.js";
7
+ import { getVaultEncryptionKey } from "./store.js";
8
+ const OLD_SECRET = "old-platform-secret-for-test";
9
+ const NEW_SECRET = "new-platform-secret-for-test";
10
+ const NOW_EPOCH = Math.floor(Date.now() / 1000);
11
+ function deriveTenantKey(tenantId, secret) {
12
+ return createHmac("sha256", secret).update(`tenant:${tenantId}`).digest();
13
+ }
14
+ describe("reEncryptAllCredentials", () => {
15
+ let pool;
16
+ let db;
17
+ beforeAll(async () => {
18
+ ({ db, pool } = await createTestDb());
19
+ });
20
+ afterAll(async () => {
21
+ await pool.close();
22
+ });
23
+ beforeEach(async () => {
24
+ await truncateAllTables(pool);
25
+ });
26
+ it("re-encrypts provider credentials from old to new secret", async () => {
27
+ const oldKey = getVaultEncryptionKey(OLD_SECRET);
28
+ const encrypted = encrypt("sk-ant-real-key-12345", oldKey);
29
+ await pool.query("INSERT INTO provider_credentials (id, provider, key_name, encrypted_value, auth_type, created_by) VALUES ($1, $2, $3, $4, $5, $6)", ["cred-1", "openrouter", "default", JSON.stringify(encrypted), "bearer", "test"]);
30
+ const credAccess = new DrizzleCredentialRepository(db);
31
+ const tenantKeyAccess = new DrizzleMigrationTenantKeyAccess(db);
32
+ const result = await reEncryptAllCredentials(credAccess, tenantKeyAccess, OLD_SECRET, NEW_SECRET);
33
+ expect(result.providerCredentials.migrated).toBe(1);
34
+ expect(result.providerCredentials.errors).toHaveLength(0);
35
+ const row = await pool.query("SELECT encrypted_value FROM provider_credentials WHERE id = $1", ["cred-1"]);
36
+ const newKey = getVaultEncryptionKey(NEW_SECRET);
37
+ const payload = JSON.parse(row.rows[0].encrypted_value);
38
+ const decrypted = decrypt(payload, newKey);
39
+ expect(decrypted).toBe("sk-ant-real-key-12345");
40
+ const oldKey2 = getVaultEncryptionKey(OLD_SECRET);
41
+ expect(() => decrypt(payload, oldKey2)).toThrow();
42
+ });
43
+ it("re-encrypts tenant BYOK keys from old to new secret", async () => {
44
+ const oldTenantKey = deriveTenantKey("t1", OLD_SECRET);
45
+ const encrypted = encrypt("sk-openai-tenant-key", oldTenantKey);
46
+ await pool.query("INSERT INTO tenant_api_keys (id, tenant_id, provider, encrypted_key, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6)", ["tk-1", "t1", "openai", JSON.stringify(encrypted), NOW_EPOCH, NOW_EPOCH]);
47
+ const credAccess = new DrizzleCredentialRepository(db);
48
+ const tenantKeyAccess = new DrizzleMigrationTenantKeyAccess(db);
49
+ const result = await reEncryptAllCredentials(credAccess, tenantKeyAccess, OLD_SECRET, NEW_SECRET);
50
+ expect(result.tenantKeys.migrated).toBe(1);
51
+ expect(result.tenantKeys.errors).toHaveLength(0);
52
+ const row = await pool.query("SELECT encrypted_key FROM tenant_api_keys WHERE id = $1", [
53
+ "tk-1",
54
+ ]);
55
+ const newTenantKey = deriveTenantKey("t1", NEW_SECRET);
56
+ const payload = JSON.parse(row.rows[0].encrypted_key);
57
+ expect(decrypt(payload, newTenantKey)).toBe("sk-openai-tenant-key");
58
+ });
59
+ it("handles mixed valid and invalid rows gracefully", async () => {
60
+ const oldKey = getVaultEncryptionKey(OLD_SECRET);
61
+ const encrypted = encrypt("valid-key", oldKey);
62
+ await pool.query("INSERT INTO provider_credentials (id, provider, key_name, encrypted_value, auth_type, created_by) VALUES ($1, $2, $3, $4, $5, $6)", ["cred-1", "openrouter", "default", JSON.stringify(encrypted), "bearer", "test"]);
63
+ await pool.query("INSERT INTO provider_credentials (id, provider, key_name, encrypted_value, auth_type, created_by) VALUES ($1, $2, $3, $4, $5, $6)", ["cred-2", "openrouter", "default", "not-valid-json", "bearer", "test"]);
64
+ const credAccess = new DrizzleCredentialRepository(db);
65
+ const tenantKeyAccess = new DrizzleMigrationTenantKeyAccess(db);
66
+ const result = await reEncryptAllCredentials(credAccess, tenantKeyAccess, OLD_SECRET, NEW_SECRET);
67
+ expect(result.providerCredentials.migrated).toBe(1);
68
+ expect(result.providerCredentials.errors).toHaveLength(1);
69
+ expect(result.providerCredentials.errors[0]).toContain("cred-2");
70
+ });
71
+ it("returns zero counts when tables are empty", async () => {
72
+ const credAccess = new DrizzleCredentialRepository(db);
73
+ const tenantKeyAccess = new DrizzleMigrationTenantKeyAccess(db);
74
+ const result = await reEncryptAllCredentials(credAccess, tenantKeyAccess, OLD_SECRET, NEW_SECRET);
75
+ expect(result.providerCredentials.migrated).toBe(0);
76
+ expect(result.tenantKeys.migrated).toBe(0);
77
+ });
78
+ it("re-encrypts multiple provider credentials", async () => {
79
+ const oldKey = getVaultEncryptionKey(OLD_SECRET);
80
+ for (let i = 1; i <= 3; i++) {
81
+ const encrypted = encrypt(`sk-key-${i}`, oldKey);
82
+ await pool.query("INSERT INTO provider_credentials (id, provider, key_name, encrypted_value, auth_type, created_by) VALUES ($1, $2, $3, $4, $5, $6)", [`cred-${i}`, "openrouter", "default", JSON.stringify(encrypted), "bearer", "test"]);
83
+ }
84
+ const credAccess = new DrizzleCredentialRepository(db);
85
+ const tenantKeyAccess = new DrizzleMigrationTenantKeyAccess(db);
86
+ const result = await reEncryptAllCredentials(credAccess, tenantKeyAccess, OLD_SECRET, NEW_SECRET);
87
+ expect(result.providerCredentials.migrated).toBe(3);
88
+ const newKey = getVaultEncryptionKey(NEW_SECRET);
89
+ for (let i = 1; i <= 3; i++) {
90
+ const row = await pool.query("SELECT encrypted_value FROM provider_credentials WHERE id = $1", [`cred-${i}`]);
91
+ const payload = JSON.parse(row.rows[0].encrypted_value);
92
+ expect(decrypt(payload, newKey)).toBe(`sk-key-${i}`);
93
+ }
94
+ });
95
+ });
@@ -0,0 +1,15 @@
1
+ import type { ICredentialMigrationAccess, IMigrationTenantKeyAccess } from "./credential-repository.js";
2
+ export interface MigrationResult {
3
+ table: string;
4
+ migratedCount: number;
5
+ errors: string[];
6
+ }
7
+ /**
8
+ * Migrate any plaintext credentials to encrypted form.
9
+ *
10
+ * For provider_credentials: re-encrypts encrypted_value column using vaultKey.
11
+ * For tenant_api_keys: re-encrypts encrypted_key column using tenantKeyDeriver.
12
+ *
13
+ * IMPORTANT: This is destructive — run in a transaction and back up first.
14
+ */
15
+ export declare function migratePlaintextCredentials(credentialRepo: ICredentialMigrationAccess, vaultKey: Buffer, tenantKeyDeriver: (tenantId: string) => Buffer, tenantKeyAccess?: IMigrationTenantKeyAccess | null): Promise<MigrationResult[]>;
@@ -0,0 +1,80 @@
1
+ import { encrypt } from "../encryption.js";
2
+ import { scanForKeyLeaks } from "../key-audit.js";
3
+ /**
4
+ * Migrate any plaintext credentials to encrypted form.
5
+ *
6
+ * For provider_credentials: re-encrypts encrypted_value column using vaultKey.
7
+ * For tenant_api_keys: re-encrypts encrypted_key column using tenantKeyDeriver.
8
+ *
9
+ * IMPORTANT: This is destructive — run in a transaction and back up first.
10
+ */
11
+ export async function migratePlaintextCredentials(credentialRepo, vaultKey, tenantKeyDeriver, tenantKeyAccess) {
12
+ const results = [];
13
+ // --- provider_credentials ---
14
+ const provResult = {
15
+ table: "provider_credentials",
16
+ migratedCount: 0,
17
+ errors: [],
18
+ };
19
+ const provRows = await credentialRepo.listAllWithEncryptedValue();
20
+ for (const row of provRows) {
21
+ try {
22
+ const parsed = JSON.parse(row.encryptedValue);
23
+ if (parsed.iv && parsed.authTag && parsed.ciphertext) {
24
+ continue; // Already encrypted
25
+ }
26
+ }
27
+ catch {
28
+ // Not JSON — treat as plaintext
29
+ }
30
+ // This row has plaintext data — encrypt it
31
+ const leaks = scanForKeyLeaks(row.encryptedValue);
32
+ if (leaks.length === 0 && row.encryptedValue.trim() === "") {
33
+ continue; // Empty value, skip
34
+ }
35
+ try {
36
+ const encrypted = encrypt(row.encryptedValue, vaultKey);
37
+ const serialized = JSON.stringify(encrypted);
38
+ await credentialRepo.updateEncryptedValueOnly(row.id, serialized);
39
+ provResult.migratedCount++;
40
+ }
41
+ catch (err) {
42
+ provResult.errors.push(`Row ${row.id}: ${err instanceof Error ? err.message : String(err)}`);
43
+ }
44
+ }
45
+ results.push(provResult);
46
+ // --- tenant_api_keys ---
47
+ if (tenantKeyAccess) {
48
+ const tenantResult = {
49
+ table: "tenant_api_keys",
50
+ migratedCount: 0,
51
+ errors: [],
52
+ };
53
+ const tenantRows = await tenantKeyAccess.listAll();
54
+ for (const row of tenantRows) {
55
+ try {
56
+ const parsed = JSON.parse(row.encryptedKey);
57
+ if (parsed.iv && parsed.authTag && parsed.ciphertext) {
58
+ continue; // Already encrypted
59
+ }
60
+ }
61
+ catch {
62
+ // Not JSON — treat as plaintext
63
+ }
64
+ if (row.encryptedKey.trim() === "")
65
+ continue;
66
+ try {
67
+ const tenantKey = tenantKeyDeriver(row.tenantId);
68
+ const encrypted = encrypt(row.encryptedKey, tenantKey);
69
+ const serialized = JSON.stringify(encrypted);
70
+ await tenantKeyAccess.updateEncryptedKey(row.id, serialized);
71
+ tenantResult.migratedCount++;
72
+ }
73
+ catch (err) {
74
+ tenantResult.errors.push(`Row ${row.id}: ${err instanceof Error ? err.message : String(err)}`);
75
+ }
76
+ }
77
+ results.push(tenantResult);
78
+ }
79
+ return results;
80
+ }
@@ -0,0 +1,111 @@
1
+ import crypto from "node:crypto";
2
+ import { describe, expect, it } from "vitest";
3
+ import { decrypt, encrypt } from "../encryption.js";
4
+ import { migratePlaintextCredentials } from "./migrate-plaintext.js";
5
+ // ---------------------------------------------------------------------------
6
+ // Mock helpers
7
+ // ---------------------------------------------------------------------------
8
+ function mockCredentialRepo(rows = []) {
9
+ const updates = [];
10
+ return {
11
+ updates,
12
+ listAllWithEncryptedValue: async () => [...rows],
13
+ updateEncryptedValueOnly: async (id, encryptedValue) => {
14
+ updates.push({ id, encryptedValue });
15
+ // Also update the source array so re-reads see the new value
16
+ const row = rows.find((r) => r.id === id);
17
+ if (row)
18
+ row.encryptedValue = encryptedValue;
19
+ },
20
+ };
21
+ }
22
+ function mockTenantKeyAccess(rows = []) {
23
+ const updates = [];
24
+ return {
25
+ updates,
26
+ listAll: async () => [...rows],
27
+ updateEncryptedKey: async (id, encryptedKey) => {
28
+ updates.push({ id, encryptedKey });
29
+ },
30
+ };
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Tests
34
+ // ---------------------------------------------------------------------------
35
+ describe("migratePlaintextCredentials", () => {
36
+ const vaultKey = crypto.randomBytes(32);
37
+ const tenantKeyDeriver = (_tenantId) => crypto.randomBytes(32);
38
+ it("returns empty results when no rows exist", async () => {
39
+ const repo = mockCredentialRepo();
40
+ const tenantAccess = mockTenantKeyAccess();
41
+ const results = await migratePlaintextCredentials(repo, vaultKey, tenantKeyDeriver, tenantAccess);
42
+ expect(results).toHaveLength(2);
43
+ expect(results.find((r) => r.table === "provider_credentials")?.migratedCount).toBe(0);
44
+ expect(results.find((r) => r.table === "tenant_api_keys")?.migratedCount).toBe(0);
45
+ });
46
+ it("returns only provider results when no tenant access provided", async () => {
47
+ const repo = mockCredentialRepo();
48
+ const results = await migratePlaintextCredentials(repo, vaultKey, tenantKeyDeriver);
49
+ expect(results).toHaveLength(1);
50
+ expect(results[0].table).toBe("provider_credentials");
51
+ });
52
+ it("skips already-encrypted provider credentials", async () => {
53
+ const encrypted = encrypt("my-secret-key", vaultKey);
54
+ const repo = mockCredentialRepo([{ id: "cred-1", encryptedValue: JSON.stringify(encrypted) }]);
55
+ const results = await migratePlaintextCredentials(repo, vaultKey, tenantKeyDeriver);
56
+ expect(results.find((r) => r.table === "provider_credentials")?.migratedCount).toBe(0);
57
+ expect(repo.updates).toHaveLength(0);
58
+ });
59
+ it("encrypts plaintext provider credentials", async () => {
60
+ const repo = mockCredentialRepo([{ id: "cred-2", encryptedValue: "sk-plaintext-key-value" }]);
61
+ const results = await migratePlaintextCredentials(repo, vaultKey, tenantKeyDeriver);
62
+ const provResult = results.find((r) => r.table === "provider_credentials");
63
+ expect(provResult?.migratedCount).toBe(1);
64
+ expect(provResult?.errors).toHaveLength(0);
65
+ expect(repo.updates).toHaveLength(1);
66
+ const parsed = JSON.parse(repo.updates[0].encryptedValue);
67
+ expect(parsed).toHaveProperty("iv");
68
+ expect(parsed).toHaveProperty("authTag");
69
+ expect(parsed).toHaveProperty("ciphertext");
70
+ expect(decrypt(parsed, vaultKey)).toBe("sk-plaintext-key-value");
71
+ });
72
+ it("skips empty provider credential values", async () => {
73
+ const repo = mockCredentialRepo([{ id: "cred-3", encryptedValue: " " }]);
74
+ const results = await migratePlaintextCredentials(repo, vaultKey, tenantKeyDeriver);
75
+ expect(results.find((r) => r.table === "provider_credentials")?.migratedCount).toBe(0);
76
+ expect(repo.updates).toHaveLength(0);
77
+ });
78
+ it("encrypts plaintext tenant API keys", async () => {
79
+ const stableKey = crypto.randomBytes(32);
80
+ const stableDeriver = (_tenantId) => stableKey;
81
+ const tenantAccess = mockTenantKeyAccess([{ id: "key-1", tenantId: "t-1", encryptedKey: "plaintext-tenant-key" }]);
82
+ const repo = mockCredentialRepo();
83
+ const results = await migratePlaintextCredentials(repo, vaultKey, stableDeriver, tenantAccess);
84
+ const tenantResult = results.find((r) => r.table === "tenant_api_keys");
85
+ expect(tenantResult?.migratedCount).toBe(1);
86
+ expect(tenantAccess.updates).toHaveLength(1);
87
+ const parsed = JSON.parse(tenantAccess.updates[0].encryptedKey);
88
+ expect(parsed).toHaveProperty("iv");
89
+ expect(decrypt(parsed, stableKey)).toBe("plaintext-tenant-key");
90
+ });
91
+ it("skips already-encrypted tenant API keys", async () => {
92
+ const stableKey = crypto.randomBytes(32);
93
+ const encrypted = encrypt("my-key", stableKey);
94
+ const tenantAccess = mockTenantKeyAccess([
95
+ { id: "key-2", tenantId: "t-1", encryptedKey: JSON.stringify(encrypted) },
96
+ ]);
97
+ const repo = mockCredentialRepo();
98
+ const results = await migratePlaintextCredentials(repo, vaultKey, () => stableKey, tenantAccess);
99
+ expect(results.find((r) => r.table === "tenant_api_keys")?.migratedCount).toBe(0);
100
+ expect(tenantAccess.updates).toHaveLength(0);
101
+ });
102
+ it("records errors without aborting migration for bad key length", async () => {
103
+ const badKey = crypto.randomBytes(16); // wrong length
104
+ const repo = mockCredentialRepo([{ id: "cred-err", encryptedValue: "plaintext-value" }]);
105
+ const results = await migratePlaintextCredentials(repo, badKey, tenantKeyDeriver);
106
+ const provResult = results.find((r) => r.table === "provider_credentials");
107
+ expect(provResult?.migratedCount).toBe(0);
108
+ expect(provResult?.errors).toHaveLength(1);
109
+ expect(provResult?.errors[0]).toContain("cred-err");
110
+ });
111
+ });
@@ -0,0 +1,15 @@
1
+ import type { PlatformDb } from "../../db/index.js";
2
+ /**
3
+ * Scan all credential columns in the database for plaintext API key patterns.
4
+ * Returns an array of findings. Empty array = all clear.
5
+ *
6
+ * This is a safety net, not a migration — the platform was designed encrypted-first.
7
+ * Run as part of deployment validation or as a periodic security check.
8
+ */
9
+ export interface PlaintextFinding {
10
+ table: string;
11
+ column: string;
12
+ rowId: string;
13
+ provider: string;
14
+ }
15
+ export declare function auditCredentialEncryption(db: PlatformDb): Promise<PlaintextFinding[]>;
@@ -0,0 +1,71 @@
1
+ import { providerCredentials, tenantApiKeys } from "../../db/schema/index.js";
2
+ import { scanForKeyLeaks } from "../key-audit.js";
3
+ export async function auditCredentialEncryption(db) {
4
+ const findings = [];
5
+ // Check provider_credentials.encrypted_value
6
+ const providerRows = await db
7
+ .select({ id: providerCredentials.id, encryptedValue: providerCredentials.encryptedValue })
8
+ .from(providerCredentials);
9
+ for (const row of providerRows) {
10
+ // A properly encrypted value should be a JSON object with iv/authTag/ciphertext
11
+ try {
12
+ const parsed = JSON.parse(row.encryptedValue);
13
+ if (!parsed.iv || !parsed.authTag || !parsed.ciphertext) {
14
+ findings.push({
15
+ table: "provider_credentials",
16
+ column: "encrypted_value",
17
+ rowId: row.id,
18
+ provider: "unknown",
19
+ });
20
+ }
21
+ }
22
+ catch {
23
+ // Not valid JSON = likely plaintext
24
+ const leaks = scanForKeyLeaks(row.encryptedValue);
25
+ if (leaks.length > 0 || row.encryptedValue.trim().length > 0) {
26
+ findings.push({
27
+ table: "provider_credentials",
28
+ column: "encrypted_value",
29
+ rowId: row.id,
30
+ provider: leaks[0]?.provider ?? "unknown",
31
+ });
32
+ }
33
+ }
34
+ }
35
+ // Check tenant_api_keys.encrypted_key (if table exists)
36
+ try {
37
+ const tenantRows = await db
38
+ .select({ id: tenantApiKeys.id, encryptedKey: tenantApiKeys.encryptedKey })
39
+ .from(tenantApiKeys);
40
+ for (const row of tenantRows) {
41
+ try {
42
+ const parsed = JSON.parse(row.encryptedKey);
43
+ if (!parsed.iv || !parsed.authTag || !parsed.ciphertext) {
44
+ findings.push({
45
+ table: "tenant_api_keys",
46
+ column: "encrypted_key",
47
+ rowId: row.id,
48
+ provider: "unknown",
49
+ });
50
+ }
51
+ }
52
+ catch {
53
+ const leaks = scanForKeyLeaks(row.encryptedKey);
54
+ if (leaks.length > 0 || row.encryptedKey.trim().length > 0) {
55
+ findings.push({
56
+ table: "tenant_api_keys",
57
+ column: "encrypted_key",
58
+ rowId: row.id,
59
+ provider: leaks[0]?.provider ?? "unknown",
60
+ });
61
+ }
62
+ }
63
+ }
64
+ }
65
+ catch (err) {
66
+ if (!(err instanceof Error && err.message.includes("no such table")))
67
+ throw err;
68
+ // Table doesn't exist yet — that's fine
69
+ }
70
+ return findings;
71
+ }