UNPKG

the-moby-effect

Version:
795 lines (735 loc) 33.1 kB
import type * as Scope from "effect/Scope"; import * as Array from "effect/Array"; import * as Context from "effect/Context"; import * as Data from "effect/Data"; import * as Effect from "effect/Effect"; import * as Function from "effect/Function"; import * as Layer from "effect/Layer"; import * as Number from "effect/Number"; import * as Option from "effect/Option"; import * as Predicate from "effect/Predicate"; import * as Record from "effect/Record"; import * as Schema from "effect/Schema"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import * as String from "effect/String"; import * as Tuple from "effect/Tuple"; import * as Socket from "effect/unstable/socket/Socket"; import type * as DockerComposeEngine from "../../DockerComposeEngine.js"; import type * as IdSchemas from "../schemas/id.js"; import * as DockerEngine from "../../DockerEngine.js"; import * as MobyDemux from "../../MobyDemux.js"; import * as MobyEndpoints from "../../MobyEndpoints.js"; /** @internal */ const makeTempDirScoped = ( containerId: IdSchemas.ContainerIdentifier ): Effect.Effect<string, DockerComposeError, MobyEndpoints.Containers | Scope.Scope> => Effect.acquireRelease( Effect.gen(function* () { const [stderr, stdout] = yield* Effect.mapError( DockerEngine.execWebsockets({ containerId, command: "mktemp -d", }), (cause) => new DockerComposeError({ cause, method: "makeTempDirScoped", }) ); if (String.isNonEmpty(stderr)) { throw new DockerComposeError({ cause: stderr, method: "makeTempDirScoped", }); } const schema = Schema.String.pipe(Schema.check(Schema.isStartsWith("/tmp/"))); const tempDir = yield* Effect.mapError( Schema.decodeEffect(schema)(stdout), (cause) => new DockerComposeError({ cause, method: "makeTempDirScoped", }) ); yield* Effect.annotateCurrentSpan("tempDir", tempDir); return tempDir; }), (tempDir) => Effect.orDie( Effect.mapError( DockerEngine.execWebsockets({ containerId, command: `rm -rf ${tempDir}`, }), (cause) => new DockerComposeError({ cause, method: "makeTempDirScoped", }) ) ) ); /** @internal */ const uploadProject = Function.dual< <E1, R1>( project: Stream.Stream<Uint8Array, E1, R1> ) => ( containerId: IdSchemas.ContainerIdentifier ) => Effect.Effect<string, E1 | DockerComposeError, R1 | MobyEndpoints.Containers | Scope.Scope>, <E1, R1>( containerId: IdSchemas.ContainerIdentifier, project: Stream.Stream<Uint8Array, E1, R1> ) => Effect.Effect<string, E1 | DockerComposeError, R1 | MobyEndpoints.Containers | Scope.Scope> >( 2, <E1, R1>( containerId: IdSchemas.ContainerIdentifier, project: Stream.Stream<Uint8Array, E1, R1> ): Effect.Effect<string, E1 | DockerComposeError, R1 | MobyEndpoints.Containers | Scope.Scope> => Effect.gen(function* () { const containers = yield* MobyEndpoints.Containers; const projectUploadDir = yield* makeTempDirScoped(containerId); yield* Effect.annotateCurrentSpan("projectUploadDir", projectUploadDir); yield* containers.putArchive(containerId, project, { path: projectUploadDir }); return projectUploadDir; }).pipe( Effect.catchTag( "DockerError", (cause) => new DockerComposeError({ cause, method: "uploadProject", }) ) ) ); /** @internal */ const camelToKebab = Function.compose(String.camelToSnake, String.snakeToKebab); /** @internal */ const stringifyOptions = ( options: Record< string, | string | number | boolean | undefined | Array<string | number | boolean> | Record<string, string | number | boolean> > ): string => Function.pipe( options, Record.toEntries, Array.filter(([, value]) => Predicate.isNotUndefined(value)), Array.flatMap(([key, value]): Array<readonly [string, string | number | boolean]> => { if (Predicate.isString(value) || Predicate.isNumber(value) || Predicate.isBoolean(value)) { return [Tuple.make(key, value)]; } else if (Array.isArray(value)) { return Array.map(value, (v) => [key, v]); } else if (Predicate.isObject(value)) { return Record.toEntries(value); } else { return Function.absurd(value as never); } }), Array.map(([key, value]) => `--${camelToKebab(key)}=${value}`), Array.join(" ") ); /** @internal */ const runCommand = ( containerId: IdSchemas.ContainerIdentifier, projectPath: string, method: string, services: ReadonlyArray<string> | undefined = [], options: | Record< string, | string | number | boolean | undefined | Array<string | number | boolean> | Record<string, string | number | boolean> > | undefined = {} ): Stream.Stream<Uint8Array, DockerComposeError, MobyEndpoints.Containers> => Effect.gen(function* () { const multiplexed = yield* DockerEngine.execWebsocketsNonBlocking({ containerId, cwd: projectPath, command: `COMPOSE_STATUS_STDOUT=1 docker compose ${method} ${stringifyOptions(options)} ${Array.join(services, " ")}`, }); const { stderr, stdin, stdout } = yield* MobyDemux.fan(multiplexed, { requestedCapacity: 16 }); const streamFailableEnsuring = <A, X, E1, E2, R1, R2>( stream: Stream.Stream<A, E1, R1>, effect: Effect.Effect<X, E2, R2> ): Stream.Stream<A, E1 | E2, R1 | R2> => Stream.flatMap(stream, (a: A) => Stream.fromEffect(Effect.map(effect, Function.constant(a)))); return streamFailableEnsuring( MobyDemux.mergeRawToTaggedStream(stdout, stderr), MobyDemux.demuxRawToSingleSink(stdin, Stream.make(new Socket.CloseEvent()), Sink.drain) ); }).pipe( Stream.unwrap, Stream.mapEffect((entry) => { if (Predicate.isTagged(entry, "stdout")) { return Effect.succeed(entry.value); } else { const decoded = new TextDecoder("utf-8").decode(entry.value); return Effect.fail(new DockerComposeError({ method, cause: decoded })); } }), Stream.mapError( (cause) => new DockerComposeError({ cause, method, }) ) ); /** @internal */ export const DockerComposeErrorTypeId: DockerComposeEngine.DockerComposeErrorTypeId = Symbol.for( "@the-moby-effect/engines/DockerCompose/DockerComposeError" ) as DockerComposeEngine.DockerComposeErrorTypeId; /** @internal */ export const TypeId: DockerComposeEngine.TypeId = Symbol.for( "@the-moby-effect/engines/DockerCompose" ) as DockerComposeEngine.TypeId; /** @internal */ export const DockerComposeProjectTypeId: DockerComposeEngine.DockerComposeProjectTypeId = Symbol.for( "@the-moby-effect/engines/DockerComposeProject" ) as DockerComposeEngine.DockerComposeProjectTypeId; /** @internal */ export const isDockerComposeError = (u: unknown): u is DockerComposeError => Predicate.hasProperty(u, DockerComposeErrorTypeId); /** @internal */ export class DockerComposeError extends Data.TaggedError("DockerComposeError")<{ method: string; cause: Schema.SchemaError | Socket.SocketError | DockerEngine.DockerError | unknown; }> { public readonly [DockerComposeErrorTypeId]: DockerComposeEngine.DockerComposeErrorTypeId = DockerComposeErrorTypeId; public override get message() { return `${String.capitalize(this.method)}`; } } /** @internal */ export const DockerCompose: Context.Service<DockerComposeEngine.DockerCompose, DockerComposeEngine.DockerCompose> = Context.Service<DockerComposeEngine.DockerCompose>("@the-moby-effect/engines/DockerCompose"); /** @internal */ export const make: (options?: { dockerEngineSocket?: string | undefined; }) => Effect.Effect< DockerComposeEngine.DockerCompose, DockerEngine.DockerError, MobyEndpoints.Containers | MobyEndpoints.System | MobyEndpoints.Images | Scope.Scope > = Effect.fnUntraced(function* (options) { const containers = yield* MobyEndpoints.Containers; const runCommandHelper = Function.flow(runCommand, Stream.provideService(MobyEndpoints.Containers, containers)); yield* DockerEngine.pingHead(); const build = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.BuildOptions | undefined ): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "build", services, { ...options }), Stream.decodeText(), Stream.splitLines ); const config = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.ConfigOptions | undefined ): Effect.Effect<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "config", services, { ...options }), Stream.decodeText(), Stream.splitLines, Stream.mkString ); const cpTo = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => <E1, R1>( service: string, localSrc: Stream.Stream<Uint8Array, E1, R1>, remoteDestLocation: string, options?: DockerComposeEngine.CopyOptions | undefined ): Effect.Effect<void, E1 | DockerComposeError, R1> => Effect.gen(function* () { const remoteTransferDir = yield* Effect.provideService( makeTempDirScoped(dindContainerId), MobyEndpoints.Containers, containers ); yield* Effect.mapError( containers.putArchive(dindContainerId, localSrc, { path: remoteTransferDir }), (cause) => new DockerComposeError({ method: "cpTo", cause }) ); const command = `cp ${remoteTransferDir} ${service}:${remoteDestLocation}`; return yield* Stream.runDrain( runCommandHelper(dindContainerId, projectPath, command, [], { ...options }) ); }).pipe(Effect.scoped); const cpFrom = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( service: string, remoteSrcLocation: string, options?: DockerComposeEngine.CopyOptions | undefined ): Stream.Stream<Uint8Array, DockerComposeError, never> => Function.pipe( makeTempDirScoped(dindContainerId), Stream.fromEffect, Stream.scoped, Stream.provideService(MobyEndpoints.Containers, containers), Stream.tap((remoteTransferDir) => Stream.runDrain( runCommandHelper( dindContainerId, projectPath, `cp ${service}:${remoteSrcLocation} ${remoteTransferDir}`, [], { ...options, } ) ) ), Stream.flatMap((remoteTransferDir) => Stream.mapError( containers.archive(dindContainerId, { path: remoteTransferDir }), (cause) => new DockerComposeError({ cause, method: "cpFrom", }) ) ) ); const create = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.CreateOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "create", services, { ...options }), Stream.runDrain ); const down = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.DownOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "down", services, { ...options }), Stream.runDrain ); const events = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.EventsOptions | undefined ): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "events", services, { ...options }), Stream.decodeText(), Stream.splitLines ); const exec = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( service: string, command: string, args?: Array<string> | undefined, options?: DockerComposeEngine.ExecOptions | undefined ): Effect.Effect< MobyDemux.MultiplexedChannel<never, DockerEngine.DockerError | Socket.SocketError, never>, DockerComposeError, Scope.Scope > => Effect.provideService( DockerEngine.execWebsocketsNonBlocking({ containerId: dindContainerId, cwd: projectPath, command: `COMPOSE_STATUS_STDOUT=1 docker compose exec ${stringifyOptions({ ...options })} ${service} ${command} ${Array.join(args ?? [], " ")}`, }), MobyEndpoints.Containers, containers ); const images = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.ImagesOptions | undefined ): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "images", services, { ...options }), Stream.decodeText(), Stream.splitLines ); const kill = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.KillOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "kill", services, { ...options }), Stream.runDrain ); const logs = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.LogsOptions | undefined ): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "logs", services, { ...options }), Stream.decodeText(), Stream.splitLines ); const ls = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => (options?: DockerComposeEngine.ListOptions | undefined): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "ls", [], { ...options }), Stream.decodeText(), Stream.splitLines ); const pause = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => (services?: Array<string> | undefined): Effect.Effect<void, DockerComposeError, never> => Function.pipe(runCommandHelper(dindContainerId, projectPath, "pause", services), Stream.runDrain); const port = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( service: string, privatePort: number, options?: DockerComposeEngine.PortOptions | undefined ): Effect.Effect<number, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "port", [service, privatePort.toString()], { ...options, }), Stream.decodeText(), Stream.splitLines, Stream.take(1), Stream.runHead, Effect.map(Option.flatMap(Number.parse)), Effect.map(Option.getOrThrow) ); const ps = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.PsOptions | undefined ): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "ps", services, { ...options }), Stream.decodeText(), Stream.splitLines ); const pull = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.PullOptions | undefined ): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "pull", services, { ...options }), Stream.decodeText(), Stream.splitLines ); const push = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.PushOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "push", services, { ...options }), Stream.runDrain ); const restart = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.RestartOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "restart", services, { ...options }), Stream.runDrain ); const rm = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.RmOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "rm", services, { ...options }), Stream.runDrain ); const run = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( service: string, command: string, args?: Array<string> | undefined, options?: DockerComposeEngine.RunOptions | undefined ): Effect.Effect< MobyDemux.MultiplexedChannel<never, DockerEngine.DockerError | Socket.SocketError, never>, DockerComposeError, Scope.Scope > => Effect.provideService( DockerEngine.execWebsocketsNonBlocking({ containerId: dindContainerId, cwd: projectPath, command: `COMPOSE_STATUS_STDOUT=1 docker compose run ${stringifyOptions({ ...options })} ${service} ${command} ${Array.join(args ?? [], " ")}`, }), MobyEndpoints.Containers, containers ); const start = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => (services?: Array<string> | undefined): Effect.Effect<void, DockerComposeError, never> => Function.pipe(runCommandHelper(dindContainerId, projectPath, "start", services), Stream.runDrain); const stop = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.StopOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "stop", services, { ...options }), Stream.runDrain ); const top = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => (services?: Array<string> | undefined): Stream.Stream<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "top", services), Stream.decodeText(), Stream.splitLines ); const unpause = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => (services?: Array<string> | undefined): Effect.Effect<void, DockerComposeError, never> => Function.pipe(runCommandHelper(dindContainerId, projectPath, "unpause", services), Stream.runDrain); const up = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services?: Array<string> | undefined, options?: DockerComposeEngine.UpOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "up", services, { ...options }), Stream.runDrain ); const version = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => (options?: DockerComposeEngine.VersionOptions | undefined): Effect.Effect<string, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "version", [], { ...options }), Stream.decodeText(), Stream.mkString ); const wait = (dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string) => ( services: Array.NonEmptyReadonlyArray<string>, options?: DockerComposeEngine.WaitOptions | undefined ): Effect.Effect<void, DockerComposeError, never> => Function.pipe( runCommandHelper(dindContainerId, projectPath, "wait", services, { ...options }), Stream.runDrain ); const pullStream = DockerEngine.pull({ image: "docker.io/library/docker:latest" }); yield* Stream.runDrain(pullStream); const dindContainerIdResource = yield* DockerEngine.runScoped({ Image: "docker.io/library/docker:latest", Entrypoint: ["/bin/sh"], Tty: false, OpenStdin: true, AttachStdin: true, AttachStdout: true, AttachStderr: true, HostConfig: { Privileged: true, Binds: [`${options?.dockerEngineSocket ?? "/var/run/docker.sock"}:/var/run/docker.sock`], }, }).pipe(Effect.map(({ Id }) => Id)); const uncurryEffectWithUploadProject = (dindContainerId: IdSchemas.ContainerIdentifier) => <P extends Array<any>, A, E, R>( func: ( dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string ) => (...args: P) => Effect.Effect<A, E, R> ) => <E1, R1>( project: Stream.Stream<Uint8Array, E1, R1>, ...args: P ): Effect.Effect<A, E | E1 | DockerComposeError, Exclude<R, Scope.Scope> | Exclude<R1, Scope.Scope>> => uploadProject(project)(dindContainerId).pipe( Effect.provideService(MobyEndpoints.Containers, containers), Effect.flatMap((cwd) => func(dindContainerId, cwd)(...args)), Effect.scoped ); const uncurryStreamWithUploadProject = (dindContainerId: IdSchemas.ContainerIdentifier) => <P extends Array<any>, A, E, R>( func: ( dindContainerId: IdSchemas.ContainerIdentifier, projectPath: string ) => (...args: P) => Stream.Stream<A, E, R> ) => <E1, R1>( project: Stream.Stream<Uint8Array, E1, R1>, ...args: P ): Stream.Stream<A, E | E1 | DockerComposeError, R | R1> => uploadProject(project)(dindContainerId).pipe( Stream.fromEffect, Stream.scoped, Stream.provideService(MobyEndpoints.Containers, containers), Stream.flatMap((cwd) => func(dindContainerId, cwd)(...args)) ); const uncurryEffect = uncurryEffectWithUploadProject(dindContainerIdResource); const uncurryStream = uncurryStreamWithUploadProject(dindContainerIdResource); // Actual compose implementation return DockerCompose.of({ [TypeId]: TypeId, build: uncurryStream(build), config: uncurryEffect(config), cpTo: <E1, R1, E2, R2>( project: Stream.Stream<Uint8Array, E1, R1>, service: string, localSrc: Stream.Stream<Uint8Array, E2, R2>, remoteDestLocation: string, options?: DockerComposeEngine.CopyOptions | undefined ): Effect.Effect<void, E1 | E2 | DockerComposeError, Exclude<R1, Scope.Scope> | Exclude<R2, Scope.Scope>> => Effect.gen(function* () { const cwd = yield* Effect.provideService( uploadProject(project)(dindContainerIdResource), MobyEndpoints.Containers, containers ); yield* cpTo(dindContainerIdResource, cwd)(service, localSrc, remoteDestLocation, options); }).pipe(Effect.scoped), cpFrom: uncurryStream(cpFrom), create: uncurryEffect(create), down: uncurryEffect(down), events: uncurryStream(events), exec: uncurryEffect(exec), images: uncurryStream(images), kill: uncurryEffect(kill), logs: uncurryStream(logs), ls: uncurryStream(ls), pause: uncurryEffect(pause), port: uncurryEffect(port), ps: uncurryStream(ps), pull: uncurryStream(pull), push: uncurryEffect(push), restart: uncurryEffect(restart), rm: uncurryEffect(rm), run: uncurryEffect(run), start: uncurryEffect(start), stop: uncurryEffect(stop), top: uncurryStream(top), unpause: uncurryEffect(unpause), up: uncurryEffect(up), version: uncurryEffect(version), wait: uncurryEffect(wait), forProject: <E1>( project: Stream.Stream<Uint8Array, E1, never> ): Effect.Effect< DockerComposeEngine.DockerComposeProject, E1 | DockerComposeError | DockerEngine.DockerError, Scope.Scope > => Effect.gen(function* () { const projectDindContainerIdResource = yield* DockerEngine.runScoped({ Image: "docker.io/library/docker:latest", Entrypoint: ["/bin/sh"], Tty: false, OpenStdin: true, AttachStdin: true, AttachStdout: true, AttachStderr: true, HostConfig: { Privileged: true, Binds: [`${options?.dockerEngineSocket ?? "/var/run/docker.sock"}:/var/run/docker.sock`], }, }).pipe( Effect.map(({ Id }) => Id), Effect.provideService(MobyEndpoints.Containers, containers) ); const cwd = yield* Effect.provideService( uploadProject(projectDindContainerIdResource, project), MobyEndpoints.Containers, containers ); return { [DockerComposeProjectTypeId]: DockerComposeProjectTypeId, build: build(projectDindContainerIdResource, cwd), config: config(projectDindContainerIdResource, cwd), cpTo: cpTo(projectDindContainerIdResource, cwd), cpFrom: cpFrom(projectDindContainerIdResource, cwd), create: create(projectDindContainerIdResource, cwd), down: down(projectDindContainerIdResource, cwd), events: events(projectDindContainerIdResource, cwd), exec: exec(projectDindContainerIdResource, cwd), images: images(projectDindContainerIdResource, cwd), kill: kill(projectDindContainerIdResource, cwd), logs: logs(projectDindContainerIdResource, cwd), ls: ls(projectDindContainerIdResource, cwd), pause: pause(projectDindContainerIdResource, cwd), port: port(projectDindContainerIdResource, cwd), ps: ps(projectDindContainerIdResource, cwd), pull: pull(projectDindContainerIdResource, cwd), push: push(projectDindContainerIdResource, cwd), restart: restart(projectDindContainerIdResource, cwd), rm: rm(projectDindContainerIdResource, cwd), run: run(projectDindContainerIdResource, cwd), start: start(projectDindContainerIdResource, cwd), stop: stop(projectDindContainerIdResource, cwd), top: top(projectDindContainerIdResource, cwd), unpause: unpause(projectDindContainerIdResource, cwd), up: up(projectDindContainerIdResource, cwd), version: version(projectDindContainerIdResource, cwd), wait: wait(projectDindContainerIdResource, cwd), }; }), }); }); /** @internal */ export const layer = ( options?: { dockerEngineSocket?: string | undefined } | undefined ): Layer.Layer< DockerComposeEngine.DockerCompose, DockerEngine.DockerError, MobyEndpoints.Containers | MobyEndpoints.System | MobyEndpoints.Images > => Layer.effect(DockerCompose, make(options)); /** @internal */ export const layerProject: <E1>( project: Stream.Stream<Uint8Array, E1, never>, tagIdentifier: string ) => { readonly tag: Context.Service<DockerComposeEngine.DockerComposeProject, DockerComposeEngine.DockerComposeProject>; readonly layer: Layer.Layer< DockerComposeEngine.DockerComposeProject, E1 | DockerComposeError | DockerEngine.DockerError, DockerComposeEngine.DockerCompose >; } = <E1>(project: Stream.Stream<Uint8Array, E1, never>, tagIdentifier: string) => { const tag = Context.Service<DockerComposeEngine.DockerComposeProject>(tagIdentifier); const effect = Effect.flatMap(DockerCompose, ({ forProject }) => forProject(project)); const layer = Layer.effect(tag, effect); return { tag, layer } as const; };