@usine/executor 0.2.1 → 0.4.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/LICENSE +661 -21
- package/README.md +212 -37
- package/dist/child-command.d.ts +5 -8
- package/dist/child-command.d.ts.map +1 -1
- package/dist/child-command.js +10 -14
- package/dist/child-command.js.map +1 -1
- package/dist/child-environment.d.ts +19 -0
- package/dist/child-environment.d.ts.map +1 -0
- package/dist/child-environment.js +18 -0
- package/dist/child-environment.js.map +1 -0
- package/dist/claude-login-lock.d.ts +9 -0
- package/dist/claude-login-lock.d.ts.map +1 -0
- package/dist/claude-login-lock.js +15 -0
- package/dist/claude-login-lock.js.map +1 -0
- package/dist/cloudflare/client.d.ts +50 -0
- package/dist/cloudflare/client.d.ts.map +1 -0
- package/dist/cloudflare/client.js +108 -0
- package/dist/cloudflare/client.js.map +1 -0
- package/dist/cloudflare/cloudflare.d.ts +17 -0
- package/dist/cloudflare/cloudflare.d.ts.map +1 -0
- package/dist/cloudflare/cloudflare.js +704 -0
- package/dist/cloudflare/cloudflare.js.map +1 -0
- package/dist/cloudflare/model.d.ts +42 -0
- package/dist/cloudflare/model.d.ts.map +1 -0
- package/dist/cloudflare/model.js +2 -0
- package/dist/cloudflare/model.js.map +1 -0
- package/dist/cloudflare/shell/environment.d.ts +12 -0
- package/dist/cloudflare/shell/environment.d.ts.map +1 -0
- package/dist/cloudflare/shell/environment.js +12 -0
- package/dist/cloudflare/shell/environment.js.map +1 -0
- package/dist/cloudflare/shell/shell.d.ts +2 -0
- package/dist/cloudflare/shell/shell.d.ts.map +1 -0
- package/dist/cloudflare/shell/shell.js +155 -0
- package/dist/cloudflare/shell/shell.js.map +1 -0
- package/dist/credential-environment.d.ts +20 -0
- package/dist/credential-environment.d.ts.map +1 -0
- package/dist/credential-environment.js +20 -0
- package/dist/credential-environment.js.map +1 -0
- package/dist/durable-session.d.ts +81 -0
- package/dist/durable-session.d.ts.map +1 -0
- package/dist/durable-session.js +550 -0
- package/dist/durable-session.js.map +1 -0
- package/dist/exe-dev/commands.d.ts +23 -13
- package/dist/exe-dev/commands.d.ts.map +1 -1
- package/dist/exe-dev/commands.js +11 -57
- package/dist/exe-dev/commands.js.map +1 -1
- package/dist/exe-dev/exe-dev.d.ts +9 -3
- package/dist/exe-dev/exe-dev.d.ts.map +1 -1
- package/dist/exe-dev/exe-dev.js +61 -128
- package/dist/exe-dev/exe-dev.js.map +1 -1
- package/dist/exe-dev/grants.d.ts.map +1 -1
- package/dist/exe-dev/grants.js +35 -15
- package/dist/exe-dev/grants.js.map +1 -1
- package/dist/exe-dev/model.d.ts +15 -19
- package/dist/exe-dev/model.d.ts.map +1 -1
- package/dist/exe-dev/model.js +9 -12
- package/dist/exe-dev/model.js.map +1 -1
- package/dist/exe-dev/preflight.d.ts +8 -4
- package/dist/exe-dev/preflight.d.ts.map +1 -1
- package/dist/exe-dev/preflight.js +26 -35
- package/dist/exe-dev/preflight.js.map +1 -1
- package/dist/executor.d.ts +292 -44
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +187 -19
- package/dist/executor.js.map +1 -1
- package/dist/guard.d.ts +57 -7
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +274 -59
- package/dist/guard.js.map +1 -1
- package/dist/harness-preflight.d.ts +27 -5
- package/dist/harness-preflight.d.ts.map +1 -1
- package/dist/harness-preflight.js +32 -31
- package/dist/harness-preflight.js.map +1 -1
- package/dist/keyed-lock.d.ts +2 -3
- package/dist/keyed-lock.d.ts.map +1 -1
- package/dist/keyed-lock.js +2 -3
- package/dist/keyed-lock.js.map +1 -1
- package/dist/leftovers.d.ts +9 -0
- package/dist/leftovers.d.ts.map +1 -0
- package/dist/leftovers.js +14 -0
- package/dist/leftovers.js.map +1 -0
- package/dist/local/credentials.d.ts +21 -0
- package/dist/local/credentials.d.ts.map +1 -0
- package/dist/local/credentials.js +39 -0
- package/dist/local/credentials.js.map +1 -0
- package/dist/local/leftovers.d.ts +8 -0
- package/dist/local/leftovers.d.ts.map +1 -0
- package/dist/local/leftovers.js +23 -0
- package/dist/local/leftovers.js.map +1 -0
- package/dist/local/local.d.ts +17 -11
- package/dist/local/local.d.ts.map +1 -1
- package/dist/local/local.js +205 -132
- package/dist/local/local.js.map +1 -1
- package/dist/memory-preflight.d.ts +27 -0
- package/dist/memory-preflight.d.ts.map +1 -0
- package/dist/memory-preflight.js +83 -0
- package/dist/memory-preflight.js.map +1 -0
- package/dist/pre-push-hook.d.ts +20 -0
- package/dist/pre-push-hook.d.ts.map +1 -0
- package/dist/pre-push-hook.js +33 -0
- package/dist/pre-push-hook.js.map +1 -0
- package/dist/prepared-attempt.d.ts +41 -3
- package/dist/prepared-attempt.d.ts.map +1 -1
- package/dist/prepared-attempt.js +109 -31
- package/dist/prepared-attempt.js.map +1 -1
- package/dist/provision.d.ts +129 -15
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +428 -69
- package/dist/provision.js.map +1 -1
- package/dist/remote/commands.d.ts +51 -0
- package/dist/remote/commands.d.ts.map +1 -0
- package/dist/remote/commands.js +94 -0
- package/dist/remote/commands.js.map +1 -0
- package/dist/remote/container.d.ts +90 -0
- package/dist/remote/container.d.ts.map +1 -0
- package/dist/remote/container.js +480 -0
- package/dist/remote/container.js.map +1 -0
- package/dist/remote/leftovers.d.ts +14 -0
- package/dist/remote/leftovers.d.ts.map +1 -0
- package/dist/remote/leftovers.js +22 -0
- package/dist/remote/leftovers.js.map +1 -0
- package/dist/remote/liveness.d.ts +33 -0
- package/dist/remote/liveness.d.ts.map +1 -0
- package/dist/remote/liveness.js +196 -0
- package/dist/remote/liveness.js.map +1 -0
- package/dist/remote/machine.d.ts +110 -0
- package/dist/remote/machine.d.ts.map +1 -0
- package/dist/remote/machine.js +2 -0
- package/dist/remote/machine.js.map +1 -0
- package/dist/remote/remote.d.ts +28 -0
- package/dist/remote/remote.d.ts.map +1 -0
- package/dist/remote/remote.js +556 -0
- package/dist/remote/remote.js.map +1 -0
- package/dist/remote/sweep.d.ts +17 -0
- package/dist/remote/sweep.d.ts.map +1 -0
- package/dist/remote/sweep.js +117 -0
- package/dist/remote/sweep.js.map +1 -0
- package/dist/renewable-credential.d.ts +17 -0
- package/dist/renewable-credential.d.ts.map +1 -0
- package/dist/renewable-credential.js +58 -0
- package/dist/renewable-credential.js.map +1 -0
- package/dist/salvage.d.ts +38 -0
- package/dist/salvage.d.ts.map +1 -0
- package/dist/salvage.js +198 -0
- package/dist/salvage.js.map +1 -0
- package/dist/ssh/api-keys.d.ts +36 -0
- package/dist/ssh/api-keys.d.ts.map +1 -0
- package/dist/ssh/api-keys.js +72 -0
- package/dist/ssh/api-keys.js.map +1 -0
- package/dist/ssh/codex-homes.d.ts +21 -0
- package/dist/ssh/codex-homes.d.ts.map +1 -0
- package/dist/ssh/codex-homes.js +78 -0
- package/dist/ssh/codex-homes.js.map +1 -0
- package/dist/ssh/container.d.ts +32 -0
- package/dist/ssh/container.d.ts.map +1 -0
- package/dist/ssh/container.js +282 -0
- package/dist/ssh/container.js.map +1 -0
- package/dist/ssh/credentials.d.ts +43 -0
- package/dist/ssh/credentials.d.ts.map +1 -0
- package/dist/ssh/credentials.js +86 -0
- package/dist/ssh/credentials.js.map +1 -0
- package/dist/ssh/gateway/admin.d.ts +45 -0
- package/dist/ssh/gateway/admin.d.ts.map +1 -0
- package/dist/ssh/gateway/admin.js +129 -0
- package/dist/ssh/gateway/admin.js.map +1 -0
- package/dist/ssh/gateway/attachments.d.ts +31 -0
- package/dist/ssh/gateway/attachments.d.ts.map +1 -0
- package/dist/ssh/gateway/attachments.js +168 -0
- package/dist/ssh/gateway/attachments.js.map +1 -0
- package/dist/ssh/gateway/environment.d.ts +71 -0
- package/dist/ssh/gateway/environment.d.ts.map +1 -0
- package/dist/ssh/gateway/environment.js +148 -0
- package/dist/ssh/gateway/environment.js.map +1 -0
- package/dist/ssh/gateway/forward.d.ts +74 -0
- package/dist/ssh/gateway/forward.d.ts.map +1 -0
- package/dist/ssh/gateway/forward.js +247 -0
- package/dist/ssh/gateway/forward.js.map +1 -0
- package/dist/ssh/gateway/preflight.d.ts +67 -0
- package/dist/ssh/gateway/preflight.d.ts.map +1 -0
- package/dist/ssh/gateway/preflight.js +320 -0
- package/dist/ssh/gateway/preflight.js.map +1 -0
- package/dist/ssh/limits.d.ts +60 -0
- package/dist/ssh/limits.d.ts.map +1 -0
- package/dist/ssh/limits.js +84 -0
- package/dist/ssh/limits.js.map +1 -0
- package/dist/ssh/model.d.ts +153 -0
- package/dist/ssh/model.d.ts.map +1 -0
- package/dist/ssh/model.js +2 -0
- package/dist/ssh/model.js.map +1 -0
- package/dist/ssh/preflight.d.ts +35 -0
- package/dist/ssh/preflight.d.ts.map +1 -0
- package/dist/ssh/preflight.js +87 -0
- package/dist/ssh/preflight.js.map +1 -0
- package/dist/ssh/provisioner/boat.d.ts +33 -0
- package/dist/ssh/provisioner/boat.d.ts.map +1 -0
- package/dist/ssh/provisioner/boat.js +247 -0
- package/dist/ssh/provisioner/boat.js.map +1 -0
- package/dist/ssh/provisioner/hetzner.d.ts +32 -0
- package/dist/ssh/provisioner/hetzner.d.ts.map +1 -0
- package/dist/ssh/provisioner/hetzner.js +337 -0
- package/dist/ssh/provisioner/hetzner.js.map +1 -0
- package/dist/ssh/provisioner/host-key.d.ts +11 -0
- package/dist/ssh/provisioner/host-key.d.ts.map +1 -0
- package/dist/ssh/provisioner/host-key.js +57 -0
- package/dist/ssh/provisioner/host-key.js.map +1 -0
- package/dist/ssh/provisioner/http.d.ts +45 -0
- package/dist/ssh/provisioner/http.d.ts.map +1 -0
- package/dist/ssh/provisioner/http.js +72 -0
- package/dist/ssh/provisioner/http.js.map +1 -0
- package/dist/ssh/provisioner/machines.d.ts +48 -0
- package/dist/ssh/provisioner/machines.d.ts.map +1 -0
- package/dist/ssh/provisioner/machines.js +686 -0
- package/dist/ssh/provisioner/machines.js.map +1 -0
- package/dist/ssh/provisioner/model.d.ts +92 -0
- package/dist/ssh/provisioner/model.d.ts.map +1 -0
- package/dist/ssh/provisioner/model.js +37 -0
- package/dist/ssh/provisioner/model.js.map +1 -0
- package/dist/ssh/ssh.d.ts +23 -0
- package/dist/ssh/ssh.d.ts.map +1 -0
- package/dist/ssh/ssh.js +145 -0
- package/dist/ssh/ssh.js.map +1 -0
- package/dist/ssh/worker-records.d.ts +18 -0
- package/dist/ssh/worker-records.d.ts.map +1 -0
- package/dist/ssh/worker-records.js +100 -0
- package/dist/ssh/worker-records.js.map +1 -0
- package/dist/ssh/workers.d.ts +80 -0
- package/dist/ssh/workers.d.ts.map +1 -0
- package/dist/ssh/workers.js +247 -0
- package/dist/ssh/workers.js.map +1 -0
- package/package.json +25 -9
- package/dist/exe-dev/channel.d.ts +0 -12
- package/dist/exe-dev/channel.d.ts.map +0 -1
- package/dist/exe-dev/channel.js +0 -42
- package/dist/exe-dev/channel.js.map +0 -1
- package/dist/exe-dev/shell.d.ts +0 -12
- package/dist/exe-dev/shell.d.ts.map +0 -1
- package/dist/exe-dev/shell.js +0 -31
- package/dist/exe-dev/shell.js.map +0 -1
- package/dist/exe-dev/sweep.d.ts +0 -10
- package/dist/exe-dev/sweep.d.ts.map +0 -1
- package/dist/exe-dev/sweep.js +0 -117
- package/dist/exe-dev/sweep.js.map +0 -1
- package/dist/invalid-frame.d.ts +0 -17
- package/dist/invalid-frame.d.ts.map +0 -1
- package/dist/invalid-frame.js +0 -111
- package/dist/invalid-frame.js.map +0 -1
- package/dist/run-host-session.d.ts +0 -27
- package/dist/run-host-session.d.ts.map +0 -1
- package/dist/run-host-session.js +0 -303
- package/dist/run-host-session.js.map +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { RemoteShell } from "@usine/agents/child-host";
|
|
2
|
+
import { SshDestination } from "@usine/core/worker";
|
|
3
|
+
import { DateTime, Effect, Schema, Stream } from "effect";
|
|
4
|
+
import { ChildProcess, type ChildProcessSpawner } from "effect/process";
|
|
5
|
+
export interface OpenForward {
|
|
6
|
+
/** The SSH client number, starting at 1. `reopen` replaces only this generation. */
|
|
7
|
+
readonly generation: number;
|
|
8
|
+
readonly url: URL;
|
|
9
|
+
}
|
|
10
|
+
declare const GatewayForwardClosed_base: Schema.Class<GatewayForwardClosed, Schema.TaggedStruct<"GatewayForwardClosed", {
|
|
11
|
+
readonly gateway: Schema.brand<Schema.String, "SshDestination">;
|
|
12
|
+
readonly generation: Schema.Int;
|
|
13
|
+
readonly since: Schema.DateTimeUtc;
|
|
14
|
+
readonly reason: Schema.NonEmptyString;
|
|
15
|
+
}>, import("effect/Cause").YieldableError>;
|
|
16
|
+
/**
|
|
17
|
+
* The error for a closed admin API forward, whose SSH client didn't open or exited. `since` is
|
|
18
|
+
* when the Gateway became unreachable, and `reason` is the SSH client's error.
|
|
19
|
+
*/
|
|
20
|
+
export declare class GatewayForwardClosed extends GatewayForwardClosed_base {
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* An SSH forward from a local port to a Gateway's admin API (ADR 0027, amendment of
|
|
24
|
+
* 2026-10-19). It opens with the first Worker behind the Gateway, reopens after a pause when
|
|
25
|
+
* its client exits, and closes with the last Worker or the executor.
|
|
26
|
+
*/
|
|
27
|
+
export interface GatewayForward {
|
|
28
|
+
/** The Gateway's SSH destination, used to identify it in logs and messages. */
|
|
29
|
+
readonly gateway: SshDestination;
|
|
30
|
+
/** The SSH command an operator can run to open the same forward manually. */
|
|
31
|
+
readonly command: string;
|
|
32
|
+
/** Returns the open forward, waiting while a client is opening. Fails immediately while the forward is closed. */
|
|
33
|
+
readonly current: Effect.Effect<OpenForward, GatewayForwardClosed>;
|
|
34
|
+
/**
|
|
35
|
+
* Replaces SSH client `generation`, or ends the pause after it closed, and waits for the next
|
|
36
|
+
* client. If another request already replaced it, waits for the current forward.
|
|
37
|
+
*/
|
|
38
|
+
readonly reopen: (generation: number) => Effect.Effect<OpenForward, GatewayForwardClosed>;
|
|
39
|
+
/** Records an unanswered request sent at `sentAt`, and returns when the first unanswered request since the last response was sent. */
|
|
40
|
+
readonly unanswered: (sentAt: DateTime.Utc) => Effect.Effect<DateTime.Utc>;
|
|
41
|
+
/** Records a response from the admin API, so the next unanswered request starts a new outage. */
|
|
42
|
+
readonly answered: Effect.Effect<void>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Opens a forward to the admin API at `adminPort` on `gateway`, using the SSH client and
|
|
46
|
+
* environment of `shell`, and keeps it open until the caller's scope closes. Each client
|
|
47
|
+
* listens on a kernel-picked port of 127.0.0.1, so it never conflicts with an operator's
|
|
48
|
+
* forward.
|
|
49
|
+
*/
|
|
50
|
+
export declare const gatewayForwardFor: (spawner: {
|
|
51
|
+
spawn(command: ChildProcess.Command): Effect.Effect<ChildProcessSpawner.ChildProcessHandle, import("effect/PlatformError").PlatformError, import("effect/Scope").Scope>;
|
|
52
|
+
exitCode(command: ChildProcess.Command): Effect.Effect<ChildProcessSpawner.ExitCode, import("effect/PlatformError").PlatformError>;
|
|
53
|
+
streamString(command: ChildProcess.Command, options?: {
|
|
54
|
+
readonly includeStderr?: boolean | undefined;
|
|
55
|
+
}): Stream.Stream<string, import("effect/PlatformError").PlatformError>;
|
|
56
|
+
streamLines(command: ChildProcess.Command, options?: {
|
|
57
|
+
readonly includeStderr?: boolean | undefined;
|
|
58
|
+
}): Stream.Stream<string, import("effect/PlatformError").PlatformError>;
|
|
59
|
+
lines(command: ChildProcess.Command, options?: {
|
|
60
|
+
readonly includeStderr?: boolean | undefined;
|
|
61
|
+
}): Effect.Effect<Array<string>, import("effect/PlatformError").PlatformError>;
|
|
62
|
+
string(command: ChildProcess.Command, options?: {
|
|
63
|
+
readonly includeStderr?: boolean | undefined;
|
|
64
|
+
}): Effect.Effect<string, import("effect/PlatformError").PlatformError>;
|
|
65
|
+
}, shell: Pick<RemoteShell, "ssh" | "sshEnvironment">, gateway: string & import("effect/Brand").Brand<"SshDestination">, adminPort: number & import("effect/Brand").Brand<"GatewayAdminPort">) => Effect.Effect<{
|
|
66
|
+
gateway: string & import("effect/Brand").Brand<"SshDestination">;
|
|
67
|
+
command: string;
|
|
68
|
+
current: Effect.Effect<OpenForward, GatewayForwardClosed, never>;
|
|
69
|
+
reopen: (generation: number) => Effect.Effect<OpenForward, GatewayForwardClosed, never>;
|
|
70
|
+
unanswered: (sentAt: DateTime.Utc) => Effect.Effect<DateTime.Utc, never, never>;
|
|
71
|
+
answered: Effect.Effect<void, never, never>;
|
|
72
|
+
}, never, import("effect/Scope").Scope>;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=forward.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../../../src/ssh/gateway/forward.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAyB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAY,MAAM,EAA8B,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAcxE,MAAM,WAAW,WAAW;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;CACnB;;;;;;;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,yBAOxC;CAAG;AAEL;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;IACnE;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;IAC1F,sIAAsI;IACtI,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC3E,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACxC;AA6DD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;yBAyQA,QAAQ,CAAC,GAAG;;uCAWxC,CAAC"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { createServer } from "node:net";
|
|
2
|
+
import { SshDestination } from "@usine/core/worker";
|
|
3
|
+
import { DateTime, Deferred, Effect, Fiber, Option, Ref, Result, Schema, Stream } from "effect";
|
|
4
|
+
import { ChildProcess } from "effect/process";
|
|
5
|
+
/** The line the SSH client prints through `LocalCommand` when its local port is listening. */
|
|
6
|
+
const OPEN_LINE = "usine-gateway-forward-open";
|
|
7
|
+
/** The time an SSH client has to connect and listen before it's replaced. */
|
|
8
|
+
const OPEN_TIMEOUT = "30 seconds";
|
|
9
|
+
/** The time a request waits for the forward to open. */
|
|
10
|
+
const OPEN_WAIT = "1 minute";
|
|
11
|
+
/** The maximum pause between SSH clients, in milliseconds. The pause doubles from one second after each failure. */
|
|
12
|
+
const MAX_PAUSE_MILLIS = 60_000;
|
|
13
|
+
/**
|
|
14
|
+
* The error for a closed admin API forward, whose SSH client didn't open or exited. `since` is
|
|
15
|
+
* when the Gateway became unreachable, and `reason` is the SSH client's error.
|
|
16
|
+
*/
|
|
17
|
+
export class GatewayForwardClosed extends Schema.TaggedError("@usine/executor/GatewayForwardClosed")("GatewayForwardClosed", {
|
|
18
|
+
gateway: SshDestination,
|
|
19
|
+
generation: Schema.Int,
|
|
20
|
+
since: Schema.DateTimeUtc,
|
|
21
|
+
reason: Schema.NonEmptyString,
|
|
22
|
+
}) {
|
|
23
|
+
}
|
|
24
|
+
const notOpened = (reason) => ({ _tag: "NotOpened", reason });
|
|
25
|
+
const exited = (reason) => ({ _tag: "Exited", reason });
|
|
26
|
+
const REPLACED = { _tag: "Replaced" };
|
|
27
|
+
const ListenerAddress = Schema.Struct({ port: Schema.Int });
|
|
28
|
+
/** Returns a free port on 127.0.0.1 picked by the kernel, released for the SSH client to listen on. */
|
|
29
|
+
const freeLocalPort = Effect.callback((resume) => {
|
|
30
|
+
const server = createServer();
|
|
31
|
+
server.once("error", (cause) => resume(Effect.fail(cause)));
|
|
32
|
+
server.listen(0, "127.0.0.1", () => {
|
|
33
|
+
const address = Schema.decodeUnknownOption(ListenerAddress)(server.address());
|
|
34
|
+
server.close(() => resume(Option.match(address, {
|
|
35
|
+
onNone: () => Effect.fail(new Error("the listener reported no port")),
|
|
36
|
+
onSome: ({ port }) => Effect.succeed(port),
|
|
37
|
+
})));
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
/** Returns the SSH client's stderr on one line, or its exit code if stderr is empty. */
|
|
41
|
+
const complaint = (stderr, exitCode) => {
|
|
42
|
+
const lines = stderr
|
|
43
|
+
.split("\n")
|
|
44
|
+
.map((line) => line.trim())
|
|
45
|
+
.filter((line) => line !== "");
|
|
46
|
+
return lines.length > 0 ? lines.join("; ") : `ssh exited with code ${String(exitCode)}`;
|
|
47
|
+
};
|
|
48
|
+
const pauseAfter = (failures) => Math.min(1000 * 2 ** Math.max(failures - 1, 0), MAX_PAUSE_MILLIS);
|
|
49
|
+
/**
|
|
50
|
+
* Opens a forward to the admin API at `adminPort` on `gateway`, using the SSH client and
|
|
51
|
+
* environment of `shell`, and keeps it open until the caller's scope closes. Each client
|
|
52
|
+
* listens on a kernel-picked port of 127.0.0.1, so it never conflicts with an operator's
|
|
53
|
+
* forward.
|
|
54
|
+
*/
|
|
55
|
+
export const gatewayForwardFor = Effect.fn("SshExecutor.gatewayForwardFor")(function* (spawner, shell, gateway, adminPort) {
|
|
56
|
+
const fields = { gateway, adminPort };
|
|
57
|
+
yield* Effect.annotateCurrentSpan(fields);
|
|
58
|
+
const forwardSpec = (port) => `127.0.0.1:${String(port)}:127.0.0.1:${String(adminPort)}`;
|
|
59
|
+
const command = [
|
|
60
|
+
shell.ssh.command,
|
|
61
|
+
...shell.ssh.args,
|
|
62
|
+
"-N",
|
|
63
|
+
"-o",
|
|
64
|
+
"ExitOnForwardFailure=yes",
|
|
65
|
+
"-L",
|
|
66
|
+
forwardSpec(adminPort),
|
|
67
|
+
gateway,
|
|
68
|
+
].join(" ");
|
|
69
|
+
const argumentsFor = (port) => [
|
|
70
|
+
...shell.ssh.args,
|
|
71
|
+
"-N",
|
|
72
|
+
// LocalCommand runs when all listeners are up, ExitOnForwardFailure exits if a listener fails, and ControlPath=none avoids the operator's shared connections.
|
|
73
|
+
"-o",
|
|
74
|
+
"ExitOnForwardFailure=yes",
|
|
75
|
+
"-o",
|
|
76
|
+
"ControlPath=none",
|
|
77
|
+
"-o",
|
|
78
|
+
"PermitLocalCommand=yes",
|
|
79
|
+
"-o",
|
|
80
|
+
`LocalCommand=echo ${OPEN_LINE}`,
|
|
81
|
+
"-L",
|
|
82
|
+
forwardSpec(port),
|
|
83
|
+
gateway,
|
|
84
|
+
];
|
|
85
|
+
const generationNumbered = (number) => Effect.all({
|
|
86
|
+
opened: Deferred.make(),
|
|
87
|
+
replace: Deferred.make(),
|
|
88
|
+
next: Deferred.make(),
|
|
89
|
+
}).pipe(Effect.map((signals) => ({ number, ...signals })));
|
|
90
|
+
const first = yield* generationNumbered(1);
|
|
91
|
+
const state = yield* Ref.make({ _tag: "Opening", generation: first });
|
|
92
|
+
const runClient = Effect.fn("SshExecutor.runGatewayForward")(function* (generation, closedSince) {
|
|
93
|
+
yield* Effect.annotateCurrentSpan({ ...fields, generation: generation.number });
|
|
94
|
+
const picked = yield* Effect.result(freeLocalPort);
|
|
95
|
+
if (Result.isFailure(picked))
|
|
96
|
+
return notOpened(`no free port on 127.0.0.1: ${picked.failure.message}`);
|
|
97
|
+
const port = picked.success;
|
|
98
|
+
yield* Effect.annotateCurrentSpan({ port });
|
|
99
|
+
yield* Effect.logDebug("Starting an SSH client for the forward to the Gateway's admin API", {
|
|
100
|
+
...fields,
|
|
101
|
+
generation: generation.number,
|
|
102
|
+
port,
|
|
103
|
+
});
|
|
104
|
+
return yield* Effect.scoped(Effect.gen(function* () {
|
|
105
|
+
const handle = yield* spawner.spawn(ChildProcess.make(shell.ssh.command, argumentsFor(port), {
|
|
106
|
+
env: { ...shell.sshEnvironment },
|
|
107
|
+
extendEnv: false,
|
|
108
|
+
detached: false,
|
|
109
|
+
forceKillAfter: "5 seconds",
|
|
110
|
+
stdin: "ignore",
|
|
111
|
+
}));
|
|
112
|
+
const stderr = yield* handle.stderr.pipe(Stream.decodeText(), Stream.mkString, Effect.forkScoped);
|
|
113
|
+
const reported = (exitCode) => Fiber.join(stderr).pipe(Effect.map((text) => complaint(text, exitCode)));
|
|
114
|
+
const listening = yield* handle.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.filter((line) => line.trim() === OPEN_LINE), Stream.runHead, Effect.timeoutOption(OPEN_TIMEOUT));
|
|
115
|
+
if (Option.isNone(listening))
|
|
116
|
+
return notOpened(`ssh didn't open the forward within ${OPEN_TIMEOUT}`);
|
|
117
|
+
if (Option.isNone(listening.value))
|
|
118
|
+
return notOpened(yield* reported(Number(yield* handle.exitCode)));
|
|
119
|
+
const open = {
|
|
120
|
+
generation: generation.number,
|
|
121
|
+
url: new URL(`http://127.0.0.1:${String(port)}`),
|
|
122
|
+
};
|
|
123
|
+
yield* Ref.set(state, { _tag: "Open", generation, open });
|
|
124
|
+
yield* Deferred.succeed(generation.opened, open);
|
|
125
|
+
yield* Option.match(closedSince, {
|
|
126
|
+
onNone: () => Effect.logInfo("Opened the forward to the Gateway's admin API", {
|
|
127
|
+
...fields,
|
|
128
|
+
generation: generation.number,
|
|
129
|
+
port,
|
|
130
|
+
}),
|
|
131
|
+
onSome: (since) => Effect.logInfo("Reopened the forward to the Gateway's admin API", {
|
|
132
|
+
...fields,
|
|
133
|
+
generation: generation.number,
|
|
134
|
+
port,
|
|
135
|
+
closedSince: DateTime.formatIso(since),
|
|
136
|
+
}),
|
|
137
|
+
});
|
|
138
|
+
// Sets the state to closed first, so no request uses a port the client no longer listens on.
|
|
139
|
+
const closedNow = (reason) => DateTime.now.pipe(Effect.flatMap((since) => Ref.set(state, {
|
|
140
|
+
_tag: "Closed",
|
|
141
|
+
generation,
|
|
142
|
+
closed: new GatewayForwardClosed({
|
|
143
|
+
gateway,
|
|
144
|
+
generation: generation.number,
|
|
145
|
+
since,
|
|
146
|
+
reason,
|
|
147
|
+
}),
|
|
148
|
+
})));
|
|
149
|
+
return yield* Effect.raceFirst(handle.exitCode.pipe(Effect.flatMap((code) => reported(Number(code))), Effect.catch((error) => Effect.succeed(`can't read the SSH client's exit code: ${error.message}`)), Effect.tap(closedNow), Effect.map(exited)), Deferred.await(generation.replace).pipe(Effect.andThen(closedNow("replaced after a request got no response")), Effect.as(REPLACED)));
|
|
150
|
+
})).pipe(Effect.catch((error) => Effect.succeed(notOpened(`can't run ${shell.ssh.command}: ${error.message}`))));
|
|
151
|
+
});
|
|
152
|
+
// Runs until the caller's scope closes, with one span per SSH client.
|
|
153
|
+
const supervise = Effect.gen(function* () {
|
|
154
|
+
let generation = first;
|
|
155
|
+
let failures = 0;
|
|
156
|
+
let closedSince = Option.none();
|
|
157
|
+
while (true) {
|
|
158
|
+
const end = yield* runClient(generation, closedSince);
|
|
159
|
+
const now = yield* DateTime.now;
|
|
160
|
+
if (end._tag === "Replaced") {
|
|
161
|
+
failures = 0;
|
|
162
|
+
closedSince = Option.some(now);
|
|
163
|
+
yield* Effect.logInfo("Replacing the forward to the Gateway's admin API, which a request found unanswered", { ...fields, generation: generation.number });
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
failures = end._tag === "Exited" ? 1 : failures + 1;
|
|
167
|
+
const since = end._tag === "Exited" ? now : Option.getOrElse(closedSince, () => now);
|
|
168
|
+
closedSince = Option.some(since);
|
|
169
|
+
const pause = pauseAfter(failures);
|
|
170
|
+
const closed = new GatewayForwardClosed({
|
|
171
|
+
gateway,
|
|
172
|
+
generation: generation.number,
|
|
173
|
+
since,
|
|
174
|
+
reason: end.reason,
|
|
175
|
+
});
|
|
176
|
+
yield* Ref.set(state, { _tag: "Closed", generation, closed });
|
|
177
|
+
yield* Deferred.fail(generation.opened, closed);
|
|
178
|
+
yield* Effect.logWarning(end._tag === "Exited"
|
|
179
|
+
? "The forward to the Gateway's admin API exited; reopening it after a pause"
|
|
180
|
+
: "Could not open the forward to the Gateway's admin API; trying again after a pause", {
|
|
181
|
+
...fields,
|
|
182
|
+
generation: generation.number,
|
|
183
|
+
closedSince: DateTime.formatIso(since),
|
|
184
|
+
failures,
|
|
185
|
+
pauseSeconds: pause / 1000,
|
|
186
|
+
reason: end.reason,
|
|
187
|
+
});
|
|
188
|
+
const trigger = yield* Effect.raceFirst(Effect.sleep(pause).pipe(Effect.as("pause elapsed")), Deferred.await(generation.replace).pipe(Effect.as("request")));
|
|
189
|
+
yield* Effect.logInfo("Reopening the forward to the Gateway's admin API", {
|
|
190
|
+
...fields,
|
|
191
|
+
generation: generation.number + 1,
|
|
192
|
+
closedSince: DateTime.formatIso(since),
|
|
193
|
+
trigger,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
const next = yield* generationNumbered(generation.number + 1);
|
|
197
|
+
yield* Ref.set(state, { _tag: "Opening", generation: next });
|
|
198
|
+
yield* Deferred.succeed(generation.next, next);
|
|
199
|
+
generation = next;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
yield* supervise.pipe(Effect.onInterrupt(() => Effect.logInfo("Closed the forward to the Gateway's admin API", fields)), Effect.forkScoped);
|
|
203
|
+
const notOpenedWithin = (generation) => DateTime.now.pipe(Effect.flatMap((since) => new GatewayForwardClosed({
|
|
204
|
+
gateway,
|
|
205
|
+
generation,
|
|
206
|
+
since,
|
|
207
|
+
reason: `the forward didn't open within ${OPEN_WAIT}`,
|
|
208
|
+
})));
|
|
209
|
+
const current = Effect.gen(function* () {
|
|
210
|
+
const now = yield* Ref.get(state);
|
|
211
|
+
switch (now._tag) {
|
|
212
|
+
case "Open":
|
|
213
|
+
return now.open;
|
|
214
|
+
case "Closed":
|
|
215
|
+
return yield* now.closed;
|
|
216
|
+
case "Opening":
|
|
217
|
+
return yield* Deferred.await(now.generation.opened).pipe(Effect.timeoutOrElse({
|
|
218
|
+
duration: OPEN_WAIT,
|
|
219
|
+
orElse: () => notOpenedWithin(now.generation.number),
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
const reopen = Effect.fn("SshExecutor.reopenGatewayForward")(function* (generation) {
|
|
224
|
+
yield* Effect.annotateCurrentSpan({ ...fields, generation });
|
|
225
|
+
const now = yield* Ref.get(state);
|
|
226
|
+
if (now.generation.number !== generation) {
|
|
227
|
+
yield* Effect.logDebug("Another request replaced the forward to the Gateway's admin API already", { ...fields, generation, current: now.generation.number });
|
|
228
|
+
return yield* current;
|
|
229
|
+
}
|
|
230
|
+
yield* Deferred.succeed(now.generation.replace, undefined);
|
|
231
|
+
return yield* Deferred.await(now.generation.next).pipe(Effect.flatMap((next) => Deferred.await(next.opened)), Effect.timeoutOrElse({
|
|
232
|
+
duration: OPEN_WAIT,
|
|
233
|
+
orElse: () => notOpenedWithin(generation + 1),
|
|
234
|
+
}));
|
|
235
|
+
});
|
|
236
|
+
const silentSince = yield* Ref.make(Option.none());
|
|
237
|
+
const unanswered = (sentAt) => Ref.modify(silentSince, (since) => {
|
|
238
|
+
const first = Option.match(since, {
|
|
239
|
+
onNone: () => sentAt,
|
|
240
|
+
onSome: (earlier) => DateTime.min(earlier, sentAt),
|
|
241
|
+
});
|
|
242
|
+
return [first, Option.some(first)];
|
|
243
|
+
});
|
|
244
|
+
const answered = Ref.set(silentSince, Option.none());
|
|
245
|
+
return { gateway, command, current, reopen, unanswered, answered };
|
|
246
|
+
});
|
|
247
|
+
//# sourceMappingURL=forward.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.js","sourceRoot":"","sources":["../../../src/ssh/gateway/forward.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAyB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChG,OAAO,EAAE,YAAY,EAA4B,MAAM,gBAAgB,CAAC;AAExE,8FAA8F;AAC9F,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAE/C,6EAA6E;AAC7E,MAAM,YAAY,GAAG,YAAY,CAAC;AAElC,wDAAwD;AACxD,MAAM,SAAS,GAAG,UAAU,CAAC;AAE7B,oHAAoH;AACpH,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAQhC;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,MAAM,CAAC,WAAW,CAC1D,sCAAsC,CACvC,CAAC,sBAAsB,EAAE;IACxB,OAAO,EAAE,cAAc;IACvB,UAAU,EAAE,MAAM,CAAC,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC,WAAW;IACzB,MAAM,EAAE,MAAM,CAAC,cAAc;CAC9B,CAAC;CAAG;AAiDL,MAAM,SAAS,GAAG,CAAC,MAAc,EAAa,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;AACjF,MAAM,MAAM,GAAG,CAAC,MAAc,EAAa,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AAC3E,MAAM,QAAQ,GAAc,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAEjD,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;AAE5D,uGAAuG;AACvG,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAgB,CAAC,MAAM,EAAE,EAAE;IAC9D,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;QACjC,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9E,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAChB,MAAM,CACJ,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;YACpB,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACrE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SAC3C,CAAC,CACH,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,wFAAwF;AACxF,MAAM,SAAS,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAU,EAAE;IAC7D,MAAM,KAAK,GAAG,MAAM;SACjB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,wBAAwB,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC1F,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAU,EAAE,CAC9C,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EACnF,OAA2D,EAC3D,KAAkD,EAClD,OAAuB,EACvB,SAA2B;IAE3B,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IACtC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;IACjG,MAAM,OAAO,GAAG;QACd,KAAK,CAAC,GAAG,CAAC,OAAO;QACjB,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI;QACjB,IAAI;QACJ,IAAI;QACJ,0BAA0B;QAC1B,IAAI;QACJ,WAAW,CAAC,SAAS,CAAC;QACtB,OAAO;KACR,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;QACrC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI;QACjB,IAAI;QACJ,8JAA8J;QAC9J,IAAI;QACJ,0BAA0B;QAC1B,IAAI;QACJ,kBAAkB;QAClB,IAAI;QACJ,wBAAwB;QACxB,IAAI;QACJ,qBAAqB,SAAS,EAAE;QAChC,IAAI;QACJ,WAAW,CAAC,IAAI,CAAC;QACjB,OAAO;KACR,CAAC;IAEF,MAAM,kBAAkB,GAAG,CAAC,MAAc,EAAE,EAAE,CAC5C,MAAM,CAAC,GAAG,CAAC;QACT,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAqC;QAC1D,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAQ;QAC9B,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAc;KAClC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAc,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAe,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAEpF,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EACpE,UAAsB,EACtB,WAAwC;QAExC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QACnD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAC1B,OAAO,SAAS,CAAC,8BAA8B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;QAC5B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,mEAAmE,EAAE;YAC1F,GAAG,MAAM;YACT,UAAU,EAAE,UAAU,CAAC,MAAM;YAC7B,IAAI;SACL,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CACzB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CACjC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE;gBACvD,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC,cAAc,EAAE;gBAChC,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,KAAK;gBACf,cAAc,EAAE,WAAW;gBAC3B,KAAK,EAAE,QAAQ;aAChB,CAAC,CACH,CAAC;YACF,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CACtC,MAAM,CAAC,UAAU,EAAE,EACnB,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,UAAU,CAClB,CAAC;YACF,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAE,EAAE,CACpC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC3E,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CACzC,MAAM,CAAC,UAAU,EAAE,EACnB,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,SAAS,CAAC,EAClD,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CACnC,CAAC;YACF,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC1B,OAAO,SAAS,CAAC,sCAAsC,YAAY,EAAE,CAAC,CAAC;YACzE,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;gBAChC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAEpE,MAAM,IAAI,GAAgB;gBACxB,UAAU,EAAE,UAAU,CAAC,MAAM;gBAC7B,GAAG,EAAE,IAAI,GAAG,CAAC,oBAAoB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;aACjD,CAAC;YACF,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACjD,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE;gBAC/B,MAAM,EAAE,GAAG,EAAE,CACX,MAAM,CAAC,OAAO,CAAC,+CAA+C,EAAE;oBAC9D,GAAG,MAAM;oBACT,UAAU,EAAE,UAAU,CAAC,MAAM;oBAC7B,IAAI;iBACL,CAAC;gBACJ,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAChB,MAAM,CAAC,OAAO,CAAC,iDAAiD,EAAE;oBAChE,GAAG,MAAM;oBACT,UAAU,EAAE,UAAU,CAAC,MAAM;oBAC7B,IAAI;oBACJ,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;iBACvC,CAAC;aACL,CAAC,CAAC;YACH,6FAA6F;YAC7F,MAAM,SAAS,GAAG,CAAC,MAAc,EAAE,EAAE,CACnC,QAAQ,CAAC,GAAG,CAAC,IAAI,CACf,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CACvB,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,UAAU;gBACV,MAAM,EAAE,IAAI,oBAAoB,CAAC;oBAC/B,OAAO;oBACP,UAAU,EAAE,UAAU,CAAC,MAAM;oBAC7B,KAAK;oBACL,MAAM;iBACP,CAAC;aACH,CAAC,CACH,CACF,CAAC;YACJ,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAC5B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAClB,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAChD,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CACrB,MAAM,CAAC,OAAO,CAAC,0CAA0C,KAAK,CAAC,OAAO,EAAE,CAAC,CAC1E,EACD,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EACrB,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CACnB,EACD,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CACrC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,0CAA0C,CAAC,CAAC,EACrE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CACpB,CACF,CAAC;QACJ,CAAC,CAAC,CACH,CAAC,IAAI,CACJ,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CACrB,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAC9E,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,sEAAsE;IACtE,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACpC,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,WAAW,GAAG,MAAM,CAAC,IAAI,EAAgB,CAAC;QAC9C,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;YACtD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;YAChC,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC5B,QAAQ,GAAG,CAAC,CAAC;gBACb,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC/B,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CACnB,oFAAoF,EACpF,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,CAC7C,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,QAAQ,GAAG,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACpD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;gBACrF,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACjC,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;gBACnC,MAAM,MAAM,GAAG,IAAI,oBAAoB,CAAC;oBACtC,OAAO;oBACP,UAAU,EAAE,UAAU,CAAC,MAAM;oBAC7B,KAAK;oBACL,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;gBACH,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC9D,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAChD,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CACtB,GAAG,CAAC,IAAI,KAAK,QAAQ;oBACnB,CAAC,CAAC,2EAA2E;oBAC7E,CAAC,CAAC,mFAAmF,EACvF;oBACE,GAAG,MAAM;oBACT,UAAU,EAAE,UAAU,CAAC,MAAM;oBAC7B,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;oBACtC,QAAQ;oBACR,YAAY,EAAE,KAAK,GAAG,IAAI;oBAC1B,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CACF,CAAC;gBACF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CACrC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,EACpD,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAC9D,CAAC;gBACF,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,kDAAkD,EAAE;oBACxE,GAAG,MAAM;oBACT,UAAU,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC;oBACjC,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;oBACtC,OAAO;iBACR,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,kBAAkB,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC9D,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7D,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC/C,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CACnB,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,CACtB,MAAM,CAAC,OAAO,CAAC,+CAA+C,EAAE,MAAM,CAAC,CACxE,EACD,MAAM,CAAC,UAAU,CAClB,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,UAAkB,EAAE,EAAE,CAC7C,QAAQ,CAAC,GAAG,CAAC,IAAI,CACf,MAAM,CAAC,OAAO,CACZ,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,oBAAoB,CAAC;QACvB,OAAO;QACP,UAAU;QACV,KAAK;QACL,MAAM,EAAE,kCAAkC,SAAS,EAAE;KACtD,CAAC,CACL,CACF,CAAC;IAEJ,MAAM,OAAO,GAA8B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC7D,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,MAAM;gBACT,OAAO,GAAG,CAAC,IAAI,CAAC;YAClB,KAAK,QAAQ;gBACX,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;YAC3B,KAAK,SAAS;gBACZ,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CACtD,MAAM,CAAC,aAAa,CAAC;oBACnB,QAAQ,EAAE,SAAS;oBACnB,MAAM,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;iBACrD,CAAC,CACH,CAAC;QACN,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,kCAAkC,CAAC,CAAC,QAAQ,CAAC,EAAE,UAAkB;QACxF,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACzC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CACpB,yEAAyE,EACzE,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,CAC1D,CAAC;YACF,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC;QACxB,CAAC;QACD,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CACpD,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EACrD,MAAM,CAAC,aAAa,CAAC;YACnB,QAAQ,EAAE,SAAS;YACnB,MAAM,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,UAAU,GAAG,CAAC,CAAC;SAC9C,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAgB,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,CAAC,MAAoB,EAAE,EAAE,CAC1C,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;YAChC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM;YACpB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC;SACnD,CAAC,CAAC;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAU,CAAC;IAC9C,CAAC,CAAC,CAAC;IACL,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAErD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAA2B,CAAC;AAC9F,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type RemoteShell } from "@usine/agents/child-host";
|
|
2
|
+
import type { Harness } from "@usine/core/agent/brain";
|
|
3
|
+
import { HarnessReady, HarnessUnavailableError } from "@usine/core/agent/capability";
|
|
4
|
+
import type { GatewayCredentialKind, WorkerName } from "@usine/core/worker";
|
|
5
|
+
import { Effect, Option } from "effect";
|
|
6
|
+
import { ExecutorOperationError, WorkerCapabilityError } from "../../executor.ts";
|
|
7
|
+
import type { HarnessProbe } from "../../harness-preflight.ts";
|
|
8
|
+
import { type RemoteCommands } from "../../remote/commands.ts";
|
|
9
|
+
import type { MachineGateway, SshMachine } from "../model.ts";
|
|
10
|
+
/**
|
|
11
|
+
* Returns the credential kind the Gateway injects for `harness`, as recorded by the last
|
|
12
|
+
* preflight: Anthropic's for Claude Code, OpenAI's for Codex. Pi uses its own login.
|
|
13
|
+
*/
|
|
14
|
+
export declare const gatewayCredentialFor: (gateway: MachineGateway, harness: Harness) => Effect.Effect<Option.Option<GatewayCredentialKind>>;
|
|
15
|
+
/**
|
|
16
|
+
* Verifies the Gateway's admin API for an SSH Worker without attaching anything: the forward
|
|
17
|
+
* opens and the admin API accepts the admin token. Records the Gateway's credential kind for
|
|
18
|
+
* each provider in the Worker's `llmProviders`. Needs no Worker machine.
|
|
19
|
+
*/
|
|
20
|
+
export declare const verifyGatewayAdmin: (worker: string & import("effect/Brand").Brand<"WorkerName">, gateway: MachineGateway) => Effect.Effect<void, WorkerCapabilityError, never>;
|
|
21
|
+
/**
|
|
22
|
+
* Verifies the Gateway in front of an SSH Worker without attaching anything: the admin API
|
|
23
|
+
* checks of `verifyGatewayAdmin`, then the machine checks of `verifyGatewayFromMachine`.
|
|
24
|
+
*/
|
|
25
|
+
export declare const verifyGateway: (commands: RemoteCommands, worker: WorkerName, machine: SshMachine, gateway: MachineGateway) => Effect.Effect<undefined, ExecutorOperationError | WorkerCapabilityError, never>;
|
|
26
|
+
/**
|
|
27
|
+
* Checks only the binary of a harness whose credential the machine doesn't keep, the Gateway's
|
|
28
|
+
* or an API key in the Attempt's environment, named by `credential` in the log. Codex's version
|
|
29
|
+
* must also be supported.
|
|
30
|
+
*/
|
|
31
|
+
export declare const harnessBinaryProbe: (commands: RemoteCommands, host: string, shell: RemoteShell, harness: "claude" | "codex", credential: string) => Effect.Effect<HarnessReady | HarnessUnavailableError, ExecutorOperationError, never>;
|
|
32
|
+
/**
|
|
33
|
+
* The harnesses that can use the operator's login on the machine or the Gateway's credential
|
|
34
|
+
* for their provider, with the hosts each login calls through the forward proxy, which
|
|
35
|
+
* `infra/hetzner/gateway/egress-allowlist` lists, and the API host that an API key in the
|
|
36
|
+
* Attempt's environment calls.
|
|
37
|
+
*/
|
|
38
|
+
declare const LOGINS: {
|
|
39
|
+
readonly claude: {
|
|
40
|
+
readonly label: "Claude Code";
|
|
41
|
+
readonly provider: "Anthropic";
|
|
42
|
+
readonly gatewayProvider: "anthropic";
|
|
43
|
+
readonly hosts: readonly ["api.anthropic.com", "platform.claude.com"];
|
|
44
|
+
readonly apiHost: "api.anthropic.com";
|
|
45
|
+
};
|
|
46
|
+
readonly codex: {
|
|
47
|
+
readonly label: "Codex";
|
|
48
|
+
readonly provider: "OpenAI";
|
|
49
|
+
readonly gatewayProvider: "openai";
|
|
50
|
+
readonly hosts: readonly ["chatgpt.com", "auth.openai.com"];
|
|
51
|
+
readonly apiHost: "api.openai.com";
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/** A harness that can use a login, the Gateway's credential, or an API key. */
|
|
55
|
+
export type LoginHarness = keyof typeof LOGINS;
|
|
56
|
+
/**
|
|
57
|
+
* Probes a brain on a Worker behind a Gateway (ADR 0027). If the Gateway has the credential of
|
|
58
|
+
* the harness's provider, checks only the harness binary. Otherwise, Claude Code and Codex use
|
|
59
|
+
* the operator's login (ADR 0026), or an API key in the Attempt's environment if `apiKeyed`
|
|
60
|
+
* returns `true` for the harness: `probe` checks the login or the binary, then the machine must
|
|
61
|
+
* connect to the login's hosts, or the provider's API host, through the forward proxy. Pi goes
|
|
62
|
+
* to `probe`, which rejects it on any remote machine. The checks run through `shell`, on the
|
|
63
|
+
* machine or in a container on it.
|
|
64
|
+
*/
|
|
65
|
+
export declare const gatewayHarnessProbe: (commands: RemoteCommands, machine: SshMachine, gateway: MachineGateway, probe: HarnessProbe, shell: RemoteShell, apiKeyed: (harness: LoginHarness) => boolean) => HarnessProbe;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../../src/ssh/gateway/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAe,MAAM,0BAA0B,CAAC;AAEzE,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,KAAK,EAAE,qBAAqB,EAAsB,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAiB,MAAM,QAAQ,CAAC;AAEvD,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAsB,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0HlF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,YACtB,cAAc,WACd,OAAO,KACf,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CASpD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,6IA+B7B,CAAC;AAqEH;;;GAGG;AACH,eAAO,MAAM,aAAa,aACd,cAAc,UAChB,UAAU,WACT,UAAU,WACV,cAAc,oFAItB,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,uMA0B7B,CAAC;AAEH;;;;;GAKG;AACH,QAAA,MAAM,MAAM;;iBAER,KAAK,EAAE,aAAa;iBACpB,QAAQ,EAAE,WAAW;iBACrB,eAAe,EAAE,WAAW;iBAC5B,KAAK;iBACL,OAAO,EAAE,mBAAmB;;;iBAG5B,KAAK,EAAE,OAAO;iBACd,QAAQ,EAAE,QAAQ;iBAClB,eAAe,EAAE,QAAQ;iBACzB,KAAK;iBACL,OAAO,EAAE,gBAAgB;;CAa5B,CAAC;AAEF,+EAA+E;AAC/E,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,MAAM,CAAC;AAqB/C;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,aACpB,cAAc,WACf,UAAU,WACV,cAAc,SAChB,YAAY,SACZ,WAAW,YACR,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,KAC3C,YAyFF,CAAC"}
|