@winstonsayno/mcp-gateway 1.3.0 → 1.5.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 +44 -0
- package/README.md +20 -2
- package/dashboard/index.html +5 -3
- package/dist/auth/ratelimit.d.ts +3 -2
- package/dist/auth/ratelimit.d.ts.map +1 -1
- package/dist/auth/ratelimit.js +2 -1
- package/dist/auth/ratelimit.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +45 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/gateway/api.d.ts +15 -3
- package/dist/gateway/api.d.ts.map +1 -1
- package/dist/gateway/api.js +33 -26
- package/dist/gateway/api.js.map +1 -1
- package/dist/gateway/index.d.ts +10 -1
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +50 -3
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/invoker.d.ts +49 -0
- package/dist/gateway/invoker.d.ts.map +1 -0
- package/dist/gateway/invoker.js +72 -0
- package/dist/gateway/invoker.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/endpoint.d.ts +16 -1
- package/dist/mcp/endpoint.d.ts.map +1 -1
- package/dist/mcp/endpoint.js +116 -32
- package/dist/mcp/endpoint.js.map +1 -1
- package/dist/monitor/index.d.ts +2 -0
- package/dist/monitor/index.d.ts.map +1 -1
- package/dist/monitor/index.js +23 -1
- package/dist/monitor/index.js.map +1 -1
- package/dist/observability/tracing.d.ts +104 -0
- package/dist/observability/tracing.d.ts.map +1 -0
- package/dist/observability/tracing.js +240 -0
- package/dist/observability/tracing.js.map +1 -0
- package/dist/security/lockout.d.ts +14 -2
- package/dist/security/lockout.d.ts.map +1 -1
- package/dist/security/lockout.js +22 -17
- package/dist/security/lockout.js.map +1 -1
- package/dist/state/index.d.ts +14 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +27 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/redis.d.ts +56 -0
- package/dist/state/redis.d.ts.map +1 -0
- package/dist/state/redis.js +263 -0
- package/dist/state/redis.js.map +1 -0
- package/dist/state/shared.d.ts +45 -0
- package/dist/state/shared.d.ts.map +1 -0
- package/dist/state/shared.js +130 -0
- package/dist/state/shared.js.map +1 -0
- package/dist/state/store.d.ts +67 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +113 -0
- package/dist/state/store.js.map +1 -0
- package/dist/utils/types.d.ts +35 -0
- package/dist/utils/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis-backed `StateStore` with a small built-in RESP2 client (no extra
|
|
3
|
+
* dependency). Supports `redis://` and `rediss://` (TLS) URLs with optional
|
|
4
|
+
* `user:password@` credentials and a `/db` number. Commands are pipelined on
|
|
5
|
+
* one connection; the connection is re-established lazily after an error.
|
|
6
|
+
*
|
|
7
|
+
* @module state/redis
|
|
8
|
+
*/
|
|
9
|
+
import type { StateStore } from './store.js';
|
|
10
|
+
export type RespValue = string | number | null | RespValue[] | RespError;
|
|
11
|
+
export declare class RespError extends Error {
|
|
12
|
+
}
|
|
13
|
+
/** Incremental RESP2 parser. Returns parsed values and leaves partial data buffered. */
|
|
14
|
+
export declare class RespParser {
|
|
15
|
+
private buf;
|
|
16
|
+
push(chunk: Buffer): RespValue[];
|
|
17
|
+
private line;
|
|
18
|
+
private parse;
|
|
19
|
+
}
|
|
20
|
+
export declare function encodeCommand(args: Array<string | number>): Buffer;
|
|
21
|
+
export interface RedisOptions {
|
|
22
|
+
url: string;
|
|
23
|
+
connectTimeoutMs?: number;
|
|
24
|
+
commandTimeoutMs?: number;
|
|
25
|
+
}
|
|
26
|
+
/** Minimal pipelining Redis client. */
|
|
27
|
+
export declare class RedisClient {
|
|
28
|
+
private readonly options;
|
|
29
|
+
private socket?;
|
|
30
|
+
private connecting?;
|
|
31
|
+
private queue;
|
|
32
|
+
private parser;
|
|
33
|
+
private closed;
|
|
34
|
+
private readonly url;
|
|
35
|
+
constructor(options: RedisOptions);
|
|
36
|
+
private failAll;
|
|
37
|
+
private open;
|
|
38
|
+
private raw;
|
|
39
|
+
command(...args: Array<string | number>): Promise<RespValue>;
|
|
40
|
+
/** Run commands inside MULTI / EXEC; resolves with the EXEC reply array. */
|
|
41
|
+
transaction(commands: Array<Array<string | number>>): Promise<RespValue[]>;
|
|
42
|
+
close(): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export declare class RedisStateStore implements StateStore {
|
|
45
|
+
readonly kind = "redis";
|
|
46
|
+
readonly client: RedisClient;
|
|
47
|
+
constructor(options: RedisOptions);
|
|
48
|
+
incr(key: string, ttlMs: number, by?: number): Promise<number>;
|
|
49
|
+
get(key: string): Promise<string | undefined>;
|
|
50
|
+
set(key: string, value: string, ttlMs?: number): Promise<void>;
|
|
51
|
+
del(key: string): Promise<void>;
|
|
52
|
+
pttl(key: string): Promise<number>;
|
|
53
|
+
ping(): Promise<void>;
|
|
54
|
+
close(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=redis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/state/redis.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,SAAS,CAAC;AAEzE,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAOvC,wFAAwF;AACxF,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAA2B;IAEtC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE;IAYhC,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,KAAK;CAmCd;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAOlE;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,uCAAuC;AACvC,qBAAa,WAAW;IAQV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,UAAU,CAAC,CAAkB;IACrC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;gBAEG,OAAO,EAAE,YAAY;IAOlD,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,IAAI;IAyDZ,OAAO,CAAC,GAAG;IAqBL,OAAO,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IAMlE,4EAA4E;IACtE,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAW1E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAa7B;AAED,qBAAa,eAAgB,YAAW,UAAU;IAChD,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;gBAEjB,OAAO,EAAE,YAAY;IAI3B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,SAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IASzD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAK7C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvB"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis-backed `StateStore` with a small built-in RESP2 client (no extra
|
|
3
|
+
* dependency). Supports `redis://` and `rediss://` (TLS) URLs with optional
|
|
4
|
+
* `user:password@` credentials and a `/db` number. Commands are pipelined on
|
|
5
|
+
* one connection; the connection is re-established lazily after an error.
|
|
6
|
+
*
|
|
7
|
+
* @module state/redis
|
|
8
|
+
*/
|
|
9
|
+
import { connect as netConnect } from 'net';
|
|
10
|
+
import { connect as tlsConnect } from 'tls';
|
|
11
|
+
import { logger } from '../utils/logger.js';
|
|
12
|
+
export class RespError extends Error {
|
|
13
|
+
}
|
|
14
|
+
/** Incremental RESP2 parser. Returns parsed values and leaves partial data buffered. */
|
|
15
|
+
export class RespParser {
|
|
16
|
+
buf = Buffer.alloc(0);
|
|
17
|
+
push(chunk) {
|
|
18
|
+
this.buf = this.buf.length ? Buffer.concat([this.buf, chunk]) : chunk;
|
|
19
|
+
const out = [];
|
|
20
|
+
for (;;) {
|
|
21
|
+
const r = this.parse(0);
|
|
22
|
+
if (!r)
|
|
23
|
+
break;
|
|
24
|
+
out.push(r.value);
|
|
25
|
+
this.buf = this.buf.subarray(r.end);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
line(from) {
|
|
30
|
+
const i = this.buf.indexOf('\r\n', from);
|
|
31
|
+
if (i < 0)
|
|
32
|
+
return undefined;
|
|
33
|
+
return { text: this.buf.toString('utf8', from, i), end: i + 2 };
|
|
34
|
+
}
|
|
35
|
+
parse(at) {
|
|
36
|
+
if (at >= this.buf.length)
|
|
37
|
+
return undefined;
|
|
38
|
+
const type = String.fromCharCode(this.buf[at]);
|
|
39
|
+
const l = this.line(at + 1);
|
|
40
|
+
if (!l)
|
|
41
|
+
return undefined;
|
|
42
|
+
switch (type) {
|
|
43
|
+
case '+':
|
|
44
|
+
return { value: l.text, end: l.end };
|
|
45
|
+
case '-':
|
|
46
|
+
return { value: new RespError(l.text), end: l.end };
|
|
47
|
+
case ':':
|
|
48
|
+
return { value: Number(l.text), end: l.end };
|
|
49
|
+
case '$': {
|
|
50
|
+
const len = Number(l.text);
|
|
51
|
+
if (len < 0)
|
|
52
|
+
return { value: null, end: l.end };
|
|
53
|
+
if (this.buf.length < l.end + len + 2)
|
|
54
|
+
return undefined;
|
|
55
|
+
return { value: this.buf.toString('utf8', l.end, l.end + len), end: l.end + len + 2 };
|
|
56
|
+
}
|
|
57
|
+
case '*': {
|
|
58
|
+
const n = Number(l.text);
|
|
59
|
+
if (n < 0)
|
|
60
|
+
return { value: null, end: l.end };
|
|
61
|
+
const items = [];
|
|
62
|
+
let end = l.end;
|
|
63
|
+
for (let i = 0; i < n; i++) {
|
|
64
|
+
const r = this.parse(end);
|
|
65
|
+
if (!r)
|
|
66
|
+
return undefined;
|
|
67
|
+
items.push(r.value);
|
|
68
|
+
end = r.end;
|
|
69
|
+
}
|
|
70
|
+
return { value: items, end };
|
|
71
|
+
}
|
|
72
|
+
default:
|
|
73
|
+
throw new Error(`RESP protocol error: unexpected type byte "${type}"`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function encodeCommand(args) {
|
|
78
|
+
const parts = [`*${args.length}\r\n`];
|
|
79
|
+
for (const a of args) {
|
|
80
|
+
const s = String(a);
|
|
81
|
+
parts.push(`$${Buffer.byteLength(s)}\r\n${s}\r\n`);
|
|
82
|
+
}
|
|
83
|
+
return Buffer.from(parts.join(''));
|
|
84
|
+
}
|
|
85
|
+
/** Minimal pipelining Redis client. */
|
|
86
|
+
export class RedisClient {
|
|
87
|
+
options;
|
|
88
|
+
socket;
|
|
89
|
+
connecting;
|
|
90
|
+
queue = [];
|
|
91
|
+
parser = new RespParser();
|
|
92
|
+
closed = false;
|
|
93
|
+
url;
|
|
94
|
+
constructor(options) {
|
|
95
|
+
this.options = options;
|
|
96
|
+
this.url = new URL(options.url);
|
|
97
|
+
if (this.url.protocol !== 'redis:' && this.url.protocol !== 'rediss:') {
|
|
98
|
+
throw new Error(`state.redis.url must start with redis:// or rediss:// (got ${this.url.protocol})`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
failAll(err) {
|
|
102
|
+
const q = this.queue;
|
|
103
|
+
this.queue = [];
|
|
104
|
+
for (const p of q)
|
|
105
|
+
p.reject(err);
|
|
106
|
+
}
|
|
107
|
+
open() {
|
|
108
|
+
if (this.socket && !this.socket.destroyed)
|
|
109
|
+
return Promise.resolve(this.socket);
|
|
110
|
+
if (this.connecting)
|
|
111
|
+
return this.connecting;
|
|
112
|
+
this.connecting = new Promise((resolve, reject) => {
|
|
113
|
+
const port = Number(this.url.port || 6379);
|
|
114
|
+
const host = this.url.hostname.replace(/^\[|\]$/g, '');
|
|
115
|
+
const socket = this.url.protocol === 'rediss:' ? tlsConnect({ host, port, servername: host }) : netConnect({ host, port });
|
|
116
|
+
const timer = setTimeout(() => socket.destroy(new Error('Redis connect timeout')), this.options.connectTimeoutMs ?? 5_000);
|
|
117
|
+
timer.unref();
|
|
118
|
+
this.parser = new RespParser();
|
|
119
|
+
socket.on('data', (chunk) => {
|
|
120
|
+
let values;
|
|
121
|
+
try {
|
|
122
|
+
values = this.parser.push(chunk);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
socket.destroy(err);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const v of values) {
|
|
129
|
+
const p = this.queue.shift();
|
|
130
|
+
if (!p)
|
|
131
|
+
continue;
|
|
132
|
+
if (v instanceof RespError)
|
|
133
|
+
p.reject(v);
|
|
134
|
+
else
|
|
135
|
+
p.resolve(v);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
socket.on('error', (err) => {
|
|
139
|
+
logger.debug(`Redis connection error: ${err.message}`);
|
|
140
|
+
});
|
|
141
|
+
socket.on('close', () => {
|
|
142
|
+
if (this.socket === socket)
|
|
143
|
+
this.socket = undefined;
|
|
144
|
+
this.failAll(new Error('Redis connection closed'));
|
|
145
|
+
});
|
|
146
|
+
socket.once(this.url.protocol === 'rediss:' ? 'secureConnect' : 'connect', () => {
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
this.socket = socket;
|
|
149
|
+
resolve(socket);
|
|
150
|
+
});
|
|
151
|
+
socket.once('close', () => {
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
reject(new Error(`Could not connect to Redis at ${host}:${port}`));
|
|
154
|
+
});
|
|
155
|
+
})
|
|
156
|
+
.then(async (socket) => {
|
|
157
|
+
const user = decodeURIComponent(this.url.username);
|
|
158
|
+
const pass = decodeURIComponent(this.url.password);
|
|
159
|
+
if (pass)
|
|
160
|
+
await this.raw(socket, user ? ['AUTH', user, pass] : ['AUTH', pass]);
|
|
161
|
+
const db = this.url.pathname.replace(/^\//, '');
|
|
162
|
+
if (db && db !== '0')
|
|
163
|
+
await this.raw(socket, ['SELECT', db]);
|
|
164
|
+
return socket;
|
|
165
|
+
})
|
|
166
|
+
.finally(() => {
|
|
167
|
+
this.connecting = undefined;
|
|
168
|
+
});
|
|
169
|
+
return this.connecting;
|
|
170
|
+
}
|
|
171
|
+
raw(socket, args) {
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
const timer = setTimeout(() => {
|
|
174
|
+
reject(new Error(`Redis command timed out: ${String(args[0])}`));
|
|
175
|
+
socket.destroy();
|
|
176
|
+
}, this.options.commandTimeoutMs ?? 5_000);
|
|
177
|
+
timer.unref();
|
|
178
|
+
this.queue.push({
|
|
179
|
+
resolve: (v) => {
|
|
180
|
+
clearTimeout(timer);
|
|
181
|
+
resolve(v);
|
|
182
|
+
},
|
|
183
|
+
reject: (e) => {
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
reject(e);
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
socket.write(encodeCommand(args));
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
async command(...args) {
|
|
192
|
+
if (this.closed)
|
|
193
|
+
throw new Error('Redis client is closed');
|
|
194
|
+
const socket = await this.open();
|
|
195
|
+
return this.raw(socket, args);
|
|
196
|
+
}
|
|
197
|
+
/** Run commands inside MULTI / EXEC; resolves with the EXEC reply array. */
|
|
198
|
+
async transaction(commands) {
|
|
199
|
+
if (this.closed)
|
|
200
|
+
throw new Error('Redis client is closed');
|
|
201
|
+
const socket = await this.open();
|
|
202
|
+
const replies = [this.raw(socket, ['MULTI']), ...commands.map((c) => this.raw(socket, c)), this.raw(socket, ['EXEC'])];
|
|
203
|
+
const all = await Promise.all(replies);
|
|
204
|
+
const exec = all[all.length - 1];
|
|
205
|
+
if (!Array.isArray(exec))
|
|
206
|
+
throw new Error('Redis transaction aborted');
|
|
207
|
+
for (const v of exec)
|
|
208
|
+
if (v instanceof RespError)
|
|
209
|
+
throw v;
|
|
210
|
+
return exec;
|
|
211
|
+
}
|
|
212
|
+
async close() {
|
|
213
|
+
this.closed = true;
|
|
214
|
+
const s = this.socket;
|
|
215
|
+
this.socket = undefined;
|
|
216
|
+
if (s && !s.destroyed) {
|
|
217
|
+
await new Promise((resolve) => {
|
|
218
|
+
s.once('close', () => resolve());
|
|
219
|
+
s.end(encodeCommand(['QUIT']));
|
|
220
|
+
setTimeout(() => s.destroy(), 500).unref();
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
this.failAll(new Error('Redis client is closed'));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
export class RedisStateStore {
|
|
227
|
+
kind = 'redis';
|
|
228
|
+
client;
|
|
229
|
+
constructor(options) {
|
|
230
|
+
this.client = new RedisClient(options);
|
|
231
|
+
}
|
|
232
|
+
async incr(key, ttlMs, by = 1) {
|
|
233
|
+
const ttl = Math.max(1, Math.ceil(ttlMs));
|
|
234
|
+
const replies = await this.client.transaction([
|
|
235
|
+
['SET', key, '0', 'PX', ttl, 'NX'],
|
|
236
|
+
['INCRBY', key, by],
|
|
237
|
+
]);
|
|
238
|
+
return Number(replies[1]);
|
|
239
|
+
}
|
|
240
|
+
async get(key) {
|
|
241
|
+
const v = await this.client.command('GET', key);
|
|
242
|
+
return v === null ? undefined : String(v);
|
|
243
|
+
}
|
|
244
|
+
async set(key, value, ttlMs) {
|
|
245
|
+
if (ttlMs && ttlMs > 0)
|
|
246
|
+
await this.client.command('SET', key, value, 'PX', Math.ceil(ttlMs));
|
|
247
|
+
else
|
|
248
|
+
await this.client.command('SET', key, value);
|
|
249
|
+
}
|
|
250
|
+
async del(key) {
|
|
251
|
+
await this.client.command('DEL', key);
|
|
252
|
+
}
|
|
253
|
+
async pttl(key) {
|
|
254
|
+
return Number(await this.client.command('PTTL', key));
|
|
255
|
+
}
|
|
256
|
+
async ping() {
|
|
257
|
+
await this.client.command('PING');
|
|
258
|
+
}
|
|
259
|
+
close() {
|
|
260
|
+
return this.client.close();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/state/redis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate limiting and brute-force lockout on top of a shared `StateStore`
|
|
3
|
+
* (used when `state.store` is not `memory`).
|
|
4
|
+
*
|
|
5
|
+
* Both fail open by default when the store is unreachable (a Redis outage
|
|
6
|
+
* must not take every tool call down); set `state.failureMode: closed` to
|
|
7
|
+
* reject requests instead.
|
|
8
|
+
*
|
|
9
|
+
* @module state/shared
|
|
10
|
+
*/
|
|
11
|
+
import type { AuthLockoutConfig, RateLimitConfig } from '../utils/types.js';
|
|
12
|
+
import { type RateLimiter } from '../auth/ratelimit.js';
|
|
13
|
+
import { type LockoutTracker } from '../security/lockout.js';
|
|
14
|
+
import type { StateStore } from './store.js';
|
|
15
|
+
export type FailureMode = 'open' | 'closed';
|
|
16
|
+
/**
|
|
17
|
+
* Sliding-window rate limiter whose counters live in the store, so the limit
|
|
18
|
+
* holds across every gateway instance sharing it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createStoreRateLimiter(config: RateLimitConfig, store: StateStore, options?: {
|
|
21
|
+
failureMode?: FailureMode;
|
|
22
|
+
now?: () => number;
|
|
23
|
+
namespace?: string;
|
|
24
|
+
}): RateLimiter;
|
|
25
|
+
/** Brute-force lockout with failure counters and locks kept in the store. */
|
|
26
|
+
export declare class StoreAuthLockout implements LockoutTracker {
|
|
27
|
+
private readonly store;
|
|
28
|
+
private readonly failureMode;
|
|
29
|
+
readonly config: Required<AuthLockoutConfig>;
|
|
30
|
+
private total;
|
|
31
|
+
private readonly recent;
|
|
32
|
+
constructor(config: AuthLockoutConfig, store: StateStore, failureMode?: FailureMode);
|
|
33
|
+
lockedFor(ip: string): Promise<number>;
|
|
34
|
+
fail(ip: string): Promise<boolean>;
|
|
35
|
+
success(ip: string): Promise<void>;
|
|
36
|
+
/** Lockouts triggered by this instance (the store holds the cluster-wide state). */
|
|
37
|
+
status(): {
|
|
38
|
+
lockedClients: number;
|
|
39
|
+
trackedClients: number;
|
|
40
|
+
lockoutsTotal: number;
|
|
41
|
+
shared: boolean;
|
|
42
|
+
};
|
|
43
|
+
close(): void;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/state/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAA+C,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAW5C;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClF,WAAW,CAiDb;AAED,6EAA6E;AAC7E,qBAAa,gBAAiB,YAAW,cAAc;IAOnD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAP9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;gBAGlD,MAAM,EAAE,iBAAiB,EACR,KAAK,EAAE,UAAU,EACjB,WAAW,GAAE,WAAoB;IAK9C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUtC,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBlC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,oFAAoF;IACpF,MAAM;;;;;;IAMN,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate limiting and brute-force lockout on top of a shared `StateStore`
|
|
3
|
+
* (used when `state.store` is not `memory`).
|
|
4
|
+
*
|
|
5
|
+
* Both fail open by default when the store is unreachable (a Redis outage
|
|
6
|
+
* must not take every tool call down); set `state.failureMode: closed` to
|
|
7
|
+
* reject requests instead.
|
|
8
|
+
*
|
|
9
|
+
* @module state/shared
|
|
10
|
+
*/
|
|
11
|
+
import { setRateLimitHeaders } from '../auth/ratelimit.js';
|
|
12
|
+
import { DEFAULT_LOCKOUT } from '../security/lockout.js';
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
|
+
let lastStoreWarning = 0;
|
|
15
|
+
function storeFailed(what, err) {
|
|
16
|
+
const t = Date.now();
|
|
17
|
+
if (t - lastStoreWarning > 10_000) {
|
|
18
|
+
lastStoreWarning = t;
|
|
19
|
+
logger.warn(`State store unavailable (${what}): ${err instanceof Error ? err.message : String(err)}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Sliding-window rate limiter whose counters live in the store, so the limit
|
|
24
|
+
* holds across every gateway instance sharing it.
|
|
25
|
+
*/
|
|
26
|
+
export function createStoreRateLimiter(config, store, options = {}) {
|
|
27
|
+
const { limit, windowSeconds, perKey = true } = config;
|
|
28
|
+
const windowMs = windowSeconds * 1000;
|
|
29
|
+
const now = options.now ?? Date.now;
|
|
30
|
+
const ns = options.namespace ?? 'rl';
|
|
31
|
+
const take = async (req) => {
|
|
32
|
+
const clientId = perKey ? (req.clientId ?? req.ip ?? 'anonymous') : 'global';
|
|
33
|
+
const t = now();
|
|
34
|
+
const index = Math.floor(t / windowMs);
|
|
35
|
+
const windowStart = index * windowMs;
|
|
36
|
+
const resetAt = windowStart + windowMs;
|
|
37
|
+
const key = (i) => `${ns}:${windowSeconds}:${clientId}:${i}`;
|
|
38
|
+
try {
|
|
39
|
+
const [current, previousRaw] = await Promise.all([store.incr(key(index), 2 * windowMs), store.get(key(index - 1))]);
|
|
40
|
+
const previous = Number(previousRaw ?? 0) || 0;
|
|
41
|
+
const overlap = 1 - (t - windowStart) / windowMs;
|
|
42
|
+
const estimated = current - 1 + previous * overlap;
|
|
43
|
+
if (estimated >= limit) {
|
|
44
|
+
// Denied requests do not count towards the limit.
|
|
45
|
+
await store.incr(key(index), 2 * windowMs, -1).catch(() => undefined);
|
|
46
|
+
logger.warn(`Rate limit exceeded for ${clientId}`);
|
|
47
|
+
return { allowed: false, limit, remaining: 0, resetAt, retryAfter: Math.max(1, Math.ceil((resetAt - t) / 1000)) };
|
|
48
|
+
}
|
|
49
|
+
return { allowed: true, limit, remaining: Math.max(0, Math.floor(limit - estimated - 1)), resetAt };
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
storeFailed('rate limit', err);
|
|
53
|
+
if (options.failureMode === 'closed')
|
|
54
|
+
return { allowed: false, limit, remaining: 0, resetAt, retryAfter: 1 };
|
|
55
|
+
return { allowed: true, limit, remaining: limit, resetAt };
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const limiter = ((req, res, next) => {
|
|
59
|
+
take(req).then((d) => {
|
|
60
|
+
setRateLimitHeaders(res, d.limit, d.remaining, d.resetAt);
|
|
61
|
+
if (!d.allowed) {
|
|
62
|
+
res.status(429).set('Retry-After', String(d.retryAfter)).json({
|
|
63
|
+
error: 'Too Many Requests',
|
|
64
|
+
message: `Rate limit of ${limit} requests per ${windowSeconds}s exceeded`,
|
|
65
|
+
retryAfter: d.retryAfter,
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
next();
|
|
70
|
+
}, next);
|
|
71
|
+
});
|
|
72
|
+
limiter.take = take;
|
|
73
|
+
limiter.close = () => { };
|
|
74
|
+
return limiter;
|
|
75
|
+
}
|
|
76
|
+
/** Brute-force lockout with failure counters and locks kept in the store. */
|
|
77
|
+
export class StoreAuthLockout {
|
|
78
|
+
store;
|
|
79
|
+
failureMode;
|
|
80
|
+
config;
|
|
81
|
+
total = 0;
|
|
82
|
+
recent = new Map();
|
|
83
|
+
constructor(config, store, failureMode = 'open') {
|
|
84
|
+
this.store = store;
|
|
85
|
+
this.failureMode = failureMode;
|
|
86
|
+
this.config = { ...DEFAULT_LOCKOUT, ...Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined)) };
|
|
87
|
+
}
|
|
88
|
+
async lockedFor(ip) {
|
|
89
|
+
try {
|
|
90
|
+
const ttl = await this.store.pttl(`lo:l:${ip}`);
|
|
91
|
+
return ttl > 0 ? Math.ceil(ttl / 1000) : ttl === -1 ? this.config.lockoutSeconds : 0;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
storeFailed('auth lockout', err);
|
|
95
|
+
return this.failureMode === 'closed' ? 1 : 0;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async fail(ip) {
|
|
99
|
+
try {
|
|
100
|
+
const n = await this.store.incr(`lo:f:${ip}`, this.config.windowSeconds * 1000);
|
|
101
|
+
if (n >= this.config.maxFailures) {
|
|
102
|
+
await this.store.set(`lo:l:${ip}`, '1', this.config.lockoutSeconds * 1000);
|
|
103
|
+
await this.store.del(`lo:f:${ip}`);
|
|
104
|
+
this.total++;
|
|
105
|
+
this.recent.set(ip, Date.now() + this.config.lockoutSeconds * 1000);
|
|
106
|
+
logger.warn(`Locked out ${ip} for ${this.config.lockoutSeconds}s after ${n} failed authentication attempts`);
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
storeFailed('auth lockout', err);
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
async success(ip) {
|
|
116
|
+
await this.store.del(`lo:f:${ip}`).catch((err) => storeFailed('auth lockout', err));
|
|
117
|
+
}
|
|
118
|
+
/** Lockouts triggered by this instance (the store holds the cluster-wide state). */
|
|
119
|
+
status() {
|
|
120
|
+
const t = Date.now();
|
|
121
|
+
for (const [ip, until] of this.recent)
|
|
122
|
+
if (until <= t)
|
|
123
|
+
this.recent.delete(ip);
|
|
124
|
+
return { lockedClients: this.recent.size, trackedClients: this.recent.size, lockoutsTotal: this.total, shared: true };
|
|
125
|
+
}
|
|
126
|
+
close() {
|
|
127
|
+
this.recent.clear();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/state/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,mBAAmB,EAA4C,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAE,eAAe,EAAuB,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAK5C,IAAI,gBAAgB,GAAG,CAAC,CAAC;AACzB,SAAS,WAAW,CAAC,IAAY,EAAE,GAAY;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACrB,IAAI,CAAC,GAAG,gBAAgB,GAAG,MAAM,EAAE,CAAC;QAClC,gBAAgB,GAAG,CAAC,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,4BAA4B,IAAI,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxG,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAuB,EACvB,KAAiB,EACjB,UAAiF,EAAE;IAEnF,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IACvD,MAAM,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAC;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAErC,MAAM,IAAI,GAAG,KAAK,EAAE,GAAY,EAA8B,EAAE;QAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAE,GAAuC,CAAC,QAAQ,IAAI,GAAG,CAAC,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAClH,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;QACvC,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,CAAC;QACrC,MAAM,OAAO,GAAG,WAAW,GAAG,QAAQ,CAAC;QACvC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,EAAE,IAAI,aAAa,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpH,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,QAAQ,CAAC;YACjD,MAAM,SAAS,GAAG,OAAO,GAAG,CAAC,GAAG,QAAQ,GAAG,OAAO,CAAC;YACnD,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;gBACvB,kDAAkD;gBAClD,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBACtE,MAAM,CAAC,IAAI,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;gBACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;YACpH,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QACtG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;YAC/B,IAAI,OAAO,CAAC,WAAW,KAAK,QAAQ;gBAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;YAC7G,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACnE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACnB,mBAAmB,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YAC1D,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;gBACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC5D,KAAK,EAAE,mBAAmB;oBAC1B,OAAO,EAAE,iBAAiB,KAAK,iBAAiB,aAAa,YAAY;oBACzE,UAAU,EAAE,CAAC,CAAC,UAAU;iBACzB,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,EAAE,CAAC;QACT,CAAC,EAAE,IAAI,CAAC,CAAC;IACX,CAAC,CAAgB,CAAC;IAClB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IACpB,OAAO,CAAC,KAAK,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IACzB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,6EAA6E;AAC7E,MAAM,OAAO,gBAAgB;IAOR;IACA;IAPV,MAAM,CAA8B;IACrC,KAAK,GAAG,CAAC,CAAC;IACD,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEpD,YACE,MAAyB,EACR,KAAiB,EACjB,cAA2B,MAAM;QADjC,UAAK,GAAL,KAAK,CAAY;QACjB,gBAAW,GAAX,WAAW,CAAsB;QAElD,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,EAAE,CAAC;IACzH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAChD,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QACvF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;YACjC,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU;QACnB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;YAChF,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;gBACjC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;gBAC3E,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBACnC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;gBACpE,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,IAAI,CAAC,MAAM,CAAC,cAAc,WAAW,CAAC,iCAAiC,CAAC,CAAC;gBAC7G,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,oFAAoF;IACpF,MAAM;QACJ,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,KAAK,IAAI,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9E,OAAO,EAAE,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACxH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable shared state for multi-instance deployments.
|
|
3
|
+
*
|
|
4
|
+
* Rate-limit windows, brute-force lockouts and MCP session metadata go
|
|
5
|
+
* through a `StateStore`. The default `MemoryStateStore` keeps everything in
|
|
6
|
+
* the process (single instance, the pre-1.4 behaviour); `RedisStateStore`
|
|
7
|
+
* (see `./redis.ts`) shares it between gateway replicas behind a load
|
|
8
|
+
* balancer, so limits hold cluster-wide and an MCP session opened on one
|
|
9
|
+
* replica is accepted by the others.
|
|
10
|
+
*
|
|
11
|
+
* @module state/store
|
|
12
|
+
*/
|
|
13
|
+
export interface StateStore {
|
|
14
|
+
/** `memory`, `redis`, or a custom name. */
|
|
15
|
+
readonly kind: string;
|
|
16
|
+
/**
|
|
17
|
+
* Atomically add `by` (default 1) to the integer at `key` and return the new
|
|
18
|
+
* value. A missing key starts at 0 and expires after `ttlMs`; an existing
|
|
19
|
+
* key keeps its expiry.
|
|
20
|
+
*/
|
|
21
|
+
incr(key: string, ttlMs: number, by?: number): Promise<number>;
|
|
22
|
+
get(key: string): Promise<string | undefined>;
|
|
23
|
+
/** Set `key` (optionally expiring after `ttlMs`). */
|
|
24
|
+
set(key: string, value: string, ttlMs?: number): Promise<void>;
|
|
25
|
+
del(key: string): Promise<void>;
|
|
26
|
+
/** Remaining time to live in ms; -1 = no expiry, -2 = missing. */
|
|
27
|
+
pttl(key: string): Promise<number>;
|
|
28
|
+
/** Health check (resolves when reachable). */
|
|
29
|
+
ping(): Promise<void>;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/** In-process store (default). */
|
|
33
|
+
export declare class MemoryStateStore implements StateStore {
|
|
34
|
+
private readonly now;
|
|
35
|
+
readonly kind = "memory";
|
|
36
|
+
private readonly data;
|
|
37
|
+
private readonly timer;
|
|
38
|
+
constructor(now?: () => number);
|
|
39
|
+
private live;
|
|
40
|
+
incr(key: string, ttlMs: number, by?: number): Promise<number>;
|
|
41
|
+
/** Synchronous variant (used by the in-memory fast paths). */
|
|
42
|
+
incrSync(key: string, ttlMs: number, by?: number): number;
|
|
43
|
+
get(key: string): Promise<string | undefined>;
|
|
44
|
+
set(key: string, value: string, ttlMs?: number): Promise<void>;
|
|
45
|
+
del(key: string): Promise<void>;
|
|
46
|
+
pttl(key: string): Promise<number>;
|
|
47
|
+
ping(): Promise<void>;
|
|
48
|
+
/** Number of live keys (tests / diagnostics). */
|
|
49
|
+
size(): number;
|
|
50
|
+
private sweep;
|
|
51
|
+
close(): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
/** Prefixes every key (namespacing several gateways in one Redis). */
|
|
54
|
+
export declare class PrefixedStateStore implements StateStore {
|
|
55
|
+
private readonly inner;
|
|
56
|
+
private readonly prefix;
|
|
57
|
+
constructor(inner: StateStore, prefix: string);
|
|
58
|
+
get kind(): string;
|
|
59
|
+
incr(key: string, ttlMs: number, by?: number): Promise<number>;
|
|
60
|
+
get(key: string): Promise<string | undefined>;
|
|
61
|
+
set(key: string, value: string, ttlMs?: number): Promise<void>;
|
|
62
|
+
del(key: string): Promise<void>;
|
|
63
|
+
pttl(key: string): Promise<number>;
|
|
64
|
+
ping(): Promise<void>;
|
|
65
|
+
close(): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/state/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC9C,qDAAqD;IACrD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,kEAAkE;IAClE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,8CAA8C;IAC9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAOD,kCAAkC;AAClC,qBAAa,gBAAiB,YAAW,UAAU;IAKrC,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJhC,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;gBAEV,GAAG,GAAE,MAAM,MAAiB;IAKzD,OAAO,CAAC,IAAI;IAUN,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,SAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAI/D,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,SAAI,GAAG,MAAM;IAW9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAI7C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAE3B,iDAAiD;IACjD,IAAI,IAAI,MAAM;IAKd,OAAO,CAAC,KAAK;IAKP,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B;AAED,sEAAsE;AACtE,qBAAa,kBAAmB,YAAW,UAAU;IAEjD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM;IAEjC,IAAI,IAAI,IAAI,MAAM,CAEjB;IACD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM;IAG5C,GAAG,CAAC,GAAG,EAAE,MAAM;IAGf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAG9C,GAAG,CAAC,GAAG,EAAE,MAAM;IAGf,IAAI,CAAC,GAAG,EAAE,MAAM;IAGhB,IAAI;IAGJ,KAAK;CAGN"}
|