joopjs 2.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 (259) hide show
  1. package/CHANGELOG.md +678 -0
  2. package/README.md +583 -0
  3. package/dist/a11y.service-C-DQQfgO.d.mts +143 -0
  4. package/dist/a11y.service-CauEJrJe.d.ts +143 -0
  5. package/dist/adapters-B6slG6hQ.d.mts +84 -0
  6. package/dist/adapters-B6slG6hQ.d.ts +84 -0
  7. package/dist/aes.service-CkoupAww.d.mts +95 -0
  8. package/dist/aes.service-CkoupAww.d.ts +95 -0
  9. package/dist/ai/index.d.mts +99 -0
  10. package/dist/ai/index.d.ts +99 -0
  11. package/dist/ai/index.js +307 -0
  12. package/dist/ai/index.js.map +1 -0
  13. package/dist/ai/index.mjs +304 -0
  14. package/dist/ai/index.mjs.map +1 -0
  15. package/dist/analytics/index.d.mts +42 -0
  16. package/dist/analytics/index.d.ts +42 -0
  17. package/dist/analytics/index.js +139 -0
  18. package/dist/analytics/index.js.map +1 -0
  19. package/dist/analytics/index.mjs +136 -0
  20. package/dist/analytics/index.mjs.map +1 -0
  21. package/dist/angular/index.d.mts +148 -0
  22. package/dist/angular/index.d.ts +148 -0
  23. package/dist/angular/index.js +122 -0
  24. package/dist/angular/index.js.map +1 -0
  25. package/dist/angular/index.mjs +101 -0
  26. package/dist/angular/index.mjs.map +1 -0
  27. package/dist/api/index.d.mts +128 -0
  28. package/dist/api/index.d.ts +128 -0
  29. package/dist/api/index.js +1358 -0
  30. package/dist/api/index.js.map +1 -0
  31. package/dist/api/index.mjs +1332 -0
  32. package/dist/api/index.mjs.map +1 -0
  33. package/dist/auth/index.d.mts +105 -0
  34. package/dist/auth/index.d.ts +105 -0
  35. package/dist/auth/index.js +989 -0
  36. package/dist/auth/index.js.map +1 -0
  37. package/dist/auth/index.mjs +979 -0
  38. package/dist/auth/index.mjs.map +1 -0
  39. package/dist/auth.service-DNVB-L4U.d.mts +16 -0
  40. package/dist/auth.service-PjUUSUIt.d.ts +16 -0
  41. package/dist/banking/index.d.mts +1530 -0
  42. package/dist/banking/index.d.ts +1530 -0
  43. package/dist/banking/index.js +4739 -0
  44. package/dist/banking/index.js.map +1 -0
  45. package/dist/banking/index.mjs +4661 -0
  46. package/dist/banking/index.mjs.map +1 -0
  47. package/dist/cache/index.d.mts +40 -0
  48. package/dist/cache/index.d.ts +40 -0
  49. package/dist/cache/index.js +174 -0
  50. package/dist/cache/index.js.map +1 -0
  51. package/dist/cache/index.mjs +172 -0
  52. package/dist/cache/index.mjs.map +1 -0
  53. package/dist/client-profile.service-BuPeXVp5.d.mts +28 -0
  54. package/dist/client-profile.service-D5bRRYQp.d.ts +28 -0
  55. package/dist/config.models-Cqg04fAQ.d.mts +84 -0
  56. package/dist/config.models-Cqg04fAQ.d.ts +84 -0
  57. package/dist/config.service-CrCvI-JS.d.ts +31 -0
  58. package/dist/config.service-Cz4QQLlf.d.mts +31 -0
  59. package/dist/core/index.d.mts +4 -0
  60. package/dist/core/index.d.ts +4 -0
  61. package/dist/core/index.js +631 -0
  62. package/dist/core/index.js.map +1 -0
  63. package/dist/core/index.mjs +619 -0
  64. package/dist/core/index.mjs.map +1 -0
  65. package/dist/crypto-utils-DriNhLdx.d.mts +30 -0
  66. package/dist/crypto-utils-DriNhLdx.d.ts +30 -0
  67. package/dist/data-storage.service-DT6xaTxE.d.ts +51 -0
  68. package/dist/data-storage.service-LvhGRCmw.d.mts +51 -0
  69. package/dist/deeplink/index.d.mts +39 -0
  70. package/dist/deeplink/index.d.ts +39 -0
  71. package/dist/deeplink/index.js +268 -0
  72. package/dist/deeplink/index.js.map +1 -0
  73. package/dist/deeplink/index.mjs +265 -0
  74. package/dist/deeplink/index.mjs.map +1 -0
  75. package/dist/deeplink.service-Ctd5u243.d.mts +35 -0
  76. package/dist/deeplink.service-uUuTnY9_.d.ts +35 -0
  77. package/dist/dev/index.d.mts +20 -0
  78. package/dist/dev/index.d.ts +20 -0
  79. package/dist/dev/index.js +51 -0
  80. package/dist/dev/index.js.map +1 -0
  81. package/dist/dev/index.mjs +49 -0
  82. package/dist/dev/index.mjs.map +1 -0
  83. package/dist/device/index.d.mts +108 -0
  84. package/dist/device/index.d.ts +108 -0
  85. package/dist/device/index.js +960 -0
  86. package/dist/device/index.js.map +1 -0
  87. package/dist/device/index.mjs +951 -0
  88. package/dist/device/index.mjs.map +1 -0
  89. package/dist/differential-privacy-BcAv1G80.d.mts +210 -0
  90. package/dist/differential-privacy-C8mAUjZr.d.ts +210 -0
  91. package/dist/encryption/index.d.mts +75 -0
  92. package/dist/encryption/index.d.ts +75 -0
  93. package/dist/encryption/index.js +605 -0
  94. package/dist/encryption/index.js.map +1 -0
  95. package/dist/encryption/index.mjs +598 -0
  96. package/dist/encryption/index.mjs.map +1 -0
  97. package/dist/form-validator-3tkmzr_o.d.mts +72 -0
  98. package/dist/form-validator-3tkmzr_o.d.ts +72 -0
  99. package/dist/forms/index.d.mts +59 -0
  100. package/dist/forms/index.d.ts +59 -0
  101. package/dist/forms/index.js +446 -0
  102. package/dist/forms/index.js.map +1 -0
  103. package/dist/forms/index.mjs +442 -0
  104. package/dist/forms/index.mjs.map +1 -0
  105. package/dist/i18n/index.d.mts +37 -0
  106. package/dist/i18n/index.d.ts +37 -0
  107. package/dist/i18n/index.js +147 -0
  108. package/dist/i18n/index.js.map +1 -0
  109. package/dist/i18n/index.mjs +145 -0
  110. package/dist/i18n/index.mjs.map +1 -0
  111. package/dist/idempotency.service-_6LqhivP.d.mts +372 -0
  112. package/dist/idempotency.service-eOKoISRD.d.ts +372 -0
  113. package/dist/index-B_ksKpS1.d.mts +202 -0
  114. package/dist/index-CqDKWTUP.d.mts +28 -0
  115. package/dist/index-CqDKWTUP.d.ts +28 -0
  116. package/dist/index-DFqEoX_l.d.ts +202 -0
  117. package/dist/index-Dz0gOur2.d.mts +36 -0
  118. package/dist/index-Dz0gOur2.d.ts +36 -0
  119. package/dist/index.d.mts +1336 -0
  120. package/dist/index.d.ts +1336 -0
  121. package/dist/index.js +19464 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/index.mjs +19155 -0
  124. package/dist/index.mjs.map +1 -0
  125. package/dist/india/index.d.mts +75 -0
  126. package/dist/india/index.d.ts +75 -0
  127. package/dist/india/index.js +325 -0
  128. package/dist/india/index.js.map +1 -0
  129. package/dist/india/index.mjs +303 -0
  130. package/dist/india/index.mjs.map +1 -0
  131. package/dist/joop-Bx7Iwj5p.d.mts +155 -0
  132. package/dist/joop-CA3DMeOO.d.ts +155 -0
  133. package/dist/native-bridge/index.d.mts +27 -0
  134. package/dist/native-bridge/index.d.ts +27 -0
  135. package/dist/native-bridge/index.js +98 -0
  136. package/dist/native-bridge/index.js.map +1 -0
  137. package/dist/native-bridge/index.mjs +96 -0
  138. package/dist/native-bridge/index.mjs.map +1 -0
  139. package/dist/network/index.d.mts +85 -0
  140. package/dist/network/index.d.ts +85 -0
  141. package/dist/network/index.js +454 -0
  142. package/dist/network/index.js.map +1 -0
  143. package/dist/network/index.mjs +451 -0
  144. package/dist/network/index.mjs.map +1 -0
  145. package/dist/network-monitor-BIwPSXme.d.mts +179 -0
  146. package/dist/network-monitor-Bqp2hvZr.d.ts +179 -0
  147. package/dist/notification.service-Dm4fvfZf.d.mts +25 -0
  148. package/dist/notification.service-tEMKatWJ.d.ts +25 -0
  149. package/dist/observability/index.d.mts +179 -0
  150. package/dist/observability/index.d.ts +179 -0
  151. package/dist/observability/index.js +559 -0
  152. package/dist/observability/index.js.map +1 -0
  153. package/dist/observability/index.mjs +552 -0
  154. package/dist/observability/index.mjs.map +1 -0
  155. package/dist/oidc-client-DIJcClmB.d.mts +190 -0
  156. package/dist/oidc-client-DxhyE59t.d.ts +190 -0
  157. package/dist/platform/index.d.mts +73 -0
  158. package/dist/platform/index.d.ts +73 -0
  159. package/dist/platform/index.js +127 -0
  160. package/dist/platform/index.js.map +1 -0
  161. package/dist/platform/index.mjs +125 -0
  162. package/dist/platform/index.mjs.map +1 -0
  163. package/dist/pwa/index.d.mts +31 -0
  164. package/dist/pwa/index.d.ts +31 -0
  165. package/dist/pwa/index.js +247 -0
  166. package/dist/pwa/index.js.map +1 -0
  167. package/dist/pwa/index.mjs +244 -0
  168. package/dist/pwa/index.mjs.map +1 -0
  169. package/dist/react/index.d.mts +133 -0
  170. package/dist/react/index.d.ts +133 -0
  171. package/dist/react/index.js +632 -0
  172. package/dist/react/index.js.map +1 -0
  173. package/dist/react/index.mjs +630 -0
  174. package/dist/react/index.mjs.map +1 -0
  175. package/dist/router/index.d.mts +39 -0
  176. package/dist/router/index.d.ts +39 -0
  177. package/dist/router/index.js +168 -0
  178. package/dist/router/index.js.map +1 -0
  179. package/dist/router/index.mjs +166 -0
  180. package/dist/router/index.mjs.map +1 -0
  181. package/dist/security/index.d.mts +206 -0
  182. package/dist/security/index.d.ts +206 -0
  183. package/dist/security/index.js +1297 -0
  184. package/dist/security/index.js.map +1 -0
  185. package/dist/security/index.mjs +1285 -0
  186. package/dist/security/index.mjs.map +1 -0
  187. package/dist/session/index.d.mts +115 -0
  188. package/dist/session/index.d.ts +115 -0
  189. package/dist/session/index.js +297 -0
  190. package/dist/session/index.js.map +1 -0
  191. package/dist/session/index.mjs +292 -0
  192. package/dist/session/index.mjs.map +1 -0
  193. package/dist/state/index.d.mts +43 -0
  194. package/dist/state/index.d.ts +43 -0
  195. package/dist/state/index.js +156 -0
  196. package/dist/state/index.js.map +1 -0
  197. package/dist/state/index.mjs +152 -0
  198. package/dist/state/index.mjs.map +1 -0
  199. package/dist/statement-parser-BHQtXwCM.d.ts +260 -0
  200. package/dist/statement-parser-C2qNmb49.d.mts +260 -0
  201. package/dist/storage/index.d.mts +40 -0
  202. package/dist/storage/index.d.ts +40 -0
  203. package/dist/storage/index.js +256 -0
  204. package/dist/storage/index.js.map +1 -0
  205. package/dist/storage/index.mjs +252 -0
  206. package/dist/storage/index.mjs.map +1 -0
  207. package/dist/sync/index.d.mts +69 -0
  208. package/dist/sync/index.d.ts +69 -0
  209. package/dist/sync/index.js +330 -0
  210. package/dist/sync/index.js.map +1 -0
  211. package/dist/sync/index.mjs +323 -0
  212. package/dist/sync/index.mjs.map +1 -0
  213. package/dist/sync-engine-DCIMRG5s.d.ts +61 -0
  214. package/dist/sync-engine-DZqyKHkK.d.mts +61 -0
  215. package/dist/theme/index.d.mts +53 -0
  216. package/dist/theme/index.d.ts +53 -0
  217. package/dist/theme/index.js +169 -0
  218. package/dist/theme/index.js.map +1 -0
  219. package/dist/theme/index.mjs +167 -0
  220. package/dist/theme/index.mjs.map +1 -0
  221. package/dist/ui/index.d.mts +66 -0
  222. package/dist/ui/index.d.ts +66 -0
  223. package/dist/ui/index.js +811 -0
  224. package/dist/ui/index.js.map +1 -0
  225. package/dist/ui/index.mjs +803 -0
  226. package/dist/ui/index.mjs.map +1 -0
  227. package/dist/utilities/index.d.mts +199 -0
  228. package/dist/utilities/index.d.ts +199 -0
  229. package/dist/utilities/index.js +1991 -0
  230. package/dist/utilities/index.js.map +1 -0
  231. package/dist/utilities/index.mjs +1923 -0
  232. package/dist/utilities/index.mjs.map +1 -0
  233. package/dist/validation/index.d.mts +60 -0
  234. package/dist/validation/index.d.ts +60 -0
  235. package/dist/validation/index.js +460 -0
  236. package/dist/validation/index.js.map +1 -0
  237. package/dist/validation/index.mjs +455 -0
  238. package/dist/validation/index.mjs.map +1 -0
  239. package/dist/vue/index.d.mts +135 -0
  240. package/dist/vue/index.d.ts +135 -0
  241. package/dist/vue/index.js +621 -0
  242. package/dist/vue/index.js.map +1 -0
  243. package/dist/vue/index.mjs +619 -0
  244. package/dist/vue/index.mjs.map +1 -0
  245. package/dist/watermark.service-Detur5tq.d.ts +235 -0
  246. package/dist/watermark.service-QNegMeQZ.d.mts +235 -0
  247. package/dist/workers/index.d.mts +42 -0
  248. package/dist/workers/index.d.ts +42 -0
  249. package/dist/workers/index.js +359 -0
  250. package/dist/workers/index.js.map +1 -0
  251. package/dist/workers/index.mjs +356 -0
  252. package/dist/workers/index.mjs.map +1 -0
  253. package/dist/workflow/index.d.mts +99 -0
  254. package/dist/workflow/index.d.ts +99 -0
  255. package/dist/workflow/index.js +282 -0
  256. package/dist/workflow/index.js.map +1 -0
  257. package/dist/workflow/index.mjs +279 -0
  258. package/dist/workflow/index.mjs.map +1 -0
  259. package/package.json +226 -0
@@ -0,0 +1,552 @@
1
+ // src/events/index.ts
2
+ var JoopSubject = class {
3
+ _listeners = [];
4
+ subscribe(listener) {
5
+ this._listeners.push(listener);
6
+ return () => {
7
+ this._listeners = this._listeners.filter((l) => l !== listener);
8
+ };
9
+ }
10
+ next(value) {
11
+ for (const listener of this._listeners) {
12
+ listener(value);
13
+ }
14
+ }
15
+ asObservable() {
16
+ return new JoopObservable((listener) => this.subscribe(listener));
17
+ }
18
+ };
19
+ var JoopBehaviorSubject = class extends JoopSubject {
20
+ _value;
21
+ constructor(initialValue) {
22
+ super();
23
+ this._value = initialValue;
24
+ }
25
+ getValue() {
26
+ return this._value;
27
+ }
28
+ next(value) {
29
+ this._value = value;
30
+ super.next(value);
31
+ }
32
+ subscribe(listener) {
33
+ listener(this._value);
34
+ return super.subscribe(listener);
35
+ }
36
+ asObservable() {
37
+ return new JoopObservable((listener) => this.subscribe(listener));
38
+ }
39
+ };
40
+ var JoopObservable = class {
41
+ constructor(_subscribeFn) {
42
+ this._subscribeFn = _subscribeFn;
43
+ }
44
+ _subscribeFn;
45
+ subscribe(listener) {
46
+ return this._subscribeFn(listener);
47
+ }
48
+ /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */
49
+ getOnce() {
50
+ let result;
51
+ const unsub = this.subscribe((v) => {
52
+ result = v;
53
+ });
54
+ unsub();
55
+ return result;
56
+ }
57
+ };
58
+
59
+ // src/observability/web-vitals.ts
60
+ var THRESHOLDS = {
61
+ lcp: [2500, 4e3],
62
+ fid: [100, 300],
63
+ inp: [200, 500],
64
+ cls: [0.1, 0.25],
65
+ ttfb: [800, 1800],
66
+ fcp: [1800, 3e3]
67
+ };
68
+ var JoopWebVitals = class {
69
+ _vitals = {};
70
+ _vitals$ = new JoopSubject();
71
+ _snapshot$ = new JoopBehaviorSubject(this._buildSnapshot());
72
+ _observers = [];
73
+ _running = false;
74
+ start() {
75
+ if (this._running || typeof PerformanceObserver === "undefined") return;
76
+ this._running = true;
77
+ this._observeLCP();
78
+ this._observeFID();
79
+ this._observeINP();
80
+ this._observeCLS();
81
+ this._observeTTFB();
82
+ this._observeFCP();
83
+ }
84
+ stop() {
85
+ this._running = false;
86
+ for (const obs of this._observers) {
87
+ try {
88
+ obs.disconnect();
89
+ } catch {
90
+ }
91
+ }
92
+ this._observers = [];
93
+ }
94
+ snapshot() {
95
+ return this._buildSnapshot();
96
+ }
97
+ vitals$() {
98
+ return this._vitals$.asObservable();
99
+ }
100
+ snapshot$() {
101
+ return this._snapshot$.asObservable();
102
+ }
103
+ getLCP() {
104
+ return this._vitals.lcp ?? null;
105
+ }
106
+ getCLS() {
107
+ return this._vitals.cls ?? null;
108
+ }
109
+ getINP() {
110
+ return this._vitals.inp ?? null;
111
+ }
112
+ getTTFB() {
113
+ return this._vitals.ttfb ?? null;
114
+ }
115
+ getFCP() {
116
+ return this._vitals.fcp ?? null;
117
+ }
118
+ getFID() {
119
+ return this._vitals.fid ?? null;
120
+ }
121
+ getRating(metric) {
122
+ const value = this._vitals[metric];
123
+ return _rate(metric, value ?? null);
124
+ }
125
+ _record(metric, value) {
126
+ this._vitals[metric] = value;
127
+ const rating = _rate(metric, value);
128
+ this._vitals$.next({ metric, value, rating });
129
+ this._snapshot$.next(this._buildSnapshot());
130
+ }
131
+ _observe(types, callback) {
132
+ try {
133
+ const obs = new PerformanceObserver(callback);
134
+ obs.observe({ type: types[0], buffered: true });
135
+ this._observers.push(obs);
136
+ } catch {
137
+ }
138
+ }
139
+ _observeLCP() {
140
+ this._observe(["largest-contentful-paint"], (list) => {
141
+ const entries = list.getEntries();
142
+ if (entries.length) this._record("lcp", entries[entries.length - 1].renderTime || entries[entries.length - 1].loadTime || entries[entries.length - 1].startTime);
143
+ });
144
+ }
145
+ _observeFID() {
146
+ this._observe(["first-input"], (list) => {
147
+ const e = list.getEntries()[0];
148
+ if (e && e.processingStart) this._record("fid", e.processingStart - e.startTime);
149
+ });
150
+ }
151
+ _observeINP() {
152
+ this._observe(["event"], (list) => {
153
+ let max = this._vitals.inp ?? 0;
154
+ for (const e of list.getEntries()) {
155
+ const entry = e;
156
+ if (entry.processingEnd) max = Math.max(max, entry.processingEnd - entry.startTime);
157
+ }
158
+ if (max > 0) this._record("inp", max);
159
+ });
160
+ }
161
+ _observeCLS() {
162
+ let clsValue = 0;
163
+ let sessionStart = 0;
164
+ let lastEntry = 0;
165
+ this._observe(["layout-shift"], (list) => {
166
+ for (const e of list.getEntries()) {
167
+ const entry = e;
168
+ if (entry.hadRecentInput) continue;
169
+ if (lastEntry > 0 && entry.startTime - lastEntry > 1e3) {
170
+ if (entry.startTime - sessionStart > 5e3) {
171
+ clsValue = 0;
172
+ sessionStart = entry.startTime;
173
+ }
174
+ }
175
+ if (lastEntry === 0) sessionStart = entry.startTime;
176
+ clsValue += entry.value ?? 0;
177
+ lastEntry = entry.startTime;
178
+ this._record("cls", clsValue);
179
+ }
180
+ });
181
+ }
182
+ _observeTTFB() {
183
+ const nav = performance.getEntriesByType?.("navigation")?.[0];
184
+ if (nav?.responseStart) this._record("ttfb", nav.responseStart);
185
+ this._observe(["navigation"], (list) => {
186
+ const e = list.getEntries()[0];
187
+ if (e?.responseStart) this._record("ttfb", e.responseStart);
188
+ });
189
+ }
190
+ _observeFCP() {
191
+ this._observe(["paint"], (list) => {
192
+ const e = list.getEntries().find((e2) => e2.name === "first-contentful-paint");
193
+ if (e) this._record("fcp", e.startTime);
194
+ });
195
+ }
196
+ _buildSnapshot() {
197
+ return {
198
+ lcp: this._vitals.lcp ?? null,
199
+ fid: this._vitals.fid ?? null,
200
+ inp: this._vitals.inp ?? null,
201
+ cls: this._vitals.cls ?? null,
202
+ ttfb: this._vitals.ttfb ?? null,
203
+ fcp: this._vitals.fcp ?? null,
204
+ capturedAt: Date.now()
205
+ };
206
+ }
207
+ };
208
+ function _rate(metric, value) {
209
+ if (value === null) return "good";
210
+ const [good, poor] = THRESHOLDS[metric] ?? [Infinity, Infinity];
211
+ return value <= good ? "good" : value <= poor ? "needs-improvement" : "poor";
212
+ }
213
+
214
+ // src/observability/session-recorder.ts
215
+ var JoopSessionRecorder = class {
216
+ _events = [];
217
+ _running = false;
218
+ _paused = false;
219
+ _startedAt = 0;
220
+ _opts = {
221
+ maskSelectors: [],
222
+ ignoreSelectors: [],
223
+ redactInputs: true,
224
+ maxEvents: 1e4,
225
+ captureScroll: true,
226
+ captureResize: true
227
+ };
228
+ _cleanup = [];
229
+ _mutationObserver = null;
230
+ _scrollTimer = null;
231
+ start(options = {}) {
232
+ if (this._running) return;
233
+ this._opts = { ...this._opts, ...options };
234
+ this._running = true;
235
+ this._paused = false;
236
+ this._events = [];
237
+ this._startedAt = Date.now();
238
+ this._attachListeners();
239
+ }
240
+ pause() {
241
+ this._paused = true;
242
+ }
243
+ resume() {
244
+ this._paused = false;
245
+ }
246
+ stop() {
247
+ this._running = false;
248
+ this._paused = false;
249
+ this._detach();
250
+ return {
251
+ startedAt: this._startedAt,
252
+ stoppedAt: Date.now(),
253
+ events: [...this._events],
254
+ url: typeof location !== "undefined" ? location.href : "",
255
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : ""
256
+ };
257
+ }
258
+ events() {
259
+ return [...this._events];
260
+ }
261
+ export(format = "json") {
262
+ const record = {
263
+ startedAt: this._startedAt,
264
+ stoppedAt: Date.now(),
265
+ events: this._events,
266
+ url: typeof location !== "undefined" ? location.href : "",
267
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : ""
268
+ };
269
+ const json = JSON.stringify(record);
270
+ if (format === "compressed") {
271
+ try {
272
+ return btoa(json);
273
+ } catch {
274
+ return json;
275
+ }
276
+ }
277
+ return json;
278
+ }
279
+ addEvent(type, data) {
280
+ this._push({ type, timestamp: Date.now(), data });
281
+ }
282
+ _push(event) {
283
+ if (!this._running || this._paused) return;
284
+ if (this._events.length >= this._opts.maxEvents) this._events.shift();
285
+ this._events.push(event);
286
+ }
287
+ _attachListeners() {
288
+ this._mutationObserver = new MutationObserver((mutations) => {
289
+ for (const m of mutations) {
290
+ if (this._shouldIgnore(m.target)) continue;
291
+ this._push({ type: "dom-mutation", timestamp: Date.now(), selector: _selector(m.target), data: { addedNodes: m.addedNodes.length, removedNodes: m.removedNodes.length, type: m.type } });
292
+ }
293
+ });
294
+ this._mutationObserver.observe(document.documentElement, { childList: true, subtree: true, attributes: true, characterData: false, attributeFilter: ["class", "style", "hidden", "disabled"] });
295
+ const onClick = (e) => {
296
+ const el = e.target;
297
+ if (this._shouldIgnore(el)) return;
298
+ this._push({ type: "click", timestamp: Date.now(), selector: _selector(el) });
299
+ };
300
+ document.addEventListener("click", onClick, { capture: true });
301
+ this._cleanup.push(() => document.removeEventListener("click", onClick, { capture: true }));
302
+ const onInput = (e) => {
303
+ const el = e.target;
304
+ if (this._shouldIgnore(el)) return;
305
+ const redact = this._opts.redactInputs && (el.type === "password" || el.dataset?.pii !== void 0 || this._opts.maskSelectors.some((s) => el.matches(s)));
306
+ this._push({ type: "input", timestamp: Date.now(), selector: _selector(el), value: redact ? "***" : void 0 });
307
+ };
308
+ document.addEventListener("input", onInput, { capture: true });
309
+ this._cleanup.push(() => document.removeEventListener("input", onInput, { capture: true }));
310
+ if (this._opts.captureScroll) {
311
+ const onScroll = () => {
312
+ if (this._scrollTimer) return;
313
+ this._scrollTimer = setTimeout(() => {
314
+ this._scrollTimer = null;
315
+ this._push({ type: "scroll", timestamp: Date.now(), data: { x: window.scrollX, y: window.scrollY } });
316
+ }, 250);
317
+ };
318
+ window.addEventListener("scroll", onScroll, { passive: true });
319
+ this._cleanup.push(() => window.removeEventListener("scroll", onScroll));
320
+ }
321
+ if (this._opts.captureResize) {
322
+ let resizeTimer = null;
323
+ const onResize = () => {
324
+ if (resizeTimer) return;
325
+ resizeTimer = setTimeout(() => {
326
+ resizeTimer = null;
327
+ this._push({ type: "resize", timestamp: Date.now(), data: { w: window.innerWidth, h: window.innerHeight } });
328
+ }, 250);
329
+ };
330
+ window.addEventListener("resize", onResize, { passive: true });
331
+ this._cleanup.push(() => window.removeEventListener("resize", onResize));
332
+ }
333
+ const onPop = () => this._push({ type: "navigation", timestamp: Date.now(), data: { url: location.href } });
334
+ window.addEventListener("popstate", onPop);
335
+ this._cleanup.push(() => window.removeEventListener("popstate", onPop));
336
+ }
337
+ _detach() {
338
+ this._mutationObserver?.disconnect();
339
+ this._mutationObserver = null;
340
+ for (const fn of this._cleanup) fn();
341
+ this._cleanup = [];
342
+ }
343
+ _shouldIgnore(el) {
344
+ if (!el) return false;
345
+ return this._opts.ignoreSelectors.some((s) => {
346
+ try {
347
+ return el.matches?.(s);
348
+ } catch {
349
+ return false;
350
+ }
351
+ });
352
+ }
353
+ };
354
+ function _selector(el) {
355
+ if (!el) return "";
356
+ const parts = [];
357
+ let current = el;
358
+ while (current && current !== document.body && parts.length < 4) {
359
+ let part = current.tagName.toLowerCase();
360
+ if (current.id) {
361
+ parts.unshift(`#${current.id}`);
362
+ break;
363
+ }
364
+ if (current.className) part += "." + Array.from(current.classList).slice(0, 2).join(".");
365
+ parts.unshift(part);
366
+ current = current.parentElement;
367
+ }
368
+ return parts.join(" > ");
369
+ }
370
+
371
+ // src/observability/correlation.service.ts
372
+ var JoopCorrelationService = class {
373
+ _correlationId = "";
374
+ _requestId = "";
375
+ newCorrelation() {
376
+ this._correlationId = crypto.randomUUID();
377
+ return this._correlationId;
378
+ }
379
+ newRequest() {
380
+ this._requestId = crypto.randomUUID();
381
+ return this._requestId;
382
+ }
383
+ getCorrelationId() {
384
+ return this._correlationId;
385
+ }
386
+ getRequestId() {
387
+ return this._requestId;
388
+ }
389
+ headers() {
390
+ const h = {};
391
+ if (this._correlationId) h["X-Correlation-ID"] = this._correlationId;
392
+ if (this._requestId) h["X-Request-ID"] = this._requestId;
393
+ return h;
394
+ }
395
+ clear() {
396
+ this._correlationId = "";
397
+ this._requestId = "";
398
+ }
399
+ };
400
+
401
+ // src/observability/audit-log.service.ts
402
+ var JoopAuditLog = class {
403
+ constructor(_maxEntries = 500) {
404
+ this._maxEntries = _maxEntries;
405
+ }
406
+ _maxEntries;
407
+ _entries = [];
408
+ _listeners = [];
409
+ record(action, options = {}) {
410
+ const entry = {
411
+ id: crypto.randomUUID(),
412
+ action,
413
+ timestamp: Date.now(),
414
+ success: options.success ?? true,
415
+ ...options
416
+ };
417
+ this._entries.push(entry);
418
+ if (this._entries.length > this._maxEntries) this._entries = this._entries.slice(-this._maxEntries);
419
+ this._listeners.forEach((l) => l(entry));
420
+ return entry;
421
+ }
422
+ getAll() {
423
+ return [...this._entries];
424
+ }
425
+ getByAction(action) {
426
+ return this._entries.filter((e) => e.action === action);
427
+ }
428
+ getBySession(sessionId) {
429
+ return this._entries.filter((e) => e.sessionId === sessionId);
430
+ }
431
+ getByUser(userId) {
432
+ return this._entries.filter((e) => e.userId === userId);
433
+ }
434
+ onRecord(listener) {
435
+ this._listeners.push(listener);
436
+ return () => {
437
+ this._listeners = this._listeners.filter((l) => l !== listener);
438
+ };
439
+ }
440
+ clear() {
441
+ this._entries = [];
442
+ }
443
+ export() {
444
+ return JSON.stringify(this._entries, null, 2);
445
+ }
446
+ };
447
+
448
+ // src/observability/performance.service.ts
449
+ var JoopPerformanceService = class {
450
+ _marks = /* @__PURE__ */ new Map();
451
+ _completed = [];
452
+ mark(name, metadata) {
453
+ this._marks.set(name, { name, startTime: performance.now(), metadata });
454
+ }
455
+ measure(name) {
456
+ const mark = this._marks.get(name);
457
+ if (!mark) return null;
458
+ const endTime = performance.now();
459
+ const entry = { ...mark, endTime, duration: endTime - mark.startTime };
460
+ this._marks.delete(name);
461
+ this._completed.push(entry);
462
+ return entry;
463
+ }
464
+ async timeAsync(name, fn) {
465
+ this.mark(name);
466
+ try {
467
+ const result = await fn();
468
+ this.measure(name);
469
+ return result;
470
+ } catch (err) {
471
+ this.measure(name);
472
+ throw err;
473
+ }
474
+ }
475
+ timeSync(name, fn) {
476
+ this.mark(name);
477
+ try {
478
+ const result = fn();
479
+ this.measure(name);
480
+ return result;
481
+ } catch (err) {
482
+ this.measure(name);
483
+ throw err;
484
+ }
485
+ }
486
+ getCompleted() {
487
+ return [...this._completed];
488
+ }
489
+ getByName(name) {
490
+ return this._completed.filter((m) => m.name === name);
491
+ }
492
+ getAverage(name) {
493
+ const entries = this._completed.filter((m) => m.name === name && m.duration !== void 0);
494
+ if (!entries.length) return null;
495
+ return entries.reduce((sum, m) => sum + m.duration, 0) / entries.length;
496
+ }
497
+ clear() {
498
+ this._marks.clear();
499
+ this._completed = [];
500
+ }
501
+ };
502
+
503
+ // src/observability/error-reporter.service.ts
504
+ var JoopErrorReporter = class {
505
+ _handlers = [];
506
+ _userId = "";
507
+ _sessionId = "";
508
+ _context = {};
509
+ setUser(userId) {
510
+ this._userId = userId;
511
+ }
512
+ setSession(sessionId) {
513
+ this._sessionId = sessionId;
514
+ }
515
+ setContext(ctx) {
516
+ this._context = { ...this._context, ...ctx };
517
+ }
518
+ addHandler(handler) {
519
+ this._handlers.push(handler);
520
+ return () => {
521
+ this._handlers = this._handlers.filter((h) => h !== handler);
522
+ };
523
+ }
524
+ capture(error, extra) {
525
+ const err = error instanceof Error ? error : new Error(String(error));
526
+ const report = {
527
+ id: crypto.randomUUID(),
528
+ message: err.message,
529
+ stack: err.stack,
530
+ context: { ...this._context, ...extra },
531
+ timestamp: Date.now(),
532
+ ...this._userId ? { userId: this._userId } : {},
533
+ ...this._sessionId ? { sessionId: this._sessionId } : {}
534
+ };
535
+ this._handlers.forEach((h) => Promise.resolve(h(report)).catch(() => {
536
+ }));
537
+ return report;
538
+ }
539
+ captureMessage(message, extra) {
540
+ return this.capture(new Error(message), extra);
541
+ }
542
+ clear() {
543
+ this._handlers = [];
544
+ this._userId = "";
545
+ this._sessionId = "";
546
+ this._context = {};
547
+ }
548
+ };
549
+
550
+ export { JoopAuditLog, JoopCorrelationService, JoopErrorReporter, JoopPerformanceService, JoopSessionRecorder, JoopWebVitals };
551
+ //# sourceMappingURL=index.mjs.map
552
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/events/index.ts","../../src/observability/web-vitals.ts","../../src/observability/session-recorder.ts","../../src/observability/correlation.service.ts","../../src/observability/audit-log.service.ts","../../src/observability/performance.service.ts","../../src/observability/error-reporter.service.ts"],"names":["e"],"mappings":"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","file":"index.mjs","sourcesContent":["export type Unsubscribe = () => void;\nexport type Listener<T> = (value: T) => void;\n\n/**\n * Lightweight pub/sub subject — emits to all current subscribers.\n * Replaces RxJS Subject without pulling in the full RxJS dependency.\n */\nexport class JoopSubject<T> {\n private _listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>): Unsubscribe {\n this._listeners.push(listener);\n return () => {\n this._listeners = this._listeners.filter(l => l !== listener);\n };\n }\n\n next(value: T): void {\n for (const listener of this._listeners) {\n listener(value);\n }\n }\n\n asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Stateful subject — replays the current value to any new subscriber immediately.\n * Replaces RxJS BehaviorSubject.\n */\nexport class JoopBehaviorSubject<T> extends JoopSubject<T> {\n private _value: T;\n\n constructor(initialValue: T) {\n super();\n this._value = initialValue;\n }\n\n getValue(): T {\n return this._value;\n }\n\n override next(value: T): void {\n this._value = value;\n super.next(value);\n }\n\n override subscribe(listener: Listener<T>): Unsubscribe {\n listener(this._value);\n return super.subscribe(listener);\n }\n\n override asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Read-only observable handle returned from asObservable().\n */\nexport class JoopObservable<T> {\n constructor(private _subscribeFn: (listener: Listener<T>) => Unsubscribe) {}\n\n subscribe(listener: Listener<T>): Unsubscribe {\n return this._subscribeFn(listener);\n }\n\n /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */\n getOnce(): T | undefined {\n let result: T | undefined;\n const unsub = this.subscribe(v => { result = v; });\n unsub();\n return result;\n }\n}\n","import { JoopBehaviorSubject, JoopSubject } from '../events';\n\nexport interface JoopVitalsSnapshot {\n lcp: number | null; // Largest Contentful Paint (ms)\n fid: number | null; // First Input Delay (ms) — deprecated, use INP\n inp: number | null; // Interaction to Next Paint (ms)\n cls: number | null; // Cumulative Layout Shift (score)\n ttfb: number | null; // Time to First Byte (ms)\n fcp: number | null; // First Contentful Paint (ms)\n capturedAt: number;\n}\n\nexport interface JoopVitalUpdate {\n metric: keyof Omit<JoopVitalsSnapshot, 'capturedAt'>;\n value: number;\n rating: 'good' | 'needs-improvement' | 'poor';\n}\n\n// Thresholds per https://web.dev/vitals/\nconst THRESHOLDS: Record<string, [number, number]> = {\n lcp: [2500, 4000],\n fid: [100, 300],\n inp: [200, 500],\n cls: [0.1, 0.25],\n ttfb: [800, 1800],\n fcp: [1800, 3000],\n};\n\nexport class JoopWebVitals {\n private _vitals: Partial<JoopVitalsSnapshot> = {};\n private _vitals$ = new JoopSubject<JoopVitalUpdate>();\n private _snapshot$ = new JoopBehaviorSubject<JoopVitalsSnapshot>(this._buildSnapshot());\n private _observers: PerformanceObserver[] = [];\n private _running = false;\n\n start(): void {\n if (this._running || typeof PerformanceObserver === 'undefined') return;\n this._running = true;\n this._observeLCP();\n this._observeFID();\n this._observeINP();\n this._observeCLS();\n this._observeTTFB();\n this._observeFCP();\n }\n\n stop(): void {\n this._running = false;\n for (const obs of this._observers) { try { obs.disconnect(); } catch {} }\n this._observers = [];\n }\n\n snapshot(): JoopVitalsSnapshot { return this._buildSnapshot(); }\n vitals$() { return this._vitals$.asObservable(); }\n snapshot$() { return this._snapshot$.asObservable(); }\n\n getLCP(): number | null { return this._vitals.lcp ?? null; }\n getCLS(): number | null { return this._vitals.cls ?? null; }\n getINP(): number | null { return this._vitals.inp ?? null; }\n getTTFB(): number | null { return this._vitals.ttfb ?? null; }\n getFCP(): number | null { return this._vitals.fcp ?? null; }\n getFID(): number | null { return this._vitals.fid ?? null; }\n\n getRating(metric: string): 'good' | 'needs-improvement' | 'poor' {\n const value = (this._vitals as Record<string, number | null>)[metric];\n return _rate(metric, value ?? null);\n }\n\n private _record(metric: keyof Omit<JoopVitalsSnapshot, 'capturedAt'>, value: number): void {\n (this._vitals as Record<string, number>)[metric] = value;\n const rating = _rate(metric as string, value);\n this._vitals$.next({ metric, value, rating });\n this._snapshot$.next(this._buildSnapshot());\n }\n\n private _observe(types: string[], callback: (list: PerformanceObserverEntryList) => void): void {\n try {\n const obs = new PerformanceObserver(callback);\n obs.observe({ type: types[0], buffered: true });\n this._observers.push(obs);\n } catch {}\n }\n\n private _observeLCP(): void {\n this._observe(['largest-contentful-paint'], list => {\n const entries = list.getEntries();\n if (entries.length) this._record('lcp', (entries[entries.length - 1] as PerformanceEntry & { renderTime?: number; loadTime?: number }).renderTime || (entries[entries.length - 1] as PerformanceEntry & { renderTime?: number; loadTime?: number }).loadTime || entries[entries.length - 1].startTime);\n });\n }\n\n private _observeFID(): void {\n this._observe(['first-input'], list => {\n const e = list.getEntries()[0] as PerformanceEntry & { processingStart?: number };\n if (e && e.processingStart) this._record('fid', e.processingStart - e.startTime);\n });\n }\n\n private _observeINP(): void {\n this._observe(['event'], list => {\n let max = this._vitals.inp ?? 0;\n for (const e of list.getEntries()) {\n const entry = e as PerformanceEntry & { processingEnd?: number };\n if (entry.processingEnd) max = Math.max(max, entry.processingEnd - entry.startTime);\n }\n if (max > 0) this._record('inp', max);\n });\n }\n\n private _observeCLS(): void {\n let clsValue = 0;\n let sessionStart = 0;\n let lastEntry = 0;\n this._observe(['layout-shift'], list => {\n for (const e of list.getEntries()) {\n const entry = e as PerformanceEntry & { hadRecentInput?: boolean; value?: number };\n if (entry.hadRecentInput) continue;\n if (lastEntry > 0 && (entry.startTime - lastEntry) > 1000) {\n if (entry.startTime - sessionStart > 5000) { clsValue = 0; sessionStart = entry.startTime; }\n }\n if (lastEntry === 0) sessionStart = entry.startTime;\n clsValue += entry.value ?? 0;\n lastEntry = entry.startTime;\n this._record('cls', clsValue);\n }\n });\n }\n\n private _observeTTFB(): void {\n const nav = performance.getEntriesByType?.('navigation')?.[0] as PerformanceEntry & { responseStart?: number };\n if (nav?.responseStart) this._record('ttfb', nav.responseStart);\n this._observe(['navigation'], list => {\n const e = list.getEntries()[0] as PerformanceEntry & { responseStart?: number };\n if (e?.responseStart) this._record('ttfb', e.responseStart);\n });\n }\n\n private _observeFCP(): void {\n this._observe(['paint'], list => {\n const e = list.getEntries().find(e => e.name === 'first-contentful-paint');\n if (e) this._record('fcp', e.startTime);\n });\n }\n\n private _buildSnapshot(): JoopVitalsSnapshot {\n return {\n lcp: this._vitals.lcp ?? null,\n fid: this._vitals.fid ?? null,\n inp: this._vitals.inp ?? null,\n cls: this._vitals.cls ?? null,\n ttfb: this._vitals.ttfb ?? null,\n fcp: this._vitals.fcp ?? null,\n capturedAt: Date.now(),\n };\n }\n}\n\nfunction _rate(metric: string, value: number | null): 'good' | 'needs-improvement' | 'poor' {\n if (value === null) return 'good';\n const [good, poor] = THRESHOLDS[metric] ?? [Infinity, Infinity];\n return value <= good ? 'good' : value <= poor ? 'needs-improvement' : 'poor';\n}\n","export type JoopRecordedEventType = 'dom-mutation' | 'click' | 'input' | 'scroll' | 'resize' | 'navigation' | 'custom';\n\nexport interface JoopRecordedEvent {\n type: JoopRecordedEventType;\n timestamp: number;\n selector?: string;\n value?: string;\n data?: Record<string, unknown>;\n}\n\nexport interface JoopSessionRecord {\n startedAt: number;\n stoppedAt: number;\n events: JoopRecordedEvent[];\n url: string;\n userAgent: string;\n}\n\nexport interface JoopSessionRecorderOptions {\n maskSelectors?: string[]; // CSS selectors to mask (replace with ***)\n ignoreSelectors?: string[]; // CSS selectors to ignore entirely\n redactInputs?: boolean; // auto-redact password + [data-pii] inputs\n maxEvents?: number;\n captureScroll?: boolean;\n captureResize?: boolean;\n}\n\nexport class JoopSessionRecorder {\n private _events: JoopRecordedEvent[] = [];\n private _running = false;\n private _paused = false;\n private _startedAt = 0;\n private _opts: Required<JoopSessionRecorderOptions> = {\n maskSelectors: [], ignoreSelectors: [],\n redactInputs: true, maxEvents: 10000,\n captureScroll: true, captureResize: true,\n };\n private _cleanup: Array<() => void> = [];\n private _mutationObserver: MutationObserver | null = null;\n private _scrollTimer: ReturnType<typeof setTimeout> | null = null;\n\n start(options: JoopSessionRecorderOptions = {}): void {\n if (this._running) return;\n this._opts = { ...this._opts, ...options };\n this._running = true; this._paused = false;\n this._events = []; this._startedAt = Date.now();\n this._attachListeners();\n }\n\n pause(): void { this._paused = true; }\n resume(): void { this._paused = false; }\n\n stop(): JoopSessionRecord {\n this._running = false; this._paused = false;\n this._detach();\n return {\n startedAt: this._startedAt, stoppedAt: Date.now(),\n events: [...this._events],\n url: typeof location !== 'undefined' ? location.href : '',\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n };\n }\n\n events(): JoopRecordedEvent[] { return [...this._events]; }\n\n export(format: 'json' | 'compressed' = 'json'): string {\n const record: JoopSessionRecord = {\n startedAt: this._startedAt, stoppedAt: Date.now(),\n events: this._events, url: typeof location !== 'undefined' ? location.href : '', userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n };\n const json = JSON.stringify(record);\n if (format === 'compressed') {\n try { return btoa(json); } catch { return json; }\n }\n return json;\n }\n\n addEvent(type: JoopRecordedEventType, data?: Record<string, unknown>): void {\n this._push({ type, timestamp: Date.now(), data });\n }\n\n private _push(event: JoopRecordedEvent): void {\n if (!this._running || this._paused) return;\n if (this._events.length >= this._opts.maxEvents) this._events.shift();\n this._events.push(event);\n }\n\n private _attachListeners(): void {\n // DOM mutations\n this._mutationObserver = new MutationObserver(mutations => {\n for (const m of mutations) {\n if (this._shouldIgnore(m.target as Element)) continue;\n this._push({ type: 'dom-mutation', timestamp: Date.now(), selector: _selector(m.target as Element), data: { addedNodes: m.addedNodes.length, removedNodes: m.removedNodes.length, type: m.type } });\n }\n });\n this._mutationObserver.observe(document.documentElement, { childList: true, subtree: true, attributes: true, characterData: false, attributeFilter: ['class', 'style', 'hidden', 'disabled'] });\n\n // Click\n const onClick = (e: MouseEvent) => {\n const el = e.target as Element;\n if (this._shouldIgnore(el)) return;\n this._push({ type: 'click', timestamp: Date.now(), selector: _selector(el) });\n };\n document.addEventListener('click', onClick, { capture: true });\n this._cleanup.push(() => document.removeEventListener('click', onClick, { capture: true }));\n\n // Input\n const onInput = (e: Event) => {\n const el = e.target as HTMLInputElement;\n if (this._shouldIgnore(el)) return;\n const redact = this._opts.redactInputs && (el.type === 'password' || el.dataset?.pii !== undefined || this._opts.maskSelectors.some(s => el.matches(s)));\n this._push({ type: 'input', timestamp: Date.now(), selector: _selector(el), value: redact ? '***' : undefined });\n };\n document.addEventListener('input', onInput, { capture: true });\n this._cleanup.push(() => document.removeEventListener('input', onInput, { capture: true }));\n\n // Scroll (throttled)\n if (this._opts.captureScroll) {\n const onScroll = () => {\n if (this._scrollTimer) return;\n this._scrollTimer = setTimeout(() => {\n this._scrollTimer = null;\n this._push({ type: 'scroll', timestamp: Date.now(), data: { x: window.scrollX, y: window.scrollY } });\n }, 250);\n };\n window.addEventListener('scroll', onScroll, { passive: true });\n this._cleanup.push(() => window.removeEventListener('scroll', onScroll));\n }\n\n // Resize (throttled)\n if (this._opts.captureResize) {\n let resizeTimer: ReturnType<typeof setTimeout> | null = null;\n const onResize = () => {\n if (resizeTimer) return;\n resizeTimer = setTimeout(() => {\n resizeTimer = null;\n this._push({ type: 'resize', timestamp: Date.now(), data: { w: window.innerWidth, h: window.innerHeight } });\n }, 250);\n };\n window.addEventListener('resize', onResize, { passive: true });\n this._cleanup.push(() => window.removeEventListener('resize', onResize));\n }\n\n // Navigation\n const onPop = () => this._push({ type: 'navigation', timestamp: Date.now(), data: { url: location.href } });\n window.addEventListener('popstate', onPop);\n this._cleanup.push(() => window.removeEventListener('popstate', onPop));\n }\n\n private _detach(): void {\n this._mutationObserver?.disconnect(); this._mutationObserver = null;\n for (const fn of this._cleanup) fn();\n this._cleanup = [];\n }\n\n private _shouldIgnore(el: Element | null): boolean {\n if (!el) return false;\n return this._opts.ignoreSelectors.some(s => { try { return el.matches?.(s); } catch { return false; } });\n }\n}\n\nfunction _selector(el: Element | null): string {\n if (!el) return '';\n const parts: string[] = [];\n let current: Element | null = el;\n while (current && current !== document.body && parts.length < 4) {\n let part = current.tagName.toLowerCase();\n if (current.id) { parts.unshift(`#${current.id}`); break; }\n if (current.className) part += '.' + Array.from(current.classList).slice(0, 2).join('.');\n parts.unshift(part);\n current = current.parentElement;\n }\n return parts.join(' > ');\n}\n","export class JoopCorrelationService {\n private _correlationId = '';\n private _requestId = '';\n\n newCorrelation(): string {\n this._correlationId = crypto.randomUUID();\n return this._correlationId;\n }\n\n newRequest(): string {\n this._requestId = crypto.randomUUID();\n return this._requestId;\n }\n\n getCorrelationId(): string { return this._correlationId; }\n getRequestId(): string { return this._requestId; }\n\n headers(): Record<string, string> {\n const h: Record<string, string> = {};\n if (this._correlationId) h['X-Correlation-ID'] = this._correlationId;\n if (this._requestId) h['X-Request-ID'] = this._requestId;\n return h;\n }\n\n clear(): void { this._correlationId = ''; this._requestId = ''; }\n}\n","export type JoopAuditAction =\n | 'login' | 'logout' | 'session-timeout' | 'session-extended'\n | 'transfer-initiated' | 'transfer-confirmed' | 'transfer-failed'\n | 'profile-updated' | 'password-changed' | 'settings-changed'\n | 'document-viewed' | 'statement-downloaded' | 'otp-sent' | 'otp-verified'\n | 'biometric-registered' | 'biometric-authenticated'\n | string;\n\nexport interface JoopAuditEntry {\n id: string;\n action: JoopAuditAction;\n timestamp: number;\n userId?: string;\n sessionId?: string;\n correlationId?: string;\n metadata?: Record<string, unknown>;\n success: boolean;\n}\n\nexport type JoopAuditListener = (entry: JoopAuditEntry) => void;\n\nexport class JoopAuditLog {\n private _entries: JoopAuditEntry[] = [];\n private _listeners: JoopAuditListener[] = [];\n\n constructor(private _maxEntries = 500) {}\n\n record(action: JoopAuditAction, options: {\n userId?: string;\n sessionId?: string;\n correlationId?: string;\n metadata?: Record<string, unknown>;\n success?: boolean;\n } = {}): JoopAuditEntry {\n const entry: JoopAuditEntry = {\n id: crypto.randomUUID(),\n action,\n timestamp: Date.now(),\n success: options.success ?? true,\n ...options,\n };\n this._entries.push(entry);\n if (this._entries.length > this._maxEntries) this._entries = this._entries.slice(-this._maxEntries);\n this._listeners.forEach(l => l(entry));\n return entry;\n }\n\n getAll(): JoopAuditEntry[] { return [...this._entries]; }\n getByAction(action: JoopAuditAction): JoopAuditEntry[] { return this._entries.filter(e => e.action === action); }\n getBySession(sessionId: string): JoopAuditEntry[] { return this._entries.filter(e => e.sessionId === sessionId); }\n getByUser(userId: string): JoopAuditEntry[] { return this._entries.filter(e => e.userId === userId); }\n\n onRecord(listener: JoopAuditListener): () => void {\n this._listeners.push(listener);\n return () => { this._listeners = this._listeners.filter(l => l !== listener); };\n }\n\n clear(): void { this._entries = []; }\n export(): string { return JSON.stringify(this._entries, null, 2); }\n}\n","export interface JoopPerfMark {\n name: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n metadata?: Record<string, unknown>;\n}\n\nexport class JoopPerformanceService {\n private _marks = new Map<string, JoopPerfMark>();\n private _completed: JoopPerfMark[] = [];\n\n mark(name: string, metadata?: Record<string, unknown>): void {\n this._marks.set(name, { name, startTime: performance.now(), metadata });\n }\n\n measure(name: string): JoopPerfMark | null {\n const mark = this._marks.get(name);\n if (!mark) return null;\n const endTime = performance.now();\n const entry: JoopPerfMark = { ...mark, endTime, duration: endTime - mark.startTime };\n this._marks.delete(name);\n this._completed.push(entry);\n return entry;\n }\n\n async timeAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {\n this.mark(name);\n try {\n const result = await fn();\n this.measure(name);\n return result;\n } catch (err) {\n this.measure(name);\n throw err;\n }\n }\n\n timeSync<T>(name: string, fn: () => T): T {\n this.mark(name);\n try {\n const result = fn();\n this.measure(name);\n return result;\n } catch (err) {\n this.measure(name);\n throw err;\n }\n }\n\n getCompleted(): JoopPerfMark[] { return [...this._completed]; }\n getByName(name: string): JoopPerfMark[] { return this._completed.filter(m => m.name === name); }\n\n getAverage(name: string): number | null {\n const entries = this._completed.filter(m => m.name === name && m.duration !== undefined);\n if (!entries.length) return null;\n return entries.reduce((sum, m) => sum + m.duration!, 0) / entries.length;\n }\n\n clear(): void { this._marks.clear(); this._completed = []; }\n}\n","export interface JoopErrorReport {\n id: string;\n message: string;\n stack?: string;\n context?: Record<string, unknown>;\n timestamp: number;\n userId?: string;\n sessionId?: string;\n}\n\nexport type JoopErrorHandler = (report: JoopErrorReport) => void | Promise<void>;\n\nexport class JoopErrorReporter {\n private _handlers: JoopErrorHandler[] = [];\n private _userId = '';\n private _sessionId = '';\n private _context: Record<string, unknown> = {};\n\n setUser(userId: string): void { this._userId = userId; }\n setSession(sessionId: string): void { this._sessionId = sessionId; }\n setContext(ctx: Record<string, unknown>): void { this._context = { ...this._context, ...ctx }; }\n\n addHandler(handler: JoopErrorHandler): () => void {\n this._handlers.push(handler);\n return () => { this._handlers = this._handlers.filter(h => h !== handler); };\n }\n\n capture(error: unknown, extra?: Record<string, unknown>): JoopErrorReport {\n const err = error instanceof Error ? error : new Error(String(error));\n const report: JoopErrorReport = {\n id: crypto.randomUUID(),\n message: err.message,\n stack: err.stack,\n context: { ...this._context, ...extra },\n timestamp: Date.now(),\n ...(this._userId ? { userId: this._userId } : {}),\n ...(this._sessionId ? { sessionId: this._sessionId } : {}),\n };\n this._handlers.forEach(h => Promise.resolve(h(report)).catch(() => {}));\n return report;\n }\n\n captureMessage(message: string, extra?: Record<string, unknown>): JoopErrorReport {\n return this.capture(new Error(message), extra);\n }\n\n clear(): void {\n this._handlers = [];\n this._userId = '';\n this._sessionId = '';\n this._context = {};\n }\n}\n"]}