ai.matey.http.core 0.2.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/LICENSE +21 -0
- package/dist/cjs/auth.js +173 -0
- package/dist/cjs/auth.js.map +1 -0
- package/dist/cjs/cors.js +140 -0
- package/dist/cjs/cors.js.map +1 -0
- package/dist/cjs/error-handler.js +147 -0
- package/dist/cjs/error-handler.js.map +1 -0
- package/dist/cjs/handler.js +335 -0
- package/dist/cjs/handler.js.map +1 -0
- package/dist/cjs/health.js +218 -0
- package/dist/cjs/health.js.map +1 -0
- package/dist/cjs/index.js +83 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/rate-limiter.js +163 -0
- package/dist/cjs/rate-limiter.js.map +1 -0
- package/dist/cjs/request-parser.js +141 -0
- package/dist/cjs/request-parser.js.map +1 -0
- package/dist/cjs/response-formatter.js +218 -0
- package/dist/cjs/response-formatter.js.map +1 -0
- package/dist/cjs/route-matcher.js +178 -0
- package/dist/cjs/route-matcher.js.map +1 -0
- package/dist/cjs/streaming-handler.js +120 -0
- package/dist/cjs/streaming-handler.js.map +1 -0
- package/dist/cjs/types.js +11 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/auth.js +163 -0
- package/dist/esm/auth.js.map +1 -0
- package/dist/esm/cors.js +134 -0
- package/dist/esm/cors.js.map +1 -0
- package/dist/esm/error-handler.js +137 -0
- package/dist/esm/error-handler.js.map +1 -0
- package/dist/esm/handler.js +331 -0
- package/dist/esm/handler.js.map +1 -0
- package/dist/esm/health.js +210 -0
- package/dist/esm/health.js.map +1 -0
- package/dist/esm/index.js +30 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/rate-limiter.js +156 -0
- package/dist/esm/rate-limiter.js.map +1 -0
- package/dist/esm/request-parser.js +136 -0
- package/dist/esm/request-parser.js.map +1 -0
- package/dist/esm/response-formatter.js +206 -0
- package/dist/esm/response-formatter.js.map +1 -0
- package/dist/esm/route-matcher.js +171 -0
- package/dist/esm/route-matcher.js.map +1 -0
- package/dist/esm/streaming-handler.js +112 -0
- package/dist/esm/streaming-handler.js.map +1 -0
- package/dist/esm/types.js +10 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/auth.d.ts +37 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/cors.d.ts +26 -0
- package/dist/types/cors.d.ts.map +1 -0
- package/dist/types/error-handler.d.ts +38 -0
- package/dist/types/error-handler.d.ts.map +1 -0
- package/dist/types/handler.d.ts +45 -0
- package/dist/types/handler.d.ts.map +1 -0
- package/dist/types/health.d.ts +164 -0
- package/dist/types/health.d.ts.map +1 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/rate-limiter.d.ts +56 -0
- package/dist/types/rate-limiter.d.ts.map +1 -0
- package/dist/types/request-parser.d.ts +22 -0
- package/dist/types/request-parser.d.ts.map +1 -0
- package/dist/types/response-formatter.d.ts +49 -0
- package/dist/types/response-formatter.d.ts.map +1 -0
- package/dist/types/route-matcher.d.ts +45 -0
- package/dist/types/route-matcher.d.ts.map +1 -0
- package/dist/types/streaming-handler.d.ts +40 -0
- package/dist/types/streaming-handler.d.ts.map +1 -0
- package/dist/types/types.d.ts +398 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +73 -0
- package/readme.md +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEH,eAAe;AACf,2CAA+C;AAAtC,6GAAA,eAAe,OAAA;AA2BxB,kBAAkB;AAClB,yDAAoF;AAA3E,iHAAA,YAAY,OAAA;AAAE,uHAAA,kBAAkB,OAAA;AAAE,gHAAA,WAAW,OAAA;AAEtD,sBAAsB;AACtB,iEAWiC;AAV/B,iHAAA,QAAQ,OAAA;AACR,kHAAA,SAAS,OAAA;AACT,uHAAA,cAAc,OAAA;AACd,qHAAA,YAAY,OAAA;AACZ,qHAAA,YAAY,OAAA;AACZ,oHAAA,WAAW,OAAA;AACX,qHAAA,YAAY,OAAA;AACZ,iHAAA,QAAQ,OAAA;AACR,sHAAA,aAAa,OAAA;AACb,6HAAA,oBAAoB,OAAA;AAGtB,OAAO;AACP,qCAA2F;AAAlF,+GAAA,oBAAoB,OAAA;AAAE,qGAAA,UAAU,OAAA;AAAE,0GAAA,eAAe,OAAA;AAAE,sGAAA,WAAW,OAAA;AAEvE,iBAAiB;AACjB,qCAQmB;AAPjB,+GAAA,oBAAoB,OAAA;AACpB,qHAAA,0BAA0B,OAAA;AAC1B,gHAAA,qBAAqB,OAAA;AACrB,mHAAA,wBAAwB,OAAA;AACxB,gHAAA,qBAAqB,OAAA;AACrB,yGAAA,cAAc,OAAA;AACd,2GAAA,gBAAgB,OAAA;AAGlB,gBAAgB;AAChB,qDAK2B;AAJzB,8GAAA,WAAW,OAAA;AACX,qHAAA,kBAAkB,OAAA;AAClB,oHAAA,iBAAiB,OAAA;AACjB,uHAAA,oBAAoB,OAAA;AAGtB,iBAAiB;AACjB,uDAQ4B;AAP1B,uHAAA,mBAAmB,OAAA;AACnB,6HAAA,yBAAyB,OAAA;AACzB,+HAAA,2BAA2B,OAAA;AAC3B,oHAAA,gBAAgB,OAAA;AAChB,oHAAA,gBAAgB,OAAA;AAChB,iHAAA,aAAa,OAAA;AACb,iHAAA,aAAa,OAAA;AAGf,YAAY;AACZ,+DAMgC;AAL9B,8HAAA,sBAAsB,OAAA;AACtB,oHAAA,YAAY,OAAA;AACZ,0HAAA,kBAAkB,OAAA;AAClB,yHAAA,iBAAiB,OAAA;AACjB,6HAAA,qBAAqB,OAAA;AAGvB,UAAU;AACV,uDAK4B;AAJ1B,gHAAA,YAAY,OAAA;AACZ,uHAAA,mBAAmB,OAAA;AACnB,iHAAA,aAAa,OAAA;AACb,mHAAA,eAAe,OAAA;AAGjB,gBAAgB;AAChB,yCAUqB;AATnB,wGAAA,WAAW,OAAA;AACX,8GAAA,iBAAiB,OAAA;AACjB,wHAAA,2BAA2B,OAAA;AAC3B,iHAAA,oBAAoB,OAAA;AACpB,gHAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Rate Limiter
|
|
4
|
+
*
|
|
5
|
+
* Implements rate limiting for HTTP requests using a sliding window algorithm.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.RateLimiter = void 0;
|
|
11
|
+
exports.userIDKeyGenerator = userIDKeyGenerator;
|
|
12
|
+
exports.tokenKeyGenerator = tokenKeyGenerator;
|
|
13
|
+
exports.combineKeyGenerators = combineKeyGenerators;
|
|
14
|
+
const request_parser_js_1 = require("./request-parser.js");
|
|
15
|
+
const response_formatter_js_1 = require("./response-formatter.js");
|
|
16
|
+
/**
|
|
17
|
+
* Rate limiter class
|
|
18
|
+
*/
|
|
19
|
+
class RateLimiter {
|
|
20
|
+
options;
|
|
21
|
+
store;
|
|
22
|
+
cleanupIntervalId;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.options = {
|
|
25
|
+
max: options.max,
|
|
26
|
+
windowMs: options.windowMs ?? 60000, // 1 minute default
|
|
27
|
+
keyGenerator: options.keyGenerator ?? defaultKeyGenerator,
|
|
28
|
+
handler: options.handler ?? defaultRateLimitHandler,
|
|
29
|
+
skip: options.skip ?? (() => false),
|
|
30
|
+
headers: options.headers ?? true,
|
|
31
|
+
};
|
|
32
|
+
this.store = new Map();
|
|
33
|
+
// Cleanup old entries periodically
|
|
34
|
+
this.cleanupIntervalId = setInterval(() => this.cleanup(), this.options.windowMs);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Dispose of the rate limiter and clean up resources.
|
|
38
|
+
* Call this when the rate limiter is no longer needed to prevent memory leaks.
|
|
39
|
+
*/
|
|
40
|
+
dispose() {
|
|
41
|
+
if (this.cleanupIntervalId) {
|
|
42
|
+
clearInterval(this.cleanupIntervalId);
|
|
43
|
+
this.cleanupIntervalId = undefined;
|
|
44
|
+
}
|
|
45
|
+
this.store.clear();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Check if request should be rate limited
|
|
49
|
+
*/
|
|
50
|
+
async check(req, res) {
|
|
51
|
+
// Check if rate limiting should be skipped
|
|
52
|
+
if (await this.options.skip(req)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const key = this.options.keyGenerator(req);
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
// Get or create state for this key
|
|
58
|
+
let state = this.store.get(key);
|
|
59
|
+
if (!state || now >= state.resetTime) {
|
|
60
|
+
// Create new window
|
|
61
|
+
state = {
|
|
62
|
+
count: 0,
|
|
63
|
+
resetTime: now + this.options.windowMs,
|
|
64
|
+
};
|
|
65
|
+
this.store.set(key, state);
|
|
66
|
+
}
|
|
67
|
+
// Increment request count
|
|
68
|
+
state.count++;
|
|
69
|
+
// Add rate limit headers
|
|
70
|
+
if (this.options.headers) {
|
|
71
|
+
res.setHeader('X-RateLimit-Limit', String(this.options.max));
|
|
72
|
+
res.setHeader('X-RateLimit-Remaining', String(Math.max(0, this.options.max - state.count)));
|
|
73
|
+
res.setHeader('X-RateLimit-Reset', String(Math.ceil(state.resetTime / 1000)));
|
|
74
|
+
}
|
|
75
|
+
// Check if limit exceeded
|
|
76
|
+
if (state.count > this.options.max) {
|
|
77
|
+
const retryAfter = Math.ceil((state.resetTime - now) / 1000);
|
|
78
|
+
if (this.options.headers) {
|
|
79
|
+
res.setHeader('Retry-After', String(retryAfter));
|
|
80
|
+
}
|
|
81
|
+
// Call custom handler
|
|
82
|
+
await this.options.handler(req, res, retryAfter);
|
|
83
|
+
return true; // Rate limited
|
|
84
|
+
}
|
|
85
|
+
return false; // Not rate limited
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Clean up expired entries
|
|
89
|
+
*/
|
|
90
|
+
cleanup() {
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
for (const [key, state] of this.store.entries()) {
|
|
93
|
+
if (now >= state.resetTime) {
|
|
94
|
+
this.store.delete(key);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Reset rate limit for a specific key
|
|
100
|
+
*/
|
|
101
|
+
reset(key) {
|
|
102
|
+
this.store.delete(key);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Reset all rate limits
|
|
106
|
+
*/
|
|
107
|
+
resetAll() {
|
|
108
|
+
this.store.clear();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get current state for a key
|
|
112
|
+
*/
|
|
113
|
+
getState(key) {
|
|
114
|
+
return this.store.get(key);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.RateLimiter = RateLimiter;
|
|
118
|
+
/**
|
|
119
|
+
* Default key generator (uses IP address)
|
|
120
|
+
*/
|
|
121
|
+
function defaultKeyGenerator(req) {
|
|
122
|
+
return (0, request_parser_js_1.getClientIP)(req);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Default rate limit handler
|
|
126
|
+
*/
|
|
127
|
+
function defaultRateLimitHandler(_req, res, retryAfter) {
|
|
128
|
+
(0, response_formatter_js_1.sendJSON)(res, {
|
|
129
|
+
error: {
|
|
130
|
+
message: 'Too many requests, please try again later.',
|
|
131
|
+
type: 'rate_limit_exceeded',
|
|
132
|
+
retryAfter,
|
|
133
|
+
},
|
|
134
|
+
}, 429);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Create key generator from user ID in request body
|
|
138
|
+
*/
|
|
139
|
+
function userIDKeyGenerator(req) {
|
|
140
|
+
// This would need to be called after body parsing
|
|
141
|
+
// For now, fall back to IP
|
|
142
|
+
return (0, request_parser_js_1.getClientIP)(req);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Create key generator from authorization token
|
|
146
|
+
*/
|
|
147
|
+
function tokenKeyGenerator(req) {
|
|
148
|
+
const auth = req.headers.authorization;
|
|
149
|
+
if (auth) {
|
|
150
|
+
return auth;
|
|
151
|
+
}
|
|
152
|
+
return (0, request_parser_js_1.getClientIP)(req);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create key generator that combines multiple factors
|
|
156
|
+
*/
|
|
157
|
+
function combineKeyGenerators(...generators) {
|
|
158
|
+
return (req) => {
|
|
159
|
+
const parts = generators.map((gen) => gen(req));
|
|
160
|
+
return parts.join(':');
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* HTTP Request Parser
|
|
4
|
+
*
|
|
5
|
+
* Parses incoming HTTP requests into a standardized format for processing.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.parseRequest = parseRequest;
|
|
11
|
+
exports.extractBearerToken = extractBearerToken;
|
|
12
|
+
exports.getClientIP = getClientIP;
|
|
13
|
+
/**
|
|
14
|
+
* Parse incoming HTTP request
|
|
15
|
+
*/
|
|
16
|
+
async function parseRequest(req, maxBodySize = 10 * 1024 * 1024 // 10MB default
|
|
17
|
+
) {
|
|
18
|
+
// Parse URL
|
|
19
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
20
|
+
const path = url.pathname;
|
|
21
|
+
const method = req.method?.toUpperCase() || 'GET';
|
|
22
|
+
// Parse query parameters
|
|
23
|
+
const query = {};
|
|
24
|
+
url.searchParams.forEach((value, key) => {
|
|
25
|
+
query[key] = value;
|
|
26
|
+
});
|
|
27
|
+
// Normalize headers
|
|
28
|
+
const headers = {};
|
|
29
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
30
|
+
if (typeof value === 'string') {
|
|
31
|
+
headers[key.toLowerCase()] = value;
|
|
32
|
+
}
|
|
33
|
+
else if (Array.isArray(value)) {
|
|
34
|
+
headers[key.toLowerCase()] = value[0] || '';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Parse body (if present)
|
|
38
|
+
let body = null;
|
|
39
|
+
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
|
40
|
+
const rawBody = await readBody(req, maxBodySize);
|
|
41
|
+
if (rawBody) {
|
|
42
|
+
const contentType = headers['content-type'] || '';
|
|
43
|
+
if (contentType.includes('application/json')) {
|
|
44
|
+
try {
|
|
45
|
+
body = JSON.parse(rawBody);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new Error(`Invalid JSON body: ${error instanceof Error ? error.message : String(error)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
52
|
+
body = parseFormData(rawBody);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Unknown content type, try JSON anyway
|
|
56
|
+
try {
|
|
57
|
+
body = JSON.parse(rawBody);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
body = rawBody;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Detect streaming request
|
|
66
|
+
const stream = body?.stream === true || headers['accept'] === 'text/event-stream';
|
|
67
|
+
return {
|
|
68
|
+
body,
|
|
69
|
+
headers,
|
|
70
|
+
path,
|
|
71
|
+
method,
|
|
72
|
+
query,
|
|
73
|
+
stream,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Read request body as string
|
|
78
|
+
*/
|
|
79
|
+
function readBody(req, maxSize) {
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
const chunks = [];
|
|
82
|
+
let totalSize = 0;
|
|
83
|
+
req.on('data', (chunk) => {
|
|
84
|
+
totalSize += chunk.length;
|
|
85
|
+
if (totalSize > maxSize) {
|
|
86
|
+
// Destroy the stream to stop receiving data and free resources
|
|
87
|
+
req.destroy();
|
|
88
|
+
reject(new Error(`Request body too large (max ${maxSize} bytes)`));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
chunks.push(chunk);
|
|
92
|
+
});
|
|
93
|
+
req.on('end', () => {
|
|
94
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
95
|
+
resolve(body);
|
|
96
|
+
});
|
|
97
|
+
req.on('error', (error) => {
|
|
98
|
+
reject(error);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse form-encoded data
|
|
104
|
+
*/
|
|
105
|
+
function parseFormData(data) {
|
|
106
|
+
const params = new URLSearchParams(data);
|
|
107
|
+
const result = {};
|
|
108
|
+
params.forEach((value, key) => {
|
|
109
|
+
result[key] = value;
|
|
110
|
+
});
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Extract bearer token from Authorization header
|
|
115
|
+
*/
|
|
116
|
+
function extractBearerToken(req) {
|
|
117
|
+
const auth = req.headers.authorization;
|
|
118
|
+
if (!auth) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const match = auth.match(/^Bearer\s+(.+)$/i);
|
|
122
|
+
return match ? match[1] || null : null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get client IP address from request
|
|
126
|
+
*/
|
|
127
|
+
function getClientIP(req) {
|
|
128
|
+
// Check common proxy headers
|
|
129
|
+
const forwarded = req.headers['x-forwarded-for'];
|
|
130
|
+
if (forwarded) {
|
|
131
|
+
const ips = typeof forwarded === 'string' ? forwarded.split(',') : forwarded;
|
|
132
|
+
return ips[0]?.trim() || 'unknown';
|
|
133
|
+
}
|
|
134
|
+
const realIP = req.headers['x-real-ip'];
|
|
135
|
+
if (realIP && typeof realIP === 'string') {
|
|
136
|
+
return realIP;
|
|
137
|
+
}
|
|
138
|
+
// Fallback to socket address
|
|
139
|
+
return req.socket.remoteAddress || 'unknown';
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=request-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-parser.js","sourceRoot":"","sources":["../../src/request-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* HTTP Response Formatter
|
|
4
|
+
*
|
|
5
|
+
* Formats responses for HTTP responses with proper headers and status codes.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.sendJSON = sendJSON;
|
|
11
|
+
exports.sendError = sendError;
|
|
12
|
+
exports.sendSSEHeaders = sendSSEHeaders;
|
|
13
|
+
exports.sendSSEChunk = sendSSEChunk;
|
|
14
|
+
exports.sendSSEEvent = sendSSEEvent;
|
|
15
|
+
exports.sendSSEDone = sendSSEDone;
|
|
16
|
+
exports.sendSSEError = sendSSEError;
|
|
17
|
+
exports.sendText = sendText;
|
|
18
|
+
exports.sendNoContent = sendNoContent;
|
|
19
|
+
exports.detectProviderFormat = detectProviderFormat;
|
|
20
|
+
/**
|
|
21
|
+
* Send JSON response
|
|
22
|
+
*/
|
|
23
|
+
function sendJSON(res, data, statusCode = 200, headers = {}) {
|
|
24
|
+
res.statusCode = statusCode;
|
|
25
|
+
res.setHeader('Content-Type', 'application/json');
|
|
26
|
+
// Set custom headers
|
|
27
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
28
|
+
res.setHeader(key, value);
|
|
29
|
+
}
|
|
30
|
+
const body = JSON.stringify(data);
|
|
31
|
+
res.end(body);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Send error response
|
|
35
|
+
*/
|
|
36
|
+
function sendError(res, error, statusCode = 500, format = 'generic') {
|
|
37
|
+
let errorBody;
|
|
38
|
+
switch (format) {
|
|
39
|
+
case 'openai':
|
|
40
|
+
errorBody = formatOpenAIError(error, statusCode);
|
|
41
|
+
break;
|
|
42
|
+
case 'anthropic':
|
|
43
|
+
errorBody = formatAnthropicError(error, statusCode);
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
errorBody = formatGenericError(error, statusCode);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
sendJSON(res, errorBody, statusCode);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Format error in OpenAI style
|
|
53
|
+
*/
|
|
54
|
+
function formatOpenAIError(error, statusCode) {
|
|
55
|
+
return {
|
|
56
|
+
error: {
|
|
57
|
+
message: error.message,
|
|
58
|
+
type: getOpenAIErrorType(statusCode),
|
|
59
|
+
code: statusCode === 429 ? 'rate_limit_exceeded' : null,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Format error in Anthropic style
|
|
65
|
+
*/
|
|
66
|
+
function formatAnthropicError(error, statusCode) {
|
|
67
|
+
return {
|
|
68
|
+
type: 'error',
|
|
69
|
+
error: {
|
|
70
|
+
type: getAnthropicErrorType(statusCode),
|
|
71
|
+
message: error.message,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Format error in generic style
|
|
77
|
+
*/
|
|
78
|
+
function formatGenericError(error, statusCode) {
|
|
79
|
+
return {
|
|
80
|
+
error: {
|
|
81
|
+
message: error.message,
|
|
82
|
+
status: statusCode,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get OpenAI error type from status code
|
|
88
|
+
*/
|
|
89
|
+
function getOpenAIErrorType(statusCode) {
|
|
90
|
+
switch (statusCode) {
|
|
91
|
+
case 400:
|
|
92
|
+
return 'invalid_request_error';
|
|
93
|
+
case 401:
|
|
94
|
+
return 'authentication_error';
|
|
95
|
+
case 403:
|
|
96
|
+
return 'permission_error';
|
|
97
|
+
case 404:
|
|
98
|
+
return 'not_found_error';
|
|
99
|
+
case 429:
|
|
100
|
+
return 'rate_limit_error';
|
|
101
|
+
case 500:
|
|
102
|
+
return 'server_error';
|
|
103
|
+
case 503:
|
|
104
|
+
return 'service_unavailable_error';
|
|
105
|
+
default:
|
|
106
|
+
return 'api_error';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get Anthropic error type from status code
|
|
111
|
+
*/
|
|
112
|
+
function getAnthropicErrorType(statusCode) {
|
|
113
|
+
switch (statusCode) {
|
|
114
|
+
case 400:
|
|
115
|
+
return 'invalid_request_error';
|
|
116
|
+
case 401:
|
|
117
|
+
return 'authentication_error';
|
|
118
|
+
case 403:
|
|
119
|
+
return 'permission_error';
|
|
120
|
+
case 404:
|
|
121
|
+
return 'not_found_error';
|
|
122
|
+
case 429:
|
|
123
|
+
return 'rate_limit_error';
|
|
124
|
+
case 500:
|
|
125
|
+
return 'api_error';
|
|
126
|
+
case 529:
|
|
127
|
+
return 'overloaded_error';
|
|
128
|
+
default:
|
|
129
|
+
return 'api_error';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Send Server-Sent Events (SSE) headers
|
|
134
|
+
*/
|
|
135
|
+
function sendSSEHeaders(res, headers = {}) {
|
|
136
|
+
res.statusCode = 200;
|
|
137
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
138
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
139
|
+
res.setHeader('Connection', 'keep-alive');
|
|
140
|
+
// Set custom headers
|
|
141
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
142
|
+
res.setHeader(key, value);
|
|
143
|
+
}
|
|
144
|
+
// Write headers (flushes them to client)
|
|
145
|
+
res.flushHeaders?.();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Send SSE data chunk
|
|
149
|
+
*/
|
|
150
|
+
function sendSSEChunk(res, data) {
|
|
151
|
+
const json = JSON.stringify(data);
|
|
152
|
+
res.write(`data: ${json}\n\n`);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Send SSE event with custom event type
|
|
156
|
+
*/
|
|
157
|
+
function sendSSEEvent(res, event, data) {
|
|
158
|
+
const json = JSON.stringify(data);
|
|
159
|
+
res.write(`event: ${event}\ndata: ${json}\n\n`);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Send SSE done marker
|
|
163
|
+
*/
|
|
164
|
+
function sendSSEDone(res) {
|
|
165
|
+
res.write('data: [DONE]\n\n');
|
|
166
|
+
res.end();
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Send SSE error
|
|
170
|
+
*/
|
|
171
|
+
function sendSSEError(res, error, format = 'generic') {
|
|
172
|
+
let errorData;
|
|
173
|
+
switch (format) {
|
|
174
|
+
case 'openai':
|
|
175
|
+
errorData = formatOpenAIError(error, 500);
|
|
176
|
+
break;
|
|
177
|
+
case 'anthropic':
|
|
178
|
+
errorData = formatAnthropicError(error, 500);
|
|
179
|
+
break;
|
|
180
|
+
default:
|
|
181
|
+
errorData = formatGenericError(error, 500);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
sendSSEChunk(res, errorData);
|
|
185
|
+
res.end();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Send plain text response
|
|
189
|
+
*/
|
|
190
|
+
function sendText(res, text, statusCode = 200, headers = {}) {
|
|
191
|
+
res.statusCode = statusCode;
|
|
192
|
+
res.setHeader('Content-Type', 'text/plain');
|
|
193
|
+
// Set custom headers
|
|
194
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
195
|
+
res.setHeader(key, value);
|
|
196
|
+
}
|
|
197
|
+
res.end(text);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Send 204 No Content response
|
|
201
|
+
*/
|
|
202
|
+
function sendNoContent(res) {
|
|
203
|
+
res.statusCode = 204;
|
|
204
|
+
res.end();
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Detect provider format from request path or headers
|
|
208
|
+
*/
|
|
209
|
+
function detectProviderFormat(path) {
|
|
210
|
+
if (path.includes('/chat/completions')) {
|
|
211
|
+
return 'openai';
|
|
212
|
+
}
|
|
213
|
+
if (path.includes('/messages')) {
|
|
214
|
+
return 'anthropic';
|
|
215
|
+
}
|
|
216
|
+
return 'generic';
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=response-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-formatter.js","sourceRoot":"","sources":["../../src/response-formatter.ts"],"names":[],"mappings":"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"}
|