@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,140 @@
1
+ import { Hono } from "hono";
2
+ import { beforeEach, describe, expect, it } from "vitest";
3
+ import { extractBearerToken, requireRole, timingSafeMapLookup } from "./index.js";
4
+ // ---------------------------------------------------------------------------
5
+ // extractBearerToken
6
+ // ---------------------------------------------------------------------------
7
+ describe("extractBearerToken", () => {
8
+ it("extracts token from valid Bearer header", () => {
9
+ expect(extractBearerToken("Bearer abc123")).toBe("abc123");
10
+ });
11
+ it("handles case-insensitive Bearer prefix", () => {
12
+ expect(extractBearerToken("bearer abc123")).toBe("abc123");
13
+ expect(extractBearerToken("BEARER abc123")).toBe("abc123");
14
+ expect(extractBearerToken("BeArEr abc123")).toBe("abc123");
15
+ });
16
+ it("returns null for undefined header", () => {
17
+ expect(extractBearerToken(undefined)).toBeNull();
18
+ });
19
+ it("returns null for empty string", () => {
20
+ expect(extractBearerToken("")).toBeNull();
21
+ });
22
+ it("returns null for non-Bearer scheme", () => {
23
+ expect(extractBearerToken("Basic abc123")).toBeNull();
24
+ expect(extractBearerToken("Digest abc123")).toBeNull();
25
+ });
26
+ it("returns null for Bearer with no token", () => {
27
+ expect(extractBearerToken("Bearer ")).toBeNull();
28
+ expect(extractBearerToken("Bearer")).toBeNull();
29
+ });
30
+ it("trims whitespace from header and token", () => {
31
+ expect(extractBearerToken(" Bearer abc123 ")).toBe("abc123");
32
+ });
33
+ it("preserves token characters", () => {
34
+ const token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiMSJ9.sig";
35
+ expect(extractBearerToken(`Bearer ${token}`)).toBe(token);
36
+ });
37
+ });
38
+ // ---------------------------------------------------------------------------
39
+ // requireRole middleware
40
+ // ---------------------------------------------------------------------------
41
+ describe("requireRole middleware", () => {
42
+ let app;
43
+ beforeEach(() => {
44
+ app = new Hono();
45
+ // Inject user directly for testing requireRole in isolation
46
+ app.use("/*", async (c, next) => {
47
+ const authHeader = c.req.header("X-Test-Roles");
48
+ if (authHeader !== undefined) {
49
+ const roles = authHeader ? authHeader.split(",").map((r) => r.trim()) : [];
50
+ const userId = c.req.header("X-Test-User-Id") ?? "test-user";
51
+ c.set("user", { id: userId, roles });
52
+ c.set("authMethod", "api_key");
53
+ }
54
+ return next();
55
+ });
56
+ app.get("/admin", requireRole("admin"), (c) => {
57
+ return c.json({ ok: true, user: c.get("user").id });
58
+ });
59
+ app.get("/editor", requireRole("editor"), (c) => {
60
+ return c.json({ ok: true });
61
+ });
62
+ });
63
+ it("allows user with required role", async () => {
64
+ const res = await app.request("/admin", {
65
+ headers: { "X-Test-User-Id": "admin-user", "X-Test-Roles": "admin,user" },
66
+ });
67
+ expect(res.status).toBe(200);
68
+ const body = await res.json();
69
+ expect(body.ok).toBe(true);
70
+ expect(body.user).toBe("admin-user");
71
+ });
72
+ it("rejects user without required role", async () => {
73
+ const res = await app.request("/admin", {
74
+ headers: { "X-Test-User-Id": "basic-user", "X-Test-Roles": "user" },
75
+ });
76
+ expect(res.status).toBe(403);
77
+ const body = await res.json();
78
+ expect(body.error).toBe("Insufficient permissions");
79
+ expect(body.required).toBe("admin");
80
+ });
81
+ it("rejects user with empty roles array", async () => {
82
+ const res = await app.request("/admin", {
83
+ headers: { "X-Test-User-Id": "no-roles", "X-Test-Roles": "" },
84
+ });
85
+ expect(res.status).toBe(403);
86
+ });
87
+ it("returns 401 when no auth (requireRole without user set)", async () => {
88
+ const noAuthApp = new Hono();
89
+ noAuthApp.get("/admin", requireRole("admin"), (c) => c.json({ ok: true }));
90
+ const res = await noAuthApp.request("/admin");
91
+ expect(res.status).toBe(401);
92
+ const body = await res.json();
93
+ expect(body.error).toBe("Authentication required");
94
+ });
95
+ it("works with multiple roles (only one required)", async () => {
96
+ const res = await app.request("/editor", {
97
+ headers: { "X-Test-Roles": "user,editor,admin" },
98
+ });
99
+ expect(res.status).toBe(200);
100
+ });
101
+ it("role check is case-sensitive", async () => {
102
+ const res = await app.request("/admin", {
103
+ headers: { "X-Test-Roles": "Admin" },
104
+ });
105
+ expect(res.status).toBe(403);
106
+ });
107
+ });
108
+ // ---------------------------------------------------------------------------
109
+ // timingSafeMapLookup
110
+ // ---------------------------------------------------------------------------
111
+ describe("timingSafeMapLookup", () => {
112
+ it("returns the value for an exact match", () => {
113
+ const map = new Map([["secret-token", "admin"]]);
114
+ expect(timingSafeMapLookup(map, "secret-token")).toBe("admin");
115
+ });
116
+ it("returns undefined for a non-matching key", () => {
117
+ const map = new Map([["secret-token", "admin"]]);
118
+ expect(timingSafeMapLookup(map, "wrong-token")).toBeUndefined();
119
+ });
120
+ it("returns undefined for a key with different length", () => {
121
+ const map = new Map([["short", "val"]]);
122
+ expect(timingSafeMapLookup(map, "a-much-longer-key")).toBeUndefined();
123
+ });
124
+ it("returns undefined when map is empty", () => {
125
+ const map = new Map();
126
+ expect(timingSafeMapLookup(map, "any-token")).toBeUndefined();
127
+ });
128
+ it("matches the correct entry among multiple keys", () => {
129
+ const map = new Map([
130
+ ["token-aaa", "read"],
131
+ ["token-bbb", "write"],
132
+ ["token-ccc", "admin"],
133
+ ]);
134
+ expect(timingSafeMapLookup(map, "token-bbb")).toBe("write");
135
+ });
136
+ it("returns undefined for empty input string", () => {
137
+ const map = new Map([["secret", "val"]]);
138
+ expect(timingSafeMapLookup(map, "")).toBeUndefined();
139
+ });
140
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Better Auth — Platform auth source of truth.
3
+ *
4
+ * Provides email+password auth, session management, and cookie-based auth
5
+ * for the platform UI. Uses PostgreSQL via pg.Pool for persistence.
6
+ *
7
+ * The auth instance is lazily initialized to avoid opening the database
8
+ * at module import time (which breaks tests).
9
+ */
10
+ import { betterAuth } from "better-auth";
11
+ import type { Pool } from "pg";
12
+ import type { PlatformDb } from "../db/index.js";
13
+ import { PgEmailVerifier } from "../email/verification.js";
14
+ /** Configuration for initializing Better Auth in platform-core. */
15
+ export interface BetterAuthConfig {
16
+ pool: Pool;
17
+ db: PlatformDb;
18
+ /** Called after a new user signs up (e.g., create personal tenant). */
19
+ onUserCreated?: (userId: string, userName: string, email: string) => Promise<void>;
20
+ }
21
+ /** The type of a better-auth instance. */
22
+ export type Auth = ReturnType<typeof betterAuth>;
23
+ /** Initialize Better Auth with the given config. Must be called before getAuth(). */
24
+ export declare function initBetterAuth(config: BetterAuthConfig): void;
25
+ /**
26
+ * Run better-auth migrations against the auth database.
27
+ * Must be called after initBetterAuth().
28
+ */
29
+ export declare function runAuthMigrations(): Promise<void>;
30
+ /**
31
+ * Get or create the singleton better-auth instance.
32
+ * Lazily initialized on first call. initBetterAuth() must be called first.
33
+ */
34
+ export declare function getAuth(): Auth;
35
+ /** Get an IEmailVerifier backed by the auth database. */
36
+ export declare function getEmailVerifier(): PgEmailVerifier;
37
+ /** Replace the singleton auth instance (for testing). */
38
+ export declare function setAuth(auth: Auth): void;
39
+ /** Reset the singleton (for testing cleanup). */
40
+ export declare function resetAuth(): void;
41
+ /** Reset the user creator singleton (for testing). */
42
+ export declare function resetUserCreator(): void;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Better Auth — Platform auth source of truth.
3
+ *
4
+ * Provides email+password auth, session management, and cookie-based auth
5
+ * for the platform UI. Uses PostgreSQL via pg.Pool for persistence.
6
+ *
7
+ * The auth instance is lazily initialized to avoid opening the database
8
+ * at module import time (which breaks tests).
9
+ */
10
+ import { betterAuth } from "better-auth";
11
+ import { twoFactor } from "better-auth/plugins";
12
+ import { RoleStore } from "../admin/role-store.js";
13
+ import { logger } from "../config/logger.js";
14
+ import { initTwoFactorSchema } from "../db/auth-user-repository.js";
15
+ import { getEmailClient } from "../email/client.js";
16
+ import { passwordResetEmailTemplate, verifyEmailTemplate } from "../email/templates.js";
17
+ import { generateVerificationToken, initVerificationSchema, PgEmailVerifier } from "../email/verification.js";
18
+ import { createUserCreator } from "./user-creator.js";
19
+ const BETTER_AUTH_SECRET = process.env.BETTER_AUTH_SECRET || "";
20
+ const BETTER_AUTH_URL = process.env.BETTER_AUTH_URL || "http://localhost:3100";
21
+ let _config = null;
22
+ let _userCreator = null;
23
+ let _userCreatorPromise = null;
24
+ async function getUserCreator() {
25
+ if (_userCreator)
26
+ return _userCreator;
27
+ if (!_userCreatorPromise) {
28
+ if (!_config)
29
+ throw new Error("BetterAuth not initialized — call initBetterAuth() first");
30
+ _userCreatorPromise = createUserCreator(new RoleStore(_config.db)).then((creator) => {
31
+ _userCreator = creator;
32
+ return creator;
33
+ });
34
+ }
35
+ return _userCreatorPromise;
36
+ }
37
+ function authOptions(pool) {
38
+ return {
39
+ database: pool,
40
+ secret: BETTER_AUTH_SECRET,
41
+ baseURL: BETTER_AUTH_URL,
42
+ basePath: "/api/auth",
43
+ socialProviders: {
44
+ ...(process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET
45
+ ? { github: { clientId: process.env.GITHUB_CLIENT_ID, clientSecret: process.env.GITHUB_CLIENT_SECRET } }
46
+ : {}),
47
+ ...(process.env.DISCORD_CLIENT_ID && process.env.DISCORD_CLIENT_SECRET
48
+ ? { discord: { clientId: process.env.DISCORD_CLIENT_ID, clientSecret: process.env.DISCORD_CLIENT_SECRET } }
49
+ : {}),
50
+ ...(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET
51
+ ? { google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET } }
52
+ : {}),
53
+ },
54
+ account: {
55
+ accountLinking: {
56
+ enabled: true,
57
+ trustedProviders: ["github", "google"],
58
+ },
59
+ },
60
+ emailAndPassword: {
61
+ enabled: true,
62
+ minPasswordLength: 12,
63
+ sendResetPassword: async ({ user, url }) => {
64
+ try {
65
+ const emailClient = getEmailClient();
66
+ const template = passwordResetEmailTemplate(url, user.email);
67
+ await emailClient.send({
68
+ to: user.email,
69
+ ...template,
70
+ userId: user.id,
71
+ templateName: "password-reset",
72
+ });
73
+ }
74
+ catch (error) {
75
+ logger.error("Failed to send password reset email:", error);
76
+ }
77
+ },
78
+ },
79
+ databaseHooks: {
80
+ user: {
81
+ create: {
82
+ after: async (user) => {
83
+ try {
84
+ const userCreator = await getUserCreator();
85
+ await userCreator.createUser(user.id);
86
+ }
87
+ catch (error) {
88
+ logger.error("Failed to run user creator:", error);
89
+ }
90
+ if (user.emailVerified)
91
+ return;
92
+ try {
93
+ await initVerificationSchema(pool);
94
+ const { token } = await generateVerificationToken(pool, user.id);
95
+ const verifyUrl = `${BETTER_AUTH_URL}/auth/verify?token=${token}`;
96
+ const emailClient = getEmailClient();
97
+ const template = verifyEmailTemplate(verifyUrl, user.email);
98
+ await emailClient.send({
99
+ to: user.email,
100
+ ...template,
101
+ userId: user.id,
102
+ templateName: "verify-email",
103
+ });
104
+ }
105
+ catch (error) {
106
+ logger.error("Failed to send verification email:", error);
107
+ }
108
+ // Delegate personal tenant creation to the consumer
109
+ if (_config?.onUserCreated) {
110
+ try {
111
+ await _config.onUserCreated(user.id, user.name || user.email, user.email);
112
+ }
113
+ catch (error) {
114
+ logger.error("Failed to run onUserCreated callback:", error);
115
+ }
116
+ }
117
+ },
118
+ },
119
+ },
120
+ },
121
+ session: {
122
+ cookieCache: { enabled: true, maxAge: 5 * 60 },
123
+ },
124
+ advanced: {
125
+ cookiePrefix: "better-auth",
126
+ cookies: {
127
+ session_token: {
128
+ attributes: {
129
+ domain: process.env.COOKIE_DOMAIN || ".wopr.bot",
130
+ },
131
+ },
132
+ },
133
+ },
134
+ plugins: [twoFactor()],
135
+ rateLimit: {
136
+ enabled: true,
137
+ window: 60,
138
+ max: 100,
139
+ customRules: {
140
+ "/sign-in/email": { window: 900, max: 5 },
141
+ "/sign-up/email": { window: 3600, max: 10 },
142
+ "/request-password-reset": { window: 3600, max: 3 },
143
+ },
144
+ storage: "memory",
145
+ },
146
+ trustedOrigins: (process.env.UI_ORIGIN || "http://localhost:3001").split(","),
147
+ };
148
+ }
149
+ /** Initialize Better Auth with the given config. Must be called before getAuth(). */
150
+ export function initBetterAuth(config) {
151
+ _config = config;
152
+ }
153
+ /**
154
+ * Run better-auth migrations against the auth database.
155
+ * Must be called after initBetterAuth().
156
+ */
157
+ export async function runAuthMigrations() {
158
+ if (!_config)
159
+ throw new Error("BetterAuth not initialized — call initBetterAuth() first");
160
+ const { getMigrations } = (await import("better-auth/db"));
161
+ const { runMigrations } = await getMigrations(authOptions(_config.pool));
162
+ await runMigrations();
163
+ await initTwoFactorSchema(_config.pool);
164
+ }
165
+ let _auth = null;
166
+ /**
167
+ * Get or create the singleton better-auth instance.
168
+ * Lazily initialized on first call. initBetterAuth() must be called first.
169
+ */
170
+ export function getAuth() {
171
+ if (!_auth) {
172
+ if (!_config)
173
+ throw new Error("BetterAuth not initialized — call initBetterAuth() first");
174
+ _auth = betterAuth(authOptions(_config.pool));
175
+ }
176
+ return _auth;
177
+ }
178
+ /** Get an IEmailVerifier backed by the auth database. */
179
+ export function getEmailVerifier() {
180
+ if (!_config)
181
+ throw new Error("BetterAuth not initialized — call initBetterAuth() first");
182
+ return new PgEmailVerifier(_config.pool);
183
+ }
184
+ /** Replace the singleton auth instance (for testing). */
185
+ export function setAuth(auth) {
186
+ _auth = auth;
187
+ }
188
+ /** Reset the singleton (for testing cleanup). */
189
+ export function resetAuth() {
190
+ _auth = null;
191
+ }
192
+ /** Reset the user creator singleton (for testing). */
193
+ export function resetUserCreator() {
194
+ _userCreator = null;
195
+ _userCreatorPromise = null;
196
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Auth — Session management, token verification, and middleware.
3
+ *
4
+ * Provides:
5
+ * - `requireRole` middleware for role-based access control
6
+ * - `scopedBearerAuth` middleware for operation-scoped API tokens
7
+ */
8
+ import type { Context, Next } from "hono";
9
+ import type { IOrgMemberRepository } from "../tenancy/org-member-repository.js";
10
+ export interface AuthUser {
11
+ id: string;
12
+ roles: string[];
13
+ }
14
+ export interface AuthEnv {
15
+ Variables: {
16
+ user: AuthUser;
17
+ authMethod: "session" | "api_key";
18
+ tokenTenantId?: string;
19
+ isOperatorToken?: boolean;
20
+ };
21
+ }
22
+ /**
23
+ * Extract the bearer token from an Authorization header value.
24
+ * Returns `null` if the header is missing, empty, or not a Bearer scheme.
25
+ */
26
+ export declare function extractBearerToken(header: string | undefined): string | null;
27
+ /**
28
+ * Timing-safe lookup of a string key in a Map.
29
+ *
30
+ * Iterates all entries and compares each key using `crypto.timingSafeEqual`
31
+ * to prevent timing side-channel attacks. Returns the value of the first
32
+ * matching key, or `undefined` if no key matches.
33
+ */
34
+ export declare function timingSafeMapLookup<V>(map: Map<string, V>, candidate: string): V | undefined;
35
+ /**
36
+ * Create a `requireRole` middleware that rejects users without the specified role.
37
+ * Must be used after `requireAuth`.
38
+ */
39
+ export declare function requireRole(role: string): (c: Context<AuthEnv>, next: Next) => Promise<void | (Response & import("hono").TypedResponse<{
40
+ error: string;
41
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
42
+ error: string;
43
+ required: string;
44
+ }, 403, "json">)>;
45
+ /** Operation scopes ordered by privilege level. */
46
+ export type TokenScope = "read" | "write" | "admin";
47
+ /**
48
+ * Parse a token's scope from the `wopr_<scope>_<random>` format.
49
+ *
50
+ * - `wopr_read_abc123` -> `"read"`
51
+ * - `wopr_write_abc123` -> `"write"`
52
+ * - `wopr_admin_abc123` -> `"admin"`
53
+ * - Any other format -> `null` (not a scoped token)
54
+ */
55
+ export declare function parseTokenScope(token: string): TokenScope | null;
56
+ /**
57
+ * Check whether a token's scope satisfies the required minimum scope.
58
+ * admin >= write >= read.
59
+ */
60
+ export declare function scopeSatisfies(tokenScope: TokenScope, requiredScope: TokenScope): boolean;
61
+ export interface ScopedTokenConfig {
62
+ /**
63
+ * Map of token string -> its scope.
64
+ * Tokens can be in `wopr_<scope>_<random>` format (scope parsed automatically)
65
+ * or plain strings mapped explicitly.
66
+ */
67
+ tokens: Map<string, TokenScope>;
68
+ }
69
+ /** Token metadata including scope and tenant association. */
70
+ export interface TokenMetadata {
71
+ scope: TokenScope;
72
+ tenantId?: string;
73
+ }
74
+ /**
75
+ * Build a token-to-scope map from environment variables.
76
+ *
77
+ * Accepts:
78
+ * - `FLEET_API_TOKEN` (legacy single token, treated as admin)
79
+ * - `FLEET_API_TOKEN_READ` (read-scoped token)
80
+ * - `FLEET_API_TOKEN_WRITE` (write-scoped token)
81
+ * - `FLEET_API_TOKEN_ADMIN` (admin-scoped token)
82
+ * - Any `wopr_<scope>_<random>` formatted token has its scope inferred.
83
+ */
84
+ export declare function buildTokenMap(env?: Record<string, string | undefined>): Map<string, TokenScope>;
85
+ /**
86
+ * Build a token-to-metadata map from environment variables.
87
+ *
88
+ * Accepts:
89
+ * - `FLEET_TOKEN_<TENANT>=<scope>:<token>` (tenant-scoped tokens)
90
+ * - Fallback to legacy token map for backwards compatibility (no tenant constraint)
91
+ *
92
+ * Example: `FLEET_TOKEN_ACME=write:wopr_write_abc123`
93
+ */
94
+ export declare function buildTokenMetadataMap(env?: Record<string, string | undefined>): Map<string, TokenMetadata>;
95
+ /**
96
+ * Create a scoped bearer auth middleware.
97
+ *
98
+ * Validates the bearer token against the token map and checks that the
99
+ * token's scope satisfies the required minimum scope for the route.
100
+ *
101
+ * @param tokenMap - Map of token -> scope (use `buildTokenMap()` to create)
102
+ * @param requiredScope - Minimum scope required for this route/group
103
+ */
104
+ export declare function scopedBearerAuth(tokenMap: Map<string, TokenScope>, requiredScope: TokenScope): (c: Context, next: Next) => Promise<void | (Response & import("hono").TypedResponse<{
105
+ error: string;
106
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
107
+ error: string;
108
+ required: TokenScope;
109
+ provided: TokenScope;
110
+ }, 403, "json">)>;
111
+ /**
112
+ * Create a tenant-aware scoped bearer auth middleware.
113
+ *
114
+ * Validates the bearer token against the metadata map, checks scope,
115
+ * and stores the token's associated tenantId for downstream ownership checks.
116
+ *
117
+ * @param metadataMap - Map of token -> metadata (use `buildTokenMetadataMap()` to create)
118
+ * @param requiredScope - Minimum scope required for this route/group
119
+ */
120
+ export declare function scopedBearerAuthWithTenant(metadataMap: Map<string, TokenMetadata>, requiredScope: TokenScope): (c: Context<AuthEnv>, next: Next) => Promise<void | (Response & import("hono").TypedResponse<{
121
+ error: string;
122
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
123
+ error: string;
124
+ required: TokenScope;
125
+ provided: TokenScope;
126
+ }, 403, "json">)>;
127
+ /**
128
+ * Middleware that resolves the current user from a better-auth session cookie.
129
+ *
130
+ * On success, sets:
131
+ * - `c.set("user", { id, roles })`
132
+ * - `c.set("authMethod", "session")`
133
+ *
134
+ * If no session cookie is present (or session is invalid), the request
135
+ * continues without a user — downstream middleware like `scopedBearerAuth`
136
+ * or `requireAuth` will handle enforcement.
137
+ *
138
+ * Uses lazy `getAuth()` to avoid initializing the DB at import time.
139
+ */
140
+ export declare function resolveSessionUser(): (c: Context, next: Next) => Promise<void>;
141
+ /**
142
+ * Middleware that requires either a valid session or a scoped API token.
143
+ *
144
+ * Tries session first, then falls back to scoped bearer auth.
145
+ * Returns 401 if neither is present.
146
+ */
147
+ export declare function requireSessionOrToken(tokenMap: Map<string, TokenScope>, requiredScope: TokenScope): (c: Context, next: Next) => Promise<void | (Response & import("hono").TypedResponse<{
148
+ error: string;
149
+ }, 401, "json">) | (Response & import("hono").TypedResponse<{
150
+ error: string;
151
+ required: TokenScope;
152
+ provided: TokenScope;
153
+ }, 403, "json">)>;
154
+ /**
155
+ * Middleware that enforces tenant ownership on tenant-scoped resources.
156
+ *
157
+ * Must be used after `scopedBearerAuthWithTenant` middleware.
158
+ * Compares the resource's tenantId against the token's tenantId.
159
+ * - If token has no tenantId (legacy/admin tokens), returns 403 Forbidden.
160
+ * - If resource tenantId matches token tenantId, passes through.
161
+ * - Otherwise, returns 403 Forbidden.
162
+ *
163
+ * @param _getResourceTenantId - Function that extracts tenantId from the resource (reserved for future use)
164
+ */
165
+ export declare function requireTenantOwnership<T>(_getResourceTenantId: (resource: T) => string | undefined): (c: Context<AuthEnv>, next: Next) => Promise<void | (Response & import("hono").TypedResponse<{
166
+ error: string;
167
+ }, 403, "json">)>;
168
+ /**
169
+ * Validate that a resource belongs to the authenticated tenant.
170
+ * Returns a response if validation fails (404 for not found or tenant mismatch).
171
+ *
172
+ * @param c - Hono context
173
+ * @param resource - The resource to check (null/undefined = not found)
174
+ * @param resourceTenantId - The resource's tenantId
175
+ * @returns Response if validation fails, undefined if validation passes
176
+ */
177
+ export declare function validateTenantOwnership<T>(c: Context, resource: T | null | undefined, resourceTenantId: string | undefined): Response | undefined;
178
+ /**
179
+ * Validate that a user has access to the requested tenant.
180
+ *
181
+ * - If requestedTenantId is falsy or matches userId, access is allowed (personal tenant).
182
+ * - Otherwise, checks org membership via IOrgMemberRepository.
183
+ *
184
+ * @returns true if the user has access, false otherwise.
185
+ */
186
+ export declare function validateTenantAccess(userId: string, requestedTenantId: string | undefined, orgMemberRepo: IOrgMemberRepository): Promise<boolean>;