recur-tw 0.12.0 → 0.13.0

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/checkout.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var RecurCheckoutScript=(()=>{var m=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var R=(e,t)=>{for(var r in t)m(e,r,{get:t[r],enumerable:!0})},_=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of E(t))!C.call(e,n)&&n!==r&&m(e,n,{get:()=>t[n],enumerable:!(o=v(t,n))||o.enumerable});return e};var U=e=>_(m({},"__esModule",{value:!0}),e);var T={};R(T,{default:()=>I});var c={embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},l=null,g=null;function f(){if(document.getElementById("recur-checkout-styles"))return;let e=document.createElement("style");e.id="recur-checkout-styles",e.textContent=`
1
+ "use strict";var RecurCheckoutScript=(()=>{var f=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var R=(e,t)=>{for(var r in t)f(e,r,{get:t[r],enumerable:!0})},_=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of E(t))!C.call(e,n)&&n!==r&&f(e,n,{get:()=>t[n],enumerable:!(o=v(t,n))||o.enumerable});return e};var U=e=>_(f({},"__esModule",{value:!0}),e);var T={};R(T,{default:()=>I});var a={embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},h=null,p=null;function m(){if(document.getElementById("recur-checkout-styles"))return;let e=document.createElement("style");e.id="recur-checkout-styles",e.textContent=`
2
2
  .recur-checkout-dialog {
3
3
  border: none;
4
4
  border-radius: 12px;
@@ -122,5 +122,5 @@
122
122
  opacity: 0.7;
123
123
  pointer-events: none;
124
124
  }
125
- `,document.head.appendChild(e)}function S(e){try{let r=new URL(e,window.location.origin).pathname.split("/"),o=r.indexOf("buy");if(o===-1||o>=r.length-1)return null;let n=r[o+1];return n?n.startsWith("prod_")?{productId:n}:{productSlug:n}:null}catch{return null}}function P(e){let t=e.getAttribute("data-key");if(t)return t;try{let o=e.getAttribute("href");if(o){let i=new URL(o,window.location.origin).searchParams.get("key");if(i)return i}}catch{}let r=document.querySelector("script[data-recur-key]");return r?r.getAttribute("data-recur-key"):window.RecurConfig?.publishableKey?window.RecurConfig.publishableKey:null}async function b(e,t){let r={};e.productId&&(r.productId=e.productId),e.email&&(r.customerEmail=e.email),e.name&&(r.customerName=e.name);let o=await fetch(`${c.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t,"X-Recur-Embed-Domain":c.embedUrl,"X-Recur-SDK-Type":"checkout.js","X-Recur-Source":window.location.origin},body:JSON.stringify(r)});if(!o.ok){let i=await o.json().catch(()=>({}));throw new Error(i.error?.message||i.error||"Failed to create checkout")}let n=await o.json();return{id:n.checkout.id,publishableKey:t,clientSecret:n.checkout.client_secret}}function y(e,t){s(),f();let r=document.createElement("dialog");r.className="recur-checkout-dialog";let o=document.createElement("div");o.className="recur-checkout-dialog__header";let n=document.createElement("button");n.className="recur-checkout-dialog__close",n.innerHTML="×",n.type="button",n.setAttribute("aria-label","Close"),n.onclick=()=>{s(),t?.(),u("recur:close",{})},o.appendChild(n);let i=document.createElement("iframe");i.className="recur-checkout-dialog__iframe",i.src=e,i.setAttribute("allow","payment"),i.setAttribute("title","Recur Checkout"),r.appendChild(o),r.appendChild(i),document.body.appendChild(r),l=r,g=i,r.showModal(),document.body.style.overflow="hidden",r.addEventListener("cancel",p=>{p.preventDefault(),s(),t?.(),u("recur:close",{})}),window.addEventListener("message",k)}function s(){l&&(l.close(),l.remove(),l=null),g=null,document.body.style.overflow="",window.removeEventListener("message",k)}function k(e){if(!e.origin.includes("recur.tw")&&!e.origin.includes("localhost"))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_PAYMENT_SUCCESS":s(),u("recur:success",r);break;case"RECUR_PAYMENT_ERROR":u("recur:error",r);break;case"RECUR_PAYMENT_CANCEL":s(),u("recur:close",{});break;case"RECUR_RESIZE":g&&r?.height&&(g.style.height=`${Math.min(r.height+56,window.innerHeight*.9)}px`);break}}function u(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function A(e,t){e.preventDefault();let r=t.getAttribute("href");if(!r){console.error("[Recur] Missing href on recur-button");return}let o=S(r);if(!o){console.error("[Recur] Invalid product URL:",r);return}let n=P(t);if(!n){console.error("[Recur] Missing publishable key. Add data-key attribute or set RecurConfig.publishableKey");return}let i={productId:o.productId||"",email:t.getAttribute("data-email")||void 0,name:t.getAttribute("data-name")||void 0,successUrl:t.getAttribute("data-success-url")||void 0,theme:t.getAttribute("data-theme")||void 0};t.setAttribute("data-loading","true");let p=t.textContent;t.textContent="...";try{let a=await b(i,n),d=new URL(`${c.embedUrl}/checkout`);d.searchParams.set("id",a.id),d.searchParams.set("key",a.publishableKey),d.searchParams.set("client_secret",a.clientSecret),i.theme&&d.searchParams.set("theme",i.theme),y(d.toString(),()=>{let x=i.successUrl})}catch(a){console.error("[Recur] Checkout error:",a),u("recur:error",{message:a.message})}finally{t.setAttribute("data-loading","false"),t.textContent=p}}function h(){document.querySelectorAll(".recur-button").forEach(t=>{t.hasAttribute("data-recur-initialized")||(t.setAttribute("data-recur-initialized","true"),t.addEventListener("click",r=>A(r,t)))})}function L(){let e=window.location.hostname;(e==="localhost"||e==="127.0.0.1"||e.includes(".local"))&&(c.embedUrl=`${window.location.protocol}//${e}:3002`,c.apiUrl=`${window.location.protocol}//${e}:3000/api`)}var w={config(e){Object.assign(c,e)},async popup(e){let t=await b(e,e.key),r=new URL(`${c.embedUrl}/checkout`);r.searchParams.set("id",t.id),r.searchParams.set("key",t.publishableKey),r.searchParams.set("client_secret",t.clientSecret),e.theme&&r.searchParams.set("theme",e.theme),y(r.toString())},close(){s()},init(){h()}};function M(){L(),f(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",h):h(),new MutationObserver(t=>{for(let r of t)r.addedNodes.length>0&&h()}).observe(document.body,{childList:!0,subtree:!0})}window.Recur=w;M();var I=w;return U(T);})();
125
+ `,document.head.appendChild(e)}function S(e){try{let r=new URL(e,window.location.origin).pathname.split("/"),o=r.indexOf("buy");if(o===-1||o>=r.length-1)return null;let n=r[o+1];return n?n.startsWith("prod_")?{productId:n}:{productSlug:n}:null}catch{return null}}function P(e){let t=e.getAttribute("data-key");if(t)return t;try{let n=e.getAttribute("href");if(n){let s=new URL(n,window.location.origin).searchParams.get("key");if(s)return s}}catch{}let r=document.querySelector("script[data-recur-key]");if(r)return r.getAttribute("data-recur-key");let o=window.RecurConfig;return o?.publishableKey?o.publishableKey:null}async function b(e,t){let r={};e.productId&&(r.productId=e.productId),e.email&&(r.customerEmail=e.email),e.name&&(r.customerName=e.name);let o=await fetch(`${a.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t,"X-Recur-Embed-Domain":a.embedUrl,"X-Recur-SDK-Type":"checkout.js","X-Recur-Source":window.location.origin},body:JSON.stringify(r)});if(!o.ok){let i=await o.json().catch(()=>({}));throw new Error(i.error?.message||i.error||"Failed to create checkout")}let n=await o.json();return{id:n.checkout.id,publishableKey:t,clientSecret:n.checkout.client_secret}}function y(e,t){u(),m();let r=document.createElement("dialog");r.className="recur-checkout-dialog";let o=document.createElement("div");o.className="recur-checkout-dialog__header";let n=document.createElement("button");n.className="recur-checkout-dialog__close",n.innerHTML="×",n.type="button",n.setAttribute("aria-label","Close"),n.onclick=()=>{u(),t?.(),d("recur:close",{})},o.appendChild(n);let i=document.createElement("iframe");i.className="recur-checkout-dialog__iframe",i.src=e,i.setAttribute("allow","payment"),i.setAttribute("title","Recur Checkout"),r.appendChild(o),r.appendChild(i),document.body.appendChild(r),h=r,p=i,r.showModal(),document.body.style.overflow="hidden",r.addEventListener("cancel",s=>{s.preventDefault(),u(),t?.(),d("recur:close",{})}),window.addEventListener("message",k)}function u(){h&&(h.close(),h.remove(),h=null),p=null,document.body.style.overflow="",window.removeEventListener("message",k)}function k(e){if(!e.origin.includes("recur.tw")&&!e.origin.includes("localhost"))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_PAYMENT_SUCCESS":u(),d("recur:success",r);break;case"RECUR_PAYMENT_ERROR":d("recur:error",r);break;case"RECUR_PAYMENT_CANCEL":u(),d("recur:close",{});break;case"RECUR_RESIZE":p&&r?.height&&(p.style.height=`${Math.min(r.height+56,window.innerHeight*.9)}px`);break}}function d(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function A(e,t){e.preventDefault();let r=t.getAttribute("href");if(!r){console.error("[Recur] Missing href on recur-button");return}let o=S(r);if(!o){console.error("[Recur] Invalid product URL:",r);return}let n=P(t);if(!n){console.error("[Recur] Missing publishable key. Add data-key attribute or set RecurConfig.publishableKey");return}let i={productId:o.productId||"",email:t.getAttribute("data-email")||void 0,name:t.getAttribute("data-name")||void 0,successUrl:t.getAttribute("data-success-url")||void 0,theme:t.getAttribute("data-theme")||void 0};t.setAttribute("data-loading","true");let s=t.textContent;t.textContent="...";try{let c=await b(i,n),l=new URL(`${a.embedUrl}/checkout`);l.searchParams.set("id",c.id),l.searchParams.set("key",c.publishableKey),l.searchParams.set("client_secret",c.clientSecret),i.theme&&l.searchParams.set("theme",i.theme),y(l.toString(),()=>{let x=i.successUrl})}catch(c){console.error("[Recur] Checkout error:",c),d("recur:error",{message:c instanceof Error?c.message:"Unknown error"})}finally{t.setAttribute("data-loading","false"),t.textContent=s}}function g(){document.querySelectorAll(".recur-button").forEach(t=>{t.hasAttribute("data-recur-initialized")||(t.setAttribute("data-recur-initialized","true"),t.addEventListener("click",r=>A(r,t)))})}function L(){let e=window.location.hostname;(e==="localhost"||e==="127.0.0.1"||e.includes(".local"))&&(a.embedUrl=`${window.location.protocol}//${e}:3002`,a.apiUrl=`${window.location.protocol}//${e}:3000/api`)}var w={config(e){Object.assign(a,e)},async popup(e){let t=await b(e,e.key),r=new URL(`${a.embedUrl}/checkout`);r.searchParams.set("id",t.id),r.searchParams.set("key",t.publishableKey),r.searchParams.set("client_secret",t.clientSecret),e.theme&&r.searchParams.set("theme",e.theme),y(r.toString())},close(){u()},init(){g()}};function M(){L(),m(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",g):g(),new MutationObserver(t=>{for(let r of t)r.addedNodes.length>0&&g()}).observe(document.body,{childList:!0,subtree:!0})}window.Recur=w;M();var I=w;return U(T);})();
126
126
  /* Recur Checkout - https://recur.tw */
package/dist/index.cjs CHANGED
@@ -1097,6 +1097,7 @@ var init_payment_form = __esm({
1097
1097
  __publicField(this, "customStyles");
1098
1098
  __publicField(this, "_isInitializing", false);
1099
1099
  __publicField(this, "_initializationAborted", false);
1100
+ __publicField(this, "_paymentSession", null);
1100
1101
  // Test mode state
1101
1102
  __publicField(this, "_showTestCardHints", false);
1102
1103
  // Coupon state
@@ -1733,7 +1734,7 @@ var init_payment_form = __esm({
1733
1734
  bubbles: true,
1734
1735
  composed: true
1735
1736
  }));
1736
- } catch (err) {
1737
+ } catch {
1737
1738
  this._couponError = "\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66";
1738
1739
  this._couponLoading = false;
1739
1740
  this.updateCouponSectionDOM();
@@ -1767,7 +1768,7 @@ var init_payment_form = __esm({
1767
1768
  bubbles: true,
1768
1769
  composed: true
1769
1770
  }));
1770
- } catch (err) {
1771
+ } catch {
1771
1772
  this._couponError = "\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66";
1772
1773
  this._couponLoading = false;
1773
1774
  this.updateCouponSectionDOM();
@@ -1926,7 +1927,8 @@ var init_payment_form = __esm({
1926
1927
  try {
1927
1928
  await paymentSession.start();
1928
1929
  } catch (startError) {
1929
- const is1008Error = startError?.message?.includes("1008") || startError?.message?.includes("timeout") || startError?.code === 1008;
1930
+ const errorObj = startError;
1931
+ const is1008Error = errorObj?.message?.includes("1008") || errorObj?.message?.includes("timeout") || errorObj?.code === 1008;
1930
1932
  if (is1008Error && this._initializationAborted) {
1931
1933
  console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring");
1932
1934
  this._isInitializing = false;
@@ -1946,7 +1948,8 @@ var init_payment_form = __esm({
1946
1948
  return;
1947
1949
  }
1948
1950
  console.log("[PaymentForm] PAYUNi update:", data);
1949
- const allFieldsComplete = data.status && data.status.CardNo === true && data.status.CardExp === true && data.status.CardCvc === true;
1951
+ const updateData = data;
1952
+ const allFieldsComplete = updateData.status && updateData.status.CardNo === true && updateData.status.CardExp === true && updateData.status.CardCvc === true;
1950
1953
  const submitBtn = document.getElementById(`${this.containerId}-submit-btn`);
1951
1954
  if (submitBtn) {
1952
1955
  submitBtn.disabled = !allFieldsComplete;
@@ -2172,7 +2175,7 @@ var init_checkout_button = __esm({
2172
2175
  this._isLoading = false;
2173
2176
  this.render();
2174
2177
  this.setupEventListeners();
2175
- this.dispatchError(error.message || "Failed to create checkout session");
2178
+ this.dispatchError(error instanceof Error ? error.message : "Failed to create checkout session");
2176
2179
  }
2177
2180
  });
2178
2181
  this.attachShadow({ mode: "open" });
@@ -2620,7 +2623,7 @@ var init_portal_button = __esm({
2620
2623
  this._isLoading = false;
2621
2624
  this.render();
2622
2625
  this.setupEventListeners();
2623
- this.dispatchError(error.message || "Failed to create portal session");
2626
+ this.dispatchError(error instanceof Error ? error.message : "Failed to create portal session");
2624
2627
  }
2625
2628
  }
2626
2629
  dispatchError(message) {
@@ -2739,7 +2742,7 @@ function toCamelCase(obj) {
2739
2742
 
2740
2743
  // package.json
2741
2744
  var package_default = {
2742
- version: "0.12.0"};
2745
+ version: "0.13.0"};
2743
2746
  var SDK_VERSION = package_default.version;
2744
2747
  var SDK_TYPE = "react";
2745
2748
  var RecurContext = React.createContext(null);
@@ -2765,7 +2768,7 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
2765
2768
  checkoutMode: "embedded",
2766
2769
  ...initialConfig
2767
2770
  });
2768
- }, [initialConfig.checkoutMode, initialConfig.publishableKey, initialConfig.containerElementId]);
2771
+ }, [initialConfig]);
2769
2772
  React__default.default.useEffect(() => {
2770
2773
  setIsCheckingOut(false);
2771
2774
  }, [config.checkoutMode]);
@@ -3263,9 +3266,10 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
3263
3266
  paymentForm.resetButton?.();
3264
3267
  return;
3265
3268
  } else {
3269
+ const failureMessage = failureError.details && !Array.isArray(failureError.details) ? failureError.details.failure_message : void 0;
3266
3270
  paymentForm.showError?.({
3267
3271
  title: "\u4ED8\u6B3E\u5931\u6557",
3268
- message: failureError.details?.failure_message || failureError.message
3272
+ message: failureMessage || failureError.message
3269
3273
  });
3270
3274
  paymentForm.resetButton?.();
3271
3275
  return;
@@ -3392,7 +3396,8 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
3392
3396
  }
3393
3397
  }
3394
3398
  } catch (pollError) {
3395
- if (pollError.message === "3D \u9A57\u8B49\u5DF2\u53D6\u6D88" || pollError.message === "\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88") {
3399
+ const errorMessage = pollError instanceof Error ? pollError.message : String(pollError);
3400
+ if (errorMessage === "3D \u9A57\u8B49\u5DF2\u53D6\u6D88" || errorMessage === "\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88") {
3396
3401
  throw pollError;
3397
3402
  }
3398
3403
  console.error("[Recur SDK] Poll error:", pollError);
@@ -3454,7 +3459,7 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
3454
3459
  currentPeriodEnd: paymentResult.subscription.currentPeriodEnd
3455
3460
  });
3456
3461
  } else {
3457
- const chargeId = paymentResult.charge?.id || paymentResult.paymentIntent?.id;
3462
+ const chargeId = paymentResult.charge?.id || paymentResult.paymentIntent?.id || checkoutResult.checkout.id;
3458
3463
  const chargeStatus = paymentResult.charge?.status || "SUCCEEDED";
3459
3464
  options.onPaymentComplete({
3460
3465
  id: chargeId,
package/dist/index.d.cts CHANGED
@@ -347,6 +347,16 @@ interface CheckoutResult {
347
347
  * SDK token expiration time
348
348
  */
349
349
  sdkTokenExpiresAt: string;
350
+ /**
351
+ * Credit token for subscription payments
352
+ * Used internally for credit binding with payment gateway
353
+ */
354
+ creditToken?: string;
355
+ /**
356
+ * SDK timestamp from getIframeToken response
357
+ * Used internally for subscription credit binding
358
+ */
359
+ sdkTimestamp?: number;
350
360
  }
351
361
  /**
352
362
  * Payment failure codes from payment provider
@@ -373,19 +383,69 @@ interface PaymentFailureDetails {
373
383
  */
374
384
  can_retry?: boolean;
375
385
  }
386
+ /**
387
+ * Standard API error codes from Recur API
388
+ *
389
+ * These codes match the backend error codes for consistent error handling.
390
+ * Use these to detect specific error conditions and provide appropriate UX.
391
+ */
392
+ type ApiErrorCode = 'bad_request' | 'unauthorized' | 'payment_required' | 'forbidden' | 'not_found' | 'conflict' | 'validation_error' | 'rate_limit_exceeded' | 'internal_server_error';
393
+ /**
394
+ * Details for duplicate subscription errors (conflict)
395
+ * Present when code is 'conflict' and attempting to create a subscription
396
+ * for a product the customer already subscribes to
397
+ */
398
+ interface DuplicateSubscriptionDetails {
399
+ /**
400
+ * ID of the existing subscription
401
+ */
402
+ existing_subscription_id: string;
403
+ /**
404
+ * Status of the existing subscription
405
+ * Typically 'ACTIVE', 'TRIAL', or 'PAST_DUE'
406
+ */
407
+ status: string;
408
+ }
409
+ /**
410
+ * Error details that can be either:
411
+ * - An array of objects (for API errors like 'conflict')
412
+ * - An object with payment failure fields (for onPaymentFailed callback)
413
+ */
414
+ type CheckoutErrorDetails = (DuplicateSubscriptionDetails | Record<string, unknown>)[] | (Record<string, unknown> & PaymentFailureDetails);
376
415
  interface CheckoutError {
377
416
  /**
378
- * Error code
417
+ * Error code - use ApiErrorCode for standard errors
379
418
  */
380
- code: string;
419
+ code: ApiErrorCode | string;
381
420
  /**
382
421
  * Human-readable error message
383
422
  */
384
423
  message: string;
424
+ /**
425
+ * URL to relevant documentation
426
+ */
427
+ docUrl?: string;
385
428
  /**
386
429
  * Additional error details
430
+ *
431
+ * For 'conflict' errors when creating subscriptions (onError):
432
+ * details is an array where details[0] contains DuplicateSubscriptionDetails
433
+ *
434
+ * For payment failures (onPaymentFailed):
435
+ * details is an object with PaymentFailureDetails fields
436
+ *
437
+ * @example
438
+ * // Conflict error (array)
439
+ * if (error.code === 'conflict' && Array.isArray(error.details)) {
440
+ * const subId = error.details[0]?.existing_subscription_id;
441
+ * }
442
+ *
443
+ * // Payment failure (object)
444
+ * if (error.details && !Array.isArray(error.details)) {
445
+ * const canRetry = error.details.can_retry;
446
+ * }
387
447
  */
388
- details?: Record<string, unknown> & PaymentFailureDetails;
448
+ details?: CheckoutErrorDetails;
389
449
  }
390
450
  /**
391
451
  * Action to take after payment failure
@@ -548,8 +608,8 @@ interface UniPaymentInstance {
548
608
  getTradeResult: (options?: {
549
609
  useDefault?: boolean;
550
610
  cardInst?: number;
551
- }) => Promise<any>;
552
- onUpdate?: (callback: (data: any) => void) => void;
611
+ }) => Promise<unknown>;
612
+ onUpdate?: (callback: (data: unknown) => void) => void;
553
613
  }
554
614
  /**
555
615
  * Customer identifier for entitlements lookup
@@ -847,6 +907,7 @@ declare class RecurPaymentForm extends HTMLElement {
847
907
  private customStyles;
848
908
  private _isInitializing;
849
909
  private _initializationAborted;
910
+ private _paymentSession;
850
911
  private _showTestCardHints;
851
912
  private _showCouponInput;
852
913
  private _couponCode;
@@ -1168,7 +1229,7 @@ interface UseSubscribeOptions {
1168
1229
  /**
1169
1230
  * Callback when payment is completed
1170
1231
  */
1171
- onPaymentComplete?: (subscription: any) => void;
1232
+ onPaymentComplete?: (subscription: SubscriptionResult) => void;
1172
1233
  /**
1173
1234
  * Callback when an error occurs
1174
1235
  */
@@ -1395,4 +1456,4 @@ declare function useSubscribe(options?: UseSubscribeOptions): UseSubscribeResult
1395
1456
  */
1396
1457
  declare function useCustomer(): UseCustomerResult;
1397
1458
 
1398
- export { type CheckDeniedReason, type CheckOptions, type CheckResult, type CheckoutError, type CheckoutOptions, type CheckoutResult, type CustomerIdentifier, type Entitlement, type EntitlementCustomer, type EntitlementStatus, type EntitlementSubscription, type Plan, type PlansResult, type Product, type ProductMetadata, type ProductsResult, type RecurConfig, type RecurContextValue, RecurProvider, type RecurProviderProps, type SubscriptionResult, type UseCustomerResult, type UseProductsOptions as UsePlansOptions, type UseProductsResult as UsePlansResult, type UseProductsOptions, type UseProductsResult, type UseSubscribeOptions, type UseSubscribeResult, useCustomer, useProducts as usePlans, useProducts, useRecur, useSubscribe };
1459
+ export { type ApiErrorCode, type CheckDeniedReason, type CheckOptions, type CheckResult, type CheckoutError, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutResult, type CustomerIdentifier, type DuplicateSubscriptionDetails, type Entitlement, type EntitlementCustomer, type EntitlementStatus, type EntitlementSubscription, type PaymentFailedAction, type PaymentFailureCode, type PaymentFailureDetails, type Plan, type PlansResult, type Product, type ProductMetadata, type ProductsResult, type RecurConfig, type RecurContextValue, RecurProvider, type RecurProviderProps, type SubscriptionResult, type UseCustomerResult, type UseProductsOptions as UsePlansOptions, type UseProductsResult as UsePlansResult, type UseProductsOptions, type UseProductsResult, type UseSubscribeOptions, type UseSubscribeResult, useCustomer, useProducts as usePlans, useProducts, useRecur, useSubscribe };
package/dist/index.d.ts CHANGED
@@ -347,6 +347,16 @@ interface CheckoutResult {
347
347
  * SDK token expiration time
348
348
  */
349
349
  sdkTokenExpiresAt: string;
350
+ /**
351
+ * Credit token for subscription payments
352
+ * Used internally for credit binding with payment gateway
353
+ */
354
+ creditToken?: string;
355
+ /**
356
+ * SDK timestamp from getIframeToken response
357
+ * Used internally for subscription credit binding
358
+ */
359
+ sdkTimestamp?: number;
350
360
  }
351
361
  /**
352
362
  * Payment failure codes from payment provider
@@ -373,19 +383,69 @@ interface PaymentFailureDetails {
373
383
  */
374
384
  can_retry?: boolean;
375
385
  }
386
+ /**
387
+ * Standard API error codes from Recur API
388
+ *
389
+ * These codes match the backend error codes for consistent error handling.
390
+ * Use these to detect specific error conditions and provide appropriate UX.
391
+ */
392
+ type ApiErrorCode = 'bad_request' | 'unauthorized' | 'payment_required' | 'forbidden' | 'not_found' | 'conflict' | 'validation_error' | 'rate_limit_exceeded' | 'internal_server_error';
393
+ /**
394
+ * Details for duplicate subscription errors (conflict)
395
+ * Present when code is 'conflict' and attempting to create a subscription
396
+ * for a product the customer already subscribes to
397
+ */
398
+ interface DuplicateSubscriptionDetails {
399
+ /**
400
+ * ID of the existing subscription
401
+ */
402
+ existing_subscription_id: string;
403
+ /**
404
+ * Status of the existing subscription
405
+ * Typically 'ACTIVE', 'TRIAL', or 'PAST_DUE'
406
+ */
407
+ status: string;
408
+ }
409
+ /**
410
+ * Error details that can be either:
411
+ * - An array of objects (for API errors like 'conflict')
412
+ * - An object with payment failure fields (for onPaymentFailed callback)
413
+ */
414
+ type CheckoutErrorDetails = (DuplicateSubscriptionDetails | Record<string, unknown>)[] | (Record<string, unknown> & PaymentFailureDetails);
376
415
  interface CheckoutError {
377
416
  /**
378
- * Error code
417
+ * Error code - use ApiErrorCode for standard errors
379
418
  */
380
- code: string;
419
+ code: ApiErrorCode | string;
381
420
  /**
382
421
  * Human-readable error message
383
422
  */
384
423
  message: string;
424
+ /**
425
+ * URL to relevant documentation
426
+ */
427
+ docUrl?: string;
385
428
  /**
386
429
  * Additional error details
430
+ *
431
+ * For 'conflict' errors when creating subscriptions (onError):
432
+ * details is an array where details[0] contains DuplicateSubscriptionDetails
433
+ *
434
+ * For payment failures (onPaymentFailed):
435
+ * details is an object with PaymentFailureDetails fields
436
+ *
437
+ * @example
438
+ * // Conflict error (array)
439
+ * if (error.code === 'conflict' && Array.isArray(error.details)) {
440
+ * const subId = error.details[0]?.existing_subscription_id;
441
+ * }
442
+ *
443
+ * // Payment failure (object)
444
+ * if (error.details && !Array.isArray(error.details)) {
445
+ * const canRetry = error.details.can_retry;
446
+ * }
387
447
  */
388
- details?: Record<string, unknown> & PaymentFailureDetails;
448
+ details?: CheckoutErrorDetails;
389
449
  }
390
450
  /**
391
451
  * Action to take after payment failure
@@ -548,8 +608,8 @@ interface UniPaymentInstance {
548
608
  getTradeResult: (options?: {
549
609
  useDefault?: boolean;
550
610
  cardInst?: number;
551
- }) => Promise<any>;
552
- onUpdate?: (callback: (data: any) => void) => void;
611
+ }) => Promise<unknown>;
612
+ onUpdate?: (callback: (data: unknown) => void) => void;
553
613
  }
554
614
  /**
555
615
  * Customer identifier for entitlements lookup
@@ -847,6 +907,7 @@ declare class RecurPaymentForm extends HTMLElement {
847
907
  private customStyles;
848
908
  private _isInitializing;
849
909
  private _initializationAborted;
910
+ private _paymentSession;
850
911
  private _showTestCardHints;
851
912
  private _showCouponInput;
852
913
  private _couponCode;
@@ -1168,7 +1229,7 @@ interface UseSubscribeOptions {
1168
1229
  /**
1169
1230
  * Callback when payment is completed
1170
1231
  */
1171
- onPaymentComplete?: (subscription: any) => void;
1232
+ onPaymentComplete?: (subscription: SubscriptionResult) => void;
1172
1233
  /**
1173
1234
  * Callback when an error occurs
1174
1235
  */
@@ -1395,4 +1456,4 @@ declare function useSubscribe(options?: UseSubscribeOptions): UseSubscribeResult
1395
1456
  */
1396
1457
  declare function useCustomer(): UseCustomerResult;
1397
1458
 
1398
- export { type CheckDeniedReason, type CheckOptions, type CheckResult, type CheckoutError, type CheckoutOptions, type CheckoutResult, type CustomerIdentifier, type Entitlement, type EntitlementCustomer, type EntitlementStatus, type EntitlementSubscription, type Plan, type PlansResult, type Product, type ProductMetadata, type ProductsResult, type RecurConfig, type RecurContextValue, RecurProvider, type RecurProviderProps, type SubscriptionResult, type UseCustomerResult, type UseProductsOptions as UsePlansOptions, type UseProductsResult as UsePlansResult, type UseProductsOptions, type UseProductsResult, type UseSubscribeOptions, type UseSubscribeResult, useCustomer, useProducts as usePlans, useProducts, useRecur, useSubscribe };
1459
+ export { type ApiErrorCode, type CheckDeniedReason, type CheckOptions, type CheckResult, type CheckoutError, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutResult, type CustomerIdentifier, type DuplicateSubscriptionDetails, type Entitlement, type EntitlementCustomer, type EntitlementStatus, type EntitlementSubscription, type PaymentFailedAction, type PaymentFailureCode, type PaymentFailureDetails, type Plan, type PlansResult, type Product, type ProductMetadata, type ProductsResult, type RecurConfig, type RecurContextValue, RecurProvider, type RecurProviderProps, type SubscriptionResult, type UseCustomerResult, type UseProductsOptions as UsePlansOptions, type UseProductsResult as UsePlansResult, type UseProductsOptions, type UseProductsResult, type UseSubscribeOptions, type UseSubscribeResult, useCustomer, useProducts as usePlans, useProducts, useRecur, useSubscribe };
package/dist/index.js CHANGED
@@ -1091,6 +1091,7 @@ var init_payment_form = __esm({
1091
1091
  __publicField(this, "customStyles");
1092
1092
  __publicField(this, "_isInitializing", false);
1093
1093
  __publicField(this, "_initializationAborted", false);
1094
+ __publicField(this, "_paymentSession", null);
1094
1095
  // Test mode state
1095
1096
  __publicField(this, "_showTestCardHints", false);
1096
1097
  // Coupon state
@@ -1727,7 +1728,7 @@ var init_payment_form = __esm({
1727
1728
  bubbles: true,
1728
1729
  composed: true
1729
1730
  }));
1730
- } catch (err) {
1731
+ } catch {
1731
1732
  this._couponError = "\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66";
1732
1733
  this._couponLoading = false;
1733
1734
  this.updateCouponSectionDOM();
@@ -1761,7 +1762,7 @@ var init_payment_form = __esm({
1761
1762
  bubbles: true,
1762
1763
  composed: true
1763
1764
  }));
1764
- } catch (err) {
1765
+ } catch {
1765
1766
  this._couponError = "\u7DB2\u8DEF\u932F\u8AA4\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66";
1766
1767
  this._couponLoading = false;
1767
1768
  this.updateCouponSectionDOM();
@@ -1920,7 +1921,8 @@ var init_payment_form = __esm({
1920
1921
  try {
1921
1922
  await paymentSession.start();
1922
1923
  } catch (startError) {
1923
- const is1008Error = startError?.message?.includes("1008") || startError?.message?.includes("timeout") || startError?.code === 1008;
1924
+ const errorObj = startError;
1925
+ const is1008Error = errorObj?.message?.includes("1008") || errorObj?.message?.includes("timeout") || errorObj?.code === 1008;
1924
1926
  if (is1008Error && this._initializationAborted) {
1925
1927
  console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring");
1926
1928
  this._isInitializing = false;
@@ -1940,7 +1942,8 @@ var init_payment_form = __esm({
1940
1942
  return;
1941
1943
  }
1942
1944
  console.log("[PaymentForm] PAYUNi update:", data);
1943
- const allFieldsComplete = data.status && data.status.CardNo === true && data.status.CardExp === true && data.status.CardCvc === true;
1945
+ const updateData = data;
1946
+ const allFieldsComplete = updateData.status && updateData.status.CardNo === true && updateData.status.CardExp === true && updateData.status.CardCvc === true;
1944
1947
  const submitBtn = document.getElementById(`${this.containerId}-submit-btn`);
1945
1948
  if (submitBtn) {
1946
1949
  submitBtn.disabled = !allFieldsComplete;
@@ -2166,7 +2169,7 @@ var init_checkout_button = __esm({
2166
2169
  this._isLoading = false;
2167
2170
  this.render();
2168
2171
  this.setupEventListeners();
2169
- this.dispatchError(error.message || "Failed to create checkout session");
2172
+ this.dispatchError(error instanceof Error ? error.message : "Failed to create checkout session");
2170
2173
  }
2171
2174
  });
2172
2175
  this.attachShadow({ mode: "open" });
@@ -2614,7 +2617,7 @@ var init_portal_button = __esm({
2614
2617
  this._isLoading = false;
2615
2618
  this.render();
2616
2619
  this.setupEventListeners();
2617
- this.dispatchError(error.message || "Failed to create portal session");
2620
+ this.dispatchError(error instanceof Error ? error.message : "Failed to create portal session");
2618
2621
  }
2619
2622
  }
2620
2623
  dispatchError(message) {
@@ -2733,7 +2736,7 @@ function toCamelCase(obj) {
2733
2736
 
2734
2737
  // package.json
2735
2738
  var package_default = {
2736
- version: "0.12.0"};
2739
+ version: "0.13.0"};
2737
2740
  var SDK_VERSION = package_default.version;
2738
2741
  var SDK_TYPE = "react";
2739
2742
  var RecurContext = createContext(null);
@@ -2759,7 +2762,7 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
2759
2762
  checkoutMode: "embedded",
2760
2763
  ...initialConfig
2761
2764
  });
2762
- }, [initialConfig.checkoutMode, initialConfig.publishableKey, initialConfig.containerElementId]);
2765
+ }, [initialConfig]);
2763
2766
  React.useEffect(() => {
2764
2767
  setIsCheckingOut(false);
2765
2768
  }, [config.checkoutMode]);
@@ -3257,9 +3260,10 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
3257
3260
  paymentForm.resetButton?.();
3258
3261
  return;
3259
3262
  } else {
3263
+ const failureMessage = failureError.details && !Array.isArray(failureError.details) ? failureError.details.failure_message : void 0;
3260
3264
  paymentForm.showError?.({
3261
3265
  title: "\u4ED8\u6B3E\u5931\u6557",
3262
- message: failureError.details?.failure_message || failureError.message
3266
+ message: failureMessage || failureError.message
3263
3267
  });
3264
3268
  paymentForm.resetButton?.();
3265
3269
  return;
@@ -3386,7 +3390,8 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
3386
3390
  }
3387
3391
  }
3388
3392
  } catch (pollError) {
3389
- if (pollError.message === "3D \u9A57\u8B49\u5DF2\u53D6\u6D88" || pollError.message === "\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88") {
3393
+ const errorMessage = pollError instanceof Error ? pollError.message : String(pollError);
3394
+ if (errorMessage === "3D \u9A57\u8B49\u5DF2\u53D6\u6D88" || errorMessage === "\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88") {
3390
3395
  throw pollError;
3391
3396
  }
3392
3397
  console.error("[Recur SDK] Poll error:", pollError);
@@ -3448,7 +3453,7 @@ function RecurProvider({ children, config: initialConfig = {}, customer: custome
3448
3453
  currentPeriodEnd: paymentResult.subscription.currentPeriodEnd
3449
3454
  });
3450
3455
  } else {
3451
- const chargeId = paymentResult.charge?.id || paymentResult.paymentIntent?.id;
3456
+ const chargeId = paymentResult.charge?.id || paymentResult.paymentIntent?.id || checkoutResult.checkout.id;
3452
3457
  const chargeStatus = paymentResult.charge?.status || "SUCCEEDED";
3453
3458
  options.onPaymentComplete({
3454
3459
  id: chargeId,
package/dist/recur.umd.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var RecurCheckout=(()=>{var te=Object.defineProperty;var vt=Object.getOwnPropertyDescriptor;var kt=Object.getOwnPropertyNames;var wt=Object.prototype.hasOwnProperty;var xt=(n,e,t)=>e in n?te(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var w=(n,e)=>()=>(n&&(e=n(n=0)),e);var E=(n,e)=>{for(var t in e)te(n,t,{get:e[t],enumerable:!0})},_t=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of kt(e))!wt.call(n,o)&&o!==t&&te(n,o,{get:()=>e[o],enumerable:!(r=vt(e,o))||r.enumerable});return n};var Ct=n=>_t(te({},"__esModule",{value:!0}),n);var l=(n,e,t)=>xt(n,typeof e!="symbol"?e+"":e,t);var De={};E(De,{RecurLoadingSpinner:()=>re});var re,Pe=w(()=>{"use strict";re=class extends HTMLElement{static get observedAttributes(){return["message","size"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get message(){return this.getAttribute("message")||"\u6B63\u5728\u8655\u7406\u8A02\u95B1..."}get size(){let e=this.getAttribute("size");return e==="small"||e==="large"?e:"medium"}getSizeValue(){return{small:24,medium:40,large:56}[this.size]}render(){let e=this.getSizeValue();this.shadowRoot.innerHTML=`
1
+ "use strict";var RecurCheckout=(()=>{var te=Object.defineProperty;var vt=Object.getOwnPropertyDescriptor;var kt=Object.getOwnPropertyNames;var wt=Object.prototype.hasOwnProperty;var xt=(n,e,t)=>e in n?te(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var w=(n,e)=>()=>(n&&(e=n(n=0)),e);var C=(n,e)=>{for(var t in e)te(n,t,{get:e[t],enumerable:!0})},_t=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of kt(e))!wt.call(n,o)&&o!==t&&te(n,o,{get:()=>e[o],enumerable:!(r=vt(e,o))||r.enumerable});return n};var Et=n=>_t(te({},"__esModule",{value:!0}),n);var l=(n,e,t)=>xt(n,typeof e!="symbol"?e+"":e,t);var Pe={};C(Pe,{RecurLoadingSpinner:()=>re});var re,De=w(()=>{"use strict";re=class extends HTMLElement{static get observedAttributes(){return["message","size"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get message(){return this.getAttribute("message")||"\u6B63\u5728\u8655\u7406\u8A02\u95B1..."}get size(){let e=this.getAttribute("size");return e==="small"||e==="large"?e:"medium"}getSizeValue(){return{small:24,medium:40,large:56}[this.size]}render(){let e=this.getSizeValue();this.shadowRoot.innerHTML=`
2
2
  <style>
3
3
  :host {
4
4
  display: block;
@@ -40,7 +40,7 @@
40
40
 
41
41
  <div class="recur-sdk__spinner"></div>
42
42
  ${this.message?`<p class="recur-sdk__loading-text">${this.message}</p>`:""}
43
- `}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",re)});var Le={};E(Le,{RecurSuccessMessage:()=>oe});var oe,Me=w(()=>{"use strict";oe=class extends HTMLElement{static get observedAttributes(){return["title","message","icon"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get successTitle(){return this.getAttribute("title")||"Subscription Complete!"}get successMessage(){return this.getAttribute("message")||"Thank you for subscribing. Your payment has been processed successfully."}get showIcon(){return this.getAttribute("icon")!=="false"}render(){this.shadowRoot.innerHTML=`
43
+ `}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",re)});var Me={};C(Me,{RecurSuccessMessage:()=>oe});var oe,Le=w(()=>{"use strict";oe=class extends HTMLElement{static get observedAttributes(){return["title","message","icon"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get successTitle(){return this.getAttribute("title")||"Subscription Complete!"}get successMessage(){return this.getAttribute("message")||"Thank you for subscribing. Your payment has been processed successfully."}get showIcon(){return this.getAttribute("icon")!=="false"}render(){this.shadowRoot.innerHTML=`
44
44
  <style>
45
45
  :host {
46
46
  display: block;
@@ -121,7 +121,7 @@
121
121
  <p class="recur-sdk__success-message">${this.successMessage}</p>
122
122
  <slot></slot>
123
123
  </div>
124
- `}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",oe)});var Ue={};E(Ue,{RecurErrorDisplay:()=>ie});var ie,He=w(()=>{"use strict";ie=class extends HTMLElement{static get observedAttributes(){return["error","error-title","dismissible"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get error(){return this.getAttribute("error")||""}get errorTitle(){return this.getAttribute("error-title")||""}get isDismissible(){return this.getAttribute("dismissible")==="true"}handleDismiss(){this.dispatchEvent(new CustomEvent("dismiss",{bubbles:!0,composed:!0})),this.remove()}render(){if(!this.error){this.shadowRoot.innerHTML="";return}this.shadowRoot.innerHTML=`
124
+ `}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",oe)});var Ue={};C(Ue,{RecurErrorDisplay:()=>ie});var ie,He=w(()=>{"use strict";ie=class extends HTMLElement{static get observedAttributes(){return["error","error-title","dismissible"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get error(){return this.getAttribute("error")||""}get errorTitle(){return this.getAttribute("error-title")||""}get isDismissible(){return this.getAttribute("dismissible")==="true"}handleDismiss(){this.dispatchEvent(new CustomEvent("dismiss",{bubbles:!0,composed:!0})),this.remove()}render(){if(!this.error){this.shadowRoot.innerHTML="";return}this.shadowRoot.innerHTML=`
125
125
  <style>
126
126
  :host {
127
127
  display: block;
@@ -220,7 +220,7 @@
220
220
  </button>
221
221
  `:""}
222
222
  </div>
223
- `,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",ie)});var Be={};E(Be,{RecurSkeletonLoader:()=>se});var se,ze=w(()=>{"use strict";se=class extends HTMLElement{static get observedAttributes(){return["type"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get type(){let e=this.getAttribute("type");return e==="list"||e==="card"?e:"payment-form"}renderPaymentFormSkeleton(){return`
223
+ `,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",ie)});var Be={};C(Be,{RecurSkeletonLoader:()=>se});var se,Ne=w(()=>{"use strict";se=class extends HTMLElement{static get observedAttributes(){return["type"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get type(){let e=this.getAttribute("type");return e==="list"||e==="card"?e:"payment-form"}renderPaymentFormSkeleton(){return`
224
224
  <div class="skeleton-field">
225
225
  <div class="skeleton-label"></div>
226
226
  <div class="skeleton-input"></div>
@@ -391,9 +391,9 @@
391
391
  </style>
392
392
 
393
393
  ${e}
394
- `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",se)});function Xe(n,e){if(!Ce(n)||!n.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ne!==void 0?Ne.createHTML(e):e}function H(n,e,t=n,r){if(e===Y)return e;let o=r!==void 0?t._$Co?.[r]:t._$Cl,i=q(e)?void 0:e._$litDirective$;return o?.constructor!==i&&(o?._$AO?.(!1),i===void 0?o=void 0:(o=new i(n),o._$AT(n,t,r)),r!==void 0?(t._$Co??(t._$Co=[]))[r]=o:t._$Cl=o),o!==void 0&&(e=H(n,o._$AS(n,e.values),o,r)),e}var U,ne,Ne,qe,I,Ye,Et,L,V,q,Ce,St,ye,F,Oe,Ke,D,je,Fe,We,Ee,p,Yt,Wt,Y,f,Ve,P,Tt,W,ve,X,B,ke,we,xe,_e,$t,J,Se=w(()=>{"use strict";U=globalThis,ne=U.trustedTypes,Ne=ne?ne.createPolicy("lit-html",{createHTML:n=>n}):void 0,qe="$lit$",I=`lit$${Math.random().toFixed(9).slice(2)}$`,Ye="?"+I,Et=`<${Ye}>`,L=U.document===void 0?{createTreeWalker:()=>({})}:document,V=()=>L.createComment(""),q=n=>n===null||typeof n!="object"&&typeof n!="function",Ce=Array.isArray,St=n=>Ce(n)||typeof n?.[Symbol.iterator]=="function",ye=`[
394
+ `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",se)});function Xe(n,e){if(!Ee(n)||!n.hasOwnProperty("raw"))throw Error("invalid template strings array");return ze!==void 0?ze.createHTML(e):e}function B(n,e,t=n,r){if(e===Y)return e;let o=r!==void 0?t._$Co?.[r]:t._$Cl,i=q(e)?void 0:e._$litDirective$;return o?.constructor!==i&&(o?._$AO?.(!1),i===void 0?o=void 0:(o=new i(n),o._$AT(n,t,r)),r!==void 0?(t._$Co??(t._$Co=[]))[r]=o:t._$Cl=o),o!==void 0&&(e=B(n,o._$AS(n,e.values),o,r)),e}var H,ne,ze,qe,A,Ye,Ct,L,V,q,Ee,St,ye,F,Oe,Ke,D,je,Fe,We,Ce,p,Yt,Wt,Y,f,Ve,M,Tt,W,ve,X,N,ke,we,xe,_e,$t,J,Se=w(()=>{"use strict";H=globalThis,ne=H.trustedTypes,ze=ne?ne.createPolicy("lit-html",{createHTML:n=>n}):void 0,qe="$lit$",A=`lit$${Math.random().toFixed(9).slice(2)}$`,Ye="?"+A,Ct=`<${Ye}>`,L=H.document===void 0?{createTreeWalker:()=>({})}:document,V=()=>L.createComment(""),q=n=>n===null||typeof n!="object"&&typeof n!="function",Ee=Array.isArray,St=n=>Ee(n)||typeof n?.[Symbol.iterator]=="function",ye=`[
395
395
  \f\r]`,F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Oe=/-->/g,Ke=/>/g,D=RegExp(`>|${ye}(?:([^\\s"'>=/]+)(${ye}*=${ye}*(?:[^
396
- \f\r"'\`<>=]|("|')|))|$)`,"g"),je=/'/g,Fe=/"/g,We=/^(?:script|style|textarea|title)$/i,Ee=n=>(e,...t)=>({_$litType$:n,strings:e,values:t}),p=Ee(1),Yt=Ee(2),Wt=Ee(3),Y=Symbol.for("lit-noChange"),f=Symbol.for("lit-nothing"),Ve=new WeakMap,P=L.createTreeWalker(L,129);Tt=(n,e)=>{let t=n.length-1,r=[],o,i=e===2?"<svg>":e===3?"<math>":"",s=F;for(let a=0;a<t;a++){let c=n[a],d,h,m=-1,x=0;for(;x<c.length&&(s.lastIndex=x,h=s.exec(c),h!==null);)x=s.lastIndex,s===F?h[1]==="!--"?s=Oe:h[1]!==void 0?s=Ke:h[2]!==void 0?(We.test(h[2])&&(o=RegExp("</"+h[2],"g")),s=D):h[3]!==void 0&&(s=D):s===D?h[0]===">"?(s=o??F,m=-1):h[1]===void 0?m=-2:(m=s.lastIndex-h[2].length,d=h[1],s=h[3]===void 0?D:h[3]==='"'?Fe:je):s===Fe||s===je?s=D:s===Oe||s===Ke?s=F:(s=D,o=void 0);let u=s===D&&n[a+1].startsWith("/>")?" ":"";i+=s===F?c+Et:m>=0?(r.push(d),c.slice(0,m)+qe+c.slice(m)+I+u):c+I+(m===-2?a:u)}return[Xe(n,i+(n[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},W=class n{constructor({strings:e,_$litType$:t},r){let o;this.parts=[];let i=0,s=0,a=e.length-1,c=this.parts,[d,h]=Tt(e,t);if(this.el=n.createElement(d,r),P.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes)}for(;(o=P.nextNode())!==null&&c.length<a;){if(o.nodeType===1){if(o.hasAttributes())for(let m of o.getAttributeNames())if(m.endsWith(qe)){let x=h[s++],u=o.getAttribute(m).split(I),T=/([.?@])?(.*)/.exec(x);c.push({type:1,index:i,name:T[2],strings:u,ctor:T[1]==="."?ke:T[1]==="?"?we:T[1]==="@"?xe:B}),o.removeAttribute(m)}else m.startsWith(I)&&(c.push({type:6,index:i}),o.removeAttribute(m));if(We.test(o.tagName)){let m=o.textContent.split(I),x=m.length-1;if(x>0){o.textContent=ne?ne.emptyScript:"";for(let u=0;u<x;u++)o.append(m[u],V()),P.nextNode(),c.push({type:2,index:++i});o.append(m[x],V())}}}else if(o.nodeType===8)if(o.data===Ye)c.push({type:2,index:i});else{let m=-1;for(;(m=o.data.indexOf(I,m+1))!==-1;)c.push({type:7,index:i}),m+=I.length-1}i++}}static createElement(e,t){let r=L.createElement("template");return r.innerHTML=e,r}};ve=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:r}=this._$AD,o=(e?.creationScope??L).importNode(t,!0);P.currentNode=o;let i=P.nextNode(),s=0,a=0,c=r[0];for(;c!==void 0;){if(s===c.index){let d;c.type===2?d=new X(i,i.nextSibling,this,e):c.type===1?d=new c.ctor(i,c.name,c.strings,this,e):c.type===6&&(d=new _e(i,this,e)),this._$AV.push(d),c=r[++a]}s!==c?.index&&(i=P.nextNode(),s++)}return P.currentNode=L,o}p(e){let t=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}},X=class n{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,o){this.type=2,this._$AH=f,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=o,this._$Cv=o?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=H(this,e,t),q(e)?e===f||e==null||e===""?(this._$AH!==f&&this._$AR(),this._$AH=f):e!==this._$AH&&e!==Y&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):St(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==f&&q(this._$AH)?this._$AA.nextSibling.data=e:this.T(L.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:r}=e,o=typeof r=="number"?this._$AC(e):(r.el===void 0&&(r.el=W.createElement(Xe(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===o)this._$AH.p(t);else{let i=new ve(o,this),s=i.u(this.options);i.p(t),this.T(s),this._$AH=i}}_$AC(e){let t=Ve.get(e.strings);return t===void 0&&Ve.set(e.strings,t=new W(e)),t}k(e){Ce(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,r,o=0;for(let i of e)o===t.length?t.push(r=new n(this.O(V()),this.O(V()),this,this.options)):r=t[o],r._$AI(i),o++;o<t.length&&(this._$AR(r&&r._$AB.nextSibling,o),t.length=o)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let r=e.nextSibling;e.remove(),e=r}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},B=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,o,i){this.type=1,this._$AH=f,this._$AN=void 0,this.element=e,this.name=t,this._$AM=o,this.options=i,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=f}_$AI(e,t=this,r,o){let i=this.strings,s=!1;if(i===void 0)e=H(this,e,t,0),s=!q(e)||e!==this._$AH&&e!==Y,s&&(this._$AH=e);else{let a=e,c,d;for(e=i[0],c=0;c<i.length-1;c++)d=H(this,a[r+c],t,c),d===Y&&(d=this._$AH[c]),s||(s=!q(d)||d!==this._$AH[c]),d===f?e=f:e!==f&&(e+=(d??"")+i[c+1]),this._$AH[c]=d}s&&!o&&this.j(e)}j(e){e===f?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},ke=class extends B{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===f?void 0:e}},we=class extends B{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==f)}},xe=class extends B{constructor(e,t,r,o,i){super(e,t,r,o,i),this.type=5}_$AI(e,t=this){if((e=H(this,e,t,0)??f)===Y)return;let r=this._$AH,o=e===f&&r!==f||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,i=e!==f&&(r===f||o);o&&this.element.removeEventListener(this.name,this,r),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},_e=class{constructor(e,t,r){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(e){H(this,e)}},$t=U.litHtmlPolyfillSupport;$t?.(W,X),(U.litHtmlVersions??(U.litHtmlVersions=[])).push("3.3.1");J=(n,e,t)=>{let r=t?.renderBefore??e,o=r._$litPart$;if(o===void 0){let i=t?.renderBefore??null;r._$litPart$=o=new X(e.insertBefore(V(),i),i,void 0,t??{})}return o._$AI(n),o}});var Ge,Je=w(()=>{Ge=`/**
396
+ \f\r"'\`<>=]|("|')|))|$)`,"g"),je=/'/g,Fe=/"/g,We=/^(?:script|style|textarea|title)$/i,Ce=n=>(e,...t)=>({_$litType$:n,strings:e,values:t}),p=Ce(1),Yt=Ce(2),Wt=Ce(3),Y=Symbol.for("lit-noChange"),f=Symbol.for("lit-nothing"),Ve=new WeakMap,M=L.createTreeWalker(L,129);Tt=(n,e)=>{let t=n.length-1,r=[],o,i=e===2?"<svg>":e===3?"<math>":"",s=F;for(let a=0;a<t;a++){let c=n[a],d,h,m=-1,x=0;for(;x<c.length&&(s.lastIndex=x,h=s.exec(c),h!==null);)x=s.lastIndex,s===F?h[1]==="!--"?s=Oe:h[1]!==void 0?s=Ke:h[2]!==void 0?(We.test(h[2])&&(o=RegExp("</"+h[2],"g")),s=D):h[3]!==void 0&&(s=D):s===D?h[0]===">"?(s=o??F,m=-1):h[1]===void 0?m=-2:(m=s.lastIndex-h[2].length,d=h[1],s=h[3]===void 0?D:h[3]==='"'?Fe:je):s===Fe||s===je?s=D:s===Oe||s===Ke?s=F:(s=D,o=void 0);let u=s===D&&n[a+1].startsWith("/>")?" ":"";i+=s===F?c+Ct:m>=0?(r.push(d),c.slice(0,m)+qe+c.slice(m)+A+u):c+A+(m===-2?a:u)}return[Xe(n,i+(n[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),r]},W=class n{constructor({strings:e,_$litType$:t},r){let o;this.parts=[];let i=0,s=0,a=e.length-1,c=this.parts,[d,h]=Tt(e,t);if(this.el=n.createElement(d,r),M.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes)}for(;(o=M.nextNode())!==null&&c.length<a;){if(o.nodeType===1){if(o.hasAttributes())for(let m of o.getAttributeNames())if(m.endsWith(qe)){let x=h[s++],u=o.getAttribute(m).split(A),T=/([.?@])?(.*)/.exec(x);c.push({type:1,index:i,name:T[2],strings:u,ctor:T[1]==="."?ke:T[1]==="?"?we:T[1]==="@"?xe:N}),o.removeAttribute(m)}else m.startsWith(A)&&(c.push({type:6,index:i}),o.removeAttribute(m));if(We.test(o.tagName)){let m=o.textContent.split(A),x=m.length-1;if(x>0){o.textContent=ne?ne.emptyScript:"";for(let u=0;u<x;u++)o.append(m[u],V()),M.nextNode(),c.push({type:2,index:++i});o.append(m[x],V())}}}else if(o.nodeType===8)if(o.data===Ye)c.push({type:2,index:i});else{let m=-1;for(;(m=o.data.indexOf(A,m+1))!==-1;)c.push({type:7,index:i}),m+=A.length-1}i++}}static createElement(e,t){let r=L.createElement("template");return r.innerHTML=e,r}};ve=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:r}=this._$AD,o=(e?.creationScope??L).importNode(t,!0);M.currentNode=o;let i=M.nextNode(),s=0,a=0,c=r[0];for(;c!==void 0;){if(s===c.index){let d;c.type===2?d=new X(i,i.nextSibling,this,e):c.type===1?d=new c.ctor(i,c.name,c.strings,this,e):c.type===6&&(d=new _e(i,this,e)),this._$AV.push(d),c=r[++a]}s!==c?.index&&(i=M.nextNode(),s++)}return M.currentNode=L,o}p(e){let t=0;for(let r of this._$AV)r!==void 0&&(r.strings!==void 0?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}},X=class n{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,o){this.type=2,this._$AH=f,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=o,this._$Cv=o?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=B(this,e,t),q(e)?e===f||e==null||e===""?(this._$AH!==f&&this._$AR(),this._$AH=f):e!==this._$AH&&e!==Y&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):St(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==f&&q(this._$AH)?this._$AA.nextSibling.data=e:this.T(L.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:r}=e,o=typeof r=="number"?this._$AC(e):(r.el===void 0&&(r.el=W.createElement(Xe(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===o)this._$AH.p(t);else{let i=new ve(o,this),s=i.u(this.options);i.p(t),this.T(s),this._$AH=i}}_$AC(e){let t=Ve.get(e.strings);return t===void 0&&Ve.set(e.strings,t=new W(e)),t}k(e){Ee(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,r,o=0;for(let i of e)o===t.length?t.push(r=new n(this.O(V()),this.O(V()),this,this.options)):r=t[o],r._$AI(i),o++;o<t.length&&(this._$AR(r&&r._$AB.nextSibling,o),t.length=o)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let r=e.nextSibling;e.remove(),e=r}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},N=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,o,i){this.type=1,this._$AH=f,this._$AN=void 0,this.element=e,this.name=t,this._$AM=o,this.options=i,r.length>2||r[0]!==""||r[1]!==""?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=f}_$AI(e,t=this,r,o){let i=this.strings,s=!1;if(i===void 0)e=B(this,e,t,0),s=!q(e)||e!==this._$AH&&e!==Y,s&&(this._$AH=e);else{let a=e,c,d;for(e=i[0],c=0;c<i.length-1;c++)d=B(this,a[r+c],t,c),d===Y&&(d=this._$AH[c]),s||(s=!q(d)||d!==this._$AH[c]),d===f?e=f:e!==f&&(e+=(d??"")+i[c+1]),this._$AH[c]=d}s&&!o&&this.j(e)}j(e){e===f?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},ke=class extends N{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===f?void 0:e}},we=class extends N{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==f)}},xe=class extends N{constructor(e,t,r,o,i){super(e,t,r,o,i),this.type=5}_$AI(e,t=this){if((e=B(this,e,t,0)??f)===Y)return;let r=this._$AH,o=e===f&&r!==f||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,i=e!==f&&(r===f||o);o&&this.element.removeEventListener(this.name,this,r),i&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},_e=class{constructor(e,t,r){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(e){B(this,e)}},$t=H.litHtmlPolyfillSupport;$t?.(W,X),(H.litHtmlVersions??(H.litHtmlVersions=[])).push("3.3.1");J=(n,e,t)=>{let r=t?.renderBefore??e,o=r._$litPart$;if(o===void 0){let i=t?.renderBefore??null;r._$litPart$=o=new X(e.insertBefore(V(),i),i,void 0,t??{})}return o._$AI(n),o}});var Ge,Je=w(()=>{Ge=`/**
397
397
  * Payment Form Skeleton - Shadow DOM Styles
398
398
  * Loading skeleton that matches the structure of RecurPaymentForm
399
399
  */
@@ -605,7 +605,7 @@
605
605
  color: #4a5568;
606
606
  margin: 0;
607
607
  }
608
- `});var Ze={};E(Ze,{RecurPaymentFormSkeleton:()=>ae});var At,ae,Qe=w(()=>{"use strict";Se();Je();At=p`
608
+ `});var Ze={};C(Ze,{RecurPaymentFormSkeleton:()=>ae});var At,ae,Qe=w(()=>{"use strict";Se();Je();At=p`
609
609
  <svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
610
610
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
611
611
  </svg>
@@ -682,13 +682,13 @@
682
682
  ${this.renderSubmitButton()}
683
683
  ${this.renderSecurityNote()}
684
684
  </div>
685
- `;J(e,this.shadowRoot)}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",ae)});var et={};E(et,{RecurToast:()=>ce,RecurToastContainer:()=>G});var ce,S,G,tt=w(()=>{"use strict";ce=class extends HTMLElement{static get observedAttributes(){return["message","type","duration"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupAutoDismiss()}get message(){return this.getAttribute("message")||"Notification"}get type(){let e=this.getAttribute("type");return e==="success"||e==="error"?e:"info"}get duration(){let e=this.getAttribute("duration");return e?parseInt(e,10):5e3}setupAutoDismiss(){let e=this.duration;e>0&&setTimeout(()=>this.dismiss(),e)}dismiss(){this.style.animation="recur-toast-slide-out 0.3s ease-in-out",setTimeout(()=>this.remove(),300)}getTypeIcon(){switch(this.type){case"success":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
685
+ `;J(e,this.shadowRoot)}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",ae)});var et={};C(et,{RecurToast:()=>ce,RecurToastContainer:()=>G});var ce,S,G,tt=w(()=>{"use strict";ce=class extends HTMLElement{static get observedAttributes(){return["message","type","duration"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupAutoDismiss()}get message(){return this.getAttribute("message")||"Notification"}get type(){let e=this.getAttribute("type");return e==="success"||e==="error"?e:"info"}get duration(){let e=this.getAttribute("duration");return e?parseInt(e,10):5e3}setupAutoDismiss(){let e=this.duration;e>0&&setTimeout(()=>this.dismiss(),e)}dismiss(){this.style.animation="recur-toast-slide-out 0.3s ease-in-out",setTimeout(()=>this.remove(),300)}getTypeIcon(){switch(this.type){case"success":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
686
686
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
687
687
  </svg>`;case"error":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
688
688
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
689
- </svg>`;case"info":default:return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
689
+ </svg>`;default:return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
690
690
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
691
- </svg>`}}getTypeColor(){switch(this.type){case"success":return"#10b981";case"error":return"#ef4444";case"info":default:return"#3b82f6"}}render(){let e=this.getTypeColor();this.shadowRoot.innerHTML=`
691
+ </svg>`}}getTypeColor(){switch(this.type){case"success":return"#10b981";case"error":return"#ef4444";default:return"#3b82f6"}}render(){let e=this.getTypeColor();this.shadowRoot.innerHTML=`
692
692
  <style>
693
693
  :host {
694
694
  display: block;
@@ -1515,7 +1515,7 @@
1515
1515
  .recur-test-card-meta {
1516
1516
  color: #9ca3af;
1517
1517
  }
1518
- `});var nt={};E(nt,{RecurPaymentForm:()=>le});var M,le,at=w(()=>{"use strict";Se();rt();it();M={lock:p`
1518
+ `});var nt={};C(nt,{RecurPaymentForm:()=>le});var U,le,at=w(()=>{"use strict";Se();rt();it();U={lock:p`
1519
1519
  <svg class="security-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1520
1520
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
1521
1521
  </svg>
@@ -1535,7 +1535,7 @@
1535
1535
  <svg class="recur-coupon__clear-icon" width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1536
1536
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
1537
1537
  </svg>
1538
- `,spinner:p`<span class="recur-coupon__spinner"></span>`},le=class extends HTMLElement{constructor(){super();l(this,"containerId");l(this,"customStyles");l(this,"_isInitializing",!1);l(this,"_initializationAborted",!1);l(this,"_showTestCardHints",!1);l(this,"_showCouponInput",!1);l(this,"_couponCode","");l(this,"_couponLoading",!1);l(this,"_couponError",null);l(this,"_appliedCoupon",null);this.containerId=this.getAttribute("container-id")||`recur-${Date.now()}`,this.customStyles=this.getAttribute("custom-styles")||"",this.attachShadow({mode:"open"})}connectedCallback(){this.render()}disconnectedCallback(){console.log("[PaymentForm] Component disconnected, cleaning up..."),this._initializationAborted=!0,this._paymentSession=null;let t=document.getElementById(`${this.containerId}-submit-btn`);if(t){let r=t.cloneNode(!0);t.parentNode?.replaceChild(r,t)}}static get observedAttributes(){return["custom-styles","customer-name","customer-email","product-name","amount","interval","checkout-id","publishable-key","api-base-url"]}attributeChangedCallback(t,r,o){r!==o&&(t==="custom-styles"?(this.customStyles=o||"",this.updateCustomStyles()):this.updateOrderSummaryDOM())}getShadowDOMStyles(){return ot}getLightDOMStyles(){return st}render(){this.renderShadowDOM(),this.renderLightDOM()}renderShadowDOM(){let t=p`
1538
+ `,spinner:p`<span class="recur-coupon__spinner"></span>`},le=class extends HTMLElement{constructor(){super();l(this,"containerId");l(this,"customStyles");l(this,"_isInitializing",!1);l(this,"_initializationAborted",!1);l(this,"_paymentSession",null);l(this,"_showTestCardHints",!1);l(this,"_showCouponInput",!1);l(this,"_couponCode","");l(this,"_couponLoading",!1);l(this,"_couponError",null);l(this,"_appliedCoupon",null);this.containerId=this.getAttribute("container-id")||`recur-${Date.now()}`,this.customStyles=this.getAttribute("custom-styles")||"",this.attachShadow({mode:"open"})}connectedCallback(){this.render()}disconnectedCallback(){console.log("[PaymentForm] Component disconnected, cleaning up..."),this._initializationAborted=!0,this._paymentSession=null;let t=document.getElementById(`${this.containerId}-submit-btn`);if(t){let r=t.cloneNode(!0);t.parentNode?.replaceChild(r,t)}}static get observedAttributes(){return["custom-styles","customer-name","customer-email","product-name","amount","interval","checkout-id","publishable-key","api-base-url"]}attributeChangedCallback(t,r,o){r!==o&&(t==="custom-styles"?(this.customStyles=o||"",this.updateCustomStyles()):this.updateOrderSummaryDOM())}getShadowDOMStyles(){return ot}getLightDOMStyles(){return st}render(){this.renderShadowDOM(),this.renderLightDOM()}renderShadowDOM(){let t=p`
1539
1539
  <style>${this.getShadowDOMStyles()}</style>
1540
1540
 
1541
1541
  <div class="payment-form-wrapper">
@@ -1563,7 +1563,7 @@
1563
1563
  <slot name="actions"></slot>
1564
1564
 
1565
1565
  <div class="security-note">
1566
- ${M.lock}
1566
+ ${U.lock}
1567
1567
  <p class="security-text">您的付款資訊經過加密保護</p>
1568
1568
  </div>
1569
1569
  </div>
@@ -1670,7 +1670,7 @@
1670
1670
  <div class="recur-coupon__applied-wrapper">
1671
1671
  <div class="recur-coupon__applied">
1672
1672
  <div class="recur-coupon__applied-info">
1673
- ${M.tagApplied}
1673
+ ${U.tagApplied}
1674
1674
  ${this._appliedCoupon.couponName?p`
1675
1675
  <span class="recur-coupon__applied-name">${this._appliedCoupon.couponName}</span>
1676
1676
  <span class="recur-coupon__applied-code">(${this._appliedCoupon.code})</span>
@@ -1683,7 +1683,7 @@
1683
1683
  ?disabled=${this._couponLoading}
1684
1684
  @click=${()=>this.removeCoupon()}
1685
1685
  >
1686
- ${this._couponLoading?M.spinner:M.close}
1686
+ ${this._couponLoading?U.spinner:U.close}
1687
1687
  </button>
1688
1688
  </div>
1689
1689
  <span class="recur-coupon__applied-amount">
@@ -1721,7 +1721,7 @@
1721
1721
  @click=${()=>this.clearCouponInput()}
1722
1722
  aria-label="清除"
1723
1723
  >
1724
- ${M.clearInput}
1724
+ ${U.clearInput}
1725
1725
  </button>
1726
1726
  `:f}
1727
1727
  </div>
@@ -1731,7 +1731,7 @@
1731
1731
  ?disabled=${this._couponLoading||!this._couponCode.trim()}
1732
1732
  @click=${()=>this.applyCoupon()}
1733
1733
  >
1734
- ${this._couponLoading?M.spinner:"\u5957\u7528"}
1734
+ ${this._couponLoading?U.spinner:"\u5957\u7528"}
1735
1735
  </button>
1736
1736
  </div>
1737
1737
  ${this._couponError?p`
@@ -1744,7 +1744,7 @@
1744
1744
  class="recur-coupon__trigger"
1745
1745
  @click=${()=>this.showCouponInput()}
1746
1746
  >
1747
- ${M.tag}
1747
+ ${U.tag}
1748
1748
  有優惠碼?
1749
1749
  </button>
1750
1750
  `}showCouponInput(){this._showCouponInput=!0,this._couponError=null,this.updateCouponSectionDOM(),requestAnimationFrame(()=>{document.getElementById(`${this.containerId}-coupon-input`)?.focus()})}cancelCouponInput(){this._showCouponInput=!1,this._couponCode="",this._couponError=null,this.updateCouponSectionDOM()}clearCouponInput(){this._couponCode="",this._couponError=null,this.updateCouponSectionDOM(),requestAnimationFrame(()=>{document.getElementById(`${this.containerId}-coupon-input`)?.focus()})}handleCouponInputChange(t){this._couponCode=t.target.value.toUpperCase(),this._couponError=null,this.updateApplyButtonState()}handleCouponKeydown(t){t.key==="Enter"?(t.preventDefault(),this.applyCoupon()):t.key==="Escape"&&this.cancelCouponInput()}updateApplyButtonState(){let t=this.querySelector(".recur-coupon__btn--apply");t&&(t.disabled=this._couponLoading||!this._couponCode.trim())}updateCouponSectionDOM(){let t=`${this.containerId}-coupon`,r=document.getElementById(t);r&&(this._appliedCoupon?(r.innerHTML=this.getCouponAppliedHTML(),this.bindCouponAppliedEvents(r)):this._showCouponInput?(r.innerHTML=this.getCouponInputHTML(),this.bindCouponInputEvents(r)):(r.innerHTML=this.getCouponTriggerHTML(),this.bindCouponTriggerEvents(r)))}getCouponTriggerHTML(){return`
@@ -1870,13 +1870,13 @@
1870
1870
  >
1871
1871
  <span id="${this.containerId}-submit-text">確認付款</span>
1872
1872
  </button>
1873
- `}async initializePayment(t,r){if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before start"),null;if(this._isInitializing=!0,await this.updateComplete(),this._initializationAborted)return console.log("[PaymentForm] Initialization aborted after updateComplete"),this._isInitializing=!1,null;if(!window.UniPayment)throw this._isInitializing=!1,new Error("PAYUNi SDK not loaded");try{let o=document.getElementById(`${this.containerId}-card-no`),i=document.getElementById(`${this.containerId}-card-exp`),s=document.getElementById(`${this.containerId}-card-cvc`);if(!o||!i||!s)return console.log("[PaymentForm] DOM elements not found, likely disconnected"),this._isInitializing=!1,null;if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before createSession"),this._isInitializing=!1,null;let a=window.UniPayment.createSession(t,{env:r==="SANDBOX"?"S":"P",elements:{CardNo:`${this.containerId}-card-no`,CardExp:`${this.containerId}-card-exp`,CardCvc:`${this.containerId}-card-cvc`}});if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before paymentSession.start()"),this._isInitializing=!1,null;try{await a.start()}catch(c){if((c?.message?.includes("1008")||c?.message?.includes("timeout")||c?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw c}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),a.onUpdate?.(c=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",c);let d=c.status&&c.status.CardNo===!0&&c.status.CardExp===!0&&c.status.CardCvc===!0,h=document.getElementById(`${this.containerId}-submit-btn`);h&&(h.disabled=!d,console.log("[PaymentForm] Submit button disabled:",!d))}),this._initializationAborted?(console.log("[PaymentForm] Initialization aborted before saving session"),this._isInitializing=!1,null):(this._paymentSession=a,this.setupFormSubmission(),this._isInitializing=!1,a))}catch(o){throw this._isInitializing=!1,console.error("[PaymentForm] Failed to initialize payment:",o),o}}setupFormSubmission(){let t=document.getElementById(`${this.containerId}-submit-btn`);t&&t.addEventListener("click",async r=>{if(r.preventDefault(),t.classList.contains("loading"))return;let o,i,s=document.getElementById(`${this.containerId}-email`),a=document.getElementById(`${this.containerId}-name`);if(s&&a){if(o=s.value,i=a.value,!o||!i){this.showError("\u8ACB\u586B\u5BEB\u59D3\u540D\u548C\u96FB\u5B50\u90F5\u4EF6");return}}else if(o=this.getAttribute("customer-email")||void 0,i=this.getAttribute("customer-name")||void 0,!o||!i){this.showError("\u5BA2\u6236\u8CC7\u8A0A\u4E0D\u5B8C\u6574");return}this.clearError(),this.setButtonLoading(!0),this.dispatchEvent(new CustomEvent("submit",{detail:{customerEmail:o,customerName:i,paymentSession:this._paymentSession,appliedCoupon:this._appliedCoupon},bubbles:!0,composed:!0}))})}setButtonLoading(t){let r=document.getElementById(`${this.containerId}-submit-btn`);r&&(t?(r.classList.add("loading"),r.disabled=!0,r.innerHTML=`
1873
+ `}async initializePayment(t,r){if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before start"),null;if(this._isInitializing=!0,await this.updateComplete(),this._initializationAborted)return console.log("[PaymentForm] Initialization aborted after updateComplete"),this._isInitializing=!1,null;if(!window.UniPayment)throw this._isInitializing=!1,new Error("PAYUNi SDK not loaded");try{let o=document.getElementById(`${this.containerId}-card-no`),i=document.getElementById(`${this.containerId}-card-exp`),s=document.getElementById(`${this.containerId}-card-cvc`);if(!o||!i||!s)return console.log("[PaymentForm] DOM elements not found, likely disconnected"),this._isInitializing=!1,null;if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before createSession"),this._isInitializing=!1,null;let a=window.UniPayment.createSession(t,{env:r==="SANDBOX"?"S":"P",elements:{CardNo:`${this.containerId}-card-no`,CardExp:`${this.containerId}-card-exp`,CardCvc:`${this.containerId}-card-cvc`}});if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before paymentSession.start()"),this._isInitializing=!1,null;try{await a.start()}catch(c){let d=c;if((d?.message?.includes("1008")||d?.message?.includes("timeout")||d?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw c}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),a.onUpdate?.(c=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",c);let d=c,h=d.status&&d.status.CardNo===!0&&d.status.CardExp===!0&&d.status.CardCvc===!0,m=document.getElementById(`${this.containerId}-submit-btn`);m&&(m.disabled=!h,console.log("[PaymentForm] Submit button disabled:",!h))}),this._initializationAborted?(console.log("[PaymentForm] Initialization aborted before saving session"),this._isInitializing=!1,null):(this._paymentSession=a,this.setupFormSubmission(),this._isInitializing=!1,a))}catch(o){throw this._isInitializing=!1,console.error("[PaymentForm] Failed to initialize payment:",o),o}}setupFormSubmission(){let t=document.getElementById(`${this.containerId}-submit-btn`);t&&t.addEventListener("click",async r=>{if(r.preventDefault(),t.classList.contains("loading"))return;let o,i,s=document.getElementById(`${this.containerId}-email`),a=document.getElementById(`${this.containerId}-name`);if(s&&a){if(o=s.value,i=a.value,!o||!i){this.showError("\u8ACB\u586B\u5BEB\u59D3\u540D\u548C\u96FB\u5B50\u90F5\u4EF6");return}}else if(o=this.getAttribute("customer-email")||void 0,i=this.getAttribute("customer-name")||void 0,!o||!i){this.showError("\u5BA2\u6236\u8CC7\u8A0A\u4E0D\u5B8C\u6574");return}this.clearError(),this.setButtonLoading(!0),this.dispatchEvent(new CustomEvent("submit",{detail:{customerEmail:o,customerName:i,paymentSession:this._paymentSession,appliedCoupon:this._appliedCoupon},bubbles:!0,composed:!0}))})}setButtonLoading(t){let r=document.getElementById(`${this.containerId}-submit-btn`);r&&(t?(r.classList.add("loading"),r.disabled=!0,r.innerHTML=`
1874
1874
  <span class="recur-loading-spinner"></span>
1875
1875
  <span>\u8655\u7406\u4E2D...</span>
1876
1876
  `):(r.classList.remove("loading"),r.disabled=!1,r.innerHTML='<span id="'+this.containerId+'-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>'))}resetButton(){this.setButtonLoading(!1)}setVerifying(t){let r=document.getElementById(`${this.containerId}-submit-btn`);r&&(t?(r.classList.add("loading"),r.disabled=!0,r.innerHTML=`
1877
1877
  <span class="recur-loading-spinner"></span>
1878
1878
  <span>3D \u9A57\u8B49\u4E2D...</span>
1879
- `):this.setButtonLoading(!1))}showError(t){let r=typeof t=="string"?t:t.message,o=typeof t=="object"?t.title:void 0,i=this.querySelector(".recur-sdk__error-container");i||(i=document.createElement("div"),i.className="recur-sdk__error-container",i.style.cssText="margin-bottom: 16px;",this.insertBefore(i,this.firstChild));let s=document.createElement("recur-error-display");s.setAttribute("error",r),o&&s.setAttribute("error-title",o),s.setAttribute("dismissible","true"),i.innerHTML="",i.appendChild(s),s.scrollIntoView({behavior:"smooth",block:"center"})}clearError(){let t=this.querySelector(".recur-sdk__error-container");t&&(t.innerHTML="")}updateComplete(){return new Promise(t=>{if(this.isConnected)setTimeout(t,0);else{let r=new MutationObserver(()=>{this.isConnected&&(r.disconnect(),setTimeout(t,0))});r.observe(document.body,{childList:!0,subtree:!0})}})}getFormData(){return{email:document.getElementById(`${this.containerId}-email`)?.value,name:document.getElementById(`${this.containerId}-name`)?.value}}setFormData(t){if(t.email){let r=document.getElementById(`${this.containerId}-email`);r&&(r.value=t.email)}if(t.name){let r=document.getElementById(`${this.containerId}-name`);r&&(r.value=t.name)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",le)});var ct={};E(ct,{RecurCheckoutButton:()=>de});var de,lt=w(()=>{"use strict";de=class extends HTMLElement{constructor(){super();l(this,"_isLoading",!1);l(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),o=this.getAttribute("product-id"),i=this.getAttribute("success-url"),s=this.getAttribute("cancel-url");if(!r){this.dispatchError("Missing required attribute: publishable-key");return}if(!o){this.dispatchError("Missing required attribute: product-id");return}if(!i){this.dispatchError("Missing required attribute: success-url");return}if(!s){this.dispatchError("Missing required attribute: cancel-url");return}this._isLoading=!0,this.render(),this.setupEventListeners();try{let a=await this.createCheckoutSession({publishableKey:r,productId:o,successUrl:this.resolveUrl(i),cancelUrl:this.resolveUrl(s),customerEmail:this.getAttribute("customer-email")||void 0,mode:this.getAttribute("mode")});this.dispatchEvent(new CustomEvent("checkout-started",{detail:{sessionId:a.id,url:a.url},bubbles:!0,composed:!0})),window.location.href=a.url}catch(a){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(a.message||"Failed to create checkout session")}});this.attachShadow({mode:"open"})}static get observedAttributes(){return["publishable-key","product-id","success-url","cancel-url","customer-email","mode","button-text","button-style","disabled"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,o){r!==o&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",o=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1879
+ `):this.setButtonLoading(!1))}showError(t){let r=typeof t=="string"?t:t.message,o=typeof t=="object"?t.title:void 0,i=this.querySelector(".recur-sdk__error-container");i||(i=document.createElement("div"),i.className="recur-sdk__error-container",i.style.cssText="margin-bottom: 16px;",this.insertBefore(i,this.firstChild));let s=document.createElement("recur-error-display");s.setAttribute("error",r),o&&s.setAttribute("error-title",o),s.setAttribute("dismissible","true"),i.innerHTML="",i.appendChild(s),s.scrollIntoView({behavior:"smooth",block:"center"})}clearError(){let t=this.querySelector(".recur-sdk__error-container");t&&(t.innerHTML="")}updateComplete(){return new Promise(t=>{if(this.isConnected)setTimeout(t,0);else{let r=new MutationObserver(()=>{this.isConnected&&(r.disconnect(),setTimeout(t,0))});r.observe(document.body,{childList:!0,subtree:!0})}})}getFormData(){return{email:document.getElementById(`${this.containerId}-email`)?.value,name:document.getElementById(`${this.containerId}-name`)?.value}}setFormData(t){if(t.email){let r=document.getElementById(`${this.containerId}-email`);r&&(r.value=t.email)}if(t.name){let r=document.getElementById(`${this.containerId}-name`);r&&(r.value=t.name)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",le)});var ct={};C(ct,{RecurCheckoutButton:()=>de});var de,lt=w(()=>{"use strict";de=class extends HTMLElement{constructor(){super();l(this,"_isLoading",!1);l(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),o=this.getAttribute("product-id"),i=this.getAttribute("success-url"),s=this.getAttribute("cancel-url");if(!r){this.dispatchError("Missing required attribute: publishable-key");return}if(!o){this.dispatchError("Missing required attribute: product-id");return}if(!i){this.dispatchError("Missing required attribute: success-url");return}if(!s){this.dispatchError("Missing required attribute: cancel-url");return}this._isLoading=!0,this.render(),this.setupEventListeners();try{let a=await this.createCheckoutSession({publishableKey:r,productId:o,successUrl:this.resolveUrl(i),cancelUrl:this.resolveUrl(s),customerEmail:this.getAttribute("customer-email")||void 0,mode:this.getAttribute("mode")});this.dispatchEvent(new CustomEvent("checkout-started",{detail:{sessionId:a.id,url:a.url},bubbles:!0,composed:!0})),window.location.href=a.url}catch(a){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(a instanceof Error?a.message:"Failed to create checkout session")}});this.attachShadow({mode:"open"})}static get observedAttributes(){return["publishable-key","product-id","success-url","cancel-url","customer-email","mode","button-text","button-style","disabled"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,o){r!==o&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",o=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1880
1880
  <style>
1881
1881
  :host {
1882
1882
  display: inline-block;
@@ -1975,7 +1975,7 @@
1975
1975
  ${this._isLoading?'<span class="spinner"></span>':""}
1976
1976
  <span>${this._isLoading?"\u8655\u7406\u4E2D...":t}</span>
1977
1977
  </button>
1978
- `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),o={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(o.mode=t.mode),t.customerEmail&&(o.customerEmail=t.customerEmail);let i=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(o)});if(!i.ok){let s=await i.json().catch(()=>({}));throw new Error(s.error?.message||`HTTP ${i.status}: Failed to create checkout session`)}return i.json()}getApiBaseUrl(){let t=this.getAttribute("api-base-url");if(t)return t;if(typeof window<"u"){let r=window.location.hostname;if(r==="localhost"||r.includes(".test")||r.includes(".local")||r==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}resolveUrl(t){return t.startsWith("/")?`${window.location.origin}${t}`:t}dispatchError(t){console.error("[recur-checkout]",t),this.dispatchEvent(new CustomEvent("checkout-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-checkout")&&customElements.define("recur-checkout",de)});var dt={};E(dt,{RecurPortalButton:()=>ue});var ue,ut=w(()=>{"use strict";ue=class extends HTMLElement{constructor(){super();l(this,"_isLoading",!1);l(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),o=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(o){await this.fetchAndRedirect(o);return}this.dispatchError("Missing required attribute: either portal-url or api-endpoint must be provided")});this.attachShadow({mode:"open"})}static get observedAttributes(){return["portal-url","api-endpoint","customer-id","return-url","button-text","button-style","disabled","target"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,o){r!==o&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",o=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1978
+ `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),o={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(o.mode=t.mode),t.customerEmail&&(o.customerEmail=t.customerEmail);let i=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(o)});if(!i.ok){let s=await i.json().catch(()=>({}));throw new Error(s.error?.message||`HTTP ${i.status}: Failed to create checkout session`)}return i.json()}getApiBaseUrl(){let t=this.getAttribute("api-base-url");if(t)return t;if(typeof window<"u"){let r=window.location.hostname;if(r==="localhost"||r.includes(".test")||r.includes(".local")||r==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}resolveUrl(t){return t.startsWith("/")?`${window.location.origin}${t}`:t}dispatchError(t){console.error("[recur-checkout]",t),this.dispatchEvent(new CustomEvent("checkout-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-checkout")&&customElements.define("recur-checkout",de)});var dt={};C(dt,{RecurPortalButton:()=>ue});var ue,ut=w(()=>{"use strict";ue=class extends HTMLElement{constructor(){super();l(this,"_isLoading",!1);l(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),o=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(o){await this.fetchAndRedirect(o);return}this.dispatchError("Missing required attribute: either portal-url or api-endpoint must be provided")});this.attachShadow({mode:"open"})}static get observedAttributes(){return["portal-url","api-endpoint","customer-id","return-url","button-text","button-style","disabled","target"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,o){r!==o&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",o=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1979
1979
  <style>
1980
1980
  :host {
1981
1981
  display: inline-block;
@@ -2102,7 +2102,7 @@
2102
2102
  <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
2103
2103
  <circle cx="12" cy="7" r="4"/>
2104
2104
  </svg>
2105
- `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),o=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),o&&(i.returnUrl=o);let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){let d=await s.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${s.status}: Failed to create portal session`)}let a=await s.json(),c=a.url||a.portalUrl;if(!c)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(c)}catch(i){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(i.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",ue)});var jt={};E(jt,{RecurCheckout:()=>N,RecurElements:()=>z,create:()=>gt,createElements:()=>Te,default:()=>Kt,init:()=>mt});async function Pt(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(Pe(),De)),Promise.resolve().then(()=>(Me(),Le)),Promise.resolve().then(()=>(He(),Ue)),Promise.resolve().then(()=>(ze(),Be)),Promise.resolve().then(()=>(Qe(),Ze)),Promise.resolve().then(()=>(tt(),et)),Promise.resolve().then(()=>(at(),nt)),Promise.resolve().then(()=>(lt(),ct)),Promise.resolve().then(()=>(ut(),dt))]);let e=["recur-loading-spinner","recur-success-message","recur-error-display","recur-skeleton-loader","recur-payment-form-skeleton","recur-toast","recur-toast-container","recur-payment-form","recur-checkout","recur-portal"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&Pt();function Lt(n){return n.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function k(n){if(n==null)return n;if(Array.isArray(n))return n.map(e=>k(e));if(n instanceof Date)return n;if(typeof n=="object"){let e={};for(let[t,r]of Object.entries(n)){let o=Lt(t);e[o]=k(r)}return e}return n}var pe={name:"recur-tw",version:"0.12.0",description:"React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",type:"module",private:!1,author:"Recur",license:"Elastic-2.0",keywords:["react","vanilla-js","subscription","checkout","payment","payuni","recurring-billing","taiwan","\u7E41\u9AD4\u4E2D\u6587","sdk","embedded-checkout"],homepage:"https://recur.tw/",bugs:{email:"support@recur.tw"},scripts:{build:"tsup",dev:"tsup --watch",lint:"eslint .","lint:fix":"eslint . --fix","type-check":"tsc --noEmit",examples:"npx http-server . -p 8080 -o /examples/"},main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"},"./server":{types:"./dist/server.d.ts",import:"./dist/server.js",require:"./dist/server.cjs"},"./vanilla":"./dist/recur.umd.js","./checkout":"./dist/checkout.js","./widget":"./dist/widget.js","./package.json":"./package.json"},unpkg:"./dist/recur.umd.js",jsdelivr:"./dist/recur.umd.js",files:["dist","README.md","AGENTS.md","LICENSE"],sideEffects:["src/components/**/*.ts","src/components/**/*.js"],peerDependencies:{react:">=18.0.0","react-dom":">=18.0.0"},peerDependenciesMeta:{react:{optional:!0},"react-dom":{optional:!0}},devDependencies:{"@eslint/js":"^9.39.1","@types/node":"^20.19.9","@types/react":"^19.1.9","@types/react-dom":"^19.1.7","@workspace/typescript-config":"workspace:*",autoprefixer:"^10.4.22",eslint:"^9","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.0.1",postcss:"^8.5.6",react:"^19.2.1","react-dom":"^19.2.1",tailwindcss:"^4.1.11",tsup:"^8.3.5",typescript:"^5.9.2","typescript-eslint":"^8.47.0"},dependencies:{"lit-html":"^3.3.1"}};var Ut=pe.version,Ht="vanilla",he=class{constructor(e){l(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}getHeaders(){return{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey,"X-Recur-SDK-Type":Ht,"X-Recur-SDK-Version":Ut,"X-Recur-Source":typeof window<"u"?window.location.origin:"server"}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,o=e.productId||e.planId,i=e.productSlug;if(!o&&!i)throw new Error("Either productId or productSlug is required");let s={customerName:t,customerEmail:r};o&&(s.productId=o),i&&(s.productSlug=i);let a=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(s)});if(!a.ok){let d=await a.json().catch(()=>({}));throw{code:d.error||"CHECKOUT_FAILED",message:d.message||"Failed to initiate checkout",details:d}}let c=await a.json();return k(c)}async fetchProducts(e){let t=new URL(`${this.config.baseUrl}/v1/products`);e?.type&&t.searchParams.set("type",e.type);let r=await fetch(t.toString(),{method:"GET",headers:this.getHeaders()});if(!r.ok){let i=await r.json().catch(()=>({}));throw{code:i.error||"FETCH_PRODUCTS_FAILED",message:i.message||"Failed to fetch products",details:i}}let o=await r.json();return k(o)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var me=class{constructor(e,t){l(this,"config");l(this,"options");l(this,"container");l(this,"checkoutId",null);l(this,"sdkToken",null);l(this,"sdkTimestamp",null);l(this,"creditToken",null);l(this,"sdkEnv","S");l(this,"payuniSDK",null);l(this,"isFormValid",!1);if(this.config=e,this.options=t,typeof t.container=="string"){let r=document.querySelector(t.container);if(!r)throw new Error(`Container not found: ${t.container}`);this.container=r}else this.container=t.container}async render(){try{await this.initCheckout(),this.renderHTML(),await this.loadPayUniSDK(),await this.initPayUniSDK(),this.setupFormSubmit()}catch(e){this.handleError(e)}}getBaseUrl(){if(this.config.baseUrl)return this.config.baseUrl;if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}async initCheckout(){let e=this.getBaseUrl(),t=await fetch(`${e}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({productId:this.options.productId||this.options.planId,customerEmail:this.options.customerEmail,customerName:this.options.customerName})});if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(i.error||"Failed to initialize checkout")}let r=await t.json(),o=k(r);this.checkoutId=o.checkout.id,this.sdkToken=o.sdkToken,this.sdkTimestamp=o.sdkTimestamp||null,this.creditToken=o.creditToken||null,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
2105
+ `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),o=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let i={};r&&(i.customerId=r),o&&(i.returnUrl=o);let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!s.ok){let d=await s.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${s.status}: Failed to create portal session`)}let a=await s.json(),c=a.url||a.portalUrl;if(!c)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(c)}catch(i){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(i instanceof Error?i.message:"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",ue)});var jt={};C(jt,{RecurCheckout:()=>O,RecurElements:()=>z,create:()=>gt,createElements:()=>Te,default:()=>Kt,init:()=>ht});async function Dt(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(De(),Pe)),Promise.resolve().then(()=>(Le(),Me)),Promise.resolve().then(()=>(He(),Ue)),Promise.resolve().then(()=>(Ne(),Be)),Promise.resolve().then(()=>(Qe(),Ze)),Promise.resolve().then(()=>(tt(),et)),Promise.resolve().then(()=>(at(),nt)),Promise.resolve().then(()=>(lt(),ct)),Promise.resolve().then(()=>(ut(),dt))]);let e=["recur-loading-spinner","recur-success-message","recur-error-display","recur-skeleton-loader","recur-payment-form-skeleton","recur-toast","recur-toast-container","recur-payment-form","recur-checkout","recur-portal"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&Dt();function Mt(n){return n.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function k(n){if(n==null)return n;if(Array.isArray(n))return n.map(e=>k(e));if(n instanceof Date)return n;if(typeof n=="object"){let e={};for(let[t,r]of Object.entries(n)){let o=Mt(t);e[o]=k(r)}return e}return n}var pe={name:"recur-tw",version:"0.13.0",description:"React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",type:"module",private:!1,author:"Recur",license:"Elastic-2.0",keywords:["react","vanilla-js","subscription","checkout","payment","payuni","recurring-billing","taiwan","\u7E41\u9AD4\u4E2D\u6587","sdk","embedded-checkout"],homepage:"https://recur.tw/",bugs:{email:"support@recur.tw"},scripts:{build:"tsup",dev:"tsup --watch",lint:"eslint .","lint:fix":"eslint . --fix","type-check":"tsc --noEmit",examples:"npx http-server . -p 8080 -o /examples/"},main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"},"./server":{types:"./dist/server.d.ts",import:"./dist/server.js",require:"./dist/server.cjs"},"./vanilla":"./dist/recur.umd.js","./checkout":"./dist/checkout.js","./widget":"./dist/widget.js","./package.json":"./package.json"},unpkg:"./dist/recur.umd.js",jsdelivr:"./dist/recur.umd.js",files:["dist","README.md","AGENTS.md","LICENSE"],sideEffects:["src/components/**/*.ts","src/components/**/*.js"],peerDependencies:{react:">=18.0.0","react-dom":">=18.0.0"},peerDependenciesMeta:{react:{optional:!0},"react-dom":{optional:!0}},devDependencies:{"@eslint/js":"^9.39.1","@types/node":"^20.19.9","@types/react":"^19.1.9","@types/react-dom":"^19.1.7","@workspace/typescript-config":"workspace:*",autoprefixer:"^10.4.22",eslint:"^9","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.0.1",postcss:"^8.5.6",react:"^19.2.1","react-dom":"^19.2.1",tailwindcss:"^4.1.11",tsup:"^8.3.5",typescript:"^5.9.2","typescript-eslint":"^8.47.0"},dependencies:{"lit-html":"^3.3.1"}};var Ut=pe.version,Ht="vanilla",me=class{constructor(e){l(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}getHeaders(){return{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey,"X-Recur-SDK-Type":Ht,"X-Recur-SDK-Version":Ut,"X-Recur-Source":typeof window<"u"?window.location.origin:"server"}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,o=e.productId||e.planId,i=e.productSlug;if(!o&&!i)throw new Error("Either productId or productSlug is required");let s={customerName:t,customerEmail:r};o&&(s.productId=o),i&&(s.productSlug=i);let a=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(s)});if(!a.ok){let d=await a.json().catch(()=>({}));throw{code:d.error||"CHECKOUT_FAILED",message:d.message||"Failed to initiate checkout",details:d}}let c=await a.json();return k(c)}async fetchProducts(e){let t=new URL(`${this.config.baseUrl}/v1/products`);e?.type&&t.searchParams.set("type",e.type);let r=await fetch(t.toString(),{method:"GET",headers:this.getHeaders()});if(!r.ok){let i=await r.json().catch(()=>({}));throw{code:i.error||"FETCH_PRODUCTS_FAILED",message:i.message||"Failed to fetch products",details:i}}let o=await r.json();return k(o)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var he=class{constructor(e,t){l(this,"config");l(this,"options");l(this,"container");l(this,"checkoutId",null);l(this,"sdkToken",null);l(this,"sdkTimestamp",null);l(this,"creditToken",null);l(this,"sdkEnv","S");l(this,"payuniSDK",null);l(this,"isFormValid",!1);if(this.config=e,this.options=t,typeof t.container=="string"){let r=document.querySelector(t.container);if(!r)throw new Error(`Container not found: ${t.container}`);this.container=r}else this.container=t.container}async render(){try{await this.initCheckout(),this.renderHTML(),await this.loadPayUniSDK(),await this.initPayUniSDK(),this.setupFormSubmit()}catch(e){this.handleError(e)}}getBaseUrl(){if(this.config.baseUrl)return this.config.baseUrl;if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}async initCheckout(){let e=this.getBaseUrl(),t=await fetch(`${e}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({productId:this.options.productId||this.options.planId,customerEmail:this.options.customerEmail,customerName:this.options.customerName})});if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(i.error||"Failed to initialize checkout")}let r=await t.json(),o=k(r);this.checkoutId=o.checkout.id,this.sdkToken=o.sdkToken,this.sdkTimestamp=o.sdkTimestamp||null,this.creditToken=o.creditToken||null,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
2106
2106
  <div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
2107
2107
  <div class="recur-checkout-header" style="margin-bottom: 24px;">
2108
2108
  <h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
@@ -2172,21 +2172,21 @@
2172
2172
  </p>
2173
2173
  </form>
2174
2174
  </div>
2175
- `}async loadPayUniSDK(){return new Promise((e,t)=>{if(window.UniPayment){e();return}let r=document.createElement("script");r.src=this.sdkEnv==="P"?"https://vendor.payuni.com.tw/sdk/uni-payment.js":"https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",r.async=!0,r.onload=()=>e(),r.onerror=()=>t(new Error("Failed to load PAYUNi SDK")),document.head.appendChild(r)})}async initPayUniSDK(){if(!this.sdkToken)throw new Error("SDK token not initialized");let e=window.UniPayment;if(!e)throw new Error("PAYUNi SDK not loaded");let t={env:this.sdkEnv,useInst:!1,elements:{CardNo:"recur-card-number",CardExp:"recur-card-exp",CardCvc:"recur-card-cvc"},style:{color:"#111827",errorColor:"#dc2626",fontSize:"14px",fontWeight:"400",lineHeight:"24px"}};this.payuniSDK=e.createSession(this.sdkToken,t),await this.payuniSDK.start(),this.payuniSDK.onUpdate(r=>{let o=r?.status;o&&(this.isFormValid=o.CardNo===!0&&o.CardExp===!0&&o.CardCvc===!0,this.updateSubmitButton())})}updateSubmitButton(){let e=document.getElementById("recur-submit-btn");e&&(e.disabled=!this.isFormValid,e.style.opacity=this.isFormValid?"1":"0.5",e.style.cursor=this.isFormValid?"pointer":"not-allowed")}setupFormSubmit(){let e=document.getElementById("recur-checkout-form");e&&e.addEventListener("submit",async t=>{t.preventDefault(),await this.handleSubmit()})}async handleSubmit(){try{this.showLoading(!0),this.hideError();let e=document.getElementById("recur-email").value,t=document.getElementById("recur-name").value;if(!e||!t)throw new Error("Please fill in all required fields");if(!this.checkoutId)throw new Error("Checkout session not initialized");if(!this.payuniSDK)throw new Error("Payment system not initialized");let r=await this.payuniSDK.getTradeResult();if(r.Status!=="SUCCESS")throw new Error(r.Message||"Card validation failed");let o=r.EncryptInfo||r.creditToken;if(!o)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let i=this.getBaseUrl(),s=await fetch(`${i}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:o,timestamp:this.sdkTimestamp||r.HashTimestamp||r.timestamp})});if(!s.ok){let h=await s.json().catch(()=>({}));throw new Error(h.error||"Failed to process payment")}let a=await s.json(),c=this.options.productId||this.options.planId||"",d={subscription:{id:a.subscription?.id||a.charge?.id||"",status:a.success?"active":"failed",productId:c,productName:"",amount:a.charge?.amount||0,billingPeriod:a.subscription?.billingPeriod||"MONTHLY",trialDays:null},subscriber:{id:"",email:document.getElementById("recur-email")?.value||"",name:document.getElementById("recur-name")?.value||""},nextSteps:{getSdkToken:"",completeSubscription:""}};this.options.onSuccess&&this.options.onSuccess(d),this.showSuccess()}catch(e){this.handleError(e)}finally{this.showLoading(!1)}}showLoading(e){let t=document.getElementById("recur-submit-btn");t&&(t.disabled=e,t.textContent=e?"Processing...":"Subscribe Now")}showError(e){let t=document.getElementById("recur-error");t&&(t.textContent=e,t.style.display="block")}hideError(){let e=document.getElementById("recur-error");e&&(e.style.display="none")}showSuccess(){this.container.innerHTML="";let e=document.createElement("recur-success-message");e.setAttribute("title","Subscription Complete!"),e.setAttribute("message","Thank you for subscribing. You will receive a confirmation email shortly."),this.container.appendChild(e)}handleError(e){let t=e?.message||"An error occurred";this.showError(t);let r={code:"CHECKOUT_ERROR",message:t};this.options.onError&&this.options.onError(r)}};var z=class{constructor(e){l(this,"publishableKey");l(this,"baseUrl");l(this,"embedUrl");l(this,"iframe",null);l(this,"container",null);l(this,"sessionId",null);l(this,"timestamp",null);l(this,"creditToken",null);l(this,"sdkToken",null);l(this,"cardToken",null);l(this,"cardTimestamp",null);l(this,"eventHandlers",new Map);typeof e=="string"?(this.publishableKey=e,this.baseUrl=this.getDefaultBaseUrl(),this.embedUrl=this.getDefaultEmbedUrl()):(this.publishableKey=e.publishableKey,this.baseUrl=e.baseUrl||this.getDefaultBaseUrl(),this.embedUrl=e.embedUrl||this.getDefaultEmbedUrl()),window.addEventListener("message",this.handleMessage.bind(this))}async mount(e){let t=typeof e=="string"?document.querySelector(e):e;if(!t)throw new Error(`Container not found: ${e}`);return this.container=t,this.iframe=document.createElement("iframe"),this.iframe.src=`${this.embedUrl}/elements?key=${encodeURIComponent(this.publishableKey)}`,this.iframe.style.cssText=`
2175
+ `}async loadPayUniSDK(){return new Promise((e,t)=>{if(window.UniPayment){e();return}let r=document.createElement("script");r.src=this.sdkEnv==="P"?"https://vendor.payuni.com.tw/sdk/uni-payment.js":"https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",r.async=!0,r.onload=()=>e(),r.onerror=()=>t(new Error("Failed to load PAYUNi SDK")),document.head.appendChild(r)})}async initPayUniSDK(){if(!this.sdkToken)throw new Error("SDK token not initialized");if(!window.UniPayment)throw new Error("PAYUNi SDK not loaded");let e={env:this.sdkEnv,useInst:!1,elements:{CardNo:"recur-card-number",CardExp:"recur-card-exp",CardCvc:"recur-card-cvc"},style:{color:"#111827",errorColor:"#dc2626",fontSize:"14px",fontWeight:"400",lineHeight:"24px"}};this.payuniSDK=window.UniPayment.createSession(this.sdkToken,e),await this.payuniSDK.start(),this.payuniSDK.onUpdate?.(t=>{let r=t?.status;r&&(this.isFormValid=r.CardNo===!0&&r.CardExp===!0&&r.CardCvc===!0,this.updateSubmitButton())})}updateSubmitButton(){let e=document.getElementById("recur-submit-btn");e&&(e.disabled=!this.isFormValid,e.style.opacity=this.isFormValid?"1":"0.5",e.style.cursor=this.isFormValid?"pointer":"not-allowed")}setupFormSubmit(){let e=document.getElementById("recur-checkout-form");e&&e.addEventListener("submit",async t=>{t.preventDefault(),await this.handleSubmit()})}async handleSubmit(){try{this.showLoading(!0),this.hideError();let e=document.getElementById("recur-email").value,t=document.getElementById("recur-name").value;if(!e||!t)throw new Error("Please fill in all required fields");if(!this.checkoutId)throw new Error("Checkout session not initialized");if(!this.payuniSDK)throw new Error("Payment system not initialized");let r=await this.payuniSDK.getTradeResult();if(r.Status!=="SUCCESS")throw new Error(r.Message||"Card validation failed");let o=r.EncryptInfo||r.creditToken;if(!o)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let i=this.getBaseUrl(),s=await fetch(`${i}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:o,timestamp:this.sdkTimestamp||r.HashTimestamp||r.timestamp})});if(!s.ok){let h=await s.json().catch(()=>({}));throw new Error(h.error||"Failed to process payment")}let a=await s.json(),c=this.options.productId||this.options.planId||"",d={subscription:{id:a.subscription?.id||a.charge?.id||"",status:a.success?"active":"failed",productId:c,productName:"",amount:a.charge?.amount||0,billingPeriod:a.subscription?.billingPeriod||"MONTHLY",trialDays:null},subscriber:{id:"",email:document.getElementById("recur-email")?.value||"",name:document.getElementById("recur-name")?.value||""},nextSteps:{getSdkToken:"",completeSubscription:""}};this.options.onSuccess&&this.options.onSuccess(d),this.showSuccess()}catch(e){this.handleError(e)}finally{this.showLoading(!1)}}showLoading(e){let t=document.getElementById("recur-submit-btn");t&&(t.disabled=e,t.textContent=e?"Processing...":"Subscribe Now")}showError(e){let t=document.getElementById("recur-error");t&&(t.textContent=e,t.style.display="block")}hideError(){let e=document.getElementById("recur-error");e&&(e.style.display="none")}showSuccess(){this.container.innerHTML="";let e=document.createElement("recur-success-message");e.setAttribute("title","Subscription Complete!"),e.setAttribute("message","Thank you for subscribing. You will receive a confirmation email shortly."),this.container.appendChild(e)}handleError(e){let t=e instanceof Error?e.message:"An error occurred";this.showError(t);let r={code:"CHECKOUT_ERROR",message:t};this.options.onError&&this.options.onError(r)}};var z=class{constructor(e){l(this,"publishableKey");l(this,"baseUrl");l(this,"embedUrl");l(this,"iframe",null);l(this,"container",null);l(this,"sessionId",null);l(this,"timestamp",null);l(this,"creditToken",null);l(this,"sdkToken",null);l(this,"cardToken",null);l(this,"cardTimestamp",null);l(this,"eventHandlers",new Map);typeof e=="string"?(this.publishableKey=e,this.baseUrl=this.getDefaultBaseUrl(),this.embedUrl=this.getDefaultEmbedUrl()):(this.publishableKey=e.publishableKey,this.baseUrl=e.baseUrl||this.getDefaultBaseUrl(),this.embedUrl=e.embedUrl||this.getDefaultEmbedUrl()),window.addEventListener("message",this.handleMessage.bind(this))}async mount(e){let t=typeof e=="string"?document.querySelector(e):e;if(!t)throw new Error(`Container not found: ${e}`);return this.container=t,this.iframe=document.createElement("iframe"),this.iframe.src=`${this.embedUrl}/elements?key=${encodeURIComponent(this.publishableKey)}`,this.iframe.style.cssText=`
2176
2176
  width: 100%;
2177
2177
  border: none;
2178
2178
  min-height: 200px;
2179
2179
  display: block;
2180
2180
  user-select: none;
2181
2181
  transition: height 0.35s ease, opacity 0.4s ease 0.1s;
2182
- `.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,o)=>{let i=setTimeout(()=>{o(new Error("Elements initialization timeout"))},3e4),s=()=>{clearTimeout(i),this.off("ready",s),r()},a=c=>{clearTimeout(i),this.off("error",a),o(new Error(c.message||"Elements initialization failed"))};this.on("ready",s),this.on("error",a)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(o=>o(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let o=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),i=a=>{clearTimeout(o),this.off("tokenized",i),t(a)},s=a=>{clearTimeout(o),this.off("error",s),r(new Error(a.message||"Tokenization failed"))};this.on("tokenized",i),this.on("error",s)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function Te(n){return new z(n)}var Bt="https://vendor.payuni.com.tw/sdk/uni-payment.js",zt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",pt=!1,ge=!1,Z=null;async function ht(n=!1){return pt&&window.UniPayment?Promise.resolve():(ge&&Z||(ge=!0,Z=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?zt:Bt,r.async=!0,r.onload=()=>{pt=!0,ge=!1,e()},r.onerror=()=>{ge=!1,Z=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),Z)}var Nt=pe.version,Ot="vanilla";var N=class n{constructor(e){l(this,"core");l(this,"currentDialog",null);l(this,"currentIframe",null);l(this,"_customer",null);l(this,"_subscription",null);l(this,"_entitlements",[]);l(this,"_customerIdentifier",null);l(this,"_isLoading",!1);l(this,"_error",null);l(this,"currentDialogElement",null);this.core=new he(e)}static async create(e){let t=new n(e);return e.customer&&(t._customerIdentifier=e.customer,await t.fetchEntitlements()),t}get customer(){return this._customer}get subscription(){return this._subscription}get entitlements(){return this._entitlements}get isLoading(){return this._isLoading}get error(){return this._error}async fetchEntitlements(){if(!this._customerIdentifier){console.warn("[Recur SDK] Cannot fetch entitlements: customer identifier not set");return}let e=this.core.getConfig();if(!e.publishableKey){console.warn("[Recur SDK] Cannot fetch entitlements: publishableKey is required");return}this._isLoading=!0,this._error=null;try{let t=e.baseUrl||"https://api.recur.tw",r=new URLSearchParams;this._customerIdentifier.email&&r.set("email",this._customerIdentifier.email),this._customerIdentifier.externalId&&r.set("external_id",this._customerIdentifier.externalId),this._customerIdentifier.id&&r.set("customer_id",this._customerIdentifier.id);let o=await fetch(`${t}/v1/customers/entitlements?${r.toString()}`,{method:"GET",headers:{"X-Recur-Publishable-Key":e.publishableKey,"X-Recur-SDK-Type":Ot,"X-Recur-SDK-Version":Nt}});if(!o.ok){let a=await o.json().catch(()=>({}));throw new Error(a.error?.message||"Failed to fetch entitlements")}let i=await o.json(),s=k(i);this._customer=s.customer||null,this._subscription=s.subscription||null,this._entitlements=s.entitlements||[]}catch(t){console.error("[Recur SDK] Failed to fetch entitlements:",t),this._error=t instanceof Error?t:new Error("Failed to fetch entitlements")}finally{this._isLoading=!1}}async refetch(){await this.fetchEntitlements()}resolveProduct(e){if(typeof e=="string")return e;if("product"in e)return e.product;throw"feature"in e?new Error("Feature-based checks are not yet supported. Coming in Phase 2."):"benefit"in e?new Error("Benefit-based checks are not yet supported. Coming in Phase 2."):new Error("Invalid check target")}check(e,t){return t?.live?this.checkLive(e):this.checkSync(e)}checkSync(e){let t=this.resolveProduct(e);if(!this._customer)return{allowed:!1,reason:"no_customer"};if(this._entitlements.length===0)return{allowed:!1,reason:"no_entitlement"};let r=this._entitlements.find(o=>o.product===t||o.productId===t);return r?{allowed:!0,entitlement:r}:{allowed:!1,reason:"not_found"}}async checkLive(e){return await this.refetch(),this.checkSync(e)}async fetchProducts(e){return await this.core.fetchProducts(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new me(t,e).render()}async redirectToCheckout(e){let t=await this.createCheckoutSession(e);window.location.href=t.url}async createCheckoutSession(e){let t=this.getBaseUrl();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");if(!e.successUrl)throw new Error("successUrl is required for hosted checkout");if(!e.cancelUrl)throw new Error("cancelUrl is required for hosted checkout");let r={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(r.productId=e.productId),e.productSlug&&(r.productSlug=e.productSlug),e.customerEmail&&(r.customerEmail=e.customerEmail),e.customerName&&(r.customerName=e.customerName),e.externalCustomerId&&(r.externalCustomerId=e.externalCustomerId);let o=this.core.getConfig(),i=await fetch(`${t}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":o.publishableKey},body:JSON.stringify(r)});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error?.message||c.error||"Failed to create checkout session")}let s=await i.json(),a=k(s);return{id:a.id,url:a.url,expiresAt:a.expiresAt,clientSecret:a.clientSecret}}async getCheckoutStatus(e,t){let r=this.getBaseUrl(),o=this.core.getConfig(),i=await fetch(`${r}/v1/checkouts/${e}?client_secret=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-Recur-Publishable-Key":o.publishableKey}});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error||"Failed to get checkout status")}let s=await i.json(),a=k(s);return{id:a.checkout.id,status:a.checkout.status,amount:a.checkout.amount,currency:a.checkout.currency,lastCharge:a.lastCharge}}async checkout(e){let t=this.core.getConfig(),r=null,o=e.productId||e.planId,i=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:o,productSlug:i,mode:e.mode}),!o&&!i)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");let s=this.getBaseUrl();console.log("[Recur SDK] Base URL:",s);let a={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},c=e.mode||"modal";if(c==="redirect"){if(!e.successUrl)throw new Error("successUrl is required for redirect mode");if(!e.cancelUrl)throw new Error("cancelUrl is required for redirect mode");console.log("[Recur SDK] Creating hosted checkout session...");let y={successUrl:e.successUrl,cancelUrl:e.cancelUrl};o&&(y.productId=o),i&&(y.productSlug=i),e.customerEmail&&(y.customerEmail=e.customerEmail),e.customerName&&(y.customerName=e.customerName),e.externalCustomerId&&(y.externalCustomerId=e.externalCustomerId);let A=await fetch(`${s}/v1/checkout/sessions`,{method:"POST",headers:a,body:JSON.stringify(y)});if(!A.ok){let R=await A.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",R),new Error(R.error?.message||R.error||"Failed to create checkout session")}let fe=await A.json(),C=k(fe);console.log("[Recur SDK] Checkout session created:",C),console.log("[Recur SDK] Redirecting to hosted checkout:",C.url),window.location.href=C.url;return}let d=null;if(c==="modal"){let y=this.createDialogWithSkeleton(e.onClose);r=y.dialog,d=y.container}else if(c==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let y=document.createElement("recur-payment-form-skeleton");d.appendChild(y)}console.log("[Recur SDK] Step 1: Creating embedded checkout...");let h={customerName:e.customerName,customerEmail:e.customerEmail};o&&(h.productId=o),i&&(h.productSlug=i),e.externalCustomerId&&(h.externalCustomerId=e.externalCustomerId),e.successUrl&&(h.successUrl=e.successUrl),e.cancelUrl&&(h.cancelUrl=e.cancelUrl);let m=await fetch(`${s}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(h)});if(!m.ok){let y=await m.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",y);let A=y.details||y.error||"Failed to create checkout";throw new Error(A)}let x=await m.json(),u=k(x);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let T=!u.livemode;if(console.log("[Recur SDK] Environment:",T?"SANDBOX":"PRODUCTION"),await ht(T),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let b=document.createElement("recur-payment-form");if(b.setAttribute("container-id",d.id||"recur-payment-container"),u.checkout?.id&&b.setAttribute("checkout-id",u.checkout.id),b.setAttribute("api-base-url",s),e.customerName&&b.setAttribute("customer-name",e.customerName),e.customerEmail&&b.setAttribute("customer-email",e.customerEmail),u.product?.name&&b.setAttribute("product-name",u.product.name),u.checkout?.amount&&b.setAttribute("amount",u.checkout.amount.toString()),u.product?.interval&&b.setAttribute("interval",u.product.interval),b.setAttribute("custom-styles",`
2182
+ `.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,o)=>{let i=setTimeout(()=>{o(new Error("Elements initialization timeout"))},3e4),s=()=>{clearTimeout(i),this.off("ready",s),r()},a=c=>{clearTimeout(i),this.off("error",a);let d=c instanceof Error?c.message:c?.message;o(new Error(d||"Elements initialization failed"))};this.on("ready",s),this.on("error",a)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(o=>o(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let o=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),i=a=>{clearTimeout(o),this.off("tokenized",i),t(a)},s=a=>{clearTimeout(o),this.off("error",s);let c=a instanceof Error?a.message:a?.message;r(new Error(c||"Tokenization failed"))};this.on("tokenized",i),this.on("error",s)})}async confirmPayment(e){if(!this.sessionId||!this.cardToken)throw new Error("Card not tokenized. Call tokenize() first.");let t=await fetch(`${this.baseUrl}/api/v1/elements/confirm`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.publishableKey},body:JSON.stringify({sessionId:this.sessionId,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function Te(n){return new z(n)}var Bt="https://vendor.payuni.com.tw/sdk/uni-payment.js",Nt="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",pt=!1,ge=!1,Z=null;async function mt(n=!1){return pt&&window.UniPayment?Promise.resolve():(ge&&Z||(ge=!0,Z=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?Nt:Bt,r.async=!0,r.onload=()=>{pt=!0,ge=!1,e()},r.onerror=()=>{ge=!1,Z=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),Z)}var zt=pe.version,Ot="vanilla",O=class n{constructor(e){l(this,"core");l(this,"currentDialog",null);l(this,"currentIframe",null);l(this,"_customer",null);l(this,"_subscription",null);l(this,"_entitlements",[]);l(this,"_customerIdentifier",null);l(this,"_isLoading",!1);l(this,"_error",null);l(this,"currentDialogElement",null);this.core=new me(e)}static async create(e){let t=new n(e);return e.customer&&(t._customerIdentifier=e.customer,await t.fetchEntitlements()),t}get customer(){return this._customer}get subscription(){return this._subscription}get entitlements(){return this._entitlements}get isLoading(){return this._isLoading}get error(){return this._error}async fetchEntitlements(){if(!this._customerIdentifier){console.warn("[Recur SDK] Cannot fetch entitlements: customer identifier not set");return}let e=this.core.getConfig();if(!e.publishableKey){console.warn("[Recur SDK] Cannot fetch entitlements: publishableKey is required");return}this._isLoading=!0,this._error=null;try{let t=e.baseUrl||"https://api.recur.tw",r=new URLSearchParams;this._customerIdentifier.email&&r.set("email",this._customerIdentifier.email),this._customerIdentifier.externalId&&r.set("external_id",this._customerIdentifier.externalId),this._customerIdentifier.id&&r.set("customer_id",this._customerIdentifier.id);let o=await fetch(`${t}/v1/customers/entitlements?${r.toString()}`,{method:"GET",headers:{"X-Recur-Publishable-Key":e.publishableKey,"X-Recur-SDK-Type":Ot,"X-Recur-SDK-Version":zt}});if(!o.ok){let a=await o.json().catch(()=>({}));throw new Error(a.error?.message||"Failed to fetch entitlements")}let i=await o.json(),s=k(i);this._customer=s.customer||null,this._subscription=s.subscription||null,this._entitlements=s.entitlements||[]}catch(t){console.error("[Recur SDK] Failed to fetch entitlements:",t),this._error=t instanceof Error?t:new Error("Failed to fetch entitlements")}finally{this._isLoading=!1}}async refetch(){await this.fetchEntitlements()}resolveProduct(e){if(typeof e=="string")return e;if("product"in e)return e.product;throw"feature"in e?new Error("Feature-based checks are not yet supported. Coming in Phase 2."):"benefit"in e?new Error("Benefit-based checks are not yet supported. Coming in Phase 2."):new Error("Invalid check target")}check(e,t){return t?.live?this.checkLive(e):this.checkSync(e)}checkSync(e){let t=this.resolveProduct(e);if(!this._customer)return{allowed:!1,reason:"no_customer"};if(this._entitlements.length===0)return{allowed:!1,reason:"no_entitlement"};let r=this._entitlements.find(o=>o.product===t||o.productId===t);return r?{allowed:!0,entitlement:r}:{allowed:!1,reason:"not_found"}}async checkLive(e){return await this.refetch(),this.checkSync(e)}async fetchProducts(e){return await this.core.fetchProducts(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new he(t,e).render()}async redirectToCheckout(e){let t=await this.createCheckoutSession(e);window.location.href=t.url}async createCheckoutSession(e){let t=this.getBaseUrl();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");if(!e.successUrl)throw new Error("successUrl is required for hosted checkout");if(!e.cancelUrl)throw new Error("cancelUrl is required for hosted checkout");let r={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(r.productId=e.productId),e.productSlug&&(r.productSlug=e.productSlug),e.customerEmail&&(r.customerEmail=e.customerEmail),e.customerName&&(r.customerName=e.customerName),e.externalCustomerId&&(r.externalCustomerId=e.externalCustomerId);let o=this.core.getConfig(),i=await fetch(`${t}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":o.publishableKey},body:JSON.stringify(r)});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error?.message||c.error||"Failed to create checkout session")}let s=await i.json(),a=k(s);return{id:a.id,url:a.url,expiresAt:a.expiresAt,clientSecret:a.clientSecret}}async getCheckoutStatus(e,t){let r=this.getBaseUrl(),o=this.core.getConfig(),i=await fetch(`${r}/v1/checkouts/${e}?client_secret=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-Recur-Publishable-Key":o.publishableKey}});if(!i.ok){let c=await i.json().catch(()=>({}));throw new Error(c.error||"Failed to get checkout status")}let s=await i.json(),a=k(s);return{id:a.checkout.id,status:a.checkout.status,amount:a.checkout.amount,currency:a.checkout.currency,lastCharge:a.lastCharge}}async checkout(e){let t=this.core.getConfig(),r=null,o=e.productId||e.planId,i=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:o,productSlug:i,mode:e.mode}),!o&&!i)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");let s=this.getBaseUrl();console.log("[Recur SDK] Base URL:",s);let a={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},c=e.mode||"modal";if(c==="redirect"){if(!e.successUrl)throw new Error("successUrl is required for redirect mode");if(!e.cancelUrl)throw new Error("cancelUrl is required for redirect mode");console.log("[Recur SDK] Creating hosted checkout session...");let y={successUrl:e.successUrl,cancelUrl:e.cancelUrl};o&&(y.productId=o),i&&(y.productSlug=i),e.customerEmail&&(y.customerEmail=e.customerEmail),e.customerName&&(y.customerName=e.customerName),e.externalCustomerId&&(y.externalCustomerId=e.externalCustomerId);let R=await fetch(`${s}/v1/checkout/sessions`,{method:"POST",headers:a,body:JSON.stringify(y)});if(!R.ok){let P=await R.json().catch(()=>({}));throw console.error("[Recur SDK] Failed to create checkout session:",P),new Error(P.error?.message||P.error||"Failed to create checkout session")}let fe=await R.json(),E=k(fe);console.log("[Recur SDK] Checkout session created:",E),console.log("[Recur SDK] Redirecting to hosted checkout:",E.url),window.location.href=E.url;return}let d=null;if(c==="modal"){let y=this.createDialogWithSkeleton(e.onClose);r=y.dialog,d=y.container}else if(c==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let y=document.createElement("recur-payment-form-skeleton");d.appendChild(y)}console.log("[Recur SDK] Step 1: Creating embedded checkout...");let h={customerName:e.customerName,customerEmail:e.customerEmail};o&&(h.productId=o),i&&(h.productSlug=i),e.externalCustomerId&&(h.externalCustomerId=e.externalCustomerId),e.successUrl&&(h.successUrl=e.successUrl),e.cancelUrl&&(h.cancelUrl=e.cancelUrl);let m=await fetch(`${s}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(h)});if(!m.ok){let y=await m.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",y);let R=y.details||y.error||"Failed to create checkout";throw new Error(R)}let x=await m.json(),u=k(x);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let T=!u.livemode;if(console.log("[Recur SDK] Environment:",T?"SANDBOX":"PRODUCTION"),await mt(T),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let b=document.createElement("recur-payment-form");if(b.setAttribute("container-id",d.id||"recur-payment-container"),u.checkout?.id&&b.setAttribute("checkout-id",u.checkout.id),b.setAttribute("api-base-url",s),e.customerName&&b.setAttribute("customer-name",e.customerName),e.customerEmail&&b.setAttribute("customer-email",e.customerEmail),u.product?.name&&b.setAttribute("product-name",u.product.name),u.checkout?.amount&&b.setAttribute("amount",u.checkout.amount.toString()),u.product?.interval&&b.setAttribute("interval",u.product.interval),b.setAttribute("custom-styles",`
2183
2183
  .form-input-focus {
2184
2184
  border-color: var(--ring, hsl(215 16% 47%)) !important;
2185
2185
  outline: 0 !important;
2186
2186
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
2187
2187
  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
2188
2188
  }
2189
- `),d.appendChild(b),await new Promise(y=>setTimeout(y,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await b.initializePayment(u.sdkToken,T?"SANDBOX":"PRODUCTION")===null){console.log("[Recur SDK] Initialization aborted");return}console.log("[Recur SDK] PAYUNi SDK initialized successfully"),console.log("[Recur SDK] Step 6: Setting up submit handler..."),b.addEventListener("submit",(async y=>{console.log("[Recur SDK] Form submitted");let A=y,{paymentSession:fe}=A.detail;try{let C=await fe.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let R=C.HashTimestamp||C.timestamp,$e={};if(u.checkout.productType==="SUBSCRIPTION"){let $=u.creditToken,_=u.sdkTimestamp;if(!$)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");$e={creditToken:$,timestamp:_||R},console.log("[Recur SDK] Using creditToken from checkout:",$.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",_?"from checkout (sdkTimestamp)":"from tradeResult")}let be=await fetch(`${s}/v1/checkouts/${u.checkout.id}/pay`,{method:"POST",headers:a,body:JSON.stringify($e)});if(!be.ok){let $=await be.json().catch(()=>({}));throw new Error($.error||"Failed to execute payment")}let ft=await be.json(),g=k(ft);if(console.log("[Recur SDK] Payment executed:",g),g.requires3D&&g.redirectUrl){if(console.log("[Recur SDK] 3D verification required"),/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||/wv|WebView|FBAN|FBAV|Instagram|Line|MicroMessenger|QQ/i.test(navigator.userAgent)||/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent)||"standalone"in navigator&&navigator.standalone){console.log("[Recur SDK] Mobile/WebView detected, using redirect for 3D verification"),window.location.href=g.redirectUrl;return}console.log("[Recur SDK] Using popup for 3D verification");{let _=window.open(g.redirectUrl,"recur_3d_verification","width=500,height=700,scrollbars=yes,resizable=yes");if(!_){console.log("[Recur SDK] Popup was blocked (null), falling back to redirect"),window.location.href=g.redirectUrl;return}if(await new Promise(K=>setTimeout(K,100)),_.closed){console.log("[Recur SDK] Popup was closed immediately, falling back to redirect"),window.location.href=g.redirectUrl;return}b.setVerifying?.(!0);let Q=u.checkout.id,Ie=u.checkout.clientSecret,bt=90,yt=2e3,O=!0,Ae=!1,Re;console.log("[Recur SDK] Starting 3D verification polling...");for(let K=0;K<bt&&O;K++){if(_.closed){console.log("[Recur SDK] Popup was closed");try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Ie)}`,{headers:a});if(v.ok){let j=await v.json();if(j.checkout?.status==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded after popup close"),O=!1,Ae=!0,Re=j.checkout?.orderId;break}}}catch(v){console.error("[Recur SDK] Final status check failed:",v)}throw console.log("[Recur SDK] Payment not confirmed, user closed popup"),b.setVerifying?.(!1),b.resetButton?.(),new Error("3D \u9A57\u8B49\u5DF2\u53D6\u6D88")}try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Ie)}`,{headers:a});if(v.ok){let j=await v.json(),ee=j.checkout?.status;if(console.log(`[Recur SDK] Poll ${K+1}: status = ${ee}`),ee==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded"),O=!1;try{_.close()}catch{}b.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:j.checkout?.orderId||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove());return}if(ee==="CANCELED"||ee==="FAILED"){console.log("[Recur SDK] Payment failed or canceled"),O=!1;try{_.close()}catch{}throw b.setVerifying?.(!1),b.resetButton?.(),new Error("\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")}}}catch(v){if(v.message==="3D \u9A57\u8B49\u5DF2\u53D6\u6D88"||v.message==="\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")throw v;console.error("[Recur SDK] Poll error:",v)}await new Promise(v=>setTimeout(v,yt))}if(O){console.log("[Recur SDK] 3D verification polling timeout");try{_.close()}catch{}throw b.setVerifying?.(!1),b.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}Ae&&(console.log("[Recur SDK] Handling success after popup close"),b.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:Re||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove()));return}}if(e.onPaymentComplete)if(g.subscription)e.onPaymentComplete({id:g.subscription.id,status:g.subscription.status,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd});else{let $=g.charge?.id||g.paymentIntent?.id,_=g.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:$,status:_,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),b.resetButton?.(),r&&(r.close(),r.remove())}catch(C){console.error("[Recur SDK] Payment error:",C);let R={code:"PAYMENT_FAILED",message:C instanceof Error?C.message:"Payment failed"};e.onError?.(R),b.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(s){console.error("[Recur SDK] Checkout error:",s),r&&(r.close(),r.remove());let a={code:"CHECKOUT_ERROR",message:s instanceof Error?s.message:"An unknown error occurred"};throw e.onError?.(a),s}}getBaseUrl(){let e=this.core.getConfig();if(e.baseUrl)return e.baseUrl;if(typeof window<"u"){let t=window.location.hostname;if(t==="localhost"||t.includes(".test")||t.includes(".local")||t==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}injectDialogStyles(){if(document.getElementById("recur-dialog-styles"))return;let e=document.createElement("style");e.id="recur-dialog-styles",e.textContent=`
2189
+ `),d.appendChild(b),await new Promise(y=>setTimeout(y,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await b.initializePayment(u.sdkToken,T?"SANDBOX":"PRODUCTION")===null){console.log("[Recur SDK] Initialization aborted");return}console.log("[Recur SDK] PAYUNi SDK initialized successfully"),console.log("[Recur SDK] Step 6: Setting up submit handler..."),b.addEventListener("submit",(async y=>{console.log("[Recur SDK] Form submitted");let R=y,{paymentSession:fe}=R.detail;try{let E=await fe.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let P=E.HashTimestamp||E.timestamp,$e={};if(u.checkout.productType==="SUBSCRIPTION"){let $=u.creditToken,_=u.sdkTimestamp;if(!$)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");$e={creditToken:$,timestamp:_||P},console.log("[Recur SDK] Using creditToken from checkout:",$.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",_?"from checkout (sdkTimestamp)":"from tradeResult")}let be=await fetch(`${s}/v1/checkouts/${u.checkout.id}/pay`,{method:"POST",headers:a,body:JSON.stringify($e)});if(!be.ok){let $=await be.json().catch(()=>({}));throw new Error($.error||"Failed to execute payment")}let ft=await be.json(),g=k(ft);if(console.log("[Recur SDK] Payment executed:",g),g.requires3D&&g.redirectUrl){if(console.log("[Recur SDK] 3D verification required"),/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||/wv|WebView|FBAN|FBAV|Instagram|Line|MicroMessenger|QQ/i.test(navigator.userAgent)||/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent)||"standalone"in navigator&&navigator.standalone){console.log("[Recur SDK] Mobile/WebView detected, using redirect for 3D verification"),window.location.href=g.redirectUrl;return}console.log("[Recur SDK] Using popup for 3D verification");{let _=window.open(g.redirectUrl,"recur_3d_verification","width=500,height=700,scrollbars=yes,resizable=yes");if(!_){console.log("[Recur SDK] Popup was blocked (null), falling back to redirect"),window.location.href=g.redirectUrl;return}if(await new Promise(j=>setTimeout(j,100)),_.closed){console.log("[Recur SDK] Popup was closed immediately, falling back to redirect"),window.location.href=g.redirectUrl;return}b.setVerifying?.(!0);let Q=u.checkout.id,Ie=u.checkout.clientSecret,bt=90,yt=2e3,K=!0,Ae=!1,Re;console.log("[Recur SDK] Starting 3D verification polling...");for(let j=0;j<bt&&K;j++){if(_.closed){console.log("[Recur SDK] Popup was closed");try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Ie)}`,{headers:a});if(v.ok){let I=await v.json();if(I.checkout?.status==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded after popup close"),K=!1,Ae=!0,Re=I.checkout?.orderId;break}}}catch(v){console.error("[Recur SDK] Final status check failed:",v)}throw console.log("[Recur SDK] Payment not confirmed, user closed popup"),b.setVerifying?.(!1),b.resetButton?.(),new Error("3D \u9A57\u8B49\u5DF2\u53D6\u6D88")}try{let v=await fetch(`${s}/v1/checkouts/${Q}/status?client_secret=${encodeURIComponent(Ie)}`,{headers:a});if(v.ok){let I=await v.json(),ee=I.checkout?.status;if(console.log(`[Recur SDK] Poll ${j+1}: status = ${ee}`),ee==="SUCCEEDED"){console.log("[Recur SDK] Payment succeeded"),K=!1;try{_.close()}catch{}b.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:I.checkout?.orderId||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove());return}if(ee==="CANCELED"||ee==="FAILED"){console.log("[Recur SDK] Payment failed or canceled"),K=!1;try{_.close()}catch{}throw b.setVerifying?.(!1),b.resetButton?.(),new Error("\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")}}}catch(v){let I=v instanceof Error?v.message:String(v);if(I==="3D \u9A57\u8B49\u5DF2\u53D6\u6D88"||I==="\u4ED8\u6B3E\u5931\u6557\u6216\u5DF2\u53D6\u6D88")throw v;console.error("[Recur SDK] Poll error:",v)}await new Promise(v=>setTimeout(v,yt))}if(K){console.log("[Recur SDK] 3D verification polling timeout");try{_.close()}catch{}throw b.setVerifying?.(!1),b.resetButton?.(),new Error("3D \u9A57\u8B49\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66")}Ae&&(console.log("[Recur SDK] Handling success after popup close"),b.setVerifying?.(!1),e.onPaymentComplete&&(g.subscription?e.onPaymentComplete({id:g.subscription.id,status:"ACTIVE",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd}):e.onPaymentComplete({id:Re||Q,status:"SUCCEEDED",productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})),r&&(r.close(),r.remove()));return}}if(e.onPaymentComplete)if(g.subscription)e.onPaymentComplete({id:g.subscription.id,status:g.subscription.status,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:g.subscription.billingPeriod,currentPeriodStart:g.subscription.currentPeriodStart,currentPeriodEnd:g.subscription.currentPeriodEnd});else{let $=g.charge?.id||g.paymentIntent?.id,_=g.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:$,status:_,productId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),b.resetButton?.(),r&&(r.close(),r.remove())}catch(E){console.error("[Recur SDK] Payment error:",E);let P={code:"PAYMENT_FAILED",message:E instanceof Error?E.message:"Payment failed"};e.onError?.(P),b.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(s){console.error("[Recur SDK] Checkout error:",s),r&&(r.close(),r.remove());let a={code:"CHECKOUT_ERROR",message:s instanceof Error?s.message:"An unknown error occurred"};throw e.onError?.(a),s}}getBaseUrl(){let e=this.core.getConfig();if(e.baseUrl)return e.baseUrl;if(typeof window<"u"){let t=window.location.hostname;if(t==="localhost"||t.includes(".test")||t.includes(".local")||t==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}injectDialogStyles(){if(document.getElementById("recur-dialog-styles"))return;let e=document.createElement("style");e.id="recur-dialog-styles",e.textContent=`
2190
2190
  .recur-dialog {
2191
2191
  border: none;
2192
2192
  border-radius: 12px;
@@ -2242,7 +2242,7 @@
2242
2242
  .recur-dialog__close:hover {
2243
2243
  background: rgba(0, 0, 0, 0.1);
2244
2244
  }
2245
- `,document.head.appendChild(e)}createDialogWithSkeleton(e){this.closeDialog(),this.injectDialogStyles();let t=document.createElement("dialog");t.id="recur-dialog",t.className="recur-dialog";let r=document.createElement("div");r.className="recur-dialog__content";let o=document.createElement("button");o.className="recur-dialog__close",o.innerHTML="\u2715",o.type="button",o.onclick=()=>{this.closeDialog(),e?.()};let i=document.createElement("div");i.id="recur-dialog-payment-container";let s=document.createElement("recur-payment-form-skeleton");return i.appendChild(s),r.appendChild(o),r.appendChild(i),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("cancel",a=>{a.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:i}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeDialog(){this.currentDialog&&(this.currentDialog.close(),this.currentDialog=null),this.currentDialogElement&&(this.currentDialogElement.close(),this.currentDialogElement.remove(),this.currentDialogElement=null)}closeModal(){this.closeDialog()}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to create portal session")}let o=await r.json();return{id:o.id,url:o.url||o.portalUrl,expiresAt:o.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function mt(n){return new N(n)}function gt(n){return N.create(n)}var Kt={init:mt,create:gt,RecurCheckout:N,RecurElements:z,createElements:Te};return Ct(jt);})();
2245
+ `,document.head.appendChild(e)}createDialogWithSkeleton(e){this.closeDialog(),this.injectDialogStyles();let t=document.createElement("dialog");t.id="recur-dialog",t.className="recur-dialog";let r=document.createElement("div");r.className="recur-dialog__content";let o=document.createElement("button");o.className="recur-dialog__close",o.innerHTML="\u2715",o.type="button",o.onclick=()=>{this.closeDialog(),e?.()};let i=document.createElement("div");i.id="recur-dialog-payment-container";let s=document.createElement("recur-payment-form-skeleton");return i.appendChild(s),r.appendChild(o),r.appendChild(i),t.appendChild(r),document.body.appendChild(t),t.showModal(),t.addEventListener("cancel",a=>{a.preventDefault(),this.closeDialog(),e?.()}),this.currentDialogElement=t,{dialog:t,container:i}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeDialog(){this.currentDialog&&(this.currentDialog.close(),this.currentDialog=null),this.currentDialogElement&&(this.currentDialogElement.close(),this.currentDialogElement.remove(),this.currentDialogElement=null)}closeModal(){this.closeDialog()}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let i=await r.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to create portal session")}let o=await r.json();return{id:o.id,url:o.url||o.portalUrl,expiresAt:o.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function ht(n){return new O(n)}function gt(n){return O.create(n)}var Kt={init:ht,create:gt,RecurCheckout:O,RecurElements:z,createElements:Te};return Et(jt);})();
2246
2246
  /*! Bundled license information:
2247
2247
 
2248
2248
  lit-html/node/lit-html.js:
package/dist/server.cjs CHANGED
@@ -11,16 +11,20 @@ var RecurAPIError = class extends Error {
11
11
  __publicField(this, "type");
12
12
  __publicField(this, "code");
13
13
  __publicField(this, "statusCode");
14
+ __publicField(this, "docUrl");
15
+ __publicField(this, "details");
14
16
  this.name = "RecurAPIError";
15
17
  this.type = error.type;
16
18
  this.code = error.code;
17
19
  this.statusCode = statusCode;
20
+ this.docUrl = error.doc_url;
21
+ this.details = error.details;
18
22
  }
19
23
  };
20
24
 
21
25
  // package.json
22
26
  var package_default = {
23
- version: "0.12.0"};
27
+ version: "0.13.0"};
24
28
 
25
29
  // src/server/resources/portal.ts
26
30
  var SDK_VERSION = package_default.version;
package/dist/server.d.cts CHANGED
@@ -92,16 +92,49 @@ interface PortalSession {
92
92
  */
93
93
  createdAt: string;
94
94
  }
95
+ /**
96
+ * Standard API error codes from Recur API
97
+ *
98
+ * These codes match the backend error codes for consistent error handling.
99
+ */
100
+ type ApiErrorCode = 'bad_request' | 'unauthorized' | 'payment_required' | 'forbidden' | 'not_found' | 'conflict' | 'validation_error' | 'rate_limit_exceeded' | 'internal_server_error';
101
+ /**
102
+ * Details for duplicate subscription errors (conflict)
103
+ */
104
+ interface DuplicateSubscriptionDetails {
105
+ /**
106
+ * ID of the existing subscription
107
+ */
108
+ existing_subscription_id: string;
109
+ /**
110
+ * Status of the existing subscription
111
+ */
112
+ status: string;
113
+ }
95
114
  interface RecurError {
96
115
  type: 'authentication_error' | 'invalid_request_error' | 'api_error';
97
- code: string;
116
+ /**
117
+ * Error code - see ApiErrorCode for standard codes
118
+ */
119
+ code: ApiErrorCode | string;
98
120
  message: string;
99
- details?: unknown;
121
+ /**
122
+ * URL to relevant documentation
123
+ */
124
+ doc_url?: string;
125
+ /**
126
+ * Additional error details
127
+ *
128
+ * For 'conflict' errors: contains DuplicateSubscriptionDetails
129
+ */
130
+ details?: (DuplicateSubscriptionDetails | Record<string, unknown>)[];
100
131
  }
101
132
  declare class RecurAPIError extends Error {
102
133
  readonly type: string;
103
134
  readonly code: string;
104
135
  readonly statusCode: number;
136
+ readonly docUrl?: string;
137
+ readonly details?: unknown[];
105
138
  constructor(error: RecurError, statusCode: number);
106
139
  }
107
140
  /**
@@ -435,4 +468,4 @@ declare class Recur {
435
468
  constructor(secretKey: string, options?: Omit<RecurConfig, 'secretKey'>);
436
469
  }
437
470
 
438
- export { type CustomerIdentifier, type Entitlement, type EntitlementCheckOptions, type EntitlementCheckResult, type EntitlementListOptions, type EntitlementListResult, type EntitlementStatus, type EntitlementSubscription, type PortalSession, type PortalSessionCreateParams, Recur, RecurAPIError, type RecurConfig, type RecurError };
471
+ export { type ApiErrorCode, type CustomerIdentifier, type DuplicateSubscriptionDetails, type Entitlement, type EntitlementCheckOptions, type EntitlementCheckResult, type EntitlementListOptions, type EntitlementListResult, type EntitlementStatus, type EntitlementSubscription, type PortalSession, type PortalSessionCreateParams, Recur, RecurAPIError, type RecurConfig, type RecurError };
package/dist/server.d.ts CHANGED
@@ -92,16 +92,49 @@ interface PortalSession {
92
92
  */
93
93
  createdAt: string;
94
94
  }
95
+ /**
96
+ * Standard API error codes from Recur API
97
+ *
98
+ * These codes match the backend error codes for consistent error handling.
99
+ */
100
+ type ApiErrorCode = 'bad_request' | 'unauthorized' | 'payment_required' | 'forbidden' | 'not_found' | 'conflict' | 'validation_error' | 'rate_limit_exceeded' | 'internal_server_error';
101
+ /**
102
+ * Details for duplicate subscription errors (conflict)
103
+ */
104
+ interface DuplicateSubscriptionDetails {
105
+ /**
106
+ * ID of the existing subscription
107
+ */
108
+ existing_subscription_id: string;
109
+ /**
110
+ * Status of the existing subscription
111
+ */
112
+ status: string;
113
+ }
95
114
  interface RecurError {
96
115
  type: 'authentication_error' | 'invalid_request_error' | 'api_error';
97
- code: string;
116
+ /**
117
+ * Error code - see ApiErrorCode for standard codes
118
+ */
119
+ code: ApiErrorCode | string;
98
120
  message: string;
99
- details?: unknown;
121
+ /**
122
+ * URL to relevant documentation
123
+ */
124
+ doc_url?: string;
125
+ /**
126
+ * Additional error details
127
+ *
128
+ * For 'conflict' errors: contains DuplicateSubscriptionDetails
129
+ */
130
+ details?: (DuplicateSubscriptionDetails | Record<string, unknown>)[];
100
131
  }
101
132
  declare class RecurAPIError extends Error {
102
133
  readonly type: string;
103
134
  readonly code: string;
104
135
  readonly statusCode: number;
136
+ readonly docUrl?: string;
137
+ readonly details?: unknown[];
105
138
  constructor(error: RecurError, statusCode: number);
106
139
  }
107
140
  /**
@@ -435,4 +468,4 @@ declare class Recur {
435
468
  constructor(secretKey: string, options?: Omit<RecurConfig, 'secretKey'>);
436
469
  }
437
470
 
438
- export { type CustomerIdentifier, type Entitlement, type EntitlementCheckOptions, type EntitlementCheckResult, type EntitlementListOptions, type EntitlementListResult, type EntitlementStatus, type EntitlementSubscription, type PortalSession, type PortalSessionCreateParams, Recur, RecurAPIError, type RecurConfig, type RecurError };
471
+ export { type ApiErrorCode, type CustomerIdentifier, type DuplicateSubscriptionDetails, type Entitlement, type EntitlementCheckOptions, type EntitlementCheckResult, type EntitlementListOptions, type EntitlementListResult, type EntitlementStatus, type EntitlementSubscription, type PortalSession, type PortalSessionCreateParams, Recur, RecurAPIError, type RecurConfig, type RecurError };
package/dist/server.js CHANGED
@@ -9,16 +9,20 @@ var RecurAPIError = class extends Error {
9
9
  __publicField(this, "type");
10
10
  __publicField(this, "code");
11
11
  __publicField(this, "statusCode");
12
+ __publicField(this, "docUrl");
13
+ __publicField(this, "details");
12
14
  this.name = "RecurAPIError";
13
15
  this.type = error.type;
14
16
  this.code = error.code;
15
17
  this.statusCode = statusCode;
18
+ this.docUrl = error.doc_url;
19
+ this.details = error.details;
16
20
  }
17
21
  };
18
22
 
19
23
  // package.json
20
24
  var package_default = {
21
- version: "0.12.0"};
25
+ version: "0.13.0"};
22
26
 
23
27
  // src/server/resources/portal.ts
24
28
  var SDK_VERSION = package_default.version;
package/dist/widget.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var RecurWidgetScript=(()=>{var g=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var v=(e,t)=>{for(var i in t)g(e,i,{get:t[i],enumerable:!0})},E=(e,t,i,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of x(t))!y.call(e,n)&&n!==i&&g(e,n,{get:()=>t[n],enumerable:!(o=w(t,n))||o.enumerable});return e};var C=e=>E(g({},"__esModule",{value:!0}),e);var L={};v(L,{default:()=>U});var d={text:"\u8A02\u95B1\u652F\u6301",color:"#667eea",textColor:"#ffffff",position:"right",xMargin:18,yMargin:18,embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},r=null,a=null,l=null,u=null;function k(){let e=document.querySelectorAll("script[data-product]"),t=e[e.length-1];if(!t)return console.error("[Recur Widget] Missing data-product attribute on script tag"),null;let i=t.getAttribute("data-key"),o=t.getAttribute("data-product");return i?o?{key:i,product:o,text:t.getAttribute("data-text")||d.text,color:t.getAttribute("data-color")||d.color,textColor:t.getAttribute("data-text-color")||d.textColor,position:t.getAttribute("data-position")||d.position,xMargin:parseInt(t.getAttribute("data-x-margin")||String(d.xMargin),10),yMargin:parseInt(t.getAttribute("data-y-margin")||String(d.yMargin),10),embedUrl:t.getAttribute("data-embed-url")||d.embedUrl,apiUrl:t.getAttribute("data-api-url")||d.apiUrl}:(console.error("[Recur Widget] Missing data-product attribute on script tag"),null):(console.error("[Recur Widget] Missing data-key attribute on script tag"),null)}function M(){if(!r)return;let e=window.location.hostname;(e==="localhost"||e==="127.0.0.1"||e.includes(".local"))&&(r.embedUrl=`${window.location.protocol}//${e}:3002`,r.apiUrl=`${window.location.protocol}//${e}:3000/api`)}function _(){if(!r||document.getElementById("recur-widget-styles"))return;let e=document.createElement("style");e.id="recur-widget-styles",e.textContent=`
1
+ "use strict";var RecurWidgetScript=(()=>{var g=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var v=(e,t)=>{for(var o in t)g(e,o,{get:t[o],enumerable:!0})},k=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of x(t))!y.call(e,n)&&n!==o&&g(e,n,{get:()=>t[n],enumerable:!(i=w(t,n))||i.enumerable});return e};var E=e=>k(g({},"__esModule",{value:!0}),e);var W={};v(W,{default:()=>S});var d={text:"\u8A02\u95B1\u652F\u6301",color:"#667eea",textColor:"#ffffff",position:"right",xMargin:18,yMargin:18,embedUrl:"https://embed.recur.tw",apiUrl:"https://api.recur.tw"},r=null,a=null,l=null,u=null;function C(){let e=document.querySelectorAll("script[data-product]"),t=e[e.length-1];if(!t)return console.error("[Recur Widget] Missing data-product attribute on script tag"),null;let o=t.getAttribute("data-key"),i=t.getAttribute("data-product");return o?i?{key:o,product:i,text:t.getAttribute("data-text")||d.text,color:t.getAttribute("data-color")||d.color,textColor:t.getAttribute("data-text-color")||d.textColor,position:t.getAttribute("data-position")||d.position,xMargin:parseInt(t.getAttribute("data-x-margin")||String(d.xMargin),10),yMargin:parseInt(t.getAttribute("data-y-margin")||String(d.yMargin),10),embedUrl:t.getAttribute("data-embed-url")||d.embedUrl,apiUrl:t.getAttribute("data-api-url")||d.apiUrl}:(console.error("[Recur Widget] Missing data-product attribute on script tag"),null):(console.error("[Recur Widget] Missing data-key attribute on script tag"),null)}function M(){if(!r)return;let e=window.location.hostname;(e==="localhost"||e==="127.0.0.1"||e.includes(".local"))&&(r.embedUrl=`${window.location.protocol}//${e}:3002`,r.apiUrl=`${window.location.protocol}//${e}:3000/api`)}function R(){if(!r||document.getElementById("recur-widget-styles"))return;let e=document.createElement("style");e.id="recur-widget-styles",e.textContent=`
2
2
  .recur-widget-button {
3
3
  position: fixed;
4
4
  bottom: ${r.yMargin}px;
@@ -123,10 +123,10 @@
123
123
  max-height: 95vh;
124
124
  }
125
125
  }
126
- `,document.head.appendChild(e)}function R(){if(!r||a)return;let e=document.createElement("button");e.className="recur-widget-button",e.setAttribute("aria-label",r.text),e.innerHTML=`
126
+ `,document.head.appendChild(e)}function _(){if(!r||a)return;let e=document.createElement("button");e.className="recur-widget-button",e.setAttribute("aria-label",r.text),e.innerHTML=`
127
127
  <svg class="recur-widget-button__icon" viewBox="0 0 24 24" fill="currentColor">
128
128
  <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
129
129
  </svg>
130
130
  <span>${r.text}</span>
131
- `,e.addEventListener("click",f),document.body.appendChild(e),a=e}async function A(){if(!r)throw new Error("Widget not configured");let e=await fetch(`${r.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":r.key,"X-Recur-Embed-Domain":r.embedUrl,"X-Recur-SDK-Type":"widget.js","X-Recur-Source":window.location.origin},body:JSON.stringify({productId:r.product})});if(!e.ok){let i=await e.json().catch(()=>({}));throw new Error(i.error?.message||i.error||"Failed to create checkout")}let t=await e.json();return{id:t.checkout.id,clientSecret:t.checkout.client_secret}}function S(e){if(!r)return;c();let t=document.createElement("dialog");t.className="recur-widget-dialog";let i=document.createElement("div");i.className="recur-widget-dialog__header";let o=document.createElement("button");o.className="recur-widget-dialog__close",o.innerHTML="&times;",o.type="button",o.setAttribute("aria-label","Close"),o.onclick=()=>{c(),s("recur:close",{})},i.appendChild(o);let n=document.createElement("iframe");n.className="recur-widget-dialog__iframe",n.src=e,n.setAttribute("allow","payment"),n.setAttribute("title","Recur Checkout"),t.appendChild(i),t.appendChild(n),document.body.appendChild(t),l=t,u=n,t.showModal(),document.body.style.overflow="hidden",t.addEventListener("cancel",b=>{b.preventDefault(),c(),s("recur:close",{})}),window.addEventListener("message",m)}function c(){l&&(l.close(),l.remove(),l=null),u=null,document.body.style.overflow="",window.removeEventListener("message",m)}function m(e){if(!e.origin.includes("recur.tw")&&!e.origin.includes("localhost"))return;let{type:t,data:i}=e.data||{};switch(t){case"RECUR_PAYMENT_SUCCESS":c(),s("recur:success",i);break;case"RECUR_PAYMENT_ERROR":s("recur:error",i);break;case"RECUR_PAYMENT_CANCEL":c(),s("recur:close",{});break;case"RECUR_RESIZE":u&&i?.height&&(u.style.height=`${Math.min(i.height+56,window.innerHeight*.9)}px`);break}}function s(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function f(){if(!(!r||!a)){a.setAttribute("data-loading","true");try{let e=await A(),t=new URL(`${r.embedUrl}/checkout`);t.searchParams.set("id",e.id),t.searchParams.set("key",r.key),t.searchParams.set("client_secret",e.clientSecret),S(t.toString())}catch(e){console.error("[Recur Widget] Error:",e),s("recur:error",{message:e.message})}finally{a.setAttribute("data-loading","false")}}}var h={open(){f()},close(){c()},show(){a&&(a.style.display="flex")},hide(){a&&(a.style.display="none")},destroy(){c(),a&&(a.remove(),a=null);let e=document.getElementById("recur-widget-styles");e&&e.remove()}};function p(){r=k(),r&&(M(),_(),R())}window.RecurWidget=h;document.readyState==="loading"?document.addEventListener("DOMContentLoaded",p):p();var U=h;return C(L);})();
131
+ `,e.addEventListener("click",f),document.body.appendChild(e),a=e}async function U(){if(!r)throw new Error("Widget not configured");let e=await fetch(`${r.apiUrl}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":r.key,"X-Recur-Embed-Domain":r.embedUrl,"X-Recur-SDK-Type":"widget.js","X-Recur-Source":window.location.origin},body:JSON.stringify({productId:r.product})});if(!e.ok){let o=await e.json().catch(()=>({}));throw new Error(o.error?.message||o.error||"Failed to create checkout")}let t=await e.json();return{id:t.checkout.id,clientSecret:t.checkout.client_secret}}function A(e){if(!r)return;c();let t=document.createElement("dialog");t.className="recur-widget-dialog";let o=document.createElement("div");o.className="recur-widget-dialog__header";let i=document.createElement("button");i.className="recur-widget-dialog__close",i.innerHTML="&times;",i.type="button",i.setAttribute("aria-label","Close"),i.onclick=()=>{c(),s("recur:close",{})},o.appendChild(i);let n=document.createElement("iframe");n.className="recur-widget-dialog__iframe",n.src=e,n.setAttribute("allow","payment"),n.setAttribute("title","Recur Checkout"),t.appendChild(o),t.appendChild(n),document.body.appendChild(t),l=t,u=n,t.showModal(),document.body.style.overflow="hidden",t.addEventListener("cancel",b=>{b.preventDefault(),c(),s("recur:close",{})}),window.addEventListener("message",m)}function c(){l&&(l.close(),l.remove(),l=null),u=null,document.body.style.overflow="",window.removeEventListener("message",m)}function m(e){if(!e.origin.includes("recur.tw")&&!e.origin.includes("localhost"))return;let{type:t,data:o}=e.data||{};switch(t){case"RECUR_PAYMENT_SUCCESS":c(),s("recur:success",o);break;case"RECUR_PAYMENT_ERROR":s("recur:error",o);break;case"RECUR_PAYMENT_CANCEL":c(),s("recur:close",{});break;case"RECUR_RESIZE":u&&o?.height&&(u.style.height=`${Math.min(o.height+56,window.innerHeight*.9)}px`);break}}function s(e,t){window.dispatchEvent(new CustomEvent(e,{detail:t}))}async function f(){if(!(!r||!a)){a.setAttribute("data-loading","true");try{let e=await U(),t=new URL(`${r.embedUrl}/checkout`);t.searchParams.set("id",e.id),t.searchParams.set("key",r.key),t.searchParams.set("client_secret",e.clientSecret),A(t.toString())}catch(e){console.error("[Recur Widget] Error:",e),s("recur:error",{message:e instanceof Error?e.message:"Unknown error"})}finally{a.setAttribute("data-loading","false")}}}var h={open(){f()},close(){c()},show(){a&&(a.style.display="flex")},hide(){a&&(a.style.display="none")},destroy(){c(),a&&(a.remove(),a=null);let e=document.getElementById("recur-widget-styles");e&&e.remove()}};function p(){r=C(),r&&(M(),R(),_())}window.RecurWidget=h;document.readyState==="loading"?document.addEventListener("DOMContentLoaded",p):p();var S=h;return E(W);})();
132
132
  /* Recur Widget - https://recur.tw */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-tw",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
5
5
  "type": "module",
6
6
  "private": false,