recur-tw 0.7.4 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1262,7 +1262,6 @@ var init_payment_form = __esm({
1262
1262
  margin: 0 0 12px 0;
1263
1263
  }
1264
1264
 
1265
- /* Slot \u6A23\u5F0F - \u9019\u6703\u61C9\u7528\u5230 slotted \u5167\u5BB9 */
1266
1265
  ::slotted(*) {
1267
1266
  display: block;
1268
1267
  }
@@ -2574,6 +2573,31 @@ async function loadPayUniSDK(isSandbox = false) {
2574
2573
  });
2575
2574
  return loadPromise;
2576
2575
  }
2576
+
2577
+ // src/case-utils.ts
2578
+ function snakeToCamel(str) {
2579
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
2580
+ }
2581
+ function toCamelCase(obj) {
2582
+ if (obj === null || obj === void 0) {
2583
+ return obj;
2584
+ }
2585
+ if (Array.isArray(obj)) {
2586
+ return obj.map((item) => toCamelCase(item));
2587
+ }
2588
+ if (obj instanceof Date) {
2589
+ return obj;
2590
+ }
2591
+ if (typeof obj === "object") {
2592
+ const result = {};
2593
+ for (const [key, value] of Object.entries(obj)) {
2594
+ const camelKey = snakeToCamel(key);
2595
+ result[camelKey] = toCamelCase(value);
2596
+ }
2597
+ return result;
2598
+ }
2599
+ return obj;
2600
+ }
2577
2601
  var RecurContext = React.createContext(null);
2578
2602
  function RecurProvider({ children, config: initialConfig = {} }) {
2579
2603
  const [config, setConfig] = React.useState({
@@ -2749,7 +2773,8 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2749
2773
  const errorMessage = errorData.details || errorData.error || "Failed to create checkout";
2750
2774
  throw new Error(errorMessage);
2751
2775
  }
2752
- const checkoutResult = await checkoutResponse.json();
2776
+ const rawCheckoutResult = await checkoutResponse.json();
2777
+ const checkoutResult = toCamelCase(rawCheckoutResult);
2753
2778
  console.log("[Recur SDK] Checkout created successfully:", checkoutResult);
2754
2779
  options.onSuccess?.(checkoutResult);
2755
2780
  console.log("[Recur SDK] Step 2: Extracting SDK token from checkout...");
@@ -2921,9 +2946,11 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2921
2946
  currentPeriodEnd: paymentResult.subscription.currentPeriodEnd
2922
2947
  });
2923
2948
  } else {
2949
+ const chargeId = paymentResult.charge?.id || paymentResult.paymentIntent?.id;
2950
+ const chargeStatus = paymentResult.charge?.status || "SUCCEEDED";
2924
2951
  options.onPaymentComplete({
2925
- id: paymentResult.checkout.id,
2926
- status: paymentResult.checkout.status,
2952
+ id: chargeId,
2953
+ status: chargeStatus,
2927
2954
  planId: checkoutResult.checkout.productId,
2928
2955
  amount: checkoutResult.checkout.amount,
2929
2956
  billingPeriod: checkoutResult.checkout.productType,
@@ -2990,7 +3017,8 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2990
3017
  const errorData = await response.json().catch(() => ({}));
2991
3018
  throw new Error(errorData.error || "Failed to fetch products");
2992
3019
  }
2993
- return await response.json();
3020
+ const rawResult = await response.json();
3021
+ return toCamelCase(rawResult);
2994
3022
  },
2995
3023
  [config]
2996
3024
  );
package/dist/index.js CHANGED
@@ -1256,7 +1256,6 @@ var init_payment_form = __esm({
1256
1256
  margin: 0 0 12px 0;
1257
1257
  }
1258
1258
 
1259
- /* Slot \u6A23\u5F0F - \u9019\u6703\u61C9\u7528\u5230 slotted \u5167\u5BB9 */
1260
1259
  ::slotted(*) {
1261
1260
  display: block;
1262
1261
  }
@@ -2568,6 +2567,31 @@ async function loadPayUniSDK(isSandbox = false) {
2568
2567
  });
2569
2568
  return loadPromise;
2570
2569
  }
2570
+
2571
+ // src/case-utils.ts
2572
+ function snakeToCamel(str) {
2573
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
2574
+ }
2575
+ function toCamelCase(obj) {
2576
+ if (obj === null || obj === void 0) {
2577
+ return obj;
2578
+ }
2579
+ if (Array.isArray(obj)) {
2580
+ return obj.map((item) => toCamelCase(item));
2581
+ }
2582
+ if (obj instanceof Date) {
2583
+ return obj;
2584
+ }
2585
+ if (typeof obj === "object") {
2586
+ const result = {};
2587
+ for (const [key, value] of Object.entries(obj)) {
2588
+ const camelKey = snakeToCamel(key);
2589
+ result[camelKey] = toCamelCase(value);
2590
+ }
2591
+ return result;
2592
+ }
2593
+ return obj;
2594
+ }
2571
2595
  var RecurContext = createContext(null);
2572
2596
  function RecurProvider({ children, config: initialConfig = {} }) {
2573
2597
  const [config, setConfig] = useState({
@@ -2743,7 +2767,8 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2743
2767
  const errorMessage = errorData.details || errorData.error || "Failed to create checkout";
2744
2768
  throw new Error(errorMessage);
2745
2769
  }
2746
- const checkoutResult = await checkoutResponse.json();
2770
+ const rawCheckoutResult = await checkoutResponse.json();
2771
+ const checkoutResult = toCamelCase(rawCheckoutResult);
2747
2772
  console.log("[Recur SDK] Checkout created successfully:", checkoutResult);
2748
2773
  options.onSuccess?.(checkoutResult);
2749
2774
  console.log("[Recur SDK] Step 2: Extracting SDK token from checkout...");
@@ -2915,9 +2940,11 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2915
2940
  currentPeriodEnd: paymentResult.subscription.currentPeriodEnd
2916
2941
  });
2917
2942
  } else {
2943
+ const chargeId = paymentResult.charge?.id || paymentResult.paymentIntent?.id;
2944
+ const chargeStatus = paymentResult.charge?.status || "SUCCEEDED";
2918
2945
  options.onPaymentComplete({
2919
- id: paymentResult.checkout.id,
2920
- status: paymentResult.checkout.status,
2946
+ id: chargeId,
2947
+ status: chargeStatus,
2921
2948
  planId: checkoutResult.checkout.productId,
2922
2949
  amount: checkoutResult.checkout.amount,
2923
2950
  billingPeriod: checkoutResult.checkout.productType,
@@ -2984,7 +3011,8 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2984
3011
  const errorData = await response.json().catch(() => ({}));
2985
3012
  throw new Error(errorData.error || "Failed to fetch products");
2986
3013
  }
2987
- return await response.json();
3014
+ const rawResult = await response.json();
3015
+ return toCamelCase(rawResult);
2988
3016
  },
2989
3017
  [config]
2990
3018
  );
package/dist/recur.umd.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var RecurCheckout=(()=>{var C=Object.defineProperty;var he=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var be=Object.prototype.hasOwnProperty;var ge=(c,e,t)=>e in c?C(c,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):c[e]=t;var b=(c,e)=>()=>(c&&(e=c(c=0)),e);var f=(c,e)=>{for(var t in e)C(c,t,{get:e[t],enumerable:!0})},ye=(c,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of fe(e))!be.call(c,i)&&i!==t&&C(c,i,{get:()=>e[i],enumerable:!(r=he(e,i))||r.enumerable});return c};var ve=c=>ye(C({},"__esModule",{value:!0}),c);var a=(c,e,t)=>ge(c,typeof e!="symbol"?e+"":e,t);var Y={};f(Y,{RecurLoadingSpinner:()=>T});var T,V=b(()=>{"use strict";T=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 I=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var ve=(n,e,t)=>e in n?I(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var g=(n,e)=>()=>(n&&(e=n(n=0)),e);var f=(n,e)=>{for(var t in e)I(n,t,{get:e[t],enumerable:!0})},ke=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ge(e))!ye.call(n,i)&&i!==t&&I(n,i,{get:()=>e[i],enumerable:!(r=be(e,i))||r.enumerable});return n};var we=n=>ke(I({},"__esModule",{value:!0}),n);var c=(n,e,t)=>ve(n,typeof e!="symbol"?e+"":e,t);var V={};f(V,{RecurLoadingSpinner:()=>R});var R,X=g(()=>{"use strict";R=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",T)});var X={};f(X,{RecurSuccessMessage:()=>I});var I,J=b(()=>{"use strict";I=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",R)});var J={};f(J,{RecurSuccessMessage:()=>P});var P,W=g(()=>{"use strict";P=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",I)});var W={};f(W,{RecurErrorDisplay:()=>R});var R,G=b(()=>{"use strict";R=class extends HTMLElement{static get observedAttributes(){return["error","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 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",P)});var G={};f(G,{RecurErrorDisplay:()=>L});var L,Z=g(()=>{"use strict";L=class extends HTMLElement{static get observedAttributes(){return["error","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 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;
@@ -211,7 +211,7 @@
211
211
  </button>
212
212
  `:""}
213
213
  </div>
214
- `,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",R)});var Z={};f(Z,{RecurSkeletonLoader:()=>P});var P,Q=b(()=>{"use strict";P=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`
214
+ `,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",L)});var Q={};f(Q,{RecurSkeletonLoader:()=>M});var M,ee=g(()=>{"use strict";M=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`
215
215
  <div class="skeleton-field">
216
216
  <div class="skeleton-label"></div>
217
217
  <div class="skeleton-input"></div>
@@ -377,7 +377,7 @@
377
377
  </style>
378
378
 
379
379
  ${e}
380
- `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",P)});var ee={};f(ee,{RecurPaymentFormSkeleton:()=>L});var L,te=b(()=>{"use strict";L=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
380
+ `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",M)});var te={};f(te,{RecurPaymentFormSkeleton:()=>U});var U,re=g(()=>{"use strict";U=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
381
381
  <style>
382
382
  :host {
383
383
  display: block;
@@ -644,7 +644,7 @@
644
644
  <p class="security-text">\u60A8\u7684\u4ED8\u6B3E\u8CC7\u8A0A\u7D93\u904E\u52A0\u5BC6\u4FDD\u8B77</p>
645
645
  </div>
646
646
  </div>
647
- `}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",L)});var re={};f(re,{RecurToast:()=>M,RecurToastContainer:()=>w});var M,g,w,ie=b(()=>{"use strict";M=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">
647
+ `}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",U)});var ie={};f(ie,{RecurToast:()=>_,RecurToastContainer:()=>E});var _,y,E,se=g(()=>{"use strict";_=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">
648
648
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
649
649
  </svg>`;case"error":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
650
650
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
@@ -764,7 +764,7 @@
764
764
  </svg>
765
765
  </button>
766
766
  </div>
767
- `,this.shadowRoot.querySelector(".toast-close")?.addEventListener("click",i=>{i.stopPropagation(),this.dismiss()}),this.shadowRoot.querySelector(".toast")?.addEventListener("click",()=>this.dismiss())}static show(e,t="info",r=5e3){let i=w.getInstance(),s=document.createElement("recur-toast");return s.setAttribute("message",e),s.setAttribute("type",t),s.setAttribute("duration",r.toString()),i.appendChild(s),s}},g=class g extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
767
+ `,this.shadowRoot.querySelector(".toast-close")?.addEventListener("click",i=>{i.stopPropagation(),this.dismiss()}),this.shadowRoot.querySelector(".toast")?.addEventListener("click",()=>this.dismiss())}static show(e,t="info",r=5e3){let i=E.getInstance(),s=document.createElement("recur-toast");return s.setAttribute("message",e),s.setAttribute("type",t),s.setAttribute("duration",r.toString()),i.appendChild(s),s}},y=class y extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
768
768
  <style>
769
769
  :host {
770
770
  position: fixed;
@@ -791,7 +791,7 @@
791
791
  </style>
792
792
 
793
793
  <slot></slot>
794
- `}static getInstance(){return g.instance||(g.instance=document.querySelector("recur-toast-container"),g.instance||(g.instance=document.createElement("recur-toast-container"),document.body.appendChild(g.instance))),g.instance}};a(g,"instance",null);w=g;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",M);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",w)});var se={};f(se,{RecurPaymentForm:()=>U});var U,oe=b(()=>{"use strict";U=class extends HTMLElement{constructor(){super();a(this,"containerId");a(this,"customStyles");a(this,"_isInitializing",!1);a(this,"_initializationAborted",!1);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","plan-name","amount","billing-period"]}attributeChangedCallback(t,r,i){t==="custom-styles"&&r!==i?(this.customStyles=i||"",this.updateCustomStyles()):r!==i&&this.updateCustomerInfoSection()}render(){this.shadowRoot.innerHTML=`
794
+ `}static getInstance(){return y.instance||(y.instance=document.querySelector("recur-toast-container"),y.instance||(y.instance=document.createElement("recur-toast-container"),document.body.appendChild(y.instance))),y.instance}};c(y,"instance",null);E=y;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",_);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",E)});var oe={};f(oe,{RecurPaymentForm:()=>A});var A,ne=g(()=>{"use strict";A=class extends HTMLElement{constructor(){super();c(this,"containerId");c(this,"customStyles");c(this,"_isInitializing",!1);c(this,"_initializationAborted",!1);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","plan-name","amount","billing-period"]}attributeChangedCallback(t,r,i){t==="custom-styles"&&r!==i?(this.customStyles=i||"",this.updateCustomStyles()):r!==i&&this.updateCustomerInfoSection()}render(){this.shadowRoot.innerHTML=`
795
795
  <style>
796
796
  :host {
797
797
  display: block;
@@ -835,7 +835,6 @@
835
835
  margin: 0 0 12px 0;
836
836
  }
837
837
 
838
- /* Slot \u6A23\u5F0F - \u9019\u6703\u61C9\u7528\u5230 slotted \u5167\u5BB9 */
839
838
  ::slotted(*) {
840
839
  display: block;
841
840
  }
@@ -900,7 +899,7 @@
900
899
  height: 36px !important;
901
900
  }
902
901
  `;t.textContent=this.customStyles+`
903
- `+r,this.appendChild(t);let i=this.createOrderSummarySection();i.slot="order-summary",this.appendChild(i);let s=this.createCustomerInfoSection();s.slot="customer-info",this.appendChild(s);let n=this.createCardFieldsSection();n.slot="card-fields",this.appendChild(n);let o=this.createActionsSection();o.slot="actions",this.appendChild(o)}updateCustomerInfoSection(){let t=this.querySelector('[slot="customer-info"]');if(t){let r=this.createCustomerInfoSection();r.slot="customer-info",t.replaceWith(r)}}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-custom-styles`);if(t){let r=`
902
+ `+r,this.appendChild(t);let i=this.createOrderSummarySection();i.slot="order-summary",this.appendChild(i);let s=this.createCustomerInfoSection();s.slot="customer-info",this.appendChild(s);let o=this.createCardFieldsSection();o.slot="card-fields",this.appendChild(o);let a=this.createActionsSection();a.slot="actions",this.appendChild(a)}updateCustomerInfoSection(){let t=this.querySelector('[slot="customer-info"]');if(t){let r=this.createCustomerInfoSection();r.slot="customer-info",t.replaceWith(r)}}updateCustomStyles(){let t=this.querySelector(`#${this.containerId}-custom-styles`);if(t){let r=`
904
903
  /* PAYUNi iframe \u5BB9\u5668\u9AD8\u5EA6\uFF08\u4F7F\u7528\u5BE6\u969B\u7684 container ID\uFF09 */
905
904
  #${this.containerId}-card-no,
906
905
  #${this.containerId}-card-exp,
@@ -908,7 +907,7 @@
908
907
  height: 36px !important;
909
908
  }
910
909
  `;t.textContent=this.customStyles+`
911
- `+r}}createOrderSummarySection(){let t=document.createElement("div");t.className="order-summary-section";let r=this.getAttribute("plan-name"),i=this.getAttribute("amount"),s=this.getAttribute("billing-period");if(!r||!i)return t;let o=s?{MONTHLY:"\u6708",QUARTERLY:"\u5B63",YEARLY:"\u5E74",WEEKLY:"\u9031"}[s]||s:"";return t.innerHTML=`
910
+ `+r}}createOrderSummarySection(){let t=document.createElement("div");t.className="order-summary-section";let r=this.getAttribute("plan-name"),i=this.getAttribute("amount"),s=this.getAttribute("billing-period");if(!r||!i)return t;let a=s?{MONTHLY:"\u6708",QUARTERLY:"\u5B63",YEARLY:"\u5E74",WEEKLY:"\u9031"}[s]||s:"";return t.innerHTML=`
912
911
  <style>
913
912
  .order-summary-section {
914
913
  background: #f7fafc;
@@ -963,10 +962,10 @@
963
962
  <span class="order-summary-label">\u8A02\u95B1\u65B9\u6848</span>
964
963
  <span class="order-summary-value">${r}</span>
965
964
  </div>
966
- ${o?`
965
+ ${a?`
967
966
  <div class="order-summary-item">
968
967
  <span class="order-summary-label">\u8A08\u8CBB\u9031\u671F</span>
969
- <span class="order-summary-value">\u6BCF${o}</span>
968
+ <span class="order-summary-value">\u6BCF${a}</span>
970
969
  </div>
971
970
  `:""}
972
971
  <div class="order-summary-item">
@@ -1221,10 +1220,10 @@
1221
1220
  >
1222
1221
  <span id="${this.containerId}-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>
1223
1222
  </button>
1224
- `,t}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 i=document.getElementById(`${this.containerId}-card-no`),s=document.getElementById(`${this.containerId}-card-exp`),n=document.getElementById(`${this.containerId}-card-cvc`);if(!i||!s||!n)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 o=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 o.start()}catch(l){if((l?.message?.includes("1008")||l?.message?.includes("timeout")||l?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw l}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),o.onUpdate?.(l=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",l);let u=l.status&&l.status.CardNo===!0&&l.status.CardExp===!0&&l.status.CardCvc===!0,y=document.getElementById(`${this.containerId}-submit-btn`);y&&(y.disabled=!u,console.log("[PaymentForm] Submit button disabled:",!u))}),this._initializationAborted?(console.log("[PaymentForm] Initialization aborted before saving session"),this._isInitializing=!1,null):(this._paymentSession=o,this.setupFormSubmission(),this._isInitializing=!1,o))}catch(i){throw this._isInitializing=!1,console.error("[PaymentForm] Failed to initialize payment:",i),i}}setupFormSubmission(){let t=document.getElementById(`${this.containerId}-submit-btn`);t&&t.addEventListener("click",async r=>{if(r.preventDefault(),t.classList.contains("loading"))return;let i,s,n=document.getElementById(`${this.containerId}-email`),o=document.getElementById(`${this.containerId}-name`);if(n&&o){if(i=n.value,s=o.value,!i||!s){this.showError("\u8ACB\u586B\u5BEB\u59D3\u540D\u548C\u96FB\u5B50\u90F5\u4EF6");return}}else if(i=this.getAttribute("customer-email")||void 0,s=this.getAttribute("customer-name")||void 0,!i||!s){this.showError("\u5BA2\u6236\u8CC7\u8A0A\u4E0D\u5B8C\u6574");return}this.clearError(),this.setButtonLoading(!0),this.dispatchEvent(new CustomEvent("submit",{detail:{customerEmail:i,customerName:s,paymentSession:this._paymentSession},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=`
1223
+ `,t}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 i=document.getElementById(`${this.containerId}-card-no`),s=document.getElementById(`${this.containerId}-card-exp`),o=document.getElementById(`${this.containerId}-card-cvc`);if(!i||!s||!o)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(l){if((l?.message?.includes("1008")||l?.message?.includes("timeout")||l?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw l}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),a.onUpdate?.(l=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",l);let d=l.status&&l.status.CardNo===!0&&l.status.CardExp===!0&&l.status.CardCvc===!0,v=document.getElementById(`${this.containerId}-submit-btn`);v&&(v.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(i){throw this._isInitializing=!1,console.error("[PaymentForm] Failed to initialize payment:",i),i}}setupFormSubmission(){let t=document.getElementById(`${this.containerId}-submit-btn`);t&&t.addEventListener("click",async r=>{if(r.preventDefault(),t.classList.contains("loading"))return;let i,s,o=document.getElementById(`${this.containerId}-email`),a=document.getElementById(`${this.containerId}-name`);if(o&&a){if(i=o.value,s=a.value,!i||!s){this.showError("\u8ACB\u586B\u5BEB\u59D3\u540D\u548C\u96FB\u5B50\u90F5\u4EF6");return}}else if(i=this.getAttribute("customer-email")||void 0,s=this.getAttribute("customer-name")||void 0,!i||!s){this.showError("\u5BA2\u6236\u8CC7\u8A0A\u4E0D\u5B8C\u6574");return}this.clearError(),this.setButtonLoading(!0),this.dispatchEvent(new CustomEvent("submit",{detail:{customerEmail:i,customerName:s,paymentSession:this._paymentSession},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=`
1225
1224
  <span class="recur-loading-spinner"></span>
1226
1225
  <span>\u8655\u7406\u4E2D...</span>
1227
- `):(r.classList.remove("loading"),r.disabled=!1,r.innerHTML='<span id="'+this.containerId+'-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>'))}resetButton(){this.setButtonLoading(!1)}showError(t){let r=this.querySelector(".recur-sdk__error-container");r||(r=document.createElement("div"),r.className="recur-sdk__error-container",r.style.cssText="margin-bottom: 16px;",this.insertBefore(r,this.firstChild));let i=document.createElement("recur-error-display");i.setAttribute("error",t),i.setAttribute("dismissible","true"),r.innerHTML="",r.appendChild(i),i.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",U)});var ne={};f(ne,{RecurCheckoutButton:()=>_});var _,ae=b(()=>{"use strict";_=class extends HTMLElement{constructor(){super();a(this,"_isLoading",!1);a(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),i=this.getAttribute("product-id"),s=this.getAttribute("success-url"),n=this.getAttribute("cancel-url");if(!r){this.dispatchError("Missing required attribute: publishable-key");return}if(!i){this.dispatchError("Missing required attribute: product-id");return}if(!s){this.dispatchError("Missing required attribute: success-url");return}if(!n){this.dispatchError("Missing required attribute: cancel-url");return}this._isLoading=!0,this.render(),this.setupEventListeners();try{let o=await this.createCheckoutSession({publishableKey:r,productId:i,successUrl:this.resolveUrl(s),cancelUrl:this.resolveUrl(n),customerEmail:this.getAttribute("customer-email")||void 0,mode:this.getAttribute("mode")});this.dispatchEvent(new CustomEvent("checkout-started",{detail:{sessionId:o.id,url:o.url},bubbles:!0,composed:!0})),window.location.href=o.url}catch(o){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(o.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,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1226
+ `):(r.classList.remove("loading"),r.disabled=!1,r.innerHTML='<span id="'+this.containerId+'-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>'))}resetButton(){this.setButtonLoading(!1)}showError(t){let r=this.querySelector(".recur-sdk__error-container");r||(r=document.createElement("div"),r.className="recur-sdk__error-container",r.style.cssText="margin-bottom: 16px;",this.insertBefore(r,this.firstChild));let i=document.createElement("recur-error-display");i.setAttribute("error",t),i.setAttribute("dismissible","true"),r.innerHTML="",r.appendChild(i),i.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",A)});var ae={};f(ae,{RecurCheckoutButton:()=>D});var D,ce=g(()=>{"use strict";D=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),i=this.getAttribute("product-id"),s=this.getAttribute("success-url"),o=this.getAttribute("cancel-url");if(!r){this.dispatchError("Missing required attribute: publishable-key");return}if(!i){this.dispatchError("Missing required attribute: product-id");return}if(!s){this.dispatchError("Missing required attribute: success-url");return}if(!o){this.dispatchError("Missing required attribute: cancel-url");return}this._isLoading=!0,this.render(),this.setupEventListeners();try{let a=await this.createCheckoutSession({publishableKey:r,productId:i,successUrl:this.resolveUrl(s),cancelUrl:this.resolveUrl(o),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,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1228
1227
  <style>
1229
1228
  :host {
1230
1229
  display: inline-block;
@@ -1323,7 +1322,7 @@
1323
1322
  ${this._isLoading?'<span class="spinner"></span>':""}
1324
1323
  <span>${this._isLoading?"\u8655\u7406\u4E2D...":t}</span>
1325
1324
  </button>
1326
- `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),i={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(i.mode=t.mode),t.customerEmail&&(i.customerEmail=t.customerEmail);let s=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(i)});if(!s.ok){let n=await s.json().catch(()=>({}));throw new Error(n.error?.message||`HTTP ${s.status}: Failed to create checkout session`)}return s.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",_)});var ce={};f(ce,{RecurPortalButton:()=>A});var A,le=b(()=>{"use strict";A=class extends HTMLElement{constructor(){super();a(this,"_isLoading",!1);a(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),i=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(i){await this.fetchAndRedirect(i);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,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1325
+ `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),i={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(i.mode=t.mode),t.customerEmail&&(i.customerEmail=t.customerEmail);let s=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(i)});if(!s.ok){let o=await s.json().catch(()=>({}));throw new Error(o.error?.message||`HTTP ${s.status}: Failed to create checkout session`)}return s.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",D)});var le={};f(le,{RecurPortalButton:()=>z});var z,de=g(()=>{"use strict";z=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),i=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(i){await this.fetchAndRedirect(i);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,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1327
1326
  <style>
1328
1327
  :host {
1329
1328
  display: inline-block;
@@ -1450,7 +1449,7 @@
1450
1449
  <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
1451
1450
  <circle cx="12" cy="7" r="4"/>
1452
1451
  </svg>
1453
- `}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"),i=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let s={};r&&(s.customerId=r),i&&(s.returnUrl=i);let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!n.ok){let u=await n.json().catch(()=>({}));throw new Error(u.error?.message||u.message||`HTTP ${n.status}: Failed to create portal session`)}let o=await n.json(),l=o.url||o.portalUrl;if(!l)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(l)}catch(s){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(s.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",A)});var Se={};f(Se,{RecurCheckout:()=>S,RecurElements:()=>k,createElements:()=>K,default:()=>Ee,init:()=>me});async function ke(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(V(),Y)),Promise.resolve().then(()=>(J(),X)),Promise.resolve().then(()=>(G(),W)),Promise.resolve().then(()=>(Q(),Z)),Promise.resolve().then(()=>(te(),ee)),Promise.resolve().then(()=>(ie(),re)),Promise.resolve().then(()=>(oe(),se)),Promise.resolve().then(()=>(ae(),ne)),Promise.resolve().then(()=>(le(),ce))]);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"&&ke();var D=class{constructor(e){a(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,i=e.productId||e.planId,s=e.productSlug;if(!i&&!s)throw new Error("Either productId or productSlug is required");let n={customerName:t,customerEmail:r};i&&(n.productId=i),s&&(n.productSlug=s);let o=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify(n)});if(!o.ok){let l=await o.json().catch(()=>({}));throw{code:l.error||"CHECKOUT_FAILED",message:l.message||"Failed to initiate checkout",details:l}}return await o.json()}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:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey}});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}}return await r.json()}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var z=class{constructor(e,t){a(this,"config");a(this,"options");a(this,"container");a(this,"checkoutId",null);a(this,"sdkToken",null);a(this,"sdkEnv","S");a(this,"payuniSDK",null);a(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.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();this.checkoutId=r.checkout.id,this.sdkToken=r.sdkToken,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
1452
+ `}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"),i=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let s={};r&&(s.customerId=r),i&&(s.returnUrl=i);let o=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok){let d=await o.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${o.status}: Failed to create portal session`)}let a=await o.json(),l=a.url||a.portalUrl;if(!l)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(l)}catch(s){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(s.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",z)});var Ie={};f(Ie,{RecurCheckout:()=>S,RecurElements:()=>x,createElements:()=>j,default:()=>Te,init:()=>pe});async function xe(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(X(),V)),Promise.resolve().then(()=>(W(),J)),Promise.resolve().then(()=>(Z(),G)),Promise.resolve().then(()=>(ee(),Q)),Promise.resolve().then(()=>(re(),te)),Promise.resolve().then(()=>(se(),ie)),Promise.resolve().then(()=>(ne(),oe)),Promise.resolve().then(()=>(ce(),ae)),Promise.resolve().then(()=>(de(),le))]);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"&&xe();function Ee(n){return n.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function b(n){if(n==null)return n;if(Array.isArray(n))return n.map(e=>b(e));if(n instanceof Date)return n;if(typeof n=="object"){let e={};for(let[t,r]of Object.entries(n)){let i=Ee(t);e[i]=b(r)}return e}return n}var H=class{constructor(e){c(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,i=e.productId||e.planId,s=e.productSlug;if(!i&&!s)throw new Error("Either productId or productSlug is required");let o={customerName:t,customerEmail:r};i&&(o.productId=i),s&&(o.productSlug=s);let a=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify(o)});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 l=await a.json();return b(l)}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:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey}});if(!r.ok){let s=await r.json().catch(()=>({}));throw{code:s.error||"FETCH_PRODUCTS_FAILED",message:s.message||"Failed to fetch products",details:s}}let i=await r.json();return b(i)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var $=class{constructor(e,t){c(this,"config");c(this,"options");c(this,"container");c(this,"checkoutId",null);c(this,"sdkToken",null);c(this,"sdkEnv","S");c(this,"payuniSDK",null);c(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.planId,customerEmail:this.options.customerEmail,customerName:this.options.customerName})});if(!t.ok){let s=await t.json().catch(()=>({}));throw new Error(s.error||"Failed to initialize checkout")}let r=await t.json(),i=b(r);this.checkoutId=i.checkout.id,this.sdkToken=i.sdkToken,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
1454
1453
  <div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
1455
1454
  <div class="recur-checkout-header" style="margin-bottom: 24px;">
1456
1455
  <h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
@@ -1520,21 +1519,21 @@
1520
1519
  </p>
1521
1520
  </form>
1522
1521
  </div>
1523
- `}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 i=r?.status;i&&(this.isFormValid=i.CardNo===!0&&i.CardExp===!0&&i.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 i=r.EncryptInfo||r.creditToken;if(!i)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let s=this.getBaseUrl(),n=await fetch(`${s}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:i,timestamp:r.HashTimestamp||r.timestamp})});if(!n.ok){let u=await n.json().catch(()=>({}));throw new Error(u.error||"Failed to process payment")}let o=await n.json(),l={subscription:{id:o.subscription?.id||o.charge?.id||"",status:o.success?"active":"failed",planId:this.options.planId,planName:"",amount:o.charge?.amount||0,billingPeriod:o.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(l),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 k=class{constructor(e){a(this,"publishableKey");a(this,"baseUrl");a(this,"embedUrl");a(this,"iframe",null);a(this,"container",null);a(this,"sessionId",null);a(this,"timestamp",null);a(this,"creditToken",null);a(this,"cardToken",null);a(this,"cardTimestamp",null);a(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=`
1522
+ `}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 i=r?.status;i&&(this.isFormValid=i.CardNo===!0&&i.CardExp===!0&&i.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 i=r.EncryptInfo||r.creditToken;if(!i)throw console.error("[Recur SDK] Missing payment token. Available fields:",Object.keys(r)),new Error("Missing payment token");let s=this.getBaseUrl(),o=await fetch(`${s}/v1/checkouts/${this.checkoutId}/pay`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({creditToken:i,timestamp:r.HashTimestamp||r.timestamp})});if(!o.ok){let d=await o.json().catch(()=>({}));throw new Error(d.error||"Failed to process payment")}let a=await o.json(),l={subscription:{id:a.subscription?.id||a.charge?.id||"",status:a.success?"active":"failed",planId:this.options.planId,planName:"",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(l),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 x=class{constructor(e){c(this,"publishableKey");c(this,"baseUrl");c(this,"embedUrl");c(this,"iframe",null);c(this,"container",null);c(this,"sessionId",null);c(this,"timestamp",null);c(this,"creditToken",null);c(this,"sdkToken",null);c(this,"cardToken",null);c(this,"cardTimestamp",null);c(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=`
1524
1523
  width: 100%;
1525
1524
  border: none;
1526
1525
  min-height: 200px;
1527
1526
  display: block;
1528
1527
  user-select: none;
1529
1528
  transition: height 0.35s ease, opacity 0.4s ease 0.1s;
1530
- `.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,i)=>{let s=setTimeout(()=>{i(new Error("Elements initialization timeout"))},3e4),n=()=>{clearTimeout(s),this.off("ready",n),r()},o=l=>{clearTimeout(s),this.off("error",o),i(new Error(l.message||"Elements initialization failed"))};this.on("ready",n),this.on("error",o)})}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(i=>i(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.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 i=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),s=o=>{clearTimeout(i),this.off("tokenized",s),t(o)},n=o=>{clearTimeout(i),this.off("error",n),r(new Error(o.message||"Tokenization failed"))};this.on("tokenized",s),this.on("error",n)})}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,sdkToken:this.cardToken,timestamp:this.cardTimestamp,creditToken:this.creditToken,productId:e.productId,email:e.email,name:e.name,metadata:e.metadata})}),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.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function K(c){return new k(c)}var xe="https://vendor.payuni.com.tw/sdk/uni-payment.js",we="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",de=!1,H=!1,E=null;async function ue(c=!1){return de&&window.UniPayment?Promise.resolve():(H&&E||(H=!0,E=new Promise((e,t)=>{let r=document.createElement("script");r.src=c?we:xe,r.async=!0,r.onload=()=>{de=!0,H=!1,e()},r.onerror=()=>{H=!1,E=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),E)}var S=class{constructor(e){a(this,"core");a(this,"currentModal",null);a(this,"currentIframe",null);a(this,"currentModalOverlay",null);this.core=new D(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 z(t,e).render()}async redirectToCheckout(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let l=window.location.hostname;if(l==="localhost"||l.includes(".test")||l.includes(".local")||l==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");let s={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(s.productId=e.productId),e.productSlug&&(s.productSlug=e.productSlug),e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail),e.customerName&&(s.customerName=e.customerName),e.externalCustomerId&&(s.externalCustomerId=e.externalCustomerId);let n=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(s)});if(!n.ok){let l=await n.json().catch(()=>({}));throw new Error(l.error?.message||"Failed to create checkout session")}let o=await n.json();window.location.href=o.url}async createCheckoutSession(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let o=window.location.hostname;if(o==="localhost"||o.includes(".test")||o.includes(".local")||o==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");let s={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(s.productId=e.productId),e.productSlug&&(s.productSlug=e.productSlug),e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail),e.customerName&&(s.customerName=e.customerName),e.externalCustomerId&&(s.externalCustomerId=e.externalCustomerId);let n=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(s)});if(!n.ok){let o=await n.json().catch(()=>({}));throw new Error(o.error?.message||"Failed to create checkout session")}return n.json()}async checkout(e){let t=this.core.getConfig(),r=null,i=e.productId||e.planId,s=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:i,productSlug:s,mode:e.mode}),!i&&!s)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");if(!e.customerName)throw new Error("customerName is required");if(!e.customerEmail)throw new Error("customerEmail is required");let n=this.getBaseUrl();console.log("[Recur SDK] Base URL:",n);let o={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},l=e.mode||"modal",u=null;if(l==="modal"){let m=this.createModalWithSkeleton(e.onClose);r=m.overlay,u=m.container}else if(l==="iframe"){if(u=this.getEmbeddedContainer(e.container),!u)throw new Error("Container is required for iframe mode");u.innerHTML="";let m=document.createElement("recur-payment-form-skeleton");u.appendChild(m)}console.log("[Recur SDK] Step 1: Creating checkout session...");let y={customerName:e.customerName,customerEmail:e.customerEmail};i&&(y.productId=i),s&&(y.productSlug=s),e.externalCustomerId&&(y.externalCustomerId=e.externalCustomerId);let $=await fetch(`${n}/v1/checkouts`,{method:"POST",headers:o,body:JSON.stringify(y)});if(!$.ok){let m=await $.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",m);let N=m.details||m.error||"Failed to create checkout";throw new Error(N)}let d=await $.json();if(console.log("[Recur SDK] Checkout created successfully:",d),e.onSuccess?.(d),l==="redirect"){let m=`https://checkout.recur.tw/${d.checkout.id}`;console.log("[Recur SDK] Redirecting to hosted checkout:",m),window.location.href=m;return}if(console.log("[Recur SDK] Step 2: Extracting SDK token..."),!d.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let j=!0;if(await ue(j),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..."),!u)throw new Error("Payment container not available");u.innerHTML="";let p=document.createElement("recur-payment-form");if(p.setAttribute("container-id",u.id||"recur-payment-container"),e.customerName&&p.setAttribute("customer-name",e.customerName),e.customerEmail&&p.setAttribute("customer-email",e.customerEmail),d.plan?.name&&p.setAttribute("plan-name",d.plan.name),d.checkout?.amount&&p.setAttribute("amount",d.checkout.amount.toString()),d.plan?.billingPeriod&&p.setAttribute("billing-period",d.plan.billingPeriod),p.setAttribute("custom-styles",`
1529
+ `.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,i)=>{let s=setTimeout(()=>{i(new Error("Elements initialization timeout"))},3e4),o=()=>{clearTimeout(s),this.off("ready",o),r()},a=l=>{clearTimeout(s),this.off("error",a),i(new Error(l.message||"Elements initialization failed"))};this.on("ready",o),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(i=>i(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 i=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),s=a=>{clearTimeout(i),this.off("tokenized",s),t(a)},o=a=>{clearTimeout(i),this.off("error",o),r(new Error(a.message||"Tokenization failed"))};this.on("tokenized",s),this.on("error",o)})}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 j(n){return new x(n)}var Ce="https://vendor.payuni.com.tw/sdk/uni-payment.js",Se="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",ue=!1,N=!1,C=null;async function me(n=!1){return ue&&window.UniPayment?Promise.resolve():(N&&C||(N=!0,C=new Promise((e,t)=>{let r=document.createElement("script");r.src=n?Se:Ce,r.async=!0,r.onload=()=>{ue=!0,N=!1,e()},r.onerror=()=>{N=!1,C=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),C)}var S=class{constructor(e){c(this,"core");c(this,"currentModal",null);c(this,"currentIframe",null);c(this,"currentModalOverlay",null);this.core=new H(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 $(t,e).render()}async redirectToCheckout(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let l=window.location.hostname;if(l==="localhost"||l.includes(".test")||l.includes(".local")||l==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");let s={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(s.productId=e.productId),e.productSlug&&(s.productSlug=e.productSlug),e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail),e.customerName&&(s.customerName=e.customerName),e.externalCustomerId&&(s.externalCustomerId=e.externalCustomerId);let o=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(s)});if(!o.ok){let l=await o.json().catch(()=>({}));throw new Error(l.error?.message||"Failed to create checkout session")}let a=await o.json();window.location.href=a.url}async createCheckoutSession(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let l=window.location.hostname;if(l==="localhost"||l.includes(".test")||l.includes(".local")||l==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");let s={successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.productId&&(s.productId=e.productId),e.productSlug&&(s.productSlug=e.productSlug),e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail),e.customerName&&(s.customerName=e.customerName),e.externalCustomerId&&(s.externalCustomerId=e.externalCustomerId);let o=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(s)});if(!o.ok){let l=await o.json().catch(()=>({}));throw new Error(l.error?.message||"Failed to create checkout session")}let a=await o.json();return b(a)}async checkout(e){let t=this.core.getConfig(),r=null,i=e.productId||e.planId,s=e.productSlug;try{if(console.log("[Recur SDK] Starting checkout flow...",{productId:i,productSlug:s,mode:e.mode}),!i&&!s)throw new Error("Either productId or productSlug is required");if(!t.publishableKey)throw new Error("publishableKey is required");if(!e.customerName)throw new Error("customerName is required");if(!e.customerEmail)throw new Error("customerEmail is required");let o=this.getBaseUrl();console.log("[Recur SDK] Base URL:",o);let a={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},l=e.mode||"modal",d=null;if(l==="modal"){let m=this.createModalWithSkeleton(e.onClose);r=m.overlay,d=m.container}else if(l==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let m=document.createElement("recur-payment-form-skeleton");d.appendChild(m)}console.log("[Recur SDK] Step 1: Creating checkout session...");let v={customerName:e.customerName,customerEmail:e.customerEmail};i&&(v.productId=i),s&&(v.productSlug=s),e.externalCustomerId&&(v.externalCustomerId=e.externalCustomerId);let B=await fetch(`${o}/v1/checkouts`,{method:"POST",headers:a,body:JSON.stringify(v)});if(!B.ok){let m=await B.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",m);let O=m.details||m.error||"Failed to create checkout";throw new Error(O)}let he=await B.json(),u=b(he);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),l==="redirect"){let m=`https://checkout.recur.tw/${u.checkout.id}`;console.log("[Recur SDK] Redirecting to hosted checkout:",m),window.location.href=m;return}if(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 q=!0;if(await me(q),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 h=document.createElement("recur-payment-form");if(h.setAttribute("container-id",d.id||"recur-payment-container"),e.customerName&&h.setAttribute("customer-name",e.customerName),e.customerEmail&&h.setAttribute("customer-email",e.customerEmail),u.plan?.name&&h.setAttribute("plan-name",u.plan.name),u.checkout?.amount&&h.setAttribute("amount",u.checkout.amount.toString()),u.plan?.billingPeriod&&h.setAttribute("billing-period",u.plan.billingPeriod),h.setAttribute("custom-styles",`
1531
1530
  .form-input-focus {
1532
1531
  border-color: var(--ring, hsl(215 16% 47%)) !important;
1533
1532
  outline: 0 !important;
1534
1533
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
1535
1534
  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
1536
1535
  }
1537
- `),u.appendChild(p),await new Promise(m=>setTimeout(m,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await p.initializePayment(d.sdkToken,j?"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..."),p.addEventListener("submit",(async m=>{console.log("[Recur SDK] Form submitted");let N=m,{paymentSession:pe}=N.detail;try{let v=await pe.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let B=v.HashTimestamp||v.timestamp,F={};if(d.checkout.productType==="SUBSCRIPTION"){let x=d.creditToken,q=d.sdkTimestamp;if(!x)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");F={creditToken:x,timestamp:q||B},console.log("[Recur SDK] Using creditToken from checkout:",x.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",q?"from checkout (sdkTimestamp)":"from tradeResult")}let O=await fetch(`${n}/v1/checkouts/${d.checkout.id}/pay`,{method:"POST",headers:o,body:JSON.stringify(F)});if(!O.ok){let x=await O.json().catch(()=>({}));throw new Error(x.error||"Failed to execute payment")}let h=await O.json();if(console.log("[Recur SDK] Payment executed:",h),h.requires3D&&h.redirectUrl){console.log("[Recur SDK] 3D verification required"),window.location.href=h.redirectUrl;return}e.onPaymentComplete&&(h.subscription?e.onPaymentComplete({id:h.subscription.id,status:h.subscription.status,planId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:h.subscription.billingPeriod,currentPeriodStart:h.subscription.currentPeriodStart,currentPeriodEnd:h.subscription.currentPeriodEnd}):e.onPaymentComplete({id:h.checkout.id,status:h.checkout.status,planId:d.checkout.productId,amount:d.checkout.amount,billingPeriod:d.checkout.productType})),console.log("[Recur SDK] Checkout flow completed successfully!"),p.resetButton?.(),r&&r.remove()}catch(v){console.error("[Recur SDK] Payment error:",v);let B={code:"PAYMENT_FAILED",message:v instanceof Error?v.message:"Payment failed"};e.onError?.(B),p.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(n){console.error("[Recur SDK] Checkout error:",n),r&&r.remove();let o={code:"CHECKOUT_ERROR",message:n instanceof Error?n.message:"An unknown error occurred"};throw e.onError?.(o),n}}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"}createModalWithSkeleton(e){this.closeModal();let t=document.createElement("div");t.id="recur-modal-overlay",t.style.cssText=`
1536
+ `),d.appendChild(h),await new Promise(m=>setTimeout(m,100)),console.log("[Recur SDK] Step 5: Initializing PAYUNi SDK..."),await h.initializePayment(u.sdkToken,q?"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..."),h.addEventListener("submit",(async m=>{console.log("[Recur SDK] Form submitted");let O=m,{paymentSession:fe}=O.detail;try{let w=await fe.getTradeResult();console.log("[Recur SDK] Trade result received"),console.log("[Recur SDK] Executing payment...");let K=w.HashTimestamp||w.timestamp,Y={};if(u.checkout.productType==="SUBSCRIPTION"){let k=u.creditToken,T=u.sdkTimestamp;if(!k)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");Y={creditToken:k,timestamp:T||K},console.log("[Recur SDK] Using creditToken from checkout:",k.substring(0,30)+"..."),console.log("[Recur SDK] Using timestamp:",T?"from checkout (sdkTimestamp)":"from tradeResult")}let F=await fetch(`${o}/v1/checkouts/${u.checkout.id}/pay`,{method:"POST",headers:a,body:JSON.stringify(Y)});if(!F.ok){let k=await F.json().catch(()=>({}));throw new Error(k.error||"Failed to execute payment")}let p=await F.json();if(console.log("[Recur SDK] Payment executed:",p),p.requires3D&&p.redirectUrl){console.log("[Recur SDK] 3D verification required"),window.location.href=p.redirectUrl;return}if(e.onPaymentComplete)if(p.subscription)e.onPaymentComplete({id:p.subscription.id,status:p.subscription.status,planId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:p.subscription.billingPeriod,currentPeriodStart:p.subscription.currentPeriodStart,currentPeriodEnd:p.subscription.currentPeriodEnd});else{let k=p.charge?.id||p.paymentIntent?.id,T=p.charge?.status||"SUCCEEDED";e.onPaymentComplete({id:k,status:T,planId:u.checkout.productId,amount:u.checkout.amount,billingPeriod:u.checkout.productType})}console.log("[Recur SDK] Checkout flow completed successfully!"),h.resetButton?.(),r&&r.remove()}catch(w){console.error("[Recur SDK] Payment error:",w);let K={code:"PAYMENT_FAILED",message:w instanceof Error?w.message:"Payment failed"};e.onError?.(K),h.resetButton?.()}})),console.log("[Recur SDK] Checkout flow initialized, waiting for user input...")}catch(o){console.error("[Recur SDK] Checkout error:",o),r&&r.remove();let a={code:"CHECKOUT_ERROR",message:o instanceof Error?o.message:"An unknown error occurred"};throw e.onError?.(a),o}}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"}createModalWithSkeleton(e){this.closeModal();let t=document.createElement("div");t.id="recur-modal-overlay",t.style.cssText=`
1538
1537
  position: fixed;
1539
1538
  top: 0;
1540
1539
  left: 0;
@@ -1573,7 +1572,7 @@
1573
1572
  border-radius: 50%;
1574
1573
  z-index: 10;
1575
1574
  transition: background 0.2s;
1576
- `,i.onmouseover=()=>{i.style.background="rgba(0, 0, 0, 0.1)"},i.onmouseout=()=>{i.style.background="rgba(0, 0, 0, 0.05)"},i.onclick=()=>{t.remove(),e?.()};let s=document.createElement("div");s.id="recur-modal-payment-container";let n=document.createElement("recur-payment-form-skeleton");return s.appendChild(n),r.appendChild(i),r.appendChild(s),t.appendChild(r),document.body.appendChild(t),this.currentModalOverlay=t,{overlay:t,container:s}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeModal(){this.currentModal&&(this.currentModal.close(),this.currentModal=null),this.currentModalOverlay&&(this.currentModalOverlay.remove(),this.currentModalOverlay=null)}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 s=await r.json().catch(()=>({}));throw new Error(s.error?.message||s.message||"Failed to create portal session")}let i=await r.json();return{id:i.id,url:i.url||i.portalUrl,expiresAt:i.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function me(c){return new S(c)}var Ee={init:me,RecurCheckout:S,RecurElements:k,createElements:K};return ve(Se);})();
1575
+ `,i.onmouseover=()=>{i.style.background="rgba(0, 0, 0, 0.1)"},i.onmouseout=()=>{i.style.background="rgba(0, 0, 0, 0.05)"},i.onclick=()=>{t.remove(),e?.()};let s=document.createElement("div");s.id="recur-modal-payment-container";let o=document.createElement("recur-payment-form-skeleton");return s.appendChild(o),r.appendChild(i),r.appendChild(s),t.appendChild(r),document.body.appendChild(t),this.currentModalOverlay=t,{overlay:t,container:s}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeModal(){this.currentModal&&(this.currentModal.close(),this.currentModal=null),this.currentModalOverlay&&(this.currentModalOverlay.remove(),this.currentModalOverlay=null)}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 s=await r.json().catch(()=>({}));throw new Error(s.error?.message||s.message||"Failed to create portal session")}let i=await r.json();return{id:i.id,url:i.url||i.portalUrl,expiresAt:i.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function pe(n){return new S(n)}var Te={init:pe,RecurCheckout:S,RecurElements:x,createElements:j};return we(Ie);})();
1577
1576
  if (typeof window !== "undefined") {
1578
1577
  window.RecurCheckout = RecurCheckout.default;
1579
1578
  window.RecurElements = RecurCheckout.RecurElements;
package/dist/server.cjs CHANGED
@@ -27,21 +27,49 @@ var PortalSessions = class {
27
27
  /**
28
28
  * Create a portal session for a customer
29
29
  *
30
+ * Customer can be identified using one of:
31
+ * - `customer`: Internal customer ID (highest priority)
32
+ * - `externalId`: External customer ID from your system
33
+ * - `email`: Customer's email address (lowest priority)
34
+ *
30
35
  * @param params - Portal session creation parameters
31
36
  * @returns The created portal session with URL
32
37
  *
33
38
  * @example
34
39
  * ```typescript
40
+ * // By customer ID
35
41
  * const session = await recur.portal.sessions.create({
36
42
  * customer: 'cus_xxx',
37
43
  * returnUrl: 'https://myapp.com/account',
38
44
  * });
39
45
  *
46
+ * // By email
47
+ * const session = await recur.portal.sessions.create({
48
+ * email: 'customer@example.com',
49
+ * returnUrl: 'https://myapp.com/account',
50
+ * });
51
+ *
52
+ * // By external ID
53
+ * const session = await recur.portal.sessions.create({
54
+ * externalId: 'user_123',
55
+ * returnUrl: 'https://myapp.com/account',
56
+ * });
57
+ *
40
58
  * // Redirect the customer to the portal
41
59
  * redirect(session.url);
42
60
  * ```
43
61
  */
44
62
  async create(params) {
63
+ if (!params.customer && !params.email && !params.externalId) {
64
+ throw new RecurAPIError(
65
+ {
66
+ type: "invalid_request_error",
67
+ code: "missing_customer_identifier",
68
+ message: "At least one of customer, email, or externalId is required"
69
+ },
70
+ 400
71
+ );
72
+ }
45
73
  const baseUrl = this.config.baseUrl || "https://api.recur.tw";
46
74
  const response = await fetch(`${baseUrl}/v1/portal/sessions`, {
47
75
  method: "POST",
@@ -51,6 +79,8 @@ var PortalSessions = class {
51
79
  },
52
80
  body: JSON.stringify({
53
81
  customerId: params.customer,
82
+ email: params.email,
83
+ externalId: params.externalId,
54
84
  returnUrl: params.returnUrl,
55
85
  configurationId: params.configuration,
56
86
  locale: params.locale
package/dist/server.d.cts CHANGED
@@ -15,11 +15,30 @@ interface RecurConfig {
15
15
  */
16
16
  baseUrl?: string;
17
17
  }
18
+ /**
19
+ * Parameters for creating a portal session
20
+ *
21
+ * Customer Identification (at least one required):
22
+ * - customer: Internal customer ID in Recur (highest priority)
23
+ * - externalId: Customer's external ID from your system
24
+ * - email: Customer's email address (lowest priority)
25
+ */
18
26
  interface PortalSessionCreateParams {
19
27
  /**
20
- * The ID of the customer to create a portal session for
28
+ * The internal ID of the customer to create a portal session for
29
+ * Takes highest priority when multiple identifiers are provided
21
30
  */
22
- customer: string;
31
+ customer?: string;
32
+ /**
33
+ * Customer's email address
34
+ * Used to identify the customer if `customer` and `externalId` are not provided
35
+ */
36
+ email?: string;
37
+ /**
38
+ * Customer's external ID from your system
39
+ * Used to identify the customer if `customer` is not provided
40
+ */
41
+ externalId?: string;
23
42
  /**
24
43
  * The URL to redirect the customer to when they exit the portal
25
44
  * If not provided, uses the default return URL from portal configuration
@@ -98,16 +117,34 @@ declare class PortalSessions {
98
117
  /**
99
118
  * Create a portal session for a customer
100
119
  *
120
+ * Customer can be identified using one of:
121
+ * - `customer`: Internal customer ID (highest priority)
122
+ * - `externalId`: External customer ID from your system
123
+ * - `email`: Customer's email address (lowest priority)
124
+ *
101
125
  * @param params - Portal session creation parameters
102
126
  * @returns The created portal session with URL
103
127
  *
104
128
  * @example
105
129
  * ```typescript
130
+ * // By customer ID
106
131
  * const session = await recur.portal.sessions.create({
107
132
  * customer: 'cus_xxx',
108
133
  * returnUrl: 'https://myapp.com/account',
109
134
  * });
110
135
  *
136
+ * // By email
137
+ * const session = await recur.portal.sessions.create({
138
+ * email: 'customer@example.com',
139
+ * returnUrl: 'https://myapp.com/account',
140
+ * });
141
+ *
142
+ * // By external ID
143
+ * const session = await recur.portal.sessions.create({
144
+ * externalId: 'user_123',
145
+ * returnUrl: 'https://myapp.com/account',
146
+ * });
147
+ *
111
148
  * // Redirect the customer to the portal
112
149
  * redirect(session.url);
113
150
  * ```
package/dist/server.d.ts CHANGED
@@ -15,11 +15,30 @@ interface RecurConfig {
15
15
  */
16
16
  baseUrl?: string;
17
17
  }
18
+ /**
19
+ * Parameters for creating a portal session
20
+ *
21
+ * Customer Identification (at least one required):
22
+ * - customer: Internal customer ID in Recur (highest priority)
23
+ * - externalId: Customer's external ID from your system
24
+ * - email: Customer's email address (lowest priority)
25
+ */
18
26
  interface PortalSessionCreateParams {
19
27
  /**
20
- * The ID of the customer to create a portal session for
28
+ * The internal ID of the customer to create a portal session for
29
+ * Takes highest priority when multiple identifiers are provided
21
30
  */
22
- customer: string;
31
+ customer?: string;
32
+ /**
33
+ * Customer's email address
34
+ * Used to identify the customer if `customer` and `externalId` are not provided
35
+ */
36
+ email?: string;
37
+ /**
38
+ * Customer's external ID from your system
39
+ * Used to identify the customer if `customer` is not provided
40
+ */
41
+ externalId?: string;
23
42
  /**
24
43
  * The URL to redirect the customer to when they exit the portal
25
44
  * If not provided, uses the default return URL from portal configuration
@@ -98,16 +117,34 @@ declare class PortalSessions {
98
117
  /**
99
118
  * Create a portal session for a customer
100
119
  *
120
+ * Customer can be identified using one of:
121
+ * - `customer`: Internal customer ID (highest priority)
122
+ * - `externalId`: External customer ID from your system
123
+ * - `email`: Customer's email address (lowest priority)
124
+ *
101
125
  * @param params - Portal session creation parameters
102
126
  * @returns The created portal session with URL
103
127
  *
104
128
  * @example
105
129
  * ```typescript
130
+ * // By customer ID
106
131
  * const session = await recur.portal.sessions.create({
107
132
  * customer: 'cus_xxx',
108
133
  * returnUrl: 'https://myapp.com/account',
109
134
  * });
110
135
  *
136
+ * // By email
137
+ * const session = await recur.portal.sessions.create({
138
+ * email: 'customer@example.com',
139
+ * returnUrl: 'https://myapp.com/account',
140
+ * });
141
+ *
142
+ * // By external ID
143
+ * const session = await recur.portal.sessions.create({
144
+ * externalId: 'user_123',
145
+ * returnUrl: 'https://myapp.com/account',
146
+ * });
147
+ *
111
148
  * // Redirect the customer to the portal
112
149
  * redirect(session.url);
113
150
  * ```
package/dist/server.js CHANGED
@@ -25,21 +25,49 @@ var PortalSessions = class {
25
25
  /**
26
26
  * Create a portal session for a customer
27
27
  *
28
+ * Customer can be identified using one of:
29
+ * - `customer`: Internal customer ID (highest priority)
30
+ * - `externalId`: External customer ID from your system
31
+ * - `email`: Customer's email address (lowest priority)
32
+ *
28
33
  * @param params - Portal session creation parameters
29
34
  * @returns The created portal session with URL
30
35
  *
31
36
  * @example
32
37
  * ```typescript
38
+ * // By customer ID
33
39
  * const session = await recur.portal.sessions.create({
34
40
  * customer: 'cus_xxx',
35
41
  * returnUrl: 'https://myapp.com/account',
36
42
  * });
37
43
  *
44
+ * // By email
45
+ * const session = await recur.portal.sessions.create({
46
+ * email: 'customer@example.com',
47
+ * returnUrl: 'https://myapp.com/account',
48
+ * });
49
+ *
50
+ * // By external ID
51
+ * const session = await recur.portal.sessions.create({
52
+ * externalId: 'user_123',
53
+ * returnUrl: 'https://myapp.com/account',
54
+ * });
55
+ *
38
56
  * // Redirect the customer to the portal
39
57
  * redirect(session.url);
40
58
  * ```
41
59
  */
42
60
  async create(params) {
61
+ if (!params.customer && !params.email && !params.externalId) {
62
+ throw new RecurAPIError(
63
+ {
64
+ type: "invalid_request_error",
65
+ code: "missing_customer_identifier",
66
+ message: "At least one of customer, email, or externalId is required"
67
+ },
68
+ 400
69
+ );
70
+ }
43
71
  const baseUrl = this.config.baseUrl || "https://api.recur.tw";
44
72
  const response = await fetch(`${baseUrl}/v1/portal/sessions`, {
45
73
  method: "POST",
@@ -49,6 +77,8 @@ var PortalSessions = class {
49
77
  },
50
78
  body: JSON.stringify({
51
79
  customerId: params.customer,
80
+ email: params.email,
81
+ externalId: params.externalId,
52
82
  returnUrl: params.returnUrl,
53
83
  configurationId: params.configuration,
54
84
  locale: params.locale
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-tw",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
5
5
  "type": "module",
6
6
  "private": false,