cinetpay-seamless 0.1.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.
@@ -0,0 +1,73 @@
1
+ import type { PaymentResponse, PaymentError } from './types';
2
+ import { Logger } from './logger';
3
+ import { EventEmitter } from './emitter';
4
+ /** @internal Options du constructeur Checkout */
5
+ export interface CheckoutOptions {
6
+ onReady?: () => void;
7
+ onPaymentSuccess?: (data: PaymentResponse) => void;
8
+ onPaymentFailed?: (data: PaymentResponse) => void;
9
+ onPaymentPending?: (data: PaymentResponse) => void;
10
+ onClose?: (data: {
11
+ status: string;
12
+ }) => void;
13
+ onError?: (error: PaymentError) => void;
14
+ logger: Logger;
15
+ emitter: EventEmitter;
16
+ }
17
+ /**
18
+ * Gère le checkout CinetPay via une popup window + overlay.
19
+ *
20
+ * Flow :
21
+ * 1. Affiche un overlay sombre avec un message d'attente
22
+ * 2. Ouvre la page de checkout dans une popup (window.open)
23
+ * 3. Poll la popup pour détecter sa fermeture
24
+ * 4. Écoute les messages postMessage de la popup
25
+ * 5. Ferme l'overlay et dispatche les callbacks
26
+ *
27
+ * @internal Utilisé par {@link CinetPaySeamless}. Ne pas instancier directement.
28
+ */
29
+ export declare class Checkout {
30
+ private overlay;
31
+ private popup;
32
+ private pollTimer;
33
+ private messageHandler;
34
+ private lastStatus;
35
+ private onReadyCallback?;
36
+ private onPaymentSuccessCallback?;
37
+ private onPaymentFailedCallback?;
38
+ private onPaymentPendingCallback?;
39
+ private onCloseCallback?;
40
+ private onErrorCallback?;
41
+ private logger;
42
+ private emitter;
43
+ constructor(options: CheckoutOptions);
44
+ /**
45
+ * Ouvre la popup de checkout et affiche l'overlay d'attente.
46
+ *
47
+ * @param paymentUrl - URL complète de la page de checkout CinetPay
48
+ */
49
+ open(paymentUrl: string): void;
50
+ /**
51
+ * Ferme la popup et l'overlay.
52
+ */
53
+ close(): void;
54
+ /** Dispatche la réponse vers le bon callback selon le statut. */
55
+ private dispatchResponse;
56
+ private injectStyles;
57
+ private createOverlay;
58
+ /**
59
+ * Ouvre la popup centrée sur l'écran.
60
+ */
61
+ private openPopup;
62
+ /**
63
+ * Poll toutes les 500ms pour détecter si la popup a été fermée
64
+ * (par l'utilisateur ou après redirection).
65
+ */
66
+ private startPolling;
67
+ private stopPolling;
68
+ /** Origines autorisées pour les messages postMessage */
69
+ private static readonly ALLOWED_ORIGINS;
70
+ /** Écoute les messages postMessage de la popup CinetPay. */
71
+ private listenForMessages;
72
+ }
73
+ //# sourceMappingURL=checkout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../src/checkout.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAiB,MAAM,SAAS,CAAA;AAC3E,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IAClD,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACjD,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IAClD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAA;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,YAAY,CAAA;CACtB;AAKD;;;;;;;;;;;GAWG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,UAAU,CAAY;IAE9B,OAAO,CAAC,eAAe,CAAC,CAAY;IACpC,OAAO,CAAC,wBAAwB,CAAC,CAAiC;IAClE,OAAO,CAAC,uBAAuB,CAAC,CAAiC;IACjE,OAAO,CAAC,wBAAwB,CAAC,CAAiC;IAClE,OAAO,CAAC,eAAe,CAAC,CAAoC;IAC5D,OAAO,CAAC,eAAe,CAAC,CAA+B;IACvD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAc;gBAEjB,OAAO,EAAE,eAAe;IAWpC;;;;OAIG;IACH,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAe9B;;OAEG;IACH,KAAK,IAAI,IAAI;IA2Bb,iEAAiE;IACjE,OAAO,CAAC,gBAAgB;IAgCxB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,aAAa;IAqCrB;;OAEG;IACH,OAAO,CAAC,SAAS;IA6BjB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,WAAW;IAOnB,wDAAwD;IACxD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAOtC;IAED,4DAA4D;IAC5D,OAAO,CAAC,iBAAiB;CA8C1B"}
@@ -0,0 +1,401 @@
1
+ const m = `
2
+ .cp-seamless-overlay {
3
+ position: fixed;
4
+ inset: 0;
5
+ z-index: 999999;
6
+ background: rgba(0, 0, 0, 0.7);
7
+ backdrop-filter: blur(6px);
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ opacity: 0;
12
+ transition: opacity 0.3s ease;
13
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
14
+ }
15
+
16
+ .cp-seamless-overlay.cp-visible {
17
+ opacity: 1;
18
+ }
19
+
20
+ .cp-seamless-wrapper {
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ }
25
+
26
+ /* Waiting screen (pendant que la popup est ouverte) */
27
+ .cp-seamless-waiting {
28
+ display: flex;
29
+ flex-direction: column;
30
+ align-items: center;
31
+ gap: 20px;
32
+ text-align: center;
33
+ padding: 40px;
34
+ }
35
+
36
+ .cp-seamless-waiting-title {
37
+ color: #fff;
38
+ font-size: 22px;
39
+ font-weight: 600;
40
+ margin: 0;
41
+ }
42
+
43
+ .cp-seamless-waiting-msg {
44
+ color: rgba(255, 255, 255, 0.7);
45
+ font-size: 15px;
46
+ margin: 0;
47
+ max-width: 320px;
48
+ line-height: 1.5;
49
+ }
50
+
51
+ .cp-seamless-spinner {
52
+ width: 48px;
53
+ height: 48px;
54
+ border: 3px solid rgba(255, 255, 255, 0.2);
55
+ border-top-color: #e8530e;
56
+ border-radius: 50%;
57
+ animation: cp-spin 0.8s linear infinite;
58
+ }
59
+
60
+ @keyframes cp-spin {
61
+ to { transform: rotate(360deg); }
62
+ }
63
+
64
+ .cp-seamless-cancel-btn {
65
+ margin-top: 12px;
66
+ padding: 10px 28px;
67
+ background: rgba(255, 255, 255, 0.12);
68
+ color: rgba(255, 255, 255, 0.8);
69
+ border: 1px solid rgba(255, 255, 255, 0.2);
70
+ border-radius: 8px;
71
+ font-size: 14px;
72
+ cursor: pointer;
73
+ transition: all 0.2s;
74
+ }
75
+
76
+ .cp-seamless-cancel-btn:hover {
77
+ background: rgba(255, 255, 255, 0.2);
78
+ color: #fff;
79
+ }
80
+
81
+ `;
82
+ const l = class l {
83
+ constructor(e) {
84
+ this.overlay = null, this.popup = null, this.pollTimer = null, this.messageHandler = null, this.lastStatus = "UNKNOWN", this.logger = e.logger, this.emitter = e.emitter, this.onReadyCallback = e.onReady, this.onPaymentSuccessCallback = e.onPaymentSuccess, this.onPaymentFailedCallback = e.onPaymentFailed, this.onPaymentPendingCallback = e.onPaymentPending, this.onCloseCallback = e.onClose, this.onErrorCallback = e.onError;
85
+ }
86
+ /**
87
+ * Ouvre la popup de checkout et affiche l'overlay d'attente.
88
+ *
89
+ * @param paymentUrl - URL complète de la page de checkout CinetPay
90
+ */
91
+ open(e) {
92
+ this.logger.debug("Opening checkout popup", { paymentUrl: e }), this.injectStyles(), this.createOverlay(), this.openPopup(e), this.listenForMessages(), this.startPolling(), requestAnimationFrame(() => {
93
+ var s;
94
+ (s = this.overlay) == null || s.classList.add("cp-visible");
95
+ }), document.body.style.overflow = "hidden";
96
+ }
97
+ /**
98
+ * Ferme la popup et l'overlay.
99
+ */
100
+ close() {
101
+ this.stopPolling(), this.messageHandler && (window.removeEventListener("message", this.messageHandler), this.messageHandler = null), this.popup && !this.popup.closed && this.popup.close(), this.popup = null, this.overlay && (this.overlay.classList.remove("cp-visible"), setTimeout(() => {
102
+ var e, s;
103
+ (e = this.overlay) == null || e.remove(), this.overlay = null, document.body.style.overflow = "", this.logger.debug("Checkout closed", { lastStatus: this.lastStatus }), this.emitter.emit("close", { status: this.lastStatus }), (s = this.onCloseCallback) == null || s.call(this, { status: this.lastStatus });
104
+ }, 300));
105
+ }
106
+ /** Dispatche la réponse vers le bon callback selon le statut. */
107
+ dispatchResponse(e) {
108
+ var s, t, i;
109
+ switch (this.lastStatus = e.status, this.logger.debug(`Payment response: ${e.status}`, {
110
+ amount: e.amount,
111
+ currency: e.currency,
112
+ transactionId: e.transactionId,
113
+ paymentMethod: e.paymentMethod
114
+ }), e.status) {
115
+ case "ACCEPTED":
116
+ this.logger.debug("Payment accepted"), this.emitter.emit("payment.success", e), (s = this.onPaymentSuccessCallback) == null || s.call(this, e);
117
+ break;
118
+ case "REFUSED":
119
+ this.logger.warn("Payment refused"), this.emitter.emit("payment.failed", e), (t = this.onPaymentFailedCallback) == null || t.call(this, e);
120
+ break;
121
+ case "PENDING":
122
+ case "INITIATED":
123
+ case "EXPIRED":
124
+ default:
125
+ this.logger.debug(`Payment pending: ${e.status}`), this.emitter.emit("payment.pending", e), (i = this.onPaymentPendingCallback) == null || i.call(this, e);
126
+ break;
127
+ }
128
+ }
129
+ injectStyles() {
130
+ if (document.getElementById("cp-seamless-styles")) return;
131
+ const e = document.createElement("style");
132
+ e.id = "cp-seamless-styles", e.textContent = m, document.head.appendChild(e);
133
+ }
134
+ createOverlay() {
135
+ this.overlay = document.createElement("div"), this.overlay.className = "cp-seamless-overlay";
136
+ const e = document.createElement("div");
137
+ e.className = "cp-seamless-wrapper";
138
+ const s = document.createElement("div");
139
+ s.className = "cp-seamless-waiting";
140
+ const t = document.createElement("div");
141
+ t.className = "cp-seamless-spinner", s.appendChild(t);
142
+ const i = document.createElement("p");
143
+ i.className = "cp-seamless-waiting-title", i.textContent = "Paiement en cours...", s.appendChild(i);
144
+ const n = document.createElement("p");
145
+ n.className = "cp-seamless-waiting-msg", n.textContent = "Finalisez votre paiement dans la fenêtre CinetPay.", s.appendChild(n);
146
+ const o = document.createElement("button");
147
+ o.className = "cp-seamless-cancel-btn", o.textContent = "Annuler", o.addEventListener("click", () => this.close()), s.appendChild(o), e.appendChild(s), this.overlay.appendChild(e), document.body.appendChild(this.overlay);
148
+ }
149
+ /**
150
+ * Ouvre la popup centrée sur l'écran.
151
+ */
152
+ openPopup(e) {
153
+ var o, p;
154
+ const i = Math.max(0, (screen.width - 500) / 2), n = Math.max(0, (screen.height - 700) / 2);
155
+ if (this.popup = window.open(
156
+ e,
157
+ "CinetPayCheckout",
158
+ `width=500,height=700,left=${i},top=${n},scrollbars=yes,resizable=yes`
159
+ ), !this.popup) {
160
+ this.logger.error("Popup blocked by browser");
161
+ const d = {
162
+ code: "POPUP_BLOCKED",
163
+ message: "La fenêtre de paiement a été bloquée par le navigateur. Autorisez les popups pour ce site."
164
+ };
165
+ this.emitter.emit("error", d), (o = this.onErrorCallback) == null || o.call(this, d), this.close();
166
+ return;
167
+ }
168
+ this.logger.debug("Popup opened"), this.emitter.emit("ready"), (p = this.onReadyCallback) == null || p.call(this);
169
+ }
170
+ /**
171
+ * Poll toutes les 500ms pour détecter si la popup a été fermée
172
+ * (par l'utilisateur ou après redirection).
173
+ */
174
+ startPolling() {
175
+ this.pollTimer = setInterval(() => {
176
+ this.popup && this.popup.closed && (this.logger.debug("Popup closed by user or redirect"), this.stopPolling(), setTimeout(() => {
177
+ this.overlay && this.close();
178
+ }, 500));
179
+ }, 500);
180
+ }
181
+ stopPolling() {
182
+ this.pollTimer && (clearInterval(this.pollTimer), this.pollTimer = null);
183
+ }
184
+ /** Écoute les messages postMessage de la popup CinetPay. */
185
+ listenForMessages() {
186
+ this.messageHandler = (e) => {
187
+ var s;
188
+ if (l.ALLOWED_ORIGINS.some((t) => e.origin === t))
189
+ try {
190
+ const t = typeof e.data == "string" ? JSON.parse(e.data) : e.data;
191
+ if (!t || typeof t != "object") return;
192
+ if (t.status) {
193
+ const i = t.status, n = {
194
+ amount: t.amount ?? t.cpm_amount ?? 0,
195
+ currency: t.currency ?? t.cpm_currency ?? "",
196
+ status: i,
197
+ paymentMethod: t.payment_method ?? t.cpm_payment_method ?? "",
198
+ description: t.description ?? t.cpm_designation ?? "",
199
+ metadata: t.metadata ?? t.cpm_custom ?? void 0,
200
+ operatorId: t.operator_id ?? t.cpm_operator_id ?? void 0,
201
+ paymentDate: t.payment_date ?? t.cpm_payment_date ?? void 0,
202
+ transactionId: t.transaction_id ?? t.cpm_trans_id ?? ""
203
+ };
204
+ this.dispatchResponse(n);
205
+ }
206
+ if (t.error || t.code === "ERROR") {
207
+ const i = {
208
+ code: t.code ?? "UNKNOWN",
209
+ message: t.message ?? t.error ?? "An error occurred"
210
+ };
211
+ this.logger.error("Payment error from popup", i), this.emitter.emit("error", i), (s = this.onErrorCallback) == null || s.call(this, i);
212
+ }
213
+ (t.action === "CLOSE" || t.type === "close") && this.close();
214
+ } catch {
215
+ }
216
+ }, window.addEventListener("message", this.messageHandler);
217
+ }
218
+ };
219
+ l.ALLOWED_ORIGINS = [
220
+ "https://secure.cinetpay.net",
221
+ "https://secure.cinetpay.com",
222
+ "https://checkout.cinetpay.net",
223
+ "https://checkout.cinetpay.com",
224
+ "https://api.cinetpay.net",
225
+ "https://api.cinetpay.co"
226
+ ];
227
+ let c = l;
228
+ const r = "[CinetPay Seamless]";
229
+ class h {
230
+ constructor(e) {
231
+ this.enabled = e;
232
+ }
233
+ /** Log de debug — requêtes, réponses, événements */
234
+ debug(e, s) {
235
+ this.enabled && (s !== void 0 ? console.debug(`${r} ${e}`, s) : console.debug(`${r} ${e}`));
236
+ }
237
+ /** Log d'avertissement — credentials exposés, statuts inattendus */
238
+ warn(e, s) {
239
+ this.enabled && (s !== void 0 ? console.warn(`${r} ${e}`, s) : console.warn(`${r} ${e}`));
240
+ }
241
+ /** Log d'erreur — erreurs API, timeouts, postMessage invalides */
242
+ error(e, s) {
243
+ this.enabled && (s !== void 0 ? console.error(`${r} ${e}`, s) : console.error(`${r} ${e}`));
244
+ }
245
+ }
246
+ class u {
247
+ constructor() {
248
+ this.listeners = /* @__PURE__ */ new Map();
249
+ }
250
+ /**
251
+ * Enregistre un handler pour un événement.
252
+ *
253
+ * @param event - Nom de l'événement
254
+ * @param handler - Fonction appelée quand l'événement est émis
255
+ * @returns Fonction pour se désabonner (équivalent de `off(event, handler)`)
256
+ *
257
+ * @example
258
+ * ```typescript
259
+ * const unsubscribe = CinetPaySeamless.on('payment.success', (data) => { ... })
260
+ * // Plus tard :
261
+ * unsubscribe()
262
+ * ```
263
+ */
264
+ on(e, s) {
265
+ return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(s), () => this.off(e, s);
266
+ }
267
+ /**
268
+ * Supprime un handler pour un événement.
269
+ *
270
+ * @param event - Nom de l'événement
271
+ * @param handler - Référence du handler à supprimer
272
+ */
273
+ off(e, s) {
274
+ var t;
275
+ (t = this.listeners.get(e)) == null || t.delete(s);
276
+ }
277
+ /**
278
+ * Enregistre un handler qui ne sera appelé qu'une seule fois.
279
+ *
280
+ * @param event - Nom de l'événement
281
+ * @param handler - Fonction appelée une seule fois
282
+ *
283
+ * @example
284
+ * ```typescript
285
+ * CinetPaySeamless.once('payment.success', (data) => {
286
+ * // Appelé une seule fois
287
+ * })
288
+ * ```
289
+ */
290
+ once(e, s) {
291
+ const t = ((...i) => {
292
+ this.off(e, t), s(...i);
293
+ });
294
+ this.on(e, t);
295
+ }
296
+ /**
297
+ * Émet un événement — appelle tous les handlers enregistrés.
298
+ * @internal
299
+ */
300
+ emit(e, ...s) {
301
+ const t = this.listeners.get(e);
302
+ if (t)
303
+ for (const i of t)
304
+ try {
305
+ i(...s);
306
+ } catch {
307
+ }
308
+ }
309
+ /**
310
+ * Supprime tous les handlers pour tous les événements.
311
+ * @internal
312
+ */
313
+ removeAll() {
314
+ this.listeners.clear();
315
+ }
316
+ }
317
+ const y = "https://secure.cinetpay.net", g = {
318
+ /** Instance du checkout actuellement ouvert */
319
+ _checkout: null,
320
+ /** Event emitter partagé */
321
+ _emitter: new u(),
322
+ /**
323
+ * Enregistre un listener d'événement (style événementiel).
324
+ *
325
+ * @param event - Nom de l'événement
326
+ * @param handler - Fonction appelée quand l'événement est émis
327
+ * @returns Fonction de désabonnement
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * const unsub = CinetPaySeamless.on('payment.success', (data) => {
332
+ * console.log('Payé !', data.amount, data.currency)
333
+ * })
334
+ * unsub() // Se désabonner
335
+ * ```
336
+ */
337
+ on(a, e) {
338
+ return this._emitter.on(a, e);
339
+ },
340
+ /**
341
+ * Supprime un listener.
342
+ */
343
+ off(a, e) {
344
+ this._emitter.off(a, e);
345
+ },
346
+ /**
347
+ * Enregistre un listener appelé une seule fois.
348
+ */
349
+ once(a, e) {
350
+ this._emitter.once(a, e);
351
+ },
352
+ /**
353
+ * Ouvre le checkout CinetPay.
354
+ *
355
+ * Affiche un overlay d'attente et ouvre la page de paiement dans une popup.
356
+ * La popup est centrée sur l'écran (500x700px).
357
+ *
358
+ * @param config - Configuration avec `paymentToken` et callbacks optionnels
359
+ * @throws {Error} Si le `paymentToken` a un format invalide
360
+ *
361
+ * @example
362
+ * ```typescript
363
+ * CinetPaySeamless.open({
364
+ * paymentToken: 'abc123def456...',
365
+ * debug: true,
366
+ * onPaymentSuccess: (data) => console.log('Payé !', data.amount),
367
+ * onPaymentFailed: (data) => console.log('Refusé'),
368
+ * onClose: ({ status }) => console.log('Fermé:', status),
369
+ * })
370
+ * ```
371
+ */
372
+ open(a) {
373
+ this.close();
374
+ const e = new h(a.debug ?? !1);
375
+ if (e.debug("CinetPaySeamless.open() called"), !/^[a-zA-Z0-9_-]{10,128}$/.test(a.paymentToken))
376
+ throw new Error("Invalid paymentToken format — expected alphanumeric string (10-128 chars)");
377
+ const s = `${y}/checkout/${a.paymentToken}`;
378
+ this._checkout = new c({
379
+ logger: e,
380
+ emitter: this._emitter,
381
+ onReady: a.onReady,
382
+ onPaymentSuccess: a.onPaymentSuccess,
383
+ onPaymentFailed: a.onPaymentFailed,
384
+ onPaymentPending: a.onPaymentPending,
385
+ onClose: a.onClose,
386
+ onError: a.onError
387
+ }), this._checkout.open(s);
388
+ },
389
+ /**
390
+ * Ferme le checkout (popup + overlay).
391
+ */
392
+ close() {
393
+ var a;
394
+ (a = this._checkout) == null || a.close(), this._checkout = null;
395
+ }
396
+ };
397
+ typeof window < "u" && (window.CinetPaySeamless = g);
398
+ export {
399
+ g as CinetPaySeamless
400
+ };
401
+ //# sourceMappingURL=cinetpay-seamless.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cinetpay-seamless.js","sources":["../src/styles.ts","../src/checkout.ts","../src/logger.ts","../src/emitter.ts","../src/index.ts"],"sourcesContent":["/**\n * Styles CSS du checkout CinetPay Seamless (mode popup).\n */\nexport const STYLES = `\n.cp-seamless-overlay {\n position: fixed;\n inset: 0;\n z-index: 999999;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(6px);\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n transition: opacity 0.3s ease;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.cp-seamless-overlay.cp-visible {\n opacity: 1;\n}\n\n.cp-seamless-wrapper {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Waiting screen (pendant que la popup est ouverte) */\n.cp-seamless-waiting {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 20px;\n text-align: center;\n padding: 40px;\n}\n\n.cp-seamless-waiting-title {\n color: #fff;\n font-size: 22px;\n font-weight: 600;\n margin: 0;\n}\n\n.cp-seamless-waiting-msg {\n color: rgba(255, 255, 255, 0.7);\n font-size: 15px;\n margin: 0;\n max-width: 320px;\n line-height: 1.5;\n}\n\n.cp-seamless-spinner {\n width: 48px;\n height: 48px;\n border: 3px solid rgba(255, 255, 255, 0.2);\n border-top-color: #e8530e;\n border-radius: 50%;\n animation: cp-spin 0.8s linear infinite;\n}\n\n@keyframes cp-spin {\n to { transform: rotate(360deg); }\n}\n\n.cp-seamless-cancel-btn {\n margin-top: 12px;\n padding: 10px 28px;\n background: rgba(255, 255, 255, 0.12);\n color: rgba(255, 255, 255, 0.8);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.cp-seamless-cancel-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n color: #fff;\n}\n\n`\n","import { STYLES } from './styles'\nimport type { PaymentResponse, PaymentError, PaymentStatus } from './types'\nimport { Logger } from './logger'\nimport { EventEmitter } from './emitter'\n\n/** @internal Options du constructeur Checkout */\nexport interface CheckoutOptions {\n onReady?: () => void\n onPaymentSuccess?: (data: PaymentResponse) => void\n onPaymentFailed?: (data: PaymentResponse) => void\n onPaymentPending?: (data: PaymentResponse) => void\n onClose?: (data: { status: string }) => void\n onError?: (error: PaymentError) => void\n logger: Logger\n emitter: EventEmitter\n}\n\n/** @internal Intervalle de polling pour vérifier si la popup est fermée */\nconst POPUP_POLL_INTERVAL = 500\n\n/**\n * Gère le checkout CinetPay via une popup window + overlay.\n *\n * Flow :\n * 1. Affiche un overlay sombre avec un message d'attente\n * 2. Ouvre la page de checkout dans une popup (window.open)\n * 3. Poll la popup pour détecter sa fermeture\n * 4. Écoute les messages postMessage de la popup\n * 5. Ferme l'overlay et dispatche les callbacks\n *\n * @internal Utilisé par {@link CinetPaySeamless}. Ne pas instancier directement.\n */\nexport class Checkout {\n private overlay: HTMLDivElement | null = null\n private popup: Window | null = null\n private pollTimer: ReturnType<typeof setInterval> | null = null\n private messageHandler: ((event: MessageEvent) => void) | null = null\n private lastStatus = 'UNKNOWN'\n\n private onReadyCallback?: () => void\n private onPaymentSuccessCallback?: (data: PaymentResponse) => void\n private onPaymentFailedCallback?: (data: PaymentResponse) => void\n private onPaymentPendingCallback?: (data: PaymentResponse) => void\n private onCloseCallback?: (data: { status: string }) => void\n private onErrorCallback?: (error: PaymentError) => void\n private logger: Logger\n private emitter: EventEmitter\n\n constructor(options: CheckoutOptions) {\n this.logger = options.logger\n this.emitter = options.emitter\n this.onReadyCallback = options.onReady\n this.onPaymentSuccessCallback = options.onPaymentSuccess\n this.onPaymentFailedCallback = options.onPaymentFailed\n this.onPaymentPendingCallback = options.onPaymentPending\n this.onCloseCallback = options.onClose\n this.onErrorCallback = options.onError\n }\n\n /**\n * Ouvre la popup de checkout et affiche l'overlay d'attente.\n *\n * @param paymentUrl - URL complète de la page de checkout CinetPay\n */\n open(paymentUrl: string): void {\n this.logger.debug('Opening checkout popup', { paymentUrl })\n this.injectStyles()\n this.createOverlay()\n this.openPopup(paymentUrl)\n this.listenForMessages()\n this.startPolling()\n\n requestAnimationFrame(() => {\n this.overlay?.classList.add('cp-visible')\n })\n\n document.body.style.overflow = 'hidden'\n }\n\n /**\n * Ferme la popup et l'overlay.\n */\n close(): void {\n this.stopPolling()\n\n if (this.messageHandler) {\n window.removeEventListener('message', this.messageHandler)\n this.messageHandler = null\n }\n\n if (this.popup && !this.popup.closed) {\n this.popup.close()\n }\n this.popup = null\n\n if (this.overlay) {\n this.overlay.classList.remove('cp-visible')\n setTimeout(() => {\n this.overlay?.remove()\n this.overlay = null\n document.body.style.overflow = ''\n\n this.logger.debug('Checkout closed', { lastStatus: this.lastStatus })\n this.emitter.emit('close', { status: this.lastStatus })\n this.onCloseCallback?.({ status: this.lastStatus })\n }, 300)\n }\n }\n\n /** Dispatche la réponse vers le bon callback selon le statut. */\n private dispatchResponse(response: PaymentResponse): void {\n this.lastStatus = response.status\n\n this.logger.debug(`Payment response: ${response.status}`, {\n amount: response.amount,\n currency: response.currency,\n transactionId: response.transactionId,\n paymentMethod: response.paymentMethod,\n })\n\n switch (response.status) {\n case 'ACCEPTED':\n this.logger.debug('Payment accepted')\n this.emitter.emit('payment.success', response)\n this.onPaymentSuccessCallback?.(response)\n break\n case 'REFUSED':\n this.logger.warn('Payment refused')\n this.emitter.emit('payment.failed', response)\n this.onPaymentFailedCallback?.(response)\n break\n case 'PENDING':\n case 'INITIATED':\n case 'EXPIRED':\n default:\n this.logger.debug(`Payment pending: ${response.status}`)\n this.emitter.emit('payment.pending', response)\n this.onPaymentPendingCallback?.(response)\n break\n }\n }\n\n private injectStyles(): void {\n if (document.getElementById('cp-seamless-styles')) return\n const styleEl = document.createElement('style')\n styleEl.id = 'cp-seamless-styles'\n styleEl.textContent = STYLES\n document.head.appendChild(styleEl)\n }\n\n private createOverlay(): void {\n this.overlay = document.createElement('div')\n this.overlay.className = 'cp-seamless-overlay'\n\n const wrapper = document.createElement('div')\n wrapper.className = 'cp-seamless-wrapper'\n\n // Spinner + message\n const waiting = document.createElement('div')\n waiting.className = 'cp-seamless-waiting'\n\n const spinner = document.createElement('div')\n spinner.className = 'cp-seamless-spinner'\n waiting.appendChild(spinner)\n\n const title = document.createElement('p')\n title.className = 'cp-seamless-waiting-title'\n title.textContent = 'Paiement en cours...'\n waiting.appendChild(title)\n\n const msg = document.createElement('p')\n msg.className = 'cp-seamless-waiting-msg'\n msg.textContent = 'Finalisez votre paiement dans la fenêtre CinetPay.'\n waiting.appendChild(msg)\n\n // Bouton fermer\n const cancelBtn = document.createElement('button')\n cancelBtn.className = 'cp-seamless-cancel-btn'\n cancelBtn.textContent = 'Annuler'\n cancelBtn.addEventListener('click', () => this.close())\n waiting.appendChild(cancelBtn)\n\n wrapper.appendChild(waiting)\n this.overlay.appendChild(wrapper)\n document.body.appendChild(this.overlay)\n }\n\n /**\n * Ouvre la popup centrée sur l'écran.\n */\n private openPopup(paymentUrl: string): void {\n const width = 500\n const height = 700\n const left = Math.max(0, (screen.width - width) / 2)\n const top = Math.max(0, (screen.height - height) / 2)\n\n this.popup = window.open(\n paymentUrl,\n 'CinetPayCheckout',\n `width=${width},height=${height},left=${left},top=${top},scrollbars=yes,resizable=yes`,\n )\n\n if (!this.popup) {\n this.logger.error('Popup blocked by browser')\n const err: PaymentError = {\n code: 'POPUP_BLOCKED',\n message: 'La fenêtre de paiement a été bloquée par le navigateur. Autorisez les popups pour ce site.',\n }\n this.emitter.emit('error', err)\n this.onErrorCallback?.(err)\n this.close()\n return\n }\n\n this.logger.debug('Popup opened')\n this.emitter.emit('ready')\n this.onReadyCallback?.()\n }\n\n /**\n * Poll toutes les 500ms pour détecter si la popup a été fermée\n * (par l'utilisateur ou après redirection).\n */\n private startPolling(): void {\n this.pollTimer = setInterval(() => {\n if (this.popup && this.popup.closed) {\n this.logger.debug('Popup closed by user or redirect')\n this.stopPolling()\n\n // Laisser un court délai pour que le postMessage arrive avant le close\n setTimeout(() => {\n if (this.overlay) {\n this.close()\n }\n }, 500)\n }\n }, POPUP_POLL_INTERVAL)\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer)\n this.pollTimer = null\n }\n }\n\n /** Origines autorisées pour les messages postMessage */\n private static readonly ALLOWED_ORIGINS = [\n 'https://secure.cinetpay.net',\n 'https://secure.cinetpay.com',\n 'https://checkout.cinetpay.net',\n 'https://checkout.cinetpay.com',\n 'https://api.cinetpay.net',\n 'https://api.cinetpay.co',\n ]\n\n /** Écoute les messages postMessage de la popup CinetPay. */\n private listenForMessages(): void {\n this.messageHandler = (event: MessageEvent) => {\n if (!Checkout.ALLOWED_ORIGINS.some((o) => event.origin === o)) {\n return\n }\n\n try {\n const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data\n if (!data || typeof data !== 'object') return\n\n if (data.status) {\n const status = data.status as PaymentStatus\n const response: PaymentResponse = {\n amount: data.amount ?? data.cpm_amount ?? 0,\n currency: data.currency ?? data.cpm_currency ?? '',\n status,\n paymentMethod: data.payment_method ?? data.cpm_payment_method ?? '',\n description: data.description ?? data.cpm_designation ?? '',\n metadata: data.metadata ?? data.cpm_custom ?? undefined,\n operatorId: data.operator_id ?? data.cpm_operator_id ?? undefined,\n paymentDate: data.payment_date ?? data.cpm_payment_date ?? undefined,\n transactionId: data.transaction_id ?? data.cpm_trans_id ?? '',\n }\n this.dispatchResponse(response)\n }\n\n if (data.error || data.code === 'ERROR') {\n const err: PaymentError = {\n code: data.code ?? 'UNKNOWN',\n message: data.message ?? data.error ?? 'An error occurred',\n }\n this.logger.error('Payment error from popup', err)\n this.emitter.emit('error', err)\n this.onErrorCallback?.(err)\n }\n\n if (data.action === 'CLOSE' || data.type === 'close') {\n this.close()\n }\n } catch {\n // Ignorer les messages non-JSON\n }\n }\n\n window.addEventListener('message', this.messageHandler)\n }\n}\n","/** Préfixe des messages de log */\nconst PREFIX = '[CinetPay Seamless]'\n\n/**\n * Logger interne du SDK Seamless.\n * Désactivé par défaut. Activable via `debug: true` dans la config.\n *\n * Tous les logs utilisent le préfixe `[CinetPay Seamless]` pour être\n * facilement filtrables dans la console du navigateur.\n */\nexport class Logger {\n private enabled: boolean\n\n constructor(enabled: boolean) {\n this.enabled = enabled\n }\n\n /** Log de debug — requêtes, réponses, événements */\n debug(message: string, data?: unknown): void {\n if (!this.enabled) return\n if (data !== undefined) {\n console.debug(`${PREFIX} ${message}`, data)\n } else {\n console.debug(`${PREFIX} ${message}`)\n }\n }\n\n /** Log d'avertissement — credentials exposés, statuts inattendus */\n warn(message: string, data?: unknown): void {\n if (!this.enabled) return\n if (data !== undefined) {\n console.warn(`${PREFIX} ${message}`, data)\n } else {\n console.warn(`${PREFIX} ${message}`)\n }\n }\n\n /** Log d'erreur — erreurs API, timeouts, postMessage invalides */\n error(message: string, data?: unknown): void {\n if (!this.enabled) return\n if (data !== undefined) {\n console.error(`${PREFIX} ${message}`, data)\n } else {\n console.error(`${PREFIX} ${message}`)\n }\n }\n}\n","import type { PaymentResponse, PaymentError } from './types'\n\n/**\n * Map des événements émis par le SDK Seamless.\n *\n * | Événement | Donnée | Quand |\n * |---|---|---|\n * | `ready` | — | Popup ouverte, passerelle prête |\n * | `payment.success` | `PaymentResponse` | Paiement accepté |\n * | `payment.failed` | `PaymentResponse` | Paiement refusé |\n * | `payment.pending` | `PaymentResponse` | En attente (PENDING, INITIATED, EXPIRED) |\n * | `close` | `{ status: string }` | Popup fermée, overlay retiré |\n * | `error` | `PaymentError` | Erreur technique |\n */\nexport interface EventMap {\n 'ready': void\n 'payment.success': PaymentResponse\n 'payment.failed': PaymentResponse\n 'payment.pending': PaymentResponse\n 'close': { status: string }\n 'error': PaymentError\n}\n\n/** Type des noms d'événements */\nexport type EventName = keyof EventMap\n\n/** Type d'un handler pour un événement donné */\ntype Handler<T> = T extends void ? () => void : (data: T) => void\n\n/**\n * Event emitter typé pour le SDK Seamless.\n *\n * Permet d'écouter les événements de paiement avec `on()` et `off()`,\n * style événementiel (`on('event', handler)`).\n *\n * @example\n * ```typescript\n * CinetPaySeamless.on('payment.success', (data) => {\n * console.log('Payé !', data.amount, data.currency)\n * })\n *\n * CinetPaySeamless.on('payment.failed', (data) => {\n * console.log('Refusé', data.transactionId)\n * })\n *\n * CinetPaySeamless.on('ready', () => {\n * console.log('Passerelle chargée')\n * })\n * ```\n */\nexport class EventEmitter {\n private listeners = new Map<string, Set<Function>>()\n\n /**\n * Enregistre un handler pour un événement.\n *\n * @param event - Nom de l'événement\n * @param handler - Fonction appelée quand l'événement est émis\n * @returns Fonction pour se désabonner (équivalent de `off(event, handler)`)\n *\n * @example\n * ```typescript\n * const unsubscribe = CinetPaySeamless.on('payment.success', (data) => { ... })\n * // Plus tard :\n * unsubscribe()\n * ```\n */\n on<E extends EventName>(event: E, handler: Handler<EventMap[E]>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set())\n }\n this.listeners.get(event)!.add(handler)\n\n // Retourne une fonction de désabonnement\n return () => this.off(event, handler)\n }\n\n /**\n * Supprime un handler pour un événement.\n *\n * @param event - Nom de l'événement\n * @param handler - Référence du handler à supprimer\n */\n off<E extends EventName>(event: E, handler: Handler<EventMap[E]>): void {\n this.listeners.get(event)?.delete(handler)\n }\n\n /**\n * Enregistre un handler qui ne sera appelé qu'une seule fois.\n *\n * @param event - Nom de l'événement\n * @param handler - Fonction appelée une seule fois\n *\n * @example\n * ```typescript\n * CinetPaySeamless.once('payment.success', (data) => {\n * // Appelé une seule fois\n * })\n * ```\n */\n once<E extends EventName>(event: E, handler: Handler<EventMap[E]>): void {\n const wrapper = ((...args: unknown[]) => {\n this.off(event, wrapper as Handler<EventMap[E]>)\n ;(handler as Function)(...args)\n }) as Handler<EventMap[E]>\n this.on(event, wrapper)\n }\n\n /**\n * Émet un événement — appelle tous les handlers enregistrés.\n * @internal\n */\n emit<E extends EventName>(event: E, ...args: EventMap[E] extends void ? [] : [EventMap[E]]): void {\n const handlers = this.listeners.get(event)\n if (!handlers) return\n for (const handler of handlers) {\n try {\n (handler as Function)(...args)\n } catch {\n // Ne pas bloquer les autres handlers si un throw\n }\n }\n }\n\n /**\n * Supprime tous les handlers pour tous les événements.\n * @internal\n */\n removeAll(): void {\n this.listeners.clear()\n }\n}\n","import { Checkout } from './checkout'\nimport type {\n SeamlessConfig,\n PaymentResponse,\n PaymentError,\n PaymentStatus,\n} from './types'\nimport { Logger } from './logger'\nimport { EventEmitter, type EventName, type EventMap } from './emitter'\n\nexport type {\n SeamlessConfig,\n PaymentResponse,\n PaymentError,\n PaymentStatus,\n}\nexport type { EventName, EventMap } from './emitter'\n\n/** @internal URL de base de la passerelle de paiement sécurisée */\nconst SECURE_BASE_URL = 'https://secure.cinetpay.net'\n\n/**\n * CinetPay Seamless — paiement inline via popup window.\n *\n * Affiche un overlay d'attente et ouvre la passerelle de paiement\n * CinetPay dans une popup. Le client reste sur votre page.\n *\n * Le `paymentToken` est obtenu côté serveur via l'API CinetPay :\n *\n * ```typescript\n * // Frontend\n * CinetPaySeamless.open({\n * paymentToken: 'abc123...',\n * onPaymentSuccess: (data) => console.log('Payé !', data.amount),\n * })\n * ```\n *\n * Ou avec des event listeners (style événementiel) :\n *\n * ```typescript\n * CinetPaySeamless.on('payment.success', (data) => { ... })\n * CinetPaySeamless.open({ paymentToken: 'abc123...' })\n * ```\n */\nexport const CinetPaySeamless = {\n /** Instance du checkout actuellement ouvert */\n _checkout: null as Checkout | null,\n\n /** Event emitter partagé */\n _emitter: new EventEmitter(),\n\n /**\n * Enregistre un listener d'événement (style événementiel).\n *\n * @param event - Nom de l'événement\n * @param handler - Fonction appelée quand l'événement est émis\n * @returns Fonction de désabonnement\n *\n * @example\n * ```typescript\n * const unsub = CinetPaySeamless.on('payment.success', (data) => {\n * console.log('Payé !', data.amount, data.currency)\n * })\n * unsub() // Se désabonner\n * ```\n */\n on<E extends EventName>(\n event: E,\n handler: EventMap[E] extends void ? () => void : (data: EventMap[E]) => void,\n ): () => void {\n return this._emitter.on(event, handler)\n },\n\n /**\n * Supprime un listener.\n */\n off<E extends EventName>(\n event: E,\n handler: EventMap[E] extends void ? () => void : (data: EventMap[E]) => void,\n ): void {\n this._emitter.off(event, handler)\n },\n\n /**\n * Enregistre un listener appelé une seule fois.\n */\n once<E extends EventName>(\n event: E,\n handler: EventMap[E] extends void ? () => void : (data: EventMap[E]) => void,\n ): void {\n this._emitter.once(event, handler)\n },\n\n /**\n * Ouvre le checkout CinetPay.\n *\n * Affiche un overlay d'attente et ouvre la page de paiement dans une popup.\n * La popup est centrée sur l'écran (500x700px).\n *\n * @param config - Configuration avec `paymentToken` et callbacks optionnels\n * @throws {Error} Si le `paymentToken` a un format invalide\n *\n * @example\n * ```typescript\n * CinetPaySeamless.open({\n * paymentToken: 'abc123def456...',\n * debug: true,\n * onPaymentSuccess: (data) => console.log('Payé !', data.amount),\n * onPaymentFailed: (data) => console.log('Refusé'),\n * onClose: ({ status }) => console.log('Fermé:', status),\n * })\n * ```\n */\n open(config: SeamlessConfig): void {\n this.close()\n\n const logger = new Logger(config.debug ?? false)\n logger.debug('CinetPaySeamless.open() called')\n\n // Validation du paymentToken\n if (!/^[a-zA-Z0-9_-]{10,128}$/.test(config.paymentToken)) {\n throw new Error('Invalid paymentToken format — expected alphanumeric string (10-128 chars)')\n }\n\n const paymentUrl = `${SECURE_BASE_URL}/checkout/${config.paymentToken}`\n\n this._checkout = new Checkout({\n logger,\n emitter: this._emitter,\n onReady: config.onReady,\n onPaymentSuccess: config.onPaymentSuccess,\n onPaymentFailed: config.onPaymentFailed,\n onPaymentPending: config.onPaymentPending,\n onClose: config.onClose,\n onError: config.onError,\n })\n\n this._checkout.open(paymentUrl)\n },\n\n /**\n * Ferme le checkout (popup + overlay).\n */\n close(): void {\n this._checkout?.close()\n this._checkout = null\n },\n}\n\n// Auto-attach to window for CDN/script tag usage\nif (typeof window !== 'undefined') {\n (window as unknown as Record<string, unknown>).CinetPaySeamless = CinetPaySeamless\n}\n"],"names":["STYLES","_Checkout","options","paymentUrl","_a","_b","response","_c","styleEl","wrapper","waiting","spinner","title","msg","cancelBtn","left","top","err","event","o","data","status","Checkout","PREFIX","Logger","enabled","message","EventEmitter","handler","args","handlers","SECURE_BASE_URL","CinetPaySeamless","config","logger"],"mappings":"AAGO,MAAMA,IAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AC6Bf,MAAMC,IAAN,MAAMA,EAAS;AAAA,EAgBpB,YAAYC,GAA0B;AAftC,SAAQ,UAAiC,MACzC,KAAQ,QAAuB,MAC/B,KAAQ,YAAmD,MAC3D,KAAQ,iBAAyD,MACjE,KAAQ,aAAa,WAYnB,KAAK,SAASA,EAAQ,QACtB,KAAK,UAAUA,EAAQ,SACvB,KAAK,kBAAkBA,EAAQ,SAC/B,KAAK,2BAA2BA,EAAQ,kBACxC,KAAK,0BAA0BA,EAAQ,iBACvC,KAAK,2BAA2BA,EAAQ,kBACxC,KAAK,kBAAkBA,EAAQ,SAC/B,KAAK,kBAAkBA,EAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAKC,GAA0B;AAC7B,SAAK,OAAO,MAAM,0BAA0B,EAAE,YAAAA,GAAY,GAC1D,KAAK,aAAA,GACL,KAAK,cAAA,GACL,KAAK,UAAUA,CAAU,GACzB,KAAK,kBAAA,GACL,KAAK,aAAA,GAEL,sBAAsB,MAAM;ADrEzB,UAAAC;ACsED,OAAAA,IAAA,KAAK,YAAL,QAAAA,EAAc,UAAU,IAAI;AAAA,IAC9B,CAAC,GAED,SAAS,KAAK,MAAM,WAAW;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,YAAA,GAED,KAAK,mBACP,OAAO,oBAAoB,WAAW,KAAK,cAAc,GACzD,KAAK,iBAAiB,OAGpB,KAAK,SAAS,CAAC,KAAK,MAAM,UAC5B,KAAK,MAAM,MAAA,GAEb,KAAK,QAAQ,MAET,KAAK,YACP,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,WAAW,MAAM;AD9FhB,UAAAA,GAAAC;AC+FC,OAAAD,IAAA,KAAK,YAAL,QAAAA,EAAc,UACd,KAAK,UAAU,MACf,SAAS,KAAK,MAAM,WAAW,IAE/B,KAAK,OAAO,MAAM,mBAAmB,EAAE,YAAY,KAAK,YAAY,GACpE,KAAK,QAAQ,KAAK,SAAS,EAAE,QAAQ,KAAK,YAAY,IACtDC,IAAA,KAAK,oBAAL,QAAAA,EAAA,WAAuB,EAAE,QAAQ,KAAK;IACxC,GAAG,GAAG;AAAA,EAEV;AAAA;AAAA,EAGQ,iBAAiBC,GAAiC;AD3GrD,QAAAF,GAAAC,GAAAE;ACqHH,YATA,KAAK,aAAaD,EAAS,QAE3B,KAAK,OAAO,MAAM,qBAAqBA,EAAS,MAAM,IAAI;AAAA,MACxD,QAAQA,EAAS;AAAA,MACjB,UAAUA,EAAS;AAAA,MACnB,eAAeA,EAAS;AAAA,MACxB,eAAeA,EAAS;AAAA,IAAA,CACzB,GAEOA,EAAS,QAAA;AAAA,MACf,KAAK;AACH,aAAK,OAAO,MAAM,kBAAkB,GACpC,KAAK,QAAQ,KAAK,mBAAmBA,CAAQ,IAC7CF,IAAA,KAAK,6BAAL,QAAAA,EAAA,WAAgCE;AAChC;AAAA,MACF,KAAK;AACH,aAAK,OAAO,KAAK,iBAAiB,GAClC,KAAK,QAAQ,KAAK,kBAAkBA,CAAQ,IAC5CD,IAAA,KAAK,4BAAL,QAAAA,EAAA,WAA+BC;AAC/B;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AACE,aAAK,OAAO,MAAM,oBAAoBA,EAAS,MAAM,EAAE,GACvD,KAAK,QAAQ,KAAK,mBAAmBA,CAAQ,IAC7CC,IAAA,KAAK,6BAAL,QAAAA,EAAA,WAAgCD;AAChC;AAAA,IAAA;AAAA,EAEN;AAAA,EAEQ,eAAqB;AAC3B,QAAI,SAAS,eAAe,oBAAoB,EAAG;AACnD,UAAME,IAAU,SAAS,cAAc,OAAO;AAC9C,IAAAA,EAAQ,KAAK,sBACbA,EAAQ,cAAcR,GACtB,SAAS,KAAK,YAAYQ,CAAO;AAAA,EACnC;AAAA,EAEQ,gBAAsB;AAC5B,SAAK,UAAU,SAAS,cAAc,KAAK,GAC3C,KAAK,QAAQ,YAAY;AAEzB,UAAMC,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,YAAY;AAGpB,UAAMC,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,YAAY;AAEpB,UAAMC,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,YAAY,uBACpBD,EAAQ,YAAYC,CAAO;AAE3B,UAAMC,IAAQ,SAAS,cAAc,GAAG;AACxC,IAAAA,EAAM,YAAY,6BAClBA,EAAM,cAAc,wBACpBF,EAAQ,YAAYE,CAAK;AAEzB,UAAMC,IAAM,SAAS,cAAc,GAAG;AACtC,IAAAA,EAAI,YAAY,2BAChBA,EAAI,cAAc,sDAClBH,EAAQ,YAAYG,CAAG;AAGvB,UAAMC,IAAY,SAAS,cAAc,QAAQ;AACjD,IAAAA,EAAU,YAAY,0BACtBA,EAAU,cAAc,WACxBA,EAAU,iBAAiB,SAAS,MAAM,KAAK,OAAO,GACtDJ,EAAQ,YAAYI,CAAS,GAE7BL,EAAQ,YAAYC,CAAO,GAC3B,KAAK,QAAQ,YAAYD,CAAO,GAChC,SAAS,KAAK,YAAY,KAAK,OAAO;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAUN,GAA0B;AD3LvC,QAAAC,GAAAC;AC8LH,UAAMU,IAAO,KAAK,IAAI,IAAI,OAAO,QAAQ,OAAS,CAAC,GAC7CC,IAAM,KAAK,IAAI,IAAI,OAAO,SAAS,OAAU,CAAC;AAQpD,QANA,KAAK,QAAQ,OAAO;AAAA,MAClBb;AAAA,MACA;AAAA,MACA,6BAAwCY,CAAI,QAAQC,CAAG;AAAA,IAAA,GAGrD,CAAC,KAAK,OAAO;AACf,WAAK,OAAO,MAAM,0BAA0B;AAC5C,YAAMC,IAAoB;AAAA,QACxB,MAAM;AAAA,QACN,SAAS;AAAA,MAAA;AAEX,WAAK,QAAQ,KAAK,SAASA,CAAG,IAC9Bb,IAAA,KAAK,oBAAL,QAAAA,EAAA,WAAuBa,IACvB,KAAK,MAAA;AACL;AAAA,IACF;AAEA,SAAK,OAAO,MAAM,cAAc,GAChC,KAAK,QAAQ,KAAK,OAAO,IACzBZ,IAAA,KAAK,oBAAL,QAAAA,EAAA;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAqB;AAC3B,SAAK,YAAY,YAAY,MAAM;AACjC,MAAI,KAAK,SAAS,KAAK,MAAM,WAC3B,KAAK,OAAO,MAAM,kCAAkC,GACpD,KAAK,YAAA,GAGL,WAAW,MAAM;AACf,QAAI,KAAK,WACP,KAAK,MAAA;AAAA,MAET,GAAG,GAAG;AAAA,IAEV,GAAG,GAAmB;AAAA,EACxB;AAAA,EAEQ,cAAoB;AAC1B,IAAI,KAAK,cACP,cAAc,KAAK,SAAS,GAC5B,KAAK,YAAY;AAAA,EAErB;AAAA;AAAA,EAaQ,oBAA0B;AAChC,SAAK,iBAAiB,CAACa,MAAwB;AD/P5C,UAAAd;ACgQD,UAAKH,EAAS,gBAAgB,KAAK,CAACkB,MAAMD,EAAM,WAAWC,CAAC;AAI5D,YAAI;AACF,gBAAMC,IAAO,OAAOF,EAAM,QAAS,WAAW,KAAK,MAAMA,EAAM,IAAI,IAAIA,EAAM;AAC7E,cAAI,CAACE,KAAQ,OAAOA,KAAS,SAAU;AAEvC,cAAIA,EAAK,QAAQ;AACf,kBAAMC,IAASD,EAAK,QACdd,IAA4B;AAAA,cAChC,QAAQc,EAAK,UAAUA,EAAK,cAAc;AAAA,cAC1C,UAAUA,EAAK,YAAYA,EAAK,gBAAgB;AAAA,cAChD,QAAAC;AAAA,cACA,eAAeD,EAAK,kBAAkBA,EAAK,sBAAsB;AAAA,cACjE,aAAaA,EAAK,eAAeA,EAAK,mBAAmB;AAAA,cACzD,UAAUA,EAAK,YAAYA,EAAK,cAAc;AAAA,cAC9C,YAAYA,EAAK,eAAeA,EAAK,mBAAmB;AAAA,cACxD,aAAaA,EAAK,gBAAgBA,EAAK,oBAAoB;AAAA,cAC3D,eAAeA,EAAK,kBAAkBA,EAAK,gBAAgB;AAAA,YAAA;AAE7D,iBAAK,iBAAiBd,CAAQ;AAAA,UAChC;AAEA,cAAIc,EAAK,SAASA,EAAK,SAAS,SAAS;AACvC,kBAAMH,IAAoB;AAAA,cACxB,MAAMG,EAAK,QAAQ;AAAA,cACnB,SAASA,EAAK,WAAWA,EAAK,SAAS;AAAA,YAAA;AAEzC,iBAAK,OAAO,MAAM,4BAA4BH,CAAG,GACjD,KAAK,QAAQ,KAAK,SAASA,CAAG,IAC9Bb,IAAA,KAAK,oBAAL,QAAAA,EAAA,WAAuBa;AAAA,UACzB;AAEA,WAAIG,EAAK,WAAW,WAAWA,EAAK,SAAS,YAC3C,KAAK,MAAA;AAAA,QAET,QAAQ;AAAA,QAER;AAAA,IACF,GAEA,OAAO,iBAAiB,WAAW,KAAK,cAAc;AAAA,EACxD;AACF;AAxDEnB,EAAwB,kBAAkB;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AA7NG,IAAMqB,IAANrB;AC/BP,MAAMsB,IAAS;AASR,MAAMC,EAAO;AAAA,EAGlB,YAAYC,GAAkB;AAC5B,SAAK,UAAUA;AAAA,EACjB;AAAA;AAAA,EAGA,MAAMC,GAAiBN,GAAsB;AAC3C,IAAK,KAAK,YACNA,MAAS,SACX,QAAQ,MAAM,GAAGG,CAAM,IAAIG,CAAO,IAAIN,CAAI,IAE1C,QAAQ,MAAM,GAAGG,CAAM,IAAIG,CAAO,EAAE;AAAA,EAExC;AAAA;AAAA,EAGA,KAAKA,GAAiBN,GAAsB;AAC1C,IAAK,KAAK,YACNA,MAAS,SACX,QAAQ,KAAK,GAAGG,CAAM,IAAIG,CAAO,IAAIN,CAAI,IAEzC,QAAQ,KAAK,GAAGG,CAAM,IAAIG,CAAO,EAAE;AAAA,EAEvC;AAAA;AAAA,EAGA,MAAMA,GAAiBN,GAAsB;AAC3C,IAAK,KAAK,YACNA,MAAS,SACX,QAAQ,MAAM,GAAGG,CAAM,IAAIG,CAAO,IAAIN,CAAI,IAE1C,QAAQ,MAAM,GAAGG,CAAM,IAAIG,CAAO,EAAE;AAAA,EAExC;AACF;ACIO,MAAMC,EAAa;AAAA,EAAnB,cAAA;AACL,SAAQ,gCAAgB,IAAA;AAAA,EAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBnD,GAAwBT,GAAUU,GAA2C;AAC3E,WAAK,KAAK,UAAU,IAAIV,CAAK,KAC3B,KAAK,UAAU,IAAIA,GAAO,oBAAI,KAAK,GAErC,KAAK,UAAU,IAAIA,CAAK,EAAG,IAAIU,CAAO,GAG/B,MAAM,KAAK,IAAIV,GAAOU,CAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAyBV,GAAUU,GAAqC;AHhFnE,QAAAxB;AGiFH,KAAAA,IAAA,KAAK,UAAU,IAAIc,CAAK,MAAxB,QAAAd,EAA2B,OAAOwB;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,KAA0BV,GAAUU,GAAqC;AACvE,UAAMnB,KAAW,IAAIoB,MAAoB;AACvC,WAAK,IAAIX,GAAOT,CAA+B,GAC7CmB,EAAqB,GAAGC,CAAI;AAAA,IAChC;AACA,SAAK,GAAGX,GAAOT,CAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAA0BS,MAAaW,GAA2D;AAChG,UAAMC,IAAW,KAAK,UAAU,IAAIZ,CAAK;AACzC,QAAKY;AACL,iBAAWF,KAAWE;AACpB,YAAI;AACD,UAAAF,EAAqB,GAAGC,CAAI;AAAA,QAC/B,QAAQ;AAAA,QAER;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAkB;AAChB,SAAK,UAAU,MAAA;AAAA,EACjB;AACF;AChHA,MAAME,IAAkB,+BAyBXC,IAAmB;AAAA;AAAA,EAE9B,WAAW;AAAA;AAAA,EAGX,UAAU,IAAIL,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBd,GACET,GACAU,GACY;AACZ,WAAO,KAAK,SAAS,GAAGV,GAAOU,CAAO;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,IACEV,GACAU,GACM;AACN,SAAK,SAAS,IAAIV,GAAOU,CAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,KACEV,GACAU,GACM;AACN,SAAK,SAAS,KAAKV,GAAOU,CAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,KAAKK,GAA8B;AACjC,SAAK,MAAA;AAEL,UAAMC,IAAS,IAAIV,EAAOS,EAAO,SAAS,EAAK;AAI/C,QAHAC,EAAO,MAAM,gCAAgC,GAGzC,CAAC,0BAA0B,KAAKD,EAAO,YAAY;AACrD,YAAM,IAAI,MAAM,2EAA2E;AAG7F,UAAM9B,IAAa,GAAG4B,CAAe,aAAaE,EAAO,YAAY;AAErE,SAAK,YAAY,IAAIX,EAAS;AAAA,MAC5B,QAAAY;AAAA,MACA,SAAS,KAAK;AAAA,MACd,SAASD,EAAO;AAAA,MAChB,kBAAkBA,EAAO;AAAA,MACzB,iBAAiBA,EAAO;AAAA,MACxB,kBAAkBA,EAAO;AAAA,MACzB,SAASA,EAAO;AAAA,MAChB,SAASA,EAAO;AAAA,IAAA,CACjB,GAED,KAAK,UAAU,KAAK9B,CAAU;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AJ5IT,QAAAC;AI6IH,KAAAA,IAAA,KAAK,cAAL,QAAAA,EAAgB,SAChB,KAAK,YAAY;AAAA,EACnB;AACF;AAGI,OAAO,SAAW,QACnB,OAA8C,mBAAmB4B;"}
@@ -0,0 +1,82 @@
1
+ (function(r,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(r=typeof globalThis<"u"?globalThis:r||self,c(r.CinetPaySeamless={}))})(this,(function(r){"use strict";const c=`
2
+ .cp-seamless-overlay {
3
+ position: fixed;
4
+ inset: 0;
5
+ z-index: 999999;
6
+ background: rgba(0, 0, 0, 0.7);
7
+ backdrop-filter: blur(6px);
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ opacity: 0;
12
+ transition: opacity 0.3s ease;
13
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
14
+ }
15
+
16
+ .cp-seamless-overlay.cp-visible {
17
+ opacity: 1;
18
+ }
19
+
20
+ .cp-seamless-wrapper {
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ }
25
+
26
+ /* Waiting screen (pendant que la popup est ouverte) */
27
+ .cp-seamless-waiting {
28
+ display: flex;
29
+ flex-direction: column;
30
+ align-items: center;
31
+ gap: 20px;
32
+ text-align: center;
33
+ padding: 40px;
34
+ }
35
+
36
+ .cp-seamless-waiting-title {
37
+ color: #fff;
38
+ font-size: 22px;
39
+ font-weight: 600;
40
+ margin: 0;
41
+ }
42
+
43
+ .cp-seamless-waiting-msg {
44
+ color: rgba(255, 255, 255, 0.7);
45
+ font-size: 15px;
46
+ margin: 0;
47
+ max-width: 320px;
48
+ line-height: 1.5;
49
+ }
50
+
51
+ .cp-seamless-spinner {
52
+ width: 48px;
53
+ height: 48px;
54
+ border: 3px solid rgba(255, 255, 255, 0.2);
55
+ border-top-color: #e8530e;
56
+ border-radius: 50%;
57
+ animation: cp-spin 0.8s linear infinite;
58
+ }
59
+
60
+ @keyframes cp-spin {
61
+ to { transform: rotate(360deg); }
62
+ }
63
+
64
+ .cp-seamless-cancel-btn {
65
+ margin-top: 12px;
66
+ padding: 10px 28px;
67
+ background: rgba(255, 255, 255, 0.12);
68
+ color: rgba(255, 255, 255, 0.8);
69
+ border: 1px solid rgba(255, 255, 255, 0.2);
70
+ border-radius: 8px;
71
+ font-size: 14px;
72
+ cursor: pointer;
73
+ transition: all 0.2s;
74
+ }
75
+
76
+ .cp-seamless-cancel-btn:hover {
77
+ background: rgba(255, 255, 255, 0.2);
78
+ color: #fff;
79
+ }
80
+
81
+ `,p=class p{constructor(e){this.overlay=null,this.popup=null,this.pollTimer=null,this.messageHandler=null,this.lastStatus="UNKNOWN",this.logger=e.logger,this.emitter=e.emitter,this.onReadyCallback=e.onReady,this.onPaymentSuccessCallback=e.onPaymentSuccess,this.onPaymentFailedCallback=e.onPaymentFailed,this.onPaymentPendingCallback=e.onPaymentPending,this.onCloseCallback=e.onClose,this.onErrorCallback=e.onError}open(e){this.logger.debug("Opening checkout popup",{paymentUrl:e}),this.injectStyles(),this.createOverlay(),this.openPopup(e),this.listenForMessages(),this.startPolling(),requestAnimationFrame(()=>{var s;(s=this.overlay)==null||s.classList.add("cp-visible")}),document.body.style.overflow="hidden"}close(){this.stopPolling(),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.popup&&!this.popup.closed&&this.popup.close(),this.popup=null,this.overlay&&(this.overlay.classList.remove("cp-visible"),setTimeout(()=>{var e,s;(e=this.overlay)==null||e.remove(),this.overlay=null,document.body.style.overflow="",this.logger.debug("Checkout closed",{lastStatus:this.lastStatus}),this.emitter.emit("close",{status:this.lastStatus}),(s=this.onCloseCallback)==null||s.call(this,{status:this.lastStatus})},300))}dispatchResponse(e){var s,t,i;switch(this.lastStatus=e.status,this.logger.debug(`Payment response: ${e.status}`,{amount:e.amount,currency:e.currency,transactionId:e.transactionId,paymentMethod:e.paymentMethod}),e.status){case"ACCEPTED":this.logger.debug("Payment accepted"),this.emitter.emit("payment.success",e),(s=this.onPaymentSuccessCallback)==null||s.call(this,e);break;case"REFUSED":this.logger.warn("Payment refused"),this.emitter.emit("payment.failed",e),(t=this.onPaymentFailedCallback)==null||t.call(this,e);break;case"PENDING":case"INITIATED":case"EXPIRED":default:this.logger.debug(`Payment pending: ${e.status}`),this.emitter.emit("payment.pending",e),(i=this.onPaymentPendingCallback)==null||i.call(this,e);break}}injectStyles(){if(document.getElementById("cp-seamless-styles"))return;const e=document.createElement("style");e.id="cp-seamless-styles",e.textContent=c,document.head.appendChild(e)}createOverlay(){this.overlay=document.createElement("div"),this.overlay.className="cp-seamless-overlay";const e=document.createElement("div");e.className="cp-seamless-wrapper";const s=document.createElement("div");s.className="cp-seamless-waiting";const t=document.createElement("div");t.className="cp-seamless-spinner",s.appendChild(t);const i=document.createElement("p");i.className="cp-seamless-waiting-title",i.textContent="Paiement en cours...",s.appendChild(i);const a=document.createElement("p");a.className="cp-seamless-waiting-msg",a.textContent="Finalisez votre paiement dans la fenêtre CinetPay.",s.appendChild(a);const o=document.createElement("button");o.className="cp-seamless-cancel-btn",o.textContent="Annuler",o.addEventListener("click",()=>this.close()),s.appendChild(o),e.appendChild(s),this.overlay.appendChild(e),document.body.appendChild(this.overlay)}openPopup(e){var o,h;const i=Math.max(0,(screen.width-500)/2),a=Math.max(0,(screen.height-700)/2);if(this.popup=window.open(e,"CinetPayCheckout",`width=500,height=700,left=${i},top=${a},scrollbars=yes,resizable=yes`),!this.popup){this.logger.error("Popup blocked by browser");const u={code:"POPUP_BLOCKED",message:"La fenêtre de paiement a été bloquée par le navigateur. Autorisez les popups pour ce site."};this.emitter.emit("error",u),(o=this.onErrorCallback)==null||o.call(this,u),this.close();return}this.logger.debug("Popup opened"),this.emitter.emit("ready"),(h=this.onReadyCallback)==null||h.call(this)}startPolling(){this.pollTimer=setInterval(()=>{this.popup&&this.popup.closed&&(this.logger.debug("Popup closed by user or redirect"),this.stopPolling(),setTimeout(()=>{this.overlay&&this.close()},500))},500)}stopPolling(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null)}listenForMessages(){this.messageHandler=e=>{var s;if(p.ALLOWED_ORIGINS.some(t=>e.origin===t))try{const t=typeof e.data=="string"?JSON.parse(e.data):e.data;if(!t||typeof t!="object")return;if(t.status){const i=t.status,a={amount:t.amount??t.cpm_amount??0,currency:t.currency??t.cpm_currency??"",status:i,paymentMethod:t.payment_method??t.cpm_payment_method??"",description:t.description??t.cpm_designation??"",metadata:t.metadata??t.cpm_custom??void 0,operatorId:t.operator_id??t.cpm_operator_id??void 0,paymentDate:t.payment_date??t.cpm_payment_date??void 0,transactionId:t.transaction_id??t.cpm_trans_id??""};this.dispatchResponse(a)}if(t.error||t.code==="ERROR"){const i={code:t.code??"UNKNOWN",message:t.message??t.error??"An error occurred"};this.logger.error("Payment error from popup",i),this.emitter.emit("error",i),(s=this.onErrorCallback)==null||s.call(this,i)}(t.action==="CLOSE"||t.type==="close")&&this.close()}catch{}},window.addEventListener("message",this.messageHandler)}};p.ALLOWED_ORIGINS=["https://secure.cinetpay.net","https://secure.cinetpay.com","https://checkout.cinetpay.net","https://checkout.cinetpay.com","https://api.cinetpay.net","https://api.cinetpay.co"];let d=p;const l="[CinetPay Seamless]";class y{constructor(e){this.enabled=e}debug(e,s){this.enabled&&(s!==void 0?console.debug(`${l} ${e}`,s):console.debug(`${l} ${e}`))}warn(e,s){this.enabled&&(s!==void 0?console.warn(`${l} ${e}`,s):console.warn(`${l} ${e}`))}error(e,s){this.enabled&&(s!==void 0?console.error(`${l} ${e}`,s):console.error(`${l} ${e}`))}}class g{constructor(){this.listeners=new Map}on(e,s){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(s),()=>this.off(e,s)}off(e,s){var t;(t=this.listeners.get(e))==null||t.delete(s)}once(e,s){const t=((...i)=>{this.off(e,t),s(...i)});this.on(e,t)}emit(e,...s){const t=this.listeners.get(e);if(t)for(const i of t)try{i(...s)}catch{}}removeAll(){this.listeners.clear()}}const f="https://secure.cinetpay.net",m={_checkout:null,_emitter:new g,on(n,e){return this._emitter.on(n,e)},off(n,e){this._emitter.off(n,e)},once(n,e){this._emitter.once(n,e)},open(n){this.close();const e=new y(n.debug??!1);if(e.debug("CinetPaySeamless.open() called"),!/^[a-zA-Z0-9_-]{10,128}$/.test(n.paymentToken))throw new Error("Invalid paymentToken format — expected alphanumeric string (10-128 chars)");const s=`${f}/checkout/${n.paymentToken}`;this._checkout=new d({logger:e,emitter:this._emitter,onReady:n.onReady,onPaymentSuccess:n.onPaymentSuccess,onPaymentFailed:n.onPaymentFailed,onPaymentPending:n.onPaymentPending,onClose:n.onClose,onError:n.onError}),this._checkout.open(s)},close(){var n;(n=this._checkout)==null||n.close(),this._checkout=null}};typeof window<"u"&&(window.CinetPaySeamless=m),r.CinetPaySeamless=m,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})}));
82
+ //# sourceMappingURL=cinetpay-seamless.umd.cjs.map