@adonis-agora/payments 0.2.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 (222) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/commands/main.d.ts +16 -0
  3. package/dist/commands/main.d.ts.map +1 -0
  4. package/dist/commands/main.js +17 -0
  5. package/dist/commands/main.js.map +1 -0
  6. package/dist/commands/make_billable.d.ts +16 -0
  7. package/dist/commands/make_billable.d.ts.map +1 -0
  8. package/dist/commands/make_billable.js +30 -0
  9. package/dist/commands/make_billable.js.map +1 -0
  10. package/dist/commands/make_webhook_handler.d.ts +20 -0
  11. package/dist/commands/make_webhook_handler.d.ts.map +1 -0
  12. package/dist/commands/make_webhook_handler.js +34 -0
  13. package/dist/commands/make_webhook_handler.js.map +1 -0
  14. package/dist/commands/payments_sync.d.ts +20 -0
  15. package/dist/commands/payments_sync.d.ts.map +1 -0
  16. package/dist/commands/payments_sync.js +95 -0
  17. package/dist/commands/payments_sync.js.map +1 -0
  18. package/dist/commands/payments_webhook.d.ts +19 -0
  19. package/dist/commands/payments_webhook.d.ts.map +1 -0
  20. package/dist/commands/payments_webhook.js +123 -0
  21. package/dist/commands/payments_webhook.js.map +1 -0
  22. package/dist/configure.d.ts +12 -0
  23. package/dist/configure.d.ts.map +1 -0
  24. package/dist/configure.js +34 -0
  25. package/dist/configure.js.map +1 -0
  26. package/dist/providers/payments_provider.d.ts +15 -0
  27. package/dist/providers/payments_provider.d.ts.map +1 -0
  28. package/dist/providers/payments_provider.js +155 -0
  29. package/dist/providers/payments_provider.js.map +1 -0
  30. package/dist/src/billing/billing_overview.d.ts +26 -0
  31. package/dist/src/billing/billing_overview.d.ts.map +1 -0
  32. package/dist/src/billing/billing_overview.js +27 -0
  33. package/dist/src/billing/billing_overview.js.map +1 -0
  34. package/dist/src/billing/billing_store.d.ts +73 -0
  35. package/dist/src/billing/billing_store.d.ts.map +1 -0
  36. package/dist/src/billing/billing_store.js +2 -0
  37. package/dist/src/billing/billing_store.js.map +1 -0
  38. package/dist/src/billing/index.d.ts +8 -0
  39. package/dist/src/billing/index.d.ts.map +1 -0
  40. package/dist/src/billing/index.js +6 -0
  41. package/dist/src/billing/index.js.map +1 -0
  42. package/dist/src/billing/lucid_billing_store.d.ts +84 -0
  43. package/dist/src/billing/lucid_billing_store.d.ts.map +1 -0
  44. package/dist/src/billing/lucid_billing_store.js +143 -0
  45. package/dist/src/billing/lucid_billing_store.js.map +1 -0
  46. package/dist/src/billing/metered_bill.d.ts +60 -0
  47. package/dist/src/billing/metered_bill.d.ts.map +1 -0
  48. package/dist/src/billing/metered_bill.js +46 -0
  49. package/dist/src/billing/metered_bill.js.map +1 -0
  50. package/dist/src/billing/mixins/index.d.ts +6 -0
  51. package/dist/src/billing/mixins/index.d.ts.map +1 -0
  52. package/dist/src/billing/mixins/index.js +6 -0
  53. package/dist/src/billing/mixins/index.js.map +1 -0
  54. package/dist/src/billing/mixins/with_billable.d.ts +23 -0
  55. package/dist/src/billing/mixins/with_billable.d.ts.map +1 -0
  56. package/dist/src/billing/mixins/with_billable.js +33 -0
  57. package/dist/src/billing/mixins/with_billable.js.map +1 -0
  58. package/dist/src/billing/mixins/with_payment.d.ts +45 -0
  59. package/dist/src/billing/mixins/with_payment.d.ts.map +1 -0
  60. package/dist/src/billing/mixins/with_payment.js +94 -0
  61. package/dist/src/billing/mixins/with_payment.js.map +1 -0
  62. package/dist/src/billing/mixins/with_subscription.d.ts +50 -0
  63. package/dist/src/billing/mixins/with_subscription.d.ts.map +1 -0
  64. package/dist/src/billing/mixins/with_subscription.js +95 -0
  65. package/dist/src/billing/mixins/with_subscription.js.map +1 -0
  66. package/dist/src/billing/mixins/with_usage_event.d.ts +22 -0
  67. package/dist/src/billing/mixins/with_usage_event.d.ts.map +1 -0
  68. package/dist/src/billing/mixins/with_usage_event.js +39 -0
  69. package/dist/src/billing/mixins/with_usage_event.js.map +1 -0
  70. package/dist/src/billing/mixins/with_webhook_event.d.ts +21 -0
  71. package/dist/src/billing/mixins/with_webhook_event.d.ts.map +1 -0
  72. package/dist/src/billing/mixins/with_webhook_event.js +42 -0
  73. package/dist/src/billing/mixins/with_webhook_event.js.map +1 -0
  74. package/dist/src/billing/webhook_dispatcher.d.ts +79 -0
  75. package/dist/src/billing/webhook_dispatcher.d.ts.map +1 -0
  76. package/dist/src/billing/webhook_dispatcher.js +125 -0
  77. package/dist/src/billing/webhook_dispatcher.js.map +1 -0
  78. package/dist/src/billing/webhook_events.d.ts +49 -0
  79. package/dist/src/billing/webhook_events.d.ts.map +1 -0
  80. package/dist/src/billing/webhook_events.js +44 -0
  81. package/dist/src/billing/webhook_events.js.map +1 -0
  82. package/dist/src/billing/webhook_processor.d.ts +39 -0
  83. package/dist/src/billing/webhook_processor.d.ts.map +1 -0
  84. package/dist/src/billing/webhook_processor.js +209 -0
  85. package/dist/src/billing/webhook_processor.js.map +1 -0
  86. package/dist/src/define_config.d.ts +251 -0
  87. package/dist/src/define_config.d.ts.map +1 -0
  88. package/dist/src/define_config.js +67 -0
  89. package/dist/src/define_config.js.map +1 -0
  90. package/dist/src/diagnostics.d.ts +155 -0
  91. package/dist/src/diagnostics.d.ts.map +1 -0
  92. package/dist/src/diagnostics.js +153 -0
  93. package/dist/src/diagnostics.js.map +1 -0
  94. package/dist/src/driver.d.ts +222 -0
  95. package/dist/src/driver.d.ts.map +1 -0
  96. package/dist/src/driver.js +2 -0
  97. package/dist/src/driver.js.map +1 -0
  98. package/dist/src/drivers/abacate.d.ts +35 -0
  99. package/dist/src/drivers/abacate.d.ts.map +1 -0
  100. package/dist/src/drivers/abacate.js +381 -0
  101. package/dist/src/drivers/abacate.js.map +1 -0
  102. package/dist/src/drivers/asaas.d.ts +36 -0
  103. package/dist/src/drivers/asaas.d.ts.map +1 -0
  104. package/dist/src/drivers/asaas.js +455 -0
  105. package/dist/src/drivers/asaas.js.map +1 -0
  106. package/dist/src/drivers/stripe.d.ts +36 -0
  107. package/dist/src/drivers/stripe.d.ts.map +1 -0
  108. package/dist/src/drivers/stripe.js +392 -0
  109. package/dist/src/drivers/stripe.js.map +1 -0
  110. package/dist/src/drivers/woovi.d.ts +49 -0
  111. package/dist/src/drivers/woovi.d.ts.map +1 -0
  112. package/dist/src/drivers/woovi.js +339 -0
  113. package/dist/src/drivers/woovi.js.map +1 -0
  114. package/dist/src/ensure_customer.d.ts +23 -0
  115. package/dist/src/ensure_customer.d.ts.map +1 -0
  116. package/dist/src/ensure_customer.js +25 -0
  117. package/dist/src/ensure_customer.js.map +1 -0
  118. package/dist/src/hooks/webhook_handlers.d.ts +50 -0
  119. package/dist/src/hooks/webhook_handlers.d.ts.map +1 -0
  120. package/dist/src/hooks/webhook_handlers.js +53 -0
  121. package/dist/src/hooks/webhook_handlers.js.map +1 -0
  122. package/dist/src/http.d.ts +24 -0
  123. package/dist/src/http.d.ts.map +1 -0
  124. package/dist/src/http.js +52 -0
  125. package/dist/src/http.js.map +1 -0
  126. package/dist/src/index.d.ts +29 -0
  127. package/dist/src/index.d.ts.map +1 -0
  128. package/dist/src/index.js +15 -0
  129. package/dist/src/index.js.map +1 -0
  130. package/dist/src/invoice/drivers/asaas.d.ts +23 -0
  131. package/dist/src/invoice/drivers/asaas.d.ts.map +1 -0
  132. package/dist/src/invoice/drivers/asaas.js +85 -0
  133. package/dist/src/invoice/drivers/asaas.js.map +1 -0
  134. package/dist/src/invoice/drivers/enotas.d.ts +23 -0
  135. package/dist/src/invoice/drivers/enotas.d.ts.map +1 -0
  136. package/dist/src/invoice/drivers/enotas.js +83 -0
  137. package/dist/src/invoice/drivers/enotas.js.map +1 -0
  138. package/dist/src/invoice/drivers/focus.d.ts +23 -0
  139. package/dist/src/invoice/drivers/focus.d.ts.map +1 -0
  140. package/dist/src/invoice/drivers/focus.js +90 -0
  141. package/dist/src/invoice/drivers/focus.js.map +1 -0
  142. package/dist/src/invoice/drivers/plugnotas.d.ts +22 -0
  143. package/dist/src/invoice/drivers/plugnotas.d.ts.map +1 -0
  144. package/dist/src/invoice/drivers/plugnotas.js +81 -0
  145. package/dist/src/invoice/drivers/plugnotas.js.map +1 -0
  146. package/dist/src/invoice/drivers/tecnospeed.d.ts +29 -0
  147. package/dist/src/invoice/drivers/tecnospeed.d.ts.map +1 -0
  148. package/dist/src/invoice/drivers/tecnospeed.js +87 -0
  149. package/dist/src/invoice/drivers/tecnospeed.js.map +1 -0
  150. package/dist/src/invoice/emit_invoice.d.ts +45 -0
  151. package/dist/src/invoice/emit_invoice.d.ts.map +1 -0
  152. package/dist/src/invoice/emit_invoice.js +72 -0
  153. package/dist/src/invoice/emit_invoice.js.map +1 -0
  154. package/dist/src/invoice/invoice_manager.d.ts +12 -0
  155. package/dist/src/invoice/invoice_manager.d.ts.map +1 -0
  156. package/dist/src/invoice/invoice_manager.js +35 -0
  157. package/dist/src/invoice/invoice_manager.js.map +1 -0
  158. package/dist/src/invoice/invoice_provider.d.ts +48 -0
  159. package/dist/src/invoice/invoice_provider.d.ts.map +1 -0
  160. package/dist/src/invoice/invoice_provider.js +2 -0
  161. package/dist/src/invoice/invoice_provider.js.map +1 -0
  162. package/dist/src/money.d.ts +11 -0
  163. package/dist/src/money.d.ts.map +1 -0
  164. package/dist/src/money.js +14 -0
  165. package/dist/src/money.js.map +1 -0
  166. package/dist/src/payments_manager.d.ts +40 -0
  167. package/dist/src/payments_manager.d.ts.map +1 -0
  168. package/dist/src/payments_manager.js +94 -0
  169. package/dist/src/payments_manager.js.map +1 -0
  170. package/dist/src/services/main.d.ts +6 -0
  171. package/dist/src/services/main.d.ts.map +1 -0
  172. package/dist/src/services/main.js +17 -0
  173. package/dist/src/services/main.js.map +1 -0
  174. package/dist/src/telescope/index.d.ts +3 -0
  175. package/dist/src/telescope/index.d.ts.map +1 -0
  176. package/dist/src/telescope/index.js +2 -0
  177. package/dist/src/telescope/index.js.map +1 -0
  178. package/dist/src/telescope/payments_watcher.d.ts +27 -0
  179. package/dist/src/telescope/payments_watcher.d.ts.map +1 -0
  180. package/dist/src/telescope/payments_watcher.js +58 -0
  181. package/dist/src/telescope/payments_watcher.js.map +1 -0
  182. package/dist/src/telescope/telescope-sdk.d.ts +21 -0
  183. package/dist/src/telescope/telescope-sdk.d.ts.map +1 -0
  184. package/dist/src/telescope/telescope-sdk.js +11 -0
  185. package/dist/src/telescope/telescope-sdk.js.map +1 -0
  186. package/dist/src/testing/fake_payments_driver.d.ts +64 -0
  187. package/dist/src/testing/fake_payments_driver.d.ts.map +1 -0
  188. package/dist/src/testing/fake_payments_driver.js +171 -0
  189. package/dist/src/testing/fake_payments_driver.js.map +1 -0
  190. package/dist/src/testing/in_memory_billing_store.d.ts +110 -0
  191. package/dist/src/testing/in_memory_billing_store.d.ts.map +1 -0
  192. package/dist/src/testing/in_memory_billing_store.js +136 -0
  193. package/dist/src/testing/in_memory_billing_store.js.map +1 -0
  194. package/dist/src/testing/index.d.ts +6 -0
  195. package/dist/src/testing/index.d.ts.map +1 -0
  196. package/dist/src/testing/index.js +4 -0
  197. package/dist/src/testing/index.js.map +1 -0
  198. package/dist/src/testing/mutable_clock.d.ts +12 -0
  199. package/dist/src/testing/mutable_clock.d.ts.map +1 -0
  200. package/dist/src/testing/mutable_clock.js +20 -0
  201. package/dist/src/testing/mutable_clock.js.map +1 -0
  202. package/dist/src/types.d.ts +178 -0
  203. package/dist/src/types.d.ts.map +1 -0
  204. package/dist/src/types.js +9 -0
  205. package/dist/src/types.js.map +1 -0
  206. package/dist/src/webhook_handlers.d.ts +76 -0
  207. package/dist/src/webhook_handlers.d.ts.map +1 -0
  208. package/dist/src/webhook_handlers.js +128 -0
  209. package/dist/src/webhook_handlers.js.map +1 -0
  210. package/dist/src/webhook_security.d.ts +29 -0
  211. package/dist/src/webhook_security.d.ts.map +1 -0
  212. package/dist/src/webhook_security.js +53 -0
  213. package/dist/src/webhook_security.js.map +1 -0
  214. package/dist/stubs/config/payments.stub +101 -0
  215. package/dist/stubs/database/migrations/create_billing_tables.stub +90 -0
  216. package/dist/stubs/main.d.ts +9 -0
  217. package/dist/stubs/main.d.ts.map +1 -0
  218. package/dist/stubs/main.js +16 -0
  219. package/dist/stubs/main.js.map +1 -0
  220. package/dist/stubs/make/billable/main.stub +28 -0
  221. package/dist/stubs/make/webhook_handler/main.stub +29 -0
  222. package/package.json +150 -0
@@ -0,0 +1,79 @@
1
+ import type { WebhookEvent } from '../types.js';
2
+ import type { WebhookProcessor } from './webhook_processor.js';
3
+ /**
4
+ * Strategy used to run a webhook event through the {@link WebhookProcessor}.
5
+ *
6
+ * - `durable` — the event is dispatched as a fire-and-forget durable workflow run
7
+ * (`@adonis-agora/durable`), so processing survives crashes and retries deterministically.
8
+ * - `queue` — the event is dispatched as an `@adonisjs/queue` job (`queueDispatch`).
9
+ * - `in-process` — the event runs inline (awaited); on failure it is retried with
10
+ * exponential backoff in the background.
11
+ * - `auto` — uses `durable` when its provider is registered, else `queue` when the queue
12
+ * provider is, else `in-process`.
13
+ */
14
+ export type WebhookDispatchMode = 'durable' | 'queue' | 'in-process' | 'auto';
15
+ export interface WebhookDispatcherOptions {
16
+ processor: WebhookProcessor;
17
+ /**
18
+ * How webhooks are processed. `'auto'` (default) lazily resolves
19
+ * `@adonis-agora/durable` and uses it when installed AND available (the app has the
20
+ * durable provider registered), else `@adonisjs/queue` when available, else
21
+ * `in-process`. `'durable'`/`'queue'` require their backend (throw when missing).
22
+ * `'in-process'` never touches either.
23
+ */
24
+ mode?: WebhookDispatchMode;
25
+ /**
26
+ * In-process retry settings (exponential backoff). Ignored when durable/queue processes
27
+ * the event, which rely on their own retries.
28
+ */
29
+ retries?: {
30
+ /** Max attempts including the first. Default 5. */
31
+ max?: number;
32
+ /** Base delay in ms. Default 500. */
33
+ baseDelayMs?: number;
34
+ /** Max delay in ms. Default 30_000. */
35
+ maxDelayMs?: number;
36
+ };
37
+ /**
38
+ * Optional availability check used in `auto` mode: resolves to `true` only when durable
39
+ * is installed AND its engine is resolvable in the app (provider registered). Defaults
40
+ * to "installed" only. The provider injects the real check.
41
+ */
42
+ durableAvailable?: () => Promise<boolean>;
43
+ /**
44
+ * Dispatch a webhook event as an `@adonisjs/queue` job. The provider wires this (it owns
45
+ * the job class, its container binding and the queue-manager registration). Absent =
46
+ * queue mode is unavailable.
47
+ */
48
+ queueDispatch?: (event: WebhookEvent) => Promise<{
49
+ jobId?: string;
50
+ }>;
51
+ }
52
+ /** The minimal durable surface we use: a workflow class with a static `dispatch`. */
53
+ export interface DurableWorkflowLike {
54
+ dispatch(input: {
55
+ event: WebhookEvent;
56
+ }): Promise<{
57
+ runId: string;
58
+ }>;
59
+ }
60
+ /**
61
+ * Runs webhook events through the {@link WebhookProcessor}. In `auto` mode (the default)
62
+ * it tries to import `@adonis-agora/durable` lazily — only when the app has it installed
63
+ * do webhooks run as durable workflows; otherwise they fall back to an in-process
64
+ * dispatcher with exponential-backoff retries.
65
+ */
66
+ export declare class WebhookDispatcher {
67
+ #private;
68
+ constructor(options: WebhookDispatcherOptions);
69
+ /**
70
+ * Dispatch a webhook event for processing. Resolves once the event is accepted (durable)
71
+ * or fully processed (in-process).
72
+ */
73
+ dispatch(event: WebhookEvent): Promise<{
74
+ runId?: string;
75
+ }>;
76
+ /** Whether durable-backed processing is active. */
77
+ get mode(): WebhookDispatchMode;
78
+ }
79
+ //# sourceMappingURL=webhook_dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook_dispatcher.d.ts","sourceRoot":"","sources":["../../../src/billing/webhook_dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC;AAE9E,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,gBAAgB,CAAC;IAC5B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE;QACR,mDAAmD;QACnD,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,qCAAqC;QACrC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,uCAAuC;QACvC,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtE;AAED,qFAAqF;AACrF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,YAAY,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtE;AAED;;;;;GAKG;AACH,qBAAa,iBAAiB;;gBAUhB,OAAO,EAAE,wBAAwB;IAS7C;;;OAGG;IACG,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAUhE,mDAAmD;IACnD,IAAI,IAAI,IAAI,mBAAmB,CAE9B;CAkFF"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Runs webhook events through the {@link WebhookProcessor}. In `auto` mode (the default)
3
+ * it tries to import `@adonis-agora/durable` lazily — only when the app has it installed
4
+ * do webhooks run as durable workflows; otherwise they fall back to an in-process
5
+ * dispatcher with exponential-backoff retries.
6
+ */
7
+ export class WebhookDispatcher {
8
+ #processor;
9
+ #mode;
10
+ #maxAttempts;
11
+ #baseDelayMs;
12
+ #maxDelayMs;
13
+ #workflow;
14
+ #durableChecked = false;
15
+ #durableAvailable;
16
+ constructor(options) {
17
+ this.#processor = options.processor;
18
+ this.#mode = options.mode ?? 'auto';
19
+ this.#maxAttempts = options.retries?.max ?? 5;
20
+ this.#baseDelayMs = options.retries?.baseDelayMs ?? 500;
21
+ this.#maxDelayMs = options.retries?.maxDelayMs ?? 30_000;
22
+ this.#durableAvailable = options.durableAvailable;
23
+ }
24
+ /**
25
+ * Dispatch a webhook event for processing. Resolves once the event is accepted (durable)
26
+ * or fully processed (in-process).
27
+ */
28
+ async dispatch(event) {
29
+ if (await this.#useDurable()) {
30
+ const workflow = await this.#resolveDurable();
31
+ const { runId } = await workflow.dispatch({ event });
32
+ return { runId };
33
+ }
34
+ return this.#processWithRetry(event);
35
+ }
36
+ /** Whether durable-backed processing is active. */
37
+ get mode() {
38
+ return this.#mode;
39
+ }
40
+ /**
41
+ * Decide whether durable handles this event. `auto` performs the lazy import once and
42
+ * caches the answer; `durable` forces it (throwing when missing); `in-process` never.
43
+ */
44
+ async #useDurable() {
45
+ if (this.#mode === 'in-process')
46
+ return false;
47
+ if (this.#mode === 'durable')
48
+ return true;
49
+ // 'auto'
50
+ if (this.#durableChecked)
51
+ return this.#workflow !== undefined;
52
+ this.#durableChecked = true;
53
+ try {
54
+ if (this.#durableAvailable && !(await this.#durableAvailable())) {
55
+ this.#workflow = undefined;
56
+ return false;
57
+ }
58
+ await import('@adonis-agora/durable');
59
+ this.#workflow = await this.#buildWorkflow();
60
+ return true;
61
+ }
62
+ catch {
63
+ this.#workflow = undefined;
64
+ return false;
65
+ }
66
+ }
67
+ /**
68
+ * Lazily build a durable workflow class that runs the event through the shared
69
+ * processor hook. Only called when durable is actually installed.
70
+ */
71
+ async #buildWorkflow() {
72
+ const durable = await import('@adonis-agora/durable');
73
+ const { BaseWorkflow } = durable;
74
+ const processor = this.#processor;
75
+ // The workflow's `run(ctx, input)` is the durable body; `dispatch` (static, inherited)
76
+ // enqueues it fire-and-forget. Input is the webhook event.
77
+ const workflow = class PaymentsWebhookWorkflow extends BaseWorkflow {
78
+ async run(_ctx, input) {
79
+ await processor.process(input.event);
80
+ }
81
+ };
82
+ return workflow;
83
+ }
84
+ async #resolveDurable() {
85
+ const workflow = this.#workflow ?? (await this.#buildWorkflow());
86
+ if (!workflow) {
87
+ throw new Error('[payments] billing.durable is set to true/auto but @adonis-agora/durable is not installed. ' +
88
+ 'Install it (`node ace add @adonis-agora/durable`) or set billing.durable to false.');
89
+ }
90
+ return workflow;
91
+ }
92
+ /**
93
+ * In-process fallback: run through the processor, retrying with exponential backoff on
94
+ * failure (up to `#maxAttempts`). Retries run in the background — the first attempt is
95
+ * awaited so the webhook endpoint can respond.
96
+ */
97
+ async #processWithRetry(event) {
98
+ try {
99
+ await this.#processor.process(event);
100
+ return {};
101
+ }
102
+ catch (error) {
103
+ // Retry in the background (don't block the webhook response). The processor itself
104
+ // publishes `webhook.failed` on the diagnostics channel.
105
+ void this.#retry(event, 2);
106
+ return {};
107
+ }
108
+ }
109
+ async #retry(event, attempt) {
110
+ if (attempt > this.#maxAttempts)
111
+ return;
112
+ const delay = Math.min(this.#baseDelayMs * 2 ** (attempt - 2), this.#maxDelayMs);
113
+ await sleep(delay);
114
+ try {
115
+ await this.#processor.process(event);
116
+ }
117
+ catch {
118
+ await this.#retry(event, attempt + 1);
119
+ }
120
+ }
121
+ }
122
+ function sleep(ms) {
123
+ return new Promise((resolve) => setTimeout(resolve, ms));
124
+ }
125
+ //# sourceMappingURL=webhook_dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook_dispatcher.js","sourceRoot":"","sources":["../../../src/billing/webhook_dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { WebhookEvent } from '../types.js';
2
+ /**
3
+ * The canonical normalized webhook event types. Every driver's `#mapWebhookType` maps
4
+ * its gateway events onto these, and the `WebhookProcessor`'s built-in sync switches on
5
+ * them. Shared constant so a typo in one driver can't silently degrade to the no-op
6
+ * branch.
7
+ */
8
+ export declare const WEBHOOK_EVENT_TYPES: readonly ["payment.succeeded", "payment.failed", "payment.refunded", "payment.updated", "subscription.created", "subscription.updated", "subscription.canceled"];
9
+ export type WebhookEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
10
+ /** Shape the built-in sync handlers expect from a payment event's `data`. */
11
+ export interface PaymentWebhookData {
12
+ gatewayId: string;
13
+ amount: number;
14
+ currency: string;
15
+ customerId?: string;
16
+ subscriptionId?: string;
17
+ /**
18
+ * The `externalReference` the app set on the charge/subscription, echoed back by the
19
+ * gateway. First-class so app handlers route payments to their local records without
20
+ * digging into `event.raw` — the reason {@link ChargeInput.externalReference} exists.
21
+ */
22
+ externalReference?: string;
23
+ /** Gateway-echoed metadata, when the gateway includes it in the webhook payload. */
24
+ metadata?: Record<string, unknown>;
25
+ }
26
+ /** Shape the built-in sync handlers expect from a subscription event's `data`. */
27
+ export interface SubscriptionWebhookData {
28
+ gatewayId: string;
29
+ customerId: string;
30
+ status: string;
31
+ planId?: string;
32
+ trialEndsAt?: string;
33
+ endsAt?: string;
34
+ }
35
+ /**
36
+ * Guard: is this event's `data` shaped like a payment event? The drivers normalize their
37
+ * payloads onto this shape (see the Asaas driver's `#mapWebhookData`); the processor
38
+ * checks it before writing a row so a malformed event can't produce garbage rows.
39
+ */
40
+ export declare function isPaymentWebhookData(data: unknown): data is PaymentWebhookData;
41
+ /** Guard: is this event's `data` shaped like a subscription event? */
42
+ export declare function isSubscriptionWebhookData(data: unknown): data is SubscriptionWebhookData;
43
+ /** Assert a webhook event's type is one of the canonical types (or a passthrough). */
44
+ export declare function isWebhookEventType(type: string): type is WebhookEventType;
45
+ /** Narrow a {@link WebhookEvent} to one of the canonical types. */
46
+ export declare function asWebhookEvent(event: WebhookEvent): WebhookEvent<unknown> & {
47
+ type: WebhookEventType;
48
+ };
49
+ //# sourceMappingURL=webhook_events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook_events.d.ts","sourceRoot":"","sources":["../../../src/billing/webhook_events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,kKAQtB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,kFAAkF;AAClF,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,kBAAkB,CAQ9E;AAED,sEAAsE;AACtE,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,uBAAuB,CAIxF;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,gBAAgB,CAEzE;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,GAClB,YAAY,CAAC,OAAO,CAAC,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAEpD"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The canonical normalized webhook event types. Every driver's `#mapWebhookType` maps
3
+ * its gateway events onto these, and the `WebhookProcessor`'s built-in sync switches on
4
+ * them. Shared constant so a typo in one driver can't silently degrade to the no-op
5
+ * branch.
6
+ */
7
+ export const WEBHOOK_EVENT_TYPES = [
8
+ 'payment.succeeded',
9
+ 'payment.failed',
10
+ 'payment.refunded',
11
+ 'payment.updated',
12
+ 'subscription.created',
13
+ 'subscription.updated',
14
+ 'subscription.canceled',
15
+ ];
16
+ /**
17
+ * Guard: is this event's `data` shaped like a payment event? The drivers normalize their
18
+ * payloads onto this shape (see the Asaas driver's `#mapWebhookData`); the processor
19
+ * checks it before writing a row so a malformed event can't produce garbage rows.
20
+ */
21
+ export function isPaymentWebhookData(data) {
22
+ if (typeof data !== 'object' || data === null)
23
+ return false;
24
+ const d = data;
25
+ return (typeof d.gatewayId === 'string' &&
26
+ typeof d.amount === 'number' &&
27
+ typeof d.currency === 'string');
28
+ }
29
+ /** Guard: is this event's `data` shaped like a subscription event? */
30
+ export function isSubscriptionWebhookData(data) {
31
+ if (typeof data !== 'object' || data === null)
32
+ return false;
33
+ const d = data;
34
+ return typeof d.gatewayId === 'string' && typeof d.customerId === 'string';
35
+ }
36
+ /** Assert a webhook event's type is one of the canonical types (or a passthrough). */
37
+ export function isWebhookEventType(type) {
38
+ return WEBHOOK_EVENT_TYPES.includes(type);
39
+ }
40
+ /** Narrow a {@link WebhookEvent} to one of the canonical types. */
41
+ export function asWebhookEvent(event) {
42
+ return event;
43
+ }
44
+ //# sourceMappingURL=webhook_events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook_events.js","sourceRoot":"","sources":["../../../src/billing/webhook_events.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,mBAAmB;IACnB,gBAAgB;IAChB,kBAAkB;IAClB,iBAAiB;IACjB,sBAAsB;IACtB,sBAAsB;IACtB,uBAAuB;CACf,CAAC;AA+BX;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC5D,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,OAAO,CACL,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAC/B,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAC5B,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAC/B,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,yBAAyB,CAAC,IAAa;IACrD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC5D,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,OAAO,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC;AAC7E,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAQ,mBAAyC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,cAAc,CAC5B,KAAmB;IAEnB,OAAO,KAA2D,CAAC;AACrE,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { PaymentsDriver } from '../driver.js';
2
+ import type { WebhookEvent } from '../types.js';
3
+ import type { BillingStore } from './billing_store.js';
4
+ /**
5
+ * A handler for a gateway webhook event type (e.g. `'invoice.payment_succeeded'`).
6
+ * Receives the normalized event plus the raw gateway payload. Return normally to mark the
7
+ * event processed; throw to mark it failed (and trigger the dispatcher's retry).
8
+ */
9
+ export type WebhookHandler = (event: WebhookEvent) => void | Promise<void>;
10
+ export interface WebhookProcessorOptions {
11
+ store: BillingStore;
12
+ /**
13
+ * The driver that received the webhook — used for lookups and sync. Optional: the
14
+ * built-in handlers persist through the store and don't call the gateway.
15
+ */
16
+ driver?: PaymentsDriver;
17
+ /** Map of gateway event type → handler. Apps register their business logic here. */
18
+ handlers?: Record<string, WebhookHandler>;
19
+ }
20
+ /**
21
+ * Routes normalized webhook events to handlers, enforcing idempotency through the
22
+ * `billing_webhook_events` ledger (keyed by gateway event id), and keeps the local
23
+ * billing tables in sync (payments, subscriptions).
24
+ *
25
+ * Built-in handlers keep the store in sync and publish the normalized business events on
26
+ * the `@adonis-agora/diagnostics` channel (`agora:payments:payment.succeeded`, ...) —
27
+ * apps react with `onDiagnostic('payments', ...)` (or the `handlers` below). App
28
+ * handlers (via `handlers`) run after the built-in sync and can dispatch work.
29
+ */
30
+ export declare class WebhookProcessor {
31
+ #private;
32
+ constructor(options: WebhookProcessorOptions);
33
+ /**
34
+ * Process a webhook event. Returns `false` when the event was already processed
35
+ * (idempotent replay). Throws when the event handler throws.
36
+ */
37
+ process(event: WebhookEvent): Promise<boolean>;
38
+ }
39
+ //# sourceMappingURL=webhook_processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook_processor.d.ts","sourceRoot":"","sources":["../../../src/billing/webhook_processor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE3E,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC3C;AAED;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;;gBAKf,OAAO,EAAE,uBAAuB;IAM5C;;;OAGG;IACG,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CA6LrD"}
@@ -0,0 +1,209 @@
1
+ import { publishPayments } from '../diagnostics.js';
2
+ import { isPaymentWebhookData, isSubscriptionWebhookData } from './webhook_events.js';
3
+ /**
4
+ * Routes normalized webhook events to handlers, enforcing idempotency through the
5
+ * `billing_webhook_events` ledger (keyed by gateway event id), and keeps the local
6
+ * billing tables in sync (payments, subscriptions).
7
+ *
8
+ * Built-in handlers keep the store in sync and publish the normalized business events on
9
+ * the `@adonis-agora/diagnostics` channel (`agora:payments:payment.succeeded`, ...) —
10
+ * apps react with `onDiagnostic('payments', ...)` (or the `handlers` below). App
11
+ * handlers (via `handlers`) run after the built-in sync and can dispatch work.
12
+ */
13
+ export class WebhookProcessor {
14
+ #store;
15
+ #driver;
16
+ #handlers;
17
+ constructor(options) {
18
+ this.#store = options.store;
19
+ this.#driver = options.driver;
20
+ this.#handlers = options.handlers ?? {};
21
+ }
22
+ /**
23
+ * Process a webhook event. Returns `false` when the event was already processed
24
+ * (idempotent replay). Throws when the event handler throws.
25
+ */
26
+ async process(event) {
27
+ const ledger = await this.#store.recordWebhookEvent({
28
+ gatewayEventId: event.id,
29
+ provider: event.provider,
30
+ type: event.type,
31
+ payload: event.raw,
32
+ });
33
+ // Already seen → idempotent replay, skip.
34
+ if (ledger === null)
35
+ return false;
36
+ publishPayments('webhook.received', {
37
+ id: event.id,
38
+ provider: event.provider,
39
+ type: event.type,
40
+ });
41
+ try {
42
+ await this.#runBuiltIn(event);
43
+ const handler = this.#handlers[event.type];
44
+ if (handler)
45
+ await handler(event);
46
+ await this.#store.markWebhookProcessed(ledger.id);
47
+ publishPayments('webhook.processed', {
48
+ id: event.id,
49
+ provider: event.provider,
50
+ type: event.type,
51
+ });
52
+ return true;
53
+ }
54
+ catch (error) {
55
+ const message = error instanceof Error ? error.message : String(error);
56
+ await this.#store.markWebhookFailed(ledger.id, message);
57
+ publishPayments('webhook.failed', {
58
+ id: event.id,
59
+ provider: event.provider,
60
+ type: event.type,
61
+ error: message,
62
+ });
63
+ throw error;
64
+ }
65
+ }
66
+ /** Built-in sync handlers, keyed by the normalized event type (shared constants). */
67
+ #runBuiltIn(event) {
68
+ switch (event.type) {
69
+ case 'payment.succeeded':
70
+ return this.#onPaymentSucceeded(event);
71
+ case 'payment.failed':
72
+ return this.#onPaymentFailed(event);
73
+ case 'payment.refunded':
74
+ return this.#onPaymentRefunded(event);
75
+ case 'subscription.created':
76
+ case 'subscription.updated':
77
+ return this.#onSubscriptionChanged(event);
78
+ case 'subscription.canceled':
79
+ return this.#onSubscriptionCanceled(event);
80
+ default:
81
+ return Promise.resolve();
82
+ }
83
+ }
84
+ async #onPaymentSucceeded(event) {
85
+ if (!isPaymentWebhookData(event.data)) {
86
+ throw new Error(`[payments] Malformed payment.succeeded payload for event ${event.id}.`);
87
+ }
88
+ const { gatewayId, amount, currency, customerId, subscriptionId } = event.data;
89
+ await this.#store.savePayment({
90
+ gatewayId,
91
+ provider: event.provider,
92
+ status: 'paid',
93
+ amount,
94
+ currency,
95
+ ...(customerId !== undefined ? { customerId } : {}),
96
+ ...(subscriptionId !== undefined ? { subscriptionId } : {}),
97
+ paidAt: new Date(),
98
+ payload: event.raw,
99
+ });
100
+ publishPayments('payment.succeeded', {
101
+ gatewayId,
102
+ provider: event.provider,
103
+ amount,
104
+ currency,
105
+ ...(event.data.externalReference !== undefined
106
+ ? { externalReference: event.data.externalReference }
107
+ : {}),
108
+ });
109
+ }
110
+ async #onPaymentFailed(event) {
111
+ if (!isPaymentWebhookData(event.data)) {
112
+ throw new Error(`[payments] Malformed payment.failed payload for event ${event.id}.`);
113
+ }
114
+ const { gatewayId, amount, currency, customerId, subscriptionId } = event.data;
115
+ await this.#store.savePayment({
116
+ gatewayId,
117
+ provider: event.provider,
118
+ status: 'failed',
119
+ amount,
120
+ currency,
121
+ ...(customerId !== undefined ? { customerId } : {}),
122
+ ...(subscriptionId !== undefined ? { subscriptionId } : {}),
123
+ payload: event.raw,
124
+ });
125
+ publishPayments('payment.failed', {
126
+ gatewayId,
127
+ provider: event.provider,
128
+ amount,
129
+ currency,
130
+ ...(event.data.externalReference !== undefined
131
+ ? { externalReference: event.data.externalReference }
132
+ : {}),
133
+ });
134
+ }
135
+ async #onPaymentRefunded(event) {
136
+ if (!isPaymentWebhookData(event.data)) {
137
+ throw new Error(`[payments] Malformed payment.refunded payload for event ${event.id}.`);
138
+ }
139
+ const { gatewayId, amount, currency } = event.data;
140
+ const existing = await this.#store.findPaymentByGatewayId(gatewayId);
141
+ if (existing) {
142
+ await this.#store.savePayment({
143
+ gatewayId,
144
+ provider: event.provider,
145
+ status: 'refunded',
146
+ amount,
147
+ currency,
148
+ ...(existing.customerId !== undefined ? { customerId: existing.customerId } : {}),
149
+ ...(existing.subscriptionId !== undefined
150
+ ? { subscriptionId: existing.subscriptionId }
151
+ : {}),
152
+ payload: event.raw,
153
+ });
154
+ }
155
+ publishPayments('payment.refunded', {
156
+ gatewayId,
157
+ provider: event.provider,
158
+ amount,
159
+ currency,
160
+ });
161
+ }
162
+ async #onSubscriptionChanged(event) {
163
+ if (!isSubscriptionWebhookData(event.data)) {
164
+ throw new Error(`[payments] Malformed subscription payload for event ${event.id}.`);
165
+ }
166
+ const data = event.data;
167
+ await this.#store.saveSubscription({
168
+ gatewayId: data.gatewayId,
169
+ provider: event.provider,
170
+ customerId: data.customerId,
171
+ status: data.status,
172
+ planId: data.planId ?? '',
173
+ ...(data.trialEndsAt !== undefined ? { trialEndsAt: new Date(data.trialEndsAt) } : {}),
174
+ ...(data.endsAt !== undefined ? { endsAt: new Date(data.endsAt) } : {}),
175
+ payload: event.raw,
176
+ });
177
+ const type = event.type === 'subscription.created' ? 'subscription.created' : 'subscription.updated';
178
+ publishPayments(type, {
179
+ gatewayId: data.gatewayId,
180
+ provider: event.provider,
181
+ customerId: data.customerId,
182
+ status: data.status,
183
+ });
184
+ }
185
+ async #onSubscriptionCanceled(event) {
186
+ if (!isSubscriptionWebhookData(event.data)) {
187
+ throw new Error(`[payments] Malformed subscription.canceled payload for event ${event.id}.`);
188
+ }
189
+ const data = event.data;
190
+ const existing = await this.#store.findSubscriptionByGatewayId(data.gatewayId);
191
+ if (existing) {
192
+ await this.#store.saveSubscription({
193
+ gatewayId: data.gatewayId,
194
+ provider: event.provider,
195
+ customerId: data.customerId,
196
+ status: 'canceled',
197
+ planId: existing.planId,
198
+ ...(data.trialEndsAt !== undefined ? { trialEndsAt: new Date(data.trialEndsAt) } : {}),
199
+ ...(data.endsAt !== undefined ? { endsAt: new Date(data.endsAt) } : {}),
200
+ payload: event.raw,
201
+ });
202
+ }
203
+ publishPayments('subscription.canceled', {
204
+ gatewayId: data.gatewayId,
205
+ provider: event.provider,
206
+ });
207
+ }
208
+ }
209
+ //# sourceMappingURL=webhook_processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook_processor.js","sourceRoot":"","sources":["../../../src/billing/webhook_processor.ts"],"names":[],"mappings":"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"}