@synth-deploy/server 0.1.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/debrief-retention.d.ts +12 -0
- package/dist/agent/debrief-retention.d.ts.map +1 -0
- package/dist/agent/debrief-retention.js +27 -0
- package/dist/agent/debrief-retention.js.map +1 -0
- package/dist/agent/envoy-client.d.ts +216 -0
- package/dist/agent/envoy-client.d.ts.map +1 -0
- package/dist/agent/envoy-client.js +266 -0
- package/dist/agent/envoy-client.js.map +1 -0
- package/dist/agent/envoy-registry.d.ts +102 -0
- package/dist/agent/envoy-registry.d.ts.map +1 -0
- package/dist/agent/envoy-registry.js +319 -0
- package/dist/agent/envoy-registry.js.map +1 -0
- package/dist/agent/health-checker.d.ts +39 -0
- package/dist/agent/health-checker.d.ts.map +1 -0
- package/dist/agent/health-checker.js +49 -0
- package/dist/agent/health-checker.js.map +1 -0
- package/dist/agent/mcp-client-manager.d.ts +36 -0
- package/dist/agent/mcp-client-manager.d.ts.map +1 -0
- package/dist/agent/mcp-client-manager.js +106 -0
- package/dist/agent/mcp-client-manager.js.map +1 -0
- package/dist/agent/stale-deployment-detector.d.ts +15 -0
- package/dist/agent/stale-deployment-detector.d.ts.map +1 -0
- package/dist/agent/stale-deployment-detector.js +50 -0
- package/dist/agent/stale-deployment-detector.js.map +1 -0
- package/dist/agent/step-runner.d.ts +31 -0
- package/dist/agent/step-runner.d.ts.map +1 -0
- package/dist/agent/step-runner.js +80 -0
- package/dist/agent/step-runner.js.map +1 -0
- package/dist/agent/synth-agent.d.ts +168 -0
- package/dist/agent/synth-agent.d.ts.map +1 -0
- package/dist/agent/synth-agent.js +1195 -0
- package/dist/agent/synth-agent.js.map +1 -0
- package/dist/api/agent.d.ts +36 -0
- package/dist/api/agent.d.ts.map +1 -0
- package/dist/api/agent.js +867 -0
- package/dist/api/agent.js.map +1 -0
- package/dist/api/api-keys.d.ts +4 -0
- package/dist/api/api-keys.d.ts.map +1 -0
- package/dist/api/api-keys.js +118 -0
- package/dist/api/api-keys.js.map +1 -0
- package/dist/api/artifacts.d.ts +5 -0
- package/dist/api/artifacts.d.ts.map +1 -0
- package/dist/api/artifacts.js +142 -0
- package/dist/api/artifacts.js.map +1 -0
- package/dist/api/auth.d.ts +4 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +280 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/deployments.d.ts +11 -0
- package/dist/api/deployments.d.ts.map +1 -0
- package/dist/api/deployments.js +1098 -0
- package/dist/api/deployments.js.map +1 -0
- package/dist/api/environments.d.ts +5 -0
- package/dist/api/environments.d.ts.map +1 -0
- package/dist/api/environments.js +69 -0
- package/dist/api/environments.js.map +1 -0
- package/dist/api/envoy-reports.d.ts +17 -0
- package/dist/api/envoy-reports.d.ts.map +1 -0
- package/dist/api/envoy-reports.js +138 -0
- package/dist/api/envoy-reports.js.map +1 -0
- package/dist/api/envoys.d.ts +5 -0
- package/dist/api/envoys.d.ts.map +1 -0
- package/dist/api/envoys.js +192 -0
- package/dist/api/envoys.js.map +1 -0
- package/dist/api/fleet.d.ts +11 -0
- package/dist/api/fleet.d.ts.map +1 -0
- package/dist/api/fleet.js +394 -0
- package/dist/api/fleet.js.map +1 -0
- package/dist/api/graph.d.ts +8 -0
- package/dist/api/graph.d.ts.map +1 -0
- package/dist/api/graph.js +355 -0
- package/dist/api/graph.js.map +1 -0
- package/dist/api/health.d.ts +20 -0
- package/dist/api/health.d.ts.map +1 -0
- package/dist/api/health.js +248 -0
- package/dist/api/health.js.map +1 -0
- package/dist/api/idp-schemas.d.ts +41 -0
- package/dist/api/idp-schemas.d.ts.map +1 -0
- package/dist/api/idp-schemas.js +17 -0
- package/dist/api/idp-schemas.js.map +1 -0
- package/dist/api/idp.d.ts +6 -0
- package/dist/api/idp.d.ts.map +1 -0
- package/dist/api/idp.js +620 -0
- package/dist/api/idp.js.map +1 -0
- package/dist/api/intake.d.ts +10 -0
- package/dist/api/intake.d.ts.map +1 -0
- package/dist/api/intake.js +418 -0
- package/dist/api/intake.js.map +1 -0
- package/dist/api/partitions.d.ts +5 -0
- package/dist/api/partitions.d.ts.map +1 -0
- package/dist/api/partitions.js +113 -0
- package/dist/api/partitions.js.map +1 -0
- package/dist/api/progress-event-store.d.ts +62 -0
- package/dist/api/progress-event-store.d.ts.map +1 -0
- package/dist/api/progress-event-store.js +118 -0
- package/dist/api/progress-event-store.js.map +1 -0
- package/dist/api/schemas.d.ts +1000 -0
- package/dist/api/schemas.d.ts.map +1 -0
- package/dist/api/schemas.js +328 -0
- package/dist/api/schemas.js.map +1 -0
- package/dist/api/security-boundaries.d.ts +4 -0
- package/dist/api/security-boundaries.d.ts.map +1 -0
- package/dist/api/security-boundaries.js +32 -0
- package/dist/api/security-boundaries.js.map +1 -0
- package/dist/api/settings.d.ts +4 -0
- package/dist/api/settings.d.ts.map +1 -0
- package/dist/api/settings.js +99 -0
- package/dist/api/settings.js.map +1 -0
- package/dist/api/system.d.ts +75 -0
- package/dist/api/system.d.ts.map +1 -0
- package/dist/api/system.js +558 -0
- package/dist/api/system.js.map +1 -0
- package/dist/api/telemetry.d.ts +4 -0
- package/dist/api/telemetry.d.ts.map +1 -0
- package/dist/api/telemetry.js +24 -0
- package/dist/api/telemetry.js.map +1 -0
- package/dist/api/users.d.ts +4 -0
- package/dist/api/users.d.ts.map +1 -0
- package/dist/api/users.js +173 -0
- package/dist/api/users.js.map +1 -0
- package/dist/archive-unpacker.d.ts +24 -0
- package/dist/archive-unpacker.d.ts.map +1 -0
- package/dist/archive-unpacker.js +239 -0
- package/dist/archive-unpacker.js.map +1 -0
- package/dist/artifact-analyzer.d.ts +59 -0
- package/dist/artifact-analyzer.d.ts.map +1 -0
- package/dist/artifact-analyzer.js +334 -0
- package/dist/artifact-analyzer.js.map +1 -0
- package/dist/auth/idp/index.d.ts +9 -0
- package/dist/auth/idp/index.d.ts.map +1 -0
- package/dist/auth/idp/index.js +5 -0
- package/dist/auth/idp/index.js.map +1 -0
- package/dist/auth/idp/ldap.d.ts +56 -0
- package/dist/auth/idp/ldap.d.ts.map +1 -0
- package/dist/auth/idp/ldap.js +276 -0
- package/dist/auth/idp/ldap.js.map +1 -0
- package/dist/auth/idp/oidc.d.ts +27 -0
- package/dist/auth/idp/oidc.d.ts.map +1 -0
- package/dist/auth/idp/oidc.js +97 -0
- package/dist/auth/idp/oidc.js.map +1 -0
- package/dist/auth/idp/role-mapping.d.ts +9 -0
- package/dist/auth/idp/role-mapping.d.ts.map +1 -0
- package/dist/auth/idp/role-mapping.js +16 -0
- package/dist/auth/idp/role-mapping.js.map +1 -0
- package/dist/auth/idp/saml.d.ts +40 -0
- package/dist/auth/idp/saml.d.ts.map +1 -0
- package/dist/auth/idp/saml.js +117 -0
- package/dist/auth/idp/saml.js.map +1 -0
- package/dist/auth/idp/types.d.ts +23 -0
- package/dist/auth/idp/types.d.ts.map +1 -0
- package/dist/auth/idp/types.js +2 -0
- package/dist/auth/idp/types.js.map +1 -0
- package/dist/fleet/fleet-executor.d.ts +35 -0
- package/dist/fleet/fleet-executor.d.ts.map +1 -0
- package/dist/fleet/fleet-executor.js +228 -0
- package/dist/fleet/fleet-executor.js.map +1 -0
- package/dist/fleet/fleet-store.d.ts +13 -0
- package/dist/fleet/fleet-store.d.ts.map +1 -0
- package/dist/fleet/fleet-store.js +13 -0
- package/dist/fleet/fleet-store.js.map +1 -0
- package/dist/fleet/index.d.ts +5 -0
- package/dist/fleet/index.d.ts.map +1 -0
- package/dist/fleet/index.js +4 -0
- package/dist/fleet/index.js.map +1 -0
- package/dist/fleet/representative-selector.d.ts +15 -0
- package/dist/fleet/representative-selector.d.ts.map +1 -0
- package/dist/fleet/representative-selector.js +71 -0
- package/dist/fleet/representative-selector.js.map +1 -0
- package/dist/graph/graph-executor.d.ts +36 -0
- package/dist/graph/graph-executor.d.ts.map +1 -0
- package/dist/graph/graph-executor.js +348 -0
- package/dist/graph/graph-executor.js.map +1 -0
- package/dist/graph/graph-inference.d.ts +22 -0
- package/dist/graph/graph-inference.d.ts.map +1 -0
- package/dist/graph/graph-inference.js +149 -0
- package/dist/graph/graph-inference.js.map +1 -0
- package/dist/graph/graph-store.d.ts +12 -0
- package/dist/graph/graph-store.d.ts.map +1 -0
- package/dist/graph/graph-store.js +61 -0
- package/dist/graph/graph-store.js.map +1 -0
- package/dist/graph/index.d.ts +5 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +4 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +837 -0
- package/dist/index.js.map +1 -0
- package/dist/intake/index.d.ts +6 -0
- package/dist/intake/index.d.ts.map +1 -0
- package/dist/intake/index.js +5 -0
- package/dist/intake/index.js.map +1 -0
- package/dist/intake/intake-processor.d.ts +17 -0
- package/dist/intake/intake-processor.d.ts.map +1 -0
- package/dist/intake/intake-processor.js +99 -0
- package/dist/intake/intake-processor.js.map +1 -0
- package/dist/intake/intake-store.d.ts +7 -0
- package/dist/intake/intake-store.d.ts.map +1 -0
- package/dist/intake/intake-store.js +7 -0
- package/dist/intake/intake-store.js.map +1 -0
- package/dist/intake/registry-poller.d.ts +41 -0
- package/dist/intake/registry-poller.d.ts.map +1 -0
- package/dist/intake/registry-poller.js +202 -0
- package/dist/intake/registry-poller.js.map +1 -0
- package/dist/intake/webhook-handlers.d.ts +37 -0
- package/dist/intake/webhook-handlers.d.ts.map +1 -0
- package/dist/intake/webhook-handlers.js +268 -0
- package/dist/intake/webhook-handlers.js.map +1 -0
- package/dist/logger.d.ts +5 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/resources.d.ts +9 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +72 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +15 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +20 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +9 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +88 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/middleware/auth.d.ts +29 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +76 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/permissions.d.ts +13 -0
- package/dist/middleware/permissions.d.ts.map +1 -0
- package/dist/middleware/permissions.js +32 -0
- package/dist/middleware/permissions.js.map +1 -0
- package/dist/pattern-store.d.ts +104 -0
- package/dist/pattern-store.d.ts.map +1 -0
- package/dist/pattern-store.js +299 -0
- package/dist/pattern-store.js.map +1 -0
- package/package.json +54 -0
- package/src/agent/debrief-retention.ts +44 -0
- package/src/agent/envoy-client.ts +474 -0
- package/src/agent/envoy-registry.ts +384 -0
- package/src/agent/health-checker.ts +70 -0
- package/src/agent/mcp-client-manager.ts +131 -0
- package/src/agent/stale-deployment-detector.ts +79 -0
- package/src/agent/step-runner.ts +124 -0
- package/src/agent/synth-agent.ts +1567 -0
- package/src/api/agent.ts +1075 -0
- package/src/api/api-keys.ts +129 -0
- package/src/api/artifacts.ts +194 -0
- package/src/api/auth.ts +320 -0
- package/src/api/deployments.ts +1347 -0
- package/src/api/environments.ts +97 -0
- package/src/api/envoy-reports.ts +159 -0
- package/src/api/envoys.ts +237 -0
- package/src/api/fleet.ts +510 -0
- package/src/api/graph.ts +516 -0
- package/src/api/health.ts +311 -0
- package/src/api/idp-schemas.ts +19 -0
- package/src/api/idp.ts +735 -0
- package/src/api/intake.ts +537 -0
- package/src/api/partitions.ts +147 -0
- package/src/api/progress-event-store.ts +153 -0
- package/src/api/schemas.ts +376 -0
- package/src/api/security-boundaries.ts +54 -0
- package/src/api/settings.ts +118 -0
- package/src/api/system.ts +704 -0
- package/src/api/telemetry.ts +32 -0
- package/src/api/users.ts +210 -0
- package/src/archive-unpacker.ts +271 -0
- package/src/artifact-analyzer.ts +438 -0
- package/src/auth/idp/index.ts +8 -0
- package/src/auth/idp/ldap.ts +340 -0
- package/src/auth/idp/oidc.ts +117 -0
- package/src/auth/idp/role-mapping.ts +22 -0
- package/src/auth/idp/saml.ts +148 -0
- package/src/auth/idp/types.ts +22 -0
- package/src/fleet/fleet-executor.ts +309 -0
- package/src/fleet/fleet-store.ts +13 -0
- package/src/fleet/index.ts +4 -0
- package/src/fleet/representative-selector.ts +83 -0
- package/src/graph/graph-executor.ts +446 -0
- package/src/graph/graph-inference.ts +184 -0
- package/src/graph/graph-store.ts +75 -0
- package/src/graph/index.ts +4 -0
- package/src/index.ts +916 -0
- package/src/intake/index.ts +5 -0
- package/src/intake/intake-processor.ts +111 -0
- package/src/intake/intake-store.ts +7 -0
- package/src/intake/registry-poller.ts +230 -0
- package/src/intake/webhook-handlers.ts +328 -0
- package/src/logger.ts +19 -0
- package/src/mcp/resources.ts +98 -0
- package/src/mcp/server.ts +34 -0
- package/src/mcp/tools.ts +117 -0
- package/src/middleware/auth.ts +103 -0
- package/src/middleware/permissions.ts +35 -0
- package/src/pattern-store.ts +409 -0
- package/tests/agent-mode.test.ts +536 -0
- package/tests/api-handlers.test.ts +1245 -0
- package/tests/archive-unpacker.test.ts +179 -0
- package/tests/artifact-analyzer.test.ts +240 -0
- package/tests/auth-middleware.test.ts +189 -0
- package/tests/decision-diary.test.ts +957 -0
- package/tests/diary-reader.test.ts +782 -0
- package/tests/envoy-client.test.ts +342 -0
- package/tests/envoy-reports.test.ts +156 -0
- package/tests/mcp-tools.test.ts +213 -0
- package/tests/orchestration.test.ts +536 -0
- package/tests/partition-deletion.test.ts +143 -0
- package/tests/partition-isolation.test.ts +830 -0
- package/tests/pattern-store.test.ts +371 -0
- package/tests/rbac-enforcement.test.ts +409 -0
- package/tests/ssrf-validation.test.ts +56 -0
- package/tests/stale-deployment.test.ts +85 -0
- package/tests/step-runner.test.ts +308 -0
- package/tests/ui-journey.test.ts +330 -0
- package/tsconfig.json +11 -0
- package/vitest.config.ts +27 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PersistentDecisionDebrief } from "@synth-deploy/core";
|
|
2
|
+
/**
|
|
3
|
+
* Runs a single retention pass: purges debrief entries older than
|
|
4
|
+
* the retention threshold.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runRetentionPass(debrief: PersistentDecisionDebrief, retentionDays?: number): number;
|
|
7
|
+
/**
|
|
8
|
+
* Starts a periodic retention scanner.
|
|
9
|
+
* Returns a cleanup function to stop the interval.
|
|
10
|
+
*/
|
|
11
|
+
export declare function startRetentionScanner(debrief: PersistentDecisionDebrief, intervalMs?: number, retentionDays?: number): () => void;
|
|
12
|
+
//# sourceMappingURL=debrief-retention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debrief-retention.d.ts","sourceRoot":"","sources":["../../src/agent/debrief-retention.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAUpE;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,yBAAyB,EAClC,aAAa,GAAE,MAA+B,GAC7C,MAAM,CAOR;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,yBAAyB,EAClC,UAAU,GAAE,MAAsC,EAClD,aAAa,GAAE,MAA+B,GAC7C,MAAM,IAAI,CASZ"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const DEFAULT_RETENTION_DAYS = Number(process.env.SYNTH_DEBRIEF_RETENTION_DAYS ?? 90);
|
|
2
|
+
const DEFAULT_RETENTION_INTERVAL_MS = Number(process.env.SYNTH_RETENTION_INTERVAL_MS ?? 24 * 60 * 60 * 1000);
|
|
3
|
+
/**
|
|
4
|
+
* Runs a single retention pass: purges debrief entries older than
|
|
5
|
+
* the retention threshold.
|
|
6
|
+
*/
|
|
7
|
+
export function runRetentionPass(debrief, retentionDays = DEFAULT_RETENTION_DAYS) {
|
|
8
|
+
const cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000);
|
|
9
|
+
const purged = debrief.purgeOlderThan(cutoff);
|
|
10
|
+
if (purged > 0) {
|
|
11
|
+
console.log(`[debrief-retention] Purged ${purged} entries older than ${retentionDays} days`);
|
|
12
|
+
}
|
|
13
|
+
return purged;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Starts a periodic retention scanner.
|
|
17
|
+
* Returns a cleanup function to stop the interval.
|
|
18
|
+
*/
|
|
19
|
+
export function startRetentionScanner(debrief, intervalMs = DEFAULT_RETENTION_INTERVAL_MS, retentionDays = DEFAULT_RETENTION_DAYS) {
|
|
20
|
+
// Run once on startup
|
|
21
|
+
runRetentionPass(debrief, retentionDays);
|
|
22
|
+
const timer = setInterval(() => {
|
|
23
|
+
runRetentionPass(debrief, retentionDays);
|
|
24
|
+
}, intervalMs);
|
|
25
|
+
return () => clearInterval(timer);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=debrief-retention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debrief-retention.js","sourceRoot":"","sources":["../../src/agent/debrief-retention.ts"],"names":[],"mappings":"AAEA,MAAM,sBAAsB,GAAG,MAAM,CACnC,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,EAAE,CAC/C,CAAC;AAEF,MAAM,6BAA6B,GAAG,MAAM,CAC1C,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAC/D,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAkC,EAClC,gBAAwB,sBAAsB;IAE9C,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IAC9C,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,8BAA8B,MAAM,uBAAuB,aAAa,OAAO,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAkC,EAClC,aAAqB,6BAA6B,EAClD,gBAAwB,sBAAsB;IAE9C,sBAAsB;IACtB,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAEzC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAC3C,CAAC,EAAE,UAAU,CAAC,CAAC;IAEf,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { ServiceHealthChecker, HealthCheckResult } from "./health-checker.js";
|
|
2
|
+
import type { DecisionType, DeploymentPlan, PlannedStep } from "@synth-deploy/core";
|
|
3
|
+
export interface EnvoyDeployResult {
|
|
4
|
+
deploymentId: string;
|
|
5
|
+
success: boolean;
|
|
6
|
+
workspacePath: string;
|
|
7
|
+
artifacts: string[];
|
|
8
|
+
executionDurationMs: number;
|
|
9
|
+
totalDurationMs: number;
|
|
10
|
+
verificationPassed: boolean;
|
|
11
|
+
verificationChecks: Array<{
|
|
12
|
+
name: string;
|
|
13
|
+
passed: boolean;
|
|
14
|
+
detail: string;
|
|
15
|
+
}>;
|
|
16
|
+
failureReason: string | null;
|
|
17
|
+
debriefEntryIds: string[];
|
|
18
|
+
/** Full debrief entries from the Envoy — Command can ingest these */
|
|
19
|
+
debriefEntries: Array<{
|
|
20
|
+
id: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
partitionId: string | null;
|
|
23
|
+
deploymentId: string | null;
|
|
24
|
+
agent: "server" | "envoy";
|
|
25
|
+
decisionType: DecisionType;
|
|
26
|
+
decision: string;
|
|
27
|
+
reasoning: string;
|
|
28
|
+
context: Record<string, unknown>;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export interface EnvoyHealthResponse {
|
|
32
|
+
status: "healthy" | "degraded";
|
|
33
|
+
service: string;
|
|
34
|
+
hostname: string;
|
|
35
|
+
os: string;
|
|
36
|
+
timestamp: string;
|
|
37
|
+
readiness: {
|
|
38
|
+
ready: boolean;
|
|
39
|
+
reason: string;
|
|
40
|
+
};
|
|
41
|
+
summary: {
|
|
42
|
+
totalDeployments: number;
|
|
43
|
+
succeeded: number;
|
|
44
|
+
failed: number;
|
|
45
|
+
executing: number;
|
|
46
|
+
environments: number;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* HTTP client for communicating with a Envoy agent.
|
|
51
|
+
*
|
|
52
|
+
* Command uses this to:
|
|
53
|
+
* 1. Check if the Envoy is healthy (pre-flight health check)
|
|
54
|
+
* 2. Delegate deployment execution to the Envoy
|
|
55
|
+
* 3. Query the Envoy's local state
|
|
56
|
+
*/
|
|
57
|
+
export declare class EnvoyClient {
|
|
58
|
+
private baseUrl;
|
|
59
|
+
private timeoutMs;
|
|
60
|
+
constructor(baseUrl: string, timeoutMs?: number);
|
|
61
|
+
get url(): string;
|
|
62
|
+
/**
|
|
63
|
+
* Check Envoy health — used as the ServiceHealthChecker for the
|
|
64
|
+
* Command Agent's pre-flight health check step.
|
|
65
|
+
*/
|
|
66
|
+
checkHealth(): Promise<EnvoyHealthResponse>;
|
|
67
|
+
/**
|
|
68
|
+
* Send a deployment instruction to the Envoy and wait for the result.
|
|
69
|
+
*/
|
|
70
|
+
deploy(instruction: {
|
|
71
|
+
deploymentId: string;
|
|
72
|
+
partitionId: string;
|
|
73
|
+
environmentId: string;
|
|
74
|
+
operationId: string;
|
|
75
|
+
version: string;
|
|
76
|
+
variables: Record<string, string>;
|
|
77
|
+
environmentName: string;
|
|
78
|
+
partitionName: string;
|
|
79
|
+
progressCallbackUrl?: string;
|
|
80
|
+
}): Promise<EnvoyDeployResult>;
|
|
81
|
+
/**
|
|
82
|
+
* Dispatch an approved plan to the Envoy for deterministic execution.
|
|
83
|
+
*/
|
|
84
|
+
executeApprovedPlan(params: {
|
|
85
|
+
deploymentId: string;
|
|
86
|
+
plan: DeploymentPlan;
|
|
87
|
+
rollbackPlan: DeploymentPlan;
|
|
88
|
+
artifactType: string;
|
|
89
|
+
artifactName: string;
|
|
90
|
+
environmentId: string;
|
|
91
|
+
progressCallbackUrl?: string;
|
|
92
|
+
callbackToken?: string;
|
|
93
|
+
}): Promise<EnvoyDeployResult>;
|
|
94
|
+
/**
|
|
95
|
+
* Ask the Envoy to produce a deployment plan (read-only reasoning phase).
|
|
96
|
+
* Returns the plan and rollback plan; the server then submits them to
|
|
97
|
+
* POST /api/deployments/:id/plan to move the deployment to awaiting_approval.
|
|
98
|
+
*/
|
|
99
|
+
requestPlan(params: {
|
|
100
|
+
deploymentId: string;
|
|
101
|
+
artifact: {
|
|
102
|
+
id: string;
|
|
103
|
+
name: string;
|
|
104
|
+
type: string;
|
|
105
|
+
analysis: {
|
|
106
|
+
summary: string;
|
|
107
|
+
dependencies: string[];
|
|
108
|
+
configurationExpectations: Record<string, string>;
|
|
109
|
+
deploymentIntent?: string;
|
|
110
|
+
confidence: number;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
environment: {
|
|
114
|
+
id: string;
|
|
115
|
+
name: string;
|
|
116
|
+
variables: Record<string, string>;
|
|
117
|
+
};
|
|
118
|
+
partition?: {
|
|
119
|
+
id: string;
|
|
120
|
+
name: string;
|
|
121
|
+
variables: Record<string, string>;
|
|
122
|
+
};
|
|
123
|
+
version: string;
|
|
124
|
+
resolvedVariables: Record<string, string>;
|
|
125
|
+
refinementFeedback?: string;
|
|
126
|
+
}): Promise<{
|
|
127
|
+
plan: DeploymentPlan;
|
|
128
|
+
rollbackPlan: DeploymentPlan;
|
|
129
|
+
delta?: string;
|
|
130
|
+
assessmentSummary?: string;
|
|
131
|
+
blocked?: boolean;
|
|
132
|
+
blockReason?: string;
|
|
133
|
+
}>;
|
|
134
|
+
/**
|
|
135
|
+
* Ask the Envoy to generate a rollback plan for a deployment that has
|
|
136
|
+
* already executed. Uses the execution record (what actually ran) rather
|
|
137
|
+
* than the forward plan, so the rollback is targeted to what actually changed.
|
|
138
|
+
*/
|
|
139
|
+
requestRollbackPlan(params: {
|
|
140
|
+
deploymentId: string;
|
|
141
|
+
artifact: {
|
|
142
|
+
name: string;
|
|
143
|
+
type: string;
|
|
144
|
+
analysis: {
|
|
145
|
+
summary: string;
|
|
146
|
+
dependencies: string[];
|
|
147
|
+
configurationExpectations: Record<string, string>;
|
|
148
|
+
deploymentIntent?: string;
|
|
149
|
+
confidence: number;
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
environment: {
|
|
153
|
+
id: string;
|
|
154
|
+
name: string;
|
|
155
|
+
};
|
|
156
|
+
completedSteps: Array<{
|
|
157
|
+
description: string;
|
|
158
|
+
action: string;
|
|
159
|
+
target: string;
|
|
160
|
+
status: "completed" | "failed" | "rolled_back";
|
|
161
|
+
output?: string;
|
|
162
|
+
}>;
|
|
163
|
+
deployedVariables: Record<string, string>;
|
|
164
|
+
version: string;
|
|
165
|
+
failureReason?: string;
|
|
166
|
+
}): Promise<DeploymentPlan>;
|
|
167
|
+
/**
|
|
168
|
+
* Validate a modified plan against the Envoy's security boundaries.
|
|
169
|
+
*/
|
|
170
|
+
validatePlan(steps: PlannedStep[]): Promise<{
|
|
171
|
+
valid: boolean;
|
|
172
|
+
violations: Array<{
|
|
173
|
+
step: string;
|
|
174
|
+
reason: string;
|
|
175
|
+
}>;
|
|
176
|
+
}>;
|
|
177
|
+
/**
|
|
178
|
+
* Ask the Envoy to validate whether user refinement feedback warrants a
|
|
179
|
+
* full replan. Cheap LLM call — no probe loop, no environment scanning.
|
|
180
|
+
* Always falls through to allow the replan if the call fails.
|
|
181
|
+
*/
|
|
182
|
+
validateRefinementFeedback(params: {
|
|
183
|
+
feedback: string;
|
|
184
|
+
currentPlanSteps: Array<{
|
|
185
|
+
description: string;
|
|
186
|
+
action: string;
|
|
187
|
+
target: string;
|
|
188
|
+
}>;
|
|
189
|
+
artifactName: string;
|
|
190
|
+
environmentName: string;
|
|
191
|
+
}): Promise<{
|
|
192
|
+
mode: "replan" | "rejection" | "response";
|
|
193
|
+
message: string;
|
|
194
|
+
}>;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Adapts the EnvoyClient to the ServiceHealthChecker interface used by
|
|
198
|
+
* the Command Agent's pre-flight health check step.
|
|
199
|
+
*
|
|
200
|
+
* When a Envoy is registered for an environment, Command's health
|
|
201
|
+
* check actually reaches out to the Envoy instead of using the
|
|
202
|
+
* DefaultHealthChecker (which always returns healthy).
|
|
203
|
+
*/
|
|
204
|
+
export declare class EnvoyHealthChecker implements ServiceHealthChecker {
|
|
205
|
+
private envoys;
|
|
206
|
+
/**
|
|
207
|
+
* Register a Envoy for a specific environment.
|
|
208
|
+
* The serviceId format is "{operationId}/{environmentName}".
|
|
209
|
+
*/
|
|
210
|
+
registerEnvoy(serviceId: string, client: EnvoyClient): void;
|
|
211
|
+
check(serviceId: string, _context: {
|
|
212
|
+
partitionId: string;
|
|
213
|
+
environmentName: string;
|
|
214
|
+
}): Promise<HealthCheckResult>;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=envoy-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envoy-client.d.ts","sourceRoot":"","sources":["../../src/agent/envoy-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { serverLog, serverWarn, serverError } from "../logger.js";
|
|
2
|
+
const DEFAULT_RETRY = {
|
|
3
|
+
maxRetries: Number(process.env.SYNTH_ENVOY_MAX_RETRIES ?? 3),
|
|
4
|
+
baseDelayMs: 1000,
|
|
5
|
+
retryableStatuses: new Set([502, 503, 504]),
|
|
6
|
+
};
|
|
7
|
+
function isTransientError(err) {
|
|
8
|
+
if (!(err instanceof Error))
|
|
9
|
+
return false;
|
|
10
|
+
const msg = err.message;
|
|
11
|
+
return (msg.includes("ECONNREFUSED") ||
|
|
12
|
+
msg.includes("ECONNRESET") ||
|
|
13
|
+
msg.includes("fetch failed") ||
|
|
14
|
+
msg.includes("abort") ||
|
|
15
|
+
msg.includes("ETIMEDOUT") ||
|
|
16
|
+
msg.includes("network"));
|
|
17
|
+
}
|
|
18
|
+
async function sleep(ms) {
|
|
19
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
20
|
+
}
|
|
21
|
+
async function fetchWithRetry(url, init, timeoutMs, opts = DEFAULT_RETRY) {
|
|
22
|
+
let lastError;
|
|
23
|
+
for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch(url, {
|
|
28
|
+
...init,
|
|
29
|
+
signal: controller.signal,
|
|
30
|
+
});
|
|
31
|
+
// If retryable status code and we have retries left, retry
|
|
32
|
+
if (opts.retryableStatuses.has(response.status) && attempt < opts.maxRetries) {
|
|
33
|
+
const delay = opts.baseDelayMs * Math.pow(2, attempt);
|
|
34
|
+
console.log(`[envoy-client] Retryable HTTP ${response.status} on attempt ${attempt + 1}/${opts.maxRetries + 1}, retrying in ${delay}ms`);
|
|
35
|
+
serverWarn(`HTTP-RETRY`, { url, status: response.status, attempt: attempt + 1, maxAttempts: opts.maxRetries + 1, delayMs: delay });
|
|
36
|
+
await sleep(delay);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
return response;
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
43
|
+
if (isTransientError(err) && attempt < opts.maxRetries) {
|
|
44
|
+
const delay = opts.baseDelayMs * Math.pow(2, attempt);
|
|
45
|
+
console.log(`[envoy-client] Transient error on attempt ${attempt + 1}/${opts.maxRetries + 1}: ${lastError.message}, retrying in ${delay}ms`);
|
|
46
|
+
serverWarn(`TRANSIENT-RETRY`, { url, error: lastError.message, attempt: attempt + 1, maxAttempts: opts.maxRetries + 1, delayMs: delay });
|
|
47
|
+
await sleep(delay);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
throw lastError;
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
clearTimeout(timeout);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw lastError ?? new Error("Retry exhausted");
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// EnvoyClient — Command's interface to a remote Envoy
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* HTTP client for communicating with a Envoy agent.
|
|
63
|
+
*
|
|
64
|
+
* Command uses this to:
|
|
65
|
+
* 1. Check if the Envoy is healthy (pre-flight health check)
|
|
66
|
+
* 2. Delegate deployment execution to the Envoy
|
|
67
|
+
* 3. Query the Envoy's local state
|
|
68
|
+
*/
|
|
69
|
+
export class EnvoyClient {
|
|
70
|
+
baseUrl;
|
|
71
|
+
timeoutMs;
|
|
72
|
+
constructor(baseUrl, timeoutMs = 10_000) {
|
|
73
|
+
this.baseUrl = baseUrl;
|
|
74
|
+
this.timeoutMs = timeoutMs;
|
|
75
|
+
}
|
|
76
|
+
get url() { return this.baseUrl; }
|
|
77
|
+
/**
|
|
78
|
+
* Check Envoy health — used as the ServiceHealthChecker for the
|
|
79
|
+
* Command Agent's pre-flight health check step.
|
|
80
|
+
*/
|
|
81
|
+
async checkHealth() {
|
|
82
|
+
serverLog("ENVOY-HEALTH-CHECK", { url: this.baseUrl });
|
|
83
|
+
const start = Date.now();
|
|
84
|
+
const response = await fetchWithRetry(`${this.baseUrl}/health`, {}, this.timeoutMs);
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
87
|
+
}
|
|
88
|
+
const result = (await response.json());
|
|
89
|
+
serverLog("ENVOY-HEALTH-OK", { url: this.baseUrl, status: result.status, ready: result.readiness.ready, durationMs: Date.now() - start });
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Send a deployment instruction to the Envoy and wait for the result.
|
|
94
|
+
*/
|
|
95
|
+
async deploy(instruction) {
|
|
96
|
+
const response = await fetchWithRetry(`${this.baseUrl}/deploy`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: { "Content-Type": "application/json" },
|
|
99
|
+
body: JSON.stringify(instruction),
|
|
100
|
+
}, this.timeoutMs * 3);
|
|
101
|
+
return (await response.json());
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Dispatch an approved plan to the Envoy for deterministic execution.
|
|
105
|
+
*/
|
|
106
|
+
async executeApprovedPlan(params) {
|
|
107
|
+
serverLog("ENVOY-EXECUTE", { deploymentId: params.deploymentId, envoyUrl: this.baseUrl, artifact: params.artifactName, steps: params.plan?.steps?.length ?? 0 });
|
|
108
|
+
const execStart = Date.now();
|
|
109
|
+
const response = await fetchWithRetry(`${this.baseUrl}/execute`, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: { "Content-Type": "application/json" },
|
|
112
|
+
body: JSON.stringify(params),
|
|
113
|
+
}, this.timeoutMs * 6);
|
|
114
|
+
const execResult = (await response.json());
|
|
115
|
+
if (execResult.success) {
|
|
116
|
+
serverLog("ENVOY-EXECUTE-COMPLETE", { deploymentId: params.deploymentId, durationMs: Date.now() - execStart });
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
serverLog("ENVOY-EXECUTE-FAILED", { deploymentId: params.deploymentId, failureReason: execResult.failureReason, durationMs: Date.now() - execStart });
|
|
120
|
+
}
|
|
121
|
+
return execResult;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Ask the Envoy to produce a deployment plan (read-only reasoning phase).
|
|
125
|
+
* Returns the plan and rollback plan; the server then submits them to
|
|
126
|
+
* POST /api/deployments/:id/plan to move the deployment to awaiting_approval.
|
|
127
|
+
*/
|
|
128
|
+
async requestPlan(params) {
|
|
129
|
+
// Forward the LLM API key so the Envoy can use it if it started without one.
|
|
130
|
+
// Sent in the request body (not headers) over the trusted server↔envoy channel.
|
|
131
|
+
serverLog("ENVOY-PLAN-REQUEST", { deploymentId: params.deploymentId, envoyUrl: this.baseUrl, artifact: params.artifact.name, version: params.version, environment: params.environment.name });
|
|
132
|
+
const llmApiKey = process.env.SYNTH_LLM_API_KEY;
|
|
133
|
+
const planStart = Date.now();
|
|
134
|
+
const response = await fetchWithRetry(`${this.baseUrl}/plan`, {
|
|
135
|
+
method: "POST",
|
|
136
|
+
headers: { "Content-Type": "application/json" },
|
|
137
|
+
body: JSON.stringify(llmApiKey ? { ...params, llmApiKey } : params),
|
|
138
|
+
}, this.timeoutMs * 18);
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
const body = await response.text().catch(() => "");
|
|
141
|
+
serverLog("ENVOY-PLAN-FAILED", { deploymentId: params.deploymentId, status: response.status, durationMs: Date.now() - planStart });
|
|
142
|
+
throw new Error(`Envoy planning failed (HTTP ${response.status}): ${body}`);
|
|
143
|
+
}
|
|
144
|
+
const planResult = (await response.json());
|
|
145
|
+
serverLog("ENVOY-PLAN-RECEIVED", { deploymentId: params.deploymentId, steps: planResult.plan?.steps?.length ?? 0, blocked: planResult.blocked ?? false, durationMs: Date.now() - planStart });
|
|
146
|
+
return planResult;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Ask the Envoy to generate a rollback plan for a deployment that has
|
|
150
|
+
* already executed. Uses the execution record (what actually ran) rather
|
|
151
|
+
* than the forward plan, so the rollback is targeted to what actually changed.
|
|
152
|
+
*/
|
|
153
|
+
async requestRollbackPlan(params) {
|
|
154
|
+
const llmApiKey = process.env.SYNTH_LLM_API_KEY;
|
|
155
|
+
const response = await fetchWithRetry(`${this.baseUrl}/rollback-plan`, {
|
|
156
|
+
method: "POST",
|
|
157
|
+
headers: { "Content-Type": "application/json" },
|
|
158
|
+
body: JSON.stringify(llmApiKey ? { ...params, llmApiKey } : params),
|
|
159
|
+
}, this.timeoutMs * 18);
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
const body = await response.text().catch(() => "");
|
|
162
|
+
throw new Error(`Envoy rollback planning failed (HTTP ${response.status}): ${body}`);
|
|
163
|
+
}
|
|
164
|
+
const data = (await response.json());
|
|
165
|
+
return data.rollbackPlan;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Validate a modified plan against the Envoy's security boundaries.
|
|
169
|
+
*/
|
|
170
|
+
async validatePlan(steps) {
|
|
171
|
+
const response = await fetchWithRetry(`${this.baseUrl}/validate-plan`, {
|
|
172
|
+
method: "POST",
|
|
173
|
+
headers: { "Content-Type": "application/json" },
|
|
174
|
+
body: JSON.stringify({ steps }),
|
|
175
|
+
}, this.timeoutMs);
|
|
176
|
+
return (await response.json());
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Ask the Envoy to validate whether user refinement feedback warrants a
|
|
180
|
+
* full replan. Cheap LLM call — no probe loop, no environment scanning.
|
|
181
|
+
* Always falls through to allow the replan if the call fails.
|
|
182
|
+
*/
|
|
183
|
+
async validateRefinementFeedback(params) {
|
|
184
|
+
const llmApiKey = process.env.SYNTH_LLM_API_KEY;
|
|
185
|
+
const response = await fetchWithRetry(`${this.baseUrl}/validate-refinement`, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
headers: { "Content-Type": "application/json" },
|
|
188
|
+
body: JSON.stringify(llmApiKey ? { ...params, llmApiKey } : params),
|
|
189
|
+
}, this.timeoutMs * 3);
|
|
190
|
+
return (await response.json());
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// EnvoyHealthChecker — adapts EnvoyClient to ServiceHealthChecker
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
/**
|
|
197
|
+
* Adapts the EnvoyClient to the ServiceHealthChecker interface used by
|
|
198
|
+
* the Command Agent's pre-flight health check step.
|
|
199
|
+
*
|
|
200
|
+
* When a Envoy is registered for an environment, Command's health
|
|
201
|
+
* check actually reaches out to the Envoy instead of using the
|
|
202
|
+
* DefaultHealthChecker (which always returns healthy).
|
|
203
|
+
*/
|
|
204
|
+
export class EnvoyHealthChecker {
|
|
205
|
+
envoys = new Map();
|
|
206
|
+
/**
|
|
207
|
+
* Register a Envoy for a specific environment.
|
|
208
|
+
* The serviceId format is "{operationId}/{environmentName}".
|
|
209
|
+
*/
|
|
210
|
+
registerEnvoy(serviceId, client) {
|
|
211
|
+
this.envoys.set(serviceId, client);
|
|
212
|
+
}
|
|
213
|
+
async check(serviceId, _context) {
|
|
214
|
+
const client = this.envoys.get(serviceId);
|
|
215
|
+
if (!client) {
|
|
216
|
+
// No Envoy registered for this service — assume healthy
|
|
217
|
+
// (same as DefaultHealthChecker behavior)
|
|
218
|
+
return { reachable: true, responseTimeMs: 0, error: null };
|
|
219
|
+
}
|
|
220
|
+
serverLog("HEALTH-CHECK", { serviceId, url: client.url });
|
|
221
|
+
const start = Date.now();
|
|
222
|
+
try {
|
|
223
|
+
const health = await client.checkHealth();
|
|
224
|
+
const responseTimeMs = Date.now() - start;
|
|
225
|
+
if (health.status === "healthy" && health.readiness.ready) {
|
|
226
|
+
serverLog("HEALTH-OK", { serviceId, responseTimeMs });
|
|
227
|
+
return { reachable: true, responseTimeMs, error: null };
|
|
228
|
+
}
|
|
229
|
+
serverWarn("HEALTH-DEGRADED", { serviceId, responseTimeMs, status: health.status, reason: health.readiness.reason });
|
|
230
|
+
return {
|
|
231
|
+
reachable: false,
|
|
232
|
+
responseTimeMs,
|
|
233
|
+
error: `Envoy reports ${health.status}: ${health.readiness.reason}`,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
const responseTimeMs = Date.now() - start;
|
|
238
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
239
|
+
// Map fetch errors to recognizable categories for the Command Agent
|
|
240
|
+
if (message.includes("abort")) {
|
|
241
|
+
serverError("HEALTH-TIMEOUT", { serviceId, responseTimeMs });
|
|
242
|
+
return {
|
|
243
|
+
reachable: false,
|
|
244
|
+
responseTimeMs,
|
|
245
|
+
error: `ETIMEDOUT: Envoy health check timed out after ${responseTimeMs}ms`,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
if (message.includes("ECONNREFUSED") ||
|
|
249
|
+
message.includes("fetch failed")) {
|
|
250
|
+
serverError("HEALTH-REFUSED", { serviceId, responseTimeMs, url: client.url });
|
|
251
|
+
return {
|
|
252
|
+
reachable: false,
|
|
253
|
+
responseTimeMs,
|
|
254
|
+
error: `ECONNREFUSED: Envoy at ${serviceId} is not responding`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
serverError("HEALTH-ERROR", { serviceId, responseTimeMs, error: message });
|
|
258
|
+
return {
|
|
259
|
+
reachable: false,
|
|
260
|
+
responseTimeMs,
|
|
261
|
+
error: `Envoy health check failed: ${message}`,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=envoy-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envoy-client.js","sourceRoot":"","sources":["../../src/agent/envoy-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { EnvoyHealthResponse } from "./envoy-client.js";
|
|
2
|
+
import type { PersistentEnvoyRegistryStore } from "@synth-deploy/core";
|
|
3
|
+
export interface EnvoyRegistration {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
url: string;
|
|
7
|
+
/** Shared secret for authenticating requests between Command and this Envoy */
|
|
8
|
+
token: string;
|
|
9
|
+
/** Environments this Envoy is assigned to (empty = available for any) */
|
|
10
|
+
assignedEnvironments: string[];
|
|
11
|
+
/** Partitions this Envoy is assigned to */
|
|
12
|
+
assignedPartitions: string[];
|
|
13
|
+
registeredAt: string;
|
|
14
|
+
lastHealthCheck: string | null;
|
|
15
|
+
lastHealthStatus: "healthy" | "degraded" | "unreachable" | null;
|
|
16
|
+
/** Cached from last successful health probe */
|
|
17
|
+
cachedHostname: string | null;
|
|
18
|
+
cachedOs: string | null;
|
|
19
|
+
cachedSummary: EnvoyHealthResponse["summary"] | null;
|
|
20
|
+
cachedReadiness: EnvoyHealthResponse["readiness"] | null;
|
|
21
|
+
}
|
|
22
|
+
export interface EnvoyRegistryEntry extends EnvoyRegistration {
|
|
23
|
+
health: "OK" | "Degraded" | "Unreachable";
|
|
24
|
+
hostname: string | null;
|
|
25
|
+
os: string | null;
|
|
26
|
+
lastSeen: string | null;
|
|
27
|
+
summary: EnvoyHealthResponse["summary"] | null;
|
|
28
|
+
readiness: EnvoyHealthResponse["readiness"] | null;
|
|
29
|
+
}
|
|
30
|
+
export declare class EnvoyRegistry {
|
|
31
|
+
private store?;
|
|
32
|
+
constructor(store?: PersistentEnvoyRegistryStore | undefined);
|
|
33
|
+
/**
|
|
34
|
+
* Register a new Envoy. Returns the registration with a generated token.
|
|
35
|
+
*/
|
|
36
|
+
register(params: {
|
|
37
|
+
name: string;
|
|
38
|
+
url: string;
|
|
39
|
+
assignedEnvironments?: string[];
|
|
40
|
+
assignedPartitions?: string[];
|
|
41
|
+
}): EnvoyRegistration;
|
|
42
|
+
/**
|
|
43
|
+
* Deregister an Envoy by ID.
|
|
44
|
+
*/
|
|
45
|
+
deregister(id: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* List all registered Envoys.
|
|
48
|
+
*/
|
|
49
|
+
list(): EnvoyRegistration[];
|
|
50
|
+
/**
|
|
51
|
+
* Update an Envoy's assignment or name.
|
|
52
|
+
*/
|
|
53
|
+
update(id: string, updates: {
|
|
54
|
+
name?: string;
|
|
55
|
+
url?: string;
|
|
56
|
+
assignedEnvironments?: string[];
|
|
57
|
+
assignedPartitions?: string[];
|
|
58
|
+
}): EnvoyRegistration | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Ensure an envoy at `url` is registered with a specific `token`.
|
|
61
|
+
* If already registered, updates its token. If not, creates a new entry.
|
|
62
|
+
* Used to bootstrap the default envoy from environment variables (SYNTH_ENVOY_TOKEN).
|
|
63
|
+
*/
|
|
64
|
+
ensureRegisteredWithToken(params: {
|
|
65
|
+
name: string;
|
|
66
|
+
url: string;
|
|
67
|
+
}, token: string): EnvoyRegistration;
|
|
68
|
+
/**
|
|
69
|
+
* Rotate the token for an Envoy. Returns the new token.
|
|
70
|
+
*/
|
|
71
|
+
rotateToken(id: string): string | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Validate a token against a registered Envoy.
|
|
74
|
+
*/
|
|
75
|
+
validateToken(token: string): EnvoyRegistration | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Update health status for an Envoy (called after probing).
|
|
78
|
+
*/
|
|
79
|
+
updateHealth(id: string, status: "healthy" | "degraded" | "unreachable"): void;
|
|
80
|
+
/**
|
|
81
|
+
* Find the best Envoy for a given environment.
|
|
82
|
+
* Priority: assigned + healthy > assigned + degraded > unassigned + healthy > fallback
|
|
83
|
+
*/
|
|
84
|
+
findForEnvironment(environmentName: string): EnvoyRegistration | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Return cached registry entry without probing (instant).
|
|
87
|
+
*/
|
|
88
|
+
get(id: string): EnvoyRegistryEntry | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* Return all cached registry entries without probing (instant).
|
|
91
|
+
*/
|
|
92
|
+
listEntries(): EnvoyRegistryEntry[];
|
|
93
|
+
/**
|
|
94
|
+
* Probe an Envoy's health and update its registry entry.
|
|
95
|
+
*/
|
|
96
|
+
probe(id: string): Promise<EnvoyRegistryEntry | undefined>;
|
|
97
|
+
/**
|
|
98
|
+
* Probe all registered Envoys and return their status.
|
|
99
|
+
*/
|
|
100
|
+
probeAll(): Promise<EnvoyRegistryEntry[]>;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=envoy-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envoy-registry.d.ts","sourceRoot":"","sources":["../../src/agent/envoy-registry.ts"],"names":[],"mappings":"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"}
|