UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

84 lines (83 loc) • 7.01 kB
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { a as getNodeSqliteKysely, i as executeSqliteQueryTakeFirstSync, r as executeSqliteQuerySync } from "./kysely-sync-K7ftY-g4.mjs"; import "./openclaw-state-db-schema-helpers-BlZefrPy.mjs"; import { d as McpOAuthStoreCorruptionError } from "./openclaw-state-worker-error-Cmtk9G4_.mjs"; import "node:util"; import { OAuthClientInformationSchema, OAuthMetadataSchema, OAuthProtectedResourceMetadataSchema, OAuthTokensSchema, OpenIdProviderDiscoveryMetadataSchema } from "@modelcontextprotocol/sdk/shared/auth.js"; //#region src/agents/mcp-oauth-store.kernel.ts const MCP_OAUTH_STORE_FORMAT_VERSION = 1; const UNINITIALIZED_STORE_FIELDS = /* @__PURE__ */ new Set(["credentialState", "pendingAuthorizationChallenge"]); function assertOptionalString(storeKey, store, field) { const value = store[field]; if (value !== void 0 && (typeof value !== "string" || value.length === 0)) throw new McpOAuthStoreCorruptionError(storeKey, `${field} must be a non-empty string`); } function assertDiscoveryState(storeKey, value) { if (value === void 0) return; if (!isRecord(value) || typeof value.authorizationServerUrl !== "string") throw new McpOAuthStoreCorruptionError(storeKey, "discoveryState is invalid"); if (!URL.canParse(value.authorizationServerUrl)) throw new McpOAuthStoreCorruptionError(storeKey, "discoveryState URLs are invalid"); if (value.resourceMetadataUrl !== void 0 && (typeof value.resourceMetadataUrl !== "string" || !URL.canParse(value.resourceMetadataUrl))) throw new McpOAuthStoreCorruptionError(storeKey, "discoveryState URLs are invalid"); if (value.resourceMetadata !== void 0 && !OAuthProtectedResourceMetadataSchema.safeParse(value.resourceMetadata).success) throw new McpOAuthStoreCorruptionError(storeKey, "discoveryState resource metadata is invalid"); if (value.authorizationServerMetadata !== void 0 && !OAuthMetadataSchema.safeParse(value.authorizationServerMetadata).success && !OpenIdProviderDiscoveryMetadataSchema.safeParse(value.authorizationServerMetadata).success) throw new McpOAuthStoreCorruptionError(storeKey, "discoveryState authorization server metadata is invalid"); } function assertAuthorizationChallenge(storeKey, value) { if (value === void 0) return; if (!isRecord(value)) throw new McpOAuthStoreCorruptionError(storeKey, "pendingAuthorizationChallenge is invalid"); const resourceMetadataUrl = value.resourceMetadataUrl; if (resourceMetadataUrl !== void 0 && (typeof resourceMetadataUrl !== "string" || !URL.canParse(resourceMetadataUrl))) throw new McpOAuthStoreCorruptionError(storeKey, "pendingAuthorizationChallenge URL is invalid"); const scope = value.scope; if (scope !== void 0 && (typeof scope !== "string" || scope.length === 0)) throw new McpOAuthStoreCorruptionError(storeKey, "pendingAuthorizationChallenge scope is invalid"); if (value.requiresAuthorization !== void 0 && value.requiresAuthorization !== true) throw new McpOAuthStoreCorruptionError(storeKey, "pendingAuthorizationChallenge requiresAuthorization must be true"); } /** Parse a canonical row without discarding SDK extension fields. */ function parseMcpOAuthStoreJson(storeKey, raw) { let value; try { value = JSON.parse(raw); } catch (error) { throw new McpOAuthStoreCorruptionError(storeKey, "store_json is not valid JSON", { cause: error }); } if (!isRecord(value)) throw new McpOAuthStoreCorruptionError(storeKey, "store_json must contain an object"); if (value.clientInformation !== void 0 && !OAuthClientInformationSchema.safeParse(value.clientInformation).success) throw new McpOAuthStoreCorruptionError(storeKey, "clientInformation is invalid"); if (value.tokens !== void 0 && !OAuthTokensSchema.safeParse(value.tokens).success) throw new McpOAuthStoreCorruptionError(storeKey, "tokens are invalid"); if (value.credentialState !== void 0 && value.credentialState !== "uninitialized" && value.credentialState !== "cleared") throw new McpOAuthStoreCorruptionError(storeKey, "credentialState is invalid"); if (value.credentialState !== void 0 && value.tokens !== void 0) throw new McpOAuthStoreCorruptionError(storeKey, "credentialState cannot coexist with tokens"); if (value.credentialState === "uninitialized" && Object.keys(value).some((field) => !UNINITIALIZED_STORE_FIELDS.has(field))) throw new McpOAuthStoreCorruptionError(storeKey, "uninitialized credential state contains authoritative OAuth fields"); if (value.tokenExpiresAt !== void 0 && (typeof value.tokenExpiresAt !== "number" || !Number.isFinite(value.tokenExpiresAt) || value.tokenExpiresAt < 0)) throw new McpOAuthStoreCorruptionError(storeKey, "tokenExpiresAt is invalid"); if (value.tokenExpiresAt !== void 0 && value.tokens === void 0) throw new McpOAuthStoreCorruptionError(storeKey, "tokenExpiresAt requires tokens"); if (value.tokensAuthorizationServerUrl !== void 0 && (typeof value.tokensAuthorizationServerUrl !== "string" || !URL.canParse(value.tokensAuthorizationServerUrl))) throw new McpOAuthStoreCorruptionError(storeKey, "tokensAuthorizationServerUrl is invalid"); if (value.tokensAuthorizationServerUrl !== void 0 && value.tokens === void 0) throw new McpOAuthStoreCorruptionError(storeKey, "tokensAuthorizationServerUrl requires tokens"); assertOptionalString(storeKey, value, "codeVerifier"); assertOptionalString(storeKey, value, "lastAuthorizationUrl"); assertOptionalString(storeKey, value, "redirectUrl"); assertDiscoveryState(storeKey, value.discoveryState); assertAuthorizationChallenge(storeKey, value.pendingAuthorizationChallenge); return value; } function storeFromRow(storeKey, row) { if (!row) return {}; if (row.format_version !== MCP_OAUTH_STORE_FORMAT_VERSION) throw new McpOAuthStoreCorruptionError(storeKey, `unsupported format version ${row.format_version}`); return parseMcpOAuthStoreJson(storeKey, row.store_json); } function readMcpOAuthStoreInDatabase(database, storeKey) { return storeFromRow(storeKey, executeSqliteQueryTakeFirstSync(database, getNodeSqliteKysely(database).selectFrom("mcp_oauth_stores").select(["format_version", "store_json"]).where("store_key", "=", storeKey))); } const MCP_OAUTH_PENDING_STATE_TTL_MS = 6e5; function replaceMcpOAuthStoreInDatabase(database, storeKey, next, assertOwnedInTransaction) { const storeJson = JSON.stringify(next); parseMcpOAuthStoreJson(storeKey, storeJson); assertOwnedInTransaction?.(database); const updatedAt = Date.now(); executeSqliteQuerySync(database, getNodeSqliteKysely(database).insertInto("mcp_oauth_stores").values({ store_key: storeKey, format_version: MCP_OAUTH_STORE_FORMAT_VERSION, store_json: storeJson, updated_at: updatedAt }).onConflict((conflict) => conflict.column("store_key").doUpdateSet({ format_version: MCP_OAUTH_STORE_FORMAT_VERSION, store_json: storeJson, updated_at: updatedAt }))); return next; } //#endregion export { replaceMcpOAuthStoreInDatabase as i, parseMcpOAuthStoreJson as n, readMcpOAuthStoreInDatabase as r, MCP_OAUTH_PENDING_STATE_TTL_MS as t };