@funnelfox/billing 0.8.0-beta.3 → 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 +174 -60
- package/dist/chunk-index.es.js +174 -61
- 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 +356 -60
- 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
|
};
|
|
@@ -1059,6 +1060,9 @@ class PrimerWrapper {
|
|
|
1059
1060
|
}
|
|
1060
1061
|
return element;
|
|
1061
1062
|
}
|
|
1063
|
+
refreshClientSession() {
|
|
1064
|
+
return this.currentHeadless?.then(headless => headless.refreshClientSession());
|
|
1065
|
+
}
|
|
1062
1066
|
}
|
|
1063
1067
|
PrimerWrapper.headlessManager = new HeadlessManager();
|
|
1064
1068
|
|
|
@@ -1125,7 +1129,7 @@ class APIClient {
|
|
|
1125
1129
|
async createClientSession(params) {
|
|
1126
1130
|
const payload = {
|
|
1127
1131
|
region: params.region || 'default',
|
|
1128
|
-
integration_type: 'primer',
|
|
1132
|
+
integration_type: params.integration ?? 'primer',
|
|
1129
1133
|
pp_ident: params.priceId,
|
|
1130
1134
|
external_id: params.externalId,
|
|
1131
1135
|
email_address: params.email,
|
|
@@ -1171,6 +1175,15 @@ class APIClient {
|
|
|
1171
1175
|
body: JSON.stringify(payload),
|
|
1172
1176
|
}));
|
|
1173
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
|
+
}
|
|
1174
1187
|
async resumePayment(params) {
|
|
1175
1188
|
const payload = {
|
|
1176
1189
|
order_id: params.orderId,
|
|
@@ -1261,6 +1274,45 @@ class APIClient {
|
|
|
1261
1274
|
}
|
|
1262
1275
|
}
|
|
1263
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
|
+
|
|
1264
1316
|
var loaderHtml = "<div class=\"ff-sdk-loader-container\">\n <div class=\"ff-sdk-loader\"></div>\n</div>\n";
|
|
1265
1317
|
|
|
1266
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 }";
|
|
@@ -1855,6 +1907,12 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1855
1907
|
this.cardEmailAddress = this.checkoutConfig.customer.email;
|
|
1856
1908
|
this.shouldApplySessionCardholderNameConfig =
|
|
1857
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
|
+
});
|
|
1858
1916
|
this._setupCallbackBridges();
|
|
1859
1917
|
}
|
|
1860
1918
|
_setupCallbackBridges() {
|
|
@@ -1896,68 +1954,38 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1896
1954
|
}
|
|
1897
1955
|
}
|
|
1898
1956
|
async createSession() {
|
|
1899
|
-
|
|
1900
|
-
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
1957
|
+
const response = await sessionService.createSession({
|
|
1901
1958
|
orgId: this.orgId,
|
|
1902
|
-
|
|
1903
|
-
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1904
|
-
});
|
|
1905
|
-
const sessionParams = {
|
|
1959
|
+
baseUrl: this.baseUrl,
|
|
1906
1960
|
priceId: this.checkoutConfig.priceId,
|
|
1907
1961
|
externalId: this.checkoutConfig.customer.externalId,
|
|
1908
1962
|
email: this.checkoutConfig.customer.email,
|
|
1909
|
-
region: this.region
|
|
1963
|
+
region: this.region,
|
|
1910
1964
|
clientMetadata: this.checkoutConfig.clientMetadata,
|
|
1911
1965
|
countryCode: this.checkoutConfig.customer.countryCode,
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
cachedResponse.radarSessionId = loadStripe(stripePublicKey)
|
|
1933
|
-
.then(stripe => stripe
|
|
1934
|
-
? stripe
|
|
1935
|
-
.createRadarSession()
|
|
1936
|
-
.then(session => session?.radarSession?.id || '')
|
|
1937
|
-
.catch(() => '')
|
|
1938
|
-
: '')
|
|
1939
|
-
.catch(() => '');
|
|
1940
|
-
}
|
|
1941
|
-
// Initialize Airwallex device fingerprinting if enabled by backend
|
|
1942
|
-
if (response.data?.airwallex_risk_enabled) {
|
|
1943
|
-
const isLivemode = response.data?.is_livemode;
|
|
1944
|
-
const deviceId = generateUUID();
|
|
1945
|
-
cachedResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
|
|
1946
|
-
.then(() => deviceId)
|
|
1947
|
-
.catch(() => {
|
|
1948
|
-
// Silently fail - return deviceId anyway
|
|
1949
|
-
return deviceId;
|
|
1950
|
-
});
|
|
1951
|
-
}
|
|
1952
|
-
return cachedResponse;
|
|
1953
|
-
});
|
|
1954
|
-
// Cache the successful response
|
|
1955
|
-
CheckoutInstance.sessionCache.set(cacheKey, sessionRequest);
|
|
1956
|
-
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);
|
|
1957
1986
|
}
|
|
1958
1987
|
this.cachedSessionResponse = sessionResponse;
|
|
1959
|
-
this.isTelemetryEnabled =
|
|
1960
|
-
!!sessionResponse.data?.sdk_telemetry_enabled || true;
|
|
1988
|
+
this.isTelemetryEnabled = !!sessionResponse.data?.sdk_telemetry_enabled;
|
|
1961
1989
|
this.isCollectingApplePayEmail =
|
|
1962
1990
|
!!sessionResponse.data?.collect_apple_pay_email;
|
|
1963
1991
|
this.applySessionCardFieldConfig(sessionResponse);
|
|
@@ -2211,9 +2239,9 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2211
2239
|
throw new CheckoutError('Cannot update price while payment is processing');
|
|
2212
2240
|
}
|
|
2213
2241
|
try {
|
|
2242
|
+
this.onLoaderChangeWithRace(true);
|
|
2214
2243
|
this._setState('updating');
|
|
2215
|
-
|
|
2216
|
-
CheckoutInstance.sessionCache.clear();
|
|
2244
|
+
sessionService.clearCache();
|
|
2217
2245
|
await this.apiClient.updateClientSession({
|
|
2218
2246
|
orderId: this.orderId,
|
|
2219
2247
|
clientToken: this.clientToken,
|
|
@@ -2221,9 +2249,12 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2221
2249
|
clientMetadata,
|
|
2222
2250
|
});
|
|
2223
2251
|
this.checkoutConfig.priceId = newPriceId;
|
|
2252
|
+
await this.primerWrapper.refreshClientSession();
|
|
2253
|
+
this.onLoaderChangeWithRace(false);
|
|
2224
2254
|
this._setState('ready');
|
|
2225
2255
|
}
|
|
2226
2256
|
catch (error) {
|
|
2257
|
+
this.onLoaderChangeWithRace(false);
|
|
2227
2258
|
this._setState('error');
|
|
2228
2259
|
this.emit(EVENTS.ERROR, error);
|
|
2229
2260
|
throw error;
|
|
@@ -2243,7 +2274,7 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2243
2274
|
return;
|
|
2244
2275
|
try {
|
|
2245
2276
|
this.stopUnhandledTelemetry();
|
|
2246
|
-
|
|
2277
|
+
sessionService.clearCache();
|
|
2247
2278
|
await this.primerWrapper.destroy();
|
|
2248
2279
|
this._setState('destroyed');
|
|
2249
2280
|
this.orderId = null;
|
|
@@ -2439,8 +2470,12 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2439
2470
|
baseUrl: this.baseUrl,
|
|
2440
2471
|
enabled: this.isTelemetryEnabled,
|
|
2441
2472
|
getContext: () => ({
|
|
2473
|
+
checkoutId: this.id,
|
|
2442
2474
|
orderId: this.orderId,
|
|
2443
2475
|
priceId: this.checkoutConfig.priceId,
|
|
2476
|
+
state: this.state,
|
|
2477
|
+
paymentMethod: this.telemetryPaymentMethod,
|
|
2478
|
+
reqId: this.cachedSessionResponse?.req_id,
|
|
2444
2479
|
}),
|
|
2445
2480
|
});
|
|
2446
2481
|
}
|
|
@@ -2450,7 +2485,6 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2450
2485
|
this.telemetryPaymentMethod = undefined;
|
|
2451
2486
|
}
|
|
2452
2487
|
}
|
|
2453
|
-
CheckoutInstance.sessionCache = new Map();
|
|
2454
2488
|
|
|
2455
2489
|
/**
|
|
2456
2490
|
* @fileoverview Public API with configuration and orchestration logic
|
|
@@ -2641,6 +2675,79 @@ async function getAvailablePaymentMethods(params) {
|
|
|
2641
2675
|
throw error;
|
|
2642
2676
|
}
|
|
2643
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
|
+
}
|
|
2644
2751
|
|
|
2645
2752
|
/**
|
|
2646
2753
|
* @fileoverview Main entry point for @funnelfox/billing
|
|
@@ -2652,6 +2759,12 @@ const Billing = {
|
|
|
2652
2759
|
initMethod: initMethod,
|
|
2653
2760
|
silentPurchase: silentPurchase,
|
|
2654
2761
|
getAvailablePaymentMethods: getAvailablePaymentMethods,
|
|
2762
|
+
stripe: {
|
|
2763
|
+
createCardForm: createStripeCardForm,
|
|
2764
|
+
purchaseWallet: purchaseStripeWallet,
|
|
2765
|
+
getAvailableWallet: getAvailableStripeWallet,
|
|
2766
|
+
getAvailablePaymentMethods: getAvailableStripePaymentMethods,
|
|
2767
|
+
},
|
|
2655
2768
|
};
|
|
2656
2769
|
if (typeof window !== 'undefined') {
|
|
2657
2770
|
window.Billing = Billing;
|
|
@@ -2675,3 +2788,4 @@ exports.configure = configure;
|
|
|
2675
2788
|
exports.createCheckout = createCheckout;
|
|
2676
2789
|
exports.createClientSession = createClientSession;
|
|
2677
2790
|
exports.getAvailablePaymentMethods = getAvailablePaymentMethods;
|
|
2791
|
+
exports.loadStripe = loadStripe;
|