joopjs 2.0.5 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/.claude/skills/auth.md +235 -0
  2. package/.claude/skills/banking.md +377 -0
  3. package/.claude/skills/encryption.md +265 -0
  4. package/.claude/skills/finance.md +248 -0
  5. package/.claude/skills/observables.md +270 -0
  6. package/.claude/skills/security.md +240 -0
  7. package/.claude/skills/setup.md +196 -0
  8. package/.cursor/rules/joopjs.mdc +150 -0
  9. package/.github/copilot-instructions.md +143 -0
  10. package/.windsurf/rules/joopjs.md +226 -0
  11. package/CHANGELOG.md +81 -0
  12. package/README.md +47 -7
  13. package/ai-rules/AGENTS.md +241 -0
  14. package/ai-rules/GEMINI.md +183 -0
  15. package/dist/ai/index.js +15 -3
  16. package/dist/ai/index.js.map +1 -1
  17. package/dist/ai/index.mjs +15 -3
  18. package/dist/ai/index.mjs.map +1 -1
  19. package/dist/analytics/index.js +10 -2
  20. package/dist/analytics/index.js.map +1 -1
  21. package/dist/analytics/index.mjs +10 -2
  22. package/dist/analytics/index.mjs.map +1 -1
  23. package/dist/angular/index.d.mts +98 -27
  24. package/dist/angular/index.d.ts +98 -27
  25. package/dist/angular/index.js +44 -0
  26. package/dist/angular/index.js.map +1 -1
  27. package/dist/angular/index.mjs +39 -1
  28. package/dist/angular/index.mjs.map +1 -1
  29. package/dist/api/index.js +15 -3
  30. package/dist/api/index.js.map +1 -1
  31. package/dist/api/index.mjs +15 -3
  32. package/dist/api/index.mjs.map +1 -1
  33. package/dist/auth/index.js +15 -3
  34. package/dist/auth/index.js.map +1 -1
  35. package/dist/auth/index.mjs +15 -3
  36. package/dist/auth/index.mjs.map +1 -1
  37. package/dist/banking/index.js +15 -3
  38. package/dist/banking/index.js.map +1 -1
  39. package/dist/banking/index.mjs +15 -3
  40. package/dist/banking/index.mjs.map +1 -1
  41. package/dist/cache/index.js +15 -3
  42. package/dist/cache/index.js.map +1 -1
  43. package/dist/cache/index.mjs +15 -3
  44. package/dist/cache/index.mjs.map +1 -1
  45. package/dist/{index-DFqEoX_l.d.ts → consent.service-CIHNtx9h.d.ts} +1 -2
  46. package/dist/{index-B_ksKpS1.d.mts → consent.service-DQ-JAEJx.d.mts} +1 -2
  47. package/dist/core/index.d.mts +34 -1
  48. package/dist/core/index.d.ts +34 -1
  49. package/dist/core/index.js +56 -5
  50. package/dist/core/index.js.map +1 -1
  51. package/dist/core/index.mjs +54 -6
  52. package/dist/core/index.mjs.map +1 -1
  53. package/dist/deeplink/index.js +15 -3
  54. package/dist/deeplink/index.js.map +1 -1
  55. package/dist/deeplink/index.mjs +15 -3
  56. package/dist/deeplink/index.mjs.map +1 -1
  57. package/dist/device/index.js +15 -3
  58. package/dist/device/index.js.map +1 -1
  59. package/dist/device/index.mjs +15 -3
  60. package/dist/device/index.mjs.map +1 -1
  61. package/dist/forms/index.js +15 -3
  62. package/dist/forms/index.js.map +1 -1
  63. package/dist/forms/index.mjs +15 -3
  64. package/dist/forms/index.mjs.map +1 -1
  65. package/dist/i18n/index.js +15 -3
  66. package/dist/i18n/index.js.map +1 -1
  67. package/dist/i18n/index.mjs +15 -3
  68. package/dist/i18n/index.mjs.map +1 -1
  69. package/dist/index.d.mts +2 -2
  70. package/dist/index.d.ts +2 -2
  71. package/dist/index.js +50 -8
  72. package/dist/index.js.map +1 -1
  73. package/dist/index.mjs +50 -8
  74. package/dist/index.mjs.map +1 -1
  75. package/dist/{joop-CA3DMeOO.d.ts → joop-Dim2yEKG.d.ts} +1 -1
  76. package/dist/{joop-Bx7Iwj5p.d.mts → joop-GkQw13f9.d.mts} +1 -1
  77. package/dist/native-bridge/index.js +10 -2
  78. package/dist/native-bridge/index.js.map +1 -1
  79. package/dist/native-bridge/index.mjs +10 -2
  80. package/dist/native-bridge/index.mjs.map +1 -1
  81. package/dist/network/index.js +15 -3
  82. package/dist/network/index.js.map +1 -1
  83. package/dist/network/index.mjs +15 -3
  84. package/dist/network/index.mjs.map +1 -1
  85. package/dist/observability/index.js +15 -3
  86. package/dist/observability/index.js.map +1 -1
  87. package/dist/observability/index.mjs +15 -3
  88. package/dist/observability/index.mjs.map +1 -1
  89. package/dist/pwa/index.js +15 -3
  90. package/dist/pwa/index.js.map +1 -1
  91. package/dist/pwa/index.mjs +15 -3
  92. package/dist/pwa/index.mjs.map +1 -1
  93. package/dist/react/index.d.mts +2 -2
  94. package/dist/react/index.d.ts +2 -2
  95. package/dist/react/index.js +15 -3
  96. package/dist/react/index.js.map +1 -1
  97. package/dist/react/index.mjs +15 -3
  98. package/dist/react/index.mjs.map +1 -1
  99. package/dist/router/index.js +15 -3
  100. package/dist/router/index.js.map +1 -1
  101. package/dist/router/index.mjs +15 -3
  102. package/dist/router/index.mjs.map +1 -1
  103. package/dist/security/index.js +15 -3
  104. package/dist/security/index.js.map +1 -1
  105. package/dist/security/index.mjs +15 -3
  106. package/dist/security/index.mjs.map +1 -1
  107. package/dist/session/index.js +15 -3
  108. package/dist/session/index.js.map +1 -1
  109. package/dist/session/index.mjs +15 -3
  110. package/dist/session/index.mjs.map +1 -1
  111. package/dist/state/index.js +15 -3
  112. package/dist/state/index.js.map +1 -1
  113. package/dist/state/index.mjs +15 -3
  114. package/dist/state/index.mjs.map +1 -1
  115. package/dist/storage/index.js +15 -3
  116. package/dist/storage/index.js.map +1 -1
  117. package/dist/storage/index.mjs +15 -3
  118. package/dist/storage/index.mjs.map +1 -1
  119. package/dist/sync/index.js +15 -3
  120. package/dist/sync/index.js.map +1 -1
  121. package/dist/sync/index.mjs +15 -3
  122. package/dist/sync/index.mjs.map +1 -1
  123. package/dist/theme/index.js +15 -3
  124. package/dist/theme/index.js.map +1 -1
  125. package/dist/theme/index.mjs +15 -3
  126. package/dist/theme/index.mjs.map +1 -1
  127. package/dist/ui/index.js +15 -3
  128. package/dist/ui/index.js.map +1 -1
  129. package/dist/ui/index.mjs +15 -3
  130. package/dist/ui/index.mjs.map +1 -1
  131. package/dist/utilities/index.js +46 -4
  132. package/dist/utilities/index.js.map +1 -1
  133. package/dist/utilities/index.mjs +46 -4
  134. package/dist/utilities/index.mjs.map +1 -1
  135. package/dist/vue/index.d.mts +2 -2
  136. package/dist/vue/index.d.ts +2 -2
  137. package/dist/vue/index.js +15 -3
  138. package/dist/vue/index.js.map +1 -1
  139. package/dist/vue/index.mjs +15 -3
  140. package/dist/vue/index.mjs.map +1 -1
  141. package/dist/workflow/index.js +15 -3
  142. package/dist/workflow/index.js.map +1 -1
  143. package/dist/workflow/index.mjs +15 -3
  144. package/dist/workflow/index.mjs.map +1 -1
  145. package/package.json +96 -32
  146. package/scripts/setup-ai.mjs +133 -0
package/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  **Enterprise-grade, framework-agnostic TypeScript SDK for financial applications.**
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-v2.0.2-blue)](https://www.npmjs.com/package/joopjs)
5
+ [![npm version](https://img.shields.io/badge/npm-v2.1.0-blue)](https://www.npmjs.com/package/joopjs)
6
6
  [![license](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
7
7
  [![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
8
- [![tests](https://img.shields.io/badge/tests-2168%20passed-success)](#)
8
+ [![tests](https://img.shields.io/badge/tests-2189%20passed-success)](#)
9
9
  [![playground](https://img.shields.io/badge/playground-live-orange)](https://kundan-leo.github.io/JoopJs/demo/)
10
10
  [![github](https://img.shields.io/badge/github-kundan--leo%2FJoopJs-black?logo=github)](https://github.com/kundan-leo/JoopJs)
11
11
 
@@ -17,11 +17,14 @@
17
17
 
18
18
  JoopJS provides 80+ production-ready services covering banking, finance, security, authentication, and encryption — all as plain TypeScript classes with no framework dependencies. Works with **React 18+**, **Angular 17+**, **Vue 3+**, or any plain TypeScript/JavaScript project.
19
19
 
20
+ **New in 2.1.0:** real Angular 17+ DI in `joopjs/angular` (`provideJoopAngular`, `injectJoop`, `joopSignal`), federation-safe singletons in `joopjs/core` (`globalSingleton`, `joopCopyCount`, `silenceDuplicateCopyWarning`) for Module Federation micro-frontends, and error-isolated observable emission.
21
+
20
22
  ---
21
23
 
22
24
  ## Table of Contents
23
25
 
24
26
  - [Install](#install)
27
+ - [AI Assistant Setup](#ai-assistant-setup)
25
28
  - [Quick Start](#quick-start)
26
29
  - [Service Catalogue](#service-catalogue)
27
30
  - [Banking](#banking-26-services)
@@ -60,6 +63,33 @@ No mandatory peer dependencies — React / Angular / Vue bindings are opt-in.
60
63
 
61
64
  ---
62
65
 
66
+ ## AI Assistant Setup
67
+
68
+ JoopJS ships rules for all major AI coding tools. One command sets them up in your project:
69
+
70
+ ```bash
71
+ npx joopjs setup-ai
72
+ ```
73
+
74
+ This copies joopjs-aware rules so that **Claude Code**, **Cursor**, **Windsurf**, **GitHub Copilot**, **Gemini CLI**, and **Codex** all understand the joopjs API — correct imports, service patterns, observable rules, and data types.
75
+
76
+ | Tool | What gets copied |
77
+ |------|-----------------|
78
+ | Claude Code | `.claude/skills/joopjs-*.md` — 7 skills (setup, banking, finance, security, auth, encryption, observables) |
79
+ | Cursor | `.cursor/rules/joopjs.mdc` — auto-applied to all `.ts` / `.tsx` / `.js` files |
80
+ | Windsurf | `.windsurf/rules/joopjs.md` — loaded by Cascade automatically |
81
+ | GitHub Copilot | `.github/copilot-instructions.md` |
82
+ | Gemini CLI | `GEMINI.md` |
83
+ | Codex / OpenAI | `AGENTS.md` |
84
+
85
+ ```bash
86
+ npx joopjs setup-ai --force # overwrite after upgrading joopjs
87
+ ```
88
+
89
+ > **Claude Code users:** after running, the command output shows the exact skill lines to add to your `CLAUDE.md`.
90
+
91
+ ---
92
+
63
93
  ## Quick Start
64
94
 
65
95
  ### 1. Initialise
@@ -446,27 +476,33 @@ function BalanceCard({ walletId }: { walletId: string }) {
446
476
 
447
477
  ### Angular
448
478
 
479
+ Real Angular 17+ DI. Only the `joopjs/angular` adapter imports `@angular/*` — the core SDK stays framework-agnostic.
480
+
449
481
  ```typescript
450
482
  // app.config.ts (standalone)
451
483
  import { ApplicationConfig } from '@angular/core';
452
- import { provideJoop } from 'joopjs/angular';
484
+ import { provideJoopAngular } from 'joopjs/angular';
453
485
  import { createJoop } from 'joopjs';
454
486
 
455
487
  export const appConfig: ApplicationConfig = {
456
488
  providers: [
457
- provideJoop(createJoop({ env: 'production', appId: 'my-app' })),
489
+ ...provideJoopAngular(createJoop({ env: 'production', appId: 'my-app' })),
458
490
  ],
459
491
  };
460
492
  ```
461
493
 
462
494
  ```typescript
463
495
  // component.ts
464
- import { inject } from '@angular/core';
465
- import { JOOP_AUTH } from 'joopjs/angular';
496
+ import { injectJoop, joopSignal } from 'joopjs/angular';
497
+ import { JoopAuthService } from 'joopjs';
466
498
 
467
499
  @Component({ ... })
468
500
  export class LoginComponent {
469
- private auth = inject(JOOP_AUTH);
501
+ private joop = injectJoop(); // typed JoopInstance via JOOP_INSTANCE
502
+ private auth = new JoopAuthService();
503
+
504
+ // Bridge any JoopJS observable to an Angular signal — auto-teardown via DestroyRef
505
+ session = joopSignal(this.auth.session$());
470
506
 
471
507
  async login(email: string, password: string) {
472
508
  const session = await this.auth.login(email, password);
@@ -475,6 +511,8 @@ export class LoginComponent {
475
511
  }
476
512
  ```
477
513
 
514
+ > Granular injection tokens still exist, and `joopAuthGuard()` (a `CanActivateFn`) plus `joopAuthInterceptor()` (an `HttpInterceptorFn`) are available for routing and HTTP. `provideJoop()`, `JoopModule`, and `fromJoop()` are deprecated but still functional.
515
+
478
516
  ### Vue
479
517
 
480
518
  ```typescript
@@ -533,6 +571,8 @@ unsub();
533
571
 
534
572
  **Critical rule:** Always use `.next(value)` to emit — **never `.emit(value)`** (that method does not exist).
535
573
 
574
+ Emission is **error-isolated**: `next()` wraps each subscriber call in try/catch over a snapshot of its listeners, so one bad subscriber won't break the stream for the others. Route subscriber errors anywhere with `setSubjectErrorHandler` (default: `console.error`).
575
+
536
576
  ---
537
577
 
538
578
  ## TypeScript Types
@@ -0,0 +1,241 @@
1
+ # AGENTS.md — JoopJS SDK
2
+
3
+ This file instructs AI coding agents (Codex, OpenAI Agents, and similar) on how to generate code using the **joopjs** SDK.
4
+
5
+ ---
6
+
7
+ ## Package
8
+
9
+ ```bash
10
+ npm install joopjs
11
+ ```
12
+
13
+ **joopjs** is a framework-agnostic TypeScript SDK for enterprise financial applications. Works with React, Angular, Vue, Node.js, and plain TypeScript.
14
+
15
+ ---
16
+
17
+ ## Import Rules
18
+
19
+ ```ts
20
+ // Main entry — everything
21
+ import { JoopAuthService, JoopDigitalWalletService } from 'joopjs';
22
+
23
+ // Sub-path imports (tree-shakeable, preferred)
24
+ import { JoopGcmService } from 'joopjs/encryption';
25
+ import { JoopAuthService } from 'joopjs/auth';
26
+ import { JoopCacheService } from 'joopjs/cache';
27
+ ```
28
+
29
+ Available sub-paths: `auth`, `encryption`, `banking`, `security`, `api`, `core`, `session`, `device`, `observability`, `theme`, `i18n`, `ui`, `forms`, `router`, `state`, `workers`, `workflow`, `sync`, `platform`, `cache`, `network`, `analytics`, `validation`, `utilities`, `pwa`, `native-bridge`, `deeplink`, `react`, `angular`, `vue`, `india`.
30
+
31
+ **Never** import from internal paths (`joopjs/src/...`, `joopjs/dist/...`).
32
+
33
+ `joopjs/core` exposes `globalSingleton`, `joopCopyCount`, and `silenceDuplicateCopyWarning`. In Module Federation micro-frontends, share joopjs as a singleton (`shared: { joopjs: { singleton: true } }`) so logger/config/event-bus state does not fragment across multiple loaded copies.
34
+
35
+ ---
36
+
37
+ ## Service Instantiation
38
+
39
+ All services are plain classes — no DI framework, no `@Injectable`, no container:
40
+
41
+ ```ts
42
+ const wallet = new JoopDigitalWalletService();
43
+ const auth = new JoopAuthService();
44
+ const gcm = new JoopGcmService();
45
+ const loans = new JoopLoanServicingService();
46
+ ```
47
+
48
+ Create once per module and reuse as singletons.
49
+
50
+ ---
51
+
52
+ ## Reactive Observables — Critical Rules
53
+
54
+ joopjs uses its own `JoopSubject` — **not RxJS**:
55
+
56
+ ```ts
57
+ // Subscribe — always returns an unsubscribe function
58
+ const unsub = service.event$().subscribe(value => {
59
+ console.log(value);
60
+ });
61
+
62
+ // Emit
63
+ subject.next(newValue); // CORRECT
64
+ subject.emit(newValue); // WRONG — throws, does not exist
65
+
66
+ // Current value (BehaviorSubject only)
67
+ const val = behaviorSubject.getValue();
68
+
69
+ // Clean up
70
+ unsub(); // call the returned function
71
+ // NOT .unsubscribe() // wrong — does not exist
72
+ // NOT subject.pipe(map(...)) // wrong — not RxJS
73
+ ```
74
+
75
+ `next()` is error-isolated: if one subscriber throws, delivery to the other subscribers still proceeds. Route subscriber errors with `setSubjectErrorHandler(fn)` (default `console.error`).
76
+
77
+ ---
78
+
79
+ ## Data Type Rules — Always Follow These
80
+
81
+ | Concept | Correct type | Never use |
82
+ |---------|-------------|-----------|
83
+ | Money amount | `number` | `BigDecimal`, `Money`, `string` |
84
+ | Currency | `string` ISO-4217 | enum, number |
85
+ | Timestamp | `number` Unix epoch ms — `Date.now()` | `new Date()`, `string` |
86
+ | ID | `string` | `number` |
87
+
88
+ ---
89
+
90
+ ## Error Handling
91
+
92
+ ```ts
93
+ try {
94
+ const result = await service.doSomething(config);
95
+ } catch (err) {
96
+ if (err instanceof Error) {
97
+ console.error(err.message);
98
+ }
99
+ }
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Common Code Patterns
105
+
106
+ ### Digital Wallet
107
+ ```ts
108
+ import { JoopDigitalWalletService } from 'joopjs';
109
+
110
+ const wallet = new JoopDigitalWalletService();
111
+ const w = wallet.createWallet('user-001', { currency: 'USD', label: 'Primary' });
112
+ wallet.topUp(w.id, 500);
113
+ wallet.pay(w.id, 50, 'merchant-id', 'Coffee');
114
+ wallet.transfer(w.id, toWalletId, 200);
115
+ const bal = wallet.getBalance(w.id);
116
+ wallet.balance$().subscribe(({ walletId, balance }) => { /* update UI */ });
117
+ ```
118
+
119
+ ### Auth + JWT
120
+ ```ts
121
+ import { JoopAuthService } from 'joopjs/auth';
122
+
123
+ const auth = new JoopAuthService();
124
+ const session = await auth.login(email, password);
125
+ auth.session$().subscribe(session => { /* null = logged out */ });
126
+ await auth.logout(session.sessionId);
127
+ ```
128
+
129
+ ### AES-GCM Encryption
130
+ ```ts
131
+ import { JoopGcmService } from 'joopjs/encryption';
132
+
133
+ const gcm = new JoopGcmService();
134
+ const key = await gcm.generateKey();
135
+ const { ciphertext, iv } = await gcm.encrypt('sensitive', key);
136
+ const plain = await gcm.decrypt(ciphertext, key, iv);
137
+ ```
138
+
139
+ ### Loan Servicing
140
+ ```ts
141
+ import { JoopLoanServicingService } from 'joopjs';
142
+
143
+ const loans = new JoopLoanServicingService();
144
+ const loan = loans.createLoan({
145
+ borrowerName: 'Alice', borrowerId: 'u-001',
146
+ principalAmount: 10000, annualInterestRatePercent: 8,
147
+ tenureMonths: 12, currency: 'USD'
148
+ });
149
+ loans.recordPayment(loan.id, loan.emiAmount);
150
+ const schedule = loans.getSchedule(loan.id);
151
+ ```
152
+
153
+ ### Sanctions Screening
154
+ ```ts
155
+ import { JoopSanctionsScreeningService } from 'joopjs';
156
+
157
+ const sanctions = new JoopSanctionsScreeningService();
158
+ sanctions.loadList('ofac', entities);
159
+ const result = sanctions.screen({ name: customerName, country: customerCountry });
160
+ if (result.status !== 'clear') { /* block or escalate */ }
161
+ ```
162
+
163
+ ### AML
164
+ ```ts
165
+ import { JoopAmlService } from 'joopjs';
166
+
167
+ const aml = new JoopAmlService();
168
+ aml.addRule({ id: 'r1', name: 'Large cash', type: 'cash', threshold: 10000, currency: 'USD', action: 'flag', enabled: true });
169
+ const alert = aml.checkTransaction({ id: 'tx1', amount: 15000, currency: 'USD', type: 'cash', userId: 'u-001', timestamp: Date.now() });
170
+ // null = passes; JoopAmlAlert = flagged
171
+ ```
172
+
173
+ ### Mutual Fund SIP
174
+ ```ts
175
+ import { JoopMutualFundService } from 'joopjs';
176
+
177
+ const mf = new JoopMutualFundService();
178
+ mf.registerFund({ id: 'f1', name: 'Growth Fund', category: 'equity', currentNav: 45.5, currency: 'USD' });
179
+ mf.invest('f1', 'investor-001', 1000);
180
+ const sip = mf.createSip('f1', 'investor-001', 500, 'monthly', Date.now());
181
+ mf.executeSip(sip.id);
182
+ ```
183
+
184
+ ### Framework Integration — React
185
+ ```tsx
186
+ import React, { useEffect } from 'react';
187
+ import { JoopDigitalWalletService } from 'joopjs';
188
+
189
+ const wallet = new JoopDigitalWalletService();
190
+
191
+ function WalletBalance() {
192
+ const [balance, setBalance] = React.useState(0);
193
+
194
+ useEffect(() => {
195
+ const unsub = wallet.balance$().subscribe(({ balance }) => setBalance(balance));
196
+ return unsub; // cleanup on unmount
197
+ }, []);
198
+
199
+ return <div>{balance}</div>;
200
+ }
201
+ ```
202
+
203
+ ### Framework Integration — Angular (17+ DI)
204
+ ```ts
205
+ // adapter imports @angular/*; the core SDK never does
206
+ import { provideJoopAngular, injectJoop, joopSignal } from 'joopjs/angular';
207
+ bootstrapApplication(AppComponent, { providers: [...provideJoopAngular(joop)] });
208
+ // in a component: const joop = injectJoop(); balance = joopSignal(joop.wallet.balance$());
209
+ ```
210
+
211
+ `joopjs/angular` (Angular 17+) provides real DI:
212
+ - `JOOP_INSTANCE` — typed `InjectionToken<JoopInstance>`; `injectJoop()` is shorthand for `inject(JOOP_INSTANCE)`.
213
+ - `provideJoopAngular(instance)` — bootstrap providers (replaces deprecated `provideJoop`).
214
+ - `joopSignal(obs, opts?)` — bridges a `JoopObservable` to an Angular `signal`, auto-teardown via `DestroyRef`. Preferred over `fromJoop` and over manual subscribe.
215
+ - `joopAuthGuard(opts?)` — functional `CanActivateFn` (`{ redirectTo?: string }`, default `/login`).
216
+ - `joopAuthInterceptor(opts?)` — `HttpInterceptorFn` attaching the access token (`{ header?, scheme? }`).
217
+ - Deprecated but still functional: string tokens, `provideJoop()`, `JoopModule`, `fromJoop()`. `toJoop()` is not deprecated.
218
+ - New optional peers: `@angular/common`, `@angular/router`.
219
+
220
+ ---
221
+
222
+ ## TypeScript Types (prefix `Joop*`)
223
+
224
+ All types are exported from `'joopjs'`:
225
+
226
+ ```ts
227
+ // Auth
228
+ JoopAuthUser, JoopAuthSession, JoopAuthToken
229
+
230
+ // Banking
231
+ JoopWallet, JoopWalletTransaction, JoopWalletTxnType
232
+ JoopLoanAccount, JoopInstallment, JoopLoanAccountStatus
233
+ JoopFxForward, JoopForwardType, JoopForwardStatus
234
+ JoopLedgerAccount, JoopJournalEntry, JoopTrialBalance
235
+
236
+ // Finance
237
+ JoopMutualFund, JoopFundHolding, JoopSip, JoopSipStatus
238
+
239
+ // Security
240
+ JoopSanctionsEntity, JoopScreeningResult, JoopAmlAlert
241
+ ```
@@ -0,0 +1,183 @@
1
+ # GEMINI.md — JoopJS SDK
2
+
3
+ This file instructs Gemini CLI on how to generate code using the **joopjs** SDK.
4
+
5
+ ---
6
+
7
+ ## Package
8
+
9
+ ```bash
10
+ npm install joopjs
11
+ ```
12
+
13
+ **joopjs** is a framework-agnostic TypeScript SDK for enterprise financial applications. Works with React, Angular, Vue, Node.js, and plain TypeScript.
14
+
15
+ ---
16
+
17
+ ## Import Rules
18
+
19
+ ```ts
20
+ // Main entry — everything
21
+ import { JoopAuthService, JoopDigitalWalletService } from 'joopjs';
22
+
23
+ // Sub-path imports (tree-shakeable, preferred)
24
+ import { JoopGcmService } from 'joopjs/encryption';
25
+ import { JoopAuthService } from 'joopjs/auth';
26
+ import { JoopCacheService } from 'joopjs/cache';
27
+ ```
28
+
29
+ Available sub-paths: `auth`, `encryption`, `banking`, `security`, `api`, `core`, `session`, `device`, `observability`, `theme`, `i18n`, `ui`, `forms`, `router`, `state`, `workers`, `workflow`, `sync`, `platform`, `cache`, `network`, `analytics`, `validation`, `utilities`, `pwa`, `native-bridge`, `deeplink`, `react`, `angular`, `vue`, `india`.
30
+
31
+ Never import from internal paths (`joopjs/src/...`, `joopjs/dist/...`).
32
+
33
+ `joopjs/core` exposes `globalSingleton`, `joopCopyCount`, and `silenceDuplicateCopyWarning`. In Module Federation micro-frontends, share joopjs as a singleton (`shared: { joopjs: { singleton: true } }`) so logger/config/event-bus state does not fragment across multiple loaded copies.
34
+
35
+ ---
36
+
37
+ ## Service Instantiation
38
+
39
+ All services are plain classes — no DI framework required:
40
+
41
+ ```ts
42
+ const wallet = new JoopDigitalWalletService();
43
+ const auth = new JoopAuthService();
44
+ const gcm = new JoopGcmService();
45
+ const loans = new JoopLoanServicingService();
46
+ ```
47
+
48
+ Create once per module and reuse as singletons.
49
+
50
+ ---
51
+
52
+ ## Reactive Observables
53
+
54
+ joopjs uses its own `JoopSubject` — **not RxJS**:
55
+
56
+ ```ts
57
+ // Subscribe — returns an unsubscribe function
58
+ const unsub = service.event$().subscribe(value => {
59
+ console.log(value);
60
+ });
61
+
62
+ // Emit (only from inside a service or your own subject)
63
+ subject.next(newValue); // CORRECT
64
+ subject.emit(newValue); // WRONG — .emit() does not exist
65
+
66
+ // Read current value (BehaviorSubject only)
67
+ const current = behaviorSubject.getValue();
68
+
69
+ // Unsubscribe
70
+ unsub(); // call the returned function
71
+ // NOT .unsubscribe() // wrong — does not exist
72
+ ```
73
+
74
+ `next()` is error-isolated: if one subscriber throws, delivery to the other subscribers still proceeds. Route subscriber errors with `setSubjectErrorHandler(fn)` (default `console.error`).
75
+
76
+ Do not use RxJS operators (`.pipe()`, `.map()`, etc.) — these are not RxJS Observables.
77
+
78
+ ---
79
+
80
+ ## Data Types
81
+
82
+ | Concept | Type | Example |
83
+ |---------|------|---------|
84
+ | Money amount | `number` | `5000.50` |
85
+ | Currency | `string` ISO-4217 | `'USD'`, `'AED'`, `'INR'` |
86
+ | Timestamp | `number` epoch ms | `Date.now()` |
87
+ | ID | `string` | `'u-001'` |
88
+
89
+ Never use a Money class, BigDecimal, or `Date` objects.
90
+
91
+ ---
92
+
93
+ ## Error Handling
94
+
95
+ All services throw standard `Error` on invalid input:
96
+
97
+ ```ts
98
+ try {
99
+ const result = await service.doSomething(config);
100
+ } catch (err) {
101
+ if (err instanceof Error) {
102
+ console.error(err.message);
103
+ }
104
+ }
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Key Services Quick Reference
110
+
111
+ ### Banking
112
+ ```ts
113
+ import { JoopDigitalWalletService, JoopLoanServicingService } from 'joopjs';
114
+
115
+ const wallet = new JoopDigitalWalletService();
116
+ const w = wallet.createWallet('user-001', { currency: 'USD' });
117
+ wallet.topUp(w.id, 500);
118
+ wallet.pay(w.id, 50, 'merchant-id', 'Coffee');
119
+ wallet.balance$().subscribe(({ walletId, balance }) => { /* update UI */ });
120
+
121
+ const loans = new JoopLoanServicingService();
122
+ const loan = loans.createLoan({ borrowerName: 'Alice', borrowerId: 'u-001', principalAmount: 10000, annualInterestRatePercent: 8, tenureMonths: 12, currency: 'USD' });
123
+ loans.recordPayment(loan.id, loan.emiAmount);
124
+ ```
125
+
126
+ ### Auth
127
+ ```ts
128
+ import { JoopAuthService } from 'joopjs/auth';
129
+
130
+ const auth = new JoopAuthService();
131
+ const session = await auth.login(email, password);
132
+ auth.session$().subscribe(session => { /* null = logged out */ });
133
+ await auth.logout(session.sessionId);
134
+ ```
135
+
136
+ ### Encryption
137
+ ```ts
138
+ import { JoopGcmService } from 'joopjs/encryption';
139
+
140
+ const gcm = new JoopGcmService();
141
+ const key = await gcm.generateKey();
142
+ const { ciphertext, iv } = await gcm.encrypt('sensitive data', key);
143
+ const plain = await gcm.decrypt(ciphertext, key, iv);
144
+ ```
145
+
146
+ ### Security
147
+ ```ts
148
+ import { JoopAmlService, JoopSanctionsScreeningService } from 'joopjs';
149
+
150
+ const aml = new JoopAmlService();
151
+ aml.addRule({ id: 'r1', name: 'Large cash', type: 'cash', threshold: 10000, currency: 'USD', action: 'flag', enabled: true });
152
+ const alert = aml.checkTransaction({ id: 'tx1', amount: 15000, currency: 'USD', type: 'cash', userId: 'u-001', timestamp: Date.now() });
153
+
154
+ const sanctions = new JoopSanctionsScreeningService();
155
+ sanctions.loadList('ofac', entities);
156
+ const result = sanctions.screen({ name: 'John Doe', country: 'US' });
157
+ // result.status: 'clear' | 'hit' | 'review'
158
+ ```
159
+
160
+ ### Framework Integrations
161
+ ```tsx
162
+ // React
163
+ import { createJoopReact } from 'joopjs/react';
164
+ const { JoopProvider, useJoopAuth, useJoopTheme } = createJoopReact(React);
165
+
166
+ // Vue
167
+ import { createJoopVue } from 'joopjs/vue';
168
+ const { provideJoop, useJoopAuth } = createJoopVue(Vue);
169
+
170
+ // Angular (17+ DI — adapter imports @angular/*; the core SDK never does)
171
+ import { provideJoopAngular, injectJoop, joopSignal } from 'joopjs/angular';
172
+ bootstrapApplication(AppComponent, { providers: [...provideJoopAngular(joop)] });
173
+ // in a component: const joop = injectJoop(); balance = joopSignal(joop.wallet.balance$());
174
+ ```
175
+
176
+ `joopjs/angular` (Angular 17+) provides real DI:
177
+ - `JOOP_INSTANCE` — typed `InjectionToken<JoopInstance>`; `injectJoop()` is shorthand for `inject(JOOP_INSTANCE)`.
178
+ - `provideJoopAngular(instance)` — bootstrap providers (replaces deprecated `provideJoop`).
179
+ - `joopSignal(obs, opts?)` — bridges a `JoopObservable` to an Angular `signal`, auto-teardown via `DestroyRef`. Preferred over `fromJoop` and over manual subscribe.
180
+ - `joopAuthGuard(opts?)` — functional `CanActivateFn` (`{ redirectTo?: string }`, default `/login`).
181
+ - `joopAuthInterceptor(opts?)` — `HttpInterceptorFn` attaching the access token (`{ header?, scheme? }`).
182
+ - Deprecated but still functional: string tokens, `provideJoop()`, `JoopModule`, `fromJoop()`. `toJoop()` is not deprecated.
183
+ - New optional peers: `@angular/common`, `@angular/router`.
package/dist/ai/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  // src/events/index.ts
4
+ var _onListenerError = (error) => {
5
+ console.error("[joopjs] a subject subscriber threw during emission:", error);
6
+ };
4
7
  var JoopSubject = class {
5
8
  _listeners = [];
6
9
  subscribe(listener) {
@@ -10,8 +13,13 @@ var JoopSubject = class {
10
13
  };
11
14
  }
12
15
  next(value) {
13
- for (const listener of this._listeners) {
14
- listener(value);
16
+ const listeners = this._listeners.slice();
17
+ for (const listener of listeners) {
18
+ try {
19
+ listener(value);
20
+ } catch (error) {
21
+ _onListenerError(error);
22
+ }
15
23
  }
16
24
  }
17
25
  asObservable() {
@@ -32,7 +40,11 @@ var JoopBehaviorSubject = class extends JoopSubject {
32
40
  super.next(value);
33
41
  }
34
42
  subscribe(listener) {
35
- listener(this._value);
43
+ try {
44
+ listener(this._value);
45
+ } catch (error) {
46
+ _onListenerError(error);
47
+ }
36
48
  return super.subscribe(listener);
37
49
  }
38
50
  asObservable() {