@goat-bravos/shared-lib-client 1.0.0 → 1.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/LICENSE.txt +21 -21
- package/README.md +145 -579
- package/dist/enums/error-code.enum.d.ts +2 -1
- package/dist/enums/error-code.enum.d.ts.map +1 -1
- package/dist/enums/error-code.enum.js +3 -5
- package/dist/enums/http-status.enum.js +2 -5
- package/dist/enums/language.enum.d.ts +5 -0
- package/dist/enums/language.enum.d.ts.map +1 -0
- package/dist/enums/language.enum.js +5 -0
- package/dist/enums/localstorage-key.enum.d.ts +3 -1
- package/dist/enums/localstorage-key.enum.d.ts.map +1 -1
- package/dist/enums/localstorage-key.enum.js +4 -5
- package/dist/index.d.ts +10 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -29
- package/dist/interceptors/auth.interceptor.d.ts +12 -0
- package/dist/interceptors/auth.interceptor.d.ts.map +1 -0
- package/dist/interceptors/auth.interceptor.js +78 -0
- package/dist/interfaces/api-response.interface.d.ts +0 -10
- package/dist/interfaces/api-response.interface.d.ts.map +1 -1
- package/dist/interfaces/api-response.interface.js +1 -2
- package/dist/interfaces/http-heades.interface.js +1 -2
- package/dist/interfaces/pagination.interface.js +1 -2
- package/dist/store/global-store.service.d.ts +35 -0
- package/dist/store/global-store.service.d.ts.map +1 -0
- package/dist/store/global-store.service.js +55 -0
- package/dist/utils/storage.util.d.ts +20 -0
- package/dist/utils/storage.util.d.ts.map +1 -0
- package/dist/utils/storage.util.js +62 -0
- package/package.json +45 -37
- package/dist/enums/error-code.enum.js.map +0 -1
- package/dist/enums/http-status.enum.js.map +0 -1
- package/dist/enums/localstorage-key.enum.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/interfaces/api-response.interface.js.map +0 -1
- package/dist/interfaces/http-heades.interface.js.map +0 -1
- package/dist/interfaces/pagination.interface.js.map +0 -1
- package/dist/services/rest/rest.config.d.ts +0 -12
- package/dist/services/rest/rest.config.d.ts.map +0 -1
- package/dist/services/rest/rest.config.js +0 -5
- package/dist/services/rest/rest.config.js.map +0 -1
- package/dist/services/rest/rest.service.d.ts +0 -64
- package/dist/services/rest/rest.service.d.ts.map +0 -1
- package/dist/services/rest/rest.service.js +0 -112
- package/dist/services/rest/rest.service.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,579 +1,145 @@
|
|
|
1
|
-
# @
|
|
2
|
-
|
|
3
|
-
A TypeScript library for
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
- 🔐 **
|
|
9
|
-
-
|
|
10
|
-
- 📦 **Type-Safe
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm install @
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### Peer Dependencies
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
import {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
createExternalUser() {
|
|
148
|
-
const newUser = { name: 'John Doe', email: 'john@example.com' };
|
|
149
|
-
|
|
150
|
-
this.restService.post<User>(
|
|
151
|
-
'https://external-api.com/users',
|
|
152
|
-
newUser
|
|
153
|
-
).subscribe({
|
|
154
|
-
next: (user) => console.log('Created:', user),
|
|
155
|
-
error: (err) => console.error('Error:', err)
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
#### Example: Internal API Calls (With Interceptors)
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
import { Component, inject } from '@angular/core';
|
|
165
|
-
import { RestService, ResponseApi, SuccessResponse } from '@intern-hub/shared-lib-client';
|
|
166
|
-
|
|
167
|
-
interface Product {
|
|
168
|
-
id: number;
|
|
169
|
-
name: string;
|
|
170
|
-
price: number;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
@Component({
|
|
174
|
-
selector: 'app-product',
|
|
175
|
-
template: `...`
|
|
176
|
-
})
|
|
177
|
-
export class ProductComponent {
|
|
178
|
-
private restService = inject(RestService);
|
|
179
|
-
|
|
180
|
-
// If apiBaseUrl is 'https://api.example.com'
|
|
181
|
-
// This will call: https://api.example.com/api/products
|
|
182
|
-
loadProducts() {
|
|
183
|
-
// Second parameter `credentials: false` - no auth token required
|
|
184
|
-
this.restService.getInternal<ResponseApi<Product[]>>('/api/products', false)
|
|
185
|
-
.subscribe({
|
|
186
|
-
next: (response) => {
|
|
187
|
-
if (response.data) {
|
|
188
|
-
console.log('Products:', response.data);
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
error: (err) => console.error('Error:', err)
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// With authentication - automatically adds Bearer token from localStorage
|
|
196
|
-
loadMyProducts() {
|
|
197
|
-
// Second parameter `credentials: true` - auth token will be added
|
|
198
|
-
this.restService.getInternal<ResponseApi<Product[]>>('/api/my-products', true)
|
|
199
|
-
.subscribe({
|
|
200
|
-
next: (response) => {
|
|
201
|
-
if (response.data) {
|
|
202
|
-
console.log('My Products:', response.data);
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
error: (err) => console.error('Error:', err)
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
createProduct() {
|
|
210
|
-
const newProduct = { name: 'Laptop', price: 999.99 };
|
|
211
|
-
|
|
212
|
-
// POST with authentication
|
|
213
|
-
this.restService.postInternal<ResponseApi<Product>>(
|
|
214
|
-
'/api/products',
|
|
215
|
-
newProduct,
|
|
216
|
-
true // credentials: true
|
|
217
|
-
).subscribe({
|
|
218
|
-
next: (response) => console.log('Created:', response.data),
|
|
219
|
-
error: (err) => console.error('Error:', err)
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
updateProduct(id: number) {
|
|
224
|
-
const updates = { price: 899.99 };
|
|
225
|
-
|
|
226
|
-
this.restService.patchInternal<ResponseApi<Product>>(
|
|
227
|
-
`/api/products/${id}`,
|
|
228
|
-
updates,
|
|
229
|
-
true // credentials: true
|
|
230
|
-
).subscribe({
|
|
231
|
-
next: (response) => console.log('Updated:', response.data),
|
|
232
|
-
error: (err) => console.error('Error:', err)
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
deleteProduct(id: number) {
|
|
237
|
-
this.restService.deleteInternal<ResponseApi<void>>(
|
|
238
|
-
`/api/products/${id}`,
|
|
239
|
-
true // credentials: true
|
|
240
|
-
).subscribe({
|
|
241
|
-
next: () => console.log('Deleted successfully'),
|
|
242
|
-
error: (err) => console.error('Error:', err)
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
#### Example: With Custom Headers and Query Params
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
loadProductsWithParams() {
|
|
252
|
-
const params = { category: 'electronics', sort: 'price' };
|
|
253
|
-
const headers = { 'X-Custom-Header': 'custom-value' };
|
|
254
|
-
|
|
255
|
-
// getInternal(path, credentials, params, headers)
|
|
256
|
-
this.restService.getInternal<ResponseApi<Product[]>>(
|
|
257
|
-
'/api/products',
|
|
258
|
-
true, // credentials
|
|
259
|
-
params, // query params
|
|
260
|
-
headers // custom headers
|
|
261
|
-
).subscribe({
|
|
262
|
-
next: (response) => console.log('Products:', response.data),
|
|
263
|
-
error: (err) => console.error('Error:', err)
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Interfaces
|
|
269
|
-
|
|
270
|
-
#### API Response Interfaces
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
import {
|
|
274
|
-
ResponseApi,
|
|
275
|
-
SuccessResponse,
|
|
276
|
-
ErrorResponse,
|
|
277
|
-
ApiStatus,
|
|
278
|
-
ApiMetadata,
|
|
279
|
-
PaginatedResponse,
|
|
280
|
-
PaginatedData
|
|
281
|
-
} from '@intern-hub/shared-lib-client';
|
|
282
|
-
|
|
283
|
-
// Generic response structure
|
|
284
|
-
const response: ResponseApi<User> = {
|
|
285
|
-
status: null,
|
|
286
|
-
data: { id: 1, name: 'John' },
|
|
287
|
-
metaData: null
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
// Success response
|
|
291
|
-
const success: SuccessResponse<User> = {
|
|
292
|
-
status: null,
|
|
293
|
-
data: { id: 1, name: 'John' },
|
|
294
|
-
metaData: null
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
// Error response
|
|
298
|
-
const error: ErrorResponse = {
|
|
299
|
-
status: {
|
|
300
|
-
code: 'validation.error',
|
|
301
|
-
message: 'Validation failed',
|
|
302
|
-
errors: {
|
|
303
|
-
email: ['Email is required'],
|
|
304
|
-
name: ['Name must be at least 3 characters']
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
data: null,
|
|
308
|
-
metaData: {
|
|
309
|
-
requestId: 'abc-123',
|
|
310
|
-
traceId: 'xyz-789',
|
|
311
|
-
timestamp: 1234567890
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
// Paginated response
|
|
316
|
-
const paginated: PaginatedResponse<User> = {
|
|
317
|
-
status: null,
|
|
318
|
-
data: {
|
|
319
|
-
items: [
|
|
320
|
-
{ id: 1, name: 'John' },
|
|
321
|
-
{ id: 2, name: 'Jane' }
|
|
322
|
-
],
|
|
323
|
-
totalItems: 100,
|
|
324
|
-
totalPages: 10
|
|
325
|
-
},
|
|
326
|
-
metaData: null
|
|
327
|
-
};
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
#### HTTP Client Headers
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
import { HttpClientHeaders } from '@intern-hub/shared-lib-client';
|
|
334
|
-
|
|
335
|
-
const headers: HttpClientHeaders = {
|
|
336
|
-
'Content-Type': 'application/json',
|
|
337
|
-
'Authorization': 'Bearer token123',
|
|
338
|
-
'X-Custom-Header': 'custom-value'
|
|
339
|
-
};
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Enums
|
|
343
|
-
|
|
344
|
-
#### HTTP Status Codes
|
|
345
|
-
|
|
346
|
-
```typescript
|
|
347
|
-
import { HttpStatus } from '@intern-hub/shared-lib-client';
|
|
348
|
-
|
|
349
|
-
if (response.status === HttpStatus.OK) {
|
|
350
|
-
console.log('Success!');
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Available statuses:
|
|
354
|
-
// HttpStatus.OK = 200
|
|
355
|
-
// HttpStatus.CREATED = 201
|
|
356
|
-
// HttpStatus.NO_CONTENT = 204
|
|
357
|
-
// HttpStatus.BAD_REQUEST = 400
|
|
358
|
-
// HttpStatus.UNAUTHORIZED = 401
|
|
359
|
-
// HttpStatus.FORBIDDEN = 403
|
|
360
|
-
// HttpStatus.NOT_FOUND = 404
|
|
361
|
-
// HttpStatus.CONFLICT = 409
|
|
362
|
-
// HttpStatus.INTERNAL_SERVER_ERROR = 500
|
|
363
|
-
// HttpStatus.SERVICE_UNAVAILABLE = 503
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
#### Error Codes
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
import { ErrorCode } from '@intern-hub/shared-lib-client';
|
|
370
|
-
|
|
371
|
-
if (error.status?.code === ErrorCode.UNAUTHORIZED) {
|
|
372
|
-
// Handle unauthorized
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Available error codes:
|
|
376
|
-
// ErrorCode.RESOURCE_NOT_FOUND = 'resource.not.found'
|
|
377
|
-
// ErrorCode.UNAUTHORIZED = 'unauthorized'
|
|
378
|
-
// ErrorCode.FORBIDDEN = 'forbidden'
|
|
379
|
-
// ErrorCode.BAD_REQUEST = 'bad.request'
|
|
380
|
-
// ErrorCode.INTERNAL_SERVER_ERROR = 'internal.server.error'
|
|
381
|
-
// ErrorCode.VALIDATION_ERROR = 'validation.error'
|
|
382
|
-
// ErrorCode.CONFLICT = 'conflict'
|
|
383
|
-
// ErrorCode.SERVICE_UNAVAILABLE = 'service.unavailable'
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
#### Storage Keys
|
|
387
|
-
|
|
388
|
-
```typescript
|
|
389
|
-
import { StorageKey } from '@intern-hub/shared-lib-client';
|
|
390
|
-
|
|
391
|
-
localStorage.setItem(StorageKey.ACCESS_TOKEN, 'token123');
|
|
392
|
-
const token = localStorage.getItem(StorageKey.ACCESS_TOKEN);
|
|
393
|
-
|
|
394
|
-
// Available keys:
|
|
395
|
-
// StorageKey.ACCESS_TOKEN = 'accessToken'
|
|
396
|
-
// StorageKey.CONTENT_TYPE = 'application/json'
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
## Complete Example: User Service
|
|
400
|
-
|
|
401
|
-
```typescript
|
|
402
|
-
import { Injectable, inject } from '@angular/core';
|
|
403
|
-
import { Observable, map, catchError, throwError } from 'rxjs';
|
|
404
|
-
import {
|
|
405
|
-
RestService,
|
|
406
|
-
ResponseApi,
|
|
407
|
-
ErrorCode
|
|
408
|
-
} from '@intern-hub/shared-lib-client';
|
|
409
|
-
|
|
410
|
-
interface User {
|
|
411
|
-
id: number;
|
|
412
|
-
name: string;
|
|
413
|
-
email: string;
|
|
414
|
-
role: string;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
@Injectable({ providedIn: 'root' })
|
|
418
|
-
export class UserService {
|
|
419
|
-
private restService = inject(RestService);
|
|
420
|
-
|
|
421
|
-
// Public endpoint - no authentication needed
|
|
422
|
-
getUsers(): Observable<User[]> {
|
|
423
|
-
return this.restService.getInternal<ResponseApi<User[]>>('/api/users', false)
|
|
424
|
-
.pipe(
|
|
425
|
-
map(response => response.data || []),
|
|
426
|
-
catchError(this.handleError)
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Protected endpoint - requires authentication
|
|
431
|
-
getCurrentUser(): Observable<User> {
|
|
432
|
-
return this.restService.getInternal<ResponseApi<User>>('/api/users/me', true)
|
|
433
|
-
.pipe(
|
|
434
|
-
map(response => {
|
|
435
|
-
if (!response.data) {
|
|
436
|
-
throw new Error('User not found');
|
|
437
|
-
}
|
|
438
|
-
return response.data;
|
|
439
|
-
}),
|
|
440
|
-
catchError(this.handleError)
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
createUser(user: Omit<User, 'id'>): Observable<User> {
|
|
445
|
-
return this.restService.postInternal<ResponseApi<User>>(
|
|
446
|
-
'/api/users',
|
|
447
|
-
user,
|
|
448
|
-
true // requires auth
|
|
449
|
-
).pipe(
|
|
450
|
-
map(response => {
|
|
451
|
-
if (!response.data) {
|
|
452
|
-
throw new Error('Failed to create user');
|
|
453
|
-
}
|
|
454
|
-
return response.data;
|
|
455
|
-
}),
|
|
456
|
-
catchError(this.handleError)
|
|
457
|
-
);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
updateUser(id: number, updates: Partial<User>): Observable<User> {
|
|
461
|
-
return this.restService.patchInternal<ResponseApi<User>>(
|
|
462
|
-
`/api/users/${id}`,
|
|
463
|
-
updates,
|
|
464
|
-
true // requires auth
|
|
465
|
-
).pipe(
|
|
466
|
-
map(response => {
|
|
467
|
-
if (!response.data) {
|
|
468
|
-
throw new Error('Failed to update user');
|
|
469
|
-
}
|
|
470
|
-
return response.data;
|
|
471
|
-
}),
|
|
472
|
-
catchError(this.handleError)
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
deleteUser(id: number): Observable<void> {
|
|
477
|
-
return this.restService.deleteInternal<ResponseApi<void>>(
|
|
478
|
-
`/api/users/${id}`,
|
|
479
|
-
true // requires auth
|
|
480
|
-
).pipe(
|
|
481
|
-
map(() => undefined),
|
|
482
|
-
catchError(this.handleError)
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
private handleError(error: any): Observable<never> {
|
|
487
|
-
console.error('API Error:', error);
|
|
488
|
-
|
|
489
|
-
if (error.status?.code === ErrorCode.UNAUTHORIZED) {
|
|
490
|
-
// User will be automatically redirected to loginPath
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
return throwError(() => error);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
## API Reference
|
|
499
|
-
|
|
500
|
-
### RestService Methods
|
|
501
|
-
|
|
502
|
-
#### External Methods (Without Interceptors)
|
|
503
|
-
|
|
504
|
-
| Method | Signature |
|
|
505
|
-
|--------|-----------|
|
|
506
|
-
| `get` | `get<T>(path: string, params?: object, headers?: object): Observable<T>` |
|
|
507
|
-
| `post` | `post<T>(path: string, body: unknown, params?: object, headers?: object): Observable<T>` |
|
|
508
|
-
| `put` | `put<T>(path: string, body: unknown, params?: object, headers?: object): Observable<T>` |
|
|
509
|
-
| `patch` | `patch<T>(path: string, body: unknown, params?: object, headers?: object): Observable<T>` |
|
|
510
|
-
| `delete` | `delete<T>(path: string, params?: object, headers?: object): Observable<T>` |
|
|
511
|
-
|
|
512
|
-
#### Internal Methods (With Interceptors)
|
|
513
|
-
|
|
514
|
-
| Method | Signature |
|
|
515
|
-
|--------|-----------|
|
|
516
|
-
| `getInternal` | `getInternal<T>(path: string, credentials?: boolean, params?: object, headers?: object): Observable<T>` |
|
|
517
|
-
| `postInternal` | `postInternal<T>(path: string, body: unknown, credentials?: boolean, params?: object, headers?: object): Observable<T>` |
|
|
518
|
-
| `putInternal` | `putInternal<T>(path: string, body: unknown, credentials?: boolean, params?: object, headers?: object): Observable<T>` |
|
|
519
|
-
| `patchInternal` | `patchInternal<T>(path: string, body: unknown, credentials?: boolean, params?: object, headers?: object): Observable<T>` |
|
|
520
|
-
| `deleteInternal` | `deleteInternal<T>(path: string, credentials?: boolean, params?: object, headers?: object): Observable<T>` |
|
|
521
|
-
|
|
522
|
-
**Note:** When `credentials` is `true`, the service automatically:
|
|
523
|
-
1. Retrieves the token from `localStorage` using the configured `tokenKey`
|
|
524
|
-
2. Adds an `Authorization: Bearer <token>` header to the request
|
|
525
|
-
3. Redirects to `loginPath` if no token is found
|
|
526
|
-
|
|
527
|
-
## Development
|
|
528
|
-
|
|
529
|
-
### Build the Library
|
|
530
|
-
|
|
531
|
-
```bash
|
|
532
|
-
npm run build
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
This will compile the TypeScript files and generate the distributable files in the `dist` folder.
|
|
536
|
-
|
|
537
|
-
### Project Structure
|
|
538
|
-
|
|
539
|
-
```
|
|
540
|
-
intern-fe-library/
|
|
541
|
-
├── src/
|
|
542
|
-
│ ├── enums/
|
|
543
|
-
│ │ ├── error-code.enum.ts
|
|
544
|
-
│ │ ├── http-status.enum.ts
|
|
545
|
-
│ │ └── localstorage-key.enum.ts
|
|
546
|
-
│ ├── interfaces/
|
|
547
|
-
│ │ ├── api-response.interface.ts
|
|
548
|
-
│ │ ├── http-heades.interface.ts
|
|
549
|
-
│ │ └── pagination.interface.ts
|
|
550
|
-
│ ├── services/
|
|
551
|
-
│ │ └── rest/
|
|
552
|
-
│ │ ├── rest.config.ts
|
|
553
|
-
│ │ └── rest.service.ts
|
|
554
|
-
│ └── index.ts
|
|
555
|
-
├── package.json
|
|
556
|
-
├── tsconfig.json
|
|
557
|
-
└── README.md
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
## TypeScript Configuration
|
|
561
|
-
|
|
562
|
-
This library is built with the following TypeScript features:
|
|
563
|
-
|
|
564
|
-
- **Decorators**: Full support for Angular decorators (`experimentalDecorators`, `emitDecoratorMetadata`)
|
|
565
|
-
- **Strict Mode**: Enabled for better type safety
|
|
566
|
-
- **Module System**: Uses `NodeNext` for modern ES modules
|
|
567
|
-
- **Declaration Files**: Generates `.d.ts` files for TypeScript consumers
|
|
568
|
-
|
|
569
|
-
## License
|
|
570
|
-
|
|
571
|
-
ISC
|
|
572
|
-
|
|
573
|
-
## Author
|
|
574
|
-
|
|
575
|
-
intern-hub
|
|
576
|
-
|
|
577
|
-
## Contributing
|
|
578
|
-
|
|
579
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
1
|
+
# @goat-bravos/shared-lib-client
|
|
2
|
+
|
|
3
|
+
A specialized TypeScript library for InternHub micro-frontend applications. This library provides shared utilities, global state management (Signals), authentication interceptors, and standardized API interfaces.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- 🚦 **Global Store**: Shared application state (User, Theme, Loading, Language) using Angular Signals.
|
|
8
|
+
- 🔐 **Auth Interceptor**: Automatic JWT token injection and smart token refresh mechanism.
|
|
9
|
+
- 🌍 **I18n Support**: Standardized language management with persistent storage.
|
|
10
|
+
- 📦 **Type-Safe API**: Consistent `ResponseApi<T>` interfaces and HTTP enums.
|
|
11
|
+
- 💾 **Storage Utils**: Type-safe wrapper for `localStorage`.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📦 Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @goat-bravos/shared-lib-client
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Peer Dependencies
|
|
22
|
+
|
|
23
|
+
Ensure you have the following dependencies installed in your project:
|
|
24
|
+
|
|
25
|
+
- `@angular/core` (>= 18.0.0)
|
|
26
|
+
- `@angular/common` (>= 18.0.0)
|
|
27
|
+
- `rxjs` (>= 7.0.0)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🛠 Usage Guide
|
|
32
|
+
|
|
33
|
+
### 1. Global Store (Manager State)
|
|
34
|
+
|
|
35
|
+
The `GlobalStoreService` uses **Angular Signals** to provide a reactive state that can be shared across multiple micro-frontends.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { inject } from "@angular/core";
|
|
39
|
+
import { GlobalStoreService, Language } from "@goat-bravos/shared-lib-client";
|
|
40
|
+
|
|
41
|
+
export class AppSidebarComponent {
|
|
42
|
+
private globalStore = inject(GlobalStoreService);
|
|
43
|
+
|
|
44
|
+
// Read state
|
|
45
|
+
user = this.globalStore.user;
|
|
46
|
+
language = this.globalStore.language;
|
|
47
|
+
|
|
48
|
+
// Update state
|
|
49
|
+
changeLanguage(lang: Language) {
|
|
50
|
+
this.globalStore.setLanguage(lang);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
logout() {
|
|
54
|
+
this.globalStore.clearState();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Internationalization (i18n)
|
|
60
|
+
|
|
61
|
+
Management of language state is built into the `GlobalStoreService`.
|
|
62
|
+
|
|
63
|
+
- **Enums**: Use the `Language` enum (`VI`, `EN`).
|
|
64
|
+
- **Initial State**: Automatically loads from `localStorage` on initialization.
|
|
65
|
+
- **Syncing**: Calling `setLanguage()` updates both the signal and `localStorage`.
|
|
66
|
+
|
|
67
|
+
**Usage with Ng-Zorro or other libraries:**
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { GlobalStoreService, Language } from "@goat-bravos/shared-lib-client";
|
|
71
|
+
import { en_US, vi_VN, NzI18nService } from "ng-zorro-antd/i18n";
|
|
72
|
+
|
|
73
|
+
// In your AppComponent or localized component
|
|
74
|
+
effect(() => {
|
|
75
|
+
const currentLang = this.globalStore.language();
|
|
76
|
+
this.i18n.setLocale(currentLang === Language.VI ? vi_VN : en_US);
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3. Authentication Interceptor
|
|
81
|
+
|
|
82
|
+
Standardize your API calls by providing the `authInterceptor` in your `app.config.ts`.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { provideHttpClient, withInterceptors } from "@angular/common/http";
|
|
86
|
+
import { authInterceptor } from "@goat-bravos/shared-lib-client";
|
|
87
|
+
|
|
88
|
+
export const appConfig: ApplicationConfig = {
|
|
89
|
+
providers: [provideHttpClient(withInterceptors([authInterceptor]))],
|
|
90
|
+
};
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
_The interceptor automatically handles 401 Unauthorized errors by dispatching a `AUTH_TOKEN_EXPIRED` event and waiting for a refresh._
|
|
94
|
+
|
|
95
|
+
### 4. Storage Utilities
|
|
96
|
+
|
|
97
|
+
Access local storage safely using `StorageUtil`.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { StorageUtil, Language } from "@goat-bravos/shared-lib-client";
|
|
101
|
+
|
|
102
|
+
// Get tokens
|
|
103
|
+
const token = StorageUtil.getAccessToken();
|
|
104
|
+
|
|
105
|
+
// Set language
|
|
106
|
+
StorageUtil.setLanguage(Language.VI);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 5. API Response Formatting
|
|
110
|
+
|
|
111
|
+
Ensure consistency across all backend responses.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { ResponseApi, SuccessResponse } from '@goat-bravos/shared-lib-client';
|
|
115
|
+
|
|
116
|
+
interface UserData {
|
|
117
|
+
id: string;
|
|
118
|
+
name: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// In your service
|
|
122
|
+
getProfile(): Observable<ResponseApi<UserData>> {
|
|
123
|
+
return this.http.get<ResponseApi<UserData>>('/api/profile');
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 📂 Project Structure
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
src/
|
|
133
|
+
├── enums/ # Http status codes, error codes, storage keys, language
|
|
134
|
+
├── interceptors/ # Shared Auth & Error interceptors
|
|
135
|
+
├── interfaces/ # Standardized API response & pagination models
|
|
136
|
+
├── store/ # Global Signals Store (Singleton)
|
|
137
|
+
├── utils/ # Storage & helper utilities
|
|
138
|
+
└── index.ts # Public API exports
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 🛡️ License
|
|
144
|
+
|
|
145
|
+
MIT
|