@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.
- package/CHANGELOG.md +18 -0
- package/README.md +157 -51
- 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
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@krovacloud/sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@krovacloud/sdk)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
4
7
|
|
|
5
|
-
Krova Cloud
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
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
|
-
|
|
16
|
-
# or:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
85
|
+
Throws if `apiKey` is missing. Exposes `client.baseUrl` (the resolved base URL), `client.cubes`, `client.catalog`, and `client.raw`.
|
|
61
86
|
|
|
62
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
130
|
+
The `Cube` type is exported for your own signatures:
|
|
80
131
|
|
|
81
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
###
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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`
|
|
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
|
-
##
|
|
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
|
-
|
|
211
|
+
Point the client at a different base URL (self-hosted gateway, staging, a proxy):
|
|
127
212
|
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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.
|
|
4
|
-
"description": "Official TypeScript SDK for
|
|
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://
|
|
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
|
-
"
|
|
24
|
-
"
|
|
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
|
+
}
|