@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/dist/chunk-index.es.js
CHANGED
|
@@ -489,7 +489,7 @@ var PaymentMethod;
|
|
|
489
489
|
/**
|
|
490
490
|
* @fileoverview Constants for Funnefox SDK
|
|
491
491
|
*/
|
|
492
|
-
const SDK_VERSION = '0.
|
|
492
|
+
const SDK_VERSION = '0.9.0-beta.1';
|
|
493
493
|
const DEFAULTS = {
|
|
494
494
|
BASE_URL: 'https://billing.funnelfox.com',
|
|
495
495
|
REGION: 'default',
|
|
@@ -528,6 +528,7 @@ const API_ENDPOINTS = {
|
|
|
528
528
|
UPDATE_CLIENT_SESSION: '/v1/checkout/update_client_session',
|
|
529
529
|
CREATE_PAYMENT: '/v1/checkout/create_payment',
|
|
530
530
|
RESUME_PAYMENT: '/v1/checkout/resume_payment',
|
|
531
|
+
STRIPE_CREATE_PAYMENT: '/v1/stripe/create_payment',
|
|
531
532
|
ONE_CLICK: '/v1/checkout/one_click',
|
|
532
533
|
CREATE_SIMPLE_CLIENT_SESSION: '/v1/checkout/create_simple_client_session',
|
|
533
534
|
};
|
|
@@ -1057,6 +1058,9 @@ class PrimerWrapper {
|
|
|
1057
1058
|
}
|
|
1058
1059
|
return element;
|
|
1059
1060
|
}
|
|
1061
|
+
refreshClientSession() {
|
|
1062
|
+
return this.currentHeadless?.then(headless => headless.refreshClientSession());
|
|
1063
|
+
}
|
|
1060
1064
|
}
|
|
1061
1065
|
PrimerWrapper.headlessManager = new HeadlessManager();
|
|
1062
1066
|
|
|
@@ -1123,7 +1127,7 @@ class APIClient {
|
|
|
1123
1127
|
async createClientSession(params) {
|
|
1124
1128
|
const payload = {
|
|
1125
1129
|
region: params.region || 'default',
|
|
1126
|
-
integration_type: 'primer',
|
|
1130
|
+
integration_type: params.integration ?? 'primer',
|
|
1127
1131
|
pp_ident: params.priceId,
|
|
1128
1132
|
external_id: params.externalId,
|
|
1129
1133
|
email_address: params.email,
|
|
@@ -1169,6 +1173,15 @@ class APIClient {
|
|
|
1169
1173
|
body: JSON.stringify(payload),
|
|
1170
1174
|
}));
|
|
1171
1175
|
}
|
|
1176
|
+
async createStripePayment(params) {
|
|
1177
|
+
return (await this.request(API_ENDPOINTS.STRIPE_CREATE_PAYMENT, {
|
|
1178
|
+
method: 'POST',
|
|
1179
|
+
body: JSON.stringify({
|
|
1180
|
+
order_id: params.orderId,
|
|
1181
|
+
payment_method_id: params.paymentMethodId,
|
|
1182
|
+
}),
|
|
1183
|
+
}));
|
|
1184
|
+
}
|
|
1172
1185
|
async resumePayment(params) {
|
|
1173
1186
|
const payload = {
|
|
1174
1187
|
order_id: params.orderId,
|
|
@@ -1259,6 +1272,45 @@ class APIClient {
|
|
|
1259
1272
|
}
|
|
1260
1273
|
}
|
|
1261
1274
|
|
|
1275
|
+
class SessionService {
|
|
1276
|
+
constructor() {
|
|
1277
|
+
this.cache = new Map();
|
|
1278
|
+
}
|
|
1279
|
+
buildCacheKey(p) {
|
|
1280
|
+
return [p.orgId, p.priceId, p.externalId, p.email, p.integration].join('-');
|
|
1281
|
+
}
|
|
1282
|
+
makeClient(orgId, baseUrl) {
|
|
1283
|
+
return new APIClient({
|
|
1284
|
+
baseUrl: baseUrl || DEFAULTS.BASE_URL,
|
|
1285
|
+
orgId,
|
|
1286
|
+
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
1287
|
+
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
createSession(p) {
|
|
1291
|
+
const key = this.buildCacheKey(p);
|
|
1292
|
+
const cached = this.cache.get(key);
|
|
1293
|
+
if (cached)
|
|
1294
|
+
return cached;
|
|
1295
|
+
const client = this.makeClient(p.orgId, p.baseUrl);
|
|
1296
|
+
const req = client.createClientSession({
|
|
1297
|
+
priceId: p.priceId,
|
|
1298
|
+
externalId: p.externalId,
|
|
1299
|
+
email: p.email,
|
|
1300
|
+
region: p.region || DEFAULTS.REGION,
|
|
1301
|
+
clientMetadata: p.clientMetadata,
|
|
1302
|
+
countryCode: p.countryCode,
|
|
1303
|
+
integration: p.integration,
|
|
1304
|
+
});
|
|
1305
|
+
this.cache.set(key, req);
|
|
1306
|
+
return req;
|
|
1307
|
+
}
|
|
1308
|
+
clearCache() {
|
|
1309
|
+
this.cache.clear();
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
var sessionService = new SessionService();
|
|
1313
|
+
|
|
1262
1314
|
var loaderHtml = "<div class=\"ff-sdk-loader-container\">\n <div class=\"ff-sdk-loader\"></div>\n</div>\n";
|
|
1263
1315
|
|
|
1264
1316
|
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 }";
|
|
@@ -1853,6 +1905,12 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1853
1905
|
this.cardEmailAddress = this.checkoutConfig.customer.email;
|
|
1854
1906
|
this.shouldApplySessionCardholderNameConfig =
|
|
1855
1907
|
this.checkoutConfig.card?.cardholderName?.required === undefined;
|
|
1908
|
+
this.apiClient = new APIClient({
|
|
1909
|
+
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
1910
|
+
orgId: this.orgId,
|
|
1911
|
+
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
1912
|
+
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1913
|
+
});
|
|
1856
1914
|
this._setupCallbackBridges();
|
|
1857
1915
|
}
|
|
1858
1916
|
_setupCallbackBridges() {
|
|
@@ -1894,68 +1952,38 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1894
1952
|
}
|
|
1895
1953
|
}
|
|
1896
1954
|
async createSession() {
|
|
1897
|
-
|
|
1898
|
-
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
1955
|
+
const response = await sessionService.createSession({
|
|
1899
1956
|
orgId: this.orgId,
|
|
1900
|
-
|
|
1901
|
-
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
1902
|
-
});
|
|
1903
|
-
const sessionParams = {
|
|
1957
|
+
baseUrl: this.baseUrl,
|
|
1904
1958
|
priceId: this.checkoutConfig.priceId,
|
|
1905
1959
|
externalId: this.checkoutConfig.customer.externalId,
|
|
1906
1960
|
email: this.checkoutConfig.customer.email,
|
|
1907
|
-
region: this.region
|
|
1961
|
+
region: this.region,
|
|
1908
1962
|
clientMetadata: this.checkoutConfig.clientMetadata,
|
|
1909
1963
|
countryCode: this.checkoutConfig.customer.countryCode,
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
cachedResponse.radarSessionId = loadStripe(stripePublicKey)
|
|
1931
|
-
.then(stripe => stripe
|
|
1932
|
-
? stripe
|
|
1933
|
-
.createRadarSession()
|
|
1934
|
-
.then(session => session?.radarSession?.id || '')
|
|
1935
|
-
.catch(() => '')
|
|
1936
|
-
: '')
|
|
1937
|
-
.catch(() => '');
|
|
1938
|
-
}
|
|
1939
|
-
// Initialize Airwallex device fingerprinting if enabled by backend
|
|
1940
|
-
if (response.data?.airwallex_risk_enabled) {
|
|
1941
|
-
const isLivemode = response.data?.is_livemode;
|
|
1942
|
-
const deviceId = generateUUID();
|
|
1943
|
-
cachedResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
|
|
1944
|
-
.then(() => deviceId)
|
|
1945
|
-
.catch(() => {
|
|
1946
|
-
// Silently fail - return deviceId anyway
|
|
1947
|
-
return deviceId;
|
|
1948
|
-
});
|
|
1949
|
-
}
|
|
1950
|
-
return cachedResponse;
|
|
1951
|
-
});
|
|
1952
|
-
// Cache the successful response
|
|
1953
|
-
CheckoutInstance.sessionCache.set(cacheKey, sessionRequest);
|
|
1954
|
-
sessionResponse = await sessionRequest;
|
|
1964
|
+
integration: 'primer',
|
|
1965
|
+
});
|
|
1966
|
+
const sessionResponse = response;
|
|
1967
|
+
if (response.data?.stripe_public_key) {
|
|
1968
|
+
const stripePublicKey = response.data.stripe_public_key;
|
|
1969
|
+
sessionResponse.radarSessionId = loadStripe(stripePublicKey)
|
|
1970
|
+
.then(stripe => stripe
|
|
1971
|
+
? stripe
|
|
1972
|
+
.createRadarSession()
|
|
1973
|
+
.then(session => session?.radarSession?.id || '')
|
|
1974
|
+
.catch(() => '')
|
|
1975
|
+
: '')
|
|
1976
|
+
.catch(() => '');
|
|
1977
|
+
}
|
|
1978
|
+
if (response.data?.airwallex_risk_enabled) {
|
|
1979
|
+
const isLivemode = response.data?.is_livemode;
|
|
1980
|
+
const deviceId = generateUUID();
|
|
1981
|
+
sessionResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
|
|
1982
|
+
.then(() => deviceId)
|
|
1983
|
+
.catch(() => deviceId);
|
|
1955
1984
|
}
|
|
1956
1985
|
this.cachedSessionResponse = sessionResponse;
|
|
1957
|
-
this.isTelemetryEnabled =
|
|
1958
|
-
!!sessionResponse.data?.sdk_telemetry_enabled || true;
|
|
1986
|
+
this.isTelemetryEnabled = !!sessionResponse.data?.sdk_telemetry_enabled;
|
|
1959
1987
|
this.isCollectingApplePayEmail =
|
|
1960
1988
|
!!sessionResponse.data?.collect_apple_pay_email;
|
|
1961
1989
|
this.applySessionCardFieldConfig(sessionResponse);
|
|
@@ -2209,9 +2237,9 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2209
2237
|
throw new CheckoutError('Cannot update price while payment is processing');
|
|
2210
2238
|
}
|
|
2211
2239
|
try {
|
|
2240
|
+
this.onLoaderChangeWithRace(true);
|
|
2212
2241
|
this._setState('updating');
|
|
2213
|
-
|
|
2214
|
-
CheckoutInstance.sessionCache.clear();
|
|
2242
|
+
sessionService.clearCache();
|
|
2215
2243
|
await this.apiClient.updateClientSession({
|
|
2216
2244
|
orderId: this.orderId,
|
|
2217
2245
|
clientToken: this.clientToken,
|
|
@@ -2219,9 +2247,12 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2219
2247
|
clientMetadata,
|
|
2220
2248
|
});
|
|
2221
2249
|
this.checkoutConfig.priceId = newPriceId;
|
|
2250
|
+
await this.primerWrapper.refreshClientSession();
|
|
2251
|
+
this.onLoaderChangeWithRace(false);
|
|
2222
2252
|
this._setState('ready');
|
|
2223
2253
|
}
|
|
2224
2254
|
catch (error) {
|
|
2255
|
+
this.onLoaderChangeWithRace(false);
|
|
2225
2256
|
this._setState('error');
|
|
2226
2257
|
this.emit(EVENTS.ERROR, error);
|
|
2227
2258
|
throw error;
|
|
@@ -2241,7 +2272,7 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2241
2272
|
return;
|
|
2242
2273
|
try {
|
|
2243
2274
|
this.stopUnhandledTelemetry();
|
|
2244
|
-
|
|
2275
|
+
sessionService.clearCache();
|
|
2245
2276
|
await this.primerWrapper.destroy();
|
|
2246
2277
|
this._setState('destroyed');
|
|
2247
2278
|
this.orderId = null;
|
|
@@ -2437,8 +2468,12 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2437
2468
|
baseUrl: this.baseUrl,
|
|
2438
2469
|
enabled: this.isTelemetryEnabled,
|
|
2439
2470
|
getContext: () => ({
|
|
2471
|
+
checkoutId: this.id,
|
|
2440
2472
|
orderId: this.orderId,
|
|
2441
2473
|
priceId: this.checkoutConfig.priceId,
|
|
2474
|
+
state: this.state,
|
|
2475
|
+
paymentMethod: this.telemetryPaymentMethod,
|
|
2476
|
+
reqId: this.cachedSessionResponse?.req_id,
|
|
2442
2477
|
}),
|
|
2443
2478
|
});
|
|
2444
2479
|
}
|
|
@@ -2448,7 +2483,6 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2448
2483
|
this.telemetryPaymentMethod = undefined;
|
|
2449
2484
|
}
|
|
2450
2485
|
}
|
|
2451
|
-
CheckoutInstance.sessionCache = new Map();
|
|
2452
2486
|
|
|
2453
2487
|
/**
|
|
2454
2488
|
* @fileoverview Public API with configuration and orchestration logic
|
|
@@ -2639,6 +2673,79 @@ async function getAvailablePaymentMethods(params) {
|
|
|
2639
2673
|
throw error;
|
|
2640
2674
|
}
|
|
2641
2675
|
}
|
|
2676
|
+
async function createStripeCardForm(element, params) {
|
|
2677
|
+
const config = resolveConfig(params, 'createStripeCardForm');
|
|
2678
|
+
const [session, { mountStripeCardForm }] = await Promise.all([
|
|
2679
|
+
sessionService.createSession({
|
|
2680
|
+
orgId: config.orgId,
|
|
2681
|
+
baseUrl: config.baseUrl,
|
|
2682
|
+
region: config.region,
|
|
2683
|
+
priceId: params.priceId,
|
|
2684
|
+
externalId: params.externalId,
|
|
2685
|
+
email: params.email,
|
|
2686
|
+
clientMetadata: params.clientMetadata,
|
|
2687
|
+
countryCode: params.countryCode,
|
|
2688
|
+
integration: 'stripe',
|
|
2689
|
+
}),
|
|
2690
|
+
import('./chunk-stripe-card-form.es.js'),
|
|
2691
|
+
]);
|
|
2692
|
+
const apiClient = new APIClient({
|
|
2693
|
+
orgId: config.orgId,
|
|
2694
|
+
baseUrl: config.baseUrl || DEFAULTS.BASE_URL,
|
|
2695
|
+
});
|
|
2696
|
+
return mountStripeCardForm(element, session, { ...params, apiClient });
|
|
2697
|
+
}
|
|
2698
|
+
async function purchaseStripeWallet(params) {
|
|
2699
|
+
const config = resolveConfig(params, 'purchaseStripeWallet');
|
|
2700
|
+
const [session, { purchaseWallet }] = await Promise.all([
|
|
2701
|
+
sessionService.createSession({
|
|
2702
|
+
orgId: config.orgId,
|
|
2703
|
+
baseUrl: config.baseUrl,
|
|
2704
|
+
region: config.region,
|
|
2705
|
+
priceId: params.priceId,
|
|
2706
|
+
externalId: params.externalId,
|
|
2707
|
+
email: params.email,
|
|
2708
|
+
clientMetadata: params.clientMetadata,
|
|
2709
|
+
countryCode: params.countryCode,
|
|
2710
|
+
integration: 'stripe',
|
|
2711
|
+
}),
|
|
2712
|
+
import('./chunk-stripe-wallet.es.js'),
|
|
2713
|
+
]);
|
|
2714
|
+
const apiClient = new APIClient({
|
|
2715
|
+
orgId: config.orgId,
|
|
2716
|
+
baseUrl: config.baseUrl || DEFAULTS.BASE_URL,
|
|
2717
|
+
});
|
|
2718
|
+
return purchaseWallet(session, { ...params, apiClient });
|
|
2719
|
+
}
|
|
2720
|
+
async function getAvailableStripeWallet(params) {
|
|
2721
|
+
const config = resolveConfig(params, 'getAvailableStripeWallet');
|
|
2722
|
+
const [session, { getAvailableWallet }] = await Promise.all([
|
|
2723
|
+
sessionService.createSession({
|
|
2724
|
+
orgId: config.orgId,
|
|
2725
|
+
baseUrl: config.baseUrl,
|
|
2726
|
+
region: config.region,
|
|
2727
|
+
priceId: params.priceId,
|
|
2728
|
+
externalId: params.externalId,
|
|
2729
|
+
email: params.email,
|
|
2730
|
+
clientMetadata: params.clientMetadata,
|
|
2731
|
+
countryCode: params.countryCode,
|
|
2732
|
+
integration: 'stripe',
|
|
2733
|
+
}),
|
|
2734
|
+
import('./chunk-stripe-wallet.es.js'),
|
|
2735
|
+
]);
|
|
2736
|
+
const result = await getAvailableWallet(session);
|
|
2737
|
+
if (result === 'APPLE_PAY')
|
|
2738
|
+
return PaymentMethod.APPLE_PAY;
|
|
2739
|
+
if (result === 'GOOGLE_PAY')
|
|
2740
|
+
return PaymentMethod.GOOGLE_PAY;
|
|
2741
|
+
return null;
|
|
2742
|
+
}
|
|
2743
|
+
async function getAvailableStripePaymentMethods(params) {
|
|
2744
|
+
const wallet = await getAvailableStripeWallet(params);
|
|
2745
|
+
return wallet
|
|
2746
|
+
? [PaymentMethod.PAYMENT_CARD, wallet]
|
|
2747
|
+
: [PaymentMethod.PAYMENT_CARD];
|
|
2748
|
+
}
|
|
2642
2749
|
|
|
2643
2750
|
/**
|
|
2644
2751
|
* @fileoverview Main entry point for @funnelfox/billing
|
|
@@ -2650,9 +2757,15 @@ const Billing = {
|
|
|
2650
2757
|
initMethod: initMethod,
|
|
2651
2758
|
silentPurchase: silentPurchase,
|
|
2652
2759
|
getAvailablePaymentMethods: getAvailablePaymentMethods,
|
|
2760
|
+
stripe: {
|
|
2761
|
+
createCardForm: createStripeCardForm,
|
|
2762
|
+
purchaseWallet: purchaseStripeWallet,
|
|
2763
|
+
getAvailableWallet: getAvailableStripeWallet,
|
|
2764
|
+
getAvailablePaymentMethods: getAvailableStripePaymentMethods,
|
|
2765
|
+
},
|
|
2653
2766
|
};
|
|
2654
2767
|
if (typeof window !== 'undefined') {
|
|
2655
2768
|
window.Billing = Billing;
|
|
2656
2769
|
}
|
|
2657
2770
|
|
|
2658
|
-
export { APIError as A, Billing as B, CheckoutError as C, DEFAULT_BUTTONS_OPTIONS as D, EVENTS as E, FunnefoxSDKError as F, NetworkError as N, PaymentMethod as P, SDK_VERSION as S, ValidationError as V, PrimerError as a, ConfigurationError as b, DEFAULTS as c, CHECKOUT_STATES as d, ERROR_CODES as e, configure as f, createCheckout as g, createClientSession as h, getAvailablePaymentMethods as i };
|
|
2771
|
+
export { APIError as A, Billing as B, CheckoutError as C, DEFAULT_BUTTONS_OPTIONS as D, EVENTS as E, FunnefoxSDKError as F, NetworkError as N, PaymentMethod as P, SDK_VERSION as S, ValidationError as V, PrimerError as a, ConfigurationError as b, DEFAULTS as c, CHECKOUT_STATES as d, ERROR_CODES as e, configure as f, createCheckout as g, createClientSession as h, getAvailablePaymentMethods as i, loadStripe as l };
|
|
@@ -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
|
+
async function mountStripeCardForm(element, session, params) {
|
|
14
|
+
const { stripe_public_key, amount, currency, order_id, is_link_enabled } = session.data;
|
|
15
|
+
const stripe = await stripeLoader.getStripe(stripe_public_key);
|
|
16
|
+
if (!stripe)
|
|
17
|
+
throw new Error('Failed to load Stripe');
|
|
18
|
+
const stripeElements = stripe.elements({
|
|
19
|
+
mode: 'subscription',
|
|
20
|
+
amount,
|
|
21
|
+
currency,
|
|
22
|
+
paymentMethodCreation: 'manual',
|
|
23
|
+
paymentMethodTypes: is_link_enabled ? ['card', 'link'] : ['card'],
|
|
24
|
+
appearance: params.appearance,
|
|
25
|
+
});
|
|
26
|
+
const paymentElement = stripeElements.create('payment', {
|
|
27
|
+
layout: 'tabs',
|
|
28
|
+
wallets: {
|
|
29
|
+
applePay: params.showWallets ? 'auto' : 'never',
|
|
30
|
+
googlePay: params.showWallets ? 'auto' : 'never',
|
|
31
|
+
},
|
|
32
|
+
terms: { card: 'never' },
|
|
33
|
+
});
|
|
34
|
+
paymentElement.mount(element);
|
|
35
|
+
await new Promise((resolve, reject) => {
|
|
36
|
+
paymentElement.once('ready', () => resolve());
|
|
37
|
+
// 'loaderror' is a valid Stripe event but not yet in the @stripe/stripe-js types
|
|
38
|
+
paymentElement.once('loaderror', e => reject(e.error));
|
|
39
|
+
});
|
|
40
|
+
params.onRenderSuccess?.();
|
|
41
|
+
return {
|
|
42
|
+
submit: async () => {
|
|
43
|
+
params.onLoaderChange?.(true);
|
|
44
|
+
try {
|
|
45
|
+
const { error: submitError } = await stripeElements.submit();
|
|
46
|
+
if (submitError)
|
|
47
|
+
throw submitError;
|
|
48
|
+
const { error, paymentMethod } = await stripe.createPaymentMethod({
|
|
49
|
+
elements: stripeElements,
|
|
50
|
+
});
|
|
51
|
+
if (error)
|
|
52
|
+
throw error;
|
|
53
|
+
const raw = await params.apiClient.createStripePayment({
|
|
54
|
+
orderId: order_id,
|
|
55
|
+
paymentMethodId: paymentMethod.id,
|
|
56
|
+
});
|
|
57
|
+
const result = params.apiClient.processPaymentResponse(raw);
|
|
58
|
+
if (result.type === 'action_required') {
|
|
59
|
+
const { error: confirmError } = await stripe.confirmPayment({
|
|
60
|
+
clientSecret: result.clientToken,
|
|
61
|
+
redirect: 'if_required',
|
|
62
|
+
confirmParams: { return_url: window.location.href },
|
|
63
|
+
});
|
|
64
|
+
if (confirmError)
|
|
65
|
+
throw confirmError;
|
|
66
|
+
}
|
|
67
|
+
params.onPaymentSuccess?.(paymentMethod, order_id);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
params.onPaymentFail?.(err);
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
params.onLoaderChange?.(false);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
exports.mountStripeCardForm = mountStripeCardForm;
|
|
@@ -0,0 +1,78 @@
|
|
|
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, amount, currency, order_id, is_link_enabled } = session.data;
|
|
13
|
+
const stripe = await getStripe(stripe_public_key);
|
|
14
|
+
if (!stripe)
|
|
15
|
+
throw new Error('Failed to load Stripe');
|
|
16
|
+
const stripeElements = stripe.elements({
|
|
17
|
+
mode: 'subscription',
|
|
18
|
+
amount,
|
|
19
|
+
currency,
|
|
20
|
+
paymentMethodCreation: 'manual',
|
|
21
|
+
paymentMethodTypes: is_link_enabled ? ['card', 'link'] : ['card'],
|
|
22
|
+
appearance: params.appearance,
|
|
23
|
+
});
|
|
24
|
+
const paymentElement = stripeElements.create('payment', {
|
|
25
|
+
layout: 'tabs',
|
|
26
|
+
wallets: {
|
|
27
|
+
applePay: params.showWallets ? 'auto' : 'never',
|
|
28
|
+
googlePay: params.showWallets ? 'auto' : 'never',
|
|
29
|
+
},
|
|
30
|
+
terms: { card: 'never' },
|
|
31
|
+
});
|
|
32
|
+
paymentElement.mount(element);
|
|
33
|
+
await new Promise((resolve, reject) => {
|
|
34
|
+
paymentElement.once('ready', () => resolve());
|
|
35
|
+
// 'loaderror' is a valid Stripe event but not yet in the @stripe/stripe-js types
|
|
36
|
+
paymentElement.once('loaderror', e => reject(e.error));
|
|
37
|
+
});
|
|
38
|
+
params.onRenderSuccess?.();
|
|
39
|
+
return {
|
|
40
|
+
submit: async () => {
|
|
41
|
+
params.onLoaderChange?.(true);
|
|
42
|
+
try {
|
|
43
|
+
const { error: submitError } = await stripeElements.submit();
|
|
44
|
+
if (submitError)
|
|
45
|
+
throw submitError;
|
|
46
|
+
const { error, paymentMethod } = await stripe.createPaymentMethod({
|
|
47
|
+
elements: stripeElements,
|
|
48
|
+
});
|
|
49
|
+
if (error)
|
|
50
|
+
throw error;
|
|
51
|
+
const raw = await params.apiClient.createStripePayment({
|
|
52
|
+
orderId: order_id,
|
|
53
|
+
paymentMethodId: paymentMethod.id,
|
|
54
|
+
});
|
|
55
|
+
const result = params.apiClient.processPaymentResponse(raw);
|
|
56
|
+
if (result.type === 'action_required') {
|
|
57
|
+
const { error: confirmError } = await stripe.confirmPayment({
|
|
58
|
+
clientSecret: result.clientToken,
|
|
59
|
+
redirect: 'if_required',
|
|
60
|
+
confirmParams: { return_url: window.location.href },
|
|
61
|
+
});
|
|
62
|
+
if (confirmError)
|
|
63
|
+
throw confirmError;
|
|
64
|
+
}
|
|
65
|
+
params.onPaymentSuccess?.(paymentMethod, order_id);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
params.onPaymentFail?.(err);
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
params.onLoaderChange?.(false);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
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,111 @@
|
|
|
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, data, totalLabel) {
|
|
14
|
+
const raw = data.apple_pay_recurring_payment_request;
|
|
15
|
+
if (raw) {
|
|
16
|
+
const parseDates = (b) => {
|
|
17
|
+
if (b.recurringPaymentStartDate)
|
|
18
|
+
Object.assign(b, {
|
|
19
|
+
recurringPaymentStartDate: new Date(b.recurringPaymentStartDate),
|
|
20
|
+
});
|
|
21
|
+
if (b.recurringPaymentEndDate)
|
|
22
|
+
Object.assign(b, {
|
|
23
|
+
recurringPaymentEndDate: new Date(b.recurringPaymentEndDate),
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
parseDates(raw.regularBilling);
|
|
27
|
+
if (raw.trialBilling)
|
|
28
|
+
parseDates(raw.trialBilling);
|
|
29
|
+
}
|
|
30
|
+
const applePay = raw
|
|
31
|
+
? { recurringPaymentRequest: raw }
|
|
32
|
+
: undefined;
|
|
33
|
+
return stripe.paymentRequest({
|
|
34
|
+
country: data.country,
|
|
35
|
+
currency: data.currency,
|
|
36
|
+
total: {
|
|
37
|
+
label: totalLabel?.trim() || 'Total',
|
|
38
|
+
amount: data.amount,
|
|
39
|
+
},
|
|
40
|
+
requestPayerName: false,
|
|
41
|
+
requestPayerEmail: false,
|
|
42
|
+
applePay,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async function getAvailableWallet(session) {
|
|
46
|
+
const { stripe_public_key } = session.data;
|
|
47
|
+
const stripe = await stripeLoader.getStripe(stripe_public_key);
|
|
48
|
+
if (!stripe)
|
|
49
|
+
throw new Error('Failed to load Stripe');
|
|
50
|
+
const paymentRequest = buildPaymentRequest(stripe, session.data);
|
|
51
|
+
const result = await paymentRequest.canMakePayment();
|
|
52
|
+
if (!result)
|
|
53
|
+
return null;
|
|
54
|
+
if (result.applePay)
|
|
55
|
+
return 'APPLE_PAY';
|
|
56
|
+
if (result.googlePay)
|
|
57
|
+
return 'GOOGLE_PAY';
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
async function purchaseWallet(session, params) {
|
|
61
|
+
const { stripe_public_key, order_id } = session.data;
|
|
62
|
+
const stripe = await stripeLoader.getStripe(stripe_public_key);
|
|
63
|
+
if (!stripe)
|
|
64
|
+
throw new Error('Failed to load Stripe');
|
|
65
|
+
const paymentRequest = buildPaymentRequest(stripe, session.data, params.totalLabel);
|
|
66
|
+
const canPay = await paymentRequest.canMakePayment();
|
|
67
|
+
if (!canPay)
|
|
68
|
+
throw new Error('No wallet payment method available');
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
paymentRequest.on('paymentmethod', async (event) => {
|
|
71
|
+
params.onLoaderChange?.(true);
|
|
72
|
+
try {
|
|
73
|
+
const raw = await params.apiClient.createStripePayment({
|
|
74
|
+
orderId: order_id,
|
|
75
|
+
paymentMethodId: event.paymentMethod.id,
|
|
76
|
+
});
|
|
77
|
+
const result = params.apiClient.processPaymentResponse(raw);
|
|
78
|
+
if (result.type === 'action_required') {
|
|
79
|
+
const { error } = await stripe.confirmPayment({
|
|
80
|
+
clientSecret: result.clientToken,
|
|
81
|
+
redirect: 'if_required',
|
|
82
|
+
confirmParams: { return_url: window.location.href },
|
|
83
|
+
});
|
|
84
|
+
if (error) {
|
|
85
|
+
event.complete('fail');
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
event.complete('success');
|
|
90
|
+
params.onPaymentSuccess?.(event.paymentMethod, order_id);
|
|
91
|
+
resolve();
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
event.complete('fail');
|
|
95
|
+
params.onPaymentFail?.(err);
|
|
96
|
+
reject(err);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
params.onLoaderChange?.(false);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
paymentRequest.on('cancel', () => {
|
|
103
|
+
params.onPaymentCancel?.();
|
|
104
|
+
resolve();
|
|
105
|
+
});
|
|
106
|
+
paymentRequest.show();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
exports.getAvailableWallet = getAvailableWallet;
|
|
111
|
+
exports.purchaseWallet = purchaseWallet;
|