@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.
@@ -489,7 +489,7 @@ var PaymentMethod;
489
489
  /**
490
490
  * @fileoverview Constants for Funnefox SDK
491
491
  */
492
- const SDK_VERSION = '0.8.0-beta.4';
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
  };
@@ -1126,7 +1127,7 @@ class APIClient {
1126
1127
  async createClientSession(params) {
1127
1128
  const payload = {
1128
1129
  region: params.region || 'default',
1129
- integration_type: 'primer',
1130
+ integration_type: params.integration ?? 'primer',
1130
1131
  pp_ident: params.priceId,
1131
1132
  external_id: params.externalId,
1132
1133
  email_address: params.email,
@@ -1172,6 +1173,15 @@ class APIClient {
1172
1173
  body: JSON.stringify(payload),
1173
1174
  }));
1174
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
+ }
1175
1185
  async resumePayment(params) {
1176
1186
  const payload = {
1177
1187
  order_id: params.orderId,
@@ -1262,6 +1272,45 @@ class APIClient {
1262
1272
  }
1263
1273
  }
1264
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
+
1265
1314
  var loaderHtml = "<div class=\"ff-sdk-loader-container\">\n <div class=\"ff-sdk-loader\"></div>\n</div>\n";
1266
1315
 
1267
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 }";
@@ -1856,6 +1905,12 @@ class CheckoutInstance extends EventEmitter {
1856
1905
  this.cardEmailAddress = this.checkoutConfig.customer.email;
1857
1906
  this.shouldApplySessionCardholderNameConfig =
1858
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
+ });
1859
1914
  this._setupCallbackBridges();
1860
1915
  }
1861
1916
  _setupCallbackBridges() {
@@ -1897,64 +1952,35 @@ class CheckoutInstance extends EventEmitter {
1897
1952
  }
1898
1953
  }
1899
1954
  async createSession() {
1900
- this.apiClient = new APIClient({
1901
- baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
1955
+ const response = await sessionService.createSession({
1902
1956
  orgId: this.orgId,
1903
- timeout: DEFAULTS.REQUEST_TIMEOUT,
1904
- retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
1905
- });
1906
- const sessionParams = {
1957
+ baseUrl: this.baseUrl,
1907
1958
  priceId: this.checkoutConfig.priceId,
1908
1959
  externalId: this.checkoutConfig.customer.externalId,
1909
1960
  email: this.checkoutConfig.customer.email,
1910
- region: this.region || DEFAULTS.REGION,
1961
+ region: this.region,
1911
1962
  clientMetadata: this.checkoutConfig.clientMetadata,
1912
1963
  countryCode: this.checkoutConfig.customer.countryCode,
1913
- };
1914
- const cacheKey = [
1915
- this.orgId,
1916
- this.checkoutConfig.priceId,
1917
- this.checkoutConfig.customer.externalId,
1918
- this.checkoutConfig.customer.email,
1919
- ].join('-');
1920
- let sessionResponse;
1921
- // Return cached response if payload hasn't changed
1922
- const cachedResponse = CheckoutInstance.sessionCache.get(cacheKey);
1923
- if (cachedResponse) {
1924
- sessionResponse = await cachedResponse;
1925
- }
1926
- else {
1927
- const sessionRequest = this.apiClient
1928
- .createClientSession(sessionParams)
1929
- .then((response) => {
1930
- const cachedResponse = response;
1931
- if (response.data?.stripe_public_key) {
1932
- const stripePublicKey = response.data.stripe_public_key;
1933
- cachedResponse.radarSessionId = loadStripe(stripePublicKey)
1934
- .then(stripe => stripe
1935
- ? stripe
1936
- .createRadarSession()
1937
- .then(session => session?.radarSession?.id || '')
1938
- .catch(() => '')
1939
- : '')
1940
- .catch(() => '');
1941
- }
1942
- // Initialize Airwallex device fingerprinting if enabled by backend
1943
- if (response.data?.airwallex_risk_enabled) {
1944
- const isLivemode = response.data?.is_livemode;
1945
- const deviceId = generateUUID();
1946
- cachedResponse.airwallexDeviceId = loadAirwallexDeviceFingerprint(deviceId, isLivemode)
1947
- .then(() => deviceId)
1948
- .catch(() => {
1949
- // Silently fail - return deviceId anyway
1950
- return deviceId;
1951
- });
1952
- }
1953
- return cachedResponse;
1954
- });
1955
- // Cache the successful response
1956
- CheckoutInstance.sessionCache.set(cacheKey, sessionRequest);
1957
- 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);
1958
1984
  }
1959
1985
  this.cachedSessionResponse = sessionResponse;
1960
1986
  this.isTelemetryEnabled = !!sessionResponse.data?.sdk_telemetry_enabled;
@@ -2213,8 +2239,7 @@ class CheckoutInstance extends EventEmitter {
2213
2239
  try {
2214
2240
  this.onLoaderChangeWithRace(true);
2215
2241
  this._setState('updating');
2216
- // Invalidate session cache
2217
- CheckoutInstance.sessionCache.clear();
2242
+ sessionService.clearCache();
2218
2243
  await this.apiClient.updateClientSession({
2219
2244
  orderId: this.orderId,
2220
2245
  clientToken: this.clientToken,
@@ -2247,7 +2272,7 @@ class CheckoutInstance extends EventEmitter {
2247
2272
  return;
2248
2273
  try {
2249
2274
  this.stopUnhandledTelemetry();
2250
- CheckoutInstance.sessionCache.clear();
2275
+ sessionService.clearCache();
2251
2276
  await this.primerWrapper.destroy();
2252
2277
  this._setState('destroyed');
2253
2278
  this.orderId = null;
@@ -2458,7 +2483,6 @@ class CheckoutInstance extends EventEmitter {
2458
2483
  this.telemetryPaymentMethod = undefined;
2459
2484
  }
2460
2485
  }
2461
- CheckoutInstance.sessionCache = new Map();
2462
2486
 
2463
2487
  /**
2464
2488
  * @fileoverview Public API with configuration and orchestration logic
@@ -2649,6 +2673,79 @@ async function getAvailablePaymentMethods(params) {
2649
2673
  throw error;
2650
2674
  }
2651
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
+ }
2652
2749
 
2653
2750
  /**
2654
2751
  * @fileoverview Main entry point for @funnelfox/billing
@@ -2660,9 +2757,15 @@ const Billing = {
2660
2757
  initMethod: initMethod,
2661
2758
  silentPurchase: silentPurchase,
2662
2759
  getAvailablePaymentMethods: getAvailablePaymentMethods,
2760
+ stripe: {
2761
+ createCardForm: createStripeCardForm,
2762
+ purchaseWallet: purchaseStripeWallet,
2763
+ getAvailableWallet: getAvailableStripeWallet,
2764
+ getAvailablePaymentMethods: getAvailableStripePaymentMethods,
2765
+ },
2663
2766
  };
2664
2767
  if (typeof window !== 'undefined') {
2665
2768
  window.Billing = Billing;
2666
2769
  }
2667
2770
 
2668
- 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;