@j0hanz/fetch-url-mcp 1.12.4 → 1.12.6
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 +74 -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 +8 -10
- 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 +14 -26
- 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,9 +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, {
|
|
238
241
|
reason: 'binary_content_detected',
|
|
239
242
|
});
|
|
243
|
+
return error;
|
|
240
244
|
}
|
|
241
245
|
// ═══════════════════════════════════════════════════════════════════
|
|
242
246
|
// FETCH ERRORS
|
|
@@ -259,32 +263,50 @@ function parseRetryAfter(header) {
|
|
|
259
263
|
}
|
|
260
264
|
function createFetchError(input, url) {
|
|
261
265
|
switch (input.kind) {
|
|
262
|
-
case 'canceled':
|
|
263
|
-
|
|
266
|
+
case 'canceled': {
|
|
267
|
+
const error = new FetchError('Request canceled', url, 499, {
|
|
264
268
|
reason: 'aborted',
|
|
265
269
|
});
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
return error;
|
|
271
|
+
}
|
|
272
|
+
case 'aborted': {
|
|
273
|
+
const error = new FetchError('Request aborted during response read', url, 499, {
|
|
268
274
|
reason: 'aborted',
|
|
269
275
|
});
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
case '
|
|
273
|
-
|
|
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, {
|
|
274
284
|
retryAfter: parseRetryAfter(input.retryAfter),
|
|
275
285
|
});
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
case '
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
case '
|
|
283
|
-
|
|
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, {
|
|
284
302
|
message: input.message,
|
|
285
303
|
});
|
|
286
|
-
|
|
287
|
-
|
|
304
|
+
return error;
|
|
305
|
+
}
|
|
306
|
+
case 'unknown': {
|
|
307
|
+
const error = new FetchError(input.message ?? 'Unexpected error', url);
|
|
308
|
+
return error;
|
|
309
|
+
}
|
|
288
310
|
default: {
|
|
289
311
|
const _exhaustive = input;
|
|
290
312
|
return _exhaustive;
|
|
@@ -303,11 +325,11 @@ function resolveErrorUrl(error, fallback) {
|
|
|
303
325
|
return typeof requestUrl === 'string' ? requestUrl : fallback;
|
|
304
326
|
}
|
|
305
327
|
const CLIENT_ERROR_CODES = new Set([
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
328
|
+
VALIDATION_ERROR,
|
|
329
|
+
EBADREDIRECT,
|
|
330
|
+
EBLOCKED,
|
|
331
|
+
ENODATA,
|
|
332
|
+
EINVAL,
|
|
311
333
|
]);
|
|
312
334
|
function mapAbortError(error, timeoutMs, url) {
|
|
313
335
|
return isTimeoutError(error)
|
|
@@ -317,10 +339,12 @@ function mapAbortError(error, timeoutMs, url) {
|
|
|
317
339
|
function mapSystemError(error, url) {
|
|
318
340
|
const { code, message } = error;
|
|
319
341
|
if (code === 'ETIMEOUT') {
|
|
320
|
-
|
|
342
|
+
const fetchError = new FetchError(message, url, 504, { code });
|
|
343
|
+
return fetchError;
|
|
321
344
|
}
|
|
322
345
|
if (code && CLIENT_ERROR_CODES.has(code)) {
|
|
323
|
-
|
|
346
|
+
const fetchError = new FetchError(message, url, 400, { code });
|
|
347
|
+
return fetchError;
|
|
324
348
|
}
|
|
325
349
|
return createFetchError({ kind: 'network', message }, url);
|
|
326
350
|
}
|
|
@@ -360,7 +384,7 @@ class MaxBytesError extends Error {
|
|
|
360
384
|
}
|
|
361
385
|
function createPinnedAgent(ipAddress) {
|
|
362
386
|
const ca = tls.rootCertificates.length > 0 ? tls.rootCertificates : undefined;
|
|
363
|
-
|
|
387
|
+
const agent = new Agent({
|
|
364
388
|
connect: {
|
|
365
389
|
lookup: (hostname, options, callback) => {
|
|
366
390
|
const family = isIP(ipAddress) === 6 ? 6 : 4;
|
|
@@ -379,6 +403,7 @@ function createPinnedAgent(ipAddress) {
|
|
|
379
403
|
keepAliveTimeout: 1000,
|
|
380
404
|
keepAliveMaxTimeout: 1000,
|
|
381
405
|
});
|
|
406
|
+
return agent;
|
|
382
407
|
}
|
|
383
408
|
class RedirectFollower {
|
|
384
409
|
fetchFn;
|
|
@@ -463,10 +488,10 @@ class RedirectFollower {
|
|
|
463
488
|
resolveRedirectTarget(baseUrl, location) {
|
|
464
489
|
const resolved = URL.parse(location, baseUrl);
|
|
465
490
|
if (!resolved) {
|
|
466
|
-
throw
|
|
491
|
+
throw invalidRedirectError();
|
|
467
492
|
}
|
|
468
493
|
if (resolved.username || resolved.password) {
|
|
469
|
-
throw
|
|
494
|
+
throw redirectCredentialsError();
|
|
470
495
|
}
|
|
471
496
|
return this.normalizeUrl(resolved.href);
|
|
472
497
|
}
|
|
@@ -478,7 +503,7 @@ class RedirectFollower {
|
|
|
478
503
|
assertHttpProtocol(url) {
|
|
479
504
|
const parsed = new URL(url);
|
|
480
505
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
481
|
-
throw
|
|
506
|
+
throw unsupportedProtocolError(parsed.protocol);
|
|
482
507
|
}
|
|
483
508
|
}
|
|
484
509
|
async withRedirectErrorContext(url, fn) {
|
|
@@ -542,11 +567,12 @@ function assertSupportedContentType(contentType, url) {
|
|
|
542
567
|
if (!mediaType) {
|
|
543
568
|
logDebug('No Content-Type header; relying on binary-content detection', {
|
|
544
569
|
url: redactUrl(url),
|
|
545
|
-
},
|
|
570
|
+
}, LOG_FETCH);
|
|
546
571
|
return;
|
|
547
572
|
}
|
|
548
573
|
if (!isTextLikeMediaType(mediaType)) {
|
|
549
|
-
|
|
574
|
+
const error = new FetchError(`Unsupported content type: ${mediaType}`, url);
|
|
575
|
+
throw error;
|
|
550
576
|
}
|
|
551
577
|
}
|
|
552
578
|
function extractEncodingTokens(value) {
|
|
@@ -567,10 +593,11 @@ function isSupportedContentEncoding(encoding) {
|
|
|
567
593
|
return encoding === 'gzip' || encoding === 'deflate' || encoding === 'br';
|
|
568
594
|
}
|
|
569
595
|
function createUnsupportedContentEncodingError(url, encodingHeader) {
|
|
570
|
-
|
|
596
|
+
const error = new FetchError(`Unsupported Content-Encoding: ${encodingHeader}`, url, 415, {
|
|
571
597
|
reason: 'unsupported_content_encoding',
|
|
572
598
|
encoding: encodingHeader,
|
|
573
599
|
});
|
|
600
|
+
return error;
|
|
574
601
|
}
|
|
575
602
|
function createDecompressor(encoding) {
|
|
576
603
|
const options = { chunkSize: 64 * 1024 };
|
|
@@ -584,7 +611,7 @@ function createDecompressor(encoding) {
|
|
|
584
611
|
}
|
|
585
612
|
}
|
|
586
613
|
function createPumpedStream(initialChunk, reader) {
|
|
587
|
-
|
|
614
|
+
const stream = new ReadableStream({
|
|
588
615
|
start(controller) {
|
|
589
616
|
if (initialChunk && initialChunk.byteLength > 0) {
|
|
590
617
|
controller.enqueue(initialChunk);
|
|
@@ -608,6 +635,7 @@ function createPumpedStream(initialChunk, reader) {
|
|
|
608
635
|
void reader.cancel(reason).catch(() => undefined);
|
|
609
636
|
},
|
|
610
637
|
});
|
|
638
|
+
return stream;
|
|
611
639
|
}
|
|
612
640
|
function buildDecodePipeline(body, encodings, url, response, signal) {
|
|
613
641
|
const decodeOrder = encodings.slice().reverse();
|
|
@@ -662,11 +690,12 @@ async function primeDecodedResponse(pipe, response, url, signal) {
|
|
|
662
690
|
const first = await pipe.decodedReader.read();
|
|
663
691
|
if (first.done) {
|
|
664
692
|
clearAbortListener();
|
|
665
|
-
|
|
693
|
+
const result = new Response(null, {
|
|
666
694
|
status: response.status,
|
|
667
695
|
statusText: response.statusText,
|
|
668
696
|
headers: pipe.headers,
|
|
669
697
|
});
|
|
698
|
+
return result;
|
|
670
699
|
}
|
|
671
700
|
const body = createPumpedStream(first.value, pipe.decodedReader);
|
|
672
701
|
if (signal) {
|
|
@@ -676,17 +705,19 @@ async function primeDecodedResponse(pipe, response, url, signal) {
|
|
|
676
705
|
clearAbortListener();
|
|
677
706
|
});
|
|
678
707
|
}
|
|
679
|
-
|
|
708
|
+
const result = new Response(body, {
|
|
680
709
|
status: response.status,
|
|
681
710
|
statusText: response.statusText,
|
|
682
711
|
headers: pipe.headers,
|
|
683
712
|
});
|
|
713
|
+
return result;
|
|
684
714
|
}
|
|
685
715
|
catch (error) {
|
|
686
716
|
clearAbortListener();
|
|
687
717
|
pipe.cleanup();
|
|
688
718
|
void pipe.decodedReader.cancel(error).catch(() => undefined);
|
|
689
|
-
|
|
719
|
+
const fetchError = new FetchError(`Content-Encoding decode failed for ${redactUrl(url)}: ${isError(error) ? error.message : String(error)}`, url);
|
|
720
|
+
throw fetchError;
|
|
690
721
|
}
|
|
691
722
|
}
|
|
692
723
|
async function decodeResponseIfNeeded(response, url, signal) {
|
|
@@ -786,7 +817,8 @@ class ResponseTextReader {
|
|
|
786
817
|
total += remaining;
|
|
787
818
|
yield slice;
|
|
788
819
|
}
|
|
789
|
-
|
|
820
|
+
const error = new MaxBytesError();
|
|
821
|
+
throw error;
|
|
790
822
|
}
|
|
791
823
|
total = newTotal;
|
|
792
824
|
yield buf;
|
|
@@ -866,10 +898,11 @@ function isReadableStreamLike(value) {
|
|
|
866
898
|
function assertReadableStreamLike(stream, url, stage) {
|
|
867
899
|
if (isReadableStreamLike(stream))
|
|
868
900
|
return;
|
|
869
|
-
|
|
901
|
+
const error = new FetchError('Invalid response stream', url, 500, {
|
|
870
902
|
reason: 'invalid_stream',
|
|
871
903
|
stage,
|
|
872
904
|
});
|
|
905
|
+
throw error;
|
|
873
906
|
}
|
|
874
907
|
function toNodeReadableStream(stream, url, stage) {
|
|
875
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 {
|