recur-tw 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/dist/index.cjs +2 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +2 -1
- package/dist/recur.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -403,6 +403,9 @@ interface CheckoutOptions {
|
|
|
403
403
|
customerName?: string;
|
|
404
404
|
customerPhone?: string;
|
|
405
405
|
|
|
406
|
+
// External customer ID - link to your existing users
|
|
407
|
+
externalCustomerId?: string;
|
|
408
|
+
|
|
406
409
|
// Checkout mode
|
|
407
410
|
mode?: 'embedded' | 'redirect'; // Default: 'embedded' if containerElementId is set
|
|
408
411
|
|
|
@@ -418,6 +421,68 @@ interface CheckoutOptions {
|
|
|
418
421
|
|
|
419
422
|
---
|
|
420
423
|
|
|
424
|
+
### Customer Identification
|
|
425
|
+
|
|
426
|
+
The SDK supports multiple ways to identify customers across your system and Recur.
|
|
427
|
+
|
|
428
|
+
#### Using External Customer ID
|
|
429
|
+
|
|
430
|
+
The `externalCustomerId` parameter allows you to link Recur subscriptions to your existing user database:
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
// React
|
|
434
|
+
await checkout({
|
|
435
|
+
planId: 'plan_xxx',
|
|
436
|
+
customerEmail: 'user@example.com',
|
|
437
|
+
customerName: 'John Doe',
|
|
438
|
+
externalCustomerId: 'user_12345', // Your system's user ID
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Vanilla JS
|
|
442
|
+
await recur.checkout({
|
|
443
|
+
planId: 'plan_xxx',
|
|
444
|
+
customerEmail: 'user@example.com',
|
|
445
|
+
externalCustomerId: 'cus_abc456',
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Hosted Checkout
|
|
449
|
+
await recur.redirectToCheckout({
|
|
450
|
+
productId: 'prod_xxx',
|
|
451
|
+
successUrl: '/success',
|
|
452
|
+
cancelUrl: '/cancel',
|
|
453
|
+
customerEmail: 'user@example.com',
|
|
454
|
+
externalCustomerId: 'user_12345',
|
|
455
|
+
});
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
#### Customer Resolution Priority
|
|
459
|
+
|
|
460
|
+
When processing a checkout, the SDK uses the following priority to identify customers:
|
|
461
|
+
|
|
462
|
+
1. **externalCustomerId** - If provided, looks up customer by external ID first
|
|
463
|
+
2. **customerEmail** - Falls back to email-based lookup
|
|
464
|
+
3. **Create new** - Creates a new customer if no match found
|
|
465
|
+
|
|
466
|
+
If an `externalCustomerId` is provided but the customer already exists by email, the external ID will be bound to that existing customer.
|
|
467
|
+
|
|
468
|
+
#### Retrieving Customer by External ID
|
|
469
|
+
|
|
470
|
+
Use the API to retrieve customers by their external ID:
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
GET /api/v1/subscribers/external/{externalCustomerId}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
This allows you to query subscription status and details using your own user identifiers.
|
|
477
|
+
|
|
478
|
+
#### Best Practices
|
|
479
|
+
|
|
480
|
+
- **Use consistent IDs**: Use your database primary key or UUID as the external ID
|
|
481
|
+
- **Set early**: Include `externalCustomerId` in the initial checkout request
|
|
482
|
+
- **Combine with email**: Always provide both email and external ID for reliability
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
421
486
|
### Custom Styling
|
|
422
487
|
|
|
423
488
|
The SDK uses Web Components with customizable styles. You can override PAYUNi input styles to match your design system.
|
package/dist/index.cjs
CHANGED
|
@@ -2480,7 +2480,8 @@ function RecurProvider({ children, config: initialConfig = {} }) {
|
|
|
2480
2480
|
productId: options.planId,
|
|
2481
2481
|
customerName: options.customerName,
|
|
2482
2482
|
customerEmail: options.customerEmail,
|
|
2483
|
-
customerPhone: options.customerPhone
|
|
2483
|
+
customerPhone: options.customerPhone,
|
|
2484
|
+
externalCustomerId: options.externalCustomerId
|
|
2484
2485
|
})
|
|
2485
2486
|
});
|
|
2486
2487
|
if (!checkoutResponse.ok) {
|
package/dist/index.d.cts
CHANGED
|
@@ -214,6 +214,13 @@ interface CheckoutOptions {
|
|
|
214
214
|
customerName?: string;
|
|
215
215
|
customerEmail?: string;
|
|
216
216
|
customerPhone?: string;
|
|
217
|
+
/**
|
|
218
|
+
* External customer ID from your system
|
|
219
|
+
* Use this to link Recur subscriptions to your existing users
|
|
220
|
+
*
|
|
221
|
+
* @example 'user_123', 'cus_abc456'
|
|
222
|
+
*/
|
|
223
|
+
externalCustomerId?: string;
|
|
217
224
|
/**
|
|
218
225
|
* Override organization ID
|
|
219
226
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -214,6 +214,13 @@ interface CheckoutOptions {
|
|
|
214
214
|
customerName?: string;
|
|
215
215
|
customerEmail?: string;
|
|
216
216
|
customerPhone?: string;
|
|
217
|
+
/**
|
|
218
|
+
* External customer ID from your system
|
|
219
|
+
* Use this to link Recur subscriptions to your existing users
|
|
220
|
+
*
|
|
221
|
+
* @example 'user_123', 'cus_abc456'
|
|
222
|
+
*/
|
|
223
|
+
externalCustomerId?: string;
|
|
217
224
|
/**
|
|
218
225
|
* Override organization ID
|
|
219
226
|
*/
|
package/dist/index.js
CHANGED
|
@@ -2474,7 +2474,8 @@ function RecurProvider({ children, config: initialConfig = {} }) {
|
|
|
2474
2474
|
productId: options.planId,
|
|
2475
2475
|
customerName: options.customerName,
|
|
2476
2476
|
customerEmail: options.customerEmail,
|
|
2477
|
-
customerPhone: options.customerPhone
|
|
2477
|
+
customerPhone: options.customerPhone,
|
|
2478
|
+
externalCustomerId: options.externalCustomerId
|
|
2478
2479
|
})
|
|
2479
2480
|
});
|
|
2480
2481
|
if (!checkoutResponse.ok) {
|
package/dist/recur.umd.js
CHANGED
|
@@ -1416,7 +1416,7 @@
|
|
|
1416
1416
|
display: block;
|
|
1417
1417
|
user-select: none;
|
|
1418
1418
|
transition: height 0.35s ease, opacity 0.4s ease 0.1s;
|
|
1419
|
-
`.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,phone:e.phone,metadata:e.metadata})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function $(c){return new v(c)}var fe="https://vendor.payuni.com.tw/sdk/uni-payment.js",be="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",te=!1,D=!1,x=null;async function re(c=!1){return te&&window.UniPayment?Promise.resolve():(D&&x||(D=!0,x=new Promise((e,t)=>{let r=document.createElement("script");r.src=c?be:fe,r.async=!0,r.onload=()=>{te=!0,D=!1,e()},r.onerror=()=>{D=!1,x=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),x)}var w=class{constructor(e){a(this,"core");a(this,"currentModal",null);a(this,"currentIframe",null);a(this,"currentModalOverlay",null);this.core=new z(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new _(t,e).render()}async redirectToCheckout(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let l=window.location.hostname;if(l==="localhost"||l.includes(".test")||l.includes(".local")||l==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r(),s={productId:e.productId,successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail);let n=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(s)});if(!n.ok){let 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(),s={productId:e.productId,successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail);let n=await fetch(`${i}/v1/checkout/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},body:JSON.stringify(s)});if(!n.ok){let o=await n.json().catch(()=>({}));throw new Error(o.error?.message||"Failed to create checkout session")}return n.json()}async checkout(e){let t=this.core.getConfig(),r=null;try{if(console.log("[Recur SDK] Starting checkout flow...",{planId:e.planId,mode:e.mode}),!e.planId)throw new Error("planId is required");if(!t.publishableKey)throw new Error("publishableKey is required");if(!e.customerEmail||!e.customerName)throw new Error("customerEmail and customerName are required");let i=this.getBaseUrl();console.log("[Recur SDK] Base URL:",i);let s={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},n=e.mode||"modal",o=null;if(n==="modal"){let u=this.createModalWithSkeleton(e.onClose);r=u.overlay,o=u.container}else if(n==="iframe"){if(o=this.getEmbeddedContainer(e.container),!o)throw new Error("Container is required for iframe mode");o.innerHTML="";let u=document.createElement("recur-payment-form-skeleton");o.appendChild(u)}console.log("[Recur SDK] Step 1: Creating checkout session...");let l=await fetch(`${i}/v1/checkouts`,{method:"POST",headers:s,body:JSON.stringify({productId:e.planId,customerName:e.customerName,customerEmail:e.customerEmail,customerPhone:e.customerPhone})});if(!l.ok){let u=await l.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",u);let A=u.details||u.error||"Failed to create checkout";throw new Error(A)}let d=await l.json();if(console.log("[Recur SDK] Checkout created successfully:",d),e.onSuccess?.(d),n==="redirect"){let u=`https://checkout.recur.tw/${d.checkout.id}`;console.log("[Recur SDK] Redirecting to hosted checkout:",u),window.location.href=u;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 y=!0;if(await re(y),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..."),!o)throw new Error("Payment container not available");o.innerHTML="";let m=document.createElement("recur-payment-form");if(m.setAttribute("container-id",o.id||"recur-payment-container"),e.customerName&&m.setAttribute("customer-name",e.customerName),e.customerEmail&&m.setAttribute("customer-email",e.customerEmail),d.plan?.name&&m.setAttribute("plan-name",d.plan.name),d.checkout?.amount&&m.setAttribute("amount",d.checkout.amount.toString()),d.plan?.billingPeriod&&m.setAttribute("billing-period",d.plan.billingPeriod),m.setAttribute("custom-styles",`
|
|
1419
|
+
`.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,phone:e.phone,metadata:e.metadata})}),r=await t.json();return t.ok?r:{status:"failed",message:r.error||r.message||"Payment failed",canRetry:r.canRetry??!0}}getDefaultBaseUrl(){if(typeof window>"u")return"https://app.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3000`:"https://app.recur.tw"}getDefaultEmbedUrl(){if(typeof window>"u")return"https://embed.recur.tw";let e=window.location.hostname;return e==="localhost"||e.includes(".test")||e.includes(".local")||e==="127.0.0.1"?`${window.location.protocol}//${e}:3002`:"https://embed.recur.tw"}destroy(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.container=null,this.sessionId=null,this.timestamp=null,this.creditToken=null,this.cardToken=null,this.cardTimestamp=null,this.eventHandlers.clear(),window.removeEventListener("message",this.handleMessage.bind(this))}};function $(c){return new v(c)}var fe="https://vendor.payuni.com.tw/sdk/uni-payment.js",be="https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",te=!1,D=!1,x=null;async function re(c=!1){return te&&window.UniPayment?Promise.resolve():(D&&x||(D=!0,x=new Promise((e,t)=>{let r=document.createElement("script");r.src=c?be:fe,r.async=!0,r.onload=()=>{te=!0,D=!1,e()},r.onerror=()=>{D=!1,x=null,t(new Error("Failed to load PAYUNi SDK"))},document.head.appendChild(r)})),x)}var w=class{constructor(e){a(this,"core");a(this,"currentModal",null);a(this,"currentIframe",null);a(this,"currentModalOverlay",null);this.core=new z(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new _(t,e).render()}async redirectToCheckout(e){let t=this.core.getConfig(),r=()=>{if(typeof window<"u"){let l=window.location.hostname;if(l==="localhost"||l.includes(".test")||l.includes(".local")||l==="127.0.0.1")return`${window.location.protocol}//${window.location.host}/api`}return"https://api.recur.tw"},i=t.baseUrl||r(),s={productId:e.productId,successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail),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(),s={productId:e.productId,successUrl:e.successUrl,cancelUrl:e.cancelUrl};e.mode&&(s.mode=e.mode),e.customerEmail&&(s.customerEmail=e.customerEmail),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;try{if(console.log("[Recur SDK] Starting checkout flow...",{planId:e.planId,mode:e.mode}),!e.planId)throw new Error("planId is required");if(!t.publishableKey)throw new Error("publishableKey is required");if(!e.customerEmail||!e.customerName)throw new Error("customerEmail and customerName are required");let i=this.getBaseUrl();console.log("[Recur SDK] Base URL:",i);let s={"Content-Type":"application/json","X-Recur-Publishable-Key":t.publishableKey},n=e.mode||"modal",o=null;if(n==="modal"){let u=this.createModalWithSkeleton(e.onClose);r=u.overlay,o=u.container}else if(n==="iframe"){if(o=this.getEmbeddedContainer(e.container),!o)throw new Error("Container is required for iframe mode");o.innerHTML="";let u=document.createElement("recur-payment-form-skeleton");o.appendChild(u)}console.log("[Recur SDK] Step 1: Creating checkout session...");let l=await fetch(`${i}/v1/checkouts`,{method:"POST",headers:s,body:JSON.stringify({productId:e.planId,customerName:e.customerName,customerEmail:e.customerEmail,customerPhone:e.customerPhone,externalCustomerId:e.externalCustomerId})});if(!l.ok){let u=await l.json().catch(()=>({}));console.error("[Recur SDK] Failed to create checkout:",u);let A=u.details||u.error||"Failed to create checkout";throw new Error(A)}let d=await l.json();if(console.log("[Recur SDK] Checkout created successfully:",d),e.onSuccess?.(d),n==="redirect"){let u=`https://checkout.recur.tw/${d.checkout.id}`;console.log("[Recur SDK] Redirecting to hosted checkout:",u),window.location.href=u;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 y=!0;if(await re(y),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..."),!o)throw new Error("Payment container not available");o.innerHTML="";let m=document.createElement("recur-payment-form");if(m.setAttribute("container-id",o.id||"recur-payment-container"),e.customerName&&m.setAttribute("customer-name",e.customerName),e.customerEmail&&m.setAttribute("customer-email",e.customerEmail),d.plan?.name&&m.setAttribute("plan-name",d.plan.name),d.checkout?.amount&&m.setAttribute("amount",d.checkout.amount.toString()),d.plan?.billingPeriod&&m.setAttribute("billing-period",d.plan.billingPeriod),m.setAttribute("custom-styles",`
|
|
1420
1420
|
.form-input-focus {
|
|
1421
1421
|
border-color: var(--ring, hsl(215 16% 47%)) !important;
|
|
1422
1422
|
outline: 0 !important;
|