@krovacloud/sdk 0.3.10 → 0.4.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/CHANGELOG.md CHANGED
@@ -5,6 +5,42 @@ All notable changes to `@krovacloud/sdk` are documented here. This project adher
5
5
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
6
6
 
7
7
 
8
+ ## 0.4.0
9
+
10
+ ### Changed
11
+
12
+ - **BREAKING** — `domains.create()` now resolves to `{ domain, records }`
13
+ instead of `Domain`. The records are the DNS entries you must publish for the
14
+ domain to work, so you can create them in the same run.
15
+
16
+ Why it changed rather than being added alongside: for a wildcard, two of the
17
+ three records (the ownership `TXT` and the `_acme-challenge` delegation) were
18
+ not derivable from anything the SDK returned. An integration had to read the
19
+ record shapes out of the docs and hope they still matched the server, which is
20
+ the arrangement that eventually breaks quietly.
21
+
22
+ ```diff
23
+ - const domain = await client.domains.create(spaceId, cubeId, { domain, port });
24
+ + const { domain, records } = await client.domains.create(spaceId, cubeId, { domain, port });
25
+ ```
26
+
27
+ ### Added
28
+
29
+ - `domains.records(spaceId, cubeId, mappingId)` — the same records, each checked
30
+ against live DNS. Poll it after publishing them; `summary.complete` turns true
31
+ only once every record is `found`. Rate limited, because it performs real
32
+ lookups.
33
+ - `DnsRecord` and `DnsRecordStatus` types.
34
+
35
+ Each record carries `mustBeGrey` and `proxyOk`, which are deliberate
36
+ opposites: the routing record may sit behind Cloudflare's proxy, the
37
+ `_acme-challenge` record must not. Automation needs both — one alone would let
38
+ you confidently orange-cloud the single record that has to stay grey.
39
+
40
+ `state: "missing"` means NOT PUBLISHED YET — the expected state before you
41
+ create the record, never an error. `state: "unknown"` means the lookup could
42
+ not be completed, which is never a statement about your DNS.
43
+
8
44
  ## 0.3.2
9
45
 
10
46
  ### Changed
package/README.md CHANGED
@@ -49,6 +49,14 @@ const cube = await krova.cubes.create("space_123", {
49
49
  console.log(`Created cube ${cube.id} (${cube.state})`);
50
50
  console.log(` ${cube.resources.vcpu} vCPU / ${cube.resources.ramGb} GB RAM, image ${cube.image}`);
51
51
 
52
+ // Everything needed to SSH in — including WHICH USER to log in as.
53
+ // Read `user`; do not derive it from `image`. It is "ubuntu" or "debian" on
54
+ // Cubes from images that ship a default user (both with passwordless sudo)
55
+ // and "root" on Cubes created before that change, so the image id cannot
56
+ // tell you. `cube.sshUser` on the Cube object carries the same value.
57
+ const ssh = await krova.cubes.ssh("space_123", cube.id);
58
+ console.log(`ssh ${ssh.user}@${ssh.host} -p ${ssh.port}`);
59
+
52
60
  // Power it off, then start it again
53
61
  await krova.cubes.powerOff("space_123", cube.id);
54
62
  await krova.cubes.wake("space_123", cube.id);
package/dist/index.cjs CHANGED
@@ -323,7 +323,19 @@ var KrovaClient = class {
323
323
  if (error !== void 0 || !response.ok) throw krovaErrorFrom(response, error);
324
324
  return data?.domains ?? [];
325
325
  },
326
- /** Attach a custom domain to a Cube. `domain` + `port` are required. */
326
+ /**
327
+ * Attach a custom domain to a Cube. `domain` + `port` are required.
328
+ *
329
+ * Returns the domain AND the DNS records you must publish for it to work —
330
+ * so you can create them in the same run, without a second call and without
331
+ * hard-coding record shapes. A wildcard needs three; an exact host needs one.
332
+ *
333
+ * ⛔ BREAKING in 0.4.0: this used to resolve to `Domain`. It now resolves to
334
+ * `{ domain, records }`, because for a wildcard two of the three records
335
+ * (the ownership TXT and the `_acme-challenge` delegation) were not
336
+ * derivable from anything the SDK returned — an integration had to read
337
+ * them out of the docs and hope they still matched the server.
338
+ */
327
339
  create: async (spaceId, cubeId, body) => {
328
340
  const { data, error, response } = await this.raw.POST(
329
341
  "/spaces/{spaceId}/cubes/{cubeId}/domains",
@@ -332,7 +344,24 @@ var KrovaClient = class {
332
344
  if (error !== void 0 || !response.ok) throw krovaErrorFrom(response, error);
333
345
  if (!data?.domain)
334
346
  throw krovaErrorFrom(response, { error: "Create domain response had no `domain`." });
335
- return data.domain;
347
+ return { domain: data.domain, records: data.records ?? [] };
348
+ },
349
+ /**
350
+ * The DNS records a domain needs, each checked against live DNS.
351
+ *
352
+ * Poll this after publishing them: `summary.complete` turns true only once
353
+ * every record is `found`. Each call performs real DNS lookups and is rate
354
+ * limited, so poll on an interval rather than in a tight loop.
355
+ */
356
+ records: async (spaceId, cubeId, mappingId) => {
357
+ const { data, error, response } = await this.raw.GET(
358
+ "/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}/records",
359
+ { params: { path: { spaceId, cubeId, mappingId } } }
360
+ );
361
+ if (error !== void 0 || !response.ok) throw krovaErrorFrom(response, error);
362
+ if (!data)
363
+ throw krovaErrorFrom(response, { error: "Domain records response was empty." });
364
+ return data;
336
365
  },
337
366
  /** Update a domain's per-domain proxy settings. */
338
367
  update: async (spaceId, cubeId, mappingId, body) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/error.ts","../src/client.ts"],"names":["createClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * The error body shape returned by the Krova Cloud API.\n *\n * Per the OpenAPI spec (`components.schemas.Error`), every non-2xx response\n * body is `{ \"error\": string }`. Additional fields may appear over time, so\n * we keep the type open.\n */\nexport interface KrovaErrorBody {\n error?: string;\n [key: string]: unknown;\n}\n\n/**\n * Error thrown by the ergonomic {@link KrovaClient} helpers when the API\n * responds with a non-2xx status.\n *\n * The raw openapi-fetch client (`client.raw`) never throws — it returns\n * `{ data, error, response }`. The helpers wrap that and throw `KrovaError`\n * so callers can `try/catch`.\n */\nexport class KrovaError extends Error {\n /** HTTP status code of the failing response. */\n readonly status: number;\n\n /**\n * A machine-readable error code, when the API surfaces one via the\n * `X-Error-Code` response header. The documented error body only carries a\n * human-readable `error` string, so this is best-effort.\n */\n readonly code?: string;\n\n /**\n * The request id from the `X-Request-Id` response header, when present.\n * Useful when contacting Krova Cloud support about a specific failure.\n */\n readonly requestId?: string;\n\n /** The parsed JSON error body, when the response had one. */\n readonly body?: KrovaErrorBody;\n\n /** The raw `Response` object, for callers that need headers/url/etc. */\n readonly response?: Response;\n\n constructor(\n message: string,\n init: {\n status: number;\n code?: string;\n requestId?: string;\n body?: KrovaErrorBody;\n response?: Response;\n },\n ) {\n super(message);\n this.name = \"KrovaError\";\n this.status = init.status;\n this.code = init.code;\n this.requestId = init.requestId;\n this.body = init.body;\n this.response = init.response;\n // Restore prototype chain for instanceof across compilation targets.\n Object.setPrototypeOf(this, KrovaError.prototype);\n }\n}\n\n/**\n * Build a {@link KrovaError} from a failing response + parsed error body.\n */\nexport function krovaErrorFrom(\n response: Response,\n body: KrovaErrorBody | undefined,\n): KrovaError {\n const message =\n (typeof body?.error === \"string\" && body.error) ||\n response.statusText ||\n `Request failed with status ${response.status}`;\n return new KrovaError(message, {\n status: response.status,\n code: response.headers.get(\"x-error-code\") ?? undefined,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n body,\n response,\n });\n}\n","import createClient, { type Client, type Middleware } from \"openapi-fetch\";\nimport { krovaErrorFrom } from \"./error.js\";\nimport type { components, paths } from \"./generated/types.js\";\n\n/** The Cube resource, as defined in the Krova Cloud OpenAPI spec. */\nexport type Cube = components[\"schemas\"][\"Cube\"];\n\n/** A region with available capacity (from the catalog). */\nexport type Region = components[\"schemas\"][\"Region\"];\n\n/** A selectable OS image (from the catalog). */\nexport type Image = components[\"schemas\"][\"Image\"];\n\n/** A volume-pricing tier (from the catalog). */\nexport type PricingTier = components[\"schemas\"][\"PricingTier\"];\n\n/** Pagination envelope returned alongside a Cube list. */\nexport type Pagination = components[\"schemas\"][\"Pagination\"];\n\n/** A Space — the tenancy an API key is scoped to. */\nexport type Space = components[\"schemas\"][\"Space\"];\n\n/** A Cube's SSH connection info (host, port, user, and pinned host keys). */\nexport type CubeSshInfo = components[\"schemas\"][\"CubeSshInfo\"];\n\n/** A custom domain attached to a Cube. */\nexport type Domain = components[\"schemas\"][\"Domain\"];\n\n/** A snapshot of a Cube's disk. */\nexport type Snapshot = components[\"schemas\"][\"Snapshot\"];\n\n/** A TCP port mapping exposing a Cube port on the host. */\nexport type TcpMapping = components[\"schemas\"][\"TcpMapping\"];\n\n/** Request body for attaching a custom domain to a Cube. */\nexport type CreateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for updating a custom domain's proxy settings. */\nexport type UpdateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for creating a TCP port mapping. */\nexport type CreateTcpMappingInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Default API base URL — the single `servers[0].url` from the OpenAPI spec. */\nexport const DEFAULT_BASE_URL = \"https://krova.cloud/api/v1\";\n\n/**\n * How the API key is presented to the server.\n *\n * - `\"x-api-key\"` (default) — `X-API-KEY: <key>`, matching the spec's\n * `components.securitySchemes.ApiKeyAuth` (an `apiKey` header named\n * `X-API-KEY`).\n * - `\"bearer\"` — `Authorization: Bearer <key>`, for gateways that expect it.\n */\nexport type AuthScheme = \"x-api-key\" | \"bearer\";\n\nexport interface KrovaClientOptions {\n /**\n * Your Krova Cloud API key (a `kro_...` token). Keys are scoped per Space\n * and inherit the permissions of the membership that created them.\n */\n apiKey: string;\n /** Override the API base URL. Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /**\n * Auth header scheme. Defaults to `\"x-api-key\"` (the spec's scheme).\n */\n authScheme?: AuthScheme;\n /**\n * Max automatic retries on retryable statuses (429, 503).\n * Defaults to 2. Set to 0 to disable retries.\n */\n maxRetries?: number;\n /**\n * A custom `fetch` implementation (e.g. for tests or a proxy). Defaults to\n * the global `fetch`.\n */\n fetch?: typeof fetch;\n}\n\n/** Statuses the retry middleware treats as transient. */\nconst RETRYABLE_STATUSES = new Set([429, 503]);\n/** Fallback backoff (ms) when the server sends no `Retry-After` header. */\nconst BASE_BACKOFF_MS = 500;\n/** Cap on any single backoff wait (ms), to keep retries \"small but real\". */\nconst MAX_BACKOFF_MS = 10_000;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Parse a `Retry-After` header (RFC 7231): either delta-seconds or an\n * HTTP-date. Returns milliseconds to wait, or `null` if absent/unparseable.\n */\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null;\n const seconds = Number(headerValue);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n const dateMs = Date.parse(headerValue);\n if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());\n return null;\n}\n\nfunction authMiddleware(apiKey: string, scheme: AuthScheme): Middleware {\n return {\n onRequest({ request }) {\n if (scheme === \"bearer\") {\n request.headers.set(\"Authorization\", `Bearer ${apiKey}`);\n } else {\n request.headers.set(\"X-API-KEY\", apiKey);\n }\n return request;\n },\n };\n}\n\n/**\n * Retry middleware: on a retryable status, wait (honoring `Retry-After` when\n * present, else exponential backoff) and re-issue the request.\n *\n * A retried request may have a body (POST/PUT/DELETE — exactly the mutating,\n * rate-limited endpoints). By the time `onResponse` runs, the request that was\n * handed to `fetch` has had its body stream consumed, so `request.clone()` here\n * throws `TypeError: unusable`. To re-issue it we stash a *pristine* clone in\n * `onRequest` — captured before the body is read — keyed by openapi-fetch's\n * per-request `id`, and clone from that pristine copy on each attempt.\n */\nfunction retryMiddleware(maxRetries: number, doFetch: typeof fetch): Middleware {\n const pristine = new Map<string, Request>();\n return {\n onRequest({ request, id }) {\n pristine.set(id, request.clone());\n return request;\n },\n onError({ id }) {\n // fetch rejected (network error) — no onResponse will fire; don't leak.\n pristine.delete(id);\n },\n async onResponse({ request, response, id }) {\n const original = pristine.get(id) ?? request;\n pristine.delete(id);\n if (maxRetries <= 0 || !RETRYABLE_STATUSES.has(response.status)) {\n return response;\n }\n let current = response;\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n if (!RETRYABLE_STATUSES.has(current.status)) break;\n const retryAfterMs = parseRetryAfterMs(current.headers.get(\"retry-after\"));\n const backoff = Math.min(BASE_BACKOFF_MS * 2 ** (attempt - 1), MAX_BACKOFF_MS);\n // Cap the wait — including a server-supplied `Retry-After` — so a hostile\n // or misconfigured server can't park the client for minutes/hours.\n await sleep(Math.min(retryAfterMs ?? backoff, MAX_BACKOFF_MS));\n // Re-issue from the pristine clone; `.clone()` keeps it reusable across\n // multiple attempts.\n current = await doFetch(original.clone());\n }\n return current;\n },\n };\n}\n\n/**\n * A typed client for the Krova Cloud API.\n *\n * @example\n * ```ts\n * const krova = new KrovaClient({ apiKey: \"kro_...\" });\n * const cubes = await krova.cubes.list(\"space_123\");\n * ```\n */\nexport class KrovaClient {\n /**\n * The underlying openapi-fetch client — a fully typed escape hatch to every\n * path in the spec. Returns `{ data, error, response }` and never throws.\n *\n * @example\n * ```ts\n * const { data, error } = await krova.raw.GET(\n * \"/spaces/{spaceId}/cubes/{cubeId}\",\n * { params: { path: { spaceId, cubeId } } },\n * );\n * ```\n */\n readonly raw: Client<paths>;\n\n /** The resolved base URL in use. */\n readonly baseUrl: string;\n\n constructor(options: KrovaClientOptions) {\n if (!options?.apiKey) {\n throw new Error(\"KrovaClient: `apiKey` is required.\");\n }\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const doFetch = options.fetch ?? globalThis.fetch;\n const maxRetries = options.maxRetries ?? 2;\n\n this.raw = createClient<paths>({\n baseUrl: this.baseUrl,\n // SECURITY: never auto-follow redirects. The Krova Cloud API is a plain\n // JSON API and never legitimately 3xx's a data call. Following a redirect\n // would resend the `X-API-KEY` header to the redirect target — and unlike\n // `Authorization`, `Cookie`, and `Proxy-Authorization`, the Fetch spec does\n // NOT strip a custom header like `X-API-KEY` on a cross-origin redirect\n // (verified against undici/Node fetch). A compromised/misconfigured proxy,\n // an open-redirect on the API, or a MITM could otherwise exfiltrate the key\n // to an attacker's host. With `\"manual\"`, a redirect comes back as a\n // non-ok response and the helpers throw `KrovaError` instead of leaking.\n redirect: \"manual\",\n ...(options.fetch ? { fetch: options.fetch } : {}),\n });\n this.raw.use(authMiddleware(options.apiKey, options.authScheme ?? \"x-api-key\"));\n if (maxRetries > 0) {\n this.raw.use(retryMiddleware(maxRetries, doFetch));\n }\n }\n\n // ---------------------------------------------------------------------------\n // Cubes\n // ---------------------------------------------------------------------------\n\n readonly cubes = {\n /** List Cubes in a Space, with pagination metadata. */\n list: async (spaceId: string) => {\n const { data, error, response } = await this.raw.GET(\"/spaces/{spaceId}/cubes\", {\n params: { path: { spaceId } },\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"List Cubes response was empty.\" });\n return data;\n },\n\n /**\n * Create a Cube. Returns the created {@link Cube}.\n *\n * @param spaceId Target Space id.\n * @param body Cube spec — `{ name, image, resources, sshPublicKey, ... }`.\n * @param opts Optional `idempotencyKey` (max 255 chars, scoped per space).\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n opts?: { idempotencyKey?: string },\n ): Promise<Cube> => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes\", {\n params: {\n path: { spaceId },\n ...(opts?.idempotencyKey\n ? { header: { \"Idempotency-Key\": opts.idempotencyKey } }\n : {}),\n },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Create Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /** Get a single Cube. Returns the {@link Cube}. */\n get: async (spaceId: string, cubeId: string): Promise<Cube> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Get Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /**\n * Update the IN-CUBE port that SSH is forwarded to.\n *\n * `cubePort` is the port **inside** the Cube that sshd listens on — NOT the\n * host port you connect to. The host port is allocated by Krova and is not\n * changed by this call. Pointing this at a port nothing is listening on\n * inside the Cube will silently make SSH unreachable; the default is 22.\n *\n * The Krova Cloud API exposes no general Cube-mutation endpoint; the only\n * mutable Cube field over the API is this port, via\n * `PUT /spaces/{spaceId}/cubes/{cubeId}/ssh-port`. This helper maps to that\n * endpoint. (Compute resize / rename are not part of the public API.)\n */\n update: async (\n spaceId: string,\n cubeId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\"][\"put\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ): Promise<unknown> => {\n const { data, error, response } = await this.raw.PUT(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Delete a Cube (asynchronous — deletion is enqueued). */\n delete: async (spaceId: string, cubeId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Delete Cube response was empty.\" });\n return data;\n },\n\n /** Power off a running Cube (asynchronous — power-off is enqueued). The Cube\n * becomes `stopped` (its host RAM is freed); start it again with `wake`. */\n powerOff: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/power-off\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Start a stopped Cube (asynchronous — start is enqueued). */\n /**\n * Restart a Cube (COLD restart).\n *\n * The hypervisor process is stopped and relaunched, so the Cube boots\n * against the host's current kernel. This is the only way a Cube picks up a\n * refreshed guest kernel after a platform image update — a `reboot` issued\n * INSIDE the Cube cannot do it, because Firecracker treats a guest reboot as\n * a shutdown and the kernel is supplied externally by the host.\n *\n * Disk state is preserved; only the kernel changes. The Cube must be\n * `running`. Concurrent restarts of the same Cube are rejected (409) rather\n * than queued twice.\n */\n restart: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restart\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n wake: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/wake\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Get a Cube's SSH connection info — host, port, login user, and (when\n * available) the pinned host public keys for strict host-key verification.\n */\n ssh: async (spaceId: string, cubeId: string): Promise<CubeSshInfo> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Cube SSH-info response was empty.\" });\n return data;\n },\n\n /**\n * Restore a Cube's disk from one of its {@link Snapshot}s (asynchronous —\n * the restore is enqueued). The Cube's current disk is replaced.\n */\n restore: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restore\",\n { params: { path: { spaceId, cubeId } }, body: { snapshotId } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n /**\n * Resolve the {@link Space} this API key is scoped to — so you don't have to\n * hardcode a `spaceId`. Handy right after constructing the client:\n *\n * @example\n * ```ts\n * const space = await krova.getSpace();\n * const cubes = await krova.cubes.list(space.id);\n * ```\n */\n async getSpace(): Promise<Space> {\n const { data, error, response } = await this.raw.GET(\"/space\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Space response was empty.\" });\n return data;\n }\n\n // ---------------------------------------------------------------------------\n // Custom domains\n // ---------------------------------------------------------------------------\n\n readonly domains = {\n /** List the custom domains attached to a Cube. */\n list: async (spaceId: string, cubeId: string): Promise<Domain[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.domains ?? [];\n },\n\n /** Attach a custom domain to a Cube. `domain` + `port` are required. */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateDomainInput,\n ): Promise<Domain> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Create domain response had no `domain`.\" });\n return data.domain;\n },\n\n /** Update a domain's per-domain proxy settings. */\n update: async (\n spaceId: string,\n cubeId: string,\n mappingId: string,\n body: UpdateDomainInput,\n ): Promise<Domain> => {\n const { data, error, response } = await this.raw.PATCH(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Update domain response had no `domain`.\" });\n return data.domain;\n },\n\n /** Detach a custom domain from a Cube. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Snapshots\n // ---------------------------------------------------------------------------\n\n readonly snapshots = {\n /** List a Cube's snapshots. */\n list: async (spaceId: string, cubeId: string): Promise<Snapshot[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.snapshots ?? [];\n },\n\n /** Create a snapshot of a Cube's disk (asynchronous — enqueued). */\n create: async (\n spaceId: string,\n cubeId: string,\n body?: { name?: string },\n ): Promise<Snapshot> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } }, body: body ?? {} },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.snapshot)\n throw krovaErrorFrom(response, { error: \"Create snapshot response had no `snapshot`.\" });\n return data.snapshot;\n },\n\n /** Delete a snapshot. */\n delete: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots/{snapshotId}\",\n { params: { path: { spaceId, cubeId, snapshotId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // TCP port mappings\n // ---------------------------------------------------------------------------\n\n readonly tcpMappings = {\n /** List a Cube's TCP port mappings. */\n list: async (spaceId: string, cubeId: string): Promise<TcpMapping[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.tcpMappings ?? [];\n },\n\n /**\n * Create a TCP port mapping exposing a Cube port on the host. `cubePort` is\n * required; `whitelistIps` optionally restricts who can reach it.\n */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateTcpMappingInput,\n ): Promise<TcpMapping> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.tcpMapping)\n throw krovaErrorFrom(response, { error: \"Create TCP mapping response had no `tcpMapping`.\" });\n return data.tcpMapping;\n },\n\n /** Delete a TCP port mapping. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Imports & backups (.cube archive import / export)\n // ---------------------------------------------------------------------------\n\n readonly imports = {\n /**\n * Start importing a `.cube` archive into a new Cube. Returns the multipart\n * upload target (`importId`, `uploadId`, presigned `parts`, …). Upload the\n * archive to those URLs, then call {@link imports.complete}.\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes/imports\", {\n params: { path: { spaceId } },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Get an in-progress or completed import by id. */\n get: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Finish an import after the archive has been uploaded — provisions the\n * Cube. Pass the uploaded `parts` (partNumber + etag) and the resolved\n * `config`.\n */\n complete: async (\n spaceId: string,\n importId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports/{importId}/complete\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/imports/{importId}/complete\",\n { params: { path: { spaceId, importId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Cancel an in-progress import. */\n cancel: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n readonly backups = {\n /** Get a time-limited download URL for a backup `.cube` archive. */\n download: async (spaceId: string, backupId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/backups/{backupId}/download\",\n { params: { path: { spaceId, backupId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Public catalog (no auth required by the API, but the key is harmless)\n // ---------------------------------------------------------------------------\n\n readonly catalog = {\n /** List regions with available capacity. */\n regions: async () => {\n const { data, error, response } = await this.raw.GET(\"/regions\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Regions response was empty.\" });\n return data;\n },\n\n /** List available OS images. */\n images: async () => {\n const { data, error, response } = await this.raw.GET(\"/images\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Images response was empty.\" });\n return data;\n },\n\n /** Per-resource hourly rates and volume pricing tiers. */\n pricing: async () => {\n const { data, error, response } = await this.raw.GET(\"/pricing\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Pricing response was empty.\" });\n return data;\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/error.ts","../src/client.ts"],"names":["createClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * The error body shape returned by the Krova Cloud API.\n *\n * Per the OpenAPI spec (`components.schemas.Error`), every non-2xx response\n * body is `{ \"error\": string }`. Additional fields may appear over time, so\n * we keep the type open.\n */\nexport interface KrovaErrorBody {\n error?: string;\n [key: string]: unknown;\n}\n\n/**\n * Error thrown by the ergonomic {@link KrovaClient} helpers when the API\n * responds with a non-2xx status.\n *\n * The raw openapi-fetch client (`client.raw`) never throws — it returns\n * `{ data, error, response }`. The helpers wrap that and throw `KrovaError`\n * so callers can `try/catch`.\n */\nexport class KrovaError extends Error {\n /** HTTP status code of the failing response. */\n readonly status: number;\n\n /**\n * A machine-readable error code, when the API surfaces one via the\n * `X-Error-Code` response header. The documented error body only carries a\n * human-readable `error` string, so this is best-effort.\n */\n readonly code?: string;\n\n /**\n * The request id from the `X-Request-Id` response header, when present.\n * Useful when contacting Krova Cloud support about a specific failure.\n */\n readonly requestId?: string;\n\n /** The parsed JSON error body, when the response had one. */\n readonly body?: KrovaErrorBody;\n\n /** The raw `Response` object, for callers that need headers/url/etc. */\n readonly response?: Response;\n\n constructor(\n message: string,\n init: {\n status: number;\n code?: string;\n requestId?: string;\n body?: KrovaErrorBody;\n response?: Response;\n },\n ) {\n super(message);\n this.name = \"KrovaError\";\n this.status = init.status;\n this.code = init.code;\n this.requestId = init.requestId;\n this.body = init.body;\n this.response = init.response;\n // Restore prototype chain for instanceof across compilation targets.\n Object.setPrototypeOf(this, KrovaError.prototype);\n }\n}\n\n/**\n * Build a {@link KrovaError} from a failing response + parsed error body.\n */\nexport function krovaErrorFrom(\n response: Response,\n body: KrovaErrorBody | undefined,\n): KrovaError {\n const message =\n (typeof body?.error === \"string\" && body.error) ||\n response.statusText ||\n `Request failed with status ${response.status}`;\n return new KrovaError(message, {\n status: response.status,\n code: response.headers.get(\"x-error-code\") ?? undefined,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n body,\n response,\n });\n}\n","import createClient, { type Client, type Middleware } from \"openapi-fetch\";\nimport { krovaErrorFrom } from \"./error.js\";\nimport type { components, paths } from \"./generated/types.js\";\n\n/** The Cube resource, as defined in the Krova Cloud OpenAPI spec. */\nexport type Cube = components[\"schemas\"][\"Cube\"];\n\n/** A region with available capacity (from the catalog). */\nexport type Region = components[\"schemas\"][\"Region\"];\n\n/** A selectable OS image (from the catalog). */\nexport type Image = components[\"schemas\"][\"Image\"];\n\n/** A volume-pricing tier (from the catalog). */\nexport type PricingTier = components[\"schemas\"][\"PricingTier\"];\n\n/** Pagination envelope returned alongside a Cube list. */\nexport type Pagination = components[\"schemas\"][\"Pagination\"];\n\n/** A Space — the tenancy an API key is scoped to. */\nexport type Space = components[\"schemas\"][\"Space\"];\n\n/** A Cube's SSH connection info (host, port, user, and pinned host keys). */\nexport type CubeSshInfo = components[\"schemas\"][\"CubeSshInfo\"];\n\n/** A custom domain attached to a Cube. */\nexport type Domain = components[\"schemas\"][\"Domain\"];\n\n/**\n * One DNS record you must publish for a domain to work.\n *\n * An ordinary subdomain needs one CNAME. A wildcard needs three: an ownership\n * TXT, the routing CNAME, and an `_acme-challenge` CNAME that lets Krova issue\n * and renew its certificate.\n *\n * ⛔ `mustBeGrey` and `proxyOk` are deliberate OPPOSITES, and automation needs\n * both. The routing record may sit behind Cloudflare's proxy (orange); the\n * `_acme-challenge` record must not, because a proxied one answers with\n * Cloudflare's addresses and the certificate authority finds nothing there.\n */\nexport type DnsRecord = components[\"schemas\"][\"DnsRecord\"];\n\n/**\n * A {@link DnsRecord} plus what Krova can currently see in public DNS.\n *\n * ⛔ `state: \"missing\"` means NOT PUBLISHED YET — the expected state before you\n * create the record, never an error. `state: \"unknown\"` means Krova could not\n * complete the lookup, which is never a statement about your DNS. Surfacing\n * either to your own users as a failure would be wrong.\n */\nexport type DnsRecordStatus = components[\"schemas\"][\"DnsRecordStatus\"];\n\n/** A snapshot of a Cube's disk. */\nexport type Snapshot = components[\"schemas\"][\"Snapshot\"];\n\n/** A TCP port mapping exposing a Cube port on the host. */\nexport type TcpMapping = components[\"schemas\"][\"TcpMapping\"];\n\n/** Request body for attaching a custom domain to a Cube. */\nexport type CreateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for updating a custom domain's proxy settings. */\nexport type UpdateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for creating a TCP port mapping. */\nexport type CreateTcpMappingInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Default API base URL — the single `servers[0].url` from the OpenAPI spec. */\nexport const DEFAULT_BASE_URL = \"https://krova.cloud/api/v1\";\n\n/**\n * How the API key is presented to the server.\n *\n * - `\"x-api-key\"` (default) — `X-API-KEY: <key>`, matching the spec's\n * `components.securitySchemes.ApiKeyAuth` (an `apiKey` header named\n * `X-API-KEY`).\n * - `\"bearer\"` — `Authorization: Bearer <key>`, for gateways that expect it.\n */\nexport type AuthScheme = \"x-api-key\" | \"bearer\";\n\nexport interface KrovaClientOptions {\n /**\n * Your Krova Cloud API key (a `kro_...` token). Keys are scoped per Space\n * and inherit the permissions of the membership that created them.\n */\n apiKey: string;\n /** Override the API base URL. Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /**\n * Auth header scheme. Defaults to `\"x-api-key\"` (the spec's scheme).\n */\n authScheme?: AuthScheme;\n /**\n * Max automatic retries on retryable statuses (429, 503).\n * Defaults to 2. Set to 0 to disable retries.\n */\n maxRetries?: number;\n /**\n * A custom `fetch` implementation (e.g. for tests or a proxy). Defaults to\n * the global `fetch`.\n */\n fetch?: typeof fetch;\n}\n\n/** Statuses the retry middleware treats as transient. */\nconst RETRYABLE_STATUSES = new Set([429, 503]);\n/** Fallback backoff (ms) when the server sends no `Retry-After` header. */\nconst BASE_BACKOFF_MS = 500;\n/** Cap on any single backoff wait (ms), to keep retries \"small but real\". */\nconst MAX_BACKOFF_MS = 10_000;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Parse a `Retry-After` header (RFC 7231): either delta-seconds or an\n * HTTP-date. Returns milliseconds to wait, or `null` if absent/unparseable.\n */\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null;\n const seconds = Number(headerValue);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n const dateMs = Date.parse(headerValue);\n if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());\n return null;\n}\n\nfunction authMiddleware(apiKey: string, scheme: AuthScheme): Middleware {\n return {\n onRequest({ request }) {\n if (scheme === \"bearer\") {\n request.headers.set(\"Authorization\", `Bearer ${apiKey}`);\n } else {\n request.headers.set(\"X-API-KEY\", apiKey);\n }\n return request;\n },\n };\n}\n\n/**\n * Retry middleware: on a retryable status, wait (honoring `Retry-After` when\n * present, else exponential backoff) and re-issue the request.\n *\n * A retried request may have a body (POST/PUT/DELETE — exactly the mutating,\n * rate-limited endpoints). By the time `onResponse` runs, the request that was\n * handed to `fetch` has had its body stream consumed, so `request.clone()` here\n * throws `TypeError: unusable`. To re-issue it we stash a *pristine* clone in\n * `onRequest` — captured before the body is read — keyed by openapi-fetch's\n * per-request `id`, and clone from that pristine copy on each attempt.\n */\nfunction retryMiddleware(maxRetries: number, doFetch: typeof fetch): Middleware {\n const pristine = new Map<string, Request>();\n return {\n onRequest({ request, id }) {\n pristine.set(id, request.clone());\n return request;\n },\n onError({ id }) {\n // fetch rejected (network error) — no onResponse will fire; don't leak.\n pristine.delete(id);\n },\n async onResponse({ request, response, id }) {\n const original = pristine.get(id) ?? request;\n pristine.delete(id);\n if (maxRetries <= 0 || !RETRYABLE_STATUSES.has(response.status)) {\n return response;\n }\n let current = response;\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n if (!RETRYABLE_STATUSES.has(current.status)) break;\n const retryAfterMs = parseRetryAfterMs(current.headers.get(\"retry-after\"));\n const backoff = Math.min(BASE_BACKOFF_MS * 2 ** (attempt - 1), MAX_BACKOFF_MS);\n // Cap the wait — including a server-supplied `Retry-After` — so a hostile\n // or misconfigured server can't park the client for minutes/hours.\n await sleep(Math.min(retryAfterMs ?? backoff, MAX_BACKOFF_MS));\n // Re-issue from the pristine clone; `.clone()` keeps it reusable across\n // multiple attempts.\n current = await doFetch(original.clone());\n }\n return current;\n },\n };\n}\n\n/**\n * A typed client for the Krova Cloud API.\n *\n * @example\n * ```ts\n * const krova = new KrovaClient({ apiKey: \"kro_...\" });\n * const cubes = await krova.cubes.list(\"space_123\");\n * ```\n */\nexport class KrovaClient {\n /**\n * The underlying openapi-fetch client — a fully typed escape hatch to every\n * path in the spec. Returns `{ data, error, response }` and never throws.\n *\n * @example\n * ```ts\n * const { data, error } = await krova.raw.GET(\n * \"/spaces/{spaceId}/cubes/{cubeId}\",\n * { params: { path: { spaceId, cubeId } } },\n * );\n * ```\n */\n readonly raw: Client<paths>;\n\n /** The resolved base URL in use. */\n readonly baseUrl: string;\n\n constructor(options: KrovaClientOptions) {\n if (!options?.apiKey) {\n throw new Error(\"KrovaClient: `apiKey` is required.\");\n }\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const doFetch = options.fetch ?? globalThis.fetch;\n const maxRetries = options.maxRetries ?? 2;\n\n this.raw = createClient<paths>({\n baseUrl: this.baseUrl,\n // SECURITY: never auto-follow redirects. The Krova Cloud API is a plain\n // JSON API and never legitimately 3xx's a data call. Following a redirect\n // would resend the `X-API-KEY` header to the redirect target — and unlike\n // `Authorization`, `Cookie`, and `Proxy-Authorization`, the Fetch spec does\n // NOT strip a custom header like `X-API-KEY` on a cross-origin redirect\n // (verified against undici/Node fetch). A compromised/misconfigured proxy,\n // an open-redirect on the API, or a MITM could otherwise exfiltrate the key\n // to an attacker's host. With `\"manual\"`, a redirect comes back as a\n // non-ok response and the helpers throw `KrovaError` instead of leaking.\n redirect: \"manual\",\n ...(options.fetch ? { fetch: options.fetch } : {}),\n });\n this.raw.use(authMiddleware(options.apiKey, options.authScheme ?? \"x-api-key\"));\n if (maxRetries > 0) {\n this.raw.use(retryMiddleware(maxRetries, doFetch));\n }\n }\n\n // ---------------------------------------------------------------------------\n // Cubes\n // ---------------------------------------------------------------------------\n\n readonly cubes = {\n /** List Cubes in a Space, with pagination metadata. */\n list: async (spaceId: string) => {\n const { data, error, response } = await this.raw.GET(\"/spaces/{spaceId}/cubes\", {\n params: { path: { spaceId } },\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"List Cubes response was empty.\" });\n return data;\n },\n\n /**\n * Create a Cube. Returns the created {@link Cube}.\n *\n * @param spaceId Target Space id.\n * @param body Cube spec — `{ name, image, resources, sshPublicKey, ... }`.\n * @param opts Optional `idempotencyKey` (max 255 chars, scoped per space).\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n opts?: { idempotencyKey?: string },\n ): Promise<Cube> => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes\", {\n params: {\n path: { spaceId },\n ...(opts?.idempotencyKey\n ? { header: { \"Idempotency-Key\": opts.idempotencyKey } }\n : {}),\n },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Create Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /** Get a single Cube. Returns the {@link Cube}. */\n get: async (spaceId: string, cubeId: string): Promise<Cube> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Get Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /**\n * Update the IN-CUBE port that SSH is forwarded to.\n *\n * `cubePort` is the port **inside** the Cube that sshd listens on — NOT the\n * host port you connect to. The host port is allocated by Krova and is not\n * changed by this call. Pointing this at a port nothing is listening on\n * inside the Cube will silently make SSH unreachable; the default is 22.\n *\n * The Krova Cloud API exposes no general Cube-mutation endpoint; the only\n * mutable Cube field over the API is this port, via\n * `PUT /spaces/{spaceId}/cubes/{cubeId}/ssh-port`. This helper maps to that\n * endpoint. (Compute resize / rename are not part of the public API.)\n */\n update: async (\n spaceId: string,\n cubeId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\"][\"put\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ): Promise<unknown> => {\n const { data, error, response } = await this.raw.PUT(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Delete a Cube (asynchronous — deletion is enqueued). */\n delete: async (spaceId: string, cubeId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Delete Cube response was empty.\" });\n return data;\n },\n\n /** Power off a running Cube (asynchronous — power-off is enqueued). The Cube\n * becomes `stopped` (its host RAM is freed); start it again with `wake`. */\n powerOff: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/power-off\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Start a stopped Cube (asynchronous — start is enqueued). */\n /**\n * Restart a Cube (COLD restart).\n *\n * The hypervisor process is stopped and relaunched, so the Cube boots\n * against the host's current kernel. This is the only way a Cube picks up a\n * refreshed guest kernel after a platform image update — a `reboot` issued\n * INSIDE the Cube cannot do it, because Firecracker treats a guest reboot as\n * a shutdown and the kernel is supplied externally by the host.\n *\n * Disk state is preserved; only the kernel changes. The Cube must be\n * `running`. Concurrent restarts of the same Cube are rejected (409) rather\n * than queued twice.\n */\n restart: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restart\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n wake: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/wake\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Get a Cube's SSH connection info — host, port, login user, and (when\n * available) the pinned host public keys for strict host-key verification.\n */\n ssh: async (spaceId: string, cubeId: string): Promise<CubeSshInfo> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Cube SSH-info response was empty.\" });\n return data;\n },\n\n /**\n * Restore a Cube's disk from one of its {@link Snapshot}s (asynchronous —\n * the restore is enqueued). The Cube's current disk is replaced.\n */\n restore: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restore\",\n { params: { path: { spaceId, cubeId } }, body: { snapshotId } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n /**\n * Resolve the {@link Space} this API key is scoped to — so you don't have to\n * hardcode a `spaceId`. Handy right after constructing the client:\n *\n * @example\n * ```ts\n * const space = await krova.getSpace();\n * const cubes = await krova.cubes.list(space.id);\n * ```\n */\n async getSpace(): Promise<Space> {\n const { data, error, response } = await this.raw.GET(\"/space\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Space response was empty.\" });\n return data;\n }\n\n // ---------------------------------------------------------------------------\n // Custom domains\n // ---------------------------------------------------------------------------\n\n readonly domains = {\n /** List the custom domains attached to a Cube. */\n list: async (spaceId: string, cubeId: string): Promise<Domain[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.domains ?? [];\n },\n\n /**\n * Attach a custom domain to a Cube. `domain` + `port` are required.\n *\n * Returns the domain AND the DNS records you must publish for it to work —\n * so you can create them in the same run, without a second call and without\n * hard-coding record shapes. A wildcard needs three; an exact host needs one.\n *\n * ⛔ BREAKING in 0.4.0: this used to resolve to `Domain`. It now resolves to\n * `{ domain, records }`, because for a wildcard two of the three records\n * (the ownership TXT and the `_acme-challenge` delegation) were not\n * derivable from anything the SDK returned — an integration had to read\n * them out of the docs and hope they still matched the server.\n */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateDomainInput,\n ): Promise<{ domain: Domain; records: DnsRecord[] }> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Create domain response had no `domain`.\" });\n return { domain: data.domain, records: data.records ?? [] };\n },\n\n /**\n * The DNS records a domain needs, each checked against live DNS.\n *\n * Poll this after publishing them: `summary.complete` turns true only once\n * every record is `found`. Each call performs real DNS lookups and is rate\n * limited, so poll on an interval rather than in a tight loop.\n */\n records: async (\n spaceId: string,\n cubeId: string,\n mappingId: string,\n ): Promise<{\n domain: string;\n isWildcard: boolean;\n records: DnsRecordStatus[];\n summary: { found: number; total: number; complete: boolean };\n checkedAt: string;\n }> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}/records\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data)\n throw krovaErrorFrom(response, { error: \"Domain records response was empty.\" });\n return data;\n },\n\n /** Update a domain's per-domain proxy settings. */\n update: async (\n spaceId: string,\n cubeId: string,\n mappingId: string,\n body: UpdateDomainInput,\n ): Promise<Domain> => {\n const { data, error, response } = await this.raw.PATCH(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Update domain response had no `domain`.\" });\n return data.domain;\n },\n\n /** Detach a custom domain from a Cube. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Snapshots\n // ---------------------------------------------------------------------------\n\n readonly snapshots = {\n /** List a Cube's snapshots. */\n list: async (spaceId: string, cubeId: string): Promise<Snapshot[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.snapshots ?? [];\n },\n\n /** Create a snapshot of a Cube's disk (asynchronous — enqueued). */\n create: async (\n spaceId: string,\n cubeId: string,\n body?: { name?: string },\n ): Promise<Snapshot> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } }, body: body ?? {} },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.snapshot)\n throw krovaErrorFrom(response, { error: \"Create snapshot response had no `snapshot`.\" });\n return data.snapshot;\n },\n\n /** Delete a snapshot. */\n delete: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots/{snapshotId}\",\n { params: { path: { spaceId, cubeId, snapshotId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // TCP port mappings\n // ---------------------------------------------------------------------------\n\n readonly tcpMappings = {\n /** List a Cube's TCP port mappings. */\n list: async (spaceId: string, cubeId: string): Promise<TcpMapping[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.tcpMappings ?? [];\n },\n\n /**\n * Create a TCP port mapping exposing a Cube port on the host. `cubePort` is\n * required; `whitelistIps` optionally restricts who can reach it.\n */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateTcpMappingInput,\n ): Promise<TcpMapping> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.tcpMapping)\n throw krovaErrorFrom(response, { error: \"Create TCP mapping response had no `tcpMapping`.\" });\n return data.tcpMapping;\n },\n\n /** Delete a TCP port mapping. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Imports & backups (.cube archive import / export)\n // ---------------------------------------------------------------------------\n\n readonly imports = {\n /**\n * Start importing a `.cube` archive into a new Cube. Returns the multipart\n * upload target (`importId`, `uploadId`, presigned `parts`, …). Upload the\n * archive to those URLs, then call {@link imports.complete}.\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes/imports\", {\n params: { path: { spaceId } },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Get an in-progress or completed import by id. */\n get: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Finish an import after the archive has been uploaded — provisions the\n * Cube. Pass the uploaded `parts` (partNumber + etag) and the resolved\n * `config`.\n */\n complete: async (\n spaceId: string,\n importId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports/{importId}/complete\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/imports/{importId}/complete\",\n { params: { path: { spaceId, importId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Cancel an in-progress import. */\n cancel: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n readonly backups = {\n /** Get a time-limited download URL for a backup `.cube` archive. */\n download: async (spaceId: string, backupId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/backups/{backupId}/download\",\n { params: { path: { spaceId, backupId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Public catalog (no auth required by the API, but the key is harmless)\n // ---------------------------------------------------------------------------\n\n readonly catalog = {\n /** List regions with available capacity. */\n regions: async () => {\n const { data, error, response } = await this.raw.GET(\"/regions\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Regions response was empty.\" });\n return data;\n },\n\n /** List available OS images. */\n images: async () => {\n const { data, error, response } = await this.raw.GET(\"/images\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Images response was empty.\" });\n return data;\n },\n\n /** Per-resource hourly rates and volume pricing tiers. */\n pricing: async () => {\n const { data, error, response } = await this.raw.GET(\"/pricing\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Pricing response was empty.\" });\n return data;\n },\n };\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -366,7 +366,7 @@ interface paths {
366
366
  ramGb: number;
367
367
  diskGb: number;
368
368
  };
369
- /** @description SSH public key written to /root/.ssh/authorized_keys at boot. Must start with ssh-ed25519, ssh-rsa, ecdsa-sha2-*, ssh-dss, or sk-*@openssh.com. */
369
+ /** @description SSH public key written to the Cube login user's authorized_keys at boot (~/.ssh/authorized_keys for the ubuntu or debian user; /root/.ssh/authorized_keys on Cubes created before the default-user change). GET /cubes/{cubeId}/ssh reports the login user for a given Cube. Must start with ssh-ed25519, ssh-rsa, ecdsa-sha2-*, ssh-dss, or sk-*@openssh.com. */
370
370
  sshPublicKey: string;
371
371
  /** @description Region slug from /v1/regions (optional). */
372
372
  region?: string;
@@ -654,7 +654,7 @@ interface paths {
654
654
  };
655
655
  /**
656
656
  * Get a Cube's SSH connection info
657
- * @description Host (server public IPv4), host SSH port, login user, and any captured SSH host public keys. `hostKeys` is empty until Krova captures cube host keys clients fall back to trust-on-first-use until then.
657
+ * @description Host (server public IPv4), host SSH port, login user, and the Cube's captured SSH host public keys. **Use `user` rather than assuming a username** — it is `ubuntu` or `debian` on Cubes created from images that ship a default user, and `root` on Cubes created before that change or imported from a rootfs without one. `hostKeys` is empty only until the reachability cron makes its first capture; clients fall back to trust-on-first-use until then, and pin strictly afterwards.
658
658
  */
659
659
  get: {
660
660
  parameters: {
@@ -811,6 +811,7 @@ interface paths {
811
811
  content: {
812
812
  "application/json": {
813
813
  domain: components["schemas"]["Domain"];
814
+ records: components["schemas"]["DnsRecord"][];
814
815
  };
815
816
  };
816
817
  };
@@ -824,6 +825,66 @@ interface paths {
824
825
  patch?: never;
825
826
  trace?: never;
826
827
  };
828
+ "/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}/records": {
829
+ parameters: {
830
+ query?: never;
831
+ header?: never;
832
+ path?: never;
833
+ cookie?: never;
834
+ };
835
+ /**
836
+ * DNS records this domain needs, with their live status
837
+ * @description Every record required for the domain to work, each checked against live DNS. Poll this after publishing them.
838
+ *
839
+ * `state` is per record: `found`, `missing` (not published yet — the expected state before you add it, never an error), `mismatch` (something else is there), or `unknown` (we could not check — never a statement about your DNS). `summary.complete` is true only when every record is `found`.
840
+ *
841
+ * A wildcard needs three records; an exact host needs one. Each call performs live DNS lookups and is rate limited.
842
+ */
843
+ get: {
844
+ parameters: {
845
+ query?: never;
846
+ header?: never;
847
+ path: {
848
+ spaceId: string;
849
+ cubeId: string;
850
+ mappingId: string;
851
+ };
852
+ cookie?: never;
853
+ };
854
+ requestBody?: never;
855
+ responses: {
856
+ /** @description Required records with live status */
857
+ 200: {
858
+ headers: {
859
+ [name: string]: unknown;
860
+ };
861
+ content: {
862
+ "application/json": {
863
+ domain: string;
864
+ isWildcard: boolean;
865
+ records: components["schemas"]["DnsRecordStatus"][];
866
+ summary: {
867
+ found: number;
868
+ total: number;
869
+ complete: boolean;
870
+ };
871
+ /** Format: date-time */
872
+ checkedAt: string;
873
+ };
874
+ };
875
+ };
876
+ 404: components["responses"]["NotFound"];
877
+ 429: components["responses"]["RateLimited"];
878
+ };
879
+ };
880
+ put?: never;
881
+ post?: never;
882
+ delete?: never;
883
+ options?: never;
884
+ head?: never;
885
+ patch?: never;
886
+ trace?: never;
887
+ };
827
888
  "/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}": {
828
889
  parameters: {
829
890
  query?: never;
@@ -1323,10 +1384,12 @@ interface paths {
1323
1384
  name: string;
1324
1385
  fileSizeBytes: number;
1325
1386
  /**
1387
+ * @description What to do with SSH access on the imported rootfs. `replace` (default) writes `sshPublicKey` to the login user's authorized_keys and requires `sshPublicKey` to be set. `keep` leaves the image's own authorized_keys and sshd configuration completely untouched — nothing is written — so you must already hold a private key that the image accepts, or you will not be able to log in.
1326
1388
  * @default replace
1327
1389
  * @enum {string}
1328
1390
  */
1329
1391
  sshKeyMode?: "replace" | "keep";
1392
+ /** @description Public key to install when `sshKeyMode` is `replace`. Written to the login user's `~/.ssh/authorized_keys` — which user that is comes from the imported rootfs itself, so an image without a Krova default user keeps logging in as root. Ignored when `sshKeyMode` is `keep`. */
1330
1393
  sshPublicKey?: string | null;
1331
1394
  region?: string | null;
1332
1395
  vcpusOverride?: number | null;
@@ -1766,6 +1829,7 @@ interface components {
1766
1829
  diskGb: number;
1767
1830
  };
1768
1831
  image: string;
1832
+ sshUser: string;
1769
1833
  costPerHour: number;
1770
1834
  /** Format: date-time */
1771
1835
  createdAt: string;
@@ -1788,6 +1852,7 @@ interface components {
1788
1852
  name: string;
1789
1853
  version: string;
1790
1854
  description: string;
1855
+ defaultUser: string;
1791
1856
  };
1792
1857
  PricingTier: {
1793
1858
  minVcpus: number;
@@ -1795,6 +1860,34 @@ interface components {
1795
1860
  multiplier: number;
1796
1861
  label: string;
1797
1862
  };
1863
+ DnsRecord: {
1864
+ /** @enum {string} */
1865
+ id: "ownership" | "routing" | "certificate";
1866
+ /** @enum {string} */
1867
+ type: "CNAME" | "TXT" | "A";
1868
+ host: string;
1869
+ value: string;
1870
+ /** @enum {string} */
1871
+ purpose: "ownership" | "routing" | "certificate";
1872
+ note?: string | null;
1873
+ mustBeGrey: boolean;
1874
+ proxyOk: boolean;
1875
+ };
1876
+ DnsRecordStatus: {
1877
+ id: string;
1878
+ /** @enum {string} */
1879
+ type: "CNAME" | "TXT" | "A";
1880
+ host: string;
1881
+ value: string;
1882
+ purpose: string;
1883
+ note?: string | null;
1884
+ mustBeGrey?: boolean;
1885
+ proxyOk?: boolean;
1886
+ /** @enum {string} */
1887
+ state: "found" | "missing" | "mismatch" | "unknown";
1888
+ detail: string;
1889
+ observed?: string[] | null;
1890
+ };
1798
1891
  Domain: {
1799
1892
  id: string;
1800
1893
  cubeId: string;
@@ -1826,6 +1919,10 @@ interface components {
1826
1919
  basicAuthUser: string | null;
1827
1920
  basicAuthEnabled: boolean;
1828
1921
  corsConfig: Record<string, never> | null;
1922
+ isWildcard: boolean;
1923
+ /** @enum {string|null} */
1924
+ wildcardCertState: "pending_delegation" | "issuing" | "ready" | "failed" | null;
1925
+ acmeDelegationTarget: string | null;
1829
1926
  /** Format: date-time */
1830
1927
  createdAt: string;
1831
1928
  /** Format: date-time */
@@ -1954,6 +2051,28 @@ type Space = components["schemas"]["Space"];
1954
2051
  type CubeSshInfo = components["schemas"]["CubeSshInfo"];
1955
2052
  /** A custom domain attached to a Cube. */
1956
2053
  type Domain = components["schemas"]["Domain"];
2054
+ /**
2055
+ * One DNS record you must publish for a domain to work.
2056
+ *
2057
+ * An ordinary subdomain needs one CNAME. A wildcard needs three: an ownership
2058
+ * TXT, the routing CNAME, and an `_acme-challenge` CNAME that lets Krova issue
2059
+ * and renew its certificate.
2060
+ *
2061
+ * ⛔ `mustBeGrey` and `proxyOk` are deliberate OPPOSITES, and automation needs
2062
+ * both. The routing record may sit behind Cloudflare's proxy (orange); the
2063
+ * `_acme-challenge` record must not, because a proxied one answers with
2064
+ * Cloudflare's addresses and the certificate authority finds nothing there.
2065
+ */
2066
+ type DnsRecord = components["schemas"]["DnsRecord"];
2067
+ /**
2068
+ * A {@link DnsRecord} plus what Krova can currently see in public DNS.
2069
+ *
2070
+ * ⛔ `state: "missing"` means NOT PUBLISHED YET — the expected state before you
2071
+ * create the record, never an error. `state: "unknown"` means Krova could not
2072
+ * complete the lookup, which is never a statement about your DNS. Surfacing
2073
+ * either to your own users as a failure would be wrong.
2074
+ */
2075
+ type DnsRecordStatus = components["schemas"]["DnsRecordStatus"];
1957
2076
  /** A snapshot of a Cube's disk. */
1958
2077
  type Snapshot = components["schemas"]["Snapshot"];
1959
2078
  /** A TCP port mapping exposing a Cube port on the host. */
@@ -2038,6 +2157,7 @@ declare class KrovaClient {
2038
2157
  diskGb: number;
2039
2158
  };
2040
2159
  image: string;
2160
+ sshUser: string;
2041
2161
  costPerHour: number;
2042
2162
  createdAt: string;
2043
2163
  updatedAt: string;
@@ -2125,8 +2245,41 @@ declare class KrovaClient {
2125
2245
  readonly domains: {
2126
2246
  /** List the custom domains attached to a Cube. */
2127
2247
  list: (spaceId: string, cubeId: string) => Promise<Domain[]>;
2128
- /** Attach a custom domain to a Cube. `domain` + `port` are required. */
2129
- create: (spaceId: string, cubeId: string, body: CreateDomainInput) => Promise<Domain>;
2248
+ /**
2249
+ * Attach a custom domain to a Cube. `domain` + `port` are required.
2250
+ *
2251
+ * Returns the domain AND the DNS records you must publish for it to work —
2252
+ * so you can create them in the same run, without a second call and without
2253
+ * hard-coding record shapes. A wildcard needs three; an exact host needs one.
2254
+ *
2255
+ * ⛔ BREAKING in 0.4.0: this used to resolve to `Domain`. It now resolves to
2256
+ * `{ domain, records }`, because for a wildcard two of the three records
2257
+ * (the ownership TXT and the `_acme-challenge` delegation) were not
2258
+ * derivable from anything the SDK returned — an integration had to read
2259
+ * them out of the docs and hope they still matched the server.
2260
+ */
2261
+ create: (spaceId: string, cubeId: string, body: CreateDomainInput) => Promise<{
2262
+ domain: Domain;
2263
+ records: DnsRecord[];
2264
+ }>;
2265
+ /**
2266
+ * The DNS records a domain needs, each checked against live DNS.
2267
+ *
2268
+ * Poll this after publishing them: `summary.complete` turns true only once
2269
+ * every record is `found`. Each call performs real DNS lookups and is rate
2270
+ * limited, so poll on an interval rather than in a tight loop.
2271
+ */
2272
+ records: (spaceId: string, cubeId: string, mappingId: string) => Promise<{
2273
+ domain: string;
2274
+ isWildcard: boolean;
2275
+ records: DnsRecordStatus[];
2276
+ summary: {
2277
+ found: number;
2278
+ total: number;
2279
+ complete: boolean;
2280
+ };
2281
+ checkedAt: string;
2282
+ }>;
2130
2283
  /** Update a domain's per-domain proxy settings. */
2131
2284
  update: (spaceId: string, cubeId: string, mappingId: string, body: UpdateDomainInput) => Promise<Domain>;
2132
2285
  /** Detach a custom domain from a Cube. */
@@ -2229,6 +2382,7 @@ declare class KrovaClient {
2229
2382
  name: string;
2230
2383
  version: string;
2231
2384
  description: string;
2385
+ defaultUser: string;
2232
2386
  }[];
2233
2387
  }>;
2234
2388
  /** Per-resource hourly rates and volume pricing tiers. */
package/dist/index.d.ts CHANGED
@@ -366,7 +366,7 @@ interface paths {
366
366
  ramGb: number;
367
367
  diskGb: number;
368
368
  };
369
- /** @description SSH public key written to /root/.ssh/authorized_keys at boot. Must start with ssh-ed25519, ssh-rsa, ecdsa-sha2-*, ssh-dss, or sk-*@openssh.com. */
369
+ /** @description SSH public key written to the Cube login user's authorized_keys at boot (~/.ssh/authorized_keys for the ubuntu or debian user; /root/.ssh/authorized_keys on Cubes created before the default-user change). GET /cubes/{cubeId}/ssh reports the login user for a given Cube. Must start with ssh-ed25519, ssh-rsa, ecdsa-sha2-*, ssh-dss, or sk-*@openssh.com. */
370
370
  sshPublicKey: string;
371
371
  /** @description Region slug from /v1/regions (optional). */
372
372
  region?: string;
@@ -654,7 +654,7 @@ interface paths {
654
654
  };
655
655
  /**
656
656
  * Get a Cube's SSH connection info
657
- * @description Host (server public IPv4), host SSH port, login user, and any captured SSH host public keys. `hostKeys` is empty until Krova captures cube host keys clients fall back to trust-on-first-use until then.
657
+ * @description Host (server public IPv4), host SSH port, login user, and the Cube's captured SSH host public keys. **Use `user` rather than assuming a username** — it is `ubuntu` or `debian` on Cubes created from images that ship a default user, and `root` on Cubes created before that change or imported from a rootfs without one. `hostKeys` is empty only until the reachability cron makes its first capture; clients fall back to trust-on-first-use until then, and pin strictly afterwards.
658
658
  */
659
659
  get: {
660
660
  parameters: {
@@ -811,6 +811,7 @@ interface paths {
811
811
  content: {
812
812
  "application/json": {
813
813
  domain: components["schemas"]["Domain"];
814
+ records: components["schemas"]["DnsRecord"][];
814
815
  };
815
816
  };
816
817
  };
@@ -824,6 +825,66 @@ interface paths {
824
825
  patch?: never;
825
826
  trace?: never;
826
827
  };
828
+ "/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}/records": {
829
+ parameters: {
830
+ query?: never;
831
+ header?: never;
832
+ path?: never;
833
+ cookie?: never;
834
+ };
835
+ /**
836
+ * DNS records this domain needs, with their live status
837
+ * @description Every record required for the domain to work, each checked against live DNS. Poll this after publishing them.
838
+ *
839
+ * `state` is per record: `found`, `missing` (not published yet — the expected state before you add it, never an error), `mismatch` (something else is there), or `unknown` (we could not check — never a statement about your DNS). `summary.complete` is true only when every record is `found`.
840
+ *
841
+ * A wildcard needs three records; an exact host needs one. Each call performs live DNS lookups and is rate limited.
842
+ */
843
+ get: {
844
+ parameters: {
845
+ query?: never;
846
+ header?: never;
847
+ path: {
848
+ spaceId: string;
849
+ cubeId: string;
850
+ mappingId: string;
851
+ };
852
+ cookie?: never;
853
+ };
854
+ requestBody?: never;
855
+ responses: {
856
+ /** @description Required records with live status */
857
+ 200: {
858
+ headers: {
859
+ [name: string]: unknown;
860
+ };
861
+ content: {
862
+ "application/json": {
863
+ domain: string;
864
+ isWildcard: boolean;
865
+ records: components["schemas"]["DnsRecordStatus"][];
866
+ summary: {
867
+ found: number;
868
+ total: number;
869
+ complete: boolean;
870
+ };
871
+ /** Format: date-time */
872
+ checkedAt: string;
873
+ };
874
+ };
875
+ };
876
+ 404: components["responses"]["NotFound"];
877
+ 429: components["responses"]["RateLimited"];
878
+ };
879
+ };
880
+ put?: never;
881
+ post?: never;
882
+ delete?: never;
883
+ options?: never;
884
+ head?: never;
885
+ patch?: never;
886
+ trace?: never;
887
+ };
827
888
  "/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}": {
828
889
  parameters: {
829
890
  query?: never;
@@ -1323,10 +1384,12 @@ interface paths {
1323
1384
  name: string;
1324
1385
  fileSizeBytes: number;
1325
1386
  /**
1387
+ * @description What to do with SSH access on the imported rootfs. `replace` (default) writes `sshPublicKey` to the login user's authorized_keys and requires `sshPublicKey` to be set. `keep` leaves the image's own authorized_keys and sshd configuration completely untouched — nothing is written — so you must already hold a private key that the image accepts, or you will not be able to log in.
1326
1388
  * @default replace
1327
1389
  * @enum {string}
1328
1390
  */
1329
1391
  sshKeyMode?: "replace" | "keep";
1392
+ /** @description Public key to install when `sshKeyMode` is `replace`. Written to the login user's `~/.ssh/authorized_keys` — which user that is comes from the imported rootfs itself, so an image without a Krova default user keeps logging in as root. Ignored when `sshKeyMode` is `keep`. */
1330
1393
  sshPublicKey?: string | null;
1331
1394
  region?: string | null;
1332
1395
  vcpusOverride?: number | null;
@@ -1766,6 +1829,7 @@ interface components {
1766
1829
  diskGb: number;
1767
1830
  };
1768
1831
  image: string;
1832
+ sshUser: string;
1769
1833
  costPerHour: number;
1770
1834
  /** Format: date-time */
1771
1835
  createdAt: string;
@@ -1788,6 +1852,7 @@ interface components {
1788
1852
  name: string;
1789
1853
  version: string;
1790
1854
  description: string;
1855
+ defaultUser: string;
1791
1856
  };
1792
1857
  PricingTier: {
1793
1858
  minVcpus: number;
@@ -1795,6 +1860,34 @@ interface components {
1795
1860
  multiplier: number;
1796
1861
  label: string;
1797
1862
  };
1863
+ DnsRecord: {
1864
+ /** @enum {string} */
1865
+ id: "ownership" | "routing" | "certificate";
1866
+ /** @enum {string} */
1867
+ type: "CNAME" | "TXT" | "A";
1868
+ host: string;
1869
+ value: string;
1870
+ /** @enum {string} */
1871
+ purpose: "ownership" | "routing" | "certificate";
1872
+ note?: string | null;
1873
+ mustBeGrey: boolean;
1874
+ proxyOk: boolean;
1875
+ };
1876
+ DnsRecordStatus: {
1877
+ id: string;
1878
+ /** @enum {string} */
1879
+ type: "CNAME" | "TXT" | "A";
1880
+ host: string;
1881
+ value: string;
1882
+ purpose: string;
1883
+ note?: string | null;
1884
+ mustBeGrey?: boolean;
1885
+ proxyOk?: boolean;
1886
+ /** @enum {string} */
1887
+ state: "found" | "missing" | "mismatch" | "unknown";
1888
+ detail: string;
1889
+ observed?: string[] | null;
1890
+ };
1798
1891
  Domain: {
1799
1892
  id: string;
1800
1893
  cubeId: string;
@@ -1826,6 +1919,10 @@ interface components {
1826
1919
  basicAuthUser: string | null;
1827
1920
  basicAuthEnabled: boolean;
1828
1921
  corsConfig: Record<string, never> | null;
1922
+ isWildcard: boolean;
1923
+ /** @enum {string|null} */
1924
+ wildcardCertState: "pending_delegation" | "issuing" | "ready" | "failed" | null;
1925
+ acmeDelegationTarget: string | null;
1829
1926
  /** Format: date-time */
1830
1927
  createdAt: string;
1831
1928
  /** Format: date-time */
@@ -1954,6 +2051,28 @@ type Space = components["schemas"]["Space"];
1954
2051
  type CubeSshInfo = components["schemas"]["CubeSshInfo"];
1955
2052
  /** A custom domain attached to a Cube. */
1956
2053
  type Domain = components["schemas"]["Domain"];
2054
+ /**
2055
+ * One DNS record you must publish for a domain to work.
2056
+ *
2057
+ * An ordinary subdomain needs one CNAME. A wildcard needs three: an ownership
2058
+ * TXT, the routing CNAME, and an `_acme-challenge` CNAME that lets Krova issue
2059
+ * and renew its certificate.
2060
+ *
2061
+ * ⛔ `mustBeGrey` and `proxyOk` are deliberate OPPOSITES, and automation needs
2062
+ * both. The routing record may sit behind Cloudflare's proxy (orange); the
2063
+ * `_acme-challenge` record must not, because a proxied one answers with
2064
+ * Cloudflare's addresses and the certificate authority finds nothing there.
2065
+ */
2066
+ type DnsRecord = components["schemas"]["DnsRecord"];
2067
+ /**
2068
+ * A {@link DnsRecord} plus what Krova can currently see in public DNS.
2069
+ *
2070
+ * ⛔ `state: "missing"` means NOT PUBLISHED YET — the expected state before you
2071
+ * create the record, never an error. `state: "unknown"` means Krova could not
2072
+ * complete the lookup, which is never a statement about your DNS. Surfacing
2073
+ * either to your own users as a failure would be wrong.
2074
+ */
2075
+ type DnsRecordStatus = components["schemas"]["DnsRecordStatus"];
1957
2076
  /** A snapshot of a Cube's disk. */
1958
2077
  type Snapshot = components["schemas"]["Snapshot"];
1959
2078
  /** A TCP port mapping exposing a Cube port on the host. */
@@ -2038,6 +2157,7 @@ declare class KrovaClient {
2038
2157
  diskGb: number;
2039
2158
  };
2040
2159
  image: string;
2160
+ sshUser: string;
2041
2161
  costPerHour: number;
2042
2162
  createdAt: string;
2043
2163
  updatedAt: string;
@@ -2125,8 +2245,41 @@ declare class KrovaClient {
2125
2245
  readonly domains: {
2126
2246
  /** List the custom domains attached to a Cube. */
2127
2247
  list: (spaceId: string, cubeId: string) => Promise<Domain[]>;
2128
- /** Attach a custom domain to a Cube. `domain` + `port` are required. */
2129
- create: (spaceId: string, cubeId: string, body: CreateDomainInput) => Promise<Domain>;
2248
+ /**
2249
+ * Attach a custom domain to a Cube. `domain` + `port` are required.
2250
+ *
2251
+ * Returns the domain AND the DNS records you must publish for it to work —
2252
+ * so you can create them in the same run, without a second call and without
2253
+ * hard-coding record shapes. A wildcard needs three; an exact host needs one.
2254
+ *
2255
+ * ⛔ BREAKING in 0.4.0: this used to resolve to `Domain`. It now resolves to
2256
+ * `{ domain, records }`, because for a wildcard two of the three records
2257
+ * (the ownership TXT and the `_acme-challenge` delegation) were not
2258
+ * derivable from anything the SDK returned — an integration had to read
2259
+ * them out of the docs and hope they still matched the server.
2260
+ */
2261
+ create: (spaceId: string, cubeId: string, body: CreateDomainInput) => Promise<{
2262
+ domain: Domain;
2263
+ records: DnsRecord[];
2264
+ }>;
2265
+ /**
2266
+ * The DNS records a domain needs, each checked against live DNS.
2267
+ *
2268
+ * Poll this after publishing them: `summary.complete` turns true only once
2269
+ * every record is `found`. Each call performs real DNS lookups and is rate
2270
+ * limited, so poll on an interval rather than in a tight loop.
2271
+ */
2272
+ records: (spaceId: string, cubeId: string, mappingId: string) => Promise<{
2273
+ domain: string;
2274
+ isWildcard: boolean;
2275
+ records: DnsRecordStatus[];
2276
+ summary: {
2277
+ found: number;
2278
+ total: number;
2279
+ complete: boolean;
2280
+ };
2281
+ checkedAt: string;
2282
+ }>;
2130
2283
  /** Update a domain's per-domain proxy settings. */
2131
2284
  update: (spaceId: string, cubeId: string, mappingId: string, body: UpdateDomainInput) => Promise<Domain>;
2132
2285
  /** Detach a custom domain from a Cube. */
@@ -2229,6 +2382,7 @@ declare class KrovaClient {
2229
2382
  name: string;
2230
2383
  version: string;
2231
2384
  description: string;
2385
+ defaultUser: string;
2232
2386
  }[];
2233
2387
  }>;
2234
2388
  /** Per-resource hourly rates and volume pricing tiers. */
package/dist/index.js CHANGED
@@ -317,7 +317,19 @@ var KrovaClient = class {
317
317
  if (error !== void 0 || !response.ok) throw krovaErrorFrom(response, error);
318
318
  return data?.domains ?? [];
319
319
  },
320
- /** Attach a custom domain to a Cube. `domain` + `port` are required. */
320
+ /**
321
+ * Attach a custom domain to a Cube. `domain` + `port` are required.
322
+ *
323
+ * Returns the domain AND the DNS records you must publish for it to work —
324
+ * so you can create them in the same run, without a second call and without
325
+ * hard-coding record shapes. A wildcard needs three; an exact host needs one.
326
+ *
327
+ * ⛔ BREAKING in 0.4.0: this used to resolve to `Domain`. It now resolves to
328
+ * `{ domain, records }`, because for a wildcard two of the three records
329
+ * (the ownership TXT and the `_acme-challenge` delegation) were not
330
+ * derivable from anything the SDK returned — an integration had to read
331
+ * them out of the docs and hope they still matched the server.
332
+ */
321
333
  create: async (spaceId, cubeId, body) => {
322
334
  const { data, error, response } = await this.raw.POST(
323
335
  "/spaces/{spaceId}/cubes/{cubeId}/domains",
@@ -326,7 +338,24 @@ var KrovaClient = class {
326
338
  if (error !== void 0 || !response.ok) throw krovaErrorFrom(response, error);
327
339
  if (!data?.domain)
328
340
  throw krovaErrorFrom(response, { error: "Create domain response had no `domain`." });
329
- return data.domain;
341
+ return { domain: data.domain, records: data.records ?? [] };
342
+ },
343
+ /**
344
+ * The DNS records a domain needs, each checked against live DNS.
345
+ *
346
+ * Poll this after publishing them: `summary.complete` turns true only once
347
+ * every record is `found`. Each call performs real DNS lookups and is rate
348
+ * limited, so poll on an interval rather than in a tight loop.
349
+ */
350
+ records: async (spaceId, cubeId, mappingId) => {
351
+ const { data, error, response } = await this.raw.GET(
352
+ "/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}/records",
353
+ { params: { path: { spaceId, cubeId, mappingId } } }
354
+ );
355
+ if (error !== void 0 || !response.ok) throw krovaErrorFrom(response, error);
356
+ if (!data)
357
+ throw krovaErrorFrom(response, { error: "Domain records response was empty." });
358
+ return data;
330
359
  },
331
360
  /** Update a domain's per-domain proxy settings. */
332
361
  update: async (spaceId, cubeId, mappingId, body) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/error.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The error body shape returned by the Krova Cloud API.\n *\n * Per the OpenAPI spec (`components.schemas.Error`), every non-2xx response\n * body is `{ \"error\": string }`. Additional fields may appear over time, so\n * we keep the type open.\n */\nexport interface KrovaErrorBody {\n error?: string;\n [key: string]: unknown;\n}\n\n/**\n * Error thrown by the ergonomic {@link KrovaClient} helpers when the API\n * responds with a non-2xx status.\n *\n * The raw openapi-fetch client (`client.raw`) never throws — it returns\n * `{ data, error, response }`. The helpers wrap that and throw `KrovaError`\n * so callers can `try/catch`.\n */\nexport class KrovaError extends Error {\n /** HTTP status code of the failing response. */\n readonly status: number;\n\n /**\n * A machine-readable error code, when the API surfaces one via the\n * `X-Error-Code` response header. The documented error body only carries a\n * human-readable `error` string, so this is best-effort.\n */\n readonly code?: string;\n\n /**\n * The request id from the `X-Request-Id` response header, when present.\n * Useful when contacting Krova Cloud support about a specific failure.\n */\n readonly requestId?: string;\n\n /** The parsed JSON error body, when the response had one. */\n readonly body?: KrovaErrorBody;\n\n /** The raw `Response` object, for callers that need headers/url/etc. */\n readonly response?: Response;\n\n constructor(\n message: string,\n init: {\n status: number;\n code?: string;\n requestId?: string;\n body?: KrovaErrorBody;\n response?: Response;\n },\n ) {\n super(message);\n this.name = \"KrovaError\";\n this.status = init.status;\n this.code = init.code;\n this.requestId = init.requestId;\n this.body = init.body;\n this.response = init.response;\n // Restore prototype chain for instanceof across compilation targets.\n Object.setPrototypeOf(this, KrovaError.prototype);\n }\n}\n\n/**\n * Build a {@link KrovaError} from a failing response + parsed error body.\n */\nexport function krovaErrorFrom(\n response: Response,\n body: KrovaErrorBody | undefined,\n): KrovaError {\n const message =\n (typeof body?.error === \"string\" && body.error) ||\n response.statusText ||\n `Request failed with status ${response.status}`;\n return new KrovaError(message, {\n status: response.status,\n code: response.headers.get(\"x-error-code\") ?? undefined,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n body,\n response,\n });\n}\n","import createClient, { type Client, type Middleware } from \"openapi-fetch\";\nimport { krovaErrorFrom } from \"./error.js\";\nimport type { components, paths } from \"./generated/types.js\";\n\n/** The Cube resource, as defined in the Krova Cloud OpenAPI spec. */\nexport type Cube = components[\"schemas\"][\"Cube\"];\n\n/** A region with available capacity (from the catalog). */\nexport type Region = components[\"schemas\"][\"Region\"];\n\n/** A selectable OS image (from the catalog). */\nexport type Image = components[\"schemas\"][\"Image\"];\n\n/** A volume-pricing tier (from the catalog). */\nexport type PricingTier = components[\"schemas\"][\"PricingTier\"];\n\n/** Pagination envelope returned alongside a Cube list. */\nexport type Pagination = components[\"schemas\"][\"Pagination\"];\n\n/** A Space — the tenancy an API key is scoped to. */\nexport type Space = components[\"schemas\"][\"Space\"];\n\n/** A Cube's SSH connection info (host, port, user, and pinned host keys). */\nexport type CubeSshInfo = components[\"schemas\"][\"CubeSshInfo\"];\n\n/** A custom domain attached to a Cube. */\nexport type Domain = components[\"schemas\"][\"Domain\"];\n\n/** A snapshot of a Cube's disk. */\nexport type Snapshot = components[\"schemas\"][\"Snapshot\"];\n\n/** A TCP port mapping exposing a Cube port on the host. */\nexport type TcpMapping = components[\"schemas\"][\"TcpMapping\"];\n\n/** Request body for attaching a custom domain to a Cube. */\nexport type CreateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for updating a custom domain's proxy settings. */\nexport type UpdateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for creating a TCP port mapping. */\nexport type CreateTcpMappingInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Default API base URL — the single `servers[0].url` from the OpenAPI spec. */\nexport const DEFAULT_BASE_URL = \"https://krova.cloud/api/v1\";\n\n/**\n * How the API key is presented to the server.\n *\n * - `\"x-api-key\"` (default) — `X-API-KEY: <key>`, matching the spec's\n * `components.securitySchemes.ApiKeyAuth` (an `apiKey` header named\n * `X-API-KEY`).\n * - `\"bearer\"` — `Authorization: Bearer <key>`, for gateways that expect it.\n */\nexport type AuthScheme = \"x-api-key\" | \"bearer\";\n\nexport interface KrovaClientOptions {\n /**\n * Your Krova Cloud API key (a `kro_...` token). Keys are scoped per Space\n * and inherit the permissions of the membership that created them.\n */\n apiKey: string;\n /** Override the API base URL. Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /**\n * Auth header scheme. Defaults to `\"x-api-key\"` (the spec's scheme).\n */\n authScheme?: AuthScheme;\n /**\n * Max automatic retries on retryable statuses (429, 503).\n * Defaults to 2. Set to 0 to disable retries.\n */\n maxRetries?: number;\n /**\n * A custom `fetch` implementation (e.g. for tests or a proxy). Defaults to\n * the global `fetch`.\n */\n fetch?: typeof fetch;\n}\n\n/** Statuses the retry middleware treats as transient. */\nconst RETRYABLE_STATUSES = new Set([429, 503]);\n/** Fallback backoff (ms) when the server sends no `Retry-After` header. */\nconst BASE_BACKOFF_MS = 500;\n/** Cap on any single backoff wait (ms), to keep retries \"small but real\". */\nconst MAX_BACKOFF_MS = 10_000;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Parse a `Retry-After` header (RFC 7231): either delta-seconds or an\n * HTTP-date. Returns milliseconds to wait, or `null` if absent/unparseable.\n */\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null;\n const seconds = Number(headerValue);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n const dateMs = Date.parse(headerValue);\n if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());\n return null;\n}\n\nfunction authMiddleware(apiKey: string, scheme: AuthScheme): Middleware {\n return {\n onRequest({ request }) {\n if (scheme === \"bearer\") {\n request.headers.set(\"Authorization\", `Bearer ${apiKey}`);\n } else {\n request.headers.set(\"X-API-KEY\", apiKey);\n }\n return request;\n },\n };\n}\n\n/**\n * Retry middleware: on a retryable status, wait (honoring `Retry-After` when\n * present, else exponential backoff) and re-issue the request.\n *\n * A retried request may have a body (POST/PUT/DELETE — exactly the mutating,\n * rate-limited endpoints). By the time `onResponse` runs, the request that was\n * handed to `fetch` has had its body stream consumed, so `request.clone()` here\n * throws `TypeError: unusable`. To re-issue it we stash a *pristine* clone in\n * `onRequest` — captured before the body is read — keyed by openapi-fetch's\n * per-request `id`, and clone from that pristine copy on each attempt.\n */\nfunction retryMiddleware(maxRetries: number, doFetch: typeof fetch): Middleware {\n const pristine = new Map<string, Request>();\n return {\n onRequest({ request, id }) {\n pristine.set(id, request.clone());\n return request;\n },\n onError({ id }) {\n // fetch rejected (network error) — no onResponse will fire; don't leak.\n pristine.delete(id);\n },\n async onResponse({ request, response, id }) {\n const original = pristine.get(id) ?? request;\n pristine.delete(id);\n if (maxRetries <= 0 || !RETRYABLE_STATUSES.has(response.status)) {\n return response;\n }\n let current = response;\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n if (!RETRYABLE_STATUSES.has(current.status)) break;\n const retryAfterMs = parseRetryAfterMs(current.headers.get(\"retry-after\"));\n const backoff = Math.min(BASE_BACKOFF_MS * 2 ** (attempt - 1), MAX_BACKOFF_MS);\n // Cap the wait — including a server-supplied `Retry-After` — so a hostile\n // or misconfigured server can't park the client for minutes/hours.\n await sleep(Math.min(retryAfterMs ?? backoff, MAX_BACKOFF_MS));\n // Re-issue from the pristine clone; `.clone()` keeps it reusable across\n // multiple attempts.\n current = await doFetch(original.clone());\n }\n return current;\n },\n };\n}\n\n/**\n * A typed client for the Krova Cloud API.\n *\n * @example\n * ```ts\n * const krova = new KrovaClient({ apiKey: \"kro_...\" });\n * const cubes = await krova.cubes.list(\"space_123\");\n * ```\n */\nexport class KrovaClient {\n /**\n * The underlying openapi-fetch client — a fully typed escape hatch to every\n * path in the spec. Returns `{ data, error, response }` and never throws.\n *\n * @example\n * ```ts\n * const { data, error } = await krova.raw.GET(\n * \"/spaces/{spaceId}/cubes/{cubeId}\",\n * { params: { path: { spaceId, cubeId } } },\n * );\n * ```\n */\n readonly raw: Client<paths>;\n\n /** The resolved base URL in use. */\n readonly baseUrl: string;\n\n constructor(options: KrovaClientOptions) {\n if (!options?.apiKey) {\n throw new Error(\"KrovaClient: `apiKey` is required.\");\n }\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const doFetch = options.fetch ?? globalThis.fetch;\n const maxRetries = options.maxRetries ?? 2;\n\n this.raw = createClient<paths>({\n baseUrl: this.baseUrl,\n // SECURITY: never auto-follow redirects. The Krova Cloud API is a plain\n // JSON API and never legitimately 3xx's a data call. Following a redirect\n // would resend the `X-API-KEY` header to the redirect target — and unlike\n // `Authorization`, `Cookie`, and `Proxy-Authorization`, the Fetch spec does\n // NOT strip a custom header like `X-API-KEY` on a cross-origin redirect\n // (verified against undici/Node fetch). A compromised/misconfigured proxy,\n // an open-redirect on the API, or a MITM could otherwise exfiltrate the key\n // to an attacker's host. With `\"manual\"`, a redirect comes back as a\n // non-ok response and the helpers throw `KrovaError` instead of leaking.\n redirect: \"manual\",\n ...(options.fetch ? { fetch: options.fetch } : {}),\n });\n this.raw.use(authMiddleware(options.apiKey, options.authScheme ?? \"x-api-key\"));\n if (maxRetries > 0) {\n this.raw.use(retryMiddleware(maxRetries, doFetch));\n }\n }\n\n // ---------------------------------------------------------------------------\n // Cubes\n // ---------------------------------------------------------------------------\n\n readonly cubes = {\n /** List Cubes in a Space, with pagination metadata. */\n list: async (spaceId: string) => {\n const { data, error, response } = await this.raw.GET(\"/spaces/{spaceId}/cubes\", {\n params: { path: { spaceId } },\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"List Cubes response was empty.\" });\n return data;\n },\n\n /**\n * Create a Cube. Returns the created {@link Cube}.\n *\n * @param spaceId Target Space id.\n * @param body Cube spec — `{ name, image, resources, sshPublicKey, ... }`.\n * @param opts Optional `idempotencyKey` (max 255 chars, scoped per space).\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n opts?: { idempotencyKey?: string },\n ): Promise<Cube> => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes\", {\n params: {\n path: { spaceId },\n ...(opts?.idempotencyKey\n ? { header: { \"Idempotency-Key\": opts.idempotencyKey } }\n : {}),\n },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Create Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /** Get a single Cube. Returns the {@link Cube}. */\n get: async (spaceId: string, cubeId: string): Promise<Cube> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Get Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /**\n * Update the IN-CUBE port that SSH is forwarded to.\n *\n * `cubePort` is the port **inside** the Cube that sshd listens on — NOT the\n * host port you connect to. The host port is allocated by Krova and is not\n * changed by this call. Pointing this at a port nothing is listening on\n * inside the Cube will silently make SSH unreachable; the default is 22.\n *\n * The Krova Cloud API exposes no general Cube-mutation endpoint; the only\n * mutable Cube field over the API is this port, via\n * `PUT /spaces/{spaceId}/cubes/{cubeId}/ssh-port`. This helper maps to that\n * endpoint. (Compute resize / rename are not part of the public API.)\n */\n update: async (\n spaceId: string,\n cubeId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\"][\"put\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ): Promise<unknown> => {\n const { data, error, response } = await this.raw.PUT(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Delete a Cube (asynchronous — deletion is enqueued). */\n delete: async (spaceId: string, cubeId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Delete Cube response was empty.\" });\n return data;\n },\n\n /** Power off a running Cube (asynchronous — power-off is enqueued). The Cube\n * becomes `stopped` (its host RAM is freed); start it again with `wake`. */\n powerOff: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/power-off\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Start a stopped Cube (asynchronous — start is enqueued). */\n /**\n * Restart a Cube (COLD restart).\n *\n * The hypervisor process is stopped and relaunched, so the Cube boots\n * against the host's current kernel. This is the only way a Cube picks up a\n * refreshed guest kernel after a platform image update — a `reboot` issued\n * INSIDE the Cube cannot do it, because Firecracker treats a guest reboot as\n * a shutdown and the kernel is supplied externally by the host.\n *\n * Disk state is preserved; only the kernel changes. The Cube must be\n * `running`. Concurrent restarts of the same Cube are rejected (409) rather\n * than queued twice.\n */\n restart: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restart\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n wake: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/wake\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Get a Cube's SSH connection info — host, port, login user, and (when\n * available) the pinned host public keys for strict host-key verification.\n */\n ssh: async (spaceId: string, cubeId: string): Promise<CubeSshInfo> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Cube SSH-info response was empty.\" });\n return data;\n },\n\n /**\n * Restore a Cube's disk from one of its {@link Snapshot}s (asynchronous —\n * the restore is enqueued). The Cube's current disk is replaced.\n */\n restore: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restore\",\n { params: { path: { spaceId, cubeId } }, body: { snapshotId } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n /**\n * Resolve the {@link Space} this API key is scoped to — so you don't have to\n * hardcode a `spaceId`. Handy right after constructing the client:\n *\n * @example\n * ```ts\n * const space = await krova.getSpace();\n * const cubes = await krova.cubes.list(space.id);\n * ```\n */\n async getSpace(): Promise<Space> {\n const { data, error, response } = await this.raw.GET(\"/space\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Space response was empty.\" });\n return data;\n }\n\n // ---------------------------------------------------------------------------\n // Custom domains\n // ---------------------------------------------------------------------------\n\n readonly domains = {\n /** List the custom domains attached to a Cube. */\n list: async (spaceId: string, cubeId: string): Promise<Domain[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.domains ?? [];\n },\n\n /** Attach a custom domain to a Cube. `domain` + `port` are required. */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateDomainInput,\n ): Promise<Domain> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Create domain response had no `domain`.\" });\n return data.domain;\n },\n\n /** Update a domain's per-domain proxy settings. */\n update: async (\n spaceId: string,\n cubeId: string,\n mappingId: string,\n body: UpdateDomainInput,\n ): Promise<Domain> => {\n const { data, error, response } = await this.raw.PATCH(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Update domain response had no `domain`.\" });\n return data.domain;\n },\n\n /** Detach a custom domain from a Cube. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Snapshots\n // ---------------------------------------------------------------------------\n\n readonly snapshots = {\n /** List a Cube's snapshots. */\n list: async (spaceId: string, cubeId: string): Promise<Snapshot[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.snapshots ?? [];\n },\n\n /** Create a snapshot of a Cube's disk (asynchronous — enqueued). */\n create: async (\n spaceId: string,\n cubeId: string,\n body?: { name?: string },\n ): Promise<Snapshot> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } }, body: body ?? {} },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.snapshot)\n throw krovaErrorFrom(response, { error: \"Create snapshot response had no `snapshot`.\" });\n return data.snapshot;\n },\n\n /** Delete a snapshot. */\n delete: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots/{snapshotId}\",\n { params: { path: { spaceId, cubeId, snapshotId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // TCP port mappings\n // ---------------------------------------------------------------------------\n\n readonly tcpMappings = {\n /** List a Cube's TCP port mappings. */\n list: async (spaceId: string, cubeId: string): Promise<TcpMapping[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.tcpMappings ?? [];\n },\n\n /**\n * Create a TCP port mapping exposing a Cube port on the host. `cubePort` is\n * required; `whitelistIps` optionally restricts who can reach it.\n */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateTcpMappingInput,\n ): Promise<TcpMapping> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.tcpMapping)\n throw krovaErrorFrom(response, { error: \"Create TCP mapping response had no `tcpMapping`.\" });\n return data.tcpMapping;\n },\n\n /** Delete a TCP port mapping. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Imports & backups (.cube archive import / export)\n // ---------------------------------------------------------------------------\n\n readonly imports = {\n /**\n * Start importing a `.cube` archive into a new Cube. Returns the multipart\n * upload target (`importId`, `uploadId`, presigned `parts`, …). Upload the\n * archive to those URLs, then call {@link imports.complete}.\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes/imports\", {\n params: { path: { spaceId } },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Get an in-progress or completed import by id. */\n get: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Finish an import after the archive has been uploaded — provisions the\n * Cube. Pass the uploaded `parts` (partNumber + etag) and the resolved\n * `config`.\n */\n complete: async (\n spaceId: string,\n importId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports/{importId}/complete\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/imports/{importId}/complete\",\n { params: { path: { spaceId, importId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Cancel an in-progress import. */\n cancel: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n readonly backups = {\n /** Get a time-limited download URL for a backup `.cube` archive. */\n download: async (spaceId: string, backupId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/backups/{backupId}/download\",\n { params: { path: { spaceId, backupId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Public catalog (no auth required by the API, but the key is harmless)\n // ---------------------------------------------------------------------------\n\n readonly catalog = {\n /** List regions with available capacity. */\n regions: async () => {\n const { data, error, response } = await this.raw.GET(\"/regions\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Regions response was empty.\" });\n return data;\n },\n\n /** List available OS images. */\n images: async () => {\n const { data, error, response } = await this.raw.GET(\"/images\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Images response was empty.\" });\n return data;\n },\n\n /** Per-resource hourly rates and volume pricing tiers. */\n pricing: async () => {\n const { data, error, response } = await this.raw.GET(\"/pricing\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Pricing response was empty.\" });\n return data;\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/error.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The error body shape returned by the Krova Cloud API.\n *\n * Per the OpenAPI spec (`components.schemas.Error`), every non-2xx response\n * body is `{ \"error\": string }`. Additional fields may appear over time, so\n * we keep the type open.\n */\nexport interface KrovaErrorBody {\n error?: string;\n [key: string]: unknown;\n}\n\n/**\n * Error thrown by the ergonomic {@link KrovaClient} helpers when the API\n * responds with a non-2xx status.\n *\n * The raw openapi-fetch client (`client.raw`) never throws — it returns\n * `{ data, error, response }`. The helpers wrap that and throw `KrovaError`\n * so callers can `try/catch`.\n */\nexport class KrovaError extends Error {\n /** HTTP status code of the failing response. */\n readonly status: number;\n\n /**\n * A machine-readable error code, when the API surfaces one via the\n * `X-Error-Code` response header. The documented error body only carries a\n * human-readable `error` string, so this is best-effort.\n */\n readonly code?: string;\n\n /**\n * The request id from the `X-Request-Id` response header, when present.\n * Useful when contacting Krova Cloud support about a specific failure.\n */\n readonly requestId?: string;\n\n /** The parsed JSON error body, when the response had one. */\n readonly body?: KrovaErrorBody;\n\n /** The raw `Response` object, for callers that need headers/url/etc. */\n readonly response?: Response;\n\n constructor(\n message: string,\n init: {\n status: number;\n code?: string;\n requestId?: string;\n body?: KrovaErrorBody;\n response?: Response;\n },\n ) {\n super(message);\n this.name = \"KrovaError\";\n this.status = init.status;\n this.code = init.code;\n this.requestId = init.requestId;\n this.body = init.body;\n this.response = init.response;\n // Restore prototype chain for instanceof across compilation targets.\n Object.setPrototypeOf(this, KrovaError.prototype);\n }\n}\n\n/**\n * Build a {@link KrovaError} from a failing response + parsed error body.\n */\nexport function krovaErrorFrom(\n response: Response,\n body: KrovaErrorBody | undefined,\n): KrovaError {\n const message =\n (typeof body?.error === \"string\" && body.error) ||\n response.statusText ||\n `Request failed with status ${response.status}`;\n return new KrovaError(message, {\n status: response.status,\n code: response.headers.get(\"x-error-code\") ?? undefined,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n body,\n response,\n });\n}\n","import createClient, { type Client, type Middleware } from \"openapi-fetch\";\nimport { krovaErrorFrom } from \"./error.js\";\nimport type { components, paths } from \"./generated/types.js\";\n\n/** The Cube resource, as defined in the Krova Cloud OpenAPI spec. */\nexport type Cube = components[\"schemas\"][\"Cube\"];\n\n/** A region with available capacity (from the catalog). */\nexport type Region = components[\"schemas\"][\"Region\"];\n\n/** A selectable OS image (from the catalog). */\nexport type Image = components[\"schemas\"][\"Image\"];\n\n/** A volume-pricing tier (from the catalog). */\nexport type PricingTier = components[\"schemas\"][\"PricingTier\"];\n\n/** Pagination envelope returned alongside a Cube list. */\nexport type Pagination = components[\"schemas\"][\"Pagination\"];\n\n/** A Space — the tenancy an API key is scoped to. */\nexport type Space = components[\"schemas\"][\"Space\"];\n\n/** A Cube's SSH connection info (host, port, user, and pinned host keys). */\nexport type CubeSshInfo = components[\"schemas\"][\"CubeSshInfo\"];\n\n/** A custom domain attached to a Cube. */\nexport type Domain = components[\"schemas\"][\"Domain\"];\n\n/**\n * One DNS record you must publish for a domain to work.\n *\n * An ordinary subdomain needs one CNAME. A wildcard needs three: an ownership\n * TXT, the routing CNAME, and an `_acme-challenge` CNAME that lets Krova issue\n * and renew its certificate.\n *\n * ⛔ `mustBeGrey` and `proxyOk` are deliberate OPPOSITES, and automation needs\n * both. The routing record may sit behind Cloudflare's proxy (orange); the\n * `_acme-challenge` record must not, because a proxied one answers with\n * Cloudflare's addresses and the certificate authority finds nothing there.\n */\nexport type DnsRecord = components[\"schemas\"][\"DnsRecord\"];\n\n/**\n * A {@link DnsRecord} plus what Krova can currently see in public DNS.\n *\n * ⛔ `state: \"missing\"` means NOT PUBLISHED YET — the expected state before you\n * create the record, never an error. `state: \"unknown\"` means Krova could not\n * complete the lookup, which is never a statement about your DNS. Surfacing\n * either to your own users as a failure would be wrong.\n */\nexport type DnsRecordStatus = components[\"schemas\"][\"DnsRecordStatus\"];\n\n/** A snapshot of a Cube's disk. */\nexport type Snapshot = components[\"schemas\"][\"Snapshot\"];\n\n/** A TCP port mapping exposing a Cube port on the host. */\nexport type TcpMapping = components[\"schemas\"][\"TcpMapping\"];\n\n/** Request body for attaching a custom domain to a Cube. */\nexport type CreateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for updating a custom domain's proxy settings. */\nexport type UpdateDomainInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Request body for creating a TCP port mapping. */\nexport type CreateTcpMappingInput = NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\n/** Default API base URL — the single `servers[0].url` from the OpenAPI spec. */\nexport const DEFAULT_BASE_URL = \"https://krova.cloud/api/v1\";\n\n/**\n * How the API key is presented to the server.\n *\n * - `\"x-api-key\"` (default) — `X-API-KEY: <key>`, matching the spec's\n * `components.securitySchemes.ApiKeyAuth` (an `apiKey` header named\n * `X-API-KEY`).\n * - `\"bearer\"` — `Authorization: Bearer <key>`, for gateways that expect it.\n */\nexport type AuthScheme = \"x-api-key\" | \"bearer\";\n\nexport interface KrovaClientOptions {\n /**\n * Your Krova Cloud API key (a `kro_...` token). Keys are scoped per Space\n * and inherit the permissions of the membership that created them.\n */\n apiKey: string;\n /** Override the API base URL. Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /**\n * Auth header scheme. Defaults to `\"x-api-key\"` (the spec's scheme).\n */\n authScheme?: AuthScheme;\n /**\n * Max automatic retries on retryable statuses (429, 503).\n * Defaults to 2. Set to 0 to disable retries.\n */\n maxRetries?: number;\n /**\n * A custom `fetch` implementation (e.g. for tests or a proxy). Defaults to\n * the global `fetch`.\n */\n fetch?: typeof fetch;\n}\n\n/** Statuses the retry middleware treats as transient. */\nconst RETRYABLE_STATUSES = new Set([429, 503]);\n/** Fallback backoff (ms) when the server sends no `Retry-After` header. */\nconst BASE_BACKOFF_MS = 500;\n/** Cap on any single backoff wait (ms), to keep retries \"small but real\". */\nconst MAX_BACKOFF_MS = 10_000;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Parse a `Retry-After` header (RFC 7231): either delta-seconds or an\n * HTTP-date. Returns milliseconds to wait, or `null` if absent/unparseable.\n */\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null;\n const seconds = Number(headerValue);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n const dateMs = Date.parse(headerValue);\n if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());\n return null;\n}\n\nfunction authMiddleware(apiKey: string, scheme: AuthScheme): Middleware {\n return {\n onRequest({ request }) {\n if (scheme === \"bearer\") {\n request.headers.set(\"Authorization\", `Bearer ${apiKey}`);\n } else {\n request.headers.set(\"X-API-KEY\", apiKey);\n }\n return request;\n },\n };\n}\n\n/**\n * Retry middleware: on a retryable status, wait (honoring `Retry-After` when\n * present, else exponential backoff) and re-issue the request.\n *\n * A retried request may have a body (POST/PUT/DELETE — exactly the mutating,\n * rate-limited endpoints). By the time `onResponse` runs, the request that was\n * handed to `fetch` has had its body stream consumed, so `request.clone()` here\n * throws `TypeError: unusable`. To re-issue it we stash a *pristine* clone in\n * `onRequest` — captured before the body is read — keyed by openapi-fetch's\n * per-request `id`, and clone from that pristine copy on each attempt.\n */\nfunction retryMiddleware(maxRetries: number, doFetch: typeof fetch): Middleware {\n const pristine = new Map<string, Request>();\n return {\n onRequest({ request, id }) {\n pristine.set(id, request.clone());\n return request;\n },\n onError({ id }) {\n // fetch rejected (network error) — no onResponse will fire; don't leak.\n pristine.delete(id);\n },\n async onResponse({ request, response, id }) {\n const original = pristine.get(id) ?? request;\n pristine.delete(id);\n if (maxRetries <= 0 || !RETRYABLE_STATUSES.has(response.status)) {\n return response;\n }\n let current = response;\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n if (!RETRYABLE_STATUSES.has(current.status)) break;\n const retryAfterMs = parseRetryAfterMs(current.headers.get(\"retry-after\"));\n const backoff = Math.min(BASE_BACKOFF_MS * 2 ** (attempt - 1), MAX_BACKOFF_MS);\n // Cap the wait — including a server-supplied `Retry-After` — so a hostile\n // or misconfigured server can't park the client for minutes/hours.\n await sleep(Math.min(retryAfterMs ?? backoff, MAX_BACKOFF_MS));\n // Re-issue from the pristine clone; `.clone()` keeps it reusable across\n // multiple attempts.\n current = await doFetch(original.clone());\n }\n return current;\n },\n };\n}\n\n/**\n * A typed client for the Krova Cloud API.\n *\n * @example\n * ```ts\n * const krova = new KrovaClient({ apiKey: \"kro_...\" });\n * const cubes = await krova.cubes.list(\"space_123\");\n * ```\n */\nexport class KrovaClient {\n /**\n * The underlying openapi-fetch client — a fully typed escape hatch to every\n * path in the spec. Returns `{ data, error, response }` and never throws.\n *\n * @example\n * ```ts\n * const { data, error } = await krova.raw.GET(\n * \"/spaces/{spaceId}/cubes/{cubeId}\",\n * { params: { path: { spaceId, cubeId } } },\n * );\n * ```\n */\n readonly raw: Client<paths>;\n\n /** The resolved base URL in use. */\n readonly baseUrl: string;\n\n constructor(options: KrovaClientOptions) {\n if (!options?.apiKey) {\n throw new Error(\"KrovaClient: `apiKey` is required.\");\n }\n this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const doFetch = options.fetch ?? globalThis.fetch;\n const maxRetries = options.maxRetries ?? 2;\n\n this.raw = createClient<paths>({\n baseUrl: this.baseUrl,\n // SECURITY: never auto-follow redirects. The Krova Cloud API is a plain\n // JSON API and never legitimately 3xx's a data call. Following a redirect\n // would resend the `X-API-KEY` header to the redirect target — and unlike\n // `Authorization`, `Cookie`, and `Proxy-Authorization`, the Fetch spec does\n // NOT strip a custom header like `X-API-KEY` on a cross-origin redirect\n // (verified against undici/Node fetch). A compromised/misconfigured proxy,\n // an open-redirect on the API, or a MITM could otherwise exfiltrate the key\n // to an attacker's host. With `\"manual\"`, a redirect comes back as a\n // non-ok response and the helpers throw `KrovaError` instead of leaking.\n redirect: \"manual\",\n ...(options.fetch ? { fetch: options.fetch } : {}),\n });\n this.raw.use(authMiddleware(options.apiKey, options.authScheme ?? \"x-api-key\"));\n if (maxRetries > 0) {\n this.raw.use(retryMiddleware(maxRetries, doFetch));\n }\n }\n\n // ---------------------------------------------------------------------------\n // Cubes\n // ---------------------------------------------------------------------------\n\n readonly cubes = {\n /** List Cubes in a Space, with pagination metadata. */\n list: async (spaceId: string) => {\n const { data, error, response } = await this.raw.GET(\"/spaces/{spaceId}/cubes\", {\n params: { path: { spaceId } },\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"List Cubes response was empty.\" });\n return data;\n },\n\n /**\n * Create a Cube. Returns the created {@link Cube}.\n *\n * @param spaceId Target Space id.\n * @param body Cube spec — `{ name, image, resources, sshPublicKey, ... }`.\n * @param opts Optional `idempotencyKey` (max 255 chars, scoped per space).\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n opts?: { idempotencyKey?: string },\n ): Promise<Cube> => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes\", {\n params: {\n path: { spaceId },\n ...(opts?.idempotencyKey\n ? { header: { \"Idempotency-Key\": opts.idempotencyKey } }\n : {}),\n },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Create Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /** Get a single Cube. Returns the {@link Cube}. */\n get: async (spaceId: string, cubeId: string): Promise<Cube> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n const cube = data?.cube;\n if (!cube) {\n throw krovaErrorFrom(response, { error: \"Get Cube response had no `cube`.\" });\n }\n return cube;\n },\n\n /**\n * Update the IN-CUBE port that SSH is forwarded to.\n *\n * `cubePort` is the port **inside** the Cube that sshd listens on — NOT the\n * host port you connect to. The host port is allocated by Krova and is not\n * changed by this call. Pointing this at a port nothing is listening on\n * inside the Cube will silently make SSH unreachable; the default is 22.\n *\n * The Krova Cloud API exposes no general Cube-mutation endpoint; the only\n * mutable Cube field over the API is this port, via\n * `PUT /spaces/{spaceId}/cubes/{cubeId}/ssh-port`. This helper maps to that\n * endpoint. (Compute resize / rename are not part of the public API.)\n */\n update: async (\n spaceId: string,\n cubeId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\"][\"put\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ): Promise<unknown> => {\n const { data, error, response } = await this.raw.PUT(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh-port\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Delete a Cube (asynchronous — deletion is enqueued). */\n delete: async (spaceId: string, cubeId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Delete Cube response was empty.\" });\n return data;\n },\n\n /** Power off a running Cube (asynchronous — power-off is enqueued). The Cube\n * becomes `stopped` (its host RAM is freed); start it again with `wake`. */\n powerOff: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/power-off\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Start a stopped Cube (asynchronous — start is enqueued). */\n /**\n * Restart a Cube (COLD restart).\n *\n * The hypervisor process is stopped and relaunched, so the Cube boots\n * against the host's current kernel. This is the only way a Cube picks up a\n * refreshed guest kernel after a platform image update — a `reboot` issued\n * INSIDE the Cube cannot do it, because Firecracker treats a guest reboot as\n * a shutdown and the kernel is supplied externally by the host.\n *\n * Disk state is preserved; only the kernel changes. The Cube must be\n * `running`. Concurrent restarts of the same Cube are rejected (409) rather\n * than queued twice.\n */\n restart: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restart\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n wake: async (spaceId: string, cubeId: string): Promise<unknown> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/wake\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Get a Cube's SSH connection info — host, port, login user, and (when\n * available) the pinned host public keys for strict host-key verification.\n */\n ssh: async (spaceId: string, cubeId: string): Promise<CubeSshInfo> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/ssh\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Cube SSH-info response was empty.\" });\n return data;\n },\n\n /**\n * Restore a Cube's disk from one of its {@link Snapshot}s (asynchronous —\n * the restore is enqueued). The Cube's current disk is replaced.\n */\n restore: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/restore\",\n { params: { path: { spaceId, cubeId } }, body: { snapshotId } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n /**\n * Resolve the {@link Space} this API key is scoped to — so you don't have to\n * hardcode a `spaceId`. Handy right after constructing the client:\n *\n * @example\n * ```ts\n * const space = await krova.getSpace();\n * const cubes = await krova.cubes.list(space.id);\n * ```\n */\n async getSpace(): Promise<Space> {\n const { data, error, response } = await this.raw.GET(\"/space\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Space response was empty.\" });\n return data;\n }\n\n // ---------------------------------------------------------------------------\n // Custom domains\n // ---------------------------------------------------------------------------\n\n readonly domains = {\n /** List the custom domains attached to a Cube. */\n list: async (spaceId: string, cubeId: string): Promise<Domain[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.domains ?? [];\n },\n\n /**\n * Attach a custom domain to a Cube. `domain` + `port` are required.\n *\n * Returns the domain AND the DNS records you must publish for it to work —\n * so you can create them in the same run, without a second call and without\n * hard-coding record shapes. A wildcard needs three; an exact host needs one.\n *\n * ⛔ BREAKING in 0.4.0: this used to resolve to `Domain`. It now resolves to\n * `{ domain, records }`, because for a wildcard two of the three records\n * (the ownership TXT and the `_acme-challenge` delegation) were not\n * derivable from anything the SDK returned — an integration had to read\n * them out of the docs and hope they still matched the server.\n */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateDomainInput,\n ): Promise<{ domain: Domain; records: DnsRecord[] }> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Create domain response had no `domain`.\" });\n return { domain: data.domain, records: data.records ?? [] };\n },\n\n /**\n * The DNS records a domain needs, each checked against live DNS.\n *\n * Poll this after publishing them: `summary.complete` turns true only once\n * every record is `found`. Each call performs real DNS lookups and is rate\n * limited, so poll on an interval rather than in a tight loop.\n */\n records: async (\n spaceId: string,\n cubeId: string,\n mappingId: string,\n ): Promise<{\n domain: string;\n isWildcard: boolean;\n records: DnsRecordStatus[];\n summary: { found: number; total: number; complete: boolean };\n checkedAt: string;\n }> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}/records\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data)\n throw krovaErrorFrom(response, { error: \"Domain records response was empty.\" });\n return data;\n },\n\n /** Update a domain's per-domain proxy settings. */\n update: async (\n spaceId: string,\n cubeId: string,\n mappingId: string,\n body: UpdateDomainInput,\n ): Promise<Domain> => {\n const { data, error, response } = await this.raw.PATCH(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.domain)\n throw krovaErrorFrom(response, { error: \"Update domain response had no `domain`.\" });\n return data.domain;\n },\n\n /** Detach a custom domain from a Cube. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/domains/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Snapshots\n // ---------------------------------------------------------------------------\n\n readonly snapshots = {\n /** List a Cube's snapshots. */\n list: async (spaceId: string, cubeId: string): Promise<Snapshot[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.snapshots ?? [];\n },\n\n /** Create a snapshot of a Cube's disk (asynchronous — enqueued). */\n create: async (\n spaceId: string,\n cubeId: string,\n body?: { name?: string },\n ): Promise<Snapshot> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots\",\n { params: { path: { spaceId, cubeId } }, body: body ?? {} },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.snapshot)\n throw krovaErrorFrom(response, { error: \"Create snapshot response had no `snapshot`.\" });\n return data.snapshot;\n },\n\n /** Delete a snapshot. */\n delete: async (spaceId: string, cubeId: string, snapshotId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/snapshots/{snapshotId}\",\n { params: { path: { spaceId, cubeId, snapshotId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // TCP port mappings\n // ---------------------------------------------------------------------------\n\n readonly tcpMappings = {\n /** List a Cube's TCP port mappings. */\n list: async (spaceId: string, cubeId: string): Promise<TcpMapping[]> => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data?.tcpMappings ?? [];\n },\n\n /**\n * Create a TCP port mapping exposing a Cube port on the host. `cubePort` is\n * required; `whitelistIps` optionally restricts who can reach it.\n */\n create: async (\n spaceId: string,\n cubeId: string,\n body: CreateTcpMappingInput,\n ): Promise<TcpMapping> => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings\",\n { params: { path: { spaceId, cubeId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (!data?.tcpMapping)\n throw krovaErrorFrom(response, { error: \"Create TCP mapping response had no `tcpMapping`.\" });\n return data.tcpMapping;\n },\n\n /** Delete a TCP port mapping. */\n delete: async (spaceId: string, cubeId: string, mappingId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/{cubeId}/tcp-mappings/{mappingId}\",\n { params: { path: { spaceId, cubeId, mappingId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Imports & backups (.cube archive import / export)\n // ---------------------------------------------------------------------------\n\n readonly imports = {\n /**\n * Start importing a `.cube` archive into a new Cube. Returns the multipart\n * upload target (`importId`, `uploadId`, presigned `parts`, …). Upload the\n * archive to those URLs, then call {@link imports.complete}.\n */\n create: async (\n spaceId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\"/spaces/{spaceId}/cubes/imports\", {\n params: { path: { spaceId } },\n body,\n });\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Get an in-progress or completed import by id. */\n get: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /**\n * Finish an import after the archive has been uploaded — provisions the\n * Cube. Pass the uploaded `parts` (partNumber + etag) and the resolved\n * `config`.\n */\n complete: async (\n spaceId: string,\n importId: string,\n body: NonNullable<\n paths[\"/spaces/{spaceId}/cubes/imports/{importId}/complete\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n ) => {\n const { data, error, response } = await this.raw.POST(\n \"/spaces/{spaceId}/cubes/imports/{importId}/complete\",\n { params: { path: { spaceId, importId } }, body },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n\n /** Cancel an in-progress import. */\n cancel: async (spaceId: string, importId: string) => {\n const { data, error, response } = await this.raw.DELETE(\n \"/spaces/{spaceId}/cubes/imports/{importId}\",\n { params: { path: { spaceId, importId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n readonly backups = {\n /** Get a time-limited download URL for a backup `.cube` archive. */\n download: async (spaceId: string, backupId: string) => {\n const { data, error, response } = await this.raw.GET(\n \"/spaces/{spaceId}/backups/{backupId}/download\",\n { params: { path: { spaceId, backupId } } },\n );\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n return data;\n },\n };\n\n // ---------------------------------------------------------------------------\n // Public catalog (no auth required by the API, but the key is harmless)\n // ---------------------------------------------------------------------------\n\n readonly catalog = {\n /** List regions with available capacity. */\n regions: async () => {\n const { data, error, response } = await this.raw.GET(\"/regions\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Regions response was empty.\" });\n return data;\n },\n\n /** List available OS images. */\n images: async () => {\n const { data, error, response } = await this.raw.GET(\"/images\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Images response was empty.\" });\n return data;\n },\n\n /** Per-resource hourly rates and volume pricing tiers. */\n pricing: async () => {\n const { data, error, response } = await this.raw.GET(\"/pricing\");\n if (error !== undefined || !response.ok) throw krovaErrorFrom(response, error);\n if (data === undefined)\n throw krovaErrorFrom(response, { error: \"Pricing response was empty.\" });\n return data;\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krovacloud/sdk",
3
- "version": "0.3.10",
3
+ "version": "0.4.0",
4
4
  "description": "Official TypeScript SDK for Krova Cloud — a typed client for provisioning and managing Cubes (Firecracker microVMs) with dedicated resources.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -61,10 +61,10 @@
61
61
  "openapi-fetch": "^0.17.0"
62
62
  },
63
63
  "devDependencies": {
64
- "@types/node": "^26.1.1",
64
+ "@types/node": "^26.3.0",
65
65
  "openapi-typescript": "^7.13.0",
66
66
  "tsup": "^8.5.1",
67
- "tsx": "^4.23.1",
67
+ "tsx": "^4.23.12",
68
68
  "typescript": "^6.0.3"
69
69
  },
70
70
  "scripts": {