Initial commit: Complete Hive distributed AI orchestration platform

This comprehensive implementation includes:
- FastAPI backend with MCP server integration
- React/TypeScript frontend with Vite
- PostgreSQL database with Redis caching
- Grafana/Prometheus monitoring stack
- Docker Compose orchestration
- Full MCP protocol support for Claude Code integration

Features:
- Agent discovery and management across network
- Visual workflow editor and execution engine
- Real-time task coordination and monitoring
- Multi-model support with specialized agents
- Distributed development task allocation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-07-07 21:44:31 +10:00
commit d7ad321176
2631 changed files with 870175 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
/**
* Utilities for handling OAuth resource URIs.
*/
/**
* Converts a server URL to a resource URL by removing the fragment.
* RFC 8707 section 2 states that resource URIs "MUST NOT include a fragment component".
* Keeps everything else unchanged (scheme, domain, port, path, query).
*/
export declare function resourceUrlFromServerUrl(url: URL | string): URL;
/**
* Checks if a requested resource URL matches a configured resource URL.
* A requested resource matches if it has the same scheme, domain, port,
* and its path starts with the configured resource's path.
*
* @param requestedResource The resource URL being requested
* @param configuredResource The resource URL that has been configured
* @returns true if the requested resource matches the configured resource, false otherwise
*/
export declare function checkResourceAllowed({ requestedResource, configuredResource }: {
requestedResource: URL | string;
configuredResource: URL | string;
}): boolean;
//# sourceMappingURL=auth-utils.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"auth-utils.d.ts","sourceRoot":"","sources":["../../../src/shared/auth-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAI,GAAG,CAIhE;AAED;;;;;;;;GAQG;AACF,wBAAgB,oBAAoB,CAClC,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,EAAE;IACzC,iBAAiB,EAAE,GAAG,GAAG,MAAM,CAAC;IAChC,kBAAkB,EAAE,GAAG,GAAG,MAAM,CAAA;CACjC,GACA,OAAO,CAwBT"}

View File

@@ -0,0 +1,48 @@
"use strict";
/**
* Utilities for handling OAuth resource URIs.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.resourceUrlFromServerUrl = resourceUrlFromServerUrl;
exports.checkResourceAllowed = checkResourceAllowed;
/**
* Converts a server URL to a resource URL by removing the fragment.
* RFC 8707 section 2 states that resource URIs "MUST NOT include a fragment component".
* Keeps everything else unchanged (scheme, domain, port, path, query).
*/
function resourceUrlFromServerUrl(url) {
const resourceURL = typeof url === "string" ? new URL(url) : new URL(url.href);
resourceURL.hash = ''; // Remove fragment
return resourceURL;
}
/**
* Checks if a requested resource URL matches a configured resource URL.
* A requested resource matches if it has the same scheme, domain, port,
* and its path starts with the configured resource's path.
*
* @param requestedResource The resource URL being requested
* @param configuredResource The resource URL that has been configured
* @returns true if the requested resource matches the configured resource, false otherwise
*/
function checkResourceAllowed({ requestedResource, configuredResource }) {
const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
// Compare the origin (scheme, domain, and port)
if (requested.origin !== configured.origin) {
return false;
}
// Handle cases like requested=/foo and configured=/foo/
if (requested.pathname.length < configured.pathname.length) {
return false;
}
// Check if the requested path starts with the configured path
// Ensure both paths end with / for proper comparison
// This ensures that if we have paths like "/api" and "/api/users",
// we properly detect that "/api/users" is a subpath of "/api"
// By adding a trailing slash if missing, we avoid false positives
// where paths like "/api123" would incorrectly match "/api"
const requestedPath = requested.pathname.endsWith('/') ? requested.pathname : requested.pathname + '/';
const configuredPath = configured.pathname.endsWith('/') ? configured.pathname : configured.pathname + '/';
return requestedPath.startsWith(configuredPath);
}
//# sourceMappingURL=auth-utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"auth-utils.js","sourceRoot":"","sources":["../../../src/shared/auth-utils.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAOH,4DAIC;AAWA,oDA6BC;AAjDF;;;;GAIG;AACH,SAAgB,wBAAwB,CAAC,GAAiB;IACxD,MAAM,WAAW,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/E,WAAW,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,kBAAkB;IACzC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;;;GAQG;AACF,SAAgB,oBAAoB,CAClC,EAAE,iBAAiB,EAAE,kBAAkB,EAGtC;IAED,MAAM,SAAS,GAAG,OAAO,iBAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACvH,MAAM,UAAU,GAAG,OAAO,kBAAkB,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAE3H,gDAAgD;IAChD,IAAI,SAAS,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wDAAwD;IACxD,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAA;IACd,CAAC;IAED,8DAA8D;IAC9D,qDAAqD;IACrD,mEAAmE;IACnE,8DAA8D;IAC9D,kEAAkE;IAClE,4DAA4D;IAC5D,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,GAAG,GAAG,CAAC;IACvG,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC;IAE3G,OAAO,aAAa,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAClD,CAAC"}

View File

@@ -0,0 +1,327 @@
import { z } from "zod";
/**
* RFC 9728 OAuth Protected Resource Metadata
*/
export declare const OAuthProtectedResourceMetadataSchema: z.ZodObject<{
resource: z.ZodString;
authorization_servers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
jwks_uri: z.ZodOptional<z.ZodString>;
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
bearer_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
resource_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
resource_name: z.ZodOptional<z.ZodString>;
resource_documentation: z.ZodOptional<z.ZodString>;
resource_policy_uri: z.ZodOptional<z.ZodString>;
resource_tos_uri: z.ZodOptional<z.ZodString>;
tls_client_certificate_bound_access_tokens: z.ZodOptional<z.ZodBoolean>;
authorization_details_types_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
dpop_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
dpop_bound_access_tokens_required: z.ZodOptional<z.ZodBoolean>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
resource: z.ZodString;
authorization_servers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
jwks_uri: z.ZodOptional<z.ZodString>;
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
bearer_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
resource_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
resource_name: z.ZodOptional<z.ZodString>;
resource_documentation: z.ZodOptional<z.ZodString>;
resource_policy_uri: z.ZodOptional<z.ZodString>;
resource_tos_uri: z.ZodOptional<z.ZodString>;
tls_client_certificate_bound_access_tokens: z.ZodOptional<z.ZodBoolean>;
authorization_details_types_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
dpop_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
dpop_bound_access_tokens_required: z.ZodOptional<z.ZodBoolean>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
resource: z.ZodString;
authorization_servers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
jwks_uri: z.ZodOptional<z.ZodString>;
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
bearer_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
resource_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
resource_name: z.ZodOptional<z.ZodString>;
resource_documentation: z.ZodOptional<z.ZodString>;
resource_policy_uri: z.ZodOptional<z.ZodString>;
resource_tos_uri: z.ZodOptional<z.ZodString>;
tls_client_certificate_bound_access_tokens: z.ZodOptional<z.ZodBoolean>;
authorization_details_types_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
dpop_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
dpop_bound_access_tokens_required: z.ZodOptional<z.ZodBoolean>;
}, z.ZodTypeAny, "passthrough">>;
/**
* RFC 8414 OAuth 2.0 Authorization Server Metadata
*/
export declare const OAuthMetadataSchema: z.ZodObject<{
issuer: z.ZodString;
authorization_endpoint: z.ZodString;
token_endpoint: z.ZodString;
registration_endpoint: z.ZodOptional<z.ZodString>;
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
response_types_supported: z.ZodArray<z.ZodString, "many">;
response_modes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
grant_types_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
token_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
token_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
service_documentation: z.ZodOptional<z.ZodString>;
revocation_endpoint: z.ZodOptional<z.ZodString>;
revocation_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
revocation_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
introspection_endpoint: z.ZodOptional<z.ZodString>;
introspection_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
introspection_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
code_challenge_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
issuer: z.ZodString;
authorization_endpoint: z.ZodString;
token_endpoint: z.ZodString;
registration_endpoint: z.ZodOptional<z.ZodString>;
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
response_types_supported: z.ZodArray<z.ZodString, "many">;
response_modes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
grant_types_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
token_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
token_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
service_documentation: z.ZodOptional<z.ZodString>;
revocation_endpoint: z.ZodOptional<z.ZodString>;
revocation_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
revocation_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
introspection_endpoint: z.ZodOptional<z.ZodString>;
introspection_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
introspection_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
code_challenge_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
issuer: z.ZodString;
authorization_endpoint: z.ZodString;
token_endpoint: z.ZodString;
registration_endpoint: z.ZodOptional<z.ZodString>;
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
response_types_supported: z.ZodArray<z.ZodString, "many">;
response_modes_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
grant_types_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
token_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
token_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
service_documentation: z.ZodOptional<z.ZodString>;
revocation_endpoint: z.ZodOptional<z.ZodString>;
revocation_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
revocation_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
introspection_endpoint: z.ZodOptional<z.ZodString>;
introspection_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
introspection_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
code_challenge_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
}, z.ZodTypeAny, "passthrough">>;
/**
* OAuth 2.1 token response
*/
export declare const OAuthTokensSchema: z.ZodObject<{
access_token: z.ZodString;
token_type: z.ZodString;
expires_in: z.ZodOptional<z.ZodNumber>;
scope: z.ZodOptional<z.ZodString>;
refresh_token: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
access_token: string;
token_type: string;
expires_in?: number | undefined;
scope?: string | undefined;
refresh_token?: string | undefined;
}, {
access_token: string;
token_type: string;
expires_in?: number | undefined;
scope?: string | undefined;
refresh_token?: string | undefined;
}>;
/**
* OAuth 2.1 error response
*/
export declare const OAuthErrorResponseSchema: z.ZodObject<{
error: z.ZodString;
error_description: z.ZodOptional<z.ZodString>;
error_uri: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
error: string;
error_description?: string | undefined;
error_uri?: string | undefined;
}, {
error: string;
error_description?: string | undefined;
error_uri?: string | undefined;
}>;
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration metadata
*/
export declare const OAuthClientMetadataSchema: z.ZodObject<{
redirect_uris: z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>;
token_endpoint_auth_method: z.ZodOptional<z.ZodString>;
grant_types: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
response_types: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
client_name: z.ZodOptional<z.ZodString>;
client_uri: z.ZodOptional<z.ZodString>;
logo_uri: z.ZodOptional<z.ZodString>;
scope: z.ZodOptional<z.ZodString>;
contacts: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
tos_uri: z.ZodOptional<z.ZodString>;
policy_uri: z.ZodOptional<z.ZodString>;
jwks_uri: z.ZodOptional<z.ZodString>;
jwks: z.ZodOptional<z.ZodAny>;
software_id: z.ZodOptional<z.ZodString>;
software_version: z.ZodOptional<z.ZodString>;
software_statement: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
redirect_uris: string[];
jwks_uri?: string | undefined;
scope?: string | undefined;
token_endpoint_auth_method?: string | undefined;
grant_types?: string[] | undefined;
response_types?: string[] | undefined;
client_name?: string | undefined;
client_uri?: string | undefined;
logo_uri?: string | undefined;
contacts?: string[] | undefined;
tos_uri?: string | undefined;
policy_uri?: string | undefined;
jwks?: any;
software_id?: string | undefined;
software_version?: string | undefined;
software_statement?: string | undefined;
}, {
redirect_uris: string[];
jwks_uri?: string | undefined;
scope?: string | undefined;
token_endpoint_auth_method?: string | undefined;
grant_types?: string[] | undefined;
response_types?: string[] | undefined;
client_name?: string | undefined;
client_uri?: string | undefined;
logo_uri?: string | undefined;
contacts?: string[] | undefined;
tos_uri?: string | undefined;
policy_uri?: string | undefined;
jwks?: any;
software_id?: string | undefined;
software_version?: string | undefined;
software_statement?: string | undefined;
}>;
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration client information
*/
export declare const OAuthClientInformationSchema: z.ZodObject<{
client_id: z.ZodString;
client_secret: z.ZodOptional<z.ZodString>;
client_id_issued_at: z.ZodOptional<z.ZodNumber>;
client_secret_expires_at: z.ZodOptional<z.ZodNumber>;
}, "strip", z.ZodTypeAny, {
client_id: string;
client_secret?: string | undefined;
client_id_issued_at?: number | undefined;
client_secret_expires_at?: number | undefined;
}, {
client_id: string;
client_secret?: string | undefined;
client_id_issued_at?: number | undefined;
client_secret_expires_at?: number | undefined;
}>;
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration full response (client information plus metadata)
*/
export declare const OAuthClientInformationFullSchema: z.ZodObject<z.objectUtil.extendShape<{
redirect_uris: z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>;
token_endpoint_auth_method: z.ZodOptional<z.ZodString>;
grant_types: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
response_types: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
client_name: z.ZodOptional<z.ZodString>;
client_uri: z.ZodOptional<z.ZodString>;
logo_uri: z.ZodOptional<z.ZodString>;
scope: z.ZodOptional<z.ZodString>;
contacts: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
tos_uri: z.ZodOptional<z.ZodString>;
policy_uri: z.ZodOptional<z.ZodString>;
jwks_uri: z.ZodOptional<z.ZodString>;
jwks: z.ZodOptional<z.ZodAny>;
software_id: z.ZodOptional<z.ZodString>;
software_version: z.ZodOptional<z.ZodString>;
software_statement: z.ZodOptional<z.ZodString>;
}, {
client_id: z.ZodString;
client_secret: z.ZodOptional<z.ZodString>;
client_id_issued_at: z.ZodOptional<z.ZodNumber>;
client_secret_expires_at: z.ZodOptional<z.ZodNumber>;
}>, "strip", z.ZodTypeAny, {
redirect_uris: string[];
client_id: string;
jwks_uri?: string | undefined;
scope?: string | undefined;
token_endpoint_auth_method?: string | undefined;
grant_types?: string[] | undefined;
response_types?: string[] | undefined;
client_name?: string | undefined;
client_uri?: string | undefined;
logo_uri?: string | undefined;
contacts?: string[] | undefined;
tos_uri?: string | undefined;
policy_uri?: string | undefined;
jwks?: any;
software_id?: string | undefined;
software_version?: string | undefined;
software_statement?: string | undefined;
client_secret?: string | undefined;
client_id_issued_at?: number | undefined;
client_secret_expires_at?: number | undefined;
}, {
redirect_uris: string[];
client_id: string;
jwks_uri?: string | undefined;
scope?: string | undefined;
token_endpoint_auth_method?: string | undefined;
grant_types?: string[] | undefined;
response_types?: string[] | undefined;
client_name?: string | undefined;
client_uri?: string | undefined;
logo_uri?: string | undefined;
contacts?: string[] | undefined;
tos_uri?: string | undefined;
policy_uri?: string | undefined;
jwks?: any;
software_id?: string | undefined;
software_version?: string | undefined;
software_statement?: string | undefined;
client_secret?: string | undefined;
client_id_issued_at?: number | undefined;
client_secret_expires_at?: number | undefined;
}>;
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration error response
*/
export declare const OAuthClientRegistrationErrorSchema: z.ZodObject<{
error: z.ZodString;
error_description: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
error: string;
error_description?: string | undefined;
}, {
error: string;
error_description?: string | undefined;
}>;
/**
* RFC 7009 OAuth 2.0 Token Revocation request
*/
export declare const OAuthTokenRevocationRequestSchema: z.ZodObject<{
token: z.ZodString;
token_type_hint: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
token: string;
token_type_hint?: string | undefined;
}, {
token: string;
token_type_hint?: string | undefined;
}>;
export type OAuthMetadata = z.infer<typeof OAuthMetadataSchema>;
export type OAuthTokens = z.infer<typeof OAuthTokensSchema>;
export type OAuthErrorResponse = z.infer<typeof OAuthErrorResponseSchema>;
export type OAuthClientMetadata = z.infer<typeof OAuthClientMetadataSchema>;
export type OAuthClientInformation = z.infer<typeof OAuthClientInformationSchema>;
export type OAuthClientInformationFull = z.infer<typeof OAuthClientInformationFullSchema>;
export type OAuthClientRegistrationError = z.infer<typeof OAuthClientRegistrationErrorSchema>;
export type OAuthTokenRevocationRequest = z.infer<typeof OAuthTokenRevocationRequestSchema>;
export type OAuthProtectedResourceMetadata = z.infer<typeof OAuthProtectedResourceMetadataSchema>;
//# sourceMappingURL=auth.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/shared/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAiBjC,CAAC;AAEjB;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA6BhB,CAAC;AAEjB;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;EAQpB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;EAKjC,CAAC;AAEL;;GAEG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB5B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;EAK/B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAgE,CAAC;AAE9G;;GAEG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;EAGrC,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;EAGpC,CAAC;AAGX,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAClF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAC1F,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAC9F,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAC5F,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC"}

View File

@@ -0,0 +1,128 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OAuthTokenRevocationRequestSchema = exports.OAuthClientRegistrationErrorSchema = exports.OAuthClientInformationFullSchema = exports.OAuthClientInformationSchema = exports.OAuthClientMetadataSchema = exports.OAuthErrorResponseSchema = exports.OAuthTokensSchema = exports.OAuthMetadataSchema = exports.OAuthProtectedResourceMetadataSchema = void 0;
const zod_1 = require("zod");
/**
* RFC 9728 OAuth Protected Resource Metadata
*/
exports.OAuthProtectedResourceMetadataSchema = zod_1.z
.object({
resource: zod_1.z.string().url(),
authorization_servers: zod_1.z.array(zod_1.z.string().url()).optional(),
jwks_uri: zod_1.z.string().url().optional(),
scopes_supported: zod_1.z.array(zod_1.z.string()).optional(),
bearer_methods_supported: zod_1.z.array(zod_1.z.string()).optional(),
resource_signing_alg_values_supported: zod_1.z.array(zod_1.z.string()).optional(),
resource_name: zod_1.z.string().optional(),
resource_documentation: zod_1.z.string().optional(),
resource_policy_uri: zod_1.z.string().url().optional(),
resource_tos_uri: zod_1.z.string().url().optional(),
tls_client_certificate_bound_access_tokens: zod_1.z.boolean().optional(),
authorization_details_types_supported: zod_1.z.array(zod_1.z.string()).optional(),
dpop_signing_alg_values_supported: zod_1.z.array(zod_1.z.string()).optional(),
dpop_bound_access_tokens_required: zod_1.z.boolean().optional(),
})
.passthrough();
/**
* RFC 8414 OAuth 2.0 Authorization Server Metadata
*/
exports.OAuthMetadataSchema = zod_1.z
.object({
issuer: zod_1.z.string(),
authorization_endpoint: zod_1.z.string(),
token_endpoint: zod_1.z.string(),
registration_endpoint: zod_1.z.string().optional(),
scopes_supported: zod_1.z.array(zod_1.z.string()).optional(),
response_types_supported: zod_1.z.array(zod_1.z.string()),
response_modes_supported: zod_1.z.array(zod_1.z.string()).optional(),
grant_types_supported: zod_1.z.array(zod_1.z.string()).optional(),
token_endpoint_auth_methods_supported: zod_1.z.array(zod_1.z.string()).optional(),
token_endpoint_auth_signing_alg_values_supported: zod_1.z
.array(zod_1.z.string())
.optional(),
service_documentation: zod_1.z.string().optional(),
revocation_endpoint: zod_1.z.string().optional(),
revocation_endpoint_auth_methods_supported: zod_1.z.array(zod_1.z.string()).optional(),
revocation_endpoint_auth_signing_alg_values_supported: zod_1.z
.array(zod_1.z.string())
.optional(),
introspection_endpoint: zod_1.z.string().optional(),
introspection_endpoint_auth_methods_supported: zod_1.z
.array(zod_1.z.string())
.optional(),
introspection_endpoint_auth_signing_alg_values_supported: zod_1.z
.array(zod_1.z.string())
.optional(),
code_challenge_methods_supported: zod_1.z.array(zod_1.z.string()).optional(),
})
.passthrough();
/**
* OAuth 2.1 token response
*/
exports.OAuthTokensSchema = zod_1.z
.object({
access_token: zod_1.z.string(),
token_type: zod_1.z.string(),
expires_in: zod_1.z.number().optional(),
scope: zod_1.z.string().optional(),
refresh_token: zod_1.z.string().optional(),
})
.strip();
/**
* OAuth 2.1 error response
*/
exports.OAuthErrorResponseSchema = zod_1.z
.object({
error: zod_1.z.string(),
error_description: zod_1.z.string().optional(),
error_uri: zod_1.z.string().optional(),
});
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration metadata
*/
exports.OAuthClientMetadataSchema = zod_1.z.object({
redirect_uris: zod_1.z.array(zod_1.z.string()).refine((uris) => uris.every((uri) => URL.canParse(uri)), { message: "redirect_uris must contain valid URLs" }),
token_endpoint_auth_method: zod_1.z.string().optional(),
grant_types: zod_1.z.array(zod_1.z.string()).optional(),
response_types: zod_1.z.array(zod_1.z.string()).optional(),
client_name: zod_1.z.string().optional(),
client_uri: zod_1.z.string().optional(),
logo_uri: zod_1.z.string().optional(),
scope: zod_1.z.string().optional(),
contacts: zod_1.z.array(zod_1.z.string()).optional(),
tos_uri: zod_1.z.string().optional(),
policy_uri: zod_1.z.string().optional(),
jwks_uri: zod_1.z.string().optional(),
jwks: zod_1.z.any().optional(),
software_id: zod_1.z.string().optional(),
software_version: zod_1.z.string().optional(),
software_statement: zod_1.z.string().optional(),
}).strip();
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration client information
*/
exports.OAuthClientInformationSchema = zod_1.z.object({
client_id: zod_1.z.string(),
client_secret: zod_1.z.string().optional(),
client_id_issued_at: zod_1.z.number().optional(),
client_secret_expires_at: zod_1.z.number().optional(),
}).strip();
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration full response (client information plus metadata)
*/
exports.OAuthClientInformationFullSchema = exports.OAuthClientMetadataSchema.merge(exports.OAuthClientInformationSchema);
/**
* RFC 7591 OAuth 2.0 Dynamic Client Registration error response
*/
exports.OAuthClientRegistrationErrorSchema = zod_1.z.object({
error: zod_1.z.string(),
error_description: zod_1.z.string().optional(),
}).strip();
/**
* RFC 7009 OAuth 2.0 Token Revocation request
*/
exports.OAuthTokenRevocationRequestSchema = zod_1.z.object({
token: zod_1.z.string(),
token_type_hint: zod_1.z.string().optional(),
}).strip();
//# sourceMappingURL=auth.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/shared/auth.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,12 @@
import { BaseMetadata } from "../types.js";
/**
* Utilities for working with BaseMetadata objects.
*/
/**
* Gets the display name for an object with BaseMetadata.
* For tools, the precedence is: title → annotations.title → name
* For other objects: title → name
* This implements the spec requirement: "if no title is provided, name should be used for display purposes"
*/
export declare function getDisplayName(metadata: BaseMetadata): string;
//# sourceMappingURL=metadataUtils.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"metadataUtils.d.ts","sourceRoot":"","sources":["../../../src/shared/metadataUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;GAEG;AAEH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAgB7D"}

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDisplayName = getDisplayName;
/**
* Utilities for working with BaseMetadata objects.
*/
/**
* Gets the display name for an object with BaseMetadata.
* For tools, the precedence is: title → annotations.title → name
* For other objects: title → name
* This implements the spec requirement: "if no title is provided, name should be used for display purposes"
*/
function getDisplayName(metadata) {
var _a;
// First check for title (not undefined and not empty string)
if (metadata.title !== undefined && metadata.title !== '') {
return metadata.title;
}
// Then check for annotations.title (only present in Tool objects)
if ('annotations' in metadata) {
const metadataWithAnnotations = metadata;
if ((_a = metadataWithAnnotations.annotations) === null || _a === void 0 ? void 0 : _a.title) {
return metadataWithAnnotations.annotations.title;
}
}
// Finally fall back to name
return metadata.name;
}
//# sourceMappingURL=metadataUtils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"metadataUtils.js","sourceRoot":"","sources":["../../../src/shared/metadataUtils.ts"],"names":[],"mappings":";;AAYA,wCAgBC;AA1BD;;GAEG;AAEH;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,QAAsB;;IACnD,6DAA6D;IAC7D,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,IAAI,QAAQ,CAAC,KAAK,KAAK,EAAE,EAAE,CAAC;QAC1D,OAAO,QAAQ,CAAC,KAAK,CAAC;IACxB,CAAC;IAED,kEAAkE;IAClE,IAAI,aAAa,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,uBAAuB,GAAG,QAA+D,CAAC;QAChG,IAAI,MAAA,uBAAuB,CAAC,WAAW,0CAAE,KAAK,EAAE,CAAC;YAC/C,OAAO,uBAAuB,CAAC,WAAW,CAAC,KAAK,CAAC;QACnD,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC"}

View File

@@ -0,0 +1,221 @@
import { ZodLiteral, ZodObject, ZodType, z } from "zod";
import { ClientCapabilities, Notification, Progress, Request, RequestId, Result, ServerCapabilities, RequestMeta, RequestInfo } from "../types.js";
import { Transport, TransportSendOptions } from "./transport.js";
import { AuthInfo } from "../server/auth/types.js";
/**
* Callback for progress notifications.
*/
export type ProgressCallback = (progress: Progress) => void;
/**
* Additional initialization options.
*/
export type ProtocolOptions = {
/**
* Whether to restrict emitted requests to only those that the remote side has indicated that they can handle, through their advertised capabilities.
*
* Note that this DOES NOT affect checking of _local_ side capabilities, as it is considered a logic error to mis-specify those.
*
* Currently this defaults to false, for backwards compatibility with SDK versions that did not advertise capabilities correctly. In future, this will default to true.
*/
enforceStrictCapabilities?: boolean;
};
/**
* The default request timeout, in miliseconds.
*/
export declare const DEFAULT_REQUEST_TIMEOUT_MSEC = 60000;
/**
* Options that can be given per request.
*/
export type RequestOptions = {
/**
* If set, requests progress notifications from the remote end (if supported). When progress notifications are received, this callback will be invoked.
*/
onprogress?: ProgressCallback;
/**
* Can be used to cancel an in-flight request. This will cause an AbortError to be raised from request().
*/
signal?: AbortSignal;
/**
* A timeout (in milliseconds) for this request. If exceeded, an McpError with code `RequestTimeout` will be raised from request().
*
* If not specified, `DEFAULT_REQUEST_TIMEOUT_MSEC` will be used as the timeout.
*/
timeout?: number;
/**
* If true, receiving a progress notification will reset the request timeout.
* This is useful for long-running operations that send periodic progress updates.
* Default: false
*/
resetTimeoutOnProgress?: boolean;
/**
* Maximum total time (in milliseconds) to wait for a response.
* If exceeded, an McpError with code `RequestTimeout` will be raised, regardless of progress notifications.
* If not specified, there is no maximum total timeout.
*/
maxTotalTimeout?: number;
} & TransportSendOptions;
/**
* Options that can be given per notification.
*/
export type NotificationOptions = {
/**
* May be used to indicate to the transport which incoming request to associate this outgoing notification with.
*/
relatedRequestId?: RequestId;
};
/**
* Extra data given to request handlers.
*/
export type RequestHandlerExtra<SendRequestT extends Request, SendNotificationT extends Notification> = {
/**
* An abort signal used to communicate if the request was cancelled from the sender's side.
*/
signal: AbortSignal;
/**
* Information about a validated access token, provided to request handlers.
*/
authInfo?: AuthInfo;
/**
* The session ID from the transport, if available.
*/
sessionId?: string;
/**
* Metadata from the original request.
*/
_meta?: RequestMeta;
/**
* The JSON-RPC ID of the request being handled.
* This can be useful for tracking or logging purposes.
*/
requestId: RequestId;
/**
* The original HTTP request.
*/
requestInfo?: RequestInfo;
/**
* Sends a notification that relates to the current request being handled.
*
* This is used by certain transports to correctly associate related messages.
*/
sendNotification: (notification: SendNotificationT) => Promise<void>;
/**
* Sends a request that relates to the current request being handled.
*
* This is used by certain transports to correctly associate related messages.
*/
sendRequest: <U extends ZodType<object>>(request: SendRequestT, resultSchema: U, options?: RequestOptions) => Promise<z.infer<U>>;
};
/**
* Implements MCP protocol framing on top of a pluggable transport, including
* features like request/response linking, notifications, and progress.
*/
export declare abstract class Protocol<SendRequestT extends Request, SendNotificationT extends Notification, SendResultT extends Result> {
private _options?;
private _transport?;
private _requestMessageId;
private _requestHandlers;
private _requestHandlerAbortControllers;
private _notificationHandlers;
private _responseHandlers;
private _progressHandlers;
private _timeoutInfo;
/**
* Callback for when the connection is closed for any reason.
*
* This is invoked when close() is called as well.
*/
onclose?: () => void;
/**
* Callback for when an error occurs.
*
* Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
*/
onerror?: (error: Error) => void;
/**
* A handler to invoke for any request types that do not have their own handler installed.
*/
fallbackRequestHandler?: (request: Request) => Promise<SendResultT>;
/**
* A handler to invoke for any notification types that do not have their own handler installed.
*/
fallbackNotificationHandler?: (notification: Notification) => Promise<void>;
constructor(_options?: ProtocolOptions | undefined);
private _setupTimeout;
private _resetTimeout;
private _cleanupTimeout;
/**
* Attaches to the given transport, starts it, and starts listening for messages.
*
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
*/
connect(transport: Transport): Promise<void>;
private _onclose;
private _onerror;
private _onnotification;
private _onrequest;
private _onprogress;
private _onresponse;
get transport(): Transport | undefined;
/**
* Closes the connection.
*/
close(): Promise<void>;
/**
* A method to check if a capability is supported by the remote side, for the given method to be called.
*
* This should be implemented by subclasses.
*/
protected abstract assertCapabilityForMethod(method: SendRequestT["method"]): void;
/**
* A method to check if a notification is supported by the local side, for the given method to be sent.
*
* This should be implemented by subclasses.
*/
protected abstract assertNotificationCapability(method: SendNotificationT["method"]): void;
/**
* A method to check if a request handler is supported by the local side, for the given method to be handled.
*
* This should be implemented by subclasses.
*/
protected abstract assertRequestHandlerCapability(method: string): void;
/**
* Sends a request and wait for a response.
*
* Do not use this method to emit notifications! Use notification() instead.
*/
request<T extends ZodType<object>>(request: SendRequestT, resultSchema: T, options?: RequestOptions): Promise<z.infer<T>>;
/**
* Emits a notification, which is a one-way message that does not expect a response.
*/
notification(notification: SendNotificationT, options?: NotificationOptions): Promise<void>;
/**
* Registers a handler to invoke when this protocol object receives a request with the given method.
*
* Note that this will replace any previous request handler for the same method.
*/
setRequestHandler<T extends ZodObject<{
method: ZodLiteral<string>;
}>>(requestSchema: T, handler: (request: z.infer<T>, extra: RequestHandlerExtra<SendRequestT, SendNotificationT>) => SendResultT | Promise<SendResultT>): void;
/**
* Removes the request handler for the given method.
*/
removeRequestHandler(method: string): void;
/**
* Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
*/
assertCanSetRequestHandler(method: string): void;
/**
* Registers a handler to invoke when this protocol object receives a notification with the given method.
*
* Note that this will replace any previous notification handler for the same method.
*/
setNotificationHandler<T extends ZodObject<{
method: ZodLiteral<string>;
}>>(notificationSchema: T, handler: (notification: z.infer<T>) => void | Promise<void>): void;
/**
* Removes the notification handler for the given method.
*/
removeNotificationHandler(method: string): void;
}
export declare function mergeCapabilities<T extends ServerCapabilities | ClientCapabilities>(base: T, additional: T): T;
//# sourceMappingURL=protocol.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/shared/protocol.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,382 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Protocol = exports.DEFAULT_REQUEST_TIMEOUT_MSEC = void 0;
exports.mergeCapabilities = mergeCapabilities;
const types_js_1 = require("../types.js");
/**
* The default request timeout, in miliseconds.
*/
exports.DEFAULT_REQUEST_TIMEOUT_MSEC = 60000;
/**
* Implements MCP protocol framing on top of a pluggable transport, including
* features like request/response linking, notifications, and progress.
*/
class Protocol {
constructor(_options) {
this._options = _options;
this._requestMessageId = 0;
this._requestHandlers = new Map();
this._requestHandlerAbortControllers = new Map();
this._notificationHandlers = new Map();
this._responseHandlers = new Map();
this._progressHandlers = new Map();
this._timeoutInfo = new Map();
this.setNotificationHandler(types_js_1.CancelledNotificationSchema, (notification) => {
const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
});
this.setNotificationHandler(types_js_1.ProgressNotificationSchema, (notification) => {
this._onprogress(notification);
});
this.setRequestHandler(types_js_1.PingRequestSchema,
// Automatic pong by default.
(_request) => ({}));
}
_setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout, resetTimeoutOnProgress = false) {
this._timeoutInfo.set(messageId, {
timeoutId: setTimeout(onTimeout, timeout),
startTime: Date.now(),
timeout,
maxTotalTimeout,
resetTimeoutOnProgress,
onTimeout
});
}
_resetTimeout(messageId) {
const info = this._timeoutInfo.get(messageId);
if (!info)
return false;
const totalElapsed = Date.now() - info.startTime;
if (info.maxTotalTimeout && totalElapsed >= info.maxTotalTimeout) {
this._timeoutInfo.delete(messageId);
throw new types_js_1.McpError(types_js_1.ErrorCode.RequestTimeout, "Maximum total timeout exceeded", { maxTotalTimeout: info.maxTotalTimeout, totalElapsed });
}
clearTimeout(info.timeoutId);
info.timeoutId = setTimeout(info.onTimeout, info.timeout);
return true;
}
_cleanupTimeout(messageId) {
const info = this._timeoutInfo.get(messageId);
if (info) {
clearTimeout(info.timeoutId);
this._timeoutInfo.delete(messageId);
}
}
/**
* Attaches to the given transport, starts it, and starts listening for messages.
*
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
*/
async connect(transport) {
var _a, _b, _c;
this._transport = transport;
const _onclose = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.onclose;
this._transport.onclose = () => {
_onclose === null || _onclose === void 0 ? void 0 : _onclose();
this._onclose();
};
const _onerror = (_b = this.transport) === null || _b === void 0 ? void 0 : _b.onerror;
this._transport.onerror = (error) => {
_onerror === null || _onerror === void 0 ? void 0 : _onerror(error);
this._onerror(error);
};
const _onmessage = (_c = this._transport) === null || _c === void 0 ? void 0 : _c.onmessage;
this._transport.onmessage = (message, extra) => {
_onmessage === null || _onmessage === void 0 ? void 0 : _onmessage(message, extra);
if ((0, types_js_1.isJSONRPCResponse)(message) || (0, types_js_1.isJSONRPCError)(message)) {
this._onresponse(message);
}
else if ((0, types_js_1.isJSONRPCRequest)(message)) {
this._onrequest(message, extra);
}
else if ((0, types_js_1.isJSONRPCNotification)(message)) {
this._onnotification(message);
}
else {
this._onerror(new Error(`Unknown message type: ${JSON.stringify(message)}`));
}
};
await this._transport.start();
}
_onclose() {
var _a;
const responseHandlers = this._responseHandlers;
this._responseHandlers = new Map();
this._progressHandlers.clear();
this._transport = undefined;
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
const error = new types_js_1.McpError(types_js_1.ErrorCode.ConnectionClosed, "Connection closed");
for (const handler of responseHandlers.values()) {
handler(error);
}
}
_onerror(error) {
var _a;
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
}
_onnotification(notification) {
var _a;
const handler = (_a = this._notificationHandlers.get(notification.method)) !== null && _a !== void 0 ? _a : this.fallbackNotificationHandler;
// Ignore notifications not being subscribed to.
if (handler === undefined) {
return;
}
// Starting with Promise.resolve() puts any synchronous errors into the monad as well.
Promise.resolve()
.then(() => handler(notification))
.catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
}
_onrequest(request, extra) {
var _a, _b, _c, _d;
const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
if (handler === undefined) {
(_b = this._transport) === null || _b === void 0 ? void 0 : _b.send({
jsonrpc: "2.0",
id: request.id,
error: {
code: types_js_1.ErrorCode.MethodNotFound,
message: "Method not found",
},
}).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
return;
}
const abortController = new AbortController();
this._requestHandlerAbortControllers.set(request.id, abortController);
const fullExtra = {
signal: abortController.signal,
sessionId: (_c = this._transport) === null || _c === void 0 ? void 0 : _c.sessionId,
_meta: (_d = request.params) === null || _d === void 0 ? void 0 : _d._meta,
sendNotification: (notification) => this.notification(notification, { relatedRequestId: request.id }),
sendRequest: (r, resultSchema, options) => this.request(r, resultSchema, { ...options, relatedRequestId: request.id }),
authInfo: extra === null || extra === void 0 ? void 0 : extra.authInfo,
requestId: request.id,
requestInfo: extra === null || extra === void 0 ? void 0 : extra.requestInfo
};
// Starting with Promise.resolve() puts any synchronous errors into the monad as well.
Promise.resolve()
.then(() => handler(request, fullExtra))
.then((result) => {
var _a;
if (abortController.signal.aborted) {
return;
}
return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
result,
jsonrpc: "2.0",
id: request.id,
});
}, (error) => {
var _a, _b;
if (abortController.signal.aborted) {
return;
}
return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
jsonrpc: "2.0",
id: request.id,
error: {
code: Number.isSafeInteger(error["code"])
? error["code"]
: types_js_1.ErrorCode.InternalError,
message: (_b = error.message) !== null && _b !== void 0 ? _b : "Internal error",
},
});
})
.catch((error) => this._onerror(new Error(`Failed to send response: ${error}`)))
.finally(() => {
this._requestHandlerAbortControllers.delete(request.id);
});
}
_onprogress(notification) {
const { progressToken, ...params } = notification.params;
const messageId = Number(progressToken);
const handler = this._progressHandlers.get(messageId);
if (!handler) {
this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
return;
}
const responseHandler = this._responseHandlers.get(messageId);
const timeoutInfo = this._timeoutInfo.get(messageId);
if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) {
try {
this._resetTimeout(messageId);
}
catch (error) {
responseHandler(error);
return;
}
}
handler(params);
}
_onresponse(response) {
const messageId = Number(response.id);
const handler = this._responseHandlers.get(messageId);
if (handler === undefined) {
this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
return;
}
this._responseHandlers.delete(messageId);
this._progressHandlers.delete(messageId);
this._cleanupTimeout(messageId);
if ((0, types_js_1.isJSONRPCResponse)(response)) {
handler(response);
}
else {
const error = new types_js_1.McpError(response.error.code, response.error.message, response.error.data);
handler(error);
}
}
get transport() {
return this._transport;
}
/**
* Closes the connection.
*/
async close() {
var _a;
await ((_a = this._transport) === null || _a === void 0 ? void 0 : _a.close());
}
/**
* Sends a request and wait for a response.
*
* Do not use this method to emit notifications! Use notification() instead.
*/
request(request, resultSchema, options) {
const { relatedRequestId, resumptionToken, onresumptiontoken } = options !== null && options !== void 0 ? options : {};
return new Promise((resolve, reject) => {
var _a, _b, _c, _d, _e, _f;
if (!this._transport) {
reject(new Error("Not connected"));
return;
}
if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.enforceStrictCapabilities) === true) {
this.assertCapabilityForMethod(request.method);
}
(_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
const messageId = this._requestMessageId++;
const jsonrpcRequest = {
...request,
jsonrpc: "2.0",
id: messageId,
};
if (options === null || options === void 0 ? void 0 : options.onprogress) {
this._progressHandlers.set(messageId, options.onprogress);
jsonrpcRequest.params = {
...request.params,
_meta: {
...(((_c = request.params) === null || _c === void 0 ? void 0 : _c._meta) || {}),
progressToken: messageId
},
};
}
const cancel = (reason) => {
var _a;
this._responseHandlers.delete(messageId);
this._progressHandlers.delete(messageId);
this._cleanupTimeout(messageId);
(_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
jsonrpc: "2.0",
method: "notifications/cancelled",
params: {
requestId: messageId,
reason: String(reason),
},
}, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => this._onerror(new Error(`Failed to send cancellation: ${error}`)));
reject(reason);
};
this._responseHandlers.set(messageId, (response) => {
var _a;
if ((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
return;
}
if (response instanceof Error) {
return reject(response);
}
try {
const result = resultSchema.parse(response.result);
resolve(result);
}
catch (error) {
reject(error);
}
});
(_d = options === null || options === void 0 ? void 0 : options.signal) === null || _d === void 0 ? void 0 : _d.addEventListener("abort", () => {
var _a;
cancel((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.reason);
});
const timeout = (_e = options === null || options === void 0 ? void 0 : options.timeout) !== null && _e !== void 0 ? _e : exports.DEFAULT_REQUEST_TIMEOUT_MSEC;
const timeoutHandler = () => cancel(new types_js_1.McpError(types_js_1.ErrorCode.RequestTimeout, "Request timed out", { timeout }));
this._setupTimeout(messageId, timeout, options === null || options === void 0 ? void 0 : options.maxTotalTimeout, timeoutHandler, (_f = options === null || options === void 0 ? void 0 : options.resetTimeoutOnProgress) !== null && _f !== void 0 ? _f : false);
this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => {
this._cleanupTimeout(messageId);
reject(error);
});
});
}
/**
* Emits a notification, which is a one-way message that does not expect a response.
*/
async notification(notification, options) {
if (!this._transport) {
throw new Error("Not connected");
}
this.assertNotificationCapability(notification.method);
const jsonrpcNotification = {
...notification,
jsonrpc: "2.0",
};
await this._transport.send(jsonrpcNotification, options);
}
/**
* Registers a handler to invoke when this protocol object receives a request with the given method.
*
* Note that this will replace any previous request handler for the same method.
*/
setRequestHandler(requestSchema, handler) {
const method = requestSchema.shape.method.value;
this.assertRequestHandlerCapability(method);
this._requestHandlers.set(method, (request, extra) => {
return Promise.resolve(handler(requestSchema.parse(request), extra));
});
}
/**
* Removes the request handler for the given method.
*/
removeRequestHandler(method) {
this._requestHandlers.delete(method);
}
/**
* Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
*/
assertCanSetRequestHandler(method) {
if (this._requestHandlers.has(method)) {
throw new Error(`A request handler for ${method} already exists, which would be overridden`);
}
}
/**
* Registers a handler to invoke when this protocol object receives a notification with the given method.
*
* Note that this will replace any previous notification handler for the same method.
*/
setNotificationHandler(notificationSchema, handler) {
this._notificationHandlers.set(notificationSchema.shape.method.value, (notification) => Promise.resolve(handler(notificationSchema.parse(notification))));
}
/**
* Removes the notification handler for the given method.
*/
removeNotificationHandler(method) {
this._notificationHandlers.delete(method);
}
}
exports.Protocol = Protocol;
function mergeCapabilities(base, additional) {
return Object.entries(additional).reduce((acc, [key, value]) => {
if (value && typeof value === "object") {
acc[key] = acc[key] ? { ...acc[key], ...value } : value;
}
else {
acc[key] = value;
}
return acc;
}, { ...base });
}
//# sourceMappingURL=protocol.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,13 @@
import { JSONRPCMessage } from "../types.js";
/**
* Buffers a continuous stdio stream into discrete JSON-RPC messages.
*/
export declare class ReadBuffer {
private _buffer?;
append(chunk: Buffer): void;
readMessage(): JSONRPCMessage | null;
clear(): void;
}
export declare function deserializeMessage(line: string): JSONRPCMessage;
export declare function serializeMessage(message: JSONRPCMessage): string;
//# sourceMappingURL=stdio.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../src/shared/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAEnE;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAC,CAAS;IAEzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI3B,WAAW,IAAI,cAAc,GAAG,IAAI;IAepC,KAAK,IAAI,IAAI;CAGd;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAE/D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAEhE"}

View File

@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReadBuffer = void 0;
exports.deserializeMessage = deserializeMessage;
exports.serializeMessage = serializeMessage;
const types_js_1 = require("../types.js");
/**
* Buffers a continuous stdio stream into discrete JSON-RPC messages.
*/
class ReadBuffer {
append(chunk) {
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
}
readMessage() {
if (!this._buffer) {
return null;
}
const index = this._buffer.indexOf("\n");
if (index === -1) {
return null;
}
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, '');
this._buffer = this._buffer.subarray(index + 1);
return deserializeMessage(line);
}
clear() {
this._buffer = undefined;
}
}
exports.ReadBuffer = ReadBuffer;
function deserializeMessage(line) {
return types_js_1.JSONRPCMessageSchema.parse(JSON.parse(line));
}
function serializeMessage(message) {
return JSON.stringify(message) + "\n";
}
//# sourceMappingURL=stdio.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../../src/shared/stdio.ts"],"names":[],"mappings":";;;AAgCA,gDAEC;AAED,4CAEC;AAtCD,0CAAmE;AAEnE;;GAEG;AACH,MAAa,UAAU;IAGrB,MAAM,CAAC,KAAa;QAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7E,CAAC;IAED,WAAW;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAChD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;IAC3B,CAAC;CACF;AAzBD,gCAyBC;AAED,SAAgB,kBAAkB,CAAC,IAAY;IAC7C,OAAO,+BAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,SAAgB,gBAAgB,CAAC,OAAuB;IACtD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;AACxC,CAAC"}

View File

@@ -0,0 +1,75 @@
import { JSONRPCMessage, MessageExtraInfo, RequestId } from "../types.js";
export type FetchLike = (url: string | URL, init?: RequestInit) => Promise<Response>;
/**
* Options for sending a JSON-RPC message.
*/
export type TransportSendOptions = {
/**
* If present, `relatedRequestId` is used to indicate to the transport which incoming request to associate this outgoing message with.
*/
relatedRequestId?: RequestId;
/**
* The resumption token used to continue long-running requests that were interrupted.
*
* This allows clients to reconnect and continue from where they left off, if supported by the transport.
*/
resumptionToken?: string;
/**
* A callback that is invoked when the resumption token changes, if supported by the transport.
*
* This allows clients to persist the latest token for potential reconnection.
*/
onresumptiontoken?: (token: string) => void;
};
/**
* Describes the minimal contract for a MCP transport that a client or server can communicate over.
*/
export interface Transport {
/**
* Starts processing messages on the transport, including any connection steps that might need to be taken.
*
* This method should only be called after callbacks are installed, or else messages may be lost.
*
* NOTE: This method should not be called explicitly when using Client, Server, or Protocol classes, as they will implicitly call start().
*/
start(): Promise<void>;
/**
* Sends a JSON-RPC message (request or response).
*
* If present, `relatedRequestId` is used to indicate to the transport which incoming request to associate this outgoing message with.
*/
send(message: JSONRPCMessage, options?: TransportSendOptions): Promise<void>;
/**
* Closes the connection.
*/
close(): Promise<void>;
/**
* Callback for when the connection is closed for any reason.
*
* This should be invoked when close() is called as well.
*/
onclose?: () => void;
/**
* Callback for when an error occurs.
*
* Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
*/
onerror?: (error: Error) => void;
/**
* Callback for when a message (request or response) is received over the connection.
*
* Includes the requestInfo and authInfo if the transport is authenticated.
*
* The requestInfo can be used to get the original request information (headers, etc.)
*/
onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void;
/**
* The session ID generated for this connection.
*/
sessionId?: string;
/**
* Sets the protocol version used for the connection (called when the initialize response is received).
*/
setProtocolVersion?: (version: string) => void;
}
//# sourceMappingURL=transport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/shared/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE1E,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;OAEG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAE7B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C,CAAA;AACD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;OAMG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7E;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAExE;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=transport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../src/shared/transport.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,25 @@
export type Variables = Record<string, string | string[]>;
export declare class UriTemplate {
/**
* Returns true if the given string contains any URI template expressions.
* A template expression is a sequence of characters enclosed in curly braces,
* like {foo} or {?bar}.
*/
static isTemplate(str: string): boolean;
private static validateLength;
private readonly template;
private readonly parts;
get variableNames(): string[];
constructor(template: string);
toString(): string;
private parse;
private getOperator;
private getNames;
private encodeValue;
private expandPart;
expand(variables: Variables): string;
private escapeRegExp;
private partToRegExp;
match(uri: string): Variables | null;
}
//# sourceMappingURL=uriTemplate.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"uriTemplate.d.ts","sourceRoot":"","sources":["../../../src/shared/uriTemplate.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;AAO1D,qBAAa,WAAW;IACtB;;;;OAIG;IACH,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAMvC,OAAO,CAAC,MAAM,CAAC,cAAc;IAW7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAGpB;IAEF,IAAI,aAAa,IAAI,MAAM,EAAE,CAE5B;gBAEW,QAAQ,EAAE,MAAM;IAM5B,QAAQ,IAAI,MAAM;IAIlB,OAAO,CAAC,KAAK;IA4Db,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,UAAU;IAwDlB,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM;IA4BpC,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IAkDpB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CA2CrC"}

View File

@@ -0,0 +1,245 @@
"use strict";
// Claude-authored implementation of RFC 6570 URI Templates
Object.defineProperty(exports, "__esModule", { value: true });
exports.UriTemplate = void 0;
const MAX_TEMPLATE_LENGTH = 1000000; // 1MB
const MAX_VARIABLE_LENGTH = 1000000; // 1MB
const MAX_TEMPLATE_EXPRESSIONS = 10000;
const MAX_REGEX_LENGTH = 1000000; // 1MB
class UriTemplate {
/**
* Returns true if the given string contains any URI template expressions.
* A template expression is a sequence of characters enclosed in curly braces,
* like {foo} or {?bar}.
*/
static isTemplate(str) {
// Look for any sequence of characters between curly braces
// that isn't just whitespace
return /\{[^}\s]+\}/.test(str);
}
static validateLength(str, max, context) {
if (str.length > max) {
throw new Error(`${context} exceeds maximum length of ${max} characters (got ${str.length})`);
}
}
get variableNames() {
return this.parts.flatMap((part) => typeof part === 'string' ? [] : part.names);
}
constructor(template) {
UriTemplate.validateLength(template, MAX_TEMPLATE_LENGTH, "Template");
this.template = template;
this.parts = this.parse(template);
}
toString() {
return this.template;
}
parse(template) {
const parts = [];
let currentText = "";
let i = 0;
let expressionCount = 0;
while (i < template.length) {
if (template[i] === "{") {
if (currentText) {
parts.push(currentText);
currentText = "";
}
const end = template.indexOf("}", i);
if (end === -1)
throw new Error("Unclosed template expression");
expressionCount++;
if (expressionCount > MAX_TEMPLATE_EXPRESSIONS) {
throw new Error(`Template contains too many expressions (max ${MAX_TEMPLATE_EXPRESSIONS})`);
}
const expr = template.slice(i + 1, end);
const operator = this.getOperator(expr);
const exploded = expr.includes("*");
const names = this.getNames(expr);
const name = names[0];
// Validate variable name length
for (const name of names) {
UriTemplate.validateLength(name, MAX_VARIABLE_LENGTH, "Variable name");
}
parts.push({ name, operator, names, exploded });
i = end + 1;
}
else {
currentText += template[i];
i++;
}
}
if (currentText) {
parts.push(currentText);
}
return parts;
}
getOperator(expr) {
const operators = ["+", "#", ".", "/", "?", "&"];
return operators.find((op) => expr.startsWith(op)) || "";
}
getNames(expr) {
const operator = this.getOperator(expr);
return expr
.slice(operator.length)
.split(",")
.map((name) => name.replace("*", "").trim())
.filter((name) => name.length > 0);
}
encodeValue(value, operator) {
UriTemplate.validateLength(value, MAX_VARIABLE_LENGTH, "Variable value");
if (operator === "+" || operator === "#") {
return encodeURI(value);
}
return encodeURIComponent(value);
}
expandPart(part, variables) {
if (part.operator === "?" || part.operator === "&") {
const pairs = part.names
.map((name) => {
const value = variables[name];
if (value === undefined)
return "";
const encoded = Array.isArray(value)
? value.map((v) => this.encodeValue(v, part.operator)).join(",")
: this.encodeValue(value.toString(), part.operator);
return `${name}=${encoded}`;
})
.filter((pair) => pair.length > 0);
if (pairs.length === 0)
return "";
const separator = part.operator === "?" ? "?" : "&";
return separator + pairs.join("&");
}
if (part.names.length > 1) {
const values = part.names
.map((name) => variables[name])
.filter((v) => v !== undefined);
if (values.length === 0)
return "";
return values.map((v) => (Array.isArray(v) ? v[0] : v)).join(",");
}
const value = variables[part.name];
if (value === undefined)
return "";
const values = Array.isArray(value) ? value : [value];
const encoded = values.map((v) => this.encodeValue(v, part.operator));
switch (part.operator) {
case "":
return encoded.join(",");
case "+":
return encoded.join(",");
case "#":
return "#" + encoded.join(",");
case ".":
return "." + encoded.join(".");
case "/":
return "/" + encoded.join("/");
default:
return encoded.join(",");
}
}
expand(variables) {
let result = "";
let hasQueryParam = false;
for (const part of this.parts) {
if (typeof part === "string") {
result += part;
continue;
}
const expanded = this.expandPart(part, variables);
if (!expanded)
continue;
// Convert ? to & if we already have a query parameter
if ((part.operator === "?" || part.operator === "&") && hasQueryParam) {
result += expanded.replace("?", "&");
}
else {
result += expanded;
}
if (part.operator === "?" || part.operator === "&") {
hasQueryParam = true;
}
}
return result;
}
escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
partToRegExp(part) {
const patterns = [];
// Validate variable name length for matching
for (const name of part.names) {
UriTemplate.validateLength(name, MAX_VARIABLE_LENGTH, "Variable name");
}
if (part.operator === "?" || part.operator === "&") {
for (let i = 0; i < part.names.length; i++) {
const name = part.names[i];
const prefix = i === 0 ? "\\" + part.operator : "&";
patterns.push({
pattern: prefix + this.escapeRegExp(name) + "=([^&]+)",
name,
});
}
return patterns;
}
let pattern;
const name = part.name;
switch (part.operator) {
case "":
pattern = part.exploded ? "([^/]+(?:,[^/]+)*)" : "([^/,]+)";
break;
case "+":
case "#":
pattern = "(.+)";
break;
case ".":
pattern = "\\.([^/,]+)";
break;
case "/":
pattern = "/" + (part.exploded ? "([^/]+(?:,[^/]+)*)" : "([^/,]+)");
break;
default:
pattern = "([^/]+)";
}
patterns.push({ pattern, name });
return patterns;
}
match(uri) {
UriTemplate.validateLength(uri, MAX_TEMPLATE_LENGTH, "URI");
let pattern = "^";
const names = [];
for (const part of this.parts) {
if (typeof part === "string") {
pattern += this.escapeRegExp(part);
}
else {
const patterns = this.partToRegExp(part);
for (const { pattern: partPattern, name } of patterns) {
pattern += partPattern;
names.push({ name, exploded: part.exploded });
}
}
}
pattern += "$";
UriTemplate.validateLength(pattern, MAX_REGEX_LENGTH, "Generated regex pattern");
const regex = new RegExp(pattern);
const match = uri.match(regex);
if (!match)
return null;
const result = {};
for (let i = 0; i < names.length; i++) {
const { name, exploded } = names[i];
const value = match[i + 1];
const cleanName = name.replace("*", "");
if (exploded && value.includes(",")) {
result[cleanName] = value.split(",");
}
else {
result[cleanName] = value;
}
}
return result;
}
}
exports.UriTemplate = UriTemplate;
//# sourceMappingURL=uriTemplate.js.map

File diff suppressed because one or more lines are too long