@cranberry-money/shared-services 8.1.3 → 10.0.2
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/README.md +157 -448
- package/dist/auth.d.ts +85 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +106 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,550 +1,259 @@
|
|
|
1
|
-
# @cranberry-money/shared-services
|
|
1
|
+
# @cranberry-money/shared-services
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Platform-agnostic service functions** that work with any axios-compatible API client.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/%40cranberry-money%2Fshared-services)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
|
-
[](https://reactjs.org/)
|
|
8
7
|
|
|
9
|
-
##
|
|
8
|
+
## 📦 Package Overview
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- **
|
|
10
|
+
This package provides reusable service functions for the Blueberry platform ecosystem. Services are pure functions that accept an API client, allowing the same business logic to work across web browsers, mobile apps, and testing environments.
|
|
11
|
+
|
|
12
|
+
### Core Philosophy
|
|
13
|
+
|
|
14
|
+
- **One service implementation, multiple platforms**: Write once, use everywhere
|
|
15
|
+
- **Platform owns authentication**: Each platform handles auth its own way (cookies, tokens, etc.)
|
|
16
|
+
- **Simple and functional**: No complex patterns, just functions that call APIs
|
|
17
|
+
- **Fully typed**: Complete TypeScript support with types from `@cranberry-money/shared-types`
|
|
16
18
|
|
|
17
19
|
## 🚀 Quick Start
|
|
18
20
|
|
|
19
21
|
### Installation
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
|
-
npm install @cranberry-money/shared-services
|
|
24
|
+
npm install @cranberry-money/shared-services
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
### Basic
|
|
27
|
+
### Basic Usage
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
createWebServiceFactory,
|
|
30
|
-
initializeFeatureFlags
|
|
31
|
-
} from '@cranberry-money/shared-services';
|
|
32
|
-
|
|
33
|
-
// 1. Initialize feature flags (optional but recommended)
|
|
34
|
-
await initializeFeatureFlags({
|
|
35
|
-
useFunctionalApiClient: true,
|
|
36
|
-
useFunctionalAuth: true,
|
|
37
|
-
useFunctionalPortfolios: true,
|
|
38
|
-
enablePerformanceMonitoring: true,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// 2. Create service factory
|
|
42
|
-
const services = createWebServiceFactory('https://api.example.com', {
|
|
43
|
-
apiTimeout: 10000,
|
|
44
|
-
enableCredentials: true,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// 3. Set up authentication provider
|
|
48
|
-
const AuthProvider = services.auth.createAuthProvider();
|
|
49
|
-
|
|
50
|
-
function App() {
|
|
51
|
-
return (
|
|
52
|
-
<AuthProvider>
|
|
53
|
-
<Dashboard />
|
|
54
|
-
</AuthProvider>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## 🏗 Architecture Overview
|
|
60
|
-
|
|
61
|
-
### Service Factory Pattern
|
|
62
|
-
|
|
63
|
-
The v3.0.0 architecture uses a service factory pattern that creates all services with explicit dependency injection:
|
|
29
|
+
#### Web Application (with cookies)
|
|
64
30
|
|
|
65
31
|
```typescript
|
|
66
|
-
//
|
|
67
|
-
|
|
32
|
+
// src/services/webApiClient.ts
|
|
33
|
+
import axios from 'axios';
|
|
68
34
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
35
|
+
export const webApiClient = axios.create({
|
|
36
|
+
baseURL: import.meta.env.VITE_API_URL,
|
|
37
|
+
withCredentials: true, // Use cookies for auth
|
|
38
|
+
});
|
|
72
39
|
```
|
|
73
40
|
|
|
74
|
-
### Pure Functional Design
|
|
75
|
-
|
|
76
|
-
All operations are pure functions with explicit dependencies:
|
|
77
|
-
|
|
78
41
|
```typescript
|
|
79
|
-
//
|
|
80
|
-
import {
|
|
42
|
+
// src/services/portfolios.ts
|
|
43
|
+
import { webApiClient } from './webApiClient';
|
|
44
|
+
import { createPortfolioService } from '@cranberry-money/shared-services';
|
|
81
45
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
tokenStorage: createWebTokenStorage(),
|
|
85
|
-
};
|
|
46
|
+
// Create your platform-specific service
|
|
47
|
+
export const portfolioService = createPortfolioService(webApiClient);
|
|
86
48
|
|
|
87
|
-
|
|
49
|
+
// Use in your application
|
|
50
|
+
const portfolios = await portfolioService.getAll();
|
|
51
|
+
const portfolio = await portfolioService.create({ name: 'My Portfolio' });
|
|
88
52
|
```
|
|
89
53
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
### React Context Integration
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import {
|
|
96
|
-
useFunctionalAuthState,
|
|
97
|
-
useFunctionalAuthActions,
|
|
98
|
-
FunctionalAuthGuard
|
|
99
|
-
} from '@cranberry-money/shared-services';
|
|
100
|
-
|
|
101
|
-
function Dashboard() {
|
|
102
|
-
const authState = useFunctionalAuthState();
|
|
103
|
-
const authActions = useFunctionalAuthActions();
|
|
104
|
-
|
|
105
|
-
const handleSignin = async () => {
|
|
106
|
-
try {
|
|
107
|
-
await authActions.signin({
|
|
108
|
-
email: 'user@example.com',
|
|
109
|
-
password: 'password123',
|
|
110
|
-
});
|
|
111
|
-
} catch (error) {
|
|
112
|
-
console.error('Signin failed:', error);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<FunctionalAuthGuard fallback={<LoginForm />}>
|
|
118
|
-
<div>
|
|
119
|
-
<h1>Welcome, {authState.user?.firstName}!</h1>
|
|
120
|
-
<button onClick={authActions.signout}>Sign Out</button>
|
|
121
|
-
</div>
|
|
122
|
-
</FunctionalAuthGuard>
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Platform-Specific Token Storage
|
|
54
|
+
#### Mobile Application (with tokens)
|
|
128
55
|
|
|
129
56
|
```typescript
|
|
130
|
-
//
|
|
131
|
-
import
|
|
132
|
-
const webStorage = createWebTokenStorage();
|
|
133
|
-
|
|
134
|
-
// Mobile (secure storage)
|
|
135
|
-
import { createMobileTokenStorage } from '@cranberry-money/shared-services';
|
|
57
|
+
// src/services/mobileApiClient.ts
|
|
58
|
+
import axios from 'axios';
|
|
136
59
|
import * as SecureStore from 'expo-secure-store';
|
|
137
|
-
const mobileStorage = createMobileTokenStorage(SecureStore);
|
|
138
|
-
|
|
139
|
-
// Testing (in-memory)
|
|
140
|
-
import { createMemoryTokenStorage } from '@cranberry-money/shared-services';
|
|
141
|
-
const testStorage = createMemoryTokenStorage();
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## 🌐 API Client
|
|
145
|
-
|
|
146
|
-
### Functional API Client
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
import { createFunctionalApiClient } from '@cranberry-money/shared-services';
|
|
150
|
-
|
|
151
|
-
const apiClient = createFunctionalApiClient({
|
|
152
|
-
baseURL: 'https://api.example.com',
|
|
153
|
-
timeout: 10000,
|
|
154
|
-
defaultHeaders: {
|
|
155
|
-
'X-Client-Version': '3.0.0',
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
60
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const result = await apiClient.post('/api/items', { name: 'Item' });
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Platform-Specific Clients
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
// Web-optimized client
|
|
168
|
-
import { createFunctionalWebApiClient } from '@cranberry-money/shared-services';
|
|
169
|
-
const webClient = createFunctionalWebApiClient('https://api.example.com');
|
|
170
|
-
|
|
171
|
-
// Mobile-optimized client
|
|
172
|
-
import { createFunctionalMobileApiClient } from '@cranberry-money/shared-services';
|
|
173
|
-
const mobileClient = createFunctionalMobileApiClient('https://api.example.com');
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
## 💼 Service Usage
|
|
177
|
-
|
|
178
|
-
### Portfolio Services
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
// Get portfolios with filtering and sorting
|
|
182
|
-
const portfolios = await services.portfolio.getPortfolios({
|
|
183
|
-
isActive: true,
|
|
184
|
-
sortBy: 'totalValue',
|
|
185
|
-
sortOrder: 'desc',
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// Create new portfolio
|
|
189
|
-
const newPortfolio = await services.portfolio.createPortfolio({
|
|
190
|
-
name: 'My Investment Portfolio',
|
|
191
|
-
description: 'Long-term growth strategy',
|
|
61
|
+
export const mobileApiClient = axios.create({
|
|
62
|
+
baseURL: process.env.API_URL,
|
|
192
63
|
});
|
|
193
64
|
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
65
|
+
// Add auth token to requests
|
|
66
|
+
mobileApiClient.interceptors.request.use(async (config) => {
|
|
67
|
+
const token = await SecureStore.getItemAsync('authToken');
|
|
68
|
+
if (token) {
|
|
69
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
70
|
+
}
|
|
71
|
+
return config;
|
|
198
72
|
});
|
|
199
73
|
```
|
|
200
74
|
|
|
201
|
-
### Reference Data Services
|
|
202
|
-
|
|
203
75
|
```typescript
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
76
|
+
// src/services/portfolios.ts
|
|
77
|
+
import { mobileApiClient } from './mobileApiClient';
|
|
78
|
+
import { createPortfolioService } from '@cranberry-money/shared-services';
|
|
207
79
|
|
|
208
|
-
|
|
209
|
-
const countries = await referenceData.getActiveCountries();
|
|
210
|
-
const industries = await referenceData.getIndustries();
|
|
211
|
-
const sectors = await referenceData.getSectorsByIndustry('tech-industry-id');
|
|
212
|
-
const exchanges = await referenceData.getStockExchangesByCountry('usa-id');
|
|
80
|
+
export const portfolioService = createPortfolioService(mobileApiClient);
|
|
213
81
|
```
|
|
214
82
|
|
|
215
|
-
##
|
|
83
|
+
## 📚 Service Patterns
|
|
216
84
|
|
|
217
|
-
###
|
|
85
|
+
### Pattern 1: Service Factory (Recommended)
|
|
218
86
|
|
|
219
|
-
|
|
220
|
-
// Start with all functional features disabled
|
|
221
|
-
await initializeFeatureFlags({
|
|
222
|
-
useFunctionalApiClient: false,
|
|
223
|
-
useFunctionalAuth: false,
|
|
224
|
-
useFunctionalPortfolios: false,
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
// Enable gradually
|
|
228
|
-
const flags = getFeatureFlags();
|
|
229
|
-
await flags.updateFlags({ useFunctionalApiClient: true });
|
|
230
|
-
// Test for 1-2 days...
|
|
231
|
-
|
|
232
|
-
await flags.updateFlags({ useFunctionalPortfolios: true });
|
|
233
|
-
// Test for 1-2 days...
|
|
234
|
-
|
|
235
|
-
await flags.updateFlags({ useFunctionalAuth: true });
|
|
236
|
-
// Complete migration
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### Migration Helpers
|
|
87
|
+
Group related operations together:
|
|
240
88
|
|
|
241
89
|
```typescript
|
|
242
|
-
import {
|
|
243
|
-
|
|
244
|
-
const helpers = createMigrationHelpers(services, {
|
|
245
|
-
apiClient: legacyApiClient,
|
|
246
|
-
authManager: legacyAuthManager,
|
|
247
|
-
});
|
|
90
|
+
import { createPortfolioService } from '@cranberry-money/shared-services';
|
|
91
|
+
import { webApiClient } from './webApiClient'; // or mobileApiClient for mobile
|
|
248
92
|
|
|
249
|
-
|
|
250
|
-
const data = await helpers.apiClient.get('/api/data');
|
|
93
|
+
const portfolioService = createPortfolioService(webApiClient);
|
|
251
94
|
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
95
|
+
// All portfolio operations in one object
|
|
96
|
+
await portfolioService.getAll({ page: 1 });
|
|
97
|
+
await portfolioService.getByUuid('123');
|
|
98
|
+
await portfolioService.create({ name: 'Tech Portfolio' });
|
|
99
|
+
await portfolioService.update('123', { name: 'Updated Portfolio' });
|
|
100
|
+
await portfolioService.delete('123');
|
|
257
101
|
```
|
|
258
102
|
|
|
259
|
-
|
|
103
|
+
### Pattern 2: Individual Functions
|
|
260
104
|
|
|
261
|
-
|
|
105
|
+
For better tree-shaking and selective imports:
|
|
262
106
|
|
|
263
107
|
```typescript
|
|
264
|
-
import {
|
|
108
|
+
import { getPortfolios, createPortfolio } from '@cranberry-money/shared-services';
|
|
109
|
+
import { webApiClient } from './webApiClient'; // or mobileApiClient for mobile
|
|
265
110
|
|
|
266
|
-
//
|
|
267
|
-
const
|
|
268
|
-
|
|
111
|
+
// Create platform-specific functions
|
|
112
|
+
const getMyPortfolios = getPortfolios(webApiClient);
|
|
113
|
+
const createMyPortfolio = createPortfolio(webApiClient);
|
|
269
114
|
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### Performance Tracking
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
import { monitorMigrationPerformance } from '@cranberry-money/shared-services';
|
|
279
|
-
|
|
280
|
-
// Wrap functions for automatic performance tracking
|
|
281
|
-
const monitored = monitorMigrationPerformance('api.getPortfolios', 'functional', () =>
|
|
282
|
-
services.portfolio.getPortfolios()
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
const result = await monitored();
|
|
286
|
-
// Automatically logs performance metrics
|
|
115
|
+
// Use them
|
|
116
|
+
await getMyPortfolios({ page: 1 });
|
|
117
|
+
await createMyPortfolio({ name: 'New Portfolio' });
|
|
287
118
|
```
|
|
288
119
|
|
|
289
120
|
## 🧪 Testing
|
|
290
121
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
```typescript
|
|
294
|
-
import { signin, createMemoryTokenStorage } from '@cranberry-money/shared-services';
|
|
295
|
-
|
|
296
|
-
describe('Authentication', () => {
|
|
297
|
-
it('should signin successfully', async () => {
|
|
298
|
-
const mockApiClient = {
|
|
299
|
-
post: jest.fn().mockResolvedValue({
|
|
300
|
-
access: 'access-token',
|
|
301
|
-
refresh: 'refresh-token',
|
|
302
|
-
user: { id: '1', email: 'test@example.com' },
|
|
303
|
-
}),
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
const deps = {
|
|
307
|
-
apiClient: mockApiClient,
|
|
308
|
-
tokenStorage: createMemoryTokenStorage(),
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
const result = await signin({ email: 'test@example.com', password: 'password' }, deps);
|
|
312
|
-
|
|
313
|
-
expect(result.user.email).toBe('test@example.com');
|
|
314
|
-
expect(mockApiClient.post).toHaveBeenCalledWith('/api/signin/', {
|
|
315
|
-
email: 'test@example.com',
|
|
316
|
-
password: 'password',
|
|
317
|
-
});
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### React Testing
|
|
122
|
+
Services are easy to test with mock API clients:
|
|
323
123
|
|
|
324
124
|
```typescript
|
|
325
|
-
import {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
test('should display user name when authenticated', () => {
|
|
336
|
-
render(
|
|
337
|
-
<TestAuthProvider>
|
|
338
|
-
<Dashboard />
|
|
339
|
-
</TestAuthProvider>
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
// Test auth-dependent component
|
|
343
|
-
});
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
## 🔧 Configuration
|
|
347
|
-
|
|
348
|
-
### Web Application Setup
|
|
349
|
-
|
|
350
|
-
```typescript
|
|
351
|
-
import { createWebServiceFactory } from '@cranberry-money/shared-services';
|
|
352
|
-
|
|
353
|
-
const services = createWebServiceFactory(process.env.REACT_APP_API_URL, {
|
|
354
|
-
apiTimeout: 15000,
|
|
355
|
-
enableCredentials: true,
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
export { services };
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### Mobile Application Setup
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
import { createMobileServiceFactory } from '@cranberry-money/shared-services';
|
|
365
|
-
import * as SecureStore from 'expo-secure-store';
|
|
366
|
-
|
|
367
|
-
const services = createMobileServiceFactory(process.env.EXPO_PUBLIC_API_URL, SecureStore, {
|
|
368
|
-
apiTimeout: 20000,
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
export { services };
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
### Environment-Based Configuration
|
|
375
|
-
|
|
376
|
-
```typescript
|
|
377
|
-
const getApiUrl = () => {
|
|
378
|
-
switch (process.env.NODE_ENV) {
|
|
379
|
-
case 'production':
|
|
380
|
-
return 'https://api.myportfolio.com';
|
|
381
|
-
case 'staging':
|
|
382
|
-
return 'https://staging-api.myportfolio.com';
|
|
383
|
-
default:
|
|
384
|
-
return 'http://localhost:8000';
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
const services = createWebServiceFactory(getApiUrl());
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
## 📚 Advanced Usage
|
|
125
|
+
import { createPortfolioService } from '@cranberry-money/shared-services';
|
|
126
|
+
|
|
127
|
+
describe('Portfolio Service', () => {
|
|
128
|
+
const mockApiClient = {
|
|
129
|
+
get: jest.fn(),
|
|
130
|
+
post: jest.fn(),
|
|
131
|
+
patch: jest.fn(),
|
|
132
|
+
delete: jest.fn()
|
|
133
|
+
};
|
|
392
134
|
|
|
393
|
-
|
|
135
|
+
const portfolioService = createPortfolioService(mockApiClient);
|
|
394
136
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
137
|
+
it('should fetch portfolios', async () => {
|
|
138
|
+
mockApiClient.get.mockResolvedValue({
|
|
139
|
+
data: { results: [], count: 0 }
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const result = await portfolioService.getAll();
|
|
143
|
+
|
|
144
|
+
expect(mockApiClient.get).toHaveBeenCalledWith('/api/portfolios/', {
|
|
145
|
+
params: undefined
|
|
146
|
+
});
|
|
147
|
+
});
|
|
404
148
|
});
|
|
405
149
|
```
|
|
406
150
|
|
|
407
|
-
|
|
151
|
+
## 🔄 React Query Integration
|
|
408
152
|
|
|
409
|
-
|
|
410
|
-
import { isFunctionalApiError } from '@cranberry-money/shared-services';
|
|
411
|
-
|
|
412
|
-
try {
|
|
413
|
-
const data = await services.portfolio.getPortfolios();
|
|
414
|
-
} catch (error) {
|
|
415
|
-
if (isFunctionalApiError(error)) {
|
|
416
|
-
console.error(`API Error (${error.status}): ${error.message}`);
|
|
417
|
-
if (error.details) {
|
|
418
|
-
console.error('Details:', error.details);
|
|
419
|
-
}
|
|
420
|
-
} else {
|
|
421
|
-
console.error('Unexpected error:', error);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Integration with React Query
|
|
153
|
+
Works seamlessly with React Query:
|
|
427
154
|
|
|
428
155
|
```typescript
|
|
429
156
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
157
|
+
import { portfolioService } from '@services/portfolios';
|
|
430
158
|
|
|
431
|
-
|
|
159
|
+
export const usePortfolios = (params?) => {
|
|
432
160
|
return useQuery({
|
|
433
|
-
queryKey: ['portfolios'],
|
|
434
|
-
queryFn: () =>
|
|
435
|
-
|
|
436
|
-
isActive: true,
|
|
437
|
-
sortBy: 'totalValue',
|
|
438
|
-
sortOrder: 'desc',
|
|
439
|
-
}),
|
|
440
|
-
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
161
|
+
queryKey: ['portfolios', params],
|
|
162
|
+
queryFn: () => portfolioService.getAll(params),
|
|
163
|
+
staleTime: 5 * 60 * 1000,
|
|
441
164
|
});
|
|
442
|
-
}
|
|
165
|
+
};
|
|
443
166
|
|
|
444
|
-
|
|
167
|
+
export const useCreatePortfolio = () => {
|
|
445
168
|
const queryClient = useQueryClient();
|
|
446
|
-
|
|
169
|
+
|
|
447
170
|
return useMutation({
|
|
448
|
-
mutationFn:
|
|
171
|
+
mutationFn: portfolioService.create,
|
|
449
172
|
onSuccess: () => {
|
|
450
173
|
queryClient.invalidateQueries({ queryKey: ['portfolios'] });
|
|
451
174
|
},
|
|
452
175
|
});
|
|
453
|
-
}
|
|
176
|
+
};
|
|
454
177
|
```
|
|
455
178
|
|
|
456
|
-
##
|
|
457
|
-
|
|
458
|
-
- **[Migration Guide](../../docs/MIGRATION-V3.md)**: Complete guide for migrating from v2.x
|
|
459
|
-
- **[Architecture Overview](../../docs/ARCHITECTURE.md)**: Detailed architecture documentation
|
|
460
|
-
- **[Best Practices](../../docs/BEST-PRACTICES.md)**: Code standards and patterns
|
|
461
|
-
- **[Service Development Guide](../../docs/SERVICE-DEVELOPMENT-GUIDE.md)**: Creating new services
|
|
462
|
-
|
|
463
|
-
## 🛠 Development
|
|
464
|
-
|
|
465
|
-
```bash
|
|
466
|
-
# Install dependencies
|
|
467
|
-
npm install
|
|
179
|
+
## 🌐 Available Services
|
|
468
180
|
|
|
469
|
-
|
|
470
|
-
|
|
181
|
+
### Financial Services
|
|
182
|
+
- `createPortfolioService` - Portfolio management
|
|
183
|
+
- `createAccountService` - Account operations
|
|
184
|
+
- `createTradeService` - Trading operations
|
|
185
|
+
- `createInstrumentService` - Financial instruments
|
|
186
|
+
- `createWithdrawalService` - Withdrawal requests
|
|
471
187
|
|
|
472
|
-
|
|
473
|
-
|
|
188
|
+
### Banking Services
|
|
189
|
+
- `createBankService` - Bank management
|
|
190
|
+
- `createCashAccountService` - Cash accounts
|
|
191
|
+
- `createTransactionService` - Transactions
|
|
474
192
|
|
|
475
|
-
|
|
476
|
-
|
|
193
|
+
### User & Compliance
|
|
194
|
+
- `createAuthService` - Authentication
|
|
195
|
+
- `createUserService` - User profiles
|
|
196
|
+
- `createDocumentService` - Documents
|
|
197
|
+
- `createTaxResidencyService` - Tax information
|
|
198
|
+
- `createInvestmentPreferenceService` - Investment preferences
|
|
477
199
|
|
|
478
|
-
|
|
479
|
-
|
|
200
|
+
### Reference Data
|
|
201
|
+
- `createCountryService` - Country data
|
|
202
|
+
- `createIndustryService` - Industries
|
|
203
|
+
- `createSectorService` - Sectors
|
|
204
|
+
- `createStockExchangeService` - Stock exchanges
|
|
480
205
|
|
|
481
|
-
|
|
482
|
-
npm run lint
|
|
483
|
-
```
|
|
206
|
+
## 📦 API Client Requirements
|
|
484
207
|
|
|
485
|
-
|
|
208
|
+
Your API client must implement this interface:
|
|
486
209
|
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
│ └── __tests__/
|
|
496
|
-
├── services/ # Service factories
|
|
497
|
-
│ ├── factories/ # Factory pattern implementation
|
|
498
|
-
│ └── __tests__/
|
|
499
|
-
├── migration/ # Migration utilities
|
|
500
|
-
│ ├── domains/ # Domain-specific migrations
|
|
501
|
-
│ ├── feature-flags.ts # Feature flag system
|
|
502
|
-
│ ├── migration-helpers.ts
|
|
503
|
-
│ └── __tests__/
|
|
504
|
-
├── integration/ # Integration examples
|
|
505
|
-
│ ├── blueberry-integration.tsx
|
|
506
|
-
│ ├── performance-benchmark.ts
|
|
507
|
-
│ └── __tests__/
|
|
508
|
-
└── index.ts # Main exports
|
|
210
|
+
```typescript
|
|
211
|
+
interface ApiClient {
|
|
212
|
+
get<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
213
|
+
post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
214
|
+
put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
215
|
+
patch<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
216
|
+
delete<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
217
|
+
}
|
|
509
218
|
```
|
|
510
219
|
|
|
511
|
-
|
|
220
|
+
Any axios instance automatically satisfies this interface.
|
|
512
221
|
|
|
513
|
-
|
|
222
|
+
## 🔗 Related Packages
|
|
514
223
|
|
|
515
|
-
- `
|
|
516
|
-
- `
|
|
517
|
-
- `
|
|
224
|
+
- `@cranberry-money/shared-types` - TypeScript type definitions
|
|
225
|
+
- `@cranberry-money/shared-constants` - API endpoints and business constants
|
|
226
|
+
- `@cranberry-money/shared-utils` - Utility functions for formatting and validation
|
|
518
227
|
|
|
519
|
-
|
|
228
|
+
## 💡 Migration from Local Services
|
|
520
229
|
|
|
521
|
-
|
|
522
|
-
- `expo-secure-store` - For mobile secure storage
|
|
230
|
+
If you're currently using local service implementations in your app:
|
|
523
231
|
|
|
524
|
-
|
|
232
|
+
### Before (Local Implementation)
|
|
233
|
+
```typescript
|
|
234
|
+
// src/services/portfolios.ts
|
|
235
|
+
import webApiClient from './webApiClient';
|
|
525
236
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
237
|
+
export const getPortfolios = (params?) => {
|
|
238
|
+
return webApiClient.get('/api/portfolios/', { params });
|
|
239
|
+
};
|
|
240
|
+
```
|
|
529
241
|
|
|
530
|
-
|
|
242
|
+
### After (Shared Implementation)
|
|
243
|
+
```typescript
|
|
244
|
+
// src/services/portfolios.ts
|
|
245
|
+
import webApiClient from './webApiClient';
|
|
246
|
+
import { createPortfolioService } from '@cranberry-money/shared-services';
|
|
531
247
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
5. Open a Pull Request
|
|
248
|
+
export const portfolioService = createPortfolioService(webApiClient);
|
|
249
|
+
// or
|
|
250
|
+
export const { getAll: getPortfolios } = createPortfolioService(webApiClient);
|
|
251
|
+
```
|
|
537
252
|
|
|
538
253
|
## 📄 License
|
|
539
254
|
|
|
540
255
|
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
541
256
|
|
|
542
|
-
## 🙏 Acknowledgments
|
|
543
|
-
|
|
544
|
-
- Built for the Blueberry platform
|
|
545
|
-
- Inspired by functional programming principles
|
|
546
|
-
- Designed for maximum type safety and developer experience
|
|
547
|
-
|
|
548
257
|
---
|
|
549
258
|
|
|
550
|
-
|
|
259
|
+
For complete documentation and architecture details, see the [Cranberry Development Guide](../../docs/CRANBERRY-DEVELOPMENT-GUIDE.md).
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-agnostic authentication service functions.
|
|
3
|
+
* Works with any axios-compatible API client.
|
|
4
|
+
*/
|
|
5
|
+
import { AxiosInstance, AxiosResponse } from 'axios';
|
|
6
|
+
import type { SigninPayload, SignupPayload, EmailVerificationPayload, TokenRefreshData as TokenRefreshResponse, TokenRefreshPayload } from '@cranberry-money/shared-types';
|
|
7
|
+
/**
|
|
8
|
+
* Individual authentication functions with dependency injection
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Sign in a user
|
|
12
|
+
* @param apiClient - Axios-compatible API client
|
|
13
|
+
* @returns Function that accepts signin payload and returns API response
|
|
14
|
+
*/
|
|
15
|
+
export declare const signin: (apiClient: AxiosInstance) => (data: SigninPayload) => Promise<AxiosResponse>;
|
|
16
|
+
/**
|
|
17
|
+
* Sign out the current user
|
|
18
|
+
* @param apiClient - Axios-compatible API client
|
|
19
|
+
* @returns Function that performs signout
|
|
20
|
+
*/
|
|
21
|
+
export declare const signout: (apiClient: AxiosInstance) => () => Promise<AxiosResponse>;
|
|
22
|
+
/**
|
|
23
|
+
* Sign up a new user
|
|
24
|
+
* @param apiClient - Axios-compatible API client
|
|
25
|
+
* @returns Function that accepts signup payload and returns API response
|
|
26
|
+
*/
|
|
27
|
+
export declare const signup: (apiClient: AxiosInstance) => (data: SignupPayload) => Promise<AxiosResponse>;
|
|
28
|
+
/**
|
|
29
|
+
* Verify user's email with verification code
|
|
30
|
+
* @param apiClient - Axios-compatible API client
|
|
31
|
+
* @returns Function that accepts verification payload and returns API response
|
|
32
|
+
*/
|
|
33
|
+
export declare const verifyEmail: (apiClient: AxiosInstance) => (data: EmailVerificationPayload) => Promise<AxiosResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Resend email verification code
|
|
36
|
+
* @param apiClient - Axios-compatible API client
|
|
37
|
+
* @returns Function that performs resend operation
|
|
38
|
+
*/
|
|
39
|
+
export declare const resendVerificationCode: (apiClient: AxiosInstance) => () => Promise<AxiosResponse>;
|
|
40
|
+
/**
|
|
41
|
+
* Refresh authentication token
|
|
42
|
+
* @param apiClient - Axios-compatible API client
|
|
43
|
+
* @returns Function that accepts refresh payload and returns token response
|
|
44
|
+
*/
|
|
45
|
+
export declare const refreshToken: (apiClient: AxiosInstance) => (data: TokenRefreshPayload) => Promise<AxiosResponse<TokenRefreshResponse>>;
|
|
46
|
+
/**
|
|
47
|
+
* Authentication service interface
|
|
48
|
+
*/
|
|
49
|
+
export interface AuthService {
|
|
50
|
+
signin: (data: SigninPayload) => Promise<AxiosResponse>;
|
|
51
|
+
signout: () => Promise<AxiosResponse>;
|
|
52
|
+
signup: (data: SignupPayload) => Promise<AxiosResponse>;
|
|
53
|
+
verifyEmail: (data: EmailVerificationPayload) => Promise<AxiosResponse>;
|
|
54
|
+
resendVerificationCode: () => Promise<AxiosResponse>;
|
|
55
|
+
refreshToken: (data: TokenRefreshPayload) => Promise<AxiosResponse<TokenRefreshResponse>>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create a complete authentication service with all operations
|
|
59
|
+
* @param apiClient - Axios-compatible API client
|
|
60
|
+
* @returns Object containing all auth operations
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* // Web application with cookies
|
|
64
|
+
* const webApiClient = axios.create({
|
|
65
|
+
* baseURL: 'https://api.example.com',
|
|
66
|
+
* withCredentials: true
|
|
67
|
+
* });
|
|
68
|
+
* const authService = createAuthService(webApiClient);
|
|
69
|
+
* await authService.signin({ email: 'user@example.com', password: 'pass' });
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // Mobile application with tokens
|
|
73
|
+
* const mobileApiClient = axios.create({
|
|
74
|
+
* baseURL: 'https://api.example.com'
|
|
75
|
+
* });
|
|
76
|
+
* // Add token interceptor for mobile
|
|
77
|
+
* mobileApiClient.interceptors.request.use(async (config) => {
|
|
78
|
+
* const token = await getStoredToken();
|
|
79
|
+
* if (token) config.headers.Authorization = `Bearer ${token}`;
|
|
80
|
+
* return config;
|
|
81
|
+
* });
|
|
82
|
+
* const authService = createAuthService(mobileApiClient);
|
|
83
|
+
*/
|
|
84
|
+
export declare const createAuthService: (apiClient: AxiosInstance) => AuthService;
|
|
85
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,gBAAgB,IAAI,oBAAoB,EACxC,mBAAmB,EACpB,MAAM,+BAA+B,CAAC;AAEvC;;GAEG;AAEH;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,WAAW,aAAa,MACrC,MAAM,aAAa,KAAG,OAAO,CAAC,aAAa,CAGpD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAAI,WAAW,aAAa,WACnC,OAAO,CAAC,aAAa,CAGjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,WAAW,aAAa,MACrC,MAAM,aAAa,KAAG,OAAO,CAAC,aAAa,CAGpD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,WAAW,aAAa,MAC1C,MAAM,wBAAwB,KAAG,OAAO,CAAC,aAAa,CAG/D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,WAAW,aAAa,WAClD,OAAO,CAAC,aAAa,CAGjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,WAAW,aAAa,MAC3C,MAAM,mBAAmB,KAAG,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAGhF,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACxD,OAAO,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IACtC,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACxD,WAAW,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACxE,sBAAsB,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IACrD,YAAY,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC;CAC3F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,aAAa,KAAG,WAS5D,CAAC"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-agnostic authentication service functions.
|
|
3
|
+
* Works with any axios-compatible API client.
|
|
4
|
+
*/
|
|
5
|
+
import { AUTH_ENDPOINTS } from '@cranberry-money/shared-constants';
|
|
6
|
+
/**
|
|
7
|
+
* Individual authentication functions with dependency injection
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Sign in a user
|
|
11
|
+
* @param apiClient - Axios-compatible API client
|
|
12
|
+
* @returns Function that accepts signin payload and returns API response
|
|
13
|
+
*/
|
|
14
|
+
export const signin = (apiClient) => {
|
|
15
|
+
return (data) => {
|
|
16
|
+
return apiClient.post(AUTH_ENDPOINTS.SIGNIN, data);
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Sign out the current user
|
|
21
|
+
* @param apiClient - Axios-compatible API client
|
|
22
|
+
* @returns Function that performs signout
|
|
23
|
+
*/
|
|
24
|
+
export const signout = (apiClient) => {
|
|
25
|
+
return () => {
|
|
26
|
+
return apiClient.post(AUTH_ENDPOINTS.SIGNOUT);
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Sign up a new user
|
|
31
|
+
* @param apiClient - Axios-compatible API client
|
|
32
|
+
* @returns Function that accepts signup payload and returns API response
|
|
33
|
+
*/
|
|
34
|
+
export const signup = (apiClient) => {
|
|
35
|
+
return (data) => {
|
|
36
|
+
return apiClient.post(AUTH_ENDPOINTS.SIGNUP, data);
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Verify user's email with verification code
|
|
41
|
+
* @param apiClient - Axios-compatible API client
|
|
42
|
+
* @returns Function that accepts verification payload and returns API response
|
|
43
|
+
*/
|
|
44
|
+
export const verifyEmail = (apiClient) => {
|
|
45
|
+
return (data) => {
|
|
46
|
+
return apiClient.post(AUTH_ENDPOINTS.EMAIL_VERIFICATION, data);
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Resend email verification code
|
|
51
|
+
* @param apiClient - Axios-compatible API client
|
|
52
|
+
* @returns Function that performs resend operation
|
|
53
|
+
*/
|
|
54
|
+
export const resendVerificationCode = (apiClient) => {
|
|
55
|
+
return () => {
|
|
56
|
+
return apiClient.post(AUTH_ENDPOINTS.RESEND_VERIFICATION);
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Refresh authentication token
|
|
61
|
+
* @param apiClient - Axios-compatible API client
|
|
62
|
+
* @returns Function that accepts refresh payload and returns token response
|
|
63
|
+
*/
|
|
64
|
+
export const refreshToken = (apiClient) => {
|
|
65
|
+
return (data) => {
|
|
66
|
+
return apiClient.post(AUTH_ENDPOINTS.TOKEN_REFRESH, data);
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Create a complete authentication service with all operations
|
|
71
|
+
* @param apiClient - Axios-compatible API client
|
|
72
|
+
* @returns Object containing all auth operations
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Web application with cookies
|
|
76
|
+
* const webApiClient = axios.create({
|
|
77
|
+
* baseURL: 'https://api.example.com',
|
|
78
|
+
* withCredentials: true
|
|
79
|
+
* });
|
|
80
|
+
* const authService = createAuthService(webApiClient);
|
|
81
|
+
* await authService.signin({ email: 'user@example.com', password: 'pass' });
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // Mobile application with tokens
|
|
85
|
+
* const mobileApiClient = axios.create({
|
|
86
|
+
* baseURL: 'https://api.example.com'
|
|
87
|
+
* });
|
|
88
|
+
* // Add token interceptor for mobile
|
|
89
|
+
* mobileApiClient.interceptors.request.use(async (config) => {
|
|
90
|
+
* const token = await getStoredToken();
|
|
91
|
+
* if (token) config.headers.Authorization = `Bearer ${token}`;
|
|
92
|
+
* return config;
|
|
93
|
+
* });
|
|
94
|
+
* const authService = createAuthService(mobileApiClient);
|
|
95
|
+
*/
|
|
96
|
+
export const createAuthService = (apiClient) => {
|
|
97
|
+
return {
|
|
98
|
+
signin: signin(apiClient),
|
|
99
|
+
signout: signout(apiClient),
|
|
100
|
+
signup: signup(apiClient),
|
|
101
|
+
verifyEmail: verifyEmail(apiClient),
|
|
102
|
+
resendVerificationCode: resendVerificationCode(apiClient),
|
|
103
|
+
refreshToken: refreshToken(apiClient),
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AASnE;;GAEG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,SAAwB,EAAE,EAAE;IACjD,OAAO,CAAC,IAAmB,EAA0B,EAAE;QACrD,OAAO,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,SAAwB,EAAE,EAAE;IAClD,OAAO,GAA2B,EAAE;QAClC,OAAO,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,SAAwB,EAAE,EAAE;IACjD,OAAO,CAAC,IAAmB,EAA0B,EAAE;QACrD,OAAO,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,SAAwB,EAAE,EAAE;IACtD,OAAO,CAAC,IAA8B,EAA0B,EAAE;QAChE,OAAO,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,SAAwB,EAAE,EAAE;IACjE,OAAO,GAA2B,EAAE;QAClC,OAAO,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;IAC5D,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAwB,EAAE,EAAE;IACvD,OAAO,CAAC,IAAyB,EAAgD,EAAE;QACjF,OAAO,SAAS,CAAC,IAAI,CAAuB,cAAc,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAClF,CAAC,CAAC;AACJ,CAAC,CAAC;AAcF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAwB,EAAe,EAAE;IACzE,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC;QACzB,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC;QACzB,WAAW,EAAE,WAAW,CAAC,SAAS,CAAC;QACnC,sBAAsB,EAAE,sBAAsB,CAAC,SAAS,CAAC;QACzD,YAAY,EAAE,YAAY,CAAC,SAAS,CAAC;KACtC,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cranberry-money/shared-services
|
|
3
|
+
* Platform-agnostic service functions for the Blueberry platform ecosystem.
|
|
4
|
+
*/
|
|
5
|
+
export { signin, signout, signup, verifyEmail, resendVerificationCode, refreshToken, createAuthService, type AuthService, } from './auth';
|
|
1
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,MAAM,EACN,OAAO,EACP,MAAM,EACN,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,iBAAiB,EACjB,KAAK,WAAW,GACjB,MAAM,QAAQ,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @cranberry-money/shared-services
|
|
3
|
+
* Platform-agnostic service functions for the Blueberry platform ecosystem.
|
|
4
|
+
*/
|
|
5
|
+
// Authentication services
|
|
6
|
+
export { signin, signout, signup, verifyEmail, resendVerificationCode, refreshToken, createAuthService, } from './auth';
|
|
3
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0BAA0B;AAC1B,OAAO,EACL,MAAM,EACN,OAAO,EACP,MAAM,EACN,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,iBAAiB,GAElB,MAAM,QAAQ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cranberry-money/shared-services",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "10.0.2",
|
|
4
|
+
"description": "Platform-agnostic API services with pure functions and dependency injection. Includes auth, portfolios, instruments, countries, sectors, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
"prepublishOnly": "npm run clean && npm run typecheck && npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@cranberry-money/shared-constants": "^8.1.3",
|
|
33
|
+
"@cranberry-money/shared-types": "^8.1.3",
|
|
32
34
|
"axios": "^1.9.0"
|
|
33
35
|
},
|
|
34
36
|
"peerDependencies": {
|