@ianmenethil/zp-observer 6.0.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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/PRIVACY.md +67 -0
  3. package/README.md +284 -0
  4. package/dist/auto-patch.cjs +171 -0
  5. package/dist/auto-patch.cjs.map +7 -0
  6. package/dist/auto-patch.mjs +148 -0
  7. package/dist/auto-patch.mjs.map +7 -0
  8. package/dist/session.cjs +1186 -0
  9. package/dist/session.cjs.map +7 -0
  10. package/dist/session.mjs +1163 -0
  11. package/dist/session.mjs.map +7 -0
  12. package/dist/types/auto-patch.d.ts +9 -0
  13. package/dist/types/auto-patch.d.ts.map +1 -0
  14. package/dist/types/core/beacon.d.ts +6 -0
  15. package/dist/types/core/beacon.d.ts.map +1 -0
  16. package/dist/types/core/detection.d.ts +34 -0
  17. package/dist/types/core/detection.d.ts.map +1 -0
  18. package/dist/types/core/event-bus.d.ts +21 -0
  19. package/dist/types/core/event-bus.d.ts.map +1 -0
  20. package/dist/types/core/experimental.d.ts +35 -0
  21. package/dist/types/core/experimental.d.ts.map +1 -0
  22. package/dist/types/core/heartbeat.d.ts +32 -0
  23. package/dist/types/core/heartbeat.d.ts.map +1 -0
  24. package/dist/types/core/lifecycle.d.ts +31 -0
  25. package/dist/types/core/lifecycle.d.ts.map +1 -0
  26. package/dist/types/core/observer.d.ts +10 -0
  27. package/dist/types/core/observer.d.ts.map +1 -0
  28. package/dist/types/core/outbox.d.ts +20 -0
  29. package/dist/types/core/outbox.d.ts.map +1 -0
  30. package/dist/types/core/random.d.ts +8 -0
  31. package/dist/types/core/random.d.ts.map +1 -0
  32. package/dist/types/core/shortcode.d.ts +17 -0
  33. package/dist/types/core/shortcode.d.ts.map +1 -0
  34. package/dist/types/core/types.d.ts +292 -0
  35. package/dist/types/core/types.d.ts.map +1 -0
  36. package/dist/types/diagnostics/preflight.d.ts +17 -0
  37. package/dist/types/diagnostics/preflight.d.ts.map +1 -0
  38. package/dist/types/index.d.ts +41 -0
  39. package/dist/types/index.d.ts.map +1 -0
  40. package/dist/types/integration/devicefp-bridge.d.ts +31 -0
  41. package/dist/types/integration/devicefp-bridge.d.ts.map +1 -0
  42. package/dist/types/integration/hpp-bridge.d.ts +13 -0
  43. package/dist/types/integration/hpp-bridge.d.ts.map +1 -0
  44. package/dist/types/integration/zenpay-auto-patch.d.ts +28 -0
  45. package/dist/types/integration/zenpay-auto-patch.d.ts.map +1 -0
  46. package/dist/types/outcome.d.ts +20 -0
  47. package/dist/types/outcome.d.ts.map +1 -0
  48. package/dist/types/session.d.ts +54 -0
  49. package/dist/types/session.d.ts.map +1 -0
  50. package/dist/types/transport/callback-transport.d.ts +17 -0
  51. package/dist/types/transport/callback-transport.d.ts.map +1 -0
  52. package/dist/types/transport/http-transport.d.ts +30 -0
  53. package/dist/types/transport/http-transport.d.ts.map +1 -0
  54. package/dist/types/umd.d.ts +16 -0
  55. package/dist/types/umd.d.ts.map +1 -0
  56. package/dist/zp-observer.cjs +1375 -0
  57. package/dist/zp-observer.cjs.map +7 -0
  58. package/dist/zp-observer.js +1377 -0
  59. package/dist/zp-observer.js.map +7 -0
  60. package/dist/zp-observer.min.js +2 -0
  61. package/dist/zp-observer.min.js.map +7 -0
  62. package/dist/zp-observer.min.obf.js +1 -0
  63. package/dist/zp-observer.mjs +1352 -0
  64. package/dist/zp-observer.mjs.map +7 -0
  65. package/package.json +91 -0
@@ -0,0 +1,1186 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/session.ts
21
+ var session_exports = {};
22
+ __export(session_exports, {
23
+ createZenPaySession: () => createZenPaySession
24
+ });
25
+ module.exports = __toCommonJS(session_exports);
26
+
27
+ // src/core/detection.ts
28
+ var DEFAULT_IFRAME_SELECTORS = [
29
+ "iframe.zp-payment-frame",
30
+ 'iframe[src*="zenithpayments"]',
31
+ 'iframe[src*="travelpay"]',
32
+ ".modal-payment iframe",
33
+ "div.modal.show iframe"
34
+ ];
35
+ function startDetection(hooks, opts) {
36
+ if (typeof document === "undefined") {
37
+ return { stop() {
38
+ } };
39
+ }
40
+ let stopped = false;
41
+ let pollTimer = null;
42
+ let mutationObserver = null;
43
+ let bootstrapHandler = null;
44
+ const startedAt = Date.now();
45
+ const findIframe = () => {
46
+ for (const selector of opts.selectors) {
47
+ const el = document.querySelector(selector);
48
+ if (el instanceof HTMLIFrameElement) return el;
49
+ }
50
+ return null;
51
+ };
52
+ const stopPolling = () => {
53
+ if (pollTimer !== null) {
54
+ clearInterval(pollTimer);
55
+ pollTimer = null;
56
+ }
57
+ };
58
+ const watchForRemoval = (iframe) => {
59
+ if (typeof MutationObserver === "undefined" || !document.body) return;
60
+ mutationObserver = new MutationObserver((mutations) => {
61
+ for (const m of mutations) {
62
+ for (const node of Array.from(m.removedNodes)) {
63
+ if (node === iframe || node instanceof Node && node.contains(iframe)) {
64
+ hooks.onRemoved();
65
+ return;
66
+ }
67
+ }
68
+ }
69
+ });
70
+ mutationObserver.observe(document.body, { childList: true, subtree: true });
71
+ };
72
+ const watchBootstrapModal = () => {
73
+ if (typeof document.addEventListener !== "function") return;
74
+ bootstrapHandler = () => hooks.onBootstrapHidden();
75
+ document.addEventListener("hidden.bs.modal", bootstrapHandler, true);
76
+ };
77
+ const onFound = (iframe) => {
78
+ stopPolling();
79
+ watchForRemoval(iframe);
80
+ watchBootstrapModal();
81
+ hooks.onFound(iframe);
82
+ };
83
+ const existing = findIframe();
84
+ if (existing) {
85
+ queueMicrotask(() => {
86
+ if (!stopped) onFound(existing);
87
+ });
88
+ } else {
89
+ pollTimer = setInterval(() => {
90
+ if (stopped) return;
91
+ if (Date.now() - startedAt > opts.timeoutMs) {
92
+ stopPolling();
93
+ hooks.onTimeout();
94
+ return;
95
+ }
96
+ const found = findIframe();
97
+ if (found) onFound(found);
98
+ }, opts.intervalMs);
99
+ }
100
+ return {
101
+ stop() {
102
+ stopped = true;
103
+ stopPolling();
104
+ if (mutationObserver) {
105
+ mutationObserver.disconnect();
106
+ mutationObserver = null;
107
+ }
108
+ if (bootstrapHandler) {
109
+ document.removeEventListener(
110
+ "hidden.bs.modal",
111
+ bootstrapHandler,
112
+ true
113
+ );
114
+ bootstrapHandler = null;
115
+ }
116
+ }
117
+ };
118
+ }
119
+
120
+ // src/core/beacon.ts
121
+ var JSON_TYPE = "application/json";
122
+ function postJsonBeacon(url, body) {
123
+ if (typeof navigator === "undefined" || typeof navigator.sendBeacon !== "function") {
124
+ return false;
125
+ }
126
+ try {
127
+ const blob = new Blob([JSON.stringify(body)], { type: JSON_TYPE });
128
+ return navigator.sendBeacon(url, blob);
129
+ } catch {
130
+ return false;
131
+ }
132
+ }
133
+
134
+ // src/core/experimental.ts
135
+ function hasGlobalExperimentalFeatures(exp) {
136
+ if (!exp) return false;
137
+ return !!(exp.pageLifecycleBeaconUrl || exp.captureWasDiscarded || exp.capturePageShow || exp.captureWindowFocus || exp.captureVisibilityDetail || exp.captureFreezeResume || exp.capturePerformanceEntries);
138
+ }
139
+ function hasIframeExperimentalFeatures(exp) {
140
+ if (!exp) return false;
141
+ return !!(exp.captureIframeResize || exp.captureIframeSrcChanges);
142
+ }
143
+ function logDiag(debug, ...args) {
144
+ if (debug && typeof console !== "undefined") {
145
+ console.log("[ZPObserver/experimental]", ...args);
146
+ }
147
+ }
148
+ function captureUserActivation() {
149
+ try {
150
+ const ua = typeof navigator !== "undefined" ? navigator.userActivation : void 0;
151
+ if (!ua) return void 0;
152
+ return {
153
+ hasBeenActive: ua.hasBeenActive ?? false,
154
+ isActive: ua.isActive ?? false
155
+ };
156
+ } catch {
157
+ return void 0;
158
+ }
159
+ }
160
+ function readNavigationDetail() {
161
+ try {
162
+ const entries = performance.getEntriesByType("navigation");
163
+ const nav = entries[0];
164
+ if (!nav) return null;
165
+ const wasDiscarded = "wasDiscarded" in nav ? Boolean(nav.wasDiscarded) : null;
166
+ return {
167
+ wasDiscarded,
168
+ redirectCount: nav.redirectCount ?? null,
169
+ transferSize: nav.transferSize ?? null,
170
+ type: nav.type ?? null
171
+ };
172
+ } catch {
173
+ return null;
174
+ }
175
+ }
176
+ function readOpenExperimentalFields(exp) {
177
+ if (!exp) return {};
178
+ const out = {};
179
+ if (exp.captureUserActivation) {
180
+ const ua = captureUserActivation();
181
+ if (ua) out.userActivation = ua;
182
+ }
183
+ if (exp.captureNavigationTimingDetail) {
184
+ const nav = readNavigationDetail();
185
+ if (nav) out.navigationDetail = nav;
186
+ }
187
+ return out;
188
+ }
189
+ function installGlobalExperimental(ctx) {
190
+ const { experimental: exp, onDiagnostic, debug, sessionId, getNavigationType: getNavigationType2 } = ctx;
191
+ const stops = [];
192
+ const beaconUrl = exp.pageLifecycleBeaconUrl;
193
+ const fireBeacon = (phase, extra) => {
194
+ if (!beaconUrl) return;
195
+ const payload = { phase, sessionId, timestamp: Date.now(), ...extra };
196
+ const ok = postJsonBeacon(beaconUrl, payload);
197
+ onDiagnostic({ kind: "exp.page_lifecycle_beacon", phase, ok, timestamp: Date.now() });
198
+ logDiag(debug, "pageLifecycleBeacon", phase, ok);
199
+ };
200
+ if (beaconUrl) {
201
+ fireBeacon("navigation", { navType: getNavigationType2() });
202
+ }
203
+ if (exp.captureWasDiscarded) {
204
+ const nav = readNavigationDetail();
205
+ const wasDiscarded = nav?.wasDiscarded ?? null;
206
+ onDiagnostic({ kind: "exp.was_discarded", wasDiscarded, timestamp: Date.now() });
207
+ logDiag(debug, "wasDiscarded", wasDiscarded);
208
+ }
209
+ if ((exp.capturePageShow || beaconUrl) && typeof window !== "undefined") {
210
+ const handler = (ev) => {
211
+ const persisted = ev.persisted === true;
212
+ if (exp.capturePageShow) {
213
+ onDiagnostic({
214
+ kind: "exp.pageshow",
215
+ persisted,
216
+ navigationType: getNavigationType2(),
217
+ timestamp: Date.now()
218
+ });
219
+ logDiag(debug, "pageshow", { persisted });
220
+ }
221
+ if (beaconUrl) fireBeacon("pageshow", { persisted });
222
+ };
223
+ window.addEventListener("pageshow", handler, { passive: true });
224
+ stops.push(() => window.removeEventListener("pageshow", handler));
225
+ }
226
+ if (beaconUrl && typeof window !== "undefined") {
227
+ const ph = (ev) => {
228
+ fireBeacon("pagehide", { persisted: ev.persisted === true });
229
+ };
230
+ window.addEventListener("pagehide", ph, { passive: true });
231
+ stops.push(() => window.removeEventListener("pagehide", ph));
232
+ }
233
+ if (exp.captureWindowFocus && typeof window !== "undefined") {
234
+ const onF = () => {
235
+ onDiagnostic({ kind: "exp.window_focus", timestamp: Date.now() });
236
+ logDiag(debug, "window focus");
237
+ };
238
+ const onB = () => {
239
+ onDiagnostic({ kind: "exp.window_blur", timestamp: Date.now() });
240
+ logDiag(debug, "window blur");
241
+ };
242
+ window.addEventListener("focus", onF, { passive: true });
243
+ window.addEventListener("blur", onB, { passive: true });
244
+ stops.push(() => {
245
+ window.removeEventListener("focus", onF);
246
+ window.removeEventListener("blur", onB);
247
+ });
248
+ }
249
+ if (exp.captureVisibilityDetail && typeof document !== "undefined") {
250
+ let lastState = document.visibilityState ?? "visible";
251
+ let lastChangeAt = Date.now();
252
+ const handler = () => {
253
+ const now = Date.now();
254
+ const curr = document.visibilityState ?? "visible";
255
+ const prev = lastState;
256
+ lastState = curr;
257
+ const deltaMs = now - lastChangeAt;
258
+ lastChangeAt = now;
259
+ const hasFocus = typeof document.hasFocus === "function" ? document.hasFocus() : null;
260
+ const onLine = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : null;
261
+ onDiagnostic({
262
+ kind: "exp.visibility_detail",
263
+ prevState: prev,
264
+ currState: curr,
265
+ prevStateDurationMs: deltaMs,
266
+ hasFocus,
267
+ onLine,
268
+ timestamp: now
269
+ });
270
+ logDiag(debug, "visibility_detail", { prev, curr, hasFocus, onLine });
271
+ };
272
+ document.addEventListener("visibilitychange", handler, { passive: true });
273
+ stops.push(() => document.removeEventListener("visibilitychange", handler));
274
+ }
275
+ if (exp.captureFreezeResume && typeof document !== "undefined") {
276
+ const onFreeze = () => {
277
+ onDiagnostic({ kind: "exp.freeze", timestamp: Date.now() });
278
+ logDiag(debug, "freeze");
279
+ };
280
+ const onResume = () => {
281
+ onDiagnostic({ kind: "exp.resume", timestamp: Date.now() });
282
+ logDiag(debug, "resume");
283
+ };
284
+ try {
285
+ document.addEventListener("freeze", onFreeze, { passive: true });
286
+ document.addEventListener("resume", onResume, { passive: true });
287
+ stops.push(() => {
288
+ document.removeEventListener("freeze", onFreeze);
289
+ document.removeEventListener("resume", onResume);
290
+ });
291
+ } catch {
292
+ logDiag(debug, "freeze/resume not supported");
293
+ }
294
+ }
295
+ if (exp.capturePerformanceEntries && typeof PerformanceObserver !== "undefined") {
296
+ const types = exp.perfEntryTypes ?? ["longtask", "largest-contentful-paint"];
297
+ const emitPerf = (entry) => {
298
+ if (entry.entryType === "longtask") {
299
+ onDiagnostic({
300
+ kind: "exp.perf_entry",
301
+ entryType: entry.entryType,
302
+ name: entry.name,
303
+ startTime: entry.startTime,
304
+ duration: entry.duration,
305
+ timestamp: Date.now()
306
+ });
307
+ } else if (entry.entryType === "largest-contentful-paint") {
308
+ const lcp = entry;
309
+ onDiagnostic({
310
+ kind: "exp.perf_entry",
311
+ entryType: entry.entryType,
312
+ name: entry.name,
313
+ startTime: entry.startTime,
314
+ ...lcp.size !== void 0 && { size: lcp.size },
315
+ ...lcp.url !== void 0 && { url: lcp.url },
316
+ timestamp: Date.now()
317
+ });
318
+ } else {
319
+ onDiagnostic({
320
+ kind: "exp.perf_entry",
321
+ entryType: entry.entryType,
322
+ name: entry.name,
323
+ startTime: entry.startTime,
324
+ timestamp: Date.now()
325
+ });
326
+ }
327
+ logDiag(debug, "perf", entry.entryType, entry.name);
328
+ };
329
+ for (const t of types) {
330
+ try {
331
+ const obs = new PerformanceObserver((list) => {
332
+ for (const entry of list.getEntries()) emitPerf(entry);
333
+ });
334
+ try {
335
+ obs.observe({ type: t, buffered: true });
336
+ } catch {
337
+ obs.observe({ entryTypes: [t] });
338
+ }
339
+ stops.push(() => obs.disconnect());
340
+ } catch (err) {
341
+ logDiag(debug, "PerformanceObserver failed for", t, err);
342
+ }
343
+ }
344
+ }
345
+ return {
346
+ stop() {
347
+ for (const s of stops) s();
348
+ }
349
+ };
350
+ }
351
+ function installIframeExperimental(iframe, ctx) {
352
+ const { experimental: exp, onDiagnostic, debug } = ctx;
353
+ const stops = [];
354
+ if (exp.captureIframeResize && typeof ResizeObserver !== "undefined") {
355
+ const ro = new ResizeObserver((entries) => {
356
+ const e = entries[entries.length - 1];
357
+ if (!e) return;
358
+ const { width, height } = e.contentRect;
359
+ onDiagnostic({
360
+ kind: "exp.iframe_resize",
361
+ width: Math.round(width),
362
+ height: Math.round(height),
363
+ timestamp: Date.now()
364
+ });
365
+ logDiag(debug, "iframe_resize", width, height);
366
+ });
367
+ ro.observe(iframe);
368
+ stops.push(() => ro.disconnect());
369
+ }
370
+ if (exp.captureIframeSrcChanges && typeof MutationObserver !== "undefined") {
371
+ let prev = iframe.src || null;
372
+ const mo = new MutationObserver(() => {
373
+ const cur = iframe.src || "";
374
+ if (cur !== prev) {
375
+ onDiagnostic({
376
+ kind: "exp.iframe_src",
377
+ previousSrc: prev,
378
+ currentSrc: cur,
379
+ timestamp: Date.now()
380
+ });
381
+ logDiag(debug, "iframe_src", prev, cur);
382
+ prev = cur || null;
383
+ }
384
+ });
385
+ mo.observe(iframe, { attributes: true, attributeFilter: ["src"] });
386
+ stops.push(() => mo.disconnect());
387
+ }
388
+ return {
389
+ stop() {
390
+ for (const s of stops) s();
391
+ }
392
+ };
393
+ }
394
+
395
+ // src/core/heartbeat.ts
396
+ function startHeartbeat(sessionId, correlationId, getMetadata, sender, hooks, opts) {
397
+ let sequence = 0;
398
+ let missed = 0;
399
+ let abandoned = false;
400
+ let timer = null;
401
+ const tick = () => {
402
+ if (abandoned) return;
403
+ sequence += 1;
404
+ const ev = {
405
+ kind: "heartbeat",
406
+ sessionId,
407
+ correlationId,
408
+ timestamp: Date.now(),
409
+ sequence,
410
+ missedBeats: missed,
411
+ metadata: getMetadata()
412
+ };
413
+ void sender.sendHeartbeat(ev).then((result) => {
414
+ if (result.ok) {
415
+ missed = 0;
416
+ } else {
417
+ missed += 1;
418
+ if (missed >= opts.missThreshold && !abandoned) {
419
+ abandoned = true;
420
+ hooks.onAbandoned(missed);
421
+ }
422
+ }
423
+ hooks.onTick(sequence, missed);
424
+ }).catch(() => {
425
+ missed += 1;
426
+ if (missed >= opts.missThreshold && !abandoned) {
427
+ abandoned = true;
428
+ hooks.onAbandoned(missed);
429
+ }
430
+ hooks.onTick(sequence, missed);
431
+ });
432
+ };
433
+ timer = setInterval(tick, opts.intervalMs);
434
+ return {
435
+ stop() {
436
+ abandoned = true;
437
+ if (timer !== null) {
438
+ clearInterval(timer);
439
+ timer = null;
440
+ }
441
+ },
442
+ heartbeatCount: () => sequence,
443
+ missedBeats: () => missed
444
+ };
445
+ }
446
+
447
+ // src/core/lifecycle.ts
448
+ function installPageLifecycle(hooks) {
449
+ if (typeof document === "undefined" || typeof window === "undefined") {
450
+ return { stop() {
451
+ } };
452
+ }
453
+ const visibilityHandler = () => {
454
+ if (document.visibilityState === "hidden") hooks.onHidden();
455
+ else if (document.visibilityState === "visible") hooks.onVisible();
456
+ };
457
+ const pageHideHandler = (event) => {
458
+ const persisted = event.persisted === true;
459
+ hooks.onPageHide(persisted);
460
+ };
461
+ document.addEventListener("visibilitychange", visibilityHandler);
462
+ window.addEventListener("pagehide", pageHideHandler);
463
+ return {
464
+ stop() {
465
+ document.removeEventListener("visibilitychange", visibilityHandler);
466
+ window.removeEventListener("pagehide", pageHideHandler);
467
+ }
468
+ };
469
+ }
470
+ function observeIframeVisibility(iframe, onChange) {
471
+ if (typeof IntersectionObserver === "undefined") {
472
+ return { stop() {
473
+ } };
474
+ }
475
+ const io = new IntersectionObserver(
476
+ (entries) => {
477
+ const entry = entries[entries.length - 1];
478
+ if (entry) onChange(entry.isIntersecting);
479
+ },
480
+ { threshold: 0.01 }
481
+ );
482
+ io.observe(iframe);
483
+ return {
484
+ stop() {
485
+ io.disconnect();
486
+ }
487
+ };
488
+ }
489
+
490
+ // src/core/shortcode.ts
491
+ var PREFIX = "zpcb_";
492
+ function generateShortcodeName() {
493
+ const ts = Date.now().toString(36);
494
+ if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
495
+ const buf = new Uint32Array(2);
496
+ crypto.getRandomValues(buf);
497
+ return `${PREFIX}${ts}_${buf[0].toString(36)}${buf[1].toString(36)}`;
498
+ }
499
+ const rand = Math.floor(Math.random() * 4294967295).toString(36);
500
+ return `${PREFIX}${ts}_${rand}`;
501
+ }
502
+ function registerShortcode(name, fn) {
503
+ if (typeof window !== "undefined") {
504
+ window[name] = fn;
505
+ }
506
+ return `window.${name}`;
507
+ }
508
+ function unregisterShortcode(name) {
509
+ if (typeof window !== "undefined") {
510
+ try {
511
+ delete window[name];
512
+ } catch {
513
+ window[name] = void 0;
514
+ }
515
+ }
516
+ }
517
+
518
+ // src/core/random.ts
519
+ function fallbackUUID() {
520
+ const hex = "0123456789abcdef";
521
+ const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
522
+ let result = "";
523
+ for (const ch of template) {
524
+ if (ch === "-") {
525
+ result += "-";
526
+ } else if (ch === "4") {
527
+ result += "4";
528
+ } else if (ch === "y") {
529
+ result += hex[Math.random() * 16 | 0];
530
+ } else {
531
+ result += hex[Math.random() * 16 | 0];
532
+ }
533
+ }
534
+ return result;
535
+ }
536
+ function generateUUID() {
537
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
538
+ return crypto.randomUUID();
539
+ }
540
+ return fallbackUUID();
541
+ }
542
+
543
+ // src/core/event-bus.ts
544
+ function createEventBus(transport, beforeSend, outbox) {
545
+ function applyBeforeSend(ev) {
546
+ if (!beforeSend) return ev;
547
+ try {
548
+ return beforeSend(ev);
549
+ } catch {
550
+ return ev;
551
+ }
552
+ }
553
+ function sendViaTransport(ev) {
554
+ return transport.send(ev).catch(() => ({ ok: false }));
555
+ }
556
+ const bus = {
557
+ emit(ev) {
558
+ const filtered = applyBeforeSend(ev);
559
+ if (!filtered) return;
560
+ if (outbox && ev.kind !== "heartbeat") {
561
+ outbox.push(filtered);
562
+ }
563
+ void sendViaTransport(filtered).then((result) => {
564
+ if (result.ok && outbox && ev.kind !== "heartbeat") {
565
+ outbox.remove(filtered);
566
+ }
567
+ });
568
+ },
569
+ async sendHeartbeat(ev) {
570
+ const filtered = applyBeforeSend(ev);
571
+ if (!filtered) return { ok: true };
572
+ const result = await sendViaTransport(filtered);
573
+ return result;
574
+ },
575
+ drain(sessionId) {
576
+ if (!outbox) return;
577
+ const pending = outbox.drain(sessionId);
578
+ for (const ev of pending) {
579
+ void sendViaTransport(ev).then((result) => {
580
+ if (result.ok) outbox.remove(ev);
581
+ });
582
+ }
583
+ }
584
+ };
585
+ return bus;
586
+ }
587
+
588
+ // src/core/outbox.ts
589
+ var STORAGE_KEY = "__zpobs_outbox_v1";
590
+ var MAX_ENTRIES = 64;
591
+ function createOutbox(onUnavailable) {
592
+ if (typeof localStorage === "undefined") {
593
+ return null;
594
+ }
595
+ function readAll() {
596
+ try {
597
+ const raw = localStorage.getItem(STORAGE_KEY);
598
+ if (!raw) return [];
599
+ const parsed = JSON.parse(raw);
600
+ if (!Array.isArray(parsed)) return [];
601
+ return parsed;
602
+ } catch {
603
+ onUnavailable("Failed to read outbox from localStorage");
604
+ return [];
605
+ }
606
+ }
607
+ function writeAll(entries) {
608
+ try {
609
+ const trimmed = entries.slice(-MAX_ENTRIES);
610
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(trimmed));
611
+ return true;
612
+ } catch (err) {
613
+ onUnavailable(
614
+ err instanceof Error ? err.message : "localStorage write failed (quota or private mode)"
615
+ );
616
+ return false;
617
+ }
618
+ }
619
+ return {
620
+ push(event) {
621
+ const entries = readAll();
622
+ entries.push({ sessionId: event.sessionId, correlationId: event.correlationId, event });
623
+ writeAll(entries);
624
+ },
625
+ remove(event) {
626
+ const entries = readAll();
627
+ const filtered = entries.filter(
628
+ (e) => !(e.event.kind === event.kind && e.event.timestamp === event.timestamp && e.event.sessionId === event.sessionId)
629
+ );
630
+ writeAll(filtered);
631
+ },
632
+ drain(targetSessionId) {
633
+ const entries = readAll();
634
+ const match = entries.filter((e) => e.sessionId === targetSessionId);
635
+ const rest = entries.filter((e) => e.sessionId !== targetSessionId);
636
+ writeAll(rest);
637
+ return match.map((e) => e.event);
638
+ }
639
+ };
640
+ }
641
+
642
+ // src/core/observer.ts
643
+ function getNavigationType() {
644
+ try {
645
+ const entries = performance.getEntriesByType("navigation");
646
+ const entry = entries[0];
647
+ return entry?.type ?? null;
648
+ } catch {
649
+ return null;
650
+ }
651
+ }
652
+ function logDebug(enabled, ...args) {
653
+ if (enabled && typeof console !== "undefined") {
654
+ console.log("[ZPObserver]", ...args);
655
+ }
656
+ }
657
+ function createObserver(options) {
658
+ if (!options || typeof options !== "object") {
659
+ throw new Error("[ZPObserver] createObserver(options) requires an options object");
660
+ }
661
+ if (!options.sessionId || typeof options.sessionId !== "string") {
662
+ throw new Error("[ZPObserver] options.sessionId is required");
663
+ }
664
+ if (!options.transport) {
665
+ throw new Error("[ZPObserver] options.transport is required");
666
+ }
667
+ const sessionId = options.sessionId;
668
+ const correlationId = options.correlationId ?? generateUUID();
669
+ const transport = options.transport;
670
+ const metadata = options.metadata ?? {};
671
+ const beforeSend = options.beforeSend;
672
+ const heartbeatMs = options.heartbeatMs ?? 5e3;
673
+ const missThreshold = options.heartbeatMissThreshold ?? 3;
674
+ const idleTimeoutMs = options.idleTimeoutMs ?? 15 * 60 * 1e3;
675
+ const detectionIntervalMs = options.detectionIntervalMs ?? 100;
676
+ const detectionTimeoutMs = options.detectionTimeoutMs ?? 3e4;
677
+ const iframeSelectors = options.iframeSelectors ?? Array.from(DEFAULT_IFRAME_SELECTORS);
678
+ const debug = options.debug === true;
679
+ const experimental = options.experimental;
680
+ const diagMax = experimental?.diagnosticsMax ?? 50;
681
+ const diagnosticsBuffer = [];
682
+ const recentEvents = [];
683
+ const eventsMax = 50;
684
+ let uiState = "IDLE";
685
+ let transportState = "CONNECTED";
686
+ let isActive = false;
687
+ let startedAtMs = 0;
688
+ let iframeEl = null;
689
+ let closed = false;
690
+ let detectionHandle = null;
691
+ let lifecycleHandle = null;
692
+ let visibilityHandle = null;
693
+ let heartbeat = null;
694
+ let idleTimer = null;
695
+ let experimentalGlobalHandle = null;
696
+ let experimentalIframeHandle = null;
697
+ const shortcodeName = generateShortcodeName();
698
+ const shortcode = registerShortcode(shortcodeName, () => {
699
+ logDebug(debug, `shortcode invoked: ${shortcodeName}`);
700
+ stop("user.callback_invoked");
701
+ });
702
+ const emitDiagnostic = (e) => {
703
+ diagnosticsBuffer.push(e);
704
+ while (diagnosticsBuffer.length > diagMax) diagnosticsBuffer.shift();
705
+ options.onDiagnostic?.(e);
706
+ logDebug(debug, "diagnostic", e);
707
+ };
708
+ const outbox = options.persistence === "localStorage" ? createOutbox((error) => {
709
+ emitDiagnostic({ kind: "system.persistence_unavailable", error, timestamp: Date.now() });
710
+ }) : null;
711
+ const bus = createEventBus(transport, beforeSend, outbox);
712
+ const trackEvent = (ev) => {
713
+ recentEvents.push(ev);
714
+ while (recentEvents.length > eventsMax) recentEvents.shift();
715
+ };
716
+ const emit = (event) => {
717
+ trackEvent(event);
718
+ bus.emit(event);
719
+ };
720
+ const getMetadata = () => {
721
+ const base = { ...metadata };
722
+ if (experimental?.attachDiagnosticsToHeartbeat) {
723
+ base.zpObserverDiagnostics = diagnosticsBuffer.slice();
724
+ }
725
+ return base;
726
+ };
727
+ const resetIdleTimer = () => {
728
+ if (idleTimeoutMs <= 0) return;
729
+ if (idleTimer !== null) clearTimeout(idleTimer);
730
+ idleTimer = setTimeout(() => {
731
+ logDebug(debug, "idle timeout reached");
732
+ stop("system.idle_timeout");
733
+ }, idleTimeoutMs);
734
+ };
735
+ const sendOpen = (iframe) => {
736
+ const openExtras = readOpenExperimentalFields(experimental);
737
+ const ev = {
738
+ kind: "open",
739
+ sessionId,
740
+ correlationId,
741
+ timestamp: Date.now(),
742
+ iframeSrc: iframe.src || null,
743
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "",
744
+ screenWidth: typeof screen !== "undefined" ? screen.width : 0,
745
+ screenHeight: typeof screen !== "undefined" ? screen.height : 0,
746
+ navigationType: getNavigationType(),
747
+ metadata: getMetadata(),
748
+ ...openExtras
749
+ };
750
+ emit(ev);
751
+ };
752
+ const sendClose = (reason, wasPersisted) => {
753
+ const hbCount = heartbeat?.heartbeatCount() ?? 0;
754
+ const missed = heartbeat?.missedBeats() ?? 0;
755
+ const ev = {
756
+ kind: "close",
757
+ sessionId,
758
+ correlationId,
759
+ timestamp: Date.now(),
760
+ reason,
761
+ elapsedMs: startedAtMs ? Date.now() - startedAtMs : 0,
762
+ heartbeatCount: hbCount,
763
+ missedBeats: missed,
764
+ wasPersisted,
765
+ metadata: getMetadata()
766
+ };
767
+ emit(ev);
768
+ };
769
+ const start = () => {
770
+ if (isActive) {
771
+ logDebug(debug, "start() called while already active \u2014 ignoring");
772
+ return;
773
+ }
774
+ isActive = true;
775
+ closed = false;
776
+ startedAtMs = Date.now();
777
+ uiState = "DETECTING";
778
+ bus.drain(sessionId);
779
+ emit({
780
+ kind: "payment.session_init",
781
+ sessionId,
782
+ correlationId,
783
+ timestamp: Date.now(),
784
+ metadata: getMetadata()
785
+ });
786
+ if (hasGlobalExperimentalFeatures(experimental) && experimental) {
787
+ experimentalGlobalHandle = installGlobalExperimental({
788
+ sessionId,
789
+ experimental,
790
+ onDiagnostic: emitDiagnostic,
791
+ debug,
792
+ getNavigationType
793
+ });
794
+ }
795
+ lifecycleHandle = installPageLifecycle({
796
+ onHidden: () => {
797
+ if (uiState === "ACTIVE_MODAL_VISIBLE") uiState = "BACKGROUND_HIDDEN";
798
+ },
799
+ onVisible: () => {
800
+ if (uiState === "BACKGROUND_HIDDEN") uiState = "ACTIVE_MODAL_VISIBLE";
801
+ },
802
+ onPageHide: (persisted) => {
803
+ if (!closed) stopInternal("page.pagehide", persisted);
804
+ }
805
+ });
806
+ detectionHandle = startDetection(
807
+ {
808
+ onFound: (iframe) => {
809
+ iframeEl = iframe;
810
+ uiState = "ACTIVE_MODAL_VISIBLE";
811
+ logDebug(debug, "iframe detected:", iframe.src);
812
+ sendOpen(iframe);
813
+ heartbeat = startHeartbeat(
814
+ sessionId,
815
+ correlationId,
816
+ getMetadata,
817
+ bus,
818
+ {
819
+ onTick: (_seq, missed) => {
820
+ transportState = missed === 0 ? "CONNECTED" : missed < missThreshold ? "HEARTBEAT_LATE" : "DISCONNECTED";
821
+ if (missed === 0) resetIdleTimer();
822
+ },
823
+ onAbandoned: () => {
824
+ transportState = "DISCONNECTED";
825
+ if (!closed) stop("system.network_abandoned");
826
+ }
827
+ },
828
+ { intervalMs: heartbeatMs, missThreshold }
829
+ );
830
+ visibilityHandle = observeIframeVisibility(iframe, (visible) => {
831
+ logDebug(debug, "iframe visibility:", visible);
832
+ });
833
+ if (hasIframeExperimentalFeatures(experimental) && experimental) {
834
+ experimentalIframeHandle = installIframeExperimental(iframe, {
835
+ sessionId,
836
+ experimental,
837
+ onDiagnostic: emitDiagnostic,
838
+ debug,
839
+ getNavigationType
840
+ });
841
+ }
842
+ resetIdleTimer();
843
+ },
844
+ onRemoved: () => {
845
+ if (!closed) stop("user.modal_closed");
846
+ },
847
+ onBootstrapHidden: () => {
848
+ if (!closed) stop("user.modal_closed");
849
+ },
850
+ onTimeout: () => {
851
+ logDebug(debug, "detection timeout \u2014 no iframe found");
852
+ }
853
+ },
854
+ {
855
+ selectors: iframeSelectors,
856
+ intervalMs: detectionIntervalMs,
857
+ timeoutMs: detectionTimeoutMs
858
+ }
859
+ );
860
+ logDebug(debug, `started session ${sessionId}, correlationId=${correlationId}, shortcode=${shortcode}`);
861
+ };
862
+ const stopInternal = (reason, wasPersisted) => {
863
+ if (closed) return;
864
+ closed = true;
865
+ isActive = false;
866
+ uiState = "DISMISSED";
867
+ logDebug(debug, `stopping: ${reason}`);
868
+ if (detectionHandle) {
869
+ detectionHandle.stop();
870
+ detectionHandle = null;
871
+ }
872
+ if (heartbeat) {
873
+ heartbeat.stop();
874
+ heartbeat = null;
875
+ }
876
+ if (visibilityHandle) {
877
+ visibilityHandle.stop();
878
+ visibilityHandle = null;
879
+ }
880
+ if (experimentalIframeHandle) {
881
+ experimentalIframeHandle.stop();
882
+ experimentalIframeHandle = null;
883
+ }
884
+ if (idleTimer !== null) {
885
+ clearTimeout(idleTimer);
886
+ idleTimer = null;
887
+ }
888
+ if (lifecycleHandle) {
889
+ lifecycleHandle.stop();
890
+ lifecycleHandle = null;
891
+ }
892
+ if (experimentalGlobalHandle) {
893
+ experimentalGlobalHandle.stop();
894
+ experimentalGlobalHandle = null;
895
+ }
896
+ sendClose(reason, wasPersisted);
897
+ unregisterShortcode(shortcodeName);
898
+ };
899
+ const stop = (reason = "user.manual_close") => {
900
+ stopInternal(reason, null);
901
+ };
902
+ const getState = () => ({
903
+ ui: uiState,
904
+ transport: transportState,
905
+ sessionId,
906
+ correlationId,
907
+ shortcode,
908
+ isActive,
909
+ iframeDetected: iframeEl !== null,
910
+ heartbeatCount: heartbeat?.heartbeatCount() ?? 0,
911
+ missedBeats: heartbeat?.missedBeats() ?? 0,
912
+ elapsedMs: startedAtMs ? Date.now() - startedAtMs : 0
913
+ });
914
+ const diagnostics = {
915
+ dump() {
916
+ return {
917
+ sessionId,
918
+ correlationId,
919
+ state: getState(),
920
+ recentEvents: recentEvents.slice(),
921
+ diagnostics: diagnosticsBuffer.slice(),
922
+ configuredTransport: transport.constructor?.name ?? "custom",
923
+ version: "6.0.0"
924
+ };
925
+ }
926
+ };
927
+ return { sessionId, correlationId, shortcode, start, stop, getState, emit, diagnostics };
928
+ }
929
+
930
+ // src/integration/zenpay-auto-patch.ts
931
+ function logDebug2(enabled, ...args) {
932
+ if (enabled && typeof console !== "undefined") {
933
+ console.log("[ZPObserver/auto-patch]", ...args);
934
+ }
935
+ }
936
+ function resolveAndCallWindowPath(windowPath) {
937
+ const path = windowPath.replace(/^window\./, "").split(".");
938
+ let ref = window;
939
+ for (const part of path) {
940
+ if (ref && typeof ref === "object" && part in ref) {
941
+ ref = ref[part];
942
+ } else {
943
+ ref = void 0;
944
+ break;
945
+ }
946
+ }
947
+ if (typeof ref === "function") ref();
948
+ }
949
+ function wrapOptions(opts, shortcode, chainExisting) {
950
+ const next = { ...opts ?? {} };
951
+ const existing = next.onPluginClose;
952
+ if (chainExisting && existing != null) {
953
+ if (typeof window !== "undefined") {
954
+ const wrapperName = `__zpobs_chain_${Date.now().toString(36)}`;
955
+ window[wrapperName] = () => {
956
+ try {
957
+ if (typeof existing === "function") {
958
+ existing();
959
+ } else if (typeof existing === "string") {
960
+ resolveAndCallWindowPath(existing);
961
+ }
962
+ } catch {
963
+ }
964
+ try {
965
+ resolveAndCallWindowPath(shortcode);
966
+ } catch {
967
+ }
968
+ };
969
+ next.onPluginClose = `window.${wrapperName}`;
970
+ return next;
971
+ }
972
+ }
973
+ next.onPluginClose = shortcode;
974
+ return next;
975
+ }
976
+ function patchJQueryPlugin($, shortcode, chainExisting, debug, onInvoke) {
977
+ const original = $.fn.zpPayment;
978
+ if (typeof original !== "function" || original.__zpobsPatched) {
979
+ return false;
980
+ }
981
+ const patched = function(opts) {
982
+ onInvoke();
983
+ return original.call(this, wrapOptions(opts, shortcode, chainExisting));
984
+ };
985
+ patched.__zpobsPatched = true;
986
+ $.fn.zpPayment = patched;
987
+ logDebug2(debug, "patched $.fn.zpPayment");
988
+ return true;
989
+ }
990
+ function patchZenPayGlobal(shortcode, chainExisting, debug, onInvoke) {
991
+ const w = window;
992
+ const original = w.ZenPay;
993
+ if (typeof original !== "function" || original.__zpobsPatched) {
994
+ return false;
995
+ }
996
+ const handler = {
997
+ construct(target, args) {
998
+ onInvoke();
999
+ const [first, ...rest] = args;
1000
+ const wrapped = wrapOptions(first, shortcode, chainExisting);
1001
+ return Reflect.construct(target, [wrapped, ...rest]);
1002
+ },
1003
+ apply(target, thisArg, args) {
1004
+ onInvoke();
1005
+ const [first, ...rest] = args;
1006
+ const wrapped = wrapOptions(first, shortcode, chainExisting);
1007
+ return Reflect.apply(target, thisArg, [
1008
+ wrapped,
1009
+ ...rest
1010
+ ]);
1011
+ }
1012
+ };
1013
+ const patched = new Proxy(original, handler);
1014
+ patched.__zpobsPatched = true;
1015
+ w.ZenPay = patched;
1016
+ logDebug2(debug, "patched window.ZenPay");
1017
+ return true;
1018
+ }
1019
+ function installZenPayAutoPatch(observer, options = {}) {
1020
+ if (typeof window === "undefined") {
1021
+ return { uninstall() {
1022
+ }, isPatched: () => false };
1023
+ }
1024
+ const pollIntervalMs = options.pollIntervalMs ?? 200;
1025
+ const pollTimeoutMs = options.pollTimeoutMs ?? 3e4;
1026
+ const chainExisting = options.chainExisting !== false;
1027
+ const debug = options.debug === true;
1028
+ let patched = false;
1029
+ const shortcode = observer.shortcode;
1030
+ const w = window;
1031
+ const emitHppInit = () => {
1032
+ observer.emit({
1033
+ kind: "payment.hpp_init",
1034
+ sessionId: observer.sessionId,
1035
+ correlationId: observer.correlationId,
1036
+ timestamp: Date.now(),
1037
+ metadata: {}
1038
+ });
1039
+ };
1040
+ const tryPatch = () => {
1041
+ let didSomething = false;
1042
+ const jq = w.jQuery ?? w.$;
1043
+ if (jq && typeof jq === "object" && "fn" in jq) {
1044
+ if (patchJQueryPlugin(jq, shortcode, chainExisting, debug, emitHppInit)) didSomething = true;
1045
+ }
1046
+ if ("ZenPay" in window) {
1047
+ if (patchZenPayGlobal(shortcode, chainExisting, debug, emitHppInit)) didSomething = true;
1048
+ }
1049
+ if (didSomething) patched = true;
1050
+ return didSomething;
1051
+ };
1052
+ tryPatch();
1053
+ const startedAt = Date.now();
1054
+ let pollTimer = setInterval(() => {
1055
+ if (Date.now() - startedAt > pollTimeoutMs) {
1056
+ if (pollTimer !== null) {
1057
+ clearInterval(pollTimer);
1058
+ pollTimer = null;
1059
+ }
1060
+ return;
1061
+ }
1062
+ tryPatch();
1063
+ }, pollIntervalMs);
1064
+ return {
1065
+ uninstall() {
1066
+ if (pollTimer !== null) {
1067
+ clearInterval(pollTimer);
1068
+ pollTimer = null;
1069
+ }
1070
+ },
1071
+ isPatched: () => patched
1072
+ };
1073
+ }
1074
+
1075
+ // src/integration/hpp-bridge.ts
1076
+ function installHPPBridge(observer) {
1077
+ if (typeof window === "undefined") {
1078
+ return { uninstall() {
1079
+ } };
1080
+ }
1081
+ const w = window;
1082
+ const original = w.onPaymentPluginLoaded;
1083
+ const wrapper = () => {
1084
+ try {
1085
+ observer.emit({
1086
+ kind: "payment.hpp_iframe_loaded",
1087
+ sessionId: observer.sessionId,
1088
+ correlationId: observer.correlationId,
1089
+ timestamp: Date.now(),
1090
+ metadata: {}
1091
+ });
1092
+ } catch {
1093
+ }
1094
+ if (typeof original === "function") {
1095
+ try {
1096
+ original();
1097
+ } catch {
1098
+ }
1099
+ }
1100
+ };
1101
+ w.onPaymentPluginLoaded = wrapper;
1102
+ return {
1103
+ uninstall() {
1104
+ w.onPaymentPluginLoaded = original ?? null;
1105
+ }
1106
+ };
1107
+ }
1108
+
1109
+ // src/session.ts
1110
+ function createZenPaySession(options) {
1111
+ const {
1112
+ sessionId,
1113
+ transport,
1114
+ correlationId,
1115
+ metadata,
1116
+ persistence,
1117
+ autoPatch,
1118
+ heartbeatMs,
1119
+ debug
1120
+ } = options;
1121
+ const observer = createObserver({
1122
+ sessionId,
1123
+ transport,
1124
+ ...correlationId !== void 0 ? { correlationId } : {},
1125
+ ...metadata !== void 0 ? { metadata } : {},
1126
+ ...persistence !== void 0 ? { persistence } : {},
1127
+ ...heartbeatMs !== void 0 ? { heartbeatMs } : {},
1128
+ ...debug !== void 0 ? { debug } : {}
1129
+ });
1130
+ observer.start();
1131
+ installZenPayAutoPatch(observer, autoPatch);
1132
+ installHPPBridge(observer);
1133
+ const fpObserver = observer;
1134
+ const hooks = {
1135
+ onFingerprintStarted(attempt) {
1136
+ fpObserver.emit({
1137
+ kind: "payment.fingerprint_started",
1138
+ sessionId,
1139
+ correlationId: fpObserver.correlationId,
1140
+ timestamp: Date.now(),
1141
+ attempt,
1142
+ metadata: metadata ?? {}
1143
+ });
1144
+ },
1145
+ onFingerprintCacheHit(age) {
1146
+ fpObserver.emit({
1147
+ kind: "payment.fingerprint_cache_hit",
1148
+ sessionId,
1149
+ correlationId: fpObserver.correlationId,
1150
+ timestamp: Date.now(),
1151
+ age,
1152
+ metadata: metadata ?? {}
1153
+ });
1154
+ },
1155
+ onFingerprintSucceeded() {
1156
+ fpObserver.emit({
1157
+ kind: "payment.fingerprint_succeeded",
1158
+ sessionId,
1159
+ correlationId: fpObserver.correlationId,
1160
+ timestamp: Date.now(),
1161
+ metadata: metadata ?? {}
1162
+ });
1163
+ },
1164
+ onFingerprintFailed(error, attempt) {
1165
+ fpObserver.emit({
1166
+ kind: "payment.fingerprint_failed",
1167
+ sessionId,
1168
+ correlationId: fpObserver.correlationId,
1169
+ timestamp: Date.now(),
1170
+ error,
1171
+ attempt,
1172
+ metadata: metadata ?? {}
1173
+ });
1174
+ }
1175
+ };
1176
+ return {
1177
+ sessionId,
1178
+ correlationId: observer.correlationId,
1179
+ observer,
1180
+ hppDefaults: {
1181
+ onPluginClose: observer.shortcode
1182
+ },
1183
+ fingerprint: { hooks }
1184
+ };
1185
+ }
1186
+ //# sourceMappingURL=session.cjs.map