@framers/agentos-ext-cloud-railway 0.1.0 → 0.1.2
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/manifest.json +4 -4
- package/package.json +15 -7
- package/src/RailwayService.ts +0 -415
- package/src/index.ts +0 -109
- package/src/tools/addDatabase.ts +0 -45
- package/src/tools/deployService.ts +0 -89
- package/src/tools/getLogs.ts +0 -50
- package/src/tools/listServices.ts +0 -44
- package/test/RailwayService.test.ts +0 -439
- package/test/index.test.ts +0 -49
- package/test/tools.test.ts +0 -310
- package/tsconfig.json +0 -22
package/test/tools.test.ts
DELETED
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
3
|
-
import { RailwayAddDatabaseTool } from '../src/tools/addDatabase';
|
|
4
|
-
import { RailwayDeployServiceTool } from '../src/tools/deployService';
|
|
5
|
-
import { RailwayGetLogsTool } from '../src/tools/getLogs';
|
|
6
|
-
import { RailwayListServicesTool } from '../src/tools/listServices';
|
|
7
|
-
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
// RailwayAddDatabaseTool
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
describe('RailwayAddDatabaseTool', () => {
|
|
13
|
-
let service: any;
|
|
14
|
-
let tool: RailwayAddDatabaseTool;
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
service = {
|
|
18
|
-
createPlugin: vi.fn(),
|
|
19
|
-
};
|
|
20
|
-
tool = new RailwayAddDatabaseTool(service);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should have correct metadata', () => {
|
|
24
|
-
expect(tool.id).toBe('railwayAddDatabase');
|
|
25
|
-
expect(tool.name).toBe('railwayAddDatabase');
|
|
26
|
-
expect(tool.displayName).toBe('Add Railway Database');
|
|
27
|
-
expect(tool.inputSchema.type).toBe('object');
|
|
28
|
-
expect(tool.inputSchema.required).toContain('projectId');
|
|
29
|
-
expect(tool.inputSchema.required).toContain('plugin');
|
|
30
|
-
expect(tool.category).toBe('cloud');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should provision a PostgreSQL database', async () => {
|
|
34
|
-
service.createPlugin.mockResolvedValue({
|
|
35
|
-
id: 'plugin-1',
|
|
36
|
-
name: 'PostgreSQL',
|
|
37
|
-
status: 'running',
|
|
38
|
-
connectionUrl: 'postgres://user:pass@host:5432/db',
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const result = await tool.execute({
|
|
42
|
-
projectId: 'proj-abc',
|
|
43
|
-
plugin: 'postgresql',
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
expect(result.success).toBe(true);
|
|
47
|
-
expect(result.data).toHaveProperty('id', 'plugin-1');
|
|
48
|
-
expect(service.createPlugin).toHaveBeenCalledWith('proj-abc', 'postgresql');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should provision a Redis database', async () => {
|
|
52
|
-
service.createPlugin.mockResolvedValue({
|
|
53
|
-
id: 'plugin-2',
|
|
54
|
-
name: 'Redis',
|
|
55
|
-
status: 'running',
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const result = await tool.execute({
|
|
59
|
-
projectId: 'proj-abc',
|
|
60
|
-
plugin: 'redis',
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
expect(result.success).toBe(true);
|
|
64
|
-
expect(service.createPlugin).toHaveBeenCalledWith('proj-abc', 'redis');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should handle errors gracefully', async () => {
|
|
68
|
-
service.createPlugin.mockRejectedValue(new Error('Project not found'));
|
|
69
|
-
|
|
70
|
-
const result = await tool.execute({
|
|
71
|
-
projectId: 'nonexistent',
|
|
72
|
-
plugin: 'postgresql',
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
expect(result.success).toBe(false);
|
|
76
|
-
expect(result.error).toContain('Project not found');
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
// RailwayDeployServiceTool
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
|
|
84
|
-
describe('RailwayDeployServiceTool', () => {
|
|
85
|
-
let service: any;
|
|
86
|
-
let tool: RailwayDeployServiceTool;
|
|
87
|
-
|
|
88
|
-
beforeEach(() => {
|
|
89
|
-
service = {
|
|
90
|
-
createProject: vi.fn(),
|
|
91
|
-
createService: vi.fn(),
|
|
92
|
-
redeployService: vi.fn(),
|
|
93
|
-
upsertVariables: vi.fn(),
|
|
94
|
-
};
|
|
95
|
-
tool = new RailwayDeployServiceTool(service);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('should have correct metadata', () => {
|
|
99
|
-
expect(tool.id).toBe('railwayDeployService');
|
|
100
|
-
expect(tool.name).toBe('railwayDeployService');
|
|
101
|
-
expect(tool.inputSchema.type).toBe('object');
|
|
102
|
-
expect(tool.inputSchema.required).toEqual([]);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('should create a new service in an existing project', async () => {
|
|
106
|
-
service.createService.mockResolvedValue({
|
|
107
|
-
id: 'svc-1',
|
|
108
|
-
name: 'api',
|
|
109
|
-
projectId: 'proj-123',
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const result = await tool.execute({
|
|
113
|
-
projectId: 'proj-123',
|
|
114
|
-
repo: 'user/repo',
|
|
115
|
-
serviceName: 'api',
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
expect(result.success).toBe(true);
|
|
119
|
-
expect(result.data?.service).toHaveProperty('id', 'svc-1');
|
|
120
|
-
expect(result.data?.projectId).toBe('proj-123');
|
|
121
|
-
expect(service.createService).toHaveBeenCalledWith('proj-123', {
|
|
122
|
-
name: 'api',
|
|
123
|
-
source: { repo: 'user/repo' },
|
|
124
|
-
variables: undefined,
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('should create a new project when projectId is omitted', async () => {
|
|
129
|
-
service.createProject.mockResolvedValue({ id: 'proj-new' });
|
|
130
|
-
service.createService.mockResolvedValue({ id: 'svc-2', name: 'app' });
|
|
131
|
-
|
|
132
|
-
const result = await tool.execute({
|
|
133
|
-
projectName: 'my-project',
|
|
134
|
-
repo: 'user/repo',
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
expect(result.success).toBe(true);
|
|
138
|
-
expect(result.data?.projectId).toBe('proj-new');
|
|
139
|
-
expect(service.createProject).toHaveBeenCalledWith('my-project');
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should redeploy an existing service', async () => {
|
|
143
|
-
service.redeployService.mockResolvedValue({
|
|
144
|
-
id: 'deploy-1',
|
|
145
|
-
status: 'BUILDING',
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
const result = await tool.execute({
|
|
149
|
-
serviceId: 'svc-1',
|
|
150
|
-
environmentId: 'env-prod',
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
expect(result.success).toBe(true);
|
|
154
|
-
expect(result.data?.deployment).toHaveProperty('id', 'deploy-1');
|
|
155
|
-
expect(service.redeployService).toHaveBeenCalledWith('svc-1', 'env-prod');
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should set variables before redeploying', async () => {
|
|
159
|
-
service.upsertVariables.mockResolvedValue({});
|
|
160
|
-
service.redeployService.mockResolvedValue({ id: 'deploy-2' });
|
|
161
|
-
|
|
162
|
-
await tool.execute({
|
|
163
|
-
serviceId: 'svc-1',
|
|
164
|
-
environmentId: 'env-prod',
|
|
165
|
-
variables: { DATABASE_URL: 'postgres://localhost/db' },
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
expect(service.upsertVariables).toHaveBeenCalledWith('svc-1', 'env-prod', {
|
|
169
|
-
DATABASE_URL: 'postgres://localhost/db',
|
|
170
|
-
});
|
|
171
|
-
expect(service.redeployService).toHaveBeenCalled();
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('should handle errors gracefully', async () => {
|
|
175
|
-
service.createService.mockRejectedValue(new Error('Rate limit exceeded'));
|
|
176
|
-
|
|
177
|
-
const result = await tool.execute({
|
|
178
|
-
projectId: 'proj-1',
|
|
179
|
-
repo: 'user/repo',
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
expect(result.success).toBe(false);
|
|
183
|
-
expect(result.error).toContain('Rate limit exceeded');
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// ---------------------------------------------------------------------------
|
|
188
|
-
// RailwayGetLogsTool
|
|
189
|
-
// ---------------------------------------------------------------------------
|
|
190
|
-
|
|
191
|
-
describe('RailwayGetLogsTool', () => {
|
|
192
|
-
let service: any;
|
|
193
|
-
let tool: RailwayGetLogsTool;
|
|
194
|
-
|
|
195
|
-
beforeEach(() => {
|
|
196
|
-
service = {
|
|
197
|
-
getDeploymentLogs: vi.fn(),
|
|
198
|
-
getBuildLogs: vi.fn(),
|
|
199
|
-
};
|
|
200
|
-
tool = new RailwayGetLogsTool(service);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('should have correct metadata', () => {
|
|
204
|
-
expect(tool.id).toBe('railwayGetLogs');
|
|
205
|
-
expect(tool.name).toBe('railwayGetLogs');
|
|
206
|
-
expect(tool.inputSchema.type).toBe('object');
|
|
207
|
-
expect(tool.inputSchema.required).toContain('deploymentId');
|
|
208
|
-
expect(tool.hasSideEffects).toBe(false);
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
it('should retrieve deployment logs by default', async () => {
|
|
212
|
-
service.getDeploymentLogs.mockResolvedValue([
|
|
213
|
-
{ timestamp: '2024-01-01T00:00:00Z', message: 'Listening on port 3000', severity: 'INFO' },
|
|
214
|
-
]);
|
|
215
|
-
|
|
216
|
-
const result = await tool.execute({ deploymentId: 'deploy-1' });
|
|
217
|
-
|
|
218
|
-
expect(result.success).toBe(true);
|
|
219
|
-
expect(result.data).toHaveLength(1);
|
|
220
|
-
expect(service.getDeploymentLogs).toHaveBeenCalledWith('deploy-1');
|
|
221
|
-
expect(service.getBuildLogs).not.toHaveBeenCalled();
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it('should retrieve build logs when type is build', async () => {
|
|
225
|
-
service.getBuildLogs.mockResolvedValue([
|
|
226
|
-
{ timestamp: '2024-01-01T00:00:00Z', message: 'Installing dependencies...', severity: 'INFO' },
|
|
227
|
-
]);
|
|
228
|
-
|
|
229
|
-
const result = await tool.execute({
|
|
230
|
-
deploymentId: 'deploy-1',
|
|
231
|
-
type: 'build',
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
expect(result.success).toBe(true);
|
|
235
|
-
expect(service.getBuildLogs).toHaveBeenCalledWith('deploy-1');
|
|
236
|
-
expect(service.getDeploymentLogs).not.toHaveBeenCalled();
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('should handle errors gracefully', async () => {
|
|
240
|
-
service.getDeploymentLogs.mockRejectedValue(new Error('Deployment not found'));
|
|
241
|
-
|
|
242
|
-
const result = await tool.execute({ deploymentId: 'nonexistent' });
|
|
243
|
-
|
|
244
|
-
expect(result.success).toBe(false);
|
|
245
|
-
expect(result.error).toContain('Deployment not found');
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// ---------------------------------------------------------------------------
|
|
250
|
-
// RailwayListServicesTool
|
|
251
|
-
// ---------------------------------------------------------------------------
|
|
252
|
-
|
|
253
|
-
describe('RailwayListServicesTool', () => {
|
|
254
|
-
let service: any;
|
|
255
|
-
let tool: RailwayListServicesTool;
|
|
256
|
-
|
|
257
|
-
beforeEach(() => {
|
|
258
|
-
service = {
|
|
259
|
-
listProjects: vi.fn(),
|
|
260
|
-
getProject: vi.fn(),
|
|
261
|
-
};
|
|
262
|
-
tool = new RailwayListServicesTool(service);
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should have correct metadata', () => {
|
|
266
|
-
expect(tool.id).toBe('railwayListServices');
|
|
267
|
-
expect(tool.name).toBe('railwayListServices');
|
|
268
|
-
expect(tool.inputSchema.type).toBe('object');
|
|
269
|
-
expect(tool.inputSchema.required).toEqual([]);
|
|
270
|
-
expect(tool.hasSideEffects).toBe(false);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it('should list all projects when no projectId is provided', async () => {
|
|
274
|
-
service.listProjects.mockResolvedValue([
|
|
275
|
-
{ id: 'proj-1', name: 'Project 1', services: [] },
|
|
276
|
-
{ id: 'proj-2', name: 'Project 2', services: [] },
|
|
277
|
-
]);
|
|
278
|
-
|
|
279
|
-
const result = await tool.execute({});
|
|
280
|
-
|
|
281
|
-
expect(result.success).toBe(true);
|
|
282
|
-
expect(result.data).toHaveLength(2);
|
|
283
|
-
expect(service.listProjects).toHaveBeenCalled();
|
|
284
|
-
expect(service.getProject).not.toHaveBeenCalled();
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it('should fetch a single project by ID', async () => {
|
|
288
|
-
service.getProject.mockResolvedValue({
|
|
289
|
-
id: 'proj-1',
|
|
290
|
-
name: 'Project 1',
|
|
291
|
-
services: [{ id: 'svc-1', name: 'api' }],
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
const result = await tool.execute({ projectId: 'proj-1' });
|
|
295
|
-
|
|
296
|
-
expect(result.success).toBe(true);
|
|
297
|
-
expect(result.data).toHaveLength(1);
|
|
298
|
-
expect(result.data![0].id).toBe('proj-1');
|
|
299
|
-
expect(service.getProject).toHaveBeenCalledWith('proj-1');
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it('should handle errors gracefully', async () => {
|
|
303
|
-
service.listProjects.mockRejectedValue(new Error('Unauthorized'));
|
|
304
|
-
|
|
305
|
-
const result = await tool.execute({});
|
|
306
|
-
|
|
307
|
-
expect(result.success).toBe(false);
|
|
308
|
-
expect(result.error).toContain('Unauthorized');
|
|
309
|
-
});
|
|
310
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ES2022"],
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"noEmitOnError": false,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"declaration": true,
|
|
14
|
-
"declarationMap": true,
|
|
15
|
-
"sourceMap": true,
|
|
16
|
-
"resolveJsonModule": true,
|
|
17
|
-
"moduleResolution": "Bundler",
|
|
18
|
-
"types": ["node"]
|
|
19
|
-
},
|
|
20
|
-
"include": ["src/**/*"],
|
|
21
|
-
"exclude": ["node_modules", "dist", "test"]
|
|
22
|
-
}
|