recur-tw 0.8.1 → 0.8.2

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/AGENTS.md ADDED
@@ -0,0 +1,124 @@
1
+ # AI Agent Quick Reference for recur-tw SDK
2
+
3
+ > This file helps AI coding assistants understand the SDK structure quickly.
4
+
5
+ ## Module Structure
6
+
7
+ ```
8
+ recur-tw
9
+ ├── index.js → React SDK (needs React 18+)
10
+ ├── server.js → Server SDK (Node.js only, uses secret key)
11
+ └── recur.umd.js → Vanilla JS (browser, via CDN or script tag)
12
+ ```
13
+
14
+ ## Which Module to Use?
15
+
16
+ | Project Type | Import | Entry Point |
17
+ |-------------|--------|-------------|
18
+ | React/Next.js | `import { RecurProvider, useRecur } from 'recur-tw'` | `dist/index.js` |
19
+ | Node.js Server | `import { Recur } from 'recur-tw/server'` | `dist/server.js` |
20
+ | Vanilla JS (CDN) | `<script src="https://unpkg.com/recur-tw/dist/recur.umd.js">` | UMD global `RecurCheckout` |
21
+ | Vanilla JS (bundler) | NOT SUPPORTED as ESM - use CDN script tag | - |
22
+
23
+ ## IMPORTANT: Vanilla JS Usage
24
+
25
+ The vanilla module (`recur-tw/vanilla`) exports UMD format ONLY. It is NOT an ES module.
26
+
27
+ **CORRECT** - Use via script tag:
28
+ ```html
29
+ <script src="https://unpkg.com/recur-tw/dist/recur.umd.js"></script>
30
+ <script>
31
+ const recur = RecurCheckout.init({ publishableKey: 'pk_xxx' });
32
+ recur.redirectToCheckout({ productId: 'prod_xxx', successUrl: '/success', cancelUrl: '/cancel' });
33
+ </script>
34
+ ```
35
+
36
+ **WRONG** - Do NOT try to import as ESM:
37
+ ```javascript
38
+ // This will NOT work!
39
+ import { init } from 'recur-tw/vanilla';
40
+ ```
41
+
42
+ ## React Quick Start
43
+
44
+ ```tsx
45
+ 'use client';
46
+ import { RecurProvider, useRecur, useProducts } from 'recur-tw';
47
+
48
+ // 1. Wrap app with provider
49
+ function App() {
50
+ return (
51
+ <RecurProvider config={{ publishableKey: 'pk_xxx' }}>
52
+ <CheckoutPage />
53
+ </RecurProvider>
54
+ );
55
+ }
56
+
57
+ // 2. Use hooks
58
+ function CheckoutPage() {
59
+ const { data: products } = useProducts();
60
+ const { checkout } = useRecur();
61
+
62
+ return (
63
+ <button onClick={() => checkout({
64
+ planId: products[0].id,
65
+ customerEmail: 'user@example.com'
66
+ })}>
67
+ Subscribe
68
+ </button>
69
+ );
70
+ }
71
+ ```
72
+
73
+ ## Server SDK Quick Start (Node.js)
74
+
75
+ ```typescript
76
+ import { Recur } from 'recur-tw/server';
77
+
78
+ const recur = new Recur({ secretKey: 'sk_xxx' });
79
+
80
+ // Create checkout session
81
+ const session = await recur.checkoutSessions.create({
82
+ productId: 'prod_xxx',
83
+ successUrl: 'https://example.com/success',
84
+ cancelUrl: 'https://example.com/cancel',
85
+ });
86
+
87
+ console.log(session.url); // Redirect user here
88
+ ```
89
+
90
+ ## Available Exports
91
+
92
+ ### Main Module (`recur-tw`)
93
+ - `RecurProvider` - React context provider
94
+ - `useRecur()` - Checkout hook (checkout, isCheckingOut)
95
+ - `useProducts()` - Fetch products hook
96
+ - Types: `RecurConfig`, `CheckoutOptions`, `Product`, etc.
97
+
98
+ ### Server Module (`recur-tw/server`)
99
+ - `Recur` - Server SDK class
100
+ - `recur.checkoutSessions.create()` - Create checkout session
101
+ - `recur.checkoutSessions.retrieve()` - Get session details
102
+ - `recur.portal.createSession()` - Create customer portal session
103
+
104
+ ### Vanilla Module (UMD global `RecurCheckout`)
105
+ - `RecurCheckout.init(config)` - Initialize SDK
106
+ - `recur.checkout(options)` - Embedded checkout
107
+ - `recur.redirectToCheckout(options)` - Hosted checkout redirect
108
+ - `recur.createCheckoutSession(options)` - Get session URL
109
+
110
+ ## Key Differences
111
+
112
+ | Feature | React SDK | Server SDK | Vanilla JS |
113
+ |---------|-----------|------------|------------|
114
+ | Environment | Browser | Node.js | Browser |
115
+ | Auth Key | Publishable (`pk_*`) | Secret (`sk_*`) | Publishable (`pk_*`) |
116
+ | Import Style | ESM | ESM | Script tag (UMD) |
117
+ | React Required | Yes | No | No |
118
+
119
+ ## Common Mistakes
120
+
121
+ 1. **Trying to import vanilla as ESM** - Use script tag instead
122
+ 2. **Using secret key in browser** - Only use `pk_*` keys client-side
123
+ 3. **Missing RecurProvider** - React hooks need the provider wrapper
124
+ 4. **Wrong import path** - Server SDK is `recur-tw/server`, not `recur-tw`
package/dist/index.cjs CHANGED
@@ -2598,6 +2598,8 @@ function toCamelCase(obj) {
2598
2598
  }
2599
2599
  return obj;
2600
2600
  }
2601
+ var SDK_VERSION = "0.8.1";
2602
+ var SDK_TYPE = "react";
2601
2603
  var RecurContext = React.createContext(null);
2602
2604
  function RecurProvider({ children, config: initialConfig = {} }) {
2603
2605
  const [config, setConfig] = React.useState({
@@ -2635,9 +2637,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2635
2637
  if (!config.publishableKey) {
2636
2638
  throw new Error("publishableKey is required");
2637
2639
  }
2638
- if (!options.customerName) {
2639
- throw new Error("customerName is required");
2640
- }
2641
2640
  if (!options.customerEmail) {
2642
2641
  throw new Error("customerEmail is required");
2643
2642
  }
@@ -2645,7 +2644,10 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2645
2644
  console.log("[Recur SDK] Base URL:", baseUrl);
2646
2645
  const headers = {
2647
2646
  "Content-Type": "application/json",
2648
- "X-Recur-Publishable-Key": config.publishableKey
2647
+ "X-Recur-Publishable-Key": config.publishableKey,
2648
+ "X-Recur-SDK-Type": SDK_TYPE,
2649
+ "X-Recur-SDK-Version": SDK_VERSION,
2650
+ "X-Recur-Source": typeof window !== "undefined" ? window.location.origin : "server"
2649
2651
  };
2650
2652
  let modalContent = null;
2651
2653
  let loadingContainer = null;
@@ -3010,7 +3012,10 @@ function RecurProvider({ children, config: initialConfig = {} }) {
3010
3012
  method: "GET",
3011
3013
  headers: {
3012
3014
  "Content-Type": "application/json",
3013
- "X-Recur-Publishable-Key": config.publishableKey
3015
+ "X-Recur-Publishable-Key": config.publishableKey,
3016
+ "X-Recur-SDK-Type": SDK_TYPE,
3017
+ "X-Recur-SDK-Version": SDK_VERSION,
3018
+ "X-Recur-Source": typeof window !== "undefined" ? window.location.origin : "server"
3014
3019
  }
3015
3020
  });
3016
3021
  if (!response.ok) {
package/dist/index.js CHANGED
@@ -2592,6 +2592,8 @@ function toCamelCase(obj) {
2592
2592
  }
2593
2593
  return obj;
2594
2594
  }
2595
+ var SDK_VERSION = "0.8.1";
2596
+ var SDK_TYPE = "react";
2595
2597
  var RecurContext = createContext(null);
2596
2598
  function RecurProvider({ children, config: initialConfig = {} }) {
2597
2599
  const [config, setConfig] = useState({
@@ -2629,9 +2631,6 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2629
2631
  if (!config.publishableKey) {
2630
2632
  throw new Error("publishableKey is required");
2631
2633
  }
2632
- if (!options.customerName) {
2633
- throw new Error("customerName is required");
2634
- }
2635
2634
  if (!options.customerEmail) {
2636
2635
  throw new Error("customerEmail is required");
2637
2636
  }
@@ -2639,7 +2638,10 @@ function RecurProvider({ children, config: initialConfig = {} }) {
2639
2638
  console.log("[Recur SDK] Base URL:", baseUrl);
2640
2639
  const headers = {
2641
2640
  "Content-Type": "application/json",
2642
- "X-Recur-Publishable-Key": config.publishableKey
2641
+ "X-Recur-Publishable-Key": config.publishableKey,
2642
+ "X-Recur-SDK-Type": SDK_TYPE,
2643
+ "X-Recur-SDK-Version": SDK_VERSION,
2644
+ "X-Recur-Source": typeof window !== "undefined" ? window.location.origin : "server"
2643
2645
  };
2644
2646
  let modalContent = null;
2645
2647
  let loadingContainer = null;
@@ -3004,7 +3006,10 @@ function RecurProvider({ children, config: initialConfig = {} }) {
3004
3006
  method: "GET",
3005
3007
  headers: {
3006
3008
  "Content-Type": "application/json",
3007
- "X-Recur-Publishable-Key": config.publishableKey
3009
+ "X-Recur-Publishable-Key": config.publishableKey,
3010
+ "X-Recur-SDK-Type": SDK_TYPE,
3011
+ "X-Recur-SDK-Version": SDK_VERSION,
3012
+ "X-Recur-Source": typeof window !== "undefined" ? window.location.origin : "server"
3008
3013
  }
3009
3014
  });
3010
3015
  if (!response.ok) {
package/dist/recur.umd.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var RecurCheckout=(()=>{var I=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var ve=(o,e,t)=>e in o?I(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var g=(o,e)=>()=>(o&&(e=o(o=0)),e);var f=(o,e)=>{for(var t in e)I(o,t,{get:e[t],enumerable:!0})},ke=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ge(e))!ye.call(o,i)&&i!==t&&I(o,i,{get:()=>e[i],enumerable:!(r=be(e,i))||r.enumerable});return o};var xe=o=>ke(I({},"__esModule",{value:!0}),o);var c=(o,e,t)=>ve(o,typeof e!="symbol"?e+"":e,t);var V={};f(V,{RecurLoadingSpinner:()=>R});var R,X=g(()=>{"use strict";R=class extends HTMLElement{static get observedAttributes(){return["message","size"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get message(){return this.getAttribute("message")||"\u6B63\u5728\u8655\u7406\u8A02\u95B1..."}get size(){let e=this.getAttribute("size");return e==="small"||e==="large"?e:"medium"}getSizeValue(){return{small:24,medium:40,large:56}[this.size]}render(){let e=this.getSizeValue();this.shadowRoot.innerHTML=`
1
+ "use strict";var RecurCheckout=(()=>{var I=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var ve=(o,e,t)=>e in o?I(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var b=(o,e)=>()=>(o&&(e=o(o=0)),e);var f=(o,e)=>{for(var t in e)I(o,t,{get:e[t],enumerable:!0})},ke=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of be(e))!ye.call(o,i)&&i!==t&&I(o,i,{get:()=>e[i],enumerable:!(r=ge(e,i))||r.enumerable});return o};var xe=o=>ke(I({},"__esModule",{value:!0}),o);var c=(o,e,t)=>ve(o,typeof e!="symbol"?e+"":e,t);var V={};f(V,{RecurLoadingSpinner:()=>R});var R,X=b(()=>{"use strict";R=class extends HTMLElement{static get observedAttributes(){return["message","size"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get message(){return this.getAttribute("message")||"\u6B63\u5728\u8655\u7406\u8A02\u95B1..."}get size(){let e=this.getAttribute("size");return e==="small"||e==="large"?e:"medium"}getSizeValue(){return{small:24,medium:40,large:56}[this.size]}render(){let e=this.getSizeValue();this.shadowRoot.innerHTML=`
2
2
  <style>
3
3
  :host {
4
4
  display: block;
@@ -40,7 +40,7 @@
40
40
 
41
41
  <div class="recur-sdk__spinner"></div>
42
42
  ${this.message?`<p class="recur-sdk__loading-text">${this.message}</p>`:""}
43
- `}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",R)});var J={};f(J,{RecurSuccessMessage:()=>P});var P,W=g(()=>{"use strict";P=class extends HTMLElement{static get observedAttributes(){return["title","message","icon"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get successTitle(){return this.getAttribute("title")||"Subscription Complete!"}get successMessage(){return this.getAttribute("message")||"Thank you for subscribing. Your payment has been processed successfully."}get showIcon(){return this.getAttribute("icon")!=="false"}render(){this.shadowRoot.innerHTML=`
43
+ `}};typeof window<"u"&&!customElements.get("recur-loading-spinner")&&customElements.define("recur-loading-spinner",R)});var J={};f(J,{RecurSuccessMessage:()=>P});var P,W=b(()=>{"use strict";P=class extends HTMLElement{static get observedAttributes(){return["title","message","icon"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get successTitle(){return this.getAttribute("title")||"Subscription Complete!"}get successMessage(){return this.getAttribute("message")||"Thank you for subscribing. Your payment has been processed successfully."}get showIcon(){return this.getAttribute("icon")!=="false"}render(){this.shadowRoot.innerHTML=`
44
44
  <style>
45
45
  :host {
46
46
  display: block;
@@ -121,7 +121,7 @@
121
121
  <p class="recur-sdk__success-message">${this.successMessage}</p>
122
122
  <slot></slot>
123
123
  </div>
124
- `}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",P)});var G={};f(G,{RecurErrorDisplay:()=>L});var L,Z=g(()=>{"use strict";L=class extends HTMLElement{static get observedAttributes(){return["error","dismissible"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get error(){return this.getAttribute("error")||""}get isDismissible(){return this.getAttribute("dismissible")==="true"}handleDismiss(){this.dispatchEvent(new CustomEvent("dismiss",{bubbles:!0,composed:!0})),this.remove()}render(){if(!this.error){this.shadowRoot.innerHTML="";return}this.shadowRoot.innerHTML=`
124
+ `}};typeof window<"u"&&!customElements.get("recur-success-message")&&customElements.define("recur-success-message",P)});var G={};f(G,{RecurErrorDisplay:()=>L});var L,Z=b(()=>{"use strict";L=class extends HTMLElement{static get observedAttributes(){return["error","dismissible"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get error(){return this.getAttribute("error")||""}get isDismissible(){return this.getAttribute("dismissible")==="true"}handleDismiss(){this.dispatchEvent(new CustomEvent("dismiss",{bubbles:!0,composed:!0})),this.remove()}render(){if(!this.error){this.shadowRoot.innerHTML="";return}this.shadowRoot.innerHTML=`
125
125
  <style>
126
126
  :host {
127
127
  display: block;
@@ -211,7 +211,7 @@
211
211
  </button>
212
212
  `:""}
213
213
  </div>
214
- `,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",L)});var Q={};f(Q,{RecurSkeletonLoader:()=>M});var M,ee=g(()=>{"use strict";M=class extends HTMLElement{static get observedAttributes(){return["type"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get type(){let e=this.getAttribute("type");return e==="list"||e==="card"?e:"payment-form"}renderPaymentFormSkeleton(){return`
214
+ `,this.isDismissible&&this.shadowRoot.querySelector(".recur-sdk__error-dismiss")?.addEventListener("click",()=>this.handleDismiss())}};typeof window<"u"&&!customElements.get("recur-error-display")&&customElements.define("recur-error-display",L)});var Q={};f(Q,{RecurSkeletonLoader:()=>M});var M,ee=b(()=>{"use strict";M=class extends HTMLElement{static get observedAttributes(){return["type"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}attributeChangedCallback(e,t,r){t!==r&&this.render()}get type(){let e=this.getAttribute("type");return e==="list"||e==="card"?e:"payment-form"}renderPaymentFormSkeleton(){return`
215
215
  <div class="skeleton-field">
216
216
  <div class="skeleton-label"></div>
217
217
  <div class="skeleton-input"></div>
@@ -377,7 +377,7 @@
377
377
  </style>
378
378
 
379
379
  ${e}
380
- `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",M)});var te={};f(te,{RecurPaymentFormSkeleton:()=>U});var U,re=g(()=>{"use strict";U=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
380
+ `}};typeof window<"u"&&!customElements.get("recur-skeleton-loader")&&customElements.define("recur-skeleton-loader",M)});var te={};f(te,{RecurPaymentFormSkeleton:()=>U});var U,re=b(()=>{"use strict";U=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render()}render(){this.shadowRoot.innerHTML=`
381
381
  <style>
382
382
  :host {
383
383
  display: block;
@@ -644,7 +644,7 @@
644
644
  <p class="security-text">\u60A8\u7684\u4ED8\u6B3E\u8CC7\u8A0A\u7D93\u904E\u52A0\u5BC6\u4FDD\u8B77</p>
645
645
  </div>
646
646
  </div>
647
- `}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",U)});var ie={};f(ie,{RecurToast:()=>_,RecurToastContainer:()=>E});var _,y,E,se=g(()=>{"use strict";_=class extends HTMLElement{static get observedAttributes(){return["message","type","duration"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupAutoDismiss()}get message(){return this.getAttribute("message")||"Notification"}get type(){let e=this.getAttribute("type");return e==="success"||e==="error"?e:"info"}get duration(){let e=this.getAttribute("duration");return e?parseInt(e,10):5e3}setupAutoDismiss(){let e=this.duration;e>0&&setTimeout(()=>this.dismiss(),e)}dismiss(){this.style.animation="recur-toast-slide-out 0.3s ease-in-out",setTimeout(()=>this.remove(),300)}getTypeIcon(){switch(this.type){case"success":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
647
+ `}};typeof window<"u"&&!customElements.get("recur-payment-form-skeleton")&&customElements.define("recur-payment-form-skeleton",U)});var ie={};f(ie,{RecurToast:()=>_,RecurToastContainer:()=>E});var _,y,E,se=b(()=>{"use strict";_=class extends HTMLElement{static get observedAttributes(){return["message","type","duration"]}constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.setupAutoDismiss()}get message(){return this.getAttribute("message")||"Notification"}get type(){let e=this.getAttribute("type");return e==="success"||e==="error"?e:"info"}get duration(){let e=this.getAttribute("duration");return e?parseInt(e,10):5e3}setupAutoDismiss(){let e=this.duration;e>0&&setTimeout(()=>this.dismiss(),e)}dismiss(){this.style.animation="recur-toast-slide-out 0.3s ease-in-out",setTimeout(()=>this.remove(),300)}getTypeIcon(){switch(this.type){case"success":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
648
648
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
649
649
  </svg>`;case"error":return`<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
650
650
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
@@ -791,7 +791,7 @@
791
791
  </style>
792
792
 
793
793
  <slot></slot>
794
- `}static getInstance(){return y.instance||(y.instance=document.querySelector("recur-toast-container"),y.instance||(y.instance=document.createElement("recur-toast-container"),document.body.appendChild(y.instance))),y.instance}};c(y,"instance",null);E=y;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",_);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",E)});var oe={};f(oe,{RecurPaymentForm:()=>A});var A,ne=g(()=>{"use strict";A=class extends HTMLElement{constructor(){super();c(this,"containerId");c(this,"customStyles");c(this,"_isInitializing",!1);c(this,"_initializationAborted",!1);this.containerId=this.getAttribute("container-id")||`recur-${Date.now()}`,this.customStyles=this.getAttribute("custom-styles")||"",this.attachShadow({mode:"open"})}connectedCallback(){this.render()}disconnectedCallback(){console.log("[PaymentForm] Component disconnected, cleaning up..."),this._initializationAborted=!0,this._paymentSession=null;let t=document.getElementById(`${this.containerId}-submit-btn`);if(t){let r=t.cloneNode(!0);t.parentNode?.replaceChild(r,t)}}static get observedAttributes(){return["custom-styles","customer-name","customer-email","plan-name","amount","billing-period"]}attributeChangedCallback(t,r,i){t==="custom-styles"&&r!==i?(this.customStyles=i||"",this.updateCustomStyles()):r!==i&&this.updateCustomerInfoSection()}render(){this.shadowRoot.innerHTML=`
794
+ `}static getInstance(){return y.instance||(y.instance=document.querySelector("recur-toast-container"),y.instance||(y.instance=document.createElement("recur-toast-container"),document.body.appendChild(y.instance))),y.instance}};c(y,"instance",null);E=y;typeof window<"u"&&!customElements.get("recur-toast")&&customElements.define("recur-toast",_);typeof window<"u"&&!customElements.get("recur-toast-container")&&customElements.define("recur-toast-container",E)});var oe={};f(oe,{RecurPaymentForm:()=>A});var A,ne=b(()=>{"use strict";A=class extends HTMLElement{constructor(){super();c(this,"containerId");c(this,"customStyles");c(this,"_isInitializing",!1);c(this,"_initializationAborted",!1);this.containerId=this.getAttribute("container-id")||`recur-${Date.now()}`,this.customStyles=this.getAttribute("custom-styles")||"",this.attachShadow({mode:"open"})}connectedCallback(){this.render()}disconnectedCallback(){console.log("[PaymentForm] Component disconnected, cleaning up..."),this._initializationAborted=!0,this._paymentSession=null;let t=document.getElementById(`${this.containerId}-submit-btn`);if(t){let r=t.cloneNode(!0);t.parentNode?.replaceChild(r,t)}}static get observedAttributes(){return["custom-styles","customer-name","customer-email","plan-name","amount","billing-period"]}attributeChangedCallback(t,r,i){t==="custom-styles"&&r!==i?(this.customStyles=i||"",this.updateCustomStyles()):r!==i&&this.updateCustomerInfoSection()}render(){this.shadowRoot.innerHTML=`
795
795
  <style>
796
796
  :host {
797
797
  display: block;
@@ -1223,7 +1223,7 @@
1223
1223
  `,t}async initializePayment(t,r){if(this._initializationAborted)return console.log("[PaymentForm] Initialization aborted before start"),null;if(this._isInitializing=!0,await this.updateComplete(),this._initializationAborted)return console.log("[PaymentForm] Initialization aborted after updateComplete"),this._isInitializing=!1,null;if(!window.UniPayment)throw this._isInitializing=!1,new Error("PAYUNi SDK not loaded");try{let i=document.getElementById(`${this.containerId}-card-no`),s=document.getElementById(`${this.containerId}-card-exp`),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 n=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 n.start()}catch(l){if((l?.message?.includes("1008")||l?.message?.includes("timeout")||l?.code===1008)&&this._initializationAborted)return console.log("[PaymentForm] Caught 1008 timeout error after component disconnect - ignoring"),this._isInitializing=!1,null;throw l}return this._initializationAborted?(console.log("[PaymentForm] Initialization aborted after paymentSession.start()"),this._isInitializing=!1,null):(this.hideCardSkeletons(),n.onUpdate?.(l=>{if(this._initializationAborted){console.log("[PaymentForm] Ignoring onUpdate event - component disconnected");return}console.log("[PaymentForm] PAYUNi update:",l);let d=l.status&&l.status.CardNo===!0&&l.status.CardExp===!0&&l.status.CardCvc===!0,v=document.getElementById(`${this.containerId}-submit-btn`);v&&(v.disabled=!d,console.log("[PaymentForm] Submit button disabled:",!d))}),this._initializationAborted?(console.log("[PaymentForm] Initialization aborted before saving session"),this._isInitializing=!1,null):(this._paymentSession=n,this.setupFormSubmission(),this._isInitializing=!1,n))}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=document.getElementById(`${this.containerId}-email`),n=document.getElementById(`${this.containerId}-name`);if(a&&n){if(i=a.value,s=n.value,!i||!s){this.showError("\u8ACB\u586B\u5BEB\u59D3\u540D\u548C\u96FB\u5B50\u90F5\u4EF6");return}}else if(i=this.getAttribute("customer-email")||void 0,s=this.getAttribute("customer-name")||void 0,!i||!s){this.showError("\u5BA2\u6236\u8CC7\u8A0A\u4E0D\u5B8C\u6574");return}this.clearError(),this.setButtonLoading(!0),this.dispatchEvent(new CustomEvent("submit",{detail:{customerEmail:i,customerName:s,paymentSession:this._paymentSession},bubbles:!0,composed:!0}))})}setButtonLoading(t){let r=document.getElementById(`${this.containerId}-submit-btn`);r&&(t?(r.classList.add("loading"),r.disabled=!0,r.innerHTML=`
1224
1224
  <span class="recur-loading-spinner"></span>
1225
1225
  <span>\u8655\u7406\u4E2D...</span>
1226
- `):(r.classList.remove("loading"),r.disabled=!1,r.innerHTML='<span id="'+this.containerId+'-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>'))}resetButton(){this.setButtonLoading(!1)}showError(t){let r=this.querySelector(".recur-sdk__error-container");r||(r=document.createElement("div"),r.className="recur-sdk__error-container",r.style.cssText="margin-bottom: 16px;",this.insertBefore(r,this.firstChild));let i=document.createElement("recur-error-display");i.setAttribute("error",t),i.setAttribute("dismissible","true"),r.innerHTML="",r.appendChild(i),i.scrollIntoView({behavior:"smooth",block:"center"})}clearError(){let t=this.querySelector(".recur-sdk__error-container");t&&(t.innerHTML="")}updateComplete(){return new Promise(t=>{if(this.isConnected)setTimeout(t,0);else{let r=new MutationObserver(()=>{this.isConnected&&(r.disconnect(),setTimeout(t,0))});r.observe(document.body,{childList:!0,subtree:!0})}})}getFormData(){return{email:document.getElementById(`${this.containerId}-email`)?.value,name:document.getElementById(`${this.containerId}-name`)?.value}}setFormData(t){if(t.email){let r=document.getElementById(`${this.containerId}-email`);r&&(r.value=t.email)}if(t.name){let r=document.getElementById(`${this.containerId}-name`);r&&(r.value=t.name)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",A)});var ae={};f(ae,{RecurCheckoutButton:()=>D});var D,ce=g(()=>{"use strict";D=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),i=this.getAttribute("product-id"),s=this.getAttribute("success-url"),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 n=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:n.id,url:n.url},bubbles:!0,composed:!0})),window.location.href=n.url}catch(n){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(n.message||"Failed to create checkout session")}});this.attachShadow({mode:"open"})}static get observedAttributes(){return["publishable-key","product-id","success-url","cancel-url","customer-email","mode","button-text","button-style","disabled"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1226
+ `):(r.classList.remove("loading"),r.disabled=!1,r.innerHTML='<span id="'+this.containerId+'-submit-text">\u78BA\u8A8D\u4ED8\u6B3E</span>'))}resetButton(){this.setButtonLoading(!1)}showError(t){let r=this.querySelector(".recur-sdk__error-container");r||(r=document.createElement("div"),r.className="recur-sdk__error-container",r.style.cssText="margin-bottom: 16px;",this.insertBefore(r,this.firstChild));let i=document.createElement("recur-error-display");i.setAttribute("error",t),i.setAttribute("dismissible","true"),r.innerHTML="",r.appendChild(i),i.scrollIntoView({behavior:"smooth",block:"center"})}clearError(){let t=this.querySelector(".recur-sdk__error-container");t&&(t.innerHTML="")}updateComplete(){return new Promise(t=>{if(this.isConnected)setTimeout(t,0);else{let r=new MutationObserver(()=>{this.isConnected&&(r.disconnect(),setTimeout(t,0))});r.observe(document.body,{childList:!0,subtree:!0})}})}getFormData(){return{email:document.getElementById(`${this.containerId}-email`)?.value,name:document.getElementById(`${this.containerId}-name`)?.value}}setFormData(t){if(t.email){let r=document.getElementById(`${this.containerId}-email`);r&&(r.value=t.email)}if(t.name){let r=document.getElementById(`${this.containerId}-name`);r&&(r.value=t.name)}}};customElements.get("recur-payment-form")||customElements.define("recur-payment-form",A)});var ae={};f(ae,{RecurCheckoutButton:()=>D});var D,ce=b(()=>{"use strict";D=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("publishable-key"),i=this.getAttribute("product-id"),s=this.getAttribute("success-url"),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 n=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:n.id,url:n.url},bubbles:!0,composed:!0})),window.location.href=n.url}catch(n){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(n.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=`
1227
1227
  <style>
1228
1228
  :host {
1229
1229
  display: inline-block;
@@ -1322,7 +1322,7 @@
1322
1322
  ${this._isLoading?'<span class="spinner"></span>':""}
1323
1323
  <span>${this._isLoading?"\u8655\u7406\u4E2D...":t}</span>
1324
1324
  </button>
1325
- `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),i={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(i.mode=t.mode),t.customerEmail&&(i.customerEmail=t.customerEmail);let s=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(i)});if(!s.ok){let a=await s.json().catch(()=>({}));throw new Error(a.error?.message||`HTTP ${s.status}: Failed to create checkout session`)}return s.json()}getApiBaseUrl(){let t=this.getAttribute("api-base-url");if(t)return t;if(typeof window<"u"){let r=window.location.hostname;if(r==="localhost"||r.includes(".test")||r.includes(".local")||r==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}resolveUrl(t){return t.startsWith("/")?`${window.location.origin}${t}`:t}dispatchError(t){console.error("[recur-checkout]",t),this.dispatchEvent(new CustomEvent("checkout-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-checkout")&&customElements.define("recur-checkout",D)});var le={};f(le,{RecurPortalButton:()=>z});var z,de=g(()=>{"use strict";z=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),i=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(i){await this.fetchAndRedirect(i);return}this.dispatchError("Missing required attribute: either portal-url or api-endpoint must be provided")});this.attachShadow({mode:"open"})}static get observedAttributes(){return["portal-url","api-endpoint","customer-id","return-url","button-text","button-style","disabled","target"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1325
+ `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}async createCheckoutSession(t){let r=this.getApiBaseUrl(),i={productId:t.productId,successUrl:t.successUrl,cancelUrl:t.cancelUrl};t.mode&&(i.mode=t.mode),t.customerEmail&&(i.customerEmail=t.customerEmail);let s=await fetch(`${r}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(i)});if(!s.ok){let a=await s.json().catch(()=>({}));throw new Error(a.error?.message||`HTTP ${s.status}: Failed to create checkout session`)}return s.json()}getApiBaseUrl(){let t=this.getAttribute("api-base-url");if(t)return t;if(typeof window<"u"){let r=window.location.hostname;if(r==="localhost"||r.includes(".test")||r.includes(".local")||r==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}resolveUrl(t){return t.startsWith("/")?`${window.location.origin}${t}`:t}dispatchError(t){console.error("[recur-checkout]",t),this.dispatchEvent(new CustomEvent("checkout-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-checkout")&&customElements.define("recur-checkout",D)});var le={};f(le,{RecurPortalButton:()=>z});var z,de=b(()=>{"use strict";z=class extends HTMLElement{constructor(){super();c(this,"_isLoading",!1);c(this,"handleClick",async t=>{if(t.preventDefault(),this._isLoading||this.hasAttribute("disabled"))return;let r=this.getAttribute("portal-url"),i=this.getAttribute("api-endpoint");if(r){this.redirectToPortal(r);return}if(i){await this.fetchAndRedirect(i);return}this.dispatchError("Missing required attribute: either portal-url or api-endpoint must be provided")});this.attachShadow({mode:"open"})}static get observedAttributes(){return["portal-url","api-endpoint","customer-id","return-url","button-text","button-style","disabled","target"]}connectedCallback(){this.render(),this.setupEventListeners()}disconnectedCallback(){let t=this.shadowRoot?.querySelector("button");t&&t.removeEventListener("click",this.handleClick)}attributeChangedCallback(t,r,i){r!==i&&this.render()}render(){let t=this.getAttribute("button-text")||this.textContent?.trim()||"\u7BA1\u7406\u8A02\u95B1",r=this.getAttribute("button-style")||"primary",i=this.hasAttribute("disabled")||this._isLoading;this.shadowRoot.innerHTML=`
1326
1326
  <style>
1327
1327
  :host {
1328
1328
  display: inline-block;
@@ -1449,7 +1449,7 @@
1449
1449
  <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
1450
1450
  <circle cx="12" cy="7" r="4"/>
1451
1451
  </svg>
1452
- `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),i=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let s={};r&&(s.customerId=r),i&&(s.returnUrl=i);let a=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!a.ok){let d=await a.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${a.status}: Failed to create portal session`)}let n=await a.json(),l=n.url||n.portalUrl;if(!l)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(l)}catch(s){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(s.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",z)});var Ie={};f(Ie,{RecurCheckout:()=>S,RecurElements:()=>w,createElements:()=>j,default:()=>Te,init:()=>pe});async function we(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(X(),V)),Promise.resolve().then(()=>(W(),J)),Promise.resolve().then(()=>(Z(),G)),Promise.resolve().then(()=>(ee(),Q)),Promise.resolve().then(()=>(re(),te)),Promise.resolve().then(()=>(se(),ie)),Promise.resolve().then(()=>(ne(),oe)),Promise.resolve().then(()=>(ce(),ae)),Promise.resolve().then(()=>(de(),le))]);let e=["recur-loading-spinner","recur-success-message","recur-error-display","recur-skeleton-loader","recur-payment-form-skeleton","recur-toast","recur-toast-container","recur-payment-form","recur-checkout","recur-portal"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&we();function Ee(o){return o.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function b(o){if(o==null)return o;if(Array.isArray(o))return o.map(e=>b(e));if(o instanceof Date)return o;if(typeof o=="object"){let e={};for(let[t,r]of Object.entries(o)){let i=Ee(t);e[i]=b(r)}return e}return o}var H=class{constructor(e){c(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,i=e.productId||e.planId,s=e.productSlug;if(!i&&!s)throw new Error("Either productId or productSlug is required");let a={customerName:t,customerEmail:r};i&&(a.productId=i),s&&(a.productSlug=s);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(a)});if(!n.ok){let d=await n.json().catch(()=>({}));throw{code:d.error||"CHECKOUT_FAILED",message:d.message||"Failed to initiate checkout",details:d}}let l=await n.json();return b(l)}async fetchProducts(e){let t=new URL(`${this.config.baseUrl}/v1/products`);e?.type&&t.searchParams.set("type",e.type);let r=await fetch(t.toString(),{method:"GET",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey}});if(!r.ok){let s=await r.json().catch(()=>({}));throw{code:s.error||"FETCH_PRODUCTS_FAILED",message:s.message||"Failed to fetch products",details:s}}let i=await r.json();return b(i)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var $=class{constructor(e,t){c(this,"config");c(this,"options");c(this,"container");c(this,"checkoutId",null);c(this,"sdkToken",null);c(this,"sdkEnv","S");c(this,"payuniSDK",null);c(this,"isFormValid",!1);if(this.config=e,this.options=t,typeof t.container=="string"){let r=document.querySelector(t.container);if(!r)throw new Error(`Container not found: ${t.container}`);this.container=r}else this.container=t.container}async render(){try{await this.initCheckout(),this.renderHTML(),await this.loadPayUniSDK(),await this.initPayUniSDK(),this.setupFormSubmit()}catch(e){this.handleError(e)}}getBaseUrl(){if(this.config.baseUrl)return this.config.baseUrl;if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}async initCheckout(){let e=this.getBaseUrl(),t=await fetch(`${e}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({productId:this.options.planId,customerEmail:this.options.customerEmail,customerName:this.options.customerName})});if(!t.ok){let s=await t.json().catch(()=>({}));throw new Error(s.error||"Failed to initialize checkout")}let r=await t.json(),i=b(r);this.checkoutId=i.checkout.id,this.sdkToken=i.sdkToken,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
1452
+ `}setupEventListeners(){let t=this.shadowRoot?.querySelector("button");t&&t.addEventListener("click",this.handleClick)}redirectToPortal(t){let r=this.getAttribute("target");this.dispatchEvent(new CustomEvent("portal-redirect",{detail:{url:t},bubbles:!0,composed:!0})),r==="_blank"?window.open(t,"_blank","noopener,noreferrer"):window.location.href=t}async fetchAndRedirect(t){let r=this.getAttribute("customer-id"),i=this.getAttribute("return-url");this._isLoading=!0,this.render(),this.setupEventListeners();try{let s={};r&&(s.customerId=r),i&&(s.returnUrl=i);let a=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!a.ok){let d=await a.json().catch(()=>({}));throw new Error(d.error?.message||d.message||`HTTP ${a.status}: Failed to create portal session`)}let n=await a.json(),l=n.url||n.portalUrl;if(!l)throw new Error("Portal URL not found in response");this._isLoading=!1,this.render(),this.setupEventListeners(),this.redirectToPortal(l)}catch(s){this._isLoading=!1,this.render(),this.setupEventListeners(),this.dispatchError(s.message||"Failed to create portal session")}}dispatchError(t){console.error("[recur-portal]",t),this.dispatchEvent(new CustomEvent("portal-error",{detail:{message:t},bubbles:!0,composed:!0}))}};typeof window<"u"&&!customElements.get("recur-portal")&&customElements.define("recur-portal",z)});var Pe={};f(Pe,{RecurCheckout:()=>C,RecurElements:()=>w,createElements:()=>j,default:()=>Re,init:()=>pe});async function we(){if(typeof window>"u"){console.warn("[Recur SDK] Cannot register Web Components: window is not defined");return}await Promise.all([Promise.resolve().then(()=>(X(),V)),Promise.resolve().then(()=>(W(),J)),Promise.resolve().then(()=>(Z(),G)),Promise.resolve().then(()=>(ee(),Q)),Promise.resolve().then(()=>(re(),te)),Promise.resolve().then(()=>(se(),ie)),Promise.resolve().then(()=>(ne(),oe)),Promise.resolve().then(()=>(ce(),ae)),Promise.resolve().then(()=>(de(),le))]);let e=["recur-loading-spinner","recur-success-message","recur-error-display","recur-skeleton-loader","recur-payment-form-skeleton","recur-toast","recur-toast-container","recur-payment-form","recur-checkout","recur-portal"].filter(t=>!customElements.get(t));e.length>0&&console.warn("[Recur SDK] The following components are not registered:",e)}typeof window<"u"&&we();function Ee(o){return o.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function g(o){if(o==null)return o;if(Array.isArray(o))return o.map(e=>g(e));if(o instanceof Date)return o;if(typeof o=="object"){let e={};for(let[t,r]of Object.entries(o)){let i=Ee(t);e[i]=g(r)}return e}return o}var Se="0.8.1",Ce="vanilla",H=class{constructor(e){c(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:"https://api.recur.tw",...e}}getHeaders(){return{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey,"X-Recur-SDK-Type":Ce,"X-Recur-SDK-Version":Se,"X-Recur-Source":typeof window<"u"?window.location.origin:"server"}}async createSubscription(e){let{customerName:t,customerEmail:r}=e,i=e.productId||e.planId,s=e.productSlug;if(!i&&!s)throw new Error("Either productId or productSlug is required");let a={customerName:t,customerEmail:r};i&&(a.productId=i),s&&(a.productSlug=s);let n=await fetch(`${this.config.baseUrl}/v1/subscriptions`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(a)});if(!n.ok){let d=await n.json().catch(()=>({}));throw{code:d.error||"CHECKOUT_FAILED",message:d.message||"Failed to initiate checkout",details:d}}let l=await n.json();return g(l)}async fetchProducts(e){let t=new URL(`${this.config.baseUrl}/v1/products`);e?.type&&t.searchParams.set("type",e.type);let r=await fetch(t.toString(),{method:"GET",headers:this.getHeaders()});if(!r.ok){let s=await r.json().catch(()=>({}));throw{code:s.error||"FETCH_PRODUCTS_FAILED",message:s.message||"Failed to fetch products",details:s}}let i=await r.json();return g(i)}async fetchPlans(){return{plans:(await this.fetchProducts({type:"SUBSCRIPTION"})).products}}getConfig(){return{...this.config}}};var $=class{constructor(e,t){c(this,"config");c(this,"options");c(this,"container");c(this,"checkoutId",null);c(this,"sdkToken",null);c(this,"sdkEnv","S");c(this,"payuniSDK",null);c(this,"isFormValid",!1);if(this.config=e,this.options=t,typeof t.container=="string"){let r=document.querySelector(t.container);if(!r)throw new Error(`Container not found: ${t.container}`);this.container=r}else this.container=t.container}async render(){try{await this.initCheckout(),this.renderHTML(),await this.loadPayUniSDK(),await this.initPayUniSDK(),this.setupFormSubmit()}catch(e){this.handleError(e)}}getBaseUrl(){if(this.config.baseUrl)return this.config.baseUrl;if(typeof window<"u"){let e=window.location.hostname;if(e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"}async initCheckout(){let e=this.getBaseUrl(),t=await fetch(`${e}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({productId:this.options.planId,customerEmail:this.options.customerEmail,customerName:this.options.customerName})});if(!t.ok){let s=await t.json().catch(()=>({}));throw new Error(s.error||"Failed to initialize checkout")}let r=await t.json(),i=g(r);this.checkoutId=i.checkout.id,this.sdkToken=i.sdkToken,this.sdkEnv=this.config.publishableKey.startsWith("pk_test_")?"S":"P"}renderHTML(){this.container.innerHTML=`
1453
1453
  <div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
1454
1454
  <div class="recur-checkout-header" style="margin-bottom: 24px;">
1455
1455
  <h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
@@ -1526,7 +1526,7 @@
1526
1526
  display: block;
1527
1527
  user-select: none;
1528
1528
  transition: height 0.35s ease, opacity 0.4s ease 0.1s;
1529
- `.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,i)=>{let s=setTimeout(()=>{i(new Error("Elements initialization timeout"))},3e4),a=()=>{clearTimeout(s),this.off("ready",a),r()},n=l=>{clearTimeout(s),this.off("error",n),i(new Error(l.message||"Elements initialization failed"))};this.on("ready",a),this.on("error",n)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(i=>i(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let i=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),s=n=>{clearTimeout(i),this.off("tokenized",s),t(n)},a=n=>{clearTimeout(i),this.off("error",a),r(new Error(n.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,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function j(o){return new w(o)}var Ce="https://vendor.payuni.com.tw/sdk/uni-payment.js",Se="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",ue=!1,N=!1,C=null;async function me(o=!1){return ue&&window.UniPayment?Promise.resolve():(N&&C||(N=!0,C=new Promise((e,t)=>{let r=document.createElement("script");r.src=o?Se:Ce,r.async=!0,r.onload=()=>{ue=!0,N=!1,e()},r.onerror=()=>{N=!1,C=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),C)}var S=class{constructor(e){c(this,"core");c(this,"currentModal",null);c(this,"currentIframe",null);c(this,"currentModalOverlay",null);this.core=new H(e)}async fetchProducts(e){return await this.core.fetchProducts(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new $(t,e).render()}async redirectToCheckout(e){let t=await this.createCheckoutSession(e);window.location.href=t.url}async createCheckoutSession(e){let t=this.getBaseUrl();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");let r={};e.productId&&(r.productId=e.productId),e.productSlug&&(r.productSlug=e.productSlug),e.customerEmail&&(r.customerEmail=e.customerEmail),e.customerName&&(r.customerName=e.customerName),e.externalCustomerId&&(r.externalCustomerId=e.externalCustomerId),e.successUrl&&(r.successUrl=e.successUrl),e.cancelUrl&&(r.cancelUrl=e.cancelUrl);let i=this.core.getConfig(),s=await fetch(`${t}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":i.publishableKey},body:JSON.stringify(r)});if(!s.ok){let l=await s.json().catch(()=>({}));throw new Error(l.error?.message||l.error||"Failed to create checkout session")}let a=await s.json(),n=b(a);return{id:n.checkout.id,url:n.url,expiresAt:n.checkout.expiresAt}}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 a=this.getBaseUrl();console.log("[Recur SDK] Base URL:",a);let n={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},l=e.mode||"modal",d=null;if(l==="modal"){let m=this.createModalWithSkeleton(e.onClose);r=m.overlay,d=m.container}else if(l==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let m=document.createElement("recur-payment-form-skeleton");d.appendChild(m)}console.log("[Recur SDK] Step 1: Creating checkout session...");let v={customerName:e.customerName,customerEmail:e.customerEmail};i&&(v.productId=i),s&&(v.productSlug=s),e.externalCustomerId&&(v.externalCustomerId=e.externalCustomerId);let B=await fetch(`${a}/v1/checkouts`,{method:"POST",headers:n,body:JSON.stringify(v)});if(!B.ok){let m=await B.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",m);let O=m.details||m.error||"Failed to create checkout";throw new Error(O)}let he=await B.json(),u=b(he);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),l==="redirect"){let m=`https://checkout.recur.tw/${u.checkout.id}`;console.log("[Recur SDK] Redirecting to hosted checkout:",m),window.location.href=m;return}if(console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let q=!0;if(await me(q),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let h=document.createElement("recur-payment-form");if(h.setAttribute("container-id",d.id||"recur-payment-container"),e.customerName&&h.setAttribute("customer-name",e.customerName),e.customerEmail&&h.setAttribute("customer-email",e.customerEmail),u.plan?.name&&h.setAttribute("plan-name",u.plan.name),u.checkout?.amount&&h.setAttribute("amount",u.checkout.amount.toString()),u.plan?.billingPeriod&&h.setAttribute("billing-period",u.plan.billingPeriod),h.setAttribute("custom-styles",`
1529
+ `.replace(/\s+/g," ").trim(),this.iframe.allow="payment *",this.iframe.setAttribute("title","Secure payment input frame"),this.iframe.setAttribute("role","presentation"),this.iframe.setAttribute("scrolling","no"),this.iframe.setAttribute("frameBorder","0"),this.container.innerHTML="",this.container.appendChild(this.iframe),new Promise((r,i)=>{let s=setTimeout(()=>{i(new Error("Elements initialization timeout"))},3e4),a=()=>{clearTimeout(s),this.off("ready",a),r()},n=l=>{clearTimeout(s),this.off("error",n),i(new Error(l.message||"Elements initialization failed"))};this.on("ready",a),this.on("error",n)})}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}off(e,t){let r=this.eventHandlers.get(e);r&&r.delete(t)}emit(e,t){let r=this.eventHandlers.get(e);r&&r.forEach(i=>i(t))}handleMessage(e){if(!this.isValidOrigin(e.origin))return;let{type:t,data:r}=e.data||{};switch(t){case"RECUR_ELEMENTS_READY":this.sessionId=r.sessionId,this.timestamp=r.timestamp,this.creditToken=r.creditToken,this.sdkToken=r.sdkToken,this.emit("ready",r);break;case"RECUR_CARD_VALID":this.emit("change",{valid:r.valid});break;case"RECUR_CARD_TOKENIZED":this.cardToken=r.cardToken,this.cardTimestamp=r.timestamp,this.emit("tokenized",r);break;case"RECUR_PAYMENT_ERROR":this.emit("error",r);break;case"RECUR_RESIZE":this.iframe&&r?.height&&(this.iframe.style.height=`${r.height}px`);break}}isValidOrigin(e){try{let t=new URL(this.embedUrl).origin;return e===t}catch{return!1}}async tokenize(){if(!this.iframe||!this.iframe.contentWindow)throw new Error("Elements not mounted");let e=new URL(this.embedUrl).origin;return this.iframe.contentWindow.postMessage({type:"RECUR_TOKENIZE"},e),new Promise((t,r)=>{let i=setTimeout(()=>{r(new Error("Tokenization timeout"))},6e4),s=n=>{clearTimeout(i),this.off("tokenized",s),t(n)},a=n=>{clearTimeout(i),this.off("error",a),r(new Error(n.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,productId:e.productId,email:e.email,name:e.name,phone:e.phone,externalCustomerId:e.externalCustomerId,metadata:e.metadata,successUrl:e.successUrl,cancelUrl:e.cancelUrl})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.sdkToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function j(o){return new w(o)}var Te="https://vendor.payuni.com.tw/sdk/uni-payment.js",Ie="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",ue=!1,N=!1,S=null;async function me(o=!1){return ue&&window.UniPayment?Promise.resolve():(N&&S||(N=!0,S=new Promise((e,t)=>{let r=document.createElement("script");r.src=o?Ie:Te,r.async=!0,r.onload=()=>{ue=!0,N=!1,e()},r.onerror=()=>{N=!1,S=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),S)}var C=class{constructor(e){c(this,"core");c(this,"currentModal",null);c(this,"currentIframe",null);c(this,"currentModalOverlay",null);this.core=new H(e)}async fetchProducts(e){return await this.core.fetchProducts(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new $(t,e).render()}async redirectToCheckout(e){let t=await this.createCheckoutSession(e);window.location.href=t.url}async createCheckoutSession(e){let t=this.getBaseUrl();if(!e.productId&&!e.productSlug)throw new Error("Either productId or productSlug is required");let r={};e.productId&&(r.productId=e.productId),e.productSlug&&(r.productSlug=e.productSlug),e.customerEmail&&(r.customerEmail=e.customerEmail),e.customerName&&(r.customerName=e.customerName),e.externalCustomerId&&(r.externalCustomerId=e.externalCustomerId),e.successUrl&&(r.successUrl=e.successUrl),e.cancelUrl&&(r.cancelUrl=e.cancelUrl);let i=this.core.getConfig(),s=await fetch(`${t}/v1/checkouts`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":i.publishableKey},body:JSON.stringify(r)});if(!s.ok){let l=await s.json().catch(()=>({}));throw new Error(l.error?.message||l.error||"Failed to create checkout session")}let a=await s.json(),n=g(a);return{id:n.checkout.id,url:n.url,expiresAt:n.checkout.expiresAt}}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.customerEmail)throw new Error("customerEmail is required");let a=this.getBaseUrl();console.log("[Recur SDK] Base URL:",a);let n={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},l=e.mode||"modal",d=null;if(l==="modal"){let m=this.createModalWithSkeleton(e.onClose);r=m.overlay,d=m.container}else if(l==="iframe"){if(d=this.getEmbeddedContainer(e.container),!d)throw new Error("Container is required for iframe mode");d.innerHTML="";let m=document.createElement("recur-payment-form-skeleton");d.appendChild(m)}console.log("[Recur SDK] Step 1: Creating checkout session...");let v={customerName:e.customerName,customerEmail:e.customerEmail};i&&(v.productId=i),s&&(v.productSlug=s),e.externalCustomerId&&(v.externalCustomerId=e.externalCustomerId);let B=await fetch(`${a}/v1/checkouts`,{method:"POST",headers:n,body:JSON.stringify(v)});if(!B.ok){let m=await B.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",m);let O=m.details||m.error||"Failed to create checkout";throw new Error(O)}let he=await B.json(),u=g(he);if(console.log("[Recur SDK] Checkout created successfully:",u),e.onSuccess?.(u),l==="redirect"){let m=`https://checkout.recur.tw/${u.checkout.id}`;console.log("[Recur SDK] Redirecting to hosted checkout:",m),window.location.href=m;return}if(console.log("[Recur SDK] Step 2: Extracting SDK token..."),!u.sdkToken)throw new Error("SDK token missing from checkout response");console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");let q=!0;if(await me(q),console.log("[Recur SDK] PAYUNi SDK loaded successfully"),!window.UniPayment)throw new Error("PAYUNi SDK failed to load");if(console.log("[Recur SDK] Step 4: Rendering payment form..."),!d)throw new Error("Payment container not available");d.innerHTML="";let h=document.createElement("recur-payment-form");if(h.setAttribute("container-id",d.id||"recur-payment-container"),e.customerName&&h.setAttribute("customer-name",e.customerName),e.customerEmail&&h.setAttribute("customer-email",e.customerEmail),u.plan?.name&&h.setAttribute("plan-name",u.plan.name),u.checkout?.amount&&h.setAttribute("amount",u.checkout.amount.toString()),u.plan?.billingPeriod&&h.setAttribute("billing-period",u.plan.billingPeriod),h.setAttribute("custom-styles",`
1530
1530
  .form-input-focus {
1531
1531
  border-color: var(--ring, hsl(215 16% 47%)) !important;
1532
1532
  outline: 0 !important;
@@ -1572,7 +1572,7 @@
1572
1572
  border-radius: 50%;
1573
1573
  z-index: 10;
1574
1574
  transition: background 0.2s;
1575
- `,i.onmouseover=()=>{i.style.background="rgba(0, 0, 0, 0.1)"},i.onmouseout=()=>{i.style.background="rgba(0, 0, 0, 0.05)"},i.onclick=()=>{t.remove(),e?.()};let s=document.createElement("div");s.id="recur-modal-payment-container";let a=document.createElement("recur-payment-form-skeleton");return s.appendChild(a),r.appendChild(i),r.appendChild(s),t.appendChild(r),document.body.appendChild(t),this.currentModalOverlay=t,{overlay:t,container:s}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeModal(){this.currentModal&&(this.currentModal.close(),this.currentModal=null),this.currentModalOverlay&&(this.currentModalOverlay.remove(),this.currentModalOverlay=null)}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let s=await r.json().catch(()=>({}));throw new Error(s.error?.message||s.message||"Failed to create portal session")}let i=await r.json();return{id:i.id,url:i.url||i.portalUrl,expiresAt:i.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function pe(o){return new S(o)}var Te={init:pe,RecurCheckout:S,RecurElements:w,createElements:j};return xe(Ie);})();
1575
+ `,i.onmouseover=()=>{i.style.background="rgba(0, 0, 0, 0.1)"},i.onmouseout=()=>{i.style.background="rgba(0, 0, 0, 0.05)"},i.onclick=()=>{t.remove(),e?.()};let s=document.createElement("div");s.id="recur-modal-payment-container";let a=document.createElement("recur-payment-form-skeleton");return s.appendChild(a),r.appendChild(i),r.appendChild(s),t.appendChild(r),document.body.appendChild(t),this.currentModalOverlay=t,{overlay:t,container:s}}getEmbeddedContainer(e){return e?typeof e=="string"?document.getElementById(e)||document.querySelector(e):e:null}closeModal(){this.currentModal&&(this.currentModal.close(),this.currentModal=null),this.currentModalOverlay&&(this.currentModalOverlay.remove(),this.currentModalOverlay=null)}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}async createPortalSession(e,t){let r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({customerId:t.customerId,returnUrl:t.returnUrl})});if(!r.ok){let s=await r.json().catch(()=>({}));throw new Error(s.error?.message||s.message||"Failed to create portal session")}let i=await r.json();return{id:i.id,url:i.url||i.portalUrl,expiresAt:i.expiresAt}}async redirectToPortal(e,t){let r=await this.createPortalSession(e,t);window.location.href=r.url}};function pe(o){return new C(o)}var Re={init:pe,RecurCheckout:C,RecurElements:w,createElements:j};return xe(Pe);})();
1576
1576
  if (typeof window !== "undefined") {
1577
1577
  window.RecurCheckout = RecurCheckout.default;
1578
1578
  window.RecurElements = RecurCheckout.RecurElements;
package/dist/server.cjs CHANGED
@@ -19,6 +19,8 @@ var RecurAPIError = class extends Error {
19
19
  };
20
20
 
21
21
  // src/server/resources/portal.ts
22
+ var SDK_VERSION = "0.8.1";
23
+ var SDK_TYPE = "server";
22
24
  var PortalSessions = class {
23
25
  constructor(config) {
24
26
  __publicField(this, "config");
@@ -75,7 +77,10 @@ var PortalSessions = class {
75
77
  method: "POST",
76
78
  headers: {
77
79
  "Authorization": `Bearer ${this.config.secretKey}`,
78
- "Content-Type": "application/json"
80
+ "Content-Type": "application/json",
81
+ "X-Recur-SDK-Type": SDK_TYPE,
82
+ "X-Recur-SDK-Version": SDK_VERSION,
83
+ "X-Recur-Source": "server"
79
84
  },
80
85
  body: JSON.stringify({
81
86
  customerId: params.customer,
package/dist/server.js CHANGED
@@ -17,6 +17,8 @@ var RecurAPIError = class extends Error {
17
17
  };
18
18
 
19
19
  // src/server/resources/portal.ts
20
+ var SDK_VERSION = "0.8.1";
21
+ var SDK_TYPE = "server";
20
22
  var PortalSessions = class {
21
23
  constructor(config) {
22
24
  __publicField(this, "config");
@@ -73,7 +75,10 @@ var PortalSessions = class {
73
75
  method: "POST",
74
76
  headers: {
75
77
  "Authorization": `Bearer ${this.config.secretKey}`,
76
- "Content-Type": "application/json"
78
+ "Content-Type": "application/json",
79
+ "X-Recur-SDK-Type": SDK_TYPE,
80
+ "X-Recur-SDK-Version": SDK_VERSION,
81
+ "X-Recur-Source": "server"
77
82
  },
78
83
  body: JSON.stringify({
79
84
  customerId: params.customer,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-tw",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
5
5
  "type": "module",
6
6
  "private": false,
@@ -58,6 +58,7 @@
58
58
  "files": [
59
59
  "dist",
60
60
  "README.md",
61
+ "AGENTS.md",
61
62
  "LICENSE"
62
63
  ],
63
64
  "sideEffects": [