@toolsdk.ai/registry 1.0.131 → 1.0.133
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 +11 -10
- package/dist/api/index.js +4 -0
- package/dist/domains/executor/executor-types.d.ts +3 -1
- package/dist/domains/executor/local-executor.d.ts +1 -1
- package/dist/domains/executor/local-executor.js +3 -3
- package/dist/domains/executor/sandbox-executor.d.ts +1 -1
- package/dist/domains/executor/sandbox-executor.js +3 -3
- package/dist/domains/oauth/__tests__/oauth-session.test.d.ts +1 -0
- package/dist/domains/oauth/__tests__/oauth-session.test.js +272 -0
- package/dist/domains/oauth/__tests__/oauth-utils.test.d.ts +1 -0
- package/dist/domains/oauth/__tests__/oauth-utils.test.js +284 -0
- package/dist/domains/oauth/index.d.ts +9 -0
- package/dist/domains/oauth/index.js +9 -0
- package/dist/domains/oauth/oauth-handler.d.ts +65 -0
- package/dist/domains/oauth/oauth-handler.js +355 -0
- package/dist/domains/oauth/oauth-route.d.ts +11 -0
- package/dist/domains/oauth/oauth-route.js +138 -0
- package/dist/domains/oauth/oauth-schema.d.ts +257 -0
- package/dist/domains/oauth/oauth-schema.js +119 -0
- package/dist/domains/oauth/oauth-session.d.ts +54 -0
- package/dist/domains/oauth/oauth-session.js +116 -0
- package/dist/domains/oauth/oauth-types.d.ts +148 -0
- package/dist/domains/oauth/oauth-types.js +9 -0
- package/dist/domains/oauth/oauth-utils.d.ts +99 -0
- package/dist/domains/oauth/oauth-utils.js +267 -0
- package/dist/domains/package/package-handler.d.ts +2 -2
- package/dist/domains/package/package-handler.js +4 -4
- package/dist/domains/package/package-route.js +5 -5
- package/dist/domains/package/package-schema.d.ts +81 -4
- package/dist/domains/package/package-schema.js +17 -0
- package/dist/domains/package/package-so.d.ts +11 -3
- package/dist/domains/package/package-so.js +4 -3
- package/dist/shared/schemas/common-schema.d.ts +92 -4
- package/dist/shared/schemas/common-schema.js +13 -0
- package/dist/shared/scripts-helpers/index.d.ts +9 -1
- package/dist/shared/utils/mcp-client-util.d.ts +3 -3
- package/dist/shared/utils/mcp-client-util.js +22 -1
- package/indexes/categories-list.json +1 -0
- package/indexes/packages-list.json +15 -0
- package/package.json +2 -1
- package/packages/developer-tools/github-mcp.json +19 -0
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<a href="https://github.com/toolsdk-ai/toolsdk-mcp-registry/actions/workflows/test.yaml">
|
|
14
14
|
<img src="https://github.com/toolsdk-ai/toolsdk-mcp-registry/actions/workflows/test.yaml/badge.svg" alt="Build Status" />
|
|
15
15
|
</a>
|
|
16
|
-
<img src="https://img.shields.io/badge/MCP_Servers-
|
|
16
|
+
<img src="https://img.shields.io/badge/MCP_Servers-4110-blue?style=flat-square" alt="MCP Servers Count" />
|
|
17
17
|
<img src="https://img.shields.io/badge/LICENSE-MIT-ff69b4?style=flat-square" alt="License" />
|
|
18
18
|
</p>
|
|
19
19
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
</p>
|
|
25
25
|
|
|
26
26
|
<p align="center">
|
|
27
|
-
🚀 <b>Open-source</b>, <b>production-ready</b>, and <b>developer-friendly</b> registry for
|
|
27
|
+
🚀 <b>Open-source</b>, <b>production-ready</b>, and <b>developer-friendly</b> registry for 4110+ Model Context Protocol (MCP) servers.
|
|
28
28
|
<br />
|
|
29
29
|
<i>Perfect for <b>AI automation</b>, <b>chatbot development</b>, <b>LLM integrations</b>, and <b>enterprise AI deployments</b>.</i>
|
|
30
30
|
</p>
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
</p>
|
|
35
35
|
|
|
36
36
|
<p align="center">
|
|
37
|
-
<a href="#mcp-servers">🔍 <b>Browse
|
|
37
|
+
<a href="#mcp-servers">🔍 <b>Browse 4110+ Tools</b></a>
|
|
38
38
|
•
|
|
39
39
|
<a href="#quick-start">🐳 <b>Deploy Private Registry</b></a>
|
|
40
40
|
•
|
|
@@ -73,7 +73,7 @@ docker compose up -d
|
|
|
73
73
|
- *See [Configuration Guide](./docs/DEVELOPMENT.md) for full details.*
|
|
74
74
|
|
|
75
75
|
> 💡 **Tip for Private Deployment**:
|
|
76
|
-
> This registry contains
|
|
76
|
+
> This registry contains 4110+ public MCP servers. If you only need a specific subset for your private environment, you can prune the `packages/` directory.
|
|
77
77
|
> 📖 See [Package Management Guide](./docs/DEVELOPMENT.md#5--package-management-for-private-deployment) for details.
|
|
78
78
|
|
|
79
79
|
That's it! Your self-hosted MCP registry is now running with:
|
|
@@ -85,7 +85,7 @@ That's it! Your self-hosted MCP registry is now running with:
|
|
|
85
85
|
|
|
86
86
|
- 🌐 **Local Web Interface**: http://localhost:3003
|
|
87
87
|
- 📚 **Swagger API Docs**: http://localhost:3003/swagger
|
|
88
|
-
- 🔍 **Search & Execute**
|
|
88
|
+
- 🔍 **Search & Execute** 4110+ MCP Servers remotely
|
|
89
89
|
- 🤖 **Integrate** with your AI agents, chatbots, and LLM applications
|
|
90
90
|
|
|
91
91
|
#### 💻 Remote Tool Execution Example
|
|
@@ -169,7 +169,7 @@ mcp_servers = requests.get(
|
|
|
169
169
|
### 🎯 Key Features
|
|
170
170
|
|
|
171
171
|
- 🔐 **Private & Self-Hosted** - Deploy your own secure MCP registry with Docker in minutes
|
|
172
|
-
- 🤖 **
|
|
172
|
+
- 🤖 **4110+ MCP Servers** - Largest curated collection of MCP servers
|
|
173
173
|
- ⚡ **Remote Execution** - Run MCP tools in isolated sandbox environments via REST API
|
|
174
174
|
- 🔍 **Powerful Search** - Fast, full-text search powered by Meilisearch
|
|
175
175
|
- 📦 **NPM Integration** - Use as a TypeScript/Node.js SDK in your projects
|
|
@@ -225,7 +225,7 @@ graph TD
|
|
|
225
225
|
|
|
226
226
|
This open-source registry provides:
|
|
227
227
|
|
|
228
|
-
- 📚 **Structured Registry** -
|
|
228
|
+
- 📚 **Structured Registry** - 4110+ validated MCP servers with metadata
|
|
229
229
|
- 🔗 **Multiple Formats** - JSON, npm package, and generated documentation
|
|
230
230
|
- 🌐 **REST API** - Query and execute tools remotely
|
|
231
231
|
- 📖 **Auto-Generated Docs** - Always up-to-date README and API documentation
|
|
@@ -313,7 +313,7 @@ Help grow the world's largest open-source MCP registry! Share your AI tools, plu
|
|
|
313
313
|
|
|
314
314
|
- [Fork this repository](https://github.com/toolsdk-ai/toolsdk-mcp-registry/fork)
|
|
315
315
|
- Create `your-mcp-server.json` in [packages/uncategorized](./packages/uncategorized)
|
|
316
|
-
- Submit a PR and join
|
|
316
|
+
- Submit a PR and join 4110+ MCP servers!
|
|
317
317
|
|
|
318
318
|
**3. Get Discovered**
|
|
319
319
|
|
|
@@ -331,9 +331,9 @@ Your MCP server will be:
|
|
|
331
331
|
|
|
332
332
|
## 📋 MCP Servers Directory
|
|
333
333
|
|
|
334
|
-
**
|
|
334
|
+
**4110+ AI Agent Tools, LLM Integrations & Automation Servers**
|
|
335
335
|
|
|
336
|
-
- ✅ **Validated & Tested** (
|
|
336
|
+
- ✅ **Validated & Tested** (711) - Production-ready MCP servers
|
|
337
337
|
- ⚙️ **Community Contributed** (3399) - Requires configuration
|
|
338
338
|
|
|
339
339
|
Browse by category: Developer Tools, AI Agents, Databases, Cloud Platforms, APIs, and more!
|
|
@@ -1908,6 +1908,7 @@ Enhance your development workflow with tools for coding and environment manageme
|
|
|
1908
1908
|
- [✅ deepsource-mcp-server](https://github.com/sapientpants/deepsource-mcp-server): Integrates with DeepSource's code quality platform to provide access to project metrics, issues, and analysis results for monitoring and troubleshooting code quality directly in conversations. (10 tools) (node)
|
|
1909
1909
|
- [✅ freecad-mcp](https://github.com/neka-nat/freecad-mcp): Enables AI-driven CAD modeling by providing a remote procedure call (RPC) server that allows programmatic control of FreeCAD, supporting operations like creating documents, inserting parts, editing objects, and executing Python code for generative design workflows. (10 tools) (python)
|
|
1910
1910
|
- [✅ gistpad-mcp](https://github.com/lostintangent/gistpad-mcp): Transforms GitHub Gists into a personal knowledge management system with specialized handling for daily notes, reusable prompts with frontmatter support, and comprehensive gist operations including creation, updating, archiving, and commenting for version-controlled knowledge storage. (28 tools) (node)
|
|
1911
|
+
- [✅ github-mcp](https://github.com/Seey215/github-mcp): A powerful GitHub automation tool that seamlessly connects AI assistants to your GitHub repositories (2 tools) (node)
|
|
1911
1912
|
- [✅ ios-simulator-mcp](https://github.com/joshuayoes/ios-simulator-mcp): Enables Claude to control iOS simulators for testing and debugging applications by providing tools for UI interaction, element inspection, and device information retrieval through Facebook's IDB tool. (10 tools) (node)
|
|
1912
1913
|
- [✅ it-tools-mcp](https://github.com/wrenchpilot/it-tools-mcp): Provides 50+ developer utilities including cryptographic operations, text processing, data format conversion, network calculations, and encoding functions through a containerized TypeScript server with security features and rate limiting. (119 tools) (node)
|
|
1913
1914
|
- [✅ jnews-mcp-server](https://github.com/juhemcp/jnews-mcp-server): Lightweight Python FastAPI server implementation for streamlined server-side interactions, using modern tooling like uv for dependency management and GitHub Actions for automated testing and deployment. (2 tools) (python)
|
package/dist/api/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { serve } from "@hono/node-server";
|
|
|
4
4
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
5
5
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
6
6
|
import { configRoutes } from "../domains/config/config-route";
|
|
7
|
+
import { oauthDemoRoutes, oauthRoutes } from "../domains/oauth/oauth-route";
|
|
7
8
|
import { repository } from "../domains/package/package-handler";
|
|
8
9
|
import { packageRoutes } from "../domains/package/package-route";
|
|
9
10
|
import { initRegistryFactory } from "../domains/registry/registry-factory";
|
|
@@ -31,6 +32,9 @@ const app = new OpenAPIHono();
|
|
|
31
32
|
// Domain routes
|
|
32
33
|
app.route("/api/v1", packageRoutes);
|
|
33
34
|
app.route("/api/v1/config", configRoutes);
|
|
35
|
+
app.route("/api/v1/oauth", oauthRoutes);
|
|
36
|
+
// Demo routes (serves demo-oauth.html and handles callbacks)
|
|
37
|
+
app.route("/demo", oauthDemoRoutes);
|
|
34
38
|
if (isSearchEnabled()) {
|
|
35
39
|
initializeSearchService().catch(console.error);
|
|
36
40
|
app.route("/api/v1/search", searchRoutes);
|
|
@@ -6,6 +6,8 @@ export interface ToolExecuteRequest {
|
|
|
6
6
|
inputData: Record<string, unknown>;
|
|
7
7
|
envs?: Record<string, string>;
|
|
8
8
|
sandboxProvider?: MCPSandboxProvider;
|
|
9
|
+
/** OAuth access token for MCP servers that require OAuth authentication */
|
|
10
|
+
accessToken?: string;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* Tool Executor Interface
|
|
@@ -13,5 +15,5 @@ export interface ToolExecuteRequest {
|
|
|
13
15
|
*/
|
|
14
16
|
export interface ToolExecutor {
|
|
15
17
|
executeTool(request: ToolExecuteRequest): Promise<unknown>;
|
|
16
|
-
listTools(packageName: string,
|
|
18
|
+
listTools(packageName: string, accessToken?: string): Promise<Tool[]>;
|
|
17
19
|
}
|
|
@@ -8,5 +8,5 @@ export declare class LocalExecutor implements ToolExecutor {
|
|
|
8
8
|
private readonly packageRepository;
|
|
9
9
|
constructor();
|
|
10
10
|
executeTool(request: ToolExecuteRequest): Promise<unknown>;
|
|
11
|
-
listTools(packageName: string): Promise<Tool[]>;
|
|
11
|
+
listTools(packageName: string, accessToken?: string): Promise<Tool[]>;
|
|
12
12
|
}
|
|
@@ -14,7 +14,7 @@ export class LocalExecutor {
|
|
|
14
14
|
}
|
|
15
15
|
async executeTool(request) {
|
|
16
16
|
const mcpServerConfig = this.packageRepository.getPackageConfig(request.packageName);
|
|
17
|
-
const { client, closeConnection } = await getMcpClient(mcpServerConfig, request.envs || {});
|
|
17
|
+
const { client, closeConnection } = await getMcpClient(mcpServerConfig, request.envs || {}, request.accessToken);
|
|
18
18
|
try {
|
|
19
19
|
const result = await client.callTool({
|
|
20
20
|
name: request.toolKey,
|
|
@@ -27,7 +27,7 @@ export class LocalExecutor {
|
|
|
27
27
|
await closeConnection();
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
async listTools(packageName) {
|
|
30
|
+
async listTools(packageName, accessToken) {
|
|
31
31
|
const mcpServerConfig = this.packageRepository.getPackageConfig(packageName);
|
|
32
32
|
const mockEnvs = {};
|
|
33
33
|
if (mcpServerConfig.env) {
|
|
@@ -35,7 +35,7 @@ export class LocalExecutor {
|
|
|
35
35
|
mockEnvs[key] = "mock_value";
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
const { client, closeConnection } = await getMcpClient(mcpServerConfig, mockEnvs);
|
|
38
|
+
const { client, closeConnection } = await getMcpClient(mcpServerConfig, mockEnvs, accessToken);
|
|
39
39
|
try {
|
|
40
40
|
const { tools } = await client.listTools();
|
|
41
41
|
console.log(`[LocalExecutor] Tools list retrieved successfully for package ${packageName}`);
|
|
@@ -12,5 +12,5 @@ export declare class SandboxExecutor implements ToolExecutor {
|
|
|
12
12
|
private readonly localExecutor;
|
|
13
13
|
constructor(provider: MCPSandboxProvider);
|
|
14
14
|
executeTool(request: ToolExecuteRequest): Promise<unknown>;
|
|
15
|
-
listTools(packageName: string): Promise<Tool[]>;
|
|
15
|
+
listTools(packageName: string, accessToken?: string): Promise<Tool[]>;
|
|
16
16
|
}
|
|
@@ -48,13 +48,13 @@ export class SandboxExecutor {
|
|
|
48
48
|
await this.sandboxPool.release(runtime, this.provider);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
async listTools(packageName) {
|
|
51
|
+
async listTools(packageName, accessToken) {
|
|
52
52
|
const mcpServerConfig = this.packageRepository.getPackageConfig(packageName);
|
|
53
53
|
const runtime = mcpServerConfig.runtime || "python";
|
|
54
54
|
// Sandbox only supports node runtime, fallback to LOCAL for other runtimes
|
|
55
55
|
if (runtime !== "node") {
|
|
56
56
|
console.log(`[SandboxExecutor] Runtime '${runtime}' is not supported in sandbox, using LOCAL execution`);
|
|
57
|
-
return await this.localExecutor.listTools(packageName);
|
|
57
|
+
return await this.localExecutor.listTools(packageName, accessToken);
|
|
58
58
|
}
|
|
59
59
|
const sandboxClient = await this.sandboxPool.acquire(runtime, this.provider);
|
|
60
60
|
try {
|
|
@@ -67,7 +67,7 @@ export class SandboxExecutor {
|
|
|
67
67
|
console.warn(`[SandboxExecutor] sandbox list tools failed, falling back to LOCAL execution`);
|
|
68
68
|
console.warn(`[SandboxExecutor] Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
69
69
|
try {
|
|
70
|
-
const tools = await this.localExecutor.listTools(packageName);
|
|
70
|
+
const tools = await this.localExecutor.listTools(packageName, accessToken);
|
|
71
71
|
console.log(`[SandboxExecutor] Tools list retrieved successfully with LOCAL fallback`);
|
|
72
72
|
return tools;
|
|
73
73
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { OAuthSessionStore } from "../oauth-session";
|
|
3
|
+
// Create a new instance for testing (not the singleton)
|
|
4
|
+
function createTestStore() {
|
|
5
|
+
const store = new OAuthSessionStore();
|
|
6
|
+
// Stop the cleanup timer to avoid interference with tests
|
|
7
|
+
store.stopCleanup();
|
|
8
|
+
return store;
|
|
9
|
+
}
|
|
10
|
+
function createMockSession(overrides = {}) {
|
|
11
|
+
return Object.assign({ sessionId: "test-session-id", state: "test-state", codeVerifier: "test-code-verifier", codeChallenge: "test-code-challenge", clientInfo: {
|
|
12
|
+
client_id: "test-client-id",
|
|
13
|
+
}, callbackBaseUrl: "http://localhost:3003/callback", mcpServerUrl: "http://localhost:3001/mcp", packageName: "github-mcp", oauthMetadata: {
|
|
14
|
+
issuer: "http://localhost:3001",
|
|
15
|
+
authorization_endpoint: "http://localhost:3001/authorize",
|
|
16
|
+
token_endpoint: "http://localhost:3001/token",
|
|
17
|
+
}, createdAt: Date.now() }, overrides);
|
|
18
|
+
}
|
|
19
|
+
describe("OAuthSessionStore", () => {
|
|
20
|
+
let store;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
store = createTestStore();
|
|
23
|
+
});
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
store.stopCleanup();
|
|
26
|
+
store.clear();
|
|
27
|
+
});
|
|
28
|
+
describe("set", () => {
|
|
29
|
+
it("should store a session", () => {
|
|
30
|
+
// Arrange
|
|
31
|
+
const session = createMockSession();
|
|
32
|
+
// Act
|
|
33
|
+
store.set(session);
|
|
34
|
+
// Assert
|
|
35
|
+
expect(store.has(session.sessionId)).toBe(true);
|
|
36
|
+
expect(store.size()).toBe(1);
|
|
37
|
+
});
|
|
38
|
+
it("should allow retrieval by sessionId after set", () => {
|
|
39
|
+
// Arrange
|
|
40
|
+
const session = createMockSession();
|
|
41
|
+
// Act
|
|
42
|
+
store.set(session);
|
|
43
|
+
const retrieved = store.get(session.sessionId);
|
|
44
|
+
// Assert
|
|
45
|
+
expect(retrieved).toEqual(session);
|
|
46
|
+
});
|
|
47
|
+
it("should allow retrieval by state after set", () => {
|
|
48
|
+
// Arrange
|
|
49
|
+
const session = createMockSession();
|
|
50
|
+
// Act
|
|
51
|
+
store.set(session);
|
|
52
|
+
const retrieved = store.getByState(session.state);
|
|
53
|
+
// Assert
|
|
54
|
+
expect(retrieved).toEqual(session);
|
|
55
|
+
});
|
|
56
|
+
it("should overwrite session with same sessionId", () => {
|
|
57
|
+
// Arrange
|
|
58
|
+
const session1 = createMockSession({ packageName: "package1" });
|
|
59
|
+
const session2 = createMockSession({ packageName: "package2" });
|
|
60
|
+
// Act
|
|
61
|
+
store.set(session1);
|
|
62
|
+
store.set(session2);
|
|
63
|
+
// Assert
|
|
64
|
+
const retrieved = store.get(session1.sessionId);
|
|
65
|
+
expect(retrieved === null || retrieved === void 0 ? void 0 : retrieved.packageName).toBe("package2");
|
|
66
|
+
expect(store.size()).toBe(1);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe("get", () => {
|
|
70
|
+
it("should return undefined for non-existent session", () => {
|
|
71
|
+
// Act
|
|
72
|
+
const result = store.get("non-existent-id");
|
|
73
|
+
// Assert
|
|
74
|
+
expect(result).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
it("should return session when exists", () => {
|
|
77
|
+
// Arrange
|
|
78
|
+
const session = createMockSession();
|
|
79
|
+
store.set(session);
|
|
80
|
+
// Act
|
|
81
|
+
const result = store.get(session.sessionId);
|
|
82
|
+
// Assert
|
|
83
|
+
expect(result).toEqual(session);
|
|
84
|
+
});
|
|
85
|
+
it("should return undefined for expired session", () => {
|
|
86
|
+
// Arrange - create session that expired 11 minutes ago
|
|
87
|
+
const expiredSession = createMockSession({
|
|
88
|
+
sessionId: "expired-session",
|
|
89
|
+
createdAt: Date.now() - 11 * 60 * 1000,
|
|
90
|
+
});
|
|
91
|
+
store.set(expiredSession);
|
|
92
|
+
// Act
|
|
93
|
+
const result = store.get("expired-session");
|
|
94
|
+
// Assert
|
|
95
|
+
expect(result).toBeUndefined();
|
|
96
|
+
expect(store.has("expired-session")).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
it("should return session that is still valid (9 minutes old)", () => {
|
|
99
|
+
// Arrange
|
|
100
|
+
const validSession = createMockSession({
|
|
101
|
+
sessionId: "valid-session",
|
|
102
|
+
createdAt: Date.now() - 9 * 60 * 1000,
|
|
103
|
+
});
|
|
104
|
+
store.set(validSession);
|
|
105
|
+
// Act
|
|
106
|
+
const result = store.get("valid-session");
|
|
107
|
+
// Assert
|
|
108
|
+
expect(result).toBeDefined();
|
|
109
|
+
expect(result === null || result === void 0 ? void 0 : result.sessionId).toBe("valid-session");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe("getByState", () => {
|
|
113
|
+
it("should return undefined for non-existent state", () => {
|
|
114
|
+
// Act
|
|
115
|
+
const result = store.getByState("non-existent-state");
|
|
116
|
+
// Assert
|
|
117
|
+
expect(result).toBeUndefined();
|
|
118
|
+
});
|
|
119
|
+
it("should return session when state exists", () => {
|
|
120
|
+
// Arrange
|
|
121
|
+
const session = createMockSession({ state: "unique-state" });
|
|
122
|
+
store.set(session);
|
|
123
|
+
// Act
|
|
124
|
+
const result = store.getByState("unique-state");
|
|
125
|
+
// Assert
|
|
126
|
+
expect(result).toEqual(session);
|
|
127
|
+
});
|
|
128
|
+
it("should return undefined for expired session by state", () => {
|
|
129
|
+
// Arrange
|
|
130
|
+
const expiredSession = createMockSession({
|
|
131
|
+
state: "expired-state",
|
|
132
|
+
createdAt: Date.now() - 11 * 60 * 1000,
|
|
133
|
+
});
|
|
134
|
+
store.set(expiredSession);
|
|
135
|
+
// Act
|
|
136
|
+
const result = store.getByState("expired-state");
|
|
137
|
+
// Assert
|
|
138
|
+
expect(result).toBeUndefined();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe("delete", () => {
|
|
142
|
+
it("should return false for non-existent session", () => {
|
|
143
|
+
// Act
|
|
144
|
+
const result = store.delete("non-existent-id");
|
|
145
|
+
// Assert
|
|
146
|
+
expect(result).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
it("should delete existing session and return true", () => {
|
|
149
|
+
// Arrange
|
|
150
|
+
const session = createMockSession();
|
|
151
|
+
store.set(session);
|
|
152
|
+
// Act
|
|
153
|
+
const result = store.delete(session.sessionId);
|
|
154
|
+
// Assert
|
|
155
|
+
expect(result).toBe(true);
|
|
156
|
+
expect(store.has(session.sessionId)).toBe(false);
|
|
157
|
+
expect(store.size()).toBe(0);
|
|
158
|
+
});
|
|
159
|
+
it("should also remove state mapping when session is deleted", () => {
|
|
160
|
+
// Arrange
|
|
161
|
+
const session = createMockSession({ state: "state-to-delete" });
|
|
162
|
+
store.set(session);
|
|
163
|
+
// Act
|
|
164
|
+
store.delete(session.sessionId);
|
|
165
|
+
const byState = store.getByState("state-to-delete");
|
|
166
|
+
// Assert
|
|
167
|
+
expect(byState).toBeUndefined();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe("has", () => {
|
|
171
|
+
it("should return false for non-existent session", () => {
|
|
172
|
+
// Act
|
|
173
|
+
const result = store.has("non-existent-id");
|
|
174
|
+
// Assert
|
|
175
|
+
expect(result).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
it("should return true for existing session", () => {
|
|
178
|
+
// Arrange
|
|
179
|
+
const session = createMockSession();
|
|
180
|
+
store.set(session);
|
|
181
|
+
// Act
|
|
182
|
+
const result = store.has(session.sessionId);
|
|
183
|
+
// Assert
|
|
184
|
+
expect(result).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
describe("size", () => {
|
|
188
|
+
it("should return 0 for empty store", () => {
|
|
189
|
+
// Act
|
|
190
|
+
const result = store.size();
|
|
191
|
+
// Assert
|
|
192
|
+
expect(result).toBe(0);
|
|
193
|
+
});
|
|
194
|
+
it("should return correct count after adding sessions", () => {
|
|
195
|
+
// Arrange
|
|
196
|
+
store.set(createMockSession({ sessionId: "session-1", state: "state-1" }));
|
|
197
|
+
store.set(createMockSession({ sessionId: "session-2", state: "state-2" }));
|
|
198
|
+
store.set(createMockSession({ sessionId: "session-3", state: "state-3" }));
|
|
199
|
+
// Act
|
|
200
|
+
const result = store.size();
|
|
201
|
+
// Assert
|
|
202
|
+
expect(result).toBe(3);
|
|
203
|
+
});
|
|
204
|
+
it("should return correct count after deleting sessions", () => {
|
|
205
|
+
// Arrange
|
|
206
|
+
store.set(createMockSession({ sessionId: "session-1", state: "state-1" }));
|
|
207
|
+
store.set(createMockSession({ sessionId: "session-2", state: "state-2" }));
|
|
208
|
+
store.delete("session-1");
|
|
209
|
+
// Act
|
|
210
|
+
const result = store.size();
|
|
211
|
+
// Assert
|
|
212
|
+
expect(result).toBe(1);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe("clear", () => {
|
|
216
|
+
it("should remove all sessions", () => {
|
|
217
|
+
// Arrange
|
|
218
|
+
store.set(createMockSession({ sessionId: "session-1", state: "state-1" }));
|
|
219
|
+
store.set(createMockSession({ sessionId: "session-2", state: "state-2" }));
|
|
220
|
+
// Act
|
|
221
|
+
store.clear();
|
|
222
|
+
// Assert
|
|
223
|
+
expect(store.size()).toBe(0);
|
|
224
|
+
expect(store.has("session-1")).toBe(false);
|
|
225
|
+
expect(store.has("session-2")).toBe(false);
|
|
226
|
+
});
|
|
227
|
+
it("should also clear state mappings", () => {
|
|
228
|
+
// Arrange
|
|
229
|
+
store.set(createMockSession({ sessionId: "session-1", state: "state-1" }));
|
|
230
|
+
// Act
|
|
231
|
+
store.clear();
|
|
232
|
+
const byState = store.getByState("state-1");
|
|
233
|
+
// Assert
|
|
234
|
+
expect(byState).toBeUndefined();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
describe("multiple sessions", () => {
|
|
238
|
+
it("should handle multiple sessions with different states", () => {
|
|
239
|
+
var _a, _b, _c, _d;
|
|
240
|
+
// Arrange
|
|
241
|
+
const session1 = createMockSession({
|
|
242
|
+
sessionId: "session-1",
|
|
243
|
+
state: "state-1",
|
|
244
|
+
packageName: "package-1",
|
|
245
|
+
});
|
|
246
|
+
const session2 = createMockSession({
|
|
247
|
+
sessionId: "session-2",
|
|
248
|
+
state: "state-2",
|
|
249
|
+
packageName: "package-2",
|
|
250
|
+
});
|
|
251
|
+
// Act
|
|
252
|
+
store.set(session1);
|
|
253
|
+
store.set(session2);
|
|
254
|
+
// Assert
|
|
255
|
+
expect((_a = store.get("session-1")) === null || _a === void 0 ? void 0 : _a.packageName).toBe("package-1");
|
|
256
|
+
expect((_b = store.get("session-2")) === null || _b === void 0 ? void 0 : _b.packageName).toBe("package-2");
|
|
257
|
+
expect((_c = store.getByState("state-1")) === null || _c === void 0 ? void 0 : _c.packageName).toBe("package-1");
|
|
258
|
+
expect((_d = store.getByState("state-2")) === null || _d === void 0 ? void 0 : _d.packageName).toBe("package-2");
|
|
259
|
+
});
|
|
260
|
+
it("should not affect other sessions when deleting one", () => {
|
|
261
|
+
// Arrange
|
|
262
|
+
store.set(createMockSession({ sessionId: "session-1", state: "state-1" }));
|
|
263
|
+
store.set(createMockSession({ sessionId: "session-2", state: "state-2" }));
|
|
264
|
+
// Act
|
|
265
|
+
store.delete("session-1");
|
|
266
|
+
// Assert
|
|
267
|
+
expect(store.has("session-1")).toBe(false);
|
|
268
|
+
expect(store.has("session-2")).toBe(true);
|
|
269
|
+
expect(store.getByState("state-2")).toBeDefined();
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|