@fjell/registry 4.4.51 → 4.4.53
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/package.json +4 -4
- package/API.md +0 -62
- package/GETTING_STARTED.md +0 -69
- package/build.js +0 -38
- package/docs/README.md +0 -74
- package/docs/TIMING_NODE_OPTIMIZATION.md +0 -207
- package/docs/TIMING_README.md +0 -170
- package/docs/docs.config.ts +0 -114
- package/docs/index.html +0 -26
- package/docs/package-lock.json +0 -5129
- package/docs/package.json +0 -34
- package/docs/public/404.html +0 -53
- package/docs/public/GETTING_STARTED.md +0 -69
- package/docs/public/README.md +0 -623
- package/docs/public/TIMING_NODE_OPTIMIZATION.md +0 -207
- package/docs/public/api.md +0 -62
- package/docs/public/client-api-overview.md +0 -137
- package/docs/public/configuration.md +0 -759
- package/docs/public/error-handling/README.md +0 -356
- package/docs/public/error-handling/network-errors.md +0 -485
- package/docs/public/examples/coordinates-example.ts +0 -253
- package/docs/public/examples/multi-level-keys.ts +0 -374
- package/docs/public/examples/registry-hub-coordinates-example.ts +0 -370
- package/docs/public/examples/registry-hub-types.ts +0 -437
- package/docs/public/examples/simple-example.ts +0 -250
- package/docs/public/examples-README.md +0 -241
- package/docs/public/fjell-icon.svg +0 -1
- package/docs/public/icon.png +0 -0
- package/docs/public/icon2.png +0 -0
- package/docs/public/memory-overhead.svg +0 -120
- package/docs/public/memory.md +0 -430
- package/docs/public/operations/README.md +0 -121
- package/docs/public/operations/all.md +0 -325
- package/docs/public/operations/create.md +0 -415
- package/docs/public/operations/get.md +0 -389
- package/docs/public/package.json +0 -63
- package/docs/public/pano.png +0 -0
- package/docs/public/pano2.png +0 -0
- package/docs/public/timing-range.svg +0 -176
- package/docs/public/timing.md +0 -483
- package/docs/timing-range.svg +0 -174
- package/docs/vitest.config.ts +0 -14
- package/examples/README.md +0 -241
- package/examples/coordinates-example.ts +0 -253
- package/examples/multi-level-keys.ts +0 -382
- package/examples/registry-hub-coordinates-example.ts +0 -370
- package/examples/registry-hub-types.ts +0 -437
- package/examples/registry-statistics-example.ts +0 -264
- package/examples/simple-example.ts +0 -250
- package/tsconfig.docs.json +0 -28
- package/vitest.config.ts +0 -22
|
@@ -1,759 +0,0 @@
|
|
|
1
|
-
# Configuration Guide
|
|
2
|
-
|
|
3
|
-
Complete guide to configuring the Fjell Client API for development and production environments.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The Fjell Client API provides extensive configuration options for authentication, error handling, retry logic, monitoring, and performance optimization. This guide covers all available options with practical examples.
|
|
8
|
-
|
|
9
|
-
## Basic Configuration
|
|
10
|
-
|
|
11
|
-
### Minimal Setup
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import { createPItemApi, createCItemApi } from '@fjell/client-api';
|
|
15
|
-
|
|
16
|
-
// Minimal configuration for development
|
|
17
|
-
const config = {
|
|
18
|
-
baseUrl: 'http://localhost:3000/api'
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const userApi = createPItemApi<User, 'user'>('user', ['users'], config);
|
|
22
|
-
const taskApi = createCItemApi<Task, 'task', 'user'>('task', ['users', 'tasks'], config);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Standard Development Configuration
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
const devConfig = {
|
|
29
|
-
baseUrl: 'http://localhost:3000/api',
|
|
30
|
-
headers: {
|
|
31
|
-
'Content-Type': 'application/json',
|
|
32
|
-
'X-Client-Version': '1.0.0'
|
|
33
|
-
},
|
|
34
|
-
timeout: 10000,
|
|
35
|
-
enableErrorHandling: true,
|
|
36
|
-
retryConfig: {
|
|
37
|
-
maxRetries: 2,
|
|
38
|
-
initialDelayMs: 500,
|
|
39
|
-
maxDelayMs: 5000
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Configuration Options
|
|
45
|
-
|
|
46
|
-
### ClientApiOptions Interface
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
interface ClientApiOptions {
|
|
50
|
-
// Required
|
|
51
|
-
baseUrl: string; // API base URL
|
|
52
|
-
|
|
53
|
-
// HTTP Configuration
|
|
54
|
-
headers?: Record<string, string>; // Default headers
|
|
55
|
-
timeout?: number; // Request timeout (ms)
|
|
56
|
-
|
|
57
|
-
// Authentication
|
|
58
|
-
readAuthenticated?: boolean; // Authenticate read operations
|
|
59
|
-
writeAuthenticated?: boolean; // Authenticate write operations
|
|
60
|
-
getOptions?: RequestOptions; // GET request options
|
|
61
|
-
postOptions?: RequestOptions; // POST request options
|
|
62
|
-
putOptions?: RequestOptions; // PUT request options
|
|
63
|
-
deleteOptions?: RequestOptions; // DELETE request options
|
|
64
|
-
|
|
65
|
-
// Error Handling
|
|
66
|
-
enableErrorHandling?: boolean; // Enable comprehensive error handling
|
|
67
|
-
retryConfig?: RetryConfig; // Retry behavior configuration
|
|
68
|
-
errorHandler?: (error: any, context?: Record<string, any>) => void; // Custom error handler
|
|
69
|
-
|
|
70
|
-
// Advanced
|
|
71
|
-
transformRequest?: (data: any) => any; // Transform request data
|
|
72
|
-
transformResponse?: (data: any) => any; // Transform response data
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### RetryConfig Interface
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
interface RetryConfig {
|
|
80
|
-
maxRetries: number; // Maximum retry attempts
|
|
81
|
-
initialDelayMs: number; // Initial delay between retries
|
|
82
|
-
maxDelayMs: number; // Maximum delay between retries
|
|
83
|
-
backoffMultiplier: number; // Exponential backoff multiplier
|
|
84
|
-
enableJitter: boolean; // Add randomness to delays
|
|
85
|
-
|
|
86
|
-
// Advanced retry logic
|
|
87
|
-
shouldRetry?: (error: any, attemptNumber: number) => boolean; // Custom retry decision
|
|
88
|
-
onRetry?: (error: any, attemptNumber: number, delay: number) => void; // Retry callback
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Authentication Configuration
|
|
93
|
-
|
|
94
|
-
### Basic Authentication
|
|
95
|
-
|
|
96
|
-
```typescript
|
|
97
|
-
const authConfig = {
|
|
98
|
-
baseUrl: 'https://api.example.com',
|
|
99
|
-
headers: {
|
|
100
|
-
'Authorization': 'Bearer your-api-token',
|
|
101
|
-
'Content-Type': 'application/json'
|
|
102
|
-
},
|
|
103
|
-
readAuthenticated: true,
|
|
104
|
-
writeAuthenticated: true
|
|
105
|
-
};
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Dynamic Authentication
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
// Token that updates automatically
|
|
112
|
-
let authToken = 'initial-token';
|
|
113
|
-
|
|
114
|
-
const dynamicAuthConfig = {
|
|
115
|
-
baseUrl: 'https://api.example.com',
|
|
116
|
-
headers: {
|
|
117
|
-
get 'Authorization'() {
|
|
118
|
-
return `Bearer ${authToken}`;
|
|
119
|
-
},
|
|
120
|
-
'Content-Type': 'application/json'
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Update token when needed
|
|
125
|
-
function updateAuthToken(newToken: string) {
|
|
126
|
-
authToken = newToken;
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Per-Operation Authentication
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
const mixedAuthConfig = {
|
|
134
|
-
baseUrl: 'https://api.example.com',
|
|
135
|
-
|
|
136
|
-
// Default headers (no auth)
|
|
137
|
-
headers: {
|
|
138
|
-
'Content-Type': 'application/json'
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
// Authenticate only write operations
|
|
142
|
-
writeAuthenticated: true,
|
|
143
|
-
|
|
144
|
-
// Custom options for different operations
|
|
145
|
-
postOptions: {
|
|
146
|
-
headers: {
|
|
147
|
-
'Authorization': 'Bearer write-token',
|
|
148
|
-
'X-Write-Permission': 'true'
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
putOptions: {
|
|
153
|
-
headers: {
|
|
154
|
-
'Authorization': 'Bearer write-token',
|
|
155
|
-
'X-Write-Permission': 'true'
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
deleteOptions: {
|
|
160
|
-
headers: {
|
|
161
|
-
'Authorization': 'Bearer admin-token',
|
|
162
|
-
'X-Admin-Permission': 'true'
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## Retry Configuration
|
|
169
|
-
|
|
170
|
-
### Development Retry Settings
|
|
171
|
-
|
|
172
|
-
```typescript
|
|
173
|
-
const devRetryConfig = {
|
|
174
|
-
maxRetries: 2,
|
|
175
|
-
initialDelayMs: 500,
|
|
176
|
-
maxDelayMs: 5000,
|
|
177
|
-
backoffMultiplier: 2,
|
|
178
|
-
enableJitter: true
|
|
179
|
-
};
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### Production Retry Settings
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
const prodRetryConfig = {
|
|
186
|
-
maxRetries: 5,
|
|
187
|
-
initialDelayMs: 1000,
|
|
188
|
-
maxDelayMs: 30000,
|
|
189
|
-
backoffMultiplier: 1.5,
|
|
190
|
-
enableJitter: true,
|
|
191
|
-
|
|
192
|
-
// Custom retry logic for production
|
|
193
|
-
shouldRetry: (error, attemptNumber) => {
|
|
194
|
-
// Always retry network and server errors
|
|
195
|
-
if (error.code === 'NETWORK_ERROR' || error.code === 'SERVER_ERROR') {
|
|
196
|
-
return attemptNumber < 5;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Limited retries for rate limiting
|
|
200
|
-
if (error.code === 'RATE_LIMIT_ERROR') {
|
|
201
|
-
return attemptNumber < 3;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// No retries for client errors
|
|
205
|
-
if (error.status >= 400 && error.status < 500) {
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return error.isRetryable && attemptNumber < 3;
|
|
210
|
-
},
|
|
211
|
-
|
|
212
|
-
// Monitor retry attempts
|
|
213
|
-
onRetry: (error, attemptNumber, delay) => {
|
|
214
|
-
console.log(`Retry attempt ${attemptNumber + 1} for ${error.code} (delay: ${delay}ms)`);
|
|
215
|
-
|
|
216
|
-
// Send metrics to monitoring service
|
|
217
|
-
metrics.increment('api.retry', {
|
|
218
|
-
error_code: error.code,
|
|
219
|
-
attempt: attemptNumber + 1
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Operation-Specific Retry Configuration
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
228
|
-
// Different retry strategies for different operations
|
|
229
|
-
const adaptiveRetryConfig = {
|
|
230
|
-
shouldRetry: (error, attemptNumber, context) => {
|
|
231
|
-
// More aggressive retries for read operations
|
|
232
|
-
if (context?.operation === 'get' || context?.operation === 'all') {
|
|
233
|
-
return error.isRetryable && attemptNumber < 5;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Conservative retries for write operations
|
|
237
|
-
if (context?.operation === 'create' || context?.operation === 'update') {
|
|
238
|
-
return error.isRetryable && attemptNumber < 2;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// No retries for delete operations
|
|
242
|
-
if (context?.operation === 'remove') {
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return error.isRetryable && attemptNumber < 3;
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## Error Handling Configuration
|
|
252
|
-
|
|
253
|
-
### Basic Error Handler
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
const basicErrorHandler = (error: any, context?: Record<string, any>) => {
|
|
257
|
-
console.error('API Error:', {
|
|
258
|
-
message: error.message,
|
|
259
|
-
code: error.code,
|
|
260
|
-
operation: context?.operation,
|
|
261
|
-
url: context?.url
|
|
262
|
-
});
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
const config = {
|
|
266
|
-
baseUrl: 'https://api.example.com',
|
|
267
|
-
enableErrorHandling: true,
|
|
268
|
-
errorHandler: basicErrorHandler
|
|
269
|
-
};
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### Production Error Handler
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
const productionErrorHandler = (error: any, context?: Record<string, any>) => {
|
|
276
|
-
// Structured logging
|
|
277
|
-
logger.error('API Operation Failed', {
|
|
278
|
-
error: {
|
|
279
|
-
message: error.message,
|
|
280
|
-
code: error.code,
|
|
281
|
-
stack: error.stack
|
|
282
|
-
},
|
|
283
|
-
context: {
|
|
284
|
-
operation: context?.operation,
|
|
285
|
-
url: context?.url,
|
|
286
|
-
method: context?.method,
|
|
287
|
-
duration: context?.duration,
|
|
288
|
-
attempts: context?.attempts
|
|
289
|
-
},
|
|
290
|
-
timestamp: new Date().toISOString(),
|
|
291
|
-
requestId: context?.requestId || generateRequestId()
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
// Error tracking service
|
|
295
|
-
errorTracking.captureException(error, {
|
|
296
|
-
tags: {
|
|
297
|
-
service: 'fjell-client-api',
|
|
298
|
-
operation: context?.operation,
|
|
299
|
-
environment: process.env.NODE_ENV
|
|
300
|
-
},
|
|
301
|
-
extra: context,
|
|
302
|
-
user: {
|
|
303
|
-
id: getCurrentUserId()
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// Business logic based on error type
|
|
308
|
-
if (error.code === 'AUTHENTICATION_ERROR') {
|
|
309
|
-
// Redirect to login
|
|
310
|
-
authService.redirectToLogin();
|
|
311
|
-
} else if (error.code === 'RATE_LIMIT_ERROR') {
|
|
312
|
-
// Implement circuit breaker
|
|
313
|
-
circuitBreaker.recordFailure();
|
|
314
|
-
} else if (error.code === 'PAYMENT_ERROR') {
|
|
315
|
-
// Send business notification
|
|
316
|
-
notificationService.sendPaymentFailure({
|
|
317
|
-
userId: context?.userId,
|
|
318
|
-
orderId: context?.orderId,
|
|
319
|
-
error: error.message
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Metrics collection
|
|
324
|
-
metrics.increment('api.errors.total', {
|
|
325
|
-
error_code: error.code,
|
|
326
|
-
operation: context?.operation,
|
|
327
|
-
environment: process.env.NODE_ENV
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
// Alerting for critical errors
|
|
331
|
-
if (error.code === 'SERVER_ERROR' && context?.attempts >= 3) {
|
|
332
|
-
alerting.sendAlert({
|
|
333
|
-
severity: 'high',
|
|
334
|
-
title: 'API Server Error After Multiple Retries',
|
|
335
|
-
description: `Operation ${context.operation} failed with ${error.message} after ${context.attempts} attempts`,
|
|
336
|
-
context
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
## Environment-Specific Configuration
|
|
343
|
-
|
|
344
|
-
### Development Environment
|
|
345
|
-
|
|
346
|
-
```typescript
|
|
347
|
-
const developmentConfig = {
|
|
348
|
-
baseUrl: 'http://localhost:3000/api',
|
|
349
|
-
headers: {
|
|
350
|
-
'Content-Type': 'application/json',
|
|
351
|
-
'X-Environment': 'development'
|
|
352
|
-
},
|
|
353
|
-
timeout: 10000,
|
|
354
|
-
enableErrorHandling: true,
|
|
355
|
-
|
|
356
|
-
retryConfig: {
|
|
357
|
-
maxRetries: 2,
|
|
358
|
-
initialDelayMs: 500,
|
|
359
|
-
maxDelayMs: 5000,
|
|
360
|
-
backoffMultiplier: 2,
|
|
361
|
-
enableJitter: false // Consistent timing for development
|
|
362
|
-
},
|
|
363
|
-
|
|
364
|
-
errorHandler: (error, context) => {
|
|
365
|
-
// Detailed logging for development
|
|
366
|
-
console.group('🚨 API Error Details');
|
|
367
|
-
console.error('Error:', error);
|
|
368
|
-
console.log('Context:', context);
|
|
369
|
-
console.groupEnd();
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
### Staging Environment
|
|
375
|
-
|
|
376
|
-
```typescript
|
|
377
|
-
const stagingConfig = {
|
|
378
|
-
baseUrl: 'https://api-staging.example.com',
|
|
379
|
-
headers: {
|
|
380
|
-
'Content-Type': 'application/json',
|
|
381
|
-
'Authorization': `Bearer ${process.env.STAGING_API_TOKEN}`,
|
|
382
|
-
'X-Environment': 'staging'
|
|
383
|
-
},
|
|
384
|
-
timeout: 15000,
|
|
385
|
-
enableErrorHandling: true,
|
|
386
|
-
|
|
387
|
-
retryConfig: {
|
|
388
|
-
maxRetries: 3,
|
|
389
|
-
initialDelayMs: 1000,
|
|
390
|
-
maxDelayMs: 15000,
|
|
391
|
-
backoffMultiplier: 2,
|
|
392
|
-
enableJitter: true
|
|
393
|
-
},
|
|
394
|
-
|
|
395
|
-
errorHandler: (error, context) => {
|
|
396
|
-
// Same as production but with additional debugging
|
|
397
|
-
productionErrorHandler(error, context);
|
|
398
|
-
|
|
399
|
-
// Extra staging-specific logging
|
|
400
|
-
if (process.env.STAGING_DEBUG === 'true') {
|
|
401
|
-
console.log('Staging Debug Info:', {
|
|
402
|
-
error,
|
|
403
|
-
context,
|
|
404
|
-
environment: 'staging'
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
};
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
### Production Environment
|
|
412
|
-
|
|
413
|
-
```typescript
|
|
414
|
-
const productionConfig = {
|
|
415
|
-
baseUrl: 'https://api.example.com',
|
|
416
|
-
headers: {
|
|
417
|
-
'Content-Type': 'application/json',
|
|
418
|
-
'Authorization': `Bearer ${process.env.PRODUCTION_API_TOKEN}`,
|
|
419
|
-
'X-Environment': 'production',
|
|
420
|
-
'X-Service-Version': process.env.SERVICE_VERSION,
|
|
421
|
-
'X-Request-Source': 'fjell-client-api'
|
|
422
|
-
},
|
|
423
|
-
timeout: 30000,
|
|
424
|
-
enableErrorHandling: true,
|
|
425
|
-
|
|
426
|
-
retryConfig: {
|
|
427
|
-
maxRetries: 5,
|
|
428
|
-
initialDelayMs: 1000,
|
|
429
|
-
maxDelayMs: 60000,
|
|
430
|
-
backoffMultiplier: 1.5,
|
|
431
|
-
enableJitter: true,
|
|
432
|
-
|
|
433
|
-
shouldRetry: (error, attemptNumber) => {
|
|
434
|
-
// Production-optimized retry logic
|
|
435
|
-
if (error.code === 'NETWORK_ERROR') return attemptNumber < 5;
|
|
436
|
-
if (error.code === 'SERVER_ERROR') return attemptNumber < 3;
|
|
437
|
-
if (error.code === 'RATE_LIMIT_ERROR') return attemptNumber < 3;
|
|
438
|
-
if (error.code === 'TIMEOUT_ERROR') return attemptNumber < 2;
|
|
439
|
-
return false;
|
|
440
|
-
},
|
|
441
|
-
|
|
442
|
-
onRetry: (error, attemptNumber, delay) => {
|
|
443
|
-
// Production retry monitoring
|
|
444
|
-
metrics.increment('api.retries', {
|
|
445
|
-
error_code: error.code,
|
|
446
|
-
attempt: attemptNumber + 1
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
},
|
|
450
|
-
|
|
451
|
-
errorHandler: productionErrorHandler
|
|
452
|
-
};
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
## Advanced Configuration Patterns
|
|
456
|
-
|
|
457
|
-
### Multi-Environment Configuration Factory
|
|
458
|
-
|
|
459
|
-
```typescript
|
|
460
|
-
interface EnvironmentConfig {
|
|
461
|
-
api: {
|
|
462
|
-
baseUrl: string;
|
|
463
|
-
token: string;
|
|
464
|
-
};
|
|
465
|
-
retry: {
|
|
466
|
-
maxRetries: number;
|
|
467
|
-
timeout: number;
|
|
468
|
-
};
|
|
469
|
-
monitoring: {
|
|
470
|
-
enabled: boolean;
|
|
471
|
-
endpoint?: string;
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const environments: Record<string, EnvironmentConfig> = {
|
|
476
|
-
development: {
|
|
477
|
-
api: {
|
|
478
|
-
baseUrl: 'http://localhost:3000/api',
|
|
479
|
-
token: 'dev-token'
|
|
480
|
-
},
|
|
481
|
-
retry: {
|
|
482
|
-
maxRetries: 2,
|
|
483
|
-
timeout: 10000
|
|
484
|
-
},
|
|
485
|
-
monitoring: {
|
|
486
|
-
enabled: false
|
|
487
|
-
}
|
|
488
|
-
},
|
|
489
|
-
|
|
490
|
-
production: {
|
|
491
|
-
api: {
|
|
492
|
-
baseUrl: 'https://api.example.com',
|
|
493
|
-
token: process.env.PROD_API_TOKEN!
|
|
494
|
-
},
|
|
495
|
-
retry: {
|
|
496
|
-
maxRetries: 5,
|
|
497
|
-
timeout: 30000
|
|
498
|
-
},
|
|
499
|
-
monitoring: {
|
|
500
|
-
enabled: true,
|
|
501
|
-
endpoint: 'https://monitoring.example.com'
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
function createApiConfig(environment: string): ClientApiOptions {
|
|
507
|
-
const envConfig = environments[environment];
|
|
508
|
-
if (!envConfig) {
|
|
509
|
-
throw new Error(`Unknown environment: ${environment}`);
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
return {
|
|
513
|
-
baseUrl: envConfig.api.baseUrl,
|
|
514
|
-
headers: {
|
|
515
|
-
'Authorization': `Bearer ${envConfig.api.token}`,
|
|
516
|
-
'Content-Type': 'application/json',
|
|
517
|
-
'X-Environment': environment
|
|
518
|
-
},
|
|
519
|
-
timeout: envConfig.retry.timeout,
|
|
520
|
-
enableErrorHandling: true,
|
|
521
|
-
|
|
522
|
-
retryConfig: {
|
|
523
|
-
maxRetries: envConfig.retry.maxRetries,
|
|
524
|
-
initialDelayMs: 1000,
|
|
525
|
-
maxDelayMs: environment === 'production' ? 60000 : 15000,
|
|
526
|
-
backoffMultiplier: environment === 'production' ? 1.5 : 2,
|
|
527
|
-
enableJitter: true
|
|
528
|
-
},
|
|
529
|
-
|
|
530
|
-
errorHandler: envConfig.monitoring.enabled
|
|
531
|
-
? productionErrorHandler
|
|
532
|
-
: developmentErrorHandler
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Usage
|
|
537
|
-
const config = createApiConfig(process.env.NODE_ENV || 'development');
|
|
538
|
-
const userApi = createPItemApi<User, 'user'>('user', ['users'], config);
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
### Configuration with Secrets Management
|
|
542
|
-
|
|
543
|
-
```typescript
|
|
544
|
-
import { getSecret } from './secrets';
|
|
545
|
-
|
|
546
|
-
async function createSecureApiConfig(): Promise<ClientApiOptions> {
|
|
547
|
-
const apiToken = await getSecret('API_TOKEN');
|
|
548
|
-
const encryptionKey = await getSecret('ENCRYPTION_KEY');
|
|
549
|
-
|
|
550
|
-
return {
|
|
551
|
-
baseUrl: process.env.API_BASE_URL!,
|
|
552
|
-
headers: {
|
|
553
|
-
'Authorization': `Bearer ${apiToken}`,
|
|
554
|
-
'Content-Type': 'application/json',
|
|
555
|
-
'X-Encryption-Key': encryptionKey
|
|
556
|
-
},
|
|
557
|
-
timeout: 30000,
|
|
558
|
-
enableErrorHandling: true,
|
|
559
|
-
|
|
560
|
-
// Transform sensitive data
|
|
561
|
-
transformRequest: (data) => {
|
|
562
|
-
// Encrypt sensitive fields
|
|
563
|
-
if (data.password) {
|
|
564
|
-
data.password = encrypt(data.password, encryptionKey);
|
|
565
|
-
}
|
|
566
|
-
return data;
|
|
567
|
-
},
|
|
568
|
-
|
|
569
|
-
transformResponse: (data) => {
|
|
570
|
-
// Decrypt sensitive fields
|
|
571
|
-
if (data.encryptedData) {
|
|
572
|
-
data.decryptedData = decrypt(data.encryptedData, encryptionKey);
|
|
573
|
-
delete data.encryptedData;
|
|
574
|
-
}
|
|
575
|
-
return data;
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
### Configuration Validation
|
|
582
|
-
|
|
583
|
-
```typescript
|
|
584
|
-
import Joi from 'joi';
|
|
585
|
-
|
|
586
|
-
const configSchema = Joi.object({
|
|
587
|
-
baseUrl: Joi.string().uri().required(),
|
|
588
|
-
timeout: Joi.number().min(1000).max(300000).default(30000),
|
|
589
|
-
retryConfig: Joi.object({
|
|
590
|
-
maxRetries: Joi.number().min(0).max(10).required(),
|
|
591
|
-
initialDelayMs: Joi.number().min(100).max(10000).required(),
|
|
592
|
-
maxDelayMs: Joi.number().min(1000).max(300000).required(),
|
|
593
|
-
backoffMultiplier: Joi.number().min(1).max(5).required(),
|
|
594
|
-
enableJitter: Joi.boolean().required()
|
|
595
|
-
}).required()
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
function validateConfig(config: ClientApiOptions): ClientApiOptions {
|
|
599
|
-
const { error, value } = configSchema.validate(config);
|
|
600
|
-
|
|
601
|
-
if (error) {
|
|
602
|
-
throw new Error(`Invalid configuration: ${error.message}`);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
return value;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// Usage
|
|
609
|
-
const config = validateConfig({
|
|
610
|
-
baseUrl: 'https://api.example.com',
|
|
611
|
-
retryConfig: {
|
|
612
|
-
maxRetries: 3,
|
|
613
|
-
initialDelayMs: 1000,
|
|
614
|
-
maxDelayMs: 30000,
|
|
615
|
-
backoffMultiplier: 2,
|
|
616
|
-
enableJitter: true
|
|
617
|
-
}
|
|
618
|
-
});
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
## Testing Configuration
|
|
622
|
-
|
|
623
|
-
### Mock Configuration for Testing
|
|
624
|
-
|
|
625
|
-
```typescript
|
|
626
|
-
const testConfig: ClientApiOptions = {
|
|
627
|
-
baseUrl: 'http://mock-api.test',
|
|
628
|
-
timeout: 5000,
|
|
629
|
-
enableErrorHandling: false, // Disable for predictable testing
|
|
630
|
-
|
|
631
|
-
retryConfig: {
|
|
632
|
-
maxRetries: 1, // Minimal retries for faster tests
|
|
633
|
-
initialDelayMs: 10,
|
|
634
|
-
maxDelayMs: 100,
|
|
635
|
-
backoffMultiplier: 1,
|
|
636
|
-
enableJitter: false // Consistent timing for tests
|
|
637
|
-
},
|
|
638
|
-
|
|
639
|
-
errorHandler: (error, context) => {
|
|
640
|
-
// Capture errors for test assertions
|
|
641
|
-
testErrorCapture.capture(error, context);
|
|
642
|
-
}
|
|
643
|
-
};
|
|
644
|
-
```
|
|
645
|
-
|
|
646
|
-
### Integration Test Configuration
|
|
647
|
-
|
|
648
|
-
```typescript
|
|
649
|
-
const integrationTestConfig: ClientApiOptions = {
|
|
650
|
-
baseUrl: process.env.TEST_API_URL || 'http://localhost:3001/api',
|
|
651
|
-
headers: {
|
|
652
|
-
'Authorization': `Bearer ${process.env.TEST_API_TOKEN}`,
|
|
653
|
-
'X-Test-Mode': 'true'
|
|
654
|
-
},
|
|
655
|
-
timeout: 10000,
|
|
656
|
-
enableErrorHandling: true,
|
|
657
|
-
|
|
658
|
-
retryConfig: {
|
|
659
|
-
maxRetries: 2,
|
|
660
|
-
initialDelayMs: 100,
|
|
661
|
-
maxDelayMs: 1000,
|
|
662
|
-
backoffMultiplier: 2,
|
|
663
|
-
enableJitter: false
|
|
664
|
-
}
|
|
665
|
-
};
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
## Configuration Best Practices
|
|
669
|
-
|
|
670
|
-
### 1. **Environment Variables**
|
|
671
|
-
|
|
672
|
-
```typescript
|
|
673
|
-
// Use environment variables for sensitive data
|
|
674
|
-
const config = {
|
|
675
|
-
baseUrl: process.env.API_BASE_URL!,
|
|
676
|
-
headers: {
|
|
677
|
-
'Authorization': `Bearer ${process.env.API_TOKEN!}`,
|
|
678
|
-
},
|
|
679
|
-
timeout: parseInt(process.env.API_TIMEOUT || '30000'),
|
|
680
|
-
|
|
681
|
-
retryConfig: {
|
|
682
|
-
maxRetries: parseInt(process.env.API_MAX_RETRIES || '3'),
|
|
683
|
-
initialDelayMs: parseInt(process.env.API_INITIAL_DELAY || '1000')
|
|
684
|
-
}
|
|
685
|
-
};
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
### 2. **Configuration Hierarchy**
|
|
689
|
-
|
|
690
|
-
```typescript
|
|
691
|
-
// Base configuration
|
|
692
|
-
const baseConfig = {
|
|
693
|
-
headers: {
|
|
694
|
-
'Content-Type': 'application/json',
|
|
695
|
-
'User-Agent': 'fjell-client-api/1.0'
|
|
696
|
-
},
|
|
697
|
-
timeout: 30000,
|
|
698
|
-
enableErrorHandling: true
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
// Environment-specific overrides
|
|
702
|
-
const envConfig = {
|
|
703
|
-
development: {
|
|
704
|
-
...baseConfig,
|
|
705
|
-
baseUrl: 'http://localhost:3000/api',
|
|
706
|
-
retryConfig: { maxRetries: 2 }
|
|
707
|
-
},
|
|
708
|
-
|
|
709
|
-
production: {
|
|
710
|
-
...baseConfig,
|
|
711
|
-
baseUrl: 'https://api.example.com',
|
|
712
|
-
retryConfig: { maxRetries: 5 }
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
```
|
|
716
|
-
|
|
717
|
-
### 3. **Type Safety**
|
|
718
|
-
|
|
719
|
-
```typescript
|
|
720
|
-
// Use TypeScript for configuration validation
|
|
721
|
-
interface AppConfig {
|
|
722
|
-
api: ClientApiOptions;
|
|
723
|
-
features: {
|
|
724
|
-
enableRetries: boolean;
|
|
725
|
-
enableCaching: boolean;
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
const appConfig: AppConfig = {
|
|
730
|
-
api: {
|
|
731
|
-
baseUrl: process.env.API_BASE_URL!,
|
|
732
|
-
retryConfig: {
|
|
733
|
-
maxRetries: 3,
|
|
734
|
-
initialDelayMs: 1000,
|
|
735
|
-
maxDelayMs: 30000,
|
|
736
|
-
backoffMultiplier: 2,
|
|
737
|
-
enableJitter: true
|
|
738
|
-
}
|
|
739
|
-
},
|
|
740
|
-
features: {
|
|
741
|
-
enableRetries: true,
|
|
742
|
-
enableCaching: false
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
## Related Documentation
|
|
748
|
-
|
|
749
|
-
- [Error Handling](./error-handling/README.md) - Configure error handling behavior
|
|
750
|
-
- [Operations](./operations/README.md) - Operation-specific configuration
|
|
751
|
-
- [Examples](../examples-README.md) - Configuration examples and patterns
|
|
752
|
-
|
|
753
|
-
## Next Steps
|
|
754
|
-
|
|
755
|
-
1. Choose appropriate configuration for your environment
|
|
756
|
-
2. Set up error handling and monitoring
|
|
757
|
-
3. Configure retry behavior for your use case
|
|
758
|
-
4. Test configuration in staging environment
|
|
759
|
-
5. Monitor and adjust configuration based on production metrics
|