@zym-test-zerog/apiclient 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,576 @@
1
+ # API Client Wrapper
2
+
3
+ A powerful and feature-rich API client wrapper for TypeScript/JavaScript applications with built-in token refresh, request signing, comprehensive error handling, and detailed logging.
4
+
5
+ ## Features
6
+
7
+ - **Modular API Organization**: Organized by API versions (v1, v2) and functionality
8
+ - **Automatic Token Refresh**: Handles 401 errors and automatically refreshes tokens
9
+ - **Request Signing**: Built-in support for request signature generation
10
+ - **Comprehensive Error Handling**: Global error interceptor with custom error handling support
11
+ - **Detailed Logging**: Request/response logging with sensitive data redaction
12
+ - **Request Cancellation**: Support for cancelling individual or all requests
13
+ - **TypeScript Support**: Full type definitions for better development experience
14
+ - **Dual Module Support**: Works with both CommonJS and ES Module
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install api-client-wrapper
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### Basic Usage
25
+
26
+ ```typescript
27
+ import { init, apiV1 } from 'api-client-wrapper';
28
+
29
+ init({
30
+ baseURL: 'https://api.example.com',
31
+ timeout: 10000,
32
+ debug: true
33
+ });
34
+
35
+ async function main() {
36
+ try {
37
+ const userInfo = await apiV1.getUserInfo();
38
+ console.log(userInfo);
39
+ } catch (error) {
40
+ console.error(error);
41
+ }
42
+ }
43
+ ```
44
+
45
+ ### Login Example
46
+
47
+ ```typescript
48
+ import { init, apiV1 } from 'api-client-wrapper';
49
+
50
+ init();
51
+
52
+ async function login() {
53
+ try {
54
+ const result = await apiV1.login({
55
+ username: 'testuser',
56
+ password: 'password123'
57
+ });
58
+ console.log('Login successful:', result);
59
+ } catch (error) {
60
+ console.error('Login failed:', error);
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Configuration
66
+
67
+ ### Initialization Options
68
+
69
+ ```typescript
70
+ interface ApiClientConfig {
71
+ baseURL?: string; // Default: 'https://www.xxx.com/api'
72
+ timeout?: number; // Default: 30000 (30s)
73
+ headers?: Record<string, string>;
74
+ debug?: boolean; // Default: false
75
+ logLevel?: 'error' | 'warn' | 'info' | 'debug';
76
+ logCallback?: LogCallback;
77
+ tokenRefreshConfig?: TokenRefreshConfig;
78
+ signConfig?: SignConfig;
79
+ errorHandler?: ErrorHandler;
80
+ }
81
+ ```
82
+
83
+ ### Token Refresh Configuration
84
+
85
+ ```typescript
86
+ import { init } from 'api-client-wrapper';
87
+
88
+ let accessToken = '';
89
+ let refreshToken = '';
90
+
91
+ init({
92
+ tokenRefreshConfig: {
93
+ refreshTokenUrl: '/auth/refresh',
94
+ getToken: () => accessToken,
95
+ setToken: (token) => { accessToken = token; },
96
+ getRefreshToken: () => refreshToken,
97
+ tokenExpiredCode: 401
98
+ }
99
+ });
100
+ ```
101
+
102
+ ### Request Signing Configuration
103
+
104
+ ```typescript
105
+ import { init } from 'api-client-wrapper';
106
+
107
+ init({
108
+ signConfig: {
109
+ secretKey: 'your-secret-key',
110
+ algorithm: 'md5', // 'md5' | 'sha1' | 'sha256'
111
+ signHeaderName: 'X-Sign',
112
+ includeParams: true,
113
+ includeHeaders: false
114
+ }
115
+ });
116
+ ```
117
+
118
+ ### Custom Error Handler
119
+
120
+ ```typescript
121
+ import { init } from 'api-client-wrapper';
122
+
123
+ init({
124
+ errorHandler: (error) => {
125
+ console.error('Error:', error.name, error.message);
126
+
127
+ if (error.name === 'NetworkError') {
128
+ // Handle network errors
129
+ } else if (error.name === 'UnauthorizedError') {
130
+ // Redirect to login
131
+ }
132
+ }
133
+ });
134
+ ```
135
+
136
+ ### Custom Log Callback
137
+
138
+ ```typescript
139
+ import { init } from 'api-client-wrapper';
140
+
141
+ const logs: any[] = [];
142
+
143
+ init({
144
+ debug: true,
145
+ logLevel: 'debug',
146
+ logCallback: (level, message, data) => {
147
+ logs.push({ level, message, data, timestamp: Date.now() });
148
+ // Send logs to external service
149
+ }
150
+ });
151
+ ```
152
+
153
+ ## API Reference
154
+
155
+ ### Core Methods
156
+
157
+ #### `init(config: ApiClientConfig): void`
158
+
159
+ Initialize the API client with configuration options.
160
+
161
+ #### `updateConfig(config: Partial<ApiClientConfig>): void`
162
+
163
+ Update the configuration after initialization.
164
+
165
+ #### `getApiClient(): ApiClient`
166
+
167
+ Get the underlying ApiClient instance for advanced usage.
168
+
169
+ #### `destroy(): void`
170
+
171
+ Destroy the API client instance and cancel all pending requests.
172
+
173
+ ### API v1
174
+
175
+ #### Authentication
176
+
177
+ ```typescript
178
+ import { apiV1 } from 'api-client-wrapper';
179
+
180
+ // Login
181
+ await apiV1.login({
182
+ username: string,
183
+ password: string
184
+ });
185
+
186
+ // Register
187
+ await apiV1.register({
188
+ username: string,
189
+ password: string,
190
+ email: string
191
+ });
192
+
193
+ // Logout
194
+ await apiV1.logout();
195
+
196
+ // Get user info
197
+ await apiV1.getUserInfo();
198
+
199
+ // Update user info
200
+ await apiV1.updateUserInfo({
201
+ username?: string,
202
+ email?: string,
203
+ avatar?: string
204
+ });
205
+ ```
206
+
207
+ #### User Management
208
+
209
+ ```typescript
210
+ // Get user list
211
+ await apiV1.getUserList({
212
+ page: number,
213
+ pageSize: number,
214
+ keyword?: string,
215
+ status?: 'active' | 'inactive' | 'banned'
216
+ });
217
+
218
+ // Get user by ID
219
+ await apiV1.getUserById(userId: string);
220
+
221
+ // Create user
222
+ await apiV1.createUser({
223
+ username: string,
224
+ email: string,
225
+ password: string,
226
+ role?: string
227
+ });
228
+
229
+ // Update user
230
+ await apiV1.updateUser(userId: string, {
231
+ username?: string,
232
+ email?: string,
233
+ avatar?: string,
234
+ status?: 'active' | 'inactive' | 'banned'
235
+ });
236
+
237
+ // Delete user
238
+ await apiV1.deleteUser(userId: string);
239
+
240
+ // Batch delete users
241
+ await apiV1.batchDeleteUsers(userIds: string[]);
242
+ ```
243
+
244
+ #### Product Management
245
+
246
+ ```typescript
247
+ // Get product list
248
+ await apiV1.getProductList({
249
+ page: number,
250
+ pageSize: number,
251
+ keyword?: string,
252
+ category?: string,
253
+ status?: 'available' | 'out_of_stock' | 'discontinued',
254
+ minPrice?: number,
255
+ maxPrice?: number
256
+ });
257
+
258
+ // Get product by ID
259
+ await apiV1.getProductById(productId: string);
260
+
261
+ // Create product
262
+ await apiV1.createProduct({
263
+ name: string,
264
+ description: string,
265
+ price: number,
266
+ stock: number,
267
+ category: string,
268
+ images: string[]
269
+ });
270
+
271
+ // Update product
272
+ await apiV1.updateProduct(productId: string, {
273
+ name?: string,
274
+ description?: string,
275
+ price?: number,
276
+ stock?: number,
277
+ category?: string,
278
+ images?: string[],
279
+ status?: 'available' | 'out_of_stock' | 'discontinued'
280
+ });
281
+
282
+ // Delete product
283
+ await apiV1.deleteProduct(productId: string);
284
+
285
+ // Update product stock
286
+ await apiV1.updateProductStock(productId: string, stock: number);
287
+ ```
288
+
289
+ ### API v2
290
+
291
+ #### Authentication
292
+
293
+ ```typescript
294
+ import { apiV2 } from 'api-client-wrapper';
295
+
296
+ // Login (V2)
297
+ await apiV2.loginV2({
298
+ account: string,
299
+ password: string,
300
+ captcha?: string,
301
+ deviceId?: string
302
+ });
303
+
304
+ // Register (V2)
305
+ await apiV2.registerV2({
306
+ account: string,
307
+ password: string,
308
+ confirmPassword: string,
309
+ email: string,
310
+ phone?: string,
311
+ captcha: string
312
+ });
313
+
314
+ // Logout (V2)
315
+ await apiV2.logoutV2();
316
+
317
+ // Get user info (V2)
318
+ await apiV2.getUserInfoV2();
319
+
320
+ // Update user info (V2)
321
+ await apiV2.updateUserInfoV2({
322
+ nickname?: string,
323
+ avatar?: string,
324
+ email?: string,
325
+ phone?: string,
326
+ gender?: 'male' | 'female' | 'other',
327
+ birthday?: string,
328
+ bio?: string
329
+ });
330
+
331
+ // Change password
332
+ await apiV2.changePasswordV2({
333
+ oldPassword: string,
334
+ newPassword: string,
335
+ confirmPassword: string
336
+ });
337
+
338
+ // Upload avatar
339
+ await apiV2.uploadAvatarV2(file: File);
340
+ ```
341
+
342
+ #### User Management (V2)
343
+
344
+ ```typescript
345
+ // Get user list (V2)
346
+ await apiV2.getUserListV2({
347
+ page: number,
348
+ pageSize: number,
349
+ keyword?: string,
350
+ status?: 'active' | 'inactive' | 'banned' | 'pending',
351
+ role?: string,
352
+ sortBy?: 'createdAt' | 'updatedAt' | 'lastLoginAt',
353
+ sortOrder?: 'asc' | 'desc'
354
+ });
355
+
356
+ // Create user (V2)
357
+ await apiV2.createUserV2({
358
+ account: string,
359
+ password: string,
360
+ nickname: string,
361
+ email: string,
362
+ phone?: string,
363
+ roles: string[]
364
+ });
365
+
366
+ // Update user (V2)
367
+ await apiV2.updateUserV2(userId: string, {
368
+ nickname?: string,
369
+ avatar?: string,
370
+ email?: string,
371
+ phone?: string,
372
+ gender?: 'male' | 'female' | 'other',
373
+ birthday?: string,
374
+ bio?: string,
375
+ status?: 'active' | 'inactive' | 'banned' | 'pending',
376
+ roles?: string[]
377
+ });
378
+
379
+ // Assign roles
380
+ await apiV2.assignRolesV2(userId: string, roles: string[]);
381
+
382
+ // Reset password
383
+ await apiV2.resetPasswordV2(userId: string, newPassword: string);
384
+
385
+ // Ban user
386
+ await apiV2.banUserV2(userId: string, reason?: string);
387
+
388
+ // Unban user
389
+ await apiV2.unbanUserV2(userId: string);
390
+ ```
391
+
392
+ #### Product Management (V2)
393
+
394
+ ```typescript
395
+ // Get product list (V2)
396
+ await apiV2.getProductListV2({
397
+ page: number,
398
+ pageSize: number,
399
+ keyword?: string,
400
+ category?: string,
401
+ subcategory?: string,
402
+ tags?: string[],
403
+ status?: 'draft' | 'published' | 'out_of_stock' | 'discontinued',
404
+ visibility?: 'public' | 'private' | 'hidden',
405
+ featured?: boolean,
406
+ minPrice?: number,
407
+ maxPrice?: number,
408
+ inStock?: boolean,
409
+ sortBy?: 'createdAt' | 'updatedAt' | 'price' | 'name' | 'stock',
410
+ sortOrder?: 'asc' | 'desc'
411
+ });
412
+
413
+ // Get product by slug
414
+ await apiV2.getProductBySlugV2(slug: string);
415
+
416
+ // Create product (V2)
417
+ await apiV2.createProductV2({
418
+ name: string,
419
+ slug?: string,
420
+ description: string,
421
+ shortDescription?: string,
422
+ price: number,
423
+ compareAtPrice?: number,
424
+ costPrice?: number,
425
+ stock: number,
426
+ lowStockThreshold?: number,
427
+ category: string,
428
+ subcategory?: string,
429
+ tags?: string[],
430
+ images: Array<{
431
+ url: string;
432
+ alt?: string;
433
+ order?: number;
434
+ }>,
435
+ variants?: Array<{
436
+ name: string;
437
+ sku: string;
438
+ price: number;
439
+ stock: number;
440
+ attributes: Record<string, string>;
441
+ }>,
442
+ attributes?: Record<string, string>,
443
+ seoTitle?: string,
444
+ seoDescription?: string,
445
+ seoKeywords?: string[],
446
+ status?: 'draft' | 'published' | 'out_of_stock' | 'discontinued',
447
+ visibility?: 'public' | 'private' | 'hidden',
448
+ featured?: boolean,
449
+ weight?: number,
450
+ dimensions?: {
451
+ length: number;
452
+ width: number;
453
+ height: number;
454
+ }
455
+ });
456
+
457
+ // Publish product
458
+ await apiV2.publishProductV2(productId: string);
459
+
460
+ // Unpublish product
461
+ await apiV2.unpublishProductV2(productId: string);
462
+
463
+ // Upload product images
464
+ await apiV2.uploadProductImagesV2(productId: string, files: File[]);
465
+ ```
466
+
467
+ ## Advanced Usage
468
+
469
+ ### Request Cancellation
470
+
471
+ ```typescript
472
+ import { getApiClient } from 'api-client-wrapper';
473
+
474
+ const client = getApiClient();
475
+ const source = client.createCancelToken('request-id');
476
+
477
+ client.cancelRequest('request-id');
478
+ client.cancelAllRequests();
479
+ ```
480
+
481
+ ### Dynamic Configuration Update
482
+
483
+ ```typescript
484
+ import { init, updateConfig } from 'api-client-wrapper';
485
+
486
+ init({
487
+ baseURL: 'https://api.example.com',
488
+ debug: false
489
+ });
490
+
491
+ updateConfig({
492
+ debug: true,
493
+ logLevel: 'info',
494
+ timeout: 15000
495
+ });
496
+ ```
497
+
498
+ ## Error Handling
499
+
500
+ The library provides comprehensive error handling with the following error types:
501
+
502
+ - **NetworkError**: Network connectivity issues
503
+ - **ServerError**: Server-side errors (5xx)
504
+ - **UnauthorizedError**: Authentication failures (401)
505
+ - **ForbiddenError**: Access denied (403)
506
+ - **NotFoundError**: Resource not found (404)
507
+ - **ClientError**: Client-side errors (4xx)
508
+ - **RequestSetupError**: Request configuration errors
509
+
510
+ Each error includes:
511
+ - `name`: Error type
512
+ - `message`: Error description
513
+ - `code`: Error code
514
+ - `status`: HTTP status code (if applicable)
515
+ - `data`: Response data (if applicable)
516
+ - `config`: Request configuration
517
+ - `response`: Axios response object
518
+
519
+ ## Logging
520
+
521
+ When `debug` is enabled, the library logs detailed request/response information:
522
+
523
+ ```
524
+ ================================================== login start ==================================================
525
+ url: https://api.example.com/v1/auth/login
526
+ method: POST
527
+ headers: { 'Content-Type': 'application/json', 'Authorization': '***REDACTED***' }
528
+ params: { username: 'test', password: '***REDACTED***' }
529
+ timestamp: 1234567890
530
+ ================================================= login end ===================================================
531
+ url: https://api.example.com/v1/auth/login
532
+ method: POST
533
+ status: 200
534
+ statusText: OK
535
+ data: { token: '...', refreshToken: '...' }
536
+ timestamp: 1234567895
537
+ duration: 5ms
538
+ ```
539
+
540
+ Sensitive information (passwords, tokens, etc.) is automatically redacted.
541
+
542
+ ## Development
543
+
544
+ ### Build
545
+
546
+ ```bash
547
+ npm run build
548
+ ```
549
+
550
+ ### Test
551
+
552
+ ```bash
553
+ npm test
554
+ npm run test:coverage
555
+ ```
556
+
557
+ ### Lint
558
+
559
+ ```bash
560
+ npm run lint
561
+ npm run lint:fix
562
+ ```
563
+
564
+ ### Type Check
565
+
566
+ ```bash
567
+ npm run typecheck
568
+ ```
569
+
570
+ ## License
571
+
572
+ MIT
573
+
574
+ ## Contributing
575
+
576
+ Contributions are welcome! Please feel free to submit a Pull Request.