@economist/web-apple-pay 0.1.3-beta.40 → 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;
@@ -2110,7 +2107,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2110
2107
  async #fetchAndCacheOptions() {
2111
2108
  this.#paymentOptions = await this.#fetchPaymentOptions();
2112
2109
  if (!this.#paymentOptions?.options?.apple_pay) {
2113
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: payment options BFF reports Apple Pay unavailable for this offer");
2114
2110
  this.style.display = "none";
2115
2111
  this.querySelector(SEL_CONTAINER)?.remove();
2116
2112
  return true;
@@ -2119,7 +2115,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2119
2115
  }
2120
2116
  /** Injects the button template and wires click and confirm event listeners. */
2121
2117
  #renderTemplate() {
2122
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2123
2118
  this.style.removeProperty("display");
2124
2119
  ensureApplePayLogoSymbol();
2125
2120
  const template = document.createElement("template");
@@ -2140,7 +2135,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2140
2135
  if (button) {
2141
2136
  button.classList.remove("wap-loading");
2142
2137
  this.#updateDisabledState();
2143
- this.#scheduleRecaptchaTokens();
2144
2138
  trackExpressWalletImpression(this.#offer.sku_id, {
2145
2139
  entryPoint: this.#entryPoint,
2146
2140
  country: this.#country
@@ -2179,25 +2173,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2179
2173
  const country = this.#country;
2180
2174
  modal.onConfirm = (recaptchaTokens) => {
2181
2175
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2182
- this.#scheduleRecaptchaTokens();
2183
2176
  };
2184
- modal.open(this.#recaptchaTokensPromise);
2185
- }
2186
- /**
2187
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2188
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2189
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2190
- * a single transient failure from permanently disabling the CTA on all retries.
2191
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2192
- */
2193
- #scheduleRecaptchaTokens() {
2194
- const attempt = getPurchaseRecaptchaTokens();
2195
- attempt.catch(() => {
2196
- if (this.#recaptchaTokensPromise === attempt) {
2197
- this.#recaptchaTokensPromise = null;
2198
- }
2199
- });
2200
- this.#recaptchaTokensPromise = attempt;
2177
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2178
+ modal.open(recaptchaTokensPromise);
2201
2179
  }
2202
2180
  async #fetchSession() {
2203
2181
  try {
@@ -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;
@@ -2105,7 +2102,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2105
2102
  async #fetchAndCacheOptions() {
2106
2103
  this.#paymentOptions = await this.#fetchPaymentOptions();
2107
2104
  if (!this.#paymentOptions?.options?.apple_pay) {
2108
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: payment options BFF reports Apple Pay unavailable for this offer");
2109
2105
  this.style.display = "none";
2110
2106
  this.querySelector(SEL_CONTAINER)?.remove();
2111
2107
  return true;
@@ -2114,7 +2110,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2114
2110
  }
2115
2111
  /** Injects the button template and wires click and confirm event listeners. */
2116
2112
  #renderTemplate() {
2117
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2118
2113
  this.style.removeProperty("display");
2119
2114
  ensureApplePayLogoSymbol();
2120
2115
  const template = document.createElement("template");
@@ -2135,7 +2130,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2135
2130
  if (button) {
2136
2131
  button.classList.remove("wap-loading");
2137
2132
  this.#updateDisabledState();
2138
- this.#scheduleRecaptchaTokens();
2139
2133
  trackExpressWalletImpression(this.#offer.sku_id, {
2140
2134
  entryPoint: this.#entryPoint,
2141
2135
  country: this.#country
@@ -2174,25 +2168,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2174
2168
  const country = this.#country;
2175
2169
  modal.onConfirm = (recaptchaTokens) => {
2176
2170
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2177
- this.#scheduleRecaptchaTokens();
2178
2171
  };
2179
- modal.open(this.#recaptchaTokensPromise);
2180
- }
2181
- /**
2182
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2183
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2184
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2185
- * a single transient failure from permanently disabling the CTA on all retries.
2186
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2187
- */
2188
- #scheduleRecaptchaTokens() {
2189
- const attempt = getPurchaseRecaptchaTokens();
2190
- attempt.catch(() => {
2191
- if (this.#recaptchaTokensPromise === attempt) {
2192
- this.#recaptchaTokensPromise = null;
2193
- }
2194
- });
2195
- this.#recaptchaTokensPromise = attempt;
2172
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2173
+ modal.open(recaptchaTokensPromise);
2196
2174
  }
2197
2175
  async #fetchSession() {
2198
2176
  try {
@@ -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;
@@ -2113,7 +2110,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2113
2110
  async #fetchAndCacheOptions() {
2114
2111
  this.#paymentOptions = await this.#fetchPaymentOptions();
2115
2112
  if (!this.#paymentOptions?.options?.apple_pay) {
2116
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: payment options BFF reports Apple Pay unavailable for this offer");
2117
2113
  this.style.display = "none";
2118
2114
  this.querySelector(SEL_CONTAINER)?.remove();
2119
2115
  return true;
@@ -2122,7 +2118,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2122
2118
  }
2123
2119
  /** Injects the button template and wires click and confirm event listeners. */
2124
2120
  #renderTemplate() {
2125
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2126
2121
  this.style.removeProperty("display");
2127
2122
  ensureApplePayLogoSymbol();
2128
2123
  const template = document.createElement("template");
@@ -2143,7 +2138,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2143
2138
  if (button) {
2144
2139
  button.classList.remove("wap-loading");
2145
2140
  this.#updateDisabledState();
2146
- this.#scheduleRecaptchaTokens();
2147
2141
  trackExpressWalletImpression(this.#offer.sku_id, {
2148
2142
  entryPoint: this.#entryPoint,
2149
2143
  country: this.#country
@@ -2182,25 +2176,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2182
2176
  const country = this.#country;
2183
2177
  modal.onConfirm = (recaptchaTokens) => {
2184
2178
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2185
- this.#scheduleRecaptchaTokens();
2186
2179
  };
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;
2180
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2181
+ modal.open(recaptchaTokensPromise);
2204
2182
  }
2205
2183
  async #fetchSession() {
2206
2184
  try {
@@ -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;
@@ -2105,7 +2102,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2105
2102
  async #fetchAndCacheOptions() {
2106
2103
  this.#paymentOptions = await this.#fetchPaymentOptions();
2107
2104
  if (!this.#paymentOptions?.options?.apple_pay) {
2108
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: payment options BFF reports Apple Pay unavailable for this offer");
2109
2105
  this.style.display = "none";
2110
2106
  this.querySelector(SEL_CONTAINER)?.remove();
2111
2107
  return true;
@@ -2114,7 +2110,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2114
2110
  }
2115
2111
  /** Injects the button template and wires click and confirm event listeners. */
2116
2112
  #renderTemplate() {
2117
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2118
2113
  this.style.removeProperty("display");
2119
2114
  ensureApplePayLogoSymbol();
2120
2115
  const template = document.createElement("template");
@@ -2135,7 +2130,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2135
2130
  if (button) {
2136
2131
  button.classList.remove("wap-loading");
2137
2132
  this.#updateDisabledState();
2138
- this.#scheduleRecaptchaTokens();
2139
2133
  trackExpressWalletImpression(this.#offer.sku_id, {
2140
2134
  entryPoint: this.#entryPoint,
2141
2135
  country: this.#country
@@ -2174,25 +2168,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2174
2168
  const country = this.#country;
2175
2169
  modal.onConfirm = (recaptchaTokens) => {
2176
2170
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2177
- this.#scheduleRecaptchaTokens();
2178
2171
  };
2179
- modal.open(this.#recaptchaTokensPromise);
2180
- }
2181
- /**
2182
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2183
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2184
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2185
- * a single transient failure from permanently disabling the CTA on all retries.
2186
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2187
- */
2188
- #scheduleRecaptchaTokens() {
2189
- const attempt = getPurchaseRecaptchaTokens();
2190
- attempt.catch(() => {
2191
- if (this.#recaptchaTokensPromise === attempt) {
2192
- this.#recaptchaTokensPromise = null;
2193
- }
2194
- });
2195
- this.#recaptchaTokensPromise = attempt;
2172
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2173
+ modal.open(recaptchaTokensPromise);
2196
2174
  }
2197
2175
  async #fetchSession() {
2198
2176
  try {
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;
@@ -2110,7 +2107,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2110
2107
  async #fetchAndCacheOptions() {
2111
2108
  this.#paymentOptions = await this.#fetchPaymentOptions();
2112
2109
  if (!this.#paymentOptions?.options?.apple_pay) {
2113
- console.log("[web-apple-pay] button removed from DOM \u2014 reason: payment options BFF reports Apple Pay unavailable for this offer");
2114
2110
  this.style.display = "none";
2115
2111
  this.querySelector(SEL_CONTAINER)?.remove();
2116
2112
  return true;
@@ -2119,7 +2115,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2119
2115
  }
2120
2116
  /** Injects the button template and wires click and confirm event listeners. */
2121
2117
  #renderTemplate() {
2122
- console.log("[web-apple-pay] button shown \u2014 reason: template injected into DOM (loading state), awaiting pipeline checks");
2123
2118
  this.style.removeProperty("display");
2124
2119
  ensureApplePayLogoSymbol();
2125
2120
  const template = document.createElement("template");
@@ -2140,7 +2135,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2140
2135
  if (button) {
2141
2136
  button.classList.remove("wap-loading");
2142
2137
  this.#updateDisabledState();
2143
- this.#scheduleRecaptchaTokens();
2144
2138
  trackExpressWalletImpression(this.#offer.sku_id, {
2145
2139
  entryPoint: this.#entryPoint,
2146
2140
  country: this.#country
@@ -2179,25 +2173,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2179
2173
  const country = this.#country;
2180
2174
  modal.onConfirm = (recaptchaTokens) => {
2181
2175
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2182
- this.#scheduleRecaptchaTokens();
2183
2176
  };
2184
- modal.open(this.#recaptchaTokensPromise);
2185
- }
2186
- /**
2187
- * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2188
- * If the fetch rejects, the field is cleared so the next `modal.open()` call
2189
- * falls back to a new attempt via the modal's own null-fallback path — preventing
2190
- * a single transient failure from permanently disabling the CTA on all retries.
2191
- * The identity guard prevents a late rejection from clobbering a newer attempt.
2192
- */
2193
- #scheduleRecaptchaTokens() {
2194
- const attempt = getPurchaseRecaptchaTokens();
2195
- attempt.catch(() => {
2196
- if (this.#recaptchaTokensPromise === attempt) {
2197
- this.#recaptchaTokensPromise = null;
2198
- }
2199
- });
2200
- this.#recaptchaTokensPromise = attempt;
2177
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2178
+ modal.open(recaptchaTokensPromise);
2201
2179
  }
2202
2180
  async #fetchSession() {
2203
2181
  try {
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.40",
4
+ "version": "0.1.3-beta.42",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",