UNPKG

the-moby-effect

Version:
788 lines 28.8 kB
import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Schema from "effect/Schema"; import * as Stream from "effect/Stream"; import * as String from "effect/String"; import * as HttpClient from "effect/unstable/http/HttpClient"; import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse"; import * as Url from "effect/unstable/http/Url"; import * as HttpApi from "effect/unstable/httpapi/HttpApi"; import * as HttpApiClient from "effect/unstable/httpapi/HttpApiClient"; import * as HttpApiEndpoint from "effect/unstable/httpapi/HttpApiEndpoint"; import * as HttpApiError from "effect/unstable/httpapi/HttpApiError"; import * as HttpApiGroup from "effect/unstable/httpapi/HttpApiGroup"; import * as HttpApiSchema from "effect/unstable/httpapi/HttpApiSchema"; import * as Socket from "effect/unstable/socket/Socket"; import { MobyConnectionOptions } from "../../MobyConnection.js"; import { makeAgnosticHttpClientLayer } from "../../MobyPlatforms.js"; import { responseToStreamingSocketOrFailUnsafe } from "../demux/hijack.js"; import { makeRawSocket } from "../demux/raw.js"; import { ArchiveChange, ContainerConfig, ContainerCreateRequest, ContainerHealth, ContainerHostConfig, ContainerInspectResponse, ContainerState, ContainerStatsResponse, ContainerSummary, ContainerTopResponse, ContainerWaitResponse } from "../generated/index.js"; import { replacer as quoteWireNumbers } from "../platforms/agnostic.js"; import { ContainerIdentifier } from "../schemas/id.js"; import { DockerError } from "./circular.js"; import { BadRequest, Conflict, Forbidden, InternalServerError, NotAcceptable, NotFound } from "./errors.js"; import { BooleanFilter, StringFilter } from "./filters.js"; /** @since 1.0.0 */ export const ListFilters = /*#__PURE__*/Schema.fromJsonString(/*#__PURE__*/Schema.Struct({ ancestor: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), before: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), expose: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), exited: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.NumberFromString)), health: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(ContainerHealth.fields["Status"])), identifier: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(ContainerIdentifier)), // isolation: Schema.optional(Schema.Array(ContainerHostConfig.fields["Isolation"])), "is-task": /*#__PURE__*/Schema.optional(/*#__PURE__*/BooleanFilter("is-task")), label: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), name: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), network: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), publish: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), since: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)), status: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(ContainerState.fields["Status"])), volume: /*#__PURE__*/Schema.optional(StringFilter) })); /** @since 1.0.0 */ export const PruneFilters = /*#__PURE__*/Schema.fromJsonString(/*#__PURE__*/Schema.Struct({ until: /*#__PURE__*/Schema.optional(StringFilter), label: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Array(Schema.String)) })); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerList */ const listContainersEndpoint = /*#__PURE__*/HttpApiEndpoint.get("list", "/json", { query: { all: /*#__PURE__*/Schema.optional(Schema.Boolean), limit: /*#__PURE__*/Schema.optional(Schema.Number), size: /*#__PURE__*/Schema.optional(Schema.Boolean), filters: /*#__PURE__*/Schema.optional(ListFilters) }, success: /*#__PURE__*/Schema.Array(ContainerSummary), // 200 OK error: [BadRequest, // 400 Bad parameter InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerCreate */ const createContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("create", "/create", { query: { platform: /*#__PURE__*/Schema.optional(Schema.String), name: /*#__PURE__*/Schema.String.pipe(/*#__PURE__*/Schema.check(/*#__PURE__*/Schema.isPattern(/^[a-zA-Z0-9][a-zA-Z0-9_.-]+/)), Schema.optional) }, payload: ContainerCreateRequest, success: /*#__PURE__*/Schema.Struct({ Id: ContainerIdentifier, Warnings: Schema.NullOr(Schema.Array(Schema.String)) }).pipe(/*#__PURE__*/HttpApiSchema.status(201)), // 201 Created error: [BadRequest, // 400 Bad parameter Forbidden, // 403 Forbidden NotFound, // 404 Not Found NotAcceptable, // 406 Not Acceptable Conflict, // 409 Name conflicts InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerInspect */ const inspectContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("inspect", "/:identifier/json", { params: { identifier: ContainerIdentifier }, query: { size: /*#__PURE__*/Schema.optional(Schema.Boolean) }, success: ContainerInspectResponse, // 200 OK error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerTop */ const topContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("top", "/:identifier/top", { params: { identifier: ContainerIdentifier }, query: { ps_args: /*#__PURE__*/Schema.optional(Schema.String) }, success: ContainerTopResponse, // 200 OK error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerLogs */ const logsContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("logs", "/:identifier/logs", { params: { identifier: ContainerIdentifier }, query: { follow: /*#__PURE__*/Schema.optional(Schema.Boolean), stdout: /*#__PURE__*/Schema.optional(Schema.Boolean), stderr: /*#__PURE__*/Schema.optional(Schema.Boolean), since: /*#__PURE__*/Schema.optional(Schema.Number), until: /*#__PURE__*/Schema.optional(Schema.Number), timestamps: /*#__PURE__*/Schema.optional(Schema.Boolean), tail: /*#__PURE__*/Schema.optional(Schema.String) }, success: /*#__PURE__*/HttpApiSchema.StreamUint8Array(), // 200 OK (streaming response) error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerChanges */ const changesContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("changes", "/:identifier/changes", { params: { identifier: ContainerIdentifier }, success: /*#__PURE__*/Schema.NullOr(/*#__PURE__*/Schema.Array(ArchiveChange)), // 200 OK error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerExport */ const exportContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("export", "/:identifier/export", { params: { identifier: ContainerIdentifier }, success: /*#__PURE__*/HttpApiSchema.StreamUint8Array(), // 200 OK (streaming response) error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerStats */ const statsContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("stats", "/:identifier/stats", { params: { identifier: ContainerIdentifier }, query: { stream: /*#__PURE__*/Schema.optional(Schema.Boolean), "one-shot": /*#__PURE__*/Schema.optional(Schema.Boolean) }, success: /*#__PURE__*/HttpApiSchema.StreamUint8Array(), // 200 OK (streaming response) error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerResize */ const resizeContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("resize", "/:identifier/resize", { params: { identifier: ContainerIdentifier }, query: { h: /*#__PURE__*/Schema.optional(Schema.Number), w: /*#__PURE__*/Schema.optional(Schema.Number) }, success: /*#__PURE__*/HttpApiSchema.Empty(200), // 200 OK error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerStart */ const startContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("start", "/:identifier/start", { params: { identifier: ContainerIdentifier }, query: { detachKeys: /*#__PURE__*/Schema.optional(Schema.String) }, success: [/*#__PURE__*/HttpApiSchema.Empty(204), /*#__PURE__*/ // 204 No Content HttpApiSchema.Empty(304) // 304 Container already started ], error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerStop */ const stopContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("stop", "/:identifier/stop", { params: { identifier: ContainerIdentifier }, query: { signal: /*#__PURE__*/Schema.optional(Schema.String), t: /*#__PURE__*/Schema.optional(Schema.Number) }, success: [/*#__PURE__*/HttpApiSchema.Empty(204), /*#__PURE__*/ // 204 No Content HttpApiSchema.Empty(304) // 304 Container already stopped ], error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerRestart */ const restartContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("restart", "/:identifier/restart", { params: { identifier: ContainerIdentifier }, query: { signal: /*#__PURE__*/Schema.optional(Schema.String), t: /*#__PURE__*/Schema.optional(Schema.Number) }, success: /*#__PURE__*/HttpApiSchema.Empty(204), // 204 No Content error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerKill */ const killContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("kill", "/:identifier/kill", { params: { identifier: ContainerIdentifier }, query: { signal: /*#__PURE__*/Schema.optional(Schema.String) }, success: /*#__PURE__*/HttpApiSchema.Empty(204), // 204 No Content error: [NotFound, // 404 Not Found Conflict, // 409 Container is not running InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerUpdate */ const updateContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("update", "/:identifier/update", { params: { identifier: ContainerIdentifier }, payload: ContainerConfig, success: /*#__PURE__*/Schema.Struct({ Warnings: /*#__PURE__*/Schema.NullOr(/*#__PURE__*/Schema.Array(Schema.String)) }), // 200 OK error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerRename */ const renameContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("rename", "/:identifier/rename", { params: { identifier: ContainerIdentifier }, query: { name: Schema.String }, success: /*#__PURE__*/HttpApiSchema.Empty(204), // 204 No Content error: [NotFound, // 404 Not Found Conflict, // 409 Name already in use InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerPause */ const pauseContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("pause", "/:identifier/pause", { params: { identifier: ContainerIdentifier }, success: /*#__PURE__*/HttpApiSchema.Empty(204), // 204 No Content error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerUnpause */ const unpauseContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("unpause", "/:identifier/unpause", { params: { identifier: ContainerIdentifier }, success: /*#__PURE__*/HttpApiSchema.Empty(204), // 204 No Content error: [NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerAttach */ const attachContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("attach", "/:identifier/attach", { params: { identifier: ContainerIdentifier }, query: { detachKeys: /*#__PURE__*/Schema.optional(Schema.String), logs: /*#__PURE__*/Schema.optional(Schema.Boolean), stream: /*#__PURE__*/Schema.optional(Schema.Boolean), stdin: /*#__PURE__*/Schema.optional(Schema.Boolean), stdout: /*#__PURE__*/Schema.optional(Schema.Boolean), stderr: /*#__PURE__*/Schema.optional(Schema.Boolean) }, headers: { Upgrade: /*#__PURE__*/Schema.Literal("tcp"), Connection: /*#__PURE__*/Schema.Literal("Upgrade") }, success: [/*#__PURE__*/HttpApiSchema.Empty(101), /*#__PURE__*/ // 101 Switching Protocols HttpApiSchema.Empty(200) // 200 OK ], error: [BadRequest, // 400 Bad parameter NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerAttachWebsocket */ const attachWebsocketContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("attachWebsocket", "/:identifier/attach/ws", { params: { identifier: ContainerIdentifier }, query: { detachKeys: /*#__PURE__*/Schema.optional(Schema.String), logs: /*#__PURE__*/Schema.optional(Schema.Boolean), stream: /*#__PURE__*/Schema.optional(Schema.Boolean), stdin: /*#__PURE__*/Schema.optional(Schema.Boolean), stdout: /*#__PURE__*/Schema.optional(Schema.Boolean), stderr: /*#__PURE__*/Schema.optional(Schema.Boolean) }, success: [/*#__PURE__*/HttpApiSchema.Empty(101), /*#__PURE__*/ // 101 Switching Protocols HttpApiSchema.Empty(200) // 200 OK ], error: [BadRequest, // 400 Bad parameter NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerWait */ const waitContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.post("wait", "/:identifier/wait", { params: { identifier: ContainerIdentifier }, query: { condition: /*#__PURE__*/Schema.optional(Schema.String) }, success: ContainerWaitResponse, // 200 OK error: [BadRequest, // 400 Bad parameter NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerDelete */ const deleteContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.delete("delete", "/:identifier", { params: { identifier: ContainerIdentifier }, query: { v: /*#__PURE__*/Schema.optional(Schema.Boolean), force: /*#__PURE__*/Schema.optional(Schema.Boolean), link: /*#__PURE__*/Schema.optional(Schema.Boolean) }, success: /*#__PURE__*/HttpApiSchema.Empty(204), // 204 No Content error: [BadRequest, // 400 Bad parameter NotFound, // 404 Not Found Conflict, // 409 Conflict InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerArchive */ const archiveContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.get("archive", "/:identifier/archive", { params: { identifier: ContainerIdentifier }, query: { path: Schema.String }, success: /*#__PURE__*/HttpApiSchema.StreamUint8Array(), // 200 OK (streaming response) error: [BadRequest, // 400 Bad parameter NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerArchiveInfo */ const archiveInfoContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.head("archiveInfo", "/:identifier/archive", { params: { identifier: ContainerIdentifier }, query: { path: Schema.String }, success: /*#__PURE__*/HttpApiSchema.Empty(200), // 200 OK error: [BadRequest, // 400 Bad parameter NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/PutContainerArchive */ const putArchiveContainerEndpoint = /*#__PURE__*/HttpApiEndpoint.put("putArchive", "/:identifier/archive", { params: { identifier: ContainerIdentifier }, payload: /*#__PURE__*/HttpApiSchema.StreamUint8Array(), query: { path: Schema.String, noOverwriteDirNonDir: /*#__PURE__*/Schema.optional(Schema.String), copyUIDGidentifier: /*#__PURE__*/Schema.optional(Schema.String) }, success: /*#__PURE__*/HttpApiSchema.Empty(200), // 200 OK error: [BadRequest, // 400 Bad parameter Forbidden, // 403 Forbidden NotFound, // 404 Not Found InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container/operation/ContainerPrune */ const pruneContainersEndpoint = /*#__PURE__*/HttpApiEndpoint.post("prune", "/prune", { query: { filters: /*#__PURE__*/Schema.optional(PruneFilters) }, success: /*#__PURE__*/Schema.Struct({ ContainersDeleted: /*#__PURE__*/Schema.NullOr(/*#__PURE__*/Schema.Array(ContainerIdentifier)), SpaceReclaimed: /*#__PURE__*/Schema.BigIntFromString.check(/*#__PURE__*/Schema.isBetweenBigInt({ minimum: 0n, maximum: 2n ** 64n - 1n })) }), // 200 OK error: [InternalServerError] }); /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Container */ const ContainersGroup = /*#__PURE__*/HttpApiGroup.make("containers").add(listContainersEndpoint, createContainerEndpoint, inspectContainerEndpoint, topContainerEndpoint, logsContainerEndpoint, changesContainerEndpoint, exportContainerEndpoint, statsContainerEndpoint, resizeContainerEndpoint, startContainerEndpoint, stopContainerEndpoint, restartContainerEndpoint, killContainerEndpoint, updateContainerEndpoint, renameContainerEndpoint, pauseContainerEndpoint, unpauseContainerEndpoint, attachContainerEndpoint, attachWebsocketContainerEndpoint, waitContainerEndpoint, deleteContainerEndpoint, archiveContainerEndpoint, archiveInfoContainerEndpoint, putArchiveContainerEndpoint, pruneContainersEndpoint).prefix("/containers"); /** * @since 1.0.0 * @category HttpApi * @see https://docs.docker.com/reference/api/engine/latest/#tag/Container */ export const ContainersApi = /*#__PURE__*/HttpApi.make("ContainersApi").add(ContainersGroup); /** * @since 1.0.0 * @category Services * @see https://docs.docker.com/reference/api/engine/latest/#tag/Container */ export class Containers extends /*#__PURE__*/Context.Service()("@the-moby-effect/endpoints/Containers", { make: /*#__PURE__*/Effect.gen(function* () { const httpClient = yield* HttpClient.HttpClient; const ContainersError = DockerError.WrapForModule("containers"); const websocketConstructor = yield* Socket.WebSocketConstructor; const client = yield* HttpApiClient.group(ContainersApi, { httpClient, group: "containers" }); const list_ = options => client.list({ query: { all: options?.all, limit: options?.limit, size: options?.size, filters: options?.filters } }).pipe(Effect.mapError(ContainersError("list"))); const create_ = options => Effect.gen(function* () { const hostConfig = options.HostConfig ? yield* ContainerHostConfig.makeEffect(options.HostConfig) : undefined; const payload = yield* ContainerCreateRequest.makeEffect({ ...options, HostConfig: hostConfig }); return yield* client.create({ query: { name: options.Name, platform: options.Platform }, payload }); }).pipe(Effect.mapError(ContainersError("create"))); const inspect_ = (identifier, options) => client.inspect({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("inspect"))); const top_ = (identifier, options) => client.top({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("top"))); const logs_ = (identifier, options) => client.logs({ params: { identifier }, query: { ...options } }).pipe(Stream.unwrap, Stream.decodeText(), Stream.splitLines, Stream.mapError(ContainersError("logs"))); const changes_ = identifier => client.changes({ params: { identifier } }).pipe(Effect.mapError(ContainersError("changes"))); const export_ = identifier => client.export({ params: { identifier } }).pipe(Stream.unwrap, Stream.mapError(ContainersError("export"))); const stats_ = (identifier, options) => client.stats({ params: { identifier }, query: { ...options } }).pipe(Stream.unwrap, Stream.decodeText(), Stream.splitLines, Stream.map(quoteWireNumbers), Stream.mapEffect(line => Schema.decodeEffect(Schema.fromJsonString(ContainerStatsResponse))(line)), Stream.mapError(ContainersError("stats"))); const resize_ = (identifier, options) => client.resize({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("resize"))); const start_ = (identifier, options) => client.start({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("start"))); const stop_ = (identifier, options) => client.stop({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("stop"))); const restart_ = (identifier, options) => client.restart({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("restart"))); const kill_ = (identifier, options) => client.kill({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("kill"))); const update_ = (identifier, config) => ContainerConfig.makeEffect(config).pipe(Effect.flatMap(payload => client.update({ params: { identifier }, payload })), Effect.mapError(ContainersError("update"))); const rename_ = (identifier, name) => client.rename({ params: { identifier }, query: { name } }).pipe(Effect.mapError(ContainersError("rename"))); const pause_ = identifier => client.pause({ params: { identifier } }).pipe(Effect.mapError(ContainersError("pause"))); const unpause_ = identifier => client.unpause({ params: { identifier } }).pipe(Effect.mapError(ContainersError("unpause"))); const attach_ = (identifier, options) => client.attach({ params: { identifier }, query: { ...options }, headers: { Connection: "Upgrade", Upgrade: "tcp" }, // FIXME: Broken on undici responseMode: "response-only" }).pipe(Effect.flatMap(responseToStreamingSocketOrFailUnsafe), Effect.mapError(ContainersError("attach"))); const attachWebsocket_ = (identifier, options) => Effect.gen(function* () { const baseUrl = "ws://0.0.0.0"; const stripBaseUrl = String.replace(baseUrl, String.empty); const emptyResponse = new Response(undefined, { status: 200 }); const noopHttpClient = HttpClient.make(request => Effect.succeed(HttpClientResponse.fromWeb(request, emptyResponse))); const client = yield* HttpApiClient.endpoint(ContainersApi, { endpoint: "attachWebsocket", httpClient: noopHttpClient, group: "containers", baseUrl }); const response = yield* client({ responseMode: "response-only", params: { identifier }, query: { ...options } }); const { hash, url, urlParams } = response.request; const wsUrl = yield* Url.make(url, urlParams, hash.valueOrUndefined).pipe(Effect.fromResult, Effect.mapError(_cause => new HttpApiError.BadRequest()), Effect.map(url => url.toString()), Effect.map(stripBaseUrl)); const websocket = websocketConstructor(wsUrl); yield* Effect.callback(resume => { if (websocket.readyState === 1) { resume(Effect.void); return; } const onOpen = () => { cleanup(); resume(Effect.void); }; const onFailure = cause => { cleanup(); resume(Effect.fail(new Socket.SocketError({ reason: new Socket.SocketOpenError({ kind: "Unknown", cause }) }))); }; const cleanup = () => { websocket.removeEventListener("open", onOpen); websocket.removeEventListener("error", onFailure); websocket.removeEventListener("close", onFailure); }; websocket.addEventListener("open", onOpen, { once: true }); websocket.addEventListener("error", onFailure, { once: true }); websocket.addEventListener("close", onFailure, { once: true }); return Effect.sync(cleanup); }); const socket = yield* Socket.fromWebSocket(Effect.acquireRelease(Effect.succeed(websocket), ws => Effect.sync(() => ws.close())), { closeCodeIsError: code => code !== 1000 }); return makeRawSocket(socket); }).pipe(Effect.mapError(ContainersError("attachWebsocket"))); const wait_ = (identifier, options) => client.wait({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("wait"))); const delete_ = (identifier, options) => client.delete({ params: { identifier }, query: { ...options } }).pipe(Effect.mapError(ContainersError("delete"))); const archive_ = (identifier, options) => client.archive({ params: { identifier }, query: { ...options } }).pipe(Stream.unwrap, Stream.mapError(ContainersError("archive"))); const archiveInfo_ = (identifier, options) => client.archiveInfo({ params: { identifier }, query: { ...options }, responseMode: "response-only" }).pipe(Effect.flatMap(HttpClientResponse.schemaHeaders(Schema.Struct({ "x-docker-container-path-stat": Schema.StringFromBase64.pipe(Schema.decodeTo(Schema.fromJsonString(Schema.Unknown)), Schema.optional) }))), Effect.map(({ "x-docker-container-path-stat": pathStat }) => pathStat), Effect.mapError(ContainersError("archiveInfo"))); const putArchive_ = (identifier, stream, options) => Effect.contextWith(context => client.putArchive({ params: { identifier }, query: { ...options }, payload: Stream.provideContext(stream, context) })).pipe(Effect.mapError(ContainersError("putArchive"))); const prune_ = filters => client.prune({ query: { filters } }).pipe(Effect.mapError(ContainersError("prune"))); return { list: list_, create: create_, inspect: inspect_, top: top_, logs: logs_, changes: changes_, export: export_, stats: stats_, resize: resize_, start: start_, stop: stop_, restart: restart_, kill: kill_, update: update_, rename: rename_, pause: pause_, unpause: unpause_, attach: attach_, attachWebsocket: attachWebsocket_, wait: wait_, delete: delete_, archive: archive_, archiveInfo: archiveInfo_, putArchive: putArchive_, prune: prune_ }; }) }) {} /** * @since 1.0.0 * @category Layers * @see https://docs.docker.com/reference/api/engine/latest/#tag/Container */ export const ContainersLayer = /*#__PURE__*/Layer.effect(Containers, Containers.make); /** * @since 1.0.0 * @category Layers * @see https://docs.docker.com/reference/api/engine/latest/#tag/Container */ export const ContainersLayerLocalSocket = /*#__PURE__*/ContainersLayer.pipe(/*#__PURE__*/Layer.provide(/*#__PURE__*/makeAgnosticHttpClientLayer(/*#__PURE__*/MobyConnectionOptions.socket({ socketPath: "/var/run/docker.sock" })))); //# sourceMappingURL=containers.js.map