@indigoai-us/hq-cloud 6.15.4 → 6.15.6
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/cli/push-scan-exclusions.test.d.ts +2 -0
- package/dist/cli/push-scan-exclusions.test.d.ts.map +1 -0
- package/dist/cli/push-scan-exclusions.test.js +87 -0
- package/dist/cli/push-scan-exclusions.test.js.map +1 -0
- package/dist/cli/rescue-exec-bit-preserve.test.js +8 -0
- package/dist/cli/rescue-exec-bit-preserve.test.js.map +1 -1
- package/dist/cli/share.d.ts.map +1 -1
- package/dist/cli/share.js +21 -1
- package/dist/cli/share.js.map +1 -1
- package/dist/cli/share.test.js +82 -0
- package/dist/cli/share.test.js.map +1 -1
- package/dist/cli/sync.d.ts +23 -0
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +9 -0
- package/dist/cli/sync.js.map +1 -1
- package/dist/lib/net-errors.d.ts.map +1 -1
- package/dist/lib/net-errors.js +4 -0
- package/dist/lib/net-errors.js.map +1 -1
- package/dist/machine-auth.test.js +7 -1
- package/dist/machine-auth.test.js.map +1 -1
- package/dist/object-io.d.ts +21 -0
- package/dist/object-io.d.ts.map +1 -1
- package/dist/object-io.js +229 -77
- package/dist/object-io.js.map +1 -1
- package/dist/object-io.test.js +211 -1
- package/dist/object-io.test.js.map +1 -1
- package/dist/outposts/billing.d.ts +41 -0
- package/dist/outposts/billing.d.ts.map +1 -0
- package/dist/outposts/billing.js +53 -0
- package/dist/outposts/billing.js.map +1 -0
- package/dist/outposts/cli-billing.d.ts +59 -0
- package/dist/outposts/cli-billing.d.ts.map +1 -0
- package/dist/outposts/cli-billing.js +93 -0
- package/dist/outposts/cli-billing.js.map +1 -0
- package/dist/outposts/cli.d.ts +13 -0
- package/dist/outposts/cli.d.ts.map +1 -0
- package/dist/outposts/cli.js +13 -0
- package/dist/outposts/cli.js.map +1 -0
- package/dist/outposts/client.d.ts +140 -0
- package/dist/outposts/client.d.ts.map +1 -0
- package/dist/outposts/client.js +271 -0
- package/dist/outposts/client.js.map +1 -0
- package/dist/outposts/client.test.d.ts +9 -0
- package/dist/outposts/client.test.d.ts.map +1 -0
- package/dist/outposts/client.test.js +226 -0
- package/dist/outposts/client.test.js.map +1 -0
- package/dist/outposts/command.d.ts +74 -0
- package/dist/outposts/command.d.ts.map +1 -0
- package/dist/outposts/command.js +661 -0
- package/dist/outposts/command.js.map +1 -0
- package/dist/outposts/command.test.d.ts +18 -0
- package/dist/outposts/command.test.d.ts.map +1 -0
- package/dist/outposts/command.test.js +933 -0
- package/dist/outposts/command.test.js.map +1 -0
- package/dist/outposts/errors.d.ts +32 -0
- package/dist/outposts/errors.d.ts.map +1 -0
- package/dist/outposts/errors.js +72 -0
- package/dist/outposts/errors.js.map +1 -0
- package/dist/outposts/heartbeat-command.d.ts +106 -0
- package/dist/outposts/heartbeat-command.d.ts.map +1 -0
- package/dist/outposts/heartbeat-command.js +186 -0
- package/dist/outposts/heartbeat-command.js.map +1 -0
- package/dist/outposts/host-deps.d.ts +49 -0
- package/dist/outposts/host-deps.d.ts.map +1 -0
- package/dist/outposts/host-deps.js +93 -0
- package/dist/outposts/host-deps.js.map +1 -0
- package/dist/outposts/index.d.ts +36 -0
- package/dist/outposts/index.d.ts.map +1 -0
- package/dist/outposts/index.js +32 -0
- package/dist/outposts/index.js.map +1 -0
- package/dist/outposts/node.d.ts +23 -0
- package/dist/outposts/node.d.ts.map +1 -0
- package/dist/outposts/node.js +22 -0
- package/dist/outposts/node.js.map +1 -0
- package/dist/outposts/remote-command.d.ts +30 -0
- package/dist/outposts/remote-command.d.ts.map +1 -0
- package/dist/outposts/remote-command.js +39 -0
- package/dist/outposts/remote-command.js.map +1 -0
- package/dist/outposts/replica-sync.d.ts +40 -0
- package/dist/outposts/replica-sync.d.ts.map +1 -0
- package/dist/outposts/replica-sync.js +188 -0
- package/dist/outposts/replica-sync.js.map +1 -0
- package/dist/outposts/replica-sync.test.d.ts +2 -0
- package/dist/outposts/replica-sync.test.d.ts.map +1 -0
- package/dist/outposts/replica-sync.test.js +224 -0
- package/dist/outposts/replica-sync.test.js.map +1 -0
- package/dist/outposts/self-deploy.d.ts +47 -0
- package/dist/outposts/self-deploy.d.ts.map +1 -0
- package/dist/outposts/self-deploy.js +188 -0
- package/dist/outposts/self-deploy.js.map +1 -0
- package/dist/outposts/self-deploy.test.d.ts +2 -0
- package/dist/outposts/self-deploy.test.d.ts.map +1 -0
- package/dist/outposts/self-deploy.test.js +186 -0
- package/dist/outposts/self-deploy.test.js.map +1 -0
- package/dist/outposts/session-heartbeat-bounds.test.d.ts +25 -0
- package/dist/outposts/session-heartbeat-bounds.test.d.ts.map +1 -0
- package/dist/outposts/session-heartbeat-bounds.test.js +156 -0
- package/dist/outposts/session-heartbeat-bounds.test.js.map +1 -0
- package/dist/outposts/session-heartbeat-guard.test.d.ts +16 -0
- package/dist/outposts/session-heartbeat-guard.test.d.ts.map +1 -0
- package/dist/outposts/session-heartbeat-guard.test.js +88 -0
- package/dist/outposts/session-heartbeat-guard.test.js.map +1 -0
- package/dist/outposts/session-heartbeat-publisher.d.ts +76 -0
- package/dist/outposts/session-heartbeat-publisher.d.ts.map +1 -0
- package/dist/outposts/session-heartbeat-publisher.js +117 -0
- package/dist/outposts/session-heartbeat-publisher.js.map +1 -0
- package/dist/outposts/session-heartbeat-publisher.test.d.ts +10 -0
- package/dist/outposts/session-heartbeat-publisher.test.d.ts.map +1 -0
- package/dist/outposts/session-heartbeat-publisher.test.js +153 -0
- package/dist/outposts/session-heartbeat-publisher.test.js.map +1 -0
- package/dist/outposts/session-heartbeat-retain-guard.test.d.ts +18 -0
- package/dist/outposts/session-heartbeat-retain-guard.test.d.ts.map +1 -0
- package/dist/outposts/session-heartbeat-retain-guard.test.js +106 -0
- package/dist/outposts/session-heartbeat-retain-guard.test.js.map +1 -0
- package/dist/outposts/session-heartbeat.d.ts +210 -0
- package/dist/outposts/session-heartbeat.d.ts.map +1 -0
- package/dist/outposts/session-heartbeat.js +657 -0
- package/dist/outposts/session-heartbeat.js.map +1 -0
- package/dist/outposts/session-heartbeat.test.d.ts +11 -0
- package/dist/outposts/session-heartbeat.test.d.ts.map +1 -0
- package/dist/outposts/session-heartbeat.test.js +370 -0
- package/dist/outposts/session-heartbeat.test.js.map +1 -0
- package/dist/outposts/ssh.d.ts +29 -0
- package/dist/outposts/ssh.d.ts.map +1 -0
- package/dist/outposts/ssh.js +66 -0
- package/dist/outposts/ssh.js.map +1 -0
- package/dist/outposts/transport.d.ts +76 -0
- package/dist/outposts/transport.d.ts.map +1 -0
- package/dist/outposts/transport.js +91 -0
- package/dist/outposts/transport.js.map +1 -0
- package/dist/outposts/transport.test.d.ts +10 -0
- package/dist/outposts/transport.test.d.ts.map +1 -0
- package/dist/outposts/transport.test.js +116 -0
- package/dist/outposts/transport.test.js.map +1 -0
- package/dist/outposts/types.d.ts +125 -0
- package/dist/outposts/types.d.ts.map +1 -0
- package/dist/outposts/types.js +13 -0
- package/dist/outposts/types.js.map +1 -0
- package/dist/personal-vault.d.ts +69 -0
- package/dist/personal-vault.d.ts.map +1 -1
- package/dist/personal-vault.js +100 -0
- package/dist/personal-vault.js.map +1 -1
- package/dist/personal-vault.test.js +140 -1
- package/dist/personal-vault.test.js.map +1 -1
- package/dist/s3.d.ts.map +1 -1
- package/dist/s3.js +62 -0
- package/dist/s3.js.map +1 -1
- package/dist/s3.test.js +126 -0
- package/dist/s3.test.js.map +1 -1
- package/package.json +39 -3
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `OutpostsClient` — typed client for the hq-pro `/outpost/*` control plane.
|
|
3
|
+
*
|
|
4
|
+
* These are the same routes hq-console's outpost panel calls and the same ones
|
|
5
|
+
* `hq outposts` drives, so this class is the single implementation of the wire
|
|
6
|
+
* contract for every first-party surface.
|
|
7
|
+
*
|
|
8
|
+
* Portable: the only things it touches are its injected transport, its injected
|
|
9
|
+
* token source, and `setTimeout`. No Node built-ins, no filesystem, no
|
|
10
|
+
* `process.exit`, no module-level side effects — safe to import from a Next.js
|
|
11
|
+
* server action, a route handler, or an edge function.
|
|
12
|
+
*
|
|
13
|
+
* Outposts are PERSONAL / caller-scoped: hq-pro keys every route on the caller's
|
|
14
|
+
* Cognito sub, so no method takes a company. `outpostId` selects a specific box;
|
|
15
|
+
* omitting it targets the caller's primary slot.
|
|
16
|
+
*
|
|
17
|
+
* Every non-2xx throws {@link OutpostHttpError} — nothing is swallowed, and the
|
|
18
|
+
* server's `step` is preserved so callers can distinguish a retryable
|
|
19
|
+
* `teardown-incomplete` from a real failure.
|
|
20
|
+
*/
|
|
21
|
+
import { OutpostHttpError, parseBillingPayload, parseCappedPayload } from "./errors.js";
|
|
22
|
+
const EXEC_RESULT_INITIAL_POLL_MS = 500;
|
|
23
|
+
const EXEC_RESULT_MAX_POLL_MS = 5_000;
|
|
24
|
+
/** The widest AWS-RunShellScript `executionTimeout`, in seconds (48h). */
|
|
25
|
+
export const EXEC_MAX_TIMEOUT_SECONDS = 172_800;
|
|
26
|
+
function sleep(ms, signal) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
if (signal?.aborted) {
|
|
29
|
+
reject(signal.reason ?? new Error("Aborted"));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const timer = setTimeout(() => {
|
|
33
|
+
signal?.removeEventListener("abort", onAbort);
|
|
34
|
+
resolve();
|
|
35
|
+
}, ms);
|
|
36
|
+
// Do NOT unref this timer. The backoff IS the work while `waitForExecResult`
|
|
37
|
+
// polls: an unresolved promise alone does not keep Node's event loop alive,
|
|
38
|
+
// so unref-ing here lets `hq outposts exec --async` / `exec-result --wait`
|
|
39
|
+
// exit before the next poll ever fires — printing nothing for a command that
|
|
40
|
+
// is still running.
|
|
41
|
+
function onAbort() {
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
reject(signal?.reason ?? new Error("Aborted"));
|
|
44
|
+
}
|
|
45
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export class OutpostsClient {
|
|
49
|
+
transport;
|
|
50
|
+
tokenSource;
|
|
51
|
+
baseUrl;
|
|
52
|
+
constructor(options) {
|
|
53
|
+
this.transport = options.transport;
|
|
54
|
+
this.tokenSource = options.token;
|
|
55
|
+
this.baseUrl = options.baseUrl;
|
|
56
|
+
}
|
|
57
|
+
/** Resolve the bearer token for one request. */
|
|
58
|
+
async token() {
|
|
59
|
+
return typeof this.tokenSource === "function"
|
|
60
|
+
? this.tokenSource()
|
|
61
|
+
: this.tokenSource;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Authenticated JSON round-trip. Throws {@link OutpostHttpError} on any
|
|
65
|
+
* non-2xx, decoding hq-pro's `{ error | message, step }` envelope for the
|
|
66
|
+
* reason plus the two structural envelopes (`billing`, `capped`) that carry no
|
|
67
|
+
* message at all.
|
|
68
|
+
*/
|
|
69
|
+
async request(options) {
|
|
70
|
+
const res = await this.transport({
|
|
71
|
+
...options,
|
|
72
|
+
token: await this.token(),
|
|
73
|
+
...(this.baseUrl ? { baseUrl: this.baseUrl } : {}),
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
const body = (await res.json().catch(() => ({})));
|
|
77
|
+
const message = typeof body.message === "string"
|
|
78
|
+
? body.message
|
|
79
|
+
: typeof body.error === "string"
|
|
80
|
+
? body.error
|
|
81
|
+
: res.statusText;
|
|
82
|
+
throw new OutpostHttpError(res.status, message, body.step, parseBillingPayload(body), parseCappedPayload(body));
|
|
83
|
+
}
|
|
84
|
+
return (await res.json());
|
|
85
|
+
}
|
|
86
|
+
// -- Lifecycle ------------------------------------------------------------
|
|
87
|
+
/**
|
|
88
|
+
* Provision the caller's Outpost.
|
|
89
|
+
*
|
|
90
|
+
* `refreshToken` lets the box authenticate AS the caller — the same body
|
|
91
|
+
* hq-console's `provisionMyOutpost` sends. It travels over HTTPS and is never
|
|
92
|
+
* logged.
|
|
93
|
+
*
|
|
94
|
+
* No duplicate is ever created: a caller already at their per-person cap gets a
|
|
95
|
+
* `409` whose body lists their existing boxes, surfaced here as an
|
|
96
|
+
* `OutpostHttpError` carrying `capped`. hq-pro checks the cap BEFORE activation
|
|
97
|
+
* billing, so a capped call is never charged.
|
|
98
|
+
*
|
|
99
|
+
* A payer with no usable card gets a `402` carrying `billing`.
|
|
100
|
+
*/
|
|
101
|
+
async provision(input) {
|
|
102
|
+
return this.request({
|
|
103
|
+
path: "/outpost/provision",
|
|
104
|
+
method: "POST",
|
|
105
|
+
body: {
|
|
106
|
+
refreshToken: input.refreshToken,
|
|
107
|
+
...(input.clientIp ? { clientIp: input.clientIp } : {}),
|
|
108
|
+
...(input.diskSizeGb ? { diskSizeGb: input.diskSizeGb } : {}),
|
|
109
|
+
...(input.agentRuntime ? { agentRuntime: input.agentRuntime } : {}),
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Every Outpost the caller owns. */
|
|
114
|
+
async list() {
|
|
115
|
+
const data = await this.request({
|
|
116
|
+
path: "/outpost/list",
|
|
117
|
+
});
|
|
118
|
+
return data.outposts ?? [];
|
|
119
|
+
}
|
|
120
|
+
/** Live detail for one box. */
|
|
121
|
+
async status(outpostId) {
|
|
122
|
+
return this.request({
|
|
123
|
+
path: "/outpost/status",
|
|
124
|
+
query: outpostId ? { outpostId } : undefined,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** Enable (or retry) Codex on a box. */
|
|
128
|
+
async enableCodex(outpostId) {
|
|
129
|
+
return this.request({
|
|
130
|
+
path: "/outpost/codex/enable",
|
|
131
|
+
method: "POST",
|
|
132
|
+
query: outpostId ? { outpostId } : undefined,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/** Ask the box to mint a fresh Claude login URL. */
|
|
136
|
+
async regenerateLoginUrl(outpostId) {
|
|
137
|
+
return this.request({
|
|
138
|
+
path: "/outpost/regenerate-login-url",
|
|
139
|
+
method: "POST",
|
|
140
|
+
query: outpostId ? { outpostId } : undefined,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Hand the box the one-time Claude sign-in code from the login URL. hq-pro
|
|
145
|
+
* stores it as the row's pending code; the box polls for it, feeds it to
|
|
146
|
+
* `claude`, and flips itself `awaiting-claude-login → ready`.
|
|
147
|
+
*/
|
|
148
|
+
async submitLoginCode(code, outpostId) {
|
|
149
|
+
return this.request({
|
|
150
|
+
path: "/outpost/login-code",
|
|
151
|
+
method: "POST",
|
|
152
|
+
body: { code },
|
|
153
|
+
query: outpostId ? { outpostId } : undefined,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Permanently destroy a box and its cloud resources.
|
|
158
|
+
*
|
|
159
|
+
* Idempotent: a `409` / `step: "teardown-incomplete"` means the gateway's
|
|
160
|
+
* timeout fired while the Lambda kept working. The row is preserved — re-issue
|
|
161
|
+
* the same call to finish.
|
|
162
|
+
*/
|
|
163
|
+
async destroy(outpostId) {
|
|
164
|
+
return this.request({
|
|
165
|
+
path: "/outpost/destroy",
|
|
166
|
+
method: "POST",
|
|
167
|
+
query: outpostId ? { outpostId } : undefined,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// -- Exec -----------------------------------------------------------------
|
|
171
|
+
/**
|
|
172
|
+
* Run a one-shot shell command via server-brokered SSM (no SSH). Synchronous,
|
|
173
|
+
* so it is bounded by the API gateway's ~20s cap — use the submit/result pair
|
|
174
|
+
* for anything longer.
|
|
175
|
+
*
|
|
176
|
+
* A `step: "platform-unsupported"` error means the box is Lightsail and has no
|
|
177
|
+
* SSM agent; fall back to SSH via {@link sshAccess}.
|
|
178
|
+
*/
|
|
179
|
+
async exec(command, outpostId) {
|
|
180
|
+
return this.request({
|
|
181
|
+
path: "/outpost/exec",
|
|
182
|
+
method: "POST",
|
|
183
|
+
body: { command },
|
|
184
|
+
query: outpostId ? { outpostId } : undefined,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/** Presign an input upload for an asynchronous command. */
|
|
188
|
+
async stageExecInput(outpostId) {
|
|
189
|
+
return this.request({
|
|
190
|
+
path: "/outpost/exec",
|
|
191
|
+
method: "POST",
|
|
192
|
+
body: { mode: "stage" },
|
|
193
|
+
query: outpostId ? { outpostId } : undefined,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/** Submit an asynchronous command; returns as soon as SSM accepts it. */
|
|
197
|
+
async submitExec(command, outpostId, timeoutSeconds) {
|
|
198
|
+
return this.request({
|
|
199
|
+
path: "/outpost/exec",
|
|
200
|
+
method: "POST",
|
|
201
|
+
body: {
|
|
202
|
+
mode: "submit",
|
|
203
|
+
command,
|
|
204
|
+
...(timeoutSeconds !== undefined ? { timeoutSeconds } : {}),
|
|
205
|
+
},
|
|
206
|
+
query: outpostId ? { outpostId } : undefined,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Poll an asynchronous command once. Streams arrive only once `done`.
|
|
211
|
+
*
|
|
212
|
+
* `signal` aborts the in-flight request itself — not just the caller's wait —
|
|
213
|
+
* so a slow or hung poll is cancelled rather than left pending.
|
|
214
|
+
*/
|
|
215
|
+
async fetchExecResult(commandId, outpostId, signal) {
|
|
216
|
+
return this.request({
|
|
217
|
+
path: "/outpost/exec",
|
|
218
|
+
method: "POST",
|
|
219
|
+
body: { mode: "result", commandId },
|
|
220
|
+
query: outpostId ? { outpostId } : undefined,
|
|
221
|
+
...(signal ? { signal } : {}),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Poll until an asynchronous command reaches a terminal state, backing off
|
|
226
|
+
* exponentially.
|
|
227
|
+
*
|
|
228
|
+
* A `429` is treated as back-pressure and retried — the command is still
|
|
229
|
+
* running, and giving up on a rate limit would strand a job that is fine. Any
|
|
230
|
+
* other error propagates.
|
|
231
|
+
*/
|
|
232
|
+
async waitForExecResult(commandId, outpostId, options = {}) {
|
|
233
|
+
const maxPollMs = options.maxPollMs ?? EXEC_RESULT_MAX_POLL_MS;
|
|
234
|
+
let delayMs = options.initialPollMs ?? EXEC_RESULT_INITIAL_POLL_MS;
|
|
235
|
+
for (;;) {
|
|
236
|
+
// Abort BEFORE issuing another poll — a signal that fired during the last
|
|
237
|
+
// backoff must not start a fresh request.
|
|
238
|
+
if (options.signal?.aborted) {
|
|
239
|
+
throw options.signal.reason ?? new Error("Aborted");
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
const result = await this.fetchExecResult(commandId, outpostId, options.signal);
|
|
243
|
+
if (result.done)
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
if (!(err instanceof OutpostHttpError) || err.status !== 429)
|
|
248
|
+
throw err;
|
|
249
|
+
}
|
|
250
|
+
await sleep(delayMs, options.signal);
|
|
251
|
+
delayMs = Math.min(delayMs * 2, maxPollMs);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// -- SSH ------------------------------------------------------------------
|
|
255
|
+
/**
|
|
256
|
+
* Fetch SSH connection info + key for a box and open the caller's IP on its SSH
|
|
257
|
+
* port. The route exists to reach a Lightsail box, which has no SSM agent.
|
|
258
|
+
*
|
|
259
|
+
* The result carries a PEM private key. Treat it as a credential: never log it,
|
|
260
|
+
* never return it to a browser, and write it only to a mode-0600 file.
|
|
261
|
+
*/
|
|
262
|
+
async sshAccess(outpostId) {
|
|
263
|
+
return this.request({
|
|
264
|
+
path: "/outpost/ssh-access",
|
|
265
|
+
method: "POST",
|
|
266
|
+
body: {},
|
|
267
|
+
query: outpostId ? { outpostId } : undefined,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/outposts/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for OutpostsClient against a stub transport.
|
|
3
|
+
*
|
|
4
|
+
* The command-tree tests cover the wire shapes end-to-end; these focus on the
|
|
5
|
+
* client's own logic: error decoding for all three envelopes, the token-source
|
|
6
|
+
* resolution contract, and the exec-result polling/backoff.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=client.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../src/outposts/client.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for OutpostsClient against a stub transport.
|
|
3
|
+
*
|
|
4
|
+
* The command-tree tests cover the wire shapes end-to-end; these focus on the
|
|
5
|
+
* client's own logic: error decoding for all three envelopes, the token-source
|
|
6
|
+
* resolution contract, and the exec-result polling/backoff.
|
|
7
|
+
*/
|
|
8
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
9
|
+
import { OutpostsClient } from "./client.js";
|
|
10
|
+
import { OutpostHttpError } from "./errors.js";
|
|
11
|
+
function jsonResponse(status, body, statusText) {
|
|
12
|
+
return new Response(JSON.stringify(body), {
|
|
13
|
+
status,
|
|
14
|
+
...(statusText ? { statusText } : {}),
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** A transport that returns queued responses in order and records requests. */
|
|
19
|
+
function stubTransport(responses) {
|
|
20
|
+
const requests = [];
|
|
21
|
+
let i = 0;
|
|
22
|
+
const transport = async (req) => {
|
|
23
|
+
requests.push(req);
|
|
24
|
+
const res = responses[i++];
|
|
25
|
+
if (!res)
|
|
26
|
+
throw new Error("stub transport exhausted");
|
|
27
|
+
return res;
|
|
28
|
+
};
|
|
29
|
+
return { transport, requests };
|
|
30
|
+
}
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
vi.restoreAllMocks();
|
|
33
|
+
});
|
|
34
|
+
describe("token resolution", () => {
|
|
35
|
+
it("accepts a static string", async () => {
|
|
36
|
+
const { transport, requests } = stubTransport([
|
|
37
|
+
jsonResponse(200, { outposts: [] }),
|
|
38
|
+
]);
|
|
39
|
+
const client = new OutpostsClient({ transport, token: "static" });
|
|
40
|
+
await client.list();
|
|
41
|
+
expect(requests[0].token).toBe("static");
|
|
42
|
+
});
|
|
43
|
+
it("calls a resolver per request", async () => {
|
|
44
|
+
const { transport, requests } = stubTransport([
|
|
45
|
+
jsonResponse(200, { outposts: [] }),
|
|
46
|
+
jsonResponse(200, { outposts: [] }),
|
|
47
|
+
]);
|
|
48
|
+
let n = 0;
|
|
49
|
+
const client = new OutpostsClient({
|
|
50
|
+
transport,
|
|
51
|
+
token: async () => `t-${++n}`,
|
|
52
|
+
});
|
|
53
|
+
await client.list();
|
|
54
|
+
await client.list();
|
|
55
|
+
expect(requests.map((r) => r.token)).toEqual(["t-1", "t-2"]);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("error decoding", () => {
|
|
59
|
+
it("uses message, then error, then statusText", async () => {
|
|
60
|
+
for (const [body, expected] of [
|
|
61
|
+
[{ message: "m", error: "e" }, "m"],
|
|
62
|
+
[{ error: "e" }, "e"],
|
|
63
|
+
// Neither field present → fall back to the response's statusText.
|
|
64
|
+
[{}, "Bad Request"],
|
|
65
|
+
]) {
|
|
66
|
+
const { transport } = stubTransport([jsonResponse(400, body, "Bad Request")]);
|
|
67
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
68
|
+
// `message` is non-enumerable on Error, so toMatchObject can't see it —
|
|
69
|
+
// assert it explicitly.
|
|
70
|
+
const err = await client
|
|
71
|
+
.status()
|
|
72
|
+
.then(() => undefined)
|
|
73
|
+
.catch((e) => e);
|
|
74
|
+
expect(err).toBeInstanceOf(OutpostHttpError);
|
|
75
|
+
expect(err?.message).toBe(expected);
|
|
76
|
+
expect(err?.status).toBe(400);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
it("preserves the server step", async () => {
|
|
80
|
+
const { transport } = stubTransport([
|
|
81
|
+
jsonResponse(409, { error: true, step: "teardown-incomplete" }),
|
|
82
|
+
]);
|
|
83
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
84
|
+
await expect(client.destroy()).rejects.toMatchObject({
|
|
85
|
+
step: "teardown-incomplete",
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it("decodes the per-person cap envelope with no message field", async () => {
|
|
89
|
+
const { transport } = stubTransport([
|
|
90
|
+
jsonResponse(409, {
|
|
91
|
+
capped: true,
|
|
92
|
+
limit: 1,
|
|
93
|
+
outposts: [{ outpostId: "primary" }],
|
|
94
|
+
}),
|
|
95
|
+
]);
|
|
96
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
97
|
+
const err = await client
|
|
98
|
+
.provision({ refreshToken: "rt" })
|
|
99
|
+
.then(() => undefined)
|
|
100
|
+
.catch((e) => e);
|
|
101
|
+
expect(err).toBeInstanceOf(OutpostHttpError);
|
|
102
|
+
expect(err?.capped?.limit).toBe(1);
|
|
103
|
+
expect(err?.capped?.outposts[0].outpostId).toBe("primary");
|
|
104
|
+
});
|
|
105
|
+
it("decodes the 402 billing envelope", async () => {
|
|
106
|
+
const { transport } = stubTransport([
|
|
107
|
+
jsonResponse(402, {
|
|
108
|
+
error: "payment required",
|
|
109
|
+
billing: {
|
|
110
|
+
status: "payment_failed",
|
|
111
|
+
setup: {
|
|
112
|
+
payerType: "person",
|
|
113
|
+
path: "/v1/billing/checkout/person",
|
|
114
|
+
method: "POST",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
]);
|
|
119
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
120
|
+
const err = await client
|
|
121
|
+
.provision({ refreshToken: "rt" })
|
|
122
|
+
.then(() => undefined)
|
|
123
|
+
.catch((e) => e);
|
|
124
|
+
expect(err?.billing?.status).toBe("payment_failed");
|
|
125
|
+
expect(err?.billing?.setup?.path).toBe("/v1/billing/checkout/person");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe("provision body", () => {
|
|
129
|
+
it("only includes optional fields when provided", async () => {
|
|
130
|
+
const { transport, requests } = stubTransport([
|
|
131
|
+
jsonResponse(200, { ok: true }),
|
|
132
|
+
]);
|
|
133
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
134
|
+
await client.provision({ refreshToken: "rt", agentRuntime: "codex" });
|
|
135
|
+
expect(requests[0].body).toEqual({
|
|
136
|
+
refreshToken: "rt",
|
|
137
|
+
agentRuntime: "codex",
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe("waitForExecResult", () => {
|
|
142
|
+
it("retries a 429 then returns the terminal result", async () => {
|
|
143
|
+
vi.useFakeTimers();
|
|
144
|
+
try {
|
|
145
|
+
const { transport } = stubTransport([
|
|
146
|
+
jsonResponse(429, { error: true, message: "slow down" }),
|
|
147
|
+
jsonResponse(200, { ok: true, status: "InProgress", done: false }),
|
|
148
|
+
jsonResponse(200, {
|
|
149
|
+
ok: true,
|
|
150
|
+
status: "Success",
|
|
151
|
+
done: true,
|
|
152
|
+
exitCode: 0,
|
|
153
|
+
}),
|
|
154
|
+
]);
|
|
155
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
156
|
+
const pending = client.waitForExecResult("cmd-1");
|
|
157
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
158
|
+
await vi.advanceTimersByTimeAsync(1_000);
|
|
159
|
+
const result = await pending;
|
|
160
|
+
expect(result.done).toBe(true);
|
|
161
|
+
expect(result.exitCode).toBe(0);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
vi.useRealTimers();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
it("propagates a non-429 error instead of polling forever", async () => {
|
|
168
|
+
const { transport } = stubTransport([
|
|
169
|
+
jsonResponse(500, { error: "boom" }),
|
|
170
|
+
]);
|
|
171
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
172
|
+
await expect(client.waitForExecResult("cmd-1")).rejects.toMatchObject({
|
|
173
|
+
status: 500,
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
it("forwards the abort signal to the in-flight poll request", async () => {
|
|
177
|
+
const { transport, requests } = stubTransport([
|
|
178
|
+
jsonResponse(200, { ok: true, status: "InProgress", done: false }),
|
|
179
|
+
]);
|
|
180
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
181
|
+
const controller = new AbortController();
|
|
182
|
+
// Kick off a wait; the first poll must carry the signal so a hung request is
|
|
183
|
+
// itself cancellable, not just the backoff between polls.
|
|
184
|
+
const pending = client
|
|
185
|
+
.waitForExecResult("cmd-1", undefined, { signal: controller.signal })
|
|
186
|
+
.catch(() => undefined);
|
|
187
|
+
// Let the first fetchExecResult run.
|
|
188
|
+
await Promise.resolve();
|
|
189
|
+
expect(requests[0].signal).toBe(controller.signal);
|
|
190
|
+
controller.abort();
|
|
191
|
+
await pending;
|
|
192
|
+
});
|
|
193
|
+
it("does not start a new poll once already aborted", async () => {
|
|
194
|
+
const { transport, requests } = stubTransport([
|
|
195
|
+
jsonResponse(200, { ok: true, status: "InProgress", done: false }),
|
|
196
|
+
]);
|
|
197
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
198
|
+
const controller = new AbortController();
|
|
199
|
+
controller.abort();
|
|
200
|
+
await expect(client.waitForExecResult("cmd-1", undefined, { signal: controller.signal })).rejects.toThrow();
|
|
201
|
+
// Aborted before entry — no request should have been issued at all.
|
|
202
|
+
expect(requests).toHaveLength(0);
|
|
203
|
+
});
|
|
204
|
+
it("aborts the wait when signalled", async () => {
|
|
205
|
+
vi.useFakeTimers();
|
|
206
|
+
try {
|
|
207
|
+
const { transport } = stubTransport([
|
|
208
|
+
jsonResponse(200, { ok: true, status: "InProgress", done: false }),
|
|
209
|
+
jsonResponse(200, { ok: true, status: "InProgress", done: false }),
|
|
210
|
+
]);
|
|
211
|
+
const client = new OutpostsClient({ transport, token: "t" });
|
|
212
|
+
const controller = new AbortController();
|
|
213
|
+
const pending = client.waitForExecResult("cmd-1", undefined, {
|
|
214
|
+
signal: controller.signal,
|
|
215
|
+
});
|
|
216
|
+
const assertion = expect(pending).rejects.toThrow();
|
|
217
|
+
controller.abort();
|
|
218
|
+
await vi.advanceTimersByTimeAsync(1_000);
|
|
219
|
+
await assertion;
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
vi.useRealTimers();
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/outposts/client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hq outposts` — the full command tree for managing personal HQ Outposts from a
|
|
3
|
+
* terminal instead of the web console.
|
|
4
|
+
*
|
|
5
|
+
* Targets the hq-pro `/outpost/*` control plane — the same routes the console's
|
|
6
|
+
* outpost panel calls — through an injected transport, so the host CLI keeps
|
|
7
|
+
* ownership of auth, telemetry, and error decoration while the command surface
|
|
8
|
+
* itself lives here and is shared by every consumer.
|
|
9
|
+
*
|
|
10
|
+
* Outposts are PERSONAL / caller-scoped: hq-pro keys every `/outpost/*` route on
|
|
11
|
+
* the caller's Cognito sub, so there is no `--company`. `--id <outpostId>` selects
|
|
12
|
+
* a specific box; when omitted hq-pro targets the caller's primary slot.
|
|
13
|
+
*
|
|
14
|
+
* Subcommands:
|
|
15
|
+
* outposts provision — provision a box (paid; requires --yes)
|
|
16
|
+
* outposts list — every Outpost you own (row summaries)
|
|
17
|
+
* outposts status [--id] — live detail for one box
|
|
18
|
+
* outposts exec <command...> — run a command on the box (sync/async/detach)
|
|
19
|
+
* outposts exec-stage — presign an input upload for an async command
|
|
20
|
+
* outposts exec-submit <cmd...> — fire-and-forget async submit
|
|
21
|
+
* outposts exec-result — poll an async command
|
|
22
|
+
* outposts codex-enable [--id] — enable / retry Codex on the box
|
|
23
|
+
* outposts login [--id] — request a fresh login URL
|
|
24
|
+
* outposts login-code <code> — hand the box its Claude sign-in code
|
|
25
|
+
* outposts destroy [--id] --yes — tear the box down (destructive; flag-guarded)
|
|
26
|
+
* outposts heartbeat — hidden; box-side systemd loop
|
|
27
|
+
* outposts self-deploy — hidden; make THIS host an unmanaged outpost
|
|
28
|
+
* outposts replica-sync — hidden; box-side full-replica timer target
|
|
29
|
+
*
|
|
30
|
+
* NOTE: hq-pro exposes no rename or settings-mutation route for Outposts (the web
|
|
31
|
+
* console can't rename them either), so this wraps only the lifecycle and status
|
|
32
|
+
* routes that exist. Renaming an Outpost is not a backend capability.
|
|
33
|
+
*/
|
|
34
|
+
import { Command } from "commander";
|
|
35
|
+
import { type OutpostTokenSource } from "./client.js";
|
|
36
|
+
import { type ReplicaSyncDependencies } from "./host-deps.js";
|
|
37
|
+
import type { OutpostTransport } from "./transport.js";
|
|
38
|
+
/**
|
|
39
|
+
* What the command tree needs from its host CLI.
|
|
40
|
+
*
|
|
41
|
+
* The transport is the load-bearing one: hq-cli passes its own `vaultApiFetch`, so
|
|
42
|
+
* Sentry breadcrumbs, the `hqk_` API-key path-rewrite table, plan-gate decoding,
|
|
43
|
+
* and plan-limit peeking all keep working exactly as they did when this code lived
|
|
44
|
+
* in the CLI.
|
|
45
|
+
*/
|
|
46
|
+
export interface OutpostsCommandDeps {
|
|
47
|
+
/** HTTP seam for every control-plane call. */
|
|
48
|
+
transport: OutpostTransport;
|
|
49
|
+
/** Resolve a bearer token for an interactive command. */
|
|
50
|
+
getToken: OutpostTokenSource;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a bearer token without prompting. Used by the box-side heartbeat,
|
|
53
|
+
* which runs under systemd where there is nobody to prompt. Falls back to
|
|
54
|
+
* `getToken`.
|
|
55
|
+
*/
|
|
56
|
+
getTokenNonInteractive?: () => Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* Read the cached Cognito session. `provision` sends the refresh token so the
|
|
59
|
+
* box can authenticate AS the caller.
|
|
60
|
+
*/
|
|
61
|
+
loadCachedTokens: () => {
|
|
62
|
+
refreshToken?: string;
|
|
63
|
+
} | undefined;
|
|
64
|
+
/** Resolve the caller's canonical `prs_*` uid (heartbeat identity). */
|
|
65
|
+
resolveCallerPersonUid: (token: string, apiBaseUrl?: string) => Promise<string>;
|
|
66
|
+
/** Control-plane origin for the heartbeat's realtime credential fetch. */
|
|
67
|
+
defaultApiBaseUrl: string;
|
|
68
|
+
/** Origin override applied to every control-plane call. */
|
|
69
|
+
baseUrl?: string;
|
|
70
|
+
/** Override host-environment probes — used by `self-deploy`/`replica-sync` tests. */
|
|
71
|
+
host?: Partial<ReplicaSyncDependencies>;
|
|
72
|
+
}
|
|
73
|
+
export declare function registerOutpostsCommand(program: Command, deps: OutpostsCommandDeps): void;
|
|
74
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/outposts/command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,gBAAgB,CAAC;AAKxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,yDAAyD;IACzD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C;;;OAGG;IACH,gBAAgB,EAAE,MAAM;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAC9D,uEAAuE;IACvE,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChF,0EAA0E;IAC1E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACzC;AAqFD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,mBAAmB,GACxB,IAAI,CAgvBN"}
|