@fruggr/zendesk-mcp-server 3.7.0 → 3.8.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/README.md +31 -21
- package/dist/THIRD-PARTY-NOTICES.md +5 -5
- package/dist/{article-sections-CzTODYsS.js → article-sections-DA7_Jm2H.js} +65 -34
- package/dist/{http-D-Xy9BWD.js → http-DuRcQrOc.js} +2809 -388
- package/dist/index.js +1555 -985
- package/dist/sbom.cdx.json +19 -19
- package/dist/{token-store-BqwB-30K.js → token-store-EwRwZiJO.js} +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -7911,6 +7911,11 @@ const ConfigSchema = object({
|
|
|
7911
7911
|
oauthMasterSecretFile: string().min(1).optional(),
|
|
7912
7912
|
/** HTTP only: the grant store URI; defaults to a file in the config dir. */
|
|
7913
7913
|
oauthStore: string().url().optional(),
|
|
7914
|
+
/**
|
|
7915
|
+
* HTTP only: where the admins' instructions, prompts and skills live
|
|
7916
|
+
* (`file://<dir>` or `memory://`); defaults to a folder in the config dir.
|
|
7917
|
+
*/
|
|
7918
|
+
customizationStore: string().url().optional(),
|
|
7914
7919
|
/** HTTP only: CIMD client ids added to the consent-skip allowlist. */
|
|
7915
7920
|
oauthTrustedClients: array(string().url()).default([]),
|
|
7916
7921
|
/** HTTP only: whether the built-in allowlist (claude.ai, ChatGPT) applies. */
|
|
@@ -8014,6 +8019,7 @@ const CLI_OPTIONS = {
|
|
|
8014
8019
|
"callback-port": { type: "string" },
|
|
8015
8020
|
"oauth-master-secret-file": { type: "string" },
|
|
8016
8021
|
"oauth-store": { type: "string" },
|
|
8022
|
+
"customization-store": { type: "string" },
|
|
8017
8023
|
"oauth-trusted-client": {
|
|
8018
8024
|
type: "string",
|
|
8019
8025
|
multiple: true
|
|
@@ -8045,6 +8051,7 @@ const FIELD_BY_FLAG = /* @__PURE__ */ new Map([
|
|
|
8045
8051
|
["cors-origin", "corsOrigins"],
|
|
8046
8052
|
["oauth-master-secret-file", "oauthMasterSecretFile"],
|
|
8047
8053
|
["oauth-store", "oauthStore"],
|
|
8054
|
+
["customization-store", "customizationStore"],
|
|
8048
8055
|
["oauth-trusted-client", "oauthTrustedClients"],
|
|
8049
8056
|
["sla-reply-thresholds", "slaReplyThresholds"],
|
|
8050
8057
|
["sla-wait-thresholds", "slaWaitThresholds"],
|
|
@@ -8112,6 +8119,7 @@ const resolveOAuthServerSettings = (cli) => ({
|
|
|
8112
8119
|
oauthMasterSecret: requireNonEmptyEnv("OAUTH_MASTER_SECRET"),
|
|
8113
8120
|
oauthMasterSecretFile: cli.oauthMasterSecretFile ?? requireNonEmptyEnv("OAUTH_MASTER_SECRET_FILE"),
|
|
8114
8121
|
oauthStore: cli.oauthStore ?? requireNonEmptyEnv("OAUTH_STORE"),
|
|
8122
|
+
customizationStore: cli.customizationStore ?? requireNonEmptyEnv("CUSTOMIZATION_STORE"),
|
|
8115
8123
|
oauthTrustedClients: [...cli.oauthTrustedClients ?? [], ...splitList(readEnv("OAUTH_TRUSTED_CLIENTS").value)],
|
|
8116
8124
|
defaultTrustedClients: cli.defaultTrustedClients
|
|
8117
8125
|
});
|
|
@@ -8383,7 +8391,7 @@ const buildHelpCenterInstructions = (config) => {
|
|
|
8383
8391
|
].join("\n");
|
|
8384
8392
|
};
|
|
8385
8393
|
//#endregion
|
|
8386
|
-
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.
|
|
8394
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/chunk-vYduTEsO.mjs
|
|
8387
8395
|
var __create = Object.create;
|
|
8388
8396
|
var __defProp = Object.defineProperty;
|
|
8389
8397
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -8415,7 +8423,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
8415
8423
|
enumerable: true
|
|
8416
8424
|
}) : target, mod));
|
|
8417
8425
|
//#endregion
|
|
8418
|
-
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.
|
|
8426
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/dialects-CDpMbily.mjs
|
|
8419
8427
|
/**
|
|
8420
8428
|
* Canonical `$schema` URIs per supported dialect (http + https variants, trailing-`#` stripped).
|
|
8421
8429
|
*/
|
|
@@ -9875,6 +9883,8 @@ const ServerResultSchema = union([
|
|
|
9875
9883
|
ListToolsResultSchema,
|
|
9876
9884
|
SubscriptionsListenResultSchema
|
|
9877
9885
|
]);
|
|
9886
|
+
//#endregion
|
|
9887
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+core@2.4.0/node_modules/@modelcontextprotocol/core/dist/auth-UMQCo-ad.mjs
|
|
9878
9888
|
/**
|
|
9879
9889
|
* Reusable URL validation that disallows `javascript:` scheme
|
|
9880
9890
|
*/
|
|
@@ -10078,7 +10088,7 @@ const OAuthTokenRevocationRequestSchema = object({
|
|
|
10078
10088
|
token_type_hint: string().optional()
|
|
10079
10089
|
}).strip();
|
|
10080
10090
|
//#endregion
|
|
10081
|
-
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.
|
|
10091
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/src-DdvbAHrR.mjs
|
|
10082
10092
|
/**
|
|
10083
10093
|
* Cross-bundle `instanceof` support for the SDK error classes.
|
|
10084
10094
|
*
|
|
@@ -14457,25 +14467,22 @@ const X_MCP_HEADER_KEY = "x-mcp-header";
|
|
|
14457
14467
|
*/
|
|
14458
14468
|
const RFC9110_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
14459
14469
|
/**
|
|
14460
|
-
* JSON Schema `type` values the spec admits on an `x-mcp-header` property
|
|
14461
|
-
*
|
|
14462
|
-
*
|
|
14463
|
-
* `number
|
|
14464
|
-
* `
|
|
14465
|
-
* parameters and expects the client to mirror them, so `number` is accepted
|
|
14466
|
-
* here so that the conformance gate passes; the discrepancy is tracked
|
|
14467
|
-
* upstream. Everything else (`object`, `array`, `null`, absent) is rejected.
|
|
14470
|
+
* JSON Schema `type` values the spec admits on an `x-mcp-header` property:
|
|
14471
|
+
* `integer`, `string` and `boolean`. `number` is explicitly not permitted
|
|
14472
|
+
* (2026-07-28 Streamable HTTP, "Schema Extension"), so a tool that annotates a
|
|
14473
|
+
* `number`-typed property is invalid (the server still checks its headers).
|
|
14474
|
+
* Everything else (`object`, `array`, `null`, absent) is rejected too.
|
|
14468
14475
|
*/
|
|
14469
14476
|
const PERMITTED_X_MCP_HEADER_TYPES = /* @__PURE__ */ new Set([
|
|
14470
14477
|
"string",
|
|
14471
14478
|
"integer",
|
|
14472
|
-
"boolean"
|
|
14473
|
-
"number"
|
|
14479
|
+
"boolean"
|
|
14474
14480
|
]);
|
|
14475
14481
|
/**
|
|
14476
14482
|
* Scan a tool's JSON-serialized `inputSchema` for `x-mcp-header` declarations
|
|
14477
14483
|
* and validate every constraint the spec places on them. Returns either the
|
|
14478
|
-
* collected declarations (possibly empty) or the first violated constraint
|
|
14484
|
+
* collected declarations (possibly empty) or the first violated constraint
|
|
14485
|
+
* (with the declarations too, when `number`-typed declarations are the only fault).
|
|
14479
14486
|
*
|
|
14480
14487
|
* The walk descends through `properties` at any depth (the spec's "any nesting
|
|
14481
14488
|
* depth" clause). The static-reachability MUST is enforced as a structural
|
|
@@ -14488,6 +14495,7 @@ const PERMITTED_X_MCP_HEADER_TYPES = /* @__PURE__ */ new Set([
|
|
|
14488
14495
|
function scanXMcpHeaderDeclarations(inputSchema) {
|
|
14489
14496
|
const declarations = [];
|
|
14490
14497
|
const seenLower = /* @__PURE__ */ new Map();
|
|
14498
|
+
let numberFault;
|
|
14491
14499
|
const visit = (node, path, reachable) => {
|
|
14492
14500
|
if (node === null || typeof node !== "object") return void 0;
|
|
14493
14501
|
const schema = node;
|
|
@@ -14497,7 +14505,11 @@ function scanXMcpHeaderDeclarations(inputSchema) {
|
|
|
14497
14505
|
if (typeof raw !== "string" || raw.length === 0) return `${pathName(path)}: x-mcp-header MUST be a non-empty string`;
|
|
14498
14506
|
if (!RFC9110_TOKEN.test(raw)) return `${pathName(path)}: x-mcp-header '${raw}' is not a valid RFC 9110 token (no spaces, control characters or HTTP delimiters)`;
|
|
14499
14507
|
const type = typeof schema.type === "string" ? schema.type : void 0;
|
|
14500
|
-
if (type === void 0 || !PERMITTED_X_MCP_HEADER_TYPES.has(type))
|
|
14508
|
+
if (type === void 0 || !PERMITTED_X_MCP_HEADER_TYPES.has(type)) {
|
|
14509
|
+
const fault$1 = `${pathName(path)}: x-mcp-header is only permitted on primitive-typed properties (string, integer, boolean); got ${type ?? "<none>"}`;
|
|
14510
|
+
if (type !== "number") return fault$1;
|
|
14511
|
+
numberFault ??= fault$1;
|
|
14512
|
+
}
|
|
14501
14513
|
const lower = raw.toLowerCase();
|
|
14502
14514
|
const prior = seenLower.get(lower);
|
|
14503
14515
|
if (prior !== void 0) return `x-mcp-header '${raw}' is not case-insensitively unique (also declared as '${prior}')`;
|
|
@@ -14524,12 +14536,17 @@ function scanXMcpHeaderDeclarations(inputSchema) {
|
|
|
14524
14536
|
}
|
|
14525
14537
|
};
|
|
14526
14538
|
const fault = visit(inputSchema, [], true);
|
|
14527
|
-
|
|
14539
|
+
if (fault !== void 0) return {
|
|
14540
|
+
valid: false,
|
|
14541
|
+
reason: numberFault ?? fault
|
|
14542
|
+
};
|
|
14543
|
+
return numberFault === void 0 ? {
|
|
14528
14544
|
valid: true,
|
|
14529
14545
|
declarations
|
|
14530
14546
|
} : {
|
|
14531
14547
|
valid: false,
|
|
14532
|
-
reason:
|
|
14548
|
+
reason: numberFault,
|
|
14549
|
+
declarations
|
|
14533
14550
|
};
|
|
14534
14551
|
}
|
|
14535
14552
|
/**
|
|
@@ -14632,7 +14649,7 @@ function valueAtPath(root, path) {
|
|
|
14632
14649
|
* A sentinel-carrying header whose payload is not canonical Base64 / valid
|
|
14633
14650
|
* UTF-8 is rejected as invalid characters.
|
|
14634
14651
|
*
|
|
14635
|
-
* Integer-typed declarations are compared numerically (the spec's SHOULD —
|
|
14652
|
+
* Integer- and number-typed declarations are compared numerically (the spec's SHOULD —
|
|
14636
14653
|
* `42.0` and `42` are equal); everything else is compared as decoded strings.
|
|
14637
14654
|
*
|
|
14638
14655
|
* Returns `undefined` when every check passes, or an
|
|
@@ -15202,22 +15219,26 @@ function standardSchemaToJsonSchema(schema, io = "input") {
|
|
|
15202
15219
|
...result
|
|
15203
15220
|
};
|
|
15204
15221
|
}
|
|
15222
|
+
const LOCAL_DEFINITION_REF = /^#\/(\$defs|definitions)\/([^/~%]+)$/;
|
|
15205
15223
|
/**
|
|
15206
15224
|
* A typeless JSON Schema root is "provably object-shaped" when either it carries object keywords
|
|
15207
15225
|
* directly (`properties`/`patternProperties`/`additionalProperties`/`required`), or it is a
|
|
15208
15226
|
* composition (`oneOf`/`anyOf`/`allOf`) whose every member is itself `type:'object'` or recursively
|
|
15209
|
-
* provably object-shaped (e.g. a nested `discriminatedUnion`). `$ref` is
|
|
15227
|
+
* provably object-shaped (e.g. a nested `discriminatedUnion`). A `$ref` is followed one hop, to an
|
|
15228
|
+
* entry of the root's `$defs`/`definitions` that is itself `type:'object'`. Used to
|
|
15210
15229
|
* decide whether stamping `type:'object'` is safe (redundant-but-valid) versus self-contradictory.
|
|
15211
15230
|
*/
|
|
15212
|
-
function isProvablyObjectShapedRoot(schema) {
|
|
15231
|
+
function isProvablyObjectShapedRoot(schema, root = schema) {
|
|
15213
15232
|
if ("properties" in schema || "patternProperties" in schema || "additionalProperties" in schema || "required" in schema) return true;
|
|
15233
|
+
const ref = typeof schema.$ref === "string" && LOCAL_DEFINITION_REF.exec(schema.$ref);
|
|
15234
|
+
if (ref && root[ref[1]]?.[ref[2]]?.type === "object") return true;
|
|
15214
15235
|
for (const key of [
|
|
15215
15236
|
"oneOf",
|
|
15216
15237
|
"anyOf",
|
|
15217
15238
|
"allOf"
|
|
15218
15239
|
]) {
|
|
15219
15240
|
const members = schema[key];
|
|
15220
|
-
if (Array.isArray(members) && members.length > 0) return members.every((m) => m !== null && typeof m === "object" && (m.type === "object" || isProvablyObjectShapedRoot(m)));
|
|
15241
|
+
if (Array.isArray(members) && members.length > 0) return members.every((m) => m !== null && typeof m === "object" && (m.type === "object" || isProvablyObjectShapedRoot(m, "$id" in m ? {} : root)));
|
|
15221
15242
|
}
|
|
15222
15243
|
return false;
|
|
15223
15244
|
}
|
|
@@ -17187,7 +17208,7 @@ function normalizeRawShapeSchema(schema) {
|
|
|
17187
17208
|
return schema;
|
|
17188
17209
|
}
|
|
17189
17210
|
//#endregion
|
|
17190
|
-
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.
|
|
17211
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/ajvProvider-DyjnscPj.mjs
|
|
17191
17212
|
var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
17192
17213
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17193
17214
|
exports.regexpCode = exports.getEsmExportName = exports.getProperty = exports.safeStringify = exports.stringify = exports.strConcat = exports.addCodeArg = exports.str = exports._ = exports.nil = exports._Code = exports.Name = exports.IDENTIFIER = exports._CodeOrName = void 0;
|
|
@@ -19865,6 +19886,28 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
19865
19886
|
const isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
19866
19887
|
/** @type {(value: string) => boolean} */
|
|
19867
19888
|
const isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
19889
|
+
/** @type {(value: string) => boolean} */
|
|
19890
|
+
const isPort = RegExp.prototype.test.bind(/^\d*$/u);
|
|
19891
|
+
/** @type {(value: string) => boolean} */
|
|
19892
|
+
const isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
19893
|
+
/** @type {(value: string) => boolean} */
|
|
19894
|
+
const isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
19895
|
+
/** @type {(value: string) => boolean} */
|
|
19896
|
+
const isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
19897
|
+
/** @type {(value: string) => boolean} */
|
|
19898
|
+
const isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
19899
|
+
/** @type {(value: string) => boolean} */
|
|
19900
|
+
const isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
19901
|
+
const BYTE_HEX = new Array(256);
|
|
19902
|
+
{
|
|
19903
|
+
const HEX_DIGITS = "0123456789ABCDEF";
|
|
19904
|
+
for (let i = 0; i < 256; i++) BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
|
|
19905
|
+
}
|
|
19906
|
+
function percentEncodeNonAscii(cp) {
|
|
19907
|
+
if (cp < 2048) return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
|
|
19908
|
+
if (cp < 65536) return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
19909
|
+
return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
19910
|
+
}
|
|
19868
19911
|
/**
|
|
19869
19912
|
* @param {Array<string>} input
|
|
19870
19913
|
* @returns {string}
|
|
@@ -19887,119 +19930,162 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
19887
19930
|
}
|
|
19888
19931
|
return acc;
|
|
19889
19932
|
}
|
|
19890
|
-
/**
|
|
19891
|
-
|
|
19892
|
-
|
|
19893
|
-
|
|
19894
|
-
|
|
19895
|
-
|
|
19933
|
+
/** @type {(value: string) => boolean} */
|
|
19934
|
+
const isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
19935
|
+
/** @type {(value: string) => boolean} */
|
|
19936
|
+
const isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
19937
|
+
/** @type {(value: string) => boolean} */
|
|
19938
|
+
const isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
19896
19939
|
/**
|
|
19897
19940
|
* @param {string} value
|
|
19898
19941
|
* @returns {boolean}
|
|
19899
19942
|
*/
|
|
19900
19943
|
const nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
19901
19944
|
/**
|
|
19902
|
-
* @param {
|
|
19945
|
+
* @param {string} zone
|
|
19903
19946
|
* @returns {boolean}
|
|
19904
19947
|
*/
|
|
19905
|
-
function
|
|
19906
|
-
|
|
19948
|
+
function isZoneIdentifier(zone) {
|
|
19949
|
+
if (zone.length === 0) return false;
|
|
19950
|
+
for (let i = 0; i < zone.length; i++) {
|
|
19951
|
+
if (isZoneCharacter(zone[i])) continue;
|
|
19952
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
19953
|
+
i += 2;
|
|
19954
|
+
continue;
|
|
19955
|
+
}
|
|
19956
|
+
return false;
|
|
19957
|
+
}
|
|
19907
19958
|
return true;
|
|
19908
19959
|
}
|
|
19909
19960
|
/**
|
|
19910
|
-
*
|
|
19911
|
-
*
|
|
19912
|
-
*
|
|
19913
|
-
* @
|
|
19961
|
+
* Compresses the longest run of zero hextets to "::" per RFC 5952. A run of a
|
|
19962
|
+
* single zero hextet is left uncompressed. On ties the leftmost run wins.
|
|
19963
|
+
*
|
|
19964
|
+
* @param {string[]} hextets
|
|
19965
|
+
* @returns {string}
|
|
19914
19966
|
*/
|
|
19915
|
-
function
|
|
19916
|
-
|
|
19917
|
-
|
|
19918
|
-
|
|
19919
|
-
|
|
19920
|
-
|
|
19921
|
-
|
|
19967
|
+
function compressIPv6ZeroRun(hextets) {
|
|
19968
|
+
let bestStart = -1;
|
|
19969
|
+
let bestLength = 0;
|
|
19970
|
+
let runStart = -1;
|
|
19971
|
+
let runLength = 0;
|
|
19972
|
+
for (let i = 0; i < hextets.length; i++) if (hextets[i] === "0") {
|
|
19973
|
+
if (runStart === -1) runStart = i;
|
|
19974
|
+
runLength++;
|
|
19975
|
+
if (runLength > bestLength) {
|
|
19976
|
+
bestLength = runLength;
|
|
19977
|
+
bestStart = runStart;
|
|
19922
19978
|
}
|
|
19923
|
-
|
|
19979
|
+
} else {
|
|
19980
|
+
runStart = -1;
|
|
19981
|
+
runLength = 0;
|
|
19924
19982
|
}
|
|
19925
|
-
return
|
|
19983
|
+
if (bestLength < 2) return hextets.join(":");
|
|
19984
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
19985
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
19986
|
+
return head + "::" + tail;
|
|
19926
19987
|
}
|
|
19927
19988
|
/**
|
|
19989
|
+
* Validates an IPv6 address against the alternatives in RFC 3986 section
|
|
19990
|
+
* 3.2.2 and returns the same address with leading hextet zeroes removed.
|
|
19991
|
+
* An embedded IPv4 address counts as two hextets and is only valid at the end.
|
|
19992
|
+
*
|
|
19928
19993
|
* @param {string} input
|
|
19929
|
-
* @returns {
|
|
19930
|
-
*/
|
|
19931
|
-
function
|
|
19932
|
-
|
|
19933
|
-
|
|
19934
|
-
|
|
19935
|
-
|
|
19936
|
-
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19940
|
-
|
|
19941
|
-
|
|
19942
|
-
let
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
if (cursor === ":") {
|
|
19949
|
-
if (endipv6Encountered === true) endIpv6 = true;
|
|
19950
|
-
if (!consume(buffer, address, output)) break;
|
|
19951
|
-
if (++tokenCount > 7) {
|
|
19952
|
-
output.error = true;
|
|
19953
|
-
break;
|
|
19954
|
-
}
|
|
19955
|
-
if (i > 0 && input[i - 1] === ":") endipv6Encountered = true;
|
|
19956
|
-
address.push(":");
|
|
19957
|
-
continue;
|
|
19958
|
-
} else if (cursor === "%") {
|
|
19959
|
-
if (!consume(buffer, address, output)) break;
|
|
19960
|
-
consume = consumeIsZone;
|
|
19961
|
-
} else {
|
|
19962
|
-
buffer.push(cursor);
|
|
19994
|
+
* @returns {string|undefined}
|
|
19995
|
+
*/
|
|
19996
|
+
function normalizeIPv6Address(input) {
|
|
19997
|
+
const compression = input.indexOf("::");
|
|
19998
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
|
|
19999
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
20000
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
20001
|
+
if (compression !== -1) {
|
|
20002
|
+
if (left.length === 1 && left[0] === "") left.length = 0;
|
|
20003
|
+
if (right.length === 1 && right[0] === "") right.length = 0;
|
|
20004
|
+
}
|
|
20005
|
+
const parts = left.concat(right);
|
|
20006
|
+
let hextetCount = 0;
|
|
20007
|
+
for (let i = 0; i < parts.length; i++) {
|
|
20008
|
+
const part = parts[i];
|
|
20009
|
+
if (part === "") return void 0;
|
|
20010
|
+
if (part.indexOf(".") !== -1) {
|
|
20011
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
|
|
20012
|
+
hextetCount += 2;
|
|
19963
20013
|
continue;
|
|
19964
20014
|
}
|
|
20015
|
+
if (!isHextet(part)) return void 0;
|
|
20016
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
20017
|
+
hextetCount++;
|
|
19965
20018
|
}
|
|
19966
|
-
if (
|
|
19967
|
-
|
|
19968
|
-
|
|
19969
|
-
|
|
19970
|
-
return
|
|
20019
|
+
if (compression === -1) {
|
|
20020
|
+
if (hextetCount !== 8) return void 0;
|
|
20021
|
+
return compressIPv6ZeroRun(parts);
|
|
20022
|
+
}
|
|
20023
|
+
if (hextetCount >= 8) return void 0;
|
|
20024
|
+
const expanded = parts.slice(0, left.length);
|
|
20025
|
+
for (let i = hextetCount; i < 8; i++) expanded.push("0");
|
|
20026
|
+
for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]);
|
|
20027
|
+
return compressIPv6ZeroRun(expanded);
|
|
19971
20028
|
}
|
|
19972
20029
|
/**
|
|
19973
20030
|
* @typedef {Object} NormalizeIPv6Result
|
|
19974
20031
|
* @property {string} host - The normalized host.
|
|
19975
20032
|
* @property {string} [escapedHost] - The escaped host.
|
|
19976
20033
|
* @property {boolean} isIPV6 - Indicates if the host is an IPv6 address.
|
|
20034
|
+
* @property {boolean} [isIPVFuture] - Indicates if the host is an IPvFuture literal.
|
|
20035
|
+
* @property {boolean} [error] - Indicates if a bracketed IP literal is malformed.
|
|
19977
20036
|
*/
|
|
19978
20037
|
/**
|
|
20038
|
+
* Validates and normalizes a bracketed IP literal. Raw zone separators remain
|
|
20039
|
+
* accepted for backwards compatibility, while encoded separators and zone
|
|
20040
|
+
* contents follow RFC 6874.
|
|
20041
|
+
*
|
|
19979
20042
|
* @param {string} host
|
|
19980
20043
|
* @returns {NormalizeIPv6Result}
|
|
19981
20044
|
*/
|
|
19982
20045
|
function normalizeIPv6(host) {
|
|
19983
|
-
|
|
20046
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
20047
|
+
if ((host[0] === "[" || host[host.length - 1] === "]") && !bracketed) return {
|
|
19984
20048
|
host,
|
|
19985
|
-
isIPV6: false
|
|
20049
|
+
isIPV6: false,
|
|
20050
|
+
error: true
|
|
19986
20051
|
};
|
|
19987
|
-
|
|
19988
|
-
if (
|
|
19989
|
-
|
|
19990
|
-
let escapedHost = ipv6.address;
|
|
19991
|
-
if (ipv6.zone) {
|
|
19992
|
-
newHost += "%" + ipv6.zone;
|
|
19993
|
-
escapedHost += "%25" + ipv6.zone;
|
|
19994
|
-
}
|
|
20052
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
20053
|
+
if (bracketed && isIPvFuture(input)) {
|
|
20054
|
+
input = input.toLowerCase();
|
|
19995
20055
|
return {
|
|
19996
|
-
host:
|
|
19997
|
-
|
|
19998
|
-
|
|
20056
|
+
host: `[${input}]`,
|
|
20057
|
+
escapedHost: input,
|
|
20058
|
+
isIPV6: false,
|
|
20059
|
+
isIPVFuture: true
|
|
20060
|
+
};
|
|
20061
|
+
}
|
|
20062
|
+
if (findToken(input, ":") < 2) return {
|
|
20063
|
+
host,
|
|
20064
|
+
isIPV6: false,
|
|
20065
|
+
error: bracketed
|
|
20066
|
+
};
|
|
20067
|
+
let zoneIdentifier = "";
|
|
20068
|
+
const zoneSeparator = input.indexOf("%");
|
|
20069
|
+
if (zoneSeparator !== -1) {
|
|
20070
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
20071
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
20072
|
+
if (!isZoneIdentifier(zoneIdentifier)) return {
|
|
20073
|
+
host,
|
|
20074
|
+
isIPV6: false,
|
|
20075
|
+
error: true
|
|
19999
20076
|
};
|
|
20000
|
-
|
|
20077
|
+
input = input.slice(0, zoneSeparator);
|
|
20078
|
+
}
|
|
20079
|
+
const address = normalizeIPv6Address(input);
|
|
20080
|
+
if (address === void 0) return {
|
|
20001
20081
|
host,
|
|
20002
|
-
isIPV6: false
|
|
20082
|
+
isIPV6: false,
|
|
20083
|
+
error: true
|
|
20084
|
+
};
|
|
20085
|
+
return {
|
|
20086
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
20087
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
20088
|
+
isIPV6: true
|
|
20003
20089
|
};
|
|
20004
20090
|
}
|
|
20005
20091
|
/**
|
|
@@ -20087,19 +20173,264 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20087
20173
|
return output.join("");
|
|
20088
20174
|
}
|
|
20089
20175
|
/**
|
|
20090
|
-
*
|
|
20091
|
-
*
|
|
20092
|
-
*
|
|
20176
|
+
* Re-escape RFC 3986 gen-delims that must not appear literally in the host.
|
|
20177
|
+
* After the URI regex parses, these characters cannot be literal in the host
|
|
20178
|
+
* field, so any that appear after decoding came from percent-encoding and
|
|
20179
|
+
* must be restored to prevent authority structure changes.
|
|
20180
|
+
*
|
|
20181
|
+
* @param {string} host
|
|
20182
|
+
* @param {boolean} isIP - true for IPv4/IPv6 hosts (skip colon re-escaping)
|
|
20183
|
+
* @returns {string}
|
|
20093
20184
|
*/
|
|
20094
|
-
|
|
20095
|
-
|
|
20096
|
-
|
|
20097
|
-
|
|
20098
|
-
|
|
20099
|
-
|
|
20100
|
-
|
|
20101
|
-
|
|
20102
|
-
|
|
20185
|
+
const HOST_DELIMS = {
|
|
20186
|
+
"@": "%40",
|
|
20187
|
+
"/": "%2F",
|
|
20188
|
+
"?": "%3F",
|
|
20189
|
+
"#": "%23",
|
|
20190
|
+
":": "%3A"
|
|
20191
|
+
};
|
|
20192
|
+
const HOST_DELIM_RE = /[@/?#:]/g;
|
|
20193
|
+
const HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
20194
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
20195
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
20196
|
+
re.lastIndex = 0;
|
|
20197
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
20198
|
+
}
|
|
20199
|
+
/**
|
|
20200
|
+
* Normalizes percent escapes and optionally decodes only unreserved ASCII bytes.
|
|
20201
|
+
* Reserved delimiters such as `%2F` stay escaped; `%2E` is unreserved.
|
|
20202
|
+
*
|
|
20203
|
+
* @param {string} input
|
|
20204
|
+
* @param {boolean} [decodeUnreserved=false]
|
|
20205
|
+
* @returns {string}
|
|
20206
|
+
*/
|
|
20207
|
+
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
20208
|
+
if (input.indexOf("%") === -1) return input;
|
|
20209
|
+
let output = "";
|
|
20210
|
+
for (let i = 0; i < input.length; i++) {
|
|
20211
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
20212
|
+
const hex = input.slice(i + 1, i + 3);
|
|
20213
|
+
if (isHexPair(hex)) {
|
|
20214
|
+
const normalizedHex = hex.toUpperCase();
|
|
20215
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
20216
|
+
if (decodeUnreserved && isUnreserved(decoded)) output += decoded;
|
|
20217
|
+
else output += "%" + normalizedHex;
|
|
20218
|
+
i += 2;
|
|
20219
|
+
continue;
|
|
20220
|
+
}
|
|
20221
|
+
}
|
|
20222
|
+
output += input[i];
|
|
20223
|
+
}
|
|
20224
|
+
return output;
|
|
20225
|
+
}
|
|
20226
|
+
/**
|
|
20227
|
+
* Normalizes path data without turning reserved escapes into live path syntax.
|
|
20228
|
+
* Valid escapes are uppercased, raw unsafe characters are escaped, and only
|
|
20229
|
+
* unreserved bytes that are not `.` are decoded.
|
|
20230
|
+
*
|
|
20231
|
+
* @param {string} input
|
|
20232
|
+
* @returns {string}
|
|
20233
|
+
*/
|
|
20234
|
+
function normalizePathEncoding(input) {
|
|
20235
|
+
let output = "";
|
|
20236
|
+
for (let i = 0; i < input.length; i++) {
|
|
20237
|
+
const ch = input[i];
|
|
20238
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
20239
|
+
const hex = input.slice(i + 1, i + 3);
|
|
20240
|
+
if (isHexPair(hex)) {
|
|
20241
|
+
const normalizedHex = hex.toUpperCase();
|
|
20242
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
20243
|
+
if (decoded !== "." && isUnreserved(decoded)) output += decoded;
|
|
20244
|
+
else output += "%" + normalizedHex;
|
|
20245
|
+
i += 2;
|
|
20246
|
+
continue;
|
|
20247
|
+
}
|
|
20248
|
+
}
|
|
20249
|
+
if (isPathCharacter(ch)) output += ch;
|
|
20250
|
+
else {
|
|
20251
|
+
const code = input.charCodeAt(i);
|
|
20252
|
+
if (code < 128) output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
20253
|
+
else if (code < 55296 || code > 57343) output += percentEncodeNonAscii(code);
|
|
20254
|
+
else if (code <= 56319 && i + 1 < input.length) {
|
|
20255
|
+
const low = input.charCodeAt(i + 1);
|
|
20256
|
+
if (low >= 56320 && low <= 57343) {
|
|
20257
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
20258
|
+
i++;
|
|
20259
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20260
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20261
|
+
}
|
|
20262
|
+
}
|
|
20263
|
+
return output;
|
|
20264
|
+
}
|
|
20265
|
+
/**
|
|
20266
|
+
* Serializes a path without rewriting reserved data. Raw RFC 3986 path
|
|
20267
|
+
* characters remain literal, valid escapes are preserved and uppercased, and
|
|
20268
|
+
* everything else is UTF-8 percent-encoded. In a path-noscheme, a colon in the
|
|
20269
|
+
* first segment must be escaped so the result cannot be parsed as a scheme.
|
|
20270
|
+
*
|
|
20271
|
+
* @param {string} input
|
|
20272
|
+
* @param {boolean} [pathNoScheme=false]
|
|
20273
|
+
* @returns {string}
|
|
20274
|
+
*/
|
|
20275
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
20276
|
+
let output = "";
|
|
20277
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
20278
|
+
for (let i = 0; i < input.length; i++) {
|
|
20279
|
+
const ch = input[i];
|
|
20280
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
20281
|
+
const hex = input.slice(i + 1, i + 3);
|
|
20282
|
+
if (isHexPair(hex)) {
|
|
20283
|
+
output += "%" + hex.toUpperCase();
|
|
20284
|
+
i += 2;
|
|
20285
|
+
continue;
|
|
20286
|
+
}
|
|
20287
|
+
}
|
|
20288
|
+
if (ch === "/") firstSegment = false;
|
|
20289
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) output += ch;
|
|
20290
|
+
else {
|
|
20291
|
+
const code = input.charCodeAt(i);
|
|
20292
|
+
if (code < 128) output += BYTE_HEX[code];
|
|
20293
|
+
else if (code < 55296 || code > 57343) output += percentEncodeNonAscii(code);
|
|
20294
|
+
else if (code <= 56319 && i + 1 < input.length) {
|
|
20295
|
+
const low = input.charCodeAt(i + 1);
|
|
20296
|
+
if (low >= 56320 && low <= 57343) {
|
|
20297
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
20298
|
+
i++;
|
|
20299
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20300
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20301
|
+
}
|
|
20302
|
+
}
|
|
20303
|
+
return output;
|
|
20304
|
+
}
|
|
20305
|
+
/**
|
|
20306
|
+
* Percent-encodes a URI component using its RFC 3986 literal character set.
|
|
20307
|
+
* Existing valid escapes are preserved and normalized to uppercase hex.
|
|
20308
|
+
*
|
|
20309
|
+
* @param {string} input
|
|
20310
|
+
* @param {(value: string) => boolean} isAllowed
|
|
20311
|
+
* @returns {string}
|
|
20312
|
+
*/
|
|
20313
|
+
function encodeComponent(input, isAllowed) {
|
|
20314
|
+
let output = "";
|
|
20315
|
+
for (let i = 0; i < input.length; i++) {
|
|
20316
|
+
const ch = input[i];
|
|
20317
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
20318
|
+
const hex = input.slice(i + 1, i + 3);
|
|
20319
|
+
if (isHexPair(hex)) {
|
|
20320
|
+
output += "%" + hex.toUpperCase();
|
|
20321
|
+
i += 2;
|
|
20322
|
+
continue;
|
|
20323
|
+
}
|
|
20324
|
+
}
|
|
20325
|
+
if (isAllowed(ch)) output += ch;
|
|
20326
|
+
else {
|
|
20327
|
+
const code = input.charCodeAt(i);
|
|
20328
|
+
if (code < 128) output += BYTE_HEX[code];
|
|
20329
|
+
else if (code < 55296 || code > 57343) output += percentEncodeNonAscii(code);
|
|
20330
|
+
else if (code <= 56319 && i + 1 < input.length) {
|
|
20331
|
+
const low = input.charCodeAt(i + 1);
|
|
20332
|
+
if (low >= 56320 && low <= 57343) {
|
|
20333
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
20334
|
+
i++;
|
|
20335
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20336
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20337
|
+
}
|
|
20338
|
+
}
|
|
20339
|
+
return output;
|
|
20340
|
+
}
|
|
20341
|
+
/**
|
|
20342
|
+
* Encodes userinfo while preserving its RFC 3986 §3.2.1 literal characters.
|
|
20343
|
+
* In particular, authority delimiters such as `@`, `/`, `?`, and `#` are data.
|
|
20344
|
+
*
|
|
20345
|
+
* @param {string} input
|
|
20346
|
+
* @returns {string}
|
|
20347
|
+
*/
|
|
20348
|
+
function encodeUserinfo(input) {
|
|
20349
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
20350
|
+
}
|
|
20351
|
+
/**
|
|
20352
|
+
* Encodes query data using the RFC 3986 §3.4 grammar. A literal `#` must be
|
|
20353
|
+
* escaped because it would otherwise begin the fragment component.
|
|
20354
|
+
*
|
|
20355
|
+
* @param {string} input
|
|
20356
|
+
* @returns {string}
|
|
20357
|
+
*/
|
|
20358
|
+
function encodeQuery(input) {
|
|
20359
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
20360
|
+
}
|
|
20361
|
+
/**
|
|
20362
|
+
* Encodes fragment data using the RFC 3986 §3.5 grammar.
|
|
20363
|
+
*
|
|
20364
|
+
* @param {string} input
|
|
20365
|
+
* @returns {string}
|
|
20366
|
+
*/
|
|
20367
|
+
function encodeFragment(input) {
|
|
20368
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
20369
|
+
}
|
|
20370
|
+
function isEscapeSafe(cp) {
|
|
20371
|
+
return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
|
|
20372
|
+
}
|
|
20373
|
+
/**
|
|
20374
|
+
* Normalizes the percent-encoding of a query or fragment component.
|
|
20375
|
+
*
|
|
20376
|
+
* Like `normalizePathEncoding`, but uses the query/fragment character set
|
|
20377
|
+
* (which additionally allows `?`) and decodes `.` since it has no dot-segment
|
|
20378
|
+
* meaning outside of a path.
|
|
20379
|
+
*
|
|
20380
|
+
* @param {string} input
|
|
20381
|
+
* @returns {string}
|
|
20382
|
+
*/
|
|
20383
|
+
function normalizeQueryFragmentEncoding(input) {
|
|
20384
|
+
let output = "";
|
|
20385
|
+
for (let i = 0; i < input.length; i++) {
|
|
20386
|
+
const ch = input[i];
|
|
20387
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
20388
|
+
const hex = input.slice(i + 1, i + 3);
|
|
20389
|
+
if (isHexPair(hex)) {
|
|
20390
|
+
const normalizedHex = hex.toUpperCase();
|
|
20391
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
20392
|
+
if (isUnreserved(decoded)) output += decoded;
|
|
20393
|
+
else output += "%" + normalizedHex;
|
|
20394
|
+
i += 2;
|
|
20395
|
+
continue;
|
|
20396
|
+
}
|
|
20397
|
+
}
|
|
20398
|
+
if (isQueryFragmentCharacter(ch)) output += ch;
|
|
20399
|
+
else {
|
|
20400
|
+
const code = input.charCodeAt(i);
|
|
20401
|
+
if (code < 128) output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
20402
|
+
else if (code < 55296 || code > 57343) output += percentEncodeNonAscii(code);
|
|
20403
|
+
else if (code <= 56319 && i + 1 < input.length) {
|
|
20404
|
+
const low = input.charCodeAt(i + 1);
|
|
20405
|
+
if (low >= 56320 && low <= 57343) {
|
|
20406
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
20407
|
+
i++;
|
|
20408
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20409
|
+
} else output += percentEncodeNonAscii(65533);
|
|
20410
|
+
}
|
|
20411
|
+
}
|
|
20412
|
+
return output;
|
|
20413
|
+
}
|
|
20414
|
+
/**
|
|
20415
|
+
* Escapes a component while preserving existing valid percent escapes.
|
|
20416
|
+
*
|
|
20417
|
+
* @param {string} input
|
|
20418
|
+
* @returns {string}
|
|
20419
|
+
*/
|
|
20420
|
+
function escapePreservingEscapes(input) {
|
|
20421
|
+
let output = "";
|
|
20422
|
+
for (let i = 0; i < input.length; i++) {
|
|
20423
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
20424
|
+
const hex = input.slice(i + 1, i + 3);
|
|
20425
|
+
if (isHexPair(hex)) {
|
|
20426
|
+
output += "%" + hex.toUpperCase();
|
|
20427
|
+
i += 2;
|
|
20428
|
+
continue;
|
|
20429
|
+
}
|
|
20430
|
+
}
|
|
20431
|
+
output += escape(input[i]);
|
|
20432
|
+
}
|
|
20433
|
+
return output;
|
|
20103
20434
|
}
|
|
20104
20435
|
/**
|
|
20105
20436
|
* @param {import('../types/index').URIComponent} component
|
|
@@ -20108,28 +20439,42 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20108
20439
|
function recomposeAuthority(component) {
|
|
20109
20440
|
const uriTokens = [];
|
|
20110
20441
|
if (component.userinfo !== void 0) {
|
|
20111
|
-
uriTokens.push(component.userinfo);
|
|
20442
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
20112
20443
|
uriTokens.push("@");
|
|
20113
20444
|
}
|
|
20114
20445
|
if (component.host !== void 0) {
|
|
20115
|
-
let host =
|
|
20446
|
+
let host = component.host;
|
|
20116
20447
|
if (!isIPv4(host)) {
|
|
20117
|
-
|
|
20118
|
-
if (ipV6res.isIPV6
|
|
20119
|
-
|
|
20448
|
+
let ipV6res = normalizeIPv6(host);
|
|
20449
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
20450
|
+
host = normalizePercentEncoding(host, true);
|
|
20451
|
+
ipV6res = normalizeIPv6(host);
|
|
20452
|
+
}
|
|
20453
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) host = `[${ipV6res.escapedHost}]`;
|
|
20454
|
+
else host = reescapeHostDelimiters(host, false);
|
|
20120
20455
|
}
|
|
20121
20456
|
uriTokens.push(host);
|
|
20122
20457
|
}
|
|
20123
20458
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
20459
|
+
const port = String(component.port);
|
|
20460
|
+
if (!isPort(port)) throw new TypeError("URI port is malformed.");
|
|
20124
20461
|
uriTokens.push(":");
|
|
20125
|
-
uriTokens.push(
|
|
20462
|
+
uriTokens.push(port);
|
|
20126
20463
|
}
|
|
20127
20464
|
return uriTokens.length ? uriTokens.join("") : void 0;
|
|
20128
20465
|
}
|
|
20129
20466
|
module.exports = {
|
|
20130
20467
|
nonSimpleDomain,
|
|
20131
20468
|
recomposeAuthority,
|
|
20132
|
-
|
|
20469
|
+
reescapeHostDelimiters,
|
|
20470
|
+
normalizePercentEncoding,
|
|
20471
|
+
normalizePathEncoding,
|
|
20472
|
+
serializePathEncoding,
|
|
20473
|
+
normalizeQueryFragmentEncoding,
|
|
20474
|
+
encodeUserinfo,
|
|
20475
|
+
encodeQuery,
|
|
20476
|
+
encodeFragment,
|
|
20477
|
+
escapePreservingEscapes,
|
|
20133
20478
|
removeDotSegments,
|
|
20134
20479
|
isIPv4,
|
|
20135
20480
|
isUUID,
|
|
@@ -20139,7 +20484,7 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20139
20484
|
}));
|
|
20140
20485
|
var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
20141
20486
|
const { isUUID } = require_utils();
|
|
20142
|
-
const URN_REG =
|
|
20487
|
+
const URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
20143
20488
|
const supportedSchemeNames = [
|
|
20144
20489
|
"http",
|
|
20145
20490
|
"https",
|
|
@@ -20210,9 +20555,10 @@ var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20210
20555
|
wsComponent.secure = void 0;
|
|
20211
20556
|
}
|
|
20212
20557
|
if (wsComponent.resourceName) {
|
|
20213
|
-
const
|
|
20558
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
20559
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
20214
20560
|
wsComponent.path = path && path !== "/" ? path : void 0;
|
|
20215
|
-
wsComponent.query =
|
|
20561
|
+
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
20216
20562
|
wsComponent.resourceName = void 0;
|
|
20217
20563
|
}
|
|
20218
20564
|
wsComponent.fragment = void 0;
|
|
@@ -20225,7 +20571,7 @@ var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20225
20571
|
return urnComponent;
|
|
20226
20572
|
}
|
|
20227
20573
|
const matches = urnComponent.path.match(URN_REG);
|
|
20228
|
-
if (matches) {
|
|
20574
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
20229
20575
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
20230
20576
|
urnComponent.nid = matches[1].toLowerCase();
|
|
20231
20577
|
urnComponent.nss = matches[2];
|
|
@@ -20319,8 +20665,19 @@ var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20319
20665
|
};
|
|
20320
20666
|
}));
|
|
20321
20667
|
var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
20322
|
-
const { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
20668
|
+
const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
20323
20669
|
const { SCHEMES, getSchemeHandler } = require_schemes();
|
|
20670
|
+
const VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
20671
|
+
const MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
20672
|
+
/**
|
|
20673
|
+
* @param {string} scheme
|
|
20674
|
+
* @returns {string}
|
|
20675
|
+
*/
|
|
20676
|
+
function decodeValidScheme(scheme) {
|
|
20677
|
+
const decodedScheme = unescape(String(scheme));
|
|
20678
|
+
if (!VALID_SCHEME.test(decodedScheme)) throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
20679
|
+
return decodedScheme;
|
|
20680
|
+
}
|
|
20324
20681
|
/**
|
|
20325
20682
|
* @template {import('./types/index').URIComponent|string} T
|
|
20326
20683
|
* @param {T} uri
|
|
@@ -20328,7 +20685,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20328
20685
|
* @returns {T}
|
|
20329
20686
|
*/
|
|
20330
20687
|
function normalize(uri, options) {
|
|
20331
|
-
if (typeof uri === "string") uri =
|
|
20688
|
+
if (typeof uri === "string") uri = normalizeString(uri, options);
|
|
20332
20689
|
else if (typeof uri === "object") uri = parse(serialize(uri, options), options);
|
|
20333
20690
|
return uri;
|
|
20334
20691
|
}
|
|
@@ -20340,7 +20697,16 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20340
20697
|
*/
|
|
20341
20698
|
function resolve(baseURI, relativeURI, options) {
|
|
20342
20699
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
20343
|
-
const
|
|
20700
|
+
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed, malformedPercentEncoding: baseMalformedPercentEncoding, malformedSchemeSpecific: baseMalformedSchemeSpecific, malformedHost: baseMalformedHost, malformedScheme: baseMalformedScheme } = parseWithStatus(baseURI, schemelessOptions);
|
|
20701
|
+
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed, malformedPercentEncoding: relativeMalformedPercentEncoding, malformedSchemeSpecific: relativeMalformedSchemeSpecific, malformedHost: relativeMalformedHost, malformedScheme: relativeMalformedScheme } = parseWithStatus(relativeURI, schemelessOptions);
|
|
20702
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
20703
|
+
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
20704
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
20705
|
+
const resolvedHost = resolved.host;
|
|
20706
|
+
const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
20707
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
20708
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
|
|
20709
|
+
if (resolved.error && !encodedASCIIHost) throw new Error(resolved.error);
|
|
20344
20710
|
schemelessOptions.skipEscape = true;
|
|
20345
20711
|
return serialize(resolved, schemelessOptions);
|
|
20346
20712
|
}
|
|
@@ -20404,27 +20770,9 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20404
20770
|
* @returns {boolean}
|
|
20405
20771
|
*/
|
|
20406
20772
|
function equal(uriA, uriB, options) {
|
|
20407
|
-
|
|
20408
|
-
|
|
20409
|
-
|
|
20410
|
-
...options,
|
|
20411
|
-
skipEscape: true
|
|
20412
|
-
});
|
|
20413
|
-
} else if (typeof uriA === "object") uriA = serialize(normalizeComponentEncoding(uriA, true), {
|
|
20414
|
-
...options,
|
|
20415
|
-
skipEscape: true
|
|
20416
|
-
});
|
|
20417
|
-
if (typeof uriB === "string") {
|
|
20418
|
-
uriB = unescape(uriB);
|
|
20419
|
-
uriB = serialize(normalizeComponentEncoding(parse(uriB, options), true), {
|
|
20420
|
-
...options,
|
|
20421
|
-
skipEscape: true
|
|
20422
|
-
});
|
|
20423
|
-
} else if (typeof uriB === "object") uriB = serialize(normalizeComponentEncoding(uriB, true), {
|
|
20424
|
-
...options,
|
|
20425
|
-
skipEscape: true
|
|
20426
|
-
});
|
|
20427
|
-
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
20773
|
+
const normalizedA = normalizeComparableURI(uriA, options);
|
|
20774
|
+
const normalizedB = normalizeComparableURI(uriB, options);
|
|
20775
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
|
|
20428
20776
|
}
|
|
20429
20777
|
/**
|
|
20430
20778
|
* @param {Readonly<import('./types/index').URIComponent>} cmpts
|
|
@@ -20450,13 +20798,17 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20450
20798
|
};
|
|
20451
20799
|
const options = Object.assign({}, opts);
|
|
20452
20800
|
const uriTokens = [];
|
|
20801
|
+
if (component.scheme) component.scheme = decodeValidScheme(component.scheme);
|
|
20453
20802
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
20454
20803
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
20455
|
-
|
|
20456
|
-
|
|
20457
|
-
|
|
20458
|
-
|
|
20459
|
-
if (options.reference !== "suffix" && component.scheme)
|
|
20804
|
+
const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
|
|
20805
|
+
const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
|
|
20806
|
+
if (component.path !== void 0) if (!options.skipEscape) component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
20807
|
+
else component.path = normalizePercentEncoding(component.path);
|
|
20808
|
+
if (options.reference !== "suffix" && component.scheme) {
|
|
20809
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
20810
|
+
uriTokens.push(component.scheme, ":");
|
|
20811
|
+
}
|
|
20460
20812
|
const authority = recomposeAuthority(component);
|
|
20461
20813
|
if (authority !== void 0) {
|
|
20462
20814
|
if (options.reference !== "suffix") uriTokens.push("//");
|
|
@@ -20466,20 +20818,84 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20466
20818
|
if (component.path !== void 0) {
|
|
20467
20819
|
let s = component.path;
|
|
20468
20820
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) s = removeDotSegments(s);
|
|
20821
|
+
if (pathNoScheme) s = serializePathEncoding(s, true);
|
|
20469
20822
|
if (authority === void 0 && s[0] === "/" && s[1] === "/") s = "/%2F" + s.slice(2);
|
|
20470
20823
|
uriTokens.push(s);
|
|
20471
20824
|
}
|
|
20472
|
-
if (component.query !== void 0) uriTokens.push("?", component.query);
|
|
20473
|
-
if (component.fragment !== void 0) uriTokens.push("#", component.fragment);
|
|
20825
|
+
if (component.query !== void 0) uriTokens.push("?", encodeQuery(component.query));
|
|
20826
|
+
if (component.fragment !== void 0) uriTokens.push("#", encodeFragment(component.fragment));
|
|
20474
20827
|
return uriTokens.join("");
|
|
20475
20828
|
}
|
|
20476
20829
|
const URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
20830
|
+
const AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
20831
|
+
const AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
|
|
20832
|
+
/**
|
|
20833
|
+
* @param {import('./types/index').URIComponent} parsed
|
|
20834
|
+
* @param {RegExpMatchArray} matches
|
|
20835
|
+
* @returns {string|undefined}
|
|
20836
|
+
*/
|
|
20837
|
+
function getParseError(parsed, matches) {
|
|
20838
|
+
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") return "URI path must start with \"/\" when authority is present.";
|
|
20839
|
+
if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) return "URI port is malformed.";
|
|
20840
|
+
}
|
|
20841
|
+
/**
|
|
20842
|
+
* Checks percent syntax without decoding the represented octets. RFC 3986
|
|
20843
|
+
* percent-encoding is byte-oriented, so sequences such as `%FF` are valid even
|
|
20844
|
+
* though they are not independently valid UTF-8.
|
|
20845
|
+
*
|
|
20846
|
+
* @param {string|undefined} component
|
|
20847
|
+
* @returns {boolean}
|
|
20848
|
+
*/
|
|
20849
|
+
function hasMalformedPercentEncoding(component) {
|
|
20850
|
+
if (component === void 0) return false;
|
|
20851
|
+
let percent = component.indexOf("%");
|
|
20852
|
+
while (percent !== -1) {
|
|
20853
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) return true;
|
|
20854
|
+
percent = component.indexOf("%", percent + 3);
|
|
20855
|
+
}
|
|
20856
|
+
return false;
|
|
20857
|
+
}
|
|
20858
|
+
/**
|
|
20859
|
+
* Whether the host is a bracketed IP literal (RFC 3986 `IP-literal`).
|
|
20860
|
+
* An unterminated `[` is not a literal, so it must still be validated as a
|
|
20861
|
+
* reg-name instead of being waved through as an IP.
|
|
20862
|
+
*
|
|
20863
|
+
* @param {string} host
|
|
20864
|
+
* @returns {boolean}
|
|
20865
|
+
*/
|
|
20866
|
+
function isIPLiteral(host) {
|
|
20867
|
+
return host[0] === "[" && host[host.length - 1] === "]";
|
|
20868
|
+
}
|
|
20869
|
+
/**
|
|
20870
|
+
* @param {RegExpMatchArray} matches
|
|
20871
|
+
* @returns {boolean}
|
|
20872
|
+
*/
|
|
20873
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
20874
|
+
const host = matches[4];
|
|
20875
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
20876
|
+
}
|
|
20877
|
+
/**
|
|
20878
|
+
* @param {import('./types/index').URIComponent} parsed
|
|
20879
|
+
* @param {import('./types/index').Options} options
|
|
20880
|
+
* @param {{ domainHost?: boolean, unicodeSupport?: boolean }|undefined} schemeHandler
|
|
20881
|
+
* @param {boolean} isIP
|
|
20882
|
+
* @returns {boolean} whether host conversion failed
|
|
20883
|
+
*/
|
|
20884
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
20885
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) try {
|
|
20886
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
20887
|
+
} catch (e) {
|
|
20888
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
20889
|
+
return true;
|
|
20890
|
+
}
|
|
20891
|
+
return false;
|
|
20892
|
+
}
|
|
20477
20893
|
/**
|
|
20478
20894
|
* @param {string} uri
|
|
20479
20895
|
* @param {import('./types/index').Options} [opts]
|
|
20480
|
-
* @returns
|
|
20896
|
+
* @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
|
|
20481
20897
|
*/
|
|
20482
|
-
function
|
|
20898
|
+
function parseWithStatus(uri, opts) {
|
|
20483
20899
|
const options = Object.assign({}, opts);
|
|
20484
20900
|
/** @type {import('./types/index').URIComponent} */
|
|
20485
20901
|
const parsed = {
|
|
@@ -20491,9 +20907,34 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20491
20907
|
query: void 0,
|
|
20492
20908
|
fragment: void 0
|
|
20493
20909
|
};
|
|
20910
|
+
let malformedAuthorityOrPort = false;
|
|
20911
|
+
let malformedPercentEncoding = false;
|
|
20912
|
+
let malformedSchemeSpecific = false;
|
|
20913
|
+
let malformedHost = false;
|
|
20914
|
+
let malformedIPLiteral = false;
|
|
20915
|
+
let malformedScheme = false;
|
|
20494
20916
|
let isIP = false;
|
|
20495
20917
|
if (options.reference === "suffix") if (options.scheme) uri = options.scheme + ":" + uri;
|
|
20496
20918
|
else uri = "//" + uri;
|
|
20919
|
+
const authorityMatch = uri.match(AUTHORITY_PREFIX);
|
|
20920
|
+
if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
|
|
20921
|
+
parsed.error = "URI authority must not contain a literal backslash.";
|
|
20922
|
+
malformedAuthorityOrPort = true;
|
|
20923
|
+
}
|
|
20924
|
+
const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
|
|
20925
|
+
if (introducerMatch !== null) {
|
|
20926
|
+
const region = introducerMatch[1];
|
|
20927
|
+
const normalizedRegion = region.replace(/[\t\n\r]/g, "");
|
|
20928
|
+
if (normalizedRegion.length >= 2) {
|
|
20929
|
+
if (normalizedRegion.slice(0, 2) !== "//") {
|
|
20930
|
+
parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
|
|
20931
|
+
malformedAuthorityOrPort = true;
|
|
20932
|
+
} else if (region.length !== normalizedRegion.length) {
|
|
20933
|
+
parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
|
|
20934
|
+
malformedAuthorityOrPort = true;
|
|
20935
|
+
}
|
|
20936
|
+
}
|
|
20937
|
+
}
|
|
20497
20938
|
const matches = uri.match(URI_PARSE);
|
|
20498
20939
|
if (matches) {
|
|
20499
20940
|
parsed.scheme = matches[1];
|
|
@@ -20503,11 +20944,33 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20503
20944
|
parsed.path = matches[6] || "";
|
|
20504
20945
|
parsed.query = matches[7];
|
|
20505
20946
|
parsed.fragment = matches[8];
|
|
20947
|
+
if (parsed.scheme !== void 0) {
|
|
20948
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
20949
|
+
if (VALID_SCHEME.test(decodedScheme)) parsed.scheme = decodedScheme.toLowerCase();
|
|
20950
|
+
else {
|
|
20951
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
20952
|
+
malformedScheme = true;
|
|
20953
|
+
}
|
|
20954
|
+
}
|
|
20955
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
20956
|
+
if (malformedPercentEncoding) parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
20506
20957
|
if (isNaN(parsed.port)) parsed.port = matches[5];
|
|
20958
|
+
const parseError = getParseError(parsed, matches);
|
|
20959
|
+
if (parseError !== void 0) {
|
|
20960
|
+
parsed.error = parsed.error || parseError;
|
|
20961
|
+
malformedAuthorityOrPort = true;
|
|
20962
|
+
}
|
|
20507
20963
|
if (parsed.host) if (isIPv4(parsed.host) === false) {
|
|
20964
|
+
const bracketedIPLiteral = isIPLiteral(parsed.host);
|
|
20965
|
+
const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
|
|
20508
20966
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
20509
|
-
|
|
20510
|
-
|
|
20967
|
+
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
20968
|
+
malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
|
|
20969
|
+
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
20970
|
+
if (malformedIPLiteral) {
|
|
20971
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
20972
|
+
malformedAuthorityOrPort = true;
|
|
20973
|
+
}
|
|
20511
20974
|
} else isIP = true;
|
|
20512
20975
|
if (parsed.scheme === void 0 && parsed.userinfo === void 0 && parsed.host === void 0 && parsed.port === void 0 && parsed.query === void 0 && !parsed.path) parsed.reference = "same-document";
|
|
20513
20976
|
else if (parsed.scheme === void 0) parsed.reference = "relative";
|
|
@@ -20515,24 +20978,78 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20515
20978
|
else parsed.reference = "uri";
|
|
20516
20979
|
if (options.reference && options.reference !== "suffix" && options.reference !== parsed.reference) parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
20517
20980
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
20518
|
-
if (!
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
}
|
|
20981
|
+
if (!malformedIPLiteral) malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
20982
|
+
if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
|
|
20983
|
+
let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
20984
|
+
if (!isIP) host = normalizePercentEncoding(host.toLowerCase());
|
|
20985
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
20524
20986
|
}
|
|
20525
20987
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
20526
|
-
if (
|
|
20527
|
-
|
|
20528
|
-
|
|
20529
|
-
|
|
20530
|
-
|
|
20531
|
-
|
|
20988
|
+
if (parsed.path) parsed.path = normalizePathEncoding(parsed.path);
|
|
20989
|
+
if (parsed.query) parsed.query = normalizeQueryFragmentEncoding(parsed.query);
|
|
20990
|
+
if (parsed.fragment) parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
|
|
20991
|
+
}
|
|
20992
|
+
if (schemeHandler && schemeHandler.parse) {
|
|
20993
|
+
schemeHandler.parse(parsed, options);
|
|
20994
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) malformedSchemeSpecific = true;
|
|
20532
20995
|
}
|
|
20533
|
-
if (schemeHandler && schemeHandler.parse) schemeHandler.parse(parsed, options);
|
|
20534
20996
|
} else parsed.error = parsed.error || "URI can not be parsed.";
|
|
20535
|
-
return
|
|
20997
|
+
return {
|
|
20998
|
+
parsed,
|
|
20999
|
+
malformedAuthorityOrPort,
|
|
21000
|
+
malformedPercentEncoding,
|
|
21001
|
+
malformedSchemeSpecific,
|
|
21002
|
+
malformedHost,
|
|
21003
|
+
malformedScheme
|
|
21004
|
+
};
|
|
21005
|
+
}
|
|
21006
|
+
/**
|
|
21007
|
+
* @param {string} uri
|
|
21008
|
+
* @param {import('./types/index').Options} [opts]
|
|
21009
|
+
* @returns
|
|
21010
|
+
*/
|
|
21011
|
+
function parse(uri, opts) {
|
|
21012
|
+
return parseWithStatus(uri, opts).parsed;
|
|
21013
|
+
}
|
|
21014
|
+
/**
|
|
21015
|
+
* @param {string} uri
|
|
21016
|
+
* @param {import('./types/index').Options} [opts]
|
|
21017
|
+
* @returns {string}
|
|
21018
|
+
*/
|
|
21019
|
+
function normalizeString(uri, opts) {
|
|
21020
|
+
return normalizeStringWithStatus(uri, opts).normalized;
|
|
21021
|
+
}
|
|
21022
|
+
/**
|
|
21023
|
+
* @param {string} uri
|
|
21024
|
+
* @param {import('./types/index').Options} [opts]
|
|
21025
|
+
* @returns {{ normalized: string, malformedAuthorityOrPort: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
|
|
21026
|
+
*/
|
|
21027
|
+
function normalizeStringWithStatus(uri, opts) {
|
|
21028
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
21029
|
+
return {
|
|
21030
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
21031
|
+
malformedAuthorityOrPort,
|
|
21032
|
+
malformedPercentEncoding,
|
|
21033
|
+
malformedSchemeSpecific,
|
|
21034
|
+
malformedHost,
|
|
21035
|
+
malformedScheme
|
|
21036
|
+
};
|
|
21037
|
+
}
|
|
21038
|
+
/**
|
|
21039
|
+
* @param {import ('./types/index').URIComponent|string} uri
|
|
21040
|
+
* @param {import('./types/index').Options} [opts]
|
|
21041
|
+
* @returns {string|undefined}
|
|
21042
|
+
*/
|
|
21043
|
+
function normalizeComparableURI(uri, opts) {
|
|
21044
|
+
if (typeof uri !== "string" && typeof uri !== "object") return;
|
|
21045
|
+
let value;
|
|
21046
|
+
try {
|
|
21047
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
21048
|
+
} catch {
|
|
21049
|
+
return;
|
|
21050
|
+
}
|
|
21051
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
21052
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
|
|
20536
21053
|
}
|
|
20537
21054
|
const fastUri = {
|
|
20538
21055
|
SCHEMES,
|
|
@@ -24322,7 +24839,7 @@ var AjvJsonSchemaValidator = class {
|
|
|
24322
24839
|
};
|
|
24323
24840
|
import_ajv.Ajv;
|
|
24324
24841
|
//#endregion
|
|
24325
|
-
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.
|
|
24842
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/mcp-oHn3ureC.mjs
|
|
24326
24843
|
const COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
|
|
24327
24844
|
/**
|
|
24328
24845
|
* Checks if a schema is completable (has completion metadata).
|
|
@@ -24344,604 +24861,425 @@ function armSseKeepAlive(intervalMs, onTick) {
|
|
|
24344
24861
|
timer.unref?.();
|
|
24345
24862
|
return timer;
|
|
24346
24863
|
}
|
|
24864
|
+
let readClassification;
|
|
24347
24865
|
/**
|
|
24348
|
-
*
|
|
24866
|
+
* The per-request micro-transport: a real, connected `Transport` whose whole
|
|
24867
|
+
* lifetime is one HTTP exchange. See the module documentation for the
|
|
24868
|
+
* response shapes it produces.
|
|
24349
24869
|
*
|
|
24350
|
-
* `
|
|
24351
|
-
*
|
|
24352
|
-
* listeners never unsubscribe peers). A throwing listener does not stop
|
|
24353
|
-
* delivery to the others.
|
|
24870
|
+
* Connecting a `Server` binds the instance to the classified modern revision
|
|
24871
|
+
* when its `supportedProtocolVersions` lists it and the SDK implements it.
|
|
24354
24872
|
*/
|
|
24355
|
-
var
|
|
24356
|
-
|
|
24873
|
+
var PerRequestHTTPServerTransport = class {
|
|
24874
|
+
static {
|
|
24875
|
+
readClassification = (transport) => transport._classification;
|
|
24876
|
+
}
|
|
24877
|
+
onclose;
|
|
24878
|
+
onerror;
|
|
24879
|
+
onmessage;
|
|
24880
|
+
_classification;
|
|
24881
|
+
_responseMode;
|
|
24882
|
+
_started = false;
|
|
24883
|
+
_used = false;
|
|
24884
|
+
_closed = false;
|
|
24885
|
+
_terminalDelivered = false;
|
|
24357
24886
|
/**
|
|
24358
|
-
*
|
|
24359
|
-
*
|
|
24887
|
+
* `true` only while the inbound message is being delivered synchronously
|
|
24888
|
+
* to the connected protocol layer. The pre-handler gates (the era
|
|
24889
|
+
* registry gate, the edge→instance handoff check, the missing-handler
|
|
24890
|
+
* rejection) answer inside this window; request handlers always run
|
|
24891
|
+
* after it (the protocol layer defers them to a microtask). An error
|
|
24892
|
+
* sent inside the window is therefore ladder-originated, and an error
|
|
24893
|
+
* sent after it is handler-produced.
|
|
24360
24894
|
*/
|
|
24361
|
-
|
|
24362
|
-
|
|
24895
|
+
_dispatchWindowOpen = false;
|
|
24896
|
+
_requestId;
|
|
24897
|
+
_deferredResponse;
|
|
24898
|
+
_sse;
|
|
24899
|
+
_abortCleanup;
|
|
24900
|
+
_keepAliveMs;
|
|
24901
|
+
constructor(options) {
|
|
24902
|
+
this._classification = options.classification;
|
|
24903
|
+
this._responseMode = options.responseMode ?? "auto";
|
|
24904
|
+
this._keepAliveMs = options.keepAliveMs ?? 15e3;
|
|
24363
24905
|
}
|
|
24364
|
-
|
|
24365
|
-
|
|
24366
|
-
|
|
24367
|
-
|
|
24368
|
-
|
|
24906
|
+
async start() {
|
|
24907
|
+
if (this._started) throw new Error("PerRequestHTTPServerTransport is already started");
|
|
24908
|
+
this._started = true;
|
|
24909
|
+
}
|
|
24910
|
+
/**
|
|
24911
|
+
* Serves the single exchange: delivers the classified message to the
|
|
24912
|
+
* connected server instance and resolves with the HTTP response.
|
|
24913
|
+
*
|
|
24914
|
+
* Throws when called a second time (the transport is strictly
|
|
24915
|
+
* single-use), or before a server has been connected to the transport.
|
|
24916
|
+
* The returned promise rejects with a connection-closed error when the
|
|
24917
|
+
* transport is closed before a response was produced (for example because
|
|
24918
|
+
* the client disconnected).
|
|
24919
|
+
*/
|
|
24920
|
+
async handleMessage(message, extra) {
|
|
24921
|
+
if (this._used) throw new Error("PerRequestHTTPServerTransport serves exactly one exchange; construct a new transport per request");
|
|
24922
|
+
if (!this._started || this.onmessage === void 0) throw new Error("PerRequestHTTPServerTransport is not connected: connect a server to this transport before handling a message");
|
|
24923
|
+
if (this._closed) throw new Error("PerRequestHTTPServerTransport is closed");
|
|
24924
|
+
this._used = true;
|
|
24925
|
+
const signal = extra?.request?.signal;
|
|
24926
|
+
if (signal?.aborted) {
|
|
24927
|
+
await this.close();
|
|
24928
|
+
throw new SdkError(SdkErrorCode.ConnectionClosed, "The request was aborted before it could be handled");
|
|
24929
|
+
}
|
|
24930
|
+
const messageExtra = {
|
|
24931
|
+
classification: this._classification,
|
|
24932
|
+
...extra?.request !== void 0 && { request: extra.request },
|
|
24933
|
+
...extra?.authInfo !== void 0 && { authInfo: extra.authInfo }
|
|
24934
|
+
};
|
|
24935
|
+
if (isJSONRPCRequest(message)) {
|
|
24936
|
+
this._requestId = message.id;
|
|
24937
|
+
let resolve;
|
|
24938
|
+
let reject;
|
|
24939
|
+
const promise = new Promise((promiseResolve, promiseReject) => {
|
|
24940
|
+
resolve = promiseResolve;
|
|
24941
|
+
reject = promiseReject;
|
|
24942
|
+
});
|
|
24943
|
+
this._deferredResponse = {
|
|
24944
|
+
promise,
|
|
24945
|
+
resolve,
|
|
24946
|
+
reject,
|
|
24947
|
+
settled: false
|
|
24948
|
+
};
|
|
24949
|
+
if (signal !== void 0) {
|
|
24950
|
+
const onAbort = () => void this.close();
|
|
24951
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
24952
|
+
this._abortCleanup = () => signal.removeEventListener("abort", onAbort);
|
|
24953
|
+
}
|
|
24954
|
+
this._dispatchWindowOpen = true;
|
|
24955
|
+
try {
|
|
24956
|
+
this.onmessage(message, messageExtra);
|
|
24957
|
+
} finally {
|
|
24958
|
+
this._dispatchWindowOpen = false;
|
|
24959
|
+
}
|
|
24960
|
+
if (this._responseMode === "sse" && !this._closed && !this._deferredResponse.settled) this.upgradeToSse();
|
|
24961
|
+
return promise;
|
|
24369
24962
|
}
|
|
24963
|
+
this.onmessage(message, messageExtra);
|
|
24964
|
+
return new Response(null, { status: 202 });
|
|
24370
24965
|
}
|
|
24371
|
-
|
|
24372
|
-
this.
|
|
24373
|
-
|
|
24374
|
-
|
|
24375
|
-
|
|
24376
|
-
|
|
24377
|
-
|
|
24966
|
+
async send(message, options) {
|
|
24967
|
+
if (this._closed) return;
|
|
24968
|
+
const isResponse = isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message);
|
|
24969
|
+
const relatedId = isResponse ? message.id : options?.relatedRequestId;
|
|
24970
|
+
if (this._requestId === void 0 || relatedId === void 0 || relatedId !== this._requestId) {
|
|
24971
|
+
if (isResponse) this.onerror?.(/* @__PURE__ */ new Error(`Received a response for an unknown request id: ${String(message.id)}`));
|
|
24972
|
+
return;
|
|
24973
|
+
}
|
|
24974
|
+
if (isResponse) {
|
|
24975
|
+
if (this._terminalDelivered) return;
|
|
24976
|
+
this._terminalDelivered = true;
|
|
24977
|
+
const errorCode = isJSONRPCErrorResponse(message) ? message.error.code : void 0;
|
|
24978
|
+
const ladderStatus = errorCode !== void 0 && (this._dispatchWindowOpen || errorCode === ProtocolErrorCode.MissingRequiredClientCapability) ? LADDER_ERROR_HTTP_STATUS[errorCode] : void 0;
|
|
24979
|
+
if (ladderStatus !== void 0 && this._sse === void 0) {
|
|
24980
|
+
this.settleResponse(Response.json(message, {
|
|
24981
|
+
status: ladderStatus,
|
|
24982
|
+
headers: { "Content-Type": "application/json" }
|
|
24983
|
+
}));
|
|
24984
|
+
queueMicrotask(() => void this.close());
|
|
24985
|
+
return;
|
|
24986
|
+
}
|
|
24987
|
+
if (this._sse !== void 0 || this._responseMode === "sse") {
|
|
24988
|
+
if (this._sse === void 0) this.upgradeToSse();
|
|
24989
|
+
this.writeMessageFrame(message);
|
|
24990
|
+
this.finalizeStream();
|
|
24991
|
+
return;
|
|
24992
|
+
}
|
|
24993
|
+
this.settleResponse(Response.json(message, {
|
|
24994
|
+
status: 200,
|
|
24995
|
+
headers: { "Content-Type": "application/json" }
|
|
24996
|
+
}));
|
|
24997
|
+
queueMicrotask(() => void this.close());
|
|
24998
|
+
return;
|
|
24999
|
+
}
|
|
25000
|
+
if (this._responseMode === "json") return;
|
|
25001
|
+
if (this._sse === void 0) this.upgradeToSse();
|
|
25002
|
+
this.writeMessageFrame(message);
|
|
25003
|
+
}
|
|
25004
|
+
/**
|
|
25005
|
+
* Writes an SSE comment frame (a keep-alive heartbeat). Dropped when the
|
|
25006
|
+
* exchange is not currently streaming.
|
|
25007
|
+
*/
|
|
25008
|
+
writeCommentFrame(comment) {
|
|
25009
|
+
if (this._closed || this._sse === void 0 || this._sse.closed) return;
|
|
25010
|
+
const frame = comment.split("\n").map((line) => `: ${line}`).join("\n");
|
|
25011
|
+
this.writeFrame(`${frame}\n\n`);
|
|
25012
|
+
}
|
|
25013
|
+
async close() {
|
|
25014
|
+
if (this._closed) return;
|
|
25015
|
+
this._closed = true;
|
|
25016
|
+
this._abortCleanup?.();
|
|
25017
|
+
this._abortCleanup = void 0;
|
|
25018
|
+
if (this._sse?.keepAliveTimer !== void 0) clearInterval(this._sse.keepAliveTimer);
|
|
25019
|
+
if (this._sse !== void 0 && !this._sse.closed) {
|
|
25020
|
+
this._sse.closed = true;
|
|
25021
|
+
try {
|
|
25022
|
+
this._sse.controller.close();
|
|
25023
|
+
} catch {}
|
|
25024
|
+
}
|
|
25025
|
+
if (this._deferredResponse !== void 0 && !this._deferredResponse.settled) {
|
|
25026
|
+
this._deferredResponse.settled = true;
|
|
25027
|
+
this._deferredResponse.reject(new SdkError(SdkErrorCode.ConnectionClosed, "Connection closed before a response was produced"));
|
|
25028
|
+
}
|
|
25029
|
+
this.onclose?.();
|
|
25030
|
+
}
|
|
25031
|
+
settleResponse(response) {
|
|
25032
|
+
if (this._deferredResponse === void 0 || this._deferredResponse.settled) return;
|
|
25033
|
+
this._deferredResponse.settled = true;
|
|
25034
|
+
this._deferredResponse.resolve(response);
|
|
25035
|
+
}
|
|
25036
|
+
upgradeToSse() {
|
|
25037
|
+
let controller;
|
|
25038
|
+
const readable = new ReadableStream({
|
|
25039
|
+
start: (streamController) => {
|
|
25040
|
+
controller = streamController;
|
|
25041
|
+
},
|
|
25042
|
+
cancel: () => {
|
|
25043
|
+
this.close();
|
|
25044
|
+
}
|
|
25045
|
+
});
|
|
25046
|
+
this._sse = {
|
|
25047
|
+
controller,
|
|
25048
|
+
encoder: new TextEncoder(),
|
|
25049
|
+
closed: false
|
|
24378
25050
|
};
|
|
25051
|
+
this._sse.keepAliveTimer = armSseKeepAlive(this._keepAliveMs, () => this.writeCommentFrame("keepalive"));
|
|
25052
|
+
this.settleResponse(new Response(readable, {
|
|
25053
|
+
status: 200,
|
|
25054
|
+
headers: {
|
|
25055
|
+
"Content-Type": "text/event-stream",
|
|
25056
|
+
"Cache-Control": "no-cache, no-transform",
|
|
25057
|
+
Connection: "keep-alive",
|
|
25058
|
+
"X-Accel-Buffering": "no"
|
|
25059
|
+
}
|
|
25060
|
+
}));
|
|
24379
25061
|
}
|
|
24380
|
-
|
|
24381
|
-
|
|
24382
|
-
|
|
25062
|
+
finalizeStream() {
|
|
25063
|
+
if (this._sse?.keepAliveTimer !== void 0) clearInterval(this._sse.keepAliveTimer);
|
|
25064
|
+
if (this._sse !== void 0 && !this._sse.closed) {
|
|
25065
|
+
this._sse.closed = true;
|
|
25066
|
+
try {
|
|
25067
|
+
this._sse.controller.close();
|
|
25068
|
+
} catch {}
|
|
25069
|
+
}
|
|
25070
|
+
queueMicrotask(() => void this.close());
|
|
25071
|
+
}
|
|
25072
|
+
writeMessageFrame(message) {
|
|
25073
|
+
this.writeFrame(`event: message\ndata: ${JSON.stringify(message)}\n\n`);
|
|
25074
|
+
}
|
|
25075
|
+
writeFrame(frame) {
|
|
25076
|
+
if (this._sse === void 0 || this._sse.closed) return;
|
|
25077
|
+
try {
|
|
25078
|
+
this._sse.controller.enqueue(this._sse.encoder.encode(frame));
|
|
25079
|
+
} catch (error) {
|
|
25080
|
+
this.onerror?.(/* @__PURE__ */ new Error(`Failed to write to the response stream: ${error}`));
|
|
25081
|
+
}
|
|
24383
25082
|
}
|
|
24384
25083
|
};
|
|
24385
|
-
/**
|
|
24386
|
-
function
|
|
24387
|
-
return
|
|
24388
|
-
|
|
24389
|
-
|
|
24390
|
-
|
|
24391
|
-
|
|
24392
|
-
|
|
24393
|
-
|
|
24394
|
-
|
|
24395
|
-
|
|
25084
|
+
/** Package-internal: the classification a per-request transport serves; `undefined` for any other transport. Not public API. */
|
|
25085
|
+
function perRequestClassificationOf(transport) {
|
|
25086
|
+
return transport instanceof PerRequestHTTPServerTransport ? readClassification(transport) : void 0;
|
|
25087
|
+
}
|
|
25088
|
+
function comparableResource(value) {
|
|
25089
|
+
const text = String(value);
|
|
25090
|
+
const hash = text.indexOf("#");
|
|
25091
|
+
return (hash === -1 ? text : text.slice(0, hash)).replace(/\/$/, "");
|
|
25092
|
+
}
|
|
25093
|
+
function sameResource(reported, expected) {
|
|
25094
|
+
if (!reported) return false;
|
|
25095
|
+
return comparableResource(reported) === comparableResource(expected);
|
|
25096
|
+
}
|
|
25097
|
+
function headerQuotedValue(value) {
|
|
25098
|
+
return value.replaceAll(/[\\"]/g, String.raw`\$&`).replaceAll(/[^\u0020-\u007E]/g, " ");
|
|
24396
25099
|
}
|
|
24397
25100
|
/**
|
|
24398
|
-
*
|
|
24399
|
-
*
|
|
24400
|
-
* Pure: no I/O, no mutation. The filter governs ONLY the four
|
|
24401
|
-
* subscription-gated change types — non-gated notifications never reach the
|
|
24402
|
-
* bus and are not modeled here.
|
|
25101
|
+
* Build a `WWW-Authenticate: Bearer …` challenge header value (RFC 6750).
|
|
24403
25102
|
*
|
|
24404
|
-
*
|
|
24405
|
-
*
|
|
24406
|
-
|
|
24407
|
-
|
|
24408
|
-
|
|
24409
|
-
|
|
24410
|
-
|
|
24411
|
-
|
|
24412
|
-
|
|
25103
|
+
* The single formatter behind every challenge this package emits — the
|
|
25104
|
+
* bearer-auth 401/403 answers and the per-operation scope-challenge 403 — so
|
|
25105
|
+
* all challenges from one server agree on parameter order and quoting. Every
|
|
25106
|
+
* parameter value is emitted as an HTTP quoted-string with `\` and `"`
|
|
25107
|
+
* escaped and non-printable characters replaced.
|
|
25108
|
+
*/
|
|
25109
|
+
function buildWwwAuthenticateHeader(errorCode, description, requiredScopes, resourceMetadataUrl) {
|
|
25110
|
+
let header = `Bearer error="${headerQuotedValue(errorCode)}", error_description="${headerQuotedValue(description)}"`;
|
|
25111
|
+
if (requiredScopes.length > 0) header += `, scope="${headerQuotedValue(requiredScopes.join(" "))}"`;
|
|
25112
|
+
if (resourceMetadataUrl) header += `, resource_metadata="${headerQuotedValue(resourceMetadataUrl)}"`;
|
|
25113
|
+
return header;
|
|
25114
|
+
}
|
|
25115
|
+
/**
|
|
25116
|
+
* Validate a raw `Authorization` header value as a Bearer token and return
|
|
25117
|
+
* the verified {@link AuthInfo}.
|
|
25118
|
+
*
|
|
25119
|
+
* The runtime-neutral core of Bearer authentication: it parses the header,
|
|
25120
|
+
* runs the verifier, compares the token's resource with `expectedResource`,
|
|
25121
|
+
* enforces `requiredScopes`, and rejects tokens without an
|
|
25122
|
+
* expiration or past it. On any failure it throws an {@link OAuthError} —
|
|
25123
|
+
* pass that to {@link bearerAuthChallengeResponse} for the matching HTTP
|
|
25124
|
+
* answer, or use {@link requireBearerAuth} to get both steps as one call.
|
|
25125
|
+
*
|
|
25126
|
+
* Framework adapters build on this: `requireBearerAuth` from
|
|
25127
|
+
* `@modelcontextprotocol/express` feeds it `req.headers.authorization`.
|
|
25128
|
+
*/
|
|
25129
|
+
async function verifyBearerToken(authorizationHeader, options) {
|
|
25130
|
+
const { verifier, requiredScopes = [], expectedResource } = options;
|
|
25131
|
+
if (!authorizationHeader) throw new OAuthError(OAuthErrorCode.InvalidToken, "Missing Authorization header");
|
|
25132
|
+
const [type, token] = authorizationHeader.split(" ");
|
|
25133
|
+
if (type?.toLowerCase() !== "bearer" || !token) throw new OAuthError(OAuthErrorCode.InvalidToken, "Invalid Authorization header format, expected 'Bearer TOKEN'");
|
|
25134
|
+
const authInfo = await verifier.verifyAccessToken(token);
|
|
25135
|
+
if (expectedResource !== void 0 && !sameResource(authInfo.resource, expectedResource)) throw new OAuthError(OAuthErrorCode.InvalidToken, "Token was not issued for this resource");
|
|
25136
|
+
if (requiredScopes.length > 0) {
|
|
25137
|
+
if (!requiredScopes.every((scope) => authInfo.scopes.includes(scope))) throw new OAuthError(OAuthErrorCode.InsufficientScope, "Insufficient scope");
|
|
24413
25138
|
}
|
|
25139
|
+
if (typeof authInfo.expiresAt !== "number" || Number.isNaN(authInfo.expiresAt)) throw new OAuthError(OAuthErrorCode.InvalidToken, "Token has no expiration time");
|
|
25140
|
+
else if (authInfo.expiresAt < Date.now() / 1e3) throw new OAuthError(OAuthErrorCode.InvalidToken, "Token has expired");
|
|
25141
|
+
if (options.resourceMetadataUrl !== void 0 && authInfo.resourceMetadataUrl === void 0) return {
|
|
25142
|
+
...authInfo,
|
|
25143
|
+
resourceMetadataUrl: options.resourceMetadataUrl
|
|
25144
|
+
};
|
|
25145
|
+
return authInfo;
|
|
24414
25146
|
}
|
|
24415
25147
|
/**
|
|
24416
|
-
*
|
|
24417
|
-
* explicitly opted in to (drops `false` and absent fields), narrowed against
|
|
24418
|
-
* the server's declared capabilities when supplied. The serving entry sends
|
|
24419
|
-
* this back in `notifications/subscriptions/acknowledged` so the ack reflects
|
|
24420
|
-
* what the server can actually deliver.
|
|
25148
|
+
* Build the HTTP answer for a Bearer authentication failure.
|
|
24421
25149
|
*
|
|
24422
|
-
*
|
|
24423
|
-
*
|
|
24424
|
-
*
|
|
24425
|
-
*
|
|
25150
|
+
* Maps an {@link OAuthError} to its status — `401` for `invalid_token` and
|
|
25151
|
+
* `403` for `insufficient_scope` (both carrying the `WWW-Authenticate: Bearer …`
|
|
25152
|
+
* challenge, with `resource_metadata` when configured so clients can discover
|
|
25153
|
+
* the Authorization Server), `500` for `server_error`, `400` for anything
|
|
25154
|
+
* else. A non-`OAuthError` value answers `500 server_error`. The body is the
|
|
25155
|
+
* OAuth error JSON.
|
|
25156
|
+
*/
|
|
25157
|
+
function bearerAuthChallengeResponse(error, options) {
|
|
25158
|
+
const { requiredScopes = [], resourceMetadataUrl } = options ?? {};
|
|
25159
|
+
if (!(error instanceof OAuthError)) {
|
|
25160
|
+
const serverError = new OAuthError(OAuthErrorCode.ServerError, "Internal Server Error");
|
|
25161
|
+
return Response.json(serverError.toResponseObject(), { status: 500 });
|
|
25162
|
+
}
|
|
25163
|
+
switch (error.code) {
|
|
25164
|
+
case OAuthErrorCode.InvalidToken: {
|
|
25165
|
+
const challenge = buildWwwAuthenticateHeader(error.code, error.message, requiredScopes, resourceMetadataUrl);
|
|
25166
|
+
return Response.json(error.toResponseObject(), {
|
|
25167
|
+
status: 401,
|
|
25168
|
+
headers: { "WWW-Authenticate": challenge }
|
|
25169
|
+
});
|
|
25170
|
+
}
|
|
25171
|
+
case OAuthErrorCode.InsufficientScope: {
|
|
25172
|
+
const challenge = buildWwwAuthenticateHeader(error.code, error.message, requiredScopes, resourceMetadataUrl);
|
|
25173
|
+
return Response.json(error.toResponseObject(), {
|
|
25174
|
+
status: 403,
|
|
25175
|
+
headers: { "WWW-Authenticate": challenge }
|
|
25176
|
+
});
|
|
25177
|
+
}
|
|
25178
|
+
case OAuthErrorCode.ServerError: return Response.json(error.toResponseObject(), { status: 500 });
|
|
25179
|
+
default: return Response.json(error.toResponseObject(), { status: 400 });
|
|
25180
|
+
}
|
|
25181
|
+
}
|
|
25182
|
+
/**
|
|
25183
|
+
* Builds the RFC 9728 Protected Resource Metadata URL for a given MCP server
|
|
25184
|
+
* URL by inserting `/.well-known/oauth-protected-resource` ahead of the path.
|
|
24426
25185
|
*
|
|
24427
|
-
*
|
|
24428
|
-
*
|
|
24429
|
-
*
|
|
24430
|
-
*
|
|
24431
|
-
*
|
|
25186
|
+
* @example
|
|
25187
|
+
* ```ts
|
|
25188
|
+
* getOAuthProtectedResourceMetadataUrl(new URL('https://api.example.com/mcp'))
|
|
25189
|
+
* // → 'https://api.example.com/.well-known/oauth-protected-resource/mcp'
|
|
25190
|
+
* ```
|
|
24432
25191
|
*/
|
|
24433
|
-
function
|
|
24434
|
-
const
|
|
24435
|
-
|
|
24436
|
-
|
|
24437
|
-
|
|
24438
|
-
if (requested.resourcesListChanged === true && allow(capabilities?.resources?.listChanged)) honored.resourcesListChanged = true;
|
|
24439
|
-
if (requested.resourceSubscriptions !== void 0 && requested.resourceSubscriptions.length > 0 && allow(capabilities?.resources?.subscribe)) honored.resourceSubscriptions = [...requested.resourceSubscriptions];
|
|
24440
|
-
return honored;
|
|
25192
|
+
function getOAuthProtectedResourceMetadataUrl(serverUrl) {
|
|
25193
|
+
const metadataUrl = new URL(serverUrl);
|
|
25194
|
+
metadataUrl.pathname = protectedResourceMetadataPath(serverUrl);
|
|
25195
|
+
metadataUrl.hash = "";
|
|
25196
|
+
return metadataUrl.href;
|
|
24441
25197
|
}
|
|
24442
|
-
/**
|
|
24443
|
-
function
|
|
24444
|
-
|
|
24445
|
-
|
|
24446
|
-
|
|
24447
|
-
|
|
24448
|
-
|
|
24449
|
-
|
|
24450
|
-
|
|
24451
|
-
|
|
25198
|
+
/** The RFC 9728 path-aware well-known path for a resource URL. */
|
|
25199
|
+
function protectedResourceMetadataPath(resourceServerUrl) {
|
|
25200
|
+
const rsPath = stripTrailingSlash(resourceServerUrl.pathname);
|
|
25201
|
+
return `/.well-known/oauth-protected-resource${rsPath === "/" ? "" : rsPath}`;
|
|
25202
|
+
}
|
|
25203
|
+
function stripTrailingSlash(path) {
|
|
25204
|
+
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
25205
|
+
}
|
|
25206
|
+
/** @internal */
|
|
25207
|
+
function supportsScopeChallengeResolver(transport) {
|
|
25208
|
+
return typeof transport === "object" && transport !== null && "setScopeChallengeResolver" in transport && typeof transport.setScopeChallengeResolver === "function";
|
|
25209
|
+
}
|
|
25210
|
+
function assertScope(scope, location) {
|
|
25211
|
+
if (typeof scope !== "string" || !/^[\u0021\u0023-\u005B\u005D-\u007E]+$/.test(scope)) throw new TypeError(`${location} must satisfy the OAuth scope-token grammar`);
|
|
25212
|
+
}
|
|
25213
|
+
function validateScopeChallenge(challenge) {
|
|
25214
|
+
if (challenge === null || typeof challenge !== "object" || !Array.isArray(challenge.scopes) || challenge.scopes.length === 0) throw new TypeError("scope challenge must contain at least one scope");
|
|
25215
|
+
for (const [index, scope] of challenge.scopes.entries()) assertScope(scope, `scope challenge scopes[${index}]`);
|
|
25216
|
+
if (challenge.errorDescription !== void 0 && typeof challenge.errorDescription !== "string") throw new TypeError("scope challenge errorDescription must be a string");
|
|
25217
|
+
if (challenge.errorDescription !== void 0 && !/^[\u0020-\u0021\u0023-\u005B\u005D-\u007E]+$/.test(challenge.errorDescription)) throw new TypeError("scope challenge errorDescription must satisfy the RFC 6750 error-description grammar");
|
|
25218
|
+
return challenge;
|
|
25219
|
+
}
|
|
25220
|
+
/** @internal */
|
|
25221
|
+
async function findScopeChallenge(requests, authInfo, resolve) {
|
|
25222
|
+
for (const request of requests) {
|
|
25223
|
+
const challenge = await resolve({
|
|
25224
|
+
request,
|
|
25225
|
+
...authInfo !== void 0 && { authInfo }
|
|
25226
|
+
});
|
|
25227
|
+
if (challenge !== void 0) return validateScopeChallenge(challenge);
|
|
24452
25228
|
}
|
|
24453
25229
|
}
|
|
24454
|
-
/**
|
|
24455
|
-
|
|
24456
|
-
|
|
24457
|
-
|
|
24458
|
-
|
|
24459
|
-
|
|
24460
|
-
|
|
24461
|
-
|
|
24462
|
-
|
|
24463
|
-
|
|
24464
|
-
|
|
25230
|
+
/**
|
|
25231
|
+
* The RFC 9728 Protected Resource Metadata URL to advertise on a scope
|
|
25232
|
+
* challenge, derived from the verified {@link AuthInfo}: the URL the
|
|
25233
|
+
* authentication gate stamped (`authInfo.resourceMetadataUrl`, set by the
|
|
25234
|
+
* bearer-auth helpers from their `resourceMetadataUrl` option), falling back
|
|
25235
|
+
* to the well-known location for an HTTP(S) RFC 8707 `resource` identifier, or
|
|
25236
|
+
* `undefined` when neither is available (the `resource_metadata` parameter is
|
|
25237
|
+
* then omitted, matching the bearer-auth challenges).
|
|
25238
|
+
*
|
|
25239
|
+
* @internal
|
|
25240
|
+
*/
|
|
25241
|
+
function scopeChallengeResourceMetadataUrl(authInfo) {
|
|
25242
|
+
if (authInfo?.resourceMetadataUrl !== void 0) return authInfo.resourceMetadataUrl;
|
|
25243
|
+
if (authInfo?.resource?.protocol === "https:" || authInfo?.resource?.protocol === "http:") return getOAuthProtectedResourceMetadataUrl(authInfo.resource);
|
|
24465
25244
|
}
|
|
24466
|
-
/**
|
|
24467
|
-
function
|
|
25245
|
+
/** @internal */
|
|
25246
|
+
function createScopeChallengeResponse(challenge, resourceMetadataUrl) {
|
|
25247
|
+
return bearerAuthChallengeResponse(new OAuthError(OAuthErrorCode.InsufficientScope, challenge.errorDescription ?? "Insufficient scope"), {
|
|
25248
|
+
requiredScopes: [...challenge.scopes],
|
|
25249
|
+
resourceMetadataUrl
|
|
25250
|
+
});
|
|
25251
|
+
}
|
|
25252
|
+
/**
|
|
25253
|
+
* Default handler re-entries per originating request — tighter than the
|
|
25254
|
+
* client driver's 10 because the shim holds a live wire request open.
|
|
25255
|
+
*/
|
|
25256
|
+
const DEFAULT_LEGACY_SHIM_MAX_ROUNDS = 8;
|
|
25257
|
+
/** Default per-leg timeout: legs are human-paced, so the 60s protocol default is wrong. */
|
|
25258
|
+
const DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS = 6e5;
|
|
25259
|
+
/** Resolves and validates `ServerOptions.inputRequired`, failing loudly at construction time. */
|
|
25260
|
+
function resolveLegacyShimOptions(options) {
|
|
25261
|
+
if (options?.maxRounds !== void 0 && (!Number.isInteger(options.maxRounds) || options.maxRounds < 1)) throw new RangeError(`inputRequired.maxRounds must be a positive integer (got ${options.maxRounds})`);
|
|
25262
|
+
if (options?.roundTimeoutMs !== void 0 && (!Number.isFinite(options.roundTimeoutMs) || options.roundTimeoutMs <= 0)) throw new RangeError(`inputRequired.roundTimeoutMs must be a positive number (got ${options.roundTimeoutMs})`);
|
|
24468
25263
|
return {
|
|
24469
|
-
|
|
24470
|
-
|
|
24471
|
-
|
|
24472
|
-
_meta: {
|
|
24473
|
-
...notification.params?._meta,
|
|
24474
|
-
[SUBSCRIPTION_ID_META_KEY]: subscriptionId
|
|
24475
|
-
}
|
|
24476
|
-
}
|
|
25264
|
+
maxRounds: options?.maxRounds ?? DEFAULT_LEGACY_SHIM_MAX_ROUNDS,
|
|
25265
|
+
roundTimeoutMs: options?.roundTimeoutMs ?? DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS,
|
|
25266
|
+
legacyShim: options?.legacyShim ?? true
|
|
24477
25267
|
};
|
|
24478
25268
|
}
|
|
24479
25269
|
/**
|
|
24480
|
-
*
|
|
24481
|
-
*
|
|
24482
|
-
*
|
|
24483
|
-
* marks `notifications` REQUIRED on the listen request).
|
|
25270
|
+
* Validates one `inputRequests` entry: malformed or unknown kinds are server
|
|
25271
|
+
* bugs and fail loudly on both eras. Shared by the modern seam's capability
|
|
25272
|
+
* check and the shim's gate.
|
|
24484
25273
|
*/
|
|
24485
|
-
function
|
|
24486
|
-
|
|
24487
|
-
|
|
24488
|
-
|
|
24489
|
-
|
|
24490
|
-
|
|
24491
|
-
|
|
24492
|
-
|
|
24493
|
-
|
|
24494
|
-
function serve(message, signal, capabilities, serverInfo) {
|
|
24495
|
-
if (open.size >= maxSubscriptions) {
|
|
24496
|
-
onerror?.(/* @__PURE__ */ new Error(`subscriptions/listen refused: subscription limit reached (${maxSubscriptions})`));
|
|
24497
|
-
return jsonRpcError(message.id, -32603, "Subscription limit reached");
|
|
24498
|
-
}
|
|
24499
|
-
const filter = parseListenFilter(message);
|
|
24500
|
-
if (filter === void 0) return jsonRpcError(message.id, -32602, "Invalid params: 'notifications' is required and must be a valid SubscriptionFilter");
|
|
24501
|
-
const honored = honoredSubset(filter, capabilities);
|
|
24502
|
-
const subscriptionId = message.id;
|
|
24503
|
-
const encoder = new TextEncoder();
|
|
24504
|
-
let controller;
|
|
24505
|
-
let closed = false;
|
|
24506
|
-
let unsubscribe;
|
|
24507
|
-
let keepAliveTimer;
|
|
24508
|
-
let abortCleanup;
|
|
24509
|
-
const writeFrame = (frame) => {
|
|
24510
|
-
if (closed) return;
|
|
24511
|
-
try {
|
|
24512
|
-
controller.enqueue(encoder.encode(frame));
|
|
24513
|
-
} catch (error) {
|
|
24514
|
-
onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
24515
|
-
}
|
|
24516
|
-
};
|
|
24517
|
-
const writeNotification = (method, params) => {
|
|
24518
|
-
writeFrame(`event: message\ndata: ${JSON.stringify({
|
|
24519
|
-
jsonrpc: "2.0",
|
|
24520
|
-
method,
|
|
24521
|
-
params
|
|
24522
|
-
})}\n\n`);
|
|
24523
|
-
};
|
|
24524
|
-
const teardown = (graceful) => {
|
|
24525
|
-
if (closed) return;
|
|
24526
|
-
if (graceful) writeFrame(`event: message\ndata: ${JSON.stringify({
|
|
24527
|
-
jsonrpc: "2.0",
|
|
24528
|
-
id: subscriptionId,
|
|
24529
|
-
result: {
|
|
24530
|
-
resultType: "complete",
|
|
24531
|
-
_meta: {
|
|
24532
|
-
[SUBSCRIPTION_ID_META_KEY]: subscriptionId,
|
|
24533
|
-
[SERVER_INFO_META_KEY]: serverInfo
|
|
24534
|
-
}
|
|
24535
|
-
}
|
|
24536
|
-
})}\n\n`);
|
|
24537
|
-
closed = true;
|
|
24538
|
-
try {
|
|
24539
|
-
unsubscribe?.();
|
|
24540
|
-
} catch (error) {
|
|
24541
|
-
onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
24542
|
-
}
|
|
24543
|
-
if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer);
|
|
24544
|
-
abortCleanup?.();
|
|
24545
|
-
open.delete(teardown);
|
|
24546
|
-
try {
|
|
24547
|
-
controller.close();
|
|
24548
|
-
} catch {}
|
|
24549
|
-
};
|
|
24550
|
-
const readable = new ReadableStream({
|
|
24551
|
-
start(streamController) {
|
|
24552
|
-
controller = streamController;
|
|
24553
|
-
const ack = stampSubscriptionId({
|
|
24554
|
-
method: "notifications/subscriptions/acknowledged",
|
|
24555
|
-
params: { notifications: honored }
|
|
24556
|
-
}, subscriptionId);
|
|
24557
|
-
writeNotification(ack.method, ack.params);
|
|
24558
|
-
if (Object.keys(honored).length === 0) {
|
|
24559
|
-
teardown(true);
|
|
24560
|
-
return;
|
|
24561
|
-
}
|
|
24562
|
-
unsubscribe = bus.subscribe((event) => {
|
|
24563
|
-
if (closed || !listenFilterAccepts(honored, event)) return;
|
|
24564
|
-
const note = stampSubscriptionId(serverEventToNotification(event), subscriptionId);
|
|
24565
|
-
writeNotification(note.method, note.params);
|
|
24566
|
-
});
|
|
24567
|
-
keepAliveTimer = armSseKeepAlive(keepAliveMs, () => writeFrame(": keepalive\n\n"));
|
|
24568
|
-
open.add(teardown);
|
|
24569
|
-
},
|
|
24570
|
-
cancel() {
|
|
24571
|
-
teardown(false);
|
|
24572
|
-
}
|
|
24573
|
-
});
|
|
24574
|
-
if (signal !== void 0) if (signal.aborted) teardown(false);
|
|
24575
|
-
else {
|
|
24576
|
-
const onAbort = () => teardown(false);
|
|
24577
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
24578
|
-
abortCleanup = () => signal.removeEventListener("abort", onAbort);
|
|
24579
|
-
}
|
|
24580
|
-
return new Response(readable, {
|
|
24581
|
-
status: 200,
|
|
24582
|
-
headers: {
|
|
24583
|
-
"Content-Type": "text/event-stream",
|
|
24584
|
-
"Cache-Control": "no-cache, no-transform",
|
|
24585
|
-
Connection: "keep-alive",
|
|
24586
|
-
"X-Accel-Buffering": "no"
|
|
24587
|
-
}
|
|
24588
|
-
});
|
|
24589
|
-
}
|
|
24590
|
-
return {
|
|
24591
|
-
serve,
|
|
24592
|
-
closeAll() {
|
|
24593
|
-
for (const teardown of open) teardown(true);
|
|
24594
|
-
},
|
|
24595
|
-
get openCount() {
|
|
24596
|
-
return open.size;
|
|
24597
|
-
}
|
|
24598
|
-
};
|
|
24599
|
-
}
|
|
24600
|
-
const CHANGE_NOTIFICATION_METHODS = /* @__PURE__ */ new Set([
|
|
24601
|
-
"notifications/tools/list_changed",
|
|
24602
|
-
"notifications/prompts/list_changed",
|
|
24603
|
-
"notifications/resources/list_changed",
|
|
24604
|
-
"notifications/resources/updated"
|
|
24605
|
-
]);
|
|
24606
|
-
/**
|
|
24607
|
-
* Per-connection listen state for the stdio entry. One instance is held by
|
|
24608
|
-
* `serveStdio` for the connection lifetime; it routes inbound
|
|
24609
|
-
* `subscriptions/listen` / `notifications/cancelled` and rewrites outbound
|
|
24610
|
-
* change notifications onto the active subscriptions. No bus — the long-lived
|
|
24611
|
-
* pinned instance's existing `send*ListChanged()` calls feed straight into
|
|
24612
|
-
* `routeOutbound()`.
|
|
24613
|
-
*/
|
|
24614
|
-
var StdioListenRouter = class {
|
|
24615
|
-
/** Active subscriptions, keyed by the listen request's JSON-RPC id verbatim. */
|
|
24616
|
-
_subs = /* @__PURE__ */ new Map();
|
|
24617
|
-
/**
|
|
24618
|
-
* The serving instance's declared capabilities. Filled in by the entry
|
|
24619
|
-
* once the modern instance is constructed (the router is created before
|
|
24620
|
-
* the instance exists), so the acknowledged filter is narrowed against
|
|
24621
|
-
* what the server can actually deliver.
|
|
24622
|
-
*/
|
|
24623
|
-
_serverCapabilities;
|
|
24624
|
-
/**
|
|
24625
|
-
* The serving instance's identity, stamped onto the graceful-close
|
|
24626
|
-
* results' `_meta` (the spec's `SubscriptionsListenResultMetaObject` extends
|
|
24627
|
-
* `ResultMetaObject`). Handed over together with the capabilities.
|
|
24628
|
-
*/
|
|
24629
|
-
_serverInfo;
|
|
24630
|
-
constructor(_maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS, serverCapabilities, serverInfo) {
|
|
24631
|
-
this._maxSubscriptions = _maxSubscriptions;
|
|
24632
|
-
this._serverCapabilities = serverCapabilities;
|
|
24633
|
-
this._serverInfo = serverInfo;
|
|
24634
|
-
}
|
|
24635
|
-
/**
|
|
24636
|
-
* Record the serving instance's declared capabilities and identity once
|
|
24637
|
-
* it has been constructed. Called by `serveStdio`'s connect path;
|
|
24638
|
-
* subsequent `serve()` calls narrow the honored filter against the
|
|
24639
|
-
* capabilities, and `teardownAll()` stamps the identity.
|
|
24640
|
-
*/
|
|
24641
|
-
setServerCapabilities(capabilities, serverInfo) {
|
|
24642
|
-
this._serverCapabilities = capabilities;
|
|
24643
|
-
if (serverInfo !== void 0) this._serverInfo = serverInfo;
|
|
24644
|
-
}
|
|
24645
|
-
/** Whether `id` is an active listen subscription on this connection. */
|
|
24646
|
-
has(id) {
|
|
24647
|
-
return this._subs.has(id);
|
|
24648
|
-
}
|
|
24649
|
-
/**
|
|
24650
|
-
* Serve one inbound `subscriptions/listen` request: registers the
|
|
24651
|
-
* subscription and returns the stamped acknowledged notification (or, on
|
|
24652
|
-
* capacity / params rejection, the in-band JSON-RPC error response).
|
|
24653
|
-
*
|
|
24654
|
-
* @throws when called before {@linkcode setServerCapabilities} (or the
|
|
24655
|
-
* constructor) has supplied the serving instance's capabilities. Honoring a
|
|
24656
|
-
* filter without knowing the server's advertised capabilities would fail
|
|
24657
|
-
* open (deliver unadvertised types); the entry guarantees capabilities are
|
|
24658
|
-
* set before any listen request is routed here.
|
|
24659
|
-
*/
|
|
24660
|
-
serve(message) {
|
|
24661
|
-
if (this._serverCapabilities === void 0) throw new Error("StdioListenRouter.serve() called before setServerCapabilities(); refusing to honor a filter without capabilities");
|
|
24662
|
-
if (this._subs.size >= this._maxSubscriptions) return {
|
|
24663
|
-
jsonrpc: "2.0",
|
|
24664
|
-
id: message.id,
|
|
24665
|
-
error: {
|
|
24666
|
-
code: -32603,
|
|
24667
|
-
message: "Subscription limit reached"
|
|
24668
|
-
}
|
|
24669
|
-
};
|
|
24670
|
-
const filter = parseListenFilter(message);
|
|
24671
|
-
if (filter === void 0) return {
|
|
24672
|
-
jsonrpc: "2.0",
|
|
24673
|
-
id: message.id,
|
|
24674
|
-
error: {
|
|
24675
|
-
code: -32602,
|
|
24676
|
-
message: "Invalid params: 'notifications' is required and must be a valid SubscriptionFilter"
|
|
24677
|
-
}
|
|
24678
|
-
};
|
|
24679
|
-
const honored = honoredSubset(filter, this._serverCapabilities);
|
|
24680
|
-
this._subs.set(message.id, honored);
|
|
24681
|
-
return stampSubscriptionId({
|
|
24682
|
-
method: "notifications/subscriptions/acknowledged",
|
|
24683
|
-
params: { notifications: honored }
|
|
24684
|
-
}, message.id);
|
|
24685
|
-
}
|
|
24686
|
-
/**
|
|
24687
|
-
* Tear down one subscription (inbound `notifications/cancelled`). Returns
|
|
24688
|
-
* `true` when a subscription was removed. After this call NOTHING further
|
|
24689
|
-
* is delivered for that subscription id (the post-cancel hardening).
|
|
24690
|
-
*/
|
|
24691
|
-
cancel(id) {
|
|
24692
|
-
return this._subs.delete(id);
|
|
24693
|
-
}
|
|
24694
|
-
/**
|
|
24695
|
-
* Route an outbound notification through the active subscriptions.
|
|
24696
|
-
*
|
|
24697
|
-
* - For a subscription-gated change notification, returns one stamped copy
|
|
24698
|
-
* per subscription that opted in to it (an empty array means it is
|
|
24699
|
-
* dropped — the modern era never delivers an un-requested change type).
|
|
24700
|
-
* - For any other outbound message, returns `'passthrough'` (the entry
|
|
24701
|
-
* forwards it as-is).
|
|
24702
|
-
*/
|
|
24703
|
-
routeOutbound(message) {
|
|
24704
|
-
if (!CHANGE_NOTIFICATION_METHODS.has(message.method)) return "passthrough";
|
|
24705
|
-
const uriParam = message.params?.["uri"];
|
|
24706
|
-
const uri = typeof uriParam === "string" ? uriParam : void 0;
|
|
24707
|
-
const event = notificationToServerEvent(message.method, uri);
|
|
24708
|
-
const out = [];
|
|
24709
|
-
for (const [subscriptionId, filter] of this._subs) if (listenFilterAccepts(filter, event)) out.push(stampSubscriptionId({
|
|
24710
|
-
method: message.method,
|
|
24711
|
-
params: message.params ?? {}
|
|
24712
|
-
}, subscriptionId));
|
|
24713
|
-
return out;
|
|
24714
|
-
}
|
|
24715
|
-
/**
|
|
24716
|
-
* Server-side graceful teardown of every active subscription: returns the
|
|
24717
|
-
* empty `subscriptions/listen` JSON-RPC result for each subscription id —
|
|
24718
|
-
* the spec's graceful-close signal, `_meta` carrying the subscription id
|
|
24719
|
-
* and the serving instance's identity — for the entry to emit before
|
|
24720
|
-
* closing the wire. Clears the set so nothing further is delivered.
|
|
24721
|
-
*/
|
|
24722
|
-
teardownAll() {
|
|
24723
|
-
const out = [];
|
|
24724
|
-
for (const id of this._subs.keys()) out.push({
|
|
24725
|
-
jsonrpc: "2.0",
|
|
24726
|
-
id,
|
|
24727
|
-
result: {
|
|
24728
|
-
resultType: "complete",
|
|
24729
|
-
_meta: {
|
|
24730
|
-
[SUBSCRIPTION_ID_META_KEY]: id,
|
|
24731
|
-
...this._serverInfo !== void 0 && { ["io.modelcontextprotocol/serverInfo"]: this._serverInfo }
|
|
24732
|
-
}
|
|
24733
|
-
}
|
|
24734
|
-
});
|
|
24735
|
-
this._subs.clear();
|
|
24736
|
-
return out;
|
|
24737
|
-
}
|
|
24738
|
-
};
|
|
24739
|
-
function notificationToServerEvent(method, uri) {
|
|
24740
|
-
switch (method) {
|
|
24741
|
-
case "notifications/tools/list_changed": return { kind: "tools_list_changed" };
|
|
24742
|
-
case "notifications/prompts/list_changed": return { kind: "prompts_list_changed" };
|
|
24743
|
-
case "notifications/resources/list_changed": return { kind: "resources_list_changed" };
|
|
24744
|
-
default: return {
|
|
24745
|
-
kind: "resource_updated",
|
|
24746
|
-
uri: uri ?? ""
|
|
24747
|
-
};
|
|
24748
|
-
}
|
|
24749
|
-
}
|
|
24750
|
-
function comparableResource(value) {
|
|
24751
|
-
const text = String(value);
|
|
24752
|
-
const hash = text.indexOf("#");
|
|
24753
|
-
return (hash === -1 ? text : text.slice(0, hash)).replace(/\/$/, "");
|
|
24754
|
-
}
|
|
24755
|
-
function sameResource(reported, expected) {
|
|
24756
|
-
if (!reported) return false;
|
|
24757
|
-
return comparableResource(reported) === comparableResource(expected);
|
|
24758
|
-
}
|
|
24759
|
-
function headerQuotedValue(value) {
|
|
24760
|
-
return value.replaceAll(/[\\"]/g, String.raw`\$&`).replaceAll(/[^\u0020-\u007E]/g, " ");
|
|
24761
|
-
}
|
|
24762
|
-
/**
|
|
24763
|
-
* Build a `WWW-Authenticate: Bearer …` challenge header value (RFC 6750).
|
|
24764
|
-
*
|
|
24765
|
-
* The single formatter behind every challenge this package emits — the
|
|
24766
|
-
* bearer-auth 401/403 answers and the per-operation scope-challenge 403 — so
|
|
24767
|
-
* all challenges from one server agree on parameter order and quoting. Every
|
|
24768
|
-
* parameter value is emitted as an HTTP quoted-string with `\` and `"`
|
|
24769
|
-
* escaped and non-printable characters replaced.
|
|
24770
|
-
*/
|
|
24771
|
-
function buildWwwAuthenticateHeader(errorCode, description, requiredScopes, resourceMetadataUrl) {
|
|
24772
|
-
let header = `Bearer error="${headerQuotedValue(errorCode)}", error_description="${headerQuotedValue(description)}"`;
|
|
24773
|
-
if (requiredScopes.length > 0) header += `, scope="${headerQuotedValue(requiredScopes.join(" "))}"`;
|
|
24774
|
-
if (resourceMetadataUrl) header += `, resource_metadata="${headerQuotedValue(resourceMetadataUrl)}"`;
|
|
24775
|
-
return header;
|
|
24776
|
-
}
|
|
24777
|
-
/**
|
|
24778
|
-
* Validate a raw `Authorization` header value as a Bearer token and return
|
|
24779
|
-
* the verified {@link AuthInfo}.
|
|
24780
|
-
*
|
|
24781
|
-
* The runtime-neutral core of Bearer authentication: it parses the header,
|
|
24782
|
-
* runs the verifier, compares the token's resource with `expectedResource`,
|
|
24783
|
-
* enforces `requiredScopes`, and rejects tokens without an
|
|
24784
|
-
* expiration or past it. On any failure it throws an {@link OAuthError} —
|
|
24785
|
-
* pass that to {@link bearerAuthChallengeResponse} for the matching HTTP
|
|
24786
|
-
* answer, or use {@link requireBearerAuth} to get both steps as one call.
|
|
24787
|
-
*
|
|
24788
|
-
* Framework adapters build on this: `requireBearerAuth` from
|
|
24789
|
-
* `@modelcontextprotocol/express` feeds it `req.headers.authorization`.
|
|
24790
|
-
*/
|
|
24791
|
-
async function verifyBearerToken(authorizationHeader, options) {
|
|
24792
|
-
const { verifier, requiredScopes = [], expectedResource } = options;
|
|
24793
|
-
if (!authorizationHeader) throw new OAuthError(OAuthErrorCode.InvalidToken, "Missing Authorization header");
|
|
24794
|
-
const [type, token] = authorizationHeader.split(" ");
|
|
24795
|
-
if (type?.toLowerCase() !== "bearer" || !token) throw new OAuthError(OAuthErrorCode.InvalidToken, "Invalid Authorization header format, expected 'Bearer TOKEN'");
|
|
24796
|
-
const authInfo = await verifier.verifyAccessToken(token);
|
|
24797
|
-
if (expectedResource !== void 0 && !sameResource(authInfo.resource, expectedResource)) throw new OAuthError(OAuthErrorCode.InvalidToken, "Token was not issued for this resource");
|
|
24798
|
-
if (requiredScopes.length > 0) {
|
|
24799
|
-
if (!requiredScopes.every((scope) => authInfo.scopes.includes(scope))) throw new OAuthError(OAuthErrorCode.InsufficientScope, "Insufficient scope");
|
|
24800
|
-
}
|
|
24801
|
-
if (typeof authInfo.expiresAt !== "number" || Number.isNaN(authInfo.expiresAt)) throw new OAuthError(OAuthErrorCode.InvalidToken, "Token has no expiration time");
|
|
24802
|
-
else if (authInfo.expiresAt < Date.now() / 1e3) throw new OAuthError(OAuthErrorCode.InvalidToken, "Token has expired");
|
|
24803
|
-
if (options.resourceMetadataUrl !== void 0 && authInfo.resourceMetadataUrl === void 0) return {
|
|
24804
|
-
...authInfo,
|
|
24805
|
-
resourceMetadataUrl: options.resourceMetadataUrl
|
|
24806
|
-
};
|
|
24807
|
-
return authInfo;
|
|
24808
|
-
}
|
|
24809
|
-
/**
|
|
24810
|
-
* Build the HTTP answer for a Bearer authentication failure.
|
|
24811
|
-
*
|
|
24812
|
-
* Maps an {@link OAuthError} to its status — `401` for `invalid_token` and
|
|
24813
|
-
* `403` for `insufficient_scope` (both carrying the `WWW-Authenticate: Bearer …`
|
|
24814
|
-
* challenge, with `resource_metadata` when configured so clients can discover
|
|
24815
|
-
* the Authorization Server), `500` for `server_error`, `400` for anything
|
|
24816
|
-
* else. A non-`OAuthError` value answers `500 server_error`. The body is the
|
|
24817
|
-
* OAuth error JSON.
|
|
24818
|
-
*/
|
|
24819
|
-
function bearerAuthChallengeResponse(error, options) {
|
|
24820
|
-
const { requiredScopes = [], resourceMetadataUrl } = options ?? {};
|
|
24821
|
-
if (!(error instanceof OAuthError)) {
|
|
24822
|
-
const serverError = new OAuthError(OAuthErrorCode.ServerError, "Internal Server Error");
|
|
24823
|
-
return Response.json(serverError.toResponseObject(), { status: 500 });
|
|
24824
|
-
}
|
|
24825
|
-
switch (error.code) {
|
|
24826
|
-
case OAuthErrorCode.InvalidToken: {
|
|
24827
|
-
const challenge = buildWwwAuthenticateHeader(error.code, error.message, requiredScopes, resourceMetadataUrl);
|
|
24828
|
-
return Response.json(error.toResponseObject(), {
|
|
24829
|
-
status: 401,
|
|
24830
|
-
headers: { "WWW-Authenticate": challenge }
|
|
24831
|
-
});
|
|
24832
|
-
}
|
|
24833
|
-
case OAuthErrorCode.InsufficientScope: {
|
|
24834
|
-
const challenge = buildWwwAuthenticateHeader(error.code, error.message, requiredScopes, resourceMetadataUrl);
|
|
24835
|
-
return Response.json(error.toResponseObject(), {
|
|
24836
|
-
status: 403,
|
|
24837
|
-
headers: { "WWW-Authenticate": challenge }
|
|
24838
|
-
});
|
|
24839
|
-
}
|
|
24840
|
-
case OAuthErrorCode.ServerError: return Response.json(error.toResponseObject(), { status: 500 });
|
|
24841
|
-
default: return Response.json(error.toResponseObject(), { status: 400 });
|
|
24842
|
-
}
|
|
24843
|
-
}
|
|
24844
|
-
/**
|
|
24845
|
-
* Builds the RFC 9728 Protected Resource Metadata URL for a given MCP server
|
|
24846
|
-
* URL by inserting `/.well-known/oauth-protected-resource` ahead of the path.
|
|
24847
|
-
*
|
|
24848
|
-
* @example
|
|
24849
|
-
* ```ts
|
|
24850
|
-
* getOAuthProtectedResourceMetadataUrl(new URL('https://api.example.com/mcp'))
|
|
24851
|
-
* // → 'https://api.example.com/.well-known/oauth-protected-resource/mcp'
|
|
24852
|
-
* ```
|
|
24853
|
-
*/
|
|
24854
|
-
function getOAuthProtectedResourceMetadataUrl(serverUrl) {
|
|
24855
|
-
const metadataUrl = new URL(serverUrl);
|
|
24856
|
-
metadataUrl.pathname = protectedResourceMetadataPath(serverUrl);
|
|
24857
|
-
metadataUrl.hash = "";
|
|
24858
|
-
return metadataUrl.href;
|
|
24859
|
-
}
|
|
24860
|
-
/** The RFC 9728 path-aware well-known path for a resource URL. */
|
|
24861
|
-
function protectedResourceMetadataPath(resourceServerUrl) {
|
|
24862
|
-
const rsPath = stripTrailingSlash(resourceServerUrl.pathname);
|
|
24863
|
-
return `/.well-known/oauth-protected-resource${rsPath === "/" ? "" : rsPath}`;
|
|
24864
|
-
}
|
|
24865
|
-
function stripTrailingSlash(path) {
|
|
24866
|
-
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
24867
|
-
}
|
|
24868
|
-
/** @internal */
|
|
24869
|
-
function supportsScopeChallengeResolver(transport) {
|
|
24870
|
-
return typeof transport === "object" && transport !== null && "setScopeChallengeResolver" in transport && typeof transport.setScopeChallengeResolver === "function";
|
|
24871
|
-
}
|
|
24872
|
-
function assertScope(scope, location) {
|
|
24873
|
-
if (typeof scope !== "string" || !/^[\u0021\u0023-\u005B\u005D-\u007E]+$/.test(scope)) throw new TypeError(`${location} must satisfy the OAuth scope-token grammar`);
|
|
24874
|
-
}
|
|
24875
|
-
function validateScopeChallenge(challenge) {
|
|
24876
|
-
if (challenge === null || typeof challenge !== "object" || !Array.isArray(challenge.scopes) || challenge.scopes.length === 0) throw new TypeError("scope challenge must contain at least one scope");
|
|
24877
|
-
for (const [index, scope] of challenge.scopes.entries()) assertScope(scope, `scope challenge scopes[${index}]`);
|
|
24878
|
-
if (challenge.errorDescription !== void 0 && typeof challenge.errorDescription !== "string") throw new TypeError("scope challenge errorDescription must be a string");
|
|
24879
|
-
if (challenge.errorDescription !== void 0 && !/^[\u0020-\u0021\u0023-\u005B\u005D-\u007E]+$/.test(challenge.errorDescription)) throw new TypeError("scope challenge errorDescription must satisfy the RFC 6750 error-description grammar");
|
|
24880
|
-
return challenge;
|
|
24881
|
-
}
|
|
24882
|
-
/** @internal */
|
|
24883
|
-
async function findScopeChallenge(requests, authInfo, resolve) {
|
|
24884
|
-
for (const request of requests) {
|
|
24885
|
-
const challenge = await resolve({
|
|
24886
|
-
request,
|
|
24887
|
-
...authInfo !== void 0 && { authInfo }
|
|
24888
|
-
});
|
|
24889
|
-
if (challenge !== void 0) return validateScopeChallenge(challenge);
|
|
24890
|
-
}
|
|
24891
|
-
}
|
|
24892
|
-
/**
|
|
24893
|
-
* The RFC 9728 Protected Resource Metadata URL to advertise on a scope
|
|
24894
|
-
* challenge, derived from the verified {@link AuthInfo}: the URL the
|
|
24895
|
-
* authentication gate stamped (`authInfo.resourceMetadataUrl`, set by the
|
|
24896
|
-
* bearer-auth helpers from their `resourceMetadataUrl` option), falling back
|
|
24897
|
-
* to the well-known location for an HTTP(S) RFC 8707 `resource` identifier, or
|
|
24898
|
-
* `undefined` when neither is available (the `resource_metadata` parameter is
|
|
24899
|
-
* then omitted, matching the bearer-auth challenges).
|
|
24900
|
-
*
|
|
24901
|
-
* @internal
|
|
24902
|
-
*/
|
|
24903
|
-
function scopeChallengeResourceMetadataUrl(authInfo) {
|
|
24904
|
-
if (authInfo?.resourceMetadataUrl !== void 0) return authInfo.resourceMetadataUrl;
|
|
24905
|
-
if (authInfo?.resource?.protocol === "https:" || authInfo?.resource?.protocol === "http:") return getOAuthProtectedResourceMetadataUrl(authInfo.resource);
|
|
24906
|
-
}
|
|
24907
|
-
/** @internal */
|
|
24908
|
-
function createScopeChallengeResponse(challenge, resourceMetadataUrl) {
|
|
24909
|
-
return bearerAuthChallengeResponse(new OAuthError(OAuthErrorCode.InsufficientScope, challenge.errorDescription ?? "Insufficient scope"), {
|
|
24910
|
-
requiredScopes: [...challenge.scopes],
|
|
24911
|
-
resourceMetadataUrl
|
|
24912
|
-
});
|
|
24913
|
-
}
|
|
24914
|
-
/**
|
|
24915
|
-
* Default handler re-entries per originating request — tighter than the
|
|
24916
|
-
* client driver's 10 because the shim holds a live wire request open.
|
|
24917
|
-
*/
|
|
24918
|
-
const DEFAULT_LEGACY_SHIM_MAX_ROUNDS = 8;
|
|
24919
|
-
/** Default per-leg timeout: legs are human-paced, so the 60s protocol default is wrong. */
|
|
24920
|
-
const DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS = 6e5;
|
|
24921
|
-
/** Resolves and validates `ServerOptions.inputRequired`, failing loudly at construction time. */
|
|
24922
|
-
function resolveLegacyShimOptions(options) {
|
|
24923
|
-
if (options?.maxRounds !== void 0 && (!Number.isInteger(options.maxRounds) || options.maxRounds < 1)) throw new RangeError(`inputRequired.maxRounds must be a positive integer (got ${options.maxRounds})`);
|
|
24924
|
-
if (options?.roundTimeoutMs !== void 0 && (!Number.isFinite(options.roundTimeoutMs) || options.roundTimeoutMs <= 0)) throw new RangeError(`inputRequired.roundTimeoutMs must be a positive number (got ${options.roundTimeoutMs})`);
|
|
24925
|
-
return {
|
|
24926
|
-
maxRounds: options?.maxRounds ?? DEFAULT_LEGACY_SHIM_MAX_ROUNDS,
|
|
24927
|
-
roundTimeoutMs: options?.roundTimeoutMs ?? DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS,
|
|
24928
|
-
legacyShim: options?.legacyShim ?? true
|
|
24929
|
-
};
|
|
24930
|
-
}
|
|
24931
|
-
/**
|
|
24932
|
-
* Validates one `inputRequests` entry: malformed or unknown kinds are server
|
|
24933
|
-
* bugs and fail loudly on both eras. Shared by the modern seam's capability
|
|
24934
|
-
* check and the shim's gate.
|
|
24935
|
-
*/
|
|
24936
|
-
function coerceEmbeddedInputRequest(method, key, entry) {
|
|
24937
|
-
if (entry === null || typeof entry !== "object" || typeof entry.method !== "string") throw new ProtocolError(ProtocolErrorCode.InternalError, `Handler for ${method} returned an invalid input request '${key}': each inputRequests entry must be an embedded elicitation/create, sampling/createMessage, or roots/list request`);
|
|
24938
|
-
const embedded = entry;
|
|
24939
|
-
const required = requiredClientCapabilitiesForInputRequest(embedded);
|
|
24940
|
-
if (required === void 0) throw new ProtocolError(ProtocolErrorCode.InternalError, `Handler for ${method} returned an input request '${key}' of kind '${embedded.method}', which is not an embedded request the 2026-07-28 revision defines`);
|
|
24941
|
-
return {
|
|
24942
|
-
embedded,
|
|
24943
|
-
required
|
|
24944
|
-
};
|
|
25274
|
+
function coerceEmbeddedInputRequest(method, key, entry) {
|
|
25275
|
+
if (entry === null || typeof entry !== "object" || typeof entry.method !== "string") throw new ProtocolError(ProtocolErrorCode.InternalError, `Handler for ${method} returned an invalid input request '${key}': each inputRequests entry must be an embedded elicitation/create, sampling/createMessage, or roots/list request`);
|
|
25276
|
+
const embedded = entry;
|
|
25277
|
+
const required = requiredClientCapabilitiesForInputRequest(embedded);
|
|
25278
|
+
if (required === void 0) throw new ProtocolError(ProtocolErrorCode.InternalError, `Handler for ${method} returned an input request '${key}' of kind '${embedded.method}', which is not an embedded request the 2026-07-28 revision defines`);
|
|
25279
|
+
return {
|
|
25280
|
+
embedded,
|
|
25281
|
+
required
|
|
25282
|
+
};
|
|
24945
25283
|
}
|
|
24946
25284
|
/**
|
|
24947
25285
|
* The 2025-11-25 URL-mode wire shape requires an `elicitationId`; the 2026
|
|
@@ -25129,6 +25467,7 @@ var Server = class extends Protocol {
|
|
|
25129
25467
|
_requestStateVerify;
|
|
25130
25468
|
_inputRequiredServing;
|
|
25131
25469
|
_legacyShim;
|
|
25470
|
+
_boundFromTransport = false;
|
|
25132
25471
|
/** Lazily-built legacy shim; the loop lives in legacyInputRequiredShim.ts behind a narrow host contract. */
|
|
25133
25472
|
_legacyInputRequiredShim() {
|
|
25134
25473
|
return this._legacyShim ??= new LegacyInputRequiredShim({
|
|
@@ -25168,6 +25507,15 @@ var Server = class extends Protocol {
|
|
|
25168
25507
|
/** Attaches to the given transport; rejects while this instance is connected to another one. */
|
|
25169
25508
|
async connect(transport) {
|
|
25170
25509
|
if (this.transport !== void 0) throw new SdkError(SdkErrorCode.AlreadyConnected, "Use a separate Server instance per connection: this instance is already connected to a transport. To connect it to a new transport, call close() first.");
|
|
25510
|
+
if (this._boundFromTransport) {
|
|
25511
|
+
this._boundFromTransport = false;
|
|
25512
|
+
this._negotiatedProtocolVersion = void 0;
|
|
25513
|
+
}
|
|
25514
|
+
const revision = perRequestClassificationOf(transport)?.revision;
|
|
25515
|
+
if (revision !== void 0 && !this._servedModernEra() && SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(revision) && modernProtocolVersions(this._supportedProtocolVersions).includes(revision)) {
|
|
25516
|
+
this._negotiatedProtocolVersion = revision;
|
|
25517
|
+
this._boundFromTransport = true;
|
|
25518
|
+
}
|
|
25171
25519
|
await super.connect(transport);
|
|
25172
25520
|
}
|
|
25173
25521
|
/**
|
|
@@ -25478,8 +25826,8 @@ var Server = class extends Protocol {
|
|
|
25478
25826
|
* @deprecated Read client identity from the per-request handler context instead: on
|
|
25479
25827
|
* 2026-07-28 (per-request envelope) requests `ctx.mcpReq.envelope` carries the client's
|
|
25480
25828
|
* declared capabilities, while on 2025-era connections this accessor keeps returning the
|
|
25481
|
-
* `initialize`-scoped value. The accessor remains functional
|
|
25482
|
-
* 2026-07-28 era
|
|
25829
|
+
* `initialize`-scoped value. The accessor remains functional where `createMcpHandler`
|
|
25830
|
+
* serves the 2026-07-28 era: it backfills it per request from the validated envelope.
|
|
25483
25831
|
*/
|
|
25484
25832
|
getClientCapabilities() {
|
|
25485
25833
|
return this._clientCapabilities;
|
|
@@ -25490,8 +25838,8 @@ var Server = class extends Protocol {
|
|
|
25490
25838
|
* @deprecated Read client identity from the per-request handler context instead: on
|
|
25491
25839
|
* 2026-07-28 (per-request envelope) requests `ctx.mcpReq.envelope` carries the client's
|
|
25492
25840
|
* name and version, while on 2025-era connections this accessor keeps returning the
|
|
25493
|
-
* `initialize`-scoped value. The accessor remains functional
|
|
25494
|
-
* 2026-07-28 era
|
|
25841
|
+
* `initialize`-scoped value. The accessor remains functional where `createMcpHandler`
|
|
25842
|
+
* serves the 2026-07-28 era: it backfills it per request from the validated envelope.
|
|
25495
25843
|
*/
|
|
25496
25844
|
getClientVersion() {
|
|
25497
25845
|
return this._clientVersion;
|
|
@@ -26084,8 +26432,14 @@ var McpServer = class {
|
|
|
26084
26432
|
if (updates.uri) this._registeredResources[updates.uri] = registeredResource;
|
|
26085
26433
|
}
|
|
26086
26434
|
if (updates.name !== void 0) registeredResource.name = updates.name;
|
|
26087
|
-
if (updates.title !== void 0) registeredResource.title = updates.title;
|
|
26088
26435
|
if (updates.metadata !== void 0) registeredResource.metadata = updates.metadata;
|
|
26436
|
+
if (updates.title !== void 0) {
|
|
26437
|
+
registeredResource.title = updates.title;
|
|
26438
|
+
registeredResource.metadata = {
|
|
26439
|
+
...registeredResource.metadata,
|
|
26440
|
+
title: updates.title
|
|
26441
|
+
};
|
|
26442
|
+
}
|
|
26089
26443
|
if (updates.callback !== void 0) registeredResource.readCallback = updates.callback;
|
|
26090
26444
|
if (updates.scopeChallenge !== void 0) registeredResource.scopeChallenge = updates.scopeChallenge === null ? void 0 : updates.scopeChallenge;
|
|
26091
26445
|
if (updates.enabled !== void 0) registeredResource.enabled = updates.enabled;
|
|
@@ -26111,9 +26465,15 @@ var McpServer = class {
|
|
|
26111
26465
|
delete this._registeredResourceTemplates[name];
|
|
26112
26466
|
if (updates.name) this._registeredResourceTemplates[updates.name] = registeredResourceTemplate;
|
|
26113
26467
|
}
|
|
26114
|
-
if (updates.title !== void 0) registeredResourceTemplate.title = updates.title;
|
|
26115
26468
|
if (updates.template !== void 0) registeredResourceTemplate.resourceTemplate = updates.template;
|
|
26116
26469
|
if (updates.metadata !== void 0) registeredResourceTemplate.metadata = updates.metadata;
|
|
26470
|
+
if (updates.title !== void 0) {
|
|
26471
|
+
registeredResourceTemplate.title = updates.title;
|
|
26472
|
+
registeredResourceTemplate.metadata = {
|
|
26473
|
+
...registeredResourceTemplate.metadata,
|
|
26474
|
+
title: updates.title
|
|
26475
|
+
};
|
|
26476
|
+
}
|
|
26117
26477
|
if (updates.callback !== void 0) registeredResourceTemplate.readCallback = updates.callback;
|
|
26118
26478
|
if (updates.scopeChallenge !== void 0) registeredResourceTemplate.scopeChallenge = updates.scopeChallenge === null ? void 0 : updates.scopeChallenge;
|
|
26119
26479
|
if (updates.enabled !== void 0) registeredResourceTemplate.enabled = updates.enabled;
|
|
@@ -26372,234 +26732,298 @@ function convertOutputSchemaJson(outputSchema) {
|
|
|
26372
26732
|
return;
|
|
26373
26733
|
}
|
|
26374
26734
|
}
|
|
26375
|
-
/**
|
|
26376
|
-
* Creates a type-safe prompt handler that captures the schema and callback in a closure.
|
|
26377
|
-
* This eliminates the need for type assertions at the call site.
|
|
26378
|
-
*/
|
|
26379
|
-
function createPromptHandler(name, argsSchema, callback) {
|
|
26380
|
-
if (argsSchema) {
|
|
26381
|
-
const typedCallback = callback;
|
|
26382
|
-
return async (args, ctx) => {
|
|
26383
|
-
const parseResult = await validateStandardSchema(argsSchema, args ?? {});
|
|
26384
|
-
if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parseResult.error}`);
|
|
26385
|
-
return typedCallback(parseResult.data, ctx);
|
|
26735
|
+
/**
|
|
26736
|
+
* Creates a type-safe prompt handler that captures the schema and callback in a closure.
|
|
26737
|
+
* This eliminates the need for type assertions at the call site.
|
|
26738
|
+
*/
|
|
26739
|
+
function createPromptHandler(name, argsSchema, callback) {
|
|
26740
|
+
if (argsSchema) {
|
|
26741
|
+
const typedCallback = callback;
|
|
26742
|
+
return async (args, ctx) => {
|
|
26743
|
+
const parseResult = await validateStandardSchema(argsSchema, args ?? {});
|
|
26744
|
+
if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parseResult.error}`);
|
|
26745
|
+
return typedCallback(parseResult.data, ctx);
|
|
26746
|
+
};
|
|
26747
|
+
} else {
|
|
26748
|
+
const typedCallback = callback;
|
|
26749
|
+
return async (_args, ctx) => {
|
|
26750
|
+
return typedCallback(ctx);
|
|
26751
|
+
};
|
|
26752
|
+
}
|
|
26753
|
+
}
|
|
26754
|
+
function createCompletionResult(suggestions) {
|
|
26755
|
+
return { completion: {
|
|
26756
|
+
values: suggestions.map(String).slice(0, 100),
|
|
26757
|
+
total: suggestions.length,
|
|
26758
|
+
hasMore: suggestions.length > 100
|
|
26759
|
+
} };
|
|
26760
|
+
}
|
|
26761
|
+
const EMPTY_COMPLETION_RESULT = { completion: {
|
|
26762
|
+
values: [],
|
|
26763
|
+
hasMore: false
|
|
26764
|
+
} };
|
|
26765
|
+
/** @internal Gets the shape of a Zod object schema */
|
|
26766
|
+
function getSchemaShape(schema) {
|
|
26767
|
+
const candidate = schema;
|
|
26768
|
+
if (candidate.shape && typeof candidate.shape === "object") return candidate.shape;
|
|
26769
|
+
}
|
|
26770
|
+
/** @internal Checks if a Zod schema is optional */
|
|
26771
|
+
function isOptionalSchema(schema) {
|
|
26772
|
+
return schema?.type === "optional";
|
|
26773
|
+
}
|
|
26774
|
+
/** @internal Unwraps an optional Zod schema */
|
|
26775
|
+
function unwrapOptionalSchema(schema) {
|
|
26776
|
+
if (!isOptionalSchema(schema)) return schema;
|
|
26777
|
+
return schema.def?.innerType ?? schema;
|
|
26778
|
+
}
|
|
26779
|
+
//#endregion
|
|
26780
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/listenRouter-Bartj63y.mjs
|
|
26781
|
+
/**
|
|
26782
|
+
* A `ServerEventBus` backed by an in-process listener set.
|
|
26783
|
+
*
|
|
26784
|
+
* `publish()` delivers synchronously to the live listener set (a listener
|
|
26785
|
+
* unsubscribing itself mid-dispatch is safe; the entry's listen-router
|
|
26786
|
+
* listeners never unsubscribe peers). A throwing listener does not stop
|
|
26787
|
+
* delivery to the others.
|
|
26788
|
+
*/
|
|
26789
|
+
var InMemoryServerEventBus = class {
|
|
26790
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
26791
|
+
/**
|
|
26792
|
+
* @param onerror - Optional callback for errors thrown by listeners
|
|
26793
|
+
* during dispatch.
|
|
26794
|
+
*/
|
|
26795
|
+
constructor(onerror) {
|
|
26796
|
+
this.onerror = onerror;
|
|
26797
|
+
}
|
|
26798
|
+
publish(event) {
|
|
26799
|
+
for (const listener of this._listeners) try {
|
|
26800
|
+
listener(event);
|
|
26801
|
+
} catch (error) {
|
|
26802
|
+
this.onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
26803
|
+
}
|
|
26804
|
+
}
|
|
26805
|
+
subscribe(listener) {
|
|
26806
|
+
this._listeners.add(listener);
|
|
26807
|
+
let live = true;
|
|
26808
|
+
return () => {
|
|
26809
|
+
if (!live) return;
|
|
26810
|
+
live = false;
|
|
26811
|
+
this._listeners.delete(listener);
|
|
26812
|
+
};
|
|
26813
|
+
}
|
|
26814
|
+
/** The number of currently registered listeners (test/introspection only — the routers track capacity via their own open-subscription set). */
|
|
26815
|
+
get listenerCount() {
|
|
26816
|
+
return this._listeners.size;
|
|
26817
|
+
}
|
|
26818
|
+
};
|
|
26819
|
+
/** Build a {@linkcode ServerNotifier} over a bus. */
|
|
26820
|
+
function createServerNotifier(bus) {
|
|
26821
|
+
return {
|
|
26822
|
+
toolsChanged: () => bus.publish({ kind: "tools_list_changed" }),
|
|
26823
|
+
promptsChanged: () => bus.publish({ kind: "prompts_list_changed" }),
|
|
26824
|
+
resourcesChanged: () => bus.publish({ kind: "resources_list_changed" }),
|
|
26825
|
+
resourceUpdated: (uri) => bus.publish({
|
|
26826
|
+
kind: "resource_updated",
|
|
26827
|
+
uri
|
|
26828
|
+
})
|
|
26829
|
+
};
|
|
26830
|
+
}
|
|
26831
|
+
/**
|
|
26832
|
+
* Whether a `subscriptions/listen` filter accepts a given change event.
|
|
26833
|
+
*
|
|
26834
|
+
* Pure: no I/O, no mutation. The filter governs ONLY the four
|
|
26835
|
+
* subscription-gated change types — non-gated notifications never reach the
|
|
26836
|
+
* bus and are not modeled here.
|
|
26837
|
+
*
|
|
26838
|
+
* `resource_updated` matches only when `resourceSubscriptions` is present and
|
|
26839
|
+
* contains the event's URI exactly (per the spec: "for these resource URIs").
|
|
26840
|
+
*/
|
|
26841
|
+
function listenFilterAccepts(filter, event) {
|
|
26842
|
+
switch (event.kind) {
|
|
26843
|
+
case "tools_list_changed": return filter.toolsListChanged === true;
|
|
26844
|
+
case "prompts_list_changed": return filter.promptsListChanged === true;
|
|
26845
|
+
case "resources_list_changed": return filter.resourcesListChanged === true;
|
|
26846
|
+
case "resource_updated": return filter.resourceSubscriptions !== void 0 && filter.resourceSubscriptions.includes(event.uri);
|
|
26847
|
+
}
|
|
26848
|
+
}
|
|
26849
|
+
/**
|
|
26850
|
+
* The honored subset of a requested filter: keeps only the fields the client
|
|
26851
|
+
* explicitly opted in to (drops `false` and absent fields), narrowed against
|
|
26852
|
+
* the server's declared capabilities when supplied. The serving entry sends
|
|
26853
|
+
* this back in `notifications/subscriptions/acknowledged` so the ack reflects
|
|
26854
|
+
* what the server can actually deliver.
|
|
26855
|
+
*
|
|
26856
|
+
* - `toolsListChanged` is honored only when `capabilities.tools.listChanged`
|
|
26857
|
+
* is advertised; likewise `promptsListChanged` / `resourcesListChanged`.
|
|
26858
|
+
* - `resourceSubscriptions` is honored only when
|
|
26859
|
+
* `capabilities.resources.subscribe` is advertised.
|
|
26860
|
+
*
|
|
26861
|
+
* `capabilities` is optional on this pure helper for test convenience only —
|
|
26862
|
+
* both wired routers REQUIRE capabilities at the call site (the HTTP router's
|
|
26863
|
+
* `serve()` takes a required parameter; `StdioListenRouter.serve()` throws
|
|
26864
|
+
* before `setServerCapabilities()` was called), so the fail-open
|
|
26865
|
+
* `undefined → honor everything` branch is never reachable on a wired entry.
|
|
26866
|
+
*/
|
|
26867
|
+
function honoredSubset(requested, capabilities) {
|
|
26868
|
+
const honored = {};
|
|
26869
|
+
const allow = (bit) => capabilities === void 0 || bit === true;
|
|
26870
|
+
if (requested.toolsListChanged === true && allow(capabilities?.tools?.listChanged)) honored.toolsListChanged = true;
|
|
26871
|
+
if (requested.promptsListChanged === true && allow(capabilities?.prompts?.listChanged)) honored.promptsListChanged = true;
|
|
26872
|
+
if (requested.resourcesListChanged === true && allow(capabilities?.resources?.listChanged)) honored.resourcesListChanged = true;
|
|
26873
|
+
if (requested.resourceSubscriptions !== void 0 && requested.resourceSubscriptions.length > 0 && allow(capabilities?.resources?.subscribe)) honored.resourceSubscriptions = [...requested.resourceSubscriptions];
|
|
26874
|
+
return honored;
|
|
26875
|
+
}
|
|
26876
|
+
/** Map a {@linkcode ServerEvent} onto its wire notification `{method, params}`. */
|
|
26877
|
+
function serverEventToNotification(event) {
|
|
26878
|
+
switch (event.kind) {
|
|
26879
|
+
case "tools_list_changed": return {
|
|
26880
|
+
method: "notifications/tools/list_changed",
|
|
26881
|
+
...event.params !== void 0 && { params: event.params }
|
|
26386
26882
|
};
|
|
26387
|
-
|
|
26388
|
-
|
|
26389
|
-
|
|
26390
|
-
|
|
26883
|
+
case "prompts_list_changed": return {
|
|
26884
|
+
method: "notifications/prompts/list_changed",
|
|
26885
|
+
...event.params !== void 0 && { params: event.params }
|
|
26886
|
+
};
|
|
26887
|
+
case "resources_list_changed": return {
|
|
26888
|
+
method: "notifications/resources/list_changed",
|
|
26889
|
+
...event.params !== void 0 && { params: event.params }
|
|
26890
|
+
};
|
|
26891
|
+
case "resource_updated": return {
|
|
26892
|
+
method: "notifications/resources/updated",
|
|
26893
|
+
params: {
|
|
26894
|
+
...event.params,
|
|
26895
|
+
uri: event.uri
|
|
26896
|
+
}
|
|
26391
26897
|
};
|
|
26392
26898
|
}
|
|
26393
26899
|
}
|
|
26394
|
-
|
|
26395
|
-
|
|
26396
|
-
|
|
26397
|
-
|
|
26398
|
-
|
|
26399
|
-
|
|
26400
|
-
|
|
26401
|
-
|
|
26402
|
-
|
|
26403
|
-
|
|
26404
|
-
} };
|
|
26405
|
-
/** @internal Gets the shape of a Zod object schema */
|
|
26406
|
-
function getSchemaShape(schema) {
|
|
26407
|
-
const candidate = schema;
|
|
26408
|
-
if (candidate.shape && typeof candidate.shape === "object") return candidate.shape;
|
|
26409
|
-
}
|
|
26410
|
-
/** @internal Checks if a Zod schema is optional */
|
|
26411
|
-
function isOptionalSchema(schema) {
|
|
26412
|
-
return schema?.type === "optional";
|
|
26900
|
+
/** Default capacity guard: refuse a new subscription when this many are already open. */
|
|
26901
|
+
const DEFAULT_MAX_SUBSCRIPTIONS = 1024;
|
|
26902
|
+
function jsonRpcError(id, code, message) {
|
|
26903
|
+
return Response.json({
|
|
26904
|
+
jsonrpc: "2.0",
|
|
26905
|
+
error: {
|
|
26906
|
+
code,
|
|
26907
|
+
message
|
|
26908
|
+
},
|
|
26909
|
+
id
|
|
26910
|
+
}, { status: 200 });
|
|
26413
26911
|
}
|
|
26414
|
-
/**
|
|
26415
|
-
function
|
|
26416
|
-
|
|
26417
|
-
|
|
26912
|
+
/** Stamp the subscription id onto a notification's `_meta`. Non-mutating. */
|
|
26913
|
+
function stampSubscriptionId(notification, subscriptionId) {
|
|
26914
|
+
return {
|
|
26915
|
+
method: notification.method,
|
|
26916
|
+
params: {
|
|
26917
|
+
...notification.params,
|
|
26918
|
+
_meta: {
|
|
26919
|
+
...notification.params?._meta,
|
|
26920
|
+
[SUBSCRIPTION_ID_META_KEY]: subscriptionId
|
|
26921
|
+
}
|
|
26922
|
+
}
|
|
26923
|
+
};
|
|
26418
26924
|
}
|
|
26419
|
-
//#endregion
|
|
26420
|
-
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.3.1/node_modules/@modelcontextprotocol/server/dist/index.mjs
|
|
26421
26925
|
/**
|
|
26422
|
-
*
|
|
26423
|
-
*
|
|
26424
|
-
*
|
|
26926
|
+
* Read the requested filter off a `subscriptions/listen` request body.
|
|
26927
|
+
* Returns the validated filter, or `undefined` when `params.notifications`
|
|
26928
|
+
* is absent or fails the schema (the caller answers `-32602` — the spec
|
|
26929
|
+
* marks `notifications` REQUIRED on the listen request).
|
|
26425
26930
|
*/
|
|
26426
|
-
|
|
26427
|
-
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
|
|
26431
|
-
|
|
26432
|
-
|
|
26433
|
-
|
|
26434
|
-
|
|
26435
|
-
|
|
26436
|
-
|
|
26437
|
-
|
|
26438
|
-
|
|
26439
|
-
* registry gate, the edge→instance handoff check, the missing-handler
|
|
26440
|
-
* rejection) answer inside this window; request handlers always run
|
|
26441
|
-
* after it (the protocol layer defers them to a microtask). An error
|
|
26442
|
-
* sent inside the window is therefore ladder-originated, and an error
|
|
26443
|
-
* sent after it is handler-produced.
|
|
26444
|
-
*/
|
|
26445
|
-
_dispatchWindowOpen = false;
|
|
26446
|
-
_requestId;
|
|
26447
|
-
_deferredResponse;
|
|
26448
|
-
_sse;
|
|
26449
|
-
_abortCleanup;
|
|
26450
|
-
_keepAliveMs;
|
|
26451
|
-
constructor(options) {
|
|
26452
|
-
this._classification = options.classification;
|
|
26453
|
-
this._responseMode = options.responseMode ?? "auto";
|
|
26454
|
-
this._keepAliveMs = options.keepAliveMs ?? 15e3;
|
|
26455
|
-
}
|
|
26456
|
-
async start() {
|
|
26457
|
-
if (this._started) throw new Error("PerRequestHTTPServerTransport is already started");
|
|
26458
|
-
this._started = true;
|
|
26459
|
-
}
|
|
26460
|
-
/**
|
|
26461
|
-
* Serves the single exchange: delivers the classified message to the
|
|
26462
|
-
* connected server instance and resolves with the HTTP response.
|
|
26463
|
-
*
|
|
26464
|
-
* Throws when called a second time (the transport is strictly
|
|
26465
|
-
* single-use), or before a server has been connected to the transport.
|
|
26466
|
-
* The returned promise rejects with a connection-closed error when the
|
|
26467
|
-
* transport is closed before a response was produced (for example because
|
|
26468
|
-
* the client disconnected).
|
|
26469
|
-
*/
|
|
26470
|
-
async handleMessage(message, extra) {
|
|
26471
|
-
if (this._used) throw new Error("PerRequestHTTPServerTransport serves exactly one exchange; construct a new transport per request");
|
|
26472
|
-
if (!this._started || this.onmessage === void 0) throw new Error("PerRequestHTTPServerTransport is not connected: connect a server to this transport before handling a message");
|
|
26473
|
-
if (this._closed) throw new Error("PerRequestHTTPServerTransport is closed");
|
|
26474
|
-
this._used = true;
|
|
26475
|
-
const signal = extra?.request?.signal;
|
|
26476
|
-
if (signal?.aborted) {
|
|
26477
|
-
await this.close();
|
|
26478
|
-
throw new SdkError(SdkErrorCode.ConnectionClosed, "The request was aborted before it could be handled");
|
|
26931
|
+
function parseListenFilter(message) {
|
|
26932
|
+
const outcome = codecForVersion(MODERN_WIRE_REVISION).validateRequest("subscriptions/listen", message);
|
|
26933
|
+
return outcome.ok ? outcome.value.params?.notifications : void 0;
|
|
26934
|
+
}
|
|
26935
|
+
function createListenRouter(options) {
|
|
26936
|
+
const { bus, onerror } = options;
|
|
26937
|
+
const maxSubscriptions = options.maxSubscriptions ?? 1024;
|
|
26938
|
+
const keepAliveMs = options.keepAliveMs ?? 15e3;
|
|
26939
|
+
const open = /* @__PURE__ */ new Set();
|
|
26940
|
+
function serve(message, signal, capabilities, serverInfo) {
|
|
26941
|
+
if (open.size >= maxSubscriptions) {
|
|
26942
|
+
onerror?.(/* @__PURE__ */ new Error(`subscriptions/listen refused: subscription limit reached (${maxSubscriptions})`));
|
|
26943
|
+
return jsonRpcError(message.id, -32603, "Subscription limit reached");
|
|
26479
26944
|
}
|
|
26480
|
-
const
|
|
26481
|
-
|
|
26482
|
-
|
|
26483
|
-
|
|
26484
|
-
|
|
26485
|
-
|
|
26486
|
-
|
|
26487
|
-
|
|
26488
|
-
|
|
26489
|
-
|
|
26490
|
-
|
|
26491
|
-
|
|
26492
|
-
});
|
|
26493
|
-
this._deferredResponse = {
|
|
26494
|
-
promise,
|
|
26495
|
-
resolve,
|
|
26496
|
-
reject,
|
|
26497
|
-
settled: false
|
|
26498
|
-
};
|
|
26499
|
-
if (signal !== void 0) {
|
|
26500
|
-
const onAbort = () => void this.close();
|
|
26501
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
26502
|
-
this._abortCleanup = () => signal.removeEventListener("abort", onAbort);
|
|
26503
|
-
}
|
|
26504
|
-
this._dispatchWindowOpen = true;
|
|
26945
|
+
const filter = parseListenFilter(message);
|
|
26946
|
+
if (filter === void 0) return jsonRpcError(message.id, -32602, "Invalid params: 'notifications' is required and must be a valid SubscriptionFilter");
|
|
26947
|
+
const honored = honoredSubset(filter, capabilities);
|
|
26948
|
+
const subscriptionId = message.id;
|
|
26949
|
+
const encoder = new TextEncoder();
|
|
26950
|
+
let controller;
|
|
26951
|
+
let closed = false;
|
|
26952
|
+
let unsubscribe;
|
|
26953
|
+
let keepAliveTimer;
|
|
26954
|
+
let abortCleanup;
|
|
26955
|
+
const writeFrame = (frame) => {
|
|
26956
|
+
if (closed) return;
|
|
26505
26957
|
try {
|
|
26506
|
-
|
|
26507
|
-
}
|
|
26508
|
-
|
|
26509
|
-
}
|
|
26510
|
-
if (this._responseMode === "sse" && !this._closed && !this._deferredResponse.settled) this.upgradeToSse();
|
|
26511
|
-
return promise;
|
|
26512
|
-
}
|
|
26513
|
-
this.onmessage(message, messageExtra);
|
|
26514
|
-
return new Response(null, { status: 202 });
|
|
26515
|
-
}
|
|
26516
|
-
async send(message, options) {
|
|
26517
|
-
if (this._closed) return;
|
|
26518
|
-
const isResponse = isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message);
|
|
26519
|
-
const relatedId = isResponse ? message.id : options?.relatedRequestId;
|
|
26520
|
-
if (this._requestId === void 0 || relatedId === void 0 || relatedId !== this._requestId) {
|
|
26521
|
-
if (isResponse) this.onerror?.(/* @__PURE__ */ new Error(`Received a response for an unknown request id: ${String(message.id)}`));
|
|
26522
|
-
return;
|
|
26523
|
-
}
|
|
26524
|
-
if (isResponse) {
|
|
26525
|
-
if (this._terminalDelivered) return;
|
|
26526
|
-
this._terminalDelivered = true;
|
|
26527
|
-
const errorCode = isJSONRPCErrorResponse(message) ? message.error.code : void 0;
|
|
26528
|
-
const ladderStatus = errorCode !== void 0 && (this._dispatchWindowOpen || errorCode === ProtocolErrorCode.MissingRequiredClientCapability) ? LADDER_ERROR_HTTP_STATUS[errorCode] : void 0;
|
|
26529
|
-
if (ladderStatus !== void 0 && this._sse === void 0) {
|
|
26530
|
-
this.settleResponse(Response.json(message, {
|
|
26531
|
-
status: ladderStatus,
|
|
26532
|
-
headers: { "Content-Type": "application/json" }
|
|
26533
|
-
}));
|
|
26534
|
-
queueMicrotask(() => void this.close());
|
|
26535
|
-
return;
|
|
26536
|
-
}
|
|
26537
|
-
if (this._sse !== void 0 || this._responseMode === "sse") {
|
|
26538
|
-
if (this._sse === void 0) this.upgradeToSse();
|
|
26539
|
-
this.writeMessageFrame(message);
|
|
26540
|
-
this.finalizeStream();
|
|
26541
|
-
return;
|
|
26958
|
+
controller.enqueue(encoder.encode(frame));
|
|
26959
|
+
} catch (error) {
|
|
26960
|
+
onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
26542
26961
|
}
|
|
26543
|
-
|
|
26544
|
-
|
|
26545
|
-
|
|
26546
|
-
|
|
26547
|
-
|
|
26548
|
-
|
|
26549
|
-
|
|
26550
|
-
|
|
26551
|
-
|
|
26552
|
-
|
|
26553
|
-
|
|
26554
|
-
|
|
26555
|
-
|
|
26556
|
-
|
|
26557
|
-
|
|
26558
|
-
|
|
26559
|
-
|
|
26560
|
-
|
|
26561
|
-
|
|
26562
|
-
|
|
26563
|
-
|
|
26564
|
-
|
|
26565
|
-
this._closed = true;
|
|
26566
|
-
this._abortCleanup?.();
|
|
26567
|
-
this._abortCleanup = void 0;
|
|
26568
|
-
if (this._sse?.keepAliveTimer !== void 0) clearInterval(this._sse.keepAliveTimer);
|
|
26569
|
-
if (this._sse !== void 0 && !this._sse.closed) {
|
|
26570
|
-
this._sse.closed = true;
|
|
26962
|
+
};
|
|
26963
|
+
const writeNotification = (method, params) => {
|
|
26964
|
+
writeFrame(`event: message\ndata: ${JSON.stringify({
|
|
26965
|
+
jsonrpc: "2.0",
|
|
26966
|
+
method,
|
|
26967
|
+
params
|
|
26968
|
+
})}\n\n`);
|
|
26969
|
+
};
|
|
26970
|
+
const teardown = (graceful) => {
|
|
26971
|
+
if (closed) return;
|
|
26972
|
+
if (graceful) writeFrame(`event: message\ndata: ${JSON.stringify({
|
|
26973
|
+
jsonrpc: "2.0",
|
|
26974
|
+
id: subscriptionId,
|
|
26975
|
+
result: {
|
|
26976
|
+
resultType: "complete",
|
|
26977
|
+
_meta: {
|
|
26978
|
+
[SUBSCRIPTION_ID_META_KEY]: subscriptionId,
|
|
26979
|
+
[SERVER_INFO_META_KEY]: serverInfo
|
|
26980
|
+
}
|
|
26981
|
+
}
|
|
26982
|
+
})}\n\n`);
|
|
26983
|
+
closed = true;
|
|
26571
26984
|
try {
|
|
26572
|
-
|
|
26985
|
+
unsubscribe?.();
|
|
26986
|
+
} catch (error) {
|
|
26987
|
+
onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
26988
|
+
}
|
|
26989
|
+
if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer);
|
|
26990
|
+
abortCleanup?.();
|
|
26991
|
+
open.delete(teardown);
|
|
26992
|
+
try {
|
|
26993
|
+
controller.close();
|
|
26573
26994
|
} catch {}
|
|
26574
|
-
}
|
|
26575
|
-
if (this._deferredResponse !== void 0 && !this._deferredResponse.settled) {
|
|
26576
|
-
this._deferredResponse.settled = true;
|
|
26577
|
-
this._deferredResponse.reject(new SdkError(SdkErrorCode.ConnectionClosed, "Connection closed before a response was produced"));
|
|
26578
|
-
}
|
|
26579
|
-
this.onclose?.();
|
|
26580
|
-
}
|
|
26581
|
-
settleResponse(response) {
|
|
26582
|
-
if (this._deferredResponse === void 0 || this._deferredResponse.settled) return;
|
|
26583
|
-
this._deferredResponse.settled = true;
|
|
26584
|
-
this._deferredResponse.resolve(response);
|
|
26585
|
-
}
|
|
26586
|
-
upgradeToSse() {
|
|
26587
|
-
let controller;
|
|
26995
|
+
};
|
|
26588
26996
|
const readable = new ReadableStream({
|
|
26589
|
-
start
|
|
26997
|
+
start(streamController) {
|
|
26590
26998
|
controller = streamController;
|
|
26999
|
+
const ack = stampSubscriptionId({
|
|
27000
|
+
method: "notifications/subscriptions/acknowledged",
|
|
27001
|
+
params: { notifications: honored }
|
|
27002
|
+
}, subscriptionId);
|
|
27003
|
+
writeNotification(ack.method, ack.params);
|
|
27004
|
+
if (Object.keys(honored).length === 0) {
|
|
27005
|
+
teardown(true);
|
|
27006
|
+
return;
|
|
27007
|
+
}
|
|
27008
|
+
unsubscribe = bus.subscribe((event) => {
|
|
27009
|
+
if (closed || !listenFilterAccepts(honored, event)) return;
|
|
27010
|
+
const note = stampSubscriptionId(serverEventToNotification(event), subscriptionId);
|
|
27011
|
+
writeNotification(note.method, note.params);
|
|
27012
|
+
});
|
|
27013
|
+
keepAliveTimer = armSseKeepAlive(keepAliveMs, () => writeFrame(": keepalive\n\n"));
|
|
27014
|
+
open.add(teardown);
|
|
26591
27015
|
},
|
|
26592
|
-
cancel
|
|
26593
|
-
|
|
27016
|
+
cancel() {
|
|
27017
|
+
teardown(false);
|
|
26594
27018
|
}
|
|
26595
27019
|
});
|
|
26596
|
-
|
|
26597
|
-
|
|
26598
|
-
|
|
26599
|
-
|
|
26600
|
-
|
|
26601
|
-
|
|
26602
|
-
|
|
27020
|
+
if (signal !== void 0) if (signal.aborted) teardown(false);
|
|
27021
|
+
else {
|
|
27022
|
+
const onAbort = () => teardown(false);
|
|
27023
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
27024
|
+
abortCleanup = () => signal.removeEventListener("abort", onAbort);
|
|
27025
|
+
}
|
|
27026
|
+
return new Response(readable, {
|
|
26603
27027
|
status: 200,
|
|
26604
27028
|
headers: {
|
|
26605
27029
|
"Content-Type": "text/event-stream",
|
|
@@ -26607,30 +27031,170 @@ var PerRequestHTTPServerTransport = class {
|
|
|
26607
27031
|
Connection: "keep-alive",
|
|
26608
27032
|
"X-Accel-Buffering": "no"
|
|
26609
27033
|
}
|
|
26610
|
-
})
|
|
27034
|
+
});
|
|
26611
27035
|
}
|
|
26612
|
-
|
|
26613
|
-
|
|
26614
|
-
|
|
26615
|
-
|
|
26616
|
-
|
|
26617
|
-
|
|
26618
|
-
|
|
27036
|
+
return {
|
|
27037
|
+
serve,
|
|
27038
|
+
closeAll() {
|
|
27039
|
+
for (const teardown of open) teardown(true);
|
|
27040
|
+
},
|
|
27041
|
+
get openCount() {
|
|
27042
|
+
return open.size;
|
|
26619
27043
|
}
|
|
26620
|
-
|
|
27044
|
+
};
|
|
27045
|
+
}
|
|
27046
|
+
const CHANGE_NOTIFICATION_METHODS = /* @__PURE__ */ new Set([
|
|
27047
|
+
"notifications/tools/list_changed",
|
|
27048
|
+
"notifications/prompts/list_changed",
|
|
27049
|
+
"notifications/resources/list_changed",
|
|
27050
|
+
"notifications/resources/updated"
|
|
27051
|
+
]);
|
|
27052
|
+
/**
|
|
27053
|
+
* Per-connection listen state for the stdio entry. One instance is held by
|
|
27054
|
+
* `serveStdio` for the connection lifetime; it routes inbound
|
|
27055
|
+
* `subscriptions/listen` / `notifications/cancelled` and rewrites outbound
|
|
27056
|
+
* change notifications onto the active subscriptions. No bus — the long-lived
|
|
27057
|
+
* pinned instance's existing `send*ListChanged()` calls feed straight into
|
|
27058
|
+
* `routeOutbound()`.
|
|
27059
|
+
*/
|
|
27060
|
+
var StdioListenRouter = class {
|
|
27061
|
+
/** Active subscriptions, keyed by the listen request's JSON-RPC id verbatim. */
|
|
27062
|
+
_subs = /* @__PURE__ */ new Map();
|
|
27063
|
+
/**
|
|
27064
|
+
* The serving instance's declared capabilities. Filled in by the entry
|
|
27065
|
+
* once the modern instance is constructed (the router is created before
|
|
27066
|
+
* the instance exists), so the acknowledged filter is narrowed against
|
|
27067
|
+
* what the server can actually deliver.
|
|
27068
|
+
*/
|
|
27069
|
+
_serverCapabilities;
|
|
27070
|
+
/**
|
|
27071
|
+
* The serving instance's identity, stamped onto the graceful-close
|
|
27072
|
+
* results' `_meta` (the spec's `SubscriptionsListenResultMetaObject` extends
|
|
27073
|
+
* `ResultMetaObject`). Handed over together with the capabilities.
|
|
27074
|
+
*/
|
|
27075
|
+
_serverInfo;
|
|
27076
|
+
constructor(_maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS, serverCapabilities, serverInfo) {
|
|
27077
|
+
this._maxSubscriptions = _maxSubscriptions;
|
|
27078
|
+
this._serverCapabilities = serverCapabilities;
|
|
27079
|
+
this._serverInfo = serverInfo;
|
|
26621
27080
|
}
|
|
26622
|
-
|
|
26623
|
-
|
|
27081
|
+
/**
|
|
27082
|
+
* Record the serving instance's declared capabilities and identity once
|
|
27083
|
+
* it has been constructed. Called by `serveStdio`'s connect path;
|
|
27084
|
+
* subsequent `serve()` calls narrow the honored filter against the
|
|
27085
|
+
* capabilities, and `teardownAll()` stamps the identity.
|
|
27086
|
+
*/
|
|
27087
|
+
setServerCapabilities(capabilities, serverInfo) {
|
|
27088
|
+
this._serverCapabilities = capabilities;
|
|
27089
|
+
if (serverInfo !== void 0) this._serverInfo = serverInfo;
|
|
26624
27090
|
}
|
|
26625
|
-
|
|
26626
|
-
|
|
26627
|
-
|
|
26628
|
-
|
|
26629
|
-
|
|
26630
|
-
|
|
26631
|
-
|
|
27091
|
+
/** Whether `id` is an active listen subscription on this connection. */
|
|
27092
|
+
has(id) {
|
|
27093
|
+
return this._subs.has(id);
|
|
27094
|
+
}
|
|
27095
|
+
/**
|
|
27096
|
+
* Serve one inbound `subscriptions/listen` request: registers the
|
|
27097
|
+
* subscription and returns the stamped acknowledged notification (or, on
|
|
27098
|
+
* capacity / params rejection, the in-band JSON-RPC error response).
|
|
27099
|
+
*
|
|
27100
|
+
* @throws when called before {@linkcode setServerCapabilities} (or the
|
|
27101
|
+
* constructor) has supplied the serving instance's capabilities. Honoring a
|
|
27102
|
+
* filter without knowing the server's advertised capabilities would fail
|
|
27103
|
+
* open (deliver unadvertised types); the entry guarantees capabilities are
|
|
27104
|
+
* set before any listen request is routed here.
|
|
27105
|
+
*/
|
|
27106
|
+
serve(message) {
|
|
27107
|
+
if (this._serverCapabilities === void 0) throw new Error("StdioListenRouter.serve() called before setServerCapabilities(); refusing to honor a filter without capabilities");
|
|
27108
|
+
if (this._subs.size >= this._maxSubscriptions) return {
|
|
27109
|
+
jsonrpc: "2.0",
|
|
27110
|
+
id: message.id,
|
|
27111
|
+
error: {
|
|
27112
|
+
code: -32603,
|
|
27113
|
+
message: "Subscription limit reached"
|
|
27114
|
+
}
|
|
27115
|
+
};
|
|
27116
|
+
const filter = parseListenFilter(message);
|
|
27117
|
+
if (filter === void 0) return {
|
|
27118
|
+
jsonrpc: "2.0",
|
|
27119
|
+
id: message.id,
|
|
27120
|
+
error: {
|
|
27121
|
+
code: -32602,
|
|
27122
|
+
message: "Invalid params: 'notifications' is required and must be a valid SubscriptionFilter"
|
|
27123
|
+
}
|
|
27124
|
+
};
|
|
27125
|
+
const honored = honoredSubset(filter, this._serverCapabilities);
|
|
27126
|
+
this._subs.set(message.id, honored);
|
|
27127
|
+
return stampSubscriptionId({
|
|
27128
|
+
method: "notifications/subscriptions/acknowledged",
|
|
27129
|
+
params: { notifications: honored }
|
|
27130
|
+
}, message.id);
|
|
27131
|
+
}
|
|
27132
|
+
/**
|
|
27133
|
+
* Tear down one subscription (inbound `notifications/cancelled`). Returns
|
|
27134
|
+
* `true` when a subscription was removed. After this call NOTHING further
|
|
27135
|
+
* is delivered for that subscription id (the post-cancel hardening).
|
|
27136
|
+
*/
|
|
27137
|
+
cancel(id) {
|
|
27138
|
+
return this._subs.delete(id);
|
|
27139
|
+
}
|
|
27140
|
+
/**
|
|
27141
|
+
* Route an outbound notification through the active subscriptions.
|
|
27142
|
+
*
|
|
27143
|
+
* - For a subscription-gated change notification, returns one stamped copy
|
|
27144
|
+
* per subscription that opted in to it (an empty array means it is
|
|
27145
|
+
* dropped — the modern era never delivers an un-requested change type).
|
|
27146
|
+
* - For any other outbound message, returns `'passthrough'` (the entry
|
|
27147
|
+
* forwards it as-is).
|
|
27148
|
+
*/
|
|
27149
|
+
routeOutbound(message) {
|
|
27150
|
+
if (!CHANGE_NOTIFICATION_METHODS.has(message.method)) return "passthrough";
|
|
27151
|
+
const uriParam = message.params?.["uri"];
|
|
27152
|
+
const uri = typeof uriParam === "string" ? uriParam : void 0;
|
|
27153
|
+
const event = notificationToServerEvent(message.method, uri);
|
|
27154
|
+
const out = [];
|
|
27155
|
+
for (const [subscriptionId, filter] of this._subs) if (listenFilterAccepts(filter, event)) out.push(stampSubscriptionId({
|
|
27156
|
+
method: message.method,
|
|
27157
|
+
params: message.params ?? {}
|
|
27158
|
+
}, subscriptionId));
|
|
27159
|
+
return out;
|
|
27160
|
+
}
|
|
27161
|
+
/**
|
|
27162
|
+
* Server-side graceful teardown of every active subscription: returns the
|
|
27163
|
+
* empty `subscriptions/listen` JSON-RPC result for each subscription id —
|
|
27164
|
+
* the spec's graceful-close signal, `_meta` carrying the subscription id
|
|
27165
|
+
* and the serving instance's identity — for the entry to emit before
|
|
27166
|
+
* closing the wire. Clears the set so nothing further is delivered.
|
|
27167
|
+
*/
|
|
27168
|
+
teardownAll() {
|
|
27169
|
+
const out = [];
|
|
27170
|
+
for (const id of this._subs.keys()) out.push({
|
|
27171
|
+
jsonrpc: "2.0",
|
|
27172
|
+
id,
|
|
27173
|
+
result: {
|
|
27174
|
+
resultType: "complete",
|
|
27175
|
+
_meta: {
|
|
27176
|
+
[SUBSCRIPTION_ID_META_KEY]: id,
|
|
27177
|
+
...this._serverInfo !== void 0 && { ["io.modelcontextprotocol/serverInfo"]: this._serverInfo }
|
|
27178
|
+
}
|
|
27179
|
+
}
|
|
27180
|
+
});
|
|
27181
|
+
this._subs.clear();
|
|
27182
|
+
return out;
|
|
26632
27183
|
}
|
|
26633
27184
|
};
|
|
27185
|
+
function notificationToServerEvent(method, uri) {
|
|
27186
|
+
switch (method) {
|
|
27187
|
+
case "notifications/tools/list_changed": return { kind: "tools_list_changed" };
|
|
27188
|
+
case "notifications/prompts/list_changed": return { kind: "prompts_list_changed" };
|
|
27189
|
+
case "notifications/resources/list_changed": return { kind: "resources_list_changed" };
|
|
27190
|
+
default: return {
|
|
27191
|
+
kind: "resource_updated",
|
|
27192
|
+
uri: uri ?? ""
|
|
27193
|
+
};
|
|
27194
|
+
}
|
|
27195
|
+
}
|
|
27196
|
+
//#endregion
|
|
27197
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/index.mjs
|
|
26634
27198
|
/**
|
|
26635
27199
|
* Serves one classified inbound message on the given server instance and
|
|
26636
27200
|
* returns the HTTP response for the exchange.
|
|
@@ -27430,7 +27994,10 @@ function jsonRpcErrorResponse(httpStatus, code, message, data, id = null) {
|
|
|
27430
27994
|
...data !== void 0 && { data }
|
|
27431
27995
|
},
|
|
27432
27996
|
id
|
|
27433
|
-
}, {
|
|
27997
|
+
}, {
|
|
27998
|
+
status: httpStatus,
|
|
27999
|
+
...httpStatus === 405 && { headers: { Allow: "POST" } }
|
|
28000
|
+
});
|
|
27434
28001
|
}
|
|
27435
28002
|
function rejectionResponse(rejection, id = null) {
|
|
27436
28003
|
return jsonRpcErrorResponse(rejection.httpStatus, rejection.code, rejection.message, rejection.data, id);
|
|
@@ -27793,7 +28360,7 @@ function createMcpHandler(factory, options = {}) {
|
|
|
27793
28360
|
const inputSchema = toolName === void 0 ? void 0 : product.toolInputSchemaJson(toolName);
|
|
27794
28361
|
if (inputSchema !== void 0) {
|
|
27795
28362
|
const scan = scanXMcpHeaderDeclarations(inputSchema);
|
|
27796
|
-
if (scan.
|
|
28363
|
+
if (scan.declarations !== void 0 && scan.declarations.length > 0) {
|
|
27797
28364
|
const rejection = validateMcpParamHeaders(scan.declarations, callParams?.arguments, request.headers);
|
|
27798
28365
|
if (rejection !== void 0) {
|
|
27799
28366
|
product.close().catch(reportError);
|
|
@@ -28419,7 +28986,7 @@ const memoisedUntilFailure = (load) => {
|
|
|
28419
28986
|
* processes never touch an article, and it is the heaviest code in the bundle.
|
|
28420
28987
|
* `tests/unit/module-graph.test.ts` keeps it off the static graph.
|
|
28421
28988
|
*/
|
|
28422
|
-
const loadArticleFormat = memoisedUntilFailure(() => import("./article-sections-
|
|
28989
|
+
const loadArticleFormat = memoisedUntilFailure(() => import("./article-sections-DA7_Jm2H.js"));
|
|
28423
28990
|
//#endregion
|
|
28424
28991
|
//#region src/utils/formatting.ts
|
|
28425
28992
|
const truncateIfNeeded = (text, advice = "Use pagination or filters to reduce results.") => {
|
|
@@ -33761,9 +34328,9 @@ const registerSingleProxies = (registration, tools) => {
|
|
|
33761
34328
|
* (`dev/reload.ts`) can keep this long-lived shell (and its transport/session)
|
|
33762
34329
|
* alive while swapping the toolset underneath it via `registerToolset`.
|
|
33763
34330
|
*/
|
|
33764
|
-
const createServerShell = (config, requestStateCodec = createRequestStateCodec({})) => {
|
|
34331
|
+
const createServerShell = (config, requestStateCodec = createRequestStateCodec({}), extraInstructions) => {
|
|
33765
34332
|
const pkg = readPackageInfo();
|
|
33766
|
-
const instructions = buildInstructions(config);
|
|
34333
|
+
const instructions = [buildInstructions(config), extraInstructions].filter((block) => block !== void 0).join("\n\n") || void 0;
|
|
33767
34334
|
return new McpServer({
|
|
33768
34335
|
name: pkg.name,
|
|
33769
34336
|
version: pkg.version
|
|
@@ -34081,8 +34648,8 @@ const toolEnv = (config) => ({
|
|
|
34081
34648
|
subdomain: config.subdomain,
|
|
34082
34649
|
brandIds: config.brandIds
|
|
34083
34650
|
});
|
|
34084
|
-
const createMcpServer = (config, getToken, logger = silentLogger, onUnauthorized, { caches = createServerCaches(config, getToken, onUnauthorized), requestStateCodec, slaRuntime = createSlaRuntime(config), listens, getBackgroundToken, alertPolling = "server", tools = createAllTools(toolEnv(config)) } = {}) => {
|
|
34085
|
-
const server = createServerShell(config, requestStateCodec);
|
|
34651
|
+
const createMcpServer = (config, getToken, logger = silentLogger, onUnauthorized, { caches = createServerCaches(config, getToken, onUnauthorized), requestStateCodec, slaRuntime = createSlaRuntime(config), listens, getBackgroundToken, alertPolling = "server", tools = createAllTools(toolEnv(config)), extraInstructions, decorate } = {}) => {
|
|
34652
|
+
const server = createServerShell(config, requestStateCodec, extraInstructions);
|
|
34086
34653
|
const sla = createSlaService(slaSettings(config), slaRuntime, caches.resolveUserId);
|
|
34087
34654
|
registerToolset(server, {
|
|
34088
34655
|
config,
|
|
@@ -34104,9 +34671,12 @@ const createMcpServer = (config, getToken, logger = silentLogger, onUnauthorized
|
|
|
34104
34671
|
installAlertSubscriptions(server, config, reader, logger, listens);
|
|
34105
34672
|
}
|
|
34106
34673
|
}
|
|
34674
|
+
decorate?.(server);
|
|
34107
34675
|
return server;
|
|
34108
34676
|
};
|
|
34109
|
-
const defaultServerFactory = ({ config, getToken, logger, onUnauthorized, caches, tools, requestStateCodec, slaRuntime, listens, getBackgroundToken, alertPolling }) => createMcpServer(config, getToken, logger, onUnauthorized, {
|
|
34677
|
+
const defaultServerFactory = ({ config, getToken, logger, onUnauthorized, caches, tools, requestStateCodec, slaRuntime, listens, getBackgroundToken, alertPolling, extraInstructions, decorate }) => createMcpServer(config, getToken, logger, onUnauthorized, {
|
|
34678
|
+
extraInstructions,
|
|
34679
|
+
decorate,
|
|
34110
34680
|
...caches ? { caches } : {},
|
|
34111
34681
|
...tools ? { tools } : {},
|
|
34112
34682
|
...slaRuntime ? { slaRuntime } : {},
|
|
@@ -34116,7 +34686,7 @@ const defaultServerFactory = ({ config, getToken, logger, onUnauthorized, caches
|
|
|
34116
34686
|
requestStateCodec
|
|
34117
34687
|
});
|
|
34118
34688
|
//#endregion
|
|
34119
|
-
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.
|
|
34689
|
+
//#region node_modules/.pnpm/@modelcontextprotocol+server@2.4.0/node_modules/@modelcontextprotocol/server/dist/stdio.mjs
|
|
34120
34690
|
/**
|
|
34121
34691
|
* Marks a stdout `'error'` listener that a closed transport left attached purely to
|
|
34122
34692
|
* swallow late write failures (see {@link StdioServerTransport.close}). A fresh
|
|
@@ -35146,7 +35716,7 @@ const installShutdown = (options) => {
|
|
|
35146
35716
|
//#endregion
|
|
35147
35717
|
//#region src/index.ts
|
|
35148
35718
|
const buildStdioTokenStore = async (config, logger) => {
|
|
35149
|
-
const { createTokenStore } = await import("./token-store-
|
|
35719
|
+
const { createTokenStore } = await import("./token-store-EwRwZiJO.js");
|
|
35150
35720
|
return createTokenStore({
|
|
35151
35721
|
subdomain: config.subdomain,
|
|
35152
35722
|
oauthClientId: config.oauthClientId,
|
|
@@ -35196,7 +35766,7 @@ const main = async () => {
|
|
|
35196
35766
|
logger,
|
|
35197
35767
|
cleanup: async () => (await starting?.catch(() => void 0))?.close()
|
|
35198
35768
|
});
|
|
35199
|
-
const { startHttpTransport } = await import("./http-
|
|
35769
|
+
const { startHttpTransport } = await import("./http-DuRcQrOc.js");
|
|
35200
35770
|
starting = startHttpTransport(config, logger);
|
|
35201
35771
|
await starting;
|
|
35202
35772
|
};
|
|
@@ -35206,4 +35776,4 @@ main().catch((error) => {
|
|
|
35206
35776
|
process.exit(1);
|
|
35207
35777
|
});
|
|
35208
35778
|
//#endregion
|
|
35209
|
-
export {
|
|
35779
|
+
export { _enum as $, ResourceTemplate as A, stampErrorBrands as B, DEFAULT_CALLBACK_PORT as C, createMcpHandler as D, WebStandardStreamableHTTPServerTransport as E, ProtocolErrorCode as F, ResultSchema as G, PaginatedRequestParamsSchema as H, ResourceNotFoundError as I, toStrictStandardSchema as J, buildInstructions as K, assertValidCacheHint as L, OAuthError as M, OAuthErrorCode as N, isLegacyRequest as O, ProtocolError as P, errnoCode as Q, brandedHasInstance as R, deadlineSignal as S, DEFAULT_MAX_REQUEST_BODY_SIZE as T, PaginatedResultSchema as U, BaseRequestParamsSchema as V, ResourceSchema as W, STARTUP_DOCS as X, compareCodeUnits as Y, createStartupError as Z, createAllTools as _, toolEnv as a, object as at, zendeskGet as b, clearToken as c, union as ct, resolveTokenPath as d, array as et, saveToken as f, silentLogger as g, readPackageInfo as h, defaultServerFactory as i, number$1 as it, verifyBearerToken as j, McpServer as k, configDir as l, unknown as lt, createRequestStateCodec as m, listenedUris as n, literal as nt, watchGrantAlerts as o, record as ot, signInRequiredError as p, Namespace as q, createServerCaches as r, looseObject as rt, startSlaRuntime as s, string as st, createListenFeed as t, boolean as tt, loadToken as u, createTopologyProvider as v, getOAuthUrls as w, REQUEST_TIMEOUT_MS as x, ZendeskApiError as y, isModernProtocolVersion as z };
|