@kontext-dev/js-sdk 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/ai/index.cjs +12 -2
- package/dist/adapters/ai/index.cjs.map +1 -1
- package/dist/adapters/ai/index.js +12 -2
- package/dist/adapters/ai/index.js.map +1 -1
- package/dist/adapters/cloudflare/index.cjs +13 -0
- package/dist/adapters/cloudflare/index.cjs.map +1 -1
- package/dist/adapters/cloudflare/index.js +13 -0
- package/dist/adapters/cloudflare/index.js.map +1 -1
- package/dist/adapters/cloudflare/react.cjs +12 -2
- package/dist/adapters/cloudflare/react.cjs.map +1 -1
- package/dist/adapters/cloudflare/react.js +12 -2
- package/dist/adapters/cloudflare/react.js.map +1 -1
- package/dist/adapters/react/index.cjs +12 -2
- package/dist/adapters/react/index.cjs.map +1 -1
- package/dist/adapters/react/index.js +12 -2
- package/dist/adapters/react/index.js.map +1 -1
- package/dist/client/index.cjs +89 -68
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +2 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +90 -70
- package/dist/client/index.js.map +1 -1
- package/dist/errors.cjs +78 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +7 -1
- package/dist/errors.d.ts +7 -1
- package/dist/errors.js +78 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.cjs +124 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +125 -87
- package/dist/index.js.map +1 -1
- package/dist/{kontext-CgIBANFo.d.cts → kontext-CBPuE-hq.d.cts} +3 -0
- package/dist/{kontext-CgIBANFo.d.ts → kontext-CBPuE-hq.d.ts} +3 -0
- package/dist/management/index.cjs +15 -0
- package/dist/management/index.cjs.map +1 -1
- package/dist/management/index.d.cts +2 -2
- package/dist/management/index.d.ts +2 -2
- package/dist/management/index.js +15 -1
- package/dist/management/index.js.map +1 -1
- package/dist/mcp/index.cjs +13 -2
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.d.cts +3 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +14 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/oauth/index.cjs +12 -2
- package/dist/oauth/index.cjs.map +1 -1
- package/dist/oauth/index.d.cts +1 -1
- package/dist/oauth/index.d.ts +1 -1
- package/dist/oauth/index.js +12 -2
- package/dist/oauth/index.js.map +1 -1
- package/dist/server/index.cjs +47 -20
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +48 -21
- package/dist/server/index.js.map +1 -1
- package/dist/{types-C6ep5fVw.d.cts → types-DicGI7ix.d.cts} +21 -1
- package/dist/{types-C6ep5fVw.d.ts → types-DicGI7ix.d.ts} +21 -1
- package/package.json +1 -1
package/dist/oauth/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/types.ts","../../src/errors.ts","../../src/oauth/provider.ts","../../src/management/types.ts","../../src/oauth/token-exchange.ts"],"names":["randomBytes"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Storage interface for persisting SDK state\n */\n\n/**\n * Generic storage interface for the Kontext SDK\n * Implementations can store data in memory, file system, or external services\n */\nexport interface KontextStorage {\n /**\n * Retrieve a JSON value by key\n * @param key Storage key\n * @returns The stored value or undefined if not found\n */\n getJson<T>(key: string): Promise<T | undefined>;\n\n /**\n * Store a JSON value by key\n * @param key Storage key\n * @param value The value to store, or undefined to delete\n */\n setJson<T>(key: string, value: T | undefined): Promise<void>;\n}\n\n/**\n * Storage key namespacing helper\n * Creates namespaced keys based on application client ID and optional session key\n */\nexport function createStorageKey(\n applicationClientId: string,\n sessionKey: string | undefined,\n ...parts: string[]\n): string {\n const namespace = sessionKey\n ? `kontext:${applicationClientId}:${sessionKey}`\n : `kontext:${applicationClientId}`;\n return [namespace, ...parts].join(\":\");\n}\n\n/**\n * Storage keys used by the SDK\n */\nexport const StorageKeys = {\n // Existing keys\n TOKENS: \"tokens\",\n CODE_VERIFIER: \"code_verifier\",\n STATE: \"state\",\n CLIENT_INFO: \"client_info\",\n\n // Pattern B (RFC 8693 Token Exchange) keys\n /** Identity tokens (no audience) */\n IDENTITY_TOKENS: \"identity_tokens\",\n /** Prefix for resource-scoped tokens */\n RESOURCE_TOKENS: \"resource_tokens\",\n} as const;\n\n/**\n * Create a storage key for a resource-scoped token\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n * @returns Storage key for the resource token\n *\n * @example\n * ```typescript\n * const key = resourceTokenKey('mcp-gateway');\n * // Returns: 'resource_tokens:mcp-gateway'\n * ```\n */\nexport function resourceTokenKey(resource: string): string {\n return `${StorageKeys.RESOURCE_TOKENS}:${resource}`;\n}\n","/**\n * Typed error classes for the Kontext SDK.\n *\n * Every error has a `kontext_` prefixed code, an auto-generated docsUrl,\n * and a `kontextError` brand for type narrowing without instanceof.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Base\n// ============================================================================\n\n/**\n * Base error class for all Kontext SDK errors.\n *\n * @example\n * ```typescript\n * import { isKontextError } from '@kontext-dev/js-sdk';\n *\n * try {\n * await client.connect();\n * } catch (err) {\n * if (isKontextError(err)) {\n * console.log(err.code); // \"kontext_authorization_required\"\n * console.log(err.docsUrl); // \"https://docs.kontext.dev/errors/kontext_authorization_required\"\n * }\n * }\n * ```\n */\nexport class KontextError extends Error {\n /** Brand field for type narrowing without instanceof */\n readonly kontextError = true as const;\n\n /** Machine-readable error code, always prefixed with `kontext_` */\n readonly code: string;\n\n /** HTTP status code when applicable */\n readonly statusCode?: number;\n\n /** Auto-generated link to error documentation */\n readonly docsUrl: string;\n\n /** Server request ID for debugging / support escalation */\n readonly requestId?: string;\n\n /** Contextual metadata bag (integration IDs, param names, etc.) */\n readonly meta: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n options?: {\n statusCode?: number;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, { cause: options?.cause });\n this.name = \"KontextError\";\n this.code = code;\n this.statusCode = options?.statusCode;\n this.requestId = options?.requestId;\n this.meta = options?.meta ?? {};\n this.docsUrl = `https://docs.kontext.dev/errors/${code}`;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n statusCode: this.statusCode,\n docsUrl: this.docsUrl,\n requestId: this.requestId,\n meta: Object.keys(this.meta).length > 0 ? this.meta : undefined,\n };\n }\n\n override toString(): string {\n const parts = [`[${this.code}] ${this.message}`];\n if (this.docsUrl) parts.push(`Docs: ${this.docsUrl}`);\n if (this.requestId) parts.push(`Request ID: ${this.requestId}`);\n return parts.join(\"\\n\");\n }\n}\n\n// ============================================================================\n// Type guard\n// ============================================================================\n\n/**\n * Check if an error is a KontextError without instanceof.\n * Works across package versions and bundler deduplication.\n */\nexport function isKontextError(err: unknown): err is KontextError {\n return (\n typeof err === \"object\" &&\n err !== null &&\n (err as Record<string, unknown>).kontextError === true\n );\n}\n\n// ============================================================================\n// Auth errors\n// ============================================================================\n\n/**\n * Thrown when authentication is required but no valid credentials are available.\n */\nexport class AuthorizationRequiredError extends KontextError {\n readonly authorizationUrl?: string;\n\n constructor(\n message = \"Authorization required. Complete the OAuth flow to continue.\",\n options?: {\n authorizationUrl?: string;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, \"kontext_authorization_required\", {\n statusCode: 401,\n ...options,\n });\n this.name = \"AuthorizationRequiredError\";\n this.authorizationUrl = options?.authorizationUrl;\n }\n}\n\n// ============================================================================\n// OAuth errors\n// ============================================================================\n\n/**\n * Thrown when an OAuth flow fails — state validation, token exchange,\n * missing code verifier, or provider errors.\n */\nexport class OAuthError extends KontextError {\n readonly errorCode?: string;\n readonly errorDescription?: string;\n\n constructor(\n message: string,\n code: string,\n options?: {\n statusCode?: number;\n errorCode?: string;\n errorDescription?: string;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, code, {\n statusCode: options?.statusCode ?? 400,\n ...options,\n });\n this.name = \"OAuthError\";\n this.errorCode = options?.errorCode;\n this.errorDescription = options?.errorDescription;\n }\n}\n\n// ============================================================================\n// Integration errors\n// ============================================================================\n\n/**\n * Thrown when an integration connection is required before a tool can be used.\n */\nexport class IntegrationConnectionRequiredError extends KontextError {\n readonly integrationId: string;\n readonly integrationName?: string;\n readonly connectUrl?: string;\n\n constructor(\n integrationId: string,\n options?: {\n integrationName?: string;\n connectUrl?: string;\n message?: string;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(\n options?.message ??\n `Connection to integration \"${integrationId}\" is required. Visit the connect URL to authorize.`,\n \"kontext_integration_connection_required\",\n { statusCode: 403, ...options },\n );\n this.name = \"IntegrationConnectionRequiredError\";\n this.integrationId = integrationId;\n this.integrationName = options?.integrationName;\n this.connectUrl = options?.connectUrl;\n }\n}\n\n// ============================================================================\n// Config errors (NEW — replaces all plain Error config throws)\n// ============================================================================\n\n/**\n * Thrown when SDK configuration is invalid or missing.\n * These are deterministic errors caught at initialization time.\n */\nexport class ConfigError extends KontextError {\n constructor(\n message: string,\n code: string,\n options?: {\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, code, options);\n this.name = \"ConfigError\";\n }\n}\n\n// ============================================================================\n// Network errors\n// ============================================================================\n\n/**\n * Thrown when there is a network or connection error.\n */\nexport class NetworkError extends KontextError {\n constructor(\n message = \"Network error. Check your internet connection and that the server is reachable.\",\n options?: {\n cause?: unknown;\n requestId?: string;\n meta?: Record<string, unknown>;\n },\n ) {\n super(message, \"kontext_network_error\", options);\n this.name = \"NetworkError\";\n }\n}\n\n// ============================================================================\n// HTTP response errors (differentiated by code)\n// ============================================================================\n\n/**\n * Thrown when the server returns an HTTP error.\n * Use `error.code` to distinguish between specific error types.\n */\nexport class HttpError extends KontextError {\n readonly retryAfter?: number;\n readonly validationErrors?: Array<{ field: string; message: string }>;\n\n constructor(\n message: string,\n code: string,\n options?: {\n statusCode?: number;\n retryAfter?: number;\n validationErrors?: Array<{ field: string; message: string }>;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, code, {\n statusCode: options?.statusCode,\n ...options,\n });\n this.name = \"HttpError\";\n this.retryAfter = options?.retryAfter;\n this.validationErrors = options?.validationErrors;\n }\n}\n\n// ============================================================================\n// Network error detection (used by translateError)\n// ============================================================================\n\n/**\n * Safely access arbitrary properties on an error object.\n * Errors in JS frequently carry extra properties (code, statusCode, etc.)\n * that aren't part of the Error interface. This avoids `as unknown as` casts.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction errorProps(err: Error): Record<string, any> {\n return err;\n}\n\nconst NETWORK_ERROR_CODES = new Set([\n \"ECONNREFUSED\",\n \"ENOTFOUND\",\n \"ETIMEDOUT\",\n \"ECONNRESET\",\n \"ECONNABORTED\",\n \"EPIPE\",\n \"UND_ERR_CONNECT_TIMEOUT\",\n]);\n\n/**\n * Detect network errors structurally rather than by string matching.\n * Checks Node.js system error codes on the error and its cause.\n */\nexport function isNetworkError(err: Error): boolean {\n if (err.name === \"AbortError\") return true;\n\n const props = errorProps(err);\n const sysCode = props.code as string | undefined;\n if (typeof sysCode === \"string\" && NETWORK_ERROR_CODES.has(sysCode))\n return true;\n\n // fetch() throws TypeError — only classify as network error when cause\n // indicates a system-level failure\n if (err.name === \"TypeError\" && err.cause instanceof Error) {\n const causeCode = errorProps(err.cause).code;\n if (typeof causeCode === \"string\" && NETWORK_ERROR_CODES.has(causeCode))\n return true;\n }\n\n return false;\n}\n\n/**\n * Detect unauthorized errors structurally.\n * Checks status code and numeric code rather than string matching on name.\n */\nexport function isUnauthorizedError(err: Error): boolean {\n const props = errorProps(err);\n\n // Check HTTP status code (most reliable)\n if (props.statusCode === 401 || props.status === 401) return true;\n\n // Check MCP SDK UnauthorizedError by name (last resort, but needed for\n // MCP SDK errors which don't set statusCode)\n if (err.name === \"UnauthorizedError\") return true;\n if (err.message === \"Unauthorized\") return true;\n\n return false;\n}\n\n// ============================================================================\n// Elicitation types\n// ============================================================================\n\nexport interface ElicitationEntry {\n readonly url: string;\n readonly message: string;\n readonly elicitationId: string;\n readonly integrationId?: string;\n readonly integrationName?: string;\n}\n\n// ============================================================================\n// HTTP error parsing\n// ============================================================================\n\n/**\n * Parse an HTTP response into an appropriate error.\n */\nexport function parseHttpError(\n statusCode: number,\n body?: unknown,\n): KontextError {\n const message =\n typeof body === \"object\" && body !== null && \"message\" in body\n ? String((body as { message: unknown }).message)\n : `HTTP ${statusCode}`;\n\n const errorCode =\n typeof body === \"object\" && body !== null && \"code\" in body\n ? String((body as { code: unknown }).code)\n : undefined;\n\n switch (statusCode) {\n case 400:\n if (\n typeof body === \"object\" &&\n body !== null &&\n \"errors\" in body &&\n Array.isArray((body as { errors: unknown }).errors)\n ) {\n return new HttpError(message, \"kontext_validation_error\", {\n statusCode: 400,\n validationErrors: (\n body as { errors: Array<{ field: string; message: string }> }\n ).errors,\n });\n }\n return new KontextError(message, errorCode ?? \"kontext_bad_request\", {\n statusCode: 400,\n });\n\n case 401:\n return new AuthorizationRequiredError(message);\n\n case 403:\n if (errorCode === \"INTEGRATION_CONNECTION_REQUIRED\") {\n const details = body as {\n integrationId?: string;\n integrationName?: string;\n connectUrl?: string;\n };\n return new IntegrationConnectionRequiredError(\n details.integrationId ?? \"unknown\",\n {\n integrationName: details.integrationName,\n connectUrl: details.connectUrl,\n message,\n },\n );\n }\n return new HttpError(message, \"kontext_policy_denied\", {\n statusCode: 403,\n meta: { policy: (body as Record<string, unknown>)?.policy },\n });\n\n case 404:\n return new HttpError(message, \"kontext_not_found\", { statusCode: 404 });\n\n case 429: {\n const retryAfter =\n typeof body === \"object\" && body !== null && \"retryAfter\" in body\n ? Number((body as { retryAfter: unknown }).retryAfter)\n : undefined;\n return new HttpError(\n retryAfter\n ? `Rate limit exceeded. Retry after ${retryAfter} seconds.`\n : \"Rate limit exceeded. Wait and retry.\",\n \"kontext_rate_limited\",\n { statusCode: 429, retryAfter },\n );\n }\n\n default:\n if (statusCode >= 500) {\n return new HttpError(\n `Server error (HTTP ${statusCode}): ${message}`,\n \"kontext_server_error\",\n { statusCode },\n );\n }\n return new KontextError(message, errorCode ?? \"kontext_unknown_error\", {\n statusCode,\n });\n }\n}\n","/**\n * KontextOAuthProvider - Implements OAuthClientProvider from @modelcontextprotocol/sdk\n *\n * This provider handles the OAuth 2.0 Authorization Code + PKCE flow\n * for authenticating MCP clients with the Kontext Gateway.\n */\n\nimport type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type {\n OAuthClientMetadata,\n OAuthClientInformationMixed,\n OAuthTokens,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { randomBytes } from \"node:crypto\";\nimport type { KontextStorage } from \"../storage/types.js\";\nimport {\n createStorageKey,\n StorageKeys,\n resourceTokenKey,\n} from \"../storage/types.js\";\nimport { OAuthError } from \"../errors.js\";\n\nexport interface KontextOAuthProviderConfig {\n /**\n * Application OAuth client ID from Kontext\n */\n clientId: string;\n\n /**\n * Redirect URI for OAuth callback\n * Must match one of the registered redirect URIs for the application\n */\n redirectUri: string;\n\n /**\n * Storage implementation for persisting tokens and PKCE state\n */\n storage: KontextStorage;\n\n /**\n * Optional session key for namespacing storage\n * Useful when multiple users/sessions share the same storage\n */\n sessionKey?: string;\n\n /**\n * Optional client name for OAuth metadata\n */\n clientName?: string;\n\n /**\n * Callback to redirect the user agent to the authorization URL\n * This is called when authorization is required\n *\n * @param url The authorization URL to redirect to\n */\n onRedirectToAuthorization: (url: URL) => void | Promise<void>;\n}\n\n/**\n * OAuth provider implementation for Kontext MCP clients\n *\n * Implements the OAuthClientProvider interface from @modelcontextprotocol/sdk\n * to handle Authorization Code + PKCE authentication flow.\n *\n * @example\n * ```typescript\n * const storage = new MemoryStorage();\n * const provider = new KontextOAuthProvider({\n * clientId: 'your-client-id',\n * redirectUri: 'http://localhost:3000/callback',\n * storage,\n * onRedirectToAuthorization: (url) => {\n * // Open browser or redirect\n * window.location.href = url.toString();\n * },\n * });\n * ```\n */\nexport class KontextOAuthProvider implements OAuthClientProvider {\n private readonly config: KontextOAuthProviderConfig;\n private readonly storagePrefix: string;\n private pendingState: string | null = null;\n private readonly expiryBufferMs = 60 * 1000;\n\n constructor(config: KontextOAuthProviderConfig) {\n this.config = config;\n this.storagePrefix = createStorageKey(config.clientId, config.sessionKey);\n }\n\n /**\n * The redirect URL for OAuth callbacks\n */\n get redirectUrl(): string | URL {\n return this.config.redirectUri;\n }\n\n /**\n * OAuth client metadata\n */\n get clientMetadata(): OAuthClientMetadata {\n return {\n redirect_uris: [this.config.redirectUri],\n client_name: this.config.clientName,\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\", // Public client\n };\n }\n\n /**\n * Generate a random state parameter for OAuth CSRF protection\n */\n state(): string {\n // Generate a cryptographically secure random string\n const array = new Uint8Array(32);\n if (globalThis.crypto?.getRandomValues) {\n globalThis.crypto.getRandomValues(array);\n } else {\n array.set(randomBytes(32));\n }\n const state = Array.from(array, (byte) =>\n byte.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n this.pendingState = state;\n void this.config.storage.setJson(\n this.getStorageKey(StorageKeys.STATE),\n state,\n );\n return state;\n }\n\n /**\n * Returns the client information (client_id)\n * Since we're a public client with pre-registered credentials,\n * we don't use dynamic client registration.\n */\n async clientInformation(): Promise<OAuthClientInformationMixed | undefined> {\n return {\n client_id: this.config.clientId,\n };\n }\n\n /**\n * Load stored OAuth tokens\n */\n async tokens(): Promise<OAuthTokens | undefined> {\n const key = this.getStorageKey(StorageKeys.TOKENS);\n return this.config.storage.getJson<OAuthTokens>(key);\n }\n\n /**\n * Save OAuth tokens after successful authorization\n */\n async saveTokens(tokens: OAuthTokens): Promise<void> {\n const key = this.getStorageKey(StorageKeys.TOKENS);\n await this.config.storage.setJson(key, this.withIssuedAt(tokens));\n }\n\n /**\n * Redirect the user agent to the authorization URL\n */\n async redirectToAuthorization(authorizationUrl: URL): Promise<void> {\n await this.config.onRedirectToAuthorization(authorizationUrl);\n }\n\n /**\n * Save the PKCE code verifier before redirecting to authorization\n */\n async saveCodeVerifier(codeVerifier: string): Promise<void> {\n const key = this.getStorageKey(StorageKeys.CODE_VERIFIER);\n await this.config.storage.setJson(key, codeVerifier);\n }\n\n /**\n * Load the PKCE code verifier for token exchange\n */\n async codeVerifier(): Promise<string> {\n const key = this.getStorageKey(StorageKeys.CODE_VERIFIER);\n const verifier = await this.config.storage.getJson<string>(key);\n if (!verifier) {\n throw new OAuthError(\n \"No PKCE code verifier found in storage. The OAuth flow may have expired or storage was cleared. Restart the auth flow.\",\n \"kontext_oauth_code_verifier_missing\",\n );\n }\n return verifier;\n }\n\n /**\n * Invalidate stored credentials\n */\n async invalidateCredentials(\n scope: \"all\" | \"client\" | \"tokens\" | \"verifier\",\n ): Promise<void> {\n if (scope === \"all\" || scope === \"tokens\") {\n const tokensKey = this.getStorageKey(StorageKeys.TOKENS);\n await this.config.storage.setJson(tokensKey, undefined);\n const identityKey = this.getStorageKey(StorageKeys.IDENTITY_TOKENS);\n await this.config.storage.setJson(identityKey, undefined);\n }\n if (scope === \"all\" || scope === \"verifier\") {\n const verifierKey = this.getStorageKey(StorageKeys.CODE_VERIFIER);\n await this.config.storage.setJson(verifierKey, undefined);\n }\n if (scope === \"all\") {\n this.pendingState = null;\n const stateKey = this.getStorageKey(StorageKeys.STATE);\n await this.config.storage.setJson(stateKey, undefined);\n }\n // 'client' scope is a no-op since we use pre-registered client info\n }\n\n /**\n * Clear all stored state (tokens, verifier, etc.)\n * Call this to force re-authentication\n */\n async clearAll(): Promise<void> {\n await this.invalidateCredentials(\"all\");\n }\n\n /**\n * Check if we have valid (non-expired) tokens\n */\n async hasValidTokens(): Promise<boolean> {\n const storedTokens = await this.tokens();\n return this.isTokenValid(storedTokens);\n }\n\n // ==========================================================================\n // Pattern B: Identity and Resource Token Management (RFC 8693)\n // ==========================================================================\n\n /**\n * Save identity tokens (no audience)\n * These are the tokens obtained from the initial OAuth flow before token exchange.\n */\n async saveIdentityTokens(tokens: OAuthTokens): Promise<void> {\n const key = this.getStorageKey(StorageKeys.IDENTITY_TOKENS);\n await this.config.storage.setJson(key, this.withIssuedAt(tokens));\n }\n\n /**\n * Load identity tokens\n * Returns the identity tokens obtained from the initial OAuth flow.\n */\n async identityTokens(): Promise<OAuthTokens | undefined> {\n const key = this.getStorageKey(StorageKeys.IDENTITY_TOKENS);\n return this.config.storage.getJson<OAuthTokens>(key);\n }\n\n /**\n * Save resource-scoped tokens for a specific resource\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n * @param tokens The resource-scoped tokens\n */\n async saveResourceTokens(\n resource: string,\n tokens: OAuthTokens,\n ): Promise<void> {\n const key = this.getStorageKey(resourceTokenKey(resource));\n await this.config.storage.setJson(key, this.withIssuedAt(tokens));\n }\n\n /**\n * Load resource-scoped tokens for a specific resource\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n * @returns The resource-scoped tokens, or undefined if not found\n */\n async resourceTokens(resource: string): Promise<OAuthTokens | undefined> {\n const key = this.getStorageKey(resourceTokenKey(resource));\n return this.config.storage.getJson<OAuthTokens>(key);\n }\n\n /**\n * Clear resource tokens for a specific resource\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n */\n async clearResourceTokens(resource: string): Promise<void> {\n const key = this.getStorageKey(resourceTokenKey(resource));\n await this.config.storage.setJson(key, undefined);\n }\n\n /**\n * Check if we have valid identity tokens\n */\n async hasValidIdentityTokens(): Promise<boolean> {\n const tokens = await this.identityTokens();\n return this.isTokenValid(tokens);\n }\n\n /**\n * Check if we have valid resource tokens for a specific resource\n *\n * @param resource The resource identifier\n */\n async hasValidResourceTokens(resource: string): Promise<boolean> {\n const tokens = await this.resourceTokens(resource);\n return this.isTokenValid(tokens);\n }\n\n async validateState(state?: string): Promise<boolean> {\n if (!state) {\n return false;\n }\n\n const key = this.getStorageKey(StorageKeys.STATE);\n const storedState =\n this.pendingState ?? (await this.config.storage.getJson<string>(key));\n const isValid = storedState === state;\n\n if (isValid) {\n this.pendingState = null;\n await this.config.storage.setJson(key, undefined);\n }\n\n return isValid;\n }\n\n private withIssuedAt(\n tokens: OAuthTokens,\n ): OAuthTokens & { issued_at?: number } {\n if (!tokens.expires_in) {\n return tokens;\n }\n return { ...tokens, issued_at: Date.now() };\n }\n\n private isTokenValid(tokens?: OAuthTokens): boolean {\n if (!tokens?.access_token) {\n return false;\n }\n\n if (!tokens.expires_in) {\n return true;\n }\n\n const issuedAt = (tokens as OAuthTokens & { issued_at?: number }).issued_at;\n if (!issuedAt) {\n return true;\n }\n\n const expiresAt = issuedAt + tokens.expires_in * 1000;\n return Date.now() < expiresAt - this.expiryBufferMs;\n }\n\n private getStorageKey(key: string): string {\n return `${this.storagePrefix}:${key}`;\n }\n}\n\n/**\n * Parse an OAuth callback URL and extract the authorization code and state\n *\n * @param callbackUrl The full callback URL with query parameters\n * @returns The authorization code and state, or error details\n */\nexport function parseOAuthCallback(callbackUrl: string | URL): {\n code?: string;\n state?: string;\n error?: string;\n errorDescription?: string;\n} {\n const url =\n typeof callbackUrl === \"string\" ? new URL(callbackUrl) : callbackUrl;\n const params = url.searchParams;\n\n const error = params.get(\"error\");\n if (error) {\n return {\n error,\n errorDescription: params.get(\"error_description\") ?? undefined,\n };\n }\n\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n}\n","/**\n * Core types for the Kontext SDK\n * These mirror the API DTOs for type-safe interactions\n */\n\n// ============================================================================\n// Applications\n// ============================================================================\n\nexport interface Application {\n id: string;\n name: string;\n canModify?: boolean;\n activeSessionCount?: number;\n idleSessionCount?: number;\n liveSessionCount?: number;\n totalSessionCount?: number;\n oauth?: ApplicationOAuth;\n archivedAt?: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ApplicationOAuth {\n type: \"public\" | \"confidential\";\n clientId: string;\n clientSecret?: string;\n pkceRequired: boolean;\n scopes: string[];\n authorizationUrl: string;\n tokenUrl: string;\n gatewayUrl: string;\n redirectUris: string[];\n}\n\nexport interface CreateApplicationOAuthInput {\n type?: \"public\" | \"confidential\";\n redirectUris: string[];\n pkceRequired?: boolean;\n scopes?: string[];\n}\n\nexport interface CreateApplicationInput {\n name: string;\n oauth: CreateApplicationOAuthInput;\n}\n\nexport interface UpdateApplicationInput {\n name?: string;\n}\n\nexport interface UpdateApplicationOAuthInput {\n pkceRequired?: boolean;\n scopes?: string[];\n redirectUris?: string[];\n}\n\nexport interface CreateApplicationResponse {\n application: Application;\n oauth: ApplicationOAuth;\n}\n\nexport interface ApplicationResponse {\n application: Application;\n}\n\nexport interface ApplicationOAuthResponse {\n oauth: ApplicationOAuth;\n}\n\nexport interface ListApplicationsResponse {\n items: Application[];\n nextCursor?: string;\n}\n\nexport interface RotateApplicationSecretResponse {\n oauth: ApplicationOAuth;\n}\n\nexport interface UpdateApplicationIntegrationsInput {\n integrationIds: string[];\n}\n\nexport interface ApplicationIntegrationsResponse {\n integrationIds: string[];\n}\n\n// ============================================================================\n// Integrations\n// ============================================================================\n\nexport type IntegrationAuthMode =\n | \"oauth\"\n | \"user_token\"\n | \"server_token\"\n | \"none\";\n\nexport type IntegrationValidationStatus = \"pending\" | \"valid\" | \"invalid\";\n\nexport interface IntegrationOAuthSummary {\n provider?: string;\n issuer?: string;\n scopes?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface IntegrationCapabilities {\n tools?: boolean;\n resources?: boolean;\n prompts?: boolean;\n}\n\nexport interface Integration {\n id: string;\n name: string;\n url: string;\n authMode: IntegrationAuthMode;\n oauth?: IntegrationOAuthSummary;\n capabilities?: IntegrationCapabilities;\n serverTokenConfigured: boolean;\n validationStatus: IntegrationValidationStatus;\n validationMessage?: string;\n lastValidatedAt?: string;\n userConnection?: ConnectionStatusResponse;\n createdAt: string;\n updatedAt: string;\n archivedAt?: string;\n}\n\nexport interface IntegrationOAuthConfigInput {\n provider?: string;\n issuer?: string;\n scopes?: string[];\n}\n\nexport interface CreateIntegrationInput {\n name: string;\n url: string;\n authMode?: IntegrationAuthMode;\n oauth?: IntegrationOAuthConfigInput;\n capabilities?: IntegrationCapabilities;\n serverToken?: string;\n}\n\nexport interface UpdateIntegrationInput {\n name?: string;\n url?: string;\n authMode?: IntegrationAuthMode;\n oauth?: IntegrationOAuthConfigInput;\n capabilities?: IntegrationCapabilities;\n serverToken?: string;\n}\n\nexport interface CreateIntegrationResponse {\n integration: Integration;\n}\n\nexport interface IntegrationResponse {\n integration: Integration;\n}\n\nexport interface ListIntegrationsResponse {\n items: Integration[];\n nextCursor?: string;\n}\n\nexport interface ValidateIntegrationResponse {\n status: IntegrationValidationStatus;\n message?: string;\n}\n\n// ============================================================================\n// Integration Connections\n// ============================================================================\n\nexport type ConnectionStatus = \"connected\" | \"disconnected\";\n\nexport interface ConnectionStatusResponse {\n connected: boolean;\n status?: ConnectionStatus;\n expiresAt?: string;\n displayName?: string;\n}\n\nexport interface ConnectionResponse {\n connection: ConnectionStatusResponse;\n}\n\nexport interface AddUserTokenInput {\n token: string;\n}\n\n// ============================================================================\n// Service Accounts\n// ============================================================================\n\nexport interface ServiceAccount {\n id: string;\n name: string;\n description: string | null;\n createdAt: string;\n}\n\nexport interface ServiceAccountCredentials {\n clientId: string;\n clientSecret: string;\n}\n\nexport interface CreateServiceAccountInput {\n name: string;\n description?: string;\n}\n\nexport interface CreateServiceAccountResponse {\n serviceAccount: ServiceAccount;\n credentials: ServiceAccountCredentials;\n}\n\nexport interface RotateSecretResponse {\n credentials: ServiceAccountCredentials;\n}\n\nexport interface ListServiceAccountsResponse {\n items: ServiceAccount[];\n nextCursor: string | null;\n}\n\nexport interface ServiceAccountResponse {\n serviceAccount: ServiceAccount;\n}\n\n// ============================================================================\n// Agent Sessions\n// ============================================================================\n\nexport type AgentSessionStatus = \"active\" | \"disconnected\";\nexport type AgentSessionDerivedStatus =\n | \"active\"\n | \"idle\"\n | \"expired\"\n | \"disconnected\";\n\nexport interface AgentSession {\n id: string;\n agentId: string;\n organizationId: string;\n authenticatedUserId: string;\n authenticatedUserEmail?: string | null;\n name: string;\n hostname?: string | null;\n userAgent?: string | null;\n clientInfo?: Record<string, unknown> | null;\n status: AgentSessionStatus;\n derivedStatus: AgentSessionDerivedStatus;\n connectedAt?: string;\n lastActiveAt?: string;\n disconnectedAt?: string;\n tokenExpiresAt?: string;\n createdAt: string;\n}\n\nexport interface AgentSessionResponse {\n session: AgentSession;\n}\n\nexport interface ListAgentSessionsResponse {\n items: AgentSession[];\n}\n\nexport interface RevokeAllSessionsResponse {\n success: boolean;\n disconnectedCount: number;\n}\n\n// ============================================================================\n// Traces & Events\n// ============================================================================\n\nexport interface Trace {\n traceId: string | null;\n sessionId: string;\n startedAt: string | null;\n endedAt: string | null;\n eventCount: number;\n okCount?: number;\n warnCount?: number;\n errorCount?: number;\n agentId?: string;\n ownerUserId?: string;\n ownerEmail?: string;\n agentName?: string;\n agentSessionId?: string;\n agentSessionName?: string;\n}\n\nexport interface TraceEvent {\n id: string;\n createdAt: string;\n sessionId: string;\n agentId: string;\n traceId?: string | null;\n apiKeyId?: string | null;\n eventType: string;\n status: string;\n durationMs?: number | null;\n integrationId?: string | null;\n toolName?: string | null;\n errorMessage?: string | null;\n bytesIn?: number | null;\n bytesOut?: number | null;\n requestJson?: unknown;\n responseJson?: unknown;\n parentEventId?: string | null;\n agentSessionId?: string | null;\n /** @deprecated Use createdAt */\n timestamp?: string;\n /** @deprecated Use status */\n level?: \"ok\" | \"warn\" | \"error\";\n /** @deprecated Use eventType */\n type?: string;\n /** @deprecated May be encoded in requestJson/responseJson */\n method?: string;\n /** @deprecated Use toolName */\n tool?: string;\n /** @deprecated Use durationMs */\n duration?: number;\n /** @deprecated Use status/errorMessage fields */\n errorType?: string;\n /** @deprecated May be encoded in requestJson/responseJson */\n metadata?: Record<string, unknown>;\n}\n\nexport interface ListTracesResponse {\n items: Trace[];\n nextCursor?: string;\n}\n\nexport interface TraceResponse {\n trace: Trace;\n events: TraceEvent[];\n}\n\nexport interface McpEvent {\n id: string;\n createdAt: string;\n agentId: string;\n integrationId: string | null;\n toolName: string | null;\n eventType: string;\n status: string;\n}\n\nexport interface McpEventListResponse {\n items: McpEvent[];\n}\n\n/**\n * @deprecated Use McpEventListResponse instead.\n */\nexport type ListEventsResponse = McpEventListResponse;\n\nexport interface TraceStats {\n totalTraces: number;\n totalEvents: number;\n eventCounts: { ok: number; warn: number; error: number };\n errorRate: number;\n latency: { avg: number; p50: number; p95: number; p99: number };\n bytesTransferred: { in: number; out: number };\n errorsByType: Array<{ type: string; count: number; percentage: number }>;\n topTools: Array<{ name: string; count: number; avgDuration: number }>;\n timeline: Array<{\n date: string;\n traceCount: number;\n eventCount: number;\n warnCount: number;\n errorCount: number;\n bytesIn: number;\n bytesOut: number;\n }>;\n}\n\nexport interface TraceStatsResponse {\n stats: TraceStats;\n}\n\n// ============================================================================\n// Pagination\n// ============================================================================\n\nexport interface PaginationParams {\n cursor?: string;\n limit?: number;\n}\n\n// ============================================================================\n// OAuth Tokens (for storage)\n// ============================================================================\n\nexport interface OAuthTokens {\n accessToken: string;\n refreshToken?: string;\n tokenType: string;\n scope?: string;\n expiresAt?: string;\n}\n\n// ============================================================================\n// Token Exchange (RFC 8693)\n// ============================================================================\n\n/**\n * RFC 8693 Token Exchange grant type\n */\nexport const TOKEN_EXCHANGE_GRANT_TYPE =\n \"urn:ietf:params:oauth:grant-type:token-exchange\";\n\n/**\n * RFC 8693 token type identifier for access tokens\n */\nexport const TOKEN_TYPE_ACCESS_TOKEN =\n \"urn:ietf:params:oauth:token-type:access_token\";\n\n/**\n * Request body for RFC 8693 token exchange\n */\nexport interface TokenExchangeRequest {\n grant_type: typeof TOKEN_EXCHANGE_GRANT_TYPE;\n subject_token: string;\n subject_token_type?: string;\n resource: string;\n scope?: string;\n audience?: string;\n}\n\n/**\n * Response from RFC 8693 token exchange\n */\nexport interface TokenExchangeResponse {\n access_token: string;\n issued_token_type: string;\n token_type: string;\n expires_in?: number;\n scope?: string;\n refresh_token?: string;\n}\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\nexport interface KontextManagementClientConfig {\n /**\n * Base URL for the Kontext API (e.g., \"https://api.kontext.dev\")\n */\n baseUrl: string;\n\n /**\n * API version to use (default: \"v1\")\n */\n apiVersion?: string;\n\n /**\n * OAuth token endpoint URL (optional)\n * If not specified, defaults to `${baseUrl}/oauth2/token`\n * Useful for local development where Hydra runs on a different port\n */\n tokenUrl?: string;\n\n /**\n * OAuth scopes to request (optional)\n * Defaults to [\"management:all\"]\n */\n scopes?: string[];\n\n /**\n * OAuth audience for token requests (optional)\n * If not specified, defaults to `${baseUrl}/api/${apiVersion}`\n * Required for Hydra token introspection\n */\n audience?: string;\n\n /**\n * Service account credentials for authentication\n */\n credentials: {\n clientId: string;\n clientSecret: string;\n };\n}\n","/**\n * RFC 8693 Token Exchange\n *\n * Generic token exchange function for exchanging identity tokens\n * for resource-scoped tokens.\n *\n * @see https://datatracker.ietf.org/doc/html/rfc8693\n */\n\nimport {\n TOKEN_EXCHANGE_GRANT_TYPE,\n TOKEN_TYPE_ACCESS_TOKEN,\n type TokenExchangeResponse,\n} from \"../management/types.js\";\nimport { OAuthError } from \"../errors.js\";\n\n/**\n * Configuration for token exchange\n */\nexport interface TokenExchangeConfig {\n /**\n * Token endpoint URL (e.g., https://api.kontext.dev/oauth2/token)\n */\n tokenUrl: string;\n\n /**\n * OAuth client ID\n */\n clientId: string;\n\n /**\n * OAuth client secret (for confidential clients)\n */\n clientSecret?: string;\n}\n\n/**\n * Exchange a subject token for a resource-scoped token (RFC 8693).\n *\n * This function implements the OAuth 2.0 Token Exchange grant type,\n * allowing an identity token to be exchanged for an access token\n * scoped to a specific resource.\n *\n * @param config - Token exchange configuration\n * @param subjectToken - The subject token to exchange (typically an access token)\n * @param resource - The target resource identifier (e.g., \"mcp-gateway\", \"my-mcp-server\")\n * @param scope - Optional scope restriction (must be subset of subject token scopes)\n * @param subjectTokenType - Optional subject token type (defaults to access token)\n * @returns Resource-scoped token response\n * @throws {OAuthError} If the token exchange fails\n *\n * @example\n * ```typescript\n * const response = await exchangeToken(\n * {\n * tokenUrl: 'https://api.kontext.dev/oauth2/token',\n * clientId: 'my-client-id',\n * },\n * identityToken,\n * 'mcp-gateway'\n * );\n * console.log(response.access_token);\n * ```\n */\nexport async function exchangeToken(\n config: TokenExchangeConfig,\n subjectToken: string,\n resource: string,\n scope?: string,\n subjectTokenType: string = TOKEN_TYPE_ACCESS_TOKEN,\n): Promise<TokenExchangeResponse> {\n // Build the request body as form-urlencoded\n const body = new URLSearchParams();\n body.set(\"grant_type\", TOKEN_EXCHANGE_GRANT_TYPE);\n body.set(\"subject_token\", subjectToken);\n body.set(\"subject_token_type\", subjectTokenType);\n body.set(\"resource\", resource);\n\n if (scope) {\n body.set(\"scope\", scope);\n }\n\n // For public clients, include client_id in the body\n // For confidential clients, use Basic auth\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n\n if (config.clientSecret) {\n // Confidential client: use Basic authentication\n const credentials = Buffer.from(\n `${config.clientId}:${config.clientSecret}`,\n ).toString(\"base64\");\n headers[\"Authorization\"] = `Basic ${credentials}`;\n } else {\n // Public client: include client_id in body\n body.set(\"client_id\", config.clientId);\n }\n\n const response = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: body.toString(),\n });\n\n if (!response.ok) {\n let errorMessage = `Token exchange failed: ${response.status} ${response.statusText}`;\n let errorCode: string | undefined;\n let integrationName: string | undefined;\n let integrationId: string | undefined;\n\n try {\n const errorBody = await response.json();\n errorCode = errorBody.error;\n if (errorBody.error_description) {\n errorMessage = errorBody.error_description;\n } else if (errorBody.error) {\n errorMessage = `Token exchange failed: ${errorBody.error}`;\n }\n // Extract integration-specific fields when present (e.g., integration_required,\n // or any error that includes integration metadata for reconnection flows)\n if (errorBody.integration_name || errorBody.integration_id) {\n integrationName = errorBody.integration_name;\n integrationId = errorBody.integration_id;\n }\n } catch {\n // Ignore JSON parse errors, use default message\n }\n\n throw new OAuthError(errorMessage, \"kontext_oauth_token_exchange_failed\", {\n errorCode,\n meta: {\n integrationName,\n integrationId,\n },\n });\n }\n\n const tokenResponse = (await response.json()) as TokenExchangeResponse;\n\n // Validate required fields\n if (!tokenResponse.access_token) {\n throw new OAuthError(\n \"Token exchange response missing access_token.\",\n \"kontext_oauth_token_exchange_failed\",\n );\n }\n\n if (!tokenResponse.issued_token_type) {\n throw new OAuthError(\n \"Token exchange response missing issued_token_type.\",\n \"kontext_oauth_token_exchange_failed\",\n );\n }\n\n if (!tokenResponse.token_type) {\n throw new OAuthError(\n \"Token exchange response missing token_type.\",\n \"kontext_oauth_token_exchange_failed\",\n );\n }\n\n return tokenResponse;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/storage/types.ts","../../src/errors.ts","../../src/oauth/provider.ts","../../src/management/types.ts","../../src/oauth/token-exchange.ts"],"names":["ErrorCode","randomBytes"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Storage interface for persisting SDK state\n */\n\n/**\n * Generic storage interface for the Kontext SDK\n * Implementations can store data in memory, file system, or external services\n */\nexport interface KontextStorage {\n /**\n * Retrieve a JSON value by key\n * @param key Storage key\n * @returns The stored value or undefined if not found\n */\n getJson<T>(key: string): Promise<T | undefined>;\n\n /**\n * Store a JSON value by key\n * @param key Storage key\n * @param value The value to store, or undefined to delete\n */\n setJson<T>(key: string, value: T | undefined): Promise<void>;\n}\n\n/**\n * Storage key namespacing helper\n * Creates namespaced keys based on application client ID and optional session key\n */\nexport function createStorageKey(\n applicationClientId: string,\n sessionKey: string | undefined,\n ...parts: string[]\n): string {\n const namespace = sessionKey\n ? `kontext:${applicationClientId}:${sessionKey}`\n : `kontext:${applicationClientId}`;\n return [namespace, ...parts].join(\":\");\n}\n\n/**\n * Storage keys used by the SDK\n */\nexport const StorageKeys = {\n // Existing keys\n TOKENS: \"tokens\",\n CODE_VERIFIER: \"code_verifier\",\n STATE: \"state\",\n CLIENT_INFO: \"client_info\",\n\n // Pattern B (RFC 8693 Token Exchange) keys\n /** Identity tokens (no audience) */\n IDENTITY_TOKENS: \"identity_tokens\",\n /** Prefix for resource-scoped tokens */\n RESOURCE_TOKENS: \"resource_tokens\",\n} as const;\n\n/**\n * Create a storage key for a resource-scoped token\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n * @returns Storage key for the resource token\n *\n * @example\n * ```typescript\n * const key = resourceTokenKey('mcp-gateway');\n * // Returns: 'resource_tokens:mcp-gateway'\n * ```\n */\nexport function resourceTokenKey(resource: string): string {\n return `${StorageKeys.RESOURCE_TOKENS}:${resource}`;\n}\n","/**\n * Typed error classes for the Kontext SDK.\n *\n * Every error has a `kontext_` prefixed code, an auto-generated docsUrl,\n * and a `kontextError` brand for type narrowing without instanceof.\n *\n * @packageDocumentation\n */\n\nimport { ErrorCode } from \"@modelcontextprotocol/sdk/types.js\";\n\n// ============================================================================\n// Base\n// ============================================================================\n\n/**\n * Base error class for all Kontext SDK errors.\n *\n * @example\n * ```typescript\n * import { isKontextError } from '@kontext-dev/js-sdk';\n *\n * try {\n * await client.connect();\n * } catch (err) {\n * if (isKontextError(err)) {\n * console.log(err.code); // \"kontext_authorization_required\"\n * console.log(err.docsUrl); // \"https://docs.kontext.dev/errors/kontext_authorization_required\"\n * }\n * }\n * ```\n */\nexport class KontextError extends Error {\n /** Brand field for type narrowing without instanceof */\n readonly kontextError = true as const;\n\n /** Machine-readable error code, always prefixed with `kontext_` */\n readonly code: string;\n\n /** HTTP status code when applicable */\n readonly statusCode?: number;\n\n /** Auto-generated link to error documentation */\n readonly docsUrl: string;\n\n /** Server request ID for debugging / support escalation */\n readonly requestId?: string;\n\n /** Contextual metadata bag (integration IDs, param names, etc.) */\n readonly meta: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n options?: {\n statusCode?: number;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, { cause: options?.cause });\n this.name = \"KontextError\";\n this.code = code;\n this.statusCode = options?.statusCode;\n this.requestId = options?.requestId;\n this.meta = options?.meta ?? {};\n this.docsUrl = `https://docs.kontext.dev/errors/${code}`;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n statusCode: this.statusCode,\n docsUrl: this.docsUrl,\n requestId: this.requestId,\n meta: Object.keys(this.meta).length > 0 ? this.meta : undefined,\n };\n }\n\n override toString(): string {\n const parts = [`[${this.code}] ${this.message}`];\n if (this.docsUrl) parts.push(`Docs: ${this.docsUrl}`);\n if (this.requestId) parts.push(`Request ID: ${this.requestId}`);\n return parts.join(\"\\n\");\n }\n}\n\n// ============================================================================\n// Type guard\n// ============================================================================\n\n/**\n * Check if an error is a KontextError without instanceof.\n * Works across package versions and bundler deduplication.\n */\nexport function isKontextError(err: unknown): err is KontextError {\n return (\n typeof err === \"object\" &&\n err !== null &&\n (err as Record<string, unknown>).kontextError === true\n );\n}\n\n// ============================================================================\n// Auth errors\n// ============================================================================\n\n/**\n * Thrown when authentication is required but no valid credentials are available.\n */\nexport class AuthorizationRequiredError extends KontextError {\n readonly authorizationUrl?: string;\n\n constructor(\n message = \"Authorization required. Complete the OAuth flow to continue.\",\n options?: {\n authorizationUrl?: string;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, \"kontext_authorization_required\", {\n statusCode: 401,\n ...options,\n });\n this.name = \"AuthorizationRequiredError\";\n this.authorizationUrl = options?.authorizationUrl;\n }\n}\n\n// ============================================================================\n// OAuth errors\n// ============================================================================\n\n/**\n * Thrown when an OAuth flow fails — state validation, token exchange,\n * missing code verifier, or provider errors.\n */\nexport class OAuthError extends KontextError {\n readonly errorCode?: string;\n readonly errorDescription?: string;\n\n constructor(\n message: string,\n code: string,\n options?: {\n statusCode?: number;\n errorCode?: string;\n errorDescription?: string;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, code, {\n statusCode: options?.statusCode ?? 400,\n ...options,\n });\n this.name = \"OAuthError\";\n this.errorCode = options?.errorCode;\n this.errorDescription = options?.errorDescription;\n }\n}\n\n// ============================================================================\n// Integration errors\n// ============================================================================\n\n/**\n * Thrown when an integration connection is required before a tool can be used.\n */\nexport class IntegrationConnectionRequiredError extends KontextError {\n readonly integrationId: string;\n readonly integrationName?: string;\n readonly connectUrl?: string;\n\n constructor(\n integrationId: string,\n options?: {\n integrationName?: string;\n connectUrl?: string;\n message?: string;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(\n options?.message ??\n `Connection to integration \"${integrationId}\" is required. Visit the connect URL to authorize.`,\n \"kontext_integration_connection_required\",\n { statusCode: 403, ...options },\n );\n this.name = \"IntegrationConnectionRequiredError\";\n this.integrationId = integrationId;\n this.integrationName = options?.integrationName;\n this.connectUrl = options?.connectUrl;\n }\n}\n\n// ============================================================================\n// Config errors (NEW — replaces all plain Error config throws)\n// ============================================================================\n\n/**\n * Thrown when SDK configuration is invalid or missing.\n * These are deterministic errors caught at initialization time.\n */\nexport class ConfigError extends KontextError {\n constructor(\n message: string,\n code: string,\n options?: {\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, code, options);\n this.name = \"ConfigError\";\n }\n}\n\n// ============================================================================\n// Network errors\n// ============================================================================\n\n/**\n * Thrown when there is a network or connection error.\n */\nexport class NetworkError extends KontextError {\n constructor(\n message = \"Network error. Check your internet connection and that the server is reachable.\",\n options?: {\n cause?: unknown;\n requestId?: string;\n meta?: Record<string, unknown>;\n },\n ) {\n super(message, \"kontext_network_error\", options);\n this.name = \"NetworkError\";\n }\n}\n\n// ============================================================================\n// HTTP response errors (differentiated by code)\n// ============================================================================\n\n/**\n * Thrown when the server returns an HTTP error.\n * Use `error.code` to distinguish between specific error types.\n */\nexport class HttpError extends KontextError {\n readonly retryAfter?: number;\n readonly validationErrors?: Array<{ field: string; message: string }>;\n\n constructor(\n message: string,\n code: string,\n options?: {\n statusCode?: number;\n retryAfter?: number;\n validationErrors?: Array<{ field: string; message: string }>;\n requestId?: string;\n meta?: Record<string, unknown>;\n cause?: unknown;\n },\n ) {\n super(message, code, {\n statusCode: options?.statusCode,\n ...options,\n });\n this.name = \"HttpError\";\n this.retryAfter = options?.retryAfter;\n this.validationErrors = options?.validationErrors;\n }\n}\n\n// ============================================================================\n// Network error detection (used by translateError)\n// ============================================================================\n\n/**\n * Safely access arbitrary properties on an error object.\n * Errors in JS frequently carry extra properties (code, statusCode, etc.)\n * that aren't part of the Error interface. This avoids `as unknown as` casts.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction errorProps(err: Error): Record<string, any> {\n return err;\n}\n\nconst NETWORK_ERROR_CODES = new Set([\n \"ECONNREFUSED\",\n \"ENOTFOUND\",\n \"ETIMEDOUT\",\n \"ECONNRESET\",\n \"ECONNABORTED\",\n \"EPIPE\",\n \"UND_ERR_CONNECT_TIMEOUT\",\n]);\n\n/**\n * Detect network errors structurally rather than by string matching.\n * Checks Node.js system error codes on the error and its cause.\n */\nexport function isNetworkError(err: Error): boolean {\n if (err.name === \"AbortError\") return true;\n\n const props = errorProps(err);\n const sysCode = props.code as string | undefined;\n if (typeof sysCode === \"string\" && NETWORK_ERROR_CODES.has(sysCode))\n return true;\n\n // fetch() throws TypeError — only classify as network error when cause\n // indicates a system-level failure\n if (err.name === \"TypeError\" && err.cause instanceof Error) {\n const causeCode = errorProps(err.cause).code;\n if (typeof causeCode === \"string\" && NETWORK_ERROR_CODES.has(causeCode))\n return true;\n }\n\n // Browser fetch() failures: TypeError with known messages, no system error code\n if (err.name === \"TypeError\") {\n const msg = err.message.toLowerCase();\n if (\n msg === \"failed to fetch\" ||\n msg === \"load failed\" ||\n msg.includes(\"networkerror\")\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Detect unauthorized errors structurally.\n * Checks status code and numeric code rather than string matching on name.\n */\nexport function isUnauthorizedError(err: Error): boolean {\n const props = errorProps(err);\n\n // Check HTTP status code (most reliable)\n if (props.statusCode === 401 || props.status === 401) return true;\n\n // StreamableHTTPError stores status as `.code`\n if (props.code === 401) return true;\n\n // MCP SDK UnauthorizedError extends Error without setting `.name`,\n // so `.name` is \"Error\". Use constructor name as fallback.\n if (err.name === \"UnauthorizedError\") return true;\n if (err.constructor?.name === \"UnauthorizedError\") return true;\n if (err.message === \"Unauthorized\") return true;\n\n return false;\n}\n\n// ============================================================================\n// Elicitation types\n// ============================================================================\n\nexport interface ElicitationEntry {\n readonly url: string;\n readonly message: string;\n readonly elicitationId: string;\n readonly integrationId?: string;\n readonly integrationName?: string;\n}\n\n// ============================================================================\n// HTTP error parsing\n// ============================================================================\n\n/**\n * Parse an HTTP response into an appropriate error.\n */\nexport function parseHttpError(\n statusCode: number,\n body?: unknown,\n): KontextError {\n const message =\n typeof body === \"object\" && body !== null && \"message\" in body\n ? String((body as { message: unknown }).message)\n : `HTTP ${statusCode}`;\n\n const errorCode =\n typeof body === \"object\" && body !== null && \"code\" in body\n ? String((body as { code: unknown }).code)\n : undefined;\n\n switch (statusCode) {\n case 400:\n if (\n typeof body === \"object\" &&\n body !== null &&\n \"errors\" in body &&\n Array.isArray((body as { errors: unknown }).errors)\n ) {\n return new HttpError(message, \"kontext_validation_error\", {\n statusCode: 400,\n validationErrors: (\n body as { errors: Array<{ field: string; message: string }> }\n ).errors,\n });\n }\n return new KontextError(message, errorCode ?? \"kontext_bad_request\", {\n statusCode: 400,\n });\n\n case 401:\n return new AuthorizationRequiredError(message);\n\n case 403:\n if (errorCode === \"INTEGRATION_CONNECTION_REQUIRED\") {\n const details = body as {\n integrationId?: string;\n integrationName?: string;\n connectUrl?: string;\n };\n return new IntegrationConnectionRequiredError(\n details.integrationId ?? \"unknown\",\n {\n integrationName: details.integrationName,\n connectUrl: details.connectUrl,\n message,\n },\n );\n }\n return new HttpError(message, \"kontext_policy_denied\", {\n statusCode: 403,\n meta: { policy: (body as Record<string, unknown>)?.policy },\n });\n\n case 404:\n return new HttpError(message, \"kontext_not_found\", { statusCode: 404 });\n\n case 429: {\n const retryAfter =\n typeof body === \"object\" && body !== null && \"retryAfter\" in body\n ? Number((body as { retryAfter: unknown }).retryAfter)\n : undefined;\n return new HttpError(\n retryAfter\n ? `Rate limit exceeded. Retry after ${retryAfter} seconds.`\n : \"Rate limit exceeded. Wait and retry.\",\n \"kontext_rate_limited\",\n { statusCode: 429, retryAfter },\n );\n }\n\n default:\n if (statusCode >= 500) {\n return new HttpError(\n `Server error (HTTP ${statusCode}): ${message}`,\n \"kontext_server_error\",\n { statusCode },\n );\n }\n return new KontextError(message, errorCode ?? \"kontext_unknown_error\", {\n statusCode,\n });\n }\n}\n\n// ============================================================================\n// MCP error translation\n// ============================================================================\n\nconst MCP_CODE_MAP: Record<number, { code: string; statusCode?: number }> = {\n [ErrorCode.ParseError]: { code: \"kontext_mcp_parse_error\" },\n [ErrorCode.InvalidRequest]: { code: \"kontext_mcp_invalid_request\" },\n [ErrorCode.MethodNotFound]: { code: \"kontext_mcp_method_not_found\" },\n [ErrorCode.InvalidParams]: { code: \"kontext_mcp_invalid_params\" },\n [ErrorCode.InternalError]: {\n code: \"kontext_mcp_internal_error\",\n statusCode: 500,\n },\n [ErrorCode.RequestTimeout]: {\n code: \"kontext_mcp_session_expired\",\n statusCode: 401,\n },\n [ErrorCode.ConnectionClosed]: { code: \"kontext_mcp_session_error\" },\n};\n\n/**\n * Translate external errors into KontextError instances.\n * Uses structural checks (numeric codes, status codes, system error codes)\n * rather than fragile string matching.\n */\nexport function translateError(err: unknown): KontextError {\n if (isKontextError(err)) return err as KontextError;\n\n if (!(err instanceof Error)) {\n return new KontextError(String(err), \"kontext_unknown_error\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const props: Record<string, any> = err;\n\n // 1. MCP protocol -32042 (URL elicitation required) — check numeric code\n if (props.code === ErrorCode.UrlElicitationRequired) {\n const elicitations = (props.elicitations ?? props.data?.elicitations) as\n | ElicitationEntry[]\n | undefined;\n const elicitation = elicitations?.[0];\n return new IntegrationConnectionRequiredError(\n elicitation?.integrationId ?? \"unknown\",\n {\n integrationName: elicitation?.integrationName,\n connectUrl: elicitation?.url,\n message: elicitation?.message,\n cause: err,\n },\n );\n }\n\n // 2. MCP JSON-RPC errors (standard and server-defined ranges)\n if (typeof props.code === \"number\" && props.code < 0) {\n const entry = MCP_CODE_MAP[props.code];\n if (entry) {\n return new KontextError(err.message, entry.code, {\n statusCode: entry.statusCode,\n cause: err,\n });\n }\n return new KontextError(err.message, \"kontext_mcp_error\", {\n cause: err,\n meta: { mcpCode: props.code },\n });\n }\n\n // 3. HTTP status on the error (from MCP SDK or fetch wrappers)\n // StreamableHTTPError stores HTTP status as `.code` (not `.statusCode`/`.status`),\n // so check `.code` as well when it's in the HTTP error range (400–599).\n const statusCode = (props.statusCode ??\n props.status ??\n (typeof props.code === \"number\" && props.code >= 400 && props.code < 600\n ? props.code\n : undefined)) as number | undefined;\n if (typeof statusCode === \"number\" && statusCode >= 400) {\n if (statusCode === 401) {\n return new AuthorizationRequiredError(err.message, { cause: err });\n }\n return new KontextError(err.message, \"kontext_server_error\", {\n statusCode,\n cause: err,\n });\n }\n\n // 4. Auth errors — structural check\n if (isUnauthorizedError(err)) {\n return new AuthorizationRequiredError(err.message, { cause: err });\n }\n\n // 5. Network errors — structural check (system error codes, not string matching)\n if (isNetworkError(err)) {\n return new NetworkError(err.message, { cause: err });\n }\n\n // 6. Fallback\n return new KontextError(err.message, \"kontext_unknown_error\", {\n cause: err,\n });\n}\n","/**\n * KontextOAuthProvider - Implements OAuthClientProvider from @modelcontextprotocol/sdk\n *\n * This provider handles the OAuth 2.0 Authorization Code + PKCE flow\n * for authenticating MCP clients with the Kontext Gateway.\n */\n\nimport type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type {\n OAuthClientMetadata,\n OAuthClientInformationMixed,\n OAuthTokens,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { randomBytes } from \"node:crypto\";\nimport type { KontextStorage } from \"../storage/types.js\";\nimport {\n createStorageKey,\n StorageKeys,\n resourceTokenKey,\n} from \"../storage/types.js\";\nimport { OAuthError } from \"../errors.js\";\n\nexport interface KontextOAuthProviderConfig {\n /**\n * Application OAuth client ID from Kontext\n */\n clientId: string;\n\n /**\n * Redirect URI for OAuth callback\n * Must match one of the registered redirect URIs for the application\n */\n redirectUri: string;\n\n /**\n * Storage implementation for persisting tokens and PKCE state\n */\n storage: KontextStorage;\n\n /**\n * Optional session key for namespacing storage\n * Useful when multiple users/sessions share the same storage\n */\n sessionKey?: string;\n\n /**\n * Optional client name for OAuth metadata\n */\n clientName?: string;\n\n /**\n * Callback to redirect the user agent to the authorization URL\n * This is called when authorization is required\n *\n * @param url The authorization URL to redirect to\n */\n onRedirectToAuthorization: (url: URL) => void | Promise<void>;\n}\n\n/**\n * OAuth provider implementation for Kontext MCP clients\n *\n * Implements the OAuthClientProvider interface from @modelcontextprotocol/sdk\n * to handle Authorization Code + PKCE authentication flow.\n *\n * @example\n * ```typescript\n * const storage = new MemoryStorage();\n * const provider = new KontextOAuthProvider({\n * clientId: 'your-client-id',\n * redirectUri: 'http://localhost:3000/callback',\n * storage,\n * onRedirectToAuthorization: (url) => {\n * // Open browser or redirect\n * window.location.href = url.toString();\n * },\n * });\n * ```\n */\nexport class KontextOAuthProvider implements OAuthClientProvider {\n private readonly config: KontextOAuthProviderConfig;\n private readonly storagePrefix: string;\n private pendingState: string | null = null;\n private readonly expiryBufferMs = 60 * 1000;\n\n constructor(config: KontextOAuthProviderConfig) {\n this.config = config;\n this.storagePrefix = createStorageKey(config.clientId, config.sessionKey);\n }\n\n /**\n * The redirect URL for OAuth callbacks\n */\n get redirectUrl(): string | URL {\n return this.config.redirectUri;\n }\n\n /**\n * OAuth client metadata\n */\n get clientMetadata(): OAuthClientMetadata {\n return {\n redirect_uris: [this.config.redirectUri],\n client_name: this.config.clientName,\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\", // Public client\n };\n }\n\n /**\n * Generate a random state parameter for OAuth CSRF protection\n */\n state(): string {\n // Generate a cryptographically secure random string\n const array = new Uint8Array(32);\n if (globalThis.crypto?.getRandomValues) {\n globalThis.crypto.getRandomValues(array);\n } else {\n array.set(randomBytes(32));\n }\n const state = Array.from(array, (byte) =>\n byte.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n this.pendingState = state;\n void this.config.storage.setJson(\n this.getStorageKey(StorageKeys.STATE),\n state,\n );\n return state;\n }\n\n /**\n * Returns the client information (client_id)\n * Since we're a public client with pre-registered credentials,\n * we don't use dynamic client registration.\n */\n async clientInformation(): Promise<OAuthClientInformationMixed | undefined> {\n return {\n client_id: this.config.clientId,\n };\n }\n\n /**\n * Load stored OAuth tokens\n */\n async tokens(): Promise<OAuthTokens | undefined> {\n const key = this.getStorageKey(StorageKeys.TOKENS);\n return this.config.storage.getJson<OAuthTokens>(key);\n }\n\n /**\n * Save OAuth tokens after successful authorization\n */\n async saveTokens(tokens: OAuthTokens): Promise<void> {\n const key = this.getStorageKey(StorageKeys.TOKENS);\n await this.config.storage.setJson(key, this.withIssuedAt(tokens));\n }\n\n /**\n * Redirect the user agent to the authorization URL\n */\n async redirectToAuthorization(authorizationUrl: URL): Promise<void> {\n await this.config.onRedirectToAuthorization(authorizationUrl);\n }\n\n /**\n * Save the PKCE code verifier before redirecting to authorization\n */\n async saveCodeVerifier(codeVerifier: string): Promise<void> {\n const key = this.getStorageKey(StorageKeys.CODE_VERIFIER);\n await this.config.storage.setJson(key, codeVerifier);\n }\n\n /**\n * Load the PKCE code verifier for token exchange\n */\n async codeVerifier(): Promise<string> {\n const key = this.getStorageKey(StorageKeys.CODE_VERIFIER);\n const verifier = await this.config.storage.getJson<string>(key);\n if (!verifier) {\n throw new OAuthError(\n \"No PKCE code verifier found in storage. The OAuth flow may have expired or storage was cleared. Restart the auth flow.\",\n \"kontext_oauth_code_verifier_missing\",\n );\n }\n return verifier;\n }\n\n /**\n * Invalidate stored credentials\n */\n async invalidateCredentials(\n scope: \"all\" | \"client\" | \"tokens\" | \"verifier\",\n ): Promise<void> {\n if (scope === \"all\" || scope === \"tokens\") {\n const tokensKey = this.getStorageKey(StorageKeys.TOKENS);\n await this.config.storage.setJson(tokensKey, undefined);\n const identityKey = this.getStorageKey(StorageKeys.IDENTITY_TOKENS);\n await this.config.storage.setJson(identityKey, undefined);\n }\n if (scope === \"all\" || scope === \"verifier\") {\n const verifierKey = this.getStorageKey(StorageKeys.CODE_VERIFIER);\n await this.config.storage.setJson(verifierKey, undefined);\n }\n if (scope === \"all\") {\n this.pendingState = null;\n const stateKey = this.getStorageKey(StorageKeys.STATE);\n await this.config.storage.setJson(stateKey, undefined);\n }\n // 'client' scope is a no-op since we use pre-registered client info\n }\n\n /**\n * Clear all stored state (tokens, verifier, etc.)\n * Call this to force re-authentication\n */\n async clearAll(): Promise<void> {\n await this.invalidateCredentials(\"all\");\n }\n\n /**\n * Check if we have valid (non-expired) tokens\n */\n async hasValidTokens(): Promise<boolean> {\n const storedTokens = await this.tokens();\n return this.isTokenValid(storedTokens);\n }\n\n // ==========================================================================\n // Pattern B: Identity and Resource Token Management (RFC 8693)\n // ==========================================================================\n\n /**\n * Save identity tokens (no audience)\n * These are the tokens obtained from the initial OAuth flow before token exchange.\n */\n async saveIdentityTokens(tokens: OAuthTokens): Promise<void> {\n const key = this.getStorageKey(StorageKeys.IDENTITY_TOKENS);\n await this.config.storage.setJson(key, this.withIssuedAt(tokens));\n }\n\n /**\n * Load identity tokens\n * Returns the identity tokens obtained from the initial OAuth flow.\n */\n async identityTokens(): Promise<OAuthTokens | undefined> {\n const key = this.getStorageKey(StorageKeys.IDENTITY_TOKENS);\n return this.config.storage.getJson<OAuthTokens>(key);\n }\n\n /**\n * Save resource-scoped tokens for a specific resource\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n * @param tokens The resource-scoped tokens\n */\n async saveResourceTokens(\n resource: string,\n tokens: OAuthTokens,\n ): Promise<void> {\n const key = this.getStorageKey(resourceTokenKey(resource));\n await this.config.storage.setJson(key, this.withIssuedAt(tokens));\n }\n\n /**\n * Load resource-scoped tokens for a specific resource\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n * @returns The resource-scoped tokens, or undefined if not found\n */\n async resourceTokens(resource: string): Promise<OAuthTokens | undefined> {\n const key = this.getStorageKey(resourceTokenKey(resource));\n return this.config.storage.getJson<OAuthTokens>(key);\n }\n\n /**\n * Clear resource tokens for a specific resource\n *\n * @param resource The resource identifier (e.g., \"mcp-gateway\")\n */\n async clearResourceTokens(resource: string): Promise<void> {\n const key = this.getStorageKey(resourceTokenKey(resource));\n await this.config.storage.setJson(key, undefined);\n }\n\n /**\n * Check if we have valid identity tokens\n */\n async hasValidIdentityTokens(): Promise<boolean> {\n const tokens = await this.identityTokens();\n return this.isTokenValid(tokens);\n }\n\n /**\n * Check if we have valid resource tokens for a specific resource\n *\n * @param resource The resource identifier\n */\n async hasValidResourceTokens(resource: string): Promise<boolean> {\n const tokens = await this.resourceTokens(resource);\n return this.isTokenValid(tokens);\n }\n\n async validateState(state?: string): Promise<boolean> {\n if (!state) {\n return false;\n }\n\n const key = this.getStorageKey(StorageKeys.STATE);\n const storedState =\n this.pendingState ?? (await this.config.storage.getJson<string>(key));\n const isValid = storedState === state;\n\n if (isValid) {\n this.pendingState = null;\n await this.config.storage.setJson(key, undefined);\n }\n\n return isValid;\n }\n\n private withIssuedAt(\n tokens: OAuthTokens,\n ): OAuthTokens & { issued_at?: number } {\n if (!tokens.expires_in) {\n return tokens;\n }\n return { ...tokens, issued_at: Date.now() };\n }\n\n private isTokenValid(tokens?: OAuthTokens): boolean {\n if (!tokens?.access_token) {\n return false;\n }\n\n if (!tokens.expires_in) {\n return true;\n }\n\n const issuedAt = (tokens as OAuthTokens & { issued_at?: number }).issued_at;\n if (!issuedAt) {\n return true;\n }\n\n const expiresAt = issuedAt + tokens.expires_in * 1000;\n return Date.now() < expiresAt - this.expiryBufferMs;\n }\n\n private getStorageKey(key: string): string {\n return `${this.storagePrefix}:${key}`;\n }\n}\n\n/**\n * Parse an OAuth callback URL and extract the authorization code and state\n *\n * @param callbackUrl The full callback URL with query parameters\n * @returns The authorization code and state, or error details\n */\nexport function parseOAuthCallback(callbackUrl: string | URL): {\n code?: string;\n state?: string;\n error?: string;\n errorDescription?: string;\n} {\n const url =\n typeof callbackUrl === \"string\" ? new URL(callbackUrl) : callbackUrl;\n const params = url.searchParams;\n\n const error = params.get(\"error\");\n if (error) {\n return {\n error,\n errorDescription: params.get(\"error_description\") ?? undefined,\n };\n }\n\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n}\n","/**\n * Core types for the Kontext SDK\n * These mirror the API DTOs for type-safe interactions\n */\n\n// ============================================================================\n// Applications\n// ============================================================================\n\nexport interface Application {\n id: string;\n name: string;\n canModify?: boolean;\n activeSessionCount?: number;\n idleSessionCount?: number;\n liveSessionCount?: number;\n totalSessionCount?: number;\n oauth?: ApplicationOAuth;\n archivedAt?: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ApplicationOAuth {\n type: \"public\" | \"confidential\";\n clientId: string;\n clientSecret?: string;\n pkceRequired: boolean;\n scopes: string[];\n authorizationUrl: string;\n tokenUrl: string;\n gatewayUrl: string;\n redirectUris: string[];\n}\n\nexport interface CreateApplicationOAuthInput {\n type?: \"public\" | \"confidential\";\n redirectUris: string[];\n pkceRequired?: boolean;\n scopes?: string[];\n}\n\nexport interface CreateApplicationInput {\n name: string;\n oauth: CreateApplicationOAuthInput;\n}\n\nexport interface UpdateApplicationInput {\n name?: string;\n}\n\nexport interface UpdateApplicationOAuthInput {\n pkceRequired?: boolean;\n scopes?: string[];\n redirectUris?: string[];\n}\n\nexport interface CreateApplicationResponse {\n application: Application;\n oauth: ApplicationOAuth;\n}\n\nexport interface ApplicationResponse {\n application: Application;\n}\n\nexport interface ApplicationOAuthResponse {\n oauth: ApplicationOAuth;\n}\n\nexport interface ListApplicationsResponse {\n items: Application[];\n nextCursor?: string;\n}\n\nexport interface RotateApplicationSecretResponse {\n oauth: ApplicationOAuth;\n}\n\nexport interface UpdateApplicationIntegrationsInput {\n integrationIds: string[];\n}\n\nexport interface ApplicationIntegrationsResponse {\n integrationIds: string[];\n}\n\n// ============================================================================\n// Integrations\n// ============================================================================\n\nexport type IntegrationAuthMode =\n | \"oauth\"\n | \"user_token\"\n | \"server_token\"\n | \"none\";\n\nexport type IntegrationValidationStatus = \"pending\" | \"valid\" | \"invalid\";\n\nexport interface IntegrationOAuthSummary {\n provider?: string;\n issuer?: string;\n scopes?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface IntegrationCapabilities {\n tools?: boolean;\n resources?: boolean;\n prompts?: boolean;\n}\n\nexport interface Integration {\n id: string;\n name: string;\n url: string;\n authMode: IntegrationAuthMode;\n oauth?: IntegrationOAuthSummary;\n capabilities?: IntegrationCapabilities;\n serverTokenConfigured: boolean;\n validationStatus: IntegrationValidationStatus;\n validationMessage?: string;\n lastValidatedAt?: string;\n userConnection?: ConnectionStatusResponse;\n sharedConnection?: ConnectionStatusResponse;\n createdAt: string;\n updatedAt: string;\n archivedAt?: string;\n}\n\nexport interface IntegrationOAuthConfigInput {\n provider?: string;\n issuer?: string;\n scopes?: string[];\n}\n\nexport interface CreateIntegrationInput {\n name: string;\n url: string;\n authMode?: IntegrationAuthMode;\n oauth?: IntegrationOAuthConfigInput;\n capabilities?: IntegrationCapabilities;\n serverToken?: string;\n}\n\nexport interface UpdateIntegrationInput {\n name?: string;\n url?: string;\n authMode?: IntegrationAuthMode;\n oauth?: IntegrationOAuthConfigInput;\n capabilities?: IntegrationCapabilities;\n serverToken?: string;\n}\n\nexport interface CreateIntegrationResponse {\n integration: Integration;\n}\n\nexport interface IntegrationResponse {\n integration: Integration;\n}\n\nexport interface ListIntegrationsResponse {\n items: Integration[];\n nextCursor?: string;\n}\n\nexport interface ValidateIntegrationResponse {\n status: IntegrationValidationStatus;\n message?: string;\n}\n\n// ============================================================================\n// Integration Connections\n// ============================================================================\n\nexport type ConnectionStatus = \"connected\" | \"disconnected\";\n\nexport interface ConnectionStatusResponse {\n connected: boolean;\n status?: ConnectionStatus;\n expiresAt?: string;\n displayName?: string;\n lastVerifiedAt?: string;\n lastVerifiedStatus?: string;\n verificationMessage?: string;\n}\n\nexport type TestConnectionStatus =\n | \"verified\"\n | \"auth_failed\"\n | \"unreachable\"\n | \"mcp_failed\"\n | \"no_credential\";\n\nexport interface TestConnectionResponse {\n status: TestConnectionStatus;\n message?: string;\n toolCount?: number;\n testedAt: string;\n connection: {\n connected: boolean;\n expiresAt?: string;\n };\n}\n\nexport interface ConnectionResponse {\n connection: ConnectionStatusResponse;\n}\n\nexport interface AddUserTokenInput {\n token: string;\n}\n\n// ============================================================================\n// Service Accounts\n// ============================================================================\n\nexport interface ServiceAccount {\n id: string;\n name: string;\n description: string | null;\n createdAt: string;\n}\n\nexport interface ServiceAccountCredentials {\n clientId: string;\n clientSecret: string;\n}\n\nexport interface CreateServiceAccountInput {\n name: string;\n description?: string;\n}\n\nexport interface CreateServiceAccountResponse {\n serviceAccount: ServiceAccount;\n credentials: ServiceAccountCredentials;\n}\n\nexport interface RotateSecretResponse {\n credentials: ServiceAccountCredentials;\n}\n\nexport interface ListServiceAccountsResponse {\n items: ServiceAccount[];\n nextCursor: string | null;\n}\n\nexport interface ServiceAccountResponse {\n serviceAccount: ServiceAccount;\n}\n\n// ============================================================================\n// Agent Sessions\n// ============================================================================\n\nexport type AgentSessionStatus = \"active\" | \"disconnected\";\nexport type AgentSessionDerivedStatus =\n | \"active\"\n | \"idle\"\n | \"expired\"\n | \"disconnected\";\n\nexport interface AgentSession {\n id: string;\n agentId: string;\n organizationId: string;\n authenticatedUserId: string;\n authenticatedUserEmail?: string | null;\n name: string;\n hostname?: string | null;\n userAgent?: string | null;\n clientInfo?: Record<string, unknown> | null;\n status: AgentSessionStatus;\n derivedStatus: AgentSessionDerivedStatus;\n connectedAt?: string;\n lastActiveAt?: string;\n disconnectedAt?: string;\n tokenExpiresAt?: string;\n createdAt: string;\n}\n\nexport interface AgentSessionResponse {\n session: AgentSession;\n}\n\nexport interface ListAgentSessionsResponse {\n items: AgentSession[];\n}\n\nexport interface RevokeAllSessionsResponse {\n success: boolean;\n disconnectedCount: number;\n}\n\n// ============================================================================\n// Traces & Events\n// ============================================================================\n\nexport interface Trace {\n traceId: string | null;\n sessionId: string;\n startedAt: string | null;\n endedAt: string | null;\n eventCount: number;\n okCount?: number;\n warnCount?: number;\n errorCount?: number;\n agentId?: string;\n ownerUserId?: string;\n ownerEmail?: string;\n agentName?: string;\n agentSessionId?: string;\n agentSessionName?: string;\n}\n\nexport interface TraceEvent {\n id: string;\n createdAt: string;\n sessionId: string;\n agentId: string;\n traceId?: string | null;\n apiKeyId?: string | null;\n eventType: string;\n status: string;\n durationMs?: number | null;\n integrationId?: string | null;\n toolName?: string | null;\n errorMessage?: string | null;\n bytesIn?: number | null;\n bytesOut?: number | null;\n requestJson?: unknown;\n responseJson?: unknown;\n parentEventId?: string | null;\n agentSessionId?: string | null;\n /** @deprecated Use createdAt */\n timestamp?: string;\n /** @deprecated Use status */\n level?: \"ok\" | \"warn\" | \"error\";\n /** @deprecated Use eventType */\n type?: string;\n /** @deprecated May be encoded in requestJson/responseJson */\n method?: string;\n /** @deprecated Use toolName */\n tool?: string;\n /** @deprecated Use durationMs */\n duration?: number;\n /** @deprecated Use status/errorMessage fields */\n errorType?: string;\n /** @deprecated May be encoded in requestJson/responseJson */\n metadata?: Record<string, unknown>;\n}\n\nexport interface ListTracesResponse {\n items: Trace[];\n nextCursor?: string;\n}\n\nexport interface TraceResponse {\n trace: Trace;\n events: TraceEvent[];\n}\n\nexport interface McpEvent {\n id: string;\n createdAt: string;\n agentId: string;\n integrationId: string | null;\n toolName: string | null;\n eventType: string;\n status: string;\n}\n\nexport interface McpEventListResponse {\n items: McpEvent[];\n}\n\n/**\n * @deprecated Use McpEventListResponse instead.\n */\nexport type ListEventsResponse = McpEventListResponse;\n\nexport interface TraceStats {\n totalTraces: number;\n totalEvents: number;\n eventCounts: { ok: number; warn: number; error: number };\n errorRate: number;\n latency: { avg: number; p50: number; p95: number; p99: number };\n bytesTransferred: { in: number; out: number };\n errorsByType: Array<{ type: string; count: number; percentage: number }>;\n topTools: Array<{ name: string; count: number; avgDuration: number }>;\n timeline: Array<{\n date: string;\n traceCount: number;\n eventCount: number;\n warnCount: number;\n errorCount: number;\n bytesIn: number;\n bytesOut: number;\n }>;\n}\n\nexport interface TraceStatsResponse {\n stats: TraceStats;\n}\n\n// ============================================================================\n// Pagination\n// ============================================================================\n\nexport interface PaginationParams {\n cursor?: string;\n limit?: number;\n}\n\n// ============================================================================\n// OAuth Tokens (for storage)\n// ============================================================================\n\nexport interface OAuthTokens {\n accessToken: string;\n refreshToken?: string;\n tokenType: string;\n scope?: string;\n expiresAt?: string;\n}\n\n// ============================================================================\n// Token Exchange (RFC 8693)\n// ============================================================================\n\n/**\n * RFC 8693 Token Exchange grant type\n */\nexport const TOKEN_EXCHANGE_GRANT_TYPE =\n \"urn:ietf:params:oauth:grant-type:token-exchange\";\n\n/**\n * RFC 8693 token type identifier for access tokens\n */\nexport const TOKEN_TYPE_ACCESS_TOKEN =\n \"urn:ietf:params:oauth:token-type:access_token\";\n\n/**\n * Kontext custom token type: the subject_token is an end-user external ID.\n * Used by confidential clients for the credential vault flow.\n */\nexport const TOKEN_TYPE_USER_ID = \"urn:kontext:user-id\";\n\n/**\n * Request body for RFC 8693 token exchange\n */\nexport interface TokenExchangeRequest {\n grant_type: typeof TOKEN_EXCHANGE_GRANT_TYPE;\n subject_token: string;\n subject_token_type?: string;\n resource: string;\n scope?: string;\n audience?: string;\n}\n\n/**\n * Response from RFC 8693 token exchange\n */\nexport interface TokenExchangeResponse {\n access_token: string;\n issued_token_type: string;\n token_type: string;\n expires_in?: number;\n scope?: string;\n refresh_token?: string;\n}\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\nexport interface KontextManagementClientConfig {\n /**\n * Base URL for the Kontext API (e.g., \"https://api.kontext.dev\")\n */\n baseUrl: string;\n\n /**\n * API version to use (default: \"v1\")\n */\n apiVersion?: string;\n\n /**\n * OAuth token endpoint URL (optional)\n * If not specified, defaults to `${baseUrl}/oauth2/token`\n * Useful for local development where Hydra runs on a different port\n */\n tokenUrl?: string;\n\n /**\n * OAuth scopes to request (optional)\n * Defaults to [\"management:all\"]\n */\n scopes?: string[];\n\n /**\n * OAuth audience for token requests (optional)\n * If not specified, defaults to `${baseUrl}/api/${apiVersion}`\n * Required for Hydra token introspection\n */\n audience?: string;\n\n /**\n * Service account credentials for authentication\n */\n credentials: {\n clientId: string;\n clientSecret: string;\n };\n}\n","/**\n * RFC 8693 Token Exchange\n *\n * Generic token exchange function for exchanging identity tokens\n * for resource-scoped tokens.\n *\n * @see https://datatracker.ietf.org/doc/html/rfc8693\n */\n\nimport {\n TOKEN_EXCHANGE_GRANT_TYPE,\n TOKEN_TYPE_ACCESS_TOKEN,\n type TokenExchangeResponse,\n} from \"../management/types.js\";\nimport { OAuthError } from \"../errors.js\";\n\n/**\n * Configuration for token exchange\n */\nexport interface TokenExchangeConfig {\n /**\n * Token endpoint URL (e.g., https://api.kontext.dev/oauth2/token)\n */\n tokenUrl: string;\n\n /**\n * OAuth client ID\n */\n clientId: string;\n\n /**\n * OAuth client secret (for confidential clients)\n */\n clientSecret?: string;\n}\n\n/**\n * Exchange a subject token for a resource-scoped token (RFC 8693).\n *\n * This function implements the OAuth 2.0 Token Exchange grant type,\n * allowing an identity token to be exchanged for an access token\n * scoped to a specific resource.\n *\n * @param config - Token exchange configuration\n * @param subjectToken - The subject token to exchange (typically an access token)\n * @param resource - The target resource identifier (e.g., \"mcp-gateway\", \"my-mcp-server\")\n * @param scope - Optional scope restriction (must be subset of subject token scopes)\n * @param subjectTokenType - Optional subject token type (defaults to access token)\n * @returns Resource-scoped token response\n * @throws {OAuthError} If the token exchange fails\n *\n * @example\n * ```typescript\n * const response = await exchangeToken(\n * {\n * tokenUrl: 'https://api.kontext.dev/oauth2/token',\n * clientId: 'my-client-id',\n * },\n * identityToken,\n * 'mcp-gateway'\n * );\n * console.log(response.access_token);\n * ```\n */\nexport async function exchangeToken(\n config: TokenExchangeConfig,\n subjectToken: string,\n resource: string,\n scope?: string,\n subjectTokenType: string = TOKEN_TYPE_ACCESS_TOKEN,\n): Promise<TokenExchangeResponse> {\n // Build the request body as form-urlencoded\n const body = new URLSearchParams();\n body.set(\"grant_type\", TOKEN_EXCHANGE_GRANT_TYPE);\n body.set(\"subject_token\", subjectToken);\n body.set(\"subject_token_type\", subjectTokenType);\n body.set(\"resource\", resource);\n\n if (scope) {\n body.set(\"scope\", scope);\n }\n\n // For public clients, include client_id in the body\n // For confidential clients, use Basic auth\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n\n if (config.clientSecret) {\n // Confidential client: use Basic authentication\n const credentials = Buffer.from(\n `${config.clientId}:${config.clientSecret}`,\n ).toString(\"base64\");\n headers[\"Authorization\"] = `Basic ${credentials}`;\n } else {\n // Public client: include client_id in body\n body.set(\"client_id\", config.clientId);\n }\n\n const response = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: body.toString(),\n });\n\n if (!response.ok) {\n let errorMessage = `Token exchange failed: ${response.status} ${response.statusText}`;\n let errorCode: string | undefined;\n let integrationName: string | undefined;\n let integrationId: string | undefined;\n\n try {\n const errorBody = await response.json();\n errorCode = errorBody.error;\n if (errorBody.error_description) {\n errorMessage = errorBody.error_description;\n } else if (errorBody.error) {\n errorMessage = `Token exchange failed: ${errorBody.error}`;\n }\n // Extract integration-specific fields when present (e.g., integration_required,\n // or any error that includes integration metadata for reconnection flows)\n if (errorBody.integration_name || errorBody.integration_id) {\n integrationName = errorBody.integration_name;\n integrationId = errorBody.integration_id;\n }\n } catch {\n // Ignore JSON parse errors, use default message\n }\n\n throw new OAuthError(errorMessage, \"kontext_oauth_token_exchange_failed\", {\n errorCode,\n meta: {\n integrationName,\n integrationId,\n },\n });\n }\n\n const tokenResponse = (await response.json()) as TokenExchangeResponse;\n\n // Validate required fields\n if (!tokenResponse.access_token) {\n throw new OAuthError(\n \"Token exchange response missing access_token.\",\n \"kontext_oauth_token_exchange_failed\",\n );\n }\n\n if (!tokenResponse.issued_token_type) {\n throw new OAuthError(\n \"Token exchange response missing issued_token_type.\",\n \"kontext_oauth_token_exchange_failed\",\n );\n }\n\n if (!tokenResponse.token_type) {\n throw new OAuthError(\n \"Token exchange response missing token_type.\",\n \"kontext_oauth_token_exchange_failed\",\n );\n }\n\n return tokenResponse;\n}\n"]}
|
package/dist/oauth/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
2
2
|
import { OAuthClientMetadata, OAuthClientInformationMixed, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
3
3
|
import { K as KontextStorage } from '../types-RIzHnRpk.cjs';
|
|
4
|
-
import { a as TokenExchangeResponse } from '../types-
|
|
4
|
+
import { a as TokenExchangeResponse } from '../types-DicGI7ix.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* KontextOAuthProvider - Implements OAuthClientProvider from @modelcontextprotocol/sdk
|
package/dist/oauth/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
2
2
|
import { OAuthClientMetadata, OAuthClientInformationMixed, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
3
3
|
import { K as KontextStorage } from '../types-RIzHnRpk.js';
|
|
4
|
-
import { a as TokenExchangeResponse } from '../types-
|
|
4
|
+
import { a as TokenExchangeResponse } from '../types-DicGI7ix.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* KontextOAuthProvider - Implements OAuthClientProvider from @modelcontextprotocol/sdk
|
package/dist/oauth/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from 'crypto';
|
|
2
|
+
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
|
2
3
|
|
|
3
4
|
// src/oauth/provider.ts
|
|
4
5
|
|
|
@@ -21,8 +22,6 @@ var StorageKeys = {
|
|
|
21
22
|
function resourceTokenKey(resource) {
|
|
22
23
|
return `${StorageKeys.RESOURCE_TOKENS}:${resource}`;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
// src/errors.ts
|
|
26
25
|
var KontextError = class extends Error {
|
|
27
26
|
/** Brand field for type narrowing without instanceof */
|
|
28
27
|
kontextError = true;
|
|
@@ -77,6 +76,17 @@ var OAuthError = class extends KontextError {
|
|
|
77
76
|
this.errorDescription = options?.errorDescription;
|
|
78
77
|
}
|
|
79
78
|
};
|
|
79
|
+
({
|
|
80
|
+
[ErrorCode.ParseError]: { },
|
|
81
|
+
[ErrorCode.InvalidRequest]: { },
|
|
82
|
+
[ErrorCode.MethodNotFound]: { },
|
|
83
|
+
[ErrorCode.InvalidParams]: { },
|
|
84
|
+
[ErrorCode.InternalError]: {
|
|
85
|
+
},
|
|
86
|
+
[ErrorCode.RequestTimeout]: {
|
|
87
|
+
},
|
|
88
|
+
[ErrorCode.ConnectionClosed]: { }
|
|
89
|
+
});
|
|
80
90
|
|
|
81
91
|
// src/oauth/provider.ts
|
|
82
92
|
var KontextOAuthProvider = class {
|