@nodetool-ai/deploy 0.7.0-rc.23 → 0.8.2

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.
Files changed (121) hide show
  1. package/README.md +41 -0
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/admin-client.d.ts +5 -39
  4. package/dist/admin-client.d.ts.map +1 -1
  5. package/dist/admin-client.js +9 -230
  6. package/dist/admin-client.js.map +1 -1
  7. package/dist/api-user-manager.d.ts.map +1 -1
  8. package/dist/api-user-manager.js +5 -2
  9. package/dist/api-user-manager.js.map +1 -1
  10. package/dist/auth.d.ts.map +1 -1
  11. package/dist/auth.js +0 -3
  12. package/dist/auth.js.map +1 -1
  13. package/dist/compose.d.ts.map +1 -1
  14. package/dist/compose.js +5 -6
  15. package/dist/compose.js.map +1 -1
  16. package/dist/configure.d.ts +1 -43
  17. package/dist/configure.d.ts.map +1 -1
  18. package/dist/configure.js +2 -43
  19. package/dist/configure.js.map +1 -1
  20. package/dist/deployment-config.d.ts +28 -786
  21. package/dist/deployment-config.d.ts.map +1 -1
  22. package/dist/deployment-config.js +34 -218
  23. package/dist/deployment-config.js.map +1 -1
  24. package/dist/docker-run.d.ts +2 -1
  25. package/dist/docker-run.d.ts.map +1 -1
  26. package/dist/docker-run.js +6 -22
  27. package/dist/docker-run.js.map +1 -1
  28. package/dist/docker.d.ts +6 -21
  29. package/dist/docker.d.ts.map +1 -1
  30. package/dist/docker.js +6 -53
  31. package/dist/docker.js.map +1 -1
  32. package/dist/image-spec.d.ts +1 -1
  33. package/dist/index.d.ts +0 -14
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/manager.d.ts.map +1 -1
  38. package/dist/manager.js +0 -44
  39. package/dist/manager.js.map +1 -1
  40. package/dist/progress.d.ts.map +1 -1
  41. package/dist/progress.js +0 -1
  42. package/dist/progress.js.map +1 -1
  43. package/dist/remote-users.d.ts.map +1 -1
  44. package/dist/remote-users.js +1 -4
  45. package/dist/remote-users.js.map +1 -1
  46. package/dist/runpod-rest.d.ts +114 -0
  47. package/dist/runpod-rest.d.ts.map +1 -0
  48. package/dist/runpod-rest.js +150 -0
  49. package/dist/runpod-rest.js.map +1 -0
  50. package/dist/self-hosted.d.ts +17 -43
  51. package/dist/self-hosted.d.ts.map +1 -1
  52. package/dist/self-hosted.js +50 -124
  53. package/dist/self-hosted.js.map +1 -1
  54. package/dist/ssh.d.ts +9 -0
  55. package/dist/ssh.d.ts.map +1 -1
  56. package/dist/ssh.js +1 -5
  57. package/dist/ssh.js.map +1 -1
  58. package/dist/state.d.ts.map +1 -1
  59. package/dist/state.js +1 -11
  60. package/dist/state.js.map +1 -1
  61. package/dist/workflow-syncer.d.ts +3 -32
  62. package/dist/workflow-syncer.d.ts.map +1 -1
  63. package/dist/workflow-syncer.js +3 -162
  64. package/dist/workflow-syncer.js.map +1 -1
  65. package/package.json +29 -14
  66. package/dist/admin-operations.d.ts +0 -197
  67. package/dist/admin-operations.d.ts.map +0 -1
  68. package/dist/admin-operations.js +0 -433
  69. package/dist/admin-operations.js.map +0 -1
  70. package/dist/admin-routes.d.ts +0 -306
  71. package/dist/admin-routes.d.ts.map +0 -1
  72. package/dist/admin-routes.js +0 -383
  73. package/dist/admin-routes.js.map +0 -1
  74. package/dist/collection-routes.d.ts +0 -37
  75. package/dist/collection-routes.d.ts.map +0 -1
  76. package/dist/collection-routes.js +0 -43
  77. package/dist/collection-routes.js.map +0 -1
  78. package/dist/deploy-to-gcp.d.ts +0 -67
  79. package/dist/deploy-to-gcp.d.ts.map +0 -1
  80. package/dist/deploy-to-gcp.js +0 -268
  81. package/dist/deploy-to-gcp.js.map +0 -1
  82. package/dist/deploy-to-runpod.d.ts +0 -53
  83. package/dist/deploy-to-runpod.d.ts.map +0 -1
  84. package/dist/deploy-to-runpod.js +0 -207
  85. package/dist/deploy-to-runpod.js.map +0 -1
  86. package/dist/fly.d.ts +0 -40
  87. package/dist/fly.d.ts.map +0 -1
  88. package/dist/fly.js +0 -291
  89. package/dist/fly.js.map +0 -1
  90. package/dist/gcp.d.ts +0 -59
  91. package/dist/gcp.d.ts.map +0 -1
  92. package/dist/gcp.js +0 -339
  93. package/dist/gcp.js.map +0 -1
  94. package/dist/google-cloud-run-api.d.ts +0 -134
  95. package/dist/google-cloud-run-api.d.ts.map +0 -1
  96. package/dist/google-cloud-run-api.js +0 -532
  97. package/dist/google-cloud-run-api.js.map +0 -1
  98. package/dist/huggingface.d.ts +0 -69
  99. package/dist/huggingface.d.ts.map +0 -1
  100. package/dist/huggingface.js +0 -346
  101. package/dist/huggingface.js.map +0 -1
  102. package/dist/railway.d.ts +0 -65
  103. package/dist/railway.d.ts.map +0 -1
  104. package/dist/railway.js +0 -284
  105. package/dist/railway.js.map +0 -1
  106. package/dist/runpod-api.d.ts +0 -206
  107. package/dist/runpod-api.d.ts.map +0 -1
  108. package/dist/runpod-api.js +0 -703
  109. package/dist/runpod-api.js.map +0 -1
  110. package/dist/runpod.d.ts +0 -82
  111. package/dist/runpod.d.ts.map +0 -1
  112. package/dist/runpod.js +0 -188
  113. package/dist/runpod.js.map +0 -1
  114. package/dist/storage-routes.d.ts +0 -55
  115. package/dist/storage-routes.d.ts.map +0 -1
  116. package/dist/storage-routes.js +0 -160
  117. package/dist/storage-routes.js.map +0 -1
  118. package/dist/sync.d.ts +0 -38
  119. package/dist/sync.d.ts.map +0 -1
  120. package/dist/sync.js +0 -130
  121. package/dist/sync.js.map +0 -1
@@ -0,0 +1,114 @@
1
+ /**
2
+ * RunPod Pod management over the REST API (https://rest.runpod.io/v1).
3
+ *
4
+ * The serverless helpers in `runpod-api.ts` create templates/endpoints (the
5
+ * job/queue model) and read the API key from `process.env`. This module manages
6
+ * **persistent Pods** — the right shape for a long-lived NodeTool WebSocket
7
+ * worker the server/CLI attaches to — and takes the API key **explicitly** so it
8
+ * can be sourced from the per-user secret store (`getSecret`), never the
9
+ * environment.
10
+ *
11
+ * REST surface used: POST /v1/pods, GET /v1/pods/{id}, POST /v1/pods/{id}/stop,
12
+ * DELETE /v1/pods/{id}, GET /v1/pods.
13
+ */
14
+ /** Request body for POST /v1/pods (subset we use; see the REST reference). */
15
+ export interface RunpodPodSpec {
16
+ name: string;
17
+ imageName: string;
18
+ computeType?: "CPU" | "GPU";
19
+ vcpuCount?: number;
20
+ cpuFlavorIds?: string[];
21
+ cpuFlavorPriority?: "availability" | "custom";
22
+ gpuTypeIds?: string[];
23
+ gpuCount?: number;
24
+ ports?: string[];
25
+ env?: Record<string, string>;
26
+ containerDiskInGb?: number;
27
+ volumeInGb?: number;
28
+ volumeMountPath?: string;
29
+ networkVolumeId?: string;
30
+ dockerEntrypoint?: string[];
31
+ dockerStartCmd?: string[];
32
+ supportPublicIp?: boolean;
33
+ globalNetworking?: boolean;
34
+ dataCenterIds?: string[];
35
+ }
36
+ /** Pod as returned by GET /v1/pods/{id} (fields we read). */
37
+ export interface RunpodPod {
38
+ id: string;
39
+ name?: string;
40
+ desiredStatus?: "RUNNING" | "EXITED" | "TERMINATED" | string;
41
+ image?: string;
42
+ /** Public IPv4; empty/null while the Pod is initializing. */
43
+ publicIp?: string | null;
44
+ /** Internal→external port map, e.g. {"7777": 41021}. */
45
+ portMappings?: Record<string, number> | null;
46
+ ports?: string[];
47
+ [k: string]: unknown;
48
+ }
49
+ /** Create (and deploy) a Pod. POST /v1/pods. */
50
+ export declare function createPod(apiKey: string, spec: RunpodPodSpec): Promise<RunpodPod>;
51
+ /** Get a Pod by id. GET /v1/pods/{id}. */
52
+ export declare function getPod(apiKey: string, id: string): Promise<RunpodPod>;
53
+ /** List Pods. GET /v1/pods. */
54
+ export declare function listPods(apiKey: string): Promise<RunpodPod[]>;
55
+ /** Stop a Pod (releases compute, keeps the volume). POST /v1/pods/{id}/stop. */
56
+ export declare function stopPod(apiKey: string, id: string): Promise<void>;
57
+ /** Terminate a Pod (deletes it). DELETE /v1/pods/{id}. */
58
+ export declare function deletePod(apiKey: string, id: string): Promise<void>;
59
+ /**
60
+ * Direct TCP WebSocket URL for an exposed `/tcp` port, or null while the Pod
61
+ * lacks a public IP / port mapping. Preferred for large frames (no HTTP proxy).
62
+ */
63
+ export declare function podDirectWsUrl(pod: RunpodPod, internalPort: number): string | null;
64
+ /**
65
+ * RunPod HTTP-proxy WebSocket URL for an exposed `/http` port. TLS-terminated
66
+ * by RunPod; subject to the proxy's size/timeout limits (fine for small frames).
67
+ */
68
+ export declare function podProxyWsUrl(podId: string, internalPort: number): string;
69
+ export interface DeployWorkerPodOptions {
70
+ /** Pod name. */
71
+ name: string;
72
+ /** Registry image RunPod pulls (must be reachable by RunPod). */
73
+ image: string;
74
+ /** Shared-secret passed as NODETOOL_WORKER_TOKEN (gates the ws handshake). */
75
+ workerToken?: string;
76
+ /** Internal port the worker serves on. Default 7777. */
77
+ internalPort?: number;
78
+ /** Expose via RunPod HTTP proxy ("http" → wss proxy) or direct TCP. */
79
+ exposure?: "http" | "tcp";
80
+ computeType?: "CPU" | "GPU";
81
+ vcpuCount?: number;
82
+ gpuTypeIds?: string[];
83
+ containerDiskInGb?: number;
84
+ /** Extra env merged into the container. */
85
+ env?: Record<string, string>;
86
+ /** Poll budget for the Pod to reach RUNNING + expose its endpoint. */
87
+ timeoutMs?: number;
88
+ }
89
+ export interface DeployedWorkerPod {
90
+ podId: string;
91
+ /** ws/wss URL to set as NODETOOL_WORKER_URL. */
92
+ wsUrl: string;
93
+ pod: RunpodPod;
94
+ }
95
+ /**
96
+ * Deploy a NodeTool worker image as a persistent RunPod Pod and wait until it is
97
+ * RUNNING with a resolvable WebSocket endpoint. Does NOT read process.env — pass
98
+ * `apiKey` (from the secret store) and `workerToken` explicitly.
99
+ *
100
+ * Reaching RUNNING + having an endpoint does not guarantee the worker process
101
+ * has finished loading nodes; the caller should connect with retry.
102
+ */
103
+ export declare function deployWorkerPod(apiKey: string, opts: DeployWorkerPodOptions): Promise<DeployedWorkerPod>;
104
+ /** Poll GET /v1/pods/{id} until RUNNING with a resolvable endpoint. */
105
+ export declare function waitForPodEndpoint(apiKey: string, id: string, opts: {
106
+ internalPort: number;
107
+ exposure: "http" | "tcp";
108
+ timeoutMs?: number;
109
+ intervalMs?: number;
110
+ }): Promise<{
111
+ pod: RunpodPod;
112
+ wsUrl: string;
113
+ }>;
114
+ //# sourceMappingURL=runpod-rest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runpod-rest.d.ts","sourceRoot":"","sources":["../src/runpod-rest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * RunPod Pod management over the REST API (https://rest.runpod.io/v1).
3
+ *
4
+ * The serverless helpers in `runpod-api.ts` create templates/endpoints (the
5
+ * job/queue model) and read the API key from `process.env`. This module manages
6
+ * **persistent Pods** — the right shape for a long-lived NodeTool WebSocket
7
+ * worker the server/CLI attaches to — and takes the API key **explicitly** so it
8
+ * can be sourced from the per-user secret store (`getSecret`), never the
9
+ * environment.
10
+ *
11
+ * REST surface used: POST /v1/pods, GET /v1/pods/{id}, POST /v1/pods/{id}/stop,
12
+ * DELETE /v1/pods/{id}, GET /v1/pods.
13
+ */
14
+ const RUNPOD_REST_BASE_URL = "https://rest.runpod.io/v1";
15
+ /**
16
+ * Call the RunPod REST API with an explicitly-supplied key.
17
+ *
18
+ * @param apiKey RunPod API key (from the per-user secret store).
19
+ * @param endpoint Path under /v1, e.g. "pods" or "pods/<id>".
20
+ */
21
+ async function runpodRest(apiKey, endpoint, method = "GET", data) {
22
+ if (!apiKey)
23
+ throw new Error("RunPod API key is required");
24
+ const init = {
25
+ method,
26
+ headers: {
27
+ Authorization: `Bearer ${apiKey}`,
28
+ "Content-Type": "application/json",
29
+ Accept: "application/json"
30
+ },
31
+ signal: AbortSignal.timeout(60_000)
32
+ };
33
+ if (data && method === "POST")
34
+ init.body = JSON.stringify(data);
35
+ const response = await fetch(`${RUNPOD_REST_BASE_URL}/${endpoint}`, init);
36
+ if (!response.ok) {
37
+ const body = await response.text().catch(() => "");
38
+ throw new Error(`RunPod REST ${method} /${endpoint} failed (${response.status}): ${body}`);
39
+ }
40
+ if (method === "DELETE" && response.status === 204)
41
+ return {};
42
+ const text = await response.text();
43
+ return text ? JSON.parse(text) : {};
44
+ }
45
+ // ---------------------------------------------------------------------------
46
+ // Pod operations
47
+ // ---------------------------------------------------------------------------
48
+ /** Create (and deploy) a Pod. POST /v1/pods. */
49
+ export async function createPod(apiKey, spec) {
50
+ const pod = (await runpodRest(apiKey, "pods", "POST", spec));
51
+ if (!pod?.id)
52
+ throw new Error("RunPod createPod returned no pod id");
53
+ return pod;
54
+ }
55
+ /** Get a Pod by id. GET /v1/pods/{id}. */
56
+ export async function getPod(apiKey, id) {
57
+ return (await runpodRest(apiKey, `pods/${id}`));
58
+ }
59
+ /** List Pods. GET /v1/pods. */
60
+ export async function listPods(apiKey) {
61
+ const res = await runpodRest(apiKey, "pods");
62
+ if (Array.isArray(res))
63
+ return res;
64
+ const arr = res.pods;
65
+ return Array.isArray(arr) ? arr : [];
66
+ }
67
+ /** Stop a Pod (releases compute, keeps the volume). POST /v1/pods/{id}/stop. */
68
+ export async function stopPod(apiKey, id) {
69
+ await runpodRest(apiKey, `pods/${id}/stop`, "POST");
70
+ }
71
+ /** Terminate a Pod (deletes it). DELETE /v1/pods/{id}. */
72
+ export async function deletePod(apiKey, id) {
73
+ await runpodRest(apiKey, `pods/${id}`, "DELETE");
74
+ }
75
+ // ---------------------------------------------------------------------------
76
+ // Endpoint helpers
77
+ // ---------------------------------------------------------------------------
78
+ /**
79
+ * Direct TCP WebSocket URL for an exposed `/tcp` port, or null while the Pod
80
+ * lacks a public IP / port mapping. Preferred for large frames (no HTTP proxy).
81
+ */
82
+ export function podDirectWsUrl(pod, internalPort) {
83
+ const ext = pod.portMappings?.[String(internalPort)];
84
+ if (!pod.publicIp || !ext)
85
+ return null;
86
+ return `ws://${pod.publicIp}:${ext}`;
87
+ }
88
+ /**
89
+ * RunPod HTTP-proxy WebSocket URL for an exposed `/http` port. TLS-terminated
90
+ * by RunPod; subject to the proxy's size/timeout limits (fine for small frames).
91
+ */
92
+ export function podProxyWsUrl(podId, internalPort) {
93
+ return `wss://${podId}-${internalPort}.proxy.runpod.net`;
94
+ }
95
+ /**
96
+ * Deploy a NodeTool worker image as a persistent RunPod Pod and wait until it is
97
+ * RUNNING with a resolvable WebSocket endpoint. Does NOT read process.env — pass
98
+ * `apiKey` (from the secret store) and `workerToken` explicitly.
99
+ *
100
+ * Reaching RUNNING + having an endpoint does not guarantee the worker process
101
+ * has finished loading nodes; the caller should connect with retry.
102
+ */
103
+ export async function deployWorkerPod(apiKey, opts) {
104
+ const internalPort = opts.internalPort ?? 7777;
105
+ const exposure = opts.exposure ?? "http";
106
+ const env = { ...(opts.env ?? {}) };
107
+ if (opts.workerToken)
108
+ env.NODETOOL_WORKER_TOKEN = opts.workerToken;
109
+ const spec = {
110
+ name: opts.name,
111
+ imageName: opts.image,
112
+ computeType: opts.computeType ?? "CPU",
113
+ vcpuCount: opts.computeType === "GPU" ? undefined : (opts.vcpuCount ?? 4),
114
+ gpuTypeIds: opts.gpuTypeIds,
115
+ ports: [`${internalPort}/${exposure}`],
116
+ env,
117
+ containerDiskInGb: opts.containerDiskInGb ?? 20
118
+ };
119
+ const created = await createPod(apiKey, spec);
120
+ const { pod, wsUrl } = await waitForPodEndpoint(apiKey, created.id, {
121
+ internalPort,
122
+ exposure,
123
+ timeoutMs: opts.timeoutMs ?? 240_000
124
+ });
125
+ return { podId: created.id, wsUrl, pod };
126
+ }
127
+ /** Poll GET /v1/pods/{id} until RUNNING with a resolvable endpoint. */
128
+ export async function waitForPodEndpoint(apiKey, id, opts) {
129
+ const deadline = Date.now() + (opts.timeoutMs ?? 240_000);
130
+ const intervalMs = opts.intervalMs ?? 5_000;
131
+ let last;
132
+ while (Date.now() < deadline) {
133
+ const pod = await getPod(apiKey, id);
134
+ last = pod;
135
+ if (pod.desiredStatus === "TERMINATED" || pod.desiredStatus === "EXITED") {
136
+ throw new Error(`Pod ${id} reached terminal status ${pod.desiredStatus}`);
137
+ }
138
+ if (pod.desiredStatus === "RUNNING") {
139
+ if (opts.exposure === "http") {
140
+ return { pod, wsUrl: podProxyWsUrl(id, opts.internalPort) };
141
+ }
142
+ const direct = podDirectWsUrl(pod, opts.internalPort);
143
+ if (direct)
144
+ return { pod, wsUrl: direct };
145
+ }
146
+ await new Promise((r) => setTimeout(r, intervalMs));
147
+ }
148
+ throw new Error(`Pod ${id} did not become reachable within the timeout (last status: ${last?.desiredStatus ?? "unknown"})`);
149
+ }
150
+ //# sourceMappingURL=runpod-rest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runpod-rest.js","sourceRoot":"","sources":["../src/runpod-rest.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,7 @@
8
8
  * - Health monitoring
9
9
  * - Localhost detection (skips SSH for localhost deployments)
10
10
  */
11
- import { DockerRunGenerator } from "./docker-run.js";
12
- import { DockerDeployment, SelfHostedDeployment } from "./deployment-config.js";
11
+ import { DockerDeployment } from "./deployment-config.js";
13
12
  import { StateManager } from "./state.js";
14
13
  /**
15
14
  * Common interface for executors used in deployer code.
@@ -75,11 +74,8 @@ export declare class LocalExecutor {
75
74
  */
76
75
  close(): void;
77
76
  /**
78
- * Execute a command locally.
79
- *
80
- * Matches SSHConnection behavior by running in a shell.
81
- * This allows shell features like pipes, redirects, &&/|| operators,
82
- * and environment variable assignments.
77
+ * Execute a command locally in a shell, so pipes, redirects, &&/||, and
78
+ * environment-variable assignments work as they do over SSH.
83
79
  */
84
80
  execute(command: string, check?: boolean, timeout?: number): Promise<[exitCode: number, stdout: string, stderr: string]>;
85
81
  /**
@@ -88,55 +84,33 @@ export declare class LocalExecutor {
88
84
  mkdir(dirPath: string, _mode?: number, parents?: boolean): Promise<void>;
89
85
  }
90
86
  /**
91
- * Base class for SSH-based deployments.
92
- *
93
- * Type parameter `T` is the concrete deployment configuration type
94
- * (e.g. DockerDeployment).
87
+ * Deployer for Docker-based self-hosted deployments, over SSH or locally.
95
88
  */
96
- export declare abstract class BaseSSHDeployer<T extends SelfHostedDeployment> {
89
+ export declare class DockerDeployer {
97
90
  readonly deploymentName: string;
98
- readonly deployment: T;
91
+ readonly deployment: DockerDeployment;
99
92
  readonly stateManager: StateManager;
100
93
  readonly isLocalhost: boolean;
101
- constructor(deploymentName: string, deployment: T, stateManager?: StateManager);
102
- protected log(results: Record<string, unknown>, message: string): void;
103
- protected getExecutor(): Executor;
94
+ constructor(deploymentName: string, deployment: DockerDeployment, stateManager?: StateManager);
95
+ private log;
96
+ private getExecutor;
104
97
  /**
105
98
  * Use an executor within a callback, ensuring proper open/close lifecycle.
106
99
  */
107
- protected withExecutor<R>(fn: (executor: Executor) => Promise<R>): Promise<R>;
108
- protected uploadContent(ssh: Executor, content: string, remotePath: string): Promise<void>;
109
- protected createDirectories(ssh: Executor, results: Record<string, unknown>): Promise<void>;
110
- protected resolveLocalRuntimeCommand(): string;
111
- protected runtimeCommandForShell(): string;
112
- protected containerGenerator(runtimeCommand?: string): DockerRunGenerator;
113
- protected containerName(): string;
100
+ private withExecutor;
101
+ private createDirectories;
102
+ private resolveLocalRuntimeCommand;
103
+ private runtimeCommandForShell;
104
+ private containerGenerator;
105
+ private containerName;
114
106
  /**
115
107
  * Return host port for direct app mode (matches DockerRunGenerator).
116
108
  */
117
- protected appHostPort(): number;
118
- protected abstract createSpecificDirectories(ssh: Executor, workspacePath: string): Promise<void>;
119
- abstract plan(): Promise<DeployPlan>;
120
- abstract apply(opts?: {
121
- dryRun?: boolean;
122
- }): Promise<DeployResult>;
123
- abstract destroy(): Promise<DeployResult>;
124
- abstract status(): Promise<DeployStatus>;
125
- abstract logs(opts?: {
126
- service?: string;
127
- follow?: boolean;
128
- tail?: number;
129
- }): Promise<string>;
130
- }
131
- /**
132
- * Deployer for Docker-based self-hosted deployments.
133
- */
134
- export declare class DockerDeployer extends BaseSSHDeployer<DockerDeployment> {
135
- protected createSpecificDirectories(ssh: Executor, workspacePath: string): Promise<void>;
109
+ private appHostPort;
136
110
  plan(): Promise<DeployPlan>;
137
111
  apply(opts?: {
138
112
  dryRun?: boolean;
139
- }): Promise<DeployResult>;
113
+ }): Promise<DeployResult | DeployPlan>;
140
114
  private stopExistingContainer;
141
115
  private stopExistingContainerWithShell;
142
116
  private stopLocalPortConflictsWithShell;
@@ -1 +1 @@
1
- {"version":3,"file":"self-hosted.d.ts","sourceRoot":"","sources":["../src/self-hosted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,OAAO,EACL,kBAAkB,EAEnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,gBAAgB,EAChB,oBAAoB,EAIrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM1C;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,CACL,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE;AAED,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,0CAA0C;AAC1C,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKhD;AAqBD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA2EjD;AAMD;;GAEG;AACH,qBAAa,aAAa;IACxB;;;OAGG;IACH,IAAI,IAAI,aAAa;IAIrB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;;;OAMG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,KAAK,UAAO,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IA8C9D;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAQ,EAAE,OAAO,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ3E;AAMD;;;;;GAKG;AACH,8BAAsB,eAAe,CAAC,CAAC,SAAS,oBAAoB;IAClE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;gBAG5B,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,CAAC,EACb,YAAY,CAAC,EAAE,YAAY;IAU7B,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAUtE,SAAS,CAAC,WAAW,IAAI,QAAQ;IAgCjC;;OAEG;cACa,YAAY,CAAC,CAAC,EAC5B,EAAE,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GACrC,OAAO,CAAC,CAAC,CAAC;cAuBG,aAAa,CAC3B,GAAG,EAAE,QAAQ,EACb,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;cAsBA,iBAAiB,CAC/B,GAAG,EAAE,QAAQ,EACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC;IAqBhB,SAAS,CAAC,0BAA0B,IAAI,MAAM;IAmB9C,SAAS,CAAC,sBAAsB,IAAI,MAAM;IAO1C,SAAS,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,kBAAkB;IAyBzE,SAAS,CAAC,aAAa,IAAI,MAAM;IAIjC;;OAEG;IACH,SAAS,CAAC,WAAW,IAAI,MAAM;IAQ/B,SAAS,CAAC,QAAQ,CAAC,yBAAyB,CAC1C,GAAG,EAAE,QAAQ,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC;IAEhB,QAAQ,CAAC,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAClE,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;IACzC,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IACxC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,MAAM,CAAC;CACpB;AAMD;;GAEG;AACH,qBAAa,cAAe,SAAQ,eAAe,CAAC,gBAAgB,CAAC;cACnD,yBAAyB,CACvC,GAAG,EAAE,QAAQ,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC;IAKV,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IAsC3B,KAAK,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;YA4DjD,qBAAqB;YAyErB,8BAA8B;YA0C9B,+BAA+B;YA2C/B,cAAc;YA2Bd,WAAW;YAoDX,kBAAkB;IAchC,OAAO,CAAC,oBAAoB;IAItB,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;IA2DhC,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IA+B/B,IAAI,CAAC,IAAI,CAAC,EAAE;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,MAAM,CAAC;YAoBL,WAAW;IAoCzB,OAAO,CAAC,iBAAiB;CA8C1B"}
1
+ {"version":3,"file":"self-hosted.d.ts","sourceRoot":"","sources":["../src/self-hosted.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,6 @@
9
9
  * - Localhost detection (skips SSH for localhost deployments)
10
10
  */
11
11
  import { execSync, execFileSync } from "child_process";
12
- import * as dns from "dns";
13
12
  import * as fs from "fs";
14
13
  import * as os from "os";
15
14
  import * as path from "path";
@@ -47,85 +46,53 @@ function expandUser(p) {
47
46
  }
48
47
  return p;
49
48
  }
50
- /**
51
- * Check if host resolves to the local machine.
52
- */
53
- export function isLocalhost(host) {
54
- const localhostNames = new Set(["localhost", "127.0.0.1", "::1", "0.0.0.0"]);
55
- const normalizedHost = host.trim().toLowerCase();
56
- if (localhostNames.has(normalizedHost)) {
57
- return true;
49
+ const LOCALHOST_NAMES = new Set(["localhost", "127.0.0.1", "::1", "0.0.0.0"]);
50
+ /** Every address a host resolves to; empty when neither tool answers. */
51
+ function resolveIps(target) {
52
+ try {
53
+ // getent (Linux) prints "127.0.0.1 localhost" — the IP is the first field.
54
+ return execFileSync("getent", ["hosts", target], {
55
+ encoding: "utf-8",
56
+ timeout: 5000
57
+ })
58
+ .trim()
59
+ .split("\n")
60
+ .map((line) => line.trim().split(/\s+/)[0])
61
+ .filter((ip) => ip.length > 0);
58
62
  }
59
- function resolveIps(target) {
60
- const ips = new Set();
61
- try {
62
- // Synchronous DNS lookup via Node.js dns.resolve
63
- const addresses = dns.resolve4.length
64
- ? (() => {
65
- try {
66
- // Use execFileSync with getent (Linux) as primary method
67
- const result = execFileSync("getent", ["hosts", target], {
68
- encoding: "utf-8",
69
- timeout: 5000
70
- }).trim();
71
- const resolved = [];
72
- for (const line of result.split("\n")) {
73
- const ip = line.trim().split(/\s+/)[0];
74
- if (ip)
75
- resolved.push(ip);
76
- }
77
- return resolved;
78
- }
79
- catch {
80
- // getent not available (macOS) — fall back to dscacheutil or just skip
81
- try {
82
- const result = execFileSync("dscacheutil", ["-q", "host", "-a", "name", target], { encoding: "utf-8", timeout: 5000 }).trim();
83
- const resolved = [];
84
- for (const line of result.split("\n")) {
85
- const match = line.match(/^ip_address:\s+(.+)/);
86
- if (match)
87
- resolved.push(match[1].trim());
88
- }
89
- return resolved;
90
- }
91
- catch {
92
- return [];
93
- }
94
- }
95
- })()
96
- : [];
97
- for (const ip of addresses)
98
- ips.add(ip);
99
- }
100
- catch {
101
- // Unable to resolve
102
- }
103
- return ips;
63
+ catch {
64
+ // getent is Linux-only; macOS answers through dscacheutil instead.
104
65
  }
105
- let hostIps;
106
66
  try {
107
- hostIps = resolveIps(host);
67
+ return execFileSync("dscacheutil", ["-q", "host", "-a", "name", target], {
68
+ encoding: "utf-8",
69
+ timeout: 5000
70
+ })
71
+ .trim()
72
+ .split("\n")
73
+ .map((line) => line.match(/^ip_address:\s+(.+)/))
74
+ .filter((match) => match !== null)
75
+ .map((match) => match[1].trim());
108
76
  }
109
77
  catch {
110
- return false;
78
+ return [];
111
79
  }
112
- if (hostIps.size === 0)
113
- return false;
114
- const localIps = new Set();
115
- for (const target of ["localhost", os.hostname()]) {
116
- try {
117
- for (const ip of resolveIps(target))
118
- localIps.add(ip);
119
- }
120
- catch {
121
- continue;
122
- }
123
- }
124
- for (const ip of hostIps) {
125
- if (localIps.has(ip))
126
- return true;
80
+ }
81
+ /**
82
+ * Check if host resolves to the local machine.
83
+ */
84
+ export function isLocalhost(host) {
85
+ if (LOCALHOST_NAMES.has(host.trim().toLowerCase())) {
86
+ return true;
127
87
  }
128
- return false;
88
+ const hostIps = resolveIps(host);
89
+ if (hostIps.length === 0)
90
+ return false;
91
+ const localIps = new Set([
92
+ ...resolveIps("localhost"),
93
+ ...resolveIps(os.hostname())
94
+ ]);
95
+ return hostIps.some((ip) => localIps.has(ip));
129
96
  }
130
97
  // ---------------------------------------------------------------------------
131
98
  // LocalExecutor
@@ -148,11 +115,8 @@ export class LocalExecutor {
148
115
  // nothing to do
149
116
  }
150
117
  /**
151
- * Execute a command locally.
152
- *
153
- * Matches SSHConnection behavior by running in a shell.
154
- * This allows shell features like pipes, redirects, &&/|| operators,
155
- * and environment variable assignments.
118
+ * Execute a command locally in a shell, so pipes, redirects, &&/||, and
119
+ * environment-variable assignments work as they do over SSH.
156
120
  */
157
121
  async execute(command, check = true, timeout) {
158
122
  try {
@@ -194,15 +158,12 @@ export class LocalExecutor {
194
158
  }
195
159
  }
196
160
  // ---------------------------------------------------------------------------
197
- // BaseSSHDeployer (abstract)
161
+ // DockerDeployer
198
162
  // ---------------------------------------------------------------------------
199
163
  /**
200
- * Base class for SSH-based deployments.
201
- *
202
- * Type parameter `T` is the concrete deployment configuration type
203
- * (e.g. DockerDeployment).
164
+ * Deployer for Docker-based self-hosted deployments, over SSH or locally.
204
165
  */
205
- export class BaseSSHDeployer {
166
+ export class DockerDeployer {
206
167
  deploymentName;
207
168
  deployment;
208
169
  stateManager;
@@ -274,24 +235,6 @@ export class BaseSSHDeployer {
274
235
  }
275
236
  }
276
237
  }
277
- // ---- Content upload ----------------------------------------------------
278
- async uploadContent(ssh, content, remotePath) {
279
- if (this.isLocalhost) {
280
- const expanded = remotePath.startsWith("~")
281
- ? expandUser(remotePath)
282
- : remotePath;
283
- const dir = path.dirname(expanded);
284
- fs.mkdirSync(dir, { recursive: true });
285
- fs.writeFileSync(expanded, content, "utf-8");
286
- }
287
- else {
288
- // Remote upload via base64 to avoid shell escaping issues
289
- const b64Content = Buffer.from(content, "utf-8").toString("base64");
290
- const dirName = path.posix.dirname(remotePath);
291
- await ssh.execute(`mkdir -p ${safeShellQuote(dirName)}`, true);
292
- await ssh.execute(`echo ${b64Content} | base64 -d > ${safeShellQuote(remotePath)}`, true);
293
- }
294
- }
295
238
  // ---- Directory creation ------------------------------------------------
296
239
  async createDirectories(ssh, results) {
297
240
  this.log(results, "Creating directories...");
@@ -301,8 +244,8 @@ export class BaseSSHDeployer {
301
244
  await ssh.mkdir(`${workspacePath}/data`, 0o755, true);
302
245
  await ssh.mkdir(`${workspacePath}/assets`, 0o755, true);
303
246
  await ssh.mkdir(`${workspacePath}/temp`, 0o755, true);
304
- // Deployment-specific directories
305
- await this.createSpecificDirectories(ssh, workspacePath);
247
+ await ssh.mkdir(`${workspacePath}/proxy`, 0o755, true);
248
+ await ssh.mkdir(`${workspacePath}/acme`, 0o755, true);
306
249
  const hfCachePath = expandUser(this.deployment.paths.hf_cache);
307
250
  await ssh.mkdir(hfCachePath, 0o755, true);
308
251
  this.log(results, ` Created: ${hfCachePath}`);
@@ -372,18 +315,7 @@ export class BaseSSHDeployer {
372
315
  return 8000;
373
316
  return container?.port ?? 8000;
374
317
  }
375
- }
376
- // ---------------------------------------------------------------------------
377
- // DockerDeployer
378
- // ---------------------------------------------------------------------------
379
- /**
380
- * Deployer for Docker-based self-hosted deployments.
381
- */
382
- export class DockerDeployer extends BaseSSHDeployer {
383
- async createSpecificDirectories(ssh, workspacePath) {
384
- await ssh.mkdir(`${workspacePath}/proxy`, 0o755, true);
385
- await ssh.mkdir(`${workspacePath}/acme`, 0o755, true);
386
- }
318
+ // ---- Deployment operations ---------------------------------------------
387
319
  async plan() {
388
320
  const plan = {
389
321
  deployment_name: this.deploymentName,
@@ -413,8 +345,9 @@ export class DockerDeployer extends BaseSSHDeployer {
413
345
  return plan;
414
346
  }
415
347
  async apply(opts) {
348
+ // A dry run reports the plan itself rather than a deployment result.
416
349
  if (opts?.dryRun) {
417
- return (await this.plan());
350
+ return await this.plan();
418
351
  }
419
352
  const results = {
420
353
  deployment_name: this.deploymentName,
@@ -430,13 +363,9 @@ export class DockerDeployer extends BaseSSHDeployer {
430
363
  await this.withExecutor(async (executor) => {
431
364
  await this.createDirectories(executor, results);
432
365
  await this.ensureImage(executor, results);
433
- // Stop existing container if present
434
366
  await this.stopExistingContainer(executor, results);
435
- // Start container
436
367
  const containerRunHash = await this.startContainer(executor, results);
437
- // Check health
438
368
  await this.checkHealth(executor, results);
439
- // Update state with success
440
369
  const containerName = this.containerName();
441
370
  await this.stateManager.writeState(this.deploymentName, {
442
371
  status: DeploymentStatus.RUNNING,
@@ -650,7 +579,6 @@ export class DockerDeployer extends BaseSSHDeployer {
650
579
  await this.withExecutor(async (ssh) => {
651
580
  const containerName = this.containerName();
652
581
  const runtime = this.runtimeCommandForShell();
653
- // Stop container
654
582
  try {
655
583
  await ssh.execute(`${runtime} stop ${safeShellQuote(containerName)}`, false, 30);
656
584
  results.steps.push(`Container stopped: ${containerName}`);
@@ -660,7 +588,6 @@ export class DockerDeployer extends BaseSSHDeployer {
660
588
  results.steps.push(`Warning: Failed to stop container: ${e.stderr}`);
661
589
  }
662
590
  }
663
- // Remove container
664
591
  try {
665
592
  await ssh.execute(`${runtime} rm ${safeShellQuote(containerName)}`, false, 30);
666
593
  results.steps.push(`Container removed: ${containerName}`);
@@ -671,7 +598,6 @@ export class DockerDeployer extends BaseSSHDeployer {
671
598
  }
672
599
  throw e;
673
600
  }
674
- // Update state
675
601
  await this.stateManager.updateDeploymentStatus(this.deploymentName, DeploymentStatus.DESTROYED);
676
602
  });
677
603
  }