@otterdeploy/docker 0.2.0 → 0.3.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/README.md +29 -20
- package/dist/index.d.mts +1 -2
- package/dist/index.mjs +6 -2947
- package/package.json +3 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,2947 +1,6 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import * as https from "node:https";
|
|
6
|
-
|
|
7
|
-
import { Duplex, PassThrough, Readable } from "node:stream";
|
|
8
|
-
import * as grpc from "@grpc/grpc-js";
|
|
9
|
-
import * as protoLoader from "@grpc/proto-loader";
|
|
10
|
-
import { randomUUID } from "node:crypto";
|
|
11
|
-
import { EventEmitter } from "node:events";
|
|
12
|
-
|
|
13
|
-
//#region src/errors.ts
|
|
14
|
-
var DockerBadRequestError = class extends TaggedError("DockerBadRequestError")() {
|
|
15
|
-
statusCode = 400;
|
|
16
|
-
};
|
|
17
|
-
var DockerUnauthorizedError = class extends TaggedError("DockerUnauthorizedError")() {
|
|
18
|
-
statusCode = 401;
|
|
19
|
-
};
|
|
20
|
-
var DockerForbiddenError = class extends TaggedError("DockerForbiddenError")() {
|
|
21
|
-
statusCode = 403;
|
|
22
|
-
};
|
|
23
|
-
var DockerNotFoundError = class extends TaggedError("DockerNotFoundError")() {
|
|
24
|
-
statusCode = 404;
|
|
25
|
-
};
|
|
26
|
-
var DockerConflictError = class extends TaggedError("DockerConflictError")() {
|
|
27
|
-
statusCode = 409;
|
|
28
|
-
};
|
|
29
|
-
var DockerServerError = class extends TaggedError("DockerServerError")() {
|
|
30
|
-
statusCode = 500;
|
|
31
|
-
};
|
|
32
|
-
var DockerServiceUnavailableError = class extends TaggedError("DockerServiceUnavailableError")() {
|
|
33
|
-
statusCode = 503;
|
|
34
|
-
};
|
|
35
|
-
var DockerNetworkError = class extends TaggedError("DockerNetworkError")() {};
|
|
36
|
-
var DockerTimeoutError = class extends TaggedError("DockerTimeoutError")() {};
|
|
37
|
-
var DockerAbortError = class extends TaggedError("DockerAbortError")() {};
|
|
38
|
-
var DockerDecodeError = class extends TaggedError("DockerDecodeError")() {};
|
|
39
|
-
var DockerUnknownError = class extends TaggedError("DockerUnknownError")() {};
|
|
40
|
-
/**
|
|
41
|
-
* Maps an HTTP status code to the appropriate Docker error class.
|
|
42
|
-
* Unknown status codes produce a DockerUnknownError.
|
|
43
|
-
*/
|
|
44
|
-
function statusCodeToError(statusCode, message) {
|
|
45
|
-
switch (statusCode) {
|
|
46
|
-
case 400: return new DockerBadRequestError({ message });
|
|
47
|
-
case 401: return new DockerUnauthorizedError({ message });
|
|
48
|
-
case 403: return new DockerForbiddenError({ message });
|
|
49
|
-
case 404: return new DockerNotFoundError({ message });
|
|
50
|
-
case 409: return new DockerConflictError({ message });
|
|
51
|
-
case 500: return new DockerServerError({ message });
|
|
52
|
-
case 503: return new DockerServiceUnavailableError({ message });
|
|
53
|
-
default: return new DockerUnknownError({
|
|
54
|
-
message,
|
|
55
|
-
statusCode
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
//#endregion
|
|
61
|
-
//#region src/transport/helpers.ts
|
|
62
|
-
/**
|
|
63
|
-
* Shared helper functions used across all transport implementations.
|
|
64
|
-
*/
|
|
65
|
-
/**
|
|
66
|
-
* Builds the request path, appending query parameters if present.
|
|
67
|
-
*/
|
|
68
|
-
function buildPath(path, query) {
|
|
69
|
-
if (!query || Object.keys(query).length === 0) return path;
|
|
70
|
-
const params = new URLSearchParams();
|
|
71
|
-
for (const [key, value] of Object.entries(query)) if (value !== void 0 && value !== null) params.append(key, String(value));
|
|
72
|
-
return `${path}?${params.toString()}`;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Collects all chunks from a readable stream into a single string.
|
|
76
|
-
*/
|
|
77
|
-
function collectBody(stream) {
|
|
78
|
-
return new Promise((resolve, reject) => {
|
|
79
|
-
const chunks = [];
|
|
80
|
-
stream.on("data", (chunk) => chunks.push(chunk));
|
|
81
|
-
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
82
|
-
stream.on("error", reject);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Extracts error message from Docker API error response body.
|
|
87
|
-
* Docker typically returns `{ message: "..." }`.
|
|
88
|
-
*/
|
|
89
|
-
function extractErrorMessage(body) {
|
|
90
|
-
try {
|
|
91
|
-
const parsed = JSON.parse(body);
|
|
92
|
-
if (typeof parsed === "object" && parsed !== null && typeof parsed.message === "string") return parsed.message;
|
|
93
|
-
} catch {}
|
|
94
|
-
return body || "Unknown error";
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
//#endregion
|
|
98
|
-
//#region src/transport/unix-transport.ts
|
|
99
|
-
var UnixTransport = class {
|
|
100
|
-
socketPath;
|
|
101
|
-
requestFn;
|
|
102
|
-
constructor(options) {
|
|
103
|
-
this.socketPath = options.socketPath ?? process.env.DOCKER_HOST?.replace("unix://", "") ?? "/var/run/docker.sock";
|
|
104
|
-
this.requestFn = options._requestFn ?? http.request;
|
|
105
|
-
}
|
|
106
|
-
async dial(options) {
|
|
107
|
-
return Result.tryPromise({
|
|
108
|
-
try: () => this.performRequest(options, false),
|
|
109
|
-
catch: (cause) => this.convertError(cause)
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
async dialStream(options) {
|
|
113
|
-
return Result.tryPromise({
|
|
114
|
-
try: () => this.performRequest(options, true),
|
|
115
|
-
catch: (cause) => this.convertError(cause)
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
async dialHijack(options) {
|
|
119
|
-
return Result.tryPromise({
|
|
120
|
-
try: () => this.performHijack(options),
|
|
121
|
-
catch: (cause) => this.convertError(cause)
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
destroy() {}
|
|
125
|
-
performHijack(options) {
|
|
126
|
-
return new Promise((resolve, reject) => {
|
|
127
|
-
const requestPath = buildPath(options.path, options.query);
|
|
128
|
-
const headers = {
|
|
129
|
-
Connection: "Upgrade",
|
|
130
|
-
Upgrade: "tcp",
|
|
131
|
-
...options.headers
|
|
132
|
-
};
|
|
133
|
-
if (options.authconfig) headers["X-Registry-Auth"] = Buffer.from(JSON.stringify(options.authconfig)).toString("base64");
|
|
134
|
-
const body = options.body;
|
|
135
|
-
let bodyStr;
|
|
136
|
-
if (body !== void 0 && typeof body !== "string" && !Buffer.isBuffer(body)) {
|
|
137
|
-
bodyStr = JSON.stringify(body);
|
|
138
|
-
if (!headers["Content-Type"] && !headers["content-type"]) headers["Content-Type"] = "application/json";
|
|
139
|
-
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
140
|
-
}
|
|
141
|
-
const req = this.requestFn({
|
|
142
|
-
socketPath: this.socketPath,
|
|
143
|
-
path: requestPath,
|
|
144
|
-
method: options.method,
|
|
145
|
-
headers
|
|
146
|
-
}, (res) => {
|
|
147
|
-
reject(new DockerNetworkError({
|
|
148
|
-
message: `Expected upgrade response, got status ${res.statusCode}`,
|
|
149
|
-
cause: void 0
|
|
150
|
-
}));
|
|
151
|
-
});
|
|
152
|
-
req.on("upgrade", (_res, socket, _head) => {
|
|
153
|
-
resolve(socket);
|
|
154
|
-
});
|
|
155
|
-
req.on("error", (err) => {
|
|
156
|
-
reject(new DockerNetworkError({
|
|
157
|
-
message: `Connection error: ${err.message}`,
|
|
158
|
-
cause: err
|
|
159
|
-
}));
|
|
160
|
-
});
|
|
161
|
-
if (bodyStr !== void 0) req.write(bodyStr);
|
|
162
|
-
req.end();
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
performRequest(options, isStream) {
|
|
166
|
-
return new Promise((resolve, reject) => {
|
|
167
|
-
const requestPath = buildPath(options.path, options.query);
|
|
168
|
-
const headers = { ...options.headers };
|
|
169
|
-
if (options.authconfig) headers["X-Registry-Auth"] = Buffer.from(JSON.stringify(options.authconfig)).toString("base64");
|
|
170
|
-
if (options.registryconfig) headers["X-Registry-Config"] = Buffer.from(JSON.stringify(options.registryconfig)).toString("base64");
|
|
171
|
-
const body = options.body;
|
|
172
|
-
const isStreamBody = body !== null && body !== void 0 && typeof body === "object" && typeof body.pipe === "function";
|
|
173
|
-
const isBufferBody = Buffer.isBuffer(body);
|
|
174
|
-
const isStringBody = typeof body === "string";
|
|
175
|
-
let bodyStr;
|
|
176
|
-
if (body !== void 0 && !isStreamBody && !isBufferBody && !isStringBody) {
|
|
177
|
-
bodyStr = JSON.stringify(body);
|
|
178
|
-
if (!headers["Content-Type"] && !headers["content-type"]) headers["Content-Type"] = "application/json";
|
|
179
|
-
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
180
|
-
} else if (isBufferBody) headers["Content-Length"] = body.length.toString();
|
|
181
|
-
else if (isStringBody) headers["Content-Length"] = Buffer.byteLength(body).toString();
|
|
182
|
-
else if (isStreamBody) headers["Transfer-Encoding"] = "chunked";
|
|
183
|
-
const req = this.requestFn({
|
|
184
|
-
socketPath: this.socketPath,
|
|
185
|
-
path: requestPath,
|
|
186
|
-
method: options.method,
|
|
187
|
-
headers
|
|
188
|
-
}, (res) => {
|
|
189
|
-
const statusCode = res.statusCode ?? 0;
|
|
190
|
-
const responseHeaders = res.headers ?? {};
|
|
191
|
-
const isSuccess = options.statusCodes[statusCode] === true;
|
|
192
|
-
if (isStream && isSuccess) {
|
|
193
|
-
resolve(res);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
collectBody(res).then((bodyText) => {
|
|
197
|
-
if (isSuccess) {
|
|
198
|
-
if (statusCode === 204 || bodyText.length === 0) {
|
|
199
|
-
resolve({
|
|
200
|
-
statusCode,
|
|
201
|
-
headers: responseHeaders,
|
|
202
|
-
body: null
|
|
203
|
-
});
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
try {
|
|
207
|
-
resolve({
|
|
208
|
-
statusCode,
|
|
209
|
-
headers: responseHeaders,
|
|
210
|
-
body: JSON.parse(bodyText)
|
|
211
|
-
});
|
|
212
|
-
} catch {
|
|
213
|
-
resolve({
|
|
214
|
-
statusCode,
|
|
215
|
-
headers: responseHeaders,
|
|
216
|
-
body: bodyText
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
} else reject(statusCodeToError(statusCode, extractErrorMessage(bodyText)));
|
|
220
|
-
}).catch((collectErr) => {
|
|
221
|
-
reject(new DockerNetworkError({
|
|
222
|
-
message: `Failed to read response body: ${String(collectErr)}`,
|
|
223
|
-
cause: collectErr
|
|
224
|
-
}));
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
req.on("error", (err) => {
|
|
228
|
-
reject(new DockerNetworkError({
|
|
229
|
-
message: `Connection error: ${err.message}`,
|
|
230
|
-
cause: err
|
|
231
|
-
}));
|
|
232
|
-
});
|
|
233
|
-
if (options.timeout !== void 0) req.setTimeout(options.timeout, () => {
|
|
234
|
-
req.destroy();
|
|
235
|
-
reject(new DockerTimeoutError({
|
|
236
|
-
message: `Request timed out after ${options.timeout}ms`,
|
|
237
|
-
timeoutMs: options.timeout
|
|
238
|
-
}));
|
|
239
|
-
});
|
|
240
|
-
if (options.signal) {
|
|
241
|
-
if (options.signal.aborted) {
|
|
242
|
-
req.destroy();
|
|
243
|
-
reject(new DockerAbortError({ message: "Request aborted" }));
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
options.signal.addEventListener("abort", () => {
|
|
247
|
-
req.destroy();
|
|
248
|
-
reject(new DockerAbortError({ message: "Request aborted" }));
|
|
249
|
-
}, { once: true });
|
|
250
|
-
}
|
|
251
|
-
if (isStreamBody) body.pipe(req);
|
|
252
|
-
else if (isBufferBody) {
|
|
253
|
-
req.write(body);
|
|
254
|
-
req.end();
|
|
255
|
-
} else if (isStringBody) {
|
|
256
|
-
req.write(body);
|
|
257
|
-
req.end();
|
|
258
|
-
} else if (bodyStr !== void 0) {
|
|
259
|
-
req.write(bodyStr);
|
|
260
|
-
req.end();
|
|
261
|
-
} else req.end();
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Converts errors thrown from the inner promise back into DockerError types.
|
|
266
|
-
* Errors that are already tagged DockerErrors pass through; unknown errors
|
|
267
|
-
* become DockerNetworkError.
|
|
268
|
-
*/
|
|
269
|
-
convertError(cause) {
|
|
270
|
-
if (cause !== null && typeof cause === "object" && "_tag" in cause) return cause;
|
|
271
|
-
return new DockerNetworkError({
|
|
272
|
-
message: `Unexpected error: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
273
|
-
cause
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
//#endregion
|
|
279
|
-
//#region src/transport/tcp-transport.ts
|
|
280
|
-
var TcpTransport = class {
|
|
281
|
-
host;
|
|
282
|
-
port;
|
|
283
|
-
agent;
|
|
284
|
-
useHttps;
|
|
285
|
-
requestFn;
|
|
286
|
-
constructor(options) {
|
|
287
|
-
this.useHttps = !!options.tls;
|
|
288
|
-
this.host = options.host;
|
|
289
|
-
this.port = options.port ?? (this.useHttps ? 2376 : 2375);
|
|
290
|
-
if (options.tls) this.agent = new https.Agent({
|
|
291
|
-
ca: options.tls.ca,
|
|
292
|
-
cert: options.tls.cert,
|
|
293
|
-
key: options.tls.key,
|
|
294
|
-
rejectUnauthorized: options.tls.rejectUnauthorized ?? true
|
|
295
|
-
});
|
|
296
|
-
this.requestFn = options._requestFn ?? (this.useHttps ? https.request : http.request);
|
|
297
|
-
}
|
|
298
|
-
async dial(options) {
|
|
299
|
-
return Result.tryPromise({
|
|
300
|
-
try: () => this.performRequest(options, false),
|
|
301
|
-
catch: (cause) => this.convertError(cause)
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
async dialStream(options) {
|
|
305
|
-
return Result.tryPromise({
|
|
306
|
-
try: () => this.performRequest(options, true),
|
|
307
|
-
catch: (cause) => this.convertError(cause)
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
async dialHijack(options) {
|
|
311
|
-
return Result.tryPromise({
|
|
312
|
-
try: () => this.performHijack(options),
|
|
313
|
-
catch: (cause) => this.convertError(cause)
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
destroy() {
|
|
317
|
-
if (this.agent) this.agent.destroy();
|
|
318
|
-
}
|
|
319
|
-
performHijack(options) {
|
|
320
|
-
return new Promise((resolve, reject) => {
|
|
321
|
-
const requestPath = buildPath(options.path, options.query);
|
|
322
|
-
const headers = {
|
|
323
|
-
Connection: "Upgrade",
|
|
324
|
-
Upgrade: "tcp",
|
|
325
|
-
...options.headers
|
|
326
|
-
};
|
|
327
|
-
if (options.authconfig) headers["X-Registry-Auth"] = Buffer.from(JSON.stringify(options.authconfig)).toString("base64");
|
|
328
|
-
const body = options.body;
|
|
329
|
-
let bodyStr;
|
|
330
|
-
if (body !== void 0 && typeof body !== "string" && !Buffer.isBuffer(body)) {
|
|
331
|
-
bodyStr = JSON.stringify(body);
|
|
332
|
-
if (!headers["Content-Type"] && !headers["content-type"]) headers["Content-Type"] = "application/json";
|
|
333
|
-
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
334
|
-
}
|
|
335
|
-
const requestOpts = {
|
|
336
|
-
hostname: this.host,
|
|
337
|
-
port: this.port,
|
|
338
|
-
path: requestPath,
|
|
339
|
-
method: options.method,
|
|
340
|
-
headers
|
|
341
|
-
};
|
|
342
|
-
if (this.agent) requestOpts.agent = this.agent;
|
|
343
|
-
const req = this.requestFn(requestOpts, (res) => {
|
|
344
|
-
reject(new DockerNetworkError({
|
|
345
|
-
message: `Expected upgrade response, got status ${res.statusCode}`,
|
|
346
|
-
cause: void 0
|
|
347
|
-
}));
|
|
348
|
-
});
|
|
349
|
-
req.on("upgrade", (_res, socket, _head) => {
|
|
350
|
-
resolve(socket);
|
|
351
|
-
});
|
|
352
|
-
req.on("error", (err) => {
|
|
353
|
-
reject(new DockerNetworkError({
|
|
354
|
-
message: `Connection error: ${err.message}`,
|
|
355
|
-
cause: err
|
|
356
|
-
}));
|
|
357
|
-
});
|
|
358
|
-
if (bodyStr !== void 0) req.write(bodyStr);
|
|
359
|
-
req.end();
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
performRequest(options, isStream) {
|
|
363
|
-
return new Promise((resolve, reject) => {
|
|
364
|
-
const requestPath = buildPath(options.path, options.query);
|
|
365
|
-
const headers = { ...options.headers };
|
|
366
|
-
if (options.authconfig) headers["X-Registry-Auth"] = Buffer.from(JSON.stringify(options.authconfig)).toString("base64");
|
|
367
|
-
if (options.registryconfig) headers["X-Registry-Config"] = Buffer.from(JSON.stringify(options.registryconfig)).toString("base64");
|
|
368
|
-
const body = options.body;
|
|
369
|
-
const isStreamBody = body !== null && body !== void 0 && typeof body === "object" && typeof body.pipe === "function";
|
|
370
|
-
const isBufferBody = Buffer.isBuffer(body);
|
|
371
|
-
const isStringBody = typeof body === "string";
|
|
372
|
-
let bodyStr;
|
|
373
|
-
if (body !== void 0 && !isStreamBody && !isBufferBody && !isStringBody) {
|
|
374
|
-
bodyStr = JSON.stringify(body);
|
|
375
|
-
if (!headers["Content-Type"] && !headers["content-type"]) headers["Content-Type"] = "application/json";
|
|
376
|
-
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
377
|
-
} else if (isBufferBody) headers["Content-Length"] = body.length.toString();
|
|
378
|
-
else if (isStringBody) headers["Content-Length"] = Buffer.byteLength(body).toString();
|
|
379
|
-
else if (isStreamBody) headers["Transfer-Encoding"] = "chunked";
|
|
380
|
-
const requestOpts = {
|
|
381
|
-
hostname: this.host,
|
|
382
|
-
port: this.port,
|
|
383
|
-
path: requestPath,
|
|
384
|
-
method: options.method,
|
|
385
|
-
headers
|
|
386
|
-
};
|
|
387
|
-
if (this.agent) requestOpts.agent = this.agent;
|
|
388
|
-
const req = this.requestFn(requestOpts, (res) => {
|
|
389
|
-
const statusCode = res.statusCode ?? 0;
|
|
390
|
-
const responseHeaders = res.headers ?? {};
|
|
391
|
-
const isSuccess = options.statusCodes[statusCode] === true;
|
|
392
|
-
if (isStream && isSuccess) {
|
|
393
|
-
resolve(res);
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
collectBody(res).then((bodyText) => {
|
|
397
|
-
if (isSuccess) {
|
|
398
|
-
if (statusCode === 204 || bodyText.length === 0) {
|
|
399
|
-
resolve({
|
|
400
|
-
statusCode,
|
|
401
|
-
headers: responseHeaders,
|
|
402
|
-
body: null
|
|
403
|
-
});
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
try {
|
|
407
|
-
resolve({
|
|
408
|
-
statusCode,
|
|
409
|
-
headers: responseHeaders,
|
|
410
|
-
body: JSON.parse(bodyText)
|
|
411
|
-
});
|
|
412
|
-
} catch {
|
|
413
|
-
resolve({
|
|
414
|
-
statusCode,
|
|
415
|
-
headers: responseHeaders,
|
|
416
|
-
body: bodyText
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
} else reject(statusCodeToError(statusCode, extractErrorMessage(bodyText)));
|
|
420
|
-
}).catch((collectErr) => {
|
|
421
|
-
reject(new DockerNetworkError({
|
|
422
|
-
message: `Failed to read response body: ${String(collectErr)}`,
|
|
423
|
-
cause: collectErr
|
|
424
|
-
}));
|
|
425
|
-
});
|
|
426
|
-
});
|
|
427
|
-
req.on("error", (err) => {
|
|
428
|
-
reject(new DockerNetworkError({
|
|
429
|
-
message: `Connection error: ${err.message}`,
|
|
430
|
-
cause: err
|
|
431
|
-
}));
|
|
432
|
-
});
|
|
433
|
-
if (options.timeout !== void 0) req.setTimeout(options.timeout, () => {
|
|
434
|
-
req.destroy();
|
|
435
|
-
reject(new DockerTimeoutError({
|
|
436
|
-
message: `Request timed out after ${options.timeout}ms`,
|
|
437
|
-
timeoutMs: options.timeout
|
|
438
|
-
}));
|
|
439
|
-
});
|
|
440
|
-
if (options.signal) {
|
|
441
|
-
if (options.signal.aborted) {
|
|
442
|
-
req.destroy();
|
|
443
|
-
reject(new DockerAbortError({ message: "Request aborted" }));
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
options.signal.addEventListener("abort", () => {
|
|
447
|
-
req.destroy();
|
|
448
|
-
reject(new DockerAbortError({ message: "Request aborted" }));
|
|
449
|
-
}, { once: true });
|
|
450
|
-
}
|
|
451
|
-
if (isStreamBody) body.pipe(req);
|
|
452
|
-
else if (isBufferBody) {
|
|
453
|
-
req.write(body);
|
|
454
|
-
req.end();
|
|
455
|
-
} else if (isStringBody) {
|
|
456
|
-
req.write(body);
|
|
457
|
-
req.end();
|
|
458
|
-
} else if (bodyStr !== void 0) {
|
|
459
|
-
req.write(bodyStr);
|
|
460
|
-
req.end();
|
|
461
|
-
} else req.end();
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Converts errors thrown from the inner promise back into DockerError types.
|
|
466
|
-
* Errors that are already tagged DockerErrors pass through; unknown errors
|
|
467
|
-
* become DockerNetworkError.
|
|
468
|
-
*/
|
|
469
|
-
convertError(cause) {
|
|
470
|
-
if (cause !== null && typeof cause === "object" && "_tag" in cause) return cause;
|
|
471
|
-
return new DockerNetworkError({
|
|
472
|
-
message: `Unexpected error: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
473
|
-
cause
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
|
|
478
|
-
//#endregion
|
|
479
|
-
//#region src/transport/ssh-transport.ts
|
|
480
|
-
/**
|
|
481
|
-
* Builds a raw HTTP/1.1 request string to send over the dial-stdio stream.
|
|
482
|
-
*/
|
|
483
|
-
function buildHttpRequest(options) {
|
|
484
|
-
const requestPath = buildPath(options.path, options.query);
|
|
485
|
-
const headers = {
|
|
486
|
-
Host: "docker",
|
|
487
|
-
...options.headers
|
|
488
|
-
};
|
|
489
|
-
if (options.authconfig) headers["X-Registry-Auth"] = Buffer.from(JSON.stringify(options.authconfig)).toString("base64");
|
|
490
|
-
if (options.registryconfig) headers["X-Registry-Config"] = Buffer.from(JSON.stringify(options.registryconfig)).toString("base64");
|
|
491
|
-
const body = options.body;
|
|
492
|
-
const isStreamBody = body !== null && body !== void 0 && typeof body === "object" && typeof body.pipe === "function";
|
|
493
|
-
const isBufferBody = Buffer.isBuffer(body);
|
|
494
|
-
const isStringBody = typeof body === "string";
|
|
495
|
-
let bodyStr;
|
|
496
|
-
if (body !== void 0 && !isStreamBody && !isBufferBody && !isStringBody) {
|
|
497
|
-
bodyStr = JSON.stringify(body);
|
|
498
|
-
if (!headers["Content-Type"] && !headers["content-type"]) headers["Content-Type"] = "application/json";
|
|
499
|
-
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
500
|
-
} else if (isBufferBody) {
|
|
501
|
-
bodyStr = body.toString();
|
|
502
|
-
headers["Content-Length"] = body.length.toString();
|
|
503
|
-
} else if (isStringBody) {
|
|
504
|
-
bodyStr = body;
|
|
505
|
-
headers["Content-Length"] = Buffer.byteLength(body).toString();
|
|
506
|
-
} else if (isStreamBody) headers["Transfer-Encoding"] = "chunked";
|
|
507
|
-
let header = `${options.method} ${requestPath} HTTP/1.1\r\n`;
|
|
508
|
-
for (const [key, value] of Object.entries(headers)) header += `${key}: ${value}\r\n`;
|
|
509
|
-
header += "\r\n";
|
|
510
|
-
return {
|
|
511
|
-
header,
|
|
512
|
-
bodyStr
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Parses a raw HTTP response from the stream into status code, headers, and body.
|
|
517
|
-
*/
|
|
518
|
-
function parseHttpResponse(raw) {
|
|
519
|
-
const headerEndIdx = raw.indexOf("\r\n\r\n");
|
|
520
|
-
const headerSection = headerEndIdx >= 0 ? raw.slice(0, headerEndIdx) : raw;
|
|
521
|
-
const body = headerEndIdx >= 0 ? raw.slice(headerEndIdx + 4) : "";
|
|
522
|
-
const lines = headerSection.split("\r\n");
|
|
523
|
-
const statusMatch = (lines[0] ?? "").match(/^HTTP\/\d\.\d\s+(\d+)/);
|
|
524
|
-
const statusCode = statusMatch?.[1] ? Number.parseInt(statusMatch[1], 10) : 0;
|
|
525
|
-
const headers = {};
|
|
526
|
-
for (let i = 1; i < lines.length; i++) {
|
|
527
|
-
const line = lines[i];
|
|
528
|
-
if (!line) continue;
|
|
529
|
-
const colonIdx = line.indexOf(":");
|
|
530
|
-
if (colonIdx > 0) {
|
|
531
|
-
const key = line.slice(0, colonIdx).trim().toLowerCase();
|
|
532
|
-
headers[key] = line.slice(colonIdx + 1).trim();
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
return {
|
|
536
|
-
statusCode,
|
|
537
|
-
headers,
|
|
538
|
-
body
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
var SshTransport = class {
|
|
542
|
-
host;
|
|
543
|
-
port;
|
|
544
|
-
username;
|
|
545
|
-
privateKey;
|
|
546
|
-
passphrase;
|
|
547
|
-
clientFactory;
|
|
548
|
-
constructor(opts) {
|
|
549
|
-
this.host = opts.host;
|
|
550
|
-
this.port = opts.port ?? 22;
|
|
551
|
-
this.username = opts.username;
|
|
552
|
-
this.privateKey = opts.privateKey;
|
|
553
|
-
this.passphrase = opts.passphrase;
|
|
554
|
-
this.clientFactory = opts._clientFactory ?? (() => new Client());
|
|
555
|
-
}
|
|
556
|
-
async dial(options) {
|
|
557
|
-
return Result.tryPromise({
|
|
558
|
-
try: () => this.performRequest(options, false),
|
|
559
|
-
catch: (cause) => this.convertError(cause)
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
async dialStream(options) {
|
|
563
|
-
return Result.tryPromise({
|
|
564
|
-
try: () => this.performRequest(options, true),
|
|
565
|
-
catch: (cause) => this.convertError(cause)
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
async dialHijack(_options) {
|
|
569
|
-
return Result.err(new DockerNetworkError({
|
|
570
|
-
message: "dialHijack is not supported over SSH transport",
|
|
571
|
-
cause: void 0
|
|
572
|
-
}));
|
|
573
|
-
}
|
|
574
|
-
destroy() {}
|
|
575
|
-
/**
|
|
576
|
-
* Connects to the SSH host, runs `docker system dial-stdio`, writes an
|
|
577
|
-
* HTTP request over the resulting bidirectional stream, and parses the
|
|
578
|
-
* HTTP response.
|
|
579
|
-
*/
|
|
580
|
-
performRequest(options, isStream) {
|
|
581
|
-
return new Promise((resolve, reject) => {
|
|
582
|
-
const client = this.clientFactory();
|
|
583
|
-
client.on("ready", () => {
|
|
584
|
-
client.exec("docker system dial-stdio", (err, stream) => {
|
|
585
|
-
if (err) {
|
|
586
|
-
client.end();
|
|
587
|
-
reject(new DockerNetworkError({
|
|
588
|
-
message: `SSH exec error: ${err.message}`,
|
|
589
|
-
cause: err
|
|
590
|
-
}));
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
const { header, bodyStr: httpBody } = buildHttpRequest(options);
|
|
594
|
-
stream.write(header);
|
|
595
|
-
const body = options.body;
|
|
596
|
-
if (body !== null && body !== void 0 && typeof body === "object" && typeof body.pipe === "function") body.pipe(stream, { end: false });
|
|
597
|
-
else if (httpBody !== void 0) stream.write(httpBody);
|
|
598
|
-
const chunks = [];
|
|
599
|
-
stream.on("data", (chunk) => {
|
|
600
|
-
chunks.push(chunk);
|
|
601
|
-
});
|
|
602
|
-
stream.on("end", () => {
|
|
603
|
-
client.end();
|
|
604
|
-
const { statusCode, headers, body } = parseHttpResponse(Buffer.concat(chunks).toString("utf-8"));
|
|
605
|
-
const isSuccess = options.statusCodes[statusCode] === true;
|
|
606
|
-
if (isStream && isSuccess) {
|
|
607
|
-
resolve(new Readable({ read() {
|
|
608
|
-
this.push(body ? Buffer.from(body) : null);
|
|
609
|
-
this.push(null);
|
|
610
|
-
} }));
|
|
611
|
-
return;
|
|
612
|
-
}
|
|
613
|
-
if (isSuccess) {
|
|
614
|
-
if (statusCode === 204 || body.length === 0) {
|
|
615
|
-
resolve({
|
|
616
|
-
statusCode,
|
|
617
|
-
headers,
|
|
618
|
-
body: null
|
|
619
|
-
});
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
try {
|
|
623
|
-
resolve({
|
|
624
|
-
statusCode,
|
|
625
|
-
headers,
|
|
626
|
-
body: JSON.parse(body)
|
|
627
|
-
});
|
|
628
|
-
} catch {
|
|
629
|
-
resolve({
|
|
630
|
-
statusCode,
|
|
631
|
-
headers,
|
|
632
|
-
body
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
} else reject(statusCodeToError(statusCode, extractErrorMessage(body)));
|
|
636
|
-
});
|
|
637
|
-
stream.on("error", (streamErr) => {
|
|
638
|
-
client.end();
|
|
639
|
-
reject(new DockerNetworkError({
|
|
640
|
-
message: `Stream error: ${streamErr.message}`,
|
|
641
|
-
cause: streamErr
|
|
642
|
-
}));
|
|
643
|
-
});
|
|
644
|
-
});
|
|
645
|
-
});
|
|
646
|
-
client.on("error", (connErr) => {
|
|
647
|
-
reject(new DockerNetworkError({
|
|
648
|
-
message: `SSH connection error: ${connErr.message}`,
|
|
649
|
-
cause: connErr
|
|
650
|
-
}));
|
|
651
|
-
});
|
|
652
|
-
client.connect({
|
|
653
|
-
host: this.host,
|
|
654
|
-
port: this.port,
|
|
655
|
-
username: this.username,
|
|
656
|
-
privateKey: this.privateKey,
|
|
657
|
-
passphrase: this.passphrase
|
|
658
|
-
});
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Converts errors thrown from the inner promise back into DockerError types.
|
|
663
|
-
* Errors that are already tagged DockerErrors pass through; unknown errors
|
|
664
|
-
* become DockerNetworkError.
|
|
665
|
-
*/
|
|
666
|
-
convertError(cause) {
|
|
667
|
-
if (cause !== null && typeof cause === "object" && "_tag" in cause) return cause;
|
|
668
|
-
return new DockerNetworkError({
|
|
669
|
-
message: `Unexpected error: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
670
|
-
cause
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
};
|
|
674
|
-
|
|
675
|
-
//#endregion
|
|
676
|
-
//#region src/transport/npipe-transport.ts
|
|
677
|
-
const DEFAULT_PIPE_PATH = "\\\\.\\pipe\\docker_engine";
|
|
678
|
-
var NamedPipeTransport = class {
|
|
679
|
-
pipePath;
|
|
680
|
-
requestFn;
|
|
681
|
-
constructor(options) {
|
|
682
|
-
this.pipePath = options.path ?? DEFAULT_PIPE_PATH;
|
|
683
|
-
this.requestFn = options._requestFn ?? http.request;
|
|
684
|
-
}
|
|
685
|
-
async dial(options) {
|
|
686
|
-
return Result.tryPromise({
|
|
687
|
-
try: () => this.performRequest(options, false),
|
|
688
|
-
catch: (cause) => this.convertError(cause)
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
async dialStream(options) {
|
|
692
|
-
return Result.tryPromise({
|
|
693
|
-
try: () => this.performRequest(options, true),
|
|
694
|
-
catch: (cause) => this.convertError(cause)
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
async dialHijack(options) {
|
|
698
|
-
return Result.tryPromise({
|
|
699
|
-
try: () => this.performHijack(options),
|
|
700
|
-
catch: (cause) => this.convertError(cause)
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
destroy() {}
|
|
704
|
-
performHijack(options) {
|
|
705
|
-
return new Promise((resolve, reject) => {
|
|
706
|
-
const requestPath = buildPath(options.path, options.query);
|
|
707
|
-
const headers = {
|
|
708
|
-
Connection: "Upgrade",
|
|
709
|
-
Upgrade: "tcp",
|
|
710
|
-
...options.headers
|
|
711
|
-
};
|
|
712
|
-
if (options.authconfig) headers["X-Registry-Auth"] = Buffer.from(JSON.stringify(options.authconfig)).toString("base64");
|
|
713
|
-
const body = options.body;
|
|
714
|
-
let bodyStr;
|
|
715
|
-
if (body !== void 0 && typeof body !== "string" && !Buffer.isBuffer(body)) {
|
|
716
|
-
bodyStr = JSON.stringify(body);
|
|
717
|
-
if (!headers["Content-Type"] && !headers["content-type"]) headers["Content-Type"] = "application/json";
|
|
718
|
-
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
719
|
-
}
|
|
720
|
-
const req = this.requestFn({
|
|
721
|
-
socketPath: this.pipePath,
|
|
722
|
-
path: requestPath,
|
|
723
|
-
method: options.method,
|
|
724
|
-
headers
|
|
725
|
-
}, (res) => {
|
|
726
|
-
reject(new DockerNetworkError({
|
|
727
|
-
message: `Expected upgrade response, got status ${res.statusCode}`,
|
|
728
|
-
cause: void 0
|
|
729
|
-
}));
|
|
730
|
-
});
|
|
731
|
-
req.on("upgrade", (_res, socket, _head) => {
|
|
732
|
-
resolve(socket);
|
|
733
|
-
});
|
|
734
|
-
req.on("error", (err) => {
|
|
735
|
-
reject(new DockerNetworkError({
|
|
736
|
-
message: `Connection error: ${err.message}`,
|
|
737
|
-
cause: err
|
|
738
|
-
}));
|
|
739
|
-
});
|
|
740
|
-
if (bodyStr !== void 0) req.write(bodyStr);
|
|
741
|
-
req.end();
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
performRequest(options, isStream) {
|
|
745
|
-
return new Promise((resolve, reject) => {
|
|
746
|
-
const requestPath = buildPath(options.path, options.query);
|
|
747
|
-
const headers = { ...options.headers };
|
|
748
|
-
if (options.authconfig) headers["X-Registry-Auth"] = Buffer.from(JSON.stringify(options.authconfig)).toString("base64");
|
|
749
|
-
if (options.registryconfig) headers["X-Registry-Config"] = Buffer.from(JSON.stringify(options.registryconfig)).toString("base64");
|
|
750
|
-
const body = options.body;
|
|
751
|
-
const isStreamBody = body !== null && body !== void 0 && typeof body === "object" && typeof body.pipe === "function";
|
|
752
|
-
const isBufferBody = Buffer.isBuffer(body);
|
|
753
|
-
const isStringBody = typeof body === "string";
|
|
754
|
-
let bodyStr;
|
|
755
|
-
if (body !== void 0 && !isStreamBody && !isBufferBody && !isStringBody) {
|
|
756
|
-
bodyStr = JSON.stringify(body);
|
|
757
|
-
if (!headers["Content-Type"] && !headers["content-type"]) headers["Content-Type"] = "application/json";
|
|
758
|
-
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
759
|
-
} else if (isBufferBody) headers["Content-Length"] = body.length.toString();
|
|
760
|
-
else if (isStringBody) headers["Content-Length"] = Buffer.byteLength(body).toString();
|
|
761
|
-
else if (isStreamBody) headers["Transfer-Encoding"] = "chunked";
|
|
762
|
-
const req = this.requestFn({
|
|
763
|
-
socketPath: this.pipePath,
|
|
764
|
-
path: requestPath,
|
|
765
|
-
method: options.method,
|
|
766
|
-
headers
|
|
767
|
-
}, (res) => {
|
|
768
|
-
const statusCode = res.statusCode ?? 0;
|
|
769
|
-
const responseHeaders = res.headers ?? {};
|
|
770
|
-
const isSuccess = options.statusCodes[statusCode] === true;
|
|
771
|
-
if (isStream && isSuccess) {
|
|
772
|
-
resolve(res);
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
collectBody(res).then((bodyText) => {
|
|
776
|
-
if (isSuccess) {
|
|
777
|
-
if (statusCode === 204 || bodyText.length === 0) {
|
|
778
|
-
resolve({
|
|
779
|
-
statusCode,
|
|
780
|
-
headers: responseHeaders,
|
|
781
|
-
body: null
|
|
782
|
-
});
|
|
783
|
-
return;
|
|
784
|
-
}
|
|
785
|
-
try {
|
|
786
|
-
resolve({
|
|
787
|
-
statusCode,
|
|
788
|
-
headers: responseHeaders,
|
|
789
|
-
body: JSON.parse(bodyText)
|
|
790
|
-
});
|
|
791
|
-
} catch {
|
|
792
|
-
resolve({
|
|
793
|
-
statusCode,
|
|
794
|
-
headers: responseHeaders,
|
|
795
|
-
body: bodyText
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
} else reject(statusCodeToError(statusCode, extractErrorMessage(bodyText)));
|
|
799
|
-
}).catch((collectErr) => {
|
|
800
|
-
reject(new DockerNetworkError({
|
|
801
|
-
message: `Failed to read response body: ${String(collectErr)}`,
|
|
802
|
-
cause: collectErr
|
|
803
|
-
}));
|
|
804
|
-
});
|
|
805
|
-
});
|
|
806
|
-
req.on("error", (err) => {
|
|
807
|
-
reject(new DockerNetworkError({
|
|
808
|
-
message: `Connection error: ${err.message}`,
|
|
809
|
-
cause: err
|
|
810
|
-
}));
|
|
811
|
-
});
|
|
812
|
-
if (options.timeout !== void 0) req.setTimeout(options.timeout, () => {
|
|
813
|
-
req.destroy();
|
|
814
|
-
reject(new DockerTimeoutError({
|
|
815
|
-
message: `Request timed out after ${options.timeout}ms`,
|
|
816
|
-
timeoutMs: options.timeout
|
|
817
|
-
}));
|
|
818
|
-
});
|
|
819
|
-
if (options.signal) {
|
|
820
|
-
if (options.signal.aborted) {
|
|
821
|
-
req.destroy();
|
|
822
|
-
reject(new DockerAbortError({ message: "Request aborted" }));
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
options.signal.addEventListener("abort", () => {
|
|
826
|
-
req.destroy();
|
|
827
|
-
reject(new DockerAbortError({ message: "Request aborted" }));
|
|
828
|
-
}, { once: true });
|
|
829
|
-
}
|
|
830
|
-
if (isStreamBody) body.pipe(req);
|
|
831
|
-
else if (isBufferBody) {
|
|
832
|
-
req.write(body);
|
|
833
|
-
req.end();
|
|
834
|
-
} else if (isStringBody) {
|
|
835
|
-
req.write(body);
|
|
836
|
-
req.end();
|
|
837
|
-
} else if (bodyStr !== void 0) {
|
|
838
|
-
req.write(bodyStr);
|
|
839
|
-
req.end();
|
|
840
|
-
} else req.end();
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
convertError(cause) {
|
|
844
|
-
if (cause !== null && typeof cause === "object" && "_tag" in cause) return cause;
|
|
845
|
-
return new DockerNetworkError({
|
|
846
|
-
message: `Unexpected error: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
847
|
-
cause
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
};
|
|
851
|
-
|
|
852
|
-
//#endregion
|
|
853
|
-
//#region src/transport/index.ts
|
|
854
|
-
function createTransport(config) {
|
|
855
|
-
switch (config.type) {
|
|
856
|
-
case "unix": return new UnixTransport({ socketPath: config.socketPath });
|
|
857
|
-
case "tcp": return new TcpTransport({
|
|
858
|
-
host: config.host,
|
|
859
|
-
port: config.port,
|
|
860
|
-
tls: config.tls
|
|
861
|
-
});
|
|
862
|
-
case "ssh": return new SshTransport({
|
|
863
|
-
host: config.host,
|
|
864
|
-
port: config.port,
|
|
865
|
-
username: config.username,
|
|
866
|
-
privateKey: config.privateKey
|
|
867
|
-
});
|
|
868
|
-
case "npipe": return new NamedPipeTransport({ path: config.path });
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
/**
|
|
872
|
-
* Create a transport by auto-detecting configuration from environment variables.
|
|
873
|
-
*
|
|
874
|
-
* Environment variables:
|
|
875
|
-
* - DOCKER_HOST: Docker daemon socket (unix://, tcp://, ssh://, npipe://)
|
|
876
|
-
* - DOCKER_TLS_VERIFY: Set to "1" to enable TLS verification
|
|
877
|
-
* - DOCKER_CERT_PATH: Directory containing ca.pem, cert.pem, key.pem
|
|
878
|
-
* - DOCKER_CLIENT_TIMEOUT: Default timeout in seconds
|
|
879
|
-
*/
|
|
880
|
-
function createTransportFromEnv() {
|
|
881
|
-
const dockerHost = process.env.DOCKER_HOST;
|
|
882
|
-
const tlsVerify = process.env.DOCKER_TLS_VERIFY === "1";
|
|
883
|
-
const certPath = process.env.DOCKER_CERT_PATH;
|
|
884
|
-
if (!dockerHost) return new UnixTransport({});
|
|
885
|
-
if (dockerHost.startsWith("unix://")) return new UnixTransport({ socketPath: dockerHost.replace("unix://", "") });
|
|
886
|
-
if (dockerHost.startsWith("npipe://")) return new NamedPipeTransport({ path: dockerHost.replace("npipe://", "") });
|
|
887
|
-
if (dockerHost.startsWith("ssh://")) {
|
|
888
|
-
const url = new URL(dockerHost);
|
|
889
|
-
return new SshTransport({
|
|
890
|
-
host: url.hostname,
|
|
891
|
-
port: url.port ? Number.parseInt(url.port, 10) : 22,
|
|
892
|
-
username: url.username || "root"
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
if (dockerHost.startsWith("tcp://")) {
|
|
896
|
-
const url = new URL(dockerHost);
|
|
897
|
-
const host = url.hostname;
|
|
898
|
-
const port = url.port ? Number.parseInt(url.port, 10) : void 0;
|
|
899
|
-
let tls;
|
|
900
|
-
if (tlsVerify || certPath) {
|
|
901
|
-
tls = { rejectUnauthorized: tlsVerify };
|
|
902
|
-
if (certPath) {
|
|
903
|
-
const caPath = path.join(certPath, "ca.pem");
|
|
904
|
-
const certFilePath = path.join(certPath, "cert.pem");
|
|
905
|
-
const keyPath = path.join(certPath, "key.pem");
|
|
906
|
-
if (fs.existsSync(caPath)) tls.ca = fs.readFileSync(caPath, "utf-8");
|
|
907
|
-
if (fs.existsSync(certFilePath)) tls.cert = fs.readFileSync(certFilePath, "utf-8");
|
|
908
|
-
if (fs.existsSync(keyPath)) tls.key = fs.readFileSync(keyPath, "utf-8");
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
return new TcpTransport({
|
|
912
|
-
host,
|
|
913
|
-
port,
|
|
914
|
-
tls
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
return new UnixTransport({ socketPath: dockerHost });
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
//#endregion
|
|
921
|
-
//#region src/client/dial.ts
|
|
922
|
-
async function typedDial(transport, options) {
|
|
923
|
-
return (await transport.dial(options)).map((res) => res.body);
|
|
924
|
-
}
|
|
925
|
-
async function voidDial(transport, options) {
|
|
926
|
-
return (await transport.dial(options)).map(() => void 0);
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
//#endregion
|
|
930
|
-
//#region src/client/system.ts
|
|
931
|
-
var SystemOperations = class {
|
|
932
|
-
constructor(transport, apiVersion) {
|
|
933
|
-
this.transport = transport;
|
|
934
|
-
this.apiVersion = apiVersion;
|
|
935
|
-
}
|
|
936
|
-
async ping() {
|
|
937
|
-
return typedDial(this.transport, {
|
|
938
|
-
method: "GET",
|
|
939
|
-
path: `/${this.apiVersion}/_ping`,
|
|
940
|
-
statusCodes: {
|
|
941
|
-
200: true,
|
|
942
|
-
500: "server error"
|
|
943
|
-
}
|
|
944
|
-
});
|
|
945
|
-
}
|
|
946
|
-
async info() {
|
|
947
|
-
return typedDial(this.transport, {
|
|
948
|
-
method: "GET",
|
|
949
|
-
path: `/${this.apiVersion}/info`,
|
|
950
|
-
statusCodes: {
|
|
951
|
-
200: true,
|
|
952
|
-
500: "server error"
|
|
953
|
-
}
|
|
954
|
-
});
|
|
955
|
-
}
|
|
956
|
-
async version() {
|
|
957
|
-
return typedDial(this.transport, {
|
|
958
|
-
method: "GET",
|
|
959
|
-
path: `/${this.apiVersion}/version`,
|
|
960
|
-
statusCodes: {
|
|
961
|
-
200: true,
|
|
962
|
-
500: "server error"
|
|
963
|
-
}
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
async df() {
|
|
967
|
-
return typedDial(this.transport, {
|
|
968
|
-
method: "GET",
|
|
969
|
-
path: `/${this.apiVersion}/system/df`,
|
|
970
|
-
statusCodes: {
|
|
971
|
-
200: true,
|
|
972
|
-
500: "server error"
|
|
973
|
-
}
|
|
974
|
-
});
|
|
975
|
-
}
|
|
976
|
-
async swarmInit(options) {
|
|
977
|
-
return typedDial(this.transport, {
|
|
978
|
-
method: "POST",
|
|
979
|
-
path: `/${this.apiVersion}/swarm/init`,
|
|
980
|
-
body: options,
|
|
981
|
-
statusCodes: {
|
|
982
|
-
200: true,
|
|
983
|
-
400: "bad parameter",
|
|
984
|
-
500: "server error",
|
|
985
|
-
503: "node is already part of a swarm"
|
|
986
|
-
}
|
|
987
|
-
});
|
|
988
|
-
}
|
|
989
|
-
async swarmJoin(options) {
|
|
990
|
-
return voidDial(this.transport, {
|
|
991
|
-
method: "POST",
|
|
992
|
-
path: `/${this.apiVersion}/swarm/join`,
|
|
993
|
-
body: options,
|
|
994
|
-
statusCodes: {
|
|
995
|
-
200: true,
|
|
996
|
-
400: "bad parameter",
|
|
997
|
-
500: "server error",
|
|
998
|
-
503: "node is already part of a swarm"
|
|
999
|
-
}
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
async swarmLeave(options) {
|
|
1003
|
-
return voidDial(this.transport, {
|
|
1004
|
-
method: "POST",
|
|
1005
|
-
path: `/${this.apiVersion}/swarm/leave`,
|
|
1006
|
-
query: options,
|
|
1007
|
-
statusCodes: {
|
|
1008
|
-
200: true,
|
|
1009
|
-
500: "server error",
|
|
1010
|
-
503: "node is not part of a swarm"
|
|
1011
|
-
}
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
async swarmUpdate(options) {
|
|
1015
|
-
const { version, rotateWorkerToken, rotateManagerToken, rotateManagerUnlockKey, ...body } = options;
|
|
1016
|
-
const query = { version };
|
|
1017
|
-
if (rotateWorkerToken !== void 0) query.rotateWorkerToken = rotateWorkerToken;
|
|
1018
|
-
if (rotateManagerToken !== void 0) query.rotateManagerToken = rotateManagerToken;
|
|
1019
|
-
if (rotateManagerUnlockKey !== void 0) query.rotateManagerUnlockKey = rotateManagerUnlockKey;
|
|
1020
|
-
return voidDial(this.transport, {
|
|
1021
|
-
method: "POST",
|
|
1022
|
-
path: `/${this.apiVersion}/swarm/update`,
|
|
1023
|
-
query,
|
|
1024
|
-
body,
|
|
1025
|
-
statusCodes: {
|
|
1026
|
-
200: true,
|
|
1027
|
-
400: "bad parameter",
|
|
1028
|
-
500: "server error",
|
|
1029
|
-
503: "node is not part of a swarm"
|
|
1030
|
-
}
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
1033
|
-
async swarmInspect() {
|
|
1034
|
-
return typedDial(this.transport, {
|
|
1035
|
-
method: "GET",
|
|
1036
|
-
path: `/${this.apiVersion}/swarm`,
|
|
1037
|
-
statusCodes: {
|
|
1038
|
-
200: true,
|
|
1039
|
-
500: "server error",
|
|
1040
|
-
503: "node is not part of a swarm"
|
|
1041
|
-
}
|
|
1042
|
-
});
|
|
1043
|
-
}
|
|
1044
|
-
async events(options) {
|
|
1045
|
-
return this.transport.dialStream({
|
|
1046
|
-
method: "GET",
|
|
1047
|
-
path: `/${this.apiVersion}/events`,
|
|
1048
|
-
query: options,
|
|
1049
|
-
statusCodes: {
|
|
1050
|
-
200: true,
|
|
1051
|
-
500: "server error"
|
|
1052
|
-
}
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
async auth(options) {
|
|
1056
|
-
return typedDial(this.transport, {
|
|
1057
|
-
method: "POST",
|
|
1058
|
-
path: `/${this.apiVersion}/auth`,
|
|
1059
|
-
body: options,
|
|
1060
|
-
statusCodes: {
|
|
1061
|
-
200: true,
|
|
1062
|
-
204: true,
|
|
1063
|
-
500: "server error"
|
|
1064
|
-
}
|
|
1065
|
-
});
|
|
1066
|
-
}
|
|
1067
|
-
async pruneBuilder(options) {
|
|
1068
|
-
return typedDial(this.transport, {
|
|
1069
|
-
method: "POST",
|
|
1070
|
-
path: `/${this.apiVersion}/build/prune`,
|
|
1071
|
-
query: options,
|
|
1072
|
-
statusCodes: {
|
|
1073
|
-
200: true,
|
|
1074
|
-
500: "server error"
|
|
1075
|
-
}
|
|
1076
|
-
});
|
|
1077
|
-
}
|
|
1078
|
-
};
|
|
1079
|
-
|
|
1080
|
-
//#endregion
|
|
1081
|
-
//#region src/transport/http-duplex.ts
|
|
1082
|
-
/**
|
|
1083
|
-
* HttpDuplex wraps a raw net.Socket (obtained from HTTP hijack/upgrade)
|
|
1084
|
-
* into a Node.js Duplex stream for bidirectional I/O.
|
|
1085
|
-
*
|
|
1086
|
-
* Used for interactive attach/exec operations where stdin needs to be
|
|
1087
|
-
* written to the connection while stdout/stderr is read from it.
|
|
1088
|
-
*/
|
|
1089
|
-
var HttpDuplex = class extends Duplex {
|
|
1090
|
-
socket;
|
|
1091
|
-
constructor(socket) {
|
|
1092
|
-
super();
|
|
1093
|
-
this.socket = socket;
|
|
1094
|
-
socket.on("data", (chunk) => {
|
|
1095
|
-
if (!this.push(chunk)) socket.pause();
|
|
1096
|
-
});
|
|
1097
|
-
socket.on("end", () => {
|
|
1098
|
-
this.push(null);
|
|
1099
|
-
});
|
|
1100
|
-
socket.on("error", (err) => {
|
|
1101
|
-
this.destroy(err);
|
|
1102
|
-
});
|
|
1103
|
-
socket.on("close", () => {
|
|
1104
|
-
this.push(null);
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
_read(_size) {
|
|
1108
|
-
this.socket.resume();
|
|
1109
|
-
}
|
|
1110
|
-
_write(chunk, _encoding, callback) {
|
|
1111
|
-
this.socket.write(chunk, callback);
|
|
1112
|
-
}
|
|
1113
|
-
_final(callback) {
|
|
1114
|
-
this.socket.end(callback);
|
|
1115
|
-
}
|
|
1116
|
-
_destroy(error, callback) {
|
|
1117
|
-
this.socket.destroy(error ?? void 0);
|
|
1118
|
-
callback(error);
|
|
1119
|
-
}
|
|
1120
|
-
};
|
|
1121
|
-
|
|
1122
|
-
//#endregion
|
|
1123
|
-
//#region src/client/exec.ts
|
|
1124
|
-
var Exec = class {
|
|
1125
|
-
id;
|
|
1126
|
-
constructor(transport, apiVersion, id) {
|
|
1127
|
-
this.transport = transport;
|
|
1128
|
-
this.apiVersion = apiVersion;
|
|
1129
|
-
this.id = id;
|
|
1130
|
-
}
|
|
1131
|
-
async start(options) {
|
|
1132
|
-
const { stdin, ...startOpts } = options ?? {};
|
|
1133
|
-
if (stdin) return (await this.transport.dialHijack({
|
|
1134
|
-
method: "POST",
|
|
1135
|
-
path: `/${this.apiVersion}/exec/${this.id}/start`,
|
|
1136
|
-
body: startOpts,
|
|
1137
|
-
hijack: true,
|
|
1138
|
-
openStdin: true,
|
|
1139
|
-
statusCodes: {
|
|
1140
|
-
200: true,
|
|
1141
|
-
101: true,
|
|
1142
|
-
404: "no such exec instance",
|
|
1143
|
-
409: "container is paused",
|
|
1144
|
-
500: "server error"
|
|
1145
|
-
}
|
|
1146
|
-
})).map((socket) => new HttpDuplex(socket));
|
|
1147
|
-
return this.transport.dialStream({
|
|
1148
|
-
method: "POST",
|
|
1149
|
-
path: `/${this.apiVersion}/exec/${this.id}/start`,
|
|
1150
|
-
body: Object.keys(startOpts).length > 0 ? startOpts : void 0,
|
|
1151
|
-
statusCodes: {
|
|
1152
|
-
200: true,
|
|
1153
|
-
404: "no such exec instance",
|
|
1154
|
-
409: "container is paused",
|
|
1155
|
-
500: "server error"
|
|
1156
|
-
}
|
|
1157
|
-
});
|
|
1158
|
-
}
|
|
1159
|
-
async resize(options) {
|
|
1160
|
-
return voidDial(this.transport, {
|
|
1161
|
-
method: "POST",
|
|
1162
|
-
path: `/${this.apiVersion}/exec/${this.id}/resize`,
|
|
1163
|
-
query: options,
|
|
1164
|
-
statusCodes: {
|
|
1165
|
-
200: true,
|
|
1166
|
-
404: "no such exec instance",
|
|
1167
|
-
500: "server error"
|
|
1168
|
-
}
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
|
-
async inspect() {
|
|
1172
|
-
return typedDial(this.transport, {
|
|
1173
|
-
method: "GET",
|
|
1174
|
-
path: `/${this.apiVersion}/exec/${this.id}/json`,
|
|
1175
|
-
statusCodes: {
|
|
1176
|
-
200: true,
|
|
1177
|
-
404: "no such exec instance",
|
|
1178
|
-
500: "server error"
|
|
1179
|
-
}
|
|
1180
|
-
});
|
|
1181
|
-
}
|
|
1182
|
-
};
|
|
1183
|
-
|
|
1184
|
-
//#endregion
|
|
1185
|
-
//#region src/client/container.ts
|
|
1186
|
-
var Container = class {
|
|
1187
|
-
id;
|
|
1188
|
-
constructor(transport, apiVersion, id) {
|
|
1189
|
-
this.transport = transport;
|
|
1190
|
-
this.apiVersion = apiVersion;
|
|
1191
|
-
this.id = id;
|
|
1192
|
-
}
|
|
1193
|
-
async inspect() {
|
|
1194
|
-
return typedDial(this.transport, {
|
|
1195
|
-
method: "GET",
|
|
1196
|
-
path: `/${this.apiVersion}/containers/${this.id}/json`,
|
|
1197
|
-
statusCodes: {
|
|
1198
|
-
200: true,
|
|
1199
|
-
404: "no such container",
|
|
1200
|
-
500: "server error"
|
|
1201
|
-
}
|
|
1202
|
-
});
|
|
1203
|
-
}
|
|
1204
|
-
async start() {
|
|
1205
|
-
return voidDial(this.transport, {
|
|
1206
|
-
method: "POST",
|
|
1207
|
-
path: `/${this.apiVersion}/containers/${this.id}/start`,
|
|
1208
|
-
statusCodes: {
|
|
1209
|
-
204: true,
|
|
1210
|
-
304: true,
|
|
1211
|
-
404: "no such container",
|
|
1212
|
-
500: "server error"
|
|
1213
|
-
}
|
|
1214
|
-
});
|
|
1215
|
-
}
|
|
1216
|
-
async stop(options) {
|
|
1217
|
-
return voidDial(this.transport, {
|
|
1218
|
-
method: "POST",
|
|
1219
|
-
path: `/${this.apiVersion}/containers/${this.id}/stop`,
|
|
1220
|
-
query: options,
|
|
1221
|
-
statusCodes: {
|
|
1222
|
-
204: true,
|
|
1223
|
-
304: true,
|
|
1224
|
-
404: "no such container",
|
|
1225
|
-
500: "server error"
|
|
1226
|
-
}
|
|
1227
|
-
});
|
|
1228
|
-
}
|
|
1229
|
-
async restart(options) {
|
|
1230
|
-
return voidDial(this.transport, {
|
|
1231
|
-
method: "POST",
|
|
1232
|
-
path: `/${this.apiVersion}/containers/${this.id}/restart`,
|
|
1233
|
-
query: options,
|
|
1234
|
-
statusCodes: {
|
|
1235
|
-
204: true,
|
|
1236
|
-
404: "no such container",
|
|
1237
|
-
500: "server error"
|
|
1238
|
-
}
|
|
1239
|
-
});
|
|
1240
|
-
}
|
|
1241
|
-
async kill(options) {
|
|
1242
|
-
return voidDial(this.transport, {
|
|
1243
|
-
method: "POST",
|
|
1244
|
-
path: `/${this.apiVersion}/containers/${this.id}/kill`,
|
|
1245
|
-
query: options,
|
|
1246
|
-
statusCodes: {
|
|
1247
|
-
204: true,
|
|
1248
|
-
404: "no such container",
|
|
1249
|
-
409: "container is not running",
|
|
1250
|
-
500: "server error"
|
|
1251
|
-
}
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
async pause() {
|
|
1255
|
-
return voidDial(this.transport, {
|
|
1256
|
-
method: "POST",
|
|
1257
|
-
path: `/${this.apiVersion}/containers/${this.id}/pause`,
|
|
1258
|
-
statusCodes: {
|
|
1259
|
-
204: true,
|
|
1260
|
-
404: "no such container",
|
|
1261
|
-
500: "server error"
|
|
1262
|
-
}
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
async unpause() {
|
|
1266
|
-
return voidDial(this.transport, {
|
|
1267
|
-
method: "POST",
|
|
1268
|
-
path: `/${this.apiVersion}/containers/${this.id}/unpause`,
|
|
1269
|
-
statusCodes: {
|
|
1270
|
-
204: true,
|
|
1271
|
-
404: "no such container",
|
|
1272
|
-
500: "server error"
|
|
1273
|
-
}
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
async remove(options) {
|
|
1277
|
-
return voidDial(this.transport, {
|
|
1278
|
-
method: "DELETE",
|
|
1279
|
-
path: `/${this.apiVersion}/containers/${this.id}`,
|
|
1280
|
-
query: options,
|
|
1281
|
-
statusCodes: {
|
|
1282
|
-
204: true,
|
|
1283
|
-
400: "bad parameter",
|
|
1284
|
-
404: "no such container",
|
|
1285
|
-
409: "conflict",
|
|
1286
|
-
500: "server error"
|
|
1287
|
-
}
|
|
1288
|
-
});
|
|
1289
|
-
}
|
|
1290
|
-
async rename(name) {
|
|
1291
|
-
return voidDial(this.transport, {
|
|
1292
|
-
method: "POST",
|
|
1293
|
-
path: `/${this.apiVersion}/containers/${this.id}/rename`,
|
|
1294
|
-
query: { name },
|
|
1295
|
-
statusCodes: {
|
|
1296
|
-
204: true,
|
|
1297
|
-
404: "no such container",
|
|
1298
|
-
409: "name already in use",
|
|
1299
|
-
500: "server error"
|
|
1300
|
-
}
|
|
1301
|
-
});
|
|
1302
|
-
}
|
|
1303
|
-
async update(options) {
|
|
1304
|
-
return typedDial(this.transport, {
|
|
1305
|
-
method: "POST",
|
|
1306
|
-
path: `/${this.apiVersion}/containers/${this.id}/update`,
|
|
1307
|
-
body: options,
|
|
1308
|
-
statusCodes: {
|
|
1309
|
-
200: true,
|
|
1310
|
-
404: "no such container",
|
|
1311
|
-
500: "server error"
|
|
1312
|
-
}
|
|
1313
|
-
});
|
|
1314
|
-
}
|
|
1315
|
-
async top(psArgs) {
|
|
1316
|
-
return typedDial(this.transport, {
|
|
1317
|
-
method: "GET",
|
|
1318
|
-
path: `/${this.apiVersion}/containers/${this.id}/top`,
|
|
1319
|
-
query: psArgs ? { ps_args: psArgs } : void 0,
|
|
1320
|
-
statusCodes: {
|
|
1321
|
-
200: true,
|
|
1322
|
-
404: "no such container",
|
|
1323
|
-
500: "server error"
|
|
1324
|
-
}
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
async changes() {
|
|
1328
|
-
return typedDial(this.transport, {
|
|
1329
|
-
method: "GET",
|
|
1330
|
-
path: `/${this.apiVersion}/containers/${this.id}/changes`,
|
|
1331
|
-
statusCodes: {
|
|
1332
|
-
200: true,
|
|
1333
|
-
404: "no such container",
|
|
1334
|
-
500: "server error"
|
|
1335
|
-
}
|
|
1336
|
-
});
|
|
1337
|
-
}
|
|
1338
|
-
async logs(options) {
|
|
1339
|
-
return this.transport.dialStream({
|
|
1340
|
-
method: "GET",
|
|
1341
|
-
path: `/${this.apiVersion}/containers/${this.id}/logs`,
|
|
1342
|
-
query: options,
|
|
1343
|
-
statusCodes: {
|
|
1344
|
-
200: true,
|
|
1345
|
-
404: "no such container",
|
|
1346
|
-
500: "server error"
|
|
1347
|
-
}
|
|
1348
|
-
});
|
|
1349
|
-
}
|
|
1350
|
-
async stats(options) {
|
|
1351
|
-
return this.transport.dialStream({
|
|
1352
|
-
method: "GET",
|
|
1353
|
-
path: `/${this.apiVersion}/containers/${this.id}/stats`,
|
|
1354
|
-
query: options,
|
|
1355
|
-
statusCodes: {
|
|
1356
|
-
200: true,
|
|
1357
|
-
404: "no such container",
|
|
1358
|
-
500: "server error"
|
|
1359
|
-
}
|
|
1360
|
-
});
|
|
1361
|
-
}
|
|
1362
|
-
async wait(options) {
|
|
1363
|
-
return typedDial(this.transport, {
|
|
1364
|
-
method: "POST",
|
|
1365
|
-
path: `/${this.apiVersion}/containers/${this.id}/wait`,
|
|
1366
|
-
query: options,
|
|
1367
|
-
statusCodes: {
|
|
1368
|
-
200: true,
|
|
1369
|
-
400: "bad parameter",
|
|
1370
|
-
404: "no such container",
|
|
1371
|
-
500: "server error"
|
|
1372
|
-
}
|
|
1373
|
-
});
|
|
1374
|
-
}
|
|
1375
|
-
async resize(options) {
|
|
1376
|
-
return voidDial(this.transport, {
|
|
1377
|
-
method: "POST",
|
|
1378
|
-
path: `/${this.apiVersion}/containers/${this.id}/resize`,
|
|
1379
|
-
query: options,
|
|
1380
|
-
statusCodes: {
|
|
1381
|
-
200: true,
|
|
1382
|
-
404: "no such container",
|
|
1383
|
-
500: "server error"
|
|
1384
|
-
}
|
|
1385
|
-
});
|
|
1386
|
-
}
|
|
1387
|
-
async attach(options) {
|
|
1388
|
-
if (options?.stdin) return (await this.transport.dialHijack({
|
|
1389
|
-
method: "POST",
|
|
1390
|
-
path: `/${this.apiVersion}/containers/${this.id}/attach`,
|
|
1391
|
-
query: options,
|
|
1392
|
-
hijack: true,
|
|
1393
|
-
openStdin: true,
|
|
1394
|
-
statusCodes: {
|
|
1395
|
-
200: true,
|
|
1396
|
-
101: true,
|
|
1397
|
-
404: "no such container",
|
|
1398
|
-
500: "server error"
|
|
1399
|
-
}
|
|
1400
|
-
})).map((socket) => new HttpDuplex(socket));
|
|
1401
|
-
return this.transport.dialStream({
|
|
1402
|
-
method: "POST",
|
|
1403
|
-
path: `/${this.apiVersion}/containers/${this.id}/attach`,
|
|
1404
|
-
query: options,
|
|
1405
|
-
statusCodes: {
|
|
1406
|
-
200: true,
|
|
1407
|
-
404: "no such container",
|
|
1408
|
-
500: "server error"
|
|
1409
|
-
}
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
async exec(options) {
|
|
1413
|
-
return (await typedDial(this.transport, {
|
|
1414
|
-
method: "POST",
|
|
1415
|
-
path: `/${this.apiVersion}/containers/${this.id}/exec`,
|
|
1416
|
-
body: options,
|
|
1417
|
-
statusCodes: {
|
|
1418
|
-
201: true,
|
|
1419
|
-
404: "no such container",
|
|
1420
|
-
409: "container is paused",
|
|
1421
|
-
500: "server error"
|
|
1422
|
-
}
|
|
1423
|
-
})).map((body) => new Exec(this.transport, this.apiVersion, body.Id));
|
|
1424
|
-
}
|
|
1425
|
-
async export() {
|
|
1426
|
-
return this.transport.dialStream({
|
|
1427
|
-
method: "GET",
|
|
1428
|
-
path: `/${this.apiVersion}/containers/${this.id}/export`,
|
|
1429
|
-
statusCodes: {
|
|
1430
|
-
200: true,
|
|
1431
|
-
404: "no such container",
|
|
1432
|
-
500: "server error"
|
|
1433
|
-
}
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
|
-
async getArchive(options) {
|
|
1437
|
-
return this.transport.dialStream({
|
|
1438
|
-
method: "GET",
|
|
1439
|
-
path: `/${this.apiVersion}/containers/${this.id}/archive`,
|
|
1440
|
-
query: { path: options.path },
|
|
1441
|
-
statusCodes: {
|
|
1442
|
-
200: true,
|
|
1443
|
-
400: "bad parameter",
|
|
1444
|
-
404: "no such container",
|
|
1445
|
-
500: "server error"
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
}
|
|
1449
|
-
async putArchive(options, stream) {
|
|
1450
|
-
return voidDial(this.transport, {
|
|
1451
|
-
method: "PUT",
|
|
1452
|
-
path: `/${this.apiVersion}/containers/${this.id}/archive`,
|
|
1453
|
-
query: { path: options.path },
|
|
1454
|
-
body: stream,
|
|
1455
|
-
headers: { "content-type": "application/x-tar" },
|
|
1456
|
-
statusCodes: {
|
|
1457
|
-
200: true,
|
|
1458
|
-
400: "bad parameter",
|
|
1459
|
-
403: "permission denied",
|
|
1460
|
-
404: "no such container",
|
|
1461
|
-
500: "server error"
|
|
1462
|
-
}
|
|
1463
|
-
});
|
|
1464
|
-
}
|
|
1465
|
-
async listCheckpoints() {
|
|
1466
|
-
return typedDial(this.transport, {
|
|
1467
|
-
method: "GET",
|
|
1468
|
-
path: `/${this.apiVersion}/containers/${this.id}/checkpoints`,
|
|
1469
|
-
statusCodes: {
|
|
1470
|
-
200: true,
|
|
1471
|
-
404: "no such container",
|
|
1472
|
-
500: "server error"
|
|
1473
|
-
}
|
|
1474
|
-
});
|
|
1475
|
-
}
|
|
1476
|
-
async createCheckpoint(options) {
|
|
1477
|
-
return voidDial(this.transport, {
|
|
1478
|
-
method: "POST",
|
|
1479
|
-
path: `/${this.apiVersion}/containers/${this.id}/checkpoints`,
|
|
1480
|
-
body: options,
|
|
1481
|
-
statusCodes: {
|
|
1482
|
-
201: true,
|
|
1483
|
-
404: "no such container",
|
|
1484
|
-
500: "server error"
|
|
1485
|
-
}
|
|
1486
|
-
});
|
|
1487
|
-
}
|
|
1488
|
-
async deleteCheckpoint(name) {
|
|
1489
|
-
return voidDial(this.transport, {
|
|
1490
|
-
method: "DELETE",
|
|
1491
|
-
path: `/${this.apiVersion}/containers/${this.id}/checkpoints/${name}`,
|
|
1492
|
-
statusCodes: {
|
|
1493
|
-
204: true,
|
|
1494
|
-
404: "no such checkpoint",
|
|
1495
|
-
500: "server error"
|
|
1496
|
-
}
|
|
1497
|
-
});
|
|
1498
|
-
}
|
|
1499
|
-
async infoArchive(options) {
|
|
1500
|
-
return (await this.transport.dial({
|
|
1501
|
-
method: "HEAD",
|
|
1502
|
-
path: `/${this.apiVersion}/containers/${this.id}/archive`,
|
|
1503
|
-
query: { path: options.path },
|
|
1504
|
-
statusCodes: {
|
|
1505
|
-
200: true,
|
|
1506
|
-
400: "bad parameter",
|
|
1507
|
-
404: "no such container",
|
|
1508
|
-
500: "server error"
|
|
1509
|
-
}
|
|
1510
|
-
})).map((res) => {
|
|
1511
|
-
const statHeader = res.headers["x-docker-container-path-stat"];
|
|
1512
|
-
if (statHeader) return JSON.parse(Buffer.from(statHeader, "base64").toString("utf-8"));
|
|
1513
|
-
return {};
|
|
1514
|
-
});
|
|
1515
|
-
}
|
|
1516
|
-
async commit(options) {
|
|
1517
|
-
const query = { container: this.id };
|
|
1518
|
-
if (options) {
|
|
1519
|
-
const { repo, tag, comment, author, pause, changes, ...rest } = options;
|
|
1520
|
-
if (repo !== void 0) query.repo = repo;
|
|
1521
|
-
if (tag !== void 0) query.tag = tag;
|
|
1522
|
-
if (comment !== void 0) query.comment = comment;
|
|
1523
|
-
if (author !== void 0) query.author = author;
|
|
1524
|
-
if (pause !== void 0) query.pause = pause;
|
|
1525
|
-
if (changes !== void 0) query.changes = changes;
|
|
1526
|
-
Object.assign(query, rest);
|
|
1527
|
-
}
|
|
1528
|
-
return typedDial(this.transport, {
|
|
1529
|
-
method: "POST",
|
|
1530
|
-
path: `/${this.apiVersion}/commit`,
|
|
1531
|
-
query,
|
|
1532
|
-
statusCodes: {
|
|
1533
|
-
201: true,
|
|
1534
|
-
404: "no such container",
|
|
1535
|
-
500: "server error"
|
|
1536
|
-
}
|
|
1537
|
-
});
|
|
1538
|
-
}
|
|
1539
|
-
};
|
|
1540
|
-
var ContainerOperations = class {
|
|
1541
|
-
constructor(transport, apiVersion) {
|
|
1542
|
-
this.transport = transport;
|
|
1543
|
-
this.apiVersion = apiVersion;
|
|
1544
|
-
}
|
|
1545
|
-
async list(options) {
|
|
1546
|
-
return typedDial(this.transport, {
|
|
1547
|
-
method: "GET",
|
|
1548
|
-
path: `/${this.apiVersion}/containers/json`,
|
|
1549
|
-
query: options,
|
|
1550
|
-
statusCodes: {
|
|
1551
|
-
200: true,
|
|
1552
|
-
400: "bad parameter",
|
|
1553
|
-
500: "server error"
|
|
1554
|
-
}
|
|
1555
|
-
});
|
|
1556
|
-
}
|
|
1557
|
-
async create(options) {
|
|
1558
|
-
const { name, platform, ...body } = options;
|
|
1559
|
-
const query = {};
|
|
1560
|
-
if (name !== void 0) query.name = name;
|
|
1561
|
-
if (platform !== void 0) query.platform = platform;
|
|
1562
|
-
return (await typedDial(this.transport, {
|
|
1563
|
-
method: "POST",
|
|
1564
|
-
path: `/${this.apiVersion}/containers/create`,
|
|
1565
|
-
query: Object.keys(query).length > 0 ? query : void 0,
|
|
1566
|
-
body,
|
|
1567
|
-
statusCodes: {
|
|
1568
|
-
201: true,
|
|
1569
|
-
400: "bad parameter",
|
|
1570
|
-
404: "no such image",
|
|
1571
|
-
409: "conflict",
|
|
1572
|
-
500: "server error"
|
|
1573
|
-
}
|
|
1574
|
-
})).map((resp) => new Container(this.transport, this.apiVersion, resp.Id));
|
|
1575
|
-
}
|
|
1576
|
-
async inspect(id) {
|
|
1577
|
-
return typedDial(this.transport, {
|
|
1578
|
-
method: "GET",
|
|
1579
|
-
path: `/${this.apiVersion}/containers/${id}/json`,
|
|
1580
|
-
statusCodes: {
|
|
1581
|
-
200: true,
|
|
1582
|
-
404: "no such container",
|
|
1583
|
-
500: "server error"
|
|
1584
|
-
}
|
|
1585
|
-
});
|
|
1586
|
-
}
|
|
1587
|
-
async prune(options) {
|
|
1588
|
-
return typedDial(this.transport, {
|
|
1589
|
-
method: "POST",
|
|
1590
|
-
path: `/${this.apiVersion}/containers/prune`,
|
|
1591
|
-
query: options,
|
|
1592
|
-
statusCodes: {
|
|
1593
|
-
200: true,
|
|
1594
|
-
500: "server error"
|
|
1595
|
-
}
|
|
1596
|
-
});
|
|
1597
|
-
}
|
|
1598
|
-
getContainer(id) {
|
|
1599
|
-
return new Container(this.transport, this.apiVersion, id);
|
|
1600
|
-
}
|
|
1601
|
-
};
|
|
1602
|
-
|
|
1603
|
-
//#endregion
|
|
1604
|
-
//#region src/session/index.ts
|
|
1605
|
-
/**
|
|
1606
|
-
* Establishes a BuildKit gRPC session over a hijacked HTTP connection.
|
|
1607
|
-
*
|
|
1608
|
-
* This is used for BuildKit v2 builds to provide registry credentials
|
|
1609
|
-
* to the builder during image builds.
|
|
1610
|
-
*/
|
|
1611
|
-
async function withSession(transport, apiVersion, auth) {
|
|
1612
|
-
const sessionId = randomUUID();
|
|
1613
|
-
const socketResult = await transport.dialHijack({
|
|
1614
|
-
method: "POST",
|
|
1615
|
-
path: `/${apiVersion}/session`,
|
|
1616
|
-
hijack: true,
|
|
1617
|
-
headers: {
|
|
1618
|
-
Upgrade: "h2c",
|
|
1619
|
-
"X-Docker-Expose-Session-Uuid": sessionId,
|
|
1620
|
-
"X-Docker-Expose-Session-Name": "docker-sdk"
|
|
1621
|
-
},
|
|
1622
|
-
statusCodes: {
|
|
1623
|
-
200: true,
|
|
1624
|
-
101: true,
|
|
1625
|
-
500: "server error"
|
|
1626
|
-
}
|
|
1627
|
-
});
|
|
1628
|
-
if (socketResult.isErr()) return socketResult;
|
|
1629
|
-
const socket = socketResult.value;
|
|
1630
|
-
try {
|
|
1631
|
-
const server = new grpc.Server();
|
|
1632
|
-
const creds = grpc.ServerCredentials.createInsecure();
|
|
1633
|
-
server.createConnectionInjector(creds).injectConnection(socket);
|
|
1634
|
-
const protoPath = path.resolve(import.meta.dirname, "auth.proto");
|
|
1635
|
-
const pkg = protoLoader.loadSync(protoPath);
|
|
1636
|
-
const authService = grpc.loadPackageDefinition(pkg).moby?.filesync?.v1?.Auth?.service;
|
|
1637
|
-
if (authService) server.addService(authService, {
|
|
1638
|
-
Credentials({ request: _request }, callback) {
|
|
1639
|
-
if (auth) callback(null, {
|
|
1640
|
-
Username: auth.username ?? "",
|
|
1641
|
-
Secret: auth.password ?? ""
|
|
1642
|
-
});
|
|
1643
|
-
else callback(null, {});
|
|
1644
|
-
},
|
|
1645
|
-
FetchToken(_call, callback) {
|
|
1646
|
-
callback(null, {});
|
|
1647
|
-
},
|
|
1648
|
-
GetTokenAuthority(_call, callback) {
|
|
1649
|
-
callback(null, {});
|
|
1650
|
-
},
|
|
1651
|
-
VerifyTokenAuthority(_call, callback) {
|
|
1652
|
-
callback(null, {});
|
|
1653
|
-
}
|
|
1654
|
-
});
|
|
1655
|
-
const close = () => {
|
|
1656
|
-
server.forceShutdown();
|
|
1657
|
-
socket.end();
|
|
1658
|
-
};
|
|
1659
|
-
return Result.ok({
|
|
1660
|
-
sessionId,
|
|
1661
|
-
close
|
|
1662
|
-
});
|
|
1663
|
-
} catch (err) {
|
|
1664
|
-
socket.end();
|
|
1665
|
-
return Result.err(new DockerNetworkError({
|
|
1666
|
-
message: `Failed to create gRPC session: ${err instanceof Error ? err.message : String(err)}`,
|
|
1667
|
-
cause: err
|
|
1668
|
-
}));
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
//#endregion
|
|
1673
|
-
//#region src/client/image.ts
|
|
1674
|
-
var Image = class {
|
|
1675
|
-
name;
|
|
1676
|
-
constructor(transport, apiVersion, name) {
|
|
1677
|
-
this.transport = transport;
|
|
1678
|
-
this.apiVersion = apiVersion;
|
|
1679
|
-
this.name = name;
|
|
1680
|
-
}
|
|
1681
|
-
async inspect() {
|
|
1682
|
-
return typedDial(this.transport, {
|
|
1683
|
-
method: "GET",
|
|
1684
|
-
path: `/${this.apiVersion}/images/${this.name}/json`,
|
|
1685
|
-
statusCodes: {
|
|
1686
|
-
200: true,
|
|
1687
|
-
404: "no such image",
|
|
1688
|
-
500: "server error"
|
|
1689
|
-
}
|
|
1690
|
-
});
|
|
1691
|
-
}
|
|
1692
|
-
async history() {
|
|
1693
|
-
return typedDial(this.transport, {
|
|
1694
|
-
method: "GET",
|
|
1695
|
-
path: `/${this.apiVersion}/images/${this.name}/history`,
|
|
1696
|
-
statusCodes: {
|
|
1697
|
-
200: true,
|
|
1698
|
-
404: "no such image",
|
|
1699
|
-
500: "server error"
|
|
1700
|
-
}
|
|
1701
|
-
});
|
|
1702
|
-
}
|
|
1703
|
-
async push(options) {
|
|
1704
|
-
return this.transport.dialStream({
|
|
1705
|
-
method: "POST",
|
|
1706
|
-
path: `/${this.apiVersion}/images/${this.name}/push`,
|
|
1707
|
-
query: options,
|
|
1708
|
-
statusCodes: {
|
|
1709
|
-
200: true,
|
|
1710
|
-
404: "no such image",
|
|
1711
|
-
500: "server error"
|
|
1712
|
-
}
|
|
1713
|
-
});
|
|
1714
|
-
}
|
|
1715
|
-
async tag(options) {
|
|
1716
|
-
return voidDial(this.transport, {
|
|
1717
|
-
method: "POST",
|
|
1718
|
-
path: `/${this.apiVersion}/images/${this.name}/tag`,
|
|
1719
|
-
query: options,
|
|
1720
|
-
statusCodes: {
|
|
1721
|
-
201: true,
|
|
1722
|
-
400: "bad parameter",
|
|
1723
|
-
404: "no such image",
|
|
1724
|
-
409: "conflict",
|
|
1725
|
-
500: "server error"
|
|
1726
|
-
}
|
|
1727
|
-
});
|
|
1728
|
-
}
|
|
1729
|
-
async remove(options) {
|
|
1730
|
-
return typedDial(this.transport, {
|
|
1731
|
-
method: "DELETE",
|
|
1732
|
-
path: `/${this.apiVersion}/images/${this.name}`,
|
|
1733
|
-
query: options,
|
|
1734
|
-
statusCodes: {
|
|
1735
|
-
200: true,
|
|
1736
|
-
404: "no such image",
|
|
1737
|
-
409: "conflict",
|
|
1738
|
-
500: "server error"
|
|
1739
|
-
}
|
|
1740
|
-
});
|
|
1741
|
-
}
|
|
1742
|
-
async get() {
|
|
1743
|
-
return this.transport.dialStream({
|
|
1744
|
-
method: "GET",
|
|
1745
|
-
path: `/${this.apiVersion}/images/${this.name}/get`,
|
|
1746
|
-
statusCodes: {
|
|
1747
|
-
200: true,
|
|
1748
|
-
500: "server error"
|
|
1749
|
-
}
|
|
1750
|
-
});
|
|
1751
|
-
}
|
|
1752
|
-
async distribution() {
|
|
1753
|
-
return typedDial(this.transport, {
|
|
1754
|
-
method: "GET",
|
|
1755
|
-
path: `/${this.apiVersion}/distribution/${this.name}/json`,
|
|
1756
|
-
statusCodes: {
|
|
1757
|
-
200: true,
|
|
1758
|
-
401: "authentication required",
|
|
1759
|
-
500: "server error"
|
|
1760
|
-
}
|
|
1761
|
-
});
|
|
1762
|
-
}
|
|
1763
|
-
};
|
|
1764
|
-
var ImageOperations = class {
|
|
1765
|
-
constructor(transport, apiVersion) {
|
|
1766
|
-
this.transport = transport;
|
|
1767
|
-
this.apiVersion = apiVersion;
|
|
1768
|
-
}
|
|
1769
|
-
async list(options) {
|
|
1770
|
-
return typedDial(this.transport, {
|
|
1771
|
-
method: "GET",
|
|
1772
|
-
path: `/${this.apiVersion}/images/json`,
|
|
1773
|
-
query: options,
|
|
1774
|
-
statusCodes: {
|
|
1775
|
-
200: true,
|
|
1776
|
-
500: "server error"
|
|
1777
|
-
}
|
|
1778
|
-
});
|
|
1779
|
-
}
|
|
1780
|
-
async create(options) {
|
|
1781
|
-
return this.transport.dialStream({
|
|
1782
|
-
method: "POST",
|
|
1783
|
-
path: `/${this.apiVersion}/images/create`,
|
|
1784
|
-
query: options,
|
|
1785
|
-
statusCodes: {
|
|
1786
|
-
200: true,
|
|
1787
|
-
404: "no such image",
|
|
1788
|
-
500: "server error"
|
|
1789
|
-
}
|
|
1790
|
-
});
|
|
1791
|
-
}
|
|
1792
|
-
async build(context, options) {
|
|
1793
|
-
const { authconfig, registryconfig, ...queryOpts } = options ?? {};
|
|
1794
|
-
if (queryOpts.version === "2") {
|
|
1795
|
-
const sessionResult = await withSession(this.transport, this.apiVersion, authconfig);
|
|
1796
|
-
if (sessionResult.isErr()) return sessionResult;
|
|
1797
|
-
const { sessionId, close } = sessionResult.value;
|
|
1798
|
-
queryOpts.session = sessionId;
|
|
1799
|
-
const buildResult = await this.transport.dialStream({
|
|
1800
|
-
method: "POST",
|
|
1801
|
-
path: `/${this.apiVersion}/build`,
|
|
1802
|
-
query: Object.keys(queryOpts).length > 0 ? queryOpts : void 0,
|
|
1803
|
-
body: context,
|
|
1804
|
-
headers: { "Content-Type": "application/x-tar" },
|
|
1805
|
-
registryconfig,
|
|
1806
|
-
statusCodes: {
|
|
1807
|
-
200: true,
|
|
1808
|
-
400: "bad parameter",
|
|
1809
|
-
500: "server error"
|
|
1810
|
-
}
|
|
1811
|
-
});
|
|
1812
|
-
if (buildResult.isErr()) {
|
|
1813
|
-
close();
|
|
1814
|
-
return buildResult;
|
|
1815
|
-
}
|
|
1816
|
-
const stream = buildResult.value;
|
|
1817
|
-
stream.on("end", close);
|
|
1818
|
-
stream.on("error", close);
|
|
1819
|
-
return buildResult;
|
|
1820
|
-
}
|
|
1821
|
-
return this.transport.dialStream({
|
|
1822
|
-
method: "POST",
|
|
1823
|
-
path: `/${this.apiVersion}/build`,
|
|
1824
|
-
query: Object.keys(queryOpts).length > 0 ? queryOpts : void 0,
|
|
1825
|
-
body: context,
|
|
1826
|
-
headers: { "Content-Type": "application/x-tar" },
|
|
1827
|
-
authconfig,
|
|
1828
|
-
registryconfig,
|
|
1829
|
-
statusCodes: {
|
|
1830
|
-
200: true,
|
|
1831
|
-
400: "bad parameter",
|
|
1832
|
-
500: "server error"
|
|
1833
|
-
}
|
|
1834
|
-
});
|
|
1835
|
-
}
|
|
1836
|
-
async load(stream) {
|
|
1837
|
-
return this.transport.dialStream({
|
|
1838
|
-
method: "POST",
|
|
1839
|
-
path: `/${this.apiVersion}/images/load`,
|
|
1840
|
-
body: stream,
|
|
1841
|
-
headers: { "Content-Type": "application/x-tar" },
|
|
1842
|
-
statusCodes: {
|
|
1843
|
-
200: true,
|
|
1844
|
-
500: "server error"
|
|
1845
|
-
}
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
async import(stream, options) {
|
|
1849
|
-
return this.transport.dialStream({
|
|
1850
|
-
method: "POST",
|
|
1851
|
-
path: `/${this.apiVersion}/images/create`,
|
|
1852
|
-
query: {
|
|
1853
|
-
fromSrc: "-",
|
|
1854
|
-
...options
|
|
1855
|
-
},
|
|
1856
|
-
body: stream,
|
|
1857
|
-
headers: { "Content-Type": "application/x-tar" },
|
|
1858
|
-
statusCodes: {
|
|
1859
|
-
200: true,
|
|
1860
|
-
500: "server error"
|
|
1861
|
-
}
|
|
1862
|
-
});
|
|
1863
|
-
}
|
|
1864
|
-
async search(options) {
|
|
1865
|
-
return typedDial(this.transport, {
|
|
1866
|
-
method: "GET",
|
|
1867
|
-
path: `/${this.apiVersion}/images/search`,
|
|
1868
|
-
query: options,
|
|
1869
|
-
statusCodes: {
|
|
1870
|
-
200: true,
|
|
1871
|
-
500: "server error"
|
|
1872
|
-
}
|
|
1873
|
-
});
|
|
1874
|
-
}
|
|
1875
|
-
async prune(options) {
|
|
1876
|
-
return typedDial(this.transport, {
|
|
1877
|
-
method: "POST",
|
|
1878
|
-
path: `/${this.apiVersion}/images/prune`,
|
|
1879
|
-
query: options,
|
|
1880
|
-
statusCodes: {
|
|
1881
|
-
200: true,
|
|
1882
|
-
500: "server error"
|
|
1883
|
-
}
|
|
1884
|
-
});
|
|
1885
|
-
}
|
|
1886
|
-
getImage(name) {
|
|
1887
|
-
return new Image(this.transport, this.apiVersion, name);
|
|
1888
|
-
}
|
|
1889
|
-
};
|
|
1890
|
-
|
|
1891
|
-
//#endregion
|
|
1892
|
-
//#region src/client/volume.ts
|
|
1893
|
-
var VolumeEntity = class {
|
|
1894
|
-
name;
|
|
1895
|
-
constructor(transport, apiVersion, name) {
|
|
1896
|
-
this.transport = transport;
|
|
1897
|
-
this.apiVersion = apiVersion;
|
|
1898
|
-
this.name = name;
|
|
1899
|
-
}
|
|
1900
|
-
async inspect() {
|
|
1901
|
-
return typedDial(this.transport, {
|
|
1902
|
-
method: "GET",
|
|
1903
|
-
path: `/${this.apiVersion}/volumes/${this.name}`,
|
|
1904
|
-
statusCodes: {
|
|
1905
|
-
200: true,
|
|
1906
|
-
404: "no such volume",
|
|
1907
|
-
500: "server error"
|
|
1908
|
-
}
|
|
1909
|
-
});
|
|
1910
|
-
}
|
|
1911
|
-
async remove(options) {
|
|
1912
|
-
return voidDial(this.transport, {
|
|
1913
|
-
method: "DELETE",
|
|
1914
|
-
path: `/${this.apiVersion}/volumes/${this.name}`,
|
|
1915
|
-
query: options,
|
|
1916
|
-
statusCodes: {
|
|
1917
|
-
204: true,
|
|
1918
|
-
404: "no such volume",
|
|
1919
|
-
409: "volume in use",
|
|
1920
|
-
500: "server error"
|
|
1921
|
-
}
|
|
1922
|
-
});
|
|
1923
|
-
}
|
|
1924
|
-
};
|
|
1925
|
-
var VolumeOperations = class {
|
|
1926
|
-
constructor(transport, apiVersion) {
|
|
1927
|
-
this.transport = transport;
|
|
1928
|
-
this.apiVersion = apiVersion;
|
|
1929
|
-
}
|
|
1930
|
-
async list(options) {
|
|
1931
|
-
return typedDial(this.transport, {
|
|
1932
|
-
method: "GET",
|
|
1933
|
-
path: `/${this.apiVersion}/volumes`,
|
|
1934
|
-
query: options,
|
|
1935
|
-
statusCodes: {
|
|
1936
|
-
200: true,
|
|
1937
|
-
500: "server error"
|
|
1938
|
-
}
|
|
1939
|
-
});
|
|
1940
|
-
}
|
|
1941
|
-
async create(options) {
|
|
1942
|
-
return typedDial(this.transport, {
|
|
1943
|
-
method: "POST",
|
|
1944
|
-
path: `/${this.apiVersion}/volumes/create`,
|
|
1945
|
-
body: options,
|
|
1946
|
-
statusCodes: {
|
|
1947
|
-
201: true,
|
|
1948
|
-
500: "server error"
|
|
1949
|
-
}
|
|
1950
|
-
});
|
|
1951
|
-
}
|
|
1952
|
-
async inspect(name) {
|
|
1953
|
-
return typedDial(this.transport, {
|
|
1954
|
-
method: "GET",
|
|
1955
|
-
path: `/${this.apiVersion}/volumes/${name}`,
|
|
1956
|
-
statusCodes: {
|
|
1957
|
-
200: true,
|
|
1958
|
-
404: "no such volume",
|
|
1959
|
-
500: "server error"
|
|
1960
|
-
}
|
|
1961
|
-
});
|
|
1962
|
-
}
|
|
1963
|
-
async prune(options) {
|
|
1964
|
-
return typedDial(this.transport, {
|
|
1965
|
-
method: "POST",
|
|
1966
|
-
path: `/${this.apiVersion}/volumes/prune`,
|
|
1967
|
-
query: options,
|
|
1968
|
-
statusCodes: {
|
|
1969
|
-
200: true,
|
|
1970
|
-
500: "server error"
|
|
1971
|
-
}
|
|
1972
|
-
});
|
|
1973
|
-
}
|
|
1974
|
-
getVolume(name) {
|
|
1975
|
-
return new VolumeEntity(this.transport, this.apiVersion, name);
|
|
1976
|
-
}
|
|
1977
|
-
};
|
|
1978
|
-
|
|
1979
|
-
//#endregion
|
|
1980
|
-
//#region src/client/network.ts
|
|
1981
|
-
var NetworkEntity = class {
|
|
1982
|
-
id;
|
|
1983
|
-
constructor(transport, apiVersion, id) {
|
|
1984
|
-
this.transport = transport;
|
|
1985
|
-
this.apiVersion = apiVersion;
|
|
1986
|
-
this.id = id;
|
|
1987
|
-
}
|
|
1988
|
-
async inspect() {
|
|
1989
|
-
return typedDial(this.transport, {
|
|
1990
|
-
method: "GET",
|
|
1991
|
-
path: `/${this.apiVersion}/networks/${this.id}`,
|
|
1992
|
-
statusCodes: {
|
|
1993
|
-
200: true,
|
|
1994
|
-
404: "network not found",
|
|
1995
|
-
500: "server error"
|
|
1996
|
-
}
|
|
1997
|
-
});
|
|
1998
|
-
}
|
|
1999
|
-
async remove() {
|
|
2000
|
-
return voidDial(this.transport, {
|
|
2001
|
-
method: "DELETE",
|
|
2002
|
-
path: `/${this.apiVersion}/networks/${this.id}`,
|
|
2003
|
-
statusCodes: {
|
|
2004
|
-
204: true,
|
|
2005
|
-
403: "operation forbidden",
|
|
2006
|
-
404: "no such network",
|
|
2007
|
-
500: "server error"
|
|
2008
|
-
}
|
|
2009
|
-
});
|
|
2010
|
-
}
|
|
2011
|
-
async connect(options) {
|
|
2012
|
-
return voidDial(this.transport, {
|
|
2013
|
-
method: "POST",
|
|
2014
|
-
path: `/${this.apiVersion}/networks/${this.id}/connect`,
|
|
2015
|
-
body: options,
|
|
2016
|
-
statusCodes: {
|
|
2017
|
-
200: true,
|
|
2018
|
-
400: "bad parameter",
|
|
2019
|
-
403: "operation forbidden",
|
|
2020
|
-
404: "network or container not found",
|
|
2021
|
-
500: "server error"
|
|
2022
|
-
}
|
|
2023
|
-
});
|
|
2024
|
-
}
|
|
2025
|
-
async disconnect(options) {
|
|
2026
|
-
return voidDial(this.transport, {
|
|
2027
|
-
method: "POST",
|
|
2028
|
-
path: `/${this.apiVersion}/networks/${this.id}/disconnect`,
|
|
2029
|
-
body: options,
|
|
2030
|
-
statusCodes: {
|
|
2031
|
-
200: true,
|
|
2032
|
-
403: "operation forbidden",
|
|
2033
|
-
404: "network or container not found",
|
|
2034
|
-
500: "server error"
|
|
2035
|
-
}
|
|
2036
|
-
});
|
|
2037
|
-
}
|
|
2038
|
-
};
|
|
2039
|
-
var NetworkOperations = class {
|
|
2040
|
-
constructor(transport, apiVersion) {
|
|
2041
|
-
this.transport = transport;
|
|
2042
|
-
this.apiVersion = apiVersion;
|
|
2043
|
-
}
|
|
2044
|
-
async list(options) {
|
|
2045
|
-
return typedDial(this.transport, {
|
|
2046
|
-
method: "GET",
|
|
2047
|
-
path: `/${this.apiVersion}/networks`,
|
|
2048
|
-
query: options,
|
|
2049
|
-
statusCodes: {
|
|
2050
|
-
200: true,
|
|
2051
|
-
500: "server error"
|
|
2052
|
-
}
|
|
2053
|
-
});
|
|
2054
|
-
}
|
|
2055
|
-
async create(options) {
|
|
2056
|
-
return typedDial(this.transport, {
|
|
2057
|
-
method: "POST",
|
|
2058
|
-
path: `/${this.apiVersion}/networks/create`,
|
|
2059
|
-
body: options,
|
|
2060
|
-
statusCodes: {
|
|
2061
|
-
201: true,
|
|
2062
|
-
400: "bad parameter",
|
|
2063
|
-
403: "operation forbidden",
|
|
2064
|
-
404: "plugin not found",
|
|
2065
|
-
500: "server error"
|
|
2066
|
-
}
|
|
2067
|
-
});
|
|
2068
|
-
}
|
|
2069
|
-
async inspect(id) {
|
|
2070
|
-
return typedDial(this.transport, {
|
|
2071
|
-
method: "GET",
|
|
2072
|
-
path: `/${this.apiVersion}/networks/${id}`,
|
|
2073
|
-
statusCodes: {
|
|
2074
|
-
200: true,
|
|
2075
|
-
404: "network not found",
|
|
2076
|
-
500: "server error"
|
|
2077
|
-
}
|
|
2078
|
-
});
|
|
2079
|
-
}
|
|
2080
|
-
async prune(options) {
|
|
2081
|
-
return typedDial(this.transport, {
|
|
2082
|
-
method: "POST",
|
|
2083
|
-
path: `/${this.apiVersion}/networks/prune`,
|
|
2084
|
-
query: options,
|
|
2085
|
-
statusCodes: {
|
|
2086
|
-
200: true,
|
|
2087
|
-
500: "server error"
|
|
2088
|
-
}
|
|
2089
|
-
});
|
|
2090
|
-
}
|
|
2091
|
-
getNetwork(id) {
|
|
2092
|
-
return new NetworkEntity(this.transport, this.apiVersion, id);
|
|
2093
|
-
}
|
|
2094
|
-
};
|
|
2095
|
-
|
|
2096
|
-
//#endregion
|
|
2097
|
-
//#region src/client/service.ts
|
|
2098
|
-
var ServiceEntity = class {
|
|
2099
|
-
id;
|
|
2100
|
-
constructor(transport, apiVersion, id) {
|
|
2101
|
-
this.transport = transport;
|
|
2102
|
-
this.apiVersion = apiVersion;
|
|
2103
|
-
this.id = id;
|
|
2104
|
-
}
|
|
2105
|
-
async inspect() {
|
|
2106
|
-
return typedDial(this.transport, {
|
|
2107
|
-
method: "GET",
|
|
2108
|
-
path: `/${this.apiVersion}/services/${this.id}`,
|
|
2109
|
-
statusCodes: {
|
|
2110
|
-
200: true,
|
|
2111
|
-
404: "no such service",
|
|
2112
|
-
500: "server error",
|
|
2113
|
-
503: "node is not part of a swarm"
|
|
2114
|
-
}
|
|
2115
|
-
});
|
|
2116
|
-
}
|
|
2117
|
-
async update(options) {
|
|
2118
|
-
const { version, registryAuthFrom, rollback, ...body } = options;
|
|
2119
|
-
const query = { version };
|
|
2120
|
-
if (registryAuthFrom !== void 0) query.registryAuthFrom = registryAuthFrom;
|
|
2121
|
-
if (rollback !== void 0) query.rollback = rollback;
|
|
2122
|
-
return voidDial(this.transport, {
|
|
2123
|
-
method: "POST",
|
|
2124
|
-
path: `/${this.apiVersion}/services/${this.id}/update`,
|
|
2125
|
-
query,
|
|
2126
|
-
body,
|
|
2127
|
-
statusCodes: {
|
|
2128
|
-
200: true,
|
|
2129
|
-
400: "bad parameter",
|
|
2130
|
-
404: "no such service",
|
|
2131
|
-
500: "server error",
|
|
2132
|
-
503: "node is not part of a swarm"
|
|
2133
|
-
}
|
|
2134
|
-
});
|
|
2135
|
-
}
|
|
2136
|
-
async remove() {
|
|
2137
|
-
return voidDial(this.transport, {
|
|
2138
|
-
method: "DELETE",
|
|
2139
|
-
path: `/${this.apiVersion}/services/${this.id}`,
|
|
2140
|
-
statusCodes: {
|
|
2141
|
-
200: true,
|
|
2142
|
-
404: "no such service",
|
|
2143
|
-
500: "server error",
|
|
2144
|
-
503: "node is not part of a swarm"
|
|
2145
|
-
}
|
|
2146
|
-
});
|
|
2147
|
-
}
|
|
2148
|
-
async logs(options) {
|
|
2149
|
-
return this.transport.dialStream({
|
|
2150
|
-
method: "GET",
|
|
2151
|
-
path: `/${this.apiVersion}/services/${this.id}/logs`,
|
|
2152
|
-
query: options,
|
|
2153
|
-
statusCodes: {
|
|
2154
|
-
200: true,
|
|
2155
|
-
404: "no such service",
|
|
2156
|
-
500: "server error",
|
|
2157
|
-
503: "node is not part of a swarm"
|
|
2158
|
-
}
|
|
2159
|
-
});
|
|
2160
|
-
}
|
|
2161
|
-
};
|
|
2162
|
-
var ServiceOperations = class {
|
|
2163
|
-
constructor(transport, apiVersion) {
|
|
2164
|
-
this.transport = transport;
|
|
2165
|
-
this.apiVersion = apiVersion;
|
|
2166
|
-
}
|
|
2167
|
-
async list(options) {
|
|
2168
|
-
return typedDial(this.transport, {
|
|
2169
|
-
method: "GET",
|
|
2170
|
-
path: `/${this.apiVersion}/services`,
|
|
2171
|
-
query: options,
|
|
2172
|
-
statusCodes: {
|
|
2173
|
-
200: true,
|
|
2174
|
-
500: "server error",
|
|
2175
|
-
503: "node is not part of a swarm"
|
|
2176
|
-
}
|
|
2177
|
-
});
|
|
2178
|
-
}
|
|
2179
|
-
async create(options) {
|
|
2180
|
-
const { ...body } = options;
|
|
2181
|
-
return typedDial(this.transport, {
|
|
2182
|
-
method: "POST",
|
|
2183
|
-
path: `/${this.apiVersion}/services/create`,
|
|
2184
|
-
body,
|
|
2185
|
-
statusCodes: {
|
|
2186
|
-
201: true,
|
|
2187
|
-
400: "bad parameter",
|
|
2188
|
-
403: "forbidden",
|
|
2189
|
-
409: "name conflicts",
|
|
2190
|
-
500: "server error",
|
|
2191
|
-
503: "node is not part of a swarm"
|
|
2192
|
-
}
|
|
2193
|
-
});
|
|
2194
|
-
}
|
|
2195
|
-
async inspect(id) {
|
|
2196
|
-
return typedDial(this.transport, {
|
|
2197
|
-
method: "GET",
|
|
2198
|
-
path: `/${this.apiVersion}/services/${id}`,
|
|
2199
|
-
statusCodes: {
|
|
2200
|
-
200: true,
|
|
2201
|
-
404: "no such service",
|
|
2202
|
-
500: "server error",
|
|
2203
|
-
503: "node is not part of a swarm"
|
|
2204
|
-
}
|
|
2205
|
-
});
|
|
2206
|
-
}
|
|
2207
|
-
getService(id) {
|
|
2208
|
-
return new ServiceEntity(this.transport, this.apiVersion, id);
|
|
2209
|
-
}
|
|
2210
|
-
};
|
|
2211
|
-
|
|
2212
|
-
//#endregion
|
|
2213
|
-
//#region src/client/task.ts
|
|
2214
|
-
var TaskEntity = class {
|
|
2215
|
-
id;
|
|
2216
|
-
constructor(transport, apiVersion, id) {
|
|
2217
|
-
this.transport = transport;
|
|
2218
|
-
this.apiVersion = apiVersion;
|
|
2219
|
-
this.id = id;
|
|
2220
|
-
}
|
|
2221
|
-
async inspect() {
|
|
2222
|
-
return typedDial(this.transport, {
|
|
2223
|
-
method: "GET",
|
|
2224
|
-
path: `/${this.apiVersion}/tasks/${this.id}`,
|
|
2225
|
-
statusCodes: {
|
|
2226
|
-
200: true,
|
|
2227
|
-
404: "no such task",
|
|
2228
|
-
500: "server error",
|
|
2229
|
-
503: "node is not part of a swarm"
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2232
|
-
}
|
|
2233
|
-
async logs(options) {
|
|
2234
|
-
return this.transport.dialStream({
|
|
2235
|
-
method: "GET",
|
|
2236
|
-
path: `/${this.apiVersion}/tasks/${this.id}/logs`,
|
|
2237
|
-
query: options,
|
|
2238
|
-
statusCodes: {
|
|
2239
|
-
200: true,
|
|
2240
|
-
404: "no such task",
|
|
2241
|
-
500: "server error",
|
|
2242
|
-
503: "node is not part of a swarm"
|
|
2243
|
-
}
|
|
2244
|
-
});
|
|
2245
|
-
}
|
|
2246
|
-
};
|
|
2247
|
-
var TaskOperations = class {
|
|
2248
|
-
constructor(transport, apiVersion) {
|
|
2249
|
-
this.transport = transport;
|
|
2250
|
-
this.apiVersion = apiVersion;
|
|
2251
|
-
}
|
|
2252
|
-
async list(options) {
|
|
2253
|
-
return typedDial(this.transport, {
|
|
2254
|
-
method: "GET",
|
|
2255
|
-
path: `/${this.apiVersion}/tasks`,
|
|
2256
|
-
query: options,
|
|
2257
|
-
statusCodes: {
|
|
2258
|
-
200: true,
|
|
2259
|
-
500: "server error",
|
|
2260
|
-
503: "node is not part of a swarm"
|
|
2261
|
-
}
|
|
2262
|
-
});
|
|
2263
|
-
}
|
|
2264
|
-
async inspect(id) {
|
|
2265
|
-
return typedDial(this.transport, {
|
|
2266
|
-
method: "GET",
|
|
2267
|
-
path: `/${this.apiVersion}/tasks/${id}`,
|
|
2268
|
-
statusCodes: {
|
|
2269
|
-
200: true,
|
|
2270
|
-
404: "no such task",
|
|
2271
|
-
500: "server error",
|
|
2272
|
-
503: "node is not part of a swarm"
|
|
2273
|
-
}
|
|
2274
|
-
});
|
|
2275
|
-
}
|
|
2276
|
-
getTask(id) {
|
|
2277
|
-
return new TaskEntity(this.transport, this.apiVersion, id);
|
|
2278
|
-
}
|
|
2279
|
-
};
|
|
2280
|
-
|
|
2281
|
-
//#endregion
|
|
2282
|
-
//#region src/client/node.ts
|
|
2283
|
-
var NodeEntity = class {
|
|
2284
|
-
id;
|
|
2285
|
-
constructor(transport, apiVersion, id) {
|
|
2286
|
-
this.transport = transport;
|
|
2287
|
-
this.apiVersion = apiVersion;
|
|
2288
|
-
this.id = id;
|
|
2289
|
-
}
|
|
2290
|
-
async inspect() {
|
|
2291
|
-
return typedDial(this.transport, {
|
|
2292
|
-
method: "GET",
|
|
2293
|
-
path: `/${this.apiVersion}/nodes/${this.id}`,
|
|
2294
|
-
statusCodes: {
|
|
2295
|
-
200: true,
|
|
2296
|
-
404: "no such node",
|
|
2297
|
-
500: "server error",
|
|
2298
|
-
503: "node is not part of a swarm"
|
|
2299
|
-
}
|
|
2300
|
-
});
|
|
2301
|
-
}
|
|
2302
|
-
async update(options) {
|
|
2303
|
-
const { version, ...body } = options;
|
|
2304
|
-
return voidDial(this.transport, {
|
|
2305
|
-
method: "POST",
|
|
2306
|
-
path: `/${this.apiVersion}/nodes/${this.id}/update`,
|
|
2307
|
-
query: { version },
|
|
2308
|
-
body,
|
|
2309
|
-
statusCodes: {
|
|
2310
|
-
200: true,
|
|
2311
|
-
400: "bad parameter",
|
|
2312
|
-
404: "no such node",
|
|
2313
|
-
500: "server error",
|
|
2314
|
-
503: "node is not part of a swarm"
|
|
2315
|
-
}
|
|
2316
|
-
});
|
|
2317
|
-
}
|
|
2318
|
-
async remove(options) {
|
|
2319
|
-
return voidDial(this.transport, {
|
|
2320
|
-
method: "DELETE",
|
|
2321
|
-
path: `/${this.apiVersion}/nodes/${this.id}`,
|
|
2322
|
-
query: options,
|
|
2323
|
-
statusCodes: {
|
|
2324
|
-
200: true,
|
|
2325
|
-
404: "no such node",
|
|
2326
|
-
500: "server error",
|
|
2327
|
-
503: "node is not part of a swarm"
|
|
2328
|
-
}
|
|
2329
|
-
});
|
|
2330
|
-
}
|
|
2331
|
-
};
|
|
2332
|
-
var NodeOperations = class {
|
|
2333
|
-
constructor(transport, apiVersion) {
|
|
2334
|
-
this.transport = transport;
|
|
2335
|
-
this.apiVersion = apiVersion;
|
|
2336
|
-
}
|
|
2337
|
-
async list(options) {
|
|
2338
|
-
return typedDial(this.transport, {
|
|
2339
|
-
method: "GET",
|
|
2340
|
-
path: `/${this.apiVersion}/nodes`,
|
|
2341
|
-
query: options,
|
|
2342
|
-
statusCodes: {
|
|
2343
|
-
200: true,
|
|
2344
|
-
500: "server error",
|
|
2345
|
-
503: "node is not part of a swarm"
|
|
2346
|
-
}
|
|
2347
|
-
});
|
|
2348
|
-
}
|
|
2349
|
-
async inspect(id) {
|
|
2350
|
-
return typedDial(this.transport, {
|
|
2351
|
-
method: "GET",
|
|
2352
|
-
path: `/${this.apiVersion}/nodes/${id}`,
|
|
2353
|
-
statusCodes: {
|
|
2354
|
-
200: true,
|
|
2355
|
-
404: "no such node",
|
|
2356
|
-
500: "server error",
|
|
2357
|
-
503: "node is not part of a swarm"
|
|
2358
|
-
}
|
|
2359
|
-
});
|
|
2360
|
-
}
|
|
2361
|
-
getNode(id) {
|
|
2362
|
-
return new NodeEntity(this.transport, this.apiVersion, id);
|
|
2363
|
-
}
|
|
2364
|
-
};
|
|
2365
|
-
|
|
2366
|
-
//#endregion
|
|
2367
|
-
//#region src/client/secret.ts
|
|
2368
|
-
var SecretEntity = class {
|
|
2369
|
-
id;
|
|
2370
|
-
constructor(transport, apiVersion, id) {
|
|
2371
|
-
this.transport = transport;
|
|
2372
|
-
this.apiVersion = apiVersion;
|
|
2373
|
-
this.id = id;
|
|
2374
|
-
}
|
|
2375
|
-
async inspect() {
|
|
2376
|
-
return typedDial(this.transport, {
|
|
2377
|
-
method: "GET",
|
|
2378
|
-
path: `/${this.apiVersion}/secrets/${this.id}`,
|
|
2379
|
-
statusCodes: {
|
|
2380
|
-
200: true,
|
|
2381
|
-
404: "no such secret",
|
|
2382
|
-
500: "server error",
|
|
2383
|
-
503: "node is not part of a swarm"
|
|
2384
|
-
}
|
|
2385
|
-
});
|
|
2386
|
-
}
|
|
2387
|
-
async update(options) {
|
|
2388
|
-
const { version, ...body } = options;
|
|
2389
|
-
return voidDial(this.transport, {
|
|
2390
|
-
method: "POST",
|
|
2391
|
-
path: `/${this.apiVersion}/secrets/${this.id}/update`,
|
|
2392
|
-
query: { version },
|
|
2393
|
-
body,
|
|
2394
|
-
statusCodes: {
|
|
2395
|
-
200: true,
|
|
2396
|
-
400: "bad parameter",
|
|
2397
|
-
404: "no such secret",
|
|
2398
|
-
500: "server error",
|
|
2399
|
-
503: "node is not part of a swarm"
|
|
2400
|
-
}
|
|
2401
|
-
});
|
|
2402
|
-
}
|
|
2403
|
-
async remove() {
|
|
2404
|
-
return voidDial(this.transport, {
|
|
2405
|
-
method: "DELETE",
|
|
2406
|
-
path: `/${this.apiVersion}/secrets/${this.id}`,
|
|
2407
|
-
statusCodes: {
|
|
2408
|
-
204: true,
|
|
2409
|
-
404: "no such secret",
|
|
2410
|
-
500: "server error",
|
|
2411
|
-
503: "node is not part of a swarm"
|
|
2412
|
-
}
|
|
2413
|
-
});
|
|
2414
|
-
}
|
|
2415
|
-
};
|
|
2416
|
-
var SecretOperations = class {
|
|
2417
|
-
constructor(transport, apiVersion) {
|
|
2418
|
-
this.transport = transport;
|
|
2419
|
-
this.apiVersion = apiVersion;
|
|
2420
|
-
}
|
|
2421
|
-
async list(options) {
|
|
2422
|
-
return typedDial(this.transport, {
|
|
2423
|
-
method: "GET",
|
|
2424
|
-
path: `/${this.apiVersion}/secrets`,
|
|
2425
|
-
query: options,
|
|
2426
|
-
statusCodes: {
|
|
2427
|
-
200: true,
|
|
2428
|
-
500: "server error",
|
|
2429
|
-
503: "node is not part of a swarm"
|
|
2430
|
-
}
|
|
2431
|
-
});
|
|
2432
|
-
}
|
|
2433
|
-
async create(options) {
|
|
2434
|
-
return typedDial(this.transport, {
|
|
2435
|
-
method: "POST",
|
|
2436
|
-
path: `/${this.apiVersion}/secrets/create`,
|
|
2437
|
-
body: options,
|
|
2438
|
-
statusCodes: {
|
|
2439
|
-
201: true,
|
|
2440
|
-
409: "name conflicts",
|
|
2441
|
-
500: "server error",
|
|
2442
|
-
503: "node is not part of a swarm"
|
|
2443
|
-
}
|
|
2444
|
-
});
|
|
2445
|
-
}
|
|
2446
|
-
async inspect(id) {
|
|
2447
|
-
return typedDial(this.transport, {
|
|
2448
|
-
method: "GET",
|
|
2449
|
-
path: `/${this.apiVersion}/secrets/${id}`,
|
|
2450
|
-
statusCodes: {
|
|
2451
|
-
200: true,
|
|
2452
|
-
404: "no such secret",
|
|
2453
|
-
500: "server error",
|
|
2454
|
-
503: "node is not part of a swarm"
|
|
2455
|
-
}
|
|
2456
|
-
});
|
|
2457
|
-
}
|
|
2458
|
-
getSecret(id) {
|
|
2459
|
-
return new SecretEntity(this.transport, this.apiVersion, id);
|
|
2460
|
-
}
|
|
2461
|
-
};
|
|
2462
|
-
|
|
2463
|
-
//#endregion
|
|
2464
|
-
//#region src/client/config.ts
|
|
2465
|
-
var ConfigEntity = class {
|
|
2466
|
-
id;
|
|
2467
|
-
constructor(transport, apiVersion, id) {
|
|
2468
|
-
this.transport = transport;
|
|
2469
|
-
this.apiVersion = apiVersion;
|
|
2470
|
-
this.id = id;
|
|
2471
|
-
}
|
|
2472
|
-
async inspect() {
|
|
2473
|
-
return typedDial(this.transport, {
|
|
2474
|
-
method: "GET",
|
|
2475
|
-
path: `/${this.apiVersion}/configs/${this.id}`,
|
|
2476
|
-
statusCodes: {
|
|
2477
|
-
200: true,
|
|
2478
|
-
404: "no such config",
|
|
2479
|
-
500: "server error",
|
|
2480
|
-
503: "node is not part of a swarm"
|
|
2481
|
-
}
|
|
2482
|
-
});
|
|
2483
|
-
}
|
|
2484
|
-
async update(options) {
|
|
2485
|
-
const { version, ...body } = options;
|
|
2486
|
-
return voidDial(this.transport, {
|
|
2487
|
-
method: "POST",
|
|
2488
|
-
path: `/${this.apiVersion}/configs/${this.id}/update`,
|
|
2489
|
-
query: { version },
|
|
2490
|
-
body,
|
|
2491
|
-
statusCodes: {
|
|
2492
|
-
200: true,
|
|
2493
|
-
400: "bad parameter",
|
|
2494
|
-
404: "no such config",
|
|
2495
|
-
500: "server error",
|
|
2496
|
-
503: "node is not part of a swarm"
|
|
2497
|
-
}
|
|
2498
|
-
});
|
|
2499
|
-
}
|
|
2500
|
-
async remove() {
|
|
2501
|
-
return voidDial(this.transport, {
|
|
2502
|
-
method: "DELETE",
|
|
2503
|
-
path: `/${this.apiVersion}/configs/${this.id}`,
|
|
2504
|
-
statusCodes: {
|
|
2505
|
-
204: true,
|
|
2506
|
-
404: "no such config",
|
|
2507
|
-
500: "server error",
|
|
2508
|
-
503: "node is not part of a swarm"
|
|
2509
|
-
}
|
|
2510
|
-
});
|
|
2511
|
-
}
|
|
2512
|
-
};
|
|
2513
|
-
var ConfigOperations = class {
|
|
2514
|
-
constructor(transport, apiVersion) {
|
|
2515
|
-
this.transport = transport;
|
|
2516
|
-
this.apiVersion = apiVersion;
|
|
2517
|
-
}
|
|
2518
|
-
async list(options) {
|
|
2519
|
-
return typedDial(this.transport, {
|
|
2520
|
-
method: "GET",
|
|
2521
|
-
path: `/${this.apiVersion}/configs`,
|
|
2522
|
-
query: options,
|
|
2523
|
-
statusCodes: {
|
|
2524
|
-
200: true,
|
|
2525
|
-
500: "server error",
|
|
2526
|
-
503: "node is not part of a swarm"
|
|
2527
|
-
}
|
|
2528
|
-
});
|
|
2529
|
-
}
|
|
2530
|
-
async create(options) {
|
|
2531
|
-
return typedDial(this.transport, {
|
|
2532
|
-
method: "POST",
|
|
2533
|
-
path: `/${this.apiVersion}/configs/create`,
|
|
2534
|
-
body: options,
|
|
2535
|
-
statusCodes: {
|
|
2536
|
-
201: true,
|
|
2537
|
-
409: "name conflicts",
|
|
2538
|
-
500: "server error",
|
|
2539
|
-
503: "node is not part of a swarm"
|
|
2540
|
-
}
|
|
2541
|
-
});
|
|
2542
|
-
}
|
|
2543
|
-
async inspect(id) {
|
|
2544
|
-
return typedDial(this.transport, {
|
|
2545
|
-
method: "GET",
|
|
2546
|
-
path: `/${this.apiVersion}/configs/${id}`,
|
|
2547
|
-
statusCodes: {
|
|
2548
|
-
200: true,
|
|
2549
|
-
404: "no such config",
|
|
2550
|
-
500: "server error",
|
|
2551
|
-
503: "node is not part of a swarm"
|
|
2552
|
-
}
|
|
2553
|
-
});
|
|
2554
|
-
}
|
|
2555
|
-
getConfig(id) {
|
|
2556
|
-
return new ConfigEntity(this.transport, this.apiVersion, id);
|
|
2557
|
-
}
|
|
2558
|
-
};
|
|
2559
|
-
|
|
2560
|
-
//#endregion
|
|
2561
|
-
//#region src/client/plugin.ts
|
|
2562
|
-
var PluginEntity = class {
|
|
2563
|
-
name;
|
|
2564
|
-
constructor(transport, apiVersion, name) {
|
|
2565
|
-
this.transport = transport;
|
|
2566
|
-
this.apiVersion = apiVersion;
|
|
2567
|
-
this.name = name;
|
|
2568
|
-
}
|
|
2569
|
-
async inspect() {
|
|
2570
|
-
return typedDial(this.transport, {
|
|
2571
|
-
method: "GET",
|
|
2572
|
-
path: `/${this.apiVersion}/plugins/${this.name}/json`,
|
|
2573
|
-
statusCodes: {
|
|
2574
|
-
200: true,
|
|
2575
|
-
404: "plugin is not found",
|
|
2576
|
-
500: "server error"
|
|
2577
|
-
}
|
|
2578
|
-
});
|
|
2579
|
-
}
|
|
2580
|
-
async remove(options) {
|
|
2581
|
-
return typedDial(this.transport, {
|
|
2582
|
-
method: "DELETE",
|
|
2583
|
-
path: `/${this.apiVersion}/plugins/${this.name}`,
|
|
2584
|
-
query: options,
|
|
2585
|
-
statusCodes: {
|
|
2586
|
-
200: true,
|
|
2587
|
-
404: "plugin is not found",
|
|
2588
|
-
500: "server error"
|
|
2589
|
-
}
|
|
2590
|
-
});
|
|
2591
|
-
}
|
|
2592
|
-
async enable(options) {
|
|
2593
|
-
return voidDial(this.transport, {
|
|
2594
|
-
method: "POST",
|
|
2595
|
-
path: `/${this.apiVersion}/plugins/${this.name}/enable`,
|
|
2596
|
-
query: options,
|
|
2597
|
-
statusCodes: {
|
|
2598
|
-
200: true,
|
|
2599
|
-
404: "plugin is not installed",
|
|
2600
|
-
500: "server error"
|
|
2601
|
-
}
|
|
2602
|
-
});
|
|
2603
|
-
}
|
|
2604
|
-
async disable(options) {
|
|
2605
|
-
return voidDial(this.transport, {
|
|
2606
|
-
method: "POST",
|
|
2607
|
-
path: `/${this.apiVersion}/plugins/${this.name}/disable`,
|
|
2608
|
-
body: options,
|
|
2609
|
-
statusCodes: {
|
|
2610
|
-
200: true,
|
|
2611
|
-
404: "plugin is not installed",
|
|
2612
|
-
500: "server error"
|
|
2613
|
-
}
|
|
2614
|
-
});
|
|
2615
|
-
}
|
|
2616
|
-
async push() {
|
|
2617
|
-
return voidDial(this.transport, {
|
|
2618
|
-
method: "POST",
|
|
2619
|
-
path: `/${this.apiVersion}/plugins/${this.name}/push`,
|
|
2620
|
-
statusCodes: {
|
|
2621
|
-
200: true,
|
|
2622
|
-
404: "plugin is not found",
|
|
2623
|
-
500: "server error"
|
|
2624
|
-
}
|
|
2625
|
-
});
|
|
2626
|
-
}
|
|
2627
|
-
async configure(options) {
|
|
2628
|
-
return voidDial(this.transport, {
|
|
2629
|
-
method: "POST",
|
|
2630
|
-
path: `/${this.apiVersion}/plugins/${this.name}/set`,
|
|
2631
|
-
body: options.env,
|
|
2632
|
-
statusCodes: {
|
|
2633
|
-
204: true,
|
|
2634
|
-
404: "plugin is not found",
|
|
2635
|
-
500: "server error"
|
|
2636
|
-
}
|
|
2637
|
-
});
|
|
2638
|
-
}
|
|
2639
|
-
async upgrade(options) {
|
|
2640
|
-
return this.transport.dialStream({
|
|
2641
|
-
method: "POST",
|
|
2642
|
-
path: `/${this.apiVersion}/plugins/${this.name}/upgrade`,
|
|
2643
|
-
query: { remote: options.remote },
|
|
2644
|
-
statusCodes: {
|
|
2645
|
-
200: true,
|
|
2646
|
-
404: "plugin is not found",
|
|
2647
|
-
500: "server error"
|
|
2648
|
-
}
|
|
2649
|
-
});
|
|
2650
|
-
}
|
|
2651
|
-
};
|
|
2652
|
-
var PluginOperations = class {
|
|
2653
|
-
constructor(transport, apiVersion) {
|
|
2654
|
-
this.transport = transport;
|
|
2655
|
-
this.apiVersion = apiVersion;
|
|
2656
|
-
}
|
|
2657
|
-
async list(options) {
|
|
2658
|
-
return typedDial(this.transport, {
|
|
2659
|
-
method: "GET",
|
|
2660
|
-
path: `/${this.apiVersion}/plugins`,
|
|
2661
|
-
query: options,
|
|
2662
|
-
statusCodes: {
|
|
2663
|
-
200: true,
|
|
2664
|
-
500: "server error"
|
|
2665
|
-
}
|
|
2666
|
-
});
|
|
2667
|
-
}
|
|
2668
|
-
async privileges(options) {
|
|
2669
|
-
return typedDial(this.transport, {
|
|
2670
|
-
method: "GET",
|
|
2671
|
-
path: `/${this.apiVersion}/plugins/privileges`,
|
|
2672
|
-
query: { remote: options.remote },
|
|
2673
|
-
statusCodes: {
|
|
2674
|
-
200: true,
|
|
2675
|
-
500: "server error"
|
|
2676
|
-
}
|
|
2677
|
-
});
|
|
2678
|
-
}
|
|
2679
|
-
async install(options) {
|
|
2680
|
-
const query = { remote: options.remote };
|
|
2681
|
-
if (options.name !== void 0) query.name = options.name;
|
|
2682
|
-
return this.transport.dialStream({
|
|
2683
|
-
method: "POST",
|
|
2684
|
-
path: `/${this.apiVersion}/plugins/pull`,
|
|
2685
|
-
query,
|
|
2686
|
-
statusCodes: {
|
|
2687
|
-
204: true,
|
|
2688
|
-
500: "server error"
|
|
2689
|
-
}
|
|
2690
|
-
});
|
|
2691
|
-
}
|
|
2692
|
-
async create(options) {
|
|
2693
|
-
return voidDial(this.transport, {
|
|
2694
|
-
method: "POST",
|
|
2695
|
-
path: `/${this.apiVersion}/plugins/create`,
|
|
2696
|
-
query: { name: options.name },
|
|
2697
|
-
statusCodes: {
|
|
2698
|
-
204: true,
|
|
2699
|
-
500: "server error"
|
|
2700
|
-
}
|
|
2701
|
-
});
|
|
2702
|
-
}
|
|
2703
|
-
getPlugin(name) {
|
|
2704
|
-
return new PluginEntity(this.transport, this.apiVersion, name);
|
|
2705
|
-
}
|
|
2706
|
-
};
|
|
2707
|
-
|
|
2708
|
-
//#endregion
|
|
2709
|
-
//#region src/client/index.ts
|
|
2710
|
-
var Docker = class Docker {
|
|
2711
|
-
system;
|
|
2712
|
-
containers;
|
|
2713
|
-
images;
|
|
2714
|
-
volumes;
|
|
2715
|
-
networks;
|
|
2716
|
-
services;
|
|
2717
|
-
tasks;
|
|
2718
|
-
nodes;
|
|
2719
|
-
secrets;
|
|
2720
|
-
configs;
|
|
2721
|
-
plugins;
|
|
2722
|
-
transport;
|
|
2723
|
-
apiVersion;
|
|
2724
|
-
constructor(config) {
|
|
2725
|
-
this.transport = createTransport(config.transport);
|
|
2726
|
-
this.apiVersion = config.apiVersion;
|
|
2727
|
-
const v = config.apiVersion;
|
|
2728
|
-
this.system = new SystemOperations(this.transport, v);
|
|
2729
|
-
this.containers = new ContainerOperations(this.transport, v);
|
|
2730
|
-
this.images = new ImageOperations(this.transport, v);
|
|
2731
|
-
this.volumes = new VolumeOperations(this.transport, v);
|
|
2732
|
-
this.networks = new NetworkOperations(this.transport, v);
|
|
2733
|
-
this.services = new ServiceOperations(this.transport, v);
|
|
2734
|
-
this.tasks = new TaskOperations(this.transport, v);
|
|
2735
|
-
this.nodes = new NodeOperations(this.transport, v);
|
|
2736
|
-
this.secrets = new SecretOperations(this.transport, v);
|
|
2737
|
-
this.configs = new ConfigOperations(this.transport, v);
|
|
2738
|
-
this.plugins = new PluginOperations(this.transport, v);
|
|
2739
|
-
}
|
|
2740
|
-
/** Create Docker client with pre-existing transport (for testing). */
|
|
2741
|
-
static fromTransport(transport, opts) {
|
|
2742
|
-
const instance = Object.create(Docker.prototype);
|
|
2743
|
-
const v = opts.apiVersion;
|
|
2744
|
-
instance.transport = transport;
|
|
2745
|
-
instance.apiVersion = v;
|
|
2746
|
-
instance.system = new SystemOperations(transport, v);
|
|
2747
|
-
instance.containers = new ContainerOperations(transport, v);
|
|
2748
|
-
instance.images = new ImageOperations(transport, v);
|
|
2749
|
-
instance.volumes = new VolumeOperations(transport, v);
|
|
2750
|
-
instance.networks = new NetworkOperations(transport, v);
|
|
2751
|
-
instance.services = new ServiceOperations(transport, v);
|
|
2752
|
-
instance.tasks = new TaskOperations(transport, v);
|
|
2753
|
-
instance.nodes = new NodeOperations(transport, v);
|
|
2754
|
-
instance.secrets = new SecretOperations(transport, v);
|
|
2755
|
-
instance.configs = new ConfigOperations(transport, v);
|
|
2756
|
-
instance.plugins = new PluginOperations(transport, v);
|
|
2757
|
-
return instance;
|
|
2758
|
-
}
|
|
2759
|
-
/**
|
|
2760
|
-
* Create Docker client from environment variables.
|
|
2761
|
-
* Reads DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH, DOCKER_CLIENT_TIMEOUT.
|
|
2762
|
-
*/
|
|
2763
|
-
static fromEnv(opts) {
|
|
2764
|
-
const transport = createTransportFromEnv();
|
|
2765
|
-
const apiVersion = opts?.apiVersion ?? "v1.47";
|
|
2766
|
-
const instance = Object.create(Docker.prototype);
|
|
2767
|
-
instance.transport = transport;
|
|
2768
|
-
instance.apiVersion = apiVersion;
|
|
2769
|
-
instance.system = new SystemOperations(transport, apiVersion);
|
|
2770
|
-
instance.containers = new ContainerOperations(transport, apiVersion);
|
|
2771
|
-
instance.images = new ImageOperations(transport, apiVersion);
|
|
2772
|
-
instance.volumes = new VolumeOperations(transport, apiVersion);
|
|
2773
|
-
instance.networks = new NetworkOperations(transport, apiVersion);
|
|
2774
|
-
instance.services = new ServiceOperations(transport, apiVersion);
|
|
2775
|
-
instance.tasks = new TaskOperations(transport, apiVersion);
|
|
2776
|
-
instance.nodes = new NodeOperations(transport, apiVersion);
|
|
2777
|
-
instance.secrets = new SecretOperations(transport, apiVersion);
|
|
2778
|
-
instance.configs = new ConfigOperations(transport, apiVersion);
|
|
2779
|
-
instance.plugins = new PluginOperations(transport, apiVersion);
|
|
2780
|
-
return instance;
|
|
2781
|
-
}
|
|
2782
|
-
/**
|
|
2783
|
-
* Pull an image from a registry.
|
|
2784
|
-
* Returns a progress stream of newline-delimited JSON.
|
|
2785
|
-
*/
|
|
2786
|
-
async pull(repoTag, options) {
|
|
2787
|
-
const parts = repoTag.split(":");
|
|
2788
|
-
const tag = parts.length > 1 ? parts.pop() : "latest";
|
|
2789
|
-
const repository = parts.join(":");
|
|
2790
|
-
return this.transport.dialStream({
|
|
2791
|
-
method: "POST",
|
|
2792
|
-
path: `/${this.apiVersion}/images/create`,
|
|
2793
|
-
query: {
|
|
2794
|
-
fromImage: repository,
|
|
2795
|
-
tag
|
|
2796
|
-
},
|
|
2797
|
-
authconfig: options?.authconfig,
|
|
2798
|
-
statusCodes: {
|
|
2799
|
-
200: true,
|
|
2800
|
-
404: "no such image",
|
|
2801
|
-
500: "server error"
|
|
2802
|
-
}
|
|
2803
|
-
});
|
|
2804
|
-
}
|
|
2805
|
-
/**
|
|
2806
|
-
* Create and run a container, waiting for it to exit.
|
|
2807
|
-
* Returns the wait result and the container instance.
|
|
2808
|
-
*/
|
|
2809
|
-
async run(image, cmd, options) {
|
|
2810
|
-
const { autoRemove, ...createOpts } = options ?? {};
|
|
2811
|
-
const createResult = await this.containers.create({
|
|
2812
|
-
...createOpts,
|
|
2813
|
-
Image: image,
|
|
2814
|
-
Cmd: cmd,
|
|
2815
|
-
AttachStdout: true,
|
|
2816
|
-
AttachStderr: true
|
|
2817
|
-
});
|
|
2818
|
-
if (createResult.isErr()) return createResult;
|
|
2819
|
-
const container = createResult.value;
|
|
2820
|
-
const attachResult = await container.attach({
|
|
2821
|
-
stream: true,
|
|
2822
|
-
stdout: true,
|
|
2823
|
-
stderr: true
|
|
2824
|
-
});
|
|
2825
|
-
if (attachResult.isErr()) return attachResult;
|
|
2826
|
-
const startResult = await container.start();
|
|
2827
|
-
if (startResult.isErr()) return startResult;
|
|
2828
|
-
const waitResult = await container.wait();
|
|
2829
|
-
if (waitResult.isErr()) return waitResult;
|
|
2830
|
-
if (autoRemove) await container.remove({ force: true });
|
|
2831
|
-
return waitResult.map((output) => ({
|
|
2832
|
-
output,
|
|
2833
|
-
container
|
|
2834
|
-
}));
|
|
2835
|
-
}
|
|
2836
|
-
destroy() {
|
|
2837
|
-
this.transport.destroy();
|
|
2838
|
-
}
|
|
2839
|
-
};
|
|
2840
|
-
|
|
2841
|
-
//#endregion
|
|
2842
|
-
//#region src/transport/stream-utils.ts
|
|
2843
|
-
var DockerStream = class extends EventEmitter {
|
|
2844
|
-
isTty;
|
|
2845
|
-
source;
|
|
2846
|
-
constructor(source, isTty) {
|
|
2847
|
-
super();
|
|
2848
|
-
this.source = source;
|
|
2849
|
-
this.isTty = isTty;
|
|
2850
|
-
source.on("data", (chunk) => this.emit("data", chunk));
|
|
2851
|
-
source.on("end", () => this.emit("end"));
|
|
2852
|
-
source.on("error", (err) => this.emit("error", err));
|
|
2853
|
-
}
|
|
2854
|
-
/**
|
|
2855
|
-
* Destroys the underlying source stream.
|
|
2856
|
-
*/
|
|
2857
|
-
destroy() {
|
|
2858
|
-
if ("destroy" in this.source && typeof this.source.destroy === "function") this.source.destroy();
|
|
2859
|
-
}
|
|
2860
|
-
};
|
|
2861
|
-
const HEADER_SIZE = 8;
|
|
2862
|
-
/**
|
|
2863
|
-
* Separates a Docker multiplexed stream into stdout and stderr PassThrough
|
|
2864
|
-
* streams based on the Docker stream multiplexing protocol.
|
|
2865
|
-
*
|
|
2866
|
-
* Docker multiplexed format: 8-byte header per frame
|
|
2867
|
-
* - Byte 0: stream type (0=stdin, 1=stdout, 2=stderr)
|
|
2868
|
-
* - Bytes 1-3: padding (0)
|
|
2869
|
-
* - Bytes 4-7: payload size (big-endian uint32)
|
|
2870
|
-
* - Followed by `size` bytes of payload
|
|
2871
|
-
*/
|
|
2872
|
-
function demuxStream(source) {
|
|
2873
|
-
const stdout = new PassThrough();
|
|
2874
|
-
const stderr = new PassThrough();
|
|
2875
|
-
let buffer = Buffer.alloc(0);
|
|
2876
|
-
function processBuffer() {
|
|
2877
|
-
while (buffer.length >= HEADER_SIZE) {
|
|
2878
|
-
const streamType = buffer.readUInt8(0);
|
|
2879
|
-
const payloadSize = buffer.readUInt32BE(4);
|
|
2880
|
-
if (buffer.length < HEADER_SIZE + payloadSize) break;
|
|
2881
|
-
const payload = buffer.subarray(HEADER_SIZE, HEADER_SIZE + payloadSize);
|
|
2882
|
-
switch (streamType) {
|
|
2883
|
-
case 1:
|
|
2884
|
-
stdout.write(payload);
|
|
2885
|
-
break;
|
|
2886
|
-
case 2:
|
|
2887
|
-
stderr.write(payload);
|
|
2888
|
-
break;
|
|
2889
|
-
}
|
|
2890
|
-
buffer = buffer.subarray(HEADER_SIZE + payloadSize);
|
|
2891
|
-
}
|
|
2892
|
-
}
|
|
2893
|
-
source.on("data", (chunk) => {
|
|
2894
|
-
buffer = Buffer.concat([buffer, chunk]);
|
|
2895
|
-
processBuffer();
|
|
2896
|
-
});
|
|
2897
|
-
source.on("end", () => {
|
|
2898
|
-
stdout.end();
|
|
2899
|
-
stderr.end();
|
|
2900
|
-
});
|
|
2901
|
-
source.on("error", (err) => {
|
|
2902
|
-
stdout.destroy(err);
|
|
2903
|
-
stderr.destroy(err);
|
|
2904
|
-
});
|
|
2905
|
-
return {
|
|
2906
|
-
stdout,
|
|
2907
|
-
stderr
|
|
2908
|
-
};
|
|
2909
|
-
}
|
|
2910
|
-
/**
|
|
2911
|
-
* Follows a newline-delimited JSON progress stream (e.g., from pull/push/build).
|
|
2912
|
-
* Accumulates all events and calls onFinished when the stream ends.
|
|
2913
|
-
* Optionally calls onProgress for each event as it arrives.
|
|
2914
|
-
*/
|
|
2915
|
-
function followProgress(stream, onFinished, onProgress) {
|
|
2916
|
-
const output = [];
|
|
2917
|
-
let buffer = "";
|
|
2918
|
-
stream.on("data", (chunk) => {
|
|
2919
|
-
buffer += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
|
|
2920
|
-
const lines = buffer.split("\n");
|
|
2921
|
-
buffer = lines.pop() ?? "";
|
|
2922
|
-
for (const line of lines) {
|
|
2923
|
-
const trimmed = line.trim();
|
|
2924
|
-
if (trimmed.length === 0) continue;
|
|
2925
|
-
try {
|
|
2926
|
-
const obj = JSON.parse(trimmed);
|
|
2927
|
-
output.push(obj);
|
|
2928
|
-
if (onProgress) onProgress(obj);
|
|
2929
|
-
} catch {}
|
|
2930
|
-
}
|
|
2931
|
-
});
|
|
2932
|
-
stream.on("end", () => {
|
|
2933
|
-
if (buffer.trim().length > 0) try {
|
|
2934
|
-
const obj = JSON.parse(buffer.trim());
|
|
2935
|
-
output.push(obj);
|
|
2936
|
-
if (onProgress) onProgress(obj);
|
|
2937
|
-
} catch {}
|
|
2938
|
-
onFinished(null, output);
|
|
2939
|
-
});
|
|
2940
|
-
stream.on("error", (err) => {
|
|
2941
|
-
onFinished(err, output);
|
|
2942
|
-
});
|
|
2943
|
-
}
|
|
2944
|
-
|
|
2945
|
-
//#endregion
|
|
2946
|
-
export { ConfigEntity, ConfigOperations, Container, ContainerOperations, Docker, DockerAbortError, DockerBadRequestError, DockerConflictError, DockerDecodeError, DockerForbiddenError, DockerNetworkError, DockerNotFoundError, DockerServerError, DockerServiceUnavailableError, DockerStream, DockerTimeoutError, DockerUnauthorizedError, DockerUnknownError, Exec, HttpDuplex, Image, ImageOperations, NamedPipeTransport, NetworkEntity, NetworkOperations, NodeEntity, NodeOperations, PluginEntity, PluginOperations, SecretEntity, SecretOperations, ServiceEntity, ServiceOperations, SystemOperations, TaskEntity, TaskOperations, VolumeEntity, VolumeOperations, createTransport, createTransportFromEnv, demuxStream, followProgress, statusCodeToError, withSession };
|
|
2947
|
-
//# sourceMappingURL=index.mjs.map
|
|
1
|
+
import*as e from"node:fs";import*as t from"node:path";import*as n from"node:http";import{Result as r,TaggedError as i}from"better-result";import*as a from"node:https";import{Client as o}from"ssh2";import{Duplex as s,PassThrough as c,Readable as l}from"node:stream";import*as u from"@grpc/grpc-js";import*as d from"@grpc/proto-loader";import{randomUUID as f}from"node:crypto";import{EventEmitter as ee}from"node:events";var p=class extends i(`DockerBadRequestError`)(){statusCode=400},m=class extends i(`DockerUnauthorizedError`)(){statusCode=401},h=class extends i(`DockerForbiddenError`)(){statusCode=403},g=class extends i(`DockerNotFoundError`)(){statusCode=404},_=class extends i(`DockerConflictError`)(){statusCode=409},v=class extends i(`DockerServerError`)(){statusCode=500},y=class extends i(`DockerServiceUnavailableError`)(){statusCode=503},b=class extends i(`DockerNetworkError`)(){},x=class extends i(`DockerTimeoutError`)(){},S=class extends i(`DockerAbortError`)(){},te=class extends i(`DockerDecodeError`)(){},C=class extends i(`DockerUnknownError`)(){};function w(e,t){switch(e){case 400:return new p({message:t});case 401:return new m({message:t});case 403:return new h({message:t});case 404:return new g({message:t});case 409:return new _({message:t});case 500:return new v({message:t});case 503:return new y({message:t});default:return new C({message:t,statusCode:e})}}function T(e,t){if(!t||Object.keys(t).length===0)return e;let n=new URLSearchParams;for(let[e,r]of Object.entries(t))r!=null&&n.append(e,String(r));return`${e}?${n.toString()}`}function E(e){return new Promise((t,n)=>{let r=[];e.on(`data`,e=>r.push(e)),e.on(`end`,()=>t(Buffer.concat(r).toString(`utf-8`))),e.on(`error`,n)})}function D(e){try{let t=JSON.parse(e);if(typeof t==`object`&&t&&typeof t.message==`string`)return t.message}catch{}return e||`Unknown error`}var O=class{socketPath;requestFn;constructor(e){this.socketPath=e.socketPath??process.env.DOCKER_HOST?.replace(`unix://`,``)??`/var/run/docker.sock`,this.requestFn=e._requestFn??n.request}async dial(e){return r.tryPromise({try:()=>this.performRequest(e,!1),catch:e=>this.convertError(e)})}async dialStream(e){return r.tryPromise({try:()=>this.performRequest(e,!0),catch:e=>this.convertError(e)})}async dialHijack(e){return r.tryPromise({try:()=>this.performHijack(e),catch:e=>this.convertError(e)})}destroy(){}performHijack(e){return new Promise((t,n)=>{let r=T(e.path,e.query),i={Connection:`Upgrade`,Upgrade:`tcp`,...e.headers};e.authconfig&&(i[`X-Registry-Auth`]=Buffer.from(JSON.stringify(e.authconfig)).toString(`base64`));let a=e.body,o;a!==void 0&&typeof a!=`string`&&!Buffer.isBuffer(a)&&(o=JSON.stringify(a),!i[`Content-Type`]&&!i[`content-type`]&&(i[`Content-Type`]=`application/json`),i[`Content-Length`]=Buffer.byteLength(o).toString());let s=this.requestFn({socketPath:this.socketPath,path:r,method:e.method,headers:i},e=>{n(new b({message:`Expected upgrade response, got status ${e.statusCode}`,cause:void 0}))});s.on(`upgrade`,(e,n,r)=>{t(n)}),s.on(`error`,e=>{n(new b({message:`Connection error: ${e.message}`,cause:e}))}),o!==void 0&&s.write(o),s.end()})}performRequest(e,t){return new Promise((n,r)=>{let i=T(e.path,e.query),a={...e.headers};e.authconfig&&(a[`X-Registry-Auth`]=Buffer.from(JSON.stringify(e.authconfig)).toString(`base64`)),e.registryconfig&&(a[`X-Registry-Config`]=Buffer.from(JSON.stringify(e.registryconfig)).toString(`base64`));let o=e.body,s=typeof o==`object`&&!!o&&typeof o.pipe==`function`,c=Buffer.isBuffer(o),l=typeof o==`string`,u;o!==void 0&&!s&&!c&&!l?(u=JSON.stringify(o),!a[`Content-Type`]&&!a[`content-type`]&&(a[`Content-Type`]=`application/json`),a[`Content-Length`]=Buffer.byteLength(u).toString()):c?a[`Content-Length`]=o.length.toString():l?a[`Content-Length`]=Buffer.byteLength(o).toString():s&&(a[`Transfer-Encoding`]=`chunked`);let d=this.requestFn({socketPath:this.socketPath,path:i,method:e.method,headers:a},i=>{let a=i.statusCode??0,o=i.headers??{},s=e.statusCodes[a]===!0;if(t&&s){n(i);return}E(i).then(e=>{if(s){if(a===204||e.length===0){n({statusCode:a,headers:o,body:null});return}try{n({statusCode:a,headers:o,body:JSON.parse(e)})}catch{n({statusCode:a,headers:o,body:e})}}else r(w(a,D(e)))}).catch(e=>{r(new b({message:`Failed to read response body: ${String(e)}`,cause:e}))})});if(d.on(`error`,e=>{r(new b({message:`Connection error: ${e.message}`,cause:e}))}),e.timeout!==void 0&&d.setTimeout(e.timeout,()=>{d.destroy(),r(new x({message:`Request timed out after ${e.timeout}ms`,timeoutMs:e.timeout}))}),e.signal){if(e.signal.aborted){d.destroy(),r(new S({message:`Request aborted`}));return}e.signal.addEventListener(`abort`,()=>{d.destroy(),r(new S({message:`Request aborted`}))},{once:!0})}s?o.pipe(d):c||l?(d.write(o),d.end()):(u===void 0||d.write(u),d.end())})}convertError(e){return typeof e==`object`&&e&&`_tag`in e?e:new b({message:`Unexpected error: ${e instanceof Error?e.message:String(e)}`,cause:e})}},k=class{host;port;agent;useHttps;requestFn;constructor(e){this.useHttps=!!e.tls,this.host=e.host,this.port=e.port??(this.useHttps?2376:2375),e.tls&&(this.agent=new a.Agent({ca:e.tls.ca,cert:e.tls.cert,key:e.tls.key,rejectUnauthorized:e.tls.rejectUnauthorized??!0})),this.requestFn=e._requestFn??(this.useHttps?a.request:n.request)}async dial(e){return r.tryPromise({try:()=>this.performRequest(e,!1),catch:e=>this.convertError(e)})}async dialStream(e){return r.tryPromise({try:()=>this.performRequest(e,!0),catch:e=>this.convertError(e)})}async dialHijack(e){return r.tryPromise({try:()=>this.performHijack(e),catch:e=>this.convertError(e)})}destroy(){this.agent&&this.agent.destroy()}performHijack(e){return new Promise((t,n)=>{let r=T(e.path,e.query),i={Connection:`Upgrade`,Upgrade:`tcp`,...e.headers};e.authconfig&&(i[`X-Registry-Auth`]=Buffer.from(JSON.stringify(e.authconfig)).toString(`base64`));let a=e.body,o;a!==void 0&&typeof a!=`string`&&!Buffer.isBuffer(a)&&(o=JSON.stringify(a),!i[`Content-Type`]&&!i[`content-type`]&&(i[`Content-Type`]=`application/json`),i[`Content-Length`]=Buffer.byteLength(o).toString());let s={hostname:this.host,port:this.port,path:r,method:e.method,headers:i};this.agent&&(s.agent=this.agent);let c=this.requestFn(s,e=>{n(new b({message:`Expected upgrade response, got status ${e.statusCode}`,cause:void 0}))});c.on(`upgrade`,(e,n,r)=>{t(n)}),c.on(`error`,e=>{n(new b({message:`Connection error: ${e.message}`,cause:e}))}),o!==void 0&&c.write(o),c.end()})}performRequest(e,t){return new Promise((n,r)=>{let i=T(e.path,e.query),a={...e.headers};e.authconfig&&(a[`X-Registry-Auth`]=Buffer.from(JSON.stringify(e.authconfig)).toString(`base64`)),e.registryconfig&&(a[`X-Registry-Config`]=Buffer.from(JSON.stringify(e.registryconfig)).toString(`base64`));let o=e.body,s=typeof o==`object`&&!!o&&typeof o.pipe==`function`,c=Buffer.isBuffer(o),l=typeof o==`string`,u;o!==void 0&&!s&&!c&&!l?(u=JSON.stringify(o),!a[`Content-Type`]&&!a[`content-type`]&&(a[`Content-Type`]=`application/json`),a[`Content-Length`]=Buffer.byteLength(u).toString()):c?a[`Content-Length`]=o.length.toString():l?a[`Content-Length`]=Buffer.byteLength(o).toString():s&&(a[`Transfer-Encoding`]=`chunked`);let d={hostname:this.host,port:this.port,path:i,method:e.method,headers:a};this.agent&&(d.agent=this.agent);let f=this.requestFn(d,i=>{let a=i.statusCode??0,o=i.headers??{},s=e.statusCodes[a]===!0;if(t&&s){n(i);return}E(i).then(e=>{if(s){if(a===204||e.length===0){n({statusCode:a,headers:o,body:null});return}try{n({statusCode:a,headers:o,body:JSON.parse(e)})}catch{n({statusCode:a,headers:o,body:e})}}else r(w(a,D(e)))}).catch(e=>{r(new b({message:`Failed to read response body: ${String(e)}`,cause:e}))})});if(f.on(`error`,e=>{r(new b({message:`Connection error: ${e.message}`,cause:e}))}),e.timeout!==void 0&&f.setTimeout(e.timeout,()=>{f.destroy(),r(new x({message:`Request timed out after ${e.timeout}ms`,timeoutMs:e.timeout}))}),e.signal){if(e.signal.aborted){f.destroy(),r(new S({message:`Request aborted`}));return}e.signal.addEventListener(`abort`,()=>{f.destroy(),r(new S({message:`Request aborted`}))},{once:!0})}s?o.pipe(f):c||l?(f.write(o),f.end()):(u===void 0||f.write(u),f.end())})}convertError(e){return typeof e==`object`&&e&&`_tag`in e?e:new b({message:`Unexpected error: ${e instanceof Error?e.message:String(e)}`,cause:e})}};function ne(e){let t=T(e.path,e.query),n={Host:`docker`,...e.headers};e.authconfig&&(n[`X-Registry-Auth`]=Buffer.from(JSON.stringify(e.authconfig)).toString(`base64`)),e.registryconfig&&(n[`X-Registry-Config`]=Buffer.from(JSON.stringify(e.registryconfig)).toString(`base64`));let r=e.body,i=typeof r==`object`&&!!r&&typeof r.pipe==`function`,a=Buffer.isBuffer(r),o=typeof r==`string`,s;r!==void 0&&!i&&!a&&!o?(s=JSON.stringify(r),!n[`Content-Type`]&&!n[`content-type`]&&(n[`Content-Type`]=`application/json`),n[`Content-Length`]=Buffer.byteLength(s).toString()):a?(s=r.toString(),n[`Content-Length`]=r.length.toString()):o?(s=r,n[`Content-Length`]=Buffer.byteLength(r).toString()):i&&(n[`Transfer-Encoding`]=`chunked`);let c=`${e.method} ${t} HTTP/1.1\r\n`;for(let[e,t]of Object.entries(n))c+=`${e}: ${t}\r\n`;return c+=`\r
|
|
2
|
+
`,{header:c,bodyStr:s}}function re(e){let t=e.indexOf(`\r
|
|
3
|
+
\r
|
|
4
|
+
`),n=t>=0?e.slice(0,t):e,r=t>=0?e.slice(t+4):``,i=n.split(`\r
|
|
5
|
+
`),a=(i[0]??``).match(/^HTTP\/\d\.\d\s+(\d+)/),o=a?.[1]?Number.parseInt(a[1],10):0,s={};for(let e=1;e<i.length;e++){let t=i[e];if(!t)continue;let n=t.indexOf(`:`);if(n>0){let e=t.slice(0,n).trim().toLowerCase();s[e]=t.slice(n+1).trim()}}return{statusCode:o,headers:s,body:r}}var ie=class{host;port;username;privateKey;passphrase;clientFactory;constructor(e){this.host=e.host,this.port=e.port??22,this.username=e.username,this.privateKey=e.privateKey,this.passphrase=e.passphrase,this.clientFactory=e._clientFactory??(()=>new o)}async dial(e){return r.tryPromise({try:()=>this.performRequest(e,!1),catch:e=>this.convertError(e)})}async dialStream(e){return r.tryPromise({try:()=>this.performRequest(e,!0),catch:e=>this.convertError(e)})}async dialHijack(e){return r.err(new b({message:`dialHijack is not supported over SSH transport`,cause:void 0}))}destroy(){}performRequest(e,t){return new Promise((n,r)=>{let i=this.clientFactory();i.on(`ready`,()=>{i.exec(`docker system dial-stdio`,(a,o)=>{if(a){i.end(),r(new b({message:`SSH exec error: ${a.message}`,cause:a}));return}let{header:s,bodyStr:c}=ne(e);o.write(s);let u=e.body;typeof u==`object`&&u&&typeof u.pipe==`function`?u.pipe(o,{end:!1}):c!==void 0&&o.write(c);let d=[];o.on(`data`,e=>{d.push(e)}),o.on(`end`,()=>{i.end();let{statusCode:a,headers:o,body:s}=re(Buffer.concat(d).toString(`utf-8`)),c=e.statusCodes[a]===!0;if(t&&c){n(new l({read(){this.push(s?Buffer.from(s):null),this.push(null)}}));return}if(c){if(a===204||s.length===0){n({statusCode:a,headers:o,body:null});return}try{n({statusCode:a,headers:o,body:JSON.parse(s)})}catch{n({statusCode:a,headers:o,body:s})}}else r(w(a,D(s)))}),o.on(`error`,e=>{i.end(),r(new b({message:`Stream error: ${e.message}`,cause:e}))})})}),i.on(`error`,e=>{r(new b({message:`SSH connection error: ${e.message}`,cause:e}))}),i.connect({host:this.host,port:this.port,username:this.username,privateKey:this.privateKey,passphrase:this.passphrase})})}convertError(e){return typeof e==`object`&&e&&`_tag`in e?e:new b({message:`Unexpected error: ${e instanceof Error?e.message:String(e)}`,cause:e})}},A=class{pipePath;requestFn;constructor(e){this.pipePath=e.path??`\\\\.\\pipe\\docker_engine`,this.requestFn=e._requestFn??n.request}async dial(e){return r.tryPromise({try:()=>this.performRequest(e,!1),catch:e=>this.convertError(e)})}async dialStream(e){return r.tryPromise({try:()=>this.performRequest(e,!0),catch:e=>this.convertError(e)})}async dialHijack(e){return r.tryPromise({try:()=>this.performHijack(e),catch:e=>this.convertError(e)})}destroy(){}performHijack(e){return new Promise((t,n)=>{let r=T(e.path,e.query),i={Connection:`Upgrade`,Upgrade:`tcp`,...e.headers};e.authconfig&&(i[`X-Registry-Auth`]=Buffer.from(JSON.stringify(e.authconfig)).toString(`base64`));let a=e.body,o;a!==void 0&&typeof a!=`string`&&!Buffer.isBuffer(a)&&(o=JSON.stringify(a),!i[`Content-Type`]&&!i[`content-type`]&&(i[`Content-Type`]=`application/json`),i[`Content-Length`]=Buffer.byteLength(o).toString());let s=this.requestFn({socketPath:this.pipePath,path:r,method:e.method,headers:i},e=>{n(new b({message:`Expected upgrade response, got status ${e.statusCode}`,cause:void 0}))});s.on(`upgrade`,(e,n,r)=>{t(n)}),s.on(`error`,e=>{n(new b({message:`Connection error: ${e.message}`,cause:e}))}),o!==void 0&&s.write(o),s.end()})}performRequest(e,t){return new Promise((n,r)=>{let i=T(e.path,e.query),a={...e.headers};e.authconfig&&(a[`X-Registry-Auth`]=Buffer.from(JSON.stringify(e.authconfig)).toString(`base64`)),e.registryconfig&&(a[`X-Registry-Config`]=Buffer.from(JSON.stringify(e.registryconfig)).toString(`base64`));let o=e.body,s=typeof o==`object`&&!!o&&typeof o.pipe==`function`,c=Buffer.isBuffer(o),l=typeof o==`string`,u;o!==void 0&&!s&&!c&&!l?(u=JSON.stringify(o),!a[`Content-Type`]&&!a[`content-type`]&&(a[`Content-Type`]=`application/json`),a[`Content-Length`]=Buffer.byteLength(u).toString()):c?a[`Content-Length`]=o.length.toString():l?a[`Content-Length`]=Buffer.byteLength(o).toString():s&&(a[`Transfer-Encoding`]=`chunked`);let d=this.requestFn({socketPath:this.pipePath,path:i,method:e.method,headers:a},i=>{let a=i.statusCode??0,o=i.headers??{},s=e.statusCodes[a]===!0;if(t&&s){n(i);return}E(i).then(e=>{if(s){if(a===204||e.length===0){n({statusCode:a,headers:o,body:null});return}try{n({statusCode:a,headers:o,body:JSON.parse(e)})}catch{n({statusCode:a,headers:o,body:e})}}else r(w(a,D(e)))}).catch(e=>{r(new b({message:`Failed to read response body: ${String(e)}`,cause:e}))})});if(d.on(`error`,e=>{r(new b({message:`Connection error: ${e.message}`,cause:e}))}),e.timeout!==void 0&&d.setTimeout(e.timeout,()=>{d.destroy(),r(new x({message:`Request timed out after ${e.timeout}ms`,timeoutMs:e.timeout}))}),e.signal){if(e.signal.aborted){d.destroy(),r(new S({message:`Request aborted`}));return}e.signal.addEventListener(`abort`,()=>{d.destroy(),r(new S({message:`Request aborted`}))},{once:!0})}s?o.pipe(d):c||l?(d.write(o),d.end()):(u===void 0||d.write(u),d.end())})}convertError(e){return typeof e==`object`&&e&&`_tag`in e?e:new b({message:`Unexpected error: ${e instanceof Error?e.message:String(e)}`,cause:e})}};function ae(e){switch(e.type){case`unix`:return new O({socketPath:e.socketPath});case`tcp`:return new k({host:e.host,port:e.port,tls:e.tls});case`ssh`:return new ie({host:e.host,port:e.port,username:e.username,privateKey:e.privateKey});case`npipe`:return new A({path:e.path})}}function oe(){let n=process.env.DOCKER_HOST,r=process.env.DOCKER_TLS_VERIFY===`1`,i=process.env.DOCKER_CERT_PATH;if(!n)return new O({});if(n.startsWith(`unix://`))return new O({socketPath:n.replace(`unix://`,``)});if(n.startsWith(`npipe://`))return new A({path:n.replace(`npipe://`,``)});if(n.startsWith(`ssh://`)){let e=new URL(n);return new ie({host:e.hostname,port:e.port?Number.parseInt(e.port,10):22,username:e.username||`root`})}if(n.startsWith(`tcp://`)){let a=new URL(n),o=a.hostname,s=a.port?Number.parseInt(a.port,10):void 0,c;if((r||i)&&(c={rejectUnauthorized:r},i)){let n=t.join(i,`ca.pem`),r=t.join(i,`cert.pem`),a=t.join(i,`key.pem`);e.existsSync(n)&&(c.ca=e.readFileSync(n,`utf-8`)),e.existsSync(r)&&(c.cert=e.readFileSync(r,`utf-8`)),e.existsSync(a)&&(c.key=e.readFileSync(a,`utf-8`))}return new k({host:o,port:s,tls:c})}return new O({socketPath:n})}async function j(e,t){return(await e.dial(t)).map(e=>e.body)}async function M(e,t){return(await e.dial(t)).map(()=>void 0)}var N=class{constructor(e,t){this.transport=e,this.apiVersion=t}async ping(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/_ping`,statusCodes:{200:!0,500:`server error`}})}async info(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/info`,statusCodes:{200:!0,500:`server error`}})}async version(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/version`,statusCodes:{200:!0,500:`server error`}})}async df(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/system/df`,statusCodes:{200:!0,500:`server error`}})}async swarmInit(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/swarm/init`,body:e,statusCodes:{200:!0,400:`bad parameter`,500:`server error`,503:`node is already part of a swarm`}})}async swarmJoin(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/swarm/join`,body:e,statusCodes:{200:!0,400:`bad parameter`,500:`server error`,503:`node is already part of a swarm`}})}async swarmLeave(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/swarm/leave`,query:e,statusCodes:{200:!0,500:`server error`,503:`node is not part of a swarm`}})}async swarmUpdate(e){let{version:t,rotateWorkerToken:n,rotateManagerToken:r,rotateManagerUnlockKey:i,...a}=e,o={version:t};return n!==void 0&&(o.rotateWorkerToken=n),r!==void 0&&(o.rotateManagerToken=r),i!==void 0&&(o.rotateManagerUnlockKey=i),M(this.transport,{method:`POST`,path:`/${this.apiVersion}/swarm/update`,query:o,body:a,statusCodes:{200:!0,400:`bad parameter`,500:`server error`,503:`node is not part of a swarm`}})}async swarmInspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/swarm`,statusCodes:{200:!0,500:`server error`,503:`node is not part of a swarm`}})}async events(e){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/events`,query:e,statusCodes:{200:!0,500:`server error`}})}async auth(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/auth`,body:e,statusCodes:{200:!0,204:!0,500:`server error`}})}async pruneBuilder(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/build/prune`,query:e,statusCodes:{200:!0,500:`server error`}})}},P=class extends s{socket;constructor(e){super(),this.socket=e,e.on(`data`,t=>{this.push(t)||e.pause()}),e.on(`end`,()=>{this.push(null)}),e.on(`error`,e=>{this.destroy(e)}),e.on(`close`,()=>{this.push(null)})}_read(e){this.socket.resume()}_write(e,t,n){this.socket.write(e,n)}_final(e){this.socket.end(e)}_destroy(e,t){this.socket.destroy(e??void 0),t(e)}},F=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async start(e){let{stdin:t,...n}=e??{};return t?(await this.transport.dialHijack({method:`POST`,path:`/${this.apiVersion}/exec/${this.id}/start`,body:n,hijack:!0,openStdin:!0,statusCodes:{200:!0,101:!0,404:`no such exec instance`,409:`container is paused`,500:`server error`}})).map(e=>new P(e)):this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/exec/${this.id}/start`,body:Object.keys(n).length>0?n:void 0,statusCodes:{200:!0,404:`no such exec instance`,409:`container is paused`,500:`server error`}})}async resize(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/exec/${this.id}/resize`,query:e,statusCodes:{200:!0,404:`no such exec instance`,500:`server error`}})}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/exec/${this.id}/json`,statusCodes:{200:!0,404:`no such exec instance`,500:`server error`}})}},I=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/json`,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async start(){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/start`,statusCodes:{204:!0,304:!0,404:`no such container`,500:`server error`}})}async stop(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/stop`,query:e,statusCodes:{204:!0,304:!0,404:`no such container`,500:`server error`}})}async restart(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/restart`,query:e,statusCodes:{204:!0,404:`no such container`,500:`server error`}})}async kill(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/kill`,query:e,statusCodes:{204:!0,404:`no such container`,409:`container is not running`,500:`server error`}})}async pause(){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/pause`,statusCodes:{204:!0,404:`no such container`,500:`server error`}})}async unpause(){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/unpause`,statusCodes:{204:!0,404:`no such container`,500:`server error`}})}async remove(e){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/containers/${this.id}`,query:e,statusCodes:{204:!0,400:`bad parameter`,404:`no such container`,409:`conflict`,500:`server error`}})}async rename(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/rename`,query:{name:e},statusCodes:{204:!0,404:`no such container`,409:`name already in use`,500:`server error`}})}async update(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/update`,body:e,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async top(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/top`,query:e?{ps_args:e}:void 0,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async changes(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/changes`,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async logs(e){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/logs`,query:e,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async stats(e){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/stats`,query:e,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async wait(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/wait`,query:e,statusCodes:{200:!0,400:`bad parameter`,404:`no such container`,500:`server error`}})}async resize(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/resize`,query:e,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async attach(e){return e?.stdin?(await this.transport.dialHijack({method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/attach`,query:e,hijack:!0,openStdin:!0,statusCodes:{200:!0,101:!0,404:`no such container`,500:`server error`}})).map(e=>new P(e)):this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/attach`,query:e,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async exec(e){return(await j(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/exec`,body:e,statusCodes:{201:!0,404:`no such container`,409:`container is paused`,500:`server error`}})).map(e=>new F(this.transport,this.apiVersion,e.Id))}async export(){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/export`,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async getArchive(e){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/archive`,query:{path:e.path},statusCodes:{200:!0,400:`bad parameter`,404:`no such container`,500:`server error`}})}async putArchive(e,t){return M(this.transport,{method:`PUT`,path:`/${this.apiVersion}/containers/${this.id}/archive`,query:{path:e.path},body:t,headers:{"content-type":`application/x-tar`},statusCodes:{200:!0,400:`bad parameter`,403:`permission denied`,404:`no such container`,500:`server error`}})}async listCheckpoints(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/containers/${this.id}/checkpoints`,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async createCheckpoint(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/${this.id}/checkpoints`,body:e,statusCodes:{201:!0,404:`no such container`,500:`server error`}})}async deleteCheckpoint(e){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/containers/${this.id}/checkpoints/${e}`,statusCodes:{204:!0,404:`no such checkpoint`,500:`server error`}})}async infoArchive(e){return(await this.transport.dial({method:`HEAD`,path:`/${this.apiVersion}/containers/${this.id}/archive`,query:{path:e.path},statusCodes:{200:!0,400:`bad parameter`,404:`no such container`,500:`server error`}})).map(e=>{let t=e.headers[`x-docker-container-path-stat`];return t?JSON.parse(Buffer.from(t,`base64`).toString(`utf-8`)):{}})}async commit(e){let t={container:this.id};if(e){let{repo:n,tag:r,comment:i,author:a,pause:o,changes:s,...c}=e;n!==void 0&&(t.repo=n),r!==void 0&&(t.tag=r),i!==void 0&&(t.comment=i),a!==void 0&&(t.author=a),o!==void 0&&(t.pause=o),s!==void 0&&(t.changes=s),Object.assign(t,c)}return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/commit`,query:t,statusCodes:{201:!0,404:`no such container`,500:`server error`}})}},L=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/containers/json`,query:e,statusCodes:{200:!0,400:`bad parameter`,500:`server error`}})}async create(e){let{name:t,platform:n,...r}=e,i={};return t!==void 0&&(i.name=t),n!==void 0&&(i.platform=n),(await j(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/create`,query:Object.keys(i).length>0?i:void 0,body:r,statusCodes:{201:!0,400:`bad parameter`,404:`no such image`,409:`conflict`,500:`server error`}})).map(e=>new I(this.transport,this.apiVersion,e.Id))}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/containers/${e}/json`,statusCodes:{200:!0,404:`no such container`,500:`server error`}})}async prune(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/containers/prune`,query:e,statusCodes:{200:!0,500:`server error`}})}getContainer(e){return new I(this.transport,this.apiVersion,e)}};async function R(e,n,i){let a=f(),o=await e.dialHijack({method:`POST`,path:`/${n}/session`,hijack:!0,headers:{Upgrade:`h2c`,"X-Docker-Expose-Session-Uuid":a,"X-Docker-Expose-Session-Name":`docker-sdk`},statusCodes:{200:!0,101:!0,500:`server error`}});if(o.isErr())return o;let s=o.value;try{let e=new u.Server,n=u.ServerCredentials.createInsecure();e.createConnectionInjector(n).injectConnection(s);let o=t.resolve(import.meta.dirname,`auth.proto`),c=d.loadSync(o),l=u.loadPackageDefinition(c).moby?.filesync?.v1?.Auth?.service;return l&&e.addService(l,{Credentials({request:e},t){i?t(null,{Username:i.username??``,Secret:i.password??``}):t(null,{})},FetchToken(e,t){t(null,{})},GetTokenAuthority(e,t){t(null,{})},VerifyTokenAuthority(e,t){t(null,{})}}),r.ok({sessionId:a,close:()=>{e.forceShutdown(),s.end()}})}catch(e){return s.end(),r.err(new b({message:`Failed to create gRPC session: ${e instanceof Error?e.message:String(e)}`,cause:e}))}}var z=class{name;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.name=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/images/${this.name}/json`,statusCodes:{200:!0,404:`no such image`,500:`server error`}})}async history(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/images/${this.name}/history`,statusCodes:{200:!0,404:`no such image`,500:`server error`}})}async push(e){return this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/images/${this.name}/push`,query:e,statusCodes:{200:!0,404:`no such image`,500:`server error`}})}async tag(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/images/${this.name}/tag`,query:e,statusCodes:{201:!0,400:`bad parameter`,404:`no such image`,409:`conflict`,500:`server error`}})}async remove(e){return j(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/images/${this.name}`,query:e,statusCodes:{200:!0,404:`no such image`,409:`conflict`,500:`server error`}})}async get(){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/images/${this.name}/get`,statusCodes:{200:!0,500:`server error`}})}async distribution(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/distribution/${this.name}/json`,statusCodes:{200:!0,401:`authentication required`,500:`server error`}})}},B=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/images/json`,query:e,statusCodes:{200:!0,500:`server error`}})}async create(e){return this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/images/create`,query:e,statusCodes:{200:!0,404:`no such image`,500:`server error`}})}async build(e,t){let{authconfig:n,registryconfig:r,...i}=t??{};if(i.version===`2`){let t=await R(this.transport,this.apiVersion,n);if(t.isErr())return t;let{sessionId:a,close:o}=t.value;i.session=a;let s=await this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/build`,query:Object.keys(i).length>0?i:void 0,body:e,headers:{"Content-Type":`application/x-tar`},registryconfig:r,statusCodes:{200:!0,400:`bad parameter`,500:`server error`}});if(s.isErr())return o(),s;let c=s.value;return c.on(`end`,o),c.on(`error`,o),s}return this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/build`,query:Object.keys(i).length>0?i:void 0,body:e,headers:{"Content-Type":`application/x-tar`},authconfig:n,registryconfig:r,statusCodes:{200:!0,400:`bad parameter`,500:`server error`}})}async load(e){return this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/images/load`,body:e,headers:{"Content-Type":`application/x-tar`},statusCodes:{200:!0,500:`server error`}})}async import(e,t){return this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/images/create`,query:{fromSrc:`-`,...t},body:e,headers:{"Content-Type":`application/x-tar`},statusCodes:{200:!0,500:`server error`}})}async search(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/images/search`,query:e,statusCodes:{200:!0,500:`server error`}})}async prune(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/images/prune`,query:e,statusCodes:{200:!0,500:`server error`}})}getImage(e){return new z(this.transport,this.apiVersion,e)}},V=class{name;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.name=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/volumes/${this.name}`,statusCodes:{200:!0,404:`no such volume`,500:`server error`}})}async remove(e){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/volumes/${this.name}`,query:e,statusCodes:{204:!0,404:`no such volume`,409:`volume in use`,500:`server error`}})}},H=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/volumes`,query:e,statusCodes:{200:!0,500:`server error`}})}async create(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/volumes/create`,body:e,statusCodes:{201:!0,500:`server error`}})}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/volumes/${e}`,statusCodes:{200:!0,404:`no such volume`,500:`server error`}})}async prune(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/volumes/prune`,query:e,statusCodes:{200:!0,500:`server error`}})}getVolume(e){return new V(this.transport,this.apiVersion,e)}},U=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/networks/${this.id}`,statusCodes:{200:!0,404:`network not found`,500:`server error`}})}async remove(){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/networks/${this.id}`,statusCodes:{204:!0,403:`operation forbidden`,404:`no such network`,500:`server error`}})}async connect(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/networks/${this.id}/connect`,body:e,statusCodes:{200:!0,400:`bad parameter`,403:`operation forbidden`,404:`network or container not found`,500:`server error`}})}async disconnect(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/networks/${this.id}/disconnect`,body:e,statusCodes:{200:!0,403:`operation forbidden`,404:`network or container not found`,500:`server error`}})}},W=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/networks`,query:e,statusCodes:{200:!0,500:`server error`}})}async create(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/networks/create`,body:e,statusCodes:{201:!0,400:`bad parameter`,403:`operation forbidden`,404:`plugin not found`,500:`server error`}})}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/networks/${e}`,statusCodes:{200:!0,404:`network not found`,500:`server error`}})}async prune(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/networks/prune`,query:e,statusCodes:{200:!0,500:`server error`}})}getNetwork(e){return new U(this.transport,this.apiVersion,e)}},G=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/services/${this.id}`,statusCodes:{200:!0,404:`no such service`,500:`server error`,503:`node is not part of a swarm`}})}async update(e){let{version:t,registryAuthFrom:n,rollback:r,...i}=e,a={version:t};return n!==void 0&&(a.registryAuthFrom=n),r!==void 0&&(a.rollback=r),M(this.transport,{method:`POST`,path:`/${this.apiVersion}/services/${this.id}/update`,query:a,body:i,statusCodes:{200:!0,400:`bad parameter`,404:`no such service`,500:`server error`,503:`node is not part of a swarm`}})}async remove(){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/services/${this.id}`,statusCodes:{200:!0,404:`no such service`,500:`server error`,503:`node is not part of a swarm`}})}async logs(e){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/services/${this.id}/logs`,query:e,statusCodes:{200:!0,404:`no such service`,500:`server error`,503:`node is not part of a swarm`}})}},K=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/services`,query:e,statusCodes:{200:!0,500:`server error`,503:`node is not part of a swarm`}})}async create(e){let{...t}=e;return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/services/create`,body:t,statusCodes:{201:!0,400:`bad parameter`,403:`forbidden`,409:`name conflicts`,500:`server error`,503:`node is not part of a swarm`}})}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/services/${e}`,statusCodes:{200:!0,404:`no such service`,500:`server error`,503:`node is not part of a swarm`}})}getService(e){return new G(this.transport,this.apiVersion,e)}},q=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/tasks/${this.id}`,statusCodes:{200:!0,404:`no such task`,500:`server error`,503:`node is not part of a swarm`}})}async logs(e){return this.transport.dialStream({method:`GET`,path:`/${this.apiVersion}/tasks/${this.id}/logs`,query:e,statusCodes:{200:!0,404:`no such task`,500:`server error`,503:`node is not part of a swarm`}})}},J=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/tasks`,query:e,statusCodes:{200:!0,500:`server error`,503:`node is not part of a swarm`}})}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/tasks/${e}`,statusCodes:{200:!0,404:`no such task`,500:`server error`,503:`node is not part of a swarm`}})}getTask(e){return new q(this.transport,this.apiVersion,e)}},se=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/nodes/${this.id}`,statusCodes:{200:!0,404:`no such node`,500:`server error`,503:`node is not part of a swarm`}})}async update(e){let{version:t,...n}=e;return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/nodes/${this.id}/update`,query:{version:t},body:n,statusCodes:{200:!0,400:`bad parameter`,404:`no such node`,500:`server error`,503:`node is not part of a swarm`}})}async remove(e){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/nodes/${this.id}`,query:e,statusCodes:{200:!0,404:`no such node`,500:`server error`,503:`node is not part of a swarm`}})}},Y=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/nodes`,query:e,statusCodes:{200:!0,500:`server error`,503:`node is not part of a swarm`}})}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/nodes/${e}`,statusCodes:{200:!0,404:`no such node`,500:`server error`,503:`node is not part of a swarm`}})}getNode(e){return new se(this.transport,this.apiVersion,e)}},ce=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/secrets/${this.id}`,statusCodes:{200:!0,404:`no such secret`,500:`server error`,503:`node is not part of a swarm`}})}async update(e){let{version:t,...n}=e;return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/secrets/${this.id}/update`,query:{version:t},body:n,statusCodes:{200:!0,400:`bad parameter`,404:`no such secret`,500:`server error`,503:`node is not part of a swarm`}})}async remove(){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/secrets/${this.id}`,statusCodes:{204:!0,404:`no such secret`,500:`server error`,503:`node is not part of a swarm`}})}},X=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/secrets`,query:e,statusCodes:{200:!0,500:`server error`,503:`node is not part of a swarm`}})}async create(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/secrets/create`,body:e,statusCodes:{201:!0,409:`name conflicts`,500:`server error`,503:`node is not part of a swarm`}})}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/secrets/${e}`,statusCodes:{200:!0,404:`no such secret`,500:`server error`,503:`node is not part of a swarm`}})}getSecret(e){return new ce(this.transport,this.apiVersion,e)}},Z=class{id;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.id=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/configs/${this.id}`,statusCodes:{200:!0,404:`no such config`,500:`server error`,503:`node is not part of a swarm`}})}async update(e){let{version:t,...n}=e;return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/configs/${this.id}/update`,query:{version:t},body:n,statusCodes:{200:!0,400:`bad parameter`,404:`no such config`,500:`server error`,503:`node is not part of a swarm`}})}async remove(){return M(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/configs/${this.id}`,statusCodes:{204:!0,404:`no such config`,500:`server error`,503:`node is not part of a swarm`}})}},Q=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/configs`,query:e,statusCodes:{200:!0,500:`server error`,503:`node is not part of a swarm`}})}async create(e){return j(this.transport,{method:`POST`,path:`/${this.apiVersion}/configs/create`,body:e,statusCodes:{201:!0,409:`name conflicts`,500:`server error`,503:`node is not part of a swarm`}})}async inspect(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/configs/${e}`,statusCodes:{200:!0,404:`no such config`,500:`server error`,503:`node is not part of a swarm`}})}getConfig(e){return new Z(this.transport,this.apiVersion,e)}},le=class{name;constructor(e,t,n){this.transport=e,this.apiVersion=t,this.name=n}async inspect(){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/plugins/${this.name}/json`,statusCodes:{200:!0,404:`plugin is not found`,500:`server error`}})}async remove(e){return j(this.transport,{method:`DELETE`,path:`/${this.apiVersion}/plugins/${this.name}`,query:e,statusCodes:{200:!0,404:`plugin is not found`,500:`server error`}})}async enable(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/plugins/${this.name}/enable`,query:e,statusCodes:{200:!0,404:`plugin is not installed`,500:`server error`}})}async disable(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/plugins/${this.name}/disable`,body:e,statusCodes:{200:!0,404:`plugin is not installed`,500:`server error`}})}async push(){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/plugins/${this.name}/push`,statusCodes:{200:!0,404:`plugin is not found`,500:`server error`}})}async configure(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/plugins/${this.name}/set`,body:e.env,statusCodes:{204:!0,404:`plugin is not found`,500:`server error`}})}async upgrade(e){return this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/plugins/${this.name}/upgrade`,query:{remote:e.remote},statusCodes:{200:!0,404:`plugin is not found`,500:`server error`}})}},$=class{constructor(e,t){this.transport=e,this.apiVersion=t}async list(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/plugins`,query:e,statusCodes:{200:!0,500:`server error`}})}async privileges(e){return j(this.transport,{method:`GET`,path:`/${this.apiVersion}/plugins/privileges`,query:{remote:e.remote},statusCodes:{200:!0,500:`server error`}})}async install(e){let t={remote:e.remote};return e.name!==void 0&&(t.name=e.name),this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/plugins/pull`,query:t,statusCodes:{204:!0,500:`server error`}})}async create(e){return M(this.transport,{method:`POST`,path:`/${this.apiVersion}/plugins/create`,query:{name:e.name},statusCodes:{204:!0,500:`server error`}})}getPlugin(e){return new le(this.transport,this.apiVersion,e)}},ue=class e{system;containers;images;volumes;networks;services;tasks;nodes;secrets;configs;plugins;transport;apiVersion;constructor(e){this.transport=ae(e.transport),this.apiVersion=e.apiVersion;let t=e.apiVersion;this.system=new N(this.transport,t),this.containers=new L(this.transport,t),this.images=new B(this.transport,t),this.volumes=new H(this.transport,t),this.networks=new W(this.transport,t),this.services=new K(this.transport,t),this.tasks=new J(this.transport,t),this.nodes=new Y(this.transport,t),this.secrets=new X(this.transport,t),this.configs=new Q(this.transport,t),this.plugins=new $(this.transport,t)}static fromTransport(t,n){let r=Object.create(e.prototype),i=n.apiVersion;return r.transport=t,r.apiVersion=i,r.system=new N(t,i),r.containers=new L(t,i),r.images=new B(t,i),r.volumes=new H(t,i),r.networks=new W(t,i),r.services=new K(t,i),r.tasks=new J(t,i),r.nodes=new Y(t,i),r.secrets=new X(t,i),r.configs=new Q(t,i),r.plugins=new $(t,i),r}static fromEnv(t){let n=oe(),r=t?.apiVersion??`v1.47`,i=Object.create(e.prototype);return i.transport=n,i.apiVersion=r,i.system=new N(n,r),i.containers=new L(n,r),i.images=new B(n,r),i.volumes=new H(n,r),i.networks=new W(n,r),i.services=new K(n,r),i.tasks=new J(n,r),i.nodes=new Y(n,r),i.secrets=new X(n,r),i.configs=new Q(n,r),i.plugins=new $(n,r),i}async pull(e,t){let n=e.split(`:`),r=n.length>1?n.pop():`latest`,i=n.join(`:`);return this.transport.dialStream({method:`POST`,path:`/${this.apiVersion}/images/create`,query:{fromImage:i,tag:r},authconfig:t?.authconfig,statusCodes:{200:!0,404:`no such image`,500:`server error`}})}async run(e,t,n){let{autoRemove:r,...i}=n??{},a=await this.containers.create({...i,Image:e,Cmd:t,AttachStdout:!0,AttachStderr:!0});if(a.isErr())return a;let o=a.value,s=await o.attach({stream:!0,stdout:!0,stderr:!0});if(s.isErr())return s;let c=await o.start();if(c.isErr())return c;let l=await o.wait();return l.isErr()?l:(r&&await o.remove({force:!0}),l.map(e=>({output:e,container:o})))}destroy(){this.transport.destroy()}},de=class extends ee{isTty;source;constructor(e,t){super(),this.source=e,this.isTty=t,e.on(`data`,e=>this.emit(`data`,e)),e.on(`end`,()=>this.emit(`end`)),e.on(`error`,e=>this.emit(`error`,e))}destroy(){`destroy`in this.source&&typeof this.source.destroy==`function`&&this.source.destroy()}};function fe(e){let t=new c,n=new c,r=Buffer.alloc(0);function i(){for(;r.length>=8;){let e=r.readUInt8(0),i=r.readUInt32BE(4);if(r.length<8+i)break;let a=r.subarray(8,8+i);switch(e){case 1:t.write(a);break;case 2:n.write(a);break}r=r.subarray(8+i)}}return e.on(`data`,e=>{r=Buffer.concat([r,e]),i()}),e.on(`end`,()=>{t.end(),n.end()}),e.on(`error`,e=>{t.destroy(e),n.destroy(e)}),{stdout:t,stderr:n}}function pe(e,t,n){let r=[],i=``;e.on(`data`,e=>{i+=typeof e==`string`?e:e.toString(`utf-8`);let t=i.split(`
|
|
6
|
+
`);i=t.pop()??``;for(let e of t){let t=e.trim();if(t.length!==0)try{let e=JSON.parse(t);r.push(e),n&&n(e)}catch{}}}),e.on(`end`,()=>{if(i.trim().length>0)try{let e=JSON.parse(i.trim());r.push(e),n&&n(e)}catch{}t(null,r)}),e.on(`error`,e=>{t(e,r)})}export{Z as ConfigEntity,Q as ConfigOperations,I as Container,L as ContainerOperations,ue as Docker,S as DockerAbortError,p as DockerBadRequestError,_ as DockerConflictError,te as DockerDecodeError,h as DockerForbiddenError,b as DockerNetworkError,g as DockerNotFoundError,v as DockerServerError,y as DockerServiceUnavailableError,de as DockerStream,x as DockerTimeoutError,m as DockerUnauthorizedError,C as DockerUnknownError,F as Exec,P as HttpDuplex,z as Image,B as ImageOperations,A as NamedPipeTransport,U as NetworkEntity,W as NetworkOperations,se as NodeEntity,Y as NodeOperations,le as PluginEntity,$ as PluginOperations,ce as SecretEntity,X as SecretOperations,G as ServiceEntity,K as ServiceOperations,N as SystemOperations,q as TaskEntity,J as TaskOperations,V as VolumeEntity,H as VolumeOperations,ae as createTransport,oe as createTransportFromEnv,fe as demuxStream,pe as followProgress,w as statusCodeToError,R as withSession};
|