@uvrn/api 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/TESTING_GUIDE.md +495 -0
- package/dist/config/loader.d.ts +10 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +52 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +17 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +10 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +67 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/routes/delta.d.ts +10 -0
- package/dist/routes/delta.d.ts.map +1 -0
- package/dist/routes/delta.js +97 -0
- package/dist/routes/delta.js.map +1 -0
- package/dist/routes/health.d.ts +10 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +56 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +130 -0
- package/dist/server.js.map +1 -0
- package/dist/types/api.d.ts +32 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +6 -0
- package/dist/types/api.js.map +1 -0
- package/jest.config.js +13 -0
- package/package.json +44 -0
- package/src/config/loader.ts +60 -0
- package/src/config/types.ts +18 -0
- package/src/index.ts +13 -0
- package/src/middleware/errorHandler.ts +69 -0
- package/src/routes/delta.ts +120 -0
- package/src/routes/health.ts +65 -0
- package/src/server.ts +139 -0
- package/src/types/api.ts +35 -0
- package/tsconfig.json +9 -0
package/TESTING_GUIDE.md
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
# Delta Engine API - Testing Guide
|
|
2
|
+
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
### 1. Start the Development Server
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd packages/uvrn-api
|
|
9
|
+
npm run dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**What to look for:**
|
|
13
|
+
- ✅ Server starts without errors
|
|
14
|
+
- ✅ You see log messages like:
|
|
15
|
+
```
|
|
16
|
+
🚀 Delta Engine API server running at http://0.0.0.0:3000
|
|
17
|
+
📊 Health check: http://0.0.0.0:3000/api/v1/health
|
|
18
|
+
📦 Environment: development
|
|
19
|
+
🔒 Rate limit: 100 requests per 1 minute
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Run Automated Tests
|
|
23
|
+
|
|
24
|
+
From the repository root:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
./test-api.sh
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This will test all 5 endpoints plus error scenarios.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Manual Testing
|
|
35
|
+
|
|
36
|
+
### Test 1: Health Check ✅
|
|
37
|
+
|
|
38
|
+
**Purpose:** Verify the server is running and the engine is available
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
curl http://localhost:3000/api/v1/health
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Expected Response (200 OK):**
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"status": "healthy",
|
|
48
|
+
"uptime": 12345,
|
|
49
|
+
"version": "1.0.0",
|
|
50
|
+
"engine": {
|
|
51
|
+
"available": true
|
|
52
|
+
},
|
|
53
|
+
"timestamp": "2026-01-15T14:55:00.000Z"
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**What to look for:**
|
|
58
|
+
- ✅ `status: "healthy"`
|
|
59
|
+
- ✅ `engine.available: true`
|
|
60
|
+
- ✅ HTTP status code `200`
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### Test 2: Version Information ✅
|
|
65
|
+
|
|
66
|
+
**Purpose:** Check API, engine, and protocol versions
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
curl http://localhost:3000/api/v1/version
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Expected Response (200 OK):**
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"apiVersion": "1.0.0",
|
|
76
|
+
"engineVersion": "1.0.0",
|
|
77
|
+
"protocolVersion": "1.0"
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**What to look for:**
|
|
82
|
+
- ✅ All version fields present
|
|
83
|
+
- ✅ HTTP status code `200`
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### Test 3: Validate Bundle Schema ✅
|
|
88
|
+
|
|
89
|
+
**Purpose:** Validate a bundle without executing it
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
curl -X POST http://localhost:3000/api/v1/delta/validate \
|
|
93
|
+
-H "Content-Type: application/json" \
|
|
94
|
+
-d '{
|
|
95
|
+
"bundleId": "test-bundle-001",
|
|
96
|
+
"claim": "Revenue reconciliation test",
|
|
97
|
+
"dataSpecs": [
|
|
98
|
+
{
|
|
99
|
+
"id": "spec-1",
|
|
100
|
+
"label": "Q4 Revenue Report",
|
|
101
|
+
"sourceKind": "report",
|
|
102
|
+
"originDocIds": ["doc-123"],
|
|
103
|
+
"metrics": [
|
|
104
|
+
{"key": "revenue", "value": 100000, "unit": "USD"}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"thresholdPct": 0.1
|
|
109
|
+
}'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Expected Response (200 OK):**
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"valid": true
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**What to look for:**
|
|
120
|
+
- ✅ `valid: true` for correct bundles
|
|
121
|
+
- ✅ HTTP status code `200`
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### Test 4: Run Engine on Bundle 🚀
|
|
126
|
+
|
|
127
|
+
**Purpose:** Execute the delta engine and get a receipt
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
curl -X POST http://localhost:3000/api/v1/delta/run \
|
|
131
|
+
-H "Content-Type: application/json" \
|
|
132
|
+
-d '{
|
|
133
|
+
"bundleId": "revenue-q4-2025",
|
|
134
|
+
"claim": "Q4 2025 revenue: $500K",
|
|
135
|
+
"dataSpecs": [
|
|
136
|
+
{
|
|
137
|
+
"id": "spec-1",
|
|
138
|
+
"label": "Accounting System",
|
|
139
|
+
"sourceKind": "report",
|
|
140
|
+
"originDocIds": ["acc-report-q4"],
|
|
141
|
+
"metrics": [
|
|
142
|
+
{"key": "revenue", "value": 500000, "unit": "USD"}
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"id": "spec-2",
|
|
147
|
+
"label": "Sales Database",
|
|
148
|
+
"sourceKind": "report",
|
|
149
|
+
"originDocIds": ["sales-db-q4"],
|
|
150
|
+
"metrics": [
|
|
151
|
+
{"key": "revenue", "value": 502000, "unit": "USD"}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
],
|
|
155
|
+
"thresholdPct": 0.05
|
|
156
|
+
}'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Expected Response (200 OK):**
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"bundleId": "revenue-q4-2025",
|
|
163
|
+
"deltaFinal": 0.004,
|
|
164
|
+
"sources": ["Accounting System", "Sales Database"],
|
|
165
|
+
"rounds": [
|
|
166
|
+
{
|
|
167
|
+
"round": 1,
|
|
168
|
+
"deltasByMetric": {"revenue": 0.004},
|
|
169
|
+
"withinThreshold": true,
|
|
170
|
+
"witnessRequired": false
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"suggestedFixes": [],
|
|
174
|
+
"outcome": "consensus",
|
|
175
|
+
"hash": "abc123..."
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**What to look for:**
|
|
180
|
+
- ✅ Receipt contains all fields: `bundleId`, `deltaFinal`, `sources`, `rounds`, `outcome`, `hash`
|
|
181
|
+
- ✅ `outcome` is either `"consensus"` or `"indeterminate"`
|
|
182
|
+
- ✅ `hash` is a SHA-256 hash string
|
|
183
|
+
- ✅ HTTP status code `200`
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### Test 5: Verify Receipt 🔐
|
|
188
|
+
|
|
189
|
+
**Purpose:** Verify receipt integrity by recomputing the hash
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
curl -X POST http://localhost:3000/api/v1/delta/verify \
|
|
193
|
+
-H "Content-Type: application/json" \
|
|
194
|
+
-d '{
|
|
195
|
+
"bundleId": "test-001",
|
|
196
|
+
"deltaFinal": 0.02,
|
|
197
|
+
"sources": ["Source A", "Source B"],
|
|
198
|
+
"rounds": [
|
|
199
|
+
{
|
|
200
|
+
"round": 1,
|
|
201
|
+
"deltasByMetric": {"metric1": 0.02},
|
|
202
|
+
"withinThreshold": true,
|
|
203
|
+
"witnessRequired": false
|
|
204
|
+
}
|
|
205
|
+
],
|
|
206
|
+
"suggestedFixes": [],
|
|
207
|
+
"outcome": "consensus",
|
|
208
|
+
"hash": "abc123def456..."
|
|
209
|
+
}'
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Expected Response (200 OK):**
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"verified": true,
|
|
216
|
+
"recomputedHash": "abc123def456..."
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**What to look for:**
|
|
221
|
+
- ✅ `verified: true` if hash matches
|
|
222
|
+
- ✅ `verified: false` if hash doesn't match
|
|
223
|
+
- ✅ `recomputedHash` is provided
|
|
224
|
+
- ✅ HTTP status code `200`
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Error Scenario Testing
|
|
229
|
+
|
|
230
|
+
### Test 6: Invalid Bundle Schema ❌
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
curl -X POST http://localhost:3000/api/v1/delta/validate \
|
|
234
|
+
-H "Content-Type: application/json" \
|
|
235
|
+
-d '{
|
|
236
|
+
"bundleId": "incomplete",
|
|
237
|
+
"claim": "Missing dataSpecs field"
|
|
238
|
+
}'
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Expected Response (200 OK with validation errors):**
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"valid": false,
|
|
245
|
+
"errors": [
|
|
246
|
+
{
|
|
247
|
+
"field": "bundle",
|
|
248
|
+
"message": "Missing required field: dataSpecs"
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**What to look for:**
|
|
255
|
+
- ✅ `valid: false`
|
|
256
|
+
- ✅ `errors` array with details
|
|
257
|
+
- ✅ HTTP status code `200` (validation succeeded, bundle failed)
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### Test 7: Wrong Content-Type ❌
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
curl -X POST http://localhost:3000/api/v1/delta/run \
|
|
265
|
+
-H "Content-Type: text/plain" \
|
|
266
|
+
-d 'not json'
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Expected Response (415 Unsupported Media Type):**
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"error": {
|
|
273
|
+
"code": "UNSUPPORTED_MEDIA_TYPE",
|
|
274
|
+
"message": "Content-Type must be application/json",
|
|
275
|
+
"details": {
|
|
276
|
+
"receivedContentType": "text/plain"
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**What to look for:**
|
|
283
|
+
- ✅ HTTP status code `415`
|
|
284
|
+
- ✅ Error message explains the issue
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
### Test 8: Malformed JSON ❌
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
curl -X POST http://localhost:3000/api/v1/delta/run \
|
|
292
|
+
-H "Content-Type: application/json" \
|
|
293
|
+
-d '{invalid json'
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Expected Response (400 Bad Request):**
|
|
297
|
+
```json
|
|
298
|
+
{
|
|
299
|
+
"error": {
|
|
300
|
+
"code": "BAD_REQUEST",
|
|
301
|
+
"message": "Invalid JSON",
|
|
302
|
+
"details": {...}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**What to look for:**
|
|
308
|
+
- ✅ HTTP status code `400`
|
|
309
|
+
- ✅ Clear error message
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
### Test 9: Rate Limiting 🚦
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
# Run this in a loop to exceed rate limit
|
|
317
|
+
for i in {1..105}; do
|
|
318
|
+
curl -s http://localhost:3000/api/v1/health > /dev/null
|
|
319
|
+
done
|
|
320
|
+
curl http://localhost:3000/api/v1/health
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Expected Response (429 Too Many Requests):**
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"error": {
|
|
327
|
+
"code": "RATE_LIMIT_EXCEEDED",
|
|
328
|
+
"message": "Too many requests, please try again later",
|
|
329
|
+
"details": {
|
|
330
|
+
"rateLimitMax": 100,
|
|
331
|
+
"timeWindow": "1 minute"
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**What to look for:**
|
|
338
|
+
- ✅ HTTP status code `429`
|
|
339
|
+
- ✅ Rate limit details in response
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
### Test 10: 404 Not Found ❌
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
curl http://localhost:3000/api/v1/nonexistent
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Expected Response (404 Not Found):**
|
|
350
|
+
```json
|
|
351
|
+
{
|
|
352
|
+
"error": {
|
|
353
|
+
"code": "NOT_FOUND",
|
|
354
|
+
"message": "Route GET /api/v1/nonexistent not found",
|
|
355
|
+
"details": {
|
|
356
|
+
"method": "GET",
|
|
357
|
+
"url": "/api/v1/nonexistent"
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**What to look for:**
|
|
364
|
+
- ✅ HTTP status code `404`
|
|
365
|
+
- ✅ Clear error message with URL
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Testing with Real Bundles
|
|
370
|
+
|
|
371
|
+
You can test with existing demo bundles from the CLI:
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
# Find demo bundles
|
|
375
|
+
ls ../../examples/*.json
|
|
376
|
+
|
|
377
|
+
# Test with a real bundle
|
|
378
|
+
curl -X POST http://localhost:3000/api/v1/delta/run \
|
|
379
|
+
-H "Content-Type: application/json" \
|
|
380
|
+
-d @../../examples/revenue-bundle.json
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Server Logs
|
|
386
|
+
|
|
387
|
+
When running in development mode (`npm run dev`), you'll see detailed logs:
|
|
388
|
+
|
|
389
|
+
**Good logs to look for:**
|
|
390
|
+
```
|
|
391
|
+
[INFO] Incoming request - GET /api/v1/health
|
|
392
|
+
[INFO] Request completed - Status: 200, Time: 5ms
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Error logs:**
|
|
396
|
+
```
|
|
397
|
+
[ERROR] Engine execution failed - Invalid bundle structure
|
|
398
|
+
[WARN] Rate limit exceeded for IP 127.0.0.1
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Checklist: Server is Working ✅
|
|
404
|
+
|
|
405
|
+
After running all tests, verify:
|
|
406
|
+
|
|
407
|
+
- [ ] Health endpoint returns `healthy` status
|
|
408
|
+
- [ ] Version endpoint returns correct versions
|
|
409
|
+
- [ ] Validate endpoint accepts valid bundles
|
|
410
|
+
- [ ] Validate endpoint rejects invalid bundles
|
|
411
|
+
- [ ] Run endpoint executes engine and returns receipt
|
|
412
|
+
- [ ] Verify endpoint checks receipt integrity
|
|
413
|
+
- [ ] Rate limiting kicks in after 100 requests
|
|
414
|
+
- [ ] Wrong content-type returns 415 error
|
|
415
|
+
- [ ] Malformed JSON returns 400 error
|
|
416
|
+
- [ ] Non-existent routes return 404 error
|
|
417
|
+
- [ ] All responses have correct error structure
|
|
418
|
+
- [ ] Server logs requests and responses
|
|
419
|
+
- [ ] No crashes or unhandled exceptions
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Performance Testing
|
|
424
|
+
|
|
425
|
+
To test performance and concurrent requests:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
# Install autocannon if not already installed
|
|
429
|
+
npm install -g autocannon
|
|
430
|
+
|
|
431
|
+
# Run load test (100 requests, 10 concurrent)
|
|
432
|
+
autocannon -c 10 -d 10 http://localhost:3000/api/v1/health
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**What to look for:**
|
|
436
|
+
- ✅ Response times < 100ms for health endpoint
|
|
437
|
+
- ✅ No 5xx errors under load
|
|
438
|
+
- ✅ Rate limiting works correctly
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Troubleshooting
|
|
443
|
+
|
|
444
|
+
### Server won't start
|
|
445
|
+
|
|
446
|
+
1. Check if port 3000 is already in use:
|
|
447
|
+
```bash
|
|
448
|
+
lsof -i :3000
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
2. Use a different port:
|
|
452
|
+
```bash
|
|
453
|
+
PORT=3001 npm run dev
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Engine not available
|
|
457
|
+
|
|
458
|
+
If health check shows `engine.available: false`:
|
|
459
|
+
|
|
460
|
+
1. Ensure `@uvrn/core` is installed:
|
|
461
|
+
```bash
|
|
462
|
+
npm list @uvrn/core
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
2. Build the engine package:
|
|
466
|
+
```bash
|
|
467
|
+
cd ../uvrn-core && npm run build
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### CORS errors (in browser)
|
|
471
|
+
|
|
472
|
+
If testing from a browser and seeing CORS errors:
|
|
473
|
+
|
|
474
|
+
1. Set allowed origins in `.env`:
|
|
475
|
+
```
|
|
476
|
+
CORS_ORIGINS=http://localhost:3000,http://localhost:8080
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
2. Restart the server
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Next Steps
|
|
484
|
+
|
|
485
|
+
Once all tests pass:
|
|
486
|
+
1. ✅ Proceed to Task A.2.3 (OpenAPI Specification)
|
|
487
|
+
2. ✅ Add integration tests with Jest
|
|
488
|
+
3. ✅ Deploy to staging environment
|
|
489
|
+
4. ✅ Run load tests with realistic traffic
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
**Created:** 2026-01-15
|
|
494
|
+
**API Version:** 1.0.0
|
|
495
|
+
**Last Updated:** 2026-01-15
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Loader
|
|
3
|
+
* Loads and validates server configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
import { ServerConfig } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Load configuration from environment variables with defaults
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadConfig(): ServerConfig;
|
|
10
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAyB,MAAM,SAAS,CAAC;AAE9D;;GAEG;AACH,wBAAgB,UAAU,IAAI,YAAY,CAkBzC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration Loader
|
|
4
|
+
* Loads and validates server configuration from environment variables
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.loadConfig = loadConfig;
|
|
8
|
+
/**
|
|
9
|
+
* Load configuration from environment variables with defaults
|
|
10
|
+
*/
|
|
11
|
+
function loadConfig() {
|
|
12
|
+
const config = {
|
|
13
|
+
port: parseInt(process.env.PORT || '3000', 10),
|
|
14
|
+
host: process.env.HOST || '0.0.0.0',
|
|
15
|
+
corsOrigins: process.env.CORS_ORIGINS?.split(',').map(o => o.trim()) || ['*'],
|
|
16
|
+
rateLimitMax: parseInt(process.env.RATE_LIMIT_MAX || '100', 10),
|
|
17
|
+
rateLimitTimeWindow: process.env.RATE_LIMIT_TIME_WINDOW || '1 minute',
|
|
18
|
+
logLevel: process.env.LOG_LEVEL || 'info',
|
|
19
|
+
nodeEnv: process.env.NODE_ENV || 'development'
|
|
20
|
+
};
|
|
21
|
+
const errors = validateConfig(config);
|
|
22
|
+
if (errors.length > 0) {
|
|
23
|
+
const errorMessages = errors.map(e => `${e.field}: ${e.message}`).join(', ');
|
|
24
|
+
throw new Error(`Configuration validation failed: ${errorMessages}`);
|
|
25
|
+
}
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate configuration values
|
|
30
|
+
*/
|
|
31
|
+
function validateConfig(config) {
|
|
32
|
+
const errors = [];
|
|
33
|
+
if (config.port < 1 || config.port > 65535) {
|
|
34
|
+
errors.push({ field: 'port', message: 'Must be between 1 and 65535' });
|
|
35
|
+
}
|
|
36
|
+
if (!config.host) {
|
|
37
|
+
errors.push({ field: 'host', message: 'Host cannot be empty' });
|
|
38
|
+
}
|
|
39
|
+
if (config.rateLimitMax < 1) {
|
|
40
|
+
errors.push({ field: 'rateLimitMax', message: 'Must be at least 1' });
|
|
41
|
+
}
|
|
42
|
+
const validLogLevels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
|
|
43
|
+
if (!validLogLevels.includes(config.logLevel)) {
|
|
44
|
+
errors.push({ field: 'logLevel', message: `Must be one of: ${validLogLevels.join(', ')}` });
|
|
45
|
+
}
|
|
46
|
+
const validNodeEnvs = ['development', 'production', 'test'];
|
|
47
|
+
if (!validNodeEnvs.includes(config.nodeEnv)) {
|
|
48
|
+
errors.push({ field: 'nodeEnv', message: `Must be one of: ${validNodeEnvs.join(', ')}` });
|
|
49
|
+
}
|
|
50
|
+
return errors;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAOH,gCAkBC;AArBD;;GAEG;AACH,SAAgB,UAAU;IACxB,MAAM,MAAM,GAAiB;QAC3B,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC;QAC9C,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,SAAS;QACnC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;QAC7E,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,KAAK,EAAE,EAAE,CAAC;QAC/D,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,UAAU;QACrE,QAAQ,EAAG,OAAO,CAAC,GAAG,CAAC,SAAsC,IAAI,MAAM;QACvE,OAAO,EAAG,OAAO,CAAC,GAAG,CAAC,QAAoC,IAAI,aAAa;KAC5E,CAAC;IAEF,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7E,MAAM,IAAI,KAAK,CAAC,oCAAoC,aAAa,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,MAAoB;IAC1C,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5E,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,aAAa,GAAG,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAC5D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Configuration Types
|
|
3
|
+
*/
|
|
4
|
+
export interface ServerConfig {
|
|
5
|
+
port: number;
|
|
6
|
+
host: string;
|
|
7
|
+
corsOrigins: string[];
|
|
8
|
+
rateLimitMax: number;
|
|
9
|
+
rateLimitTimeWindow: string;
|
|
10
|
+
logLevel: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
11
|
+
nodeEnv: 'development' | 'production' | 'test';
|
|
12
|
+
}
|
|
13
|
+
export interface ConfigValidationError {
|
|
14
|
+
field: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAClE,OAAO,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":";AAAA;;GAEG"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delta Engine API - Entry Point
|
|
3
|
+
* Exports for programmatic usage
|
|
4
|
+
*/
|
|
5
|
+
export { startServer, createServer } from './server';
|
|
6
|
+
export type { ServerConfig } from './config/types';
|
|
7
|
+
export type { ErrorResponse, HealthResponse, VersionResponse, ValidationResponse } from './types/api';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EACV,aAAa,EACb,cAAc,EACd,eAAe,EACf,kBAAkB,EACnB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Delta Engine API - Entry Point
|
|
4
|
+
* Exports for programmatic usage
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createServer = exports.startServer = void 0;
|
|
8
|
+
var server_1 = require("./server");
|
|
9
|
+
Object.defineProperty(exports, "startServer", { enumerable: true, get: function () { return server_1.startServer; } });
|
|
10
|
+
Object.defineProperty(exports, "createServer", { enumerable: true, get: function () { return server_1.createServer; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,mCAAqD;AAA5C,qGAAA,WAAW,OAAA;AAAE,sGAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Error Handler
|
|
3
|
+
* Handles uncaught errors and formats error responses
|
|
4
|
+
*/
|
|
5
|
+
import { FastifyInstance } from 'fastify';
|
|
6
|
+
/**
|
|
7
|
+
* Register global error handler
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerErrorHandler(server: FastifyInstance): void;
|
|
10
|
+
//# sourceMappingURL=errorHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/middleware/errorHandler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAA8C,MAAM,SAAS,CAAC;AAGtF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAyDlE"}
|