import * as logs from "@distilled.cloud/aws/cloudwatch-logs"; import * as ecr from "@distilled.cloud/aws/ecr"; import * as ecs from "@distilled.cloud/aws/ecs"; import * as iam from "@distilled.cloud/aws/iam"; import { Region } from "@distilled.cloud/aws/Region"; import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import type { Scope } from "effect/Scope"; import { Platform, type Main, type PlatformProps, type PlatformServices } from "../../Platform.ts"; import * as Provider from "../../Provider.ts"; import { Resource, type ResourceBinding } from "../../Resource.ts"; import type { RuntimeContext } from "../../RuntimeContext.ts"; import { type HostRuntimeContext, type ServerHost } from "../../Server/Process.ts"; import { Stack } from "../../Stack.ts"; import type { Credentials } from "../Credentials.ts"; import { type BundledImageSource, type DockerfileImageSource, type RegistryImageSource } from "../ECR/ImageSource.ts"; import { AWSEnvironment } from "../Environment.ts"; import type { PolicyStatement } from "../IAM/Policy.ts"; import type { Providers } from "../Providers.ts"; export declare const isTask: (value: any) => value is Task; declare const TaskEnvironment_base: Context.ServiceClass>; export declare class TaskEnvironment extends TaskEnvironment_base { } /** * The binding contract shared by the ECS container platforms (`Task` and the * image-owning `Service`): env vars and IAM policy statements land on the * task role, plus task-level volumes/mount points requested through the * binding channel (e.g. `EFS.Mount`). */ export interface TaskBindingContract { /** Environment variables injected into the task's containers. */ env?: Record; /** IAM policy statements attached to the task role. */ policyStatements?: PolicyStatement[]; /** * Task-level volumes requested through the binding channel (e.g. * `EFS.Mount`). Merged with the resource's own `volumes` prop. */ volumes?: ecs.Volume[]; /** * Container mount points for binding-requested volumes, applied to the * primary container. */ mountPoints?: ecs.MountPoint[]; } /** * Task-definition configuration shared by `AWS.ECS.Task` and the * image-owning form of `AWS.ECS.Service` (which synthesizes its own task * definition from the same surface). */ export interface TaskDefinitionConfig { /** * Task-level cpu configuration for Fargate. * @default 256 */ cpu?: number; /** * Task-level memory configuration for Fargate. * @default 512 */ memory?: number; /** * HTTP port exposed by the container. */ port?: number; /** * Additional environment variables for the container. */ env?: Record; /** * Environment files to load into the primary container, e.g. `.env` * objects stored in S3: * `[{ value: "arn:aws:s3:::my-bucket/app.env", type: "s3" }]`. * * Variables from `env` (and the container's own `environment`) take * precedence over values loaded from environment files. The execution * role is automatically granted `s3:GetObject` on the referenced objects * and `s3:GetBucketLocation` on their buckets. */ environmentFiles?: ecs.EnvironmentFile[]; /** * Command override for the primary container (Docker `CMD`). */ command?: string[]; /** * Container definition overrides applied after Alchemy's defaults for the * primary container. */ container?: Partial; /** * Additional sidecar containers appended to the task definition after the * primary container. Each entry is a full, typed * {@link ecs.ContainerDefinition} (image URIs supplied by the user, e.g. * from an `ECR.Image` or an external registry). * * Use this to declare multi-container tasks: log routers (firelens), * proxies (Envoy/App Mesh), metric agents (otel/cloudwatch), or any * companion process that shares the task's network namespace. */ sidecars?: ecs.ContainerDefinition[]; /** * Task definition network mode. * @default "awsvpc" */ networkMode?: ecs.NetworkMode; /** * Launch-type compatibilities the task definition must support. * @default ["FARGATE"] */ requiresCompatibilities?: ecs.Compatibility[]; /** * Task-level data volumes (host / docker / EFS / FSx Windows / S3 / * configured-at-launch). Containers reference these via `mountPoints`. */ volumes?: ecs.Volume[]; /** * Task definition placement constraints (`memberOf` expressions). Only * applies to EC2/EXTERNAL launch types. */ placementConstraints?: ecs.TaskDefinitionPlacementConstraint[]; /** * CPU architecture and operating-system family the task runs on, e.g. * `{ cpuArchitecture: "ARM64", operatingSystemFamily: "LINUX" }`. */ runtimePlatform?: ecs.RuntimePlatform; /** * Amount of ephemeral storage (in GiB) to allocate for the task on Fargate. */ ephemeralStorage?: ecs.EphemeralStorage; /** * IPC resource namespace to use for the containers in the task. */ ipcMode?: ecs.IpcMode; /** * Process namespace to use for the containers in the task. */ pidMode?: ecs.PidMode; /** * App Mesh proxy configuration. */ proxyConfiguration?: ecs.ProxyConfiguration; /** * Elastic Inference accelerators to attach to the task. */ inferenceAccelerators?: ecs.InferenceAccelerator[]; /** * Whether to enable AWS Fault Injection (FIS) actions on the task. * @default false */ enableFaultInjection?: boolean; /** * Additional task definition overrides applied last (escape hatch for * fields not yet surfaced as first-class props). */ taskDefinition?: Partial>; /** * Additional managed policy ARNs for the task role. */ taskRoleManagedPolicyArns?: string[]; /** * Additional managed policy ARNs for the execution role. */ executionRoleManagedPolicyArns?: string[]; } export interface TaskPropsBase extends PlatformProps, TaskDefinitionConfig { /** * ECS task family. If omitted, a unique family is generated. */ taskName?: string; /** * User-defined tags to apply to task-owned resources. */ tags?: Record; } /** * Bundle an inline Effect program (`main`) into a generated image whose * environment comes from `image`, `dockerfile`, or the default bun base. */ export interface BundledTaskProps extends TaskPropsBase, BundledImageSource { } /** * Build the user's own Dockerfile (`context` + optional `dockerfile` path) * into the task image. */ export interface DockerfileTaskProps extends TaskPropsBase, DockerfileImageSource { } /** * Run a pre-built registry image (`image`), mirrored into ECR. */ export interface ImageTaskProps extends TaskPropsBase, RegistryImageSource { } /** * Task props — the image comes from exactly one of three sources, flat on * the props: `main` (bundled Effect program), `context` (user Dockerfile), * or `image` (registry reference). */ export type TaskProps = BundledTaskProps | DockerfileTaskProps | ImageTaskProps; export interface Task extends Resource<"AWS.ECS.Task", TaskProps, { /** The ARN of the registered task definition revision. */ taskDefinitionArn: string; /** The task definition family name. */ taskFamily: string; /** The name of the main container in the task definition. */ containerName: string; /** The container port the task listens on. */ port: number; /** The full URI of the container image the task runs. */ imageUri: string; /** The name of the ECR repository holding the built image. */ repositoryName: string; /** The URI of the ECR repository holding the built image. */ repositoryUri: string; /** The ARN of the task role assumed by the running containers. */ taskRoleArn: string; /** The name of the task role. */ taskRoleName: string; /** The ARN of the execution role used to pull images and write logs. */ executionRoleArn: string; /** The name of the execution role. */ executionRoleName: string; /** The CloudWatch log group the task writes to. */ logGroupName: string; /** The ARN of the CloudWatch log group. */ logGroupArn: string; /** The content hash of the task's container image. */ code: { /** The content hash of the task's container image. */ hash: string; }; }, TaskBindingContract, Providers> { } export type TaskServices = Credentials | Region | ServerHost | AWSEnvironment; /** * The impl shape for an effectful `Task`: a `run` entry that executes to * completion when the container starts, and/or a `fetch` HTTP handler for * tasks deployed as servers (e.g. referenced by an `ECS.Service`). */ export type TaskShape = void | (Exclude, void> & { /** * Runs to completion when the container starts, after which the * container exits. */ run?: Effect.Effect; }); export interface TaskRuntimeContext extends HostRuntimeContext { readonly Type: "AWS.ECS.Task"; } export { createContainerRuntimeContext } from "../../Server/Process.ts"; /** * A Fargate task definition with a container image from one of three * sources, declared flat on the props: * * - `main` — bundle an inline Effect program into a generated image * (compose with `image` or an inline `dockerfile` to pick the * environment; defaults to `oven/bun:1`). * - `context` — build your own Dockerfile (`dockerfile` is a path relative * to the cwd, defaulting to `${context}/Dockerfile`). * - `image` — run a pre-built registry image, mirrored into ECR. * * `Task` provisions task + execution IAM roles, a CloudWatch log group, and * an ECR repository holding the built (or mirrored) image, then registers a * Fargate task definition. Each reconcile registers a new immutable * revision. A launched task runs until its process exits — it is the target * of `AWS.ECS.RunTask` / `StopTask` bindings and `AWS.ECS.Schedule`; * effectful impls return `{ run }`, executed to completion when the * container starts. * * Beyond the primary container you can declare task-level configuration * (volumes, runtime platform, ephemeral storage, IPC/PID mode, placement * constraints) and append additional `sidecars` for multi-container tasks. * ### Creating a Task * **Example:** Remote Image * ```typescript * const migrate = yield* Task("DbMigrate", { * image: "public.ecr.aws/docker/library/busybox:stable", * command: ["sh", "-c", "echo done"], * cpu: 256, * memory: 512, * }); * ``` * * **Example:** Build Your Own Dockerfile * ```typescript * const render = yield* Task("RenderJob", { * context: "./render", // dockerfile defaults to ./render/Dockerfile * dockerfile: "./render/Dockerfile.gpu", // always a PATH * cpu: 1024, * memory: 4096, * }); * ``` * * **Example:** Inline Effect Program * ```typescript * const drainer = yield* Task( * "QueueDrainer", * { main: import.meta.url, image: "oven/bun:1", cpu: 256, memory: 512 }, * Effect.gen(function* () { * const receive = yield* AWS.SQS.ReceiveMessage(queue); * return { * run: Effect.gen(function* () { * // runs to completion, then the container exits * const batch = yield* receive({ MaxNumberOfMessages: 10 }); * }), * }; * }), * ); * ``` * * ### Multi-Container Tasks * **Example:** Task with a Sidecar * ```typescript * const task = yield* Task("ApiTask", { * main: import.meta.url, * port: 3000, * sidecars: [ * { * name: "otel-collector", * image: "public.ecr.aws/aws-observability/aws-otel-collector:latest", * essential: false, * portMappings: [{ containerPort: 4317, protocol: "tcp" }], * }, * ], * }); * ``` * * ### Bundling & Tree-shaking * `main` is bundled with rolldown at deploy time. Top-level calls in the * `effect`, `@effect/*`, `alchemy`, `@alchemy.run/*`, and * `@distilled.cloud/*` packages receive `#__PURE__` annotations by * default, so anything the task doesn't use from those packages is * tree-shaken out of the bundle. Any other package — including your own * app — is left untouched unless you list it explicitly. * * **Example:** Treat additional packages as pure * Pass package names (or picomatch globs) via `build.pure.packages` to * annotate them in addition to the defaults. * ```typescript * { * main: import.meta.url, * build: { * pure: { packages: ["my-lib", "@my-scope/*"] }, * }, * } * ``` * * Listing a package annotates calls whose result is bound (variable * initializers, exports) — safe anywhere. If a listed package also * declares `"sideEffects": false` (or `[]`) in its `package.json`, that * combination opts it into full annotation: top-level calls whose result * is discarded (e.g. `router.on("/path", handler)` registrations) are * also marked pure and deleted under minification when unused. Only list * a `sideEffects: false` package if its modules really are free of * meaningful top-level side effects. The `effect`, `alchemy`, and * `@distilled.cloud` defaults declare exactly that, on purpose — their * modules are designed to be fully tree-shakeable. * * **Example:** Disable pure annotations * ```typescript * { * main: import.meta.url, * build: { pure: false }, * } * ``` * * ### Task-Level Configuration * **Example:** ARM64 with EFS Volume and Ephemeral Storage * ```typescript * const task = yield* Task("WorkerTask", { * main: import.meta.url, * runtimePlatform: { cpuArchitecture: "ARM64", operatingSystemFamily: "LINUX" }, * ephemeralStorage: { sizeInGiB: 40 }, * volumes: [ * { * name: "data", * efsVolumeConfiguration: { fileSystemId: fileSystem.fileSystemId }, * }, * ], * container: { * mountPoints: [{ sourceVolume: "data", containerPath: "/data" }], * }, * }); * ``` * * **Example:** Environment Files from S3 * ```typescript * const task = yield* Task("ApiTask", { * main: import.meta.url, * environmentFiles: [ * { value: "arn:aws:s3:::my-config-bucket/app.env", type: "s3" }, * ], * }); * ``` * * @resource */ export declare const Task: Platform; /** Docker build platform matching the task definition's declared runtime. */ export declare const taskImagePlatform: (runtimePlatform?: ecs.RuntimePlatform) => "linux/amd64" | "linux/arm64"; /** * Create the IAM role assumed by ECS tasks if it doesn't already exist. * Idempotent: an `EntityAlreadyExistsException` adopts the existing role * only when it carries our internal tags. */ export declare const createTaskRoleIfNotExists: (args_0: { id: string; roleName: string; }) => Effect.Effect; /** * Ensure the ECS execution role exists with the standard execution policy * (plus any additional managed policies) attached. */ export declare const ensureTaskExecutionRole: (args_0: { id: string; roleName: string; managedPolicyArns?: string[]; }) => Effect.Effect; /** * Sync the execution role's read access to the S3 `environmentFiles`: put * an inline policy granting `s3:GetObject` on the referenced objects (and * `s3:GetBucketLocation` on their buckets), or delete the policy when no * environment files are configured. */ export declare const syncEnvironmentFilesPolicy: (args_0: { roleName: string; environmentFiles: ecs.EnvironmentFile[] | undefined; }) => Effect.Effect; /** Ensure the CloudWatch log group the task writes to exists. */ export declare const ensureTaskLogGroup: (args_0: { id: string; logGroupName: string; }) => Effect.Effect; /** * Apply the binding channel to the task role: collect env vars, put (or * clear) the inline policy from bound policy statements, and dedupe * binding-requested volumes/mount points. */ export declare const attachTaskBindings: (args_0: { roleName: string; policyName: string; bindings: ResourceBinding[]; }) => Effect.Effect<{ env: Record | undefined; volumes: ecs.Volume[]; mountPoints: ecs.MountPoint[]; }, import("@distilled.cloud/aws/Errors").AccessDeniedException | import("@distilled.cloud/aws/Errors").EndpointError | import("@distilled.cloud/aws/Errors").ExpiredTokenException | import("effect/unstable/http/HttpClientError").HttpClientError | import("@distilled.cloud/aws/Errors").IncompleteSignature | import("@distilled.cloud/aws/Errors").InternalFailure | iam.LimitExceededException | import("@distilled.cloud/aws/Errors").MalformedHttpRequestException | iam.MalformedPolicyDocumentException | import("@distilled.cloud/aws/Errors").NoMatchingRuleError | iam.NoSuchEntityException | import("@distilled.cloud/aws/Errors").NotAuthorized | import("@distilled.cloud/aws/Errors").OperationAborted | import("@distilled.cloud/aws/Errors").OptInRequired | import("@distilled.cloud/aws/Errors").RequestAbortedException | import("@distilled.cloud/aws/Errors").RequestEntityTooLargeException | import("@distilled.cloud/aws/Errors").RequestExpired | import("@distilled.cloud/aws/Errors").RequestTimeoutException | iam.ServiceFailureException | import("@distilled.cloud/aws/Errors").ServiceUnavailable | import("@distilled.cloud/aws/Errors").ThrottlingException | import("@distilled.cloud/aws/Errors").UnknownAwsError | import("@distilled.cloud/aws/Errors").UnknownOperationException | iam.UnmodifiableEntityException | import("@distilled.cloud/aws/Errors").UnrecognizedClientException | import("@distilled.cloud/aws/Errors").ValidationError | import("@distilled.cloud/aws/Errors").ValidationException, Credentials | import("effect/unstable/http/HttpClient").HttpClient>; /** * Register a new task definition revision from the shared * {@link TaskDefinitionConfig} surface. */ export declare const registerTaskDefinitionRevision: (args_0: { props: TaskDefinitionConfig; family: string; imageUri: string; taskRoleArn: string; executionRoleArn: string; logGroupName: string; tags: Record; /** Task-level volumes requested through the binding channel. */ bindingVolumes?: ecs.Volume[]; /** Primary-container mount points for binding-requested volumes. */ bindingMountPoints?: ecs.MountPoint[]; }) => Effect.Effect; /** * Sync tags on a task definition revision: diff observed revision tags * against desired and apply the delta. */ export declare const syncTaskDefinitionTags: (args_0: { revisionArn: string; tags: Record; }) => Effect.Effect; /** * Reap the task-definition revision superseded by a reconcile: registering * always produces a NEW revision, so without this every reconcile strands * the previous revision ACTIVE forever. Deregister + hard-delete the prior * revision once the new one is registered. * * Guarded to the same family — `previousArn` can reference a foreign task * definition this resource does not own (e.g. an `ECS.Service` switched from * a BYO `task:` reference to the image-owning form), which must be left * untouched. Idempotent: both calls tolerate "already gone", and a revision * still referenced by running tasks parks in `DELETE_IN_PROGRESS` until AWS * finishes the delete. */ export declare const reapSupersededTaskDefinitionRevision: (args_0: { /** The revision recorded before this reconcile (`output.taskDefinitionArn`). */ previousArn: string | undefined; /** The freshly-registered revision ARN. */ nextArn: string; }) => Effect.Effect; /** * Tear down the infrastructure a task definition owns: every remaining * revision of the family (deregister + hard delete), the ECR repository, the * log group, and the task/execution roles. Idempotent — every step tolerates * "already gone". */ export declare const deleteTaskDefinitionInfrastructure: (output: { taskDefinitionArn: string; /** * The family owned by this resource. When present, EVERY remaining ACTIVE * revision is swept — state rows written before reconcile-time revision * reaping can have superseded revisions beyond the recorded one. */ taskFamily?: string; repositoryName: string; logGroupName: string; taskRoleName: string; executionRoleName: string; }) => Effect.Effect; export declare const TaskProvider: () => import("effect/Layer").Layer, never, AWSEnvironment | import("../../AlchemyContext.ts").AlchemyContext | Credentials | import("../../Docker/Docker.ts").Docker | import("effect/FileSystem").FileSystem | import("effect/unstable/http/HttpClient").HttpClient | import("effect/Path").Path | Stack | import("../../Stage.ts").Stage>; //# sourceMappingURL=Task.d.ts.map