import * as ecr from "@distilled.cloud/aws/ecr"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import type * as rolldown from "rolldown"; import { AlchemyContext } from "../../AlchemyContext.ts"; import * as Bundle from "../../Bundle/Bundle.ts"; import { Docker } from "../../Docker/Docker.ts"; import { type InlineDockerfile } from "../../Docker/Dockerfile.ts"; /** * INTERNAL — shared container image-source machinery for AWS container * platforms (`AWS.ECS.Task`, `AWS.ECS.Service`, `AWS.EKS.*`). * * NOT exported from the AWS barrel or `ECR/index.ts`. Consumers import the * module path directly. * * A platform's props separate the ENVIRONMENT (what the container is) from * the PROGRAM (`main` — "and run my bundled Effect program in it"): * * - environment (at most one): `image` (registry ref) | `context` + * `dockerfile`-as-path (docker build) | inline `dockerfile` content * (`Dockerfile.inline`) | the default bun base when `main` stands alone. * - `main` present → the bundle is injected into the environment (COPY + * ENTRYPOINT) and pushed as a derived image. `main` absent → the * environment runs verbatim: `image` is mirrored into ECR * (docker pull → tag → push, content-addressed on the ref), a Dockerfile * builds as-is. * * `dockerfile` is a string PATH (relative to the cwd, defaulting to * `${context}/Dockerfile`) or an `InlineDockerfile` * (`{ content: Input }`, usually via `Dockerfile.inline`). Inline * content may interpolate Outputs (e.g. `FROM ${base.imageUri}`), creating * a real dependency edge; never interpolate secrets — content is baked * into image layers. * * Every source lands in an auto-created (caller-named) private ECR * repository so the compute platform pulls from a registry that is reliable * from private VPCs and IAM-authenticated. */ /** * Bundle an Effect program into a generated image. Alchemy bundles `main` * with rolldown and bakes it into a Dockerfile generated from the * environment (`image`, `dockerfile`, or the default bun base). */ export interface BundledImageSource { /** * Module entrypoint for the bundled program. This should typically be * `import.meta.url` from an inline Effect program. */ main: string; /** * Environment image: used as the generated Dockerfile's `FROM`. Any * registry ref works (private non-ECR registries require docker * credentials on the build machine); the image must be able to run the * bun runtime. Exclusive with {@link dockerfile} / {@link context}. * @default "oven/bun:1" */ image?: string; /** * Environment Dockerfile: a string is a PATH (built in {@link context}, * then the bundle is layered on top in a second stage); an * {@link InlineDockerfile} is inline content used as the environment * preamble (built with no context — its own `COPY`s are unsupported). * The resulting environment must be able to run the bun runtime. * Exclusive with {@link image}. */ dockerfile?: string | InlineDockerfile; /** * Build context for a path {@link dockerfile} environment. Exclusive * with {@link image} and inline dockerfiles. */ context?: string; /** * Named export to load from `main`. * @default "default" */ handler?: string; /** * Bundler configuration for the entrypoint: rolldown `input`/`output` * overrides plus pure-annotation options (`pure`). `effect`, `@effect/*`, * `alchemy`, `@alchemy.run/*`, and `@distilled.cloud/*` are annotated as * pure by default so unused code from those packages is tree-shaken; list * additional packages via `pure.packages`, or disable with `pure: false`. */ build?: Bundle.BundleConfig; } /** * Build the image from the user's own Dockerfile and build context — no * Effect program is bundled. */ export interface DockerfileImageSource { /** * Docker build context directory. Optional when {@link dockerfile} is * inline content (which builds with an empty context). */ context?: string; /** * Path to the Dockerfile relative to the cwd (NOT the context), or * {@link InlineDockerfile} content. The Dockerfile must define its own * `CMD`/`ENTRYPOINT` (no program is injected). * @default `${context}/Dockerfile` */ dockerfile?: string | InlineDockerfile; } /** * Mirror a pre-built registry image into ECR (docker pull → tag → push). */ export interface RegistryImageSource { /** * A pre-built image reference, e.g. * `public.ecr.aws/docker/library/busybox:stable`. */ image: string; } /** * The image-source union. Discriminated by presence: exactly one of * `main`, `context`, or `image`. */ export type ImageSourceProps = BundledImageSource | DockerfileImageSource | RegistryImageSource; /** Loose bag shape used to sniff which source variant a props object is. */ export interface ImageSourceLike { main?: string; handler?: string; build?: BundledImageSource["build"]; context?: string; dockerfile?: string | InlineDockerfile; image?: string; } export type ImageSourceKind = "main" | "context" | "image"; /** * Which image source a props bag declares. `main` always wins (the other * fields then describe its ENVIRONMENT); without `main`, `image` is the * mirrored-verbatim source and any `context`/`dockerfile` (path or inline) * is an external docker build. */ export declare const imageSourceKind: (source: ImageSourceLike) => ImageSourceKind | undefined; /** * Validate environment-source exclusivity. Dies (plan-time defect) on * `image`+`dockerfile`, `image`+`context`, or inline-`dockerfile`+`context`. */ export declare const validateImageSource: (id: string, source: ImageSourceLike) => Effect.Effect; /** The resolved (built/mirrored + pushed) image. */ export interface ResolvedImage { /** Full image reference, `:`. */ imageUri: string; /** Name of the ECR repository the image was pushed to. */ repositoryName: string; /** URI of the ECR repository the image was pushed to. */ repositoryUri: string; /** Content hash identifying the image (also the image tag). */ codeHash: string; } export interface ResolveImageOptions { /** Logical resource id — keys the stable build-context directory. */ id: string; /** * The props bag carrying the image source fields (`main` / `context` / * `image` plus their modifiers). */ source: ImageSourceLike; /** Name of the ECR repository to (auto-create and) push into. */ repositoryName: string; /** * Known repository URI (from prior Attributes). When provided, repository * creation is skipped. */ repositoryUri?: string; /** Tags applied to the auto-created repository. */ tags?: Record; /** * Target image platform. * @default "linux/amd64" */ platform?: string; /** * Port the generated Dockerfile should `ENV PORT=` + `EXPOSE` * (`main` source only). */ port?: number; /** * True when the resource was declared without an inline Effect impl — * `main` is then bundled as-is without the virtual-entry bootstrap. */ isExternal?: boolean; /** * The virtual-entry bootstrap wrapped around `main` for Effect-native * programs: receives the resolved entry import path and returns the * generated entry module source. Platform-specific (server vs one-shot * differ per platform), so the caller supplies it. */ bootstrap: (importPath: string) => string; /** Plan-status session used to emit build/push progress notes. */ session: { note: (message: string) => Effect.Effect; }; } /** * The standard bun bootstrap used by `AWS.ECS.Task` / `AWS.ECS.Service` * generated entries: resolves the bundled program's registered runners * (`host.run` loops and served `fetch`/`run` handlers) and runs them with a * Bun HTTP server bound to `PORT`. */ export declare const makeBunBootstrap: (handler: string) => (importPath: string) => string; /** * Content hash for the sources whose identity is computable WITHOUT running * a bundler: * * - `context` — hash of the build-context directory + Dockerfile content + * platform. * - `image` — hash of the image reference + platform (re-mirror only when * the ref changes). * - `main` — `undefined`: the hash comes from the bundle output, so it is * only known inside `resolve`. * * Providers use this in `diff` to surface content drift (files changed under * an unchanged `context` path) as an update. */ export declare const computeStaticSourceHash: (source: ImageSourceLike, platform?: string | undefined) => Effect.Effect; /** * Init-time constructor for the image-source resolver. Resolves the services * that are only available at provider-layer construction (Docker, the * `.alchemy` directory, the rolldown virtual-entry plugin) and returns * `resolve`, the per-reconcile entrypoint. */ export declare const makeImageSource: Effect.Effect<{ resolve: (options: ResolveImageOptions) => Effect.Effect<{ imageUri: string; repositoryName: string; repositoryUri: string; codeHash: string; }, import("@distilled.cloud/aws/Errors").AccessDeniedException | Bundle.BundleError | 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 | ecr.InvalidParameterException | ecr.InvalidTagParameterException | ecr.KmsException | ecr.LimitExceededException | import("@distilled.cloud/aws/Errors").MalformedHttpRequestException | import("@distilled.cloud/aws/Errors").NoMatchingRuleError | import("@distilled.cloud/aws/Errors").NotAuthorized | import("@distilled.cloud/aws/Errors").OperationAborted | import("@distilled.cloud/aws/Errors").OptInRequired | import("effect/PlatformError").PlatformError | ecr.RepositoryNotFoundException | import("@distilled.cloud/aws/Errors").RequestAbortedException | import("@distilled.cloud/aws/Errors").RequestEntityTooLargeException | import("@distilled.cloud/aws/Errors").RequestExpired | import("@distilled.cloud/aws/Errors").RequestTimeoutException | ecr.ServerException | import("@distilled.cloud/aws/Errors").ServiceUnavailable | import("@distilled.cloud/aws/Errors").ThrottlingException | import("effect/Cause").TimeoutError | ecr.TooManyTagsException | import("@distilled.cloud/aws/Errors").UnknownAwsError | import("@distilled.cloud/aws/Errors").UnknownOperationException | import("@distilled.cloud/aws/Errors").UnrecognizedClientException | import("@distilled.cloud/aws/Errors").ValidationError | import("@distilled.cloud/aws/Errors").ValidationException, import("@distilled.cloud/aws/Credentials").Credentials | FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient | Path.Path | import("../../Stack.ts").Stack | import("../../Stage.ts").Stage>; hash: (options: { source: ImageSourceLike; platform?: string; port?: number; isExternal?: boolean; bootstrap: (importPath: string) => string; }) => Effect.Effect; watchMain: (options: { source: BundledImageSource; isExternal?: boolean; bootstrap: (importPath: string) => string; }) => Effect.Effect<{ inputOptions: rolldown.InputOptions; outputOptions: rolldown.OutputOptions; extra: Bundle.BundleConfig | undefined; }, import("effect/PlatformError").PlatformError, FileSystem.FileSystem | Path.Path>; }, never, AlchemyContext | Docker | Path.Path>; /** The resolver service returned by {@link makeImageSource}. */ export interface ImageSource extends Effect.Success { } //# sourceMappingURL=ImageSource.d.ts.map