@paynext/sdk 0.0.168 → 0.0.169
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 +3 -46
- package/dist/index.es.js +167 -65
- package/dist/index.umd.js +88 -1
- package/package.json +1 -1
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
|
|
104
|
+
interface PayNextConfig {
|
|
120
105
|
clientToken: string
|
|
121
106
|
apiVersion: string
|
|
122
|
-
environment: '
|
|
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
|
-
|
|
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
|
|
2
|
-
var
|
|
3
|
-
var s = (
|
|
4
|
-
const
|
|
1
|
+
var g = Object.defineProperty;
|
|
2
|
+
var w = (a, t, e) => t in a ? g(a, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[t] = e;
|
|
3
|
+
var s = (a, t, e) => w(a, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
const l = "https://cdn-sdk-dev.paynext.com/checkout.html", u = "https://cdn-sdk.paynext.com/checkout.html", x = {
|
|
5
5
|
develop: "https://cdn-sdk-dev.paynext.com",
|
|
6
6
|
production: "https://cdn-sdk.paynext.com"
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
function C(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 h {
|
|
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((
|
|
115
|
+
return new Promise((o, n) => {
|
|
26
116
|
if (!this.iframe || !this.iframe.contentWindow) {
|
|
27
|
-
|
|
117
|
+
n(new Error("Iframe not initialized"));
|
|
28
118
|
return;
|
|
29
119
|
}
|
|
30
|
-
const
|
|
31
|
-
this.pendingRequests.set(
|
|
32
|
-
this.pendingRequests.has(
|
|
33
|
-
}, 3e4), this.iframe.contentWindow.postMessage(
|
|
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:
|
|
46
|
-
this.pendingRequests.delete(e.requestId),
|
|
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
|
|
79
|
-
this.allowedOrigin =
|
|
80
|
-
const n = document.createElement("iframe"), i =
|
|
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 : x[o];
|
|
170
|
+
const n = document.createElement("iframe"), i = o === "develop" ? l : u, 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 = C(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,35 @@ 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((
|
|
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
|
|
109
|
-
if (!
|
|
198
|
+
const o = document.getElementById(t);
|
|
199
|
+
if (!o)
|
|
110
200
|
throw new Error(`Container element "${t}" not found`);
|
|
111
|
-
this.container =
|
|
112
|
-
|
|
113
|
-
|
|
201
|
+
this.container = o, this.config = e, this.iframe && await this.unmount();
|
|
202
|
+
const i = (e.environment?.toLowerCase()?.includes("develop") || e.environment?.toLowerCase()?.includes("staging") ? "develop" : "production") === "develop" ? l : u;
|
|
203
|
+
let r = !1;
|
|
204
|
+
try {
|
|
205
|
+
await fetch(i, {
|
|
206
|
+
method: "HEAD",
|
|
207
|
+
mode: "no-cors",
|
|
208
|
+
cache: "no-cache"
|
|
209
|
+
}), r = !1, console.log("[PayNext Iframe] CDN is available, using remote iframe");
|
|
210
|
+
} catch {
|
|
211
|
+
r = !0, console.warn("[PayNext Iframe] CDN not available, using inline fallback mode"), console.log("[PayNext Iframe] This is normal if CDN is not yet deployed or during local testing");
|
|
212
|
+
}
|
|
213
|
+
this.iframe = this.createIframe(e, r), window.addEventListener("message", this.handleMessage), o.innerHTML = "", o.appendChild(this.iframe), await new Promise((y, m) => {
|
|
214
|
+
const p = setTimeout(() => {
|
|
215
|
+
m(new Error("Iframe load timeout"));
|
|
114
216
|
}, 1e4);
|
|
115
217
|
this.iframe.onload = () => {
|
|
116
|
-
clearTimeout(
|
|
218
|
+
clearTimeout(p), y();
|
|
117
219
|
}, this.iframe.onerror = () => {
|
|
118
|
-
clearTimeout(
|
|
220
|
+
clearTimeout(p), m(new Error("Iframe failed to load"));
|
|
119
221
|
};
|
|
120
222
|
}), await this.waitForReady(), await this.sendMessage("paynext:mount", {
|
|
121
223
|
config: {
|
|
@@ -127,8 +229,8 @@ class l {
|
|
|
127
229
|
onCheckoutFail: void 0
|
|
128
230
|
}
|
|
129
231
|
}), console.log("[PayNext Iframe] Checkout mounted successfully");
|
|
130
|
-
} catch (
|
|
131
|
-
throw console.error("[PayNext Iframe] Mount failed:",
|
|
232
|
+
} catch (o) {
|
|
233
|
+
throw console.error("[PayNext Iframe] Mount failed:", o), await this.unmount(), o;
|
|
132
234
|
}
|
|
133
235
|
}
|
|
134
236
|
// unmount checkout
|
|
@@ -159,45 +261,45 @@ class l {
|
|
|
159
261
|
}
|
|
160
262
|
// preload iframe (optional optimization)
|
|
161
263
|
static async preload(t) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
264
|
+
const o = (t?.toLowerCase()?.includes("develop") || t?.toLowerCase()?.includes("staging") ? "develop" : "production") === "develop" ? l : u, n = document.createElement("link");
|
|
265
|
+
n.rel = "preconnect", n.href = new URL(o).origin, document.head.appendChild(n);
|
|
266
|
+
const i = document.createElement("link");
|
|
267
|
+
i.rel = "dns-prefetch", i.href = new URL(o).origin, document.head.appendChild(i);
|
|
166
268
|
}
|
|
167
269
|
}
|
|
168
|
-
const
|
|
169
|
-
preload:
|
|
170
|
-
},
|
|
171
|
-
let
|
|
172
|
-
async function
|
|
270
|
+
const E = {
|
|
271
|
+
preload: h.preload
|
|
272
|
+
}, k = "https://cdn-sdk-dev.paynext.com/index.cdn.js", P = "https://cdn-sdk.paynext.com/index.cdn.js";
|
|
273
|
+
let d = null, c = null;
|
|
274
|
+
async function f(a) {
|
|
275
|
+
if (c)
|
|
276
|
+
return c;
|
|
173
277
|
if (d)
|
|
174
278
|
return d;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const t = o?.toLowerCase()?.includes("develop") || o?.toLowerCase()?.includes("staging") ? "develop" : "production";
|
|
178
|
-
return r = new Promise((e, n) => {
|
|
279
|
+
const t = a?.toLowerCase()?.includes("develop") || a?.toLowerCase()?.includes("staging") ? "develop" : "production";
|
|
280
|
+
return d = new Promise((e, o) => {
|
|
179
281
|
if (typeof window > "u") {
|
|
180
|
-
|
|
282
|
+
o(new Error("PayNext SDK can only be loaded in browser environment"));
|
|
181
283
|
return;
|
|
182
284
|
}
|
|
183
285
|
if (window.PayNextSDK) {
|
|
184
|
-
console.log("[PayNext CDN] SDK already loaded from cache"),
|
|
286
|
+
console.log("[PayNext CDN] SDK already loaded from cache"), c = window.PayNextSDK, e(c);
|
|
185
287
|
return;
|
|
186
288
|
}
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
if (!
|
|
191
|
-
console.error("[PayNext CDN] PayNextSDK not found in window after load"),
|
|
289
|
+
const n = document.createElement("script");
|
|
290
|
+
n.src = t === "develop" ? k : P, n.crossOrigin = "*", n.async = !0, n.onload = () => {
|
|
291
|
+
const i = window.PayNextSDK;
|
|
292
|
+
if (!i) {
|
|
293
|
+
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
294
|
return;
|
|
193
295
|
}
|
|
194
|
-
|
|
195
|
-
},
|
|
196
|
-
console.error("[PayNext CDN] Failed to load script:",
|
|
197
|
-
}, document.head.appendChild(
|
|
198
|
-
}),
|
|
296
|
+
c = i, e(i);
|
|
297
|
+
}, n.onerror = (i) => {
|
|
298
|
+
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"));
|
|
299
|
+
}, document.head.appendChild(n);
|
|
300
|
+
}), d;
|
|
199
301
|
}
|
|
200
|
-
class
|
|
302
|
+
class I {
|
|
201
303
|
constructor() {
|
|
202
304
|
s(this, "cdnInstance", null);
|
|
203
305
|
s(this, "iframeInstance", null);
|
|
@@ -207,7 +309,7 @@ class C {
|
|
|
207
309
|
// initialize
|
|
208
310
|
async initialize(t) {
|
|
209
311
|
try {
|
|
210
|
-
if (this.initPromise = await
|
|
312
|
+
if (this.initPromise = await f(t), !this.initPromise.PayNextCheckout)
|
|
211
313
|
throw new Error("PayNextCheckout not found in CDN module");
|
|
212
314
|
this.cdnInstance = new this.initPromise.PayNextCheckout();
|
|
213
315
|
} catch (e) {
|
|
@@ -223,7 +325,7 @@ class C {
|
|
|
223
325
|
}
|
|
224
326
|
// mount with iframe mode support
|
|
225
327
|
async mount(t, e) {
|
|
226
|
-
return e.iframeMode === !0 ? (this.mode = "iframe", this.iframeInstance || (this.iframeInstance = new
|
|
328
|
+
return e.iframeMode === !0 ? (this.mode = "iframe", this.iframeInstance || (this.iframeInstance = new h()), this.iframeInstance.mount(t, e)) : (this.mode = "direct", await this.initialize(e.environment), this.waitForReady(), this.cdnInstance?.mount(t, e));
|
|
227
329
|
}
|
|
228
330
|
// unmount with mode detection
|
|
229
331
|
async unmount() {
|
|
@@ -241,17 +343,17 @@ class C {
|
|
|
241
343
|
}
|
|
242
344
|
// preload (optional optimization)
|
|
243
345
|
static async preload(t, e) {
|
|
244
|
-
e?.iframeMode ? await
|
|
346
|
+
e?.iframeMode ? await h.preload(t) : await f(t);
|
|
245
347
|
}
|
|
246
348
|
}
|
|
247
|
-
const
|
|
248
|
-
preload:
|
|
349
|
+
const R = {
|
|
350
|
+
preload: I.preload
|
|
249
351
|
};
|
|
250
|
-
var
|
|
352
|
+
var v = /* @__PURE__ */ ((a) => (a.PAYPAL = "PAYPAL", a.APPLE_PAY = "APPLEPAY", a.GOOGLE_PAY = "GPAY", a.CARD = "CARD", a.VENMO = "VENMO", a))(v || {});
|
|
251
353
|
export {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
354
|
+
I as PayNextCheckout,
|
|
355
|
+
h as PayNextCheckoutIframe,
|
|
356
|
+
R as PayNextSDK,
|
|
357
|
+
E as PayNextSDKIframe,
|
|
358
|
+
v as PaymentMethod
|
|
257
359
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1,88 @@
|
|
|
1
|
-
(function(
|
|
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 R=(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)=>R(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",x={develop:"https://cdn-sdk-dev.paynext.com",production:"https://cdn-sdk.paynext.com"};function P(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:x[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=P(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 a=(e.environment?.toLowerCase()?.includes("develop")||e.environment?.toLowerCase()?.includes("staging")?"develop":"production")==="develop"?s:c;let l=!1;try{await fetch(a,{method:"HEAD",mode:"no-cors",cache:"no-cache"}),l=!1,console.log("[PayNext Iframe] CDN is available, using remote iframe")}catch{l=!0,console.warn("[PayNext Iframe] CDN not available, using inline fallback mode"),console.log("[PayNext Iframe] This is normal if CDN is not yet deployed or during local testing")}this.iframe=this.createIframe(e,l),window.addEventListener("message",this.handleMessage),o.innerHTML="",o.appendChild(this.iframe),await new Promise((v,g)=>{const w=setTimeout(()=>{g(new Error("Iframe load timeout"))},1e4);this.iframe.onload=()=>{clearTimeout(w),v()},this.iframe.onerror=()=>{clearTimeout(w),g(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 C={preload:m.preload},k="https://cdn-sdk-dev.paynext.com/index.cdn.js",I="https://cdn-sdk.paynext.com/index.cdn.js";let u=null,h=null;async function p(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"?k:I,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 f{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 p(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 p(t)}}const N={preload:f.preload};var y=(r=>(r.PAYPAL="PAYPAL",r.APPLE_PAY="APPLEPAY",r.GOOGLE_PAY="GPAY",r.CARD="CARD",r.VENMO="VENMO",r))(y||{});i.PayNextCheckout=f,i.PayNextCheckoutIframe=m,i.PayNextSDK=N,i.PayNextSDKIframe=C,i.PaymentMethod=y,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
|