@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,155 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ import { LucidBillingStore } from '../src/billing/lucid_billing_store.js';
3
+ import { WebhookDispatcher } from '../src/billing/webhook_dispatcher.js';
4
+ import { WebhookProcessor } from '../src/billing/webhook_processor.js';
5
+ import { InvoiceManager, resolveInvoiceProviders } from '../src/invoice/invoice_manager.js';
6
+ import { PaymentsManager, resolveDrivers } from '../src/payments_manager.js';
7
+ import { setPayments } from '../src/services/main.js';
8
+ import { discoverWebhookHandlers, loadWebhookHandlersFromBarrel, resolveWebhookHandler, } from '../src/webhook_handlers.js';
9
+ /**
10
+ * Wires `@adonis-agora/payments` into the AdonisJS application: binds a singleton
11
+ * {@link PaymentsManager} built from `config/payments.ts`, wires the optional Lucid
12
+ * billing layer (store + webhook processor + dispatcher), and mounts the webhook route
13
+ * under `/payments/webhook/:provider`.
14
+ */
15
+ export default class PaymentsProvider {
16
+ app;
17
+ #webhook;
18
+ constructor(app) {
19
+ this.app = app;
20
+ }
21
+ register() {
22
+ const config = this.app.config.get('payments', {});
23
+ this.app.container.singleton(PaymentsManager, async () => {
24
+ // Build invoice providers first so drivers can resolve them from their ctx (a
25
+ // charge with `invoice: true|'name'` emits through the invoice provider).
26
+ let invoices;
27
+ if (config.invoice) {
28
+ const providers = await resolveInvoiceProviders(config.invoice);
29
+ invoices = new InvoiceManager(providers);
30
+ }
31
+ const drivers = await resolveDrivers(config, invoices);
32
+ const manager = new PaymentsManager({
33
+ drivers,
34
+ ...(invoices !== undefined ? { invoices } : {}),
35
+ ...(config.methods !== undefined ? { methods: config.methods } : {}),
36
+ ...(config.default !== undefined ? { defaultName: config.default } : {}),
37
+ });
38
+ // Hand the manager to the lazy `services/main` singleton so `getPayments()` works.
39
+ setPayments(manager);
40
+ return manager;
41
+ });
42
+ }
43
+ async boot() {
44
+ await this.app.booted(async () => {
45
+ const config = this.app.config.get('payments', {});
46
+ // Build the billing layer here (async — resolves the app emitter + handler
47
+ // factories), so the mounted route can emit `billing:*` and run app handlers.
48
+ if (config.billing?.enabled !== false) {
49
+ await this.#buildBillingLayer(config);
50
+ }
51
+ // Resolve the manager here so `setPayments` runs and `getPayments()` works for
52
+ // services that read it during boot — after every provider has registered.
53
+ await this.app.container.make(PaymentsManager);
54
+ const router = await this.app.container.make('router');
55
+ this.#registerWebhookRoute(router);
56
+ });
57
+ }
58
+ async #buildBillingLayer(config) {
59
+ const store = new LucidBillingStore();
60
+ const handlers = await this.#resolveAllHandlers(config.billing?.handlers);
61
+ const processor = new WebhookProcessor({
62
+ store,
63
+ ...(handlers !== undefined ? { handlers } : {}),
64
+ });
65
+ this.#webhook = new WebhookDispatcher({
66
+ processor,
67
+ mode: this.#resolveMode(config),
68
+ // In 'auto', durable is used only when its engine is resolvable in the app
69
+ // (i.e. the durable provider is registered) — not merely installed.
70
+ durableAvailable: () => this.#isDurableAvailable(),
71
+ });
72
+ }
73
+ /**
74
+ * Merge webhook handlers from the two sources:
75
+ * 1. `config.billing.handlers` (functions or service classes),
76
+ * 2. the conventions folder `app/payment_handlers/` (build-time barrel, runtime scan
77
+ * as fallback) — the durable-style discovery.
78
+ */
79
+ async #resolveAllHandlers(configHandlers) {
80
+ const handlers = {};
81
+ if (configHandlers) {
82
+ for (const [type, entry] of Object.entries(configHandlers)) {
83
+ handlers[type] = await resolveWebhookHandler(entry, this.app.container);
84
+ }
85
+ }
86
+ for (const discovered of await this.#discoverFolderHandlers()) {
87
+ handlers[discovered.type] = await resolveWebhookHandler(discovered.entry, this.app.container);
88
+ }
89
+ return Object.keys(handlers).length > 0 ? handlers : undefined;
90
+ }
91
+ /** Discover handlers in `app/payment_handlers/`: build-time barrel, else runtime scan. */
92
+ async #discoverFolderHandlers() {
93
+ const barrel = await this.#loadGeneratedBarrel();
94
+ if (barrel)
95
+ return loadWebhookHandlersFromBarrel(barrel);
96
+ const dir = this.app.makePath('app/payment_handlers');
97
+ return discoverWebhookHandlers(dir);
98
+ }
99
+ /** Import the Assembler `init`-hook barrel (`.adonisjs/payments/webhook_handlers.js`). */
100
+ async #loadGeneratedBarrel() {
101
+ const path = this.app.makePath('.adonisjs/payments/webhook_handlers.js');
102
+ try {
103
+ const mod = (await import(pathToFileURL(path).href));
104
+ return mod.webhookHandlers ?? null;
105
+ }
106
+ catch (err) {
107
+ const code = err.code;
108
+ if (code === 'ERR_MODULE_NOT_FOUND' || code === 'ENOENT')
109
+ return null;
110
+ throw err;
111
+ }
112
+ }
113
+ /** Whether the app has a resolvable durable workflow engine. */
114
+ async #isDurableAvailable() {
115
+ try {
116
+ const { WorkflowEngine } = await import('@adonis-agora/durable');
117
+ await this.app.container.make(WorkflowEngine);
118
+ return true;
119
+ }
120
+ catch {
121
+ return false;
122
+ }
123
+ }
124
+ /** Map `billing.durable` (`'auto' | boolean`) onto the dispatcher's mode. */
125
+ #resolveMode(config) {
126
+ const setting = config.billing?.durable ?? 'auto';
127
+ if (setting === true)
128
+ return 'durable';
129
+ if (setting === false)
130
+ return 'in-process';
131
+ return 'auto';
132
+ }
133
+ #registerWebhookRoute(router) {
134
+ router
135
+ .post('/payments/webhook/:provider', async (ctx) => {
136
+ const manager = await this.app.container.make(PaymentsManager);
137
+ const provider = String(ctx.params.provider);
138
+ try {
139
+ const driver = manager.driver(provider);
140
+ const rawBody = ctx.request.raw() ?? '';
141
+ const event = driver.parseWebhook(rawBody, ctx.request.headers());
142
+ if (this.#webhook) {
143
+ await this.#webhook.dispatch(event);
144
+ }
145
+ return ctx.response.status(200).json({ received: true });
146
+ }
147
+ catch (error) {
148
+ const message = error instanceof Error ? error.message : 'invalid webhook';
149
+ return ctx.response.status(400).json({ error: message });
150
+ }
151
+ })
152
+ .as('payments.webhook');
153
+ }
154
+ }
155
+ //# sourceMappingURL=payments_provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payments_provider.js","sourceRoot":"","sources":["../../providers/payments_provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { BillingStore } from './billing_store.js';
2
+ /** One aggregate line of the billing overview. */
3
+ export interface BillingOverviewMetric {
4
+ key: string;
5
+ label: string;
6
+ value: number;
7
+ }
8
+ /** The dashboard's data contract: aggregate KPIs over a window. */
9
+ export interface BillingOverview {
10
+ period: {
11
+ from: Date;
12
+ to: Date;
13
+ };
14
+ metrics: BillingOverviewMetric[];
15
+ }
16
+ /**
17
+ * Compute a billing overview from the store — the data foundation a billing dashboard
18
+ * (Agora dashboard pattern) renders. Aggregates KPIs over a `from`/`to` window: revenue
19
+ * (sum of paid payments), active subscriptions, and usage per meter. Pure store queries
20
+ * (no gateway calls), so it works headless and is trivially testable.
21
+ */
22
+ export declare function billingOverview(store: BillingStore, options: {
23
+ from: Date;
24
+ to: Date;
25
+ }): Promise<BillingOverview>;
26
+ //# sourceMappingURL=billing_overview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing_overview.d.ts","sourceRoot":"","sources":["../../../src/billing/billing_overview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,kDAAkD;AAClD,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IACjC,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GAChC,OAAO,CAAC,eAAe,CAAC,CAqB1B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Compute a billing overview from the store — the data foundation a billing dashboard
3
+ * (Agora dashboard pattern) renders. Aggregates KPIs over a `from`/`to` window: revenue
4
+ * (sum of paid payments), active subscriptions, and usage per meter. Pure store queries
5
+ * (no gateway calls), so it works headless and is trivially testable.
6
+ */
7
+ export async function billingOverview(store, options) {
8
+ const { from, to } = options;
9
+ const [revenue, activeSubscriptions, usage] = await Promise.all([
10
+ store.revenue({ from, to }),
11
+ store.countActiveSubscriptions(),
12
+ store.usageReport({ from, to }),
13
+ ]);
14
+ const metrics = [
15
+ { key: 'revenue', label: 'Revenue (cents)', value: revenue },
16
+ { key: 'active_subscriptions', label: 'Active subscriptions', value: activeSubscriptions },
17
+ ];
18
+ for (const line of usage) {
19
+ metrics.push({
20
+ key: `meter:${line.meter}`,
21
+ label: `Usage · ${line.meter}`,
22
+ value: line.quantity,
23
+ });
24
+ }
25
+ return { period: { from, to }, metrics };
26
+ }
27
+ //# sourceMappingURL=billing_overview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing_overview.js","sourceRoot":"","sources":["../../../src/billing/billing_overview.ts"],"names":[],"mappings":"AAeA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,KAAmB,EACnB,OAAiC;IAEjC,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC9D,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAC3B,KAAK,CAAC,wBAAwB,EAAE;QAChC,KAAK,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;KAChC,CAAC,CAAC;IAEH,MAAM,OAAO,GAA4B;QACvC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE;QAC5D,EAAE,GAAG,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,mBAAmB,EAAE;KAC3F,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC;YACX,GAAG,EAAE,SAAS,IAAI,CAAC,KAAK,EAAE;YAC1B,KAAK,EAAE,WAAW,IAAI,CAAC,KAAK,EAAE;YAC9B,KAAK,EAAE,IAAI,CAAC,QAAQ;SACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,73 @@
1
+ import type { BillingPayment, BillingSubscription, BillingUsageEvent, BillingWebhookEvent } from './mixins/index.js';
2
+ /**
3
+ * The persistence SPI for the billing layer. The Lucid implementation writes through the
4
+ * configured models; an in-memory implementation exists in `src/testing` so the billing
5
+ * layer is unit-testable without a database.
6
+ *
7
+ * Generic over the row types so the in-memory store can use plain objects while the
8
+ * Lucid store returns model instances.
9
+ */
10
+ export interface BillingStore<SubscriptionRow = BillingSubscription, PaymentRow = BillingPayment, WebhookEventRow = BillingWebhookEvent, UsageEventRow = BillingUsageEvent> {
11
+ /** Upsert a subscription keyed by gateway id. Returns the stored row. */
12
+ saveSubscription(sub: {
13
+ gatewayId: string;
14
+ provider: string;
15
+ customerId: string;
16
+ status: string;
17
+ planId: string;
18
+ trialEndsAt?: Date | null;
19
+ endsAt?: Date | null;
20
+ payload?: Record<string, unknown>;
21
+ }): Promise<SubscriptionRow>;
22
+ findSubscriptionByGatewayId(gatewayId: string): Promise<SubscriptionRow | null>;
23
+ /** Upsert a payment keyed by gateway id. Returns the stored row. */
24
+ savePayment(payment: {
25
+ gatewayId: string;
26
+ provider: string;
27
+ status: string;
28
+ amount: number;
29
+ currency: string;
30
+ customerId?: string | null;
31
+ subscriptionId?: string | null;
32
+ paidAt?: Date | null;
33
+ payload?: Record<string, unknown>;
34
+ }): Promise<PaymentRow>;
35
+ findPaymentByGatewayId(gatewayId: string): Promise<PaymentRow | null>;
36
+ /** Record a webhook event for idempotency. Returns null when the event was already recorded. */
37
+ recordWebhookEvent(event: {
38
+ gatewayEventId: string;
39
+ provider: string;
40
+ type: string;
41
+ payload: Record<string, unknown>;
42
+ }): Promise<WebhookEventRow | null>;
43
+ markWebhookProcessed(id: string): Promise<void>;
44
+ markWebhookFailed(id: string, error: string): Promise<void>;
45
+ /** Record one metered-usage event (a metered subscription's consumption). */
46
+ recordUsage(event: {
47
+ subscriptionId?: string | null;
48
+ customerId?: string;
49
+ meter: string;
50
+ quantity: number;
51
+ metadata?: Record<string, unknown>;
52
+ recordedAt?: Date;
53
+ }): Promise<UsageEventRow>;
54
+ /** Aggregate metered usage by meter, filtered by subscription/customer/meter/window. */
55
+ usageReport(query: {
56
+ subscriptionId?: string;
57
+ customerId?: string;
58
+ meter?: string;
59
+ from?: Date;
60
+ to?: Date;
61
+ }): Promise<Array<{
62
+ meter: string;
63
+ quantity: number;
64
+ }>>;
65
+ /** Sum of paid payments within a window (revenue, in cents). */
66
+ revenue(query: {
67
+ from?: Date;
68
+ to?: Date;
69
+ }): Promise<number>;
70
+ /** Count of active subscriptions (status `'active'`/`'trialing'`). */
71
+ countActiveSubscriptions(): Promise<number>;
72
+ }
73
+ //# sourceMappingURL=billing_store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing_store.d.ts","sourceRoot":"","sources":["../../../src/billing/billing_store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY,CAC3B,eAAe,GAAG,mBAAmB,EACrC,UAAU,GAAG,cAAc,EAC3B,eAAe,GAAG,mBAAmB,EACrC,aAAa,GAAG,iBAAiB;IAIjC,yEAAyE;IACzE,gBAAgB,CAAC,GAAG,EAAE;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;QAC1B,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAE7B,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAIhF,oEAAoE;IACpE,WAAW,CAAC,OAAO,EAAE;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAExB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAItE,gGAAgG;IAChG,kBAAkB,CAAC,KAAK,EAAE;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClC,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAEpC,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAI5D,6EAA6E;IAC7E,WAAW,CAAC,KAAK,EAAE;QACjB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,UAAU,CAAC,EAAE,IAAI,CAAC;KACnB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE3B,wFAAwF;IACxF,WAAW,CAAC,KAAK,EAAE;QACjB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,IAAI,CAAC;QACZ,EAAE,CAAC,EAAE,IAAI,CAAC;KACX,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAExD,gEAAgE;IAChE,OAAO,CAAC,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5D,sEAAsE;IACtE,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=billing_store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing_store.js","sourceRoot":"","sources":["../../../src/billing/billing_store.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ export type { BillingStore } from './billing_store.js';
2
+ export { LucidBillingStore, lucidBillingStore } from './lucid_billing_store.js';
3
+ export type { BillingModels } from './lucid_billing_store.js';
4
+ export { withBillable } from './mixins/with_billable.js';
5
+ export { BillingSubscription, withSubscription } from './mixins/with_subscription.js';
6
+ export { BillingPayment, withPayment } from './mixins/with_payment.js';
7
+ export { BillingWebhookEvent } from './mixins/with_webhook_event.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/billing/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChF,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { LucidBillingStore, lucidBillingStore } from './lucid_billing_store.js';
2
+ export { withBillable } from './mixins/with_billable.js';
3
+ export { BillingSubscription, withSubscription } from './mixins/with_subscription.js';
4
+ export { BillingPayment, withPayment } from './mixins/with_payment.js';
5
+ export { BillingWebhookEvent } from './mixins/with_webhook_event.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/billing/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAEhF,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1,84 @@
1
+ import type { NormalizeConstructor } from '@adonisjs/core/types/helpers';
2
+ import type { BillingStore } from './billing_store.js';
3
+ import { BillingPayment as DefaultPayment, BillingSubscription as DefaultSubscription, BillingUsageEvent as DefaultUsageEvent, BillingWebhookEvent as DefaultWebhookEvent } from './mixins/index.js';
4
+ /**
5
+ * Models the billing layer persists through. Apps may override any of them with their own
6
+ * model composed from the corresponding mixin (authkit `lucidStores` pattern).
7
+ */
8
+ export interface BillingModels {
9
+ subscriptionModel?: NormalizeConstructor<typeof DefaultSubscription>;
10
+ paymentModel?: NormalizeConstructor<typeof DefaultPayment>;
11
+ webhookEventModel?: NormalizeConstructor<typeof DefaultWebhookEvent>;
12
+ usageEventModel?: NormalizeConstructor<typeof DefaultUsageEvent>;
13
+ }
14
+ type SubscriptionInstance = InstanceType<typeof DefaultSubscription>;
15
+ type PaymentInstance = InstanceType<typeof DefaultPayment>;
16
+ type WebhookEventInstance = InstanceType<typeof DefaultWebhookEvent>;
17
+ type UsageEventInstance = InstanceType<typeof DefaultUsageEvent>;
18
+ /**
19
+ * Lucid implementation of {@link BillingStore}. Resolves the models passed in (defaulting
20
+ * to the bundled ones) and writes through them, so custom models/composed mixins keep
21
+ * working with the same store.
22
+ */
23
+ export declare class LucidBillingStore implements BillingStore<SubscriptionInstance, PaymentInstance, WebhookEventInstance, UsageEventInstance> {
24
+ #private;
25
+ constructor(models?: BillingModels);
26
+ saveSubscription(sub: {
27
+ gatewayId: string;
28
+ provider: string;
29
+ customerId: string;
30
+ status: string;
31
+ planId: string;
32
+ trialEndsAt?: Date | null;
33
+ endsAt?: Date | null;
34
+ payload?: Record<string, unknown>;
35
+ }): Promise<SubscriptionInstance>;
36
+ findSubscriptionByGatewayId(gatewayId: string): Promise<SubscriptionInstance | null>;
37
+ savePayment(payment: {
38
+ gatewayId: string;
39
+ provider: string;
40
+ status: string;
41
+ amount: number;
42
+ currency: string;
43
+ customerId?: string | null;
44
+ subscriptionId?: string | null;
45
+ paidAt?: Date | null;
46
+ payload?: Record<string, unknown>;
47
+ }): Promise<PaymentInstance>;
48
+ findPaymentByGatewayId(gatewayId: string): Promise<PaymentInstance | null>;
49
+ recordWebhookEvent(event: {
50
+ gatewayEventId: string;
51
+ provider: string;
52
+ type: string;
53
+ payload: Record<string, unknown>;
54
+ }): Promise<WebhookEventInstance | null>;
55
+ markWebhookProcessed(id: string): Promise<void>;
56
+ markWebhookFailed(id: string, error: string): Promise<void>;
57
+ recordUsage(event: {
58
+ subscriptionId?: string | null;
59
+ customerId?: string;
60
+ meter: string;
61
+ quantity: number;
62
+ metadata?: Record<string, unknown>;
63
+ recordedAt?: Date;
64
+ }): Promise<UsageEventInstance>;
65
+ usageReport(query: {
66
+ subscriptionId?: string;
67
+ customerId?: string;
68
+ meter?: string;
69
+ from?: Date;
70
+ to?: Date;
71
+ }): Promise<Array<{
72
+ meter: string;
73
+ quantity: number;
74
+ }>>;
75
+ revenue(query: {
76
+ from?: Date;
77
+ to?: Date;
78
+ }): Promise<number>;
79
+ countActiveSubscriptions(): Promise<number>;
80
+ }
81
+ /** Builder matching the authkit `lucidStores(...)` convention. */
82
+ export declare function lucidBillingStore(models?: BillingModels): BillingStore;
83
+ export {};
84
+ //# sourceMappingURL=lucid_billing_store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucid_billing_store.d.ts","sourceRoot":"","sources":["../../../src/billing/lucid_billing_store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ import { DateTime } from 'luxon';
2
+ import { BillingPayment as DefaultPayment, BillingSubscription as DefaultSubscription, BillingUsageEvent as DefaultUsageEvent, BillingWebhookEvent as DefaultWebhookEvent, } from './mixins/index.js';
3
+ /**
4
+ * Lucid implementation of {@link BillingStore}. Resolves the models passed in (defaulting
5
+ * to the bundled ones) and writes through them, so custom models/composed mixins keep
6
+ * working with the same store.
7
+ */
8
+ export class LucidBillingStore {
9
+ #subscriptionModel;
10
+ #paymentModel;
11
+ #webhookEventModel;
12
+ #usageEventModel;
13
+ constructor(models = {}) {
14
+ this.#subscriptionModel = (models.subscriptionModel ??
15
+ DefaultSubscription);
16
+ this.#paymentModel = (models.paymentModel ?? DefaultPayment);
17
+ this.#webhookEventModel = (models.webhookEventModel ??
18
+ DefaultWebhookEvent);
19
+ this.#usageEventModel = (models.usageEventModel ??
20
+ DefaultUsageEvent);
21
+ }
22
+ async saveSubscription(sub) {
23
+ const existing = await this.findSubscriptionByGatewayId(sub.gatewayId);
24
+ const row = (existing ?? new this.#subscriptionModel());
25
+ row.gatewayId = sub.gatewayId;
26
+ row.provider = sub.provider;
27
+ row.customerId = sub.customerId;
28
+ row.status = sub.status;
29
+ row.planId = sub.planId;
30
+ row.trialEndsAt = sub.trialEndsAt ? DateTime.fromJSDate(sub.trialEndsAt) : null;
31
+ row.endsAt = sub.endsAt ? DateTime.fromJSDate(sub.endsAt) : null;
32
+ row.payload = sub.payload ?? {};
33
+ await row.save();
34
+ return row;
35
+ }
36
+ async findSubscriptionByGatewayId(gatewayId) {
37
+ const row = await this.#subscriptionModel.findBy('gateway_id', gatewayId);
38
+ return row;
39
+ }
40
+ async savePayment(payment) {
41
+ const existing = await this.findPaymentByGatewayId(payment.gatewayId);
42
+ const row = (existing ?? new this.#paymentModel());
43
+ row.gatewayId = payment.gatewayId;
44
+ row.provider = payment.provider;
45
+ row.status = payment.status;
46
+ row.amount = payment.amount;
47
+ row.currency = payment.currency;
48
+ row.customerId = payment.customerId ?? null;
49
+ row.subscriptionId = payment.subscriptionId ?? null;
50
+ row.paidAt = payment.paidAt ? DateTime.fromJSDate(payment.paidAt) : null;
51
+ row.payload = payment.payload ?? {};
52
+ await row.save();
53
+ return row;
54
+ }
55
+ async findPaymentByGatewayId(gatewayId) {
56
+ const row = await this.#paymentModel.findBy('gateway_id', gatewayId);
57
+ return row;
58
+ }
59
+ async recordWebhookEvent(event) {
60
+ const existing = await this.#webhookEventModel.findBy('gateway_event_id', event.gatewayEventId);
61
+ if (existing)
62
+ return null;
63
+ const row = new this.#webhookEventModel();
64
+ row.gatewayEventId = event.gatewayEventId;
65
+ row.provider = event.provider;
66
+ row.type = event.type;
67
+ row.status = 'received';
68
+ row.payload = event.payload;
69
+ row.error = null;
70
+ await row.save();
71
+ return row;
72
+ }
73
+ async markWebhookProcessed(id) {
74
+ const row = await this.#webhookEventModel.find(id);
75
+ if (row) {
76
+ row.status = 'processed';
77
+ await row.save();
78
+ }
79
+ }
80
+ async markWebhookFailed(id, error) {
81
+ const row = await this.#webhookEventModel.find(id);
82
+ if (row) {
83
+ row.status = 'failed';
84
+ row.error = error;
85
+ await row.save();
86
+ }
87
+ }
88
+ async recordUsage(event) {
89
+ const row = new this.#usageEventModel();
90
+ row.subscriptionId = event.subscriptionId ?? null;
91
+ row.customerId = event.customerId ?? null;
92
+ row.meter = event.meter;
93
+ row.quantity = event.quantity;
94
+ row.metadata = event.metadata ?? {};
95
+ row.recordedAt = event.recordedAt ? DateTime.fromJSDate(event.recordedAt) : DateTime.now();
96
+ await row.save();
97
+ return row;
98
+ }
99
+ async usageReport(query) {
100
+ const builder = this.#usageEventModel
101
+ .query()
102
+ .select('meter')
103
+ .sum('quantity as quantity')
104
+ .groupBy('meter');
105
+ if (query.subscriptionId !== undefined)
106
+ builder.where('subscription_id', query.subscriptionId);
107
+ else if (query.customerId !== undefined)
108
+ builder.where('customer_id', query.customerId);
109
+ if (query.meter !== undefined)
110
+ builder.where('meter', query.meter);
111
+ if (query.from !== undefined)
112
+ builder.where('recorded_at', '>=', query.from);
113
+ if (query.to !== undefined)
114
+ builder.where('recorded_at', '<', query.to);
115
+ const rows = await builder;
116
+ return rows.map((row) => ({
117
+ meter: row.meter,
118
+ quantity: Number(row.quantity),
119
+ }));
120
+ }
121
+ async revenue(query) {
122
+ const builder = this.#paymentModel.query().where('status', 'paid').sum('amount as total');
123
+ if (query.from !== undefined)
124
+ builder.where('paid_at', '>=', query.from);
125
+ if (query.to !== undefined)
126
+ builder.where('paid_at', '<', query.to);
127
+ const rows = await builder;
128
+ const total = rows[0]?.total;
129
+ return Number(total ?? 0);
130
+ }
131
+ async countActiveSubscriptions() {
132
+ const count = await this.#subscriptionModel
133
+ .query()
134
+ .whereIn('status', ['active', 'trialing'])
135
+ .count('* as total');
136
+ return Number(count[0]?.total ?? 0);
137
+ }
138
+ }
139
+ /** Builder matching the authkit `lucidStores(...)` convention. */
140
+ export function lucidBillingStore(models = {}) {
141
+ return new LucidBillingStore(models);
142
+ }
143
+ //# sourceMappingURL=lucid_billing_store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucid_billing_store.js","sourceRoot":"","sources":["../../../src/billing/lucid_billing_store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { BillingStore } from './billing_store.js';
2
+ /** The per-meter rate and included allowance for a metered plan. */
3
+ export interface MeterRate {
4
+ /** The meter name, e.g. `'api_calls'`. */
5
+ meter: string;
6
+ /** Price per unit of the meter, in currency smallest unit (e.g. cents). */
7
+ rate: number;
8
+ /** Units included free of charge per billing period. Defaults to 0. */
9
+ included?: number;
10
+ }
11
+ /** One metered bill line — how much of a meter was consumed and what it costs. */
12
+ export interface MeteredBillLine {
13
+ meter: string;
14
+ quantity: number;
15
+ /** Quantity beyond the plan's included allowance. */
16
+ billable: number;
17
+ /** `billable × rate`, in cents. */
18
+ amount: number;
19
+ }
20
+ /** The result of pricing a period's metered usage. */
21
+ export interface MeteredBill {
22
+ lines: MeteredBillLine[];
23
+ /** Sum of all line amounts, in cents. */
24
+ total: number;
25
+ }
26
+ /**
27
+ * Price a period's metered usage against per-meter rates — the "how much do I bill for
28
+ * what was consumed" step of a metered subscription. Pure: feed it a
29
+ * {@link BillingStore.usageReport} result and the plan's {@link MeterRate}s.
30
+ *
31
+ * ```ts
32
+ * const usage = await store.usageReport({ subscriptionId: sub.id, from, to })
33
+ * const bill = meteredBill(usage, [
34
+ * { meter: 'api_calls', rate: 0.5, included: 1000 },
35
+ * { meter: 'storage_gb', rate: 200 },
36
+ * ])
37
+ * bill.total // cents to charge for overage
38
+ * ```
39
+ */
40
+ export declare function meteredBill(usage: Array<{
41
+ meter: string;
42
+ quantity: number;
43
+ }>, rates: MeterRate[]): MeteredBill;
44
+ /**
45
+ * Convenience: run a subscription's metered usage for a window through
46
+ * {@link meteredBill}. Fetches the usage from the store, prices it with `rates`, and
47
+ * returns the bill (plus the raw usage for reference).
48
+ */
49
+ export declare function meteredBillForSubscription(store: BillingStore, input: {
50
+ subscriptionId: string;
51
+ from: Date;
52
+ to: Date;
53
+ rates: MeterRate[];
54
+ }): Promise<MeteredBill & {
55
+ usage: Array<{
56
+ meter: string;
57
+ quantity: number;
58
+ }>;
59
+ }>;
60
+ //# sourceMappingURL=metered_bill.d.ts.map