UNPKG

@tanstack/ai-mcp

Version:

Host-side Model Context Protocol client for TanStack AI: discover and run MCP server tools, resources, and prompts in any adapter's chat() loop, with generated end-to-end types.

195 lines (194 loc) • 6.17 kB
import { isJsonObject, isNonEmptyString, isRecord, issues } from "./value.js"; //#region src/events/wire.ts var DELIVERY_MODES = /* @__PURE__ */ new Set([ "poll", "push", "webhook" ]); function isIsoDateTime(value) { if (!/^\d{4}-\d{2}-\d{2}T/.test(value)) return false; return !Number.isNaN(Date.parse(value)); } function isDeliveryMode(value) { return typeof value === "string" && DELIVERY_MODES.has(value); } function parseEventDefinition(value) { if (!isRecord(value)) return void 0; if (!isNonEmptyString(value.name)) return void 0; if (!Array.isArray(value.delivery) || value.delivery.length === 0) return; const delivery = []; for (const mode of value.delivery) { if (!isDeliveryMode(mode)) return void 0; delivery.push(mode); } if (!("inputSchema" in value) || !("payloadSchema" in value)) return void 0; const description = typeof value.description === "string" ? value.description : void 0; const meta = isJsonObject(value._meta) ? value._meta : void 0; return { name: value.name, ...description === void 0 ? {} : { description }, delivery, inputSchema: value.inputSchema, payloadSchema: value.payloadSchema, ...meta === void 0 ? {} : { _meta: meta } }; } var listEventsResult = { "~standard": { version: 1, vendor: "tanstack-ai-mcp", validate(value) { if (!isRecord(value) || !Array.isArray(value.events)) return issues("events/list result must include an events array"); const events = []; for (const item of value.events) { const event = parseEventDefinition(item); if (event === void 0) return issues("events/list contains an invalid event descriptor"); events.push(event); } const nextCursor = value.nextCursor; if (nextCursor !== void 0 && typeof nextCursor !== "string") return issues("nextCursor must be a string"); return { value: { events, ...nextCursor === void 0 ? {} : { nextCursor } } }; } } }; var DELIVERY_STATUS_TYPES = { active: "boolean", lastDeliveryAt: "string", lastError: "string", failedSince: "string", throttled: "boolean", retryAfterMs: "number" }; function isDeliveryStatus(value) { if (!isRecord(value)) return false; return Object.entries(DELIVERY_STATUS_TYPES).every(([field, type]) => { const fieldValue = value[field]; if (fieldValue === void 0) return true; if (field === "lastError" && fieldValue === null) return true; return typeof fieldValue === type; }); } /** `undefined` when absent, `null` when present but malformed. */ function parseDeliveryStatus(value) { if (value === void 0) return void 0; return isDeliveryStatus(value) ? value : null; } var subscribeResult = { "~standard": { version: 1, vendor: "tanstack-ai-mcp", validate(value) { if (!isRecord(value) || !isNonEmptyString(value.id)) return issues("events/subscribe result must include id"); if (typeof value.truncated !== "boolean") return issues("events/subscribe result must include truncated"); if (value.refreshBefore !== null && typeof value.refreshBefore !== "string") return issues("refreshBefore must be an ISO timestamp or null"); if (typeof value.refreshBefore === "string" && !isIsoDateTime(value.refreshBefore)) return issues("refreshBefore must be an ISO timestamp or null"); let cursor = null; if (value.cursor === void 0 || value.cursor === null) cursor = null; else if (typeof value.cursor === "string") cursor = value.cursor; else return issues("cursor must be a string or null"); const deliveryStatus = parseDeliveryStatus(value.deliveryStatus); if (deliveryStatus === null) return issues("deliveryStatus has a field of the wrong type"); return { value: { id: value.id, refreshBefore: value.refreshBefore, cursor, truncated: value.truncated, ...deliveryStatus === void 0 ? {} : { deliveryStatus } } }; } } }; function parseEventOccurrence(value) { if (!isRecord(value)) return void 0; if (!isNonEmptyString(value.eventId) || !isNonEmptyString(value.name)) return; if (typeof value.timestamp !== "string" || !isIsoDateTime(value.timestamp)) return; const data = value.data; if (!isJsonObject(data)) return void 0; const event = { eventId: value.eventId, name: value.name, timestamp: value.timestamp, data }; if (value.cursor === void 0) return event; if (value.cursor !== null && typeof value.cursor !== "string") return void 0; event.cursor = value.cursor; return event; } /** * Classify a parsed webhook JSON body as an event or a control envelope. * * @experimental */ function classifyWebhookBody(json) { if (!isRecord(json)) return { kind: "invalid", issue: "body must be an object" }; if (typeof json.type === "string") { if (json.type === "verification") { if (!isNonEmptyString(json.challenge)) return { kind: "invalid", issue: "verification requires challenge" }; return { kind: "verification", challenge: json.challenge }; } if (json.type === "gap") { if (!isNonEmptyString(json.cursor)) return { kind: "invalid", issue: "gap requires cursor" }; return { kind: "gap", cursor: json.cursor }; } if (json.type === "terminated") { if (!isRecord(json.error)) return { kind: "invalid", issue: "terminated requires error" }; if (typeof json.error.code !== "number") return { kind: "invalid", issue: "terminated error.code must be a number" }; if (typeof json.error.message !== "string") return { kind: "invalid", issue: "terminated error.message must be a string" }; return { kind: "terminated", error: { code: json.error.code, message: json.error.message, ...json.error.data === void 0 ? {} : { data: json.error.data } } }; } return { kind: "invalid", issue: `unknown control type ${json.type}` }; } const event = parseEventOccurrence(json); if (event === void 0) return { kind: "invalid", issue: "invalid event envelope" }; return { kind: "event", event }; } var emptyResult = { "~standard": { version: 1, vendor: "tanstack-ai-mcp", validate() { return { value: {} }; } } }; //#endregion export { classifyWebhookBody, emptyResult, listEventsResult, subscribeResult }; //# sourceMappingURL=wire.js.map