@owlmeans/server-payment 0.1.18-rc.20 → 0.1.18-rc.21
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.
- package/README.md +1 -1
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-payment/SKILL.md +402 -260
- package/build/config.d.ts +15 -1
- package/build/config.d.ts.map +1 -1
- package/build/config.js +99 -3
- package/build/config.js.map +1 -1
- package/build/consts.d.ts +27 -0
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +27 -0
- package/build/consts.js.map +1 -1
- package/build/consumer/capture.d.ts +74 -0
- package/build/consumer/capture.d.ts.map +1 -0
- package/build/consumer/capture.js +291 -0
- package/build/consumer/capture.js.map +1 -0
- package/build/consumer/format.d.ts +27 -0
- package/build/consumer/format.d.ts.map +1 -0
- package/build/consumer/format.js +81 -0
- package/build/consumer/format.js.map +1 -0
- package/build/consumer/handlers.d.ts +28 -0
- package/build/consumer/handlers.d.ts.map +1 -0
- package/build/consumer/handlers.js +173 -0
- package/build/consumer/handlers.js.map +1 -0
- package/build/consumer/index.d.ts +7 -0
- package/build/consumer/index.d.ts.map +1 -0
- package/build/consumer/index.js +6 -0
- package/build/consumer/index.js.map +1 -0
- package/build/consumer/mail.d.ts +27 -0
- package/build/consumer/mail.d.ts.map +1 -0
- package/build/consumer/mail.js +314 -0
- package/build/consumer/mail.js.map +1 -0
- package/build/consumer/origin.d.ts +14 -0
- package/build/consumer/origin.d.ts.map +1 -0
- package/build/consumer/origin.js +47 -0
- package/build/consumer/origin.js.map +1 -0
- package/build/consumer/reconcile.d.ts +12 -0
- package/build/consumer/reconcile.d.ts.map +1 -0
- package/build/consumer/reconcile.js +317 -0
- package/build/consumer/reconcile.js.map +1 -0
- package/build/consumer/records.d.ts +78 -0
- package/build/consumer/records.d.ts.map +1 -0
- package/build/consumer/records.js +296 -0
- package/build/consumer/records.js.map +1 -0
- package/build/consumer/service.d.ts +51 -0
- package/build/consumer/service.d.ts.map +1 -0
- package/build/consumer/service.js +760 -0
- package/build/consumer/service.js.map +1 -0
- package/build/consumer/withdrawal.d.ts +57 -0
- package/build/consumer/withdrawal.d.ts.map +1 -0
- package/build/consumer/withdrawal.js +247 -0
- package/build/consumer/withdrawal.js.map +1 -0
- package/build/index.d.ts +4 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/model.d.ts +6 -1
- package/build/model.d.ts.map +1 -1
- package/build/model.js +134 -4
- package/build/model.js.map +1 -1
- package/build/observer.d.ts +4 -0
- package/build/observer.d.ts.map +1 -1
- package/build/observer.js +13 -0
- package/build/observer.js.map +1 -1
- package/build/plugins/checkout-plugins.d.ts +49 -0
- package/build/plugins/checkout-plugins.d.ts.map +1 -0
- package/build/plugins/checkout-plugins.js +124 -0
- package/build/plugins/checkout-plugins.js.map +1 -0
- package/build/plugins/estimate.d.ts.map +1 -1
- package/build/plugins/estimate.js +41 -8
- package/build/plugins/estimate.js.map +1 -1
- package/build/plugins/events.d.ts +2 -0
- package/build/plugins/events.d.ts.map +1 -1
- package/build/plugins/events.js +126 -9
- package/build/plugins/events.js.map +1 -1
- package/build/plugins/fx.d.ts +5 -0
- package/build/plugins/fx.d.ts.map +1 -1
- package/build/plugins/fx.js +25 -0
- package/build/plugins/fx.js.map +1 -1
- package/build/plugins/portal.d.ts.map +1 -1
- package/build/plugins/portal.js +11 -1
- package/build/plugins/portal.js.map +1 -1
- package/build/plugins/stripe.d.ts +21 -2
- package/build/plugins/stripe.d.ts.map +1 -1
- package/build/plugins/stripe.js +397 -61
- package/build/plugins/stripe.js.map +1 -1
- package/build/resource.d.ts +8 -1
- package/build/resource.d.ts.map +1 -1
- package/build/resource.js +59 -2
- package/build/resource.js.map +1 -1
- package/build/service.d.ts +2 -1
- package/build/service.d.ts.map +1 -1
- package/build/service.js +28 -5
- package/build/service.js.map +1 -1
- package/build/subscription.d.ts +6 -0
- package/build/subscription.d.ts.map +1 -1
- package/build/subscription.js +1 -0
- package/build/subscription.js.map +1 -1
- package/build/sync.d.ts +7 -0
- package/build/sync.d.ts.map +1 -1
- package/build/sync.js +108 -15
- package/build/sync.js.map +1 -1
- package/build/types.d.ts +707 -4
- package/build/types.d.ts.map +1 -1
- package/build/utils.d.ts +22 -1
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +27 -1
- package/build/utils.js.map +1 -1
- package/package.json +14 -13
- package/src/config.ts +111 -7
- package/src/consts.ts +34 -0
- package/src/consumer/capture.ts +362 -0
- package/src/consumer/format.ts +90 -0
- package/src/consumer/handlers.ts +211 -0
- package/src/consumer/index.ts +6 -0
- package/src/consumer/mail.ts +368 -0
- package/src/consumer/origin.ts +63 -0
- package/src/consumer/reconcile.ts +329 -0
- package/src/consumer/records.ts +374 -0
- package/src/consumer/service.ts +868 -0
- package/src/consumer/withdrawal.ts +302 -0
- package/src/index.ts +6 -4
- package/src/model.ts +148 -6
- package/src/observer.ts +15 -2
- package/src/plugins/checkout-plugins.ts +155 -0
- package/src/plugins/estimate.ts +49 -9
- package/src/plugins/events.ts +135 -11
- package/src/plugins/fx.ts +29 -0
- package/src/plugins/portal.ts +11 -1
- package/src/plugins/stripe.ts +476 -60
- package/src/resource.ts +87 -4
- package/src/service.ts +28 -6
- package/src/subscription.ts +7 -0
- package/src/sync.ts +124 -17
- package/src/types.ts +756 -6
- package/src/utils.ts +56 -7
- package/tests/checkout-consumer.spec.ts +348 -0
- package/tests/checkout-plugins.spec.ts +164 -0
- package/tests/consumer-events.spec.ts +218 -0
- package/tests/consumer-fixtures.ts +132 -0
- package/tests/consumer-ops.spec.ts +351 -0
- package/tests/consumer-rights.integration.spec.ts +150 -0
- package/tests/consumer-rights.spec.ts +501 -0
- package/tests/context.ts +20 -2
- package/tests/fake-stripe.ts +188 -18
package/build/types.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import type Stripe from 'stripe';
|
|
1
2
|
import type { InitializedService, LazyService } from '@owlmeans/context';
|
|
2
3
|
import type { ResourceRecord } from '@owlmeans/resource';
|
|
3
4
|
import type { MongoResource } from '@owlmeans/mongo-resource';
|
|
4
5
|
import type { PluginConfig } from '@owlmeans/config';
|
|
5
6
|
import type { PermissionSet } from '@owlmeans/auth';
|
|
7
|
+
import type { AbstractRequest } from '@owlmeans/entrypoint';
|
|
8
|
+
import type { MailMessage } from '@owlmeans/mailer';
|
|
6
9
|
import type { Config as ApiConfig, Context as ApiContext } from '@owlmeans/server-api';
|
|
7
|
-
import type { AmountCheckoutPolicy, CheckoutPricingMode, EntitlementView, LimitDeclaration, LimitView, PlanCapability, PlanDuration, PortalFlow, PriceEstimate, PricingPolicy, Product, ProductPlan, ProductType, QuantityCheckoutPolicy, SubscriptionStatus } from '@owlmeans/payment';
|
|
10
|
+
import type { AmountCheckoutPolicy, AmountNarrowing, AmountPolicyView, BillingProfileView, CancellationBody, CancellationKind, CancellationReceipt, CancellationStatus, CheckoutPricingMode, ConsentKind, ConsumerRegion, ConsumerRightsDeclaration, ConsumerRightsLinks, ConsumerRightsPolicy, DeclarationChannel, DeclarationKind, EntitlementView, LimitDeclaration, LimitView, PerformanceConsentBody, PerformanceConsentResponse, PerformanceConsentView, PlanCapability, PlanDuration, PlanPriceView, PlanWithdrawalComponent, PortalFlow, PriceEstimate, PricingPolicy, Product, ProductPlan, ProductType, PurchaseKind, PurchaseView, QuantityCheckoutPolicy, SubscriptionStartBody, SubscriptionStartResponse, SubscriptionStartView, SubscriptionStatus, WithdrawalBody, WithdrawalCandidateList, WithdrawalReceipt, WithdrawalStatus } from '@owlmeans/payment';
|
|
8
11
|
export interface Config extends ApiConfig {
|
|
9
12
|
}
|
|
10
13
|
export interface Context<C extends Config = Config> extends ApiContext<C> {
|
|
@@ -23,6 +26,11 @@ export interface PaymentPlan extends ProductPlan {
|
|
|
23
26
|
pricingMode?: CheckoutPricingMode;
|
|
24
27
|
amountPolicy?: AmountCheckoutPolicy;
|
|
25
28
|
quantityPolicy?: QuantityCheckoutPolicy;
|
|
29
|
+
/**
|
|
30
|
+
* Exact prices in further currencies, major units by lowercase ISO 4217 code (`{ usd: 20 }`).
|
|
31
|
+
* Synced as the reusable Price's `currency_options`, never converted.
|
|
32
|
+
*/
|
|
33
|
+
currencyPrices?: Record<string, number>;
|
|
26
34
|
}
|
|
27
35
|
export interface PaymentProductDef {
|
|
28
36
|
sku: string;
|
|
@@ -65,6 +73,19 @@ export interface PaymentPlanDef {
|
|
|
65
73
|
minQuantity?: number;
|
|
66
74
|
maxQuantity?: number;
|
|
67
75
|
defaultQuantity?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Exact prices in further currencies, major units by ISO 4217 code (`{ usd: 20 }`): a recurring
|
|
78
|
+
* or quantity plan's synced Price carries each as a `currency_options` entry at exactly this
|
|
79
|
+
* amount, while its default currency (the settlement currency) is converted as before.
|
|
80
|
+
*/
|
|
81
|
+
currencyPrices?: Record<string, number>;
|
|
82
|
+
/**
|
|
83
|
+
* The separately priced parts of a subscription for a withdrawal (CJEU C-641/19): their
|
|
84
|
+
* `shareMinor` sum to `round(price × 100)`. Absent: the whole price is one `time` component.
|
|
85
|
+
*/
|
|
86
|
+
withdrawal?: {
|
|
87
|
+
components: PlanWithdrawalComponent[];
|
|
88
|
+
};
|
|
68
89
|
}
|
|
69
90
|
/** File paths (or values) of the Stripe secrets. The webhook secret is an optional override. */
|
|
70
91
|
export interface StripeSecretsDef {
|
|
@@ -100,6 +121,36 @@ export interface StripePricingPluginConfig extends PluginConfig, StripePricingDe
|
|
|
100
121
|
export interface PricingDef extends PricingPolicy {
|
|
101
122
|
stripe?: StripePricingDef;
|
|
102
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* The business the consumer contracts with — backend only, never advertised. `name` is what the
|
|
126
|
+
* express statements say (`{{trader}}` in a consent or start request); the mails' identity line,
|
|
127
|
+
* the withdrawal information and the model form ("To: …") say `legalName`, `address` and `email`.
|
|
128
|
+
*/
|
|
129
|
+
export type TraderDef = {
|
|
130
|
+
name: string;
|
|
131
|
+
legalName: string;
|
|
132
|
+
/** Postal address; without it (or `email`) the mails render without it and the boot warns. */
|
|
133
|
+
address?: string;
|
|
134
|
+
email?: string;
|
|
135
|
+
website?: string;
|
|
136
|
+
};
|
|
137
|
+
/** The consumer-rights mail options — backend only, never advertised. */
|
|
138
|
+
export interface ConsumerMailDef {
|
|
139
|
+
/** The mailer service alias. Default `MAILER_SERVICE`. */
|
|
140
|
+
alias?: string;
|
|
141
|
+
from?: string;
|
|
142
|
+
replyTo?: string;
|
|
143
|
+
/** Evidence archive addresses: each receives its own copy of every consumer-rights mail. */
|
|
144
|
+
bcc?: string[];
|
|
145
|
+
}
|
|
146
|
+
export interface ConsumerMailPluginConfig extends PluginConfig, ConsumerMailDef {
|
|
147
|
+
trader?: TraderDef;
|
|
148
|
+
}
|
|
149
|
+
/** `declareConsumerRights`'s argument: the advertised policy plus the backend-only trader and mail options. */
|
|
150
|
+
export type ConsumerRightsDef = ConsumerRightsDeclaration & {
|
|
151
|
+
trader?: TraderDef;
|
|
152
|
+
mail?: ConsumerMailDef;
|
|
153
|
+
};
|
|
103
154
|
/** What the managed customer portal configuration shows. */
|
|
104
155
|
export interface PortalBrandingDef {
|
|
105
156
|
headline?: string;
|
|
@@ -120,10 +171,104 @@ export interface CreateLinkParams {
|
|
|
120
171
|
amountMinor?: number;
|
|
121
172
|
/** Stripe Checkout and future paid-invoice language. Caller supplies a Stripe-supported locale. */
|
|
122
173
|
locale?: string;
|
|
123
|
-
/**
|
|
124
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Trusted application copy shown beside the Checkout confirmation button — never caller-provided
|
|
176
|
+
* text. A function receives the charge currency and the price the session charges.
|
|
177
|
+
*/
|
|
178
|
+
submitText?: string | ((context: CheckoutTextContext) => string);
|
|
125
179
|
successUrl?: string;
|
|
126
180
|
cancelUrl?: string;
|
|
181
|
+
/** The billing country the buyer declared (ISO 3166-1 alpha-2). A locked profile overrides it. */
|
|
182
|
+
country?: string;
|
|
183
|
+
/** The subscription start request recorded right before a subscription checkout. */
|
|
184
|
+
startRequestId?: string;
|
|
185
|
+
/** The language the buyer is shown legal copy in; default: the billing country's. */
|
|
186
|
+
consumerLanguage?: string;
|
|
187
|
+
/** The request's geolocated country (`cf-ipcountry`) — second location evidence, stored at lock. */
|
|
188
|
+
ipCountry?: string;
|
|
189
|
+
}
|
|
190
|
+
/** What a submit-text function is told about the session it labels. */
|
|
191
|
+
export interface CheckoutTextContext {
|
|
192
|
+
language: string;
|
|
193
|
+
/** The charge currency, lowercase. */
|
|
194
|
+
currency: string;
|
|
195
|
+
/** A subscription's unit price in the charge currency; an amount checkout's pre-tax charge. */
|
|
196
|
+
unitAmountMinor?: number;
|
|
197
|
+
interval?: 'month' | 'year';
|
|
198
|
+
region: ConsumerRegion | null;
|
|
199
|
+
country?: string;
|
|
200
|
+
}
|
|
201
|
+
/** What a plugin narrows: one entity's amount checkout of one plan, at one instant. */
|
|
202
|
+
export interface CheckoutNarrowInput {
|
|
203
|
+
entityId: string;
|
|
204
|
+
productSku: string;
|
|
205
|
+
planSku?: string;
|
|
206
|
+
/** The plan's own amount policy — the same for everyone. */
|
|
207
|
+
base: AmountCheckoutPolicy;
|
|
208
|
+
at: Date;
|
|
209
|
+
}
|
|
210
|
+
/** A checkout about to be created — what `admit` may veto. */
|
|
211
|
+
export interface CheckoutAttempt {
|
|
212
|
+
entityId: string;
|
|
213
|
+
productSku: string;
|
|
214
|
+
planSku?: string;
|
|
215
|
+
mode: 'amount' | 'quantity' | 'subscription';
|
|
216
|
+
/** Amount mode: the net value bought, in the amount policy's currency. */
|
|
217
|
+
amountMinor?: number;
|
|
218
|
+
/** The amount policy's currency (amount mode), else the charge currency. */
|
|
219
|
+
amountCurrency?: string;
|
|
220
|
+
/** Amount mode: the pre-tax charge in `currency`. */
|
|
221
|
+
chargeMinor?: number;
|
|
222
|
+
currency: string;
|
|
223
|
+
/** The session lifetime the gateway will set; absent: Stripe's default (24 h). */
|
|
224
|
+
sessionTtlSeconds?: number;
|
|
225
|
+
expiresAt?: Date;
|
|
226
|
+
at: Date;
|
|
227
|
+
}
|
|
228
|
+
/** A plugin's admission: an optional reservation it binds to the session in `created`. */
|
|
229
|
+
export interface CheckoutAdmission {
|
|
230
|
+
reservationId?: string;
|
|
231
|
+
}
|
|
232
|
+
/** The session a checkout became. */
|
|
233
|
+
export interface CheckoutCreated extends CheckoutAttempt {
|
|
234
|
+
sessionId: string;
|
|
235
|
+
url: string;
|
|
236
|
+
/** What this plugin's own `admit` answered. */
|
|
237
|
+
reservationId?: string;
|
|
238
|
+
}
|
|
239
|
+
export type CheckoutOutcome = 'paid' | 'expired' | 'failed';
|
|
240
|
+
/**
|
|
241
|
+
* How a checkout ended: `paid` (completed and paid), `expired`, or `failed` — an asynchronous
|
|
242
|
+
* payment failure, or a session that never became usable (a later plugin vetoed, Stripe refused,
|
|
243
|
+
* a `created` threw; then `sessionId` may be absent and `reservationId` names the hold to release).
|
|
244
|
+
*/
|
|
245
|
+
export interface CheckoutSettled {
|
|
246
|
+
entityId: string;
|
|
247
|
+
productSku?: string;
|
|
248
|
+
planSku?: string;
|
|
249
|
+
sessionId?: string;
|
|
250
|
+
reservationId?: string;
|
|
251
|
+
outcome: CheckoutOutcome;
|
|
252
|
+
amountMinor?: number;
|
|
253
|
+
at: Date;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* A seam around amount and subscription checkout, registered with `gateway(ctx).use(plugin)` (a
|
|
257
|
+
* plugin with an `alias` registered twice replaces the first). Errors from `narrow` and `admit`
|
|
258
|
+
* propagate — a plugin fails closed; `settled` errors are logged, since holds carry their own TTL.
|
|
259
|
+
*/
|
|
260
|
+
export interface CheckoutPlugin {
|
|
261
|
+
alias?: string;
|
|
262
|
+
/** Lower what this entity may buy now; `null` for no opinion. */
|
|
263
|
+
narrow?: (ctx: ApiContext, input: CheckoutNarrowInput) => Promise<AmountNarrowing | null>;
|
|
264
|
+
/** Veto (throw, e.g. `CheckoutLimitExceeded`) or hold a reservation for the session. */
|
|
265
|
+
admit?: (ctx: ApiContext, attempt: CheckoutAttempt) => Promise<CheckoutAdmission | void>;
|
|
266
|
+
/** The session exists — bind the reservation. A throw expires the session and rethrows. */
|
|
267
|
+
created?: (ctx: ApiContext, created: CheckoutCreated) => Promise<void>;
|
|
268
|
+
/** From the webhook (paid, expired, failed) or from a checkout that never became usable. */
|
|
269
|
+
settled?: (ctx: ApiContext, settled: CheckoutSettled) => Promise<void>;
|
|
270
|
+
/** The longest a session may stay open; the gateway uses the smallest, clamped to 30 min–24 h. */
|
|
271
|
+
sessionTtlSeconds?: number;
|
|
127
272
|
}
|
|
128
273
|
export interface PortalLinkOptions {
|
|
129
274
|
flow: PortalFlow;
|
|
@@ -165,6 +310,17 @@ export interface GatewayService extends InitializedService {
|
|
|
165
310
|
scanned: number;
|
|
166
311
|
updated: number;
|
|
167
312
|
}>;
|
|
313
|
+
/** Register a checkout plugin; one with an `alias` already registered replaces it. */
|
|
314
|
+
use: (plugin: CheckoutPlugin) => void;
|
|
315
|
+
/** The registered checkout plugins, in registration order. */
|
|
316
|
+
checkoutPlugins: () => readonly CheckoutPlugin[];
|
|
317
|
+
/**
|
|
318
|
+
* The entity's amount policy of an amount plan as narrowed NOW — the very computation
|
|
319
|
+
* `createLink` enforces. Mongo and plugins only; works unmanaged.
|
|
320
|
+
*/
|
|
321
|
+
amountPolicy: (ctx: ApiContext, entityId: string, productSku: string, planSku?: string) => Promise<AmountPolicyView>;
|
|
322
|
+
/** The synced prices of a product's plans, per currency — stored rows, no Stripe call. */
|
|
323
|
+
planPrices: (ctx: ApiContext, productSku: string) => Promise<PlanPriceView[]>;
|
|
168
324
|
}
|
|
169
325
|
export interface PaymentGatewayOptions {
|
|
170
326
|
dbAlias?: string;
|
|
@@ -175,6 +331,8 @@ export interface PaymentGatewayOptions {
|
|
|
175
331
|
*/
|
|
176
332
|
manage?: boolean;
|
|
177
333
|
}
|
|
334
|
+
/** A Stripe client for one context — the default reads the configured secret. */
|
|
335
|
+
export type StripeFactory = (ctx: ApiContext) => Promise<Stripe>;
|
|
178
336
|
/** @deprecated use `PaymentGatewayOptions` */
|
|
179
337
|
export type PaymentResourceOptions = PaymentGatewayOptions;
|
|
180
338
|
interface TopUpBase {
|
|
@@ -262,6 +420,14 @@ export interface RefundEvent {
|
|
|
262
420
|
netAmountMinor?: number;
|
|
263
421
|
/** Fulfillment targets: the pre-tax subtotal charged at checkout. */
|
|
264
422
|
chargeAmountMinor?: number;
|
|
423
|
+
/** The refund's own metadata. */
|
|
424
|
+
metadata?: Record<string, string>;
|
|
425
|
+
/**
|
|
426
|
+
* Set when the refund executes a withdrawal (`refund.metadata.withdrawalId`): the `onWithdrawal`
|
|
427
|
+
* observer takes back exactly the unused units — an `onRefund` observer must skip its own
|
|
428
|
+
* claw-back for such a refund, or the units are taken back twice.
|
|
429
|
+
*/
|
|
430
|
+
withdrawalId?: string;
|
|
265
431
|
}
|
|
266
432
|
export type DisputePhase = 'opened' | 'funds-withdrawn' | 'funds-reinstated' | 'closed';
|
|
267
433
|
export interface DisputeEvent {
|
|
@@ -292,6 +458,64 @@ export interface PaymentFailedEvent {
|
|
|
292
458
|
nextAttemptAt?: Date;
|
|
293
459
|
eventKey: string;
|
|
294
460
|
}
|
|
461
|
+
/** A consumer's express request was recorded (performance consent or subscription start). */
|
|
462
|
+
export interface ConsentEvent {
|
|
463
|
+
kind: ConsentKind;
|
|
464
|
+
consentId: string;
|
|
465
|
+
entityId: string;
|
|
466
|
+
profileId?: string;
|
|
467
|
+
/** The purchases the consent covers (none for a start request, which precedes its purchase). */
|
|
468
|
+
purchaseIds: string[];
|
|
469
|
+
planSku?: string;
|
|
470
|
+
textVersion: string;
|
|
471
|
+
language: string;
|
|
472
|
+
decidedAt: Date;
|
|
473
|
+
expiresAt?: Date;
|
|
474
|
+
/** `consent:<consentId>`. */
|
|
475
|
+
eventKey: string;
|
|
476
|
+
}
|
|
477
|
+
/** A withdrawal executed (`refunded`) or left to an operator (`review`). */
|
|
478
|
+
export interface WithdrawalEvent {
|
|
479
|
+
withdrawalId: string;
|
|
480
|
+
/** `withdrawal:<withdrawalId>`. */
|
|
481
|
+
eventKey: string;
|
|
482
|
+
entityId: string;
|
|
483
|
+
channel: DeclarationChannel;
|
|
484
|
+
purchase: PurchaseRef;
|
|
485
|
+
declaredAt: Date;
|
|
486
|
+
status: WithdrawalStatus;
|
|
487
|
+
refund: {
|
|
488
|
+
amountMinor: number;
|
|
489
|
+
currency: string;
|
|
490
|
+
netMinor?: number;
|
|
491
|
+
refundId?: string;
|
|
492
|
+
creditNoteId?: string;
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* The purchase's units as the usage meter read them: `returned` is what the application takes
|
|
496
|
+
* back (`granted − used`), `null` without a meter.
|
|
497
|
+
*/
|
|
498
|
+
units: {
|
|
499
|
+
granted: number;
|
|
500
|
+
used: number;
|
|
501
|
+
returned: number;
|
|
502
|
+
} | null;
|
|
503
|
+
subscriptionCanceled: boolean;
|
|
504
|
+
}
|
|
505
|
+
/** A cancellation was declared (matched to a subscription or not). */
|
|
506
|
+
export interface CancellationEvent {
|
|
507
|
+
cancellationId: string;
|
|
508
|
+
/** `cancellation:<cancellationId>`. */
|
|
509
|
+
eventKey: string;
|
|
510
|
+
entityId?: string;
|
|
511
|
+
matched: boolean;
|
|
512
|
+
channel: DeclarationChannel;
|
|
513
|
+
kind: CancellationKind;
|
|
514
|
+
status: CancellationStatus;
|
|
515
|
+
subscriptionId?: string;
|
|
516
|
+
effectiveAt?: Date;
|
|
517
|
+
declaredAt: Date;
|
|
518
|
+
}
|
|
295
519
|
export interface TopUpCallback {
|
|
296
520
|
(completion: TopUpCompletion, ctx: ApiContext): Promise<void>;
|
|
297
521
|
}
|
|
@@ -307,18 +531,37 @@ export interface DisputeCallback {
|
|
|
307
531
|
export interface PaymentFailedCallback {
|
|
308
532
|
(event: PaymentFailedEvent, ctx: ApiContext): Promise<void>;
|
|
309
533
|
}
|
|
310
|
-
|
|
534
|
+
export interface ConsentCallback {
|
|
535
|
+
(event: ConsentEvent, ctx: ApiContext): Promise<void>;
|
|
536
|
+
}
|
|
537
|
+
export interface WithdrawalCallback {
|
|
538
|
+
(event: WithdrawalEvent, ctx: ApiContext): Promise<void>;
|
|
539
|
+
}
|
|
540
|
+
export interface CancellationCallback {
|
|
541
|
+
(event: CancellationEvent, ctx: ApiContext): Promise<void>;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Callbacks run sequentially and are awaited. A paygate callback's throw escapes so the paygate
|
|
545
|
+
* retries; a consumer-rights callback (`onConsent`, `onWithdrawal`, `onCancellation`) runs AFTER
|
|
546
|
+
* the records and the paygate steps, and its throw is recorded and retried by `reconcile()`.
|
|
547
|
+
*/
|
|
311
548
|
export interface CompletionObserver extends LazyService {
|
|
312
549
|
onTopUp: (cb: TopUpCallback) => void;
|
|
313
550
|
onSubscription: (cb: SubscriptionCallback) => void;
|
|
314
551
|
onRefund: (cb: RefundCallback) => void;
|
|
315
552
|
onDispute: (cb: DisputeCallback) => void;
|
|
316
553
|
onPaymentFailed: (cb: PaymentFailedCallback) => void;
|
|
554
|
+
onConsent: (cb: ConsentCallback) => void;
|
|
555
|
+
onWithdrawal: (cb: WithdrawalCallback) => void;
|
|
556
|
+
onCancellation: (cb: CancellationCallback) => void;
|
|
317
557
|
propagateTopUp: (completion: TopUpCompletion, ctx: ApiContext) => Promise<void>;
|
|
318
558
|
propagateSubscription: (event: SubscriptionEvent, ctx: ApiContext) => Promise<void>;
|
|
319
559
|
propagateRefund: (event: RefundEvent, ctx: ApiContext) => Promise<void>;
|
|
320
560
|
propagateDispute: (event: DisputeEvent, ctx: ApiContext) => Promise<void>;
|
|
321
561
|
propagatePaymentFailed: (event: PaymentFailedEvent, ctx: ApiContext) => Promise<void>;
|
|
562
|
+
propagateConsent: (event: ConsentEvent, ctx: ApiContext) => Promise<void>;
|
|
563
|
+
propagateWithdrawal: (event: WithdrawalEvent, ctx: ApiContext) => Promise<void>;
|
|
564
|
+
propagateCancellation: (event: CancellationEvent, ctx: ApiContext) => Promise<void>;
|
|
322
565
|
}
|
|
323
566
|
export interface PaygateCustomerRecord extends ResourceRecord {
|
|
324
567
|
paygate: string;
|
|
@@ -328,6 +571,10 @@ export interface PaygateCustomerRecord extends ResourceRecord {
|
|
|
328
571
|
email?: string;
|
|
329
572
|
name?: string;
|
|
330
573
|
taxId?: string;
|
|
574
|
+
/** The paygate customer's billing address country, as its last webhook stated it. */
|
|
575
|
+
country?: string;
|
|
576
|
+
/** The paygate customer's own currency (set by its first subscription or invoice). */
|
|
577
|
+
currency?: string;
|
|
331
578
|
deletedAt?: Date;
|
|
332
579
|
}
|
|
333
580
|
export interface PaygateCustomerResource extends MongoResource<PaygateCustomerRecord> {
|
|
@@ -375,6 +622,18 @@ export interface PaymentSubscriptionRecord extends ResourceRecord {
|
|
|
375
622
|
lastEventId?: string;
|
|
376
623
|
initialPropagatedAt?: Date;
|
|
377
624
|
propagated?: PropagatedState;
|
|
625
|
+
/** The subscription's currency (lowercase). */
|
|
626
|
+
currency?: string;
|
|
627
|
+
checkoutSessionId?: string;
|
|
628
|
+
purchaseId?: string;
|
|
629
|
+
firstInvoiceId?: string;
|
|
630
|
+
country?: string;
|
|
631
|
+
email?: string;
|
|
632
|
+
amountTotalMinor?: number;
|
|
633
|
+
amountTaxMinor?: number;
|
|
634
|
+
termsAccepted?: boolean;
|
|
635
|
+
startRequestId?: string;
|
|
636
|
+
withdrawnAt?: Date;
|
|
378
637
|
}
|
|
379
638
|
export interface PaymentSubscriptionResource extends MongoResource<PaymentSubscriptionRecord> {
|
|
380
639
|
byExternalId: (externalId: string, paygate: string) => Promise<PaymentSubscriptionRecord | null>;
|
|
@@ -405,6 +664,13 @@ export interface PaymentFulfillmentRecord extends ResourceRecord {
|
|
|
405
664
|
refundedAt?: Date;
|
|
406
665
|
disputedAt?: Date;
|
|
407
666
|
disputeStatus?: string;
|
|
667
|
+
country?: string;
|
|
668
|
+
email?: string;
|
|
669
|
+
profileId?: string;
|
|
670
|
+
amountTotalMinor?: number;
|
|
671
|
+
amountTaxMinor?: number;
|
|
672
|
+
termsAccepted?: boolean;
|
|
673
|
+
purchaseId?: string;
|
|
408
674
|
}
|
|
409
675
|
export interface PaymentFulfillmentResource extends MongoResource<PaymentFulfillmentRecord> {
|
|
410
676
|
byExternalId: (externalId: string, paygate: string) => Promise<PaymentFulfillmentRecord | null>;
|
|
@@ -455,12 +721,35 @@ export interface PaymentUsageCounterRecord extends ResourceRecord {
|
|
|
455
721
|
}
|
|
456
722
|
export interface PaymentUsageCounterResource extends MongoResource<PaymentUsageCounterRecord> {
|
|
457
723
|
}
|
|
724
|
+
/** One currency option of a synced price. */
|
|
725
|
+
export interface SyncedPriceOption {
|
|
726
|
+
currency: string;
|
|
727
|
+
unitAmount: number;
|
|
728
|
+
}
|
|
729
|
+
/** A reusable price as the last sync left it — what `planPrices` and checkout read without Stripe. */
|
|
730
|
+
export interface SyncedPrice {
|
|
731
|
+
planSku: string;
|
|
732
|
+
priceId: string;
|
|
733
|
+
lookupKey: string;
|
|
734
|
+
/** The default currency and its amount. */
|
|
735
|
+
currency: string;
|
|
736
|
+
unitAmount: number;
|
|
737
|
+
/** `currency_options` besides the default currency. */
|
|
738
|
+
options: SyncedPriceOption[];
|
|
739
|
+
taxBehavior?: string;
|
|
740
|
+
interval?: 'month' | 'year';
|
|
741
|
+
sourceUnitAmount: number;
|
|
742
|
+
sourceCurrency: string;
|
|
743
|
+
syncedAt: Date;
|
|
744
|
+
}
|
|
458
745
|
export interface FingerprintRecord extends ResourceRecord {
|
|
459
746
|
sku: string;
|
|
460
747
|
hash: string;
|
|
461
748
|
productId?: string;
|
|
462
749
|
/** The paygate object the fingerprint describes (a portal configuration id). */
|
|
463
750
|
externalId?: string;
|
|
751
|
+
/** A product's synced reusable prices. */
|
|
752
|
+
prices?: SyncedPrice[];
|
|
464
753
|
updatedAt: Date;
|
|
465
754
|
}
|
|
466
755
|
export interface FingerprintResource extends MongoResource<FingerprintRecord> {
|
|
@@ -561,5 +850,419 @@ export interface ReconcileAllResult {
|
|
|
561
850
|
repaired: number;
|
|
562
851
|
failed: number;
|
|
563
852
|
}
|
|
853
|
+
/** Where a billing profile's country came from. */
|
|
854
|
+
export type BillingProfileSource = 'checkout' | 'customer' | 'manual';
|
|
855
|
+
/** One per organization: the billing country fixed at the first purchase (first write wins). */
|
|
856
|
+
export interface BillingProfileRecord extends ResourceRecord {
|
|
857
|
+
entityId: string;
|
|
858
|
+
country: string;
|
|
859
|
+
region: ConsumerRegion;
|
|
860
|
+
/** The charge currency, fixed with the country. */
|
|
861
|
+
currency: string;
|
|
862
|
+
/** The language of the legal copy. */
|
|
863
|
+
language: string;
|
|
864
|
+
source: BillingProfileSource;
|
|
865
|
+
paygate: string;
|
|
866
|
+
customerId?: string;
|
|
867
|
+
sessionId?: string;
|
|
868
|
+
/** The geolocated country of the request that started the locking checkout — VAT evidence. */
|
|
869
|
+
ipCountry?: string;
|
|
870
|
+
email?: string;
|
|
871
|
+
name?: string;
|
|
872
|
+
/** A business tax id was given at the locking checkout. */
|
|
873
|
+
business?: boolean;
|
|
874
|
+
lockedAt: Date;
|
|
875
|
+
createdAt: Date;
|
|
876
|
+
updatedAt?: Date;
|
|
877
|
+
}
|
|
878
|
+
export interface BillingProfileResource extends MongoResource<BillingProfileRecord> {
|
|
879
|
+
byEntity: (entityId: string) => Promise<BillingProfileRecord | null>;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* One purchase — a contract and its withdrawal window: a paid one-time checkout (`top-up`) or a
|
|
883
|
+
* subscription's first invoice (`subscription`). Renewals are not purchases.
|
|
884
|
+
*/
|
|
885
|
+
export interface PurchaseRecord extends ResourceRecord {
|
|
886
|
+
/** `stripe:<session id>` (one-time) or `stripe:<subscription id>`. */
|
|
887
|
+
purchaseId: string;
|
|
888
|
+
/** `CR-YYMMDD-XXXXXX` — what a consumer quotes. */
|
|
889
|
+
contractRef: string;
|
|
890
|
+
entityId: string;
|
|
891
|
+
kind: PurchaseKind;
|
|
892
|
+
paygate: string;
|
|
893
|
+
sessionId?: string;
|
|
894
|
+
subscriptionId?: string;
|
|
895
|
+
paymentIntentId?: string;
|
|
896
|
+
invoiceId?: string;
|
|
897
|
+
invoiceNumber?: string;
|
|
898
|
+
invoiceLineId?: string;
|
|
899
|
+
productSku: string;
|
|
900
|
+
planSku?: string;
|
|
901
|
+
profileId?: string;
|
|
902
|
+
country?: string;
|
|
903
|
+
region?: ConsumerRegion;
|
|
904
|
+
ipCountry?: string;
|
|
905
|
+
inScope: boolean;
|
|
906
|
+
language: string;
|
|
907
|
+
email?: string;
|
|
908
|
+
name?: string;
|
|
909
|
+
business?: boolean;
|
|
910
|
+
/** The charge currency. */
|
|
911
|
+
currency: string;
|
|
912
|
+
amountSubtotalMinor: number;
|
|
913
|
+
amountTaxMinor: number;
|
|
914
|
+
amountTotalMinor: number;
|
|
915
|
+
presentmentCurrency?: string;
|
|
916
|
+
presentmentAmountMinor?: number;
|
|
917
|
+
/** Amount checkout: the net value credited, in `amountCurrency`. */
|
|
918
|
+
netAmountMinor?: number;
|
|
919
|
+
amountCurrency?: string;
|
|
920
|
+
/** Quantity checkout: the units bought. */
|
|
921
|
+
units?: number;
|
|
922
|
+
taxBehavior?: string;
|
|
923
|
+
/**
|
|
924
|
+
* Stripe's own `consent.terms_of_service` of the checkout — absent when the session did not
|
|
925
|
+
* collect it (the policy's `checkoutTerms` off, or the fallback of a Dashboard without a terms URL).
|
|
926
|
+
*/
|
|
927
|
+
termsAccepted?: boolean;
|
|
928
|
+
textVersion?: string;
|
|
929
|
+
copyVersion?: string;
|
|
930
|
+
startRequestId?: string;
|
|
931
|
+
/** When the consumer expressly requested the services (the start request) — time deductions count from here. */
|
|
932
|
+
servicesStartedAt?: Date;
|
|
933
|
+
/** When the confirmation mail was claimed — one claim per purchase, whatever the outcome of the send. */
|
|
934
|
+
confirmationMailAt?: Date;
|
|
935
|
+
purchasedAt: Date;
|
|
936
|
+
/** Exclusive end of the withdrawal window; absent outside the consumer-rights territories. */
|
|
937
|
+
deadline?: Date;
|
|
938
|
+
consentId?: string;
|
|
939
|
+
consentedAt?: Date;
|
|
940
|
+
withdrawalId?: string;
|
|
941
|
+
withdrawnAt?: Date;
|
|
942
|
+
/** Refunded so far on this purchase's payment, tax included. */
|
|
943
|
+
refundedMinor?: number;
|
|
944
|
+
/** Set once the whole payment is refunded — the window closes. */
|
|
945
|
+
refundedAt?: Date;
|
|
946
|
+
cancellationId?: string;
|
|
947
|
+
cancelEffectiveAt?: Date;
|
|
948
|
+
createdAt: Date;
|
|
949
|
+
updatedAt?: Date;
|
|
950
|
+
}
|
|
951
|
+
export interface PurchaseResource extends MongoResource<PurchaseRecord> {
|
|
952
|
+
byPurchaseId: (purchaseId: string) => Promise<PurchaseRecord | null>;
|
|
953
|
+
}
|
|
954
|
+
/** The request evidence a consumer act is recorded with (`requestOriginOf`). */
|
|
955
|
+
export interface RequestOrigin {
|
|
956
|
+
/** `cf-connecting-ip`, else the LAST `x-forwarded-for` entry, else `x-real-ip`, else the socket. */
|
|
957
|
+
ip?: string;
|
|
958
|
+
/** The raw `x-forwarded-for` header. */
|
|
959
|
+
forwardedFor?: string;
|
|
960
|
+
/** `user-agent`, at most 512 characters. */
|
|
961
|
+
userAgent?: string;
|
|
962
|
+
/** `cf-ipcountry`. */
|
|
963
|
+
ipCountry?: string;
|
|
964
|
+
acceptLanguage?: string;
|
|
965
|
+
/** The channel the request came through (`http`, `mcp`, …), when the application knows. */
|
|
966
|
+
via?: string;
|
|
967
|
+
}
|
|
968
|
+
/** Append-only: one express request — a performance consent or a subscription start request. */
|
|
969
|
+
export interface ConsumerConsentRecord extends ResourceRecord, RequestOrigin {
|
|
970
|
+
kind: ConsentKind;
|
|
971
|
+
entityId: string;
|
|
972
|
+
profileId?: string;
|
|
973
|
+
/** The person who gave it — the confirmation is mailed here. */
|
|
974
|
+
name?: string;
|
|
975
|
+
email?: string;
|
|
976
|
+
purchaseIds: string[];
|
|
977
|
+
planSku?: string;
|
|
978
|
+
/** The plan's name as the statement said it (`{{plan}}`). */
|
|
979
|
+
planName?: string;
|
|
980
|
+
textVersion: string;
|
|
981
|
+
copyVersion: string;
|
|
982
|
+
/** The language the statement was shown in. */
|
|
983
|
+
language: string;
|
|
984
|
+
uiLanguage?: string;
|
|
985
|
+
trader: string;
|
|
986
|
+
/** The statement exactly as rendered and recorded. */
|
|
987
|
+
text: {
|
|
988
|
+
request: string;
|
|
989
|
+
acknowledgement: string;
|
|
990
|
+
checkbox: string;
|
|
991
|
+
};
|
|
992
|
+
links: ConsumerRightsLinks;
|
|
993
|
+
/** The latest deadline among the covered purchases. */
|
|
994
|
+
deadline?: Date;
|
|
995
|
+
decidedAt: Date;
|
|
996
|
+
/** A start request stops being usable at this instant. */
|
|
997
|
+
expiresAt?: Date;
|
|
998
|
+
}
|
|
999
|
+
export interface ConsumerConsentResource extends MongoResource<ConsumerConsentRecord> {
|
|
1000
|
+
}
|
|
1001
|
+
/** Append-only: one withdrawal or cancellation declaration, matched to a contract or not. */
|
|
1002
|
+
export interface ConsumerDeclarationRecord extends ResourceRecord, RequestOrigin {
|
|
1003
|
+
kind: DeclarationKind;
|
|
1004
|
+
channel: DeclarationChannel;
|
|
1005
|
+
entityId?: string;
|
|
1006
|
+
purchaseId?: string;
|
|
1007
|
+
subscriptionId?: string;
|
|
1008
|
+
/** The contract as the consumer named it. */
|
|
1009
|
+
contractRef?: string;
|
|
1010
|
+
name: string;
|
|
1011
|
+
email: string;
|
|
1012
|
+
cancellationKind?: CancellationKind;
|
|
1013
|
+
reason?: string;
|
|
1014
|
+
effective?: 'earliest' | 'date';
|
|
1015
|
+
requestedDate?: string;
|
|
1016
|
+
language: string;
|
|
1017
|
+
textVersion?: string;
|
|
1018
|
+
copyVersion: string;
|
|
1019
|
+
receivedAt: Date;
|
|
1020
|
+
matched: boolean;
|
|
1021
|
+
profileId?: string;
|
|
1022
|
+
/** A repeated declaration of a contract already withdrawn from: the original's id. */
|
|
1023
|
+
duplicateOf?: string;
|
|
1024
|
+
/** The status decided on receipt (`WithdrawalStatus` / `CancellationStatus`); execution steps are events. */
|
|
1025
|
+
status: string;
|
|
1026
|
+
refundMinor?: number;
|
|
1027
|
+
currency?: string;
|
|
1028
|
+
effectiveAt?: Date;
|
|
1029
|
+
}
|
|
1030
|
+
export interface ConsumerDeclarationResource extends MongoResource<ConsumerDeclarationRecord> {
|
|
1031
|
+
}
|
|
1032
|
+
export type ConsumerEventAction = 'mail' | 'computed' | 'meter' | 'refund' | 'credit-note' | 'subscription-cancel' | 'cancel-scheduled' | 'observers' | 'lock' | 'lock-mismatch' | 'relock' | 'unlock' | 'duplicate' | 'checkout-terms-fallback';
|
|
1033
|
+
export type ConsumerRecordKind = 'purchase' | 'consent' | 'declaration' | 'profile' | 'checkout';
|
|
1034
|
+
/** Append-only: one execution or audit step. */
|
|
1035
|
+
export interface ConsumerEventRecord extends ResourceRecord {
|
|
1036
|
+
/** The purchase id, consent id, declaration id, or the entity id of a profile or a checkout. */
|
|
1037
|
+
recordId: string;
|
|
1038
|
+
recordKind: ConsumerRecordKind;
|
|
1039
|
+
entityId?: string;
|
|
1040
|
+
action: ConsumerEventAction;
|
|
1041
|
+
/** The mail kind of a `mail` event; the observer family of an `observers` one. */
|
|
1042
|
+
step?: string;
|
|
1043
|
+
ok: boolean;
|
|
1044
|
+
/** A mail deliberately not sent (a reserved domain, a renderer that suppressed it). */
|
|
1045
|
+
skipped?: boolean;
|
|
1046
|
+
externalId?: string;
|
|
1047
|
+
amountMinor?: number;
|
|
1048
|
+
currency?: string;
|
|
1049
|
+
/** JSON. */
|
|
1050
|
+
detail?: string;
|
|
1051
|
+
error?: string;
|
|
1052
|
+
at: Date;
|
|
1053
|
+
}
|
|
1054
|
+
export interface ConsumerEventResource extends MongoResource<ConsumerEventRecord> {
|
|
1055
|
+
}
|
|
1056
|
+
/** What a usage meter is told about the purchase it reads. */
|
|
1057
|
+
export interface PurchaseRef {
|
|
1058
|
+
purchaseId: string;
|
|
1059
|
+
kind: PurchaseKind;
|
|
1060
|
+
entityId: string;
|
|
1061
|
+
contractRef: string;
|
|
1062
|
+
productSku: string;
|
|
1063
|
+
planSku?: string;
|
|
1064
|
+
/** One-time purchases: the checkout session id. */
|
|
1065
|
+
sessionId?: string;
|
|
1066
|
+
/** Subscription purchases: the paygate subscription id. */
|
|
1067
|
+
subscriptionId?: string;
|
|
1068
|
+
invoiceId?: string;
|
|
1069
|
+
purchasedAt: Date;
|
|
1070
|
+
}
|
|
1071
|
+
export interface UsageQuery {
|
|
1072
|
+
entityId: string;
|
|
1073
|
+
purchase: PurchaseRef;
|
|
1074
|
+
/** The purchase's consent — before it the consumer bears no cost; absent: nothing is deductible. */
|
|
1075
|
+
after?: Date;
|
|
1076
|
+
at: Date;
|
|
1077
|
+
}
|
|
1078
|
+
export interface UsageReading {
|
|
1079
|
+
/** Units the purchase granted. */
|
|
1080
|
+
granted: number;
|
|
1081
|
+
/** Units of it used so far. */
|
|
1082
|
+
used: number;
|
|
1083
|
+
/** Units of it used strictly after `after` (0 without `after`). */
|
|
1084
|
+
usedAfter: number;
|
|
1085
|
+
/** Units of it that paid off an earlier overdraft when it was granted. */
|
|
1086
|
+
settled?: number;
|
|
1087
|
+
/** Units of it already taken back by an earlier (money) refund. */
|
|
1088
|
+
clawed?: number;
|
|
1089
|
+
remaining?: number;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* The application's reading of how much of one purchase was used — for a withdrawal's refund.
|
|
1093
|
+
* The deduction is `usedAfter + settled + clawed`.
|
|
1094
|
+
*/
|
|
1095
|
+
export interface UsageMeter {
|
|
1096
|
+
used: (ctx: ApiContext, query: UsageQuery) => Promise<UsageReading>;
|
|
1097
|
+
}
|
|
1098
|
+
/** Who acts: the organization, and the person's prefill. */
|
|
1099
|
+
export interface ConsumerSubject {
|
|
1100
|
+
entityId: string;
|
|
1101
|
+
profileId?: string;
|
|
1102
|
+
name?: string;
|
|
1103
|
+
email?: string;
|
|
1104
|
+
/** `public` when an application matched a public declaration to this organization itself. */
|
|
1105
|
+
channel?: DeclarationChannel;
|
|
1106
|
+
}
|
|
1107
|
+
export type ConsumerMailKind = 'purchase' | 'consent' | 'start' | 'withdrawal' | 'cancellation';
|
|
1108
|
+
/** What a consumer-rights mail is rendered from. */
|
|
1109
|
+
export interface ConsumerMailData {
|
|
1110
|
+
kind: ConsumerMailKind;
|
|
1111
|
+
/** The purchase id, consent id or declaration id. */
|
|
1112
|
+
recordId: string;
|
|
1113
|
+
entityId?: string;
|
|
1114
|
+
language: string;
|
|
1115
|
+
to: string;
|
|
1116
|
+
name?: string;
|
|
1117
|
+
trader: TraderDef;
|
|
1118
|
+
links: ConsumerRightsLinks;
|
|
1119
|
+
purchase?: PurchaseRecord;
|
|
1120
|
+
purchases?: PurchaseRecord[];
|
|
1121
|
+
consent?: ConsumerConsentRecord;
|
|
1122
|
+
declaration?: ConsumerDeclarationRecord;
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Replace or suppress a consumer-rights mail: answer a message to send it instead, `null` to send
|
|
1126
|
+
* nothing (recorded as skipped), `undefined` to send the rendered one.
|
|
1127
|
+
*/
|
|
1128
|
+
export type ConsumerMailRenderer = (kind: ConsumerMailKind, data: ConsumerMailData, rendered: MailMessage) => MailMessage | null | undefined | Promise<MailMessage | null | undefined>;
|
|
1129
|
+
export interface LockOptions {
|
|
1130
|
+
customerId?: string;
|
|
1131
|
+
sessionId?: string;
|
|
1132
|
+
ipCountry?: string;
|
|
1133
|
+
email?: string;
|
|
1134
|
+
name?: string;
|
|
1135
|
+
business?: boolean;
|
|
1136
|
+
/** The charge currency; default: an active subscription's, else the region's. */
|
|
1137
|
+
currency?: string;
|
|
1138
|
+
language?: string;
|
|
1139
|
+
/** `manual` only: replace an existing lock (audited as a `relock` event). */
|
|
1140
|
+
force?: boolean;
|
|
1141
|
+
by?: string;
|
|
1142
|
+
reason?: string;
|
|
1143
|
+
}
|
|
1144
|
+
/** Who removes a lock, and why — kept on the `unlock` event. */
|
|
1145
|
+
export interface UnlockOptions {
|
|
1146
|
+
by?: string;
|
|
1147
|
+
reason?: string;
|
|
1148
|
+
}
|
|
1149
|
+
export interface ConsumerReconcileOptions {
|
|
1150
|
+
/** How far back declarations, mails and observers are retried. Default 30 days. */
|
|
1151
|
+
since?: Date;
|
|
1152
|
+
/** The most items per step. Default 50. */
|
|
1153
|
+
limit?: number;
|
|
1154
|
+
}
|
|
1155
|
+
export interface ConsumerReconcileResult {
|
|
1156
|
+
retried: number;
|
|
1157
|
+
mailed: number;
|
|
1158
|
+
observed: number;
|
|
1159
|
+
backfilled: number;
|
|
1160
|
+
locked: number;
|
|
1161
|
+
failed: number;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Lazy: reachable while the application is still being wired (`useMeter`, `useMailRenderer` before
|
|
1165
|
+
* the context initializes); the gateway's initialization initializes it at boot.
|
|
1166
|
+
*/
|
|
1167
|
+
export interface ConsumerRightsService extends LazyService {
|
|
1168
|
+
/**
|
|
1169
|
+
* `false`: every paygate-calling method (`withdraw`, `cancel`, `reconcile`'s paygate steps) refuses.
|
|
1170
|
+
* An explicit `manage` of `appendConsumerRights` wins over the gateway's, whatever the order.
|
|
1171
|
+
*/
|
|
1172
|
+
readonly managed: boolean;
|
|
1173
|
+
policy: () => Promise<ConsumerRightsPolicy | null>;
|
|
1174
|
+
/** The locked billing profile, or `null`. */
|
|
1175
|
+
profile: (entityId: string) => Promise<BillingProfileView | null>;
|
|
1176
|
+
/** Lock the billing country; the first write wins unless a `manual` lock is `force`d. */
|
|
1177
|
+
lock: (entityId: string, country: string, source: BillingProfileSource, opts?: LockOptions) => Promise<BillingProfileView>;
|
|
1178
|
+
/**
|
|
1179
|
+
* An operator removes the lock: the profile is deleted and an `unlock` event keeps it. No lazy lock
|
|
1180
|
+
* from the paygate customer follows (checkout, reconcile); the next completed purchase locks again.
|
|
1181
|
+
* @returns the profile as it was, or `null` when nothing was locked
|
|
1182
|
+
*/
|
|
1183
|
+
unlock: (entityId: string, opts?: UnlockOptions) => Promise<BillingProfileView | null>;
|
|
1184
|
+
purchases: (entityId: string, opts?: {
|
|
1185
|
+
open?: boolean;
|
|
1186
|
+
at?: Date;
|
|
1187
|
+
}) => Promise<PurchaseView[]>;
|
|
1188
|
+
consentView: (entityId: string, at?: Date) => Promise<PerformanceConsentView>;
|
|
1189
|
+
/** @throws PerformanceConsentRequired (428) for a stale text version */
|
|
1190
|
+
recordConsent: (subject: ConsumerSubject, body: PerformanceConsentBody, origin?: RequestOrigin) => Promise<PerformanceConsentResponse>;
|
|
1191
|
+
/** @throws PerformanceConsentRequired while an open in-scope window has no consent */
|
|
1192
|
+
assertConsent: (entityId: string, at?: Date) => Promise<void>;
|
|
1193
|
+
startView: (entityId: string, planSku: string, opts?: {
|
|
1194
|
+
language?: string;
|
|
1195
|
+
}) => Promise<SubscriptionStartView>;
|
|
1196
|
+
/** @throws SubscriptionStartRequired (428) for a stale text version */
|
|
1197
|
+
/** `plan`: the plan's short name the statement says (default: its localized catalogue title). */
|
|
1198
|
+
recordStartRequest: (subject: ConsumerSubject, body: SubscriptionStartBody, origin?: RequestOrigin, opts?: {
|
|
1199
|
+
plan?: string;
|
|
1200
|
+
}) => Promise<SubscriptionStartResponse>;
|
|
1201
|
+
/**
|
|
1202
|
+
* The fresh start request bound to this entity and plan, or `null` when none is required.
|
|
1203
|
+
* @throws SubscriptionStartRequired
|
|
1204
|
+
*/
|
|
1205
|
+
assertStartRequest: (entityId: string, planSku: string, startRequestId?: string) => Promise<ConsumerConsentRecord | null>;
|
|
1206
|
+
withdrawalCandidates: (entityId: string, subject?: Partial<ConsumerSubject>) => Promise<WithdrawalCandidateList>;
|
|
1207
|
+
/** `subject: null` — the public function: matched by contract reference and e-mail, never disclosed. */
|
|
1208
|
+
withdraw: (subject: ConsumerSubject | null, body: WithdrawalBody, origin?: RequestOrigin) => Promise<WithdrawalReceipt>;
|
|
1209
|
+
cancel: (subject: ConsumerSubject | null, body: CancellationBody, origin?: RequestOrigin) => Promise<CancellationReceipt>;
|
|
1210
|
+
useMeter: (meter: UsageMeter | null) => void;
|
|
1211
|
+
useMailRenderer: (renderer: ConsumerMailRenderer | null) => void;
|
|
1212
|
+
usageMeter: () => UsageMeter | null;
|
|
1213
|
+
mailRenderer: () => ConsumerMailRenderer | null;
|
|
1214
|
+
/** Retry refunds, credit notes, cancellations, mails and observers; backfill purchases and legacy locks. */
|
|
1215
|
+
reconcile: (opts?: ConsumerReconcileOptions) => Promise<ConsumerReconcileResult>;
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* `appendConsumerRights` options. `manage`, `usage` and `stripe` apply to the service whenever the
|
|
1219
|
+
* call comes — before or after the gateway registered it; the resources' `dbAlias` / `serviceAlias`
|
|
1220
|
+
* are those of the first registration.
|
|
1221
|
+
*/
|
|
1222
|
+
export interface ConsumerRightsOptions {
|
|
1223
|
+
/**
|
|
1224
|
+
* `false` in a process that never talks to the paygate (reads and consent asserts only). Absent:
|
|
1225
|
+
* the gateway's `manage`, else managed.
|
|
1226
|
+
*/
|
|
1227
|
+
manage?: boolean;
|
|
1228
|
+
/** The application's usage meter; without one a withdrawal is left to an operator (`review`). */
|
|
1229
|
+
usage?: UsageMeter;
|
|
1230
|
+
alias?: string;
|
|
1231
|
+
/** The paygate client; default: the configured Stripe secret. */
|
|
1232
|
+
stripe?: StripeFactory;
|
|
1233
|
+
dbAlias?: string;
|
|
1234
|
+
serviceAlias?: string;
|
|
1235
|
+
}
|
|
1236
|
+
/** What a public declaration is throttled by. */
|
|
1237
|
+
export interface ConsumerThrottleKey {
|
|
1238
|
+
action: 'withdrawal' | 'cancellation';
|
|
1239
|
+
email: string;
|
|
1240
|
+
ip?: string;
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* The hooks of `consumerRightsEntrypoints`. Every hook gets the request's context last, so an
|
|
1244
|
+
* application keeps its counters and lookups on the context, never in module state.
|
|
1245
|
+
*/
|
|
1246
|
+
export interface ConsumerRightsHandlerOptions {
|
|
1247
|
+
/** The organization a signed-in request acts for. Default: `req.entity.id`. */
|
|
1248
|
+
resolveEntity?: (req: AbstractRequest, ctx: ApiContext) => string | null | undefined;
|
|
1249
|
+
/** The person's profile id and prefill. */
|
|
1250
|
+
subjectOf?: (req: AbstractRequest, ctx: ApiContext) => Partial<ConsumerSubject> | Promise<Partial<ConsumerSubject>>;
|
|
1251
|
+
/** Refuse a money-moving act (consent, start, withdraw, cancel) — e.g. an API-key request. */
|
|
1252
|
+
guardMoney?: (req: AbstractRequest, action: string, ctx: ApiContext) => void | Promise<void>;
|
|
1253
|
+
/** REQUIRED when the public subtree is bound: throw (e.g. 429) to refuse a public declaration. */
|
|
1254
|
+
throttle?: (req: AbstractRequest, key: ConsumerThrottleKey, ctx: ApiContext) => void | Promise<void>;
|
|
1255
|
+
/** The request evidence; default `requestOriginOf`. */
|
|
1256
|
+
metaOf?: (req: AbstractRequest, ctx: ApiContext) => RequestOrigin;
|
|
1257
|
+
/** The least time a public declaration takes to answer, matched or not. Default 1000 ms. */
|
|
1258
|
+
publicMinMs?: number;
|
|
1259
|
+
/** The plan's short name a start request's statement says (default: its localized catalogue title). */
|
|
1260
|
+
planNameOf?: (planSku: string, language: string, req: AbstractRequest, ctx: ApiContext) => string | undefined | Promise<string | undefined>;
|
|
1261
|
+
serviceAlias?: string;
|
|
1262
|
+
}
|
|
1263
|
+
export interface CheckoutReadHandlerOptions {
|
|
1264
|
+
resolveEntity?: (req: AbstractRequest, ctx: ApiContext) => string | null | undefined;
|
|
1265
|
+
gatewayAlias?: string;
|
|
1266
|
+
}
|
|
564
1267
|
export {};
|
|
565
1268
|
//# sourceMappingURL=types.d.ts.map
|