recur-tw 0.2.0 → 0.3.1

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/README.md CHANGED
@@ -719,7 +719,25 @@ Check out the `/examples` directory for complete working examples:
719
719
 
720
720
  ## Migration Guide
721
721
 
722
- ### From v0.0.2 to v0.0.3
722
+ ### From v0.2.0 to v0.3.0
723
+
724
+ **Breaking Changes:**
725
+ - 移除 `/v1/checkout/init` 端點
726
+ - Vanilla JS `createEmbeddedCheckout()` 改用 `/v1/checkouts` API
727
+ - 付款執行改用 `/v1/checkouts/:id/pay`
728
+
729
+ **New API Endpoints:**
730
+ ```
731
+ POST /v1/checkouts → 建立 checkout session
732
+ GET /v1/checkouts/:id → 取得狀態
733
+ POST /v1/checkouts/:id → 刷新 SDK Token
734
+ DELETE /v1/checkouts/:id → 取消
735
+ POST /v1/checkouts/:id/pay → 執行付款
736
+ ```
737
+
738
+ **無需程式碼變更** - SDK 內部已自動遷移到新端點。
739
+
740
+ ### From v0.0.x to v0.1.0
723
741
 
724
742
  **Breaking Changes:**
725
743
  - `organizationId` → `publishableKey` in config
@@ -730,10 +748,10 @@ Check out the `/examples` directory for complete working examples:
730
748
  **Migration:**
731
749
 
732
750
  ```tsx
733
- // Before (v0.0.2)
751
+ // Before
734
752
  <RecurProvider config={{ organizationId: 'org_xxx' }}>
735
753
 
736
- // After (v0.0.3)
754
+ // After
737
755
  <RecurProvider config={{ publishableKey: 'pk_test_xxx' }}>
738
756
  ```
739
757
 
package/dist/index.cjs CHANGED
@@ -2090,19 +2090,20 @@ var init_checkout_button = __esm({
2090
2090
  }
2091
2091
  async createCheckoutSession(options) {
2092
2092
  const baseUrl = this.getApiBaseUrl();
2093
+ const requestBody = {
2094
+ productId: options.productId,
2095
+ successUrl: options.successUrl,
2096
+ cancelUrl: options.cancelUrl
2097
+ };
2098
+ if (options.mode) requestBody.mode = options.mode;
2099
+ if (options.customerEmail) requestBody.customerEmail = options.customerEmail;
2093
2100
  const response = await fetch(`${baseUrl}/v1/checkout/sessions`, {
2094
2101
  method: "POST",
2095
2102
  headers: {
2096
2103
  "Content-Type": "application/json",
2097
2104
  "X-Recur-Publishable-Key": options.publishableKey
2098
2105
  },
2099
- body: JSON.stringify({
2100
- productId: options.productId,
2101
- mode: options.mode,
2102
- successUrl: options.successUrl,
2103
- cancelUrl: options.cancelUrl,
2104
- customerEmail: options.customerEmail
2105
- })
2106
+ body: JSON.stringify(requestBody)
2106
2107
  });
2107
2108
  if (!response.ok) {
2108
2109
  const error = await response.json().catch(() => ({}));
package/dist/index.js CHANGED
@@ -2084,19 +2084,20 @@ var init_checkout_button = __esm({
2084
2084
  }
2085
2085
  async createCheckoutSession(options) {
2086
2086
  const baseUrl = this.getApiBaseUrl();
2087
+ const requestBody = {
2088
+ productId: options.productId,
2089
+ successUrl: options.successUrl,
2090
+ cancelUrl: options.cancelUrl
2091
+ };
2092
+ if (options.mode) requestBody.mode = options.mode;
2093
+ if (options.customerEmail) requestBody.customerEmail = options.customerEmail;
2087
2094
  const response = await fetch(`${baseUrl}/v1/checkout/sessions`, {
2088
2095
  method: "POST",
2089
2096
  headers: {
2090
2097
  "Content-Type": "application/json",
2091
2098
  "X-Recur-Publishable-Key": options.publishableKey
2092
2099
  },
2093
- body: JSON.stringify({
2094
- productId: options.productId,
2095
- mode: options.mode,
2096
- successUrl: options.successUrl,
2097
- cancelUrl: options.cancelUrl,
2098
- customerEmail: options.customerEmail
2099
- })
2100
+ body: JSON.stringify(requestBody)
2100
2101
  });
2101
2102
  if (!response.ok) {
2102
2103
  const error = await response.json().catch(() => ({}));
package/dist/recur.umd.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var RecurCheckout=(()=>{var v=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var G=(l,e,t)=>e in l?v(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var m=(l,e)=>()=>(l&&(e=l(l=0)),e);var u=(l,e)=>{for(var t in e)v(l,t,{get:e[t],enumerable:!0})},Q=(l,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of J(e))!Z.call(l,i)&&i!==t&&v(l,i,{get:()=>e[i],enumerable:!(r=W(e,i))||r.enumerable});return l};var ee=l=>Q(v({},"__esModule",{value:!0}),l);var n=(l,e,t)=>G(l,typeof e!="symbol"?e+"":e,t);var U={};u(U,{RecurLoadingSpinner:()=>k});var k,H=m(()=>{"use strict";k=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 v=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var G=(l,e,t)=>e in l?v(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var m=(l,e)=>()=>(l&&(e=l(l=0)),e);var d=(l,e)=>{for(var t in e)v(l,t,{get:e[t],enumerable:!0})},Q=(l,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of J(e))!Z.call(l,i)&&i!==t&&v(l,i,{get:()=>e[i],enumerable:!(r=W(e,i))||r.enumerable});return l};var ee=l=>Q(v({},"__esModule",{value:!0}),l);var a=(l,e,t)=>G(l,typeof e!="symbol"?e+"":e,t);var U={};d(U,{RecurLoadingSpinner:()=>k});var k,H=m(()=>{"use strict";k=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",k)});var $={};u($,{RecurSuccessMessage:()=>x});var x,A=m(()=>{"use strict";x=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",k)});var $={};d($,{RecurSuccessMessage:()=>x});var x,A=m(()=>{"use strict";x=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",x)});var D={};u(D,{RecurErrorDisplay:()=>w});var w,B=m(()=>{"use strict";w=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",x)});var B={};d(B,{RecurErrorDisplay:()=>w});var w,D=m(()=>{"use strict";w=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",w)});var N={};u(N,{RecurSkeletonLoader:()=>E});var E,O=m(()=>{"use strict";E=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",w)});var N={};d(N,{RecurSkeletonLoader:()=>E});var E,O=m(()=>{"use strict";E=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",E)});var F={};u(F,{RecurPaymentFormSkeleton:()=>C});var C,j=m(()=>{"use strict";C=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",E)});var F={};d(F,{RecurPaymentFormSkeleton:()=>C});var C,j=m(()=>{"use strict";C=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;
@@ -594,7 +594,7 @@
594
594
  <p class="security-text">\u60A8\u7684\u4ED8\u6B3E\u8CC7\u8A0A\u7D93\u904E\u52A0\u5BC6\u4FDD\u8B77</p>
595
595
  </div>
596
596
  </div>
597
- `}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",C)});var b={};u(b,{RecurToast:()=>T,RecurToastContainer:()=>f});var T,p,f,g=m(()=>{"use strict";T=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">
597
+ `}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",C)});var b={};d(b,{RecurToast:()=>T,RecurToastContainer:()=>f});var T,u,f,g=m(()=>{"use strict";T=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">
598
598
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
599
599
  </svg>`;case"error":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
600
600
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
@@ -714,7 +714,7 @@
714
714
  </svg>
715
715
  </button>
716
716
  </div>
717
- `,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=f.getInstance(),s=document.createElement("recur-toast");return s.setAttribute("message",e),s.setAttribute("type",t),s.setAttribute("duration",r.toString()),i.appendChild(s),s}},p=class p extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
717
+ `,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=f.getInstance(),s=document.createElement("recur-toast");return s.setAttribute("message",e),s.setAttribute("type",t),s.setAttribute("duration",r.toString()),i.appendChild(s),s}},u=class u extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
718
718
  <style>
719
719
  :host {
720
720
  position: fixed;
@@ -741,7 +741,7 @@
741
741
  </style>
742
742
 
743
743
  <slot></slot>
744
- `}static getInstance(){return p.instance||(p.instance=document.querySelector("recur-toast-container"),p.instance||(p.instance=document.createElement("recur-toast-container"),document.body.appendChild(p.instance))),p.instance}};n(p,"instance",null);f=p;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",T);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",f)});var K={};u(K,{RecurPaymentForm:()=>M});var M,q=m(()=>{"use strict";M=class extends HTMLElement{constructor(){super();n(this,"containerId");n(this,"customStyles");n(this,"_isInitializing",!1);n(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=`
744
+ `}static getInstance(){return u.instance||(u.instance=document.querySelector("recur-toast-container"),u.instance||(u.instance=document.createElement("recur-toast-container"),document.body.appendChild(u.instance))),u.instance}};a(u,"instance",null);f=u;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",T);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",f)});var K={};d(K,{RecurPaymentForm:()=>M});var M,q=m(()=>{"use strict";M=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=`
745
745
  <style>
746
746
  /* \u9019\u4E9B\u6A23\u5F0F\u88AB\u9694\u96E2\u5728 Shadow DOM \u5167\uFF0C\u4E0D\u6703\u5F71\u97FF\u5916\u90E8 */
747
747
  :host {
@@ -851,7 +851,7 @@
851
851
  height: 36px !important;
852
852
  }
853
853
  `;t.textContent=this.customStyles+`
854
- `+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 a=this.createCardFieldsSection();a.slot="card-fields",this.appendChild(a);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=`
854
+ `+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=`
855
855
  /* PAYUNi iframe \u5BB9\u5668\u9AD8\u5EA6\uFF08\u4F7F\u7528\u5BE6\u969B\u7684 container ID\uFF09 */
856
856
  #${this.containerId}-card-no,
857
857
  #${this.containerId}-card-exp,
@@ -1138,10 +1138,10 @@
1138
1138
  >
1139
1139
  <span id="${this.containerId}-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>
1140
1140
  </button>
1141
- `,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`),a=document.getElementById(`${this.containerId}-card-cvc`);if(!i||!s||!a)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(c){if((c?.message?.includes("1008")||c?.message?.includes("timeout")||c?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw c}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(o.onUpdate?.(c=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",c);let d=c.status&&c.status.CardNo===!0&&c.status.CardExp===!0&&c.status.CardCvc===!0,_=document.getElementById(`${this.containerId}-submit-btn`);_&&(_.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=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,a,o=document.getElementById(`${this.containerId}-email`),c=document.getElementById(`${this.containerId}-name`),d=document.getElementById(`${this.containerId}-phone`);if(o&&c){if(i=o.value,s=c.value,a=d?.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,customerPhone:a,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=`
1141
+ `,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(c){if((c?.message?.includes("1008")||c?.message?.includes("timeout")||c?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw c}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(o.onUpdate?.(c=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",c);let p=c.status&&c.status.CardNo===!0&&c.status.CardExp===!0&&c.status.CardCvc===!0,_=document.getElementById(`${this.containerId}-submit-btn`);_&&(_.disabled=!p,console.log("[PaymentForm] Submit button disabled:",!p))}),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,o=document.getElementById(`${this.containerId}-email`),c=document.getElementById(`${this.containerId}-name`),p=document.getElementById(`${this.containerId}-phone`);if(o&&c){if(i=o.value,s=c.value,n=p?.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,customerPhone:n,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=`
1142
1142
  <span class="recur-loading-spinner"></span>
1143
1143
  <span>\u8655\u7406\u4E2D...</span>
1144
- `):(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,phone:document.getElementById(`${this.containerId}-phone`)?.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)}if(t.phone){let r=document.getElementById(`${this.containerId}-phone`);r&&(r.value=t.phone)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",M)});var Y={};u(Y,{RecurCheckoutButton:()=>I});var I,V=m(()=>{"use strict";I=class extends HTMLElement{constructor(){super();n(this,"_isLoading",!1);n(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"),a=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(!a){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(a),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=`
1144
+ `):(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,phone:document.getElementById(`${this.containerId}-phone`)?.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)}if(t.phone){let r=document.getElementById(`${this.containerId}-phone`);r&&(r.value=t.phone)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",M)});var Y={};d(Y,{RecurCheckoutButton:()=>I});var I,V=m(()=>{"use strict";I=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=`
1145
1145
  <style>
1146
1146
  :host {
1147
1147
  display: inline-block;
@@ -1240,7 +1240,7 @@
1240
1240
  ${this._isLoading?'<span class="spinner"></span>':""}
1241
1241
  <span>${this._isLoading?"\u8655\u7406\u4E2D...":t}</span>
1242
1242
  </button>
1243
- `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),i=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify({productId:t.productId,mode:t.mode,successUrl:t.successUrl,cancelUrl:t.cancelUrl,customerEmail:t.customerEmail})});if(!i.ok){let s=await i.json().catch(()=>({}));throw new Error(s.error?.message||`HTTP ${i.status}: Failed to create checkout session`)}return i.json()}getApiBaseUrl(){let t=this.getAttribute("api-base-url");if(t)return t;if(typeof window<"u"){let r=window.location.hostname;if(r==="localhost"||r.includes(".test")||r.includes(".local")||r==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}resolveUrl(t){return t.startsWith("/")?`${window.location.origin}${t}`:t}dispatchError(t){console.error("[recur-checkout]",t),this.dispatchEvent(new CustomEvent("checkout-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-checkout")&&customElements.define("recur-checkout",I)});var ie={};u(ie,{RecurCheckout:()=>y,RecurElements:()=>h,createElements:()=>z,default:()=>re,init:()=>X});async function te(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(H(),U)),Promise.resolve().then(()=>(A(),$)),Promise.resolve().then(()=>(B(),D)),Promise.resolve().then(()=>(O(),N)),Promise.resolve().then(()=>(j(),F)),Promise.resolve().then(()=>(g(),b)),Promise.resolve().then(()=>(q(),K)),Promise.resolve().then(()=>(V(),Y))]);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"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&te();var S=class{constructor(e){n(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}async createSubscription(e){let{planId:t,customerName:r,customerEmail:i,customerPhone:s}=e;if(!t)throw new Error("planId is required");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({planId:t,customerName:r,customerEmail:i,customerPhone:s})});if(!a.ok){let o=await a.json().catch(()=>({}));throw{code:o.error||"CHECKOUT_FAILED",message:o.message||"Failed to initiate checkout",details:o}}return await a.json()}async fetchPlans(){let e=await fetch(`${this.config.baseUrl}/v1/plans`,{method:"GET",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey}});if(!e.ok){let t=await e.json().catch(()=>({}));throw{code:t.error||"FETCH_PLANS_FAILED",message:t.message||"Failed to fetch plans",details:t}}return await e.json()}getConfig(){return{...this.config}}};var L=class{constructor(e){n(this,"overlay",null);n(this,"modal",null);n(this,"iframe",null);n(this,"onClose");n(this,"handleMessage",e=>{e.origin===window.location.origin&&(e.data?.type==="RECUR_PAYMENT_COMPLETE"?this.close():e.data?.type==="RECUR_PAYMENT_CANCEL"&&this.close())});this.onClose=e}open(e){this.overlay=document.createElement("div"),this.overlay.style.cssText=`
1243
+ `}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",I)});var ie={};d(ie,{RecurCheckout:()=>y,RecurElements:()=>h,createElements:()=>z,default:()=>re,init:()=>X});async function te(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(H(),U)),Promise.resolve().then(()=>(A(),$)),Promise.resolve().then(()=>(D(),B)),Promise.resolve().then(()=>(O(),N)),Promise.resolve().then(()=>(j(),F)),Promise.resolve().then(()=>(g(),b)),Promise.resolve().then(()=>(q(),K)),Promise.resolve().then(()=>(V(),Y))]);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"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&te();var S=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{planId:t,customerName:r,customerEmail:i,customerPhone:s}=e;if(!t)throw new Error("planId is required");let n=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({planId:t,customerName:r,customerEmail:i,customerPhone:s})});if(!n.ok){let o=await n.json().catch(()=>({}));throw{code:o.error||"CHECKOUT_FAILED",message:o.message||"Failed to initiate checkout",details:o}}return await n.json()}async fetchPlans(){let e=await fetch(`${this.config.baseUrl}/v1/plans`,{method:"GET",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey}});if(!e.ok){let t=await e.json().catch(()=>({}));throw{code:t.error||"FETCH_PLANS_FAILED",message:t.message||"Failed to fetch plans",details:t}}return await e.json()}getConfig(){return{...this.config}}};var L=class{constructor(e){a(this,"overlay",null);a(this,"modal",null);a(this,"iframe",null);a(this,"onClose");a(this,"handleMessage",e=>{e.origin===window.location.origin&&(e.data?.type==="RECUR_PAYMENT_COMPLETE"?this.close():e.data?.type==="RECUR_PAYMENT_CANCEL"&&this.close())});this.onClose=e}open(e){this.overlay=document.createElement("div"),this.overlay.style.cssText=`
1244
1244
  position: fixed;
1245
1245
  top: 0;
1246
1246
  left: 0;
@@ -1285,12 +1285,12 @@
1285
1285
  height: 100%;
1286
1286
  border: none;
1287
1287
  border-radius: 8px;
1288
- `,this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"),this.modal.appendChild(t),this.modal.appendChild(this.iframe),this.overlay.appendChild(this.modal),document.body.appendChild(this.overlay),document.body.style.overflow="hidden",this.overlay.onclick=r=>{r.target===this.overlay&&this.close()},window.addEventListener("message",this.handleMessage)}close(){this.overlay&&this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay),document.body.style.overflow="",this.overlay=null,this.modal=null,this.iframe=null,window.removeEventListener("message",this.handleMessage),this.onClose&&this.onClose()}};var R=class{constructor(e,t){n(this,"container");n(this,"iframe",null);n(this,"onClose");n(this,"handleMessage",e=>{e.origin===window.location.origin&&(e.data?.type==="RECUR_PAYMENT_COMPLETE"?this.remove():e.data?.type==="RECUR_PAYMENT_CANCEL"&&this.remove())});if(typeof e=="string"){let r=document.querySelector(e);if(!r)throw new Error(`Container element not found: ${e}`);this.container=r}else this.container=e;this.onClose=t}embed(e){this.container.innerHTML="",this.iframe=document.createElement("iframe"),this.iframe.src=e,this.iframe.style.cssText=`
1288
+ `,this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"),this.modal.appendChild(t),this.modal.appendChild(this.iframe),this.overlay.appendChild(this.modal),document.body.appendChild(this.overlay),document.body.style.overflow="hidden",this.overlay.onclick=r=>{r.target===this.overlay&&this.close()},window.addEventListener("message",this.handleMessage)}close(){this.overlay&&this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay),document.body.style.overflow="",this.overlay=null,this.modal=null,this.iframe=null,window.removeEventListener("message",this.handleMessage),this.onClose&&this.onClose()}};var R=class{constructor(e,t){a(this,"container");a(this,"iframe",null);a(this,"onClose");a(this,"handleMessage",e=>{e.origin===window.location.origin&&(e.data?.type==="RECUR_PAYMENT_COMPLETE"?this.remove():e.data?.type==="RECUR_PAYMENT_CANCEL"&&this.remove())});if(typeof e=="string"){let r=document.querySelector(e);if(!r)throw new Error(`Container element not found: ${e}`);this.container=r}else this.container=e;this.onClose=t}embed(e){this.container.innerHTML="",this.iframe=document.createElement("iframe"),this.iframe.src=e,this.iframe.style.cssText=`
1289
1289
  width: 100%;
1290
1290
  height: 600px;
1291
1291
  border: 1px solid #e5e7eb;
1292
1292
  border-radius: 8px;
1293
- `,this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"),this.container.appendChild(this.iframe),window.addEventListener("message",this.handleMessage)}remove(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,window.removeEventListener("message",this.handleMessage),this.onClose&&this.onClose()}};var P=class{constructor(e,t){n(this,"config");n(this,"options");n(this,"container");n(this,"sdkToken",null);n(this,"sdkEnv","S");n(this,"payuniSDK",null);n(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)}}async initCheckout(){let e=()=>{if(typeof window<"u"){let s=window.location.hostname;if(s==="localhost"||s.includes(".test")||s.includes(".local")||s==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},t=this.config.baseUrl||e(),r=await fetch(`${t}/v1/checkout/init`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({planId:this.options.planId,iframeDomain:window.location.origin})});if(!r.ok){let s=await r.json().catch(()=>({}));throw new Error(s.error||"Failed to initialize checkout")}let i=await r.json();this.sdkToken=i.sdkToken,this.sdkEnv=i.env}renderHTML(){this.container.innerHTML=`
1293
+ `,this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"),this.container.appendChild(this.iframe),window.addEventListener("message",this.handleMessage)}remove(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,window.removeEventListener("message",this.handleMessage),this.onClose&&this.onClose()}};var P=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,customerPhone:this.options.customerPhone})});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=`
1294
1294
  <div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
1295
1295
  <div class="recur-checkout-header" style="margin-bottom: 24px;">
1296
1296
  <h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
@@ -1372,14 +1372,14 @@
1372
1372
  </p>
1373
1373
  </form>
1374
1374
  </div>
1375
- `}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,r=document.getElementById("recur-phone").value;if(!e||!t)throw new Error("Please fill in all required fields");if(!this.payuniSDK)throw new Error("Payment system not initialized");let i=await this.payuniSDK.getTradeResult();if(i.Status!=="SUCCESS")throw new Error(i.Message||"Card validation failed");let s=()=>{if(typeof window<"u"){let d=window.location.hostname;if(d==="localhost"||d.includes(".test")||d.includes(".local")||d==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},a=this.config.baseUrl||s(),o=await fetch(`${a}/v1/subscriptions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({planId:this.options.planId,customerEmail:e,customerName:t,customerPhone:r||void 0})});if(!o.ok){let d=await o.json().catch(()=>({}));throw new Error(d.error||"Failed to create subscription")}let c=await o.json();this.options.onSuccess&&this.options.onSuccess(c),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 h=class{constructor(e){n(this,"publishableKey");n(this,"baseUrl");n(this,"embedUrl");n(this,"iframe",null);n(this,"container",null);n(this,"sessionId",null);n(this,"timestamp",null);n(this,"creditToken",null);n(this,"cardToken",null);n(this,"cardTimestamp",null);n(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=`
1375
+ `}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,r=document.getElementById("recur-phone").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 i=await this.payuniSDK.getTradeResult();if(i.Status!=="SUCCESS")throw new Error(i.Message||"Card validation failed");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.creditToken,timestamp:i.timestamp})});if(!n.ok){let p=await n.json().catch(()=>({}));throw new Error(p.error||"Failed to process payment")}let o=await n.json(),c={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(c),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 h=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=`
1376
1376
  width: 100%;
1377
1377
  border: none;
1378
1378
  min-height: 200px;
1379
1379
  display: block;
1380
1380
  user-select: none;
1381
1381
  transition: height 0.35s ease, opacity 0.4s ease 0.1s;
1382
- `.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),a=()=>{clearTimeout(s),this.off("ready",a),r()},o=c=>{clearTimeout(s),this.off("error",o),i(new Error(c.message||"Elements initialization failed"))};this.on("ready",a),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)},a=o=>{clearTimeout(i),this.off("error",a),r(new Error(o.message||"Tokenization failed"))};this.on("tokenized",s),this.on("error",a)})}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,phone:e.phone,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 z(l){return new h(l)}var y=class{constructor(e){n(this,"core");n(this,"currentModal",null);n(this,"currentIframe",null);this.core=new S(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new P(t,e).render()}async redirectToCheckout(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(),s=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify({productId:e.productId,mode:e.mode,successUrl:e.successUrl,cancelUrl:e.cancelUrl,customerEmail:e.customerEmail})});if(!s.ok){let o=await s.json().catch(()=>({}));throw new Error(o.error?.message||"Failed to create checkout session")}let a=await s.json();window.location.href=a.url}async createCheckoutSession(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let a=window.location.hostname;if(a==="localhost"||a.includes(".test")||a.includes(".local")||a==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r(),s=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify({productId:e.productId,mode:e.mode,successUrl:e.successUrl,cancelUrl:e.cancelUrl,customerEmail:e.customerEmail})});if(!s.ok){let a=await s.json().catch(()=>({}));throw new Error(a.error?.message||"Failed to create checkout session")}return s.json()}async checkout(e){try{let t=await this.core.createSubscription(e);e.onSuccess&&e.onSuccess(t);let r=this.core.getConfig(),i=e.mode||"redirect";if(r.mockMode)console.log("[Recur SDK] \u{1F3AD} Mock mode: Showing mock payment UI"),await this.showMockPaymentUI(i,t,e.container,e.onClose);else{let a=`${r.baseUrl||window.location.origin}/checkout/${t.subscription.id}`;switch(i){case"modal":this.openModal(a,e.onClose);break;case"iframe":this.embedIframe(a,e.container,e.onClose);break;case"redirect":default:window.location.href=a;break}}}catch(t){if(e.onError)e.onError(t);else throw console.error("Recur checkout error:",t),t}}openModal(e,t){this.closeModal(),this.currentModal=new L(()=>{this.currentModal=null,t&&t()}),this.currentModal.open(e)}embedIframe(e,t,r){if(!t)throw new Error("Container is required for iframe mode");this.removeIframe(),this.currentIframe=new R(t,()=>{this.currentIframe=null,r&&r()}),this.currentIframe.embed(e)}closeModal(){this.currentModal&&(this.currentModal.close(),this.currentModal=null)}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async showMockPaymentUI(e,t,r,i){let s=this.generateMockPaymentHTML(t);switch(e){case"modal":this.showMockModal(s,i);break;case"iframe":this.showMockIframe(s,r,i);break;case"redirect":default:let o=`${window.location.origin}/checkout/${t.subscription.id}`;console.log("[Recur SDK] \u{1F3AD} Mock mode: Would redirect to:",o);let{RecurToast:c}=await Promise.resolve().then(()=>(g(),b));c.show("\u{1F3AD} Mock \u6A21\u5F0F\uFF1A\u5728\u771F\u5BE6\u74B0\u5883\u4E2D\uFF0C\u7528\u6236\u6703\u88AB\u5C0E\u5411\u4ED8\u6B3E\u9801\u9762","info",8e3),console.log("Payment URL:",o);break}}generateMockPaymentHTML(e){return`
1382
+ `.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=c=>{clearTimeout(s),this.off("error",o),i(new Error(c.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,phone:e.phone,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 z(l){return new h(l)}var y=class{constructor(e){a(this,"core");a(this,"currentModal",null);a(this,"currentIframe",null);this.core=new S(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new P(t,e).render()}async redirectToCheckout(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let c=window.location.hostname;if(c==="localhost"||c.includes(".test")||c.includes(".local")||c==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r(),s={productId:e.productId,successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail);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 c=await n.json().catch(()=>({}));throw new Error(c.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(),s={productId:e.productId,successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail);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){try{let t=await this.core.createSubscription(e);e.onSuccess&&e.onSuccess(t);let r=this.core.getConfig(),i=e.mode||"redirect";if(r.mockMode)console.log("[Recur SDK] \u{1F3AD} Mock mode: Showing mock payment UI"),await this.showMockPaymentUI(i,t,e.container,e.onClose);else{let n=`${r.baseUrl||window.location.origin}/checkout/${t.subscription.id}`;switch(i){case"modal":this.openModal(n,e.onClose);break;case"iframe":this.embedIframe(n,e.container,e.onClose);break;case"redirect":default:window.location.href=n;break}}}catch(t){if(e.onError)e.onError(t);else throw console.error("Recur checkout error:",t),t}}openModal(e,t){this.closeModal(),this.currentModal=new L(()=>{this.currentModal=null,t&&t()}),this.currentModal.open(e)}embedIframe(e,t,r){if(!t)throw new Error("Container is required for iframe mode");this.removeIframe(),this.currentIframe=new R(t,()=>{this.currentIframe=null,r&&r()}),this.currentIframe.embed(e)}closeModal(){this.currentModal&&(this.currentModal.close(),this.currentModal=null)}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async showMockPaymentUI(e,t,r,i){let s=this.generateMockPaymentHTML(t);switch(e){case"modal":this.showMockModal(s,i);break;case"iframe":this.showMockIframe(s,r,i);break;case"redirect":default:let o=`${window.location.origin}/checkout/${t.subscription.id}`;console.log("[Recur SDK] \u{1F3AD} Mock mode: Would redirect to:",o);let{RecurToast:c}=await Promise.resolve().then(()=>(g(),b));c.show("\u{1F3AD} Mock \u6A21\u5F0F\uFF1A\u5728\u771F\u5BE6\u74B0\u5883\u4E2D\uFF0C\u7528\u6236\u6703\u88AB\u5C0E\u5411\u4ED8\u6B3E\u9801\u9762","info",8e3),console.log("Payment URL:",o);break}}generateMockPaymentHTML(e){return`
1383
1383
  <!DOCTYPE html>
1384
1384
  <html>
1385
1385
  <head>
@@ -1592,7 +1592,7 @@
1592
1592
  font-size: 18px;
1593
1593
  z-index: 1;
1594
1594
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
1595
- `,s.onclick=()=>{r.remove(),t&&t()};let a=document.createElement("iframe");a.style.cssText="width: 100%; height: 100%; border: none;",a.srcdoc=e,i.appendChild(s),i.appendChild(a),r.appendChild(i),document.body.appendChild(r),window.addEventListener("message",async o=>{if(o.data.type==="recur-mock-payment-success"){if(o.data.showToast){let{RecurToast:c}=await Promise.resolve().then(()=>(g(),b));c.show(o.data.showToast.message,o.data.showToast.type||"success",5e3)}r.remove(),t&&t()}})}showMockIframe(e,t,r){if(!t)throw new Error("Container is required for iframe mode");let i=typeof t=="string"?document.getElementById(t)||document.querySelector(t):t;if(!i)throw new Error("Container element not found");i.innerHTML="";let s=document.createElement("iframe");s.style.cssText="width: 100%; height: 100%; border: none; min-height: 600px;",s.srcdoc=e,i.appendChild(s),window.addEventListener("message",async a=>{if(a.data.type==="recur-mock-payment-success"){if(a.data.showToast){let{RecurToast:o}=await Promise.resolve().then(()=>(g(),b));o.show(a.data.showToast.message,a.data.showToast.type||"success",5e3)}r&&r()}})}};function X(l){return new y(l)}var re={init:X,RecurCheckout:y,RecurElements:h,createElements:z};return ee(ie);})();
1595
+ `,s.onclick=()=>{r.remove(),t&&t()};let n=document.createElement("iframe");n.style.cssText="width: 100%; height: 100%; border: none;",n.srcdoc=e,i.appendChild(s),i.appendChild(n),r.appendChild(i),document.body.appendChild(r),window.addEventListener("message",async o=>{if(o.data.type==="recur-mock-payment-success"){if(o.data.showToast){let{RecurToast:c}=await Promise.resolve().then(()=>(g(),b));c.show(o.data.showToast.message,o.data.showToast.type||"success",5e3)}r.remove(),t&&t()}})}showMockIframe(e,t,r){if(!t)throw new Error("Container is required for iframe mode");let i=typeof t=="string"?document.getElementById(t)||document.querySelector(t):t;if(!i)throw new Error("Container element not found");i.innerHTML="";let s=document.createElement("iframe");s.style.cssText="width: 100%; height: 100%; border: none; min-height: 600px;",s.srcdoc=e,i.appendChild(s),window.addEventListener("message",async n=>{if(n.data.type==="recur-mock-payment-success"){if(n.data.showToast){let{RecurToast:o}=await Promise.resolve().then(()=>(g(),b));o.show(n.data.showToast.message,n.data.showToast.type||"success",5e3)}r&&r()}})}};function X(l){return new y(l)}var re={init:X,RecurCheckout:y,RecurElements:h,createElements:z};return ee(ie);})();
1596
1596
  if (typeof window !== "undefined") {
1597
1597
  window.RecurCheckout = RecurCheckout.default;
1598
1598
  window.RecurElements = RecurCheckout.RecurElements;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-tw",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
5
5
  "type": "module",
6
6
  "private": false,