@funnelfox/billing 0.8.0 → 0.9.0-beta.0
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/dist/chunk-index.cjs.js +144 -58
- package/dist/chunk-index.es.js +144 -59
- package/dist/chunk-stripe-card-form.cjs.js +64 -0
- package/dist/chunk-stripe-card-form.es.js +62 -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 +80 -0
- package/dist/chunk-stripe-wallet.es.js +77 -0
- package/dist/funnelfox-billing.js +279 -58
- package/dist/funnelfox-billing.min.js +1 -1
- package/package.json +5 -5
- package/src/types.d.ts +76 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @funnelfox/billing v0.1.0
|
|
3
|
+
* JavaScript SDK for Funnelfox billing with Primer integration
|
|
4
|
+
*
|
|
5
|
+
* @author Funnelfox
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
import { g as getStripe } from './chunk-stripe-loader.es.js';
|
|
9
|
+
import './chunk-index.es.js';
|
|
10
|
+
|
|
11
|
+
async function mountStripeCardForm(element, session, params) {
|
|
12
|
+
const { stripe_public_key, stripe_intent, order_id } = session.data;
|
|
13
|
+
const { intent_client_secret, customer_session_client_secret } = stripe_intent;
|
|
14
|
+
const stripe = await getStripe(stripe_public_key);
|
|
15
|
+
if (!stripe)
|
|
16
|
+
throw new Error('Failed to load Stripe');
|
|
17
|
+
const stripeElements = stripe.elements({
|
|
18
|
+
clientSecret: intent_client_secret,
|
|
19
|
+
customerSessionClientSecret: customer_session_client_secret,
|
|
20
|
+
appearance: params.appearance,
|
|
21
|
+
});
|
|
22
|
+
const paymentElement = stripeElements.create('payment', {
|
|
23
|
+
layout: 'tabs',
|
|
24
|
+
wallets: {
|
|
25
|
+
applePay: params.showWallets ? 'auto' : 'never',
|
|
26
|
+
googlePay: params.showWallets ? 'auto' : 'never',
|
|
27
|
+
},
|
|
28
|
+
terms: { card: 'never' },
|
|
29
|
+
});
|
|
30
|
+
paymentElement.mount(element);
|
|
31
|
+
await new Promise((resolve, reject) => {
|
|
32
|
+
paymentElement.once('ready', () => resolve());
|
|
33
|
+
// 'loaderror' is a valid Stripe event but not yet in the @stripe/stripe-js types
|
|
34
|
+
paymentElement.once('loaderror', e => reject(e.error));
|
|
35
|
+
});
|
|
36
|
+
params.onRenderSuccess?.();
|
|
37
|
+
return {
|
|
38
|
+
submit: async () => {
|
|
39
|
+
params.onLoaderChange?.(true);
|
|
40
|
+
try {
|
|
41
|
+
const { error: submitError } = await stripeElements.submit();
|
|
42
|
+
if (submitError)
|
|
43
|
+
throw submitError;
|
|
44
|
+
const { error, paymentMethod } = await stripe.createPaymentMethod({
|
|
45
|
+
elements: stripeElements,
|
|
46
|
+
});
|
|
47
|
+
if (error)
|
|
48
|
+
throw error;
|
|
49
|
+
params.onPaymentSuccess?.(paymentMethod, order_id);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
params.onPaymentFail?.(err);
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
params.onLoaderChange?.(false);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { mountStripeCardForm };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @funnelfox/billing v0.1.0
|
|
3
|
+
* JavaScript SDK for Funnelfox billing with Primer integration
|
|
4
|
+
*
|
|
5
|
+
* @author Funnelfox
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
var index = require('./chunk-index.cjs.js');
|
|
11
|
+
|
|
12
|
+
const cache = new Map();
|
|
13
|
+
function getStripe(publicKey) {
|
|
14
|
+
if (!cache.has(publicKey)) {
|
|
15
|
+
cache.set(publicKey, index.loadStripe(publicKey));
|
|
16
|
+
}
|
|
17
|
+
return cache.get(publicKey);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.getStripe = getStripe;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @funnelfox/billing v0.1.0
|
|
3
|
+
* JavaScript SDK for Funnelfox billing with Primer integration
|
|
4
|
+
*
|
|
5
|
+
* @author Funnelfox
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
import { l as loadStripe } from './chunk-index.es.js';
|
|
9
|
+
|
|
10
|
+
const cache = new Map();
|
|
11
|
+
function getStripe(publicKey) {
|
|
12
|
+
if (!cache.has(publicKey)) {
|
|
13
|
+
cache.set(publicKey, loadStripe(publicKey));
|
|
14
|
+
}
|
|
15
|
+
return cache.get(publicKey);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { getStripe as g };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @funnelfox/billing v0.1.0
|
|
3
|
+
* JavaScript SDK for Funnelfox billing with Primer integration
|
|
4
|
+
*
|
|
5
|
+
* @author Funnelfox
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
var stripeLoader = require('./chunk-stripe-loader.cjs.js');
|
|
11
|
+
require('./chunk-index.cjs.js');
|
|
12
|
+
|
|
13
|
+
function buildPaymentRequest(stripe, stripe_intent, totalLabel) {
|
|
14
|
+
return stripe.paymentRequest({
|
|
15
|
+
country: stripe_intent.country || 'US',
|
|
16
|
+
currency: stripe_intent.currency || 'USD',
|
|
17
|
+
total: {
|
|
18
|
+
label: totalLabel ?? 'Test Total',
|
|
19
|
+
amount: stripe_intent.amount || 1,
|
|
20
|
+
},
|
|
21
|
+
requestPayerName: false,
|
|
22
|
+
requestPayerEmail: false,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function getAvailableWallet(session) {
|
|
26
|
+
const { stripe_public_key, stripe_intent } = session.data;
|
|
27
|
+
const stripe = await stripeLoader.getStripe(stripe_public_key);
|
|
28
|
+
if (!stripe)
|
|
29
|
+
throw new Error('Failed to load Stripe');
|
|
30
|
+
const paymentRequest = buildPaymentRequest(stripe, stripe_intent);
|
|
31
|
+
const result = await paymentRequest.canMakePayment();
|
|
32
|
+
if (!result)
|
|
33
|
+
return null;
|
|
34
|
+
if (result.applePay)
|
|
35
|
+
return 'APPLE_PAY';
|
|
36
|
+
if (result.googlePay)
|
|
37
|
+
return 'GOOGLE_PAY';
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
async function purchaseWallet(session, params) {
|
|
41
|
+
const { stripe_public_key, stripe_intent, order_id } = session.data;
|
|
42
|
+
const { intent_client_secret } = stripe_intent;
|
|
43
|
+
const stripe = await stripeLoader.getStripe(stripe_public_key);
|
|
44
|
+
if (!stripe)
|
|
45
|
+
throw new Error('Failed to load Stripe');
|
|
46
|
+
const paymentRequest = buildPaymentRequest(stripe, stripe_intent, params.totalLabel);
|
|
47
|
+
const canPay = await paymentRequest.canMakePayment();
|
|
48
|
+
if (!canPay)
|
|
49
|
+
throw new Error('No wallet payment method available');
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
paymentRequest.on('paymentmethod', async (event) => {
|
|
52
|
+
params.onLoaderChange?.(true);
|
|
53
|
+
try {
|
|
54
|
+
const { error } = await stripe.confirmCardPayment(intent_client_secret, { payment_method: event.paymentMethod.id }, { handleActions: false });
|
|
55
|
+
if (error) {
|
|
56
|
+
event.complete('fail');
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
event.complete('success');
|
|
60
|
+
params.onPaymentSuccess?.(event.paymentMethod, order_id);
|
|
61
|
+
resolve();
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
params.onPaymentFail?.(err);
|
|
65
|
+
reject(err);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
params.onLoaderChange?.(false);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
paymentRequest.on('cancel', () => {
|
|
72
|
+
params.onPaymentCancel?.();
|
|
73
|
+
resolve();
|
|
74
|
+
});
|
|
75
|
+
paymentRequest.show();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
exports.getAvailableWallet = getAvailableWallet;
|
|
80
|
+
exports.purchaseWallet = purchaseWallet;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @funnelfox/billing v0.1.0
|
|
3
|
+
* JavaScript SDK for Funnelfox billing with Primer integration
|
|
4
|
+
*
|
|
5
|
+
* @author Funnelfox
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
import { g as getStripe } from './chunk-stripe-loader.es.js';
|
|
9
|
+
import './chunk-index.es.js';
|
|
10
|
+
|
|
11
|
+
function buildPaymentRequest(stripe, stripe_intent, totalLabel) {
|
|
12
|
+
return stripe.paymentRequest({
|
|
13
|
+
country: stripe_intent.country || 'US',
|
|
14
|
+
currency: stripe_intent.currency || 'USD',
|
|
15
|
+
total: {
|
|
16
|
+
label: totalLabel ?? 'Test Total',
|
|
17
|
+
amount: stripe_intent.amount || 1,
|
|
18
|
+
},
|
|
19
|
+
requestPayerName: false,
|
|
20
|
+
requestPayerEmail: false,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async function getAvailableWallet(session) {
|
|
24
|
+
const { stripe_public_key, stripe_intent } = session.data;
|
|
25
|
+
const stripe = await getStripe(stripe_public_key);
|
|
26
|
+
if (!stripe)
|
|
27
|
+
throw new Error('Failed to load Stripe');
|
|
28
|
+
const paymentRequest = buildPaymentRequest(stripe, stripe_intent);
|
|
29
|
+
const result = await paymentRequest.canMakePayment();
|
|
30
|
+
if (!result)
|
|
31
|
+
return null;
|
|
32
|
+
if (result.applePay)
|
|
33
|
+
return 'APPLE_PAY';
|
|
34
|
+
if (result.googlePay)
|
|
35
|
+
return 'GOOGLE_PAY';
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
async function purchaseWallet(session, params) {
|
|
39
|
+
const { stripe_public_key, stripe_intent, order_id } = session.data;
|
|
40
|
+
const { intent_client_secret } = stripe_intent;
|
|
41
|
+
const stripe = await getStripe(stripe_public_key);
|
|
42
|
+
if (!stripe)
|
|
43
|
+
throw new Error('Failed to load Stripe');
|
|
44
|
+
const paymentRequest = buildPaymentRequest(stripe, stripe_intent, params.totalLabel);
|
|
45
|
+
const canPay = await paymentRequest.canMakePayment();
|
|
46
|
+
if (!canPay)
|
|
47
|
+
throw new Error('No wallet payment method available');
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
paymentRequest.on('paymentmethod', async (event) => {
|
|
50
|
+
params.onLoaderChange?.(true);
|
|
51
|
+
try {
|
|
52
|
+
const { error } = await stripe.confirmCardPayment(intent_client_secret, { payment_method: event.paymentMethod.id }, { handleActions: false });
|
|
53
|
+
if (error) {
|
|
54
|
+
event.complete('fail');
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
event.complete('success');
|
|
58
|
+
params.onPaymentSuccess?.(event.paymentMethod, order_id);
|
|
59
|
+
resolve();
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
params.onPaymentFail?.(err);
|
|
63
|
+
reject(err);
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
params.onLoaderChange?.(false);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
paymentRequest.on('cancel', () => {
|
|
70
|
+
params.onPaymentCancel?.();
|
|
71
|
+
resolve();
|
|
72
|
+
});
|
|
73
|
+
paymentRequest.show();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { getAvailableWallet, purchaseWallet };
|
|
@@ -495,7 +495,7 @@
|
|
|
495
495
|
/**
|
|
496
496
|
* @fileoverview Constants for Funnefox SDK
|
|
497
497
|
*/
|
|
498
|
-
const SDK_VERSION = '0.
|
|
498
|
+
const SDK_VERSION = '0.9.0-beta.0';
|
|
499
499
|
const DEFAULTS = {
|
|
500
500
|
BASE_URL: 'https://billing.funnelfox.com',
|
|
501
501
|
REGION: 'default',
|
|
@@ -1132,7 +1132,7 @@
|
|
|
1132
1132
|
async createClientSession(params) {
|
|
1133
1133
|
const payload = {
|
|
1134
1134
|
region: params.region || 'default',
|
|
1135
|
-
integration_type: 'primer',
|
|
1135
|
+
integration_type: params.integration ?? 'primer',
|
|
1136
1136
|
pp_ident: params.priceId,
|
|
1137
1137
|
external_id: params.externalId,
|
|
1138
1138
|
email_address: params.email,
|
|
@@ -1268,6 +1268,45 @@
|
|
|
1268
1268
|
}
|
|
1269
1269
|
}
|
|
1270
1270
|
|
|
1271
|
+
class SessionService {
|
|
1272
|
+
constructor() {
|
|
1273
|
+
this.cache = new Map();
|
|
1274
|
+
}
|
|
1275
|
+
buildCacheKey(p) {
|
|
1276
|
+
return [p.orgId, p.priceId, p.externalId, p.email, p.integration].join('-');
|
|
1277
|
+
}
|
|
1278
|
+
makeClient(orgId, baseUrl) {
|
|
1279
|
+
return new APIClient({
|
|
1280
|
+
baseUrl: baseUrl || DEFAULTS.BASE_URL,
|
|
1281
|
+
orgId,
|
|
1282
|
+
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
1283
|
+
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
createSession(p) {
|
|
1287
|
+
const key = this.buildCacheKey(p);
|
|
1288
|
+
const cached = this.cache.get(key);
|
|
1289
|
+
if (cached)
|
|
1290
|
+
return cached;
|
|
1291
|
+
const client = this.makeClient(p.orgId, p.baseUrl);
|
|
1292
|
+
const req = client.createClientSession({
|
|
1293
|
+
priceId: p.priceId,
|
|
1294
|
+
externalId: p.externalId,
|
|
1295
|
+
email: p.email,
|
|
1296
|
+
region: p.region || DEFAULTS.REGION,
|
|
1297
|
+
clientMetadata: p.clientMetadata,
|
|
1298
|
+
countryCode: p.countryCode,
|
|
1299
|
+
integration: p.integration,
|
|
1300
|
+
});
|
|
1301
|
+
this.cache.set(key, req);
|
|
1302
|
+
return req;
|
|
1303
|
+
}
|
|
1304
|
+
clearCache() {
|
|
1305
|
+
this.cache.clear();
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
var sessionService = new SessionService();
|
|
1309
|
+
|
|
1271
1310
|
var loaderHtml = "<div class=\"ff-sdk-loader-container\">\n <div class=\"ff-sdk-loader\"></div>\n</div>\n";
|
|
1272
1311
|
|
|
1273
1312
|
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 }";
|
|
@@ -1862,6 +1901,12 @@
|
|
|
1862
1901
|
this.cardEmailAddress = this.checkoutConfig.customer.email;
|
|
1863
1902
|
this.shouldApplySessionCardholderNameConfig =
|
|
1864
1903
|
this.checkoutConfig.card?.cardholderName?.required === undefined;
|
|
1904
|
+
this.apiClient = new APIClient({
|
|
1905
|
+
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
1906
|
+
orgId: this.orgId,
|
|
1907
|
+
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
1908
|
+
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1909
|
+
});
|
|
1865
1910
|
this._setupCallbackBridges();
|
|
1866
1911
|
}
|
|
1867
1912
|
_setupCallbackBridges() {
|
|
@@ -1903,64 +1948,35 @@
|
|
|
1903
1948
|
}
|
|
1904
1949
|
}
|
|
1905
1950
|
async createSession() {
|
|
1906
|
-
|
|
1907
|
-
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
1951
|
+
const response = await sessionService.createSession({
|
|
1908
1952
|
orgId: this.orgId,
|
|
1909
|
-
|
|
1910
|
-
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1911
|
-
});
|
|
1912
|
-
const sessionParams = {
|
|
1953
|
+
baseUrl: this.baseUrl,
|
|
1913
1954
|
priceId: this.checkoutConfig.priceId,
|
|
1914
1955
|
externalId: this.checkoutConfig.customer.externalId,
|
|
1915
1956
|
email: this.checkoutConfig.customer.email,
|
|
1916
|
-
region: this.region
|
|
1957
|
+
region: this.region,
|
|
1917
1958
|
clientMetadata: this.checkoutConfig.clientMetadata,
|
|
1918
1959
|
countryCode: this.checkoutConfig.customer.countryCode,
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
cachedResponse.radarSessionId = loadStripe(stripePublicKey)
|
|
1940
|
-
.then(stripe => stripe
|
|
1941
|
-
? stripe
|
|
1942
|
-
.createRadarSession()
|
|
1943
|
-
.then(session => session?.radarSession?.id || '')
|
|
1944
|
-
.catch(() => '')
|
|
1945
|
-
: '')
|
|
1946
|
-
.catch(() => '');
|
|
1947
|
-
}
|
|
1948
|
-
// Initialize Airwallex device fingerprinting if enabled by backend
|
|
1949
|
-
if (response.data?.airwallex_risk_enabled) {
|
|
1950
|
-
const isLivemode = response.data?.is_livemode;
|
|
1951
|
-
const deviceId = generateUUID();
|
|
1952
|
-
cachedResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
|
|
1953
|
-
.then(() => deviceId)
|
|
1954
|
-
.catch(() => {
|
|
1955
|
-
// Silently fail - return deviceId anyway
|
|
1956
|
-
return deviceId;
|
|
1957
|
-
});
|
|
1958
|
-
}
|
|
1959
|
-
return cachedResponse;
|
|
1960
|
-
});
|
|
1961
|
-
// Cache the successful response
|
|
1962
|
-
CheckoutInstance.sessionCache.set(cacheKey, sessionRequest);
|
|
1963
|
-
sessionResponse = await sessionRequest;
|
|
1960
|
+
integration: 'primer',
|
|
1961
|
+
});
|
|
1962
|
+
const sessionResponse = response;
|
|
1963
|
+
if (response.data?.stripe_public_key) {
|
|
1964
|
+
const stripePublicKey = response.data.stripe_public_key;
|
|
1965
|
+
sessionResponse.radarSessionId = loadStripe(stripePublicKey)
|
|
1966
|
+
.then(stripe => stripe
|
|
1967
|
+
? stripe
|
|
1968
|
+
.createRadarSession()
|
|
1969
|
+
.then(session => session?.radarSession?.id || '')
|
|
1970
|
+
.catch(() => '')
|
|
1971
|
+
: '')
|
|
1972
|
+
.catch(() => '');
|
|
1973
|
+
}
|
|
1974
|
+
if (response.data?.airwallex_risk_enabled) {
|
|
1975
|
+
const isLivemode = response.data?.is_livemode;
|
|
1976
|
+
const deviceId = generateUUID();
|
|
1977
|
+
sessionResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
|
|
1978
|
+
.then(() => deviceId)
|
|
1979
|
+
.catch(() => deviceId);
|
|
1964
1980
|
}
|
|
1965
1981
|
this.cachedSessionResponse = sessionResponse;
|
|
1966
1982
|
this.isTelemetryEnabled = !!sessionResponse.data?.sdk_telemetry_enabled;
|
|
@@ -2219,8 +2235,7 @@
|
|
|
2219
2235
|
try {
|
|
2220
2236
|
this.onLoaderChangeWithRace(true);
|
|
2221
2237
|
this._setState('updating');
|
|
2222
|
-
|
|
2223
|
-
CheckoutInstance.sessionCache.clear();
|
|
2238
|
+
sessionService.clearCache();
|
|
2224
2239
|
await this.apiClient.updateClientSession({
|
|
2225
2240
|
orderId: this.orderId,
|
|
2226
2241
|
clientToken: this.clientToken,
|
|
@@ -2253,7 +2268,7 @@
|
|
|
2253
2268
|
return;
|
|
2254
2269
|
try {
|
|
2255
2270
|
this.stopUnhandledTelemetry();
|
|
2256
|
-
|
|
2271
|
+
sessionService.clearCache();
|
|
2257
2272
|
await this.primerWrapper.destroy();
|
|
2258
2273
|
this._setState('destroyed');
|
|
2259
2274
|
this.orderId = null;
|
|
@@ -2464,7 +2479,6 @@
|
|
|
2464
2479
|
this.telemetryPaymentMethod = undefined;
|
|
2465
2480
|
}
|
|
2466
2481
|
}
|
|
2467
|
-
CheckoutInstance.sessionCache = new Map();
|
|
2468
2482
|
|
|
2469
2483
|
/**
|
|
2470
2484
|
* @fileoverview Public API with configuration and orchestration logic
|
|
@@ -2655,6 +2669,71 @@
|
|
|
2655
2669
|
throw error;
|
|
2656
2670
|
}
|
|
2657
2671
|
}
|
|
2672
|
+
async function createStripeCardForm(element, params) {
|
|
2673
|
+
const config = resolveConfig(params, 'createStripeCardForm');
|
|
2674
|
+
const [session, { mountStripeCardForm }] = await Promise.all([
|
|
2675
|
+
sessionService.createSession({
|
|
2676
|
+
orgId: config.orgId,
|
|
2677
|
+
baseUrl: config.baseUrl,
|
|
2678
|
+
region: config.region,
|
|
2679
|
+
priceId: params.priceId,
|
|
2680
|
+
externalId: params.externalId,
|
|
2681
|
+
email: params.email,
|
|
2682
|
+
clientMetadata: params.clientMetadata,
|
|
2683
|
+
countryCode: params.countryCode,
|
|
2684
|
+
integration: 'stripe',
|
|
2685
|
+
}),
|
|
2686
|
+
Promise.resolve().then(function () { return stripeCardForm; }),
|
|
2687
|
+
]);
|
|
2688
|
+
return mountStripeCardForm(element, session, params);
|
|
2689
|
+
}
|
|
2690
|
+
async function purchaseStripeWallet(params) {
|
|
2691
|
+
const config = resolveConfig(params, 'purchaseStripeWallet');
|
|
2692
|
+
const [session, { purchaseWallet }] = await Promise.all([
|
|
2693
|
+
sessionService.createSession({
|
|
2694
|
+
orgId: config.orgId,
|
|
2695
|
+
baseUrl: config.baseUrl,
|
|
2696
|
+
region: config.region,
|
|
2697
|
+
priceId: params.priceId,
|
|
2698
|
+
externalId: params.externalId,
|
|
2699
|
+
email: params.email,
|
|
2700
|
+
clientMetadata: params.clientMetadata,
|
|
2701
|
+
countryCode: params.countryCode,
|
|
2702
|
+
integration: 'stripe',
|
|
2703
|
+
}),
|
|
2704
|
+
Promise.resolve().then(function () { return stripeWallet; }),
|
|
2705
|
+
]);
|
|
2706
|
+
return purchaseWallet(session, params);
|
|
2707
|
+
}
|
|
2708
|
+
async function getAvailableStripeWallet(params) {
|
|
2709
|
+
const config = resolveConfig(params, 'getAvailableStripeWallet');
|
|
2710
|
+
const [session, { getAvailableWallet }] = await Promise.all([
|
|
2711
|
+
sessionService.createSession({
|
|
2712
|
+
orgId: config.orgId,
|
|
2713
|
+
baseUrl: config.baseUrl,
|
|
2714
|
+
region: config.region,
|
|
2715
|
+
priceId: params.priceId,
|
|
2716
|
+
externalId: params.externalId,
|
|
2717
|
+
email: params.email,
|
|
2718
|
+
clientMetadata: params.clientMetadata,
|
|
2719
|
+
countryCode: params.countryCode,
|
|
2720
|
+
integration: 'stripe',
|
|
2721
|
+
}),
|
|
2722
|
+
Promise.resolve().then(function () { return stripeWallet; }),
|
|
2723
|
+
]);
|
|
2724
|
+
const result = await getAvailableWallet(session);
|
|
2725
|
+
if (result === 'APPLE_PAY')
|
|
2726
|
+
return exports.PaymentMethod.APPLE_PAY;
|
|
2727
|
+
if (result === 'GOOGLE_PAY')
|
|
2728
|
+
return exports.PaymentMethod.GOOGLE_PAY;
|
|
2729
|
+
return null;
|
|
2730
|
+
}
|
|
2731
|
+
async function getAvailableStripePaymentMethods(params) {
|
|
2732
|
+
const wallet = await getAvailableStripeWallet(params);
|
|
2733
|
+
return wallet
|
|
2734
|
+
? [exports.PaymentMethod.PAYMENT_CARD, wallet]
|
|
2735
|
+
: [exports.PaymentMethod.PAYMENT_CARD];
|
|
2736
|
+
}
|
|
2658
2737
|
|
|
2659
2738
|
/**
|
|
2660
2739
|
* @fileoverview Main entry point for @funnelfox/billing
|
|
@@ -2666,6 +2745,12 @@
|
|
|
2666
2745
|
initMethod: initMethod,
|
|
2667
2746
|
silentPurchase: silentPurchase,
|
|
2668
2747
|
getAvailablePaymentMethods: getAvailablePaymentMethods,
|
|
2748
|
+
stripe: {
|
|
2749
|
+
createCardForm: createStripeCardForm,
|
|
2750
|
+
purchaseWallet: purchaseStripeWallet,
|
|
2751
|
+
getAvailableWallet: getAvailableStripeWallet,
|
|
2752
|
+
getAvailablePaymentMethods: getAvailableStripePaymentMethods,
|
|
2753
|
+
},
|
|
2669
2754
|
};
|
|
2670
2755
|
if (typeof window !== 'undefined') {
|
|
2671
2756
|
window.Billing = Billing;
|
|
@@ -3069,6 +3154,142 @@
|
|
|
3069
3154
|
default: createDefaultSkin
|
|
3070
3155
|
});
|
|
3071
3156
|
|
|
3157
|
+
const cache = new Map();
|
|
3158
|
+
function getStripe(publicKey) {
|
|
3159
|
+
if (!cache.has(publicKey)) {
|
|
3160
|
+
cache.set(publicKey, loadStripe(publicKey));
|
|
3161
|
+
}
|
|
3162
|
+
return cache.get(publicKey);
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
async function mountStripeCardForm(element, session, params) {
|
|
3166
|
+
const { stripe_public_key, stripe_intent, order_id } = session.data;
|
|
3167
|
+
const { intent_client_secret, customer_session_client_secret } = stripe_intent;
|
|
3168
|
+
const stripe = await getStripe(stripe_public_key);
|
|
3169
|
+
if (!stripe)
|
|
3170
|
+
throw new Error('Failed to load Stripe');
|
|
3171
|
+
const stripeElements = stripe.elements({
|
|
3172
|
+
clientSecret: intent_client_secret,
|
|
3173
|
+
customerSessionClientSecret: customer_session_client_secret,
|
|
3174
|
+
appearance: params.appearance,
|
|
3175
|
+
});
|
|
3176
|
+
const paymentElement = stripeElements.create('payment', {
|
|
3177
|
+
layout: 'tabs',
|
|
3178
|
+
wallets: {
|
|
3179
|
+
applePay: params.showWallets ? 'auto' : 'never',
|
|
3180
|
+
googlePay: params.showWallets ? 'auto' : 'never',
|
|
3181
|
+
},
|
|
3182
|
+
terms: { card: 'never' },
|
|
3183
|
+
});
|
|
3184
|
+
paymentElement.mount(element);
|
|
3185
|
+
await new Promise((resolve, reject) => {
|
|
3186
|
+
paymentElement.once('ready', () => resolve());
|
|
3187
|
+
// 'loaderror' is a valid Stripe event but not yet in the @stripe/stripe-js types
|
|
3188
|
+
paymentElement.once('loaderror', e => reject(e.error));
|
|
3189
|
+
});
|
|
3190
|
+
params.onRenderSuccess?.();
|
|
3191
|
+
return {
|
|
3192
|
+
submit: async () => {
|
|
3193
|
+
params.onLoaderChange?.(true);
|
|
3194
|
+
try {
|
|
3195
|
+
const { error: submitError } = await stripeElements.submit();
|
|
3196
|
+
if (submitError)
|
|
3197
|
+
throw submitError;
|
|
3198
|
+
const { error, paymentMethod } = await stripe.createPaymentMethod({
|
|
3199
|
+
elements: stripeElements,
|
|
3200
|
+
});
|
|
3201
|
+
if (error)
|
|
3202
|
+
throw error;
|
|
3203
|
+
params.onPaymentSuccess?.(paymentMethod, order_id);
|
|
3204
|
+
}
|
|
3205
|
+
catch (err) {
|
|
3206
|
+
params.onPaymentFail?.(err);
|
|
3207
|
+
throw err;
|
|
3208
|
+
}
|
|
3209
|
+
finally {
|
|
3210
|
+
params.onLoaderChange?.(false);
|
|
3211
|
+
}
|
|
3212
|
+
},
|
|
3213
|
+
};
|
|
3214
|
+
}
|
|
3215
|
+
|
|
3216
|
+
var stripeCardForm = /*#__PURE__*/Object.freeze({
|
|
3217
|
+
__proto__: null,
|
|
3218
|
+
mountStripeCardForm: mountStripeCardForm
|
|
3219
|
+
});
|
|
3220
|
+
|
|
3221
|
+
function buildPaymentRequest(stripe, stripe_intent, totalLabel) {
|
|
3222
|
+
return stripe.paymentRequest({
|
|
3223
|
+
country: stripe_intent.country || 'US',
|
|
3224
|
+
currency: stripe_intent.currency || 'USD',
|
|
3225
|
+
total: {
|
|
3226
|
+
label: totalLabel ?? 'Test Total',
|
|
3227
|
+
amount: stripe_intent.amount || 1,
|
|
3228
|
+
},
|
|
3229
|
+
requestPayerName: false,
|
|
3230
|
+
requestPayerEmail: false,
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
async function getAvailableWallet(session) {
|
|
3234
|
+
const { stripe_public_key, stripe_intent } = session.data;
|
|
3235
|
+
const stripe = await getStripe(stripe_public_key);
|
|
3236
|
+
if (!stripe)
|
|
3237
|
+
throw new Error('Failed to load Stripe');
|
|
3238
|
+
const paymentRequest = buildPaymentRequest(stripe, stripe_intent);
|
|
3239
|
+
const result = await paymentRequest.canMakePayment();
|
|
3240
|
+
if (!result)
|
|
3241
|
+
return null;
|
|
3242
|
+
if (result.applePay)
|
|
3243
|
+
return 'APPLE_PAY';
|
|
3244
|
+
if (result.googlePay)
|
|
3245
|
+
return 'GOOGLE_PAY';
|
|
3246
|
+
return null;
|
|
3247
|
+
}
|
|
3248
|
+
async function purchaseWallet(session, params) {
|
|
3249
|
+
const { stripe_public_key, stripe_intent, order_id } = session.data;
|
|
3250
|
+
const { intent_client_secret } = stripe_intent;
|
|
3251
|
+
const stripe = await getStripe(stripe_public_key);
|
|
3252
|
+
if (!stripe)
|
|
3253
|
+
throw new Error('Failed to load Stripe');
|
|
3254
|
+
const paymentRequest = buildPaymentRequest(stripe, stripe_intent, params.totalLabel);
|
|
3255
|
+
const canPay = await paymentRequest.canMakePayment();
|
|
3256
|
+
if (!canPay)
|
|
3257
|
+
throw new Error('No wallet payment method available');
|
|
3258
|
+
return new Promise((resolve, reject) => {
|
|
3259
|
+
paymentRequest.on('paymentmethod', async (event) => {
|
|
3260
|
+
params.onLoaderChange?.(true);
|
|
3261
|
+
try {
|
|
3262
|
+
const { error } = await stripe.confirmCardPayment(intent_client_secret, { payment_method: event.paymentMethod.id }, { handleActions: false });
|
|
3263
|
+
if (error) {
|
|
3264
|
+
event.complete('fail');
|
|
3265
|
+
throw error;
|
|
3266
|
+
}
|
|
3267
|
+
event.complete('success');
|
|
3268
|
+
params.onPaymentSuccess?.(event.paymentMethod, order_id);
|
|
3269
|
+
resolve();
|
|
3270
|
+
}
|
|
3271
|
+
catch (err) {
|
|
3272
|
+
params.onPaymentFail?.(err);
|
|
3273
|
+
reject(err);
|
|
3274
|
+
}
|
|
3275
|
+
finally {
|
|
3276
|
+
params.onLoaderChange?.(false);
|
|
3277
|
+
}
|
|
3278
|
+
});
|
|
3279
|
+
paymentRequest.on('cancel', () => {
|
|
3280
|
+
params.onPaymentCancel?.();
|
|
3281
|
+
resolve();
|
|
3282
|
+
});
|
|
3283
|
+
paymentRequest.show();
|
|
3284
|
+
});
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
var stripeWallet = /*#__PURE__*/Object.freeze({
|
|
3288
|
+
__proto__: null,
|
|
3289
|
+
getAvailableWallet: getAvailableWallet,
|
|
3290
|
+
purchaseWallet: purchaseWallet
|
|
3291
|
+
});
|
|
3292
|
+
|
|
3072
3293
|
exports.APIError = APIError;
|
|
3073
3294
|
exports.Billing = Billing;
|
|
3074
3295
|
exports.CHECKOUT_STATES = CHECKOUT_STATES;
|