@funnelfox/billing 0.8.0-beta.4 → 0.8.0-ffb-395.4
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 +211 -0
- package/dist/chunk-index.cjs.js +162 -58
- package/dist/chunk-index.es.js +162 -59
- package/dist/chunk-stripe-card-form.cjs.js +80 -0
- package/dist/chunk-stripe-card-form.es.js +78 -0
- package/dist/chunk-stripe-loader.cjs.js +20 -0
- package/dist/chunk-stripe-loader.es.js +18 -0
- package/dist/chunk-stripe-wallet.cjs.js +111 -0
- package/dist/chunk-stripe-wallet.es.js +108 -0
- package/dist/funnelfox-billing.js +344 -58
- package/dist/funnelfox-billing.min.js +1 -1
- package/package.json +5 -5
- package/src/types.d.ts +94 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ A modern TypeScript SDK for subscription payments with Primer Headless Checkout
|
|
|
11
11
|
- 🔧 **Robust**: Built-in error handling, retries, and validation
|
|
12
12
|
- 📦 **Lightweight**: Minimal dependencies, browser-optimized
|
|
13
13
|
- 🎨 **Headless Checkout**: Full control over checkout UI with Primer Headless Checkout
|
|
14
|
+
- 💳 **Stripe Integration**: Native Stripe Elements card form and Apple Pay / Google Pay wallets
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -711,6 +712,216 @@ const headlessCheckout = await Primer.createHeadless(session.clientToken, {
|
|
|
711
712
|
await headlessCheckout.start();
|
|
712
713
|
```
|
|
713
714
|
|
|
715
|
+
## Stripe Integration
|
|
716
|
+
|
|
717
|
+
The `Billing.stripe` namespace provides a Stripe-native checkout experience — no Primer dependency required. It supports card payments via Stripe Elements and native wallet payments (Apple Pay / Google Pay) via the Payment Request API.
|
|
718
|
+
|
|
719
|
+
> **Note:** `@primer-io/checkout-web` is **not** required for Stripe integration. Only `@funnelfox/billing` and a Stripe-enabled price in your Funnelfox account are needed.
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
### `Billing.stripe.createCardForm(element, params)`
|
|
724
|
+
|
|
725
|
+
Mounts a Stripe Elements payment form into a DOM element. Returns a `{ submit() }` handle — you control when payment is triggered (e.g. on your own button click).
|
|
726
|
+
|
|
727
|
+
```javascript
|
|
728
|
+
const element = document.getElementById('card-form');
|
|
729
|
+
|
|
730
|
+
const cardForm = await Billing.stripe.createCardForm(element, {
|
|
731
|
+
// Required
|
|
732
|
+
priceId: 'price_123',
|
|
733
|
+
externalId: 'user_456',
|
|
734
|
+
|
|
735
|
+
// Optional
|
|
736
|
+
orgId: 'your-org-id',
|
|
737
|
+
email: 'user@example.com',
|
|
738
|
+
countryCode: 'US',
|
|
739
|
+
showWallets: false, // show Apple Pay / Google Pay inside the form
|
|
740
|
+
appearance: {
|
|
741
|
+
// Stripe Elements appearance API
|
|
742
|
+
theme: 'stripe',
|
|
743
|
+
},
|
|
744
|
+
|
|
745
|
+
// Callbacks
|
|
746
|
+
onRenderSuccess: () => {
|
|
747
|
+
document.getElementById('pay-button').disabled = false;
|
|
748
|
+
},
|
|
749
|
+
onLoaderChange: loading => {
|
|
750
|
+
document.getElementById('pay-button').disabled = loading;
|
|
751
|
+
},
|
|
752
|
+
onPaymentSuccess: (paymentMethod, orderId) => {
|
|
753
|
+
window.location.href = '/success?order=' + orderId;
|
|
754
|
+
},
|
|
755
|
+
onPaymentFail: error => {
|
|
756
|
+
console.error('Payment failed:', error.message);
|
|
757
|
+
},
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
// Wire up your own submit button
|
|
761
|
+
document.getElementById('pay-button').addEventListener('click', async () => {
|
|
762
|
+
await cardForm.submit();
|
|
763
|
+
});
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
**Key parameters:**
|
|
767
|
+
|
|
768
|
+
| Parameter | Type | Description |
|
|
769
|
+
| ---------------- | -------- | --------------------------------------------------------------------------------- |
|
|
770
|
+
| `priceId` | string | Price identifier |
|
|
771
|
+
| `externalId` | string | Your user identifier |
|
|
772
|
+
| `email` | string? | Customer email |
|
|
773
|
+
| `orgId` | string? | Org ID (if not globally configured) |
|
|
774
|
+
| `showWallets` | boolean? | Show Apple Pay / Google Pay inside the Stripe form |
|
|
775
|
+
| `appearance` | object? | [Stripe Elements Appearance API](https://stripe.com/docs/elements/appearance-api) |
|
|
776
|
+
| `clientMetadata` | object? | Custom metadata attached to the order |
|
|
777
|
+
|
|
778
|
+
**Returns:** `Promise<{ submit: () => Promise<void> }>`
|
|
779
|
+
|
|
780
|
+
---
|
|
781
|
+
|
|
782
|
+
### `Billing.stripe.getAvailableWallet(params)`
|
|
783
|
+
|
|
784
|
+
Checks whether Apple Pay or Google Pay is available on the current device and browser. Use this to conditionally show a wallet button before attempting payment.
|
|
785
|
+
|
|
786
|
+
```javascript
|
|
787
|
+
const wallet = await Billing.stripe.getAvailableWallet({
|
|
788
|
+
priceId: 'price_123',
|
|
789
|
+
externalId: 'user_456',
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
if (wallet === 'APPLE_PAY') {
|
|
793
|
+
document.getElementById('apple-pay-btn').style.display = 'block';
|
|
794
|
+
} else if (wallet === 'GOOGLE_PAY') {
|
|
795
|
+
document.getElementById('google-pay-btn').style.display = 'block';
|
|
796
|
+
} else {
|
|
797
|
+
// No wallet available — show card form only
|
|
798
|
+
}
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
**Returns:** `Promise<'APPLE_PAY' | 'GOOGLE_PAY' | null>`
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
### `Billing.stripe.purchaseWallet(params)`
|
|
806
|
+
|
|
807
|
+
Triggers the native Apple Pay or Google Pay payment sheet. Call this on button click after confirming a wallet is available via `getAvailableWallet`.
|
|
808
|
+
|
|
809
|
+
```javascript
|
|
810
|
+
document.getElementById('wallet-btn').addEventListener('click', async () => {
|
|
811
|
+
await Billing.stripe.purchaseWallet({
|
|
812
|
+
priceId: 'price_123',
|
|
813
|
+
externalId: 'user_456',
|
|
814
|
+
totalLabel: 'Premium Plan', // Label shown in the payment sheet
|
|
815
|
+
|
|
816
|
+
onPaymentSuccess: (paymentMethod, orderId) => {
|
|
817
|
+
window.location.href = '/success?order=' + orderId;
|
|
818
|
+
},
|
|
819
|
+
onPaymentFail: error => {
|
|
820
|
+
console.error('Wallet payment failed:', error.message);
|
|
821
|
+
},
|
|
822
|
+
onPaymentCancel: () => {
|
|
823
|
+
console.log('User cancelled');
|
|
824
|
+
},
|
|
825
|
+
onLoaderChange: loading => {
|
|
826
|
+
document.getElementById('wallet-btn').disabled = loading;
|
|
827
|
+
},
|
|
828
|
+
});
|
|
829
|
+
});
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
**Key parameters:**
|
|
833
|
+
|
|
834
|
+
| Parameter | Type | Description |
|
|
835
|
+
| ---------------- | ------- | --------------------------------------------------- |
|
|
836
|
+
| `priceId` | string | Price identifier |
|
|
837
|
+
| `externalId` | string | Your user identifier |
|
|
838
|
+
| `totalLabel` | string? | Label shown next to the amount in the payment sheet |
|
|
839
|
+
| `email` | string? | Customer email |
|
|
840
|
+
| `clientMetadata` | object? | Custom metadata attached to the order |
|
|
841
|
+
|
|
842
|
+
---
|
|
843
|
+
|
|
844
|
+
### `Billing.stripe.getAvailablePaymentMethods(params)`
|
|
845
|
+
|
|
846
|
+
Returns all Stripe payment methods available for the current device. Always includes `PAYMENT_CARD`; also includes a wallet method if one is detected.
|
|
847
|
+
|
|
848
|
+
```javascript
|
|
849
|
+
const methods = await Billing.stripe.getAvailablePaymentMethods({
|
|
850
|
+
priceId: 'price_123',
|
|
851
|
+
externalId: 'user_456',
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
// methods: ['PAYMENT_CARD', 'APPLE_PAY'] or ['PAYMENT_CARD'] etc.
|
|
855
|
+
console.log('Available:', methods);
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
**Returns:** `Promise<PaymentMethod[]>` — always contains `PAYMENT_CARD`, optionally `APPLE_PAY` or `GOOGLE_PAY`
|
|
859
|
+
|
|
860
|
+
---
|
|
861
|
+
|
|
862
|
+
### Combined Example: Wallet Detection + Card Form Fallback
|
|
863
|
+
|
|
864
|
+
The recommended pattern — show a wallet button when available, always show the card form as fallback:
|
|
865
|
+
|
|
866
|
+
```javascript
|
|
867
|
+
import { Billing } from '@funnelfox/billing';
|
|
868
|
+
|
|
869
|
+
Billing.configure({ orgId: 'your-org-id' });
|
|
870
|
+
|
|
871
|
+
const params = {
|
|
872
|
+
priceId: 'price_123',
|
|
873
|
+
externalId: 'user_456',
|
|
874
|
+
email: 'user@example.com',
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
async function initCheckout() {
|
|
878
|
+
// 1. Check for wallet availability
|
|
879
|
+
const wallet = await Billing.stripe.getAvailableWallet(params);
|
|
880
|
+
|
|
881
|
+
if (wallet) {
|
|
882
|
+
const walletBtn = document.getElementById('wallet-btn');
|
|
883
|
+
walletBtn.textContent =
|
|
884
|
+
wallet === 'APPLE_PAY' ? 'Pay with Apple Pay' : 'Pay with Google Pay';
|
|
885
|
+
walletBtn.style.display = 'block';
|
|
886
|
+
|
|
887
|
+
walletBtn.addEventListener('click', () => {
|
|
888
|
+
Billing.stripe.purchaseWallet({
|
|
889
|
+
...params,
|
|
890
|
+
totalLabel: 'Premium Plan',
|
|
891
|
+
onPaymentSuccess: (_, orderId) => {
|
|
892
|
+
window.location.href = '/success?order=' + orderId;
|
|
893
|
+
},
|
|
894
|
+
onPaymentFail: err => alert(err.message),
|
|
895
|
+
onPaymentCancel: () => console.log('Cancelled'),
|
|
896
|
+
});
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// 2. Always mount card form as fallback
|
|
901
|
+
const cardForm = await Billing.stripe.createCardForm(
|
|
902
|
+
document.getElementById('card-form'),
|
|
903
|
+
{
|
|
904
|
+
...params,
|
|
905
|
+
onPaymentSuccess: (_, orderId) => {
|
|
906
|
+
window.location.href = '/success?order=' + orderId;
|
|
907
|
+
},
|
|
908
|
+
onPaymentFail: err => alert(err.message),
|
|
909
|
+
onLoaderChange: loading => {
|
|
910
|
+
document.getElementById('pay-btn').disabled = loading;
|
|
911
|
+
},
|
|
912
|
+
}
|
|
913
|
+
);
|
|
914
|
+
|
|
915
|
+
document.getElementById('pay-btn').addEventListener('click', () => {
|
|
916
|
+
cardForm.submit();
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
initCheckout();
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
---
|
|
924
|
+
|
|
714
925
|
## Browser Support
|
|
715
926
|
|
|
716
927
|
- Chrome 60+
|
package/dist/chunk-index.cjs.js
CHANGED
|
@@ -491,7 +491,7 @@ exports.PaymentMethod = void 0;
|
|
|
491
491
|
/**
|
|
492
492
|
* @fileoverview Constants for Funnefox SDK
|
|
493
493
|
*/
|
|
494
|
-
const SDK_VERSION = '0.
|
|
494
|
+
const SDK_VERSION = '0.9.0-beta.1';
|
|
495
495
|
const DEFAULTS = {
|
|
496
496
|
BASE_URL: 'https://billing.funnelfox.com',
|
|
497
497
|
REGION: 'default',
|
|
@@ -530,6 +530,7 @@ const API_ENDPOINTS = {
|
|
|
530
530
|
UPDATE_CLIENT_SESSION: '/v1/checkout/update_client_session',
|
|
531
531
|
CREATE_PAYMENT: '/v1/checkout/create_payment',
|
|
532
532
|
RESUME_PAYMENT: '/v1/checkout/resume_payment',
|
|
533
|
+
STRIPE_CREATE_PAYMENT: '/v1/stripe/create_payment',
|
|
533
534
|
ONE_CLICK: '/v1/checkout/one_click',
|
|
534
535
|
CREATE_SIMPLE_CLIENT_SESSION: '/v1/checkout/create_simple_client_session',
|
|
535
536
|
};
|
|
@@ -1128,7 +1129,7 @@ class APIClient {
|
|
|
1128
1129
|
async createClientSession(params) {
|
|
1129
1130
|
const payload = {
|
|
1130
1131
|
region: params.region || 'default',
|
|
1131
|
-
integration_type: 'primer',
|
|
1132
|
+
integration_type: params.integration ?? 'primer',
|
|
1132
1133
|
pp_ident: params.priceId,
|
|
1133
1134
|
external_id: params.externalId,
|
|
1134
1135
|
email_address: params.email,
|
|
@@ -1174,6 +1175,15 @@ class APIClient {
|
|
|
1174
1175
|
body: JSON.stringify(payload),
|
|
1175
1176
|
}));
|
|
1176
1177
|
}
|
|
1178
|
+
async createStripePayment(params) {
|
|
1179
|
+
return (await this.request(API_ENDPOINTS.STRIPE_CREATE_PAYMENT, {
|
|
1180
|
+
method: 'POST',
|
|
1181
|
+
body: JSON.stringify({
|
|
1182
|
+
order_id: params.orderId,
|
|
1183
|
+
payment_method_id: params.paymentMethodId,
|
|
1184
|
+
}),
|
|
1185
|
+
}));
|
|
1186
|
+
}
|
|
1177
1187
|
async resumePayment(params) {
|
|
1178
1188
|
const payload = {
|
|
1179
1189
|
order_id: params.orderId,
|
|
@@ -1264,6 +1274,45 @@ class APIClient {
|
|
|
1264
1274
|
}
|
|
1265
1275
|
}
|
|
1266
1276
|
|
|
1277
|
+
class SessionService {
|
|
1278
|
+
constructor() {
|
|
1279
|
+
this.cache = new Map();
|
|
1280
|
+
}
|
|
1281
|
+
buildCacheKey(p) {
|
|
1282
|
+
return [p.orgId, p.priceId, p.externalId, p.email, p.integration].join('-');
|
|
1283
|
+
}
|
|
1284
|
+
makeClient(orgId, baseUrl) {
|
|
1285
|
+
return new APIClient({
|
|
1286
|
+
baseUrl: baseUrl || DEFAULTS.BASE_URL,
|
|
1287
|
+
orgId,
|
|
1288
|
+
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
1289
|
+
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
createSession(p) {
|
|
1293
|
+
const key = this.buildCacheKey(p);
|
|
1294
|
+
const cached = this.cache.get(key);
|
|
1295
|
+
if (cached)
|
|
1296
|
+
return cached;
|
|
1297
|
+
const client = this.makeClient(p.orgId, p.baseUrl);
|
|
1298
|
+
const req = client.createClientSession({
|
|
1299
|
+
priceId: p.priceId,
|
|
1300
|
+
externalId: p.externalId,
|
|
1301
|
+
email: p.email,
|
|
1302
|
+
region: p.region || DEFAULTS.REGION,
|
|
1303
|
+
clientMetadata: p.clientMetadata,
|
|
1304
|
+
countryCode: p.countryCode,
|
|
1305
|
+
integration: p.integration,
|
|
1306
|
+
});
|
|
1307
|
+
this.cache.set(key, req);
|
|
1308
|
+
return req;
|
|
1309
|
+
}
|
|
1310
|
+
clearCache() {
|
|
1311
|
+
this.cache.clear();
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
var sessionService = new SessionService();
|
|
1315
|
+
|
|
1267
1316
|
var loaderHtml = "<div class=\"ff-sdk-loader-container\">\n <div class=\"ff-sdk-loader\"></div>\n</div>\n";
|
|
1268
1317
|
|
|
1269
1318
|
if(typeof document!=="undefined")document.head.appendChild(document.createElement("style")).textContent=".ff-sdk-loader-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: rgba(255, 255, 255);\n z-index: 2;\n}\n\n.ff-sdk-loader {\n width: 24px;\n height: 24px;\n border: 4px solid #e32f41;\n border-top: 4px solid transparent;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }";
|
|
@@ -1858,6 +1907,12 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1858
1907
|
this.cardEmailAddress = this.checkoutConfig.customer.email;
|
|
1859
1908
|
this.shouldApplySessionCardholderNameConfig =
|
|
1860
1909
|
this.checkoutConfig.card?.cardholderName?.required === undefined;
|
|
1910
|
+
this.apiClient = new APIClient({
|
|
1911
|
+
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
1912
|
+
orgId: this.orgId,
|
|
1913
|
+
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
1914
|
+
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1915
|
+
});
|
|
1861
1916
|
this._setupCallbackBridges();
|
|
1862
1917
|
}
|
|
1863
1918
|
_setupCallbackBridges() {
|
|
@@ -1899,64 +1954,35 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1899
1954
|
}
|
|
1900
1955
|
}
|
|
1901
1956
|
async createSession() {
|
|
1902
|
-
|
|
1903
|
-
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
1957
|
+
const response = await sessionService.createSession({
|
|
1904
1958
|
orgId: this.orgId,
|
|
1905
|
-
|
|
1906
|
-
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1907
|
-
});
|
|
1908
|
-
const sessionParams = {
|
|
1959
|
+
baseUrl: this.baseUrl,
|
|
1909
1960
|
priceId: this.checkoutConfig.priceId,
|
|
1910
1961
|
externalId: this.checkoutConfig.customer.externalId,
|
|
1911
1962
|
email: this.checkoutConfig.customer.email,
|
|
1912
|
-
region: this.region
|
|
1963
|
+
region: this.region,
|
|
1913
1964
|
clientMetadata: this.checkoutConfig.clientMetadata,
|
|
1914
1965
|
countryCode: this.checkoutConfig.customer.countryCode,
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
cachedResponse.radarSessionId = loadStripe(stripePublicKey)
|
|
1936
|
-
.then(stripe => stripe
|
|
1937
|
-
? stripe
|
|
1938
|
-
.createRadarSession()
|
|
1939
|
-
.then(session => session?.radarSession?.id || '')
|
|
1940
|
-
.catch(() => '')
|
|
1941
|
-
: '')
|
|
1942
|
-
.catch(() => '');
|
|
1943
|
-
}
|
|
1944
|
-
// Initialize Airwallex device fingerprinting if enabled by backend
|
|
1945
|
-
if (response.data?.airwallex_risk_enabled) {
|
|
1946
|
-
const isLivemode = response.data?.is_livemode;
|
|
1947
|
-
const deviceId = generateUUID();
|
|
1948
|
-
cachedResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
|
|
1949
|
-
.then(() => deviceId)
|
|
1950
|
-
.catch(() => {
|
|
1951
|
-
// Silently fail - return deviceId anyway
|
|
1952
|
-
return deviceId;
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
return cachedResponse;
|
|
1956
|
-
});
|
|
1957
|
-
// Cache the successful response
|
|
1958
|
-
CheckoutInstance.sessionCache.set(cacheKey, sessionRequest);
|
|
1959
|
-
sessionResponse = await sessionRequest;
|
|
1966
|
+
integration: 'primer',
|
|
1967
|
+
});
|
|
1968
|
+
const sessionResponse = response;
|
|
1969
|
+
if (response.data?.stripe_public_key) {
|
|
1970
|
+
const stripePublicKey = response.data.stripe_public_key;
|
|
1971
|
+
sessionResponse.radarSessionId = loadStripe(stripePublicKey)
|
|
1972
|
+
.then(stripe => stripe
|
|
1973
|
+
? stripe
|
|
1974
|
+
.createRadarSession()
|
|
1975
|
+
.then(session => session?.radarSession?.id || '')
|
|
1976
|
+
.catch(() => '')
|
|
1977
|
+
: '')
|
|
1978
|
+
.catch(() => '');
|
|
1979
|
+
}
|
|
1980
|
+
if (response.data?.airwallex_risk_enabled) {
|
|
1981
|
+
const isLivemode = response.data?.is_livemode;
|
|
1982
|
+
const deviceId = generateUUID();
|
|
1983
|
+
sessionResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
|
|
1984
|
+
.then(() => deviceId)
|
|
1985
|
+
.catch(() => deviceId);
|
|
1960
1986
|
}
|
|
1961
1987
|
this.cachedSessionResponse = sessionResponse;
|
|
1962
1988
|
this.isTelemetryEnabled = !!sessionResponse.data?.sdk_telemetry_enabled;
|
|
@@ -2215,8 +2241,7 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2215
2241
|
try {
|
|
2216
2242
|
this.onLoaderChangeWithRace(true);
|
|
2217
2243
|
this._setState('updating');
|
|
2218
|
-
|
|
2219
|
-
CheckoutInstance.sessionCache.clear();
|
|
2244
|
+
sessionService.clearCache();
|
|
2220
2245
|
await this.apiClient.updateClientSession({
|
|
2221
2246
|
orderId: this.orderId,
|
|
2222
2247
|
clientToken: this.clientToken,
|
|
@@ -2249,7 +2274,7 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2249
2274
|
return;
|
|
2250
2275
|
try {
|
|
2251
2276
|
this.stopUnhandledTelemetry();
|
|
2252
|
-
|
|
2277
|
+
sessionService.clearCache();
|
|
2253
2278
|
await this.primerWrapper.destroy();
|
|
2254
2279
|
this._setState('destroyed');
|
|
2255
2280
|
this.orderId = null;
|
|
@@ -2460,7 +2485,6 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2460
2485
|
this.telemetryPaymentMethod = undefined;
|
|
2461
2486
|
}
|
|
2462
2487
|
}
|
|
2463
|
-
CheckoutInstance.sessionCache = new Map();
|
|
2464
2488
|
|
|
2465
2489
|
/**
|
|
2466
2490
|
* @fileoverview Public API with configuration and orchestration logic
|
|
@@ -2651,6 +2675,79 @@ async function getAvailablePaymentMethods(params) {
|
|
|
2651
2675
|
throw error;
|
|
2652
2676
|
}
|
|
2653
2677
|
}
|
|
2678
|
+
async function createStripeCardForm(element, params) {
|
|
2679
|
+
const config = resolveConfig(params, 'createStripeCardForm');
|
|
2680
|
+
const [session, { mountStripeCardForm }] = await Promise.all([
|
|
2681
|
+
sessionService.createSession({
|
|
2682
|
+
orgId: config.orgId,
|
|
2683
|
+
baseUrl: config.baseUrl,
|
|
2684
|
+
region: config.region,
|
|
2685
|
+
priceId: params.priceId,
|
|
2686
|
+
externalId: params.externalId,
|
|
2687
|
+
email: params.email,
|
|
2688
|
+
clientMetadata: params.clientMetadata,
|
|
2689
|
+
countryCode: params.countryCode,
|
|
2690
|
+
integration: 'stripe',
|
|
2691
|
+
}),
|
|
2692
|
+
Promise.resolve().then(function () { return require('./chunk-stripe-card-form.cjs.js'); }),
|
|
2693
|
+
]);
|
|
2694
|
+
const apiClient = new APIClient({
|
|
2695
|
+
orgId: config.orgId,
|
|
2696
|
+
baseUrl: config.baseUrl || DEFAULTS.BASE_URL,
|
|
2697
|
+
});
|
|
2698
|
+
return mountStripeCardForm(element, session, { ...params, apiClient });
|
|
2699
|
+
}
|
|
2700
|
+
async function purchaseStripeWallet(params) {
|
|
2701
|
+
const config = resolveConfig(params, 'purchaseStripeWallet');
|
|
2702
|
+
const [session, { purchaseWallet }] = await Promise.all([
|
|
2703
|
+
sessionService.createSession({
|
|
2704
|
+
orgId: config.orgId,
|
|
2705
|
+
baseUrl: config.baseUrl,
|
|
2706
|
+
region: config.region,
|
|
2707
|
+
priceId: params.priceId,
|
|
2708
|
+
externalId: params.externalId,
|
|
2709
|
+
email: params.email,
|
|
2710
|
+
clientMetadata: params.clientMetadata,
|
|
2711
|
+
countryCode: params.countryCode,
|
|
2712
|
+
integration: 'stripe',
|
|
2713
|
+
}),
|
|
2714
|
+
Promise.resolve().then(function () { return require('./chunk-stripe-wallet.cjs.js'); }),
|
|
2715
|
+
]);
|
|
2716
|
+
const apiClient = new APIClient({
|
|
2717
|
+
orgId: config.orgId,
|
|
2718
|
+
baseUrl: config.baseUrl || DEFAULTS.BASE_URL,
|
|
2719
|
+
});
|
|
2720
|
+
return purchaseWallet(session, { ...params, apiClient });
|
|
2721
|
+
}
|
|
2722
|
+
async function getAvailableStripeWallet(params) {
|
|
2723
|
+
const config = resolveConfig(params, 'getAvailableStripeWallet');
|
|
2724
|
+
const [session, { getAvailableWallet }] = await Promise.all([
|
|
2725
|
+
sessionService.createSession({
|
|
2726
|
+
orgId: config.orgId,
|
|
2727
|
+
baseUrl: config.baseUrl,
|
|
2728
|
+
region: config.region,
|
|
2729
|
+
priceId: params.priceId,
|
|
2730
|
+
externalId: params.externalId,
|
|
2731
|
+
email: params.email,
|
|
2732
|
+
clientMetadata: params.clientMetadata,
|
|
2733
|
+
countryCode: params.countryCode,
|
|
2734
|
+
integration: 'stripe',
|
|
2735
|
+
}),
|
|
2736
|
+
Promise.resolve().then(function () { return require('./chunk-stripe-wallet.cjs.js'); }),
|
|
2737
|
+
]);
|
|
2738
|
+
const result = await getAvailableWallet(session);
|
|
2739
|
+
if (result === 'APPLE_PAY')
|
|
2740
|
+
return exports.PaymentMethod.APPLE_PAY;
|
|
2741
|
+
if (result === 'GOOGLE_PAY')
|
|
2742
|
+
return exports.PaymentMethod.GOOGLE_PAY;
|
|
2743
|
+
return null;
|
|
2744
|
+
}
|
|
2745
|
+
async function getAvailableStripePaymentMethods(params) {
|
|
2746
|
+
const wallet = await getAvailableStripeWallet(params);
|
|
2747
|
+
return wallet
|
|
2748
|
+
? [exports.PaymentMethod.PAYMENT_CARD, wallet]
|
|
2749
|
+
: [exports.PaymentMethod.PAYMENT_CARD];
|
|
2750
|
+
}
|
|
2654
2751
|
|
|
2655
2752
|
/**
|
|
2656
2753
|
* @fileoverview Main entry point for @funnelfox/billing
|
|
@@ -2662,6 +2759,12 @@ const Billing = {
|
|
|
2662
2759
|
initMethod: initMethod,
|
|
2663
2760
|
silentPurchase: silentPurchase,
|
|
2664
2761
|
getAvailablePaymentMethods: getAvailablePaymentMethods,
|
|
2762
|
+
stripe: {
|
|
2763
|
+
createCardForm: createStripeCardForm,
|
|
2764
|
+
purchaseWallet: purchaseStripeWallet,
|
|
2765
|
+
getAvailableWallet: getAvailableStripeWallet,
|
|
2766
|
+
getAvailablePaymentMethods: getAvailableStripePaymentMethods,
|
|
2767
|
+
},
|
|
2665
2768
|
};
|
|
2666
2769
|
if (typeof window !== 'undefined') {
|
|
2667
2770
|
window.Billing = Billing;
|
|
@@ -2685,3 +2788,4 @@ exports.configure = configure;
|
|
|
2685
2788
|
exports.createCheckout = createCheckout;
|
|
2686
2789
|
exports.createClientSession = createClientSession;
|
|
2687
2790
|
exports.getAvailablePaymentMethods = getAvailablePaymentMethods;
|
|
2791
|
+
exports.loadStripe = loadStripe;
|