@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
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Build the refund action over a driver resolver (the app's `PaymentsManager.driver`).
3
+ *
4
+ * The capability check happens BEFORE the call, matching `PaymentsManager.assertCapability`: a
5
+ * driver that declares `refunds: false` implements `refund()` only to throw, and discovering that
6
+ * from a gateway round-trip reads to the operator like a network failure.
7
+ */
8
+ export function createRefundAction(resolveDriver) {
9
+ return async ({ provider, gatewayId, amount }) => {
10
+ let driver;
11
+ try {
12
+ driver = await resolveDriver(provider);
13
+ }
14
+ catch (error) {
15
+ // The manager's own message names which drivers ARE configured, which is exactly the
16
+ // next thing the operator needs to know.
17
+ return { kind: 'unavailable', message: messageOf(error, `provider "${provider}" not found`) };
18
+ }
19
+ if (driver.capabilities?.refunds !== true) {
20
+ return {
21
+ kind: 'unsupported',
22
+ message: `The "${provider}" gateway has no refund API. Refund this payment from the gateway's own dashboard.`,
23
+ };
24
+ }
25
+ try {
26
+ const refund = await driver.refund(gatewayId, amount);
27
+ return {
28
+ kind: 'ok',
29
+ refund: {
30
+ gatewayId: refund.gatewayId,
31
+ amount: refund.amount.amount,
32
+ currency: refund.amount.currency,
33
+ status: refund.status,
34
+ },
35
+ };
36
+ }
37
+ catch (error) {
38
+ return { kind: 'gateway-error', message: messageOf(error, 'the gateway refused the refund') };
39
+ }
40
+ };
41
+ }
42
+ /**
43
+ * Build the retry action over the store plus the app's webhook processor.
44
+ *
45
+ * The ledger dance is the fiddly part and it lives here, once:
46
+ *
47
+ * 1. `recordWebhookEvent` re-claims a `failed` row and hands the ORIGINAL delivery back — both
48
+ * the raw payload and the NORMALIZED event recorded beside it. That is the only way to read
49
+ * a stored delivery through the `BillingStore` contract.
50
+ * 2. The event is rebuilt from those two columns. It is NEVER re-parsed: `parseWebhook`
51
+ * re-verifies a signature computed over headers the ledger does not keep, so rebuilding that
52
+ * way answered `422` on Stripe, Adyen and every other gateway that signs — a retry that
53
+ * worked for a minority of gateways, and only for the ones an attacker would not need to
54
+ * forge. A row with no `normalized` (written before the migration) is `undeliverable`,
55
+ * stated plainly, rather than half-replayed.
56
+ * 3. The row is put BACK to `failed` before `process` runs, because `WebhookProcessor.process`
57
+ * claims through `recordWebhookEvent` itself, and a row sitting at `received` reads to it as
58
+ * "in flight" — it would return `false` and run nothing at all. This is the one place that
59
+ * subtlety is written down.
60
+ * 4. `process` claims it properly and marks it `processed` or `failed` with the real reason.
61
+ */
62
+ export function createReplayAction(deps) {
63
+ return async ({ gatewayEventId, provider, type, previousError }) => {
64
+ const claimed = await deps.store.recordWebhookEvent({
65
+ gatewayEventId,
66
+ provider,
67
+ type,
68
+ // Ignored on the re-claim path — the row keeps the payload and the normalized event it
69
+ // was recorded with, which is precisely what we need back.
70
+ payload: {},
71
+ });
72
+ if (claimed === null)
73
+ return { kind: 'conflict' };
74
+ const row = claimed;
75
+ const ledgerId = String(row.id);
76
+ const restore = () => deps.store.markWebhookFailed(ledgerId, previousError ?? '');
77
+ if (row.normalized === null || row.normalized === undefined) {
78
+ // Put the row back exactly as the operator found it: this refusal is about THIS retry, and
79
+ // stamping it over the handler's original message would destroy the only record of why the
80
+ // event failed in the first place.
81
+ await restore();
82
+ return {
83
+ kind: 'undeliverable',
84
+ message: 'This event was recorded before `billing_webhook_events.normalized` existed, so the normalized event it carried was never stored and cannot be rebuilt without re-verifying the gateway signature — which needs headers this table has never kept. Deliveries received since then replay normally; nothing can backfill this one.',
85
+ };
86
+ }
87
+ const event = {
88
+ id: gatewayEventId,
89
+ provider,
90
+ type,
91
+ data: row.normalized,
92
+ raw: row.payload ?? {},
93
+ };
94
+ await restore();
95
+ try {
96
+ await deps.process(event);
97
+ return { kind: 'processed' };
98
+ }
99
+ catch (error) {
100
+ return { kind: 'failed', message: messageOf(error, 'the handler threw again') };
101
+ }
102
+ };
103
+ }
104
+ /** Every action reports a cause; an unreadable throw still gets a sentence rather than `{}`. */
105
+ function messageOf(error, fallback) {
106
+ if (error instanceof Error && error.message !== '')
107
+ return error.message;
108
+ if (typeof error === 'string' && error !== '')
109
+ return error;
110
+ return fallback;
111
+ }
112
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/dashboard/actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ import { type DashboardSession, type DashboardSessionUser } from './session_cookie.js';
2
+ /**
3
+ * Framework-light `dashboardAuth` mechanism for the payments dashboard — config resolution, the
4
+ * open-redirect guard, the login decision, and session verification. NO AdonisJS types leak in
5
+ * (mirroring {@link file://./handlers.ts handlers.ts}), so every branch is unit-testable against a
6
+ * plain object with no HTTP server. The provider (`providers/dashboard_provider.ts`) adapts an
7
+ * `HttpContext` to these functions and owns the cookie read/write via AdonisJS's native cookie API.
8
+ *
9
+ * When configured it gates BOTH the dashboard HTML shell (a full-page navigation redirected `302`
10
+ * to a server-rendered login page) and the JSON API (a plain `401`) behind a signed session cookie.
11
+ * When left unconfigured the dashboard behaves exactly as before (no login/logout routes, no
12
+ * session guard).
13
+ *
14
+ * Ported from `@adonis-agora/durable`'s `src/dashboard/auth.ts` with only the names changed, so the
15
+ * Agora consoles share ONE auth story rather than each inventing its own.
16
+ */
17
+ /** Host hook validating submitted credentials from the built-in login page (Mode B — standalone). */
18
+ export type LoginHook = (username: string, password: string) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
19
+ /**
20
+ * Host hook validating the HOST APP's own auth off the raw request (Mode A — SSO / "open from your
21
+ * app"). Receives the underlying platform request object (an AdonisJS `Request['request']`, i.e. the
22
+ * raw Node `IncomingMessage`) rather than an AdonisJS type, so this module stays framework-light and
23
+ * unit-testable with no `HttpContext` — the provider passes it through untouched. Mirrors
24
+ * `@adonis-agora/durable`'s `SessionHook` byte-for-byte (same two-mode split).
25
+ */
26
+ export type SessionHook = (request: unknown) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
27
+ /**
28
+ * Author-facing `dashboardAuth` option on `config/payments_dashboard.ts`. Gates the dashboard behind
29
+ * a signed session cookie, minted by whichever mode(s) are configured:
30
+ *
31
+ * - Mode B (`login`) — the built-in server-rendered login page (`GET <path>/login`), for a
32
+ * standalone console with its own credentials.
33
+ * - Mode A (`session`) — `POST <path>/session`, for a host app that's already authenticated the
34
+ * operator itself and wants a one-shot "open the console" button (a one-shot "open the console" button).
35
+ *
36
+ * Both may be configured together; at least one is required. The bundled dashboard SPA is unaware of
37
+ * which mode(s) are active — it only reacts to a 401's `{ auth: { modes } }` body (see
38
+ * `payments-client.ts`).
39
+ *
40
+ * Each hook is just a plain function that may be `async` and close over
41
+ * `app.container`/services (import them at the top of `config/payments_dashboard.ts`), so there is
42
+ * nothing extra to build for the async case.
43
+ */
44
+ export interface DashboardAuthOptions {
45
+ /** REQUIRED HMAC-SHA256 signing key. Missing/empty => boot error (fail closed). */
46
+ secret: string;
47
+ /** Cookie TTL as a duration string (`'8h'`, `'30m'`, `'7d'`). Default `'8h'`. */
48
+ ttl?: string;
49
+ /** Validates submitted username/password; return the session user, or `null` to deny. Thrown
50
+ * errors are treated as a denial (logged once, never surfaced to the client). May be async. */
51
+ login?: LoginHook;
52
+ /** Validates the host app's own auth off the raw request; return the session user, or `null` to
53
+ * deny. Thrown errors are treated as a denial. May be async. */
54
+ session?: SessionHook;
55
+ }
56
+ /** Which auth surface(s) are active — carried on an API 401's `{ auth: { modes } }` body so the SPA
57
+ * knows whether to offer the login page or just report "not authenticated". */
58
+ export type AuthMode = 'session' | 'login';
59
+ /** Resolved, validated `dashboardAuth` config shared by the guard, the login/session handlers, and
60
+ * the page. */
61
+ export interface ResolvedDashboardAuth {
62
+ secret: string;
63
+ ttlMs: number;
64
+ modes: AuthMode[];
65
+ login?: LoginHook;
66
+ session?: SessionHook;
67
+ }
68
+ /** Cookie name carrying the signed dashboard session. */
69
+ export declare const SESSION_COOKIE_NAME = "payments_dashboard_session";
70
+ /**
71
+ * Validate + resolve the `dashboardAuth` option. Returns `null` when unconfigured (today's
72
+ * unauthenticated behavior, unchanged). Throws at boot (fail closed) when configured but missing a
73
+ * secret, or neither `login` nor `session` is a function — the host learns immediately rather than
74
+ * shipping an un-mintable gate.
75
+ */
76
+ export declare function resolveDashboardAuth(options: DashboardAuthOptions | undefined): ResolvedDashboardAuth | null;
77
+ /**
78
+ * Guard a client-supplied redirect target against an open redirect: it must be a same-origin,
79
+ * root-relative path (`/payments/foo`), never a protocol-relative (`//evil.com`) or absolute
80
+ * (`https://evil.com`) URL. Falls back to `fallback` (the dashboard's own `basePath`) for anything
81
+ * else, including a missing/non-string value.
82
+ */
83
+ export declare function sanitizeReturnTo(candidate: unknown, fallback: string): string;
84
+ /**
85
+ * The framework-light outcome of a login attempt, mapped to HTTP by the provider:
86
+ * - `ok` → set `cookieValue` as the session cookie, reply `200 { redirectTo }`.
87
+ * - `bad-request` → `400` (body missing string `username`/`password`).
88
+ * - `unauthorized` → uniform `401 { error }` for EVERY credential failure (unknown user, wrong
89
+ * password, or a throwing hook) — no user-enumeration. `hookError` is set only when the hook
90
+ * threw, so the provider can warn-log it once without changing the client-visible response.
91
+ */
92
+ export type LoginOutcome = {
93
+ kind: 'ok';
94
+ cookieValue: string;
95
+ redirectTo: string;
96
+ } | {
97
+ kind: 'bad-request';
98
+ message: string;
99
+ } | {
100
+ kind: 'unauthorized';
101
+ message: string;
102
+ hookError?: unknown;
103
+ };
104
+ /**
105
+ * Decide a login attempt end-to-end (validate body → run hook → mint cookie) with no HTTP types.
106
+ * On success returns the signed cookie value to set plus the sanitized `redirectTo`; the password
107
+ * is forwarded to the hook AS-IS (empty string when blank), so the hook alone decides whether a
108
+ * password is required. `404`-worthy (Mode B not configured) is the provider's call, not this
109
+ * function's — it only runs once the provider has confirmed `auth.login` exists.
110
+ */
111
+ export declare function performLogin(auth: ResolvedDashboardAuth, body: unknown, basePath: string, now?: number): Promise<LoginOutcome>;
112
+ /**
113
+ * The framework-light outcome of a Mode A session-mint attempt (`POST <path>/session`), mapped to
114
+ * HTTP by the provider: `ok` → set the cookie, reply `204`; `unauthorized` → uniform `401` (the
115
+ * `session` hook returned/threw a denial).
116
+ */
117
+ export type SessionOutcome = {
118
+ kind: 'ok';
119
+ cookieValue: string;
120
+ } | {
121
+ kind: 'unauthorized';
122
+ hookError?: unknown;
123
+ };
124
+ /**
125
+ * Decide a Mode A session-mint attempt end-to-end: run the host's `session` hook against the raw
126
+ * platform request, and mint the cookie on success. No body to validate — the hook reads whatever it
127
+ * needs directly off `request` (its own cookie/JWT/header).
128
+ */
129
+ export declare function performSession(auth: ResolvedDashboardAuth, request: unknown, now?: number): Promise<SessionOutcome>;
130
+ /**
131
+ * Read + verify a session cookie value, returning the session or `null` when absent, tampered, or
132
+ * expired. Thin wrapper over {@link verifySessionCookie} so the provider never touches crypto.
133
+ */
134
+ export declare function readSession(auth: ResolvedDashboardAuth, cookieValue: string | undefined, now?: number): DashboardSession | null;
135
+ export type { DashboardSession, DashboardSessionUser } from './session_cookie.js';
136
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/dashboard/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAG1B,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;GAcG;AAEH,qGAAqG;AACrG,MAAM,MAAM,SAAS,GAAG,CACtB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAAG,oBAAoB,GAAG,IAAI,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAAG,oBAAoB,GAAG,IAAI,CAAC;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;oGACgG;IAChG,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;qEACiE;IACjE,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED;gFACgF;AAChF,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3C;gBACgB;AAChB,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAoBhE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,oBAAoB,GAAG,SAAS,GACxC,qBAAqB,GAAG,IAAI,CA0B9B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM7E;AAaD;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAoBnE;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,qBAAqB,EAC3B,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAuBvB;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAElD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,CAAC,CAezB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,qBAAqB,EAC3B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,GAAG,CAAC,EAAE,MAAM,GACX,gBAAgB,GAAG,IAAI,CAMzB;AAED,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,152 @@
1
+ import { signSessionCookie, verifySessionCookie, } from './session_cookie.js';
2
+ /** Cookie name carrying the signed dashboard session. */
3
+ export const SESSION_COOKIE_NAME = 'payments_dashboard_session';
4
+ const DEFAULT_TTL = '8h';
5
+ const DEFAULT_TTL_MS = 8 * 60 * 60 * 1000;
6
+ const DURATION_UNITS = {
7
+ s: 1000,
8
+ m: 60 * 1000,
9
+ h: 60 * 60 * 1000,
10
+ d: 24 * 60 * 60 * 1000,
11
+ };
12
+ /** Parse a `'<number><s|m|h|d>'` duration to ms; falls back to the 8h default on a bad value. */
13
+ function durationToMs(ttl) {
14
+ const match = /^(\d+)([smhd])$/.exec(ttl.trim());
15
+ if (!match)
16
+ return DEFAULT_TTL_MS;
17
+ const unit = DURATION_UNITS[match[2] ?? ''];
18
+ if (unit === undefined)
19
+ return DEFAULT_TTL_MS;
20
+ return Number(match[1]) * unit;
21
+ }
22
+ /**
23
+ * Validate + resolve the `dashboardAuth` option. Returns `null` when unconfigured (today's
24
+ * unauthenticated behavior, unchanged). Throws at boot (fail closed) when configured but missing a
25
+ * secret, or neither `login` nor `session` is a function — the host learns immediately rather than
26
+ * shipping an un-mintable gate.
27
+ */
28
+ export function resolveDashboardAuth(options) {
29
+ if (options === undefined)
30
+ return null;
31
+ if (typeof options.secret !== 'string' || options.secret === '') {
32
+ throw new Error('payments_dashboard: dashboardAuth.secret is required and must be a non-empty string ' +
33
+ '(HMAC-SHA256 signing key, 32+ bytes recommended). Failing closed.');
34
+ }
35
+ const hasLogin = typeof options.login === 'function';
36
+ const hasSession = typeof options.session === 'function';
37
+ if (!hasLogin && !hasSession) {
38
+ throw new Error('payments_dashboard: dashboardAuth needs at least one of `login` or `session` (a login hook or ' +
39
+ 'a host-session hook).');
40
+ }
41
+ const modes = [];
42
+ if (hasSession)
43
+ modes.push('session');
44
+ if (hasLogin)
45
+ modes.push('login');
46
+ return {
47
+ secret: options.secret,
48
+ ttlMs: durationToMs(options.ttl ?? DEFAULT_TTL),
49
+ modes,
50
+ ...(hasLogin ? { login: options.login } : {}),
51
+ ...(hasSession ? { session: options.session } : {}),
52
+ };
53
+ }
54
+ /**
55
+ * Guard a client-supplied redirect target against an open redirect: it must be a same-origin,
56
+ * root-relative path (`/payments/foo`), never a protocol-relative (`//evil.com`) or absolute
57
+ * (`https://evil.com`) URL. Falls back to `fallback` (the dashboard's own `basePath`) for anything
58
+ * else, including a missing/non-string value.
59
+ */
60
+ export function sanitizeReturnTo(candidate, fallback) {
61
+ if (typeof candidate !== 'string')
62
+ return fallback;
63
+ if (!candidate.startsWith('/'))
64
+ return fallback;
65
+ if (candidate.startsWith('//'))
66
+ return fallback;
67
+ if (candidate.includes('://'))
68
+ return fallback;
69
+ return candidate;
70
+ }
71
+ function isString(value) {
72
+ return typeof value === 'string';
73
+ }
74
+ const UNAUTHORIZED_MESSAGE = 'Invalid username or password.';
75
+ /**
76
+ * Run a host hook (`login` or `session`) defensively: a throw is treated as a denial (uniform
77
+ * failure) so a buggy hook never 500s the endpoint into a stack-trace leak. The thrown error is
78
+ * surfaced on the outcome (`hookError`) so the provider can warn-log it once, but it never reaches
79
+ * the client.
80
+ */
81
+ async function runHook(hook) {
82
+ try {
83
+ return { user: (await hook()) ?? null };
84
+ }
85
+ catch (error) {
86
+ return { user: null, error };
87
+ }
88
+ }
89
+ /**
90
+ * Decide a login attempt end-to-end (validate body → run hook → mint cookie) with no HTTP types.
91
+ * On success returns the signed cookie value to set plus the sanitized `redirectTo`; the password
92
+ * is forwarded to the hook AS-IS (empty string when blank), so the hook alone decides whether a
93
+ * password is required. `404`-worthy (Mode B not configured) is the provider's call, not this
94
+ * function's — it only runs once the provider has confirmed `auth.login` exists.
95
+ */
96
+ export async function performLogin(auth, body, basePath, now) {
97
+ const parsed = (body ?? {});
98
+ if (!isString(parsed.username) || !isString(parsed.password)) {
99
+ return { kind: 'bad-request', message: 'Body must include string `username` and `password`.' };
100
+ }
101
+ const login = auth.login;
102
+ if (!login) {
103
+ return { kind: 'unauthorized', message: UNAUTHORIZED_MESSAGE };
104
+ }
105
+ const { user, error } = await runHook(() => login(parsed.username, parsed.password));
106
+ if (!user) {
107
+ return error !== undefined
108
+ ? { kind: 'unauthorized', message: UNAUTHORIZED_MESSAGE, hookError: error }
109
+ : { kind: 'unauthorized', message: UNAUTHORIZED_MESSAGE };
110
+ }
111
+ const cookieValue = signSessionCookie(user, {
112
+ secret: auth.secret,
113
+ ttlMs: auth.ttlMs,
114
+ ...(now !== undefined ? { now } : {}),
115
+ });
116
+ return { kind: 'ok', cookieValue, redirectTo: sanitizeReturnTo(parsed.returnTo, basePath) };
117
+ }
118
+ /**
119
+ * Decide a Mode A session-mint attempt end-to-end: run the host's `session` hook against the raw
120
+ * platform request, and mint the cookie on success. No body to validate — the hook reads whatever it
121
+ * needs directly off `request` (its own cookie/JWT/header).
122
+ */
123
+ export async function performSession(auth, request, now) {
124
+ const session = auth.session;
125
+ if (!session)
126
+ return { kind: 'unauthorized' };
127
+ const { user, error } = await runHook(() => session(request));
128
+ if (!user) {
129
+ return error !== undefined
130
+ ? { kind: 'unauthorized', hookError: error }
131
+ : { kind: 'unauthorized' };
132
+ }
133
+ const cookieValue = signSessionCookie(user, {
134
+ secret: auth.secret,
135
+ ttlMs: auth.ttlMs,
136
+ ...(now !== undefined ? { now } : {}),
137
+ });
138
+ return { kind: 'ok', cookieValue };
139
+ }
140
+ /**
141
+ * Read + verify a session cookie value, returning the session or `null` when absent, tampered, or
142
+ * expired. Thin wrapper over {@link verifySessionCookie} so the provider never touches crypto.
143
+ */
144
+ export function readSession(auth, cookieValue, now) {
145
+ if (cookieValue === undefined || cookieValue === '')
146
+ return null;
147
+ return verifySessionCookie(cookieValue, {
148
+ secret: auth.secret,
149
+ ...(now !== undefined ? { now } : {}),
150
+ });
151
+ }
152
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/dashboard/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import { type DashboardAuthOptions, type ResolvedDashboardAuth } from './auth.js';
3
+ /**
4
+ * Authorization guard for the dashboard. Runs before every dashboard route
5
+ * (API + HTML). Return `true` to allow the request, `false` to deny it (the
6
+ * provider replies `403`). May be async (e.g. an auth lookup).
7
+ *
8
+ * It receives the AdonisJS {@link HttpContext}, so it can read the session,
9
+ * a bearer token, an IP allow-list, etc.
10
+ */
11
+ export type AuthorizeHook = (ctx: HttpContext) => boolean | Promise<boolean>;
12
+ /** Shape of `config/payments_dashboard.ts`. */
13
+ export interface PaymentsDashboardConfig {
14
+ /**
15
+ * Master switch. When `false`, the provider registers no routes at all — the
16
+ * dashboard is completely absent. Defaults to `true`.
17
+ */
18
+ enabled?: boolean;
19
+ /**
20
+ * URL prefix the dashboard + its API mount under. Defaults to `/payments`. The HTML is
21
+ * served at the prefix root; the JSON API lives under `<path>/api`.
22
+ *
23
+ * It shares that prefix with the machine endpoints — `POST /payments/webhook/:provider`
24
+ * and `GET /payments/client/status` — and does so safely, because every route this
25
+ * provider registers is an EXACT path (`/payments`, `/payments/assets/:file`,
26
+ * `/payments/api/…`, login/session/logout). There is no SPA catch-all, so the dashboard's
27
+ * `enforce` guard cannot reach a delivery it was never routed. If you ever add one, the
28
+ * webhook route is what it would swallow, and a 403'd webhook looks exactly like a gateway
29
+ * outage from the outside.
30
+ */
31
+ path?: string;
32
+ /**
33
+ * ISO 4217 code the SPA formats the money columns with. Cents stay integer cents on the
34
+ * wire either way — this only decides how the edge renders them. Defaults to `'BRL'`.
35
+ */
36
+ currency?: string;
37
+ /**
38
+ * Per-request authorization guard. Defaults to {@link defaultAuthorize}:
39
+ * allow everything OUTSIDE production, and in production require a bearer
40
+ * token matching the `PAYMENTS_DASHBOARD_TOKEN` env var (deny if it is unset).
41
+ */
42
+ authorize?: AuthorizeHook;
43
+ /**
44
+ * Optional built-in login screen. When set, the provider mounts a
45
+ * server-rendered `GET <path>/login` page plus `POST <path>/login` /
46
+ * `GET <path>/logout`, and stamps a session guard on the dashboard: an
47
+ * unauthenticated page navigation is redirected (`302`) to the login page and
48
+ * an unauthenticated API request gets `401`. The signed session cookie is
49
+ * minted only by the host's {@link DashboardAuthOptions.login} hook.
50
+ *
51
+ * This is ADDITIVE and composes WITH {@link authorize} (both must pass) — it
52
+ * does not replace it. Omit it entirely for no login/logout routes and no
53
+ * session guard. Missing `secret`/`login` fails closed at boot.
54
+ */
55
+ dashboardAuth?: DashboardAuthOptions;
56
+ }
57
+ /** A fully-resolved config — every field present (defaults applied). */
58
+ export interface ResolvedPaymentsDashboardConfig {
59
+ enabled: boolean;
60
+ path: string;
61
+ currency: string;
62
+ authorize: AuthorizeHook;
63
+ /** Resolved built-in login config, or `null` when `dashboardAuth` is unconfigured. */
64
+ dashboardAuth: ResolvedDashboardAuth | null;
65
+ }
66
+ /**
67
+ * The default guard: open outside production; in production it requires a
68
+ * bearer token equal to `PAYMENTS_DASHBOARD_TOKEN`. If that env var is unset in
69
+ * production the dashboard is denied entirely (fail-closed) — you must opt in
70
+ * by setting a token or supplying your own {@link AuthorizeHook}.
71
+ *
72
+ * Identical posture to `@adonis-agora/durable`'s `defaultAuthorize`, down to the
73
+ * constant-time compare; only the env var name differs.
74
+ */
75
+ export declare function defaultAuthorize(ctx: HttpContext): boolean;
76
+ /** Apply defaults to a partial config, producing a fully-resolved one. */
77
+ export declare function resolveConfig(config?: PaymentsDashboardConfig): ResolvedPaymentsDashboardConfig;
78
+ /** Identity helper giving `config/payments_dashboard.ts` full type-checking. */
79
+ export declare function defineConfig(config?: PaymentsDashboardConfig): PaymentsDashboardConfig;
80
+ //# sourceMappingURL=define_config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/dashboard/define_config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAE3B,MAAM,WAAW,CAAC;AAEnB;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7E,+CAA+C;AAC/C,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAC;CACtC;AAED,wEAAwE;AACxE,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,sFAAsF;IACtF,aAAa,EAAE,qBAAqB,GAAG,IAAI,CAAC;CAC7C;AAyCD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAQ1D;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAC3B,MAAM,GAAE,uBAA4B,GACnC,+BAA+B,CAajC;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,MAAM,GAAE,uBAA4B,GAAG,uBAAuB,CAE1F"}
@@ -0,0 +1,83 @@
1
+ import { timingSafeEqual } from 'node:crypto';
2
+ import { resolveDashboardAuth, } from './auth.js';
3
+ /**
4
+ * Whether the process is running in production. Mirrors how AdonisJS reads the
5
+ * environment without taking a hard dependency on its env service.
6
+ */
7
+ function isProduction() {
8
+ return (process.env.NODE_ENV ?? '').toLowerCase() === 'production';
9
+ }
10
+ /**
11
+ * Extract a bearer token from an `Authorization: Bearer <token>` header, a
12
+ * `token` query-string param, or an `x-payments-token` header — whichever is
13
+ * present. Returns `undefined` when none is supplied.
14
+ */
15
+ function readToken(ctx) {
16
+ const header = ctx.request.header('authorization');
17
+ if (header) {
18
+ const match = /^Bearer\s+(.+)$/i.exec(header);
19
+ if (match?.[1])
20
+ return match[1].trim();
21
+ }
22
+ const xHeader = ctx.request.header('x-payments-token');
23
+ if (xHeader)
24
+ return xHeader.trim();
25
+ const qs = ctx.request.qs().token;
26
+ if (typeof qs === 'string' && qs.length > 0)
27
+ return qs;
28
+ return undefined;
29
+ }
30
+ /**
31
+ * Compare two secrets in constant time (guarding for equal byte-length first,
32
+ * since {@link timingSafeEqual} throws on a length mismatch). Returns `false`
33
+ * for any length difference, otherwise the timing-safe equality — so the token
34
+ * check leaks neither a match nor the token's length via response time.
35
+ */
36
+ function secretsMatch(a, b) {
37
+ const bufA = Buffer.from(a);
38
+ const bufB = Buffer.from(b);
39
+ if (bufA.length !== bufB.length)
40
+ return false;
41
+ return timingSafeEqual(bufA, bufB);
42
+ }
43
+ /**
44
+ * The default guard: open outside production; in production it requires a
45
+ * bearer token equal to `PAYMENTS_DASHBOARD_TOKEN`. If that env var is unset in
46
+ * production the dashboard is denied entirely (fail-closed) — you must opt in
47
+ * by setting a token or supplying your own {@link AuthorizeHook}.
48
+ *
49
+ * Identical posture to `@adonis-agora/durable`'s `defaultAuthorize`, down to the
50
+ * constant-time compare; only the env var name differs.
51
+ */
52
+ export function defaultAuthorize(ctx) {
53
+ if (!isProduction())
54
+ return true;
55
+ const expected = process.env.PAYMENTS_DASHBOARD_TOKEN;
56
+ if (!expected)
57
+ return false;
58
+ const provided = readToken(ctx);
59
+ if (provided === undefined)
60
+ return false;
61
+ // Constant-time compare to remove the timing side-channel from the token check.
62
+ return secretsMatch(provided, expected);
63
+ }
64
+ /** Apply defaults to a partial config, producing a fully-resolved one. */
65
+ export function resolveConfig(config = {}) {
66
+ const rawPath = config.path ?? '/payments';
67
+ // Normalize: ensure a single leading slash and no trailing slash (root stays '/').
68
+ const trimmed = `/${rawPath.replace(/^\/+/, '').replace(/\/+$/, '')}`;
69
+ return {
70
+ enabled: config.enabled ?? true,
71
+ path: trimmed === '/' ? '' : trimmed,
72
+ currency: config.currency ?? 'BRL',
73
+ authorize: config.authorize ?? defaultAuthorize,
74
+ // Validate + resolve now so a misconfigured secret/login fails closed at boot,
75
+ // not on the first login attempt. `null` when `dashboardAuth` is omitted.
76
+ dashboardAuth: resolveDashboardAuth(config.dashboardAuth),
77
+ };
78
+ }
79
+ /** Identity helper giving `config/payments_dashboard.ts` full type-checking. */
80
+ export function defineConfig(config = {}) {
81
+ return config;
82
+ }
83
+ //# sourceMappingURL=define_config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/dashboard/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAGL,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAoEnB;;;GAGG;AACH,SAAS,YAAY;IACnB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,GAAgB;IACjC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACnD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACvD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC;IAClC,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACvD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,CAAS,EAAE,CAAS;IACxC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAgB;IAC/C,IAAI,CAAC,YAAY,EAAE;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IACtD,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACzC,gFAAgF;IAChF,OAAO,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAC3B,MAAM,GAA4B,EAAE;IAEpC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC;IAC3C,mFAAmF;IACnF,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;IACtE,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;QAC/B,IAAI,EAAE,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;QACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,KAAK;QAClC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,gBAAgB;QAC/C,+EAA+E;QAC/E,0EAA0E;QAC1E,aAAa,EAAE,oBAAoB,CAAC,MAAM,CAAC,aAAa,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,MAAM,GAA4B,EAAE;IAC/D,OAAO,MAAM,CAAC;AAChB,CAAC"}