joopjs 2.0.4 → 2.0.6

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.
@@ -0,0 +1,265 @@
1
+ # /encryption — JoopJS Encryption Services
2
+
3
+ > Author: Kundan Singh
4
+
5
+ All encryption services are imported from `'joopjs'`. Uses Web Crypto API (browser) or Node.js `crypto` module — no external dependencies required for basic usage. Advanced ciphers use `@noble/ciphers` and `@noble/curves`.
6
+
7
+ ---
8
+
9
+ ## AES-GCM Symmetric Encryption
10
+
11
+ ```ts
12
+ import { JoopGcmService } from 'joopjs';
13
+ const gcm = new JoopGcmService();
14
+
15
+ // Generate a key (256-bit)
16
+ const key = await gcm.generateKey(); // CryptoKey
17
+
18
+ // Encrypt
19
+ const encrypted = await gcm.encrypt('Hello, World!', key);
20
+ // { ciphertext: string, iv: string, tag: string } — all base64
21
+
22
+ // Decrypt
23
+ const plaintext = await gcm.decrypt(encrypted.ciphertext, key, encrypted.iv);
24
+ // 'Hello, World!'
25
+
26
+ // Encrypt objects
27
+ const enc = await gcm.encryptObject({ amount: 5000, userId: 'u-001' }, key);
28
+ const obj = await gcm.decryptObject(enc, key); // { amount: 5000, userId: 'u-001' }
29
+
30
+ // Key export/import for storage
31
+ const exported = await gcm.exportKey(key); // base64 string
32
+ const imported = await gcm.importKey(exported); // CryptoKey
33
+ ```
34
+
35
+ **Use for:** Encrypting data at rest, local storage encryption, session data.
36
+
37
+ ---
38
+
39
+ ## RSA-OAEP Asymmetric Encryption
40
+
41
+ ```ts
42
+ import { JoopRsaService } from 'joopjs';
43
+ const rsa = new JoopRsaService();
44
+
45
+ // Generate key pair (2048-bit)
46
+ const keyPair = await rsa.generateKeyPair();
47
+ // { publicKey: CryptoKey, privateKey: CryptoKey }
48
+
49
+ // Encrypt with public key
50
+ const encrypted = await rsa.encrypt('sensitive data', keyPair.publicKey);
51
+
52
+ // Decrypt with private key
53
+ const plaintext = await rsa.decrypt(encrypted, keyPair.privateKey);
54
+
55
+ // Export keys for storage/transport
56
+ const pubPem = await rsa.exportPublicKey(keyPair.publicKey); // PEM string
57
+ const privPem = await rsa.exportPrivateKey(keyPair.privateKey); // PEM string (store securely)
58
+ const pub2 = await rsa.importPublicKey(pubPem);
59
+ const priv2 = await rsa.importPrivateKey(privPem);
60
+
61
+ // Sign + verify
62
+ const signature = await rsa.sign('message', keyPair.privateKey);
63
+ const valid = await rsa.verify('message', signature, keyPair.publicKey); // true
64
+ ```
65
+
66
+ **Use for:** Encrypting symmetric keys, signing tokens, server-to-client key exchange.
67
+
68
+ ---
69
+
70
+ ## X25519 Key Exchange (ECDH)
71
+
72
+ ```ts
73
+ import { JoopX25519Service } from 'joopjs';
74
+ const x25519 = new JoopX25519Service();
75
+
76
+ // Both parties generate their own key pairs
77
+ const aliceKeys = x25519.generateKeyPair(); // { privateKey: Uint8Array, publicKey: Uint8Array }
78
+ const bobKeys = x25519.generateKeyPair();
79
+
80
+ // Exchange public keys, derive shared secret
81
+ const aliceShared = x25519.deriveSharedSecret(aliceKeys.privateKey, bobKeys.publicKey);
82
+ const bobShared = x25519.deriveSharedSecret(bobKeys.privateKey, aliceKeys.publicKey);
83
+ // aliceShared === bobShared (both Uint8Array, 32 bytes)
84
+
85
+ // Convert to AES key for actual encryption
86
+ const aesKey = await x25519.deriveAesKey(aliceShared); // CryptoKey for AES-GCM
87
+
88
+ // Serialise keys for transport
89
+ const pubHex = x25519.toHex(aliceKeys.publicKey);
90
+ const pubBack = x25519.fromHex(pubHex);
91
+ ```
92
+
93
+ **Use for:** Perfect forward secrecy, establishing E2E encrypted channels between parties.
94
+
95
+ ---
96
+
97
+ ## End-to-End (E2E) Encryption Flow
98
+
99
+ Combines X25519 key exchange + AES-GCM message encryption:
100
+
101
+ ```ts
102
+ import { JoopX25519Service, JoopGcmService } from 'joopjs';
103
+ const dh = new JoopX25519Service();
104
+ const gcm = new JoopGcmService();
105
+
106
+ // --- Setup (once per session) ---
107
+ const clientKeys = dh.generateKeyPair();
108
+ const serverPubKey = /* received from server */ new Uint8Array(32);
109
+
110
+ const sharedSecret = dh.deriveSharedSecret(clientKeys.privateKey, serverPubKey);
111
+ const sessionKey = await dh.deriveAesKey(sharedSecret);
112
+
113
+ // --- Per message ---
114
+ async function sendMessage(plaintext: string) {
115
+ return gcm.encrypt(plaintext, sessionKey);
116
+ }
117
+
118
+ async function receiveMessage(ciphertext: string, iv: string) {
119
+ return gcm.decrypt(ciphertext, sessionKey, iv);
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Hashing
126
+
127
+ ```ts
128
+ import { JoopHashService } from 'joopjs';
129
+ const hash = new JoopHashService();
130
+
131
+ const sha256 = await hash.sha256('password123'); // hex string
132
+ const sha512 = await hash.sha512('password123');
133
+ const hmac = await hash.hmac('message', 'secret'); // HMAC-SHA256
134
+
135
+ // Password hashing (bcrypt-equivalent, using PBKDF2)
136
+ const hashPwd = await hash.hashPassword('mypassword'); // { hash, salt }
137
+ const matches = await hash.verifyPassword('mypassword', hashPwd.hash, hashPwd.salt);
138
+
139
+ // Integrity checksums
140
+ const checksum = await hash.checksum(dataBuffer); // SHA-256 hex
141
+ const isValid = await hash.verifyChecksum(dataBuffer, checksum);
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Key Manager
147
+
148
+ ```ts
149
+ import { JoopKeyManagerService } from 'joopjs';
150
+ const km = new JoopKeyManagerService();
151
+
152
+ // Store and retrieve keys by ID
153
+ await km.store('session-key', aesKey, { expiresAt: Date.now() + 3600_000 });
154
+ const key = await km.retrieve('session-key'); // CryptoKey | null
155
+ km.revoke('session-key');
156
+ km.revokeExpired(); // cleanup expired keys
157
+
158
+ // Key rotation
159
+ const newKey = await km.rotate('session-key'); // generates new, stores, returns old
160
+ const exists = km.has('session-key');
161
+ const listing = km.list(); // [{ id, type, expiresAt, metadata }]
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Secure Random
167
+
168
+ ```ts
169
+ import { JoopRandomService } from 'joopjs';
170
+ const rand = new JoopRandomService();
171
+
172
+ const bytes = rand.bytes(32); // Uint8Array, cryptographically secure
173
+ const hex = rand.hex(32); // 64-char hex string
174
+ const uuid = rand.uuid(); // UUID v4
175
+ const token = rand.token(48); // URL-safe base64 token
176
+ const integer = rand.integer(1, 100); // inclusive range
177
+ const nonce = rand.nonce(); // 16-byte hex nonce
178
+ ```
179
+
180
+ ---
181
+
182
+ ## Field-Level Encryption (PII Protection)
183
+
184
+ ```ts
185
+ import { JoopFieldEncryptionService } from 'joopjs';
186
+ const ffe = new JoopFieldEncryptionService();
187
+
188
+ const key = await ffe.generateKey();
189
+
190
+ // Encrypt sensitive fields in an object
191
+ const protected = await ffe.encryptFields(
192
+ { name: 'Alice', pan: '4111111111111111', dob: '1990-01-01', email: 'alice@bank.com' },
193
+ ['pan', 'dob'], // fields to encrypt
194
+ key,
195
+ );
196
+ // { name: 'Alice', pan: '<encrypted>', dob: '<encrypted>', email: 'alice@bank.com' }
197
+
198
+ const restored = await ffe.decryptFields(protected, ['pan', 'dob'], key);
199
+ // original object restored
200
+
201
+ // Deterministic encryption (searchable, order-preserving)
202
+ const detEnc = await ffe.encryptDeterministic('4111111111111111', key);
203
+ // same input always produces same output — can be used as index
204
+ ```
205
+
206
+ ---
207
+
208
+ ## TLS / Certificate Utilities
209
+
210
+ ```ts
211
+ import { JoopCertificateService } from 'joopjs';
212
+ const cert = new JoopCertificateService();
213
+
214
+ const parsed = cert.parsePem(pemString); // { subject, issuer, validity, fingerprint, extensions }
215
+ const valid = cert.isValid(pemString); // checks expiry + basic format
216
+ const chain = cert.buildChain([leafPem, intermediatePem, rootPem]);
217
+ const pinned = cert.pin(pemString); // SHA-256 fingerprint for certificate pinning
218
+ const days = cert.daysUntilExpiry(pemString);
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Vault (Secret Store)
224
+
225
+ ```ts
226
+ import { JoopVaultService } from 'joopjs';
227
+ const vault = new JoopVaultService({ masterKey: 'master-key-from-env' });
228
+
229
+ await vault.set('db-password', 'super-secret');
230
+ const secret = await vault.get('db-password'); // 'super-secret'
231
+ vault.delete('db-password');
232
+
233
+ // Versioned secrets
234
+ await vault.setVersion('api-key', 'v1', 'key-abc');
235
+ await vault.setVersion('api-key', 'v2', 'key-xyz');
236
+ const current = await vault.get('api-key'); // 'key-xyz' (latest)
237
+ const v1 = await vault.getVersion('api-key', 'v1'); // 'key-abc'
238
+
239
+ vault.rotate('api-key', 'key-new'); // sets new version, keeps old versions
240
+ ```
241
+
242
+ ---
243
+
244
+ ## What Gets Published to npm
245
+
246
+ Controlled by `"files"` in `package.json` — acts as an allowlist. Only these two are included:
247
+
248
+ | Published to npm | Never published |
249
+ |-----------------|----------------|
250
+ | `dist/` — ESM + CJS + `.d.ts` for all 34 sub-paths | `src/` — TypeScript source |
251
+ | `CHANGELOG.md` — release history | `tests/` — test suite |
252
+ | | `scripts/` — release automation |
253
+ | | `playground/` — Vite demo app |
254
+ | | `.claude/` — Claude skills (including this file) |
255
+ | | `.cursor/` — Cursor rules |
256
+ | | `.windsurf/` — Windsurf rules |
257
+ | | `GEMINI.md`, `AGENTS.md` — AI tool instructions |
258
+ | | `tsup.config.ts`, `vitest.config.ts`, `tsconfig.json` |
259
+
260
+ Source code, AI rules, and dev tooling are **never** published to npm.
261
+
262
+ Verify the tarball contents before any publish:
263
+ ```bash
264
+ npm pack --dry-run
265
+ ```
@@ -0,0 +1,248 @@
1
+ # /finance — JoopJS Finance Services
2
+
3
+ > Author: Kundan Singh
4
+
5
+ All finance services are imported from `'joopjs'`. Instantiate as plain singletons.
6
+
7
+ ---
8
+
9
+ ## Mutual Fund
10
+
11
+ ```ts
12
+ import { JoopMutualFundService } from 'joopjs';
13
+ const mf = new JoopMutualFundService();
14
+
15
+ mf.registerFund({ id: 'EQ001', name: 'Equity Growth Fund', category: 'equity', currentNav: 45.50, currency: 'USD' });
16
+ mf.updateNav('EQ001', 48.00);
17
+
18
+ const holding = mf.invest('EQ001', 'inv-001', 5000);
19
+ // holding.units = 5000/45.50, holding.averageCostNav = 45.50
20
+
21
+ const redemption = mf.redeem('EQ001', 'inv-001', 50); // redeem 50 units
22
+ // redemption.proceeds, redemption.realizedGain
23
+
24
+ mf.updateNav('EQ001', 48.00); // refreshes holding.currentValue
25
+ const h = mf.getHolding('EQ001', 'inv-001');
26
+ // h.currentValue, h.unrealizedGain, h.returnPercent
27
+
28
+ // SIP (Systematic Investment Plan)
29
+ const sip = mf.createSip('EQ001', 'inv-001', 500, 'monthly', Date.now(), {
30
+ endDate: Date.now() + 365 * 86_400_000,
31
+ });
32
+ mf.executeSip(sip.id); // executes and advances nextExecutionDate
33
+ mf.pauseSip(sip.id); mf.resumeSip(sip.id); mf.cancelSip(sip.id);
34
+ ```
35
+
36
+ **Frequencies:** `'weekly'` | `'monthly'` | `'quarterly'`
37
+ **Fund categories:** `'equity'` | `'debt'` | `'hybrid'` | `'money-market'` | `'index'` | `'etf'`
38
+ **Key types:** `JoopMutualFund`, `JoopFundHolding`, `JoopFundRedemption`, `JoopSip`, `JoopSipStatus`, `JoopFundCategory`
39
+
40
+ ---
41
+
42
+ ## Budget Tracker
43
+
44
+ ```ts
45
+ import { JoopBudgetTrackerService } from 'joopjs';
46
+ const budget = new JoopBudgetTrackerService();
47
+
48
+ budget.createBudget({ name: 'Monthly Budget', period: 'monthly', currency: 'USD', startDate: Date.now() });
49
+ budget.addCategory(budgetId, { name: 'Food', limit: 500 });
50
+ budget.recordSpend(budgetId, categoryId, 120, 'Groceries');
51
+ const report = budget.getReport(budgetId);
52
+ // { categories: [{ name, limit, spent, remaining, overBudget }], totalLimit, totalSpent }
53
+ const alerts = budget.getAlerts(budgetId, 80); // categories at >80% utilization
54
+ ```
55
+
56
+ **Key types:** `JoopBudget`, `JoopBudgetCategory`, `JoopBudgetReport`, `JoopBudgetAlert`
57
+
58
+ ---
59
+
60
+ ## Portfolio Tracker
61
+
62
+ ```ts
63
+ import { JoopPortfolioTrackerService } from 'joopjs';
64
+ const portfolio = new JoopPortfolioTrackerService();
65
+
66
+ portfolio.createPortfolio({ name: 'My Investments', currency: 'USD', userId: 'u-001' });
67
+ portfolio.addHolding(pid, { symbol: 'AAPL', name: 'Apple Inc', quantity: 10, avgCostPrice: 150, currentPrice: 175, assetClass: 'equity' });
68
+ portfolio.updatePrice(pid, 'AAPL', 180);
69
+ const summary = portfolio.getSummary(pid);
70
+ // { totalInvested, currentValue, totalGain, gainPercent, holdings[] }
71
+ portfolio.rebalance(pid, { AAPL: 60, BONDS: 40 }); // target allocation %
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Tax Calculator
77
+
78
+ ```ts
79
+ import { JoopTaxCalculatorService } from 'joopjs';
80
+ const tax = new JoopTaxCalculatorService();
81
+
82
+ tax.setTaxProfile({ jurisdiction: 'US', filingStatus: 'single', year: 2025 });
83
+ tax.addSlab(5000, 0); tax.addSlab(45000, 12); tax.addSlab(95000, 22);
84
+ const liability = tax.calculate(75000); // { taxableIncome, taxLiability, effectiveRate, slabs }
85
+ const capitalGain = tax.calcCapitalGainsTax(50000, 12, 'US');
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Cash Flow Forecaster
91
+
92
+ ```ts
93
+ import { JoopCashFlowForecastService } from 'joopjs';
94
+ const cf = new JoopCashFlowForecastService();
95
+
96
+ cf.addCashFlow({ name: 'Salary', amount: 5000, frequency: 'monthly', startDate: Date.now(), type: 'inflow' });
97
+ cf.addCashFlow({ name: 'Rent', amount: 1500, frequency: 'monthly', startDate: Date.now(), type: 'outflow' });
98
+ const forecast = cf.forecast(Date.now(), Date.now() + 90 * 86_400_000);
99
+ // { periods: [{ date, inflows, outflows, netCashFlow, runningBalance }], summary }
100
+ const summary = cf.getSummary(Date.now(), Date.now() + 90 * 86_400_000);
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Expense Tracker
106
+
107
+ ```ts
108
+ import { JoopExpenseTrackerService } from 'joopjs';
109
+ const exp = new JoopExpenseTrackerService();
110
+
111
+ exp.add({ userId: 'u-001', amount: 45.50, category: 'dining', description: 'Lunch', date: Date.now() });
112
+ const monthly = exp.getByPeriod('u-001', startTs, endTs);
113
+ const byCategory = exp.getByCategory('u-001', 'dining', startTs, endTs);
114
+ const totals = exp.getTotals('u-001', startTs, endTs); // { total, byCategory: Map }
115
+ exp.setLimit('u-001', 'dining', 300); // monthly limit
116
+ const limit = exp.checkLimit('u-001', 'dining'); // { limit, spent, exceeded }
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Goal Savings
122
+
123
+ ```ts
124
+ import { JoopGoalSavingsService } from 'joopjs';
125
+ const goals = new JoopGoalSavingsService();
126
+
127
+ const goal = goals.create({ name: 'Emergency Fund', targetAmount: 10000, currency: 'USD', targetDate: Date.now() + 365 * 86_400_000 });
128
+ goals.contribute(goal.id, 500);
129
+ const progress = goals.getProgress(goal.id);
130
+ // { current, target, percent, remaining, projectedDate, onTrack }
131
+ const monthly = goals.getSuggestedContribution(goal.id); // amount needed per month to hit target
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Net Worth
137
+
138
+ ```ts
139
+ import { JoopNetWorthService } from 'joopjs';
140
+ const nw = new JoopNetWorthService();
141
+
142
+ nw.addAsset({ id: 'home', name: 'House', category: 'real-estate', value: 500000, currency: 'USD' });
143
+ nw.addLiability({ id: 'mortgage', name: 'Mortgage', category: 'loans', balance: 350000, currency: 'USD' });
144
+ const snapshot = nw.getSnapshot();
145
+ // { totalAssets, totalLiabilities, netWorth, assetBreakdown, liabilityBreakdown }
146
+ nw.updateAsset('home', { value: 520000 });
147
+ const history = nw.getHistory(); // snapshots over time
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Investment Calculator
153
+
154
+ ```ts
155
+ import { JoopInvestmentCalculatorService } from 'joopjs';
156
+ const calc = new JoopInvestmentCalculatorService();
157
+
158
+ const compound = calc.compoundInterest(10000, 8, 10); // { principal, rate, years, finalAmount, interest }
159
+ const sip = calc.sipReturns(5000, 12, 15); // { monthlyAmount, months, annualRate, maturityAmount }
160
+ const lumpsum = calc.lumpsumReturns(100000, 12, 10);
161
+ const emi = calc.emiCalc(500000, 8.5, 20); // { emi, totalPayment, totalInterest }
162
+ const rule72 = calc.rule72(8); // 9 years to double
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Financial Report Generator
168
+
169
+ ```ts
170
+ import { JoopFinancialReportService } from 'joopjs';
171
+ const reports = new JoopFinancialReportService();
172
+
173
+ reports.addEntry({ type: 'income', category: 'salary', amount: 5000, date: Date.now() });
174
+ reports.addEntry({ type: 'expense', category: 'rent', amount: 1500, date: Date.now() });
175
+ const pnl = reports.getPnLStatement(startTs, endTs);
176
+ // { income, expenses, grossProfit, operatingExpenses, netProfit }
177
+ const balance = reports.getBalanceSheet();
178
+ const cashFlow = reports.getCashFlowStatement(startTs, endTs);
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Currency Converter
184
+
185
+ ```ts
186
+ import { JoopCurrencyConverterService } from 'joopjs';
187
+ const fx = new JoopCurrencyConverterService();
188
+
189
+ fx.setRate('USD', 'EUR', 0.92);
190
+ fx.setRate('USD', 'INR', 83.5);
191
+ const result = fx.convert(1000, 'USD', 'EUR'); // { amount: 920, from, to, rate, timestamp }
192
+ const multi = fx.convertMultiple(1000, 'USD', ['EUR', 'INR', 'GBP']);
193
+ const history = fx.getRateHistory('USD', 'EUR'); // historical rates
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Loan Calculator
199
+
200
+ ```ts
201
+ import { JoopLoanCalculatorService } from 'joopjs';
202
+ const lc = new JoopLoanCalculatorService();
203
+
204
+ const emi = lc.calculateEmi(500000, 8.5, 20); // { emi, totalPayment, totalInterest, schedule }
205
+ const eligibility = lc.checkEligibility({ income: 80000, obligations: 20000, rate: 8.5, tenureYears: 20 });
206
+ // { eligible, maxLoanAmount, maxEmi }
207
+ const prepay = lc.calcPrepaymentImpact(500000, 8.5, 20, { amount: 100000, afterMonth: 24 });
208
+ // { newTenure, interestSaved, reducedEmi }
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Fixed Deposit
214
+
215
+ ```ts
216
+ import { JoopFixedDepositService } from 'joopjs';
217
+ const fd = new JoopFixedDepositService();
218
+
219
+ const deposit = fd.create({ principal: 50000, annualRate: 6.5, tenureMonths: 12, currency: 'USD', compoundFrequency: 'quarterly' });
220
+ const maturity = fd.calcMaturity(deposit.id); // { maturityAmount, interestEarned, effectiveRate }
221
+ fd.prematureClose(deposit.id, 0.5); // 0.5% penalty
222
+ const due = fd.getMaturing(30 * 86_400_000); // maturing in 30 days
223
+ ```
224
+
225
+ ---
226
+
227
+ ## What Gets Published to npm
228
+
229
+ Controlled by `"files"` in `package.json` — acts as an allowlist. Only these two are included:
230
+
231
+ | Published to npm | Never published |
232
+ |-----------------|----------------|
233
+ | `dist/` — ESM + CJS + `.d.ts` for all 34 sub-paths | `src/` — TypeScript source |
234
+ | `CHANGELOG.md` — release history | `tests/` — test suite |
235
+ | | `scripts/` — release automation |
236
+ | | `playground/` — Vite demo app |
237
+ | | `.claude/` — Claude skills (including this file) |
238
+ | | `.cursor/` — Cursor rules |
239
+ | | `.windsurf/` — Windsurf rules |
240
+ | | `GEMINI.md`, `AGENTS.md` — AI tool instructions |
241
+ | | `tsup.config.ts`, `vitest.config.ts`, `tsconfig.json` |
242
+
243
+ Source code, AI rules, and dev tooling are **never** published to npm.
244
+
245
+ Verify the tarball contents before any publish:
246
+ ```bash
247
+ npm pack --dry-run
248
+ ```