@absolutejs/deploy 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloudTarget.d.ts +4 -4
- package/dist/cloudflare.d.ts +2 -2
- package/dist/cloudflare.js.map +2 -2
- package/dist/deployer.d.ts +9 -9
- package/dist/digitalocean.d.ts +5 -5
- package/dist/digitalocean.js +2 -8
- package/dist/digitalocean.js.map +5 -5
- package/dist/digitaloceanDns.d.ts +2 -2
- package/dist/digitaloceanDns.js +2 -8
- package/dist/digitaloceanDns.js.map +6 -6
- package/dist/digitaloceanEphemeralInfrastructure.d.ts +20 -0
- package/dist/digitaloceanEphemeralInfrastructure.js +610 -0
- package/dist/digitaloceanEphemeralInfrastructure.js.map +13 -0
- package/dist/digitaloceanInfrastructure.js +2 -8
- package/dist/digitaloceanInfrastructure.js.map +6 -6
- package/dist/digitaloceanIngress.js +2 -8
- package/dist/digitaloceanIngress.js.map +5 -5
- package/dist/dns.d.ts +1 -1
- package/dist/dns.js.map +2 -2
- package/dist/env.d.ts +1 -1
- package/dist/env.js.map +2 -2
- package/dist/ephemeralInfrastructure.d.ts +37 -0
- package/dist/ephemeralInfrastructure.js +4 -0
- package/dist/ephemeralInfrastructure.js.map +9 -0
- package/dist/gcp.js +2 -6
- package/dist/gcp.js.map +3 -3
- package/dist/hetzner.d.ts +3 -3
- package/dist/hetzner.js +2 -8
- package/dist/hetzner.js.map +5 -5
- package/dist/hetznerDns.d.ts +2 -2
- package/dist/hetznerDns.js.map +2 -2
- package/dist/hetznerInfrastructure.js +2 -8
- package/dist/hetznerInfrastructure.js.map +7 -7
- package/dist/index.d.ts +10 -10
- package/dist/index.js +16 -64
- package/dist/index.js.map +5 -5
- package/dist/linode.d.ts +3 -3
- package/dist/linode.js +2 -8
- package/dist/linode.js.map +5 -5
- package/dist/linodeInfrastructure.js +3 -13
- package/dist/linodeInfrastructure.js.map +7 -7
- package/dist/preview.d.ts +3 -3
- package/dist/preview.js +2 -5
- package/dist/preview.js.map +3 -3
- package/dist/processManagers.d.ts +4 -4
- package/dist/route53.d.ts +2 -2
- package/dist/route53.js.map +2 -2
- package/dist/targets.d.ts +1 -1
- package/dist/tls.d.ts +5 -5
- package/dist/tls.js +2 -5
- package/dist/tls.js.map +3 -3
- package/dist/vultr.d.ts +4 -4
- package/dist/vultr.js +2 -8
- package/dist/vultr.js.map +5 -5
- package/dist/vultrInfrastructure.js +2 -8
- package/dist/vultrInfrastructure.js.map +7 -7
- package/package.json +12 -5
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/targets.ts", "../src/cloudTarget.ts", "../src/hetzner.ts", "../src/infrastructureAdapter.ts", "../src/hetznerInfrastructure.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Target interface + bundled adapters (localTarget, sshTarget).\n *\n * A Target is the narrowest abstraction over \"a place I can deploy to\":\n *\n * - `exec(cmd, opts?)` — run a shell command, capture stdout/stderr/exitCode.\n * - `upload(localPath, remotePath, opts?)` — copy a local file or directory\n * to the target. Implementation is free to use whatever is fast (rsync,\n * scp, mv).\n * - `close?()` — optional teardown.\n *\n * Two adapters are bundled:\n *\n * - `localTarget` runs in a temp directory on the local filesystem. Useful\n * for tests and for \"deploy\" workflows that happen on the same host.\n * - `sshTarget` shells out to the system `ssh` and `rsync` binaries. No\n * `ssh2` npm dependency — the controller machine just needs `ssh` and\n * (optionally) `rsync` in PATH, which is universal on Mac/Linux/WSL.\n *\n * Provider-specific targets (Cloudflare Workers HTTP API, Fly Machines API,\n * AWS Fargate) don't fit \"exec + upload\" and ship as siblings later.\n */\n\nimport { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport type ExecOptions = {\n /** Working directory on the target. Default: target's root. */\n cwd?: string;\n /** Env vars to set for this command (merged onto target.env). */\n env?: Record<string, string>;\n /** Hard kill after this many ms. Default 600_000 (10 min). 0 disables. */\n timeoutMs?: number;\n /** Pipe stdout/stderr through here as it streams (lines, newline-stripped). */\n onLog?: (line: string, stream: \"stdout\" | \"stderr\") => void;\n /** Stdin payload — a string is written verbatim. */\n stdin?: string;\n};\n\nexport type ExecResult = {\n stdout: string;\n stderr: string;\n exitCode: number;\n};\n\nexport type UploadOptions = {\n /** Exclude paths matching these globs from a directory upload. */\n exclude?: string[];\n /** When uploading a directory, delete remote files not present locally. */\n deleteOrphans?: boolean;\n};\n\nexport type Target = {\n /** Human-readable description (e.g. \"ssh root@droplet-1.example.com\"). */\n readonly description: string;\n exec: (cmd: string, opts?: ExecOptions) => Promise<ExecResult>;\n upload: (\n localPath: string,\n remotePath: string,\n opts?: UploadOptions,\n ) => Promise<void>;\n close?: () => Promise<void>;\n};\n\n// -----------------------------------------------------------------------------\n// localTarget\n// -----------------------------------------------------------------------------\n\nexport type LocalTargetOptions = {\n /** Root directory the target operates in. Created if missing. */\n root: string;\n /** Env merged into every exec. */\n env?: Record<string, string>;\n};\n\nconst decodeChunks = async (\n reader: ReadableStream<Uint8Array> | null,\n onLine: ((line: string) => void) | undefined,\n): Promise<string> => {\n if (!reader) return \"\";\n const decoder = new TextDecoder();\n let buffer = \"\";\n let collected = \"\";\n const stream = reader.getReader();\n try {\n while (true) {\n const { done, value } = await stream.read();\n if (done) break;\n const chunk = decoder.decode(value, { stream: true });\n collected += chunk;\n if (!onLine) continue;\n buffer += chunk;\n let newline = buffer.indexOf(\"\\n\");\n while (newline !== -1) {\n const line = buffer.slice(0, newline).replace(/\\r$/, \"\");\n if (line.length > 0) onLine(line);\n buffer = buffer.slice(newline + 1);\n newline = buffer.indexOf(\"\\n\");\n }\n }\n const tail = decoder.decode();\n collected += tail;\n if (onLine && (buffer + tail).length > 0)\n onLine((buffer + tail).replace(/\\r$/, \"\"));\n } finally {\n stream.releaseLock();\n }\n return collected;\n};\n\nconst runSpawn = async (\n argv: string[],\n options: {\n cwd?: string;\n env?: Record<string, string>;\n timeoutMs?: number;\n onLog?: ExecOptions[\"onLog\"];\n stdin?: string;\n },\n): Promise<ExecResult> => {\n const proc = Bun.spawn(argv, {\n cwd: options.cwd,\n env: options.env,\n stderr: \"pipe\",\n stdin: options.stdin === undefined ? \"ignore\" : \"pipe\",\n stdout: \"pipe\",\n });\n\n if (options.stdin !== undefined && proc.stdin) {\n // Bun.spawn returns a FileSink for piped stdin — `write` + `end`, not a\n // WritableStream. (We use a permissive cast because @types/bun's\n // Subprocess.stdin discriminant flips based on the stdin generic.)\n const sink = proc.stdin as unknown as {\n write: (chunk: string | Uint8Array) => number | Promise<number>;\n end: () => void | Promise<void>;\n };\n const wrote = sink.write(options.stdin);\n if (wrote && typeof (wrote as Promise<number>).then === \"function\") {\n await wrote;\n }\n const ended = sink.end();\n if (ended && typeof (ended as Promise<void>).then === \"function\") {\n await ended;\n }\n }\n\n const timeout = options.timeoutMs ?? 600_000;\n let timer: ReturnType<typeof setTimeout> | undefined;\n if (timeout > 0) {\n timer = setTimeout(() => {\n try {\n proc.kill();\n } catch {\n /* already gone */\n }\n }, timeout);\n }\n\n const stdoutPromise = decodeChunks(\n proc.stdout as unknown as ReadableStream<Uint8Array>,\n options.onLog ? (line) => options.onLog!(line, \"stdout\") : undefined,\n );\n const stderrPromise = decodeChunks(\n proc.stderr as unknown as ReadableStream<Uint8Array>,\n options.onLog ? (line) => options.onLog!(line, \"stderr\") : undefined,\n );\n\n const [stdout, stderr, exitCode] = await Promise.all([\n stdoutPromise,\n stderrPromise,\n proc.exited,\n ]);\n if (timer) clearTimeout(timer);\n\n return { exitCode: exitCode ?? -1, stderr, stdout };\n};\n\nexport const localTarget = (options: LocalTargetOptions): Target => {\n const baseEnv = { ...options.env };\n const ensureRoot = async () => {\n await mkdir(options.root, { recursive: true });\n };\n\n return {\n description: `local ${options.root}`,\n exec: async (cmd, opts) => {\n await ensureRoot();\n return runSpawn([\"sh\", \"-c\", cmd], {\n cwd: opts?.cwd ?? options.root,\n env: { ...process.env, ...baseEnv, ...(opts?.env ?? {}) } as Record<\n string,\n string\n >,\n onLog: opts?.onLog,\n stdin: opts?.stdin,\n timeoutMs: opts?.timeoutMs,\n });\n },\n upload: async (localPath, remotePath, opts) => {\n await ensureRoot();\n const dest = remotePath.startsWith(\"/\")\n ? remotePath\n : join(options.root, remotePath);\n const argv = [\"rsync\", \"-a\"];\n if (opts?.deleteOrphans) argv.push(\"--delete\");\n for (const pattern of opts?.exclude ?? [])\n argv.push(\"--exclude\", pattern);\n // rsync semantics: a trailing slash on the source copies *contents*; without it the dir itself is nested.\n argv.push(localPath, dest);\n const result = await runSpawn(argv, { timeoutMs: 600_000 });\n if (result.exitCode !== 0) {\n throw new Error(\n `local upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`,\n );\n }\n },\n };\n};\n\n// -----------------------------------------------------------------------------\n// sshTarget\n// -----------------------------------------------------------------------------\n\nexport type SshTargetOptions = {\n /** Hostname or IP of the remote. */\n host: string;\n /** Login user. Default `root`. */\n user?: string;\n /** SSH port. Default 22. */\n port?: number;\n /** Path to SSH identity file. Default: ssh's own search. */\n identity?: string;\n /** Extra flags appended to every `ssh` invocation. */\n sshFlags?: string[];\n /**\n * Use rsync for `upload`. Default true. When false, falls back to `scp`\n * which is universal but doesn't support delete / exclude.\n */\n rsync?: boolean;\n /**\n * Env vars to forward via `ssh -o SendEnv=...`. Most remote sshd configs\n * accept only `LANG` and `LC_*` by default; for app env vars use the\n * step `env` option instead, which prepends `KEY=value` to the command.\n */\n forwardEnv?: string[];\n};\n\nconst sshTargetString = (options: SshTargetOptions): string => {\n const user = options.user ?? \"root\";\n return `${user}@${options.host}`;\n};\n\nconst sshBaseFlags = (options: SshTargetOptions): string[] => {\n const flags: string[] = [];\n if (options.port !== undefined && options.port !== 22)\n flags.push(\"-p\", String(options.port));\n if (options.identity !== undefined) flags.push(\"-i\", options.identity);\n // Never get stuck on a host-key prompt; treat unknown hosts as a fatal config issue rather than a UX detour.\n flags.push(\"-o\", \"BatchMode=yes\", \"-o\", \"StrictHostKeyChecking=accept-new\");\n for (const flag of options.sshFlags ?? []) flags.push(flag);\n return flags;\n};\n\nconst shellQuote = (value: string): string =>\n `'${value.replace(/'/g, `'\\\\''`)}'`;\n\nconst buildRemoteCmd = (cmd: string, opts: ExecOptions | undefined): string => {\n const env = opts?.env;\n const envPrefix = env\n ? Object.entries(env)\n .map(([k, v]) => `${k}=${shellQuote(v)}`)\n .join(\" \") + \" \"\n : \"\";\n if (opts?.cwd) {\n return `cd ${shellQuote(opts.cwd)} && ${envPrefix}${cmd}`;\n }\n return `${envPrefix}${cmd}`;\n};\n\nexport const sshTarget = (options: SshTargetOptions): Target => {\n const remote = sshTargetString(options);\n const useRsync = options.rsync ?? true;\n\n return {\n description: `ssh ${remote}${options.port && options.port !== 22 ? `:${options.port}` : \"\"}`,\n exec: async (cmd, opts) => {\n const argv = [\"ssh\", ...sshBaseFlags(options)];\n for (const name of options.forwardEnv ?? [])\n argv.push(\"-o\", `SendEnv=${name}`);\n argv.push(remote, buildRemoteCmd(cmd, opts));\n return runSpawn(argv, {\n onLog: opts?.onLog,\n stdin: opts?.stdin,\n timeoutMs: opts?.timeoutMs,\n });\n },\n upload: async (localPath, remotePath, opts) => {\n if (useRsync) {\n const sshCmd = [\"ssh\", ...sshBaseFlags(options)]\n .map((part) => (part.includes(\" \") ? `'${part}'` : part))\n .join(\" \");\n const argv = [\"rsync\", \"-az\", \"-e\", sshCmd];\n if (opts?.deleteOrphans) argv.push(\"--delete\");\n for (const pattern of opts?.exclude ?? [])\n argv.push(\"--exclude\", pattern);\n argv.push(localPath, `${remote}:${remotePath}`);\n const result = await runSpawn(argv, { timeoutMs: 600_000 });\n if (result.exitCode !== 0) {\n throw new Error(\n `rsync upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`,\n );\n }\n return;\n }\n // scp fallback — no exclude, no delete. We still need -r to copy directories.\n const argv = [\n \"scp\",\n \"-r\",\n ...sshBaseFlags(options),\n localPath,\n `${remote}:${remotePath}`,\n ];\n const result = await runSpawn(argv, { timeoutMs: 600_000 });\n if (result.exitCode !== 0) {\n throw new Error(\n `scp upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`,\n );\n }\n },\n };\n};\n",
|
|
6
|
-
"/**\n * Shared \"cloud-provider Target\" plumbing used by the\n * provider-specific adapters (`./digitalocean`, `./hetzner`, future\n * `./linode`, `./vultr`, etc.).\n *\n * The provider supplies a small `CloudTargetHooks` bag that knows\n * the provider's:\n *\n * - find-by-name lookup\n * - create call (closure over create params)\n * - fetch-by-id (used to poll for `active`)\n * - destroy-by-id\n * - status + ipv4 + id extraction from the provider's Server shape\n * - readiness predicate (status reached the terminal \"running\" value)\n *\n * `createCloudTarget()` does the universal machinery: provision-or-\n * reuse, poll until ready + IPv4, wait for SSH probe, build\n * `sshTarget` against the IPv4, return the Target wrapped with\n * `{ id, ipv4, destroy() }`.\n *\n * The public adapter (e.g. `digitalOceanTarget`) is a 30-line facade\n * that wires its provider-specific bits and renames `id` → `dropletId`\n * on the way out.\n */\n\nimport type { Target } from
|
|
7
|
-
"/**\n * @absolutejs/deploy/hetzner — provision-or-reuse Target adapter for\n * Hetzner Cloud servers. Sibling to {@link digitalOceanTarget}; same\n * shape, different API.\n *\n * What it does:\n *\n * 1. Looks up a server by `name`. If present and running, reuses it.\n * 2. If not present, creates it via the Hetzner Cloud v1 API and\n * waits for `status === 'running'` with a public IPv4 assigned.\n * 3. Waits for SSH readiness (TCP connect on port 22 with backoff,\n * or a caller-supplied probe).\n * 4. Returns a Target that wraps sshTarget against the server's\n * public IPv4, plus `serverId`, `ipv4`, and a `destroy()` helper.\n *\n * Idempotent by name — Hetzner enforces unique server names per\n * project, so calling twice with the same name returns the same\n * server.\n *\n * Narrow HetznerClientLike interface keeps the official `hcloud-js`\n * SDK out as a hard dep. Default client uses `fetch` against\n * `api.hetzner.cloud/v1`; pass your own for retry / observability.\n */\n\nimport type { Target } from \"./targets\";\nimport { createCloudTarget, type CloudTargetHooks } from \"./cloudTarget\";\n\nconst HETZNER_API_BASE = \"https://api.hetzner.cloud/v1\";\n\n/**\n * Minimal subset of Hetzner Cloud API calls we make. Lets callers\n * BYO a client with retry / observability / etc.\n */\nexport type HetznerClientLike = {\n request: <T = unknown>(\n method: \"GET\" | \"POST\" | \"DELETE\",\n path: string,\n body?: unknown,\n ) => Promise<T>;\n};\n\n/** A Hetzner Cloud server, narrowed to what we inspect. */\nexport type HetznerServer = {\n id: number;\n name: string;\n status:\n | \"initializing\"\n | \"starting\"\n | \"running\"\n | \"stopping\"\n | \"off\"\n | \"deleting\"\n | \"migrating\"\n | \"rebuilding\"\n | \"unknown\";\n public_net: {\n ipv4: { id: number; ip: string; blocked: boolean; dns_ptr?: string } | null;\n ipv6: { id: number; ip: string; blocked: boolean } | null;\n };\n server_type?: { name: string };\n datacenter?: { location: { name: string } };\n labels?: Record<string, string>;\n private_net?: Array<{ ip: string; network: number }>;\n};\n\nexport type HetznerTargetOptions = {\n /** API token (https://docs.hetzner.cloud/#authentication). Required unless `client` is set. */\n token?: string;\n /** Custom client. Overrides token-built default. */\n client?: HetznerClientLike;\n\n // ── Server shape ─────────────────────────────────────────────────\n /** Server name. Hetzner-unique per project; also our idempotency key. */\n name: string;\n /** Location slug — `'nbg1'`, `'fsn1'`, `'hel1'`, `'ash'`, `'hil'`. */\n location: string;\n /** Server type slug — `'cx22'`, `'cpx11'`, `'ccx13'`, etc. */\n serverType: string;\n /** Image slug or numeric id, e.g. `'ubuntu-22.04'`. */\n image: string | number;\n /** SSH key fingerprints, numeric ids, or names. At least one required. */\n sshKeys: ReadonlyArray<string | number>;\n /** Labels (Hetzner's key-value tags). */\n labels?: Record<string, string>;\n /** cloud-init user data — a shell script or YAML config. */\n userData?: string;\n /** Attach to a Cloud Network (by id). */\n networkId?: number;\n /** Disable IPv4 public addressing. Default: enabled. */\n disablePublicIpv4?: boolean;\n /** Disable IPv6 public addressing. Default: enabled. */\n disablePublicIpv6?: boolean;\n\n // ── SSH wrap ────────────────────────────────────────────────────\n /** SSH login user. Default `'root'`. */\n user?: string;\n /** Path to SSH identity file forwarded to sshTarget. */\n identity?: string;\n /** SSH port. Default 22. */\n port?: number;\n\n // ── Timing ──────────────────────────────────────────────────────\n /** Max time to wait for server `running` + IPv4. Default 5 min. */\n provisionTimeoutMs?: number;\n /** Max time to wait for SSH probe to succeed. Default 2 min. */\n sshReadinessTimeoutMs?: number;\n /** Poll interval for provision + ssh probe. Default 5 s. */\n pollIntervalMs?: number;\n\n // ── Observability + injection points ───────────────────────────\n /** Called with status updates (one line each). Default: noop. */\n onLog?: (line: string) => void;\n /**\n * Override the SSH readiness probe. Default opens a TCP socket to\n * `host:port`. Tests pass a fake probe to skip real network IO.\n */\n probeSsh?: (host: string, port: number) => Promise<boolean>;\n /** Sleep used between polls. Tests can pass a synchronous resolver. */\n sleep?: (ms: number) => Promise<void>;\n /** Wall clock. Defaults to `Date.now`. Tests can swap. */\n now?: () => number;\n};\n\nexport type HetznerTarget = Target & {\n readonly serverId: number;\n readonly ipv4: string;\n /** Destroy the server via the Hetzner API. */\n destroy: () => Promise<void>;\n};\n\nexport class HetznerError extends Error {\n readonly status: number;\n readonly body: unknown;\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = \"HetznerError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/**\n * fetch-backed default client. Talks JSON to `api.hetzner.cloud/v1`.\n * Throws HetznerError on non-2xx with the response body attached so\n * the caller can switch on `err.status`.\n */\nexport const createHetznerClient = (\n token: string,\n options: { baseUrl?: string; fetch?: typeof fetch } = {},\n): HetznerClientLike => {\n const base = options.baseUrl ?? HETZNER_API_BASE;\n const f = options.fetch ?? fetch;\n return {\n request: async <T>(\n method: \"GET\" | \"POST\" | \"DELETE\",\n path: string,\n body?: unknown,\n ): Promise<T> => {\n const init: RequestInit = {\n headers: {\n authorization: `Bearer ${token}`,\n \"content-type\": \"application/json\",\n },\n method,\n };\n if (body !== undefined) init.body = JSON.stringify(body);\n const response = await f(`${base}${path}`, init);\n if (response.status === 204) return undefined as T;\n const text = await response.text();\n const parsed = text.length > 0 ? JSON.parse(text) : undefined;\n if (!response.ok) {\n throw new HetznerError(\n `Hetzner Cloud API ${method} ${path} failed: ${response.status} ${response.statusText}`,\n response.status,\n parsed,\n );\n }\n return parsed as T;\n },\n };\n};\n\nconst resolveClient = (\n options: Pick<HetznerTargetOptions, \"client\" | \"token\">,\n): HetznerClientLike => {\n if (options.client !== undefined) return options.client;\n if (options.token !== undefined && options.token.length > 0) {\n return createHetznerClient(options.token);\n }\n throw new Error(\n \"[deploy/hetzner] either `token` or `client` must be provided\",\n );\n};\n\nconst publicIpv4 = (server: HetznerServer): string | undefined =>\n server.public_net.ipv4?.ip;\n\n/**\n * Find a server by name. Returns undefined if absent. Hetzner\n * enforces unique server names per project, so duplicates aren't\n * possible — but if the API ever returns >1 we still surface that\n * loudly.\n */\nexport const findHetznerServer = async (\n client: HetznerClientLike,\n name: string,\n): Promise<HetznerServer | undefined> => {\n const body = await client.request<{ servers: HetznerServer[] }>(\n \"GET\",\n `/servers?name=${encodeURIComponent(name)}`,\n );\n const matches = body.servers.filter((server) => server.name === name);\n if (matches.length === 0) return undefined;\n if (matches.length > 1) {\n throw new Error(\n `[deploy/hetzner] multiple servers named \"${name}\" (${matches\n .map((server) => server.id)\n .join(\", \")}). Hetzner shouldn't allow this — resolve manually.`,\n );\n }\n return matches[0];\n};\n\n/** List servers, optionally filtered by label selector. */\nexport const listHetznerServers = async (options: {\n token?: string;\n client?: HetznerClientLike;\n /** Label selector, e.g. `'env=prod'` or `'env in (prod,staging)'`. */\n labelSelector?: string;\n}): Promise<HetznerServer[]> => {\n const client = resolveClient(options);\n const path =\n options.labelSelector !== undefined\n ? `/servers?label_selector=${encodeURIComponent(options.labelSelector)}`\n : \"/servers\";\n const body = await client.request<{ servers: HetznerServer[] }>(\"GET\", path);\n return body.servers;\n};\n\n/** Destroy a server by id. 404 treated as idempotent success. */\nexport const destroyHetznerServer = async (options: {\n token?: string;\n client?: HetznerClientLike;\n id: number;\n}): Promise<void> => {\n const client = resolveClient(options);\n try {\n await client.request(\"DELETE\", `/servers/${options.id}`);\n } catch (error) {\n if (error instanceof HetznerError && error.status === 404) {\n return; // already destroyed — idempotent\n }\n throw error;\n }\n};\n\n/**\n * Provision-or-reuse a Hetzner Cloud server by name, wait for SSH,\n * return a Target. Idempotent: same name → same server.\n */\nexport const hetznerTarget = async (\n options: HetznerTargetOptions,\n): Promise<HetznerTarget> => {\n const client = resolveClient(options);\n const publicIpv4Enabled = options.disablePublicIpv4 !== true;\n const publicIpv6Enabled = options.disablePublicIpv6 !== true;\n\n const hooks: CloudTargetHooks<HetznerServer> = {\n create: async () => {\n const created = await client.request<{ server: HetznerServer }>(\n \"POST\",\n \"/servers\",\n {\n name: options.name,\n location: options.location,\n server_type: options.serverType,\n image: options.image,\n ssh_keys: [...options.sshKeys],\n start_after_create: true,\n public_net: {\n enable_ipv4: publicIpv4Enabled,\n enable_ipv6: publicIpv6Enabled,\n },\n ...(options.labels !== undefined ? { labels: options.labels } : {}),\n ...(options.userData !== undefined\n ? { user_data: options.userData }\n : {}),\n ...(options.networkId !== undefined\n ? { networks: [options.networkId] }\n : {}),\n },\n );\n return created.server;\n },\n destroy: (id) => destroyHetznerServer({ client, id }),\n fetch: async (id) => {\n const refreshed: { server: HetznerServer } = await client.request(\n \"GET\",\n `/servers/${id}`,\n );\n return refreshed.server;\n },\n findByName: (name) => findHetznerServer(client, name),\n getId: (server) => server.id,\n getIpv4: publicIpv4,\n getStatus: (server) => server.status,\n isReady: (server) => server.status === \"running\",\n };\n\n const result = await createCloudTarget(hooks, {\n describeTarget: (sshDescription) =>\n `hetzner server \"${options.name}\" (${sshDescription})`,\n entityWord: \"server\",\n logPrefix: \"[hetzner]\",\n name: options.name,\n region: options.location,\n ...(options.user !== undefined ? { user: options.user } : {}),\n ...(options.identity !== undefined ? { identity: options.identity } : {}),\n ...(options.port !== undefined ? { port: options.port } : {}),\n ...(options.provisionTimeoutMs !== undefined\n ? { provisionTimeoutMs: options.provisionTimeoutMs }\n : {}),\n ...(options.sshReadinessTimeoutMs !== undefined\n ? { sshReadinessTimeoutMs: options.sshReadinessTimeoutMs }\n : {}),\n ...(options.pollIntervalMs !== undefined\n ? { pollIntervalMs: options.pollIntervalMs }\n : {}),\n ...(options.onLog !== undefined ? { onLog: options.onLog } : {}),\n ...(options.probeSsh !== undefined ? { probeSsh: options.probeSsh } : {}),\n ...(options.sleep !== undefined ? { sleep: options.sleep } : {}),\n ...(options.now !== undefined ? { now: options.now } : {}),\n });\n\n return {\n description: result.description,\n destroy: result.destroy,\n exec: result.exec,\n ipv4: result.ipv4,\n serverId: result.id,\n upload: result.upload,\n ...(result.close !== undefined ? { close: result.close } : {}),\n };\n};\n",
|
|
8
|
-
"import type { InfrastructureNode } from \"./infrastructure\";\n\nexport type InfrastructureAgentOptions = {\n audience?: string;\n port?: number;\n preferPrivateNetwork?: boolean;\n protocol?: \"http\" | \"https\";\n};\n\nexport const infrastructureAgent = (\n options: InfrastructureAgentOptions | undefined,\n addresses: Pick<InfrastructureNode, \"privateIpv4\" | \"publicIpv4\">,\n) => {\n if (!options) return undefined;\n const host = options.preferPrivateNetwork\n ? (addresses.privateIpv4 ?? addresses.publicIpv4)\n : (addresses.publicIpv4 ?? addresses.privateIpv4);\n if (!host) return undefined;\n\n return {\n url: `${options.protocol ?? \"http\"}://${host}:${options.port ?? 8081}/`,\n ...(options.audience ? { audience: options.audience } : {}),\n };\n};\n\nexport const leastPopulatedRegion = <Region extends { region: string }>(\n regions: readonly Region[],\n observed: readonly string[],\n requested?: string,\n) => {\n const eligible = requested\n ? regions.filter((region) => region.region === requested)\n : [...regions];\n if (eligible.length === 0) return undefined;\n const counts = new Map(eligible.map((region) => [region.region, 0]));\n for (const region of observed) {\n if (counts.has(region)) counts.set(region, (counts.get(region) ?? 0) + 1);\n }\n const selected = [...counts].sort(\n (left, right)
|
|
9
|
-
"import {\n createHetznerClient,\n destroyHetznerServer,\n findHetznerServer,\n listHetznerServers,\n type HetznerClientLike,\n type HetznerServer,\n} from \"./hetzner\";\nimport {\n infrastructureAgent,\n leastPopulatedRegion,\n type InfrastructureAgentOptions,\n} from \"./infrastructureAdapter\";\nimport type {\n InfrastructureNode,\n InfrastructureNodeState,\n InfrastructureProvider,\n} from \"./infrastructure\";\n\nexport type HetznerFleetRegion = {\n image: string | number;\n networkId?: number;\n region: string;\n serverType: string;\n sshKeys: ReadonlyArray<string | number>;\n userData?: string;\n};\n\nexport type HetznerInfrastructureProviderOptions = {\n agent?: InfrastructureAgentOptions;\n client?: HetznerClientLike;\n labelKey?: string;\n labelValue?: string;\n regions: readonly HetznerFleetRegion[];\n token?: string;\n};\n\nconst stateFor = (status: HetznerServer[\"status\"]): InfrastructureNodeState => {\n if (status === \"running\") return \"ready\";\n if ([\"initializing\", \"starting\", \"migrating\", \"rebuilding\"].includes(status))\n return \"pending\";\n\n return \"terminated\";\n};\n\nconst parseNodeId = (id: string) => {\n const match = /^hetzner:([1-9][0-9]*)$/.exec(id);\n if (!match?.[1])\n throw new Error(\"[deploy/hetzner] invalid infrastructure node id\");\n\n return Number(match[1]);\n};\n\nexport const createHetznerInfrastructureProvider = (\n options: HetznerInfrastructureProviderOptions,\n): InfrastructureProvider => {\n if (options.regions.length === 0)\n throw new Error(\"[deploy/hetzner] at least one fleet region is required\");\n const client =\n options.client ??\n (options.token ? createHetznerClient(options.token) : undefined);\n if (!client)\n throw new Error(\n \"[deploy/hetzner] either `token` or `client` must be provided\",\n );\n const labelKey = options.labelKey ?? \"absolutejs-role\";\n const labelValue = options.labelValue ?? \"absolutejs-paas-node\";\n\n const normalize = (server: HetznerServer): InfrastructureNode => {\n const publicIpv4 = server.public_net.ipv4?.ip;\n const privateIpv4 = server.private_net?.[0]?.ip;\n const agent = infrastructureAgent(options.agent, {\n privateIpv4,\n publicIpv4,\n });\n\n return {\n id: `hetzner:${server.id}`,\n label: server.name,\n provider: \"hetzner\",\n region: server.datacenter?.location.name ?? \"unknown\",\n state: stateFor(server.status),\n ...(publicIpv4 ? { publicIpv4 } : {}),\n ...(privateIpv4 ? { privateIpv4 } : {}),\n ...(agent ? { agent } : {}),\n };\n };\n const list = () =>\n listHetznerServers({\n client,\n labelSelector: `${labelKey}=${labelValue}`,\n });\n\n return {\n capabilities: {\n cloudInit: true,\n idempotentProvisioning: true,\n privateNetworking: true,\n regionalPlacement: true,\n regions: options.regions.map(({ region }) => region),\n },\n getNode: async (id) => {\n const result = await client.request<{ server: HetznerServer }>(\n \"GET\",\n `/servers/${parseNodeId(id)}`,\n );\n\n return normalize(result.server);\n },\n listNodes: async () => (await list()).map(normalize),\n name: \"hetzner\",\n provisionNode: async (input) => {\n const existing = await findHetznerServer(client, input.name);\n if (existing) return normalize(existing);\n const servers = await list();\n const region = leastPopulatedRegion(\n options.regions,\n servers.map((server) => server.datacenter?.location.name ?? \"unknown\"),\n input.region,\n );\n if (!region)\n throw new Error(\n `[deploy/hetzner] region ${input.region ?? \"(any)\"} is not configured`,\n );\n const result = await client.request<{ server: HetznerServer }>(\n \"POST\",\n \"/servers\",\n {\n image: region.image,\n labels: { [labelKey]: labelValue },\n location: region.region,\n name: input.name,\n public_net: { enable_ipv4: true, enable_ipv6: true },\n server_type: region.serverType,\n ssh_keys: [...region.sshKeys],\n start_after_create: true,\n ...(region.networkId ? { networks: [region.networkId] } : {}),\n ...(
|
|
5
|
+
"/**\n * Target interface + bundled adapters (localTarget, sshTarget).\n *\n * A Target is the narrowest abstraction over \"a place I can deploy to\":\n *\n * - `exec(cmd, opts?)` — run a shell command, capture stdout/stderr/exitCode.\n * - `upload(localPath, remotePath, opts?)` — copy a local file or directory\n * to the target. Implementation is free to use whatever is fast (rsync,\n * scp, mv).\n * - `close?()` — optional teardown.\n *\n * Two adapters are bundled:\n *\n * - `localTarget` runs in a temp directory on the local filesystem. Useful\n * for tests and for \"deploy\" workflows that happen on the same host.\n * - `sshTarget` shells out to the system `ssh` and `rsync` binaries. No\n * `ssh2` npm dependency — the controller machine just needs `ssh` and\n * (optionally) `rsync` in PATH, which is universal on Mac/Linux/WSL.\n *\n * Provider-specific targets (Cloudflare Workers HTTP API, Fly Machines API,\n * AWS Fargate) don't fit \"exec + upload\" and ship as siblings later.\n */\n\nimport { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport type ExecOptions = {\n\t/** Working directory on the target. Default: target's root. */\n\tcwd?: string;\n\t/** Env vars to set for this command (merged onto target.env). */\n\tenv?: Record<string, string>;\n\t/** Hard kill after this many ms. Default 600_000 (10 min). 0 disables. */\n\ttimeoutMs?: number;\n\t/** Pipe stdout/stderr through here as it streams (lines, newline-stripped). */\n\tonLog?: (line: string, stream: 'stdout' | 'stderr') => void;\n\t/** Stdin payload — a string is written verbatim. */\n\tstdin?: string;\n};\n\nexport type ExecResult = {\n\tstdout: string;\n\tstderr: string;\n\texitCode: number;\n};\n\nexport type UploadOptions = {\n\t/** Exclude paths matching these globs from a directory upload. */\n\texclude?: string[];\n\t/** When uploading a directory, delete remote files not present locally. */\n\tdeleteOrphans?: boolean;\n};\n\nexport type Target = {\n\t/** Human-readable description (e.g. \"ssh root@droplet-1.example.com\"). */\n\treadonly description: string;\n\texec: (cmd: string, opts?: ExecOptions) => Promise<ExecResult>;\n\tupload: (localPath: string, remotePath: string, opts?: UploadOptions) => Promise<void>;\n\tclose?: () => Promise<void>;\n};\n\n// -----------------------------------------------------------------------------\n// localTarget\n// -----------------------------------------------------------------------------\n\nexport type LocalTargetOptions = {\n\t/** Root directory the target operates in. Created if missing. */\n\troot: string;\n\t/** Env merged into every exec. */\n\tenv?: Record<string, string>;\n};\n\nconst decodeChunks = async (\n\treader: ReadableStream<Uint8Array> | null,\n\tonLine: ((line: string) => void) | undefined,\n): Promise<string> => {\n\tif (!reader) return '';\n\tconst decoder = new TextDecoder();\n\tlet buffer = '';\n\tlet collected = '';\n\tconst stream = reader.getReader();\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await stream.read();\n\t\t\tif (done) break;\n\t\t\tconst chunk = decoder.decode(value, { stream: true });\n\t\t\tcollected += chunk;\n\t\t\tif (!onLine) continue;\n\t\t\tbuffer += chunk;\n\t\t\tlet newline = buffer.indexOf('\\n');\n\t\t\twhile (newline !== -1) {\n\t\t\t\tconst line = buffer.slice(0, newline).replace(/\\r$/, '');\n\t\t\t\tif (line.length > 0) onLine(line);\n\t\t\t\tbuffer = buffer.slice(newline + 1);\n\t\t\t\tnewline = buffer.indexOf('\\n');\n\t\t\t}\n\t\t}\n\t\tconst tail = decoder.decode();\n\t\tcollected += tail;\n\t\tif (onLine && (buffer + tail).length > 0) onLine((buffer + tail).replace(/\\r$/, ''));\n\t} finally {\n\t\tstream.releaseLock();\n\t}\n\treturn collected;\n};\n\nconst runSpawn = async (\n\targv: string[],\n\toptions: {\n\t\tcwd?: string;\n\t\tenv?: Record<string, string>;\n\t\ttimeoutMs?: number;\n\t\tonLog?: ExecOptions['onLog'];\n\t\tstdin?: string;\n\t},\n): Promise<ExecResult> => {\n\tconst proc = Bun.spawn(argv, {\n\t\tcwd: options.cwd,\n\t\tenv: options.env,\n\t\tstderr: 'pipe',\n\t\tstdin: options.stdin === undefined ? 'ignore' : 'pipe',\n\t\tstdout: 'pipe',\n\t});\n\n\tif (options.stdin !== undefined && proc.stdin) {\n\t\t// Bun.spawn returns a FileSink for piped stdin — `write` + `end`, not a\n\t\t// WritableStream. (We use a permissive cast because @types/bun's\n\t\t// Subprocess.stdin discriminant flips based on the stdin generic.)\n\t\tconst sink = proc.stdin as unknown as {\n\t\t\twrite: (chunk: string | Uint8Array) => number | Promise<number>;\n\t\t\tend: () => void | Promise<void>;\n\t\t};\n\t\tconst wrote = sink.write(options.stdin);\n\t\tif (wrote && typeof (wrote as Promise<number>).then === 'function') {\n\t\t\tawait wrote;\n\t\t}\n\t\tconst ended = sink.end();\n\t\tif (ended && typeof (ended as Promise<void>).then === 'function') {\n\t\t\tawait ended;\n\t\t}\n\t}\n\n\tconst timeout = options.timeoutMs ?? 600_000;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tif (timeout > 0) {\n\t\ttimer = setTimeout(() => {\n\t\t\ttry { proc.kill(); } catch { /* already gone */ }\n\t\t}, timeout);\n\t}\n\n\tconst stdoutPromise = decodeChunks(\n\t\tproc.stdout as unknown as ReadableStream<Uint8Array>,\n\t\toptions.onLog ? (line) => options.onLog!(line, 'stdout') : undefined,\n\t);\n\tconst stderrPromise = decodeChunks(\n\t\tproc.stderr as unknown as ReadableStream<Uint8Array>,\n\t\toptions.onLog ? (line) => options.onLog!(line, 'stderr') : undefined,\n\t);\n\n\tconst [stdout, stderr, exitCode] = await Promise.all([\n\t\tstdoutPromise,\n\t\tstderrPromise,\n\t\tproc.exited,\n\t]);\n\tif (timer) clearTimeout(timer);\n\n\treturn { exitCode: exitCode ?? -1, stderr, stdout };\n};\n\nexport const localTarget = (options: LocalTargetOptions): Target => {\n\tconst baseEnv = { ...options.env };\n\tconst ensureRoot = async () => { await mkdir(options.root, { recursive: true }); };\n\n\treturn {\n\t\tdescription: `local ${options.root}`,\n\t\texec: async (cmd, opts) => {\n\t\t\tawait ensureRoot();\n\t\t\treturn runSpawn(['sh', '-c', cmd], {\n\t\t\t\tcwd: opts?.cwd ?? options.root,\n\t\t\t\tenv: { ...process.env, ...baseEnv, ...(opts?.env ?? {}) } as Record<string, string>,\n\t\t\t\tonLog: opts?.onLog,\n\t\t\t\tstdin: opts?.stdin,\n\t\t\t\ttimeoutMs: opts?.timeoutMs,\n\t\t\t});\n\t\t},\n\t\tupload: async (localPath, remotePath, opts) => {\n\t\t\tawait ensureRoot();\n\t\t\tconst dest = remotePath.startsWith('/') ? remotePath : join(options.root, remotePath);\n\t\t\tconst argv = ['rsync', '-a'];\n\t\t\tif (opts?.deleteOrphans) argv.push('--delete');\n\t\t\tfor (const pattern of opts?.exclude ?? []) argv.push('--exclude', pattern);\n\t\t\t// rsync semantics: a trailing slash on the source copies *contents*; without it the dir itself is nested.\n\t\t\targv.push(localPath, dest);\n\t\t\tconst result = await runSpawn(argv, { timeoutMs: 600_000 });\n\t\t\tif (result.exitCode !== 0) {\n\t\t\t\tthrow new Error(`local upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);\n\t\t\t}\n\t\t},\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// sshTarget\n// -----------------------------------------------------------------------------\n\nexport type SshTargetOptions = {\n\t/** Hostname or IP of the remote. */\n\thost: string;\n\t/** Login user. Default `root`. */\n\tuser?: string;\n\t/** SSH port. Default 22. */\n\tport?: number;\n\t/** Path to SSH identity file. Default: ssh's own search. */\n\tidentity?: string;\n\t/** Extra flags appended to every `ssh` invocation. */\n\tsshFlags?: string[];\n\t/**\n\t * Use rsync for `upload`. Default true. When false, falls back to `scp`\n\t * which is universal but doesn't support delete / exclude.\n\t */\n\trsync?: boolean;\n\t/**\n\t * Env vars to forward via `ssh -o SendEnv=...`. Most remote sshd configs\n\t * accept only `LANG` and `LC_*` by default; for app env vars use the\n\t * step `env` option instead, which prepends `KEY=value` to the command.\n\t */\n\tforwardEnv?: string[];\n};\n\nconst sshTargetString = (options: SshTargetOptions): string => {\n\tconst user = options.user ?? 'root';\n\treturn `${user}@${options.host}`;\n};\n\nconst sshBaseFlags = (options: SshTargetOptions): string[] => {\n\tconst flags: string[] = [];\n\tif (options.port !== undefined && options.port !== 22) flags.push('-p', String(options.port));\n\tif (options.identity !== undefined) flags.push('-i', options.identity);\n\t// Never get stuck on a host-key prompt; treat unknown hosts as a fatal config issue rather than a UX detour.\n\tflags.push('-o', 'BatchMode=yes', '-o', 'StrictHostKeyChecking=accept-new');\n\tfor (const flag of options.sshFlags ?? []) flags.push(flag);\n\treturn flags;\n};\n\nconst shellQuote = (value: string): string => `'${value.replace(/'/g, `'\\\\''`)}'`;\n\nconst buildRemoteCmd = (cmd: string, opts: ExecOptions | undefined): string => {\n\tconst env = opts?.env;\n\tconst envPrefix = env\n\t\t? Object.entries(env).map(([k, v]) => `${k}=${shellQuote(v)}`).join(' ') + ' '\n\t\t: '';\n\tif (opts?.cwd) {\n\t\treturn `cd ${shellQuote(opts.cwd)} && ${envPrefix}${cmd}`;\n\t}\n\treturn `${envPrefix}${cmd}`;\n};\n\nexport const sshTarget = (options: SshTargetOptions): Target => {\n\tconst remote = sshTargetString(options);\n\tconst useRsync = options.rsync ?? true;\n\n\treturn {\n\t\tdescription: `ssh ${remote}${options.port && options.port !== 22 ? `:${options.port}` : ''}`,\n\t\texec: async (cmd, opts) => {\n\t\t\tconst argv = ['ssh', ...sshBaseFlags(options)];\n\t\t\tfor (const name of options.forwardEnv ?? []) argv.push('-o', `SendEnv=${name}`);\n\t\t\targv.push(remote, buildRemoteCmd(cmd, opts));\n\t\t\treturn runSpawn(argv, {\n\t\t\t\tonLog: opts?.onLog,\n\t\t\t\tstdin: opts?.stdin,\n\t\t\t\ttimeoutMs: opts?.timeoutMs,\n\t\t\t});\n\t\t},\n\t\tupload: async (localPath, remotePath, opts) => {\n\t\t\tif (useRsync) {\n\t\t\t\tconst sshCmd = ['ssh', ...sshBaseFlags(options)].map((part) => part.includes(' ') ? `'${part}'` : part).join(' ');\n\t\t\t\tconst argv = ['rsync', '-az', '-e', sshCmd];\n\t\t\t\tif (opts?.deleteOrphans) argv.push('--delete');\n\t\t\t\tfor (const pattern of opts?.exclude ?? []) argv.push('--exclude', pattern);\n\t\t\t\targv.push(localPath, `${remote}:${remotePath}`);\n\t\t\t\tconst result = await runSpawn(argv, { timeoutMs: 600_000 });\n\t\t\t\tif (result.exitCode !== 0) {\n\t\t\t\t\tthrow new Error(`rsync upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// scp fallback — no exclude, no delete. We still need -r to copy directories.\n\t\t\tconst argv = ['scp', '-r', ...sshBaseFlags(options), localPath, `${remote}:${remotePath}`];\n\t\t\tconst result = await runSpawn(argv, { timeoutMs: 600_000 });\n\t\t\tif (result.exitCode !== 0) {\n\t\t\t\tthrow new Error(`scp upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);\n\t\t\t}\n\t\t},\n\t};\n};\n",
|
|
6
|
+
"/**\n * Shared \"cloud-provider Target\" plumbing used by the\n * provider-specific adapters (`./digitalocean`, `./hetzner`, future\n * `./linode`, `./vultr`, etc.).\n *\n * The provider supplies a small `CloudTargetHooks` bag that knows\n * the provider's:\n *\n * - find-by-name lookup\n * - create call (closure over create params)\n * - fetch-by-id (used to poll for `active`)\n * - destroy-by-id\n * - status + ipv4 + id extraction from the provider's Server shape\n * - readiness predicate (status reached the terminal \"running\" value)\n *\n * `createCloudTarget()` does the universal machinery: provision-or-\n * reuse, poll until ready + IPv4, wait for SSH probe, build\n * `sshTarget` against the IPv4, return the Target wrapped with\n * `{ id, ipv4, destroy() }`.\n *\n * The public adapter (e.g. `digitalOceanTarget`) is a 30-line facade\n * that wires its provider-specific bits and renames `id` → `dropletId`\n * on the way out.\n */\n\nimport type { Target } from './targets';\nimport { sshTarget } from './targets';\n\n/** Provider-specific hooks. Keep these pure of network IO timing — the helper schedules. */\nexport type CloudTargetHooks<Server, Id = number> = {\n\t/** Find a server by name. Returns undefined if absent. */\n\tfindByName: (name: string) => Promise<Server | undefined>;\n\t/** Create the server. Closure over provider-specific create params. */\n\tcreate: () => Promise<Server>;\n\t/** Fetch a fresh copy of the server by id. Used to poll. */\n\tfetch: (id: Id) => Promise<Server>;\n\t/** Destroy a server by id. 404 should be treated as idempotent success. */\n\tdestroy: (id: Id) => Promise<void>;\n\t/** True when the server has reached its terminal \"running\" status. */\n\tisReady: (server: Server) => boolean;\n\t/** Extract the provider-assigned id (number for DO/Hetzner/Linode, string for Vultr). */\n\tgetId: (server: Server) => Id;\n\t/** Extract the public IPv4. Returns undefined while one is being assigned. */\n\tgetIpv4: (server: Server) => string | undefined;\n\t/** Extract the current status as a string (for log lines). */\n\tgetStatus: (server: Server) => string;\n};\n\nexport type CloudTargetOptions = {\n\t/** Provider's idempotency key (server name). */\n\tname: string;\n\t/** Region / location label — used in the \"creating\" log line. */\n\tregion: string;\n\n\t/** SSH login user. Default `'root'`. */\n\tuser?: string;\n\t/** SSH identity file. */\n\tidentity?: string;\n\t/** SSH port. Default 22. */\n\tport?: number;\n\n\t/** Default 5 min. */\n\tprovisionTimeoutMs?: number;\n\t/** Default 2 min. */\n\tsshReadinessTimeoutMs?: number;\n\t/** Default 5 s. */\n\tpollIntervalMs?: number;\n\n\t/** Called with status updates. */\n\tonLog?: (line: string) => void;\n\t/** Override SSH probe — tests skip real TCP IO. */\n\tprobeSsh?: (host: string, port: number) => Promise<boolean>;\n\t/** Override sleep — tests skip real waits. */\n\tsleep?: (ms: number) => Promise<void>;\n\t/** Override clock — tests inject deterministic timestamps. */\n\tnow?: () => number;\n\n\t/**\n\t * Short log prefix, e.g. `'[do]'` or `'[hetzner]'`. Threaded through\n\t * every log line so multi-provider deploys distinguish output.\n\t */\n\tlogPrefix: string;\n\t/**\n\t * Provider's word for the entity in log copy — `'droplet'` for DO,\n\t * `'server'` for Hetzner. Preserves provider-accurate output.\n\t */\n\tentityWord: string;\n\t/**\n\t * Build the Target's `description` field. Receives the resolved\n\t * IPv4 + the wrapped sshTarget description.\n\t */\n\tdescribeTarget: (sshDescription: string) => string;\n};\n\nexport type CloudTargetResult<Id = number> = {\n\tid: Id;\n\tipv4: string;\n\tdescription: string;\n\texec: Target['exec'];\n\tupload: Target['upload'];\n\tclose?: Target['close'];\n\tdestroy: () => Promise<void>;\n};\n\nconst defaultSleep = (ms: number): Promise<void> =>\n\tnew Promise((resolve) => setTimeout(resolve, ms));\n\nconst defaultProbeSsh = async (host: string, port: number): Promise<boolean> => {\n\tconst PROBE_TIMEOUT_MS = 2_000;\n\treturn new Promise<boolean>((resolve) => {\n\t\tlet settled = false;\n\t\tconst settle = (value: boolean) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tresolve(value);\n\t\t};\n\t\tconst timer = setTimeout(() => settle(false), PROBE_TIMEOUT_MS);\n\t\tBun.connect({\n\t\t\thostname: host,\n\t\t\tport,\n\t\t\tsocket: {\n\t\t\t\tdata: () => {},\n\t\t\t\terror: () => {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tsettle(false);\n\t\t\t\t},\n\t\t\t\topen: (socket) => {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tsocket.end();\n\t\t\t\t\tsettle(true);\n\t\t\t\t}\n\t\t\t}\n\t\t}).catch(() => {\n\t\t\tclearTimeout(timer);\n\t\t\tsettle(false);\n\t\t});\n\t});\n};\n\n/**\n * The shared provision-or-reuse + wait-for-ready + wait-for-SSH\n * pipeline. Provider-specific adapters wire their `CloudTargetHooks`\n * + their option-shape mapping and return a typed result.\n */\nexport const createCloudTarget = async <Server, Id = number>(\n\thooks: CloudTargetHooks<Server, Id>,\n\toptions: CloudTargetOptions\n): Promise<CloudTargetResult<Id>> => {\n\tconst log = options.onLog ?? (() => {});\n\tconst probeSsh = options.probeSsh ?? defaultProbeSsh;\n\tconst sleep = options.sleep ?? defaultSleep;\n\tconst now = options.now ?? Date.now;\n\tconst pollMs = options.pollIntervalMs ?? 5_000;\n\tconst provisionTimeout = options.provisionTimeoutMs ?? 5 * 60_000;\n\tconst sshTimeout = options.sshReadinessTimeoutMs ?? 2 * 60_000;\n\tconst port = options.port ?? 22;\n\tconst prefix = options.logPrefix;\n\tconst noun = options.entityWord;\n\n\tconst existing = await hooks.findByName(options.name);\n\tlet current: Server;\n\tif (existing === undefined) {\n\t\tlog(`${prefix} creating ${noun} \"${options.name}\" in ${options.region}`);\n\t\tcurrent = await hooks.create();\n\t} else {\n\t\tlog(\n\t\t\t`${prefix} reusing ${noun} \"${options.name}\" (id ${hooks.getId(existing)}, status ${hooks.getStatus(existing)})`\n\t\t);\n\t\tcurrent = existing;\n\t}\n\n\t// Wait for status=ready AND public IPv4 assigned.\n\tconst provisionStart = now();\n\tlet ipv4 = hooks.getIpv4(current);\n\twhile (!hooks.isReady(current) || ipv4 === undefined) {\n\t\tif (now() - provisionStart > provisionTimeout) {\n\t\t\tthrow new Error(\n\t\t\t\t`${prefix} provision timeout after ${provisionTimeout}ms — ${noun} ${hooks.getId(current)} status \"${hooks.getStatus(current)}\", ipv4 ${ipv4 ?? '(unassigned)'}`\n\t\t\t);\n\t\t}\n\t\tawait sleep(pollMs);\n\t\tcurrent = await hooks.fetch(hooks.getId(current));\n\t\tipv4 = hooks.getIpv4(current);\n\t\tlog(\n\t\t\t`${prefix} poll: status=${hooks.getStatus(current)} ipv4=${ipv4 ?? '(none yet)'}`\n\t\t);\n\t}\n\tlog(`${prefix} ${noun} ready at ${ipv4}`);\n\n\t// Wait for SSH readiness.\n\tconst sshStart = now();\n\twhile (!(await probeSsh(ipv4, port))) {\n\t\tif (now() - sshStart > sshTimeout) {\n\t\t\tthrow new Error(\n\t\t\t\t`${prefix} SSH readiness timeout after ${sshTimeout}ms — ${ipv4}:${port} did not accept connections`\n\t\t\t);\n\t\t}\n\t\tawait sleep(pollMs);\n\t\tlog(`${prefix} waiting on ssh ${ipv4}:${port}`);\n\t}\n\tlog(`${prefix} ssh ready at ${ipv4}:${port}`);\n\n\tconst ssh = sshTarget({\n\t\thost: ipv4,\n\t\t...(options.user !== undefined ? { user: options.user } : {}),\n\t\t...(options.identity !== undefined ? { identity: options.identity } : {}),\n\t\t...(options.port !== undefined ? { port: options.port } : {})\n\t});\n\n\tconst id = hooks.getId(current);\n\tconst resolvedIpv4 = ipv4;\n\n\treturn {\n\t\tdescription: options.describeTarget(ssh.description),\n\t\tdestroy: () =>\n\t\t\thooks.destroy(id).then(() => {\n\t\t\t\tlog(`${prefix} destroyed ${noun} ${id}`);\n\t\t\t}),\n\t\texec: ssh.exec,\n\t\tid,\n\t\tipv4: resolvedIpv4,\n\t\tupload: ssh.upload,\n\t\t...(ssh.close !== undefined ? { close: ssh.close } : {})\n\t};\n};\n",
|
|
7
|
+
"/**\n * @absolutejs/deploy/hetzner — provision-or-reuse Target adapter for\n * Hetzner Cloud servers. Sibling to {@link digitalOceanTarget}; same\n * shape, different API.\n *\n * What it does:\n *\n * 1. Looks up a server by `name`. If present and running, reuses it.\n * 2. If not present, creates it via the Hetzner Cloud v1 API and\n * waits for `status === 'running'` with a public IPv4 assigned.\n * 3. Waits for SSH readiness (TCP connect on port 22 with backoff,\n * or a caller-supplied probe).\n * 4. Returns a Target that wraps sshTarget against the server's\n * public IPv4, plus `serverId`, `ipv4`, and a `destroy()` helper.\n *\n * Idempotent by name — Hetzner enforces unique server names per\n * project, so calling twice with the same name returns the same\n * server.\n *\n * Narrow HetznerClientLike interface keeps the official `hcloud-js`\n * SDK out as a hard dep. Default client uses `fetch` against\n * `api.hetzner.cloud/v1`; pass your own for retry / observability.\n */\n\nimport type { Target } from './targets';\nimport { createCloudTarget, type CloudTargetHooks } from './cloudTarget';\n\nconst HETZNER_API_BASE = 'https://api.hetzner.cloud/v1';\n\n/**\n * Minimal subset of Hetzner Cloud API calls we make. Lets callers\n * BYO a client with retry / observability / etc.\n */\nexport type HetznerClientLike = {\n\trequest: <T = unknown>(\n\t\tmethod: 'GET' | 'POST' | 'DELETE',\n\t\tpath: string,\n\t\tbody?: unknown\n\t) => Promise<T>;\n};\n\n/** A Hetzner Cloud server, narrowed to what we inspect. */\nexport type HetznerServer = {\n\tid: number;\n\tname: string;\n\tstatus:\n\t\t| 'initializing'\n\t\t| 'starting'\n\t\t| 'running'\n\t\t| 'stopping'\n\t\t| 'off'\n\t\t| 'deleting'\n\t\t| 'migrating'\n\t\t| 'rebuilding'\n\t\t| 'unknown';\n\tpublic_net: {\n\t\tipv4: { id: number; ip: string; blocked: boolean; dns_ptr?: string } | null;\n\t\tipv6: { id: number; ip: string; blocked: boolean } | null;\n\t};\n\tserver_type?: { name: string };\n\tdatacenter?: { location: { name: string } };\n\tlabels?: Record<string, string>;\n\tprivate_net?: Array<{ ip: string; network: number }>;\n};\n\nexport type HetznerTargetOptions = {\n\t/** API token (https://docs.hetzner.cloud/#authentication). Required unless `client` is set. */\n\ttoken?: string;\n\t/** Custom client. Overrides token-built default. */\n\tclient?: HetznerClientLike;\n\n\t// ── Server shape ─────────────────────────────────────────────────\n\t/** Server name. Hetzner-unique per project; also our idempotency key. */\n\tname: string;\n\t/** Location slug — `'nbg1'`, `'fsn1'`, `'hel1'`, `'ash'`, `'hil'`. */\n\tlocation: string;\n\t/** Server type slug — `'cx22'`, `'cpx11'`, `'ccx13'`, etc. */\n\tserverType: string;\n\t/** Image slug or numeric id, e.g. `'ubuntu-22.04'`. */\n\timage: string | number;\n\t/** SSH key fingerprints, numeric ids, or names. At least one required. */\n\tsshKeys: ReadonlyArray<string | number>;\n\t/** Labels (Hetzner's key-value tags). */\n\tlabels?: Record<string, string>;\n\t/** cloud-init user data — a shell script or YAML config. */\n\tuserData?: string;\n\t/** Attach to a Cloud Network (by id). */\n\tnetworkId?: number;\n\t/** Disable IPv4 public addressing. Default: enabled. */\n\tdisablePublicIpv4?: boolean;\n\t/** Disable IPv6 public addressing. Default: enabled. */\n\tdisablePublicIpv6?: boolean;\n\n\t// ── SSH wrap ────────────────────────────────────────────────────\n\t/** SSH login user. Default `'root'`. */\n\tuser?: string;\n\t/** Path to SSH identity file forwarded to sshTarget. */\n\tidentity?: string;\n\t/** SSH port. Default 22. */\n\tport?: number;\n\n\t// ── Timing ──────────────────────────────────────────────────────\n\t/** Max time to wait for server `running` + IPv4. Default 5 min. */\n\tprovisionTimeoutMs?: number;\n\t/** Max time to wait for SSH probe to succeed. Default 2 min. */\n\tsshReadinessTimeoutMs?: number;\n\t/** Poll interval for provision + ssh probe. Default 5 s. */\n\tpollIntervalMs?: number;\n\n\t// ── Observability + injection points ───────────────────────────\n\t/** Called with status updates (one line each). Default: noop. */\n\tonLog?: (line: string) => void;\n\t/**\n\t * Override the SSH readiness probe. Default opens a TCP socket to\n\t * `host:port`. Tests pass a fake probe to skip real network IO.\n\t */\n\tprobeSsh?: (host: string, port: number) => Promise<boolean>;\n\t/** Sleep used between polls. Tests can pass a synchronous resolver. */\n\tsleep?: (ms: number) => Promise<void>;\n\t/** Wall clock. Defaults to `Date.now`. Tests can swap. */\n\tnow?: () => number;\n};\n\nexport type HetznerTarget = Target & {\n\treadonly serverId: number;\n\treadonly ipv4: string;\n\t/** Destroy the server via the Hetzner API. */\n\tdestroy: () => Promise<void>;\n};\n\nexport class HetznerError extends Error {\n\treadonly status: number;\n\treadonly body: unknown;\n\tconstructor(message: string, status: number, body: unknown) {\n\t\tsuper(message);\n\t\tthis.name = 'HetznerError';\n\t\tthis.status = status;\n\t\tthis.body = body;\n\t}\n}\n\n/**\n * fetch-backed default client. Talks JSON to `api.hetzner.cloud/v1`.\n * Throws HetznerError on non-2xx with the response body attached so\n * the caller can switch on `err.status`.\n */\nexport const createHetznerClient = (\n\ttoken: string,\n\toptions: { baseUrl?: string; fetch?: typeof fetch } = {}\n): HetznerClientLike => {\n\tconst base = options.baseUrl ?? HETZNER_API_BASE;\n\tconst f = options.fetch ?? fetch;\n\treturn {\n\t\trequest: async <T>(\n\t\t\tmethod: 'GET' | 'POST' | 'DELETE',\n\t\t\tpath: string,\n\t\t\tbody?: unknown\n\t\t): Promise<T> => {\n\t\t\tconst init: RequestInit = {\n\t\t\t\theaders: {\n\t\t\t\t\tauthorization: `Bearer ${token}`,\n\t\t\t\t\t'content-type': 'application/json'\n\t\t\t\t},\n\t\t\t\tmethod\n\t\t\t};\n\t\t\tif (body !== undefined) init.body = JSON.stringify(body);\n\t\t\tconst response = await f(`${base}${path}`, init);\n\t\t\tif (response.status === 204) return undefined as T;\n\t\t\tconst text = await response.text();\n\t\t\tconst parsed = text.length > 0 ? JSON.parse(text) : undefined;\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new HetznerError(\n\t\t\t\t\t`Hetzner Cloud API ${method} ${path} failed: ${response.status} ${response.statusText}`,\n\t\t\t\t\tresponse.status,\n\t\t\t\t\tparsed\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn parsed as T;\n\t\t}\n\t};\n};\n\nconst resolveClient = (\n\toptions: Pick<HetznerTargetOptions, 'client' | 'token'>\n): HetznerClientLike => {\n\tif (options.client !== undefined) return options.client;\n\tif (options.token !== undefined && options.token.length > 0) {\n\t\treturn createHetznerClient(options.token);\n\t}\n\tthrow new Error(\n\t\t'[deploy/hetzner] either `token` or `client` must be provided'\n\t);\n};\n\nconst publicIpv4 = (server: HetznerServer): string | undefined =>\n\tserver.public_net.ipv4?.ip;\n\n/**\n * Find a server by name. Returns undefined if absent. Hetzner\n * enforces unique server names per project, so duplicates aren't\n * possible — but if the API ever returns >1 we still surface that\n * loudly.\n */\nexport const findHetznerServer = async (\n\tclient: HetznerClientLike,\n\tname: string\n): Promise<HetznerServer | undefined> => {\n\tconst body = await client.request<{ servers: HetznerServer[] }>(\n\t\t'GET',\n\t\t`/servers?name=${encodeURIComponent(name)}`\n\t);\n\tconst matches = body.servers.filter((server) => server.name === name);\n\tif (matches.length === 0) return undefined;\n\tif (matches.length > 1) {\n\t\tthrow new Error(\n\t\t\t`[deploy/hetzner] multiple servers named \"${name}\" (${matches\n\t\t\t\t.map((server) => server.id)\n\t\t\t\t.join(', ')}). Hetzner shouldn't allow this — resolve manually.`\n\t\t);\n\t}\n\treturn matches[0];\n};\n\n/** List servers, optionally filtered by label selector. */\nexport const listHetznerServers = async (options: {\n\ttoken?: string;\n\tclient?: HetznerClientLike;\n\t/** Label selector, e.g. `'env=prod'` or `'env in (prod,staging)'`. */\n\tlabelSelector?: string;\n}): Promise<HetznerServer[]> => {\n\tconst client = resolveClient(options);\n\tconst path =\n\t\toptions.labelSelector !== undefined\n\t\t\t? `/servers?label_selector=${encodeURIComponent(options.labelSelector)}`\n\t\t\t: '/servers';\n\tconst body = await client.request<{ servers: HetznerServer[] }>('GET', path);\n\treturn body.servers;\n};\n\n/** Destroy a server by id. 404 treated as idempotent success. */\nexport const destroyHetznerServer = async (options: {\n\ttoken?: string;\n\tclient?: HetznerClientLike;\n\tid: number;\n}): Promise<void> => {\n\tconst client = resolveClient(options);\n\ttry {\n\t\tawait client.request('DELETE', `/servers/${options.id}`);\n\t} catch (error) {\n\t\tif (error instanceof HetznerError && error.status === 404) {\n\t\t\treturn; // already destroyed — idempotent\n\t\t}\n\t\tthrow error;\n\t}\n};\n\n/**\n * Provision-or-reuse a Hetzner Cloud server by name, wait for SSH,\n * return a Target. Idempotent: same name → same server.\n */\nexport const hetznerTarget = async (\n\toptions: HetznerTargetOptions\n): Promise<HetznerTarget> => {\n\tconst client = resolveClient(options);\n\tconst publicIpv4Enabled = options.disablePublicIpv4 !== true;\n\tconst publicIpv6Enabled = options.disablePublicIpv6 !== true;\n\n\tconst hooks: CloudTargetHooks<HetznerServer> = {\n\t\tcreate: async () => {\n\t\t\tconst created = await client.request<{ server: HetznerServer }>(\n\t\t\t\t'POST',\n\t\t\t\t'/servers',\n\t\t\t\t{\n\t\t\t\t\tname: options.name,\n\t\t\t\t\tlocation: options.location,\n\t\t\t\t\tserver_type: options.serverType,\n\t\t\t\t\timage: options.image,\n\t\t\t\t\tssh_keys: [...options.sshKeys],\n\t\t\t\t\tstart_after_create: true,\n\t\t\t\t\tpublic_net: {\n\t\t\t\t\t\tenable_ipv4: publicIpv4Enabled,\n\t\t\t\t\t\tenable_ipv6: publicIpv6Enabled\n\t\t\t\t\t},\n\t\t\t\t\t...(options.labels !== undefined\n\t\t\t\t\t\t? { labels: options.labels }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(options.userData !== undefined\n\t\t\t\t\t\t? { user_data: options.userData }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(options.networkId !== undefined\n\t\t\t\t\t\t? { networks: [options.networkId] }\n\t\t\t\t\t\t: {})\n\t\t\t\t}\n\t\t\t);\n\t\t\treturn created.server;\n\t\t},\n\t\tdestroy: (id) => destroyHetznerServer({ client, id }),\n\t\tfetch: async (id) => {\n\t\t\tconst refreshed: { server: HetznerServer } = await client.request(\n\t\t\t\t'GET',\n\t\t\t\t`/servers/${id}`\n\t\t\t);\n\t\t\treturn refreshed.server;\n\t\t},\n\t\tfindByName: (name) => findHetznerServer(client, name),\n\t\tgetId: (server) => server.id,\n\t\tgetIpv4: publicIpv4,\n\t\tgetStatus: (server) => server.status,\n\t\tisReady: (server) => server.status === 'running'\n\t};\n\n\tconst result = await createCloudTarget(hooks, {\n\t\tdescribeTarget: (sshDescription) =>\n\t\t\t`hetzner server \"${options.name}\" (${sshDescription})`,\n\t\tentityWord: 'server',\n\t\tlogPrefix: '[hetzner]',\n\t\tname: options.name,\n\t\tregion: options.location,\n\t\t...(options.user !== undefined ? { user: options.user } : {}),\n\t\t...(options.identity !== undefined ? { identity: options.identity } : {}),\n\t\t...(options.port !== undefined ? { port: options.port } : {}),\n\t\t...(options.provisionTimeoutMs !== undefined\n\t\t\t? { provisionTimeoutMs: options.provisionTimeoutMs }\n\t\t\t: {}),\n\t\t...(options.sshReadinessTimeoutMs !== undefined\n\t\t\t? { sshReadinessTimeoutMs: options.sshReadinessTimeoutMs }\n\t\t\t: {}),\n\t\t...(options.pollIntervalMs !== undefined\n\t\t\t? { pollIntervalMs: options.pollIntervalMs }\n\t\t\t: {}),\n\t\t...(options.onLog !== undefined ? { onLog: options.onLog } : {}),\n\t\t...(options.probeSsh !== undefined ? { probeSsh: options.probeSsh } : {}),\n\t\t...(options.sleep !== undefined ? { sleep: options.sleep } : {}),\n\t\t...(options.now !== undefined ? { now: options.now } : {})\n\t});\n\n\treturn {\n\t\tdescription: result.description,\n\t\tdestroy: result.destroy,\n\t\texec: result.exec,\n\t\tipv4: result.ipv4,\n\t\tserverId: result.id,\n\t\tupload: result.upload,\n\t\t...(result.close !== undefined ? { close: result.close } : {})\n\t};\n};\n",
|
|
8
|
+
"import type { InfrastructureNode } from \"./infrastructure\";\n\nexport type InfrastructureAgentOptions = {\n audience?: string;\n port?: number;\n preferPrivateNetwork?: boolean;\n protocol?: \"http\" | \"https\";\n};\n\nexport const infrastructureAgent = (\n options: InfrastructureAgentOptions | undefined,\n addresses: Pick<InfrastructureNode, \"privateIpv4\" | \"publicIpv4\">,\n) => {\n if (!options) return undefined;\n const host = options.preferPrivateNetwork\n ? (addresses.privateIpv4 ?? addresses.publicIpv4)\n : (addresses.publicIpv4 ?? addresses.privateIpv4);\n if (!host) return undefined;\n\n return {\n url: `${options.protocol ?? \"http\"}://${host}:${options.port ?? 8081}/`,\n ...(options.audience ? { audience: options.audience } : {}),\n };\n};\n\nexport const leastPopulatedRegion = <Region extends { region: string }>(\n regions: readonly Region[],\n observed: readonly string[],\n requested?: string,\n) => {\n const eligible = requested\n ? regions.filter((region) => region.region === requested)\n : [...regions];\n if (eligible.length === 0) return undefined;\n const counts = new Map(eligible.map((region) => [region.region, 0]));\n for (const region of observed) {\n if (counts.has(region)) counts.set(region, (counts.get(region) ?? 0) + 1);\n }\n const selected = [...counts].sort(\n (left, right) =>\n left[1] - right[1] || left[0].localeCompare(right[0]),\n )[0]?.[0];\n\n return eligible.find((region) => region.region === selected);\n};\n",
|
|
9
|
+
"import {\n createHetznerClient,\n destroyHetznerServer,\n findHetznerServer,\n listHetznerServers,\n type HetznerClientLike,\n type HetznerServer,\n} from \"./hetzner\";\nimport {\n infrastructureAgent,\n leastPopulatedRegion,\n type InfrastructureAgentOptions,\n} from \"./infrastructureAdapter\";\nimport type {\n InfrastructureNode,\n InfrastructureNodeState,\n InfrastructureProvider,\n} from \"./infrastructure\";\n\nexport type HetznerFleetRegion = {\n image: string | number;\n networkId?: number;\n region: string;\n serverType: string;\n sshKeys: ReadonlyArray<string | number>;\n userData?: string;\n};\n\nexport type HetznerInfrastructureProviderOptions = {\n agent?: InfrastructureAgentOptions;\n client?: HetznerClientLike;\n labelKey?: string;\n labelValue?: string;\n regions: readonly HetznerFleetRegion[];\n token?: string;\n};\n\nconst stateFor = (status: HetznerServer[\"status\"]): InfrastructureNodeState => {\n if (status === \"running\") return \"ready\";\n if (\n [\"initializing\", \"starting\", \"migrating\", \"rebuilding\"].includes(status)\n )\n return \"pending\";\n\n return \"terminated\";\n};\n\nconst parseNodeId = (id: string) => {\n const match = /^hetzner:([1-9][0-9]*)$/.exec(id);\n if (!match?.[1])\n throw new Error(\"[deploy/hetzner] invalid infrastructure node id\");\n\n return Number(match[1]);\n};\n\nexport const createHetznerInfrastructureProvider = (\n options: HetznerInfrastructureProviderOptions,\n): InfrastructureProvider => {\n if (options.regions.length === 0)\n throw new Error(\"[deploy/hetzner] at least one fleet region is required\");\n const client =\n options.client ??\n (options.token ? createHetznerClient(options.token) : undefined);\n if (!client)\n throw new Error(\n \"[deploy/hetzner] either `token` or `client` must be provided\",\n );\n const labelKey = options.labelKey ?? \"absolutejs-role\";\n const labelValue = options.labelValue ?? \"absolutejs-paas-node\";\n\n const normalize = (server: HetznerServer): InfrastructureNode => {\n const publicIpv4 = server.public_net.ipv4?.ip;\n const privateIpv4 = server.private_net?.[0]?.ip;\n const agent = infrastructureAgent(options.agent, {\n privateIpv4,\n publicIpv4,\n });\n\n return {\n id: `hetzner:${server.id}`,\n label: server.name,\n provider: \"hetzner\",\n region: server.datacenter?.location.name ?? \"unknown\",\n state: stateFor(server.status),\n ...(publicIpv4 ? { publicIpv4 } : {}),\n ...(privateIpv4 ? { privateIpv4 } : {}),\n ...(agent ? { agent } : {}),\n };\n };\n const list = () =>\n listHetznerServers({\n client,\n labelSelector: `${labelKey}=${labelValue}`,\n });\n\n return {\n capabilities: {\n cloudInit: true,\n idempotentProvisioning: true,\n privateNetworking: true,\n regionalPlacement: true,\n regions: options.regions.map(({ region }) => region),\n },\n getNode: async (id) => {\n const result = await client.request<{ server: HetznerServer }>(\n \"GET\",\n `/servers/${parseNodeId(id)}`,\n );\n\n return normalize(result.server);\n },\n listNodes: async () => (await list()).map(normalize),\n name: \"hetzner\",\n provisionNode: async (input) => {\n const existing = await findHetznerServer(client, input.name);\n if (existing) return normalize(existing);\n const servers = await list();\n const region = leastPopulatedRegion(\n options.regions,\n servers.map((server) => server.datacenter?.location.name ?? \"unknown\"),\n input.region,\n );\n if (!region)\n throw new Error(\n `[deploy/hetzner] region ${input.region ?? \"(any)\"} is not configured`,\n );\n const result = await client.request<{ server: HetznerServer }>(\n \"POST\",\n \"/servers\",\n {\n image: region.image,\n labels: { [labelKey]: labelValue },\n location: region.region,\n name: input.name,\n public_net: { enable_ipv4: true, enable_ipv6: true },\n server_type: region.serverType,\n ssh_keys: [...region.sshKeys],\n start_after_create: true,\n ...(region.networkId ? { networks: [region.networkId] } : {}),\n ...(input.userData ?? region.userData\n ? { user_data: input.userData ?? region.userData }\n : {}),\n },\n );\n\n return normalize(result.server);\n },\n terminateNode: async (id) =>\n destroyHetznerServer({ client, id: parseNodeId(id) }),\n };\n};\n"
|
|
10
10
|
],
|
|
11
|
-
"mappings": "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",
|
|
12
|
-
"debugId": "
|
|
11
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA;AACA;AA+CA,IAAM,eAAe,OACpB,QACA,WACqB;AAAA,EACrB,IAAI,CAAC;AAAA,IAAQ,OAAO;AAAA,EACpB,MAAM,UAAU,IAAI;AAAA,EACpB,IAAI,SAAS;AAAA,EACb,IAAI,YAAY;AAAA,EAChB,MAAM,SAAS,OAAO,UAAU;AAAA,EAChC,IAAI;AAAA,IACH,OAAO,MAAM;AAAA,MACZ,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,MAC1C,IAAI;AAAA,QAAM;AAAA,MACV,MAAM,QAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,MACpD,aAAa;AAAA,MACb,IAAI,CAAC;AAAA,QAAQ;AAAA,MACb,UAAU;AAAA,MACV,IAAI,UAAU,OAAO,QAAQ;AAAA,CAAI;AAAA,MACjC,OAAO,YAAY,IAAI;AAAA,QACtB,MAAM,OAAO,OAAO,MAAM,GAAG,OAAO,EAAE,QAAQ,OAAO,EAAE;AAAA,QACvD,IAAI,KAAK,SAAS;AAAA,UAAG,OAAO,IAAI;AAAA,QAChC,SAAS,OAAO,MAAM,UAAU,CAAC;AAAA,QACjC,UAAU,OAAO,QAAQ;AAAA,CAAI;AAAA,MAC9B;AAAA,IACD;AAAA,IACA,MAAM,OAAO,QAAQ,OAAO;AAAA,IAC5B,aAAa;AAAA,IACb,IAAI,WAAW,SAAS,MAAM,SAAS;AAAA,MAAG,QAAQ,SAAS,MAAM,QAAQ,OAAO,EAAE,CAAC;AAAA,YAClF;AAAA,IACD,OAAO,YAAY;AAAA;AAAA,EAEpB,OAAO;AAAA;AAGR,IAAM,WAAW,OAChB,MACA,YAOyB;AAAA,EACzB,MAAM,OAAO,IAAI,MAAM,MAAM;AAAA,IAC5B,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ;AAAA,IACb,QAAQ;AAAA,IACR,OAAO,QAAQ,UAAU,YAAY,WAAW;AAAA,IAChD,QAAQ;AAAA,EACT,CAAC;AAAA,EAED,IAAI,QAAQ,UAAU,aAAa,KAAK,OAAO;AAAA,IAI9C,MAAM,OAAO,KAAK;AAAA,IAIlB,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK;AAAA,IACtC,IAAI,SAAS,OAAQ,MAA0B,SAAS,YAAY;AAAA,MACnE,MAAM;AAAA,IACP;AAAA,IACA,MAAM,QAAQ,KAAK,IAAI;AAAA,IACvB,IAAI,SAAS,OAAQ,MAAwB,SAAS,YAAY;AAAA,MACjE,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,MAAM,UAAU,QAAQ,aAAa;AAAA,EACrC,IAAI;AAAA,EACJ,IAAI,UAAU,GAAG;AAAA,IAChB,QAAQ,WAAW,MAAM;AAAA,MACxB,IAAI;AAAA,QAAE,KAAK,KAAK;AAAA,QAAK,MAAM;AAAA,OACzB,OAAO;AAAA,EACX;AAAA,EAEA,MAAM,gBAAgB,aACrB,KAAK,QACL,QAAQ,QAAQ,CAAC,SAAS,QAAQ,MAAO,MAAM,QAAQ,IAAI,SAC5D;AAAA,EACA,MAAM,gBAAgB,aACrB,KAAK,QACL,QAAQ,QAAQ,CAAC,SAAS,QAAQ,MAAO,MAAM,QAAQ,IAAI,SAC5D;AAAA,EAEA,OAAO,QAAQ,QAAQ,YAAY,MAAM,QAAQ,IAAI;AAAA,IACpD;AAAA,IACA;AAAA,IACA,KAAK;AAAA,EACN,CAAC;AAAA,EACD,IAAI;AAAA,IAAO,aAAa,KAAK;AAAA,EAE7B,OAAO,EAAE,UAAU,YAAY,IAAI,QAAQ,OAAO;AAAA;AAG5C,IAAM,cAAc,CAAC,YAAwC;AAAA,EACnE,MAAM,UAAU,KAAK,QAAQ,IAAI;AAAA,EACjC,MAAM,aAAa,YAAY;AAAA,IAAE,MAAM,MAAM,QAAQ,MAAM,EAAE,WAAW,KAAK,CAAC;AAAA;AAAA,EAE9E,OAAO;AAAA,IACN,aAAa,SAAS,QAAQ;AAAA,IAC9B,MAAM,OAAO,KAAK,SAAS;AAAA,MAC1B,MAAM,WAAW;AAAA,MACjB,OAAO,SAAS,CAAC,MAAM,MAAM,GAAG,GAAG;AAAA,QAClC,KAAK,MAAM,OAAO,QAAQ;AAAA,QAC1B,KAAK,KAAK,QAAQ,QAAQ,YAAa,MAAM,OAAO,CAAC,EAAG;AAAA,QACxD,OAAO,MAAM;AAAA,QACb,OAAO,MAAM;AAAA,QACb,WAAW,MAAM;AAAA,MAClB,CAAC;AAAA;AAAA,IAEF,QAAQ,OAAO,WAAW,YAAY,SAAS;AAAA,MAC9C,MAAM,WAAW;AAAA,MACjB,MAAM,OAAO,WAAW,WAAW,GAAG,IAAI,aAAa,KAAK,QAAQ,MAAM,UAAU;AAAA,MACpF,MAAM,OAAO,CAAC,SAAS,IAAI;AAAA,MAC3B,IAAI,MAAM;AAAA,QAAe,KAAK,KAAK,UAAU;AAAA,MAC7C,WAAW,WAAW,MAAM,WAAW,CAAC;AAAA,QAAG,KAAK,KAAK,aAAa,OAAO;AAAA,MAEzE,KAAK,KAAK,WAAW,IAAI;AAAA,MACzB,MAAM,SAAS,MAAM,SAAS,MAAM,EAAE,WAAW,OAAQ,CAAC;AAAA,MAC1D,IAAI,OAAO,aAAa,GAAG;AAAA,QAC1B,MAAM,IAAI,MAAM,6BAA6B,OAAO,cAAc,OAAO,UAAU,OAAO,QAAQ;AAAA,MACnG;AAAA;AAAA,EAEF;AAAA;AA+BD,IAAM,kBAAkB,CAAC,YAAsC;AAAA,EAC9D,MAAM,OAAO,QAAQ,QAAQ;AAAA,EAC7B,OAAO,GAAG,QAAQ,QAAQ;AAAA;AAG3B,IAAM,eAAe,CAAC,YAAwC;AAAA,EAC7D,MAAM,QAAkB,CAAC;AAAA,EACzB,IAAI,QAAQ,SAAS,aAAa,QAAQ,SAAS;AAAA,IAAI,MAAM,KAAK,MAAM,OAAO,QAAQ,IAAI,CAAC;AAAA,EAC5F,IAAI,QAAQ,aAAa;AAAA,IAAW,MAAM,KAAK,MAAM,QAAQ,QAAQ;AAAA,EAErE,MAAM,KAAK,MAAM,iBAAiB,MAAM,kCAAkC;AAAA,EAC1E,WAAW,QAAQ,QAAQ,YAAY,CAAC;AAAA,IAAG,MAAM,KAAK,IAAI;AAAA,EAC1D,OAAO;AAAA;AAGR,IAAM,aAAa,CAAC,UAA0B,IAAI,MAAM,QAAQ,MAAM,OAAO;AAE7E,IAAM,iBAAiB,CAAC,KAAa,SAA0C;AAAA,EAC9E,MAAM,MAAM,MAAM;AAAA,EAClB,MAAM,YAAY,MACf,OAAO,QAAQ,GAAG,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,KAAK,WAAW,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,MACzE;AAAA,EACH,IAAI,MAAM,KAAK;AAAA,IACd,OAAO,MAAM,WAAW,KAAK,GAAG,QAAQ,YAAY;AAAA,EACrD;AAAA,EACA,OAAO,GAAG,YAAY;AAAA;AAGhB,IAAM,YAAY,CAAC,YAAsC;AAAA,EAC/D,MAAM,SAAS,gBAAgB,OAAO;AAAA,EACtC,MAAM,WAAW,QAAQ,SAAS;AAAA,EAElC,OAAO;AAAA,IACN,aAAa,OAAO,SAAS,QAAQ,QAAQ,QAAQ,SAAS,KAAK,IAAI,QAAQ,SAAS;AAAA,IACxF,MAAM,OAAO,KAAK,SAAS;AAAA,MAC1B,MAAM,OAAO,CAAC,OAAO,GAAG,aAAa,OAAO,CAAC;AAAA,MAC7C,WAAW,QAAQ,QAAQ,cAAc,CAAC;AAAA,QAAG,KAAK,KAAK,MAAM,WAAW,MAAM;AAAA,MAC9E,KAAK,KAAK,QAAQ,eAAe,KAAK,IAAI,CAAC;AAAA,MAC3C,OAAO,SAAS,MAAM;AAAA,QACrB,OAAO,MAAM;AAAA,QACb,OAAO,MAAM;AAAA,QACb,WAAW,MAAM;AAAA,MAClB,CAAC;AAAA;AAAA,IAEF,QAAQ,OAAO,WAAW,YAAY,SAAS;AAAA,MAC9C,IAAI,UAAU;AAAA,QACb,MAAM,SAAS,CAAC,OAAO,GAAG,aAAa,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,SAAS,GAAG,IAAI,IAAI,UAAU,IAAI,EAAE,KAAK,GAAG;AAAA,QAChH,MAAM,QAAO,CAAC,SAAS,OAAO,MAAM,MAAM;AAAA,QAC1C,IAAI,MAAM;AAAA,UAAe,MAAK,KAAK,UAAU;AAAA,QAC7C,WAAW,WAAW,MAAM,WAAW,CAAC;AAAA,UAAG,MAAK,KAAK,aAAa,OAAO;AAAA,QACzE,MAAK,KAAK,WAAW,GAAG,UAAU,YAAY;AAAA,QAC9C,MAAM,UAAS,MAAM,SAAS,OAAM,EAAE,WAAW,OAAQ,CAAC;AAAA,QAC1D,IAAI,QAAO,aAAa,GAAG;AAAA,UAC1B,MAAM,IAAI,MAAM,6BAA6B,QAAO,cAAc,QAAO,UAAU,QAAO,QAAQ;AAAA,QACnG;AAAA,QACA;AAAA,MACD;AAAA,MAEA,MAAM,OAAO,CAAC,OAAO,MAAM,GAAG,aAAa,OAAO,GAAG,WAAW,GAAG,UAAU,YAAY;AAAA,MACzF,MAAM,SAAS,MAAM,SAAS,MAAM,EAAE,WAAW,OAAQ,CAAC;AAAA,MAC1D,IAAI,OAAO,aAAa,GAAG;AAAA,QAC1B,MAAM,IAAI,MAAM,2BAA2B,OAAO,cAAc,OAAO,UAAU,OAAO,QAAQ;AAAA,MACjG;AAAA;AAAA,EAEF;AAAA;;;AC5LD,IAAM,eAAe,CAAC,OACrB,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAEjD,IAAM,kBAAkB,OAAO,MAAc,SAAmC;AAAA,EAC/E,MAAM,mBAAmB;AAAA,EACzB,OAAO,IAAI,QAAiB,CAAC,YAAY;AAAA,IACxC,IAAI,UAAU;AAAA,IACd,MAAM,SAAS,CAAC,UAAmB;AAAA,MAClC,IAAI;AAAA,QAAS;AAAA,MACb,UAAU;AAAA,MACV,QAAQ,KAAK;AAAA;AAAA,IAEd,MAAM,QAAQ,WAAW,MAAM,OAAO,KAAK,GAAG,gBAAgB;AAAA,IAC9D,IAAI,QAAQ;AAAA,MACX,UAAU;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,QACP,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM;AAAA,UACZ,aAAa,KAAK;AAAA,UAClB,OAAO,KAAK;AAAA;AAAA,QAEb,MAAM,CAAC,WAAW;AAAA,UACjB,aAAa,KAAK;AAAA,UAClB,OAAO,IAAI;AAAA,UACX,OAAO,IAAI;AAAA;AAAA,MAEb;AAAA,IACD,CAAC,EAAE,MAAM,MAAM;AAAA,MACd,aAAa,KAAK;AAAA,MAClB,OAAO,KAAK;AAAA,KACZ;AAAA,GACD;AAAA;AAQK,IAAM,oBAAoB,OAChC,OACA,YACoC;AAAA,EACpC,MAAM,MAAM,QAAQ,UAAU,MAAM;AAAA,EACpC,MAAM,WAAW,QAAQ,YAAY;AAAA,EACrC,MAAM,QAAQ,QAAQ,SAAS;AAAA,EAC/B,MAAM,MAAM,QAAQ,OAAO,KAAK;AAAA,EAChC,MAAM,SAAS,QAAQ,kBAAkB;AAAA,EACzC,MAAM,mBAAmB,QAAQ,sBAAsB,IAAI;AAAA,EAC3D,MAAM,aAAa,QAAQ,yBAAyB,IAAI;AAAA,EACxD,MAAM,OAAO,QAAQ,QAAQ;AAAA,EAC7B,MAAM,SAAS,QAAQ;AAAA,EACvB,MAAM,OAAO,QAAQ;AAAA,EAErB,MAAM,WAAW,MAAM,MAAM,WAAW,QAAQ,IAAI;AAAA,EACpD,IAAI;AAAA,EACJ,IAAI,aAAa,WAAW;AAAA,IAC3B,IAAI,GAAG,mBAAmB,SAAS,QAAQ,YAAY,QAAQ,QAAQ;AAAA,IACvE,UAAU,MAAM,MAAM,OAAO;AAAA,EAC9B,EAAO;AAAA,IACN,IACC,GAAG,kBAAkB,SAAS,QAAQ,aAAa,MAAM,MAAM,QAAQ,aAAa,MAAM,UAAU,QAAQ,IAC7G;AAAA,IACA,UAAU;AAAA;AAAA,EAIX,MAAM,iBAAiB,IAAI;AAAA,EAC3B,IAAI,OAAO,MAAM,QAAQ,OAAO;AAAA,EAChC,OAAO,CAAC,MAAM,QAAQ,OAAO,KAAK,SAAS,WAAW;AAAA,IACrD,IAAI,IAAI,IAAI,iBAAiB,kBAAkB;AAAA,MAC9C,MAAM,IAAI,MACT,GAAG,kCAAkC,6BAAuB,QAAQ,MAAM,MAAM,OAAO,aAAa,MAAM,UAAU,OAAO,YAAY,QAAQ,gBAChJ;AAAA,IACD;AAAA,IACA,MAAM,MAAM,MAAM;AAAA,IAClB,UAAU,MAAM,MAAM,MAAM,MAAM,MAAM,OAAO,CAAC;AAAA,IAChD,OAAO,MAAM,QAAQ,OAAO;AAAA,IAC5B,IACC,GAAG,uBAAuB,MAAM,UAAU,OAAO,UAAU,QAAQ,cACpE;AAAA,EACD;AAAA,EACA,IAAI,GAAG,UAAU,iBAAiB,MAAM;AAAA,EAGxC,MAAM,WAAW,IAAI;AAAA,EACrB,OAAO,CAAE,MAAM,SAAS,MAAM,IAAI,GAAI;AAAA,IACrC,IAAI,IAAI,IAAI,WAAW,YAAY;AAAA,MAClC,MAAM,IAAI,MACT,GAAG,sCAAsC,uBAAiB,QAAQ,iCACnE;AAAA,IACD;AAAA,IACA,MAAM,MAAM,MAAM;AAAA,IAClB,IAAI,GAAG,yBAAyB,QAAQ,MAAM;AAAA,EAC/C;AAAA,EACA,IAAI,GAAG,uBAAuB,QAAQ,MAAM;AAAA,EAE5C,MAAM,MAAM,UAAU;AAAA,IACrB,MAAM;AAAA,OACF,QAAQ,SAAS,YAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,OACvD,QAAQ,aAAa,YAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,OACnE,QAAQ,SAAS,YAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,EAC5D,CAAC;AAAA,EAED,MAAM,KAAK,MAAM,MAAM,OAAO;AAAA,EAC9B,MAAM,eAAe;AAAA,EAErB,OAAO;AAAA,IACN,aAAa,QAAQ,eAAe,IAAI,WAAW;AAAA,IACnD,SAAS,MACR,MAAM,QAAQ,EAAE,EAAE,KAAK,MAAM;AAAA,MAC5B,IAAI,GAAG,oBAAoB,QAAQ,IAAI;AAAA,KACvC;AAAA,IACF,MAAM,IAAI;AAAA,IACV;AAAA,IACA,MAAM;AAAA,IACN,QAAQ,IAAI;AAAA,OACR,IAAI,UAAU,YAAY,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;AAAA,EACvD;AAAA;;;ACpMD,IAAM,mBAAmB;AAAA;AAuGlB,MAAM,qBAAqB,MAAM;AAAA,EAC9B;AAAA,EACA;AAAA,EACT,WAAW,CAAC,SAAiB,QAAgB,MAAe;AAAA,IAC3D,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA,IACZ,KAAK,SAAS;AAAA,IACd,KAAK,OAAO;AAAA;AAEd;AAOO,IAAM,sBAAsB,CAClC,OACA,UAAsD,CAAC,MAChC;AAAA,EACvB,MAAM,OAAO,QAAQ,WAAW;AAAA,EAChC,MAAM,IAAI,QAAQ,SAAS;AAAA,EAC3B,OAAO;AAAA,IACN,SAAS,OACR,QACA,MACA,SACgB;AAAA,MAChB,MAAM,OAAoB;AAAA,QACzB,SAAS;AAAA,UACR,eAAe,UAAU;AAAA,UACzB,gBAAgB;AAAA,QACjB;AAAA,QACA;AAAA,MACD;AAAA,MACA,IAAI,SAAS;AAAA,QAAW,KAAK,OAAO,KAAK,UAAU,IAAI;AAAA,MACvD,MAAM,WAAW,MAAM,EAAE,GAAG,OAAO,QAAQ,IAAI;AAAA,MAC/C,IAAI,SAAS,WAAW;AAAA,QAAK;AAAA,MAC7B,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,MACjC,MAAM,SAAS,KAAK,SAAS,IAAI,KAAK,MAAM,IAAI,IAAI;AAAA,MACpD,IAAI,CAAC,SAAS,IAAI;AAAA,QACjB,MAAM,IAAI,aACT,qBAAqB,UAAU,gBAAgB,SAAS,UAAU,SAAS,cAC3E,SAAS,QACT,MACD;AAAA,MACD;AAAA,MACA,OAAO;AAAA;AAAA,EAET;AAAA;AAGD,IAAM,gBAAgB,CACrB,YACuB;AAAA,EACvB,IAAI,QAAQ,WAAW;AAAA,IAAW,OAAO,QAAQ;AAAA,EACjD,IAAI,QAAQ,UAAU,aAAa,QAAQ,MAAM,SAAS,GAAG;AAAA,IAC5D,OAAO,oBAAoB,QAAQ,KAAK;AAAA,EACzC;AAAA,EACA,MAAM,IAAI,MACT,8DACD;AAAA;AAGD,IAAM,aAAa,CAAC,WACnB,OAAO,WAAW,MAAM;AAQlB,IAAM,oBAAoB,OAChC,QACA,SACwC;AAAA,EACxC,MAAM,OAAO,MAAM,OAAO,QACzB,OACA,iBAAiB,mBAAmB,IAAI,GACzC;AAAA,EACA,MAAM,UAAU,KAAK,QAAQ,OAAO,CAAC,WAAW,OAAO,SAAS,IAAI;AAAA,EACpE,IAAI,QAAQ,WAAW;AAAA,IAAG;AAAA,EAC1B,IAAI,QAAQ,SAAS,GAAG;AAAA,IACvB,MAAM,IAAI,MACT,4CAA4C,UAAU,QACpD,IAAI,CAAC,WAAW,OAAO,EAAE,EACzB,KAAK,IAAI,2DACZ;AAAA,EACD;AAAA,EACA,OAAO,QAAQ;AAAA;AAIT,IAAM,qBAAqB,OAAO,YAKT;AAAA,EAC/B,MAAM,SAAS,cAAc,OAAO;AAAA,EACpC,MAAM,OACL,QAAQ,kBAAkB,YACvB,2BAA2B,mBAAmB,QAAQ,aAAa,MACnE;AAAA,EACJ,MAAM,OAAO,MAAM,OAAO,QAAsC,OAAO,IAAI;AAAA,EAC3E,OAAO,KAAK;AAAA;AAIN,IAAM,uBAAuB,OAAO,YAItB;AAAA,EACpB,MAAM,SAAS,cAAc,OAAO;AAAA,EACpC,IAAI;AAAA,IACH,MAAM,OAAO,QAAQ,UAAU,YAAY,QAAQ,IAAI;AAAA,IACtD,OAAO,OAAO;AAAA,IACf,IAAI,iBAAiB,gBAAgB,MAAM,WAAW,KAAK;AAAA,MAC1D;AAAA,IACD;AAAA,IACA,MAAM;AAAA;AAAA;AAQD,IAAM,gBAAgB,OAC5B,YAC4B;AAAA,EAC5B,MAAM,SAAS,cAAc,OAAO;AAAA,EACpC,MAAM,oBAAoB,QAAQ,sBAAsB;AAAA,EACxD,MAAM,oBAAoB,QAAQ,sBAAsB;AAAA,EAExD,MAAM,QAAyC;AAAA,IAC9C,QAAQ,YAAY;AAAA,MACnB,MAAM,UAAU,MAAM,OAAO,QAC5B,QACA,YACA;AAAA,QACC,MAAM,QAAQ;AAAA,QACd,UAAU,QAAQ;AAAA,QAClB,aAAa,QAAQ;AAAA,QACrB,OAAO,QAAQ;AAAA,QACf,UAAU,CAAC,GAAG,QAAQ,OAAO;AAAA,QAC7B,oBAAoB;AAAA,QACpB,YAAY;AAAA,UACX,aAAa;AAAA,UACb,aAAa;AAAA,QACd;AAAA,WACI,QAAQ,WAAW,YACpB,EAAE,QAAQ,QAAQ,OAAO,IACzB,CAAC;AAAA,WACA,QAAQ,aAAa,YACtB,EAAE,WAAW,QAAQ,SAAS,IAC9B,CAAC;AAAA,WACA,QAAQ,cAAc,YACvB,EAAE,UAAU,CAAC,QAAQ,SAAS,EAAE,IAChC,CAAC;AAAA,MACL,CACD;AAAA,MACA,OAAO,QAAQ;AAAA;AAAA,IAEhB,SAAS,CAAC,OAAO,qBAAqB,EAAE,QAAQ,GAAG,CAAC;AAAA,IACpD,OAAO,OAAO,OAAO;AAAA,MACpB,MAAM,YAAuC,MAAM,OAAO,QACzD,OACA,YAAY,IACb;AAAA,MACA,OAAO,UAAU;AAAA;AAAA,IAElB,YAAY,CAAC,SAAS,kBAAkB,QAAQ,IAAI;AAAA,IACpD,OAAO,CAAC,WAAW,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT,WAAW,CAAC,WAAW,OAAO;AAAA,IAC9B,SAAS,CAAC,WAAW,OAAO,WAAW;AAAA,EACxC;AAAA,EAEA,MAAM,SAAS,MAAM,kBAAkB,OAAO;AAAA,IAC7C,gBAAgB,CAAC,mBAChB,mBAAmB,QAAQ,UAAU;AAAA,IACtC,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,MAAM,QAAQ;AAAA,IACd,QAAQ,QAAQ;AAAA,OACZ,QAAQ,SAAS,YAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,OACvD,QAAQ,aAAa,YAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,OACnE,QAAQ,SAAS,YAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,OACvD,QAAQ,uBAAuB,YAChC,EAAE,oBAAoB,QAAQ,mBAAmB,IACjD,CAAC;AAAA,OACA,QAAQ,0BAA0B,YACnC,EAAE,uBAAuB,QAAQ,sBAAsB,IACvD,CAAC;AAAA,OACA,QAAQ,mBAAmB,YAC5B,EAAE,gBAAgB,QAAQ,eAAe,IACzC,CAAC;AAAA,OACA,QAAQ,UAAU,YAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,OAC1D,QAAQ,aAAa,YAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,OACnE,QAAQ,UAAU,YAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,OAC1D,QAAQ,QAAQ,YAAY,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;AAAA,EACzD,CAAC;AAAA,EAED,OAAO;AAAA,IACN,aAAa,OAAO;AAAA,IACpB,SAAS,OAAO;AAAA,IAChB,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,UAAU,OAAO;AAAA,IACjB,QAAQ,OAAO;AAAA,OACX,OAAO,UAAU,YAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,EAC7D;AAAA;;;AC/UM,IAAM,sBAAsB,CACjC,SACA,cACG;AAAA,EACH,IAAI,CAAC;AAAA,IAAS;AAAA,EACd,MAAM,OAAO,QAAQ,uBAChB,UAAU,eAAe,UAAU,aACnC,UAAU,cAAc,UAAU;AAAA,EACvC,IAAI,CAAC;AAAA,IAAM;AAAA,EAEX,OAAO;AAAA,IACL,KAAK,GAAG,QAAQ,YAAY,YAAY,QAAQ,QAAQ,QAAQ;AAAA,OAC5D,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,EAC3D;AAAA;AAGK,IAAM,uBAAuB,CAClC,SACA,UACA,cACG;AAAA,EACH,MAAM,WAAW,YACb,QAAQ,OAAO,CAAC,WAAW,OAAO,WAAW,SAAS,IACtD,CAAC,GAAG,OAAO;AAAA,EACf,IAAI,SAAS,WAAW;AAAA,IAAG;AAAA,EAC3B,MAAM,SAAS,IAAI,IAAI,SAAS,IAAI,CAAC,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC;AAAA,EACnE,WAAW,UAAU,UAAU;AAAA,IAC7B,IAAI,OAAO,IAAI,MAAM;AAAA,MAAG,OAAO,IAAI,SAAS,OAAO,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA,EAC1E;AAAA,EACA,MAAM,WAAW,CAAC,GAAG,MAAM,EAAE,KAC3B,CAAC,MAAM,UACL,KAAK,KAAK,MAAM,MAAM,KAAK,GAAG,cAAc,MAAM,EAAE,CACxD,EAAE,KAAK;AAAA,EAEP,OAAO,SAAS,KAAK,CAAC,WAAW,OAAO,WAAW,QAAQ;AAAA;;;ACN7D,IAAM,WAAW,CAAC,WAA6D;AAAA,EAC7E,IAAI,WAAW;AAAA,IAAW,OAAO;AAAA,EACjC,IACE,CAAC,gBAAgB,YAAY,aAAa,YAAY,EAAE,SAAS,MAAM;AAAA,IAEvE,OAAO;AAAA,EAET,OAAO;AAAA;AAGT,IAAM,cAAc,CAAC,OAAe;AAAA,EAClC,MAAM,QAAQ,0BAA0B,KAAK,EAAE;AAAA,EAC/C,IAAI,CAAC,QAAQ;AAAA,IACX,MAAM,IAAI,MAAM,iDAAiD;AAAA,EAEnE,OAAO,OAAO,MAAM,EAAE;AAAA;AAGjB,IAAM,sCAAsC,CACjD,YAC2B;AAAA,EAC3B,IAAI,QAAQ,QAAQ,WAAW;AAAA,IAC7B,MAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E,MAAM,SACJ,QAAQ,WACP,QAAQ,QAAQ,oBAAoB,QAAQ,KAAK,IAAI;AAAA,EACxD,IAAI,CAAC;AAAA,IACH,MAAM,IAAI,MACR,8DACF;AAAA,EACF,MAAM,WAAW,QAAQ,YAAY;AAAA,EACrC,MAAM,aAAa,QAAQ,cAAc;AAAA,EAEzC,MAAM,YAAY,CAAC,WAA8C;AAAA,IAC/D,MAAM,cAAa,OAAO,WAAW,MAAM;AAAA,IAC3C,MAAM,cAAc,OAAO,cAAc,IAAI;AAAA,IAC7C,MAAM,QAAQ,oBAAoB,QAAQ,OAAO;AAAA,MAC/C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,IAED,OAAO;AAAA,MACL,IAAI,WAAW,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,MACd,UAAU;AAAA,MACV,QAAQ,OAAO,YAAY,SAAS,QAAQ;AAAA,MAC5C,OAAO,SAAS,OAAO,MAAM;AAAA,SACzB,cAAa,EAAE,wBAAW,IAAI,CAAC;AAAA,SAC/B,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,SACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IAC3B;AAAA;AAAA,EAEF,MAAM,OAAO,MACX,mBAAmB;AAAA,IACjB;AAAA,IACA,eAAe,GAAG,YAAY;AAAA,EAChC,CAAC;AAAA,EAEH,OAAO;AAAA,IACL,cAAc;AAAA,MACZ,WAAW;AAAA,MACX,wBAAwB;AAAA,MACxB,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,MACnB,SAAS,QAAQ,QAAQ,IAAI,GAAG,aAAa,MAAM;AAAA,IACrD;AAAA,IACA,SAAS,OAAO,OAAO;AAAA,MACrB,MAAM,SAAS,MAAM,OAAO,QAC1B,OACA,YAAY,YAAY,EAAE,GAC5B;AAAA,MAEA,OAAO,UAAU,OAAO,MAAM;AAAA;AAAA,IAEhC,WAAW,aAAa,MAAM,KAAK,GAAG,IAAI,SAAS;AAAA,IACnD,MAAM;AAAA,IACN,eAAe,OAAO,UAAU;AAAA,MAC9B,MAAM,WAAW,MAAM,kBAAkB,QAAQ,MAAM,IAAI;AAAA,MAC3D,IAAI;AAAA,QAAU,OAAO,UAAU,QAAQ;AAAA,MACvC,MAAM,UAAU,MAAM,KAAK;AAAA,MAC3B,MAAM,SAAS,qBACb,QAAQ,SACR,QAAQ,IAAI,CAAC,WAAW,OAAO,YAAY,SAAS,QAAQ,SAAS,GACrE,MAAM,MACR;AAAA,MACA,IAAI,CAAC;AAAA,QACH,MAAM,IAAI,MACR,2BAA2B,MAAM,UAAU,2BAC7C;AAAA,MACF,MAAM,SAAS,MAAM,OAAO,QAC1B,QACA,YACA;AAAA,QACE,OAAO,OAAO;AAAA,QACd,QAAQ,GAAG,WAAW,WAAW;AAAA,QACjC,UAAU,OAAO;AAAA,QACjB,MAAM,MAAM;AAAA,QACZ,YAAY,EAAE,aAAa,MAAM,aAAa,KAAK;AAAA,QACnD,aAAa,OAAO;AAAA,QACpB,UAAU,CAAC,GAAG,OAAO,OAAO;AAAA,QAC5B,oBAAoB;AAAA,WAChB,OAAO,YAAY,EAAE,UAAU,CAAC,OAAO,SAAS,EAAE,IAAI,CAAC;AAAA,WACvD,MAAM,YAAY,OAAO,WACzB,EAAE,WAAW,MAAM,YAAY,OAAO,SAAS,IAC/C,CAAC;AAAA,MACP,CACF;AAAA,MAEA,OAAO,UAAU,OAAO,MAAM;AAAA;AAAA,IAEhC,eAAe,OAAO,OACpB,qBAAqB,EAAE,QAAQ,IAAI,YAAY,EAAE,EAAE,CAAC;AAAA,EACxD;AAAA;",
|
|
12
|
+
"debugId": "476732DAEAFCE24E64756E2164756E21",
|
|
13
13
|
"names": []
|
|
14
14
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
*
|
|
11
11
|
* See README for the typical "deploy to a DigitalOcean droplet" recipe.
|
|
12
12
|
*/
|
|
13
|
-
export type { ExecOptions, ExecResult, LocalTargetOptions, SshTargetOptions, Target, UploadOptions, } from
|
|
14
|
-
export { localTarget, sshTarget } from
|
|
15
|
-
export type { BareManagerOptions, ProcessManager, ProcessManagerContext, SystemdManagerOptions, } from
|
|
16
|
-
export { bareManager, systemdManager } from
|
|
17
|
-
export type { DeployContext, DeployHooks, DeployOptions, DeployResult, DeployStep, Deployer, DeployerOptions, ReleaseAnnotations, ReleaseRecord, Source, VerifySpec, } from
|
|
18
|
-
export { createDeployer, defaultBunPipeline } from
|
|
19
|
-
export type { CreatedReleaseArtifact, ReleaseArtifactMetadata, } from
|
|
20
|
-
export { createReleaseArtifact, extractReleaseArtifact, receiveReleaseArtifact, ReleaseArtifactError, } from
|
|
21
|
-
export type { EdgeIngress, EdgeIngressBackend, EdgeIngressCapabilities, EdgeIngressProtocol, EdgeIngressProvider, EdgeIngressSpec, EdgeIngressState, } from
|
|
22
|
-
export { EdgeIngressValidationError, normalizedEdgeIngressBackends, validateEdgeIngressSpec, } from
|
|
13
|
+
export type { ExecOptions, ExecResult, LocalTargetOptions, SshTargetOptions, Target, UploadOptions, } from './targets';
|
|
14
|
+
export { localTarget, sshTarget } from './targets';
|
|
15
|
+
export type { BareManagerOptions, ProcessManager, ProcessManagerContext, SystemdManagerOptions, } from './processManagers';
|
|
16
|
+
export { bareManager, systemdManager } from './processManagers';
|
|
17
|
+
export type { DeployContext, DeployHooks, DeployOptions, DeployResult, DeployStep, Deployer, DeployerOptions, ReleaseAnnotations, ReleaseRecord, Source, VerifySpec, } from './deployer';
|
|
18
|
+
export { createDeployer, defaultBunPipeline } from './deployer';
|
|
19
|
+
export type { CreatedReleaseArtifact, ReleaseArtifactMetadata, } from './releaseArtifact';
|
|
20
|
+
export { createReleaseArtifact, extractReleaseArtifact, receiveReleaseArtifact, ReleaseArtifactError, } from './releaseArtifact';
|
|
21
|
+
export type { EdgeIngress, EdgeIngressBackend, EdgeIngressCapabilities, EdgeIngressProtocol, EdgeIngressProvider, EdgeIngressSpec, EdgeIngressState, } from './edgeIngress';
|
|
22
|
+
export { EdgeIngressValidationError, normalizedEdgeIngressBackends, validateEdgeIngressSpec, } from './edgeIngress';
|
package/dist/index.js
CHANGED
|
@@ -355,13 +355,7 @@ var sshTarget = (options) => {
|
|
|
355
355
|
}
|
|
356
356
|
return;
|
|
357
357
|
}
|
|
358
|
-
const argv = [
|
|
359
|
-
"scp",
|
|
360
|
-
"-r",
|
|
361
|
-
...sshBaseFlags(options),
|
|
362
|
-
localPath,
|
|
363
|
-
`${remote}:${remotePath}`
|
|
364
|
-
];
|
|
358
|
+
const argv = ["scp", "-r", ...sshBaseFlags(options), localPath, `${remote}:${remotePath}`];
|
|
365
359
|
const result = await runSpawn(argv, { timeoutMs: 600000 });
|
|
366
360
|
if (result.exitCode !== 0) {
|
|
367
361
|
throw new Error(`scp upload failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);
|
|
@@ -402,17 +396,11 @@ rm -f ${pidPath(ctx.appName)}
|
|
|
402
396
|
`.trim();
|
|
403
397
|
return {
|
|
404
398
|
reload: async (target, ctx) => {
|
|
405
|
-
const stop = await target.exec(stopCmd(ctx), {
|
|
406
|
-
onLog: ctx.onLog,
|
|
407
|
-
timeoutMs: 30000
|
|
408
|
-
});
|
|
399
|
+
const stop = await target.exec(stopCmd(ctx), { onLog: ctx.onLog, timeoutMs: 30000 });
|
|
409
400
|
if (stop.exitCode !== 0) {
|
|
410
401
|
throw new Error(`bareManager.stop failed (exit ${stop.exitCode}): ${stop.stderr}`);
|
|
411
402
|
}
|
|
412
|
-
const start = await target.exec(startCmd(ctx), {
|
|
413
|
-
onLog: ctx.onLog,
|
|
414
|
-
timeoutMs: 30000
|
|
415
|
-
});
|
|
403
|
+
const start = await target.exec(startCmd(ctx), { onLog: ctx.onLog, timeoutMs: 30000 });
|
|
416
404
|
if (start.exitCode !== 0) {
|
|
417
405
|
throw new Error(`bareManager.start failed (exit ${start.exitCode}): ${start.stderr}`);
|
|
418
406
|
}
|
|
@@ -427,10 +415,7 @@ rm -f ${pidPath(ctx.appName)}
|
|
|
427
415
|
return "unknown";
|
|
428
416
|
},
|
|
429
417
|
stop: async (target, ctx) => {
|
|
430
|
-
const result = await target.exec(stopCmd(ctx), {
|
|
431
|
-
onLog: ctx.onLog,
|
|
432
|
-
timeoutMs: 30000
|
|
433
|
-
});
|
|
418
|
+
const result = await target.exec(stopCmd(ctx), { onLog: ctx.onLog, timeoutMs: 30000 });
|
|
434
419
|
if (result.exitCode !== 0) {
|
|
435
420
|
throw new Error(`bareManager.stop failed (exit ${result.exitCode}): ${result.stderr}`);
|
|
436
421
|
}
|
|
@@ -476,24 +461,15 @@ var systemdManager = (options = {}) => {
|
|
|
476
461
|
if (writeUnit.exitCode !== 0) {
|
|
477
462
|
throw new Error(`systemdManager: writing unit failed (exit ${writeUnit.exitCode}): ${writeUnit.stderr}`);
|
|
478
463
|
}
|
|
479
|
-
const reload = await target.exec(`${systemctl} daemon-reload`, {
|
|
480
|
-
onLog: ctx.onLog,
|
|
481
|
-
timeoutMs: 15000
|
|
482
|
-
});
|
|
464
|
+
const reload = await target.exec(`${systemctl} daemon-reload`, { onLog: ctx.onLog, timeoutMs: 15000 });
|
|
483
465
|
if (reload.exitCode !== 0) {
|
|
484
466
|
throw new Error(`systemdManager: daemon-reload failed (exit ${reload.exitCode}): ${reload.stderr}`);
|
|
485
467
|
}
|
|
486
|
-
const enable = await target.exec(`${systemctl} enable ${name}`, {
|
|
487
|
-
onLog: ctx.onLog,
|
|
488
|
-
timeoutMs: 15000
|
|
489
|
-
});
|
|
468
|
+
const enable = await target.exec(`${systemctl} enable ${name}`, { onLog: ctx.onLog, timeoutMs: 15000 });
|
|
490
469
|
if (enable.exitCode !== 0) {
|
|
491
470
|
throw new Error(`systemdManager: enable failed (exit ${enable.exitCode}): ${enable.stderr}`);
|
|
492
471
|
}
|
|
493
|
-
const restart = await target.exec(`${systemctl} restart ${name}`, {
|
|
494
|
-
onLog: ctx.onLog,
|
|
495
|
-
timeoutMs: 60000
|
|
496
|
-
});
|
|
472
|
+
const restart = await target.exec(`${systemctl} restart ${name}`, { onLog: ctx.onLog, timeoutMs: 60000 });
|
|
497
473
|
if (restart.exitCode !== 0) {
|
|
498
474
|
throw new Error(`systemdManager: restart failed (exit ${restart.exitCode}): ${restart.stderr}`);
|
|
499
475
|
}
|
|
@@ -508,10 +484,7 @@ var systemdManager = (options = {}) => {
|
|
|
508
484
|
return "unknown";
|
|
509
485
|
},
|
|
510
486
|
stop: async (target, ctx) => {
|
|
511
|
-
const result = await target.exec(`${systemctl} stop ${unitName(ctx)}`, {
|
|
512
|
-
onLog: ctx.onLog,
|
|
513
|
-
timeoutMs: 30000
|
|
514
|
-
});
|
|
487
|
+
const result = await target.exec(`${systemctl} stop ${unitName(ctx)}`, { onLog: ctx.onLog, timeoutMs: 30000 });
|
|
515
488
|
if (result.exitCode !== 0) {
|
|
516
489
|
throw new Error(`systemdManager: stop failed (exit ${result.exitCode}): ${result.stderr}`);
|
|
517
490
|
}
|
|
@@ -519,14 +492,7 @@ var systemdManager = (options = {}) => {
|
|
|
519
492
|
};
|
|
520
493
|
};
|
|
521
494
|
// src/deployer.ts
|
|
522
|
-
var DEFAULT_EXCLUDES = [
|
|
523
|
-
"node_modules",
|
|
524
|
-
"dist",
|
|
525
|
-
"build",
|
|
526
|
-
".git",
|
|
527
|
-
".DS_Store",
|
|
528
|
-
"*.log"
|
|
529
|
-
];
|
|
495
|
+
var DEFAULT_EXCLUDES = ["node_modules", "dist", "build", ".git", ".DS_Store", "*.log"];
|
|
530
496
|
var noopHooks = {
|
|
531
497
|
onError: () => {},
|
|
532
498
|
onLog: () => {},
|
|
@@ -554,9 +520,7 @@ var defaultBunPipeline = () => [
|
|
|
554
520
|
{
|
|
555
521
|
name: "prepare",
|
|
556
522
|
run: async (ctx) => {
|
|
557
|
-
const result = await ctx.target.exec(`mkdir -p ${ctx.releasePath}`, {
|
|
558
|
-
onLog: (line, stream) => ctx.hooks.onLog(line, stream, "prepare")
|
|
559
|
-
});
|
|
523
|
+
const result = await ctx.target.exec(`mkdir -p ${ctx.releasePath}`, { onLog: (line, stream) => ctx.hooks.onLog(line, stream, "prepare") });
|
|
560
524
|
requireSuccess("prepare: mkdir", result);
|
|
561
525
|
}
|
|
562
526
|
},
|
|
@@ -603,10 +567,7 @@ var defaultBunPipeline = () => [
|
|
|
603
567
|
name: "link",
|
|
604
568
|
run: async (ctx) => {
|
|
605
569
|
const tmpLink = `${ctx.currentPath}.next`;
|
|
606
|
-
const result = await ctx.target.exec(`ln -sfn ${ctx.releasePath} ${tmpLink} && mv -Tf ${tmpLink} ${ctx.currentPath}`, {
|
|
607
|
-
onLog: (line, stream) => ctx.hooks.onLog(line, stream, "link"),
|
|
608
|
-
timeoutMs: 1e4
|
|
609
|
-
});
|
|
570
|
+
const result = await ctx.target.exec(`ln -sfn ${ctx.releasePath} ${tmpLink} && mv -Tf ${tmpLink} ${ctx.currentPath}`, { onLog: (line, stream) => ctx.hooks.onLog(line, stream, "link"), timeoutMs: 1e4 });
|
|
610
571
|
requireSuccess("link", result);
|
|
611
572
|
}
|
|
612
573
|
},
|
|
@@ -671,10 +632,7 @@ var createDeployer = (options) => {
|
|
|
671
632
|
const rootPath = options.rootPath ?? `/srv/${options.appName}`;
|
|
672
633
|
const currentPath = `${rootPath}/current`;
|
|
673
634
|
const releasesPath = `${rootPath}/releases`;
|
|
674
|
-
const env = {
|
|
675
|
-
NODE_ENV: "production",
|
|
676
|
-
...options.env
|
|
677
|
-
};
|
|
635
|
+
const env = { NODE_ENV: "production", ...options.env };
|
|
678
636
|
const processManager = options.processManager ?? bareManager();
|
|
679
637
|
const verify = options.verify === undefined ? null : options.verify;
|
|
680
638
|
let disposed = false;
|
|
@@ -718,9 +676,7 @@ var createDeployer = (options) => {
|
|
|
718
676
|
}
|
|
719
677
|
};
|
|
720
678
|
const cleanOrphanedSymlink = async () => {
|
|
721
|
-
await options.target.exec(`rm -f ${currentPath}.next`, {
|
|
722
|
-
timeoutMs: 5000
|
|
723
|
-
});
|
|
679
|
+
await options.target.exec(`rm -f ${currentPath}.next`, { timeoutMs: 5000 });
|
|
724
680
|
};
|
|
725
681
|
const runSteps = async (steps, releaseId, runOpts) => {
|
|
726
682
|
const ctx = buildCtx(releaseId, {
|
|
@@ -786,9 +742,7 @@ var createDeployer = (options) => {
|
|
|
786
742
|
};
|
|
787
743
|
};
|
|
788
744
|
const ensureRoot = async () => {
|
|
789
|
-
const result = await options.target.exec(`mkdir -p ${releasesPath}`, {
|
|
790
|
-
timeoutMs: 1e4
|
|
791
|
-
});
|
|
745
|
+
const result = await options.target.exec(`mkdir -p ${releasesPath}`, { timeoutMs: 1e4 });
|
|
792
746
|
requireSuccess("ensureRoot", result);
|
|
793
747
|
};
|
|
794
748
|
const activeProcessContext = () => ({
|
|
@@ -852,9 +806,7 @@ var createDeployer = (options) => {
|
|
|
852
806
|
return { removed: [] };
|
|
853
807
|
const removed = all.slice(0, all.length - keep);
|
|
854
808
|
for (const releaseId of removed) {
|
|
855
|
-
await options.target.exec(`rm -rf ${releasesPath}/${releaseId}`, {
|
|
856
|
-
timeoutMs: 60000
|
|
857
|
-
});
|
|
809
|
+
await options.target.exec(`rm -rf ${releasesPath}/${releaseId}`, { timeoutMs: 60000 });
|
|
858
810
|
}
|
|
859
811
|
return { removed };
|
|
860
812
|
},
|
|
@@ -909,5 +861,5 @@ export {
|
|
|
909
861
|
EdgeIngressValidationError
|
|
910
862
|
};
|
|
911
863
|
|
|
912
|
-
//# debugId=
|
|
864
|
+
//# debugId=671ADD60C650540564756E2164756E21
|
|
913
865
|
//# sourceMappingURL=index.js.map
|