@economist/web-apple-pay 0.1.3-beta.41 → 0.1.3-beta.42

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/index.js CHANGED
@@ -1913,6 +1913,7 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
1913
1913
  };
1914
1914
 
1915
1915
  // src/apple-pay-button.ts
1916
+ var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
1916
1917
  var TOTAL_LABEL = "The Economist";
1917
1918
  var DEFAULT_CURRENCY = "USD";
1918
1919
  var DEFAULT_TOTAL = "0.00";
@@ -1928,7 +1929,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1928
1929
  define(_ApplePayButton.tag, _ApplePayButton);
1929
1930
  }
1930
1931
  /**
1931
- * Creates and configures an ApplePayButton if the offer is eligible.
1932
+ * Creates and configures an ApplePayButton if the feature flag is present.
1932
1933
  */
1933
1934
  static createIfEnabled(offer, country, entryPoint) {
1934
1935
  if (!offer) {
@@ -1937,6 +1938,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1937
1938
  if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1938
1939
  return null;
1939
1940
  }
1941
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1942
+ return null;
1943
+ }
1940
1944
  _ApplePayButton.define();
1941
1945
  const button = document.createElement(_ApplePayButton.tag);
1942
1946
  button.offer = offer;
@@ -1965,7 +1969,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1965
1969
  #returnUrl = "";
1966
1970
  #supportedBillingCountries = [];
1967
1971
  #entryPoint = "";
1968
- #recaptchaTokensPromise = null;
1969
1972
  // ─── Public API ─────────────────────────────────────────────────────────────
1970
1973
  get offer() {
1971
1974
  return this.#offer;
@@ -2030,7 +2033,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2030
2033
  this.#paymentOptions = null;
2031
2034
  this.#returnUrl = "";
2032
2035
  this.#supportedBillingCountries = [];
2033
- this.#recaptchaTokensPromise = null;
2034
2036
  this.querySelector(SEL_CONTAINER)?.remove();
2035
2037
  }
2036
2038
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -2043,10 +2045,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2043
2045
  this.#captureReturnUrl();
2044
2046
  this.#computeBillingCountries();
2045
2047
  if (await this.#fetchAndCacheOptions()) return;
2046
- console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
2047
2048
  this.#finishLoading();
2048
- } catch (error) {
2049
- console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
2049
+ } catch {
2050
2050
  this.style.display = "none";
2051
2051
  this.querySelector(SEL_CONTAINER)?.remove();
2052
2052
  } finally {
@@ -2057,7 +2057,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2057
2057
  async #checkAvailability() {
2058
2058
  const available = await isApplePayAvailable();
2059
2059
  if (!available) {
2060
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
2061
2060
  this.style.display = "none";
2062
2061
  this.querySelector(SEL_CONTAINER)?.remove();
2063
2062
  return true;
@@ -2071,7 +2070,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2071
2070
  async #checkSession() {
2072
2071
  this.#sessionData = await this.#fetchSession();
2073
2072
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
2074
- console.log(`[web-apple-pay] button removed from DOM \u2014 reason: session check failed, userType="${this.#sessionData.userType}"`);
2075
2073
  this.style.display = "none";
2076
2074
  this.querySelector(SEL_CONTAINER)?.remove();
2077
2075
  return true;
@@ -2081,7 +2079,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2081
2079
  /** Returns `true` (hide) when no offer has been set before mount. */
2082
2080
  #checkOffer() {
2083
2081
  if (!this.#offer) {
2084
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
2085
2082
  this.style.display = "none";
2086
2083
  this.querySelector(SEL_CONTAINER)?.remove();
2087
2084
  return true;
@@ -2109,16 +2106,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2109
2106
  */
2110
2107
  async #fetchAndCacheOptions() {
2111
2108
  this.#paymentOptions = await this.#fetchPaymentOptions();
2112
- if (!this.#paymentOptions) {
2113
- console.warn("[web-apple-pay] button removed from DOM \u2014 reason: getPaymentOptions threw an error (see previous log for details)");
2114
- this.style.display = "none";
2115
- this.querySelector(SEL_CONTAINER)?.remove();
2116
- return true;
2117
- }
2118
- if (!this.#paymentOptions.options?.apple_pay) {
2119
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: BFF responded but apple_pay is absent from payment options", {
2120
- receivedOptions: this.#paymentOptions.options
2121
- });
2109
+ if (!this.#paymentOptions?.options?.apple_pay) {
2122
2110
  this.style.display = "none";
2123
2111
  this.querySelector(SEL_CONTAINER)?.remove();
2124
2112
  return true;
@@ -2127,7 +2115,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2127
2115
  }
2128
2116
  /** Injects the button template and wires click and confirm event listeners. */
2129
2117
  #renderTemplate() {
2130
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2131
2118
  this.style.removeProperty("display");
2132
2119
  ensureApplePayLogoSymbol();
2133
2120
  const template = document.createElement("template");
@@ -2148,7 +2135,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2148
2135
  if (button) {
2149
2136
  button.classList.remove("wap-loading");
2150
2137
  this.#updateDisabledState();
2151
- this.#scheduleRecaptchaTokens();
2152
2138
  trackExpressWalletImpression(this.#offer.sku_id, {
2153
2139
  entryPoint: this.#entryPoint,
2154
2140
  country: this.#country
@@ -2187,25 +2173,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2187
2173
  const country = this.#country;
2188
2174
  modal.onConfirm = (recaptchaTokens) => {
2189
2175
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2190
- this.#scheduleRecaptchaTokens();
2191
2176
  };
2192
- modal.open(this.#recaptchaTokensPromise);
2193
- }
2194
- /**
2195
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2196
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2197
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2198
- * a single transient failure from permanently disabling the CTA on all retries.
2199
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2200
- */
2201
- #scheduleRecaptchaTokens() {
2202
- const attempt = getPurchaseRecaptchaTokens();
2203
- attempt.catch(() => {
2204
- if (this.#recaptchaTokensPromise === attempt) {
2205
- this.#recaptchaTokensPromise = null;
2206
- }
2207
- });
2208
- this.#recaptchaTokensPromise = attempt;
2177
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2178
+ modal.open(recaptchaTokensPromise);
2209
2179
  }
2210
2180
  async #fetchSession() {
2211
2181
  try {
@@ -2216,16 +2186,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2216
2186
  }
2217
2187
  async #fetchPaymentOptions() {
2218
2188
  try {
2219
- const options = await getPaymentOptions({
2189
+ return await getPaymentOptions({
2220
2190
  sku: this.#offer.sku_id,
2221
2191
  countryCode: this.#country,
2222
2192
  currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
2223
2193
  checkoutUrl: this.#returnUrl
2224
2194
  });
2225
- console.log("[web-apple-pay] getPaymentOptions response received", options);
2226
- return options;
2227
- } catch (error) {
2228
- console.warn("[web-apple-pay] getPaymentOptions fetch failed \u2014 returning null", error);
2195
+ } catch {
2229
2196
  return null;
2230
2197
  }
2231
2198
  }
@@ -6,7 +6,7 @@ export declare class ApplePayButton extends HTMLElement {
6
6
  static readonly tag = "teg-apple-pay-button";
7
7
  static define(): void;
8
8
  /**
9
- * Creates and configures an ApplePayButton if the offer is eligible.
9
+ * Creates and configures an ApplePayButton if the feature flag is present.
10
10
  */
11
11
  static createIfEnabled(offer: Offer | undefined, country: string, entryPoint?: ApplePayEntryPoint): ApplePayButton | null;
12
12
  get offer(): Offer | null;
@@ -1908,6 +1908,7 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
1908
1908
  };
1909
1909
 
1910
1910
  // src/apple-pay-button.ts
1911
+ var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
1911
1912
  var TOTAL_LABEL = "The Economist";
1912
1913
  var DEFAULT_CURRENCY = "USD";
1913
1914
  var DEFAULT_TOTAL = "0.00";
@@ -1923,7 +1924,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1923
1924
  define(_ApplePayButton.tag, _ApplePayButton);
1924
1925
  }
1925
1926
  /**
1926
- * Creates and configures an ApplePayButton if the offer is eligible.
1927
+ * Creates and configures an ApplePayButton if the feature flag is present.
1927
1928
  */
1928
1929
  static createIfEnabled(offer, country, entryPoint) {
1929
1930
  if (!offer) {
@@ -1932,6 +1933,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1932
1933
  if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1933
1934
  return null;
1934
1935
  }
1936
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1937
+ return null;
1938
+ }
1935
1939
  _ApplePayButton.define();
1936
1940
  const button = document.createElement(_ApplePayButton.tag);
1937
1941
  button.offer = offer;
@@ -1960,7 +1964,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1960
1964
  #returnUrl = "";
1961
1965
  #supportedBillingCountries = [];
1962
1966
  #entryPoint = "";
1963
- #recaptchaTokensPromise = null;
1964
1967
  // ─── Public API ─────────────────────────────────────────────────────────────
1965
1968
  get offer() {
1966
1969
  return this.#offer;
@@ -2025,7 +2028,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2025
2028
  this.#paymentOptions = null;
2026
2029
  this.#returnUrl = "";
2027
2030
  this.#supportedBillingCountries = [];
2028
- this.#recaptchaTokensPromise = null;
2029
2031
  this.querySelector(SEL_CONTAINER)?.remove();
2030
2032
  }
2031
2033
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -2038,10 +2040,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2038
2040
  this.#captureReturnUrl();
2039
2041
  this.#computeBillingCountries();
2040
2042
  if (await this.#fetchAndCacheOptions()) return;
2041
- console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
2042
2043
  this.#finishLoading();
2043
- } catch (error) {
2044
- console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
2044
+ } catch {
2045
2045
  this.style.display = "none";
2046
2046
  this.querySelector(SEL_CONTAINER)?.remove();
2047
2047
  } finally {
@@ -2052,7 +2052,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2052
2052
  async #checkAvailability() {
2053
2053
  const available = await isApplePayAvailable();
2054
2054
  if (!available) {
2055
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
2056
2055
  this.style.display = "none";
2057
2056
  this.querySelector(SEL_CONTAINER)?.remove();
2058
2057
  return true;
@@ -2066,7 +2065,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2066
2065
  async #checkSession() {
2067
2066
  this.#sessionData = await this.#fetchSession();
2068
2067
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
2069
- console.log(`[web-apple-pay] button removed from DOM \u2014 reason: session check failed, userType="${this.#sessionData.userType}"`);
2070
2068
  this.style.display = "none";
2071
2069
  this.querySelector(SEL_CONTAINER)?.remove();
2072
2070
  return true;
@@ -2076,7 +2074,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2076
2074
  /** Returns `true` (hide) when no offer has been set before mount. */
2077
2075
  #checkOffer() {
2078
2076
  if (!this.#offer) {
2079
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
2080
2077
  this.style.display = "none";
2081
2078
  this.querySelector(SEL_CONTAINER)?.remove();
2082
2079
  return true;
@@ -2104,16 +2101,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2104
2101
  */
2105
2102
  async #fetchAndCacheOptions() {
2106
2103
  this.#paymentOptions = await this.#fetchPaymentOptions();
2107
- if (!this.#paymentOptions) {
2108
- console.warn("[web-apple-pay] button removed from DOM \u2014 reason: getPaymentOptions threw an error (see previous log for details)");
2109
- this.style.display = "none";
2110
- this.querySelector(SEL_CONTAINER)?.remove();
2111
- return true;
2112
- }
2113
- if (!this.#paymentOptions.options?.apple_pay) {
2114
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: BFF responded but apple_pay is absent from payment options", {
2115
- receivedOptions: this.#paymentOptions.options
2116
- });
2104
+ if (!this.#paymentOptions?.options?.apple_pay) {
2117
2105
  this.style.display = "none";
2118
2106
  this.querySelector(SEL_CONTAINER)?.remove();
2119
2107
  return true;
@@ -2122,7 +2110,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2122
2110
  }
2123
2111
  /** Injects the button template and wires click and confirm event listeners. */
2124
2112
  #renderTemplate() {
2125
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2126
2113
  this.style.removeProperty("display");
2127
2114
  ensureApplePayLogoSymbol();
2128
2115
  const template = document.createElement("template");
@@ -2143,7 +2130,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2143
2130
  if (button) {
2144
2131
  button.classList.remove("wap-loading");
2145
2132
  this.#updateDisabledState();
2146
- this.#scheduleRecaptchaTokens();
2147
2133
  trackExpressWalletImpression(this.#offer.sku_id, {
2148
2134
  entryPoint: this.#entryPoint,
2149
2135
  country: this.#country
@@ -2182,25 +2168,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2182
2168
  const country = this.#country;
2183
2169
  modal.onConfirm = (recaptchaTokens) => {
2184
2170
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2185
- this.#scheduleRecaptchaTokens();
2186
2171
  };
2187
- modal.open(this.#recaptchaTokensPromise);
2188
- }
2189
- /**
2190
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2191
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2192
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2193
- * a single transient failure from permanently disabling the CTA on all retries.
2194
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2195
- */
2196
- #scheduleRecaptchaTokens() {
2197
- const attempt = getPurchaseRecaptchaTokens();
2198
- attempt.catch(() => {
2199
- if (this.#recaptchaTokensPromise === attempt) {
2200
- this.#recaptchaTokensPromise = null;
2201
- }
2202
- });
2203
- this.#recaptchaTokensPromise = attempt;
2172
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2173
+ modal.open(recaptchaTokensPromise);
2204
2174
  }
2205
2175
  async #fetchSession() {
2206
2176
  try {
@@ -2211,16 +2181,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2211
2181
  }
2212
2182
  async #fetchPaymentOptions() {
2213
2183
  try {
2214
- const options = await getPaymentOptions({
2184
+ return await getPaymentOptions({
2215
2185
  sku: this.#offer.sku_id,
2216
2186
  countryCode: this.#country,
2217
2187
  currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
2218
2188
  checkoutUrl: this.#returnUrl
2219
2189
  });
2220
- console.log("[web-apple-pay] getPaymentOptions response received", options);
2221
- return options;
2222
- } catch (error) {
2223
- console.warn("[web-apple-pay] getPaymentOptions fetch failed \u2014 returning null", error);
2190
+ } catch {
2224
2191
  return null;
2225
2192
  }
2226
2193
  }
@@ -1916,6 +1916,7 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
1916
1916
  };
1917
1917
 
1918
1918
  // src/apple-pay-button.ts
1919
+ var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
1919
1920
  var TOTAL_LABEL = "The Economist";
1920
1921
  var DEFAULT_CURRENCY = "USD";
1921
1922
  var DEFAULT_TOTAL = "0.00";
@@ -1931,7 +1932,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1931
1932
  define(_ApplePayButton.tag, _ApplePayButton);
1932
1933
  }
1933
1934
  /**
1934
- * Creates and configures an ApplePayButton if the offer is eligible.
1935
+ * Creates and configures an ApplePayButton if the feature flag is present.
1935
1936
  */
1936
1937
  static createIfEnabled(offer, country, entryPoint) {
1937
1938
  if (!offer) {
@@ -1940,6 +1941,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1940
1941
  if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1941
1942
  return null;
1942
1943
  }
1944
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1945
+ return null;
1946
+ }
1943
1947
  _ApplePayButton.define();
1944
1948
  const button = document.createElement(_ApplePayButton.tag);
1945
1949
  button.offer = offer;
@@ -1968,7 +1972,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1968
1972
  #returnUrl = "";
1969
1973
  #supportedBillingCountries = [];
1970
1974
  #entryPoint = "";
1971
- #recaptchaTokensPromise = null;
1972
1975
  // ─── Public API ─────────────────────────────────────────────────────────────
1973
1976
  get offer() {
1974
1977
  return this.#offer;
@@ -2033,7 +2036,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2033
2036
  this.#paymentOptions = null;
2034
2037
  this.#returnUrl = "";
2035
2038
  this.#supportedBillingCountries = [];
2036
- this.#recaptchaTokensPromise = null;
2037
2039
  this.querySelector(SEL_CONTAINER)?.remove();
2038
2040
  }
2039
2041
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -2046,10 +2048,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2046
2048
  this.#captureReturnUrl();
2047
2049
  this.#computeBillingCountries();
2048
2050
  if (await this.#fetchAndCacheOptions()) return;
2049
- console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
2050
2051
  this.#finishLoading();
2051
- } catch (error) {
2052
- console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
2052
+ } catch {
2053
2053
  this.style.display = "none";
2054
2054
  this.querySelector(SEL_CONTAINER)?.remove();
2055
2055
  } finally {
@@ -2060,7 +2060,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2060
2060
  async #checkAvailability() {
2061
2061
  const available = await isApplePayAvailable();
2062
2062
  if (!available) {
2063
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
2064
2063
  this.style.display = "none";
2065
2064
  this.querySelector(SEL_CONTAINER)?.remove();
2066
2065
  return true;
@@ -2074,7 +2073,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2074
2073
  async #checkSession() {
2075
2074
  this.#sessionData = await this.#fetchSession();
2076
2075
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
2077
- console.log(`[web-apple-pay] button removed from DOM \u2014 reason: session check failed, userType="${this.#sessionData.userType}"`);
2078
2076
  this.style.display = "none";
2079
2077
  this.querySelector(SEL_CONTAINER)?.remove();
2080
2078
  return true;
@@ -2084,7 +2082,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2084
2082
  /** Returns `true` (hide) when no offer has been set before mount. */
2085
2083
  #checkOffer() {
2086
2084
  if (!this.#offer) {
2087
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
2088
2085
  this.style.display = "none";
2089
2086
  this.querySelector(SEL_CONTAINER)?.remove();
2090
2087
  return true;
@@ -2112,16 +2109,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2112
2109
  */
2113
2110
  async #fetchAndCacheOptions() {
2114
2111
  this.#paymentOptions = await this.#fetchPaymentOptions();
2115
- if (!this.#paymentOptions) {
2116
- console.warn("[web-apple-pay] button removed from DOM \u2014 reason: getPaymentOptions threw an error (see previous log for details)");
2117
- this.style.display = "none";
2118
- this.querySelector(SEL_CONTAINER)?.remove();
2119
- return true;
2120
- }
2121
- if (!this.#paymentOptions.options?.apple_pay) {
2122
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: BFF responded but apple_pay is absent from payment options", {
2123
- receivedOptions: this.#paymentOptions.options
2124
- });
2112
+ if (!this.#paymentOptions?.options?.apple_pay) {
2125
2113
  this.style.display = "none";
2126
2114
  this.querySelector(SEL_CONTAINER)?.remove();
2127
2115
  return true;
@@ -2130,7 +2118,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2130
2118
  }
2131
2119
  /** Injects the button template and wires click and confirm event listeners. */
2132
2120
  #renderTemplate() {
2133
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2134
2121
  this.style.removeProperty("display");
2135
2122
  ensureApplePayLogoSymbol();
2136
2123
  const template = document.createElement("template");
@@ -2151,7 +2138,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2151
2138
  if (button) {
2152
2139
  button.classList.remove("wap-loading");
2153
2140
  this.#updateDisabledState();
2154
- this.#scheduleRecaptchaTokens();
2155
2141
  trackExpressWalletImpression(this.#offer.sku_id, {
2156
2142
  entryPoint: this.#entryPoint,
2157
2143
  country: this.#country
@@ -2190,25 +2176,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2190
2176
  const country = this.#country;
2191
2177
  modal.onConfirm = (recaptchaTokens) => {
2192
2178
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2193
- this.#scheduleRecaptchaTokens();
2194
2179
  };
2195
- modal.open(this.#recaptchaTokensPromise);
2196
- }
2197
- /**
2198
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2199
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2200
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2201
- * a single transient failure from permanently disabling the CTA on all retries.
2202
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2203
- */
2204
- #scheduleRecaptchaTokens() {
2205
- const attempt = getPurchaseRecaptchaTokens();
2206
- attempt.catch(() => {
2207
- if (this.#recaptchaTokensPromise === attempt) {
2208
- this.#recaptchaTokensPromise = null;
2209
- }
2210
- });
2211
- this.#recaptchaTokensPromise = attempt;
2180
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2181
+ modal.open(recaptchaTokensPromise);
2212
2182
  }
2213
2183
  async #fetchSession() {
2214
2184
  try {
@@ -2219,16 +2189,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2219
2189
  }
2220
2190
  async #fetchPaymentOptions() {
2221
2191
  try {
2222
- const options = await getPaymentOptions({
2192
+ return await getPaymentOptions({
2223
2193
  sku: this.#offer.sku_id,
2224
2194
  countryCode: this.#country,
2225
2195
  currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
2226
2196
  checkoutUrl: this.#returnUrl
2227
2197
  });
2228
- console.log("[web-apple-pay] getPaymentOptions response received", options);
2229
- return options;
2230
- } catch (error) {
2231
- console.warn("[web-apple-pay] getPaymentOptions fetch failed \u2014 returning null", error);
2198
+ } catch {
2232
2199
  return null;
2233
2200
  }
2234
2201
  }
@@ -1908,6 +1908,7 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
1908
1908
  };
1909
1909
 
1910
1910
  // src/apple-pay-button.ts
1911
+ var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
1911
1912
  var TOTAL_LABEL = "The Economist";
1912
1913
  var DEFAULT_CURRENCY = "USD";
1913
1914
  var DEFAULT_TOTAL = "0.00";
@@ -1923,7 +1924,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1923
1924
  define(_ApplePayButton.tag, _ApplePayButton);
1924
1925
  }
1925
1926
  /**
1926
- * Creates and configures an ApplePayButton if the offer is eligible.
1927
+ * Creates and configures an ApplePayButton if the feature flag is present.
1927
1928
  */
1928
1929
  static createIfEnabled(offer, country, entryPoint) {
1929
1930
  if (!offer) {
@@ -1932,6 +1933,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1932
1933
  if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1933
1934
  return null;
1934
1935
  }
1936
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1937
+ return null;
1938
+ }
1935
1939
  _ApplePayButton.define();
1936
1940
  const button = document.createElement(_ApplePayButton.tag);
1937
1941
  button.offer = offer;
@@ -1960,7 +1964,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1960
1964
  #returnUrl = "";
1961
1965
  #supportedBillingCountries = [];
1962
1966
  #entryPoint = "";
1963
- #recaptchaTokensPromise = null;
1964
1967
  // ─── Public API ─────────────────────────────────────────────────────────────
1965
1968
  get offer() {
1966
1969
  return this.#offer;
@@ -2025,7 +2028,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2025
2028
  this.#paymentOptions = null;
2026
2029
  this.#returnUrl = "";
2027
2030
  this.#supportedBillingCountries = [];
2028
- this.#recaptchaTokensPromise = null;
2029
2031
  this.querySelector(SEL_CONTAINER)?.remove();
2030
2032
  }
2031
2033
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -2038,10 +2040,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2038
2040
  this.#captureReturnUrl();
2039
2041
  this.#computeBillingCountries();
2040
2042
  if (await this.#fetchAndCacheOptions()) return;
2041
- console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
2042
2043
  this.#finishLoading();
2043
- } catch (error) {
2044
- console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
2044
+ } catch {
2045
2045
  this.style.display = "none";
2046
2046
  this.querySelector(SEL_CONTAINER)?.remove();
2047
2047
  } finally {
@@ -2052,7 +2052,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2052
2052
  async #checkAvailability() {
2053
2053
  const available = await isApplePayAvailable();
2054
2054
  if (!available) {
2055
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
2056
2055
  this.style.display = "none";
2057
2056
  this.querySelector(SEL_CONTAINER)?.remove();
2058
2057
  return true;
@@ -2066,7 +2065,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2066
2065
  async #checkSession() {
2067
2066
  this.#sessionData = await this.#fetchSession();
2068
2067
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
2069
- console.log(`[web-apple-pay] button removed from DOM \u2014 reason: session check failed, userType="${this.#sessionData.userType}"`);
2070
2068
  this.style.display = "none";
2071
2069
  this.querySelector(SEL_CONTAINER)?.remove();
2072
2070
  return true;
@@ -2076,7 +2074,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2076
2074
  /** Returns `true` (hide) when no offer has been set before mount. */
2077
2075
  #checkOffer() {
2078
2076
  if (!this.#offer) {
2079
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
2080
2077
  this.style.display = "none";
2081
2078
  this.querySelector(SEL_CONTAINER)?.remove();
2082
2079
  return true;
@@ -2104,16 +2101,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2104
2101
  */
2105
2102
  async #fetchAndCacheOptions() {
2106
2103
  this.#paymentOptions = await this.#fetchPaymentOptions();
2107
- if (!this.#paymentOptions) {
2108
- console.warn("[web-apple-pay] button removed from DOM \u2014 reason: getPaymentOptions threw an error (see previous log for details)");
2109
- this.style.display = "none";
2110
- this.querySelector(SEL_CONTAINER)?.remove();
2111
- return true;
2112
- }
2113
- if (!this.#paymentOptions.options?.apple_pay) {
2114
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: BFF responded but apple_pay is absent from payment options", {
2115
- receivedOptions: this.#paymentOptions.options
2116
- });
2104
+ if (!this.#paymentOptions?.options?.apple_pay) {
2117
2105
  this.style.display = "none";
2118
2106
  this.querySelector(SEL_CONTAINER)?.remove();
2119
2107
  return true;
@@ -2122,7 +2110,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2122
2110
  }
2123
2111
  /** Injects the button template and wires click and confirm event listeners. */
2124
2112
  #renderTemplate() {
2125
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2126
2113
  this.style.removeProperty("display");
2127
2114
  ensureApplePayLogoSymbol();
2128
2115
  const template = document.createElement("template");
@@ -2143,7 +2130,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2143
2130
  if (button) {
2144
2131
  button.classList.remove("wap-loading");
2145
2132
  this.#updateDisabledState();
2146
- this.#scheduleRecaptchaTokens();
2147
2133
  trackExpressWalletImpression(this.#offer.sku_id, {
2148
2134
  entryPoint: this.#entryPoint,
2149
2135
  country: this.#country
@@ -2182,25 +2168,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2182
2168
  const country = this.#country;
2183
2169
  modal.onConfirm = (recaptchaTokens) => {
2184
2170
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2185
- this.#scheduleRecaptchaTokens();
2186
2171
  };
2187
- modal.open(this.#recaptchaTokensPromise);
2188
- }
2189
- /**
2190
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2191
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2192
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2193
- * a single transient failure from permanently disabling the CTA on all retries.
2194
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2195
- */
2196
- #scheduleRecaptchaTokens() {
2197
- const attempt = getPurchaseRecaptchaTokens();
2198
- attempt.catch(() => {
2199
- if (this.#recaptchaTokensPromise === attempt) {
2200
- this.#recaptchaTokensPromise = null;
2201
- }
2202
- });
2203
- this.#recaptchaTokensPromise = attempt;
2172
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2173
+ modal.open(recaptchaTokensPromise);
2204
2174
  }
2205
2175
  async #fetchSession() {
2206
2176
  try {
@@ -2211,16 +2181,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2211
2181
  }
2212
2182
  async #fetchPaymentOptions() {
2213
2183
  try {
2214
- const options = await getPaymentOptions({
2184
+ return await getPaymentOptions({
2215
2185
  sku: this.#offer.sku_id,
2216
2186
  countryCode: this.#country,
2217
2187
  currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
2218
2188
  checkoutUrl: this.#returnUrl
2219
2189
  });
2220
- console.log("[web-apple-pay] getPaymentOptions response received", options);
2221
- return options;
2222
- } catch (error) {
2223
- console.warn("[web-apple-pay] getPaymentOptions fetch failed \u2014 returning null", error);
2190
+ } catch {
2224
2191
  return null;
2225
2192
  }
2226
2193
  }
package/dist/src/index.js CHANGED
@@ -1913,6 +1913,7 @@ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
1913
1913
  };
1914
1914
 
1915
1915
  // src/apple-pay-button.ts
1916
+ var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
1916
1917
  var TOTAL_LABEL = "The Economist";
1917
1918
  var DEFAULT_CURRENCY = "USD";
1918
1919
  var DEFAULT_TOTAL = "0.00";
@@ -1928,7 +1929,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1928
1929
  define(_ApplePayButton.tag, _ApplePayButton);
1929
1930
  }
1930
1931
  /**
1931
- * Creates and configures an ApplePayButton if the offer is eligible.
1932
+ * Creates and configures an ApplePayButton if the feature flag is present.
1932
1933
  */
1933
1934
  static createIfEnabled(offer, country, entryPoint) {
1934
1935
  if (!offer) {
@@ -1937,6 +1938,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1937
1938
  if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1938
1939
  return null;
1939
1940
  }
1941
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1942
+ return null;
1943
+ }
1940
1944
  _ApplePayButton.define();
1941
1945
  const button = document.createElement(_ApplePayButton.tag);
1942
1946
  button.offer = offer;
@@ -1965,7 +1969,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1965
1969
  #returnUrl = "";
1966
1970
  #supportedBillingCountries = [];
1967
1971
  #entryPoint = "";
1968
- #recaptchaTokensPromise = null;
1969
1972
  // ─── Public API ─────────────────────────────────────────────────────────────
1970
1973
  get offer() {
1971
1974
  return this.#offer;
@@ -2030,7 +2033,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2030
2033
  this.#paymentOptions = null;
2031
2034
  this.#returnUrl = "";
2032
2035
  this.#supportedBillingCountries = [];
2033
- this.#recaptchaTokensPromise = null;
2034
2036
  this.querySelector(SEL_CONTAINER)?.remove();
2035
2037
  }
2036
2038
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -2043,10 +2045,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2043
2045
  this.#captureReturnUrl();
2044
2046
  this.#computeBillingCountries();
2045
2047
  if (await this.#fetchAndCacheOptions()) return;
2046
- console.log("[web-apple-pay] button shown \u2014 reason: all checks passed, Apple Pay is available and offer is eligible");
2047
2048
  this.#finishLoading();
2048
- } catch (error) {
2049
- console.warn("[web-apple-pay] button hidden \u2014 reason: unexpected error in render pipeline", error);
2049
+ } catch {
2050
2050
  this.style.display = "none";
2051
2051
  this.querySelector(SEL_CONTAINER)?.remove();
2052
2052
  } finally {
@@ -2057,7 +2057,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2057
2057
  async #checkAvailability() {
2058
2058
  const available = await isApplePayAvailable();
2059
2059
  if (!available) {
2060
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: Apple Pay unavailable on this device/browser");
2061
2060
  this.style.display = "none";
2062
2061
  this.querySelector(SEL_CONTAINER)?.remove();
2063
2062
  return true;
@@ -2071,7 +2070,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2071
2070
  async #checkSession() {
2072
2071
  this.#sessionData = await this.#fetchSession();
2073
2072
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
2074
- console.log(`[web-apple-pay] button removed from DOM \u2014 reason: session check failed, userType="${this.#sessionData.userType}"`);
2075
2073
  this.style.display = "none";
2076
2074
  this.querySelector(SEL_CONTAINER)?.remove();
2077
2075
  return true;
@@ -2081,7 +2079,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2081
2079
  /** Returns `true` (hide) when no offer has been set before mount. */
2082
2080
  #checkOffer() {
2083
2081
  if (!this.#offer) {
2084
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: no offer set on element before mount");
2085
2082
  this.style.display = "none";
2086
2083
  this.querySelector(SEL_CONTAINER)?.remove();
2087
2084
  return true;
@@ -2109,16 +2106,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2109
2106
  */
2110
2107
  async #fetchAndCacheOptions() {
2111
2108
  this.#paymentOptions = await this.#fetchPaymentOptions();
2112
- if (!this.#paymentOptions) {
2113
- console.warn("[web-apple-pay] button removed from DOM \u2014 reason: getPaymentOptions threw an error (see previous log for details)");
2114
- this.style.display = "none";
2115
- this.querySelector(SEL_CONTAINER)?.remove();
2116
- return true;
2117
- }
2118
- if (!this.#paymentOptions.options?.apple_pay) {
2119
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: BFF responded but apple_pay is absent from payment options", {
2120
- receivedOptions: this.#paymentOptions.options
2121
- });
2109
+ if (!this.#paymentOptions?.options?.apple_pay) {
2122
2110
  this.style.display = "none";
2123
2111
  this.querySelector(SEL_CONTAINER)?.remove();
2124
2112
  return true;
@@ -2127,7 +2115,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2127
2115
  }
2128
2116
  /** Injects the button template and wires click and confirm event listeners. */
2129
2117
  #renderTemplate() {
2130
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2131
2118
  this.style.removeProperty("display");
2132
2119
  ensureApplePayLogoSymbol();
2133
2120
  const template = document.createElement("template");
@@ -2148,7 +2135,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2148
2135
  if (button) {
2149
2136
  button.classList.remove("wap-loading");
2150
2137
  this.#updateDisabledState();
2151
- this.#scheduleRecaptchaTokens();
2152
2138
  trackExpressWalletImpression(this.#offer.sku_id, {
2153
2139
  entryPoint: this.#entryPoint,
2154
2140
  country: this.#country
@@ -2187,25 +2173,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2187
2173
  const country = this.#country;
2188
2174
  modal.onConfirm = (recaptchaTokens) => {
2189
2175
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2190
- this.#scheduleRecaptchaTokens();
2191
2176
  };
2192
- modal.open(this.#recaptchaTokensPromise);
2193
- }
2194
- /**
2195
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2196
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2197
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2198
- * a single transient failure from permanently disabling the CTA on all retries.
2199
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2200
- */
2201
- #scheduleRecaptchaTokens() {
2202
- const attempt = getPurchaseRecaptchaTokens();
2203
- attempt.catch(() => {
2204
- if (this.#recaptchaTokensPromise === attempt) {
2205
- this.#recaptchaTokensPromise = null;
2206
- }
2207
- });
2208
- this.#recaptchaTokensPromise = attempt;
2177
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2178
+ modal.open(recaptchaTokensPromise);
2209
2179
  }
2210
2180
  async #fetchSession() {
2211
2181
  try {
@@ -2216,16 +2186,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2216
2186
  }
2217
2187
  async #fetchPaymentOptions() {
2218
2188
  try {
2219
- const options = await getPaymentOptions({
2189
+ return await getPaymentOptions({
2220
2190
  sku: this.#offer.sku_id,
2221
2191
  countryCode: this.#country,
2222
2192
  currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
2223
2193
  checkoutUrl: this.#returnUrl
2224
2194
  });
2225
- console.log("[web-apple-pay] getPaymentOptions response received", options);
2226
- return options;
2227
- } catch (error) {
2228
- console.warn("[web-apple-pay] getPaymentOptions fetch failed \u2014 returning null", error);
2195
+ } catch {
2229
2196
  return null;
2230
2197
  }
2231
2198
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@economist/web-apple-pay",
3
3
  "description": "Web component package for Apple Pay checkout UI",
4
- "version": "0.1.3-beta.41",
4
+ "version": "0.1.3-beta.42",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",