@checkstack/satellite-common 0.5.3 → 0.7.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/CHANGELOG.md +116 -0
- package/package.json +5 -5
- package/src/index.ts +8 -0
- package/src/protocol.test.ts +150 -0
- package/src/protocol.ts +154 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,121 @@
|
|
|
1
1
|
# @checkstack/satellite-common
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 270ef29: Extend the satellite protocol for script-package distribution: the
|
|
8
|
+
`authenticated` / `config_updated` payloads now carry an optional
|
|
9
|
+
`scriptPackagesLockfileHash` (the durable convergence backstop), a new
|
|
10
|
+
`refresh_script_packages { lockfileHash }` core->satellite control push,
|
|
11
|
+
and a new `script_package_sync_state` satellite->core report message. All
|
|
12
|
+
additions are optional / additive, so existing satellites and protocol
|
|
13
|
+
tests are unaffected.
|
|
14
|
+
- 270ef29: Satellite-side script-package reconciliation over the WS channel.
|
|
15
|
+
|
|
16
|
+
- `satellite-common`: WS request/reply messages for pulling the manifest +
|
|
17
|
+
blobs from core (`request_script_package_manifest` /
|
|
18
|
+
`request_script_package_blob` -> `script_package_manifest` /
|
|
19
|
+
`script_package_blob`).
|
|
20
|
+
- `satellite-backend`: the WS handler answers those requests from the
|
|
21
|
+
script-packages store (satellites pull from core, never the registry).
|
|
22
|
+
- `@checkstack/satellite`: the client gains request/reply plumbing + a
|
|
23
|
+
`SatelliteScriptPackages` manager that reuses the Phase 2 reconciler
|
|
24
|
+
(`reconcileToHash` + `createReconcileFsDeps`) over the WS transport. It
|
|
25
|
+
reconciles on a `refresh_script_packages` push and on the
|
|
26
|
+
assignment-carried hash (startup / reconnect backstop), pulls only missing
|
|
27
|
+
blobs (delta), materializes via `bun install --offline`, atomically flips
|
|
28
|
+
`current`, reports sync state back, and degrades cleanly (error state, no
|
|
29
|
+
stale tree, no registry access) when a blob can't be fetched. Reconciles
|
|
30
|
+
are serialized + coalesced + idempotent.
|
|
31
|
+
|
|
32
|
+
- 270ef29: Secrets platform Phase 3: just-in-time secret delivery to satellites + source-side masking, and central-execution injection for healthcheck collectors.
|
|
33
|
+
|
|
34
|
+
- New satellite WS messages `request_run_secrets` / `run_secrets`: just
|
|
35
|
+
before a satellite runs a collector that declares a `secretEnv`, it asks
|
|
36
|
+
core for that collector's resolved env; core resolves ONLY the secrets the
|
|
37
|
+
collector's OWN persisted assignment declares (least-privilege — the
|
|
38
|
+
satellite cannot choose) and replies with the env map (or a clear error).
|
|
39
|
+
The satellite injects it memory-only for the run and drops it on
|
|
40
|
+
completion. Secrets never ride the persisted assignment and never touch
|
|
41
|
+
disk.
|
|
42
|
+
- Source-side masking: the satellite runs `maskSecrets` over the collector's
|
|
43
|
+
stdout/stderr/result/error using the run's delivered values BEFORE the
|
|
44
|
+
result leaves the satellite (defense in depth).
|
|
45
|
+
- `CollectorStrategy.execute` gains an optional `secretEnv`. The
|
|
46
|
+
inline-script and shell collectors inject it into the runner
|
|
47
|
+
(`process.env` / `$VAR`) and mask the values out of their output.
|
|
48
|
+
- Healthcheck collectors running centrally (the queue executor) also resolve
|
|
49
|
+
- inject `secretEnv` via `secretResolverRef`, closing the gap where a
|
|
50
|
+
centrally-run secretEnv collector got no secrets. A missing required
|
|
51
|
+
secret fails the run clearly in all paths.
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- Updated dependencies [270ef29]
|
|
56
|
+
- Updated dependencies [270ef29]
|
|
57
|
+
- Updated dependencies [270ef29]
|
|
58
|
+
- Updated dependencies [b995afb]
|
|
59
|
+
- Updated dependencies [b995afb]
|
|
60
|
+
- Updated dependencies [270ef29]
|
|
61
|
+
- Updated dependencies [270ef29]
|
|
62
|
+
- @checkstack/healthcheck-common@1.4.0
|
|
63
|
+
|
|
64
|
+
## 0.6.0
|
|
65
|
+
|
|
66
|
+
### Minor Changes
|
|
67
|
+
|
|
68
|
+
- 35bc682: feat(healthcheck): expose check + system run-context to script collectors
|
|
69
|
+
|
|
70
|
+
Script health checks can now read which check and system a run is for.
|
|
71
|
+
Previously shell scripts got only a curated env whitelist and inline
|
|
72
|
+
scripts only `context.config`, so a script had no built-in way to know
|
|
73
|
+
its own check name or the system it was checking.
|
|
74
|
+
|
|
75
|
+
- `@checkstack/backend-api`: new `CollectorRunContext` type
|
|
76
|
+
(`{ check: { id, name, intervalSeconds }, system: { id, name } }`) and
|
|
77
|
+
an optional `runContext` param on `CollectorStrategy.execute`. Optional,
|
|
78
|
+
so existing collector implementations are unaffected.
|
|
79
|
+
- Shell-script collector: injects reserved `CHECKSTACK_CHECK_ID`,
|
|
80
|
+
`CHECKSTACK_CHECK_NAME`, `CHECKSTACK_CHECK_INTERVAL_SECONDS`,
|
|
81
|
+
`CHECKSTACK_SYSTEM_ID`, `CHECKSTACK_SYSTEM_NAME` env vars (user-supplied
|
|
82
|
+
`env` still wins on collision).
|
|
83
|
+
- Inline-script collector: exposes `context.check` and `context.system`
|
|
84
|
+
alongside `context.config`; the inline-script editor now types them for
|
|
85
|
+
autocomplete.
|
|
86
|
+
- Shell editors (health-check collectors and automation shell actions) now
|
|
87
|
+
also suggest the user's own `env` (JSON) keys as `$NAME` completions, via
|
|
88
|
+
the new exported `customShellEnvVars` helper. Keys that aren't valid shell
|
|
89
|
+
identifiers are omitted.
|
|
90
|
+
- Fix: the Typefox `CodeEditor` captured a stale `onChange` at editor start,
|
|
91
|
+
so editing one `DynamicForm` field reverted sibling fields changed since
|
|
92
|
+
mount (e.g. typing in a shell `script` field wiped an unsaved `env` value,
|
|
93
|
+
or deleted a sibling automation action added after mount). The change
|
|
94
|
+
handler now routes through a ref to the current `onChange`.
|
|
95
|
+
- Fix: focusing a JSON editor threw "LanguageStatusService.addStatus is not
|
|
96
|
+
supported" because the standalone service set omitted `ILanguageStatusService`.
|
|
97
|
+
That one service is now registered via `serviceOverrides`.
|
|
98
|
+
- Fix: the automation trigger card nested a `<Badge>` (a `<div>`) inside a
|
|
99
|
+
`<p>`, producing a `validateDOMNesting` warning. Switched the wrapper to a
|
|
100
|
+
`<div>`.
|
|
101
|
+
- Local runs (`queue-executor`) and satellite runs both populate the
|
|
102
|
+
context. `SatelliteAssignment` (and the `getAssignmentsForSatellite`
|
|
103
|
+
RPC output) gained optional `configName` / `systemName` so the metadata
|
|
104
|
+
reaches satellite-side execution; `HealthCheckService` resolves the
|
|
105
|
+
system name via the catalog client.
|
|
106
|
+
|
|
107
|
+
BREAKING CHANGE: `createHealthCheckRouter` now requires a `catalogClient`
|
|
108
|
+
option (used to resolve system names for satellite assignments). Update
|
|
109
|
+
call sites to pass the catalog RPC client.
|
|
110
|
+
|
|
111
|
+
### Patch Changes
|
|
112
|
+
|
|
113
|
+
- Updated dependencies [6d52276]
|
|
114
|
+
- Updated dependencies [35bc682]
|
|
115
|
+
- @checkstack/common@0.12.0
|
|
116
|
+
- @checkstack/healthcheck-common@1.3.0
|
|
117
|
+
- @checkstack/signal-common@0.2.5
|
|
118
|
+
|
|
3
119
|
## 0.5.3
|
|
4
120
|
|
|
5
121
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/satellite-common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@checkstack/common": "0.
|
|
13
|
-
"@checkstack/healthcheck-common": "1.
|
|
14
|
-
"@checkstack/signal-common": "0.2.
|
|
12
|
+
"@checkstack/common": "0.12.0",
|
|
13
|
+
"@checkstack/healthcheck-common": "1.3.0",
|
|
14
|
+
"@checkstack/signal-common": "0.2.5",
|
|
15
15
|
"@orpc/contract": "^1.13.14",
|
|
16
16
|
"zod": "^4.2.1"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"typescript": "^5.7.2",
|
|
20
20
|
"@checkstack/tsconfig": "0.0.7",
|
|
21
|
-
"@checkstack/scripts": "0.3.
|
|
21
|
+
"@checkstack/scripts": "0.3.4"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"typecheck": "tsgo -b",
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,14 @@ export {
|
|
|
29
29
|
type AuthFailedMessage,
|
|
30
30
|
type ConfigUpdatedMessage,
|
|
31
31
|
type ShutdownMessage,
|
|
32
|
+
type ScriptPackageSyncStateMessage,
|
|
33
|
+
type RefreshScriptPackagesMessage,
|
|
34
|
+
type ScriptPackageManifestMessage,
|
|
35
|
+
type ScriptPackageBlobMessage,
|
|
36
|
+
type RequestScriptPackageManifestMessage,
|
|
37
|
+
type RequestScriptPackageBlobMessage,
|
|
38
|
+
type RequestRunSecretsMessage,
|
|
39
|
+
type RunSecretsMessage,
|
|
32
40
|
} from "./protocol";
|
|
33
41
|
export {
|
|
34
42
|
SATELLITE_STATUS_CHANGED,
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
SatelliteAssignmentSchema,
|
|
4
|
+
CoreToSatelliteMessageSchema,
|
|
5
|
+
SatelliteToCoreMessageSchema,
|
|
6
|
+
} from "./protocol";
|
|
7
|
+
|
|
8
|
+
describe("SatelliteAssignmentSchema", () => {
|
|
9
|
+
const base = {
|
|
10
|
+
configId: "config-1",
|
|
11
|
+
systemId: "system-1",
|
|
12
|
+
strategyId: "http",
|
|
13
|
+
config: {},
|
|
14
|
+
intervalSeconds: 60,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
test("parses an assignment WITH configName and systemName", () => {
|
|
18
|
+
const parsed = SatelliteAssignmentSchema.parse({
|
|
19
|
+
...base,
|
|
20
|
+
configName: "API health",
|
|
21
|
+
systemName: "Production API",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(parsed.configName).toBe("API health");
|
|
25
|
+
expect(parsed.systemName).toBe("Production API");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("parses an assignment WITHOUT configName and systemName (optional)", () => {
|
|
29
|
+
const parsed = SatelliteAssignmentSchema.parse(base);
|
|
30
|
+
|
|
31
|
+
expect(parsed.configName).toBeUndefined();
|
|
32
|
+
expect(parsed.systemName).toBeUndefined();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("script-packages protocol extensions", () => {
|
|
37
|
+
test("authenticated carries an optional scriptPackagesLockfileHash", () => {
|
|
38
|
+
const withHash = CoreToSatelliteMessageSchema.parse({
|
|
39
|
+
type: "authenticated",
|
|
40
|
+
satelliteId: "sat-1",
|
|
41
|
+
assignments: [],
|
|
42
|
+
scriptPackagesLockfileHash: "abc123",
|
|
43
|
+
});
|
|
44
|
+
expect(withHash.type).toBe("authenticated");
|
|
45
|
+
if (withHash.type === "authenticated") {
|
|
46
|
+
expect(withHash.scriptPackagesLockfileHash).toBe("abc123");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("authenticated WITHOUT the hash still parses (version-skew safe)", () => {
|
|
51
|
+
const parsed = CoreToSatelliteMessageSchema.parse({
|
|
52
|
+
type: "authenticated",
|
|
53
|
+
satelliteId: "sat-1",
|
|
54
|
+
assignments: [],
|
|
55
|
+
});
|
|
56
|
+
expect(parsed.type).toBe("authenticated");
|
|
57
|
+
if (parsed.type === "authenticated") {
|
|
58
|
+
expect(parsed.scriptPackagesLockfileHash).toBeUndefined();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("config_updated carries the optional hash", () => {
|
|
63
|
+
const parsed = CoreToSatelliteMessageSchema.parse({
|
|
64
|
+
type: "config_updated",
|
|
65
|
+
assignments: [],
|
|
66
|
+
scriptPackagesLockfileHash: null,
|
|
67
|
+
});
|
|
68
|
+
if (parsed.type === "config_updated") {
|
|
69
|
+
expect(parsed.scriptPackagesLockfileHash).toBeNull();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("refresh_script_packages round-trips", () => {
|
|
74
|
+
const parsed = CoreToSatelliteMessageSchema.parse({
|
|
75
|
+
type: "refresh_script_packages",
|
|
76
|
+
lockfileHash: "deadbeef",
|
|
77
|
+
});
|
|
78
|
+
expect(parsed.type).toBe("refresh_script_packages");
|
|
79
|
+
if (parsed.type === "refresh_script_packages") {
|
|
80
|
+
expect(parsed.lockfileHash).toBe("deadbeef");
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("script_package_sync_state round-trips (satellite -> core)", () => {
|
|
85
|
+
const parsed = SatelliteToCoreMessageSchema.parse({
|
|
86
|
+
type: "script_package_sync_state",
|
|
87
|
+
lockfileHash: "abc",
|
|
88
|
+
status: "ready",
|
|
89
|
+
});
|
|
90
|
+
expect(parsed.type).toBe("script_package_sync_state");
|
|
91
|
+
if (parsed.type === "script_package_sync_state") {
|
|
92
|
+
expect(parsed.status).toBe("ready");
|
|
93
|
+
expect(parsed.lockfileHash).toBe("abc");
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("script_package_sync_state carries an error", () => {
|
|
98
|
+
const parsed = SatelliteToCoreMessageSchema.parse({
|
|
99
|
+
type: "script_package_sync_state",
|
|
100
|
+
lockfileHash: null,
|
|
101
|
+
status: "error",
|
|
102
|
+
errorMessage: "blob fetch failed",
|
|
103
|
+
});
|
|
104
|
+
if (parsed.type === "script_package_sync_state") {
|
|
105
|
+
expect(parsed.status).toBe("error");
|
|
106
|
+
expect(parsed.errorMessage).toBe("blob fetch failed");
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("run-secrets request/reply (Phase 3 JIT delivery)", () => {
|
|
112
|
+
test("parses request_run_secrets", () => {
|
|
113
|
+
const parsed = SatelliteToCoreMessageSchema.parse({
|
|
114
|
+
type: "request_run_secrets",
|
|
115
|
+
requestId: "req-1",
|
|
116
|
+
configId: "config-1",
|
|
117
|
+
collectorId: "inline-script",
|
|
118
|
+
runId: "run-1",
|
|
119
|
+
});
|
|
120
|
+
expect(parsed.type).toBe("request_run_secrets");
|
|
121
|
+
if (parsed.type === "request_run_secrets") {
|
|
122
|
+
expect(parsed.requestId).toBe("req-1");
|
|
123
|
+
expect(parsed.collectorId).toBe("inline-script");
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("parses run_secrets reply with env", () => {
|
|
128
|
+
const parsed = CoreToSatelliteMessageSchema.parse({
|
|
129
|
+
type: "run_secrets",
|
|
130
|
+
requestId: "req-1",
|
|
131
|
+
env: { API_TOKEN: "resolved-value" },
|
|
132
|
+
});
|
|
133
|
+
if (parsed.type === "run_secrets") {
|
|
134
|
+
expect(parsed.env).toEqual({ API_TOKEN: "resolved-value" });
|
|
135
|
+
expect(parsed.error).toBeUndefined();
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("parses run_secrets reply with error (no env)", () => {
|
|
140
|
+
const parsed = CoreToSatelliteMessageSchema.parse({
|
|
141
|
+
type: "run_secrets",
|
|
142
|
+
requestId: "req-1",
|
|
143
|
+
error: "required secret not available",
|
|
144
|
+
});
|
|
145
|
+
if (parsed.type === "run_secrets") {
|
|
146
|
+
expect(parsed.error).toBe("required secret not available");
|
|
147
|
+
expect(parsed.env).toBeUndefined();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
package/src/protocol.ts
CHANGED
|
@@ -38,6 +38,9 @@ export const SatelliteAssignmentSchema = z.object({
|
|
|
38
38
|
config: z.record(z.string(), z.unknown()),
|
|
39
39
|
collectors: z.array(SatelliteCollectorConfigSchema).optional(),
|
|
40
40
|
intervalSeconds: z.number(),
|
|
41
|
+
/** Curated run-context metadata. Optional for version-skew safety. */
|
|
42
|
+
configName: z.string().optional(),
|
|
43
|
+
systemName: z.string().optional(),
|
|
41
44
|
});
|
|
42
45
|
|
|
43
46
|
export type SatelliteAssignment = z.infer<typeof SatelliteAssignmentSchema>;
|
|
@@ -75,6 +78,64 @@ const StrategyErrorMessageSchema = z.object({
|
|
|
75
78
|
message: z.string(),
|
|
76
79
|
});
|
|
77
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Reports the satellite's script-package reconcile state back to the core,
|
|
83
|
+
* which persists it in `script_package_satellite_state` for the admin UI.
|
|
84
|
+
* Sent after a reconcile attempt (success or failure).
|
|
85
|
+
*/
|
|
86
|
+
const ScriptPackageSyncStateMessageSchema = z.object({
|
|
87
|
+
type: z.literal("script_package_sync_state"),
|
|
88
|
+
/** Active lockfile hash this satellite has materialized, or null. */
|
|
89
|
+
lockfileHash: z.string().nullable(),
|
|
90
|
+
/** "pending" | "syncing" | "ready" | "error" */
|
|
91
|
+
status: z.enum(["pending", "syncing", "ready", "error"]),
|
|
92
|
+
errorMessage: z.string().optional(),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Satellite -> core request for the manifest of a lockfile hash, so the
|
|
97
|
+
* satellite can diff against its local cache. The core replies with a
|
|
98
|
+
* `script_package_manifest` message. Delivered over the existing
|
|
99
|
+
* authenticated WS channel (no separate satellite HTTP auth surface).
|
|
100
|
+
*/
|
|
101
|
+
const RequestScriptPackageManifestMessageSchema = z.object({
|
|
102
|
+
type: z.literal("request_script_package_manifest"),
|
|
103
|
+
lockfileHash: z.string(),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Satellite -> core request for one content-addressed blob by integrity.
|
|
108
|
+
* The core replies with a `script_package_blob` message (base64 bytes).
|
|
109
|
+
*/
|
|
110
|
+
const RequestScriptPackageBlobMessageSchema = z.object({
|
|
111
|
+
type: z.literal("request_script_package_blob"),
|
|
112
|
+
integrity: z.string(),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Satellite -> core just-in-time request for a collector run's resolved
|
|
117
|
+
* secret env, sent right before the satellite executes a collector that
|
|
118
|
+
* declares a `secretEnv` mapping. The core resolves ONLY that collector's
|
|
119
|
+
* declared `secretEnv` (read from the persisted assignment — the satellite
|
|
120
|
+
* does not get to choose which secrets), and replies with a `run_secrets`
|
|
121
|
+
* message carrying the env map (or an error).
|
|
122
|
+
*
|
|
123
|
+
* Secrets NEVER ride the persisted assignment payload; they are delivered
|
|
124
|
+
* over this authenticated channel per-run and held in satellite memory only
|
|
125
|
+
* for the lifetime of the run. `requestId` correlates the reply (a config
|
|
126
|
+
* can run repeatedly; `runId` is for logging/audit).
|
|
127
|
+
*/
|
|
128
|
+
const RequestRunSecretsMessageSchema = z.object({
|
|
129
|
+
type: z.literal("request_run_secrets"),
|
|
130
|
+
/** Correlation id for the reply. */
|
|
131
|
+
requestId: z.string(),
|
|
132
|
+
/** The assignment/collector whose declared secretEnv to resolve. */
|
|
133
|
+
configId: z.string(),
|
|
134
|
+
collectorId: z.string(),
|
|
135
|
+
/** Opaque per-run id for audit/logging on the core side. */
|
|
136
|
+
runId: z.string(),
|
|
137
|
+
});
|
|
138
|
+
|
|
78
139
|
/**
|
|
79
140
|
* Discriminated union of all messages that a satellite can send to the core.
|
|
80
141
|
*/
|
|
@@ -83,6 +144,10 @@ export const SatelliteToCoreMessageSchema = z.discriminatedUnion("type", [
|
|
|
83
144
|
HeartbeatMessageSchema,
|
|
84
145
|
ResultMessageSchema,
|
|
85
146
|
StrategyErrorMessageSchema,
|
|
147
|
+
ScriptPackageSyncStateMessageSchema,
|
|
148
|
+
RequestScriptPackageManifestMessageSchema,
|
|
149
|
+
RequestScriptPackageBlobMessageSchema,
|
|
150
|
+
RequestRunSecretsMessageSchema,
|
|
86
151
|
]);
|
|
87
152
|
|
|
88
153
|
export type SatelliteToCoreMessage = z.infer<
|
|
@@ -94,6 +159,18 @@ export type AuthenticateMessage = z.infer<typeof AuthenticateMessageSchema>;
|
|
|
94
159
|
export type HeartbeatMessage = z.infer<typeof HeartbeatMessageSchema>;
|
|
95
160
|
export type ResultMessage = z.infer<typeof ResultMessageSchema>;
|
|
96
161
|
export type StrategyErrorMessage = z.infer<typeof StrategyErrorMessageSchema>;
|
|
162
|
+
export type ScriptPackageSyncStateMessage = z.infer<
|
|
163
|
+
typeof ScriptPackageSyncStateMessageSchema
|
|
164
|
+
>;
|
|
165
|
+
export type RequestScriptPackageManifestMessage = z.infer<
|
|
166
|
+
typeof RequestScriptPackageManifestMessageSchema
|
|
167
|
+
>;
|
|
168
|
+
export type RequestScriptPackageBlobMessage = z.infer<
|
|
169
|
+
typeof RequestScriptPackageBlobMessageSchema
|
|
170
|
+
>;
|
|
171
|
+
export type RequestRunSecretsMessage = z.infer<
|
|
172
|
+
typeof RequestRunSecretsMessageSchema
|
|
173
|
+
>;
|
|
97
174
|
|
|
98
175
|
// =============================================================================
|
|
99
176
|
// CORE → SATELLITE MESSAGES
|
|
@@ -103,6 +180,13 @@ const AuthenticatedMessageSchema = z.object({
|
|
|
103
180
|
type: z.literal("authenticated"),
|
|
104
181
|
satelliteId: z.string(),
|
|
105
182
|
assignments: z.array(SatelliteAssignmentSchema),
|
|
183
|
+
/**
|
|
184
|
+
* Desired script-package lockfile hash. Carried alongside assignments as
|
|
185
|
+
* the durable convergence backstop: a satellite that booted after (or
|
|
186
|
+
* missed) a `refresh_script_packages` push still converges on connect.
|
|
187
|
+
* Optional for version-skew safety; null means "no packages installed".
|
|
188
|
+
*/
|
|
189
|
+
scriptPackagesLockfileHash: z.string().nullable().optional(),
|
|
106
190
|
});
|
|
107
191
|
|
|
108
192
|
const AuthFailedMessageSchema = z.object({
|
|
@@ -113,6 +197,8 @@ const AuthFailedMessageSchema = z.object({
|
|
|
113
197
|
const ConfigUpdatedMessageSchema = z.object({
|
|
114
198
|
type: z.literal("config_updated"),
|
|
115
199
|
assignments: z.array(SatelliteAssignmentSchema),
|
|
200
|
+
/** See {@link AuthenticatedMessageSchema.scriptPackagesLockfileHash}. */
|
|
201
|
+
scriptPackagesLockfileHash: z.string().nullable().optional(),
|
|
116
202
|
});
|
|
117
203
|
|
|
118
204
|
const ShutdownMessageSchema = z.object({
|
|
@@ -120,6 +206,60 @@ const ShutdownMessageSchema = z.object({
|
|
|
120
206
|
reason: z.string(),
|
|
121
207
|
});
|
|
122
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Control push telling the satellite to reconcile its script packages to a
|
|
211
|
+
* new lockfile hash. Sent by each core instance's `script-packages.changed`
|
|
212
|
+
* broadcast handler to its currently-connected satellites. Best-effort
|
|
213
|
+
* liveness; the assignment-carried `scriptPackagesLockfileHash` is the
|
|
214
|
+
* durable backstop.
|
|
215
|
+
*/
|
|
216
|
+
const RefreshScriptPackagesMessageSchema = z.object({
|
|
217
|
+
type: z.literal("refresh_script_packages"),
|
|
218
|
+
lockfileHash: z.string(),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
/** One resolved package in a manifest reply. */
|
|
222
|
+
const ManifestEntryWireSchema = z.object({
|
|
223
|
+
name: z.string(),
|
|
224
|
+
version: z.string(),
|
|
225
|
+
integrity: z.string(),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
/** Core reply to `request_script_package_manifest`. */
|
|
229
|
+
const ScriptPackageManifestMessageSchema = z.object({
|
|
230
|
+
type: z.literal("script_package_manifest"),
|
|
231
|
+
lockfileHash: z.string(),
|
|
232
|
+
entries: z.array(ManifestEntryWireSchema),
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
/** Core reply to `request_script_package_blob` (base64 compressed bytes). */
|
|
236
|
+
const ScriptPackageBlobMessageSchema = z.object({
|
|
237
|
+
type: z.literal("script_package_blob"),
|
|
238
|
+
integrity: z.string(),
|
|
239
|
+
/** base64-encoded compressed blob bytes, or null if not found. */
|
|
240
|
+
data: z.string().nullable(),
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Core reply to `request_run_secrets`. Carries the resolved env map on
|
|
245
|
+
* success, or an `error` when a required secret could not be resolved /
|
|
246
|
+
* the collector was not found. The satellite injects `env` memory-only for
|
|
247
|
+
* the run and drops it on completion; on `error` it fails the run clearly
|
|
248
|
+
* rather than running without the secret.
|
|
249
|
+
*
|
|
250
|
+
* The env map never persists on the core side and is never written to disk
|
|
251
|
+
* on the satellite.
|
|
252
|
+
*/
|
|
253
|
+
const RunSecretsMessageSchema = z.object({
|
|
254
|
+
type: z.literal("run_secrets"),
|
|
255
|
+
/** Correlates with the originating `request_run_secrets`. */
|
|
256
|
+
requestId: z.string(),
|
|
257
|
+
/** Resolved env, present only on success. */
|
|
258
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
259
|
+
/** Set when resolution failed; `env` is then absent. */
|
|
260
|
+
error: z.string().optional(),
|
|
261
|
+
});
|
|
262
|
+
|
|
123
263
|
/**
|
|
124
264
|
* Discriminated union of all messages that the core can send to a satellite.
|
|
125
265
|
*/
|
|
@@ -128,6 +268,10 @@ export const CoreToSatelliteMessageSchema = z.discriminatedUnion("type", [
|
|
|
128
268
|
AuthFailedMessageSchema,
|
|
129
269
|
ConfigUpdatedMessageSchema,
|
|
130
270
|
ShutdownMessageSchema,
|
|
271
|
+
RefreshScriptPackagesMessageSchema,
|
|
272
|
+
ScriptPackageManifestMessageSchema,
|
|
273
|
+
ScriptPackageBlobMessageSchema,
|
|
274
|
+
RunSecretsMessageSchema,
|
|
131
275
|
]);
|
|
132
276
|
|
|
133
277
|
export type CoreToSatelliteMessage = z.infer<
|
|
@@ -139,3 +283,13 @@ export type AuthenticatedMessage = z.infer<typeof AuthenticatedMessageSchema>;
|
|
|
139
283
|
export type AuthFailedMessage = z.infer<typeof AuthFailedMessageSchema>;
|
|
140
284
|
export type ConfigUpdatedMessage = z.infer<typeof ConfigUpdatedMessageSchema>;
|
|
141
285
|
export type ShutdownMessage = z.infer<typeof ShutdownMessageSchema>;
|
|
286
|
+
export type RefreshScriptPackagesMessage = z.infer<
|
|
287
|
+
typeof RefreshScriptPackagesMessageSchema
|
|
288
|
+
>;
|
|
289
|
+
export type ScriptPackageManifestMessage = z.infer<
|
|
290
|
+
typeof ScriptPackageManifestMessageSchema
|
|
291
|
+
>;
|
|
292
|
+
export type ScriptPackageBlobMessage = z.infer<
|
|
293
|
+
typeof ScriptPackageBlobMessageSchema
|
|
294
|
+
>;
|
|
295
|
+
export type RunSecretsMessage = z.infer<typeof RunSecretsMessageSchema>;
|