joopjs 2.0.5 → 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.
- package/.claude/skills/auth.md +235 -0
- package/.claude/skills/banking.md +377 -0
- package/.claude/skills/encryption.md +265 -0
- package/.claude/skills/finance.md +248 -0
- package/.claude/skills/observables.md +242 -0
- package/.claude/skills/security.md +240 -0
- package/.claude/skills/setup.md +185 -0
- package/.cursor/rules/joopjs.mdc +151 -0
- package/.github/copilot-instructions.md +141 -0
- package/.windsurf/rules/joopjs.md +222 -0
- package/CHANGELOG.md +52 -0
- package/README.md +29 -1
- package/ai-rules/AGENTS.md +220 -0
- package/ai-rules/GEMINI.md +169 -0
- package/package.json +81 -31
- package/scripts/setup-ai.mjs +133 -0
|
@@ -0,0 +1,220 @@
|
|
|
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
|
+
---
|
|
34
|
+
|
|
35
|
+
## Service Instantiation
|
|
36
|
+
|
|
37
|
+
All services are plain classes — no DI framework, no `@Injectable`, no container:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const wallet = new JoopDigitalWalletService();
|
|
41
|
+
const auth = new JoopAuthService();
|
|
42
|
+
const gcm = new JoopGcmService();
|
|
43
|
+
const loans = new JoopLoanServicingService();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Create once per module and reuse as singletons.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Reactive Observables — Critical Rules
|
|
51
|
+
|
|
52
|
+
joopjs uses its own `JoopSubject` — **not RxJS**:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// Subscribe — always returns an unsubscribe function
|
|
56
|
+
const unsub = service.event$().subscribe(value => {
|
|
57
|
+
console.log(value);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Emit
|
|
61
|
+
subject.next(newValue); // CORRECT
|
|
62
|
+
subject.emit(newValue); // WRONG — throws, does not exist
|
|
63
|
+
|
|
64
|
+
// Current value (BehaviorSubject only)
|
|
65
|
+
const val = behaviorSubject.getValue();
|
|
66
|
+
|
|
67
|
+
// Clean up
|
|
68
|
+
unsub(); // call the returned function
|
|
69
|
+
// NOT .unsubscribe() // wrong — does not exist
|
|
70
|
+
// NOT subject.pipe(map(...)) // wrong — not RxJS
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Data Type Rules — Always Follow These
|
|
76
|
+
|
|
77
|
+
| Concept | Correct type | Never use |
|
|
78
|
+
|---------|-------------|-----------|
|
|
79
|
+
| Money amount | `number` | `BigDecimal`, `Money`, `string` |
|
|
80
|
+
| Currency | `string` ISO-4217 | enum, number |
|
|
81
|
+
| Timestamp | `number` Unix epoch ms — `Date.now()` | `new Date()`, `string` |
|
|
82
|
+
| ID | `string` | `number` |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Error Handling
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
try {
|
|
90
|
+
const result = await service.doSomething(config);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (err instanceof Error) {
|
|
93
|
+
console.error(err.message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Common Code Patterns
|
|
101
|
+
|
|
102
|
+
### Digital Wallet
|
|
103
|
+
```ts
|
|
104
|
+
import { JoopDigitalWalletService } from 'joopjs';
|
|
105
|
+
|
|
106
|
+
const wallet = new JoopDigitalWalletService();
|
|
107
|
+
const w = wallet.createWallet('user-001', { currency: 'USD', label: 'Primary' });
|
|
108
|
+
wallet.topUp(w.id, 500);
|
|
109
|
+
wallet.pay(w.id, 50, 'merchant-id', 'Coffee');
|
|
110
|
+
wallet.transfer(w.id, toWalletId, 200);
|
|
111
|
+
const bal = wallet.getBalance(w.id);
|
|
112
|
+
wallet.balance$().subscribe(({ walletId, balance }) => { /* update UI */ });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Auth + JWT
|
|
116
|
+
```ts
|
|
117
|
+
import { JoopAuthService } from 'joopjs/auth';
|
|
118
|
+
|
|
119
|
+
const auth = new JoopAuthService();
|
|
120
|
+
const session = await auth.login(email, password);
|
|
121
|
+
auth.session$().subscribe(session => { /* null = logged out */ });
|
|
122
|
+
await auth.logout(session.sessionId);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### AES-GCM Encryption
|
|
126
|
+
```ts
|
|
127
|
+
import { JoopGcmService } from 'joopjs/encryption';
|
|
128
|
+
|
|
129
|
+
const gcm = new JoopGcmService();
|
|
130
|
+
const key = await gcm.generateKey();
|
|
131
|
+
const { ciphertext, iv } = await gcm.encrypt('sensitive', key);
|
|
132
|
+
const plain = await gcm.decrypt(ciphertext, key, iv);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Loan Servicing
|
|
136
|
+
```ts
|
|
137
|
+
import { JoopLoanServicingService } from 'joopjs';
|
|
138
|
+
|
|
139
|
+
const loans = new JoopLoanServicingService();
|
|
140
|
+
const loan = loans.createLoan({
|
|
141
|
+
borrowerName: 'Alice', borrowerId: 'u-001',
|
|
142
|
+
principalAmount: 10000, annualInterestRatePercent: 8,
|
|
143
|
+
tenureMonths: 12, currency: 'USD'
|
|
144
|
+
});
|
|
145
|
+
loans.recordPayment(loan.id, loan.emiAmount);
|
|
146
|
+
const schedule = loans.getSchedule(loan.id);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Sanctions Screening
|
|
150
|
+
```ts
|
|
151
|
+
import { JoopSanctionsScreeningService } from 'joopjs';
|
|
152
|
+
|
|
153
|
+
const sanctions = new JoopSanctionsScreeningService();
|
|
154
|
+
sanctions.loadList('ofac', entities);
|
|
155
|
+
const result = sanctions.screen({ name: customerName, country: customerCountry });
|
|
156
|
+
if (result.status !== 'clear') { /* block or escalate */ }
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### AML
|
|
160
|
+
```ts
|
|
161
|
+
import { JoopAmlService } from 'joopjs';
|
|
162
|
+
|
|
163
|
+
const aml = new JoopAmlService();
|
|
164
|
+
aml.addRule({ id: 'r1', name: 'Large cash', type: 'cash', threshold: 10000, currency: 'USD', action: 'flag', enabled: true });
|
|
165
|
+
const alert = aml.checkTransaction({ id: 'tx1', amount: 15000, currency: 'USD', type: 'cash', userId: 'u-001', timestamp: Date.now() });
|
|
166
|
+
// null = passes; JoopAmlAlert = flagged
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Mutual Fund SIP
|
|
170
|
+
```ts
|
|
171
|
+
import { JoopMutualFundService } from 'joopjs';
|
|
172
|
+
|
|
173
|
+
const mf = new JoopMutualFundService();
|
|
174
|
+
mf.registerFund({ id: 'f1', name: 'Growth Fund', category: 'equity', currentNav: 45.5, currency: 'USD' });
|
|
175
|
+
mf.invest('f1', 'investor-001', 1000);
|
|
176
|
+
const sip = mf.createSip('f1', 'investor-001', 500, 'monthly', Date.now());
|
|
177
|
+
mf.executeSip(sip.id);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Framework Integration — React
|
|
181
|
+
```tsx
|
|
182
|
+
import React, { useEffect } from 'react';
|
|
183
|
+
import { JoopDigitalWalletService } from 'joopjs';
|
|
184
|
+
|
|
185
|
+
const wallet = new JoopDigitalWalletService();
|
|
186
|
+
|
|
187
|
+
function WalletBalance() {
|
|
188
|
+
const [balance, setBalance] = React.useState(0);
|
|
189
|
+
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
const unsub = wallet.balance$().subscribe(({ balance }) => setBalance(balance));
|
|
192
|
+
return unsub; // cleanup on unmount
|
|
193
|
+
}, []);
|
|
194
|
+
|
|
195
|
+
return <div>{balance}</div>;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## TypeScript Types (prefix `Joop*`)
|
|
202
|
+
|
|
203
|
+
All types are exported from `'joopjs'`:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
// Auth
|
|
207
|
+
JoopAuthUser, JoopAuthSession, JoopAuthToken
|
|
208
|
+
|
|
209
|
+
// Banking
|
|
210
|
+
JoopWallet, JoopWalletTransaction, JoopWalletTxnType
|
|
211
|
+
JoopLoanAccount, JoopInstallment, JoopLoanAccountStatus
|
|
212
|
+
JoopFxForward, JoopForwardType, JoopForwardStatus
|
|
213
|
+
JoopLedgerAccount, JoopJournalEntry, JoopTrialBalance
|
|
214
|
+
|
|
215
|
+
// Finance
|
|
216
|
+
JoopMutualFund, JoopFundHolding, JoopSip, JoopSipStatus
|
|
217
|
+
|
|
218
|
+
// Security
|
|
219
|
+
JoopSanctionsEntity, JoopScreeningResult, JoopAmlAlert
|
|
220
|
+
```
|
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
---
|
|
34
|
+
|
|
35
|
+
## Service Instantiation
|
|
36
|
+
|
|
37
|
+
All services are plain classes — no DI framework required:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const wallet = new JoopDigitalWalletService();
|
|
41
|
+
const auth = new JoopAuthService();
|
|
42
|
+
const gcm = new JoopGcmService();
|
|
43
|
+
const loans = new JoopLoanServicingService();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Create once per module and reuse as singletons.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Reactive Observables
|
|
51
|
+
|
|
52
|
+
joopjs uses its own `JoopSubject` — **not RxJS**:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// Subscribe — returns an unsubscribe function
|
|
56
|
+
const unsub = service.event$().subscribe(value => {
|
|
57
|
+
console.log(value);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Emit (only from inside a service or your own subject)
|
|
61
|
+
subject.next(newValue); // CORRECT
|
|
62
|
+
subject.emit(newValue); // WRONG — .emit() does not exist
|
|
63
|
+
|
|
64
|
+
// Read current value (BehaviorSubject only)
|
|
65
|
+
const current = behaviorSubject.getValue();
|
|
66
|
+
|
|
67
|
+
// Unsubscribe
|
|
68
|
+
unsub(); // call the returned function
|
|
69
|
+
// NOT .unsubscribe() // wrong — does not exist
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Do not use RxJS operators (`.pipe()`, `.map()`, etc.) — these are not RxJS Observables.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Data Types
|
|
77
|
+
|
|
78
|
+
| Concept | Type | Example |
|
|
79
|
+
|---------|------|---------|
|
|
80
|
+
| Money amount | `number` | `5000.50` |
|
|
81
|
+
| Currency | `string` ISO-4217 | `'USD'`, `'AED'`, `'INR'` |
|
|
82
|
+
| Timestamp | `number` epoch ms | `Date.now()` |
|
|
83
|
+
| ID | `string` | `'u-001'` |
|
|
84
|
+
|
|
85
|
+
Never use a Money class, BigDecimal, or `Date` objects.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Error Handling
|
|
90
|
+
|
|
91
|
+
All services throw standard `Error` on invalid input:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
try {
|
|
95
|
+
const result = await service.doSomething(config);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (err instanceof Error) {
|
|
98
|
+
console.error(err.message);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Key Services Quick Reference
|
|
106
|
+
|
|
107
|
+
### Banking
|
|
108
|
+
```ts
|
|
109
|
+
import { JoopDigitalWalletService, JoopLoanServicingService } from 'joopjs';
|
|
110
|
+
|
|
111
|
+
const wallet = new JoopDigitalWalletService();
|
|
112
|
+
const w = wallet.createWallet('user-001', { currency: 'USD' });
|
|
113
|
+
wallet.topUp(w.id, 500);
|
|
114
|
+
wallet.pay(w.id, 50, 'merchant-id', 'Coffee');
|
|
115
|
+
wallet.balance$().subscribe(({ walletId, balance }) => { /* update UI */ });
|
|
116
|
+
|
|
117
|
+
const loans = new JoopLoanServicingService();
|
|
118
|
+
const loan = loans.createLoan({ borrowerName: 'Alice', borrowerId: 'u-001', principalAmount: 10000, annualInterestRatePercent: 8, tenureMonths: 12, currency: 'USD' });
|
|
119
|
+
loans.recordPayment(loan.id, loan.emiAmount);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Auth
|
|
123
|
+
```ts
|
|
124
|
+
import { JoopAuthService } from 'joopjs/auth';
|
|
125
|
+
|
|
126
|
+
const auth = new JoopAuthService();
|
|
127
|
+
const session = await auth.login(email, password);
|
|
128
|
+
auth.session$().subscribe(session => { /* null = logged out */ });
|
|
129
|
+
await auth.logout(session.sessionId);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Encryption
|
|
133
|
+
```ts
|
|
134
|
+
import { JoopGcmService } from 'joopjs/encryption';
|
|
135
|
+
|
|
136
|
+
const gcm = new JoopGcmService();
|
|
137
|
+
const key = await gcm.generateKey();
|
|
138
|
+
const { ciphertext, iv } = await gcm.encrypt('sensitive data', key);
|
|
139
|
+
const plain = await gcm.decrypt(ciphertext, key, iv);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Security
|
|
143
|
+
```ts
|
|
144
|
+
import { JoopAmlService, JoopSanctionsScreeningService } from 'joopjs';
|
|
145
|
+
|
|
146
|
+
const aml = new JoopAmlService();
|
|
147
|
+
aml.addRule({ id: 'r1', name: 'Large cash', type: 'cash', threshold: 10000, currency: 'USD', action: 'flag', enabled: true });
|
|
148
|
+
const alert = aml.checkTransaction({ id: 'tx1', amount: 15000, currency: 'USD', type: 'cash', userId: 'u-001', timestamp: Date.now() });
|
|
149
|
+
|
|
150
|
+
const sanctions = new JoopSanctionsScreeningService();
|
|
151
|
+
sanctions.loadList('ofac', entities);
|
|
152
|
+
const result = sanctions.screen({ name: 'John Doe', country: 'US' });
|
|
153
|
+
// result.status: 'clear' | 'hit' | 'review'
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Framework Integrations
|
|
157
|
+
```tsx
|
|
158
|
+
// React
|
|
159
|
+
import { createJoopReact } from 'joopjs/react';
|
|
160
|
+
const { JoopProvider, useJoopAuth, useJoopTheme } = createJoopReact(React);
|
|
161
|
+
|
|
162
|
+
// Vue
|
|
163
|
+
import { createJoopVue } from 'joopjs/vue';
|
|
164
|
+
const { provideJoop, useJoopAuth } = createJoopVue(Vue);
|
|
165
|
+
|
|
166
|
+
// Angular
|
|
167
|
+
import { provideJoop } from 'joopjs/angular';
|
|
168
|
+
bootstrapApplication(AppComponent, { providers: [provideJoop(joop)] });
|
|
169
|
+
```
|
package/package.json
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joopjs",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Framework-agnostic JavaScript SDK for enterprise web applications. Works with React, Angular, Vue, and any JavaScript project.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
5
|
+
"keywords": [
|
|
6
|
+
"sdk",
|
|
7
|
+
"encryption",
|
|
8
|
+
"session",
|
|
9
|
+
"storage",
|
|
10
|
+
"auth",
|
|
11
|
+
"http",
|
|
12
|
+
"logger",
|
|
13
|
+
"aes",
|
|
14
|
+
"x25519",
|
|
15
|
+
"typescript"
|
|
16
|
+
],
|
|
8
17
|
"license": "MIT",
|
|
9
18
|
"homepage": "https://kundan-leo.github.io/JoopJs/demo/",
|
|
10
19
|
"repository": {
|
|
@@ -14,30 +23,9 @@
|
|
|
14
23
|
"bugs": {
|
|
15
24
|
"url": "https://github.com/kundan-leo/JoopJs/issues"
|
|
16
25
|
},
|
|
17
|
-
"keywords": [
|
|
18
|
-
"sdk",
|
|
19
|
-
"banking",
|
|
20
|
-
"fintech",
|
|
21
|
-
"finance",
|
|
22
|
-
"encryption",
|
|
23
|
-
"auth",
|
|
24
|
-
"aml",
|
|
25
|
-
"sanctions",
|
|
26
|
-
"wallet",
|
|
27
|
-
"loan",
|
|
28
|
-
"typescript",
|
|
29
|
-
"react",
|
|
30
|
-
"angular",
|
|
31
|
-
"vue"
|
|
32
|
-
],
|
|
33
26
|
"main": "dist/index.js",
|
|
34
27
|
"module": "dist/index.mjs",
|
|
35
28
|
"types": "dist/index.d.ts",
|
|
36
|
-
"files": [
|
|
37
|
-
"dist",
|
|
38
|
-
"README.md",
|
|
39
|
-
"CHANGELOG.md"
|
|
40
|
-
],
|
|
41
29
|
"exports": {
|
|
42
30
|
".": {
|
|
43
31
|
"import": "./dist/index.mjs",
|
|
@@ -94,6 +82,11 @@
|
|
|
94
82
|
"require": "./dist/device/index.js",
|
|
95
83
|
"types": "./dist/device/index.d.ts"
|
|
96
84
|
},
|
|
85
|
+
"./dev": {
|
|
86
|
+
"import": "./dist/dev/index.mjs",
|
|
87
|
+
"require": "./dist/dev/index.js",
|
|
88
|
+
"types": "./dist/dev/index.d.ts"
|
|
89
|
+
},
|
|
97
90
|
"./theme": {
|
|
98
91
|
"import": "./dist/theme/index.mjs",
|
|
99
92
|
"require": "./dist/theme/index.js",
|
|
@@ -210,6 +203,43 @@
|
|
|
210
203
|
"types": "./dist/india/index.d.ts"
|
|
211
204
|
}
|
|
212
205
|
},
|
|
206
|
+
"files": [
|
|
207
|
+
"dist",
|
|
208
|
+
"CHANGELOG.md",
|
|
209
|
+
"ai-rules",
|
|
210
|
+
"scripts/setup-ai.mjs",
|
|
211
|
+
".claude/skills/setup.md",
|
|
212
|
+
".claude/skills/banking.md",
|
|
213
|
+
".claude/skills/finance.md",
|
|
214
|
+
".claude/skills/security.md",
|
|
215
|
+
".claude/skills/auth.md",
|
|
216
|
+
".claude/skills/encryption.md",
|
|
217
|
+
".claude/skills/observables.md",
|
|
218
|
+
".cursor/rules/joopjs.mdc",
|
|
219
|
+
".windsurf/rules/joopjs.md",
|
|
220
|
+
".github/copilot-instructions.md"
|
|
221
|
+
],
|
|
222
|
+
"bin": {
|
|
223
|
+
"joopjs": "scripts/setup-ai.mjs"
|
|
224
|
+
},
|
|
225
|
+
"scripts": {
|
|
226
|
+
"build": "tsup",
|
|
227
|
+
"build:watch": "tsup --watch",
|
|
228
|
+
"typecheck": "tsc --noEmit",
|
|
229
|
+
"clean": "rimraf dist dist-playground",
|
|
230
|
+
"test": "vitest run",
|
|
231
|
+
"test:ui": "vitest --ui --open",
|
|
232
|
+
"test:watch": "vitest",
|
|
233
|
+
"test:coverage": "vitest run --coverage",
|
|
234
|
+
"playground": "vite playground/ --config playground/vite.config.ts",
|
|
235
|
+
"playground:build": "vite build playground/ --config playground/vite.config.ts",
|
|
236
|
+
"preflight": "node scripts/preflight.mjs",
|
|
237
|
+
"release:dry": "node scripts/release.mjs --dry-run",
|
|
238
|
+
"release:patch": "node scripts/release.mjs patch",
|
|
239
|
+
"release:minor": "node scripts/release.mjs minor",
|
|
240
|
+
"release:major": "node scripts/release.mjs major",
|
|
241
|
+
"release": "node scripts/release.mjs"
|
|
242
|
+
},
|
|
213
243
|
"dependencies": {
|
|
214
244
|
"@noble/ciphers": "^2.2.0",
|
|
215
245
|
"@noble/curves": "^2.2.0",
|
|
@@ -222,14 +252,34 @@
|
|
|
222
252
|
"vue": ">=3.0.0"
|
|
223
253
|
},
|
|
224
254
|
"peerDependenciesMeta": {
|
|
225
|
-
"react": {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
"
|
|
255
|
+
"react": {
|
|
256
|
+
"optional": true
|
|
257
|
+
},
|
|
258
|
+
"@angular/core": {
|
|
259
|
+
"optional": true
|
|
260
|
+
},
|
|
261
|
+
"rxjs": {
|
|
262
|
+
"optional": true
|
|
263
|
+
},
|
|
264
|
+
"vue": {
|
|
265
|
+
"optional": true
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
"devDependencies": {
|
|
269
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
270
|
+
"@vitest/ui": "^2.1.0",
|
|
271
|
+
"fake-indexeddb": "^6.2.5",
|
|
272
|
+
"jsdom": "^29.1.1",
|
|
273
|
+
"rimraf": "^5.0.0",
|
|
274
|
+
"tsup": "^8.3.0",
|
|
275
|
+
"typescript": "^5.3.3",
|
|
276
|
+
"vite": "^5.4.0",
|
|
277
|
+
"vitest": "^2.1.0"
|
|
229
278
|
},
|
|
230
279
|
"engines": {
|
|
231
280
|
"node": ">=18.0.0"
|
|
232
281
|
},
|
|
233
|
-
"
|
|
282
|
+
"author": {
|
|
283
|
+
"name": "Kundan Singh"
|
|
284
|
+
}
|
|
234
285
|
}
|
|
235
|
-
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* joopjs setup-ai
|
|
4
|
+
*
|
|
5
|
+
* Copies AI assistant rules for joopjs into your project so that
|
|
6
|
+
* Claude Code, Cursor, Windsurf, GitHub Copilot, Gemini CLI, and Codex
|
|
7
|
+
* all understand how to use the joopjs SDK correctly.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npx joopjs setup-ai # copy rules (skip existing files)
|
|
11
|
+
* npx joopjs setup-ai --force # overwrite existing files
|
|
12
|
+
* npx joopjs # show help
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { copyFileSync, mkdirSync, existsSync } from 'fs';
|
|
16
|
+
import { resolve, dirname, join, basename } from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const PACKAGE_DIR = resolve(__dirname, '..');
|
|
21
|
+
const PROJECT_DIR = process.cwd();
|
|
22
|
+
const FORCE = process.argv.includes('--force');
|
|
23
|
+
const CMD = process.argv[2];
|
|
24
|
+
|
|
25
|
+
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
26
|
+
const ok = msg => console.log(` ✓ ${msg}`);
|
|
27
|
+
const skip = msg => console.log(` · skipped ${msg} (use --force to overwrite)`);
|
|
28
|
+
const info = msg => console.log(` ${msg}`);
|
|
29
|
+
const hr = () => console.log(`\n${'━'.repeat(52)}`);
|
|
30
|
+
|
|
31
|
+
function ensureDir(dir) {
|
|
32
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function copyFile(src, dest) {
|
|
36
|
+
const label = dest.replace(PROJECT_DIR + '/', '').replace(PROJECT_DIR + '\\', '');
|
|
37
|
+
if (!existsSync(src)) return;
|
|
38
|
+
if (existsSync(dest) && !FORCE) { skip(label); return; }
|
|
39
|
+
ensureDir(dirname(dest));
|
|
40
|
+
copyFileSync(src, dest);
|
|
41
|
+
ok(label);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ── help ─────────────────────────────────────────────────────────────────────
|
|
45
|
+
function showHelp() {
|
|
46
|
+
console.log(`
|
|
47
|
+
joopjs — AI rules setup for joopjs
|
|
48
|
+
|
|
49
|
+
Usage:
|
|
50
|
+
npx joopjs setup-ai Copy AI rules to your project
|
|
51
|
+
npx joopjs setup-ai --force Overwrite existing rule files
|
|
52
|
+
|
|
53
|
+
What gets copied:
|
|
54
|
+
.claude/skills/joopjs-*.md Claude Code skills (7 skills)
|
|
55
|
+
.cursor/rules/joopjs.mdc Cursor rule
|
|
56
|
+
.windsurf/rules/joopjs.md Windsurf Cascade rule
|
|
57
|
+
.github/copilot-instructions.md GitHub Copilot instructions
|
|
58
|
+
GEMINI.md Gemini CLI instructions
|
|
59
|
+
AGENTS.md Codex / OpenAI Agents instructions
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── main ─────────────────────────────────────────────────────────────────────
|
|
64
|
+
if (CMD !== 'setup-ai') {
|
|
65
|
+
showHelp();
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
hr();
|
|
70
|
+
console.log(' joopjs — AI Rules Setup');
|
|
71
|
+
if (FORCE) console.log(' MODE: --force (existing files will be overwritten)');
|
|
72
|
+
hr();
|
|
73
|
+
console.log('');
|
|
74
|
+
|
|
75
|
+
// ── 1. Claude Code skills ─────────────────────────────────────────────────────
|
|
76
|
+
console.log(' Claude Code skills:');
|
|
77
|
+
const CONSUMER_SKILLS = ['setup', 'banking', 'finance', 'security', 'auth', 'encryption', 'observables'];
|
|
78
|
+
for (const skill of CONSUMER_SKILLS) {
|
|
79
|
+
copyFile(
|
|
80
|
+
join(PACKAGE_DIR, '.claude', 'skills', `${skill}.md`),
|
|
81
|
+
join(PROJECT_DIR, '.claude', 'skills', `joopjs-${skill}.md`)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── 2. Cursor ─────────────────────────────────────────────────────────────────
|
|
86
|
+
console.log('\n Cursor:');
|
|
87
|
+
copyFile(
|
|
88
|
+
join(PACKAGE_DIR, '.cursor', 'rules', 'joopjs.mdc'),
|
|
89
|
+
join(PROJECT_DIR, '.cursor', 'rules', 'joopjs.mdc')
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// ── 3. Windsurf ───────────────────────────────────────────────────────────────
|
|
93
|
+
console.log('\n Windsurf Cascade:');
|
|
94
|
+
copyFile(
|
|
95
|
+
join(PACKAGE_DIR, '.windsurf', 'rules', 'joopjs.md'),
|
|
96
|
+
join(PROJECT_DIR, '.windsurf', 'rules', 'joopjs.md')
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// ── 4. GitHub Copilot ─────────────────────────────────────────────────────────
|
|
100
|
+
console.log('\n GitHub Copilot:');
|
|
101
|
+
copyFile(
|
|
102
|
+
join(PACKAGE_DIR, '.github', 'copilot-instructions.md'),
|
|
103
|
+
join(PROJECT_DIR, '.github', 'copilot-instructions.md')
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// ── 5. Gemini CLI ─────────────────────────────────────────────────────────────
|
|
107
|
+
console.log('\n Gemini CLI:');
|
|
108
|
+
copyFile(
|
|
109
|
+
join(PACKAGE_DIR, 'ai-rules', 'GEMINI.md'),
|
|
110
|
+
join(PROJECT_DIR, 'GEMINI.md')
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// ── 6. Codex / OpenAI Agents ─────────────────────────────────────────────────
|
|
114
|
+
console.log('\n Codex / OpenAI Agents:');
|
|
115
|
+
copyFile(
|
|
116
|
+
join(PACKAGE_DIR, 'ai-rules', 'AGENTS.md'),
|
|
117
|
+
join(PROJECT_DIR, 'AGENTS.md')
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// ── summary ───────────────────────────────────────────────────────────────────
|
|
121
|
+
hr();
|
|
122
|
+
console.log(' Done! Your AI tools now understand joopjs.\n');
|
|
123
|
+
console.log(' Next steps:');
|
|
124
|
+
console.log(' 1. Claude Code — add skills to your CLAUDE.md:');
|
|
125
|
+
console.log('');
|
|
126
|
+
for (const skill of CONSUMER_SKILLS) {
|
|
127
|
+
console.log(` | /joopjs-${skill.padEnd(11)} | JoopJS ${skill} guide |`);
|
|
128
|
+
}
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log(' 2. Cursor / Windsurf — rules are auto-detected from their folders.');
|
|
131
|
+
console.log(' 3. Copilot / Gemini / Codex — files are at project root, ready to use.');
|
|
132
|
+
hr();
|
|
133
|
+
console.log('');
|