session-collab-mcp 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -50
- package/dist/{chunk-V4APNPXF.js → chunk-SOUW3JSS.js} +120 -9
- package/dist/chunk-SOUW3JSS.js.map +1 -0
- package/dist/cli.js +4 -11
- package/dist/cli.js.map +1 -1
- package/dist/http/cli.js +266 -84
- package/dist/http/cli.js.map +1 -1
- package/package.json +11 -6
- package/dist/chunk-V4APNPXF.js.map +0 -1
package/dist/http/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/http/cli.ts","../../src/http/server.ts"],"sourcesContent":["#!/usr/bin/env node\n// HTTP server for Session Collaboration MCP\n\nimport { readFileSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { createLocalDatabase, getDefaultDbPath } from '../db/sqlite-adapter.js';\nimport { startHttpServer } from './server.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction loadMigrations(): string[] {\n const migrationsDir = join(__dirname, '..', '..', 'migrations');\n return [\n readFileSync(join(migrationsDir, '0001_init.sql'), 'utf-8'),\n readFileSync(join(migrationsDir, '0002_auth.sql'), 'utf-8'),\n readFileSync(join(migrationsDir, '0003_config.sql'), 'utf-8'),\n readFileSync(join(migrationsDir, '0004_symbols.sql'), 'utf-8'),\n readFileSync(join(migrationsDir, '0005_references.sql'), 'utf-8'),\n readFileSync(join(migrationsDir, '0006_composite_indexes.sql'), 'utf-8'),\n ];\n}\n\nfunction parseArgs(): { dbPath?: string; host: string; port: number } {\n const args = process.argv.slice(2);\n let dbPath: string | undefined;\n let host = '127.0.0.1';\n let port = 8765;\n\n for (let i = 0; i < args.length; i++) {\n const value = args[i + 1];\n if (args[i] === '--db' && value) {\n dbPath = value;\n i++;\n } else if (args[i] === '--host' && value) {\n host = value;\n i++;\n } else if (args[i] === '--port' && value) {\n port = Number(value);\n i++;\n }\n }\n\n return { dbPath, host, port };\n}\n\nasync function main(): Promise<void> {\n const { dbPath, host, port } = parseArgs();\n const db = createLocalDatabase(dbPath);\n\n try {\n const migrations = loadMigrations();\n db.initSchema(migrations);\n } catch (error) {\n if (!(error instanceof Error && error.message.includes('already exists'))) {\n console.error('Warning: Migration error:', error);\n }\n }\n\n await startHttpServer(db, { host, port });\n console.error(`Session Collab HTTP Server running at http://${host}:${port}`);\n console.error(`Database: ${dbPath ?? getDefaultDbPath()}`);\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n","import http from 'http';\nimport { URL } from 'url';\nimport type { DatabaseAdapter } from '../db/sqlite-adapter.js';\nimport type { McpToolResult } from '../mcp/protocol.js';\nimport { getMcpTools, handleMcpRequest } from '../mcp/server.js';\n\ntype JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };\n\ntype HttpResponse = {\n ok: boolean;\n data?: JsonValue;\n error?: { code: string; message: string };\n};\n\nfunction sendJson(res: http.ServerResponse, status: number, body: HttpResponse): void {\n const payload = JSON.stringify(body);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(payload),\n });\n res.end(payload);\n}\n\nfunction parseBody(req: http.IncomingMessage): Promise<JsonValue | undefined> {\n return new Promise((resolve, reject) => {\n let data = '';\n req.on('data', (chunk) => {\n data += chunk;\n if (data.length > 1_000_000) {\n reject(new Error('Payload too large'));\n }\n });\n req.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data) as JsonValue);\n } catch (error) {\n reject(error);\n }\n });\n });\n}\n\nexport function normalizeToolResult(result: McpToolResult): HttpResponse {\n const text = result.content?.[0]?.text ?? '';\n try {\n const data = JSON.parse(text) as JsonValue;\n if (result.isError) {\n const errorCode = (data && typeof data === 'object' && 'error' in data)\n ? String((data as { error?: string }).error ?? 'UNKNOWN')\n : 'UNKNOWN';\n const message = (data && typeof data === 'object' && 'message' in data)\n ? String((data as { message?: string }).message ?? 'Error')\n : 'Error';\n return { ok: false, error: { code: errorCode, message } };\n }\n return { ok: true, data };\n } catch {\n if (result.isError) {\n return { ok: false, error: { code: 'UNKNOWN', message: text || 'Error' } };\n }\n return { ok: true, data: text };\n }\n}\n\nexport function coerceQueryValue(value: string): string | number | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n const num = Number(value);\n if (!Number.isNaN(num) && value.trim() !== '') {\n return num;\n }\n return value;\n}\n\nexport function parseQueryParams(url: URL): Record<string, JsonValue> {\n const params: Record<string, JsonValue> = {};\n for (const [key, value] of url.searchParams.entries()) {\n params[key] = coerceQueryValue(value);\n }\n return params;\n}\n\nasync function handleTool(\n db: DatabaseAdapter,\n name: string,\n args: Record<string, unknown>\n): Promise<HttpResponse> {\n const result = await handleMcpRequest(db, name, args);\n return normalizeToolResult(result);\n}\n\nexport function createHttpServer(db: DatabaseAdapter): http.Server {\n return http.createServer(async (req, res) => {\n try {\n const method = req.method ?? 'GET';\n const url = new URL(req.url ?? '/', 'http://localhost');\n\n if (method === 'GET' && url.pathname === '/health') {\n sendJson(res, 200, { ok: true, data: { status: 'ok' } });\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/tools') {\n sendJson(res, 200, { ok: true, data: { tools: getMcpTools() } });\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/tools/call') {\n const body = (await parseBody(req)) as { name?: string; args?: Record<string, unknown> } | undefined;\n if (!body?.name) {\n sendJson(res, 400, { ok: false, error: { code: 'INVALID_INPUT', message: 'name is required' } });\n return;\n }\n const response = await handleTool(db, body.name, body.args ?? {});\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/sessions/start') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_session_start', body ?? {});\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/sessions/end') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_session_end', body ?? {});\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/sessions') {\n const args = parseQueryParams(url);\n const response = await handleTool(db, 'collab_session_list', args);\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/config') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_config', body ?? {});\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/status') {\n const args = parseQueryParams(url);\n const response = await handleTool(db, 'collab_status', args);\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/claims') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_claim', { action: 'create', ...(body ?? {}) });\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/claims/check') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_claim', { action: 'check', ...(body ?? {}) });\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/claims/release') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_claim', { action: 'release', ...(body ?? {}) });\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/claims') {\n const args = parseQueryParams(url);\n const response = await handleTool(db, 'collab_claim', { action: 'list', ...args });\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/memory/save') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_memory_save', body ?? {});\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/memory/recall') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_memory_recall', body ?? {});\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/memory/clear') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_memory_clear', body ?? {});\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/protect/register') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_protect', { action: 'register', ...(body ?? {}) });\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/protect/check') {\n const body = (await parseBody(req)) as Record<string, unknown>;\n const response = await handleTool(db, 'collab_protect', { action: 'check', ...(body ?? {}) });\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/protect/list') {\n const args = parseQueryParams(url);\n const response = await handleTool(db, 'collab_protect', { action: 'list', ...args });\n sendJson(res, response.ok ? 200 : 400, response);\n return;\n }\n\n sendJson(res, 404, { ok: false, error: { code: 'NOT_FOUND', message: 'Not found' } });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unexpected error';\n sendJson(res, 500, { ok: false, error: { code: 'INTERNAL_ERROR', message } });\n }\n });\n}\n\nexport async function startHttpServer(\n db: DatabaseAdapter,\n options: { host: string; port: number }\n): Promise<http.Server> {\n const server = createHttpServer(db);\n await new Promise<void>((resolve, reject) => {\n server.listen(options.port, options.host, () => resolve());\n server.on('error', reject);\n });\n return server;\n}\n"],"mappings":";;;;;;;;;AAGA,SAAS,oBAAoB;AAC7B,SAAS,MAAM,eAAe;AAC9B,SAAS,qBAAqB;;;ACL9B,OAAO,UAAU;AACjB,SAAS,WAAW;AAapB,SAAS,SAAS,KAA0B,QAAgB,MAA0B;AACpF,QAAM,UAAU,KAAK,UAAU,IAAI;AACnC,MAAI,UAAU,QAAQ;AAAA,IACpB,gBAAgB;AAAA,IAChB,kBAAkB,OAAO,WAAW,OAAO;AAAA,EAC7C,CAAC;AACD,MAAI,IAAI,OAAO;AACjB;AAEA,SAAS,UAAU,KAA2D;AAC5E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO;AACX,QAAI,GAAG,QAAQ,CAAC,UAAU;AACxB,cAAQ;AACR,UAAI,KAAK,SAAS,KAAW;AAC3B,eAAO,IAAI,MAAM,mBAAmB,CAAC;AAAA,MACvC;AAAA,IACF,CAAC;AACD,QAAI,GAAG,OAAO,MAAM;AAClB,UAAI,CAAC,MAAM;AACT,gBAAQ,MAAS;AACjB;AAAA,MACF;AACA,UAAI;AACF,gBAAQ,KAAK,MAAM,IAAI,CAAc;AAAA,MACvC,SAAS,OAAO;AACd,eAAO,KAAK;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEO,SAAS,oBAAoB,QAAqC;AACvE,QAAM,OAAO,OAAO,UAAU,CAAC,GAAG,QAAQ;AAC1C,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,QAAI,OAAO,SAAS;AAClB,YAAM,YAAa,QAAQ,OAAO,SAAS,YAAY,WAAW,OAC9D,OAAQ,KAA4B,SAAS,SAAS,IACtD;AACJ,YAAM,UAAW,QAAQ,OAAO,SAAS,YAAY,aAAa,OAC9D,OAAQ,KAA8B,WAAW,OAAO,IACxD;AACJ,aAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,WAAW,QAAQ,EAAE;AAAA,IAC1D;AACA,WAAO,EAAE,IAAI,MAAM,KAAK;AAAA,EAC1B,QAAQ;AACN,QAAI,OAAO,SAAS;AAClB,aAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAAA,IAC3E;AACA,WAAO,EAAE,IAAI,MAAM,MAAM,KAAK;AAAA,EAChC;AACF;AAEO,SAAS,iBAAiB,OAA0C;AACzE,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,QAAS,QAAO;AAC9B,QAAM,MAAM,OAAO,KAAK;AACxB,MAAI,CAAC,OAAO,MAAM,GAAG,KAAK,MAAM,KAAK,MAAM,IAAI;AAC7C,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,KAAqC;AACpE,QAAM,SAAoC,CAAC;AAC3C,aAAW,CAAC,KAAK,KAAK,KAAK,IAAI,aAAa,QAAQ,GAAG;AACrD,WAAO,GAAG,IAAI,iBAAiB,KAAK;AAAA,EACtC;AACA,SAAO;AACT;AAEA,eAAe,WACb,IACA,MACA,MACuB;AACvB,QAAM,SAAS,MAAM,iBAAiB,IAAI,MAAM,IAAI;AACpD,SAAO,oBAAoB,MAAM;AACnC;AAEO,SAAS,iBAAiB,IAAkC;AACjE,SAAO,KAAK,aAAa,OAAO,KAAK,QAAQ;AAC3C,QAAI;AACF,YAAM,SAAS,IAAI,UAAU;AAC7B,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AAEtD,UAAI,WAAW,SAAS,IAAI,aAAa,WAAW;AAClD,iBAAS,KAAK,KAAK,EAAE,IAAI,MAAM,MAAM,EAAE,QAAQ,KAAK,EAAE,CAAC;AACvD;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,IAAI,aAAa,aAAa;AACpD,iBAAS,KAAK,KAAK,EAAE,IAAI,MAAM,MAAM,EAAE,OAAO,YAAY,EAAE,EAAE,CAAC;AAC/D;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,kBAAkB;AAC1D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,YAAI,CAAC,MAAM,MAAM;AACf,mBAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,iBAAiB,SAAS,mBAAmB,EAAE,CAAC;AAC/F;AAAA,QACF;AACA,cAAM,WAAW,MAAM,WAAW,IAAI,KAAK,MAAM,KAAK,QAAQ,CAAC,CAAC;AAChE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,sBAAsB;AAC9D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,wBAAwB,QAAQ,CAAC,CAAC;AACxE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,oBAAoB;AAC5D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,sBAAsB,QAAQ,CAAC,CAAC;AACtE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,IAAI,aAAa,gBAAgB;AACvD,cAAM,OAAO,iBAAiB,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,uBAAuB,IAAI;AACjE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,cAAc;AACtD,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,iBAAiB,QAAQ,CAAC,CAAC;AACjE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,IAAI,aAAa,cAAc;AACrD,cAAM,OAAO,iBAAiB,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,iBAAiB,IAAI;AAC3D,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,cAAc;AACtD,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,gBAAgB,EAAE,QAAQ,UAAU,GAAI,QAAQ,CAAC,EAAG,CAAC;AAC3F,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,oBAAoB;AAC5D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,gBAAgB,EAAE,QAAQ,SAAS,GAAI,QAAQ,CAAC,EAAG,CAAC;AAC1F,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,sBAAsB;AAC9D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,gBAAgB,EAAE,QAAQ,WAAW,GAAI,QAAQ,CAAC,EAAG,CAAC;AAC5F,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,IAAI,aAAa,cAAc;AACrD,cAAM,OAAO,iBAAiB,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,gBAAgB,EAAE,QAAQ,QAAQ,GAAG,KAAK,CAAC;AACjF,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,mBAAmB;AAC3D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,sBAAsB,QAAQ,CAAC,CAAC;AACtE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,qBAAqB;AAC7D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,wBAAwB,QAAQ,CAAC,CAAC;AACxE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,oBAAoB;AAC5D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,uBAAuB,QAAQ,CAAC,CAAC;AACvE,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,wBAAwB;AAChE,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,kBAAkB,EAAE,QAAQ,YAAY,GAAI,QAAQ,CAAC,EAAG,CAAC;AAC/F,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,UAAU,IAAI,aAAa,qBAAqB;AAC7D,cAAM,OAAQ,MAAM,UAAU,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,kBAAkB,EAAE,QAAQ,SAAS,GAAI,QAAQ,CAAC,EAAG,CAAC;AAC5F,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,IAAI,aAAa,oBAAoB;AAC3D,cAAM,OAAO,iBAAiB,GAAG;AACjC,cAAM,WAAW,MAAM,WAAW,IAAI,kBAAkB,EAAE,QAAQ,QAAQ,GAAG,KAAK,CAAC;AACnF,iBAAS,KAAK,SAAS,KAAK,MAAM,KAAK,QAAQ;AAC/C;AAAA,MACF;AAEA,eAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,aAAa,SAAS,YAAY,EAAE,CAAC;AAAA,IACtF,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,eAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,kBAAkB,QAAQ,EAAE,CAAC;AAAA,IAC9E;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,gBACpB,IACA,SACsB;AACtB,QAAM,SAAS,iBAAiB,EAAE;AAClC,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,WAAO,OAAO,QAAQ,MAAM,QAAQ,MAAM,MAAM,QAAQ,CAAC;AACzD,WAAO,GAAG,SAAS,MAAM;AAAA,EAC3B,CAAC;AACD,SAAO;AACT;;;AD5OA,IAAMA,aAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAExD,SAAS,iBAA2B;AAClC,QAAM,gBAAgB,KAAKA,YAAW,MAAM,MAAM,YAAY;AAC9D,SAAO;AAAA,IACL,aAAa,KAAK,eAAe,eAAe,GAAG,OAAO;AAAA,IAC1D,aAAa,KAAK,eAAe,eAAe,GAAG,OAAO;AAAA,IAC1D,aAAa,KAAK,eAAe,iBAAiB,GAAG,OAAO;AAAA,IAC5D,aAAa,KAAK,eAAe,kBAAkB,GAAG,OAAO;AAAA,IAC7D,aAAa,KAAK,eAAe,qBAAqB,GAAG,OAAO;AAAA,IAChE,aAAa,KAAK,eAAe,4BAA4B,GAAG,OAAO;AAAA,EACzE;AACF;AAEA,SAAS,YAA6D;AACpE,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,MAAI;AACJ,MAAI,OAAO;AACX,MAAI,OAAO;AAEX,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,QAAQ,KAAK,IAAI,CAAC;AACxB,QAAI,KAAK,CAAC,MAAM,UAAU,OAAO;AAC/B,eAAS;AACT;AAAA,IACF,WAAW,KAAK,CAAC,MAAM,YAAY,OAAO;AACxC,aAAO;AACP;AAAA,IACF,WAAW,KAAK,CAAC,MAAM,YAAY,OAAO;AACxC,aAAO,OAAO,KAAK;AACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,MAAM,KAAK;AAC9B;AAEA,eAAe,OAAsB;AACnC,QAAM,EAAE,QAAQ,MAAM,KAAK,IAAI,UAAU;AACzC,QAAM,KAAK,oBAAoB,MAAM;AAErC,MAAI;AACF,UAAM,aAAa,eAAe;AAClC,OAAG,WAAW,UAAU;AAAA,EAC1B,SAAS,OAAO;AACd,QAAI,EAAE,iBAAiB,SAAS,MAAM,QAAQ,SAAS,gBAAgB,IAAI;AACzE,cAAQ,MAAM,6BAA6B,KAAK;AAAA,IAClD;AAAA,EACF;AAEA,QAAM,gBAAgB,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,UAAQ,MAAM,gDAAgD,IAAI,IAAI,IAAI,EAAE;AAC5E,UAAQ,MAAM,aAAa,UAAU,iBAAiB,CAAC,EAAE;AAC3D;AAEA,KAAK,EAAE,MAAM,CAAC,UAAU;AACtB,UAAQ,MAAM,gBAAgB,KAAK;AACnC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["__dirname"]}
|
|
1
|
+
{"version":3,"sources":["../../src/http/cli.ts","../../src/http/server.ts"],"sourcesContent":["#!/usr/bin/env node\n// HTTP server for Session Collaboration MCP\n\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { createLocalDatabase, getDefaultDbPath } from '../db/sqlite-adapter.js';\nimport { startHttpServer } from './server.js';\nimport { loadMigrationsFromDir } from '../db/migrations.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction loadMigrations(): string[] {\n const migrationsDir = join(__dirname, '..', '..', 'migrations');\n return loadMigrationsFromDir(migrationsDir);\n}\n\nfunction parseArgs(): { dbPath?: string; host: string; port: number; allowedHosts: string[] } {\n const args = process.argv.slice(2);\n let dbPath: string | undefined;\n let host = '127.0.0.1';\n let port = 8765;\n const allowedHosts: string[] = [];\n\n for (let i = 0; i < args.length; i++) {\n const value = args[i + 1];\n if (args[i] === '--db' && value) {\n dbPath = value;\n i++;\n } else if (args[i] === '--host' && value) {\n host = value;\n i++;\n } else if (args[i] === '--port' && value) {\n port = Number(value);\n i++;\n } else if (args[i] === '--allowed-host' && value) {\n allowedHosts.push(value);\n i++;\n }\n }\n\n return { dbPath, host, port, allowedHosts };\n}\n\nasync function main(): Promise<void> {\n const { dbPath, host, port, allowedHosts } = parseArgs();\n const db = createLocalDatabase(dbPath);\n const apiToken = process.env.SESSION_COLLAB_HTTP_TOKEN;\n const envAllowedHosts = (process.env.SESSION_COLLAB_ALLOWED_HOSTS ?? '')\n .split(',')\n .map((hostEntry) => hostEntry.trim())\n .filter(Boolean);\n\n try {\n const migrations = loadMigrations();\n db.initSchema(migrations);\n } catch (error) {\n if (!(error instanceof Error && error.message.includes('already exists'))) {\n console.error('Warning: Migration error:', error);\n }\n }\n\n await startHttpServer(db, {\n host,\n port,\n apiToken,\n allowedHosts: [...envAllowedHosts, ...allowedHosts],\n });\n console.error(`Session Collab HTTP Server running at http://${host}:${port}`);\n console.error(`Database: ${dbPath ?? getDefaultDbPath()}`);\n console.error(`MCP endpoint: POST /mcp`);\n console.error(`Convenience REST API: /v1/*`);\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n","import http from 'http';\nimport { URL } from 'url';\nimport type { DatabaseAdapter } from '../db/sqlite-adapter.js';\nimport type { JsonRpcRequest, JsonRpcResponse, McpToolResult } from '../mcp/protocol.js';\nimport { JsonRpcRequestSchema } from '../mcp/protocol.js';\nimport { McpServer, getMcpTools, handleMcpRequest } from '../mcp/server.js';\nimport { generateId } from '../utils/crypto.js';\n\ntype JsonPrimitive = null | boolean | number | string;\ntype JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };\n\nexport type HttpSuccessResponse = {\n ok: true;\n data?: JsonValue;\n};\n\nexport type HttpErrorResponse = {\n ok: false;\n error: string;\n code: string;\n message: string;\n trace_id: string;\n};\n\nexport type HttpResponse = HttpSuccessResponse | HttpErrorResponse;\n\nexport type HttpServerOptions = {\n host?: string;\n allowedHosts?: string[];\n apiToken?: string;\n};\n\nclass HttpRequestError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n message: string\n ) {\n super(message);\n this.name = 'HttpRequestError';\n }\n}\n\nfunction normalizeHost(host: string): string {\n return host.trim().toLowerCase();\n}\n\nfunction normalizeHostHeader(rawHost: string | undefined): string | null {\n if (!rawHost) return null;\n const first = rawHost.split(',')[0]?.trim();\n if (!first) return null;\n\n if (first.startsWith('[')) {\n const closingIndex = first.indexOf(']');\n if (closingIndex !== -1) {\n return normalizeHost(first.slice(1, closingIndex));\n }\n }\n\n const withoutPort = first.includes(':') ? first.split(':')[0] : first;\n return normalizeHost(withoutPort);\n}\n\nfunction isLocalBindHost(host: string): boolean {\n const normalized = normalizeHost(host);\n return normalized === '127.0.0.1' || normalized === 'localhost' || normalized === '::1';\n}\n\nfunction buildAllowedHosts(host: string, configuredHosts: string[] = []): Set<string> {\n const allowedHosts = new Set(configuredHosts.map(normalizeHost).filter(Boolean));\n\n if (isLocalBindHost(host)) {\n allowedHosts.add('localhost');\n allowedHosts.add('127.0.0.1');\n allowedHosts.add('::1');\n } else if (host !== '0.0.0.0' && host !== '::') {\n allowedHosts.add(normalizeHost(host));\n }\n\n return allowedHosts;\n}\n\nfunction getTraceId(req: http.IncomingMessage): string {\n const requestId = req.headers['x-request-id'];\n if (typeof requestId === 'string' && requestId.trim()) {\n return requestId.trim();\n }\n return generateId();\n}\n\nfunction sendJson(\n res: http.ServerResponse,\n status: number,\n body: unknown,\n traceId: string,\n contentType: string = 'application/json'\n): void {\n const payload = JSON.stringify(body);\n res.writeHead(status, {\n 'Content-Type': contentType,\n 'Content-Length': Buffer.byteLength(payload),\n 'X-Request-ID': traceId,\n });\n res.end(payload);\n}\n\nfunction sendHttpError(\n res: http.ServerResponse,\n status: number,\n code: string,\n message: string,\n traceId: string\n): void {\n sendJson(res, status, { ok: false, error: code, code, message, trace_id: traceId }, traceId);\n}\n\nfunction sendJsonRpcResponse(\n res: http.ServerResponse,\n status: number,\n response: JsonRpcResponse,\n traceId: string\n): void {\n sendJson(res, status, response as unknown as JsonValue, traceId);\n}\n\nfunction sendJsonRpcError(\n res: http.ServerResponse,\n status: number,\n id: string | number | null,\n code: number,\n message: string,\n traceId: string\n): void {\n sendJson(\n res,\n status,\n {\n jsonrpc: '2.0',\n id,\n error: {\n code,\n message,\n data: { trace_id: traceId },\n },\n } as unknown as JsonValue,\n traceId\n );\n}\n\nasync function readJsonBody(req: http.IncomingMessage): Promise<JsonValue | undefined> {\n return await new Promise((resolve, reject) => {\n let data = '';\n let settled = false;\n\n const rejectOnce = (error: Error) => {\n if (settled) return;\n settled = true;\n reject(error);\n };\n\n const resolveOnce = (value: JsonValue | undefined) => {\n if (settled) return;\n settled = true;\n resolve(value);\n };\n\n req.on('data', (chunk) => {\n if (settled) return;\n data += chunk;\n if (data.length > 1_000_000) {\n rejectOnce(new HttpRequestError(413, 'PAYLOAD_TOO_LARGE', 'Payload too large'));\n req.pause();\n }\n });\n\n req.on('end', () => {\n if (settled) return;\n if (!data) {\n resolveOnce(undefined);\n return;\n }\n\n try {\n resolveOnce(JSON.parse(data) as JsonValue);\n } catch {\n rejectOnce(new HttpRequestError(400, 'INVALID_JSON', 'Request body must be valid JSON'));\n }\n });\n\n req.on('error', (error) => rejectOnce(error instanceof Error ? error : new Error(String(error))));\n });\n}\n\nexport function normalizeToolResult(result: McpToolResult, traceId: string): HttpResponse {\n const text = result.content?.[0]?.text ?? '';\n\n try {\n const data = JSON.parse(text) as JsonValue;\n if (result.isError) {\n const errorCode =\n data && typeof data === 'object' && 'error' in data\n ? String((data as { error?: string }).error ?? 'UNKNOWN')\n : 'UNKNOWN';\n const message =\n data && typeof data === 'object' && 'message' in data\n ? String((data as { message?: string }).message ?? 'Error')\n : 'Error';\n return {\n ok: false,\n error: errorCode,\n code: errorCode,\n message,\n trace_id: traceId,\n };\n }\n\n return { ok: true, data };\n } catch {\n if (result.isError) {\n return {\n ok: false,\n error: 'UNKNOWN',\n code: 'UNKNOWN',\n message: text || 'Error',\n trace_id: traceId,\n };\n }\n\n return { ok: true, data: text };\n }\n}\n\nexport function coerceQueryValue(value: string): string | number | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n const num = Number(value);\n if (!Number.isNaN(num) && value.trim() !== '') {\n return num;\n }\n return value;\n}\n\nexport function parseQueryParams(url: URL): Record<string, JsonValue> {\n const params: Record<string, JsonValue> = {};\n for (const [key, value] of url.searchParams.entries()) {\n params[key] = coerceQueryValue(value);\n }\n return params;\n}\n\nfunction enforceHttpSecurity(\n req: http.IncomingMessage,\n options: Required<Pick<HttpServerOptions, 'host'>> & Pick<HttpServerOptions, 'allowedHosts' | 'apiToken'>\n): void {\n const allowedHosts = buildAllowedHosts(options.host, options.allowedHosts);\n const hostHeader = normalizeHostHeader(req.headers.host);\n\n if (allowedHosts.size > 0) {\n if (!hostHeader || !allowedHosts.has(hostHeader)) {\n throw new HttpRequestError(403, 'INVALID_HOST', 'Host header is not allowed');\n }\n\n const originHeader = req.headers.origin;\n if (originHeader) {\n let origin: URL;\n try {\n origin = new URL(originHeader);\n } catch {\n throw new HttpRequestError(403, 'INVALID_ORIGIN', 'Origin header is invalid');\n }\n\n if (!allowedHosts.has(normalizeHost(origin.hostname))) {\n throw new HttpRequestError(403, 'INVALID_ORIGIN', 'Origin header is not allowed');\n }\n }\n }\n\n if (options.apiToken) {\n const authHeader = req.headers.authorization;\n const expected = `Bearer ${options.apiToken}`;\n if (authHeader !== expected) {\n throw new HttpRequestError(401, 'UNAUTHORIZED', 'Valid bearer token is required');\n }\n }\n}\n\nasync function handleRestTool(\n db: DatabaseAdapter,\n name: string,\n args: Record<string, unknown>,\n traceId: string\n): Promise<HttpResponse> {\n const result = await handleMcpRequest(db, name, args);\n return normalizeToolResult(result, traceId);\n}\n\nexport function createHttpServer(db: DatabaseAdapter, options: HttpServerOptions = {}): http.Server {\n const host = options.host ?? '127.0.0.1';\n const mcpServer = new McpServer(db);\n\n return http.createServer(async (req, res) => {\n const traceId = getTraceId(req);\n\n try {\n const method = req.method ?? 'GET';\n const url = new URL(req.url ?? '/', 'http://localhost');\n\n if (method === 'GET' && url.pathname === '/health') {\n sendJson(res, 200, { ok: true, data: { status: 'ok' } }, traceId);\n return;\n }\n\n enforceHttpSecurity(req, {\n host,\n allowedHosts: options.allowedHosts,\n apiToken: options.apiToken,\n });\n\n if (method === 'GET' && url.pathname === '/v1/tools') {\n sendJson(res, 200, { ok: true, data: { tools: getMcpTools() } }, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/tools/call') {\n const body = (await readJsonBody(req)) as { name?: string; args?: Record<string, unknown> } | undefined;\n if (!body?.name) {\n sendHttpError(res, 400, 'INVALID_INPUT', 'name is required', traceId);\n return;\n }\n const response = await handleRestTool(db, body.name, body.args ?? {}, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/mcp') {\n const body = await readJsonBody(req);\n const validation = JsonRpcRequestSchema.safeParse(body);\n if (!validation.success) {\n sendJsonRpcError(res, 400, null, -32600, 'Invalid Request', traceId);\n return;\n }\n\n const response = await mcpServer.handleRequest(validation.data as JsonRpcRequest);\n sendJsonRpcResponse(res, 200, response, traceId);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/mcp') {\n sendHttpError(\n res,\n 501,\n 'STREAM_NOT_SUPPORTED',\n 'This server exposes MCP JSON-RPC over HTTP POST at /mcp. SSE streaming is not implemented.',\n traceId\n );\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/sessions/start') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_session_start', body ?? {}, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/sessions/end') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_session_end', body ?? {}, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/sessions') {\n const response = await handleRestTool(db, 'collab_session_list', parseQueryParams(url), traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/config') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_config', body ?? {}, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/status') {\n const response = await handleRestTool(db, 'collab_status', parseQueryParams(url), traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/claims') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_claim', { action: 'create', ...(body ?? {}) }, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/claims/check') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_claim', { action: 'check', ...(body ?? {}) }, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/claims/release') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_claim', { action: 'release', ...(body ?? {}) }, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/claims') {\n const response = await handleRestTool(\n db,\n 'collab_claim',\n { action: 'list', ...parseQueryParams(url) },\n traceId\n );\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/memory/save') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_memory_save', body ?? {}, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/memory/recall') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_memory_recall', body ?? {}, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/memory/clear') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_memory_clear', body ?? {}, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/protect/register') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_protect', { action: 'register', ...(body ?? {}) }, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'POST' && url.pathname === '/v1/protect/check') {\n const body = (await readJsonBody(req)) as Record<string, unknown> | undefined;\n const response = await handleRestTool(db, 'collab_protect', { action: 'check', ...(body ?? {}) }, traceId);\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n if (method === 'GET' && url.pathname === '/v1/protect/list') {\n const response = await handleRestTool(\n db,\n 'collab_protect',\n { action: 'list', ...parseQueryParams(url) },\n traceId\n );\n sendJson(res, response.ok ? 200 : 400, response as unknown as JsonValue, traceId);\n return;\n }\n\n sendHttpError(res, 404, 'NOT_FOUND', 'Not found', traceId);\n } catch (error) {\n if (error instanceof HttpRequestError) {\n sendHttpError(res, error.status, error.code, error.message, traceId);\n return;\n }\n\n const message = error instanceof Error ? error.message : 'Unexpected error';\n sendHttpError(res, 500, 'INTERNAL_ERROR', message, traceId);\n }\n });\n}\n\nexport async function startHttpServer(\n db: DatabaseAdapter,\n options: { host: string; port: number; allowedHosts?: string[]; apiToken?: string }\n): Promise<http.Server> {\n const normalizedHost = normalizeHost(options.host);\n\n if (!isLocalBindHost(normalizedHost)) {\n if (!options.apiToken) {\n throw new Error('Non-local HTTP binds require SESSION_COLLAB_HTTP_TOKEN');\n }\n\n const allowedHosts = buildAllowedHosts(normalizedHost, options.allowedHosts);\n if (allowedHosts.size === 0) {\n throw new Error('Non-local HTTP binds require at least one allowed host');\n }\n }\n\n const server = createHttpServer(db, options);\n await new Promise<void>((resolve, reject) => {\n server.listen(options.port, options.host, () => resolve());\n server.on('error', reject);\n });\n return server;\n}\n"],"mappings":"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","names":["__dirname"]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "session-collab-mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "MCP server for
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Provider-agnostic MCP collaboration server for agent sessions - prevents conflicts, persists context, and protects important files",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
8
|
+
"agent",
|
|
9
|
+
"ai-agent",
|
|
10
10
|
"collaboration",
|
|
11
11
|
"session",
|
|
12
|
-
"conflict-prevention"
|
|
12
|
+
"conflict-prevention",
|
|
13
|
+
"working-memory",
|
|
14
|
+
"conflict-detection"
|
|
13
15
|
],
|
|
14
16
|
"type": "module",
|
|
15
17
|
"bin": {
|
|
@@ -37,10 +39,13 @@
|
|
|
37
39
|
"zod": "^3.24.1"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
|
-
"tsx": "^4.19.2",
|
|
41
42
|
"@types/better-sqlite3": "^7.6.12",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^8.58.2",
|
|
44
|
+
"@typescript-eslint/parser": "^8.58.2",
|
|
42
45
|
"eslint": "^9.17.0",
|
|
46
|
+
"fast-check": "^4.7.0",
|
|
43
47
|
"tsup": "^8.5.1",
|
|
48
|
+
"tsx": "^4.19.2",
|
|
44
49
|
"typescript": "^5.7.2",
|
|
45
50
|
"vitest": "^2.1.8"
|
|
46
51
|
}
|