@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
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Global Error Handler
|
|
4
|
+
* Handles uncaught errors and formats error responses
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.registerErrorHandler = registerErrorHandler;
|
|
8
|
+
/**
|
|
9
|
+
* Register global error handler
|
|
10
|
+
*/
|
|
11
|
+
function registerErrorHandler(server) {
|
|
12
|
+
server.setErrorHandler((error, request, reply) => {
|
|
13
|
+
// Log the error
|
|
14
|
+
request.log.error({
|
|
15
|
+
err: error,
|
|
16
|
+
url: request.url,
|
|
17
|
+
method: request.method
|
|
18
|
+
}, 'Request error');
|
|
19
|
+
// Determine status code
|
|
20
|
+
const statusCode = error.statusCode || 500;
|
|
21
|
+
// Map error to code
|
|
22
|
+
let errorCode = 'INTERNAL_ERROR';
|
|
23
|
+
if (statusCode === 400)
|
|
24
|
+
errorCode = 'BAD_REQUEST';
|
|
25
|
+
else if (statusCode === 404)
|
|
26
|
+
errorCode = 'NOT_FOUND';
|
|
27
|
+
else if (statusCode === 415)
|
|
28
|
+
errorCode = 'UNSUPPORTED_MEDIA_TYPE';
|
|
29
|
+
else if (statusCode === 429)
|
|
30
|
+
errorCode = 'RATE_LIMIT_EXCEEDED';
|
|
31
|
+
else if (statusCode === 503)
|
|
32
|
+
errorCode = 'SERVICE_UNAVAILABLE';
|
|
33
|
+
// Build error response
|
|
34
|
+
const errorResponse = {
|
|
35
|
+
error: {
|
|
36
|
+
code: errorCode,
|
|
37
|
+
message: error.message || 'An unexpected error occurred',
|
|
38
|
+
details: {
|
|
39
|
+
statusCode
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
// Don't expose internal error details in production
|
|
44
|
+
if (process.env.NODE_ENV !== 'production' && error.stack) {
|
|
45
|
+
errorResponse.error.details = {
|
|
46
|
+
...errorResponse.error.details,
|
|
47
|
+
stack: error.stack
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
reply.code(statusCode).send(errorResponse);
|
|
51
|
+
});
|
|
52
|
+
// Handle 404 errors
|
|
53
|
+
server.setNotFoundHandler((request, reply) => {
|
|
54
|
+
const errorResponse = {
|
|
55
|
+
error: {
|
|
56
|
+
code: 'NOT_FOUND',
|
|
57
|
+
message: `Route ${request.method} ${request.url} not found`,
|
|
58
|
+
details: {
|
|
59
|
+
method: request.method,
|
|
60
|
+
url: request.url
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
reply.code(404).send(errorResponse);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=errorHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/middleware/errorHandler.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAQH,oDAyDC;AA5DD;;GAEG;AACH,SAAgB,oBAAoB,CAAC,MAAuB;IAC1D,MAAM,CAAC,eAAe,CAAC,CAAC,KAAmB,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;QAC3F,gBAAgB;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAChB,GAAG,EAAE,KAAK;YACV,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,EAAE,eAAe,CAAC,CAAC;QAEpB,wBAAwB;QACxB,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,GAAG,CAAC;QAE3C,oBAAoB;QACpB,IAAI,SAAS,GAAG,gBAAgB,CAAC;QACjC,IAAI,UAAU,KAAK,GAAG;YAAE,SAAS,GAAG,aAAa,CAAC;aAC7C,IAAI,UAAU,KAAK,GAAG;YAAE,SAAS,GAAG,WAAW,CAAC;aAChD,IAAI,UAAU,KAAK,GAAG;YAAE,SAAS,GAAG,wBAAwB,CAAC;aAC7D,IAAI,UAAU,KAAK,GAAG;YAAE,SAAS,GAAG,qBAAqB,CAAC;aAC1D,IAAI,UAAU,KAAK,GAAG;YAAE,SAAS,GAAG,qBAAqB,CAAC;QAE/D,uBAAuB;QACvB,MAAM,aAAa,GAAkB;YACnC,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,8BAA8B;gBACxD,OAAO,EAAE;oBACP,UAAU;iBACX;aACF;SACF,CAAC;QAEF,oDAAoD;QACpD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACzD,aAAa,CAAC,KAAK,CAAC,OAAO,GAAG;gBAC5B,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO;gBAC9B,KAAK,EAAE,KAAK,CAAC,KAAK;aACnB,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,CAAC,kBAAkB,CAAC,CAAC,OAAuB,EAAE,KAAmB,EAAE,EAAE;QACzE,MAAM,aAAa,GAAkB;YACnC,KAAK,EAAE;gBACL,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,SAAS,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,YAAY;gBAC3D,OAAO,EAAE;oBACP,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,GAAG,EAAE,OAAO,CAAC,GAAG;iBACjB;aACF;SACF,CAAC;QAEF,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delta Engine API Routes
|
|
3
|
+
* Endpoints for bundle processing, validation, and verification
|
|
4
|
+
*/
|
|
5
|
+
import { FastifyInstance } from 'fastify';
|
|
6
|
+
/**
|
|
7
|
+
* Register delta engine routes
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerDeltaRoutes(server: FastifyInstance): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=delta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.d.ts","sourceRoot":"","sources":["../../src/routes/delta.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAUxE;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqGhF"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Delta Engine API Routes
|
|
4
|
+
* Endpoints for bundle processing, validation, and verification
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.registerDeltaRoutes = registerDeltaRoutes;
|
|
8
|
+
const core_1 = require("@uvrn/core");
|
|
9
|
+
/**
|
|
10
|
+
* Register delta engine routes
|
|
11
|
+
*/
|
|
12
|
+
async function registerDeltaRoutes(server) {
|
|
13
|
+
// POST /api/v1/delta/run - Execute engine on bundle
|
|
14
|
+
server.post('/api/v1/delta/run', async (request, reply) => {
|
|
15
|
+
try {
|
|
16
|
+
const bundle = request.body;
|
|
17
|
+
// Validate bundle schema
|
|
18
|
+
const validation = (0, core_1.validateBundle)(bundle);
|
|
19
|
+
if (!validation.valid) {
|
|
20
|
+
return reply.code(400).send({
|
|
21
|
+
error: {
|
|
22
|
+
code: 'INVALID_BUNDLE',
|
|
23
|
+
message: 'Bundle validation failed',
|
|
24
|
+
details: { validationError: validation.error }
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// Execute engine
|
|
29
|
+
const receipt = (0, core_1.runDeltaEngine)(bundle);
|
|
30
|
+
return reply.code(200).send(receipt);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
34
|
+
request.log.error({ error: errorMessage }, 'Engine execution failed');
|
|
35
|
+
return reply.code(500).send({
|
|
36
|
+
error: {
|
|
37
|
+
code: 'ENGINE_ERROR',
|
|
38
|
+
message: 'Failed to process bundle',
|
|
39
|
+
details: { error: errorMessage }
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// POST /api/v1/delta/validate - Validate bundle schema
|
|
45
|
+
server.post('/api/v1/delta/validate', async (request, reply) => {
|
|
46
|
+
try {
|
|
47
|
+
const bundle = request.body;
|
|
48
|
+
const validation = (0, core_1.validateBundle)(bundle);
|
|
49
|
+
if (!validation.valid) {
|
|
50
|
+
return reply.code(200).send({
|
|
51
|
+
valid: false,
|
|
52
|
+
errors: [
|
|
53
|
+
{
|
|
54
|
+
field: 'bundle',
|
|
55
|
+
message: validation.error || 'Validation failed'
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return reply.code(200).send({ valid: true });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
64
|
+
request.log.error({ error: errorMessage }, 'Validation failed');
|
|
65
|
+
return reply.code(500).send({
|
|
66
|
+
error: {
|
|
67
|
+
code: 'VALIDATION_ERROR',
|
|
68
|
+
message: 'Failed to validate bundle',
|
|
69
|
+
details: { error: errorMessage }
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
// POST /api/v1/delta/verify - Verify receipt replay
|
|
75
|
+
server.post('/api/v1/delta/verify', async (request, reply) => {
|
|
76
|
+
try {
|
|
77
|
+
const receipt = request.body;
|
|
78
|
+
const verifyResult = (0, core_1.verifyReceipt)(receipt);
|
|
79
|
+
return reply.code(200).send({
|
|
80
|
+
verified: verifyResult.verified,
|
|
81
|
+
recomputedHash: verifyResult.recomputedHash
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
86
|
+
request.log.error({ error: errorMessage }, 'Verification failed');
|
|
87
|
+
return reply.code(500).send({
|
|
88
|
+
error: {
|
|
89
|
+
code: 'VERIFICATION_ERROR',
|
|
90
|
+
message: 'Failed to verify receipt',
|
|
91
|
+
details: { error: errorMessage }
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=delta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.js","sourceRoot":"","sources":["../../src/routes/delta.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health and Version Routes
|
|
3
|
+
* System status and version information endpoints
|
|
4
|
+
*/
|
|
5
|
+
import { FastifyInstance } from 'fastify';
|
|
6
|
+
/**
|
|
7
|
+
* Register health and version routes
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerHealthRoutes(server: FastifyInstance): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAOxE;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDjF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Health and Version Routes
|
|
4
|
+
* System status and version information endpoints
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.registerHealthRoutes = registerHealthRoutes;
|
|
8
|
+
const SERVER_START_TIME = Date.now();
|
|
9
|
+
const API_VERSION = '1.0.0';
|
|
10
|
+
const PROTOCOL_VERSION = '1.0';
|
|
11
|
+
/**
|
|
12
|
+
* Register health and version routes
|
|
13
|
+
*/
|
|
14
|
+
async function registerHealthRoutes(server) {
|
|
15
|
+
// GET /api/v1/health - Health check endpoint
|
|
16
|
+
server.get('/api/v1/health', async (_request, reply) => {
|
|
17
|
+
const uptime = Date.now() - SERVER_START_TIME;
|
|
18
|
+
// Check if engine is available by attempting to import it
|
|
19
|
+
let engineAvailable = true;
|
|
20
|
+
try {
|
|
21
|
+
require('@uvrn/core');
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
engineAvailable = false;
|
|
25
|
+
}
|
|
26
|
+
const health = {
|
|
27
|
+
status: engineAvailable ? 'healthy' : 'unhealthy',
|
|
28
|
+
uptime,
|
|
29
|
+
version: API_VERSION,
|
|
30
|
+
engine: {
|
|
31
|
+
available: engineAvailable
|
|
32
|
+
},
|
|
33
|
+
timestamp: new Date().toISOString()
|
|
34
|
+
};
|
|
35
|
+
const statusCode = engineAvailable ? 200 : 503;
|
|
36
|
+
return reply.code(statusCode).send(health);
|
|
37
|
+
});
|
|
38
|
+
// GET /api/v1/version - Version information
|
|
39
|
+
server.get('/api/v1/version', async (_request, reply) => {
|
|
40
|
+
let engineVersion = 'unknown';
|
|
41
|
+
try {
|
|
42
|
+
const enginePkg = require('@uvrn/core/package.json');
|
|
43
|
+
engineVersion = enginePkg.version;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Engine version not available
|
|
47
|
+
}
|
|
48
|
+
const version = {
|
|
49
|
+
apiVersion: API_VERSION,
|
|
50
|
+
engineVersion,
|
|
51
|
+
protocolVersion: PROTOCOL_VERSION
|
|
52
|
+
};
|
|
53
|
+
return reply.code(200).send(version);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAYH,oDAiDC;AAxDD,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACrC,MAAM,WAAW,GAAG,OAAO,CAAC;AAC5B,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;;GAEG;AACI,KAAK,UAAU,oBAAoB,CAAC,MAAuB;IAChE,6CAA6C;IAC7C,MAAM,CAAC,GAAG,CAEP,gBAAgB,EAAE,KAAK,EAAE,QAAwB,EAAE,KAAmB,EAAE,EAAE;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,iBAAiB,CAAC;QAE9C,0DAA0D;QAC1D,IAAI,eAAe,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,CAAC,YAAY,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,eAAe,GAAG,KAAK,CAAC;QAC1B,CAAC;QAED,MAAM,MAAM,GAAmB;YAC7B,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;YACjD,MAAM;YACN,OAAO,EAAE,WAAW;YACpB,MAAM,EAAE;gBACN,SAAS,EAAE,eAAe;aAC3B;YACD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,4CAA4C;IAC5C,MAAM,CAAC,GAAG,CAEP,iBAAiB,EAAE,KAAK,EAAE,QAAwB,EAAE,KAAmB,EAAE,EAAE;QAC5E,IAAI,aAAa,GAAG,SAAS,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;YACrD,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;QAED,MAAM,OAAO,GAAoB;YAC/B,UAAU,EAAE,WAAW;YACvB,aAAa;YACb,eAAe,EAAE,gBAAgB;SAClC,CAAC;QAEF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delta Engine API Server
|
|
3
|
+
* Fastify-based REST API for bundle processing
|
|
4
|
+
*/
|
|
5
|
+
import { FastifyInstance } from 'fastify';
|
|
6
|
+
import { ServerConfig } from './config/types';
|
|
7
|
+
/**
|
|
8
|
+
* Create and configure Fastify server instance
|
|
9
|
+
*/
|
|
10
|
+
export declare function createServer(config?: ServerConfig): Promise<FastifyInstance>;
|
|
11
|
+
/**
|
|
12
|
+
* Start the server
|
|
13
|
+
*/
|
|
14
|
+
export declare function startServer(config?: ServerConfig): Promise<FastifyInstance>;
|
|
15
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAKnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAuFlF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAoBjF"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Delta Engine API Server
|
|
4
|
+
* Fastify-based REST API for bundle processing
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createServer = createServer;
|
|
11
|
+
exports.startServer = startServer;
|
|
12
|
+
const fastify_1 = __importDefault(require("fastify"));
|
|
13
|
+
const cors_1 = __importDefault(require("@fastify/cors"));
|
|
14
|
+
const helmet_1 = __importDefault(require("@fastify/helmet"));
|
|
15
|
+
const rate_limit_1 = __importDefault(require("@fastify/rate-limit"));
|
|
16
|
+
const loader_1 = require("./config/loader");
|
|
17
|
+
const delta_1 = require("./routes/delta");
|
|
18
|
+
const health_1 = require("./routes/health");
|
|
19
|
+
const errorHandler_1 = require("./middleware/errorHandler");
|
|
20
|
+
/**
|
|
21
|
+
* Create and configure Fastify server instance
|
|
22
|
+
*/
|
|
23
|
+
async function createServer(config) {
|
|
24
|
+
// Load configuration
|
|
25
|
+
const serverConfig = config || (0, loader_1.loadConfig)();
|
|
26
|
+
// Create Fastify instance with logging
|
|
27
|
+
const server = (0, fastify_1.default)({
|
|
28
|
+
logger: {
|
|
29
|
+
level: serverConfig.logLevel,
|
|
30
|
+
transport: serverConfig.nodeEnv === 'development' ? {
|
|
31
|
+
target: 'pino-pretty',
|
|
32
|
+
options: {
|
|
33
|
+
translateTime: 'HH:MM:ss Z',
|
|
34
|
+
ignore: 'pid,hostname'
|
|
35
|
+
}
|
|
36
|
+
} : undefined
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// Register plugins
|
|
40
|
+
await server.register(helmet_1.default, {
|
|
41
|
+
contentSecurityPolicy: serverConfig.nodeEnv === 'production' ? undefined : false
|
|
42
|
+
});
|
|
43
|
+
await server.register(cors_1.default, {
|
|
44
|
+
origin: serverConfig.corsOrigins,
|
|
45
|
+
credentials: true
|
|
46
|
+
});
|
|
47
|
+
await server.register(rate_limit_1.default, {
|
|
48
|
+
max: serverConfig.rateLimitMax,
|
|
49
|
+
timeWindow: serverConfig.rateLimitTimeWindow,
|
|
50
|
+
errorResponseBuilder: () => ({
|
|
51
|
+
error: {
|
|
52
|
+
code: 'RATE_LIMIT_EXCEEDED',
|
|
53
|
+
message: 'Too many requests, please try again later',
|
|
54
|
+
details: {
|
|
55
|
+
rateLimitMax: serverConfig.rateLimitMax,
|
|
56
|
+
timeWindow: serverConfig.rateLimitTimeWindow
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
// Add request logging hook
|
|
62
|
+
server.addHook('onRequest', async (request, _reply) => {
|
|
63
|
+
request.log.info({
|
|
64
|
+
url: request.url,
|
|
65
|
+
method: request.method,
|
|
66
|
+
ip: request.ip
|
|
67
|
+
}, 'Incoming request');
|
|
68
|
+
});
|
|
69
|
+
server.addHook('onResponse', async (request, reply) => {
|
|
70
|
+
request.log.info({
|
|
71
|
+
url: request.url,
|
|
72
|
+
method: request.method,
|
|
73
|
+
statusCode: reply.statusCode,
|
|
74
|
+
responseTime: reply.elapsedTime
|
|
75
|
+
}, 'Request completed');
|
|
76
|
+
});
|
|
77
|
+
// Validate content-type for POST requests
|
|
78
|
+
server.addHook('preHandler', async (request, reply) => {
|
|
79
|
+
if (request.method === 'POST' && request.url.startsWith('/api/v1/delta/')) {
|
|
80
|
+
const contentType = request.headers['content-type'];
|
|
81
|
+
if (!contentType || !contentType.includes('application/json')) {
|
|
82
|
+
return reply.code(415).send({
|
|
83
|
+
error: {
|
|
84
|
+
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
85
|
+
message: 'Content-Type must be application/json',
|
|
86
|
+
details: {
|
|
87
|
+
receivedContentType: contentType || 'none'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// Register routes
|
|
95
|
+
await (0, health_1.registerHealthRoutes)(server);
|
|
96
|
+
await (0, delta_1.registerDeltaRoutes)(server);
|
|
97
|
+
// Register error handler (must be last)
|
|
98
|
+
(0, errorHandler_1.registerErrorHandler)(server);
|
|
99
|
+
return server;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Start the server
|
|
103
|
+
*/
|
|
104
|
+
async function startServer(config) {
|
|
105
|
+
const serverConfig = config || (0, loader_1.loadConfig)();
|
|
106
|
+
const server = await createServer(serverConfig);
|
|
107
|
+
try {
|
|
108
|
+
await server.listen({
|
|
109
|
+
port: serverConfig.port,
|
|
110
|
+
host: serverConfig.host
|
|
111
|
+
});
|
|
112
|
+
server.log.info(`🚀 Delta Engine API server running at http://${serverConfig.host}:${serverConfig.port}`);
|
|
113
|
+
server.log.info(`📊 Health check: http://${serverConfig.host}:${serverConfig.port}/api/v1/health`);
|
|
114
|
+
server.log.info(`📦 Environment: ${serverConfig.nodeEnv}`);
|
|
115
|
+
server.log.info(`🔒 Rate limit: ${serverConfig.rateLimitMax} requests per ${serverConfig.rateLimitTimeWindow}`);
|
|
116
|
+
return server;
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
server.log.error(error);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Start server if run directly
|
|
124
|
+
if (require.main === module) {
|
|
125
|
+
startServer().catch((error) => {
|
|
126
|
+
console.error('Failed to start server:', error);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API-specific type definitions
|
|
3
|
+
*/
|
|
4
|
+
export interface ErrorResponse {
|
|
5
|
+
error: {
|
|
6
|
+
code: string;
|
|
7
|
+
message: string;
|
|
8
|
+
details?: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface HealthResponse {
|
|
12
|
+
status: 'healthy' | 'unhealthy';
|
|
13
|
+
uptime: number;
|
|
14
|
+
version: string;
|
|
15
|
+
engine: {
|
|
16
|
+
available: boolean;
|
|
17
|
+
};
|
|
18
|
+
timestamp: string;
|
|
19
|
+
}
|
|
20
|
+
export interface VersionResponse {
|
|
21
|
+
apiVersion: string;
|
|
22
|
+
engineVersion: string;
|
|
23
|
+
protocolVersion: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ValidationResponse {
|
|
26
|
+
valid: boolean;
|
|
27
|
+
errors?: Array<{
|
|
28
|
+
field: string;
|
|
29
|
+
message: string;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QACN,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":";AAAA;;GAEG"}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
preset: 'ts-jest',
|
|
3
|
+
testEnvironment: 'node',
|
|
4
|
+
roots: ['<rootDir>/tests'],
|
|
5
|
+
testMatch: ['**/*.test.ts'],
|
|
6
|
+
collectCoverageFrom: [
|
|
7
|
+
'src/**/*.ts',
|
|
8
|
+
'!src/**/*.d.ts',
|
|
9
|
+
'!src/index.ts',
|
|
10
|
+
],
|
|
11
|
+
coverageDirectory: 'coverage',
|
|
12
|
+
coverageReporters: ['text', 'lcov', 'html'],
|
|
13
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uvrn/api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "UVRN REST API — HTTP access to bundle processing",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"uvrn",
|
|
9
|
+
"rest-api",
|
|
10
|
+
"bundle",
|
|
11
|
+
"protocol"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"fastify": "^4.25.0",
|
|
16
|
+
"@fastify/cors": "^8.5.0",
|
|
17
|
+
"@fastify/rate-limit": "^9.1.0",
|
|
18
|
+
"@fastify/helmet": "^11.1.0",
|
|
19
|
+
"@uvrn/core": "1.0.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^20.0.0",
|
|
23
|
+
"@types/jest": "^29.5.0",
|
|
24
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
25
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
26
|
+
"eslint": "^8.0.0",
|
|
27
|
+
"jest": "^29.5.0",
|
|
28
|
+
"pino-pretty": "^10.3.0",
|
|
29
|
+
"ts-jest": "^29.1.0",
|
|
30
|
+
"tsx": "^4.7.0",
|
|
31
|
+
"typescript": "^5.3.0"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"dev": "tsx watch src/server.ts",
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"start": "node dist/server.js",
|
|
40
|
+
"test": "jest",
|
|
41
|
+
"lint": "eslint src/**/*.ts",
|
|
42
|
+
"clean": "rm -rf dist"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Loader
|
|
3
|
+
* Loads and validates server configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ServerConfig, ConfigValidationError } from './types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Load configuration from environment variables with defaults
|
|
10
|
+
*/
|
|
11
|
+
export function loadConfig(): ServerConfig {
|
|
12
|
+
const config: ServerConfig = {
|
|
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 as ServerConfig['logLevel']) || 'info',
|
|
19
|
+
nodeEnv: (process.env.NODE_ENV as ServerConfig['nodeEnv']) || 'development'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const errors = validateConfig(config);
|
|
23
|
+
if (errors.length > 0) {
|
|
24
|
+
const errorMessages = errors.map(e => `${e.field}: ${e.message}`).join(', ');
|
|
25
|
+
throw new Error(`Configuration validation failed: ${errorMessages}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return config;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Validate configuration values
|
|
33
|
+
*/
|
|
34
|
+
function validateConfig(config: ServerConfig): ConfigValidationError[] {
|
|
35
|
+
const errors: ConfigValidationError[] = [];
|
|
36
|
+
|
|
37
|
+
if (config.port < 1 || config.port > 65535) {
|
|
38
|
+
errors.push({ field: 'port', message: 'Must be between 1 and 65535' });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!config.host) {
|
|
42
|
+
errors.push({ field: 'host', message: 'Host cannot be empty' });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (config.rateLimitMax < 1) {
|
|
46
|
+
errors.push({ field: 'rateLimitMax', message: 'Must be at least 1' });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const validLogLevels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
|
|
50
|
+
if (!validLogLevels.includes(config.logLevel)) {
|
|
51
|
+
errors.push({ field: 'logLevel', message: `Must be one of: ${validLogLevels.join(', ')}` });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const validNodeEnvs = ['development', 'production', 'test'];
|
|
55
|
+
if (!validNodeEnvs.includes(config.nodeEnv)) {
|
|
56
|
+
errors.push({ field: 'nodeEnv', message: `Must be one of: ${validNodeEnvs.join(', ')}` });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return errors;
|
|
60
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Configuration Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ServerConfig {
|
|
6
|
+
port: number;
|
|
7
|
+
host: string;
|
|
8
|
+
corsOrigins: string[];
|
|
9
|
+
rateLimitMax: number;
|
|
10
|
+
rateLimitTimeWindow: string;
|
|
11
|
+
logLevel: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
12
|
+
nodeEnv: 'development' | 'production' | 'test';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ConfigValidationError {
|
|
16
|
+
field: string;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delta Engine API - Entry Point
|
|
3
|
+
* Exports for programmatic usage
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { startServer, createServer } from './server';
|
|
7
|
+
export type { ServerConfig } from './config/types';
|
|
8
|
+
export type {
|
|
9
|
+
ErrorResponse,
|
|
10
|
+
HealthResponse,
|
|
11
|
+
VersionResponse,
|
|
12
|
+
ValidationResponse
|
|
13
|
+
} from './types/api';
|