@blen/fedreg-mcp-server 2.0.10 → 2.1.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 +13 -1
- package/README.md +17 -2
- package/dist/accounts/app.d.ts +16 -0
- package/dist/accounts/app.d.ts.map +1 -0
- package/dist/accounts/app.js +352 -0
- package/dist/accounts/app.js.map +1 -0
- package/dist/accounts/config.d.ts +16 -0
- package/dist/accounts/config.d.ts.map +1 -0
- package/dist/accounts/config.js +50 -0
- package/dist/accounts/config.js.map +1 -0
- package/dist/accounts/crypto.d.ts +18 -0
- package/dist/accounts/crypto.d.ts.map +1 -0
- package/dist/accounts/crypto.js +43 -0
- package/dist/accounts/crypto.js.map +1 -0
- package/dist/accounts/portal.d.ts +8 -0
- package/dist/accounts/portal.d.ts.map +1 -0
- package/dist/accounts/portal.js +170 -0
- package/dist/accounts/portal.js.map +1 -0
- package/dist/accounts/provider.d.ts +2568 -0
- package/dist/accounts/provider.d.ts.map +1 -0
- package/dist/accounts/provider.js +107 -0
- package/dist/accounts/provider.js.map +1 -0
- package/dist/accounts/runtime.d.ts +16 -0
- package/dist/accounts/runtime.d.ts.map +1 -0
- package/dist/accounts/runtime.js +122 -0
- package/dist/accounts/runtime.js.map +1 -0
- package/dist/accounts/store.d.ts +25 -0
- package/dist/accounts/store.d.ts.map +1 -0
- package/dist/accounts/store.js +142 -0
- package/dist/accounts/store.js.map +1 -0
- package/dist/bin.js +31 -18
- package/dist/bin.js.map +1 -1
- package/dist/sdk/bindings.js +1 -1
- package/dist/sdk/bindings.js.map +1 -1
- package/dist/sdk/sources/corpus-loader.d.ts +3 -1
- package/dist/sdk/sources/corpus-loader.d.ts.map +1 -1
- package/dist/sdk/sources/corpus-loader.js +10 -2
- package/dist/sdk/sources/corpus-loader.js.map +1 -1
- package/dist/sdk/sources/ecfr.d.ts.map +1 -1
- package/dist/sdk/sources/ecfr.js +2 -0
- package/dist/sdk/sources/ecfr.js.map +1 -1
- package/dist/sdk/sources/fr.d.ts.map +1 -1
- package/dist/sdk/sources/fr.js +2 -0
- package/dist/sdk/sources/fr.js.map +1 -1
- package/dist/sdk/sources/regs.js +1 -1
- package/dist/sdk/sources/regs.js.map +1 -1
- package/dist/sdk/sources/source.d.ts +5 -4
- package/dist/sdk/sources/source.d.ts.map +1 -1
- package/dist/server/http.js +3 -3
- package/dist/server/http.js.map +1 -1
- package/dist/server/mcpServer.js +2 -2
- package/dist/server/mcpServer.js.map +1 -1
- package/dist/server/stdio.js +1 -1
- package/dist/server/stdio.js.map +1 -1
- package/dist/server/toolCatalog.d.ts +3 -1
- package/dist/server/toolCatalog.d.ts.map +1 -1
- package/dist/server/toolCatalog.js.map +1 -1
- package/dist/server/zodToJsonSchema.d.ts +1 -1
- package/dist/server/zodToJsonSchema.d.ts.map +1 -1
- package/dist/supervisor/index.d.ts +11 -0
- package/dist/supervisor/index.d.ts.map +1 -1
- package/dist/supervisor/index.js +16 -1
- package/dist/supervisor/index.js.map +1 -1
- package/dist/tools/describeSchema.d.ts +1 -1
- package/dist/tools/describeSchema.d.ts.map +1 -1
- package/dist/tools/describeSchema.js +1 -1
- package/dist/tools/describeSchema.js.map +1 -1
- package/dist/tools/execute.d.ts +7 -2
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/execute.js +15 -4
- package/dist/tools/execute.js.map +1 -1
- package/dist/tools/searchApi.d.ts +1 -1
- package/dist/tools/searchApi.d.ts.map +1 -1
- package/dist/tools/searchApi.js +1 -1
- package/dist/tools/searchApi.js.map +1 -1
- package/dist/util/httpClient.d.ts +30 -4
- package/dist/util/httpClient.d.ts.map +1 -1
- package/dist/util/httpClient.js +121 -50
- package/dist/util/httpClient.js.map +1 -1
- package/dist/util/logger.js +7 -1
- package/dist/util/logger.js.map +1 -1
- package/dist/util/upstreamGate.d.ts +28 -0
- package/dist/util/upstreamGate.d.ts.map +1 -0
- package/dist/util/upstreamGate.js +74 -0
- package/dist/util/upstreamGate.js.map +1 -0
- package/dist/web/assets/blen-logo-BKJFojyj.png +0 -0
- package/dist/web/assets/index--Hn7cjpj.js +299 -0
- package/dist/web/assets/index-bNtg7OeV.css +2 -0
- package/dist/web/index.html +14 -0
- package/package.json +35 -7
package/dist/util/httpClient.js
CHANGED
|
@@ -14,8 +14,13 @@ export class HttpClient {
|
|
|
14
14
|
timeoutMs;
|
|
15
15
|
retries;
|
|
16
16
|
retry429;
|
|
17
|
+
maxRetryAfterMs;
|
|
17
18
|
dispatcher;
|
|
18
19
|
preflightLimiter;
|
|
20
|
+
gate;
|
|
21
|
+
label;
|
|
22
|
+
/** Identical GETs already on the wire; later callers share the first one's result. */
|
|
23
|
+
inflight = new Map();
|
|
19
24
|
constructor(opts) {
|
|
20
25
|
this.#defaultHeaders = opts.defaultHeaders ?? {};
|
|
21
26
|
this.baseUrl = opts.baseUrl;
|
|
@@ -23,8 +28,11 @@ export class HttpClient {
|
|
|
23
28
|
this.timeoutMs = opts.timeoutMs ?? 20_000;
|
|
24
29
|
this.retries = opts.retries ?? 3;
|
|
25
30
|
this.retry429 = opts.retry429 ?? true;
|
|
31
|
+
this.maxRetryAfterMs = opts.maxRetryAfterMs ?? 5000;
|
|
26
32
|
this.dispatcher = opts.dispatcher;
|
|
27
33
|
this.preflightLimiter = opts.preflightLimiter;
|
|
34
|
+
this.gate = opts.gate;
|
|
35
|
+
this.label = opts.label ?? new URL(opts.baseUrl).host;
|
|
28
36
|
const max = opts.cacheMaxItems ?? 2000;
|
|
29
37
|
const ttl = opts.cacheTtlMs ?? 300_000;
|
|
30
38
|
this.cacheEnabled = max > 0 && ttl > 0;
|
|
@@ -33,78 +41,120 @@ export class HttpClient {
|
|
|
33
41
|
async call(o) {
|
|
34
42
|
const url = this.buildUrl(o.path, o.query);
|
|
35
43
|
const method = o.method ?? 'GET';
|
|
36
|
-
const key = method === 'GET'
|
|
37
|
-
if (key && this.cache.has(key)) {
|
|
44
|
+
const key = method === 'GET' ? this.cacheKey(url, o.headers) : '';
|
|
45
|
+
if (key && this.cacheEnabled && this.cache.has(key)) {
|
|
38
46
|
log.debug('http.cache_hit', { url });
|
|
39
47
|
return this.cache.get(key).body;
|
|
40
48
|
}
|
|
49
|
+
// Join an identical request already on the wire rather than queueing a second one.
|
|
50
|
+
const pending = key ? this.inflight.get(key) : undefined;
|
|
51
|
+
if (pending)
|
|
52
|
+
return pending;
|
|
53
|
+
const run = this.fetchWithRetry(url, method, o, key);
|
|
54
|
+
if (key) {
|
|
55
|
+
this.inflight.set(key, run);
|
|
56
|
+
run.then(() => this.inflight.delete(key), () => this.inflight.delete(key));
|
|
57
|
+
}
|
|
58
|
+
return run;
|
|
59
|
+
}
|
|
60
|
+
async fetchWithRetry(url, method, o, key) {
|
|
41
61
|
const accept = o.accept === 'xml' ? 'application/xml,text/xml'
|
|
42
62
|
: o.accept === 'text' ? 'text/plain'
|
|
43
63
|
: 'application/json';
|
|
44
|
-
if (this.preflightLimiter && !this.preflightLimiter.tryTake()) {
|
|
64
|
+
if (this.preflightLimiter && !(await this.preflightLimiter.tryTake())) {
|
|
45
65
|
const wait = this.preflightLimiter.secondsUntilNext?.() ?? 0;
|
|
46
66
|
const err = new HttpError(`${method} ${url} -> upstream rate limit reached${Number.isFinite(wait) && wait > 0 ? ` (retry in ~${wait}s)` : ''}`, 429, '');
|
|
47
67
|
err.name = 'RegsRateLimited';
|
|
48
68
|
throw err;
|
|
49
69
|
}
|
|
50
70
|
let attempt = 0;
|
|
51
|
-
let
|
|
52
|
-
|
|
71
|
+
let retried429 = false;
|
|
72
|
+
for (;;) {
|
|
53
73
|
try {
|
|
54
|
-
|
|
55
|
-
method,
|
|
56
|
-
headers: {
|
|
57
|
-
'accept': accept,
|
|
58
|
-
'user-agent': this.userAgent,
|
|
59
|
-
...this.#defaultHeaders,
|
|
60
|
-
...(o.body ? { 'content-type': 'application/json' } : {}),
|
|
61
|
-
...(o.headers ?? {}),
|
|
62
|
-
},
|
|
63
|
-
body: o.body ? JSON.stringify(o.body) : undefined,
|
|
64
|
-
bodyTimeout: this.timeoutMs,
|
|
65
|
-
headersTimeout: this.timeoutMs,
|
|
66
|
-
...(this.dispatcher ? { dispatcher: this.dispatcher } : {}),
|
|
67
|
-
});
|
|
68
|
-
// undici.request returns raw bytes, unlike fetch. Decode before parsing,
|
|
69
|
-
// reporting upstream errors, or caching the response.
|
|
70
|
-
const encoding = res.headers['content-encoding'];
|
|
71
|
-
const decoded = typeof encoding === 'string' && encoding.trim().toLowerCase() === 'gzip'
|
|
72
|
-
? new TextDecoder().decode(await decompressGzip(Buffer.from(await res.body.arrayBuffer())))
|
|
73
|
-
: undefined;
|
|
74
|
-
if (res.statusCode >= 400) {
|
|
75
|
-
const text = decoded ?? await res.body.text();
|
|
76
|
-
const err = new HttpError(`${method} ${url} -> ${res.statusCode}`, res.statusCode, text);
|
|
77
|
-
if (res.statusCode === 429) {
|
|
78
|
-
const retryAfter = Array.isArray(res.headers['retry-after']) ? res.headers['retry-after'][0] : res.headers['retry-after'];
|
|
79
|
-
err.name = 'RateLimited';
|
|
80
|
-
err.message = `${method} ${url} -> 429 Too Many Requests${retryAfter ? ` (retry-after ${retryAfter})` : ''}`;
|
|
81
|
-
}
|
|
82
|
-
throw err;
|
|
83
|
-
}
|
|
84
|
-
let body;
|
|
85
|
-
if (accept.startsWith('application/json'))
|
|
86
|
-
body = decoded === undefined ? await res.body.json() : JSON.parse(decoded);
|
|
87
|
-
else
|
|
88
|
-
body = decoded ?? await res.body.text();
|
|
89
|
-
const headers = {};
|
|
90
|
-
for (const [k, v] of Object.entries(res.headers))
|
|
91
|
-
headers[k] = Array.isArray(v) ? v.join(',') : String(v ?? '');
|
|
92
|
-
if (key)
|
|
93
|
-
this.cache.set(key, { status: res.statusCode, body, headers });
|
|
94
|
-
return body;
|
|
74
|
+
return await this.attempt(url, method, o, accept, key);
|
|
95
75
|
}
|
|
96
76
|
catch (err) {
|
|
97
|
-
|
|
77
|
+
if (err instanceof GateTimeoutError)
|
|
78
|
+
throw err;
|
|
98
79
|
const status = err instanceof HttpError ? err.status : 0;
|
|
99
|
-
|
|
80
|
+
if (status === 429) {
|
|
81
|
+
const pauseMs = Math.min(err.retryAfterMs ?? 1000, this.maxRetryAfterMs);
|
|
82
|
+
// Back off every caller of this upstream, not just this one.
|
|
83
|
+
this.gate?.pause(pauseMs);
|
|
84
|
+
if (!this.retry429 || retried429)
|
|
85
|
+
throw err;
|
|
86
|
+
retried429 = true;
|
|
87
|
+
await new Promise(r => setTimeout(r, pauseMs));
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const retryable = status === 0 || status >= 500;
|
|
100
91
|
if (!retryable || attempt === this.retries)
|
|
101
|
-
|
|
92
|
+
throw err;
|
|
102
93
|
const delay = Math.min(2 ** attempt * 250, 4000);
|
|
103
94
|
await new Promise(r => setTimeout(r, delay));
|
|
104
95
|
attempt++;
|
|
105
96
|
}
|
|
106
97
|
}
|
|
107
|
-
|
|
98
|
+
}
|
|
99
|
+
/** One request, holding a gate slot only while it is on the wire. */
|
|
100
|
+
async attempt(url, method, o, accept, key) {
|
|
101
|
+
let release;
|
|
102
|
+
if (this.gate) {
|
|
103
|
+
try {
|
|
104
|
+
release = await this.gate.acquire();
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
throw new GateTimeoutError(`${this.label} is busy: too many requests from this server are waiting. Make fewer parallel calls or retry shortly.`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const res = await request(url, {
|
|
112
|
+
method,
|
|
113
|
+
headers: {
|
|
114
|
+
'accept': accept,
|
|
115
|
+
'user-agent': this.userAgent,
|
|
116
|
+
...this.#defaultHeaders,
|
|
117
|
+
...(o.body ? { 'content-type': 'application/json' } : {}),
|
|
118
|
+
...(o.headers ?? {}),
|
|
119
|
+
},
|
|
120
|
+
body: o.body ? JSON.stringify(o.body) : undefined,
|
|
121
|
+
bodyTimeout: this.timeoutMs,
|
|
122
|
+
headersTimeout: this.timeoutMs,
|
|
123
|
+
...(this.dispatcher ? { dispatcher: this.dispatcher } : {}),
|
|
124
|
+
});
|
|
125
|
+
// undici.request returns raw bytes, unlike fetch. Decode before parsing,
|
|
126
|
+
// reporting upstream errors, or caching the response.
|
|
127
|
+
const encoding = res.headers['content-encoding'];
|
|
128
|
+
const decoded = typeof encoding === 'string' && encoding.trim().toLowerCase() === 'gzip'
|
|
129
|
+
? new TextDecoder().decode(await decompressGzip(Buffer.from(await res.body.arrayBuffer())))
|
|
130
|
+
: undefined;
|
|
131
|
+
if (res.statusCode >= 400) {
|
|
132
|
+
const text = decoded ?? await res.body.text();
|
|
133
|
+
const err = new HttpError(`${method} ${url} -> ${res.statusCode}`, res.statusCode, text);
|
|
134
|
+
if (res.statusCode === 429) {
|
|
135
|
+
const retryAfter = Array.isArray(res.headers['retry-after']) ? res.headers['retry-after'][0] : res.headers['retry-after'];
|
|
136
|
+
err.name = 'RateLimited';
|
|
137
|
+
err.retryAfterMs = parseRetryAfter(retryAfter);
|
|
138
|
+
err.message = `${this.label} is rate limiting this server: ${method} ${url} -> 429 Too Many Requests${retryAfter ? ` (retry-after ${retryAfter})` : ''}`;
|
|
139
|
+
log.warn('upstream.rate_limited', { source: this.label, host: new URL(url).host, ...(retryAfter ? { retryAfter } : {}) });
|
|
140
|
+
}
|
|
141
|
+
throw err;
|
|
142
|
+
}
|
|
143
|
+
let body;
|
|
144
|
+
if (accept.startsWith('application/json'))
|
|
145
|
+
body = decoded === undefined ? await res.body.json() : JSON.parse(decoded);
|
|
146
|
+
else
|
|
147
|
+
body = decoded ?? await res.body.text();
|
|
148
|
+
const headers = {};
|
|
149
|
+
for (const [k, v] of Object.entries(res.headers))
|
|
150
|
+
headers[k] = Array.isArray(v) ? v.join(',') : String(v ?? '');
|
|
151
|
+
if (key && this.cacheEnabled)
|
|
152
|
+
this.cache.set(key, { status: res.statusCode, body, headers });
|
|
153
|
+
return body;
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
release?.();
|
|
157
|
+
}
|
|
108
158
|
}
|
|
109
159
|
cacheKey(url, perCallHeaders) {
|
|
110
160
|
const merged = { ...this.#defaultHeaders, ...(perCallHeaders ?? {}) };
|
|
@@ -135,9 +185,23 @@ export class HttpClient {
|
|
|
135
185
|
return url.toString();
|
|
136
186
|
}
|
|
137
187
|
}
|
|
188
|
+
/** Retry-After as milliseconds: delta-seconds or an HTTP date; undefined if absent or invalid. */
|
|
189
|
+
function parseRetryAfter(value) {
|
|
190
|
+
if (!value)
|
|
191
|
+
return undefined;
|
|
192
|
+
const v = value.trim();
|
|
193
|
+
// Check numerics first: Date.parse('1.5') is a valid date in V8 (2001), not 1.5 seconds.
|
|
194
|
+
if (/^\d+(\.\d+)?$/.test(v))
|
|
195
|
+
return Number(v) * 1000;
|
|
196
|
+
if (/^[\d.]+$/.test(v))
|
|
197
|
+
return undefined;
|
|
198
|
+
const at = Date.parse(v);
|
|
199
|
+
return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());
|
|
200
|
+
}
|
|
138
201
|
export class HttpError extends Error {
|
|
139
202
|
status;
|
|
140
203
|
bodySnippet;
|
|
204
|
+
retryAfterMs;
|
|
141
205
|
constructor(message, status, bodySnippet) {
|
|
142
206
|
super(message);
|
|
143
207
|
this.status = status;
|
|
@@ -145,4 +209,11 @@ export class HttpError extends Error {
|
|
|
145
209
|
this.name = 'HttpError';
|
|
146
210
|
}
|
|
147
211
|
}
|
|
212
|
+
/** No gate slot freed up within maxWaitMs. Never retried: the queue is already full. */
|
|
213
|
+
class GateTimeoutError extends HttpError {
|
|
214
|
+
constructor(message) {
|
|
215
|
+
super(message, 429, '');
|
|
216
|
+
this.name = 'RateLimited';
|
|
217
|
+
}
|
|
218
|
+
}
|
|
148
219
|
//# sourceMappingURL=httpClient.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpClient.js","sourceRoot":"","sources":["../../src/util/httpClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"httpClient.js","sourceRoot":"","sources":["../../src/util/httpClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;AAwCzC,MAAM,OAAO,UAAU;IACrB,eAAe,CAAyB;IACvB,KAAK,CAAuF;IAC5F,YAAY,CAAU;IACtB,OAAO,CAAS;IAChB,SAAS,CAAS;IAClB,SAAS,CAAS;IAClB,OAAO,CAAS;IAChB,QAAQ,CAAU;IAClB,eAAe,CAAS;IACxB,UAAU,CAAc;IACxB,gBAAgB,CAAoB;IACpC,IAAI,CAAoB;IACxB,KAAK,CAAS;IAC/B,sFAAsF;IACrE,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEhE,YAAY,IAAuB;QACjC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,cAAc,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,yEAAyE,CAAC;QAC7G,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;QACtC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC;QACpD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;QACtD,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC;QACvC,IAAI,CAAC,YAAY,GAAG,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,IAAI,CAAc,CAAc;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,IAAI,GAAG,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YACrC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAS,CAAC;QACxC,CAAC;QACD,mFAAmF;QACnF,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,IAAI,OAAO;YAAE,OAAO,OAAqB,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAI,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QACxD,IAAI,GAAG,EAAE,CAAC;YACR,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,cAAc,CAAI,GAAW,EAAE,MAAsB,EAAE,CAAc,EAAE,GAAW;QAC9F,MAAM,MAAM,GACV,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,0BAA0B;YAC/C,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY;gBACpC,CAAC,CAAC,kBAAkB,CAAC;QAEvB,IAAI,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,EAAE,IAAI,CAAC,CAAC;YAC7D,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,kCAAkC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACzJ,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC;YAC7B,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,SAAS,CAAC;YACR,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;YAC5D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,gBAAgB;oBAAE,MAAM,GAAG,CAAC;gBAC/C,MAAM,MAAM,GAAG,GAAG,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBACzD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;oBACnB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAE,GAAiB,CAAC,YAAY,IAAI,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;oBACxF,6DAA6D;oBAC7D,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,UAAU;wBAAE,MAAM,GAAG,CAAC;oBAC5C,UAAU,GAAG,IAAI,CAAC;oBAClB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;oBAC/C,SAAS;gBACX,CAAC;gBACD,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC;gBAChD,IAAI,CAAC,SAAS,IAAI,OAAO,KAAK,IAAI,CAAC,OAAO;oBAAE,MAAM,GAAG,CAAC;gBACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC;gBACjD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC7C,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAED,qEAAqE;IAC7D,KAAK,CAAC,OAAO,CAAI,GAAW,EAAE,MAAsB,EAAE,CAAc,EAAE,MAAc,EAAE,GAAW;QACvG,IAAI,OAAiC,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,gBAAgB,CAAC,GAAG,IAAI,CAAC,KAAK,uGAAuG,CAAC,CAAC;YACnJ,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;gBAC7B,MAAM;gBACN,OAAO,EAAE;oBACP,QAAQ,EAAE,MAAM;oBAChB,YAAY,EAAE,IAAI,CAAC,SAAS;oBAC5B,GAAG,IAAI,CAAC,eAAe;oBACvB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACzD,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;iBACrB;gBACD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;gBACjD,WAAW,EAAE,IAAI,CAAC,SAAS;gBAC3B,cAAc,EAAE,IAAI,CAAC,SAAS;gBAC9B,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5D,CAAC,CAAC;YAEH,yEAAyE;YACzE,sDAAsD;YACtD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,MAAM;gBACtF,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;gBAC3F,CAAC,CAAC,SAAS,CAAC;YAEd,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;gBAC1B,MAAM,IAAI,GAAG,OAAO,IAAI,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC9C,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,GAAG,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;gBACzF,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;oBAC3B,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;oBAC1H,GAAG,CAAC,IAAI,GAAG,aAAa,CAAC;oBACzB,GAAG,CAAC,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;oBAC/C,GAAG,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,KAAK,kCAAkC,MAAM,IAAI,GAAG,4BAA4B,UAAU,CAAC,CAAC,CAAC,iBAAiB,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBACzJ,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC5H,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,IAAI,IAAa,CAAC;YAClB,IAAI,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC;gBAAE,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;;gBACjH,IAAI,GAAG,OAAO,IAAI,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7C,MAAM,OAAO,GAA2B,EAAE,CAAC;YAC3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAChH,IAAI,GAAG,IAAI,IAAI,CAAC,YAAY;gBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAC7F,OAAO,IAAS,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAEO,QAAQ,CAAC,GAAW,EAAE,cAAuC;QACnE,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,EAAE,CAAC;QACtE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC,CAAC,mCAAmC;QACzE,MAAM,UAAU,GAA2B,EAAE,CAAC;QAC9C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YAAE,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;QACrG,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChG,OAAO,GAAG,GAAG,KAAK,IAAI,EAAE,CAAC;IAC3B,CAAC;IAEO,QAAQ,CAAC,IAAY,EAAE,KAA4B;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;oBAAE,SAAS;gBAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;oBAAE,KAAK,MAAM,IAAI,IAAI,CAAC;wBAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;;oBAChF,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;CACF;AAED,kGAAkG;AAClG,SAAS,eAAe,CAAC,KAAyB;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACvB,yFAAyF;IACzF,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACrD,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,OAAO,SAAU,SAAQ,KAAK;IAEW;IAAgC;IAD7E,YAAY,CAAU;IACtB,YAAY,OAAe,EAAkB,MAAc,EAAkB,WAAmB;QAC9F,KAAK,CAAC,OAAO,CAAC,CAAC;QAD4B,WAAM,GAAN,MAAM,CAAQ;QAAkB,gBAAW,GAAX,WAAW,CAAQ;QAE9F,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,wFAAwF;AACxF,MAAM,gBAAiB,SAAQ,SAAS;IACtC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
|
package/dist/util/logger.js
CHANGED
|
@@ -9,10 +9,16 @@ export const log = {
|
|
|
9
9
|
warn: (msg, extra) => write('warn', msg, extra),
|
|
10
10
|
error: (msg, extra) => write('error', msg, extra),
|
|
11
11
|
};
|
|
12
|
+
const RESERVED = new Set(['t', 'level', 'msg', 'message', 'timestamp']);
|
|
12
13
|
function write(level, msg, extra) {
|
|
13
14
|
if (order[level] < order[envLevel()])
|
|
14
15
|
return;
|
|
15
|
-
const
|
|
16
|
+
const fields = {};
|
|
17
|
+
// Extras never overwrite the envelope. `message`/`timestamp` are reserved too: log
|
|
18
|
+
// platforms (Railway) map `msg` onto `message`, which would silently drop an extra `message`.
|
|
19
|
+
for (const [k, v] of Object.entries(extra ?? {}))
|
|
20
|
+
fields[RESERVED.has(k) ? `extra_${k}` : k] = v;
|
|
21
|
+
const line = JSON.stringify({ t: new Date().toISOString(), level, msg, ...fields });
|
|
16
22
|
// stdio transport reserves stdout for JSON-RPC; log to stderr.
|
|
17
23
|
process.stderr.write(line + '\n');
|
|
18
24
|
}
|
package/dist/util/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/util/logger.ts"],"names":[],"mappings":"AACA,MAAM,KAAK,GAA0B,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAElF,SAAS,QAAQ;IACf,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IACjE,OAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAa,CAAC,QAAQ,CAAC,CAAU,CAAC,CAAC,CAAC,CAAE,CAAW,CAAC,CAAC,CAAC,MAAM,CAAC;AACtG,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,KAAK,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;IACnF,IAAI,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;IACjF,IAAI,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;IACjF,KAAK,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;CACpF,CAAC;AAEF,SAAS,KAAK,CAAC,KAAY,EAAE,GAAW,EAAE,KAA+B;IACvE,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAAE,OAAO;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/util/logger.ts"],"names":[],"mappings":"AACA,MAAM,KAAK,GAA0B,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAElF,SAAS,QAAQ;IACf,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IACjE,OAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAa,CAAC,QAAQ,CAAC,CAAU,CAAC,CAAC,CAAC,CAAE,CAAW,CAAC,CAAC,CAAC,MAAM,CAAC;AACtG,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,KAAK,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;IACnF,IAAI,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;IACjF,IAAI,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;IACjF,KAAK,EAAE,CAAC,GAAW,EAAE,KAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;CACpF,CAAC;AAEF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;AAExE,SAAS,KAAK,CAAC,KAAY,EAAE,GAAW,EAAE,KAA+B;IACvE,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAAE,OAAO;IAC7C,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,mFAAmF;IACnF,8FAA8F;IAC9F,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjG,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IACpF,+DAA+D;IAC/D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared admission control for one upstream API: at most `concurrency` requests in flight,
|
|
3
|
+
* started no faster than `ratePerSec` (bursting to `burst`). Every user's calls leave from
|
|
4
|
+
* the same server IP, so this is the server's whole footprint on that API. Callers wait
|
|
5
|
+
* for a slot instead of failing, but never longer than `maxWaitMs`; a 429 pauses new
|
|
6
|
+
* starts so concurrent callers back off together.
|
|
7
|
+
*/
|
|
8
|
+
export declare class UpstreamGate {
|
|
9
|
+
private readonly opts;
|
|
10
|
+
private active;
|
|
11
|
+
private tokens;
|
|
12
|
+
private updatedAt;
|
|
13
|
+
private pausedUntil;
|
|
14
|
+
private readonly queue;
|
|
15
|
+
private wake?;
|
|
16
|
+
constructor(opts: {
|
|
17
|
+
concurrency: number;
|
|
18
|
+
ratePerSec: number;
|
|
19
|
+
burst: number;
|
|
20
|
+
maxWaitMs: number;
|
|
21
|
+
});
|
|
22
|
+
/** Resolves with a release function once the request may start. */
|
|
23
|
+
acquire(): Promise<() => void>;
|
|
24
|
+
/** Stop starting requests for `ms` (an upstream 429 asked us to slow down). */
|
|
25
|
+
pause(ms: number): void;
|
|
26
|
+
private drain;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=upstreamGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstreamGate.d.ts","sourceRoot":"","sources":["../../src/util/upstreamGate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,qBAAa,YAAY;IASrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IARvB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8G;IACpI,OAAO,CAAC,IAAI,CAAC,CAAiB;gBAGX,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAKtG,mEAAmE;IACnE,OAAO,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;IAa9B,+EAA+E;IAC/E,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IASvB,OAAO,CAAC,KAAK;CAgCd"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared admission control for one upstream API: at most `concurrency` requests in flight,
|
|
3
|
+
* started no faster than `ratePerSec` (bursting to `burst`). Every user's calls leave from
|
|
4
|
+
* the same server IP, so this is the server's whole footprint on that API. Callers wait
|
|
5
|
+
* for a slot instead of failing, but never longer than `maxWaitMs`; a 429 pauses new
|
|
6
|
+
* starts so concurrent callers back off together.
|
|
7
|
+
*/
|
|
8
|
+
export class UpstreamGate {
|
|
9
|
+
opts;
|
|
10
|
+
active = 0;
|
|
11
|
+
tokens;
|
|
12
|
+
updatedAt = Date.now();
|
|
13
|
+
pausedUntil = 0;
|
|
14
|
+
queue = [];
|
|
15
|
+
wake;
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
this.opts = opts;
|
|
18
|
+
this.tokens = opts.burst;
|
|
19
|
+
}
|
|
20
|
+
/** Resolves with a release function once the request may start. */
|
|
21
|
+
acquire() {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const timer = setTimeout(() => {
|
|
24
|
+
const i = this.queue.findIndex(w => w.timer === timer);
|
|
25
|
+
if (i >= 0)
|
|
26
|
+
this.queue.splice(i, 1);
|
|
27
|
+
reject(new Error(`waited ${this.opts.maxWaitMs}ms for an upstream slot`));
|
|
28
|
+
}, this.opts.maxWaitMs);
|
|
29
|
+
timer.unref?.();
|
|
30
|
+
this.queue.push({ resolve, reject, timer });
|
|
31
|
+
this.drain();
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** Stop starting requests for `ms` (an upstream 429 asked us to slow down). */
|
|
35
|
+
pause(ms) {
|
|
36
|
+
this.pausedUntil = Math.max(this.pausedUntil, Date.now() + ms);
|
|
37
|
+
// Resume at the steady rate: no burst accrues while paused, so the pause does not
|
|
38
|
+
// end with `concurrency` requests hitting the API that just throttled us.
|
|
39
|
+
this.tokens = Math.min(this.tokens, 1);
|
|
40
|
+
this.updatedAt = Math.max(this.updatedAt, this.pausedUntil);
|
|
41
|
+
this.drain();
|
|
42
|
+
}
|
|
43
|
+
drain() {
|
|
44
|
+
while (this.queue.length && this.active < this.opts.concurrency) {
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
// updatedAt sits in the future during a pause; accrue nothing until it passes.
|
|
47
|
+
if (now > this.updatedAt) {
|
|
48
|
+
this.tokens = Math.min(this.opts.burst, this.tokens + ((now - this.updatedAt) / 1000) * this.opts.ratePerSec);
|
|
49
|
+
this.updatedAt = now;
|
|
50
|
+
}
|
|
51
|
+
const waitMs = Math.max(this.pausedUntil - now, this.tokens >= 1 ? 0 : ((1 - this.tokens) / this.opts.ratePerSec) * 1000);
|
|
52
|
+
if (waitMs > 0) {
|
|
53
|
+
if (!this.wake) {
|
|
54
|
+
this.wake = setTimeout(() => { this.wake = undefined; this.drain(); }, Math.ceil(waitMs));
|
|
55
|
+
this.wake.unref?.();
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.tokens -= 1;
|
|
60
|
+
this.active++;
|
|
61
|
+
const waiter = this.queue.shift();
|
|
62
|
+
clearTimeout(waiter.timer);
|
|
63
|
+
let released = false;
|
|
64
|
+
waiter.resolve(() => {
|
|
65
|
+
if (released)
|
|
66
|
+
return;
|
|
67
|
+
released = true;
|
|
68
|
+
this.active--;
|
|
69
|
+
this.drain();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=upstreamGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstreamGate.js","sourceRoot":"","sources":["../../src/util/upstreamGate.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|