@adonis-agora/payments 0.2.0 → 0.4.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 (346) hide show
  1. package/CHANGELOG.md +2375 -0
  2. package/dist/assets/spa/assets/index-B7rU8eIL.css +2 -0
  3. package/dist/assets/spa/assets/index-BcM2VH5k.js +10 -0
  4. package/dist/assets/spa/assets/index-BcM2VH5k.js.map +1 -0
  5. package/dist/assets/spa/index.html +20 -0
  6. package/dist/commands/main.d.ts +4 -3
  7. package/dist/commands/main.d.ts.map +1 -1
  8. package/dist/commands/main.js +9 -2
  9. package/dist/commands/main.js.map +1 -1
  10. package/dist/commands/make_billable.d.ts.map +1 -1
  11. package/dist/commands/make_billable.js +1 -1
  12. package/dist/commands/make_billable.js.map +1 -1
  13. package/dist/commands/make_webhook_handler.d.ts.map +1 -1
  14. package/dist/commands/make_webhook_handler.js +1 -1
  15. package/dist/commands/make_webhook_handler.js.map +1 -1
  16. package/dist/commands/payments_health.d.ts +31 -0
  17. package/dist/commands/payments_health.d.ts.map +1 -0
  18. package/dist/commands/payments_health.js +113 -0
  19. package/dist/commands/payments_health.js.map +1 -0
  20. package/dist/commands/payments_sync.d.ts +18 -4
  21. package/dist/commands/payments_sync.d.ts.map +1 -1
  22. package/dist/commands/payments_sync.js +136 -40
  23. package/dist/commands/payments_sync.js.map +1 -1
  24. package/dist/commands/payments_webhook.d.ts.map +1 -1
  25. package/dist/commands/payments_webhook.js.map +1 -1
  26. package/dist/configure.d.ts +12 -5
  27. package/dist/configure.d.ts.map +1 -1
  28. package/dist/configure.js +18 -5
  29. package/dist/configure.js.map +1 -1
  30. package/dist/providers/dashboard_provider.d.ts +97 -0
  31. package/dist/providers/dashboard_provider.d.ts.map +1 -0
  32. package/dist/providers/dashboard_provider.js +430 -0
  33. package/dist/providers/dashboard_provider.js.map +1 -0
  34. package/dist/providers/payments_client_provider.d.ts +41 -0
  35. package/dist/providers/payments_client_provider.d.ts.map +1 -0
  36. package/dist/providers/payments_client_provider.js +95 -0
  37. package/dist/providers/payments_client_provider.js.map +1 -0
  38. package/dist/providers/payments_provider.d.ts +35 -0
  39. package/dist/providers/payments_provider.d.ts.map +1 -1
  40. package/dist/providers/payments_provider.js +250 -36
  41. package/dist/providers/payments_provider.js.map +1 -1
  42. package/dist/src/billing/billing_health.d.ts +85 -0
  43. package/dist/src/billing/billing_health.d.ts.map +1 -0
  44. package/dist/src/billing/billing_health.js +155 -0
  45. package/dist/src/billing/billing_health.js.map +1 -0
  46. package/dist/src/billing/billing_overview.d.ts +4 -3
  47. package/dist/src/billing/billing_overview.d.ts.map +1 -1
  48. package/dist/src/billing/billing_overview.js +14 -5
  49. package/dist/src/billing/billing_overview.js.map +1 -1
  50. package/dist/src/billing/billing_store.d.ts +634 -5
  51. package/dist/src/billing/billing_store.d.ts.map +1 -1
  52. package/dist/src/billing/billing_store.js +18 -1
  53. package/dist/src/billing/billing_store.js.map +1 -1
  54. package/dist/src/billing/index.d.ts +4 -3
  55. package/dist/src/billing/index.d.ts.map +1 -1
  56. package/dist/src/billing/index.js +2 -1
  57. package/dist/src/billing/index.js.map +1 -1
  58. package/dist/src/billing/list_query.d.ts +16 -0
  59. package/dist/src/billing/list_query.d.ts.map +1 -0
  60. package/dist/src/billing/list_query.js +28 -0
  61. package/dist/src/billing/list_query.js.map +1 -0
  62. package/dist/src/billing/lucid_billing_store.d.ts +122 -4
  63. package/dist/src/billing/lucid_billing_store.d.ts.map +1 -1
  64. package/dist/src/billing/lucid_billing_store.js +811 -13
  65. package/dist/src/billing/lucid_billing_store.js.map +1 -1
  66. package/dist/src/billing/mixins/index.d.ts +5 -2
  67. package/dist/src/billing/mixins/index.d.ts.map +1 -1
  68. package/dist/src/billing/mixins/index.js +5 -2
  69. package/dist/src/billing/mixins/index.js.map +1 -1
  70. package/dist/src/billing/mixins/with_audit_event.d.ts +48 -0
  71. package/dist/src/billing/mixins/with_audit_event.d.ts.map +1 -0
  72. package/dist/src/billing/mixins/with_audit_event.js +77 -0
  73. package/dist/src/billing/mixins/with_audit_event.js.map +1 -0
  74. package/dist/src/billing/mixins/with_billable.d.ts.map +1 -1
  75. package/dist/src/billing/mixins/with_customer.d.ts +39 -0
  76. package/dist/src/billing/mixins/with_customer.d.ts.map +1 -0
  77. package/dist/src/billing/mixins/with_customer.js +68 -0
  78. package/dist/src/billing/mixins/with_customer.js.map +1 -0
  79. package/dist/src/billing/mixins/with_dispute.d.ts +68 -0
  80. package/dist/src/billing/mixins/with_dispute.d.ts.map +1 -0
  81. package/dist/src/billing/mixins/with_dispute.js +83 -0
  82. package/dist/src/billing/mixins/with_dispute.js.map +1 -0
  83. package/dist/src/billing/mixins/with_payment.d.ts +42 -0
  84. package/dist/src/billing/mixins/with_payment.d.ts.map +1 -1
  85. package/dist/src/billing/mixins/with_payment.js +29 -3
  86. package/dist/src/billing/mixins/with_payment.js.map +1 -1
  87. package/dist/src/billing/mixins/with_subscription.d.ts +7 -0
  88. package/dist/src/billing/mixins/with_subscription.d.ts.map +1 -1
  89. package/dist/src/billing/mixins/with_subscription.js +15 -1
  90. package/dist/src/billing/mixins/with_subscription.js.map +1 -1
  91. package/dist/src/billing/mixins/with_usage_event.d.ts +7 -0
  92. package/dist/src/billing/mixins/with_usage_event.d.ts.map +1 -1
  93. package/dist/src/billing/mixins/with_usage_event.js +15 -1
  94. package/dist/src/billing/mixins/with_usage_event.js.map +1 -1
  95. package/dist/src/billing/mixins/with_webhook_event.d.ts +18 -0
  96. package/dist/src/billing/mixins/with_webhook_event.d.ts.map +1 -1
  97. package/dist/src/billing/mixins/with_webhook_event.js +18 -1
  98. package/dist/src/billing/mixins/with_webhook_event.js.map +1 -1
  99. package/dist/src/billing/resolve_dispatch.d.ts +22 -0
  100. package/dist/src/billing/resolve_dispatch.d.ts.map +1 -0
  101. package/dist/src/billing/resolve_dispatch.js +44 -0
  102. package/dist/src/billing/resolve_dispatch.js.map +1 -0
  103. package/dist/src/billing/resolve_store.d.ts +18 -0
  104. package/dist/src/billing/resolve_store.d.ts.map +1 -0
  105. package/dist/src/billing/resolve_store.js +35 -0
  106. package/dist/src/billing/resolve_store.js.map +1 -0
  107. package/dist/src/billing/schema.d.ts +108 -0
  108. package/dist/src/billing/schema.d.ts.map +1 -0
  109. package/dist/src/billing/schema.js +350 -0
  110. package/dist/src/billing/schema.js.map +1 -0
  111. package/dist/src/billing/webhook_dispatcher.d.ts +95 -16
  112. package/dist/src/billing/webhook_dispatcher.d.ts.map +1 -1
  113. package/dist/src/billing/webhook_dispatcher.js +186 -33
  114. package/dist/src/billing/webhook_dispatcher.js.map +1 -1
  115. package/dist/src/billing/webhook_events.d.ts +67 -1
  116. package/dist/src/billing/webhook_events.d.ts.map +1 -1
  117. package/dist/src/billing/webhook_events.js +15 -0
  118. package/dist/src/billing/webhook_events.js.map +1 -1
  119. package/dist/src/billing/webhook_processor.d.ts.map +1 -1
  120. package/dist/src/billing/webhook_processor.js +325 -5
  121. package/dist/src/billing/webhook_processor.js.map +1 -1
  122. package/dist/src/client/define_config.d.ts +150 -0
  123. package/dist/src/client/define_config.d.ts.map +1 -0
  124. package/dist/src/client/define_config.js +98 -0
  125. package/dist/src/client/define_config.js.map +1 -0
  126. package/dist/src/client/handlers.d.ts +71 -0
  127. package/dist/src/client/handlers.d.ts.map +1 -0
  128. package/dist/src/client/handlers.js +119 -0
  129. package/dist/src/client/handlers.js.map +1 -0
  130. package/dist/src/client/index.d.ts +15 -0
  131. package/dist/src/client/index.d.ts.map +1 -0
  132. package/dist/src/client/index.js +12 -0
  133. package/dist/src/client/index.js.map +1 -0
  134. package/dist/src/client/statuses.d.ts +38 -0
  135. package/dist/src/client/statuses.d.ts.map +1 -0
  136. package/dist/src/client/statuses.js +42 -0
  137. package/dist/src/client/statuses.js.map +1 -0
  138. package/dist/src/dashboard/actions.d.ts +143 -0
  139. package/dist/src/dashboard/actions.d.ts.map +1 -0
  140. package/dist/src/dashboard/actions.js +112 -0
  141. package/dist/src/dashboard/actions.js.map +1 -0
  142. package/dist/src/dashboard/auth.d.ts +136 -0
  143. package/dist/src/dashboard/auth.d.ts.map +1 -0
  144. package/dist/src/dashboard/auth.js +152 -0
  145. package/dist/src/dashboard/auth.js.map +1 -0
  146. package/dist/src/dashboard/define_config.d.ts +80 -0
  147. package/dist/src/dashboard/define_config.d.ts.map +1 -0
  148. package/dist/src/dashboard/define_config.js +83 -0
  149. package/dist/src/dashboard/define_config.js.map +1 -0
  150. package/dist/src/dashboard/handlers.d.ts +281 -0
  151. package/dist/src/dashboard/handlers.d.ts.map +1 -0
  152. package/dist/src/dashboard/handlers.js +960 -0
  153. package/dist/src/dashboard/handlers.js.map +1 -0
  154. package/dist/src/dashboard/index.d.ts +17 -0
  155. package/dist/src/dashboard/index.d.ts.map +1 -0
  156. package/dist/src/dashboard/index.js +13 -0
  157. package/dist/src/dashboard/index.js.map +1 -0
  158. package/dist/src/dashboard/login_page.d.ts +23 -0
  159. package/dist/src/dashboard/login_page.d.ts.map +1 -0
  160. package/dist/src/dashboard/login_page.js +170 -0
  161. package/dist/src/dashboard/login_page.js.map +1 -0
  162. package/dist/src/dashboard/period.d.ts +31 -0
  163. package/dist/src/dashboard/period.d.ts.map +1 -0
  164. package/dist/src/dashboard/period.js +44 -0
  165. package/dist/src/dashboard/period.js.map +1 -0
  166. package/dist/src/dashboard/session_cookie.d.ts +42 -0
  167. package/dist/src/dashboard/session_cookie.d.ts.map +1 -0
  168. package/dist/src/dashboard/session_cookie.js +97 -0
  169. package/dist/src/dashboard/session_cookie.js.map +1 -0
  170. package/dist/src/dashboard/spa.d.ts +24 -0
  171. package/dist/src/dashboard/spa.d.ts.map +1 -0
  172. package/dist/src/dashboard/spa.js +52 -0
  173. package/dist/src/dashboard/spa.js.map +1 -0
  174. package/dist/src/define_config.d.ts +245 -10
  175. package/dist/src/define_config.d.ts.map +1 -1
  176. package/dist/src/define_config.js +97 -1
  177. package/dist/src/define_config.js.map +1 -1
  178. package/dist/src/diagnostics.d.ts +287 -7
  179. package/dist/src/diagnostics.d.ts.map +1 -1
  180. package/dist/src/diagnostics.js +317 -1
  181. package/dist/src/diagnostics.js.map +1 -1
  182. package/dist/src/driver.d.ts +139 -5
  183. package/dist/src/driver.d.ts.map +1 -1
  184. package/dist/src/drivers/abacate.d.ts +13 -3
  185. package/dist/src/drivers/abacate.d.ts.map +1 -1
  186. package/dist/src/drivers/abacate.js +112 -19
  187. package/dist/src/drivers/abacate.js.map +1 -1
  188. package/dist/src/drivers/adyen.d.ts +164 -0
  189. package/dist/src/drivers/adyen.d.ts.map +1 -0
  190. package/dist/src/drivers/adyen.js +678 -0
  191. package/dist/src/drivers/adyen.js.map +1 -0
  192. package/dist/src/drivers/asaas.d.ts +53 -3
  193. package/dist/src/drivers/asaas.d.ts.map +1 -1
  194. package/dist/src/drivers/asaas.js +364 -29
  195. package/dist/src/drivers/asaas.js.map +1 -1
  196. package/dist/src/drivers/dodo.d.ts +135 -0
  197. package/dist/src/drivers/dodo.d.ts.map +1 -0
  198. package/dist/src/drivers/dodo.js +864 -0
  199. package/dist/src/drivers/dodo.js.map +1 -0
  200. package/dist/src/drivers/efi.d.ts +98 -0
  201. package/dist/src/drivers/efi.d.ts.map +1 -0
  202. package/dist/src/drivers/efi.js +628 -0
  203. package/dist/src/drivers/efi.js.map +1 -0
  204. package/dist/src/drivers/infinitepay.d.ts +156 -0
  205. package/dist/src/drivers/infinitepay.d.ts.map +1 -0
  206. package/dist/src/drivers/infinitepay.js +321 -0
  207. package/dist/src/drivers/infinitepay.js.map +1 -0
  208. package/dist/src/drivers/lemonsqueezy.d.ts +125 -0
  209. package/dist/src/drivers/lemonsqueezy.d.ts.map +1 -0
  210. package/dist/src/drivers/lemonsqueezy.js +632 -0
  211. package/dist/src/drivers/lemonsqueezy.js.map +1 -0
  212. package/dist/src/drivers/mercadopago.d.ts +97 -0
  213. package/dist/src/drivers/mercadopago.d.ts.map +1 -0
  214. package/dist/src/drivers/mercadopago.js +844 -0
  215. package/dist/src/drivers/mercadopago.js.map +1 -0
  216. package/dist/src/drivers/mollie.d.ts +125 -0
  217. package/dist/src/drivers/mollie.d.ts.map +1 -0
  218. package/dist/src/drivers/mollie.js +812 -0
  219. package/dist/src/drivers/mollie.js.map +1 -0
  220. package/dist/src/drivers/paddle.d.ts +148 -0
  221. package/dist/src/drivers/paddle.d.ts.map +1 -0
  222. package/dist/src/drivers/paddle.js +738 -0
  223. package/dist/src/drivers/paddle.js.map +1 -0
  224. package/dist/src/drivers/pagarme.d.ts +97 -0
  225. package/dist/src/drivers/pagarme.d.ts.map +1 -0
  226. package/dist/src/drivers/pagarme.js +829 -0
  227. package/dist/src/drivers/pagarme.js.map +1 -0
  228. package/dist/src/drivers/pagbank.d.ts +57 -0
  229. package/dist/src/drivers/pagbank.d.ts.map +1 -0
  230. package/dist/src/drivers/pagbank.js +499 -0
  231. package/dist/src/drivers/pagbank.js.map +1 -0
  232. package/dist/src/drivers/paypal.d.ts +120 -0
  233. package/dist/src/drivers/paypal.d.ts.map +1 -0
  234. package/dist/src/drivers/paypal.js +891 -0
  235. package/dist/src/drivers/paypal.js.map +1 -0
  236. package/dist/src/drivers/polar.d.ts +118 -0
  237. package/dist/src/drivers/polar.d.ts.map +1 -0
  238. package/dist/src/drivers/polar.js +604 -0
  239. package/dist/src/drivers/polar.js.map +1 -0
  240. package/dist/src/drivers/razorpay.d.ts +103 -0
  241. package/dist/src/drivers/razorpay.d.ts.map +1 -0
  242. package/dist/src/drivers/razorpay.js +867 -0
  243. package/dist/src/drivers/razorpay.js.map +1 -0
  244. package/dist/src/drivers/shared.d.ts +33 -0
  245. package/dist/src/drivers/shared.d.ts.map +1 -0
  246. package/dist/src/drivers/shared.js +37 -0
  247. package/dist/src/drivers/shared.js.map +1 -0
  248. package/dist/src/drivers/square.d.ts +133 -0
  249. package/dist/src/drivers/square.d.ts.map +1 -0
  250. package/dist/src/drivers/square.js +905 -0
  251. package/dist/src/drivers/square.js.map +1 -0
  252. package/dist/src/drivers/stripe.d.ts +41 -4
  253. package/dist/src/drivers/stripe.d.ts.map +1 -1
  254. package/dist/src/drivers/stripe.js +823 -26
  255. package/dist/src/drivers/stripe.js.map +1 -1
  256. package/dist/src/drivers/woovi.d.ts +11 -4
  257. package/dist/src/drivers/woovi.d.ts.map +1 -1
  258. package/dist/src/drivers/woovi.js +162 -29
  259. package/dist/src/drivers/woovi.js.map +1 -1
  260. package/dist/src/ensure_customer.d.ts +34 -1
  261. package/dist/src/ensure_customer.d.ts.map +1 -1
  262. package/dist/src/ensure_customer.js +29 -4
  263. package/dist/src/ensure_customer.js.map +1 -1
  264. package/dist/src/hooks/webhook_handlers.d.ts.map +1 -1
  265. package/dist/src/hooks/webhook_handlers.js.map +1 -1
  266. package/dist/src/http.d.ts +37 -3
  267. package/dist/src/http.d.ts.map +1 -1
  268. package/dist/src/http.js +69 -5
  269. package/dist/src/http.js.map +1 -1
  270. package/dist/src/index.d.ts +54 -26
  271. package/dist/src/index.d.ts.map +1 -1
  272. package/dist/src/index.js +29 -12
  273. package/dist/src/index.js.map +1 -1
  274. package/dist/src/invoice/drivers/asaas.d.ts.map +1 -1
  275. package/dist/src/invoice/drivers/asaas.js.map +1 -1
  276. package/dist/src/invoice/drivers/enotas.d.ts.map +1 -1
  277. package/dist/src/invoice/drivers/enotas.js.map +1 -1
  278. package/dist/src/invoice/drivers/focus.d.ts.map +1 -1
  279. package/dist/src/invoice/drivers/focus.js.map +1 -1
  280. package/dist/src/invoice/drivers/plugnotas.d.ts.map +1 -1
  281. package/dist/src/invoice/drivers/plugnotas.js.map +1 -1
  282. package/dist/src/invoice/drivers/tecnospeed.d.ts.map +1 -1
  283. package/dist/src/invoice/drivers/tecnospeed.js.map +1 -1
  284. package/dist/src/invoice/emit_invoice.d.ts.map +1 -1
  285. package/dist/src/invoice/emit_invoice.js +31 -11
  286. package/dist/src/invoice/emit_invoice.js.map +1 -1
  287. package/dist/src/invoice/invoice_manager.d.ts.map +1 -1
  288. package/dist/src/money.d.ts +23 -5
  289. package/dist/src/money.d.ts.map +1 -1
  290. package/dist/src/money.js +72 -7
  291. package/dist/src/money.js.map +1 -1
  292. package/dist/src/payments_manager.d.ts +8 -1
  293. package/dist/src/payments_manager.d.ts.map +1 -1
  294. package/dist/src/payments_manager.js +168 -6
  295. package/dist/src/payments_manager.js.map +1 -1
  296. package/dist/src/services/main.d.ts +38 -0
  297. package/dist/src/services/main.d.ts.map +1 -1
  298. package/dist/src/services/main.js +130 -0
  299. package/dist/src/services/main.js.map +1 -1
  300. package/dist/src/telescope/index.d.ts +2 -0
  301. package/dist/src/telescope/index.d.ts.map +1 -1
  302. package/dist/src/telescope/index.js +1 -0
  303. package/dist/src/telescope/index.js.map +1 -1
  304. package/dist/src/telescope/payments_watcher.d.ts +10 -4
  305. package/dist/src/telescope/payments_watcher.d.ts.map +1 -1
  306. package/dist/src/telescope/payments_watcher.js +66 -14
  307. package/dist/src/telescope/payments_watcher.js.map +1 -1
  308. package/dist/src/telescope/register.d.ts +62 -0
  309. package/dist/src/telescope/register.d.ts.map +1 -0
  310. package/dist/src/telescope/register.js +48 -0
  311. package/dist/src/telescope/register.js.map +1 -0
  312. package/dist/src/testing/fake_payments.d.ts +62 -0
  313. package/dist/src/testing/fake_payments.d.ts.map +1 -0
  314. package/dist/src/testing/fake_payments.js +82 -0
  315. package/dist/src/testing/fake_payments.js.map +1 -0
  316. package/dist/src/testing/fake_payments_driver.d.ts +1 -1
  317. package/dist/src/testing/fake_payments_driver.d.ts.map +1 -1
  318. package/dist/src/testing/fake_payments_driver.js.map +1 -1
  319. package/dist/src/testing/in_memory_billing_store.d.ts +151 -2
  320. package/dist/src/testing/in_memory_billing_store.d.ts.map +1 -1
  321. package/dist/src/testing/in_memory_billing_store.js +517 -4
  322. package/dist/src/testing/in_memory_billing_store.js.map +1 -1
  323. package/dist/src/testing/index.d.ts +3 -2
  324. package/dist/src/testing/index.d.ts.map +1 -1
  325. package/dist/src/testing/index.js +1 -0
  326. package/dist/src/testing/index.js.map +1 -1
  327. package/dist/src/testing/mutable_clock.d.ts.map +1 -1
  328. package/dist/src/types.d.ts +161 -5
  329. package/dist/src/types.d.ts.map +1 -1
  330. package/dist/src/types.js +30 -1
  331. package/dist/src/types.js.map +1 -1
  332. package/dist/src/webhook_handlers.d.ts +96 -2
  333. package/dist/src/webhook_handlers.d.ts.map +1 -1
  334. package/dist/src/webhook_handlers.js +91 -10
  335. package/dist/src/webhook_handlers.js.map +1 -1
  336. package/dist/src/webhook_security.d.ts +94 -3
  337. package/dist/src/webhook_security.d.ts.map +1 -1
  338. package/dist/src/webhook_security.js +173 -9
  339. package/dist/src/webhook_security.js.map +1 -1
  340. package/dist/stubs/config/payments.stub +13 -0
  341. package/dist/stubs/config/payments_client.stub +42 -0
  342. package/dist/stubs/config/payments_dashboard.stub +38 -0
  343. package/dist/stubs/database/migrations/create_billing_tables.stub +35 -77
  344. package/dist/stubs/main.js.map +1 -1
  345. package/dist/stubs/make/webhook_handler/main.stub +29 -11
  346. package/package.json +67 -32
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Shared webhook-auth primitives for the drivers. Every gateway signs webhooks
3
3
  * differently (Stripe: SDK HMAC; AbacatePay: HMAC-SHA256; Woovi: HMAC-SHA1 or
4
- * RSA-SHA256; Asaas: shared token), but the comparison and digest mechanics are the
5
- * same — they live here so every driver verifies with the same, timing-safe code.
4
+ * RSA-SHA256; Asaas: shared token; PagBank: a bare SHA-256 over token+body), but the
5
+ * comparison and digest mechanics are the same — they live here so every driver verifies with the same, timing-safe code.
6
6
  */
7
7
  /** Length-independent, timing-safe string comparison. */
8
8
  export declare function safeCompare(received: string, expected: string): boolean;
@@ -11,7 +11,24 @@ export declare function safeCompare(received: string, expected: string): boolean
11
11
  * timing-safe. `digest` matches the gateway's encoding (`base64` for AbacatePay and
12
12
  * Woovi's HMAC mode).
13
13
  */
14
- export declare function verifyHmacSignature(rawBody: string, signature: string | undefined, secret: string, algorithm: 'sha256' | 'sha1'): boolean;
14
+ export declare function verifyHmacSignature(rawBody: string, signature: string | undefined, secret: string, algorithm: 'sha256' | 'sha1',
15
+ /**
16
+ * How the gateway encodes the digest. Base64 is the default because the first gateways
17
+ * here used it; hex is at least as common (Paddle, Lemon Squeezy, Razorpay, Mercado Pago,
18
+ * Mollie all send hex), and getting it wrong fails CLOSED — every signature mismatches —
19
+ * so it is safe to leave to the caller.
20
+ */
21
+ encoding?: 'base64' | 'hex'): boolean;
22
+ /**
23
+ * The same check over a payload the gateway builds rather than the raw body.
24
+ *
25
+ * Several schemes sign a CONSTRUCTED string — Paddle's `ts:body`, Standard Webhooks'
26
+ * `id.timestamp.body`, Square's `notificationUrl + body`, Mercado Pago's id/request/ts
27
+ * manifest. The signed bytes are the whole security property, so building them is the one
28
+ * step a driver must own; this only removes the reason to hand-roll the comparison, which
29
+ * is where a `===` creeps back in and reintroduces a timing side channel.
30
+ */
31
+ export declare function verifyHmacOverPayload(payload: string, signature: string | undefined, secret: string, algorithm: 'sha256' | 'sha1', encoding?: 'base64' | 'hex'): boolean;
15
32
  /**
16
33
  * Verify Woovi's recommended `x-webhook-signature`: an RSA-SHA256 signature made with
17
34
  * Woovi's private key, verified here against the public key published at
@@ -26,4 +43,78 @@ export declare function verifyRsaSha256Signature(rawBody: string, signature: str
26
43
  * set. Drivers only reach this when their credential is configured.
27
44
  */
28
45
  export declare function requireMatchingCredential(received: string | undefined, expected: string, provider: string, what: string): void;
46
+ /**
47
+ * Verify PagBank's `x-authenticity-token`: the hex SHA-256 of `<token>-<rawBody>`, where
48
+ * `<token>` is the very same Bearer token that authenticates API calls.
49
+ *
50
+ * Read that construction again, because it is not an HMAC. It is a secret **prefix**
51
+ * hashed with a Merkle–Damgård function, which is the textbook setup for a
52
+ * length-extension forgery: anyone who has seen one valid (body, token) pair can compute
53
+ * a valid token for that body plus a suffix, without ever learning the secret. What saves
54
+ * it in practice is that the forged body is the original body followed by binary padding,
55
+ * and `JSON.parse` rejects that — so a forgery has to survive the parser, not just the
56
+ * hash. It is still weaker than the HMAC every other gateway here uses, and the secret is
57
+ * shared with the API credential, so rotating one rotates the other.
58
+ *
59
+ * The comparison is timing-safe and case-insensitive (PagBank sends lowercase hex).
60
+ */
61
+ export declare function verifyPagBankAuthenticityToken(rawBody: string, received: string | undefined, token: string): boolean;
62
+ /**
63
+ * Verify a [Standard Webhooks](https://www.standardwebhooks.com/) signature.
64
+ *
65
+ * The scheme: sign `` `${webhook-id}.${webhook-timestamp}.${rawBody}` `` with HMAC-SHA256,
66
+ * base64. The `webhook-signature` header carries a SPACE-SEPARATED list of `v1,<sig>` — a
67
+ * list, because a secret being rotated is signed with both keys at once, so checking only
68
+ * the first entry breaks every rotation.
69
+ *
70
+ * `keyEncoding` is the part that bites, and neither vendor documents it — both derivations
71
+ * below were read out of their own SDK source:
72
+ *
73
+ * - `'base64'` (the spec default) — strip the `whsec_` prefix and base64-DECODE the rest.
74
+ * Dodo Payments does this.
75
+ * - `'raw'` — use the secret's UTF-8 bytes as-is, `whsec_` prefix included. Polar does this
76
+ * (its SDK base64-encodes the secret before handing it to the reference library, which
77
+ * decodes it straight back).
78
+ *
79
+ * Getting it wrong fails closed — every signature mismatches — so the cost is a rejected
80
+ * webhook, not an accepted forgery. Which is why each driver pins its own derivation with a
81
+ * test that signs using the OTHER one and asserts rejection.
82
+ *
83
+ * `toleranceSeconds` bounds replay. It defaults to 5 minutes, the spec's own recommendation;
84
+ * pass `0` to skip the check. Note the idempotency ledger already makes a replayed event a
85
+ * no-op — this is the outer guard, not the only one.
86
+ */
87
+ export declare function verifyStandardWebhookSignature(options: {
88
+ rawBody: string;
89
+ headers: Record<string, string | string[] | undefined>;
90
+ secret: string;
91
+ keyEncoding: 'base64' | 'raw';
92
+ toleranceSeconds?: number;
93
+ /** Overridable clock, so the tolerance is testable. */
94
+ now?: Date;
95
+ }): boolean;
96
+ /**
97
+ * Refuse to boot when a configured driver CAN authenticate webhook deliveries but was given
98
+ * nothing to authenticate them with.
99
+ *
100
+ * The hole: the library mounts `POST /payments/webhook/:provider` for every configured
101
+ * provider, and a driver whose credential slot is empty verifies nothing — so anyone who
102
+ * knows the URL can post `{"event":"PAYMENT_RECEIVED", ...}` and the built-in sync marks a
103
+ * payment paid. Nothing logged it, nothing warned, and the app's own webhook-security tests
104
+ * passed *because* they only asserted that a good signature is accepted.
105
+ *
106
+ * This package already fails closed in the two comparable places — the dashboard throws at
107
+ * boot on a missing session secret, the dispatcher throws on a mode it cannot serve — and
108
+ * this is the same decision for the one endpoint the public internet can reach.
109
+ *
110
+ * The opt-out is explicit and per-provider, because terminating verification upstream is a
111
+ * real deployment (mutual TLS at the edge, an API gateway that checks the signature) and it
112
+ * is exactly what Efí's driver does by design. What it must not be is the default.
113
+ */
114
+ export declare function assertWebhookVerification(drivers: Iterable<[string, {
115
+ provider?: string;
116
+ webhookVerification?: string;
117
+ }]>, options?: {
118
+ allowUnverifiedWebhooks?: boolean | readonly string[];
119
+ }): void;
29
120
  //# sourceMappingURL=webhook_security.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhook_security.d.ts","sourceRoot":"","sources":["../../src/webhook_security.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIvE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,GAAG,MAAM,GAC3B,OAAO,CAIT;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,SAAS,EAAE,MAAM,GAChB,OAAO,CAWT;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,IAAI,CAON"}
1
+ {"version":3,"file":"webhook_security.d.ts","sourceRoot":"","sources":["../../src/webhook_security.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIvE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,GAAG,MAAM;AAC5B;;;;;GAKG;AACH,QAAQ,GAAE,QAAQ,GAAG,KAAgB,GACpC,OAAO,CAST;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,GAAG,MAAM,EAC5B,QAAQ,GAAE,QAAQ,GAAG,KAAgB,GACpC,OAAO,CAST;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,SAAS,EAAE,MAAM,GAChB,OAAO,CAgBT;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,IAAI,CAUN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,KAAK,EAAE,MAAM,GACZ,OAAO,CAST;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,QAAQ,GAAG,KAAK,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAuCV;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,EAChF,OAAO,GAAE;IAAE,uBAAuB,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAA;CAAO,GACtE,IAAI,CAoBN"}
@@ -1,9 +1,11 @@
1
- import { createHmac, verify as cryptoVerify, timingSafeEqual } from 'node:crypto';
1
+ import { createHash, createHmac, verify as cryptoVerify, timingSafeEqual } from 'node:crypto';
2
+ import { reportWebhookVerification } from './diagnostics.js';
3
+ import { headerValue } from './http.js';
2
4
  /**
3
5
  * Shared webhook-auth primitives for the drivers. Every gateway signs webhooks
4
6
  * differently (Stripe: SDK HMAC; AbacatePay: HMAC-SHA256; Woovi: HMAC-SHA1 or
5
- * RSA-SHA256; Asaas: shared token), but the comparison and digest mechanics are the
6
- * same — they live here so every driver verifies with the same, timing-safe code.
7
+ * RSA-SHA256; Asaas: shared token; PagBank: a bare SHA-256 over token+body), but the
8
+ * comparison and digest mechanics are the same — they live here so every driver verifies with the same, timing-safe code.
7
9
  */
8
10
  /** Length-independent, timing-safe string comparison. */
9
11
  export function safeCompare(received, expected) {
@@ -16,11 +18,41 @@ export function safeCompare(received, expected) {
16
18
  * timing-safe. `digest` matches the gateway's encoding (`base64` for AbacatePay and
17
19
  * Woovi's HMAC mode).
18
20
  */
19
- export function verifyHmacSignature(rawBody, signature, secret, algorithm) {
20
- if (signature === undefined || signature === '')
21
+ export function verifyHmacSignature(rawBody, signature, secret, algorithm,
22
+ /**
23
+ * How the gateway encodes the digest. Base64 is the default because the first gateways
24
+ * here used it; hex is at least as common (Paddle, Lemon Squeezy, Razorpay, Mercado Pago,
25
+ * Mollie all send hex), and getting it wrong fails CLOSED — every signature mismatches —
26
+ * so it is safe to leave to the caller.
27
+ */
28
+ encoding = 'base64') {
29
+ if (signature === undefined || signature === '') {
30
+ reportWebhookVerification(`hmac-${algorithm}`, false);
21
31
  return false;
22
- const expected = createHmac(algorithm, secret).update(rawBody, 'utf8').digest('base64');
23
- return safeCompare(signature, expected);
32
+ }
33
+ const expected = createHmac(algorithm, secret).update(rawBody, 'utf8').digest(encoding);
34
+ const ok = safeCompare(signature, expected);
35
+ reportWebhookVerification(`hmac-${algorithm}`, ok);
36
+ return ok;
37
+ }
38
+ /**
39
+ * The same check over a payload the gateway builds rather than the raw body.
40
+ *
41
+ * Several schemes sign a CONSTRUCTED string — Paddle's `ts:body`, Standard Webhooks'
42
+ * `id.timestamp.body`, Square's `notificationUrl + body`, Mercado Pago's id/request/ts
43
+ * manifest. The signed bytes are the whole security property, so building them is the one
44
+ * step a driver must own; this only removes the reason to hand-roll the comparison, which
45
+ * is where a `===` creeps back in and reintroduces a timing side channel.
46
+ */
47
+ export function verifyHmacOverPayload(payload, signature, secret, algorithm, encoding = 'base64') {
48
+ if (signature === undefined || signature === '') {
49
+ reportWebhookVerification(`hmac-${algorithm}-over-payload`, false);
50
+ return false;
51
+ }
52
+ const expected = createHmac(algorithm, secret).update(payload, 'utf8').digest(encoding);
53
+ const ok = safeCompare(signature, expected);
54
+ reportWebhookVerification(`hmac-${algorithm}-over-payload`, ok);
55
+ return ok;
24
56
  }
25
57
  /**
26
58
  * Verify Woovi's recommended `x-webhook-signature`: an RSA-SHA256 signature made with
@@ -29,12 +61,16 @@ export function verifyHmacSignature(rawBody, signature, secret, algorithm) {
29
61
  * PEM document (the dashboard shows it base64-encoded).
30
62
  */
31
63
  export function verifyRsaSha256Signature(rawBody, signature, publicKey) {
32
- if (signature === undefined || signature === '')
64
+ if (signature === undefined || signature === '') {
65
+ reportWebhookVerification('rsa-sha256', false);
33
66
  return false;
67
+ }
34
68
  const pem = publicKey.includes('-----BEGIN')
35
69
  ? publicKey
36
70
  : Buffer.from(publicKey, 'base64').toString('utf8');
37
- return cryptoVerify('RSA-SHA256', Buffer.from(rawBody, 'utf8'), pem, Buffer.from(signature, 'base64'));
71
+ const ok = cryptoVerify('RSA-SHA256', Buffer.from(rawBody, 'utf8'), pem, Buffer.from(signature, 'base64'));
72
+ reportWebhookVerification('rsa-sha256', ok);
73
+ return ok;
38
74
  }
39
75
  /**
40
76
  * Enforce a configured webhook credential against the request headers. Returns the
@@ -44,10 +80,138 @@ export function verifyRsaSha256Signature(rawBody, signature, publicKey) {
44
80
  */
45
81
  export function requireMatchingCredential(received, expected, provider, what) {
46
82
  if (received === undefined || received === '') {
83
+ reportWebhookVerification('shared-token', false);
47
84
  throw new Error(`[payments] Missing webhook ${what} on ${provider} request.`);
48
85
  }
49
86
  if (!safeCompare(received, expected)) {
87
+ reportWebhookVerification('shared-token', false);
50
88
  throw new Error(`[payments] Invalid ${provider} webhook ${what}.`);
51
89
  }
90
+ reportWebhookVerification('shared-token', true);
91
+ }
92
+ /**
93
+ * Verify PagBank's `x-authenticity-token`: the hex SHA-256 of `<token>-<rawBody>`, where
94
+ * `<token>` is the very same Bearer token that authenticates API calls.
95
+ *
96
+ * Read that construction again, because it is not an HMAC. It is a secret **prefix**
97
+ * hashed with a Merkle–Damgård function, which is the textbook setup for a
98
+ * length-extension forgery: anyone who has seen one valid (body, token) pair can compute
99
+ * a valid token for that body plus a suffix, without ever learning the secret. What saves
100
+ * it in practice is that the forged body is the original body followed by binary padding,
101
+ * and `JSON.parse` rejects that — so a forgery has to survive the parser, not just the
102
+ * hash. It is still weaker than the HMAC every other gateway here uses, and the secret is
103
+ * shared with the API credential, so rotating one rotates the other.
104
+ *
105
+ * The comparison is timing-safe and case-insensitive (PagBank sends lowercase hex).
106
+ */
107
+ export function verifyPagBankAuthenticityToken(rawBody, received, token) {
108
+ if (received === undefined || received === '') {
109
+ reportWebhookVerification('sha256-token-prefix', false);
110
+ return false;
111
+ }
112
+ const expected = createHash('sha256').update(`${token}-${rawBody}`, 'utf8').digest('hex');
113
+ const ok = safeCompare(received.toLowerCase(), expected);
114
+ reportWebhookVerification('sha256-token-prefix', ok);
115
+ return ok;
116
+ }
117
+ /**
118
+ * Verify a [Standard Webhooks](https://www.standardwebhooks.com/) signature.
119
+ *
120
+ * The scheme: sign `` `${webhook-id}.${webhook-timestamp}.${rawBody}` `` with HMAC-SHA256,
121
+ * base64. The `webhook-signature` header carries a SPACE-SEPARATED list of `v1,<sig>` — a
122
+ * list, because a secret being rotated is signed with both keys at once, so checking only
123
+ * the first entry breaks every rotation.
124
+ *
125
+ * `keyEncoding` is the part that bites, and neither vendor documents it — both derivations
126
+ * below were read out of their own SDK source:
127
+ *
128
+ * - `'base64'` (the spec default) — strip the `whsec_` prefix and base64-DECODE the rest.
129
+ * Dodo Payments does this.
130
+ * - `'raw'` — use the secret's UTF-8 bytes as-is, `whsec_` prefix included. Polar does this
131
+ * (its SDK base64-encodes the secret before handing it to the reference library, which
132
+ * decodes it straight back).
133
+ *
134
+ * Getting it wrong fails closed — every signature mismatches — so the cost is a rejected
135
+ * webhook, not an accepted forgery. Which is why each driver pins its own derivation with a
136
+ * test that signs using the OTHER one and asserts rejection.
137
+ *
138
+ * `toleranceSeconds` bounds replay. It defaults to 5 minutes, the spec's own recommendation;
139
+ * pass `0` to skip the check. Note the idempotency ledger already makes a replayed event a
140
+ * no-op — this is the outer guard, not the only one.
141
+ */
142
+ export function verifyStandardWebhookSignature(options) {
143
+ const id = headerValue(options.headers, 'webhook-id');
144
+ const timestamp = headerValue(options.headers, 'webhook-timestamp');
145
+ const signature = headerValue(options.headers, 'webhook-signature');
146
+ if (!id || !timestamp || !signature) {
147
+ reportWebhookVerification('standard-webhooks', false);
148
+ return false;
149
+ }
150
+ const tolerance = options.toleranceSeconds ?? 300;
151
+ if (tolerance > 0) {
152
+ const sent = Number(timestamp);
153
+ if (!Number.isFinite(sent)) {
154
+ reportWebhookVerification('standard-webhooks', false);
155
+ return false;
156
+ }
157
+ const nowSeconds = Math.floor((options.now ?? new Date()).getTime() / 1000);
158
+ if (Math.abs(nowSeconds - sent) > tolerance) {
159
+ reportWebhookVerification('standard-webhooks', false);
160
+ return false;
161
+ }
162
+ }
163
+ const key = options.keyEncoding === 'raw'
164
+ ? Buffer.from(options.secret, 'utf8')
165
+ : Buffer.from(options.secret.replace(/^whsec_/, ''), 'base64');
166
+ const expected = createHmac('sha256', key)
167
+ .update(`${id}.${timestamp}.${options.rawBody}`, 'utf8')
168
+ .digest('base64');
169
+ // Every `v1,<sig>` entry is checked: during a secret rotation the gateway signs with both
170
+ // the old and the new key, and only one of them can match.
171
+ const ok = signature
172
+ .split(' ')
173
+ .filter((part) => part.startsWith('v1,'))
174
+ .some((part) => safeCompare(part.slice(3), expected));
175
+ reportWebhookVerification('standard-webhooks', ok);
176
+ return ok;
177
+ }
178
+ /**
179
+ * Refuse to boot when a configured driver CAN authenticate webhook deliveries but was given
180
+ * nothing to authenticate them with.
181
+ *
182
+ * The hole: the library mounts `POST /payments/webhook/:provider` for every configured
183
+ * provider, and a driver whose credential slot is empty verifies nothing — so anyone who
184
+ * knows the URL can post `{"event":"PAYMENT_RECEIVED", ...}` and the built-in sync marks a
185
+ * payment paid. Nothing logged it, nothing warned, and the app's own webhook-security tests
186
+ * passed *because* they only asserted that a good signature is accepted.
187
+ *
188
+ * This package already fails closed in the two comparable places — the dashboard throws at
189
+ * boot on a missing session secret, the dispatcher throws on a mode it cannot serve — and
190
+ * this is the same decision for the one endpoint the public internet can reach.
191
+ *
192
+ * The opt-out is explicit and per-provider, because terminating verification upstream is a
193
+ * real deployment (mutual TLS at the edge, an API gateway that checks the signature) and it
194
+ * is exactly what Efí's driver does by design. What it must not be is the default.
195
+ */
196
+ export function assertWebhookVerification(drivers, options = {}) {
197
+ const allow = options.allowUnverifiedWebhooks;
198
+ if (allow === true)
199
+ return;
200
+ const allowed = new Set(Array.isArray(allow) ? allow : []);
201
+ for (const [name, driver] of drivers) {
202
+ if (driver.webhookVerification !== 'unconfigured')
203
+ continue;
204
+ if (allowed.has(name) || (driver.provider !== undefined && allowed.has(driver.provider))) {
205
+ continue;
206
+ }
207
+ throw new Error([
208
+ `[payments] The "${name}" driver can verify webhook deliveries but has no credential`,
209
+ `configured, so \`POST /payments/webhook/${driver.provider ?? name}\` would accept any`,
210
+ 'request that reaches it — including one that marks a payment paid.',
211
+ "Set the gateway's webhook secret/token (see the provider docs page for the env var),",
212
+ 'or, if verification is genuinely terminated upstream, say so explicitly with',
213
+ `\`allowUnverifiedWebhooks: ['${name}']\` in config/payments.ts.`,
214
+ ].join(' '));
215
+ }
52
216
  }
53
217
  //# sourceMappingURL=webhook_security.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhook_security.js","sourceRoot":"","sources":["../../src/webhook_security.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAElF;;;;;GAKG;AAEH,yDAAyD;AACzD,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,QAAgB;IAC5D,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,SAA6B,EAC7B,MAAc,EACd,SAA4B;IAE5B,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxF,OAAO,WAAW,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAe,EACf,SAA6B,EAC7B,SAAiB;IAEjB,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC1C,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO,YAAY,CACjB,YAAY,EACZ,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAC5B,GAAG,EACH,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CACjC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAA4B,EAC5B,QAAgB,EAChB,QAAgB,EAChB,IAAY;IAEZ,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,OAAO,QAAQ,WAAW,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,YAAY,IAAI,GAAG,CAAC,CAAC;IACrE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"webhook_security.js","sourceRoot":"","sources":["../../src/webhook_security.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,19 @@ export default defineConfig({
37
37
  // // Recommended RSA signature (x-webhook-signature):
38
38
  // webhookPublicKey: env.get('WOOVI_PUBLIC_KEY'),
39
39
  // }),
40
+ // pagbank: payments.pagbank({
41
+ // token: env.get('PAGBANK_TOKEN'),
42
+ // // Webhooks are verified with the SAME token (x-authenticity-token); there is no
43
+ // // separate secret. Only turn verification off for the sandbox, never in production.
44
+ // notificationUrls: [`${env.get('APP_URL')}/payments/webhook/pagbank`],
45
+ // }),
46
+ // efi: payments.efi({
47
+ // clientId: env.get('EFI_CLIENT_ID'),
48
+ // clientSecret: env.get('EFI_CLIENT_SECRET'),
49
+ // pixKey: env.get('EFI_PIX_KEY'),
50
+ // // Efí's Pix API needs mutual TLS: the .p12 from the dashboard, as a path or Buffer.
51
+ // certificate: env.get('EFI_CERTIFICATE'),
52
+ // }),
40
53
  },
41
54
 
42
55
  /**
@@ -0,0 +1,42 @@
1
+ {{{
2
+ exports({ to: app.configPath('payments_client.ts') })
3
+ }}}
4
+ import { defineConfig } from '@adonis-agora/payments/client'
5
+
6
+ /**
7
+ * Configuration for the browser-facing payment status endpoint — the one
8
+ * \`usePaymentStatus()\` from \`@adonis-agora/payments-react\` polls while a Pix
9
+ * QR code or a boleto is on screen.
10
+ *
11
+ * DISABLED BY DEFAULT. Unlike the dashboard, this endpoint is reachable by every
12
+ * logged-in browser, so you turn it on deliberately.
13
+ *
14
+ * The three hooks below are the whole authorization story:
15
+ *
16
+ * - \`authorize\` — is this request allowed at all (default: there is a
17
+ * resolved user on \`ctx.auth\`; no user is a 401).
18
+ * - \`owner\` — who is asking (default: \`{ type: 'User', id: user.id }\`).
19
+ * - \`authorizeReference\` — may this caller see THIS payment. The default checks
20
+ * the payment's gateway customer against the one the owner
21
+ * holds in \`billing_customers\`. If you never recorded that
22
+ * mapping with \`ensureCustomer(..., { store, owner })\`, the
23
+ * default DENIES — write your own hook against your own
24
+ * tables instead.
25
+ */
26
+ export default defineConfig({
27
+ // Turn it on. Nothing is mounted while this is false.
28
+ // enabled: true,
29
+ // path: '/payments/client',
30
+ // authorize: async (ctx) => {
31
+ // await ctx.auth.check()
32
+ // return ctx.auth.user !== undefined
33
+ // },
34
+ // owner: async (ctx) => {
35
+ // const user = ctx.auth.user
36
+ // return user ? { type: 'User', id: String(user.id) } : null
37
+ // },
38
+ // authorizeReference: async (ctx, reference) => {
39
+ // const order = await Order.findBy('gatewayPaymentId', reference)
40
+ // return order?.userId === ctx.auth.user?.id
41
+ // },
42
+ })
@@ -0,0 +1,38 @@
1
+ {{{
2
+ exports({ to: app.configPath('payments_dashboard.ts') })
3
+ }}}
4
+ import { defineConfig } from '@adonis-agora/payments/dashboard'
5
+
6
+ /**
7
+ * Configuration for the @adonis-agora/payments dashboard.
8
+ *
9
+ * By default the dashboard is open OUTSIDE production, and in production it
10
+ * requires a bearer token equal to \`PAYMENTS_DASHBOARD_TOKEN\` (deny if unset).
11
+ * Replace \`authorize\` with your own guard (session, role, IP allow-list, …).
12
+ *
13
+ * Set \`enabled: false\` to remove it entirely — no routes are registered at all.
14
+ *
15
+ * \`dashboardAuth\` is an ADDITIVE, optional session gate on top of \`authorize\` —
16
+ * a signed cookie minted via a built-in login page (Mode B: \`login\`) and/or a
17
+ * "open the console from your app" endpoint (Mode A: \`session\`). At least one
18
+ * of the two is required when \`dashboardAuth\` is set.
19
+ */
20
+ export default defineConfig({
21
+ // enabled: true,
22
+ // path: '/payments-dashboard',
23
+ // currency: 'BRL',
24
+ // authorize: (ctx) => ctx.auth.user?.isAdmin === true,
25
+ // dashboardAuth: {
26
+ // secret: env.get('PAYMENTS_DASHBOARD_SECRET'),
27
+ // ttl: '8h',
28
+ // // Mode B — standalone login page.
29
+ // login: async (username, password) => {
30
+ // if (username === 'admin' && password === env.get('PAYMENTS_DASHBOARD_PASSWORD')) {
31
+ // return { id: 'admin', name: 'Admin' }
32
+ // }
33
+ // return null
34
+ // },
35
+ // // Mode A — mint a session for an already-authenticated host request.
36
+ // // session: async (request) => (request.user?.isAdmin ? { id: request.user.id } : null),
37
+ // },
38
+ })
@@ -2,89 +2,47 @@
2
2
  exports({ to: app.migrationsPath(`${new Date().getTime()}_create_billing_tables.ts`) })
3
3
  }}}
4
4
  import { BaseSchema } from '@adonisjs/lucid/schema'
5
+ import { createBillingTables, dropBillingTables } from '@adonis-agora/payments'
5
6
 
7
+ /**
8
+ * The billing tables, for an app that would rather run DDL explicitly than have the library
9
+ * do it.
10
+ *
11
+ * **You may not need this file.** `@adonis-agora/payments` creates its own tables on first
12
+ * use, the same way `@adonis-agora/durable` and `@adonis-agora/authz` do — that is the
13
+ * ecosystem convention, and it is on by default. This migration exists for the case where
14
+ * that is not wanted: a shared database you do not own, a team that reviews every DDL, a
15
+ * deploy that runs migrations as a separate step.
16
+ *
17
+ * If you keep it, turn the automatic path off so there is one owner:
18
+ *
19
+ * // config/payments.ts
20
+ * billing: { autoCreateSchema: false }
21
+ *
22
+ * Leaving both on is harmless — the DDL is idempotent, so whichever runs second does
23
+ * nothing — but "who creates this table" should have one answer.
24
+ *
25
+ * Both paths call the SAME `createBillingTables`, which is the point: a schema defined twice
26
+ * is a schema that drifts, and this package spent a release finding the consequences of two
27
+ * things that were supposed to agree and did not.
28
+ *
29
+ * `this.defer` is how a Lucid migration hands over the query client.
30
+ *
31
+ * `createBillingTables` is idempotent in both directions: it creates what is missing AND
32
+ * applies the guarded `ALTER`s for columns the library added after a table shipped. So
33
+ * re-running this migration after upgrading the package carries those columns — which is
34
+ * why running it twice is safe and why there is no second file.
35
+ */
6
36
  export default class extends BaseSchema {
7
- protected tableName = 'billing_customers'
8
-
9
37
  async up() {
10
- this.schema.createTable('billing_customers', (table) => {
11
- table.uuid('id').primary()
12
- table.string('owner_type')
13
- table.string('owner_id')
14
- table.string('gateway_id').unique()
15
- table.string('provider')
16
- table.string('email').nullable()
17
- table.string('name').nullable()
18
- table.string('tax_id').nullable()
19
- table.jsonb('metadata').nullable()
20
- table.timestamp('created_at', { useTz: true }).notNullable()
21
- table.timestamp('updated_at', { useTz: true }).notNullable()
22
- table.index(['owner_type', 'owner_id'], 'billing_customers_owner_idx')
23
- })
24
-
25
- this.schema.createTable('billing_subscriptions', (table) => {
26
- table.uuid('id').primary()
27
- table.string('gateway_id').unique()
28
- table.string('provider')
29
- table.string('status')
30
- table.string('plan_id')
31
- table.string('customer_id').nullable()
32
- table.timestamp('trial_ends_at', { useTz: true }).nullable()
33
- table.timestamp('ends_at', { useTz: true }).nullable()
34
- table.jsonb('payload').nullable()
35
- table.timestamp('created_at', { useTz: true }).notNullable()
36
- table.timestamp('updated_at', { useTz: true }).notNullable()
37
- table.index(['customer_id'], 'billing_subscriptions_customer_idx')
38
- })
39
-
40
- this.schema.createTable('billing_payments', (table) => {
41
- table.uuid('id').primary()
42
- table.string('gateway_id').unique()
43
- table.string('provider')
44
- table.string('status')
45
- table.bigInteger('amount')
46
- table.string('currency', 3)
47
- table.string('customer_id').nullable()
48
- table.string('subscription_id').nullable()
49
- table.jsonb('payload').nullable()
50
- table.timestamp('paid_at', { useTz: true }).nullable()
51
- table.timestamp('created_at', { useTz: true }).notNullable()
52
- table.timestamp('updated_at', { useTz: true }).notNullable()
53
- table.index(['customer_id'], 'billing_payments_customer_idx')
54
- table.index(['subscription_id'], 'billing_payments_subscription_idx')
55
- })
56
-
57
- this.schema.createTable('billing_webhook_events', (table) => {
58
- table.uuid('id').primary()
59
- table.string('gateway_event_id').unique()
60
- table.string('provider')
61
- table.string('type')
62
- table.string('status')
63
- table.jsonb('payload').nullable()
64
- table.text('error').nullable()
65
- table.timestamp('created_at', { useTz: true }).notNullable()
66
- table.timestamp('updated_at', { useTz: true }).notNullable()
67
- })
68
-
69
- this.schema.createTable('billing_usage_events', (table) => {
70
- table.uuid('id').primary()
71
- table.string('subscription_id').nullable()
72
- table.string('customer_id').nullable()
73
- table.string('meter')
74
- table.integer('quantity').defaultTo(1)
75
- table.jsonb('metadata').nullable()
76
- table.timestamp('recorded_at', { useTz: true }).notNullable()
77
- table.timestamp('updated_at', { useTz: true }).notNullable()
78
- table.index(['subscription_id', 'meter'], 'billing_usage_subscription_meter_idx')
79
- table.index(['customer_id', 'meter'], 'billing_usage_customer_meter_idx')
38
+ this.defer(async (db) => {
39
+ await createBillingTables(db)
80
40
  })
81
41
  }
82
42
 
83
43
  async down() {
84
- this.schema.dropTable('billing_customers')
85
- this.schema.dropTable('billing_subscriptions')
86
- this.schema.dropTable('billing_payments')
87
- this.schema.dropTable('billing_webhook_events')
88
- this.schema.dropTable('billing_usage_events')
44
+ this.defer(async (db) => {
45
+ await dropBillingTables(db)
46
+ })
89
47
  }
90
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../stubs/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,MAA0B,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../stubs/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,MAA0B,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -6,24 +6,42 @@
6
6
  })
7
7
  }}}
8
8
  import { inject } from '@adonisjs/core'
9
- import type { WebhookEvent } from '@adonis-agora/payments'
9
+ import type { WebhookEventFor } from '@adonis-agora/payments'
10
10
 
11
11
  /**
12
- * Webhook handler para `{{ entity.name }}` — rodado pela rota da própria lib
13
- * (`/payments/webhook/:provider`) dentro do WebhookProcessor. Um throw marca o evento
14
- * como failed no ledger e o dispatcher re-tenta (durable/in-process).
12
+ * Webhook handler for `{{ entity.name }}`, run by the library's own route
13
+ * (`POST /payments/webhook/:provider`) inside the WebhookProcessor. Throwing marks the
14
+ * event `failed` in the ledger, the dispatcher retries, and the route answers 500 so the
15
+ * gateway redelivers — a 2xx over a failed event is the payment lost.
15
16
  *
16
- * Faça a lógica pesada rodar numa fila/workflow durable e dispatch aqui:
17
+ * The class is resolved from the container, so constructor injection works: add a
18
+ * dependency and `@inject()` supplies it.
17
19
  *
18
- * const engine = await app.container.make(WorkflowEngine)
19
- * await engine.start(MyWorkflow, { ... }, randomUUID())
20
+ * `eventType` is checked at BOOT: a type in the `payment.*`/`subscription.*` namespace that
21
+ * is not one of the normalized `WEBHOOK_EVENT_TYPES` throws, because a handler nothing ever
22
+ * calls is a grant that silently never happens while the delivery is recorded as processed.
23
+ *
24
+ * Webhooks must answer fast. Do the heavy work — the grant, the activation — in a durable
25
+ * workflow and only dispatch from here:
26
+ *
27
+ * await this.engine.start(MyWorkflow, { externalReference }, randomUUID())
20
28
  */
21
29
  @inject()
22
30
  export default class {{ handlerName }}Handler {
23
31
  static readonly eventType = '{{ entity.name }}'
24
32
 
25
- async handle(event: WebhookEvent): Promise<void> {
26
- // Sua lógica de negócio (ou dispatch pra um workflow durable / job da fila)...
27
- void event
33
+ /**
34
+ * `WebhookEventFor<'{{ entity.name }}'>` types `event.data` from the event type — a payment
35
+ * payload for the payment events, a dispute payload for the dispute ones — so nothing here
36
+ * needs the `event.data as PaymentWebhookData` cast that used to open every handler, and
37
+ * reading a payment field off a dispute is a compile error rather than `undefined`.
38
+ */
39
+ async handle(event: WebhookEventFor<'{{ entity.name }}'>): Promise<void> {
40
+ // `externalReference` is the id YOUR app set on the charge, echoed back by the
41
+ // gateway — the routing key from this event to your own row.
42
+ const { externalReference } = event.data
43
+ if (!externalReference) return
44
+
45
+ void externalReference
28
46
  }
29
- }
47
+ }