@j0hanz/fetch-url-mcp 1.12.3 → 1.12.5
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/dist/http/auth.d.ts.map +1 -1
- package/dist/http/auth.js +44 -29
- package/dist/http/helpers.d.ts.map +1 -1
- package/dist/http/helpers.js +22 -12
- package/dist/http/native.d.ts.map +1 -1
- package/dist/http/native.js +30 -29
- package/dist/http/rate-limit.d.ts.map +1 -1
- package/dist/http/rate-limit.js +5 -3
- package/dist/index.js +3 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +11 -7
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +12 -9
- package/dist/lib/error-codes.d.ts +11 -0
- package/dist/lib/error-codes.d.ts.map +1 -0
- package/dist/lib/error-codes.js +15 -0
- package/dist/lib/error-messages.d.ts +13 -0
- package/dist/lib/error-messages.d.ts.map +1 -0
- package/dist/lib/error-messages.js +51 -0
- package/dist/lib/fetch-pipeline.d.ts.map +1 -1
- package/dist/lib/fetch-pipeline.js +5 -4
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +80 -41
- package/dist/lib/logger-names.d.ts +14 -0
- package/dist/lib/logger-names.d.ts.map +1 -0
- package/dist/lib/logger-names.js +13 -0
- package/dist/lib/mcp-interop.d.ts +1 -11
- package/dist/lib/mcp-interop.d.ts.map +1 -1
- package/dist/lib/mcp-interop.js +10 -73
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/session.js +2 -1
- package/dist/lib/tool-errors.d.ts +39 -0
- package/dist/lib/tool-errors.d.ts.map +1 -0
- package/dist/lib/tool-errors.js +252 -0
- package/dist/lib/url.d.ts.map +1 -1
- package/dist/lib/url.js +18 -15
- package/dist/lib/utils.d.ts +4 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +18 -9
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +3 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -6
- package/dist/tasks/call-contract.d.ts.map +1 -1
- package/dist/tasks/call-contract.js +9 -11
- package/dist/tasks/execution.d.ts.map +1 -1
- package/dist/tasks/execution.js +17 -14
- package/dist/tasks/handlers.d.ts.map +1 -1
- package/dist/tasks/handlers.js +9 -8
- package/dist/tasks/manager.d.ts.map +1 -1
- package/dist/tasks/manager.js +14 -13
- package/dist/tasks/owner.d.ts +0 -1
- package/dist/tasks/owner.d.ts.map +1 -1
- package/dist/tasks/owner.js +0 -25
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +15 -27
- package/dist/transform/dom-prep.d.ts.map +1 -1
- package/dist/transform/dom-prep.js +10 -8
- package/dist/transform/shared.d.ts.map +1 -1
- package/dist/transform/shared.js +2 -1
- package/dist/transform/transform.d.ts.map +1 -1
- package/dist/transform/transform.js +29 -21
- package/dist/transform/worker-pool.d.ts.map +1 -1
- package/dist/transform/worker-pool.js +16 -12
- package/package.json +1 -1
package/dist/lib/config.js
CHANGED
|
@@ -16,16 +16,16 @@ function hasPackageJsonVersion(value) {
|
|
|
16
16
|
function readServerVersion(moduleUrl) {
|
|
17
17
|
const packageJsonPath = findPackageJSON(moduleUrl);
|
|
18
18
|
if (!packageJsonPath)
|
|
19
|
-
throw
|
|
19
|
+
throw Error('package.json not found');
|
|
20
20
|
let packageJson;
|
|
21
21
|
try {
|
|
22
22
|
packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
throw
|
|
25
|
+
throw Error(`Failed to parse package.json at ${packageJsonPath}: ${getErrorMessage(error)}`, { cause: error });
|
|
26
26
|
}
|
|
27
27
|
if (!hasPackageJsonVersion(packageJson)) {
|
|
28
|
-
throw
|
|
28
|
+
throw Error(`package.json version is missing at ${packageJsonPath}`);
|
|
29
29
|
}
|
|
30
30
|
return packageJson.version;
|
|
31
31
|
}
|
|
@@ -184,14 +184,17 @@ const EnvParser = {
|
|
|
184
184
|
if (!value)
|
|
185
185
|
return undefined;
|
|
186
186
|
const parsed = URL.parse(value);
|
|
187
|
-
if (!parsed)
|
|
188
|
-
|
|
187
|
+
if (!parsed) {
|
|
188
|
+
const error = new ConfigError(`Invalid ${name} value: ${value}`);
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
189
191
|
return parsed;
|
|
190
192
|
},
|
|
191
193
|
allowedHosts(envValue) {
|
|
192
|
-
|
|
194
|
+
const hosts = new Set(EnvParser.list(envValue)
|
|
193
195
|
.map((h) => EnvParser.normalizeHostValue(h))
|
|
194
196
|
.filter((h) => h !== null));
|
|
197
|
+
return hosts;
|
|
195
198
|
},
|
|
196
199
|
optionalFilePath(value) {
|
|
197
200
|
const trimmed = value?.trim();
|
|
@@ -303,7 +306,8 @@ function buildHttpsConfig() {
|
|
|
303
306
|
const certFile = EnvParser.optionalFilePath(env['SERVER_TLS_CERT_FILE']);
|
|
304
307
|
const caFile = EnvParser.optionalFilePath(env['SERVER_TLS_CA_FILE']);
|
|
305
308
|
if ((keyFile && !certFile) || (!keyFile && certFile)) {
|
|
306
|
-
|
|
309
|
+
const error = new ConfigError('Both SERVER_TLS_KEY_FILE and SERVER_TLS_CERT_FILE must be set together');
|
|
310
|
+
throw error;
|
|
307
311
|
}
|
|
308
312
|
return {
|
|
309
313
|
enabled: Boolean(keyFile && certFile),
|
package/dist/lib/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/lib/core.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/lib/core.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/core.js
CHANGED
|
@@ -3,6 +3,7 @@ import process from 'node:process';
|
|
|
3
3
|
import { getSystemErrorMessage, inspect, stripVTControlCharacters, } from 'node:util';
|
|
4
4
|
import {} from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
5
|
import { config } from './config.js';
|
|
6
|
+
import { LOG_SESSION } from './logger-names.js';
|
|
6
7
|
import { getErrorMessage, isAbortError, startAbortableIntervalLoop, } from './utils.js';
|
|
7
8
|
export { config, enableHttpMode, serverVersion } from './config.js';
|
|
8
9
|
const requestContext = new AsyncLocalStorage({
|
|
@@ -225,7 +226,8 @@ function formatMetadata(meta) {
|
|
|
225
226
|
return ` ${inspect(merged, { breakLength: Infinity, colors: false, compact: true, sorted: true })}`;
|
|
226
227
|
}
|
|
227
228
|
function createTimestamp() {
|
|
228
|
-
|
|
229
|
+
const now = new Date();
|
|
230
|
+
return now.toISOString();
|
|
229
231
|
}
|
|
230
232
|
function formatLogEntry(level, message, meta, logger) {
|
|
231
233
|
if (config.logging.format === 'json') {
|
|
@@ -511,12 +513,12 @@ function getCleanupIntervalMs(sessionTtlMs) {
|
|
|
511
513
|
function handleSessionCleanupError(error) {
|
|
512
514
|
if (isAbortError(error))
|
|
513
515
|
return;
|
|
514
|
-
logWarn('Session cleanup loop failed', { error: getErrorMessage(error) },
|
|
516
|
+
logWarn('Session cleanup loop failed', { error: getErrorMessage(error) }, LOG_SESSION);
|
|
515
517
|
}
|
|
516
518
|
function logRejectedSettledResults(results, message) {
|
|
517
519
|
for (const result of results) {
|
|
518
520
|
if (result.status === 'rejected') {
|
|
519
|
-
logWarn(message, { error: getErrorMessage(result.reason) },
|
|
521
|
+
logWarn(message, { error: getErrorMessage(result.reason) }, LOG_SESSION);
|
|
520
522
|
}
|
|
521
523
|
}
|
|
522
524
|
}
|
|
@@ -556,7 +558,7 @@ class SessionCleanupLoop {
|
|
|
556
558
|
logInfo('Expired sessions evicted', {
|
|
557
559
|
evicted: evicted.length,
|
|
558
560
|
timestamp: new Date(now).toISOString(),
|
|
559
|
-
},
|
|
561
|
+
}, LOG_SESSION);
|
|
560
562
|
}
|
|
561
563
|
}
|
|
562
564
|
async closeExpiredSession(sessionId, session) {
|
|
@@ -567,7 +569,7 @@ class SessionCleanupLoop {
|
|
|
567
569
|
catch (error) {
|
|
568
570
|
logWarn('Expired session pre-close hook failed', {
|
|
569
571
|
error: getErrorMessage(error),
|
|
570
|
-
},
|
|
572
|
+
}, LOG_SESSION);
|
|
571
573
|
}
|
|
572
574
|
}
|
|
573
575
|
const closePromise = Promise.allSettled([
|
|
@@ -596,7 +598,7 @@ class SessionCleanupLoop {
|
|
|
596
598
|
catch (error) {
|
|
597
599
|
logWarn('Session close operation failed or timed out', {
|
|
598
600
|
error: getErrorMessage(error),
|
|
599
|
-
},
|
|
601
|
+
}, LOG_SESSION);
|
|
600
602
|
}
|
|
601
603
|
finally {
|
|
602
604
|
if (timeoutId) {
|
|
@@ -609,7 +611,7 @@ class SessionCleanupLoop {
|
|
|
609
611
|
catch (error) {
|
|
610
612
|
logWarn('Failed to unregister session server', {
|
|
611
613
|
error: getErrorMessage(error),
|
|
612
|
-
},
|
|
614
|
+
}, LOG_SESSION);
|
|
613
615
|
}
|
|
614
616
|
}
|
|
615
617
|
logCloseFailure(target, error) {
|
|
@@ -617,9 +619,10 @@ class SessionCleanupLoop {
|
|
|
617
619
|
return;
|
|
618
620
|
logWarn(`Failed to close expired session ${target}`, {
|
|
619
621
|
error: getErrorMessage(error),
|
|
620
|
-
},
|
|
622
|
+
}, LOG_SESSION);
|
|
621
623
|
}
|
|
622
624
|
}
|
|
623
625
|
export function startSessionCleanupLoop(store, sessionTtlMs, options) {
|
|
624
|
-
|
|
626
|
+
const loop = new SessionCleanupLoop(store, sessionTtlMs, options?.onEvictSession, options?.cleanupIntervalMs);
|
|
627
|
+
return loop.start();
|
|
625
628
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const EBLOCKED = "EBLOCKED";
|
|
2
|
+
export declare const ETIMEOUT = "ETIMEOUT";
|
|
3
|
+
export declare const EINVAL = "EINVAL";
|
|
4
|
+
export declare const ENODATA = "ENODATA";
|
|
5
|
+
export declare const EBADREDIRECT = "EBADREDIRECT";
|
|
6
|
+
export declare const EUNSUPPORTEDPROTOCOL = "EUNSUPPORTEDPROTOCOL";
|
|
7
|
+
export declare const FETCH_ERROR = "FETCH_ERROR";
|
|
8
|
+
export declare const ABORTED = "ABORTED";
|
|
9
|
+
export declare const QUEUE_FULL = "queue_full";
|
|
10
|
+
export declare const VALIDATION_ERROR = "VALIDATION_ERROR";
|
|
11
|
+
//# sourceMappingURL=error-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../../src/lib/error-codes.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,aAAa,CAAC;AACnC,eAAO,MAAM,QAAQ,aAAa,CAAC;AACnC,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,OAAO,YAAY,CAAC;AAGjC,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAG3D,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,OAAO,YAAY,CAAC;AACjC,eAAO,MAAM,UAAU,eAAe,CAAC;AAGvC,eAAO,MAAM,gBAAgB,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// ── Error codes ────────────────────────────────
|
|
2
|
+
// DNS / network resolution
|
|
3
|
+
export const EBLOCKED = 'EBLOCKED';
|
|
4
|
+
export const ETIMEOUT = 'ETIMEOUT';
|
|
5
|
+
export const EINVAL = 'EINVAL';
|
|
6
|
+
export const ENODATA = 'ENODATA';
|
|
7
|
+
// HTTP redirect
|
|
8
|
+
export const EBADREDIRECT = 'EBADREDIRECT';
|
|
9
|
+
export const EUNSUPPORTEDPROTOCOL = 'EUNSUPPORTEDPROTOCOL';
|
|
10
|
+
// Fetch pipeline
|
|
11
|
+
export const FETCH_ERROR = 'FETCH_ERROR';
|
|
12
|
+
export const ABORTED = 'ABORTED';
|
|
13
|
+
export const QUEUE_FULL = 'queue_full';
|
|
14
|
+
// Validation
|
|
15
|
+
export const VALIDATION_ERROR = 'VALIDATION_ERROR';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CodedError } from './utils.js';
|
|
2
|
+
export declare function blockedIpError(target: string, reason: 'cloud-metadata' | 'private'): CodedError;
|
|
3
|
+
export declare function blockedHostError(hostname: string): CodedError;
|
|
4
|
+
export declare function blockedCnameError(hostname: string, cname: string): CodedError;
|
|
5
|
+
export declare function dnsTimeoutError(hostname: string): CodedError;
|
|
6
|
+
export declare function dnsNoResultsError(hostname: string): CodedError;
|
|
7
|
+
export declare function invalidAddressFamilyError(hostname: string): CodedError;
|
|
8
|
+
export declare function invalidHostnameError(): CodedError;
|
|
9
|
+
export declare function invalidUrlError(): CodedError;
|
|
10
|
+
export declare function invalidRedirectError(): CodedError;
|
|
11
|
+
export declare function redirectCredentialsError(): CodedError;
|
|
12
|
+
export declare function unsupportedProtocolError(protocol: string): CodedError;
|
|
13
|
+
//# sourceMappingURL=error-messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-messages.d.ts","sourceRoot":"","sources":["../../src/lib/error-messages.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAIxC,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,UAAU,CAUZ;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAM7D;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAM7E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAM5D;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAM9D;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAMtE;AAED,wBAAgB,oBAAoB,IAAI,UAAU,CAGjD;AAED,wBAAgB,eAAe,IAAI,UAAU,CAG5C;AAID,wBAAgB,oBAAoB,IAAI,UAAU,CAGjD;AAED,wBAAgB,wBAAwB,IAAI,UAAU,CAMrD;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAMrE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { EBADREDIRECT, EBLOCKED, EINVAL, ENODATA, ETIMEOUT, EUNSUPPORTEDPROTOCOL, } from './error-codes.js';
|
|
2
|
+
import { CodedError } from './utils.js';
|
|
3
|
+
// ── DNS / Network ──────────────────────────────────────────────────
|
|
4
|
+
export function blockedIpError(target, reason) {
|
|
5
|
+
const detail = reason === 'cloud-metadata'
|
|
6
|
+
? 'Cloud metadata endpoints are not allowed'
|
|
7
|
+
: 'Private IPs are not allowed';
|
|
8
|
+
const error = new CodedError(`Blocked IP range: ${target}. ${detail}`, EBLOCKED);
|
|
9
|
+
return error;
|
|
10
|
+
}
|
|
11
|
+
export function blockedHostError(hostname) {
|
|
12
|
+
const error = new CodedError(`Blocked host: ${hostname}. Internal hosts are not allowed`, EBLOCKED);
|
|
13
|
+
return error;
|
|
14
|
+
}
|
|
15
|
+
export function blockedCnameError(hostname, cname) {
|
|
16
|
+
const error = new CodedError(`Blocked DNS CNAME detected for ${hostname}: ${cname}`, EBLOCKED);
|
|
17
|
+
return error;
|
|
18
|
+
}
|
|
19
|
+
export function dnsTimeoutError(hostname) {
|
|
20
|
+
const error = new CodedError(`DNS lookup timed out for ${hostname}`, ETIMEOUT);
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
export function dnsNoResultsError(hostname) {
|
|
24
|
+
const error = new CodedError(`No DNS results returned for ${hostname}`, ENODATA);
|
|
25
|
+
return error;
|
|
26
|
+
}
|
|
27
|
+
export function invalidAddressFamilyError(hostname) {
|
|
28
|
+
const error = new CodedError(`Invalid address family returned for ${hostname}`, EINVAL);
|
|
29
|
+
return error;
|
|
30
|
+
}
|
|
31
|
+
export function invalidHostnameError() {
|
|
32
|
+
const error = new CodedError('Invalid hostname provided', EINVAL);
|
|
33
|
+
return error;
|
|
34
|
+
}
|
|
35
|
+
export function invalidUrlError() {
|
|
36
|
+
const error = new CodedError('Invalid URL', EINVAL);
|
|
37
|
+
return error;
|
|
38
|
+
}
|
|
39
|
+
// ── HTTP Redirect ──────────────────────────────────────────────────
|
|
40
|
+
export function invalidRedirectError() {
|
|
41
|
+
const error = new CodedError('Invalid redirect target', EBADREDIRECT);
|
|
42
|
+
return error;
|
|
43
|
+
}
|
|
44
|
+
export function redirectCredentialsError() {
|
|
45
|
+
const error = new CodedError('Redirect target includes credentials', EBADREDIRECT);
|
|
46
|
+
return error;
|
|
47
|
+
}
|
|
48
|
+
export function unsupportedProtocolError(protocol) {
|
|
49
|
+
const error = new CodedError(`Unsupported redirect protocol: ${protocol}`, EUNSUPPORTEDPROTOCOL);
|
|
50
|
+
return error;
|
|
51
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-pipeline.d.ts","sourceRoot":"","sources":["../../src/lib/fetch-pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"fetch-pipeline.d.ts","sourceRoot":"","sources":["../../src/lib/fetch-pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAQrE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,CAAC;AAGtB,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AACD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAmGD,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,MAAM,GAAG,SAAS,CAQpB;AAyBD,UAAU,oBAAoB,CAAC,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,SAAS,EAAE,CAAC,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxE;AACD,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC;IACR,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,iBAAiB,CAAC;AAmBtB,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC/B,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAiD5B;AAED,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAwBF,eAAO,MAAM,iBAAiB,GAC5B,OAAO,mBAAmB,EAC1B,KAAK,MAAM,EACX,SAAS,WAAW,KACnB,OAAO,CAAC,sBAAsB,CAchC,CAAC;AAEF,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,SAAS,EAAE,CAClB,KAAK,EAAE,mBAAmB,EAC1B,aAAa,EAAE,MAAM,KAClB,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC/D;AACD,UAAU,eAAe;IACvB,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,oBAAoB,CAAC;CAC7D;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC;IACT,QAAQ,EAAE,cAAc,CAAC,sBAAsB,CAAC,CAAC;IACjD,YAAY,EAAE,mBAAmB,CAAC;CACnC,CAAC,CAyBD"}
|
|
@@ -2,6 +2,7 @@ import { transformBufferToMarkdown } from '../transform/transform.js';
|
|
|
2
2
|
import {} from '../transform/types.js';
|
|
3
3
|
import { config, logDebug } from './core.js';
|
|
4
4
|
import { fetchNormalizedUrlBuffer, normalizeUrl, transformToRawUrl, } from './http.js';
|
|
5
|
+
import { LOG_FETCH } from './logger-names.js';
|
|
5
6
|
import { withSignal } from './utils.js';
|
|
6
7
|
export { withSignal };
|
|
7
8
|
const TRUNCATION_MARKER = '...[truncated]';
|
|
@@ -116,16 +117,16 @@ export async function executeFetchPipeline(options) {
|
|
|
116
117
|
if (resolvedUrl.transformed) {
|
|
117
118
|
logDebug('Using transformed raw content URL', {
|
|
118
119
|
original: resolvedUrl.originalUrl,
|
|
119
|
-
},
|
|
120
|
+
}, LOG_FETCH);
|
|
120
121
|
}
|
|
121
122
|
options.onStage?.('fetch_remote');
|
|
122
|
-
logDebug('Fetching URL', { url: resolvedUrl.normalizedUrl },
|
|
123
|
+
logDebug('Fetching URL', { url: resolvedUrl.normalizedUrl }, LOG_FETCH);
|
|
123
124
|
const { buffer, encoding, truncated, finalUrl } = await fetchNormalizedUrlBuffer(resolvedUrl.normalizedUrl, withSignal(options.signal));
|
|
124
125
|
if (finalUrl && finalUrl !== resolvedUrl.normalizedUrl) {
|
|
125
126
|
logDebug('Fetch redirected', {
|
|
126
127
|
fromUrl: resolvedUrl.normalizedUrl,
|
|
127
128
|
toUrl: finalUrl,
|
|
128
|
-
},
|
|
129
|
+
}, LOG_FETCH);
|
|
129
130
|
}
|
|
130
131
|
options.onStage?.('response_ready');
|
|
131
132
|
options.onStage?.('transform_start');
|
|
@@ -177,7 +178,7 @@ export async function performSharedFetch(options, deps = {}) {
|
|
|
177
178
|
url: pipeline.finalUrl ?? pipeline.url,
|
|
178
179
|
contentSize: inlineResult.contentSize,
|
|
179
180
|
maxInlineChars: config.constants.maxInlineContentChars,
|
|
180
|
-
},
|
|
181
|
+
}, LOG_FETCH);
|
|
181
182
|
}
|
|
182
183
|
return { pipeline, inlineResult };
|
|
183
184
|
}
|
package/dist/lib/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/lib/http.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAmB,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/lib/http.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAmB,MAAM,QAAQ,CAAC;AAyBhD,OAAO,EAOL,KAAK,eAAe,EAErB,MAAM,UAAU,CAAC;AAkxClB,UAAU,qBAAqB;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAoKD,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA6ND,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE/C;AACD,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAEA;AACD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjE;AACD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAE9D;AACD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAExD;AACD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,qBAAqB,CAEvB;AACD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,qBAAqB,EAC9B,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAEN;AACD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAEN;AACD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAE7D;AACD,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CASzC;AACD,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,MAAM,CAAC,CAEjB;AACD,wBAAsB,wBAAwB,CAC5C,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC;IACT,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAED"}
|
package/dist/lib/http.js
CHANGED
|
@@ -8,9 +8,12 @@ import tls from 'node:tls';
|
|
|
8
8
|
import { createBrotliDecompress, createGunzip, createInflate } from 'node:zlib';
|
|
9
9
|
import { Agent } from 'undici';
|
|
10
10
|
import { config, getOperationId, getRequestId, logDebug, logError, logWarn, redactUrl, } from './core.js';
|
|
11
|
+
import { EBADREDIRECT, EBLOCKED, EINVAL, ENODATA, VALIDATION_ERROR, } from './error-codes.js';
|
|
12
|
+
import { invalidRedirectError, redirectCredentialsError, unsupportedProtocolError, } from './error-messages.js';
|
|
13
|
+
import { LOG_FETCH } from './logger-names.js';
|
|
11
14
|
import { isIP } from './url.js';
|
|
12
|
-
import { BLOCKED_HOST_SUFFIXES, createDnsPreflight, IpBlocker, RawUrlTransformer, SafeDnsResolver, UrlNormalizer,
|
|
13
|
-
import { composeAbortSignal,
|
|
15
|
+
import { BLOCKED_HOST_SUFFIXES, createDnsPreflight, IpBlocker, RawUrlTransformer, SafeDnsResolver, UrlNormalizer, } from './url.js';
|
|
16
|
+
import { composeAbortSignal, FetchError, isAbortError, isError, isObject, isSystemError, toError, } from './utils.js';
|
|
14
17
|
// ═══════════════════════════════════════════════════════════════════
|
|
15
18
|
// ENCODING DETECTION
|
|
16
19
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -234,7 +237,10 @@ function isBinaryContent(buffer, encoding) {
|
|
|
234
237
|
return hasNullByte(buffer, BINARY_SCAN_LIMIT);
|
|
235
238
|
}
|
|
236
239
|
function createBinaryContentError(url) {
|
|
237
|
-
|
|
240
|
+
const error = new FetchError('Binary content detected', url, 500, {
|
|
241
|
+
reason: 'binary_content_detected',
|
|
242
|
+
});
|
|
243
|
+
return error;
|
|
238
244
|
}
|
|
239
245
|
// ═══════════════════════════════════════════════════════════════════
|
|
240
246
|
// FETCH ERRORS
|
|
@@ -257,28 +263,50 @@ function parseRetryAfter(header) {
|
|
|
257
263
|
}
|
|
258
264
|
function createFetchError(input, url) {
|
|
259
265
|
switch (input.kind) {
|
|
260
|
-
case 'canceled':
|
|
261
|
-
|
|
266
|
+
case 'canceled': {
|
|
267
|
+
const error = new FetchError('Request canceled', url, 499, {
|
|
268
|
+
reason: 'aborted',
|
|
269
|
+
});
|
|
270
|
+
return error;
|
|
271
|
+
}
|
|
272
|
+
case 'aborted': {
|
|
273
|
+
const error = new FetchError('Request aborted during response read', url, 499, {
|
|
262
274
|
reason: 'aborted',
|
|
263
275
|
});
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
case 'timeout':
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
276
|
+
return error;
|
|
277
|
+
}
|
|
278
|
+
case 'timeout': {
|
|
279
|
+
const error = new FetchError(`Request timed out after ${input.timeout}ms`, url, 504, { timeout: input.timeout });
|
|
280
|
+
return error;
|
|
281
|
+
}
|
|
282
|
+
case 'rate-limited': {
|
|
283
|
+
const error = new FetchError('Too many requests', url, 429, {
|
|
270
284
|
retryAfter: parseRetryAfter(input.retryAfter),
|
|
271
285
|
});
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
case '
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
case '
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
286
|
+
return error;
|
|
287
|
+
}
|
|
288
|
+
case 'http': {
|
|
289
|
+
const error = new FetchError(`HTTP ${input.status}: ${input.statusText}`, url, input.status);
|
|
290
|
+
return error;
|
|
291
|
+
}
|
|
292
|
+
case 'too-many-redirects': {
|
|
293
|
+
const error = new FetchError('Too many redirects', url);
|
|
294
|
+
return error;
|
|
295
|
+
}
|
|
296
|
+
case 'missing-redirect-location': {
|
|
297
|
+
const error = new FetchError('Redirect missing Location header', url);
|
|
298
|
+
return error;
|
|
299
|
+
}
|
|
300
|
+
case 'network': {
|
|
301
|
+
const error = new FetchError('Network error', url, undefined, {
|
|
302
|
+
message: input.message,
|
|
303
|
+
});
|
|
304
|
+
return error;
|
|
305
|
+
}
|
|
306
|
+
case 'unknown': {
|
|
307
|
+
const error = new FetchError(input.message ?? 'Unexpected error', url);
|
|
308
|
+
return error;
|
|
309
|
+
}
|
|
282
310
|
default: {
|
|
283
311
|
const _exhaustive = input;
|
|
284
312
|
return _exhaustive;
|
|
@@ -297,11 +325,11 @@ function resolveErrorUrl(error, fallback) {
|
|
|
297
325
|
return typeof requestUrl === 'string' ? requestUrl : fallback;
|
|
298
326
|
}
|
|
299
327
|
const CLIENT_ERROR_CODES = new Set([
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
328
|
+
VALIDATION_ERROR,
|
|
329
|
+
EBADREDIRECT,
|
|
330
|
+
EBLOCKED,
|
|
331
|
+
ENODATA,
|
|
332
|
+
EINVAL,
|
|
305
333
|
]);
|
|
306
334
|
function mapAbortError(error, timeoutMs, url) {
|
|
307
335
|
return isTimeoutError(error)
|
|
@@ -311,10 +339,12 @@ function mapAbortError(error, timeoutMs, url) {
|
|
|
311
339
|
function mapSystemError(error, url) {
|
|
312
340
|
const { code, message } = error;
|
|
313
341
|
if (code === 'ETIMEOUT') {
|
|
314
|
-
|
|
342
|
+
const fetchError = new FetchError(message, url, 504, { code });
|
|
343
|
+
return fetchError;
|
|
315
344
|
}
|
|
316
345
|
if (code && CLIENT_ERROR_CODES.has(code)) {
|
|
317
|
-
|
|
346
|
+
const fetchError = new FetchError(message, url, 400, { code });
|
|
347
|
+
return fetchError;
|
|
318
348
|
}
|
|
319
349
|
return createFetchError({ kind: 'network', message }, url);
|
|
320
350
|
}
|
|
@@ -354,7 +384,7 @@ class MaxBytesError extends Error {
|
|
|
354
384
|
}
|
|
355
385
|
function createPinnedAgent(ipAddress) {
|
|
356
386
|
const ca = tls.rootCertificates.length > 0 ? tls.rootCertificates : undefined;
|
|
357
|
-
|
|
387
|
+
const agent = new Agent({
|
|
358
388
|
connect: {
|
|
359
389
|
lookup: (hostname, options, callback) => {
|
|
360
390
|
const family = isIP(ipAddress) === 6 ? 6 : 4;
|
|
@@ -373,6 +403,7 @@ function createPinnedAgent(ipAddress) {
|
|
|
373
403
|
keepAliveTimeout: 1000,
|
|
374
404
|
keepAliveMaxTimeout: 1000,
|
|
375
405
|
});
|
|
406
|
+
return agent;
|
|
376
407
|
}
|
|
377
408
|
class RedirectFollower {
|
|
378
409
|
fetchFn;
|
|
@@ -457,10 +488,10 @@ class RedirectFollower {
|
|
|
457
488
|
resolveRedirectTarget(baseUrl, location) {
|
|
458
489
|
const resolved = URL.parse(location, baseUrl);
|
|
459
490
|
if (!resolved) {
|
|
460
|
-
throw
|
|
491
|
+
throw invalidRedirectError();
|
|
461
492
|
}
|
|
462
493
|
if (resolved.username || resolved.password) {
|
|
463
|
-
throw
|
|
494
|
+
throw redirectCredentialsError();
|
|
464
495
|
}
|
|
465
496
|
return this.normalizeUrl(resolved.href);
|
|
466
497
|
}
|
|
@@ -472,7 +503,7 @@ class RedirectFollower {
|
|
|
472
503
|
assertHttpProtocol(url) {
|
|
473
504
|
const parsed = new URL(url);
|
|
474
505
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
475
|
-
throw
|
|
506
|
+
throw unsupportedProtocolError(parsed.protocol);
|
|
476
507
|
}
|
|
477
508
|
}
|
|
478
509
|
async withRedirectErrorContext(url, fn) {
|
|
@@ -536,11 +567,12 @@ function assertSupportedContentType(contentType, url) {
|
|
|
536
567
|
if (!mediaType) {
|
|
537
568
|
logDebug('No Content-Type header; relying on binary-content detection', {
|
|
538
569
|
url: redactUrl(url),
|
|
539
|
-
},
|
|
570
|
+
}, LOG_FETCH);
|
|
540
571
|
return;
|
|
541
572
|
}
|
|
542
573
|
if (!isTextLikeMediaType(mediaType)) {
|
|
543
|
-
|
|
574
|
+
const error = new FetchError(`Unsupported content type: ${mediaType}`, url);
|
|
575
|
+
throw error;
|
|
544
576
|
}
|
|
545
577
|
}
|
|
546
578
|
function extractEncodingTokens(value) {
|
|
@@ -561,10 +593,11 @@ function isSupportedContentEncoding(encoding) {
|
|
|
561
593
|
return encoding === 'gzip' || encoding === 'deflate' || encoding === 'br';
|
|
562
594
|
}
|
|
563
595
|
function createUnsupportedContentEncodingError(url, encodingHeader) {
|
|
564
|
-
|
|
596
|
+
const error = new FetchError(`Unsupported Content-Encoding: ${encodingHeader}`, url, 415, {
|
|
565
597
|
reason: 'unsupported_content_encoding',
|
|
566
598
|
encoding: encodingHeader,
|
|
567
599
|
});
|
|
600
|
+
return error;
|
|
568
601
|
}
|
|
569
602
|
function createDecompressor(encoding) {
|
|
570
603
|
const options = { chunkSize: 64 * 1024 };
|
|
@@ -578,7 +611,7 @@ function createDecompressor(encoding) {
|
|
|
578
611
|
}
|
|
579
612
|
}
|
|
580
613
|
function createPumpedStream(initialChunk, reader) {
|
|
581
|
-
|
|
614
|
+
const stream = new ReadableStream({
|
|
582
615
|
start(controller) {
|
|
583
616
|
if (initialChunk && initialChunk.byteLength > 0) {
|
|
584
617
|
controller.enqueue(initialChunk);
|
|
@@ -602,6 +635,7 @@ function createPumpedStream(initialChunk, reader) {
|
|
|
602
635
|
void reader.cancel(reason).catch(() => undefined);
|
|
603
636
|
},
|
|
604
637
|
});
|
|
638
|
+
return stream;
|
|
605
639
|
}
|
|
606
640
|
function buildDecodePipeline(body, encodings, url, response, signal) {
|
|
607
641
|
const decodeOrder = encodings.slice().reverse();
|
|
@@ -656,11 +690,12 @@ async function primeDecodedResponse(pipe, response, url, signal) {
|
|
|
656
690
|
const first = await pipe.decodedReader.read();
|
|
657
691
|
if (first.done) {
|
|
658
692
|
clearAbortListener();
|
|
659
|
-
|
|
693
|
+
const result = new Response(null, {
|
|
660
694
|
status: response.status,
|
|
661
695
|
statusText: response.statusText,
|
|
662
696
|
headers: pipe.headers,
|
|
663
697
|
});
|
|
698
|
+
return result;
|
|
664
699
|
}
|
|
665
700
|
const body = createPumpedStream(first.value, pipe.decodedReader);
|
|
666
701
|
if (signal) {
|
|
@@ -670,17 +705,19 @@ async function primeDecodedResponse(pipe, response, url, signal) {
|
|
|
670
705
|
clearAbortListener();
|
|
671
706
|
});
|
|
672
707
|
}
|
|
673
|
-
|
|
708
|
+
const result = new Response(body, {
|
|
674
709
|
status: response.status,
|
|
675
710
|
statusText: response.statusText,
|
|
676
711
|
headers: pipe.headers,
|
|
677
712
|
});
|
|
713
|
+
return result;
|
|
678
714
|
}
|
|
679
715
|
catch (error) {
|
|
680
716
|
clearAbortListener();
|
|
681
717
|
pipe.cleanup();
|
|
682
718
|
void pipe.decodedReader.cancel(error).catch(() => undefined);
|
|
683
|
-
|
|
719
|
+
const fetchError = new FetchError(`Content-Encoding decode failed for ${redactUrl(url)}: ${isError(error) ? error.message : String(error)}`, url);
|
|
720
|
+
throw fetchError;
|
|
684
721
|
}
|
|
685
722
|
}
|
|
686
723
|
async function decodeResponseIfNeeded(response, url, signal) {
|
|
@@ -780,7 +817,8 @@ class ResponseTextReader {
|
|
|
780
817
|
total += remaining;
|
|
781
818
|
yield slice;
|
|
782
819
|
}
|
|
783
|
-
|
|
820
|
+
const error = new MaxBytesError();
|
|
821
|
+
throw error;
|
|
784
822
|
}
|
|
785
823
|
total = newTotal;
|
|
786
824
|
yield buf;
|
|
@@ -860,10 +898,11 @@ function isReadableStreamLike(value) {
|
|
|
860
898
|
function assertReadableStreamLike(stream, url, stage) {
|
|
861
899
|
if (isReadableStreamLike(stream))
|
|
862
900
|
return;
|
|
863
|
-
|
|
901
|
+
const error = new FetchError('Invalid response stream', url, 500, {
|
|
864
902
|
reason: 'invalid_stream',
|
|
865
903
|
stage,
|
|
866
904
|
});
|
|
905
|
+
throw error;
|
|
867
906
|
}
|
|
868
907
|
function toNodeReadableStream(stream, url, stage) {
|
|
869
908
|
assertReadableStreamLike(stream, url, stage);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger names for different components of the application.
|
|
3
|
+
*/
|
|
4
|
+
export declare const LOG_AUTH = "auth";
|
|
5
|
+
export declare const LOG_HTTP = "http";
|
|
6
|
+
export declare const LOG_SESSION = "session";
|
|
7
|
+
export declare const LOG_SERVER = "server";
|
|
8
|
+
export declare const LOG_FETCH = "fetch";
|
|
9
|
+
export declare const LOG_TRANSFORM = "transform";
|
|
10
|
+
export declare const LOG_TASKS = "tasks";
|
|
11
|
+
export declare const LOG_RATE_LIMIT = "rate-limit";
|
|
12
|
+
export declare const LOG_MCP = "mcp";
|
|
13
|
+
export declare const LOG_FETCH_URL = "fetch-url";
|
|
14
|
+
//# sourceMappingURL=logger-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-names.d.ts","sourceRoot":"","sources":["../../src/lib/logger-names.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,WAAW,YAAY,CAAC;AACrC,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,aAAa,cAAc,CAAC;AACzC,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,OAAO,QAAQ,CAAC;AAC7B,eAAO,MAAM,aAAa,cAAc,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger names for different components of the application.
|
|
3
|
+
*/
|
|
4
|
+
export const LOG_AUTH = 'auth';
|
|
5
|
+
export const LOG_HTTP = 'http';
|
|
6
|
+
export const LOG_SESSION = 'session';
|
|
7
|
+
export const LOG_SERVER = 'server';
|
|
8
|
+
export const LOG_FETCH = 'fetch';
|
|
9
|
+
export const LOG_TRANSFORM = 'transform';
|
|
10
|
+
export const LOG_TASKS = 'tasks';
|
|
11
|
+
export const LOG_RATE_LIMIT = 'rate-limit';
|
|
12
|
+
export const LOG_MCP = 'mcp';
|
|
13
|
+
export const LOG_FETCH_URL = 'fetch-url';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import {
|
|
2
|
+
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
export declare function createMcpError(code: number, message: string, data?: unknown): McpError;
|
|
5
5
|
export type JsonRpcId = string | number | null;
|
|
@@ -53,16 +53,6 @@ export declare function isJsonRpcResponseBody(body: unknown): body is JsonRpcRes
|
|
|
53
53
|
export declare function isMcpMessageBody(body: unknown): body is JsonRpcMessageBody;
|
|
54
54
|
export declare function acceptsEventStream(header: string | null | undefined): boolean;
|
|
55
55
|
export declare function acceptsJsonAndEventStream(header: string | null | undefined): boolean;
|
|
56
|
-
type ToolErrorResponse = CallToolResult & {
|
|
57
|
-
isError: true;
|
|
58
|
-
};
|
|
59
|
-
export declare function createToolErrorResponse(message: string, url: string, extra?: {
|
|
60
|
-
code?: string | number;
|
|
61
|
-
statusCode?: number;
|
|
62
|
-
details?: Record<string, unknown>;
|
|
63
|
-
data?: unknown;
|
|
64
|
-
}): ToolErrorResponse;
|
|
65
|
-
export declare function handleToolError(error: unknown, url: string, fallbackMessage?: string): ToolErrorResponse;
|
|
66
56
|
type CleanupCallback = () => void;
|
|
67
57
|
type RequestHandlerFn = (request: unknown, extra?: unknown) => Promise<unknown>;
|
|
68
58
|
interface ToolPresentation {
|