recur-tw 0.7.2 → 0.7.4

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
@@ -1220,7 +1220,6 @@ var init_payment_form = __esm({
1220
1220
  render() {
1221
1221
  this.shadowRoot.innerHTML = `
1222
1222
  <style>
1223
- /* \u9019\u4E9B\u6A23\u5F0F\u88AB\u9694\u96E2\u5728 Shadow DOM \u5167\uFF0C\u4E0D\u6703\u5F71\u97FF\u5916\u90E8 */
1224
1223
  :host {
1225
1224
  display: block;
1226
1225
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
@@ -1594,12 +1593,16 @@ var init_payment_form = __esm({
1594
1593
  .recur-payuni-iframe {
1595
1594
  height: 36px;
1596
1595
  width: 100%;
1596
+ max-width: 100%;
1597
+ box-sizing: border-box;
1597
1598
  }
1598
1599
 
1599
1600
  .recur-card-row {
1600
1601
  display: grid;
1601
1602
  grid-template-columns: 1fr 1fr;
1602
1603
  gap: 12px;
1604
+ max-width: 100%;
1605
+ box-sizing: border-box;
1603
1606
  }
1604
1607
 
1605
1608
  /* Container needs relative positioning for skeleton overlay */
@@ -1699,6 +1702,7 @@ var init_payment_form = __esm({
1699
1702
  align-items: center;
1700
1703
  justify-content: center;
1701
1704
  gap: 8px;
1705
+ box-sizing: border-box;
1702
1706
  }
1703
1707
 
1704
1708
  .recur-submit-button:hover:not(:disabled) {
@@ -2646,7 +2650,11 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2646
2650
  width: 90%;
2647
2651
  max-height: 90vh;
2648
2652
  overflow-y: auto;
2653
+ overflow-x: hidden;
2649
2654
  position: relative;
2655
+ border-radius: 12px;
2656
+ background: white;
2657
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
2650
2658
  `;
2651
2659
  const closeButton = document.createElement("button");
2652
2660
  closeButton.className = "recur-sdk__close-button";
@@ -2684,11 +2692,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2684
2692
  loadingContainer = document.createElement("div");
2685
2693
  loadingContainer.id = "recur-modal-loading";
2686
2694
  loadingContainer.className = "recur-sdk__loading-container";
2687
- loadingContainer.style.cssText = `
2688
- background: white;
2689
- border-radius: 12px;
2690
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
2691
- `;
2692
2695
  const skeleton = document.createElement("recur-payment-form-skeleton");
2693
2696
  loadingContainer.appendChild(skeleton);
2694
2697
  modalContent.appendChild(closeButton);
package/dist/index.js CHANGED
@@ -1214,7 +1214,6 @@ var init_payment_form = __esm({
1214
1214
  render() {
1215
1215
  this.shadowRoot.innerHTML = `
1216
1216
  <style>
1217
- /* \u9019\u4E9B\u6A23\u5F0F\u88AB\u9694\u96E2\u5728 Shadow DOM \u5167\uFF0C\u4E0D\u6703\u5F71\u97FF\u5916\u90E8 */
1218
1217
  :host {
1219
1218
  display: block;
1220
1219
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
@@ -1588,12 +1587,16 @@ var init_payment_form = __esm({
1588
1587
  .recur-payuni-iframe {
1589
1588
  height: 36px;
1590
1589
  width: 100%;
1590
+ max-width: 100%;
1591
+ box-sizing: border-box;
1591
1592
  }
1592
1593
 
1593
1594
  .recur-card-row {
1594
1595
  display: grid;
1595
1596
  grid-template-columns: 1fr 1fr;
1596
1597
  gap: 12px;
1598
+ max-width: 100%;
1599
+ box-sizing: border-box;
1597
1600
  }
1598
1601
 
1599
1602
  /* Container needs relative positioning for skeleton overlay */
@@ -1693,6 +1696,7 @@ var init_payment_form = __esm({
1693
1696
  align-items: center;
1694
1697
  justify-content: center;
1695
1698
  gap: 8px;
1699
+ box-sizing: border-box;
1696
1700
  }
1697
1701
 
1698
1702
  .recur-submit-button:hover:not(:disabled) {
@@ -2640,7 +2644,11 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2640
2644
  width: 90%;
2641
2645
  max-height: 90vh;
2642
2646
  overflow-y: auto;
2647
+ overflow-x: hidden;
2643
2648
  position: relative;
2649
+ border-radius: 12px;
2650
+ background: white;
2651
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
2644
2652
  `;
2645
2653
  const closeButton = document.createElement("button");
2646
2654
  closeButton.className = "recur-sdk__close-button";
@@ -2678,11 +2686,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2678
2686
  loadingContainer = document.createElement("div");
2679
2687
  loadingContainer.id = "recur-modal-loading";
2680
2688
  loadingContainer.className = "recur-sdk__loading-container";
2681
- loadingContainer.style.cssText = `
2682
- background: white;
2683
- border-radius: 12px;
2684
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
2685
- `;
2686
2689
  const skeleton = document.createElement("recur-payment-form-skeleton");
2687
2690
  loadingContainer.appendChild(skeleton);
2688
2691
  modalContent.appendChild(closeButton);
package/dist/recur.umd.js CHANGED
@@ -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:()=>x});var M,g,x,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",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">
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=x.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=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=`
768
768
  <style>
769
769
  :host {
770
770
  position: fixed;
@@ -791,9 +791,8 @@
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);x=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",x)});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 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=`
795
795
  <style>
796
- /* \u9019\u4E9B\u6A23\u5F0F\u88AB\u9694\u96E2\u5728 Shadow DOM \u5167\uFF0C\u4E0D\u6703\u5F71\u97FF\u5916\u90E8 */
797
796
  :host {
798
797
  display: block;
799
798
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
@@ -1097,12 +1096,16 @@
1097
1096
  .recur-payuni-iframe {
1098
1097
  height: 36px;
1099
1098
  width: 100%;
1099
+ max-width: 100%;
1100
+ box-sizing: border-box;
1100
1101
  }
1101
1102
 
1102
1103
  .recur-card-row {
1103
1104
  display: grid;
1104
1105
  grid-template-columns: 1fr 1fr;
1105
1106
  gap: 12px;
1107
+ max-width: 100%;
1108
+ box-sizing: border-box;
1106
1109
  }
1107
1110
 
1108
1111
  /* Container needs relative positioning for skeleton overlay */
@@ -1180,6 +1183,7 @@
1180
1183
  align-items: center;
1181
1184
  justify-content: center;
1182
1185
  gap: 8px;
1186
+ box-sizing: border-box;
1183
1187
  }
1184
1188
 
1185
1189
  .recur-submit-button:hover:not(:disabled) {
@@ -1523,14 +1527,14 @@
1523
1527
  display: block;
1524
1528
  user-select: none;
1525
1529
  transition: height 0.35s ease, opacity 0.4s ease 0.1s;
1526
- `.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 we="https://vendor.payuni.com.tw/sdk/uni-payment.js",xe="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?xe:we,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",`
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",`
1527
1531
  .form-input-focus {
1528
1532
  border-color: var(--ring, hsl(215 16% 47%)) !important;
1529
1533
  outline: 0 !important;
1530
1534
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring, hsl(215 16% 47%)) 50%, transparent) !important;
1531
1535
  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;
1532
1536
  }
1533
- `),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 w=d.creditToken,q=d.sdkTimestamp;if(!w)throw console.error("[Recur SDK] Missing creditToken from checkout for subscription"),new Error("Missing creditToken for subscription payment");F={creditToken:w,timestamp:q||B},console.log("[Recur SDK] Using creditToken from checkout:",w.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 w=await O.json().catch(()=>({}));throw new Error(w.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=`
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=`
1534
1538
  position: fixed;
1535
1539
  top: 0;
1536
1540
  left: 0;
@@ -1546,7 +1550,11 @@
1546
1550
  width: 90%;
1547
1551
  max-height: 90vh;
1548
1552
  overflow-y: auto;
1553
+ overflow-x: hidden;
1549
1554
  position: relative;
1555
+ border-radius: 12px;
1556
+ background: white;
1557
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
1550
1558
  `;let i=document.createElement("button");i.innerHTML="\u2715",i.style.cssText=`
1551
1559
  position: absolute;
1552
1560
  top: 12px;
@@ -1565,11 +1573,7 @@
1565
1573
  border-radius: 50%;
1566
1574
  z-index: 10;
1567
1575
  transition: background 0.2s;
1568
- `,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",s.style.cssText=`
1569
- background: white;
1570
- border-radius: 12px;
1571
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
1572
- `;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);})();
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);})();
1573
1577
  if (typeof window !== "undefined") {
1574
1578
  window.RecurCheckout = RecurCheckout.default;
1575
1579
  window.RecurElements = RecurCheckout.RecurElements;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-tw",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
5
5
  "type": "module",
6
6
  "private": false,