@happyvertical/smrt-commerce 0.51.32 → 0.51.34
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/AGENTS.md +17 -0
- package/README.md +88 -0
- package/dist/__tests__/foreign-key-fixtures.d.ts +13 -0
- package/dist/__tests__/foreign-key-fixtures.d.ts.map +1 -0
- package/dist/__tests__/helpers/anchor-fixture.d.ts +36 -0
- package/dist/__tests__/helpers/anchor-fixture.d.ts.map +1 -0
- package/dist/__tests__/helpers/billing-fixture.d.ts +51 -0
- package/dist/__tests__/helpers/billing-fixture.d.ts.map +1 -0
- package/dist/__tests__/helpers/consumer-license-sale.d.ts +13 -0
- package/dist/__tests__/helpers/consumer-license-sale.d.ts.map +1 -0
- package/dist/__tests__/helpers/crypto-rail.d.ts +69 -0
- package/dist/__tests__/helpers/crypto-rail.d.ts.map +1 -0
- package/dist/__tests__/helpers/fake-stripe.d.ts +147 -0
- package/dist/__tests__/helpers/fake-stripe.d.ts.map +1 -0
- package/dist/billing/btcpay.d.ts +40 -0
- package/dist/billing/btcpay.d.ts.map +1 -0
- package/dist/billing/cards.d.ts +14 -4
- package/dist/billing/credits.d.ts +7 -2
- package/dist/billing/credits.d.ts.map +1 -1
- package/dist/billing/crypto.d.ts +32 -0
- package/dist/billing/crypto.d.ts.map +1 -0
- package/dist/billing/cycles.d.ts +21 -1
- package/dist/billing/events.d.ts +23 -4
- package/dist/billing/events.d.ts.map +1 -1
- package/dist/billing/index.d.ts +5 -1
- package/dist/billing/index.d.ts.map +1 -1
- package/dist/billing/invoice-payments.d.ts +29 -0
- package/dist/billing/invoice-payments.d.ts.map +1 -0
- package/dist/billing/jobs.d.ts +3 -3
- package/dist/billing/payment-attempts.d.ts +143 -0
- package/dist/billing/payment-attempts.d.ts.map +1 -0
- package/dist/billing/period-close.d.ts +1 -1
- package/dist/billing/provider.d.ts +109 -3
- package/dist/billing/provider.d.ts.map +1 -1
- package/dist/billing/runtime.d.ts +122 -14
- package/dist/billing/runtime.d.ts.map +1 -1
- package/dist/billing/stripe.d.ts +16 -2
- package/dist/billing/stripe.d.ts.map +1 -1
- package/dist/billing/top-up.d.ts +4 -4
- package/dist/collections/ContractCollection.d.ts +4 -0
- package/dist/collections/ContractLineItemCollection.d.ts +4 -0
- package/dist/collections/CustomerCollection.d.ts +4 -0
- package/dist/collections/FulfillmentCollection.d.ts +5 -1
- package/dist/collections/FulfillmentLineItemCollection.d.ts +4 -0
- package/dist/collections/InvoiceCollection.d.ts +4 -0
- package/dist/collections/InvoiceLineItemCollection.d.ts +5 -1
- package/dist/collections/PaymentAllocationCollection.d.ts +4 -0
- package/dist/collections/PaymentCollection.d.ts +5 -1
- package/dist/collections/PaymentInstrumentCollection.d.ts +4 -0
- package/dist/collections/PaymentIntentCollection.d.ts +12 -1
- package/dist/collections/PayoutCollection.d.ts +12 -1
- package/dist/collections/VendorCollection.d.ts +4 -0
- package/dist/index.d.ts +64 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4055 -2859
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +920 -91
- package/dist/migrations/moneyMinorUnits.d.ts +61 -1
- package/dist/models/Contract.d.ts +6 -2
- package/dist/models/ContractLineItem.d.ts +5 -1
- package/dist/models/Customer.d.ts +5 -1
- package/dist/models/Fulfillment.d.ts +5 -1
- package/dist/models/FulfillmentLineItem.d.ts +5 -1
- package/dist/models/Invoice.d.ts +6 -2
- package/dist/models/InvoiceLineItem.d.ts +5 -1
- package/dist/models/Payment.d.ts +6 -2
- package/dist/models/PaymentAllocation.d.ts +5 -1
- package/dist/models/PaymentInstrument.d.ts +5 -1
- package/dist/models/PaymentIntent.d.ts +24 -1
- package/dist/models/Payout.d.ts +24 -1
- package/dist/models/Vendor.d.ts +5 -1
- package/dist/models/billing.d.ts +111 -1
- package/dist/models/billing.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +320 -9
- package/dist/types/index.d.ts +5 -1
- package/dist/ui.d.ts +14 -1
- package/package.json +11 -10
package/AGENTS.md
CHANGED
|
@@ -100,6 +100,23 @@ for usage.
|
|
|
100
100
|
`WRITTEN_OFF` (a later payment is recorded; the status stays).
|
|
101
101
|
- **`Invoice.providerTaxAmount`** is added to line-item tax; it is
|
|
102
102
|
server-managed (not API-writable). `toAccountingInput()` emits major units.
|
|
103
|
+
- **Payment rails (#3138).** A runtime has one issuing `provider` and any
|
|
104
|
+
number of `paymentProviders` (unique names, one inbox namespace each; a
|
|
105
|
+
provider with `capabilities.issuesInvoices === false` can never issue).
|
|
106
|
+
`observe()` resolves the provider from the delivery namespace, never the
|
|
107
|
+
payload. Crypto rails implement the port over `@happyvertical/payments`'
|
|
108
|
+
`CryptoCheckoutGateway`; never call BTCPay (or any gateway) from here.
|
|
109
|
+
Settlement is decided by the pure `decideAttempt()` from gateway state and
|
|
110
|
+
`paymentPolicy` — the gateway's `settled` is authoritative and nothing here
|
|
111
|
+
counts confirmations. A `BillingPaymentAttempt` (`(provider, checkout_id)`
|
|
112
|
+
deterministic id) records every state and settles once; grants and payments
|
|
113
|
+
are keyed by checkout id. Invoice payments close the issuer's invoice out of
|
|
114
|
+
band in `observe()` (idempotent) before `project()` records the payment, and
|
|
115
|
+
`settlePaidInvoice` skips (records nothing for) a `paidOutOfBand` invoice
|
|
116
|
+
the rail latched with `outOfBandRequestedAt`; other out-of-band closes are
|
|
117
|
+
recorded as `OTHER` payments. Rails never save cards or charge tax: a taxed
|
|
118
|
+
credit purchase on a rail needs an explicit `automaticTax: false`. Exceptions are flags for operators;
|
|
119
|
+
nothing reverses or refunds automatically.
|
|
103
120
|
- **Known limits**: write-offs post no bad-debt journal (AR stays until paid
|
|
104
121
|
or journaled by an operator); discounts still reach Stripe as negative lines (the SDK's
|
|
105
122
|
line `discount` would change the lines a replayed push reconciles, so it
|
package/README.md
CHANGED
|
@@ -373,6 +373,94 @@ const evaluator = await SpendingPolicyEvaluator.create({
|
|
|
373
373
|
`automaticTax: false` to keep them untaxed), and Stripe customers are
|
|
374
374
|
created idempotently.
|
|
375
375
|
|
|
376
|
+
### Payment rails: BTC and other crypto (#3138)
|
|
377
|
+
|
|
378
|
+
A seller runtime can take payments on more than one **rail**. The issuing
|
|
379
|
+
`provider` (Stripe) still issues, taxes, and emails every invoice; extra rails
|
|
380
|
+
in `paymentProviders` let a payer choose, per payment, to pay an invoice or buy
|
|
381
|
+
prepaid credit another way. The crypto rail runs short-lived, fiat-priced
|
|
382
|
+
checkouts through `@happyvertical/payments`' provider-neutral
|
|
383
|
+
`CryptoCheckoutGateway` — BTCPay Server at launch — so another gateway can
|
|
384
|
+
replace BTCPay without changing this package or its consumers.
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
import {
|
|
388
|
+
BillingRuntime,
|
|
389
|
+
createBtcPayBillingProvider,
|
|
390
|
+
createStripeBillingProvider,
|
|
391
|
+
} from '@happyvertical/smrt-commerce';
|
|
392
|
+
|
|
393
|
+
const btcpay = createBtcPayBillingProvider({
|
|
394
|
+
baseUrl, apiKey, storeId, // one BTCPay store per seller entity
|
|
395
|
+
webhookSecret, metadataSecret, // from the host's secret store, by name
|
|
396
|
+
speedPolicy: 'LowMediumSpeed', // settle after 2 confirmations (BTCPay offers 0/1/2/6)
|
|
397
|
+
rateSource: 'kraken',
|
|
398
|
+
minimumAmount: { CAD: 500, USD: 500 },
|
|
399
|
+
});
|
|
400
|
+
const billing = await BillingRuntime.create({
|
|
401
|
+
db, sellerTenantId, kind: 'provider',
|
|
402
|
+
provider: createStripeBillingProvider({ stripe, webhookSecret }),
|
|
403
|
+
paymentProviders: [btcpay],
|
|
404
|
+
paymentPolicy: { latePaymentPolicy: 'review', refundBasis: 'original_native' },
|
|
405
|
+
billingRelationships,
|
|
406
|
+
ledger: { ...ledger, cryptoHoldingsAccountId, fxGainLossAccountId, feesAccountId },
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// Prepaid credit or an issued invoice, paid with BTC:
|
|
410
|
+
await billing.createCreditCheckout({ ...purchase, provider: 'btcpay' });
|
|
411
|
+
await billing.createInvoicePayment({ invoiceId, provider: 'btcpay', purchaseId, successUrl, cancelUrl });
|
|
412
|
+
|
|
413
|
+
// Webhook route for the rail (BTCPay signs with its own header):
|
|
414
|
+
await billing.acceptWebhook(rawBody, '', { provider: 'btcpay', headers: request.headers });
|
|
415
|
+
await billing.processEvents();
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
- **Settlement is the gateway's.** Credit is granted and invoices are paid
|
|
419
|
+
only when the gateway reports `settled` under its own confirmation policy;
|
|
420
|
+
this package never counts confirmations. BTCPay offers 0, 1, 2 or 6
|
|
421
|
+
confirmations; the default is `LowMediumSpeed` (2 confirmations).
|
|
422
|
+
- **Payment attempts.** Every rail checkout is a `BillingPaymentAttempt`
|
|
423
|
+
recording the locked fiat price, fiat and native amounts received, rate and
|
|
424
|
+
rate source, each payment's txid, rail and fee, a timeline of status changes,
|
|
425
|
+
and what settlement produced. `listPaymentAttempts()` feeds "payment
|
|
426
|
+
confirming" displays and operator queues; `refreshPaymentAttempts()` is the
|
|
427
|
+
polling fallback for missed webhooks.
|
|
428
|
+
- **Dunning pauses** for an invoice while a payment for it is confirming
|
|
429
|
+
(0-conf seen); if the payment then expires or is invalidated the payer's
|
|
430
|
+
standing is re-applied.
|
|
431
|
+
- **Invoices paid on a rail** are closed at the issuer with
|
|
432
|
+
`markInvoicePaidOutOfBand` (Stripe `paid_out_of_band`), so Stripe stops
|
|
433
|
+
collecting; Stripe's own `paid` event then records nothing more.
|
|
434
|
+
`createInvoicePayment` refuses when the issuing provider cannot do that.
|
|
435
|
+
- **Exceptions never auto-refund.** Underpaid, overpaid, late, manually marked
|
|
436
|
+
(at the gateway), invalidated-after-settlement, and paid-twice attempts are
|
|
437
|
+
flagged for an operator (`resolvePaymentAttempt`). Per-seller
|
|
438
|
+
`paymentPolicy` sets under/overpayment tolerances (basis points), late
|
|
439
|
+
payments (`review` | `accept`), manually marked checkouts, hold vs convert
|
|
440
|
+
(`conversionHandler`), and the refund basis.
|
|
441
|
+
- **Ledger.** Receipts are booked at the locked fiat amount into
|
|
442
|
+
`cryptoHoldingsAccountId` (default `cashAccountId`); money received above
|
|
443
|
+
the price is booked as customer credit (prepaid-credit liability).
|
|
444
|
+
`recordManualRefund()` refunds from that excess first, then from purchased
|
|
445
|
+
credit (or an invoice payment kept as credit because the invoice was paid
|
|
446
|
+
elsewhere) — capped cumulatively, once per reference; an invoice payment
|
|
447
|
+
applied to its invoice is reversed at the issuer, not here.
|
|
448
|
+
`recordCryptoConversion()` posts a conversion with FX gain/loss.
|
|
449
|
+
- **Upgrading.** Additive schema: `_smrt_billing_payment_attempts` (run
|
|
450
|
+
`smrt db:migrate`). A runtime without `paymentProviders` never reads it.
|
|
451
|
+
- **One live payment per invoice.** The issuer's own `paid` event for an
|
|
452
|
+
invoice a rail closed out of band records nothing (the rail records it); an
|
|
453
|
+
out-of-band close made by someone else (wire, cheque) is recorded as an
|
|
454
|
+
`OTHER`-method payment; a real card payment made while a rail payment
|
|
455
|
+
confirms is recorded and the rail money is flagged `invoice_already_paid`.
|
|
456
|
+
An issuer close whose rail payment never settles is flagged
|
|
457
|
+
`out_of_band_without_settlement`: reopen the invoice at the issuer, then
|
|
458
|
+
`resolvePaymentAttempt()` it, after which a later out-of-band close is
|
|
459
|
+
recorded normally.
|
|
460
|
+
- **Entities.** Each legal entity is its own seller runtime with its own
|
|
461
|
+
store, keys, and ledger. Inter-entity resale is ordinary reseller billing
|
|
462
|
+
between two sellers, payable on any rail the selling entity offers.
|
|
463
|
+
|
|
376
464
|
See [`AGENTS.md`](./AGENTS.md#billing-period-close-3060) for invariants and
|
|
377
465
|
known limits.
|
|
378
466
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface CommerceForeignKeyFixtures {
|
|
2
|
+
db: {
|
|
3
|
+
type: 'sqlite';
|
|
4
|
+
url: string;
|
|
5
|
+
};
|
|
6
|
+
customerIds?: string[];
|
|
7
|
+
vendorIds?: string[];
|
|
8
|
+
contractIds?: string[];
|
|
9
|
+
}
|
|
10
|
+
/** Seed only the real same-package parents referenced by a test scenario. */
|
|
11
|
+
export declare function seedCommerceForeignKeyFixtures({ db, customerIds, vendorIds, contractIds, }: CommerceForeignKeyFixtures): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=foreign-key-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foreign-key-fixtures.d.ts","sourceRoot":"","sources":["../../src/__tests__/foreign-key-fixtures.ts"],"names":[],"mappings":"AAIA,UAAU,0BAA0B;IAClC,EAAE,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,6EAA6E;AAC7E,wBAAsB,8BAA8B,CAAC,EACnD,EAAE,EACF,WAAgB,EAChB,SAAc,EACd,WAAgB,GACjB,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B5C"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for billing-cycle anchor tests (#3116), shared by the SQLite suite
|
|
3
|
+
* and the PostgreSQL lane. Scenarios run at fixed future dates with no usage
|
|
4
|
+
* charges, so only flat plans are billed.
|
|
5
|
+
*/
|
|
6
|
+
import type { TenantSubscription } from '@happyvertical/smrt-subscriptions';
|
|
7
|
+
import type { BillingRuntime } from '../../billing/runtime.js';
|
|
8
|
+
import { type BillingLineSource } from '../../models/billing.js';
|
|
9
|
+
import { type BillingWorld } from './billing-fixture.js';
|
|
10
|
+
export declare const at: (iso: string) => Date;
|
|
11
|
+
export declare const DAY = 86400000;
|
|
12
|
+
export declare function subscriptionOf(world: BillingWorld, tenantId: string): Promise<TenantSubscription>;
|
|
13
|
+
export declare function updateSubscription(world: BillingWorld, tenantId: string, patch: Partial<Pick<TenantSubscription, 'startedAt' | 'canceledAt' | 'trialEndsAt' | 'status'>>): Promise<TenantSubscription>;
|
|
14
|
+
/** Put SITE (billed to NETWORK) out of the way so NETWORK has nothing due. */
|
|
15
|
+
export declare function parkNetwork(world: BillingWorld): Promise<void>;
|
|
16
|
+
/** Subscribe another tenant to the provider's site plan, billed to NETWORK. */
|
|
17
|
+
export declare function addNetworkSite(world: BillingWorld, tenantId: string, startedAt: Date): Promise<TenantSubscription>;
|
|
18
|
+
/** A payer's invoices from the provider runtime, oldest period first. */
|
|
19
|
+
export declare function invoicesOf(world: BillingWorld, payer: string, runtime?: BillingRuntime): Promise<import("../../index.js").Invoice[]>;
|
|
20
|
+
export declare function flatClaims(world: BillingWorld, subscriptionId?: string): Promise<BillingLineSource[]>;
|
|
21
|
+
/** Claimed windows as ISO pairs with amounts, in time order. */
|
|
22
|
+
export declare function claimedWindows(world: BillingWorld, subscriptionId: string): Promise<Array<[string, string, number]>>;
|
|
23
|
+
/** Assert that no two flat claims of one subscription cover the same time. */
|
|
24
|
+
export declare function overlappingClaims(world: BillingWorld): Promise<string[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Hold a runtime's first flat-plan claim insert for `lineKey` until
|
|
27
|
+
* `release()`: `reached` resolves once the claim has read the existing
|
|
28
|
+
* coverage and is about to insert, so a test can interleave a second worker
|
|
29
|
+
* deterministically.
|
|
30
|
+
*/
|
|
31
|
+
export declare function holdFlatClaim(runtime: BillingRuntime, lineKey: string): {
|
|
32
|
+
reached: Promise<void>;
|
|
33
|
+
release: () => void;
|
|
34
|
+
restore: () => void;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=anchor-fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-fixture.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/anchor-fixture.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EACL,KAAK,iBAAiB,EAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,EAAE,GAAI,KAAK,MAAM,SAAkB,CAAC;AACjD,eAAO,MAAM,GAAG,WAAa,CAAC;AAE9B,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAM7B;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,CACZ,IAAI,CACF,kBAAkB,EAClB,WAAW,GAAG,YAAY,GAAG,aAAa,GAAG,QAAQ,CACtD,CACF,GACA,OAAO,CAAC,kBAAkB,CAAC,CAO7B;AAED,8EAA8E;AAC9E,wBAAsB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpE;AAED,+EAA+E;AAC/E,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,IAAI,GACd,OAAO,CAAC,kBAAkB,CAAC,CAgB7B;AAED,yEAAyE;AACzE,wBAAsB,UAAU,CAC9B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAA+B,+CAUzC;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,YAAY,EACnB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAW9B;AAED,gEAAgE;AAChE,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAM1C;AAED,8EAA8E;AAC9E,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAqBnB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM;;mBAGhD,IAAI;;EAqBzB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small reseller world for billing-period close tests (#3060), shared by
|
|
3
|
+
* the SQLite suite and the PostgreSQL lane.
|
|
4
|
+
*
|
|
5
|
+
* PROVIDER sells to NETWORK (a reseller that pays for SITE's usage and plan)
|
|
6
|
+
* and to SOLO (billed for itself). NETWORK resells to SITE (retail usage) and
|
|
7
|
+
* to SITE2 (NETWORK's own flat plan).
|
|
8
|
+
*/
|
|
9
|
+
import type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';
|
|
10
|
+
import { BillingAdjustmentCollection, ClientChargeCollection, CommercialUsageService, ResellerBillingService, SubscriptionPlanCollection, TenantSubscriptionCollection } from '@happyvertical/smrt-subscriptions';
|
|
11
|
+
import { BillingRelationshipService } from '@happyvertical/smrt-tenancy';
|
|
12
|
+
import { type BillingLedgerAccounts, BillingRuntime, type PayerStandingChange } from '../../billing/runtime.js';
|
|
13
|
+
import { FakeStripe } from './fake-stripe.js';
|
|
14
|
+
export declare const PROVIDER = "00000000-0000-4000-8000-00000000000a";
|
|
15
|
+
export declare const NETWORK = "aaaaaaaa-1111-4111-8111-aaaaaaaaaaaa";
|
|
16
|
+
export declare const SITE = "cccccccc-3333-4333-8333-cccccccccccc";
|
|
17
|
+
export declare const SITE2 = "eeeeeeee-5555-4555-8555-eeeeeeeeeeee";
|
|
18
|
+
export declare const SOLO = "dddddddd-4444-4444-8444-dddddddddddd";
|
|
19
|
+
export declare const STRANGER = "ffffffff-6666-4666-8666-ffffffffffff";
|
|
20
|
+
/** The current UTC calendar month, closable by passing `now: periodEnd + 1d`. */
|
|
21
|
+
export declare function currentMonth(): {
|
|
22
|
+
periodStart: Date;
|
|
23
|
+
periodEnd: Date;
|
|
24
|
+
now: Date;
|
|
25
|
+
};
|
|
26
|
+
export declare function nextMonth(period: {
|
|
27
|
+
periodEnd: Date;
|
|
28
|
+
}): {
|
|
29
|
+
periodStart: Date;
|
|
30
|
+
periodEnd: Date;
|
|
31
|
+
now: Date;
|
|
32
|
+
};
|
|
33
|
+
export interface BillingWorld {
|
|
34
|
+
db: DatabaseInterface;
|
|
35
|
+
stripe: FakeStripe;
|
|
36
|
+
provider: BillingRuntime;
|
|
37
|
+
reseller: BillingRuntime;
|
|
38
|
+
commercial: CommercialUsageService;
|
|
39
|
+
relationships: BillingRelationshipService;
|
|
40
|
+
resellerBilling: ResellerBillingService;
|
|
41
|
+
ledger: BillingLedgerAccounts;
|
|
42
|
+
standingChanges: PayerStandingChange[];
|
|
43
|
+
subscriptions: TenantSubscriptionCollection;
|
|
44
|
+
plans: SubscriptionPlanCollection;
|
|
45
|
+
charges: ClientChargeCollection;
|
|
46
|
+
adjustments: BillingAdjustmentCollection;
|
|
47
|
+
/** Record and rate one usage event (10 tokens) for a tenant. */
|
|
48
|
+
usage(tenantId: string, quantity?: number): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
export declare function createBillingWorld(db: DatabaseInterface): Promise<BillingWorld>;
|
|
51
|
+
//# sourceMappingURL=billing-fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing-fixture.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/billing-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,OAAO,EACL,2BAA2B,EAC3B,sBAAsB,EACtB,sBAAsB,EAGtB,sBAAsB,EACtB,0BAA0B,EAC1B,4BAA4B,EAE7B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,0BAA0B,EAG3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,qBAAqB,EAC1B,cAAc,EACd,KAAK,mBAAmB,EACzB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,UAAU,EAAkB,MAAM,kBAAkB,CAAC;AAE9D,eAAO,MAAM,QAAQ,yCAAyC,CAAC;AAC/D,eAAO,MAAM,OAAO,yCAAyC,CAAC;AAC9D,eAAO,MAAM,IAAI,yCAAyC,CAAC;AAC3D,eAAO,MAAM,KAAK,yCAAyC,CAAC;AAC5D,eAAO,MAAM,IAAI,yCAAyC,CAAC;AAC3D,eAAO,MAAM,QAAQ,yCAAyC,CAAC;AAE/D,iFAAiF;AACjF,wBAAgB,YAAY,IAAI;IAC9B,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,GAAG,EAAE,IAAI,CAAC;CACX,CAaA;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE;;;;EAUpD;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,iBAAiB,CAAC;IACtB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,sBAAsB,CAAC;IACnC,aAAa,EAAE,0BAA0B,CAAC;IAC1C,eAAe,EAAE,sBAAsB,CAAC;IACxC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,eAAe,EAAE,mBAAmB,EAAE,CAAC;IACvC,aAAa,EAAE,4BAA4B,CAAC;IAC5C,KAAK,EAAE,0BAA0B,CAAC;IAClC,OAAO,EAAE,sBAAsB,CAAC;IAChC,WAAW,EAAE,2BAA2B,CAAC;IACzC,gEAAgE;IAChE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAID,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,iBAAiB,GACpB,OAAO,CAAC,YAAY,CAAC,CA6OvB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type SmrtObject } from '@happyvertical/smrt-core';
|
|
2
|
+
export declare const CONSUMER_PACKAGE = "@fixture/market-core";
|
|
3
|
+
export declare function defineConsumerLicenseSale(): Promise<{
|
|
4
|
+
ctor: typeof SmrtObject;
|
|
5
|
+
dispose: () => void;
|
|
6
|
+
}>;
|
|
7
|
+
/**
|
|
8
|
+
* Each `LicenseSale` keeps its own identity and table, the schema planner
|
|
9
|
+
* keeps commerce's `contracts` free of the consumer's class, and commerce's
|
|
10
|
+
* `LicenseSale` still round-trips through its own table.
|
|
11
|
+
*/
|
|
12
|
+
export declare function assertLicenseSalesCoexist(consumer: typeof SmrtObject): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=consumer-license-sale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumer-license-sale.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/consumer-license-sale.ts"],"names":[],"mappings":"AAwBA,OAAO,EAEL,KAAK,UAAU,EAGhB,MAAM,0BAA0B,CAAC;AAKlC,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAEvD,wBAAsB,yBAAyB,IAAI,OAAO,CAAC;IACzD,IAAI,EAAE,OAAO,UAAU,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC,CAgCD;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,OAAO,UAAU,GAC1B,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A crypto payment rail world for #3138: the billing fixture's Stripe
|
|
3
|
+
* issuing provider plus an in-memory `CryptoCheckoutGateway`, wired into one
|
|
4
|
+
* seller runtime. Shared by the SQLite suite and the PostgreSQL lane.
|
|
5
|
+
*/
|
|
6
|
+
import { type CreateCryptoCheckoutInput, type CryptoCheckout, type CryptoCheckoutException, type CryptoCheckoutGateway, type CryptoCheckoutPayment, type CryptoCheckoutStatus } from '@happyvertical/payments';
|
|
7
|
+
import type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';
|
|
8
|
+
import type { BillingPaymentPolicy } from '../../billing/payment-attempts.js';
|
|
9
|
+
import type { BillingProvider } from '../../billing/provider.js';
|
|
10
|
+
import { type BillingLedgerAccounts, BillingRuntime } from '../../billing/runtime.js';
|
|
11
|
+
import { type BillingWorld } from './billing-fixture.js';
|
|
12
|
+
export declare const RAIL_METADATA_SECRET = "rail-metadata-secret";
|
|
13
|
+
export declare const RAIL_SIGNATURE = "fake-rail-ok";
|
|
14
|
+
interface FakeCheckout {
|
|
15
|
+
id: string;
|
|
16
|
+
orderId: string;
|
|
17
|
+
amount: number;
|
|
18
|
+
currency: string;
|
|
19
|
+
metadata: Record<string, string>;
|
|
20
|
+
status: CryptoCheckoutStatus;
|
|
21
|
+
exception: CryptoCheckoutException;
|
|
22
|
+
amountPaid: number;
|
|
23
|
+
payments: CryptoCheckoutPayment[];
|
|
24
|
+
owned: boolean;
|
|
25
|
+
/** Settlement asset override (default BTC). */
|
|
26
|
+
asset?: string;
|
|
27
|
+
}
|
|
28
|
+
/** An in-memory gateway: tests move checkouts through their states. */
|
|
29
|
+
export declare class FakeCryptoGateway implements CryptoCheckoutGateway {
|
|
30
|
+
readonly id = "btcpay";
|
|
31
|
+
readonly checkouts: Map<string, FakeCheckout>;
|
|
32
|
+
created: number;
|
|
33
|
+
private counter;
|
|
34
|
+
createCheckout(input: CreateCryptoCheckoutInput): Promise<CryptoCheckout>;
|
|
35
|
+
getCheckout(checkoutId: string): Promise<CryptoCheckout>;
|
|
36
|
+
listCheckouts(input: {
|
|
37
|
+
orderId: string;
|
|
38
|
+
}): Promise<CryptoCheckout[]>;
|
|
39
|
+
verifyWebhook(rawBody: string, headers: Headers | Record<string, string | undefined>): {
|
|
40
|
+
eventId: string;
|
|
41
|
+
checkoutId: string | null;
|
|
42
|
+
type: string;
|
|
43
|
+
redelivery: boolean;
|
|
44
|
+
};
|
|
45
|
+
/** Move a checkout: `paid` is fiat minor units received. */
|
|
46
|
+
set(checkoutId: string, status: CryptoCheckoutStatus, options?: {
|
|
47
|
+
exception?: CryptoCheckoutException;
|
|
48
|
+
paid?: number;
|
|
49
|
+
paymentStatus?: CryptoCheckoutPayment['status'];
|
|
50
|
+
}): void;
|
|
51
|
+
private view;
|
|
52
|
+
}
|
|
53
|
+
export interface RailWorld extends BillingWorld {
|
|
54
|
+
gateway: FakeCryptoGateway;
|
|
55
|
+
rail: BillingProvider;
|
|
56
|
+
runtime: BillingRuntime;
|
|
57
|
+
railLedger: BillingLedgerAccounts;
|
|
58
|
+
/** Provider invoice ids closed as paid out of band. */
|
|
59
|
+
outOfBand: string[];
|
|
60
|
+
/** Deliver a signed rail webhook for a checkout and process events. */
|
|
61
|
+
railEvent(checkoutId: string, eventId?: string): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
export declare function createRailWorld(db: DatabaseInterface, options?: {
|
|
64
|
+
paymentPolicy?: Partial<BillingPaymentPolicy>;
|
|
65
|
+
/** Give Stripe the out-of-band method (default true). */
|
|
66
|
+
outOfBand?: boolean;
|
|
67
|
+
}): Promise<RailWorld>;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=crypto-rail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-rail.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/crypto-rail.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAE1B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EAE1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAI7E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,qBAAqB,EAC1B,cAAc,EACf,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,sBAAsB,CAAC;AAG9B,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAG7C,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,uBAAuB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,uEAAuE;AACvE,qBAAa,iBAAkB,YAAW,qBAAqB;IAC7D,QAAQ,CAAC,EAAE,YAAY;IACvB,QAAQ,CAAC,SAAS,4BAAmC;IACrD,OAAO,SAAK;IACZ,OAAO,CAAC,OAAO,CAAK;IAEd,cAAc,CAClB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,cAAc,CAAC;IAyBpB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAOxD,aAAa,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAM1E,aAAa,CACX,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;;;;;;IAsBvD,4DAA4D;IAC5D,GAAG,CACD,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,oBAAoB,EAC5B,OAAO,GAAE;QACP,SAAS,CAAC,EAAE,uBAAuB,CAAC;QACpC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;KAC5C,GACL,IAAI;IA6BP,OAAO,CAAC,IAAI;CAsBb;AAED,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,qBAAqB,CAAC;IAClC,uDAAuD;IACvD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,uEAAuE;IACvE,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAID,wBAAsB,eAAe,CACnC,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9C,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAC;CAChB,GACL,OAAO,CAAC,SAAS,CAAC,CAmFpB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { StripeAccountingProvider } from '@happyvertical/accounting';
|
|
2
|
+
export declare const WEBHOOK_SECRET = "whsec_test_billing";
|
|
3
|
+
interface FakeCustomer {
|
|
4
|
+
id: string;
|
|
5
|
+
created: number;
|
|
6
|
+
name?: string;
|
|
7
|
+
email?: string;
|
|
8
|
+
address?: Record<string, string>;
|
|
9
|
+
tax_exempt?: string;
|
|
10
|
+
default_payment_method?: string;
|
|
11
|
+
metadata: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
interface FakeInvoiceItem {
|
|
14
|
+
id: string;
|
|
15
|
+
customer: string;
|
|
16
|
+
currency: string;
|
|
17
|
+
quantity: number;
|
|
18
|
+
unit_amount: number;
|
|
19
|
+
description: string;
|
|
20
|
+
invoice: string | null;
|
|
21
|
+
metadata: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
interface FakeInvoice {
|
|
24
|
+
id: string;
|
|
25
|
+
customer: string;
|
|
26
|
+
currency: string;
|
|
27
|
+
status: 'draft' | 'open' | 'paid' | 'void' | 'uncollectible';
|
|
28
|
+
collection_method: 'send_invoice' | 'charge_automatically';
|
|
29
|
+
auto_advance: boolean;
|
|
30
|
+
finalized: number;
|
|
31
|
+
due_date: number | null;
|
|
32
|
+
created: number;
|
|
33
|
+
automatic_tax: boolean;
|
|
34
|
+
items: string[];
|
|
35
|
+
subtotal: number;
|
|
36
|
+
tax: number;
|
|
37
|
+
total: number;
|
|
38
|
+
amount_paid: number;
|
|
39
|
+
amount_remaining: number;
|
|
40
|
+
metadata: Record<string, string>;
|
|
41
|
+
sent: number;
|
|
42
|
+
paid_out_of_band?: boolean;
|
|
43
|
+
}
|
|
44
|
+
interface FakeSession {
|
|
45
|
+
id: string;
|
|
46
|
+
url: string;
|
|
47
|
+
mode: string;
|
|
48
|
+
currency: string | null;
|
|
49
|
+
amount_subtotal: number | null;
|
|
50
|
+
amount_tax: number;
|
|
51
|
+
amount_total: number | null;
|
|
52
|
+
customer: string | null;
|
|
53
|
+
status: 'open' | 'complete' | 'expired';
|
|
54
|
+
payment_status: 'paid' | 'unpaid' | 'no_payment_required';
|
|
55
|
+
automatic_tax: boolean;
|
|
56
|
+
customer_update_address: boolean;
|
|
57
|
+
billing_address_collection: string | null;
|
|
58
|
+
setup_future_usage: string | null;
|
|
59
|
+
payment_method: string | null;
|
|
60
|
+
metadata: Record<string, string>;
|
|
61
|
+
}
|
|
62
|
+
/** How a saved payment method answers an off-session charge. */
|
|
63
|
+
export type FakeCardBehavior = 'succeed' | 'processing' | 'decline' | 'authentication_required';
|
|
64
|
+
interface FakePaymentIntent {
|
|
65
|
+
id: string;
|
|
66
|
+
object: 'payment_intent';
|
|
67
|
+
created: number;
|
|
68
|
+
amount: number;
|
|
69
|
+
currency: string;
|
|
70
|
+
customer: string;
|
|
71
|
+
payment_method: string;
|
|
72
|
+
status: string;
|
|
73
|
+
last_payment_error: Record<string, string> | null;
|
|
74
|
+
metadata: Record<string, string>;
|
|
75
|
+
}
|
|
76
|
+
export declare class FakeStripe {
|
|
77
|
+
readonly customers: Map<string, FakeCustomer>;
|
|
78
|
+
readonly invoiceItems: Map<string, FakeInvoiceItem>;
|
|
79
|
+
readonly invoices: Map<string, FakeInvoice>;
|
|
80
|
+
readonly sessions: Map<string, FakeSession>;
|
|
81
|
+
readonly paymentIntents: Map<string, FakePaymentIntent>;
|
|
82
|
+
/** False while Stripe's search index lags behind writes. */
|
|
83
|
+
searchable: boolean;
|
|
84
|
+
/** Behavior of each saved payment method (default `succeed`). */
|
|
85
|
+
readonly cards: Map<string, FakeCardBehavior>;
|
|
86
|
+
readonly subscriptions: Map<string, Record<string, unknown>>;
|
|
87
|
+
readonly requests: Array<{
|
|
88
|
+
method: string;
|
|
89
|
+
path: string;
|
|
90
|
+
key?: string;
|
|
91
|
+
}>;
|
|
92
|
+
private readonly idempotent;
|
|
93
|
+
private failures;
|
|
94
|
+
private counter;
|
|
95
|
+
private nextId;
|
|
96
|
+
/** Make the next matching request(s) fail. */
|
|
97
|
+
fail(method: string, path: RegExp, when?: 'before' | 'after', times?: number): void;
|
|
98
|
+
provider(): Promise<StripeAccountingProvider>;
|
|
99
|
+
readonly fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
100
|
+
private route;
|
|
101
|
+
private applyCustomer;
|
|
102
|
+
private recalculate;
|
|
103
|
+
private customerView;
|
|
104
|
+
private sessionView;
|
|
105
|
+
private view;
|
|
106
|
+
/** Customer pays an open invoice in full. */
|
|
107
|
+
pay(invoiceId: string): void;
|
|
108
|
+
/**
|
|
109
|
+
* Stripe's automatic collection of a finalized `charge_automatically`
|
|
110
|
+
* invoice: charges the customer's default card. Returns the outcome.
|
|
111
|
+
*/
|
|
112
|
+
collect(invoiceId: string): 'paid' | 'failed';
|
|
113
|
+
/**
|
|
114
|
+
* The customer finishes a checkout: a payment session is paid with tax
|
|
115
|
+
* from the collected (or customer) address; a setup session saves
|
|
116
|
+
* `paymentMethod`. A collected address is saved to the customer when the
|
|
117
|
+
* session asked to.
|
|
118
|
+
*/
|
|
119
|
+
completeSession(sessionId: string, options?: {
|
|
120
|
+
paymentMethod?: string;
|
|
121
|
+
address?: Record<string, string>;
|
|
122
|
+
}): FakeSession;
|
|
123
|
+
private createPaymentIntent;
|
|
124
|
+
/** A processing PaymentIntent settles (Stripe then sends its event). */
|
|
125
|
+
settlePaymentIntent(intentId: string, status: 'succeeded' | 'failed'): FakePaymentIntent;
|
|
126
|
+
setInvoiceStatus(invoiceId: string, status: FakeInvoice['status']): void;
|
|
127
|
+
lineItemsOf(invoiceId: string): FakeInvoiceItem[];
|
|
128
|
+
}
|
|
129
|
+
/** A signed Stripe webhook delivery for `event`. */
|
|
130
|
+
export declare function signedEvent(event: Record<string, unknown>): {
|
|
131
|
+
payload: string;
|
|
132
|
+
signature: string;
|
|
133
|
+
};
|
|
134
|
+
export declare function invoiceEvent(type: string, invoiceId: string): Record<string, unknown>;
|
|
135
|
+
export declare function checkoutEvent(session: {
|
|
136
|
+
id: string;
|
|
137
|
+
mode?: string;
|
|
138
|
+
currency: string | null;
|
|
139
|
+
amount_subtotal: number | null;
|
|
140
|
+
amount_total?: number | null;
|
|
141
|
+
metadata: Record<string, string>;
|
|
142
|
+
}, paymentStatus?: string, type?: string): Record<string, unknown>;
|
|
143
|
+
/** A `payment_intent.*` event for a PaymentIntent the fake holds. */
|
|
144
|
+
export declare function paymentIntentEvent(type: string, intent: Record<string, unknown>): Record<string, unknown>;
|
|
145
|
+
export declare function subscriptionEvent(type: string, subscriptionId: string): Record<string, unknown>;
|
|
146
|
+
export {};
|
|
147
|
+
//# sourceMappingURL=fake-stripe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-stripe.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/fake-stripe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BTCPay Server as a crypto payment rail (#3138): sugar over
|
|
3
|
+
* {@link createCryptoBillingProvider} with the SDK's BTCPay checkout gateway.
|
|
4
|
+
* One BTCPay store per seller; keys and secrets come from the host's secret
|
|
5
|
+
* store, never from this package.
|
|
6
|
+
*/
|
|
7
|
+
import { type BtcpayClientOptions, type BtcpaySpeedPolicy } from '@happyvertical/payments/btcpay';
|
|
8
|
+
import type { BillingProvider } from './provider.js';
|
|
9
|
+
export interface BtcPayBillingProviderOptions {
|
|
10
|
+
/** Server origin, for example `https://btcpay.example.com`. */
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
/** Store-scoped key: `canviewinvoices` + `cancreateinvoice` suffice. */
|
|
13
|
+
apiKey: string;
|
|
14
|
+
storeId: string;
|
|
15
|
+
/** The store webhook's secret. */
|
|
16
|
+
webhookSecret: string;
|
|
17
|
+
/** Secret signing the `smrt_*` checkout metadata. */
|
|
18
|
+
metadataSecret: string;
|
|
19
|
+
/**
|
|
20
|
+
* Confirmations before BTCPay settles on-chain: `HighSpeed` 0,
|
|
21
|
+
* `MediumSpeed` 1, `LowMediumSpeed` 2 (default, the owner's settlement
|
|
22
|
+
* policy), `LowSpeed` 6.
|
|
23
|
+
*/
|
|
24
|
+
speedPolicy?: BtcpaySpeedPolicy;
|
|
25
|
+
/** Default `['BTC-CHAIN']`; add `BTC-LN` once the store has Lightning. */
|
|
26
|
+
paymentMethods?: string[];
|
|
27
|
+
expirationMinutes?: number;
|
|
28
|
+
monitoringMinutes?: number;
|
|
29
|
+
/** BTCPay's own underpayment tolerance, percent (default 0). */
|
|
30
|
+
paymentTolerance?: number;
|
|
31
|
+
/** Label of the store's rate source, recorded on every payment. */
|
|
32
|
+
rateSource?: string;
|
|
33
|
+
/** Minimum checkout per currency, minor units. */
|
|
34
|
+
minimumAmount?: Record<string, number>;
|
|
35
|
+
/** Provider name (default `btcpay`). */
|
|
36
|
+
name?: string;
|
|
37
|
+
fetch?: BtcpayClientOptions['fetch'];
|
|
38
|
+
}
|
|
39
|
+
export declare function createBtcPayBillingProvider(options: BtcPayBillingProviderOptions): BillingProvider;
|
|
40
|
+
//# sourceMappingURL=btcpay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btcpay.d.ts","sourceRoot":"","sources":["../../src/billing/btcpay.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EAEvB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,WAAW,4BAA4B;IAC3C,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;CACtC;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B,GACpC,eAAe,CAsBjB"}
|
package/dist/billing/cards.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Card on file (#3139): a provider checkout that saves a payment method
|
|
3
|
+
* without charging, and the settlement that makes it the payer's default.
|
|
4
|
+
*
|
|
5
|
+
* A completed setup (or a credit purchase that saved its card) is applied
|
|
6
|
+
* from the provider's checkout event: `observe()` re-reads the session and
|
|
7
|
+
* makes the saved method the provider customer's default; `project()`
|
|
8
|
+
* records it as the payer customer's default commerce `PaymentInstrument`
|
|
9
|
+
* and adopts the billing address collected at checkout as the tax location.
|
|
10
|
+
*/
|
|
11
|
+
import type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';
|
|
12
|
+
import type { BillingAccount } from '../models/billing.js';
|
|
13
|
+
import type { BillingProviderCheckoutSession, BillingProviderCheckoutState } from './provider.js';
|
|
14
|
+
import type { BillingRuntime } from './runtime.js';
|
|
5
15
|
export declare const CARD_SETUP_PURPOSE = "card_setup";
|
|
6
16
|
/** Checkout metadata flag: the session saves its payment method. */
|
|
7
17
|
export declare const SAVE_CARD_METADATA = "smrt_save_card";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BillingProviderCheckoutSession } from './provider.js';
|
|
2
|
-
import { BillingRuntime } from './runtime.js';
|
|
1
|
+
import { type BillingProviderCheckoutSession } from './provider.js';
|
|
2
|
+
import type { BillingRuntime } from './runtime.js';
|
|
3
3
|
export declare const CREDIT_PURCHASE_PURPOSE = "credit_purchase";
|
|
4
4
|
export interface CreateCreditCheckoutInput {
|
|
5
5
|
/** The `period: 'balance'` spending policy to credit. */
|
|
@@ -27,6 +27,11 @@ export interface CreateCreditCheckoutInput {
|
|
|
27
27
|
* automatically charged invoices (#3139).
|
|
28
28
|
*/
|
|
29
29
|
savePaymentMethod?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The payment rail to pay with (a provider name from the runtime's
|
|
32
|
+
* `provider` or `paymentProviders`; default the issuing provider, #3138).
|
|
33
|
+
*/
|
|
34
|
+
provider?: string;
|
|
30
35
|
}
|
|
31
36
|
/** The checkout metadata a completed purchase is settled from. */
|
|
32
37
|
export interface CreditPurchaseMetadata {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../src/billing/credits.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../src/billing/credits.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,KAAK,8BAA8B,EAEpC,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAQnD,eAAO,MAAM,uBAAuB,oBAAoB,CAAC;AAEzD,MAAM,WAAW,yBAAyB;IACxC,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAuBD,uEAAuE;AACvE,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,sBAAsB,GAAG,IAAI,CAwB/B;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,8BAA8B,CAAC,CAwHzC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A crypto payment rail for the {@link BillingProvider} port (#3138).
|
|
3
|
+
*
|
|
4
|
+
* The rail runs short-lived, fiat-priced checkouts through a
|
|
5
|
+
* `CryptoCheckoutGateway` from `@happyvertical/payments` — BTCPay at launch,
|
|
6
|
+
* any other implementation of the port later. It never issues invoices: the
|
|
7
|
+
* runtime's issuing provider (Stripe) does, and this rail pays them or buys
|
|
8
|
+
* prepaid credit. Settlement is the gateway's decision (its confirmation
|
|
9
|
+
* policy); this package never counts confirmations.
|
|
10
|
+
*/
|
|
11
|
+
import { type CryptoCheckoutGateway } from '@happyvertical/payments';
|
|
12
|
+
import { type BillingProvider } from './provider.js';
|
|
13
|
+
export interface CryptoBillingProviderOptions {
|
|
14
|
+
/** A checkout gateway, for example `createBtcpayCheckoutGateway()`. */
|
|
15
|
+
gateway: CryptoCheckoutGateway;
|
|
16
|
+
/**
|
|
17
|
+
* Secret the `smrt_*` checkout metadata is signed with. Rotating it
|
|
18
|
+
* strands checkouts created before the rotation.
|
|
19
|
+
*/
|
|
20
|
+
metadataSecret: string;
|
|
21
|
+
/** Provider name on local rows and in the inbox (default the gateway id). */
|
|
22
|
+
name?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Smallest checkout accepted, per currency, in minor units (fee and dust
|
|
25
|
+
* economics). A currency without an entry has no minimum.
|
|
26
|
+
*/
|
|
27
|
+
minimumAmount?: Record<string, number>;
|
|
28
|
+
}
|
|
29
|
+
export declare function createCryptoBillingProvider(options: CryptoBillingProviderOptions): BillingProvider;
|
|
30
|
+
/** Exact decimal string → integer atomic units; rejects excess precision. */
|
|
31
|
+
export declare function decimalToAtomic(value: string, exponent: number): number;
|
|
32
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/billing/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAEL,KAAK,qBAAqB,EAG3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGL,KAAK,eAAe,EAMrB,MAAM,eAAe,CAAC;AASvB,MAAM,WAAW,4BAA4B;IAC3C,uEAAuE;IACvE,OAAO,EAAE,qBAAqB,CAAC;IAC/B;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAKD,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B,GACpC,eAAe,CAqHjB;AAkED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYvE"}
|