@owlmeans/payment 0.1.18-rc.46 → 0.1.18-rc.48
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 +21 -21
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/entitlements/SKILL.md +7 -6
- package/agent-meta/skills/payment/SKILL.md +150 -104
- package/build/advertise.js +1 -11
- package/build/advertise.js.map +1 -1
- package/build/checkout/consts.d.ts +2 -0
- package/build/checkout/consts.d.ts.map +1 -0
- package/build/checkout/consts.js +2 -0
- package/build/checkout/consts.js.map +1 -0
- package/build/checkout/index.d.ts +3 -0
- package/build/checkout/index.d.ts.map +1 -1
- package/build/checkout/index.js +1 -0
- package/build/checkout/index.js.map +1 -1
- package/build/checkout/narrow/types.d.ts +25 -0
- package/build/checkout/narrow/types.d.ts.map +1 -0
- package/build/checkout/narrow/types.js +2 -0
- package/build/checkout/narrow/types.js.map +1 -0
- package/build/checkout/narrow.d.ts +5 -22
- package/build/checkout/narrow.d.ts.map +1 -1
- package/build/checkout/narrow.js +43 -54
- package/build/checkout/narrow.js.map +1 -1
- package/build/checkout/protocols.d.ts +1 -25
- package/build/checkout/protocols.d.ts.map +1 -1
- package/build/checkout/protocols.js +1 -1
- package/build/checkout/protocols.js.map +1 -1
- package/build/checkout/types.d.ts +29 -0
- package/build/checkout/types.d.ts.map +1 -0
- package/build/checkout/types.js +2 -0
- package/build/checkout/types.js.map +1 -0
- package/build/consts.d.ts +82 -1
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +145 -1
- package/build/consts.js.map +1 -1
- package/build/consts.local.d.ts +20 -0
- package/build/consts.local.d.ts.map +1 -0
- package/build/consts.local.js +23 -0
- package/build/consts.local.js.map +1 -0
- package/build/consumer/cancel.d.ts +1 -1
- package/build/consumer/cancel.d.ts.map +1 -1
- package/build/consumer/cancel.js.map +1 -1
- package/build/consumer/consts.d.ts +20 -0
- package/build/consumer/consts.d.ts.map +1 -0
- package/build/consumer/consts.js +39 -0
- package/build/consumer/consts.js.map +1 -0
- package/build/consumer/consts.local.d.ts +7 -0
- package/build/consumer/consts.local.d.ts.map +1 -0
- package/build/consumer/consts.local.js +13 -0
- package/build/consumer/consts.local.js.map +1 -0
- package/build/consumer/copy/types.d.ts +56 -0
- package/build/consumer/copy/types.d.ts.map +1 -0
- package/build/consumer/copy/types.js +2 -0
- package/build/consumer/copy/types.js.map +1 -0
- package/build/consumer/copy.d.ts +13 -49
- package/build/consumer/copy.d.ts.map +1 -1
- package/build/consumer/copy.js +75 -79
- package/build/consumer/copy.js.map +1 -1
- package/build/consumer/deadline/types.d.ts +30 -0
- package/build/consumer/deadline/types.d.ts.map +1 -0
- package/build/consumer/deadline/types.js +2 -0
- package/build/consumer/deadline/types.js.map +1 -0
- package/build/consumer/deadline.d.ts +8 -39
- package/build/consumer/deadline.d.ts.map +1 -1
- package/build/consumer/deadline.js +41 -52
- package/build/consumer/deadline.js.map +1 -1
- package/build/consumer/fifo/types.d.ts +17 -0
- package/build/consumer/fifo/types.d.ts.map +1 -0
- package/build/consumer/fifo/types.js +2 -0
- package/build/consumer/fifo/types.js.map +1 -0
- package/build/consumer/fifo.d.ts +3 -39
- package/build/consumer/fifo.d.ts.map +1 -1
- package/build/consumer/fifo.js +30 -36
- package/build/consumer/fifo.js.map +1 -1
- package/build/consumer/index.d.ts +8 -0
- package/build/consumer/index.d.ts.map +1 -1
- package/build/consumer/index.js +1 -0
- package/build/consumer/index.js.map +1 -1
- package/build/consumer/policy/types.d.ts +20 -0
- package/build/consumer/policy/types.d.ts.map +1 -0
- package/build/consumer/policy/types.js +2 -0
- package/build/consumer/policy/types.js.map +1 -0
- package/build/consumer/policy.d.ts +8 -30
- package/build/consumer/policy.d.ts.map +1 -1
- package/build/consumer/policy.js +66 -97
- package/build/consumer/policy.js.map +1 -1
- package/build/consumer/protocols.d.ts +1 -86
- package/build/consumer/protocols.d.ts.map +1 -1
- package/build/consumer/protocols.js +1 -4
- package/build/consumer/protocols.js.map +1 -1
- package/build/consumer/refund/types.d.ts +27 -0
- package/build/consumer/refund/types.d.ts.map +1 -0
- package/build/consumer/refund/types.js +2 -0
- package/build/consumer/refund/types.js.map +1 -0
- package/build/consumer/refund.d.ts +6 -71
- package/build/consumer/refund.d.ts.map +1 -1
- package/build/consumer/refund.js +86 -97
- package/build/consumer/refund.js.map +1 -1
- package/build/consumer/refusal.d.ts.map +1 -1
- package/build/consumer/refusal.js +2 -7
- package/build/consumer/refusal.js.map +1 -1
- package/build/consumer/revive/types.d.ts +19 -0
- package/build/consumer/revive/types.d.ts.map +1 -0
- package/build/consumer/revive/types.js +2 -0
- package/build/consumer/revive/types.js.map +1 -0
- package/build/consumer/revive.d.ts +8 -8
- package/build/consumer/revive.d.ts.map +1 -1
- package/build/consumer/revive.js +40 -23
- package/build/consumer/revive.js.map +1 -1
- package/build/consumer/types.d.ts +196 -0
- package/build/consumer/types.d.ts.map +1 -0
- package/build/consumer/types.js +2 -0
- package/build/consumer/types.js.map +1 -0
- package/build/consumer/types.local.d.ts +11 -0
- package/build/consumer/types.local.d.ts.map +1 -0
- package/build/consumer/types.local.js +2 -0
- package/build/consumer/types.local.js.map +1 -0
- package/build/countries.d.ts +0 -19
- package/build/countries.d.ts.map +1 -1
- package/build/countries.js +1 -63
- package/build/countries.js.map +1 -1
- package/build/entitled.d.ts +14 -0
- package/build/entitled.d.ts.map +1 -0
- package/build/entitled.js +17 -0
- package/build/entitled.js.map +1 -0
- package/build/entitlement/types.d.ts +29 -0
- package/build/entitlement/types.d.ts.map +1 -0
- package/build/entitlement/types.js +2 -0
- package/build/entitlement/types.js.map +1 -0
- package/build/entitlement.d.ts +7 -72
- package/build/entitlement.d.ts.map +1 -1
- package/build/entitlement.js +55 -109
- package/build/entitlement.js.map +1 -1
- package/build/errors.d.ts +1 -27
- package/build/errors.d.ts.map +1 -1
- package/build/errors.js +1 -9
- package/build/errors.js.map +1 -1
- package/build/estimate/types.d.ts +34 -0
- package/build/estimate/types.d.ts.map +1 -0
- package/build/estimate/types.js +2 -0
- package/build/estimate/types.js.map +1 -0
- package/build/estimate.d.ts +7 -53
- package/build/estimate.d.ts.map +1 -1
- package/build/estimate.js +61 -87
- package/build/estimate.js.map +1 -1
- package/build/i18n/consumer-rights/be.json +12 -4
- package/build/i18n/consumer-rights/de.json +12 -4
- package/build/i18n/consumer-rights/en.json +12 -4
- package/build/i18n/consumer-rights/es.json +12 -4
- package/build/i18n/consumer-rights/fr.json +12 -4
- package/build/i18n/consumer-rights/pl.json +12 -4
- package/build/i18n/consumer-rights/ru.json +12 -4
- package/build/i18n/consumer-rights/uk.json +12 -4
- package/build/i18n.js +25 -25
- package/build/i18n.js.map +1 -1
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/limit/types.d.ts +44 -0
- package/build/limit/types.d.ts.map +1 -0
- package/build/limit/types.js +2 -0
- package/build/limit/types.js.map +1 -0
- package/build/limit.d.ts +11 -38
- package/build/limit.d.ts.map +1 -1
- package/build/limit.js +80 -94
- package/build/limit.js.map +1 -1
- package/build/model/checkout.js +1 -1
- package/build/model/checkout.js.map +1 -1
- package/build/model/consts.d.ts +15 -0
- package/build/model/consts.d.ts.map +1 -0
- package/build/model/consts.js +193 -0
- package/build/model/consts.js.map +1 -0
- package/build/model/consts.local.d.ts +35 -0
- package/build/model/consts.local.d.ts.map +1 -0
- package/build/model/consts.local.js +65 -0
- package/build/model/consts.local.js.map +1 -0
- package/build/model/consumer.d.ts +1 -10
- package/build/model/consumer.d.ts.map +1 -1
- package/build/model/consumer.js +7 -160
- package/build/model/consumer.js.map +1 -1
- package/build/model/estimate.d.ts.map +1 -1
- package/build/model/estimate.js +2 -27
- package/build/model/estimate.js.map +1 -1
- package/build/model/index.d.ts +1 -0
- package/build/model/index.d.ts.map +1 -1
- package/build/model/index.js +1 -0
- package/build/model/index.js.map +1 -1
- package/build/model/plan.js +1 -1
- package/build/model/plan.js.map +1 -1
- package/build/model/view.d.ts +1 -6
- package/build/model/view.d.ts.map +1 -1
- package/build/model/view.js +2 -73
- package/build/model/view.js.map +1 -1
- package/build/pricing/types.d.ts +13 -0
- package/build/pricing/types.d.ts.map +1 -0
- package/build/pricing/types.js +2 -0
- package/build/pricing/types.js.map +1 -0
- package/build/pricing.d.ts +7 -1
- package/build/pricing.d.ts.map +1 -1
- package/build/pricing.js +70 -59
- package/build/pricing.js.map +1 -1
- package/build/promo/types.d.ts +14 -0
- package/build/promo/types.d.ts.map +1 -0
- package/build/promo/types.js +2 -0
- package/build/promo/types.js.map +1 -0
- package/build/promo.d.ts +5 -9
- package/build/promo.d.ts.map +1 -1
- package/build/promo.js +17 -18
- package/build/promo.js.map +1 -1
- package/build/regions/types.d.ts +32 -0
- package/build/regions/types.d.ts.map +1 -0
- package/build/regions/types.js +2 -0
- package/build/regions/types.js.map +1 -0
- package/build/regions.d.ts +8 -42
- package/build/regions.d.ts.map +1 -1
- package/build/regions.js +40 -82
- package/build/regions.js.map +1 -1
- package/build/service.d.ts.map +1 -1
- package/build/service.js +10 -12
- package/build/service.js.map +1 -1
- package/build/types.d.ts +71 -0
- package/build/types.d.ts.map +1 -1
- package/build/types.local.d.ts +4 -0
- package/build/types.local.d.ts.map +1 -0
- package/build/types.local.js +2 -0
- package/build/types.local.js.map +1 -0
- package/build/view/types.d.ts +33 -0
- package/build/view/types.d.ts.map +1 -0
- package/build/view/types.js +2 -0
- package/build/view/types.js.map +1 -0
- package/build/view.d.ts +7 -24
- package/build/view.d.ts.map +1 -1
- package/build/view.js +71 -84
- package/build/view.js.map +1 -1
- package/package.json +11 -11
- package/src/advertise.ts +1 -14
- package/src/checkout/consts.ts +1 -0
- package/src/checkout/index.ts +3 -0
- package/src/checkout/narrow/types.ts +27 -0
- package/src/checkout/narrow.ts +53 -62
- package/src/checkout/protocols.ts +3 -24
- package/src/checkout/types.ts +27 -0
- package/src/consts.local.ts +34 -0
- package/src/consts.ts +161 -1
- package/src/consumer/cancel.ts +1 -2
- package/src/consumer/consts.local.ts +16 -0
- package/src/consumer/consts.ts +46 -0
- package/src/consumer/copy/types.ts +54 -0
- package/src/consumer/copy.ts +96 -101
- package/src/consumer/deadline/types.ts +30 -0
- package/src/consumer/deadline.ts +47 -68
- package/src/consumer/fifo/types.ts +17 -0
- package/src/consumer/fifo.ts +34 -63
- package/src/consumer/index.ts +8 -0
- package/src/consumer/policy/types.ts +20 -0
- package/src/consumer/policy.ts +62 -92
- package/src/consumer/protocols.ts +4 -79
- package/src/consumer/refund/types.ts +27 -0
- package/src/consumer/refund.ts +97 -152
- package/src/consumer/refusal.ts +2 -8
- package/src/consumer/revive/types.ts +23 -0
- package/src/consumer/revive.ts +57 -34
- package/src/consumer/types.local.ts +10 -0
- package/src/consumer/types.ts +189 -0
- package/src/countries.ts +1 -67
- package/src/entitled.ts +20 -0
- package/src/entitlement/types.ts +29 -0
- package/src/entitlement.ts +67 -128
- package/src/errors.ts +2 -47
- package/src/estimate/types.ts +34 -0
- package/src/estimate.ts +68 -102
- package/src/i18n/consumer-rights/be.json +12 -4
- package/src/i18n/consumer-rights/de.json +12 -4
- package/src/i18n/consumer-rights/en.json +12 -4
- package/src/i18n/consumer-rights/es.json +12 -4
- package/src/i18n/consumer-rights/fr.json +12 -4
- package/src/i18n/consumer-rights/pl.json +12 -4
- package/src/i18n/consumer-rights/ru.json +12 -4
- package/src/i18n/consumer-rights/uk.json +12 -4
- package/src/i18n.ts +26 -25
- package/src/index.ts +8 -1
- package/src/limit/types.ts +41 -0
- package/src/limit.ts +102 -110
- package/src/model/checkout.ts +1 -1
- package/src/model/consts.local.ts +83 -0
- package/src/model/consts.ts +206 -0
- package/src/model/consumer.ts +8 -183
- package/src/model/estimate.ts +3 -30
- package/src/model/index.ts +1 -0
- package/src/model/plan.ts +1 -1
- package/src/model/view.ts +3 -82
- package/src/pricing/types.ts +13 -0
- package/src/pricing.ts +94 -71
- package/src/promo/types.ts +18 -0
- package/src/promo.ts +31 -26
- package/src/regions/types.ts +42 -0
- package/src/regions.ts +60 -90
- package/src/service.ts +12 -21
- package/src/types.local.ts +5 -0
- package/src/types.ts +73 -0
- package/src/view/types.ts +39 -0
- package/src/view.ts +100 -101
- package/tests/checkout-narrow.spec.ts +19 -19
- package/tests/consumer-copy.spec.ts +228 -43
- package/tests/consumer-deadline.spec.ts +21 -22
- package/tests/consumer-fifo.spec.ts +12 -12
- package/tests/consumer-refund.spec.ts +27 -29
- package/tests/consumer-regions.spec.ts +39 -39
- package/tests/consumer-wire.spec.ts +52 -10
- package/tests/contract.spec.ts +3 -3
- package/tests/entitlement.spec.ts +26 -28
- package/tests/estimate.spec.ts +26 -26
- package/tests/limit.spec.ts +33 -36
- package/tests/pricing.spec.ts +10 -13
- package/tests/view.spec.ts +24 -24
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ server integration (`@owlmeans/server-payment`) implements against these contrac
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
bun add @owlmeans/payment@^0.1.18-rc.
|
|
11
|
+
bun add @owlmeans/payment@^0.1.18-rc.48
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
## Concepts
|
|
@@ -49,25 +49,23 @@ const proMonthly: ProductPlan = {
|
|
|
49
49
|
Gate a route on a capability or on a limit:
|
|
50
50
|
|
|
51
51
|
```typescript
|
|
52
|
-
import { ENTITLEMENT_GATE, LIMIT_GATE, entitled,
|
|
52
|
+
import { ENTITLEMENT_GATE, LIMIT_GATE, entitled, planLimitHelper } from '@owlmeans/payment'
|
|
53
53
|
|
|
54
54
|
protocol(route(WHITELABEL, '/whitelabel', backend(BASE, RouteMethod.POST)), contract(typed()),
|
|
55
55
|
entitled('feature:whitelabel'))
|
|
56
56
|
protocol(route(INVITE, '/invite', backend(BASE, RouteMethod.POST)), contract(typed()),
|
|
57
|
-
{ gate: { alias: LIMIT_GATE, params: [formatLimitParam('seats')] } })
|
|
57
|
+
{ gate: { alias: LIMIT_GATE, params: [planLimitHelper.formatLimitParam('seats')] } })
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
Build and read an entitlement view:
|
|
61
61
|
|
|
62
62
|
```typescript
|
|
63
|
-
import {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
capabilityOf(fromWire, 'feature:whitelabel')
|
|
70
|
-
hasLimitRoom(limitOf(fromWire, 'seats'))
|
|
63
|
+
import { entitlementViewHelper, planLimitHelper } from '@owlmeans/payment'
|
|
64
|
+
|
|
65
|
+
const view = entitlementViewHelper.entitlementViewOf(plan, planView, usage) // server
|
|
66
|
+
const fromWire = entitlementViewHelper.reviveEntitlementView(await response.json()) // browser: ISO strings → Dates
|
|
67
|
+
planLimitHelper.capabilityOf(fromWire, 'feature:whitelabel')
|
|
68
|
+
planLimitHelper.hasLimitRoom(planLimitHelper.limitOf(fromWire, 'seats'))
|
|
71
69
|
```
|
|
72
70
|
|
|
73
71
|
Refuse and recover the fields on the other side of a service hop:
|
|
@@ -88,20 +86,22 @@ if (error instanceof LimitExhausted) { error.limitKey; error.used; error.limit;
|
|
|
88
86
|
(`product`, `products`, `plans`, `plan`, `allPlans`, `localize`, `shallowAuthentication`),
|
|
89
87
|
`l10nToId`, record types/prefixes.
|
|
90
88
|
- Checkout: `CheckoutPricingMode`, `AmountCheckoutPolicy`/`QuantityCheckoutPolicy` (+ schemas),
|
|
91
|
-
`assertAmountCheckoutPolicy`, `assertQuantityCheckoutPolicy`,
|
|
92
|
-
`
|
|
89
|
+
`checkoutPricingHelper` (`assertAmountCheckoutPolicy`, `assertQuantityCheckoutPolicy`,
|
|
90
|
+
`assertCheckoutAmount`, `chargeAmountMinor`), `CreateCheckoutBody` (`planSku`) / `CreateCheckoutResponse` (+ schemas),
|
|
93
91
|
`PortalFlow`, `PortalLinkBody` / `PortalLinkResponse` (+ schemas).
|
|
94
92
|
- Entitlement grammar: `ENTITLEMENT_GATE`, `LIMIT_GATE`, `CAPABILITY_FEATURE_SCOPE`,
|
|
95
|
-
`CAPABILITY_LIMIT_SCOPE`, `entitled`, `
|
|
96
|
-
`
|
|
93
|
+
`CAPABILITY_LIMIT_SCOPE`, `entitled`, `entitlementParamHelper` (`parseEntitlementParam`,
|
|
94
|
+
`formatEntitlementParam`, `hasEntitlement`, `entitlementList`), `planLimitHelper`
|
|
95
|
+
(`parseLimitParam`, `formatLimitParam`).
|
|
97
96
|
- Statuses: `SubscriptionStatus` (incl. `PastDue`), `ENTITLING_STATUSES`, `TERMINAL_STATUSES`,
|
|
98
97
|
`INTERNAL_PAYGATE`.
|
|
99
98
|
- Limits and promos: `LimitKind`, `LimitWindow`, `LimitDeclaration`, `PlanCapability`,
|
|
100
|
-
`PromoDeclaration` (+ schemas), `windowKeyOf`, `windowBoundsOf
|
|
101
|
-
`OCCUPANCY_WINDOW`, `promoActive`, `promoViewOf
|
|
99
|
+
`PromoDeclaration` (+ schemas), `planLimitHelper` (`windowKeyOf`, `windowBoundsOf`),
|
|
100
|
+
`LIFETIME_WINDOW`, `OCCUPANCY_WINDOW`, `promoHelper` (`promoActive`, `promoViewOf`).
|
|
102
101
|
- Views: `EntitlementView`, `EntitlementPlanView`, `CapabilityView`, `LimitView`, `PromoView`,
|
|
103
|
-
`LimitUsage` (+ wire schemas), `capabilityViewsOf`, `limitViewsOf`,
|
|
104
|
-
`
|
|
102
|
+
`LimitUsage` (+ wire schemas), `entitlementViewHelper` (`capabilityViewsOf`, `limitViewsOf`,
|
|
103
|
+
`entitlementViewOf`, `reviveEntitlementView`), `planLimitHelper` (`capabilityOf`, `limitOf`,
|
|
104
|
+
`hasLimitRoom`).
|
|
105
105
|
- Errors: `EntitlementRefusal` → `CapabilityRequired`, `LimitExhausted` (all `AuthForbidden`);
|
|
106
106
|
`PaymentError` family incl. `LimitUnknown`, `LimitMisdeclared`, `PlanRequired`,
|
|
107
107
|
`PlanRankConflict`, `WebhookSetupError`, `PortalUnavailable` (declares `httpStatus = 409`, so an
|
|
@@ -110,7 +110,7 @@ if (error instanceof LimitExhausted) { error.limitKey; error.used; error.limit;
|
|
|
110
110
|
|
|
111
111
|
## Common pitfalls
|
|
112
112
|
|
|
113
|
-
- A limit parameter is never a capability: `hasEntitlement(sets, 'limit:x')` is always `false`.
|
|
113
|
+
- A limit parameter is never a capability: `entitlementParamHelper.hasEntitlement(sets, 'limit:x')` is always `false`.
|
|
114
114
|
- A view's dates are ISO strings on the wire — revive before calling date methods.
|
|
115
115
|
- A promo ends AT `until`; grandfathering needs the subscription's creation date on the plan view.
|
|
116
116
|
- A refusal's fields survive a hop only through its message; catch the class, not the text.
|
|
@@ -129,7 +129,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
129
129
|
your project's skill store (`.agents/skills/`):
|
|
130
130
|
|
|
131
131
|
```sh
|
|
132
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
132
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.49
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
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/payment",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.48",
|
|
5
|
+
"generatedAt": "2026-10-05T21:03:06.402Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -116,7 +116,8 @@ Limits are event-sourced with synchronous admission:
|
|
|
116
116
|
|
|
117
117
|
## The entitlement view
|
|
118
118
|
|
|
119
|
-
One read of an entity's position, built by
|
|
119
|
+
One read of an entity's position, built by
|
|
120
|
+
`entitlementViewHelper.entitlementViewOf(plan, planView, usage, at)`:
|
|
120
121
|
|
|
121
122
|
- `plan` — sku, rank, free, status, paygate, period, trial, cancel-at-period-end, past-due,
|
|
122
123
|
fallback plan;
|
|
@@ -125,11 +126,11 @@ One read of an entity's position, built by `entitlementViewOf(plan, planView, us
|
|
|
125
126
|
`windowStart`/`resetsAt` for window limits;
|
|
126
127
|
- `at` — when it was computed.
|
|
127
128
|
|
|
128
|
-
The server serves it; the browser reads it with the same `capabilityOf` /
|
|
129
|
-
`hasLimitRoom` the gate logic uses. On the wire every date is an ISO string — revive
|
|
130
|
-
(`reviveEntitlementView`) before using a date. In the browser `null` means
|
|
131
|
-
paid controls disabled rather than enabled-then-refused, and an application
|
|
132
|
-
reads the view through the pure selectors rather than polling it a second time.
|
|
129
|
+
The server serves it; the browser reads it with the same `planLimitHelper.capabilityOf` /
|
|
130
|
+
`limitOf` / `hasLimitRoom` the gate logic uses. On the wire every date is an ISO string — revive
|
|
131
|
+
(`entitlementViewHelper.reviveEntitlementView`) before using a date. In the browser `null` means
|
|
132
|
+
"not known yet": render paid controls disabled rather than enabled-then-refused, and an application
|
|
133
|
+
with its own store reads the view through the pure selectors rather than polling it a second time.
|
|
133
134
|
|
|
134
135
|
## Refusals
|
|
135
136
|
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/payment
|
|
9
9
|
|
|
10
10
|
**Layer:** Core
|
|
11
|
-
**Install:** `"@owlmeans/payment": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/payment": "^0.1.18-rc.48"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
The contracts half of payments: the catalogue (products, plans, localizations), amount- and
|
|
14
14
|
quantity-priced checkout, the entitlement model — plan capabilities, counted limits, promos,
|
|
@@ -30,27 +30,27 @@ admission, the usage ledger, the two gate services — is the `entitlements` ski
|
|
|
30
30
|
| `SubscriptionStatus` · `ENTITLING_STATUSES` · `TERMINAL_STATUSES` · `INTERNAL_PAYGATE` | Lifecycle vocabulary. `Active`/`Trial`/`PastDue` entitle; `Canceled`/`Expired`/`Ended`/`Blocked` are terminal; `Suspended` is revoked until resumed. |
|
|
31
31
|
| `LimitKind` · `LimitWindow` · `PortalFlow` (+ schemas) | `window`/`lifetime`/`occupancy`; `day`/`month`; `manage`/`cancel`/`update`/`change`/`payment-method`. |
|
|
32
32
|
| `ENTITLEMENT_GATE` · `LIMIT_GATE` · `CAPABILITY_FEATURE_SCOPE` · `CAPABILITY_LIMIT_SCOPE` | The two gate aliases and the two reserved scopes (`feature` for flags, `limit` for limit parameters). |
|
|
33
|
-
| `entitled` · `parseEntitlementParam` · `formatEntitlementParam` · `hasEntitlement` · `entitlementList` | The capability grammar and predicate. |
|
|
34
|
-
| `parseLimitParam` · `formatLimitParam` · `windowKeyOf` · `windowBoundsOf` · `LIFETIME_WINDOW` · `OCCUPANCY_WINDOW` | The limit grammar and window algebra. |
|
|
35
|
-
| `promoActive` · `promoViewOf` | Whether a promo is in force for one subscription at one instant. |
|
|
33
|
+
| `entitled` · `entitlementParamHelper` (`parseEntitlementParam` · `formatEntitlementParam` · `hasEntitlement` · `entitlementList`) | The capability grammar and predicate. |
|
|
34
|
+
| `planLimitHelper` (`parseLimitParam` · `formatLimitParam` · `windowKeyOf` · `windowBoundsOf`) · `LIFETIME_WINDOW` · `OCCUPANCY_WINDOW` | The limit grammar and window algebra. |
|
|
35
|
+
| `promoHelper` (`promoActive` · `promoViewOf`) | Whether a promo is in force for one subscription at one instant. |
|
|
36
36
|
| `EntitlementView` · `EntitlementPlanView` · `CapabilityView` · `LimitView` · `PromoView` · `LimitUsage` (+ wire schemas) | The entitlement view and its rows. |
|
|
37
|
-
| `capabilityViewsOf` · `limitViewsOf` · `entitlementViewOf` · `reviveEntitlementView` · `capabilityOf` · `limitOf` · `hasLimitRoom` | Pure view builders and readers. |
|
|
37
|
+
| `entitlementViewHelper` (`capabilityViewsOf` · `limitViewsOf` · `entitlementViewOf` · `reviveEntitlementView`) · `planLimitHelper` (`capabilityOf` · `limitOf` · `hasLimitRoom`) | Pure view builders and readers. |
|
|
38
38
|
| `CreateCheckoutBody` (`planSku`, `country`, `startRequestId`) · `CreateCheckoutResponse` · `PortalLinkBody` · `PortalLinkResponse` (+ schemas) | Wire shapes an application's own checkout and portal protocols use. |
|
|
39
|
-
| `CheckoutPricingMode` · `AmountCheckoutPolicy` / `QuantityCheckoutPolicy` (+ schemas) · `assertAmountCheckoutPolicy` · `assertQuantityCheckoutPolicy` · `assertCheckoutAmount` · `chargeAmountMinor` | Checkout pricing policies and their validation. |
|
|
40
|
-
| `PricingPolicy` (+ schema) · `DEFAULT_PRICING_POLICY` · `assertPricingPolicy` · `TaxBehavior` · `TaxEstimateStatus` · `TaxType` (+ schemas) | Declared tax/currency behaviour (see § Pricing policy and tax estimate). |
|
|
41
|
-
| `PriceEstimate` · `PriceEstimateBody` · `TaxEstimate` · `TaxRateEstimate` (+ schemas) · `estimateOf` · `ratePpmOf` | The tax/local-currency estimate read model and its pure math. |
|
|
39
|
+
| `CheckoutPricingMode` · `AmountCheckoutPolicy` / `QuantityCheckoutPolicy` (+ schemas) · `checkoutPricingHelper` (`assertAmountCheckoutPolicy` · `assertQuantityCheckoutPolicy` · `assertCheckoutAmount` · `chargeAmountMinor`) | Checkout pricing policies and their validation. |
|
|
40
|
+
| `PricingPolicy` (+ schema) · `DEFAULT_PRICING_POLICY` · `priceEstimateHelper.assertPricingPolicy` · `TaxBehavior` · `TaxEstimateStatus` · `TaxType` (+ schemas) | Declared tax/currency behaviour (see § Pricing policy and tax estimate). |
|
|
41
|
+
| `PriceEstimate` · `PriceEstimateBody` · `TaxEstimate` · `TaxRateEstimate` (+ schemas) · `priceEstimateHelper` (`estimateOf` · `ratePpmOf`) | The tax/local-currency estimate read model and its pure math. |
|
|
42
42
|
| `COUNTRY_CURRENCIES` · `currencyOfCountry` · `COUNTRY_CODES` · `CountrySchema` | ISO 3166-1 → ISO 4217 reference map for a country picker. |
|
|
43
43
|
| `EntitlementRefusal` · `CapabilityRequired` · `LimitExhausted` | Entitlement refusals — all `AuthForbidden` (403). |
|
|
44
44
|
| `PaymentError` · `PaygateError` · `UnknownPaygate` · `PaygateMappingError` · `WebhookSetupError` · `PortalUnavailable` · `ProductError` · `UnknownProduct` · `UnknownPlan` · `PlanRequired` · `PlanRankConflict` · `LimitUnknown` · `LimitMisdeclared` · `PaymentIdentificationError` · `SubscriptionError` · `UnknownSubscription` · `ConsumerRightsError` | Faults (500), except `PortalUnavailable` (409). Importing the package registers every type's message under `errors.<type>` in eight languages (the seven of `SUPPORTED_LNGS` plus `fr`). |
|
|
45
45
|
| `ConsumerRightsRefusal` · `PerformanceConsentRequired` · `SubscriptionStartRequired` (428) · `BillingCountryLocked` · `WithdrawalUnavailable` · `CancellationUnavailable` · `CheckoutLimitExceeded` (409) · `consentRefusalOf` | Consumer-rights and checkout-limit refusals — declared statuses, never `AuthForbidden` (§ Consumer rights). |
|
|
46
46
|
| `ConsumerRegion` · `PurchaseKind` · `ConsentKind` · `DeclarationKind` · `DeclarationChannel` · `CancellationKind` · `WithdrawalStatus` · `CancellationStatus` · `WithdrawalUnavailableReason` · `CancellationUnavailableReason` (+ schemas) | Consumer-rights vocabulary. |
|
|
47
|
-
| `EU_COUNTRIES` · `EU_CONSUMER_TERRITORIES` · `EEA_EXTRA` · `CONSUMER_RIGHTS_TERRITORIES` · `COUNTRY_LANGUAGES` · `isEuCountry` · `isEeaCountry` · `regionOf` · `inScope` · `chargeCurrencyOf` · `billingLanguageOf` | Territories, region, scope, charge currency, legal language. |
|
|
48
|
-
| `ConsumerRightsPolicy` (+ `Links`, `Mechanisms`, schemas) · `DEFAULT_CONSUMER_RIGHTS` · `makeConsumerRightsPolicy` · `assertConsumerRightsPolicy` · `linksOf` · `CONSUMER_RIGHTS_RECORD_TYPE`/`_ID` | The consumer-rights policy record. |
|
|
49
|
-
| `BillingProfileView` · `PurchaseView`/`List` · `PerformanceConsentView`/`Body`/`Response` · `SubscriptionStartView`/`Query`/`Body`/`Response` · `WithdrawalEstimate` · `WithdrawalCandidate`/`List` · `WithdrawalBody` · `DeclarationReceipt` · `WithdrawalReceipt` · `CancellationBody` · `CancellationReceipt` · `ConsumerRightsPublicView` (+ schemas) · `revive*` | Consumer-rights wire shapes (ISO dates) and their revivers. |
|
|
50
|
-
| `withdrawalDeadlineOf` · `lastWithdrawalDayOf` · `withdrawalOpen` · `oneTimeWithdrawalRefund` · `subscriptionWithdrawalRefund` · `splitByShares` · `allocateFifo` · `unitsUsedAfter` · `cancellationEffectiveAt` | Pure calculators. |
|
|
51
|
-
| `CONSUMER_RIGHTS_RESOURCE` · `CONSUMER_RIGHTS_COPY_VERSION` · `consumerRightsCopy` · `consumerText` · `consentStatementOf` · `legalLabelsOf` · `placeholdersOf` | The legal copy. |
|
|
47
|
+
| `EU_COUNTRIES` · `EU_CONSUMER_TERRITORIES` · `EEA_EXTRA` · `CONSUMER_RIGHTS_TERRITORIES` · `COUNTRY_LANGUAGES` · `consumerRegionHelper` (`isEuCountry` · `isEeaCountry` · `regionOf` · `inScope` · `chargeCurrencyOf` · `billingLanguageOf`) | Territories, region, scope, charge currency, legal language. |
|
|
48
|
+
| `ConsumerRightsPolicy` (+ `Links`, `Mechanisms`, schemas) · `DEFAULT_CONSUMER_RIGHTS` · `makeConsumerRightsPolicy` · `consumerRightsPolicyHelper` (`assertConsumerRightsPolicy` · `linksOf`) · `CONSUMER_RIGHTS_RECORD_TYPE`/`_ID` | The consumer-rights policy record. |
|
|
49
|
+
| `BillingProfileView` · `PurchaseView`/`List` · `PerformanceConsentView`/`Body`/`Response` · `SubscriptionStartView`/`Query`/`Body`/`Response` · `WithdrawalEstimate` · `WithdrawalCandidate`/`List` · `WithdrawalBody` · `DeclarationReceipt` · `WithdrawalReceipt` · `CancellationBody` · `CancellationReceipt` · `ConsumerRightsPublicView` (+ schemas) · `consumerReviveHelper.revive*` | Consumer-rights wire shapes (ISO dates) and their revivers. |
|
|
50
|
+
| `withdrawalDeadlineHelper` (`withdrawalDeadlineOf` · `lastWithdrawalDayOf` · `withdrawalOpen`) · `withdrawalRefundHelper` (`oneTimeWithdrawalRefund` · `subscriptionWithdrawalRefund` · `splitByShares`) · `fifoHelper` (`allocateFifo` · `unitsUsedAfter`) · `cancellationEffectiveAt` | Pure calculators. |
|
|
51
|
+
| `CONSUMER_RIGHTS_RESOURCE` · `CONSUMER_RIGHTS_COPY_VERSION` · `consumerCopyHelper` (`consumerRightsCopy` · `consumerText` · `consentStatementOf` · `startContextOf` · `legalLabelsOf` · `placeholdersOf`) | The legal copy and the start statement's variant. |
|
|
52
52
|
| `makeConsumerRightsProtocols` · `makeCheckoutReadProtocols` | Protocol factories. |
|
|
53
|
-
| `AmountNarrowing` · `narrowAmountPolicy` · `amountAllowed` · `CheckoutLimitView` · `AmountPolicyView`/`Query` · `PlanPriceView`/`List`/`PlanPricesQuery` (+ schemas) | Per-entity narrowing of an amount checkout, and synced plan prices. |
|
|
53
|
+
| `AmountNarrowing` · `amountNarrowingHelper` (`narrowAmountPolicy` · `amountAllowed`) · `CheckoutLimitView` · `AmountPolicyView`/`Query` · `PlanPriceView`/`List`/`PlanPricesQuery` (+ schemas) | Per-entity narrowing of an amount checkout, and synced plan prices. |
|
|
54
54
|
|
|
55
55
|
Subpath: `./utils` — the `Config` / `Context` aliases to type your own context against.
|
|
56
56
|
|
|
@@ -99,13 +99,14 @@ A **limit** is counted: a `LimitDeclaration` under a key in `plan.limits`, asked
|
|
|
99
99
|
limit:<key>[>=<n>]
|
|
100
100
|
|
|
101
101
|
- **`limit` is a reserved scope.** A plan never declares a capability set under it,
|
|
102
|
-
`hasEntitlement` answers `false` for any `limit:` parameter, and the view
|
|
103
|
-
set. A limit requirement can therefore never be satisfied by a capability
|
|
102
|
+
`entitlementParamHelper.hasEntitlement` answers `false` for any `limit:` parameter, and the view
|
|
103
|
+
builders skip such a set. A limit requirement can therefore never be satisfied by a capability
|
|
104
|
+
grant.
|
|
104
105
|
- **One grammar, two gate services.** Capability parameters go to `ENTITLEMENT_GATE`
|
|
105
106
|
(`entitled(params)` is sugar for it), limit parameters to `LIMIT_GATE`
|
|
106
|
-
(`{ gate: { alias: LIMIT_GATE, params: [formatLimitParam(key)] } }`). The aliases
|
|
107
|
-
the framework collects an entrypoint's gates per gate service — one alias would let
|
|
108
|
-
requirement hide the other.
|
|
107
|
+
(`{ gate: { alias: LIMIT_GATE, params: [planLimitHelper.formatLimitParam(key)] } }`). The aliases
|
|
108
|
+
differ because the framework collects an entrypoint's gates per gate service — one alias would let
|
|
109
|
+
one requirement hide the other.
|
|
109
110
|
- **`@` is deliberately not part of the grammar.** That is `@owlmeans/iam`'s resource-selector
|
|
110
111
|
syntax; reusing it would make two different things look identical in a route declaration.
|
|
111
112
|
- **Keep flags, magnitudes and counts apart.** `CAPABILITY_FEATURE_SCOPE` carries booleans; a
|
|
@@ -114,16 +115,17 @@ A **limit** is counted: a `LimitDeclaration` under a key in `plan.limits`, asked
|
|
|
114
115
|
with it.
|
|
115
116
|
- **A floor is a numeric question.** `>=n` passes only for a number at least that big — a boolean
|
|
116
117
|
flag, however true, does not answer it. For a limit, `>=n` asks for `n` units of room.
|
|
117
|
-
- **A malformed parameter answers `false` / `null`, it never throws.**
|
|
118
|
-
`parseLimitParam` returns `null`
|
|
119
|
-
|
|
118
|
+
- **A malformed parameter answers `false` / `null`, it never throws.**
|
|
119
|
+
`entitlementParamHelper.hasEntitlement` refuses, `planLimitHelper.parseLimitParam` returns `null`
|
|
120
|
+
for a capability parameter, a bare key, an empty key or a floor that is not positive. A gate that
|
|
121
|
+
crashed on a typo would take down the endpoint it guards.
|
|
120
122
|
- **Declare the requirement on the protocol, not in the handler.** The framework asserts gates
|
|
121
123
|
before the handler is entered, so the route table states what a feature costs. Several
|
|
122
124
|
parameters of one gate are OR'd. The gate services themselves live in the server integration.
|
|
123
125
|
|
|
124
126
|
## The three limit kinds
|
|
125
127
|
|
|
126
|
-
| Kind | Window key (`windowKeyOf`) | Renews | Typical use |
|
|
128
|
+
| Kind | Window key (`planLimitHelper.windowKeyOf`) | Renews | Typical use |
|
|
127
129
|
|---|---|---|---|
|
|
128
130
|
| `window` + `day` | `YYYY-MM-DD` | at UTC midnight | per-day actions |
|
|
129
131
|
| `window` + `month` | `YYYY-MM` | on the 1st, UTC | per-month actions |
|
|
@@ -132,8 +134,8 @@ A **limit** is counted: a `LimitDeclaration` under a key in `plan.limits`, asked
|
|
|
132
134
|
|
|
133
135
|
- Windows are **calendar UTC**, never rolling and never local: two servers in two zones must agree
|
|
134
136
|
on which counter a unit lands in.
|
|
135
|
-
- `windowBoundsOf(window, at)` returns `start` inclusive and `resetsAt`
|
|
136
|
-
is the first instant of the next window and already belongs to it.
|
|
137
|
+
- `planLimitHelper.windowBoundsOf(window, at)` returns `start` inclusive and `resetsAt`
|
|
138
|
+
**exclusive** — `resetsAt` is the first instant of the next window and already belongs to it.
|
|
137
139
|
- A `window` limit without a known `window` (or an unknown kind) throws `LimitMisdeclared`: a
|
|
138
140
|
misdeclared plan is loud, not a silently unlimited one.
|
|
139
141
|
- `limit: 0` means "not included" — a declared key with no room, which a UI renders as such.
|
|
@@ -147,30 +149,32 @@ A **limit** is counted: a `LimitDeclaration` under a key in `plan.limits`, asked
|
|
|
147
149
|
- A lapsed promo makes a capability `granted: false` and a limit's `limit: 0` — the row stays in
|
|
148
150
|
the view with `promo.active: false`, so a UI can say the promotion ended rather than pretend the
|
|
149
151
|
feature never existed.
|
|
150
|
-
- `promoViewOf` → `{ until, grandfathered, active }` is what a UI inscribes: active and
|
|
151
|
-
grandfathered ⇒ "free until"; grandfathered ⇒ "kept for your plan"; inactive ⇒ "ended".
|
|
152
|
+
- `promoHelper.promoViewOf` → `{ until, grandfathered, active }` is what a UI inscribes: active and
|
|
153
|
+
not grandfathered ⇒ "free until"; grandfathered ⇒ "kept for your plan"; inactive ⇒ "ended".
|
|
152
154
|
- An unparseable `until` is never in force.
|
|
153
155
|
|
|
154
156
|
## The entitlement view
|
|
155
157
|
|
|
156
|
-
`entitlementViewOf(plan, planView, usage, at?)` is the one read of what an
|
|
158
|
+
`entitlementViewHelper.entitlementViewOf(plan, planView, usage, at?)` is the one read of what an
|
|
159
|
+
entity may do:
|
|
157
160
|
|
|
158
161
|
- `plan` — the `EntitlementPlanView` the caller resolved (sku, rank, free, status, paygate,
|
|
159
162
|
period, trial, cancel-at-period-end, past-due, fallback). **Promos are measured against
|
|
160
163
|
`planView.subscribedAt`** — set it to the subscription's creation date, or nothing is
|
|
161
164
|
grandfathered.
|
|
162
|
-
- `capabilities` — `capabilityViewsOf`: one row per non-null, non-false permission, `param`
|
|
165
|
+
- `capabilities` — its `capabilityViewsOf`: one row per non-null, non-false permission, `param`
|
|
163
166
|
exactly as the capability gate takes it.
|
|
164
|
-
- `limits` — `limitViewsOf`: one row per declared key; `used` from the `LimitUsage` row of the
|
|
167
|
+
- `limits` — its `limitViewsOf`: one row per declared key; `used` from the `LimitUsage` row of the
|
|
165
168
|
CURRENT window (none ⇒ `0`); `remaining = max(0, limit - used)`; `windowStart`/`resetsAt` only
|
|
166
169
|
for a window limit.
|
|
167
|
-
- Read it with `capabilityOf(view, param)` (the same predicate as the gate, over
|
|
168
|
-
`limitOf(view, key)` and
|
|
169
|
-
|
|
170
|
+
- Read it with `planLimitHelper.capabilityOf(view, param)` (the same predicate as the gate, over
|
|
171
|
+
granted rows), `planLimitHelper.limitOf(view, key)` and
|
|
172
|
+
`planLimitHelper.hasLimitRoom(limitView, atLeast)`. The server gate and the browser call the same
|
|
173
|
+
functions, so the UI's "disabled" and the server's refusal cannot disagree.
|
|
170
174
|
- **The wire carries dates as ISO strings.** The view schemas describe that
|
|
171
175
|
(`{ type: 'string', format: 'date-time' }`): a response serializer writes a `Date` through it as
|
|
172
176
|
ISO, while the record convention (`DateSchema`, an object) would serialize it as `{}`. A browser
|
|
173
|
-
calls `reviveEntitlementView` before touching a date.
|
|
177
|
+
calls `entitlementViewHelper.reviveEntitlementView` before touching a date.
|
|
174
178
|
|
|
175
179
|
## Refusals and faults
|
|
176
180
|
|
|
@@ -229,9 +233,9 @@ infer a pricing mode from the presence of `amountMinor`.
|
|
|
229
233
|
|
|
230
234
|
The plan's `amountPolicy` is the same for everyone; what one entity may buy NOW is narrower when a
|
|
231
235
|
checkout plugin (a spending tier, a rolling cap, a fraud hold) answers an `AmountNarrowing`
|
|
232
|
-
`{ maximumMinor, reason, resetsAt?, remainingMinor? }`.
|
|
233
|
-
{ productSku?, planSku? })` is the one
|
|
234
|
-
share, so they cannot disagree:
|
|
236
|
+
`{ maximumMinor, reason, resetsAt?, remainingMinor? }`.
|
|
237
|
+
`amountNarrowingHelper.narrowAmountPolicy(base, narrowings, { productSku?, planSku? })` is the one
|
|
238
|
+
computation the server's refusal and the dialog's control share, so they cannot disagree:
|
|
235
239
|
|
|
236
240
|
- the maximum is the smallest of the base maximum and every narrowing's (negative or fractional
|
|
237
241
|
values floor at 0); `reason`/`resetsAt`/`remainingMinor` come from the narrowing that set it,
|
|
@@ -239,10 +243,11 @@ share, so they cannot disagree:
|
|
|
239
243
|
- presets above the maximum are dropped, the default is clamped into `[minimum, maximum]`;
|
|
240
244
|
- `limit` is `null` when nothing lowered the base maximum — no note to show;
|
|
241
245
|
- **`limit.blocked`** (`limit.maximumMinor < base.minimumMinor`) means no amount may be bought now.
|
|
242
|
-
The returned `policy` is then still a VALID policy
|
|
243
|
-
pinned to the minimum with no
|
|
244
|
-
|
|
245
|
-
|
|
246
|
+
The returned `policy` is then still a VALID policy
|
|
247
|
+
(`checkoutPricingHelper.assertAmountCheckoutPolicy` accepts it), pinned to the minimum with no
|
|
248
|
+
presets, so a validator never throws — but it is NOT an offer of the minimum: a UI disables the
|
|
249
|
+
input and the confirm button on `blocked`, and a server refuses every amount with
|
|
250
|
+
`CheckoutLimitExceeded`. `amountNarrowingHelper.amountAllowed(view, amount)` answers exactly that.
|
|
246
251
|
|
|
247
252
|
`CheckoutLimitExceeded` (409) packs `checkout-limit-exceeded:<encodeURIComponent(reason)>:
|
|
248
253
|
<maximumMinor>:<currency>[:<resetsAt ISO>]` and rebuilds `reason`, `maximumMinor`, `currency`,
|
|
@@ -267,17 +272,18 @@ billing country is locked and overrides the request — a picker then shows it a
|
|
|
267
272
|
it), `region`, `currency`, `behavior`, `tax: TaxEstimate` (`status`
|
|
268
273
|
one of `TaxEstimateStatus` — `taxed`/`reverse-charge`/`none`/`at-checkout`/`location-required` —
|
|
269
274
|
plus `subtotalMinor`/`taxMinor`/`totalMinor`, `scalable`, and `rates: TaxRateEstimate[]` with
|
|
270
|
-
`ratePpm` parsed by `ratePpmOf` from Stripe's `percentage_decimal`, never
|
|
271
|
-
and an optional `local` (currency + `exchangeRate`, from Stripe's FX Quotes).
|
|
272
|
-
`estimateOf(amountMinor, estimate)` re-derives tax and a total
|
|
273
|
-
estimate's own reference one — exact only when `scalable` and the
|
|
274
|
-
`taxMinor`/`totalMinor` come back `null` otherwise, meaning "computed
|
|
275
|
-
number. When the source estimate carries `local`, the result's own
|
|
276
|
-
and total in THAT currency
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
275
|
+
`ratePpm` parsed by `priceEstimateHelper.ratePpmOf` from Stripe's `percentage_decimal`, never
|
|
276
|
+
`Number(x) * 10_000`), and an optional `local` (currency + `exchangeRate`, from Stripe's FX Quotes).
|
|
277
|
+
The pure helper `priceEstimateHelper.estimateOf(amountMinor, estimate)` re-derives tax and a total
|
|
278
|
+
for a DIFFERENT amount than the estimate's own reference one — exact only when `scalable` and the
|
|
279
|
+
behavior is `Exclusive`; both `taxMinor`/`totalMinor` come back `null` otherwise, meaning "computed
|
|
280
|
+
at checkout", never a wrong number. When the source estimate carries `local`, the result's own
|
|
281
|
+
`local` gives the subtotal, tax and total in THAT currency
|
|
282
|
+
(`subtotalAmount`/`taxAmount`/`totalAmount`, major units) alongside the integration-currency ones —
|
|
283
|
+
a UI shows one or the other, marking the local figures `≈`, never both side by side.
|
|
284
|
+
`COUNTRY_CURRENCIES` / `currencyOfCountry` / `COUNTRY_CODES` is a reference ISO 3166-1 → ISO 4217
|
|
285
|
+
map for a country picker and the local-currency lookup — not a Stripe list, and a country absent
|
|
286
|
+
from it still gets a tax estimate, just no local-currency line.
|
|
281
287
|
|
|
282
288
|
## Consumer rights (EU withdrawal, cancellation, country lock)
|
|
283
289
|
|
|
@@ -291,13 +297,14 @@ Nothing here is product copy — the trader, plan and product names are placehol
|
|
|
291
297
|
- `EU_COUNTRIES` (27, Greece is `GR`), `EU_CONSUMER_TERRITORIES` (plus AX, GF, GP, MQ, RE, YT, MF —
|
|
292
298
|
consumer law applies there even where EU VAT does not), `EEA_EXTRA` (IS, LI, NO) and their union
|
|
293
299
|
`CONSUMER_RIGHTS_TERRITORIES`, the default `policy.countries`.
|
|
294
|
-
- `regionOf(country, policy?)`: `Eu` inside the policy's territories, `Other`
|
|
295
|
-
country. `inScope(region, country, policy)`: a known
|
|
296
|
-
known region, else `unknownCountry` — `'protect'` by
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
300
|
+
- `consumerRegionHelper.regionOf(country, policy?)`: `Eu` inside the policy's territories, `Other`
|
|
301
|
+
outside, `null` for no country. `consumerRegionHelper.inScope(region, country, policy)`: a known
|
|
302
|
+
country decides by the territories, else a known region, else `unknownCountry` — `'protect'` by
|
|
303
|
+
default, so an unknown buyer is protected.
|
|
304
|
+
- `consumerRegionHelper.chargeCurrencyOf(region, policy, fallback)`: the policy's currency for the
|
|
305
|
+
region; an unknown region reads as `Eu`. The display currency is the charge currency, everywhere.
|
|
306
|
+
- `consumerRegionHelper.billingLanguageOf(country, policy?, fallback?)`: `policy.languages`, then
|
|
307
|
+
`COUNTRY_LANGUAGES` (unambiguous countries only — BE, LU, CH are absent), then `fallback`, then
|
|
301
308
|
`policy.defaultLanguage`. Legal copy is shown in this language, with a toggle to the UI language.
|
|
302
309
|
|
|
303
310
|
### The policy record
|
|
@@ -307,56 +314,66 @@ server integration through `makeConsumerRightsPolicy(def)` — `DEFAULT_CONSUMER
|
|
|
307
314
|
(14 days, weekend rollover, margin 5 — a period ending on a public holiday runs to the next working
|
|
308
315
|
day and holiday clusters need up to five, no per-country calendar is kept —, every mechanism OFF,
|
|
309
316
|
`defaultLanguage: 'en'`, start requests
|
|
310
|
-
usable 3600 s) — and `assertConsumerRightsPolicy` (non-empty
|
|
311
|
-
countries, `withdrawalDays >= 14`, margin 0..7, lowercase currencies,
|
|
312
|
-
language present, `withdrawalInformation` required while `withdrawal` or
|
|
313
|
-
on
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
317
|
+
usable 3600 s) — and `consumerRightsPolicyHelper.assertConsumerRightsPolicy` (non-empty
|
|
318
|
+
`textVersion`, `^[A-Z]{2}$` countries, `withdrawalDays >= 14`, margin 0..7, lowercase currencies,
|
|
319
|
+
https links, the default language present, `withdrawalInformation` required while `withdrawal` or
|
|
320
|
+
`performanceConsent` is on, `consentContext` a lowercase key `^[a-z][a-z0-9-]*$`; throws
|
|
321
|
+
`ConsumerRightsError('policy:<field>')`). It carries only public links, territories, switches and
|
|
322
|
+
the consent context — mail options live in a backend-only plugin config — so it is ADVERTISED to the
|
|
323
|
+
browser like the pricing policy. **`consentContext`** names the copy variant of the performance
|
|
324
|
+
consent (`'included'`: the credit limits included in a plan are used first, so the consent covers
|
|
325
|
+
topped-up credits once those limits have run out): the server records and mails, and the dialog
|
|
326
|
+
shows, the `_<context>` texts (§ The legal copy); absent, the base texts.
|
|
327
|
+
`PaymentService.consumerRightsPolicy()` answers `null` when none is declared: no consumer-rights
|
|
328
|
+
behaviour at all. `consumerRightsPolicyHelper.linksOf(policy, lng)` merges a language's links field
|
|
329
|
+
by field over the default language's (`de-AT` reads `de`).
|
|
318
330
|
|
|
319
331
|
`ProductPlan.withdrawal.components: PlanWithdrawalComponent[]` (`{ key, basis: 'time' | 'units',
|
|
320
332
|
shareMinor }`) states the separately priced parts of a subscription (CJEU C-641/19 PE Digital:
|
|
321
|
-
without them the whole price is pro rata by time).
|
|
333
|
+
without them the whole price is pro rata by time). The same declaration picks the subscription start
|
|
334
|
+
statement: a `units` part makes it the `_units` variant (`consumerCopyHelper.startContextOf`, § The
|
|
335
|
+
legal copy).
|
|
322
336
|
|
|
323
337
|
### Wire views
|
|
324
338
|
|
|
325
339
|
Every view schema carries dates as ISO strings (as `model/view.ts` does) and is revived with its
|
|
326
|
-
`revive*`
|
|
327
|
-
`reviveConsentResponse`, `reviveStartResponse`, `reviveWithdrawalList`,
|
|
328
|
-
`reviveCheckoutLimit`, `reviveAmountPolicyView`) — idempotent. A nullable enum on
|
|
329
|
-
`null` in its enum (ajv rejects `null` otherwise). The consent and start views carry
|
|
330
|
-
name the statement is rendered with,
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
contract
|
|
340
|
+
`consumerReviveHelper.revive*` member (`reviveConsentView`, `revivePurchase`/`List`,
|
|
341
|
+
`reviveBillingProfile`, `reviveConsentResponse`, `reviveStartResponse`, `reviveWithdrawalList`,
|
|
342
|
+
`reviveReceipt`, `reviveCheckoutLimit`, `reviveAmountPolicyView`) — idempotent. A nullable enum on
|
|
343
|
+
the wire lists `null` in its enum (ajv rejects `null` otherwise). The consent and start views carry
|
|
344
|
+
`trader`, the name the statement is rendered with, and `context`, the variant it is rendered with —
|
|
345
|
+
the consent view the policy's `consentContext`, the start view
|
|
346
|
+
`consumerCopyHelper.startContextOf(plan)` (`'units'`), each absent for the base — so the server's
|
|
347
|
+
record and the dialog's text are identical. `WithdrawalBody` and `CancellationBody` ask only for
|
|
348
|
+
name, contract and e-mail (plus the cancellation kind, reason and date) and accept an optional
|
|
349
|
+
`honeypot` a person never fills. A public declaration answers `DeclarationReceipt` — what was
|
|
350
|
+
declared and when, never whether a contract matched.
|
|
335
351
|
|
|
336
352
|
### Calculators — always in the consumer's favour
|
|
337
353
|
|
|
338
354
|
All amounts in BigInt; a deduction rounds DOWN, a refund rounds UP, a refund never exceeds what is
|
|
339
355
|
still unrefunded.
|
|
340
356
|
|
|
341
|
-
- `withdrawalDeadlineOf(purchasedAt, rule | policy)` → the EXCLUSIVE end:
|
|
342
|
-
`days`, a Saturday/Sunday last day moved to Monday, + `marginDays`, start
|
|
343
|
-
Wed 2026-09-23 → 2026-10-13T00:00Z; Sat 2026-09-26 → 2026-10-18T00:00Z; Sun
|
|
344
|
-
2027-01-10T00:00Z (margin 5). `withdrawalOpen(window, at)` —
|
|
345
|
-
not refunded. **A person is shown the last included day**,
|
|
346
|
-
UTC day of `deadline − 1 ms`),
|
|
347
|
-
|
|
348
|
-
|
|
357
|
+
- `withdrawalDeadlineHelper.withdrawalDeadlineOf(purchasedAt, rule | policy)` → the EXCLUSIVE end:
|
|
358
|
+
the purchase's UTC day + `days`, a Saturday/Sunday last day moved to Monday, + `marginDays`, start
|
|
359
|
+
of the next UTC day. Wed 2026-09-23 → 2026-10-13T00:00Z; Sat 2026-09-26 → 2026-10-18T00:00Z; Sun
|
|
360
|
+
2026-12-20 → 2027-01-10T00:00Z (margin 5). `withdrawalDeadlineHelper.withdrawalOpen(window, at)` —
|
|
361
|
+
before the deadline, not withdrawn, not refunded. **A person is shown the last included day**,
|
|
362
|
+
`withdrawalDeadlineHelper.lastWithdrawalDayOf(deadline)` (the UTC day of `deadline − 1 ms`),
|
|
363
|
+
phrased "until the end of <date>" — never the exclusive instant.
|
|
364
|
+
- `withdrawalRefundHelper.oneTimeWithdrawalRefund({ paidMinor, refundedMinor?, unitsGranted, unitsUsed })`
|
|
365
|
+
→ `min(paid − refunded, ceil(paid × (granted − used) / granted))`; `unitsUsed` is the deduction —
|
|
349
366
|
units used AFTER consent (none before it) plus debt settled from the lot plus units already
|
|
350
367
|
clawed back (`@owlmeans/server-payment` passes the meter's `usedAfter + settled + clawed`);
|
|
351
368
|
returns `unitsReturned`. 1256 paid, 125k of 500k used → 942.
|
|
352
|
-
- `subscriptionWithdrawalRefund(...)` splits `netMinor` by the components
|
|
353
|
-
remainder); a `time` part loses
|
|
354
|
-
`
|
|
355
|
-
`floor(c × used / granted)`; gross =
|
|
356
|
-
days and 100k of 500k used → 2091.
|
|
357
|
-
- `allocateFifo(lots, spends)` — a spend takes the oldest lot granted at or before it;
|
|
358
|
-
`unallocated`. `unitsUsedAfter(lot, consentedAt)` counts slices strictly
|
|
359
|
-
without one.
|
|
369
|
+
- `withdrawalRefundHelper.subscriptionWithdrawalRefund(...)` splits `netMinor` by the components
|
|
370
|
+
(its `splitByShares`, largest remainder); a `time` part loses
|
|
371
|
+
`floor(c × elapsedDays / periodDays)` counted from `max(periodStart, servicesRequestedAt)` —
|
|
372
|
+
NOTHING without a start request; a `units` part loses `floor(c × used / granted)`; gross =
|
|
373
|
+
`ceil(paid × refundNet / net)`. Net 2000 / paid 2460, 3 of 30 days and 100k of 500k used → 2091.
|
|
374
|
+
- `fifoHelper.allocateFifo(lots, spends)` — a spend takes the oldest lot granted at or before it;
|
|
375
|
+
overflow is `unallocated`. `fifoHelper.unitsUsedAfter(lot, consentedAt)` counts slices strictly
|
|
376
|
+
after the consent, `0` without one.
|
|
360
377
|
- `cancellationEffectiveAt(periodEnd, 'month' | 'year', requested?)` — the period end, or the first
|
|
361
378
|
boundary on or after a later requested date (end-of-month clamped from the anchor).
|
|
362
379
|
|
|
@@ -386,10 +403,11 @@ The i18n resource `payment-consumer-rights` (`CONSUMER_RIGHTS_RESOURCE`, library
|
|
|
386
403
|
namespace), in en pl ru be uk es de fr, versioned by `CONSUMER_RIGHTS_COPY_VERSION` (bump it on ANY
|
|
387
404
|
change to a bundle). Branches: `performance-consent`, `subscription-start` (`title`, `intro`,
|
|
388
405
|
`request`, `acknowledgement`, `checkbox` = request + space + acknowledgement, `confirm`,
|
|
389
|
-
`decline`; the consent branch also `purchase
|
|
406
|
+
`decline`; the consent branch also `purchase`; the start branch's `request`/`acknowledgement`/
|
|
407
|
+
`checkbox` also as `_units`), `withdrawal`, `cancellation` (form labels and the
|
|
390
408
|
statutory buttons `function` / `confirm`), `links`, `checkout` (`terms-acceptance.{in-scope,
|
|
391
409
|
other}` markdown, `renewal.{month, year, after-submit}`, `price.{exclusive, inclusive, exclusive-tax}` (VAT wording for the territories, "applicable tax" for a buyer outside them), `top-up`,
|
|
392
|
-
`top-up-note`), `email.{common, consent, start, purchase, withdrawal, cancellation}` (the purchase
|
|
410
|
+
`top-up-note`), `email.{common, consent, start (`rule` + `rule_units`), purchase, withdrawal, cancellation}` (the purchase
|
|
393
411
|
mail carries the CRD Annex I(A) withdrawal information with the function's address and the Annex
|
|
394
412
|
I(B) model form, per language from the national models; there `{{trader}}` is the trader's whole
|
|
395
413
|
identity — legal name, address, e-mail; a `review` withdrawal receipt promises the reimbursement
|
|
@@ -397,12 +415,38 @@ within the statutory 14 days; `email.cancellation.review` answers an extraordina
|
|
|
397
415
|
whose status is `CancellationStatus.Review`), `credit-note.memo`. In the consent and start
|
|
398
416
|
STATEMENTS `{{trader}}` is the trader's short name.
|
|
399
417
|
|
|
400
|
-
- Read it with `consumerRightsCopy(lng)` (any language, merged key by key over
|
|
401
|
-
instance, never drains a bundle — `resolveI18nResource`),
|
|
402
|
-
`{{name}}`; throws
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
418
|
+
- Read it with `consumerCopyHelper.consumerRightsCopy(lng)` (any language, merged key by key over
|
|
419
|
+
English, no i18next instance, never drains a bundle — `i18nHelper.resolveI18nResource`),
|
|
420
|
+
`consumerCopyHelper.consumerText(lng, path, vars, context?)` (fills `{{name}}`; throws
|
|
421
|
+
`ConsumerRightsError('copy:<path>[:<name>]')` on a missing text or value — a legal text never goes
|
|
422
|
+
out with a hole), `consumerCopyHelper.consentStatementOf(lng, kind, { trader, plan?, context? })`
|
|
423
|
+
(the exact statement the dialog shows, the server records and the mail repeats) and
|
|
424
|
+
`consumerCopyHelper.legalLabelsOf(lng)`.
|
|
425
|
+
- **Context variants** (the i18next context suffix): with a `context`,
|
|
426
|
+
`consumerCopyHelper.consumerText` reads `<path>_<context>` first and the base `path` only where no
|
|
427
|
+
such variant exists (a missing value then names the variant: `copy:<path>_<context>:<name>`); an
|
|
428
|
+
empty context is none. `consumerCopyHelper.consentStatementOf` passes its `context` to all three
|
|
429
|
+
texts. Shipped variants, all eight languages, same placeholders as the base keys, each request
|
|
430
|
+
keeping the base request's statutory opening verbatim; a new variant lands in every language at
|
|
431
|
+
once, with its base key's placeholders:
|
|
432
|
+
- `performance-consent.{title,intro,request,checkbox}_included` — the consuming platform's
|
|
433
|
+
vocabulary: "topped-up credits" (pl doładowane, ru пополненные, be папоўненыя, uk поповнені, es
|
|
434
|
+
recargados, de aufgeladene, fr rechargés) are spent once "the credit limits included in my plan"
|
|
435
|
+
(a plan's non-monetary credits) have run out; `checkbox_included` = `request_included` + space +
|
|
436
|
+
the BASE `acknowledgement` (generic "credits", so `acknowledgement` has no variant).
|
|
437
|
+
- **The subscription start statement follows the plan's withdrawal arithmetic.** The BASE
|
|
438
|
+
`subscription-start.{request,acknowledgement,checkbox}` and `email.start.rule` describe the
|
|
439
|
+
common case — the plan withdrawn pro rata by the DAYS ELAPSED only ("starts the {{plan}}
|
|
440
|
+
services — including the AI work within the usage the plan includes — now …; … I pay for the
|
|
441
|
+
services provided until then, pro rata by the days elapsed, and everything else is
|
|
442
|
+
reimbursed"); `…_units` (`checkbox_units` = `request_units` + space + `acknowledgement_units`)
|
|
443
|
+
describe the split — services pro rata by time, the right of withdrawal expiring for the
|
|
444
|
+
included units used. `consumerCopyHelper.startContextOf(plan)` is the ONE decision: `'units'`
|
|
445
|
+
exactly when the plan's `withdrawal.components` has a `basis: 'units'` part, else `undefined`.
|
|
446
|
+
Every renderer takes the context from it — the server's start view, the recorded statement and
|
|
447
|
+
the start mail, and the dialog (from the view's `context`) — so the statement on screen is the
|
|
448
|
+
one recorded. `title`, `intro`, `confirm`, `decline` have no `_units` variant. Generic statutory
|
|
449
|
+
text (the purchase mail's withdrawal information) stays generic.
|
|
406
450
|
- Statutory labels are pinned by a test: en "Withdraw from contract here" / "Confirm withdrawal",
|
|
407
451
|
"Cancel contracts here" / "Cancel now"; de "Vertrag widerrufen" / "Widerruf bestätigen",
|
|
408
452
|
"Verträge hier kündigen" / "Jetzt kündigen"; fr "Renoncer au contrat ici" / "Confirmer la
|
|
@@ -412,13 +456,15 @@ STATEMENTS `{{trader}}` is the trader's short name.
|
|
|
412
456
|
"Cancelar ahora"; uk/ru/be are courtesy translations.
|
|
413
457
|
- The express request uses the statutory verbs (PL "Żądam i wyrażam wyraźną zgodę … Przyjmuję do
|
|
414
458
|
wiadomości …", DE "Ich verlange ausdrücklich und stimme ausdrücklich zu … Mir ist bekannt …", FR
|
|
415
|
-
"Je demande expressément et j’accepte expressément … Je reconnais perdre …").
|
|
459
|
+
"Je demande expressément et j’accepte expressément … Je reconnais perdre …"). Every start
|
|
460
|
+
request — base and `_units`, every language — opens with the same three words as that language's
|
|
461
|
+
performance request (pinned by the copy spec).
|
|
416
462
|
- Wording rule, enforced by a scan of every language: say "the right of withdrawal expires" and
|
|
417
463
|
"only unused credits are reimbursed" — never non-refundable / nicht erstattungsfähig / non
|
|
418
464
|
remboursable / bezzwrotny / no reembolsable / невозвратный / неповоротний / незваротны.
|
|
419
465
|
- Paygate texts (`checkout.*`) stay within 1200 characters after interpolating long URLs.
|
|
420
|
-
- An application overrides a text with `addI18nApp(lng, CONSUMER_RIGHTS_RESOURCE, data,
|
|
421
|
-
LIB_NAMESPACE })`; every placeholder of a text must match its English master.
|
|
466
|
+
- An application overrides a text with `i18nHelper.addI18nApp(lng, CONSUMER_RIGHTS_RESOURCE, data,
|
|
467
|
+
{ ns: LIB_NAMESPACE })`; every placeholder of a text must match its English master.
|
|
422
468
|
|
|
423
469
|
### Protocol factories
|
|
424
470
|
|
package/build/advertise.js
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import { CONFIG_RECORD } from '@owlmeans/context';
|
|
2
2
|
import { apiConfigPlugin, every } from '@owlmeans/api-config';
|
|
3
|
-
import {
|
|
4
|
-
/**
|
|
5
|
-
* The pricing policy record carries only flags and TTLs (never a Stripe secret, an API version, or
|
|
6
|
-
* a migration switch — those stay in a backend-only plugin), so advertising it to the browser is
|
|
7
|
-
* safe. The consumer-rights policy record carries only public links, territories and switches
|
|
8
|
-
* (the mail options — sender, archive copy — stay in a backend-only plugin config), so the browser
|
|
9
|
-
* renders the same links and switches the server enforces.
|
|
10
|
-
*/
|
|
11
|
-
const advertisedRecordTypes = new Set([
|
|
12
|
-
L10N_RECORD_TYPE, PLAN_RECORD_TYPE, PRODUCT_RECORD_TYPE, PRICING_POLICY_RECORD_TYPE, CONSUMER_RIGHTS_RECORD_TYPE,
|
|
13
|
-
]);
|
|
3
|
+
import { advertisedRecordTypes } from './consts.local.js';
|
|
14
4
|
apiConfigPlugin({
|
|
15
5
|
allow: {
|
|
16
6
|
[CONFIG_RECORD]: every(true, value => value != null && typeof value === 'object'
|
package/build/advertise.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advertise.js","sourceRoot":"","sources":["../src/advertise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,
|
|
1
|
+
{"version":3,"file":"advertise.js","sourceRoot":"","sources":["../src/advertise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,eAAe,CAAC;IACd,KAAK,EAAE;QACL,CAAC,aAAa,CAAC,EAAE,KAAK,CACpB,IAAI,EACJ,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;eAC9C,qBAAqB,CAAC,GAAG,CAAE,KAAiC,CAAC,UAAU,IAAI,EAAE,CAAC,CACpF;KACF;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/checkout/consts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/checkout/consts.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAA"}
|