@typesensekit/mcp
Advanced tools
| #!/usr/bin/env node | ||
| // src/server.ts | ||
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| // ../core/src/client.ts | ||
| import Typesense from "typesense"; | ||
| // ../core/src/config.ts | ||
| import { z } from "zod"; | ||
| var nodeConfigSchema = z.object({ | ||
| host: z.string().min(1), | ||
| port: z.number().int().positive().optional(), | ||
| protocol: z.enum(["http", "https"]).optional(), | ||
| path: z.string().optional() | ||
| }); | ||
| var serverConfigSchema = z.object({ | ||
| url: z.string().url(), | ||
| apiKey: z.string().min(1), | ||
| connectionTimeoutSeconds: z.number().positive().optional(), | ||
| nearestNode: nodeConfigSchema.optional(), | ||
| numRetries: z.number().int().nonnegative().optional(), | ||
| retryIntervalSeconds: z.number().positive().optional(), | ||
| healthcheckIntervalSeconds: z.number().positive().optional() | ||
| }); | ||
| // ../core/src/client.ts | ||
| function nodeFromUrl(url) { | ||
| const parsed = new URL(url); | ||
| const node = { | ||
| host: parsed.hostname, | ||
| port: parsed.port ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : 80, | ||
| protocol: parsed.protocol.replace(":", "") | ||
| }; | ||
| if (parsed.pathname !== "/") node.path = parsed.pathname; | ||
| return node; | ||
| } | ||
| function normalizeNearestNode(node) { | ||
| if (!node) return void 0; | ||
| return { | ||
| host: node.host, | ||
| port: node.port ?? (node.protocol === "http" ? 80 : 443), | ||
| protocol: node.protocol ?? "https", | ||
| path: node.path | ||
| }; | ||
| } | ||
| function createClient(config) { | ||
| const parsed = serverConfigSchema.parse(config); | ||
| const clientConfig = { | ||
| nodes: [nodeFromUrl(parsed.url)], | ||
| apiKey: parsed.apiKey, | ||
| connectionTimeoutSeconds: parsed.connectionTimeoutSeconds, | ||
| nearestNode: normalizeNearestNode(parsed.nearestNode), | ||
| numRetries: parsed.numRetries, | ||
| retryIntervalSeconds: parsed.retryIntervalSeconds, | ||
| healthcheckIntervalSeconds: parsed.healthcheckIntervalSeconds | ||
| }; | ||
| return new Typesense.Client(clientConfig); | ||
| } | ||
| // ../core/src/redaction.ts | ||
| var REDACTED = "[REDACTED]"; | ||
| var CIRCULAR = "[Circular]"; | ||
| var SECRET_KEYS = /* @__PURE__ */ new Set([ | ||
| "api_key", | ||
| "apikey", | ||
| "authorization", | ||
| "cookie", | ||
| "secret", | ||
| "setcookie", | ||
| "token", | ||
| "xtypesenseapikey" | ||
| ]); | ||
| function shouldRedactKey(key) { | ||
| const normalized = key.toLowerCase().replace(/[-_\s]/g, ""); | ||
| return SECRET_KEYS.has(normalized) || normalized.endsWith("apikey") || normalized.endsWith("token") || normalized.endsWith("secret"); | ||
| } | ||
| function isTypesenseApiKeyShape(value) { | ||
| return Array.isArray(value.actions) && Array.isArray(value.collections); | ||
| } | ||
| function redactText(value) { | ||
| return value.replace( | ||
| /(["']?authorization["']?\s*[:=]\s*)(["']?)(?:Bearer|Basic)?\s*[-A-Za-z0-9._~+/=]+(["']?)/gi, | ||
| (_match, prefix, openQuote) => `${prefix}${openQuote}${REDACTED}${openQuote}` | ||
| ).replace( | ||
| /(["']?(?:x-typesense-api-key|api[_-]?key|apikey|token|secret|cookie|set-cookie)["']?\s*[:=]\s*)(["']?)([^"',\s}\]]+)(["']?)/gi, | ||
| (_match, prefix, openQuote, _secret) => `${prefix}${openQuote}${REDACTED}${openQuote}` | ||
| ).replace(/\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/gi, `$1 ${REDACTED}`); | ||
| } | ||
| function redactError(error, seen) { | ||
| const output = {}; | ||
| for (const key of Object.getOwnPropertyNames(error)) { | ||
| output[key] = redactValue( | ||
| error[key], | ||
| seen | ||
| ); | ||
| } | ||
| if (!("name" in output)) output.name = error.name; | ||
| if (!("message" in output)) output.message = redactText(error.message); | ||
| return output; | ||
| } | ||
| function redactValue(value, seen) { | ||
| if (typeof value === "string") return redactText(value); | ||
| if (Array.isArray(value)) { | ||
| return value.map((item) => redactValue(item, seen)); | ||
| } | ||
| if (typeof value !== "object" || value === null) { | ||
| return value; | ||
| } | ||
| if (seen.has(value)) return CIRCULAR; | ||
| seen.add(value); | ||
| if (value instanceof Error) { | ||
| return redactError(value, seen); | ||
| } | ||
| const record = value; | ||
| return Object.fromEntries( | ||
| Object.entries(record).map(([key, child]) => [ | ||
| key, | ||
| shouldRedactKey(key) || key === "value" && isTypesenseApiKeyShape(record) ? REDACTED : redactValue(child, seen) | ||
| ]) | ||
| ); | ||
| } | ||
| function redactSecrets(value) { | ||
| return redactValue(value, /* @__PURE__ */ new WeakSet()); | ||
| } | ||
| // ../core/src/errors.ts | ||
| var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([ | ||
| "EAI_AGAIN", | ||
| "ECONNABORTED", | ||
| "ECONNREFUSED", | ||
| "ECONNRESET", | ||
| "ENOTFOUND", | ||
| "ETIMEDOUT" | ||
| ]); | ||
| function readErrorLike(error) { | ||
| return typeof error === "object" && error !== null ? error : {}; | ||
| } | ||
| function findNetworkErrorCode(error) { | ||
| const errorLike = readErrorLike(error); | ||
| if (typeof errorLike.code === "string" && NETWORK_ERROR_CODES.has(errorLike.code.toUpperCase())) { | ||
| return errorLike.code.toUpperCase(); | ||
| } | ||
| if (typeof errorLike.message === "string") { | ||
| const match = errorLike.message.match( | ||
| /\b(EAI_AGAIN|ECONNABORTED|ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT)\b/i | ||
| ); | ||
| if (match?.[1]) return match[1].toUpperCase(); | ||
| } | ||
| return errorLike.cause === void 0 ? void 0 : findNetworkErrorCode(errorLike.cause); | ||
| } | ||
| function endpointLabel(error) { | ||
| const errorLike = readErrorLike(error); | ||
| const host = typeof errorLike.hostname === "string" ? errorLike.hostname : typeof errorLike.host === "string" ? errorLike.host : typeof errorLike.address === "string" ? errorLike.address : void 0; | ||
| const port = typeof errorLike.port === "number" || typeof errorLike.port === "string" ? String(errorLike.port) : void 0; | ||
| if (host && port) return `${host}:${port}`; | ||
| if (host) return host; | ||
| return errorLike.cause === void 0 ? void 0 : endpointLabel(errorLike.cause); | ||
| } | ||
| function conciseNetworkErrorMessage(error) { | ||
| const code = findNetworkErrorCode(error); | ||
| if (!code) return void 0; | ||
| const endpoint = endpointLabel(error); | ||
| return `Request failed: ${code}${endpoint ? ` ${endpoint}` : ""}`; | ||
| } | ||
| function normalizeTypesenseError(error) { | ||
| if (error instanceof Error) { | ||
| const errorLike = error; | ||
| const status = errorLike.httpStatus ?? errorLike.status; | ||
| return { | ||
| code: typeof status === "number" ? String(status) : error.name || "TypesenseError", | ||
| message: redactText(error.message), | ||
| details: redactSecrets(error) | ||
| }; | ||
| } | ||
| if (typeof error === "object" && error !== null) { | ||
| const errorLike = error; | ||
| return { | ||
| code: typeof errorLike.status === "number" ? String(errorLike.status) : "TypesenseError", | ||
| message: typeof errorLike.message === "string" ? redactText(errorLike.message) : "Unknown Typesense error", | ||
| details: redactSecrets(error) | ||
| }; | ||
| } | ||
| return { code: "TypesenseError", message: redactText(String(error)) }; | ||
| } | ||
| function formatTypesenseErrorMessage(error, options = {}) { | ||
| const normalized = normalizeTypesenseError(error); | ||
| const message = conciseNetworkErrorMessage(error) ?? normalized.message; | ||
| if (!options.debug) return message; | ||
| return [ | ||
| message, | ||
| "", | ||
| "Debug details:", | ||
| JSON.stringify(normalized.details ?? normalized, null, 2) | ||
| ].join("\n"); | ||
| } | ||
| // ../core/src/operations/aliases.ts | ||
| import { z as z2 } from "zod"; | ||
| // ../core/src/operations/http.ts | ||
| function api(client) { | ||
| return client.apiCall; | ||
| } | ||
| function enc(value) { | ||
| return encodeURIComponent(value); | ||
| } | ||
| function collectionPath(collection) { | ||
| return `/collections/${enc(collection)}`; | ||
| } | ||
| // ../core/src/operations/aliases.ts | ||
| var aliasesOperations = [ | ||
| { | ||
| name: "aliases.list", | ||
| summary: "List aliases", | ||
| category: "aliases", | ||
| input: z2.object({}), | ||
| execute: async (client) => api(client).get("/aliases") | ||
| }, | ||
| { | ||
| name: "aliases.create", | ||
| summary: "Create or upsert an alias", | ||
| category: "aliases", | ||
| input: z2.object({ | ||
| name: z2.string(), | ||
| value: z2.object({ collection_name: z2.string() }) | ||
| }), | ||
| execute: async (client, input) => api(client).put(`/aliases/${enc(input.name)}`, input.value) | ||
| }, | ||
| { | ||
| name: "aliases.retrieve", | ||
| summary: "Retrieve an alias", | ||
| category: "aliases", | ||
| input: z2.object({ name: z2.string() }), | ||
| execute: async (client, input) => api(client).get(`/aliases/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "aliases.delete", | ||
| summary: "Delete an alias", | ||
| category: "aliases", | ||
| input: z2.object({ name: z2.string() }), | ||
| execute: async (client, input) => api(client).delete(`/aliases/${enc(input.name)}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/analytics.ts | ||
| import { z as z3 } from "zod"; | ||
| var analyticsOperations = [ | ||
| { | ||
| name: "analytics.rules.list", | ||
| summary: "List analytics rules", | ||
| category: "analytics", | ||
| input: z3.object({ ruleTag: z3.string().optional() }), | ||
| execute: async (client, input) => api(client).get( | ||
| "/analytics/rules", | ||
| input.ruleTag ? { rule_tag: input.ruleTag } : void 0 | ||
| ) | ||
| }, | ||
| { | ||
| name: "analytics.rules.create", | ||
| summary: "Create one or more analytics rules", | ||
| category: "analytics", | ||
| input: z3.object({ | ||
| value: z3.union([ | ||
| z3.record(z3.unknown()), | ||
| z3.array(z3.record(z3.unknown())).min(1) | ||
| ]) | ||
| }), | ||
| execute: async (client, input) => api(client).post("/analytics/rules", input.value) | ||
| }, | ||
| { | ||
| name: "analytics.rules.upsert", | ||
| summary: "Create or update an analytics rule", | ||
| category: "analytics", | ||
| input: z3.object({ name: z3.string(), value: z3.record(z3.unknown()) }), | ||
| execute: async (client, input) => api(client).put(`/analytics/rules/${enc(input.name)}`, input.value) | ||
| }, | ||
| { | ||
| name: "analytics.rules.delete", | ||
| summary: "Delete an analytics rule", | ||
| category: "analytics", | ||
| input: z3.object({ name: z3.string() }), | ||
| execute: async (client, input) => api(client).delete(`/analytics/rules/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "analytics.rules.retrieve", | ||
| summary: "Retrieve an analytics rule", | ||
| category: "analytics", | ||
| input: z3.object({ name: z3.string() }), | ||
| execute: async (client, input) => api(client).get(`/analytics/rules/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "analytics.events.create", | ||
| summary: "Create an analytics event", | ||
| category: "analytics", | ||
| input: z3.object({ | ||
| type: z3.string(), | ||
| name: z3.string(), | ||
| data: z3.record(z3.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).post("/analytics/events", input) | ||
| }, | ||
| { | ||
| name: "analytics.events.list", | ||
| summary: "Retrieve recent analytics events for a user and rule", | ||
| category: "analytics", | ||
| input: z3.object({ | ||
| userId: z3.string().min(1), | ||
| name: z3.string().min(1), | ||
| limit: z3.number().int().positive().max(1e3) | ||
| }), | ||
| execute: async (client, input) => api(client).get("/analytics/events", { | ||
| user_id: input.userId, | ||
| name: input.name, | ||
| n: input.limit | ||
| }) | ||
| }, | ||
| { | ||
| name: "analytics.flush", | ||
| summary: "Flush in-memory analytics data to persistent storage", | ||
| category: "analytics", | ||
| input: z3.object({}), | ||
| execute: async (client) => api(client).post("/analytics/flush") | ||
| }, | ||
| { | ||
| name: "analytics.status", | ||
| summary: "Retrieve analytics subsystem status", | ||
| category: "analytics", | ||
| input: z3.object({}), | ||
| execute: async (client) => api(client).get("/analytics/status") | ||
| } | ||
| ]; | ||
| // ../core/src/operations/api.ts | ||
| import { z as z4 } from "zod"; | ||
| var methodSchema = z4.enum(["get", "post", "put", "patch", "delete"]); | ||
| var normalizedMethodSchema = z4.preprocess( | ||
| (value) => typeof value === "string" ? value.toLowerCase() : value, | ||
| methodSchema | ||
| ); | ||
| var apiOperations = [ | ||
| { | ||
| name: "api.call", | ||
| summary: "Call any Typesense API endpoint not yet covered by a first-class operation", | ||
| category: "api", | ||
| input: z4.object({ | ||
| method: normalizedMethodSchema, | ||
| path: z4.string().startsWith("/"), | ||
| params: z4.record(z4.unknown()).optional(), | ||
| body: z4.unknown().optional() | ||
| }), | ||
| execute: async (client, input) => { | ||
| const request = api(client); | ||
| if (input.method === "get") return request.get(input.path, input.params); | ||
| if (input.method === "delete") | ||
| return request.delete(input.path, input.params); | ||
| if (input.method === "post") | ||
| return request.post(input.path, input.body, input.params); | ||
| if (input.method === "put") | ||
| return request.put(input.path, input.body, input.params); | ||
| return request.patch(input.path, input.body, input.params); | ||
| } | ||
| } | ||
| ]; | ||
| // ../core/src/operations/collections.ts | ||
| import { z as z5 } from "zod"; | ||
| var DEFAULT_WAIT_TIMEOUT_MS = 3e4; | ||
| var DEFAULT_WAIT_INTERVAL_MS = 1e3; | ||
| var baseFieldSchema = z5.object({ | ||
| name: z5.string(), | ||
| facet: z5.boolean().optional(), | ||
| index: z5.boolean().optional(), | ||
| optional: z5.boolean().optional(), | ||
| sort: z5.boolean().optional(), | ||
| locale: z5.string().optional(), | ||
| infix: z5.boolean().optional(), | ||
| stem: z5.boolean().optional() | ||
| }).passthrough(); | ||
| var createFieldSchema = baseFieldSchema.extend({ | ||
| type: z5.string() | ||
| }); | ||
| var patchFieldSchema = baseFieldSchema.extend({ | ||
| type: z5.string().optional(), | ||
| drop: z5.boolean().optional() | ||
| }); | ||
| var fieldLifecycleInputSchema = z5.object({ | ||
| collection: z5.string(), | ||
| field: z5.string().optional(), | ||
| yes: z5.boolean().optional(), | ||
| numDim: z5.coerce.number().int().positive().optional(), | ||
| vecDist: z5.string().optional(), | ||
| hnswM: z5.coerce.number().int().positive().optional(), | ||
| hnswEfConstruction: z5.coerce.number().int().positive().optional(), | ||
| embedFrom: z5.union([z5.string(), z5.array(z5.string())]).optional(), | ||
| embedModel: z5.string().optional(), | ||
| embedApiKey: z5.string().optional(), | ||
| timeoutMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_TIMEOUT_MS), | ||
| intervalMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_INTERVAL_MS) | ||
| }).passthrough(); | ||
| var waitInputSchema = z5.object({ | ||
| collection: z5.string(), | ||
| fieldPresent: z5.string().optional(), | ||
| fieldMissing: z5.string().optional(), | ||
| fieldEmbedFrom: z5.string().optional(), | ||
| timeoutMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_TIMEOUT_MS), | ||
| intervalMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_INTERVAL_MS) | ||
| }); | ||
| var FIELD_LIFECYCLE_KEYS = /* @__PURE__ */ new Set([ | ||
| "collection", | ||
| "field", | ||
| "yes", | ||
| "numDim", | ||
| "vecDist", | ||
| "hnswM", | ||
| "hnswEfConstruction", | ||
| "embedFrom", | ||
| "embedModel", | ||
| "embedApiKey", | ||
| "timeoutMs", | ||
| "intervalMs" | ||
| ]); | ||
| function sleep(ms) { | ||
| return new Promise((resolve) => setTimeout(resolve, ms)); | ||
| } | ||
| function isObject(value) { | ||
| return typeof value === "object" && value !== null && !Array.isArray(value); | ||
| } | ||
| function requestedFieldName(input) { | ||
| const name = input.field ?? input.name; | ||
| if (typeof name !== "string" || !name) { | ||
| throw new Error("A field name is required. Pass --field or include name."); | ||
| } | ||
| return name; | ||
| } | ||
| function requiresConfirmation(collection) { | ||
| return /^production(?:__|-|$)/i.test(collection) || /^prod(?:__|-|$)/i.test(collection); | ||
| } | ||
| function assertDestructiveConfirmed(input) { | ||
| if (requiresConfirmation(input.collection) && !input.yes) { | ||
| throw new Error( | ||
| `Refusing to modify production collection ${input.collection} without --yes.` | ||
| ); | ||
| } | ||
| } | ||
| function findField(collection, fieldName) { | ||
| return collection.fields?.find((field) => { | ||
| if (!isObject(field)) return false; | ||
| return field.name === fieldName; | ||
| }); | ||
| } | ||
| async function retrieveCollection(client, collection) { | ||
| return api(client).get(collectionPath(collection)); | ||
| } | ||
| function buildFieldDefinition(input) { | ||
| const field = Object.fromEntries( | ||
| Object.entries(input).filter( | ||
| ([key, value]) => value !== void 0 && !FIELD_LIFECYCLE_KEYS.has(key) | ||
| ) | ||
| ); | ||
| field.name = requestedFieldName(input); | ||
| if (input.numDim !== void 0) field.num_dim = input.numDim; | ||
| if (input.vecDist !== void 0) field.vec_dist = input.vecDist; | ||
| if (input.hnswM !== void 0 || input.hnswEfConstruction !== void 0) { | ||
| const hnswParams = isObject(field.hnsw_params) ? field.hnsw_params : {}; | ||
| if (input.hnswM !== void 0) hnswParams.M = input.hnswM; | ||
| if (input.hnswEfConstruction !== void 0) { | ||
| hnswParams.ef_construction = input.hnswEfConstruction; | ||
| } | ||
| field.hnsw_params = hnswParams; | ||
| } | ||
| if (input.embedFrom !== void 0 || input.embedModel !== void 0 || input.embedApiKey !== void 0) { | ||
| const embed = isObject(field.embed) ? field.embed : {}; | ||
| const modelConfig = isObject(embed.model_config) ? embed.model_config : {}; | ||
| if (input.embedFrom !== void 0) { | ||
| embed.from = Array.isArray(input.embedFrom) ? input.embedFrom : [input.embedFrom]; | ||
| } | ||
| if (input.embedModel !== void 0) | ||
| modelConfig.model_name = input.embedModel; | ||
| if (input.embedApiKey !== void 0) | ||
| modelConfig.api_key = input.embedApiKey; | ||
| embed.model_config = modelConfig; | ||
| field.embed = embed; | ||
| } | ||
| if (typeof field.type !== "string" || !field.type) { | ||
| throw new Error("A field type is required. Pass --type or include type."); | ||
| } | ||
| return field; | ||
| } | ||
| function parseEmbedFromCondition(condition) { | ||
| const separator = condition.indexOf(":"); | ||
| if (separator === -1) { | ||
| throw new Error("--field-embed-from must use FIELD:SOURCE format."); | ||
| } | ||
| return { | ||
| fieldName: condition.slice(0, separator), | ||
| source: condition.slice(separator + 1) | ||
| }; | ||
| } | ||
| function isTransientCollectionUpdateError(error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| return /another collection update operation is in progress/i.test(message) || /timeout of \d+ms exceeded/i.test(message) || /econnaborted/i.test(message); | ||
| } | ||
| function evaluateWaitCondition(collection, input) { | ||
| const conditions = [ | ||
| input.fieldPresent, | ||
| input.fieldMissing, | ||
| input.fieldEmbedFrom | ||
| ].filter(Boolean); | ||
| if (conditions.length !== 1) { | ||
| throw new Error( | ||
| "Pass exactly one wait condition: --field-present, --field-missing, or --field-embed-from." | ||
| ); | ||
| } | ||
| if (input.fieldPresent) { | ||
| return { | ||
| ok: Boolean(findField(collection, input.fieldPresent)), | ||
| condition: "field-present", | ||
| field: input.fieldPresent | ||
| }; | ||
| } | ||
| if (input.fieldMissing) { | ||
| return { | ||
| ok: !findField(collection, input.fieldMissing), | ||
| condition: "field-missing", | ||
| field: input.fieldMissing | ||
| }; | ||
| } | ||
| const { fieldName, source } = parseEmbedFromCondition( | ||
| input.fieldEmbedFrom ?? "" | ||
| ); | ||
| const field = findField(collection, fieldName); | ||
| const from = isObject(field) && isObject(field.embed) && Array.isArray(field.embed.from) ? field.embed.from : []; | ||
| return { | ||
| ok: from.includes(source), | ||
| condition: "field-embed-from", | ||
| field: fieldName, | ||
| source | ||
| }; | ||
| } | ||
| async function waitForCollectionCondition(client, input) { | ||
| const startedAt = Date.now(); | ||
| let lastError; | ||
| let attempts = 0; | ||
| while (Date.now() - startedAt <= input.timeoutMs) { | ||
| attempts += 1; | ||
| try { | ||
| const collection = await retrieveCollection(client, input.collection); | ||
| const result = evaluateWaitCondition(collection, input); | ||
| if (result.ok) { | ||
| return { | ||
| collection: input.collection, | ||
| attempts, | ||
| ...result | ||
| }; | ||
| } | ||
| } catch (error) { | ||
| if (!isTransientCollectionUpdateError(error)) throw error; | ||
| lastError = error; | ||
| } | ||
| await sleep(input.intervalMs); | ||
| } | ||
| const detail = lastError instanceof Error ? ` Last error: ${lastError.message}` : ""; | ||
| throw new Error( | ||
| `Timed out waiting for collection ${input.collection} schema condition.${detail}` | ||
| ); | ||
| } | ||
| async function dropField(client, input) { | ||
| assertDestructiveConfirmed(input); | ||
| const fieldName = requestedFieldName(input); | ||
| const collection = await retrieveCollection(client, input.collection); | ||
| const existingField = findField(collection, fieldName); | ||
| if (!existingField) { | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: fieldName, | ||
| alreadyMissing: true | ||
| }; | ||
| } | ||
| const result = await api(client).patch(collectionPath(input.collection), { | ||
| fields: [{ name: fieldName, drop: true }] | ||
| }); | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: fieldName, | ||
| before: existingField, | ||
| result | ||
| }; | ||
| } | ||
| async function addField(client, input) { | ||
| const field = buildFieldDefinition(input); | ||
| const result = await api(client).patch(collectionPath(input.collection), { | ||
| fields: [field] | ||
| }); | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: field.name, | ||
| added: field, | ||
| result | ||
| }; | ||
| } | ||
| var collectionOperations = [ | ||
| { | ||
| name: "collections.create", | ||
| summary: "Create a collection", | ||
| category: "collections", | ||
| input: z5.object({ | ||
| name: z5.string(), | ||
| fields: z5.array(createFieldSchema), | ||
| default_sorting_field: z5.string().optional(), | ||
| token_separators: z5.array(z5.string()).optional(), | ||
| symbols_to_index: z5.array(z5.string()).optional(), | ||
| enable_nested_fields: z5.boolean().optional() | ||
| }), | ||
| execute: async (client, input) => api(client).post("/collections", input) | ||
| }, | ||
| { | ||
| name: "collections.list", | ||
| summary: "List collections", | ||
| category: "collections", | ||
| input: z5.object({}), | ||
| execute: async (client) => api(client).get("/collections") | ||
| }, | ||
| { | ||
| name: "collections.retrieve", | ||
| summary: "Retrieve a collection", | ||
| category: "collections", | ||
| input: z5.object({ collection: z5.string() }), | ||
| execute: async (client, input) => api(client).get(collectionPath(input.collection)) | ||
| }, | ||
| { | ||
| name: "collections.update", | ||
| summary: "Update a collection schema", | ||
| category: "collections", | ||
| input: z5.object({ | ||
| collection: z5.string(), | ||
| fields: z5.array(patchFieldSchema).optional() | ||
| }), | ||
| execute: async (client, input) => api(client).patch(collectionPath(input.collection), { | ||
| fields: input.fields | ||
| }) | ||
| }, | ||
| { | ||
| name: "collections.wait", | ||
| summary: "Wait for a collection schema condition", | ||
| category: "collections", | ||
| input: waitInputSchema, | ||
| execute: waitForCollectionCondition | ||
| }, | ||
| { | ||
| name: "collections.fields.add", | ||
| summary: "Add a field to a collection", | ||
| category: "collections", | ||
| input: fieldLifecycleInputSchema, | ||
| execute: addField | ||
| }, | ||
| { | ||
| name: "collections.fields.drop", | ||
| summary: "Drop a field from a collection", | ||
| category: "collections", | ||
| input: fieldLifecycleInputSchema, | ||
| execute: dropField | ||
| }, | ||
| { | ||
| name: "collections.fields.replace", | ||
| summary: "Safely replace a collection field", | ||
| category: "collections", | ||
| input: fieldLifecycleInputSchema, | ||
| execute: async (client, input) => { | ||
| const fieldName = requestedFieldName(input); | ||
| const replacement = buildFieldDefinition(input); | ||
| const dropResult = await dropField(client, input); | ||
| await waitForCollectionCondition(client, { | ||
| collection: input.collection, | ||
| fieldMissing: fieldName, | ||
| timeoutMs: input.timeoutMs, | ||
| intervalMs: input.intervalMs | ||
| }); | ||
| try { | ||
| await api(client).patch(collectionPath(input.collection), { | ||
| fields: [replacement] | ||
| }); | ||
| } catch (error) { | ||
| throw new Error( | ||
| [ | ||
| error instanceof Error ? error.message : String(error), | ||
| "", | ||
| "The original field was dropped, but adding the replacement failed.", | ||
| `Recover with: tsk collections.fields.add --collection ${input.collection} --input field.json` | ||
| ].join("\n") | ||
| ); | ||
| } | ||
| const waitResult = await waitForCollectionCondition(client, { | ||
| collection: input.collection, | ||
| fieldPresent: fieldName, | ||
| timeoutMs: input.timeoutMs, | ||
| intervalMs: input.intervalMs | ||
| }); | ||
| const collection = await retrieveCollection(client, input.collection); | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: fieldName, | ||
| before: "before" in dropResult ? dropResult.before : void 0, | ||
| after: findField(collection, fieldName), | ||
| wait: waitResult | ||
| }; | ||
| } | ||
| }, | ||
| { | ||
| name: "collections.delete", | ||
| summary: "Delete a collection", | ||
| category: "collections", | ||
| input: z5.object({ collection: z5.string() }), | ||
| execute: async (client, input) => api(client).delete(collectionPath(input.collection)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/conversations.ts | ||
| import { z as z6 } from "zod"; | ||
| var conversationOperations = [ | ||
| { | ||
| name: "conversations.models.list", | ||
| summary: "List conversation models", | ||
| category: "conversations", | ||
| input: z6.object({}), | ||
| execute: async (client) => api(client).get("/conversations/models") | ||
| }, | ||
| { | ||
| name: "conversations.models.create", | ||
| summary: "Create a conversation model", | ||
| category: "conversations", | ||
| input: z6.object({ value: z6.record(z6.unknown()) }), | ||
| execute: async (client, input) => api(client).post("/conversations/models", input.value) | ||
| }, | ||
| { | ||
| name: "conversations.models.retrieve", | ||
| summary: "Retrieve a conversation model", | ||
| category: "conversations", | ||
| input: z6.object({ id: z6.string() }), | ||
| execute: async (client, input) => api(client).get(`/conversations/models/${enc(input.id)}`) | ||
| }, | ||
| { | ||
| name: "conversations.models.delete", | ||
| summary: "Delete a conversation model", | ||
| category: "conversations", | ||
| input: z6.object({ id: z6.string() }), | ||
| execute: async (client, input) => api(client).delete(`/conversations/models/${enc(input.id)}`) | ||
| }, | ||
| { | ||
| name: "conversations.history.retrieve", | ||
| summary: "Retrieve conversation history", | ||
| category: "conversations", | ||
| input: z6.object({ conversation_id: z6.string().optional() }), | ||
| execute: async (client, input) => api(client).get( | ||
| "/conversations/history", | ||
| input.conversation_id ? { conversation_id: input.conversation_id } : void 0 | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/curation-sets.ts | ||
| import { z as z7 } from "zod"; | ||
| function base(name) { | ||
| return name ? `/curation_sets/${enc(name)}` : "/curation_sets"; | ||
| } | ||
| function itemPath(name, id) { | ||
| const path = `${base(name)}/items`; | ||
| return id ? `${path}/${enc(id)}` : path; | ||
| } | ||
| var curationSetOperations = [ | ||
| { | ||
| name: "curation_sets.list", | ||
| summary: "List global curation sets", | ||
| category: "curations", | ||
| input: z7.object({}), | ||
| execute: async (client) => api(client).get(base()) | ||
| }, | ||
| { | ||
| name: "curation_sets.upsert", | ||
| summary: "Create or update a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ | ||
| name: z7.string(), | ||
| value: z7.object({ items: z7.array(z7.record(z7.unknown())) }) | ||
| }), | ||
| execute: async (client, input) => api(client).put(base(input.name), input.value) | ||
| }, | ||
| { | ||
| name: "curation_sets.retrieve", | ||
| summary: "Retrieve a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string() }), | ||
| execute: async (client, input) => api(client).get(base(input.name)) | ||
| }, | ||
| { | ||
| name: "curation_sets.delete", | ||
| summary: "Delete a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string() }), | ||
| execute: async (client, input) => api(client).delete(base(input.name)) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.list", | ||
| summary: "List items in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name)) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.upsert", | ||
| summary: "Create or update an item in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ | ||
| name: z7.string(), | ||
| id: z7.string(), | ||
| value: z7.record(z7.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(itemPath(input.name, input.id), input.value) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.retrieve", | ||
| summary: "Retrieve an item in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string(), id: z7.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name, input.id)) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.delete", | ||
| summary: "Delete an item in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string(), id: z7.string() }), | ||
| execute: async (client, input) => api(client).delete(itemPath(input.name, input.id)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/documents.ts | ||
| import { z as z8 } from "zod"; | ||
| var documentSchema = z8.record(z8.unknown()); | ||
| var idsSchema = z8.array(z8.string().min(1)).min(1); | ||
| var searchParams = z8.record( | ||
| z8.union([ | ||
| z8.string(), | ||
| z8.number(), | ||
| z8.boolean(), | ||
| z8.array(z8.string()), | ||
| z8.array(z8.number()) | ||
| ]) | ||
| ); | ||
| var documentOperations = [ | ||
| { | ||
| name: "documents.index", | ||
| summary: "Index a document", | ||
| category: "documents", | ||
| input: z8.object({ collection: z8.string(), document: documentSchema }), | ||
| execute: async (client, input) => api(client).post( | ||
| `${collectionPath(input.collection)}/documents`, | ||
| input.document | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.upsert", | ||
| summary: "Upsert a document", | ||
| category: "documents", | ||
| input: z8.object({ collection: z8.string(), document: documentSchema }), | ||
| execute: async (client, input) => api(client).post( | ||
| `${collectionPath(input.collection)}/documents`, | ||
| input.document, | ||
| { action: "upsert" } | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.get", | ||
| summary: "Get a document by id", | ||
| category: "documents", | ||
| input: z8.object({ collection: z8.string(), id: z8.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/${enc(input.id)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.get_many", | ||
| summary: "Get multiple documents by id", | ||
| category: "documents", | ||
| input: z8.object({ collection: z8.string(), ids: idsSchema }), | ||
| execute: async (client, input) => { | ||
| const request = api(client); | ||
| return Promise.all( | ||
| input.ids.map( | ||
| (id) => request.get( | ||
| `${collectionPath(input.collection)}/documents/${enc(id)}` | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
| }, | ||
| { | ||
| name: "documents.update", | ||
| summary: "Update a document by id", | ||
| category: "documents", | ||
| input: z8.object({ | ||
| collection: z8.string(), | ||
| id: z8.string(), | ||
| document: documentSchema | ||
| }), | ||
| execute: async (client, input) => api(client).patch( | ||
| `${collectionPath(input.collection)}/documents/${enc(input.id)}`, | ||
| input.document | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.delete", | ||
| summary: "Delete a document by id", | ||
| category: "documents", | ||
| input: z8.object({ collection: z8.string(), id: z8.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
| `${collectionPath(input.collection)}/documents/${enc(input.id)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.import", | ||
| summary: "Import documents into a collection", | ||
| category: "documents", | ||
| input: z8.object({ | ||
| collection: z8.string(), | ||
| documents: z8.union([z8.string(), z8.array(documentSchema)]), | ||
| action: z8.enum(["create", "upsert", "update", "emplace"]).optional() | ||
| }), | ||
| execute: async (client, input) => api(client).post( | ||
| `${collectionPath(input.collection)}/documents/import`, | ||
| Array.isArray(input.documents) ? input.documents.map((doc) => JSON.stringify(doc)).join("\n") : input.documents, | ||
| input.action ? { action: input.action } : void 0 | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.export", | ||
| summary: "Export documents from a collection", | ||
| category: "documents", | ||
| input: z8.object({ | ||
| collection: z8.string(), | ||
| params: searchParams.optional() | ||
| }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/export`, | ||
| input.params | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.search", | ||
| summary: "Search within a collection", | ||
| category: "documents", | ||
| input: z8.object({ collection: z8.string(), params: searchParams }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| input.params | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/keys.ts | ||
| import { z as z9 } from "zod"; | ||
| var keysOperations = [ | ||
| { | ||
| name: "keys.list", | ||
| summary: "List API keys", | ||
| category: "keys", | ||
| input: z9.object({}), | ||
| execute: async (client) => api(client).get("/keys") | ||
| }, | ||
| { | ||
| name: "keys.create", | ||
| summary: "Create an API key", | ||
| category: "keys", | ||
| input: z9.object({ value: z9.record(z9.unknown()) }), | ||
| execute: async (client, input) => api(client).post("/keys", input.value) | ||
| }, | ||
| { | ||
| name: "keys.retrieve", | ||
| summary: "Retrieve an API key", | ||
| category: "keys", | ||
| input: z9.object({ id: z9.union([z9.string(), z9.number()]) }), | ||
| execute: async (client, input) => api(client).get(`/keys/${enc(String(input.id))}`) | ||
| }, | ||
| { | ||
| name: "keys.delete", | ||
| summary: "Delete an API key", | ||
| category: "keys", | ||
| input: z9.object({ id: z9.union([z9.string(), z9.number()]) }), | ||
| execute: async (client, input) => api(client).delete(`/keys/${enc(String(input.id))}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/nl-search-models.ts | ||
| import { z as z10 } from "zod"; | ||
| var modelConfigSchema = z10.object({ | ||
| id: z10.string().optional(), | ||
| model_name: z10.string().optional(), | ||
| api_key: z10.string().optional(), | ||
| api_url: z10.string().url().optional(), | ||
| max_bytes: z10.number().int().positive().optional(), | ||
| temperature: z10.number().optional(), | ||
| system_prompt: z10.string().optional(), | ||
| top_p: z10.number().optional(), | ||
| top_k: z10.number().int().optional(), | ||
| stop_sequences: z10.array(z10.string()).optional(), | ||
| api_version: z10.string().optional(), | ||
| project_id: z10.string().optional(), | ||
| access_token: z10.string().optional(), | ||
| refresh_token: z10.string().optional(), | ||
| client_id: z10.string().optional(), | ||
| client_secret: z10.string().optional(), | ||
| region: z10.string().optional(), | ||
| max_output_tokens: z10.number().int().positive().optional(), | ||
| account_id: z10.string().optional() | ||
| }).passthrough(); | ||
| function modelPath(id) { | ||
| return `/nl_search_models/${enc(id)}`; | ||
| } | ||
| var nlSearchModelOperations = [ | ||
| { | ||
| name: "nl_search_models.list", | ||
| summary: "List natural language search models", | ||
| category: "nl_search_models", | ||
| input: z10.object({}), | ||
| execute: async (client) => api(client).get("/nl_search_models") | ||
| }, | ||
| { | ||
| name: "nl_search_models.create", | ||
| summary: "Create a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ value: modelConfigSchema }), | ||
| execute: async (client, input) => api(client).post("/nl_search_models", input.value) | ||
| }, | ||
| { | ||
| name: "nl_search_models.retrieve", | ||
| summary: "Retrieve a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ id: z10.string().min(1) }), | ||
| execute: async (client, input) => api(client).get(modelPath(input.id)) | ||
| }, | ||
| { | ||
| name: "nl_search_models.update", | ||
| summary: "Update a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ id: z10.string().min(1), value: modelConfigSchema }), | ||
| execute: async (client, input) => api(client).put(modelPath(input.id), input.value) | ||
| }, | ||
| { | ||
| name: "nl_search_models.delete", | ||
| summary: "Delete a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ id: z10.string().min(1) }), | ||
| execute: async (client, input) => api(client).delete(modelPath(input.id)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/overrides.ts | ||
| import { z as z11 } from "zod"; | ||
| var overridesOperations = [ | ||
| { | ||
| name: "overrides.list", | ||
| summary: "List overrides", | ||
| category: "overrides", | ||
| input: z11.object({ collection: z11.string() }), | ||
| execute: async (client, input) => api(client).get(`${collectionPath(input.collection)}/overrides`) | ||
| }, | ||
| { | ||
| name: "overrides.create", | ||
| summary: "Create or upsert a override", | ||
| category: "overrides", | ||
| input: z11.object({ | ||
| collection: z11.string(), | ||
| name: z11.string(), | ||
| value: z11.record(z11.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put( | ||
| `${collectionPath(input.collection)}/overrides/${enc(input.name)}`, | ||
| input.value | ||
| ) | ||
| }, | ||
| { | ||
| name: "overrides.retrieve", | ||
| summary: "Retrieve a override", | ||
| category: "overrides", | ||
| input: z11.object({ collection: z11.string(), name: z11.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/overrides/${enc(input.name)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "overrides.delete", | ||
| summary: "Delete a override", | ||
| category: "overrides", | ||
| input: z11.object({ collection: z11.string(), name: z11.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
| `${collectionPath(input.collection)}/overrides/${enc(input.name)}` | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/presets.ts | ||
| import { z as z12 } from "zod"; | ||
| var presetsOperations = [ | ||
| { | ||
| name: "presets.list", | ||
| summary: "List presets", | ||
| category: "presets", | ||
| input: z12.object({}), | ||
| execute: async (client) => api(client).get("/presets") | ||
| }, | ||
| { | ||
| name: "presets.create", | ||
| summary: "Create or upsert a preset", | ||
| category: "presets", | ||
| input: z12.object({ | ||
| name: z12.string(), | ||
| value: z12.record(z12.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(`/presets/${enc(input.name)}`, { | ||
| value: input.value | ||
| }) | ||
| }, | ||
| { | ||
| name: "presets.retrieve", | ||
| summary: "Retrieve a preset", | ||
| category: "presets", | ||
| input: z12.object({ name: z12.string() }), | ||
| execute: async (client, input) => api(client).get(`/presets/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "presets.delete", | ||
| summary: "Delete a preset", | ||
| category: "presets", | ||
| input: z12.object({ name: z12.string() }), | ||
| execute: async (client, input) => api(client).delete(`/presets/${enc(input.name)}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/search.ts | ||
| import { z as z13 } from "zod"; | ||
| var searchParams2 = z13.record(z13.unknown()); | ||
| var facetBySchema = z13.union([z13.string().min(1), z13.array(z13.string().min(1))]); | ||
| function withoutUndefined(params) { | ||
| return Object.fromEntries( | ||
| Object.entries(params).filter(([, value]) => value !== void 0) | ||
| ); | ||
| } | ||
| var searchOperations = [ | ||
| { | ||
| name: "search", | ||
| summary: "Search a collection", | ||
| category: "search", | ||
| input: z13.object({ collection: z13.string(), params: searchParams2 }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| input.params | ||
| ) | ||
| }, | ||
| { | ||
| name: "multi_search", | ||
| summary: "Run a Typesense multi-search", | ||
| category: "search", | ||
| input: z13.object({ | ||
| searches: z13.array(searchParams2), | ||
| commonParams: searchParams2.optional() | ||
| }), | ||
| execute: async (client, input) => api(client).post( | ||
| "/multi_search", | ||
| { searches: input.searches }, | ||
| input.commonParams | ||
| ) | ||
| }, | ||
| { | ||
| name: "search.facets", | ||
| summary: "Explore facet counts for a collection", | ||
| category: "search", | ||
| input: z13.object({ | ||
| collection: z13.string(), | ||
| facetBy: facetBySchema, | ||
| q: z13.string().optional().default("*"), | ||
| queryBy: z13.string().optional(), | ||
| filterBy: z13.string().optional(), | ||
| maxFacetValues: z13.number().int().positive().optional(), | ||
| perPage: z13.number().int().nonnegative().optional().default(0) | ||
| }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| withoutUndefined({ | ||
| q: input.q, | ||
| query_by: input.queryBy, | ||
| filter_by: input.filterBy, | ||
| facet_by: Array.isArray(input.facetBy) ? input.facetBy.join(",") : input.facetBy, | ||
| max_facet_values: input.maxFacetValues, | ||
| per_page: input.perPage | ||
| }) | ||
| ) | ||
| }, | ||
| { | ||
| name: "search.suggestions", | ||
| summary: "Fetch prefix search suggestions from a collection", | ||
| category: "search", | ||
| input: z13.object({ | ||
| collection: z13.string(), | ||
| q: z13.string(), | ||
| queryBy: z13.string(), | ||
| filterBy: z13.string().optional(), | ||
| includeFields: z13.union([z13.string(), z13.array(z13.string())]).optional(), | ||
| limit: z13.number().int().positive().max(50).optional().default(5), | ||
| prefix: z13.boolean().optional().default(true) | ||
| }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| withoutUndefined({ | ||
| q: input.q, | ||
| query_by: input.queryBy, | ||
| filter_by: input.filterBy, | ||
| include_fields: Array.isArray(input.includeFields) ? input.includeFields.join(",") : input.includeFields, | ||
| per_page: input.limit, | ||
| prefix: input.prefix | ||
| }) | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/stemming.ts | ||
| import { z as z14 } from "zod"; | ||
| var wordMappingSchema = z14.object({ | ||
| word: z14.string().min(1), | ||
| root: z14.string().min(1) | ||
| }); | ||
| var stemmingOperations = [ | ||
| { | ||
| name: "stemming.dictionaries.list", | ||
| summary: "List stemming dictionaries", | ||
| category: "stemming", | ||
| input: z14.object({}), | ||
| execute: async (client) => api(client).get("/stemming/dictionaries") | ||
| }, | ||
| { | ||
| name: "stemming.dictionaries.retrieve", | ||
| summary: "Retrieve a stemming dictionary", | ||
| category: "stemming", | ||
| input: z14.object({ id: z14.string().min(1) }), | ||
| execute: async (client, input) => api(client).get(`/stemming/dictionaries/${enc(input.id)}`) | ||
| }, | ||
| { | ||
| name: "stemming.dictionaries.import", | ||
| summary: "Import or replace a stemming dictionary from word mappings", | ||
| category: "stemming", | ||
| input: z14.object({ | ||
| id: z14.string().min(1), | ||
| words: z14.union([z14.string().min(1), z14.array(wordMappingSchema).min(1)]) | ||
| }), | ||
| execute: async (client, input) => api(client).post( | ||
| "/stemming/dictionaries/import", | ||
| Array.isArray(input.words) ? input.words.map( | ||
| (mapping) => JSON.stringify(mapping) | ||
| ).join("\n") : input.words, | ||
| { id: input.id } | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/stopwords.ts | ||
| import { z as z15 } from "zod"; | ||
| var stopwordsOperations = [ | ||
| { | ||
| name: "stopwords.list", | ||
| summary: "List stopwords", | ||
| category: "stopwords", | ||
| input: z15.object({}), | ||
| execute: async (client) => api(client).get("/stopwords") | ||
| }, | ||
| { | ||
| name: "stopwords.create", | ||
| summary: "Create or upsert a stopword", | ||
| category: "stopwords", | ||
| input: z15.object({ | ||
| name: z15.string(), | ||
| value: z15.record(z15.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(`/stopwords/${enc(input.name)}`, input.value) | ||
| }, | ||
| { | ||
| name: "stopwords.retrieve", | ||
| summary: "Retrieve a stopword", | ||
| category: "stopwords", | ||
| input: z15.object({ name: z15.string() }), | ||
| execute: async (client, input) => api(client).get(`/stopwords/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "stopwords.delete", | ||
| summary: "Delete a stopword", | ||
| category: "stopwords", | ||
| input: z15.object({ name: z15.string() }), | ||
| execute: async (client, input) => api(client).delete(`/stopwords/${enc(input.name)}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/synonym-sets.ts | ||
| import { z as z16 } from "zod"; | ||
| function base2(name) { | ||
| return name ? `/synonym_sets/${enc(name)}` : "/synonym_sets"; | ||
| } | ||
| function itemPath2(name, id) { | ||
| const path = `${base2(name)}/items`; | ||
| return id ? `${path}/${enc(id)}` : path; | ||
| } | ||
| var synonymSetOperations = [ | ||
| { | ||
| name: "synonym_sets.list", | ||
| summary: "List global synonym sets", | ||
| category: "synonyms", | ||
| input: z16.object({}), | ||
| execute: async (client) => api(client).get(base2()) | ||
| }, | ||
| { | ||
| name: "synonym_sets.create", | ||
| summary: "Create or upsert a global synonym set", | ||
| category: "synonyms", | ||
| input: z16.object({ | ||
| name: z16.string(), | ||
| value: z16.object({ | ||
| items: z16.array(z16.record(z16.unknown())) | ||
| }) | ||
| }), | ||
| execute: async (client, input) => api(client).put(base2(input.name), input.value) | ||
| }, | ||
| { | ||
| name: "synonym_sets.retrieve", | ||
| summary: "Retrieve a global synonym set", | ||
| category: "synonyms", | ||
| input: z16.object({ name: z16.string() }), | ||
| execute: async (client, input) => api(client).get(base2(input.name)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.delete", | ||
| summary: "Delete a global synonym set", | ||
| category: "synonyms", | ||
| input: z16.object({ name: z16.string() }), | ||
| execute: async (client, input) => api(client).delete(base2(input.name)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.list", | ||
| summary: "List items in a global synonym set", | ||
| category: "synonyms", | ||
| input: z16.object({ name: z16.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath2(input.name)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.create", | ||
| summary: "Create or upsert an item in a global synonym set", | ||
| category: "synonyms", | ||
| input: z16.object({ | ||
| name: z16.string(), | ||
| id: z16.string(), | ||
| value: z16.record(z16.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(itemPath2(input.name, input.id), input.value) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.retrieve", | ||
| summary: "Retrieve an item in a global synonym set", | ||
| category: "synonyms", | ||
| input: z16.object({ name: z16.string(), id: z16.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath2(input.name, input.id)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.delete", | ||
| summary: "Delete an item in a global synonym set", | ||
| category: "synonyms", | ||
| input: z16.object({ name: z16.string(), id: z16.string() }), | ||
| execute: async (client, input) => api(client).delete(itemPath2(input.name, input.id)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/synonyms.ts | ||
| import { z as z17 } from "zod"; | ||
| function isNotFound(error) { | ||
| if (typeof error !== "object" || error === null) return false; | ||
| const { httpStatus, status } = error; | ||
| return httpStatus === 404 || status === 404; | ||
| } | ||
| function synonymSetNames(collection) { | ||
| return Array.isArray(collection.synonym_sets) ? collection.synonym_sets.filter( | ||
| (name) => typeof name === "string" | ||
| ) : []; | ||
| } | ||
| function globalSynonymGuidance(collection, sets) { | ||
| return [ | ||
| `Collection-level synonyms are unavailable for ${collection}.`, | ||
| sets.length > 0 ? `This collection is linked to global synonym sets: ${sets.join(", ")}.` : "This Typesense version may use global synonym sets.", | ||
| "Use synonym_sets.list to inspect global synonym sets:", | ||
| "tsk synonym_sets.list --input '{}' --json" | ||
| ].join("\n"); | ||
| } | ||
| var synonymsOperations = [ | ||
| { | ||
| name: "synonyms.list", | ||
| summary: "List synonyms", | ||
| category: "synonyms", | ||
| input: z17.object({ collection: z17.string() }), | ||
| execute: async (client, input) => { | ||
| const request = api(client); | ||
| try { | ||
| return await request.get( | ||
| `${collectionPath(input.collection)}/synonyms` | ||
| ); | ||
| } catch (error) { | ||
| if (!isNotFound(error)) throw error; | ||
| const collection = await request.get( | ||
| collectionPath(input.collection) | ||
| ); | ||
| throw new Error( | ||
| globalSynonymGuidance(input.collection, synonymSetNames(collection)) | ||
| ); | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| name: "synonyms.create", | ||
| summary: "Create or upsert a synonym", | ||
| category: "synonyms", | ||
| input: z17.object({ | ||
| collection: z17.string(), | ||
| name: z17.string(), | ||
| value: z17.record(z17.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put( | ||
| `${collectionPath(input.collection)}/synonyms/${enc(input.name)}`, | ||
| input.value | ||
| ) | ||
| }, | ||
| { | ||
| name: "synonyms.retrieve", | ||
| summary: "Retrieve a synonym", | ||
| category: "synonyms", | ||
| input: z17.object({ collection: z17.string(), name: z17.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/synonyms/${enc(input.name)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "synonyms.delete", | ||
| summary: "Delete a synonym", | ||
| category: "synonyms", | ||
| input: z17.object({ collection: z17.string(), name: z17.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
| `${collectionPath(input.collection)}/synonyms/${enc(input.name)}` | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/system.ts | ||
| import { z as z18 } from "zod"; | ||
| var systemOperations = [ | ||
| { | ||
| name: "operations.schema_changes", | ||
| summary: "List in-progress collection schema changes", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/operations/schema_changes") | ||
| }, | ||
| { | ||
| name: "operations.snapshot", | ||
| summary: "Create a point-in-time server snapshot", | ||
| category: "system", | ||
| input: z18.object({ snapshotPath: z18.string().min(1) }), | ||
| execute: async (client, input) => api(client).post("/operations/snapshot", void 0, { | ||
| snapshot_path: input.snapshotPath | ||
| }) | ||
| }, | ||
| { | ||
| name: "operations.vote", | ||
| summary: "Trigger leader re-election on a follower node", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).post("/operations/vote") | ||
| }, | ||
| { | ||
| name: "operations.cache.clear", | ||
| summary: "Clear cached search responses", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).post("/operations/cache/clear") | ||
| }, | ||
| { | ||
| name: "operations.db.compact", | ||
| summary: "Compact the on-disk Typesense database", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).post("/operations/db/compact") | ||
| }, | ||
| { | ||
| name: "operations.slow_requests.configure", | ||
| summary: "Configure the slow-request logging threshold", | ||
| category: "system", | ||
| input: z18.object({ thresholdMs: z18.number().int().min(-1) }), | ||
| execute: async (client, input) => api(client).post("/config", { | ||
| "log-slow-requests-time-ms": input.thresholdMs | ||
| }) | ||
| }, | ||
| { | ||
| name: "health", | ||
| summary: "Check Typesense cluster health", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/health") | ||
| }, | ||
| { | ||
| name: "metrics", | ||
| summary: "Retrieve Typesense metrics", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/metrics.json") | ||
| }, | ||
| { | ||
| name: "stats", | ||
| summary: "Retrieve Typesense stats", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/stats.json") | ||
| }, | ||
| { | ||
| name: "debug", | ||
| summary: "Retrieve Typesense debug info", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/debug") | ||
| } | ||
| ]; | ||
| // ../core/src/operations/index.ts | ||
| var operations = [ | ||
| ...collectionOperations, | ||
| ...documentOperations, | ||
| ...searchOperations, | ||
| ...aliasesOperations, | ||
| ...synonymsOperations, | ||
| ...synonymSetOperations, | ||
| ...curationSetOperations, | ||
| ...overridesOperations, | ||
| ...keysOperations, | ||
| ...analyticsOperations, | ||
| ...presetsOperations, | ||
| ...stopwordsOperations, | ||
| ...stemmingOperations, | ||
| ...conversationOperations, | ||
| ...nlSearchModelOperations, | ||
| ...apiOperations, | ||
| ...systemOperations | ||
| ]; | ||
| // package.json | ||
| var package_default = { | ||
| name: "@typesensekit/mcp", | ||
| version: "1.2.0", | ||
| type: "module", | ||
| main: "dist/server.js", | ||
| types: "dist/server.d.ts", | ||
| bin: { | ||
| "typesensekit-mcp": "dist/cli.js", | ||
| "typesensekit-mcp-http": "dist/http.js" | ||
| }, | ||
| exports: { | ||
| ".": { | ||
| types: "./dist/server.d.ts", | ||
| import: "./dist/server.js" | ||
| } | ||
| }, | ||
| files: [ | ||
| "dist", | ||
| "README.md" | ||
| ], | ||
| scripts: { | ||
| build: "tsup", | ||
| dev: "tsup --watch", | ||
| typecheck: "tsc --noEmit", | ||
| test: "vitest run" | ||
| }, | ||
| dependencies: { | ||
| "@modelcontextprotocol/sdk": "^1.29.0", | ||
| zod: "^3.25.76", | ||
| typesense: "^3.0.6" | ||
| }, | ||
| devDependencies: { | ||
| tsup: "^8.5.1", | ||
| "@types/node": "^22.10.0", | ||
| "@typesensekit/core": "workspace:*" | ||
| }, | ||
| publishConfig: { | ||
| access: "public" | ||
| }, | ||
| description: "MCP stdio server exposing Typesense API operations as tools.", | ||
| license: "MIT", | ||
| author: "Akshit Kr Nagpal", | ||
| repository: { | ||
| type: "git", | ||
| url: "git+https://github.com/akshitkrnagpal/typesensekit.git", | ||
| directory: "packages/mcp" | ||
| }, | ||
| bugs: { | ||
| url: "https://github.com/akshitkrnagpal/typesensekit/issues" | ||
| }, | ||
| homepage: "https://github.com/akshitkrnagpal/typesensekit#readme", | ||
| keywords: [ | ||
| "typesense", | ||
| "cli", | ||
| "mcp", | ||
| "model-context-protocol", | ||
| "search" | ||
| ] | ||
| }; | ||
| // src/read-only.ts | ||
| var READ_ONLY_OPERATION_NAMES = /* @__PURE__ */ new Set([ | ||
| "aliases.list", | ||
| "aliases.retrieve", | ||
| "analytics.events.list", | ||
| "analytics.rules.list", | ||
| "analytics.rules.retrieve", | ||
| "analytics.status", | ||
| "collections.list", | ||
| "collections.retrieve", | ||
| "collections.wait", | ||
| "conversations.history.retrieve", | ||
| "conversations.models.list", | ||
| "conversations.models.retrieve", | ||
| "curation_sets.items.list", | ||
| "curation_sets.items.retrieve", | ||
| "curation_sets.list", | ||
| "curation_sets.retrieve", | ||
| "debug", | ||
| "documents.export", | ||
| "documents.get", | ||
| "documents.get_many", | ||
| "documents.search", | ||
| "health", | ||
| "metrics", | ||
| "multi_search", | ||
| "nl_search_models.list", | ||
| "nl_search_models.retrieve", | ||
| "overrides.list", | ||
| "overrides.retrieve", | ||
| "operations.schema_changes", | ||
| "presets.list", | ||
| "presets.retrieve", | ||
| "search", | ||
| "search.facets", | ||
| "search.suggestions", | ||
| "stats", | ||
| "stemming.dictionaries.list", | ||
| "stemming.dictionaries.retrieve", | ||
| "stopwords.list", | ||
| "stopwords.retrieve", | ||
| "synonym_sets.items.list", | ||
| "synonym_sets.items.retrieve", | ||
| "synonym_sets.list", | ||
| "synonym_sets.retrieve", | ||
| "synonyms.list", | ||
| "synonyms.retrieve" | ||
| ]); | ||
| function isReadOnlyOperation(operation) { | ||
| return READ_ONLY_OPERATION_NAMES.has(operation.name); | ||
| } | ||
| function filterMcpOperations(operations2, readOnly) { | ||
| return readOnly ? operations2.filter(isReadOnlyOperation) : operations2; | ||
| } | ||
| function readOnlyFromEnv(value) { | ||
| if (value === void 0) return true; | ||
| return !["0", "false", "no", "off"].includes(value.toLowerCase()); | ||
| } | ||
| // src/env.ts | ||
| function readEnvConfig() { | ||
| return serverConfigSchema.parse({ | ||
| url: process.env.TYPESENSE_URL, | ||
| apiKey: process.env.TYPESENSE_API_KEY, | ||
| connectionTimeoutSeconds: process.env.TYPESENSE_CONNECTION_TIMEOUT_SECONDS ? Number(process.env.TYPESENSE_CONNECTION_TIMEOUT_SECONDS) : void 0 | ||
| }); | ||
| } | ||
| function readMcpOptions() { | ||
| return { | ||
| readOnly: readOnlyFromEnv(process.env.TYPESENSEKIT_READ_ONLY) | ||
| }; | ||
| } | ||
| // src/resources.ts | ||
| import { | ||
| ResourceTemplate | ||
| } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| function jsonContents(uri, value) { | ||
| return { | ||
| contents: [ | ||
| { | ||
| uri, | ||
| mimeType: "application/json", | ||
| text: JSON.stringify(value, null, 2) | ||
| } | ||
| ] | ||
| }; | ||
| } | ||
| function textContents(uri, value) { | ||
| return { | ||
| contents: [{ uri, mimeType: "text/plain", text: value }] | ||
| }; | ||
| } | ||
| function operationSummary(operation) { | ||
| return { | ||
| name: operation.name, | ||
| summary: operation.summary, | ||
| category: operation.category, | ||
| readOnly: READ_ONLY_OPERATION_NAMES.has(operation.name) | ||
| }; | ||
| } | ||
| function operationManifest(activeOperations, readOnly) { | ||
| return { | ||
| readOnly, | ||
| operations: activeOperations.map(operationSummary) | ||
| }; | ||
| } | ||
| function singleVariable(value, variable) { | ||
| if (typeof value === "string") return value; | ||
| throw new Error(`Missing ${variable} resource variable`); | ||
| } | ||
| async function readOperationResource(client, operationName, input, uri) { | ||
| const operation = operations.find( | ||
| (candidate) => candidate.name === operationName | ||
| ); | ||
| if (!operation) throw new Error(`${operationName} not found`); | ||
| try { | ||
| const result = await operation.execute( | ||
| client, | ||
| operation.input.parse(input) | ||
| ); | ||
| return jsonContents(uri, result); | ||
| } catch (error) { | ||
| return textContents(uri, formatTypesenseErrorMessage(error)); | ||
| } | ||
| } | ||
| function registerTypesenseResources(server, client, activeOperations, readOnly) { | ||
| server.registerResource( | ||
| "typesensekit-operations", | ||
| "typesensekit://operations", | ||
| { | ||
| title: "TypesenseKit Operations", | ||
| description: "Operations currently exposed by this MCP server.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri) => jsonContents(uri.href, operationManifest(activeOperations, readOnly)) | ||
| ); | ||
| server.registerResource( | ||
| "typesensekit-read-only-tools", | ||
| "typesensekit://read-only-tools", | ||
| { | ||
| title: "TypesenseKit Read-only Tools", | ||
| description: "Operation names included in default read-only MCP mode.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri) => jsonContents(uri.href, { | ||
| operations: [...READ_ONLY_OPERATION_NAMES].sort() | ||
| }) | ||
| ); | ||
| server.registerResource( | ||
| "typesense-collection-schema", | ||
| new ResourceTemplate("typesense://collections/{collection}/schema", { | ||
| list: void 0 | ||
| }), | ||
| { | ||
| title: "Typesense Collection Schema", | ||
| description: "Retrieve a Typesense collection schema by collection name.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri, variables) => readOperationResource( | ||
| client, | ||
| "collections.retrieve", | ||
| { collection: singleVariable(variables.collection, "collection") }, | ||
| uri.href | ||
| ) | ||
| ); | ||
| server.registerResource( | ||
| "typesense-document", | ||
| new ResourceTemplate( | ||
| "typesense://collections/{collection}/documents/{id}", | ||
| { | ||
| list: void 0 | ||
| } | ||
| ), | ||
| { | ||
| title: "Typesense Document", | ||
| description: "Retrieve a Typesense document by collection and document id.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri, variables) => readOperationResource( | ||
| client, | ||
| "documents.get", | ||
| { | ||
| collection: singleVariable(variables.collection, "collection"), | ||
| id: singleVariable(variables.id, "id") | ||
| }, | ||
| uri.href | ||
| ) | ||
| ); | ||
| } | ||
| // src/server.ts | ||
| function toToolShape(input) { | ||
| const objectInput = input; | ||
| return objectInput.shape; | ||
| } | ||
| function createTypesenseMcpServer(options = {}) { | ||
| const server = new McpServer({ | ||
| name: "typesensekit", | ||
| version: package_default.version | ||
| }); | ||
| const client = createClient(readEnvConfig()); | ||
| const mcpOptions = { ...readMcpOptions(), ...options }; | ||
| const activeOperations = filterMcpOperations(operations, mcpOptions.readOnly); | ||
| registerTypesenseResources( | ||
| server, | ||
| client, | ||
| activeOperations, | ||
| mcpOptions.readOnly | ||
| ); | ||
| for (const operation of activeOperations) { | ||
| server.registerTool( | ||
| operation.name, | ||
| { | ||
| title: operation.name, | ||
| description: operation.summary, | ||
| inputSchema: toToolShape(operation.input) | ||
| }, | ||
| async (args) => { | ||
| try { | ||
| const input = operation.input.parse(args); | ||
| const result = await operation.execute(client, input); | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: JSON.stringify(redactSecrets(result), null, 2) | ||
| } | ||
| ] | ||
| }; | ||
| } catch (error) { | ||
| const message = formatTypesenseErrorMessage(error); | ||
| return { isError: true, content: [{ type: "text", text: message }] }; | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| return server; | ||
| } | ||
| export { | ||
| createTypesenseMcpServer | ||
| }; |
+1
-1
| #!/usr/bin/env node | ||
| import { | ||
| createTypesenseMcpServer | ||
| } from "./chunk-MZXJKIHS.js"; | ||
| } from "./chunk-KY4R2JA7.js"; | ||
@@ -6,0 +6,0 @@ // src/cli.ts |
+1
-1
| #!/usr/bin/env node | ||
| import { | ||
| createTypesenseMcpServer | ||
| } from "./chunk-MZXJKIHS.js"; | ||
| } from "./chunk-KY4R2JA7.js"; | ||
@@ -6,0 +6,0 @@ // src/http.ts |
+407
-116
@@ -74,3 +74,3 @@ // src/server.ts | ||
| const normalized = key.toLowerCase().replace(/[-_\s]/g, ""); | ||
| return SECRET_KEYS.has(normalized) || normalized.endsWith("apikey"); | ||
| return SECRET_KEYS.has(normalized) || normalized.endsWith("apikey") || normalized.endsWith("token") || normalized.endsWith("secret"); | ||
| } | ||
@@ -253,6 +253,21 @@ function isTypesenseApiKeyShape(value) { | ||
| category: "analytics", | ||
| input: z3.object({}), | ||
| execute: async (client) => api(client).get("/analytics/rules") | ||
| input: z3.object({ ruleTag: z3.string().optional() }), | ||
| execute: async (client, input) => api(client).get( | ||
| "/analytics/rules", | ||
| input.ruleTag ? { rule_tag: input.ruleTag } : void 0 | ||
| ) | ||
| }, | ||
| { | ||
| name: "analytics.rules.create", | ||
| summary: "Create one or more analytics rules", | ||
| category: "analytics", | ||
| input: z3.object({ | ||
| value: z3.union([ | ||
| z3.record(z3.unknown()), | ||
| z3.array(z3.record(z3.unknown())).min(1) | ||
| ]) | ||
| }), | ||
| execute: async (client, input) => api(client).post("/analytics/rules", input.value) | ||
| }, | ||
| { | ||
| name: "analytics.rules.upsert", | ||
@@ -272,2 +287,9 @@ summary: "Create or update an analytics rule", | ||
| { | ||
| name: "analytics.rules.retrieve", | ||
| summary: "Retrieve an analytics rule", | ||
| category: "analytics", | ||
| input: z3.object({ name: z3.string() }), | ||
| execute: async (client, input) => api(client).get(`/analytics/rules/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "analytics.events.create", | ||
@@ -282,2 +304,31 @@ summary: "Create an analytics event", | ||
| execute: async (client, input) => api(client).post("/analytics/events", input) | ||
| }, | ||
| { | ||
| name: "analytics.events.list", | ||
| summary: "Retrieve recent analytics events for a user and rule", | ||
| category: "analytics", | ||
| input: z3.object({ | ||
| userId: z3.string().min(1), | ||
| name: z3.string().min(1), | ||
| limit: z3.number().int().positive().max(1e3) | ||
| }), | ||
| execute: async (client, input) => api(client).get("/analytics/events", { | ||
| user_id: input.userId, | ||
| name: input.name, | ||
| n: input.limit | ||
| }) | ||
| }, | ||
| { | ||
| name: "analytics.flush", | ||
| summary: "Flush in-memory analytics data to persistent storage", | ||
| category: "analytics", | ||
| input: z3.object({}), | ||
| execute: async (client) => api(client).post("/analytics/flush") | ||
| }, | ||
| { | ||
| name: "analytics.status", | ||
| summary: "Retrieve analytics subsystem status", | ||
| category: "analytics", | ||
| input: z3.object({}), | ||
| execute: async (client) => api(client).get("/analytics/status") | ||
| } | ||
@@ -717,13 +768,88 @@ ]; | ||
| // ../core/src/operations/curation-sets.ts | ||
| import { z as z7 } from "zod"; | ||
| function base(name) { | ||
| return name ? `/curation_sets/${enc(name)}` : "/curation_sets"; | ||
| } | ||
| function itemPath(name, id) { | ||
| const path = `${base(name)}/items`; | ||
| return id ? `${path}/${enc(id)}` : path; | ||
| } | ||
| var curationSetOperations = [ | ||
| { | ||
| name: "curation_sets.list", | ||
| summary: "List global curation sets", | ||
| category: "curations", | ||
| input: z7.object({}), | ||
| execute: async (client) => api(client).get(base()) | ||
| }, | ||
| { | ||
| name: "curation_sets.upsert", | ||
| summary: "Create or update a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ | ||
| name: z7.string(), | ||
| value: z7.object({ items: z7.array(z7.record(z7.unknown())) }) | ||
| }), | ||
| execute: async (client, input) => api(client).put(base(input.name), input.value) | ||
| }, | ||
| { | ||
| name: "curation_sets.retrieve", | ||
| summary: "Retrieve a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string() }), | ||
| execute: async (client, input) => api(client).get(base(input.name)) | ||
| }, | ||
| { | ||
| name: "curation_sets.delete", | ||
| summary: "Delete a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string() }), | ||
| execute: async (client, input) => api(client).delete(base(input.name)) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.list", | ||
| summary: "List items in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name)) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.upsert", | ||
| summary: "Create or update an item in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ | ||
| name: z7.string(), | ||
| id: z7.string(), | ||
| value: z7.record(z7.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(itemPath(input.name, input.id), input.value) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.retrieve", | ||
| summary: "Retrieve an item in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string(), id: z7.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name, input.id)) | ||
| }, | ||
| { | ||
| name: "curation_sets.items.delete", | ||
| summary: "Delete an item in a global curation set", | ||
| category: "curations", | ||
| input: z7.object({ name: z7.string(), id: z7.string() }), | ||
| execute: async (client, input) => api(client).delete(itemPath(input.name, input.id)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/documents.ts | ||
| import { z as z7 } from "zod"; | ||
| var documentSchema = z7.record(z7.unknown()); | ||
| var idsSchema = z7.array(z7.string().min(1)).min(1); | ||
| var searchParams = z7.record( | ||
| z7.union([ | ||
| z7.string(), | ||
| z7.number(), | ||
| z7.boolean(), | ||
| z7.array(z7.string()), | ||
| z7.array(z7.number()) | ||
| import { z as z8 } from "zod"; | ||
| var documentSchema = z8.record(z8.unknown()); | ||
| var idsSchema = z8.array(z8.string().min(1)).min(1); | ||
| var searchParams = z8.record( | ||
| z8.union([ | ||
| z8.string(), | ||
| z8.number(), | ||
| z8.boolean(), | ||
| z8.array(z8.string()), | ||
| z8.array(z8.number()) | ||
| ]) | ||
@@ -736,3 +862,3 @@ ); | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), document: documentSchema }), | ||
| input: z8.object({ collection: z8.string(), document: documentSchema }), | ||
| execute: async (client, input) => api(client).post( | ||
@@ -747,3 +873,3 @@ `${collectionPath(input.collection)}/documents`, | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), document: documentSchema }), | ||
| input: z8.object({ collection: z8.string(), document: documentSchema }), | ||
| execute: async (client, input) => api(client).post( | ||
@@ -759,3 +885,3 @@ `${collectionPath(input.collection)}/documents`, | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), id: z7.string() }), | ||
| input: z8.object({ collection: z8.string(), id: z8.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
@@ -769,3 +895,3 @@ `${collectionPath(input.collection)}/documents/${enc(input.id)}` | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), ids: idsSchema }), | ||
| input: z8.object({ collection: z8.string(), ids: idsSchema }), | ||
| execute: async (client, input) => { | ||
@@ -786,5 +912,5 @@ const request = api(client); | ||
| category: "documents", | ||
| input: z7.object({ | ||
| collection: z7.string(), | ||
| id: z7.string(), | ||
| input: z8.object({ | ||
| collection: z8.string(), | ||
| id: z8.string(), | ||
| document: documentSchema | ||
@@ -801,3 +927,3 @@ }), | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), id: z7.string() }), | ||
| input: z8.object({ collection: z8.string(), id: z8.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
@@ -811,6 +937,6 @@ `${collectionPath(input.collection)}/documents/${enc(input.id)}` | ||
| category: "documents", | ||
| input: z7.object({ | ||
| collection: z7.string(), | ||
| documents: z7.union([z7.string(), z7.array(documentSchema)]), | ||
| action: z7.enum(["create", "upsert", "update", "emplace"]).optional() | ||
| input: z8.object({ | ||
| collection: z8.string(), | ||
| documents: z8.union([z8.string(), z8.array(documentSchema)]), | ||
| action: z8.enum(["create", "upsert", "update", "emplace"]).optional() | ||
| }), | ||
@@ -827,4 +953,4 @@ execute: async (client, input) => api(client).post( | ||
| category: "documents", | ||
| input: z7.object({ | ||
| collection: z7.string(), | ||
| input: z8.object({ | ||
| collection: z8.string(), | ||
| params: searchParams.optional() | ||
@@ -841,3 +967,3 @@ }), | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), params: searchParams }), | ||
| input: z8.object({ collection: z8.string(), params: searchParams }), | ||
| execute: async (client, input) => api(client).get( | ||
@@ -851,3 +977,3 @@ `${collectionPath(input.collection)}/documents/search`, | ||
| // ../core/src/operations/keys.ts | ||
| import { z as z8 } from "zod"; | ||
| import { z as z9 } from "zod"; | ||
| var keysOperations = [ | ||
@@ -858,3 +984,3 @@ { | ||
| category: "keys", | ||
| input: z8.object({}), | ||
| input: z9.object({}), | ||
| execute: async (client) => api(client).get("/keys") | ||
@@ -866,3 +992,3 @@ }, | ||
| category: "keys", | ||
| input: z8.object({ value: z8.record(z8.unknown()) }), | ||
| input: z9.object({ value: z9.record(z9.unknown()) }), | ||
| execute: async (client, input) => api(client).post("/keys", input.value) | ||
@@ -874,3 +1000,3 @@ }, | ||
| category: "keys", | ||
| input: z8.object({ id: z8.union([z8.string(), z8.number()]) }), | ||
| input: z9.object({ id: z9.union([z9.string(), z9.number()]) }), | ||
| execute: async (client, input) => api(client).get(`/keys/${enc(String(input.id))}`) | ||
@@ -882,3 +1008,3 @@ }, | ||
| category: "keys", | ||
| input: z8.object({ id: z8.union([z8.string(), z8.number()]) }), | ||
| input: z9.object({ id: z9.union([z9.string(), z9.number()]) }), | ||
| execute: async (client, input) => api(client).delete(`/keys/${enc(String(input.id))}`) | ||
@@ -888,4 +1014,68 @@ } | ||
| // ../core/src/operations/nl-search-models.ts | ||
| import { z as z10 } from "zod"; | ||
| var modelConfigSchema = z10.object({ | ||
| id: z10.string().optional(), | ||
| model_name: z10.string().optional(), | ||
| api_key: z10.string().optional(), | ||
| api_url: z10.string().url().optional(), | ||
| max_bytes: z10.number().int().positive().optional(), | ||
| temperature: z10.number().optional(), | ||
| system_prompt: z10.string().optional(), | ||
| top_p: z10.number().optional(), | ||
| top_k: z10.number().int().optional(), | ||
| stop_sequences: z10.array(z10.string()).optional(), | ||
| api_version: z10.string().optional(), | ||
| project_id: z10.string().optional(), | ||
| access_token: z10.string().optional(), | ||
| refresh_token: z10.string().optional(), | ||
| client_id: z10.string().optional(), | ||
| client_secret: z10.string().optional(), | ||
| region: z10.string().optional(), | ||
| max_output_tokens: z10.number().int().positive().optional(), | ||
| account_id: z10.string().optional() | ||
| }).passthrough(); | ||
| function modelPath(id) { | ||
| return `/nl_search_models/${enc(id)}`; | ||
| } | ||
| var nlSearchModelOperations = [ | ||
| { | ||
| name: "nl_search_models.list", | ||
| summary: "List natural language search models", | ||
| category: "nl_search_models", | ||
| input: z10.object({}), | ||
| execute: async (client) => api(client).get("/nl_search_models") | ||
| }, | ||
| { | ||
| name: "nl_search_models.create", | ||
| summary: "Create a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ value: modelConfigSchema }), | ||
| execute: async (client, input) => api(client).post("/nl_search_models", input.value) | ||
| }, | ||
| { | ||
| name: "nl_search_models.retrieve", | ||
| summary: "Retrieve a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ id: z10.string().min(1) }), | ||
| execute: async (client, input) => api(client).get(modelPath(input.id)) | ||
| }, | ||
| { | ||
| name: "nl_search_models.update", | ||
| summary: "Update a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ id: z10.string().min(1), value: modelConfigSchema }), | ||
| execute: async (client, input) => api(client).put(modelPath(input.id), input.value) | ||
| }, | ||
| { | ||
| name: "nl_search_models.delete", | ||
| summary: "Delete a natural language search model", | ||
| category: "nl_search_models", | ||
| input: z10.object({ id: z10.string().min(1) }), | ||
| execute: async (client, input) => api(client).delete(modelPath(input.id)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/overrides.ts | ||
| import { z as z9 } from "zod"; | ||
| import { z as z11 } from "zod"; | ||
| var overridesOperations = [ | ||
@@ -896,3 +1086,3 @@ { | ||
| category: "overrides", | ||
| input: z9.object({ collection: z9.string() }), | ||
| input: z11.object({ collection: z11.string() }), | ||
| execute: async (client, input) => api(client).get(`${collectionPath(input.collection)}/overrides`) | ||
@@ -904,6 +1094,6 @@ }, | ||
| category: "overrides", | ||
| input: z9.object({ | ||
| collection: z9.string(), | ||
| name: z9.string(), | ||
| value: z9.record(z9.unknown()) | ||
| input: z11.object({ | ||
| collection: z11.string(), | ||
| name: z11.string(), | ||
| value: z11.record(z11.unknown()) | ||
| }), | ||
@@ -919,3 +1109,3 @@ execute: async (client, input) => api(client).put( | ||
| category: "overrides", | ||
| input: z9.object({ collection: z9.string(), name: z9.string() }), | ||
| input: z11.object({ collection: z11.string(), name: z11.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
@@ -929,3 +1119,3 @@ `${collectionPath(input.collection)}/overrides/${enc(input.name)}` | ||
| category: "overrides", | ||
| input: z9.object({ collection: z9.string(), name: z9.string() }), | ||
| input: z11.object({ collection: z11.string(), name: z11.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
@@ -938,3 +1128,3 @@ `${collectionPath(input.collection)}/overrides/${enc(input.name)}` | ||
| // ../core/src/operations/presets.ts | ||
| import { z as z10 } from "zod"; | ||
| import { z as z12 } from "zod"; | ||
| var presetsOperations = [ | ||
@@ -945,3 +1135,3 @@ { | ||
| category: "presets", | ||
| input: z10.object({}), | ||
| input: z12.object({}), | ||
| execute: async (client) => api(client).get("/presets") | ||
@@ -953,5 +1143,5 @@ }, | ||
| category: "presets", | ||
| input: z10.object({ | ||
| name: z10.string(), | ||
| value: z10.record(z10.unknown()) | ||
| input: z12.object({ | ||
| name: z12.string(), | ||
| value: z12.record(z12.unknown()) | ||
| }), | ||
@@ -966,3 +1156,3 @@ execute: async (client, input) => api(client).put(`/presets/${enc(input.name)}`, { | ||
| category: "presets", | ||
| input: z10.object({ name: z10.string() }), | ||
| input: z12.object({ name: z12.string() }), | ||
| execute: async (client, input) => api(client).get(`/presets/${enc(input.name)}`) | ||
@@ -974,3 +1164,3 @@ }, | ||
| category: "presets", | ||
| input: z10.object({ name: z10.string() }), | ||
| input: z12.object({ name: z12.string() }), | ||
| execute: async (client, input) => api(client).delete(`/presets/${enc(input.name)}`) | ||
@@ -981,5 +1171,5 @@ } | ||
| // ../core/src/operations/search.ts | ||
| import { z as z11 } from "zod"; | ||
| var searchParams2 = z11.record(z11.unknown()); | ||
| var facetBySchema = z11.union([z11.string().min(1), z11.array(z11.string().min(1))]); | ||
| import { z as z13 } from "zod"; | ||
| var searchParams2 = z13.record(z13.unknown()); | ||
| var facetBySchema = z13.union([z13.string().min(1), z13.array(z13.string().min(1))]); | ||
| function withoutUndefined(params) { | ||
@@ -995,3 +1185,3 @@ return Object.fromEntries( | ||
| category: "search", | ||
| input: z11.object({ collection: z11.string(), params: searchParams2 }), | ||
| input: z13.object({ collection: z13.string(), params: searchParams2 }), | ||
| execute: async (client, input) => api(client).get( | ||
@@ -1006,4 +1196,4 @@ `${collectionPath(input.collection)}/documents/search`, | ||
| category: "search", | ||
| input: z11.object({ | ||
| searches: z11.array(searchParams2), | ||
| input: z13.object({ | ||
| searches: z13.array(searchParams2), | ||
| commonParams: searchParams2.optional() | ||
@@ -1021,10 +1211,10 @@ }), | ||
| category: "search", | ||
| input: z11.object({ | ||
| collection: z11.string(), | ||
| input: z13.object({ | ||
| collection: z13.string(), | ||
| facetBy: facetBySchema, | ||
| q: z11.string().optional().default("*"), | ||
| queryBy: z11.string().optional(), | ||
| filterBy: z11.string().optional(), | ||
| maxFacetValues: z11.number().int().positive().optional(), | ||
| perPage: z11.number().int().nonnegative().optional().default(0) | ||
| q: z13.string().optional().default("*"), | ||
| queryBy: z13.string().optional(), | ||
| filterBy: z13.string().optional(), | ||
| maxFacetValues: z13.number().int().positive().optional(), | ||
| perPage: z13.number().int().nonnegative().optional().default(0) | ||
| }), | ||
@@ -1047,10 +1237,10 @@ execute: async (client, input) => api(client).get( | ||
| category: "search", | ||
| input: z11.object({ | ||
| collection: z11.string(), | ||
| q: z11.string(), | ||
| queryBy: z11.string(), | ||
| filterBy: z11.string().optional(), | ||
| includeFields: z11.union([z11.string(), z11.array(z11.string())]).optional(), | ||
| limit: z11.number().int().positive().max(50).optional().default(5), | ||
| prefix: z11.boolean().optional().default(true) | ||
| input: z13.object({ | ||
| collection: z13.string(), | ||
| q: z13.string(), | ||
| queryBy: z13.string(), | ||
| filterBy: z13.string().optional(), | ||
| includeFields: z13.union([z13.string(), z13.array(z13.string())]).optional(), | ||
| limit: z13.number().int().positive().max(50).optional().default(5), | ||
| prefix: z13.boolean().optional().default(true) | ||
| }), | ||
@@ -1071,4 +1261,43 @@ execute: async (client, input) => api(client).get( | ||
| // ../core/src/operations/stemming.ts | ||
| import { z as z14 } from "zod"; | ||
| var wordMappingSchema = z14.object({ | ||
| word: z14.string().min(1), | ||
| root: z14.string().min(1) | ||
| }); | ||
| var stemmingOperations = [ | ||
| { | ||
| name: "stemming.dictionaries.list", | ||
| summary: "List stemming dictionaries", | ||
| category: "stemming", | ||
| input: z14.object({}), | ||
| execute: async (client) => api(client).get("/stemming/dictionaries") | ||
| }, | ||
| { | ||
| name: "stemming.dictionaries.retrieve", | ||
| summary: "Retrieve a stemming dictionary", | ||
| category: "stemming", | ||
| input: z14.object({ id: z14.string().min(1) }), | ||
| execute: async (client, input) => api(client).get(`/stemming/dictionaries/${enc(input.id)}`) | ||
| }, | ||
| { | ||
| name: "stemming.dictionaries.import", | ||
| summary: "Import or replace a stemming dictionary from word mappings", | ||
| category: "stemming", | ||
| input: z14.object({ | ||
| id: z14.string().min(1), | ||
| words: z14.union([z14.string().min(1), z14.array(wordMappingSchema).min(1)]) | ||
| }), | ||
| execute: async (client, input) => api(client).post( | ||
| "/stemming/dictionaries/import", | ||
| Array.isArray(input.words) ? input.words.map( | ||
| (mapping) => JSON.stringify(mapping) | ||
| ).join("\n") : input.words, | ||
| { id: input.id } | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/stopwords.ts | ||
| import { z as z12 } from "zod"; | ||
| import { z as z15 } from "zod"; | ||
| var stopwordsOperations = [ | ||
@@ -1079,3 +1308,3 @@ { | ||
| category: "stopwords", | ||
| input: z12.object({}), | ||
| input: z15.object({}), | ||
| execute: async (client) => api(client).get("/stopwords") | ||
@@ -1087,5 +1316,5 @@ }, | ||
| category: "stopwords", | ||
| input: z12.object({ | ||
| name: z12.string(), | ||
| value: z12.record(z12.unknown()) | ||
| input: z15.object({ | ||
| name: z15.string(), | ||
| value: z15.record(z15.unknown()) | ||
| }), | ||
@@ -1098,3 +1327,3 @@ execute: async (client, input) => api(client).put(`/stopwords/${enc(input.name)}`, input.value) | ||
| category: "stopwords", | ||
| input: z12.object({ name: z12.string() }), | ||
| input: z15.object({ name: z15.string() }), | ||
| execute: async (client, input) => api(client).get(`/stopwords/${enc(input.name)}`) | ||
@@ -1106,3 +1335,3 @@ }, | ||
| category: "stopwords", | ||
| input: z12.object({ name: z12.string() }), | ||
| input: z15.object({ name: z15.string() }), | ||
| execute: async (client, input) => api(client).delete(`/stopwords/${enc(input.name)}`) | ||
@@ -1113,8 +1342,8 @@ } | ||
| // ../core/src/operations/synonym-sets.ts | ||
| import { z as z13 } from "zod"; | ||
| function base(name) { | ||
| import { z as z16 } from "zod"; | ||
| function base2(name) { | ||
| return name ? `/synonym_sets/${enc(name)}` : "/synonym_sets"; | ||
| } | ||
| function itemPath(name, id) { | ||
| const path = `${base(name)}/items`; | ||
| function itemPath2(name, id) { | ||
| const path = `${base2(name)}/items`; | ||
| return id ? `${path}/${enc(id)}` : path; | ||
@@ -1127,4 +1356,4 @@ } | ||
| category: "synonyms", | ||
| input: z13.object({}), | ||
| execute: async (client) => api(client).get(base()) | ||
| input: z16.object({}), | ||
| execute: async (client) => api(client).get(base2()) | ||
| }, | ||
@@ -1135,9 +1364,9 @@ { | ||
| category: "synonyms", | ||
| input: z13.object({ | ||
| name: z13.string(), | ||
| value: z13.object({ | ||
| items: z13.array(z13.record(z13.unknown())) | ||
| input: z16.object({ | ||
| name: z16.string(), | ||
| value: z16.object({ | ||
| items: z16.array(z16.record(z16.unknown())) | ||
| }) | ||
| }), | ||
| execute: async (client, input) => api(client).put(base(input.name), input.value) | ||
| execute: async (client, input) => api(client).put(base2(input.name), input.value) | ||
| }, | ||
@@ -1148,4 +1377,4 @@ { | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string() }), | ||
| execute: async (client, input) => api(client).get(base(input.name)) | ||
| input: z16.object({ name: z16.string() }), | ||
| execute: async (client, input) => api(client).get(base2(input.name)) | ||
| }, | ||
@@ -1156,4 +1385,4 @@ { | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string() }), | ||
| execute: async (client, input) => api(client).delete(base(input.name)) | ||
| input: z16.object({ name: z16.string() }), | ||
| execute: async (client, input) => api(client).delete(base2(input.name)) | ||
| }, | ||
@@ -1164,4 +1393,4 @@ { | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name)) | ||
| input: z16.object({ name: z16.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath2(input.name)) | ||
| }, | ||
@@ -1172,8 +1401,8 @@ { | ||
| category: "synonyms", | ||
| input: z13.object({ | ||
| name: z13.string(), | ||
| id: z13.string(), | ||
| value: z13.record(z13.unknown()) | ||
| input: z16.object({ | ||
| name: z16.string(), | ||
| id: z16.string(), | ||
| value: z16.record(z16.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(itemPath(input.name, input.id), input.value) | ||
| execute: async (client, input) => api(client).put(itemPath2(input.name, input.id), input.value) | ||
| }, | ||
@@ -1184,4 +1413,4 @@ { | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string(), id: z13.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name, input.id)) | ||
| input: z16.object({ name: z16.string(), id: z16.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath2(input.name, input.id)) | ||
| }, | ||
@@ -1192,4 +1421,4 @@ { | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string(), id: z13.string() }), | ||
| execute: async (client, input) => api(client).delete(itemPath(input.name, input.id)) | ||
| input: z16.object({ name: z16.string(), id: z16.string() }), | ||
| execute: async (client, input) => api(client).delete(itemPath2(input.name, input.id)) | ||
| } | ||
@@ -1199,3 +1428,3 @@ ]; | ||
| // ../core/src/operations/synonyms.ts | ||
| import { z as z14 } from "zod"; | ||
| import { z as z17 } from "zod"; | ||
| function isNotFound(error) { | ||
@@ -1224,3 +1453,3 @@ if (typeof error !== "object" || error === null) return false; | ||
| category: "synonyms", | ||
| input: z14.object({ collection: z14.string() }), | ||
| input: z17.object({ collection: z17.string() }), | ||
| execute: async (client, input) => { | ||
@@ -1247,6 +1476,6 @@ const request = api(client); | ||
| category: "synonyms", | ||
| input: z14.object({ | ||
| collection: z14.string(), | ||
| name: z14.string(), | ||
| value: z14.record(z14.unknown()) | ||
| input: z17.object({ | ||
| collection: z17.string(), | ||
| name: z17.string(), | ||
| value: z17.record(z17.unknown()) | ||
| }), | ||
@@ -1262,3 +1491,3 @@ execute: async (client, input) => api(client).put( | ||
| category: "synonyms", | ||
| input: z14.object({ collection: z14.string(), name: z14.string() }), | ||
| input: z17.object({ collection: z17.string(), name: z17.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
@@ -1272,3 +1501,3 @@ `${collectionPath(input.collection)}/synonyms/${enc(input.name)}` | ||
| category: "synonyms", | ||
| input: z14.object({ collection: z14.string(), name: z14.string() }), | ||
| input: z17.object({ collection: z17.string(), name: z17.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
@@ -1281,9 +1510,55 @@ `${collectionPath(input.collection)}/synonyms/${enc(input.name)}` | ||
| // ../core/src/operations/system.ts | ||
| import { z as z15 } from "zod"; | ||
| import { z as z18 } from "zod"; | ||
| var systemOperations = [ | ||
| { | ||
| name: "operations.schema_changes", | ||
| summary: "List in-progress collection schema changes", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/operations/schema_changes") | ||
| }, | ||
| { | ||
| name: "operations.snapshot", | ||
| summary: "Create a point-in-time server snapshot", | ||
| category: "system", | ||
| input: z18.object({ snapshotPath: z18.string().min(1) }), | ||
| execute: async (client, input) => api(client).post("/operations/snapshot", void 0, { | ||
| snapshot_path: input.snapshotPath | ||
| }) | ||
| }, | ||
| { | ||
| name: "operations.vote", | ||
| summary: "Trigger leader re-election on a follower node", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).post("/operations/vote") | ||
| }, | ||
| { | ||
| name: "operations.cache.clear", | ||
| summary: "Clear cached search responses", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).post("/operations/cache/clear") | ||
| }, | ||
| { | ||
| name: "operations.db.compact", | ||
| summary: "Compact the on-disk Typesense database", | ||
| category: "system", | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).post("/operations/db/compact") | ||
| }, | ||
| { | ||
| name: "operations.slow_requests.configure", | ||
| summary: "Configure the slow-request logging threshold", | ||
| category: "system", | ||
| input: z18.object({ thresholdMs: z18.number().int().min(-1) }), | ||
| execute: async (client, input) => api(client).post("/config", { | ||
| "log-slow-requests-time-ms": input.thresholdMs | ||
| }) | ||
| }, | ||
| { | ||
| name: "health", | ||
| summary: "Check Typesense cluster health", | ||
| category: "system", | ||
| input: z15.object({}), | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/health") | ||
@@ -1295,3 +1570,3 @@ }, | ||
| category: "system", | ||
| input: z15.object({}), | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/metrics.json") | ||
@@ -1303,3 +1578,3 @@ }, | ||
| category: "system", | ||
| input: z15.object({}), | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/stats.json") | ||
@@ -1311,3 +1586,3 @@ }, | ||
| category: "system", | ||
| input: z15.object({}), | ||
| input: z18.object({}), | ||
| execute: async (client) => api(client).get("/debug") | ||
@@ -1325,2 +1600,3 @@ } | ||
| ...synonymSetOperations, | ||
| ...curationSetOperations, | ||
| ...overridesOperations, | ||
@@ -1331,3 +1607,5 @@ ...keysOperations, | ||
| ...stopwordsOperations, | ||
| ...stemmingOperations, | ||
| ...conversationOperations, | ||
| ...nlSearchModelOperations, | ||
| ...apiOperations, | ||
@@ -1340,3 +1618,3 @@ ...systemOperations | ||
| name: "@typesensekit/mcp", | ||
| version: "1.1.3", | ||
| version: "1.2.0", | ||
| type: "module", | ||
@@ -1403,2 +1681,6 @@ main: "dist/server.js", | ||
| "aliases.retrieve", | ||
| "analytics.events.list", | ||
| "analytics.rules.list", | ||
| "analytics.rules.retrieve", | ||
| "analytics.status", | ||
| "collections.list", | ||
@@ -1410,2 +1692,6 @@ "collections.retrieve", | ||
| "conversations.models.retrieve", | ||
| "curation_sets.items.list", | ||
| "curation_sets.items.retrieve", | ||
| "curation_sets.list", | ||
| "curation_sets.retrieve", | ||
| "debug", | ||
@@ -1419,4 +1705,7 @@ "documents.export", | ||
| "multi_search", | ||
| "nl_search_models.list", | ||
| "nl_search_models.retrieve", | ||
| "overrides.list", | ||
| "overrides.retrieve", | ||
| "operations.schema_changes", | ||
| "presets.list", | ||
@@ -1428,2 +1717,4 @@ "presets.retrieve", | ||
| "stats", | ||
| "stemming.dictionaries.list", | ||
| "stemming.dictionaries.retrieve", | ||
| "stopwords.list", | ||
@@ -1430,0 +1721,0 @@ "stopwords.retrieve", |
+1
-1
| { | ||
| "name": "@typesensekit/mcp", | ||
| "version": "1.1.3", | ||
| "version": "1.2.0", | ||
| "type": "module", | ||
@@ -5,0 +5,0 @@ "main": "dist/server.js", |
| #!/usr/bin/env node | ||
| // src/server.ts | ||
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| // ../core/src/client.ts | ||
| import Typesense from "typesense"; | ||
| // ../core/src/config.ts | ||
| import { z } from "zod"; | ||
| var nodeConfigSchema = z.object({ | ||
| host: z.string().min(1), | ||
| port: z.number().int().positive().optional(), | ||
| protocol: z.enum(["http", "https"]).optional(), | ||
| path: z.string().optional() | ||
| }); | ||
| var serverConfigSchema = z.object({ | ||
| url: z.string().url(), | ||
| apiKey: z.string().min(1), | ||
| connectionTimeoutSeconds: z.number().positive().optional(), | ||
| nearestNode: nodeConfigSchema.optional(), | ||
| numRetries: z.number().int().nonnegative().optional(), | ||
| retryIntervalSeconds: z.number().positive().optional(), | ||
| healthcheckIntervalSeconds: z.number().positive().optional() | ||
| }); | ||
| // ../core/src/client.ts | ||
| function nodeFromUrl(url) { | ||
| const parsed = new URL(url); | ||
| const node = { | ||
| host: parsed.hostname, | ||
| port: parsed.port ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : 80, | ||
| protocol: parsed.protocol.replace(":", "") | ||
| }; | ||
| if (parsed.pathname !== "/") node.path = parsed.pathname; | ||
| return node; | ||
| } | ||
| function normalizeNearestNode(node) { | ||
| if (!node) return void 0; | ||
| return { | ||
| host: node.host, | ||
| port: node.port ?? (node.protocol === "http" ? 80 : 443), | ||
| protocol: node.protocol ?? "https", | ||
| path: node.path | ||
| }; | ||
| } | ||
| function createClient(config) { | ||
| const parsed = serverConfigSchema.parse(config); | ||
| const clientConfig = { | ||
| nodes: [nodeFromUrl(parsed.url)], | ||
| apiKey: parsed.apiKey, | ||
| connectionTimeoutSeconds: parsed.connectionTimeoutSeconds, | ||
| nearestNode: normalizeNearestNode(parsed.nearestNode), | ||
| numRetries: parsed.numRetries, | ||
| retryIntervalSeconds: parsed.retryIntervalSeconds, | ||
| healthcheckIntervalSeconds: parsed.healthcheckIntervalSeconds | ||
| }; | ||
| return new Typesense.Client(clientConfig); | ||
| } | ||
| // ../core/src/redaction.ts | ||
| var REDACTED = "[REDACTED]"; | ||
| var CIRCULAR = "[Circular]"; | ||
| var SECRET_KEYS = /* @__PURE__ */ new Set([ | ||
| "api_key", | ||
| "apikey", | ||
| "authorization", | ||
| "cookie", | ||
| "secret", | ||
| "setcookie", | ||
| "token", | ||
| "xtypesenseapikey" | ||
| ]); | ||
| function shouldRedactKey(key) { | ||
| const normalized = key.toLowerCase().replace(/[-_\s]/g, ""); | ||
| return SECRET_KEYS.has(normalized) || normalized.endsWith("apikey"); | ||
| } | ||
| function isTypesenseApiKeyShape(value) { | ||
| return Array.isArray(value.actions) && Array.isArray(value.collections); | ||
| } | ||
| function redactText(value) { | ||
| return value.replace( | ||
| /(["']?authorization["']?\s*[:=]\s*)(["']?)(?:Bearer|Basic)?\s*[-A-Za-z0-9._~+/=]+(["']?)/gi, | ||
| (_match, prefix, openQuote) => `${prefix}${openQuote}${REDACTED}${openQuote}` | ||
| ).replace( | ||
| /(["']?(?:x-typesense-api-key|api[_-]?key|apikey|token|secret|cookie|set-cookie)["']?\s*[:=]\s*)(["']?)([^"',\s}\]]+)(["']?)/gi, | ||
| (_match, prefix, openQuote, _secret) => `${prefix}${openQuote}${REDACTED}${openQuote}` | ||
| ).replace(/\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/gi, `$1 ${REDACTED}`); | ||
| } | ||
| function redactError(error, seen) { | ||
| const output = {}; | ||
| for (const key of Object.getOwnPropertyNames(error)) { | ||
| output[key] = redactValue( | ||
| error[key], | ||
| seen | ||
| ); | ||
| } | ||
| if (!("name" in output)) output.name = error.name; | ||
| if (!("message" in output)) output.message = redactText(error.message); | ||
| return output; | ||
| } | ||
| function redactValue(value, seen) { | ||
| if (typeof value === "string") return redactText(value); | ||
| if (Array.isArray(value)) { | ||
| return value.map((item) => redactValue(item, seen)); | ||
| } | ||
| if (typeof value !== "object" || value === null) { | ||
| return value; | ||
| } | ||
| if (seen.has(value)) return CIRCULAR; | ||
| seen.add(value); | ||
| if (value instanceof Error) { | ||
| return redactError(value, seen); | ||
| } | ||
| const record = value; | ||
| return Object.fromEntries( | ||
| Object.entries(record).map(([key, child]) => [ | ||
| key, | ||
| shouldRedactKey(key) || key === "value" && isTypesenseApiKeyShape(record) ? REDACTED : redactValue(child, seen) | ||
| ]) | ||
| ); | ||
| } | ||
| function redactSecrets(value) { | ||
| return redactValue(value, /* @__PURE__ */ new WeakSet()); | ||
| } | ||
| // ../core/src/errors.ts | ||
| var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([ | ||
| "EAI_AGAIN", | ||
| "ECONNABORTED", | ||
| "ECONNREFUSED", | ||
| "ECONNRESET", | ||
| "ENOTFOUND", | ||
| "ETIMEDOUT" | ||
| ]); | ||
| function readErrorLike(error) { | ||
| return typeof error === "object" && error !== null ? error : {}; | ||
| } | ||
| function findNetworkErrorCode(error) { | ||
| const errorLike = readErrorLike(error); | ||
| if (typeof errorLike.code === "string" && NETWORK_ERROR_CODES.has(errorLike.code.toUpperCase())) { | ||
| return errorLike.code.toUpperCase(); | ||
| } | ||
| if (typeof errorLike.message === "string") { | ||
| const match = errorLike.message.match( | ||
| /\b(EAI_AGAIN|ECONNABORTED|ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT)\b/i | ||
| ); | ||
| if (match?.[1]) return match[1].toUpperCase(); | ||
| } | ||
| return errorLike.cause === void 0 ? void 0 : findNetworkErrorCode(errorLike.cause); | ||
| } | ||
| function endpointLabel(error) { | ||
| const errorLike = readErrorLike(error); | ||
| const host = typeof errorLike.hostname === "string" ? errorLike.hostname : typeof errorLike.host === "string" ? errorLike.host : typeof errorLike.address === "string" ? errorLike.address : void 0; | ||
| const port = typeof errorLike.port === "number" || typeof errorLike.port === "string" ? String(errorLike.port) : void 0; | ||
| if (host && port) return `${host}:${port}`; | ||
| if (host) return host; | ||
| return errorLike.cause === void 0 ? void 0 : endpointLabel(errorLike.cause); | ||
| } | ||
| function conciseNetworkErrorMessage(error) { | ||
| const code = findNetworkErrorCode(error); | ||
| if (!code) return void 0; | ||
| const endpoint = endpointLabel(error); | ||
| return `Request failed: ${code}${endpoint ? ` ${endpoint}` : ""}`; | ||
| } | ||
| function normalizeTypesenseError(error) { | ||
| if (error instanceof Error) { | ||
| const errorLike = error; | ||
| const status = errorLike.httpStatus ?? errorLike.status; | ||
| return { | ||
| code: typeof status === "number" ? String(status) : error.name || "TypesenseError", | ||
| message: redactText(error.message), | ||
| details: redactSecrets(error) | ||
| }; | ||
| } | ||
| if (typeof error === "object" && error !== null) { | ||
| const errorLike = error; | ||
| return { | ||
| code: typeof errorLike.status === "number" ? String(errorLike.status) : "TypesenseError", | ||
| message: typeof errorLike.message === "string" ? redactText(errorLike.message) : "Unknown Typesense error", | ||
| details: redactSecrets(error) | ||
| }; | ||
| } | ||
| return { code: "TypesenseError", message: redactText(String(error)) }; | ||
| } | ||
| function formatTypesenseErrorMessage(error, options = {}) { | ||
| const normalized = normalizeTypesenseError(error); | ||
| const message = conciseNetworkErrorMessage(error) ?? normalized.message; | ||
| if (!options.debug) return message; | ||
| return [ | ||
| message, | ||
| "", | ||
| "Debug details:", | ||
| JSON.stringify(normalized.details ?? normalized, null, 2) | ||
| ].join("\n"); | ||
| } | ||
| // ../core/src/operations/aliases.ts | ||
| import { z as z2 } from "zod"; | ||
| // ../core/src/operations/http.ts | ||
| function api(client) { | ||
| return client.apiCall; | ||
| } | ||
| function enc(value) { | ||
| return encodeURIComponent(value); | ||
| } | ||
| function collectionPath(collection) { | ||
| return `/collections/${enc(collection)}`; | ||
| } | ||
| // ../core/src/operations/aliases.ts | ||
| var aliasesOperations = [ | ||
| { | ||
| name: "aliases.list", | ||
| summary: "List aliases", | ||
| category: "aliases", | ||
| input: z2.object({}), | ||
| execute: async (client) => api(client).get("/aliases") | ||
| }, | ||
| { | ||
| name: "aliases.create", | ||
| summary: "Create or upsert an alias", | ||
| category: "aliases", | ||
| input: z2.object({ | ||
| name: z2.string(), | ||
| value: z2.object({ collection_name: z2.string() }) | ||
| }), | ||
| execute: async (client, input) => api(client).put(`/aliases/${enc(input.name)}`, input.value) | ||
| }, | ||
| { | ||
| name: "aliases.retrieve", | ||
| summary: "Retrieve an alias", | ||
| category: "aliases", | ||
| input: z2.object({ name: z2.string() }), | ||
| execute: async (client, input) => api(client).get(`/aliases/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "aliases.delete", | ||
| summary: "Delete an alias", | ||
| category: "aliases", | ||
| input: z2.object({ name: z2.string() }), | ||
| execute: async (client, input) => api(client).delete(`/aliases/${enc(input.name)}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/analytics.ts | ||
| import { z as z3 } from "zod"; | ||
| var analyticsOperations = [ | ||
| { | ||
| name: "analytics.rules.list", | ||
| summary: "List analytics rules", | ||
| category: "analytics", | ||
| input: z3.object({}), | ||
| execute: async (client) => api(client).get("/analytics/rules") | ||
| }, | ||
| { | ||
| name: "analytics.rules.upsert", | ||
| summary: "Create or update an analytics rule", | ||
| category: "analytics", | ||
| input: z3.object({ name: z3.string(), value: z3.record(z3.unknown()) }), | ||
| execute: async (client, input) => api(client).put(`/analytics/rules/${enc(input.name)}`, input.value) | ||
| }, | ||
| { | ||
| name: "analytics.rules.delete", | ||
| summary: "Delete an analytics rule", | ||
| category: "analytics", | ||
| input: z3.object({ name: z3.string() }), | ||
| execute: async (client, input) => api(client).delete(`/analytics/rules/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "analytics.events.create", | ||
| summary: "Create an analytics event", | ||
| category: "analytics", | ||
| input: z3.object({ | ||
| type: z3.string(), | ||
| name: z3.string(), | ||
| data: z3.record(z3.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).post("/analytics/events", input) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/api.ts | ||
| import { z as z4 } from "zod"; | ||
| var methodSchema = z4.enum(["get", "post", "put", "patch", "delete"]); | ||
| var normalizedMethodSchema = z4.preprocess( | ||
| (value) => typeof value === "string" ? value.toLowerCase() : value, | ||
| methodSchema | ||
| ); | ||
| var apiOperations = [ | ||
| { | ||
| name: "api.call", | ||
| summary: "Call any Typesense API endpoint not yet covered by a first-class operation", | ||
| category: "api", | ||
| input: z4.object({ | ||
| method: normalizedMethodSchema, | ||
| path: z4.string().startsWith("/"), | ||
| params: z4.record(z4.unknown()).optional(), | ||
| body: z4.unknown().optional() | ||
| }), | ||
| execute: async (client, input) => { | ||
| const request = api(client); | ||
| if (input.method === "get") return request.get(input.path, input.params); | ||
| if (input.method === "delete") | ||
| return request.delete(input.path, input.params); | ||
| if (input.method === "post") | ||
| return request.post(input.path, input.body, input.params); | ||
| if (input.method === "put") | ||
| return request.put(input.path, input.body, input.params); | ||
| return request.patch(input.path, input.body, input.params); | ||
| } | ||
| } | ||
| ]; | ||
| // ../core/src/operations/collections.ts | ||
| import { z as z5 } from "zod"; | ||
| var DEFAULT_WAIT_TIMEOUT_MS = 3e4; | ||
| var DEFAULT_WAIT_INTERVAL_MS = 1e3; | ||
| var baseFieldSchema = z5.object({ | ||
| name: z5.string(), | ||
| facet: z5.boolean().optional(), | ||
| index: z5.boolean().optional(), | ||
| optional: z5.boolean().optional(), | ||
| sort: z5.boolean().optional(), | ||
| locale: z5.string().optional(), | ||
| infix: z5.boolean().optional(), | ||
| stem: z5.boolean().optional() | ||
| }).passthrough(); | ||
| var createFieldSchema = baseFieldSchema.extend({ | ||
| type: z5.string() | ||
| }); | ||
| var patchFieldSchema = baseFieldSchema.extend({ | ||
| type: z5.string().optional(), | ||
| drop: z5.boolean().optional() | ||
| }); | ||
| var fieldLifecycleInputSchema = z5.object({ | ||
| collection: z5.string(), | ||
| field: z5.string().optional(), | ||
| yes: z5.boolean().optional(), | ||
| numDim: z5.coerce.number().int().positive().optional(), | ||
| vecDist: z5.string().optional(), | ||
| hnswM: z5.coerce.number().int().positive().optional(), | ||
| hnswEfConstruction: z5.coerce.number().int().positive().optional(), | ||
| embedFrom: z5.union([z5.string(), z5.array(z5.string())]).optional(), | ||
| embedModel: z5.string().optional(), | ||
| embedApiKey: z5.string().optional(), | ||
| timeoutMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_TIMEOUT_MS), | ||
| intervalMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_INTERVAL_MS) | ||
| }).passthrough(); | ||
| var waitInputSchema = z5.object({ | ||
| collection: z5.string(), | ||
| fieldPresent: z5.string().optional(), | ||
| fieldMissing: z5.string().optional(), | ||
| fieldEmbedFrom: z5.string().optional(), | ||
| timeoutMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_TIMEOUT_MS), | ||
| intervalMs: z5.coerce.number().int().nonnegative().default(DEFAULT_WAIT_INTERVAL_MS) | ||
| }); | ||
| var FIELD_LIFECYCLE_KEYS = /* @__PURE__ */ new Set([ | ||
| "collection", | ||
| "field", | ||
| "yes", | ||
| "numDim", | ||
| "vecDist", | ||
| "hnswM", | ||
| "hnswEfConstruction", | ||
| "embedFrom", | ||
| "embedModel", | ||
| "embedApiKey", | ||
| "timeoutMs", | ||
| "intervalMs" | ||
| ]); | ||
| function sleep(ms) { | ||
| return new Promise((resolve) => setTimeout(resolve, ms)); | ||
| } | ||
| function isObject(value) { | ||
| return typeof value === "object" && value !== null && !Array.isArray(value); | ||
| } | ||
| function requestedFieldName(input) { | ||
| const name = input.field ?? input.name; | ||
| if (typeof name !== "string" || !name) { | ||
| throw new Error("A field name is required. Pass --field or include name."); | ||
| } | ||
| return name; | ||
| } | ||
| function requiresConfirmation(collection) { | ||
| return /^production(?:__|-|$)/i.test(collection) || /^prod(?:__|-|$)/i.test(collection); | ||
| } | ||
| function assertDestructiveConfirmed(input) { | ||
| if (requiresConfirmation(input.collection) && !input.yes) { | ||
| throw new Error( | ||
| `Refusing to modify production collection ${input.collection} without --yes.` | ||
| ); | ||
| } | ||
| } | ||
| function findField(collection, fieldName) { | ||
| return collection.fields?.find((field) => { | ||
| if (!isObject(field)) return false; | ||
| return field.name === fieldName; | ||
| }); | ||
| } | ||
| async function retrieveCollection(client, collection) { | ||
| return api(client).get(collectionPath(collection)); | ||
| } | ||
| function buildFieldDefinition(input) { | ||
| const field = Object.fromEntries( | ||
| Object.entries(input).filter( | ||
| ([key, value]) => value !== void 0 && !FIELD_LIFECYCLE_KEYS.has(key) | ||
| ) | ||
| ); | ||
| field.name = requestedFieldName(input); | ||
| if (input.numDim !== void 0) field.num_dim = input.numDim; | ||
| if (input.vecDist !== void 0) field.vec_dist = input.vecDist; | ||
| if (input.hnswM !== void 0 || input.hnswEfConstruction !== void 0) { | ||
| const hnswParams = isObject(field.hnsw_params) ? field.hnsw_params : {}; | ||
| if (input.hnswM !== void 0) hnswParams.M = input.hnswM; | ||
| if (input.hnswEfConstruction !== void 0) { | ||
| hnswParams.ef_construction = input.hnswEfConstruction; | ||
| } | ||
| field.hnsw_params = hnswParams; | ||
| } | ||
| if (input.embedFrom !== void 0 || input.embedModel !== void 0 || input.embedApiKey !== void 0) { | ||
| const embed = isObject(field.embed) ? field.embed : {}; | ||
| const modelConfig = isObject(embed.model_config) ? embed.model_config : {}; | ||
| if (input.embedFrom !== void 0) { | ||
| embed.from = Array.isArray(input.embedFrom) ? input.embedFrom : [input.embedFrom]; | ||
| } | ||
| if (input.embedModel !== void 0) | ||
| modelConfig.model_name = input.embedModel; | ||
| if (input.embedApiKey !== void 0) | ||
| modelConfig.api_key = input.embedApiKey; | ||
| embed.model_config = modelConfig; | ||
| field.embed = embed; | ||
| } | ||
| if (typeof field.type !== "string" || !field.type) { | ||
| throw new Error("A field type is required. Pass --type or include type."); | ||
| } | ||
| return field; | ||
| } | ||
| function parseEmbedFromCondition(condition) { | ||
| const separator = condition.indexOf(":"); | ||
| if (separator === -1) { | ||
| throw new Error("--field-embed-from must use FIELD:SOURCE format."); | ||
| } | ||
| return { | ||
| fieldName: condition.slice(0, separator), | ||
| source: condition.slice(separator + 1) | ||
| }; | ||
| } | ||
| function isTransientCollectionUpdateError(error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| return /another collection update operation is in progress/i.test(message) || /timeout of \d+ms exceeded/i.test(message) || /econnaborted/i.test(message); | ||
| } | ||
| function evaluateWaitCondition(collection, input) { | ||
| const conditions = [ | ||
| input.fieldPresent, | ||
| input.fieldMissing, | ||
| input.fieldEmbedFrom | ||
| ].filter(Boolean); | ||
| if (conditions.length !== 1) { | ||
| throw new Error( | ||
| "Pass exactly one wait condition: --field-present, --field-missing, or --field-embed-from." | ||
| ); | ||
| } | ||
| if (input.fieldPresent) { | ||
| return { | ||
| ok: Boolean(findField(collection, input.fieldPresent)), | ||
| condition: "field-present", | ||
| field: input.fieldPresent | ||
| }; | ||
| } | ||
| if (input.fieldMissing) { | ||
| return { | ||
| ok: !findField(collection, input.fieldMissing), | ||
| condition: "field-missing", | ||
| field: input.fieldMissing | ||
| }; | ||
| } | ||
| const { fieldName, source } = parseEmbedFromCondition( | ||
| input.fieldEmbedFrom ?? "" | ||
| ); | ||
| const field = findField(collection, fieldName); | ||
| const from = isObject(field) && isObject(field.embed) && Array.isArray(field.embed.from) ? field.embed.from : []; | ||
| return { | ||
| ok: from.includes(source), | ||
| condition: "field-embed-from", | ||
| field: fieldName, | ||
| source | ||
| }; | ||
| } | ||
| async function waitForCollectionCondition(client, input) { | ||
| const startedAt = Date.now(); | ||
| let lastError; | ||
| let attempts = 0; | ||
| while (Date.now() - startedAt <= input.timeoutMs) { | ||
| attempts += 1; | ||
| try { | ||
| const collection = await retrieveCollection(client, input.collection); | ||
| const result = evaluateWaitCondition(collection, input); | ||
| if (result.ok) { | ||
| return { | ||
| collection: input.collection, | ||
| attempts, | ||
| ...result | ||
| }; | ||
| } | ||
| } catch (error) { | ||
| if (!isTransientCollectionUpdateError(error)) throw error; | ||
| lastError = error; | ||
| } | ||
| await sleep(input.intervalMs); | ||
| } | ||
| const detail = lastError instanceof Error ? ` Last error: ${lastError.message}` : ""; | ||
| throw new Error( | ||
| `Timed out waiting for collection ${input.collection} schema condition.${detail}` | ||
| ); | ||
| } | ||
| async function dropField(client, input) { | ||
| assertDestructiveConfirmed(input); | ||
| const fieldName = requestedFieldName(input); | ||
| const collection = await retrieveCollection(client, input.collection); | ||
| const existingField = findField(collection, fieldName); | ||
| if (!existingField) { | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: fieldName, | ||
| alreadyMissing: true | ||
| }; | ||
| } | ||
| const result = await api(client).patch(collectionPath(input.collection), { | ||
| fields: [{ name: fieldName, drop: true }] | ||
| }); | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: fieldName, | ||
| before: existingField, | ||
| result | ||
| }; | ||
| } | ||
| async function addField(client, input) { | ||
| const field = buildFieldDefinition(input); | ||
| const result = await api(client).patch(collectionPath(input.collection), { | ||
| fields: [field] | ||
| }); | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: field.name, | ||
| added: field, | ||
| result | ||
| }; | ||
| } | ||
| var collectionOperations = [ | ||
| { | ||
| name: "collections.create", | ||
| summary: "Create a collection", | ||
| category: "collections", | ||
| input: z5.object({ | ||
| name: z5.string(), | ||
| fields: z5.array(createFieldSchema), | ||
| default_sorting_field: z5.string().optional(), | ||
| token_separators: z5.array(z5.string()).optional(), | ||
| symbols_to_index: z5.array(z5.string()).optional(), | ||
| enable_nested_fields: z5.boolean().optional() | ||
| }), | ||
| execute: async (client, input) => api(client).post("/collections", input) | ||
| }, | ||
| { | ||
| name: "collections.list", | ||
| summary: "List collections", | ||
| category: "collections", | ||
| input: z5.object({}), | ||
| execute: async (client) => api(client).get("/collections") | ||
| }, | ||
| { | ||
| name: "collections.retrieve", | ||
| summary: "Retrieve a collection", | ||
| category: "collections", | ||
| input: z5.object({ collection: z5.string() }), | ||
| execute: async (client, input) => api(client).get(collectionPath(input.collection)) | ||
| }, | ||
| { | ||
| name: "collections.update", | ||
| summary: "Update a collection schema", | ||
| category: "collections", | ||
| input: z5.object({ | ||
| collection: z5.string(), | ||
| fields: z5.array(patchFieldSchema).optional() | ||
| }), | ||
| execute: async (client, input) => api(client).patch(collectionPath(input.collection), { | ||
| fields: input.fields | ||
| }) | ||
| }, | ||
| { | ||
| name: "collections.wait", | ||
| summary: "Wait for a collection schema condition", | ||
| category: "collections", | ||
| input: waitInputSchema, | ||
| execute: waitForCollectionCondition | ||
| }, | ||
| { | ||
| name: "collections.fields.add", | ||
| summary: "Add a field to a collection", | ||
| category: "collections", | ||
| input: fieldLifecycleInputSchema, | ||
| execute: addField | ||
| }, | ||
| { | ||
| name: "collections.fields.drop", | ||
| summary: "Drop a field from a collection", | ||
| category: "collections", | ||
| input: fieldLifecycleInputSchema, | ||
| execute: dropField | ||
| }, | ||
| { | ||
| name: "collections.fields.replace", | ||
| summary: "Safely replace a collection field", | ||
| category: "collections", | ||
| input: fieldLifecycleInputSchema, | ||
| execute: async (client, input) => { | ||
| const fieldName = requestedFieldName(input); | ||
| const replacement = buildFieldDefinition(input); | ||
| const dropResult = await dropField(client, input); | ||
| await waitForCollectionCondition(client, { | ||
| collection: input.collection, | ||
| fieldMissing: fieldName, | ||
| timeoutMs: input.timeoutMs, | ||
| intervalMs: input.intervalMs | ||
| }); | ||
| try { | ||
| await api(client).patch(collectionPath(input.collection), { | ||
| fields: [replacement] | ||
| }); | ||
| } catch (error) { | ||
| throw new Error( | ||
| [ | ||
| error instanceof Error ? error.message : String(error), | ||
| "", | ||
| "The original field was dropped, but adding the replacement failed.", | ||
| `Recover with: tsk collections.fields.add --collection ${input.collection} --input field.json` | ||
| ].join("\n") | ||
| ); | ||
| } | ||
| const waitResult = await waitForCollectionCondition(client, { | ||
| collection: input.collection, | ||
| fieldPresent: fieldName, | ||
| timeoutMs: input.timeoutMs, | ||
| intervalMs: input.intervalMs | ||
| }); | ||
| const collection = await retrieveCollection(client, input.collection); | ||
| return { | ||
| ok: true, | ||
| collection: input.collection, | ||
| field: fieldName, | ||
| before: "before" in dropResult ? dropResult.before : void 0, | ||
| after: findField(collection, fieldName), | ||
| wait: waitResult | ||
| }; | ||
| } | ||
| }, | ||
| { | ||
| name: "collections.delete", | ||
| summary: "Delete a collection", | ||
| category: "collections", | ||
| input: z5.object({ collection: z5.string() }), | ||
| execute: async (client, input) => api(client).delete(collectionPath(input.collection)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/conversations.ts | ||
| import { z as z6 } from "zod"; | ||
| var conversationOperations = [ | ||
| { | ||
| name: "conversations.models.list", | ||
| summary: "List conversation models", | ||
| category: "conversations", | ||
| input: z6.object({}), | ||
| execute: async (client) => api(client).get("/conversations/models") | ||
| }, | ||
| { | ||
| name: "conversations.models.create", | ||
| summary: "Create a conversation model", | ||
| category: "conversations", | ||
| input: z6.object({ value: z6.record(z6.unknown()) }), | ||
| execute: async (client, input) => api(client).post("/conversations/models", input.value) | ||
| }, | ||
| { | ||
| name: "conversations.models.retrieve", | ||
| summary: "Retrieve a conversation model", | ||
| category: "conversations", | ||
| input: z6.object({ id: z6.string() }), | ||
| execute: async (client, input) => api(client).get(`/conversations/models/${enc(input.id)}`) | ||
| }, | ||
| { | ||
| name: "conversations.models.delete", | ||
| summary: "Delete a conversation model", | ||
| category: "conversations", | ||
| input: z6.object({ id: z6.string() }), | ||
| execute: async (client, input) => api(client).delete(`/conversations/models/${enc(input.id)}`) | ||
| }, | ||
| { | ||
| name: "conversations.history.retrieve", | ||
| summary: "Retrieve conversation history", | ||
| category: "conversations", | ||
| input: z6.object({ conversation_id: z6.string().optional() }), | ||
| execute: async (client, input) => api(client).get( | ||
| "/conversations/history", | ||
| input.conversation_id ? { conversation_id: input.conversation_id } : void 0 | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/documents.ts | ||
| import { z as z7 } from "zod"; | ||
| var documentSchema = z7.record(z7.unknown()); | ||
| var idsSchema = z7.array(z7.string().min(1)).min(1); | ||
| var searchParams = z7.record( | ||
| z7.union([ | ||
| z7.string(), | ||
| z7.number(), | ||
| z7.boolean(), | ||
| z7.array(z7.string()), | ||
| z7.array(z7.number()) | ||
| ]) | ||
| ); | ||
| var documentOperations = [ | ||
| { | ||
| name: "documents.index", | ||
| summary: "Index a document", | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), document: documentSchema }), | ||
| execute: async (client, input) => api(client).post( | ||
| `${collectionPath(input.collection)}/documents`, | ||
| input.document | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.upsert", | ||
| summary: "Upsert a document", | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), document: documentSchema }), | ||
| execute: async (client, input) => api(client).post( | ||
| `${collectionPath(input.collection)}/documents`, | ||
| input.document, | ||
| { action: "upsert" } | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.get", | ||
| summary: "Get a document by id", | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), id: z7.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/${enc(input.id)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.get_many", | ||
| summary: "Get multiple documents by id", | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), ids: idsSchema }), | ||
| execute: async (client, input) => { | ||
| const request = api(client); | ||
| return Promise.all( | ||
| input.ids.map( | ||
| (id) => request.get( | ||
| `${collectionPath(input.collection)}/documents/${enc(id)}` | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
| }, | ||
| { | ||
| name: "documents.update", | ||
| summary: "Update a document by id", | ||
| category: "documents", | ||
| input: z7.object({ | ||
| collection: z7.string(), | ||
| id: z7.string(), | ||
| document: documentSchema | ||
| }), | ||
| execute: async (client, input) => api(client).patch( | ||
| `${collectionPath(input.collection)}/documents/${enc(input.id)}`, | ||
| input.document | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.delete", | ||
| summary: "Delete a document by id", | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), id: z7.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
| `${collectionPath(input.collection)}/documents/${enc(input.id)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.import", | ||
| summary: "Import documents into a collection", | ||
| category: "documents", | ||
| input: z7.object({ | ||
| collection: z7.string(), | ||
| documents: z7.union([z7.string(), z7.array(documentSchema)]), | ||
| action: z7.enum(["create", "upsert", "update", "emplace"]).optional() | ||
| }), | ||
| execute: async (client, input) => api(client).post( | ||
| `${collectionPath(input.collection)}/documents/import`, | ||
| Array.isArray(input.documents) ? input.documents.map((doc) => JSON.stringify(doc)).join("\n") : input.documents, | ||
| input.action ? { action: input.action } : void 0 | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.export", | ||
| summary: "Export documents from a collection", | ||
| category: "documents", | ||
| input: z7.object({ | ||
| collection: z7.string(), | ||
| params: searchParams.optional() | ||
| }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/export`, | ||
| input.params | ||
| ) | ||
| }, | ||
| { | ||
| name: "documents.search", | ||
| summary: "Search within a collection", | ||
| category: "documents", | ||
| input: z7.object({ collection: z7.string(), params: searchParams }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| input.params | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/keys.ts | ||
| import { z as z8 } from "zod"; | ||
| var keysOperations = [ | ||
| { | ||
| name: "keys.list", | ||
| summary: "List API keys", | ||
| category: "keys", | ||
| input: z8.object({}), | ||
| execute: async (client) => api(client).get("/keys") | ||
| }, | ||
| { | ||
| name: "keys.create", | ||
| summary: "Create an API key", | ||
| category: "keys", | ||
| input: z8.object({ value: z8.record(z8.unknown()) }), | ||
| execute: async (client, input) => api(client).post("/keys", input.value) | ||
| }, | ||
| { | ||
| name: "keys.retrieve", | ||
| summary: "Retrieve an API key", | ||
| category: "keys", | ||
| input: z8.object({ id: z8.union([z8.string(), z8.number()]) }), | ||
| execute: async (client, input) => api(client).get(`/keys/${enc(String(input.id))}`) | ||
| }, | ||
| { | ||
| name: "keys.delete", | ||
| summary: "Delete an API key", | ||
| category: "keys", | ||
| input: z8.object({ id: z8.union([z8.string(), z8.number()]) }), | ||
| execute: async (client, input) => api(client).delete(`/keys/${enc(String(input.id))}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/overrides.ts | ||
| import { z as z9 } from "zod"; | ||
| var overridesOperations = [ | ||
| { | ||
| name: "overrides.list", | ||
| summary: "List overrides", | ||
| category: "overrides", | ||
| input: z9.object({ collection: z9.string() }), | ||
| execute: async (client, input) => api(client).get(`${collectionPath(input.collection)}/overrides`) | ||
| }, | ||
| { | ||
| name: "overrides.create", | ||
| summary: "Create or upsert a override", | ||
| category: "overrides", | ||
| input: z9.object({ | ||
| collection: z9.string(), | ||
| name: z9.string(), | ||
| value: z9.record(z9.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put( | ||
| `${collectionPath(input.collection)}/overrides/${enc(input.name)}`, | ||
| input.value | ||
| ) | ||
| }, | ||
| { | ||
| name: "overrides.retrieve", | ||
| summary: "Retrieve a override", | ||
| category: "overrides", | ||
| input: z9.object({ collection: z9.string(), name: z9.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/overrides/${enc(input.name)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "overrides.delete", | ||
| summary: "Delete a override", | ||
| category: "overrides", | ||
| input: z9.object({ collection: z9.string(), name: z9.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
| `${collectionPath(input.collection)}/overrides/${enc(input.name)}` | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/presets.ts | ||
| import { z as z10 } from "zod"; | ||
| var presetsOperations = [ | ||
| { | ||
| name: "presets.list", | ||
| summary: "List presets", | ||
| category: "presets", | ||
| input: z10.object({}), | ||
| execute: async (client) => api(client).get("/presets") | ||
| }, | ||
| { | ||
| name: "presets.create", | ||
| summary: "Create or upsert a preset", | ||
| category: "presets", | ||
| input: z10.object({ | ||
| name: z10.string(), | ||
| value: z10.record(z10.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(`/presets/${enc(input.name)}`, { | ||
| value: input.value | ||
| }) | ||
| }, | ||
| { | ||
| name: "presets.retrieve", | ||
| summary: "Retrieve a preset", | ||
| category: "presets", | ||
| input: z10.object({ name: z10.string() }), | ||
| execute: async (client, input) => api(client).get(`/presets/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "presets.delete", | ||
| summary: "Delete a preset", | ||
| category: "presets", | ||
| input: z10.object({ name: z10.string() }), | ||
| execute: async (client, input) => api(client).delete(`/presets/${enc(input.name)}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/search.ts | ||
| import { z as z11 } from "zod"; | ||
| var searchParams2 = z11.record(z11.unknown()); | ||
| var facetBySchema = z11.union([z11.string().min(1), z11.array(z11.string().min(1))]); | ||
| function withoutUndefined(params) { | ||
| return Object.fromEntries( | ||
| Object.entries(params).filter(([, value]) => value !== void 0) | ||
| ); | ||
| } | ||
| var searchOperations = [ | ||
| { | ||
| name: "search", | ||
| summary: "Search a collection", | ||
| category: "search", | ||
| input: z11.object({ collection: z11.string(), params: searchParams2 }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| input.params | ||
| ) | ||
| }, | ||
| { | ||
| name: "multi_search", | ||
| summary: "Run a Typesense multi-search", | ||
| category: "search", | ||
| input: z11.object({ | ||
| searches: z11.array(searchParams2), | ||
| commonParams: searchParams2.optional() | ||
| }), | ||
| execute: async (client, input) => api(client).post( | ||
| "/multi_search", | ||
| { searches: input.searches }, | ||
| input.commonParams | ||
| ) | ||
| }, | ||
| { | ||
| name: "search.facets", | ||
| summary: "Explore facet counts for a collection", | ||
| category: "search", | ||
| input: z11.object({ | ||
| collection: z11.string(), | ||
| facetBy: facetBySchema, | ||
| q: z11.string().optional().default("*"), | ||
| queryBy: z11.string().optional(), | ||
| filterBy: z11.string().optional(), | ||
| maxFacetValues: z11.number().int().positive().optional(), | ||
| perPage: z11.number().int().nonnegative().optional().default(0) | ||
| }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| withoutUndefined({ | ||
| q: input.q, | ||
| query_by: input.queryBy, | ||
| filter_by: input.filterBy, | ||
| facet_by: Array.isArray(input.facetBy) ? input.facetBy.join(",") : input.facetBy, | ||
| max_facet_values: input.maxFacetValues, | ||
| per_page: input.perPage | ||
| }) | ||
| ) | ||
| }, | ||
| { | ||
| name: "search.suggestions", | ||
| summary: "Fetch prefix search suggestions from a collection", | ||
| category: "search", | ||
| input: z11.object({ | ||
| collection: z11.string(), | ||
| q: z11.string(), | ||
| queryBy: z11.string(), | ||
| filterBy: z11.string().optional(), | ||
| includeFields: z11.union([z11.string(), z11.array(z11.string())]).optional(), | ||
| limit: z11.number().int().positive().max(50).optional().default(5), | ||
| prefix: z11.boolean().optional().default(true) | ||
| }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/documents/search`, | ||
| withoutUndefined({ | ||
| q: input.q, | ||
| query_by: input.queryBy, | ||
| filter_by: input.filterBy, | ||
| include_fields: Array.isArray(input.includeFields) ? input.includeFields.join(",") : input.includeFields, | ||
| per_page: input.limit, | ||
| prefix: input.prefix | ||
| }) | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/stopwords.ts | ||
| import { z as z12 } from "zod"; | ||
| var stopwordsOperations = [ | ||
| { | ||
| name: "stopwords.list", | ||
| summary: "List stopwords", | ||
| category: "stopwords", | ||
| input: z12.object({}), | ||
| execute: async (client) => api(client).get("/stopwords") | ||
| }, | ||
| { | ||
| name: "stopwords.create", | ||
| summary: "Create or upsert a stopword", | ||
| category: "stopwords", | ||
| input: z12.object({ | ||
| name: z12.string(), | ||
| value: z12.record(z12.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(`/stopwords/${enc(input.name)}`, input.value) | ||
| }, | ||
| { | ||
| name: "stopwords.retrieve", | ||
| summary: "Retrieve a stopword", | ||
| category: "stopwords", | ||
| input: z12.object({ name: z12.string() }), | ||
| execute: async (client, input) => api(client).get(`/stopwords/${enc(input.name)}`) | ||
| }, | ||
| { | ||
| name: "stopwords.delete", | ||
| summary: "Delete a stopword", | ||
| category: "stopwords", | ||
| input: z12.object({ name: z12.string() }), | ||
| execute: async (client, input) => api(client).delete(`/stopwords/${enc(input.name)}`) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/synonym-sets.ts | ||
| import { z as z13 } from "zod"; | ||
| function base(name) { | ||
| return name ? `/synonym_sets/${enc(name)}` : "/synonym_sets"; | ||
| } | ||
| function itemPath(name, id) { | ||
| const path = `${base(name)}/items`; | ||
| return id ? `${path}/${enc(id)}` : path; | ||
| } | ||
| var synonymSetOperations = [ | ||
| { | ||
| name: "synonym_sets.list", | ||
| summary: "List global synonym sets", | ||
| category: "synonyms", | ||
| input: z13.object({}), | ||
| execute: async (client) => api(client).get(base()) | ||
| }, | ||
| { | ||
| name: "synonym_sets.create", | ||
| summary: "Create or upsert a global synonym set", | ||
| category: "synonyms", | ||
| input: z13.object({ | ||
| name: z13.string(), | ||
| value: z13.object({ | ||
| items: z13.array(z13.record(z13.unknown())) | ||
| }) | ||
| }), | ||
| execute: async (client, input) => api(client).put(base(input.name), input.value) | ||
| }, | ||
| { | ||
| name: "synonym_sets.retrieve", | ||
| summary: "Retrieve a global synonym set", | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string() }), | ||
| execute: async (client, input) => api(client).get(base(input.name)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.delete", | ||
| summary: "Delete a global synonym set", | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string() }), | ||
| execute: async (client, input) => api(client).delete(base(input.name)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.list", | ||
| summary: "List items in a global synonym set", | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.create", | ||
| summary: "Create or upsert an item in a global synonym set", | ||
| category: "synonyms", | ||
| input: z13.object({ | ||
| name: z13.string(), | ||
| id: z13.string(), | ||
| value: z13.record(z13.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put(itemPath(input.name, input.id), input.value) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.retrieve", | ||
| summary: "Retrieve an item in a global synonym set", | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string(), id: z13.string() }), | ||
| execute: async (client, input) => api(client).get(itemPath(input.name, input.id)) | ||
| }, | ||
| { | ||
| name: "synonym_sets.items.delete", | ||
| summary: "Delete an item in a global synonym set", | ||
| category: "synonyms", | ||
| input: z13.object({ name: z13.string(), id: z13.string() }), | ||
| execute: async (client, input) => api(client).delete(itemPath(input.name, input.id)) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/synonyms.ts | ||
| import { z as z14 } from "zod"; | ||
| function isNotFound(error) { | ||
| if (typeof error !== "object" || error === null) return false; | ||
| const { httpStatus, status } = error; | ||
| return httpStatus === 404 || status === 404; | ||
| } | ||
| function synonymSetNames(collection) { | ||
| return Array.isArray(collection.synonym_sets) ? collection.synonym_sets.filter( | ||
| (name) => typeof name === "string" | ||
| ) : []; | ||
| } | ||
| function globalSynonymGuidance(collection, sets) { | ||
| return [ | ||
| `Collection-level synonyms are unavailable for ${collection}.`, | ||
| sets.length > 0 ? `This collection is linked to global synonym sets: ${sets.join(", ")}.` : "This Typesense version may use global synonym sets.", | ||
| "Use synonym_sets.list to inspect global synonym sets:", | ||
| "tsk synonym_sets.list --input '{}' --json" | ||
| ].join("\n"); | ||
| } | ||
| var synonymsOperations = [ | ||
| { | ||
| name: "synonyms.list", | ||
| summary: "List synonyms", | ||
| category: "synonyms", | ||
| input: z14.object({ collection: z14.string() }), | ||
| execute: async (client, input) => { | ||
| const request = api(client); | ||
| try { | ||
| return await request.get( | ||
| `${collectionPath(input.collection)}/synonyms` | ||
| ); | ||
| } catch (error) { | ||
| if (!isNotFound(error)) throw error; | ||
| const collection = await request.get( | ||
| collectionPath(input.collection) | ||
| ); | ||
| throw new Error( | ||
| globalSynonymGuidance(input.collection, synonymSetNames(collection)) | ||
| ); | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| name: "synonyms.create", | ||
| summary: "Create or upsert a synonym", | ||
| category: "synonyms", | ||
| input: z14.object({ | ||
| collection: z14.string(), | ||
| name: z14.string(), | ||
| value: z14.record(z14.unknown()) | ||
| }), | ||
| execute: async (client, input) => api(client).put( | ||
| `${collectionPath(input.collection)}/synonyms/${enc(input.name)}`, | ||
| input.value | ||
| ) | ||
| }, | ||
| { | ||
| name: "synonyms.retrieve", | ||
| summary: "Retrieve a synonym", | ||
| category: "synonyms", | ||
| input: z14.object({ collection: z14.string(), name: z14.string() }), | ||
| execute: async (client, input) => api(client).get( | ||
| `${collectionPath(input.collection)}/synonyms/${enc(input.name)}` | ||
| ) | ||
| }, | ||
| { | ||
| name: "synonyms.delete", | ||
| summary: "Delete a synonym", | ||
| category: "synonyms", | ||
| input: z14.object({ collection: z14.string(), name: z14.string() }), | ||
| execute: async (client, input) => api(client).delete( | ||
| `${collectionPath(input.collection)}/synonyms/${enc(input.name)}` | ||
| ) | ||
| } | ||
| ]; | ||
| // ../core/src/operations/system.ts | ||
| import { z as z15 } from "zod"; | ||
| var systemOperations = [ | ||
| { | ||
| name: "health", | ||
| summary: "Check Typesense cluster health", | ||
| category: "system", | ||
| input: z15.object({}), | ||
| execute: async (client) => api(client).get("/health") | ||
| }, | ||
| { | ||
| name: "metrics", | ||
| summary: "Retrieve Typesense metrics", | ||
| category: "system", | ||
| input: z15.object({}), | ||
| execute: async (client) => api(client).get("/metrics.json") | ||
| }, | ||
| { | ||
| name: "stats", | ||
| summary: "Retrieve Typesense stats", | ||
| category: "system", | ||
| input: z15.object({}), | ||
| execute: async (client) => api(client).get("/stats.json") | ||
| }, | ||
| { | ||
| name: "debug", | ||
| summary: "Retrieve Typesense debug info", | ||
| category: "system", | ||
| input: z15.object({}), | ||
| execute: async (client) => api(client).get("/debug") | ||
| } | ||
| ]; | ||
| // ../core/src/operations/index.ts | ||
| var operations = [ | ||
| ...collectionOperations, | ||
| ...documentOperations, | ||
| ...searchOperations, | ||
| ...aliasesOperations, | ||
| ...synonymsOperations, | ||
| ...synonymSetOperations, | ||
| ...overridesOperations, | ||
| ...keysOperations, | ||
| ...analyticsOperations, | ||
| ...presetsOperations, | ||
| ...stopwordsOperations, | ||
| ...conversationOperations, | ||
| ...apiOperations, | ||
| ...systemOperations | ||
| ]; | ||
| // package.json | ||
| var package_default = { | ||
| name: "@typesensekit/mcp", | ||
| version: "1.1.3", | ||
| type: "module", | ||
| main: "dist/server.js", | ||
| types: "dist/server.d.ts", | ||
| bin: { | ||
| "typesensekit-mcp": "dist/cli.js", | ||
| "typesensekit-mcp-http": "dist/http.js" | ||
| }, | ||
| exports: { | ||
| ".": { | ||
| types: "./dist/server.d.ts", | ||
| import: "./dist/server.js" | ||
| } | ||
| }, | ||
| files: [ | ||
| "dist", | ||
| "README.md" | ||
| ], | ||
| scripts: { | ||
| build: "tsup", | ||
| dev: "tsup --watch", | ||
| typecheck: "tsc --noEmit", | ||
| test: "vitest run" | ||
| }, | ||
| dependencies: { | ||
| "@modelcontextprotocol/sdk": "^1.29.0", | ||
| zod: "^3.25.76", | ||
| typesense: "^3.0.6" | ||
| }, | ||
| devDependencies: { | ||
| tsup: "^8.5.1", | ||
| "@types/node": "^22.10.0", | ||
| "@typesensekit/core": "workspace:*" | ||
| }, | ||
| publishConfig: { | ||
| access: "public" | ||
| }, | ||
| description: "MCP stdio server exposing Typesense API operations as tools.", | ||
| license: "MIT", | ||
| author: "Akshit Kr Nagpal", | ||
| repository: { | ||
| type: "git", | ||
| url: "git+https://github.com/akshitkrnagpal/typesensekit.git", | ||
| directory: "packages/mcp" | ||
| }, | ||
| bugs: { | ||
| url: "https://github.com/akshitkrnagpal/typesensekit/issues" | ||
| }, | ||
| homepage: "https://github.com/akshitkrnagpal/typesensekit#readme", | ||
| keywords: [ | ||
| "typesense", | ||
| "cli", | ||
| "mcp", | ||
| "model-context-protocol", | ||
| "search" | ||
| ] | ||
| }; | ||
| // src/read-only.ts | ||
| var READ_ONLY_OPERATION_NAMES = /* @__PURE__ */ new Set([ | ||
| "aliases.list", | ||
| "aliases.retrieve", | ||
| "collections.list", | ||
| "collections.retrieve", | ||
| "collections.wait", | ||
| "conversations.history.retrieve", | ||
| "conversations.models.list", | ||
| "conversations.models.retrieve", | ||
| "debug", | ||
| "documents.export", | ||
| "documents.get", | ||
| "documents.get_many", | ||
| "documents.search", | ||
| "health", | ||
| "metrics", | ||
| "multi_search", | ||
| "overrides.list", | ||
| "overrides.retrieve", | ||
| "presets.list", | ||
| "presets.retrieve", | ||
| "search", | ||
| "search.facets", | ||
| "search.suggestions", | ||
| "stats", | ||
| "stopwords.list", | ||
| "stopwords.retrieve", | ||
| "synonym_sets.items.list", | ||
| "synonym_sets.items.retrieve", | ||
| "synonym_sets.list", | ||
| "synonym_sets.retrieve", | ||
| "synonyms.list", | ||
| "synonyms.retrieve" | ||
| ]); | ||
| function isReadOnlyOperation(operation) { | ||
| return READ_ONLY_OPERATION_NAMES.has(operation.name); | ||
| } | ||
| function filterMcpOperations(operations2, readOnly) { | ||
| return readOnly ? operations2.filter(isReadOnlyOperation) : operations2; | ||
| } | ||
| function readOnlyFromEnv(value) { | ||
| if (value === void 0) return true; | ||
| return !["0", "false", "no", "off"].includes(value.toLowerCase()); | ||
| } | ||
| // src/env.ts | ||
| function readEnvConfig() { | ||
| return serverConfigSchema.parse({ | ||
| url: process.env.TYPESENSE_URL, | ||
| apiKey: process.env.TYPESENSE_API_KEY, | ||
| connectionTimeoutSeconds: process.env.TYPESENSE_CONNECTION_TIMEOUT_SECONDS ? Number(process.env.TYPESENSE_CONNECTION_TIMEOUT_SECONDS) : void 0 | ||
| }); | ||
| } | ||
| function readMcpOptions() { | ||
| return { | ||
| readOnly: readOnlyFromEnv(process.env.TYPESENSEKIT_READ_ONLY) | ||
| }; | ||
| } | ||
| // src/resources.ts | ||
| import { | ||
| ResourceTemplate | ||
| } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| function jsonContents(uri, value) { | ||
| return { | ||
| contents: [ | ||
| { | ||
| uri, | ||
| mimeType: "application/json", | ||
| text: JSON.stringify(value, null, 2) | ||
| } | ||
| ] | ||
| }; | ||
| } | ||
| function textContents(uri, value) { | ||
| return { | ||
| contents: [{ uri, mimeType: "text/plain", text: value }] | ||
| }; | ||
| } | ||
| function operationSummary(operation) { | ||
| return { | ||
| name: operation.name, | ||
| summary: operation.summary, | ||
| category: operation.category, | ||
| readOnly: READ_ONLY_OPERATION_NAMES.has(operation.name) | ||
| }; | ||
| } | ||
| function operationManifest(activeOperations, readOnly) { | ||
| return { | ||
| readOnly, | ||
| operations: activeOperations.map(operationSummary) | ||
| }; | ||
| } | ||
| function singleVariable(value, variable) { | ||
| if (typeof value === "string") return value; | ||
| throw new Error(`Missing ${variable} resource variable`); | ||
| } | ||
| async function readOperationResource(client, operationName, input, uri) { | ||
| const operation = operations.find( | ||
| (candidate) => candidate.name === operationName | ||
| ); | ||
| if (!operation) throw new Error(`${operationName} not found`); | ||
| try { | ||
| const result = await operation.execute( | ||
| client, | ||
| operation.input.parse(input) | ||
| ); | ||
| return jsonContents(uri, result); | ||
| } catch (error) { | ||
| return textContents(uri, formatTypesenseErrorMessage(error)); | ||
| } | ||
| } | ||
| function registerTypesenseResources(server, client, activeOperations, readOnly) { | ||
| server.registerResource( | ||
| "typesensekit-operations", | ||
| "typesensekit://operations", | ||
| { | ||
| title: "TypesenseKit Operations", | ||
| description: "Operations currently exposed by this MCP server.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri) => jsonContents(uri.href, operationManifest(activeOperations, readOnly)) | ||
| ); | ||
| server.registerResource( | ||
| "typesensekit-read-only-tools", | ||
| "typesensekit://read-only-tools", | ||
| { | ||
| title: "TypesenseKit Read-only Tools", | ||
| description: "Operation names included in default read-only MCP mode.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri) => jsonContents(uri.href, { | ||
| operations: [...READ_ONLY_OPERATION_NAMES].sort() | ||
| }) | ||
| ); | ||
| server.registerResource( | ||
| "typesense-collection-schema", | ||
| new ResourceTemplate("typesense://collections/{collection}/schema", { | ||
| list: void 0 | ||
| }), | ||
| { | ||
| title: "Typesense Collection Schema", | ||
| description: "Retrieve a Typesense collection schema by collection name.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri, variables) => readOperationResource( | ||
| client, | ||
| "collections.retrieve", | ||
| { collection: singleVariable(variables.collection, "collection") }, | ||
| uri.href | ||
| ) | ||
| ); | ||
| server.registerResource( | ||
| "typesense-document", | ||
| new ResourceTemplate( | ||
| "typesense://collections/{collection}/documents/{id}", | ||
| { | ||
| list: void 0 | ||
| } | ||
| ), | ||
| { | ||
| title: "Typesense Document", | ||
| description: "Retrieve a Typesense document by collection and document id.", | ||
| mimeType: "application/json" | ||
| }, | ||
| async (uri, variables) => readOperationResource( | ||
| client, | ||
| "documents.get", | ||
| { | ||
| collection: singleVariable(variables.collection, "collection"), | ||
| id: singleVariable(variables.id, "id") | ||
| }, | ||
| uri.href | ||
| ) | ||
| ); | ||
| } | ||
| // src/server.ts | ||
| function toToolShape(input) { | ||
| const objectInput = input; | ||
| return objectInput.shape; | ||
| } | ||
| function createTypesenseMcpServer(options = {}) { | ||
| const server = new McpServer({ | ||
| name: "typesensekit", | ||
| version: package_default.version | ||
| }); | ||
| const client = createClient(readEnvConfig()); | ||
| const mcpOptions = { ...readMcpOptions(), ...options }; | ||
| const activeOperations = filterMcpOperations(operations, mcpOptions.readOnly); | ||
| registerTypesenseResources( | ||
| server, | ||
| client, | ||
| activeOperations, | ||
| mcpOptions.readOnly | ||
| ); | ||
| for (const operation of activeOperations) { | ||
| server.registerTool( | ||
| operation.name, | ||
| { | ||
| title: operation.name, | ||
| description: operation.summary, | ||
| inputSchema: toToolShape(operation.input) | ||
| }, | ||
| async (args) => { | ||
| try { | ||
| const input = operation.input.parse(args); | ||
| const result = await operation.execute(client, input); | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: JSON.stringify(redactSecrets(result), null, 2) | ||
| } | ||
| ] | ||
| }; | ||
| } catch (error) { | ||
| const message = formatTypesenseErrorMessage(error); | ||
| return { isError: true, content: [{ type: "text", text: message }] }; | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| return server; | ||
| } | ||
| export { | ||
| createTypesenseMcpServer | ||
| }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
122926
18.96%3783
17.96%2
100%