agents 0.31.0 → 0.32.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/dist/{agent-routing-wS1TimZ_.d.ts → agent-routing-vVMA7m8Y.d.ts} +6 -6
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-Bamxxb6Y.d.ts → agent-tools-gGXXkf1z.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/agent-tools.js +0 -1
- package/dist/agent-tools.js.map +1 -1
- package/dist/browser/ai.js +1 -1
- package/dist/browser/tools/ai-sdk.d.ts +66 -1
- package/dist/browser/tools/ai-sdk.js +2 -2
- package/dist/browser/tools/pi.js +2 -2
- package/dist/browser/tools/tanstack-ai.d.ts +2 -2
- package/dist/browser/tools/tanstack-ai.js +2 -2
- package/dist/browser/tools/tanstack-ai.js.map +1 -1
- package/dist/{browser-tool-lGnvEBLJ.js → browser-tool-DRan7Lk6.js} +2 -2
- package/dist/{browser-tool-lGnvEBLJ.js.map → browser-tool-DRan7Lk6.js.map} +1 -1
- package/dist/catalog-BpOejOsE.js +239 -0
- package/dist/catalog-BpOejOsE.js.map +1 -0
- package/dist/catalog-BpiVV1OF.d.ts +173 -0
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/{client-wn4-yqGz.d.ts → client-eSfgYvd3.d.ts} +2 -2
- package/dist/client.d.ts +1 -1
- package/dist/{cloudflare-Dzvc7V2N.js → cloudflare-CUUm_9q9.js} +26 -4
- package/dist/cloudflare-CUUm_9q9.js.map +1 -0
- package/dist/{do-oauth-client-provider-DfsUcpc3.d.ts → do-oauth-client-provider-DtNqv7oj.d.ts} +26 -2
- package/dist/{index-YSKgfgg9.d.ts → emitter-BJZtCVjQ.d.ts} +6 -140
- package/dist/emitter-DPOVcCln.js +15 -0
- package/dist/emitter-DPOVcCln.js.map +1 -0
- package/dist/experimental/channels/web/index.js +1 -1
- package/dist/harness/container/index.js +0 -1
- package/dist/harness/container/index.js.map +1 -1
- package/dist/harness/container/runtime/index.js +2 -2
- package/dist/harness/opencode/index.js +0 -1
- package/dist/harness/opencode/index.js.map +1 -1
- package/dist/harness/pi/index.d.ts +11 -4
- package/dist/harness/pi/index.js +43 -141
- package/dist/harness/pi/index.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -2
- package/dist/markdown-BZ-VLtA1.js +86 -0
- package/dist/markdown-BZ-VLtA1.js.map +1 -0
- package/dist/mcp/client/do-oauth-client-provider.d.ts +4 -2
- package/dist/mcp/client/do-oauth-client-provider.js +15 -1
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/models/pi-ai/index.js +129 -2
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/observability/ai/index.js +1 -2
- package/dist/observability/ai/index.js.map +1 -1
- package/dist/observability/index.d.ts +170 -9
- package/dist/observability/index.js +386 -11
- package/dist/observability/index.js.map +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/resource-B59OV2a2.js +325 -0
- package/dist/resource-B59OV2a2.js.map +1 -0
- package/dist/routing/index.d.ts +1 -1
- package/dist/script-CFDLTk5b.d.ts +91 -0
- package/dist/script-workspace-BpdAYq1R.d.ts +41 -0
- package/dist/serializable.d.ts +1 -1
- package/dist/skill-DRBcIBjC.d.ts +221 -0
- package/dist/skills/index.d.ts +275 -36
- package/dist/skills/index.js +265 -1534
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/runner.d.ts +37 -0
- package/dist/skills/runner.js +912 -0
- package/dist/skills/runner.js.map +1 -0
- package/dist/skills/tools/ai-sdk.d.ts +36 -0
- package/dist/skills/tools/ai-sdk.js +94 -0
- package/dist/skills/tools/ai-sdk.js.map +1 -0
- package/dist/source-9RQzlEhM.d.ts +112 -0
- package/dist/{src-BGolXG_H.js → src-DoGNJ4Ud.js} +4 -5
- package/dist/src-DoGNJ4Ud.js.map +1 -0
- package/dist/sub-routing.d.ts +1 -1
- package/dist/tool-CxKsvxjm.js.map +1 -1
- package/dist/tool-DkT_DJBm.js.map +1 -1
- package/dist/{tool-helpers-BodWi4gd.js → tool-helpers-BI7ifO2S.js} +1 -2
- package/dist/{tool-helpers-BodWi4gd.js.map → tool-helpers-BI7ifO2S.js.map} +1 -1
- package/dist/vite.d.ts +2 -2
- package/dist/vite.js +10 -258
- package/dist/vite.js.map +1 -1
- package/dist/voice/index.d.ts +1 -1
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-CyoeosdO.js → websockets-C6SJtWCJ.js} +1 -2
- package/dist/{websockets-CyoeosdO.js.map → websockets-C6SJtWCJ.js.map} +1 -1
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +0 -1
- package/dist/workflows.js.map +1 -1
- package/docs/harnesses/pi.md +9 -3
- package/docs/mcp-client.md +23 -1
- package/docs/mcp-servers.md +2 -2
- package/docs/observability.md +5 -3
- package/package.json +24 -15
- package/dist/ai-sdk-hW3vntnk.d.ts +0 -72
- package/dist/cloudflare-Dzvc7V2N.js.map +0 -1
- package/dist/index-iv9FTXX9.d.ts +0 -311
- package/dist/skills/compile.d.ts +0 -40
- package/dist/skills/compile.js +0 -65
- package/dist/skills/compile.js.map +0 -1
- package/dist/src-BGolXG_H.js.map +0 -1
- package/skills-module.d.ts +0 -22
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { d as err, f as ok, l as parseSkillFrontmatter, s as SkillParseError } from "./resource-B59OV2a2.js";
|
|
2
|
+
import { parse, stringify } from "yaml";
|
|
3
|
+
//#region src/skills/markdown.ts
|
|
4
|
+
/**
|
|
5
|
+
* `SKILL.md` text: YAML frontmatter between `---` lines, then Markdown.
|
|
6
|
+
* Kept apart from `./skill` because it loads the YAML parser.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
const FRONTMATTER = /^\uFEFF?---[ \t]*\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n([\s\S]*))?$/;
|
|
11
|
+
/**
|
|
12
|
+
* Parse a `SKILL.md` file.
|
|
13
|
+
*
|
|
14
|
+
* Follows the spec's guide for agents: a skill that breaks a rule still
|
|
15
|
+
* parses, with each broken rule in `warnings`. Frontmatter that only fails
|
|
16
|
+
* because of unquoted values containing `: ` (for example
|
|
17
|
+
* `description: Use when: the user asks`), which many clients accept, is
|
|
18
|
+
* read again with those values quoted. The parse fails only when the skill
|
|
19
|
+
* cannot be used: no frontmatter, YAML that still does not parse, no
|
|
20
|
+
* description, or an unsafe name.
|
|
21
|
+
*
|
|
22
|
+
* To check a skill before storing it, require `warnings` to be empty.
|
|
23
|
+
*
|
|
24
|
+
* @param markdown - The full file: YAML frontmatter, then Markdown.
|
|
25
|
+
* @param options - `directory` to check the name against.
|
|
26
|
+
* @returns The parsed skill and warnings, or a `SkillParseError`.
|
|
27
|
+
*/
|
|
28
|
+
function parseSkill(markdown, options = {}) {
|
|
29
|
+
const match = FRONTMATTER.exec(markdown);
|
|
30
|
+
if (!match) return err(new SkillParseError("missing-frontmatter", "SKILL.md must start with YAML frontmatter between --- lines."));
|
|
31
|
+
const yaml = match[1] ?? "";
|
|
32
|
+
const body = match[2] ?? "";
|
|
33
|
+
const parsed = parseFrontmatterYaml(yaml);
|
|
34
|
+
if (parsed.ok) return parseSkillFrontmatter(parsed.value ?? {}, body, options);
|
|
35
|
+
const repaired = parseFrontmatterYaml(quoteColonValues(yaml));
|
|
36
|
+
if (!repaired.ok) return parsed;
|
|
37
|
+
const result = parseSkillFrontmatter(repaired.value ?? {}, body, options);
|
|
38
|
+
return result.ok ? {
|
|
39
|
+
...result,
|
|
40
|
+
warnings: [new SkillParseError("invalid-yaml", "SKILL.md frontmatter is not valid YAML; it was read after quoting values that contain `: `.", { cause: parsed.error.cause }), ...result.warnings]
|
|
41
|
+
} : result;
|
|
42
|
+
}
|
|
43
|
+
function parseFrontmatterYaml(yaml) {
|
|
44
|
+
try {
|
|
45
|
+
return ok(parse(yaml));
|
|
46
|
+
} catch (cause) {
|
|
47
|
+
return err(new SkillParseError("invalid-yaml", `SKILL.md frontmatter is not valid YAML: ${cause instanceof Error ? cause.message : String(cause)}`, { cause }));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Quote top-level `key: value` lines whose value contains `: `, the most
|
|
52
|
+
* common way hand-written frontmatter breaks YAML. Values that are already
|
|
53
|
+
* quoted, block scalars, or flow collections are left alone.
|
|
54
|
+
*/
|
|
55
|
+
function quoteColonValues(yaml) {
|
|
56
|
+
return yaml.split(/\r?\n/).map((line) => {
|
|
57
|
+
const match = /^([A-Za-z0-9_-]+):[ \t]+(.+)$/.exec(line);
|
|
58
|
+
if (!match) return line;
|
|
59
|
+
const [, key, value] = match;
|
|
60
|
+
if (value === void 0 || !value.includes(": ")) return line;
|
|
61
|
+
if (/^["'|>[{&*!]/.test(value)) return line;
|
|
62
|
+
return `${key}: ${JSON.stringify(value.trim())}`;
|
|
63
|
+
}).join("\n");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Render a skill back to `SKILL.md` text.
|
|
67
|
+
*
|
|
68
|
+
* @param skill - The parsed skill.
|
|
69
|
+
* @returns Frontmatter and body that {@link parseSkill} reads back to an
|
|
70
|
+
* equal skill.
|
|
71
|
+
*/
|
|
72
|
+
function formatSkill(skill) {
|
|
73
|
+
return `---\n${stringify({
|
|
74
|
+
name: skill.name,
|
|
75
|
+
description: skill.description,
|
|
76
|
+
...skill.license === void 0 ? {} : { license: skill.license },
|
|
77
|
+
...skill.compatibility === void 0 ? {} : { compatibility: skill.compatibility },
|
|
78
|
+
...Object.keys(skill.metadata).length === 0 ? {} : { metadata: skill.metadata },
|
|
79
|
+
...skill.allowedTools.length === 0 ? {} : { "allowed-tools": skill.allowedTools.join(" ") },
|
|
80
|
+
...skill.extraFields
|
|
81
|
+
}).trimEnd()}\n---\n${skill.body}`;
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { parseSkill as n, formatSkill as t };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=markdown-BZ-VLtA1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-BZ-VLtA1.js","names":["parseYaml","stringifyYaml"],"sources":["../src/skills/markdown.ts"],"sourcesContent":["import { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { err, ok, type SkillResult } from \"./result\";\nimport {\n parseSkillFrontmatter,\n SkillParseError,\n type ParseSkillOptions,\n type Skill,\n type SkillParseResult\n} from \"./skill\";\n\n/**\n * `SKILL.md` text: YAML frontmatter between `---` lines, then Markdown.\n * Kept apart from `./skill` because it loads the YAML parser.\n *\n * @module\n */\n\nconst FRONTMATTER =\n /^\\uFEFF?---[ \\t]*\\r?\\n(?:([\\s\\S]*?)\\r?\\n)?---[ \\t]*(?:\\r?\\n([\\s\\S]*))?$/;\n\n/**\n * Parse a `SKILL.md` file.\n *\n * Follows the spec's guide for agents: a skill that breaks a rule still\n * parses, with each broken rule in `warnings`. Frontmatter that only fails\n * because of unquoted values containing `: ` (for example\n * `description: Use when: the user asks`), which many clients accept, is\n * read again with those values quoted. The parse fails only when the skill\n * cannot be used: no frontmatter, YAML that still does not parse, no\n * description, or an unsafe name.\n *\n * To check a skill before storing it, require `warnings` to be empty.\n *\n * @param markdown - The full file: YAML frontmatter, then Markdown.\n * @param options - `directory` to check the name against.\n * @returns The parsed skill and warnings, or a `SkillParseError`.\n */\nexport function parseSkill(\n markdown: string,\n options: ParseSkillOptions = {}\n): SkillParseResult {\n const match = FRONTMATTER.exec(markdown);\n if (!match) {\n return err(\n new SkillParseError(\n \"missing-frontmatter\",\n \"SKILL.md must start with YAML frontmatter between --- lines.\"\n )\n );\n }\n\n const yaml = match[1] ?? \"\";\n const body = match[2] ?? \"\";\n const parsed = parseFrontmatterYaml(yaml);\n if (parsed.ok) {\n return parseSkillFrontmatter(parsed.value ?? {}, body, options);\n }\n const repaired = parseFrontmatterYaml(quoteColonValues(yaml));\n if (!repaired.ok) return parsed;\n const result = parseSkillFrontmatter(repaired.value ?? {}, body, options);\n return result.ok\n ? {\n ...result,\n warnings: [\n new SkillParseError(\n \"invalid-yaml\",\n \"SKILL.md frontmatter is not valid YAML; it was read after quoting values that contain `: `.\",\n { cause: parsed.error.cause }\n ),\n ...result.warnings\n ]\n }\n : result;\n}\n\nfunction parseFrontmatterYaml(\n yaml: string\n): SkillResult<unknown, SkillParseError> {\n try {\n return ok(parseYaml(yaml));\n } catch (cause) {\n return err(\n new SkillParseError(\n \"invalid-yaml\",\n `SKILL.md frontmatter is not valid YAML: ${cause instanceof Error ? cause.message : String(cause)}`,\n { cause }\n )\n );\n }\n}\n\n/**\n * Quote top-level `key: value` lines whose value contains `: `, the most\n * common way hand-written frontmatter breaks YAML. Values that are already\n * quoted, block scalars, or flow collections are left alone.\n */\nfunction quoteColonValues(yaml: string): string {\n return yaml\n .split(/\\r?\\n/)\n .map((line) => {\n const match = /^([A-Za-z0-9_-]+):[ \\t]+(.+)$/.exec(line);\n if (!match) return line;\n const [, key, value] = match;\n if (value === undefined || !value.includes(\": \")) return line;\n if (/^[\"'|>[{&*!]/.test(value)) return line;\n return `${key}: ${JSON.stringify(value.trim())}`;\n })\n .join(\"\\n\");\n}\n\n/**\n * Render a skill back to `SKILL.md` text.\n *\n * @param skill - The parsed skill.\n * @returns Frontmatter and body that {@link parseSkill} reads back to an\n * equal skill.\n */\nexport function formatSkill(skill: Skill): string {\n const frontmatter: Record<string, unknown> = {\n name: skill.name,\n description: skill.description,\n ...(skill.license === undefined ? {} : { license: skill.license }),\n ...(skill.compatibility === undefined\n ? {}\n : { compatibility: skill.compatibility }),\n ...(Object.keys(skill.metadata).length === 0\n ? {}\n : { metadata: skill.metadata }),\n ...(skill.allowedTools.length === 0\n ? {}\n : { \"allowed-tools\": skill.allowedTools.join(\" \") }),\n ...skill.extraFields\n };\n return `---\\n${stringifyYaml(frontmatter).trimEnd()}\\n---\\n${skill.body}`;\n}\n"],"mappings":";;;;;;;;;AAiBA,MAAM,cACJ;;;;;;;;;;;;;;;;;;AAmBF,SAAgB,WACd,UACA,UAA6B,CAAC,GACZ;CAClB,MAAM,QAAQ,YAAY,KAAK,QAAQ;CACvC,IAAI,CAAC,OACH,OAAO,IACL,IAAI,gBACF,uBACA,8DACF,CACF;CAGF,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,SAAS,qBAAqB,IAAI;CACxC,IAAI,OAAO,IACT,OAAO,sBAAsB,OAAO,SAAS,CAAC,GAAG,MAAM,OAAO;CAEhE,MAAM,WAAW,qBAAqB,iBAAiB,IAAI,CAAC;CAC5D,IAAI,CAAC,SAAS,IAAI,OAAO;CACzB,MAAM,SAAS,sBAAsB,SAAS,SAAS,CAAC,GAAG,MAAM,OAAO;CACxE,OAAO,OAAO,KACV;EACE,GAAG;EACH,UAAU,CACR,IAAI,gBACF,gBACA,+FACA,EAAE,OAAO,OAAO,MAAM,MAAM,CAC9B,GACA,GAAG,OAAO,QACZ;CACF,IACA;AACN;AAEA,SAAS,qBACP,MACuC;CACvC,IAAI;EACF,OAAO,GAAGA,MAAU,IAAI,CAAC;CAC3B,SAAS,OAAO;EACd,OAAO,IACL,IAAI,gBACF,gBACA,2CAA2C,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KAChG,EAAE,MAAM,CACV,CACF;CACF;AACF;;;;;;AAOA,SAAS,iBAAiB,MAAsB;CAC9C,OAAO,KACJ,MAAM,OAAO,CAAC,CACd,KAAK,SAAS;EACb,MAAM,QAAQ,gCAAgC,KAAK,IAAI;EACvD,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,GAAG,KAAK,SAAS;EACvB,IAAI,UAAU,KAAA,KAAa,CAAC,MAAM,SAAS,IAAI,GAAG,OAAO;EACzD,IAAI,eAAe,KAAK,KAAK,GAAG,OAAO;EACvC,OAAO,GAAG,IAAI,IAAI,KAAK,UAAU,MAAM,KAAK,CAAC;CAC/C,CAAC,CAAC,CACD,KAAK,IAAI;AACd;;;;;;;;AASA,SAAgB,YAAY,OAAsB;CAgBhD,OAAO,QAAQC,UAAc;EAd3B,MAAM,MAAM;EACZ,aAAa,MAAM;EACnB,GAAI,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;EAChE,GAAI,MAAM,kBAAkB,KAAA,IACxB,CAAC,IACD,EAAE,eAAe,MAAM,cAAc;EACzC,GAAI,OAAO,KAAK,MAAM,QAAQ,CAAC,CAAC,WAAW,IACvC,CAAC,IACD,EAAE,UAAU,MAAM,SAAS;EAC/B,GAAI,MAAM,aAAa,WAAW,IAC9B,CAAC,IACD,EAAE,iBAAiB,MAAM,aAAa,KAAK,GAAG,EAAE;EACpD,GAAG,MAAM;CAE4B,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,MAAM;AACrE"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
i as DurableObjectOAuthClientProviderOptions,
|
|
2
3
|
n as AgentsOAuthProvider,
|
|
3
4
|
r as DurableObjectOAuthClientProvider,
|
|
4
5
|
t as AgentMcpOAuthProvider
|
|
5
|
-
} from "../../do-oauth-client-provider-
|
|
6
|
+
} from "../../do-oauth-client-provider-DtNqv7oj.js";
|
|
6
7
|
export {
|
|
7
8
|
AgentMcpOAuthProvider,
|
|
8
9
|
AgentsOAuthProvider,
|
|
9
|
-
DurableObjectOAuthClientProvider
|
|
10
|
+
DurableObjectOAuthClientProvider,
|
|
11
|
+
DurableObjectOAuthClientProviderOptions
|
|
10
12
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { nanoid } from "nanoid";
|
|
3
|
+
import { validateClientMetadataUrl } from "@modelcontextprotocol/client";
|
|
3
4
|
//#region src/mcp/client/do-oauth-client-provider.ts
|
|
4
5
|
const STATE_EXPIRATION_MS = 600 * 1e3;
|
|
5
6
|
const codeVerifierStateStorage = new AsyncLocalStorage();
|
|
@@ -26,11 +27,24 @@ function isExpired(createdAt) {
|
|
|
26
27
|
return Date.now() - createdAt > STATE_EXPIRATION_MS;
|
|
27
28
|
}
|
|
28
29
|
var DurableObjectOAuthClientProvider = class {
|
|
29
|
-
constructor(storage, clientName, baseRedirectUrl) {
|
|
30
|
+
constructor(storage, clientName, baseRedirectUrl, options = {}) {
|
|
30
31
|
this.storage = storage;
|
|
31
32
|
this.clientName = clientName;
|
|
32
33
|
this.baseRedirectUrl = baseRedirectUrl;
|
|
33
34
|
if (!storage) throw new Error("DurableObjectOAuthClientProvider requires a valid DurableObjectStorage instance");
|
|
35
|
+
validateClientMetadataUrl(options.clientMetadataUrl);
|
|
36
|
+
this.clientMetadataUrl = options.clientMetadataUrl || void 0;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The Client ID Metadata Document to serve at `clientMetadataUrl`.
|
|
40
|
+
* Throws when the provider has no `clientMetadataUrl`.
|
|
41
|
+
*/
|
|
42
|
+
get clientMetadataDocument() {
|
|
43
|
+
if (!this.clientMetadataUrl) throw new Error("clientMetadataDocument requires a clientMetadataUrl option");
|
|
44
|
+
return {
|
|
45
|
+
client_id: this.clientMetadataUrl,
|
|
46
|
+
...this.clientMetadata
|
|
47
|
+
};
|
|
34
48
|
}
|
|
35
49
|
get clientMetadata() {
|
|
36
50
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do-oauth-client-provider.js","names":[],"sources":["../../../src/mcp/client/do-oauth-client-provider.ts"],"sourcesContent":["import type {\n OAuthClientInformationContext,\n OAuthClientMetadata,\n OAuthClientProvider,\n OAuthDiscoveryState,\n StoredOAuthClientInformation,\n StoredOAuthTokens\n} from \"@modelcontextprotocol/client\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { nanoid } from \"nanoid\";\n\nconst STATE_EXPIRATION_MS = 10 * 60 * 1000; // 10 minutes\n\nconst codeVerifierStateStorage = new AsyncLocalStorage<{\n state: string;\n servedKey?: string;\n}>();\n\ninterface StoredState {\n nonce: string;\n serverId: string;\n createdAt: number;\n}\n\ninterface StoredCodeVerifier {\n verifier: string;\n createdAt: number;\n}\n\n// A slight extension to the standard OAuthClientProvider interface because `redirectToAuthorization` doesn't give us the interface we need\n// This allows us to track authentication for a specific server and associated dynamic client registration\nexport interface AgentMcpOAuthProvider extends OAuthClientProvider {\n authUrl: string | undefined;\n clientId: string | undefined;\n serverId: string | undefined;\n checkState(\n state: string\n ): Promise<{ valid: boolean; serverId?: string; error?: string }>;\n consumeState(state: string): Promise<void>;\n runWithCodeVerifierState?<T>(\n state: string,\n callback: () => Promise<T>\n ): Promise<T>;\n deleteCodeVerifier(): Promise<void>;\n}\n\nfunction parseOAuthState(\n state: string\n): { nonce: string; serverId: string } | undefined {\n const parts = state.split(\".\");\n if (parts.length !== 2) {\n return undefined;\n }\n\n const [nonce, serverId] = parts;\n if (!nonce || !serverId) {\n return undefined;\n }\n\n return { nonce, serverId };\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nasync function createCodeChallenge(verifier: string): Promise<string> {\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(verifier)\n );\n return base64UrlEncode(new Uint8Array(digest));\n}\n\nfunction isExpired(createdAt: number): boolean {\n return Date.now() - createdAt > STATE_EXPIRATION_MS;\n}\n\n/**\n * @deprecated Use {@link AgentMcpOAuthProvider} instead.\n */\nexport type AgentsOAuthProvider = AgentMcpOAuthProvider;\n\nexport class DurableObjectOAuthClientProvider implements AgentMcpOAuthProvider {\n private _authUrl_: string | undefined;\n private _serverId_: string | undefined;\n private _clientId_: string | undefined;\n\n constructor(\n public storage: DurableObjectStorage,\n public clientName: string,\n public baseRedirectUrl: string\n ) {\n if (!storage) {\n throw new Error(\n \"DurableObjectOAuthClientProvider requires a valid DurableObjectStorage instance\"\n );\n }\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n client_name: this.clientName,\n client_uri: this.clientUri,\n grant_types: [\"authorization_code\", \"refresh_token\"],\n redirect_uris: [this.redirectUrl],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\"\n };\n }\n\n get clientUri() {\n return new URL(this.redirectUrl).origin;\n }\n\n get redirectUrl() {\n return this.baseRedirectUrl;\n }\n\n get clientId() {\n if (!this._clientId_) {\n throw new Error(\"Trying to access clientId before it was set\");\n }\n return this._clientId_;\n }\n\n set clientId(clientId_: string) {\n this._clientId_ = clientId_;\n }\n\n get serverId() {\n if (!this._serverId_) {\n throw new Error(\"Trying to access serverId before it was set\");\n }\n return this._serverId_;\n }\n\n set serverId(serverId_: string) {\n this._serverId_ = serverId_;\n }\n\n keyPrefix(clientId: string) {\n return `/${this.clientName}/${this.serverId}/${clientId}`;\n }\n\n clientInfoKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/client_info/`;\n }\n\n discoveryStateKey() {\n return `/${this.clientName}/${this.serverId}/oauth_discovery`;\n }\n\n async saveDiscoveryState(state: OAuthDiscoveryState): Promise<void> {\n await this.storage.put(this.discoveryStateKey(), state);\n }\n\n async discoveryState(): Promise<OAuthDiscoveryState | undefined> {\n return (\n (await this.storage.get<OAuthDiscoveryState>(this.discoveryStateKey())) ??\n undefined\n );\n }\n\n async clientInformation(\n _context?: OAuthClientInformationContext\n ): Promise<StoredOAuthClientInformation | undefined> {\n if (!this._clientId_) return undefined;\n return (\n (await this.storage.get<StoredOAuthClientInformation>(\n this.clientInfoKey(this.clientId)\n )) ?? undefined\n );\n }\n\n async saveClientInformation(\n clientInformation: StoredOAuthClientInformation,\n _context?: OAuthClientInformationContext\n ): Promise<void> {\n this.clientId = clientInformation.client_id;\n // Round-trip the SDK's issuer stamp verbatim. The SDK treats a credential\n // stamped for another issuer as absent, so one durable slot per MCP server\n // is both sufficient and safer than maintaining our own issuer index.\n await this.storage.put(\n this.clientInfoKey(clientInformation.client_id),\n clientInformation\n );\n }\n\n tokenKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/token`;\n }\n\n async tokens(\n _context?: OAuthClientInformationContext\n ): Promise<StoredOAuthTokens | undefined> {\n if (!this._clientId_) return undefined;\n return (\n (await this.storage.get<StoredOAuthTokens>(\n this.tokenKey(this.clientId)\n )) ?? undefined\n );\n }\n\n async saveTokens(\n tokens: StoredOAuthTokens,\n _context?: OAuthClientInformationContext\n ): Promise<void> {\n // Keep the SDK-owned issuer stamp intact for SEP-2352 validation. Discovery\n // is needed across the browser redirect, but once token issuance succeeds\n // it must not pin later re-authorization to this AS: a subsequent 401 must\n // re-read PRM so an authorization-server migration can be observed.\n await this.storage.put(this.tokenKey(this.clientId), tokens);\n await this.storage.delete(this.discoveryStateKey());\n }\n\n get authUrl() {\n return this._authUrl_;\n }\n\n stateKey(nonce: string) {\n return `/${this.clientName}/${this.serverId}/state/${nonce}`;\n }\n\n async state(): Promise<string> {\n const nonce = nanoid();\n const state = `${nonce}.${this.serverId}`;\n const storedState: StoredState = {\n nonce,\n serverId: this.serverId,\n createdAt: Date.now()\n };\n await this.storage.put(this.stateKey(nonce), storedState);\n return state;\n }\n\n async checkState(\n state: string\n ): Promise<{ valid: boolean; serverId?: string; error?: string }> {\n const parsed = parseOAuthState(state);\n if (!parsed) {\n return { valid: false, error: \"Invalid state format\" };\n }\n\n const { nonce, serverId } = parsed;\n const key = this.stateKey(nonce);\n const storedState = await this.storage.get<StoredState>(key);\n\n if (!storedState) {\n return { valid: false, error: \"State not found or already used\" };\n }\n\n if (storedState.serverId !== serverId) {\n await this.storage.delete(key);\n return { valid: false, error: \"State serverId mismatch\" };\n }\n\n if (isExpired(storedState.createdAt)) {\n const deleteKeys = [key];\n if (this._clientId_) {\n deleteKeys.push(this.stateCodeVerifierKey(this.clientId, nonce));\n }\n await this.storage.delete(deleteKeys);\n return { valid: false, error: \"State expired\" };\n }\n\n return { valid: true, serverId };\n }\n\n async consumeState(state: string): Promise<void> {\n const parsed = parseOAuthState(state);\n if (!parsed) {\n // This should never happen since checkState validates format first.\n // Log for debugging but don't throw - state consumption is best-effort.\n console.warn(`[OAuth] consumeState called with invalid state format`);\n return;\n }\n await this.storage.delete(this.stateKey(parsed.nonce));\n }\n\n async redirectToAuthorization(authUrl: URL): Promise<void> {\n this._authUrl_ = authUrl.toString();\n\n const clientId = this._clientId_;\n const serverId = this._serverId_;\n if (!clientId || !serverId) {\n return;\n }\n\n const state = authUrl.searchParams.get(\"state\");\n const codeChallenge = authUrl.searchParams.get(\"code_challenge\");\n if (!state || !codeChallenge) {\n return;\n }\n\n const parsed = parseOAuthState(state);\n if (!parsed || parsed.serverId !== serverId) {\n return;\n }\n\n const challengeKey = this.challengeCodeVerifierKey(clientId, codeChallenge);\n const pendingVerifier =\n await this.storage.get<StoredCodeVerifier>(challengeKey);\n if (!pendingVerifier) {\n return;\n }\n\n if (isExpired(pendingVerifier.createdAt)) {\n await this.storage.delete(challengeKey);\n return;\n }\n\n await this.storage.put(\n this.stateCodeVerifierKey(clientId, parsed.nonce),\n pendingVerifier\n );\n await this.storage.delete(challengeKey);\n }\n\n async invalidateCredentials(\n scope: \"all\" | \"client\" | \"tokens\" | \"verifier\" | \"discovery\"\n ): Promise<void> {\n const deleteKeys: string[] = [];\n\n if (scope === \"all\" || scope === \"discovery\") {\n deleteKeys.push(this.discoveryStateKey());\n }\n\n if (this._clientId_) {\n const clientId = this.clientId;\n if (scope === \"all\" || scope === \"client\") {\n deleteKeys.push(this.clientInfoKey(clientId));\n }\n if (scope === \"all\" || scope === \"tokens\") {\n deleteKeys.push(this.tokenKey(clientId));\n }\n if (scope === \"all\" || scope === \"verifier\") {\n deleteKeys.push(\n ...(await this.codeVerifierKeys(clientId, {\n includeChallengeKeys: true\n }))\n );\n }\n }\n\n if (deleteKeys.length > 0) {\n await this.storage.delete([...new Set(deleteKeys)]);\n }\n }\n\n /**\n * Delete every key this provider stores for its server: tokens and client\n * info for any client ID, verifiers, pending states and discovery state.\n * Used when the server is removed. Other servers' keys are untouched.\n */\n async clearServerStorage(): Promise<void> {\n const keys = [\n ...(\n await this.storage.list({\n prefix: `/${this.clientName}/${this.serverId}/`\n })\n ).keys()\n ];\n // DO storage caps a multi-key delete at 128 keys.\n for (let i = 0; i < keys.length; i += 128) {\n await this.storage.delete(keys.slice(i, i + 128));\n }\n }\n\n codeVerifierKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier`;\n }\n\n stateCodeVerifierPrefix(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier/`;\n }\n\n stateCodeVerifierKey(clientId: string, nonce: string) {\n return `${this.stateCodeVerifierPrefix(clientId)}${nonce}`;\n }\n\n challengeCodeVerifierPrefix(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier_challenge/`;\n }\n\n challengeCodeVerifierKey(clientId: string, codeChallenge: string) {\n return `${this.challengeCodeVerifierPrefix(clientId)}${codeChallenge}`;\n }\n\n async codeVerifierKeys(\n clientId: string,\n options: { includeChallengeKeys?: boolean } = {}\n ): Promise<string[]> {\n const legacyKey = this.codeVerifierKey(clientId);\n const keys: string[] = [];\n\n if (await this.storage.get(legacyKey)) {\n keys.push(legacyKey);\n }\n\n const stateKeys = await this.storage.list({\n prefix: this.stateCodeVerifierPrefix(clientId)\n });\n keys.push(...stateKeys.keys());\n\n if (options.includeChallengeKeys) {\n const challengeKeys = await this.storage.list({\n prefix: this.challengeCodeVerifierPrefix(clientId)\n });\n keys.push(...challengeKeys.keys());\n }\n\n return keys;\n }\n\n async saveCodeVerifier(verifier: string): Promise<void> {\n await this.deleteExpiredChallengeCodeVerifiers(this.clientId);\n\n const codeChallenge = await createCodeChallenge(verifier);\n const storedVerifier: StoredCodeVerifier = {\n verifier,\n createdAt: Date.now()\n };\n\n await this.storage.put(\n this.challengeCodeVerifierKey(this.clientId, codeChallenge),\n storedVerifier\n );\n }\n\n private async deleteExpiredChallengeCodeVerifiers(\n clientId: string\n ): Promise<void> {\n const challengeVerifiers = await this.storage.list<StoredCodeVerifier>({\n prefix: this.challengeCodeVerifierPrefix(clientId)\n });\n const expiredKeys = [...challengeVerifiers.entries()]\n .filter(([, storedVerifier]) => isExpired(storedVerifier.createdAt))\n .map(([key]) => key);\n if (expiredKeys.length > 0) {\n await this.storage.delete(expiredKeys);\n }\n }\n\n async codeVerifier(): Promise<string> {\n const context = codeVerifierStateStorage.getStore();\n if (context) {\n const stateVerifier = await this.codeVerifierForState(context.state);\n if (stateVerifier) {\n context.servedKey = stateVerifier.key;\n return stateVerifier.verifier;\n }\n }\n\n const legacyVerifier = await this.storage.get<string>(\n this.codeVerifierKey(this.clientId)\n );\n if (legacyVerifier) {\n if (context) {\n context.servedKey = this.codeVerifierKey(this.clientId);\n }\n return legacyVerifier;\n }\n\n if (context) {\n throw new Error(\"No code verifier found for OAuth state\");\n }\n\n const pendingVerifiers = await this.storage.list<StoredCodeVerifier>({\n prefix: this.stateCodeVerifierPrefix(this.clientId)\n });\n const unexpiredPendingVerifiers = [...pendingVerifiers.entries()].filter(\n ([, storedVerifier]) => !isExpired(storedVerifier.createdAt)\n );\n const expiredKeys = [...pendingVerifiers.entries()]\n .filter(([, storedVerifier]) => isExpired(storedVerifier.createdAt))\n .map(([key]) => key);\n if (expiredKeys.length > 0) {\n await this.storage.delete(expiredKeys);\n }\n\n if (unexpiredPendingVerifiers.length === 1) {\n const [[, storedVerifier]] = unexpiredPendingVerifiers;\n return storedVerifier.verifier;\n }\n\n if (unexpiredPendingVerifiers.length > 1) {\n throw new Error(\n \"Multiple OAuth code verifiers are pending; complete authorization with the callback state\"\n );\n }\n\n throw new Error(\"No code verifier found\");\n }\n\n private async codeVerifierForState(\n state: string\n ): Promise<{ key: string; verifier: string } | undefined> {\n const parsed = parseOAuthState(state);\n if (!parsed) {\n throw new Error(\"Invalid state format\");\n }\n\n const key = this.stateCodeVerifierKey(this.clientId, parsed.nonce);\n const storedVerifier = await this.storage.get<StoredCodeVerifier>(key);\n if (!storedVerifier) {\n return undefined;\n }\n\n if (isExpired(storedVerifier.createdAt)) {\n await this.storage.delete(key);\n throw new Error(\"Code verifier expired\");\n }\n\n return { key, verifier: storedVerifier.verifier };\n }\n\n async runWithCodeVerifierState<T>(\n state: string,\n callback: () => Promise<T>\n ): Promise<T> {\n return codeVerifierStateStorage.run({ state }, callback);\n }\n\n async deleteCodeVerifier(): Promise<void> {\n const context = codeVerifierStateStorage.getStore();\n if (context?.servedKey) {\n await this.storage.delete(context.servedKey);\n return;\n }\n\n if (context) {\n const parsed = parseOAuthState(context.state);\n if (parsed) {\n await this.storage.delete(\n this.stateCodeVerifierKey(this.clientId, parsed.nonce)\n );\n return;\n }\n }\n\n const keys = await this.codeVerifierKeys(this.clientId);\n if (keys.length > 0) {\n await this.storage.delete(keys);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"do-oauth-client-provider.js","names":[],"sources":["../../../src/mcp/client/do-oauth-client-provider.ts"],"sourcesContent":["import type {\n OAuthClientInformationContext,\n OAuthClientMetadata,\n OAuthClientProvider,\n OAuthDiscoveryState,\n StoredOAuthClientInformation,\n StoredOAuthTokens\n} from \"@modelcontextprotocol/client\";\nimport { validateClientMetadataUrl } from \"@modelcontextprotocol/client\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { nanoid } from \"nanoid\";\n\nconst STATE_EXPIRATION_MS = 10 * 60 * 1000; // 10 minutes\n\nconst codeVerifierStateStorage = new AsyncLocalStorage<{\n state: string;\n servedKey?: string;\n}>();\n\ninterface StoredState {\n nonce: string;\n serverId: string;\n createdAt: number;\n}\n\ninterface StoredCodeVerifier {\n verifier: string;\n createdAt: number;\n}\n\n// A slight extension to the standard OAuthClientProvider interface because `redirectToAuthorization` doesn't give us the interface we need\n// This allows us to track authentication for a specific server and associated dynamic client registration\nexport interface AgentMcpOAuthProvider extends OAuthClientProvider {\n authUrl: string | undefined;\n clientId: string | undefined;\n serverId: string | undefined;\n checkState(\n state: string\n ): Promise<{ valid: boolean; serverId?: string; error?: string }>;\n consumeState(state: string): Promise<void>;\n runWithCodeVerifierState?<T>(\n state: string,\n callback: () => Promise<T>\n ): Promise<T>;\n deleteCodeVerifier(): Promise<void>;\n}\n\nfunction parseOAuthState(\n state: string\n): { nonce: string; serverId: string } | undefined {\n const parts = state.split(\".\");\n if (parts.length !== 2) {\n return undefined;\n }\n\n const [nonce, serverId] = parts;\n if (!nonce || !serverId) {\n return undefined;\n }\n\n return { nonce, serverId };\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nasync function createCodeChallenge(verifier: string): Promise<string> {\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(verifier)\n );\n return base64UrlEncode(new Uint8Array(digest));\n}\n\nfunction isExpired(createdAt: number): boolean {\n return Date.now() - createdAt > STATE_EXPIRATION_MS;\n}\n\n/**\n * @deprecated Use {@link AgentMcpOAuthProvider} instead.\n */\nexport type AgentsOAuthProvider = AgentMcpOAuthProvider;\n\nexport interface DurableObjectOAuthClientProviderOptions {\n /**\n * HTTPS URL of this client's OAuth Client ID Metadata Document.\n *\n * When an authorization server advertises\n * `client_id_metadata_document_supported`, the client uses this URL as its\n * `client_id` instead of dynamic client registration. Other servers still\n * use dynamic client registration. Serve\n * {@link DurableObjectOAuthClientProvider.clientMetadataDocument} at this\n * URL, and use a stable `callbackPath` so the document's `redirect_uris`\n * match every authorization request.\n */\n clientMetadataUrl?: string;\n}\n\nexport class DurableObjectOAuthClientProvider implements AgentMcpOAuthProvider {\n private _authUrl_: string | undefined;\n private _serverId_: string | undefined;\n private _clientId_: string | undefined;\n readonly clientMetadataUrl: string | undefined;\n\n constructor(\n public storage: DurableObjectStorage,\n public clientName: string,\n public baseRedirectUrl: string,\n options: DurableObjectOAuthClientProviderOptions = {}\n ) {\n if (!storage) {\n throw new Error(\n \"DurableObjectOAuthClientProvider requires a valid DurableObjectStorage instance\"\n );\n }\n validateClientMetadataUrl(options.clientMetadataUrl);\n this.clientMetadataUrl = options.clientMetadataUrl || undefined;\n }\n\n /**\n * The Client ID Metadata Document to serve at `clientMetadataUrl`.\n * Throws when the provider has no `clientMetadataUrl`.\n */\n get clientMetadataDocument(): OAuthClientMetadata & { client_id: string } {\n if (!this.clientMetadataUrl) {\n throw new Error(\n \"clientMetadataDocument requires a clientMetadataUrl option\"\n );\n }\n return { client_id: this.clientMetadataUrl, ...this.clientMetadata };\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n client_name: this.clientName,\n client_uri: this.clientUri,\n grant_types: [\"authorization_code\", \"refresh_token\"],\n redirect_uris: [this.redirectUrl],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\"\n };\n }\n\n get clientUri() {\n return new URL(this.redirectUrl).origin;\n }\n\n get redirectUrl() {\n return this.baseRedirectUrl;\n }\n\n get clientId() {\n if (!this._clientId_) {\n throw new Error(\"Trying to access clientId before it was set\");\n }\n return this._clientId_;\n }\n\n set clientId(clientId_: string) {\n this._clientId_ = clientId_;\n }\n\n get serverId() {\n if (!this._serverId_) {\n throw new Error(\"Trying to access serverId before it was set\");\n }\n return this._serverId_;\n }\n\n set serverId(serverId_: string) {\n this._serverId_ = serverId_;\n }\n\n keyPrefix(clientId: string) {\n return `/${this.clientName}/${this.serverId}/${clientId}`;\n }\n\n clientInfoKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/client_info/`;\n }\n\n discoveryStateKey() {\n return `/${this.clientName}/${this.serverId}/oauth_discovery`;\n }\n\n async saveDiscoveryState(state: OAuthDiscoveryState): Promise<void> {\n await this.storage.put(this.discoveryStateKey(), state);\n }\n\n async discoveryState(): Promise<OAuthDiscoveryState | undefined> {\n return (\n (await this.storage.get<OAuthDiscoveryState>(this.discoveryStateKey())) ??\n undefined\n );\n }\n\n async clientInformation(\n _context?: OAuthClientInformationContext\n ): Promise<StoredOAuthClientInformation | undefined> {\n if (!this._clientId_) return undefined;\n return (\n (await this.storage.get<StoredOAuthClientInformation>(\n this.clientInfoKey(this.clientId)\n )) ?? undefined\n );\n }\n\n async saveClientInformation(\n clientInformation: StoredOAuthClientInformation,\n _context?: OAuthClientInformationContext\n ): Promise<void> {\n this.clientId = clientInformation.client_id;\n // Round-trip the SDK's issuer stamp verbatim. The SDK treats a credential\n // stamped for another issuer as absent, so one durable slot per MCP server\n // is both sufficient and safer than maintaining our own issuer index.\n await this.storage.put(\n this.clientInfoKey(clientInformation.client_id),\n clientInformation\n );\n }\n\n tokenKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/token`;\n }\n\n async tokens(\n _context?: OAuthClientInformationContext\n ): Promise<StoredOAuthTokens | undefined> {\n if (!this._clientId_) return undefined;\n return (\n (await this.storage.get<StoredOAuthTokens>(\n this.tokenKey(this.clientId)\n )) ?? undefined\n );\n }\n\n async saveTokens(\n tokens: StoredOAuthTokens,\n _context?: OAuthClientInformationContext\n ): Promise<void> {\n // Keep the SDK-owned issuer stamp intact for SEP-2352 validation. Discovery\n // is needed across the browser redirect, but once token issuance succeeds\n // it must not pin later re-authorization to this AS: a subsequent 401 must\n // re-read PRM so an authorization-server migration can be observed.\n await this.storage.put(this.tokenKey(this.clientId), tokens);\n await this.storage.delete(this.discoveryStateKey());\n }\n\n get authUrl() {\n return this._authUrl_;\n }\n\n stateKey(nonce: string) {\n return `/${this.clientName}/${this.serverId}/state/${nonce}`;\n }\n\n async state(): Promise<string> {\n const nonce = nanoid();\n const state = `${nonce}.${this.serverId}`;\n const storedState: StoredState = {\n nonce,\n serverId: this.serverId,\n createdAt: Date.now()\n };\n await this.storage.put(this.stateKey(nonce), storedState);\n return state;\n }\n\n async checkState(\n state: string\n ): Promise<{ valid: boolean; serverId?: string; error?: string }> {\n const parsed = parseOAuthState(state);\n if (!parsed) {\n return { valid: false, error: \"Invalid state format\" };\n }\n\n const { nonce, serverId } = parsed;\n const key = this.stateKey(nonce);\n const storedState = await this.storage.get<StoredState>(key);\n\n if (!storedState) {\n return { valid: false, error: \"State not found or already used\" };\n }\n\n if (storedState.serverId !== serverId) {\n await this.storage.delete(key);\n return { valid: false, error: \"State serverId mismatch\" };\n }\n\n if (isExpired(storedState.createdAt)) {\n const deleteKeys = [key];\n if (this._clientId_) {\n deleteKeys.push(this.stateCodeVerifierKey(this.clientId, nonce));\n }\n await this.storage.delete(deleteKeys);\n return { valid: false, error: \"State expired\" };\n }\n\n return { valid: true, serverId };\n }\n\n async consumeState(state: string): Promise<void> {\n const parsed = parseOAuthState(state);\n if (!parsed) {\n // This should never happen since checkState validates format first.\n // Log for debugging but don't throw - state consumption is best-effort.\n console.warn(`[OAuth] consumeState called with invalid state format`);\n return;\n }\n await this.storage.delete(this.stateKey(parsed.nonce));\n }\n\n async redirectToAuthorization(authUrl: URL): Promise<void> {\n this._authUrl_ = authUrl.toString();\n\n const clientId = this._clientId_;\n const serverId = this._serverId_;\n if (!clientId || !serverId) {\n return;\n }\n\n const state = authUrl.searchParams.get(\"state\");\n const codeChallenge = authUrl.searchParams.get(\"code_challenge\");\n if (!state || !codeChallenge) {\n return;\n }\n\n const parsed = parseOAuthState(state);\n if (!parsed || parsed.serverId !== serverId) {\n return;\n }\n\n const challengeKey = this.challengeCodeVerifierKey(clientId, codeChallenge);\n const pendingVerifier =\n await this.storage.get<StoredCodeVerifier>(challengeKey);\n if (!pendingVerifier) {\n return;\n }\n\n if (isExpired(pendingVerifier.createdAt)) {\n await this.storage.delete(challengeKey);\n return;\n }\n\n await this.storage.put(\n this.stateCodeVerifierKey(clientId, parsed.nonce),\n pendingVerifier\n );\n await this.storage.delete(challengeKey);\n }\n\n async invalidateCredentials(\n scope: \"all\" | \"client\" | \"tokens\" | \"verifier\" | \"discovery\"\n ): Promise<void> {\n const deleteKeys: string[] = [];\n\n if (scope === \"all\" || scope === \"discovery\") {\n deleteKeys.push(this.discoveryStateKey());\n }\n\n if (this._clientId_) {\n const clientId = this.clientId;\n if (scope === \"all\" || scope === \"client\") {\n deleteKeys.push(this.clientInfoKey(clientId));\n }\n if (scope === \"all\" || scope === \"tokens\") {\n deleteKeys.push(this.tokenKey(clientId));\n }\n if (scope === \"all\" || scope === \"verifier\") {\n deleteKeys.push(\n ...(await this.codeVerifierKeys(clientId, {\n includeChallengeKeys: true\n }))\n );\n }\n }\n\n if (deleteKeys.length > 0) {\n await this.storage.delete([...new Set(deleteKeys)]);\n }\n }\n\n /**\n * Delete every key this provider stores for its server: tokens and client\n * info for any client ID, verifiers, pending states and discovery state.\n * Used when the server is removed. Other servers' keys are untouched.\n */\n async clearServerStorage(): Promise<void> {\n const keys = [\n ...(\n await this.storage.list({\n prefix: `/${this.clientName}/${this.serverId}/`\n })\n ).keys()\n ];\n // DO storage caps a multi-key delete at 128 keys.\n for (let i = 0; i < keys.length; i += 128) {\n await this.storage.delete(keys.slice(i, i + 128));\n }\n }\n\n codeVerifierKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier`;\n }\n\n stateCodeVerifierPrefix(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier/`;\n }\n\n stateCodeVerifierKey(clientId: string, nonce: string) {\n return `${this.stateCodeVerifierPrefix(clientId)}${nonce}`;\n }\n\n challengeCodeVerifierPrefix(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier_challenge/`;\n }\n\n challengeCodeVerifierKey(clientId: string, codeChallenge: string) {\n return `${this.challengeCodeVerifierPrefix(clientId)}${codeChallenge}`;\n }\n\n async codeVerifierKeys(\n clientId: string,\n options: { includeChallengeKeys?: boolean } = {}\n ): Promise<string[]> {\n const legacyKey = this.codeVerifierKey(clientId);\n const keys: string[] = [];\n\n if (await this.storage.get(legacyKey)) {\n keys.push(legacyKey);\n }\n\n const stateKeys = await this.storage.list({\n prefix: this.stateCodeVerifierPrefix(clientId)\n });\n keys.push(...stateKeys.keys());\n\n if (options.includeChallengeKeys) {\n const challengeKeys = await this.storage.list({\n prefix: this.challengeCodeVerifierPrefix(clientId)\n });\n keys.push(...challengeKeys.keys());\n }\n\n return keys;\n }\n\n async saveCodeVerifier(verifier: string): Promise<void> {\n await this.deleteExpiredChallengeCodeVerifiers(this.clientId);\n\n const codeChallenge = await createCodeChallenge(verifier);\n const storedVerifier: StoredCodeVerifier = {\n verifier,\n createdAt: Date.now()\n };\n\n await this.storage.put(\n this.challengeCodeVerifierKey(this.clientId, codeChallenge),\n storedVerifier\n );\n }\n\n private async deleteExpiredChallengeCodeVerifiers(\n clientId: string\n ): Promise<void> {\n const challengeVerifiers = await this.storage.list<StoredCodeVerifier>({\n prefix: this.challengeCodeVerifierPrefix(clientId)\n });\n const expiredKeys = [...challengeVerifiers.entries()]\n .filter(([, storedVerifier]) => isExpired(storedVerifier.createdAt))\n .map(([key]) => key);\n if (expiredKeys.length > 0) {\n await this.storage.delete(expiredKeys);\n }\n }\n\n async codeVerifier(): Promise<string> {\n const context = codeVerifierStateStorage.getStore();\n if (context) {\n const stateVerifier = await this.codeVerifierForState(context.state);\n if (stateVerifier) {\n context.servedKey = stateVerifier.key;\n return stateVerifier.verifier;\n }\n }\n\n const legacyVerifier = await this.storage.get<string>(\n this.codeVerifierKey(this.clientId)\n );\n if (legacyVerifier) {\n if (context) {\n context.servedKey = this.codeVerifierKey(this.clientId);\n }\n return legacyVerifier;\n }\n\n if (context) {\n throw new Error(\"No code verifier found for OAuth state\");\n }\n\n const pendingVerifiers = await this.storage.list<StoredCodeVerifier>({\n prefix: this.stateCodeVerifierPrefix(this.clientId)\n });\n const unexpiredPendingVerifiers = [...pendingVerifiers.entries()].filter(\n ([, storedVerifier]) => !isExpired(storedVerifier.createdAt)\n );\n const expiredKeys = [...pendingVerifiers.entries()]\n .filter(([, storedVerifier]) => isExpired(storedVerifier.createdAt))\n .map(([key]) => key);\n if (expiredKeys.length > 0) {\n await this.storage.delete(expiredKeys);\n }\n\n if (unexpiredPendingVerifiers.length === 1) {\n const [[, storedVerifier]] = unexpiredPendingVerifiers;\n return storedVerifier.verifier;\n }\n\n if (unexpiredPendingVerifiers.length > 1) {\n throw new Error(\n \"Multiple OAuth code verifiers are pending; complete authorization with the callback state\"\n );\n }\n\n throw new Error(\"No code verifier found\");\n }\n\n private async codeVerifierForState(\n state: string\n ): Promise<{ key: string; verifier: string } | undefined> {\n const parsed = parseOAuthState(state);\n if (!parsed) {\n throw new Error(\"Invalid state format\");\n }\n\n const key = this.stateCodeVerifierKey(this.clientId, parsed.nonce);\n const storedVerifier = await this.storage.get<StoredCodeVerifier>(key);\n if (!storedVerifier) {\n return undefined;\n }\n\n if (isExpired(storedVerifier.createdAt)) {\n await this.storage.delete(key);\n throw new Error(\"Code verifier expired\");\n }\n\n return { key, verifier: storedVerifier.verifier };\n }\n\n async runWithCodeVerifierState<T>(\n state: string,\n callback: () => Promise<T>\n ): Promise<T> {\n return codeVerifierStateStorage.run({ state }, callback);\n }\n\n async deleteCodeVerifier(): Promise<void> {\n const context = codeVerifierStateStorage.getStore();\n if (context?.servedKey) {\n await this.storage.delete(context.servedKey);\n return;\n }\n\n if (context) {\n const parsed = parseOAuthState(context.state);\n if (parsed) {\n await this.storage.delete(\n this.stateCodeVerifierKey(this.clientId, parsed.nonce)\n );\n return;\n }\n }\n\n const keys = await this.codeVerifierKeys(this.clientId);\n if (keys.length > 0) {\n await this.storage.delete(keys);\n }\n }\n}\n"],"mappings":";;;;AAYA,MAAM,sBAAsB,MAAU;AAEtC,MAAM,2BAA2B,IAAI,kBAGlC;AA8BH,SAAS,gBACP,OACiD;CACjD,MAAM,QAAQ,MAAM,MAAM,GAAG;CAC7B,IAAI,MAAM,WAAW,GACnB;CAGF,MAAM,CAAC,OAAO,YAAY;CAC1B,IAAI,CAAC,SAAS,CAAC,UACb;CAGF,OAAO;EAAE;EAAO;CAAS;AAC3B;AAEA,SAAS,gBAAgB,OAA2B;CAClD,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,OACjB,UAAU,OAAO,aAAa,IAAI;CAEpC,OAAO,KAAK,MAAM,CAAC,CAChB,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,OAAO,EAAE;AACtB;AAEA,eAAe,oBAAoB,UAAmC;CACpE,MAAM,SAAS,MAAM,OAAO,OAAO,OACjC,WACA,IAAI,YAAY,CAAC,CAAC,OAAO,QAAQ,CACnC;CACA,OAAO,gBAAgB,IAAI,WAAW,MAAM,CAAC;AAC/C;AAEA,SAAS,UAAU,WAA4B;CAC7C,OAAO,KAAK,IAAI,IAAI,YAAY;AAClC;AAsBA,IAAa,mCAAb,MAA+E;CAM7E,YACE,SACA,YACA,iBACA,UAAmD,CAAC,GACpD;EAJO,KAAA,UAAA;EACA,KAAA,aAAA;EACA,KAAA,kBAAA;EAGP,IAAI,CAAC,SACH,MAAM,IAAI,MACR,iFACF;EAEF,0BAA0B,QAAQ,iBAAiB;EACnD,KAAK,oBAAoB,QAAQ,qBAAqB,KAAA;CACxD;;;;;CAMA,IAAI,yBAAsE;EACxE,IAAI,CAAC,KAAK,mBACR,MAAM,IAAI,MACR,4DACF;EAEF,OAAO;GAAE,WAAW,KAAK;GAAmB,GAAG,KAAK;EAAe;CACrE;CAEA,IAAI,iBAAsC;EACxC,OAAO;GACL,aAAa,KAAK;GAClB,YAAY,KAAK;GACjB,aAAa,CAAC,sBAAsB,eAAe;GACnD,eAAe,CAAC,KAAK,WAAW;GAChC,gBAAgB,CAAC,MAAM;GACvB,4BAA4B;EAC9B;CACF;CAEA,IAAI,YAAY;EACd,OAAO,IAAI,IAAI,KAAK,WAAW,CAAC,CAAC;CACnC;CAEA,IAAI,cAAc;EAChB,OAAO,KAAK;CACd;CAEA,IAAI,WAAW;EACb,IAAI,CAAC,KAAK,YACR,MAAM,IAAI,MAAM,6CAA6C;EAE/D,OAAO,KAAK;CACd;CAEA,IAAI,SAAS,WAAmB;EAC9B,KAAK,aAAa;CACpB;CAEA,IAAI,WAAW;EACb,IAAI,CAAC,KAAK,YACR,MAAM,IAAI,MAAM,6CAA6C;EAE/D,OAAO,KAAK;CACd;CAEA,IAAI,SAAS,WAAmB;EAC9B,KAAK,aAAa;CACpB;CAEA,UAAU,UAAkB;EAC1B,OAAO,IAAI,KAAK,WAAW,GAAG,KAAK,SAAS,GAAG;CACjD;CAEA,cAAc,UAAkB;EAC9B,OAAO,GAAG,KAAK,UAAU,QAAQ,EAAE;CACrC;CAEA,oBAAoB;EAClB,OAAO,IAAI,KAAK,WAAW,GAAG,KAAK,SAAS;CAC9C;CAEA,MAAM,mBAAmB,OAA2C;EAClE,MAAM,KAAK,QAAQ,IAAI,KAAK,kBAAkB,GAAG,KAAK;CACxD;CAEA,MAAM,iBAA2D;EAC/D,OACG,MAAM,KAAK,QAAQ,IAAyB,KAAK,kBAAkB,CAAC,KACrE,KAAA;CAEJ;CAEA,MAAM,kBACJ,UACmD;EACnD,IAAI,CAAC,KAAK,YAAY,OAAO,KAAA;EAC7B,OACG,MAAM,KAAK,QAAQ,IAClB,KAAK,cAAc,KAAK,QAAQ,CAClC,KAAM,KAAA;CAEV;CAEA,MAAM,sBACJ,mBACA,UACe;EACf,KAAK,WAAW,kBAAkB;EAIlC,MAAM,KAAK,QAAQ,IACjB,KAAK,cAAc,kBAAkB,SAAS,GAC9C,iBACF;CACF;CAEA,SAAS,UAAkB;EACzB,OAAO,GAAG,KAAK,UAAU,QAAQ,EAAE;CACrC;CAEA,MAAM,OACJ,UACwC;EACxC,IAAI,CAAC,KAAK,YAAY,OAAO,KAAA;EAC7B,OACG,MAAM,KAAK,QAAQ,IAClB,KAAK,SAAS,KAAK,QAAQ,CAC7B,KAAM,KAAA;CAEV;CAEA,MAAM,WACJ,QACA,UACe;EAKf,MAAM,KAAK,QAAQ,IAAI,KAAK,SAAS,KAAK,QAAQ,GAAG,MAAM;EAC3D,MAAM,KAAK,QAAQ,OAAO,KAAK,kBAAkB,CAAC;CACpD;CAEA,IAAI,UAAU;EACZ,OAAO,KAAK;CACd;CAEA,SAAS,OAAe;EACtB,OAAO,IAAI,KAAK,WAAW,GAAG,KAAK,SAAS,SAAS;CACvD;CAEA,MAAM,QAAyB;EAC7B,MAAM,QAAQ,OAAO;EACrB,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAK;EAC/B,MAAM,cAA2B;GAC/B;GACA,UAAU,KAAK;GACf,WAAW,KAAK,IAAI;EACtB;EACA,MAAM,KAAK,QAAQ,IAAI,KAAK,SAAS,KAAK,GAAG,WAAW;EACxD,OAAO;CACT;CAEA,MAAM,WACJ,OACgE;EAChE,MAAM,SAAS,gBAAgB,KAAK;EACpC,IAAI,CAAC,QACH,OAAO;GAAE,OAAO;GAAO,OAAO;EAAuB;EAGvD,MAAM,EAAE,OAAO,aAAa;EAC5B,MAAM,MAAM,KAAK,SAAS,KAAK;EAC/B,MAAM,cAAc,MAAM,KAAK,QAAQ,IAAiB,GAAG;EAE3D,IAAI,CAAC,aACH,OAAO;GAAE,OAAO;GAAO,OAAO;EAAkC;EAGlE,IAAI,YAAY,aAAa,UAAU;GACrC,MAAM,KAAK,QAAQ,OAAO,GAAG;GAC7B,OAAO;IAAE,OAAO;IAAO,OAAO;GAA0B;EAC1D;EAEA,IAAI,UAAU,YAAY,SAAS,GAAG;GACpC,MAAM,aAAa,CAAC,GAAG;GACvB,IAAI,KAAK,YACP,WAAW,KAAK,KAAK,qBAAqB,KAAK,UAAU,KAAK,CAAC;GAEjE,MAAM,KAAK,QAAQ,OAAO,UAAU;GACpC,OAAO;IAAE,OAAO;IAAO,OAAO;GAAgB;EAChD;EAEA,OAAO;GAAE,OAAO;GAAM;EAAS;CACjC;CAEA,MAAM,aAAa,OAA8B;EAC/C,MAAM,SAAS,gBAAgB,KAAK;EACpC,IAAI,CAAC,QAAQ;GAGX,QAAQ,KAAK,uDAAuD;GACpE;EACF;EACA,MAAM,KAAK,QAAQ,OAAO,KAAK,SAAS,OAAO,KAAK,CAAC;CACvD;CAEA,MAAM,wBAAwB,SAA6B;EACzD,KAAK,YAAY,QAAQ,SAAS;EAElC,MAAM,WAAW,KAAK;EACtB,MAAM,WAAW,KAAK;EACtB,IAAI,CAAC,YAAY,CAAC,UAChB;EAGF,MAAM,QAAQ,QAAQ,aAAa,IAAI,OAAO;EAC9C,MAAM,gBAAgB,QAAQ,aAAa,IAAI,gBAAgB;EAC/D,IAAI,CAAC,SAAS,CAAC,eACb;EAGF,MAAM,SAAS,gBAAgB,KAAK;EACpC,IAAI,CAAC,UAAU,OAAO,aAAa,UACjC;EAGF,MAAM,eAAe,KAAK,yBAAyB,UAAU,aAAa;EAC1E,MAAM,kBACJ,MAAM,KAAK,QAAQ,IAAwB,YAAY;EACzD,IAAI,CAAC,iBACH;EAGF,IAAI,UAAU,gBAAgB,SAAS,GAAG;GACxC,MAAM,KAAK,QAAQ,OAAO,YAAY;GACtC;EACF;EAEA,MAAM,KAAK,QAAQ,IACjB,KAAK,qBAAqB,UAAU,OAAO,KAAK,GAChD,eACF;EACA,MAAM,KAAK,QAAQ,OAAO,YAAY;CACxC;CAEA,MAAM,sBACJ,OACe;EACf,MAAM,aAAuB,CAAC;EAE9B,IAAI,UAAU,SAAS,UAAU,aAC/B,WAAW,KAAK,KAAK,kBAAkB,CAAC;EAG1C,IAAI,KAAK,YAAY;GACnB,MAAM,WAAW,KAAK;GACtB,IAAI,UAAU,SAAS,UAAU,UAC/B,WAAW,KAAK,KAAK,cAAc,QAAQ,CAAC;GAE9C,IAAI,UAAU,SAAS,UAAU,UAC/B,WAAW,KAAK,KAAK,SAAS,QAAQ,CAAC;GAEzC,IAAI,UAAU,SAAS,UAAU,YAC/B,WAAW,KACT,GAAI,MAAM,KAAK,iBAAiB,UAAU,EACxC,sBAAsB,KACxB,CAAC,CACH;EAEJ;EAEA,IAAI,WAAW,SAAS,GACtB,MAAM,KAAK,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC,CAAC;CAEtD;;;;;;CAOA,MAAM,qBAAoC;EACxC,MAAM,OAAO,CACX,IACE,MAAM,KAAK,QAAQ,KAAK,EACtB,QAAQ,IAAI,KAAK,WAAW,GAAG,KAAK,SAAS,GAC/C,CAAC,EAAA,CACD,KAAK,CACT;EAEA,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,KACpC,MAAM,KAAK,QAAQ,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC;CAEpD;CAEA,gBAAgB,UAAkB;EAChC,OAAO,GAAG,KAAK,UAAU,QAAQ,EAAE;CACrC;CAEA,wBAAwB,UAAkB;EACxC,OAAO,GAAG,KAAK,UAAU,QAAQ,EAAE;CACrC;CAEA,qBAAqB,UAAkB,OAAe;EACpD,OAAO,GAAG,KAAK,wBAAwB,QAAQ,IAAI;CACrD;CAEA,4BAA4B,UAAkB;EAC5C,OAAO,GAAG,KAAK,UAAU,QAAQ,EAAE;CACrC;CAEA,yBAAyB,UAAkB,eAAuB;EAChE,OAAO,GAAG,KAAK,4BAA4B,QAAQ,IAAI;CACzD;CAEA,MAAM,iBACJ,UACA,UAA8C,CAAC,GAC5B;EACnB,MAAM,YAAY,KAAK,gBAAgB,QAAQ;EAC/C,MAAM,OAAiB,CAAC;EAExB,IAAI,MAAM,KAAK,QAAQ,IAAI,SAAS,GAClC,KAAK,KAAK,SAAS;EAGrB,MAAM,YAAY,MAAM,KAAK,QAAQ,KAAK,EACxC,QAAQ,KAAK,wBAAwB,QAAQ,EAC/C,CAAC;EACD,KAAK,KAAK,GAAG,UAAU,KAAK,CAAC;EAE7B,IAAI,QAAQ,sBAAsB;GAChC,MAAM,gBAAgB,MAAM,KAAK,QAAQ,KAAK,EAC5C,QAAQ,KAAK,4BAA4B,QAAQ,EACnD,CAAC;GACD,KAAK,KAAK,GAAG,cAAc,KAAK,CAAC;EACnC;EAEA,OAAO;CACT;CAEA,MAAM,iBAAiB,UAAiC;EACtD,MAAM,KAAK,oCAAoC,KAAK,QAAQ;EAE5D,MAAM,gBAAgB,MAAM,oBAAoB,QAAQ;EACxD,MAAM,iBAAqC;GACzC;GACA,WAAW,KAAK,IAAI;EACtB;EAEA,MAAM,KAAK,QAAQ,IACjB,KAAK,yBAAyB,KAAK,UAAU,aAAa,GAC1D,cACF;CACF;CAEA,MAAc,oCACZ,UACe;EAIf,MAAM,cAAc,CAAC,IAAG,MAHS,KAAK,QAAQ,KAAyB,EACrE,QAAQ,KAAK,4BAA4B,QAAQ,EACnD,CAAC,EAAA,CAC0C,QAAQ,CAAC,CAAC,CAClD,QAAQ,GAAG,oBAAoB,UAAU,eAAe,SAAS,CAAC,CAAC,CACnE,KAAK,CAAC,SAAS,GAAG;EACrB,IAAI,YAAY,SAAS,GACvB,MAAM,KAAK,QAAQ,OAAO,WAAW;CAEzC;CAEA,MAAM,eAAgC;EACpC,MAAM,UAAU,yBAAyB,SAAS;EAClD,IAAI,SAAS;GACX,MAAM,gBAAgB,MAAM,KAAK,qBAAqB,QAAQ,KAAK;GACnE,IAAI,eAAe;IACjB,QAAQ,YAAY,cAAc;IAClC,OAAO,cAAc;GACvB;EACF;EAEA,MAAM,iBAAiB,MAAM,KAAK,QAAQ,IACxC,KAAK,gBAAgB,KAAK,QAAQ,CACpC;EACA,IAAI,gBAAgB;GAClB,IAAI,SACF,QAAQ,YAAY,KAAK,gBAAgB,KAAK,QAAQ;GAExD,OAAO;EACT;EAEA,IAAI,SACF,MAAM,IAAI,MAAM,wCAAwC;EAG1D,MAAM,mBAAmB,MAAM,KAAK,QAAQ,KAAyB,EACnE,QAAQ,KAAK,wBAAwB,KAAK,QAAQ,EACpD,CAAC;EACD,MAAM,4BAA4B,CAAC,GAAG,iBAAiB,QAAQ,CAAC,CAAC,CAAC,QAC/D,GAAG,oBAAoB,CAAC,UAAU,eAAe,SAAS,CAC7D;EACA,MAAM,cAAc,CAAC,GAAG,iBAAiB,QAAQ,CAAC,CAAC,CAChD,QAAQ,GAAG,oBAAoB,UAAU,eAAe,SAAS,CAAC,CAAC,CACnE,KAAK,CAAC,SAAS,GAAG;EACrB,IAAI,YAAY,SAAS,GACvB,MAAM,KAAK,QAAQ,OAAO,WAAW;EAGvC,IAAI,0BAA0B,WAAW,GAAG;GAC1C,MAAM,CAAC,GAAG,mBAAmB;GAC7B,OAAO,eAAe;EACxB;EAEA,IAAI,0BAA0B,SAAS,GACrC,MAAM,IAAI,MACR,2FACF;EAGF,MAAM,IAAI,MAAM,wBAAwB;CAC1C;CAEA,MAAc,qBACZ,OACwD;EACxD,MAAM,SAAS,gBAAgB,KAAK;EACpC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,sBAAsB;EAGxC,MAAM,MAAM,KAAK,qBAAqB,KAAK,UAAU,OAAO,KAAK;EACjE,MAAM,iBAAiB,MAAM,KAAK,QAAQ,IAAwB,GAAG;EACrE,IAAI,CAAC,gBACH;EAGF,IAAI,UAAU,eAAe,SAAS,GAAG;GACvC,MAAM,KAAK,QAAQ,OAAO,GAAG;GAC7B,MAAM,IAAI,MAAM,uBAAuB;EACzC;EAEA,OAAO;GAAE;GAAK,UAAU,eAAe;EAAS;CAClD;CAEA,MAAM,yBACJ,OACA,UACY;EACZ,OAAO,yBAAyB,IAAI,EAAE,MAAM,GAAG,QAAQ;CACzD;CAEA,MAAM,qBAAoC;EACxC,MAAM,UAAU,yBAAyB,SAAS;EAClD,IAAI,SAAS,WAAW;GACtB,MAAM,KAAK,QAAQ,OAAO,QAAQ,SAAS;GAC3C;EACF;EAEA,IAAI,SAAS;GACX,MAAM,SAAS,gBAAgB,QAAQ,KAAK;GAC5C,IAAI,QAAQ;IACV,MAAM,KAAK,QAAQ,OACjB,KAAK,qBAAqB,KAAK,UAAU,OAAO,KAAK,CACvD;IACA;GACF;EACF;EAEA,MAAM,OAAO,MAAM,KAAK,iBAAiB,KAAK,QAAQ;EACtD,IAAI,KAAK,SAAS,GAChB,MAAM,KAAK,QAAQ,OAAO,IAAI;CAElC;AACF"}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
jt as ElicitResult,
|
|
25
25
|
qt as getNamespacedData,
|
|
26
26
|
zt as MCPClientOAuthResult
|
|
27
|
-
} from "../../agent-routing-
|
|
27
|
+
} from "../../agent-routing-vVMA7m8Y.js";
|
|
28
28
|
import { i as McpClientOptions } from "../../types-D2naO3rA.js";
|
|
29
29
|
export {
|
|
30
30
|
type ElicitRequest,
|
package/dist/mcp/index.d.ts
CHANGED
package/dist/mcp/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getAgentByName } from "../agent-routing.js";
|
|
2
2
|
import "../types.js";
|
|
3
|
-
import { i as getCurrentAgent, t as Agent } from "../src-
|
|
3
|
+
import { i as getCurrentAgent, t as Agent } from "../src-DoGNJ4Ud.js";
|
|
4
4
|
import { c as RPCClientTransport, i as normalizeServerId, l as RPC_DO_PREFIX, n as MCP_SERVER_ID_MAX_LENGTH, u as isDurableObjectNamespace } from "../client-DMWujQJ1.js";
|
|
5
5
|
import { n as getMcpAuthContext, r as runWithAuthContext, t as createStatelessMcpHandler } from "../handler-stateless-B5hU3dxK.js";
|
|
6
6
|
import { SSEClientTransport, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../../classPrivateFieldGet2-DZBYAB34.js";
|
|
2
|
+
import { t as _classPrivateMethodInitSpec } from "../../classPrivateMethodInitSpec-qMjJ6sHQ.js";
|
|
1
3
|
import { C as isCatalogModelId, T as isRunPathLanguageModelId, _ as isGatewayErrorEnvelope, a as normalizeChatCompletion, c as gatewaySlugForBaseUrl, d as resolveGatewayProvider, f as createTransport, g as headersToObject, h as errorFromResponse, i as normalizeChatCompletionsStream, l as isGatewayShapedUrl, m as errorFromGatewayEnvelope, n as imageMediaTypeOf, o as prepareChatCompletionsRequest, r as sseDataStream, s as GATEWAY_PROVIDER_NAMES, t as buildImageInput, v as unwrapEnvelope, x as isAbortError, y as CloudflareAIError } from "../../images-CfuRCjwq.js";
|
|
2
4
|
import { i as mergeModelOptions, o as resolveOptions, r as gatewayLayerOf } from "../../settings-Dk2il2Hf.js";
|
|
3
5
|
import { calculateCost, clampThinkingLevel, createAssistantMessageEventStream, createProvider, getCurrentTools, normalizeContext, parseStreamingJson } from "@earendil-works/pi-ai";
|
|
@@ -666,6 +668,124 @@ async function assertOk(response, context) {
|
|
|
666
668
|
throw await errorFromResponse(response, context);
|
|
667
669
|
}
|
|
668
670
|
//#endregion
|
|
671
|
+
//#region src/models/pi-ai/wires/partial-arguments.ts
|
|
672
|
+
const VALID_ESCAPES = /* @__PURE__ */ new Set([
|
|
673
|
+
"\"",
|
|
674
|
+
"\\",
|
|
675
|
+
"/",
|
|
676
|
+
"b",
|
|
677
|
+
"f",
|
|
678
|
+
"n",
|
|
679
|
+
"r",
|
|
680
|
+
"t",
|
|
681
|
+
"u"
|
|
682
|
+
]);
|
|
683
|
+
const HEX = /^[0-9a-fA-F]$/;
|
|
684
|
+
var _text = /* @__PURE__ */ new WeakMap();
|
|
685
|
+
var _snapshot = /* @__PURE__ */ new WeakMap();
|
|
686
|
+
var _needsRepair = /* @__PURE__ */ new WeakMap();
|
|
687
|
+
var _containers = /* @__PURE__ */ new WeakMap();
|
|
688
|
+
var _inString = /* @__PURE__ */ new WeakMap();
|
|
689
|
+
var _escape = /* @__PURE__ */ new WeakMap();
|
|
690
|
+
var _PartialArguments_brand = /* @__PURE__ */ new WeakSet();
|
|
691
|
+
/**
|
|
692
|
+
* A streamed tool call's arguments, parsed as their text arrives.
|
|
693
|
+
*
|
|
694
|
+
* pi-ai's `parseStreamingJson` re-parses the whole text on every delta: a
|
|
695
|
+
* `JSON.parse` that throws, a character-by-character repair, a second throwing
|
|
696
|
+
* `JSON.parse`, then a partial parse. Over a long argument, such as a file
|
|
697
|
+
* passed to a write tool, that is quadratic in time and garbage.
|
|
698
|
+
*
|
|
699
|
+
* This keeps the lexer state (open containers, whether the text ends inside a
|
|
700
|
+
* string or an escape) across deltas, so each delta scans only its own
|
|
701
|
+
* characters. A snapshot closes the open string and containers and hands the
|
|
702
|
+
* result to the native `JSON.parse`, which still reads the whole text but
|
|
703
|
+
* throws nothing and builds no intermediate strings in JavaScript. When the text ends mid-token (a key, a
|
|
704
|
+
* number, `tru`) the closed text does not parse, and the previous snapshot
|
|
705
|
+
* stands until the next delta. Unlike `parseStreamingJson`, a partial string
|
|
706
|
+
* keeps its trailing whitespace. Text that needs pi-ai's repairs (raw control
|
|
707
|
+
* characters or invalid escapes inside a string) goes back to
|
|
708
|
+
* `parseStreamingJson` for the rest of the call.
|
|
709
|
+
*/
|
|
710
|
+
var PartialArguments = class {
|
|
711
|
+
constructor() {
|
|
712
|
+
_classPrivateMethodInitSpec(this, _PartialArguments_brand);
|
|
713
|
+
_classPrivateFieldInitSpec(this, _text, "");
|
|
714
|
+
_classPrivateFieldInitSpec(this, _snapshot, {});
|
|
715
|
+
_classPrivateFieldInitSpec(this, _needsRepair, false);
|
|
716
|
+
_classPrivateFieldInitSpec(this, _containers, []);
|
|
717
|
+
_classPrivateFieldInitSpec(this, _inString, false);
|
|
718
|
+
_classPrivateFieldInitSpec(this, _escape, void 0);
|
|
719
|
+
}
|
|
720
|
+
get text() {
|
|
721
|
+
return _classPrivateFieldGet2(_text, this);
|
|
722
|
+
}
|
|
723
|
+
/** Append `delta` and return the arguments parsed so far. */
|
|
724
|
+
push(delta) {
|
|
725
|
+
_classPrivateFieldSet2(_text, this, _classPrivateFieldGet2(_text, this) + delta);
|
|
726
|
+
if (!_classPrivateFieldGet2(_needsRepair, this)) _assertClassBrand(_PartialArguments_brand, this, _scan).call(this, delta);
|
|
727
|
+
if (_classPrivateFieldGet2(_needsRepair, this)) {
|
|
728
|
+
_classPrivateFieldSet2(_snapshot, this, parseStreamingJson(_classPrivateFieldGet2(_text, this)));
|
|
729
|
+
return _classPrivateFieldGet2(_snapshot, this);
|
|
730
|
+
}
|
|
731
|
+
const parsed = _assertClassBrand(_PartialArguments_brand, this, _parseClosed).call(this);
|
|
732
|
+
if (parsed !== void 0) _classPrivateFieldSet2(_snapshot, this, parsed);
|
|
733
|
+
return _classPrivateFieldGet2(_snapshot, this);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
function _scan(delta) {
|
|
737
|
+
for (const char of delta) {
|
|
738
|
+
if (_classPrivateFieldGet2(_escape, this) !== void 0) {
|
|
739
|
+
_classPrivateFieldSet2(_escape, this, _classPrivateFieldGet2(_escape, this) + char);
|
|
740
|
+
if (_classPrivateFieldGet2(_escape, this).length === 1) {
|
|
741
|
+
if (!VALID_ESCAPES.has(char)) {
|
|
742
|
+
_classPrivateFieldSet2(_needsRepair, this, true);
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (char !== "u") _classPrivateFieldSet2(_escape, this, void 0);
|
|
746
|
+
} else {
|
|
747
|
+
if (!HEX.test(char)) {
|
|
748
|
+
_classPrivateFieldSet2(_needsRepair, this, true);
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (_classPrivateFieldGet2(_escape, this).length === 5) _classPrivateFieldSet2(_escape, this, void 0);
|
|
752
|
+
}
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
if (_classPrivateFieldGet2(_inString, this)) {
|
|
756
|
+
if (char === "\"") _classPrivateFieldSet2(_inString, this, false);
|
|
757
|
+
else if (char === "\\") _classPrivateFieldSet2(_escape, this, "");
|
|
758
|
+
else if (char < " ") {
|
|
759
|
+
_classPrivateFieldSet2(_needsRepair, this, true);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
if (char === "\"") _classPrivateFieldSet2(_inString, this, true);
|
|
765
|
+
else if (char === "{") _classPrivateFieldGet2(_containers, this).push("}");
|
|
766
|
+
else if (char === "[") _classPrivateFieldGet2(_containers, this).push("]");
|
|
767
|
+
else if (char === "}" || char === "]") _classPrivateFieldGet2(_containers, this).pop();
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function _parseClosed() {
|
|
771
|
+
let text = _classPrivateFieldGet2(_text, this);
|
|
772
|
+
if (_classPrivateFieldGet2(_inString, this)) {
|
|
773
|
+
if (_classPrivateFieldGet2(_escape, this) !== void 0) text = text.slice(0, text.length - _classPrivateFieldGet2(_escape, this).length - 1);
|
|
774
|
+
text += "\"";
|
|
775
|
+
} else {
|
|
776
|
+
text = text.trimEnd();
|
|
777
|
+
if (text.endsWith(",")) text = text.slice(0, -1);
|
|
778
|
+
}
|
|
779
|
+
for (let i = _classPrivateFieldGet2(_containers, this).length - 1; i >= 0; i--) text += _classPrivateFieldGet2(_containers, this)[i];
|
|
780
|
+
if (text.trim() === "") return {};
|
|
781
|
+
try {
|
|
782
|
+
const value = JSON.parse(text);
|
|
783
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
784
|
+
} catch {
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
//#endregion
|
|
669
789
|
//#region src/models/pi-ai/wires/chat-completions.ts
|
|
670
790
|
/**
|
|
671
791
|
* Chat-completions wire: Workers AI on the run path, and any pi-ai model whose
|
|
@@ -756,6 +876,7 @@ var CompletionAssembler = class {
|
|
|
756
876
|
this.stream = stream;
|
|
757
877
|
this.openToolCalls = /* @__PURE__ */ new Map();
|
|
758
878
|
this.closedToolCalls = /* @__PURE__ */ new Set();
|
|
879
|
+
this.toolArguments = /* @__PURE__ */ new Map();
|
|
759
880
|
this.blocks = output.content;
|
|
760
881
|
}
|
|
761
882
|
indexOf(block) {
|
|
@@ -837,6 +958,7 @@ var CompletionAssembler = class {
|
|
|
837
958
|
this.closedToolCalls.add(index);
|
|
838
959
|
block.arguments = parseStreamingJson(block.partialArguments ?? "");
|
|
839
960
|
delete block.partialArguments;
|
|
961
|
+
this.toolArguments.delete(index);
|
|
840
962
|
this.stream.push({
|
|
841
963
|
contentIndex: this.indexOf(block),
|
|
842
964
|
partial: this.output,
|
|
@@ -879,8 +1001,13 @@ var CompletionAssembler = class {
|
|
|
879
1001
|
}
|
|
880
1002
|
this.lastToolIndex = index;
|
|
881
1003
|
if (args.length > 0) {
|
|
882
|
-
|
|
883
|
-
|
|
1004
|
+
let parser = this.toolArguments.get(index);
|
|
1005
|
+
if (parser === void 0) {
|
|
1006
|
+
parser = new PartialArguments();
|
|
1007
|
+
this.toolArguments.set(index, parser);
|
|
1008
|
+
}
|
|
1009
|
+
block.arguments = parser.push(args);
|
|
1010
|
+
block.partialArguments = parser.text;
|
|
884
1011
|
this.stream.push({
|
|
885
1012
|
contentIndex: this.indexOf(block),
|
|
886
1013
|
delta: args,
|