@ambushsoftworks/nestjs-payments-graphql 0.8.0 → 0.10.0-rc.2

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 (38) hide show
  1. package/CHANGELOG.md +170 -0
  2. package/README.md +142 -2
  3. package/dist/constants.d.ts +2 -0
  4. package/dist/constants.js +3 -1
  5. package/dist/constants.js.map +1 -1
  6. package/dist/exceptions/index.d.ts +3 -0
  7. package/dist/exceptions/index.js +7 -1
  8. package/dist/exceptions/index.js.map +1 -1
  9. package/dist/gateways/payment-gateway.interface.d.ts +4 -0
  10. package/dist/gateways/recurring-payment-gateway.interface.d.ts +14 -0
  11. package/dist/gateways/stripe/stripe-webhook.controller.d.ts +5 -3
  12. package/dist/gateways/stripe/stripe-webhook.controller.js +43 -21
  13. package/dist/gateways/stripe/stripe-webhook.controller.js.map +1 -1
  14. package/dist/gateways/stripe/stripe.gateway.d.ts +21 -0
  15. package/dist/gateways/stripe/stripe.gateway.js +140 -9
  16. package/dist/gateways/stripe/stripe.gateway.js.map +1 -1
  17. package/dist/gateways/stripe/types.d.ts +1 -0
  18. package/dist/gateways/stripe/types.js +2 -1
  19. package/dist/gateways/stripe/types.js.map +1 -1
  20. package/dist/index.d.ts +4 -3
  21. package/dist/index.js +7 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/interfaces/payment-event-listener.interface.d.ts +2 -0
  24. package/dist/interfaces/payment-method-policy.interface.d.ts +11 -0
  25. package/dist/interfaces/payment-method-policy.interface.js +3 -0
  26. package/dist/interfaces/payment-method-policy.interface.js.map +1 -0
  27. package/dist/payments.module.d.ts +3 -0
  28. package/dist/payments.module.js +10 -0
  29. package/dist/payments.module.js.map +1 -1
  30. package/dist/services/customer.service.d.ts +3 -1
  31. package/dist/services/customer.service.js +2 -1
  32. package/dist/services/customer.service.js.map +1 -1
  33. package/dist/services/payment-method.service.d.ts +19 -2
  34. package/dist/services/payment-method.service.js +151 -12
  35. package/dist/services/payment-method.service.js.map +1 -1
  36. package/dist/services/payment.service.js +19 -3
  37. package/dist/services/payment.service.js.map +1 -1
  38. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -28,6 +28,176 @@ prose for buried obligations. The marker was introduced in v0.4.0 and
28
28
 
29
29
  ## [Unreleased]
30
30
 
31
+ ## [0.10.0] - 2026-09-29
32
+
33
+ > **Upgrade note.** `PaymentMethodService` takes `ModuleRef` as a third
34
+ > constructor argument. It is optional, so a consumer constructing the service
35
+ > by hand — in tests, mostly — still compiles and behaves exactly as before;
36
+ > without it no policy is resolved. Pass it if you want the policy honoured in a
37
+ > hand-built container. Nothing else changes for an existing consumer, and
38
+ > **absent a registered policy every path behaves exactly as it did in 0.9.0.**
39
+
40
+ 0.9.0 let a session say whether the card it kept should become the customer's
41
+ default. This closes the class that switch guards case by case: **the package
42
+ now asks before every default it writes, on every path, including ones not
43
+ written yet.**
44
+
45
+ ### Added
46
+ - **`IPaymentMethodPolicy`**, with the `PAYMENT_METHOD_POLICY` token and the
47
+ `paymentMethodPolicyInstance` module option. `mayBecomeDefault` is asked
48
+ before the provider is called, with the `trigger` that caused the write —
49
+ `explicit`, `setup` or `payment` — so a consumer can answer differently by
50
+ origin.
51
+
52
+ It exists because the knowledge and the write live in different places. A
53
+ consumer holding cards belonging to third parties knows which card is whose
54
+ and had already written guards on its own mutations; the package writes the
55
+ default inside webhook handling, where those guards never run. Rather than
56
+ teach the package what a third party is, it asks.
57
+
58
+ - **`PaymentMethodDefaultRefusedException`** (`PAYMENT_METHOD_DEFAULT_REFUSED`),
59
+ thrown when a policy refuses an `explicit` request. Someone clicked a button
60
+ and is waiting; a silent no-op reads as success while the card does not stick.
61
+ The automatic paths log and leave the default alone instead — they run inside
62
+ a webhook, where throwing answers 500 and the provider redelivers for days.
63
+
64
+ - **`paymentMethodPolicyTimeoutMs`** (default `5000`) and the
65
+ `PAYMENT_METHOD_POLICY_TIMEOUT` token.
66
+
67
+ - **`resolveSetupPaymentMethod` on `RecurringPaymentGateway`** (optional):
68
+ reports the card a completed setup session collected, and whether the session
69
+ asked for it to be adopted, **without writing anything**. A setup session only
70
+ reveals its card on completion, so `adoptSetupPaymentMethod` resolved and
71
+ adopted in one call and left no point at which a policy could be consulted.
72
+ That method now builds on this one, so there is a single reading of the
73
+ session's answer.
74
+
75
+ ### Changed
76
+ - **A policy that throws, rejects or times out is treated as a refusal**, logged
77
+ at error level. This is the opposite of every other consumer hook in the
78
+ package — a branding resolver or a charge-options resolver that fails lets the
79
+ payment proceed, because the cost of proceeding is cosmetic. The cost of
80
+ proceeding here is charging the wrong person. **Fail open for cosmetic, fail
81
+ closed for authority.**
82
+
83
+ The timeout is the only one in the package, and the inconsistency is
84
+ deliberate: everywhere else the safe answer to an unanswerable question is
85
+ "proceed", so a timeout could only cause harm.
86
+
87
+ - **A gateway that cannot be gated refuses rather than proceeds.** With a policy
88
+ registered, a setup-session adoption on a gateway without
89
+ `resolveSetupPaymentMethod` is refused and logged with what to implement.
90
+ Without a policy, the legacy path is used unchanged.
91
+
92
+ ### Fixed
93
+ - **`PaidInvoiceEvent`'s card ids depended on which webhook won a race.** A
94
+ Checkout payment fires `checkout.session.completed` and
95
+ `payment_intent.succeeded` in no guaranteed order; whichever applies the
96
+ payment builds the event, and the other is short-circuited as already
97
+ applied. The ids rode only on the session path, so a listener pinning a card
98
+ to the person it belongs to got nothing whenever the intent event landed
99
+ first — and the card stayed on the payer, attached to nobody.
100
+
101
+ Both paths now carry `customerId` and `savedPaymentMethodId`, under the same
102
+ `off_session` rule and with no extra provider call. Adoption still happens
103
+ once, because it keys off `adoptSavedPaymentMethod`, which only the session
104
+ completion sets. Until now the fire-once guard was the *absence* of those ids
105
+ on the intent path, which is precisely what broke them. Reported against
106
+ `0.10.0-rc.1`.
107
+
108
+ ### Docs
109
+ - New **Deciding which cards may become the default**, answering the question
110
+ **What "ownership" means** (v0.9.0) ends on: ownership means only that a card
111
+ is attached to that provider customer, and this is how you tell the package
112
+ which of those cards are not the payer's own.
113
+ - `payment-method-policy-gate.spec.ts` fails the build if a new default-writing
114
+ call site skips the gate — the guarantee that makes a hook better than a
115
+ per-path switch, and the reason it is worth having at all.
116
+
117
+ ## [0.9.0] - 2026-09-29
118
+
119
+ > **Not published separately — released as part of `0.10.0`.** Verifying this
120
+ > release on its own would have verified code `0.10.0` replaces: the setup-card
121
+ > path documented below was rewired a day later so a policy could be consulted
122
+ > before anything is written. The two were verified together instead. Pin
123
+ > `0.10.0`; everything here is in it.
124
+
125
+ A card kept while paying is now usable, and **the caller decides whether it
126
+ becomes the card everything else gets charged**. That second half is the
127
+ release: the first draft of this work adopted automatically, which is wrong for
128
+ any customer who pays on behalf of others, and the reporting consumer caught it
129
+ on production before we shipped.
130
+
131
+ ### Added
132
+ - **`savePaymentMethod` on `createPaymentSession`** — `{ providerCustomerId,
133
+ adoptAsDefault? }`. One object, so asking to keep a card without naming a
134
+ customer to attach it to cannot be expressed; that combination left a
135
+ consumer's card on a provider-invented customer nothing in their database
136
+ pointed at. For Stripe it becomes `customer` plus
137
+ `payment_intent_data.setup_future_usage: 'off_session'`.
138
+
139
+ `customer` and `setup_future_usage` remain **unreserved**, so passthrough code
140
+ written before this is unaffected. Only a contradiction is refused — a
141
+ different customer, or `on_session` alongside `savePaymentMethod` — on the
142
+ same precedent as `paymentIntentData.metadata.invoiceId`.
143
+
144
+ - **`adoptAsDefault` on `createSetupSession`** and
145
+ `CustomerService.createSetupSession(..., { adoptAsDefault })`, **defaulting to
146
+ `true`** — what that path has always done. Pass `false` when collecting a card
147
+ for somebody the customer pays on behalf of.
148
+
149
+ - **`adoptPaymentMethod` on `RecurringPaymentGateway`** (optional), for a card
150
+ whose id is already resolved. `adoptSetupPaymentMethod` now delegates to the
151
+ same private tail, so "default only when the customer has none" exists once.
152
+
153
+ - **`customerId` in `providerData`** on payment-mode Checkout completions, and
154
+ **`providerCustomerId` / `paymentMethodId` on `PaidInvoiceEvent`** — both
155
+ nullable and "when present". A listener receives the event, not the normalised
156
+ webhook, so these ids were previously unreachable without re-reading the
157
+ payment and calling the provider.
158
+
159
+ - **`STRIPE_ADOPT_AS_DEFAULT_METADATA_KEY`**, the metadata key carrying the
160
+ adoption decision from session creation to the webhook that acts on it.
161
+
162
+ ### Changed
163
+ - **Adoption is opt-in for payments, and silence means no.** A card kept during
164
+ a payment becomes the default only when the session asked for it.
165
+
166
+ A customer who pays on behalf of others is one provider customer holding
167
+ several people's cards, and the default is what everyone *without* their own
168
+ card is charged. Adopting automatically makes one third party's card the payer
169
+ for all the rest, invisibly to the cardholder. A recruiting agency with 53
170
+ client companies hit exactly this: one client's card became the account
171
+ default and was on course to pay for the other 52. Nothing was charged.
172
+
173
+ - **Only an `off_session` mandate is adopted.** A card kept `on_session` is
174
+ attached and logged and never becomes the off-session default: that consent is
175
+ for charges the customer is present for, and spending it on a renewal produces
176
+ an authentication-required decline nobody is there to answer.
177
+
178
+ - **Adoption runs only for a settled payment**, after the payment is recorded,
179
+ and can never fail the webhook. A throw would answer 500 and the provider
180
+ would redeliver for about three days, re-running the payment handler each
181
+ time. Failures are reported through `webhook.errorReporter` instead of being
182
+ swallowed silently, as they were before.
183
+
184
+ ### Fixed
185
+ - **The webhook never wrote `PaymentCustomer.defaultPaymentMethodId`.** Only
186
+ `PaymentMethodService` mirrored it, and the webhook called the gateway
187
+ directly — so a card saved through the *documented* setup flow set the
188
+ provider's default and left the mirrored column null, making this README's
189
+ promise that you can render the current card without a provider round trip
190
+ untrue for the main path. Both adoption paths now go through
191
+ `PaymentMethodService` and mirror what they set. Found while verifying a
192
+ consumer's report, not reported.
193
+
194
+ ### Docs
195
+ - New **Saving a card while paying**, **Choosing whether a saved card becomes
196
+ the default**, and **What "ownership" means** sections. The last one says
197
+ plainly that ownership means "attached to this provider customer" and nothing
198
+ more, which is weaker than the word suggests and matters to anyone building a
199
+ card picker on `listPaymentMethods`.
200
+
31
201
  ## [0.8.0] - 2026-09-28
32
202
 
33
203
  Off-session charges can finally say **which brand is charging**. A consumer
package/README.md CHANGED
@@ -24,6 +24,10 @@ Production-grade payments module for NestJS with GraphQL support. Invoicing (inc
24
24
  - [Pinning a schedule to one card](#pinning-a-schedule-to-one-card)
25
25
  - [Per-charge gateway options for renewals](#per-charge-gateway-options-for-renewals)
26
26
  - [Saved Cards](#saved-cards)
27
+ - [What "ownership" means](#what-ownership-means)
28
+ - [Deciding which cards may become the default](#deciding-which-cards-may-become-the-default)
29
+ - [Saving a card while paying](#saving-a-card-while-paying)
30
+ - [Choosing whether a saved card becomes the default](#choosing-whether-a-saved-card-becomes-the-default)
27
31
  - [Managing saved cards](#managing-saved-cards)
28
32
  - [Stripe-specific off-session options](#stripe-specific-off-session-options-gatewayoptions)
29
33
  - [E-Transfer](#e-transfer)
@@ -1062,7 +1066,136 @@ const { setupUrl, providerSetupId } = await customerService.createSetupSession(
1062
1066
 
1063
1067
  **Completing the setup is a webhook, not a redirect.** Your success URL fires in the customer's browser; the card is not usable until `checkout.session.completed` arrives and the package records it. Do not tell the client their card is saved based on the redirect alone.
1064
1068
 
1065
- **Which card gets charged.** The provider is the source of truth — for Stripe, `invoice_settings.default_payment_method`. `PaymentCustomer.defaultPaymentMethodId` mirrors it so you can render the current card without a provider round trip, but the package never consults that column to decide what to charge. One authority is what stops the two disagreeing. On the completion webhook the collected card becomes the default **only when the customer has none**, so a client adding a second card does not silently change what gets billed.
1069
+ **Which card gets charged.** The provider is the source of truth — for Stripe, `invoice_settings.default_payment_method`. `PaymentCustomer.defaultPaymentMethodId` mirrors it so you can render the current card without a provider round trip, but the package never consults that column to decide what to charge. One authority is what stops the two disagreeing. A collected card becomes the default **only when the customer has none**, so a client adding a second card does not silently change what gets billed.
1070
+
1071
+ > **The mirror was not written on the webhook path before v0.9.0.** Only `PaymentMethodService` ever updated `defaultPaymentMethodId`, and the webhook called the gateway directly — so a card saved through the ordinary setup flow set the provider's default and left the column null. If you have been rendering from that column, it has been blank for cards saved that way; it is maintained from v0.9.0 on, and a `confirmSetup` call or any card-management write refreshes it for existing rows.
1072
+
1073
+ #### What "ownership" means
1074
+
1075
+ `ownsPaymentMethod`, `assertOwned` and every method taking a `paymentMethodId` mean one thing by ownership: **the card is attached to that client's provider customer.** Nothing more.
1076
+
1077
+ That is worth stating plainly, because a provider customer can end up holding cards that are not the payer's own. Anything paid with `savePaymentMethod` attaches, and so does any card saved through a setup session — so a customer who pays on behalf of others accumulates their cards in one wallet, and the package cannot tell them apart.
1078
+
1079
+ The consequences are yours to manage:
1080
+
1081
+ - `listPaymentMethods` returns **every** attached card, so a picker built straight onto it will offer a third party's card for somebody else's purchase.
1082
+ - `setDefaultPaymentMethod` accepts any attached card, because by this definition the client owns it.
1083
+
1084
+ What the package guarantees is narrower and worth having: it never *chooses* a card. Adoption is opt-in per session (below), an existing default is never overridden, and `createOffSessionPayment` refuses rather than falling back to whatever is on file. The package still does not know *which* cards are not the payer's own — but as of v0.10.0 you can tell it, per decision, with a policy: see [Deciding which cards may become the default](#deciding-which-cards-may-become-the-default).
1085
+
1086
+
1087
+
1088
+ #### Deciding which cards may become the default
1089
+
1090
+ *Added in v0.10.0.*
1091
+
1092
+ The section above ends by saying the package cannot tell a third party's card from the payer's own. This is how you tell it.
1093
+
1094
+ ```typescript
1095
+ import type { IPaymentMethodPolicy } from '@ambushsoftworks/nestjs-payments-graphql';
1096
+
1097
+ class WalletPolicy implements IPaymentMethodPolicy {
1098
+ constructor(private readonly cards: CardOwnershipService) {}
1099
+
1100
+ async mayBecomeDefault({ clientDetailsId, paymentMethodId, trigger }) {
1101
+ // An account that pays for other people never gets an automatic default.
1102
+ if (trigger !== 'explicit') {
1103
+ return !(await this.cards.paysOnBehalfOfOthers(clientDetailsId));
1104
+ }
1105
+ // A deliberate click is allowed, unless the card is somebody else's.
1106
+ return !(await this.cards.belongsToThirdParty(paymentMethodId));
1107
+ }
1108
+ }
1109
+
1110
+ // In forRootAsync's useFactory:
1111
+ paymentMethodPolicyInstance: new WalletPolicy(cards),
1112
+ ```
1113
+
1114
+ **It is asked at the only two places the package writes a default**, before the provider is called — so a refusal costs no network request. `trigger` says what caused the write:
1115
+
1116
+ | Trigger | Cause | A refusal |
1117
+ |---|---|---|
1118
+ | `explicit` | `setDefaultPaymentMethod` — a person chose this card | **throws** `PaymentMethodDefaultRefusedException` |
1119
+ | `setup` | a setup session completed, via the webhook or `confirmSetup` | logs, leaves the default alone |
1120
+ | `payment` | a buyer kept a card while paying and the session asked to adopt it | logs, leaves the default alone |
1121
+
1122
+ The explicit path throws because somebody is waiting for an answer, and a silent no-op reads as success while the card quietly does not stick. The automatic paths do not, because they run inside a webhook: throwing there answers 500 and Stripe redelivers for about three days.
1123
+
1124
+ In every case the card stays attached and chargeable by id. Only the default is untouched.
1125
+
1126
+ **A policy that fails is a refusal.** If `mayBecomeDefault` throws, rejects, or takes longer than `paymentMethodPolicyTimeoutMs` (default 5000), the package logs at error level and treats the answer as `false`.
1127
+
1128
+ > This is the opposite of every other consumer hook here, and deliberately so. A branding resolver that fails lets the payment go through, because the cost of proceeding is a missing brand name on a statement. The cost of proceeding *here* is charging the wrong person's card; the cost of refusing is a customer with no default and a loud `no_payment_method` on their next renewal. **Fail open for cosmetic, fail closed for authority.** It is also the only timeout in the package — everywhere else a slow callback is left to finish, because there the safe answer is "proceed" and a timeout could only cause harm.
1129
+
1130
+ **Why a hook and not a flag on each path.** [Saving a card while paying](#saving-a-card-while-paying) already lets a session say whether its card should be adopted, and that stays — it is the first line, and it is the right place to answer when you know at checkout time. The policy is the backstop: it guards the *two functions* rather than the paths anyone thought to list, so a path added in a later version inherits it. A spec fails the build if a new default-writing call site skips the gate.
1131
+
1132
+ Use both. A session flag cannot help when the decision depends on something you only learn from the webhook that triggers the adoption.
1133
+
1134
+ > **This governs the default, and only the default.** A policy decides what
1135
+ > gets charged when nothing else is specified — it does not decide which cards
1136
+ > Stripe's **hosted Checkout page offers back to the payer**. That page selects
1137
+ > saved cards by the provider's own `allow_redisplay` marking, not by the
1138
+ > default, and a card collected through a setup-mode Checkout session is marked
1139
+ > redisplayable. So a customer who holds a third party's card can still be shown
1140
+ > it, pre-selected, on a hosted page for a different purchase. The package does
1141
+ > not yet control that marking; if it matters to you, keep the payer's saved
1142
+ > cards off sessions where they should not appear, and say so — we have an open
1143
+ > design request for it.
1144
+
1145
+ **Your gateway needs `resolveSetupPaymentMethod`** if you wrote your own and you register a policy. A setup session only reveals its card when it completes, so the package has to be able to ask what was collected before anything is written. Without it a setup-session adoption is **refused** rather than performed ungated, and the refusal is logged with what to implement. The bundled Stripe gateway has it.
1146
+
1147
+ #### Saving a card while paying
1148
+
1149
+ *Added in v0.9.0.*
1150
+
1151
+ A buyer paying through hosted Checkout can keep the card for later. Pass `savePaymentMethod` and the gateway attaches it to the customer you name:
1152
+
1153
+ ```typescript
1154
+ const customer = await customerService.createOrLinkCustomer(
1155
+ divisionId, clientDetailsId, email, name,
1156
+ );
1157
+
1158
+ await gateway.createPaymentSession({
1159
+ invoiceId, amount, currency: 'CAD', successUrl, cancelUrl,
1160
+ savePaymentMethod: {
1161
+ providerCustomerId: customer.providerCustomerId,
1162
+ adoptAsDefault: true, // see below — defaults to false
1163
+ },
1164
+ });
1165
+ ```
1166
+
1167
+ **One object, not a flag and a customer id.** A card needs a customer to attach to; without one the provider either refuses or invents a customer nothing in your database points at, and the card is lost with no error anywhere. A consumer hit exactly that and spent a day on it. This shape makes it unrepresentable.
1168
+
1169
+ **`adoptAsDefault` decides whether it becomes the card auto-renew uses, and it defaults to `false`.**
1170
+
1171
+ | `adoptAsDefault` | customer has no default | customer has a default |
1172
+ |---|---|---|
1173
+ | `true` | the saved card becomes the default | unchanged — never overridden |
1174
+ | `false` or absent | unchanged: still no default | unchanged |
1175
+
1176
+ The card is attached in every row, and chargeable by id via `createOffSessionPayment`'s `paymentMethodId`. Only the default differs.
1177
+
1178
+ > **Why silence means no.** Keeping a card and choosing what everything *else* gets charged are different decisions, and only you know whether the payer owns the card they just typed. A customer who pays on behalf of others — an agency, a parent company, a bookkeeper — is one provider customer holding several people's cards, and the default is what everyone *without* their own card is charged. A consumer hit this on production: a recruiting agency with 53 client companies paid for one client's posting, that client's card became the account default, and it was on course to pay for the other 52. Nothing was charged; they caught it within the hour. Pass `true` when the payer is buying for themselves, and leave it out when they are not.
1179
+
1180
+ The card id reaches your listener on `PaidInvoiceEvent` as `paymentMethodId`, with `providerCustomerId` beside it, so you can file it against whoever it belongs to without a provider round trip.
1181
+
1182
+ **Only `off_session` counts.** The package adopts a card only when the mandate says the customer will not be present for future charges. A card kept `on_session` is attached and logged, and never becomes the off-session default — that consent is for charges the customer is there for, and using it for a renewal is how you get an authentication-required decline at 02:00.
1183
+
1184
+ **Equivalent through `gatewayOptions`.** `customer` and `setup_future_usage` are not reserved, so code written before v0.9.0 keeps working. What is refused is a *contradiction* — naming a different customer, or asking for `on_session` alongside `savePaymentMethod` — because resolving it either way would be a guess. The package writes its decision into the PaymentIntent's metadata under `adoptAsDefault` (exported as `STRIPE_ADOPT_AS_DEFAULT_METADATA_KEY`); keep that key out of your own metadata.
1185
+
1186
+ #### Choosing whether a saved card becomes the default
1187
+
1188
+ The same choice applies to setup sessions, where it **defaults to `true`** — that is what `createSetupSession` has always done, so nothing changes for existing consumers:
1189
+
1190
+ ```typescript
1191
+ await customerService.createSetupSession(
1192
+ divisionId, clientDetailsId, email, name, successUrl, cancelUrl,
1193
+ 'stripe', undefined,
1194
+ { adoptAsDefault: false }, // a card you are collecting for a third party
1195
+ );
1196
+ ```
1197
+
1198
+ **The answer travels with the session.** Adoption happens in two places that cannot see each other — the `checkout.session.completed` webhook, and `confirmSetup` when you confirm on the redirect — and either may land first. The package writes the decision onto the SetupIntent at session creation, so both read the same answer and `confirmSetup` needs no extra argument. Clearing a default yourself afterwards does not work: the webhook can land after your clear and set it again.
1066
1199
 
1067
1200
  #### Managing saved cards
1068
1201
 
@@ -1137,7 +1270,7 @@ Declare `@@unique([clientDetailsId, provider])` on `PaymentCustomer` to match, a
1137
1270
 
1138
1271
  **Keep the `divisionId` column** even though you no longer key on it. The bundled adapter still writes it on create and `assertPaymentsSchema` still requires it, so dropping it because "we do not scope by division" fails at boot — or on the first card save if you skip the schema assertion. It stays useful as a record of which division first created the customer.
1139
1272
 
1140
- A custom gateway must implement `adoptSetupPaymentMethod` to support saved cards. It is optional on `RecurringPaymentGateway` so v0.2.x gateways still compile; without it the webhook logs a warning and the card stays unusable for auto-charge.
1273
+ A custom gateway must implement `adoptSetupPaymentMethod` to support saved cards, `adoptPaymentMethod` (v0.9.0) to support a card kept while paying, and `resolveSetupPaymentMethod` (v0.10.0) so a setup session's card can be reported before it is adopted — the second takes a payment method id the gateway has already resolved, rather than a setup intent. Both are optional on `RecurringPaymentGateway` so older gateways still compile; without them the webhook logs a warning and the card stays unusable for auto-charge. Implement them over one shared code path: "default only when the customer has none, never override" stops being true the moment there are two copies of it.
1141
1274
 
1142
1275
  #### Stripe-specific off-session options (`gatewayOptions`)
1143
1276
 
@@ -1250,6 +1383,8 @@ paymentEventListenerInstance: {
1250
1383
 
1251
1384
  Event payloads include `metadata` from the invoice plus the full `lineItems` snapshot so consumers don't need to re-query.
1252
1385
 
1386
+ `PaidInvoiceEvent` also carries `providerCustomerId` and `paymentMethodId` (v0.9.0), so a listener can act on a card the payment kept — filing it against the party it belongs to, for instance — without re-reading the payment and calling the provider. Both are **nullable and "when present", not a guarantee**: five paths fire `onInvoicePaid`, and a manually recorded payment or an e-transfer confirmation has no card at all. The recurring auto-charge path knows the card but does not yet pass it here.
1387
+
1253
1388
  ### Transactions
1254
1389
 
1255
1390
  `ITransactionManager.runInTransaction(fn)` gives the callback a `TransactionRepositories` bag with all repositories bound to the same ORM transaction. The package uses this internally when recording payments and mutating totals.
@@ -1523,6 +1658,8 @@ Two database constraints are load-bearing wherever you are coming from, because
1523
1658
  |--------|------|-------------|
1524
1659
  | `paymentEventListenerInstance` | `IPaymentEventListener` | Domain callbacks — see [Event Listeners](#event-listeners). Only `onInvoicePaid` is required. |
1525
1660
  | `recurringChargeOptionsResolverInstance` | `IRecurringChargeOptionsResolver` | Supplies `gatewayOptions` for each renewal charge — see [Per-charge gateway options for renewals](#per-charge-gateway-options-for-renewals). Absent, renewals charge as before; a resolver that throws degrades to charging without options rather than failing the renewal. |
1661
+ | `paymentMethodPolicyInstance` | `IPaymentMethodPolicy` | Decides whether a card may become a customer's default — see [Deciding which cards may become the default](#deciding-which-cards-may-become-the-default). Absent, every path behaves as before. A policy that throws, rejects or times out is treated as a **refusal**. |
1662
+ | `paymentMethodPolicyTimeoutMs` | `number` | How long `mayBecomeDefault` may take before the answer is treated as a refusal. Default `5000`. The only timeout in the package. |
1526
1663
  | `webhook` | `{ errorReporter? }` | `webhook.errorReporter` is called with anything a webhook handler throws. Route it somewhere you will see it: since v0.5.0 a failed handler answers 500 and Stripe retries for ~3 days. |
1527
1664
  | `tax` | `{ requireExplicit? }` | See [Tax](#tax). Set `tax.requireExplicit` if you bill in more than one jurisdiction. |
1528
1665
  | `features` | see below | Feature flags. Enabling one without its backing repository throws at boot. |
@@ -1600,6 +1737,8 @@ import {
1600
1737
  TRANSACTION_MANAGER,
1601
1738
  PAYMENT_EVENT_LISTENER,
1602
1739
  RECURRING_CHARGE_OPTIONS_RESOLVER,
1740
+ PAYMENT_METHOD_POLICY,
1741
+ PAYMENT_METHOD_POLICY_TIMEOUT,
1603
1742
  PAYMENT_EMAIL_SENDER,
1604
1743
  PAYMENT_CLIENT_RESOLVER,
1605
1744
  PAYMENT_EMAIL_BRANDING_RESOLVER,
@@ -1648,6 +1787,7 @@ All exceptions extend `PaymentException` (a plain `Error` subclass) with a stabl
1648
1787
  | `PaymentIntentOperationNotSupportedException` | `PAYMENT_INTENT_OPERATION_NOT_SUPPORTED` |
1649
1788
  | `InvalidTaxConfigurationException` | `INVALID_TAX_CONFIGURATION` |
1650
1789
  | `PaymentMethodNotOwnedException` | `PAYMENT_METHOD_NOT_OWNED` |
1790
+ | `PaymentMethodDefaultRefusedException` | `PAYMENT_METHOD_DEFAULT_REFUSED` |
1651
1791
  | `PaymentMethodOperationNotSupportedException` | `PAYMENT_METHOD_OPERATION_NOT_SUPPORTED` |
1652
1792
  | `NoChargeablePaymentMethodException` | `NO_CHARGEABLE_PAYMENT_METHOD` |
1653
1793
 
@@ -9,6 +9,8 @@ export declare const PAYMENT_EVENT_LISTENER: unique symbol;
9
9
  export declare const RECURRING_INVOICE_REPOSITORY: unique symbol;
10
10
  export declare const PAYMENT_CUSTOMER_REPOSITORY: unique symbol;
11
11
  export declare const RECURRING_CHARGE_OPTIONS_RESOLVER: unique symbol;
12
+ export declare const PAYMENT_METHOD_POLICY: unique symbol;
13
+ export declare const PAYMENT_METHOD_POLICY_TIMEOUT: unique symbol;
12
14
  export declare const PAYMENT_EMAIL_SENDER: unique symbol;
13
15
  export declare const PAYMENT_CLIENT_RESOLVER: unique symbol;
14
16
  export declare const PAYMENT_EMAIL_BRANDING_RESOLVER: unique symbol;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PAYMENT_SERVICE = exports.TAX_OPTIONS = exports.E_TRANSFER_CODE_PREFIX = exports.DEFAULT_CURRENCY = exports.WEBHOOK_ERROR_REPORTER = exports.PAYMENT_EMAIL_TEMPLATE_RENDERER = exports.PAYMENT_EMAIL_BRANDING_RESOLVER = exports.PAYMENT_CLIENT_RESOLVER = exports.PAYMENT_EMAIL_SENDER = exports.RECURRING_CHARGE_OPTIONS_RESOLVER = exports.PAYMENT_CUSTOMER_REPOSITORY = exports.RECURRING_INVOICE_REPOSITORY = exports.PAYMENT_EVENT_LISTENER = exports.TRANSACTION_MANAGER = exports.WEBHOOK_IDEMPOTENCY_REPOSITORY = exports.PAYMENT_CONFIG_REPOSITORY = exports.PAYMENT_PLAN_REPOSITORY = exports.REFUND_REPOSITORY = exports.PAYMENT_REPOSITORY = exports.INVOICE_REPOSITORY = void 0;
3
+ exports.PAYMENT_SERVICE = exports.TAX_OPTIONS = exports.E_TRANSFER_CODE_PREFIX = exports.DEFAULT_CURRENCY = exports.WEBHOOK_ERROR_REPORTER = exports.PAYMENT_EMAIL_TEMPLATE_RENDERER = exports.PAYMENT_EMAIL_BRANDING_RESOLVER = exports.PAYMENT_CLIENT_RESOLVER = exports.PAYMENT_EMAIL_SENDER = exports.PAYMENT_METHOD_POLICY_TIMEOUT = exports.PAYMENT_METHOD_POLICY = exports.RECURRING_CHARGE_OPTIONS_RESOLVER = exports.PAYMENT_CUSTOMER_REPOSITORY = exports.RECURRING_INVOICE_REPOSITORY = exports.PAYMENT_EVENT_LISTENER = exports.TRANSACTION_MANAGER = exports.WEBHOOK_IDEMPOTENCY_REPOSITORY = exports.PAYMENT_CONFIG_REPOSITORY = exports.PAYMENT_PLAN_REPOSITORY = exports.REFUND_REPOSITORY = exports.PAYMENT_REPOSITORY = exports.INVOICE_REPOSITORY = void 0;
4
4
  exports.INVOICE_REPOSITORY = Symbol('IInvoiceRepository');
5
5
  exports.PAYMENT_REPOSITORY = Symbol('IPaymentRepository');
6
6
  exports.REFUND_REPOSITORY = Symbol('IRefundRepository');
@@ -12,6 +12,8 @@ exports.PAYMENT_EVENT_LISTENER = Symbol('IPaymentEventListener');
12
12
  exports.RECURRING_INVOICE_REPOSITORY = Symbol('IRecurringInvoiceRepository');
13
13
  exports.PAYMENT_CUSTOMER_REPOSITORY = Symbol('IPaymentCustomerRepository');
14
14
  exports.RECURRING_CHARGE_OPTIONS_RESOLVER = Symbol('IRecurringChargeOptionsResolver');
15
+ exports.PAYMENT_METHOD_POLICY = Symbol('IPaymentMethodPolicy');
16
+ exports.PAYMENT_METHOD_POLICY_TIMEOUT = Symbol('PaymentMethodPolicyTimeout');
15
17
  exports.PAYMENT_EMAIL_SENDER = Symbol('IPaymentEmailSender');
16
18
  exports.PAYMENT_CLIENT_RESOLVER = Symbol('IPaymentClientResolver');
17
19
  exports.PAYMENT_EMAIL_BRANDING_RESOLVER = Symbol('IPaymentEmailBrandingResolver');
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAClD,QAAA,kBAAkB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAClD,QAAA,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAChD,QAAA,uBAAuB,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAC3D,QAAA,yBAAyB,GAAG,MAAM,CAAC,0BAA0B,CAAC,CAAC;AAC/D,QAAA,8BAA8B,GAAG,MAAM,CAClD,+BAA+B,CAChC,CAAC;AACW,QAAA,mBAAmB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AACpD,QAAA,sBAAsB,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;AACzD,QAAA,4BAA4B,GAAG,MAAM,CAChD,6BAA6B,CAC9B,CAAC;AACW,QAAA,2BAA2B,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;AAOnE,QAAA,iCAAiC,GAAG,MAAM,CACrD,iCAAiC,CAClC,CAAC;AAGW,QAAA,oBAAoB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AACrD,QAAA,uBAAuB,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAC3D,QAAA,+BAA+B,GAAG,MAAM,CACnD,+BAA+B,CAChC,CAAC;AACW,QAAA,+BAA+B,GAAG,MAAM,CACnD,+BAA+B,CAChC,CAAC;AAGW,QAAA,sBAAsB,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAGxD,QAAA,gBAAgB,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC7C,QAAA,sBAAsB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAGvD,QAAA,WAAW,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAYnC,QAAA,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAClD,QAAA,kBAAkB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAClD,QAAA,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAChD,QAAA,uBAAuB,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAC3D,QAAA,yBAAyB,GAAG,MAAM,CAAC,0BAA0B,CAAC,CAAC;AAC/D,QAAA,8BAA8B,GAAG,MAAM,CAClD,+BAA+B,CAChC,CAAC;AACW,QAAA,mBAAmB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AACpD,QAAA,sBAAsB,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;AACzD,QAAA,4BAA4B,GAAG,MAAM,CAChD,6BAA6B,CAC9B,CAAC;AACW,QAAA,2BAA2B,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;AAOnE,QAAA,iCAAiC,GAAG,MAAM,CACrD,iCAAiC,CAClC,CAAC;AASW,QAAA,qBAAqB,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAOvD,QAAA,6BAA6B,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;AAGrE,QAAA,oBAAoB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AACrD,QAAA,uBAAuB,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAC3D,QAAA,+BAA+B,GAAG,MAAM,CACnD,+BAA+B,CAChC,CAAC;AACW,QAAA,+BAA+B,GAAG,MAAM,CACnD,+BAA+B,CAChC,CAAC;AAGW,QAAA,sBAAsB,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAGxD,QAAA,gBAAgB,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC7C,QAAA,sBAAsB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAGvD,QAAA,WAAW,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAYnC,QAAA,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC"}
@@ -50,6 +50,9 @@ export declare class InvalidTaxConfigurationException extends PaymentException {
50
50
  export declare class PaymentMethodNotOwnedException extends PaymentException {
51
51
  constructor(message: string);
52
52
  }
53
+ export declare class PaymentMethodDefaultRefusedException extends PaymentException {
54
+ constructor(message: string);
55
+ }
53
56
  export declare class PaymentMethodOperationNotSupportedException extends PaymentException {
54
57
  constructor(message: string);
55
58
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NoChargeablePaymentMethodException = exports.PaymentMethodOperationNotSupportedException = exports.PaymentMethodNotOwnedException = exports.InvalidTaxConfigurationException = exports.PaymentIntentOperationNotSupportedException = exports.PaymentIntentNotCancellableException = exports.PaymentIntentNotReusableException = exports.PublishableKeyNotConfiguredException = exports.UniqueConstraintViolationException = exports.InvalidRecurringInvoiceStateException = exports.InvalidPaymentStateException = exports.RefundNotAllowedException = exports.InvoiceNumberExhaustedException = exports.InvoiceNotPayableException = exports.DuplicatePaymentException = exports.PaymentGatewayException = exports.PaymentAmountExceededException = exports.InvalidInvoiceStateException = exports.PaymentException = void 0;
3
+ exports.NoChargeablePaymentMethodException = exports.PaymentMethodOperationNotSupportedException = exports.PaymentMethodDefaultRefusedException = exports.PaymentMethodNotOwnedException = exports.InvalidTaxConfigurationException = exports.PaymentIntentOperationNotSupportedException = exports.PaymentIntentNotCancellableException = exports.PaymentIntentNotReusableException = exports.PublishableKeyNotConfiguredException = exports.UniqueConstraintViolationException = exports.InvalidRecurringInvoiceStateException = exports.InvalidPaymentStateException = exports.RefundNotAllowedException = exports.InvoiceNumberExhaustedException = exports.InvoiceNotPayableException = exports.DuplicatePaymentException = exports.PaymentGatewayException = exports.PaymentAmountExceededException = exports.InvalidInvoiceStateException = exports.PaymentException = void 0;
4
4
  class PaymentException extends Error {
5
5
  constructor(message, code) {
6
6
  super(message);
@@ -108,6 +108,12 @@ class PaymentMethodNotOwnedException extends PaymentException {
108
108
  }
109
109
  }
110
110
  exports.PaymentMethodNotOwnedException = PaymentMethodNotOwnedException;
111
+ class PaymentMethodDefaultRefusedException extends PaymentException {
112
+ constructor(message) {
113
+ super(message, 'PAYMENT_METHOD_DEFAULT_REFUSED');
114
+ }
115
+ }
116
+ exports.PaymentMethodDefaultRefusedException = PaymentMethodDefaultRefusedException;
111
117
  class PaymentMethodOperationNotSupportedException extends PaymentException {
112
118
  constructor(message) {
113
119
  super(message, 'PAYMENT_METHOD_OPERATION_NOT_SUPPORTED');
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exceptions/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exceptions/index.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,10 @@ export interface PaymentGateway {
11
11
  metadata?: Record<string, string>;
12
12
  expiresAt?: Date;
13
13
  gatewayOptions?: Record<string, unknown>;
14
+ savePaymentMethod?: {
15
+ providerCustomerId: string;
16
+ adoptAsDefault?: boolean;
17
+ };
14
18
  idempotencyKey?: string;
15
19
  }): Promise<{
16
20
  checkoutUrl: string;
@@ -30,6 +30,7 @@ export interface RecurringPaymentGateway {
30
30
  cancelUrl: string;
31
31
  metadata?: Record<string, string>;
32
32
  currency?: string;
33
+ adoptAsDefault?: boolean;
33
34
  }): Promise<{
34
35
  setupUrl: string;
35
36
  providerSetupId: string;
@@ -41,6 +42,19 @@ export interface RecurringPaymentGateway {
41
42
  paymentMethodId: string | null;
42
43
  madeDefault: boolean;
43
44
  }>;
45
+ resolveSetupPaymentMethod?(params: {
46
+ setupIntentId: string;
47
+ }): Promise<{
48
+ paymentMethodId: string | null;
49
+ adoptAsDefault: boolean;
50
+ }>;
51
+ adoptPaymentMethod?(params: {
52
+ providerCustomerId: string;
53
+ paymentMethodId: string;
54
+ }): Promise<{
55
+ paymentMethodId: string | null;
56
+ madeDefault: boolean;
57
+ }>;
44
58
  listPaymentMethods?(params: {
45
59
  providerCustomerId: string;
46
60
  }): Promise<SavedPaymentMethod[]>;
@@ -5,7 +5,7 @@ import type { Request } from 'express';
5
5
  import { GatewayRegistryService } from '../gateway-registry.service';
6
6
  import { PaymentService } from '../../services/payment.service';
7
7
  import { RefundService } from '../../services/refund.service';
8
- import { CustomerService } from '../../services/customer.service';
8
+ import { PaymentMethodService } from '../../services/payment-method.service';
9
9
  export declare const PAYMENTS_WEBHOOK = "payments_webhook";
10
10
  export declare const PaymentsWebhook: () => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
11
11
  export declare class StripeWebhookController implements OnModuleInit {
@@ -13,15 +13,17 @@ export declare class StripeWebhookController implements OnModuleInit {
13
13
  private readonly gatewayRegistry;
14
14
  private readonly paymentService;
15
15
  private readonly refundService;
16
- private readonly customerService;
16
+ private readonly paymentMethodService;
17
17
  private readonly logger;
18
18
  private errorReporter;
19
- constructor(moduleRef: ModuleRef, gatewayRegistry: GatewayRegistryService, paymentService: PaymentService, refundService: RefundService, customerService: CustomerService);
19
+ constructor(moduleRef: ModuleRef, gatewayRegistry: GatewayRegistryService, paymentService: PaymentService, refundService: RefundService, paymentMethodService: PaymentMethodService);
20
20
  onModuleInit(): void;
21
21
  handleStripeWebhook(req: RawBodyRequest<Request>): Promise<{
22
22
  received: boolean;
23
23
  }>;
24
24
  private routeEvent;
25
25
  private adoptSetupPaymentMethod;
26
+ private adoptPaymentMethod;
27
+ private adopt;
26
28
  private handleWithRetry;
27
29
  }