@synth-deploy/server 1.0.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/envoy-client.d.ts +65 -15
- package/dist/agent/envoy-client.d.ts.map +1 -1
- package/dist/agent/envoy-client.js +58 -8
- package/dist/agent/envoy-client.js.map +1 -1
- package/dist/agent/stale-deployment-detector.js +1 -1
- package/dist/agent/stale-deployment-detector.js.map +1 -1
- package/dist/agent/synth-agent.d.ts +7 -5
- package/dist/agent/synth-agent.d.ts.map +1 -1
- package/dist/agent/synth-agent.js +59 -50
- package/dist/agent/synth-agent.js.map +1 -1
- package/dist/alert-webhooks/alert-parsers.d.ts +21 -0
- package/dist/alert-webhooks/alert-parsers.d.ts.map +1 -0
- package/dist/alert-webhooks/alert-parsers.js +184 -0
- package/dist/alert-webhooks/alert-parsers.js.map +1 -0
- package/dist/api/agent.d.ts +0 -6
- package/dist/api/agent.d.ts.map +1 -1
- package/dist/api/agent.js +6 -459
- package/dist/api/agent.js.map +1 -1
- package/dist/api/alert-webhooks.d.ts +13 -0
- package/dist/api/alert-webhooks.d.ts.map +1 -0
- package/dist/api/alert-webhooks.js +279 -0
- package/dist/api/alert-webhooks.js.map +1 -0
- package/dist/api/envoy-reports.js +2 -2
- package/dist/api/envoy-reports.js.map +1 -1
- package/dist/api/envoys.js +1 -1
- package/dist/api/envoys.js.map +1 -1
- package/dist/api/fleet.d.ts.map +1 -1
- package/dist/api/fleet.js +14 -15
- package/dist/api/fleet.js.map +1 -1
- package/dist/api/graph.js +3 -3
- package/dist/api/graph.js.map +1 -1
- package/dist/api/operations.d.ts +7 -0
- package/dist/api/operations.d.ts.map +1 -0
- package/dist/api/operations.js +1900 -0
- package/dist/api/operations.js.map +1 -0
- package/dist/api/partitions.js +1 -1
- package/dist/api/partitions.js.map +1 -1
- package/dist/api/schemas.d.ts +434 -133
- package/dist/api/schemas.d.ts.map +1 -1
- package/dist/api/schemas.js +53 -25
- package/dist/api/schemas.js.map +1 -1
- package/dist/api/system.d.ts.map +1 -1
- package/dist/api/system.js +22 -21
- package/dist/api/system.js.map +1 -1
- package/dist/artifact-analyzer.js +2 -2
- package/dist/artifact-analyzer.js.map +1 -1
- package/dist/fleet/fleet-executor.js +3 -3
- package/dist/fleet/fleet-executor.js.map +1 -1
- package/dist/graph/graph-executor.d.ts.map +1 -1
- package/dist/graph/graph-executor.js +18 -4
- package/dist/graph/graph-executor.js.map +1 -1
- package/dist/index.js +89 -61
- package/dist/index.js.map +1 -1
- package/dist/mcp/resources.js +3 -3
- package/dist/mcp/resources.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +2 -9
- package/dist/mcp/tools.js.map +1 -1
- package/dist/middleware/auth.js +1 -1
- package/dist/middleware/auth.js.map +1 -1
- package/package.json +1 -1
- package/src/agent/envoy-client.ts +111 -19
- package/src/agent/stale-deployment-detector.ts +1 -1
- package/src/agent/synth-agent.ts +76 -56
- package/src/alert-webhooks/alert-parsers.ts +291 -0
- package/src/api/agent.ts +9 -528
- package/src/api/alert-webhooks.ts +354 -0
- package/src/api/envoy-reports.ts +2 -2
- package/src/api/envoys.ts +1 -1
- package/src/api/fleet.ts +14 -15
- package/src/api/graph.ts +3 -3
- package/src/api/operations.ts +2260 -0
- package/src/api/partitions.ts +1 -1
- package/src/api/schemas.ts +59 -27
- package/src/api/system.ts +23 -21
- package/src/artifact-analyzer.ts +2 -2
- package/src/fleet/fleet-executor.ts +3 -3
- package/src/graph/graph-executor.ts +18 -4
- package/src/index.ts +91 -61
- package/src/mcp/resources.ts +3 -3
- package/src/mcp/tools.ts +5 -9
- package/src/middleware/auth.ts +1 -1
- package/tests/agent-mode.test.ts +5 -376
- package/tests/api-handlers.test.ts +27 -27
- package/tests/composite-operations.test.ts +557 -0
- package/tests/decision-diary.test.ts +62 -63
- package/tests/diary-reader.test.ts +14 -18
- package/tests/mcp-tools.test.ts +1 -1
- package/tests/orchestration.test.ts +34 -30
- package/tests/partition-isolation.test.ts +4 -9
- package/tests/rbac-enforcement.test.ts +8 -8
- package/tests/ui-journey.test.ts +9 -9
- package/dist/api/deployments.d.ts +0 -11
- package/dist/api/deployments.d.ts.map +0 -1
- package/dist/api/deployments.js +0 -1098
- package/dist/api/deployments.js.map +0 -1
- package/src/api/deployments.ts +0 -1347
|
@@ -115,14 +115,18 @@ function makeTrigger(opts: {
|
|
|
115
115
|
version?: string;
|
|
116
116
|
variables?: Record<string, string>;
|
|
117
117
|
}) {
|
|
118
|
-
|
|
118
|
+
const input = {
|
|
119
|
+
type: "deploy" as const,
|
|
119
120
|
artifactId: opts.artifact?.id ?? "",
|
|
120
121
|
artifactVersionId: opts.version ?? "2.0.0",
|
|
122
|
+
};
|
|
123
|
+
const trigger = {
|
|
121
124
|
partitionId: opts.partition?.id,
|
|
122
125
|
environmentId: opts.environment?.id ?? "",
|
|
123
126
|
triggeredBy: "user" as const,
|
|
124
127
|
...(opts.variables ? { variables: opts.variables } : {}),
|
|
125
128
|
};
|
|
129
|
+
return { input, trigger };
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
// ---------------------------------------------------------------------------
|
|
@@ -159,7 +163,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
159
163
|
artifact, partition, environment: env,
|
|
160
164
|
variables: { LOG_LEVEL: "error" },
|
|
161
165
|
});
|
|
162
|
-
const result = await agent.
|
|
166
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
163
167
|
|
|
164
168
|
expect(result.status).toBe("succeeded");
|
|
165
169
|
expect(result.completedAt).not.toBeUndefined();
|
|
@@ -172,7 +176,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
172
176
|
});
|
|
173
177
|
|
|
174
178
|
// Diary records every pipeline step
|
|
175
|
-
const entries = diary.
|
|
179
|
+
const entries = diary.getByOperation(result.id);
|
|
176
180
|
expect(entries.length).toBeGreaterThanOrEqual(5);
|
|
177
181
|
|
|
178
182
|
// Each entry has a real decision and reasoning
|
|
@@ -195,7 +199,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
195
199
|
healthChecker.willReturn(HEALTHY);
|
|
196
200
|
|
|
197
201
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
198
|
-
const result = await agent.
|
|
202
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
199
203
|
|
|
200
204
|
expect(result.status).toBe("succeeded");
|
|
201
205
|
expect(result.variables).toEqual({
|
|
@@ -203,7 +207,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
203
207
|
PARTITION_SPECIFIC: "abc",
|
|
204
208
|
});
|
|
205
209
|
|
|
206
|
-
const entries = diary.
|
|
210
|
+
const entries = diary.getByOperation(result.id);
|
|
207
211
|
const completion = findDecisions(entries, "Marking deployment of")[0];
|
|
208
212
|
expect(completion.reasoning).toContain("No variable conflicts");
|
|
209
213
|
});
|
|
@@ -222,7 +226,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
222
226
|
const env = seedEnvironment("staging");
|
|
223
227
|
|
|
224
228
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
225
|
-
const result = await agent.
|
|
229
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
226
230
|
|
|
227
231
|
expect(result.status).toBe("failed");
|
|
228
232
|
expect(result.failureReason).toContain("unreachable");
|
|
@@ -230,7 +234,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
230
234
|
// Should have retried (initial + 1 retry = 2 calls)
|
|
231
235
|
expect(healthChecker.callCount).toBe(2);
|
|
232
236
|
|
|
233
|
-
const entries = diary.
|
|
237
|
+
const entries = diary.getByOperation(result.id);
|
|
234
238
|
const retryEntries = findDecisions(entries, "attempting retry");
|
|
235
239
|
expect(retryEntries).toHaveLength(1);
|
|
236
240
|
expect(retryEntries[0].reasoning).toContain("restarting");
|
|
@@ -250,14 +254,14 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
250
254
|
const env = seedEnvironment("staging");
|
|
251
255
|
|
|
252
256
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
253
|
-
const result = await agent.
|
|
257
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
254
258
|
|
|
255
259
|
expect(result.status).toBe("failed");
|
|
256
260
|
|
|
257
261
|
// Only called once — no retry for DNS errors
|
|
258
262
|
expect(healthChecker.callCount).toBe(1);
|
|
259
263
|
|
|
260
|
-
const entries = diary.
|
|
264
|
+
const entries = diary.getByOperation(result.id);
|
|
261
265
|
|
|
262
266
|
// Should have decided NOT to retry
|
|
263
267
|
const abortEntries = findDecisions(entries, "aborting without retry");
|
|
@@ -280,11 +284,11 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
280
284
|
const env = seedEnvironment("production");
|
|
281
285
|
|
|
282
286
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
283
|
-
const result = await agent.
|
|
287
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
284
288
|
|
|
285
289
|
expect(result.status).toBe("failed");
|
|
286
290
|
|
|
287
|
-
const entries = diary.
|
|
291
|
+
const entries = diary.getByOperation(result.id);
|
|
288
292
|
const retryEntries = findDecisions(entries, "attempting retry");
|
|
289
293
|
expect(retryEntries).toHaveLength(1);
|
|
290
294
|
|
|
@@ -305,11 +309,11 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
305
309
|
const env = seedEnvironment("staging");
|
|
306
310
|
|
|
307
311
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
308
|
-
const result = await agent.
|
|
312
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
309
313
|
|
|
310
314
|
expect(result.status).toBe("failed");
|
|
311
315
|
|
|
312
|
-
const entries = diary.
|
|
316
|
+
const entries = diary.getByOperation(result.id);
|
|
313
317
|
const retryEntries = findDecisions(entries, "attempting retry");
|
|
314
318
|
expect(retryEntries).toHaveLength(1);
|
|
315
319
|
|
|
@@ -326,11 +330,11 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
326
330
|
const env = seedEnvironment("production");
|
|
327
331
|
|
|
328
332
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
329
|
-
const result = await agent.
|
|
333
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
330
334
|
|
|
331
335
|
expect(result.status).toBe("succeeded");
|
|
332
336
|
|
|
333
|
-
const entries = diary.
|
|
337
|
+
const entries = diary.getByOperation(result.id);
|
|
334
338
|
const recoveryEntries = findDecisions(entries, "recovered on retry");
|
|
335
339
|
expect(recoveryEntries).toHaveLength(1);
|
|
336
340
|
expect(recoveryEntries[0].reasoning).toContain("transient");
|
|
@@ -345,11 +349,11 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
345
349
|
const env = seedEnvironment("production");
|
|
346
350
|
|
|
347
351
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
348
|
-
const result = await agent.
|
|
352
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
349
353
|
|
|
350
354
|
expect(result.status).toBe("succeeded");
|
|
351
355
|
|
|
352
|
-
const entries = diary.
|
|
356
|
+
const entries = diary.getByOperation(result.id);
|
|
353
357
|
const retryEntries = findDecisions(entries, "attempting retry");
|
|
354
358
|
expect(retryEntries).toHaveLength(1);
|
|
355
359
|
// Server errors get different reasoning than connection refused
|
|
@@ -371,13 +375,13 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
371
375
|
healthChecker.willReturn(HEALTHY);
|
|
372
376
|
|
|
373
377
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
374
|
-
const result = await agent.
|
|
378
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
375
379
|
|
|
376
380
|
// Single override → agent proceeds (might be intentional)
|
|
377
381
|
expect(result.status).toBe("succeeded");
|
|
378
382
|
expect(result.variables.DB_HOST).toBe("prod-db.internal");
|
|
379
383
|
|
|
380
|
-
const entries = diary.
|
|
384
|
+
const entries = diary.getByOperation(result.id);
|
|
381
385
|
const crossEnvEntries = findDecisions(entries, "Cross-environment");
|
|
382
386
|
expect(crossEnvEntries).toHaveLength(1);
|
|
383
387
|
|
|
@@ -402,14 +406,14 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
402
406
|
healthChecker.willReturn(HEALTHY);
|
|
403
407
|
|
|
404
408
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
405
|
-
const result = await agent.
|
|
409
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
406
410
|
|
|
407
411
|
// THIS IS THE KEY BEHAVIORAL DIFFERENCE:
|
|
408
412
|
// Multiple cross-env connectivity overrides → deployment blocked
|
|
409
413
|
expect(result.status).toBe("failed");
|
|
410
414
|
expect(result.failureReason).toContain("high-risk");
|
|
411
415
|
|
|
412
|
-
const entries = diary.
|
|
416
|
+
const entries = diary.getByOperation(result.id);
|
|
413
417
|
|
|
414
418
|
// Agent explains WHY it blocked
|
|
415
419
|
const blockEntries = findDecisions(entries, "Blocking deployment");
|
|
@@ -435,7 +439,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
435
439
|
healthChecker.willReturn(HEALTHY);
|
|
436
440
|
|
|
437
441
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
438
|
-
const result = await agent.
|
|
442
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
439
443
|
|
|
440
444
|
// Non-connectivity cross-env → proceeds (can't route traffic)
|
|
441
445
|
expect(result.status).toBe("succeeded");
|
|
@@ -449,12 +453,12 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
449
453
|
healthChecker.willReturn(HEALTHY);
|
|
450
454
|
|
|
451
455
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
452
|
-
const result = await agent.
|
|
456
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
453
457
|
|
|
454
458
|
expect(result.status).toBe("succeeded");
|
|
455
459
|
expect(result.variables.API_SECRET).toBe("partition-secret-xyz");
|
|
456
460
|
|
|
457
|
-
const entries = diary.
|
|
461
|
+
const entries = diary.getByOperation(result.id);
|
|
458
462
|
const sensitiveEntries = findDecisions(entries, "Security-sensitive");
|
|
459
463
|
expect(sensitiveEntries).toHaveLength(1);
|
|
460
464
|
expect(sensitiveEntries[0].reasoning).toContain("audit");
|
|
@@ -479,8 +483,8 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
479
483
|
healthChecker.willReturn(HEALTHY);
|
|
480
484
|
|
|
481
485
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
482
|
-
const result = await agent.
|
|
483
|
-
const entries = diary.
|
|
486
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
487
|
+
const entries = diary.getByOperation(result.id);
|
|
484
488
|
|
|
485
489
|
for (const entry of entries) {
|
|
486
490
|
expect(entry.partitionId).toBe(partition.id);
|
|
@@ -499,17 +503,17 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
499
503
|
const env = seedEnvironment("production");
|
|
500
504
|
|
|
501
505
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
502
|
-
const result = await agent.
|
|
506
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
503
507
|
|
|
504
508
|
expect(result.status).toBe("failed");
|
|
505
509
|
|
|
506
510
|
for (const entryId of result.debriefEntryIds) {
|
|
507
511
|
const entry = diary.getById(entryId);
|
|
508
512
|
expect(entry).toBeDefined();
|
|
509
|
-
expect(entry!.
|
|
513
|
+
expect(entry!.operationId).toBe(result.id);
|
|
510
514
|
}
|
|
511
515
|
|
|
512
|
-
const entries = diary.
|
|
516
|
+
const entries = diary.getByOperation(result.id);
|
|
513
517
|
const failEntry = findDecisions(entries, "Deployment failed")[0];
|
|
514
518
|
expect(failEntry.context).toHaveProperty(
|
|
515
519
|
"step",
|
|
@@ -525,7 +529,7 @@ describe("Deployment Orchestration Engine", () => {
|
|
|
525
529
|
const env = seedEnvironment("production");
|
|
526
530
|
|
|
527
531
|
const trigger = makeTrigger({ artifact, partition, environment: env });
|
|
528
|
-
const result = await agent.
|
|
532
|
+
const result = await agent.triggerOperation(trigger.input, trigger.trigger);
|
|
529
533
|
|
|
530
534
|
const stored = deployments.get(result.id);
|
|
531
535
|
expect(stored).toBeDefined();
|
|
@@ -119,15 +119,10 @@ async function testDeployWithPartition(
|
|
|
119
119
|
|
|
120
120
|
const artifact = getOrCreateArtifact();
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
artifactId: artifact.id,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
environmentId: env.id,
|
|
127
|
-
triggeredBy: "user" as const,
|
|
128
|
-
...(variables ? { variables } : {}),
|
|
129
|
-
};
|
|
130
|
-
return agent.triggerDeployment(trigger);
|
|
122
|
+
return agent.triggerOperation(
|
|
123
|
+
{ type: "deploy", artifactId: artifact.id, artifactVersionId: version },
|
|
124
|
+
{ partitionId: partition.id, environmentId: env.id, triggeredBy: "user", ...(variables ? { variables } : {}) },
|
|
125
|
+
);
|
|
131
126
|
}
|
|
132
127
|
|
|
133
128
|
// ---------------------------------------------------------------------------
|
|
@@ -18,7 +18,7 @@ import { InMemoryDeploymentStore } from "../src/agent/synth-agent.js";
|
|
|
18
18
|
import { registerPartitionRoutes } from "../src/api/partitions.js";
|
|
19
19
|
import { registerEnvironmentRoutes } from "../src/api/environments.js";
|
|
20
20
|
import { registerSettingsRoutes } from "../src/api/settings.js";
|
|
21
|
-
import {
|
|
21
|
+
import { registerOperationRoutes } from "../src/api/operations.js";
|
|
22
22
|
import { registerArtifactRoutes } from "../src/api/artifacts.js";
|
|
23
23
|
import { registerAuthMiddleware, generateTokens } from "../src/middleware/auth.js";
|
|
24
24
|
|
|
@@ -120,7 +120,7 @@ async function createTestServer(): Promise<TestContext> {
|
|
|
120
120
|
registerPartitionRoutes(app, partitions, deployments, diary, telemetry);
|
|
121
121
|
registerEnvironmentRoutes(app, environments, deployments, telemetry);
|
|
122
122
|
registerSettingsRoutes(app, settings, telemetry);
|
|
123
|
-
|
|
123
|
+
registerOperationRoutes(app, deployments, diary, partitions, environments, artifactStore, settings, telemetry);
|
|
124
124
|
registerArtifactRoutes(app, artifactStore, telemetry);
|
|
125
125
|
|
|
126
126
|
await app.ready();
|
|
@@ -175,8 +175,8 @@ describe("RBAC enforcement", () => {
|
|
|
175
175
|
describe("unauthenticated requests return 401", () => {
|
|
176
176
|
const routes: Array<{ method: "GET" | "POST" | "PUT" | "DELETE"; url: string }> = [
|
|
177
177
|
// Deployments
|
|
178
|
-
{ method: "GET", url: "/api/
|
|
179
|
-
{ method: "POST", url: "/api/
|
|
178
|
+
{ method: "GET", url: "/api/operations" },
|
|
179
|
+
{ method: "POST", url: "/api/operations" },
|
|
180
180
|
{ method: "GET", url: "/api/debrief" },
|
|
181
181
|
// Artifacts
|
|
182
182
|
{ method: "GET", url: "/api/artifacts" },
|
|
@@ -215,10 +215,10 @@ describe("RBAC enforcement", () => {
|
|
|
215
215
|
// -------------------------------------------------------------------------
|
|
216
216
|
|
|
217
217
|
describe("viewer cannot perform write operations (403)", () => {
|
|
218
|
-
it("POST /api/
|
|
218
|
+
it("POST /api/operations returns 403 for viewer", async () => {
|
|
219
219
|
const res = await ctx.app.inject({
|
|
220
220
|
method: "POST",
|
|
221
|
-
url: "/api/
|
|
221
|
+
url: "/api/operations",
|
|
222
222
|
headers: { authorization: `Bearer ${ctx.viewerToken}` },
|
|
223
223
|
payload: { artifactId: "a1", environmentId: "e1" },
|
|
224
224
|
});
|
|
@@ -318,10 +318,10 @@ describe("RBAC enforcement", () => {
|
|
|
318
318
|
// -------------------------------------------------------------------------
|
|
319
319
|
|
|
320
320
|
describe("viewer can access read-only routes (200)", () => {
|
|
321
|
-
it("GET /api/
|
|
321
|
+
it("GET /api/operations returns 200 for viewer", async () => {
|
|
322
322
|
const res = await ctx.app.inject({
|
|
323
323
|
method: "GET",
|
|
324
|
-
url: "/api/
|
|
324
|
+
url: "/api/operations",
|
|
325
325
|
headers: { authorization: `Bearer ${ctx.viewerToken}` },
|
|
326
326
|
});
|
|
327
327
|
expect(res.statusCode).toBe(200);
|
package/tests/ui-journey.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { FastifyInstance } from "fastify";
|
|
|
4
4
|
import { DecisionDebrief, PartitionStore, EnvironmentStore, ArtifactStore, SettingsStore, TelemetryStore } from "@synth-deploy/core";
|
|
5
5
|
import type { Deployment, DebriefEntry, PostmortemReport, OperationHistory } from "@synth-deploy/core";
|
|
6
6
|
import { SynthAgent, InMemoryDeploymentStore } from "../src/agent/synth-agent.js";
|
|
7
|
-
import {
|
|
7
|
+
import { registerOperationRoutes } from "../src/api/operations.js";
|
|
8
8
|
import { registerPartitionRoutes } from "../src/api/partitions.js";
|
|
9
9
|
import { registerEnvironmentRoutes } from "../src/api/environments.js";
|
|
10
10
|
import { registerArtifactRoutes } from "../src/api/artifacts.js";
|
|
@@ -61,7 +61,7 @@ beforeAll(async () => {
|
|
|
61
61
|
|
|
62
62
|
app = Fastify();
|
|
63
63
|
addMockAuth(app);
|
|
64
|
-
|
|
64
|
+
registerOperationRoutes(app, deployments, diary, partitions, environments, artifactStore, settings, telemetry);
|
|
65
65
|
registerPartitionRoutes(app, partitions, deployments, diary, telemetry);
|
|
66
66
|
registerEnvironmentRoutes(app, environments, deployments, telemetry);
|
|
67
67
|
registerArtifactRoutes(app, artifactStore, telemetry);
|
|
@@ -174,7 +174,7 @@ describe("Complete UI user journey", () => {
|
|
|
174
174
|
it("triggers a deployment", async () => {
|
|
175
175
|
const res = await app.inject({
|
|
176
176
|
method: "POST",
|
|
177
|
-
url: "/api/
|
|
177
|
+
url: "/api/operations",
|
|
178
178
|
payload: {
|
|
179
179
|
artifactId,
|
|
180
180
|
partitionId,
|
|
@@ -194,7 +194,7 @@ describe("Complete UI user journey", () => {
|
|
|
194
194
|
it("lists deployments filtered by partition", async () => {
|
|
195
195
|
const res = await app.inject({
|
|
196
196
|
method: "GET",
|
|
197
|
-
url: `/api/
|
|
197
|
+
url: `/api/operations?partitionId=${partitionId}`,
|
|
198
198
|
});
|
|
199
199
|
|
|
200
200
|
const body = JSON.parse(res.payload);
|
|
@@ -207,7 +207,7 @@ describe("Complete UI user journey", () => {
|
|
|
207
207
|
it("gets deployment detail", async () => {
|
|
208
208
|
const res = await app.inject({
|
|
209
209
|
method: "GET",
|
|
210
|
-
url: `/api/
|
|
210
|
+
url: `/api/operations/${firstDeploymentId}`,
|
|
211
211
|
});
|
|
212
212
|
|
|
213
213
|
const body = JSON.parse(res.payload);
|
|
@@ -219,7 +219,7 @@ describe("Complete UI user journey", () => {
|
|
|
219
219
|
it("triggers a second deployment (version upgrade)", async () => {
|
|
220
220
|
const res = await app.inject({
|
|
221
221
|
method: "POST",
|
|
222
|
-
url: "/api/
|
|
222
|
+
url: "/api/operations",
|
|
223
223
|
payload: {
|
|
224
224
|
artifactId,
|
|
225
225
|
partitionId,
|
|
@@ -239,7 +239,7 @@ describe("Complete UI user journey", () => {
|
|
|
239
239
|
it("lists all deployments for partition showing both", async () => {
|
|
240
240
|
const res = await app.inject({
|
|
241
241
|
method: "GET",
|
|
242
|
-
url: `/api/
|
|
242
|
+
url: `/api/operations?partitionId=${partitionId}`,
|
|
243
243
|
});
|
|
244
244
|
|
|
245
245
|
const body = JSON.parse(res.payload);
|
|
@@ -254,7 +254,7 @@ describe("Complete UI user journey", () => {
|
|
|
254
254
|
it("lists deployments filtered by artifact", async () => {
|
|
255
255
|
const res = await app.inject({
|
|
256
256
|
method: "GET",
|
|
257
|
-
url: `/api/
|
|
257
|
+
url: `/api/operations?artifactId=${artifactId}`,
|
|
258
258
|
});
|
|
259
259
|
|
|
260
260
|
const body = JSON.parse(res.payload);
|
|
@@ -277,7 +277,7 @@ describe("Complete UI user journey", () => {
|
|
|
277
277
|
});
|
|
278
278
|
|
|
279
279
|
it("lists all deployments", async () => {
|
|
280
|
-
const res = await app.inject({ method: "GET", url: "/api/
|
|
280
|
+
const res = await app.inject({ method: "GET", url: "/api/operations" });
|
|
281
281
|
const body = JSON.parse(res.payload);
|
|
282
282
|
expect(body.deployments.length).toBeGreaterThanOrEqual(2);
|
|
283
283
|
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { FastifyInstance } from "fastify";
|
|
2
|
-
import type { LlmClient, IPartitionStore, IEnvironmentStore, IArtifactStore, ISettingsStore, IDeploymentStore, ITelemetryStore, DebriefWriter, DebriefReader } from "@synth-deploy/core";
|
|
3
|
-
import type { ProgressEventStore } from "./progress-event-store.js";
|
|
4
|
-
import { EnvoyClient } from "../agent/envoy-client.js";
|
|
5
|
-
import type { EnvoyRegistry } from "../agent/envoy-registry.js";
|
|
6
|
-
/**
|
|
7
|
-
* REST API routes for deployments. These are the traditional (non-MCP) interface
|
|
8
|
-
* for the web UI and integrations.
|
|
9
|
-
*/
|
|
10
|
-
export declare function registerDeploymentRoutes(app: FastifyInstance, deployments: IDeploymentStore, debrief: DebriefWriter & DebriefReader, partitions: IPartitionStore, environments: IEnvironmentStore, artifactStore: IArtifactStore, settings: ISettingsStore, telemetry: ITelemetryStore, progressStore?: ProgressEventStore, envoyClient?: EnvoyClient, envoyRegistry?: EnvoyRegistry, llm?: LlmClient): void;
|
|
11
|
-
//# sourceMappingURL=deployments.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deployments.d.ts","sourceRoot":"","sources":["../../src/api/deployments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAA+C,MAAM,oBAAoB,CAAC;AAatO,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,eAAe,EACpB,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,aAAa,GAAG,aAAa,EACtC,UAAU,EAAE,eAAe,EAC3B,YAAY,EAAE,iBAAiB,EAC/B,aAAa,EAAE,cAAc,EAC7B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,eAAe,EAC1B,aAAa,CAAC,EAAE,kBAAkB,EAClC,WAAW,CAAC,EAAE,WAAW,EACzB,aAAa,CAAC,EAAE,aAAa,EAC7B,GAAG,CAAC,EAAE,SAAS,GACd,IAAI,CAitCN"}
|