import * as yup$1 from "yup"; //#region src/deployments.d.ts declare const DEPLOYMENT_ENV_VAR_KEY_REGEX: RegExp; declare const DEPLOYMENT_SOURCE_ID_REGEX: RegExp; declare const MAX_DEPLOYMENT_SOURCE_ID_LENGTH = 63; declare const DEPLOYMENT_RUNTIMES: readonly ["fly", "gcp"]; type DeploymentRuntime = typeof DEPLOYMENT_RUNTIMES[number]; declare const DEFAULT_DEPLOYMENT_RUNTIME = "fly"; declare const DEPLOYMENT_VERSIONS: { readonly "gcp-beta-1": "gcp"; }; type DeploymentVersion = keyof typeof DEPLOYMENT_VERSIONS; declare const DEPLOYMENT_VERSION_TOKENS: DeploymentVersion[]; declare function isDeploymentRuntime(value: unknown): value is DeploymentRuntime; declare function isDeploymentVersion(value: unknown): value is DeploymentVersion; /** * The runtime a deploy file's `version` export selects. Absent (or null) is the * default runtime; an unknown token is null, and the caller refuses it. */ declare function deploymentRuntimeForVersion(version: string | null | undefined): DeploymentRuntime | null; /** * How many file entries a manifest may carry. * * High enough that the listing is the WHOLE tree for essentially any real * source: node_modules and build output are excluded before packaging, and what * survives is source, which is thousands of files at the top end rather than * tens of thousands. The dashboard shows every entry, so this is the number that * decides whether it is showing everything. * * The cost is a JSON column: ~90 bytes an entry, so ~180 KB before Postgres * compresses it — and paths in one tree share nearly all their prefixes, which * TOAST squashes hard. Worth it to be able to say "these are the files" rather * than "these are some of them". */ declare const MAX_SOURCE_MANIFEST_ENTRIES = 2000; declare const MAX_SOURCE_MANIFEST_PATH_LENGTH = 1024; type DeploymentSourceManifest = { /** Every file packaged, including the ones `entries` had no room for. */file_count: number; /** Their total size before compression. */ total_bytes: number; /** What was actually uploaded, after tar + gzip. */ compressed_bytes: number; /** * The largest files, biggest first, capped at MAX_SOURCE_MANIFEST_ENTRIES. * * Largest-first rather than a truncated alphabetical walk, because the cap * then only ever drops files too small to be anyone's problem — the question * this answers is which files are big. */ entries: { path: string; bytes: number; }[]; }; /** * The manifest for a packaged tree, capped. `paths` and `sizes` come from the * packager, which already holds every entry it wrote. */ declare function buildSourceManifest(options: { files: { path: string; bytes: number; }[]; compressedBytes: number; }): DeploymentSourceManifest; /** * Parses a stored manifest, or null when there is none / it is not one. * * Tolerant on purpose: this is a debugging aid read out of a JSON column, and a * row written by an older client (or hand-edited) must degrade to "no manifest" * rather than break the deployment it belongs to. */ declare function parseSourceManifest(value: unknown): DeploymentSourceManifest | null; /** * The manifest entries belonging to one service, and whether the listing is * complete for it. * * `rootDirectory` is the service's own subtree of the shared upload; null or * "." means the whole tree. Paths are posix and relative to the upload root. * * `prefix` is that root as a path prefix ("web/", or "" for the whole tree). * Returned rather than left for the caller to re-derive: entries keep their * full paths, so anything that displays them relative to the service — the * dashboard's folder tree — needs exactly the prefix this filtered on, and a * second copy of this normalisation is a second place for it to drift. */ declare function sourceManifestEntriesForService(manifest: DeploymentSourceManifest, rootDirectory: string | null): { entries: { path: string; bytes: number; }[]; truncated: boolean; prefix: string; }; declare const DEPLOYMENT_CONNECTION_VALUE_REGEX: RegExp; /** * The managed Hexclave service's slot on the deployments board. A service in * the deploy file's `deploy` export must never shadow it — `service("hexclave")` * doesn't exist (the `hexclave` context object replaces it), but the id stays * reserved so connection values like "hexclave.projectId" are unambiguous. */ declare const HEXCLAVE_SERVICE_ID = "hexclave"; declare const HEXCLAVE_OUTPUT_KEYS: readonly ["projectId", "apiUrl", "jwksUrl", "publishableClientKey", "secretServerKey"]; declare const SERVICE_OUTPUT_KEYS: readonly ["url", "hostname"]; /** * Splits a connection reference into its parts. One parser so the CLI, the * backend and the runtime cannot disagree about what `api.url:9090` * means. Returns null when the value is not a reference at all. */ declare function parseConnectionValue(value: string): { serviceId: string; outputKey: string; port: number | null; } | null; /** * Whether a reference actually requires its target to have DEPLOYED. The * answer depends on the RUNTIME, because it is a fact about where addresses * come from: * * On "fly", a service's private hostname is a pure function of its identity * (Fly's 6PN DNS publishes ".internal" the moment the app exists), so * `hostname` and a private `url` with a named port resolve before the target * ever runs. Only a PUBLIC url (the platform URL, which exists once the service * is up) and a bare `url()` (which has to read the target's ports) wait. * `targetIsPublic` is null when the caller cannot answer — a reference into a * source this deploy file does not contain, or one naming a port the target * does not declare — in which case the conservative answer is that it waits. * Getting this wrong in the other direction would serialize independent * deploys, cascade false "skipped" results when the target fails, and reject * mutually-wired services as circular. * * On "gcp", every SERVICE output waits — `url` and `hostname` alike, public or * private, named port or not. Both are the target's runtime ADDRESS, and GCP * publishes none for a service that does not exist yet: a private service is * reached at its VM's internal IP (assigned when the instance is created), a * public one at its platform URL, and a serverless one at the URI its revision * got. The cost is that mutually-wired services are a circular dependency * there, reported as one, instead of silently resolving. * * `hexclave.*` outputs are not service outputs and never wait — they come from * the managed service, which always exists. */ declare function connectionRequiresTargetDeployed(runtime: DeploymentRuntime, outputKey: string, port: number | null, targetIsPublic: boolean | null): boolean; /** Formats a connection reference. The inverse of parseConnectionValue. */ declare function formatConnectionValue(serviceId: string, outputKey: string, port?: number | null): string; type HexclaveOutputKey = typeof HEXCLAVE_OUTPUT_KEYS[number]; type ServiceOutputKey = typeof SERVICE_OUTPUT_KEYS[number]; type DeploymentEnvVarDefinition = { type?: "secret" | "connection" | undefined; value?: string | undefined; key?: string | undefined; }; /** * The builder machine for one deployment source. * * A property of the DEPLOYMENT rather than of any service: one `hexclave deploy` * uploads one tree and builds every service of it on ONE machine, so there is * exactly one builder to size and a per-service field could only ever be a * request that some other service's request overrode. * * Absent, or `memory` absent within it, means the deployment picks its own size * — the floor a build of that shape needs (see DEFAULT_BUILDER_MEMORY, and the * larger floor an auto-detected build gets). */ type DeploymentBuilderDefinition = { memory?: DeploymentMemorySize | undefined; }; type DeploymentServiceDefinition = { type: DeploymentServiceType; public?: boolean | undefined; ports: DeploymentPorts; min_instances?: number | undefined; max_instances?: number | undefined; memory?: DeploymentMemorySize | undefined; root_directory?: string | undefined; dockerfile_path?: string | undefined; image?: string | undefined; persistent_volumes?: Record | undefined; build_command?: string | undefined; start_command?: string | undefined; env: Record; }; declare function deploymentServiceIsBuilt(definition: Pick): boolean; declare function deploymentServiceUsesGeneratedDockerfile(definition: Pick): boolean; type DeploymentPortDefinition = { protocol: "http" | "tcp"; }; type DeploymentPorts = Record; type DeploymentVolumeDefinition = { path: string; size_gb: number; }; type DeploymentServiceType = "server" | "serverless"; declare const DEPLOYMENT_SERVICE_TYPES: readonly ["server", "serverless"]; /** A port's explicitly configured protocol. */ declare function portProtocol(port: DeploymentPortDefinition): "http" | "tcp"; /** One declared port, with the record's key parsed. */ type DeploymentPortEntry = { port: number; protocol: "http" | "tcp"; }; /** * The ports as a list, ascending by port number. Every * consumer that has to compare, count or iterate ports goes through this, so the * key parsing happens in exactly one place — and so the order is * the same everywhere (object key order would otherwise put "80" after "8080" * for one caller and not another). * * Keys that are not port numbers are dropped rather than thrown on: this runs on * stored rows, and a hand-edited one must not take down a listing. Every write * path validates the shape. */ declare function deploymentPortEntries(ports: DeploymentPorts): DeploymentPortEntry[]; declare const DEPLOYMENT_PORT_KEY_REGEX: RegExp; /** * The port number that additionally answers on the standard 80/443, or null when * the service has no single obvious one. * * For a PUBLIC service it is the LOWEST-numbered HTTP port. Lowest rather than * first-encountered: deploymentPortEntries sorts numerically, so the holder is a * property of the port set and not of JSON key ordering. That determinism is the * whole point — the holder is the port the service's bare URL names and the only * one a custom domain can front, so an arbitrary pick would silently move both. * * For a PRIVATE service it is the sole HTTP port, because a private service gets * public IPs the moment a custom domain is attached and that domain terminates * TLS on 443. Null when there are several, which is what makes such a service * ineligible to hold a domain at all. * * KEPT IN SYNC WITH standardPortsHolderFor in apps/marshal/src/services.ts. */ declare function standardPortsHolderPort(ports: DeploymentPorts, isPublic: boolean): number | null; /** * Whether this port is the one that owns the service's standard 80/443, and so * the one whose URL carries no `:port` suffix. * * VERIFIED AGAINST REAL FLY: every other port of a public service is reachable * on its own number over BOTH IPv4 and IPv6 — a shared IPv4 forwards any port, * so long as the traffic carries SNI or a Host header for the proxy to route on. * The difference between the holder and the rest is the URL shape and which port * a custom domain can front, NOT reachability. */ declare function deploymentPortOwnsStandardPorts(ports: DeploymentPorts, isPublic: boolean, port: number): boolean; /** * Declared ports that collide with the external listeners the standard-ports * holder reserves, as a sorted list (empty when there is no conflict). * * The holder does not only answer on its own number — it also claims external 80 * and 443, which is what makes the platform URL and any custom domain * certificate work. Those are listeners on the WHOLE app: the runtime emits one * entry per declared port, so a *different* port that is itself numbered 80 or * 443 asks for an external listener the holder has already taken. Two entries * claiming one external port is a config the runtime cannot serve — it is * rejected outright, or routes one of them somewhere the author did not ask for. * * The cheap example is a public service with * `{ 80: { protocol: "http" }, 443: { protocol: "http" } }`: 80 is the * holder, claims 80 and 443, and the declared 443 claims 443 again. This is * refused rather than resolved by precedence, because every way of resolving it * silently drops or retargets a port the author explicitly declared. */ declare function reservedStandardPortConflicts(ports: DeploymentPorts, isPublic: boolean): number[]; /** * The port a bare `url()` refers to, or null when the service leaves it * ambiguous (several HTTP ports) or impossible (none). Callers phrase their own * error — the CLI wants a config-file diagnostic, the backend an HTTP status — * which is why this returns null rather than throwing. */ declare function soleHttpDeploymentPort(ports: DeploymentPorts): number | null; /** One port's definition, or null when the service does not declare it. */ declare function deploymentPortEntry(ports: DeploymentPorts, port: number): DeploymentPortEntry | null; declare const MAX_PORTS_PER_SERVICE = 10; declare const MAX_INSTANCES_PER_SERVICE = 10; declare const MIN_VOLUME_SIZE_GB = 1; declare const MAX_VOLUME_SIZE_GB = 500; declare const MAX_PERSISTENT_VOLUMES_PER_SERVICE = 1; declare const FREE_PLAN_MAX_VOLUMES_PER_PROJECT = 1; declare const FREE_PLAN_MAX_VOLUME_SIZE_GB = 10; declare const DEPLOYMENT_VOLUME_ID_REGEX: RegExp; declare const MAX_VOLUME_ID_LENGTH = 26; declare const DEPLOYMENT_MEMORY_SIZES: readonly ["512MB", "1GB", "2GB", "4GB", "8GB", "16GB", "32GB"]; type DeploymentMemorySize = typeof DEPLOYMENT_MEMORY_SIZES[number]; declare const FLY_SERVER_MEMORY_SIZES: readonly ["512MB", "1GB", "2GB", "4GB", "8GB"]; declare const FLY_SERVERLESS_MEMORY_SIZES: readonly ["512MB", "1GB", "2GB", "4GB", "8GB"]; declare const GCP_SERVER_MEMORY_SIZES: readonly ["1GB", "2GB", "4GB", "8GB"]; declare const GCP_SERVERLESS_MEMORY_SIZES: readonly ["512MB", "1GB", "2GB", "4GB", "8GB"]; declare const SERVER_MEMORY_SIZES: readonly ["512MB", "1GB", "2GB", "4GB", "8GB"]; declare const SERVERLESS_MEMORY_SIZES: readonly ["512MB", "1GB", "2GB", "4GB", "8GB"]; declare const BUILDER_MEMORY_SIZES: readonly ["8GB", "16GB", "32GB"]; declare const DEFAULT_SERVER_MEMORY = "512MB"; declare const DEFAULT_SERVERLESS_MEMORY = "512MB"; declare const GCP_DEFAULT_SERVER_MEMORY = "1GB"; declare const DEFAULT_BUILDER_MEMORY = "8GB"; /** The rungs a service of this type may ask for on this runtime. */ declare function deploymentMemorySizesForType(type: DeploymentServiceType, runtime?: DeploymentRuntime): readonly DeploymentMemorySize[]; /** What a service of this type runs at on this runtime when it declares no `memory`. */ declare function defaultDeploymentMemoryForType(type: DeploymentServiceType, runtime?: DeploymentRuntime): DeploymentMemorySize; /** A size token as a whole number of megabytes. */ declare function deploymentMemoryToMb(size: DeploymentMemorySize): number; /** * The size token for a stored megabyte count, or null when no rung matches. * * Null rather than a throw or a rounded neighbour: the input is a database * column, and a value written by a future version (or edited by hand) must * degrade to "unset" — which every reader already handles — rather than claim * to be a size the deployment is not running. */ declare function deploymentMemoryFromMb(megabytes: number): DeploymentMemorySize | null; /** * The canonical token for something an author wrote, or null. * * Case-insensitive and space-tolerant on PURPOSE, and used only to phrase a * "did you mean" — never to accept the input. "4gb" and "4 GB" are refused like * any other non-canonical spelling; recognising them is what lets the error say * which token to write instead of listing seven and leaving the reader to * diff them by eye. Binary suffixes are recognised for the same reason: "4Gi" * is what someone arriving from a container platform will type first. */ declare function suggestDeploymentMemorySize(raw: string): DeploymentMemorySize | null; /** * The CPU that comes with a memory size, and whether it is a whole core. * * Derived rather than declared — see the note on the ladder above — but NOT * hidden: on the smaller server sizes it is a burstable fraction of a core, and * a 4GB server that turns out to have one shared core is a surprise worth * spending a line of UI on rather than one to meet under load. Every surface * that shows a size shows this beside it. * * `shared` means the vCPU is a burstable slice: it can reach a full core in * bursts and is throttled to `count` sustained. A dedicated CPU is `count` * cores, always. * * This is the DISPLAY copy of the mapping. The runtime derives its own machine * shapes from the same ladder at the point it calls a provider — that boundary * re-derives rather than trusting a number off the wire, exactly as it * re-validates every other part of a spec. */ declare function deploymentCpuForMemory(type: DeploymentServiceType, memory: DeploymentMemorySize, runtime?: DeploymentRuntime): { count: number; shared: boolean; }; /** * The most memory one project may hold in ALWAYS-ON services at once. * * Hexclave's own capacity guard, not a per-project quota: nothing meters * deployment compute, so the plan ladder bounds what one service may ask for * and this bounds how many of them may ask at once. Without it a paid project * can stand up an arbitrary number of top-rung servers, each of which is a * machine somebody pays for. * * Only always-on services count (effective `min_instances` of 1 or more). A * service that scales to zero holds no machine while it is idle, and how far it * may scale UP is already bounded by MAX_INSTANCES_PER_SERVICE. */ declare const MAX_PROJECT_ALWAYS_ON_MEMORY_MB: number; declare const MAX_DEPLOYMENT_COMMAND_LENGTH = 2048; /** * Whether `value` is usable as a build or start command. * * Control characters are refused rather than escaped. A build command becomes a * line of a generated Dockerfile and a start command becomes an argv entry in a * machine config, and in both places a newline or a NUL is a structural * character of the thing being generated rather than data — so the rule is * stated here, once, and the generators may then assume it. */ declare function isValidDeploymentCommand(value: string): boolean; declare const MAX_DEPLOYMENT_IMAGE_REF_LENGTH = 512; declare const DEFAULT_DEPLOYMENT_IMAGE_REGISTRY = "docker.io"; declare const DEFAULT_DEPLOYMENT_IMAGE_NAMESPACE = "library"; /** * An image reference in its parts, always fully qualified: `postgres:16` parses * to the registry `docker.io` and the repository `library/postgres`, because * that is what actually gets pulled and a stored definition should say so. * * Exactly one of `tag` and `digest` is set. A tag is a POINTER the publisher can * move; a digest is the content hash and cannot be moved. Both spellings are * accepted from authors and neither is resolved here — the reference reaches the * runtime as written, and an author who needs fixed bytes writes the digest. */ type DeploymentImageRef = { registry: string; repository: string; tag: string | null; digest: string | null; canonical: string; }; /** * Parses and normalizes an image reference. * * Returns the failure MESSAGE rather than just null (unlike * parseConnectionValue) because every caller wants to say the same thing and * the useful part is always *which* rule was broken: the CLI prints it as a * deploy-file diagnostic, the schema as a validation error, and the backend as * a 400. One message, phrased once. */ declare function parseDeploymentImageRef(value: string): { ok: true; ref: DeploymentImageRef; } | { ok: false; message: string; }; declare const deploymentEnvVarSchema: yup$1.ObjectSchema<{ type: "secret" | "connection" | undefined; value: string | undefined; key: string | undefined; default_value: undefined; }, yup$1.AnyObject, { type: undefined; value: undefined; key: undefined; default_value: undefined; }, "">; declare const deploymentSecretDefaultsSchema: yup$1.MixedSchema, yup$1.AnyObject, undefined, "">; declare const MAX_DEPLOYMENT_CI_ENV_BYTES: number; declare const deploymentCiEnvSchema: yup$1.MixedSchema, yup$1.AnyObject, undefined, "">; declare const deploymentServiceDefinitionSchema: yup$1.ObjectSchema<{ type: "server" | "serverless"; public: boolean | undefined; ports: Record; min_instances: number | undefined; max_instances: number | undefined; memory: "512MB" | "1GB" | "2GB" | "4GB" | "8GB" | "16GB" | "32GB" | undefined; root_directory: string | undefined; persistent_volumes: Record | undefined; dockerfile_path: string | undefined; image: string | undefined; build_command: string | undefined; start_command: string | undefined; dev_command: undefined; env: Record; }, yup$1.AnyObject, { type: undefined; public: undefined; ports: undefined; min_instances: undefined; max_instances: undefined; memory: undefined; root_directory: undefined; persistent_volumes: undefined; dockerfile_path: undefined; image: undefined; build_command: undefined; start_command: undefined; dev_command: undefined; env: undefined; }, "">; /** * The `builder` a deploy file declares, alongside its services. * * Deliberately its own schema rather than a field of the service one: the * builder is one machine per DEPLOYMENT, and the sync route stores it on the * deployment source rather than on any service row. */ declare const deploymentBuilderDefinitionSchema: yup$1.ObjectSchema<{ memory: "8GB" | "16GB" | "32GB" | undefined; }, yup$1.AnyObject, { memory: undefined; }, "">; //#endregion export { MIN_VOLUME_SIZE_GB as $, DeploymentVolumeDefinition as A, reservedStandardPortConflicts as At, HexclaveOutputKey as B, DeploymentPortEntry as C, isDeploymentRuntime as Ct, DeploymentServiceType as D, parseDeploymentImageRef as Dt, DeploymentServiceDefinition as E, parseConnectionValue as Et, GCP_DEFAULT_SERVER_MEMORY as F, MAX_INSTANCES_PER_SERVICE as G, MAX_DEPLOYMENT_COMMAND_LENGTH as H, GCP_SERVERLESS_MEMORY_SIZES as I, MAX_PROJECT_ALWAYS_ON_MEMORY_MB as J, MAX_PERSISTENT_VOLUMES_PER_SERVICE as K, GCP_SERVER_MEMORY_SIZES as L, FLY_SERVER_MEMORY_SIZES as M, sourceManifestEntriesForService as Mt, FREE_PLAN_MAX_VOLUMES_PER_PROJECT as N, standardPortsHolderPort as Nt, DeploymentSourceManifest as O, parseSourceManifest as Ot, FREE_PLAN_MAX_VOLUME_SIZE_GB as P, suggestDeploymentMemorySize as Pt, MAX_VOLUME_SIZE_GB as Q, HEXCLAVE_OUTPUT_KEYS as R, DeploymentPortDefinition as S, formatConnectionValue as St, DeploymentRuntime as T, isValidDeploymentCommand as Tt, MAX_DEPLOYMENT_IMAGE_REF_LENGTH as U, MAX_DEPLOYMENT_CI_ENV_BYTES as V, MAX_DEPLOYMENT_SOURCE_ID_LENGTH as W, MAX_SOURCE_MANIFEST_PATH_LENGTH as X, MAX_SOURCE_MANIFEST_ENTRIES as Y, MAX_VOLUME_ID_LENGTH as Z, DEPLOYMENT_VOLUME_ID_REGEX as _, deploymentRuntimeForVersion as _t, DEFAULT_DEPLOYMENT_RUNTIME as a, connectionRequiresTargetDeployed as at, DeploymentImageRef as b, deploymentServiceIsBuilt as bt, DEPLOYMENT_CONNECTION_VALUE_REGEX as c, deploymentCiEnvSchema as ct, DEPLOYMENT_PORT_KEY_REGEX as d, deploymentMemoryFromMb as dt, SERVERLESS_MEMORY_SIZES as et, DEPLOYMENT_RUNTIMES as f, deploymentMemorySizesForType as ft, DEPLOYMENT_VERSION_TOKENS as g, deploymentPortOwnsStandardPorts as gt, DEPLOYMENT_VERSIONS as h, deploymentPortEntry as ht, DEFAULT_DEPLOYMENT_IMAGE_REGISTRY as i, buildSourceManifest as it, FLY_SERVERLESS_MEMORY_SIZES as j, soleHttpDeploymentPort as jt, DeploymentVersion as k, portProtocol as kt, DEPLOYMENT_ENV_VAR_KEY_REGEX as l, deploymentCpuForMemory as lt, DEPLOYMENT_SOURCE_ID_REGEX as m, deploymentPortEntries as mt, DEFAULT_BUILDER_MEMORY as n, SERVICE_OUTPUT_KEYS as nt, DEFAULT_SERVERLESS_MEMORY as o, defaultDeploymentMemoryForType as ot, DEPLOYMENT_SERVICE_TYPES as p, deploymentMemoryToMb as pt, MAX_PORTS_PER_SERVICE as q, DEFAULT_DEPLOYMENT_IMAGE_NAMESPACE as r, ServiceOutputKey as rt, DEFAULT_SERVER_MEMORY as s, deploymentBuilderDefinitionSchema as st, BUILDER_MEMORY_SIZES as t, SERVER_MEMORY_SIZES as tt, DEPLOYMENT_MEMORY_SIZES as u, deploymentEnvVarSchema as ut, DeploymentBuilderDefinition as v, deploymentSecretDefaultsSchema as vt, DeploymentPorts as w, isDeploymentVersion as wt, DeploymentMemorySize as x, deploymentServiceUsesGeneratedDockerfile as xt, DeploymentEnvVarDefinition as y, deploymentServiceDefinitionSchema as yt, HEXCLAVE_SERVICE_ID as z }; //# sourceMappingURL=deployments--S2KluCd.d.ts.map