rbxstudio-mcp 1.9.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/LICENSE +21 -0
- package/README.md +319 -0
- package/dist/__tests__/bridge-service.test.d.ts +2 -0
- package/dist/__tests__/bridge-service.test.d.ts.map +1 -0
- package/dist/__tests__/bridge-service.test.js +109 -0
- package/dist/__tests__/bridge-service.test.js.map +1 -0
- package/dist/__tests__/http-server.test.d.ts +2 -0
- package/dist/__tests__/http-server.test.d.ts.map +1 -0
- package/dist/__tests__/http-server.test.js +193 -0
- package/dist/__tests__/http-server.test.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +2 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +182 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/__tests__/smoke.test.d.ts +2 -0
- package/dist/__tests__/smoke.test.d.ts.map +1 -0
- package/dist/__tests__/smoke.test.js +63 -0
- package/dist/__tests__/smoke.test.js.map +1 -0
- package/dist/bridge-service.d.ts +17 -0
- package/dist/bridge-service.d.ts.map +1 -0
- package/dist/bridge-service.js +77 -0
- package/dist/bridge-service.js.map +1 -0
- package/dist/http-server.d.ts +4 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +290 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1102 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/index.d.ts +273 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +628 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/studio-client.d.ts +7 -0
- package/dist/tools/studio-client.d.ts.map +1 -0
- package/dist/tools/studio-client.js +19 -0
- package/dist/tools/studio-client.js.map +1 -0
- package/package.json +69 -0
- package/studio-plugin/INSTALLATION.md +150 -0
- package/studio-plugin/MCPPlugin.rbxmx +3253 -0
- package/studio-plugin/plugin.json +10 -0
- package/studio-plugin/plugin.luau +3584 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.test.js","sourceRoot":"","sources":["../../src/__tests__/http-server.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import { createHttpServer } from '../http-server';
|
|
3
|
+
import { RobloxStudioTools } from '../tools/index';
|
|
4
|
+
import { BridgeService } from '../bridge-service';
|
|
5
|
+
describe('Integration Tests', () => {
|
|
6
|
+
let app;
|
|
7
|
+
let bridge;
|
|
8
|
+
let tools;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
bridge = new BridgeService();
|
|
11
|
+
tools = new RobloxStudioTools(bridge);
|
|
12
|
+
app = createHttpServer(tools, bridge);
|
|
13
|
+
});
|
|
14
|
+
describe('Full Connection Flow', () => {
|
|
15
|
+
test('should handle complete connection lifecycle', async () => {
|
|
16
|
+
// 1. Initial state - nothing connected
|
|
17
|
+
let status = await request(app).get('/status').expect(200);
|
|
18
|
+
expect(status.body.pluginConnected).toBe(false);
|
|
19
|
+
expect(status.body.mcpServerActive).toBe(false);
|
|
20
|
+
// 2. Plugin connects
|
|
21
|
+
await request(app).post('/ready').expect(200);
|
|
22
|
+
status = await request(app).get('/status').expect(200);
|
|
23
|
+
expect(status.body.pluginConnected).toBe(true);
|
|
24
|
+
expect(status.body.mcpServerActive).toBe(false);
|
|
25
|
+
// 3. Plugin polls - should show MCP not connected
|
|
26
|
+
let pollResponse = await request(app).get('/poll').expect(503);
|
|
27
|
+
expect(pollResponse.body).toMatchObject({
|
|
28
|
+
error: 'MCP server not connected',
|
|
29
|
+
pluginConnected: true,
|
|
30
|
+
mcpConnected: false
|
|
31
|
+
});
|
|
32
|
+
// 4. MCP server activates
|
|
33
|
+
app.setMCPServerActive(true);
|
|
34
|
+
status = await request(app).get('/status').expect(200);
|
|
35
|
+
expect(status.body.pluginConnected).toBe(true);
|
|
36
|
+
expect(status.body.mcpServerActive).toBe(true);
|
|
37
|
+
// 5. Plugin polls - should show both connected
|
|
38
|
+
pollResponse = await request(app).get('/poll').expect(200);
|
|
39
|
+
expect(pollResponse.body).toMatchObject({
|
|
40
|
+
request: null,
|
|
41
|
+
mcpConnected: true,
|
|
42
|
+
pluginConnected: true
|
|
43
|
+
});
|
|
44
|
+
// 6. Plugin disconnects
|
|
45
|
+
await request(app).post('/disconnect').expect(200);
|
|
46
|
+
status = await request(app).get('/status').expect(200);
|
|
47
|
+
expect(status.body.pluginConnected).toBe(false);
|
|
48
|
+
expect(status.body.mcpServerActive).toBe(true); // MCP still active
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('Request/Response Flow', () => {
|
|
52
|
+
test('should handle complete request/response cycle', async () => {
|
|
53
|
+
// Setup: Connect everything
|
|
54
|
+
await request(app).post('/ready').expect(200);
|
|
55
|
+
app.setMCPServerActive(true);
|
|
56
|
+
// 1. MCP sends a request through bridge
|
|
57
|
+
const mcpRequestPromise = bridge.sendRequest('/api/test-endpoint', {
|
|
58
|
+
testData: 'hello',
|
|
59
|
+
value: 123
|
|
60
|
+
});
|
|
61
|
+
// 2. Plugin polls and gets the request
|
|
62
|
+
const pollResponse = await request(app).get('/poll').expect(200);
|
|
63
|
+
expect(pollResponse.body.request).toMatchObject({
|
|
64
|
+
endpoint: '/api/test-endpoint',
|
|
65
|
+
data: {
|
|
66
|
+
testData: 'hello',
|
|
67
|
+
value: 123
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
const requestId = pollResponse.body.requestId;
|
|
71
|
+
// 3. Plugin processes and sends response
|
|
72
|
+
await request(app)
|
|
73
|
+
.post('/response')
|
|
74
|
+
.send({
|
|
75
|
+
requestId: requestId,
|
|
76
|
+
response: {
|
|
77
|
+
success: true,
|
|
78
|
+
result: 'processed',
|
|
79
|
+
echo: 'hello'
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
.expect(200);
|
|
83
|
+
// 4. MCP receives the response
|
|
84
|
+
const mcpResponse = await mcpRequestPromise;
|
|
85
|
+
expect(mcpResponse).toEqual({
|
|
86
|
+
success: true,
|
|
87
|
+
result: 'processed',
|
|
88
|
+
echo: 'hello'
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
test('should handle error responses', async () => {
|
|
92
|
+
// Setup
|
|
93
|
+
await request(app).post('/ready').expect(200);
|
|
94
|
+
app.setMCPServerActive(true);
|
|
95
|
+
// Send request
|
|
96
|
+
const mcpRequestPromise = bridge.sendRequest('/api/failing-endpoint', {});
|
|
97
|
+
// Poll for request
|
|
98
|
+
const pollResponse = await request(app).get('/poll').expect(200);
|
|
99
|
+
const requestId = pollResponse.body.requestId;
|
|
100
|
+
// Send error response
|
|
101
|
+
await request(app)
|
|
102
|
+
.post('/response')
|
|
103
|
+
.send({
|
|
104
|
+
requestId: requestId,
|
|
105
|
+
error: 'Operation failed: Invalid input'
|
|
106
|
+
})
|
|
107
|
+
.expect(200);
|
|
108
|
+
// Should reject with the error
|
|
109
|
+
await expect(mcpRequestPromise).rejects.toEqual('Operation failed: Invalid input');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('Disconnect Recovery', () => {
|
|
113
|
+
test('should handle disconnect and reconnect gracefully', async () => {
|
|
114
|
+
// Initial connection
|
|
115
|
+
await request(app).post('/ready').expect(200);
|
|
116
|
+
app.setMCPServerActive(true);
|
|
117
|
+
// Create some pending requests
|
|
118
|
+
const request1 = bridge.sendRequest('/api/test1', {});
|
|
119
|
+
const request2 = bridge.sendRequest('/api/test2', {});
|
|
120
|
+
// Verify requests are pending
|
|
121
|
+
let poll = await request(app).get('/poll').expect(200);
|
|
122
|
+
expect(poll.body.request).toBeTruthy();
|
|
123
|
+
// Disconnect
|
|
124
|
+
await request(app).post('/disconnect').expect(200);
|
|
125
|
+
// Requests should be rejected
|
|
126
|
+
await expect(request1).rejects.toThrow('Connection closed');
|
|
127
|
+
await expect(request2).rejects.toThrow('Connection closed');
|
|
128
|
+
// Reconnect
|
|
129
|
+
await request(app).post('/ready').expect(200);
|
|
130
|
+
// Should be able to handle new requests
|
|
131
|
+
const newRequestPromise = bridge.sendRequest('/api/test3', {});
|
|
132
|
+
poll = await request(app).get('/poll').expect(200);
|
|
133
|
+
expect(poll.body.request?.endpoint).toBe('/api/test3');
|
|
134
|
+
// Complete the new request
|
|
135
|
+
await request(app)
|
|
136
|
+
.post('/response')
|
|
137
|
+
.send({
|
|
138
|
+
requestId: poll.body.requestId,
|
|
139
|
+
response: { success: true }
|
|
140
|
+
})
|
|
141
|
+
.expect(200);
|
|
142
|
+
const result = await newRequestPromise;
|
|
143
|
+
expect(result).toEqual({ success: true });
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe('Connection State Display', () => {
|
|
147
|
+
test('should show correct pending states during connection', async () => {
|
|
148
|
+
// Initially disconnected: "HTTP: X MCP: X"
|
|
149
|
+
let health = await request(app).get('/health').expect(200);
|
|
150
|
+
expect(health.body.pluginConnected).toBe(false);
|
|
151
|
+
expect(health.body.mcpServerActive).toBe(false);
|
|
152
|
+
// Plugin starts polling: "HTTP: ... MCP: ..."
|
|
153
|
+
await request(app).get('/poll').expect(503);
|
|
154
|
+
health = await request(app).get('/health').expect(200);
|
|
155
|
+
expect(health.body.pluginConnected).toBe(true);
|
|
156
|
+
expect(health.body.mcpServerActive).toBe(false);
|
|
157
|
+
// MCP connects: "HTTP: OK MCP: OK"
|
|
158
|
+
app.setMCPServerActive(true);
|
|
159
|
+
const poll = await request(app).get('/poll').expect(200);
|
|
160
|
+
expect(poll.body.mcpConnected).toBe(true);
|
|
161
|
+
expect(poll.body.pluginConnected).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
describe('Timeout Handling', () => {
|
|
165
|
+
test('should handle request timeouts', async () => {
|
|
166
|
+
jest.useFakeTimers();
|
|
167
|
+
// Setup
|
|
168
|
+
await request(app).post('/ready').expect(200);
|
|
169
|
+
app.setMCPServerActive(true);
|
|
170
|
+
// Send request but don't respond
|
|
171
|
+
const timeoutPromise = bridge.sendRequest('/api/slow-endpoint', {});
|
|
172
|
+
// Plugin polls for it
|
|
173
|
+
await request(app).get('/poll').expect(200);
|
|
174
|
+
// Fast forward time past timeout
|
|
175
|
+
jest.advanceTimersByTime(31000);
|
|
176
|
+
// Request should timeout
|
|
177
|
+
await expect(timeoutPromise).rejects.toThrow('Request timeout');
|
|
178
|
+
jest.useRealTimers();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,GAAsB,CAAC;IAC3B,IAAI,MAAqB,CAAC;IAC1B,IAAI,KAAwB,CAAC;IAE7B,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAC7B,KAAK,GAAG,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACtC,GAAG,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC7D,uCAAuC;YACvC,IAAI,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEhD,qBAAqB;YACrB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAE9C,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEhD,kDAAkD;YAClD,IAAI,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC;gBACtC,KAAK,EAAE,0BAA0B;gBACjC,eAAe,EAAE,IAAI;gBACrB,YAAY,EAAE,KAAK;aACpB,CAAC,CAAC;YAEH,0BAA0B;YAC1B,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAE7B,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE/C,+CAA+C;YAC/C,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3D,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC;gBACtC,OAAO,EAAE,IAAI;gBACb,YAAY,EAAE,IAAI;gBAClB,eAAe,EAAE,IAAI;aACtB,CAAC,CAAC;YAEH,wBAAwB;YACxB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEnD,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB;QACrE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC/D,4BAA4B;YAC5B,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9C,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAE7B,wCAAwC;YACxC,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC,oBAAoB,EAAE;gBACjE,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,GAAG;aACX,CAAC,CAAC;YAEH,uCAAuC;YACvC,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;gBAC9C,QAAQ,EAAE,oBAAoB;gBAC9B,IAAI,EAAE;oBACJ,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,GAAG;iBACX;aACF,CAAC,CAAC;YACH,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;YAE9C,yCAAyC;YACzC,MAAM,OAAO,CAAC,GAAG,CAAC;iBACf,IAAI,CAAC,WAAW,CAAC;iBACjB,IAAI,CAAC;gBACJ,SAAS,EAAE,SAAS;gBACpB,QAAQ,EAAE;oBACR,OAAO,EAAE,IAAI;oBACb,MAAM,EAAE,WAAW;oBACnB,IAAI,EAAE,OAAO;iBACd;aACF,CAAC;iBACD,MAAM,CAAC,GAAG,CAAC,CAAC;YAEf,+BAA+B;YAC/B,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC;gBAC1B,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,WAAW;gBACnB,IAAI,EAAE,OAAO;aACd,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC/C,QAAQ;YACR,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9C,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAE7B,eAAe;YACf,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;YAE1E,mBAAmB;YACnB,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;YAE9C,sBAAsB;YACtB,MAAM,OAAO,CAAC,GAAG,CAAC;iBACf,IAAI,CAAC,WAAW,CAAC;iBACjB,IAAI,CAAC;gBACJ,SAAS,EAAE,SAAS;gBACpB,KAAK,EAAE,iCAAiC;aACzC,CAAC;iBACD,MAAM,CAAC,GAAG,CAAC,CAAC;YAEf,+BAA+B;YAC/B,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,IAAI,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACnE,qBAAqB;YACrB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9C,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAE7B,+BAA+B;YAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YACtD,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YAEtD,8BAA8B;YAC9B,IAAI,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;YAEvC,aAAa;YACb,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEnD,8BAA8B;YAC9B,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;YAC5D,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;YAE5D,YAAY;YACZ,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAE9C,wCAAwC;YACxC,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YAE/D,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAEvD,2BAA2B;YAC3B,MAAM,OAAO,CAAC,GAAG,CAAC;iBACf,IAAI,CAAC,WAAW,CAAC;iBACjB,IAAI,CAAC;gBACJ,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS;gBAC9B,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;aAC5B,CAAC;iBACD,MAAM,CAAC,GAAG,CAAC,CAAC;YAEf,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,IAAI,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;YACtE,4CAA4C;YAC5C,IAAI,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEhD,+CAA+C;YAC/C,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAE5C,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEhD,oCAAoC;YACpC,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAE7B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,IAAI,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAChD,IAAI,CAAC,aAAa,EAAE,CAAC;YAErB,QAAQ;YACR,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9C,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAE7B,iCAAiC;YACjC,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;YAEpE,sBAAsB;YACtB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAE5C,iCAAiC;YACjC,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAEhC,yBAAyB;YACzB,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;YAEhE,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smoke.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/smoke.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { BridgeService } from '../bridge-service.js';
|
|
2
|
+
import { createHttpServer } from '../http-server.js';
|
|
3
|
+
import { RobloxStudioTools } from '../tools/index.js';
|
|
4
|
+
import request from 'supertest';
|
|
5
|
+
describe('Smoke Tests - Connection Fixes', () => {
|
|
6
|
+
test('BridgeService should be instantiable', () => {
|
|
7
|
+
const bridge = new BridgeService();
|
|
8
|
+
expect(bridge).toBeDefined();
|
|
9
|
+
expect(bridge.getPendingRequest()).toBeNull();
|
|
10
|
+
});
|
|
11
|
+
test('HTTP server should start and respond to health check', async () => {
|
|
12
|
+
const bridge = new BridgeService();
|
|
13
|
+
const tools = new RobloxStudioTools(bridge);
|
|
14
|
+
const app = createHttpServer(tools, bridge);
|
|
15
|
+
const response = await request(app)
|
|
16
|
+
.get('/health')
|
|
17
|
+
.expect(200);
|
|
18
|
+
expect(response.body.status).toBe('ok');
|
|
19
|
+
expect(response.body.service).toBe('robloxstudio-mcp');
|
|
20
|
+
});
|
|
21
|
+
test('clearAllPendingRequests should clear all requests', async () => {
|
|
22
|
+
const bridge = new BridgeService();
|
|
23
|
+
// Don't wait for these promises - they'll be rejected
|
|
24
|
+
const promise1 = bridge.sendRequest('/test1', {});
|
|
25
|
+
const promise2 = bridge.sendRequest('/test2', {});
|
|
26
|
+
// Should have pending requests
|
|
27
|
+
expect(bridge.getPendingRequest()).toBeTruthy();
|
|
28
|
+
// Clear all requests
|
|
29
|
+
bridge.clearAllPendingRequests();
|
|
30
|
+
// Should have no pending requests
|
|
31
|
+
expect(bridge.getPendingRequest()).toBeNull();
|
|
32
|
+
// Promises should reject
|
|
33
|
+
await expect(promise1).rejects.toThrow('Connection closed');
|
|
34
|
+
await expect(promise2).rejects.toThrow('Connection closed');
|
|
35
|
+
});
|
|
36
|
+
test('Disconnect endpoint should clear pending requests', async () => {
|
|
37
|
+
const bridge = new BridgeService();
|
|
38
|
+
const tools = new RobloxStudioTools(bridge);
|
|
39
|
+
const app = createHttpServer(tools, bridge);
|
|
40
|
+
// Add a pending request (don't await it)
|
|
41
|
+
const pendingPromise = bridge.sendRequest('/test', { data: 'test' });
|
|
42
|
+
// Disconnect should clear it
|
|
43
|
+
await request(app)
|
|
44
|
+
.post('/disconnect')
|
|
45
|
+
.expect(200);
|
|
46
|
+
// Request should be rejected
|
|
47
|
+
await expect(pendingPromise).rejects.toThrow('Connection closed');
|
|
48
|
+
});
|
|
49
|
+
test('Connection states should update correctly', async () => {
|
|
50
|
+
const bridge = new BridgeService();
|
|
51
|
+
const tools = new RobloxStudioTools(bridge);
|
|
52
|
+
const app = createHttpServer(tools, bridge);
|
|
53
|
+
// Initially not connected
|
|
54
|
+
expect(app.isPluginConnected()).toBe(false);
|
|
55
|
+
// After ready
|
|
56
|
+
await request(app).post('/ready').expect(200);
|
|
57
|
+
expect(app.isPluginConnected()).toBe(true);
|
|
58
|
+
// After disconnect
|
|
59
|
+
await request(app).post('/disconnect').expect(200);
|
|
60
|
+
expect(app.isPluginConnected()).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=smoke.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smoke.test.js","sourceRoot":"","sources":["../../src/__tests__/smoke.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class BridgeService {
|
|
2
|
+
private pendingRequests;
|
|
3
|
+
private requestTimeout;
|
|
4
|
+
sendRequest(endpoint: string, data: any): Promise<any>;
|
|
5
|
+
getPendingRequest(): {
|
|
6
|
+
requestId: string;
|
|
7
|
+
request: {
|
|
8
|
+
endpoint: string;
|
|
9
|
+
data: any;
|
|
10
|
+
};
|
|
11
|
+
} | null;
|
|
12
|
+
resolveRequest(requestId: string, response: any): void;
|
|
13
|
+
rejectRequest(requestId: string, error: any): void;
|
|
14
|
+
cleanupOldRequests(): void;
|
|
15
|
+
clearAllPendingRequests(): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=bridge-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-service.d.ts","sourceRoot":"","sources":["../src/bridge-service.ts"],"names":[],"mappings":"AAWA,qBAAa,aAAa;IACxB,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,cAAc,CAAS;IAEzB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAyB5D,iBAAiB,IAAI;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,GAAG,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI;IAuB3F,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG;IAQ/C,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG;IAS3C,kBAAkB;IAWlB,uBAAuB;CAMxB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
export class BridgeService {
|
|
3
|
+
pendingRequests = new Map();
|
|
4
|
+
requestTimeout = 30000; // 30 seconds timeout
|
|
5
|
+
async sendRequest(endpoint, data) {
|
|
6
|
+
const requestId = uuidv4();
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const request = {
|
|
9
|
+
id: requestId,
|
|
10
|
+
endpoint,
|
|
11
|
+
data,
|
|
12
|
+
timestamp: Date.now(),
|
|
13
|
+
resolve,
|
|
14
|
+
reject
|
|
15
|
+
};
|
|
16
|
+
this.pendingRequests.set(requestId, request);
|
|
17
|
+
// Set timeout
|
|
18
|
+
setTimeout(() => {
|
|
19
|
+
if (this.pendingRequests.has(requestId)) {
|
|
20
|
+
this.pendingRequests.delete(requestId);
|
|
21
|
+
reject(new Error('Request timeout'));
|
|
22
|
+
}
|
|
23
|
+
}, this.requestTimeout);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
getPendingRequest() {
|
|
27
|
+
// Get oldest pending request
|
|
28
|
+
let oldestRequest = null;
|
|
29
|
+
for (const request of this.pendingRequests.values()) {
|
|
30
|
+
if (!oldestRequest || request.timestamp < oldestRequest.timestamp) {
|
|
31
|
+
oldestRequest = request;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (oldestRequest) {
|
|
35
|
+
return {
|
|
36
|
+
requestId: oldestRequest.id,
|
|
37
|
+
request: {
|
|
38
|
+
endpoint: oldestRequest.endpoint,
|
|
39
|
+
data: oldestRequest.data
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
resolveRequest(requestId, response) {
|
|
46
|
+
const request = this.pendingRequests.get(requestId);
|
|
47
|
+
if (request) {
|
|
48
|
+
this.pendingRequests.delete(requestId);
|
|
49
|
+
request.resolve(response);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
rejectRequest(requestId, error) {
|
|
53
|
+
const request = this.pendingRequests.get(requestId);
|
|
54
|
+
if (request) {
|
|
55
|
+
this.pendingRequests.delete(requestId);
|
|
56
|
+
request.reject(error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Clean up old requests
|
|
60
|
+
cleanupOldRequests() {
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
for (const [id, request] of this.pendingRequests.entries()) {
|
|
63
|
+
if (now - request.timestamp > this.requestTimeout) {
|
|
64
|
+
this.pendingRequests.delete(id);
|
|
65
|
+
request.reject(new Error('Request timeout'));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Force cleanup all pending requests (used on disconnect)
|
|
70
|
+
clearAllPendingRequests() {
|
|
71
|
+
for (const [id, request] of this.pendingRequests.entries()) {
|
|
72
|
+
request.reject(new Error('Connection closed'));
|
|
73
|
+
}
|
|
74
|
+
this.pendingRequests.clear();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=bridge-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-service.js","sourceRoot":"","sources":["../src/bridge-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { RobloxStudioTools } from './tools/index.js';
|
|
2
|
+
import { BridgeService } from './bridge-service.js';
|
|
3
|
+
export declare function createHttpServer(tools: RobloxStudioTools, bridge: BridgeService): import("express-serve-static-core").Express;
|
|
4
|
+
//# sourceMappingURL=http-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,aAAa,+CAkT/E"}
|