From ed32d3da2c84d408bab1cb73086375f8ab2f4699 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Wed, 20 May 2026 03:54:11 -0400 Subject: [PATCH 01/15] =?UTF-8?q?=E2=9C=A8=20#1045:=20Complete=20MCP=20Ser?= =?UTF-8?q?ver=20Scaffold=20Implements=20a=20working=20MCP=20server=20for?= =?UTF-8?q?=20the=20Arranger=20introspection=20API,=20built=20on=20`@model?= =?UTF-8?q?contextprotocol/sdk`=20v1.x=20with=20the=20Streamable=20HTTP=20?= =?UTF-8?q?transport.=20*=20Adds=20configuration=20via=20Zod-validated=20e?= =?UTF-8?q?nvironment=20variables=20*=20Adds=20Arranger=20connection=20val?= =?UTF-8?q?idation=20at=20startup=20*=20Adds=20Pino=20logging=20*=20Adds?= =?UTF-8?q?=20an=20Express=20server=20with=20the=20configured=20MCP=20endp?= =?UTF-8?q?oint=20for=20Streamable=20HTTP=20transport=20*=20Adds=20MCP=20R?= =?UTF-8?q?esources=20for=20the=20Arranger=20introspection=20endpoints:=20?= =?UTF-8?q?=20=20*=20`arranger://introspection/server`=20=20=20*=20`arrang?= =?UTF-8?q?er://introspection/sqon`=20=20=20*=20`arranger://introspection/?= =?UTF-8?q?catalog/{catalogId}`=20*=20Adds=20MCP=20Tools=20for=20the=20Arr?= =?UTF-8?q?anger=20introspection=20endpoints:=20=20=20*=20`list-catalogs`?= =?UTF-8?q?=20=20=20*=20`get-sqon-schema`=20=20=20*=20`get-catalog-fields`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/.env.schema | 9 + apps/mcp-server/mcp-inspector.json | 8 + apps/mcp-server/package.json | 38 + apps/mcp-server/src/arranger/client.ts | 2 +- apps/mcp-server/src/arranger/validation.ts | 35 + apps/mcp-server/src/config.ts | 16 - apps/mcp-server/src/http/app.ts | 102 + apps/mcp-server/src/index.ts | 43 +- apps/mcp-server/src/mcp/resources.ts | 88 +- apps/mcp-server/src/mcp/tools.ts | 78 +- apps/mcp-server/src/mcp/types.ts | 22 - apps/mcp-server/src/server.ts | 42 + apps/mcp-server/src/utils/config.ts | 115 + .../src/utils/inMemoryEventStore.ts | 81 + apps/mcp-server/src/utils/logger.ts | 60 + package-lock.json | 2089 ++++++++++++++++- package.json | 3 + 17 files changed, 2652 insertions(+), 179 deletions(-) create mode 100644 apps/mcp-server/.env.schema create mode 100644 apps/mcp-server/mcp-inspector.json create mode 100644 apps/mcp-server/src/arranger/validation.ts delete mode 100644 apps/mcp-server/src/config.ts create mode 100644 apps/mcp-server/src/http/app.ts delete mode 100644 apps/mcp-server/src/mcp/types.ts create mode 100644 apps/mcp-server/src/server.ts create mode 100644 apps/mcp-server/src/utils/config.ts create mode 100644 apps/mcp-server/src/utils/inMemoryEventStore.ts create mode 100644 apps/mcp-server/src/utils/logger.ts diff --git a/apps/mcp-server/.env.schema b/apps/mcp-server/.env.schema new file mode 100644 index 000000000..6525e2843 --- /dev/null +++ b/apps/mcp-server/.env.schema @@ -0,0 +1,9 @@ +ARRANGER_BASE_URL=http://localhost:5050 +ARRANGER_CATALOGUES=server +ARRANGER_REQUEST_TIMEOUT_MS=10_000 + +MCP_HOST=0.0.0.0 +MCP_PORT=3100 +MCP_PATH=/mcp + +LOG_LEVEL=info diff --git a/apps/mcp-server/mcp-inspector.json b/apps/mcp-server/mcp-inspector.json new file mode 100644 index 000000000..4f15a1575 --- /dev/null +++ b/apps/mcp-server/mcp-inspector.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "mcp-server": { + "type": "streamable-http", + "url": "http://127.0.0.1:3100/mcp" + } + } +} diff --git a/apps/mcp-server/package.json b/apps/mcp-server/package.json index 7b313f93d..abe62c988 100644 --- a/apps/mcp-server/package.json +++ b/apps/mcp-server/package.json @@ -1,7 +1,45 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@overture-stack/arranger-mcp-server", + "description": "Arranger MCP Server", "version": "0.0.0-dev", + "homepage": "https://github.com/overture-stack/arranger#readme", + "bugs": { + "url": "https://github.com/overture-stack/arranger/issues" + }, + "main": "src/index.ts", + "types": "src/index.ts", + "repository": { + "directory": "apps/mcp-server", + "type": "git", + "url": "git+https://github.com/overture-stack/arranger.git" + }, "private": true, + "scripts": { + "dev": "NODE_ENV=development tsx watch --include './src/**/*' ./src/index.ts", + "start": "tsx ./src/index.ts", + "test": "tsx --test ./src/**/*.test.ts", + "inspect": "npx @modelcontextprotocol/inspector --config ./mcp-inspector.json --server mcp-server" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "cors": "^2.8.6", + "dotenv": "^16.6.1", + "express": "^4.21.2", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "zod": "^3.25.76" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.5", + "@types/cors": "^2.8.12", + "@types/express": "^4.17.14", + "@types/node": "^25.6.2", + "tsx": "^4.21.0", + "typescript": "^5.8.3" + }, + "imports": { + "#*": "./src/*" + }, "type": "module" } diff --git a/apps/mcp-server/src/arranger/client.ts b/apps/mcp-server/src/arranger/client.ts index 5f4704369..39cc0cce8 100644 --- a/apps/mcp-server/src/arranger/client.ts +++ b/apps/mcp-server/src/arranger/client.ts @@ -1,4 +1,4 @@ -import type { ArrangerMcpConfig } from '#config.js'; +import type { ArrangerMcpConfig } from '#utils/config.js'; import type { ArrangerCatalogIntrospection, diff --git a/apps/mcp-server/src/arranger/validation.ts b/apps/mcp-server/src/arranger/validation.ts new file mode 100644 index 000000000..b22f2034b --- /dev/null +++ b/apps/mcp-server/src/arranger/validation.ts @@ -0,0 +1,35 @@ +import { type ArrangerIntrospectionClient } from '#arranger/client.js'; +import { type ArrangerMcpConfig } from '#utils/config.js'; +import logger from '#utils/logger.js'; + +/** + * Validates the connection to Arranger by checking the /introspection and /introspection/sqon endpoints, + * and ensuring that all configured catalogues are available. + * @param config - The MCP server configuration containing Arranger connection details and catalogues to validate. + * @param client - An instance of ArrangerIntrospectionClient used to make requests to Arranger. + * @throws Will throw an error if the connection to Arranger fails or if any configured catalogue is not available. + */ +export const validateArrangerConnection = async ( + config: ArrangerMcpConfig, + client: ArrangerIntrospectionClient, +): Promise => { + try { + const server = await client.getServerIntrospection(); + await client.getSqonIntrospection(); + logger.info('Connected to Arranger /introspection and /introspection/sqon.'); + + const available = new Set(Object.keys(server.catalogs)); + const missing = config.catalogues.filter((catalogue) => !available.has(catalogue)); + if (missing.length > 0) { + throw new Error(`Configured catalogues not available on Arranger: ${missing.join(', ')}`); + } + + for (const catalogId of config.catalogues) { + await client.getCatalogIntrospection(catalogId); + } + logger.info({ catalogues: config.catalogues }, 'All configured catalogues validated.'); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Arranger connection validation failed: ${message}`); + } +}; diff --git a/apps/mcp-server/src/config.ts b/apps/mcp-server/src/config.ts deleted file mode 100644 index 20edd3b12..000000000 --- a/apps/mcp-server/src/config.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface ArrangerMcpConfig { - arrangerBaseUrl: string; - requestTimeoutMs: number; -} - -const DEFAULT_ARRANGER_BASE_URL = 'http://localhost:5050'; -const DEFAULT_REQUEST_TIMEOUT_MS = 10_000; - -const trimTrailingSlash = (value: string) => value.replace(/\/+$/, ''); - -export const createArrangerMcpConfig = ( - overrides: Partial = {}, -): ArrangerMcpConfig => ({ - arrangerBaseUrl: trimTrailingSlash(overrides.arrangerBaseUrl || process.env.ARRANGER_BASE_URL || DEFAULT_ARRANGER_BASE_URL), - requestTimeoutMs: overrides.requestTimeoutMs || Number(process.env.ARRANGER_REQUEST_TIMEOUT_MS || DEFAULT_REQUEST_TIMEOUT_MS), -}); diff --git a/apps/mcp-server/src/http/app.ts b/apps/mcp-server/src/http/app.ts new file mode 100644 index 000000000..c185e3976 --- /dev/null +++ b/apps/mcp-server/src/http/app.ts @@ -0,0 +1,102 @@ +import { randomUUID } from 'node:crypto'; + +import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express'; +import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp'; +import { isInitializeRequest } from '@modelcontextprotocol/sdk/types'; +import { type Express, type Request, type Response } from 'express'; + +import { type ArrangerMcpConfig } from '#utils/config.js'; +import { InMemoryEventStore } from '#utils/inMemoryEventStore.js'; +import logger from '#utils/logger.js'; + +export type McpHttpApp = { + app: Express; + shutdown: () => Promise; +}; + +// This code was adapted from the official MCP Server "Streamable HTTP" example: +// https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/src/examples/server/simpleStreamableHttp.ts +export const createHttpApp = (config: ArrangerMcpConfig, serverFactory: () => McpServer): McpHttpApp => { + const transports: Record = {}; + + const postHandler = async (req: Request, res: Response) => { + const sessionId = req.headers['mcp-session-id'] as string | undefined; + try { + let transport: StreamableHTTPServerTransport; + if (sessionId && transports[sessionId]) { + transport = transports[sessionId]; + } else if (!sessionId && isInitializeRequest(req.body)) { + transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID(), + eventStore: new InMemoryEventStore(), + onsessioninitialized: (sid) => { + logger.info(`Session initialized with ID: ${sid}`); + transports[sid] = transport; + }, + }); + transport.onclose = () => { + const sid = transport.sessionId; + if (sid && transports[sid]) { + logger.info(`Transport closed for session ${sid}, removing from transports map`); + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete transports[sid]; + } + }; + + await serverFactory().connect(transport); + await transport.handleRequest(req, res, req.body); + return; + } else { + res.status(400).json({ + jsonrpc: '2.0', + error: { code: -32000, message: 'Bad Request: No valid session ID provided' }, + id: null, + }); + return; + } + await transport.handleRequest(req, res, req.body); + } catch (error) { + logger.error({ error }, 'Error handling MCP POST'); + if (!res.headersSent) { + res.status(500).json({ + jsonrpc: '2.0', + error: { code: -32603, message: 'Internal server error' }, + id: null, + }); + } + } + }; + + const sessionHandler = async (req: Request, res: Response) => { + const sessionId = req.headers['mcp-session-id'] as string | undefined; + if (!sessionId || !transports[sessionId]) { + res.status(400).send('Invalid or missing session ID'); + return; + } + await transports[sessionId].handleRequest(req, res); + }; + + const app = createMcpExpressApp(); + const { + mcp: { path }, + } = config; + app.post(path, postHandler); + app.get(path, sessionHandler); + app.delete(path, sessionHandler); + + const shutdown = async () => { + for (const sessionId of Object.keys(transports)) { + try { + logger.debug(`Closing transport for session ${sessionId}`); + await transports[sessionId].close(); + } catch (error) { + logger.error({ error, sessionId }, 'Error closing transport'); + } + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete transports[sessionId]; + } + }; + + return { app, shutdown }; +}; diff --git a/apps/mcp-server/src/index.ts b/apps/mcp-server/src/index.ts index 1bf2907f0..0fee56e96 100644 --- a/apps/mcp-server/src/index.ts +++ b/apps/mcp-server/src/index.ts @@ -1,38 +1,9 @@ -import { createArrangerIntrospectionClient } from '#arranger/client.js'; -import { createArrangerMcpConfig } from '#config.js'; -import { buildCatalogResources, buildStaticResources } from '#mcp/resources.js'; -import { buildFoundationTools } from '#mcp/tools.js'; +import 'dotenv/config'; -export interface ArrangerMcpFoundation { - config: ReturnType; - tools: ReturnType; - resources: ReturnType; - loadCatalogResources(): Promise>; -} +import { startServer } from '#server.js'; +import logger from '#utils/logger.js'; -export const createArrangerMcpFoundation = (): ArrangerMcpFoundation => { - const config = createArrangerMcpConfig(); - const client = createArrangerIntrospectionClient(config); - - return { - config, - resources: buildStaticResources(), - tools: buildFoundationTools(), - loadCatalogResources: async () => { - const serverIntrospection = await client.getServerIntrospection(); - return buildCatalogResources(serverIntrospection); - }, - }; -}; - -/* - The intended next step is roughly: - - 1. create the MCP transport/server - 2. register static resources from `buildStaticResources()` - 3. register dynamic catalog resources after `getServerIntrospection()` - 4. implement tool handlers by calling: - - client.getServerIntrospection() - - client.getSqonIntrospection() - - client.getCatalogIntrospection(catalogId) -*/ +startServer().catch((err) => { + logger.error({ err }, 'Failed to start MCP server'); + process.exit(1); +}); diff --git a/apps/mcp-server/src/mcp/resources.ts b/apps/mcp-server/src/mcp/resources.ts index b4fdd4df3..4ff90acb1 100644 --- a/apps/mcp-server/src/mcp/resources.ts +++ b/apps/mcp-server/src/mcp/resources.ts @@ -1,25 +1,69 @@ -import type { ArrangerServerIntrospection } from '#arranger/types.js'; +import { ResourceTemplate, type McpServer } from '@modelcontextprotocol/sdk/server/mcp'; -import type { McpResourceDefinition } from './types.js'; +import { type McpServerDeps } from '#server.js'; -export const buildStaticResources = (): McpResourceDefinition[] => [ - { - description: 'Arranger-wide server summary and catalog inventory.', - name: 'arranger_server_introspection', - uri: 'arranger://introspection/server', - }, - { - description: 'Shared SQON schema and SQON operator metadata for this Arranger instance.', - name: 'arranger_sqon_schema', - uri: 'arranger://introspection/sqon', - }, -]; +const JSON_MIME = 'application/json'; -export const buildCatalogResources = ( - serverIntrospection: ArrangerServerIntrospection, -): McpResourceDefinition[] => - Object.keys(serverIntrospection.catalogs).map((catalogId) => ({ - description: `Field-level introspection for the "${catalogId}" catalog.`, - name: `arranger_catalog_${catalogId}`, - uri: `arranger://introspection/catalog/${catalogId}`, - })); +export const registerResources = (server: McpServer, { client }: McpServerDeps): void => { + server.registerResource( + 'arranger-server-introspection', + 'arranger://introspection/server', + { + title: 'Arranger Server Introspection', + description: 'Arranger-wide server summary and catalog inventory (GET /introspection).', + mimeType: JSON_MIME, + }, + async (uri) => { + const data = await client.getServerIntrospection(); + return { + contents: [{ uri: uri.href, mimeType: JSON_MIME, text: JSON.stringify(data, null, 2) }], + }; + }, + ); + + server.registerResource( + 'arranger-sqon-schema', + 'arranger://introspection/sqon', + { + title: 'SQON Schema', + description: + 'Shared SQON Schema and SQON operator metadata for this Arranger instance (GET /introspection/sqon).', + mimeType: JSON_MIME, + }, + async (uri) => { + const data = await client.getSqonIntrospection(); + return { + contents: [{ uri: uri.href, mimeType: JSON_MIME, text: JSON.stringify(data, null, 2) }], + }; + }, + ); + + server.registerResource( + 'arranger-catalog-fields', + new ResourceTemplate('arranger://introspection/catalog/{catalogId}', { + list: async () => { + const { catalogs } = await client.getServerIntrospection(); + return { + resources: Object.keys(catalogs).map((catalogId) => ({ + uri: `arranger://introspection/catalog/${catalogId}`, + name: catalogId, + mimeType: JSON_MIME, + })), + }; + }, + }), + { + title: 'Arranger Catalog Fields', + description: + 'Per-catalog field metadata: displayName, type, unit, validOperators (GET /introspection/:catalogId).', + mimeType: JSON_MIME, + }, + async (uri, { catalogId }) => { + const id = Array.isArray(catalogId) ? catalogId[0] : catalogId; + const data = await client.getCatalogIntrospection(id); + return { + contents: [{ uri: uri.href, mimeType: JSON_MIME, text: JSON.stringify(data, null, 2) }], + }; + }, + ); +}; diff --git a/apps/mcp-server/src/mcp/tools.ts b/apps/mcp-server/src/mcp/tools.ts index a05681632..6c95b7021 100644 --- a/apps/mcp-server/src/mcp/tools.ts +++ b/apps/mcp-server/src/mcp/tools.ts @@ -1,26 +1,58 @@ -import type { McpToolDefinition } from './types.js'; +import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp'; +import { z } from 'zod'; -export const buildFoundationTools = (): McpToolDefinition[] => [ - { - description: 'List the catalogs exposed by the connected Arranger server.', - name: 'list_catalogs', - }, - { - description: 'Return the shared SQON schema and operator metadata for the connected Arranger server.', - name: 'get_sqon_schema', - }, - { - description: 'Return field introspection for one catalog, including field names, field types, and valid operators.', - inputSchema: { - properties: { - catalogId: { - description: 'Catalog identifier from the Arranger /introspection payload.', - type: 'string', - }, +import { type McpServerDeps } from '#server.js'; + +const fieldShape = z.object({ + displayName: z.string(), + type: z.string(), + unit: z.string().nullable().optional(), + validOperators: z.array(z.string()), +}); + +export const registerTools = (server: McpServer, { client }: McpServerDeps): void => { + server.registerTool( + 'list-catalogs', + { + title: 'List Arranger Catalogs', + description: 'Returns the catalogs exposed by the connected Arranger server.', + }, + async () => { + const { catalogs } = await client.getServerIntrospection(); + const ids = Object.keys(catalogs); + return { content: [{ type: 'text', text: `Available catalogs: ${ids.join(', ')}` }] }; + }, + ); + + server.registerTool( + 'get-sqon-schema', + { + title: 'Get SQON Schema', + description: 'Returns the shared SQON Schema and operator metadata for the connected Arranger server.', + }, + async () => { + const data = await client.getSqonIntrospection(); + return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }; + }, + ); + + server.registerTool( + 'get-catalog-fields', + { + title: 'Get Catalog Fields', + description: 'Returns the field map for one catalog (displayName, type, unit, validOperators).', + inputSchema: { + catalogId: z.string().min(1).describe('Catalog identifier from the Arranger /introspection payload.'), }, - required: ['catalogId'], - type: 'object', + outputSchema: { catalogId: z.string(), fields: z.record(fieldShape) }, + }, + async ({ catalogId }) => { + const data = await client.getCatalogIntrospection(catalogId); + const structured = { catalogId: data.catalogId, fields: data.fields }; + return { + content: [{ type: 'text', text: JSON.stringify(structured, null, 2) }], + structuredContent: structured, + }; }, - name: 'get_catalog_fields', - }, -]; + ); +}; diff --git a/apps/mcp-server/src/mcp/types.ts b/apps/mcp-server/src/mcp/types.ts deleted file mode 100644 index 43c5fdc3c..000000000 --- a/apps/mcp-server/src/mcp/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -export interface McpResourceDefinition { - name: string; - description: string; - uri: string; -} - -export interface McpToolArgument { - name: string; - description: string; - required?: boolean; - type: 'string' | 'number' | 'boolean'; -} - -export interface McpToolDefinition { - name: string; - description: string; - inputSchema?: { - type: 'object'; - properties: Record; - required?: string[]; - }; -} diff --git a/apps/mcp-server/src/server.ts b/apps/mcp-server/src/server.ts new file mode 100644 index 000000000..35d8d7c29 --- /dev/null +++ b/apps/mcp-server/src/server.ts @@ -0,0 +1,42 @@ +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; + +import { createArrangerIntrospectionClient, type ArrangerIntrospectionClient } from '#arranger/client.js'; +import { validateArrangerConnection } from '#arranger/validation.js'; +import { createHttpApp } from '#http/app.js'; +import { registerResources } from '#mcp/resources.js'; +import { registerTools } from '#mcp/tools.js'; +import { createArrangerMcpConfig, type ArrangerMcpConfig } from '#utils/config.js'; +import logger from '#utils/logger.js'; + +export type McpServerDeps = { + config: ArrangerMcpConfig; + client: ArrangerIntrospectionClient; +}; + +export const createMcpServer = (deps: McpServerDeps): McpServer => { + const server = new McpServer({ name: 'arranger-mcp-server', version: '0.0.0-dev' }); + registerResources(server, deps); + registerTools(server, deps); + return server; +}; + +export const startServer = async (): Promise => { + const config = createArrangerMcpConfig(); + const client = createArrangerIntrospectionClient(config); + await validateArrangerConnection(config, client); + + const deps: McpServerDeps = { config, client }; + const { app, shutdown } = createHttpApp(config, () => createMcpServer(deps)); + + const { host, port, path } = config.mcp; + app.listen(port, () => { + logger.info(`MCP server running at http://${host}:${port}${path}`); + }); + + process.on('SIGINT', async () => { + logger.info('Shutting down server...'); + await shutdown(); + logger.info('Server shutdown complete.'); + process.exit(0); + }); +}; diff --git a/apps/mcp-server/src/utils/config.ts b/apps/mcp-server/src/utils/config.ts new file mode 100644 index 000000000..86d512f92 --- /dev/null +++ b/apps/mcp-server/src/utils/config.ts @@ -0,0 +1,115 @@ +import { z as zod } from 'zod'; + +import { createLogger } from '#utils/logger.js'; + +const DEFAULT_REQUEST_TIMEOUT_MS = 10_000; + +const logger = createLogger('Config'); + +/** + * Utility function to trim trailing slashes from a URL string. + * @param value - The URL string to trim. + * @returns The input string with any trailing slashes removed. + * @example + * ```ts + * trimTrailingSlash('https://example.com/') // returns 'https://example.com' + * trimTrailingSlash('https://example.com/path/') // returns 'https://example.com/path' + * ``` + */ +const trimTrailingSlash = (value: string) => value.replace(/\/+$/, ''); + +/** + * Convert a comma-separated string of catalogue names into an array of trimmed strings, filtering out any empty values. + * @param cataloguesString - A comma-separated string of catalogue names. + * @returns An array of trimmed catalogue names. + * @example + * ```ts + * parseCatalogueList('catalogue1,catalogue2,catalogue3') // returns ['catalogue1', 'catalogue2', 'catalogue3'] + * parseCatalogueList('catalogue1,, catalogue2, ,catalogue3,') // returns ['catalogue1', 'catalogue2', 'catalogue3'] + * ``` + */ +const parseCatalogueList = (cataloguesString: string): string[] => { + return cataloguesString + .split(',') + .map((catalogue) => catalogue.trim()) + .filter(Boolean); +}; + +/** + * Zod schema for validating and parsing environment variables for the Arranger MCP server configuration. + * This schema ensures that all required values are present and correctly formatted, and provides default values + * where appropriate (i.e. for optional environment variables). + */ +const envSchema = zod.object({ + ARRANGER_BASE_URL: zod + .string({ + message: 'ARRANGER_BASE_URL is required and must be a valid URL', + }) + .url('ARRANGER_BASE_URL must be a valid URL') + .transform(trimTrailingSlash), + ARRANGER_CATALOGUES: zod + .string({ + message: 'ARRANGER_CATALOGUES is required and must be a comma-separated list of catalogue names', + }) + .min(1, 'ARRANGER_CATALOGUES is required and cannot be empty') + .transform(parseCatalogueList), + ARRANGER_REQUEST_TIMEOUT_MS: zod.preprocess( + (value) => { + if (typeof value === 'string') { + // Remove underscores to allow for more human-friendly large numbers (e.g., "10_000" instead of "10000") + return value.replace(/_/g, ''); + } + return value; + }, + zod.coerce + .number({ + message: 'ARRANGER_REQUEST_TIMEOUT_MS must be a valid number', + }) + .int('ARRANGER_REQUEST_TIMEOUT_MS must be an integer') + .positive('ARRANGER_REQUEST_TIMEOUT_MS must be a positive number') + .optional() + .default(DEFAULT_REQUEST_TIMEOUT_MS), + ), + MCP_HOST: zod.string().optional().default('0.0.0.0'), + MCP_PORT: zod.coerce.number().int().positive().max(65535, 'MCP_PORT cannot exceed 65535').optional().default(3100), + MCP_PATH: zod.string().optional().default('/mcp'), + LOG_LEVEL: zod + .enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal'], { + message: 'LOG_LEVEL must be one of: trace, debug, info, warn, error, fatal', + }) + .optional() + .default('info'), +}); + +/** + * Zod schema for the Arranger MCP server configuration, derived from `envSchema`. + * Transforms the validated env vars into a structured config object. + */ +const ArrangerMcpConfig = envSchema.transform((data) => ({ + arrangerBaseUrl: data.ARRANGER_BASE_URL, + catalogues: data.ARRANGER_CATALOGUES, + requestTimeoutMs: data.ARRANGER_REQUEST_TIMEOUT_MS, + mcp: { + host: data.MCP_HOST, + port: data.MCP_PORT, + path: data.MCP_PATH, + }, +})); +export type ArrangerMcpConfig = zod.infer; + +/** + * Validates and parses environment variables to create the Arranger MCP server configuration object. + * If validation fails, logs detailed error messages and exits the process. + * @returns - A validated and structured ArrangerMcpConfig object derived from env vars. + * @remarks - This function will terminate the process if any required environment variables are missing or invalid. + */ +export const createArrangerMcpConfig = (): ArrangerMcpConfig => { + const result = ArrangerMcpConfig.safeParse(process.env); + if (!result.success) { + const errorMessages = result.error.errors.map((err) => err.message).join('; '); + logger.error(`Arranger configuration validation failed: ${errorMessages}`); + logger.info('Exiting.'); + process.exit(1); + } + return result.data; +}; diff --git a/apps/mcp-server/src/utils/inMemoryEventStore.ts b/apps/mcp-server/src/utils/inMemoryEventStore.ts new file mode 100644 index 000000000..3f847ba3a --- /dev/null +++ b/apps/mcp-server/src/utils/inMemoryEventStore.ts @@ -0,0 +1,81 @@ +// In-memory event store implementation from the MCP TypeScript SDK examples: +// https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/src/examples/shared/inMemoryEventStore.ts +// TODO: Replace with a persistent storage solution for production use +import { type EventStore } from '@modelcontextprotocol/sdk/server/streamableHttp'; +import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types'; + +/** + * Simple in-memory implementation of the EventStore interface for resumability + * This is primarily intended for examples and testing, not for production use + * where a persistent storage solution would be more appropriate. + */ +export class InMemoryEventStore implements EventStore { + private events = new Map(); + + /** + * Generates a unique event ID for a given stream ID + */ + private generateEventId(streamId: string): string { + return `${streamId}_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`; + } + + /** + * Extracts the stream ID from an event ID + */ + private getStreamIdFromEventId(eventId: string): string { + const parts = eventId.split('_'); + return parts.length > 0 ? parts[0] : ''; + } + + /** + * Stores an event with a generated event ID + * Implements EventStore.storeEvent + */ + async storeEvent(streamId: string, message: JSONRPCMessage): Promise { + const eventId = this.generateEventId(streamId); + this.events.set(eventId, { streamId, message }); + return eventId; + } + + /** + * Replays events that occurred after a specific event ID + * Implements EventStore.replayEventsAfter + */ + async replayEventsAfter( + lastEventId: string, + { send }: { send: (eventId: string, message: JSONRPCMessage) => Promise }, + ): Promise { + if (!lastEventId || !this.events.has(lastEventId)) { + return ''; + } + + // Extract the stream ID from the event ID + const streamId = this.getStreamIdFromEventId(lastEventId); + if (!streamId) { + return ''; + } + + let foundLastEvent = false; + + // Sort events by eventId for chronological ordering + const sortedEvents = [...this.events.entries()].sort((a, b) => a[0].localeCompare(b[0])); + + for (const [eventId, { streamId: eventStreamId, message }] of sortedEvents) { + // Only include events from the same stream + if (eventStreamId !== streamId) { + continue; + } + + // Start sending events after we find the lastEventId + if (eventId === lastEventId) { + foundLastEvent = true; + continue; + } + + if (foundLastEvent) { + await send(eventId, message); + } + } + return streamId; + } +} diff --git a/apps/mcp-server/src/utils/logger.ts b/apps/mcp-server/src/utils/logger.ts new file mode 100644 index 000000000..c1c10e128 --- /dev/null +++ b/apps/mcp-server/src/utils/logger.ts @@ -0,0 +1,60 @@ +import pino, { type Logger, type LoggerOptions } from 'pino'; +import pretty from 'pino-pretty'; + +/** + * Create a pretty stream for pino that outputs colourized logs with timestamps in UTC ISO format, and excludes pid and + * hostname from the log output. Logs are sent to stderr to keep stdout clean for potential MCP STDIO Transport. + */ +const createStream = () => + pretty({ + colorize: true, + translateTime: 'UTC:yyyy-mm-dd"T"HH:MM:ss.l"Z"', // UTC time with ISO format, e.g., 2024-06-01T12:00:00.000Z + ignore: 'pid,hostname', + destination: 2, // stderr + }); + +/** + * Base logger options for all logger instances. The logger name is set to 'mcp-server' and the log level is determined + * by the LOG_LEVEL environment variable, defaulting to 'info' if not set. + */ +const baseOptions: LoggerOptions = { + name: 'mcp-server', + level: process.env.LOG_LEVEL ?? 'info', +}; + +/** + * Creates a pino logger instance with optional module name prefix. If a module name is provided, it will be included + * as a prefix in all log messages from that logger instance. + * + * @param moduleName - Optional name of the module to include as a prefix in log messages. + * @remarks If no module name is provided, the logger will not include any prefix in log messages. + * + * @returns A pino logger instance, optionally with a module name prefix in log messages. + * + * @example + * ```ts + * const logger = createLogger('MyModule'); + * logger.info('This is an info message'); // Output: [MyModule] This is an info message + * ``` + */ +export const createLogger = (moduleName?: string): Logger => { + const logger = pino(baseOptions, createStream()); + + if (!moduleName) { + return logger; + } + + return logger.child( + {}, + { + msgPrefix: `[${moduleName}] `, + }, + ); +}; + +/** + * Default logger instance without a module name prefix for general use across the application. + */ +const logger = createLogger(); + +export default logger; diff --git a/package-lock.json b/package-lock.json index ef3f8a3e6..c3cd3c128 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,41 @@ }, "apps/mcp-server": { "name": "@overture-stack/arranger-mcp-server", - "version": "0.0.0-dev" + "version": "0.0.0-dev", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "cors": "^2.8.6", + "dotenv": "^16.6.1", + "express": "^4.21.2", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "zod": "^3.25.76" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.5", + "@types/cors": "^2.8.12", + "@types/express": "^4.17.14", + "@types/node": "^25.6.2", + "tsx": "^4.21.0", + "typescript": "^5.8.3" + } + }, + "apps/mcp-server/node_modules/@types/node": { + "version": "25.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz", + "integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "apps/mcp-server/node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "dev": true, + "license": "MIT" }, "apps/search-server": { "name": "@overture-stack/arranger-search-server", @@ -3692,6 +3726,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3708,6 +3743,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3724,6 +3760,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3740,6 +3777,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3756,6 +3794,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3772,6 +3811,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3788,6 +3828,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3804,6 +3845,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3820,6 +3862,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3836,6 +3879,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3852,6 +3896,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3868,6 +3913,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3884,6 +3930,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3900,6 +3947,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3916,6 +3964,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3932,6 +3981,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3948,6 +3998,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3964,6 +4015,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3980,6 +4032,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3996,6 +4049,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4012,6 +4066,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4045,6 +4100,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4061,6 +4117,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4077,6 +4134,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4093,6 +4151,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4520,6 +4579,18 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -5736,6 +5807,396 @@ "resolve": "~1.22.2" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -6079,6 +6540,12 @@ "zod": "^3.21.4" } }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -8069,9 +8536,9 @@ "license": "MIT" }, "node_modules/@tsconfig/node22": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.0.tgz", - "integrity": "sha512-twLQ77zevtxobBOD4ToAtVmuYrpeYUh3qh+TEp+08IWhpsrIflVHqQ1F1CiPxQGL7doCdBIOOCF+1Tm833faNg==", + "version": "22.0.5", + "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.5.tgz", + "integrity": "sha512-hLf2ld+sYN/BtOJjHUWOk568dvjFQkHnLNa6zce25GIH+vxKfvTgm3qpaH6ToF5tu/NN0IH66s+Bb5wElHrLcw==", "dev": true, "license": "MIT" }, @@ -9538,7 +10005,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -9570,7 +10036,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -9588,7 +10053,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, "node_modules/alien-signals": { @@ -10438,6 +10902,15 @@ "node": ">= 4.5.0" } }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/autobind-decorator": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/autobind-decorator/-/autobind-decorator-1.4.3.tgz", @@ -13415,6 +13888,12 @@ "node": ">=7.0.0" } }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, "node_modules/colormin": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", @@ -13810,9 +14289,9 @@ "dev": true }, "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -13820,6 +14299,10 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cosmiconfig": { @@ -14010,7 +14493,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -14677,6 +15159,15 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -15685,6 +16176,7 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -16558,6 +17050,15 @@ "node": ">=0.8.0" } }, + "node_modules/eventsource-parser": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz", + "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -16734,6 +17235,24 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-rate-limit": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.1.tgz", + "integrity": "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -16850,11 +17369,16 @@ "node": ">= 0.4" } }, + "node_modules/fast-copy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz", + "integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -16892,11 +17416,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, "funding": [ { "type": "github", @@ -18266,6 +18795,12 @@ "he": "bin/he" } }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, "node_modules/history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -18320,6 +18855,15 @@ "node": ">=0.10.0" } }, + "node_modules/hono": { + "version": "4.12.18", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", + "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/hpagent": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz", @@ -18889,6 +19433,15 @@ "node": ">=0.10.0" } }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -19350,6 +19903,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -19571,7 +20130,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -21503,11 +22061,19 @@ "dev": true, "license": "MIT" }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21598,6 +22164,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -22623,7 +23195,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -23456,6 +24027,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -23967,7 +24547,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -24076,6 +24655,105 @@ "node": ">=6" } }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pino-pretty/node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/pino-pretty/node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -24085,6 +24763,15 @@ "node": ">= 6" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -27543,6 +28230,22 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, "node_modules/promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -27844,6 +28547,12 @@ ], "license": "MIT" }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, "node_modules/ramda": { "version": "0.28.0", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", @@ -28886,6 +29595,15 @@ "node": ">=8.10.0" } }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/recast": { "version": "0.11.23", "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", @@ -29280,7 +29998,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -29500,6 +30217,49 @@ "fsevents": "~2.3.2" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/router/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/router/node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -29651,6 +30411,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -29962,7 +30731,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -29974,7 +30742,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -30312,6 +31079,15 @@ "dev": true, "license": "MIT" }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -30472,6 +31248,15 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -31284,6 +32069,24 @@ "node": ">=0.8" } }, + "node_modules/thread-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz", + "integrity": "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==", + "license": "MIT", + "dependencies": { + "real-require": "^1.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/thread-stream/node_modules/real-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-1.0.0.tgz", + "integrity": "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==", + "license": "MIT" + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -32464,12 +33267,12 @@ } }, "node_modules/tsx": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", - "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "license": "MIT", "dependencies": { - "esbuild": "~0.25.0", + "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -32482,6 +33285,463 @@ "fsevents": "~2.3.3" } }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, "node_modules/tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -35269,7 +36529,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -37276,126 +38535,147 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "dev": true, "optional": true }, "@esbuild/android-arm": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "dev": true, "optional": true }, "@esbuild/android-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "dev": true, "optional": true }, "@esbuild/android-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "dev": true, "optional": true }, "@esbuild/darwin-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "dev": true, "optional": true }, "@esbuild/darwin-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "dev": true, "optional": true }, "@esbuild/freebsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "dev": true, "optional": true }, "@esbuild/linux-arm": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "dev": true, "optional": true }, "@esbuild/linux-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "dev": true, "optional": true }, "@esbuild/linux-ia32": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "dev": true, "optional": true }, "@esbuild/linux-loong64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "dev": true, "optional": true }, "@esbuild/linux-mips64el": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "dev": true, "optional": true }, "@esbuild/linux-ppc64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "dev": true, "optional": true }, "@esbuild/linux-riscv64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "dev": true, "optional": true }, "@esbuild/linux-s390x": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "dev": true, "optional": true }, "@esbuild/linux-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "dev": true, "optional": true }, "@esbuild/netbsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "dev": true, "optional": true }, "@esbuild/netbsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "dev": true, "optional": true }, "@esbuild/openbsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "dev": true, "optional": true }, "@esbuild/openbsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "dev": true, "optional": true }, "@esbuild/openharmony-arm64": { @@ -37409,24 +38689,28 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "dev": true, "optional": true }, "@esbuild/win32-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "dev": true, "optional": true }, "@esbuild/win32-ia32": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "dev": true, "optional": true }, "@esbuild/win32-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "dev": true, "optional": true }, "@eslint-community/eslint-utils": { @@ -37710,6 +38994,12 @@ "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", "requires": {} }, + "@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "requires": {} + }, "@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -38552,6 +39842,247 @@ "resolve": "~1.22.2" } }, + "@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "requires": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "dependencies": { + "accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "requires": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + } + }, + "body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "requires": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + } + }, + "content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==" + }, + "cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==" + }, + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "requires": { + "ms": "^2.1.3" + } + }, + "eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "requires": { + "eventsource-parser": "^3.0.1" + } + }, + "express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "requires": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + } + }, + "finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "requires": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + } + }, + "fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==" + }, + "http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "requires": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + } + }, + "iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" + }, + "merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==" + }, + "mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==" + }, + "mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "requires": { + "mime-db": "^1.54.0" + } + }, + "negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==" + }, + "qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "requires": { + "side-channel": "^1.1.0" + } + }, + "raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "requires": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + } + }, + "send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "requires": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + } + }, + "serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "requires": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + } + }, + "statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==" + }, + "type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "requires": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + } + } + } + }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -39492,7 +41023,39 @@ } }, "@overture-stack/arranger-mcp-server": { - "version": "file:apps/mcp-server" + "version": "file:apps/mcp-server", + "requires": { + "@modelcontextprotocol/sdk": "^1.29.0", + "@tsconfig/node22": "^22.0.5", + "@types/cors": "^2.8.12", + "@types/express": "^4.17.14", + "@types/node": "^25.6.2", + "cors": "^2.8.6", + "dotenv": "^16.6.1", + "express": "^4.21.2", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "tsx": "^4.21.0", + "typescript": "^5.8.3", + "zod": "^3.25.76" + }, + "dependencies": { + "@types/node": { + "version": "25.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz", + "integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==", + "dev": true, + "requires": { + "undici-types": "~7.19.0" + } + }, + "undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "dev": true + } + } }, "@overture-stack/arranger-search-server": { "version": "file:apps/search-server", @@ -39557,6 +41120,11 @@ "zod": "^3.21.4" } }, + "@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" + }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -40881,9 +42449,9 @@ "dev": true }, "@tsconfig/node22": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.0.tgz", - "integrity": "sha512-twLQ77zevtxobBOD4ToAtVmuYrpeYUh3qh+TEp+08IWhpsrIflVHqQ1F1CiPxQGL7doCdBIOOCF+1Tm833faNg==", + "version": "22.0.5", + "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.5.tgz", + "integrity": "sha512-hLf2ld+sYN/BtOJjHUWOk568dvjFQkHnLNa6zce25GIH+vxKfvTgm3qpaH6ToF5tu/NN0IH66s+Bb5wElHrLcw==", "dev": true }, "@turbo/darwin-64": { @@ -41954,7 +43522,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, "requires": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -41965,8 +43532,7 @@ "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" } } }, @@ -41981,7 +43547,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, "requires": { "ajv": "^8.0.0" } @@ -42584,6 +44149,11 @@ "dev": true, "optional": true }, + "atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" + }, "autobind-decorator": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/autobind-decorator/-/autobind-decorator-1.4.3.tgz", @@ -44948,6 +46518,11 @@ "simple-swizzle": "^0.2.2" } }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, "colormin": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", @@ -45228,9 +46803,9 @@ "dev": true }, "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "requires": { "object-assign": "^4", "vary": "^1" @@ -45381,7 +46956,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -45868,6 +47442,11 @@ "@babel/runtime": "^7.21.0" } }, + "dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" + }, "de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -46626,6 +48205,7 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dev": true, "requires": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", @@ -47215,6 +48795,11 @@ "original": ">=0.0.5" } }, + "eventsource-parser": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz", + "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==" + }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -47375,6 +48960,14 @@ } } }, + "express-rate-limit": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.1.tgz", + "integrity": "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==", + "requires": { + "ip-address": "^10.2.0" + } + }, "exsolve": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", @@ -47440,11 +49033,15 @@ } } }, + "fast-copy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz", + "integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { "version": "3.3.3", @@ -47476,11 +49073,15 @@ "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", "dev": true }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, "fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==" }, "fastparse": { "version": "1.1.2", @@ -48441,6 +50042,11 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + }, "history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -48489,6 +50095,11 @@ "parse-passwd": "^1.0.0" } }, + "hono": { + "version": "4.12.18", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", + "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==" + }, "hpagent": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz", @@ -48907,6 +50518,11 @@ "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", "dev": true }, + "ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -49199,6 +50815,11 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" + }, "is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -49332,8 +50953,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "isobject": { "version": "3.0.1", @@ -50662,11 +52282,15 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, + "jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==" + }, "joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" }, "jquery": { "version": "3.7.1", @@ -50733,6 +52357,11 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==" + }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -51511,8 +53140,7 @@ "minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "minipass": { "version": "7.1.2", @@ -52125,6 +53753,11 @@ "es-object-atoms": "^1.0.0" } }, + "on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" + }, "on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -52489,8 +54122,7 @@ "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-parse": { "version": "1.0.7", @@ -52567,12 +54199,89 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, + "pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "requires": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + } + }, + "pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "requires": { + "split2": "^4.0.0" + } + }, + "pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", + "requires": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "dependencies": { + "pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==" + }, + "strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==" + } + } + }, + "pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==" + }, "pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true }, + "pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==" + }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -55096,6 +56805,11 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==" + }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -55304,6 +57018,11 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, "ramda": { "version": "0.28.0", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", @@ -56101,6 +57820,11 @@ "picomatch": "^2.2.1" } }, + "real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" + }, "recast": { "version": "0.11.23", "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", @@ -56405,8 +58129,7 @@ "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "require-main-filename": { "version": "1.0.1", @@ -56558,6 +58281,33 @@ "fsevents": "~2.3.2" } }, + "router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "requires": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "dependencies": { + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "requires": { + "ms": "^2.1.3" + } + }, + "path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==" + } + } + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -56661,6 +58411,11 @@ "is-regex": "^1.2.1" } }, + "safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -56901,7 +58656,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -56909,8 +58663,7 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "shell-quote": { "version": "1.6.1", @@ -57170,6 +58923,14 @@ } } }, + "sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "requires": { + "atomic-sleep": "^1.0.0" + } + }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -57300,6 +59061,11 @@ } } }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -57884,6 +59650,21 @@ "thenify": ">= 3.1.0 < 4" } }, + "thread-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz", + "integrity": "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==", + "requires": { + "real-require": "^1.0.0" + }, + "dependencies": { + "real-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-1.0.0.tgz", + "integrity": "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==" + } + } + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -58570,13 +60351,204 @@ } }, "tsx": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", - "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "requires": { - "esbuild": "~0.25.0", + "esbuild": "~0.27.0", "fsevents": "~2.3.3", "get-tsconfig": "^4.7.5" + }, + "dependencies": { + "@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "optional": true + }, + "@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "optional": true + }, + "@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "optional": true + }, + "esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "requires": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + } } }, "tty-browserify": { @@ -60430,7 +62402,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index ed866a48e..9e92399a5 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,9 @@ "graphql-router:build": "npm run build --w modules/graphql-router", "graphql-router:watch": "npm run watch --w modules/graphql-router", "install:memory-safe": "npm i --ignore-scripts && npm rebuild --foreground-scripts --workspaces --loglevel=warn", + "mcp-server": "npm run start --w apps/mcp-server", + "mcp-server:dev": "npm run dev --w apps/mcp-server", + "mcp-server:inspect": "npm run inspect --w apps/mcp-server", "modules:build": "npm run build --w modules", "modules:tag": "npm version --ws --force-publish --yes", "modules:watch": "npm run watch --w modules", From 04a2e9fcdeb9974c1a82387442ff84244e0094c2 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 21 May 2026 11:30:39 -0400 Subject: [PATCH 02/15] =?UTF-8?q?=F0=9F=93=9D=20Update=20MCP=20Server=20RE?= =?UTF-8?q?ADME?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/README.md | 177 ++++++++++++++++++++++++++++---------- 1 file changed, 131 insertions(+), 46 deletions(-) diff --git a/apps/mcp-server/README.md b/apps/mcp-server/README.md index 05f9e5f8a..cf5913c44 100644 --- a/apps/mcp-server/README.md +++ b/apps/mcp-server/README.md @@ -1,68 +1,153 @@ -# Arranger MCP Server Foundation +# Arranger MCP Server -This app is the starting point for an MCP server that learns how to talk to Arranger by consuming Arranger's introspection endpoints. +This app is an MCP server that learns how to talk to Arranger by consuming Arranger's introspection endpoints. -The current scaffold does not implement a full MCP transport or SDK binding yet. Instead, it defines: +The current scaffold implements the Streamable HTTP MCP transport using **v1.x** of the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk/tree/v1.x). -- how to read Arranger introspection -- how to model that information as MCP-friendly resources -- which MCP tools are natural to expose first +## Folder Structure -## Why this exists +```text +src/ +├── arranger/ +│ ├── client.ts # fetches Arranger introspection endpoints +│ ├── types.ts # response types for introspection payloads +│ └── validation.ts # validates the connection to Arranger +├── http/ +│ └── app.ts # MCP express app with Streamable HTTP transport +├── mcp/ +│ ├── resources.ts # registers MCP resources +│ └── tools.ts # registers MCP tools +├── utils/ +│ ├── config.ts # env/config parsing +│ ├── inMemoryEventStore.ts # in-memory storage util for dev +│ └── logger.ts # pino logger wrapper +├── index.ts # entrypoint for the application +└── server.ts # creates the MCP server +``` -The intended flow is: +## Quick Start -1. call Arranger's `/introspection` -2. call Arranger's `/introspection/sqon` -3. call Arranger's `/introspection/:catalogId` -4. expose those results to MCP clients as resources and tool-backed lookups +1. Install dependencies: -## Tools vs skills +```bash +# from project root +npm ci +``` -In this context: +2. Configure environment variables: -- **tools** are callable operations an MCP client can invoke, such as "list catalogs" or "get SQON schema" -- **resources** are readable documents the MCP client can fetch, such as the server introspection payload or a catalog field listing -- **skills** are not part of the MCP standard itself; they are higher-level agent behaviors or authored instructions layered on top of tools/resources +> [!NOTE] +> See [Configuration](#configuration) for more details. -For this scaffold, the important MCP building blocks are tools and resources. +```bash +# from apps/mcp-server +cp .env.schema .env +``` -## Folder layout +3. Build Arranger modules: -```text -src/ - arranger/ - client.ts # fetches Arranger introspection endpoints - types.ts # response types for introspection payloads - mcp/ - resources.ts # MCP-facing resource definitions backed by introspection - tools.ts # MCP-facing tool definitions backed by introspection - types.ts # simple MCP-ish types for the scaffold - config.ts # env/config parsing for the future MCP server - index.ts # composition entrypoint for the scaffold +```bash +# from project root +npm run modules:build ``` -## Intended first MCP features +4. (Optional) Ensure Elasticsearch and Arranger Server are running. -- `list_catalogs` -- `get_sqon_schema` -- `get_catalog_fields` +> [!NOTE] +> This is only necessary if you are developing against a local Arranger Server. See [Testing](#testing) for more details. -Those all map directly to already-implemented Arranger introspection endpoints. +```bash +# from project root +make start-es +ES_INDEX=file_centric DOCUMENT_TYPE=file CONFIGS_PATH=$(pwd)/docker/server npm run dev:server +``` -## Not implemented yet +5. Start the MCP Server: -- actual MCP SDK bootstrap -- stdin/stdout server transport -- authentication -- query execution tools -- SQON generation helpers beyond introspection exposure +```bash +# from project root +npm run mcp-server:dev +``` + +## Configuration + +Configuration of this application is done by providing [environment variables](#environment-variables) to the application at run time. + +> [!WARNING] +> If **required** environment variables are not available or misconfigured at run time, the application will shut down immediately. + +An example environment variables file is located at [`.env.schema`](./.env.schema). This example file lists all available configuration variables and is prepopulated with default values that should work to run the application locally. You can copy the contents of this file to populate a `.env`: + +```bash +# from apps/mcp-server +cp .env.schema .env +``` + +### Environment Variables + +| Name | Description | Type | Required | Default | +| -------------------------- | ----------------------------------------------------------------------- | -------- | ------------ | ----------------------- | +| `ARRANGER_BASE_URL` | URL for the Arranger Server | `string` | **Required** | `http://localhost:5050` | +| `ARRANGER_CATALOGUES` | Comma-separated list of Arranger catalogues to expose to the MCP Server | `string` | **Required** | `server` | +| `ARRANGER_REQUEST_TIMEOUT` | Timeout for requests to Arranger | `number` | Optional | `10_0000` | +| `MCP_HOST` | Host URL for the MCP server | `string` | Optional | `0.0.0.0` | +| `MCP_PORT` | Port the MCP Server will listen for requests on | `number` | Optional | `3100` | +| `MCP_PATH` | Endpoint for the MCP Stremable HTTP transport | `string` | Optional | `/mcp` | +| `LOG_LEVEL` | Pino [log level](https://getpino.io/#/docs/api?id=level-1) | `string` | Optional | `info` | + +## Testing + +### Local Arranger -## Suggested next step +To test the MCP Server against a **local** instance of Arranger Server: -When you're ready to implement the actual MCP server, keep this app focused on: +1. Confirm your [`apps/mcp-server/.env`](.env) configuration aligns with your local Arranger server. -- fetching and caching Arranger introspection -- exposing catalog and SQON metadata to MCP clients +2. Ensure ES and Arranger Server are running: -Then add query execution tools only after the metadata contract feels stable. +```bash +# from project root + +# start ES (note: you may need to seed ES with `make seed-es` after if this is your first time) +make start-es + +# start Arranger Server (config may vary) +ES_INDEX=file_centric DOCUMENT_TYPE=file CONFIGS_PATH=$(pwd)/docker/server npm run dev:server +``` + +3. Start the MCP Server: + +```bash +# from project root +npm run mcp-server:dev +``` + +4. Start the [MCP Inspector](https://github.com/modelcontextprotocol/inspector): + +```bash +# from project root +npm run mcp-server:inspect +``` + +5. You can then open the MCP Inspector URL in your web browser (`http://localhost:6274/?MCP_PROXY_AUTH_TOKEN={AUTH_TOKEN}`), connect to the MCP Server via Streamable HTTP, and test the Resources and Tools. + +### Remote Arranger + +To test against a **remote** instance of Arranger Server: + +1. Update the `ARRANGER_BASE_URL` and `ARRANGER_CATALOGUES` in your MCP Server `.env` file to point to and reflect the state of your remote Arranger. +2. Follow steps 3-5 of the [**local**](#local-arranger) testing instructions. + +### LM Studio + +To test with **LM Studio** instead of MCP Inspector: + +- Follow the LM Studio instructions to add an MCP server configuration: https://lmstudio.ai/docs/app/mcp + - Provide the config JSON in [`apps/mcp-server/mcp-inspector.json`](./mcp-inspector.json) + +## Not Implemented Yet + +- stdin/stdout server transport +- authentication +- query execution tools +- SQON generation helpers beyond introspection exposure From 6ebb16c268a2805bee90778ec08a1cef46cdd5ae Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Fri, 22 May 2026 10:51:57 -0400 Subject: [PATCH 03/15] =?UTF-8?q?=E2=9C=85=20Add=20Unit=20Tests=20for=20`v?= =?UTF-8?q?alidateArrangerConnection`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/arranger/validation.test.ts | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 apps/mcp-server/src/arranger/validation.test.ts diff --git a/apps/mcp-server/src/arranger/validation.test.ts b/apps/mcp-server/src/arranger/validation.test.ts new file mode 100644 index 000000000..5ef0eb249 --- /dev/null +++ b/apps/mcp-server/src/arranger/validation.test.ts @@ -0,0 +1,126 @@ +import assert from 'node:assert'; +import { mock, suite, test } from 'node:test'; + +import { type ArrangerIntrospectionClient } from '#arranger/client.js'; +import type { + ArrangerCatalogIntrospection, + ArrangerServerIntrospection, + ArrangerSqonIntrospection, +} from '#arranger/types.js'; +import { validateArrangerConnection } from '#arranger/validation.js'; +import { type ArrangerMcpConfig } from '#utils/config.js'; + +const mockConfig = (catalogues: string[] = ['catalog-a']): ArrangerMcpConfig => ({ + arrangerBaseUrl: 'http://arranger.test', + catalogues, + requestTimeoutMs: 1000, + mcp: { + host: '0.0.0.0', + port: 3100, + path: '/mcp', + }, +}); + +const mockServerIntrospection = (catalogIds: string[]): ArrangerServerIntrospection => ({ + catalogCount: catalogIds.length, + catalogs: Object.fromEntries( + catalogIds.map((id) => [ + id, + { + documentType: 'doc', + paths: { + graphql: `/${id}/graphql`, + introspection: `/introspection/${id}`, + }, + }, + ]), + ), + mode: catalogIds.length > 1 ? 'multiple' : 'single', + sqonSchemaPath: '/introspection/sqon', +}); + +const mockSqonIntrospection = (): ArrangerSqonIntrospection => ({ + $schema: 'https://json-schema.org/draft/2020-12/schema', + aliases: {}, + description: '', + operators: { combination: [], field: [] }, + schema: {}, + title: 'SQON', + version: '0.0.0', +}); + +const mockCatalogIntrospection = (catalogId: string): ArrangerCatalogIntrospection => ({ + catalogId, + documentType: 'doc', + generatedAt: '2026-01-01T00:00:00Z', + meta: { authFiltered: false }, + fields: {}, +}); + +const mockClient = (overrides: Partial = {}): ArrangerIntrospectionClient => ({ + getServerIntrospection: mock.fn(async () => mockServerIntrospection(['catalog-a'])), + getSqonIntrospection: mock.fn(async () => mockSqonIntrospection()), + getCatalogIntrospection: mock.fn(async (id: string) => mockCatalogIntrospection(id)), + ...overrides, +}); + +suite('validateArrangerConnection', () => { + test('resolves when introspection succeeds and all configured catalogues are available', async () => { + const config = mockConfig(['catalog-a', 'catalog-b']); + const client = mockClient({ + getServerIntrospection: mock.fn(async () => mockServerIntrospection(['catalog-a', 'catalog-b'])), + }); + + await assert.doesNotReject(validateArrangerConnection(config, client)); + }); + + test('throws when the /introspection endpoint is unreachable', async () => { + const config = mockConfig(); + const client = mockClient({ + getServerIntrospection: mock.fn(async () => { + throw new Error('Failed to fetch /introspection: 503 Service Unavailable'); + }), + }); + + await assert.rejects(validateArrangerConnection(config, client), { + message: /Arranger connection validation failed:.*\/introspection.*503/, + }); + }); + + test('throws when the /introspection/sqon endpoint is unreachable', async () => { + const config = mockConfig(); + const client = mockClient({ + getSqonIntrospection: mock.fn(async () => { + throw new Error('Failed to fetch /introspection/sqon: 404 Not Found'); + }), + }); + + await assert.rejects(validateArrangerConnection(config, client), { + message: /Arranger connection validation failed:.*\/introspection\/sqon.*404/, + }); + }); + + test('throws when a configured catalogue is not available on Arranger', async () => { + const config = mockConfig(['catalog-a', 'missing-catalog']); + const client = mockClient({ + getServerIntrospection: mock.fn(async () => mockServerIntrospection(['catalog-a'])), + }); + + await assert.rejects(validateArrangerConnection(config, client), { + message: /Configured catalogues not available on Arranger: missing-catalog/, + }); + }); + + test('throws when a network error occurs during validation', async () => { + const config = mockConfig(); + const client = mockClient({ + getServerIntrospection: mock.fn(async () => { + throw new Error('fetch failed: ECONNREFUSED'); + }), + }); + + await assert.rejects(validateArrangerConnection(config, client), { + message: /Arranger connection validation failed:.*ECONNREFUSED/, + }); + }); +}); From 38b92053601cc8ca4eb4053e77d56b4aa09ef5cc Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Fri, 22 May 2026 16:07:09 -0400 Subject: [PATCH 04/15] =?UTF-8?q?=E2=9C=85=20Add=20Unit=20Tests=20for=20`c?= =?UTF-8?q?reateArrangerMcpConfig`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/package.json | 2 +- apps/mcp-server/src/utils/config.test.ts | 290 +++++++++++++++++++++++ 2 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 apps/mcp-server/src/utils/config.test.ts diff --git a/apps/mcp-server/package.json b/apps/mcp-server/package.json index abe62c988..673e4fff3 100644 --- a/apps/mcp-server/package.json +++ b/apps/mcp-server/package.json @@ -18,7 +18,7 @@ "scripts": { "dev": "NODE_ENV=development tsx watch --include './src/**/*' ./src/index.ts", "start": "tsx ./src/index.ts", - "test": "tsx --test ./src/**/*.test.ts", + "test": "tsx --test --experimental-test-module-mocks ./src/**/*.test.ts", "inspect": "npx @modelcontextprotocol/inspector --config ./mcp-inspector.json --server mcp-server" }, "dependencies": { diff --git a/apps/mcp-server/src/utils/config.test.ts b/apps/mcp-server/src/utils/config.test.ts new file mode 100644 index 000000000..61e4a0d48 --- /dev/null +++ b/apps/mcp-server/src/utils/config.test.ts @@ -0,0 +1,290 @@ +import assert from 'node:assert'; +import { after, afterEach, before, beforeEach, mock, suite, test } from 'node:test'; + +const ENV_KEYS = [ + 'ARRANGER_BASE_URL', + 'ARRANGER_CATALOGUES', + 'ARRANGER_REQUEST_TIMEOUT_MS', + 'MCP_HOST', + 'MCP_PORT', + 'MCP_PATH', + 'LOG_LEVEL', +] as const; + +// Redefining ArrangerMcpConfig type to avoid importing from config.ts before the logger module is mocked +type ArrangerMcpConfig = { + arrangerBaseUrl: string; + catalogues: string[]; + requestTimeoutMs: number; + mcp: { + host: string; + port: number; + path: string; + }; +}; + +const originalEnv: Partial> = {}; + +/** + * Sets env vars for tests, ensuring that any keys already defined in `ENV_KEYS` are cleared before applying overrides. + * @param overrides - Object containing env var values to set for the test. Keys should be from `ENV_KEYS`. + * @remark Use `undefined` to explicitly unset a variable. + * @remark This function does not restore original env vars after the test. + */ +const setEnv = (overrides: Partial>) => { + for (const key of ENV_KEYS) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete process.env[key]; + } + for (const [key, value] of Object.entries(overrides)) { + if (value !== undefined) { + process.env[key] = value; + } + } +}; + +suite('createArrangerMcpConfig', () => { + const errorLogs: string[] = []; + let loggerMock: ReturnType; + let exitMock: ReturnType; + let createArrangerMcpConfig: () => ArrangerMcpConfig; + let exitCode = 0; + + before(async () => { + // Mock the logger module **before** importing createArrangerMcpConfig + loggerMock = mock.module('#utils/logger.js', { + namedExports: { + createLogger: () => ({ + error: (msg: string) => { + errorLogs.push(msg); + }, + info: mock.fn(), + }), + }, + }); + + // Prevent the real process.exit from killing the test runner + exitMock = mock.method(process, 'exit', (code?: number) => { + exitCode = code ?? 0; + throw new Error('__process_exit__'); + }); + + // Dynamic import **after** the logger mock is registered, so that createArrangerMcpConfig uses the mocked logger + ({ createArrangerMcpConfig } = await import('#utils/config.js')); + }); + + beforeEach(() => { + // Capture original env vars before each test so they can be restored in afterEach + for (const key of ENV_KEYS) { + originalEnv[key] = process.env[key]; + } + // Reset captured logs and exit code before each test + errorLogs.length = 0; + exitCode = 0; + }); + + after(() => { + loggerMock.restore(); + exitMock.mock.restore(); + }); + + afterEach(() => { + // Restore original env vars after each test to avoid side effects + for (const key of ENV_KEYS) { + if (originalEnv[key] === undefined) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete process.env[key]; + } else { + process.env[key] = originalEnv[key]; + } + } + }); + + suite('successful configuration', () => { + test('builds config from process.env when all variables provided and valid', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com/', + ARRANGER_CATALOGUES: 'catalog-a, catalog-b ,catalog-c', + ARRANGER_REQUEST_TIMEOUT_MS: '5_000', + MCP_HOST: '127.0.0.1', + MCP_PORT: '4200', + MCP_PATH: '/custom-mcp', + LOG_LEVEL: 'debug', + }); + + const config = createArrangerMcpConfig(); + + assert.deepStrictEqual(config, { + arrangerBaseUrl: 'https://arranger.example.com', + catalogues: ['catalog-a', 'catalog-b', 'catalog-c'], + requestTimeoutMs: 5000, + mcp: { + host: '127.0.0.1', + port: 4200, + path: '/custom-mcp', + }, + }); + }); + + test('builds config with defaults for optional variables when only required variables are provided', () => { + setEnv({ + ARRANGER_BASE_URL: 'http://localhost:5050', + ARRANGER_CATALOGUES: 'catalog-a', + }); + + const config = createArrangerMcpConfig(); + + assert.deepStrictEqual(config, { + arrangerBaseUrl: 'http://localhost:5050', + catalogues: ['catalog-a'], + requestTimeoutMs: 10_000, + mcp: { + host: '0.0.0.0', + port: 3100, + path: '/mcp', + }, + }); + }); + + test('trims a single trailing slash from ARRANGER_BASE_URL', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com/', + ARRANGER_CATALOGUES: 'catalog-a', + }); + + const config = createArrangerMcpConfig(); + + assert.strictEqual(config.arrangerBaseUrl, 'https://arranger.example.com'); + }); + + test('filters empty entries from ARRANGER_CATALOGUES', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + ARRANGER_CATALOGUES: 'catalog-a,, catalog-b, ,catalog-c,', + }); + + const config = createArrangerMcpConfig(); + + assert.deepStrictEqual(config.catalogues, ['catalog-a', 'catalog-b', 'catalog-c']); + }); + }); + + suite('missing required environment variables', () => { + test('exits when ARRANGER_BASE_URL is missing', () => { + setEnv({ + ARRANGER_CATALOGUES: 'catalog-a', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /ARRANGER_BASE_URL is required and must be a valid URL/); + }); + + test('exits when ARRANGER_CATALOGUES is missing', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match( + errorLogs.join(''), + /ARRANGER_CATALOGUES is required and must be a comma-separated list of catalogue names/, + ); + }); + + test('exits when both required variables are missing', () => { + setEnv({}); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + const combined = errorLogs.join(''); + assert.match(combined, /ARRANGER_BASE_URL/); + assert.match(combined, /ARRANGER_CATALOGUES/); + }); + }); + + suite('invalid environment variables', () => { + test('exits when ARRANGER_BASE_URL is not a valid URL', () => { + setEnv({ + ARRANGER_BASE_URL: 'not-a-url', + ARRANGER_CATALOGUES: 'catalog-a', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /ARRANGER_BASE_URL must be a valid URL/); + }); + + test('exits when ARRANGER_CATALOGUES is an empty string', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + ARRANGER_CATALOGUES: '', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /ARRANGER_CATALOGUES is required and cannot be empty/); + }); + + test('exits when ARRANGER_REQUEST_TIMEOUT_MS is not a number', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + ARRANGER_CATALOGUES: 'catalog-a', + ARRANGER_REQUEST_TIMEOUT_MS: 'not-a-number', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /ARRANGER_REQUEST_TIMEOUT_MS must be a valid number/); + }); + + test('exits when ARRANGER_REQUEST_TIMEOUT_MS is not an integer', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + ARRANGER_CATALOGUES: 'catalog-a', + ARRANGER_REQUEST_TIMEOUT_MS: '1.5', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /ARRANGER_REQUEST_TIMEOUT_MS must be an integer/); + }); + + test('exits when ARRANGER_REQUEST_TIMEOUT_MS is not positive', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + ARRANGER_CATALOGUES: 'catalog-a', + ARRANGER_REQUEST_TIMEOUT_MS: '-100', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /ARRANGER_REQUEST_TIMEOUT_MS must be a positive number/); + }); + + test('exits when MCP_PORT exceeds 65535', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + ARRANGER_CATALOGUES: 'catalog-a', + MCP_PORT: '70000', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /MCP_PORT cannot exceed 65535/); + }); + + test('exits when LOG_LEVEL is not one of the allowed values', () => { + setEnv({ + ARRANGER_BASE_URL: 'https://arranger.example.com', + ARRANGER_CATALOGUES: 'catalog-a', + LOG_LEVEL: 'verbose', + }); + + assert.throws(() => createArrangerMcpConfig(), /__process_exit__/); + assert.strictEqual(exitCode, 1); + assert.match(errorLogs.join(''), /LOG_LEVEL must be one of: trace, debug, info, warn, error, fatal/); + }); + }); +}); From a3a24d0b0dc37d9e71ddf373e9f3c8d7b9dc2e96 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Wed, 27 May 2026 09:24:56 -0400 Subject: [PATCH 05/15] =?UTF-8?q?=E2=9C=85=20Add=20Integration=20Tests=20f?= =?UTF-8?q?or=20MCP=20Server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dev/sessions.md | 23 ++ .../multiconfigs/catalog-a/base.json | 38 +++ .../multiconfigs/catalog-b/base.json | 27 ++ integration-tests/mcp-server/package.json | 17 ++ .../test/assets/catalog_a.mappings.json | 9 + .../test/assets/catalog_b.mappings.json | 8 + .../mcp-server/test/index.test.ts | 240 ++++++++++++++++++ .../mcp-server/test/readResources.ts | 79 ++++++ .../mcp-server/test/readTools.ts | 81 ++++++ .../mcp-server/test/spinupActive.ts | 53 ++++ .../mcp-server/test/startMcpServer.ts | 55 ++++ integration-tests/mcp-server/tsconfig.json | 18 ++ package-lock.json | 211 ++++++++++++--- package.json | 1 + 14 files changed, 828 insertions(+), 32 deletions(-) create mode 100644 integration-tests/mcp-server/multiconfigs/catalog-a/base.json create mode 100644 integration-tests/mcp-server/multiconfigs/catalog-b/base.json create mode 100644 integration-tests/mcp-server/package.json create mode 100644 integration-tests/mcp-server/test/assets/catalog_a.mappings.json create mode 100644 integration-tests/mcp-server/test/assets/catalog_b.mappings.json create mode 100644 integration-tests/mcp-server/test/index.test.ts create mode 100644 integration-tests/mcp-server/test/readResources.ts create mode 100644 integration-tests/mcp-server/test/readTools.ts create mode 100644 integration-tests/mcp-server/test/spinupActive.ts create mode 100644 integration-tests/mcp-server/test/startMcpServer.ts create mode 100644 integration-tests/mcp-server/tsconfig.json diff --git a/.dev/sessions.md b/.dev/sessions.md index e86a976e7..78994dadb 100644 --- a/.dev/sessions.md +++ b/.dev/sessions.md @@ -6,6 +6,29 @@ Newest first. --- +## 2026-05-26 + +**Done:** +- Added `integration-tests/mcp-server` workspace with end-to-end tests for `apps/mcp-server` + - Spins up Arranger search-server in-process (multicatalog mode) with two test catalogs, then starts the MCP server pointed at it, then drives it over Streamable HTTP via the official MCP SDK Client + - Connection assertion is implicit: `validateArrangerConnection` runs before `app.listen`, so the suite reaching the test phase proves the MCP→Arranger contract works + - Test coverage: spinup/active (ping, capabilities, resource/tool listings), MCP resources (`arranger://introspection/server`, `arranger://introspection/sqon`, `arranger://introspection/catalog/{id}` via template), MCP tools (`list-catalogs`, `get-sqon-schema`, `get-catalog-fields` happy + 404 paths) + - 13 tests in 4 suites; runs against the same local ES used by `integration-tests/server` +- Added `integration-tests/mcp-server` to the root `package.json` workspaces list + +**Decisions:** +- Backend: spin up search-server in-process (mirrors `integration-tests/server`), not external nor mocked — keeps the harness self-contained while exercising the real Arranger contract. +- Coverage: multicatalog only — exercises the catalog resource template and `list-catalogs` with >1 catalog. Single-catalog is a subset and not worth doubling runtime for. +- Catalog field introspection (`/introspection/{catalogId}`) reads from `catalogConfigs.extended`, which is empty in the existing `integration-tests/server` multiconfigs. New fixtures under `integration-tests/mcp-server/multiconfigs/` include populated `extended` arrays so the tests can assert real field metadata. +- Test files live under `test/` and the entry point is `test/index.test.ts`. Node 24's test runner auto-discovers `.ts` files in `test/`; node 20 does not, so this suite requires node 24+ (consistent with the project's `engines.node >= 20` but practically aligned with the dev shell setup). +- Lazy MCP client access via `getClient: () => Client` — `node:test` suite factories run at registration time, before `before()` hooks have populated state. Each test resolves the client when it actually runs. + +**Open threads:** +- Single-catalog coverage is not exercised; can be added if MCP server adds single-catalog-specific behavior (currently it doesn't differentiate). +- Negative test for `validateArrangerConnection` failure on startup is covered by unit tests (`apps/mcp-server/src/arranger/validation.test.ts`); not duplicated as an integration test because the production startup path calls `process.exit(1)`, which is awkward to exercise in-process. + +--- + ## 2026-05-18 **Done:** diff --git a/integration-tests/mcp-server/multiconfigs/catalog-a/base.json b/integration-tests/mcp-server/multiconfigs/catalog-a/base.json new file mode 100644 index 000000000..2f4fa12d6 --- /dev/null +++ b/integration-tests/mcp-server/multiconfigs/catalog-a/base.json @@ -0,0 +1,38 @@ +{ + "catalogId": "catalog-a", + "documentType": "modelA", + "esIndex": "testing-mcp-models_a", + "extended": [ + { + "displayName": "Analysis ID", + "displayType": "keyword", + "fieldName": "analysis_id", + "isActive": true, + "isArray": false, + "primaryKey": true, + "quickSearchEnabled": false, + "type": "keyword" + }, + { + "displayName": "Age at Diagnosis", + "displayType": "number", + "fieldName": "age_at_diagnosis", + "isActive": true, + "isArray": false, + "primaryKey": false, + "quickSearchEnabled": false, + "type": "long", + "unit": "years" + }, + { + "displayName": "Vital Status", + "displayType": "keyword", + "fieldName": "vital_status", + "isActive": true, + "isArray": false, + "primaryKey": false, + "quickSearchEnabled": false, + "type": "keyword" + } + ] +} diff --git a/integration-tests/mcp-server/multiconfigs/catalog-b/base.json b/integration-tests/mcp-server/multiconfigs/catalog-b/base.json new file mode 100644 index 000000000..4884c7828 --- /dev/null +++ b/integration-tests/mcp-server/multiconfigs/catalog-b/base.json @@ -0,0 +1,27 @@ +{ + "catalogId": "catalog-b", + "documentType": "modelB", + "esIndex": "testing-mcp-models_b", + "extended": [ + { + "displayName": "Sample ID", + "displayType": "keyword", + "fieldName": "sample_id", + "isActive": true, + "isArray": false, + "primaryKey": true, + "quickSearchEnabled": false, + "type": "keyword" + }, + { + "displayName": "Created At", + "displayType": "date", + "fieldName": "createdAt", + "isActive": true, + "isArray": false, + "primaryKey": false, + "quickSearchEnabled": false, + "type": "date" + } + ] +} diff --git a/integration-tests/mcp-server/package.json b/integration-tests/mcp-server/package.json new file mode 100644 index 000000000..56496950d --- /dev/null +++ b/integration-tests/mcp-server/package.json @@ -0,0 +1,17 @@ +{ + "name": "integration-tests-mcp-server", + "dependencies": { + "@elastic/elasticsearch": "^7.17.14", + "@modelcontextprotocol/sdk": "^1.29.0", + "@overture-stack/arranger-graphql-router": "file:../../modules/graphql-router" + }, + "devDependencies": { + "prettier": "^3.4.2", + "tsx": "^4.19.3" + }, + "private": "true", + "scripts": { + "test": "tsx --test" + }, + "type": "module" +} diff --git a/integration-tests/mcp-server/test/assets/catalog_a.mappings.json b/integration-tests/mcp-server/test/assets/catalog_a.mappings.json new file mode 100644 index 000000000..3bc5c9128 --- /dev/null +++ b/integration-tests/mcp-server/test/assets/catalog_a.mappings.json @@ -0,0 +1,9 @@ +{ + "mappings": { + "properties": { + "analysis_id": { "type": "keyword" }, + "age_at_diagnosis": { "type": "long" }, + "vital_status": { "type": "keyword" } + } + } +} diff --git a/integration-tests/mcp-server/test/assets/catalog_b.mappings.json b/integration-tests/mcp-server/test/assets/catalog_b.mappings.json new file mode 100644 index 000000000..41ad28114 --- /dev/null +++ b/integration-tests/mcp-server/test/assets/catalog_b.mappings.json @@ -0,0 +1,8 @@ +{ + "mappings": { + "properties": { + "sample_id": { "type": "keyword" }, + "createdAt": { "type": "date" } + } + } +} diff --git a/integration-tests/mcp-server/test/index.test.ts b/integration-tests/mcp-server/test/index.test.ts new file mode 100644 index 000000000..6f317c88d --- /dev/null +++ b/integration-tests/mcp-server/test/index.test.ts @@ -0,0 +1,240 @@ +import { after, before, suite } from 'node:test'; +import path from 'path'; + +import { Client } from '@modelcontextprotocol/sdk/client'; +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp'; +import { stringToNumber } from '@overture-stack/arranger-types/tools'; +import dotenv from 'dotenv'; + +import ArrangerServer from '../../../apps/search-server/src/server.js'; +import { buildSearchClient, type SupportedSearchClients } from '../../../modules/graphql-router/src/index.js'; +import catalogABase from '../multiconfigs/catalog-a/base.json' with { type: 'json' }; +import catalogBBase from '../multiconfigs/catalog-b/base.json' with { type: 'json' }; + +import catalogAMappings from './assets/catalog_a.mappings.json' with { type: 'json' }; +import catalogBMappings from './assets/catalog_b.mappings.json' with { type: 'json' }; +import readResources from './readResources.js'; +import readTools from './readTools.js'; +import spinupActive from './spinupActive.js'; +import { startMcpServerForTest, type StartedMcpServer } from './startMcpServer.js'; + +dotenv.config({ path: path.resolve('../../.env.test') }); + +const esHost = process.env.ES_HOST || 'http://127.0.0.1:9200'; +const esPass = process.env.ES_PASS; +const esUser = process.env.ES_USER; +const setsIndex = process.env.ES_ARRANGER_SETS_INDEX || 'arranger-sets-mcp-testing'; +const setsType = process.env.ES_ARRANGER_SETS_TYPE || 'arranger-sets-mcp-testing'; +const searchEngine = (process.env.SEARCH_ENGINE || 'elasticsearch') satisfies SupportedSearchClients; +const arrangerPort = stringToNumber(process.env.SERVER_PORT, 5780); +const mcpPort = stringToNumber(process.env.MCP_TEST_PORT, 3199); + +const arrangerBaseUrl = `http://127.0.0.1:${arrangerPort}`; + +const catalogConfigs = [ + { + catalogId: catalogABase.catalogId, + documentType: catalogABase.documentType, + esIndex: catalogABase.esIndex, + mappings: catalogAMappings, + extendedFieldNames: catalogABase.extended.map((field) => field.fieldName), + }, + { + catalogId: catalogBBase.catalogId, + documentType: catalogBBase.documentType, + esIndex: catalogBBase.esIndex, + mappings: catalogBMappings, + extendedFieldNames: catalogBBase.extended.map((field) => field.fieldName), + }, +]; + +const configuredCatalogues = catalogConfigs.map((c) => c.catalogId); +const expectedDocumentTypes = Object.fromEntries(catalogConfigs.map((c) => [c.catalogId, c.documentType])); +const expectedFieldsByCatalog = Object.fromEntries(catalogConfigs.map((c) => [c.catalogId, c.extendedFieldNames])); + +const useESAuth = !!esPass && !!esUser; +const esClient = await buildSearchClient({ + client: searchEngine as SupportedSearchClients, + node: esHost, + ...(useESAuth && { + username: esUser, + password: esPass, + }), +}); + +const cleanupIndices = async () => { + const allTestIndices = [...catalogConfigs.map((c) => c.esIndex), setsIndex]; + const uniqueIndices = [...new Set(allTestIndices)]; + + const deletePromises = uniqueIndices.map(async (index) => { + try { + await esClient.indices.delete({ index }); + } catch (err: any) { + if (err?.meta?.body?.error?.type !== 'index_not_found_exception') { + console.warn(`Warning: Could not delete index ${index}:`, err.message); + } + } + }); + + await Promise.all(deletePromises); +}; + +// Test runtime context — populated by the `before` hook below, read lazily by tests via `getClient()`. +// This indirection is necessary because suite/test factory calls below execute at suite-registration +// time, which happens *before* the `before` hook runs. +const context: { mcpClient?: Client } = {}; +const getClient = () => { + if (!context.mcpClient) { + throw new Error('MCP client has not been initialized — `before` hook did not run successfully'); + } + return context.mcpClient; +}; + +suite('integration-tests/mcp-server', { concurrency: false }, () => { + let arrangerApp: Awaited> | undefined; + let mcpServer: StartedMcpServer | undefined; + + before(async () => { + try { + await cleanupIndices(); + } catch { + // ignore — cleanup is best-effort + } + + try { + console.error('\n------------------------------------'); + console.log('Initializing Elasticsearch testing indices\n'); + + for (const { catalogId, esIndex, mappings } of catalogConfigs) { + console.debug(' - Creating index for', catalogId); + await esClient.indices.create({ + index: esIndex, + body: mappings, + }); + } + + console.log('\n Success!'); + } catch (err) { + console.error('------------------------------------'); + console.error('FATAL: Index setup failed - aborting tests\n'); + console.error(` ${err}\n`); + console.error('------------------------------------\n'); + process.exit(1); + } + + try { + console.error('\n------------------------------------'); + console.log('Setting up Arranger - Multicatalog Mode for MCP tests\n'); + + arrangerApp = await ArrangerServer({ + catalogConfigsPath: './multiconfigs', + disableDownloads: false, + disableFilters: false, + disablePlayground: false, + disableSets: true, + enableAdmin: false, + enableNetworkAggregation: undefined, + esClient, + serverPort: arrangerPort, + setsIndex, + setsType, + }); + } catch (err) { + console.error('\n\n------------------------------------'); + console.error('FATAL: Arranger Server is not available - aborting tests\n'); + console.error(` ${err instanceof Error ? err.stack : err}\n`); + console.error('------------------------------------\n'); + process.exit(1); + } + + try { + console.error('\n------------------------------------'); + console.log('Starting MCP Server for tests\n'); + + mcpServer = await startMcpServerForTest({ + arrangerBaseUrl, + catalogues: configuredCatalogues, + requestTimeoutMs: 5000, + mcp: { + host: '127.0.0.1', + port: mcpPort, + path: '/mcp', + }, + }); + } catch (err) { + console.error('\n\n------------------------------------'); + console.error('FATAL: MCP Server failed to start (likely a connection issue with Arranger)\n'); + console.error(` ${err instanceof Error ? err.stack : err}\n`); + console.error('------------------------------------\n'); + process.exit(1); + } + + try { + console.error('\n------------------------------------'); + console.log('Connecting MCP Client over Streamable HTTP\n'); + + const mcpClient = new Client({ name: 'arranger-mcp-server-integration-tests', version: '0.0.0-test' }); + const transport = new StreamableHTTPClientTransport(new URL(mcpServer.url)); + await mcpClient.connect(transport); + context.mcpClient = mcpClient; + } catch (err) { + console.error('\n\n------------------------------------'); + console.error('FATAL: MCP Client failed to connect to MCP Server\n'); + console.error(` ${err instanceof Error ? err.stack : err}\n`); + console.error('------------------------------------\n'); + process.exit(1); + } + }); + + suite('Startup and active spinup', () => { + spinupActive({ getClient, configuredCatalogues }); + }); + + suite('Resources', () => { + readResources({ + getClient, + configuredCatalogues, + expectedDocumentTypes, + expectedFieldsByCatalog, + }); + }); + + suite('Tools', () => { + readTools({ + getClient, + configuredCatalogues, + expectedDocumentTypes, + expectedFieldsByCatalog, + }); + }); + + after(async () => { + try { + await context.mcpClient?.close(); + console.log('\nDisconnected MCP Client\n'); + } catch (err) { + console.warn('Warning: error closing MCP client:', err); + } + + try { + await mcpServer?.shutdown(); + console.log('\nStopped MCP Server\n'); + } catch (err) { + console.warn('Warning: error shutting down MCP server:', err); + } + + try { + arrangerApp?.close(); + console.log('\nStopped Arranger Server\n'); + } catch (err) { + console.warn('Warning: error closing Arranger server:', err); + } + + try { + await cleanupIndices(); + console.log('\nCleared Elasticsearch testing indices\n'); + } catch (err) { + console.warn('Warning: error cleaning up indices:', err); + } + }); +}); diff --git a/integration-tests/mcp-server/test/readResources.ts b/integration-tests/mcp-server/test/readResources.ts new file mode 100644 index 000000000..f077070ad --- /dev/null +++ b/integration-tests/mcp-server/test/readResources.ts @@ -0,0 +1,79 @@ +import assert from 'node:assert'; +import { test } from 'node:test'; + +import { type Client } from '@modelcontextprotocol/sdk/client'; + +export type ResourceEnv = { + getClient: () => Client; + configuredCatalogues: string[]; + expectedDocumentTypes: Record; + expectedFieldsByCatalog: Record; +}; + +const readJsonResource = async (mcpClient: Client, uri: string) => { + const result = await mcpClient.readResource({ uri }); + assert.ok(result.contents.length > 0, `expected contents for resource ${uri}`); + const [first] = result.contents; + assert.equal(first.mimeType, 'application/json'); + assert.equal(first.uri, uri); + assert.equal(typeof first.text, 'string'); + return JSON.parse(first.text as string); +}; + +export default ({ getClient, configuredCatalogues, expectedDocumentTypes, expectedFieldsByCatalog }: ResourceEnv) => { + test('1.reads arranger://introspection/server', async () => { + const data = await readJsonResource(getClient(), 'arranger://introspection/server'); + + assert.equal(data.mode, 'multiple'); + assert.equal(data.catalogCount, configuredCatalogues.length); + assert.equal(data.sqonSchemaPath, '/introspection/sqon'); + + for (const catalogId of configuredCatalogues) { + const catalog = data.catalogs[catalogId]; + assert.ok(catalog, `expected catalog '${catalogId}' in server introspection`); + assert.equal(catalog.documentType, expectedDocumentTypes[catalogId]); + assert.equal(catalog.paths.graphql, `/${catalogId}/graphql`); + assert.equal(catalog.paths.introspection, `/introspection/${catalogId}`); + } + }); + + test('2.reads arranger://introspection/sqon', async () => { + const data = await readJsonResource(getClient(), 'arranger://introspection/sqon'); + + assert.equal(typeof data.version, 'string'); + assert.equal(typeof data.title, 'string'); + assert.ok(data.schema, 'expected SQON schema body'); + assert.ok(data.operators, 'expected SQON operator metadata'); + assert.ok(Array.isArray(data.operators.combination)); + assert.ok(Array.isArray(data.operators.field)); + }); + + test('3.lists catalog field resources via the resource template', async () => { + const { resourceTemplates } = await getClient().listResourceTemplates(); + const template = resourceTemplates.find((t) => t.uriTemplate === 'arranger://introspection/catalog/{catalogId}'); + assert.ok(template, 'expected catalog-fields resource template to be registered'); + }); + + test('4.reads arranger://introspection/catalog/{id} for each configured catalogue', async () => { + for (const catalogId of configuredCatalogues) { + const data = await readJsonResource(getClient(), `arranger://introspection/catalog/${catalogId}`); + + assert.equal(data.catalogId, catalogId); + assert.equal(data.documentType, expectedDocumentTypes[catalogId]); + assert.equal(typeof data.generatedAt, 'string'); + assert.ok(data.fields, 'expected fields object on catalog introspection'); + + const fieldNames = Object.keys(data.fields).sort(); + const expectedFieldNames = [...expectedFieldsByCatalog[catalogId]].sort(); + assert.deepEqual(fieldNames, expectedFieldNames); + + for (const fieldName of expectedFieldNames) { + const field = data.fields[fieldName]; + assert.equal(typeof field.displayName, 'string'); + assert.equal(typeof field.type, 'string'); + assert.ok(Array.isArray(field.validOperators)); + assert.ok(field.validOperators.length > 0); + } + } + }); +}; diff --git a/integration-tests/mcp-server/test/readTools.ts b/integration-tests/mcp-server/test/readTools.ts new file mode 100644 index 000000000..8382e5141 --- /dev/null +++ b/integration-tests/mcp-server/test/readTools.ts @@ -0,0 +1,81 @@ +import assert from 'node:assert'; +import { test } from 'node:test'; + +import { type Client } from '@modelcontextprotocol/sdk/client'; + +export type ToolEnv = { + getClient: () => Client; + configuredCatalogues: string[]; + expectedDocumentTypes: Record; + expectedFieldsByCatalog: Record; +}; + +const getTextContent = (result: Awaited>): string => { + assert.notEqual(result.isError, true, `tool call returned isError: ${JSON.stringify(result)}`); + assert.ok(Array.isArray(result.content), 'expected tool result content to be an array'); + + const [first] = result.content as { type: string; text?: string }[]; + assert.ok(first, 'expected at least one content entry in tool result'); + assert.equal(first.type, 'text'); + assert.equal(typeof first.text, 'string'); + return first.text as string; +}; + +export default ({ getClient, configuredCatalogues, expectedFieldsByCatalog }: ToolEnv) => { + test("1.'list-catalogs' returns the configured catalogue IDs", async () => { + const result = await getClient().callTool({ name: 'list-catalogs' }); + const text = getTextContent(result); + + for (const catalogId of configuredCatalogues) { + assert.ok(text.includes(catalogId), `expected '${catalogId}' in list-catalogs output, got: ${text}`); + } + }); + + test("2.'get-sqon-schema' returns a valid SQON introspection payload", async () => { + const result = await getClient().callTool({ name: 'get-sqon-schema' }); + const text = getTextContent(result); + const data = JSON.parse(text); + + assert.equal(typeof data.version, 'string'); + assert.equal(typeof data.title, 'string'); + assert.ok(data.schema); + assert.ok(data.operators); + assert.ok(Array.isArray(data.operators.combination)); + assert.ok(Array.isArray(data.operators.field)); + }); + + test("3.'get-catalog-fields' returns field metadata for each configured catalogue", async () => { + for (const catalogId of configuredCatalogues) { + const result = await getClient().callTool({ + name: 'get-catalog-fields', + arguments: { catalogId }, + }); + + const text = getTextContent(result); + const data = JSON.parse(text); + + assert.equal(data.catalogId, catalogId); + assert.ok(data.fields, `expected fields object for '${catalogId}'`); + + const fieldNames = Object.keys(data.fields).sort(); + const expected = [...expectedFieldsByCatalog[catalogId]].sort(); + assert.deepEqual(fieldNames, expected); + + // Tool also declares an outputSchema -> structured content should match the text content. + const structured = (result as { structuredContent?: { catalogId: string; fields: Record } }) + .structuredContent; + assert.ok(structured, "expected 'get-catalog-fields' to return structuredContent"); + assert.equal(structured?.catalogId, catalogId); + assert.deepEqual(Object.keys(structured?.fields ?? {}).sort(), expected); + } + }); + + test("4.'get-catalog-fields' returns an error for an unknown catalogue", async () => { + const result = await getClient().callTool({ + name: 'get-catalog-fields', + arguments: { catalogId: 'this-catalog-does-not-exist' }, + }); + + assert.equal(result.isError, true, 'expected tool call to surface the upstream Arranger 404 as an MCP error'); + }); +}; diff --git a/integration-tests/mcp-server/test/spinupActive.ts b/integration-tests/mcp-server/test/spinupActive.ts new file mode 100644 index 000000000..cef69e269 --- /dev/null +++ b/integration-tests/mcp-server/test/spinupActive.ts @@ -0,0 +1,53 @@ +import assert from 'node:assert'; +import { test } from 'node:test'; + +import { type Client } from '@modelcontextprotocol/sdk/client'; + +export type SpinupEnv = { + getClient: () => Client; + configuredCatalogues: string[]; +}; + +/** + * Asserts that the MCP server started successfully and is reachable via the MCP protocol. + * + * Reaching this suite means `startMcpServerForTest` already validated the connection to Arranger + * (`validateArrangerConnection` runs before `app.listen`). Anything here is a redundancy check + * to confirm that the MCP transport is wired correctly and that the resources/tools registered + * by the server are visible to a client. + */ +export default ({ getClient, configuredCatalogues }: SpinupEnv) => { + test('1.responds to a ping over the MCP transport', async () => { + await assert.doesNotReject(getClient().ping()); + }); + + test('2.reports server name and version after initialization', async () => { + const info = getClient().getServerVersion(); + assert.ok(info, 'expected server version info to be populated after connect()'); + assert.equal(info?.name, 'arranger-mcp-server'); + }); + + test('3.advertises resources and tools capabilities', async () => { + const capabilities = getClient().getServerCapabilities(); + assert.ok(capabilities, 'expected server capabilities to be populated after connect()'); + assert.ok(capabilities?.resources, 'expected resources capability'); + assert.ok(capabilities?.tools, 'expected tools capability'); + }); + + test('4.lists the three resources registered by the MCP server', async () => { + const { resources } = await getClient().listResources(); + const uris = resources.map((resource) => resource.uri).sort(); + const expected = [ + 'arranger://introspection/server', + 'arranger://introspection/sqon', + ...configuredCatalogues.map((id) => `arranger://introspection/catalog/${id}`), + ].sort(); + assert.deepEqual(uris, expected); + }); + + test('5.lists the three tools registered by the MCP server', async () => { + const { tools } = await getClient().listTools(); + const names = tools.map((tool) => tool.name).sort(); + assert.deepEqual(names, ['get-catalog-fields', 'get-sqon-schema', 'list-catalogs']); + }); +}; diff --git a/integration-tests/mcp-server/test/startMcpServer.ts b/integration-tests/mcp-server/test/startMcpServer.ts new file mode 100644 index 000000000..67e8d770f --- /dev/null +++ b/integration-tests/mcp-server/test/startMcpServer.ts @@ -0,0 +1,55 @@ +import { type Server } from 'http'; + +import { createArrangerIntrospectionClient } from '../../../apps/mcp-server/src/arranger/client.js'; +import { validateArrangerConnection } from '../../../apps/mcp-server/src/arranger/validation.js'; +import { createHttpApp } from '../../../apps/mcp-server/src/http/app.js'; +import { createMcpServer } from '../../../apps/mcp-server/src/server.js'; +import type { ArrangerMcpConfig } from '../../../apps/mcp-server/src/utils/config.js'; + +export type StartedMcpServer = { + config: ArrangerMcpConfig; + httpServer: Server; + url: string; + shutdown: () => Promise; +}; + +/** + * Starts the MCP server in-process for integration testing. + * + * Mirrors `startServer()` from `apps/mcp-server/src/server.ts`, but accepts a config object + * directly (instead of reading `process.env`) and returns the http.Server so the test harness + * can close it during teardown. + * + * Calling `validateArrangerConnection` here also serves as the "startup proves connectivity" + * assertion: if the configured Arranger isn't reachable, this throws and the test fails. + */ +export const startMcpServerForTest = async (config: ArrangerMcpConfig): Promise => { + const introspectionClient = createArrangerIntrospectionClient(config); + + await validateArrangerConnection(config, introspectionClient); + + const { app, shutdown: shutdownTransports } = createHttpApp(config, () => + createMcpServer({ config, client: introspectionClient }), + ); + + const { host, port, path } = config.mcp; + + const httpServer = await new Promise((resolve, reject) => { + const server = app.listen(port, host, () => resolve(server)); + server.once('error', reject); + }); + + const shutdown = async () => { + await shutdownTransports(); + await new Promise((resolve, reject) => { + httpServer.close((err) => (err ? reject(err) : resolve())); + }); + }; + + return { + config, + httpServer, + url: `http://${host === '0.0.0.0' ? '127.0.0.1' : host}:${port}${path}`, + shutdown, + }; +}; diff --git a/integration-tests/mcp-server/tsconfig.json b/integration-tests/mcp-server/tsconfig.json new file mode 100644 index 000000000..321e54413 --- /dev/null +++ b/integration-tests/mcp-server/tsconfig.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + /* Modules */ + "module": "nodenext" /* Specify what module code is generated. */, + "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */, + + /* JavaScript Support */ + "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + + /* Emit */ + "noEmit": true /* Disable emitting files from a compilation. */, + + /* Type Checking */ + "erasableSyntaxOnly": true + } +} diff --git a/package-lock.json b/package-lock.json index c3cd3c128..e2d9d6c3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "apps/search-server", "apps/mcp-server", "integration-tests/import", + "integration-tests/mcp-server", "integration-tests/server", "modules/charts", "modules/components", @@ -110,6 +111,32 @@ "@types/node": "*" } }, + "apps/search-server/node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "apps/search-server/node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, "integration-tests/import": { "name": "integration-tests-import", "dependencies": { @@ -120,6 +147,18 @@ "ts-jest": "^29.0.5" } }, + "integration-tests/mcp-server": { + "name": "integration-tests-mcp-server", + "dependencies": { + "@elastic/elasticsearch": "^7.17.14", + "@modelcontextprotocol/sdk": "^1.29.0", + "@overture-stack/arranger-graphql-router": "file:../../modules/graphql-router" + }, + "devDependencies": { + "prettier": "^3.4.2", + "tsx": "^4.19.3" + } + }, "integration-tests/server": { "name": "integration-tests-server", "dependencies": { @@ -3732,6 +3771,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -3749,6 +3789,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -3766,6 +3807,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -3783,6 +3825,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -3800,6 +3843,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -3817,6 +3861,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -3834,6 +3879,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3851,6 +3897,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3868,6 +3915,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3885,6 +3933,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3902,6 +3951,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3919,6 +3969,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3936,6 +3987,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3953,6 +4005,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3970,6 +4023,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3987,6 +4041,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -4004,6 +4059,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -4021,6 +4077,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -4038,6 +4095,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -4055,6 +4113,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -4072,6 +4131,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -4106,6 +4166,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -4123,6 +4184,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -4140,6 +4202,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -4157,6 +4220,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -9067,6 +9131,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/serve-static": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", @@ -19377,6 +19451,10 @@ "resolved": "integration-tests/import", "link": true }, + "node_modules/integration-tests-mcp-server": { + "resolved": "integration-tests/mcp-server", + "link": true + }, "node_modules/integration-tests-server": { "resolved": "integration-tests/server", "link": true @@ -38536,147 +38614,168 @@ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/android-arm": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/android-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/android-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/darwin-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/darwin-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/freebsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/freebsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-arm": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-ia32": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-loong64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-mips64el": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-ppc64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-riscv64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-s390x": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/netbsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/netbsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/openbsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/openbsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/openharmony-arm64": { "version": "0.27.4", @@ -38690,28 +38789,32 @@ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/win32-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/win32-ia32": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/win32-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@eslint-community/eslint-utils": { "version": "4.4.1", @@ -41065,6 +41168,7 @@ "@overture-stack/sqon": "file:../../modules/sqon", "@tsconfig/node22": "^22.0.0", "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", "@types/node": "^22.19.13", "cors": "^2.8.5", "dotenv": "^16.0.3", @@ -41082,6 +41186,30 @@ "requires": { "@types/node": "*" } + }, + "@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } } } }, @@ -41615,8 +41743,8 @@ "@storybook/csf-plugin": "9.1.20", "@storybook/icons": "^1.4.0", "@storybook/react-dom-shim": "9.1.20", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "ts-dedent": "^2.0.0" } }, @@ -42874,7 +43002,7 @@ "integrity": "sha512-grNfPdesm/xVJPyohfW752bM8N9kuJUx2yFo0I41mZwF3BuXt4+IV4TwaCPcBtA1V3C5r2NUPyqfEUpNTtWbvA==", "dev": true, "requires": { - "@types/react": "*" + "@types/react": "^18.3.12" } }, "@types/react-table": { @@ -42882,7 +43010,7 @@ "resolved": "https://registry.npmjs.org/@types/react-table/-/react-table-6.8.15.tgz", "integrity": "sha512-5+1Fv5aqvjEvfmjDhGyJgtA/spUSuTcUWSP8e2QS6vdFUdDeRiQmqDK+2619mm9htlmWMgb8vUMUlpsKXmUgRg==", "requires": { - "@types/react": "*" + "@types/react": "^18.3.12" } }, "@types/resolve": { @@ -42891,6 +43019,15 @@ "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", "dev": true }, + "@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/serve-static": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", @@ -43687,7 +43824,7 @@ "resolved": "https://registry.npmjs.org/apollo-server/-/apollo-server-3.13.0.tgz", "integrity": "sha512-hgT/MswNB5G1r+oBhggVX4Fjw53CFLqG15yB5sN+OrYkCVWF5YwPbJWHfSWa7699JMEXJGaoVfFzcvLZK0UlDg==", "requires": { - "@types/express": "4.17.14", + "@types/express": "4.17.25", "apollo-server-core": "^3.13.0", "apollo-server-express": "^3.13.0", "express": "^4.17.1" @@ -43780,7 +43917,7 @@ "@types/accepts": "^1.3.5", "@types/body-parser": "1.19.2", "@types/cors": "2.8.12", - "@types/express": "4.17.14", + "@types/express": "4.17.25", "@types/express-serve-static-core": "4.17.31", "accepts": "^1.3.5", "apollo-server-core": "^3.13.0", @@ -50468,6 +50605,16 @@ "ts-jest": "^29.0.5" } }, + "integration-tests-mcp-server": { + "version": "file:integration-tests/mcp-server", + "requires": { + "@elastic/elasticsearch": "^7.17.14", + "@modelcontextprotocol/sdk": "^1.29.0", + "@overture-stack/arranger-graphql-router": "file:../../modules/graphql-router", + "prettier": "^3.4.2", + "tsx": "^4.19.3" + } + }, "integration-tests-server": { "version": "file:integration-tests/server", "requires": { @@ -59206,7 +59353,7 @@ "requires": { "@storybook/addon-actions": "^3.2.10", "prop-types": "^15.5.10", - "react": "^0.14.7 || ^15.0.0", + "react": "^18.3.1", "react-router": "^3.0.0 || ^4.0.0", "vue": "^2.4.4", "vue-router": "^2.7.0" diff --git a/package.json b/package.json index 9e92399a5..ff3d4c3c6 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "apps/search-server", "apps/mcp-server", "integration-tests/import", + "integration-tests/mcp-server", "integration-tests/server", "modules/charts", "modules/components", From 9f26b7fdcf7b96219e1fcb715d082995fad135d9 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Wed, 27 May 2026 12:47:41 -0400 Subject: [PATCH 06/15] =?UTF-8?q?=F0=9F=92=A1=20Update=20comments=20in=20M?= =?UTF-8?q?CP=20Server=20integration=20tests=20for=20clarity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- integration-tests/mcp-server/test/index.test.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/integration-tests/mcp-server/test/index.test.ts b/integration-tests/mcp-server/test/index.test.ts index 6f317c88d..49a5e0ccc 100644 --- a/integration-tests/mcp-server/test/index.test.ts +++ b/integration-tests/mcp-server/test/index.test.ts @@ -79,9 +79,8 @@ const cleanupIndices = async () => { await Promise.all(deletePromises); }; -// Test runtime context — populated by the `before` hook below, read lazily by tests via `getClient()`. -// This indirection is necessary because suite/test factory calls below execute at suite-registration -// time, which happens *before* the `before` hook runs. +// Test runtime context — populated by the `before` hook below, consumed by tests via `getClient()`. +// Defined here to avoid issues with test isolation and variable scope across the `before` hook and individual tests. const context: { mcpClient?: Client } = {}; const getClient = () => { if (!context.mcpClient) { @@ -94,6 +93,12 @@ suite('integration-tests/mcp-server', { concurrency: false }, () => { let arrangerApp: Awaited> | undefined; let mcpServer: StartedMcpServer | undefined; + // Does the following before tests run: + // - 1. Cleans up any existing test indices + // - 2. Initializes test indices with mappings for the test suite + // - 3. Starts an Arranger server in multicatalog mode + // - 4. Starts the MCP server + // - 5. Connects an MCP client to the MCP server and stores it in `context` for tests to use before(async () => { try { await cleanupIndices(); From 1aa391839f469d911eb1cbd38488a08651a62ab6 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 28 May 2026 11:32:19 -0400 Subject: [PATCH 07/15] =?UTF-8?q?=E2=9C=85=20Update=20MCP=20Server=20Types?= =?UTF-8?q?=20and=20Tests=20*=20Update=20`fieldShape`=20Zod=20schema=20in?= =?UTF-8?q?=20MCP=20tools=20to=20reflect=20new=20Arranger=20introspection?= =?UTF-8?q?=20response=20types=20*=20Update=20MCP=20Server=20validation=20?= =?UTF-8?q?unit=20tests=20to=20reflect=20new=20Arranger=20introspection=20?= =?UTF-8?q?response=20types=20*=20Update=20MCP=20Server=20integration=20te?= =?UTF-8?q?sts=20to=20reflect=20new=20Arranger=20introspection=20response?= =?UTF-8?q?=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/src/arranger/validation.test.ts | 1 + apps/mcp-server/src/mcp/tools.ts | 1 - integration-tests/mcp-server/test/index.test.ts | 8 ++++---- integration-tests/mcp-server/test/readResources.ts | 6 +++--- integration-tests/mcp-server/test/readTools.ts | 5 +++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/mcp-server/src/arranger/validation.test.ts b/apps/mcp-server/src/arranger/validation.test.ts index 5ef0eb249..c9565dd28 100644 --- a/apps/mcp-server/src/arranger/validation.test.ts +++ b/apps/mcp-server/src/arranger/validation.test.ts @@ -54,6 +54,7 @@ const mockCatalogIntrospection = (catalogId: string): ArrangerCatalogIntrospecti documentType: 'doc', generatedAt: '2026-01-01T00:00:00Z', meta: { authFiltered: false }, + operators: {}, fields: {}, }); diff --git a/apps/mcp-server/src/mcp/tools.ts b/apps/mcp-server/src/mcp/tools.ts index 2ad0e82bc..b3bd9edaf 100644 --- a/apps/mcp-server/src/mcp/tools.ts +++ b/apps/mcp-server/src/mcp/tools.ts @@ -7,7 +7,6 @@ const fieldShape = z.object({ displayName: z.string(), type: z.string(), unit: z.string().nullable().optional(), - validOperators: z.array(z.string()), }); export const registerTools = (server: McpServer, { client }: McpServerDeps): void => { diff --git a/integration-tests/mcp-server/test/index.test.ts b/integration-tests/mcp-server/test/index.test.ts index 49a5e0ccc..afd229fc0 100644 --- a/integration-tests/mcp-server/test/index.test.ts +++ b/integration-tests/mcp-server/test/index.test.ts @@ -7,7 +7,7 @@ import { stringToNumber } from '@overture-stack/arranger-types/tools'; import dotenv from 'dotenv'; import ArrangerServer from '../../../apps/search-server/src/server.js'; -import { buildSearchClient, type SupportedSearchClients } from '../../../modules/graphql-router/src/index.js'; +import { buildSearchClient } from '../../../modules/graphql-router/src/index.js'; import catalogABase from '../multiconfigs/catalog-a/base.json' with { type: 'json' }; import catalogBBase from '../multiconfigs/catalog-b/base.json' with { type: 'json' }; @@ -25,8 +25,8 @@ const esPass = process.env.ES_PASS; const esUser = process.env.ES_USER; const setsIndex = process.env.ES_ARRANGER_SETS_INDEX || 'arranger-sets-mcp-testing'; const setsType = process.env.ES_ARRANGER_SETS_TYPE || 'arranger-sets-mcp-testing'; -const searchEngine = (process.env.SEARCH_ENGINE || 'elasticsearch') satisfies SupportedSearchClients; -const arrangerPort = stringToNumber(process.env.SERVER_PORT, 5780); +const searchEngine = process.env.SEARCH_ENGINE || 'elasticsearch'; +const arrangerPort = stringToNumber(process.env.SERVER_PORT, 5678); const mcpPort = stringToNumber(process.env.MCP_TEST_PORT, 3199); const arrangerBaseUrl = `http://127.0.0.1:${arrangerPort}`; @@ -54,7 +54,7 @@ const expectedFieldsByCatalog = Object.fromEntries(catalogConfigs.map((c) => [c. const useESAuth = !!esPass && !!esUser; const esClient = await buildSearchClient({ - client: searchEngine as SupportedSearchClients, + client: searchEngine, node: esHost, ...(useESAuth && { username: esUser, diff --git a/integration-tests/mcp-server/test/readResources.ts b/integration-tests/mcp-server/test/readResources.ts index f077070ad..c84980487 100644 --- a/integration-tests/mcp-server/test/readResources.ts +++ b/integration-tests/mcp-server/test/readResources.ts @@ -50,7 +50,9 @@ export default ({ getClient, configuredCatalogues, expectedDocumentTypes, expect test('3.lists catalog field resources via the resource template', async () => { const { resourceTemplates } = await getClient().listResourceTemplates(); - const template = resourceTemplates.find((t) => t.uriTemplate === 'arranger://introspection/catalog/{catalogId}'); + const template = resourceTemplates.find( + (t) => t.uriTemplate === 'arranger://introspection/catalog/{catalogId}', + ); assert.ok(template, 'expected catalog-fields resource template to be registered'); }); @@ -71,8 +73,6 @@ export default ({ getClient, configuredCatalogues, expectedDocumentTypes, expect const field = data.fields[fieldName]; assert.equal(typeof field.displayName, 'string'); assert.equal(typeof field.type, 'string'); - assert.ok(Array.isArray(field.validOperators)); - assert.ok(field.validOperators.length > 0); } } }); diff --git a/integration-tests/mcp-server/test/readTools.ts b/integration-tests/mcp-server/test/readTools.ts index 8382e5141..079bfb3eb 100644 --- a/integration-tests/mcp-server/test/readTools.ts +++ b/integration-tests/mcp-server/test/readTools.ts @@ -62,8 +62,9 @@ export default ({ getClient, configuredCatalogues, expectedFieldsByCatalog }: To assert.deepEqual(fieldNames, expected); // Tool also declares an outputSchema -> structured content should match the text content. - const structured = (result as { structuredContent?: { catalogId: string; fields: Record } }) - .structuredContent; + const structured = ( + result as { structuredContent?: { catalogId: string; fields: Record } } + ).structuredContent; assert.ok(structured, "expected 'get-catalog-fields' to return structuredContent"); assert.equal(structured?.catalogId, catalogId); assert.deepEqual(Object.keys(structured?.fields ?? {}).sort(), expected); From 1bd48fd20b599f7b78fcecaac71536d2d24aee1d Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 28 May 2026 11:35:50 -0400 Subject: [PATCH 08/15] =?UTF-8?q?=F0=9F=94=A5=20Remove=20`pnpm-lock.yaml`?= =?UTF-8?q?=20*=20Remove=20unnecessary=20`pnpm-lock.yaml`,=20this=20projec?= =?UTF-8?q?t=20exclusively=20uses=20`npm`=20not=20`pnpm`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pnpm-lock.yaml | 2628 ------------------------------------------------ 1 file changed, 2628 deletions(-) delete mode 100644 pnpm-lock.yaml diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index fc522b021..000000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,2628 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - '@eslint/js': - specifier: ^9.18.0 - version: 9.39.4 - '@tsconfig/node22': - specifier: ^22.0.0 - version: 22.0.5 - '@types/node': - specifier: ^22.13.10 - version: 22.19.15 - concurrently: - specifier: ^9.1.2 - version: 9.2.1 - eslint: - specifier: ^9.18.0 - version: 9.39.4 - eslint-config-prettier: - specifier: ^10.1.1 - version: 10.1.8(eslint@9.39.4) - eslint-import-resolver-typescript: - specifier: ^3.7.0 - version: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4) - eslint-plugin-file-extension-in-import-ts: - specifier: ^2.1.1 - version: 2.1.1 - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4) - globals: - specifier: ^15.14.0 - version: 15.15.0 - prettier: - specifier: ^3.5.3 - version: 3.8.1 - prettier-plugin-organize-imports: - specifier: ^4.1.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) - typescript: - specifier: ^5.8.2 - version: 5.9.3 - typescript-eslint: - specifier: ^8.26.1 - version: 8.58.0(eslint@9.39.4)(typescript@5.9.3) - -packages: - - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} - - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.4': - resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@napi-rs/wasm-runtime@0.2.12': - resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - - '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@tsconfig/node22@22.0.5': - resolution: {integrity: sha512-hLf2ld+sYN/BtOJjHUWOk568dvjFQkHnLNa6zce25GIH+vxKfvTgm3qpaH6ToF5tu/NN0IH66s+Bb5wElHrLcw==} - - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - - '@types/node@22.19.15': - resolution: {integrity: sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==} - - '@typescript-eslint/eslint-plugin@8.58.0': - resolution: {integrity: sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.58.0 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/parser@8.58.0': - resolution: {integrity: sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/project-service@8.58.0': - resolution: {integrity: sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/scope-manager@8.58.0': - resolution: {integrity: sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.58.0': - resolution: {integrity: sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/type-utils@8.58.0': - resolution: {integrity: sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/types@8.58.0': - resolution: {integrity: sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.58.0': - resolution: {integrity: sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/utils@8.58.0': - resolution: {integrity: sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/visitor-keys@8.58.0': - resolution: {integrity: sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} - cpu: [arm] - os: [android] - - '@unrs/resolver-binding-android-arm64@1.11.1': - resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} - cpu: [arm64] - os: [android] - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} - cpu: [arm64] - os: [darwin] - - '@unrs/resolver-binding-darwin-x64@1.11.1': - resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} - cpu: [x64] - os: [darwin] - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} - cpu: [x64] - os: [freebsd] - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} - cpu: [arm64] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} - cpu: [arm64] - os: [linux] - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} - cpu: [ppc64] - os: [linux] - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} - cpu: [riscv64] - os: [linux] - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} - cpu: [riscv64] - os: [linux] - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} - cpu: [s390x] - os: [linux] - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} - cpu: [x64] - os: [linux] - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} - cpu: [x64] - os: [linux] - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} - cpu: [arm64] - os: [win32] - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} - cpu: [ia32] - os: [win32] - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} - cpu: [x64] - os: [win32] - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} - - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - brace-expansion@1.1.13: - resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} - - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} - engines: {node: 18 || 20 || >=22} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concurrently@9.2.1: - resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} - engines: {node: '>=18'} - hasBin: true - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - es-abstract@1.24.1: - resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} - - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-prettier@10.1.8: - resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-import-resolver-typescript@3.10.1: - resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - - eslint-module-utils@2.12.1: - resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-file-extension-in-import-ts@2.1.1: - resolution: {integrity: sha512-cZMQy+/nG6TU9eN2C0m3HO0N4D1t6brg0DR3YPzh0m/MHEFSfY+/2VaEbkMbtyJjPJxwlRLYGD2aGCqo2+M3bA==} - - eslint-plugin-import@2.32.0: - resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@9.39.4: - resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - generator-function@2.0.1: - resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} - engines: {node: '>= 0.4'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} - - get-tsconfig@4.13.7: - resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} - engines: {node: '>=18'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-bun-module@2.0.0: - resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - napi-postinstall@0.3.4: - resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} - - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} - - object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier-plugin-organize-imports@4.3.0: - resolution: {integrity: sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==} - peerDependencies: - prettier: '>=2.0' - typescript: '>=2.9' - vue-tsc: ^2.1.0 || 3 - peerDependenciesMeta: - vue-tsc: - optional: true - - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} - engines: {node: '>=14'} - hasBin: true - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} - - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} - - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - stable-hash@0.0.5: - resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - - typescript-eslint@8.58.0: - resolution: {integrity: sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - unrs-resolver@1.11.1: - resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - -snapshots: - - '@emnapi/core@1.9.1': - dependencies: - '@emnapi/wasi-threads': 1.2.0 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.9.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)': - dependencies: - eslint: 9.39.4 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.21.2': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.14.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.4': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@napi-rs/wasm-runtime@0.2.12': - dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.9.1 - '@tybys/wasm-util': 0.10.1 - optional: true - - '@nolyfill/is-core-module@1.0.39': {} - - '@rtsao/scc@1.1.0': {} - - '@tsconfig/node22@22.0.5': {} - - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/estree@1.0.8': {} - - '@types/json-schema@7.0.15': {} - - '@types/json5@0.0.29': {} - - '@types/node@22.19.15': - dependencies: - undici-types: 6.21.0 - - '@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.58.0 - '@typescript-eslint/type-utils': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.0 - eslint: 9.39.4 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.58.0 - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.0 - debug: 4.4.3 - eslint: 9.39.4 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.58.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) - '@typescript-eslint/types': 8.58.0 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.58.0': - dependencies: - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/visitor-keys': 8.58.0 - - '@typescript-eslint/tsconfig-utils@8.58.0(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.58.0(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.4 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.58.0': {} - - '@typescript-eslint/typescript-estree@8.58.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.58.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/visitor-keys': 8.58.0 - debug: 4.4.3 - minimatch: 10.2.5 - semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.58.0(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/scope-manager': 8.58.0 - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) - eslint: 9.39.4 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.58.0': - dependencies: - '@typescript-eslint/types': 8.58.0 - eslint-visitor-keys: 5.0.1 - - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - optional: true - - '@unrs/resolver-binding-android-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - dependencies: - '@napi-rs/wasm-runtime': 0.2.12 - optional: true - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - optional: true - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - ajv@6.14.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-regex@5.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - argparse@2.0.1: {} - - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - array-includes@3.1.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - is-string: 1.1.1 - math-intrinsics: 1.1.0 - - array.prototype.findlastindex@1.2.6: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-shim-unscopables: 1.1.0 - - array.prototype.flat@1.3.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-shim-unscopables: 1.1.0 - - array.prototype.flatmap@1.3.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-shim-unscopables: 1.1.0 - - arraybuffer.prototype.slice@1.0.4: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - - async-function@1.0.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - balanced-match@1.0.2: {} - - balanced-match@4.0.4: {} - - brace-expansion@1.1.13: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@5.0.5: - dependencies: - balanced-match: 4.0.4 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - concat-map@0.0.1: {} - - concurrently@9.2.1: - dependencies: - chalk: 4.1.2 - rxjs: 7.8.2 - shell-quote: 1.8.3 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.2 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - data-view-buffer@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-offset@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - debug@3.2.7: - dependencies: - ms: 2.1.3 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - emoji-regex@8.0.0: {} - - es-abstract@1.24.1: - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.20 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - es-shim-unscopables@1.1.0: - dependencies: - hasown: 2.0.2 - - es-to-primitive@1.3.0: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - - escalade@3.2.0: {} - - escape-string-regexp@4.0.0: {} - - eslint-config-prettier@10.1.8(eslint@9.39.4): - dependencies: - eslint: 9.39.4 - - eslint-import-resolver-node@0.3.9: - dependencies: - debug: 3.2.7 - is-core-module: 2.16.1 - resolve: 1.22.11 - transitivePeerDependencies: - - supports-color - - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4): - dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.3 - eslint: 9.39.4 - get-tsconfig: 4.13.7 - is-bun-module: 2.0.0 - stable-hash: 0.0.5 - tinyglobby: 0.2.15 - unrs-resolver: 1.11.1 - optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - eslint: 9.39.4 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4) - transitivePeerDependencies: - - supports-color - - eslint-plugin-file-extension-in-import-ts@2.1.1: - dependencies: - is-core-module: 2.16.1 - resolve: 1.22.11 - - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.9 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 9.39.4 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.5 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint-visitor-keys@5.0.1: {} - - eslint@9.39.4: - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.4 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - function-bind@1.1.2: {} - - function.prototype.name@1.1.8: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.2 - is-callable: 1.2.7 - - functions-have-names@1.2.3: {} - - generator-function@2.0.1: {} - - get-caller-file@2.0.5: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-symbol-description@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - - get-tsconfig@4.13.7: - dependencies: - resolve-pkg-maps: 1.0.0 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - globals@14.0.0: {} - - globals@15.15.0: {} - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - - gopd@1.2.0: {} - - has-bigints@1.1.0: {} - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-proto@1.2.0: - dependencies: - dunder-proto: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 - - is-array-buffer@3.0.5: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-async-function@2.1.1: - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 - - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-bun-module@2.0.0: - dependencies: - semver: 7.7.4 - - is-callable@1.2.7: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-data-view@1.0.2: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 - - is-date-object@1.1.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-extglob@2.1.1: {} - - is-finalizationregistry@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-fullwidth-code-point@3.0.0: {} - - is-generator-function@1.1.2: - dependencies: - call-bound: 1.0.4 - generator-function: 2.0.1 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-map@2.0.3: {} - - is-negative-zero@2.0.3: {} - - is-number-object@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.4: - dependencies: - call-bound: 1.0.4 - - is-string@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-symbol@1.1.1: - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.20 - - is-weakmap@2.0.2: {} - - is-weakref@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-weakset@2.0.4: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - isarray@2.0.5: {} - - isexe@2.0.0: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@1.0.2: - dependencies: - minimist: 1.2.8 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - math-intrinsics@1.1.0: {} - - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.5 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.13 - - minimist@1.2.8: {} - - ms@2.1.3: {} - - napi-postinstall@0.3.4: {} - - natural-compare@1.4.0: {} - - object-inspect@1.13.4: {} - - object-keys@1.1.1: {} - - object.assign@4.1.7: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - object.fromentries@2.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-object-atoms: 1.1.1 - - object.groupby@1.0.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.1 - - object.values@1.2.1: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - own-keys@1.0.1: - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - picomatch@4.0.4: {} - - possible-typed-array-names@1.1.0: {} - - prelude-ls@1.2.1: {} - - prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3): - dependencies: - prettier: 3.8.1 - typescript: 5.9.3 - - prettier@3.8.1: {} - - punycode@2.3.1: {} - - reflect.getprototypeof@1.0.10: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - - regexp.prototype.flags@1.5.4: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - - require-directory@2.1.1: {} - - resolve-from@4.0.0: {} - - resolve-pkg-maps@1.0.0: {} - - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - rxjs@7.8.2: - dependencies: - tslib: 2.8.1 - - safe-array-concat@1.1.3: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 - - safe-push-apply@1.0.0: - dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - - semver@6.3.1: {} - - semver@7.7.4: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - - set-proto@1.0.0: - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - shell-quote@1.8.3: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - stable-hash@0.0.5: {} - - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string.prototype.trim@1.2.10: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.1 - es-object-atoms: 1.1.1 - has-property-descriptors: 1.0.2 - - string.prototype.trimend@1.0.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-bom@3.0.0: {} - - strip-json-comments@3.1.1: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tree-kill@1.2.2: {} - - ts-api-utils@2.5.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - tsconfig-paths@3.15.0: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - - tslib@2.8.1: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typed-array-byte-length@1.0.3: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - - typed-array-byte-offset@1.0.4: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 - - typed-array-length@1.0.7: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 - - typescript-eslint@8.58.0(eslint@9.39.4)(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.58.0(@typescript-eslint/parser@8.58.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.0(eslint@9.39.4)(typescript@5.9.3) - eslint: 9.39.4 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} - - unbox-primitive@1.1.0: - dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 - - undici-types@6.21.0: {} - - unrs-resolver@1.11.1: - dependencies: - napi-postinstall: 0.3.4 - optionalDependencies: - '@unrs/resolver-binding-android-arm-eabi': 1.11.1 - '@unrs/resolver-binding-android-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-x64': 1.11.1 - '@unrs/resolver-binding-freebsd-x64': 1.11.1 - '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 - '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 - '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-musl': 1.11.1 - '@unrs/resolver-binding-wasm32-wasi': 1.11.1 - '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 - '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 - '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-builtin-type@1.2.1: - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.2 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.20 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-typed-array@1.1.20: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - y18n@5.0.8: {} - - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yocto-queue@0.1.0: {} From 3d1503a3969f0aa704eba15ae5772d4e4f9c4072 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 28 May 2026 11:55:56 -0400 Subject: [PATCH 09/15] =?UTF-8?q?=F0=9F=92=9A=20Move=20MCP=20Server=20`tsx?= =?UTF-8?q?`=20from=20`devDependencies`=20to=20`dependencies`=20*=20Moved?= =?UTF-8?q?=20`tsx`=20from=20`devDependencies`=20to=20`dependencies`=20in?= =?UTF-8?q?=20`apps/mcp-server/package.json`=20for=20the=20Jenkins=20Docke?= =?UTF-8?q?r=20build=20(which=20runs=20`npm=20ci=20--omit=3Ddev`)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/package.json | 2 +- package-lock.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mcp-server/package.json b/apps/mcp-server/package.json index 673e4fff3..bb356113d 100644 --- a/apps/mcp-server/package.json +++ b/apps/mcp-server/package.json @@ -28,6 +28,7 @@ "express": "^4.21.2", "pino": "^10.3.1", "pino-pretty": "^13.1.3", + "tsx": "^4.21.0", "zod": "^3.25.76" }, "devDependencies": { @@ -35,7 +36,6 @@ "@types/cors": "^2.8.12", "@types/express": "^4.17.14", "@types/node": "^25.6.2", - "tsx": "^4.21.0", "typescript": "^5.8.3" }, "imports": { diff --git a/package-lock.json b/package-lock.json index e2deaaef3..e74867221 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "express": "^4.21.2", "pino": "^10.3.1", "pino-pretty": "^13.1.3", + "tsx": "^4.21.0", "zod": "^3.25.76" }, "devDependencies": { @@ -59,7 +60,6 @@ "@types/cors": "^2.8.12", "@types/express": "^4.17.14", "@types/node": "^25.6.2", - "tsx": "^4.21.0", "typescript": "^5.8.3" } }, From 7d226172967577f9594d97cea3d19e06896291cd Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 28 May 2026 14:14:12 -0400 Subject: [PATCH 10/15] =?UTF-8?q?=F0=9F=91=B7=20Add=20Dockerfile=20target?= =?UTF-8?q?=20for=20`mcp-server`=20*=20Updates=20`Dockerfile.local`=20and?= =?UTF-8?q?=20`Dockerfile.jenkins`=20(and=20their=20corresponding=20`.dock?= =?UTF-8?q?erignore`=20files)=20to=20include=20build=20targets=20for=20`mc?= =?UTF-8?q?p-server`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dev/sessions.md | 14 +++++++++++++ docker/Dockerfile.jenkins | 29 ++++++++++++++++++++++++++ docker/Dockerfile.jenkins.dockerignore | 1 + docker/Dockerfile.local | 25 ++++++++++++++++++++++ docker/Dockerfile.local.dockerignore | 1 + 5 files changed, 70 insertions(+) diff --git a/.dev/sessions.md b/.dev/sessions.md index 6d25b9902..18f94a970 100644 --- a/.dev/sessions.md +++ b/.dev/sessions.md @@ -15,15 +15,29 @@ Newest first. - Added `description` as an optional catalogue config property (`configOptionalProperties.DESCRIPTION` in `modules/types`) — surfaces in both the root `/introspection` response and the per-catalogue `/introspection/:catalogId` response via conditional spread (key absent when not configured, not `undefined`) - Restructured `CatalogIntrospectionResponse`: removed `validOperators` from individual fields; added top-level `operators: Record` keyed by field type; `buildFieldOperators()` in `buildCatalogueIntrospection.ts` - Updated unit tests to match new shape; added coverage for `description` present/absent and `operators` deduplication +- Added `mcp-server` Docker target to both `docker/Dockerfile.local` and `docker/Dockerfile.jenkins`, mirroring the existing `server` target structure + - Both targets `COPY --from=scaffolding` the shared `node_modules` and `apps/mcp-server` source; no internal modules are copied because the MCP server is standalone (talks to Arranger over HTTP, not ES directly) + - CMD runs `node_modules/.bin/tsx ./apps/mcp-server/src/index.ts` (no shell-level pre-check; `validateArrangerConnection` runs in-app at startup) + - EXPOSE 3100 matches the `MCP_PORT` default +- Updated `docker/Dockerfile.jenkins` scaffolding stage to include `--workspace apps/mcp-server` in the `npm ci --omit=dev` install, so the jenkins production image installs the MCP server's runtime deps +- Moved `tsx` from `devDependencies` to `dependencies` in `apps/mcp-server/package.json` (load-bearing for the jenkins build, which runs `npm ci --omit=dev`; mirrors what `apps/search-server` already does) +- Updated both `.dockerignore` files (`Dockerfile.local.dockerignore`, `Dockerfile.jenkins.dockerignore`) to add `!apps/mcp-server`, allowing the folder through the build context **Decisions:** + - `operators` (not `typeOperators`) — cleaner, consistent with existing "operators" vocabulary in SQON introspection - `buildFieldOperators` (not `buildTypeOperators`) — "field operators" is the established naming family in `modules/sqon` (`SqonFieldOp`, `SqonFieldOperatorDetail`, `getSqonFieldOperatorDetails`) - `description` on per-catalogue response too (not just root listing) — complete data at the endpoint; LLM context optimization is the MCP layer's responsibility - `getValidOperators` → `modules/sqon` consolidation is out of scope: requires redesigning `applicableTo` data in `getSqonFieldOperatorDetails` (range types incorrectly include `filter`, `some-not-in`, `all` at present); separate roadmap item +- MCP server target does NOT use a shell wrapper or pre-flight script. The app's own `validateArrangerConnection` handles the Arranger readiness check at startup — duplicating that at the shell level would be redundant. +- Kept tsx-from-source at runtime (not a tsc pre-build) to match `apps/search-server`'s pattern. Revisiting that for both apps together is a future concern. +- Did not modify `docker-compose.yml` — that's a separate "is the MCP server part of the dev stack?" decision. **Open threads:** + - `getValidFieldOperators` → `modules/sqon` consolidation: follow-up when sqon consolidation roadmap item is picked up +- `package-lock.json` will need an `npm install` to reflect tsx moving sections in `apps/mcp-server/package.json`. +- `docker-compose.yml` does not include the MCP server. If the local Compose dev stack should boot MCP alongside server/ES/UI, that needs a follow-up (port 3100, depends_on server, ARRANGER_BASE_URL pointed at the `server` service). --- diff --git a/docker/Dockerfile.jenkins b/docker/Dockerfile.jenkins index 9feb18174..55ccf95f3 100644 --- a/docker/Dockerfile.jenkins +++ b/docker/Dockerfile.jenkins @@ -23,6 +23,7 @@ RUN npm ci \ --ignore-scripts \ --include-workspace-root=false \ --workspace apps/search-server \ + --workspace apps/mcp-server \ --workspace modules/graphql-router \ --workspace modules/types \ --workspace modules/sqon @@ -87,3 +88,31 @@ USER $APP_USER EXPOSE 5050 CMD ["/bin/sh", "-c", "scripts/ping-elasticsearch.sh && node_modules/.bin/tsx ./apps/search-server/index.ts"] + +####################################################### +# Arranger MCP Server +####################################################### +FROM node:24-alpine AS mcp-server + +ARG APP_FOLDER +ARG APP_USER +ARG APP_GID +ARG APP_UID + +LABEL org.opencontainers.image.source=https://github.com/overture-stack/arranger +LABEL org.opencontainers.image.description="Arranger MCP Server" + +RUN apk --no-cache add shadow \ + && groupmod -g $APP_GID $APP_USER \ + && usermod -u $APP_UID -g $APP_GID $APP_USER + +WORKDIR $APP_FOLDER + +COPY --from=scaffolding --chown=$APP_USER:$APP_USER $APP_FOLDER/node_modules ./node_modules +COPY --from=scaffolding --chown=$APP_USER:$APP_USER $APP_FOLDER/apps/mcp-server ./apps/mcp-server + +USER $APP_USER + +EXPOSE 3100 + +CMD ["node_modules/.bin/tsx", "./apps/mcp-server/src/index.ts"] diff --git a/docker/Dockerfile.jenkins.dockerignore b/docker/Dockerfile.jenkins.dockerignore index c658ac55d..3df526e2f 100644 --- a/docker/Dockerfile.jenkins.dockerignore +++ b/docker/Dockerfile.jenkins.dockerignore @@ -3,6 +3,7 @@ **/node_modules apps/**/* !apps/search-server +!apps/mcp-server docker-compose.yml docker docs diff --git a/docker/Dockerfile.local b/docker/Dockerfile.local index 3064d8ba9..b3793cb1a 100644 --- a/docker/Dockerfile.local +++ b/docker/Dockerfile.local @@ -77,3 +77,28 @@ EXPOSE 5050 CMD ["/bin/sh", "-c", "scripts/ping-elasticsearch.sh && node_modules/.bin/tsx ./apps/search-server/index.ts"] +####################################################### +# Arranger MCP Server +####################################################### +FROM node:24-alpine AS mcp-server + +ARG APP_FOLDER +ARG APP_USER +ARG APP_GID +ARG APP_UID + +RUN apk --no-cache add shadow \ + && groupmod -g $APP_GID $APP_USER \ + && usermod -u $APP_UID -g $APP_GID $APP_USER + +WORKDIR $APP_FOLDER + +COPY --from=scaffolding --chown=$APP_USER:$APP_USER $APP_FOLDER/node_modules ./node_modules +COPY --from=scaffolding --chown=$APP_USER:$APP_USER $APP_FOLDER/apps/mcp-server ./apps/mcp-server + +USER $APP_USER + +EXPOSE 3100 + +CMD ["node_modules/.bin/tsx", "./apps/mcp-server/src/index.ts"] + diff --git a/docker/Dockerfile.local.dockerignore b/docker/Dockerfile.local.dockerignore index 1270255fb..f9e8cac18 100644 --- a/docker/Dockerfile.local.dockerignore +++ b/docker/Dockerfile.local.dockerignore @@ -5,6 +5,7 @@ **/node_modules apps/**/* !apps/search-server +!apps/mcp-server docker-compose.yml docker docs From ab2ca15c60587190b08ec30163ba0a4fa5ae2d64 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 4 Jun 2026 11:33:54 -0400 Subject: [PATCH 11/15] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typos=20in=20M?= =?UTF-8?q?CP=20Server=20README=20and=20package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Anders Richardsson <2107110+justincorrigible@users.noreply.github.com> --- apps/mcp-server/README.md | 4 ++-- integration-tests/mcp-server/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/mcp-server/README.md b/apps/mcp-server/README.md index cf5913c44..419b2c3a7 100644 --- a/apps/mcp-server/README.md +++ b/apps/mcp-server/README.md @@ -89,10 +89,10 @@ cp .env.schema .env | -------------------------- | ----------------------------------------------------------------------- | -------- | ------------ | ----------------------- | | `ARRANGER_BASE_URL` | URL for the Arranger Server | `string` | **Required** | `http://localhost:5050` | | `ARRANGER_CATALOGUES` | Comma-separated list of Arranger catalogues to expose to the MCP Server | `string` | **Required** | `server` | -| `ARRANGER_REQUEST_TIMEOUT` | Timeout for requests to Arranger | `number` | Optional | `10_0000` | +| `ARRANGER_REQUEST_TIMEOUT_MS` | Timeout for requests to Arranger | `number` | Optional | `10_000` | | `MCP_HOST` | Host URL for the MCP server | `string` | Optional | `0.0.0.0` | | `MCP_PORT` | Port the MCP Server will listen for requests on | `number` | Optional | `3100` | -| `MCP_PATH` | Endpoint for the MCP Stremable HTTP transport | `string` | Optional | `/mcp` | +| `MCP_PATH` | Endpoint for the MCP Streamable HTTP transport | `string` | Optional | `/mcp` | | `LOG_LEVEL` | Pino [log level](https://getpino.io/#/docs/api?id=level-1) | `string` | Optional | `info` | ## Testing diff --git a/integration-tests/mcp-server/package.json b/integration-tests/mcp-server/package.json index 56496950d..0421d2236 100644 --- a/integration-tests/mcp-server/package.json +++ b/integration-tests/mcp-server/package.json @@ -9,7 +9,7 @@ "prettier": "^3.4.2", "tsx": "^4.19.3" }, - "private": "true", + "private": true, "scripts": { "test": "tsx --test" }, From fab720c5f29ac93086033638409c75e958d6ffc9 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 4 Jun 2026 15:52:15 -0400 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=8E=A8=20Use=20alias=20for=20Zod=20?= =?UTF-8?q?import=20in=20MCP=20Tools=20*=20Use=20`import=20{=20z=20as=20zo?= =?UTF-8?q?d=20}=20from=20'zod'`=20to=20avoid=20single=20letter=20variable?= =?UTF-8?q?=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/src/mcp/tools.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/mcp-server/src/mcp/tools.ts b/apps/mcp-server/src/mcp/tools.ts index b3bd9edaf..14cad8097 100644 --- a/apps/mcp-server/src/mcp/tools.ts +++ b/apps/mcp-server/src/mcp/tools.ts @@ -1,12 +1,12 @@ import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp'; -import { z } from 'zod'; +import { z as zod } from 'zod'; import { type McpServerDeps } from '#server.js'; -const fieldShape = z.object({ - displayName: z.string(), - type: z.string(), - unit: z.string().nullable().optional(), +const fieldShape = zod.object({ + displayName: zod.string(), + type: zod.string(), + unit: zod.string().nullable().optional(), }); export const registerTools = (server: McpServer, { client }: McpServerDeps): void => { @@ -42,9 +42,9 @@ export const registerTools = (server: McpServer, { client }: McpServerDeps): voi description: 'Return field introspection for one catalogue. `operators` maps each field type to its valid SQON operators. `fields` lists each field with its `type`, `displayName`, optional `unit`, and optional `description`.', inputSchema: { - catalogId: z.string().min(1).describe('Catalog identifier from the Arranger /introspection payload.'), + catalogId: zod.string().min(1).describe('Catalog identifier from the Arranger /introspection payload.'), }, - outputSchema: { catalogId: z.string(), fields: z.record(fieldShape) }, + outputSchema: { catalogId: zod.string(), fields: zod.record(fieldShape) }, }, async ({ catalogId }) => { const data = await client.getCatalogIntrospection(catalogId); From 89d63fc33f7a678486ca320c18f7610b19a0aa37 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Thu, 4 Jun 2026 15:55:06 -0400 Subject: [PATCH 13/15] =?UTF-8?q?=F0=9F=8E=A8=20Improve=20graceful=20shutd?= =?UTF-8?q?own=20of=20MCP=20Server=20Express=20app=20*=20Handle=20both=20`?= =?UTF-8?q?SIGINT`=20and=20`SIGTERM`=20*=20Rename=20`shutdown`=20returned?= =?UTF-8?q?=20from=20`createHttpApp`=20to=20`closeAllSessions`=20for=20cla?= =?UTF-8?q?rity=20*=20Update=20tests=20to=20use=20`closeAllSessions`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/src/http/app.ts | 6 ++-- apps/mcp-server/src/server.ts | 31 ++++++++++++++----- .../mcp-server/test/startMcpServer.ts | 4 +-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/apps/mcp-server/src/http/app.ts b/apps/mcp-server/src/http/app.ts index c185e3976..9ba307fa6 100644 --- a/apps/mcp-server/src/http/app.ts +++ b/apps/mcp-server/src/http/app.ts @@ -12,7 +12,7 @@ import logger from '#utils/logger.js'; export type McpHttpApp = { app: Express; - shutdown: () => Promise; + closeAllSessions: () => Promise; }; // This code was adapted from the official MCP Server "Streamable HTTP" example: @@ -85,7 +85,7 @@ export const createHttpApp = (config: ArrangerMcpConfig, serverFactory: () => Mc app.get(path, sessionHandler); app.delete(path, sessionHandler); - const shutdown = async () => { + const closeAllSessions = async () => { for (const sessionId of Object.keys(transports)) { try { logger.debug(`Closing transport for session ${sessionId}`); @@ -98,5 +98,5 @@ export const createHttpApp = (config: ArrangerMcpConfig, serverFactory: () => Mc } }; - return { app, shutdown }; + return { app, closeAllSessions }; }; diff --git a/apps/mcp-server/src/server.ts b/apps/mcp-server/src/server.ts index 35d8d7c29..6a35230db 100644 --- a/apps/mcp-server/src/server.ts +++ b/apps/mcp-server/src/server.ts @@ -26,17 +26,34 @@ export const startServer = async (): Promise => { await validateArrangerConnection(config, client); const deps: McpServerDeps = { config, client }; - const { app, shutdown } = createHttpApp(config, () => createMcpServer(deps)); + const { app, closeAllSessions } = createHttpApp(config, () => createMcpServer(deps)); const { host, port, path } = config.mcp; app.listen(port, () => { logger.info(`MCP server running at http://${host}:${port}${path}`); }); - process.on('SIGINT', async () => { - logger.info('Shutting down server...'); - await shutdown(); - logger.info('Server shutdown complete.'); - process.exit(0); - }); + const gracefulShutdown = async (signal: string) => { + logger.info(`Received ${signal}, initiating graceful shutdown...`); + + // Force shutdown fallback after 30 seconds + const hardShutdownTimeout = setTimeout(() => { + logger.error('Graceful shutdown timed out, forcing exit'); + process.exit(1); + }, 30000); + + hardShutdownTimeout.unref(); // Allow process to exit if this is the only thing left + + try { + await closeAllSessions(); + logger.info('Graceful shutdown complete, exiting now.'); + process.exit(0); + } catch (error) { + logger.error({ error }, 'Error during graceful shutdown, forcing exit'); + process.exit(1); + } + }; + + process.on('SIGINT', () => gracefulShutdown('SIGINT')); + process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); }; diff --git a/integration-tests/mcp-server/test/startMcpServer.ts b/integration-tests/mcp-server/test/startMcpServer.ts index 67e8d770f..b774a106e 100644 --- a/integration-tests/mcp-server/test/startMcpServer.ts +++ b/integration-tests/mcp-server/test/startMcpServer.ts @@ -28,7 +28,7 @@ export const startMcpServerForTest = async (config: ArrangerMcpConfig): Promise< await validateArrangerConnection(config, introspectionClient); - const { app, shutdown: shutdownTransports } = createHttpApp(config, () => + const { app, closeAllSessions } = createHttpApp(config, () => createMcpServer({ config, client: introspectionClient }), ); @@ -40,7 +40,7 @@ export const startMcpServerForTest = async (config: ArrangerMcpConfig): Promise< }); const shutdown = async () => { - await shutdownTransports(); + await closeAllSessions(); await new Promise((resolve, reject) => { httpServer.close((err) => (err ? reject(err) : resolve())); }); From 1656f9eac7fc39824fc84522665a0f5893b3787f Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Fri, 5 Jun 2026 14:45:29 -0400 Subject: [PATCH 14/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20Refactor=20MCP=20?= =?UTF-8?q?Server=20Tools=20for=20Consistency=20*=20Add=20`outputSchema`s?= =?UTF-8?q?=20for=20each=20MCP=20Tool=20*=20Consistently=20return=20both?= =?UTF-8?q?=20`content`=20and=20`structuredContent`=20for=20MCP=20Server?= =?UTF-8?q?=20Tools,=20where=20it=20makes=20sense=20(on=20Tools=20with=20`?= =?UTF-8?q?outputSchema`s)=20*=20Add=20Zod=20schema=20definitions=20for=20?= =?UTF-8?q?Arranger=20introspection=20endpoint=20responses,=20move=20to=20?= =?UTF-8?q?`#arranger/types.ts`=20for=20now=20=20=20*=20NOTE:=20there=20is?= =?UTF-8?q?=20a=20pending=20TODO=20/=20tech=20debt=20in=20the=20repo=20to?= =?UTF-8?q?=20make=20these=20Zod=20schema=20definitions=20where=20the=20in?= =?UTF-8?q?trospection=20response=20types=20are=20defined,=20and=20to=20in?= =?UTF-8?q?fer=20the=20types=20based=20on=20these=20schemas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/src/arranger/types.ts | 54 +++++++++++++++++++++++++++ apps/mcp-server/src/mcp/tools.ts | 28 ++++++++------ 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/apps/mcp-server/src/arranger/types.ts b/apps/mcp-server/src/arranger/types.ts index b7ca5dd74..4a1825cfa 100644 --- a/apps/mcp-server/src/arranger/types.ts +++ b/apps/mcp-server/src/arranger/types.ts @@ -1,6 +1,60 @@ +import { z as zod } from 'zod'; + export type { CatalogFieldIntrospection as ArrangerCatalogFieldDetails, CatalogIntrospectionResponse as ArrangerCatalogIntrospection, IntrospectionResponse as ArrangerServerIntrospection, SqonIntrospectionResponse as ArrangerSqonIntrospection, } from '../../../search-server/src/introspection/types.js'; + +// TODO: as part of tech debt item "Introspection types should be Zod-first to allow reuse as MCP output schemas", +// these types should be replaced with exports from the search-server's Zod schemas once that work is done. + +export const catalogsSchema = zod.record( + zod.object({ + description: zod.string().optional(), + documentType: zod.string(), + paths: zod.object({ + fields: zod.string().optional(), + graphql: zod.string(), + introspection: zod.string(), + }), + }), +); + +const sqonOperatorDetailSchema = zod.object({ + applicableTo: zod.union([zod.literal('all'), zod.array(zod.string())]), + op: zod.string(), + valueType: zod.string(), +}); + +export const sqonIntrospectionSchema = zod.object({ + $schema: zod.string(), + aliases: zod.record(zod.string()), + description: zod.string(), + operators: zod.object({ + combination: zod.array(zod.string()), + field: zod.array(sqonOperatorDetailSchema), + }), + schema: zod.record(zod.unknown()), + title: zod.string(), + version: zod.string(), +}); + +const fieldSchema = zod.object({ + displayName: zod.string(), + type: zod.string(), + unit: zod.string().nullable().optional(), +}); + +export const catalogIntrospectionSchema = zod.object({ + catalogId: zod.string(), + description: zod.string().optional(), + documentType: zod.string(), + generatedAt: zod.string(), + meta: zod.object({ + authFiltered: zod.boolean(), + }), + operators: zod.record(zod.array(zod.string())), + fields: zod.record(fieldSchema), +}); diff --git a/apps/mcp-server/src/mcp/tools.ts b/apps/mcp-server/src/mcp/tools.ts index 14cad8097..acd1ca8f9 100644 --- a/apps/mcp-server/src/mcp/tools.ts +++ b/apps/mcp-server/src/mcp/tools.ts @@ -1,25 +1,24 @@ import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import { z as zod } from 'zod'; +import { catalogsSchema, sqonIntrospectionSchema, catalogIntrospectionSchema } from '#arranger/types.js'; import { type McpServerDeps } from '#server.js'; -const fieldShape = zod.object({ - displayName: zod.string(), - type: zod.string(), - unit: zod.string().nullable().optional(), -}); - export const registerTools = (server: McpServer, { client }: McpServerDeps): void => { server.registerTool( 'list-catalogs', { title: 'List Arranger Catalogs', description: 'Returns the catalogs exposed by the connected Arranger server.', + outputSchema: zod.object({ catalogs: catalogsSchema }), }, async () => { const { catalogs } = await client.getServerIntrospection(); const ids = Object.keys(catalogs); - return { content: [{ type: 'text', text: `Available catalogs: ${ids.join(', ')}` }] }; + return { + content: [{ type: 'text', text: `Available catalogs: ${ids.join(', ')}` }], + structuredContent: { catalogs }, + }; }, ); @@ -28,10 +27,15 @@ export const registerTools = (server: McpServer, { client }: McpServerDeps): voi { title: 'Get SQON Schema', description: 'Returns the shared SQON Schema and operator metadata for the connected Arranger server.', + outputSchema: sqonIntrospectionSchema, }, async () => { const data = await client.getSqonIntrospection(); - return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }; + const sqonSchema = sqonIntrospectionSchema.parse(data); + return { + content: [{ type: 'text', text: JSON.stringify(sqonSchema) }], + structuredContent: sqonSchema, + }; }, ); @@ -44,14 +48,14 @@ export const registerTools = (server: McpServer, { client }: McpServerDeps): voi inputSchema: { catalogId: zod.string().min(1).describe('Catalog identifier from the Arranger /introspection payload.'), }, - outputSchema: { catalogId: zod.string(), fields: zod.record(fieldShape) }, + outputSchema: catalogIntrospectionSchema, }, async ({ catalogId }) => { const data = await client.getCatalogIntrospection(catalogId); - const structured = { catalogId: data.catalogId, fields: data.fields }; + const catalogIntrospection = catalogIntrospectionSchema.parse(data); return { - content: [{ type: 'text', text: JSON.stringify(structured, null, 2) }], - structuredContent: structured, + content: [{ type: 'text', text: JSON.stringify(catalogIntrospection, null, 2) }], + structuredContent: catalogIntrospection, }; }, ); From 863a022e34cc029832a473e03a19cd957acccd55 Mon Sep 17 00:00:00 2001 From: Rakesh Mistry Date: Fri, 5 Jun 2026 16:11:16 -0400 Subject: [PATCH 15/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20PR=20Feedback:=20?= =?UTF-8?q?Refactor=20MCP=20Server=20"List=20Catalogs"=20Tool?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mcp-server/src/arranger/types.ts | 7 +++++++ apps/mcp-server/src/mcp/tools.ts | 14 ++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/mcp-server/src/arranger/types.ts b/apps/mcp-server/src/arranger/types.ts index 4a1825cfa..de0e23bfc 100644 --- a/apps/mcp-server/src/arranger/types.ts +++ b/apps/mcp-server/src/arranger/types.ts @@ -22,6 +22,13 @@ export const catalogsSchema = zod.record( }), ); +export const serverIntrospectionSchema = zod.object({ + catalogCount: zod.number(), + catalogs: catalogsSchema, + mode: zod.union([zod.literal('single'), zod.literal('multiple')]), + sqonSchemaPath: zod.string(), +}); + const sqonOperatorDetailSchema = zod.object({ applicableTo: zod.union([zod.literal('all'), zod.array(zod.string())]), op: zod.string(), diff --git a/apps/mcp-server/src/mcp/tools.ts b/apps/mcp-server/src/mcp/tools.ts index acd1ca8f9..9f37ffc07 100644 --- a/apps/mcp-server/src/mcp/tools.ts +++ b/apps/mcp-server/src/mcp/tools.ts @@ -1,7 +1,12 @@ import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import { z as zod } from 'zod'; -import { catalogsSchema, sqonIntrospectionSchema, catalogIntrospectionSchema } from '#arranger/types.js'; +import { + catalogIntrospectionSchema, + catalogsSchema, + serverIntrospectionSchema, + sqonIntrospectionSchema, +} from '#arranger/types.js'; import { type McpServerDeps } from '#server.js'; export const registerTools = (server: McpServer, { client }: McpServerDeps): void => { @@ -13,10 +18,11 @@ export const registerTools = (server: McpServer, { client }: McpServerDeps): voi outputSchema: zod.object({ catalogs: catalogsSchema }), }, async () => { - const { catalogs } = await client.getServerIntrospection(); - const ids = Object.keys(catalogs); + const data = await client.getServerIntrospection(); + const { catalogs } = serverIntrospectionSchema.parse(data); + const catalogIds = Object.keys(catalogs); return { - content: [{ type: 'text', text: `Available catalogs: ${ids.join(', ')}` }], + content: [{ type: 'text', text: `Available catalogs: ${catalogIds.join(', ')}` }], structuredContent: { catalogs }, }; },