@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.
- package/LICENSE +21 -0
- package/PRIVACY.md +67 -0
- package/README.md +284 -0
- package/dist/auto-patch.cjs +171 -0
- package/dist/auto-patch.cjs.map +7 -0
- package/dist/auto-patch.mjs +148 -0
- package/dist/auto-patch.mjs.map +7 -0
- package/dist/session.cjs +1186 -0
- package/dist/session.cjs.map +7 -0
- package/dist/session.mjs +1163 -0
- package/dist/session.mjs.map +7 -0
- package/dist/types/auto-patch.d.ts +9 -0
- package/dist/types/auto-patch.d.ts.map +1 -0
- package/dist/types/core/beacon.d.ts +6 -0
- package/dist/types/core/beacon.d.ts.map +1 -0
- package/dist/types/core/detection.d.ts +34 -0
- package/dist/types/core/detection.d.ts.map +1 -0
- package/dist/types/core/event-bus.d.ts +21 -0
- package/dist/types/core/event-bus.d.ts.map +1 -0
- package/dist/types/core/experimental.d.ts +35 -0
- package/dist/types/core/experimental.d.ts.map +1 -0
- package/dist/types/core/heartbeat.d.ts +32 -0
- package/dist/types/core/heartbeat.d.ts.map +1 -0
- package/dist/types/core/lifecycle.d.ts +31 -0
- package/dist/types/core/lifecycle.d.ts.map +1 -0
- package/dist/types/core/observer.d.ts +10 -0
- package/dist/types/core/observer.d.ts.map +1 -0
- package/dist/types/core/outbox.d.ts +20 -0
- package/dist/types/core/outbox.d.ts.map +1 -0
- package/dist/types/core/random.d.ts +8 -0
- package/dist/types/core/random.d.ts.map +1 -0
- package/dist/types/core/shortcode.d.ts +17 -0
- package/dist/types/core/shortcode.d.ts.map +1 -0
- package/dist/types/core/types.d.ts +292 -0
- package/dist/types/core/types.d.ts.map +1 -0
- package/dist/types/diagnostics/preflight.d.ts +17 -0
- package/dist/types/diagnostics/preflight.d.ts.map +1 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/integration/devicefp-bridge.d.ts +31 -0
- package/dist/types/integration/devicefp-bridge.d.ts.map +1 -0
- package/dist/types/integration/hpp-bridge.d.ts +13 -0
- package/dist/types/integration/hpp-bridge.d.ts.map +1 -0
- package/dist/types/integration/zenpay-auto-patch.d.ts +28 -0
- package/dist/types/integration/zenpay-auto-patch.d.ts.map +1 -0
- package/dist/types/outcome.d.ts +20 -0
- package/dist/types/outcome.d.ts.map +1 -0
- package/dist/types/session.d.ts +54 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/transport/callback-transport.d.ts +17 -0
- package/dist/types/transport/callback-transport.d.ts.map +1 -0
- package/dist/types/transport/http-transport.d.ts +30 -0
- package/dist/types/transport/http-transport.d.ts.map +1 -0
- package/dist/types/umd.d.ts +16 -0
- package/dist/types/umd.d.ts.map +1 -0
- package/dist/zp-observer.cjs +1375 -0
- package/dist/zp-observer.cjs.map +7 -0
- package/dist/zp-observer.js +1377 -0
- package/dist/zp-observer.js.map +7 -0
- package/dist/zp-observer.min.js +2 -0
- package/dist/zp-observer.min.js.map +7 -0
- package/dist/zp-observer.min.obf.js +1 -0
- package/dist/zp-observer.mjs +1352 -0
- package/dist/zp-observer.mjs.map +7 -0
- package/package.json +91 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zenith Payments
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/PRIVACY.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Privacy notice — @ianmenethil/zp-observer
|
|
2
|
+
|
|
3
|
+
This library collects a small, fixed set of fields for each payment session. It does **not** read form values, iframe contents, cookies, or arbitrary DOM state.
|
|
4
|
+
|
|
5
|
+
## Fields collected
|
|
6
|
+
|
|
7
|
+
### `open` event (once per session)
|
|
8
|
+
|
|
9
|
+
| Field | Purpose |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `sessionId` | Identifier you pass in; typically the merchant unique payment id |
|
|
12
|
+
| `timestamp` | When the modal iframe was first detected |
|
|
13
|
+
| `iframeSrc` | The iframe's `src` URL (Zenith-hosted origin) |
|
|
14
|
+
| `userAgent` | `navigator.userAgent` — for debugging browser-specific issues |
|
|
15
|
+
| `screenWidth` / `screenHeight` | Screen size — for mobile vs desktop bucketing |
|
|
16
|
+
| `navigationType` | `performance.getEntriesByType('navigation')[0].type` |
|
|
17
|
+
| `metadata` | Whatever you pass into `createObserver({ metadata: ... })` |
|
|
18
|
+
|
|
19
|
+
### `heartbeat` event (every `heartbeatMs`, default 5s)
|
|
20
|
+
|
|
21
|
+
| Field | Purpose |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `sessionId`, `timestamp`, `metadata` | as above |
|
|
24
|
+
| `sequence` | Monotonic counter for deduplication |
|
|
25
|
+
| `missedBeats` | How many consecutive failures we've seen |
|
|
26
|
+
|
|
27
|
+
### `close` event (once per session)
|
|
28
|
+
|
|
29
|
+
| Field | Purpose |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `sessionId`, `timestamp`, `metadata` | as above |
|
|
32
|
+
| `reason` | One of seven documented reasons (see README) |
|
|
33
|
+
| `elapsedMs` | How long the session lasted |
|
|
34
|
+
| `heartbeatCount` | Total heartbeats sent |
|
|
35
|
+
| `missedBeats` | Consecutive failures at close time |
|
|
36
|
+
| `wasPersisted` | `pagehide.persisted` — true if page went into bfcache |
|
|
37
|
+
|
|
38
|
+
## Fields **not** collected
|
|
39
|
+
|
|
40
|
+
- No form field values or payment card data (cross-origin blocks this anyway)
|
|
41
|
+
- No cookies or storage contents
|
|
42
|
+
- No click / keystroke events
|
|
43
|
+
- No page URL beyond what you pass in `metadata`
|
|
44
|
+
- No IP address (your server records that when it receives the request)
|
|
45
|
+
|
|
46
|
+
## Scrubbing
|
|
47
|
+
|
|
48
|
+
Use `beforeSend` to mutate or drop events before they leave the browser:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
createObserver({
|
|
52
|
+
sessionId: mUPID,
|
|
53
|
+
transport: httpTransport({ ... }),
|
|
54
|
+
beforeSend: (ev) => {
|
|
55
|
+
if (ev.kind === 'open') {
|
|
56
|
+
return { ...ev, userAgent: '' };
|
|
57
|
+
}
|
|
58
|
+
return ev;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Return `null` to drop an event entirely.
|
|
64
|
+
|
|
65
|
+
## Cross-origin note
|
|
66
|
+
|
|
67
|
+
The ZenPay payment iframe is on a Zenith-controlled domain. Browser same-origin policy means this library **cannot** read anything inside the iframe — no form values, no DOM, no keystrokes. It only observes the iframe element itself (presence, size, visibility) from the parent page.
|
package/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# @ianmenethil/zp-observer
|
|
2
|
+
|
|
3
|
+
Telemetry for **Zenith hosted checkout**: v6 adds **domain events**, **correlation IDs**, **persistent outbox**, and a **unified session entry point** on top of the proven open/heartbeat/close model. Cross-page outcome reporting, device fingerprint bridge hooks, and HPP lifecycle observation are all wired through a single typed event bus.
|
|
4
|
+
|
|
5
|
+
**Pick one path:**
|
|
6
|
+
|
|
7
|
+
| You are… | Go to |
|
|
8
|
+
|----------|--------|
|
|
9
|
+
| Using **Vite / webpack / Node ESM** | [npm — ES modules](#npm--es-modules-import) |
|
|
10
|
+
| Using **CommonJS** (`require`) | [npm — CommonJS](#npm--commonjs-require) |
|
|
11
|
+
| Using a **plain HTML page** with no bundler | [CDN — `<script>` tag](#cdn--script-tag-no-bundler) |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Install (npm only)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @ianmenethil/zp-observer
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quickstart (unified session — v6)
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createZenPaySession, httpTransport } from '@ianmenethil/zp-observer/session';
|
|
27
|
+
|
|
28
|
+
const session = createZenPaySession({
|
|
29
|
+
sessionId: merchantUPID,
|
|
30
|
+
transport: httpTransport({ openUrl, aliveUrl, closeUrl }),
|
|
31
|
+
persistence: 'localStorage',
|
|
32
|
+
metadata: { merchantId: 'ACME', env: 'prod' },
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// session.observer is started automatically.
|
|
36
|
+
// Pass session.hppDefaults.onPluginClose to ZenPay.
|
|
37
|
+
// Pass session.fingerprint.hooks into DEVICEFP's captureThumbmark() options.
|
|
38
|
+
// session.correlationId ties every event together.
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Correlation IDs
|
|
42
|
+
|
|
43
|
+
Every event carries a `correlationId` — a UUID minted by the observer (or supplied via `createObserver({ correlationId })`). It flows through the fingerprint, HPP init, modal open, heartbeats, close, and outcome events so your backend can join the full payment story without timestamp guessing. Pass it to DEVICEFP via the bridge hooks, or embed it in `merchantUniquePaymentId` metadata.
|
|
44
|
+
|
|
45
|
+
## npm — ES modules (`import`)
|
|
46
|
+
|
|
47
|
+
**`headers` on `httpTransport` is optional.** If you omit it, requests still run: heartbeats and fetch fallbacks send **`Content-Type: application/json`** only, and use **`credentials: 'include'`** so **first-party / same-site cookies** are included when the browser allows it. **`navigator.sendBeacon`** (used for `open` / `close` when it succeeds) **cannot set custom headers** — only the JSON body.
|
|
48
|
+
|
|
49
|
+
So integrators often:
|
|
50
|
+
|
|
51
|
+
- **No extra auth** — omit `headers`; rely on **session cookies** on your own origin, or **signed query params** baked into the three URLs.
|
|
52
|
+
- **Bearer / API key** — pass `headers: () => ({ Authorization: 'Bearer …' })` (or any static object) so **heartbeat** and **fetch fallbacks** include them; beacons still won’t.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import {
|
|
56
|
+
createObserver,
|
|
57
|
+
httpTransport,
|
|
58
|
+
installZenPayAutoPatch,
|
|
59
|
+
} from '@ianmenethil/zp-observer';
|
|
60
|
+
|
|
61
|
+
const mUPID = 'your-merchant-unique-payment-id';
|
|
62
|
+
|
|
63
|
+
const observer = createObserver({
|
|
64
|
+
sessionId: mUPID,
|
|
65
|
+
transport: httpTransport({
|
|
66
|
+
openUrl: `https://your-api.example/telemetry/${mUPID}?e=open`,
|
|
67
|
+
aliveUrl: `https://your-api.example/telemetry/${mUPID}?e=alive`,
|
|
68
|
+
closeUrl: `https://your-api.example/telemetry/${mUPID}?e=close`,
|
|
69
|
+
// Optional — only if your server needs extra headers on fetch() calls:
|
|
70
|
+
// headers: () => ({ Authorization: `Bearer ${getLogsToken()}` }),
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Optional: rewrite ZenPay init so onPluginClose uses observer.shortcode automatically
|
|
75
|
+
installZenPayAutoPatch(observer);
|
|
76
|
+
|
|
77
|
+
observer.start();
|
|
78
|
+
|
|
79
|
+
// Then open ZenPay as you already do, e.g.:
|
|
80
|
+
// $.zpPayment({ merchantUniquePaymentId: mUPID, onPluginClose: observer.shortcode }).init();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Without auto-patch:** after `start()`, pass **`observer.shortcode`** (a string like `window.zpcb_…`) to ZenPay’s **`onPluginClose`** — same value as the v4 bridge.
|
|
84
|
+
|
|
85
|
+
**Optional subpath** (only the ZenPay patch helper):
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { installZenPayAutoPatch } from '@ianmenethil/zp-observer/auto-patch';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## npm — CommonJS (`require`)
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
const {
|
|
97
|
+
createObserver,
|
|
98
|
+
httpTransport,
|
|
99
|
+
installZenPayAutoPatch,
|
|
100
|
+
} = require('@ianmenethil/zp-observer');
|
|
101
|
+
|
|
102
|
+
const mUPID = 'your-merchant-unique-payment-id';
|
|
103
|
+
|
|
104
|
+
const observer = createObserver({
|
|
105
|
+
sessionId: mUPID,
|
|
106
|
+
transport: httpTransport({
|
|
107
|
+
openUrl: `https://your-api.example/telemetry/${mUPID}?e=open`,
|
|
108
|
+
aliveUrl: `https://your-api.example/telemetry/${mUPID}?e=alive`,
|
|
109
|
+
closeUrl: `https://your-api.example/telemetry/${mUPID}?e=close`,
|
|
110
|
+
}),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
installZenPayAutoPatch(observer);
|
|
114
|
+
observer.start();
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## CDN — `<script>` tag (no bundler)
|
|
120
|
+
|
|
121
|
+
1. Add **one** script from **`dist/`** (published path on unpkg/jsDelivr includes `dist/`).
|
|
122
|
+
|
|
123
|
+
2. Use the global **`ZPObserver`** — same names as the npm API: `createObserver`, `httpTransport`, `installZenPayAutoPatch`, `callbackTransport`, `VERSION`.
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<script src="https://unpkg.com/@ianmenethil/zp-observer/dist/zp-observer.min.js"></script>
|
|
127
|
+
<script>
|
|
128
|
+
(function () {
|
|
129
|
+
var mUPID = ‘your-merchant-unique-payment-id’;
|
|
130
|
+
|
|
131
|
+
var observer = ZPObserver.createObserver({
|
|
132
|
+
sessionId: mUPID,
|
|
133
|
+
transport: ZPObserver.httpTransport({
|
|
134
|
+
openUrl: ‘/telemetry/’ + mUPID + ‘?e=open’,
|
|
135
|
+
aliveUrl: ‘/telemetry/’ + mUPID + ‘?e=alive’,
|
|
136
|
+
closeUrl: ‘/telemetry/’ + mUPID + ‘?e=close’,
|
|
137
|
+
}),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
ZPObserver.installZenPayAutoPatch(observer);
|
|
141
|
+
observer.start();
|
|
142
|
+
|
|
143
|
+
// ZenPay init — if you don’t use auto-patch, pass onPluginClose: observer.shortcode
|
|
144
|
+
})();
|
|
145
|
+
</script>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Which CDN file?**
|
|
149
|
+
|
|
150
|
+
| File | When |
|
|
151
|
+
|------|------|
|
|
152
|
+
| `dist/zp-observer.js` | Debugging (readable) |
|
|
153
|
+
| `dist/zp-observer.min.js` | **Default** production |
|
|
154
|
+
| `dist/zp-observer.min.obf.js` | Minified + obfuscated |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## API (quick reference)
|
|
159
|
+
|
|
160
|
+
| Export | Role |
|
|
161
|
+
|--------|------|
|
|
162
|
+
| **`createObserver(options)`** | Returns `{ sessionId, correlationId, shortcode, start, stop, getState, emit, diagnostics }`. |
|
|
163
|
+
| **`httpTransport({ openUrl, aliveUrl, closeUrl, eventUrl?, headers?, fetch? })`** | Default HTTP transport. `eventUrl` (optional) receives domain events. |
|
|
164
|
+
| **`callbackTransport({ onOpen?, onHeartbeat?, onClose?, onEvent? })`** | Bring-your-own-sink. `onEvent` receives domain events. |
|
|
165
|
+
| **`installZenPayAutoPatch(observer)`** | Wraps `$.fn.zpPayment` / `window.ZenPay` to inject `observer.shortcode` and emit `payment.hpp_init`. |
|
|
166
|
+
| **`installHPPBridge(observer)`** | Wraps `window.onPaymentPluginLoaded` to emit `payment.hpp_iframe_loaded`. |
|
|
167
|
+
| **`installDeviceFPBridge(observer, opts?)`** | Returns typed hooks (`onFingerprintStarted`, `onFingerprintCacheHit`, `onFingerprintSucceeded`, `onFingerprintFailed`) that emit domain events. Spread into DEVICEFP's `captureThumbmark()`. |
|
|
168
|
+
| **`preflight({ transport, sample? })`** | Sends a `payment.preflight` event and returns a structured `PreflightReport` for integration debugging. |
|
|
169
|
+
| **`reportOutcome({ correlationId, sessionId, outcome, transport })`** | Posts a single `payment.outcome` event from your return/thank-you page. |
|
|
170
|
+
| **`createZenPaySession(options)`** | Unified entry (subpath `@ianmenethil/zp-observer/session`). Composes observer, auto-patch, HPP bridge, and fingerprint hooks. |
|
|
171
|
+
| **`VERSION`** | Package version string. |
|
|
172
|
+
| **`ExperimentalOptions` / `onDiagnostic`** | See [Experimental / lab](#experimental--lab-optional). |
|
|
173
|
+
|
|
174
|
+
**`observer.emit(event)`** — push any `ObserverEvent` onto the bus (bridges, merchant code).
|
|
175
|
+
**`observer.diagnostics.dump()`** — JSON-serializable snapshot for support tickets.
|
|
176
|
+
**`observer.shortcode`** — string to pass to ZenPay as **`onPluginClose`** (e.g. `window.zpcb_abc123`).
|
|
177
|
+
**`observer.correlationId`** — the UUID tying this session's events together.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Experimental / lab (optional)
|
|
182
|
+
|
|
183
|
+
Use this to **turn on one browser signal at a time** and record what actually fires in your merchants’ browsers. Nothing here changes the core **`open` / `heartbeat` / `close`** contract unless you opt in to extra fields or heartbeats.
|
|
184
|
+
|
|
185
|
+
- **`onDiagnostic`** — callback with typed **`DiagnosticEvent`** (`exp.pageshow`, `exp.freeze`, `exp.perf_entry`, …).
|
|
186
|
+
- **`experimental.*`** — booleans such as **`capturePageShow`**, **`captureFreezeResume`**, **`capturePerformanceEntries`**, **`captureIframeResize`**, **`captureIframeSrcChanges`**, **`captureVisibilityDetail`** (includes **`navigator.onLine`** as **informational only**), **`captureWindowFocus`**, **`captureWasDiscarded`**, **`captureUserActivation`**, **`captureNavigationTimingDetail`** (adds **`userActivation`** / **`navigationDetail`** on the **`open`** payload when set).
|
|
187
|
+
- **`pageLifecycleBeaconUrl`** — optional URL; sends JSON **`sendBeacon`** for **`navigation`** (at `start()`), **`pageshow`**, **`pagehide`** (mirrors the v1.2 experiment’s page-lifecycle beacons). **`exp.page_lifecycle_beacon`** diagnostics report whether **`sendBeacon`** returned true.
|
|
188
|
+
- **`attachDiagnosticsToHeartbeat`** — append a ring buffer to **`metadata.zpObserverDiagnostics`** on each heartbeat (cap with **`diagnosticsMax`**, default 50).
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
createObserver({
|
|
192
|
+
sessionId: mUPID,
|
|
193
|
+
transport: /* … */,
|
|
194
|
+
debug: true,
|
|
195
|
+
onDiagnostic: (ev) => {
|
|
196
|
+
console.table(ev);
|
|
197
|
+
// or POST to your lab sink
|
|
198
|
+
},
|
|
199
|
+
experimental: {
|
|
200
|
+
capturePageShow: true,
|
|
201
|
+
captureFreezeResume: true,
|
|
202
|
+
capturePerformanceEntries: true,
|
|
203
|
+
captureIframeResize: true,
|
|
204
|
+
captureIframeSrcChanges: true,
|
|
205
|
+
attachDiagnosticsToHeartbeat: true,
|
|
206
|
+
// pageLifecycleBeaconUrl: 'https://your-lab.example/beacon',
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Bring your own transport (npm ESM example)
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { createObserver, callbackTransport } from '@ianmenethil/zp-observer';
|
|
217
|
+
|
|
218
|
+
const observer = createObserver({
|
|
219
|
+
sessionId: mUPID,
|
|
220
|
+
transport: callbackTransport({
|
|
221
|
+
onOpen: (ev) => {
|
|
222
|
+
void navigator.sendBeacon('/telemetry', JSON.stringify(ev));
|
|
223
|
+
},
|
|
224
|
+
onHeartbeat: async (ev) => {
|
|
225
|
+
const res = await fetch('/telemetry', {
|
|
226
|
+
method: 'POST',
|
|
227
|
+
headers: { 'Content-Type': 'application/json' },
|
|
228
|
+
body: JSON.stringify(ev),
|
|
229
|
+
});
|
|
230
|
+
return { ok: res.ok, status: res.status };
|
|
231
|
+
},
|
|
232
|
+
onClose: (ev) => {
|
|
233
|
+
void navigator.sendBeacon('/telemetry', JSON.stringify(ev));
|
|
234
|
+
},
|
|
235
|
+
}),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
observer.start();
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Build output layout (`dist/`)
|
|
244
|
+
|
|
245
|
+
| File | Purpose |
|
|
246
|
+
|------|---------|
|
|
247
|
+
| **`dist/zp-observer.mjs`** | **npm ESM** — `import` resolves here |
|
|
248
|
+
| **`dist/zp-observer.cjs`** | **npm CJS** — `require()` resolves here |
|
|
249
|
+
| **`dist/auto-patch.mjs`** | **npm ESM subpath** — `@ianmenethil/zp-observer/auto-patch` |
|
|
250
|
+
| **`dist/auto-patch.cjs`** | **npm CJS subpath** |
|
|
251
|
+
| **`dist/session.mjs`** | **npm ESM subpath** — `@ianmenethil/zp-observer/session` |
|
|
252
|
+
| **`dist/session.cjs`** | **npm CJS subpath** |
|
|
253
|
+
| **`dist/zp-observer.min.js`** | **CDN** — `<script src>` IIFE, global `ZPObserver` |
|
|
254
|
+
| **`dist/zp-observer.js`** | **CDN debug** — unminified IIFE |
|
|
255
|
+
| **`dist/zp-observer.min.obf.js`** | **CDN obfuscated** — minified + obfuscated |
|
|
256
|
+
| **`dist/types/`** | **TypeScript** — `.d.ts` declarations |
|
|
257
|
+
|
|
258
|
+
Do not point a raw `<script>` at `.mjs` / `.cjs` files (those use ESM `import`/`export` or CJS `require`).
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Close reasons
|
|
263
|
+
|
|
264
|
+
Typed as **`CloseReason`** in the published `.d.ts`. Examples: `user.callback_invoked`, `user.modal_closed`, `system.idle_timeout`, `system.network_abandoned`, `page.pagehide`, `user.manual_close`.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Publishing (`@ianmenethil/zp-observer`)
|
|
269
|
+
|
|
270
|
+
1. `npm login` with an account that can publish the **`@ianmenethil`** scope.
|
|
271
|
+
2. Bump **`version`** in `package.json` (or run `npm version patch|minor|major`).
|
|
272
|
+
3. Run **`npm run publish:npm`** (same as **`npm publish --access public`**). **`prepack`** runs **`npm run check`** (lint + typecheck + test + knip + jscpd) and **`npm run build`** before the tarball is packed.
|
|
273
|
+
|
|
274
|
+
**Internal CDN:** On the Anticide build machine, run `npm run build:local` to copy the IIFE bundles to `_ZP-CDN-server\public`.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Privacy
|
|
279
|
+
|
|
280
|
+
See [`PRIVACY.md`](PRIVACY.md).
|
|
281
|
+
|
|
282
|
+
## License
|
|
283
|
+
|
|
284
|
+
MIT © Zenith Payments
|
|
@@ -0,0 +1,171 @@
|
|
|
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/auto-patch.ts
|
|
21
|
+
var auto_patch_exports = {};
|
|
22
|
+
__export(auto_patch_exports, {
|
|
23
|
+
installZenPayAutoPatch: () => installZenPayAutoPatch
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(auto_patch_exports);
|
|
26
|
+
|
|
27
|
+
// src/integration/zenpay-auto-patch.ts
|
|
28
|
+
function logDebug(enabled, ...args) {
|
|
29
|
+
if (enabled && typeof console !== "undefined") {
|
|
30
|
+
console.log("[ZPObserver/auto-patch]", ...args);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function resolveAndCallWindowPath(windowPath) {
|
|
34
|
+
const path = windowPath.replace(/^window\./, "").split(".");
|
|
35
|
+
let ref = window;
|
|
36
|
+
for (const part of path) {
|
|
37
|
+
if (ref && typeof ref === "object" && part in ref) {
|
|
38
|
+
ref = ref[part];
|
|
39
|
+
} else {
|
|
40
|
+
ref = void 0;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (typeof ref === "function") ref();
|
|
45
|
+
}
|
|
46
|
+
function wrapOptions(opts, shortcode, chainExisting) {
|
|
47
|
+
const next = { ...opts ?? {} };
|
|
48
|
+
const existing = next.onPluginClose;
|
|
49
|
+
if (chainExisting && existing != null) {
|
|
50
|
+
if (typeof window !== "undefined") {
|
|
51
|
+
const wrapperName = `__zpobs_chain_${Date.now().toString(36)}`;
|
|
52
|
+
window[wrapperName] = () => {
|
|
53
|
+
try {
|
|
54
|
+
if (typeof existing === "function") {
|
|
55
|
+
existing();
|
|
56
|
+
} else if (typeof existing === "string") {
|
|
57
|
+
resolveAndCallWindowPath(existing);
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
resolveAndCallWindowPath(shortcode);
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
next.onPluginClose = `window.${wrapperName}`;
|
|
67
|
+
return next;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
next.onPluginClose = shortcode;
|
|
71
|
+
return next;
|
|
72
|
+
}
|
|
73
|
+
function patchJQueryPlugin($, shortcode, chainExisting, debug, onInvoke) {
|
|
74
|
+
const original = $.fn.zpPayment;
|
|
75
|
+
if (typeof original !== "function" || original.__zpobsPatched) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const patched = function(opts) {
|
|
79
|
+
onInvoke();
|
|
80
|
+
return original.call(this, wrapOptions(opts, shortcode, chainExisting));
|
|
81
|
+
};
|
|
82
|
+
patched.__zpobsPatched = true;
|
|
83
|
+
$.fn.zpPayment = patched;
|
|
84
|
+
logDebug(debug, "patched $.fn.zpPayment");
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
function patchZenPayGlobal(shortcode, chainExisting, debug, onInvoke) {
|
|
88
|
+
const w = window;
|
|
89
|
+
const original = w.ZenPay;
|
|
90
|
+
if (typeof original !== "function" || original.__zpobsPatched) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const handler = {
|
|
94
|
+
construct(target, args) {
|
|
95
|
+
onInvoke();
|
|
96
|
+
const [first, ...rest] = args;
|
|
97
|
+
const wrapped = wrapOptions(first, shortcode, chainExisting);
|
|
98
|
+
return Reflect.construct(target, [wrapped, ...rest]);
|
|
99
|
+
},
|
|
100
|
+
apply(target, thisArg, args) {
|
|
101
|
+
onInvoke();
|
|
102
|
+
const [first, ...rest] = args;
|
|
103
|
+
const wrapped = wrapOptions(first, shortcode, chainExisting);
|
|
104
|
+
return Reflect.apply(target, thisArg, [
|
|
105
|
+
wrapped,
|
|
106
|
+
...rest
|
|
107
|
+
]);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const patched = new Proxy(original, handler);
|
|
111
|
+
patched.__zpobsPatched = true;
|
|
112
|
+
w.ZenPay = patched;
|
|
113
|
+
logDebug(debug, "patched window.ZenPay");
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
function installZenPayAutoPatch(observer, options = {}) {
|
|
117
|
+
if (typeof window === "undefined") {
|
|
118
|
+
return { uninstall() {
|
|
119
|
+
}, isPatched: () => false };
|
|
120
|
+
}
|
|
121
|
+
const pollIntervalMs = options.pollIntervalMs ?? 200;
|
|
122
|
+
const pollTimeoutMs = options.pollTimeoutMs ?? 3e4;
|
|
123
|
+
const chainExisting = options.chainExisting !== false;
|
|
124
|
+
const debug = options.debug === true;
|
|
125
|
+
let patched = false;
|
|
126
|
+
const shortcode = observer.shortcode;
|
|
127
|
+
const w = window;
|
|
128
|
+
const emitHppInit = () => {
|
|
129
|
+
observer.emit({
|
|
130
|
+
kind: "payment.hpp_init",
|
|
131
|
+
sessionId: observer.sessionId,
|
|
132
|
+
correlationId: observer.correlationId,
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
metadata: {}
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
const tryPatch = () => {
|
|
138
|
+
let didSomething = false;
|
|
139
|
+
const jq = w.jQuery ?? w.$;
|
|
140
|
+
if (jq && typeof jq === "object" && "fn" in jq) {
|
|
141
|
+
if (patchJQueryPlugin(jq, shortcode, chainExisting, debug, emitHppInit)) didSomething = true;
|
|
142
|
+
}
|
|
143
|
+
if ("ZenPay" in window) {
|
|
144
|
+
if (patchZenPayGlobal(shortcode, chainExisting, debug, emitHppInit)) didSomething = true;
|
|
145
|
+
}
|
|
146
|
+
if (didSomething) patched = true;
|
|
147
|
+
return didSomething;
|
|
148
|
+
};
|
|
149
|
+
tryPatch();
|
|
150
|
+
const startedAt = Date.now();
|
|
151
|
+
let pollTimer = setInterval(() => {
|
|
152
|
+
if (Date.now() - startedAt > pollTimeoutMs) {
|
|
153
|
+
if (pollTimer !== null) {
|
|
154
|
+
clearInterval(pollTimer);
|
|
155
|
+
pollTimer = null;
|
|
156
|
+
}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
tryPatch();
|
|
160
|
+
}, pollIntervalMs);
|
|
161
|
+
return {
|
|
162
|
+
uninstall() {
|
|
163
|
+
if (pollTimer !== null) {
|
|
164
|
+
clearInterval(pollTimer);
|
|
165
|
+
pollTimer = null;
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
isPatched: () => patched
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=auto-patch.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/auto-patch.ts", "../src/integration/zenpay-auto-patch.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * @ianmenethil/zp-observer/auto-patch \u2014 subpath entry\n *\n * Single export: installZenPayAutoPatch. Import via:\n * import { installZenPayAutoPatch } from '@ianmenethil/zp-observer/auto-patch';\n */\n\nexport { installZenPayAutoPatch } from './integration/zenpay-auto-patch.js';\nexport type { AutoPatchHandle, AutoPatchOptions } from './integration/zenpay-auto-patch.js';\n", "/**\n * ZenPay plugin auto-patch (v6).\n *\n * One-line integration: detects the ZenPay plugin and rewrites its\n * `onPluginClose` at invocation time to use our shortcode. Emits\n * `payment.hpp_init` domain events when the plugin is invoked so the\n * observer's event stream captures HPP lifecycle.\n *\n * Supports:\n * - v3: jQuery plugin `$.fn.zpPayment`\n * - v5: global `window.ZenPay` (class or factory)\n *\n * If neither is present at install time, we set a short-lived polling\n * watch (plugins are typically loaded via <script> before first payment).\n */\n\nimport type { Observer } from '../core/types.js';\n\ninterface JQueryLike {\n\tfn: { zpPayment?: unknown };\n}\n\ninterface ZPOptions {\n\tonPluginClose?: unknown;\n\t[key: string]: unknown;\n}\n\ntype PluginFn = (this: unknown, opts?: ZPOptions) => unknown;\n\nexport interface AutoPatchHandle {\n\tuninstall(): void;\n\tisPatched(): boolean;\n}\n\nexport interface AutoPatchOptions {\n\tpollIntervalMs?: number;\n\tpollTimeoutMs?: number;\n\tchainExisting?: boolean;\n\tdebug?: boolean;\n}\n\nfunction logDebug(enabled: boolean, ...args: unknown[]): void {\n\tif (enabled && typeof console !== 'undefined') {\n\t\tconsole.log('[ZPObserver/auto-patch]', ...args);\n\t}\n}\n\nfunction resolveAndCallWindowPath(windowPath: string): void {\n\tconst path = windowPath.replace(/^window\\./, '').split('.');\n\tlet ref: unknown = window;\n\tfor (const part of path) {\n\t\tif (ref && typeof ref === 'object' && part in ref) {\n\t\t\tref = (ref as Record<string, unknown>)[part];\n\t\t} else {\n\t\t\tref = undefined;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (typeof ref === 'function') (ref as () => void)();\n}\n\nfunction wrapOptions(\n\topts: ZPOptions | undefined,\n\tshortcode: string,\n\tchainExisting: boolean,\n): ZPOptions {\n\tconst next: ZPOptions = { ...(opts ?? {}) };\n\tconst existing = next.onPluginClose;\n\n\tif (chainExisting && existing != null) {\n\t\tif (typeof window !== 'undefined') {\n\t\t\tconst wrapperName = `__zpobs_chain_${Date.now().toString(36)}`;\n\t\t\t(window as unknown as Record<string, unknown>)[wrapperName] = () => {\n\t\t\t\ttry {\n\t\t\t\t\tif (typeof existing === 'function') {\n\t\t\t\t\t\t(existing as () => void)();\n\t\t\t\t\t} else if (typeof existing === 'string') {\n\t\t\t\t\t\tresolveAndCallWindowPath(existing);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tresolveAndCallWindowPath(shortcode);\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore\n\t\t\t\t}\n\t\t\t};\n\t\t\tnext.onPluginClose = `window.${wrapperName}`;\n\t\t\treturn next;\n\t\t}\n\t}\n\n\tnext.onPluginClose = shortcode;\n\treturn next;\n}\n\nfunction patchJQueryPlugin(\n\t$: JQueryLike,\n\tshortcode: string,\n\tchainExisting: boolean,\n\tdebug: boolean,\n\tonInvoke: () => void,\n): boolean {\n\tconst original = $.fn.zpPayment as PluginFn | undefined;\n\tif (typeof original !== 'function' || (original as { __zpobsPatched?: boolean }).__zpobsPatched) {\n\t\treturn false;\n\t}\n\n\tconst patched: PluginFn & { __zpobsPatched?: boolean } = function (\n\t\tthis: unknown,\n\t\topts?: ZPOptions,\n\t) {\n\t\tonInvoke();\n\t\treturn original.call(this, wrapOptions(opts, shortcode, chainExisting));\n\t};\n\tpatched.__zpobsPatched = true;\n\t$.fn.zpPayment = patched;\n\n\tlogDebug(debug, 'patched $.fn.zpPayment');\n\treturn true;\n}\n\nfunction patchZenPayGlobal(\n\tshortcode: string,\n\tchainExisting: boolean,\n\tdebug: boolean,\n\tonInvoke: () => void,\n): boolean {\n\tconst w = window as unknown as {\n\t\tZenPay?: (new (opts?: ZPOptions) => unknown) | ((opts?: ZPOptions) => unknown);\n\t};\n\tconst original = w.ZenPay;\n\tif (typeof original !== 'function' || (original as { __zpobsPatched?: boolean }).__zpobsPatched) {\n\t\treturn false;\n\t}\n\n\tconst handler: ProxyHandler<typeof original> = {\n\t\tconstruct(target, args) {\n\t\t\tonInvoke();\n\t\t\tconst [first, ...rest] = args as [ZPOptions | undefined, ...unknown[]];\n\t\t\tconst wrapped = wrapOptions(first, shortcode, chainExisting);\n\t\t\treturn Reflect.construct(target, [wrapped, ...rest]) as object;\n\t\t},\n\t\tapply(target, thisArg, args) {\n\t\t\tonInvoke();\n\t\t\tconst [first, ...rest] = args as [ZPOptions | undefined, ...unknown[]];\n\t\t\tconst wrapped = wrapOptions(first, shortcode, chainExisting);\n\t\t\treturn Reflect.apply(target as (...a: unknown[]) => unknown, thisArg, [\n\t\t\t\twrapped,\n\t\t\t\t...rest,\n\t\t\t]);\n\t\t},\n\t};\n\n\tconst patched = new Proxy(original, handler) as typeof original & {\n\t\t__zpobsPatched?: boolean;\n\t};\n\tpatched.__zpobsPatched = true;\n\tw.ZenPay = patched;\n\n\tlogDebug(debug, 'patched window.ZenPay');\n\treturn true;\n}\n\nexport function installZenPayAutoPatch(\n\tobserver: Pick<Observer, 'sessionId' | 'correlationId' | 'shortcode' | 'emit'>,\n\toptions: AutoPatchOptions = {},\n): AutoPatchHandle {\n\tif (typeof window === 'undefined') {\n\t\treturn { uninstall() {}, isPatched: () => false };\n\t}\n\n\tconst pollIntervalMs = options.pollIntervalMs ?? 200;\n\tconst pollTimeoutMs = options.pollTimeoutMs ?? 30_000;\n\tconst chainExisting = options.chainExisting !== false;\n\tconst debug = options.debug === true;\n\n\tlet patched = false;\n\tconst shortcode = observer.shortcode;\n\tconst w = window as unknown as { jQuery?: JQueryLike; $?: JQueryLike };\n\n\tconst emitHppInit = () => {\n\t\tobserver.emit({\n\t\t\tkind: 'payment.hpp_init',\n\t\t\tsessionId: observer.sessionId,\n\t\t\tcorrelationId: observer.correlationId,\n\t\t\ttimestamp: Date.now(),\n\t\t\tmetadata: {},\n\t\t});\n\t};\n\n\tconst tryPatch = (): boolean => {\n\t\tlet didSomething = false;\n\n\t\tconst jq = w.jQuery ?? w.$;\n\t\tif (jq && typeof jq === 'object' && 'fn' in jq) {\n\t\t\tif (patchJQueryPlugin(jq, shortcode, chainExisting, debug, emitHppInit)) didSomething = true;\n\t\t}\n\n\t\tif ('ZenPay' in window) {\n\t\t\tif (patchZenPayGlobal(shortcode, chainExisting, debug, emitHppInit)) didSomething = true;\n\t\t}\n\n\t\tif (didSomething) patched = true;\n\t\treturn didSomething;\n\t};\n\n\ttryPatch();\n\n\tconst startedAt = Date.now();\n\tlet pollTimer: ReturnType<typeof setInterval> | null = setInterval(() => {\n\t\tif (Date.now() - startedAt > pollTimeoutMs) {\n\t\t\tif (pollTimer !== null) {\n\t\t\t\tclearInterval(pollTimer);\n\t\t\t\tpollTimer = null;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\ttryPatch();\n\t}, pollIntervalMs);\n\n\treturn {\n\t\tuninstall() {\n\t\t\tif (pollTimer !== null) {\n\t\t\t\tclearInterval(pollTimer);\n\t\t\t\tpollTimer = null;\n\t\t\t}\n\t\t},\n\t\tisPatched: () => patched,\n\t};\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|