@owlmeans/server-payment 0.1.18-rc.11 → 0.1.18-rc.12
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 +47 -7
- package/build/config.d.ts +15 -1
- package/build/config.d.ts.map +1 -1
- package/build/config.js +26 -2
- package/build/config.js.map +1 -1
- package/build/consts.d.ts +10 -0
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +10 -0
- package/build/consts.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/plugins/estimate.d.ts +43 -0
- package/build/plugins/estimate.d.ts.map +1 -0
- package/build/plugins/estimate.js +225 -0
- package/build/plugins/estimate.js.map +1 -0
- package/build/plugins/events.d.ts.map +1 -1
- package/build/plugins/events.js +3 -1
- package/build/plugins/events.js.map +1 -1
- package/build/plugins/portal.d.ts.map +1 -1
- package/build/plugins/portal.js +6 -2
- package/build/plugins/portal.js.map +1 -1
- package/build/plugins/stripe.d.ts +2 -1
- package/build/plugins/stripe.d.ts.map +1 -1
- package/build/plugins/stripe.js +35 -16
- package/build/plugins/stripe.js.map +1 -1
- package/build/service.d.ts.map +1 -1
- package/build/service.js +6 -0
- package/build/service.js.map +1 -1
- package/build/sync.d.ts +5 -0
- package/build/sync.d.ts.map +1 -1
- package/build/sync.js +63 -8
- package/build/sync.js.map +1 -1
- package/build/types.d.ts +30 -1
- package/build/types.d.ts.map +1 -1
- package/build/utils.d.ts +3 -1
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +3 -1
- package/build/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/config.ts +33 -5
- package/src/consts.ts +11 -0
- package/src/index.ts +2 -0
- package/src/plugins/estimate.ts +298 -0
- package/src/plugins/events.ts +3 -1
- package/src/plugins/portal.ts +6 -2
- package/src/plugins/stripe.ts +37 -16
- package/src/service.ts +6 -0
- package/src/sync.ts +75 -8
- package/src/types.ts +33 -2
- package/src/utils.ts +6 -2
- package/tests/checkout.spec.ts +65 -2
- package/tests/estimate.spec.ts +218 -0
- package/tests/events.spec.ts +13 -0
- package/tests/fake-stripe.ts +123 -6
- package/tests/portal.spec.ts +19 -2
- package/tests/sync.spec.ts +88 -0
package/README.md
CHANGED
|
@@ -130,7 +130,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
130
130
|
your project's skill store (`.agents/skills/`):
|
|
131
131
|
|
|
132
132
|
```sh
|
|
133
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
133
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.29
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/server-payment",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.12",
|
|
5
|
+
"generatedAt": "2026-09-18T19:03:53.989Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -7,7 +7,7 @@ user-invocable: false
|
|
|
7
7
|
|
|
8
8
|
# @owlmeans/server-payment
|
|
9
9
|
|
|
10
|
-
**Install:** `bun add @owlmeans/server-payment@^0.1.18-rc.
|
|
10
|
+
**Install:** `bun add @owlmeans/server-payment@^0.1.18-rc.12`
|
|
11
11
|
|
|
12
12
|
Public MIT package. It embeds Stripe into an application backend and owns everything between
|
|
13
13
|
Stripe and an entity's entitlements: the subscription store, one-time fulfillments, the usage
|
|
@@ -22,6 +22,10 @@ the `entitlements` skill.
|
|
|
22
22
|
```typescript
|
|
23
23
|
stripeSecrets(cfg, { api: '/secrets/stripe-key' }) // webhook secret: optional override
|
|
24
24
|
portalBranding(cfg, { returnUrl: 'https://app.example.com/billing', headline: 'Example' })
|
|
25
|
+
declarePaymentPricing(cfg, { // absent entirely: today's fixed behaviour, unchanged
|
|
26
|
+
tax: { automatic: true, behavior: TaxBehavior.Exclusive, collectTaxId: true, estimate: true },
|
|
27
|
+
currency: { adaptive: true, estimate: true },
|
|
28
|
+
})
|
|
25
29
|
declarePaymentProduct(cfg, { sku: 'app-plans', type: ProductType.Service, services: ['app'], name: 'Plans' })
|
|
26
30
|
declarePaymentPlan(cfg, { productSku: 'app-plans', sku: 'free', rank: 0, free: true, price: 0, … })
|
|
27
31
|
declarePaymentPlan(cfg, { productSku: 'app-plans', sku: 'pro-monthly', rank: 10, price: 20,
|
|
@@ -82,19 +86,49 @@ does not know as a string, and the collection validator rejects it.
|
|
|
82
86
|
|
|
83
87
|
## Checkout and fulfillment
|
|
84
88
|
|
|
85
|
-
- `Amount`: one inline `price_data` item for the synchronized product, quantity 1,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
- `Amount`: one inline `price_data` item for the synchronized product, quantity 1, its `tax_behavior`
|
|
90
|
+
the declared `PricingPolicy.tax.behavior` (default `'exclusive'`), no promotion codes; the net
|
|
91
|
+
`amountMinor` and the grossed-up `chargeAmountMinor` travel in the session metadata. `Quantity`:
|
|
92
|
+
the reusable price under the plan lookup key, adjustable quantity. Subscription: `planSku` (else
|
|
93
|
+
the product's first recurring plan), quantity 1.
|
|
89
94
|
- A plan the paygate does not sell — a free plan, another gateway's plan — is refused
|
|
90
|
-
(`ProductError`).
|
|
95
|
+
(`ProductError`). `checkoutOptions(policy, promotions)` puts automatic tax, billing address
|
|
96
|
+
collection, tax-id collection and Adaptive Pricing (`adaptive_pricing`) on the session, each
|
|
97
|
+
independently, exactly as `PricingPolicy` declares them — an undeclared policy reproduces the
|
|
98
|
+
fixed pre-policy session (automatic tax + tax-id collection on, no Adaptive Pricing).
|
|
91
99
|
- `checkout.session.completed` and `…async_payment_succeeded` fulfill only a `payment`-mode session
|
|
92
100
|
with `payment_status === 'paid'`; an amount session must match its metadata currency and subtotal.
|
|
101
|
+
Adaptive Pricing never disturbs this: Session/webhook amounts stay in the integration currency
|
|
102
|
+
(USD here) whatever currency the buyer paid in.
|
|
93
103
|
- A pending `payment-fulfillment` row (with `paymentIntentId` and `invoiceId`) is written before
|
|
94
104
|
observers run; `fulfilledAt` is stamped after they succeed. An observer throw escapes so Stripe
|
|
95
105
|
redelivers, and the observer must stay idempotent by `externalId` — a crash after its side effect
|
|
96
106
|
and before the stamp redelivers the same session.
|
|
97
107
|
|
|
108
|
+
## Price sync and the tax estimate
|
|
109
|
+
|
|
110
|
+
- `syncStripeProducts` gives a matching, still-`unspecified` price the declared `tax.behavior` IN
|
|
111
|
+
PLACE (`prices.update`; Stripe forbids changing a price already `exclusive`/`inclusive`) and a
|
|
112
|
+
fresh one on creation; a price already carrying the OPPOSITE behavior is deactivated and replaced,
|
|
113
|
+
the same as any other catalogue mismatch. Before an in-place update it checks the account's own
|
|
114
|
+
tax-settings default (`stripe.tax.settings.retrieve`) and skips the update — logging why — when
|
|
115
|
+
that default would make the price behave the other way for existing renewals, unless
|
|
116
|
+
`declarePaymentPricing({ stripe: { migrateUnspecifiedPrices: true } })` opts in. The behavior is
|
|
117
|
+
part of the sync fingerprint, so declaring or changing it re-syncs every product exactly once.
|
|
118
|
+
- `GatewayService.estimatePrice(ctx, { entityId, productSku, planSku?, country? })` (`estimatePrice`
|
|
119
|
+
in `plugins/estimate.ts`) is a Stripe Tax calculation (plus, with `currency.estimate` and
|
|
120
|
+
`currency.adaptive` both on, an FX Quotes lookup) for one product/plan's reference amount, at a
|
|
121
|
+
billing country the request names or the entity's paygate customer's. **$0.05 per distinct**
|
|
122
|
+
(currency, country, amount, tax code, behavior, matching tax ids) **combination** — cached per
|
|
123
|
+
gateway-service instance (never module-level: several instances in one process, as in tests, must
|
|
124
|
+
never share hits) for 24h; a rate-limit or connection error is never cached. Its status
|
|
125
|
+
(`TaxEstimateStatus`) covers a resolved rate, EU/GB reverse charge (a saved tax id whose OWN
|
|
126
|
+
country matches the one being estimated), no tax, "compute at checkout" (an unsupported
|
|
127
|
+
jurisdiction, or an invalid-request error such as a US address with no postal code), and
|
|
128
|
+
"choose a country" (neither the request nor the customer names one — zero Stripe calls). The FX
|
|
129
|
+
Quotes call is a Stripe PREVIEW endpoint (`STRIPE_FX_QUOTES_API_VERSION`, `stripe.rawRequest`),
|
|
130
|
+
and its failure only drops the estimate's `local` field, never the tax half.
|
|
131
|
+
|
|
98
132
|
## The subscription store
|
|
99
133
|
|
|
100
134
|
- **The effective plan** is the highest-ranked row in `ENTITLING_STATUSES` (catalogue rank; the
|
|
@@ -183,7 +217,9 @@ and logged when it fails.
|
|
|
183
217
|
price switching between every product's active recurring prices with prorations — both
|
|
184
218
|
subscription features off when nothing recurring is sold. `portalBranding` supplies the business
|
|
185
219
|
profile and default return URL; fingerprint `portal:<service>` holds its id, and its hash covers
|
|
186
|
-
the catalogue
|
|
220
|
+
the catalogue (including the declared tax behavior — a price `sync.ts` replaces refreshes the
|
|
221
|
+
portal's `products[].prices` too), the branding and the deployment key, so an unchanged
|
|
222
|
+
declaration makes no call.
|
|
187
223
|
- **Each deployment owns its own portal configuration**, tagged
|
|
188
224
|
`{ owlmeans: 'payment', service, deployment: webhookUrlOf(ctx) }` (`STRIPE_DEPLOYMENT_KEY`) — the
|
|
189
225
|
webhook URL keys it even when undeliverable (local). The configuration the fingerprint row names
|
|
@@ -286,6 +322,10 @@ database.
|
|
|
286
322
|
- https://docs.stripe.com/api/subscriptions/object — statuses `incomplete|incomplete_expired|trialing|active|past_due|canceled|unpaid|paused`; `pause_collection` pauses collection without changing the status; `paused` only after a trial without a payment method; on `2025-02-24.acacia` (stripe-node 17) `current_period_start/end` and `invoice.subscription` are top-level and move in later versions.
|
|
287
323
|
- https://docs.stripe.com/customer-management/portal-deep-links and https://docs.stripe.com/api/customer_portal/sessions/create — `flow_data.type` ∈ `payment_method_update|subscription_cancel|subscription_update|subscription_update_confirm`; `subscription_update_confirm.items` holds exactly one `{ id: <subscription item id>, price, quantity }`; `after_completion` is `redirect|hosted_confirmation|portal_homepage`; the configuration must enable `subscription_update` (with `products[{product, prices[]}]`) and `subscription_cancel`.
|
|
288
324
|
- https://docs.stripe.com/api/customer_portal/configurations/create — `features.{customer_update, invoice_history, payment_method_update, subscription_cancel{enabled, mode, proration_behavior}, subscription_update{enabled, default_allowed_updates, products, proration_behavior}}`, `business_profile`, `default_return_url`, `metadata`; updatable by id, retrievable and listable (`active`, paginated), and never deletable — a configuration can only be deactivated.
|
|
325
|
+
- https://docs.stripe.com/api/tax/calculations/create — `line_items[].tax_behavior` (default `exclusive`), `tax_code`; `customer_details.address_source` ∈ `billing|shipping`; `tax_ids[]` shifts liability (a valid id is never validated for correctness); the response's `tax_breakdown[].tax_rate_details.percentage_decimal` is a STRING (parse it exactly, never `Number(x) * 10_000`) and `.rate_type` ∈ `flat_amount|percentage` (a flat rate never scales with the amount).
|
|
326
|
+
- https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior — a price's `tax_behavior` can be set only from `unspecified`; once `exclusive`/`inclusive` it cannot change, and `inferred_by_currency` (an account tax-settings default) resolves to exclusive for USD/CAD, inclusive otherwise.
|
|
327
|
+
- https://docs.stripe.com/payments/currencies/localize-prices/adaptive-pricing — `adaptive_pricing.enabled` on a Checkout Session; requires the price currency to be a settlement currency; Session/PaymentIntent/webhook amounts stay in the integration currency, with `presentment_details.{presentment_amount, presentment_currency}` alongside them when the buyer paid differently.
|
|
328
|
+
- https://docs.stripe.com/api/fx_quotes/create — a **preview** endpoint (needs a preview `Stripe-Version`, called via `stripe.rawRequest`); `to_currency`/`from_currencies[]`; `lock_duration: 'none'` is free, `five_minutes|hour|day` add a fee (`rate_details.duration_premium`) baked into `exchange_rate`.
|
|
289
329
|
|
|
290
330
|
## Related
|
|
291
331
|
|
package/build/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Config, PaymentPlan, PaymentPlanDef, PaymentProductDef, PortalBrandingDef, StripeSecretsDef } from './types.js';
|
|
1
|
+
import type { Config, PaymentPlan, PaymentPlanDef, PaymentProductDef, PortalBrandingDef, PricingDef, StripeSecretsDef } from './types.js';
|
|
2
2
|
export declare const declarePaymentProduct: (cfg: Config, def: PaymentProductDef) => void;
|
|
3
3
|
/**
|
|
4
4
|
* Declare a plan into the configuration catalogue.
|
|
@@ -32,4 +32,18 @@ export declare const assertPlanDeclarations: (cfg: Config) => void;
|
|
|
32
32
|
export declare const stripeSecrets: (cfg: Config, paths: StripeSecretsDef) => void;
|
|
33
33
|
/** Branding and the default return URL of the managed customer portal configuration. */
|
|
34
34
|
export declare const portalBranding: (cfg: Config, def: PortalBrandingDef) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Declare the pricing policy: whether checkout collects tax and a VAT/GST id, what `tax_behavior`
|
|
37
|
+
* synced prices are given, Adaptive Pricing, and whether the estimate endpoints are served. A
|
|
38
|
+
* config never carries more than one — a second call replaces the first, so re-declaring (a test, a
|
|
39
|
+
* config module re-run) is safe rather than silently ignored (a config resource resolves an id to
|
|
40
|
+
* its FIRST match).
|
|
41
|
+
*
|
|
42
|
+
* `def.stripe` (the FX Quotes preview version, the unspecified-price migration switch) is
|
|
43
|
+
* Stripe-only and goes to a backend plugin, never the advertised `PricingPolicy` record.
|
|
44
|
+
*
|
|
45
|
+
* @throws PaymentError (`assertPricingPolicy`) when an estimate is declared without the tax or
|
|
46
|
+
* currency capability it requires.
|
|
47
|
+
*/
|
|
48
|
+
export declare const declarePaymentPricing: (cfg: Config, def: PricingDef) => void;
|
|
35
49
|
//# sourceMappingURL=config.d.ts.map
|
package/build/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,MAAM,EAAE,WAAW,EAAE,cAAc,EAAkB,iBAAiB,EAAE,iBAAiB,EACzF,UAAU,EAAE,gBAAgB,EAC7B,MAAM,YAAY,CAAA;AAEnB,eAAO,MAAM,qBAAqB,QAAS,MAAM,OAAO,iBAAiB,KAAG,IAS3E,CAAA;AA8BD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,QAAS,MAAM,OAAO,cAAc,KAAG,IA2CrE,CAAA;AAED,gDAAgD;AAChD,eAAO,MAAM,eAAe,QAAS,MAAM,KAAG,WAAW,EACiD,CAAA;AAE1G;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,QAAS,MAAM,KAAG,IAmBpD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,QAAS,MAAM,SAAS,gBAAgB,KAAG,IAIpE,CAAA;AAED,wFAAwF;AACxF,eAAO,MAAM,cAAc,QAAS,MAAM,OAAO,iBAAiB,KAAG,IAOpE,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,QAAS,MAAM,OAAO,UAAU,KAAG,IAUpE,CAAA"}
|
package/build/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { toConfigRecord } from '@owlmeans/server-app';
|
|
2
2
|
import { plugin } from '@owlmeans/config';
|
|
3
|
-
import { assertAmountCheckoutPolicy, assertQuantityCheckoutPolicy, CAPABILITY_LIMIT_SCOPE, CheckoutPricingMode, LimitKind, LimitMisdeclared, LimitWindow, PLAN_RECORD_PREFIX, PLAN_RECORD_TYPE, PlanDuration, PlanRankConflict, PlanStatus, PRODUCT_RECORD_PREFIX, PRODUCT_RECORD_TYPE, } from '@owlmeans/payment';
|
|
4
|
-
import { STRIPE_PAYGATE_ALIAS, STRIPE_PLUGIN_CONFIG, STRIPE_PORTAL_PLUGIN_CONFIG } from './consts.js';
|
|
3
|
+
import { assertAmountCheckoutPolicy, assertPricingPolicy, assertQuantityCheckoutPolicy, CAPABILITY_LIMIT_SCOPE, CheckoutPricingMode, LimitKind, LimitMisdeclared, LimitWindow, PLAN_RECORD_PREFIX, PLAN_RECORD_TYPE, PlanDuration, PlanRankConflict, PlanStatus, PRICING_POLICY_RECORD_ID, PRICING_POLICY_RECORD_TYPE, PRODUCT_RECORD_PREFIX, PRODUCT_RECORD_TYPE, } from '@owlmeans/payment';
|
|
4
|
+
import { STRIPE_PAYGATE_ALIAS, STRIPE_PLUGIN_CONFIG, STRIPE_PORTAL_PLUGIN_CONFIG, STRIPE_PRICING_PLUGIN_CONFIG, } from './consts.js';
|
|
5
5
|
export const declarePaymentProduct = (cfg, def) => {
|
|
6
6
|
cfg.records = cfg.records ?? [];
|
|
7
7
|
const product = {
|
|
@@ -141,4 +141,28 @@ export const portalBranding = (cfg, def) => {
|
|
|
141
141
|
...(def.termsOfServiceUrl != null ? { termsOfServiceUrl: def.termsOfServiceUrl } : {}),
|
|
142
142
|
}, STRIPE_PORTAL_PLUGIN_CONFIG);
|
|
143
143
|
};
|
|
144
|
+
/**
|
|
145
|
+
* Declare the pricing policy: whether checkout collects tax and a VAT/GST id, what `tax_behavior`
|
|
146
|
+
* synced prices are given, Adaptive Pricing, and whether the estimate endpoints are served. A
|
|
147
|
+
* config never carries more than one — a second call replaces the first, so re-declaring (a test, a
|
|
148
|
+
* config module re-run) is safe rather than silently ignored (a config resource resolves an id to
|
|
149
|
+
* its FIRST match).
|
|
150
|
+
*
|
|
151
|
+
* `def.stripe` (the FX Quotes preview version, the unspecified-price migration switch) is
|
|
152
|
+
* Stripe-only and goes to a backend plugin, never the advertised `PricingPolicy` record.
|
|
153
|
+
*
|
|
154
|
+
* @throws PaymentError (`assertPricingPolicy`) when an estimate is declared without the tax or
|
|
155
|
+
* currency capability it requires.
|
|
156
|
+
*/
|
|
157
|
+
export const declarePaymentPricing = (cfg, def) => {
|
|
158
|
+
const { stripe, ...policy } = def;
|
|
159
|
+
assertPricingPolicy(policy);
|
|
160
|
+
cfg.records = (cfg.records ?? []).filter(record => record.id !== PRICING_POLICY_RECORD_ID);
|
|
161
|
+
cfg.records.push({
|
|
162
|
+
...toConfigRecord(policy), recordType: PRICING_POLICY_RECORD_TYPE, id: PRICING_POLICY_RECORD_ID,
|
|
163
|
+
});
|
|
164
|
+
if (stripe != null) {
|
|
165
|
+
plugin(cfg, { ...stripe }, STRIPE_PRICING_PLUGIN_CONFIG);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
144
168
|
//# sourceMappingURL=config.js.map
|
package/build/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EACL,0BAA0B,EAAE,4BAA4B,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/build/consts.d.ts
CHANGED
|
@@ -3,7 +3,17 @@ export { INTERNAL_PAYGATE, LIMIT_GATE };
|
|
|
3
3
|
export declare const STRIPE_PAYGATE_ALIAS = "stripe";
|
|
4
4
|
export declare const STRIPE_PLUGIN_CONFIG = "_external:stripe";
|
|
5
5
|
export declare const STRIPE_PORTAL_PLUGIN_CONFIG = "_external:stripe-portal";
|
|
6
|
+
/** Stripe-only pricing settings (FX Quotes API version, the unspecified-price migration switch) — never advertised to the browser, unlike the `PricingPolicy` record itself. */
|
|
7
|
+
export declare const STRIPE_PRICING_PLUGIN_CONFIG = "_external:stripe-pricing";
|
|
6
8
|
export declare const STRIPE_SIGNATURE = "Stripe-Signature";
|
|
9
|
+
/**
|
|
10
|
+
* The FX Quotes API is a Stripe PREVIEW endpoint as of this writing: it answers only a
|
|
11
|
+
* `Stripe-Version` header naming a preview version, never the SDK's pinned stable one. Verify this
|
|
12
|
+
* string against https://docs.stripe.com/api/fx_quotes/create before relying on it, and override it
|
|
13
|
+
* with `declarePaymentPricing({ stripe: { fxApiVersion } })` once Stripe moves the API or renames
|
|
14
|
+
* the preview.
|
|
15
|
+
*/
|
|
16
|
+
export declare const STRIPE_FX_QUOTES_API_VERSION = "2025-07-30.preview";
|
|
7
17
|
export declare const GATEWAY_SERVICE = "payment-gateway";
|
|
8
18
|
export declare const PAYMENT_OBSERVER = "payment-observer";
|
|
9
19
|
export declare const ENTITLEMENT_SERVICE = "payment-entitlement";
|
package/build/consts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAGhE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAA;AAEvC,eAAO,MAAM,oBAAoB,WAAW,CAAA;AAC5C,eAAO,MAAM,oBAAoB,qBAAqB,CAAA;AACtD,eAAO,MAAM,2BAA2B,4BAA4B,CAAA;AACpE,eAAO,MAAM,gBAAgB,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAGhE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAA;AAEvC,eAAO,MAAM,oBAAoB,WAAW,CAAA;AAC5C,eAAO,MAAM,oBAAoB,qBAAqB,CAAA;AACtD,eAAO,MAAM,2BAA2B,4BAA4B,CAAA;AACpE,gLAAgL;AAChL,eAAO,MAAM,4BAA4B,6BAA6B,CAAA;AACtE,eAAO,MAAM,gBAAgB,qBAAqB,CAAA;AAElD;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,uBAAuB,CAAA;AAChE,eAAO,MAAM,eAAe,oBAAoB,CAAA;AAChD,eAAO,MAAM,gBAAgB,qBAAqB,CAAA;AAClD,eAAO,MAAM,mBAAmB,wBAAwB,CAAA;AAExD,eAAO,MAAM,oBAAoB,6BAA6B,CAAA;AAC9D,eAAO,MAAM,wBAAwB,yBAAyB,CAAA;AAC9D,eAAO,MAAM,uBAAuB,wBAAwB,CAAA;AAC5D,eAAO,MAAM,mBAAmB,oBAAoB,CAAA;AACpD,eAAO,MAAM,iBAAiB,kBAAkB,CAAA;AAChD,eAAO,MAAM,yBAAyB,0BAA0B,CAAA;AAChE,eAAO,MAAM,uBAAuB,wBAAwB,CAAA;AAE5D,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,WAAW,CAAA;AAE1C;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,aAAa,CAAA;AAC1C,eAAO,MAAM,kBAAkB,YAAY,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAA;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAY1C,CAAA;AAEF,MAAM,WAAW,aAAa;IAAG,OAAO,EAAE,MAAM,CAAA;CAAE;AAClD,MAAM,WAAW,YAAY;IAAG,EAAE,EAAE,OAAO,CAAA;CAAE;AAC7C,MAAM,WAAW,yBAAyB;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAyB/E,qFAAqF;AACrF,eAAO,MAAM,WAAW;;IAEtB,yFAAyF;;;;IAKzF,mFAAmF;;IAMnF,+EAA+E;;CAMvE,CAAA"}
|
package/build/consts.js
CHANGED
|
@@ -6,7 +6,17 @@ export { INTERNAL_PAYGATE, LIMIT_GATE };
|
|
|
6
6
|
export const STRIPE_PAYGATE_ALIAS = 'stripe';
|
|
7
7
|
export const STRIPE_PLUGIN_CONFIG = '_external:stripe';
|
|
8
8
|
export const STRIPE_PORTAL_PLUGIN_CONFIG = '_external:stripe-portal';
|
|
9
|
+
/** Stripe-only pricing settings (FX Quotes API version, the unspecified-price migration switch) — never advertised to the browser, unlike the `PricingPolicy` record itself. */
|
|
10
|
+
export const STRIPE_PRICING_PLUGIN_CONFIG = '_external:stripe-pricing';
|
|
9
11
|
export const STRIPE_SIGNATURE = 'Stripe-Signature';
|
|
12
|
+
/**
|
|
13
|
+
* The FX Quotes API is a Stripe PREVIEW endpoint as of this writing: it answers only a
|
|
14
|
+
* `Stripe-Version` header naming a preview version, never the SDK's pinned stable one. Verify this
|
|
15
|
+
* string against https://docs.stripe.com/api/fx_quotes/create before relying on it, and override it
|
|
16
|
+
* with `declarePaymentPricing({ stripe: { fxApiVersion } })` once Stripe moves the API or renames
|
|
17
|
+
* the preview.
|
|
18
|
+
*/
|
|
19
|
+
export const STRIPE_FX_QUOTES_API_VERSION = '2025-07-30.preview';
|
|
10
20
|
export const GATEWAY_SERVICE = 'payment-gateway';
|
|
11
21
|
export const PAYMENT_OBSERVER = 'payment-observer';
|
|
12
22
|
export const ENTITLEMENT_SERVICE = 'payment-entitlement';
|
package/build/consts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAGhE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAA;AAEvC,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAA;AAC5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAA;AACtD,MAAM,CAAC,MAAM,2BAA2B,GAAG,yBAAyB,CAAA;AACpE,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export { classifySubscriptionChange, commitSubscription, propagatedStateOf, subs
|
|
|
15
15
|
export type { CommitOptions, CommitResult } from './subscription.js';
|
|
16
16
|
export { planLookupKey, syncPaymentProducts, syncStripeProducts } from './sync.js';
|
|
17
17
|
export { amountCheckoutLineItem, quantityCheckoutLineItem } from './plugins/stripe.js';
|
|
18
|
+
export { makeEstimateCache, estimateStripePrice } from './plugins/estimate.js';
|
|
19
|
+
export type { EstimateCache } from './plugins/estimate.js';
|
|
18
20
|
export { applySubscription, createEventHandler, mapStatus } from './plugins/events.js';
|
|
19
21
|
export type { ApplyOptions } from './plugins/events.js';
|
|
20
22
|
export { ensureWebhookEndpoint, stripeWebhookSecret, stripeWebhookSecrets, webhookUrlOf, } from './plugins/webhook-manager.js';
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC7F,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACvJ,OAAO,EACL,0BAA0B,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,oBAAoB,GACxF,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClF,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACtF,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,qBAAqB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,GAC/E,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAC7F,gBAAgB,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EACpG,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC7F,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACvJ,OAAO,EACL,0BAA0B,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,oBAAoB,GACxF,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClF,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC9E,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACtF,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,qBAAqB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,GAC/E,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAC7F,gBAAgB,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EACpG,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export { consumeLimit, consumptionByRefOf, consumptionOf, limitStateOf, reconcil
|
|
|
13
13
|
export { classifySubscriptionChange, commitSubscription, propagatedStateOf, subscriptionEventKey, } from './subscription.js';
|
|
14
14
|
export { planLookupKey, syncPaymentProducts, syncStripeProducts } from './sync.js';
|
|
15
15
|
export { amountCheckoutLineItem, quantityCheckoutLineItem } from './plugins/stripe.js';
|
|
16
|
+
export { makeEstimateCache, estimateStripePrice } from './plugins/estimate.js';
|
|
16
17
|
export { applySubscription, createEventHandler, mapStatus } from './plugins/events.js';
|
|
17
18
|
export { ensureWebhookEndpoint, stripeWebhookSecret, stripeWebhookSecrets, webhookUrlOf, } from './plugins/webhook-manager.js';
|
|
18
19
|
export { ensurePortalConfiguration } from './plugins/portal.js';
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC7F,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACvJ,OAAO,EACL,0BAA0B,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,oBAAoB,GACxF,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClF,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAEtF,OAAO,EACL,qBAAqB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,GAC/E,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAC7F,gBAAgB,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EACpG,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC7F,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACvJ,OAAO,EACL,0BAA0B,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,oBAAoB,GACxF,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClF,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE9E,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAEtF,OAAO,EACL,qBAAqB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,GAC/E,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAC7F,gBAAgB,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EACpG,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type Stripe from 'stripe';
|
|
2
|
+
import type { PriceEstimate } from '@owlmeans/payment';
|
|
3
|
+
import type { Context as ApiContext } from '@owlmeans/server-api';
|
|
4
|
+
import type { PriceEstimateParams } from '../types.js';
|
|
5
|
+
interface CacheEntry<T> {
|
|
6
|
+
value: T;
|
|
7
|
+
expiresAt: number;
|
|
8
|
+
}
|
|
9
|
+
export interface EstimateCache {
|
|
10
|
+
taxTtlMs: number;
|
|
11
|
+
fxTtlMs: number;
|
|
12
|
+
customerTtlMs: number;
|
|
13
|
+
tax: Map<string, CacheEntry<TaxOutcome>>;
|
|
14
|
+
fx: Map<string, CacheEntry<FxOutcome>>;
|
|
15
|
+
customer: Map<string, CacheEntry<Stripe.Customer | null>>;
|
|
16
|
+
inflight: Map<string, Promise<unknown>>;
|
|
17
|
+
}
|
|
18
|
+
/** @param taxTtlMs default 24h; @param fxTtlMs default 1h; @param customerTtlMs default 5min. */
|
|
19
|
+
export declare const makeEstimateCache: (taxTtlMs?: number, fxTtlMs?: number, customerTtlMs?: number) => EstimateCache;
|
|
20
|
+
type TaxOutcome = {
|
|
21
|
+
ok: true;
|
|
22
|
+
calculation: Stripe.Tax.Calculation;
|
|
23
|
+
} | {
|
|
24
|
+
ok: false;
|
|
25
|
+
code?: string;
|
|
26
|
+
};
|
|
27
|
+
type FxOutcome = {
|
|
28
|
+
currency: string;
|
|
29
|
+
exchangeRate: number;
|
|
30
|
+
fxFeeRate?: number;
|
|
31
|
+
} | null;
|
|
32
|
+
/**
|
|
33
|
+
* A Stripe Tax estimate (and, when the pricing policy asks for it, a local-currency conversion) for
|
|
34
|
+
* one product/plan, at a billing country the request names or the entity's paygate customer does.
|
|
35
|
+
*
|
|
36
|
+
* Costs one Tax Calculation API call ($0.05) per distinct (currency, country, amount, tax code,
|
|
37
|
+
* behavior, matching tax ids) within `cache`'s TTL, and one free FX Quotes call per distinct
|
|
38
|
+
* (currency, local currency) — never more, and never for a rate-limit or connection error, which is
|
|
39
|
+
* never cached.
|
|
40
|
+
*/
|
|
41
|
+
export declare const estimateStripePrice: (ctx: ApiContext, stripe: Stripe, params: PriceEstimateParams, cache: EstimateCache) => Promise<PriceEstimate>;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=estimate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimate.d.ts","sourceRoot":"","sources":["../../src/plugins/estimate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAKhC,OAAO,KAAK,EAAE,aAAa,EAAgC,MAAM,mBAAmB,CAAA;AACpF,OAAO,KAAK,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAKjE,OAAO,KAAK,EAA+B,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAOnF,UAAU,UAAU,CAAC,CAAC;IAAI,KAAK,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAEvD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAA;IACxC,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAA;IACtC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAA;IACzD,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;CACxC;AAED,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,cAClB,MAAM,YAAkC,MAAM,kBACzC,MAAM,KACpB,aAED,CAAA;AAwDF,KAAK,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAgFlG,KAAK,SAAS,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAsBtF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,QACzB,UAAU,UAAU,MAAM,UAAU,mBAAmB,SAAS,aAAa,KACjF,OAAO,CAAC,aAAa,CA4FvB,CAAA"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { chargeAmountMinor, CheckoutPricingMode, currencyOfCountry, ProductError, ratePpmOf, TaxBehavior, TaxEstimateStatus, TaxType, UnknownProduct, } from '@owlmeans/payment';
|
|
2
|
+
import { STRIPE_FX_QUOTES_API_VERSION, STRIPE_PAYGATE_ALIAS } from '../consts.js';
|
|
3
|
+
import { findProduct } from '../plan.js';
|
|
4
|
+
import { isSoldThrough } from '../sync.js';
|
|
5
|
+
import { isMissingObject, paygateCustomers, payment, stripePricingConfig } from '../utils.js';
|
|
6
|
+
/** @param taxTtlMs default 24h; @param fxTtlMs default 1h; @param customerTtlMs default 5min. */
|
|
7
|
+
export const makeEstimateCache = (taxTtlMs = 24 * 60 * 60 * 1_000, fxTtlMs = 60 * 60 * 1_000, customerTtlMs = 5 * 60 * 1_000) => ({
|
|
8
|
+
taxTtlMs, fxTtlMs, customerTtlMs, tax: new Map(), fx: new Map(), customer: new Map(), inflight: new Map(),
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* A keyed value cached for `ttlMs`, with in-flight requests shared across concurrent callers. Only
|
|
12
|
+
* a settled (resolved) outcome is cached — a thrown error (a rate limit, a dropped connection) never
|
|
13
|
+
* is, so the next call simply tries again.
|
|
14
|
+
*/
|
|
15
|
+
const cached = async (store, inflight, key, ttlMs, factory) => {
|
|
16
|
+
const now = Date.now();
|
|
17
|
+
const hit = store.get(key);
|
|
18
|
+
if (hit != null && hit.expiresAt > now) {
|
|
19
|
+
return hit.value;
|
|
20
|
+
}
|
|
21
|
+
const pending = inflight.get(key);
|
|
22
|
+
if (pending != null) {
|
|
23
|
+
return pending;
|
|
24
|
+
}
|
|
25
|
+
const promise = factory().then(value => {
|
|
26
|
+
store.set(key, { value, expiresAt: Date.now() + ttlMs });
|
|
27
|
+
inflight.delete(key);
|
|
28
|
+
return value;
|
|
29
|
+
}).catch(error => {
|
|
30
|
+
inflight.delete(key);
|
|
31
|
+
throw error;
|
|
32
|
+
});
|
|
33
|
+
inflight.set(key, promise);
|
|
34
|
+
return promise;
|
|
35
|
+
};
|
|
36
|
+
// -------------------------------------------------------------------------------------------
|
|
37
|
+
// Customer lookup — the fallback country and the tax ids a request-given country still checks.
|
|
38
|
+
// -------------------------------------------------------------------------------------------
|
|
39
|
+
const cachedCustomer = async (ctx, stripe, entityId, cache) => cached(cache.customer, cache.inflight, `customer:${entityId}`, cache.customerTtlMs, async () => {
|
|
40
|
+
const record = await paygateCustomers(ctx).byEntity(entityId, STRIPE_PAYGATE_ALIAS);
|
|
41
|
+
if (record == null || record.deletedAt != null) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const retrieved = await stripe.customers.retrieve(record.externalId, { expand: ['tax_ids'] });
|
|
46
|
+
return retrieved.deleted ? null : retrieved;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (isMissingObject(error))
|
|
50
|
+
return null;
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
/** A duck-typed check, matching `isMissingObject` above: the installed SDK's own error classes. */
|
|
55
|
+
const isInvalidRequest = (error) => error?.type === 'StripeInvalidRequestError';
|
|
56
|
+
const NON_SCALABLE_REASONS = new Set([
|
|
57
|
+
'portion_product_exempt', 'portion_reduced_rated', 'portion_standard_rated', 'taxable_basis_reduced',
|
|
58
|
+
'proportionally_rated',
|
|
59
|
+
]);
|
|
60
|
+
/** A linear percentage rate scales with the amount; a flat fee, a partial exemption, or several inclusive rates do not. */
|
|
61
|
+
const scalableOf = (breakdown, behavior) => {
|
|
62
|
+
if (breakdown.some(row => row.tax_rate_details?.rate_type === 'flat_amount'))
|
|
63
|
+
return false;
|
|
64
|
+
if (breakdown.some(row => NON_SCALABLE_REASONS.has(row.taxability_reason)))
|
|
65
|
+
return false;
|
|
66
|
+
if (behavior === TaxBehavior.Inclusive && breakdown.length > 1)
|
|
67
|
+
return false;
|
|
68
|
+
return true;
|
|
69
|
+
};
|
|
70
|
+
const statusOf = (breakdown, taxMinor) => {
|
|
71
|
+
if (breakdown.some(row => row.taxability_reason === 'reverse_charge'))
|
|
72
|
+
return TaxEstimateStatus.ReverseCharge;
|
|
73
|
+
if (taxMinor > 0)
|
|
74
|
+
return TaxEstimateStatus.Taxed;
|
|
75
|
+
if (breakdown.some(row => row.taxability_reason === 'not_supported'))
|
|
76
|
+
return TaxEstimateStatus.AtCheckout;
|
|
77
|
+
return TaxEstimateStatus.None;
|
|
78
|
+
};
|
|
79
|
+
const TAX_TYPE_MAP = Object.freeze({
|
|
80
|
+
vat: TaxType.Vat, gst: TaxType.Gst, sales_tax: TaxType.SalesTax,
|
|
81
|
+
});
|
|
82
|
+
const taxTypeOf = (raw) => raw != null && raw in TAX_TYPE_MAP ? TAX_TYPE_MAP[raw] : TaxType.Tax;
|
|
83
|
+
const ratesOf = (breakdown) => breakdown
|
|
84
|
+
.filter((row) => row.tax_rate_details != null)
|
|
85
|
+
.map(row => ({
|
|
86
|
+
type: taxTypeOf(row.tax_rate_details.tax_type),
|
|
87
|
+
percentage: row.tax_rate_details.percentage_decimal,
|
|
88
|
+
ratePpm: ratePpmOf(row.tax_rate_details.percentage_decimal),
|
|
89
|
+
...(row.tax_rate_details.country != null ? { country: row.tax_rate_details.country } : {}),
|
|
90
|
+
...(row.tax_rate_details.state != null ? { state: row.tax_rate_details.state } : {}),
|
|
91
|
+
}));
|
|
92
|
+
const taxEstimateOf = (calculation, behavior, subtotalMinor) => {
|
|
93
|
+
const breakdown = calculation.tax_breakdown ?? [];
|
|
94
|
+
const taxMinor = calculation.tax_amount_exclusive + calculation.tax_amount_inclusive;
|
|
95
|
+
const status = statusOf(breakdown, taxMinor);
|
|
96
|
+
return {
|
|
97
|
+
status, subtotalMinor, taxMinor, totalMinor: calculation.amount_total,
|
|
98
|
+
scalable: scalableOf(breakdown, behavior), rates: ratesOf(breakdown),
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
/** The reference amount and currency of the estimate: an amount plan's default preset, else the plan's own price. */
|
|
102
|
+
const referenceOf = (plan) => {
|
|
103
|
+
if (plan.pricingMode === CheckoutPricingMode.Amount) {
|
|
104
|
+
if (plan.amountPolicy == null)
|
|
105
|
+
throw new ProductError(`amount-policy:${plan.sku}`);
|
|
106
|
+
return {
|
|
107
|
+
subtotalMinor: chargeAmountMinor(plan.amountPolicy.defaultMinor, plan.amountPolicy),
|
|
108
|
+
currency: plan.amountPolicy.currency.toLowerCase(),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return { subtotalMinor: Math.round(plan.price * 100), currency: (plan.currency ?? 'usd').toLowerCase() };
|
|
112
|
+
};
|
|
113
|
+
/** A placeholder estimate — no known tax, shown by its `status`, never by its zeroed numbers. */
|
|
114
|
+
const unresolvedEstimate = (status, subtotalMinor) => ({
|
|
115
|
+
status, subtotalMinor, taxMinor: 0, totalMinor: subtotalMinor, scalable: false, rates: [],
|
|
116
|
+
});
|
|
117
|
+
const fetchFxRate = async (stripe, currency, localCurrency, apiVersion) => {
|
|
118
|
+
const response = await stripe.rawRequest('POST', '/v1/fx_quotes', { to_currency: currency, 'from_currencies[]': localCurrency, lock_duration: 'none' }, { apiVersion });
|
|
119
|
+
const rate = response.rates?.[localCurrency];
|
|
120
|
+
if (rate?.exchange_rate == null) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
currency: localCurrency, exchangeRate: rate.exchange_rate,
|
|
125
|
+
...(rate.rate_details?.fx_fee_rate != null ? { fxFeeRate: rate.rate_details.fx_fee_rate } : {}),
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
// -------------------------------------------------------------------------------------------
|
|
129
|
+
/**
|
|
130
|
+
* A Stripe Tax estimate (and, when the pricing policy asks for it, a local-currency conversion) for
|
|
131
|
+
* one product/plan, at a billing country the request names or the entity's paygate customer does.
|
|
132
|
+
*
|
|
133
|
+
* Costs one Tax Calculation API call ($0.05) per distinct (currency, country, amount, tax code,
|
|
134
|
+
* behavior, matching tax ids) within `cache`'s TTL, and one free FX Quotes call per distinct
|
|
135
|
+
* (currency, local currency) — never more, and never for a rate-limit or connection error, which is
|
|
136
|
+
* never cached.
|
|
137
|
+
*/
|
|
138
|
+
export const estimateStripePrice = async (ctx, stripe, params, cache) => {
|
|
139
|
+
const product = await findProduct(ctx, params.productSku);
|
|
140
|
+
if (product == null)
|
|
141
|
+
throw new UnknownProduct(params.productSku);
|
|
142
|
+
const plans = (await payment(ctx).allPlans(product.sku))
|
|
143
|
+
.filter(plan => isSoldThrough(product, plan, STRIPE_PAYGATE_ALIAS));
|
|
144
|
+
const plan = params.planSku != null
|
|
145
|
+
? plans.find(item => item.sku === params.planSku)
|
|
146
|
+
: plans.find(item => item.recurring != null) ?? plans[0];
|
|
147
|
+
if (plan == null)
|
|
148
|
+
throw new ProductError(params.planSku != null ? `plan:${params.planSku}` : 'plan');
|
|
149
|
+
const pricing = await payment(ctx).pricingPolicy();
|
|
150
|
+
const behavior = pricing.tax.behavior ?? TaxBehavior.Exclusive;
|
|
151
|
+
const { subtotalMinor, currency } = referenceOf(plan);
|
|
152
|
+
let country = params.country?.toUpperCase();
|
|
153
|
+
let source = country != null ? 'request' : undefined;
|
|
154
|
+
let matchingTaxIds = [];
|
|
155
|
+
let taxabilityOverride;
|
|
156
|
+
const customer = await cachedCustomer(ctx, stripe, params.entityId, cache);
|
|
157
|
+
if (customer != null) {
|
|
158
|
+
if (country == null && customer.address?.country != null) {
|
|
159
|
+
country = customer.address.country;
|
|
160
|
+
source = 'customer';
|
|
161
|
+
}
|
|
162
|
+
if (country != null) {
|
|
163
|
+
matchingTaxIds = (customer.tax_ids?.data ?? [])
|
|
164
|
+
.filter(taxId => taxId.country === country)
|
|
165
|
+
.map(taxId => ({ type: taxId.type, value: taxId.value }));
|
|
166
|
+
if (customer.tax_exempt === 'exempt')
|
|
167
|
+
taxabilityOverride = 'customer_exempt';
|
|
168
|
+
else if (customer.tax_exempt === 'reverse')
|
|
169
|
+
taxabilityOverride = 'reverse_charge';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (country == null) {
|
|
173
|
+
return { currency, behavior, tax: unresolvedEstimate(TaxEstimateStatus.LocationRequired, subtotalMinor) };
|
|
174
|
+
}
|
|
175
|
+
const cacheKey = JSON.stringify([
|
|
176
|
+
currency, country, subtotalMinor, product.taxCode ?? null, behavior,
|
|
177
|
+
matchingTaxIds.map(id => `${id.type}:${id.value}`).sort(), taxabilityOverride ?? null,
|
|
178
|
+
]);
|
|
179
|
+
const outcome = await cached(cache.tax, cache.inflight, `tax:${cacheKey}`, cache.taxTtlMs, async () => {
|
|
180
|
+
try {
|
|
181
|
+
const calculation = await stripe.tax.calculations.create({
|
|
182
|
+
currency,
|
|
183
|
+
line_items: [{
|
|
184
|
+
amount: subtotalMinor, reference: plan.sku, tax_behavior: behavior,
|
|
185
|
+
...(product.taxCode != null ? { tax_code: product.taxCode } : {}),
|
|
186
|
+
}],
|
|
187
|
+
customer_details: {
|
|
188
|
+
address: { country },
|
|
189
|
+
address_source: 'billing',
|
|
190
|
+
// Cast: `Stripe.TaxId.type` (the customer's saved tax id) and the Tax Calculation
|
|
191
|
+
// parameter's own tax-id-type enum are independently generated from Stripe's OpenAPI
|
|
192
|
+
// spec and can drift apart in this pinned SDK; every value here still came from a real
|
|
193
|
+
// Stripe `TaxId` record, so it is valid at the API even where the two types disagree.
|
|
194
|
+
...(matchingTaxIds.length > 0
|
|
195
|
+
? { tax_ids: matchingTaxIds }
|
|
196
|
+
: {}),
|
|
197
|
+
...(taxabilityOverride != null ? { taxability_override: taxabilityOverride } : {}),
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
return { ok: true, calculation };
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
if (isInvalidRequest(error))
|
|
204
|
+
return { ok: false, code: error.code };
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const tax = outcome.ok
|
|
209
|
+
? taxEstimateOf(outcome.calculation, behavior, subtotalMinor)
|
|
210
|
+
: unresolvedEstimate(TaxEstimateStatus.AtCheckout, subtotalMinor);
|
|
211
|
+
const result = { country, source, currency, behavior, tax };
|
|
212
|
+
if (pricing.currency.estimate && pricing.currency.adaptive === true) {
|
|
213
|
+
const localCurrency = currencyOfCountry(country);
|
|
214
|
+
if (localCurrency != null && localCurrency !== currency) {
|
|
215
|
+
const apiVersion = (await stripePricingConfig(ctx))?.fxApiVersion ?? STRIPE_FX_QUOTES_API_VERSION;
|
|
216
|
+
// A preview endpoint: unreachable or erroring never fails the estimate, it only drops `local`.
|
|
217
|
+
const fx = await cached(cache.fx, cache.inflight, `fx:${currency}:${localCurrency}:${apiVersion}`, cache.fxTtlMs, () => fetchFxRate(stripe, currency, localCurrency, apiVersion)).catch(() => null);
|
|
218
|
+
if (fx != null) {
|
|
219
|
+
result.local = { currency: fx.currency, exchangeRate: fx.exchangeRate, ...(fx.fxFeeRate != null ? { fxFeeRate: fx.fxFeeRate } : {}) };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
};
|
|
225
|
+
//# sourceMappingURL=estimate.js.map
|