@dockstat/docker 0.1.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.
@@ -0,0 +1,384 @@
1
+ import type { BodyInit } from "bun"
2
+ import { BaseModule } from "../base"
3
+ import type { DockerWebSocket } from "../_socket"
4
+ import type {
5
+ ArchiveInfo,
6
+ AttachOptions,
7
+ ContainerConfig,
8
+ ContainerCreateResponse,
9
+ ContainerInspectResponse,
10
+ ContainerPruneResponse,
11
+ ContainerStatsResponse,
12
+ ContainerSummary,
13
+ ContainerTopResponse,
14
+ ContainerUpdateResponse,
15
+ ContainerWaitResponse,
16
+ CreateContainerOptions,
17
+ ExecCreateOptions,
18
+ ExecCreateResponse,
19
+ ExecInspectResponse,
20
+ ExecStartOptions,
21
+ FilesystemChange,
22
+ ListContainersOptions,
23
+ LogsOptions,
24
+ PruneContainersOptions,
25
+ StatsOptions,
26
+ UpdateContainerOptions,
27
+ WaitCondition,
28
+ } from "./types"
29
+
30
+ /**
31
+ * Container Module - handles all Docker container operations
32
+ */
33
+ export class ContainerModule extends BaseModule {
34
+ /**
35
+ * List containers
36
+ * @param options - List options
37
+ * @returns Array of container summaries
38
+ */
39
+ async list(options?: ListContainersOptions): Promise<ContainerSummary[]> {
40
+ const path = `/containers/json`
41
+ const res = await this.request(path, "GET", undefined, undefined, options)
42
+ return (await res.json()) as ContainerSummary[]
43
+ }
44
+
45
+ /**
46
+ * Create a container
47
+ * @param config - Container configuration
48
+ * @param options - Create options
49
+ * @returns Container create response with ID
50
+ */
51
+ async create(config: ContainerConfig, options?: CreateContainerOptions): Promise<ContainerCreateResponse> {
52
+ const path = `/containers/create`
53
+ const res = await this.request(path, "POST", config, undefined, options)
54
+ return (await res.json()) as ContainerCreateResponse
55
+ }
56
+
57
+ /**
58
+ * Inspect a container
59
+ * @param id - Container ID or name
60
+ * @param size - Return container size information
61
+ * @returns Detailed container information
62
+ */
63
+ async inspect(id: string, size: boolean = false): Promise<ContainerInspectResponse> {
64
+ const res = await this.request(`/containers/${id}/json`, "GET", undefined, undefined, {
65
+ size: size,
66
+ })
67
+ return (await res.json()) as ContainerInspectResponse
68
+ }
69
+
70
+ /**
71
+ * Start a container
72
+ * @param id - Container ID or name
73
+ * @param detachKeys - Override the key sequence for detaching
74
+ */
75
+ async start(id: string, detachKeys?: string): Promise<void> {
76
+ await this.request(`/containers/${id}/start`, "POST", undefined, undefined, {
77
+ detachKeys: detachKeys,
78
+ })
79
+ }
80
+
81
+ /**
82
+ * Stop a container
83
+ * @param id - Container ID or name
84
+ * @param t - Number of seconds to wait before killing the container
85
+ */
86
+ async stop(id: string, t?: number): Promise<void> {
87
+ await this.request(`/containers/${id}/stop`, "POST", undefined, undefined, { t: t })
88
+ }
89
+
90
+ /**
91
+ * Restart a container
92
+ * @param id - Container ID or name
93
+ * @param t - Number of seconds to wait before killing the container
94
+ */
95
+ async restart(id: string, t?: number): Promise<void> {
96
+ await this.request(`/containers/${id}/restart`, "POST", undefined, undefined, { t: t })
97
+ }
98
+
99
+ /**
100
+ * Kill a container
101
+ * @param id - Container ID or name
102
+ * @param signal - Signal to send to the container
103
+ */
104
+ async kill(id: string, signal?: string): Promise<void> {
105
+ await this.request(`/containers/${id}/kill`, "POST", undefined, undefined, { signal: signal })
106
+ }
107
+
108
+ /**
109
+ * Remove a container
110
+ * @param id - Container ID or name
111
+ * @param v - Remove anonymous volumes associated with the container
112
+ * @param force - Force removal of running containers
113
+ * @param link - Remove the specified link associated with the container
114
+ */
115
+ async remove(
116
+ id: string,
117
+ v: boolean = false,
118
+ force: boolean = false,
119
+ link: boolean = false
120
+ ): Promise<void> {
121
+ await this.request(`/containers/${id}`, "DELETE", undefined, undefined, {
122
+ v: v,
123
+ force: force,
124
+ link: link,
125
+ })
126
+ }
127
+
128
+ /**
129
+ * Rename a container
130
+ * @param id - Container ID or name
131
+ * @param name - New name for the container
132
+ */
133
+ async rename(id: string, name: string): Promise<void> {
134
+ await this.request(`/containers/${id}/rename`, "POST", undefined, undefined, { name: name })
135
+ }
136
+
137
+ /**
138
+ * Pause a container
139
+ * @param id - Container ID or
140
+ name
141
+ */
142
+ async pause(id: string): Promise<void> {
143
+ await this.request(`/containers/${id}/pause`, "POST")
144
+ }
145
+
146
+ /**
147
+ * Unpause a container
148
+ * @param id - Container ID or name
149
+ */
150
+ async unpause(id: string): Promise<void> {
151
+ await this.request(`/containers/${id}/unpause`, "POST")
152
+ }
153
+
154
+ /**
155
+ * Wait for a container
156
+ * @param id - Container ID or name
157
+ * @param condition - Wait until condition is met
158
+ * @returns Container wait response with exit status
159
+ */
160
+ async wait(id: string, condition?: WaitCondition): Promise<ContainerWaitResponse> {
161
+ const res = await this.request(`/containers/${id}/wait`, "POST", undefined, undefined, {
162
+ condition: condition,
163
+ })
164
+ return (await res.json()) as ContainerWaitResponse
165
+ }
166
+
167
+ /**
168
+ * List processes running inside a container
169
+ * @param id - Container ID or name
170
+ * @param ps_args - Arguments for ps command
171
+ * @returns Top processes response
172
+ */
173
+ async top(id: string, ps_args?: string): Promise<ContainerTopResponse> {
174
+ const res = await this.request(`/containers/${id}/top`, "GET", undefined, undefined, {
175
+ ps_args: encodeURIComponent(ps_args || ""),
176
+ })
177
+ return (await res.json()) as ContainerTopResponse
178
+ }
179
+
180
+ /**
181
+ * Get container logs
182
+ * @param id - Container ID or name
183
+ * @param options - Log options
184
+ * @returns Log stream
185
+ */
186
+ async logs(id: string, options?: LogsOptions): Promise<Response> {
187
+ return await this.request(`/containers/${id}/logs`, "GET", undefined, undefined, options)
188
+ }
189
+
190
+ /**
191
+ * Get container resource usage statistics
192
+ * @param id - Container ID or name
193
+ * @param options - Stats options
194
+ * @returns Container stats response
195
+ */
196
+ async stats(id: string, options?: StatsOptions): Promise<ContainerStatsResponse | Response> {
197
+ const res = await this.request(`/containers/${id}/stats`, "GET", undefined, undefined, options)
198
+
199
+ if (options?.stream) {
200
+ return res
201
+ }
202
+
203
+ return (await res.json()) as ContainerStatsResponse
204
+ }
205
+
206
+ /**
207
+ * Get changes on container filesystem
208
+ * @param id - Container ID or name
209
+ * @returns Array of filesystem changes
210
+ */
211
+ async changes(id: string): Promise<FilesystemChange[]> {
212
+ const res = await this.request(`/containers/${id}/changes`, "GET")
213
+ return (await res.json()) as FilesystemChange[]
214
+ }
215
+
216
+ /**
217
+ * Export a container
218
+ * @param id - Container ID or name
219
+ * @returns Exported container archive
220
+ */
221
+ async export(id: string): Promise<Response> {
222
+ return await this.request(`/containers/${id}/export`, "GET")
223
+ }
224
+
225
+ /**
226
+ * Update container configuration
227
+ * @param id - Container ID or name
228
+ * @param options - Update options
229
+ * @returns Update response with warnings
230
+ */
231
+ async update(id: string, options: UpdateContainerOptions): Promise<ContainerUpdateResponse> {
232
+ const res = await this.request(`/containers/${id}/update`, "POST", options)
233
+ return res.json() as ContainerUpdateResponse
234
+ }
235
+
236
+ /**
237
+ * Resize container TTY
238
+ * @param id - Container ID or name
239
+ * @param h - Height of the TTY session
240
+ * @param w - Width of the TTY session
241
+ */
242
+ async resize(id: string, h: number, w: number): Promise<void> {
243
+ await this.request(`/containers/${id}/resize`, "POST", undefined, undefined, { h: h, w: w })
244
+ }
245
+
246
+ /**
247
+ * Attach to a container
248
+ * @param id - Container ID or name
249
+ * @param options - Attach options
250
+ * @returns Attach connection
251
+ */
252
+ async attach(id: string, options?: AttachOptions): Promise<Response> {
253
+ return await this.request(`/containers/${id}/attach`, "POST", undefined, undefined, options)
254
+ }
255
+
256
+ /**
257
+ * Attach to a container via WebSocket
258
+ * @param id - Container ID or name
259
+ * @param options - Attach options
260
+ * @returns WebSocket-like connection
261
+ * @note Uses the attach endpoint with stream wrapping for compatibility with Unix sockets
262
+ */
263
+ async attachWebSocket(id: string, options?: AttachOptions): Promise<DockerWebSocket> {
264
+ const response = await this.request(
265
+ `/containers/${id}/attach`,
266
+ "POST",
267
+ undefined,
268
+ undefined,
269
+ options
270
+ )
271
+
272
+ this.ws.attach(response)
273
+
274
+ return this.ws
275
+ }
276
+
277
+ /**
278
+ * Get an archive of a filesystem resource in a container
279
+ * @param id - Container ID or name
280
+ * @param path - Resource path in the container
281
+ * @returns Archive stream
282
+ */
283
+
284
+ async getArchive(id: string, path: string): Promise<Response> {
285
+ return await this.request(`/containers/${id}/archive`, "GET", undefined, undefined, {
286
+ path: path,
287
+ })
288
+ }
289
+
290
+ /**
291
+ * Check if a file exists in a container
292
+ * @param id - Container ID or name
293
+ * @param path - Resource path in the container
294
+ * @returns Archive info or null
295
+ */
296
+ async archiveInfo(id: string, path: string): Promise<ArchiveInfo | null> {
297
+ const res = await this.request(`/containers/${id}/archive`, "HEAD", undefined, undefined, {
298
+ path: path,
299
+ })
300
+
301
+ const dockerContentType = res.headers.get("X-Docker-Container-Path-Stat")
302
+ if (!dockerContentType) return null
303
+
304
+ try {
305
+ return JSON.parse(dockerContentType)
306
+ } catch {
307
+ return null
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Extract an archive of files or folders to a directory in the container
313
+ * @param id - Container ID or name
314
+ * @param path - Path to extract to
315
+ * @param archive - Archive to extract
316
+ * @param noOverwriteDirNonDir - If true, will not overwrite a dir with a non-dir
317
+ * @param copyUIDGID - If set to true, copy ownership from archive to target
318
+ */
319
+ async putArchive(
320
+ id: string,
321
+ path: string,
322
+ archive: BodyInit,
323
+ noOverwriteDirNonDir: boolean = false,
324
+ copyUIDGID: boolean = false
325
+ ): Promise<void> {
326
+ await this.request(`/containers/${id}/archive`, "PUT", archive, undefined, {
327
+ path: path,
328
+ noOverwriteDirNonDir: noOverwriteDirNonDir,
329
+ copyUIDGID: copyUIDGID,
330
+ })
331
+ }
332
+
333
+ /**
334
+ * Create an exec instance
335
+ * @param id - Container ID or name
336
+ * @param options - Exec create options
337
+ * @returns Exec create response with exec ID
338
+ */
339
+ async execCreate(id: string, options: ExecCreateOptions): Promise<ExecCreateResponse> {
340
+ const res = await this.request(`/containers/${id}/exec`, "POST", options)
341
+ return (await res.json()) as ExecCreateResponse
342
+ }
343
+
344
+ /**
345
+ * Start an exec instance
346
+ * @param id - Exec ID
347
+ * @param options - Exec start options
348
+ * @returns Exec stream
349
+ */
350
+ async execStart(id: string, options?: ExecStartOptions): Promise<Response> {
351
+ const res = await this.request(`/exec/${id}/start`, "POST", undefined, undefined,options)
352
+ return res
353
+ }
354
+
355
+ /**
356
+ * Inspect an exec instance
357
+ * @param id - Exec ID
358
+ * @returns Exec inspect response
359
+ */
360
+ async execInspect(id: string): Promise<ExecInspectResponse> {
361
+ const res = await this.request(`/exec/${id}/json`, "GET")
362
+ return (await res.json()) as ExecInspectResponse
363
+ }
364
+
365
+ /**
366
+ * Resize an exec TTY
367
+ * @param id - Exec ID
368
+ * @param h - Height of the TTY session
369
+ * @param w - Width of the TTY session
370
+ */
371
+ async execResize(id: string, h: number, w: number): Promise<void> {
372
+ await this.request(`/exec/${id}/resize`, "POST", undefined, undefined, { h: h, w: w })
373
+ }
374
+
375
+ /**
376
+ * Delete stopped containers
377
+ * @param options - Prune options
378
+ * @returns Prune response with deleted containers and reclaimed space
379
+ */
380
+ async prune(options?: PruneContainersOptions): Promise<ContainerPruneResponse> {
381
+ const res = await this.request(`/containers/prune`, "POST", undefined, undefined, options)
382
+ return (await res.json()) as ContainerPruneResponse
383
+ }
384
+ }