@dinoconfig/js-sdk 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/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/README.md +743 -0
- package/index.d.ts +88 -0
- package/index.js +883 -0
- package/lib/cache/cache-manager.d.ts +86 -0
- package/lib/cache/cache.types.d.ts +105 -0
- package/lib/cache/index.d.ts +8 -0
- package/lib/cache/memory-cache.d.ts +86 -0
- package/lib/cache/storage-cache.d.ts +58 -0
- package/lib/config-api.d.ts +111 -0
- package/lib/dinoconfig-js-sdk.d.ts +140 -0
- package/lib/discovery-api.d.ts +174 -0
- package/lib/http-client.d.ts +245 -0
- package/lib/types.d.ts +364 -0
- package/package.json +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
# DinoConfig JavaScript SDK
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@dinoconfig/js-sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@dinoconfig/js-sdk)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
|
|
9
|
+
Official JavaScript/TypeScript SDK for the DinoConfig API. This SDK provides a simple, type-safe, and intuitive way to interact with DinoConfig's configuration management system.
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [Features](#features)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Quick Start](#quick-start)
|
|
16
|
+
- [Configuration Options](#configuration-options)
|
|
17
|
+
- [Authentication](#authentication)
|
|
18
|
+
- [Caching](#caching)
|
|
19
|
+
- [API Reference](#api-reference)
|
|
20
|
+
- [Configs API](#configs-api)
|
|
21
|
+
- [Discovery API](#discovery-api)
|
|
22
|
+
- [Code Generation](#code-generation)
|
|
23
|
+
- [Error Handling](#error-handling)
|
|
24
|
+
- [TypeScript Support](#typescript-support)
|
|
25
|
+
- [Examples](#examples)
|
|
26
|
+
- [Contributing](#contributing)
|
|
27
|
+
- [License](#license)
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- **Simple Initialization** - Single factory function following modern SDK patterns
|
|
32
|
+
- **Automatic Authentication** - API key to token exchange handled automatically
|
|
33
|
+
- **Shorthand Path Syntax** - Use `"Brand.Config.Key"` dot notation for concise access
|
|
34
|
+
- **Discovery API** - Discover brands, configs, and schemas dynamically
|
|
35
|
+
- **Full Introspection** - Get complete visibility into all available configurations
|
|
36
|
+
- **Multi-Layer Caching** - In-memory (L1) and persistent storage (L2) caching for improved performance
|
|
37
|
+
- **Code Generation** - Generate TypeScript types from your config schemas
|
|
38
|
+
- **Type-Safe** - Full TypeScript support with comprehensive type definitions
|
|
39
|
+
- **Zero Dependencies** - Uses native `fetch` API, no external HTTP libraries required
|
|
40
|
+
- **Retry Logic** - Built-in exponential backoff for failed requests
|
|
41
|
+
- **Timeout Support** - Configurable request timeouts
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# npm
|
|
47
|
+
npm install @dinoconfig/js-sdk
|
|
48
|
+
|
|
49
|
+
# yarn
|
|
50
|
+
yarn add @dinoconfig/js-sdk
|
|
51
|
+
|
|
52
|
+
# pnpm
|
|
53
|
+
pnpm add @dinoconfig/js-sdk
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { dinoconfigApi } from '@dinoconfig/js-sdk';
|
|
60
|
+
|
|
61
|
+
// Initialize the SDK
|
|
62
|
+
const dinoconfig = await dinoconfigApi({
|
|
63
|
+
apiKey: 'dino_your-api-key-here',
|
|
64
|
+
baseUrl: 'https://api.dinoconfig.com', // optional
|
|
65
|
+
timeout: 10000 // optional
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Get entire config
|
|
69
|
+
const config = await dinoconfig.configs.get('MyBrand', 'AppSettings');
|
|
70
|
+
console.log('All values:', config.data.values);
|
|
71
|
+
|
|
72
|
+
// Get single value (shorthand)
|
|
73
|
+
const theme = await dinoconfig.configs.getValue('MyBrand.AppSettings.theme');
|
|
74
|
+
console.log('Theme:', theme.data);
|
|
75
|
+
|
|
76
|
+
// Get single value (full params)
|
|
77
|
+
const response = await dinoconfig.configs.getValue('MyBrand', 'AppSettings', 'theme');
|
|
78
|
+
console.log('Theme:', response.data);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**That's it!** The SDK handles:
|
|
82
|
+
- API key to access token exchange
|
|
83
|
+
- Authorization headers
|
|
84
|
+
- Request formatting and parsing
|
|
85
|
+
|
|
86
|
+
## Configuration Options
|
|
87
|
+
|
|
88
|
+
| Option | Type | Required | Default | Description |
|
|
89
|
+
|--------|------|----------|---------|-------------|
|
|
90
|
+
| `apiKey` | `string` | **Yes** | - | Your DinoConfig API key |
|
|
91
|
+
| `baseUrl` | `string` | No | `'http://localhost:3000'` | Base URL for the API |
|
|
92
|
+
| `timeout` | `number` | No | `10000` | Request timeout in milliseconds |
|
|
93
|
+
| `cache` | `CacheConfig` | No | `{ enabled: false }` | Cache configuration (see [Caching](#caching)) |
|
|
94
|
+
|
|
95
|
+
### Example with All Options
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const dinoconfig = await dinoconfigApi({
|
|
99
|
+
apiKey: 'dino_abc123def456...',
|
|
100
|
+
baseUrl: 'https://api.dinoconfig.com',
|
|
101
|
+
timeout: 15000,
|
|
102
|
+
cache: {
|
|
103
|
+
enabled: true,
|
|
104
|
+
ttl: 60000,
|
|
105
|
+
storage: 'localStorage',
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Caching
|
|
111
|
+
|
|
112
|
+
The SDK includes a powerful multi-layer caching system that significantly improves performance by reducing network requests.
|
|
113
|
+
|
|
114
|
+
### Cache Layers
|
|
115
|
+
|
|
116
|
+
The cache operates on two layers:
|
|
117
|
+
|
|
118
|
+
1. **L1 - Memory Cache** (Fast, short-lived)
|
|
119
|
+
- In-memory storage for instant access
|
|
120
|
+
- Default TTL: 60 seconds (configurable)
|
|
121
|
+
- Cleared when the application restarts
|
|
122
|
+
|
|
123
|
+
2. **L2 - Storage Cache** (Persistent, longer-lived)
|
|
124
|
+
- Browser `localStorage` or `IndexedDB` (future)
|
|
125
|
+
- Persists across page reloads
|
|
126
|
+
- Default TTL: 5 minutes (configurable)
|
|
127
|
+
|
|
128
|
+
### Cache Flow
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
Request → L1 Memory Cache → L2 Storage Cache → Network API
|
|
132
|
+
(if miss) (if miss) (source of truth)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Enabling Caching
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const dinoconfig = await dinoconfigApi({
|
|
139
|
+
apiKey: 'dino_your-api-key',
|
|
140
|
+
cache: {
|
|
141
|
+
enabled: true, // Enable caching
|
|
142
|
+
ttl: 60000, // 1 minute TTL for memory cache
|
|
143
|
+
maxSize: 1000, // Maximum cache entries
|
|
144
|
+
storage: 'localStorage', // Use localStorage for persistence
|
|
145
|
+
staleWhileRevalidate: false // Return stale data while refreshing
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Cache Configuration Options
|
|
151
|
+
|
|
152
|
+
| Option | Type | Default | Description |
|
|
153
|
+
|--------|------|---------|-------------|
|
|
154
|
+
| `enabled` | `boolean` | `false` | Whether caching is enabled |
|
|
155
|
+
| `ttl` | `number` | `60000` | Time-to-live in milliseconds (1 minute) |
|
|
156
|
+
| `maxSize` | `number` | `1000` | Maximum number of entries in memory cache |
|
|
157
|
+
| `storage` | `'memory' \| 'localStorage' \| 'indexedDB'` | `undefined` | Storage backend for L2 cache |
|
|
158
|
+
| `staleWhileRevalidate` | `boolean` | `false` | Return stale data while fetching fresh data |
|
|
159
|
+
|
|
160
|
+
### Cache-Aware Requests
|
|
161
|
+
|
|
162
|
+
All API methods automatically use the cache when enabled. You can control caching behavior per request:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Use cache (default behavior when cache is enabled)
|
|
166
|
+
const response = await dinoconfig.configs.getValue(
|
|
167
|
+
'Brand', 'Config', 'key'
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Force refresh (bypass cache)
|
|
171
|
+
const response = await dinoconfig.configs.getValue(
|
|
172
|
+
'Brand', 'Config', 'key',
|
|
173
|
+
{ forceRefresh: true }
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Disable cache for this request
|
|
177
|
+
const response = await dinoconfig.configs.getValue(
|
|
178
|
+
'Brand', 'Config', 'key',
|
|
179
|
+
{ cache: false }
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Cache Management
|
|
184
|
+
|
|
185
|
+
The SDK exposes a `cache` API for manual cache control:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// Get cache statistics
|
|
189
|
+
const stats = dinoconfig.cache.getStats();
|
|
190
|
+
console.log(`Hits: ${stats.hits}, Misses: ${stats.misses}, Hit Rate: ${(stats.hitRate * 100).toFixed(1)}%`);
|
|
191
|
+
|
|
192
|
+
// Clear all cache
|
|
193
|
+
await dinoconfig.cache.clear();
|
|
194
|
+
|
|
195
|
+
// Invalidate cache by pattern (regex)
|
|
196
|
+
await dinoconfig.cache.invalidate('brand:Paysafe:*'); // Clear all Paysafe configs
|
|
197
|
+
await dinoconfig.cache.invalidate('config:.*:.*:featureFlag'); // Clear all feature flags
|
|
198
|
+
|
|
199
|
+
// Prefetch a value into cache
|
|
200
|
+
await dinoconfig.cache.prefetch('key', async () => {
|
|
201
|
+
return await dinoconfig.configs.getValue('Brand', 'Config', 'key');
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Cache Performance
|
|
206
|
+
|
|
207
|
+
With caching enabled, subsequent requests to the same configuration value are served from cache, providing:
|
|
208
|
+
|
|
209
|
+
- **99%+ faster response times** - Cache hits typically take < 5ms vs 200-500ms for network requests
|
|
210
|
+
- **Reduced API costs** - Fewer network requests
|
|
211
|
+
- **Better offline experience** - Cached values available when network is unavailable
|
|
212
|
+
- **Improved user experience** - Instant configuration value access
|
|
213
|
+
|
|
214
|
+
### Example: Cache in Action
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
const dinoconfig = await dinoconfigApi({
|
|
218
|
+
apiKey: 'dino_...',
|
|
219
|
+
cache: {
|
|
220
|
+
enabled: true,
|
|
221
|
+
ttl: 60000,
|
|
222
|
+
storage: 'localStorage',
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// First request - hits network (~250ms)
|
|
227
|
+
console.time('first');
|
|
228
|
+
const response1 = await dinoconfig.configs.getValue('Brand', 'Config', 'key');
|
|
229
|
+
console.timeEnd('first'); // ~250ms
|
|
230
|
+
|
|
231
|
+
// Second request - served from cache (~1ms)
|
|
232
|
+
console.time('second');
|
|
233
|
+
const response2 = await dinoconfig.configs.getValue('Brand', 'Config', 'key');
|
|
234
|
+
console.timeEnd('second'); // ~1ms ⚡
|
|
235
|
+
|
|
236
|
+
// Check cache performance
|
|
237
|
+
const stats = dinoconfig.cache.getStats();
|
|
238
|
+
console.log(`Cache hit rate: ${(stats.hitRate * 100).toFixed(1)}%`);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Cache Best Practices
|
|
242
|
+
|
|
243
|
+
1. **Enable caching for production** - Significantly improves performance
|
|
244
|
+
2. **Use appropriate TTL** - Balance freshness vs performance (1-5 minutes recommended)
|
|
245
|
+
3. **Use localStorage for browser apps** - Persists across page reloads
|
|
246
|
+
4. **Invalidate cache on updates** - Use cache invalidation when you know configs changed
|
|
247
|
+
5. **Monitor cache hit rates** - Use `getStats()` to track cache effectiveness
|
|
248
|
+
|
|
249
|
+
## Authentication
|
|
250
|
+
|
|
251
|
+
### Security Best Practices
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// DO: Use environment variables
|
|
255
|
+
const dinoconfig = await dinoconfigApi({
|
|
256
|
+
apiKey: process.env.DINOCONFIG_API_KEY!,
|
|
257
|
+
baseUrl: process.env.DINOCONFIG_BASE_URL
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// DON'T: Hardcode API keys in source code
|
|
261
|
+
const dinoconfig = await dinoconfigApi({
|
|
262
|
+
apiKey: 'dino_abc123...' // Never do this in production!
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## API Reference
|
|
267
|
+
|
|
268
|
+
### Configs API
|
|
269
|
+
|
|
270
|
+
The Configs API provides methods to retrieve configuration values.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
#### `configs.get(path, options?)` / `configs.get(brand, config, options?)`
|
|
275
|
+
|
|
276
|
+
Retrieves an entire configuration with all its values.
|
|
277
|
+
|
|
278
|
+
**Signatures:**
|
|
279
|
+
```typescript
|
|
280
|
+
// Shorthand path
|
|
281
|
+
get(path: string, options?: RequestOptions): Promise<ApiResponse<ConfigData>>
|
|
282
|
+
|
|
283
|
+
// Full parameters
|
|
284
|
+
get(brand: string, config: string, options?: RequestOptions): Promise<ApiResponse<ConfigData>>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Returns:** `ApiResponse<ConfigData>` containing:
|
|
288
|
+
- `name` - Configuration name
|
|
289
|
+
- `description` - Configuration description
|
|
290
|
+
- `values` - All key-value pairs as `Record<string, unknown>`
|
|
291
|
+
- `version` - Configuration version
|
|
292
|
+
- `keys` - Array of all key names
|
|
293
|
+
- `createdAt` - Creation timestamp
|
|
294
|
+
- `updatedAt` - Last update timestamp
|
|
295
|
+
|
|
296
|
+
**Examples:**
|
|
297
|
+
```typescript
|
|
298
|
+
// Shorthand path
|
|
299
|
+
const config = await dinoconfig.configs.get('MyBrand.FeatureFlags');
|
|
300
|
+
console.log(config.data.values);
|
|
301
|
+
// { enableDarkMode: true, maxUsers: 100, ... }
|
|
302
|
+
|
|
303
|
+
// Full parameters
|
|
304
|
+
const config = await dinoconfig.configs.get('MyBrand', 'FeatureFlags');
|
|
305
|
+
console.log(`Version: ${config.data.version}`);
|
|
306
|
+
console.log(`Keys: ${config.data.keys.join(', ')}`);
|
|
307
|
+
|
|
308
|
+
// Access specific values
|
|
309
|
+
const { values } = config.data;
|
|
310
|
+
const darkMode = values.enableDarkMode as boolean;
|
|
311
|
+
const maxUsers = values.maxUsers as number;
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
#### `configs.getValue(path, options?)` / `configs.getValue(brand, config, key, options?)`
|
|
317
|
+
|
|
318
|
+
Retrieves a specific configuration value.
|
|
319
|
+
|
|
320
|
+
**Signatures:**
|
|
321
|
+
```typescript
|
|
322
|
+
// Shorthand path
|
|
323
|
+
getValue(path: string, options?: RequestOptions): Promise<ApiResponse<unknown>>
|
|
324
|
+
|
|
325
|
+
// Full parameters
|
|
326
|
+
getValue(brand: string, config: string, key: string, options?: RequestOptions): Promise<ApiResponse<unknown>>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Examples:**
|
|
330
|
+
```typescript
|
|
331
|
+
// Shorthand path (recommended)
|
|
332
|
+
const response = await dinoconfig.configs.getValue('MyBrand.FeatureFlags.enableDarkMode');
|
|
333
|
+
console.log('Dark mode:', response.data); // true
|
|
334
|
+
|
|
335
|
+
// Full parameters
|
|
336
|
+
const response = await dinoconfig.configs.getValue('MyBrand', 'FeatureFlags', 'enableDarkMode');
|
|
337
|
+
console.log('Dark mode:', response.data);
|
|
338
|
+
|
|
339
|
+
// With request options
|
|
340
|
+
const response = await dinoconfig.configs.getValue(
|
|
341
|
+
'MyBrand.CriticalConfig.databaseUrl',
|
|
342
|
+
{ timeout: 30000, retries: 5 }
|
|
343
|
+
);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
### Discovery API
|
|
349
|
+
|
|
350
|
+
The Discovery API enables dynamic configuration discovery.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
#### `discovery.listBrands(options?)`
|
|
355
|
+
|
|
356
|
+
Lists all brands accessible by your API key.
|
|
357
|
+
|
|
358
|
+
**Returns:** `ApiResponse<BrandInfo[]>`
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
const response = await dinoconfig.discovery.listBrands();
|
|
362
|
+
response.data.forEach(brand => {
|
|
363
|
+
console.log(`${brand.name}: ${brand.configCount} configs`);
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
#### `discovery.listConfigs(brandName, options?)`
|
|
370
|
+
|
|
371
|
+
Lists all configurations for a specific brand.
|
|
372
|
+
|
|
373
|
+
**Returns:** `ApiResponse<ConfigInfo[]>`
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
const response = await dinoconfig.discovery.listConfigs('MyBrand');
|
|
377
|
+
response.data.forEach(config => {
|
|
378
|
+
console.log(`${config.name} (v${config.version}): ${config.keys.length} keys`);
|
|
379
|
+
});
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
#### `discovery.getSchema(brandName, configName, options?)`
|
|
385
|
+
|
|
386
|
+
Gets the schema/structure for a specific configuration.
|
|
387
|
+
|
|
388
|
+
**Returns:** `ApiResponse<ConfigSchema>`
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
const response = await dinoconfig.discovery.getSchema('MyBrand', 'FeatureFlags');
|
|
392
|
+
Object.entries(response.data.fields).forEach(([name, field]) => {
|
|
393
|
+
console.log(`${name}: ${field.type}${field.required ? ' (required)' : ''}`);
|
|
394
|
+
});
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
#### `discovery.introspect(options?)`
|
|
400
|
+
|
|
401
|
+
Performs full introspection, returning all brands, configs, and values.
|
|
402
|
+
|
|
403
|
+
**Returns:** `ApiResponse<IntrospectionResult>`
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
const response = await dinoconfig.discovery.introspect();
|
|
407
|
+
const { company, brands } = response.data;
|
|
408
|
+
|
|
409
|
+
console.log(`Company: ${company}`);
|
|
410
|
+
brands.forEach(brand => {
|
|
411
|
+
console.log(`\nBrand: ${brand.name}`);
|
|
412
|
+
brand.configs.forEach(config => {
|
|
413
|
+
console.log(` Config: ${config.name} (${config.keys.length} keys)`);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
### Request Options
|
|
421
|
+
|
|
422
|
+
All API methods accept an optional `RequestOptions` object:
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
interface RequestOptions {
|
|
426
|
+
/** Custom headers for this specific request */
|
|
427
|
+
headers?: Record<string, string>;
|
|
428
|
+
/** Request timeout in milliseconds (overrides default) */
|
|
429
|
+
timeout?: number;
|
|
430
|
+
/** Number of retry attempts for failed requests */
|
|
431
|
+
retries?: number;
|
|
432
|
+
/** Whether to use cache (default: true when cache is enabled) */
|
|
433
|
+
cache?: boolean;
|
|
434
|
+
/** Force refresh from API, bypassing cache */
|
|
435
|
+
forceRefresh?: boolean;
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Example with options:**
|
|
440
|
+
```typescript
|
|
441
|
+
const response = await dinoconfig.configs.getValue(
|
|
442
|
+
'MyBrand',
|
|
443
|
+
'Settings',
|
|
444
|
+
'apiEndpoint',
|
|
445
|
+
{
|
|
446
|
+
timeout: 5000,
|
|
447
|
+
retries: 3,
|
|
448
|
+
cache: true, // Use cache (default)
|
|
449
|
+
forceRefresh: false, // Don't bypass cache
|
|
450
|
+
headers: {
|
|
451
|
+
'X-Request-ID': 'unique-request-id'
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Code Generation
|
|
458
|
+
|
|
459
|
+
Generate TypeScript types from your DinoConfig schemas using the [@dinoconfig/cli](https://www.npmjs.com/package/@dinoconfig/cli) package:
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
# Install CLI
|
|
463
|
+
npm install -g @dinoconfig/cli
|
|
464
|
+
|
|
465
|
+
# Generate types
|
|
466
|
+
npx @dinoconfig/cli codegen --api-key=dino_xxx --output=./src/types/dinoconfig.d.ts
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Usage with Generated Types
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
import { dinoconfigApi } from '@dinoconfig/js-sdk';
|
|
473
|
+
import { DinoConfig } from './types/dinoconfig';
|
|
474
|
+
|
|
475
|
+
const dinoconfig = await dinoconfigApi({
|
|
476
|
+
apiKey: process.env.DINOCONFIG_API_KEY!
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
// Full type safety with generics
|
|
480
|
+
const flags = await dinoconfig.configs.get<DinoConfig.MyBrand.FeatureFlags>(
|
|
481
|
+
'MyBrand',
|
|
482
|
+
'FeatureFlags'
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
// TypeScript knows the exact types!
|
|
486
|
+
flags.data.values.enableDarkMode; // boolean ✓
|
|
487
|
+
flags.data.values.maxUploadSize; // number ✓
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
For full documentation, see [@dinoconfig/cli](https://www.npmjs.com/package/@dinoconfig/cli).
|
|
491
|
+
## Error Handling
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
try {
|
|
495
|
+
const response = await dinoconfig.configs.getValue('Brand.Config.Key');
|
|
496
|
+
console.log('Value:', response.data);
|
|
497
|
+
} catch (error) {
|
|
498
|
+
if (error instanceof Error) {
|
|
499
|
+
console.error('Error:', error.message);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Common Error Scenarios
|
|
505
|
+
|
|
506
|
+
| Status | Meaning | Suggested Action |
|
|
507
|
+
|--------|---------|------------------|
|
|
508
|
+
| 401 | Unauthorized | Check API key validity |
|
|
509
|
+
| 403 | Forbidden | Verify permissions |
|
|
510
|
+
| 404 | Not Found | Check brand/config/key names |
|
|
511
|
+
| 429 | Rate Limited | Implement backoff |
|
|
512
|
+
| 500 | Server Error | Retry with backoff |
|
|
513
|
+
|
|
514
|
+
## TypeScript Support
|
|
515
|
+
|
|
516
|
+
### Exported Types
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
import {
|
|
520
|
+
// Main SDK
|
|
521
|
+
dinoconfigApi,
|
|
522
|
+
DinoConfigInstance,
|
|
523
|
+
DinoConfigSDKConfig,
|
|
524
|
+
ApiResponse,
|
|
525
|
+
RequestOptions,
|
|
526
|
+
|
|
527
|
+
// APIs
|
|
528
|
+
ConfigAPI,
|
|
529
|
+
DiscoveryAPI,
|
|
530
|
+
CacheAPI,
|
|
531
|
+
|
|
532
|
+
// Config types
|
|
533
|
+
ConfigData,
|
|
534
|
+
|
|
535
|
+
// Discovery types
|
|
536
|
+
BrandInfo,
|
|
537
|
+
ConfigInfo,
|
|
538
|
+
ConfigSchema,
|
|
539
|
+
FieldSchema,
|
|
540
|
+
FieldType,
|
|
541
|
+
FieldValidation,
|
|
542
|
+
IntrospectionResult,
|
|
543
|
+
BrandInfoDetail,
|
|
544
|
+
ConfigInfoDetail,
|
|
545
|
+
KeyInfo,
|
|
546
|
+
|
|
547
|
+
// Cache types
|
|
548
|
+
CacheConfig,
|
|
549
|
+
CacheStats
|
|
550
|
+
} from '@dinoconfig/js-sdk';
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Key Interfaces
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
/** SDK configuration options */
|
|
557
|
+
interface DinoConfigSDKConfig {
|
|
558
|
+
/** The API key for authentication */
|
|
559
|
+
apiKey: string;
|
|
560
|
+
/** The base URL of the DinoConfig API */
|
|
561
|
+
baseUrl?: string;
|
|
562
|
+
/** Request timeout in milliseconds */
|
|
563
|
+
timeout?: number;
|
|
564
|
+
/** Cache configuration options */
|
|
565
|
+
cache?: Partial<CacheConfig>;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** SDK instance returned by dinoconfigApi() */
|
|
569
|
+
interface DinoConfigInstance {
|
|
570
|
+
/** Configuration API for retrieving config values */
|
|
571
|
+
configs: ConfigAPI;
|
|
572
|
+
/** Discovery API for exploring available brands, configs, and schemas */
|
|
573
|
+
discovery: DiscoveryAPI;
|
|
574
|
+
/** Cache API for managing the cache layer */
|
|
575
|
+
cache: CacheAPI;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/** Full config data */
|
|
579
|
+
interface ConfigData {
|
|
580
|
+
readonly name: string;
|
|
581
|
+
readonly description?: string;
|
|
582
|
+
readonly values: Record<string, unknown>;
|
|
583
|
+
readonly version: number;
|
|
584
|
+
readonly keys: readonly string[];
|
|
585
|
+
readonly createdAt: Date;
|
|
586
|
+
readonly updatedAt?: Date;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/** API response wrapper */
|
|
590
|
+
interface ApiResponse<T> {
|
|
591
|
+
data: T;
|
|
592
|
+
success: boolean;
|
|
593
|
+
message?: string;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** Request customization options */
|
|
597
|
+
interface RequestOptions {
|
|
598
|
+
/** Custom headers */
|
|
599
|
+
headers?: Record<string, string>;
|
|
600
|
+
/** Request timeout in milliseconds */
|
|
601
|
+
timeout?: number;
|
|
602
|
+
/** Number of retry attempts */
|
|
603
|
+
retries?: number;
|
|
604
|
+
/** Whether to use cache (default: true when cache is enabled) */
|
|
605
|
+
cache?: boolean;
|
|
606
|
+
/** Force refresh from API, bypassing cache */
|
|
607
|
+
forceRefresh?: boolean;
|
|
608
|
+
}
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
## Examples
|
|
612
|
+
|
|
613
|
+
### Basic Usage
|
|
614
|
+
|
|
615
|
+
```typescript
|
|
616
|
+
import { dinoconfigApi } from '@dinoconfig/js-sdk';
|
|
617
|
+
|
|
618
|
+
const dinoconfig = await dinoconfigApi({
|
|
619
|
+
apiKey: process.env.DINOCONFIG_API_KEY!
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
// Get entire config
|
|
623
|
+
const config = await dinoconfig.configs.get('Brand.Config');
|
|
624
|
+
console.log(config.data.values);
|
|
625
|
+
|
|
626
|
+
// Get single value
|
|
627
|
+
const value = await dinoconfig.configs.getValue('Brand.Config.Key');
|
|
628
|
+
console.log(value.data);
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Express.js Integration
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import express from 'express';
|
|
635
|
+
import { dinoconfigApi, DinoConfigInstance } from '@dinoconfig/js-sdk';
|
|
636
|
+
|
|
637
|
+
let dinoconfig: DinoConfigInstance;
|
|
638
|
+
|
|
639
|
+
async function initApp() {
|
|
640
|
+
dinoconfig = await dinoconfigApi({
|
|
641
|
+
apiKey: process.env.DINOCONFIG_API_KEY!
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
const app = express();
|
|
645
|
+
|
|
646
|
+
app.get('/config/:brand/:config/:key', async (req, res) => {
|
|
647
|
+
try {
|
|
648
|
+
const { brand, config, key } = req.params;
|
|
649
|
+
const response = await dinoconfig.configs.getValue(brand, config, key);
|
|
650
|
+
res.json(response.data);
|
|
651
|
+
} catch (error) {
|
|
652
|
+
res.status(500).json({ error: 'Failed to fetch config' });
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
app.listen(3000);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
initApp();
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Next.js API Route
|
|
663
|
+
|
|
664
|
+
```typescript
|
|
665
|
+
// app/api/config/[...path]/route.ts
|
|
666
|
+
import { dinoconfigApi } from '@dinoconfig/js-sdk';
|
|
667
|
+
import { NextResponse } from 'next/server';
|
|
668
|
+
|
|
669
|
+
export async function GET(
|
|
670
|
+
request: Request,
|
|
671
|
+
{ params }: { params: { path: string[] } }
|
|
672
|
+
) {
|
|
673
|
+
const [brand, config, key] = params.path;
|
|
674
|
+
|
|
675
|
+
const dinoconfig = await dinoconfigApi({
|
|
676
|
+
apiKey: process.env.DINOCONFIG_API_KEY!
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
const response = await dinoconfig.configs.getValue(brand, config, key);
|
|
680
|
+
return NextResponse.json(response.data);
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### With Caching
|
|
685
|
+
|
|
686
|
+
```typescript
|
|
687
|
+
// Initialize with cache enabled
|
|
688
|
+
const dinoconfig = await dinoconfigApi({
|
|
689
|
+
apiKey: process.env.DINOCONFIG_API_KEY!,
|
|
690
|
+
cache: {
|
|
691
|
+
enabled: true,
|
|
692
|
+
ttl: 60000, // 1 minute
|
|
693
|
+
storage: 'localStorage',
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
// First request - network call (~250ms)
|
|
698
|
+
const response1 = await dinoconfig.configs.getValue('MyBrand', 'Settings', 'apiUrl');
|
|
699
|
+
|
|
700
|
+
// Second request - cached (~1ms) ⚡
|
|
701
|
+
const response2 = await dinoconfig.configs.getValue('MyBrand', 'Settings', 'apiUrl');
|
|
702
|
+
|
|
703
|
+
// Force refresh when needed
|
|
704
|
+
const freshResponse = await dinoconfig.configs.getValue(
|
|
705
|
+
'MyBrand',
|
|
706
|
+
'Settings',
|
|
707
|
+
'apiUrl',
|
|
708
|
+
{ forceRefresh: true }
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
// Check cache performance
|
|
712
|
+
const stats = dinoconfig.cache.getStats();
|
|
713
|
+
console.log(`Cache hit rate: ${(stats.hitRate * 100).toFixed(1)}%`);
|
|
714
|
+
```
|
|
715
|
+
## Requirements
|
|
716
|
+
|
|
717
|
+
- **Node.js** >= 18.0.0 (for native `fetch` support)
|
|
718
|
+
- **TypeScript** >= 5.0.0 (for TypeScript projects)
|
|
719
|
+
|
|
720
|
+
## Contributing
|
|
721
|
+
|
|
722
|
+
```bash
|
|
723
|
+
# Clone and install
|
|
724
|
+
git clone https://github.com/dinoconfig/dinoconfig-js-sdk.git
|
|
725
|
+
npm install
|
|
726
|
+
|
|
727
|
+
# Build
|
|
728
|
+
npx nx build dinoconfig-js-sdk
|
|
729
|
+
|
|
730
|
+
# Test
|
|
731
|
+
npx nx test dinoconfig-js-sdk
|
|
732
|
+
|
|
733
|
+
# Lint
|
|
734
|
+
npx nx lint dinoconfig-js-sdk
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
## License
|
|
738
|
+
|
|
739
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
Made with ❤️ by the DinoConfig Team
|