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
package/CHANGELOG.md ADDED
@@ -0,0 +1,678 @@
1
+ # Changelog
2
+
3
+ **Author:** Kundan Singh
4
+
5
+ All notable changes to **JoopJS** are documented here.
6
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
7
+ Versioning follows [Semantic Versioning](https://semver.org/).
8
+
9
+ ---
10
+
11
+ ## Version History
12
+
13
+ | Version | Codename | New Services | Tests | Total Tests | Sub-paths Added |
14
+ |---|---|---|---|---|---|
15
+ | [2.0.0](#200--vue-composables) | Vue Composables | — | +39 | **1080** | `vue` |
16
+ | [1.9.0](#190--banking-depth) | Banking Depth | 4 | +100 | **1041** | — |
17
+ | [1.8.0](#180--framework-bindings) | Framework Bindings | — | +25 | 941 | `react`, `angular` |
18
+ | [1.7.0](#170--mobile-core-services) | Mobile Core Services | 5 | +48 | **916** | — |
19
+ | [1.6.0](#160--platform-foundation) | Platform Foundation | 1 | +15 | 868 | `platform` |
20
+ | [1.5.0](#150--ai-era-enterprise-pack) | AI-Era Enterprise Pack | 21 | +198 | 853 | `ai`, `state`, `workers`, `workflow`, `sync` |
21
+ | [1.4.0](#140--platform-services-pack) | Platform Services Pack | 16 | +160 | 655 | `forms`, `pwa`, `router` |
22
+ | [1.3.0](#130--enterprise-feature-pack) | Enterprise Feature Pack | 15 | +143 | 495 | `cache`, `network`, `analytics`, `validation` |
23
+ | [1.2.0](#120--framework-agnostic-services-pack) | Framework-Agnostic Services Pack | 9 | +94 | 352 | `theme`, `i18n`, `ui`, `native-bridge`, `deeplink` |
24
+ | [1.1.0](#110--enterprise--banking-pack) | Enterprise & Banking Pack | 22 | +134 | 258 | `banking`, `observability`, `security`, `device`, `dev` |
25
+ | [1.0.0](#100--initial-release) | Initial Release | 14 | 124 | 124 | `encryption`, `storage`, `auth`, `api`, `core`, `session` |
26
+
27
+ ---
28
+
29
+ ## Sub-path Exports Reference
30
+
31
+ | Import path | Key exports |
32
+ |---|---|
33
+ | `joopjs` | Everything (main entry) |
34
+ | `joopjs/encryption` | `JoopGcmService`, `JoopRsaService`, `JoopAesService`, `JoopX25519Service`, `JoopE2EService`, `JoopCryptoUtils` |
35
+ | `joopjs/storage` | `JoopScopeMapService`, `JoopDataStorage`, `JoopIndexedDbService` |
36
+ | `joopjs/auth` | `JoopAuthService`, `JoopTokenService`, `JoopPKCEService`, `JoopOtpService`, `JoopBiometricService`, `JoopMfaService`, `JoopOIDCClient` |
37
+ | `joopjs/api` | `JoopHttpClient`, `JoopRequestService`, `JoopInterceptorPipeline`, `JoopCircuitBreaker`, `JoopOfflineQueue`, `JoopPollingService`, `JoopFileSaverService`, `JoopResponseMapper`, `JoopExportService`, `JoopWebhookVerifier`, `JoopIdempotencyService` |
38
+ | `joopjs/core` | `JoopConfigService`, `JoopLogger`, `JoopPluginService`, `JoopEnvironmentService`, `JoopHealthService`, `JoopFeatureFlagService`, `JoopRateLimiter`, `JoopConsentService` |
39
+ | `joopjs/session` | `JoopSessionTimeoutService`, `JoopMultiTabSync`, `JoopConcurrentSessionService`, `JoopIdleService` |
40
+ | `joopjs/banking` | IBAN, currency, masking, transaction ID, Luhn/card, `JoopReceiptService`; v1.9.0+: `JoopFraudDetection`, `JoopOpenBankingClient`, `JoopPaymentOrchestrator`, `JoopStatementParser` |
41
+ | `joopjs/observability` | `JoopCorrelationService`, `JoopAuditLog`, `JoopPerformanceService`, `JoopErrorReporter`, `JoopWebVitals`, `JoopSessionRecorder` |
42
+ | `joopjs/security` | `JoopSecureStorage`, `JoopBehavioralBiometrics`, `JoopRiskEngine`, `JoopPIIScanner`, `JoopSecretSharing`, `JoopDifferentialPrivacy`, `JoopWatermarkService` |
43
+ | `joopjs/device` | `JoopDeviceFingerprintService`, `JoopKeyVault`, `JoopBiometricAuth`, `JoopPushService`, `JoopAppLifecycle`, `JoopNetworkMonitor` |
44
+ | `joopjs/dev` | `JoopMockService` |
45
+ | `joopjs/theme` | `JoopThemeService` |
46
+ | `joopjs/i18n` | `JoopI18nService` |
47
+ | `joopjs/ui` | `JoopLoaderService`, `JoopAlertService`, `JoopPaginationService`, `JoopPrintService`, `JoopA11yService`, `JoopVirtualScroll` |
48
+ | `joopjs/native-bridge` | `JoopNativeBridgeService` |
49
+ | `joopjs/deeplink` | `JoopDeeplinkService` |
50
+ | `joopjs/cache` | `JoopCacheService` |
51
+ | `joopjs/network` | `JoopWebSocketService`, `JoopStreamingService` |
52
+ | `joopjs/analytics` | `JoopAnalyticsService`, `consoleAnalyticsAdapter` |
53
+ | `joopjs/validation` | `JoopFormValidator` |
54
+ | `joopjs/utilities` | Date, Hijri, QR, barcode, chart data, geo, media, clipboard, image, sanitizer, PDF, watermark, notification, geo utils |
55
+ | `joopjs/forms` | `JoopFormBuilder`, `JoopField`, `JoopForm` |
56
+ | `joopjs/pwa` | `JoopServiceWorkerService`, `JoopNotificationService` |
57
+ | `joopjs/router` | `JoopRouterService` |
58
+ | `joopjs/ai` | `JoopAiClient`, `JoopToolRegistry` |
59
+ | `joopjs/state` | `JoopStore`, `createStore`, `createSlice` |
60
+ | `joopjs/workers` | `JoopWorkerPool`, `JoopCompressionService` |
61
+ | `joopjs/workflow` | `JoopStateMachine`, `JoopWorkflowEngine` |
62
+ | `joopjs/sync` | `JoopSyncEngine`, `CRDTCounter`, `CRDTSet`, `CRDTRegister`, `CRDTText`, `mergeCRDT` |
63
+ | `joopjs/platform` | `JoopPlatform`, all adapter interfaces |
64
+ | `joopjs/react` | `createJoopReact()`, `JoopProvider`, all hooks (v1.8.0+) |
65
+ | `joopjs/angular` | `provideJoop()`, `JoopModule`, `fromJoop()`, `toJoop()`, `createZonedFromJoop()`, all injection tokens (v1.8.0+) |
66
+ | `joopjs/vue` | `createJoopVue()`, `provideJoop`, `useJoop`, all composables (v2.0.0+) |
67
+
68
+ ---
69
+
70
+ ## [2.0.0] — Vue Composables
71
+
72
+ **0 new core services · 39 new tests · 1080 tests total · 90 test files · 1 new sub-path**
73
+
74
+ ### Added
75
+
76
+ - **`joopjs/vue`** sub-path — Vue 3.x integration using the same factory pattern as React: `createJoopVue(Vue)` receives the Vue instance as a parameter so the package never imports `vue` directly. Marks `vue >=3.0.0` as an optional peer dependency. Ships 12 composables:
77
+ - `provideJoop(instance)` — registers a `JoopInstance` into the component tree via Vue `provide()`
78
+ - `useJoop()` — access the full `JoopInstance` from any child component
79
+ - `useJoopNetworkMonitor()` — reactive `online`, `type`, `effectiveType`, `isMetered` refs; auto-destroys monitor on `onUnmounted`
80
+ - `useJoopAppLifecycle()` — reactive `state` and `isActive` computed refs; auto-destroys listener on `onUnmounted`
81
+ - `useJoopKeyVault(key, config?)` — AES-GCM vault `value`/`loading` refs + `set()`, `remove()`, `refresh()`
82
+ - `useJoopAuth()` — `isLoggedIn` ref reactive to `isLoggedIn$()`, plus `login()` → `setLoggedIn(true)` and `logout()`
83
+ - `useJoopTheme()` — `active` ref + `themes` computed array + `setTheme(name)`
84
+ - `useJoopI18n()` — `language`/`direction` refs reactive to `language$()`, plus `t()` and `setLanguage()`
85
+ - `useJoopLoader()` — `isLoading` ref + `show()` / `hide()`
86
+ - `useJoopConfig<T>(key)` — computed ref returning typed config value
87
+ - `useJoopFeatureFlag(key, ctx?)` — `enabled` and `variant` computed refs
88
+ - `useJoopStore(selector)` — selector-based reactive ref; auto-unsubscribes on `onUnmounted`
89
+ - `package.json` `peerDependencies`: `vue >=3.0.0` (optional).
90
+ - `package.json` exports: `./vue` sub-path entry.
91
+ - `tsup.config.ts`: added `vue/index` entry point; added `vue` to externals.
92
+
93
+ ### Tests added
94
+
95
+ | File | Tests |
96
+ |---|---|
97
+ | `tests/vue-composables.test.ts` | 39 (factory, provide/inject, auth, theme, i18n, loader, config, flags, store, network, lifecycle, key vault) |
98
+
99
+ ---
100
+
101
+ ## [1.9.0] — Banking Depth
102
+
103
+ **4 new services · 100 new tests · 1041 tests total · 89 test files**
104
+
105
+ ### Added
106
+
107
+ - **`JoopFraudDetection`** (`joopjs/banking`) — 5-signal fraud scoring engine with velocity count, velocity amount, large-amount, geo-distance, and time-anomaly evaluators. Reactive `result$` observable and `onAlert()` handler registration. Score 0-100 → level (low/medium/high/critical) → recommendation (allow/review/challenge/block). Inline Haversine distance for geo scoring with no external deps.
108
+ - **`JoopOpenBankingClient`** (`joopjs/banking`) — PSD2/OBIE-spec Open Banking client. OAuth2 client-credentials with token caching. Endpoints: `getAccounts()`, `getTransactions()`, `createConsent()`, `getConsentStatus()`, `revokeConsent()`, `initiatePayment()`. FAPI headers: `x-fapi-interaction-id`, `x-fapi-financial-id`, `x-ob-consent-id`. Requires config via `createJoop`.
109
+ - **`JoopPaymentOrchestrator`** (`joopjs/banking`) — 8-state 3DS payment session lifecycle (`idle → initiating → awaiting_3ds → processing_3ds → authorised → settled → failed → cancelled`). Per-session `JoopBehaviorSubject` for reactive UI binding via `session$(sessionId)`. Card PAN masked to last-4 immediately after `initiate()`. AbortController per request with configurable `timeoutMs`. Requires config via `createJoop`.
110
+ - **`JoopStatementParser`** (`joopjs/banking`) — Auto-detect parser for 4 statement formats. MT940: regex-based field extraction (`:20:/:25:/:60F:/:61:/:86:`). OFX/QFX: SGML `<STMTTRN>` block extraction. QIF: line-by-line state machine (D/T/P/M/N/^). CSV: configurable column mapping, auto date-format detection, European number format support, RFC 4180-compliant quoted field parsing. All parsers produce stable deterministic transaction IDs.
111
+ - `JoopInstance.fraud` — `JoopFraudDetection` instance available on every `createJoop()` call.
112
+ - `JoopInstance.statementParser` — `JoopStatementParser` instance available on every `createJoop()` call.
113
+ - `JoopInstance.openBanking` — `JoopOpenBankingClient | null` (null until configured).
114
+ - `JoopInstance.payment` — `JoopPaymentOrchestrator | null` (null until configured).
115
+
116
+ ### Tests added
117
+
118
+ | File | Tests |
119
+ |---|---|
120
+ | `tests/fraud-detection.test.ts` | 19 |
121
+ | `tests/open-banking.test.ts` | 15 |
122
+ | `tests/payment-orchestrator.test.ts` | 18 |
123
+ | `tests/statement-parser.test.ts` | 48 (MT940, OFX, QIF, CSV, edge cases) |
124
+
125
+ ---
126
+
127
+ ## [1.8.0] — Framework Bindings
128
+
129
+ **0 new core services · 25 new tests · 941 tests total · 85 test files · 2 new sub-paths**
130
+
131
+ ### Added
132
+
133
+ - **`joopjs/react`** sub-path — Zero-dependency React integration using factory pattern `createJoopReact(React)`. Avoids any direct `import from 'react'` so the package stays framework-agnostic. Ships 12 hooks:
134
+ - `JoopProvider` — React context provider
135
+ - `useJoop` — access full `JoopInstance` inside the tree
136
+ - `useJoopNetworkMonitor` — reactive online/offline + network-type state
137
+ - `useJoopAppLifecycle` — reactive foreground/background state
138
+ - `useJoopKeyVault` — AES-GCM vault get/set/remove with loading state
139
+ - `useJoopAuth` — login state reactive subscription
140
+ - `useJoopTheme` — active theme name + `setTheme()`
141
+ - `useJoopI18n` — language + direction + `t()` + `setLanguage()`
142
+ - `useJoopLoader` — loading state + `show()` / `hide()`
143
+ - `useJoopConfig` — typed config value
144
+ - `useJoopFeatureFlag` — enabled + variant
145
+ - `useJoopStore` — selector-based store subscription
146
+ - **`joopjs/angular`** sub-path — Angular 17+ integration without importing `@angular/core`. String-based injection tokens (14 total: `JOOP`, `JOOP_AUTH`, `JOOP_THEME`, `JOOP_I18N`, `JOOP_HTTP`, `JOOP_LOADER`, `JOOP_ALERT`, `JOOP_ROUTER`, `JOOP_ANALYTICS`, `JOOP_FEATURE_FLAGS`, `JOOP_AUDIT_LOG`, `JOOP_STORE`, `JOOP_KEY_VAULT`, `JOOP_NETWORK`, `JOOP_LIFECYCLE`). Factory functions: `provideJoop(instance)` for standalone apps, `JoopModule.forRoot()` for NgModule, `fromJoop()` / `toJoop()` for RxJS bridging, `createZonedFromJoop()` for `NgZone` change detection.
147
+ - `package.json` `peerDependencies`: `react >=18`, `@angular/core >=17`, `rxjs >=7` (all optional).
148
+ - `package.json` exports: `./react` and `./angular` sub-path entries.
149
+ - `tsup.config.ts`: added `react/index` and `angular/index` entry points; added `react`, `react-dom`, `@angular/core`, `@angular/common`, `rxjs` to externals.
150
+
151
+ ### Tests added
152
+
153
+ | File | Tests |
154
+ |---|---|
155
+ | `tests/react-hooks.test.ts` | 11 |
156
+ | `tests/angular.test.ts` | 14 |
157
+
158
+ ---
159
+
160
+ ## [1.7.0] — Mobile Core Services
161
+
162
+ **5 new services · 48 new tests · 916 tests total · 83 test files**
163
+
164
+ ### Added
165
+
166
+ #### `joopjs/device` — Mobile Core
167
+
168
+ - **`JoopKeyVault`** — Secure key-value store with optional AES-GCM encryption (PBKDF2, 100k iterations, SHA-256). Without an `encryptionKey` stores raw plaintext; with one, every value is stored as base64-encoded `IV ‖ ciphertext`. Methods: `set / get / remove / clear / has / rotateKey`. `rotateKey(newKey, keys)` re-encrypts a set of keys atomically — useful for key rotation without data loss. Accepts a `JoopKeyVaultAdapter` injection for React Native Keychain or MMKV-encrypted storage.
169
+
170
+ - **`JoopBiometricAuth`** — WebAuthn/FIDO2 biometric authentication for web; adapter delegation for React Native. `enroll(userId, displayName)` creates a platform passkey via `navigator.credentials.create()` with ES256 + RS256 pubKeyCredParams and `residentKey: 'preferred'`. `authenticate(options?)` calls `navigator.credentials.get()` and returns `true/false` — never throws. `isAvailable()` wraps `PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()`. `canAuthenticate()` provides a quick availability check without prompting. Accepts a `JoopBiometricAdapter` (e.g. `react-native-biometrics`).
171
+
172
+ - **`JoopPushService`** — Web Push + local notification service. `requestPermission()` wraps `Notification.requestPermission()`. `subscribe(options)` registers with a service worker's `PushManager` using a VAPID key and returns `{ endpoint, p256dh, auth }` ready to send to your server. `show(payload)` fires a local `Notification`. `setBadgeCount(n)` / `clearBadge()` wrap the Badging API. `onMessage(handler)` for foreground push payloads — returns unsubscribe function. `destroy()` removes all handlers and adapter subscriptions. Accepts a `JoopPushAdapter` (e.g. FCM/APNs wrappers for React Native).
173
+
174
+ - **`JoopAppLifecycle`** — App state machine (`'active' | 'background' | 'inactive' | 'unknown'`) driven by `document.visibilitychange` + `window.focus/blur` on web. `state$()` reactive observable; `getState()` synchronous snapshot; `isActive()` boolean predicate. `onForeground(fn)` fires each time the app returns from background; `onBackground(fn)` fires each time it leaves foreground. `destroy()` removes all DOM event listeners. Accepts a `JoopLifecycleAdapter` (e.g. React Native `AppState` wrapper).
175
+
176
+ - **`JoopNetworkMonitor`** — Connectivity and network-type monitor. `isOnline()` reflects `navigator.onLine`. `getState()` returns `{ online, type, effectiveType, downlink, rtt, saveData, metered }` — reads `NetworkInformation` API when available. `isMetered()` returns `true` for cellular connections (or when `metered` flag is set). `onOnline(fn)` / `onOffline(fn)` / `onTypeChange(fn)` reactive callbacks — each returns an unsubscribe function. `destroy()` removes all listeners. Accepts a `JoopNetworkAdapter` (e.g. React Native NetInfo).
177
+
178
+ #### Platform adapter interfaces (added to `joopjs/platform`)
179
+
180
+ | Interface | Methods |
181
+ |---|---|
182
+ | `JoopKeyVaultAdapter` | `get(key) / set(key, val) / remove(key) / clear()` — all async |
183
+ | `JoopBiometricAdapter` | `isAvailable() / authenticate(reason?)` |
184
+ | `JoopPushAdapter` | `requestPermission() / getToken(serverKey?) / onMessage(handler) / setBadgeCount?(count)` |
185
+ | `JoopLifecycleAdapter` | `getState() / onChange(handler)` — handler receives `JoopAppState` |
186
+ | `JoopNetworkAdapter` | `getState() / onChange(handler)` — handler receives `JoopNetworkState` |
187
+
188
+ ### React Native quick start (v1.7.0 additions)
189
+
190
+ ```ts
191
+ import { JoopPlatform } from 'joopjs/platform';
192
+ import ReactNativeBiometrics from 'react-native-biometrics';
193
+ import NetInfo from '@react-native-community/netinfo';
194
+ import { AppState } from 'react-native';
195
+
196
+ JoopPlatform.init({
197
+ adapter: {
198
+ biometric: {
199
+ isAvailable: async () => {
200
+ const { available } = await new ReactNativeBiometrics().isSensorAvailable();
201
+ return available;
202
+ },
203
+ authenticate: async (reason = 'Confirm identity') => {
204
+ const { success } = await new ReactNativeBiometrics()
205
+ .simplePrompt({ promptMessage: reason });
206
+ return success;
207
+ },
208
+ },
209
+ lifecycle: {
210
+ getState: () => {
211
+ const s = AppState.currentState;
212
+ return s === 'active' ? 'active' : s === 'background' ? 'background' : 'inactive';
213
+ },
214
+ onChange: (fn) => {
215
+ const sub = AppState.addEventListener('change', s =>
216
+ fn(s === 'active' ? 'active' : s === 'background' ? 'background' : 'inactive'));
217
+ return () => sub.remove();
218
+ },
219
+ },
220
+ network: {
221
+ getState: () => ({ online: true, type: 'unknown' }),
222
+ onChange: (fn) => NetInfo.addEventListener(state =>
223
+ fn({ online: !!state.isConnected, type: state.type as 'wifi' | 'cellular' })),
224
+ },
225
+ },
226
+ });
227
+ ```
228
+
229
+ ---
230
+
231
+ ## [1.6.0] — Platform Foundation
232
+
233
+ **1 new module · 15 new tests · 868 tests total**
234
+
235
+ ### Added
236
+
237
+ #### `joopjs/platform` — Platform Abstraction Layer (new sub-path)
238
+
239
+ - **`JoopPlatform`** — Central platform registry and adapter injection point. `JoopPlatform.init({ adapter })` is called once at app startup to register platform-specific implementations. Auto-detects `type: 'web' | 'react-native' | 'node' | 'unknown'` via `navigator.product`, `process.versions.node`, and `window` presence. Predicates: `isWeb()`, `isMobile()`, `isNode()`. `capabilities()` returns a snapshot of available APIs: `compression`, `workers`, `crypto`, `dom`, `localStorage`, `sessionStorage`, `serviceWorker`. `getStorage()` / `getSessionStorage()` return the best available `JoopStorageAdapter` (custom → native → in-memory fallback). `_reset()` for test teardown.
240
+
241
+ - **`JoopStorageAdapter`** — `getItem / setItem / removeItem / clear?`. Implemented by `localStorage`, `sessionStorage`, MMKV, and the built-in memory fallback. Used as the standard storage contract throughout the library.
242
+
243
+ - **`JoopCompressionAdapter`** — `compress(data, format) / decompress(data, format)` returning `Promise<Uint8Array>`. Drop-in for `fflate` or `pako` on React Native.
244
+
245
+ - **`JoopWorkerAdapter`** — `run<T,R>(fn, arg, timeoutMs?) / terminate?()`. For platforms with custom threading (e.g. `react-native-threads`).
246
+
247
+ - **`JoopCryptoAdapter`** — `subtle: SubtleCrypto / getRandomValues<T>(array): T`. For environments with non-standard WebCrypto placement.
248
+
249
+ ### Changed (non-breaking)
250
+
251
+ - **`JoopCompressionService`** — Checks `JoopPlatform.getAdapter().compression` first; falls through to native `CompressionStream`; throws a descriptive error with setup instructions if neither is available. `isSupported()` now also returns `true` when a compression adapter is registered.
252
+
253
+ - **`JoopWorkerPool`** — Detects `Worker` availability via `_workersAvailable()`. Falls back to main-thread `setTimeout(0)` execution (or a registered `JoopWorkerAdapter`) when Workers are unavailable. `run()` / `map()` / `terminate()` API is unchanged.
254
+
255
+ - **`JoopOIDCClient`** — `config.storage` widened from `Storage` to `JoopStorageAdapter`. Defaults through `sessionStorage → JoopPlatform.getSessionStorage()`. Added `buildLoginUrl(options)` for React Native (returns a URL string instead of redirecting). `logout()` guards `window.location` assignment to be web-only.
256
+
257
+ - **`JoopIdempotencyService`** — `config.storage` widened to `JoopStorageAdapter`. Replaced `Storage.length / key()` enumeration with an internal `_keys: Set<string>` — compatible with any adapter. Fixed: `generate()` returning an existing key now registers it in `_keys` so `clearAll()` covers it.
258
+
259
+ - **`JoopStreamingService`** — Skips native `EventSource` when `JoopPlatform.isMobile()` is true; always uses the fetch-based SSE path on React Native.
260
+
261
+ ### React Native quick start (v1.6.0)
262
+
263
+ ```ts
264
+ import { JoopPlatform } from 'joopjs/platform';
265
+ import { MMKV } from 'react-native-mmkv';
266
+ import { gzip, ungzip } from 'fflate';
267
+
268
+ JoopPlatform.init({
269
+ adapter: {
270
+ storage: new MMKV(),
271
+ compression: {
272
+ compress: (d, _fmt) => new Promise((res, rej) => gzip(d, (e, r) => e ? rej(e) : res(r))),
273
+ decompress: (d, _fmt) => new Promise((res, rej) => ungzip(d, (e, r) => e ? rej(e) : res(r))),
274
+ },
275
+ },
276
+ });
277
+ ```
278
+
279
+ ---
280
+
281
+ ## [1.5.0] — AI-Era Enterprise Pack
282
+
283
+ **21 new services · 198 new tests · 853 tests total**
284
+
285
+ ### Added
286
+
287
+ #### `joopjs/ai` — AI / LLM (new sub-path)
288
+
289
+ - **`JoopAiClient`** — Multi-provider LLM gateway. Supports OpenAI, Anthropic, Gemini, Ollama, and custom providers via a `JoopAiProvider` config. Streaming via SSE fetch with delta accumulation, tool-call parsing, AbortSignal cancellation. Provider-specific request builders keep the API uniform: `chat(messages, options?)`, `stream(messages, options?)`, `complete(prompt, options?)`. Returns `JoopAiUsage` token counts.
290
+
291
+ - **`JoopToolRegistry`** — Function-calling registry for LLM tool use. `register(name, schema, handler)`, `dispatch(name, args)`. Format converters: `toOpenAiFormat()`, `toAnthropicFormat()`, `toGeminiFormat()` emit provider-ready tool definitions.
292
+
293
+ - **`JoopStreamingService`** *(moved to `joopjs/network`)* — SSE streaming for both native `EventSource` (GET) and fetch-based POST streams. Parses `id:/event:/data:` fields, dispatches typed `JoopSSEMessage` events, auto-reconnects up to `maxReconnects`.
294
+
295
+ #### `joopjs/security` additions — Behavioral & Risk
296
+
297
+ - **`JoopBehavioralBiometrics`** — Bot-detection via passive behavioral telemetry: keystroke intervals + dwell times, mouse speed + acceleration, scroll velocity, touch force. `record()` starts passive collection. `getScore()` uses coefficient-of-variation thresholds to return a `JoopBiometricScore`. `compare(profile)` computes similarity to a saved baseline. `anomaly$()` observable emits z-score deviations. `destroy()` removes all DOM listeners.
298
+
299
+ - **`JoopRiskEngine`** — Composite risk scorer with 7 weighted built-in factors: `failed_attempts`, `biometrics`, `mfa`, `known_device`, `vpn`, `time_anomaly`, `transaction_amount`. `evaluate(context)` returns `JoopRiskScore` with numeric score (0-100) and `'low' | 'medium' | 'high' | 'critical'` level. `addFactor()` for custom signals. `reset()` clears counters.
300
+
301
+ #### `joopjs/workers` — Concurrency (new sub-path)
302
+
303
+ - **`JoopWorkerPool`** — Web Worker thread pool. Serializes any function via `.toString()` into a Blob-URL worker. Round-robin dispatch across configurable `poolSize`. Per-task `timeoutMs` with abort. Automatic drain queue for backpressure. `run<T,R>(fn, arg)` / `map<T,R>(items, fn)` / `terminate()`. Falls back to main-thread execution when Workers are unavailable (see v1.6.0 PAL changes).
304
+
305
+ - **`JoopCompressionService`** — `CompressionStream`/`DecompressionStream` wrapper for `gzip`, `deflate`, and `deflate-raw`. `compress(data) / decompress(data)` operate on `Uint8Array`. `compressString(text) / decompressString(b64)` work with base64. `ratio(original, compressed)` reports efficiency. `isSupported()` checks platform.
306
+
307
+ #### `joopjs/state` — Observable Store (new sub-path)
308
+
309
+ - **`JoopStore<S>`** — Observable state container. `dispatch(type, payload?)` runs the matching reducer. `select(selector)` returns a subscription that only emits on value change. Unlimited undo/redo via `undo()` / `redo()` with internal `_history` / `_future` stacks. `createSlice(name, initialState, reducers)` for namespaced reducer registration. `createStore(config)` factory. `getState()` synchronous snapshot.
310
+
311
+ #### `joopjs/sync` — Local-First / Offline (new sub-path)
312
+
313
+ - **`JoopSyncEngine`** — Offline-first mutation queue. `mutate(operation, payload)` enqueues a `JoopMutation` and auto-syncs when online. Batched POST sync with per-result `ok/conflict` processing. Exponential retry up to `maxRetries`. `status$()` observable: `'idle' | 'syncing' | 'error'`. `resolve(id, strategy)` resolves conflicts with `'local' | 'remote' | 'merge'`.
314
+
315
+ - **`CRDTCounter / CRDTSet / CRDTRegister / CRDTText`** — Four CvRDT implementations. `CRDTCounter`: PN-Counter with per-node increment/decrement maps; `increment(nodeId)` / `decrement(nodeId)` / `value()`. `CRDTSet`: Add-Wins set with `add(item)` / `remove(item)` / `has(item)`. `CRDTRegister<T>`: Last-Write-Wins by `{ timestamp, nodeId }` comparison. `CRDTText`: simplified RGA for collaborative text editing. `mergeCRDT(a, b)` generic helper for all CRDT types.
316
+
317
+ #### `joopjs/workflow` — State Machine & Workflow (new sub-path)
318
+
319
+ - **`JoopStateMachine<S,E>`** — XState-lite FSM. `define(config)` with declarative `on` transition maps, optional guard functions, `onEnter`/`onExit` lifecycle hooks, and action callbacks. `send(event)` resolves the transition and fires hooks. `current()` / `state$()`. `toMermaid()` exports a `stateDiagram-v2` diagram string.
320
+
321
+ - **`JoopWorkflowEngine`** — DAG-based saga orchestrator. `define(name, steps[])` where each step has `run`, optional `after: string[]` dependencies, and `compensate` rollback. Topological parallel execution; timeout wrapping per step. `execute(workflowName, context)` returns `JoopWorkflowRun`. Automatic saga compensation on any step failure.
322
+
323
+ #### `joopjs/security` additions — Privacy / Zero-Knowledge
324
+
325
+ - **`JoopPIIScanner`** — Pattern-based PII detection. Built-in patterns: credit cards, SSN, email, US phone, IBAN, passport, IP address, JWT, API keys. `scan(text)` returns `JoopPIIFinding[]` with match indices. `redact(text)` replaces findings in reverse-index order for stability. `pseudonymize(text)` replaces with SHA-256 truncated hashes. Custom `JoopPIIPattern` support.
326
+
327
+ - **`JoopSecretSharing`** — Shamir's Secret Sharing over the secp256k1 256-bit prime field. `split(secret, n, k)` produces `n` shares; any `k` suffice for reconstruction. `combine(shares)` uses Lagrange interpolation over the prime field. `serializeShare(share)` / `deserializeShare(b64)` for base64 transport. All arithmetic uses BigInt to avoid float precision loss.
328
+
329
+ - **`JoopDifferentialPrivacy`** — Statistical privacy. `addLaplaceNoise(value, sensitivity, epsilon)` via inverse-CDF sampling. `addGaussianNoise(value, sensitivity, epsilon, delta)` via Box-Muller transform. `privatizeCount(count, sensitivity, epsilon)` clamps result to non-negative integer. `randomizedResponse(truth, epsilon)` probabilistic flip. `computePrivacyBudget(queries, epsilon)` cumulative budget accounting.
330
+
331
+ - **`JoopWatermarkService`** — Dual-mode watermarking. `apply(el, text, options?)` tiles a canvas-rendered text overlay as a CSS `backgroundImage` on the target element. `embedInImage(imageData, payload)` encodes an arbitrary string into the R-channel LSBs of an `ImageData` object. `extractFromImage(imageData)` recovers the payload. Works entirely in the browser with no external dependencies.
332
+
333
+ #### `joopjs/observability` additions
334
+
335
+ - **`JoopWebVitals`** — Core Web Vitals collector via `PerformanceObserver`. Tracks LCP (Largest Contentful Paint), CLS (Cumulative Layout Shift, session-window accumulation), INP (Interaction to Next Paint), FCP (First Contentful Paint), TTFB (Time to First Byte). `getRating(metric, value)` returns `'good' | 'needs-improvement' | 'poor'` against Google thresholds. `onVital(handler)` / `getSnapshot()` / `flush()`.
336
+
337
+ - **`JoopSessionRecorder`** — DOM session recorder via `MutationObserver` + click/input/scroll/resize/popstate listeners. Auto-redacts `type=password` and `[data-pii]` inputs. `start()` / `stop()` / `pause()` / `resume()` flow control. `maxEvents` cap. `addEvent(type, data)` for custom instrumentation. `export('json' | 'compressed')` returns a serialized `JoopSessionRecord`.
338
+
339
+ #### `joopjs/auth` additions
340
+
341
+ - **`JoopOIDCClient`** — Full OpenID Connect client with PKCE. `discover(issuerUrl)` fetches `.well-known/openid-configuration`. `login(options?)` generates a SHA-256 code challenge, persists state, and redirects to the authorization endpoint. `handleCallback()` verifies state, exchanges the code for tokens, and schedules silent renewal. `silentRenew()` refreshes tokens before expiry. `buildLoginUrl(options)` for React Native in-app browser flows (v1.6.0 extension). `logout()` calls the end-session endpoint on web.
342
+
343
+ #### `joopjs/api` additions
344
+
345
+ - **`JoopWebhookVerifier`** — HMAC-SHA256 webhook signature verification. Provider-aware: Stripe (`t=,v1=` header format), GitHub (`sha256=` prefix), generic (raw signature). Timing-safe XOR comparison. `sign(payload, secret)` for outgoing webhooks. `verify(request, secret, options?)` returns `true/false`.
346
+
347
+ - **`JoopIdempotencyService`** — Client-side idempotency key management. `generate(opKey)` returns a live key or creates a new UUID-based one with TTL. `wrap(opKey, fn)` executes `fn(key)` and auto-clears on success (retains on failure for retry). `get(opKey)` / `clear(opKey)` / `clearAll()` / `gc()`. Keys survive page reload via `JoopStorageAdapter`.
348
+
349
+ ### Bug fixes
350
+
351
+ - **`JoopSecretSharing`** — Fixed `_modMul` called with two arguments instead of three (missing `PRIME`), causing `"Cannot mix BigInt and other types"` on share recovery.
352
+ - **`JoopSyncEngine`** tests — `sync()` was guarded by `!this._online`; tests now explicitly set `_online` state before calling `engine.sync()`.
353
+ - **`JoopBehavioralBiometrics`** — Event handler signatures (`MouseEvent`, `TouchEvent`) cast to `EventListener` for TypeScript 5.9 strict DTS compatibility.
354
+
355
+ ---
356
+
357
+ ## [1.4.0] — Platform Services Pack
358
+
359
+ **16 new services · 160 new tests · 655 tests total**
360
+
361
+ ### Added
362
+
363
+ #### `joopjs/storage` addition
364
+
365
+ - **`JoopIndexedDbService`** — Promise-based IndexedDB wrapper. `open(config)` creates stores with optional indexes. CRUD: `get<T>(store, key)`, `set(store, key, value)`, `delete(store, key)`, `getAll<T>(store)`, `getAllKeys(store)`, `bulkSet(store, entries)`. `query(store, indexName, range)` for indexed range queries. `count(store)` / `clear(store)` / `deleteDatabase()`. Full TypeScript generics throughout.
366
+
367
+ #### `joopjs/encryption` addition
368
+
369
+ - **`JoopCryptoUtils`** — Standalone WebCrypto utilities (also re-exported from `joopjs/utilities`). SHA-256/512/1 digest. HMAC-SHA256/512 with timing-safe `verify()`. PBKDF2 key derivation. `hashPassword(password, iterations?)` / `verifyPassword(password, hash)`. `randomBytes(n)` / `uuid()`. `hexToBytes` / `bytesToHex` / `bytesToBase64` / `base64ToBytes`. AES-GCM `deriveKey(password)`.
370
+
371
+ #### `joopjs/forms` — Form Builder (new sub-path)
372
+
373
+ - **`JoopFormBuilder`** — Reactive form state management without framework coupling. **`JoopField<T>`** tracks: `value`, `dirty`, `touched`, `valid`, `errors[]` — integrated with any `JoopValidationRule[]`. **`JoopForm`** aggregates multiple fields and exposes: `valid`, `dirty`, `getValue()`, `errors()`, `reset()`, `markAllTouched()`, `state$()` observable. `build(config)` factory.
374
+
375
+ #### `joopjs/core` additions
376
+
377
+ - **`JoopRateLimiter`** — `throttle(fn, ms)`, `debounce(fn, ms, immediate?)`, `debounceAsync(fn, ms)`, `once(key, fn)` per-key guard. Named bucket registry via `getBucket(name)`.
378
+
379
+ - **`JoopTokenBucket`** — Standalone token bucket: configurable `capacity` + `refillRate`. `consume(tokens?)` / `tryConsume(tokens?)` (waits for availability via polling). `available()` / `reset()`.
380
+
381
+ - **`JoopConsentService`** — GDPR/PDPA cookie consent. Five categories: `necessary / analytics / marketing / functional / personalization`. `grant(category)` / `revoke(category)` / `acceptAll()` / `rejectAll()`. `localStorage` persistence. `state$()` observable. `onChange(category, handler)` per-category callbacks.
382
+
383
+ #### `joopjs/session` addition
384
+
385
+ - **`JoopIdleService`** — Two-tier user idle detection. Listens to configurable DOM events (`mousemove`, `keydown`, `scroll`, `touchstart`). `idleMs` triggers `'idle'`; `expiredMs` triggers `'expired'`. `state$()` observable. `onIdle()` / `onActive()` / `onExpired()` callbacks. `reset()` restarts the timer.
386
+
387
+ #### `joopjs/utilities` additions
388
+
389
+ - **`JoopBarcodeService`** — Pure-SVG barcode generators. **Code128B** (full ASCII, mod-103 checksum). **EAN-13** (L/G/R parity encoding, check-digit validation). **Code39** (alphanumeric). `generateBarcodeDataUrl(text, type, options?)` for inline use.
390
+
391
+ - **`JoopPdfService`** — Minimal PDF 1.4 writer, zero dependencies. Text placement `text(x, y, content, options?)`. Line drawing `line(x1, y1, x2, y2)`. Filled/stroked rectangles. Auto-zebra tables with colored headers. Convenience builders: `receipt(lines)` / `statement(data)`. Output: `toDataUrl()` / `download(filename)`.
392
+
393
+ - **`JoopNotificationService`** — Web Push API wrapper: `requestPermission()`, `show(options)` (browser notification or SW notification), VAPID `subscribe(vapidKey)` / `unsubscribe()`, `onMessage(handler)` from service worker, `permission$()` observable.
394
+
395
+ - **`JoopGeoService`** — Geolocation: `getPosition(options?)` / `watchPosition(handler, options?)`. Haversine `distanceBetween(a, b)`. `isInRadius(center, point, radiusKm)`. Compass `bearing(from, to)`. `toDms(coord)` / `toDecimal(dms)`. `getPermissionState()`.
396
+
397
+ - **`JoopMediaService`** — Camera/microphone/screen access. `requestCamera()` / `requestMicrophone()` / `requestScreenShare()`. `capturePhoto(stream)` → `Blob`. `createRecorder(stream, options)` → `JoopMediaRecorder` with `start()` / `stop()` / `pause()` / `getBlob()`. `getDevices()` / `checkPermission(type)` / `attachStream(el, stream)`.
398
+
399
+ - **Chart data utilities** — `bucketByTime(data, interval)` (hourly/daily/weekly/monthly/yearly). `rollingAverage(data, window)`. `normalize(data)`. `cumulative(data)`. `movingSum(data, window)`. `aggregateByCategory(data, key)`. `percentChange(data)`. `detectTrend(data)` via linear regression. `sparklinePoints(data)` / `sparklineSvg(data, options)`.
400
+
401
+ #### `joopjs/ui` additions
402
+
403
+ - **`JoopA11yService`** — Accessibility utilities. `announce(message, politeness?)` uses ARIA live regions. `trapFocus(el, options?)` constrains Tab navigation; `releaseFocus(el)` / `releaseAllTraps()`. `createSkipLink(target, label?)`. `setPageTitle(title)`. `getFocusable(el)` returns all focusable descendants. `visuallyHide(el)` / `visuallyShow(el)`. `onFocusChange(handler)`.
404
+
405
+ - **`JoopVirtualScroll<T>`** — Virtualized list. Only renders the visible window + configurable `overscan` items. Top/bottom `JoopBehaviorSubject`-driven spacer elements maintain scroll height. `updateItems(items)` / `scrollTo(index)` / `getVisibleRange()` / `onRangeChange(handler)`.
406
+
407
+ #### `joopjs/pwa` — PWA (new sub-path)
408
+
409
+ - **`JoopServiceWorkerService`** — Service worker lifecycle: `register(url, options?)` / `unregister()`. Update detection via `onUpdateAvailable(handler)` (fires when a waiting worker is found). `postMessage(data)` / `onMessage(handler)` for SW communication. `onlineState$()` reflects `navigator.onLine`. `state$()` tracks `'unregistered' | 'installing' | 'installed' | 'activated'`.
410
+
411
+ #### `joopjs/router` — SPA Router (new sub-path)
412
+
413
+ - **`JoopRouterService`** — History API SPA routing. `navigate(path, state?)` / `replace(path)` / `back()` / `forward()` / `go(delta)`. Async guards with abort support: `addGuard(guard)`. `match(pattern)` with `:param` extraction and wildcard support. `buildUrl(pattern, params, query?)`. `parseUrl(url)` → `{ path, params, query, hash }`. `route$()` observable.
414
+
415
+ ### Changed
416
+
417
+ - `JoopInstance` extended with 13 new service fields: `indexedDb`, `crypto`, `formBuilder`, `rateLimiter`, `idle`, `consent`, `pdf`, `notification`, `a11y`, `router`, `sw`, `geo`, `media`.
418
+ - `package.json` — 3 new sub-path exports: `./forms`, `./pwa`, `./router`.
419
+
420
+ ---
421
+
422
+ ## [1.3.0] — Enterprise Feature Pack
423
+
424
+ **15 new services · 143 new tests · 495 tests total**
425
+
426
+ ### Added
427
+
428
+ #### `joopjs/cache` — TTL Cache (new sub-path)
429
+
430
+ - **`JoopCacheService`** — TTL in-memory cache with LRU eviction. `set<T>(key, value, ttlMs?)` / `get<T>(key)` (null on expiry, auto-deletes on read). `getOrSet<T>(key, factory, ttlMs?)` — compute-and-cache, factory called once. `has(key)` checks expiry. `prune()` removes expired entries (returns count). `ttl(key)` remaining ms or -1. `extend(key, ttlMs)`. `stats()` → `{ size, maxSize, totalHits }`. LRU eviction by `createdAt` when `maxSize` is reached.
431
+
432
+ #### `joopjs/network` — WebSocket (new sub-path)
433
+
434
+ - **`JoopWebSocketService`** — Auto-reconnect WebSocket with message queue. `connect(url, protocols?)` / `disconnect()`. `send(data: string | object)` — JSON-serialises objects; queues while disconnected. `on(type)` — filtered observable per message type. `state$()` → `'connecting' | 'open' | 'closing' | 'closed'`. `message$()` — all incoming messages as `JoopWsMessage`. Auto-reconnect up to `maxReconnects` with `reconnectMs` delay. Optional `pingIntervalMs` keep-alive.
435
+
436
+ #### `joopjs/analytics` — Analytics (new sub-path)
437
+
438
+ - **`JoopAnalyticsService`** — Adapter-pattern event pipeline. `addAdapter(adapter)` / `removeAdapter(name)`. `track(name, props?)` — emits to all adapters, queues events before first adapter. `page(name, props?)` — calls adapter `page()` and auto-tracks `page:<name>`. `identify(userId, traits?)`. `flush()` drains pre-adapter queue. `setContext(ctx)` merges into all event properties. `events$()` observable. **`consoleAnalyticsAdapter`** — built-in dev adapter.
439
+
440
+ #### `joopjs/validation` — Validation (new sub-path)
441
+
442
+ - **`JoopFormValidator`** — Rule-based form validation, no dependencies. Individual validators: `required`, `email`, `phone` (E.164), `minLength`, `maxLength`, `min`, `max`, `amount`, `iban`, `luhn`, `pattern`, `dateRange`. Each returns `string | null` (error or valid). `validate(value, rules)` → `{ valid, errors[] }`. `validateForm(form, schema)` → `Record<field, errors[]>`. `passwordStrength(password)` → `{ score: 0-4, label, suggestions[] }`.
443
+
444
+ #### `joopjs/core` additions
445
+
446
+ - **`JoopFeatureFlagService`** — Client-side feature flags with targeting. `define(flags)` / `loadFromUrl(url)`. `isEnabled(key, context?)` evaluates: `environments[]`, `allowedUsers[]`, `rolloutPercent` (deterministic FNV-1a hash). `setOverride(key, value)` / `clearOverrides()`. `getVariant(key, context?)`. `flags$()` observable.
447
+
448
+ #### `joopjs/auth` additions
449
+
450
+ - **`JoopMfaService`** — Multi-factor authentication orchestration.
451
+ - **TOTP**: `generateTotpSecret(length?)`, `getTotpUri(secret, account, issuer?)`, `setupTotp(account, issuer?)` → `{ secret, uri, backupCodes }`, `verifyTotp(token, secret, window?)`.
452
+ - **OTP Challenges**: `createChallenge(dest, channel, ttlMs?, maxAttempts?)` → challenge with `_code` for delivery, `verifyChallenge(id, token)` → `{ success, reason, attemptsLeft }`.
453
+ - **Backup Codes**: `generateBackupCodes(count?, length?)`, `hashBackupCodes(codes)` (SHA-256), `verifyBackupCode(code, hashedCodes)` → `{ valid, remaining[] }`.
454
+ - **Biometric**: `isBiometricAvailable()`, `registerBiometric(userId, displayName?)`, `verifyBiometric(credentialId)`.
455
+
456
+ #### `joopjs/encryption` addition
457
+
458
+ - **`JoopE2EService`** — RSA + AES-GCM hybrid end-to-end encryption.
459
+ - Key gen: `generateKeyPair(bits?)` (RSA-OAEP) / `generateSigningKeyPair(bits?)` (RSA-PSS).
460
+ - PEM I/O: `export/importPublicKeyPem`, `export/importPrivateKeyPem`. JWK I/O: `export/importPublicKeyJwk`.
461
+ - Hybrid: `encryptForRecipient(plaintext, publicKey)` → `JoopE2EPayload` (RSA-OAEP wraps ephemeral AES-GCM key). `decryptFromSender(payload, privateKey)`. Handles arbitrary payload sizes.
462
+ - Signatures (RSA-PSS, saltLength=32): `sign(data, privateKey)` → base64, `verify(data, sig, publicKey)` → boolean.
463
+ - Session keys: `generateSessionKey()` / `wrapSessionKey(key, recipientPk)` / `unwrapSessionKey(wrapped, sk)`.
464
+ - Direct RSA (< 190 bytes): `encryptRaw` / `decryptRaw`. Fingerprint: `fingerprint(publicKey)` → SHA-256 hex.
465
+
466
+ #### `joopjs/ui` additions
467
+
468
+ - **`JoopPaginationService`** — Page state manager. `setTotal(n)` / `setPage(n)` / `setPageSize(n)` — all clamp and recalculate. `nextPage()` / `prevPage()` / `firstPage()` / `lastPage()`. `getState()` → `{ page, pageSize, total, totalPages, hasPrev, hasNext, from, to }`. `getPages(maxVisible?)` → number array with ellipsis as `-1`. `state$()` observable.
469
+
470
+ - **`JoopPrintService`** — Browser print utilities. `printElement(el, title?, styles?)` opens a print window with cloned HTML. `printHtml(html, title?)`. `printReceipt(data)` — monospace receipt with padded label-value columns. `buildReceiptText(lines)` for preview without printing.
471
+
472
+ #### `joopjs/api` additions
473
+
474
+ - **`JoopExportService`** — CSV/JSON/text file downloads. `toCsv(data, options?)` — headers, delimiter, BOM, null-value config. Quote-escaping doubles `"` inside values. `tableToCsv(rows, headers?)`. `downloadCsv / downloadExcel / downloadJson / downloadText`.
475
+
476
+ #### `joopjs/banking` additions
477
+
478
+ - **Luhn algorithm + card utilities** — `validateLuhn(cardNumber)`, `luhnCheckDigit(partial)`, `getCardNetwork(cardNumber)` → `visa | mastercard | amex | discover | unionpay | jcb | diners | maestro | unknown`, `getCardInfo(cardNumber)` → `{ network, valid, lengths[], cvvLength, formatted }`, `formatCardNumber(cardNumber)`, `isCardExpired(month, year)`, `validateCvv(cvv, network?)`.
479
+
480
+ #### `joopjs/utilities` additions
481
+
482
+ - **`JoopClipboardService`** + `clipboard` singleton — `copy(text)` (`navigator.clipboard` → `execCommand` fallback), `paste()`, `copyElement(el)`, `events$()` observable.
483
+
484
+ - **`JoopImageService`** — Canvas-based image utilities: `compress(file, options?)` (JPEG/WebP), `resize(file, w, h)`, `toBase64(file)`, `getInfo(file)` → `{ width, height, size, type }`, `validate(file, options)` → `{ valid, errors[] }`, `thumbnail(file, size?)`.
485
+
486
+ - **Date & Hijri utilities** — `isBusinessDay`, `addBusinessDays`, `getBusinessDaysBetween` (configurable weekends — Fri/Sat for Gulf). `toHijri(date)` / `fromHijri(y, m, d)` via Julian Day Number. `formatHijri`, `formatDate(date, format, locale?)`, `timeAgo(date, locale?)`, `parseDate`, `daysBetween`, `isDateInRange`.
487
+
488
+ - **QR code generator** (`generateQr`, `generateQrDataUrl`, `generatePaymentQr`) — ISO 18004 compliant, versions 1-10. EC levels `L | M | Q | H`. Full Reed-Solomon over GF(256). All 8 mask patterns evaluated by penalty score. Finder/alignment/timing patterns, dark module, format info. Pure SVG output, no dependencies. `generatePaymentQr(amount, currency, reference, options?)`.
489
+
490
+ ### `JoopInstance` new fields (v1.3.0)
491
+
492
+ `cache`, `ws`, `analytics`, `featureFlags`, `mfa`, `e2e`, `formValidator`, `pagination`, `print`, `exporter`, `clipboard`, `image`
493
+
494
+ ---
495
+
496
+ ## [1.2.0] — Framework-Agnostic Services Pack
497
+
498
+ **9 new services · 94 new tests · 352 tests total**
499
+
500
+ Expanded the SDK with theme, i18n, UI, and session services rewritten as framework-agnostic TypeScript — no Angular or RxJS dependencies.
501
+
502
+ ### Added
503
+
504
+ #### `joopjs/theme` — Theme Engine (new sub-path)
505
+
506
+ - **`JoopThemeService`** — CSS custom-property theme engine. `load(themesOrUrl)` registers theme definitions from an inline array or remote JSON. `apply(theme | name)` / `applyById(id)` / `applyDefault()` switch themes at runtime. Each palette generates CSS variables: `--joop-pr-500: #1976d2`, `--joop-pr-c-500: #ffffff` (contrast). `applyVars(vars)` injects arbitrary CSS custom properties. `getMapped()` → `JoopThemeInfo[]` for theme-picker UIs. `active$()` / `activeId$()` observables.
507
+
508
+ #### `joopjs/i18n` — Internationalisation (new sub-path)
509
+
510
+ - **`JoopI18nService`** — Language, culture, and RTL management. Auto-detects RTL for 14 languages: `ar`, `arc`, `ckb`, `dv`, `fa`, `ha`, `he`, `khw`, `ks`, `ps`, `sd`, `ur`, `uz_AF`, `yi`. `setLanguage(lang)` / `setLanguageCulture(culture)`. `loadFromUrl(lang, url)` / `loadFromObject(lang, obj)` — repeated calls merge translations. `t(key, params?)` — dot-notation key resolution (`'ERRORS.TITLE'`) with `{{ param }}` interpolation; falls back to fallback language then raw key. `isRtl()` / `getDirection()` / `applyDirection(el?)`. `language$()` / `culture$()` observables.
511
+
512
+ #### `joopjs/ui` — UI Services (new sub-path)
513
+
514
+ - **`JoopLoaderService`** — Request-counter loading state. `show()` / `hide()` increment/decrement a counter: loader shows when `0 → 1`, hides when it returns to `0`. No flicker on concurrent requests. `forceShow()` / `reset()`. Optional `delayMs` to suppress brief-request spinners. `isLoading()` / `isLoading$()` / `pendingCount`.
515
+
516
+ - **`JoopAlertService`** — Pure-DOM toast and dialog system, zero framework dependency. Toasts: `toast(message, options?)` — four types (`success / error / warning / info`), four positions, auto-dismiss, optional close button. Dialogs: `dialog(options)` → `Promise<string>` (button action). Inline alerts: `showInline(data)` / `hideInline()` / `inline$()`. `open$()` / `dismiss()`.
517
+
518
+ #### `joopjs/native-bridge` — Native Bridge (new sub-path)
519
+
520
+ - **`JoopNativeBridgeService`** — Bidirectional native-WebView message bridge. `sendToNative(target, method, data)` auto-detects: iOS `webkit.messageHandlers`, Android `window[target][method]`, legacy `document.location.href` scheme. `dispatch(message)` pushes to JS-side subscribers. `onMessage(type)` filtered subscription. `startListening(allowedOrigins?)` registers `window.message` with optional origin allowlist. `allMessages$()` / `destroy()`.
521
+
522
+ #### `joopjs/deeplink` — Deeplink (new sub-path)
523
+
524
+ - **`JoopDeeplinkService`** — Cross-tab deeplink coordination via `localStorage` storage events. `setModule(module, data?)` writes and immediately removes the payload (so the event fires reliably), emits `close$(true)`. `startListening(key?)` installs a storage event handler. `requestClose()` emits `close$(false)`. `readIncoming(key?)` reads a payload left by another tab on page load. `close$()` / `incoming$()` / `module$()` observables.
525
+
526
+ #### `joopjs/api` additions
527
+
528
+ - **`JoopFileSaverService`** — File download utility. `download(url, options?)` fetches, extracts filename from `Content-Disposition`, routes to iOS WebView path (`webkit.messageHandlers` base64 postMessage) or standard browser path (`<a>` + `URL.createObjectURL`). `saveBlob(blob, fileName)` / `blobToBase64(blob)` / `getMimeType(fileName)` / `isIosWebView(handlerName?)`.
529
+
530
+ - **`JoopResponseMapper`** — Normalizes legacy v6 `compDet[]` and current v7+ `components{}` API responses into `JoopMappedResponse`. `map(raw)` auto-detects format. Extracts `scope` (first char: `M/O/N/S`) and `dataKey`. `buildScopedMap(response)` groups by scope prefix. `getComponent(response, key)`. `hasError` flag.
531
+
532
+ #### `joopjs/utilities` additions
533
+
534
+ - `flattenObj(obj)` / `buildQueryString(params)` / `buildFormData(params, files?)` / `urlEncode(params)` / `getRandomNum(min, max)`
535
+
536
+ ### `JoopInstance` new fields (v1.2.0)
537
+
538
+ `theme`, `i18n`, `loader`, `alert`, `nativeBridge`, `deeplink`, `fileSaver`, `responseMapper`
539
+
540
+ ---
541
+
542
+ ## [1.1.0] — Enterprise & Banking Pack
543
+
544
+ **22 new services · 134 new tests · 258 tests total**
545
+
546
+ ### Added
547
+
548
+ #### `joopjs/security` — Secure Storage (new sub-path)
549
+
550
+ - **`JoopSecureStorage`** — AES-GCM encrypted wrapper for `localStorage`, `sessionStorage`, or in-memory storage. Transparently encrypts all values at rest. Returns `null` on decryption failure. `local / session / memory` storage type config. `getItem / setItem / removeItem / clear`.
551
+
552
+ - **Sanitizer utilities** — `escapeHtml`, `stripHtml`, `sanitizeInput`, `stripSqlKeywords`, `sanitizeFileName`, `isValidUrl`, `isValidEmail`, `isValidPhone`, `isAlphanumeric`, `truncate`. XSS and injection prevention at all user-input boundaries.
553
+
554
+ #### `joopjs/auth` additions
555
+
556
+ - **`JoopTokenService`** — JWT access/refresh token management. Decodes JWT payloads (without verification). `isExpired(token)`. Auto-schedules refresh 30s before expiry via `onRefreshNeeded` callback. `setTokens(access, refresh)` / `getAccessToken()` / `getRefreshToken()` / `clearTokens()`.
557
+
558
+ - **`JoopPKCEService`** — RFC 7636 PKCE OAuth2 helper. `generateCodeVerifier()` — 64-byte crypto-random, base64url-encoded. `generateCodeChallenge(verifier)` — SHA-256, base64url-encoded. `generateState()`. `buildAuthUrl(config)` — complete authorization URL with challenge.
559
+
560
+ - **`JoopOtpService`** — TOTP (RFC 6238 / HMAC-SHA-1) and one-time code generation. `generateTotp(secret, time?)` / `verifyTotp(token, secret, window?)`. `generateNumericOtp(length?)` / `generateAlphanumericOtp(length?)` for SMS/email flows.
561
+
562
+ - **`JoopBiometricService`** — WebAuthn/FIDO2 platform authenticator wrapper. `register(userId, displayName, rpId?)` / `authenticate(credentialId, rpId?)` / `isAvailable()` / `generateChallenge()` / `credentialIdToBase64(id)`.
563
+
564
+ #### `joopjs/api` additions
565
+
566
+ - **`JoopInterceptorPipeline`** — Request/response/error interceptor pipeline. `addRequestInterceptor(fn)` / `addResponseInterceptor(fn)` / `addErrorInterceptor(fn)` — each returns an unsubscribe function. `executeRequest(req)` / `executeResponse(res)` / `executeError(err)` runs the chain.
567
+
568
+ - **`withRetry(fn, config)`** — Exponential backoff retry. `maxAttempts`, `baseDelayMs`, `maxDelayMs`, `jitter` (multiplicative), `retryOn(err)` predicate to skip non-retriable errors.
569
+
570
+ - **`JoopCircuitBreaker`** — Three-state circuit breaker. `closed` (normal) → `open` (blocking after `failureThreshold`) → `half-open` (recovery probe after `timeoutMs`). `execute(fn)` / `reset()` / `getState()`.
571
+
572
+ - **`JoopOfflineQueue`** — Queues requests when offline, drains on `window.online`. `enqueue(fn)` / `drainNow()` / `clear()` / `size`.
573
+
574
+ - **`JoopPollingService`** — Interval-based polling. `start(name, fn, intervalMs, options?)` — `immediate` first-run, `stopWhen(result)` predicate, `onError(err)` handler. `stop(name)` / `stopAll()`. `result$(name)` observable.
575
+
576
+ #### `joopjs/session` additions
577
+
578
+ - **`JoopMultiTabSync`** — `BroadcastChannel`-based cross-tab event bus. `broadcast(type, payload?)` / `on(type, handler)`. Built-in types: `logout`, `login`, `session-warning`, `token-refresh`. Filters own messages automatically.
579
+
580
+ - **`JoopConcurrentSessionService`** — Heartbeat-based duplicate session detection. Broadcasts a session ID at `heartbeatMs` intervals. `onDuplicateDetected(handler)` / `start()` / `stop()`.
581
+
582
+ #### `joopjs/observability` — Observability (new sub-path)
583
+
584
+ - **`JoopCorrelationService`** — Generates and tracks `X-Correlation-ID` + `X-Request-ID`. `headers()` → `Record<string, string>`. `newCorrelationId()` / `currentCorrelationId()`.
585
+
586
+ - **`JoopAuditLog`** — Bounded, immutable audit trail. Records: login, logout, transfer, profile-change, biometric, custom. `addEntry(action, details?)` / `getEntries(filter?)` / `exportJson()` / `onEntry(handler)`. Configurable `maxEntries`.
587
+
588
+ - **`JoopPerformanceService`** — `mark(name)` / `measure(name, start, end?)` pair. `timeAsync(name, fn)` / `timeSync(name, fn)` wrappers. `getAverage(name)` for baselines. `getMark(name)` / `getAll()`.
589
+
590
+ - **`JoopErrorReporter`** — Pluggable error capture. `addHandler(fn)` / `report(error, context?)`. Enriches each `JoopErrorReport` with `userId`, `sessionId`, structured context. `clearHandlers()`.
591
+
592
+ #### `joopjs/device` — Device (new sub-path)
593
+
594
+ - **`JoopDeviceFingerprintService`** — SHA-256 fingerprint from user agent, language, timezone, screen resolution, hardware concurrency, and touch points. `fingerprint()` (async). `getStableId()` caches in `localStorage` for consistent cross-session identification.
595
+
596
+ #### `joopjs/dev` — Developer Tools (new sub-path)
597
+
598
+ - **`JoopMockService`** — Intercepts `fetch` globally in development. `register(pattern, handler, options?)` — string substring or RegExp URL matching with optional method filter and `delayMs`. `enable()` / `disable()` at runtime without reload. `unregister(pattern)` / `clear()`.
599
+
600
+ #### `joopjs/banking` — Banking Utilities (new sub-path)
601
+
602
+ **Masking** — `maskCard`, `formatCard`, `maskIban`, `maskAccountNumber`, `maskEmail`, `maskPhone`, `maskName`
603
+
604
+ **IBAN** — `validateIban` (mod-97, 80 countries), `formatIban` (4-char groups), `parseIban` → `{ country, checkDigits, bban }`, `getIbanCountry`, `getSupportedIbanCountries`
605
+
606
+ **Currency & Amounts** — `formatCurrency` (Intl.NumberFormat), `parseCurrencyString`, `convertCurrency`, `getCurrencySymbol`, `formatAmount`. Safe arithmetic (integer-based): `safeAdd`, `safeSubtract`, `safeMultiply`, `safeDivide`, `roundAmount`, `toMinorUnits`, `fromMinorUnits`, `sumAmounts`, `clampAmount`, `isValidAmount`.
607
+
608
+ **Transaction IDs** — `generateTransactionId(prefix?)` → `TXN-<timestamp>-<hex>`, `generateReferenceNumber`, `parseTransactionId`, `isValidTransactionId`, `generateBatchId` → `BATCH-<hex>`
609
+
610
+ **Receipts** — `JoopReceiptService` — structured receipt builder with plain-text, JSON, and HTML renderers.
611
+
612
+ ### `JoopInstance` new fields (v1.1.0)
613
+
614
+ `secureStorage`, `token`, `pkce`, `otp`, `biometric`, `interceptors`, `circuitBreaker`, `offlineQueue`, `polling`, `multiTab`, `concurrentSession`, `correlation`, `auditLog`, `perf`, `errorReporter`, `deviceFingerprint`, `receipt`, `mock`
615
+
616
+ ---
617
+
618
+ ## [1.0.0] — Initial Release
619
+
620
+ **14 services · 124 tests · 10 test files**
621
+
622
+ ### Added
623
+
624
+ #### Reactive primitives (framework-agnostic)
625
+
626
+ - **`JoopSubject`** — Pub/sub with `subscribe(fn)` / `next(value)` / `unsubscribe(fn)` / `complete()`. Returns an unsubscribe function.
627
+ - **`JoopBehaviorSubject<T>`** — Extends `JoopSubject`; holds the current value. New subscribers receive the last emitted value immediately. `getValue()` synchronous read.
628
+ - **`JoopObservable<T>`** — Read-only view over a `JoopSubject`. `subscribe(fn)` / `pipe(fn)` for synchronous transforms.
629
+
630
+ #### `joopjs/core` — Core Services (new sub-path)
631
+
632
+ - **`JoopConfigService`** / `configService` singleton — `load(urlOrObject)` fetches remote JSON or accepts an inline object. `get<T>(key, default?)` nested dot-notation access. `set(key, value)` / `has(key)` / `reset()`. `config$()` observable.
633
+ - **`JoopLogger`** / `logger` singleton — Configurable logging with pub/sub. Levels: `debug / info / warn / error`. Per-level filtering. `onLog(handler)` for structured log forwarding. `setLevel(level)` / `disable()` / `enable()`.
634
+
635
+ #### `joopjs/storage` — Storage (new sub-path)
636
+
637
+ - **`JoopScopeMapService`** — Four-scope in-memory store: `app`, `page`, `screen`, `session`. `set(scope, key, value)` / `get(scope, key)` / `delete(scope, key)` / `clear(scope)` / `getAll(scope)`.
638
+ - **`JoopDataStorage`** — Typed scope-based key-value store with `menu$()` observable. `setData(scope, key, value)` / `getData(scope, key)` / `deleteKey(scope, key)` / `clearScope(scope)`.
639
+
640
+ #### `joopjs/auth` — Auth (new sub-path)
641
+
642
+ - **`JoopAuthService`** — Login state observable. `login(user)` / `logout()` / `isLoggedIn()` / `user$()` / `getUser()`.
643
+
644
+ #### `joopjs/api` — HTTP Client (new sub-path)
645
+
646
+ - **`JoopHttpClient`** — Fetch-based HTTP client. `get/post/put/patch/delete(url, options?)`. Configurable `timeoutMs`. Upload progress via `onUploadProgress`. `setBaseUrl(url)` / `setDefaultHeaders(headers)`. Returns typed `JoopResponse<T>`.
647
+ - **`JoopRequestService`** — High-level dispatcher. `send(config)` with E2E encryption support (AES/RSA orchestration), loader tracking, and error normalization. `sendBackground(config)` for fire-and-forget.
648
+ - `isHttpError(err)` — type guard for `JoopHttpError`.
649
+
650
+ #### `joopjs/encryption` — Encryption (new sub-path)
651
+
652
+ - **`JoopGcmService`** — AES-256-GCM symmetric encryption. `encrypt(data, key)` / `decrypt(ciphertext, key)` via WebCrypto. `generateKey()` / `exportKey(key)` / `importKey(raw)`.
653
+ - **`JoopRsaService`** — RSA-OAEP-SHA256 asymmetric encryption. `generateKeyPair()` / `encrypt(data, publicKey)` / `decrypt(ciphertext, privateKey)`. SPKI/PKCS8 key export/import.
654
+ - **`JoopAesService`** — AES E2E orchestrator: session-key mode (RSA-wrapped AES session key) and request mode (per-request AES-GCM + RSA key transport). Used by `JoopRequestService`.
655
+ - **`JoopX25519Service`** — X25519 ECDH key exchange via `@noble/curves`. `generateKeyPair()`. `computeSharedSecret(privateKey, publicKey)`. HKDF-SHA512 key derivation into ChaCha20-Poly1305. `encrypt(data, recipientPublic)` / `decrypt(ciphertext, privateKey, senderPublic)`.
656
+
657
+ #### `joopjs/session` — Session (new sub-path)
658
+
659
+ - **`JoopSessionTimeoutService`** — Two-stage idle session timeout. Listens to DOM activity events. `warningMs` triggers a warning; `timeoutMs` triggers logout. `onWarning(handler)` / `onTimeout(handler)`. `reset()` / `start()` / `stop()`.
660
+
661
+ #### `joopjs/` — Core models and utilities
662
+
663
+ - **`JoopClientProfile`** / `clientProfile` singleton — Runtime session state holder. `set(profile)` / `get()` / `profile$()` / `clear()`.
664
+ - **`JoopPluginService`** — `install(plugin, context?)` / `uninstall(name)` / `getPlugin(name)`. Prevents duplicates. Async `install` hooks.
665
+ - **`JoopEnvironmentService`** — Named environment profiles with `apiBaseUrl` and feature flags. `detect()` via `NODE_ENV` / hostname. `isFeatureEnabled(flag)`.
666
+ - **`JoopHealthService`** — `register(name, checkFn)` / `registerPingUrl(name, url)` / `runAll()` → `JoopHealthCheckResult[]` with latency.
667
+
668
+ #### Utility functions
669
+
670
+ `removeTrailingSlash`, `objectToQueryString`, `deepClone`, `randomString`, `bufferToHex`, `getDeviceInfo`, `isBrowser`
671
+
672
+ ### Build
673
+
674
+ - Dual ESM + CJS bundles via tsup
675
+ - Full TypeScript declarations (`.d.ts`)
676
+ - 6 sub-path exports: `joopjs/encryption`, `joopjs/storage`, `joopjs/auth`, `joopjs/api`, `joopjs/core`, `joopjs/session`
677
+ - External peer deps: `@noble/ciphers`, `@noble/curves`, `base64-arraybuffer`
678
+ - Zero Angular / RxJS / framework dependencies