@redocly/realm 0.136.0-next.9 → 0.136.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +190 -0
- package/dist/client/App.js +1 -1
- package/dist/client/ScriptLoader.js +1 -1
- package/dist/client/TestProvider.js +1 -1
- package/dist/client/app/Link.js +1 -1
- package/dist/client/app/Sidebar/useBreadcrumbs.js +1 -1
- package/dist/client/app/Sidebar/useSidebarItems.js +1 -1
- package/dist/client/app/Sidebar/utils.d.ts +1 -1
- package/dist/client/app/hooks/catalog/useCatalogClassic.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogFilter.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogSearch.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogSort.js +1 -1
- package/dist/client/app/hooks/products/useCurrentProduct.js +1 -1
- package/dist/client/app/hooks/useAutoScroll.js +1 -1
- package/dist/client/app/hooks/useBanner.js +1 -1
- package/dist/client/app/hooks/useL10nConfig.js +1 -1
- package/dist/client/app/hooks/useLoginUrl.js +1 -1
- package/dist/client/app/hooks/usePageTimeTracker.js +1 -1
- package/dist/client/app/hooks/useRouteChangeTracker.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
- package/dist/client/app/pages/DevLogin/DevLogin.js +1 -1
- package/dist/client/app/search/useSearch.d.ts +1 -0
- package/dist/client/app/search/useSearch.js +1 -1
- package/dist/client/app/seo/hooks/useHreflangLinks.js +1 -1
- package/dist/client/app/useMobileMenu.js +1 -1
- package/dist/client/app/usePreloadHistory.d.ts +1 -1
- package/dist/client/app/usePreloadHistory.js +1 -1
- package/dist/client/app/utils/loadAndNavigate.d.ts +1 -1
- package/dist/client/browser-entry.js +2 -2
- package/dist/client/providers/hooks.d.ts +1 -1
- package/dist/client/providers/hooks.js +1 -1
- package/dist/client/providers/page-data/hooks.js +1 -1
- package/dist/client/providers/post-message/PostMessageProvider.js +1 -1
- package/dist/constants/api.d.ts +2 -0
- package/dist/constants/api.js +1 -1
- package/dist/server/constants/common.d.ts +2 -0
- package/dist/server/constants/common.js +1 -1
- package/dist/server/constants/plugins/search.d.ts +1 -1
- package/dist/server/constants/plugins/search.js +1 -1
- package/dist/server/esbuild/esbuild.js +1 -1
- package/dist/server/esbuild/plugins/themes-resolver.js +4 -2
- package/dist/server/plugins/dev-onboarding/template/App.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/AppsList.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/ApiKeyItem.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/ApiLogDetails.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/ApiLogs.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/CreateApiKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/DeleteAppDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditApis.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDescriptionDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditCallbackUrlDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/RevokeAPIKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/RollAPIKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/UpdateApiKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/index.js +1 -1
- package/dist/server/plugins/mcp/audit/audit-log.d.ts +36 -0
- package/dist/server/plugins/mcp/audit/audit-log.js +1 -0
- package/dist/server/plugins/mcp/audit/constants.d.ts +6 -0
- package/dist/server/plugins/mcp/audit/constants.js +1 -0
- package/dist/server/plugins/mcp/audit/secret-patterns.d.ts +2 -0
- package/dist/server/plugins/mcp/audit/secret-patterns.js +1 -0
- package/dist/server/plugins/mcp/codemode/build-tool-list.d.ts +12 -0
- package/dist/server/plugins/mcp/codemode/build-tool-list.js +2 -0
- package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +4 -4
- package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +1 -0
- package/dist/server/plugins/mcp/codemode/capabilities/utils.js +3 -3
- package/dist/server/plugins/mcp/codemode/code-execution-audit.d.ts +17 -0
- package/dist/server/plugins/mcp/codemode/code-execution-audit.js +1 -0
- package/dist/server/plugins/mcp/codemode/constants.js +1 -1
- package/dist/server/plugins/mcp/codemode/prompts.d.ts +6 -3
- package/dist/server/plugins/mcp/codemode/prompts.js +7 -4
- package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.js +1 -1
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.d.ts +6 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.js +54 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/form-data.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/form-data.js +17 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.js +2 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url-search-params.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url-search-params.js +64 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url.js +239 -0
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.d.ts +19 -0
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -0
- package/dist/server/plugins/mcp/codemode/tools/tool-errors.d.ts +4 -0
- package/dist/server/plugins/mcp/codemode/tools/tool-errors.js +1 -0
- package/dist/server/plugins/mcp/constants.d.ts +1 -0
- package/dist/server/plugins/mcp/constants.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-full-api-description.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.d.ts +5 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +2 -0
- package/dist/server/plugins/mcp/docs-mcp/utils.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +35 -15
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +3 -2
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.d.ts +24 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.d.ts +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.d.ts +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +3 -0
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +47 -24
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/servers/mcp-server.d.ts +1 -0
- package/dist/server/plugins/mcp/servers/mcp-server.js +3 -1
- package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +11 -0
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/ApiDetailsPage.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/RuleDetailsPage.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/index.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/utils.d.ts +1 -1
- package/dist/server/plugins/scorecard-classic/template/views.js +1 -1
- package/dist/server/plugins/search/engines/typesense/index.js +1 -1
- package/dist/server/ssr/render.js +1 -1
- package/dist/server/tools/notifiers/formatter.d.ts +1 -0
- package/dist/server/tools/notifiers/formatter.js +3 -3
- package/dist/server/tools/notifiers/logger.d.ts +1 -0
- package/dist/server/tools/notifiers/logger.js +2 -2
- package/dist/server/types/plugin-hooks.d.ts +1 -1
- package/dist/server/utils/llmstxt/agent-feedback-llms-footer.js +1 -1
- package/dist/server/web-server/routes/ask-ai.d.ts +11 -0
- package/dist/server/web-server/routes/ask-ai.js +1 -1
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
- package/dist/types/api.d.ts +3 -0
- package/package.json +20 -20
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills.d.ts +0 -2
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills.js +0 -99
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
const
|
|
2
|
-
`)}const
|
|
3
|
-
`);
|
|
4
|
-
`)
|
|
1
|
+
import{buildToolList as i}from"./build-tool-list.js";const l=2048,c="Both `execute` arguments are required: `code` (the JavaScript to run; return a value to receive it) and `description` (a short human-readable summary of what the code does).",n="Available tools (exact signatures come from `describe-tools`):";function a(e,t){if(t.length===0)return e;const o=l-e.length-n.length-3,s=i(t,o);return s?[e,"",n,s].join(`
|
|
2
|
+
`):e}function h(e,t=[]){const o=["Run JavaScript in a sandbox against the documentation tools on the global `tools` object.",e?"The extra globals are `tools`, `fetch`, `URL`, `URLSearchParams`, and `FormData` - there is no `console`, `setTimeout`, `require`, or Node.js API; all other I/O goes through `tools`.":"The only extra global is `tools` - there is no `fetch`, `console`, `setTimeout`, `require`, or Node.js API; all I/O goes through `tools`.","","Workflow - minimize round-trips; one `describe-tools` call plus one `execute` call covers most requests:","1. Analyze the request and decide which sandbox tools it needs.","2. Call `describe-tools` with those names to get their exact TypeScript signatures - inputs, result shapes, and a worked example. NEVER call `execute` with guessed method names, parameter names, enum values, or result field names: read fields off the declared return types, not from assumptions.","3. Batch everything into a SINGLE script: chain tool calls, pass one call's output into the next, process results in plain JavaScript, and `return` only what the request needs."].join(`
|
|
3
|
+
`);return a(o,t)}const d=["Get the exact TypeScript signatures of the sandbox tools available to `execute`.","Analyze the user request first, then pass `tools` with only the tool names the request needs (every name is listed in this input schema / description); omit `tools` only when you cannot tell which tools apply.","Always call this before your first `execute` and never guess signatures. Request every tool the task may need in ONE call instead of calling this repeatedly."].join(`
|
|
4
|
+
`);function u(e,t=[]){const o=["This server exposes documentation tools (API discovery, endpoint details, security schemes, full-text search) through two tools:","- `describe-tools` returns the exact TypeScript signatures of the sandbox tools.","- `execute` runs JavaScript that calls those tools on the global `tools` object.","Workflow: analyze the request, call `describe-tools` once with only the tool names it needs, then batch everything into a single `execute` script. Minimize round-trips and never guess tool signatures.",...e?["The sandbox also has a global `fetch` that can call the documented APIs (allow-listed hosts only). Include `fetch` in your `describe-tools` call to get its contract and the list of callable APIs."]:[]].join(`
|
|
5
|
+
`);return a(o,t)}const p=["Example - list the write endpoints of an API:","","```ts","const { items } = await tools.listApis({ filter: 'billing' });","const { endpoints } = await tools.getEndpoints({ name: items[0].name });","const writes = endpoints.filter((e) => e.method !== 'GET');","return { api: items[0].name, writes: writes.map((e) => `${e.method} ${e.path}`) };","```"].join(`
|
|
6
|
+
`),m=["Types named `OpenApi\u2026` are the standard OpenAPI Specification objects.","Payload samples live on a media type object (`requestBody.content[mediaType]`, `responses[code].content[mediaType]`): `.example` holds a single value, `.examples[name].value` a named map, and some descriptions only set `.schema.example`. Read each before concluding a sample is absent."].join(`
|
|
7
|
+
`);export{d as DESCRIBE_TOOLS_DESCRIPTION,l as DESCRIPTION_CHAR_LIMIT,c as EXECUTE_ARGS_NOTE,p as PLAIN_EXECUTE_EXAMPLE,m as USAGE_NOTES,u as buildCodeModeInstructions,h as buildExecuteDescription};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{setupHostFunctions as a}from"../../../../sandbox/utils/setup-host-functions.js";import{evalGuestCode as p}from"../../../../sandbox/utils/eval-guest-code.js";import{SANDBOX_FETCH_SETUP as i}from"./polyfills.js";import{FETCH_BRIDGE_FUNCTION_NAME as u,FETCH_BRIDGE_GLOBAL_NAME as c,TOOLS_BRIDGE_GLOBAL_NAME as n}from"../constants.js";const m=100,f=50;function T(r,t){return(e,l)=>{const s=[a(e,r,{globalName:n,budget:l,maxCalls:m,messages:{outputTooLarge:o=>`Tool output is too large (${o} bytes); request narrower data instead`,callLimitExceeded:o=>`Exceeded the limit of ${o} tool calls`}})];return t&&s.push(a(e,{[u]:o=>t(o)},{globalName:c,budget:l,maxCalls:f,messages:{outputTooLarge:o=>`Response is too large (${o} bytes); request less data`,callLimitExceeded:o=>`Exceeded the limit of ${o} fetch calls`}})),p(e,E(!!t)),()=>{for(const o of s)o()}}}function E(r){const t=r?i:"",e=`globalThis[${JSON.stringify(n)}]`;return`(() => {${t}
|
|
1
|
+
import{setupHostFunctions as a}from"../../../../sandbox/utils/setup-host-functions.js";import{evalGuestCode as p}from"../../../../sandbox/utils/eval-guest-code.js";import{SANDBOX_FETCH_SETUP as i}from"./polyfills/index.js";import{FETCH_BRIDGE_FUNCTION_NAME as u,FETCH_BRIDGE_GLOBAL_NAME as c,TOOLS_BRIDGE_GLOBAL_NAME as n}from"../constants.js";const m=100,f=50;function T(r,t){return(e,l)=>{const s=[a(e,r,{globalName:n,budget:l,maxCalls:m,messages:{outputTooLarge:o=>`Tool output is too large (${o} bytes); request narrower data instead`,callLimitExceeded:o=>`Exceeded the limit of ${o} tool calls`}})];return t&&s.push(a(e,{[u]:o=>t(o)},{globalName:c,budget:l,maxCalls:f,messages:{outputTooLarge:o=>`Response is too large (${o} bytes); request less data`,callLimitExceeded:o=>`Exceeded the limit of ${o} fetch calls`}})),p(e,E(!!t)),()=>{for(const o of s)o()}}}function E(r){const t=r?i:"",e=`globalThis[${JSON.stringify(n)}]`;return`(() => {${t}
|
|
2
2
|
const tools = ${e};
|
|
3
3
|
${e} = new Proxy(tools, {
|
|
4
4
|
get(target, prop) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fetch`: not a polyfill but a bridge. It takes the host rail off the global object so guest
|
|
3
|
+
* code cannot reach it directly, encodes the body, and hands the host a plain request.
|
|
4
|
+
*/
|
|
5
|
+
export declare const FETCH_SHIM = "\n const hostFetch = globalThis.__fetchBridge.fetch;\n delete globalThis.__fetchBridge;\n // RFC 7578: a field name travels with its quote and line breaks escaped, so a name cannot close its own header and open a part the caller did not write.\n const escapeFieldName = (name) =>\n String(name).replace(\n /[\"\\r\\n]/g,\n (char) => '%' + char.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'),\n );\n globalThis.fetch = (url, init = {}) => {\n let body;\n let autoContentType;\n if (init.body instanceof URLSearchParams) {\n body = init.body.toString();\n autoContentType = 'application/x-www-form-urlencoded';\n } else if (init.body instanceof FormData) {\n const boundary = '----FormBoundary' + Math.random().toString(36).slice(2);\n body = init.body._fields\n .map(([k, v]) =>\n '--' + boundary + '\\r\\nContent-Disposition: form-data; name=\"' + escapeFieldName(k) + '\"\\r\\n\\r\\n' + v,\n )\n .join('\\r\\n') + '\\r\\n--' + boundary + '--';\n autoContentType = 'multipart/form-data; boundary=' + boundary;\n } else if (init.body != null && typeof init.body !== 'string') {\n throw new TypeError('fetch body must be a string, URLSearchParams, or FormData');\n } else {\n body = init.body ?? undefined;\n }\n const callerHeaders = init.headers;\n const hasContentType = callerHeaders != null && Object.keys(callerHeaders).some(\n (k) => k.toLowerCase() === 'content-type',\n );\n const headers = autoContentType && !hasContentType\n ? Object.assign({ 'content-type': autoContentType }, callerHeaders)\n : callerHeaders;\n return hostFetch({ url: String(url), method: init.method, headers, body })\n .then((res) => {\n const resHeaders = res.headers || {};\n return {\n status: res.status,\n statusText: res.statusText,\n ok: res.ok,\n headers: {\n get: (name) => {\n const value = resHeaders[String(name).toLowerCase()];\n return value === undefined ? null : value;\n },\n },\n json: () => Promise.resolve(JSON.parse(res.bodyText)),\n text: () => Promise.resolve(res.bodyText),\n };\n });\n };\n";
|
|
6
|
+
//# sourceMappingURL=fetch-shim.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import{FETCH_BRIDGE_FUNCTION_NAME as t,FETCH_BRIDGE_GLOBAL_NAME as e}from"../../constants.js";const n=`
|
|
2
|
+
const hostFetch = globalThis.${e}.${t};
|
|
3
|
+
delete globalThis.${e};
|
|
4
|
+
// RFC 7578: a field name travels with its quote and line breaks escaped, so a name cannot close its own header and open a part the caller did not write.
|
|
5
|
+
const escapeFieldName = (name) =>
|
|
6
|
+
String(name).replace(
|
|
7
|
+
/["\\r\\n]/g,
|
|
8
|
+
(char) => '%' + char.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'),
|
|
9
|
+
);
|
|
10
|
+
globalThis.fetch = (url, init = {}) => {
|
|
11
|
+
let body;
|
|
12
|
+
let autoContentType;
|
|
13
|
+
if (init.body instanceof URLSearchParams) {
|
|
14
|
+
body = init.body.toString();
|
|
15
|
+
autoContentType = 'application/x-www-form-urlencoded';
|
|
16
|
+
} else if (init.body instanceof FormData) {
|
|
17
|
+
const boundary = '----FormBoundary' + Math.random().toString(36).slice(2);
|
|
18
|
+
body = init.body._fields
|
|
19
|
+
.map(([k, v]) =>
|
|
20
|
+
'--' + boundary + '\\r\\nContent-Disposition: form-data; name="' + escapeFieldName(k) + '"\\r\\n\\r\\n' + v,
|
|
21
|
+
)
|
|
22
|
+
.join('\\r\\n') + '\\r\\n--' + boundary + '--';
|
|
23
|
+
autoContentType = 'multipart/form-data; boundary=' + boundary;
|
|
24
|
+
} else if (init.body != null && typeof init.body !== 'string') {
|
|
25
|
+
throw new TypeError('fetch body must be a string, URLSearchParams, or FormData');
|
|
26
|
+
} else {
|
|
27
|
+
body = init.body ?? undefined;
|
|
28
|
+
}
|
|
29
|
+
const callerHeaders = init.headers;
|
|
30
|
+
const hasContentType = callerHeaders != null && Object.keys(callerHeaders).some(
|
|
31
|
+
(k) => k.toLowerCase() === 'content-type',
|
|
32
|
+
);
|
|
33
|
+
const headers = autoContentType && !hasContentType
|
|
34
|
+
? Object.assign({ 'content-type': autoContentType }, callerHeaders)
|
|
35
|
+
: callerHeaders;
|
|
36
|
+
return hostFetch({ url: String(url), method: init.method, headers, body })
|
|
37
|
+
.then((res) => {
|
|
38
|
+
const resHeaders = res.headers || {};
|
|
39
|
+
return {
|
|
40
|
+
status: res.status,
|
|
41
|
+
statusText: res.statusText,
|
|
42
|
+
ok: res.ok,
|
|
43
|
+
headers: {
|
|
44
|
+
get: (name) => {
|
|
45
|
+
const value = resHeaders[String(name).toLowerCase()];
|
|
46
|
+
return value === undefined ? null : value;
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
json: () => Promise.resolve(JSON.parse(res.bodyText)),
|
|
50
|
+
text: () => Promise.resolve(res.bodyText),
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
`;export{n as FETCH_SHIM};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** `FormData`: the multipart body the fetch shim serializes. */
|
|
2
|
+
export declare const FORM_DATA_POLYFILL = "\n const FormData = class FormData {\n constructor() { this._fields = []; }\n append(key, value) { this._fields.push([String(key), String(value)]); }\n set(key, value) {\n const k = String(key), v = String(value);\n this._fields = this._fields.filter(([fk]) => fk !== k);\n this._fields.push([k, v]);\n }\n get(key) { return (this._fields.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }\n has(key) { return this._fields.some(([k]) => k === String(key)); }\n delete(key) { this._fields = this._fields.filter(([k]) => k !== String(key)); }\n entries() { return this._fields.values(); }\n [Symbol.iterator]() { return this._fields.values(); }\n };\n globalThis.FormData = FormData;\n";
|
|
3
|
+
//# sourceMappingURL=form-data.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const e=`
|
|
2
|
+
const FormData = class FormData {
|
|
3
|
+
constructor() { this._fields = []; }
|
|
4
|
+
append(key, value) { this._fields.push([String(key), String(value)]); }
|
|
5
|
+
set(key, value) {
|
|
6
|
+
const k = String(key), v = String(value);
|
|
7
|
+
this._fields = this._fields.filter(([fk]) => fk !== k);
|
|
8
|
+
this._fields.push([k, v]);
|
|
9
|
+
}
|
|
10
|
+
get(key) { return (this._fields.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }
|
|
11
|
+
has(key) { return this._fields.some(([k]) => k === String(key)); }
|
|
12
|
+
delete(key) { this._fields = this._fields.filter(([k]) => k !== String(key)); }
|
|
13
|
+
entries() { return this._fields.values(); }
|
|
14
|
+
[Symbol.iterator]() { return this._fields.values(); }
|
|
15
|
+
};
|
|
16
|
+
globalThis.FormData = FormData;
|
|
17
|
+
`;export{e as FORM_DATA_POLYFILL};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** `URLSearchParams`: query-string parsing and serialization, and the store behind `URL.searchParams`. */
|
|
2
|
+
export declare const URL_SEARCH_PARAMS_POLYFILL = "\n // application/x-www-form-urlencoded reads '+' as a space, and leaves an escape it cannot read alone.\n // Decoding one well-formed run at a time is what keeps a stray '%' \u2014 '?discount=50%', a half-encoded cursor \u2014 from throwing URIError and ending the run.\n const decodeFormPart = (value) =>\n value.replace(/\\+/g, ' ').replace(/(?:%[0-9A-Fa-f]{2})+/g, (escaped) => {\n try { return decodeURIComponent(escaped); } catch (error) { return escaped; }\n });\n\n // The same rules in reverse: everything but alphanumerics and * - . _ is percent-encoded, and a space is '+'. encodeURIComponent keeps !'()~ literal, so those are encoded after it runs.\n const encodeFormPart = (value) =>\n encodeURIComponent(String(value))\n .replace(/%20/g, '+')\n .replace(/[!'()~]/g, (char) => '%' + char.charCodeAt(0).toString(16).toUpperCase());\n\n const URLSearchParams = class URLSearchParams {\n constructor(init) {\n this._params = [];\n if (init == null) return;\n if (typeof init === 'string') {\n const str = init.startsWith('?') ? init.slice(1) : init;\n for (const pair of (str ? str.split('&') : [])) {\n if (pair === '') continue;\n const eq = pair.indexOf('=');\n const key = eq >= 0 ? pair.slice(0, eq) : pair;\n const value = eq >= 0 ? pair.slice(eq + 1) : '';\n this._params.push([decodeFormPart(key), decodeFormPart(value)]);\n }\n } else if (typeof init[Symbol.iterator] === 'function') {\n // [['a', '1'], ['b', '2']] and another URLSearchParams both arrive here.\n for (const [key, value] of init) this._params.push([String(key), String(value)]);\n } else if (typeof init === 'object') {\n for (const [key, value] of Object.entries(init)) this._params.push([key, String(value)]);\n }\n }\n get size() { return this._params.length; }\n append(key, value) { this._params.push([String(key), String(value)]); }\n set(key, value) {\n const k = String(key), v = String(value);\n const at = this._params.findIndex(([pk]) => pk === k);\n if (at === -1) { this._params.push([k, v]); return; }\n // Overwrite where the key already sat, so an edit does not reorder the query the server sent.\n this._params[at] = [k, v];\n this._params = this._params.filter(([pk], index) => pk !== k || index === at);\n }\n get(key) { return (this._params.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }\n getAll(key) { return this._params.filter(([k]) => k === String(key)).map(([, v]) => v); }\n has(key) { return this._params.some(([k]) => k === String(key)); }\n delete(key) { this._params = this._params.filter(([k]) => k !== String(key)); }\n forEach(callback, thisArg) {\n for (const [k, v] of [...this._params]) callback.call(thisArg, v, k, this);\n }\n keys() { return this._params.map(([k]) => k).values(); }\n values() { return this._params.map(([, v]) => v).values(); }\n entries() { return this._params.map(([k, v]) => [k, v]).values(); }\n sort() { this._params.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)); }\n [Symbol.iterator]() { return this.entries(); }\n toString() {\n return this._params\n .map(([k, v]) => encodeFormPart(k) + '=' + encodeFormPart(v))\n .join('&');\n }\n };\n globalThis.URLSearchParams = URLSearchParams;\n";
|
|
3
|
+
//# sourceMappingURL=url-search-params.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const e=`
|
|
2
|
+
// application/x-www-form-urlencoded reads '+' as a space, and leaves an escape it cannot read alone.
|
|
3
|
+
// Decoding one well-formed run at a time is what keeps a stray '%' \u2014 '?discount=50%', a half-encoded cursor \u2014 from throwing URIError and ending the run.
|
|
4
|
+
const decodeFormPart = (value) =>
|
|
5
|
+
value.replace(/\\+/g, ' ').replace(/(?:%[0-9A-Fa-f]{2})+/g, (escaped) => {
|
|
6
|
+
try { return decodeURIComponent(escaped); } catch (error) { return escaped; }
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// The same rules in reverse: everything but alphanumerics and * - . _ is percent-encoded, and a space is '+'. encodeURIComponent keeps !'()~ literal, so those are encoded after it runs.
|
|
10
|
+
const encodeFormPart = (value) =>
|
|
11
|
+
encodeURIComponent(String(value))
|
|
12
|
+
.replace(/%20/g, '+')
|
|
13
|
+
.replace(/[!'()~]/g, (char) => '%' + char.charCodeAt(0).toString(16).toUpperCase());
|
|
14
|
+
|
|
15
|
+
const URLSearchParams = class URLSearchParams {
|
|
16
|
+
constructor(init) {
|
|
17
|
+
this._params = [];
|
|
18
|
+
if (init == null) return;
|
|
19
|
+
if (typeof init === 'string') {
|
|
20
|
+
const str = init.startsWith('?') ? init.slice(1) : init;
|
|
21
|
+
for (const pair of (str ? str.split('&') : [])) {
|
|
22
|
+
if (pair === '') continue;
|
|
23
|
+
const eq = pair.indexOf('=');
|
|
24
|
+
const key = eq >= 0 ? pair.slice(0, eq) : pair;
|
|
25
|
+
const value = eq >= 0 ? pair.slice(eq + 1) : '';
|
|
26
|
+
this._params.push([decodeFormPart(key), decodeFormPart(value)]);
|
|
27
|
+
}
|
|
28
|
+
} else if (typeof init[Symbol.iterator] === 'function') {
|
|
29
|
+
// [['a', '1'], ['b', '2']] and another URLSearchParams both arrive here.
|
|
30
|
+
for (const [key, value] of init) this._params.push([String(key), String(value)]);
|
|
31
|
+
} else if (typeof init === 'object') {
|
|
32
|
+
for (const [key, value] of Object.entries(init)) this._params.push([key, String(value)]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
get size() { return this._params.length; }
|
|
36
|
+
append(key, value) { this._params.push([String(key), String(value)]); }
|
|
37
|
+
set(key, value) {
|
|
38
|
+
const k = String(key), v = String(value);
|
|
39
|
+
const at = this._params.findIndex(([pk]) => pk === k);
|
|
40
|
+
if (at === -1) { this._params.push([k, v]); return; }
|
|
41
|
+
// Overwrite where the key already sat, so an edit does not reorder the query the server sent.
|
|
42
|
+
this._params[at] = [k, v];
|
|
43
|
+
this._params = this._params.filter(([pk], index) => pk !== k || index === at);
|
|
44
|
+
}
|
|
45
|
+
get(key) { return (this._params.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }
|
|
46
|
+
getAll(key) { return this._params.filter(([k]) => k === String(key)).map(([, v]) => v); }
|
|
47
|
+
has(key) { return this._params.some(([k]) => k === String(key)); }
|
|
48
|
+
delete(key) { this._params = this._params.filter(([k]) => k !== String(key)); }
|
|
49
|
+
forEach(callback, thisArg) {
|
|
50
|
+
for (const [k, v] of [...this._params]) callback.call(thisArg, v, k, this);
|
|
51
|
+
}
|
|
52
|
+
keys() { return this._params.map(([k]) => k).values(); }
|
|
53
|
+
values() { return this._params.map(([, v]) => v).values(); }
|
|
54
|
+
entries() { return this._params.map(([k, v]) => [k, v]).values(); }
|
|
55
|
+
sort() { this._params.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)); }
|
|
56
|
+
[Symbol.iterator]() { return this.entries(); }
|
|
57
|
+
toString() {
|
|
58
|
+
return this._params
|
|
59
|
+
.map(([k, v]) => encodeFormPart(k) + '=' + encodeFormPart(v))
|
|
60
|
+
.join('&');
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
globalThis.URLSearchParams = URLSearchParams;
|
|
64
|
+
`;export{e as URL_SEARCH_PARAMS_POLYFILL};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** `URL`: parses and resolves a url string, and exposes its parts. */
|
|
2
|
+
export declare const URL_POLYFILL = "\n // Collapses '.' and '..'. A backslash separates path segments, the way the host parser reads\n // one, so it is folded into '/' first \u2014 otherwise the two disagree about where the host name\n // ends in 'https://a.example\\@b.example/', and guest code reads a host the gateway never calls.\n const normalizePath = (rawPath) => {\n const path = rawPath.replace(/\\\\/g, '/');\n const out = [];\n for (const segment of path.split('/')) {\n if (segment === '.') continue;\n if (segment === '..') { if (out.length > 1) out.pop(); continue; }\n out.push(segment);\n }\n let joined = out.join('/');\n if ((path.endsWith('/.') || path.endsWith('/..')) && !joined.endsWith('/')) joined += '/';\n return joined;\n };\n\n const DEFAULT_PORTS = { 'http:': '80', 'https:': '443', 'ws:': '80', 'wss:': '443', 'ftp:': '21' };\n\n // Percent-encode what cannot travel literally in a url, so a hand-assembled path or query\n // reaches the host parser as the caller meant it. Non-ASCII goes out as UTF-8, in runs, so a\n // surrogate pair is encoded as the one character it stands for.\n const encodeLiterals = (value) =>\n value.replace(/[\\s\"<>\\`{}\\\\^]|[^\\x00-\\x7F]+/g, (chunk) => {\n try { return encodeURIComponent(chunk); } catch (error) { return chunk; }\n });\n\n // A non-ASCII host name is lower-cased but not punycoded \u2014 that needs an IDNA table this sandbox\n // does not carry. The host re-parses the url before it fetches, so the request still goes to the\n // punycoded name; only what guest code reads back differs.\n const parseHostPort = (hostport, scheme) => {\n let hostname = hostport;\n let port = '';\n if (hostport.startsWith('[')) {\n const close = hostport.indexOf(']');\n hostname = hostport.slice(0, close + 1);\n const after = hostport.slice(close + 1);\n if (after.startsWith(':')) port = after.slice(1);\n } else {\n const colon = hostport.lastIndexOf(':');\n if (colon !== -1) { hostname = hostport.slice(0, colon); port = hostport.slice(colon + 1); }\n }\n if (port !== '' && !/^[0-9]+$/.test(port)) return null;\n if (hostname === '') return null;\n return {\n hostname: hostname.toLowerCase(),\n port: DEFAULT_PORTS[scheme] === port ? '' : port,\n // A host written without a port leaves the port alone, rather than clearing it.\n hasPort: port !== '',\n };\n };\n\n const ABSOLUTE_RE = /^([A-Za-z][A-Za-z0-9+\\-.]*):(\\/\\/)?([\\s\\S]*)$/;\n\n const parseAuthorityUrl = (scheme, rest) => {\n const cut = rest.search(/[/\\\\?#]/);\n const authority = cut === -1 ? rest : rest.slice(0, cut);\n let tail = cut === -1 ? '' : rest.slice(cut);\n let username = '';\n let password = '';\n let hostport = authority;\n const at = authority.lastIndexOf('@');\n if (at !== -1) {\n const credentials = authority.slice(0, at);\n hostport = authority.slice(at + 1);\n const colon = credentials.indexOf(':');\n username = colon === -1 ? credentials : credentials.slice(0, colon);\n password = colon === -1 ? '' : credentials.slice(colon + 1);\n }\n const hostPort = parseHostPort(hostport, scheme);\n if (!hostPort) return null;\n let hash = '';\n const hashAt = tail.indexOf('#');\n if (hashAt !== -1) { hash = tail.slice(hashAt); tail = tail.slice(0, hashAt); }\n let search = '';\n const queryAt = tail.indexOf('?');\n if (queryAt !== -1) { search = tail.slice(queryAt); tail = tail.slice(0, queryAt); }\n let pathname = tail === '' ? '/' : tail;\n if (!/^[/\\\\]/.test(pathname)) pathname = '/' + pathname;\n return {\n protocol: scheme,\n username,\n password,\n hostname: hostPort.hostname,\n port: hostPort.port,\n pathname: encodeLiterals(normalizePath(pathname)),\n search: encodeLiterals(search === '?' ? '' : search),\n hash: encodeLiterals(hash === '#' ? '' : hash),\n };\n };\n\n const parseUrl = (input, base) => {\n // A tab or newline inside a url is dropped, not encoded \u2014 the host parser does the same, and\n // a url copied out of a wrapped response body is the usual way one gets in here.\n const str = String(input).trim().replace(/[\\t\\n\\r]/g, '');\n const matched = ABSOLUTE_RE.exec(str);\n // A scheme with no `//` (mailto:, data:) is not a fetch target, so it is not resolved.\n if (matched) return matched[2] ? parseAuthorityUrl(matched[1].toLowerCase() + ':', matched[3]) : null;\n if (base === undefined) return null;\n const resolved = parseUrl(base, undefined);\n if (!resolved) return null;\n if (/^[/\\\\]{2}/.test(str)) return parseAuthorityUrl(resolved.protocol, str.slice(2));\n const parts = { ...resolved };\n if (str.startsWith('#')) {\n parts.hash = encodeLiterals(str === '#' ? '' : str);\n return parts;\n }\n let rest = str;\n let hash = '';\n const hashAt = rest.indexOf('#');\n if (hashAt !== -1) { hash = rest.slice(hashAt); rest = rest.slice(0, hashAt); }\n let search = '';\n const queryAt = rest.indexOf('?');\n if (queryAt !== -1) { search = rest.slice(queryAt); rest = rest.slice(0, queryAt); }\n if (rest !== '') {\n const absolute = /^[/\\\\]/.test(rest)\n ? rest\n : resolved.pathname.slice(0, resolved.pathname.lastIndexOf('/') + 1) + rest;\n parts.pathname = encodeLiterals(normalizePath(absolute));\n }\n // An empty reference with no query of its own keeps the base query (RFC 3986 section 5.3).\n parts.search = rest === '' && search === '' ? resolved.search : encodeLiterals(search === '?' ? '' : search);\n parts.hash = encodeLiterals(hash === '#' ? '' : hash);\n return parts;\n };\n\n const URL = class URL {\n constructor(input, base) {\n const parsed = parseUrl(input, base === undefined ? undefined : String(base));\n if (!parsed) throw new TypeError('Invalid URL: ' + String(input));\n this._parts = parsed;\n this._params = undefined;\n this._edited = false;\n }\n // The query stays exactly as it arrived until searchParams edits it, so reading a url apart\n // and putting it back together does not re-encode what the server sent.\n _applyParams() {\n if (this._edited && this._params) {\n const query = this._params.toString();\n this._parts.search = query ? '?' + query : '';\n this._edited = false;\n }\n }\n // Every part a caller can read, it can also write. Guest code runs sloppy, so a missing\n // setter would swallow `url.host = \u2026` and fetch the address the caller meant to replace.\n get protocol() { return this._parts.protocol; }\n set protocol(value) {\n const next = String(value).toLowerCase().replace(/:$/, '') + ':';\n // Only a scheme that carries an authority can replace one, the way the host parser reads it.\n if (DEFAULT_PORTS[next] !== undefined) this._parts.protocol = next;\n }\n get username() { return this._parts.username; }\n set username(value) { this._parts.username = String(value); }\n get password() { return this._parts.password; }\n set password(value) { this._parts.password = String(value); }\n get hostname() { return this._parts.hostname; }\n set hostname(value) { this._parts.hostname = String(value).toLowerCase(); }\n get port() { return this._parts.port; }\n set port(value) {\n const port = String(value);\n if (port !== '' && !/^[0-9]+$/.test(port)) return;\n this._parts.port = DEFAULT_PORTS[this._parts.protocol] === port ? '' : port;\n }\n get host() {\n return this._parts.port ? this._parts.hostname + ':' + this._parts.port : this._parts.hostname;\n }\n set host(value) {\n const parsed = parseHostPort(String(value), this._parts.protocol);\n if (!parsed) return;\n this._parts.hostname = parsed.hostname;\n if (parsed.hasPort) this._parts.port = parsed.port;\n }\n get origin() { return this._parts.protocol + '//' + this.host; }\n get pathname() { return this._parts.pathname; }\n set pathname(value) {\n const path = String(value);\n this._parts.pathname = encodeLiterals(path.startsWith('/') ? path : '/' + path);\n }\n get search() {\n this._applyParams();\n return this._parts.search;\n }\n set search(value) {\n const query = String(value);\n const body = query.startsWith('?') ? query.slice(1) : query;\n this._parts.search = body ? encodeLiterals('?' + body) : '';\n this._params = undefined;\n this._edited = false;\n }\n get searchParams() {\n if (!this._params) {\n const params = new URLSearchParams(this._parts.search);\n const url = this;\n // Every method that can change the parameters has to mark the query for re-serialization.\n for (const method of ['append', 'set', 'delete', 'sort']) {\n const original = params[method];\n params[method] = function (...args) {\n url._edited = true;\n return original.apply(params, args);\n };\n }\n this._params = params;\n }\n return this._params;\n }\n get hash() { return this._parts.hash; }\n set hash(value) {\n const fragment = String(value);\n this._parts.hash = fragment === ''\n ? ''\n : encodeLiterals(fragment.startsWith('#') ? fragment : '#' + fragment);\n }\n get href() {\n this._applyParams();\n const credentials = this._parts.username\n ? this._parts.username + (this._parts.password ? ':' + this._parts.password : '') + '@'\n : '';\n return this._parts.protocol + '//' + credentials + this.host +\n this._parts.pathname + this._parts.search + this._parts.hash;\n }\n set href(value) {\n const parsed = parseUrl(value, undefined);\n if (!parsed) throw new TypeError('Invalid URL: ' + String(value));\n this._parts = parsed;\n this._params = undefined;\n this._edited = false;\n }\n toString() { return this.href; }\n toJSON() { return this.href; }\n static canParse(input, base) {\n return parseUrl(input, base === undefined ? undefined : String(base)) !== null;\n }\n static parse(input, base) {\n const parsed = parseUrl(input, base === undefined ? undefined : String(base));\n return parsed ? new URL(input, base) : null;\n }\n };\n globalThis.URL = URL;\n";
|
|
3
|
+
//# sourceMappingURL=url.d.ts.map
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
const t=`
|
|
2
|
+
// Collapses '.' and '..'. A backslash separates path segments, the way the host parser reads
|
|
3
|
+
// one, so it is folded into '/' first \u2014 otherwise the two disagree about where the host name
|
|
4
|
+
// ends in 'https://a.example\\@b.example/', and guest code reads a host the gateway never calls.
|
|
5
|
+
const normalizePath = (rawPath) => {
|
|
6
|
+
const path = rawPath.replace(/\\\\/g, '/');
|
|
7
|
+
const out = [];
|
|
8
|
+
for (const segment of path.split('/')) {
|
|
9
|
+
if (segment === '.') continue;
|
|
10
|
+
if (segment === '..') { if (out.length > 1) out.pop(); continue; }
|
|
11
|
+
out.push(segment);
|
|
12
|
+
}
|
|
13
|
+
let joined = out.join('/');
|
|
14
|
+
if ((path.endsWith('/.') || path.endsWith('/..')) && !joined.endsWith('/')) joined += '/';
|
|
15
|
+
return joined;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const DEFAULT_PORTS = { 'http:': '80', 'https:': '443', 'ws:': '80', 'wss:': '443', 'ftp:': '21' };
|
|
19
|
+
|
|
20
|
+
// Percent-encode what cannot travel literally in a url, so a hand-assembled path or query
|
|
21
|
+
// reaches the host parser as the caller meant it. Non-ASCII goes out as UTF-8, in runs, so a
|
|
22
|
+
// surrogate pair is encoded as the one character it stands for.
|
|
23
|
+
const encodeLiterals = (value) =>
|
|
24
|
+
value.replace(/[\\s"<>\\\`{}\\\\^]|[^\\x00-\\x7F]+/g, (chunk) => {
|
|
25
|
+
try { return encodeURIComponent(chunk); } catch (error) { return chunk; }
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// A non-ASCII host name is lower-cased but not punycoded \u2014 that needs an IDNA table this sandbox
|
|
29
|
+
// does not carry. The host re-parses the url before it fetches, so the request still goes to the
|
|
30
|
+
// punycoded name; only what guest code reads back differs.
|
|
31
|
+
const parseHostPort = (hostport, scheme) => {
|
|
32
|
+
let hostname = hostport;
|
|
33
|
+
let port = '';
|
|
34
|
+
if (hostport.startsWith('[')) {
|
|
35
|
+
const close = hostport.indexOf(']');
|
|
36
|
+
hostname = hostport.slice(0, close + 1);
|
|
37
|
+
const after = hostport.slice(close + 1);
|
|
38
|
+
if (after.startsWith(':')) port = after.slice(1);
|
|
39
|
+
} else {
|
|
40
|
+
const colon = hostport.lastIndexOf(':');
|
|
41
|
+
if (colon !== -1) { hostname = hostport.slice(0, colon); port = hostport.slice(colon + 1); }
|
|
42
|
+
}
|
|
43
|
+
if (port !== '' && !/^[0-9]+$/.test(port)) return null;
|
|
44
|
+
if (hostname === '') return null;
|
|
45
|
+
return {
|
|
46
|
+
hostname: hostname.toLowerCase(),
|
|
47
|
+
port: DEFAULT_PORTS[scheme] === port ? '' : port,
|
|
48
|
+
// A host written without a port leaves the port alone, rather than clearing it.
|
|
49
|
+
hasPort: port !== '',
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const ABSOLUTE_RE = /^([A-Za-z][A-Za-z0-9+\\-.]*):(\\/\\/)?([\\s\\S]*)$/;
|
|
54
|
+
|
|
55
|
+
const parseAuthorityUrl = (scheme, rest) => {
|
|
56
|
+
const cut = rest.search(/[/\\\\?#]/);
|
|
57
|
+
const authority = cut === -1 ? rest : rest.slice(0, cut);
|
|
58
|
+
let tail = cut === -1 ? '' : rest.slice(cut);
|
|
59
|
+
let username = '';
|
|
60
|
+
let password = '';
|
|
61
|
+
let hostport = authority;
|
|
62
|
+
const at = authority.lastIndexOf('@');
|
|
63
|
+
if (at !== -1) {
|
|
64
|
+
const credentials = authority.slice(0, at);
|
|
65
|
+
hostport = authority.slice(at + 1);
|
|
66
|
+
const colon = credentials.indexOf(':');
|
|
67
|
+
username = colon === -1 ? credentials : credentials.slice(0, colon);
|
|
68
|
+
password = colon === -1 ? '' : credentials.slice(colon + 1);
|
|
69
|
+
}
|
|
70
|
+
const hostPort = parseHostPort(hostport, scheme);
|
|
71
|
+
if (!hostPort) return null;
|
|
72
|
+
let hash = '';
|
|
73
|
+
const hashAt = tail.indexOf('#');
|
|
74
|
+
if (hashAt !== -1) { hash = tail.slice(hashAt); tail = tail.slice(0, hashAt); }
|
|
75
|
+
let search = '';
|
|
76
|
+
const queryAt = tail.indexOf('?');
|
|
77
|
+
if (queryAt !== -1) { search = tail.slice(queryAt); tail = tail.slice(0, queryAt); }
|
|
78
|
+
let pathname = tail === '' ? '/' : tail;
|
|
79
|
+
if (!/^[/\\\\]/.test(pathname)) pathname = '/' + pathname;
|
|
80
|
+
return {
|
|
81
|
+
protocol: scheme,
|
|
82
|
+
username,
|
|
83
|
+
password,
|
|
84
|
+
hostname: hostPort.hostname,
|
|
85
|
+
port: hostPort.port,
|
|
86
|
+
pathname: encodeLiterals(normalizePath(pathname)),
|
|
87
|
+
search: encodeLiterals(search === '?' ? '' : search),
|
|
88
|
+
hash: encodeLiterals(hash === '#' ? '' : hash),
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const parseUrl = (input, base) => {
|
|
93
|
+
// A tab or newline inside a url is dropped, not encoded \u2014 the host parser does the same, and
|
|
94
|
+
// a url copied out of a wrapped response body is the usual way one gets in here.
|
|
95
|
+
const str = String(input).trim().replace(/[\\t\\n\\r]/g, '');
|
|
96
|
+
const matched = ABSOLUTE_RE.exec(str);
|
|
97
|
+
// A scheme with no \`//\` (mailto:, data:) is not a fetch target, so it is not resolved.
|
|
98
|
+
if (matched) return matched[2] ? parseAuthorityUrl(matched[1].toLowerCase() + ':', matched[3]) : null;
|
|
99
|
+
if (base === undefined) return null;
|
|
100
|
+
const resolved = parseUrl(base, undefined);
|
|
101
|
+
if (!resolved) return null;
|
|
102
|
+
if (/^[/\\\\]{2}/.test(str)) return parseAuthorityUrl(resolved.protocol, str.slice(2));
|
|
103
|
+
const parts = { ...resolved };
|
|
104
|
+
if (str.startsWith('#')) {
|
|
105
|
+
parts.hash = encodeLiterals(str === '#' ? '' : str);
|
|
106
|
+
return parts;
|
|
107
|
+
}
|
|
108
|
+
let rest = str;
|
|
109
|
+
let hash = '';
|
|
110
|
+
const hashAt = rest.indexOf('#');
|
|
111
|
+
if (hashAt !== -1) { hash = rest.slice(hashAt); rest = rest.slice(0, hashAt); }
|
|
112
|
+
let search = '';
|
|
113
|
+
const queryAt = rest.indexOf('?');
|
|
114
|
+
if (queryAt !== -1) { search = rest.slice(queryAt); rest = rest.slice(0, queryAt); }
|
|
115
|
+
if (rest !== '') {
|
|
116
|
+
const absolute = /^[/\\\\]/.test(rest)
|
|
117
|
+
? rest
|
|
118
|
+
: resolved.pathname.slice(0, resolved.pathname.lastIndexOf('/') + 1) + rest;
|
|
119
|
+
parts.pathname = encodeLiterals(normalizePath(absolute));
|
|
120
|
+
}
|
|
121
|
+
// An empty reference with no query of its own keeps the base query (RFC 3986 section 5.3).
|
|
122
|
+
parts.search = rest === '' && search === '' ? resolved.search : encodeLiterals(search === '?' ? '' : search);
|
|
123
|
+
parts.hash = encodeLiterals(hash === '#' ? '' : hash);
|
|
124
|
+
return parts;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const URL = class URL {
|
|
128
|
+
constructor(input, base) {
|
|
129
|
+
const parsed = parseUrl(input, base === undefined ? undefined : String(base));
|
|
130
|
+
if (!parsed) throw new TypeError('Invalid URL: ' + String(input));
|
|
131
|
+
this._parts = parsed;
|
|
132
|
+
this._params = undefined;
|
|
133
|
+
this._edited = false;
|
|
134
|
+
}
|
|
135
|
+
// The query stays exactly as it arrived until searchParams edits it, so reading a url apart
|
|
136
|
+
// and putting it back together does not re-encode what the server sent.
|
|
137
|
+
_applyParams() {
|
|
138
|
+
if (this._edited && this._params) {
|
|
139
|
+
const query = this._params.toString();
|
|
140
|
+
this._parts.search = query ? '?' + query : '';
|
|
141
|
+
this._edited = false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Every part a caller can read, it can also write. Guest code runs sloppy, so a missing
|
|
145
|
+
// setter would swallow \`url.host = \u2026\` and fetch the address the caller meant to replace.
|
|
146
|
+
get protocol() { return this._parts.protocol; }
|
|
147
|
+
set protocol(value) {
|
|
148
|
+
const next = String(value).toLowerCase().replace(/:$/, '') + ':';
|
|
149
|
+
// Only a scheme that carries an authority can replace one, the way the host parser reads it.
|
|
150
|
+
if (DEFAULT_PORTS[next] !== undefined) this._parts.protocol = next;
|
|
151
|
+
}
|
|
152
|
+
get username() { return this._parts.username; }
|
|
153
|
+
set username(value) { this._parts.username = String(value); }
|
|
154
|
+
get password() { return this._parts.password; }
|
|
155
|
+
set password(value) { this._parts.password = String(value); }
|
|
156
|
+
get hostname() { return this._parts.hostname; }
|
|
157
|
+
set hostname(value) { this._parts.hostname = String(value).toLowerCase(); }
|
|
158
|
+
get port() { return this._parts.port; }
|
|
159
|
+
set port(value) {
|
|
160
|
+
const port = String(value);
|
|
161
|
+
if (port !== '' && !/^[0-9]+$/.test(port)) return;
|
|
162
|
+
this._parts.port = DEFAULT_PORTS[this._parts.protocol] === port ? '' : port;
|
|
163
|
+
}
|
|
164
|
+
get host() {
|
|
165
|
+
return this._parts.port ? this._parts.hostname + ':' + this._parts.port : this._parts.hostname;
|
|
166
|
+
}
|
|
167
|
+
set host(value) {
|
|
168
|
+
const parsed = parseHostPort(String(value), this._parts.protocol);
|
|
169
|
+
if (!parsed) return;
|
|
170
|
+
this._parts.hostname = parsed.hostname;
|
|
171
|
+
if (parsed.hasPort) this._parts.port = parsed.port;
|
|
172
|
+
}
|
|
173
|
+
get origin() { return this._parts.protocol + '//' + this.host; }
|
|
174
|
+
get pathname() { return this._parts.pathname; }
|
|
175
|
+
set pathname(value) {
|
|
176
|
+
const path = String(value);
|
|
177
|
+
this._parts.pathname = encodeLiterals(path.startsWith('/') ? path : '/' + path);
|
|
178
|
+
}
|
|
179
|
+
get search() {
|
|
180
|
+
this._applyParams();
|
|
181
|
+
return this._parts.search;
|
|
182
|
+
}
|
|
183
|
+
set search(value) {
|
|
184
|
+
const query = String(value);
|
|
185
|
+
const body = query.startsWith('?') ? query.slice(1) : query;
|
|
186
|
+
this._parts.search = body ? encodeLiterals('?' + body) : '';
|
|
187
|
+
this._params = undefined;
|
|
188
|
+
this._edited = false;
|
|
189
|
+
}
|
|
190
|
+
get searchParams() {
|
|
191
|
+
if (!this._params) {
|
|
192
|
+
const params = new URLSearchParams(this._parts.search);
|
|
193
|
+
const url = this;
|
|
194
|
+
// Every method that can change the parameters has to mark the query for re-serialization.
|
|
195
|
+
for (const method of ['append', 'set', 'delete', 'sort']) {
|
|
196
|
+
const original = params[method];
|
|
197
|
+
params[method] = function (...args) {
|
|
198
|
+
url._edited = true;
|
|
199
|
+
return original.apply(params, args);
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
this._params = params;
|
|
203
|
+
}
|
|
204
|
+
return this._params;
|
|
205
|
+
}
|
|
206
|
+
get hash() { return this._parts.hash; }
|
|
207
|
+
set hash(value) {
|
|
208
|
+
const fragment = String(value);
|
|
209
|
+
this._parts.hash = fragment === ''
|
|
210
|
+
? ''
|
|
211
|
+
: encodeLiterals(fragment.startsWith('#') ? fragment : '#' + fragment);
|
|
212
|
+
}
|
|
213
|
+
get href() {
|
|
214
|
+
this._applyParams();
|
|
215
|
+
const credentials = this._parts.username
|
|
216
|
+
? this._parts.username + (this._parts.password ? ':' + this._parts.password : '') + '@'
|
|
217
|
+
: '';
|
|
218
|
+
return this._parts.protocol + '//' + credentials + this.host +
|
|
219
|
+
this._parts.pathname + this._parts.search + this._parts.hash;
|
|
220
|
+
}
|
|
221
|
+
set href(value) {
|
|
222
|
+
const parsed = parseUrl(value, undefined);
|
|
223
|
+
if (!parsed) throw new TypeError('Invalid URL: ' + String(value));
|
|
224
|
+
this._parts = parsed;
|
|
225
|
+
this._params = undefined;
|
|
226
|
+
this._edited = false;
|
|
227
|
+
}
|
|
228
|
+
toString() { return this.href; }
|
|
229
|
+
toJSON() { return this.href; }
|
|
230
|
+
static canParse(input, base) {
|
|
231
|
+
return parseUrl(input, base === undefined ? undefined : String(base)) !== null;
|
|
232
|
+
}
|
|
233
|
+
static parse(input, base) {
|
|
234
|
+
const parsed = parseUrl(input, base === undefined ? undefined : String(base));
|
|
235
|
+
return parsed ? new URL(input, base) : null;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
globalThis.URL = URL;
|
|
239
|
+
`;export{t as URL_POLYFILL};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{renderDescribeToolsOutput as
|
|
1
|
+
import{renderDescribeToolsOutput as k}from"../capabilities/index.js";import{McpServerType as h}from"../../constants.js";import{reportMcpToolCalled as E,reportMcpToolError as S}from"../../workers/mcp-tool-telemetry.js";import{DESCRIBE_TOOLS_TOOL_NAME as w}from"../constants.js";import{sanitizeToolName as s}from"../build-tool-type-declarations.js";import{UnknownToolError as T}from"./tool-errors.js";function x(i,l){const r=[...new Set([...i.map(n=>s(n.name)),...l.map(n=>s(n.id))])];return{type:"object",required:[],additionalProperties:!1,properties:{tools:{type:"array",description:`Tool names to describe: ${r.join(", ")}. Omit to describe everything.`,items:r.length>0?{type:"string",enum:r}:{type:"string"},nullable:!0}}}}function L(i,l,r,n){const c=new Map(i.map(t=>[s(t.name),t])),p=new Map(r.map(t=>[s(t.id),t]));return async t=>{const m=performance.now(),d=n.mcpMode??"code";try{const o=[...new Set((t.tools??[]).map(s))],a=o.length===0,f=o.filter(e=>!c.has(e)&&!p.has(e));if(f.length>0){const e=[...c.keys(),...p.keys()];throw new T(`Unknown tool(s): ${f.join(", ")}. Valid tools: ${e.join(", ")}.`)}const g=a?r:r.filter(e=>o.includes(s(e.id))),u=a?i:o.filter(e=>c.has(e)).map(e=>c.get(e)),M=await Promise.all(u.map(e=>l(e.name))),b=u.filter((e,v)=>M[v]),y=k(b,g,n);return E({tool:w,mode:d,serverType:h.Docs,durationMs:Math.round(performance.now()-m),outputLength:y.length}),{content:[{type:"text",text:y}]}}catch(o){const a=o instanceof T;throw S({tool:w,mode:d,serverType:h.Docs,durationMs:Math.round(performance.now()-m),message:o instanceof Error?o.message:String(o),stack:!a&&o instanceof Error&&o.stack||"",errorClass:a?"tool_error":"server_error"}),o}}}export{L as describeTools,x as describeToolsSchema};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mcpToolHandlers as l}from"../../../../../client/mcp-tool-handlers-entry.js";import{runInSandbox as p}from"../../../../sandbox/sandbox.js";import{isMcpToolAvailable as h}from"../../workers/execute-mcp-tool.js";import{buildExecuteHostFetch as b,isFetchCapable as E}from"../../gateway-mcp/fetch-capability.js";import{withAuthRequiredMeta as T}from"../../gateway-mcp/upstream-auth.js";import{CODE_MODE_TOOL_NAMES as
|
|
1
|
+
import{mcpToolHandlers as l}from"../../../../../client/mcp-tool-handlers-entry.js";import{runInSandbox as p}from"../../../../sandbox/sandbox.js";import{isMcpToolAvailable as h}from"../../workers/execute-mcp-tool.js";import{buildExecuteHostFetch as b,isFetchCapable as E}from"../../gateway-mcp/fetch-capability.js";import{withAuthRequiredMeta as T}from"../../gateway-mcp/upstream-auth.js";import{CODE_MODE_TOOL_NAMES as C,EXECUTE_TOOL_NAME as O}from"../constants.js";import{sanitizeToolName as A}from"../build-tool-type-declarations.js";import{invokeTool as w}from"../invoke-tool.js";import{createSandboxSetup as x}from"../sandbox/create-sandbox-setup.js";import{auditCode as y}from"../code-audit.js";import{reportCodeExecuted as M}from"../code-execution-telemetry.js";import{logCodeExecutionAudit as N}from"../code-execution-audit.js";const v=async(e,t,r)=>{const o=await F(t,r),n=[],i=E(t)?b(t,c=>n.push(c)):void 0;let a=0;const u=i?c=>(a+=1,i(c)):void 0,d=y(e.code);N({audit:d,code:e.code,description:e.description,sessionHandle:e.sessionHandle,toolNames:Object.keys(o),fetchBudget:t.gatewayFetchBudgetPerExec,fetchCapable:i!==void 0});const m=Date.now(),{result:f,error:s}=await p(e.code,{setupContext:x(o,u)});return M({audit:d,fetchCount:a,outcome:s===void 0?"ok":"error",durationMs:Date.now()-m}),T({content:[{type:"text",text:JSON.stringify({result:f,error:s})}],isError:s!==void 0},n)};async function F(e,t){const r={};for(const o of Object.keys(l))C.has(o)||!await h({toolName:o,context:e}).catch(()=>!1)||(r[A(o)]=i=>w(o,i,e,t));return r}var J={[O]:v};export{J as default};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CallToolResult, InputRequiredResult } from '@modelcontextprotocol/server';
|
|
2
|
+
import type { McpToolSchema } from '../../../../types';
|
|
3
|
+
import type { McpToolContext } from '../../types.js';
|
|
4
|
+
import type { KvService } from '@redocly/config';
|
|
5
|
+
export type ManageApiCredentialsDeps = {
|
|
6
|
+
getClientCapabilities: () => {
|
|
7
|
+
elicitation?: {
|
|
8
|
+
url?: unknown;
|
|
9
|
+
};
|
|
10
|
+
} | undefined;
|
|
11
|
+
getKv: () => Promise<KvService>;
|
|
12
|
+
};
|
|
13
|
+
export declare function isManageApiCredentialsToolAvailable(context: McpToolContext): boolean;
|
|
14
|
+
export declare function manageApiCredentialsSchema(context: McpToolContext): McpToolSchema;
|
|
15
|
+
export declare function manageApiCredentials(context: McpToolContext, deps: ManageApiCredentialsDeps): (args: {
|
|
16
|
+
api?: unknown;
|
|
17
|
+
sessionHandle?: unknown;
|
|
18
|
+
}) => Promise<CallToolResult | InputRequiredResult>;
|
|
19
|
+
//# sourceMappingURL=manage-credentials.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{MANAGE_API_CREDENTIALS_TOOL_NAME as m}from"../../constants.js";import{buildUpstreamCredentialFallback as h,buildUpstreamCredentialInputRequired as f}from"../../gateway-mcp/elicitation.js";import{getCallableApis as o,isFetchCapable as g}from"../../gateway-mcp/fetch-capability.js";import{secretStore as A}from"../../gateway-mcp/secret-store.js";import{MISSING_SESSION_HANDLE_MESSAGE as v,resolveSecretSubject as b}from"../../gateway-mcp/subject.js";import{resolveUpstreamAuthScheme as y}from"../../gateway-mcp/upstream-auth-scheme.js";function k(e){return!!e.elicitationEnabled&&g(e)}function j(e){const t=o(e).map(n=>n.relativePath);return{name:m,description:["Get a secure link where the user sets, replaces, or removes the credentials this server sends to a documented API.","Call it when the user wants to change or clear an API key, or when a tool result tells you the stored credentials were rejected.","It returns a link for the user to open - never ask for the secret in the conversation and never pass it as an argument."].join(`
|
|
2
|
+
`),annotations:{title:"Manage API credentials",readOnlyHint:!1,openWorldHint:!1},schema:{type:"object",required:["api"],additionalProperties:!1,properties:{api:{type:"string",description:`The API to manage credentials for.${t.length>0?` One of: ${t.join(", ")}.`:""}`,minLength:1,...t.length>0?{enum:t}:{}},sessionHandle:{type:"string",description:"Handle returned by createAnonymousSession. Required while the caller is anonymous, so the credentials are stored against the same subject the API calls use.",minLength:1}}}}}function H(e,i){return async t=>{const n=b(e.user,typeof t.sessionHandle=="string"?t.sessionHandle:void 0);if(n.kind==="invalid")return l(n.message);if(n.kind==="anonymous")return l(v);const{subject:u}=n,s=typeof t.api=="string"?t.api:"",r=o(e).find(a=>a.relativePath===s||a.name===s);if(!r){const a=o(e).map(d=>d.relativePath).join(", ");return l(`Unknown api "${s}". Credentials can only be managed for the APIs this server can call: ${a||"none"}.`)}const c=await i.getKv(),p={subject:u,baseUrl:e.baseUrl??"",target:{api:r.relativePath,name:r.name},auth:await y(e,r.relativePath),kv:c,hasExistingSecret:await A.hasSecret(c,u,r.relativePath),reason:{kind:"requested"}};return i.getClientCapabilities()?.elicitation?.url?await f(p):{content:[{type:"text",text:await h(p)}],isError:!1}}}function l(e){return{content:[{type:"text",text:e}],isError:!0}}export{k as isManageApiCredentialsToolAvailable,H as manageApiCredentials,j as manageApiCredentialsSchema};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class n extends Error{constructor(r){super(r),this.name="UnknownToolError"}}export{n as UnknownToolError};
|
|
@@ -15,4 +15,5 @@ export declare const MAX_DOCUMENTS_PER_CATEGORY = 3;
|
|
|
15
15
|
export declare const MCP_NOT_ALLOWED_TEMPLATE_ID = "mcp-not-allowed";
|
|
16
16
|
export declare const DEFAULT_DOCS_MCP_SERVER_NAME = "Docs MCP server";
|
|
17
17
|
export declare const CREATE_ANONYMOUS_SESSION_TOOL_NAME = "createAnonymousSession";
|
|
18
|
+
export declare const MANAGE_API_CREDENTIALS_TOOL_NAME = "manageApiCredentials";
|
|
18
19
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LATEST_PROTOCOL_VERSION as o}from"@modelcontextprotocol/server";const
|
|
1
|
+
import{LATEST_PROTOCOL_VERSION as o}from"@modelcontextprotocol/server";const r={Docs:"docs"},e={InternalError:-32603,ServerError:-32e3,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602},_=o,t=3e4,O=15e3,n=3,s="mcp-not-allowed",A="Docs MCP server",T="createAnonymousSession",M="manageApiCredentials";export{T as CREATE_ANONYMOUS_SESSION_TOOL_NAME,t as DEFAULT_CONNECTION_TIMEOUT_MS,A as DEFAULT_DOCS_MCP_SERVER_NAME,M as MANAGE_API_CREDENTIALS_TOOL_NAME,n as MAX_DOCUMENTS_PER_CATEGORY,s as MCP_NOT_ALLOWED_TEMPLATE_ID,_ as MCP_PROTOCOL_VERSION,e as McpErrorCodes,r as McpServerType,O as SSE_KEEPALIVE_INTERVAL_MS};
|