@paynext/sdk 0.0.168 → 0.0.170

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,21 +2,6 @@
2
2
 
3
3
  TypeScript SDK for integrating PayNext payment processing with full type safety and multiple payment methods support.
4
4
 
5
- ## 🛡️ NEW: PCI-Compliant Iframe Mode
6
-
7
- Enable iframe mode for enhanced PCI compliance by adding one parameter:
8
-
9
- ```typescript
10
- await checkout.mount('checkout-container', {
11
- clientToken: 'your-token',
12
- environment: 'production',
13
- apiVersion: 'v1',
14
- iframeMode: true, // 🛡️ Isolates payment data in secure iframe
15
- })
16
- ```
17
-
18
- **Benefits:** Reduced PCI scope, isolated processing, XSS protection. See [Iframe Quick Start](./IFRAME_QUICKSTART.md) for details.
19
-
20
5
  ## Installation
21
6
 
22
7
  ```bash
@@ -116,11 +101,10 @@ export const CheckoutComponent: FC<Readonly<IProps>> = (props) => {
116
101
  ## Configuration
117
102
 
118
103
  ```typescript
119
- interface PayNextConfigExtended extends PayNextConfig {
104
+ interface PayNextConfig {
120
105
  clientToken: string
121
106
  apiVersion: string
122
- environment: 'develop' | 'staging' | 'sandbox' | 'production'
123
- iframeMode?: boolean // 🛡️ Enable PCI-compliant iframe mode (default: false)
107
+ environment: 'sandbox' | 'production',
124
108
  variant?: 'default' | 'compact'
125
109
  locale?: Locale
126
110
  translate?: CheckoutTranslate
@@ -210,31 +194,4 @@ The SDK supports recent versions of all major browsers:
210
194
 
211
195
  ## Security
212
196
 
213
- ### PCI Compliance
214
-
215
- **Iframe Mode (Recommended)**: Enables PCI-compliant iframe isolation for reduced compliance scope.
216
-
217
- ```typescript
218
- await checkout.mount('checkout-container', {
219
- iframeMode: true, // Isolates payment data processing
220
- // ... other config
221
- })
222
- ```
223
-
224
- ### Content Security Policy
225
-
226
- For iframe mode, add to your HTML:
227
-
228
- ```html
229
- <meta http-equiv="Content-Security-Policy"
230
- content="frame-src https://cdn-sdk.paynext.com https://cdn-sdk-dev.paynext.com;">
231
- ```
232
-
233
- ### Security Features
234
-
235
- - PCI DSS Level 1 compliant
236
- - End-to-end encryption (TLS 1.3)
237
- - Tokenization of sensitive data
238
- - No sensitive payment data stored locally
239
- - Optional iframe isolation for reduced PCI scope
240
- - Sandbox iframe security attributes (when iframe mode enabled)
197
+ PCI DSS compliant with end-to-end encryption. No sensitive payment data is stored locally.
package/dist/index.es.js CHANGED
@@ -1,11 +1,101 @@
1
- var f = Object.defineProperty;
2
- var p = (o, t, e) => t in o ? f(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e;
3
- var s = (o, t, e) => p(o, typeof t != "symbol" ? t + "" : t, e);
4
- const h = "https://cdn-sdk-dev.paynext.com/checkout.html", u = "https://cdn-sdk.paynext.com/checkout.html", w = {
1
+ var w = Object.defineProperty;
2
+ var x = (a, t, e) => t in a ? w(a, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[t] = e;
3
+ var s = (a, t, e) => x(a, typeof t != "symbol" ? t + "" : t, e);
4
+ const m = "https://cdn-sdk-dev.paynext.com/checkout.html", p = "https://cdn-sdk.paynext.com/checkout.html", C = {
5
5
  develop: "https://cdn-sdk-dev.paynext.com",
6
6
  production: "https://cdn-sdk.paynext.com"
7
7
  };
8
- class l {
8
+ function k(a) {
9
+ return `<!DOCTYPE html>
10
+ <html lang="en">
11
+ <head>
12
+ <meta charset="UTF-8">
13
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
14
+ <title>PayNext Checkout</title>
15
+ <style>
16
+ * { margin: 0; padding: 0; box-sizing: border-box; }
17
+ html, body { width: 100%; height: 100%; overflow: hidden; }
18
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
19
+ #checkout-container { width: 100%; min-height: 100%; }
20
+ .loading { display: flex; align-items: center; justify-content: center; min-height: 400px; color: #666; font-size: 14px; }
21
+ .loading::after { content: '...'; animation: dots 1.5s steps(4, end) infinite; }
22
+ @keyframes dots { 0%, 20% { content: '.'; } 40% { content: '..'; } 60%, 100% { content: '...'; } }
23
+ </style>
24
+ </head>
25
+ <body>
26
+ <div id="checkout-container"><div class="loading">Loading checkout</div></div>
27
+ <script type="module">
28
+ const MessageType = {
29
+ MOUNT: 'paynext:mount', UNMOUNT: 'paynext:unmount', UPDATE_CONFIG: 'paynext:updateConfig',
30
+ READY: 'paynext:ready', LOADED: 'paynext:loaded', ATTEMPT: 'paynext:attempt',
31
+ COMPLETE: 'paynext:complete', FAIL: 'paynext:fail', ERROR: 'paynext:error', RESIZE: 'paynext:resize'
32
+ }
33
+ let checkout = null, parentOrigin = null, config = null
34
+
35
+ function sendToParent(type, payload, requestId) {
36
+ if (!parentOrigin) return
37
+ window.parent.postMessage({ type, payload, requestId }, parentOrigin)
38
+ }
39
+
40
+ window.addEventListener('message', async (event) => {
41
+ const data = event.data
42
+ if (!parentOrigin) parentOrigin = event.origin
43
+ if (event.origin !== parentOrigin || !data.type?.startsWith('paynext:')) return
44
+
45
+ try {
46
+ switch (data.type) {
47
+ case MessageType.MOUNT:
48
+ if (data.payload?.config) {
49
+ config = data.payload.config
50
+ const { PayNextCheckout } = await import('${a}')
51
+ checkout = new PayNextCheckout()
52
+ await checkout.mount('checkout-container', {
53
+ ...config,
54
+ onCheckoutLoaded: (result) => { sendToParent(MessageType.LOADED, result, data.requestId); notifyResize() },
55
+ onCheckoutAttempt: (result) => sendToParent(MessageType.ATTEMPT, result),
56
+ onCheckoutComplete: (result) => sendToParent(MessageType.COMPLETE, result),
57
+ onCheckoutFail: (error) => sendToParent(MessageType.FAIL, error)
58
+ })
59
+ sendToParent(MessageType.READY, { success: true }, data.requestId)
60
+ setupResizeObserver()
61
+ }
62
+ break
63
+ case MessageType.UNMOUNT:
64
+ if (checkout) { await checkout.unmount(); checkout = null }
65
+ sendToParent(MessageType.READY, { success: true }, data.requestId)
66
+ break
67
+ case MessageType.UPDATE_CONFIG:
68
+ if (checkout && data.payload?.config) {
69
+ await checkout.updateConfig(data.payload.config)
70
+ sendToParent(MessageType.READY, { success: true }, data.requestId)
71
+ }
72
+ break
73
+ }
74
+ } catch (error) {
75
+ sendToParent(MessageType.ERROR, { message: error.message, stack: error.stack }, data.requestId)
76
+ }
77
+ })
78
+
79
+ function setupResizeObserver() {
80
+ new ResizeObserver(entries => {
81
+ for (const entry of entries) sendToParent(MessageType.RESIZE, { height: entry.contentRect.height })
82
+ }).observe(document.body)
83
+ }
84
+
85
+ function notifyResize() { sendToParent(MessageType.RESIZE, { height: document.body.scrollHeight }) }
86
+
87
+ window.addEventListener('load', () => {
88
+ setTimeout(() => window.parent.postMessage({ type: MessageType.READY, payload: { success: true } }, '*'), 100)
89
+ })
90
+
91
+ window.addEventListener('error', (event) => {
92
+ sendToParent(MessageType.ERROR, { message: event.error?.message || 'Unknown error', stack: event.error?.stack })
93
+ })
94
+ <\/script>
95
+ </body>
96
+ </html>`;
97
+ }
98
+ class f {
9
99
  constructor() {
10
100
  s(this, "iframe", null);
11
101
  s(this, "container", null);
@@ -22,15 +112,15 @@ class l {
22
112
  }
23
113
  // send message to iframe
24
114
  sendMessage(t, e) {
25
- return new Promise((n, i) => {
115
+ return new Promise((o, n) => {
26
116
  if (!this.iframe || !this.iframe.contentWindow) {
27
- i(new Error("Iframe not initialized"));
117
+ n(new Error("Iframe not initialized"));
28
118
  return;
29
119
  }
30
- const a = this.generateRequestId(), c = { type: t, payload: e, requestId: a };
31
- this.pendingRequests.set(a, { resolve: n, reject: i }), setTimeout(() => {
32
- this.pendingRequests.has(a) && (this.pendingRequests.delete(a), i(new Error(`Request timeout: ${t}`)));
33
- }, 3e4), this.iframe.contentWindow.postMessage(c, this.allowedOrigin);
120
+ const i = this.generateRequestId(), r = { type: t, payload: e, requestId: i };
121
+ this.pendingRequests.set(i, { resolve: o, reject: n }), setTimeout(() => {
122
+ this.pendingRequests.has(i) && (this.pendingRequests.delete(i), n(new Error(`Request timeout: ${t}`)));
123
+ }, 3e4), this.iframe.contentWindow.postMessage(r, this.allowedOrigin);
34
124
  });
35
125
  }
36
126
  // handle messages from iframe
@@ -42,8 +132,8 @@ class l {
42
132
  const e = t.data;
43
133
  if (!(!e.type || !e.type.startsWith("paynext:"))) {
44
134
  if (e.requestId && this.pendingRequests.has(e.requestId)) {
45
- const { resolve: n } = this.pendingRequests.get(e.requestId);
46
- this.pendingRequests.delete(e.requestId), n(e.payload);
135
+ const { resolve: o } = this.pendingRequests.get(e.requestId);
136
+ this.pendingRequests.delete(e.requestId), o(e.payload);
47
137
  return;
48
138
  }
49
139
  switch (e.type) {
@@ -74,11 +164,11 @@ class l {
74
164
  }
75
165
  }
76
166
  // create and configure iframe
77
- createIframe(t) {
78
- const e = t.environment?.toLowerCase()?.includes("develop") || t.environment?.toLowerCase()?.includes("staging") ? "develop" : "production";
79
- this.allowedOrigin = w[e];
80
- const n = document.createElement("iframe"), i = e === "develop" ? h : u;
81
- return n.src = i, n.style.border = "none", n.style.width = "100%", n.style.minHeight = "400px", n.style.display = "block", n.allow = "payment *", n.sandbox.add(
167
+ createIframe(t, e = !1) {
168
+ const o = t.environment?.toLowerCase()?.includes("develop") || t.environment?.toLowerCase()?.includes("staging") ? "develop" : "production";
169
+ this.allowedOrigin = e ? window.location.origin : C[o];
170
+ const n = document.createElement("iframe"), i = o === "develop" ? m : p, r = o === "develop" ? "https://cdn-sdk-dev.paynext.com/index.cdn.js" : "https://cdn-sdk.paynext.com/index.cdn.js";
171
+ return e ? (console.log("[PayNext Iframe] Using inline iframe mode (embedded HTML)"), console.log("[PayNext Iframe] SDK will load from:", r), n.srcdoc = k(r)) : (console.log("[PayNext Iframe] Using CDN iframe mode"), console.log("[PayNext Iframe] Loading iframe from:", i), n.src = i), n.style.border = "none", n.style.width = "100%", n.style.minHeight = "400px", n.style.display = "block", n.allow = "payment *", n.sandbox.add(
82
172
  "allow-scripts",
83
173
  // required for SDK execution
84
174
  "allow-same-origin",
@@ -99,23 +189,37 @@ class l {
99
189
  for (; !this.isReady; ) {
100
190
  if (Date.now() - e > t)
101
191
  throw new Error("Iframe initialization timeout");
102
- await new Promise((n) => setTimeout(n, 100));
192
+ await new Promise((o) => setTimeout(o, 100));
103
193
  }
104
194
  }
105
195
  // mount checkout in iframe
106
196
  async mount(t, e) {
107
197
  try {
108
- const n = document.getElementById(t);
109
- if (!n)
198
+ const o = document.getElementById(t);
199
+ if (!o)
110
200
  throw new Error(`Container element "${t}" not found`);
111
- this.container = n, this.config = e, this.iframe && await this.unmount(), this.iframe = this.createIframe(e), window.addEventListener("message", this.handleMessage), n.innerHTML = "", n.appendChild(this.iframe), await new Promise((i, a) => {
112
- const c = setTimeout(() => {
113
- a(new Error("Iframe load timeout"));
201
+ this.container = o, this.config = e, this.iframe && await this.unmount();
202
+ const n = e.environment?.toLowerCase()?.includes("develop") || e.environment?.toLowerCase()?.includes("staging") ? "develop" : "production", i = n === "develop" ? m : p, r = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.startsWith("192.168.") || window.location.hostname.endsWith(".local");
203
+ let l = r;
204
+ if (!r && n === "develop")
205
+ try {
206
+ const u = new AbortController(), h = setTimeout(() => u.abort(), 2e3);
207
+ await fetch(i, {
208
+ method: "HEAD",
209
+ signal: u.signal,
210
+ cache: "no-cache"
211
+ }), clearTimeout(h), l = !1, console.log("[PayNext Iframe] CDN is available, using remote iframe");
212
+ } catch {
213
+ l = !0, console.warn("[PayNext Iframe] CDN not available, using inline fallback mode");
214
+ }
215
+ l && (console.log("[PayNext Iframe] Using inline fallback mode"), console.log("[PayNext Iframe] Reason:", r ? "localhost detected" : "CDN not available")), this.iframe = this.createIframe(e, l), window.addEventListener("message", this.handleMessage), o.innerHTML = "", o.appendChild(this.iframe), await new Promise((u, h) => {
216
+ const y = setTimeout(() => {
217
+ h(new Error("Iframe load timeout"));
114
218
  }, 1e4);
115
219
  this.iframe.onload = () => {
116
- clearTimeout(c), i();
220
+ clearTimeout(y), u();
117
221
  }, this.iframe.onerror = () => {
118
- clearTimeout(c), a(new Error("Iframe failed to load"));
222
+ clearTimeout(y), h(new Error("Iframe failed to load"));
119
223
  };
120
224
  }), await this.waitForReady(), await this.sendMessage("paynext:mount", {
121
225
  config: {
@@ -127,8 +231,8 @@ class l {
127
231
  onCheckoutFail: void 0
128
232
  }
129
233
  }), console.log("[PayNext Iframe] Checkout mounted successfully");
130
- } catch (n) {
131
- throw console.error("[PayNext Iframe] Mount failed:", n), await this.unmount(), n;
234
+ } catch (o) {
235
+ throw console.error("[PayNext Iframe] Mount failed:", o), await this.unmount(), o;
132
236
  }
133
237
  }
134
238
  // unmount checkout
@@ -159,45 +263,45 @@ class l {
159
263
  }
160
264
  // preload iframe (optional optimization)
161
265
  static async preload(t) {
162
- const n = (t?.toLowerCase()?.includes("develop") || t?.toLowerCase()?.includes("staging") ? "develop" : "production") === "develop" ? h : u, i = document.createElement("link");
163
- i.rel = "preconnect", i.href = new URL(n).origin, document.head.appendChild(i);
164
- const a = document.createElement("link");
165
- a.rel = "dns-prefetch", a.href = new URL(n).origin, document.head.appendChild(a);
266
+ const o = (t?.toLowerCase()?.includes("develop") || t?.toLowerCase()?.includes("staging") ? "develop" : "production") === "develop" ? m : p, n = document.createElement("link");
267
+ n.rel = "preconnect", n.href = new URL(o).origin, document.head.appendChild(n);
268
+ const i = document.createElement("link");
269
+ i.rel = "dns-prefetch", i.href = new URL(o).origin, document.head.appendChild(i);
166
270
  }
167
271
  }
168
- const P = {
169
- preload: l.preload
170
- }, y = "https://cdn-sdk-dev.paynext.com/index.cdn.js", g = "https://cdn-sdk.paynext.com/index.cdn.js";
171
- let r = null, d = null;
172
- async function m(o) {
272
+ const E = {
273
+ preload: f.preload
274
+ }, P = "https://cdn-sdk-dev.paynext.com/index.cdn.js", I = "https://cdn-sdk.paynext.com/index.cdn.js";
275
+ let d = null, c = null;
276
+ async function g(a) {
277
+ if (c)
278
+ return c;
173
279
  if (d)
174
280
  return d;
175
- if (r)
176
- return r;
177
- const t = o?.toLowerCase()?.includes("develop") || o?.toLowerCase()?.includes("staging") ? "develop" : "production";
178
- return r = new Promise((e, n) => {
281
+ const t = a?.toLowerCase()?.includes("develop") || a?.toLowerCase()?.includes("staging") ? "develop" : "production";
282
+ return d = new Promise((e, o) => {
179
283
  if (typeof window > "u") {
180
- n(new Error("PayNext SDK can only be loaded in browser environment"));
284
+ o(new Error("PayNext SDK can only be loaded in browser environment"));
181
285
  return;
182
286
  }
183
287
  if (window.PayNextSDK) {
184
- console.log("[PayNext CDN] SDK already loaded from cache"), d = window.PayNextSDK, e(d);
288
+ console.log("[PayNext CDN] SDK already loaded from cache"), c = window.PayNextSDK, e(c);
185
289
  return;
186
290
  }
187
- const i = document.createElement("script");
188
- i.src = t === "develop" ? y : g, i.crossOrigin = "*", i.async = !0, i.onload = () => {
189
- const a = window.PayNextSDK;
190
- if (!a) {
191
- console.error("[PayNext CDN] PayNextSDK not found in window after load"), r = null, document.head.removeChild(i), n(new Error("PayNextSDK not found in global scope after loading"));
291
+ const n = document.createElement("script");
292
+ n.src = t === "develop" ? P : I, n.crossOrigin = "*", n.async = !0, n.onload = () => {
293
+ const i = window.PayNextSDK;
294
+ if (!i) {
295
+ console.error("[PayNext CDN] PayNextSDK not found in window after load"), d = null, document.head.removeChild(n), o(new Error("PayNextSDK not found in global scope after loading"));
192
296
  return;
193
297
  }
194
- d = a, e(a);
195
- }, i.onerror = (a) => {
196
- console.error("[PayNext CDN] Failed to load script:", a), r = null, document.head.removeChild(i), n(new Error("Failed to load PayNext SDK script from CDN"));
197
- }, document.head.appendChild(i);
198
- }), r;
298
+ c = i, e(i);
299
+ }, n.onerror = (i) => {
300
+ console.error("[PayNext CDN] Failed to load script:", i), d = null, document.head.removeChild(n), o(new Error("Failed to load PayNext SDK script from CDN"));
301
+ }, document.head.appendChild(n);
302
+ }), d;
199
303
  }
200
- class C {
304
+ class v {
201
305
  constructor() {
202
306
  s(this, "cdnInstance", null);
203
307
  s(this, "iframeInstance", null);
@@ -207,7 +311,7 @@ class C {
207
311
  // initialize
208
312
  async initialize(t) {
209
313
  try {
210
- if (this.initPromise = await m(t), !this.initPromise.PayNextCheckout)
314
+ if (this.initPromise = await g(t), !this.initPromise.PayNextCheckout)
211
315
  throw new Error("PayNextCheckout not found in CDN module");
212
316
  this.cdnInstance = new this.initPromise.PayNextCheckout();
213
317
  } catch (e) {
@@ -223,7 +327,7 @@ class C {
223
327
  }
224
328
  // mount with iframe mode support
225
329
  async mount(t, e) {
226
- return e.iframeMode === !0 ? (this.mode = "iframe", this.iframeInstance || (this.iframeInstance = new l()), this.iframeInstance.mount(t, e)) : (this.mode = "direct", await this.initialize(e.environment), this.waitForReady(), this.cdnInstance?.mount(t, e));
330
+ return e.iframeMode === !0 ? (this.mode = "iframe", this.iframeInstance || (this.iframeInstance = new f()), this.iframeInstance.mount(t, e)) : (this.mode = "direct", await this.initialize(e.environment), this.waitForReady(), this.cdnInstance?.mount(t, e));
227
331
  }
228
332
  // unmount with mode detection
229
333
  async unmount() {
@@ -241,17 +345,17 @@ class C {
241
345
  }
242
346
  // preload (optional optimization)
243
347
  static async preload(t, e) {
244
- e?.iframeMode ? await l.preload(t) : await m(t);
348
+ e?.iframeMode ? await f.preload(t) : await g(t);
245
349
  }
246
350
  }
247
- const I = {
248
- preload: C.preload
351
+ const T = {
352
+ preload: v.preload
249
353
  };
250
- var x = /* @__PURE__ */ ((o) => (o.PAYPAL = "PAYPAL", o.APPLE_PAY = "APPLEPAY", o.GOOGLE_PAY = "GPAY", o.CARD = "CARD", o.VENMO = "VENMO", o))(x || {});
354
+ var N = /* @__PURE__ */ ((a) => (a.PAYPAL = "PAYPAL", a.APPLE_PAY = "APPLEPAY", a.GOOGLE_PAY = "GPAY", a.CARD = "CARD", a.VENMO = "VENMO", a))(N || {});
251
355
  export {
252
- C as PayNextCheckout,
253
- l as PayNextCheckoutIframe,
254
- I as PayNextSDK,
255
- P as PayNextSDKIframe,
256
- x as PaymentMethod
356
+ v as PayNextCheckout,
357
+ f as PayNextCheckoutIframe,
358
+ T as PayNextSDK,
359
+ E as PayNextSDKIframe,
360
+ N as PaymentMethod
257
361
  };
package/dist/index.umd.js CHANGED
@@ -1 +1,88 @@
1
- (function(a,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(a=typeof globalThis<"u"?globalThis:a||self,s(a["PayNext SDK"]={}))})(this,(function(a){"use strict";var k=Object.defineProperty;var I=(a,s,c)=>s in a?k(a,s,{enumerable:!0,configurable:!0,writable:!0,value:c}):a[s]=c;var r=(a,s,c)=>I(a,typeof s!="symbol"?s+"":s,c);const s="https://cdn-sdk-dev.paynext.com/checkout.html",c="https://cdn-sdk.paynext.com/checkout.html",w={develop:"https://cdn-sdk-dev.paynext.com",production:"https://cdn-sdk.paynext.com"};class u{constructor(){r(this,"iframe",null);r(this,"container",null);r(this,"config",null);r(this,"messageHandlers",new Map);r(this,"pendingRequests",new Map);r(this,"isReady",!1);r(this,"allowedOrigin","");this.handleMessage=this.handleMessage.bind(this)}generateRequestId(){return`${Date.now()}-${Math.random().toString(36).substr(2,9)}`}sendMessage(t,e){return new Promise((n,i)=>{if(!this.iframe||!this.iframe.contentWindow){i(new Error("Iframe not initialized"));return}const o=this.generateRequestId(),m={type:t,payload:e,requestId:o};this.pendingRequests.set(o,{resolve:n,reject:i}),setTimeout(()=>{this.pendingRequests.has(o)&&(this.pendingRequests.delete(o),i(new Error(`Request timeout: ${t}`)))},3e4),this.iframe.contentWindow.postMessage(m,this.allowedOrigin)})}handleMessage(t){if(t.origin!==this.allowedOrigin){console.warn("[PayNext Iframe] Message from unauthorized origin:",t.origin);return}const e=t.data;if(!(!e.type||!e.type.startsWith("paynext:"))){if(e.requestId&&this.pendingRequests.has(e.requestId)){const{resolve:n}=this.pendingRequests.get(e.requestId);this.pendingRequests.delete(e.requestId),n(e.payload);return}switch(e.type){case"paynext:ready":this.isReady=!0,console.log("[PayNext Iframe] SDK ready");break;case"paynext:loaded":this.config?.onCheckoutLoaded&&this.config.onCheckoutLoaded(e.payload);break;case"paynext:attempt":this.config?.onCheckoutAttempt&&this.config.onCheckoutAttempt(e.payload);break;case"paynext:complete":this.config?.onCheckoutComplete&&this.config.onCheckoutComplete(e.payload);break;case"paynext:fail":this.config?.onCheckoutFail&&this.config.onCheckoutFail(e.payload);break;case"paynext:error":console.error("[PayNext Iframe] Error:",e.payload);break;case"paynext:resize":this.iframe&&e.payload?.height&&(this.iframe.style.height=`${e.payload.height}px`);break;default:console.warn("[PayNext Iframe] Unknown message type:",e.type)}}}createIframe(t){const e=t.environment?.toLowerCase()?.includes("develop")||t.environment?.toLowerCase()?.includes("staging")?"develop":"production";this.allowedOrigin=w[e];const n=document.createElement("iframe"),i=e==="develop"?s:c;return n.src=i,n.style.border="none",n.style.width="100%",n.style.minHeight="400px",n.style.display="block",n.allow="payment *",n.sandbox.add("allow-scripts","allow-same-origin","allow-forms","allow-popups","allow-popups-to-escape-sandbox","allow-top-navigation-by-user-activation"),n.setAttribute("referrerpolicy","strict-origin-when-cross-origin"),n.setAttribute("importance","high"),n}async waitForReady(t=1e4){const e=Date.now();for(;!this.isReady;){if(Date.now()-e>t)throw new Error("Iframe initialization timeout");await new Promise(n=>setTimeout(n,100))}}async mount(t,e){try{const n=document.getElementById(t);if(!n)throw new Error(`Container element "${t}" not found`);this.container=n,this.config=e,this.iframe&&await this.unmount(),this.iframe=this.createIframe(e),window.addEventListener("message",this.handleMessage),n.innerHTML="",n.appendChild(this.iframe),await new Promise((i,o)=>{const m=setTimeout(()=>{o(new Error("Iframe load timeout"))},1e4);this.iframe.onload=()=>{clearTimeout(m),i()},this.iframe.onerror=()=>{clearTimeout(m),o(new Error("Iframe failed to load"))}}),await this.waitForReady(),await this.sendMessage("paynext:mount",{config:{...e,onCheckoutLoaded:void 0,onCheckoutAttempt:void 0,onCheckoutComplete:void 0,onCheckoutFail:void 0}}),console.log("[PayNext Iframe] Checkout mounted successfully")}catch(n){throw console.error("[PayNext Iframe] Mount failed:",n),await this.unmount(),n}}async unmount(){try{this.iframe&&(this.isReady&&await this.sendMessage("paynext:unmount").catch(()=>{}),this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),window.removeEventListener("message",this.handleMessage),this.container&&(this.container.innerHTML="",this.container=null),this.isReady=!1,this.config=null,this.pendingRequests.clear(),this.messageHandlers.clear(),console.log("[PayNext Iframe] Checkout unmounted")}catch(t){console.error("[PayNext Iframe] Unmount failed:",t)}}async updateConfig(t){if(!this.isReady)throw new Error("Iframe not ready");this.config={...this.config,...t},await this.sendMessage("paynext:updateConfig",{config:{...t,onCheckoutLoaded:void 0,onCheckoutAttempt:void 0,onCheckoutComplete:void 0,onCheckoutFail:void 0}})}static async preload(t){const n=(t?.toLowerCase()?.includes("develop")||t?.toLowerCase()?.includes("staging")?"develop":"production")==="develop"?s:c,i=document.createElement("link");i.rel="preconnect",i.href=new URL(n).origin,document.head.appendChild(i);const o=document.createElement("link");o.rel="dns-prefetch",o.href=new URL(n).origin,document.head.appendChild(o)}}const g={preload:u.preload},C="https://cdn-sdk-dev.paynext.com/index.cdn.js",P="https://cdn-sdk.paynext.com/index.cdn.js";let l=null,h=null;async function f(d){if(h)return h;if(l)return l;const t=d?.toLowerCase()?.includes("develop")||d?.toLowerCase()?.includes("staging")?"develop":"production";return l=new Promise((e,n)=>{if(typeof window>"u"){n(new Error("PayNext SDK can only be loaded in browser environment"));return}if(window.PayNextSDK){console.log("[PayNext CDN] SDK already loaded from cache"),h=window.PayNextSDK,e(h);return}const i=document.createElement("script");i.src=t==="develop"?C:P,i.crossOrigin="*",i.async=!0,i.onload=()=>{const o=window.PayNextSDK;if(!o){console.error("[PayNext CDN] PayNextSDK not found in window after load"),l=null,document.head.removeChild(i),n(new Error("PayNextSDK not found in global scope after loading"));return}h=o,e(o)},i.onerror=o=>{console.error("[PayNext CDN] Failed to load script:",o),l=null,document.head.removeChild(i),n(new Error("Failed to load PayNext SDK script from CDN"))},document.head.appendChild(i)}),l}class p{constructor(){r(this,"cdnInstance",null);r(this,"iframeInstance",null);r(this,"initPromise",null);r(this,"mode","direct")}async initialize(t){try{if(this.initPromise=await f(t),!this.initPromise.PayNextCheckout)throw new Error("PayNextCheckout not found in CDN module");this.cdnInstance=new this.initPromise.PayNextCheckout}catch(e){throw console.error("[PayNext CDN] Failed to initialize:",e),e}}waitForReady(){if(!this.initPromise)throw new Error("SDK initialization not started");if(!this.cdnInstance)throw new Error("SDK instance not created")}async mount(t,e){return e.iframeMode===!0?(this.mode="iframe",this.iframeInstance||(this.iframeInstance=new u),this.iframeInstance.mount(t,e)):(this.mode="direct",await this.initialize(e.environment),this.waitForReady(),this.cdnInstance?.mount(t,e))}async unmount(){if(this.mode==="iframe"&&this.iframeInstance)return this.iframeInstance.unmount();if(this.waitForReady(),this.cdnInstance?.unmount)return this.cdnInstance.unmount()}async updateConfig(t){if(this.mode==="iframe"&&this.iframeInstance)return this.iframeInstance.updateConfig(t);if(this.waitForReady(),this.cdnInstance?.updateConfig)return this.cdnInstance.updateConfig(t)}static async preload(t,e){e?.iframeMode?await u.preload(t):await f(t)}}const x={preload:p.preload};var y=(d=>(d.PAYPAL="PAYPAL",d.APPLE_PAY="APPLEPAY",d.GOOGLE_PAY="GPAY",d.CARD="CARD",d.VENMO="VENMO",d))(y||{});a.PayNextCheckout=p,a.PayNextCheckoutIframe=u,a.PayNextSDK=x,a.PayNextSDKIframe=g,a.PaymentMethod=y,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(i,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(i=typeof globalThis<"u"?globalThis:i||self,s(i["PayNext SDK"]={}))})(this,(function(i){"use strict";var E=Object.defineProperty;var T=(i,s,c)=>s in i?E(i,s,{enumerable:!0,configurable:!0,writable:!0,value:c}):i[s]=c;var d=(i,s,c)=>T(i,typeof s!="symbol"?s+"":s,c);const s="https://cdn-sdk-dev.paynext.com/checkout.html",c="https://cdn-sdk.paynext.com/checkout.html",C={develop:"https://cdn-sdk-dev.paynext.com",production:"https://cdn-sdk.paynext.com"};function k(r){return`<!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>PayNext Checkout</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ html, body { width: 100%; height: 100%; overflow: hidden; }
10
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
11
+ #checkout-container { width: 100%; min-height: 100%; }
12
+ .loading { display: flex; align-items: center; justify-content: center; min-height: 400px; color: #666; font-size: 14px; }
13
+ .loading::after { content: '...'; animation: dots 1.5s steps(4, end) infinite; }
14
+ @keyframes dots { 0%, 20% { content: '.'; } 40% { content: '..'; } 60%, 100% { content: '...'; } }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <div id="checkout-container"><div class="loading">Loading checkout</div></div>
19
+ <script type="module">
20
+ const MessageType = {
21
+ MOUNT: 'paynext:mount', UNMOUNT: 'paynext:unmount', UPDATE_CONFIG: 'paynext:updateConfig',
22
+ READY: 'paynext:ready', LOADED: 'paynext:loaded', ATTEMPT: 'paynext:attempt',
23
+ COMPLETE: 'paynext:complete', FAIL: 'paynext:fail', ERROR: 'paynext:error', RESIZE: 'paynext:resize'
24
+ }
25
+ let checkout = null, parentOrigin = null, config = null
26
+
27
+ function sendToParent(type, payload, requestId) {
28
+ if (!parentOrigin) return
29
+ window.parent.postMessage({ type, payload, requestId }, parentOrigin)
30
+ }
31
+
32
+ window.addEventListener('message', async (event) => {
33
+ const data = event.data
34
+ if (!parentOrigin) parentOrigin = event.origin
35
+ if (event.origin !== parentOrigin || !data.type?.startsWith('paynext:')) return
36
+
37
+ try {
38
+ switch (data.type) {
39
+ case MessageType.MOUNT:
40
+ if (data.payload?.config) {
41
+ config = data.payload.config
42
+ const { PayNextCheckout } = await import('${r}')
43
+ checkout = new PayNextCheckout()
44
+ await checkout.mount('checkout-container', {
45
+ ...config,
46
+ onCheckoutLoaded: (result) => { sendToParent(MessageType.LOADED, result, data.requestId); notifyResize() },
47
+ onCheckoutAttempt: (result) => sendToParent(MessageType.ATTEMPT, result),
48
+ onCheckoutComplete: (result) => sendToParent(MessageType.COMPLETE, result),
49
+ onCheckoutFail: (error) => sendToParent(MessageType.FAIL, error)
50
+ })
51
+ sendToParent(MessageType.READY, { success: true }, data.requestId)
52
+ setupResizeObserver()
53
+ }
54
+ break
55
+ case MessageType.UNMOUNT:
56
+ if (checkout) { await checkout.unmount(); checkout = null }
57
+ sendToParent(MessageType.READY, { success: true }, data.requestId)
58
+ break
59
+ case MessageType.UPDATE_CONFIG:
60
+ if (checkout && data.payload?.config) {
61
+ await checkout.updateConfig(data.payload.config)
62
+ sendToParent(MessageType.READY, { success: true }, data.requestId)
63
+ }
64
+ break
65
+ }
66
+ } catch (error) {
67
+ sendToParent(MessageType.ERROR, { message: error.message, stack: error.stack }, data.requestId)
68
+ }
69
+ })
70
+
71
+ function setupResizeObserver() {
72
+ new ResizeObserver(entries => {
73
+ for (const entry of entries) sendToParent(MessageType.RESIZE, { height: entry.contentRect.height })
74
+ }).observe(document.body)
75
+ }
76
+
77
+ function notifyResize() { sendToParent(MessageType.RESIZE, { height: document.body.scrollHeight }) }
78
+
79
+ window.addEventListener('load', () => {
80
+ setTimeout(() => window.parent.postMessage({ type: MessageType.READY, payload: { success: true } }, '*'), 100)
81
+ })
82
+
83
+ window.addEventListener('error', (event) => {
84
+ sendToParent(MessageType.ERROR, { message: event.error?.message || 'Unknown error', stack: event.error?.stack })
85
+ })
86
+ <\/script>
87
+ </body>
88
+ </html>`}class m{constructor(){d(this,"iframe",null);d(this,"container",null);d(this,"config",null);d(this,"messageHandlers",new Map);d(this,"pendingRequests",new Map);d(this,"isReady",!1);d(this,"allowedOrigin","");this.handleMessage=this.handleMessage.bind(this)}generateRequestId(){return`${Date.now()}-${Math.random().toString(36).substr(2,9)}`}sendMessage(t,e){return new Promise((o,n)=>{if(!this.iframe||!this.iframe.contentWindow){n(new Error("Iframe not initialized"));return}const a=this.generateRequestId(),l={type:t,payload:e,requestId:a};this.pendingRequests.set(a,{resolve:o,reject:n}),setTimeout(()=>{this.pendingRequests.has(a)&&(this.pendingRequests.delete(a),n(new Error(`Request timeout: ${t}`)))},3e4),this.iframe.contentWindow.postMessage(l,this.allowedOrigin)})}handleMessage(t){if(t.origin!==this.allowedOrigin){console.warn("[PayNext Iframe] Message from unauthorized origin:",t.origin);return}const e=t.data;if(!(!e.type||!e.type.startsWith("paynext:"))){if(e.requestId&&this.pendingRequests.has(e.requestId)){const{resolve:o}=this.pendingRequests.get(e.requestId);this.pendingRequests.delete(e.requestId),o(e.payload);return}switch(e.type){case"paynext:ready":this.isReady=!0,console.log("[PayNext Iframe] SDK ready");break;case"paynext:loaded":this.config?.onCheckoutLoaded&&this.config.onCheckoutLoaded(e.payload);break;case"paynext:attempt":this.config?.onCheckoutAttempt&&this.config.onCheckoutAttempt(e.payload);break;case"paynext:complete":this.config?.onCheckoutComplete&&this.config.onCheckoutComplete(e.payload);break;case"paynext:fail":this.config?.onCheckoutFail&&this.config.onCheckoutFail(e.payload);break;case"paynext:error":console.error("[PayNext Iframe] Error:",e.payload);break;case"paynext:resize":this.iframe&&e.payload?.height&&(this.iframe.style.height=`${e.payload.height}px`);break;default:console.warn("[PayNext Iframe] Unknown message type:",e.type)}}}createIframe(t,e=!1){const o=t.environment?.toLowerCase()?.includes("develop")||t.environment?.toLowerCase()?.includes("staging")?"develop":"production";this.allowedOrigin=e?window.location.origin:C[o];const n=document.createElement("iframe"),a=o==="develop"?s:c,l=o==="develop"?"https://cdn-sdk-dev.paynext.com/index.cdn.js":"https://cdn-sdk.paynext.com/index.cdn.js";return e?(console.log("[PayNext Iframe] Using inline iframe mode (embedded HTML)"),console.log("[PayNext Iframe] SDK will load from:",l),n.srcdoc=k(l)):(console.log("[PayNext Iframe] Using CDN iframe mode"),console.log("[PayNext Iframe] Loading iframe from:",a),n.src=a),n.style.border="none",n.style.width="100%",n.style.minHeight="400px",n.style.display="block",n.allow="payment *",n.sandbox.add("allow-scripts","allow-same-origin","allow-forms","allow-popups","allow-popups-to-escape-sandbox","allow-top-navigation-by-user-activation"),n.setAttribute("referrerpolicy","strict-origin-when-cross-origin"),n.setAttribute("importance","high"),n}async waitForReady(t=1e4){const e=Date.now();for(;!this.isReady;){if(Date.now()-e>t)throw new Error("Iframe initialization timeout");await new Promise(o=>setTimeout(o,100))}}async mount(t,e){try{const o=document.getElementById(t);if(!o)throw new Error(`Container element "${t}" not found`);this.container=o,this.config=e,this.iframe&&await this.unmount();const n=e.environment?.toLowerCase()?.includes("develop")||e.environment?.toLowerCase()?.includes("staging")?"develop":"production",a=n==="develop"?s:c,l=window.location.hostname==="localhost"||window.location.hostname==="127.0.0.1"||window.location.hostname.startsWith("192.168.")||window.location.hostname.endsWith(".local");let p=l;if(!l&&n==="develop")try{const f=new AbortController,y=setTimeout(()=>f.abort(),2e3);await fetch(a,{method:"HEAD",signal:f.signal,cache:"no-cache"}),clearTimeout(y),p=!1,console.log("[PayNext Iframe] CDN is available, using remote iframe")}catch{p=!0,console.warn("[PayNext Iframe] CDN not available, using inline fallback mode")}p&&(console.log("[PayNext Iframe] Using inline fallback mode"),console.log("[PayNext Iframe] Reason:",l?"localhost detected":"CDN not available")),this.iframe=this.createIframe(e,p),window.addEventListener("message",this.handleMessage),o.innerHTML="",o.appendChild(this.iframe),await new Promise((f,y)=>{const P=setTimeout(()=>{y(new Error("Iframe load timeout"))},1e4);this.iframe.onload=()=>{clearTimeout(P),f()},this.iframe.onerror=()=>{clearTimeout(P),y(new Error("Iframe failed to load"))}}),await this.waitForReady(),await this.sendMessage("paynext:mount",{config:{...e,onCheckoutLoaded:void 0,onCheckoutAttempt:void 0,onCheckoutComplete:void 0,onCheckoutFail:void 0}}),console.log("[PayNext Iframe] Checkout mounted successfully")}catch(o){throw console.error("[PayNext Iframe] Mount failed:",o),await this.unmount(),o}}async unmount(){try{this.iframe&&(this.isReady&&await this.sendMessage("paynext:unmount").catch(()=>{}),this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),window.removeEventListener("message",this.handleMessage),this.container&&(this.container.innerHTML="",this.container=null),this.isReady=!1,this.config=null,this.pendingRequests.clear(),this.messageHandlers.clear(),console.log("[PayNext Iframe] Checkout unmounted")}catch(t){console.error("[PayNext Iframe] Unmount failed:",t)}}async updateConfig(t){if(!this.isReady)throw new Error("Iframe not ready");this.config={...this.config,...t},await this.sendMessage("paynext:updateConfig",{config:{...t,onCheckoutLoaded:void 0,onCheckoutAttempt:void 0,onCheckoutComplete:void 0,onCheckoutFail:void 0}})}static async preload(t){const o=(t?.toLowerCase()?.includes("develop")||t?.toLowerCase()?.includes("staging")?"develop":"production")==="develop"?s:c,n=document.createElement("link");n.rel="preconnect",n.href=new URL(o).origin,document.head.appendChild(n);const a=document.createElement("link");a.rel="dns-prefetch",a.href=new URL(o).origin,document.head.appendChild(a)}}const I={preload:m.preload},N="https://cdn-sdk-dev.paynext.com/index.cdn.js",v="https://cdn-sdk.paynext.com/index.cdn.js";let u=null,h=null;async function g(r){if(h)return h;if(u)return u;const t=r?.toLowerCase()?.includes("develop")||r?.toLowerCase()?.includes("staging")?"develop":"production";return u=new Promise((e,o)=>{if(typeof window>"u"){o(new Error("PayNext SDK can only be loaded in browser environment"));return}if(window.PayNextSDK){console.log("[PayNext CDN] SDK already loaded from cache"),h=window.PayNextSDK,e(h);return}const n=document.createElement("script");n.src=t==="develop"?N:v,n.crossOrigin="*",n.async=!0,n.onload=()=>{const a=window.PayNextSDK;if(!a){console.error("[PayNext CDN] PayNextSDK not found in window after load"),u=null,document.head.removeChild(n),o(new Error("PayNextSDK not found in global scope after loading"));return}h=a,e(a)},n.onerror=a=>{console.error("[PayNext CDN] Failed to load script:",a),u=null,document.head.removeChild(n),o(new Error("Failed to load PayNext SDK script from CDN"))},document.head.appendChild(n)}),u}class w{constructor(){d(this,"cdnInstance",null);d(this,"iframeInstance",null);d(this,"initPromise",null);d(this,"mode","direct")}async initialize(t){try{if(this.initPromise=await g(t),!this.initPromise.PayNextCheckout)throw new Error("PayNextCheckout not found in CDN module");this.cdnInstance=new this.initPromise.PayNextCheckout}catch(e){throw console.error("[PayNext CDN] Failed to initialize:",e),e}}waitForReady(){if(!this.initPromise)throw new Error("SDK initialization not started");if(!this.cdnInstance)throw new Error("SDK instance not created")}async mount(t,e){return e.iframeMode===!0?(this.mode="iframe",this.iframeInstance||(this.iframeInstance=new m),this.iframeInstance.mount(t,e)):(this.mode="direct",await this.initialize(e.environment),this.waitForReady(),this.cdnInstance?.mount(t,e))}async unmount(){if(this.mode==="iframe"&&this.iframeInstance)return this.iframeInstance.unmount();if(this.waitForReady(),this.cdnInstance?.unmount)return this.cdnInstance.unmount()}async updateConfig(t){if(this.mode==="iframe"&&this.iframeInstance)return this.iframeInstance.updateConfig(t);if(this.waitForReady(),this.cdnInstance?.updateConfig)return this.cdnInstance.updateConfig(t)}static async preload(t,e){e?.iframeMode?await m.preload(t):await g(t)}}const R={preload:w.preload};var x=(r=>(r.PAYPAL="PAYPAL",r.APPLE_PAY="APPLEPAY",r.GOOGLE_PAY="GPAY",r.CARD="CARD",r.VENMO="VENMO",r))(x||{});i.PayNextCheckout=w,i.PayNextCheckoutIframe=m,i.PayNextSDK=R,i.PayNextSDKIframe=I,i.PaymentMethod=x,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paynext/sdk",
3
- "version": "0.0.168",
3
+ "version": "0.0.170",
4
4
  "description": "PayNext SDK - Payment processing with automatic CDN loading",
5
5
  "type": "module",
6
6
  "main": "dist/index.es.js",