@llmindset/hf-mcp 0.3.2 → 0.3.4
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/docs-search/doc-fetch.d.ts +1 -0
- package/dist/docs-search/doc-fetch.d.ts.map +1 -1
- package/dist/docs-search/doc-fetch.js +9 -12
- package/dist/docs-search/doc-fetch.js.map +1 -1
- package/dist/docs-search/doc-fetch.test.js +56 -11
- package/dist/docs-search/doc-fetch.test.js.map +1 -1
- package/dist/file-icons.d.ts +3 -0
- package/dist/file-icons.d.ts.map +1 -0
- package/dist/file-icons.js +38 -0
- package/dist/file-icons.js.map +1 -0
- package/dist/gradio-files.d.ts +0 -1
- package/dist/gradio-files.d.ts.map +1 -1
- package/dist/gradio-files.js +2 -35
- package/dist/gradio-files.js.map +1 -1
- package/dist/hf-api-call.d.ts.map +1 -1
- package/dist/hf-api-call.js +7 -7
- package/dist/hf-api-call.js.map +1 -1
- package/dist/index.browser.d.ts +48 -0
- package/dist/index.browser.d.ts.map +1 -0
- package/dist/index.browser.js +153 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/jobs/commands/uv-utils.d.ts +0 -3
- package/dist/jobs/commands/uv-utils.d.ts.map +1 -1
- package/dist/jobs/commands/uv-utils.js +2 -2
- package/dist/jobs/commands/uv-utils.js.map +1 -1
- package/dist/jobs/jobs-tool.d.ts.map +1 -1
- package/dist/jobs/jobs-tool.js +11 -12
- package/dist/jobs/jobs-tool.js.map +1 -1
- package/dist/jobs/schema-help.d.ts +2 -9
- package/dist/jobs/schema-help.d.ts.map +1 -1
- package/dist/jobs/schema-help.js +3 -3
- package/dist/jobs/schema-help.js.map +1 -1
- package/dist/jobs/sse-handler.d.ts +3 -2
- package/dist/jobs/sse-handler.d.ts.map +1 -1
- package/dist/jobs/sse-handler.js +8 -4
- package/dist/jobs/sse-handler.js.map +1 -1
- package/dist/jobs/types.d.ts +1 -1
- package/dist/logger.d.ts +2 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/network/fetch-profile.d.ts +24 -0
- package/dist/network/fetch-profile.d.ts.map +1 -0
- package/dist/network/fetch-profile.js +80 -0
- package/dist/network/fetch-profile.js.map +1 -0
- package/dist/network/index.d.ts +5 -0
- package/dist/network/index.d.ts.map +1 -0
- package/dist/network/index.js +5 -0
- package/dist/network/index.js.map +1 -0
- package/dist/network/ip-policy.d.ts +6 -0
- package/dist/network/ip-policy.d.ts.map +1 -0
- package/dist/network/ip-policy.js +202 -0
- package/dist/network/ip-policy.js.map +1 -0
- package/dist/network/ip-policy.test.d.ts +2 -0
- package/dist/network/ip-policy.test.d.ts.map +1 -0
- package/dist/network/ip-policy.test.js +46 -0
- package/dist/network/ip-policy.test.js.map +1 -0
- package/dist/network/safe-fetch.d.ts +16 -0
- package/dist/network/safe-fetch.d.ts.map +1 -0
- package/dist/network/safe-fetch.js +124 -0
- package/dist/network/safe-fetch.js.map +1 -0
- package/dist/network/safe-fetch.test.d.ts +2 -0
- package/dist/network/safe-fetch.test.d.ts.map +1 -0
- package/dist/network/safe-fetch.test.js +136 -0
- package/dist/network/safe-fetch.test.js.map +1 -0
- package/dist/network/url-policy.d.ts +32 -0
- package/dist/network/url-policy.d.ts.map +1 -0
- package/dist/network/url-policy.js +230 -0
- package/dist/network/url-policy.js.map +1 -0
- package/dist/network/url-policy.test.d.ts +2 -0
- package/dist/network/url-policy.test.d.ts.map +1 -0
- package/dist/network/url-policy.test.js +57 -0
- package/dist/network/url-policy.test.js.map +1 -0
- package/dist/readme-utils.d.ts.map +1 -1
- package/dist/readme-utils.js +3 -4
- package/dist/readme-utils.js.map +1 -1
- package/dist/space/commands/discover.d.ts +0 -5
- package/dist/space/commands/discover.d.ts.map +1 -1
- package/dist/space/commands/discover.js +9 -2
- package/dist/space/commands/discover.js.map +1 -1
- package/dist/space/commands/invoke.js +1 -59
- package/dist/space/commands/invoke.js.map +1 -1
- package/dist/space/commands/view-parameters.d.ts.map +1 -1
- package/dist/space/commands/view-parameters.js +3 -98
- package/dist/space/commands/view-parameters.js.map +1 -1
- package/dist/space/dynamic-space-tool.d.ts.map +1 -1
- package/dist/space/dynamic-space-tool.js +5 -2
- package/dist/space/dynamic-space-tool.js.map +1 -1
- package/dist/space/utils/gradio-caller.d.ts.map +1 -1
- package/dist/space/utils/gradio-caller.js +13 -6
- package/dist/space/utils/gradio-caller.js.map +1 -1
- package/dist/space/utils/space-http.d.ts +8 -0
- package/dist/space/utils/space-http.d.ts.map +1 -0
- package/dist/space/utils/space-http.js +49 -0
- package/dist/space/utils/space-http.js.map +1 -0
- package/dist/space-files.d.ts +0 -1
- package/dist/space-files.d.ts.map +1 -1
- package/dist/space-files.js +3 -36
- package/dist/space-files.js.map +1 -1
- package/package.json +6 -2
- package/src/docs-search/doc-fetch.test.ts +98 -28
- package/src/docs-search/doc-fetch.ts +9 -16
- package/src/file-icons.ts +39 -0
- package/src/gradio-files.ts +2 -40
- package/src/hf-api-call.ts +8 -10
- package/src/index.browser.ts +183 -0
- package/src/index.ts +1 -0
- package/src/jobs/commands/uv-utils.ts +2 -2
- package/src/jobs/jobs-tool.ts +13 -12
- package/src/jobs/schema-help.ts +4 -4
- package/src/jobs/sse-handler.ts +12 -7
- package/src/logger.ts +2 -2
- package/src/network/fetch-profile.ts +112 -0
- package/src/network/index.ts +4 -0
- package/src/network/ip-policy.test.ts +58 -0
- package/src/network/ip-policy.ts +252 -0
- package/src/network/safe-fetch.test.ts +181 -0
- package/src/network/safe-fetch.ts +174 -0
- package/src/network/url-policy.test.ts +100 -0
- package/src/network/url-policy.ts +304 -0
- package/src/readme-utils.ts +11 -10
- package/src/space/commands/discover.ts +10 -2
- package/src/space/commands/invoke.ts +1 -88
- package/src/space/commands/view-parameters.ts +3 -136
- package/src/space/dynamic-space-tool.ts +6 -2
- package/src/space/utils/gradio-caller.ts +25 -12
- package/src/space/utils/space-http.ts +75 -0
- package/src/space-files.ts +3 -41
- package/test/fetch-guard.spec.ts +70 -0
- package/test/jobs/sse-handler.spec.ts +60 -0
- package/dist/space/utils/result-formatter.d.ts +0 -4
- package/dist/space/utils/result-formatter.d.ts.map +0 -1
- package/dist/space/utils/result-formatter.js +0 -146
- package/dist/space/utils/result-formatter.js.map +0 -1
- package/src/space/utils/result-formatter.ts +0 -226
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createExternalHttpsPolicy, createHfDocsPolicy } from './url-policy.js';
|
|
3
|
+
import { safeFetch } from './safe-fetch.js';
|
|
4
|
+
describe('safeFetch', () => {
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
vi.clearAllMocks();
|
|
7
|
+
vi.unstubAllGlobals();
|
|
8
|
+
});
|
|
9
|
+
it('follows redirects manually and validates each hop', async () => {
|
|
10
|
+
const fetchMock = vi
|
|
11
|
+
.fn()
|
|
12
|
+
.mockResolvedValueOnce(new Response('', { status: 302, headers: { location: '/docs/next' } }))
|
|
13
|
+
.mockResolvedValueOnce(new Response('ok', { status: 200 }));
|
|
14
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
15
|
+
const result = await safeFetch('https://huggingface.co/docs/start', {
|
|
16
|
+
urlPolicy: createHfDocsPolicy(),
|
|
17
|
+
externalOnly: true,
|
|
18
|
+
});
|
|
19
|
+
expect(result.redirectsFollowed).toBe(1);
|
|
20
|
+
expect(result.finalUrl.toString()).toBe('https://huggingface.co/docs/next');
|
|
21
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
22
|
+
expect(fetchMock.mock.calls[0]?.[0]).toBe('https://huggingface.co/docs/start');
|
|
23
|
+
expect(fetchMock.mock.calls[1]?.[0]).toBe('https://huggingface.co/docs/next');
|
|
24
|
+
});
|
|
25
|
+
it('rejects redirect to disallowed host', async () => {
|
|
26
|
+
const fetchMock = vi
|
|
27
|
+
.fn()
|
|
28
|
+
.mockResolvedValueOnce(new Response('', { status: 302, headers: { location: 'https://example.com/path' } }));
|
|
29
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
30
|
+
await expect(safeFetch('https://huggingface.co/docs/start', {
|
|
31
|
+
urlPolicy: createHfDocsPolicy(),
|
|
32
|
+
externalOnly: true,
|
|
33
|
+
})).rejects.toThrow('URL hostname is not allowed');
|
|
34
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
35
|
+
});
|
|
36
|
+
it('enforces redirect limits', async () => {
|
|
37
|
+
const fetchMock = vi
|
|
38
|
+
.fn()
|
|
39
|
+
.mockResolvedValueOnce(new Response('', { status: 302, headers: { location: '/docs/a' } }))
|
|
40
|
+
.mockResolvedValueOnce(new Response('', { status: 302, headers: { location: '/docs/b' } }));
|
|
41
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
42
|
+
await expect(safeFetch('https://huggingface.co/docs/start', {
|
|
43
|
+
urlPolicy: createHfDocsPolicy(),
|
|
44
|
+
maxRedirects: 1,
|
|
45
|
+
})).rejects.toThrow('Redirect limit exceeded');
|
|
46
|
+
});
|
|
47
|
+
it('enforces timeout', async () => {
|
|
48
|
+
const fetchMock = vi.fn().mockImplementation((_url, init) => new Promise((_, reject) => {
|
|
49
|
+
const signal = init?.signal;
|
|
50
|
+
signal?.addEventListener('abort', () => {
|
|
51
|
+
reject(new DOMException('aborted', 'AbortError'));
|
|
52
|
+
}, { once: true });
|
|
53
|
+
}));
|
|
54
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
55
|
+
await expect(safeFetch('https://example.com/file.wav', {
|
|
56
|
+
urlPolicy: createExternalHttpsPolicy(),
|
|
57
|
+
timeoutMs: 5,
|
|
58
|
+
})).rejects.toThrow('Request timed out');
|
|
59
|
+
});
|
|
60
|
+
it('keeps caller abort signal active while streaming response body', async () => {
|
|
61
|
+
const fetchMock = vi.fn().mockImplementation((_url, init) => {
|
|
62
|
+
const stream = new ReadableStream({
|
|
63
|
+
start(controller) {
|
|
64
|
+
init?.signal?.addEventListener('abort', () => {
|
|
65
|
+
controller.error(new DOMException('aborted', 'AbortError'));
|
|
66
|
+
}, { once: true });
|
|
67
|
+
},
|
|
68
|
+
pull() {
|
|
69
|
+
return new Promise(() => { });
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
return Promise.resolve(new Response(stream, { status: 200 }));
|
|
73
|
+
});
|
|
74
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
75
|
+
const controller = new AbortController();
|
|
76
|
+
const { response } = await safeFetch('https://example.com/file.wav', {
|
|
77
|
+
urlPolicy: createExternalHttpsPolicy(),
|
|
78
|
+
timeoutMs: 500,
|
|
79
|
+
requestInit: { signal: controller.signal },
|
|
80
|
+
});
|
|
81
|
+
const reader = response.body?.getReader();
|
|
82
|
+
if (!reader) {
|
|
83
|
+
throw new Error('Expected response body to exist');
|
|
84
|
+
}
|
|
85
|
+
const readPromise = Promise.race([
|
|
86
|
+
reader.read(),
|
|
87
|
+
new Promise((_, reject) => {
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
reject(new Error('stream read did not abort'));
|
|
90
|
+
}, 100);
|
|
91
|
+
}),
|
|
92
|
+
]);
|
|
93
|
+
controller.abort();
|
|
94
|
+
await expect(readPromise).rejects.toMatchObject({ name: 'AbortError' });
|
|
95
|
+
});
|
|
96
|
+
it('enforces timeout while streaming response body', async () => {
|
|
97
|
+
const fetchMock = vi.fn().mockImplementation((_url, init) => {
|
|
98
|
+
const stream = new ReadableStream({
|
|
99
|
+
start(controller) {
|
|
100
|
+
init?.signal?.addEventListener('abort', () => {
|
|
101
|
+
controller.error(new DOMException('aborted', 'AbortError'));
|
|
102
|
+
}, { once: true });
|
|
103
|
+
},
|
|
104
|
+
pull() {
|
|
105
|
+
return new Promise(() => { });
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
return Promise.resolve(new Response(stream, { status: 200 }));
|
|
109
|
+
});
|
|
110
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
111
|
+
const { response } = await safeFetch('https://example.com/file.wav', {
|
|
112
|
+
urlPolicy: createExternalHttpsPolicy(),
|
|
113
|
+
timeoutMs: 10,
|
|
114
|
+
});
|
|
115
|
+
const reader = response.body?.getReader();
|
|
116
|
+
if (!reader) {
|
|
117
|
+
throw new Error('Expected response body to exist');
|
|
118
|
+
}
|
|
119
|
+
const readPromise = Promise.race([
|
|
120
|
+
reader.read(),
|
|
121
|
+
new Promise((_, reject) => {
|
|
122
|
+
setTimeout(() => {
|
|
123
|
+
reject(new Error('stream read did not timeout'));
|
|
124
|
+
}, 200);
|
|
125
|
+
}),
|
|
126
|
+
]);
|
|
127
|
+
await expect(readPromise).rejects.toMatchObject({ name: 'AbortError' });
|
|
128
|
+
});
|
|
129
|
+
it('blocks internal destinations when externalOnly is enabled', async () => {
|
|
130
|
+
await expect(safeFetch('https://127.0.0.1/x', {
|
|
131
|
+
urlPolicy: createExternalHttpsPolicy(),
|
|
132
|
+
externalOnly: true,
|
|
133
|
+
})).rejects.toThrow('Blocked internal or reserved address');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
//# sourceMappingURL=safe-fetch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-fetch.test.js","sourceRoot":"","sources":["../../src/network/safe-fetch.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface UrlPathRules {
|
|
2
|
+
requiredPrefix?: string;
|
|
3
|
+
}
|
|
4
|
+
export type UrlProtocol = 'https:' | 'http:';
|
|
5
|
+
export interface UrlQueryRules {
|
|
6
|
+
allowAny?: boolean;
|
|
7
|
+
allowKeys?: ReadonlySet<string>;
|
|
8
|
+
}
|
|
9
|
+
export interface UrlPolicy {
|
|
10
|
+
allowedProtocols: ReadonlySet<UrlProtocol>;
|
|
11
|
+
allowedHosts?: ReadonlySet<string>;
|
|
12
|
+
allowSubdomainsOf?: readonly string[];
|
|
13
|
+
requireDefaultPort?: boolean;
|
|
14
|
+
pathRules?: UrlPathRules;
|
|
15
|
+
queryRules?: UrlQueryRules;
|
|
16
|
+
allowCredentials?: boolean;
|
|
17
|
+
customValidator?: (url: URL) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function validateUrlAgainstPolicy(url: URL, policy: UrlPolicy): void;
|
|
20
|
+
export declare function parseAndValidateUrl(input: string | URL, policy: UrlPolicy): URL;
|
|
21
|
+
export declare function createHfDocsPolicy(): UrlPolicy;
|
|
22
|
+
export declare function createGradioMcpPolicy(): UrlPolicy;
|
|
23
|
+
export declare function isLocalhostHostname(hostname: string): boolean;
|
|
24
|
+
export declare function createExternalHttpsPolicy(): UrlPolicy;
|
|
25
|
+
export declare function createHuggingFaceHubPolicy(): UrlPolicy;
|
|
26
|
+
export declare function createLocalhostHttpPolicy(): UrlPolicy;
|
|
27
|
+
export declare function createExactHostPolicy(hostname: string, allowedProtocol: UrlProtocol): UrlPolicy;
|
|
28
|
+
export declare function createHostPrefixPolicy(hostname: string, requiredPrefix: string, allowedProtocol?: UrlProtocol): UrlPolicy;
|
|
29
|
+
export declare function createGradioMcpHostPolicy(hostname: string, allowedProtocol: UrlProtocol): UrlPolicy;
|
|
30
|
+
export declare function createGradioSchemaHostPolicy(hostname: string): UrlPolicy;
|
|
31
|
+
export declare function createHttpOrHttpsPolicy(): UrlPolicy;
|
|
32
|
+
//# sourceMappingURL=url-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-policy.d.ts","sourceRoot":"","sources":["../../src/network/url-policy.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,SAAS;IACzB,gBAAgB,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAC3C,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;CACrC;AA0JD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAe1E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,GAAG,CAI/E;AAED,wBAAgB,kBAAkB,IAAI,SAAS,CAe9C;AAED,wBAAgB,qBAAqB,IAAI,SAAS,CAejD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,wBAAgB,yBAAyB,IAAI,SAAS,CAMrD;AAED,wBAAgB,0BAA0B,IAAI,SAAS,CAOtD;AAED,wBAAgB,yBAAyB,IAAI,SAAS,CAOrD;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,GAAG,SAAS,CAO/F;AAED,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,eAAe,GAAE,WAAsB,GACrC,SAAS,CAUX;AAED,wBAAgB,yBAAyB,CACxC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,WAAW,GAC1B,SAAS,CAEX;AAED,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAExE;AAED,wBAAgB,uBAAuB,IAAI,SAAS,CAMnD"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
const LOCALHOST_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);
|
|
2
|
+
const ENCODED_SEPARATOR_RE = /%(?:2f|5c)/i;
|
|
3
|
+
const ENCODED_BYTE_RE = /%[0-9a-f]{2}/i;
|
|
4
|
+
const INVALID_PERCENT_ENCODING_RE = /%(?![0-9a-f]{2})/i;
|
|
5
|
+
function normalizeHostname(hostname) {
|
|
6
|
+
return hostname.toLowerCase().replace(/\.+$/, '');
|
|
7
|
+
}
|
|
8
|
+
function safeDecodeURIComponent(value) {
|
|
9
|
+
try {
|
|
10
|
+
return decodeURIComponent(value);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error('URL contains invalid percent-encoding');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function collectDecodedPathVariants(pathname) {
|
|
17
|
+
const variants = [pathname];
|
|
18
|
+
let current = pathname;
|
|
19
|
+
for (let i = 0; i < 2; i += 1) {
|
|
20
|
+
if (!current.includes('%')) {
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
const decoded = safeDecodeURIComponent(current);
|
|
24
|
+
if (decoded === current) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
variants.push(decoded);
|
|
28
|
+
current = decoded;
|
|
29
|
+
}
|
|
30
|
+
return variants;
|
|
31
|
+
}
|
|
32
|
+
function hasDotSegments(pathname) {
|
|
33
|
+
const normalized = pathname.replace(/\\/g, '/');
|
|
34
|
+
const segments = normalized.split('/');
|
|
35
|
+
return segments.some((segment) => segment === '.' || segment === '..');
|
|
36
|
+
}
|
|
37
|
+
function matchesRequiredPrefix(pathname, requiredPrefix) {
|
|
38
|
+
const normalizedPath = pathname.replace(/\\/g, '/');
|
|
39
|
+
const normalizedPrefix = requiredPrefix.replace(/\\/g, '/');
|
|
40
|
+
if (normalizedPath === normalizedPrefix) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (normalizedPrefix.endsWith('/') && normalizedPath === normalizedPrefix.slice(0, -1)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return normalizedPath.startsWith(normalizedPrefix);
|
|
47
|
+
}
|
|
48
|
+
function assertHostAllowed(hostname, policy) {
|
|
49
|
+
if (!policy.allowedHosts && (!policy.allowSubdomainsOf || policy.allowSubdomainsOf.length === 0)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const normalized = normalizeHostname(hostname);
|
|
53
|
+
if (policy.allowedHosts) {
|
|
54
|
+
for (const host of policy.allowedHosts) {
|
|
55
|
+
if (normalizeHostname(host) === normalized) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (policy.allowSubdomainsOf) {
|
|
61
|
+
for (const domain of policy.allowSubdomainsOf) {
|
|
62
|
+
const normalizedDomain = normalizeHostname(domain);
|
|
63
|
+
if (normalized === normalizedDomain || normalized.endsWith(`.${normalizedDomain}`)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`URL hostname is not allowed: ${hostname}`);
|
|
69
|
+
}
|
|
70
|
+
function assertPathAllowed(url, pathRules) {
|
|
71
|
+
const pathname = url.pathname;
|
|
72
|
+
if (pathname.includes('%') && INVALID_PERCENT_ENCODING_RE.test(pathname)) {
|
|
73
|
+
throw new Error('URL path contains invalid percent-encoding');
|
|
74
|
+
}
|
|
75
|
+
const variants = collectDecodedPathVariants(pathname);
|
|
76
|
+
const hasEncodedSeparators = variants.some((variant) => ENCODED_SEPARATOR_RE.test(variant));
|
|
77
|
+
if (hasEncodedSeparators) {
|
|
78
|
+
throw new Error('URL path contains encoded separators');
|
|
79
|
+
}
|
|
80
|
+
const hasUnsafeDotSegments = variants.some((variant) => hasDotSegments(variant));
|
|
81
|
+
if (hasUnsafeDotSegments) {
|
|
82
|
+
throw new Error('URL path contains dot-segments');
|
|
83
|
+
}
|
|
84
|
+
if (variants.length > 1) {
|
|
85
|
+
const decodedOnce = variants[1] ?? '';
|
|
86
|
+
if (ENCODED_BYTE_RE.test(decodedOnce)) {
|
|
87
|
+
throw new Error('URL path appears to use double-encoding');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (pathRules?.requiredPrefix) {
|
|
91
|
+
const hasPrefix = variants.some((variant) => matchesRequiredPrefix(variant, pathRules.requiredPrefix ?? ''));
|
|
92
|
+
if (!hasPrefix) {
|
|
93
|
+
throw new Error(`URL path must start with ${pathRules.requiredPrefix}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function assertQueryAllowed(url, policy) {
|
|
98
|
+
const rules = policy.queryRules;
|
|
99
|
+
if (!rules || rules.allowAny === true) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!rules.allowKeys) {
|
|
103
|
+
if (url.search.length > 0) {
|
|
104
|
+
throw new Error('URL query string is not allowed');
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
for (const key of url.searchParams.keys()) {
|
|
109
|
+
if (!rules.allowKeys.has(key)) {
|
|
110
|
+
throw new Error(`URL query parameter is not allowed: ${key}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function assertPortAllowed(url, policy) {
|
|
115
|
+
if (!policy.requireDefaultPort || url.port.length === 0) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const defaultPort = url.protocol === 'https:' ? '443' : url.protocol === 'http:' ? '80' : '';
|
|
119
|
+
if (!defaultPort || url.port !== defaultPort) {
|
|
120
|
+
throw new Error(`URL port is not allowed for protocol ${url.protocol}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export function validateUrlAgainstPolicy(url, policy) {
|
|
124
|
+
if (!policy.allowedProtocols.has(url.protocol)) {
|
|
125
|
+
throw new Error(`URL protocol is not allowed: ${url.protocol}`);
|
|
126
|
+
}
|
|
127
|
+
if (!policy.allowCredentials && (url.username.length > 0 || url.password.length > 0)) {
|
|
128
|
+
throw new Error('URL credentials are not allowed');
|
|
129
|
+
}
|
|
130
|
+
assertHostAllowed(url.hostname, policy);
|
|
131
|
+
assertPortAllowed(url, policy);
|
|
132
|
+
assertPathAllowed(url, policy.pathRules);
|
|
133
|
+
assertQueryAllowed(url, policy);
|
|
134
|
+
policy.customValidator?.(url);
|
|
135
|
+
}
|
|
136
|
+
export function parseAndValidateUrl(input, policy) {
|
|
137
|
+
const parsed = input instanceof URL ? new URL(input.toString()) : new URL(input.trim());
|
|
138
|
+
validateUrlAgainstPolicy(parsed, policy);
|
|
139
|
+
return parsed;
|
|
140
|
+
}
|
|
141
|
+
export function createHfDocsPolicy() {
|
|
142
|
+
const hfHosts = new Set(['huggingface.co', 'www.huggingface.co']);
|
|
143
|
+
return {
|
|
144
|
+
allowedProtocols: new Set(['https:']),
|
|
145
|
+
allowedHosts: new Set(['huggingface.co', 'www.huggingface.co', 'gradio.app', 'www.gradio.app']),
|
|
146
|
+
allowCredentials: false,
|
|
147
|
+
queryRules: { allowAny: true },
|
|
148
|
+
customValidator: (url) => {
|
|
149
|
+
const host = normalizeHostname(url.hostname);
|
|
150
|
+
if (hfHosts.has(host) && !matchesRequiredPrefix(url.pathname, '/docs/')) {
|
|
151
|
+
throw new Error('Hugging Face docs URLs must remain under /docs/');
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
export function createGradioMcpPolicy() {
|
|
157
|
+
return {
|
|
158
|
+
allowedProtocols: new Set(['https:', 'http:']),
|
|
159
|
+
pathRules: {
|
|
160
|
+
requiredPrefix: '/gradio_api/mcp',
|
|
161
|
+
},
|
|
162
|
+
allowCredentials: false,
|
|
163
|
+
queryRules: { allowAny: true },
|
|
164
|
+
customValidator: (url) => {
|
|
165
|
+
const enforceLocalHttpOnly = process.env.NODE_ENV === 'production';
|
|
166
|
+
if (enforceLocalHttpOnly && url.protocol === 'http:' && !isLocalhostHostname(url.hostname)) {
|
|
167
|
+
throw new Error('HTTP is only allowed for localhost Gradio MCP endpoints');
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export function isLocalhostHostname(hostname) {
|
|
173
|
+
return LOCALHOST_HOSTS.has(normalizeHostname(hostname));
|
|
174
|
+
}
|
|
175
|
+
export function createExternalHttpsPolicy() {
|
|
176
|
+
return {
|
|
177
|
+
allowedProtocols: new Set(['https:']),
|
|
178
|
+
allowCredentials: false,
|
|
179
|
+
queryRules: { allowAny: true },
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
export function createHuggingFaceHubPolicy() {
|
|
183
|
+
return {
|
|
184
|
+
allowedProtocols: new Set(['https:']),
|
|
185
|
+
allowedHosts: new Set(['huggingface.co', 'www.huggingface.co', 'hf.co']),
|
|
186
|
+
allowCredentials: false,
|
|
187
|
+
queryRules: { allowAny: true },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
export function createLocalhostHttpPolicy() {
|
|
191
|
+
return {
|
|
192
|
+
allowedProtocols: new Set(['https:', 'http:']),
|
|
193
|
+
allowedHosts: new Set(['localhost', '127.0.0.1', '[::1]']),
|
|
194
|
+
allowCredentials: false,
|
|
195
|
+
queryRules: { allowAny: true },
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
export function createExactHostPolicy(hostname, allowedProtocol) {
|
|
199
|
+
return {
|
|
200
|
+
allowedProtocols: new Set([allowedProtocol]),
|
|
201
|
+
allowedHosts: new Set([hostname.toLowerCase()]),
|
|
202
|
+
allowCredentials: false,
|
|
203
|
+
queryRules: { allowAny: true },
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
export function createHostPrefixPolicy(hostname, requiredPrefix, allowedProtocol = 'https:') {
|
|
207
|
+
return {
|
|
208
|
+
allowedProtocols: new Set([allowedProtocol]),
|
|
209
|
+
allowedHosts: new Set([hostname.toLowerCase()]),
|
|
210
|
+
pathRules: {
|
|
211
|
+
requiredPrefix,
|
|
212
|
+
},
|
|
213
|
+
allowCredentials: false,
|
|
214
|
+
queryRules: { allowAny: true },
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
export function createGradioMcpHostPolicy(hostname, allowedProtocol) {
|
|
218
|
+
return createHostPrefixPolicy(hostname, '/gradio_api/mcp', allowedProtocol);
|
|
219
|
+
}
|
|
220
|
+
export function createGradioSchemaHostPolicy(hostname) {
|
|
221
|
+
return createHostPrefixPolicy(hostname, '/gradio_api/mcp/schema');
|
|
222
|
+
}
|
|
223
|
+
export function createHttpOrHttpsPolicy() {
|
|
224
|
+
return {
|
|
225
|
+
allowedProtocols: new Set(['https:', 'http:']),
|
|
226
|
+
allowCredentials: false,
|
|
227
|
+
queryRules: { allowAny: true },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=url-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-policy.js","sourceRoot":"","sources":["../../src/network/url-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-policy.test.d.ts","sourceRoot":"","sources":["../../src/network/url-policy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createExactHostPolicy, createExternalHttpsPolicy, createGradioMcpHostPolicy, createGradioSchemaHostPolicy, createHuggingFaceHubPolicy, createLocalhostHttpPolicy, createGradioMcpPolicy, createHfDocsPolicy, isLocalhostHostname, parseAndValidateUrl, } from './url-policy.js';
|
|
3
|
+
describe('url-policy', () => {
|
|
4
|
+
describe('HF docs policy', () => {
|
|
5
|
+
it('accepts valid Hugging Face docs and Gradio docs URLs', () => {
|
|
6
|
+
expect(() => parseAndValidateUrl('https://huggingface.co/docs/transformers', createHfDocsPolicy())).not.toThrow();
|
|
7
|
+
expect(() => parseAndValidateUrl('https://www.huggingface.co/docs/datasets', createHfDocsPolicy())).not.toThrow();
|
|
8
|
+
expect(() => parseAndValidateUrl('https://www.gradio.app/guides', createHfDocsPolicy())).not.toThrow();
|
|
9
|
+
});
|
|
10
|
+
it('rejects non-https or non-allowlisted hosts', () => {
|
|
11
|
+
expect(() => parseAndValidateUrl('http://huggingface.co/docs/transformers', createHfDocsPolicy())).toThrow('URL protocol is not allowed');
|
|
12
|
+
expect(() => parseAndValidateUrl('https://example.com/docs/transformers', createHfDocsPolicy())).toThrow('URL hostname is not allowed');
|
|
13
|
+
});
|
|
14
|
+
it('rejects traversal and encoded traversal variants', () => {
|
|
15
|
+
const variants = [
|
|
16
|
+
'https://huggingface.co/docs/../x',
|
|
17
|
+
'https://huggingface.co/docs/%2e%2e/x',
|
|
18
|
+
'https://huggingface.co/docs/%2e%2e%2fx',
|
|
19
|
+
'https://huggingface.co/docs/..%2fx',
|
|
20
|
+
'https://huggingface.co/docs/%2e%2e%5cx',
|
|
21
|
+
'https://huggingface.co/docs/%252e%252e%252fx',
|
|
22
|
+
];
|
|
23
|
+
for (const candidate of variants) {
|
|
24
|
+
expect(() => parseAndValidateUrl(candidate, createHfDocsPolicy())).toThrow();
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
it('enforces /docs/ prefix on HF hosts', () => {
|
|
28
|
+
expect(() => parseAndValidateUrl('https://huggingface.co/models/some-model', createHfDocsPolicy())).toThrow('Hugging Face docs URLs must remain under /docs/');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('Gradio MCP policy', () => {
|
|
32
|
+
it('accepts mcp endpoint URLs over https', () => {
|
|
33
|
+
expect(() => parseAndValidateUrl('https://demo-space.hf.space/gradio_api/mcp/', createGradioMcpPolicy())).not.toThrow();
|
|
34
|
+
expect(() => parseAndValidateUrl('https://fake-mcp.local/gradio_api/mcp/', createGradioMcpPolicy())).not.toThrow();
|
|
35
|
+
});
|
|
36
|
+
it('rejects invalid paths', () => {
|
|
37
|
+
expect(() => parseAndValidateUrl('https://demo-space.hf.space/not-mcp', createGradioMcpPolicy())).toThrow('URL path must start with /gradio_api/mcp');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('external https policy', () => {
|
|
41
|
+
it('rejects credentials in URL', () => {
|
|
42
|
+
expect(() => parseAndValidateUrl('https://user:pass@example.com/file.wav', createExternalHttpsPolicy())).toThrow('URL credentials are not allowed');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
it('supports huggingface hub and localhost policy helpers', () => {
|
|
46
|
+
expect(() => parseAndValidateUrl('https://huggingface.co/api/models', createHuggingFaceHubPolicy())).not.toThrow();
|
|
47
|
+
expect(() => parseAndValidateUrl('http://localhost:7860/health', createLocalhostHttpPolicy())).not.toThrow();
|
|
48
|
+
expect(() => parseAndValidateUrl('https://example.com/x', createExactHostPolicy('example.com', 'https:'))).not.toThrow();
|
|
49
|
+
expect(() => parseAndValidateUrl('https://demo-space.hf.space/gradio_api/mcp/schema', createGradioSchemaHostPolicy('demo-space.hf.space'))).not.toThrow();
|
|
50
|
+
expect(() => parseAndValidateUrl('https://demo-space.hf.space/gradio_api/mcp/', createGradioMcpHostPolicy('demo-space.hf.space', 'https:'))).not.toThrow();
|
|
51
|
+
expect(isLocalhostHostname('localhost')).toBe(true);
|
|
52
|
+
expect(isLocalhostHostname('127.0.0.1')).toBe(true);
|
|
53
|
+
expect(isLocalhostHostname('[::1]')).toBe(true);
|
|
54
|
+
expect(isLocalhostHostname('example.com')).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=url-policy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-policy.test.js","sourceRoot":"","sources":["../../src/network/url-policy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readme-utils.d.ts","sourceRoot":"","sources":["../src/readme-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"readme-utils.d.ts","sourceRoot":"","sources":["../src/readme-utils.ts"],"names":[],"mappings":"AAiBA,wBAAsB,kBAAkB,CACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,GAAG,UAAU,EAC3B,WAAW,GAAE,OAAe,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0CxB"}
|
package/dist/readme-utils.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
import { fetchWithProfile, NETWORK_FETCH_PROFILES } from './network/fetch-profile.js';
|
|
1
2
|
const DEFAULT_MAX_README_CHARS = 10_000;
|
|
2
3
|
export async function fetchReadmeContent(repoName, type, includeYaml = false) {
|
|
3
4
|
try {
|
|
4
|
-
const baseUrl = type === 'datasets'
|
|
5
|
-
? `https://huggingface.co/datasets/${repoName}`
|
|
6
|
-
: `https://huggingface.co/${repoName}`;
|
|
5
|
+
const baseUrl = type === 'datasets' ? `https://huggingface.co/datasets/${repoName}` : `https://huggingface.co/${repoName}`;
|
|
7
6
|
const url = `${baseUrl}/resolve/main/README.md`;
|
|
8
|
-
const response = await
|
|
7
|
+
const { response } = await fetchWithProfile(url, NETWORK_FETCH_PROFILES.hfHub());
|
|
9
8
|
if (!response.ok) {
|
|
10
9
|
if (response.status === 404) {
|
|
11
10
|
return null;
|
package/dist/readme-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readme-utils.js","sourceRoot":"","sources":["../src/readme-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"readme-utils.js","sourceRoot":"","sources":["../src/readme-utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGtF,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAUxC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,QAAgB,EAChB,IAA2B,EAC3B,cAAuB,KAAK;IAE5B,IAAI,CAAC;QAEJ,MAAM,OAAO,GACZ,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC,CAAC,0BAA0B,QAAQ,EAAE,CAAC;QAE5G,MAAM,GAAG,GAAG,GAAG,OAAO,yBAAyB,CAAC;QAEhD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,sBAAsB,CAAC,KAAK,EAAE,CAAC,CAAC;QAEjF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAE7B,OAAO,IAAI,CAAC;YACb,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAGpC,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QAGD,IAAI,OAAO,CAAC,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC;YAC7D,OAAO,GAAG,GAAG,SAAS,0BAA0B,wBAAwB,CAAC,QAAQ,EAAE,8BAA8B,OAAO,GAAG,CAAC;QAC7H,CAAC;QAGD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,OAAO,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAEhB,OAAO,CAAC,KAAK,CAAC,8BAA8B,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAQD,SAAS,oBAAoB,CAAC,OAAe;IAE5C,MAAM,WAAW,GAAG,mDAAmD,CAAC;IACxE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAEzC,IAAI,KAAK,EAAE,CAAC;QAEX,OAAO,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAGD,OAAO,OAAO,CAAC;AAChB,CAAC"}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
1
|
import type { ToolResult } from '../../types/tool-result.js';
|
|
2
|
-
export declare const DISCOVER_PROMPTS: {
|
|
3
|
-
RESULTS_HEADER: string;
|
|
4
|
-
NO_RESULTS: string;
|
|
5
|
-
FETCH_ERROR: (url: string, error: string) => string;
|
|
6
|
-
};
|
|
7
2
|
export declare function discoverSpaces(): Promise<ToolResult>;
|
|
8
3
|
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../../src/space/commands/discover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../../src/space/commands/discover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAgF7D,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC,CAgD1D"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { escapeMarkdown } from '../../utilities.js';
|
|
2
2
|
import { VIEW_PARAMETERS } from '../types.js';
|
|
3
|
-
|
|
3
|
+
import { fetchWithProfile, NETWORK_FETCH_PROFILES } from '../../network/fetch-profile.js';
|
|
4
|
+
const DISCOVER_PROMPTS = {
|
|
4
5
|
RESULTS_HEADER: `**Available Spaces:**
|
|
5
6
|
|
|
6
7
|
These spaces can be invoked using the \`dynamic_space\` tool.
|
|
@@ -53,7 +54,13 @@ export async function discoverSpaces() {
|
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
try {
|
|
56
|
-
const
|
|
57
|
+
const allowPermissiveUrls = process.env.ALLOW_PERMISSIVE_URLS === 'true';
|
|
58
|
+
const profile = allowPermissiveUrls
|
|
59
|
+
? NETWORK_FETCH_PROFILES.httpOrHttpsPermissive()
|
|
60
|
+
: NETWORK_FETCH_PROFILES.externalHttps();
|
|
61
|
+
const { response } = await fetchWithProfile(url, profile, {
|
|
62
|
+
timeoutMs: 10000,
|
|
63
|
+
});
|
|
57
64
|
if (!response.ok) {
|
|
58
65
|
return {
|
|
59
66
|
formatted: DISCOVER_PROMPTS.FETCH_ERROR(url, `HTTP ${response.status}`),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/space/commands/discover.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/space/commands/discover.ts"],"names":[],"mappings":"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"}
|