@salla.sa/applepay 2.14.586 → 2.14.588

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salla.sa/applepay",
3
- "version": "2.14.586",
3
+ "version": "2.14.588",
4
4
  "description": "Salla Apple Pay light",
5
5
  "main": "dist/app.js",
6
6
  "scripts": {
@@ -26,5 +26,5 @@
26
26
  "dependencies": {
27
27
  "axios": "^1.10.0"
28
28
  },
29
- "gitHead": "f1bb0e84d7e11fe5d9b9fb3ef48290578a6570fb"
29
+ "gitHead": "14e0efc2f77beafae2ab6a70ef14373df89fcfa1"
30
30
  }
@@ -11,4 +11,12 @@ export declare function buildApplePayMethodData(opts: {
11
11
 
12
12
  export declare function ensureApplePaySdk(): Promise<void>;
13
13
 
14
- export declare function canCompleteApplePay(currency?: string): Promise<boolean>;
14
+ export declare function normalizeApplePayNetworks(raw: string[] | Record<string, string> | null | undefined): string[];
15
+
16
+ export declare function applePayNetworks(): string[];
17
+
18
+ export declare function resolveApplePayNetworks(
19
+ networks: string[] | Record<string, string> | null | undefined,
20
+ ): string[];
21
+
22
+ export declare function canCompleteApplePay(currency?: string, networks?: string[] | null): Promise<boolean>;
@@ -85,6 +85,43 @@ export function ensureApplePaySdk() {
85
85
  return sdkPromise;
86
86
  }
87
87
 
88
+ /**
89
+ * Coerce a networks payload into an array. PHP serializes the list as an object when the
90
+ * array keys are non-sequential, so both shapes arrive.
91
+ *
92
+ * @param {string[]|Object|null|undefined} raw
93
+ * @returns {string[]}
94
+ */
95
+ export function normalizeApplePayNetworks(raw) {
96
+ if (Array.isArray(raw)) return [...raw];
97
+ if (raw && typeof raw === 'object') return Object.values(raw);
98
+
99
+ return [];
100
+ }
101
+
102
+ /**
103
+ * The store's buy-now networks from config.
104
+ *
105
+ * @returns {string[]}
106
+ */
107
+ export function applePayNetworks() {
108
+ return normalizeApplePayNetworks(
109
+ salla?.config?.get?.('store.settings.buy_now.supportedNetworks')
110
+ || salla?.config?.get?.('store.settings.buy_now.networks'),
111
+ );
112
+ }
113
+
114
+ /**
115
+ * The networks for this attempt. `null`/`undefined` means "not supplied" and defers to config;
116
+ * an array — empty included — is the backend's answer and is used as-is.
117
+ *
118
+ * @param {string[]|Object|null|undefined} networks
119
+ * @returns {string[]}
120
+ */
121
+ export function resolveApplePayNetworks(networks) {
122
+ return networks == null ? applePayNetworks() : normalizeApplePayNetworks(networks);
123
+ }
124
+
88
125
  /**
89
126
  * Whether Apple Pay can be completed in the current browser: natively
90
127
  * (Safari / Apple devices) or via the Payment Request API (non-Safari browsers
@@ -93,9 +130,16 @@ export function ensureApplePaySdk() {
93
130
  * For the QR path this awaits the SDK before probing, so callers get a stable
94
131
  * answer on first load instead of racing the async script fetch.
95
132
  * @param {string} [currency]
133
+ * @param {string[]} [networks] The backend's list; null/undefined defers to the buy-now config.
96
134
  * @returns {Promise<boolean>}
97
135
  */
98
- export async function canCompleteApplePay(currency = 'SAR') {
136
+ export async function canCompleteApplePay(currency = 'SAR', networks = null) {
137
+ const supportedNetworks = resolveApplePayNetworks(networks);
138
+
139
+ // Nothing to charge with — checked before the native probe, which would report "available"
140
+ // and only fail after the shopper taps pay.
141
+ if (!supportedNetworks.length) return false;
142
+
99
143
  try {
100
144
  if (window.ApplePaySession?.canMakePayments?.()) return true;
101
145
  } catch (e) { /* not supported natively */ }
@@ -114,9 +158,7 @@ export async function canCompleteApplePay(currency = 'SAR') {
114
158
  buildApplePayMethodData({
115
159
  version: 3,
116
160
  merchantIdentifier: applePayMerchantId(),
117
- supportedNetworks: salla?.config?.get?.('store.settings.buy_now.supportedNetworks')
118
- || salla?.config?.get?.('store.settings.buy_now.networks')
119
- || ['masterCard', 'visa'],
161
+ supportedNetworks,
120
162
  countryCode: salla?.config?.get?.('store.store_country') || 'SA',
121
163
  }),
122
164
  { total: { label: 'Salla', amount: { currency: currency || 'SAR', value: '0.00' } } },
package/src/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import http from './http';
2
2
  import DetectOS from './DetectOS';
3
3
  import { mutateShippingContact } from './utils';
4
+ import { resolveApplePayNetworks } from './apple-pay-support';
4
5
 
5
6
  // SSR-safe: only access window in browser environment
6
7
  if (typeof window !== 'undefined') {
@@ -16,6 +17,11 @@ const APPLE_PAY_METHOD = 'https://apple.com/apple-pay';
16
17
  // only get it once the SDK loads. Keeps native-vs-PaymentRequest routing stable.
17
18
  const HAS_NATIVE_APPLE_PAY = typeof window !== 'undefined' && !!window.ApplePaySession;
18
19
 
20
+ // Shown when the backend offers no usable network. twilight can ship ahead of Languages-Module,
21
+ // so fall through to `payment_failed` while the key is missing — never a hardcoded sentence.
22
+ const NO_SUPPORTED_NETWORK_KEY = 'pages.checkout.apple_pay_no_supported_network';
23
+ const NO_SUPPORTED_NETWORK_FALLBACK_KEY = 'pages.checkout.payment_failed';
24
+
19
25
  /**
20
26
  * Full Example
21
27
  *
@@ -185,16 +191,12 @@ const SallaApplePay = typeof window !== 'undefined' ? {
185
191
  startNativeSession: async function (event) {
186
192
 
187
193
  let version = SallaApplePay.getApplePaySessionVersion();
188
- // Normalize to an array: the backend can serialize the networks list as a JSON object
189
- // (non-sequential PHP array keys). Copy it so we never mutate the shared `detail` reference.
190
- // Works for both legacy (plain array) and unified (object-shaped) payloads.
191
- let rawNetworks = SallaApplePay.detail.supportedNetworks;
192
- let supportedNetworks = Array.isArray(rawNetworks) ? [...rawNetworks] : Object.values(rawNetworks || {});
194
+ // The backend resolves this per shopper, so it goes to Apple verbatim. Adding mada back
195
+ // here is what let a shopper authorize with Face ID and only then be refused.
196
+ let supportedNetworks = resolveApplePayNetworks(SallaApplePay.detail.supportedNetworks);
197
+
193
198
  if (!supportedNetworks.length) {
194
- supportedNetworks = ['masterCard', 'visa'];
195
- }
196
- if (version === 5 && !supportedNetworks.includes('mada')) {
197
- supportedNetworks.push('mada');
199
+ return SallaApplePay.abandonNoSupportedNetwork();
198
200
  }
199
201
 
200
202
  SallaApplePay.request = {
@@ -325,6 +327,23 @@ const SallaApplePay = typeof window !== 'undefined' ? {
325
327
  });
326
328
  },
327
329
 
330
+ /**
331
+ * Give up before the sheet opens: the backend left no usable network.
332
+ *
333
+ * Routed through onCancel so the host gets the same terminal signals as a dismissal and the
334
+ * button recovers. trackPaymentFailed self-gates on Payment Submitted, so the funnel is safe.
335
+ */
336
+ abandonNoSupportedNetwork: () => {
337
+ salla.logger.error('🍏 Pay: no supported network for this shopper — Apple Pay not offered');
338
+
339
+ const message = salla?.lang?.get?.(NO_SUPPORTED_NETWORK_KEY);
340
+ const resolved = !message || message === NO_SUPPORTED_NETWORK_KEY
341
+ ? salla?.lang?.get?.(NO_SUPPORTED_NETWORK_FALLBACK_KEY)
342
+ : message;
343
+
344
+ SallaApplePay.onCancel({}, resolved || null);
345
+ },
346
+
328
347
  onCancel: (event = {}, message = null) => {
329
348
  SallaApplePay.canceled = true;
330
349
  // Sheet opened (Payment Submitted already fired) but the attempt ended
@@ -612,9 +631,12 @@ const SallaApplePay = typeof window !== 'undefined' ? {
612
631
  }
613
632
 
614
633
  const version = SallaApplePay.getApplePaySessionVersion();
615
- const supportedNetworks = [...(SallaApplePay.detail.supportedNetworks || ['masterCard', 'visa'])];
616
- if (version === 5 && !supportedNetworks.includes('mada')) {
617
- supportedNetworks.push('mada');
634
+ // Same contract as the native flow. resolveApplePayNetworks also handles the
635
+ // object-shaped payload, which the old spread would have thrown on.
636
+ const supportedNetworks = resolveApplePayNetworks(SallaApplePay.detail.supportedNetworks);
637
+
638
+ if (!supportedNetworks.length) {
639
+ return SallaApplePay.abandonNoSupportedNetwork();
618
640
  }
619
641
 
620
642
  const methodData = [{