@toolsdk.ai/registry 1.0.92 → 1.0.94
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/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +26 -0
- package/dist/api/package-handler.d.ts +39 -0
- package/dist/api/package-handler.js +37 -0
- package/dist/api/package-route.d.ts +2 -0
- package/dist/api/package-route.js +36 -0
- package/dist/api/package-so.d.ts +5 -0
- package/dist/api/package-so.js +44 -0
- package/dist/api/package.test.d.ts +1 -0
- package/dist/api/package.test.js +20 -0
- package/dist/helper.js +128 -184
- package/dist/schema.d.ts +20 -4
- package/dist/schema.js +46 -43
- package/dist/types.d.ts +8 -1
- package/dist/types.js +1 -2
- package/package.json +13 -7
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { Hono } from 'hono';
|
|
4
|
+
import { serve } from '@hono/node-server';
|
|
5
|
+
import { packageRoutes } from './package-route';
|
|
6
|
+
dotenv.config({ path: path.resolve(process.cwd(), '.env.local') });
|
|
7
|
+
dotenv.config({ path: path.resolve(process.cwd(), '.env') });
|
|
8
|
+
const app = new Hono();
|
|
9
|
+
app.route('/api/v1', packageRoutes);
|
|
10
|
+
app.get('/', (c) => {
|
|
11
|
+
return c.text('MCP Registry API Server is running!');
|
|
12
|
+
});
|
|
13
|
+
app.notFound((c) => {
|
|
14
|
+
return c.json({ success: false, code: 404, message: 'Route not found' }, 404);
|
|
15
|
+
});
|
|
16
|
+
app.onError((err, c) => {
|
|
17
|
+
console.error('Server Error:', err);
|
|
18
|
+
return c.json({ success: false, code: 500, message: 'Internal server error' }, 500);
|
|
19
|
+
});
|
|
20
|
+
const port = process.env.MCP_SERVER_PORT ? parseInt(process.env.MCP_SERVER_PORT) : 3000;
|
|
21
|
+
console.log(`Server is running on: http://localhost:${port}`);
|
|
22
|
+
serve({
|
|
23
|
+
fetch: app.fetch,
|
|
24
|
+
port,
|
|
25
|
+
});
|
|
26
|
+
export default app;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Context } from 'hono';
|
|
2
|
+
export declare const packageHandler: {
|
|
3
|
+
executeTool: (c: Context) => Promise<(globalThis.Response & import("hono").TypedResponse<never, 200 | 500, "json">) | (globalThis.Response & import("hono").TypedResponse<{
|
|
4
|
+
success: false;
|
|
5
|
+
code: number;
|
|
6
|
+
message: string;
|
|
7
|
+
}, 404, "json">)>;
|
|
8
|
+
getPackageDetail: (c: Context) => Promise<(globalThis.Response & import("hono").TypedResponse<{
|
|
9
|
+
success: false;
|
|
10
|
+
code: number;
|
|
11
|
+
message: string;
|
|
12
|
+
}, 400, "json">) | (globalThis.Response & import("hono").TypedResponse<{
|
|
13
|
+
success: boolean;
|
|
14
|
+
code: number;
|
|
15
|
+
message: string;
|
|
16
|
+
data?: {
|
|
17
|
+
type: "mcp-server";
|
|
18
|
+
packageName: string;
|
|
19
|
+
runtime: "node" | "python" | "java" | "go";
|
|
20
|
+
key?: string | undefined;
|
|
21
|
+
name?: string | undefined;
|
|
22
|
+
description?: string | undefined;
|
|
23
|
+
packageVersion?: string | undefined;
|
|
24
|
+
bin?: string | undefined;
|
|
25
|
+
binArgs?: string[] | undefined;
|
|
26
|
+
readme?: string | undefined;
|
|
27
|
+
url?: string | undefined;
|
|
28
|
+
license?: string | undefined;
|
|
29
|
+
logo?: string | undefined;
|
|
30
|
+
author?: string | undefined;
|
|
31
|
+
env?: {
|
|
32
|
+
[x: string]: {
|
|
33
|
+
description: string;
|
|
34
|
+
required: boolean;
|
|
35
|
+
};
|
|
36
|
+
} | undefined;
|
|
37
|
+
} | undefined;
|
|
38
|
+
}, 200 | 404, "json">)>;
|
|
39
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PackageSO } from './package-so';
|
|
2
|
+
export const packageHandler = {
|
|
3
|
+
executeTool: async (c) => {
|
|
4
|
+
const requestBody = await c.req.json();
|
|
5
|
+
try {
|
|
6
|
+
const toolSO = new PackageSO();
|
|
7
|
+
const result = await toolSO.executeTool(requestBody);
|
|
8
|
+
const statusCode = result.success ? 200 : 500;
|
|
9
|
+
return c.json(result, statusCode);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (error instanceof Error && (error.message.includes('not found') || error.message.includes('Unknown tool'))) {
|
|
13
|
+
return c.json({
|
|
14
|
+
success: false,
|
|
15
|
+
code: 404,
|
|
16
|
+
message: `Package '${requestBody.packageName}' or tool '${requestBody.toolKey}' not found`,
|
|
17
|
+
}, 404);
|
|
18
|
+
}
|
|
19
|
+
// Other errors are still thrown
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
getPackageDetail: async (c) => {
|
|
24
|
+
const packageName = c.req.query('packageName');
|
|
25
|
+
if (!packageName) {
|
|
26
|
+
return c.json({
|
|
27
|
+
success: false,
|
|
28
|
+
code: 400,
|
|
29
|
+
message: 'Missing packageName query parameter',
|
|
30
|
+
}, 400);
|
|
31
|
+
}
|
|
32
|
+
const toolSO = new PackageSO();
|
|
33
|
+
const result = await toolSO.getPackageDetail(packageName);
|
|
34
|
+
const statusCode = result.success ? 200 : 404;
|
|
35
|
+
return c.json(result, statusCode);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { packageHandler } from './package-handler';
|
|
4
|
+
export const packageRoutes = new Hono();
|
|
5
|
+
packageRoutes.post('/packages/run', packageHandler.executeTool);
|
|
6
|
+
packageRoutes.get('/packages/detail', packageHandler.getPackageDetail);
|
|
7
|
+
packageRoutes.get('/config/categories', (c) => {
|
|
8
|
+
const categories = require('../../config/categories.mjs').default;
|
|
9
|
+
const response = {
|
|
10
|
+
success: true,
|
|
11
|
+
code: 200,
|
|
12
|
+
message: 'Categories retrieved successfully',
|
|
13
|
+
data: categories,
|
|
14
|
+
};
|
|
15
|
+
return c.json(response);
|
|
16
|
+
});
|
|
17
|
+
packageRoutes.get('/config/featured', (c) => {
|
|
18
|
+
const featured = require('../../config/featured.mjs').default;
|
|
19
|
+
const response = {
|
|
20
|
+
success: true,
|
|
21
|
+
code: 200,
|
|
22
|
+
message: 'Featured list retrieved successfully',
|
|
23
|
+
data: featured,
|
|
24
|
+
};
|
|
25
|
+
return c.json(response);
|
|
26
|
+
});
|
|
27
|
+
packageRoutes.get('/indexes/packages-list', async (c) => {
|
|
28
|
+
const packagesList = (await import('../../indexes/packages-list.json')).default;
|
|
29
|
+
const response = {
|
|
30
|
+
success: true,
|
|
31
|
+
code: 200,
|
|
32
|
+
message: 'Packages list retrieved successfully',
|
|
33
|
+
data: packagesList,
|
|
34
|
+
};
|
|
35
|
+
return c.json(response);
|
|
36
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { getPackageConfigByKey, getMcpClient, typedAllPackagesList } from '../helper.js';
|
|
4
|
+
export class PackageSO {
|
|
5
|
+
async executeTool(request) {
|
|
6
|
+
const mcpServerConfig = getPackageConfigByKey(request.packageName);
|
|
7
|
+
const { client, closeConnection } = await getMcpClient(mcpServerConfig, request.envs || {});
|
|
8
|
+
try {
|
|
9
|
+
const result = await client.callTool({
|
|
10
|
+
name: request.toolKey,
|
|
11
|
+
arguments: request.inputData,
|
|
12
|
+
});
|
|
13
|
+
console.log(`Tool ${request.toolKey} executed successfully`);
|
|
14
|
+
return {
|
|
15
|
+
success: true,
|
|
16
|
+
code: 200,
|
|
17
|
+
message: 'Tool executed successfully',
|
|
18
|
+
data: result,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
await closeConnection();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async getPackageDetail(packageName) {
|
|
26
|
+
const packageInfo = typedAllPackagesList[packageName];
|
|
27
|
+
if (!packageInfo) {
|
|
28
|
+
return {
|
|
29
|
+
success: false,
|
|
30
|
+
code: 404,
|
|
31
|
+
message: `Package ${packageName} not found`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const jsonFilePath = path.join(__dirname, '../../packages/', packageInfo.path);
|
|
35
|
+
const jsonStr = fs.readFileSync(jsonFilePath, 'utf-8');
|
|
36
|
+
const packageConfig = JSON.parse(jsonStr);
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
code: 200,
|
|
40
|
+
message: 'Package detail retrieved successfully',
|
|
41
|
+
data: packageConfig,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// npx vitest run src/api/package.test.ts
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { PackageSO } from './package-so';
|
|
4
|
+
describe('PackageSO - MCP Tool Execution Service Test', () => {
|
|
5
|
+
it('should execute tool successfully', async () => {
|
|
6
|
+
const toolSO = new PackageSO();
|
|
7
|
+
const request = {
|
|
8
|
+
packageName: 'mcp-starter',
|
|
9
|
+
toolKey: 'hello_tool',
|
|
10
|
+
inputData: { name: 'Mike' },
|
|
11
|
+
envs: {},
|
|
12
|
+
};
|
|
13
|
+
const result = await toolSO.executeTool(request);
|
|
14
|
+
expect(result.success).toBe(true);
|
|
15
|
+
expect(result.data).toEqual({
|
|
16
|
+
content: [],
|
|
17
|
+
message: 'Hello, Mike!',
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
package/dist/helper.js
CHANGED
|
@@ -1,141 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import axios from 'axios';
|
|
5
|
+
import semver from 'semver';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import allPackagesList from '../indexes/packages-list.json';
|
|
8
|
+
import assert from 'assert';
|
|
9
|
+
import { MCPServerPackageConfigSchema, PackagesListSchema } from './schema';
|
|
10
|
+
export const typedAllPackagesList = PackagesListSchema.parse(allPackagesList);
|
|
11
|
+
export function getPackageConfigByKey(packageKey) {
|
|
12
|
+
const value = typedAllPackagesList[packageKey];
|
|
13
|
+
if (!value) {
|
|
14
|
+
throw new Error(`Package '${packageKey}' not found in packages list.`);
|
|
7
15
|
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
-
};
|
|
47
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.typedAllPackagesList = void 0;
|
|
49
|
-
exports.getPackageConfigByKey = getPackageConfigByKey;
|
|
50
|
-
exports.getPackageJSON = getPackageJSON;
|
|
51
|
-
exports.getMcpClient = getMcpClient;
|
|
52
|
-
exports.updatePackageJsonDependencies = updatePackageJsonDependencies;
|
|
53
|
-
exports.getActualVersion = getActualVersion;
|
|
54
|
-
exports.withTimeout = withTimeout;
|
|
55
|
-
exports.isValidNpmPackage = isValidNpmPackage;
|
|
56
|
-
const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
57
|
-
const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
|
|
58
|
-
const fs_1 = __importDefault(require("fs"));
|
|
59
|
-
const axios_1 = __importDefault(require("axios"));
|
|
60
|
-
const semver_1 = __importDefault(require("semver"));
|
|
61
|
-
const path = __importStar(require("path"));
|
|
62
|
-
const packages_list_json_1 = __importDefault(require("../indexes/packages-list.json"));
|
|
63
|
-
const assert_1 = __importDefault(require("assert"));
|
|
64
|
-
const schema_1 = require("./schema");
|
|
65
|
-
exports.typedAllPackagesList = schema_1.PackagesListSchema.parse(packages_list_json_1.default);
|
|
66
|
-
function getPackageConfigByKey(packageKey) {
|
|
67
|
-
const value = exports.typedAllPackagesList[packageKey];
|
|
68
16
|
const jsonFile = value.path;
|
|
69
17
|
// read the JSON file and convert it to MCPServerPackageConfig
|
|
70
|
-
const jsonStr =
|
|
71
|
-
const mcpServerConfig =
|
|
18
|
+
const jsonStr = fs.readFileSync(__dirname + '/../packages/' + jsonFile, 'utf-8');
|
|
19
|
+
const mcpServerConfig = MCPServerPackageConfigSchema.parse(JSON.parse(jsonStr));
|
|
72
20
|
return mcpServerConfig;
|
|
73
21
|
}
|
|
74
|
-
function getPackageJSON(packageName) {
|
|
22
|
+
export function getPackageJSON(packageName) {
|
|
75
23
|
const packageJSONFilePath = __dirname + '/../node_modules/' + packageName + '/package.json';
|
|
76
|
-
const packageJSONStr =
|
|
24
|
+
const packageJSONStr = fs.readFileSync(packageJSONFilePath, 'utf8');
|
|
77
25
|
const packageJSON = JSON.parse(packageJSONStr);
|
|
78
26
|
return packageJSON;
|
|
79
27
|
}
|
|
80
|
-
function getMcpClient(mcpServerConfig, env) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
28
|
+
export async function getMcpClient(mcpServerConfig, env) {
|
|
29
|
+
const { packageName } = mcpServerConfig;
|
|
30
|
+
const packageJSON = getPackageJSON(packageName);
|
|
31
|
+
let binFilePath = '';
|
|
32
|
+
let binPath;
|
|
33
|
+
if (typeof packageJSON.bin === 'string') {
|
|
34
|
+
binPath = packageJSON.bin;
|
|
35
|
+
}
|
|
36
|
+
else if (typeof packageJSON.bin === 'object') {
|
|
37
|
+
binPath = Object.values(packageJSON.bin)[0];
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
binPath = packageJSON.main;
|
|
41
|
+
}
|
|
42
|
+
assert(binPath, `Package ${packageName} does not have a valid bin path in package.json.`);
|
|
43
|
+
// binFilePath = 'plugin_packages/' + packageName + `/${binPath}`;
|
|
44
|
+
binFilePath = __dirname + '/../node_modules/' + packageName + `/${binPath}`;
|
|
45
|
+
const mcpServerBinPath = mcpServerConfig.bin || binFilePath;
|
|
46
|
+
const binArgs = mcpServerConfig.binArgs || [];
|
|
47
|
+
const transport = new StdioClientTransport({
|
|
48
|
+
command: process.execPath,
|
|
49
|
+
args: [mcpServerBinPath, ...binArgs],
|
|
50
|
+
env: env || {},
|
|
51
|
+
});
|
|
52
|
+
const client = new Client({
|
|
53
|
+
name: `mcp-server-${mcpServerConfig.name}-client`,
|
|
54
|
+
version: '1.0.0',
|
|
55
|
+
}, {
|
|
56
|
+
capabilities: {
|
|
57
|
+
tools: {},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
await client.connect(transport);
|
|
61
|
+
const closeConnection = async () => {
|
|
62
|
+
try {
|
|
63
|
+
await client.close();
|
|
91
64
|
}
|
|
92
|
-
|
|
93
|
-
|
|
65
|
+
catch (e) {
|
|
66
|
+
console.warn(`${packageName} mcp client close failure.`, e);
|
|
94
67
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
binFilePath = __dirname + '/../node_modules/' + packageName + `/${binPath}`;
|
|
98
|
-
const mcpServerBinPath = mcpServerConfig.bin || binFilePath;
|
|
99
|
-
const binArgs = mcpServerConfig.binArgs || [];
|
|
100
|
-
const transport = new stdio_js_1.StdioClientTransport({
|
|
101
|
-
command: process.execPath,
|
|
102
|
-
args: [mcpServerBinPath, ...binArgs],
|
|
103
|
-
env: env || {},
|
|
104
|
-
});
|
|
105
|
-
const client = new index_js_1.Client({
|
|
106
|
-
name: `mcp-server-${mcpServerConfig.name}-client`,
|
|
107
|
-
version: '1.0.0',
|
|
108
|
-
}, {
|
|
109
|
-
capabilities: {
|
|
110
|
-
tools: {},
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
yield client.connect(transport);
|
|
114
|
-
const closeConnection = () => __awaiter(this, void 0, void 0, function* () {
|
|
115
|
-
try {
|
|
116
|
-
yield client.close();
|
|
117
|
-
}
|
|
118
|
-
catch (e) {
|
|
119
|
-
console.warn(`${packageName} mcp client close failure.`, e);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
return { client, transport, closeConnection };
|
|
123
|
-
});
|
|
68
|
+
};
|
|
69
|
+
return { client, transport, closeConnection };
|
|
124
70
|
}
|
|
125
|
-
function updatePackageJsonDependencies({ packageDeps, enableValidation = false, }) {
|
|
71
|
+
export function updatePackageJsonDependencies({ packageDeps, enableValidation = false, }) {
|
|
126
72
|
var _a;
|
|
127
73
|
// Write package.json dependencies
|
|
128
74
|
const packageJsonFile = './package.json';
|
|
129
|
-
const packageJSONStr =
|
|
75
|
+
const packageJSONStr = fs.readFileSync(packageJsonFile, 'utf-8');
|
|
130
76
|
const newDeps = {
|
|
131
77
|
'@modelcontextprotocol/sdk': '^1.12.0',
|
|
78
|
+
'@hono/node-server': '1.15.0',
|
|
132
79
|
lodash: '^4.17.21',
|
|
133
80
|
zod: '^3.23.30',
|
|
134
81
|
axios: '^1.9.0',
|
|
82
|
+
hono: '4.8.3',
|
|
135
83
|
semver: '^7.5.4',
|
|
136
84
|
};
|
|
137
85
|
for (const [depName, depVer] of Object.entries(packageDeps)) {
|
|
138
|
-
if (!enableValidation || ((_a =
|
|
86
|
+
if (!enableValidation || ((_a = typedAllPackagesList[depName]) === null || _a === void 0 ? void 0 : _a.validated)) {
|
|
139
87
|
newDeps[depName] = depVer || 'latest';
|
|
140
88
|
}
|
|
141
89
|
}
|
|
@@ -147,17 +95,17 @@ function updatePackageJsonDependencies({ packageDeps, enableValidation = false,
|
|
|
147
95
|
}
|
|
148
96
|
const packageJSON = JSON.parse(packageJSONStr);
|
|
149
97
|
packageJSON.dependencies = newDeps;
|
|
150
|
-
|
|
98
|
+
fs.writeFileSync(packageJsonFile, JSON.stringify(packageJSON, null, 2), 'utf-8');
|
|
151
99
|
console.log(`Generated new package.json file at ${packageJsonFile}`);
|
|
152
100
|
return;
|
|
153
101
|
}
|
|
154
|
-
function getActualVersion(packageName, configuredVersion) {
|
|
102
|
+
export function getActualVersion(packageName, configuredVersion) {
|
|
155
103
|
if (configuredVersion && configuredVersion !== 'latest') {
|
|
156
104
|
return configuredVersion;
|
|
157
105
|
}
|
|
158
106
|
try {
|
|
159
107
|
const packageJsonPath = path.join(__dirname, '../node_modules', packageName, 'package.json');
|
|
160
|
-
const packageJson = JSON.parse(
|
|
108
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
161
109
|
return packageJson.version;
|
|
162
110
|
}
|
|
163
111
|
catch (e) {
|
|
@@ -165,7 +113,7 @@ function getActualVersion(packageName, configuredVersion) {
|
|
|
165
113
|
return 'latest';
|
|
166
114
|
}
|
|
167
115
|
}
|
|
168
|
-
function withTimeout(ms, promise) {
|
|
116
|
+
export function withTimeout(ms, promise) {
|
|
169
117
|
return new Promise((resolve, reject) => {
|
|
170
118
|
const timer = setTimeout(() => {
|
|
171
119
|
reject(new Error(`Operation timed out after ${ms}ms`));
|
|
@@ -188,88 +136,84 @@ function checkDependencyValidity(dependencyData, versionRange) {
|
|
|
188
136
|
// 使用 semver 检查是否有满足版本范围的有效版本
|
|
189
137
|
const versions = Object.keys(dependencyData.versions);
|
|
190
138
|
for (const version of versions) {
|
|
191
|
-
if (
|
|
139
|
+
if (semver.satisfies(version, versionRange)) {
|
|
192
140
|
return true;
|
|
193
141
|
}
|
|
194
142
|
}
|
|
195
143
|
return false;
|
|
196
144
|
}
|
|
197
145
|
// 通用依赖项检查函数
|
|
198
|
-
function checkDependencies(dependencies) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
try {
|
|
207
|
-
const depResponse = yield axios_1.default.get(`https://registry.npmjs.org/${depName}`, {
|
|
208
|
-
timeout: 5000,
|
|
209
|
-
headers: {
|
|
210
|
-
'User-Agent': 'MyToolManager/1.0',
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
if (depResponse.status !== 200 || !depResponse.data.versions) {
|
|
214
|
-
console.error(`Failed to fetch ${depName}`);
|
|
215
|
-
dependencyCache[cacheKey] = false;
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
const isValid = checkDependencyValidity(depResponse.data, depVersionRange);
|
|
219
|
-
dependencyCache[cacheKey] = isValid;
|
|
220
|
-
if (!isValid) {
|
|
221
|
-
console.error(`Invalid or missing: ${depName}`);
|
|
222
|
-
}
|
|
223
|
-
return isValid;
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
console.error(`Error fetching ${depName}: ${error.message}`);
|
|
227
|
-
dependencyCache[cacheKey] = false;
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
const promises = Object.entries(dependencies).map(([depName, depVersionRange]) => checkSingleDependency(depName, depVersionRange));
|
|
232
|
-
const results = yield Promise.all(promises);
|
|
233
|
-
return results.every((result) => result);
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
// 判断 npm 包及其依赖是否有效
|
|
237
|
-
function isValidNpmPackage(packageName) {
|
|
238
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
239
|
-
var _a, _b, _c, _d;
|
|
146
|
+
async function checkDependencies(dependencies) {
|
|
147
|
+
const dependencyCache = {};
|
|
148
|
+
const checkSingleDependency = async (depName, depVersionRange) => {
|
|
149
|
+
const cacheKey = `${depName}@${depVersionRange}`;
|
|
150
|
+
if (dependencyCache[cacheKey] !== undefined) {
|
|
151
|
+
return dependencyCache[cacheKey];
|
|
152
|
+
}
|
|
240
153
|
try {
|
|
241
|
-
|
|
242
|
-
console.log('checking package:', packageName);
|
|
243
|
-
const response = yield axios_1.default.get(`https://registry.npmjs.org/${packageName}`, {
|
|
154
|
+
const depResponse = await axios.get(`https://registry.npmjs.org/${depName}`, {
|
|
244
155
|
timeout: 5000,
|
|
245
156
|
headers: {
|
|
246
157
|
'User-Agent': 'MyToolManager/1.0',
|
|
247
158
|
},
|
|
248
159
|
});
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
return false;
|
|
253
|
-
}
|
|
254
|
-
// 获取主包的最新版本信息
|
|
255
|
-
const latestVersion = response.data['dist-tags'].latest;
|
|
256
|
-
const versionData = (_d = (_c = response.data) === null || _c === void 0 ? void 0 : _c.versions) === null || _d === void 0 ? void 0 : _d[latestVersion];
|
|
257
|
-
if (!versionData) {
|
|
258
|
-
console.error(`Invalid package: ${packageName} - No version data found`);
|
|
160
|
+
if (depResponse.status !== 200 || !depResponse.data.versions) {
|
|
161
|
+
console.error(`Failed to fetch ${depName}`);
|
|
162
|
+
dependencyCache[cacheKey] = false;
|
|
259
163
|
return false;
|
|
260
164
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return false;
|
|
165
|
+
const isValid = checkDependencyValidity(depResponse.data, depVersionRange);
|
|
166
|
+
dependencyCache[cacheKey] = isValid;
|
|
167
|
+
if (!isValid) {
|
|
168
|
+
console.error(`Invalid or missing: ${depName}`);
|
|
266
169
|
}
|
|
267
|
-
|
|
268
|
-
return true;
|
|
170
|
+
return isValid;
|
|
269
171
|
}
|
|
270
172
|
catch (error) {
|
|
271
|
-
console.error(`Error
|
|
173
|
+
console.error(`Error fetching ${depName}: ${error.message}`);
|
|
174
|
+
dependencyCache[cacheKey] = false;
|
|
272
175
|
return false;
|
|
273
176
|
}
|
|
274
|
-
}
|
|
177
|
+
};
|
|
178
|
+
const promises = Object.entries(dependencies).map(([depName, depVersionRange]) => checkSingleDependency(depName, depVersionRange));
|
|
179
|
+
const results = await Promise.all(promises);
|
|
180
|
+
return results.every((result) => result);
|
|
181
|
+
}
|
|
182
|
+
// 判断 npm 包及其依赖是否有效
|
|
183
|
+
export async function isValidNpmPackage(packageName) {
|
|
184
|
+
var _a, _b, _c, _d;
|
|
185
|
+
try {
|
|
186
|
+
// 检查主包是否存在
|
|
187
|
+
console.log('checking package:', packageName);
|
|
188
|
+
const response = await axios.get(`https://registry.npmjs.org/${packageName}`, {
|
|
189
|
+
timeout: 5000,
|
|
190
|
+
headers: {
|
|
191
|
+
'User-Agent': 'MyToolManager/1.0',
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
// 检查主包是否被标记为 unpublished
|
|
195
|
+
if (response.status !== 200 || !((_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a['dist-tags']) === null || _b === void 0 ? void 0 : _b.latest)) {
|
|
196
|
+
console.error(`Package marked as unpublished: ${packageName}`);
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
// 获取主包的最新版本信息
|
|
200
|
+
const latestVersion = response.data['dist-tags'].latest;
|
|
201
|
+
const versionData = (_d = (_c = response.data) === null || _c === void 0 ? void 0 : _c.versions) === null || _d === void 0 ? void 0 : _d[latestVersion];
|
|
202
|
+
if (!versionData) {
|
|
203
|
+
console.error(`Invalid package: ${packageName} - No version data found`);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
// 检查 dependencies 和 devDependencies
|
|
207
|
+
console.log(`Checking dependencies for ${packageName}`);
|
|
208
|
+
const dependencies = Object.assign(Object.assign({}, versionData.dependencies), versionData.devDependencies);
|
|
209
|
+
if (!(await checkDependencies(dependencies))) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
console.log(`Valid package: ${packageName}`);
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error(`Error validating package ${packageName}:`, error.message);
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
275
219
|
}
|
package/dist/schema.d.ts
CHANGED
|
@@ -2,6 +2,22 @@ import { z } from 'zod';
|
|
|
2
2
|
export declare const PackageKeySchema: z.ZodString;
|
|
3
3
|
export declare const HostingBlackListSchema: z.ZodArray<z.ZodString, "many">;
|
|
4
4
|
export declare const FeaturedListSchema: z.ZodArray<z.ZodString, "many">;
|
|
5
|
+
export declare const ToolExecuteSchema: z.ZodObject<{
|
|
6
|
+
packageName: z.ZodString;
|
|
7
|
+
toolKey: z.ZodString;
|
|
8
|
+
inputData: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
9
|
+
envs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
packageName: string;
|
|
12
|
+
toolKey: string;
|
|
13
|
+
inputData: Record<string, unknown>;
|
|
14
|
+
envs?: Record<string, string> | undefined;
|
|
15
|
+
}, {
|
|
16
|
+
packageName: string;
|
|
17
|
+
toolKey: string;
|
|
18
|
+
inputData: Record<string, unknown>;
|
|
19
|
+
envs?: Record<string, string> | undefined;
|
|
20
|
+
}>;
|
|
5
21
|
export declare const CategoryConfigSchema: z.ZodObject<{
|
|
6
22
|
key: z.ZodString;
|
|
7
23
|
name: z.ZodString;
|
|
@@ -42,8 +58,8 @@ export declare const MCPServerPackageConfigSchema: z.ZodObject<{
|
|
|
42
58
|
}>>>;
|
|
43
59
|
}, "strip", z.ZodTypeAny, {
|
|
44
60
|
type: "mcp-server";
|
|
45
|
-
runtime: "node" | "python" | "java" | "go";
|
|
46
61
|
packageName: string;
|
|
62
|
+
runtime: "node" | "python" | "java" | "go";
|
|
47
63
|
key?: string | undefined;
|
|
48
64
|
name?: string | undefined;
|
|
49
65
|
description?: string | undefined;
|
|
@@ -61,8 +77,8 @@ export declare const MCPServerPackageConfigSchema: z.ZodObject<{
|
|
|
61
77
|
}> | undefined;
|
|
62
78
|
}, {
|
|
63
79
|
type: "mcp-server";
|
|
64
|
-
runtime: "node" | "python" | "java" | "go";
|
|
65
80
|
packageName: string;
|
|
81
|
+
runtime: "node" | "python" | "java" | "go";
|
|
66
82
|
key?: string | undefined;
|
|
67
83
|
name?: string | undefined;
|
|
68
84
|
description?: string | undefined;
|
|
@@ -106,8 +122,8 @@ export declare const PackageConfigSchema: z.ZodDiscriminatedUnion<"type", [z.Zod
|
|
|
106
122
|
}>>>;
|
|
107
123
|
}, "strip", z.ZodTypeAny, {
|
|
108
124
|
type: "mcp-server";
|
|
109
|
-
runtime: "node" | "python" | "java" | "go";
|
|
110
125
|
packageName: string;
|
|
126
|
+
runtime: "node" | "python" | "java" | "go";
|
|
111
127
|
key?: string | undefined;
|
|
112
128
|
name?: string | undefined;
|
|
113
129
|
description?: string | undefined;
|
|
@@ -125,8 +141,8 @@ export declare const PackageConfigSchema: z.ZodDiscriminatedUnion<"type", [z.Zod
|
|
|
125
141
|
}> | undefined;
|
|
126
142
|
}, {
|
|
127
143
|
type: "mcp-server";
|
|
128
|
-
runtime: "node" | "python" | "java" | "go";
|
|
129
144
|
packageName: string;
|
|
145
|
+
runtime: "node" | "python" | "java" | "go";
|
|
130
146
|
key?: string | undefined;
|
|
131
147
|
name?: string | undefined;
|
|
132
148
|
description?: string | undefined;
|
package/dist/schema.js
CHANGED
|
@@ -1,52 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
name: zod_1.z.string(),
|
|
11
|
-
description: zod_1.z.string().optional(),
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const PackageKeySchema = z.string();
|
|
3
|
+
export const HostingBlackListSchema = z.array(PackageKeySchema);
|
|
4
|
+
export const FeaturedListSchema = z.array(PackageKeySchema);
|
|
5
|
+
export const ToolExecuteSchema = z.object({
|
|
6
|
+
packageName: z.string(),
|
|
7
|
+
toolKey: z.string(),
|
|
8
|
+
inputData: z.record(z.unknown()),
|
|
9
|
+
envs: z.record(z.string()).optional(),
|
|
12
10
|
});
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
export const CategoryConfigSchema = z.object({
|
|
12
|
+
key: z.string(),
|
|
13
|
+
name: z.string(),
|
|
14
|
+
description: z.string().optional(),
|
|
15
|
+
});
|
|
16
|
+
export const MCPServerPackageConfigSchema = z.object({
|
|
17
|
+
type: z.literal('mcp-server'),
|
|
18
|
+
runtime: z.enum(['node', 'python', 'java', 'go']),
|
|
19
|
+
packageName: z.string().describe('Name of the node, python, java package '),
|
|
20
|
+
packageVersion: z.string().optional().describe('Version of the package, if not provided then it will use latest version'),
|
|
21
|
+
bin: z.string().optional().describe('Binary Command to run the MCP server, if not provided then it will use the package name'),
|
|
22
|
+
binArgs: z.array(z.string()).optional().describe('Binary Arguments to pass to the command, if not provided then it will use an empty array'),
|
|
20
23
|
// if no custom key then would use name
|
|
21
|
-
key:
|
|
22
|
-
name:
|
|
23
|
-
description:
|
|
24
|
-
readme:
|
|
25
|
-
url:
|
|
26
|
-
license:
|
|
27
|
-
logo:
|
|
28
|
-
author:
|
|
29
|
-
env:
|
|
30
|
-
.record(
|
|
31
|
-
description:
|
|
32
|
-
required:
|
|
24
|
+
key: z.string().optional().describe('Unique key for url and slug'),
|
|
25
|
+
name: z.string().optional().describe('Custom name for display, if empty then it will use the package name'),
|
|
26
|
+
description: z.string().optional(),
|
|
27
|
+
readme: z.string().optional().describe('URL to the README file, if not provided then it will use the package URL'),
|
|
28
|
+
url: z.string().optional(),
|
|
29
|
+
license: z.string().optional().describe('Open source license lie MIT, AGPL, GPL, etc'),
|
|
30
|
+
logo: z.string().optional().describe('URL to custom logo image, if undefined and the URL is Github, then it will use the Github logo'),
|
|
31
|
+
author: z.string().optional().describe('Author name of the ToolSDK.ai\'s developer ID'),
|
|
32
|
+
env: z
|
|
33
|
+
.record(z.object({
|
|
34
|
+
description: z.string(),
|
|
35
|
+
required: z.boolean(),
|
|
33
36
|
}))
|
|
34
37
|
.optional(),
|
|
35
38
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
type:
|
|
40
|
-
packageName:
|
|
41
|
-
url:
|
|
39
|
+
export const PackageConfigSchema = z.discriminatedUnion('type', [
|
|
40
|
+
MCPServerPackageConfigSchema,
|
|
41
|
+
z.object({
|
|
42
|
+
type: z.literal('toolapp'),
|
|
43
|
+
packageName: z.string(),
|
|
44
|
+
url: z.string().optional(),
|
|
42
45
|
}),
|
|
43
46
|
]);
|
|
44
|
-
|
|
45
|
-
category:
|
|
46
|
-
path:
|
|
47
|
-
validated:
|
|
48
|
-
tools:
|
|
49
|
-
name:
|
|
50
|
-
description:
|
|
47
|
+
export const PackagesListSchema = z.record(z.object({
|
|
48
|
+
category: z.string().optional(),
|
|
49
|
+
path: z.string(),
|
|
50
|
+
validated: z.boolean().optional(),
|
|
51
|
+
tools: z.record(z.object({
|
|
52
|
+
name: z.string().optional(),
|
|
53
|
+
description: z.string().optional(),
|
|
51
54
|
})).optional(),
|
|
52
55
|
}));
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { CategoryConfigSchema, PackageConfigSchema, MCPServerPackageConfigSchema, PackagesListSchema } from './schema';
|
|
2
|
+
import type { CategoryConfigSchema, PackageConfigSchema, MCPServerPackageConfigSchema, PackagesListSchema, ToolExecuteSchema } from './schema';
|
|
3
3
|
export type MCPServerPackageConfig = z.infer<typeof MCPServerPackageConfigSchema>;
|
|
4
4
|
export type PackageConfig = z.infer<typeof PackageConfigSchema>;
|
|
5
5
|
export type CategoryConfig = z.infer<typeof CategoryConfigSchema>;
|
|
6
6
|
export type PackagesList = z.infer<typeof PackagesListSchema>;
|
|
7
|
+
export type ToolExecute = z.infer<typeof ToolExecuteSchema>;
|
|
8
|
+
export interface Response<T> {
|
|
9
|
+
success: boolean;
|
|
10
|
+
code: number;
|
|
11
|
+
message: string;
|
|
12
|
+
data?: T;
|
|
13
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toolsdk.ai/registry",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.94",
|
|
4
4
|
"description": "An Open, Structured, and Standard Registry for MCP Servers and Packages.",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./config/*": "./config/*",
|
|
@@ -21,16 +21,19 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsc",
|
|
23
23
|
"lint": "eslint . --ext .ts,.tsx --ignore-pattern \"api/\"",
|
|
24
|
-
"
|
|
24
|
+
"dev": "tsx watch src/api/index.ts",
|
|
25
|
+
"start": "NODE_ENV=production tsx src/api/index.ts"
|
|
25
26
|
},
|
|
26
27
|
"keywords": [],
|
|
27
28
|
"author": "",
|
|
28
29
|
"license": "MIT",
|
|
29
30
|
"dependencies": {
|
|
30
31
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
32
|
+
"@hono/node-server": "1.15.0",
|
|
31
33
|
"lodash": "^4.17.21",
|
|
32
34
|
"zod": "^3.23.30",
|
|
33
35
|
"axios": "^1.9.0",
|
|
36
|
+
"hono": "4.8.3",
|
|
34
37
|
"semver": "^7.5.4",
|
|
35
38
|
"@toolsdk.ai/aws-ses-mcp": "1.0.1",
|
|
36
39
|
"@toolsdk.ai/mcp-send-email": "1.0.0",
|
|
@@ -156,7 +159,7 @@
|
|
|
156
159
|
"qasphere-mcp": "0.2.1",
|
|
157
160
|
"mcp-developer-name": "1.0.2",
|
|
158
161
|
"@nextdrive/github-action-trigger-mcp": "0.1.2",
|
|
159
|
-
"@ahdev/dokploy-mcp": "1.
|
|
162
|
+
"@ahdev/dokploy-mcp": "1.4.0",
|
|
160
163
|
"@jsonresume/mcp": "3.0.3",
|
|
161
164
|
"@growthbook/mcp": "0.1.1",
|
|
162
165
|
"deepsource-mcp-server": "1.2.1",
|
|
@@ -223,7 +226,7 @@
|
|
|
223
226
|
"hermes-search-mcp": "1.0.1",
|
|
224
227
|
"agentql-mcp": "1.0.0",
|
|
225
228
|
"pickapicon-mcp": "1.0.3",
|
|
226
|
-
"@adenot/mcp-google-search": "0.2.
|
|
229
|
+
"@adenot/mcp-google-search": "0.2.1",
|
|
227
230
|
"octagon-deep-research-mcp": "1.0.18",
|
|
228
231
|
"@humansean/mcp-bocha": "1.0.1",
|
|
229
232
|
"@cyanheads/pubmed-mcp-server": "1.2.3",
|
|
@@ -482,7 +485,7 @@
|
|
|
482
485
|
"mcp-lighthouse": "0.1.4",
|
|
483
486
|
"bitcoin-mcp": "0.0.6",
|
|
484
487
|
"@mcpfun/mcp-server-ccxt": "1.2.1",
|
|
485
|
-
"@agentek/mcp-server": "0.1.
|
|
488
|
+
"@agentek/mcp-server": "0.1.22",
|
|
486
489
|
"binance-mcp-server": "1.1.0",
|
|
487
490
|
"coincap-mcp": "0.9.3",
|
|
488
491
|
"@mcp-dockmaster/mcp-cryptowallet-evm": "1.0.6",
|
|
@@ -555,7 +558,7 @@
|
|
|
555
558
|
"mcp-nmap-server": "1.0.1",
|
|
556
559
|
"mcp-cisco-support": "1.9.8",
|
|
557
560
|
"@winterjung/mcp-korean-spell": "1.0.1",
|
|
558
|
-
"12306-mcp": "0.3.
|
|
561
|
+
"12306-mcp": "0.3.4",
|
|
559
562
|
"@openbnb/mcp-server-airbnb": "0.1.1",
|
|
560
563
|
"mcp-server-diff-typescript": "1.0.5",
|
|
561
564
|
"git-commands-mcp": "0.1.4",
|
|
@@ -624,10 +627,13 @@
|
|
|
624
627
|
"@types/lodash": "^4.17.17",
|
|
625
628
|
"@types/node": "^22.15.21",
|
|
626
629
|
"@types/semver": "^7.5.8",
|
|
630
|
+
"dotenv": "^17.2.1",
|
|
627
631
|
"eslint": "^9.27.0",
|
|
628
632
|
"eslint-plugin-react": "^7.37.5",
|
|
629
633
|
"globals": "^16.2.0",
|
|
634
|
+
"tsx": "^4.20.3",
|
|
630
635
|
"typescript": "^5.8.3",
|
|
631
|
-
"typescript-eslint": "^8.33.0"
|
|
636
|
+
"typescript-eslint": "^8.33.0",
|
|
637
|
+
"vitest": "^3.2.4"
|
|
632
638
|
}
|
|
633
639
|
}
|