toolcraft 0.0.309 → 0.0.311
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/composition.json +3 -3
- package/dist/composition.json +3 -3
- package/node_modules/auth-store/README.md +16 -0
- package/node_modules/auth-store/dist/encrypted-file-store.d.ts +3 -0
- package/node_modules/auth-store/dist/encrypted-file-store.js +7 -0
- package/node_modules/auth-store/dist/index.d.ts +1 -0
- package/node_modules/auth-store/dist/keychain-store.d.ts +8 -0
- package/node_modules/auth-store/dist/keychain-store.js +13 -0
- package/node_modules/auth-store/dist/transaction-lock.d.ts +24 -0
- package/node_modules/auth-store/dist/transaction-lock.js +152 -0
- package/node_modules/auth-store/dist/types.d.ts +2 -0
- package/node_modules/tiny-http-mcp-server/dist/composition.json +1 -1
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/README.md +33 -0
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/auth-store-session-store.js +8 -0
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +202 -185
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/session-transaction.d.ts +6 -0
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/session-transaction.js +42 -0
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.d.ts +3 -1
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js +7 -3
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/types.d.ts +14 -1
- package/node_modules/tiny-http-mcp-server/package.json +1 -1
- package/node_modules/tiny-mcp-client/dist/index.d.ts +39 -1
- package/node_modules/tiny-mcp-client/dist/index.js +503 -254
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +2 -2
|
@@ -279,8 +279,8 @@ function receivedType(value) {
|
|
|
279
279
|
}
|
|
280
280
|
return typeof value;
|
|
281
281
|
}
|
|
282
|
-
function issue(
|
|
283
|
-
return { path:
|
|
282
|
+
function issue(path5, expected, value, message, keyword = keywordFor(expected)) {
|
|
283
|
+
return { path: path5, expected, received: receivedType(value), message, keyword };
|
|
284
284
|
}
|
|
285
285
|
function keywordFor(expected) {
|
|
286
286
|
if (["null", "boolean", "object", "array", "number", "integer", "string"].includes(expected)) {
|
|
@@ -997,113 +997,113 @@ function evaluateArrayApplicators(graph, node, schema, value, context) {
|
|
|
997
997
|
}
|
|
998
998
|
return results;
|
|
999
999
|
}
|
|
1000
|
-
function evaluateValidationKeywords(node, schema, value,
|
|
1000
|
+
function evaluateValidationKeywords(node, schema, value, path5) {
|
|
1001
1001
|
const results = [];
|
|
1002
1002
|
const types = typeof schema.type === "string" ? [schema.type] : Array.isArray(schema.type) ? schema.type : [];
|
|
1003
1003
|
if (types.length > 0 && !types.some((type) => typeof type === "string" && typeMatches(type, value))) {
|
|
1004
|
-
results.push(invalidResult(issue(
|
|
1004
|
+
results.push(invalidResult(issue(path5, types.join(","), value, `must be ${types.join(",")}`)));
|
|
1005
1005
|
return results;
|
|
1006
1006
|
}
|
|
1007
1007
|
if (schema.const !== void 0 && !deepEqual(schema.const, value)) {
|
|
1008
|
-
results.push(invalidResult(issue(
|
|
1008
|
+
results.push(invalidResult(issue(path5, "const", value, "must be equal to constant")));
|
|
1009
1009
|
}
|
|
1010
1010
|
if (Array.isArray(schema.enum) && !schema.enum.some((entry) => deepEqual(entry, value))) {
|
|
1011
|
-
results.push(invalidResult(issue(
|
|
1011
|
+
results.push(invalidResult(issue(path5, "enum", value, "must be equal to one of the allowed values")));
|
|
1012
1012
|
}
|
|
1013
1013
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1014
|
-
evaluateNumberKeywords(schema, value,
|
|
1014
|
+
evaluateNumberKeywords(schema, value, path5, results);
|
|
1015
1015
|
}
|
|
1016
1016
|
if (typeof value === "string") {
|
|
1017
|
-
evaluateStringKeywords(schema, value,
|
|
1017
|
+
evaluateStringKeywords(schema, value, path5, results);
|
|
1018
1018
|
}
|
|
1019
1019
|
if (Array.isArray(value)) {
|
|
1020
|
-
evaluateArrayKeywords(schema, value,
|
|
1020
|
+
evaluateArrayKeywords(schema, value, path5, results);
|
|
1021
1021
|
}
|
|
1022
1022
|
if (isObject(value)) {
|
|
1023
|
-
evaluateObjectKeywords(node, schema, value,
|
|
1023
|
+
evaluateObjectKeywords(node, schema, value, path5, results);
|
|
1024
1024
|
}
|
|
1025
1025
|
return results;
|
|
1026
1026
|
}
|
|
1027
|
-
function evaluateNumberKeywords(schema, value,
|
|
1027
|
+
function evaluateNumberKeywords(schema, value, path5, results) {
|
|
1028
1028
|
if (typeof schema.multipleOf === "number" && !isMultipleOf(value, schema.multipleOf)) {
|
|
1029
|
-
results.push(invalidResult(issue(
|
|
1029
|
+
results.push(invalidResult(issue(path5, `multiple of ${schema.multipleOf}`, value, `must be multiple of ${schema.multipleOf}`)));
|
|
1030
1030
|
}
|
|
1031
1031
|
if (typeof schema.maximum === "number" && value > schema.maximum) {
|
|
1032
|
-
results.push(invalidResult(issue(
|
|
1032
|
+
results.push(invalidResult(issue(path5, `<= ${schema.maximum}`, value, `must be <= ${schema.maximum}`)));
|
|
1033
1033
|
}
|
|
1034
1034
|
if (typeof schema.minimum === "number" && value < schema.minimum) {
|
|
1035
|
-
results.push(invalidResult(issue(
|
|
1035
|
+
results.push(invalidResult(issue(path5, `>= ${schema.minimum}`, value, `must be >= ${schema.minimum}`)));
|
|
1036
1036
|
}
|
|
1037
1037
|
if (typeof schema.exclusiveMaximum === "number" && value >= schema.exclusiveMaximum) {
|
|
1038
|
-
results.push(invalidResult(issue(
|
|
1038
|
+
results.push(invalidResult(issue(path5, `< ${schema.exclusiveMaximum}`, value, `must be < ${schema.exclusiveMaximum}`)));
|
|
1039
1039
|
}
|
|
1040
1040
|
if (typeof schema.exclusiveMinimum === "number" && value <= schema.exclusiveMinimum) {
|
|
1041
|
-
results.push(invalidResult(issue(
|
|
1041
|
+
results.push(invalidResult(issue(path5, `> ${schema.exclusiveMinimum}`, value, `must be > ${schema.exclusiveMinimum}`)));
|
|
1042
1042
|
}
|
|
1043
1043
|
}
|
|
1044
|
-
function evaluateStringKeywords(schema, value,
|
|
1044
|
+
function evaluateStringKeywords(schema, value, path5, results) {
|
|
1045
1045
|
const length = unicodeLength(value);
|
|
1046
1046
|
if (typeof schema.maxLength === "number" && length > schema.maxLength) {
|
|
1047
|
-
results.push(invalidResult(issue(
|
|
1047
|
+
results.push(invalidResult(issue(path5, `length <= ${schema.maxLength}`, value, `must NOT have more than ${schema.maxLength} characters`)));
|
|
1048
1048
|
}
|
|
1049
1049
|
if (typeof schema.minLength === "number" && length < schema.minLength) {
|
|
1050
|
-
results.push(invalidResult(issue(
|
|
1050
|
+
results.push(invalidResult(issue(path5, `length >= ${schema.minLength}`, value, `must NOT have fewer than ${schema.minLength} characters`)));
|
|
1051
1051
|
}
|
|
1052
1052
|
if (typeof schema.pattern === "string" && !new RegExp(schema.pattern, "u").test(value)) {
|
|
1053
|
-
results.push(invalidResult(issue(
|
|
1053
|
+
results.push(invalidResult(issue(path5, `pattern ${schema.pattern}`, value, `must match pattern ${schema.pattern}`)));
|
|
1054
1054
|
}
|
|
1055
1055
|
}
|
|
1056
|
-
function evaluateArrayKeywords(schema, value,
|
|
1056
|
+
function evaluateArrayKeywords(schema, value, path5, results) {
|
|
1057
1057
|
if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
|
|
1058
|
-
results.push(invalidResult(issue(
|
|
1058
|
+
results.push(invalidResult(issue(path5, `items <= ${schema.maxItems}`, value, `must NOT have more than ${schema.maxItems} items`)));
|
|
1059
1059
|
}
|
|
1060
1060
|
if (typeof schema.minItems === "number" && value.length < schema.minItems) {
|
|
1061
|
-
results.push(invalidResult(issue(
|
|
1061
|
+
results.push(invalidResult(issue(path5, `items >= ${schema.minItems}`, value, `must NOT have fewer than ${schema.minItems} items`)));
|
|
1062
1062
|
}
|
|
1063
1063
|
if (schema.uniqueItems === true) {
|
|
1064
1064
|
for (let left = 0; left < value.length; left += 1) {
|
|
1065
1065
|
for (let right = left + 1; right < value.length; right += 1) {
|
|
1066
1066
|
if (deepEqual(value[left], value[right])) {
|
|
1067
|
-
results.push(invalidResult(issue(
|
|
1067
|
+
results.push(invalidResult(issue(path5, "unique items", value, "must NOT have duplicate items")));
|
|
1068
1068
|
return;
|
|
1069
1069
|
}
|
|
1070
1070
|
}
|
|
1071
1071
|
}
|
|
1072
1072
|
}
|
|
1073
1073
|
}
|
|
1074
|
-
function evaluateObjectKeywords(node, schema, value,
|
|
1074
|
+
function evaluateObjectKeywords(node, schema, value, path5, results) {
|
|
1075
1075
|
const keys = Object.keys(value);
|
|
1076
1076
|
if (typeof schema.maxProperties === "number" && keys.length > schema.maxProperties) {
|
|
1077
|
-
results.push(invalidResult(issue(
|
|
1077
|
+
results.push(invalidResult(issue(path5, `properties <= ${schema.maxProperties}`, value, `must NOT have more than ${schema.maxProperties} properties`)));
|
|
1078
1078
|
}
|
|
1079
1079
|
if (typeof schema.minProperties === "number" && keys.length < schema.minProperties) {
|
|
1080
|
-
results.push(invalidResult(issue(
|
|
1080
|
+
results.push(invalidResult(issue(path5, `properties >= ${schema.minProperties}`, value, `must NOT have fewer than ${schema.minProperties} properties`)));
|
|
1081
1081
|
}
|
|
1082
1082
|
if (Array.isArray(schema.required)) {
|
|
1083
1083
|
for (const key2 of schema.required) {
|
|
1084
1084
|
if (typeof key2 === "string" && !Object.prototype.hasOwnProperty.call(value, key2)) {
|
|
1085
|
-
results.push(invalidResult(issue([...
|
|
1085
|
+
results.push(invalidResult(issue([...path5, key2], "required", void 0, `must have required property '${key2}'`)));
|
|
1086
1086
|
}
|
|
1087
1087
|
}
|
|
1088
1088
|
}
|
|
1089
1089
|
const dependentRequired = isObject(schema.dependentRequired) ? schema.dependentRequired : {};
|
|
1090
1090
|
for (const [key2, dependencies] of Object.entries(dependentRequired)) {
|
|
1091
1091
|
if (Object.prototype.hasOwnProperty.call(value, key2) && Array.isArray(dependencies)) {
|
|
1092
|
-
addMissingDependencies(value, dependencies,
|
|
1092
|
+
addMissingDependencies(value, dependencies, path5, results);
|
|
1093
1093
|
}
|
|
1094
1094
|
}
|
|
1095
1095
|
if (node.dialect === "draft7" && isObject(schema.dependencies)) {
|
|
1096
1096
|
for (const [key2, dependencies] of Object.entries(schema.dependencies)) {
|
|
1097
1097
|
if (Object.prototype.hasOwnProperty.call(value, key2) && Array.isArray(dependencies)) {
|
|
1098
|
-
addMissingDependencies(value, dependencies,
|
|
1098
|
+
addMissingDependencies(value, dependencies, path5, results);
|
|
1099
1099
|
}
|
|
1100
1100
|
}
|
|
1101
1101
|
}
|
|
1102
1102
|
}
|
|
1103
|
-
function addMissingDependencies(value, dependencies,
|
|
1103
|
+
function addMissingDependencies(value, dependencies, path5, results) {
|
|
1104
1104
|
for (const dependency of dependencies) {
|
|
1105
1105
|
if (typeof dependency === "string" && !Object.prototype.hasOwnProperty.call(value, dependency)) {
|
|
1106
|
-
results.push(invalidResult(issue([...
|
|
1106
|
+
results.push(invalidResult(issue([...path5, dependency], "dependency", void 0, `must have property '${dependency}'`)));
|
|
1107
1107
|
}
|
|
1108
1108
|
}
|
|
1109
1109
|
}
|
|
@@ -3397,19 +3397,168 @@ var SubscriptionManager = class {
|
|
|
3397
3397
|
|
|
3398
3398
|
// ../mcp-oauth/dist/client/auth-store-session-store.js
|
|
3399
3399
|
import crypto from "node:crypto";
|
|
3400
|
-
import
|
|
3400
|
+
import path4 from "node:path";
|
|
3401
3401
|
|
|
3402
3402
|
// ../auth-store/dist/encrypted-file-store.js
|
|
3403
|
-
import { createCipheriv, createDecipheriv, randomBytes, randomUUID, scrypt } from "node:crypto";
|
|
3403
|
+
import { createCipheriv, createDecipheriv, randomBytes, randomUUID as randomUUID2, scrypt } from "node:crypto";
|
|
3404
3404
|
import { promises as fs } from "node:fs";
|
|
3405
3405
|
import { homedir, hostname, userInfo } from "node:os";
|
|
3406
|
-
import
|
|
3406
|
+
import path2 from "node:path";
|
|
3407
3407
|
|
|
3408
3408
|
// ../auth-store/dist/error-codes.js
|
|
3409
3409
|
function hasOwnErrorCode(error, code) {
|
|
3410
3410
|
return error instanceof Error && Object.prototype.hasOwnProperty.call(error, "code") && error.code === code;
|
|
3411
3411
|
}
|
|
3412
3412
|
|
|
3413
|
+
// ../auth-store/dist/transaction-lock.js
|
|
3414
|
+
import { randomUUID } from "node:crypto";
|
|
3415
|
+
import path from "node:path";
|
|
3416
|
+
async function withSecretStoreFileLock(fs2, lockDirectory, operation, options = {}) {
|
|
3417
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
3418
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs < 0 || timeoutMs > 2147483647)
|
|
3419
|
+
throw new Error("Invalid secret-store transaction lock timeout");
|
|
3420
|
+
options.signal?.throwIfAborted();
|
|
3421
|
+
const deadline = performance.now() + timeoutMs;
|
|
3422
|
+
const directory = path.resolve(lockDirectory);
|
|
3423
|
+
await assertLockDirectoryPath(fs2, directory);
|
|
3424
|
+
await fs2.mkdir(directory, { recursive: true, mode: 448 });
|
|
3425
|
+
await assertLockDirectoryPath(fs2, directory);
|
|
3426
|
+
const name = `${process.pid}-${randomUUID()}.claim`;
|
|
3427
|
+
const claimPath = path.join(directory, name);
|
|
3428
|
+
const temporaryPath = `${claimPath}.tmp`;
|
|
3429
|
+
let claimed = true;
|
|
3430
|
+
let temporaryCreated = false;
|
|
3431
|
+
let outcome;
|
|
3432
|
+
try {
|
|
3433
|
+
try {
|
|
3434
|
+
await fs2.writeFile(claimPath, JSON.stringify({ ticket: null }), { encoding: "utf8", flag: "wx", mode: 384 });
|
|
3435
|
+
} catch (error) {
|
|
3436
|
+
if (hasOwnErrorCode(error, "EEXIST"))
|
|
3437
|
+
claimed = false;
|
|
3438
|
+
throw error;
|
|
3439
|
+
}
|
|
3440
|
+
const existing = await readClaims(fs2, directory, name);
|
|
3441
|
+
const ticket = existing.reduce((max, claim) => Math.max(max, claim.ticket ?? 0), 0) + 1;
|
|
3442
|
+
if (!Number.isSafeInteger(ticket))
|
|
3443
|
+
throw new Error("Secret-store transaction lock ticket overflow");
|
|
3444
|
+
temporaryCreated = true;
|
|
3445
|
+
try {
|
|
3446
|
+
await fs2.writeFile(temporaryPath, JSON.stringify({ ticket }), { encoding: "utf8", flag: "wx", mode: 384 });
|
|
3447
|
+
} catch (error) {
|
|
3448
|
+
if (hasOwnErrorCode(error, "EEXIST"))
|
|
3449
|
+
temporaryCreated = false;
|
|
3450
|
+
throw error;
|
|
3451
|
+
}
|
|
3452
|
+
await fs2.rename(temporaryPath, claimPath);
|
|
3453
|
+
temporaryCreated = false;
|
|
3454
|
+
for (; ; ) {
|
|
3455
|
+
options.signal?.throwIfAborted();
|
|
3456
|
+
const peers = await readClaims(fs2, directory, name);
|
|
3457
|
+
if (!peers.some((peer) => peer.ticket === null || peer.ticket < ticket || peer.ticket === ticket && peer.name < name))
|
|
3458
|
+
break;
|
|
3459
|
+
const remaining = deadline - performance.now();
|
|
3460
|
+
if (remaining <= 0)
|
|
3461
|
+
throw new Error("Timed out waiting for secret-store transaction lock");
|
|
3462
|
+
await new Promise((resolve, reject) => {
|
|
3463
|
+
const abort = () => {
|
|
3464
|
+
clearTimeout(timer);
|
|
3465
|
+
options.signal?.removeEventListener("abort", abort);
|
|
3466
|
+
reject(options.signal?.reason);
|
|
3467
|
+
};
|
|
3468
|
+
const timer = setTimeout(() => {
|
|
3469
|
+
options.signal?.removeEventListener("abort", abort);
|
|
3470
|
+
resolve();
|
|
3471
|
+
}, Math.min(10, remaining));
|
|
3472
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
3473
|
+
if (options.signal?.aborted)
|
|
3474
|
+
abort();
|
|
3475
|
+
});
|
|
3476
|
+
}
|
|
3477
|
+
options.signal?.throwIfAborted();
|
|
3478
|
+
outcome = { result: await operation() };
|
|
3479
|
+
} catch (error) {
|
|
3480
|
+
outcome = { error };
|
|
3481
|
+
}
|
|
3482
|
+
const cleanup = [];
|
|
3483
|
+
for (const target of [...temporaryCreated ? [temporaryPath] : [], ...claimed ? [claimPath] : []]) {
|
|
3484
|
+
try {
|
|
3485
|
+
await fs2.unlink(target);
|
|
3486
|
+
} catch (error) {
|
|
3487
|
+
if (!hasOwnErrorCode(error, "ENOENT"))
|
|
3488
|
+
cleanup.push(error);
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
if (cleanup.length)
|
|
3492
|
+
throw new AggregateError([..."error" in outcome ? [outcome.error] : [], ...cleanup], "Secret-store transaction lock cleanup failed");
|
|
3493
|
+
if ("error" in outcome)
|
|
3494
|
+
throw outcome.error;
|
|
3495
|
+
return outcome.result;
|
|
3496
|
+
}
|
|
3497
|
+
async function assertNoSymbolicLink(fs2, target) {
|
|
3498
|
+
try {
|
|
3499
|
+
if ((await fs2.lstat(target)).isSymbolicLink())
|
|
3500
|
+
throw new Error("Refusing secret-store transaction lock through symbolic link");
|
|
3501
|
+
} catch (error) {
|
|
3502
|
+
if (!hasOwnErrorCode(error, "ENOENT"))
|
|
3503
|
+
throw error;
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
async function assertLockDirectoryPath(fs2, directory) {
|
|
3507
|
+
const root = path.parse(directory).root;
|
|
3508
|
+
const segments = directory.slice(root.length).split(path.sep).filter(Boolean);
|
|
3509
|
+
let current = root;
|
|
3510
|
+
for (const [index, segment] of segments.entries()) {
|
|
3511
|
+
current = path.join(current, segment);
|
|
3512
|
+
if (index > 0 || segments.length === 1)
|
|
3513
|
+
await assertNoSymbolicLink(fs2, current);
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
async function readClaims(fs2, directory, ownName) {
|
|
3517
|
+
const claims = [];
|
|
3518
|
+
for (const name of await fs2.readdir(directory)) {
|
|
3519
|
+
if (name === ownName || !name.endsWith(".claim"))
|
|
3520
|
+
continue;
|
|
3521
|
+
const pidText = name.slice(0, name.indexOf("-"));
|
|
3522
|
+
const pid = Number(pidText);
|
|
3523
|
+
if (!Number.isSafeInteger(pid) || pid < 1 || String(pid) !== pidText)
|
|
3524
|
+
throw new Error("Malformed secret-store transaction lock owner");
|
|
3525
|
+
const target = path.join(directory, name);
|
|
3526
|
+
await assertNoSymbolicLink(fs2, target);
|
|
3527
|
+
let alive = true;
|
|
3528
|
+
try {
|
|
3529
|
+
process.kill(pid, 0);
|
|
3530
|
+
} catch (error) {
|
|
3531
|
+
alive = !hasOwnErrorCode(error, "ESRCH");
|
|
3532
|
+
}
|
|
3533
|
+
if (!alive) {
|
|
3534
|
+
try {
|
|
3535
|
+
await fs2.unlink(target);
|
|
3536
|
+
} catch (error) {
|
|
3537
|
+
if (!hasOwnErrorCode(error, "ENOENT"))
|
|
3538
|
+
throw error;
|
|
3539
|
+
}
|
|
3540
|
+
continue;
|
|
3541
|
+
}
|
|
3542
|
+
let ticket = null;
|
|
3543
|
+
let raw;
|
|
3544
|
+
try {
|
|
3545
|
+
raw = await fs2.readFile(target, "utf8");
|
|
3546
|
+
} catch (error) {
|
|
3547
|
+
if (hasOwnErrorCode(error, "ENOENT"))
|
|
3548
|
+
continue;
|
|
3549
|
+
throw error;
|
|
3550
|
+
}
|
|
3551
|
+
try {
|
|
3552
|
+
const value = JSON.parse(raw);
|
|
3553
|
+
if (value !== null && typeof value === "object" && "ticket" in value && typeof value.ticket === "number" && Number.isSafeInteger(value.ticket) && value.ticket > 0)
|
|
3554
|
+
ticket = value.ticket;
|
|
3555
|
+
} catch {
|
|
3556
|
+
}
|
|
3557
|
+
claims.push({ name, ticket });
|
|
3558
|
+
}
|
|
3559
|
+
return claims;
|
|
3560
|
+
}
|
|
3561
|
+
|
|
3413
3562
|
// ../auth-store/dist/encrypted-file-store.js
|
|
3414
3563
|
var derivedKeyCache = /* @__PURE__ */ new Map();
|
|
3415
3564
|
var ENCRYPTION_ALGORITHM = "aes-256-gcm";
|
|
@@ -3435,7 +3584,7 @@ var EncryptedFileStore = class {
|
|
|
3435
3584
|
const defaultFileName = input.defaultFileName ?? "credentials.enc";
|
|
3436
3585
|
assertSafeDefaultDirectory(defaultDirectory);
|
|
3437
3586
|
assertSafeDefaultFileName(defaultFileName);
|
|
3438
|
-
this.filePath =
|
|
3587
|
+
this.filePath = path2.join(homeDirectory, defaultDirectory, defaultFileName);
|
|
3439
3588
|
this.symbolicLinkCheckStartPath = resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory);
|
|
3440
3589
|
} else {
|
|
3441
3590
|
this.filePath = input.filePath;
|
|
@@ -3475,6 +3624,12 @@ var EncryptedFileStore = class {
|
|
|
3475
3624
|
return null;
|
|
3476
3625
|
}
|
|
3477
3626
|
}
|
|
3627
|
+
async withLock(operation, options = {}) {
|
|
3628
|
+
await this.assertCredentialPathHasNoSymbolicLinks(`${this.filePath}.lock`);
|
|
3629
|
+
if (this.fs.readdir === void 0)
|
|
3630
|
+
throw new Error("Secret-store transaction locks require filesystem readdir support");
|
|
3631
|
+
return withSecretStoreFileLock(this.fs, `${this.filePath}.lock`, operation, options);
|
|
3632
|
+
}
|
|
3478
3633
|
async set(value) {
|
|
3479
3634
|
await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
|
|
3480
3635
|
const key2 = await this.getEncryptionKey();
|
|
@@ -3491,9 +3646,9 @@ var EncryptedFileStore = class {
|
|
|
3491
3646
|
authTag: authTag.toString("base64"),
|
|
3492
3647
|
ciphertext: ciphertext.toString("base64")
|
|
3493
3648
|
};
|
|
3494
|
-
await this.fs.mkdir(
|
|
3649
|
+
await this.fs.mkdir(path2.dirname(this.filePath), { recursive: true });
|
|
3495
3650
|
await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
|
|
3496
|
-
const temporaryPath = `${this.filePath}.${process.pid}.${
|
|
3651
|
+
const temporaryPath = `${this.filePath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
3497
3652
|
let temporaryCreated = false;
|
|
3498
3653
|
try {
|
|
3499
3654
|
await this.assertCredentialPathHasNoSymbolicLinks(temporaryPath);
|
|
@@ -3523,7 +3678,7 @@ var EncryptedFileStore = class {
|
|
|
3523
3678
|
}
|
|
3524
3679
|
}
|
|
3525
3680
|
async assertCredentialPathHasNoSymbolicLinks(targetPath) {
|
|
3526
|
-
const resolvedPath =
|
|
3681
|
+
const resolvedPath = path2.resolve(targetPath);
|
|
3527
3682
|
const protectedPaths = getProtectedCredentialPaths(resolvedPath, this.symbolicLinkCheckStartPath);
|
|
3528
3683
|
for (const currentPath of protectedPaths) {
|
|
3529
3684
|
try {
|
|
@@ -3554,26 +3709,26 @@ var EncryptedFileStore = class {
|
|
|
3554
3709
|
};
|
|
3555
3710
|
function resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory) {
|
|
3556
3711
|
const [firstSegment] = defaultDirectory.split(/[\\/]+/).filter(Boolean);
|
|
3557
|
-
return
|
|
3712
|
+
return path2.resolve(homeDirectory, firstSegment ?? ".");
|
|
3558
3713
|
}
|
|
3559
3714
|
function getProtectedCredentialPaths(resolvedPath, symbolicLinkCheckStartPath) {
|
|
3560
3715
|
if (symbolicLinkCheckStartPath === null) {
|
|
3561
3716
|
return getExplicitProtectedCredentialPaths(resolvedPath);
|
|
3562
3717
|
}
|
|
3563
|
-
const resolvedStartPath =
|
|
3718
|
+
const resolvedStartPath = path2.resolve(symbolicLinkCheckStartPath);
|
|
3564
3719
|
if (!isPathInsideOrEqual(resolvedPath, resolvedStartPath)) {
|
|
3565
|
-
return [
|
|
3720
|
+
return [path2.dirname(resolvedPath), resolvedPath];
|
|
3566
3721
|
}
|
|
3567
3722
|
const protectedPaths = [resolvedStartPath];
|
|
3568
3723
|
let currentPath = resolvedStartPath;
|
|
3569
|
-
for (const segment of
|
|
3570
|
-
currentPath =
|
|
3724
|
+
for (const segment of path2.relative(resolvedStartPath, resolvedPath).split(path2.sep).filter(Boolean)) {
|
|
3725
|
+
currentPath = path2.join(currentPath, segment);
|
|
3571
3726
|
protectedPaths.push(currentPath);
|
|
3572
3727
|
}
|
|
3573
3728
|
return protectedPaths;
|
|
3574
3729
|
}
|
|
3575
3730
|
function assertSafeDefaultDirectory(defaultDirectory) {
|
|
3576
|
-
if (
|
|
3731
|
+
if (path2.isAbsolute(defaultDirectory) || path2.win32.isAbsolute(defaultDirectory)) {
|
|
3577
3732
|
throw new Error("defaultDirectory must be a relative path inside the home directory");
|
|
3578
3733
|
}
|
|
3579
3734
|
for (const segment of splitPathSegments(defaultDirectory)) {
|
|
@@ -3591,15 +3746,15 @@ function splitPathSegments(value) {
|
|
|
3591
3746
|
return value.split("/").flatMap((segment) => segment.split("\\")).filter((segment) => segment.length > 0);
|
|
3592
3747
|
}
|
|
3593
3748
|
function getExplicitProtectedCredentialPaths(resolvedPath) {
|
|
3594
|
-
const parsed =
|
|
3595
|
-
const segments = resolvedPath.slice(parsed.root.length).split(
|
|
3749
|
+
const parsed = path2.parse(resolvedPath);
|
|
3750
|
+
const segments = resolvedPath.slice(parsed.root.length).split(path2.sep).filter((segment) => segment.length > 0);
|
|
3596
3751
|
if (segments.length <= 1) {
|
|
3597
3752
|
return [resolvedPath];
|
|
3598
3753
|
}
|
|
3599
3754
|
const protectedPaths = [];
|
|
3600
3755
|
let currentPath = parsed.root;
|
|
3601
3756
|
for (const [index, segment] of segments.entries()) {
|
|
3602
|
-
currentPath =
|
|
3757
|
+
currentPath = path2.join(currentPath, segment);
|
|
3603
3758
|
if (index === 0) {
|
|
3604
3759
|
continue;
|
|
3605
3760
|
}
|
|
@@ -3608,8 +3763,8 @@ function getExplicitProtectedCredentialPaths(resolvedPath) {
|
|
|
3608
3763
|
return protectedPaths;
|
|
3609
3764
|
}
|
|
3610
3765
|
function isPathInsideOrEqual(childPath, parentPath) {
|
|
3611
|
-
const relativePath =
|
|
3612
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
3766
|
+
const relativePath = path2.relative(parentPath, childPath);
|
|
3767
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path2.isAbsolute(relativePath);
|
|
3613
3768
|
}
|
|
3614
3769
|
async function removeIfPresent(fileSystem, filePath) {
|
|
3615
3770
|
try {
|
|
@@ -3692,16 +3847,24 @@ function isAlreadyExistsError(error) {
|
|
|
3692
3847
|
|
|
3693
3848
|
// ../auth-store/dist/keychain-store.js
|
|
3694
3849
|
import { spawn } from "node:child_process";
|
|
3850
|
+
import { createHash } from "node:crypto";
|
|
3851
|
+
import { promises as nodeFs } from "node:fs";
|
|
3852
|
+
import { homedir as homedir2 } from "node:os";
|
|
3853
|
+
import path3 from "node:path";
|
|
3695
3854
|
var SECURITY_CLI = "security";
|
|
3696
3855
|
var KEYCHAIN_ITEM_NOT_FOUND_EXIT_CODE = 44;
|
|
3697
3856
|
var KeychainStore = class {
|
|
3698
3857
|
runCommand;
|
|
3699
3858
|
service;
|
|
3700
3859
|
account;
|
|
3860
|
+
lockFs;
|
|
3861
|
+
lockDirectory;
|
|
3701
3862
|
constructor(input) {
|
|
3702
3863
|
this.runCommand = input.runCommand ?? runSecurityCommand;
|
|
3703
3864
|
this.service = input.service.trim();
|
|
3704
3865
|
this.account = input.account.trim();
|
|
3866
|
+
this.lockFs = input.lock?.fs ?? nodeFs;
|
|
3867
|
+
this.lockDirectory = input.lock?.directory ?? path3.join(homedir2(), ".auth-store", "keychain-locks");
|
|
3705
3868
|
if (this.service.length === 0) {
|
|
3706
3869
|
throw new Error("Keychain service must not be empty");
|
|
3707
3870
|
}
|
|
@@ -3719,6 +3882,10 @@ var KeychainStore = class {
|
|
|
3719
3882
|
}
|
|
3720
3883
|
throw createSecurityCliFailure("read secret from macOS Keychain", result);
|
|
3721
3884
|
}
|
|
3885
|
+
async withLock(operation, options = {}) {
|
|
3886
|
+
const identity = createHash("sha256").update(JSON.stringify([this.service, this.account])).digest("hex");
|
|
3887
|
+
return withSecretStoreFileLock(this.lockFs, path3.join(this.lockDirectory, identity), operation, options);
|
|
3888
|
+
}
|
|
3722
3889
|
async set(value) {
|
|
3723
3890
|
if (value.includes("\n") || value.includes("\r")) {
|
|
3724
3891
|
throw new Error("Keychain secrets cannot contain line breaks");
|
|
@@ -3904,6 +4071,12 @@ var DEFAULT_CLIENT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth-clients";
|
|
|
3904
4071
|
var MAX_JS_DATE_MS = 864e13;
|
|
3905
4072
|
function createAuthStoreSessionStore(options = {}) {
|
|
3906
4073
|
return {
|
|
4074
|
+
async withLock(resource, operation, lockOptions) {
|
|
4075
|
+
const store = createResourceSecretStore(resource, options);
|
|
4076
|
+
if (store.withLock === void 0)
|
|
4077
|
+
throw new Error("OAuth secret-store backend does not support transaction locks");
|
|
4078
|
+
return store.withLock(operation, lockOptions);
|
|
4079
|
+
},
|
|
3907
4080
|
async load(resource) {
|
|
3908
4081
|
const store = createResourceSecretStore(resource, options);
|
|
3909
4082
|
const value = await store.get();
|
|
@@ -3958,10 +4131,10 @@ function createAuthStoreClientStore(options) {
|
|
|
3958
4131
|
function createNamedSecretStore(key2, options, defaults) {
|
|
3959
4132
|
const hash = crypto.createHash("sha256").update(key2).digest("hex");
|
|
3960
4133
|
const configuredFilePath = options.fileStore?.filePath;
|
|
3961
|
-
const parsedFilePath = configuredFilePath === void 0 ? null :
|
|
4134
|
+
const parsedFilePath = configuredFilePath === void 0 ? null : path4.parse(configuredFilePath);
|
|
3962
4135
|
const fileStore = {
|
|
3963
4136
|
...options.fileStore,
|
|
3964
|
-
filePath: parsedFilePath === null ? void 0 :
|
|
4137
|
+
filePath: parsedFilePath === null ? void 0 : path4.join(parsedFilePath.dir, `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`),
|
|
3965
4138
|
salt: options.fileStore?.salt ?? defaults.salt,
|
|
3966
4139
|
defaultDirectory: options.fileStore?.defaultDirectory || defaults.directory,
|
|
3967
4140
|
defaultFileName: parsedFilePath === null ? `${hash}.enc` : `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
|
|
@@ -4003,7 +4176,7 @@ function isStoredOAuthSession(value) {
|
|
|
4003
4176
|
if (!isObjectRecord(value)) {
|
|
4004
4177
|
return false;
|
|
4005
4178
|
}
|
|
4006
|
-
return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && isStoredOAuthClient(getOwnEntry3(value, "client")) && isStoredOAuthDiscovery(getOwnEntry3(value, "discovery")) && isStoredOAuthTokensOrMissing(getOwnEntry3(value, "tokens"));
|
|
4179
|
+
return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && isStoredOAuthClient(getOwnEntry3(value, "client")) && isStoredOAuthDiscovery(getOwnEntry3(value, "discovery")) && (getOwnEntry3(value, "refreshState") === void 0 || getOwnEntry3(value, "refreshState") === "pending" && getOwnEntry3(value, "tokens") === void 0) && isStoredOAuthTokensOrMissing(getOwnEntry3(value, "tokens"));
|
|
4007
4180
|
}
|
|
4008
4181
|
function isStoredOAuthClient(value) {
|
|
4009
4182
|
if (!isObjectRecord(value) || !isNonBlankOwnString(value, "clientId")) {
|
|
@@ -4432,7 +4605,9 @@ var OAuthError = class extends Error {
|
|
|
4432
4605
|
status;
|
|
4433
4606
|
retryable;
|
|
4434
4607
|
terminal;
|
|
4435
|
-
|
|
4608
|
+
/** True only when a complete OAuth error response establishes rejection. */
|
|
4609
|
+
outcomeKnown;
|
|
4610
|
+
constructor(shape, status, outcomeKnown = true) {
|
|
4436
4611
|
super(shape.error_description ?? shape.error);
|
|
4437
4612
|
this.name = "OAuthError";
|
|
4438
4613
|
this.error = shape.error;
|
|
@@ -4443,6 +4618,7 @@ var OAuthError = class extends Error {
|
|
|
4443
4618
|
this.status = status;
|
|
4444
4619
|
this.retryable = isRetryableOAuthError(this);
|
|
4445
4620
|
this.terminal = !this.retryable;
|
|
4621
|
+
this.outcomeKnown = outcomeKnown;
|
|
4446
4622
|
}
|
|
4447
4623
|
};
|
|
4448
4624
|
function isRetryableOAuthError(error) {
|
|
@@ -4557,7 +4733,8 @@ async function readOAuthJsonObjectResponse(response, signal) {
|
|
|
4557
4733
|
}
|
|
4558
4734
|
const record2 = payload;
|
|
4559
4735
|
if (!response.ok) {
|
|
4560
|
-
|
|
4736
|
+
const error = getOwnEntry5(record2, "error");
|
|
4737
|
+
throw new OAuthError(readOAuthError(record2, fallbackError.error), response.status, typeof error === "string" && error.trim().length > 0);
|
|
4561
4738
|
}
|
|
4562
4739
|
return record2;
|
|
4563
4740
|
}
|
|
@@ -4576,7 +4753,7 @@ function getOwnEntry5(record2, key2) {
|
|
|
4576
4753
|
}
|
|
4577
4754
|
function createFallbackOAuthError(status) {
|
|
4578
4755
|
const error = status === 503 ? "temporarily_unavailable" : "server_error";
|
|
4579
|
-
return new OAuthError({ error }, status);
|
|
4756
|
+
return new OAuthError({ error }, status, false);
|
|
4580
4757
|
}
|
|
4581
4758
|
function normalizeBearerTokenType(value) {
|
|
4582
4759
|
if (typeof value !== "string") {
|
|
@@ -4585,6 +4762,55 @@ function normalizeBearerTokenType(value) {
|
|
|
4585
4762
|
return value.toLowerCase() === "bearer" ? "Bearer" : null;
|
|
4586
4763
|
}
|
|
4587
4764
|
|
|
4765
|
+
// ../mcp-oauth/dist/client/session-transaction.js
|
|
4766
|
+
var queues = /* @__PURE__ */ new WeakMap();
|
|
4767
|
+
async function withOAuthSessionTransaction(store, resource, operation, options = {}) {
|
|
4768
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
4769
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647)
|
|
4770
|
+
throw new Error("sessionLockTimeoutMs must be an integer from 1 to 2147483647 milliseconds");
|
|
4771
|
+
options.signal?.throwIfAborted();
|
|
4772
|
+
const started = performance.now();
|
|
4773
|
+
const pending = queues.get(store) ?? /* @__PURE__ */ new Map();
|
|
4774
|
+
queues.set(store, pending);
|
|
4775
|
+
const previous = pending.get(resource) ?? Promise.resolve();
|
|
4776
|
+
let release;
|
|
4777
|
+
const current = new Promise((resolve) => {
|
|
4778
|
+
release = resolve;
|
|
4779
|
+
});
|
|
4780
|
+
const tail = previous.then(() => current);
|
|
4781
|
+
pending.set(resource, tail);
|
|
4782
|
+
try {
|
|
4783
|
+
let timer;
|
|
4784
|
+
let rejectWait;
|
|
4785
|
+
const waiting = new Promise((resolve, reject) => {
|
|
4786
|
+
rejectWait = reject;
|
|
4787
|
+
previous.then(resolve, reject);
|
|
4788
|
+
});
|
|
4789
|
+
const abort = () => rejectWait(options.signal?.reason);
|
|
4790
|
+
try {
|
|
4791
|
+
timer = setTimeout(() => rejectWait(new Error("Timed out waiting for OAuth session transaction lock")), timeoutMs);
|
|
4792
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
4793
|
+
if (options.signal?.aborted)
|
|
4794
|
+
abort();
|
|
4795
|
+
await waiting;
|
|
4796
|
+
} finally {
|
|
4797
|
+
clearTimeout(timer);
|
|
4798
|
+
options.signal?.removeEventListener("abort", abort);
|
|
4799
|
+
}
|
|
4800
|
+
options.signal?.throwIfAborted();
|
|
4801
|
+
return store.withLock === void 0 ? await operation() : await store.withLock(resource, operation, {
|
|
4802
|
+
signal: options.signal,
|
|
4803
|
+
timeoutMs: Math.max(0, timeoutMs - (performance.now() - started))
|
|
4804
|
+
});
|
|
4805
|
+
} finally {
|
|
4806
|
+
release();
|
|
4807
|
+
void tail.then(() => {
|
|
4808
|
+
if (pending.get(resource) === tail)
|
|
4809
|
+
pending.delete(resource);
|
|
4810
|
+
});
|
|
4811
|
+
}
|
|
4812
|
+
}
|
|
4813
|
+
|
|
4588
4814
|
// ../mcp-oauth/dist/client/default-oauth-client-provider.js
|
|
4589
4815
|
var MAX_JS_DATE_MS3 = 864e13;
|
|
4590
4816
|
function createOAuthClientProvider(options) {
|
|
@@ -4599,8 +4825,6 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
4599
4825
|
const clientStore = options.authStore === void 0 ? null : createAuthStoreClientStore(options.authStore);
|
|
4600
4826
|
const now = options.now ?? Date.now;
|
|
4601
4827
|
const registeredClients = /* @__PURE__ */ new Map();
|
|
4602
|
-
const refreshPromises = /* @__PURE__ */ new Map();
|
|
4603
|
-
const authorizationPromises = /* @__PURE__ */ new Map();
|
|
4604
4828
|
if (options.initialGrant !== void 0) {
|
|
4605
4829
|
let resource;
|
|
4606
4830
|
try {
|
|
@@ -4634,13 +4858,14 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
4634
4858
|
const accessToken = session?.tokens?.accessToken;
|
|
4635
4859
|
if (session === null && !initialGrantConsumed && initialGrant?.resource === requestUrl && initialGrant.tokens !== void 0 && !isExpired(initialGrant.tokens, now)) {
|
|
4636
4860
|
input.headers.set("Authorization", `Bearer ${initialGrant.tokens.accessToken}`);
|
|
4637
|
-
return;
|
|
4861
|
+
return { ...initialGrant.tokens };
|
|
4638
4862
|
}
|
|
4639
4863
|
if (session === null || accessToken === void 0 || session.tokens === void 0 || isExpired(session.tokens, now)) {
|
|
4640
4864
|
return;
|
|
4641
4865
|
}
|
|
4642
4866
|
assertRequestMatchesResource(requestUrl, session.resource);
|
|
4643
4867
|
input.headers.set("Authorization", `Bearer ${accessToken}`);
|
|
4868
|
+
return { ...session.tokens };
|
|
4644
4869
|
},
|
|
4645
4870
|
async handleUnauthorized(input) {
|
|
4646
4871
|
try {
|
|
@@ -4648,11 +4873,28 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
4648
4873
|
const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
|
|
4649
4874
|
const resource = canonicalizeResourceIndicator(input.discovery.resource);
|
|
4650
4875
|
assertRequestMatchesResource(requestUrl, resource);
|
|
4651
|
-
const
|
|
4876
|
+
const cached = await loadSession(resource);
|
|
4877
|
+
const currentTokens = cached?.tokens ?? (!initialGrantConsumed && initialGrant?.resource === resource ? initialGrant.tokens : void 0);
|
|
4878
|
+
let rejectedCurrentGrant = hasCachedAccessToken(cached) || !initialGrantConsumed && initialGrant?.resource === resource;
|
|
4879
|
+
let presentedTokens = input.presentedTokens;
|
|
4880
|
+
if (input.presentedTokens !== void 0) {
|
|
4881
|
+
rejectedCurrentGrant = false;
|
|
4882
|
+
if (input.presentedTokens !== null) {
|
|
4883
|
+
const presented = normalizeStoredTokens(input.presentedTokens);
|
|
4884
|
+
const header = input.requestHeaders?.get("Authorization") ?? "";
|
|
4885
|
+
const separator = header.indexOf(" ");
|
|
4886
|
+
if (presented === void 0 || header.slice(0, separator).toLowerCase() !== "bearer" || header.slice(separator + 1).trim() !== presented.accessToken)
|
|
4887
|
+
throw new Error("OAuth rejected-request provenance does not match its authorization header");
|
|
4888
|
+
presentedTokens = presented;
|
|
4889
|
+
rejectedCurrentGrant = currentTokens !== void 0 && sameTokenGrant(currentTokens, presented);
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4892
|
+
const challengeError = input.challenge?.params.error;
|
|
4893
|
+
const forceRefresh = rejectedCurrentGrant && (challengeError === "invalid_token" || input.presentedTokens !== void 0 && challengeError === void 0);
|
|
4652
4894
|
const session = await ensureAuthorizedSession(resource, {
|
|
4653
4895
|
...input.discovery,
|
|
4654
4896
|
resource
|
|
4655
|
-
}, input.fetch, true, forceRefresh, input.signal);
|
|
4897
|
+
}, input.fetch, true, forceRefresh, input.signal, presentedTokens);
|
|
4656
4898
|
if (session?.tokens?.accessToken === void 0) {
|
|
4657
4899
|
return { action: "fail" };
|
|
4658
4900
|
}
|
|
@@ -4666,204 +4908,196 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
4666
4908
|
}
|
|
4667
4909
|
}
|
|
4668
4910
|
};
|
|
4669
|
-
async function ensureAuthorizedSession(resource, discovery, fetch2, allowInteractive, forceRefresh = false, signal) {
|
|
4911
|
+
async function ensureAuthorizedSession(resource, discovery, fetch2, allowInteractive, forceRefresh = false, signal, rejectedTokens) {
|
|
4670
4912
|
signal?.throwIfAborted();
|
|
4671
4913
|
const canonicalResource = canonicalizeResourceIndicator(resource);
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
if (discovery !== void 0 && getOwnString2(discovery.authorizationServerMetadata, "issuer") !== discovery.authorizationServer) {
|
|
4677
|
-
throw new Error("OAuth discovery authorization-server issuer mismatch");
|
|
4678
|
-
}
|
|
4679
|
-
if (session !== null && (canonicalizeResourceIndicator(session.resource) !== canonicalResource || getOwnString2(session.discovery.authorizationServerMetadata, "issuer") !== session.authorizationServer || discovery !== void 0 && discovery.authorizationServer !== session.authorizationServer)) {
|
|
4680
|
-
await clearSession(canonicalResource);
|
|
4681
|
-
session = null;
|
|
4682
|
-
}
|
|
4683
|
-
if (session === null && discovery !== void 0 && !initialGrantConsumed && initialGrant?.resource === canonicalResource && initialGrant.tokens !== void 0 && initialGrant.client !== null) {
|
|
4684
|
-
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
4685
|
-
session = {
|
|
4686
|
-
resource: canonicalResource,
|
|
4687
|
-
authorizationServer: discovery.authorizationServer,
|
|
4688
|
-
client: initialGrant.client,
|
|
4689
|
-
tokens: initialGrant.tokens,
|
|
4690
|
-
discovery: toStoredDiscovery(discovery)
|
|
4691
|
-
};
|
|
4692
|
-
await saveSession(canonicalResource, session);
|
|
4693
|
-
initialGrantConsumed = true;
|
|
4914
|
+
return withOAuthSessionTransaction(sessionStore, canonicalResource, async () => {
|
|
4915
|
+
let session = await loadSession(canonicalResource);
|
|
4916
|
+
if (session !== null && initialGrant?.resource === canonicalResource)
|
|
4917
|
+
initialGrantConsumed = true;
|
|
4694
4918
|
signal?.throwIfAborted();
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
if (session
|
|
4919
|
+
if (discovery !== void 0 && getOwnString2(discovery.authorizationServerMetadata, "issuer") !== discovery.authorizationServer) {
|
|
4920
|
+
throw new Error("OAuth discovery authorization-server issuer mismatch");
|
|
4921
|
+
}
|
|
4922
|
+
if (session !== null && (canonicalizeResourceIndicator(session.resource) !== canonicalResource || getOwnString2(session.discovery.authorizationServerMetadata, "issuer") !== session.authorizationServer || discovery !== void 0 && discovery.authorizationServer !== session.authorizationServer)) {
|
|
4923
|
+
await clearSession(canonicalResource);
|
|
4924
|
+
session = null;
|
|
4925
|
+
}
|
|
4926
|
+
if (session === null && discovery !== void 0 && !initialGrantConsumed && initialGrant?.resource === canonicalResource && initialGrant.tokens !== void 0 && initialGrant.client !== null) {
|
|
4927
|
+
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
4928
|
+
session = {
|
|
4929
|
+
resource: canonicalResource,
|
|
4930
|
+
authorizationServer: discovery.authorizationServer,
|
|
4931
|
+
client: initialGrant.client,
|
|
4932
|
+
tokens: initialGrant.tokens,
|
|
4933
|
+
discovery: toStoredDiscovery(discovery)
|
|
4934
|
+
};
|
|
4935
|
+
await saveSession(canonicalResource, session);
|
|
4936
|
+
initialGrantConsumed = true;
|
|
4937
|
+
signal?.throwIfAborted();
|
|
4938
|
+
}
|
|
4939
|
+
if (forceRefresh && rejectedTokens !== void 0 && (rejectedTokens === null || session?.tokens === void 0 || !sameTokenGrant(session.tokens, rejectedTokens)))
|
|
4940
|
+
forceRefresh = false;
|
|
4941
|
+
const sessionDiscovery = resolveDiscovery(discovery, session);
|
|
4942
|
+
if (session?.refreshState === "pending") {
|
|
4943
|
+
if (!allowInteractive || options.allowInteractive === false || sessionDiscovery === void 0)
|
|
4944
|
+
throw new Error("OAuth refresh outcome is unknown; authorize again before using this resource");
|
|
4945
|
+
return authorizeSession(canonicalResource, clearSessionTokens(session), sessionDiscovery, fetch2, signal);
|
|
4946
|
+
}
|
|
4947
|
+
if (session?.tokens !== void 0 && !forceRefresh && !isExpired(session.tokens, now)) {
|
|
4703
4948
|
return session;
|
|
4704
4949
|
}
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4950
|
+
if (session?.tokens?.refreshToken !== void 0 && sessionDiscovery !== void 0 && (forceRefresh || isExpired(session.tokens, now))) {
|
|
4951
|
+
session = await refreshSession(canonicalResource, session, sessionDiscovery, fetch2, signal);
|
|
4952
|
+
if (session?.tokens !== void 0 && !isExpired(session.tokens, now)) {
|
|
4953
|
+
return session;
|
|
4954
|
+
}
|
|
4955
|
+
}
|
|
4956
|
+
if (forceRefresh && session?.tokens !== void 0) {
|
|
4957
|
+
session = clearSessionTokens(session);
|
|
4958
|
+
await saveSession(canonicalResource, session);
|
|
4959
|
+
}
|
|
4960
|
+
if (!allowInteractive || sessionDiscovery === void 0) {
|
|
4961
|
+
return session;
|
|
4962
|
+
}
|
|
4963
|
+
if (options.allowInteractive === false)
|
|
4964
|
+
throw new Error("OAuth interactive authorization is disabled");
|
|
4965
|
+
return authorizeSession(canonicalResource, session, sessionDiscovery, fetch2, signal);
|
|
4966
|
+
}, { signal, timeoutMs: options.sessionLockTimeoutMs });
|
|
4716
4967
|
}
|
|
4717
4968
|
async function refreshSession(resource, session, discovery, fetch2, signal) {
|
|
4718
4969
|
signal?.throwIfAborted();
|
|
4719
4970
|
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
return inFlight;
|
|
4971
|
+
if (session.tokens?.refreshToken === void 0) {
|
|
4972
|
+
return session;
|
|
4723
4973
|
}
|
|
4724
|
-
const
|
|
4974
|
+
const pendingSession = { ...clearSessionTokens(session), refreshState: "pending" };
|
|
4975
|
+
await saveSession(resource, pendingSession);
|
|
4976
|
+
signal?.throwIfAborted();
|
|
4977
|
+
let refreshAttempted = false;
|
|
4978
|
+
let refreshedTokens;
|
|
4979
|
+
while (true) {
|
|
4725
4980
|
try {
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
return null;
|
|
4755
|
-
}
|
|
4756
|
-
if (!refreshAttempted && isRetryableOAuthError(error)) {
|
|
4757
|
-
refreshAttempted = true;
|
|
4758
|
-
continue;
|
|
4759
|
-
}
|
|
4760
|
-
throw error;
|
|
4761
|
-
}
|
|
4981
|
+
refreshedTokens = await refreshAccessToken({
|
|
4982
|
+
tokenEndpoint: requireOwnString(discovery.authorizationServerMetadata, "token_endpoint", "Authorization server metadata"),
|
|
4983
|
+
clientId: session.client.clientId,
|
|
4984
|
+
clientSecret: session.client.clientSecret,
|
|
4985
|
+
refreshToken: session.tokens.refreshToken,
|
|
4986
|
+
resource,
|
|
4987
|
+
fetch: fetch2,
|
|
4988
|
+
signal,
|
|
4989
|
+
now
|
|
4990
|
+
});
|
|
4991
|
+
break;
|
|
4992
|
+
} catch (error) {
|
|
4993
|
+
signal?.throwIfAborted();
|
|
4994
|
+
if (!(error instanceof OAuthError) || !error.outcomeKnown)
|
|
4995
|
+
throw error;
|
|
4996
|
+
if (error.error === "invalid_grant") {
|
|
4997
|
+
const clearedSession = clearSessionTokens(session);
|
|
4998
|
+
await saveSession(resource, clearedSession);
|
|
4999
|
+
return clearedSession;
|
|
5000
|
+
}
|
|
5001
|
+
if (shouldReRegisterStoredDynamicClient(error, await loadRegisteredClient(discovery.authorizationServer), false)) {
|
|
5002
|
+
await clearRegisteredClient(discovery.authorizationServer);
|
|
5003
|
+
await clearSession(resource);
|
|
5004
|
+
return null;
|
|
5005
|
+
}
|
|
5006
|
+
if (!refreshAttempted && isRetryableOAuthError(error)) {
|
|
5007
|
+
refreshAttempted = true;
|
|
5008
|
+
continue;
|
|
4762
5009
|
}
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
tokens: {
|
|
4766
|
-
...refreshedTokens,
|
|
4767
|
-
refreshToken: refreshedTokens.refreshToken ?? session.tokens.refreshToken
|
|
4768
|
-
},
|
|
4769
|
-
discovery: toStoredDiscovery(discovery)
|
|
4770
|
-
};
|
|
4771
|
-
await saveSession(resource, updatedSession);
|
|
4772
|
-
return updatedSession;
|
|
4773
|
-
} finally {
|
|
4774
|
-
refreshPromises.delete(resource);
|
|
5010
|
+
await saveSession(resource, session);
|
|
5011
|
+
throw error;
|
|
4775
5012
|
}
|
|
4776
|
-
}
|
|
4777
|
-
|
|
4778
|
-
|
|
5013
|
+
}
|
|
5014
|
+
const updatedSession = {
|
|
5015
|
+
...session,
|
|
5016
|
+
tokens: {
|
|
5017
|
+
...refreshedTokens,
|
|
5018
|
+
refreshToken: refreshedTokens.refreshToken ?? session.tokens.refreshToken
|
|
5019
|
+
},
|
|
5020
|
+
discovery: toStoredDiscovery(discovery)
|
|
5021
|
+
};
|
|
5022
|
+
await saveSession(resource, updatedSession);
|
|
5023
|
+
return updatedSession;
|
|
4779
5024
|
}
|
|
4780
5025
|
async function authorizeSession(resource, existingSession, discovery, fetch2, signal) {
|
|
4781
5026
|
signal?.throwIfAborted();
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
5027
|
+
assertS256PkceSupport(discovery.authorizationServerMetadata);
|
|
5028
|
+
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
5029
|
+
let currentSession = existingSession;
|
|
5030
|
+
let transientRetryAttempted = false;
|
|
5031
|
+
let reRegistrationAttempted = false;
|
|
5032
|
+
while (true) {
|
|
5033
|
+
const loopback = await createLoopbackAuthorizationSession({
|
|
5034
|
+
openBrowser: options.browser.openBrowser,
|
|
5035
|
+
readLine: options.browser.readLine,
|
|
5036
|
+
createServer: options.browser.createServer,
|
|
5037
|
+
landingPage: options.browser.landingPage,
|
|
5038
|
+
redirectUri: options.browser.redirectUri,
|
|
5039
|
+
signal: options.browser.signal === void 0 ? signal : signal === void 0 ? options.browser.signal : AbortSignal.any([signal, options.browser.signal]),
|
|
5040
|
+
timeoutMs: options.browser.timeoutMs
|
|
5041
|
+
});
|
|
5042
|
+
let resolvedClient = null;
|
|
5043
|
+
try {
|
|
5044
|
+
resolvedClient = await resolveClient(currentSession, discovery, loopback.redirectUri, fetch2, signal);
|
|
5045
|
+
const sessionWithoutTokens = {
|
|
5046
|
+
resource,
|
|
5047
|
+
authorizationServer: discovery.authorizationServer,
|
|
5048
|
+
client: resolvedClient.client,
|
|
5049
|
+
discovery: toStoredDiscovery(discovery)
|
|
5050
|
+
};
|
|
5051
|
+
await saveSession(resource, sessionWithoutTokens);
|
|
5052
|
+
const verifier = generateCodeVerifier();
|
|
5053
|
+
const challenge = generateCodeChallenge(verifier);
|
|
5054
|
+
const authorizationUrl = buildAuthorizationUrl({
|
|
5055
|
+
metadata: discovery.authorizationServerMetadata,
|
|
5056
|
+
resource,
|
|
5057
|
+
clientId: resolvedClient.client.clientId,
|
|
5058
|
+
redirectUri: loopback.redirectUri,
|
|
5059
|
+
codeChallenge: challenge,
|
|
5060
|
+
clientMetadata: getClientMetadata(options.client)
|
|
4801
5061
|
});
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
const session = {
|
|
4836
|
-
...sessionWithoutTokens,
|
|
4837
|
-
tokens
|
|
4838
|
-
};
|
|
4839
|
-
await saveSession(resource, session);
|
|
4840
|
-
return session;
|
|
4841
|
-
} catch (error) {
|
|
4842
|
-
signal?.throwIfAborted();
|
|
4843
|
-
if (shouldReRegisterStoredDynamicClient(error, resolvedClient, reRegistrationAttempted)) {
|
|
4844
|
-
reRegistrationAttempted = true;
|
|
4845
|
-
await clearRegisteredClient(discovery.authorizationServer);
|
|
4846
|
-
await clearSession(resource);
|
|
4847
|
-
currentSession = null;
|
|
4848
|
-
continue;
|
|
4849
|
-
}
|
|
4850
|
-
if (!transientRetryAttempted && isRetryableOAuthError(error)) {
|
|
4851
|
-
transientRetryAttempted = true;
|
|
4852
|
-
await clearSession(resource);
|
|
4853
|
-
currentSession = null;
|
|
4854
|
-
continue;
|
|
4855
|
-
}
|
|
4856
|
-
throw error;
|
|
4857
|
-
} finally {
|
|
4858
|
-
loopback.close();
|
|
5062
|
+
const code = await loopback.waitForCode(authorizationUrl);
|
|
5063
|
+
const tokens = await exchangeAuthorizationCode({
|
|
5064
|
+
tokenEndpoint: requireOwnString(discovery.authorizationServerMetadata, "token_endpoint", "Authorization server metadata"),
|
|
5065
|
+
clientId: resolvedClient.client.clientId,
|
|
5066
|
+
clientSecret: resolvedClient.client.clientSecret,
|
|
5067
|
+
code,
|
|
5068
|
+
codeVerifier: verifier,
|
|
5069
|
+
redirectUri: loopback.redirectUri,
|
|
5070
|
+
resource,
|
|
5071
|
+
fetch: fetch2,
|
|
5072
|
+
signal,
|
|
5073
|
+
now
|
|
5074
|
+
});
|
|
5075
|
+
const session = {
|
|
5076
|
+
...sessionWithoutTokens,
|
|
5077
|
+
tokens
|
|
5078
|
+
};
|
|
5079
|
+
await saveSession(resource, session);
|
|
5080
|
+
return session;
|
|
5081
|
+
} catch (error) {
|
|
5082
|
+
signal?.throwIfAborted();
|
|
5083
|
+
if (shouldReRegisterStoredDynamicClient(error, resolvedClient, reRegistrationAttempted)) {
|
|
5084
|
+
reRegistrationAttempted = true;
|
|
5085
|
+
await clearRegisteredClient(discovery.authorizationServer);
|
|
5086
|
+
await clearSession(resource);
|
|
5087
|
+
currentSession = null;
|
|
5088
|
+
continue;
|
|
5089
|
+
}
|
|
5090
|
+
if (!transientRetryAttempted && isRetryableOAuthError(error)) {
|
|
5091
|
+
transientRetryAttempted = true;
|
|
5092
|
+
await clearSession(resource);
|
|
5093
|
+
currentSession = null;
|
|
5094
|
+
continue;
|
|
4859
5095
|
}
|
|
5096
|
+
throw error;
|
|
5097
|
+
} finally {
|
|
5098
|
+
loopback.close();
|
|
4860
5099
|
}
|
|
4861
|
-
}
|
|
4862
|
-
const finalPromise = promise.finally(() => {
|
|
4863
|
-
authorizationPromises.delete(resource);
|
|
4864
|
-
});
|
|
4865
|
-
authorizationPromises.set(resource, finalPromise);
|
|
4866
|
-
return finalPromise;
|
|
5100
|
+
}
|
|
4867
5101
|
}
|
|
4868
5102
|
async function resolveClient(existingSession, discovery, redirectUri, fetch2, parentSignal) {
|
|
4869
5103
|
parentSignal?.throwIfAborted();
|
|
@@ -5014,9 +5248,13 @@ function resolveDiscovery(discovery, session) {
|
|
|
5014
5248
|
authorizationServerMetadata: metadata
|
|
5015
5249
|
};
|
|
5016
5250
|
}
|
|
5251
|
+
function sameTokenGrant(left, right) {
|
|
5252
|
+
return left.accessToken === right.accessToken && left.refreshToken === right.refreshToken && left.tokenType === right.tokenType && left.expiresAt === right.expiresAt && left.scope === right.scope;
|
|
5253
|
+
}
|
|
5017
5254
|
function clearSessionTokens(session) {
|
|
5018
5255
|
const nextSession = { ...session };
|
|
5019
5256
|
delete nextSession.tokens;
|
|
5257
|
+
delete nextSession.refreshState;
|
|
5020
5258
|
return nextSession;
|
|
5021
5259
|
}
|
|
5022
5260
|
function hasCachedAccessToken(session) {
|
|
@@ -5026,6 +5264,9 @@ function normalizeLoadedSession(session) {
|
|
|
5026
5264
|
if (session === null) {
|
|
5027
5265
|
return null;
|
|
5028
5266
|
}
|
|
5267
|
+
const refreshState = getOwnEntry6(session, "refreshState");
|
|
5268
|
+
if (refreshState !== void 0 && (refreshState !== "pending" || getOwnEntry6(session, "tokens") !== void 0))
|
|
5269
|
+
throw new Error("Stored OAuth refresh state is invalid");
|
|
5029
5270
|
const client = normalizeStoredClient(getOwnEntry6(session, "client"));
|
|
5030
5271
|
if (client === null) {
|
|
5031
5272
|
return { ...session, client: { clientId: "" }, tokens: void 0 };
|
|
@@ -5298,7 +5539,7 @@ function getParameterHeaders(schema) {
|
|
|
5298
5539
|
const names = /* @__PURE__ */ new Set();
|
|
5299
5540
|
const ancestors = /* @__PURE__ */ new Set();
|
|
5300
5541
|
let nodes = 0;
|
|
5301
|
-
const visit = (value,
|
|
5542
|
+
const visit = (value, path5, reachable, depth) => {
|
|
5302
5543
|
if (++nodes > 1e4 || depth > 64)
|
|
5303
5544
|
throw new Error("MCP header schema traversal limit exceeded");
|
|
5304
5545
|
if (typeof value === "boolean")
|
|
@@ -5309,7 +5550,7 @@ function getParameterHeaders(schema) {
|
|
|
5309
5550
|
try {
|
|
5310
5551
|
if (Object.prototype.hasOwnProperty.call(value, "x-mcp-header")) {
|
|
5311
5552
|
const name = value["x-mcp-header"];
|
|
5312
|
-
if (!reachable ||
|
|
5553
|
+
if (!reachable || path5.length === 0 || typeof name !== "string" || name.length === 0 || [...name].some((character) => {
|
|
5313
5554
|
const code = character.charCodeAt(0);
|
|
5314
5555
|
return !tokenPunctuation.has(character) && !(code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122);
|
|
5315
5556
|
}))
|
|
@@ -5320,25 +5561,25 @@ function getParameterHeaders(schema) {
|
|
|
5320
5561
|
if (names.has(key2))
|
|
5321
5562
|
throw new Error("Duplicate x-mcp-header name");
|
|
5322
5563
|
names.add(key2);
|
|
5323
|
-
headers.push({ name: `Mcp-Param-${name}`, path: [...
|
|
5564
|
+
headers.push({ name: `Mcp-Param-${name}`, path: [...path5], type: value.type });
|
|
5324
5565
|
}
|
|
5325
5566
|
for (const [keyword, child] of Object.entries(value)) {
|
|
5326
5567
|
if (schemaMaps.has(keyword)) {
|
|
5327
5568
|
if (!isRecord3(child))
|
|
5328
5569
|
throw new Error("Invalid schema map");
|
|
5329
5570
|
for (const [key2, nested] of Object.entries(child))
|
|
5330
|
-
visit(nested, keyword === "properties" ? [...
|
|
5571
|
+
visit(nested, keyword === "properties" ? [...path5, key2] : path5, reachable && keyword === "properties", depth + 1);
|
|
5331
5572
|
} else if (schemaArrays.has(keyword)) {
|
|
5332
5573
|
if (!Array.isArray(child))
|
|
5333
5574
|
throw new Error("Invalid schema array");
|
|
5334
5575
|
for (const nested of child)
|
|
5335
|
-
visit(nested,
|
|
5576
|
+
visit(nested, path5, false, depth + 1);
|
|
5336
5577
|
} else if (schemaChildren.has(keyword)) {
|
|
5337
5578
|
if (Array.isArray(child))
|
|
5338
5579
|
for (const nested of child)
|
|
5339
|
-
visit(nested,
|
|
5580
|
+
visit(nested, path5, false, depth + 1);
|
|
5340
5581
|
else
|
|
5341
|
-
visit(child,
|
|
5582
|
+
visit(child, path5, false, depth + 1);
|
|
5342
5583
|
}
|
|
5343
5584
|
}
|
|
5344
5585
|
} finally {
|
|
@@ -5536,8 +5777,8 @@ function authorizationServerMetadataLocations(issuer) {
|
|
|
5536
5777
|
];
|
|
5537
5778
|
const issuerUrl = new URL(issuer);
|
|
5538
5779
|
if (issuerUrl.pathname !== "/") {
|
|
5539
|
-
const
|
|
5540
|
-
issuerUrl.pathname = `${
|
|
5780
|
+
const path5 = issuerUrl.pathname.endsWith("/") ? issuerUrl.pathname.slice(0, -1) : issuerUrl.pathname;
|
|
5781
|
+
issuerUrl.pathname = `${path5}/.well-known/openid-configuration`;
|
|
5541
5782
|
locations.push(issuerUrl.toString());
|
|
5542
5783
|
}
|
|
5543
5784
|
return locations;
|
|
@@ -6789,6 +7030,7 @@ var HttpTransport = class {
|
|
|
6789
7030
|
oauthMetadataDiscovery;
|
|
6790
7031
|
inFlightFetchAbortControllers = /* @__PURE__ */ new Set();
|
|
6791
7032
|
inFlightOAuthAbortControllers = /* @__PURE__ */ new Set();
|
|
7033
|
+
oauthRequestTokens = /* @__PURE__ */ new WeakMap();
|
|
6792
7034
|
openResponseReaders = /* @__PURE__ */ new Set();
|
|
6793
7035
|
modernRequests = /* @__PURE__ */ new Map();
|
|
6794
7036
|
modernMode = false;
|
|
@@ -7059,7 +7301,7 @@ var HttpTransport = class {
|
|
|
7059
7301
|
}
|
|
7060
7302
|
async authorizeRequestHeaders(headers, signal) {
|
|
7061
7303
|
signal?.throwIfAborted();
|
|
7062
|
-
await this.oauthProvider?.authorizeRequest?.({
|
|
7304
|
+
const tokens = await this.oauthProvider?.authorizeRequest?.({
|
|
7063
7305
|
requestUrl: new URL(this.url),
|
|
7064
7306
|
headers,
|
|
7065
7307
|
signal,
|
|
@@ -7068,6 +7310,7 @@ var HttpTransport = class {
|
|
|
7068
7310
|
signal: signal === void 0 ? init?.signal : init?.signal == null ? signal : AbortSignal.any([signal, init.signal])
|
|
7069
7311
|
})
|
|
7070
7312
|
});
|
|
7313
|
+
if (tokens !== void 0) this.oauthRequestTokens.set(headers, { ...tokens });
|
|
7071
7314
|
signal?.throwIfAborted();
|
|
7072
7315
|
return headers;
|
|
7073
7316
|
}
|
|
@@ -7211,7 +7454,7 @@ var HttpTransport = class {
|
|
|
7211
7454
|
const message = responseBody.length === 0 ? `HTTP transport POST failed (${statusDescriptor})` : `HTTP transport POST failed (${statusDescriptor}): ${responseBody}`;
|
|
7212
7455
|
throw new HttpTransportError(message, response.status, "POST");
|
|
7213
7456
|
}
|
|
7214
|
-
async maybeHandleUnauthorizedResponse(response, signal) {
|
|
7457
|
+
async maybeHandleUnauthorizedResponse(response, signal, requestHeaders, presentedTokens) {
|
|
7215
7458
|
if (response.status !== 401 || this.oauthProvider === void 0) {
|
|
7216
7459
|
return false;
|
|
7217
7460
|
}
|
|
@@ -7232,6 +7475,8 @@ var HttpTransport = class {
|
|
|
7232
7475
|
challenge,
|
|
7233
7476
|
discovery,
|
|
7234
7477
|
signal,
|
|
7478
|
+
requestHeaders: new Headers(requestHeaders),
|
|
7479
|
+
presentedTokens,
|
|
7235
7480
|
fetch: (url, init) => fetchMcpResponse(this.fetchImpl, url, {
|
|
7236
7481
|
...init,
|
|
7237
7482
|
signal: init?.signal == null ? signal : AbortSignal.any([signal, init.signal])
|
|
@@ -7372,16 +7617,20 @@ var HttpTransport = class {
|
|
|
7372
7617
|
const request = async () => {
|
|
7373
7618
|
controller.signal.throwIfAborted();
|
|
7374
7619
|
const headers = await input.createHeaders(controller.signal);
|
|
7620
|
+
const headerSnapshot = new Headers(headers);
|
|
7621
|
+
const tokens = this.oauthRequestTokens.get(headers) ?? null;
|
|
7375
7622
|
controller.signal.throwIfAborted();
|
|
7376
|
-
|
|
7623
|
+
const response = await this.fetchWithAbort(input.url ?? this.url, {
|
|
7377
7624
|
method: input.method,
|
|
7378
7625
|
headers,
|
|
7379
7626
|
body: input.body
|
|
7380
7627
|
}, controller);
|
|
7628
|
+
return { response, headers: headerSnapshot, tokens };
|
|
7381
7629
|
};
|
|
7382
7630
|
try {
|
|
7383
|
-
let
|
|
7384
|
-
if (await this.maybeHandleUnauthorizedResponse(response, controller.signal))
|
|
7631
|
+
let attempt = await request();
|
|
7632
|
+
if (await this.maybeHandleUnauthorizedResponse(attempt.response, controller.signal, attempt.headers, attempt.tokens)) attempt = await request();
|
|
7633
|
+
const response = attempt.response;
|
|
7385
7634
|
const oauthError = this.oauthProvider === void 0 ? null : this.readOAuthChallengeError(response);
|
|
7386
7635
|
if (oauthError !== null) {
|
|
7387
7636
|
void response.body?.cancel().catch(() => void 0);
|