@krovacloud/sdk 0.1.1 → 0.1.2

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +157 -51
  3. package/package.json +21 -14
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@ All notable changes to `@krovacloud/sdk` are documented here. This project adher
4
4
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the
5
5
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
6
6
 
7
+ ## 0.1.2
8
+
9
+ ### Changed
10
+
11
+ - **Documentation & packaging polish** — no runtime behavior change.
12
+ - Rewrote the README to a complete public reference: npm/license/types
13
+ badges, a runnable Quickstart traced against the shipped API, a per-export
14
+ reference for `KrovaClient`, every `client.cubes.*` and `client.catalog.*`
15
+ helper, `client.raw`, and `KrovaError` (with its full field table), plus
16
+ Auth, Error-handling, Configuration, TypeScript, Requirements, and a
17
+ **Related packages** section linking `@krovacloud/cli`,
18
+ `@krovacloud/webhook`, `@krovacloud/mcp`, and `n8n-nodes-krova`.
19
+ - Sharpened the `package.json` `description`, expanded `keywords`
20
+ (added `api`, `api-client`, `cubes`, `openapi`), and pointed `homepage`
21
+ at [krova.cloud](https://krova.cloud).
22
+ - Added a top-level `"types"` fallback and a `"./package.json"` entry to the
23
+ `exports` map for broader tooling compatibility.
24
+
7
25
  ## 0.1.1
8
26
 
9
27
  ### Fixed
package/README.md CHANGED
@@ -1,23 +1,29 @@
1
1
  # @krovacloud/sdk
2
2
 
3
- The official TypeScript SDK for the [Krova Cloud](https://krova.cloud) API — a fully typed client generated directly from the Krova Cloud OpenAPI specification.
3
+ [![npm version](https://img.shields.io/npm/v/@krovacloud/sdk?color=cb3837&logo=npm)](https://www.npmjs.com/package/@krovacloud/sdk)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@krovacloud/sdk?color=cb3837&logo=npm)](https://www.npmjs.com/package/@krovacloud/sdk)
5
+ [![license: MIT](https://img.shields.io/npm/l/@krovacloud/sdk?color=blue)](./LICENSE)
6
+ [![types: included](https://img.shields.io/npm/types/@krovacloud/sdk?logo=typescript)](https://www.typescriptlang.org/)
4
7
 
5
- Krova Cloud is a self-service platform for lightweight **Cubes** (Firecracker microVMs) on dedicated bare-metal servers. This SDK gives you typed access to every endpoint plus ergonomic helpers for the common Cube and catalog operations.
8
+ The official TypeScript SDK for the [Krova Cloud](https://krova.cloud) API a fully typed client for provisioning and managing **Cubes** (Firecracker microVMs) on dedicated bare-metal servers.
6
9
 
7
- - **Fully typed** — request bodies, responses, and path params are typed from the OpenAPI spec via [`openapi-typescript`](https://github.com/openapi-ts/openapi-typescript) + [`openapi-fetch`](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch).
8
- - **ESM + CJS** — ships both, with `.d.ts` types.
9
- - **Ergonomic helpers** — `client.cubes.*` and `client.catalog.*` unwrap the response and throw on errors.
10
- - **Escape hatch** — `client.raw` exposes the underlying typed client for every operation in the spec (31 operations across 22 resource paths).
10
+ ## Highlights
11
+
12
+ - **Fully typed** — request bodies, responses, and path params are generated from the Krova Cloud OpenAPI spec via [`openapi-typescript`](https://github.com/openapi-ts/openapi-typescript) + [`openapi-fetch`](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch).
13
+ - **Ergonomic helpers** — `client.cubes.*` and `client.catalog.*` unwrap the response body and throw a typed `KrovaError` on failure.
14
+ - **Full escape hatch** — `client.raw` exposes the underlying typed client for *every* operation in the spec (31 operations across 22 resource paths).
15
+ - **Zero-config resilience** — automatic retries on `429` / `503`, honoring `Retry-After`.
16
+ - **ESM + CJS** — ships both, with bundled `.d.ts` declarations. No runtime dependencies beyond `openapi-fetch`.
11
17
 
12
18
  ## Install
13
19
 
14
20
  ```sh
15
- pnpm add @krovacloud/sdk
16
- # or: npm install @krovacloud/sdk
21
+ npm i @krovacloud/sdk
22
+ # or: pnpm add @krovacloud/sdk
17
23
  # or: yarn add @krovacloud/sdk
18
24
  ```
19
25
 
20
- Requires Node.js 18+ (uses the global `fetch`).
26
+ Requires **Node.js 18** (uses the global `fetch`).
21
27
 
22
28
  ## Quickstart
23
29
 
@@ -32,13 +38,14 @@ const krova = new KrovaClient({
32
38
  const cubes = await krova.cubes.list("space_123");
33
39
  console.log(cubes);
34
40
 
35
- // Create a Cube
41
+ // Create a Cube (sshPublicKey is required)
36
42
  const cube = await krova.cubes.create("space_123", {
37
43
  name: "web-server",
38
44
  image: "ubuntu-24.04",
39
45
  resources: { vcpu: 2, ramGb: 4, diskGb: 40 },
40
46
  sshPublicKey: "ssh-ed25519 AAAA...your-key... you@host",
41
47
  });
48
+
42
49
  console.log(`Created cube ${cube.id} (${cube.state})`);
43
50
  console.log(` ${cube.resources.vcpu} vCPU / ${cube.resources.ramGb} GB RAM, image ${cube.image}`);
44
51
 
@@ -47,60 +54,139 @@ await krova.cubes.sleep("space_123", cube.id);
47
54
  await krova.cubes.wake("space_123", cube.id);
48
55
  ```
49
56
 
50
- ### Public catalog
57
+ ## Authentication
58
+
59
+ Get an API key at **[krova.cloud](https://krova.cloud)** → your Space settings. Keys are **scoped per Space**, inherit the permissions of the membership that created them, and look like `kro_...`.
51
60
 
52
- The catalog endpoints do not require authentication, but the client sends your key harmlessly:
61
+ By default the client sends the key as the `X-API-KEY` header (the API's security scheme). If your gateway expects a bearer token instead, pass `authScheme: "bearer"`:
53
62
 
54
63
  ```ts
55
- const regions = await krova.catalog.regions();
56
- const images = await krova.catalog.images();
57
- const pricing = await krova.catalog.pricing();
64
+ const krova = new KrovaClient({ apiKey: "kro_...", authScheme: "bearer" });
65
+ ```
66
+
67
+ > **Keep keys secret.** Never commit a key or embed it in a browser bundle. Load it from an environment variable or a secrets manager.
68
+
69
+ ## API reference
70
+
71
+ Every public export, with its real signature and a short example.
72
+
73
+ ### `new KrovaClient(options)`
74
+
75
+ ```ts
76
+ new KrovaClient({
77
+ apiKey: string, // required — your "kro_..." token
78
+ baseUrl?: string, // default: "https://krova.cloud/api/v1"
79
+ authScheme?: "x-api-key" | "bearer", // default: "x-api-key"
80
+ maxRetries?: number, // default: 2 — retries 429/503 (honors Retry-After); 0 disables
81
+ fetch?: typeof fetch, // optional fetch override (proxy, tests)
82
+ });
58
83
  ```
59
84
 
60
- ### The raw client (every endpoint)
85
+ Throws if `apiKey` is missing. Exposes `client.baseUrl` (the resolved base URL), `client.cubes`, `client.catalog`, and `client.raw`.
61
86
 
62
- The ergonomic helpers cover Cubes and the catalog. For everything else — Domains, TCP mappings, Snapshots, Backups, Imports, Webhooks — use `krova.raw`, the fully typed [`openapi-fetch`](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch) client. It returns `{ data, error, response }` and never throws:
87
+ ### `client.cubes`
88
+
89
+ Ergonomic helpers for the Cube lifecycle. Each unwraps the response body and throws `KrovaError` on a non-2xx status.
90
+
91
+ | Method | Signature | Returns |
92
+ | --- | --- | --- |
93
+ | `list` | `(spaceId: string)` | the Cube list body |
94
+ | `create` | `(spaceId, body, opts?)` | the created `Cube` |
95
+ | `get` | `(spaceId, cubeId)` | the Cube body |
96
+ | `update` | `(spaceId, cubeId, body)` | updates the Cube's SSH port |
97
+ | `delete` | `(spaceId, cubeId)` | enqueues deletion |
98
+ | `sleep` | `(spaceId, cubeId)` | enqueues sleep |
99
+ | `wake` | `(spaceId, cubeId)` | enqueues wake |
63
100
 
64
101
  ```ts
65
- const { data, error } = await krova.raw.POST(
66
- "/spaces/{spaceId}/webhooks",
102
+ // create sshPublicKey is required; region + userData (cloud-init) are optional.
103
+ // opts.idempotencyKey (≤255 chars, per-space) makes retries safe.
104
+ const cube = await krova.cubes.create(
105
+ "space_123",
67
106
  {
68
- params: { path: { spaceId: "space_123" } },
69
- body: { url: "https://example.com/hook", events: ["cube.running"] },
107
+ name: "web-server",
108
+ image: "ubuntu-24.04",
109
+ resources: { vcpu: 2, ramGb: 4, diskGb: 40 },
110
+ sshPublicKey: "ssh-ed25519 AAAA... you@host",
111
+ region: "us-east", // optional — slug from catalog.regions()
112
+ userData: "#cloud-config\n", // optional — cloud-init (max 16 KB)
70
113
  },
114
+ { idempotencyKey: "deploy-2026-07-01" },
71
115
  );
72
- if (error) {
73
- console.error("Webhook create failed:", error.error);
74
- } else {
75
- console.log(data);
76
- }
116
+
117
+ // get / list
118
+ const one = await krova.cubes.get("space_123", cube.id);
119
+ const all = await krova.cubes.list("space_123");
120
+
121
+ // update — the only mutable Cube field over the public API is the SSH port
122
+ await krova.cubes.update("space_123", cube.id, { cubePort: 2222 });
123
+
124
+ // lifecycle — sleep, wake, delete are asynchronous (enqueued)
125
+ await krova.cubes.sleep("space_123", cube.id);
126
+ await krova.cubes.wake("space_123", cube.id);
127
+ await krova.cubes.delete("space_123", cube.id);
77
128
  ```
78
129
 
79
- ## Authentication
130
+ The `Cube` type is exported for your own signatures:
80
131
 
81
- Create an API key from your Space settings in the [Krova Cloud dashboard](https://krova.cloud). Keys are **scoped per Space** and inherit the permissions of the membership that created them; they look like `kro_...`.
132
+ ```ts
133
+ import type { Cube } from "@krovacloud/sdk";
134
+ // {
135
+ // id: string; name: string;
136
+ // state: "pending" | "booting" | "running" | "sleeping" | "stopping" | "error" | "deleted";
137
+ // publicIpv4: string | null;
138
+ // resources: { vcpu: number; ramGb: number; diskGb: number };
139
+ // image: string; costPerHour: number;
140
+ // createdAt: string; updatedAt: string;
141
+ // }
142
+ ```
82
143
 
83
- By default the client sends the key as the `X-API-KEY` header, matching the API's security scheme. If your gateway expects a bearer token instead, pass `authScheme: "bearer"`:
144
+ ### `client.catalog`
145
+
146
+ Public catalog endpoints (no auth required by the API; the client sends your key harmlessly).
84
147
 
85
148
  ```ts
86
- const krova = new KrovaClient({ apiKey: "kro_...", authScheme: "bearer" });
149
+ const regions = await krova.catalog.regions(); // regions with available capacity
150
+ const images = await krova.catalog.images(); // available OS images
151
+ const pricing = await krova.catalog.pricing(); // per-resource hourly rates + volume tiers
87
152
  ```
88
153
 
89
- ### Options
154
+ ### `client.raw` — every endpoint
155
+
156
+ The helpers cover Cubes and the catalog. For everything else — Domains, TCP mappings, Snapshots, Backups, Imports, Webhooks — use `client.raw`, the fully typed [`openapi-fetch`](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch) client. It returns `{ data, error, response }` and **never throws**:
90
157
 
91
158
  ```ts
92
- new KrovaClient({
93
- apiKey: "kro_...", // required
94
- baseUrl: "https://krova.cloud/api/v1", // default
95
- authScheme: "x-api-key", // "x-api-key" (default) | "bearer"
96
- maxRetries: 2, // retries on 429/503 (honors Retry-After); 0 disables
97
- fetch: customFetch, // optional fetch override
159
+ const { data, error } = await krova.raw.POST("/spaces/{spaceId}/webhooks", {
160
+ params: { path: { spaceId: "space_123" } },
161
+ body: { url: "https://example.com/hook", events: ["cube.running"] },
98
162
  });
163
+
164
+ if (error) {
165
+ console.error("Webhook create failed:", error.error);
166
+ } else {
167
+ console.log(data);
168
+ }
99
169
  ```
100
170
 
101
- ## Error handling
171
+ Path, method, params, and body are all type-checked against the spec. The generated `paths` and `components` types are also exported for advanced use:
172
+
173
+ ```ts
174
+ import type { paths, components } from "@krovacloud/sdk";
175
+ type Domain = components["schemas"]["Domain"];
176
+ ```
177
+
178
+ ### `KrovaError`
179
+
180
+ Thrown by the `cubes.*` / `catalog.*` helpers on any non-2xx response. (`client.raw` never throws — it returns the error in `{ error }`.)
102
181
 
103
- The ergonomic helpers throw a `KrovaError` on any non-2xx response. It carries the HTTP `status`, the API's error `message`, and — when the API sends them — a `code` (`X-Error-Code`), a `requestId` (`X-Request-Id`), and the parsed `body`:
182
+ | Field | Type | Source |
183
+ | --- | --- | --- |
184
+ | `status` | `number` | HTTP status code |
185
+ | `message` | `string` | the API's `error` string, else `statusText` |
186
+ | `code` | `string \| undefined` | `X-Error-Code` response header |
187
+ | `requestId` | `string \| undefined` | `X-Request-Id` response header |
188
+ | `body` | `object \| undefined` | the parsed JSON error body |
189
+ | `response` | `Response \| undefined` | the raw `Response` |
104
190
 
105
191
  ```ts
106
192
  import { KrovaError } from "@krovacloud/sdk";
@@ -110,29 +196,49 @@ try {
110
196
  } catch (err) {
111
197
  if (err instanceof KrovaError) {
112
198
  console.error(`[${err.status}] ${err.message}`);
113
- if (err.requestId) console.error("request id:", err.requestId);
199
+ if (err.code) console.error("code:", err.code);
200
+ if (err.requestId) console.error("request id:", err.requestId); // quote this to support
114
201
  } else {
115
202
  throw err;
116
203
  }
117
204
  }
118
205
  ```
119
206
 
120
- Mutating `POST` / `DELETE` endpoints are rate-limited (10 requests / 60s per client IP). The client automatically retries `429` and `503` responses (up to `maxRetries`, honoring the `Retry-After` header).
207
+ Mutating `POST` / `DELETE` endpoints are rate-limited (10 requests / 60s per client IP). The client automatically retries `429` and `503` up to `maxRetries` times, honoring the `Retry-After` header.
121
208
 
122
- ## API reference
123
-
124
- The full Krova Cloud API is documented in the OpenAPI spec vendored in this repo ([`openapi.json`](./openapi.json)). See [krova.cloud](https://krova.cloud) for the hosted docs and to obtain a key.
209
+ ## Configuration
125
210
 
126
- ## Development
211
+ Point the client at a different base URL (self-hosted gateway, staging, a proxy):
127
212
 
128
- ```sh
129
- pnpm install
130
- pnpm gen # regenerate src/generated/types.ts from openapi.json
131
- pnpm typecheck
132
- pnpm build # ESM + CJS + d.ts into dist/
133
- pnpm test # node:test via tsx (no network)
213
+ ```ts
214
+ const krova = new KrovaClient({
215
+ apiKey: "kro_...",
216
+ baseUrl: "https://gateway.internal/krova/api/v1",
217
+ });
134
218
  ```
135
219
 
220
+ ## TypeScript
221
+
222
+ The package ships its own type declarations — no `@types/*` install needed. `Cube`, `KrovaError`, `KrovaClientOptions`, `AuthScheme`, and the generated `paths` / `components` are all exported.
223
+
224
+ ## Related packages
225
+
226
+ | Package | What it is |
227
+ | --- | --- |
228
+ | [`@krovacloud/cli`](https://www.npmjs.com/package/@krovacloud/cli) | Command-line interface for Krova Cloud |
229
+ | [`@krovacloud/webhook`](https://www.npmjs.com/package/@krovacloud/webhook) | Verify and parse Krova Cloud webhook events |
230
+ | [`@krovacloud/mcp`](https://www.npmjs.com/package/@krovacloud/mcp) | Model Context Protocol server for Krova Cloud |
231
+ | [`n8n-nodes-krova`](https://www.npmjs.com/package/n8n-nodes-krova) | n8n community nodes for Krova Cloud |
232
+
233
+ ## Requirements
234
+
235
+ - **Node.js ≥ 18** (global `fetch`).
236
+ - Works in any modern runtime with a WHATWG `fetch` (Deno, Bun, edge). Pass a custom `fetch` if the global isn't available.
237
+
238
+ ## Contributing
239
+
240
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). Report security issues privately per [SECURITY.md](./SECURITY.md).
241
+
136
242
  ## License
137
243
 
138
244
  [MIT](./LICENSE) © 2026 Krova Inc.
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@krovacloud/sdk",
3
- "version": "0.1.1",
4
- "description": "Official TypeScript SDK for the Krova Cloud API — a typed client generated from the Krova Cloud OpenAPI spec.",
3
+ "version": "0.1.2",
4
+ "description": "Official TypeScript SDK for Krova Cloud — a typed client for provisioning and managing Cubes (Firecracker microVMs) on bare-metal.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "author": "Krova Inc.",
8
- "homepage": "https://github.com/krovacloud/krova-js#readme",
8
+ "homepage": "https://krova.cloud",
9
9
  "repository": {
10
10
  "type": "git",
11
11
  "url": "git+https://github.com/krovacloud/krova-js.git"
@@ -16,12 +16,16 @@
16
16
  "keywords": [
17
17
  "krova",
18
18
  "krova-cloud",
19
+ "sdk",
20
+ "api",
21
+ "api-client",
19
22
  "firecracker",
20
- "cube",
21
23
  "microvm",
24
+ "cube",
25
+ "cubes",
22
26
  "cloud",
23
- "sdk",
24
- "typescript"
27
+ "typescript",
28
+ "openapi"
25
29
  ],
26
30
  "publishConfig": {
27
31
  "access": "public"
@@ -31,6 +35,7 @@
31
35
  "types": "./dist/index.d.ts",
32
36
  "exports": {
33
37
  ".": {
38
+ "types": "./dist/index.d.ts",
34
39
  "import": {
35
40
  "types": "./dist/index.d.ts",
36
41
  "default": "./dist/index.js"
@@ -39,7 +44,8 @@
39
44
  "types": "./dist/index.d.cts",
40
45
  "default": "./dist/index.cjs"
41
46
  }
42
- }
47
+ },
48
+ "./package.json": "./package.json"
43
49
  },
44
50
  "files": [
45
51
  "dist",
@@ -50,6 +56,13 @@
50
56
  "engines": {
51
57
  "node": ">=18"
52
58
  },
59
+ "scripts": {
60
+ "gen": "openapi-typescript openapi.json -o src/generated/types.ts",
61
+ "build": "tsup",
62
+ "typecheck": "tsc --noEmit",
63
+ "test": "tsx --test tests/*.test.ts",
64
+ "prepublishOnly": "pnpm build"
65
+ },
53
66
  "dependencies": {
54
67
  "openapi-fetch": "^0.17.0"
55
68
  },
@@ -59,11 +72,5 @@
59
72
  "tsup": "^8.5.1",
60
73
  "tsx": "^4.22.4",
61
74
  "typescript": "^5.9.3"
62
- },
63
- "scripts": {
64
- "gen": "openapi-typescript openapi.json -o src/generated/types.ts",
65
- "build": "tsup",
66
- "typecheck": "tsc --noEmit",
67
- "test": "tsx --test tests/*.test.ts"
68
75
  }
69
- }
76
+ }